Skip to content

Commit

Permalink
Improve link protection
Browse files Browse the repository at this point in the history
  • Loading branch information
octref committed Aug 26, 2019
1 parent a66e9d4 commit 2ef8955
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 24 deletions.
1 change: 1 addition & 0 deletions src/vs/platform/product/common/product.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ export interface IProductConfiguration {
};
readonly portable?: string;
readonly uiExtensions?: readonly string[];
readonly linkProtectionTrustedDomains?: readonly string[];
}

export interface IExeBasedExtensionTip {
Expand Down
62 changes: 38 additions & 24 deletions src/vs/workbench/contrib/url/common/url.contribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,29 +50,20 @@ Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions).registe
localize('developer', 'Developer')
);

const DEAFULT_TRUSTED_DOMAINS = [
'https://code.visualstudio.com',
'https://go.microsoft.com',
'https://github.com',
'https://marketplace.visualstudio.com',
'https://vscode-auth.github.com'
];

const configureTrustedDomainsHandler = async (
quickInputService: IQuickInputService,
storageService: IStorageService,
linkProtectionTrustedDomains: string[],
domainToConfigure?: string
) => {
let trustedDomains: string[] = DEAFULT_TRUSTED_DOMAINS;

try {
const trustedDomainsSrc = storageService.get('http.trustedDomains', StorageScope.GLOBAL);
const trustedDomainsSrc = storageService.get('http.linkProtectionTrustedDomains', StorageScope.GLOBAL);
if (trustedDomainsSrc) {
trustedDomains = JSON.parse(trustedDomainsSrc);
linkProtectionTrustedDomains = JSON.parse(trustedDomainsSrc);
}
} catch (err) { }

const domainQuickPickItems: IQuickPickItem[] = trustedDomains
const domainQuickPickItems: IQuickPickItem[] = linkProtectionTrustedDomains
.filter(d => d !== '*')
.map(d => {
return {
Expand All @@ -88,12 +79,12 @@ const configureTrustedDomainsHandler = async (
type: 'item',
label: localize('openAllLinksWithoutPrompt', 'Open all links without prompt'),
id: '*',
picked: trustedDomains.indexOf('*') !== -1
picked: linkProtectionTrustedDomains.indexOf('*') !== -1
}
];

let domainToConfigureItem: IQuickPickItem | undefined = undefined;
if (domainToConfigure && trustedDomains.indexOf(domainToConfigure) === -1) {
if (domainToConfigure && linkProtectionTrustedDomains.indexOf(domainToConfigure) === -1) {
domainToConfigureItem = {
type: 'item',
label: domainToConfigure,
Expand All @@ -116,7 +107,7 @@ const configureTrustedDomainsHandler = async (

if (pickedResult) {
const pickedDomains: string[] = pickedResult.map(r => r.id!);
storageService.store('http.trustedDomains', JSON.stringify(pickedDomains), StorageScope.GLOBAL);
storageService.store('http.linkProtectionTrustedDomains', JSON.stringify(pickedDomains), StorageScope.GLOBAL);

return pickedDomains;
}
Expand All @@ -125,16 +116,26 @@ const configureTrustedDomainsHandler = async (
};

const configureTrustedDomainCommand = {
id: 'workbench.action.configureTrustedDomains',
id: 'workbench.action.configureLinkProtectionTrustedDomains',
description: {
description: localize('configureTrustedDomains', 'Configure Trusted Domains'),
description: localize('configureLinkProtectionTrustedDomains', 'Configure Trusted Domains for Link Protection'),
args: [{ name: 'domainToConfigure', schema: { type: 'string' } }]
},
handler: (accessor: ServicesAccessor, domainToConfigure?: string) => {
const quickInputService = accessor.get(IQuickInputService);
const storageService = accessor.get(IStorageService);

return configureTrustedDomainsHandler(quickInputService, storageService, domainToConfigure);
const productService = accessor.get(IProductService);

const trustedDomains = productService.linkProtectionTrustedDomains
? [...productService.linkProtectionTrustedDomains]
: [];

return configureTrustedDomainsHandler(
quickInputService,
storageService,
trustedDomains,
domainToConfigure
);
}
};

Expand Down Expand Up @@ -164,17 +165,22 @@ class OpenerValidatorContributions implements IWorkbenchContribution {
return true;
}

let trustedDomains: string[] = DEAFULT_TRUSTED_DOMAINS;
let trustedDomains: string[] = this._productService.linkProtectionTrustedDomains
? [...this._productService.linkProtectionTrustedDomains]
: [];

try {
const trustedDomainsSrc = this._storageService.get('http.trustedDomains', StorageScope.GLOBAL);
const trustedDomainsSrc = this._storageService.get('http.linkProtectionTrustedDomains', StorageScope.GLOBAL);
if (trustedDomainsSrc) {
trustedDomains = JSON.parse(trustedDomainsSrc);
}
} catch (err) { }

const domainToOpen = `${scheme}://${authority}`;

if (isDomainTrusted(domainToOpen, trustedDomains)) {
if (isLocalhostAuthority(authority)) {
return true;
} else if (isDomainTrusted(domainToOpen, trustedDomains)) {
return true;
} else {
const choice = await this._dialogService.show(
Expand All @@ -201,7 +207,7 @@ class OpenerValidatorContributions implements IWorkbenchContribution {
}
// Configure Trusted Domains
else if (choice === 2) {
const pickedDomains = await configureTrustedDomainsHandler(this._quickInputService, this._storageService, domainToOpen);
const pickedDomains = await configureTrustedDomainsHandler(this._quickInputService, this._storageService, trustedDomains, domainToOpen);
if (pickedDomains.indexOf(domainToOpen) !== -1) {
return true;
}
Expand All @@ -218,6 +224,13 @@ Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).regi
LifecyclePhase.Restored
);

const rLocalhost = /^localhost:\d+$/i;
const r127 = /^127.0.0.1:\d+$/;

function isLocalhostAuthority(authority: string) {
return rLocalhost.test(authority) || r127.test(authority);
}

/**
* Check whether a domain like https://www.microsoft.com matches
* the list of trusted domains.
Expand All @@ -235,3 +248,4 @@ function isDomainTrusted(domain: string, trustedDomains: string[]) {

return false;
}

0 comments on commit 2ef8955

Please sign in to comment.