Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xxadev
vscode
提交
40bc003e
V
vscode
项目概览
xxadev
/
vscode
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
V
vscode
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
40bc003e
编写于
9月 11, 2019
作者:
P
Pine Wu
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Fix #80595
上级
1963239c
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
373 addition
and
236 deletion
+373
-236
src/vs/nls.d.ts
src/vs/nls.d.ts
+8
-2
src/vs/workbench/contrib/url/common/trustedDomains.ts
src/vs/workbench/contrib/url/common/trustedDomains.ts
+193
-0
src/vs/workbench/contrib/url/common/trustedDomainsValidator.ts
...s/workbench/contrib/url/common/trustedDomainsValidator.ts
+155
-0
src/vs/workbench/contrib/url/common/url.contribution.ts
src/vs/workbench/contrib/url/common/url.contribution.ts
+16
-233
src/vs/workbench/test/contrib/linkProtection.test.ts
src/vs/workbench/test/contrib/linkProtection.test.ts
+1
-1
未找到文件。
src/vs/nls.d.ts
浏览文件 @
40bc003e
...
...
@@ -9,11 +9,17 @@ export interface ILocalizeInfo {
}
/**
* Localize a message. `message` can contain `{n}` notation where it is replaced by the nth value in `...args`.
* Localize a message.
*
* `message` can contain `{n}` notation where it is replaced by the nth value in `...args`
* For example, `localize('hello {0}', name)`
*/
export
declare
function
localize
(
info
:
ILocalizeInfo
,
message
:
string
,
...
args
:
(
string
|
number
|
boolean
|
undefined
|
null
)[]):
string
;
/**
* Localize a message. `message` can contain `{n}` notation where it is replaced by the nth value in `...args`.
* Localize a message.
*
* `message` can contain `{n}` notation where it is replaced by the nth value in `...args`
* For example, `localize('hello {0}', name)`
*/
export
declare
function
localize
(
key
:
string
,
message
:
string
,
...
args
:
(
string
|
number
|
boolean
|
undefined
|
null
)[]):
string
;
src/vs/workbench/contrib/url/common/trustedDomains.ts
0 → 100644
浏览文件 @
40bc003e
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
{
localize
}
from
'
vs/nls
'
;
import
{
ServicesAccessor
}
from
'
vs/platform/instantiation/common/instantiation
'
;
import
{
IQuickInputService
,
IQuickPickItem
}
from
'
vs/platform/quickinput/common/quickInput
'
;
import
{
IStorageService
,
StorageScope
}
from
'
vs/platform/storage/common/storage
'
;
import
{
IProductService
}
from
'
vs/platform/product/common/product
'
;
export
const
enum
ConfigureTrustedDomainActionType
{
ToggleTrustAll
=
'
toggleTrustAll
'
,
Add
=
'
add
'
,
Configure
=
'
configure
'
,
Reset
=
'
reset
'
}
export
const
configureTrustedDomainSettingsCommand
=
{
id
:
'
workbench.action.configureTrustedDomain
'
,
description
:
{
description
:
localize
(
'
configureTrustedDomain
'
,
'
Configure Trusted Domains for Link Protection
'
),
args
:
[]
},
handler
:
async
(
accessor
:
ServicesAccessor
)
=>
{
const
quickInputService
=
accessor
.
get
(
IQuickInputService
);
const
storageService
=
accessor
.
get
(
IStorageService
);
const
productService
=
accessor
.
get
(
IProductService
);
let
trustedDomains
:
string
[]
=
productService
.
linkProtectionTrustedDomains
?
[...
productService
.
linkProtectionTrustedDomains
]
:
[];
try
{
const
trustedDomainsSrc
=
storageService
.
get
(
'
http.linkProtectionTrustedDomains
'
,
StorageScope
.
GLOBAL
);
if
(
trustedDomainsSrc
)
{
trustedDomains
=
JSON
.
parse
(
trustedDomainsSrc
);
}
}
catch
(
err
)
{
}
const
trustOrUntrustAllLabel
=
trustedDomains
.
indexOf
(
'
*
'
)
===
-
1
?
localize
(
'
trustedDomain.trustAll
'
,
'
Disable Link Protection
'
)
:
localize
(
'
trustedDomain.untrustAll
'
,
'
Enable Link Protection
'
);
const
trustOrUntrustAll
:
IQuickPickItem
=
{
id
:
ConfigureTrustedDomainActionType
.
ToggleTrustAll
,
label
:
trustOrUntrustAllLabel
};
const
result
=
await
quickInputService
.
pick
(
[
trustOrUntrustAll
,
{
id
:
ConfigureTrustedDomainActionType
.
Add
,
label
:
localize
(
'
trustedDomain.add
'
,
'
Add Trusted Domain
'
)
},
{
id
:
ConfigureTrustedDomainActionType
.
Configure
,
label
:
localize
(
'
trustedDomain.edit
'
,
'
View and configure Trusted Domains
'
)
},
{
id
:
ConfigureTrustedDomainActionType
.
Reset
,
label
:
localize
(
'
trustedDomain.reset
'
,
'
Reset Trusted Domains
'
)
}
],
{}
);
if
(
result
)
{
switch
(
result
.
id
)
{
case
ConfigureTrustedDomainActionType
.
ToggleTrustAll
:
toggleAll
(
trustedDomains
,
storageService
);
break
;
case
ConfigureTrustedDomainActionType
.
Add
:
addDomain
(
trustedDomains
,
storageService
,
quickInputService
);
break
;
case
ConfigureTrustedDomainActionType
.
Configure
:
configureDomains
(
trustedDomains
,
storageService
,
quickInputService
);
break
;
case
ConfigureTrustedDomainActionType
.
Reset
:
resetDomains
(
storageService
,
productService
);
break
;
}
}
}
};
function
toggleAll
(
trustedDomains
:
string
[],
storageService
:
IStorageService
)
{
if
(
trustedDomains
.
indexOf
(
'
*
'
)
===
-
1
)
{
storageService
.
store
(
'
http.linkProtectionTrustedDomains
'
,
JSON
.
stringify
(
trustedDomains
.
concat
([
'
*
'
])),
StorageScope
.
GLOBAL
);
}
else
{
storageService
.
store
(
'
http.linkProtectionTrustedDomains
'
,
JSON
.
stringify
(
trustedDomains
.
filter
(
x
=>
x
!==
'
*
'
)),
StorageScope
.
GLOBAL
);
}
}
function
addDomain
(
trustedDomains
:
string
[],
storageService
:
IStorageService
,
quickInputService
:
IQuickInputService
)
{
quickInputService
.
input
({
placeHolder
:
'
Domain to trust
'
,
validateInput
:
i
=>
{
if
(
!
i
.
match
(
/^https
?
:
\/\/
/
))
{
return
Promise
.
resolve
(
undefined
);
}
return
Promise
.
resolve
(
i
);
}
})
.
then
(
result
=>
{
console
.
log
(
result
);
if
(
result
)
{
storageService
.
store
(
'
http.linkProtectionTrustedDomains
'
,
JSON
.
stringify
(
trustedDomains
.
concat
([
result
])),
StorageScope
.
GLOBAL
);
}
});
}
function
configureDomains
(
trustedDomains
:
string
[],
storageService
:
IStorageService
,
quickInputService
:
IQuickInputService
)
{
const
domainQuickPickItems
:
IQuickPickItem
[]
=
trustedDomains
.
filter
(
d
=>
d
!==
'
*
'
)
.
map
(
d
=>
{
return
{
type
:
'
item
'
,
label
:
d
,
id
:
d
,
picked
:
true
};
});
quickInputService
.
pick
(
domainQuickPickItems
,
{
canPickMany
:
true
}).
then
(
result
=>
{
const
pickedDomains
:
string
[]
=
result
.
map
(
r
=>
r
.
id
!
);
storageService
.
store
(
'
http.linkProtectionTrustedDomains
'
,
JSON
.
stringify
(
pickedDomains
),
StorageScope
.
GLOBAL
);
});
}
function
resetDomains
(
storageService
:
IStorageService
,
productService
:
IProductService
)
{
if
(
productService
.
linkProtectionTrustedDomains
)
{
storageService
.
store
(
'
http.linkProtectionTrustedDomains
'
,
JSON
.
stringify
(
productService
.
linkProtectionTrustedDomains
),
StorageScope
.
GLOBAL
);
}
else
{
storageService
.
store
(
'
http.linkProtectionTrustedDomains
'
,
JSON
.
stringify
([]),
StorageScope
.
GLOBAL
);
}
}
export
async
function
configureOpenerTrustedDomainsHandler
(
trustedDomains
:
string
[],
domainToConfigure
:
string
,
quickInputService
:
IQuickInputService
,
storageService
:
IStorageService
)
{
const
openAllLinksItem
:
IQuickPickItem
=
{
type
:
'
item
'
,
label
:
localize
(
'
trustedDomain.trustAllAndOpenLink
'
,
'
Disable Link Protection and open link
'
),
id
:
'
*
'
,
picked
:
trustedDomains
.
indexOf
(
'
*
'
)
!==
-
1
};
const
trustDomainItem
:
IQuickPickItem
=
{
type
:
'
item
'
,
label
:
localize
(
'
trustedDomain.trustDomainAndOpenLink
'
,
'
Trust {0} and open link
'
,
domainToConfigure
),
id
:
domainToConfigure
,
picked
:
true
};
const
pickedResult
=
await
quickInputService
.
pick
([
openAllLinksItem
,
trustDomainItem
],
{
activeItem
:
trustDomainItem
});
if
(
pickedResult
)
{
if
(
pickedResult
.
id
&&
trustedDomains
.
indexOf
(
pickedResult
.
id
)
===
-
1
)
{
storageService
.
store
(
'
http.linkProtectionTrustedDomains
'
,
JSON
.
stringify
([...
trustedDomains
,
pickedResult
.
id
]),
StorageScope
.
GLOBAL
);
return
[...
trustedDomains
,
pickedResult
.
id
];
}
}
return
[];
}
src/vs/workbench/contrib/url/common/trustedDomainsValidator.ts
0 → 100644
浏览文件 @
40bc003e
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
{
Schemas
}
from
'
vs/base/common/network
'
;
import
Severity
from
'
vs/base/common/severity
'
;
import
{
equalsIgnoreCase
}
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
'
;
import
{
IOpenerService
}
from
'
vs/platform/opener/common/opener
'
;
import
{
IProductService
}
from
'
vs/platform/product/common/product
'
;
import
{
IQuickInputService
}
from
'
vs/platform/quickinput/common/quickInput
'
;
import
{
IStorageService
,
StorageScope
}
from
'
vs/platform/storage/common/storage
'
;
import
{
IWorkbenchContribution
}
from
'
vs/workbench/common/contributions
'
;
import
{
configureOpenerTrustedDomainsHandler
}
from
'
vs/workbench/contrib/url/common/trustedDomains
'
;
export
class
OpenerValidatorContributions
implements
IWorkbenchContribution
{
constructor
(
@
IOpenerService
private
readonly
_openerService
:
IOpenerService
,
@
IStorageService
private
readonly
_storageService
:
IStorageService
,
@
IDialogService
private
readonly
_dialogService
:
IDialogService
,
@
IProductService
private
readonly
_productService
:
IProductService
,
@
IQuickInputService
private
readonly
_quickInputService
:
IQuickInputService
)
{
this
.
_openerService
.
registerValidator
({
shouldOpen
:
r
=>
this
.
validateLink
(
r
)
});
}
async
validateLink
(
resource
:
URI
):
Promise
<
boolean
>
{
const
{
scheme
,
authority
}
=
resource
;
if
(
!
equalsIgnoreCase
(
scheme
,
Schemas
.
http
)
&&
!
equalsIgnoreCase
(
scheme
,
Schemas
.
https
))
{
return
true
;
}
const
domainToOpen
=
`
${
scheme
}
://
${
authority
}
`
;
const
trustedDomains
=
readTrustedDomains
(
this
.
_storageService
,
this
.
_productService
);
if
(
isURLDomainTrusted
(
resource
,
trustedDomains
))
{
return
true
;
}
else
{
const
{
choice
}
=
await
this
.
_dialogService
.
show
(
Severity
.
Info
,
localize
(
'
openExternalLinkAt
'
,
'
Do you want {0} to open the external website?
\n
{1}
'
,
this
.
_productService
.
nameShort
,
resource
.
toString
(
true
)
),
[
localize
(
'
openLink
'
,
'
Open Link
'
),
localize
(
'
cancel
'
,
'
Cancel
'
),
localize
(
'
configureTrustedDomains
'
,
'
Configure Trusted Domains
'
)
],
{
cancelId
:
1
}
);
// Open Link
if
(
choice
===
0
)
{
return
true
;
}
// Configure Trusted Domains
else
if
(
choice
===
2
)
{
const
pickedDomains
=
await
configureOpenerTrustedDomainsHandler
(
trustedDomains
,
domainToOpen
,
this
.
_quickInputService
,
this
.
_storageService
);
// Trust all domains
if
(
pickedDomains
.
indexOf
(
'
*
'
)
!==
-
1
)
{
return
true
;
}
// Trust current domain
if
(
pickedDomains
.
indexOf
(
domainToOpen
)
!==
-
1
)
{
return
true
;
}
return
false
;
}
return
false
;
}
}
}
function
readTrustedDomains
(
storageService
:
IStorageService
,
productService
:
IProductService
)
{
let
trustedDomains
:
string
[]
=
productService
.
linkProtectionTrustedDomains
?
[...
productService
.
linkProtectionTrustedDomains
]
:
[];
try
{
const
trustedDomainsSrc
=
storageService
.
get
(
'
http.linkProtectionTrustedDomains
'
,
StorageScope
.
GLOBAL
);
if
(
trustedDomainsSrc
)
{
trustedDomains
=
JSON
.
parse
(
trustedDomainsSrc
);
}
}
catch
(
err
)
{
}
return
trustedDomains
;
}
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.
*
* - Schemes must match
* - There's no subdomain matching. For example https://microsoft.com doesn't match https://www.microsoft.com
* - Star matches all. For example https://*.microsoft.com matches https://www.microsoft.com
*/
export
function
isURLDomainTrusted
(
url
:
URI
,
trustedDomains
:
string
[])
{
if
(
isLocalhostAuthority
(
url
.
authority
))
{
return
true
;
}
const
domain
=
`
${
url
.
scheme
}
://
${
url
.
authority
}
`
;
for
(
let
i
=
0
;
i
<
trustedDomains
.
length
;
i
++
)
{
if
(
trustedDomains
[
i
]
===
'
*
'
)
{
return
true
;
}
if
(
trustedDomains
[
i
]
===
domain
)
{
return
true
;
}
if
(
trustedDomains
[
i
].
indexOf
(
'
*
'
)
!==
-
1
)
{
const
parsedTrustedDomain
=
URI
.
parse
(
trustedDomains
[
i
]);
if
(
url
.
scheme
===
parsedTrustedDomain
.
scheme
)
{
const
authoritySegments
=
url
.
authority
.
split
(
'
.
'
);
const
trustedDomainAuthoritySegments
=
parsedTrustedDomain
.
authority
.
split
(
'
.
'
);
if
(
authoritySegments
.
length
===
trustedDomainAuthoritySegments
.
length
)
{
if
(
authoritySegments
.
every
(
(
val
,
i
)
=>
trustedDomainAuthoritySegments
[
i
]
===
'
*
'
||
val
===
trustedDomainAuthoritySegments
[
i
]
)
)
{
return
true
;
}
}
}
}
}
return
false
;
}
src/vs/workbench/contrib/url/common/url.contribution.ts
浏览文件 @
40bc003e
...
...
@@ -3,29 +3,19 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
{
localize
}
from
'
vs/nls
'
;
import
{
SyncActionDescriptor
,
MenuRegistry
,
MenuId
}
from
'
vs/platform/actions/common/actions
'
;
import
{
Registry
}
from
'
vs/platform/registry/common/platform
'
;
import
{
Extensions
as
ActionExtensions
,
IWorkbenchActionRegistry
}
from
'
vs/workbench/common/actions
'
;
import
{
IURLService
}
from
'
vs/platform/url/common/url
'
;
import
{
IQuickInputService
,
IQuickPickItem
,
IQuickPickSeparator
}
from
'
vs/platform/quickinput/common/quickInput
'
;
import
{
URI
}
from
'
vs/base/common/uri
'
;
import
{
Action
}
from
'
vs/base/common/actions
'
;
import
{
IStorageService
,
StorageScope
}
from
'
vs/platform/storage/common/storage
'
;
import
{
URI
}
from
'
vs/base/common/uri
'
;
import
{
localize
}
from
'
vs/nls
'
;
import
{
MenuId
,
MenuRegistry
,
SyncActionDescriptor
}
from
'
vs/platform/actions/common/actions
'
;
import
{
CommandsRegistry
}
from
'
vs/platform/commands/common/commands
'
;
import
{
ServicesAccessor
}
from
'
vs/platform/instantiation/common/instantiation
'
;
import
{
IWorkbenchContribution
,
IWorkbenchContributionsRegistry
,
Extensions
as
WorkbenchExtensions
}
from
'
vs/workbench/common/contributions
'
;
import
{
LifecyclePhase
}
from
'
vs/platform/lifecycle/common/lifecycle
'
;
import
{
IDialogService
}
from
'
vs/platform/dialogs/common/dialogs
'
;
import
{
IProductService
}
from
'
vs/platform/product/common/product
'
;
import
{
IOpenerService
}
from
'
vs/platform/opener/common/opener
'
;
import
{
equalsIgnoreCase
}
from
'
vs/base/common/strings
'
;
import
{
Schemas
}
from
'
vs/base/common/network
'
;
import
Severity
from
'
vs/base/common/severity
'
;
import
{
IQuickInputService
}
from
'
vs/platform/quickinput/common/quickInput
'
;
import
{
Registry
}
from
'
vs/platform/registry/common/platform
'
;
import
{
IURLService
}
from
'
vs/platform/url/common/url
'
;
import
{
Extensions
as
ActionExtensions
,
IWorkbenchActionRegistry
}
from
'
vs/workbench/common/actions
'
;
import
{
Extensions
as
WorkbenchExtensions
,
IWorkbenchContributionsRegistry
}
from
'
vs/workbench/common/contributions
'
;
import
{
configureTrustedDomainSettingsCommand
}
from
'
vs/workbench/contrib/url/common/trustedDomains
'
;
import
{
OpenerValidatorContributions
}
from
'
vs/workbench/contrib/url/common/trustedDomainsValidator
'
;
export
class
OpenUrlAction
extends
Action
{
static
readonly
ID
=
'
workbench.action.url.openUrl
'
;
...
...
@@ -54,227 +44,20 @@ Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions).registe
localize
(
'
developer
'
,
'
Developer
'
)
);
const
configureTrustedDomainsHandler
=
async
(
quickInputService
:
IQuickInputService
,
storageService
:
IStorageService
,
linkProtectionTrustedDomains
:
string
[],
domainToConfigure
?:
string
)
=>
{
try
{
const
trustedDomainsSrc
=
storageService
.
get
(
'
http.linkProtectionTrustedDomains
'
,
StorageScope
.
GLOBAL
);
if
(
trustedDomainsSrc
)
{
linkProtectionTrustedDomains
=
JSON
.
parse
(
trustedDomainsSrc
);
}
}
catch
(
err
)
{
}
const
domainQuickPickItems
:
IQuickPickItem
[]
=
linkProtectionTrustedDomains
.
filter
(
d
=>
d
!==
'
*
'
)
.
map
(
d
=>
{
return
{
type
:
'
item
'
,
label
:
d
,
id
:
d
,
picked
:
true
};
});
const
specialQuickPickItems
:
IQuickPickItem
[]
=
[
{
type
:
'
item
'
,
label
:
localize
(
'
openAllLinksWithoutPrompt
'
,
'
Open all links without prompt
'
),
id
:
'
*
'
,
picked
:
linkProtectionTrustedDomains
.
indexOf
(
'
*
'
)
!==
-
1
}
];
let
domainToConfigureItem
:
IQuickPickItem
|
undefined
=
undefined
;
if
(
domainToConfigure
&&
linkProtectionTrustedDomains
.
indexOf
(
domainToConfigure
)
===
-
1
)
{
domainToConfigureItem
=
{
type
:
'
item
'
,
label
:
domainToConfigure
,
id
:
domainToConfigure
,
picked
:
true
,
description
:
localize
(
'
trustDomainAndOpenLink
'
,
'
Trust domain and open link
'
)
};
specialQuickPickItems
.
push
(
<
IQuickPickItem
>
domainToConfigureItem
);
}
const
quickPickItems
:
(
IQuickPickItem
|
IQuickPickSeparator
)[]
=
domainQuickPickItems
.
length
===
0
?
specialQuickPickItems
:
[...
specialQuickPickItems
,
{
type
:
'
separator
'
},
...
domainQuickPickItems
];
const
pickedResult
=
await
quickInputService
.
pick
(
quickPickItems
,
{
canPickMany
:
true
,
activeItem
:
domainToConfigureItem
});
if
(
pickedResult
)
{
const
pickedDomains
:
string
[]
=
pickedResult
.
map
(
r
=>
r
.
id
!
);
storageService
.
store
(
'
http.linkProtectionTrustedDomains
'
,
JSON
.
stringify
(
pickedDomains
),
StorageScope
.
GLOBAL
);
return
pickedDomains
;
}
return
[];
};
const
configureTrustedDomainCommand
=
{
id
:
'
workbench.action.configureLinkProtectionTrustedDomains
'
,
description
:
{
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
);
const
productService
=
accessor
.
get
(
IProductService
);
const
trustedDomains
=
productService
.
linkProtectionTrustedDomains
?
[...
productService
.
linkProtectionTrustedDomains
]
:
[];
return
configureTrustedDomainsHandler
(
quickInputService
,
storageService
,
trustedDomains
,
domainToConfigure
);
}
};
/**
* Trusted Domains Contribution
*/
CommandsRegistry
.
registerCommand
(
configureTrustedDomainCommand
);
CommandsRegistry
.
registerCommand
(
configureTrustedDomain
Settings
Command
);
MenuRegistry
.
appendMenuItem
(
MenuId
.
CommandPalette
,
{
command
:
{
id
:
configureTrustedDomainCommand
.
id
,
title
:
configureTrustedDomainCommand
.
description
.
description
id
:
configureTrustedDomain
Settings
Command
.
id
,
title
:
configureTrustedDomain
Settings
Command
.
description
.
description
}
});
class
OpenerValidatorContributions
implements
IWorkbenchContribution
{
constructor
(
@
IOpenerService
private
readonly
_openerService
:
IOpenerService
,
@
IStorageService
private
readonly
_storageService
:
IStorageService
,
@
IDialogService
private
readonly
_dialogService
:
IDialogService
,
@
IProductService
private
readonly
_productService
:
IProductService
,
@
IQuickInputService
private
readonly
_quickInputService
:
IQuickInputService
)
{
this
.
_openerService
.
registerValidator
({
shouldOpen
:
r
=>
this
.
validateLink
(
r
)
});
}
async
validateLink
(
resource
:
URI
):
Promise
<
boolean
>
{
const
{
scheme
,
authority
}
=
resource
;
if
(
!
equalsIgnoreCase
(
scheme
,
Schemas
.
http
)
&&
!
equalsIgnoreCase
(
scheme
,
Schemas
.
https
))
{
return
true
;
}
let
trustedDomains
:
string
[]
=
this
.
_productService
.
linkProtectionTrustedDomains
?
[...
this
.
_productService
.
linkProtectionTrustedDomains
]
:
[];
try
{
const
trustedDomainsSrc
=
this
.
_storageService
.
get
(
'
http.linkProtectionTrustedDomains
'
,
StorageScope
.
GLOBAL
);
if
(
trustedDomainsSrc
)
{
trustedDomains
=
JSON
.
parse
(
trustedDomainsSrc
);
}
}
catch
(
err
)
{
}
const
domainToOpen
=
`
${
scheme
}
://
${
authority
}
`
;
if
(
isURLDomainTrusted
(
resource
,
trustedDomains
))
{
return
true
;
}
else
{
const
{
choice
}
=
await
this
.
_dialogService
.
show
(
Severity
.
Info
,
localize
(
'
openExternalLinkAt
'
,
'
Do you want {0} to open the external website?
\n
{1}
'
,
this
.
_productService
.
nameShort
,
resource
.
toString
(
true
)
),
[
localize
(
'
openLink
'
,
'
Open Link
'
),
localize
(
'
cancel
'
,
'
Cancel
'
),
localize
(
'
configureTrustedDomains
'
,
'
Configure Trusted Domains
'
)
],
{
cancelId
:
1
}
);
// Open Link
if
(
choice
===
0
)
{
return
true
;
}
// Configure Trusted Domains
else
if
(
choice
===
2
)
{
const
pickedDomains
=
await
configureTrustedDomainsHandler
(
this
.
_quickInputService
,
this
.
_storageService
,
trustedDomains
,
domainToOpen
);
if
(
pickedDomains
.
indexOf
(
domainToOpen
)
!==
-
1
)
{
return
true
;
}
return
false
;
}
return
false
;
}
}
}
Registry
.
as
<
IWorkbenchContributionsRegistry
>
(
WorkbenchExtensions
.
Workbench
).
registerWorkbenchContribution
(
OpenerValidatorContributions
,
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.
*
* - Schemes must match
* - There's no subdomain matching. For example https://microsoft.com doesn't match https://www.microsoft.com
* - Star matches all. For example https://*.microsoft.com matches https://www.microsoft.com
*/
export
function
isURLDomainTrusted
(
url
:
URI
,
trustedDomains
:
string
[])
{
if
(
isLocalhostAuthority
(
url
.
authority
))
{
return
true
;
}
const
domain
=
`
${
url
.
scheme
}
://
${
url
.
authority
}
`
;
for
(
let
i
=
0
;
i
<
trustedDomains
.
length
;
i
++
)
{
if
(
trustedDomains
[
i
]
===
'
*
'
)
{
return
true
;
}
if
(
trustedDomains
[
i
]
===
domain
)
{
return
true
;
}
if
(
trustedDomains
[
i
].
indexOf
(
'
*
'
)
!==
-
1
)
{
const
parsedTrustedDomain
=
URI
.
parse
(
trustedDomains
[
i
]);
if
(
url
.
scheme
===
parsedTrustedDomain
.
scheme
)
{
const
authoritySegments
=
url
.
authority
.
split
(
'
.
'
);
const
trustedDomainAuthoritySegments
=
parsedTrustedDomain
.
authority
.
split
(
'
.
'
);
if
(
authoritySegments
.
length
===
trustedDomainAuthoritySegments
.
length
)
{
if
(
authoritySegments
.
every
(
(
val
,
i
)
=>
trustedDomainAuthoritySegments
[
i
]
===
'
*
'
||
val
===
trustedDomainAuthoritySegments
[
i
]
)
)
{
return
true
;
}
}
}
}
}
return
false
;
}
src/vs/workbench/test/contrib/linkProtection.test.ts
浏览文件 @
40bc003e
...
...
@@ -5,7 +5,7 @@
import
*
as
assert
from
'
assert
'
;
import
{
isURLDomainTrusted
}
from
'
vs/workbench/contrib/url/common/
url.contribution
'
;
import
{
isURLDomainTrusted
}
from
'
vs/workbench/contrib/url/common/
trustedDomainsValidator
'
;
import
{
URI
}
from
'
vs/base/common/uri
'
;
suite
(
'
Link protection domain matching
'
,
()
=>
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录