Skip to content

Commit

Permalink
certificate support (#112)
Browse files Browse the repository at this point in the history
  • Loading branch information
TingluoHuang authored and bryanmacfarlane committed Aug 29, 2017
1 parent 3daeadd commit d467665
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 36 deletions.
1 change: 0 additions & 1 deletion api/VsoClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import url = require("url");
import path = require("path");
/// Import base rest class ///
import * as restm from 'typed-rest-client/RestClient';
import * as httpm from 'typed-rest-client/HttpClient';
import ifm = require("./interfaces/common/VsoBaseInterfaces");

interface VssApiResourceLocationLookup {
Expand Down
57 changes: 54 additions & 3 deletions api/WebApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,12 @@ import ntlmm = require('./handlers/ntlm');
import patm = require('./handlers/personalaccesstoken');

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

import fs = require('fs');
import crypto = require('crypto');

/**
* Methods to return handler objects (see handlers folder)
*/
Expand Down Expand Up @@ -89,8 +91,37 @@ export class WebApi {
constructor(defaultUrl: string, authHandler: VsoBaseInterfaces.IRequestHandler, options?: VsoBaseInterfaces.IRequestOptions) {
this.serverUrl = defaultUrl;
this.authHandler = authHandler;
this.options = options;
this.rest = new rm.RestClient('vsts-node-api', null, [this.authHandler], options);
this.options = options || {};

// try get proxy setting from environment variable set by VSTS-Task-Lib if there is no proxy setting in the options
if (!this.options.proxy || !this.options.proxy.proxyUrl) {
if (global['_vsts_task_lib_proxy']) {
let proxyFromEnv: VsoBaseInterfaces.IProxyConfiguration = {
proxyUrl: global['_vsts_task_lib_proxy_url'],
proxyUsername: global['_vsts_task_lib_proxy_username'],
proxyPassword: this._readTaskLibSecrets(global['_vsts_task_lib_proxy_password']),
proxyBypassHosts: JSON.parse(global['_vsts_task_lib_proxy_bypass'] || "[]"),
};

this.options.proxy = proxyFromEnv;
}
}

// try get cert setting from environment variable set by VSTS-Task-Lib if there is no cert setting in the options
if (!this.options.cert) {
if (global['_vsts_task_lib_cert']) {
let certFromEnv: VsoBaseInterfaces.ICertConfiguration = {
caFile: global['_vsts_task_lib_cert_ca'],
certFile: global['_vsts_task_lib_cert_clientcert'],
keyFile: global['_vsts_task_lib_cert_key'],
passphrase: this._readTaskLibSecrets(global['_vsts_task_lib_cert_passphrase']),
};

this.options.cert = certFromEnv;
}
}

this.rest = new rm.RestClient('vsts-node-api', null, [this.authHandler], this.options);
this.vsoClient = new vsom.VsoClient(defaultUrl, this.rest);
}

Expand Down Expand Up @@ -280,4 +311,24 @@ export class WebApi {
handlers = handlers || [this.authHandler];
return new workitemtrackingm.WorkItemTrackingApi(serverUrl, handlers, this.options);
}

private _readTaskLibSecrets(lookupKey: string): string {
// the lookupKey should has following format
// base64encoded<keyFilePath>:base64encoded<encryptedContent>
if (lookupKey && lookupKey.indexOf(':') > 0) {
let lookupInfo: string[] = lookupKey.split(':', 2);

// file contains encryption key
let keyFile = new Buffer(lookupInfo[0], 'base64').toString('utf8');
let encryptKey = new Buffer(fs.readFileSync(keyFile, 'utf8'), 'base64');

let encryptedContent: string = new Buffer(lookupInfo[1], 'base64').toString('utf8');

let decipher = crypto.createDecipher("aes-256-ctr", encryptKey)
let decryptedContent = decipher.update(encryptedContent, 'hex', 'utf8')
decryptedContent += decipher.final('utf8');

return decryptedContent;
}
}
}
8 changes: 8 additions & 0 deletions api/interfaces/common/VsoBaseInterfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,19 @@ export interface IRequestOptions {
socketTimeout?: number,
ignoreSslError?: boolean,
proxy?: IProxyConfiguration
cert?: ICertConfiguration
}

export interface IProxyConfiguration {
proxyUrl: string;
proxyUsername?: string;
proxyPassword?: string;
proxyBypassHosts?: string[];
}

export interface ICertConfiguration {
caFile?: string;
certFile?: string;
keyFile?: string;
passphrase?: string;
}
62 changes: 31 additions & 31 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
{
"name": "vso-node-api",
"description": "Node client for Visual Studio Online/TFS REST APIs",
"version": "6.2.7-preview",
"main": "./WebApi.js",
"typings": "./WebApi.d.ts",
"scripts": {
"build": "node make.js build",
"test": "node make.js test",
"samples": "node make.js test && node samples/run.js"
},
"repository": {
"type": "git",
"url": "https://github.com/Microsoft/vso-node-api"
},
"author": "Microsoft Corporation",
"contributors": [
"Bryan MacFarlane <[email protected]>",
"Scott Dallamura <[email protected]>",
"Teddy Ward <[email protected]>"
],
"license": "MIT",
"dependencies": {
"tunnel": "0.0.4",
"typed-rest-client": "^0.11.0",
"underscore": "^1.8.3"
},
"devDependencies": {
"shelljs": "^0.7.0",
"typescript": "^2.1.4"
}
}
"name": "vso-node-api",
"description": "Node client for Visual Studio Online/TFS REST APIs",
"version": "6.2.8-preview",
"main": "./WebApi.js",
"typings": "./WebApi.d.ts",
"scripts": {
"build": "node make.js build",
"test": "node make.js test",
"samples": "node make.js test && node samples/run.js"
},
"repository": {
"type": "git",
"url": "https://github.com/Microsoft/vso-node-api"
},
"author": "Microsoft Corporation",
"contributors": [
"Bryan MacFarlane <[email protected]>",
"Scott Dallamura <[email protected]>",
"Teddy Ward <[email protected]>"
],
"license": "MIT",
"dependencies": {
"tunnel": "0.0.4",
"typed-rest-client": "^0.12.0",
"underscore": "^1.8.3"
},
"devDependencies": {
"shelljs": "^0.7.0",
"typescript": "^2.1.4"
}
}
12 changes: 11 additions & 1 deletion samples/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export async function getWebApi(): Promise<vm.WebApi> {
let authHandler = vm.getPersonalAccessTokenHandler(token);

let option = undefined;

// The following sample is for testing proxy
// option = {
// proxy: {
Expand All @@ -34,6 +34,16 @@ export async function getWebApi(): Promise<vm.WebApi> {
// ignoreSslError: true
// };

// The following sample is for testing cert
// option = {
// cert: {
// caFile: "E:\\certutil\\doctest\\ca2.pem",
// certFile: "E:\\certutil\\doctest\\client-cert2.pem",
// keyFile: "E:\\certutil\\doctest\\client-cert-key2.pem",
// passphrase: "test123",
// },
// };

let vsts: vm.WebApi = new vm.WebApi(serverUrl, authHandler, option);
let connData: lim.ConnectionData = await vsts.connect();
console.log('Hello ' + connData.authenticatedUser.providerDisplayName);
Expand Down

0 comments on commit d467665

Please sign in to comment.