提交 92dafb39 编写于 作者: B Benjamin Pasero

web - implement credentials provider and add API

上级 2b22c0a0
......@@ -5,49 +5,33 @@
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { MainContext, MainThreadKeytarShape, IExtHostContext } from 'vs/workbench/api/common/extHost.protocol';
import { ICredentialsService } from 'vs/platform/credentials/common/credentials';
import { optional } from 'vs/platform/instantiation/common/instantiation';
import { ICredentialsService } from 'vs/workbench/services/credentials/common/credentials';
@extHostNamedCustomer(MainContext.MainThreadKeytar)
export class MainThreadKeytar implements MainThreadKeytarShape {
private readonly _credentialsService?: ICredentialsService;
constructor(
_extHostContext: IExtHostContext,
@optional(ICredentialsService) credentialsService: ICredentialsService,
) {
this._credentialsService = credentialsService;
}
dispose(): void {
//
}
@ICredentialsService private readonly _credentialsService: ICredentialsService,
) { }
async $getPassword(service: string, account: string): Promise<string | null> {
if (this._credentialsService) {
return this._credentialsService.getPassword(service, account);
}
return null;
}
async $setPassword(service: string, account: string, password: string): Promise<void> {
if (this._credentialsService) {
return this._credentialsService.setPassword(service, account, password);
}
}
async $deletePassword(service: string, account: string): Promise<boolean> {
if (this._credentialsService) {
return this._credentialsService.deletePassword(service, account);
}
return false;
}
async $findPassword(service: string): Promise<string | null> {
if (this._credentialsService) {
return this._credentialsService.findPassword(service);
}
return null;
dispose(): void {
//
}
}
......@@ -117,12 +117,7 @@ class CodeRendererMain extends Disposable {
const payload = await this.resolveWorkspaceInitializationPayload();
// Environment
const environmentService = new BrowserWorkbenchEnvironmentService({
workspaceId: payload.id,
remoteAuthority: this.configuration.remoteAuthority,
webviewEndpoint: this.configuration.webviewEndpoint,
connectionToken: this.configuration.connectionToken
});
const environmentService = new BrowserWorkbenchEnvironmentService(payload.id, this.configuration);
serviceCollection.set(IWorkbenchEnvironmentService, environmentService);
// Product
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ICredentialsService } from 'vs/workbench/services/credentials/common/credentials';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
export interface ICredentialsProvider {
getPassword(service: string, account: string): Promise<string | null>;
setPassword(service: string, account: string, password: string): Promise<void>;
deletePassword(service: string, account: string): Promise<boolean>;
findPassword(service: string): Promise<string | null>;
}
export class BrowserCredentialsService implements ICredentialsService {
_serviceBrand!: ServiceIdentifier<any>;
private credentialsProvider: ICredentialsProvider;
constructor(@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService) {
if (environmentService.options && environmentService.options.credentialsProvider) {
this.credentialsProvider = environmentService.options.credentialsProvider;
} else {
this.credentialsProvider = new LocalStorageCredentialsProvider();
}
}
async getPassword(service: string, account: string): Promise<string | null> {
return this.credentialsProvider.getPassword(service, account);
}
async setPassword(service: string, account: string, password: string): Promise<void> {
return this.credentialsProvider.setPassword(service, account, password);
}
async deletePassword(service: string, account: string): Promise<boolean> {
return this.credentialsProvider.deletePassword(service, account);
}
async findPassword(service: string): Promise<string | null> {
return this.credentialsProvider.findPassword(service);
}
}
interface ICredential {
service: string;
account: string;
password: string;
}
class LocalStorageCredentialsProvider implements ICredentialsProvider {
static readonly CREDENTIALS_OPENED_KEY = 'credentials.provider';
private _credentials: ICredential[];
private get credentials(): ICredential[] {
if (!this._credentials) {
try {
const serializedCredentials = window.localStorage.getItem(LocalStorageCredentialsProvider.CREDENTIALS_OPENED_KEY);
if (serializedCredentials) {
this._credentials = JSON.parse(serializedCredentials);
}
} catch (error) {
// ignore
}
if (!Array.isArray(this._credentials)) {
this._credentials = [];
}
}
return this._credentials;
}
private save(): void {
window.localStorage.setItem(LocalStorageCredentialsProvider.CREDENTIALS_OPENED_KEY, JSON.stringify(this.credentials));
}
async getPassword(service: string, account: string): Promise<string | null> {
return this.doGetPassword(service, account);
}
private async doGetPassword(service: string, account?: string): Promise<string | null> {
for (const credential of this.credentials) {
if (credential.service === service) {
if (typeof account !== 'string' || account === credential.account) {
return credential.password;
}
}
}
return null;
}
async setPassword(service: string, account: string, password: string): Promise<void> {
this.deletePassword(service, account);
this.credentials.push({ service, account, password });
this.save();
}
async deletePassword(service: string, account: string): Promise<boolean> {
let found = false;
this._credentials = this.credentials.filter(credential => {
if (credential.service === service && credential.account === account) {
found = true;
return false;
}
return true;
});
if (found) {
this.save();
}
return found;
}
async findPassword(service: string): Promise<string | null> {
return this.doGetPassword(service);
}
}
registerSingleton(ICredentialsService, BrowserCredentialsService, true);
......@@ -3,12 +3,14 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
export const ICredentialsService = createDecorator<ICredentialsService>('ICredentialsService');
export interface ICredentialsService {
_serviceBrand: any;
_serviceBrand: ServiceIdentifier<any>;
getPassword(service: string, account: string): Promise<string | null>;
setPassword(service: string, account: string, password: string): Promise<void>;
deletePassword(service: string, account: string): Promise<boolean>;
......
......@@ -3,8 +3,10 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ICredentialsService } from 'vs/platform/credentials/common/credentials';
import { ICredentialsService } from 'vs/workbench/services/credentials/common/credentials';
import { IdleValue } from 'vs/base/common/async';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
type KeytarModule = {
getPassword(service: string, account: string): Promise<string | null>;
......@@ -15,7 +17,7 @@ type KeytarModule = {
export class KeytarCredentialsService implements ICredentialsService {
_serviceBrand: any;
_serviceBrand!: ServiceIdentifier<any>;
private readonly _keytar = new IdleValue<Promise<KeytarModule>>(() => import('keytar'));
......@@ -39,3 +41,5 @@ export class KeytarCredentialsService implements ICredentialsService {
return keytar.findPassword(service);
}
}
registerSingleton(ICredentialsService, KeytarCredentialsService, true);
......@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { IWindowConfiguration, IPath, IPathsToWaitFor } from 'vs/platform/windows/common/windows';
import { IEnvironmentService, IExtensionHostDebugParams, IDebugParams, BACKUPS } from 'vs/platform/environment/common/environment';
import { IExtensionHostDebugParams, IDebugParams, BACKUPS } from 'vs/platform/environment/common/environment';
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
import { URI } from 'vs/base/common/uri';
import { IProcessEnvironment } from 'vs/base/common/platform';
......@@ -13,6 +13,8 @@ import { ExportData } from 'vs/base/common/performance';
import { LogLevel } from 'vs/platform/log/common/log';
import { joinPath } from 'vs/base/common/resources';
import { Schemas } from 'vs/base/common/network';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { IWorkbenchConstructionOptions } from 'vs/workbench/workbench.web.api';
export class BrowserWindowConfiguration implements IWindowConfiguration {
......@@ -66,26 +68,26 @@ export interface IBrowserWindowConfiguration {
connectionToken?: string;
}
export class BrowserWorkbenchEnvironmentService implements IEnvironmentService {
export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironmentService {
_serviceBrand!: ServiceIdentifier<IEnvironmentService>;
_serviceBrand!: ServiceIdentifier<IWorkbenchEnvironmentService>;
readonly configuration: IWindowConfiguration = new BrowserWindowConfiguration();
constructor(configuration: IBrowserWindowConfiguration) {
constructor(workspaceId: string, public readonly options: IWorkbenchConstructionOptions) {
this.args = { _: [] };
this.appRoot = '/web/';
this.appNameLong = 'Visual Studio Code - Web';
this.configuration.remoteAuthority = configuration.remoteAuthority;
this.configuration.remoteAuthority = options.remoteAuthority;
this.userRoamingDataHome = URI.file('/User').with({ scheme: Schemas.userData });
this.settingsResource = joinPath(this.userRoamingDataHome, 'settings.json');
this.keybindingsResource = joinPath(this.userRoamingDataHome, 'keybindings.json');
this.keyboardLayoutResource = joinPath(this.userRoamingDataHome, 'keyboardLayout.json');
this.localeResource = joinPath(this.userRoamingDataHome, 'locale.json');
this.backupHome = joinPath(this.userRoamingDataHome, BACKUPS);
this.configuration.backupWorkspaceResource = joinPath(this.backupHome, configuration.workspaceId);
this.configuration.connectionToken = configuration.connectionToken || this.getConnectionTokenFromLocation();
this.configuration.backupWorkspaceResource = joinPath(this.backupHome, workspaceId);
this.configuration.connectionToken = options.connectionToken || this.getConnectionTokenFromLocation();
this.logsPath = '/web/logs';
......@@ -94,7 +96,7 @@ export class BrowserWorkbenchEnvironmentService implements IEnvironmentService {
break: false
};
this.webviewEndpoint = configuration.webviewEndpoint;
this.webviewEndpoint = options.webviewEndpoint;
this.untitledWorkspacesHome = URI.from({ scheme: Schemas.untitled, path: 'Workspaces' });
if (document && document.location && document.location.search) {
......
......@@ -6,6 +6,7 @@
import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
import { IWindowConfiguration } from 'vs/platform/windows/common/windows';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IWorkbenchConstructionOptions } from 'vs/workbench/workbench.web.api';
export const IWorkbenchEnvironmentService = createDecorator<IWorkbenchEnvironmentService>('environmentService');
......@@ -14,4 +15,6 @@ export interface IWorkbenchEnvironmentService extends IEnvironmentService {
_serviceBrand: ServiceIdentifier<IEnvironmentService>;
readonly configuration: IWindowConfiguration;
readonly options?: IWorkbenchConstructionOptions;
}
......@@ -47,7 +47,7 @@ suite('FileUserDataProvider', () => {
userDataResource = URI.file(userDataPath).with({ scheme: Schemas.userData });
await Promise.all([pfs.mkdirp(userDataPath), pfs.mkdirp(backupsPath)]);
const environmentService = new BrowserWorkbenchEnvironmentService({ workspaceId: 'workspaceId' });
const environmentService = new BrowserWorkbenchEnvironmentService('workspaceId', { remoteAuthority: 'remote' });
environmentService.userRoamingDataHome = userDataResource;
const userDataFileSystemProvider = new FileUserDataProvider(URI.file(userDataPath), URI.file(backupsPath), diskFileSystemProvider, environmentService);
......@@ -321,7 +321,7 @@ suite('FileUserDataProvider - Watching', () => {
localUserDataResource = URI.file(userDataPath);
userDataResource = localUserDataResource.with({ scheme: Schemas.userData });
const environmentService = new BrowserWorkbenchEnvironmentService({ workspaceId: 'workspaceId' });
const environmentService = new BrowserWorkbenchEnvironmentService('workspaceId', { remoteAuthority: 'remote' });
environmentService.userRoamingDataHome = userDataResource;
const userDataFileSystemProvider = new FileUserDataProvider(localUserDataResource, localBackupsResource, new TestFileSystemProvider(fileEventEmitter.event), environmentService);
......
......@@ -49,6 +49,7 @@ import 'vs/workbench/services/accessibility/node/accessibilityService';
import 'vs/workbench/services/remote/node/tunnelService';
import 'vs/workbench/services/backup/node/backupFileService';
import 'vs/workbench/services/opener/electron-browser/openerService';
import 'vs/workbench/services/credentials/node/credentialsService';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
......@@ -74,8 +75,6 @@ import { IMenubarService } from 'vs/platform/menubar/common/menubar';
import { MenubarService } from 'vs/platform/menubar/electron-browser/menubarService';
import { IURLService } from 'vs/platform/url/common/url';
import { RelayURLService } from 'vs/platform/url/electron-browser/urlService';
import { ICredentialsService } from 'vs/platform/credentials/common/credentials';
import { KeytarCredentialsService } from 'vs/platform/credentials/node/credentialsService';
registerSingleton(IClipboardService, ClipboardService, true);
registerSingleton(IRequestService, RequestService, true);
......@@ -89,7 +88,6 @@ registerSingleton(IIssueService, IssueService);
registerSingleton(IWorkspacesService, WorkspacesService);
registerSingleton(IMenubarService, MenubarService);
registerSingleton(IURLService, RelayURLService);
registerSingleton(ICredentialsService, KeytarCredentialsService, true);
//#endregion
......
......@@ -8,6 +8,7 @@ import { main } from 'vs/workbench/browser/web.main';
import { UriComponents } from 'vs/base/common/uri';
import { IFileSystemProvider } from 'vs/platform/files/common/files';
import { IWebSocketFactory } from 'vs/platform/remote/browser/browserSocketFactory';
import { ICredentialsProvider } from 'vs/workbench/services/credentials/browser/credentialsService';
export interface IWorkbenchConstructionOptions {
......@@ -53,6 +54,11 @@ export interface IWorkbenchConstructionOptions {
* Experimental: Whether to enable the smoke test driver.
*/
driver?: boolean;
/**
* Experimental: The credentials provider to store and retrieve secrets.
*/
credentialsProvider?: ICredentialsProvider;
}
/**
......
......@@ -36,6 +36,7 @@ import 'vs/workbench/services/extensions/browser/extensionService';
import 'vs/workbench/services/extensionManagement/common/extensionManagementServerService';
import 'vs/workbench/services/telemetry/browser/telemetryService';
import 'vs/workbench/services/configurationResolver/browser/configurationResolverService';
import 'vs/workbench/services/credentials/browser/credentialsService';
import 'vs/workbench/browser/web.simpleservices';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
......
......@@ -436,6 +436,7 @@
"**/vs/base/**/common/**",
"**/vs/platform/**/common/**",
"**/vs/editor/common/**",
"**/vs/workbench/workbench.web.api",
"**/vs/workbench/common/**",
"**/vs/workbench/services/**/common/**",
"**/vs/workbench/api/**/common/**",
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册