mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-17 17:22:42 -05:00
Merge from vscode 5e80bf449c995aa32a59254c0ff845d37da11b70 (#9317)
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Uri } from 'vscode';
|
||||
|
||||
export interface ClientDetails {
|
||||
id?: string;
|
||||
secret?: string;
|
||||
}
|
||||
|
||||
export interface ClientConfig {
|
||||
OSS: ClientDetails;
|
||||
INSIDERS: ClientDetails;
|
||||
STABLE: ClientDetails;
|
||||
EXPLORATION: ClientDetails;
|
||||
|
||||
VSO: ClientDetails;
|
||||
VSO_PPE: ClientDetails;
|
||||
VSO_DEV: ClientDetails;
|
||||
}
|
||||
|
||||
export class Registrar {
|
||||
private _config: ClientConfig;
|
||||
|
||||
constructor() {
|
||||
try {
|
||||
this._config = require('./config.json') as ClientConfig;
|
||||
} catch (e) {
|
||||
this._config = {
|
||||
OSS: {},
|
||||
INSIDERS: {},
|
||||
STABLE: {},
|
||||
EXPLORATION: {},
|
||||
VSO: {},
|
||||
VSO_PPE: {},
|
||||
VSO_DEV: {}
|
||||
};
|
||||
}
|
||||
}
|
||||
getClientDetails(callbackUri: Uri): ClientDetails {
|
||||
let details: ClientDetails | undefined;
|
||||
switch (callbackUri.scheme) {
|
||||
case 'code-oss':
|
||||
details = this._config.OSS;
|
||||
break;
|
||||
|
||||
case 'vscode-insiders':
|
||||
details = this._config.INSIDERS;
|
||||
break;
|
||||
|
||||
case 'vscode':
|
||||
details = this._config.STABLE;
|
||||
break;
|
||||
|
||||
case 'vscode-exploration':
|
||||
details = this._config.EXPLORATION;
|
||||
break;
|
||||
|
||||
case 'https':
|
||||
switch (callbackUri.authority) {
|
||||
case 'online.visualstudio.com':
|
||||
details = this._config.VSO;
|
||||
break;
|
||||
case 'online-ppe.core.vsengsaas.visualstudio.com':
|
||||
details = this._config.VSO_PPE;
|
||||
break;
|
||||
case 'online.dev.core.vsengsaas.visualstudio.com':
|
||||
details = this._config.VSO_DEV;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw new Error(`Unrecognized callback ${callbackUri}`);
|
||||
}
|
||||
|
||||
if (!details.id || !details.secret) {
|
||||
throw new Error(`No client configuration available for ${callbackUri}`);
|
||||
}
|
||||
|
||||
return details;
|
||||
}
|
||||
}
|
||||
|
||||
const ClientRegistrar = new Registrar();
|
||||
export default ClientRegistrar;
|
||||
73
extensions/github-authentication/src/common/keychain.ts
Normal file
73
extensions/github-authentication/src/common/keychain.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
// keytar depends on a native module shipped in vscode, so this is
|
||||
// how we load it
|
||||
import * as keytarType from 'keytar';
|
||||
import { env } from 'vscode';
|
||||
import Logger from './logger';
|
||||
|
||||
function getKeytar(): Keytar | undefined {
|
||||
try {
|
||||
return require('keytar');
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export type Keytar = {
|
||||
getPassword: typeof keytarType['getPassword'];
|
||||
setPassword: typeof keytarType['setPassword'];
|
||||
deletePassword: typeof keytarType['deletePassword'];
|
||||
};
|
||||
|
||||
const SERVICE_ID = `${env.uriScheme}-github.login`;
|
||||
const ACCOUNT_ID = 'account';
|
||||
|
||||
export class Keychain {
|
||||
private keytar: Keytar;
|
||||
|
||||
constructor() {
|
||||
const keytar = getKeytar();
|
||||
if (!keytar) {
|
||||
throw new Error('System keychain unavailable');
|
||||
}
|
||||
|
||||
this.keytar = keytar;
|
||||
}
|
||||
|
||||
async setToken(token: string): Promise<void> {
|
||||
try {
|
||||
return await this.keytar.setPassword(SERVICE_ID, ACCOUNT_ID, token);
|
||||
} catch (e) {
|
||||
// Ignore
|
||||
Logger.error(`Setting token failed: ${e}`);
|
||||
}
|
||||
}
|
||||
|
||||
async getToken(): Promise<string | null | undefined> {
|
||||
try {
|
||||
return await this.keytar.getPassword(SERVICE_ID, ACCOUNT_ID);
|
||||
} catch (e) {
|
||||
// Ignore
|
||||
Logger.error(`Getting token failed: ${e}`);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
}
|
||||
|
||||
async deleteToken(): Promise<boolean | undefined> {
|
||||
try {
|
||||
return await this.keytar.deletePassword(SERVICE_ID, ACCOUNT_ID);
|
||||
} catch (e) {
|
||||
// Ignore
|
||||
Logger.error(`Deleting token failed: ${e}`);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const keychain = new Keychain();
|
||||
55
extensions/github-authentication/src/common/logger.ts
Normal file
55
extensions/github-authentication/src/common/logger.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
type LogLevel = 'Trace' | 'Info' | 'Error';
|
||||
|
||||
class Log {
|
||||
private output: vscode.OutputChannel;
|
||||
|
||||
constructor() {
|
||||
this.output = vscode.window.createOutputChannel('GitHub Authentication');
|
||||
}
|
||||
|
||||
private data2String(data: any): string {
|
||||
if (data instanceof Error) {
|
||||
return data.stack || data.message;
|
||||
}
|
||||
if (data.success === false && data.message) {
|
||||
return data.message;
|
||||
}
|
||||
return data.toString();
|
||||
}
|
||||
|
||||
public info(message: string, data?: any): void {
|
||||
this.logLevel('Info', message, data);
|
||||
}
|
||||
|
||||
public error(message: string, data?: any): void {
|
||||
this.logLevel('Error', message, data);
|
||||
}
|
||||
|
||||
public logLevel(level: LogLevel, message: string, data?: any): void {
|
||||
this.output.appendLine(`[${level} - ${this.now()}] ${message}`);
|
||||
if (data) {
|
||||
this.output.appendLine(this.data2String(data));
|
||||
}
|
||||
}
|
||||
|
||||
private now(): string {
|
||||
const now = new Date();
|
||||
return padLeft(now.getUTCHours() + '', 2, '0')
|
||||
+ ':' + padLeft(now.getMinutes() + '', 2, '0')
|
||||
+ ':' + padLeft(now.getUTCSeconds() + '', 2, '0') + '.' + now.getMilliseconds();
|
||||
}
|
||||
}
|
||||
|
||||
function padLeft(s: string, n: number, pad = ' ') {
|
||||
return pad.repeat(Math.max(0, n - s.length)) + s;
|
||||
}
|
||||
|
||||
const Logger = new Log();
|
||||
export default Logger;
|
||||
73
extensions/github-authentication/src/common/utils.ts
Normal file
73
extensions/github-authentication/src/common/utils.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Event, Disposable } from 'vscode';
|
||||
|
||||
export function filterEvent<T>(event: Event<T>, filter: (e: T) => boolean): Event<T> {
|
||||
return (listener, thisArgs = null, disposables?) => event(e => filter(e) && listener.call(thisArgs, e), null, disposables);
|
||||
}
|
||||
|
||||
export function onceEvent<T>(event: Event<T>): Event<T> {
|
||||
return (listener, thisArgs = null, disposables?) => {
|
||||
const result = event(e => {
|
||||
result.dispose();
|
||||
return listener.call(thisArgs, e);
|
||||
}, null, disposables);
|
||||
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export interface PromiseAdapter<T, U> {
|
||||
(
|
||||
value: T,
|
||||
resolve:
|
||||
(value?: U | PromiseLike<U>) => void,
|
||||
reject:
|
||||
(reason: any) => void
|
||||
): any;
|
||||
}
|
||||
|
||||
const passthrough = (value: any, resolve: (value?: any) => void) => resolve(value);
|
||||
|
||||
/**
|
||||
* Return a promise that resolves with the next emitted event, or with some future
|
||||
* event as decided by an adapter.
|
||||
*
|
||||
* If specified, the adapter is a function that will be called with
|
||||
* `(event, resolve, reject)`. It will be called once per event until it resolves or
|
||||
* rejects.
|
||||
*
|
||||
* The default adapter is the passthrough function `(value, resolve) => resolve(value)`.
|
||||
*
|
||||
* @param event the event
|
||||
* @param adapter controls resolution of the returned promise
|
||||
* @returns a promise that resolves or rejects as specified by the adapter
|
||||
*/
|
||||
export async function promiseFromEvent<T, U>(
|
||||
event: Event<T>,
|
||||
adapter: PromiseAdapter<T, U> = passthrough): Promise<U> {
|
||||
let subscription: Disposable;
|
||||
return new Promise<U>((resolve, reject) =>
|
||||
subscription = event((value: T) => {
|
||||
try {
|
||||
Promise.resolve(adapter(value, resolve, reject))
|
||||
.catch(reject);
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
})
|
||||
).then(
|
||||
(result: U) => {
|
||||
subscription.dispose();
|
||||
return result;
|
||||
},
|
||||
error => {
|
||||
subscription.dispose();
|
||||
throw error;
|
||||
}
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user