-
Notifications
You must be signed in to change notification settings - Fork 5.9k
/
Copy pathgithub-auth.diff
118 lines (109 loc) · 4.61 KB
/
github-auth.diff
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
Use our own GitHub auth relay server
Microsoft's does not work with self-hosted instances so we run our own.
Also add an extra set of scopes so that tokens provided via --github-auth will
work for the PR extension.
Index: code-server/lib/vscode/extensions/github-authentication/src/githubServer.ts
===================================================================
--- code-server.orig/lib/vscode/extensions/github-authentication/src/githubServer.ts
+++ code-server/lib/vscode/extensions/github-authentication/src/githubServer.ts
@@ -17,7 +17,7 @@ const localize = nls.loadMessageBundle()
const CLIENT_ID = '01ab8ac9400c4e429b23';
const NETWORK_ERROR = 'network error';
-const AUTH_RELAY_SERVER = 'vscode-auth.github.com';
+const AUTH_RELAY_SERVER = 'auth.code-server.dev';
// const AUTH_RELAY_STAGING_SERVER = 'client-auth-staging-14a768b.herokuapp.com';
class UriEventHandler extends vscode.EventEmitter<vscode.Uri> implements vscode.UriHandler {
Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts
+++ code-server/lib/vscode/src/vs/server/node/webClientServer.ts
@@ -274,7 +274,7 @@ export class WebClientServer {
id: generateUuid(),
providerId: 'github',
accessToken: this._environmentService.args['github-auth'],
- scopes: [['user:email'], ['repo']]
+ scopes: [['read:user', 'user:email', 'repo'], ['user:email'], ['repo']]
} : undefined;
const base = relativeRoot(getOriginalUrl(req))
const vscodeBase = relativePath(getOriginalUrl(req))
Index: code-server/lib/vscode/src/vs/code/browser/workbench/workbench.ts
===================================================================
--- code-server.orig/lib/vscode/src/vs/code/browser/workbench/workbench.ts
+++ code-server/lib/vscode/src/vs/code/browser/workbench/workbench.ts
@@ -17,6 +17,7 @@ import { isFolderToOpen, isWorkspaceToOp
import { create, ICredentialsProvider, IURLCallbackProvider, IWorkbenchConstructionOptions, IWorkspace, IWorkspaceProvider } from 'vs/workbench/workbench.web.main';
import { posix } from 'vs/base/common/path';
import { ltrim } from 'vs/base/common/strings';
+import { equals as arrayEquals } from 'vs/base/common/arrays';
interface ICredential {
service: string;
@@ -24,6 +25,13 @@ interface ICredential {
password: string;
}
+interface IToken {
+ accessToken: string
+ account?: { label: string }
+ id: string
+ scopes: string[]
+}
+
class LocalStorageCredentialsProvider implements ICredentialsProvider {
private static readonly CREDENTIALS_STORAGE_KEY = 'credentials.provider';
@@ -51,6 +59,58 @@ class LocalStorageCredentialsProvider im
scopes,
accessToken: authSessionInfo!.accessToken
}))));
+
+ // Add tokens for extensions to use. This works for extensions like the
+ // pull requests one or GitLens.
+ const extensionId = `vscode.${authSessionInfo.providerId}-authentication`;
+ const service = `${product.urlProtocol}${extensionId}`;
+ const account = `${authSessionInfo.providerId}.auth`;
+ // Oddly the scopes need to match exactly so we cannot just have one token
+ // with all the scopes, instead we have to duplicate the token for each
+ // expected set of scopes.
+ const tokens: IToken[] = authSessionInfo.scopes.map((scopes) => ({
+ id: authSessionInfo!.id,
+ scopes: scopes.sort(), // Sort for comparing later.
+ accessToken: authSessionInfo!.accessToken,
+ }));
+ this.getPassword(service, account).then((raw) => {
+ let existing: {
+ content: IToken[]
+ } | undefined;
+
+ if (raw) {
+ try {
+ const json = JSON.parse(raw);
+ json.content = JSON.parse(json.content);
+ existing = json;
+ } catch (error) {
+ console.log(error);
+ }
+ }
+
+ // Keep tokens for account and scope combinations we do not have in case
+ // there is an extension that uses scopes we have not accounted for (in
+ // these cases the user will need to manually authenticate the extension
+ // through the UI) or the user has tokens for other accounts.
+ if (existing?.content) {
+ existing.content = existing.content.filter((existingToken) => {
+ const scopes = existingToken.scopes.sort();
+ return !(tokens.find((token) => {
+ return arrayEquals(scopes, token.scopes)
+ && token.account?.label === existingToken.account?.label;
+ }))
+ })
+ }
+
+ return this.setPassword(service, account, JSON.stringify({
+ extensionId,
+ ...(existing || {}),
+ content: JSON.stringify([
+ ...tokens,
+ ...(existing?.content || []),
+ ])
+ }));
+ })
}
}