Skip to content

Commit d467665

Browse files
TingluoHuangbryanmacfarlane
authored andcommitted
certificate support (#112)
1 parent 3daeadd commit d467665

File tree

5 files changed

+104
-36
lines changed

5 files changed

+104
-36
lines changed

api/VsoClient.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import url = require("url");
77
import path = require("path");
88
/// Import base rest class ///
99
import * as restm from 'typed-rest-client/RestClient';
10-
import * as httpm from 'typed-rest-client/HttpClient';
1110
import ifm = require("./interfaces/common/VsoBaseInterfaces");
1211

1312
interface VssApiResourceLocationLookup {

api/WebApi.ts

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,12 @@ import ntlmm = require('./handlers/ntlm');
3636
import patm = require('./handlers/personalaccesstoken');
3737

3838
import * as rm from 'typed-rest-client/RestClient';
39-
//import * as hm from 'typed-rest-client/HttpClient';
4039
import vsom = require('./VsoClient');
4140
import lim = require("./interfaces/LocationsInterfaces");
4241

42+
import fs = require('fs');
43+
import crypto = require('crypto');
44+
4345
/**
4446
* Methods to return handler objects (see handlers folder)
4547
*/
@@ -89,8 +91,37 @@ export class WebApi {
8991
constructor(defaultUrl: string, authHandler: VsoBaseInterfaces.IRequestHandler, options?: VsoBaseInterfaces.IRequestOptions) {
9092
this.serverUrl = defaultUrl;
9193
this.authHandler = authHandler;
92-
this.options = options;
93-
this.rest = new rm.RestClient('vsts-node-api', null, [this.authHandler], options);
94+
this.options = options || {};
95+
96+
// try get proxy setting from environment variable set by VSTS-Task-Lib if there is no proxy setting in the options
97+
if (!this.options.proxy || !this.options.proxy.proxyUrl) {
98+
if (global['_vsts_task_lib_proxy']) {
99+
let proxyFromEnv: VsoBaseInterfaces.IProxyConfiguration = {
100+
proxyUrl: global['_vsts_task_lib_proxy_url'],
101+
proxyUsername: global['_vsts_task_lib_proxy_username'],
102+
proxyPassword: this._readTaskLibSecrets(global['_vsts_task_lib_proxy_password']),
103+
proxyBypassHosts: JSON.parse(global['_vsts_task_lib_proxy_bypass'] || "[]"),
104+
};
105+
106+
this.options.proxy = proxyFromEnv;
107+
}
108+
}
109+
110+
// try get cert setting from environment variable set by VSTS-Task-Lib if there is no cert setting in the options
111+
if (!this.options.cert) {
112+
if (global['_vsts_task_lib_cert']) {
113+
let certFromEnv: VsoBaseInterfaces.ICertConfiguration = {
114+
caFile: global['_vsts_task_lib_cert_ca'],
115+
certFile: global['_vsts_task_lib_cert_clientcert'],
116+
keyFile: global['_vsts_task_lib_cert_key'],
117+
passphrase: this._readTaskLibSecrets(global['_vsts_task_lib_cert_passphrase']),
118+
};
119+
120+
this.options.cert = certFromEnv;
121+
}
122+
}
123+
124+
this.rest = new rm.RestClient('vsts-node-api', null, [this.authHandler], this.options);
94125
this.vsoClient = new vsom.VsoClient(defaultUrl, this.rest);
95126
}
96127

@@ -280,4 +311,24 @@ export class WebApi {
280311
handlers = handlers || [this.authHandler];
281312
return new workitemtrackingm.WorkItemTrackingApi(serverUrl, handlers, this.options);
282313
}
314+
315+
private _readTaskLibSecrets(lookupKey: string): string {
316+
// the lookupKey should has following format
317+
// base64encoded<keyFilePath>:base64encoded<encryptedContent>
318+
if (lookupKey && lookupKey.indexOf(':') > 0) {
319+
let lookupInfo: string[] = lookupKey.split(':', 2);
320+
321+
// file contains encryption key
322+
let keyFile = new Buffer(lookupInfo[0], 'base64').toString('utf8');
323+
let encryptKey = new Buffer(fs.readFileSync(keyFile, 'utf8'), 'base64');
324+
325+
let encryptedContent: string = new Buffer(lookupInfo[1], 'base64').toString('utf8');
326+
327+
let decipher = crypto.createDecipher("aes-256-ctr", encryptKey)
328+
let decryptedContent = decipher.update(encryptedContent, 'hex', 'utf8')
329+
decryptedContent += decipher.final('utf8');
330+
331+
return decryptedContent;
332+
}
333+
}
283334
}

api/interfaces/common/VsoBaseInterfaces.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,19 @@ export interface IRequestOptions {
6767
socketTimeout?: number,
6868
ignoreSslError?: boolean,
6969
proxy?: IProxyConfiguration
70+
cert?: ICertConfiguration
7071
}
7172

7273
export interface IProxyConfiguration {
7374
proxyUrl: string;
7475
proxyUsername?: string;
7576
proxyPassword?: string;
7677
proxyBypassHosts?: string[];
78+
}
79+
80+
export interface ICertConfiguration {
81+
caFile?: string;
82+
certFile?: string;
83+
keyFile?: string;
84+
passphrase?: string;
7785
}

package.json

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,32 @@
11
{
2-
"name": "vso-node-api",
3-
"description": "Node client for Visual Studio Online/TFS REST APIs",
4-
"version": "6.2.7-preview",
5-
"main": "./WebApi.js",
6-
"typings": "./WebApi.d.ts",
7-
"scripts": {
8-
"build": "node make.js build",
9-
"test": "node make.js test",
10-
"samples": "node make.js test && node samples/run.js"
11-
},
12-
"repository": {
13-
"type": "git",
14-
"url": "https://github.com/Microsoft/vso-node-api"
15-
},
16-
"author": "Microsoft Corporation",
17-
"contributors": [
18-
"Bryan MacFarlane <[email protected]>",
19-
"Scott Dallamura <[email protected]>",
20-
"Teddy Ward <[email protected]>"
21-
],
22-
"license": "MIT",
23-
"dependencies": {
24-
"tunnel": "0.0.4",
25-
"typed-rest-client": "^0.11.0",
26-
"underscore": "^1.8.3"
27-
},
28-
"devDependencies": {
29-
"shelljs": "^0.7.0",
30-
"typescript": "^2.1.4"
31-
}
32-
}
2+
"name": "vso-node-api",
3+
"description": "Node client for Visual Studio Online/TFS REST APIs",
4+
"version": "6.2.8-preview",
5+
"main": "./WebApi.js",
6+
"typings": "./WebApi.d.ts",
7+
"scripts": {
8+
"build": "node make.js build",
9+
"test": "node make.js test",
10+
"samples": "node make.js test && node samples/run.js"
11+
},
12+
"repository": {
13+
"type": "git",
14+
"url": "https://github.com/Microsoft/vso-node-api"
15+
},
16+
"author": "Microsoft Corporation",
17+
"contributors": [
18+
"Bryan MacFarlane <[email protected]>",
19+
"Scott Dallamura <[email protected]>",
20+
"Teddy Ward <[email protected]>"
21+
],
22+
"license": "MIT",
23+
"dependencies": {
24+
"tunnel": "0.0.4",
25+
"typed-rest-client": "^0.12.0",
26+
"underscore": "^1.8.3"
27+
},
28+
"devDependencies": {
29+
"shelljs": "^0.7.0",
30+
"typescript": "^2.1.4"
31+
}
32+
}

samples/common.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export async function getWebApi(): Promise<vm.WebApi> {
2020
let authHandler = vm.getPersonalAccessTokenHandler(token);
2121

2222
let option = undefined;
23-
23+
2424
// The following sample is for testing proxy
2525
// option = {
2626
// proxy: {
@@ -34,6 +34,16 @@ export async function getWebApi(): Promise<vm.WebApi> {
3434
// ignoreSslError: true
3535
// };
3636

37+
// The following sample is for testing cert
38+
// option = {
39+
// cert: {
40+
// caFile: "E:\\certutil\\doctest\\ca2.pem",
41+
// certFile: "E:\\certutil\\doctest\\client-cert2.pem",
42+
// keyFile: "E:\\certutil\\doctest\\client-cert-key2.pem",
43+
// passphrase: "test123",
44+
// },
45+
// };
46+
3747
let vsts: vm.WebApi = new vm.WebApi(serverUrl, authHandler, option);
3848
let connData: lim.ConnectionData = await vsts.connect();
3949
console.log('Hello ' + connData.authenticatedUser.providerDisplayName);

0 commit comments

Comments
 (0)