Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/platform/authentication/vscode-node/session.ts
13401 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { authentication, AuthenticationGetSessionOptions, AuthenticationSession, AuthenticationSessionsChangeEvent } from 'vscode';
7
import { mixin } from '../../../util/vs/base/common/objects';
8
import { URI } from '../../../util/vs/base/common/uri';
9
import { AuthPermissionMode, ConfigKey, IConfigurationService } from '../../configuration/common/configurationService';
10
import { authProviderId, GITHUB_SCOPE_ALIGNED, GITHUB_SCOPE_READ_USER, GITHUB_SCOPE_USER_EMAIL, MinimalModeError } from '../common/authentication';
11
12
export const SESSION_LOGIN_MESSAGE = 'You are not signed in to GitHub. Please sign in to use Copilot.';
13
// These types are subsets of the "real" types AuthenticationSessionAccountInformation and
14
// AuthenticationSession. They allow us to use the type system to validate which fields
15
// are actually needed and hence which ones need values when we construct fake session.
16
type CopilotAuthenticationSessionAccountInformation = {
17
label: string;
18
};
19
20
export type CopilotAuthenticationSession = {
21
accessToken: string;
22
account: CopilotAuthenticationSessionAccountInformation;
23
};
24
25
async function getAuthSession(providerId: string, defaultScopes: string[], getSilentSession: () => Promise<AuthenticationSession | undefined>, options: AuthenticationGetSessionOptions = {}) {
26
const accounts = await authentication.getAccounts(providerId);
27
if (!accounts.length) {
28
return await authentication.getSession(providerId, defaultScopes, options);
29
}
30
31
if (options.forceNewSession) {
32
const session = await authentication.getSession(providerId, defaultScopes, {
33
...options,
34
forceNewSession: mixin({ learnMore: URI.parse('https://aka.ms/copilotRepoScope') }, options.forceNewSession),
35
// When GitHub becomes a true multi-account provider, we won't have to clearSessionPreference.
36
clearSessionPreference: true
37
});
38
return session;
39
}
40
41
const silentSession = await getSilentSession();
42
if (silentSession) {
43
return silentSession;
44
}
45
46
if (options.createIfNone) {
47
// This will force GitHub auth to present a picker to choose which account you want to log in to if there
48
// are multiple accounts.
49
// When GitHub becomes a true multi-account provider, we can change this to just createIfNone: true.
50
const session = await authentication.getSession(providerId, defaultScopes, options);
51
return session;
52
}
53
// Pass the options in as they are
54
return await authentication.getSession(providerId, defaultScopes, options);
55
}
56
57
/**
58
* Cast a wide net to get a session with any of the scopes that Copilot needs.
59
* @param configurationService for determining the auth provider
60
* @returns an auth session with any of the scopes that Copilot needs, or undefined if none is found
61
* @deprecated use `IAuthenticationService` instead
62
*/
63
export function getAnyAuthSession(configurationService: IConfigurationService, options?: AuthenticationGetSessionOptions): Promise<AuthenticationSession | undefined> {
64
const providerId = authProviderId(configurationService);
65
66
return getAuthSession(
67
providerId,
68
GITHUB_SCOPE_USER_EMAIL,
69
async () => {
70
// Ask for aligned scopes first, since that's what we want to use going forward.
71
if (configurationService.getConfig(ConfigKey.Shared.AuthPermissions) !== AuthPermissionMode.Minimal) {
72
const permissive = await authentication.getSession(providerId, GITHUB_SCOPE_ALIGNED, { silent: true });
73
if (permissive) {
74
return permissive;
75
}
76
}
77
const minimal = await authentication.getSession(providerId, GITHUB_SCOPE_USER_EMAIL, { silent: true });
78
if (minimal) {
79
return minimal;
80
}
81
// This is what Completions extension use to ask for and is here mostly for backwards compatibility.
82
const fallback = await authentication.getSession(providerId, GITHUB_SCOPE_READ_USER, { silent: true });
83
if (fallback) {
84
return fallback;
85
}
86
return undefined;
87
},
88
options
89
);
90
}
91
92
/**
93
* Get a session with an access token that has the same scopes as other GitHub extensions like GitHub Pull Requests.
94
* @param configurationService for determining the auth provider
95
* @param options what get passed in to getSession
96
* @returns an auth session with a token with the aligned scopes, or undefined if none is found
97
* @deprecated use `IAuthenticationService` instead
98
*/
99
export function getAlignedSession(configurationService: IConfigurationService, options: AuthenticationGetSessionOptions): Promise<AuthenticationSession | undefined> {
100
if (configurationService.getConfig(ConfigKey.Shared.AuthPermissions) === AuthPermissionMode.Minimal) {
101
if (options.createIfNone || options.forceNewSession) {
102
throw new MinimalModeError();
103
}
104
return Promise.resolve(undefined);
105
}
106
const providerId = authProviderId(configurationService);
107
return getAuthSession(
108
providerId,
109
GITHUB_SCOPE_ALIGNED,
110
async () => await authentication.getSession(providerId, GITHUB_SCOPE_ALIGNED, { silent: true }),
111
options
112
);
113
}
114
115
export function authChangeAffectsCopilot(event: AuthenticationSessionsChangeEvent, configurationService: IConfigurationService): boolean {
116
const provider = event.provider;
117
const providerId = authProviderId(configurationService);
118
return provider.id === providerId;
119
}
120
121