@codingame/monaco-vscode-quickaccess-service-override 1.85.0-next.2 → 1.85.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/quickaccess.js +1 -0
- package/vscode/src/vs/workbench/contrib/url/browser/externalUriResolver.js +27 -0
- package/vscode/src/vs/workbench/contrib/url/browser/trustedDomains.js +200 -0
- package/vscode/src/vs/workbench/contrib/url/browser/trustedDomainsFileSystemProvider.js +136 -0
- package/vscode/src/vs/workbench/contrib/url/browser/trustedDomainsValidator.js +205 -0
- package/vscode/src/vs/workbench/contrib/url/browser/url.contribution.js +70 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codingame/monaco-vscode-quickaccess-service-override",
|
|
3
|
-
"version": "1.85.
|
|
3
|
+
"version": "1.85.1",
|
|
4
4
|
"keywords": [],
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "CodinGame",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"module": "index.js",
|
|
19
19
|
"types": "index.d.ts",
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"vscode": "npm:@codingame/monaco-vscode-api@1.85.
|
|
21
|
+
"vscode": "npm:@codingame/monaco-vscode-api@1.85.1",
|
|
22
22
|
"monaco-editor": "0.45.0"
|
|
23
23
|
}
|
|
24
24
|
}
|
package/quickaccess.js
CHANGED
|
@@ -13,6 +13,7 @@ import './vscode/src/vs/workbench/contrib/codeEditor/browser/quickaccess/gotoLin
|
|
|
13
13
|
import 'vscode/vscode/vs/workbench/contrib/codeEditor/browser/quickaccess/gotoSymbolQuickAccess';
|
|
14
14
|
import './vscode/src/vs/workbench/browser/actions/quickAccessActions.js';
|
|
15
15
|
import './vscode/src/vs/workbench/contrib/quickaccess/browser/quickAccess.contribution.js';
|
|
16
|
+
import './vscode/src/vs/workbench/contrib/url/browser/url.contribution.js';
|
|
16
17
|
import 'vscode/vscode/vs/workbench/browser/workbench.contribution';
|
|
17
18
|
|
|
18
19
|
let isKeybindingConfigurationVisible = () => {
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { __decorate, __param } from '../../../../../../../external/tslib/tslib.es6.js';
|
|
2
|
+
import { Disposable } from 'monaco-editor/esm/vs/base/common/lifecycle.js';
|
|
3
|
+
import { IOpenerService } from 'monaco-editor/esm/vs/platform/opener/common/opener.js';
|
|
4
|
+
import { IBrowserWorkbenchEnvironmentService } from 'vscode/vscode/vs/workbench/services/environment/browser/environmentService';
|
|
5
|
+
|
|
6
|
+
let ExternalUriResolverContribution = class ExternalUriResolverContribution extends Disposable {
|
|
7
|
+
constructor(_openerService, _workbenchEnvironmentService) {
|
|
8
|
+
super();
|
|
9
|
+
if (_workbenchEnvironmentService.options && _workbenchEnvironmentService.options.resolveExternalUri) {
|
|
10
|
+
this._register(_openerService.registerExternalUriResolver({
|
|
11
|
+
resolveExternalUri: async (resource) => {
|
|
12
|
+
return {
|
|
13
|
+
resolved: await _workbenchEnvironmentService.options.resolveExternalUri(resource),
|
|
14
|
+
dispose: () => {
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
}));
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
ExternalUriResolverContribution = ( __decorate([
|
|
23
|
+
( __param(0, IOpenerService)),
|
|
24
|
+
( __param(1, IBrowserWorkbenchEnvironmentService))
|
|
25
|
+
], ExternalUriResolverContribution));
|
|
26
|
+
|
|
27
|
+
export { ExternalUriResolverContribution };
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { URI } from 'monaco-editor/esm/vs/base/common/uri.js';
|
|
2
|
+
import { localizeWithPath } from 'monaco-editor/esm/vs/nls.js';
|
|
3
|
+
import { IProductService } from 'monaco-editor/esm/vs/platform/product/common/productService.js';
|
|
4
|
+
import { IStorageService } from 'monaco-editor/esm/vs/platform/storage/common/storage.js';
|
|
5
|
+
import { IEditorService } from 'vscode/vscode/vs/workbench/services/editor/common/editorService';
|
|
6
|
+
import { IAuthenticationService } from 'vscode/vscode/vs/workbench/services/authentication/common/authentication';
|
|
7
|
+
import { IFileService } from 'monaco-editor/esm/vs/platform/files/common/files.js';
|
|
8
|
+
import { ITextFileService } from 'vscode/vscode/vs/workbench/services/textfile/common/textfiles';
|
|
9
|
+
import { IWorkspaceContextService } from 'monaco-editor/esm/vs/platform/workspace/common/workspace.js';
|
|
10
|
+
import { IBrowserWorkbenchEnvironmentService } from 'vscode/vscode/vs/workbench/services/environment/browser/environmentService';
|
|
11
|
+
|
|
12
|
+
const TRUSTED_DOMAINS_URI = ( URI.parse('trustedDomains:/Trusted Domains'));
|
|
13
|
+
const TRUSTED_DOMAINS_STORAGE_KEY = 'http.linkProtectionTrustedDomains';
|
|
14
|
+
const TRUSTED_DOMAINS_CONTENT_STORAGE_KEY = 'http.linkProtectionTrustedDomainsContent';
|
|
15
|
+
const manageTrustedDomainSettingsCommand = {
|
|
16
|
+
id: 'workbench.action.manageTrustedDomain',
|
|
17
|
+
description: {
|
|
18
|
+
description: ( localizeWithPath(
|
|
19
|
+
'vs/workbench/contrib/url/browser/trustedDomains',
|
|
20
|
+
'trustedDomain.manageTrustedDomain',
|
|
21
|
+
'Manage Trusted Domains'
|
|
22
|
+
)),
|
|
23
|
+
args: []
|
|
24
|
+
},
|
|
25
|
+
handler: async (accessor) => {
|
|
26
|
+
const editorService = accessor.get(IEditorService);
|
|
27
|
+
editorService.openEditor({ resource: TRUSTED_DOMAINS_URI, languageId: 'jsonc', options: { pinned: true } });
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
async function configureOpenerTrustedDomainsHandler(trustedDomains, domainToConfigure, resource, quickInputService, storageService, editorService, telemetryService) {
|
|
32
|
+
const parsedDomainToConfigure = ( URI.parse(domainToConfigure));
|
|
33
|
+
const toplevelDomainSegements = parsedDomainToConfigure.authority.split('.');
|
|
34
|
+
const domainEnd = toplevelDomainSegements.slice(toplevelDomainSegements.length - 2).join('.');
|
|
35
|
+
const topLevelDomain = '*.' + domainEnd;
|
|
36
|
+
const options = [];
|
|
37
|
+
options.push({
|
|
38
|
+
type: 'item',
|
|
39
|
+
label: ( localizeWithPath(
|
|
40
|
+
'vs/workbench/contrib/url/browser/trustedDomains',
|
|
41
|
+
'trustedDomain.trustDomain',
|
|
42
|
+
'Trust {0}',
|
|
43
|
+
domainToConfigure
|
|
44
|
+
)),
|
|
45
|
+
id: 'trust',
|
|
46
|
+
toTrust: domainToConfigure,
|
|
47
|
+
picked: true
|
|
48
|
+
});
|
|
49
|
+
const isIP = toplevelDomainSegements.length === 4 &&
|
|
50
|
+
toplevelDomainSegements.every(segment => Number.isInteger(+segment) || Number.isInteger(+segment.split(':')[0]));
|
|
51
|
+
if (isIP) {
|
|
52
|
+
if (parsedDomainToConfigure.authority.includes(':')) {
|
|
53
|
+
const base = parsedDomainToConfigure.authority.split(':')[0];
|
|
54
|
+
options.push({
|
|
55
|
+
type: 'item',
|
|
56
|
+
label: ( localizeWithPath(
|
|
57
|
+
'vs/workbench/contrib/url/browser/trustedDomains',
|
|
58
|
+
'trustedDomain.trustAllPorts',
|
|
59
|
+
'Trust {0} on all ports',
|
|
60
|
+
base
|
|
61
|
+
)),
|
|
62
|
+
toTrust: base + ':*',
|
|
63
|
+
id: 'trust'
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
options.push({
|
|
69
|
+
type: 'item',
|
|
70
|
+
label: ( localizeWithPath(
|
|
71
|
+
'vs/workbench/contrib/url/browser/trustedDomains',
|
|
72
|
+
'trustedDomain.trustSubDomain',
|
|
73
|
+
'Trust {0} and all its subdomains',
|
|
74
|
+
domainEnd
|
|
75
|
+
)),
|
|
76
|
+
toTrust: topLevelDomain,
|
|
77
|
+
id: 'trust'
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
options.push({
|
|
81
|
+
type: 'item',
|
|
82
|
+
label: ( localizeWithPath(
|
|
83
|
+
'vs/workbench/contrib/url/browser/trustedDomains',
|
|
84
|
+
'trustedDomain.trustAllDomains',
|
|
85
|
+
'Trust all domains (disables link protection)'
|
|
86
|
+
)),
|
|
87
|
+
toTrust: '*',
|
|
88
|
+
id: 'trust'
|
|
89
|
+
});
|
|
90
|
+
options.push({
|
|
91
|
+
type: 'item',
|
|
92
|
+
label: ( localizeWithPath(
|
|
93
|
+
'vs/workbench/contrib/url/browser/trustedDomains',
|
|
94
|
+
'trustedDomain.manageTrustedDomains',
|
|
95
|
+
'Manage Trusted Domains'
|
|
96
|
+
)),
|
|
97
|
+
id: 'manage'
|
|
98
|
+
});
|
|
99
|
+
const pickedResult = await quickInputService.pick(options, { activeItem: options[0] });
|
|
100
|
+
if (pickedResult && pickedResult.id) {
|
|
101
|
+
switch (pickedResult.id) {
|
|
102
|
+
case 'manage':
|
|
103
|
+
await editorService.openEditor({
|
|
104
|
+
resource: TRUSTED_DOMAINS_URI.with({ fragment: ( resource.toString()) }),
|
|
105
|
+
languageId: 'jsonc',
|
|
106
|
+
options: { pinned: true }
|
|
107
|
+
});
|
|
108
|
+
return trustedDomains;
|
|
109
|
+
case 'trust': {
|
|
110
|
+
const itemToTrust = pickedResult.toTrust;
|
|
111
|
+
if (trustedDomains.indexOf(itemToTrust) === -1) {
|
|
112
|
+
storageService.remove(TRUSTED_DOMAINS_CONTENT_STORAGE_KEY, -1 );
|
|
113
|
+
storageService.store(TRUSTED_DOMAINS_STORAGE_KEY, JSON.stringify([...trustedDomains, itemToTrust]), -1 , 0 );
|
|
114
|
+
return [...trustedDomains, itemToTrust];
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return [];
|
|
120
|
+
}
|
|
121
|
+
function extractGitHubRemotesFromGitConfig(gitConfig) {
|
|
122
|
+
const domains = ( new Set());
|
|
123
|
+
let match;
|
|
124
|
+
const RemoteMatcher = /^\s*url\s*=\s*(?:git@|https:\/\/)github\.com(?::|\/)(\S*)\s*$/mg;
|
|
125
|
+
while (match = RemoteMatcher.exec(gitConfig)) {
|
|
126
|
+
const repo = match[1].replace(/\.git$/, '');
|
|
127
|
+
if (repo) {
|
|
128
|
+
domains.add(`https://github.com/${repo}/`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return [...domains];
|
|
132
|
+
}
|
|
133
|
+
async function getRemotes(fileService, textFileService, contextService) {
|
|
134
|
+
const workspaceUris = ( contextService.getWorkspace().folders.map(folder => folder.uri));
|
|
135
|
+
const domains = await Promise.race([
|
|
136
|
+
( new Promise(resolve => setTimeout(() => resolve([]), 2000))),
|
|
137
|
+
Promise.all(( workspaceUris.map(async (workspaceUri) => {
|
|
138
|
+
try {
|
|
139
|
+
const path = workspaceUri.path;
|
|
140
|
+
const uri = workspaceUri.with({ path: `${path !== '/' ? path : ''}/.git/config` });
|
|
141
|
+
const exists = await fileService.exists(uri);
|
|
142
|
+
if (!exists) {
|
|
143
|
+
return [];
|
|
144
|
+
}
|
|
145
|
+
const gitConfig = (await (textFileService.read(uri, { acceptTextOnly: true }).catch(() => ({ value: '' })))).value;
|
|
146
|
+
return extractGitHubRemotesFromGitConfig(gitConfig);
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
return [];
|
|
150
|
+
}
|
|
151
|
+
})))
|
|
152
|
+
]);
|
|
153
|
+
const set = domains.reduce((set, list) => list.reduce((set, item) => set.add(item), set), ( new Set()));
|
|
154
|
+
return [...set];
|
|
155
|
+
}
|
|
156
|
+
async function readTrustedDomains(accessor) {
|
|
157
|
+
const { defaultTrustedDomains, trustedDomains } = readStaticTrustedDomains(accessor);
|
|
158
|
+
const [workspaceDomains, userDomains] = await Promise.all([readWorkspaceTrustedDomains(accessor), readAuthenticationTrustedDomains(accessor)]);
|
|
159
|
+
return {
|
|
160
|
+
workspaceDomains,
|
|
161
|
+
userDomains,
|
|
162
|
+
defaultTrustedDomains,
|
|
163
|
+
trustedDomains,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
async function readWorkspaceTrustedDomains(accessor) {
|
|
167
|
+
const fileService = accessor.get(IFileService);
|
|
168
|
+
const textFileService = accessor.get(ITextFileService);
|
|
169
|
+
const workspaceContextService = accessor.get(IWorkspaceContextService);
|
|
170
|
+
return getRemotes(fileService, textFileService, workspaceContextService);
|
|
171
|
+
}
|
|
172
|
+
async function readAuthenticationTrustedDomains(accessor) {
|
|
173
|
+
const authenticationService = accessor.get(IAuthenticationService);
|
|
174
|
+
return authenticationService.isAuthenticationProviderRegistered('github') && ((await authenticationService.getSessions('github')) ?? []).length > 0
|
|
175
|
+
? [`https://github.com`]
|
|
176
|
+
: [];
|
|
177
|
+
}
|
|
178
|
+
function readStaticTrustedDomains(accessor) {
|
|
179
|
+
const storageService = accessor.get(IStorageService);
|
|
180
|
+
const productService = accessor.get(IProductService);
|
|
181
|
+
const environmentService = accessor.get(IBrowserWorkbenchEnvironmentService);
|
|
182
|
+
const defaultTrustedDomains = [
|
|
183
|
+
...(productService.linkProtectionTrustedDomains ?? []),
|
|
184
|
+
...(environmentService.options?.additionalTrustedDomains ?? [])
|
|
185
|
+
];
|
|
186
|
+
let trustedDomains = [];
|
|
187
|
+
try {
|
|
188
|
+
const trustedDomainsSrc = storageService.get(TRUSTED_DOMAINS_STORAGE_KEY, -1 );
|
|
189
|
+
if (trustedDomainsSrc) {
|
|
190
|
+
trustedDomains = JSON.parse(trustedDomainsSrc);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
catch (err) { }
|
|
194
|
+
return {
|
|
195
|
+
defaultTrustedDomains,
|
|
196
|
+
trustedDomains,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export { TRUSTED_DOMAINS_CONTENT_STORAGE_KEY, TRUSTED_DOMAINS_STORAGE_KEY, configureOpenerTrustedDomainsHandler, extractGitHubRemotesFromGitConfig, manageTrustedDomainSettingsCommand, readAuthenticationTrustedDomains, readStaticTrustedDomains, readTrustedDomains, readWorkspaceTrustedDomains };
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { __decorate, __param } from '../../../../../../../external/tslib/tslib.es6.js';
|
|
2
|
+
import { Event } from 'monaco-editor/esm/vs/base/common/event.js';
|
|
3
|
+
import { parse } from 'monaco-editor/esm/vs/base/common/json.js';
|
|
4
|
+
import { FileType, IFileService } from 'monaco-editor/esm/vs/platform/files/common/files.js';
|
|
5
|
+
import { IStorageService } from 'monaco-editor/esm/vs/platform/storage/common/storage.js';
|
|
6
|
+
import { VSBuffer } from 'monaco-editor/esm/vs/base/common/buffer.js';
|
|
7
|
+
import { TRUSTED_DOMAINS_CONTENT_STORAGE_KEY, readTrustedDomains, TRUSTED_DOMAINS_STORAGE_KEY } from './trustedDomains.js';
|
|
8
|
+
import { assertIsDefined } from 'monaco-editor/esm/vs/base/common/types.js';
|
|
9
|
+
import { IInstantiationService } from 'monaco-editor/esm/vs/platform/instantiation/common/instantiation.js';
|
|
10
|
+
|
|
11
|
+
const TRUSTED_DOMAINS_SCHEMA = 'trustedDomains';
|
|
12
|
+
const TRUSTED_DOMAINS_STAT = {
|
|
13
|
+
type: FileType.File,
|
|
14
|
+
ctime: Date.now(),
|
|
15
|
+
mtime: Date.now(),
|
|
16
|
+
size: 0
|
|
17
|
+
};
|
|
18
|
+
const CONFIG_HELP_TEXT_PRE = `// Links matching one or more entries in the list below can be opened without link protection.
|
|
19
|
+
// The following examples show what entries can look like:
|
|
20
|
+
// - "https://microsoft.com": Matches this specific domain using https
|
|
21
|
+
// - "https://microsoft.com:8080": Matches this specific domain on this port using https
|
|
22
|
+
// - "https://microsoft.com:*": Matches this specific domain on any port using https
|
|
23
|
+
// - "https://microsoft.com/foo": Matches https://microsoft.com/foo and https://microsoft.com/foo/bar,
|
|
24
|
+
// but not https://microsoft.com/foobar or https://microsoft.com/bar
|
|
25
|
+
// - "https://*.microsoft.com": Match all domains ending in "microsoft.com" using https
|
|
26
|
+
// - "microsoft.com": Match this specific domain using either http or https
|
|
27
|
+
// - "*.microsoft.com": Match all domains ending in "microsoft.com" using either http or https
|
|
28
|
+
// - "http://192.168.0.1: Matches this specific IP using http
|
|
29
|
+
// - "http://192.168.0.*: Matches all IP's with this prefix using http
|
|
30
|
+
// - "*": Match all domains using either http or https
|
|
31
|
+
//
|
|
32
|
+
`;
|
|
33
|
+
const CONFIG_HELP_TEXT_AFTER = `//
|
|
34
|
+
// You can use the "Manage Trusted Domains" command to open this file.
|
|
35
|
+
// Save this file to apply the trusted domains rules.
|
|
36
|
+
`;
|
|
37
|
+
const CONFIG_PLACEHOLDER_TEXT = `[
|
|
38
|
+
// "https://microsoft.com"
|
|
39
|
+
]`;
|
|
40
|
+
function computeTrustedDomainContent(defaultTrustedDomains, trustedDomains, userTrustedDomains, workspaceTrustedDomains, configuring) {
|
|
41
|
+
let content = CONFIG_HELP_TEXT_PRE;
|
|
42
|
+
if (defaultTrustedDomains.length > 0) {
|
|
43
|
+
content += `// By default, VS Code trusts "localhost" as well as the following domains:\n`;
|
|
44
|
+
defaultTrustedDomains.forEach(d => {
|
|
45
|
+
content += `// - "${d}"\n`;
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
content += `// By default, VS Code trusts "localhost".\n`;
|
|
50
|
+
}
|
|
51
|
+
if (userTrustedDomains.length) {
|
|
52
|
+
content += `//\n// Additionally, the following domains are trusted based on your logged-in Accounts:\n`;
|
|
53
|
+
userTrustedDomains.forEach(d => {
|
|
54
|
+
content += `// - "${d}"\n`;
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
if (workspaceTrustedDomains.length) {
|
|
58
|
+
content += `//\n// Further, the following domains are trusted based on your workspace configuration:\n`;
|
|
59
|
+
workspaceTrustedDomains.forEach(d => {
|
|
60
|
+
content += `// - "${d}"\n`;
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
content += CONFIG_HELP_TEXT_AFTER;
|
|
64
|
+
content += configuring ? `\n// Currently configuring trust for ${configuring}\n` : '';
|
|
65
|
+
if (trustedDomains.length === 0) {
|
|
66
|
+
content += CONFIG_PLACEHOLDER_TEXT;
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
content += JSON.stringify(trustedDomains, null, 2);
|
|
70
|
+
}
|
|
71
|
+
return content;
|
|
72
|
+
}
|
|
73
|
+
let TrustedDomainsFileSystemProvider = class TrustedDomainsFileSystemProvider {
|
|
74
|
+
constructor(fileService, storageService, instantiationService) {
|
|
75
|
+
this.fileService = fileService;
|
|
76
|
+
this.storageService = storageService;
|
|
77
|
+
this.instantiationService = instantiationService;
|
|
78
|
+
this.capabilities = 2 ;
|
|
79
|
+
this.onDidChangeCapabilities = Event.None;
|
|
80
|
+
this.onDidChangeFile = Event.None;
|
|
81
|
+
this.fileService.registerProvider(TRUSTED_DOMAINS_SCHEMA, this);
|
|
82
|
+
}
|
|
83
|
+
stat(resource) {
|
|
84
|
+
return Promise.resolve(TRUSTED_DOMAINS_STAT);
|
|
85
|
+
}
|
|
86
|
+
async readFile(resource) {
|
|
87
|
+
let trustedDomainsContent = this.storageService.get(TRUSTED_DOMAINS_CONTENT_STORAGE_KEY, -1 );
|
|
88
|
+
const configuring = resource.fragment;
|
|
89
|
+
const { defaultTrustedDomains, trustedDomains, userDomains, workspaceDomains } = await this.instantiationService.invokeFunction(readTrustedDomains);
|
|
90
|
+
if (!trustedDomainsContent ||
|
|
91
|
+
trustedDomainsContent.indexOf(CONFIG_HELP_TEXT_PRE) === -1 ||
|
|
92
|
+
trustedDomainsContent.indexOf(CONFIG_HELP_TEXT_AFTER) === -1 ||
|
|
93
|
+
trustedDomainsContent.indexOf(configuring ?? '') === -1 ||
|
|
94
|
+
( [...defaultTrustedDomains, ...trustedDomains, ...userDomains, ...workspaceDomains].some(d => !assertIsDefined(trustedDomainsContent).includes(d)))) {
|
|
95
|
+
trustedDomainsContent = computeTrustedDomainContent(defaultTrustedDomains, trustedDomains, userDomains, workspaceDomains, configuring);
|
|
96
|
+
}
|
|
97
|
+
const buffer = VSBuffer.fromString(trustedDomainsContent).buffer;
|
|
98
|
+
return buffer;
|
|
99
|
+
}
|
|
100
|
+
writeFile(resource, content, opts) {
|
|
101
|
+
try {
|
|
102
|
+
const trustedDomainsContent = ( VSBuffer.wrap(content).toString());
|
|
103
|
+
const trustedDomains = parse(trustedDomainsContent);
|
|
104
|
+
this.storageService.store(TRUSTED_DOMAINS_CONTENT_STORAGE_KEY, trustedDomainsContent, -1 , 0 );
|
|
105
|
+
this.storageService.store(TRUSTED_DOMAINS_STORAGE_KEY, JSON.stringify(trustedDomains) || '', -1 , 0 );
|
|
106
|
+
}
|
|
107
|
+
catch (err) { }
|
|
108
|
+
return Promise.resolve();
|
|
109
|
+
}
|
|
110
|
+
watch(resource, opts) {
|
|
111
|
+
return {
|
|
112
|
+
dispose() {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
mkdir(resource) {
|
|
118
|
+
return Promise.resolve(undefined);
|
|
119
|
+
}
|
|
120
|
+
readdir(resource) {
|
|
121
|
+
return Promise.resolve(undefined);
|
|
122
|
+
}
|
|
123
|
+
delete(resource, opts) {
|
|
124
|
+
return Promise.resolve(undefined);
|
|
125
|
+
}
|
|
126
|
+
rename(from, to, opts) {
|
|
127
|
+
return Promise.resolve(undefined);
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
TrustedDomainsFileSystemProvider = ( __decorate([
|
|
131
|
+
( __param(0, IFileService)),
|
|
132
|
+
( __param(1, IStorageService)),
|
|
133
|
+
( __param(2, IInstantiationService))
|
|
134
|
+
], TrustedDomainsFileSystemProvider));
|
|
135
|
+
|
|
136
|
+
export { TrustedDomainsFileSystemProvider };
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { __decorate, __param } from '../../../../../../../external/tslib/tslib.es6.js';
|
|
2
|
+
import { WindowIdleValue } from 'monaco-editor/esm/vs/base/browser/dom.js';
|
|
3
|
+
import { mainWindow } from 'monaco-editor/esm/vs/base/browser/window.js';
|
|
4
|
+
import { matchesScheme, Schemas } from 'monaco-editor/esm/vs/base/common/network.js';
|
|
5
|
+
import Severity from 'monaco-editor/esm/vs/base/common/severity.js';
|
|
6
|
+
import { URI } from 'monaco-editor/esm/vs/base/common/uri.js';
|
|
7
|
+
import { localizeWithPath } from 'monaco-editor/esm/vs/nls.js';
|
|
8
|
+
import { IClipboardService } from 'monaco-editor/esm/vs/platform/clipboard/common/clipboardService.js';
|
|
9
|
+
import { IConfigurationService } from 'monaco-editor/esm/vs/platform/configuration/common/configuration.js';
|
|
10
|
+
import '../../../../../../../override/vs/platform/dialogs/common/dialogs.js';
|
|
11
|
+
import { IInstantiationService } from 'monaco-editor/esm/vs/platform/instantiation/common/instantiation.js';
|
|
12
|
+
import { IOpenerService } from 'monaco-editor/esm/vs/platform/opener/common/opener.js';
|
|
13
|
+
import { IProductService } from 'monaco-editor/esm/vs/platform/product/common/productService.js';
|
|
14
|
+
import { IQuickInputService } from 'monaco-editor/esm/vs/platform/quickinput/common/quickInput.js';
|
|
15
|
+
import { IStorageService } from 'monaco-editor/esm/vs/platform/storage/common/storage.js';
|
|
16
|
+
import { ITelemetryService } from 'monaco-editor/esm/vs/platform/telemetry/common/telemetry.js';
|
|
17
|
+
import { IWorkspaceContextService } from 'monaco-editor/esm/vs/platform/workspace/common/workspace.js';
|
|
18
|
+
import { IWorkspaceTrustManagementService } from 'monaco-editor/esm/vs/platform/workspace/common/workspaceTrust.js';
|
|
19
|
+
import { readAuthenticationTrustedDomains, readWorkspaceTrustedDomains, readStaticTrustedDomains, configureOpenerTrustedDomainsHandler } from './trustedDomains.js';
|
|
20
|
+
import { testUrlMatchesGlob } from 'vscode/vscode/vs/workbench/contrib/url/common/urlGlob';
|
|
21
|
+
import { IAuthenticationService } from 'vscode/vscode/vs/workbench/services/authentication/common/authentication';
|
|
22
|
+
import { IEditorService } from 'vscode/vscode/vs/workbench/services/editor/common/editorService';
|
|
23
|
+
import { IDialogService } from 'vscode/vscode/vs/platform/dialogs/common/dialogs';
|
|
24
|
+
|
|
25
|
+
let OpenerValidatorContributions = class OpenerValidatorContributions {
|
|
26
|
+
constructor(_openerService, _storageService, _dialogService, _productService, _quickInputService, _editorService, _clipboardService, _telemetryService, _instantiationService, _authenticationService, _workspaceContextService, _configurationService, _workspaceTrustService) {
|
|
27
|
+
this._openerService = _openerService;
|
|
28
|
+
this._storageService = _storageService;
|
|
29
|
+
this._dialogService = _dialogService;
|
|
30
|
+
this._productService = _productService;
|
|
31
|
+
this._quickInputService = _quickInputService;
|
|
32
|
+
this._editorService = _editorService;
|
|
33
|
+
this._clipboardService = _clipboardService;
|
|
34
|
+
this._telemetryService = _telemetryService;
|
|
35
|
+
this._instantiationService = _instantiationService;
|
|
36
|
+
this._authenticationService = _authenticationService;
|
|
37
|
+
this._workspaceContextService = _workspaceContextService;
|
|
38
|
+
this._configurationService = _configurationService;
|
|
39
|
+
this._workspaceTrustService = _workspaceTrustService;
|
|
40
|
+
this._openerService.registerValidator({ shouldOpen: (uri, options) => this.validateLink(uri, options) });
|
|
41
|
+
this._readAuthenticationTrustedDomainsResult = ( new WindowIdleValue(
|
|
42
|
+
mainWindow,
|
|
43
|
+
() => this._instantiationService.invokeFunction(readAuthenticationTrustedDomains)
|
|
44
|
+
));
|
|
45
|
+
this._authenticationService.onDidRegisterAuthenticationProvider(() => {
|
|
46
|
+
this._readAuthenticationTrustedDomainsResult?.dispose();
|
|
47
|
+
this._readAuthenticationTrustedDomainsResult = ( new WindowIdleValue(
|
|
48
|
+
mainWindow,
|
|
49
|
+
() => this._instantiationService.invokeFunction(readAuthenticationTrustedDomains)
|
|
50
|
+
));
|
|
51
|
+
});
|
|
52
|
+
this._readWorkspaceTrustedDomainsResult = ( new WindowIdleValue(
|
|
53
|
+
mainWindow,
|
|
54
|
+
() => this._instantiationService.invokeFunction(readWorkspaceTrustedDomains)
|
|
55
|
+
));
|
|
56
|
+
this._workspaceContextService.onDidChangeWorkspaceFolders(() => {
|
|
57
|
+
this._readWorkspaceTrustedDomainsResult?.dispose();
|
|
58
|
+
this._readWorkspaceTrustedDomainsResult = ( new WindowIdleValue(
|
|
59
|
+
mainWindow,
|
|
60
|
+
() => this._instantiationService.invokeFunction(readWorkspaceTrustedDomains)
|
|
61
|
+
));
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
async validateLink(resource, openOptions) {
|
|
65
|
+
if (!matchesScheme(resource, Schemas.http) && !matchesScheme(resource, Schemas.https)) {
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
if (openOptions?.fromWorkspace && this._workspaceTrustService.isWorkspaceTrusted() && !this._configurationService.getValue('workbench.trustedDomains.promptInTrustedWorkspace')) {
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
const originalResource = resource;
|
|
72
|
+
let resourceUri;
|
|
73
|
+
if (typeof resource === 'string') {
|
|
74
|
+
resourceUri = ( URI.parse(resource));
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
resourceUri = resource;
|
|
78
|
+
}
|
|
79
|
+
const { scheme, authority, path, query, fragment } = resourceUri;
|
|
80
|
+
const domainToOpen = `${scheme}://${authority}`;
|
|
81
|
+
const [workspaceDomains, userDomains] = await Promise.all([this._readWorkspaceTrustedDomainsResult.value, this._readAuthenticationTrustedDomainsResult.value]);
|
|
82
|
+
const { defaultTrustedDomains, trustedDomains, } = this._instantiationService.invokeFunction(readStaticTrustedDomains);
|
|
83
|
+
const allTrustedDomains = [...defaultTrustedDomains, ...trustedDomains, ...userDomains, ...workspaceDomains];
|
|
84
|
+
if (isURLDomainTrusted(resourceUri, allTrustedDomains)) {
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
let formattedLink = `${scheme}://${authority}${path}`;
|
|
89
|
+
const linkTail = `${query ? '?' + query : ''}${fragment ? '#' + fragment : ''}`;
|
|
90
|
+
const remainingLength = Math.max(0, 60 - formattedLink.length);
|
|
91
|
+
const linkTailLengthToKeep = Math.min(Math.max(5, remainingLength), linkTail.length);
|
|
92
|
+
if (linkTailLengthToKeep === linkTail.length) {
|
|
93
|
+
formattedLink += linkTail;
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
formattedLink += linkTail.charAt(0) + '...' + linkTail.substring(linkTail.length - linkTailLengthToKeep + 1);
|
|
97
|
+
}
|
|
98
|
+
const { result } = await this._dialogService.prompt({
|
|
99
|
+
type: Severity.Info,
|
|
100
|
+
message: ( localizeWithPath(
|
|
101
|
+
'vs/workbench/contrib/url/browser/trustedDomainsValidator',
|
|
102
|
+
'openExternalLinkAt',
|
|
103
|
+
'Do you want {0} to open the external website?',
|
|
104
|
+
this._productService.nameShort
|
|
105
|
+
)),
|
|
106
|
+
detail: typeof originalResource === 'string' ? originalResource : formattedLink,
|
|
107
|
+
buttons: [
|
|
108
|
+
{
|
|
109
|
+
label: ( localizeWithPath(
|
|
110
|
+
'vs/workbench/contrib/url/browser/trustedDomainsValidator',
|
|
111
|
+
{ key: 'open', comment: ['&& denotes a mnemonic'] },
|
|
112
|
+
'&&Open'
|
|
113
|
+
)),
|
|
114
|
+
run: () => true
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
label: ( localizeWithPath(
|
|
118
|
+
'vs/workbench/contrib/url/browser/trustedDomainsValidator',
|
|
119
|
+
{ key: 'copy', comment: ['&& denotes a mnemonic'] },
|
|
120
|
+
'&&Copy'
|
|
121
|
+
)),
|
|
122
|
+
run: () => {
|
|
123
|
+
this._clipboardService.writeText(typeof originalResource === 'string' ? originalResource : ( resourceUri.toString(true)));
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
label: ( localizeWithPath(
|
|
129
|
+
'vs/workbench/contrib/url/browser/trustedDomainsValidator',
|
|
130
|
+
{ key: 'configureTrustedDomains', comment: ['&& denotes a mnemonic'] },
|
|
131
|
+
'Configure &&Trusted Domains'
|
|
132
|
+
)),
|
|
133
|
+
run: async () => {
|
|
134
|
+
const pickedDomains = await configureOpenerTrustedDomainsHandler(trustedDomains, domainToOpen, resourceUri, this._quickInputService, this._storageService, this._editorService);
|
|
135
|
+
if (pickedDomains.indexOf('*') !== -1) {
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
if (isURLDomainTrusted(resourceUri, pickedDomains)) {
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
],
|
|
145
|
+
cancelButton: {
|
|
146
|
+
run: () => false
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
return result;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
OpenerValidatorContributions = ( __decorate([
|
|
154
|
+
( __param(0, IOpenerService)),
|
|
155
|
+
( __param(1, IStorageService)),
|
|
156
|
+
( __param(2, IDialogService)),
|
|
157
|
+
( __param(3, IProductService)),
|
|
158
|
+
( __param(4, IQuickInputService)),
|
|
159
|
+
( __param(5, IEditorService)),
|
|
160
|
+
( __param(6, IClipboardService)),
|
|
161
|
+
( __param(7, ITelemetryService)),
|
|
162
|
+
( __param(8, IInstantiationService)),
|
|
163
|
+
( __param(9, IAuthenticationService)),
|
|
164
|
+
( __param(10, IWorkspaceContextService)),
|
|
165
|
+
( __param(11, IConfigurationService)),
|
|
166
|
+
( __param(12, IWorkspaceTrustManagementService))
|
|
167
|
+
], OpenerValidatorContributions));
|
|
168
|
+
const rLocalhost = /^localhost(:\d+)?$/i;
|
|
169
|
+
const r127 = /^127.0.0.1(:\d+)?$/;
|
|
170
|
+
function isLocalhostAuthority(authority) {
|
|
171
|
+
return rLocalhost.test(authority) || r127.test(authority);
|
|
172
|
+
}
|
|
173
|
+
function normalizeURL(url) {
|
|
174
|
+
const caseInsensitiveAuthorities = ['github.com'];
|
|
175
|
+
try {
|
|
176
|
+
const parsed = typeof url === 'string' ? ( URI.parse(url, true)) : url;
|
|
177
|
+
if (caseInsensitiveAuthorities.includes(parsed.authority)) {
|
|
178
|
+
return ( parsed.with({ path: parsed.path.toLowerCase() }).toString(true));
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
return ( parsed.toString(true));
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
catch {
|
|
185
|
+
return ( url.toString());
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
function isURLDomainTrusted(url, trustedDomains) {
|
|
189
|
+
url = ( URI.parse(normalizeURL(url)));
|
|
190
|
+
trustedDomains = ( trustedDomains.map(normalizeURL));
|
|
191
|
+
if (isLocalhostAuthority(url.authority)) {
|
|
192
|
+
return true;
|
|
193
|
+
}
|
|
194
|
+
for (let i = 0; i < trustedDomains.length; i++) {
|
|
195
|
+
if (trustedDomains[i] === '*') {
|
|
196
|
+
return true;
|
|
197
|
+
}
|
|
198
|
+
if (testUrlMatchesGlob(url, trustedDomains[i])) {
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export { OpenerValidatorContributions, isURLDomainTrusted };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { URI } from 'monaco-editor/esm/vs/base/common/uri.js';
|
|
2
|
+
import { localizeWithPath } from 'monaco-editor/esm/vs/nls.js';
|
|
3
|
+
import { registerAction2, MenuRegistry, MenuId, Action2 } from 'monaco-editor/esm/vs/platform/actions/common/actions.js';
|
|
4
|
+
import { CommandsRegistry } from 'monaco-editor/esm/vs/platform/commands/common/commands.js';
|
|
5
|
+
import { IQuickInputService } from 'monaco-editor/esm/vs/platform/quickinput/common/quickInput.js';
|
|
6
|
+
import { Registry } from 'monaco-editor/esm/vs/platform/registry/common/platform.js';
|
|
7
|
+
import { IURLService } from 'vscode/vscode/vs/platform/url/common/url';
|
|
8
|
+
import { Extensions } from 'vscode/vscode/vs/workbench/common/contributions';
|
|
9
|
+
import { ExternalUriResolverContribution } from './externalUriResolver.js';
|
|
10
|
+
import { manageTrustedDomainSettingsCommand } from './trustedDomains.js';
|
|
11
|
+
import { TrustedDomainsFileSystemProvider } from './trustedDomainsFileSystemProvider.js';
|
|
12
|
+
import { OpenerValidatorContributions } from './trustedDomainsValidator.js';
|
|
13
|
+
import { Categories } from 'monaco-editor/esm/vs/platform/action/common/actionCommonCategories.js';
|
|
14
|
+
import { Extensions as Extensions$1 } from 'monaco-editor/esm/vs/platform/configuration/common/configurationRegistry.js';
|
|
15
|
+
import { workbenchConfigurationNodeBase } from 'vscode/vscode/vs/workbench/common/configuration';
|
|
16
|
+
|
|
17
|
+
class OpenUrlAction extends Action2 {
|
|
18
|
+
constructor() {
|
|
19
|
+
super({
|
|
20
|
+
id: 'workbench.action.url.openUrl',
|
|
21
|
+
title: { value: ( localizeWithPath('vs/workbench/contrib/url/browser/url.contribution', 'openUrl', "Open URL")), original: 'Open URL' },
|
|
22
|
+
category: Categories.Developer,
|
|
23
|
+
f1: true
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
async run(accessor) {
|
|
27
|
+
const quickInputService = accessor.get(IQuickInputService);
|
|
28
|
+
const urlService = accessor.get(IURLService);
|
|
29
|
+
return quickInputService.input({ prompt: ( localizeWithPath(
|
|
30
|
+
'vs/workbench/contrib/url/browser/url.contribution',
|
|
31
|
+
'urlToOpen',
|
|
32
|
+
"URL to open"
|
|
33
|
+
)) }).then(input => {
|
|
34
|
+
if (input) {
|
|
35
|
+
const uri = ( URI.parse(input));
|
|
36
|
+
urlService.open(uri, { originalUrl: input });
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
registerAction2(OpenUrlAction);
|
|
42
|
+
CommandsRegistry.registerCommand(manageTrustedDomainSettingsCommand);
|
|
43
|
+
MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
|
|
44
|
+
command: {
|
|
45
|
+
id: manageTrustedDomainSettingsCommand.id,
|
|
46
|
+
title: {
|
|
47
|
+
value: manageTrustedDomainSettingsCommand.description.description,
|
|
48
|
+
original: 'Manage Trusted Domains'
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
( Registry.as(Extensions.Workbench)).registerWorkbenchContribution(OpenerValidatorContributions, 3 );
|
|
53
|
+
( Registry.as(Extensions.Workbench)).registerWorkbenchContribution(TrustedDomainsFileSystemProvider, 2 );
|
|
54
|
+
( Registry.as(Extensions.Workbench)).registerWorkbenchContribution(ExternalUriResolverContribution, 2 );
|
|
55
|
+
const configurationRegistry = ( Registry.as(Extensions$1.Configuration));
|
|
56
|
+
configurationRegistry.registerConfiguration({
|
|
57
|
+
...workbenchConfigurationNodeBase,
|
|
58
|
+
properties: {
|
|
59
|
+
'workbench.trustedDomains.promptInTrustedWorkspace': {
|
|
60
|
+
scope: 1 ,
|
|
61
|
+
type: 'boolean',
|
|
62
|
+
default: false,
|
|
63
|
+
description: ( localizeWithPath(
|
|
64
|
+
'vs/workbench/contrib/url/browser/url.contribution',
|
|
65
|
+
'workbench.trustedDomains.promptInTrustedWorkspace',
|
|
66
|
+
"When enabled, trusted domain prompts will appear when opening links in trusted workspaces."
|
|
67
|
+
))
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
});
|