mirror of
https://github.com/microsoft/vscode.git
synced 2025-12-21 02:39:14 +00:00
Wire in a auth callback parameter to indicate Copilot terms were shown to the user (microsoft/vscode-internalbacklog#5761) (#262439)
* implement as a bag * nit --------- Co-authored-by: TylerLeonhardt <2644648+TylerLeonhardt@users.noreply.github.com>
This commit is contained in:
@@ -72,6 +72,10 @@ interface IFlowTriggerOptions {
|
|||||||
* The specific auth provider to use for the flow.
|
* The specific auth provider to use for the flow.
|
||||||
*/
|
*/
|
||||||
signInProvider?: GitHubSocialSignInProvider;
|
signInProvider?: GitHubSocialSignInProvider;
|
||||||
|
/**
|
||||||
|
* Extra parameters to include in the OAuth flow.
|
||||||
|
*/
|
||||||
|
extraAuthorizeParameters?: Record<string, string>;
|
||||||
/**
|
/**
|
||||||
* The Uri that the OAuth flow will redirect to. (i.e. vscode.dev/redirect)
|
* The Uri that the OAuth flow will redirect to. (i.e. vscode.dev/redirect)
|
||||||
*/
|
*/
|
||||||
@@ -180,6 +184,7 @@ class UrlHandlerFlow implements IFlow {
|
|||||||
enterpriseUri,
|
enterpriseUri,
|
||||||
nonce,
|
nonce,
|
||||||
signInProvider,
|
signInProvider,
|
||||||
|
extraAuthorizeParameters,
|
||||||
uriHandler,
|
uriHandler,
|
||||||
existingLogin,
|
existingLogin,
|
||||||
logger,
|
logger,
|
||||||
@@ -210,6 +215,11 @@ class UrlHandlerFlow implements IFlow {
|
|||||||
if (signInProvider) {
|
if (signInProvider) {
|
||||||
searchParams.append('provider', signInProvider);
|
searchParams.append('provider', signInProvider);
|
||||||
}
|
}
|
||||||
|
if (extraAuthorizeParameters) {
|
||||||
|
for (const [key, value] of Object.entries(extraAuthorizeParameters)) {
|
||||||
|
searchParams.append(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// The extra toString, parse is apparently needed for env.openExternal
|
// The extra toString, parse is apparently needed for env.openExternal
|
||||||
// to open the correct URL.
|
// to open the correct URL.
|
||||||
@@ -259,6 +269,7 @@ class LocalServerFlow implements IFlow {
|
|||||||
callbackUri,
|
callbackUri,
|
||||||
enterpriseUri,
|
enterpriseUri,
|
||||||
signInProvider,
|
signInProvider,
|
||||||
|
extraAuthorizeParameters,
|
||||||
existingLogin,
|
existingLogin,
|
||||||
logger
|
logger
|
||||||
}: IFlowTriggerOptions): Promise<string> {
|
}: IFlowTriggerOptions): Promise<string> {
|
||||||
@@ -285,6 +296,11 @@ class LocalServerFlow implements IFlow {
|
|||||||
if (signInProvider) {
|
if (signInProvider) {
|
||||||
searchParams.append('provider', signInProvider);
|
searchParams.append('provider', signInProvider);
|
||||||
}
|
}
|
||||||
|
if (extraAuthorizeParameters) {
|
||||||
|
for (const [key, value] of Object.entries(extraAuthorizeParameters)) {
|
||||||
|
searchParams.append(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const loginUrl = baseUri.with({
|
const loginUrl = baseUri.with({
|
||||||
path: '/login/oauth/authorize',
|
path: '/login/oauth/authorize',
|
||||||
@@ -332,7 +348,7 @@ class DeviceCodeFlow implements IFlow {
|
|||||||
supportsSupportedClients: true,
|
supportsSupportedClients: true,
|
||||||
supportsUnsupportedClients: true
|
supportsUnsupportedClients: true
|
||||||
};
|
};
|
||||||
async trigger({ scopes, baseUri, signInProvider, logger }: IFlowTriggerOptions) {
|
async trigger({ scopes, baseUri, signInProvider, extraAuthorizeParameters, logger }: IFlowTriggerOptions) {
|
||||||
logger.info(`Trying device code flow... (${scopes})`);
|
logger.info(`Trying device code flow... (${scopes})`);
|
||||||
|
|
||||||
// Get initial device code
|
// Get initial device code
|
||||||
@@ -369,9 +385,16 @@ class DeviceCodeFlow implements IFlow {
|
|||||||
await env.clipboard.writeText(json.user_code);
|
await env.clipboard.writeText(json.user_code);
|
||||||
|
|
||||||
let open = Uri.parse(json.verification_uri);
|
let open = Uri.parse(json.verification_uri);
|
||||||
if (signInProvider) {
|
|
||||||
const query = new URLSearchParams(open.query);
|
const query = new URLSearchParams(open.query);
|
||||||
|
if (signInProvider) {
|
||||||
query.set('provider', signInProvider);
|
query.set('provider', signInProvider);
|
||||||
|
}
|
||||||
|
if (extraAuthorizeParameters) {
|
||||||
|
for (const [key, value] of Object.entries(extraAuthorizeParameters)) {
|
||||||
|
query.set(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (signInProvider || extraAuthorizeParameters) {
|
||||||
open = open.with({ query: query.toString() });
|
open = open.with({ query: query.toString() });
|
||||||
}
|
}
|
||||||
const uriToOpen = await env.asExternalUri(open);
|
const uriToOpen = await env.asExternalUri(open);
|
||||||
|
|||||||
@@ -44,6 +44,27 @@ interface GitHubAuthenticationProviderOptions extends vscode.AuthenticationProvi
|
|||||||
* leaving it up to the user to choose the social sign-in provider on the sign-in page.
|
* leaving it up to the user to choose the social sign-in provider on the sign-in page.
|
||||||
*/
|
*/
|
||||||
readonly provider?: GitHubSocialSignInProvider;
|
readonly provider?: GitHubSocialSignInProvider;
|
||||||
|
readonly extraAuthorizeParameters?: Record<string, string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isGitHubAuthenticationProviderOptions(object: any): object is GitHubAuthenticationProviderOptions {
|
||||||
|
if (!object || typeof object !== 'object') {
|
||||||
|
throw new Error('Options are not an object');
|
||||||
|
}
|
||||||
|
if (object.provider !== undefined && !isSocialSignInProvider(object.provider)) {
|
||||||
|
throw new Error(`Provider is invalid: ${object.provider}`);
|
||||||
|
}
|
||||||
|
if (object.extraAuthorizeParameters !== undefined) {
|
||||||
|
if (!object.extraAuthorizeParameters || typeof object.extraAuthorizeParameters !== 'object') {
|
||||||
|
throw new Error('Extra parameters must be a record of string keys and string values.');
|
||||||
|
}
|
||||||
|
for (const [key, value] of Object.entries(object.extraAuthorizeParameters)) {
|
||||||
|
if (typeof key !== 'string' || typeof value !== 'string') {
|
||||||
|
throw new Error('Extra parameters must be a record of string keys and string values.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class UriEventHandler extends vscode.EventEmitter<vscode.Uri> implements vscode.UriHandler {
|
export class UriEventHandler extends vscode.EventEmitter<vscode.Uri> implements vscode.UriHandler {
|
||||||
@@ -338,12 +359,15 @@ export class GitHubAuthenticationProvider implements vscode.AuthenticationProvid
|
|||||||
scopes: JSON.stringify(scopes),
|
scopes: JSON.stringify(scopes),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (options && !isGitHubAuthenticationProviderOptions(options)) {
|
||||||
|
throw new Error('Invalid options');
|
||||||
|
}
|
||||||
const sessions = await this._sessionsPromise;
|
const sessions = await this._sessionsPromise;
|
||||||
const loginWith = options?.account?.label;
|
const loginWith = options?.account?.label;
|
||||||
const signInProvider = isSocialSignInProvider(options?.provider) ? options.provider : undefined;
|
const signInProvider = options?.provider;
|
||||||
this._logger.info(`Logging in with${signInProvider ? ` ${signInProvider}, ` : ''} '${loginWith ? loginWith : 'any'}' account...`);
|
this._logger.info(`Logging in with${signInProvider ? ` ${signInProvider}, ` : ''} '${loginWith ? loginWith : 'any'}' account...`);
|
||||||
const scopeString = sortedScopes.join(' ');
|
const scopeString = sortedScopes.join(' ');
|
||||||
const token = await this._githubServer.login(scopeString, signInProvider, loginWith);
|
const token = await this._githubServer.login(scopeString, signInProvider, options?.extraAuthorizeParameters, loginWith);
|
||||||
const session = await this.tokenToSession(token, scopes);
|
const session = await this.tokenToSession(token, scopes);
|
||||||
this.afterSessionLoad(session);
|
this.afterSessionLoad(session);
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ const REDIRECT_URL_STABLE = 'https://vscode.dev/redirect';
|
|||||||
const REDIRECT_URL_INSIDERS = 'https://insiders.vscode.dev/redirect';
|
const REDIRECT_URL_INSIDERS = 'https://insiders.vscode.dev/redirect';
|
||||||
|
|
||||||
export interface IGitHubServer {
|
export interface IGitHubServer {
|
||||||
login(scopes: string, signInProvider?: GitHubSocialSignInProvider, existingLogin?: string): Promise<string>;
|
login(scopes: string, signInProvider?: GitHubSocialSignInProvider, extraAuthorizeParameters?: Record<string, string>, existingLogin?: string): Promise<string>;
|
||||||
logout(session: vscode.AuthenticationSession): Promise<void>;
|
logout(session: vscode.AuthenticationSession): Promise<void>;
|
||||||
getUserInfo(token: string): Promise<{ id: string; accountName: string }>;
|
getUserInfo(token: string): Promise<{ id: string; accountName: string }>;
|
||||||
sendAdditionalTelemetryInfo(session: vscode.AuthenticationSession): Promise<void>;
|
sendAdditionalTelemetryInfo(session: vscode.AuthenticationSession): Promise<void>;
|
||||||
@@ -87,7 +87,7 @@ export class GitHubServer implements IGitHubServer {
|
|||||||
return this._isNoCorsEnvironment;
|
return this._isNoCorsEnvironment;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async login(scopes: string, signInProvider?: GitHubSocialSignInProvider, existingLogin?: string): Promise<string> {
|
public async login(scopes: string, signInProvider?: GitHubSocialSignInProvider, extraAuthorizeParameters?: Record<string, string>, existingLogin?: string): Promise<string> {
|
||||||
this._logger.info(`Logging in for the following scopes: ${scopes}`);
|
this._logger.info(`Logging in for the following scopes: ${scopes}`);
|
||||||
|
|
||||||
// Used for showing a friendlier message to the user when the explicitly cancel a flow.
|
// Used for showing a friendlier message to the user when the explicitly cancel a flow.
|
||||||
@@ -136,6 +136,7 @@ export class GitHubServer implements IGitHubServer {
|
|||||||
callbackUri,
|
callbackUri,
|
||||||
nonce,
|
nonce,
|
||||||
signInProvider,
|
signInProvider,
|
||||||
|
extraAuthorizeParameters,
|
||||||
baseUri: this.baseUri,
|
baseUri: this.baseUri,
|
||||||
logger: this._logger,
|
logger: this._logger,
|
||||||
uriHandler: this._uriHandler,
|
uriHandler: this._uriHandler,
|
||||||
|
|||||||
@@ -908,7 +908,13 @@ export class ChatEntitlementRequests extends Disposable {
|
|||||||
const providerId = ChatEntitlementRequests.providerId(this.configurationService);
|
const providerId = ChatEntitlementRequests.providerId(this.configurationService);
|
||||||
|
|
||||||
const scopes = options?.additionalScopes ? distinct([...defaultChat.providerScopes[0], ...options.additionalScopes]) : defaultChat.providerScopes[0];
|
const scopes = options?.additionalScopes ? distinct([...defaultChat.providerScopes[0], ...options.additionalScopes]) : defaultChat.providerScopes[0];
|
||||||
const session = await this.authenticationService.createSession(providerId, scopes, options?.useSocialProvider ? { provider: options.useSocialProvider } : undefined);
|
const session = await this.authenticationService.createSession(
|
||||||
|
providerId,
|
||||||
|
scopes,
|
||||||
|
{
|
||||||
|
extraAuthorizeParameters: { get_started_with: 'copilot-vscode' },
|
||||||
|
provider: options?.useSocialProvider
|
||||||
|
});
|
||||||
|
|
||||||
this.authenticationExtensionsService.updateAccountPreference(defaultChat.extensionId, providerId, session.account);
|
this.authenticationExtensionsService.updateAccountPreference(defaultChat.extensionId, providerId, session.account);
|
||||||
this.authenticationExtensionsService.updateAccountPreference(defaultChat.chatExtensionId, providerId, session.account);
|
this.authenticationExtensionsService.updateAccountPreference(defaultChat.chatExtensionId, providerId, session.account);
|
||||||
|
|||||||
Reference in New Issue
Block a user