Skip to content

Commit 956f523

Browse files
committed
Update github-auth patch
The local credentials provider is no longer used when there is a remote so this code moved into the backend web credential provider.
1 parent 694c44b commit 956f523

File tree

1 file changed

+91
-89
lines changed

1 file changed

+91
-89
lines changed

patches/github-auth.diff

+91-89
Original file line numberDiff line numberDiff line change
@@ -1,105 +1,107 @@
1-
Use our own GitHub auth relay server
1+
Add the ability to provide a GitHub token
22

3-
Microsoft's does not work with self-hosted instances so we run our own.
3+
To test install the GitHub PR extension and start code-server with GITHUB_TOKEN
4+
or set github-auth in the config file. The extension should be authenticated.
45

5-
Also add an extra set of scopes so that tokens provided via --github-auth will
6-
work for the PR extension.
7-
8-
Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts
9-
===================================================================
10-
--- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts
11-
+++ code-server/lib/vscode/src/vs/server/node/webClientServer.ts
12-
@@ -277,7 +277,7 @@ export class WebClientServer {
13-
id: generateUuid(),
14-
providerId: 'github',
15-
accessToken: this._environmentService.args['github-auth'],
16-
- scopes: [['user:email'], ['repo']]
17-
+ scopes: [['read:user', 'user:email', 'repo'], ['user:email'], ['repo']]
18-
} : undefined;
19-
const base = relativeRoot(getOriginalUrl(req))
20-
const vscodeBase = relativePath(getOriginalUrl(req))
21-
Index: code-server/lib/vscode/src/vs/code/browser/workbench/workbench.ts
6+
Index: code-server/lib/vscode/src/vs/platform/credentials/node/credentialsMainService.ts
227
===================================================================
23-
--- code-server.orig/lib/vscode/src/vs/code/browser/workbench/workbench.ts
24-
+++ code-server/lib/vscode/src/vs/code/browser/workbench/workbench.ts
25-
@@ -17,6 +17,7 @@ import { isFolderToOpen, isWorkspaceToOp
26-
import { create, ICredentialsProvider, IURLCallbackProvider, IWorkbenchConstructionOptions, IWorkspace, IWorkspaceProvider } from 'vs/workbench/workbench.web.main';
27-
import { posix } from 'vs/base/common/path';
28-
import { ltrim } from 'vs/base/common/strings';
29-
+import { equals as arrayEquals } from 'vs/base/common/arrays';
30-
31-
interface ICredential {
32-
service: string;
33-
@@ -24,6 +25,13 @@ interface ICredential {
34-
password: string;
35-
}
8+
--- code-server.orig/lib/vscode/src/vs/platform/credentials/node/credentialsMainService.ts
9+
+++ code-server/lib/vscode/src/vs/platform/credentials/node/credentialsMainService.ts
10+
@@ -5,18 +5,32 @@
3611

12+
import { InMemoryCredentialsProvider } from 'vs/platform/credentials/common/credentials';
13+
import { ILogService } from 'vs/platform/log/common/log';
14+
-import { INativeEnvironmentService } from 'vs/platform/environment/common/environment';
15+
+import { IServerEnvironmentService } from 'vs/server/node/serverEnvironmentService';
16+
import { IProductService } from 'vs/platform/product/common/productService';
17+
import { BaseCredentialsMainService, KeytarModule } from 'vs/platform/credentials/common/credentialsMainService';
18+
+import { generateUuid } from 'vs/base/common/uuid';
19+
+import { equals as arrayEquals } from 'vs/base/common/arrays';
20+
+
3721
+interface IToken {
3822
+ accessToken: string
3923
+ account?: { label: string }
4024
+ id: string
4125
+ scopes: string[]
4226
+}
43-
+
44-
class LocalStorageCredentialsProvider implements ICredentialsProvider {
4527

46-
private static readonly CREDENTIALS_STORAGE_KEY = 'credentials.provider';
47-
@@ -51,6 +59,58 @@ class LocalStorageCredentialsProvider im
48-
scopes,
49-
accessToken: authSessionInfo!.accessToken
50-
}))));
28+
export class CredentialsWebMainService extends BaseCredentialsMainService {
29+
30+
constructor(
31+
@ILogService logService: ILogService,
32+
- @INativeEnvironmentService private readonly environmentMainService: INativeEnvironmentService,
33+
+ @IServerEnvironmentService private readonly environmentMainService: IServerEnvironmentService,
34+
@IProductService private readonly productService: IProductService,
35+
) {
36+
super(logService);
37+
+ if (this.environmentMainService.args["github-auth"]) {
38+
+ this.storeGitHubToken(this.environmentMainService.args["github-auth"]).catch((error) => {
39+
+ this.logService.error('Failed to store provided GitHub token', error)
40+
+ })
41+
+ }
42+
}
43+
44+
// If the credentials service is running on the server, we add a suffix -server to differentiate from the location that the
45+
@@ -45,4 +59,62 @@ export class CredentialsWebMainService e
46+
}
47+
return this._keytarCache;
48+
}
49+
+
50+
+ /**
51+
+ * Authenticate the GitHub authentication extension with CLI arguments.
52+
+ */
53+
+ private async storeGitHubToken(githubToken: string): Promise<void> {
54+
+ const extensionId = 'vscode.github-authentication';
55+
+ const service = `${await this.getSecretStoragePrefix()}${extensionId}`;
56+
+ const account = 'github.auth';
57+
+ const scopes = [['read:user', 'user:email', 'repo']]
58+
+
59+
+ // Oddly the scopes need to match exactly so we cannot just have one token
60+
+ // with all the scopes, instead we have to duplicate the token for each
61+
+ // expected set of scopes.
62+
+ const tokens: IToken[] = scopes.map((scopes) => ({
63+
+ id: generateUuid(),
64+
+ scopes: scopes.sort(), // Sort for comparing later.
65+
+ accessToken: githubToken,
66+
+ }));
5167
+
52-
+ // Add tokens for extensions to use. This works for extensions like the
53-
+ // pull requests one or GitLens.
54-
+ const extensionId = `vscode.${authSessionInfo.providerId}-authentication`;
55-
+ const service = `${product.urlProtocol}${extensionId}`;
56-
+ const account = `${authSessionInfo.providerId}.auth`;
57-
+ // Oddly the scopes need to match exactly so we cannot just have one token
58-
+ // with all the scopes, instead we have to duplicate the token for each
59-
+ // expected set of scopes.
60-
+ const tokens: IToken[] = authSessionInfo.scopes.map((scopes) => ({
61-
+ id: authSessionInfo!.id,
62-
+ scopes: scopes.sort(), // Sort for comparing later.
63-
+ accessToken: authSessionInfo!.accessToken,
64-
+ }));
65-
+ this.getPassword(service, account).then((raw) => {
66-
+ let existing: {
67-
+ content: IToken[]
68-
+ } | undefined;
68+
+ const raw = await this.getPassword(service, account)
6969
+
70-
+ if (raw) {
71-
+ try {
72-
+ const json = JSON.parse(raw);
73-
+ json.content = JSON.parse(json.content);
74-
+ existing = json;
75-
+ } catch (error) {
76-
+ console.log(error);
77-
+ }
78-
+ }
70+
+ let existing: {
71+
+ content: IToken[]
72+
+ } | undefined;
7973
+
80-
+ // Keep tokens for account and scope combinations we do not have in case
81-
+ // there is an extension that uses scopes we have not accounted for (in
82-
+ // these cases the user will need to manually authenticate the extension
83-
+ // through the UI) or the user has tokens for other accounts.
84-
+ if (existing?.content) {
85-
+ existing.content = existing.content.filter((existingToken) => {
86-
+ const scopes = existingToken.scopes.sort();
87-
+ return !(tokens.find((token) => {
88-
+ return arrayEquals(scopes, token.scopes)
89-
+ && token.account?.label === existingToken.account?.label;
90-
+ }))
91-
+ })
92-
+ }
74+
+ if (raw) {
75+
+ try {
76+
+ const json = JSON.parse(raw);
77+
+ json.content = JSON.parse(json.content);
78+
+ existing = json;
79+
+ } catch (error) {
80+
+ this.logService.error('Failed to parse existing GitHub credentials', error)
81+
+ }
82+
+ }
9383
+
94-
+ return this.setPassword(service, account, JSON.stringify({
95-
+ extensionId,
96-
+ ...(existing || {}),
97-
+ content: JSON.stringify([
98-
+ ...tokens,
99-
+ ...(existing?.content || []),
100-
+ ])
101-
+ }));
84+
+ // Keep tokens for account and scope combinations we do not have in case
85+
+ // there is an extension that uses scopes we have not accounted for (in
86+
+ // these cases the user will need to manually authenticate the extension
87+
+ // through the UI) or the user has tokens for other accounts.
88+
+ if (existing?.content) {
89+
+ existing.content = existing.content.filter((existingToken) => {
90+
+ const scopes = existingToken.scopes.sort();
91+
+ return !(tokens.find((token) => {
92+
+ return arrayEquals(scopes, token.scopes)
93+
+ && token.account?.label === existingToken.account?.label;
94+
+ }))
10295
+ })
103-
}
104-
}
105-
96+
+ }
97+
+
98+
+ return this.setPassword(service, account, JSON.stringify({
99+
+ extensionId,
100+
+ ...(existing || {}),
101+
+ content: JSON.stringify([
102+
+ ...tokens,
103+
+ ...(existing?.content || []),
104+
+ ])
105+
+ }));
106+
+ }
107+
}

0 commit comments

Comments
 (0)