mirror of
https://github.com/Microsoft/vscode
synced 2024-10-02 17:32:41 +00:00
Try to revoke tokens that are getting deleted
Best effort. Fixes https://github.com/microsoft/vscode/issues/152055
This commit is contained in:
parent
c59a7a21f7
commit
ac27273e48
|
@ -21,7 +21,8 @@ module.exports = withBrowserDefaults({
|
|||
'uuid': path.resolve(__dirname, 'node_modules/uuid/dist/esm-browser/index.js'),
|
||||
'./node/authServer': path.resolve(__dirname, 'src/browser/authServer'),
|
||||
'./node/crypto': path.resolve(__dirname, 'src/browser/crypto'),
|
||||
'./node/fetch': path.resolve(__dirname, 'src/browser/fetch')
|
||||
'./node/fetch': path.resolve(__dirname, 'src/browser/fetch'),
|
||||
'./node/buffer': path.resolve(__dirname, 'src/browser/buffer'),
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
8
extensions/github-authentication/src/browser/buffer.ts
Normal file
8
extensions/github-authentication/src/browser/buffer.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export function base64Encode(text: string): string {
|
||||
return btoa(text);
|
||||
}
|
|
@ -26,4 +26,7 @@ export class Log {
|
|||
this.output.error(message);
|
||||
}
|
||||
|
||||
public warn(message: string): void {
|
||||
this.output.warn(message);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -201,7 +201,8 @@ const allFlows: IFlow[] = [
|
|||
supportsGitHubEnterpriseServer: false,
|
||||
supportsHostedGitHubEnterprise: true,
|
||||
supportsRemoteExtensionHost: true,
|
||||
supportsWebWorkerExtensionHost: true,
|
||||
// Web worker can't open a port to listen for the redirect
|
||||
supportsWebWorkerExtensionHost: false,
|
||||
// exchanging a code for a token requires a client secret
|
||||
supportsNoClientSecret: false,
|
||||
supportsSupportedClients: true,
|
||||
|
|
|
@ -363,6 +363,7 @@ export class GitHubAuthenticationProvider implements vscode.AuthenticationProvid
|
|||
sessions.splice(sessionIndex, 1);
|
||||
|
||||
await this.storeSessions(sessions);
|
||||
await this._githubServer.logout(session);
|
||||
|
||||
this._sessionChangeEmitter.fire({ added: [], removed: [session], changed: [] });
|
||||
} else {
|
||||
|
|
|
@ -12,6 +12,8 @@ import { crypto } from './node/crypto';
|
|||
import { fetching } from './node/fetch';
|
||||
import { ExtensionHost, GitHubTarget, getFlows } from './flows';
|
||||
import { NETWORK_ERROR, USER_CANCELLATION_ERROR } from './common/errors';
|
||||
import { Config } from './config';
|
||||
import { base64Encode } from './node/buffer';
|
||||
|
||||
// This is the error message that we throw if the login was cancelled for any reason. Extensions
|
||||
// calling `getSession` can handle this error to know that the user cancelled the login.
|
||||
|
@ -22,6 +24,7 @@ const REDIRECT_URL_INSIDERS = 'https://insiders.vscode.dev/redirect';
|
|||
|
||||
export interface IGitHubServer {
|
||||
login(scopes: string): Promise<string>;
|
||||
logout(session: vscode.AuthenticationSession): Promise<void>;
|
||||
getUserInfo(token: string): Promise<{ id: string; accountName: string }>;
|
||||
sendAdditionalTelemetryInfo(session: vscode.AuthenticationSession): Promise<void>;
|
||||
friendlyName: string;
|
||||
|
@ -78,9 +81,14 @@ export class GitHubServer implements IGitHubServer {
|
|||
}
|
||||
|
||||
// TODO@joaomoreno TODO@TylerLeonhardt
|
||||
private _isNoCorsEnvironment: boolean | undefined;
|
||||
private async isNoCorsEnvironment(): Promise<boolean> {
|
||||
if (this._isNoCorsEnvironment !== undefined) {
|
||||
return this._isNoCorsEnvironment;
|
||||
}
|
||||
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));
|
||||
this._isNoCorsEnvironment = (uri.scheme === 'https' && /^((insiders\.)?vscode|github)\./.test(uri.authority)) || (uri.scheme === 'http' && /^localhost/.test(uri.authority));
|
||||
return this._isNoCorsEnvironment;
|
||||
}
|
||||
|
||||
public async login(scopes: string): Promise<string> {
|
||||
|
@ -144,6 +152,58 @@ export class GitHubServer implements IGitHubServer {
|
|||
throw new Error(userCancelled ? CANCELLATION_ERROR : 'No auth flow succeeded.');
|
||||
}
|
||||
|
||||
public async logout(session: vscode.AuthenticationSession): Promise<void> {
|
||||
this._logger.trace(`Deleting session (${session.id}) from server...`);
|
||||
|
||||
if (!Config.gitHubClientSecret) {
|
||||
this._logger.warn('No client secret configured for GitHub authentication. The token has been deleted with best effort on this system, but we are unable to delete the token on server without the client secret.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Only attempt to delete OAuth tokens. They are always prefixed with `gho_`.
|
||||
// https://docs.github.com/en/rest/apps/oauth-applications#about-oauth-apps-and-oauth-authorizations-of-github-apps
|
||||
if (!session.accessToken.startsWith('gho_')) {
|
||||
this._logger.warn('The token being deleted is not an OAuth token. It has been deleted locally, but we cannot delete it on server.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isSupportedTarget(this._type, this._ghesUri)) {
|
||||
this._logger.trace('GitHub.com and GitHub hosted GitHub Enterprise are the only options that support deleting tokens on the server. Skipping.');
|
||||
return;
|
||||
}
|
||||
|
||||
const authHeader = 'Basic ' + base64Encode(`${Config.gitHubClientId}:${Config.gitHubClientSecret}`);
|
||||
const uri = this.getServerUri(`/applications/${Config.gitHubClientId}/token`);
|
||||
|
||||
try {
|
||||
// Defined here: https://docs.github.com/en/rest/apps/oauth-applications?apiVersion=2022-11-28#delete-an-app-token
|
||||
const result = await fetching(uri.toString(true), {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
Accept: 'application/vnd.github+json',
|
||||
Authorization: authHeader,
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
'User-Agent': `${vscode.env.appName} (${vscode.env.appHost})`
|
||||
},
|
||||
body: JSON.stringify({ access_token: session.accessToken }),
|
||||
});
|
||||
|
||||
if (result.status === 204) {
|
||||
this._logger.trace(`Successfully deleted token from session (${session.id}) from server.`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const body = await result.text();
|
||||
throw new Error(body);
|
||||
} catch (e) {
|
||||
throw new Error(`${result.status} ${result.statusText}`);
|
||||
}
|
||||
} catch (e) {
|
||||
this._logger.warn('Failed to delete token from server.' + e.message ?? e);
|
||||
}
|
||||
}
|
||||
|
||||
private getServerUri(path: string = '') {
|
||||
const apiUri = this.baseUri;
|
||||
// github.com and Hosted GitHub Enterprise instances
|
||||
|
|
8
extensions/github-authentication/src/node/buffer.ts
Normal file
8
extensions/github-authentication/src/node/buffer.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export function base64Encode(text: string): string {
|
||||
return Buffer.from(text, 'binary').toString('base64');
|
||||
}
|
Loading…
Reference in a new issue