@@ -18,6 +18,7 @@ import { parseLogLevel } from 'vs/platform/log/common/log';
18
18
import product from 'vs/platform/product/common/product' ;
19
19
import { isFolderToOpen , isWorkspaceToOpen } from 'vs/platform/windows/common/windows' ;
20
20
import { create , ICredentialsProvider , IHomeIndicator , IProductQualityChangeHandler , ISettingsSyncOptions , IURLCallbackProvider , IWelcomeBanner , IWindowIndicator , IWorkbenchConstructionOptions , IWorkspace , IWorkspaceProvider } from 'vs/workbench/workbench.web.api' ;
21
+ import { equals as arrayEquals } from 'vs/base/common/arrays' ;
21
22
22
23
function doCreateUri ( path : string , queryValues : Map < string , string > ) : URI {
23
24
let query : string | undefined = undefined ;
@@ -49,6 +50,14 @@ interface ICredential {
49
50
password : string ;
50
51
}
51
52
53
+ /** @author coder */
54
+ interface IToken {
55
+ accessToken : string
56
+ account ?: { label : string }
57
+ id : string
58
+ scopes : string [ ]
59
+ }
60
+
52
61
class LocalStorageCredentialsProvider implements ICredentialsProvider {
53
62
54
63
static readonly CREDENTIALS_OPENED_KEY = 'credentials.provider' ;
@@ -76,6 +85,61 @@ class LocalStorageCredentialsProvider implements ICredentialsProvider {
76
85
scopes,
77
86
accessToken : authSessionInfo ! . accessToken
78
87
} ) ) ) ) ;
88
+
89
+ /**
90
+ * Add tokens for extensions to use. This works for extensions like the
91
+ * pull requests one or GitLens.
92
+ * @author coder
93
+ */
94
+ const extensionId = `vscode.${ authSessionInfo . providerId } -authentication` ;
95
+ const service = `${ product . urlProtocol } ${ extensionId } ` ;
96
+ const account = `${ authSessionInfo . providerId } .auth` ;
97
+ // Oddly the scopes need to match exactly so we cannot just have one token
98
+ // with all the scopes, instead we have to duplicate the token for each
99
+ // expected set of scopes.
100
+ const tokens : IToken [ ] = authSessionInfo . scopes . map ( ( scopes ) => ( {
101
+ id : authSessionInfo ! . id ,
102
+ scopes : scopes . sort ( ) , // Sort for comparing later.
103
+ accessToken : authSessionInfo ! . accessToken ,
104
+ } ) ) ;
105
+ this . getPassword ( service , account ) . then ( ( raw ) => {
106
+ let existing : {
107
+ content : IToken [ ]
108
+ } | undefined ;
109
+
110
+ if ( raw ) {
111
+ try {
112
+ const json = JSON . parse ( raw ) ;
113
+ json . content = JSON . parse ( json . content ) ;
114
+ existing = json ;
115
+ } catch ( error ) {
116
+ console . log ( error ) ;
117
+ }
118
+ }
119
+
120
+ // Keep tokens for account and scope combinations we do not have in case
121
+ // there is an extension that uses scopes we have not accounted for (in
122
+ // these cases the user will need to manually authenticate the extension
123
+ // through the UI) or the user has tokens for other accounts.
124
+ if ( existing ?. content ) {
125
+ existing . content = existing . content . filter ( ( existingToken ) => {
126
+ const scopes = existingToken . scopes . sort ( ) ;
127
+ return ! ( tokens . find ( ( token ) => {
128
+ return arrayEquals ( scopes , token . scopes )
129
+ && token . account ?. label === existingToken . account ?. label ;
130
+ } ) )
131
+ } )
132
+ }
133
+
134
+ return this . setPassword ( service , account , JSON . stringify ( {
135
+ extensionId,
136
+ ...( existing || { } ) ,
137
+ content : JSON . stringify ( [
138
+ ...tokens ,
139
+ ...( existing ?. content || [ ] ) ,
140
+ ] )
141
+ } ) ) ;
142
+ } )
79
143
}
80
144
}
81
145
@@ -446,7 +510,7 @@ class WindowIndicator implements IWindowIndicator {
446
510
/**
447
511
* If the value begins with a slash assume it is a file path and convert it to
448
512
* use the vscode-remote scheme.
449
- *
513
+ *
450
514
* We also add the remote authority in toRemote. It needs to be accurate
451
515
* otherwise other URIs won't match it, leading to issues such as this one:
452
516
* https://github.com/coder/code-server/issues/4630
0 commit comments