mirror of
https://github.com/microsoft/vscode.git
synced 2025-12-26 13:19:42 +00:00
Implement GitHub Enterprise authn provider (#115940)
This commit is contained in:
@@ -10,6 +10,7 @@ import { v4 as uuid } from 'uuid';
|
||||
import { PromiseAdapter, promiseFromEvent } from './common/utils';
|
||||
import Logger from './common/logger';
|
||||
import { ExperimentationTelemetry } from './experimentationService';
|
||||
import { AuthProviderType } from './github';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
@@ -25,10 +26,6 @@ class UriEventHandler extends vscode.EventEmitter<vscode.Uri> implements vscode.
|
||||
|
||||
export const uriHandler = new UriEventHandler;
|
||||
|
||||
const onDidManuallyProvideToken = new vscode.EventEmitter<string | undefined>();
|
||||
|
||||
|
||||
|
||||
function parseQuery(uri: vscode.Uri) {
|
||||
return uri.query.split('&').reduce((prev: any, current) => {
|
||||
const queryString = current.split('=');
|
||||
@@ -39,14 +36,15 @@ function parseQuery(uri: vscode.Uri) {
|
||||
|
||||
export class GitHubServer {
|
||||
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> }>();
|
||||
|
||||
constructor(private readonly telemetryReporter: ExperimentationTelemetry) { }
|
||||
constructor(private type: AuthProviderType, private readonly telemetryReporter: ExperimentationTelemetry) { }
|
||||
|
||||
private isTestEnvironment(url: vscode.Uri): boolean {
|
||||
return /\.azurewebsites\.net$/.test(url.authority) || url.authority.startsWith('localhost:');
|
||||
return this.type === AuthProviderType['github-enterprise'] || /\.azurewebsites\.net$/.test(url.authority) || url.authority.startsWith('localhost:');
|
||||
}
|
||||
|
||||
// TODO@joaomoreno TODO@RMacfarlane
|
||||
@@ -104,7 +102,7 @@ export class GitHubServer {
|
||||
|
||||
return Promise.race([
|
||||
codeExchangePromise.promise,
|
||||
promiseFromEvent<string | undefined, string>(onDidManuallyProvideToken.event, (token: string | undefined, resolve, reject): void => {
|
||||
promiseFromEvent<string | undefined, string>(this._onDidManuallyProvideToken.event, (token: string | undefined, resolve, reject): void => {
|
||||
if (!token) {
|
||||
reject('Cancelled');
|
||||
} else {
|
||||
@@ -164,11 +162,30 @@ export class GitHubServer {
|
||||
}
|
||||
};
|
||||
|
||||
private getServerUri(path?: string) {
|
||||
const apiUri = this.type === AuthProviderType['github-enterprise']
|
||||
? vscode.Uri.parse(vscode.workspace.getConfiguration('github-enterprise').get<string>('uri') || '', true)
|
||||
: vscode.Uri.parse('https://api.github.com');
|
||||
|
||||
if (!path) {
|
||||
path = '';
|
||||
}
|
||||
if (this.type === AuthProviderType['github-enterprise']) {
|
||||
path = '/api/v3' + path;
|
||||
}
|
||||
|
||||
return vscode.Uri.parse(`${apiUri.scheme}://${apiUri.authority}${path}`);
|
||||
}
|
||||
|
||||
private updateStatusBarItem(isStart?: boolean) {
|
||||
if (isStart && !this._statusBarItem) {
|
||||
this._statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
|
||||
this._statusBarItem.text = localize('signingIn', "$(mark-github) Signing in to github.com...");
|
||||
this._statusBarItem.command = 'github.provide-token';
|
||||
this._statusBarItem.text = this.type === AuthProviderType.github
|
||||
? localize('signingIn', "$(mark-github) Signing in to github.com...")
|
||||
: localize('signingInEnterprise', "$(mark-github) Signing in to {0}...", this.getServerUri().authority);
|
||||
this._statusBarItem.command = this.type === AuthProviderType.github
|
||||
? 'github.provide-token'
|
||||
: 'github-enterprise.provide-token';
|
||||
this._statusBarItem.show();
|
||||
}
|
||||
|
||||
@@ -181,7 +198,7 @@ export class GitHubServer {
|
||||
public async manuallyProvideToken() {
|
||||
const uriOrToken = await vscode.window.showInputBox({ prompt: 'Token', ignoreFocusOut: true });
|
||||
if (!uriOrToken) {
|
||||
onDidManuallyProvideToken.fire(undefined);
|
||||
this._onDidManuallyProvideToken.fire(undefined);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -192,14 +209,14 @@ export class GitHubServer {
|
||||
} catch (e) {
|
||||
// If it doesn't look like a URI, treat it as a token.
|
||||
Logger.info('Treating input as token');
|
||||
onDidManuallyProvideToken.fire(uriOrToken);
|
||||
this._onDidManuallyProvideToken.fire(uriOrToken);
|
||||
}
|
||||
}
|
||||
|
||||
private async getScopes(token: string): Promise<string[]> {
|
||||
try {
|
||||
Logger.info('Getting token scopes...');
|
||||
const result = await fetch('https://api.github.com', {
|
||||
const result = await fetch(this.getServerUri('/').toString(), {
|
||||
headers: {
|
||||
Authorization: `token ${token}`,
|
||||
'User-Agent': 'Visual-Studio-Code'
|
||||
@@ -223,7 +240,7 @@ export class GitHubServer {
|
||||
let result: Response;
|
||||
try {
|
||||
Logger.info('Getting user info...');
|
||||
result = await fetch('https://api.github.com/user', {
|
||||
result = await fetch(this.getServerUri('/user').toString(), {
|
||||
headers: {
|
||||
Authorization: `token ${token}`,
|
||||
'User-Agent': 'Visual-Studio-Code'
|
||||
@@ -279,6 +296,34 @@ export class GitHubServer {
|
||||
} catch (e) {
|
||||
// No-op
|
||||
}
|
||||
}
|
||||
|
||||
public async checkEnterpriseVersion(token: string): Promise<void> {
|
||||
try {
|
||||
|
||||
const result = await fetch(this.getServerUri('/meta').toString(), {
|
||||
headers: {
|
||||
Authorization: `token ${token}`,
|
||||
'User-Agent': 'Visual-Studio-Code'
|
||||
}
|
||||
});
|
||||
|
||||
if (!result.ok) {
|
||||
return;
|
||||
}
|
||||
|
||||
const json: { verifiable_password_authentication: boolean, installed_version: string } = await result.json();
|
||||
|
||||
/* __GDPR__
|
||||
"ghe-session" : {
|
||||
"version": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
}
|
||||
*/
|
||||
this.telemetryReporter.sendTelemetryEvent('ghe-session', {
|
||||
version: json.installed_version
|
||||
});
|
||||
} catch {
|
||||
// No-op
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user