119 lines
4.6 KiB
Diff
119 lines
4.6 KiB
Diff
|
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 || []),
|
||
|
+ ])
|
||
|
+ }));
|
||
|
+ })
|
||
|
}
|
||
|
}
|
||
|
|