forked from microsoft/vscode
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathaskpass.ts
More file actions
98 lines (81 loc) · 2.9 KB
/
askpass.ts
File metadata and controls
98 lines (81 loc) · 2.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { window, InputBoxOptions, Uri, OutputChannel, Disposable, workspace } from 'vscode';
import { IDisposable, EmptyDisposable, toDisposable } from './util';
import * as path from 'path';
import { IIPCHandler, IIPCServer, createIPCServer } from './ipc/ipcServer';
import { CredentialsProvider, Credentials } from './api/git';
export class Askpass implements IIPCHandler {
private disposable: IDisposable = EmptyDisposable;
private cache = new Map<string, Credentials>();
private credentialsProviders = new Set<CredentialsProvider>();
static async create(outputChannel: OutputChannel, context?: string): Promise<Askpass> {
try {
return new Askpass(await createIPCServer(context));
} catch (err) {
outputChannel.appendLine(`[error] Failed to create git askpass IPC: ${err}`);
return new Askpass();
}
}
private constructor(private ipc?: IIPCServer) {
if (ipc) {
this.disposable = ipc.registerHandler('askpass', this);
}
}
async handle({ request, host }: { request: string, host: string }): Promise<string> {
const config = workspace.getConfiguration('git', null);
const enabled = config.get<boolean>('enabled');
if (!enabled) {
return '';
}
const uri = Uri.parse(host);
const authority = uri.authority.replace(/^.*@/, '');
const password = /password/i.test(request);
const cached = this.cache.get(authority);
if (cached && password) {
this.cache.delete(authority);
return cached.password;
}
if (!password) {
for (const credentialsProvider of this.credentialsProviders) {
try {
const credentials = await credentialsProvider.getCredentials(uri);
if (credentials) {
this.cache.set(authority, credentials);
setTimeout(() => this.cache.delete(authority), 60_000);
return credentials.username;
}
} catch { }
}
}
const options: InputBoxOptions = {
password,
placeHolder: request,
prompt: `Git: ${host}`,
ignoreFocusOut: true
};
return await window.showInputBox(options) || '';
}
getEnv(): { [key: string]: string; } {
if (!this.ipc) {
return {
GIT_ASKPASS: path.join(__dirname, 'askpass-empty.sh')
};
}
return {
...this.ipc.getEnv(),
GIT_ASKPASS: path.join(__dirname, 'askpass.sh'),
VSCODE_GIT_ASKPASS_NODE: process.execPath,
VSCODE_GIT_ASKPASS_MAIN: path.join(__dirname, 'askpass-main.js')
};
}
registerCredentialsProvider(provider: CredentialsProvider): Disposable {
this.credentialsProviders.add(provider);
return toDisposable(() => this.credentialsProviders.delete(provider));
}
dispose(): void {
this.disposable.dispose();
}
}