Portable mode improvements and bug fixes (#287063)

Disabled protocol handlers and registry updates on Windows in portable mode.
Added API proposal to detect if VS Code is running in portable mode from extensions.
Skipped protocol redirect in GitHub authentication in portable mode.
This commit is contained in:
Dmitriy Vasyura
2026-01-24 04:22:53 -08:00
committed by GitHub
parent 141d5452e8
commit aa19df565f
25 changed files with 156 additions and 26 deletions

View File

@@ -228,7 +228,8 @@ export class MsalAuthProvider implements AuthenticationProvider {
const flows = getMsalFlows({
extensionHost: this._context.extension.extensionKind === ExtensionKind.UI ? ExtensionHost.Local : ExtensionHost.Remote,
supportedClient: isSupportedClient(callbackUri),
isBrokerSupported: cachedPca.isBrokerAvailable
isBrokerSupported: cachedPca.isBrokerAvailable,
isPortableMode: env.isAppPortable
});
const authority = new URL(scopeData.tenant, this._env.activeDirectoryEndpointUrl).toString();
@@ -364,7 +365,8 @@ export class MsalAuthProvider implements AuthenticationProvider {
const flows = getMsalFlows({
extensionHost: this._context.extension.extensionKind === ExtensionKind.UI ? ExtensionHost.Local : ExtensionHost.Remote,
isBrokerSupported: cachedPca.isBrokerAvailable,
supportedClient: isSupportedClient(callbackUri)
supportedClient: isSupportedClient(callbackUri),
isPortableMode: env.isAppPortable
});
const authority = new URL(scopeData.tenant, this._env.activeDirectoryEndpointUrl).toString();

View File

@@ -22,6 +22,7 @@ interface IMsalFlowOptions {
supportsRemoteExtensionHost: boolean;
supportsUnsupportedClient: boolean;
supportsBroker: boolean;
supportsPortableMode: boolean;
}
interface IMsalFlowTriggerOptions {
@@ -47,7 +48,8 @@ class DefaultLoopbackFlow implements IMsalFlow {
options: IMsalFlowOptions = {
supportsRemoteExtensionHost: false,
supportsUnsupportedClient: true,
supportsBroker: true
supportsBroker: true,
supportsPortableMode: true
};
async trigger({ cachedPca, authority, scopes, claims, loginHint, windowHandle, logger }: IMsalFlowTriggerOptions): Promise<AuthenticationResult> {
@@ -76,7 +78,8 @@ class UrlHandlerFlow implements IMsalFlow {
options: IMsalFlowOptions = {
supportsRemoteExtensionHost: true,
supportsUnsupportedClient: false,
supportsBroker: false
supportsBroker: false,
supportsPortableMode: false
};
async trigger({ cachedPca, authority, scopes, claims, loginHint, windowHandle, logger, uriHandler, callbackUri }: IMsalFlowTriggerOptions): Promise<AuthenticationResult> {
@@ -105,7 +108,8 @@ class DeviceCodeFlow implements IMsalFlow {
options: IMsalFlowOptions = {
supportsRemoteExtensionHost: true,
supportsUnsupportedClient: true,
supportsBroker: false
supportsBroker: false,
supportsPortableMode: true
};
async trigger({ cachedPca, authority, scopes, claims, logger }: IMsalFlowTriggerOptions): Promise<AuthenticationResult> {
@@ -128,6 +132,7 @@ export interface IMsalFlowQuery {
extensionHost: ExtensionHost;
supportedClient: boolean;
isBrokerSupported: boolean;
isPortableMode: boolean;
}
export function getMsalFlows(query: IMsalFlowQuery): IMsalFlow[] {
@@ -139,6 +144,7 @@ export function getMsalFlows(query: IMsalFlowQuery): IMsalFlow[] {
}
useFlow &&= flow.options.supportsBroker || !query.isBrokerSupported;
useFlow &&= flow.options.supportsUnsupportedClient || query.supportedClient;
useFlow &&= flow.options.supportsPortableMode || !query.isPortableMode;
if (useFlow) {
flows.push(flow);
}

View File

@@ -11,7 +11,8 @@ suite('getMsalFlows', () => {
const query: IMsalFlowQuery = {
extensionHost: ExtensionHost.Local,
supportedClient: true,
isBrokerSupported: false
isBrokerSupported: false,
isPortableMode: false
};
const flows = getMsalFlows(query);
assert.strictEqual(flows.length, 3);
@@ -24,7 +25,8 @@ suite('getMsalFlows', () => {
const query: IMsalFlowQuery = {
extensionHost: ExtensionHost.Local,
supportedClient: true,
isBrokerSupported: true
isBrokerSupported: true,
isPortableMode: false
};
const flows = getMsalFlows(query);
assert.strictEqual(flows.length, 1);
@@ -35,7 +37,8 @@ suite('getMsalFlows', () => {
const query: IMsalFlowQuery = {
extensionHost: ExtensionHost.Remote,
supportedClient: true,
isBrokerSupported: false
isBrokerSupported: false,
isPortableMode: false
};
const flows = getMsalFlows(query);
assert.strictEqual(flows.length, 2);
@@ -47,7 +50,8 @@ suite('getMsalFlows', () => {
const query: IMsalFlowQuery = {
extensionHost: ExtensionHost.Local,
supportedClient: false,
isBrokerSupported: false
isBrokerSupported: false,
isPortableMode: false
};
const flows = getMsalFlows(query);
assert.strictEqual(flows.length, 2);
@@ -59,7 +63,8 @@ suite('getMsalFlows', () => {
const query: IMsalFlowQuery = {
extensionHost: ExtensionHost.Remote,
supportedClient: false,
isBrokerSupported: false
isBrokerSupported: false,
isPortableMode: false
};
const flows = getMsalFlows(query);
assert.strictEqual(flows.length, 1);
@@ -70,10 +75,24 @@ suite('getMsalFlows', () => {
const query: IMsalFlowQuery = {
extensionHost: ExtensionHost.Local,
supportedClient: false,
isBrokerSupported: true
isBrokerSupported: true,
isPortableMode: false
};
const flows = getMsalFlows(query);
assert.strictEqual(flows.length, 1);
assert.strictEqual(flows[0].label, 'default');
});
test('should exclude protocol handler flow in portable mode', () => {
const query: IMsalFlowQuery = {
extensionHost: ExtensionHost.Local,
supportedClient: true,
isBrokerSupported: false,
isPortableMode: true
};
const flows = getMsalFlows(query);
assert.strictEqual(flows.length, 2);
assert.strictEqual(flows[0].label, 'default');
assert.strictEqual(flows[1].label, 'device code');
});
});