Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xxadev
vscode
提交
ce1e0612
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,发现更多精彩内容 >>
提交
ce1e0612
编写于
10月 26, 2020
作者:
B
Benjamin Pasero
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
proxy auth - implement a way to remember credentials
上级
4d064bc7
变更
3
隐藏空白更改
内联
并排
Showing
3 changed file
with
197 addition
and
58 deletion
+197
-58
src/vs/code/electron-main/app.ts
src/vs/code/electron-main/app.ts
+3
-50
src/vs/code/electron-main/auth2.ts
src/vs/code/electron-main/auth2.ts
+167
-0
src/vs/workbench/electron-sandbox/window.ts
src/vs/workbench/electron-sandbox/window.ts
+27
-8
未找到文件。
src/vs/code/electron-main/app.ts
浏览文件 @
ce1e0612
...
...
@@ -34,6 +34,7 @@ import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProper
import
{
getDelayedChannel
,
StaticRouter
,
createChannelReceiver
,
createChannelSender
}
from
'
vs/base/parts/ipc/common/ipc
'
;
import
product
from
'
vs/platform/product/common/product
'
;
import
{
ProxyAuthHandler
}
from
'
vs/code/electron-main/auth
'
;
import
{
ProxyAuthHandler2
}
from
'
vs/code/electron-main/auth2
'
;
import
{
Disposable
}
from
'
vs/base/common/lifecycle
'
;
import
{
IWindowsMainService
,
ICodeWindow
}
from
'
vs/platform/windows/electron-main/windows
'
;
import
{
URI
}
from
'
vs/base/common/uri
'
;
...
...
@@ -111,56 +112,6 @@ export class CodeApplication extends Disposable {
// Dispose on shutdown
this
.
lifecycleMainService
.
onWillShutdown
(()
=>
this
.
dispose
());
// Login handler for proxy support
if
(
this
.
configurationService
.
getValue
(
'
window.enableExperimentalProxyLoginDialog
'
)
===
true
)
{
let
handledProxyLogins
=
0
;
app
.
on
(
'
login
'
,
(
event
,
webContents
,
req
,
authInfo
,
cb
)
=>
{
if
(
!
authInfo
.
isProxy
)
{
return
;
// only for proxy
}
this
.
logService
.
trace
(
'
app#login (proxy) - enter
'
);
if
(
!
this
.
windowsMainService
)
{
this
.
logService
.
trace
(
'
app#login (proxy) - exit - too early to handle
'
);
return
;
// too early to handle
}
// Find suitable window to show dialog
const
window
=
this
.
windowsMainService
.
getWindowByWebContents
(
webContents
)
||
this
.
windowsMainService
.
getLastActiveWindow
();
if
(
!
window
)
{
this
.
logService
.
trace
(
'
app#login (proxy) - exit - no opened window found
'
);
return
;
// unexpected
}
// Limit logins to 1 per session to avoid duplicate login prompts
handledProxyLogins
++
;
if
(
handledProxyLogins
>
1
)
{
return
;
// only once
}
// Signal we handle this on our own
event
.
preventDefault
();
// Open proxy dialog
this
.
logService
.
trace
(
`app#login (proxy) - asking window
${
window
.
id
}
to handle proxy login`
);
const
payload
=
{
authInfo
,
replyChannel
:
`vscode:proxyAuthResponse:
${
generateUuid
()}
`
};
window
.
sendWhenReady
(
'
vscode:openProxyAuthDialog
'
,
payload
);
// Handle reply
const
proxyAuthResponseHandler
=
(
event
:
Event
,
channel
:
string
,
credentials
:
{
username
:
string
,
password
:
string
})
=>
{
if
(
channel
===
payload
.
replyChannel
)
{
this
.
logService
.
trace
(
`app#login (proxy) - exit - received credentials from window
${
window
.
id
}
`
);
webContents
.
off
(
'
ipc-message
'
,
proxyAuthResponseHandler
);
cb
(
credentials
.
username
,
credentials
.
password
);
}
};
webContents
.
on
(
'
ipc-message
'
,
proxyAuthResponseHandler
);
});
}
// Contextmenu via IPC support
registerContextMenuListener
();
...
...
@@ -440,6 +391,8 @@ export class CodeApplication extends Disposable {
// Setup Auth Handler
if
(
this
.
configurationService
.
getValue
(
'
window.enableExperimentalProxyLoginDialog
'
)
!==
true
)
{
this
.
_register
(
new
ProxyAuthHandler
());
}
else
{
this
.
_register
(
appInstantiationService
.
createInstance
(
ProxyAuthHandler2
));
}
// Open Windows
...
...
src/vs/code/electron-main/auth2.ts
0 → 100644
浏览文件 @
ce1e0612
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
{
Disposable
}
from
'
vs/base/common/lifecycle
'
;
import
{
Event
}
from
'
vs/base/common/event
'
;
import
{
app
,
AuthInfo
,
WebContents
,
Event
as
ElectronEvent
}
from
'
electron
'
;
import
{
ILogService
}
from
'
vs/platform/log/common/log
'
;
import
{
IWindowsMainService
}
from
'
vs/platform/windows/electron-main/windows
'
;
import
{
INativeHostMainService
}
from
'
vs/platform/native/electron-main/nativeHostMainService
'
;
import
{
IEncryptionMainService
}
from
'
vs/platform/encryption/electron-main/encryptionMainService
'
;
import
{
generateUuid
}
from
'
vs/base/common/uuid
'
;
type
LoginEvent
=
{
event
:
ElectronEvent
;
webContents
:
WebContents
;
authInfo
:
AuthInfo
;
cb
:
(
username
:
string
,
password
:
string
)
=>
void
;
};
type
Credentials
=
{
username
:
string
;
password
:
string
;
};
export
class
ProxyAuthHandler2
extends
Disposable
{
private
static
PROXY_CREDENTIALS_SERVICE_KEY
=
'
vscode.proxy-credentials
'
;
private
pendingProxyHandler
=
false
;
private
proxyDialogShown
=
false
;
private
storedProxyCredentialsUsed
=
false
;
constructor
(
@
ILogService
private
readonly
logService
:
ILogService
,
@
IWindowsMainService
private
readonly
windowsMainService
:
IWindowsMainService
,
@
INativeHostMainService
private
readonly
nativeHostMainService
:
INativeHostMainService
,
@
IEncryptionMainService
private
readonly
encryptionMainService
:
IEncryptionMainService
)
{
super
();
this
.
registerListeners
();
}
private
registerListeners
():
void
{
const
onLogin
=
Event
.
fromNodeEventEmitter
<
LoginEvent
>
(
app
,
'
login
'
,
(
event
,
webContents
,
req
,
authInfo
,
cb
)
=>
({
event
,
webContents
,
req
,
authInfo
,
cb
}));
this
.
_register
(
onLogin
(
this
.
onLogin
,
this
));
}
private
onLogin
(
event
:
LoginEvent
):
void
{
if
(
!
event
.
authInfo
.
isProxy
)
{
return
;
// only for proxy
}
if
(
this
.
pendingProxyHandler
)
{
this
.
logService
.
trace
(
'
auth#onLogin (proxy) - exit - pending proxy handling found
'
);
return
;
// never more than once at the same time
}
if
(
this
.
proxyDialogShown
)
{
this
.
logService
.
trace
(
'
auth#onLogin (proxy) - exit - proxy dialog already shown
'
);
return
;
// only one dialog per session at max
}
this
.
handleOnLogin
(
event
);
}
private
async
handleOnLogin
({
event
,
webContents
,
authInfo
,
cb
}:
LoginEvent
):
Promise
<
void
>
{
this
.
logService
.
trace
(
'
auth#handleOnLogin (proxy) - enter
'
);
this
.
pendingProxyHandler
=
true
;
try
{
const
credentials
=
await
this
.
resolveProxyCredentials
(
event
,
webContents
,
authInfo
);
if
(
credentials
)
{
this
.
logService
.
trace
(
'
auth#handleOnLogin (proxy) - got credentials
'
);
cb
(
credentials
.
username
,
credentials
.
password
);
}
else
{
this
.
logService
.
trace
(
'
auth#handleOnLogin (proxy) - did not get credentials
'
);
}
}
finally
{
this
.
logService
.
trace
(
'
auth#handleOnLogin (proxy) - exit
'
);
this
.
pendingProxyHandler
=
false
;
}
}
private
async
resolveProxyCredentials
(
event
:
ElectronEvent
,
webContents
:
WebContents
,
authInfo
:
AuthInfo
):
Promise
<
Credentials
|
undefined
>
{
this
.
logService
.
trace
(
'
auth#resolveProxyCredentials - enter
'
);
// Signal we handle this on our own
event
.
preventDefault
();
// Find any previously stored credentials
let
username
:
string
|
undefined
=
undefined
;
let
password
:
string
|
undefined
=
undefined
;
try
{
const
encryptedSerializedProxyCredentials
=
await
this
.
nativeHostMainService
.
getPassword
(
undefined
,
ProxyAuthHandler2
.
PROXY_CREDENTIALS_SERVICE_KEY
,
'
account
'
);
if
(
encryptedSerializedProxyCredentials
)
{
const
credentials
:
Credentials
=
JSON
.
parse
(
await
this
.
encryptionMainService
.
decrypt
(
encryptedSerializedProxyCredentials
));
if
(
credentials
.
username
&&
credentials
.
password
)
{
username
=
credentials
.
username
;
password
=
credentials
.
password
;
}
}
}
catch
(
error
)
{
this
.
logService
.
error
(
error
);
// handle errors by asking user for login via dialog
}
// Reply with stored credentials unless we used them already.
// In that case we need to show a login dialog again because
// they seem invalid.
if
(
!
this
.
storedProxyCredentialsUsed
&&
username
&&
password
)
{
this
.
logService
.
trace
(
'
auth#resolveProxyCredentials (proxy) - exit - found stored credentials to use
'
);
this
.
storedProxyCredentialsUsed
=
true
;
return
{
username
,
password
};
}
// Find suitable window to show dialog
const
window
=
this
.
windowsMainService
.
getWindowByWebContents
(
webContents
)
||
this
.
windowsMainService
.
getLastActiveWindow
();
if
(
!
window
)
{
this
.
logService
.
trace
(
'
auth#resolveProxyCredentials (proxy) - exit - no opened window found to show dialog in
'
);
return
undefined
;
// unexpected
}
this
.
logService
.
trace
(
`auth#resolveProxyCredentials (proxy) - asking window
${
window
.
id
}
to handle proxy login`
);
// Open proxy dialog
const
payload
=
{
authInfo
,
username
,
password
,
replyChannel
:
`vscode:proxyAuthResponse:
${
generateUuid
()}
`
};
window
.
sendWhenReady
(
'
vscode:openProxyAuthenticationDialog
'
,
payload
);
this
.
proxyDialogShown
=
true
;
// Handle reply
return
new
Promise
(
resolve
=>
{
const
proxyAuthResponseHandler
=
async
(
event
:
ElectronEvent
,
channel
:
string
,
reply
:
Credentials
&
{
remember
:
boolean
})
=>
{
if
(
channel
===
payload
.
replyChannel
)
{
this
.
logService
.
trace
(
`auth#resolveProxyCredentials - exit - received credentials from window
${
window
.
id
}
`
);
webContents
.
off
(
'
ipc-message
'
,
proxyAuthResponseHandler
);
const
credentials
:
Credentials
=
{
username
:
reply
.
username
,
password
:
reply
.
password
};
// Update stored credentials based on `remember` flag
try
{
if
(
reply
.
remember
)
{
const
encryptedSerializedCredentials
=
await
this
.
encryptionMainService
.
encrypt
(
JSON
.
stringify
(
credentials
));
await
this
.
nativeHostMainService
.
setPassword
(
undefined
,
ProxyAuthHandler2
.
PROXY_CREDENTIALS_SERVICE_KEY
,
'
account
'
,
encryptedSerializedCredentials
);
}
else
{
await
this
.
nativeHostMainService
.
deletePassword
(
undefined
,
ProxyAuthHandler2
.
PROXY_CREDENTIALS_SERVICE_KEY
,
'
account
'
);
}
}
catch
(
error
)
{
this
.
logService
.
error
(
error
);
// handle gracefully
}
resolve
({
username
:
credentials
.
username
,
password
:
credentials
.
password
});
}
};
webContents
.
on
(
'
ipc-message
'
,
proxyAuthResponseHandler
);
});
}
}
src/vs/workbench/electron-sandbox/window.ts
浏览文件 @
ce1e0612
...
...
@@ -43,7 +43,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import
{
MenubarControl
}
from
'
../browser/parts/titlebar/menubarControl
'
;
import
{
ILabelService
}
from
'
vs/platform/label/common/label
'
;
import
{
IUpdateService
}
from
'
vs/platform/update/common/update
'
;
import
{
IStorageService
}
from
'
vs/platform/storage/common/storage
'
;
import
{
IStorageService
,
StorageScope
}
from
'
vs/platform/storage/common/storage
'
;
import
{
IPreferencesService
}
from
'
../services/preferences/common/preferences
'
;
import
{
IMenubarData
,
IMenubarMenu
,
IMenubarKeybinding
,
IMenubarMenuItemSubmenu
,
IMenubarMenuItemAction
,
MenubarMenuItem
}
from
'
vs/platform/menubar/common/menubar
'
;
import
{
IMenubarService
}
from
'
vs/platform/menubar/electron-sandbox/menubar
'
;
...
...
@@ -68,6 +68,8 @@ import { AuthInfo } from 'vs/base/parts/sandbox/electron-sandbox/electronTypes';
export
class
NativeWindow
extends
Disposable
{
private
static
REMEMBER_PROXY_CREDENTIALS_KEY
=
'
window.rememberProxyCredentials
'
;
private
touchBarMenu
:
IMenu
|
undefined
;
private
readonly
touchBarDisposables
=
this
.
_register
(
new
DisposableStore
());
private
lastInstalledTouchedBar
:
ICommandAction
[][]
|
undefined
;
...
...
@@ -110,7 +112,8 @@ export class NativeWindow extends Disposable {
@
IFilesConfigurationService
private
readonly
filesConfigurationService
:
IFilesConfigurationService
,
@
IProductService
private
readonly
productService
:
IProductService
,
@
IRemoteAuthorityResolverService
private
readonly
remoteAuthorityResolverService
:
IRemoteAuthorityResolverService
,
@
IDialogService
private
readonly
dialogService
:
IDialogService
@
IDialogService
private
readonly
dialogService
:
IDialogService
,
@
IStorageService
private
readonly
storageService
:
IStorageService
)
{
super
();
...
...
@@ -203,24 +206,40 @@ export class NativeWindow extends Disposable {
});
// Proxy Login Dialog
ipcRenderer
.
on
(
'
vscode:openProxyAuthDialog
'
,
async
(
event
:
unknown
,
payload
:
{
authInfo
:
AuthInfo
,
replyChannel
:
string
})
=>
{
ipcRenderer
.
on
(
'
vscode:openProxyAuthenticationDialog
'
,
async
(
event
:
unknown
,
payload
:
{
authInfo
:
AuthInfo
,
username
?:
string
,
password
?:
string
,
replyChannel
:
string
})
=>
{
const
rememberCredentials
=
this
.
storageService
.
getBoolean
(
NativeWindow
.
REMEMBER_PROXY_CREDENTIALS_KEY
,
StorageScope
.
GLOBAL
);
const
result
=
await
this
.
dialogService
.
input
(
'
question
'
,
nls
.
localize
(
'
proxyAuthRequired
'
,
"
Proxy Authentication Required
"
),
[
nls
.
localize
({
key
:
'
loginButton
'
,
comment
:
[
'
&& denotes a mnemonic
'
]
},
"
&&Log In
"
),
nls
.
localize
({
key
:
'
cancelButton
'
,
comment
:
[
'
&& denotes a mnemonic
'
]
},
"
&&Cancel
"
)
],
[
{
placeholder
:
nls
.
localize
(
'
username
'
,
"
Username
"
)
},
{
placeholder
:
nls
.
localize
(
'
password
'
,
"
Password
"
),
type
:
'
password
'
}
{
placeholder
:
nls
.
localize
(
'
username
'
,
"
Username
"
)
,
value
:
payload
.
username
},
{
placeholder
:
nls
.
localize
(
'
password
'
,
"
Password
"
),
type
:
'
password
'
,
value
:
payload
.
password
}
],
{
cancelId
:
1
,
detail
:
nls
.
localize
(
'
proxyDetail
'
,
"
The proxy {0} requires a userame and password.
"
,
`
${
payload
.
authInfo
.
host
}
:
${
payload
.
authInfo
.
port
}
`
)
detail
:
nls
.
localize
(
'
proxyDetail
'
,
"
The proxy {0} requires a userame and password.
"
,
`
${
payload
.
authInfo
.
host
}
:
${
payload
.
authInfo
.
port
}
`
),
checkbox
:
{
label
:
nls
.
localize
(
'
rememberCredentials
'
,
"
Remember my credentials
"
),
checked
:
rememberCredentials
}
});
if
(
result
.
choice
!==
1
&&
result
.
values
)
{
ipcRenderer
.
send
(
payload
.
replyChannel
,
{
username
:
result
.
values
[
0
],
password
:
result
.
values
[
1
]
});
if
(
result
.
choice
!==
0
||
!
result
.
values
)
{
return
;
// dialog canceled
}
// Update state based on checkbox
if
(
result
.
checkboxChecked
)
{
this
.
storageService
.
store
(
NativeWindow
.
REMEMBER_PROXY_CREDENTIALS_KEY
,
true
,
StorageScope
.
GLOBAL
);
}
else
{
this
.
storageService
.
remove
(
NativeWindow
.
REMEMBER_PROXY_CREDENTIALS_KEY
,
StorageScope
.
GLOBAL
);
}
// Reply back to main side with credentials
const
[
username
,
password
]
=
result
.
values
;
ipcRenderer
.
send
(
payload
.
replyChannel
,
{
username
,
password
,
remember
:
!!
result
.
checkboxChecked
});
});
// Accessibility support changed event
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录