提交 73d9d76e 编写于 作者: P Pine Wu

Fix #83731

上级 e88e032d
......@@ -26,6 +26,8 @@ const TRUSTED_DOMAINS_STAT: IStat = {
const CONFIG_HELP_TEXT_PRE = `// Links matching one or more entries in the list below can be opened without link protection.
// The following examples show what entries can look like:
// - "https://microsoft.com": Matches this specific domain using https
// - "https://microsoft.com/foo": Matches https://microsoft.com/foo and https://microsoft.com/foo/bar,
// but not https://microsoft.com/foobar or https://microsoft.com/bar
// - "https://*.microsoft.com": Match all domains ending in "microsoft.com" using https
// - "microsoft.com": Match this specific domain using either http or https
// - "*.microsoft.com": Match all domains ending in "microsoft.com" using either http or https
......
......@@ -5,7 +5,7 @@
import { Schemas } from 'vs/base/common/network';
import Severity from 'vs/base/common/severity';
import { equalsIgnoreCase } from 'vs/base/common/strings';
import { equalsIgnoreCase, startsWith } from 'vs/base/common/strings';
import { URI } from 'vs/base/common/uri';
import { localize } from 'vs/nls';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
......@@ -14,7 +14,10 @@ import { IProductService } from 'vs/platform/product/common/productService';
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { configureOpenerTrustedDomainsHandler, readTrustedDomains } from 'vs/workbench/contrib/url/common/trustedDomains';
import {
configureOpenerTrustedDomainsHandler,
readTrustedDomains
} from 'vs/workbench/contrib/url/common/trustedDomains';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
export class OpenerValidatorContributions implements IWorkbenchContribution {
......@@ -132,10 +135,11 @@ export function isURLDomainTrusted(url: URI, trustedDomains: string[]) {
}
if (url.authority === parsedTrustedDomain.authority) {
return true;
return pathMatches(url.path, parsedTrustedDomain.path);
}
if (trustedDomains[i].indexOf('*') !== -1) {
let reversedAuthoritySegments = url.authority.split('.').reverse();
const reversedTrustedDomainAuthoritySegments = parsedTrustedDomain.authority.split('.').reverse();
......@@ -146,11 +150,11 @@ export function isURLDomainTrusted(url: URI, trustedDomains: string[]) {
reversedAuthoritySegments = reversedAuthoritySegments.slice(0, reversedTrustedDomainAuthoritySegments.length);
}
if (
reversedAuthoritySegments.every((val, i) => {
return reversedTrustedDomainAuthoritySegments[i] === '*' || val === reversedTrustedDomainAuthoritySegments[i];
})
) {
const authorityMatches = reversedAuthoritySegments.every((val, i) => {
return reversedTrustedDomainAuthoritySegments[i] === '*' || val === reversedTrustedDomainAuthoritySegments[i];
});
if (authorityMatches && pathMatches(url.path, parsedTrustedDomain.path)) {
return true;
}
}
......@@ -158,3 +162,19 @@ export function isURLDomainTrusted(url: URI, trustedDomains: string[]) {
return false;
}
function pathMatches(open: string, rule: string) {
if (rule === '/') {
return true;
}
const openSegments = open.split('/');
const ruleSegments = rule.split('/');
for (let i = 0; i < ruleSegments.length; i++) {
if (ruleSegments[i] !== openSegments[i]) {
return false;
}
}
return true;
}
......@@ -8,49 +8,67 @@ import * as assert from 'assert';
import { isURLDomainTrusted } from 'vs/workbench/contrib/url/common/trustedDomainsValidator';
import { URI } from 'vs/base/common/uri';
function linkProtectedByRules(link: string, rules: string[]) {
assert.ok(isURLDomainTrusted(URI.parse(link), rules));
function linkAllowedByRules(link: string, rules: string[]) {
assert.ok(isURLDomainTrusted(URI.parse(link), rules), `Link\n${link}\n should be protected by rules\n${JSON.stringify(rules)}`);
}
function linkNotProtectedByRules(link: string, rules: string[]) {
assert.ok(!isURLDomainTrusted(URI.parse(link), rules));
function linkNotAllowedByRules(link: string, rules: string[]) {
assert.ok(!isURLDomainTrusted(URI.parse(link), rules), `Link\n${link}\n should NOT be protected by rules\n${JSON.stringify(rules)}`);
}
suite('Link protection domain matching', () => {
test('simple', () => {
linkNotProtectedByRules('https://x.org', []);
linkNotAllowedByRules('https://x.org', []);
linkProtectedByRules('https://x.org', ['https://x.org']);
linkProtectedByRules('https://x.org/foo', ['https://x.org']);
linkAllowedByRules('https://x.org', ['https://x.org']);
linkAllowedByRules('https://x.org/foo', ['https://x.org']);
linkNotProtectedByRules('https://x.org', ['http://x.org']);
linkNotProtectedByRules('http://x.org', ['https://x.org']);
linkNotAllowedByRules('https://x.org', ['http://x.org']);
linkNotAllowedByRules('http://x.org', ['https://x.org']);
linkNotProtectedByRules('https://www.x.org', ['https://x.org']);
linkNotAllowedByRules('https://www.x.org', ['https://x.org']);
linkProtectedByRules('https://www.x.org', ['https://www.x.org', 'https://y.org']);
linkAllowedByRules('https://www.x.org', ['https://www.x.org', 'https://y.org']);
});
test('localhost', () => {
linkProtectedByRules('https://127.0.0.1', []);
linkProtectedByRules('https://127.0.0.1:3000', []);
linkProtectedByRules('https://localhost', []);
linkProtectedByRules('https://localhost:3000', []);
linkAllowedByRules('https://127.0.0.1', []);
linkAllowedByRules('https://127.0.0.1:3000', []);
linkAllowedByRules('https://localhost', []);
linkAllowedByRules('https://localhost:3000', []);
});
test('* star', () => {
linkProtectedByRules('https://a.x.org', ['https://*.x.org']);
linkProtectedByRules('https://a.b.x.org', ['https://*.x.org']);
linkProtectedByRules('https://a.x.org', ['https://a.x.*']);
linkProtectedByRules('https://a.x.org', ['https://a.*.org']);
linkProtectedByRules('https://a.x.org', ['https://*.*.org']);
linkProtectedByRules('https://a.b.x.org', ['https://*.b.*.org']);
linkProtectedByRules('https://a.a.b.x.org', ['https://*.b.*.org']);
linkAllowedByRules('https://a.x.org', ['https://*.x.org']);
linkAllowedByRules('https://a.b.x.org', ['https://*.x.org']);
linkAllowedByRules('https://a.x.org', ['https://a.x.*']);
linkAllowedByRules('https://a.x.org', ['https://a.*.org']);
linkAllowedByRules('https://a.x.org', ['https://*.*.org']);
linkAllowedByRules('https://a.b.x.org', ['https://*.b.*.org']);
linkAllowedByRules('https://a.a.b.x.org', ['https://*.b.*.org']);
});
test('no scheme', () => {
linkProtectedByRules('https://a.x.org', ['a.x.org']);
linkProtectedByRules('https://a.x.org', ['*.x.org']);
linkProtectedByRules('https://a.b.x.org', ['*.x.org']);
linkProtectedByRules('https://x.org', ['*.x.org']);
linkAllowedByRules('https://a.x.org', ['a.x.org']);
linkAllowedByRules('https://a.x.org', ['*.x.org']);
linkAllowedByRules('https://a.b.x.org', ['*.x.org']);
linkAllowedByRules('https://x.org', ['*.x.org']);
});
test('sub paths', () => {
linkAllowedByRules('https://x.org/foo', ['https://x.org/foo']);
linkAllowedByRules('https://x.org/foo', ['x.org/foo']);
linkAllowedByRules('https://x.org/foo', ['*.org/foo']);
linkNotAllowedByRules('https://x.org/bar', ['https://x.org/foo']);
linkNotAllowedByRules('https://x.org/bar', ['x.org/foo']);
linkNotAllowedByRules('https://x.org/bar', ['*.org/foo']);
linkAllowedByRules('https://x.org/foo/bar', ['https://x.org/foo']);
linkNotAllowedByRules('https://x.org/foo2', ['https://x.org/foo']);
linkNotAllowedByRules('https://www.x.org/foo', ['https://x.org/foo']);
linkNotAllowedByRules('https://a.x.org/bar', ['https://*.x.org/foo']);
linkNotAllowedByRules('https://a.b.x.org/bar', ['https://*.x.org/foo']);
});
});
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册