mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-19 14:58:16 -05:00
Add account id to authentication session object
This commit is contained in:
@@ -12,12 +12,27 @@ import Logger from './common/logger';
|
||||
export const onDidChangeSessions = new vscode.EventEmitter<vscode.AuthenticationSessionsChangeEvent>();
|
||||
|
||||
interface SessionData {
|
||||
id: string;
|
||||
account?: {
|
||||
displayName: string;
|
||||
id: string;
|
||||
}
|
||||
scopes: string[];
|
||||
accessToken: string;
|
||||
}
|
||||
|
||||
// TODO remove
|
||||
interface OldSessionData {
|
||||
id: string;
|
||||
accountName: string;
|
||||
scopes: string[];
|
||||
accessToken: string;
|
||||
}
|
||||
|
||||
function isOldSessionData(x: any): x is OldSessionData {
|
||||
return !!x.accountName;
|
||||
}
|
||||
|
||||
export class GitHubAuthenticationProvider {
|
||||
private _sessions: vscode.AuthenticationSession[] = [];
|
||||
private _githubServer = new GitHubServer();
|
||||
@@ -68,15 +83,34 @@ export class GitHubAuthenticationProvider {
|
||||
const storedSessions = await keychain.getToken();
|
||||
if (storedSessions) {
|
||||
try {
|
||||
const sessionData: SessionData[] = JSON.parse(storedSessions);
|
||||
return sessionData.map(session => {
|
||||
return {
|
||||
id: session.id,
|
||||
accountName: session.accountName,
|
||||
scopes: session.scopes,
|
||||
getAccessToken: () => Promise.resolve(session.accessToken)
|
||||
};
|
||||
const sessionData: (SessionData | OldSessionData)[] = JSON.parse(storedSessions);
|
||||
const sessionPromises = sessionData.map(async (session: SessionData | OldSessionData): Promise<vscode.AuthenticationSession | undefined> => {
|
||||
try {
|
||||
const needsUserInfo = isOldSessionData(session) || !session.account;
|
||||
let userInfo: { id: string, accountName: string };
|
||||
if (needsUserInfo) {
|
||||
userInfo = await this._githubServer.getUserInfo(session.accessToken);
|
||||
}
|
||||
|
||||
return {
|
||||
id: session.id,
|
||||
account: {
|
||||
displayName: isOldSessionData(session)
|
||||
? session.accountName
|
||||
: session.account?.displayName ?? userInfo!.accountName,
|
||||
id: isOldSessionData(session)
|
||||
? userInfo!.id
|
||||
: session.account?.id ?? userInfo!.id
|
||||
},
|
||||
scopes: session.scopes,
|
||||
getAccessToken: () => Promise.resolve(session.accessToken)
|
||||
};
|
||||
} catch (e) {
|
||||
return undefined;
|
||||
}
|
||||
});
|
||||
|
||||
return (await Promise.all(sessionPromises)).filter((x: vscode.AuthenticationSession | undefined): x is vscode.AuthenticationSession => !!x);
|
||||
} catch (e) {
|
||||
Logger.error(`Error reading sessions: ${e}`);
|
||||
}
|
||||
@@ -90,7 +124,7 @@ export class GitHubAuthenticationProvider {
|
||||
const resolvedAccessToken = await session.getAccessToken();
|
||||
return {
|
||||
id: session.id,
|
||||
accountName: session.accountName,
|
||||
account: session.account,
|
||||
scopes: session.scopes,
|
||||
accessToken: resolvedAccessToken
|
||||
};
|
||||
@@ -125,7 +159,10 @@ export class GitHubAuthenticationProvider {
|
||||
return {
|
||||
id: uuid(),
|
||||
getAccessToken: () => Promise.resolve(token),
|
||||
accountName: userInfo.accountName,
|
||||
account: {
|
||||
displayName: userInfo.accountName,
|
||||
id: userInfo.id
|
||||
},
|
||||
scopes: scopes
|
||||
};
|
||||
}
|
||||
|
||||
@@ -145,6 +145,7 @@ export class GitHubServer {
|
||||
Logger.info('Got account info!');
|
||||
resolve({ id: json.id, accountName: json.login });
|
||||
} else {
|
||||
Logger.error('Getting account info failed');
|
||||
reject(new Error(result.statusMessage));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -25,7 +25,10 @@ interface IToken {
|
||||
expiresAt?: number; // UNIX epoch time at which token will expire
|
||||
refreshToken: string;
|
||||
|
||||
accountName: string;
|
||||
account: {
|
||||
displayName: string;
|
||||
id: string;
|
||||
};
|
||||
scope: string;
|
||||
sessionId: string; // The account id + the scope
|
||||
}
|
||||
@@ -44,7 +47,10 @@ interface IStoredSession {
|
||||
id: string;
|
||||
refreshToken: string;
|
||||
scope: string; // Scopes are alphabetized and joined with a space
|
||||
accountName: string;
|
||||
account: {
|
||||
displayName: string,
|
||||
id: string
|
||||
}
|
||||
}
|
||||
|
||||
function parseQuery(uri: vscode.Uri) {
|
||||
@@ -93,7 +99,10 @@ export class AzureActiveDirectoryService {
|
||||
this._tokens.push({
|
||||
accessToken: undefined,
|
||||
refreshToken: session.refreshToken,
|
||||
accountName: session.accountName,
|
||||
account: {
|
||||
displayName: session.account.displayName,
|
||||
id: session.account.id
|
||||
},
|
||||
scope: session.scope,
|
||||
sessionId: session.id
|
||||
});
|
||||
@@ -125,7 +134,7 @@ export class AzureActiveDirectoryService {
|
||||
id: token.sessionId,
|
||||
refreshToken: token.refreshToken,
|
||||
scope: token.scope,
|
||||
accountName: token.accountName
|
||||
account: token.account
|
||||
};
|
||||
});
|
||||
|
||||
@@ -199,7 +208,7 @@ export class AzureActiveDirectoryService {
|
||||
return {
|
||||
id: token.sessionId,
|
||||
getAccessToken: () => this.resolveAccessToken(token),
|
||||
accountName: token.accountName,
|
||||
account: token.account,
|
||||
scopes: token.scope.split(' ')
|
||||
};
|
||||
}
|
||||
@@ -223,8 +232,6 @@ export class AzureActiveDirectoryService {
|
||||
} catch (e) {
|
||||
throw new Error('Unavailable due to network problems');
|
||||
}
|
||||
|
||||
throw new Error('Unavailable due to network problems');
|
||||
}
|
||||
|
||||
private getTokenClaims(accessToken: string): ITokenClaims {
|
||||
@@ -419,7 +426,10 @@ export class AzureActiveDirectoryService {
|
||||
refreshToken: json.refresh_token,
|
||||
scope,
|
||||
sessionId: existingId || `${claims.tid}/${(claims.oid || (claims.altsecid || '' + claims.ipd || ''))}/${uuid()}`,
|
||||
accountName: claims.email || claims.unique_name || 'user@example.com'
|
||||
account: {
|
||||
displayName: claims.email || claims.unique_name || 'user@example.com',
|
||||
id: `${claims.tid}/${(claims.oid || (claims.altsecid || '' + claims.ipd || ''))}`
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
const selectedSession = await vscode.window.showQuickPick(sessions.map(session => {
|
||||
return {
|
||||
id: session.id,
|
||||
label: session.accountName
|
||||
label: session.account.displayName
|
||||
};
|
||||
}));
|
||||
|
||||
|
||||
@@ -1412,7 +1412,10 @@ export interface RenameProvider {
|
||||
export interface AuthenticationSession {
|
||||
id: string;
|
||||
getAccessToken(): Thenable<string>;
|
||||
accountName: string;
|
||||
account: {
|
||||
displayName: string;
|
||||
id: string;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
5
src/vs/vscode.proposed.d.ts
vendored
5
src/vs/vscode.proposed.d.ts
vendored
@@ -21,7 +21,10 @@ declare module 'vscode' {
|
||||
export interface AuthenticationSession {
|
||||
id: string;
|
||||
getAccessToken(): Thenable<string>;
|
||||
accountName: string;
|
||||
account: {
|
||||
displayName: string;
|
||||
id: string;
|
||||
};
|
||||
scopes: string[]
|
||||
}
|
||||
|
||||
|
||||
@@ -129,21 +129,21 @@ export class MainThreadAuthenticationProvider extends Disposable {
|
||||
}
|
||||
|
||||
private registerSession(session: modes.AuthenticationSession) {
|
||||
this._sessions.set(session.id, session.accountName);
|
||||
this._sessions.set(session.id, session.account.displayName);
|
||||
|
||||
const existingSessionsForAccount = this._accounts.get(session.accountName);
|
||||
const existingSessionsForAccount = this._accounts.get(session.account.displayName);
|
||||
if (existingSessionsForAccount) {
|
||||
this._accounts.set(session.accountName, existingSessionsForAccount.concat(session.id));
|
||||
this._accounts.set(session.account.displayName, existingSessionsForAccount.concat(session.id));
|
||||
return;
|
||||
} else {
|
||||
this._accounts.set(session.accountName, [session.id]);
|
||||
this._accounts.set(session.account.displayName, [session.id]);
|
||||
}
|
||||
|
||||
const menuItem = MenuRegistry.appendMenuItem(MenuId.AccountsContext, {
|
||||
group: '1_accounts',
|
||||
command: {
|
||||
id: `configureSessions${session.id}`,
|
||||
title: `${session.accountName} (${this.displayName})`
|
||||
title: `${session.account.displayName} (${this.displayName})`
|
||||
},
|
||||
order: 3
|
||||
});
|
||||
@@ -170,11 +170,11 @@ export class MainThreadAuthenticationProvider extends Disposable {
|
||||
}
|
||||
|
||||
if (selected.label === manage) {
|
||||
this.manageTrustedExtensions(quickInputService, storageService, session.accountName);
|
||||
this.manageTrustedExtensions(quickInputService, storageService, session.account.displayName);
|
||||
}
|
||||
|
||||
if (selected.label === showUsage) {
|
||||
this.showUsage(quickInputService, session.accountName);
|
||||
this.showUsage(quickInputService, session.account.displayName);
|
||||
}
|
||||
|
||||
quickPick.dispose();
|
||||
@@ -188,28 +188,28 @@ export class MainThreadAuthenticationProvider extends Disposable {
|
||||
},
|
||||
});
|
||||
|
||||
this._sessionMenuItems.set(session.accountName, [menuItem, manageCommand]);
|
||||
this._sessionMenuItems.set(session.account.displayName, [menuItem, manageCommand]);
|
||||
}
|
||||
|
||||
async signOut(dialogService: IDialogService, session: modes.AuthenticationSession): Promise<void> {
|
||||
const providerUsage = accountUsages.get(this.id);
|
||||
const accountUsage = (providerUsage || {})[session.accountName] || [];
|
||||
const sessionsForAccount = this._accounts.get(session.accountName);
|
||||
const accountUsage = (providerUsage || {})[session.account.displayName] || [];
|
||||
const sessionsForAccount = this._accounts.get(session.account.displayName);
|
||||
|
||||
// Skip dialog if nothing is using the account
|
||||
if (!accountUsage.length) {
|
||||
accountUsages.set(this.id, { [session.accountName]: [] });
|
||||
accountUsages.set(this.id, { [session.account.displayName]: [] });
|
||||
sessionsForAccount?.forEach(sessionId => this.logout(sessionId));
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await dialogService.confirm({
|
||||
title: nls.localize('signOutConfirm', "Sign out of {0}", session.accountName),
|
||||
message: nls.localize('signOutMessage', "The account {0} is currently used by: \n\n{1}\n\n Sign out of these features?", session.accountName, accountUsage.join('\n'))
|
||||
title: nls.localize('signOutConfirm', "Sign out of {0}", session.account.displayName),
|
||||
message: nls.localize('signOutMessage', "The account {0} is currently used by: \n\n{1}\n\n Sign out of these features?", session.account.displayName, accountUsage.join('\n'))
|
||||
});
|
||||
|
||||
if (result.confirmed) {
|
||||
accountUsages.set(this.id, { [session.accountName]: [] });
|
||||
accountUsages.set(this.id, { [session.account.displayName]: [] });
|
||||
sessionsForAccount?.forEach(sessionId => this.logout(sessionId));
|
||||
}
|
||||
}
|
||||
@@ -218,9 +218,9 @@ export class MainThreadAuthenticationProvider extends Disposable {
|
||||
return (await this._proxy.$getSessions(this.id)).map(session => {
|
||||
return {
|
||||
id: session.id,
|
||||
accountName: session.accountName,
|
||||
account: session.account,
|
||||
getAccessToken: () => {
|
||||
addAccountUsage(this.id, session.accountName, nls.localize('sync', "Preferences Sync"));
|
||||
addAccountUsage(this.id, session.account.displayName, nls.localize('sync', "Preferences Sync"));
|
||||
return this._proxy.$getSessionAccessToken(this.id, session.id);
|
||||
}
|
||||
};
|
||||
@@ -258,7 +258,7 @@ export class MainThreadAuthenticationProvider extends Disposable {
|
||||
return this._proxy.$login(this.id, scopes).then(session => {
|
||||
return {
|
||||
id: session.id,
|
||||
accountName: session.accountName,
|
||||
account: session.account,
|
||||
getAccessToken: () => this._proxy.$getSessionAccessToken(this.id, session.id)
|
||||
};
|
||||
});
|
||||
|
||||
@@ -47,12 +47,12 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
|
||||
.map(session => {
|
||||
return {
|
||||
id: session.id,
|
||||
accountName: session.accountName,
|
||||
account: session.account,
|
||||
scopes: session.scopes,
|
||||
getAccessToken: async () => {
|
||||
const isAllowed = await this._proxy.$getSessionsPrompt(
|
||||
provider.id,
|
||||
session.accountName,
|
||||
session.account.displayName,
|
||||
provider.displayName,
|
||||
extensionId,
|
||||
requestingExtension.displayName || requestingExtension.name);
|
||||
@@ -80,15 +80,15 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
|
||||
}
|
||||
|
||||
const session = await provider.login(scopes);
|
||||
await this._proxy.$setTrustedExtension(provider.id, session.accountName, ExtensionIdentifier.toKey(requestingExtension.identifier), extensionName);
|
||||
await this._proxy.$setTrustedExtension(provider.id, session.account.displayName, ExtensionIdentifier.toKey(requestingExtension.identifier), extensionName);
|
||||
return {
|
||||
id: session.id,
|
||||
accountName: session.accountName,
|
||||
account: session.account,
|
||||
scopes: session.scopes,
|
||||
getAccessToken: async () => {
|
||||
const isAllowed = await this._proxy.$getSessionsPrompt(
|
||||
provider.id,
|
||||
session.accountName,
|
||||
session.account.displayName,
|
||||
provider.displayName,
|
||||
ExtensionIdentifier.toKey(requestingExtension.identifier),
|
||||
requestingExtension.displayName || requestingExtension.name);
|
||||
|
||||
@@ -157,7 +157,7 @@ export class UserDataSyncAccounts extends Disposable {
|
||||
|
||||
const sessions = await this.authenticationService.getSessions(authenticationProviderId) || [];
|
||||
for (const session of sessions) {
|
||||
const account: IUserDataSyncAccount = { authenticationProviderId, sessionId: session.id, accountName: session.accountName };
|
||||
const account: IUserDataSyncAccount = { authenticationProviderId, sessionId: session.id, accountName: session.account.displayName };
|
||||
accounts.set(account.accountName, account);
|
||||
if (this.isCurrentAccount(account)) {
|
||||
currentAccount = account;
|
||||
@@ -196,7 +196,7 @@ export class UserDataSyncAccounts extends Disposable {
|
||||
if (isAuthenticationProvider(result)) {
|
||||
const session = await this.authenticationService.login(result.id, result.scopes);
|
||||
sessionId = session.id;
|
||||
accountName = session.accountName;
|
||||
accountName = session.account.displayName;
|
||||
} else {
|
||||
sessionId = result.sessionId;
|
||||
accountName = result.accountName;
|
||||
|
||||
Reference in New Issue
Block a user