Skip to content

Commit

Permalink
Align with the latest vscode API
Browse files Browse the repository at this point in the history
  • Loading branch information
vinokurig committed Aug 25, 2020
1 parent be223fb commit 8ef9a91
Show file tree
Hide file tree
Showing 8 changed files with 269 additions and 225 deletions.
49 changes: 27 additions & 22 deletions packages/core/src/browser/authentication-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,24 +28,29 @@ export interface AuthenticationSession {
id: string;
accessToken: string;
account: {
displayName: string;
label: string;
id: string;
}
scopes: string[];
scopes: ReadonlyArray<string>;
}

export interface AuthenticationSessionsChangeEvent {
added: string[];
removed: string[];
changed: string[];
added: ReadonlyArray<string>;
removed: ReadonlyArray<string>;
changed: ReadonlyArray<string>;
}

export interface AuthenticationProviderInformation {
id: string;
label: string;
}

export interface AuthenticationProvider {
id: string;

supportsMultipleAccounts: boolean;

displayName: string;
label: string;

hasSessions(): boolean;

Expand All @@ -68,12 +73,12 @@ export interface AuthenticationService {
unregisterAuthenticationProvider(id: string): void;
sessionsUpdate(providerId: string, event: AuthenticationSessionsChangeEvent): void;

readonly onDidRegisterAuthenticationProvider: Event<string>;
readonly onDidUnregisterAuthenticationProvider: Event<string>;
readonly onDidRegisterAuthenticationProvider: Event<AuthenticationProviderInformation>;
readonly onDidUnregisterAuthenticationProvider: Event<AuthenticationProviderInformation>;

readonly onDidChangeSessions: Event<{ providerId: string, event: AuthenticationSessionsChangeEvent }>;
readonly onDidChangeSessions: Event<{ providerId: string, label: string, event: AuthenticationSessionsChangeEvent }>;
getSessions(providerId: string): Promise<ReadonlyArray<AuthenticationSession>>;
getDisplayName(providerId: string): string;
getLabel(providerId: string): string;
supportsMultipleAccounts(providerId: string): boolean;
login(providerId: string, scopes: string[]): Promise<AuthenticationSession>;
logout(providerId: string, sessionId: string): Promise<void>;
Expand All @@ -85,15 +90,15 @@ export interface AuthenticationService {
export class AuthenticationServiceImpl implements AuthenticationService {
private authenticationProviders: Map<string, AuthenticationProvider> = new Map<string, AuthenticationProvider>();

private onDidRegisterAuthenticationProviderEmitter: Emitter<string> = new Emitter<string>();
readonly onDidRegisterAuthenticationProvider: Event<string> = this.onDidRegisterAuthenticationProviderEmitter.event;
private onDidRegisterAuthenticationProviderEmitter: Emitter<AuthenticationProviderInformation> = new Emitter<AuthenticationProviderInformation>();
readonly onDidRegisterAuthenticationProvider: Event<AuthenticationProviderInformation> = this.onDidRegisterAuthenticationProviderEmitter.event;

private onDidUnregisterAuthenticationProviderEmitter: Emitter<string> = new Emitter<string>();
readonly onDidUnregisterAuthenticationProvider: Event<string> = this.onDidUnregisterAuthenticationProviderEmitter.event;
private onDidUnregisterAuthenticationProviderEmitter: Emitter<AuthenticationProviderInformation> = new Emitter<AuthenticationProviderInformation>();
readonly onDidUnregisterAuthenticationProvider: Event<AuthenticationProviderInformation> = this.onDidUnregisterAuthenticationProviderEmitter.event;

private onDidChangeSessionsEmitter: Emitter<{ providerId: string, event: AuthenticationSessionsChangeEvent }> =
new Emitter<{ providerId: string, event: AuthenticationSessionsChangeEvent }>();
readonly onDidChangeSessions: Event<{ providerId: string, event: AuthenticationSessionsChangeEvent }> = this.onDidChangeSessionsEmitter.event;
private onDidChangeSessionsEmitter: Emitter<{ providerId: string, label: string, event: AuthenticationSessionsChangeEvent }> =
new Emitter<{ providerId: string, label: string, event: AuthenticationSessionsChangeEvent }>();
readonly onDidChangeSessions: Event<{ providerId: string, label: string, event: AuthenticationSessionsChangeEvent }> = this.onDidChangeSessionsEmitter.event;

getProviderIds(): string[] {
const providerIds: string[] = [];
Expand All @@ -109,29 +114,29 @@ export class AuthenticationServiceImpl implements AuthenticationService {

registerAuthenticationProvider(id: string, authenticationProvider: AuthenticationProvider): void {
this.authenticationProviders.set(id, authenticationProvider);
this.onDidRegisterAuthenticationProviderEmitter.fire(id);
this.onDidRegisterAuthenticationProviderEmitter.fire({ id, label: authenticationProvider.label });
}

unregisterAuthenticationProvider(id: string): void {
const provider = this.authenticationProviders.get(id);
if (provider) {
this.authenticationProviders.delete(id);
this.onDidUnregisterAuthenticationProviderEmitter.fire(id);
this.onDidUnregisterAuthenticationProviderEmitter.fire({ id, label: provider.label });
}
}

async sessionsUpdate(id: string, event: AuthenticationSessionsChangeEvent): Promise<void> {
this.onDidChangeSessionsEmitter.fire({ providerId: id, event: event });
const provider = this.authenticationProviders.get(id);
if (provider) {
await provider.updateSessionItems(event);
this.onDidChangeSessionsEmitter.fire({ providerId: id, label: provider.label, event: event });
}
}

getDisplayName(id: string): string {
getLabel(id: string): string {
const authProvider = this.authenticationProviders.get(id);
if (authProvider) {
return authProvider.displayName;
return authProvider.label;
} else {
throw new Error(`No authentication provider '${id}' is currently registered.`);
}
Expand Down
20 changes: 12 additions & 8 deletions packages/plugin-ext/src/common/plugin-api-rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ import {
} from './plugin-api-rpc-model';
import { ExtPluginApi } from './plugin-ext-api-contribution';
import { KeysToAnyValues, KeysToKeysToAnyValue } from './types';
import { AuthenticationSession, CancellationToken, Progress, ProgressOptions } from '@theia/plugin';
import { CancellationToken, Progress, ProgressOptions } from '@theia/plugin';
import { DebuggerDescription } from '@theia/debug/lib/common/debug-service';
import { DebugProtocol } from 'vscode-debugprotocol';
import { SymbolInformation } from 'vscode-languageserver-types';
Expand All @@ -78,7 +78,10 @@ import { QuickTitleButton } from '@theia/core/lib/common/quick-open-model';
import * as files from '@theia/filesystem/lib/common/files';
import { BinaryBuffer } from '@theia/core/lib/common/buffer';
import { ResourceLabelFormatter } from '@theia/core/lib/common/label-protocol';
import { AuthenticationSessionsChangeEvent } from '@theia/core/lib/browser/authentication-service';
import {
AuthenticationProviderInformation,
AuthenticationSessionsChangeEvent
} from '@theia/core/lib/browser/authentication-service';

export interface PreferenceData {
[scope: number]: any;
Expand Down Expand Up @@ -1504,24 +1507,25 @@ export interface AuthenticationExt {
$getSessionAccessToken(id: string, sessionId: string): Promise<string>;
$login(id: string, scopes: string[]): Promise<theia.AuthenticationSession>;
$logout(id: string, sessionId: string): Promise<void>;
$onDidChangeAuthenticationSessions(providerId: string, event: theia.AuthenticationSessionsChangeEvent): Promise<void>;
$onDidChangeAuthenticationProviders(added: string[], removed: string[]): Promise<void>;
$onDidChangeAuthenticationSessions(id: string, label: string, event: AuthenticationSessionsChangeEvent): Promise<void>;
$onDidChangeAuthenticationProviders(added: AuthenticationProviderInformation[], removed: theia.AuthenticationProviderInformation[]): Promise<void>;
}

export interface AuthenticationMain {
$registerAuthenticationProvider(id: string, displayName: string, supportsMultipleAccounts: boolean): void;
$registerAuthenticationProvider(id: string, label: string, supportsMultipleAccounts: boolean): void;
$unregisterAuthenticationProvider(id: string): void;
$getProviderIds(): Promise<string[]>;
$sendDidChangeSessions(providerId: string, event: AuthenticationSessionsChangeEvent): void;
$getSession(providerId: string, scopes: string[], extensionId: string, extensionName: string,
options: { createIfNone?: boolean, clearSessionPreference?: boolean }): Promise<AuthenticationSession | undefined>;
options: { createIfNone?: boolean, clearSessionPreference?: boolean }): Promise<theia.AuthenticationSession | undefined>;
$selectSession(providerId: string, providerName: string, extensionId: string, extensionName: string,
potentialSessions: AuthenticationSession[], scopes: string[], clearSessionPreference: boolean): Promise<AuthenticationSession>;
potentialSessions: theia.AuthenticationSession[], scopes: string[], clearSessionPreference: boolean): Promise<theia.AuthenticationSession>;
$getSessionsPrompt(providerId: string, accountName: string, providerName: string, extensionId: string, extensionName: string): Promise<boolean>;
$loginPrompt(providerName: string, extensionName: string): Promise<boolean>;
$setTrustedExtension(providerId: string, accountName: string, extensionId: string, extensionName: string): Promise<void>;
$setTrustedExtensionAndAccountPreference(providerId: string, accountName: string, extensionId: string, extensionName: string, sessionId: string): Promise<void>;

$getSessions(providerId: string): Promise<ReadonlyArray<theia.AuthenticationSession>>;
$login(providerId: string, scopes: string[]): Promise<theia.AuthenticationSession>;
$logout(providerId: string, sessionId: string): Promise<void>;
}

Expand Down
48 changes: 26 additions & 22 deletions packages/plugin-ext/src/main/browser/authentication-main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ import { StorageService } from '@theia/core/lib/browser';
import {
AuthenticationProvider,
AuthenticationService,
AuthenticationSession,
AuthenticationSessionsChangeEvent,
readAllowedExtensions
} from '@theia/core/lib/browser/authentication-service';
import { AuthenticationSession } from '../../plugin/types-impl';
import { QuickPickItem, QuickPickService } from '@theia/core/lib/common/quick-pick-service';

export class AuthenticationMainImpl implements AuthenticationMain {
Expand All @@ -48,10 +48,10 @@ export class AuthenticationMainImpl implements AuthenticationMain {
this.quickPickService = container.get(QuickPickService);

this.authenticationService.onDidChangeSessions(e => {
this.proxy.$onDidChangeAuthenticationSessions(e.providerId, e.event);
this.proxy.$onDidChangeAuthenticationSessions(e.providerId, e.label, e.event);
});
this.authenticationService.onDidRegisterAuthenticationProvider(providerId => {
this.proxy.$onDidChangeAuthenticationProviders([providerId], []);
this.authenticationService.onDidRegisterAuthenticationProvider(info => {
this.proxy.$onDidChangeAuthenticationProviders([info], []);
});
this.authenticationService.onDidUnregisterAuthenticationProvider(providerId => {
this.proxy.$onDidChangeAuthenticationProviders([], [providerId]);
Expand All @@ -61,8 +61,8 @@ export class AuthenticationMainImpl implements AuthenticationMain {
return Promise.resolve(this.authenticationService.getProviderIds());
}

async $registerAuthenticationProvider(id: string, displayName: string, supportsMultipleAccounts: boolean): Promise<void> {
const provider = new AuthenticationProviderImp(this.proxy, id, displayName, supportsMultipleAccounts, this.storageService, this.messageService);
async $registerAuthenticationProvider(id: string, label: string, supportsMultipleAccounts: boolean): Promise<void> {
const provider = new AuthenticationProviderImp(this.proxy, id, label, supportsMultipleAccounts, this.storageService, this.messageService);
this.authenticationService.registerAuthenticationProvider(id, provider);
}

Expand All @@ -78,20 +78,24 @@ export class AuthenticationMainImpl implements AuthenticationMain {
return this.authenticationService.getSessions(id);
}

$login(providerId: string, scopes: string[]): Promise<AuthenticationSession> {
return this.authenticationService.login(providerId, scopes);
}

$logout(providerId: string, sessionId: string): Promise<void> {
return this.authenticationService.logout(providerId, sessionId);
}

async $getSession(providerId: string, scopes: string[], extensionId: string, extensionName: string,
options: { createIfNone: boolean, clearSessionPreference: boolean }): Promise<AuthenticationSession | undefined> {
const orderedScopes = scopes.sort().join(' ');
const sessions = (await this.$getSessions(providerId)).filter(session => session.scopes.sort().join(' ') === orderedScopes);
const displayName = this.authenticationService.getDisplayName(providerId);
const sessions = (await this.$getSessions(providerId)).filter(session => session.scopes.slice().sort().join(' ') === orderedScopes);
const label = this.authenticationService.getLabel(providerId);

if (sessions.length > 0) {
if (sessions.length) {
if (!this.authenticationService.supportsMultipleAccounts(providerId)) {
const session = sessions[0];
const allowed = await this.$getSessionsPrompt(providerId, session.account.displayName, displayName, extensionId, extensionName);
const allowed = await this.$getSessionsPrompt(providerId, session.account.label, label, extensionId, extensionName);
if (allowed) {
return session;
} else {
Expand All @@ -100,17 +104,17 @@ export class AuthenticationMainImpl implements AuthenticationMain {
}

// On renderer side, confirm consent, ask user to choose between accounts if multiple sessions are valid
const selected = await this.$selectSession(providerId, displayName, extensionId, extensionName, sessions, scopes, options.clearSessionPreference);
const selected = await this.$selectSession(providerId, label, extensionId, extensionName, sessions, scopes, !!options.clearSessionPreference);
return sessions.find(session => session.id === selected.id);
} else {
if (options.createIfNone) {
const isAllowed = await this.$loginPrompt(displayName, extensionName);
const isAllowed = await this.$loginPrompt(label, extensionName);
if (!isAllowed) {
throw new Error('User did not consent to login.');
}

const session = await this.authenticationService.login(providerId, scopes);
await this.$setTrustedExtension(providerId, session.account.displayName, extensionId, extensionName);
await this.$setTrustedExtensionAndAccountPreference(providerId, session.account.label, extensionId, extensionName, session.id);
return session;
}
}
Expand All @@ -129,7 +133,7 @@ export class AuthenticationMainImpl implements AuthenticationMain {
if (existingSessionPreference) {
const matchingSession = potentialSessions.find(session => session.id === existingSessionPreference);
if (matchingSession) {
const allowed = await this.$getSessionsPrompt(providerId, matchingSession.account.displayName, providerName, extensionId, extensionName);
const allowed = await this.$getSessionsPrompt(providerId, matchingSession.account.label, providerName, extensionId, extensionName);
if (allowed) {
return matchingSession;
}
Expand All @@ -139,7 +143,7 @@ export class AuthenticationMainImpl implements AuthenticationMain {

return new Promise(async (resolve, reject) => {
const items: QuickPickItem<{ session?: AuthenticationSession }>[] = potentialSessions.map(session => ({
label: session.account.displayName,
label: session.account.label,
value: { session }
}));
items.push({
Expand All @@ -153,7 +157,7 @@ export class AuthenticationMainImpl implements AuthenticationMain {
});
if (selected) {
const session = selected.session ?? await this.authenticationService.login(providerId, scopes);
const accountName = session.account.displayName;
const accountName = session.account.label;

const allowList = await readAllowedExtensions(this.storageService, providerId, accountName);
if (!allowList.find(allowed => allowed.id === extensionId)) {
Expand Down Expand Up @@ -195,7 +199,7 @@ export class AuthenticationMainImpl implements AuthenticationMain {
return choice === 'Allow';
}

async $setTrustedExtension(providerId: string, accountName: string, extensionId: string, extensionName: string): Promise<void> {
async $setTrustedExtensionAndAccountPreference(providerId: string, accountName: string, extensionId: string, extensionName: string, sessionId: string): Promise<void> {
const allowList = await readAllowedExtensions(this.storageService, providerId, accountName);
if (!allowList.find(allowed => allowed.id === extensionId)) {
allowList.push({ id: extensionId, name: extensionName });
Expand Down Expand Up @@ -239,7 +243,7 @@ export class AuthenticationProviderImp implements AuthenticationProvider {
constructor(
private readonly proxy: AuthenticationExt,
public readonly id: string,
public readonly displayName: string,
public readonly label: string,
public readonly supportsMultipleAccounts: boolean,
private readonly storageService: StorageService,
private readonly messageService: MessageService
Expand All @@ -250,14 +254,14 @@ export class AuthenticationProviderImp implements AuthenticationProvider {
}

private registerSession(session: AuthenticationSession): void {
this.sessions.set(session.id, session.account.displayName);
this.sessions.set(session.id, session.account.label);

const existingSessionsForAccount = this.accounts.get(session.account.displayName);
const existingSessionsForAccount = this.accounts.get(session.account.label);
if (existingSessionsForAccount) {
this.accounts.set(session.account.displayName, existingSessionsForAccount.concat(session.id));
this.accounts.set(session.account.label, existingSessionsForAccount.concat(session.id));
return;
} else {
this.accounts.set(session.account.displayName, [session.id]);
this.accounts.set(session.account.label, [session.id]);
}
}

Expand Down
Loading

0 comments on commit 8ef9a91

Please sign in to comment.