Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enabling typedef tslint rule for taco packages #58

Merged
merged 11 commits into from Oct 8, 2015
4 changes: 2 additions & 2 deletions src/remotebuild/lib/cli.ts
Expand Up @@ -46,7 +46,7 @@ class CliHelper {
})
.then(function (): Q.Promise<void> {
var command: string = nconf.get("_")[0] || "start";
var task = Commands.tasks[command];
var task: RemoteBuild.IRemoteBuildTask = Commands.tasks[command];

if (!task) {
Logger.logError(resources.getString("UnknownCommand", command));
Expand Down Expand Up @@ -102,5 +102,5 @@ class CliHelper {
}
}

var cli = CliHelper.cli;
var cli: () => void = CliHelper.cli;
export = cli;
9 changes: 4 additions & 5 deletions src/remotebuild/lib/commands.ts
Expand Up @@ -9,7 +9,9 @@
/// <reference path="../../typings/node.d.ts" />
/// <reference path="../../typings/Q.d.ts" />
/// <reference path="../../typings/nconf.d.ts" />
/// <reference path="../../typings/remotebuild.d.ts" />
/// <reference path="../../typings/tacoUtils.d.ts" />

"use strict";
import Q = require ("q");

Expand All @@ -20,12 +22,9 @@ import server = require ("./server");
import utils = require ("taco-utils");

import Logger = utils.Logger;
interface IRemoteBuildTask {
execute(config: RemoteBuildConf, cliArguments?: string[]): Q.Promise<any>;
}

class Commands {
public static tasks: { [key: string]: IRemoteBuildTask } = {
public static tasks: { [key: string]: RemoteBuild.IRemoteBuildTask } = {
start: {
execute: function (config: RemoteBuildConf, cliArguments?: string[]): Q.Promise<any> {
return server.start(config);
Expand All @@ -42,7 +41,7 @@ class Commands {
},
certificates: {
execute: function (config: RemoteBuildConf, cliArguments: string[]): Q.Promise<any> {
var subCommand = cliArguments[1];
var subCommand: string = cliArguments[1];
switch (subCommand) {
case "generate":
return server.generateClientCert(config);
Expand Down
124 changes: 56 additions & 68 deletions src/remotebuild/lib/darwin/darwinCerts.ts
Expand Up @@ -10,6 +10,8 @@
/// <reference path="../../../typings/Q.d.ts" />
/// <reference path="../../../typings/node.d.ts" />
/// <reference path="../../../typings/rimraf.d.ts" />
/// <reference path="../../../typings/certOptions.d.ts" />

"use strict";

import child_process = require ("child_process");
Expand All @@ -28,11 +30,10 @@ import tacoUtils = require ("taco-utils");

import utils = tacoUtils.UtilHelper;
import logger = tacoUtils.Logger;
var exec = child_process.exec;

class Certs {
private static debug = false;
private static CERT_DEFAULTS = {
private static debug: boolean = false;
private static CERT_DEFAULTS: Certs.ICertOptions = {
days: 1825, // 5 years
country: "US",
ca_cn: os.hostname().substring(0, 50) + ".RB.CA", // Note: these cn entries have a maximum length of 64 bytes. If a hostname contains unicode characters, then os.hostname will return an ascii mis-encoding which is still one byte per character.
Expand All @@ -43,15 +44,15 @@ class Certs {
private static certStore: HostSpecifics.ICertStore = null;

public static resetServerCert(conf: RemoteBuildConf, yesOrNoHandler?: Certs.ICliHandler): Q.Promise<any> {
var certsDir = path.join(conf.serverDir, "certs");
var certsDir: string = path.join(conf.serverDir, "certs");

if (!fs.existsSync(certsDir)) {
return Certs.initializeServerCerts(conf);
}

var shouldProceedDeferred = Q.defer();
var shouldProceedDeferred: Q.Deferred<any> = Q.defer();
yesOrNoHandler = yesOrNoHandler || readline.createInterface({ input: process.stdin, output: process.stdout });
var answerCallback = function (answer: string): void {
var answerCallback: (answer: string) => void = function (answer: string): void {
answer = answer.toLowerCase();
if (resources.getString("OSXResetServerCertResponseYes").split("\n").indexOf(answer) !== -1) {
yesOrNoHandler.close();
Expand Down Expand Up @@ -80,11 +81,11 @@ class Certs {
}

public static generateClientCert(conf: RemoteBuildConf): Q.Promise<number> {
var certsDir = path.join(conf.serverDir, "certs");
var caKeyPath = path.join(certsDir, "ca-key.pem");
var caCertPath = path.join(certsDir, "ca-cert.pem");
var certsDir: string = path.join(conf.serverDir, "certs");
var caKeyPath: string = path.join(certsDir, "ca-key.pem");
var caCertPath: string = path.join(certsDir, "ca-cert.pem");
if (!fs.existsSync(caKeyPath) || !fs.existsSync(caCertPath)) {
var error = resources.getString("CAFilesNotFound", caKeyPath, caCertPath);
var error: string = resources.getString("CAFilesNotFound", caKeyPath, caCertPath);
return Q(0).thenReject(error);
}

Expand All @@ -100,8 +101,8 @@ class Certs {
}

public static initializeServerCerts(conf: RemoteBuildConf): Q.Promise<HostSpecifics.ICertStore> {
var certsDir = path.join(conf.serverDir, "certs");
var certPaths = {
var certsDir: string = path.join(conf.serverDir, "certs");
var certPaths: Certs.ICertPaths = {
certsDir: certsDir,
caKeyPath: path.join(certsDir, "ca-key.pem"),
caCertPath: path.join(certsDir, "ca-cert.pem"),
Expand All @@ -110,7 +111,7 @@ class Certs {
newCerts: false
};

var certsExist = fs.existsSync(certPaths.caCertPath) && fs.existsSync(certPaths.serverKeyPath) && fs.existsSync(certPaths.serverCertPath);
var certsExist: boolean = fs.existsSync(certPaths.caCertPath) && fs.existsSync(certPaths.serverKeyPath) && fs.existsSync(certPaths.serverCertPath);
certPaths.newCerts = !certsExist;
var promise: Q.Promise<any>;
if (certsExist) {
Expand All @@ -133,7 +134,7 @@ class Certs {

utils.createDirectoryIfNecessary(certsDir);
fs.chmodSync(certsDir, 448); // 0700, user read/write/executable, no other permissions
var options = Certs.certOptionsFromConf(conf);
var options: Certs.ICertOptions = Certs.certOptionsFromConf(conf);
return Certs.makeSelfSigningCACert(certPaths.caKeyPath, certPaths.caCertPath, options).
then(function (): Q.Promise<void> {
return Certs.makeSelfSignedCert(certPaths.caKeyPath, certPaths.caCertPath, certPaths.serverKeyPath, certPaths.serverCertPath, options, conf);
Expand Down Expand Up @@ -164,39 +165,39 @@ class Certs {
public static isExpired(certPath: string): Q.Promise<boolean> {
return Certs.displayCert(certPath, ["dates"]).
then(function (output: { stdout: string; stderr: string }): boolean {
var notAfter = new Date(output.stdout.substring(output.stdout.indexOf("notAfter=") + 9, output.stdout.length - 1));
var notAfter: Date = new Date(output.stdout.substring(output.stdout.indexOf("notAfter=") + 9, output.stdout.length - 1));
return (notAfter.getTime() < new Date().getTime());
});
}

// display fields an array of any of these: 'subject', 'issuer', 'dates', etc. (see https://www.openssl.org/docs/apps/x509.html)
public static displayCert(certPath: string, displayFields: string[]): Q.Promise<{ stdout: string; stderr: string }> {
// openssl x509 -noout -in selfsigned-cert.pem -subject -issuer -dates
var args = "x509 -noout -in " + certPath;
var args: string = "x509 -noout -in " + certPath;
(displayFields || []).forEach(function (f: string): void {
args += " -" + f;
});
return Certs.openSslPromise(args);
}

public static removeAllCertsSync(conf: RemoteBuildConf): void {
var certsDir = path.join(conf.serverDir, "certs");
var certsDir: string = path.join(conf.serverDir, "certs");
if (fs.existsSync(certsDir)) {
rimraf.sync(certsDir);
}
}

public static downloadClientCerts(conf: RemoteBuildConf, pinString: string): string {
Certs.purgeExpiredPinBasedClientCertsSync(conf);
var clientCertsDir = path.join(conf.serverDir, "certs", "client");
var clientCertsDir: string = path.join(conf.serverDir, "certs", "client");

var pin = parseInt(pinString, 10);
var pin: number = parseInt(pinString, 10);
if (isNaN(pin)) {
throw { code: 400, id: "InvalidPin" };
}

var pinDir = path.join(clientCertsDir, "" + pin);
var pfx = path.join(pinDir, "client.pfx");
var pinDir: string = path.join(clientCertsDir, "" + pin);
var pfx: string = path.join(pinDir, "client.pfx");
if (!fs.existsSync(pfx)) {
throw { code: 404, id: "ClientCertNotFoundForPIN" };
}
Expand All @@ -205,20 +206,20 @@ class Certs {
}

public static invalidatePIN(conf: RemoteBuildConf, pinString: string): void {
var pinDir = path.join(conf.serverDir, "certs", "client", "" + parseInt(pinString, 10));
var pinDir: string = path.join(conf.serverDir, "certs", "client", "" + parseInt(pinString, 10));
rimraf(pinDir, utils.emptyMethod);
}

public static purgeExpiredPinBasedClientCertsSync(conf: RemoteBuildConf): void {
var clientCertsDir = path.join(conf.serverDir, "certs", "client");
var clientCertsDir: string = path.join(conf.serverDir, "certs", "client");
if (!fs.existsSync(clientCertsDir)) {
return;
}

var pinTimeoutInMinutes = conf.pinTimeout;
var expiredIfOlderThan = new Date().getTime() - (pinTimeoutInMinutes * 60 * 1000);
var pinTimeoutInMinutes: number = conf.pinTimeout;
var expiredIfOlderThan: number = new Date().getTime() - (pinTimeoutInMinutes * 60 * 1000);
fs.readdirSync(clientCertsDir).forEach(function (f: string): void {
var pfx = path.join(clientCertsDir, f, "client.pfx");
var pfx: string = path.join(clientCertsDir, f, "client.pfx");
if (fs.existsSync(pfx) && fs.statSync(pfx).mtime.getTime() < expiredIfOlderThan) {
rimraf.sync(path.join(clientCertsDir, f));
}
Expand All @@ -228,22 +229,22 @@ class Certs {
// Makes a CA cert that will be used for self-signing our server and client certs.
// Exported for tests
public static makeSelfSigningCACert(caKeyPath: string, caCertPath: string, options?: Certs.ICertOptions): Q.Promise<{ stdout: string; stderr: string }> {
options = options || {};
var days = options.days || Certs.CERT_DEFAULTS.days;
var country = options.country || Certs.CERT_DEFAULTS.country;
var cn = Certs.CERT_DEFAULTS.ca_cn;
options = options || <Certs.ICertOptions> {};
var days: number = options.days || Certs.CERT_DEFAULTS.days;
var country: string = options.country || Certs.CERT_DEFAULTS.country;
var cn: string = Certs.CERT_DEFAULTS.ca_cn;
return Certs.openSslPromise("req -newkey rsa:4096 -x509 -days " + days + " -nodes -subj /C=" + country + "/CN=" + cn + " -keyout " + caKeyPath + " -out " + caCertPath);
}

// Makes a new private key and certificate signed with the CA.
// Exported for tests
public static makeSelfSignedCert(caKeyPath: string, caCertPath: string, outKeyPath: string, outCertPath: string, options: Certs.ICertOptions, conf: RemoteBuildConf): Q.Promise<void> {
options = options || {};
var csrPath = path.join(path.dirname(outCertPath), "CSR-" + path.basename(outCertPath));
var days = options.days || Certs.CERT_DEFAULTS.days;
var cn = options.cn || Certs.CERT_DEFAULTS.client_cn;
options = options || <Certs.ICertOptions> {};
var csrPath: string = path.join(path.dirname(outCertPath), "CSR-" + path.basename(outCertPath));
var days: number = options.days || Certs.CERT_DEFAULTS.days;
var cn: string = options.cn || Certs.CERT_DEFAULTS.client_cn;

var cnfPath = path.join(conf.serverDir, "certs", "openssl.cnf");
var cnfPath: string = path.join(conf.serverDir, "certs", "openssl.cnf");
Certs.writeConfigFile(cnfPath, conf);

return Certs.openSslPromise("genrsa -out " + outKeyPath + " 1024").
Expand All @@ -264,9 +265,9 @@ class Certs {
}

private static openSslPromise(args: string): Q.Promise<{ stdout: string; stderr: string }> {
var deferred = Q.defer<{ stdout: string; stderr: string }>();
var deferred: Q.Deferred<{ stdout: string; stderr: string }> = Q.defer<{ stdout: string; stderr: string }>();

exec("openssl " + args, function (error: Error, stdout: Buffer, stderr: Buffer): void {
child_process.exec("openssl " + args, function (error: Error, stdout: Buffer, stderr: Buffer): void {
if (Certs.debug) {
logger.log("exec openssl " + args);
logger.log(util.format("stdout: %s", stdout));
Expand All @@ -284,7 +285,7 @@ class Certs {
}

private static certOptionsFromConf(conf: RemoteBuildConf): Certs.ICertOptions {
var options: Certs.ICertOptions = {};
var options: Certs.ICertOptions = <Certs.ICertOptions> {};
if (conf.certExpirationDays < 1) {
logger.log(resources.getString("CertExpirationInvalid", conf.certExpirationDays, Certs.CERT_DEFAULTS.days));
options.days = Certs.CERT_DEFAULTS.days;
Expand All @@ -296,14 +297,14 @@ class Certs {
}

private static writeConfigFile(cnfPath: string, conf: RemoteBuildConf): void {
var net = os.networkInterfaces();
var cnf = "[req]\ndistinguished_name = req_distinguished_name\nreq_extensions = v3_req\n[req_distinguished_name]\nC_default = US\n[ v3_req ]\nbasicConstraints = CA:FALSE\nkeyUsage = nonRepudiation, digitalSignature, keyEncipherment\nsubjectAltName = @alt_names\n[alt_names]\n";
var net: any = os.networkInterfaces();
var cnf: string = "[req]\ndistinguished_name = req_distinguished_name\nreq_extensions = v3_req\n[req_distinguished_name]\nC_default = US\n[ v3_req ]\nbasicConstraints = CA:FALSE\nkeyUsage = nonRepudiation, digitalSignature, keyEncipherment\nsubjectAltName = @alt_names\n[alt_names]\n";
var hostname: string = conf.hostname;
cnf += util.format("DNS.1 = %s\n", hostname);

var ipCount = 1;
Object.keys(net).forEach(function(key: string){
for (var i = 0; i < net[key].length; i++) {
var ipCount: number = 1;
Object.keys(net).forEach(function(key: string): void{
for (var i: number = 0; i < net[key].length; i++) {
if (net[key][i].address && !net[key][i].internal) {
cnf += util.format("IP.%d = %s\n", ipCount, net[key][i].address);
ipCount++;
Expand All @@ -315,16 +316,16 @@ class Certs {
}

private static makeClientPinAndSslCert(caKeyPath: string, caCertPath: string, certsDir: string, options: Certs.ICertOptions, conf: RemoteBuildConf): Q.Promise<number> {
options = options || {};
options = options || <Certs.ICertOptions> {};
options.cn = Certs.CERT_DEFAULTS.client_cn;
var clientCertsPath = path.join(certsDir, "client");
var clientCertsPath: string = path.join(certsDir, "client");
utils.createDirectoryIfNecessary(clientCertsPath);
// 6 digit random pin (Math.random excludes 1.0)
var pin = 100000 + Math.floor(Math.random() * 900000);
var pinDir = path.join(clientCertsPath, "" + pin);
var pfxPath = path.join(pinDir, "client.pfx");
var clientKeyPath = path.join(pinDir, "client-key.pem");
var clientCertPath = path.join(pinDir, "client-cert.pem");
var pin: number = 100000 + Math.floor(Math.random() * 900000);
var pinDir: string = path.join(clientCertsPath, "" + pin);
var pfxPath: string = path.join(pinDir, "client.pfx");
var clientKeyPath: string = path.join(pinDir, "client-key.pem");
var clientCertPath: string = path.join(pinDir, "client-cert.pem");

utils.createDirectoryIfNecessary(pinDir);
return Certs.makeSelfSignedCert(caKeyPath, caCertPath, clientKeyPath, clientCertPath, options, conf).
Expand All @@ -339,16 +340,16 @@ class Certs {
}

private static makePfx(caCertPath: string, keyPath: string, certPath: string, outPfxPath: string, options?: Certs.ICertOptions): Q.Promise<{ stdout: string; stderr: string }> {
options = options || {};
var name = Certs.CERT_DEFAULTS.pfx_name;
options = options || <Certs.ICertOptions> {};
var name: string = Certs.CERT_DEFAULTS.pfx_name;
return Certs.openSslPromise("pkcs12 -export -in " + certPath + " -inkey " + keyPath + " -certfile " + caCertPath + " -out " + outPfxPath +
" -name \'" + name + "\' -password pass:");
}

private static printSetupInstructionsToConsole(conf: RemoteBuildConf, pin: number): void {
var host = conf.hostname;
var port = conf.port;
var pinTimeoutInMinutes = conf.pinTimeout;
var host: string = conf.hostname;
var port: number = conf.port;
var pinTimeoutInMinutes: number = conf.pinTimeout;
logger.log(resources.getString("OSXCertSetupInformation", host, port, pin));
if (pinTimeoutInMinutes) {
logger.log(resources.getString("OSXCertSetupPinTimeout", pinTimeoutInMinutes));
Expand All @@ -361,17 +362,4 @@ class Certs {
}
}

module Certs {
export interface ICertOptions {
days?: number;
cn?: string;
country?: string;
};

export interface ICliHandler {
question: (question: string, answerCallback: (answer: string) => void) => void;
close: () => void;
}
}

export = Certs;
4 changes: 2 additions & 2 deletions src/remotebuild/lib/darwin/darwinSpecifics.ts
Expand Up @@ -96,8 +96,8 @@ class DarwinSpecifics implements HostSpecifics.IHostSpecifics {
if (conf.secure) {
conf.set("suppressSetupMessage", true);
return certs.generateClientCert(conf).then(function (pin: number): NodeJSHttp.Agent {
var pfxPath = path.join(conf.serverDir, "certs", "client", pin.toString(), "client.pfx");
var cert = fs.readFileSync(pfxPath);
var pfxPath: string = path.join(conf.serverDir, "certs", "client", pin.toString(), "client.pfx");
var cert: Buffer = fs.readFileSync(pfxPath);
fs.unlinkSync(pfxPath);
// TODO: Remove the casting once we've get some complete/up-to-date .d.ts files. See https://github.com/Microsoft/TACO/issues/18
return new https.Agent(<https.RequestOptions> {strictSSL: true, pfx: cert });
Expand Down
2 changes: 1 addition & 1 deletion src/remotebuild/lib/help.ts
Expand Up @@ -50,7 +50,7 @@ class Help extends HelpCommandBase {
return baseRun(data);
}

var moduleConfig = self.remotebuildConf.moduleConfig(topic);
var moduleConfig: RemoteBuild.IServerModuleConfiguration = self.remotebuildConf.moduleConfig(topic);
if (moduleConfig) {
try {
var mod: RemoteBuild.IServerModuleFactory = require(moduleConfig.requirePath || topic);
Expand Down