Skip to content

Commit 2e5312c

Browse files
author
Rachel Macfarlane
committed
Add account id to authentication session object
1 parent c622be7 commit 2e5312c

9 files changed

Lines changed: 99 additions & 45 deletions

File tree

extensions/github-authentication/src/github.ts

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,27 @@ import Logger from './common/logger';
1212
export const onDidChangeSessions = new vscode.EventEmitter<vscode.AuthenticationSessionsChangeEvent>();
1313

1414
interface SessionData {
15+
id: string;
16+
account?: {
17+
displayName: string;
18+
id: string;
19+
}
20+
scopes: string[];
21+
accessToken: string;
22+
}
23+
24+
// TODO remove
25+
interface OldSessionData {
1526
id: string;
1627
accountName: string;
1728
scopes: string[];
1829
accessToken: string;
1930
}
2031

32+
function isOldSessionData(x: any): x is OldSessionData {
33+
return !!x.accountName;
34+
}
35+
2136
export class GitHubAuthenticationProvider {
2237
private _sessions: vscode.AuthenticationSession[] = [];
2338
private _githubServer = new GitHubServer();
@@ -68,15 +83,34 @@ export class GitHubAuthenticationProvider {
6883
const storedSessions = await keychain.getToken();
6984
if (storedSessions) {
7085
try {
71-
const sessionData: SessionData[] = JSON.parse(storedSessions);
72-
return sessionData.map(session => {
73-
return {
74-
id: session.id,
75-
accountName: session.accountName,
76-
scopes: session.scopes,
77-
getAccessToken: () => Promise.resolve(session.accessToken)
78-
};
86+
const sessionData: (SessionData | OldSessionData)[] = JSON.parse(storedSessions);
87+
const sessionPromises = sessionData.map(async (session: SessionData | OldSessionData): Promise<vscode.AuthenticationSession | undefined> => {
88+
try {
89+
const needsUserInfo = isOldSessionData(session) || !session.account;
90+
let userInfo: { id: string, accountName: string };
91+
if (needsUserInfo) {
92+
userInfo = await this._githubServer.getUserInfo(session.accessToken);
93+
}
94+
95+
return {
96+
id: session.id,
97+
account: {
98+
displayName: isOldSessionData(session)
99+
? session.accountName
100+
: session.account?.displayName ?? userInfo!.accountName,
101+
id: isOldSessionData(session)
102+
? userInfo!.id
103+
: session.account?.id ?? userInfo!.id
104+
},
105+
scopes: session.scopes,
106+
getAccessToken: () => Promise.resolve(session.accessToken)
107+
};
108+
} catch (e) {
109+
return undefined;
110+
}
79111
});
112+
113+
return (await Promise.all(sessionPromises)).filter((x: vscode.AuthenticationSession | undefined): x is vscode.AuthenticationSession => !!x);
80114
} catch (e) {
81115
Logger.error(`Error reading sessions: ${e}`);
82116
}
@@ -90,7 +124,7 @@ export class GitHubAuthenticationProvider {
90124
const resolvedAccessToken = await session.getAccessToken();
91125
return {
92126
id: session.id,
93-
accountName: session.accountName,
127+
account: session.account,
94128
scopes: session.scopes,
95129
accessToken: resolvedAccessToken
96130
};
@@ -125,7 +159,10 @@ export class GitHubAuthenticationProvider {
125159
return {
126160
id: uuid(),
127161
getAccessToken: () => Promise.resolve(token),
128-
accountName: userInfo.accountName,
162+
account: {
163+
displayName: userInfo.accountName,
164+
id: userInfo.id
165+
},
129166
scopes: scopes
130167
};
131168
}

extensions/github-authentication/src/githubServer.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ export class GitHubServer {
145145
Logger.info('Got account info!');
146146
resolve({ id: json.id, accountName: json.login });
147147
} else {
148+
Logger.error('Getting account info failed');
148149
reject(new Error(result.statusMessage));
149150
}
150151
});

extensions/vscode-account/src/AADHelper.ts

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@ interface IToken {
2525
expiresAt?: number; // UNIX epoch time at which token will expire
2626
refreshToken: string;
2727

28-
accountName: string;
28+
account: {
29+
displayName: string;
30+
id: string;
31+
};
2932
scope: string;
3033
sessionId: string; // The account id + the scope
3134
}
@@ -44,7 +47,10 @@ interface IStoredSession {
4447
id: string;
4548
refreshToken: string;
4649
scope: string; // Scopes are alphabetized and joined with a space
47-
accountName: string;
50+
account: {
51+
displayName: string,
52+
id: string
53+
}
4854
}
4955

5056
function parseQuery(uri: vscode.Uri) {
@@ -93,7 +99,10 @@ export class AzureActiveDirectoryService {
9399
this._tokens.push({
94100
accessToken: undefined,
95101
refreshToken: session.refreshToken,
96-
accountName: session.accountName,
102+
account: {
103+
displayName: session.account.displayName,
104+
id: session.account.id
105+
},
97106
scope: session.scope,
98107
sessionId: session.id
99108
});
@@ -125,7 +134,7 @@ export class AzureActiveDirectoryService {
125134
id: token.sessionId,
126135
refreshToken: token.refreshToken,
127136
scope: token.scope,
128-
accountName: token.accountName
137+
account: token.account
129138
};
130139
});
131140

@@ -199,7 +208,7 @@ export class AzureActiveDirectoryService {
199208
return {
200209
id: token.sessionId,
201210
getAccessToken: () => this.resolveAccessToken(token),
202-
accountName: token.accountName,
211+
account: token.account,
203212
scopes: token.scope.split(' ')
204213
};
205214
}
@@ -223,8 +232,6 @@ export class AzureActiveDirectoryService {
223232
} catch (e) {
224233
throw new Error('Unavailable due to network problems');
225234
}
226-
227-
throw new Error('Unavailable due to network problems');
228235
}
229236

230237
private getTokenClaims(accessToken: string): ITokenClaims {
@@ -419,7 +426,10 @@ export class AzureActiveDirectoryService {
419426
refreshToken: json.refresh_token,
420427
scope,
421428
sessionId: existingId || `${claims.tid}/${(claims.oid || (claims.altsecid || '' + claims.ipd || ''))}/${uuid()}`,
422-
accountName: claims.email || claims.unique_name || 'user@example.com'
429+
account: {
430+
displayName: claims.email || claims.unique_name || 'user@example.com',
431+
id: `${claims.tid}/${(claims.oid || (claims.altsecid || '' + claims.ipd || ''))}`
432+
}
423433
};
424434
}
425435

extensions/vscode-account/src/extension.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ export async function activate(context: vscode.ExtensionContext) {
6969
const selectedSession = await vscode.window.showQuickPick(sessions.map(session => {
7070
return {
7171
id: session.id,
72-
label: session.accountName
72+
label: session.account.displayName
7373
};
7474
}));
7575

src/vs/editor/common/modes.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1412,7 +1412,10 @@ export interface RenameProvider {
14121412
export interface AuthenticationSession {
14131413
id: string;
14141414
getAccessToken(): Thenable<string>;
1415-
accountName: string;
1415+
account: {
1416+
displayName: string;
1417+
id: string;
1418+
}
14161419
}
14171420

14181421
/**

src/vs/vscode.proposed.d.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@ declare module 'vscode' {
2121
export interface AuthenticationSession {
2222
id: string;
2323
getAccessToken(): Thenable<string>;
24-
accountName: string;
24+
account: {
25+
displayName: string;
26+
id: string;
27+
};
2528
scopes: string[]
2629
}
2730

src/vs/workbench/api/browser/mainThreadAuthentication.ts

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -129,21 +129,21 @@ export class MainThreadAuthenticationProvider extends Disposable {
129129
}
130130

131131
private registerSession(session: modes.AuthenticationSession) {
132-
this._sessions.set(session.id, session.accountName);
132+
this._sessions.set(session.id, session.account.displayName);
133133

134-
const existingSessionsForAccount = this._accounts.get(session.accountName);
134+
const existingSessionsForAccount = this._accounts.get(session.account.displayName);
135135
if (existingSessionsForAccount) {
136-
this._accounts.set(session.accountName, existingSessionsForAccount.concat(session.id));
136+
this._accounts.set(session.account.displayName, existingSessionsForAccount.concat(session.id));
137137
return;
138138
} else {
139-
this._accounts.set(session.accountName, [session.id]);
139+
this._accounts.set(session.account.displayName, [session.id]);
140140
}
141141

142142
const menuItem = MenuRegistry.appendMenuItem(MenuId.AccountsContext, {
143143
group: '1_accounts',
144144
command: {
145145
id: `configureSessions${session.id}`,
146-
title: `${session.accountName} (${this.displayName})`
146+
title: `${session.account.displayName} (${this.displayName})`
147147
},
148148
order: 3
149149
});
@@ -170,11 +170,11 @@ export class MainThreadAuthenticationProvider extends Disposable {
170170
}
171171

172172
if (selected.label === manage) {
173-
this.manageTrustedExtensions(quickInputService, storageService, session.accountName);
173+
this.manageTrustedExtensions(quickInputService, storageService, session.account.displayName);
174174
}
175175

176176
if (selected.label === showUsage) {
177-
this.showUsage(quickInputService, session.accountName);
177+
this.showUsage(quickInputService, session.account.displayName);
178178
}
179179

180180
quickPick.dispose();
@@ -188,28 +188,28 @@ export class MainThreadAuthenticationProvider extends Disposable {
188188
},
189189
});
190190

191-
this._sessionMenuItems.set(session.accountName, [menuItem, manageCommand]);
191+
this._sessionMenuItems.set(session.account.displayName, [menuItem, manageCommand]);
192192
}
193193

194194
async signOut(dialogService: IDialogService, session: modes.AuthenticationSession): Promise<void> {
195195
const providerUsage = accountUsages.get(this.id);
196-
const accountUsage = (providerUsage || {})[session.accountName] || [];
197-
const sessionsForAccount = this._accounts.get(session.accountName);
196+
const accountUsage = (providerUsage || {})[session.account.displayName] || [];
197+
const sessionsForAccount = this._accounts.get(session.account.displayName);
198198

199199
// Skip dialog if nothing is using the account
200200
if (!accountUsage.length) {
201-
accountUsages.set(this.id, { [session.accountName]: [] });
201+
accountUsages.set(this.id, { [session.account.displayName]: [] });
202202
sessionsForAccount?.forEach(sessionId => this.logout(sessionId));
203203
return;
204204
}
205205

206206
const result = await dialogService.confirm({
207-
title: nls.localize('signOutConfirm', "Sign out of {0}", session.accountName),
208-
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'))
207+
title: nls.localize('signOutConfirm', "Sign out of {0}", session.account.displayName),
208+
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'))
209209
});
210210

211211
if (result.confirmed) {
212-
accountUsages.set(this.id, { [session.accountName]: [] });
212+
accountUsages.set(this.id, { [session.account.displayName]: [] });
213213
sessionsForAccount?.forEach(sessionId => this.logout(sessionId));
214214
}
215215
}
@@ -218,9 +218,9 @@ export class MainThreadAuthenticationProvider extends Disposable {
218218
return (await this._proxy.$getSessions(this.id)).map(session => {
219219
return {
220220
id: session.id,
221-
accountName: session.accountName,
221+
account: session.account,
222222
getAccessToken: () => {
223-
addAccountUsage(this.id, session.accountName, nls.localize('sync', "Preferences Sync"));
223+
addAccountUsage(this.id, session.account.displayName, nls.localize('sync', "Preferences Sync"));
224224
return this._proxy.$getSessionAccessToken(this.id, session.id);
225225
}
226226
};
@@ -258,7 +258,7 @@ export class MainThreadAuthenticationProvider extends Disposable {
258258
return this._proxy.$login(this.id, scopes).then(session => {
259259
return {
260260
id: session.id,
261-
accountName: session.accountName,
261+
account: session.account,
262262
getAccessToken: () => this._proxy.$getSessionAccessToken(this.id, session.id)
263263
};
264264
});

src/vs/workbench/api/common/extHostAuthentication.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,12 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
4747
.map(session => {
4848
return {
4949
id: session.id,
50-
accountName: session.accountName,
50+
account: session.account,
5151
scopes: session.scopes,
5252
getAccessToken: async () => {
5353
const isAllowed = await this._proxy.$getSessionsPrompt(
5454
provider.id,
55-
session.accountName,
55+
session.account.displayName,
5656
provider.displayName,
5757
extensionId,
5858
requestingExtension.displayName || requestingExtension.name);
@@ -80,15 +80,15 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
8080
}
8181

8282
const session = await provider.login(scopes);
83-
await this._proxy.$setTrustedExtension(provider.id, session.accountName, ExtensionIdentifier.toKey(requestingExtension.identifier), extensionName);
83+
await this._proxy.$setTrustedExtension(provider.id, session.account.displayName, ExtensionIdentifier.toKey(requestingExtension.identifier), extensionName);
8484
return {
8585
id: session.id,
86-
accountName: session.accountName,
86+
account: session.account,
8787
scopes: session.scopes,
8888
getAccessToken: async () => {
8989
const isAllowed = await this._proxy.$getSessionsPrompt(
9090
provider.id,
91-
session.accountName,
91+
session.account.displayName,
9292
provider.displayName,
9393
ExtensionIdentifier.toKey(requestingExtension.identifier),
9494
requestingExtension.displayName || requestingExtension.name);

src/vs/workbench/contrib/userDataSync/browser/userDataSyncAccount.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ export class UserDataSyncAccounts extends Disposable {
157157

158158
const sessions = await this.authenticationService.getSessions(authenticationProviderId) || [];
159159
for (const session of sessions) {
160-
const account: IUserDataSyncAccount = { authenticationProviderId, sessionId: session.id, accountName: session.accountName };
160+
const account: IUserDataSyncAccount = { authenticationProviderId, sessionId: session.id, accountName: session.account.displayName };
161161
accounts.set(account.accountName, account);
162162
if (this.isCurrentAccount(account)) {
163163
currentAccount = account;
@@ -196,7 +196,7 @@ export class UserDataSyncAccounts extends Disposable {
196196
if (isAuthenticationProvider(result)) {
197197
const session = await this.authenticationService.login(result.id, result.scopes);
198198
sessionId = session.id;
199-
accountName = session.accountName;
199+
accountName = session.account.displayName;
200200
} else {
201201
sessionId = result.sessionId;
202202
accountName = result.accountName;

0 commit comments

Comments
 (0)