1 | "use strict";
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
18 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
19 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
20 | else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
21 | return c > 3 && r && Object.defineProperty(target, key, r), r;
|
22 | };
|
23 | var __metadata = (this && this.__metadata) || function (k, v) {
|
24 | if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
25 | };
|
26 | Object.defineProperty(exports, "__esModule", { value: true });
|
27 | exports.readAllowedExtensions = exports.AuthenticationServiceImpl = exports.AuthenticationService = void 0;
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 | const inversify_1 = require("inversify");
|
34 | const event_1 = require("../common/event");
|
35 | const storage_service_1 = require("../browser/storage-service");
|
36 | const disposable_1 = require("../common/disposable");
|
37 | const menu_1 = require("../common/menu");
|
38 | const command_1 = require("../common/command");
|
39 | const nls_1 = require("../common/nls");
|
40 | exports.AuthenticationService = Symbol('AuthenticationService');
|
41 | let AuthenticationServiceImpl = class AuthenticationServiceImpl {
|
42 | constructor() {
|
43 | this.noAccountsCommand = { id: 'noAccounts' };
|
44 | this.signInRequestItems = new Map();
|
45 | this.sessionMap = new Map();
|
46 | this.authenticationProviders = new Map();
|
47 | this.onDidRegisterAuthenticationProviderEmitter = new event_1.Emitter();
|
48 | this.onDidRegisterAuthenticationProvider = this.onDidRegisterAuthenticationProviderEmitter.event;
|
49 | this.onDidUnregisterAuthenticationProviderEmitter = new event_1.Emitter();
|
50 | this.onDidUnregisterAuthenticationProvider = this.onDidUnregisterAuthenticationProviderEmitter.event;
|
51 | this.onDidChangeSessionsEmitter = new event_1.Emitter();
|
52 | this.onDidChangeSessions = this.onDidChangeSessionsEmitter.event;
|
53 | }
|
54 | init() {
|
55 | this.onDidChangeSessions(event => this.handleSessionChange(event));
|
56 | this.commands.registerCommand(this.noAccountsCommand, {
|
57 | execute: () => { },
|
58 | isEnabled: () => false
|
59 | });
|
60 | }
|
61 | async handleSessionChange(changeEvent) {
|
62 | var _a;
|
63 | if (changeEvent.event.added && changeEvent.event.added.length > 0) {
|
64 | const sessions = await this.getSessions(changeEvent.providerId);
|
65 | sessions.forEach(session => {
|
66 | if (!this.sessionMap.get(session.id)) {
|
67 | this.sessionMap.set(session.id, this.createAccountUi(changeEvent.providerId, changeEvent.label, session));
|
68 | }
|
69 | });
|
70 | }
|
71 | for (const removed of changeEvent.event.removed || []) {
|
72 | const sessionId = typeof removed === 'string' ? removed : removed === null || removed === void 0 ? void 0 : removed.id;
|
73 | if (sessionId) {
|
74 | (_a = this.sessionMap.get(sessionId)) === null || _a === void 0 ? void 0 : _a.dispose();
|
75 | this.sessionMap.delete(sessionId);
|
76 | }
|
77 | }
|
78 | }
|
79 | createAccountUi(providerId, providerLabel, session) {
|
80 |
|
81 | const providerAccountId = `account-sign-out-${providerId}-${session.account.id}`;
|
82 | this.commands.unregisterCommand(providerAccountId);
|
83 | const providerAccountSubmenu = [...menu_1.ACCOUNTS_SUBMENU, providerAccountId];
|
84 | this.menus.unregisterMenuAction({ commandId: providerAccountId }, providerAccountSubmenu);
|
85 |
|
86 | const disposables = new disposable_1.DisposableCollection();
|
87 | disposables.push(this.commands.registerCommand({ id: providerAccountId }, {
|
88 | execute: async () => {
|
89 | this.signOutOfAccount(providerId, session.account.label);
|
90 | }
|
91 | }));
|
92 | this.menus.registerSubmenu(providerAccountSubmenu, `${session.account.label} (${providerLabel})`);
|
93 | disposables.push(this.menus.registerMenuAction(providerAccountSubmenu, {
|
94 | label: nls_1.nls.localizeByDefault('Sign Out'),
|
95 | commandId: providerAccountId
|
96 | }));
|
97 | return disposables;
|
98 | }
|
99 | getProviderIds() {
|
100 | const providerIds = [];
|
101 | this.authenticationProviders.forEach(provider => {
|
102 | providerIds.push(provider.id);
|
103 | });
|
104 | return providerIds;
|
105 | }
|
106 | isAuthenticationProviderRegistered(id) {
|
107 | return this.authenticationProviders.has(id);
|
108 | }
|
109 | updateAccountsMenuItem() {
|
110 | let hasSession = false;
|
111 | this.authenticationProviders.forEach(async (provider) => {
|
112 | hasSession = hasSession || provider.hasSessions();
|
113 | });
|
114 | if (hasSession && this.noAccountsMenuItem) {
|
115 | this.noAccountsMenuItem.dispose();
|
116 | this.noAccountsMenuItem = undefined;
|
117 | }
|
118 | if (!hasSession && !this.noAccountsMenuItem) {
|
119 | this.noAccountsMenuItem = this.menus.registerMenuAction(menu_1.ACCOUNTS_MENU, {
|
120 | label: 'You are not signed in to any accounts',
|
121 | order: '0',
|
122 | commandId: this.noAccountsCommand.id
|
123 | });
|
124 | }
|
125 | }
|
126 | registerAuthenticationProvider(id, authenticationProvider) {
|
127 | if (this.authenticationProviders.get(id)) {
|
128 | throw new Error(`An authentication provider with id '${id}' is already registered.`);
|
129 | }
|
130 | this.authenticationProviders.set(id, authenticationProvider);
|
131 | this.onDidRegisterAuthenticationProviderEmitter.fire({ id, label: authenticationProvider.label });
|
132 | this.updateAccountsMenuItem();
|
133 | console.log(`An authentication provider with id '${id}' was registered.`);
|
134 | }
|
135 | unregisterAuthenticationProvider(id) {
|
136 | const provider = this.authenticationProviders.get(id);
|
137 | if (provider) {
|
138 | this.authenticationProviders.delete(id);
|
139 | this.onDidUnregisterAuthenticationProviderEmitter.fire({ id, label: provider.label });
|
140 | this.updateAccountsMenuItem();
|
141 | }
|
142 | else {
|
143 | console.error(`Failed to unregister an authentication provider. A provider with id '${id}' was not found.`);
|
144 | }
|
145 | }
|
146 | async updateSessions(id, event) {
|
147 | const provider = this.authenticationProviders.get(id);
|
148 | if (provider) {
|
149 | await provider.updateSessionItems(event);
|
150 | this.onDidChangeSessionsEmitter.fire({ providerId: id, label: provider.label, event: event });
|
151 | this.updateAccountsMenuItem();
|
152 | if (event.added) {
|
153 | await this.updateNewSessionRequests(provider);
|
154 | }
|
155 | }
|
156 | else {
|
157 | console.error(`Failed to update an authentication session. An authentication provider with id '${id}' was not found.`);
|
158 | }
|
159 | }
|
160 | async updateNewSessionRequests(provider) {
|
161 | const existingRequestsForProvider = this.signInRequestItems.get(provider.id);
|
162 | if (!existingRequestsForProvider) {
|
163 | return;
|
164 | }
|
165 | const sessions = await provider.getSessions();
|
166 | Object.keys(existingRequestsForProvider).forEach(requestedScopes => {
|
167 | if (sessions.some(session => session.scopes.slice().sort().join('') === requestedScopes)) {
|
168 | const sessionRequest = existingRequestsForProvider[requestedScopes];
|
169 | if (sessionRequest) {
|
170 | sessionRequest.disposables.forEach(item => item.dispose());
|
171 | }
|
172 | delete existingRequestsForProvider[requestedScopes];
|
173 | if (Object.keys(existingRequestsForProvider).length === 0) {
|
174 | this.signInRequestItems.delete(provider.id);
|
175 | }
|
176 | else {
|
177 | this.signInRequestItems.set(provider.id, existingRequestsForProvider);
|
178 | }
|
179 | }
|
180 | });
|
181 | }
|
182 | async requestNewSession(providerId, scopes, extensionId, extensionName) {
|
183 | let provider = this.authenticationProviders.get(providerId);
|
184 | if (!provider) {
|
185 |
|
186 |
|
187 |
|
188 | await new Promise((resolve, _) => {
|
189 | this.onDidRegisterAuthenticationProvider(e => {
|
190 | if (e.id === providerId) {
|
191 | provider = this.authenticationProviders.get(providerId);
|
192 | resolve(undefined);
|
193 | }
|
194 | });
|
195 | });
|
196 | }
|
197 | if (provider) {
|
198 | const providerRequests = this.signInRequestItems.get(providerId);
|
199 | const scopesList = scopes.sort().join('');
|
200 | const extensionHasExistingRequest = providerRequests
|
201 | && providerRequests[scopesList]
|
202 | && providerRequests[scopesList].requestingExtensionIds.indexOf(extensionId) > -1;
|
203 | if (extensionHasExistingRequest) {
|
204 | return;
|
205 | }
|
206 | const menuItem = this.menus.registerMenuAction(menu_1.ACCOUNTS_SUBMENU, {
|
207 | label: `Sign in to use ${extensionName} (1)`,
|
208 | order: '1',
|
209 | commandId: `${extensionId}signIn`,
|
210 | });
|
211 | const signInCommand = this.commands.registerCommand({ id: `${extensionId}signIn` }, {
|
212 | execute: async () => {
|
213 | const session = await this.login(providerId, scopes);
|
214 |
|
215 | const allowList = await readAllowedExtensions(this.storageService, providerId, session.account.label);
|
216 | if (!allowList.find(allowed => allowed.id === extensionId)) {
|
217 | allowList.push({ id: extensionId, name: extensionName });
|
218 | this.storageService.setData(`authentication-trusted-extensions-${providerId}-${session.account.label}`, JSON.stringify(allowList));
|
219 | }
|
220 |
|
221 | this.storageService.setData(`authentication-session-${extensionName}-${providerId}`, session.id);
|
222 | }
|
223 | });
|
224 | if (providerRequests) {
|
225 | const existingRequest = providerRequests[scopesList] || { disposables: [], requestingExtensionIds: [] };
|
226 | providerRequests[scopesList] = {
|
227 | disposables: [...existingRequest.disposables, menuItem, signInCommand],
|
228 | requestingExtensionIds: [...existingRequest.requestingExtensionIds, extensionId]
|
229 | };
|
230 | this.signInRequestItems.set(providerId, providerRequests);
|
231 | }
|
232 | else {
|
233 | this.signInRequestItems.set(providerId, {
|
234 | [scopesList]: {
|
235 | disposables: [menuItem, signInCommand],
|
236 | requestingExtensionIds: [extensionId]
|
237 | }
|
238 | });
|
239 | }
|
240 | }
|
241 | }
|
242 | getLabel(id) {
|
243 | const authProvider = this.authenticationProviders.get(id);
|
244 | if (authProvider) {
|
245 | return authProvider.label;
|
246 | }
|
247 | else {
|
248 | throw new Error(`No authentication provider '${id}' is currently registered.`);
|
249 | }
|
250 | }
|
251 | supportsMultipleAccounts(id) {
|
252 | const authProvider = this.authenticationProviders.get(id);
|
253 | if (authProvider) {
|
254 | return authProvider.supportsMultipleAccounts;
|
255 | }
|
256 | else {
|
257 | throw new Error(`No authentication provider '${id}' is currently registered.`);
|
258 | }
|
259 | }
|
260 | async getSessions(id, scopes) {
|
261 | const authProvider = this.authenticationProviders.get(id);
|
262 | if (authProvider) {
|
263 | return authProvider.getSessions(scopes);
|
264 | }
|
265 | else {
|
266 | throw new Error(`No authentication provider '${id}' is currently registered.`);
|
267 | }
|
268 | }
|
269 | async login(id, scopes) {
|
270 | const authProvider = this.authenticationProviders.get(id);
|
271 | if (authProvider) {
|
272 | return authProvider.createSession(scopes);
|
273 | }
|
274 | else {
|
275 | throw new Error(`No authentication provider '${id}' is currently registered.`);
|
276 | }
|
277 | }
|
278 | async logout(id, sessionId) {
|
279 | const authProvider = this.authenticationProviders.get(id);
|
280 | if (authProvider) {
|
281 | return authProvider.removeSession(sessionId);
|
282 | }
|
283 | else {
|
284 | throw new Error(`No authentication provider '${id}' is currently registered.`);
|
285 | }
|
286 | }
|
287 | async signOutOfAccount(id, accountName) {
|
288 | const authProvider = this.authenticationProviders.get(id);
|
289 | if (authProvider) {
|
290 | return authProvider.signOut(accountName);
|
291 | }
|
292 | else {
|
293 | throw new Error(`No authentication provider '${id}' is currently registered.`);
|
294 | }
|
295 | }
|
296 | };
|
297 | __decorate([
|
298 | (0, inversify_1.inject)(menu_1.MenuModelRegistry),
|
299 | __metadata("design:type", menu_1.MenuModelRegistry)
|
300 | ], AuthenticationServiceImpl.prototype, "menus", void 0);
|
301 | __decorate([
|
302 | (0, inversify_1.inject)(command_1.CommandRegistry),
|
303 | __metadata("design:type", command_1.CommandRegistry)
|
304 | ], AuthenticationServiceImpl.prototype, "commands", void 0);
|
305 | __decorate([
|
306 | (0, inversify_1.inject)(storage_service_1.StorageService),
|
307 | __metadata("design:type", Object)
|
308 | ], AuthenticationServiceImpl.prototype, "storageService", void 0);
|
309 | __decorate([
|
310 | (0, inversify_1.postConstruct)(),
|
311 | __metadata("design:type", Function),
|
312 | __metadata("design:paramtypes", []),
|
313 | __metadata("design:returntype", void 0)
|
314 | ], AuthenticationServiceImpl.prototype, "init", null);
|
315 | AuthenticationServiceImpl = __decorate([
|
316 | (0, inversify_1.injectable)()
|
317 | ], AuthenticationServiceImpl);
|
318 | exports.AuthenticationServiceImpl = AuthenticationServiceImpl;
|
319 | async function readAllowedExtensions(storageService, providerId, accountName) {
|
320 | let trustedExtensions = [];
|
321 | try {
|
322 | const trustedExtensionSrc = await storageService.getData(`authentication-trusted-extensions-${providerId}-${accountName}`);
|
323 | if (trustedExtensionSrc) {
|
324 | trustedExtensions = JSON.parse(trustedExtensionSrc);
|
325 | }
|
326 | }
|
327 | catch (err) {
|
328 | console.error(err);
|
329 | }
|
330 | return trustedExtensions;
|
331 | }
|
332 | exports.readAllowedExtensions = readAllowedExtensions;
|
333 |
|
\ | No newline at end of file |