From 2dab7cfcdfd28a43cb4d39364c9dbf75f8441e56 Mon Sep 17 00:00:00 2001 From: Baptiste Augrain <daiyam@zokugun.org> Date: Thu, 3 Feb 2022 21:46:31 +0100 Subject: [PATCH] fix(1.64): update patch (#988) --- build/linux/appimage/build.sh | 4 +- patches/use-github-pat.patch | 247 +++++++++++++++++++++++++++------- 2 files changed, 198 insertions(+), 53 deletions(-) diff --git a/build/linux/appimage/build.sh b/build/linux/appimage/build.sh index 1b126b7..3b297a1 100755 --- a/build/linux/appimage/build.sh +++ b/build/linux/appimage/build.sh @@ -19,10 +19,10 @@ if [[ "$VSCODE_ARCH" == "x64" ]]; then sed -i 's/grep docker/# grep docker/' pkg2appimage.AppDir/usr/share/pkg2appimage/functions.sh bash -ex pkg2appimage.AppDir/AppRun recipe.yml - + rm -f pkg2appimage-*.AppImage rm -rf pkg2appimage.AppDir rm -rf VSCodium fi -cd "${CALLER_DIR}" \ No newline at end of file +cd "${CALLER_DIR}" diff --git a/patches/use-github-pat.patch b/patches/use-github-pat.patch index 81af3c5..5e84cac 100644 --- a/patches/use-github-pat.patch +++ b/patches/use-github-pat.patch @@ -1,9 +1,12 @@ diff --git a/extensions/github-authentication/src/githubServer.ts b/extensions/github-authentication/src/githubServer.ts -index fe0fbfd..656d8bb 100644 +index 3002e937c81..9674d8d2089 100644 --- a/extensions/github-authentication/src/githubServer.ts +++ b/extensions/github-authentication/src/githubServer.ts -@@ -6,8 +6,6 @@ - import * as nls from 'vscode-nls'; +@@ -3,41 +3,13 @@ + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +-import * as nls from 'vscode-nls'; import * as vscode from 'vscode'; import fetch, { Response } from 'node-fetch'; -import { v4 as uuid } from 'uuid'; @@ -11,19 +14,26 @@ index fe0fbfd..656d8bb 100644 import { ExperimentationTelemetry } from './experimentationService'; import { AuthProviderType } from './github'; import { Log } from './common/logger'; -@@ -15,8 +13,6 @@ import { Log } from './common/logger'; - const localize = nls.loadMessageBundle(); +-import { isSupportedEnvironment } from './common/env'; +- +-const localize = nls.loadMessageBundle(); +-const CLIENT_ID = '01ab8ac9400c4e429b23'; const NETWORK_ERROR = 'network error'; -const AUTH_RELAY_SERVER = 'vscode-auth.github.com'; -// const AUTH_RELAY_STAGING_SERVER = 'client-auth-staging-14a768b.herokuapp.com'; - - class UriEventHandler extends vscode.EventEmitter<vscode.Uri> implements vscode.UriHandler { - constructor(private readonly Logger: Log) { -@@ -29,14 +25,6 @@ class UriEventHandler extends vscode.EventEmitter<vscode.Uri> implements vscode. - } - } - +- +-class UriEventHandler extends vscode.EventEmitter<vscode.Uri> implements vscode.UriHandler { +- constructor(private readonly Logger: Log) { +- super(); +- } +- +- public handleUri(uri: vscode.Uri) { +- this.Logger.trace('Handling Uri...'); +- this.fire(uri); +- } +-} +- -function parseQuery(uri: vscode.Uri) { - return uri.query.split('&').reduce((prev: any, current) => { - const queryString = current.split('='); @@ -31,44 +41,64 @@ index fe0fbfd..656d8bb 100644 - return prev; - }, {}); -} -- + export interface IGitHubServer extends vscode.Disposable { login(scopes: string): Promise<string>; - getUserInfo(token: string): Promise<{ id: string, accountName: string }>; -@@ -96,11 +84,7 @@ async function getUserInfo(token: string, serverUri: vscode.Uri, logger: Log): P +@@ -47,13 +19,6 @@ export interface IGitHubServer extends vscode.Disposable { + type: AuthProviderType; + } + +-interface IGitHubDeviceCodeResponse { +- device_code: string; +- user_code: string; +- verification_uri: string; +- interval: number; +-} +- + async function getScopes(token: string, serverUri: vscode.Uri, logger: Log): Promise<string[]> { + try { + logger.info('Getting token scopes...'); +@@ -115,315 +80,49 @@ async function getUserInfo(token: string, serverUri: vscode.Uri, logger: Log): P export class GitHubServer implements IGitHubServer { friendlyName = 'GitHub'; type = AuthProviderType.github; - private _statusBarItem: vscode.StatusBarItem | undefined; - private _onDidManuallyProvideToken = new vscode.EventEmitter<string | undefined>(); - +- - private _pendingStates = new Map<string, string[]>(); - private _codeExchangePromises = new Map<string, { promise: Promise<string>, cancel: vscode.EventEmitter<void> }>(); - private _statusBarCommandId = `${this.type}.provide-manually`; - private _disposable: vscode.Disposable; - private _uriHandler = new UriEventHandler(this._logger); -@@ -115,137 +99,35 @@ export class GitHubServer implements IGitHubServer { - this._disposable.dispose(); +- private _statusBarCommandId = `${this.type}.provide-manually`; +- private _disposable: vscode.Disposable; +- private _uriHandler = new UriEventHandler(this._logger); + + constructor(private readonly _supportDeviceCodeFlow: boolean, private readonly _logger: Log, private readonly _telemetryReporter: ExperimentationTelemetry) { +- this._disposable = vscode.Disposable.from( +- vscode.commands.registerCommand(this._statusBarCommandId, () => this.manuallyProvideUri()), +- vscode.window.registerUriHandler(this._uriHandler)); ++ this._supportDeviceCodeFlow; } -- private isTestEnvironment(url: vscode.Uri): boolean { -- return /\.azurewebsites\.net$/.test(url.authority) || url.authority.startsWith('localhost:'); + dispose() { +- this._disposable.dispose(); - } - - // TODO@joaomoreno TODO@TylerLeonhardt - private async isNoCorsEnvironment(): Promise<boolean> { - const uri = await vscode.env.asExternalUri(vscode.Uri.parse(`${vscode.env.uriScheme}://vscode.github-authentication/dummy`)); - return (uri.scheme === 'https' && /^((insiders\.)?vscode|github)\./.test(uri.authority)) || (uri.scheme === 'http' && /^localhost/.test(uri.authority)); -- } -- + } + public async login(scopes: string): Promise<string> { this._logger.info(`Logging in for the following scopes: ${scopes}`); - const callbackUri = await vscode.env.asExternalUri(vscode.Uri.parse(`${vscode.env.uriScheme}://vscode.github-authentication/did-authenticate`)); - -- if (this.isTestEnvironment(callbackUri)) { -- const token = await vscode.window.showInputBox({ prompt: 'GitHub Personal Access Token', ignoreFocusOut: true }); -- if (!token) { throw new Error('Sign in failed: No token provided'); } +- if (!isSupportedEnvironment(callbackUri)) { +- const token = this._supportDeviceCodeFlow +- ? await this.doDeviceCodeFlow(scopes) +- : await vscode.window.showInputBox({ prompt: 'GitHub Personal Access Token', ignoreFocusOut: true }); +- +- if (!token) { throw new Error('No token provided'); } - - const tokenScopes = await getScopes(token, this.getServerUri('/'), this._logger); // Example: ['repo', 'user'] - const scopesList = scopes.split(' '); // Example: 'read:user repo user:email' @@ -77,22 +107,14 @@ index fe0fbfd..656d8bb 100644 - if (included || !scope.includes(':')) { - return included; - } -+ const token = await vscode.window.showInputBox({ prompt: 'GitHub Personal Access Token', ignoreFocusOut: true }); -+ if (!token) { throw new Error('Sign in failed: No token provided'); } - +- - return scope.split(':').some(splitScopes => { - return tokenScopes.includes(splitScopes); - }); - })) { - throw new Error(`The provided token does not match the requested scopes: ${scopes}`); -+ const tokenScopes = await getScopes(token, this.getServerUri('/'), this._logger); // Example: ['repo', 'user'] -+ const scopesList = scopes.split(' '); // Example: 'read:user repo user:email' -+ if (!scopesList.every(scope => { -+ const included = tokenScopes.includes(scope); -+ if (included || !scope.includes(':')) { -+ return included; - } - +- } +- - return token; - } - @@ -111,13 +133,8 @@ index fe0fbfd..656d8bb 100644 - if (!codeExchangePromise) { - codeExchangePromise = promiseFromEvent(this._uriHandler.event, this.exchangeCodeForToken(scopes)); - this._codeExchangePromises.set(scopes, codeExchangePromise); -+ return scope.split(':').some(splitScopes => { -+ return tokenScopes.includes(splitScopes); -+ }); -+ })) { -+ throw new Error(`The provided token does not match the requested scopes: ${scopes}`); - } - +- } +- - return Promise.race([ - codeExchangePromise.promise, - promiseFromEvent<string | undefined, string>(this._onDidManuallyProvideToken.event, (token: string | undefined, resolve, reject): void => { @@ -134,6 +151,110 @@ index fe0fbfd..656d8bb 100644 - this._codeExchangePromises.delete(scopes); - this.updateStatusBarItem(false); - }); +- } +- +- private async doDeviceCodeFlow(scopes: string): Promise<string> { +- // Get initial device code +- const uri = `https://github.com/login/device/code?client_id=${CLIENT_ID}&scope=${scopes}`; +- const result = await fetch(uri, { +- method: 'POST', +- headers: { +- Accept: 'application/json' +- } +- }); +- if (!result.ok) { +- throw new Error(`Failed to get one-time code: ${await result.text()}`); +- } +- +- const json = await result.json() as IGitHubDeviceCodeResponse; +- +- +- const modalResult = await vscode.window.showInformationMessage( +- localize('code.title', "Your Code: {0}", json.user_code), +- { +- modal: true, +- detail: localize('code.detail', "To finish authenticating, navigate to GitHub and paste in the above one-time code.") +- }, 'Copy & Continue to GitHub'); +- +- if (modalResult !== 'Copy & Continue to GitHub') { +- throw new Error('Cancelled'); +- } +- +- await vscode.env.clipboard.writeText(json.user_code); +- +- const uriToOpen = await vscode.env.asExternalUri(vscode.Uri.parse(json.verification_uri)); +- await vscode.env.openExternal(uriToOpen); +- +- return await vscode.window.withProgress<string>({ +- location: vscode.ProgressLocation.Notification, +- cancellable: true, +- title: localize( +- 'progress', +- "Open [{0}]({0}) in a new tab and paste your one-time code: {1}", +- json.verification_uri, +- json.user_code) +- }, async (_, token) => { +- return await this.waitForDeviceCodeAccessToken(json, token); +- }); +- } +- +- private async waitForDeviceCodeAccessToken( +- json: IGitHubDeviceCodeResponse, +- token: vscode.CancellationToken +- ): Promise<string> { +- +- const refreshTokenUri = `https://github.com/login/oauth/access_token?client_id=${CLIENT_ID}&device_code=${json.device_code}&grant_type=urn:ietf:params:oauth:grant-type:device_code`; +- +- // Try for 2 minutes +- const attempts = 120 / json.interval; +- for (let i = 0; i < attempts; i++) { +- await new Promise(resolve => setTimeout(resolve, json.interval * 1000)); +- if (token.isCancellationRequested) { +- throw new Error('Cancelled'); +- } +- let accessTokenResult; +- try { +- accessTokenResult = await fetch(refreshTokenUri, { +- method: 'POST', +- headers: { +- Accept: 'application/json' +- } +- }); +- } catch { +- continue; +- } +- +- if (!accessTokenResult.ok) { +- continue; +- } ++ const token = await vscode.window.showInputBox({ prompt: 'GitHub Personal Access Token', ignoreFocusOut: true }); + +- const accessTokenJson = await accessTokenResult.json(); ++ if (!token) { throw new Error('No token provided'); } + +- if (accessTokenJson.error === 'authorization_pending') { +- continue; +- } +- +- if (accessTokenJson.error) { +- throw new Error(accessTokenJson.error_description); ++ const tokenScopes = await getScopes(token, this.getServerUri('/'), this._logger); // Example: ['repo', 'user'] ++ const scopesList = scopes.split(' '); // Example: 'read:user repo user:email' ++ if (!scopesList.every(scope => { ++ const included = tokenScopes.includes(scope); ++ if (included || !scope.includes(':')) { ++ return included; + } + +- return accessTokenJson.access_token; ++ return scope.split(':').some(splitScopes => { ++ return tokenScopes.includes(splitScopes); ++ }); ++ })) { ++ throw new Error(`The provided token does not match the requested scopes: ${scopes}`); + } + +- throw new Error('Cancelled'); + return token; } @@ -196,10 +317,34 @@ index fe0fbfd..656d8bb 100644 - } - } - - private async manuallyProvideUri() { - const uri = await vscode.window.showInputBox({ - prompt: 'Uri', -@@ -277,44 +159,7 @@ export class GitHubServer implements IGitHubServer { +- private async manuallyProvideUri() { +- const uri = await vscode.window.showInputBox({ +- prompt: 'Uri', +- ignoreFocusOut: true, +- validateInput(value) { +- if (!value) { +- return undefined; +- } +- const error = localize('validUri', "Please enter a valid Uri from the GitHub login page."); +- try { +- const uri = vscode.Uri.parse(value.trim()); +- if (!uri.scheme || uri.scheme === 'file') { +- return error; +- } +- } catch (e) { +- return error; +- } +- return undefined; +- } +- }); +- if (!uri) { +- return; +- } +- +- this._uriHandler.handleUri(vscode.Uri.parse(uri.trim())); +- } +- + public getUserInfo(token: string): Promise<{ id: string, accountName: string }> { return getUserInfo(token, this.getServerUri('/user'), this._logger); } @@ -241,7 +386,7 @@ index fe0fbfd..656d8bb 100644 - } catch (e) { - // No-op - } -+ public async sendAdditionalTelemetryInfo(_token: string): Promise<void> { ++ public async sendAdditionalTelemetryInfo(_: string): Promise<void> { } public async checkEnterpriseVersion(token: string): Promise<void> {