#!/usr/bin/env node /** * Modules */ var fs = require('fs'); var url = require('url'); var http = require('http'); var path = require('path'); var Stream = require('stream').Stream; var StringDecoder = require('string_decoder').StringDecoder; /** * Mozilla Root Cert URL */ var certUrl = 'https://raw.githubusercontent.com/joyent/node/master/src/node_root_certs.h'; /** * Get Root Certs */ function getRootCerts(callback) { return request(certUrl, function(err, res, body) { if (err) return callback(err); body = body.replace(/,\s*$/, ''); body = 'var certs = {\n' + body + '\n};\n'; body = body.replace(/^"/gm, '+ "'); body = body.replace(/^\+ "-----B/gm, '"-----B'); body = body.replace(/\/\*([^*]+)\*\/\n(?=")/g, function(_, name) { var key = name.trim(); return '// ' + key + '\n' + '"' + key + '":\n'; }); body += '' + '\n' + '// Use hash table for efficiency:\n' + 'var trusted = Object.keys(certs).reduce(function(trusted, key) {\n' + ' var pem = certs[key];\n' + ' pem = pem.replace(/-----BEGIN CERTIFICATE-----/g, "");\n' + ' pem = pem.replace(/-----END CERTIFICATE-----/g, "");\n' + ' pem = pem.replace(/\\s+/g, "");\n' + ' trusted[pem] = key;\n' + ' return trusted;\n' + '}, {});\n' + '\n' + 'function getTrusted(pem) {\n' + ' pem = pem + "";\n' + ' pem = pem.replace(/-----BEGIN CERTIFICATE-----/g, "");\n' + ' pem = pem.replace(/-----END CERTIFICATE-----/g, "");\n' + ' pem = pem.replace(/\\s+/g, "");\n' + ' if (!Object.prototype.hasOwnProperty.call(trusted, pem)) return;\n' + ' return trusted[pem];\n' + '}\n' + '\n' + 'function getCert(name) {\n' + ' name = name.replace(/^\s+|\s+$/g, "");\n' + ' if (!Object.prototype.hasOwnProperty.call(certs, name)) return;\n' + ' return certs[name];\n' + '}\n' + '\n' + 'exports.certs = certs;\n' + 'exports.trusted = trusted;\n' + 'exports.getCert = getCert;\n' + 'exports.getTrusted = getTrusted;\n'; return callback(null, body); }); } /** * Helpers */ function request(options, callback) { if (typeof options === 'string' || options.hostname) { options = { uri: options }; } var uri = options.uri || options.url , body = options.json ? JSON.stringify(options.json) : options.body || ''; if (typeof uri !== 'object') { uri = url.parse(uri); } if (options.qs) { var query = uri.query ? qs.parse(uri.query) : {}; Object.keys(options.qs).forEach(function(key) { query[key] = options.qs[key]; }); uri.path = uri.pathname + '?' + qs.stringify(query); } var protocol = uri.protocol === 'https:' ? require('https') : http; options.method = options.method || (body ? 'POST' : 'GET'); options.method = options.method.toUpperCase(); options.headers = options.headers || {}; options.headers['Accept'] = options.headers['Accept'] || 'text/plain; charset=utf-8'; if (options.json) { options.headers['Content-Type'] = 'application/json; charset=utf-8'; options.headers['Accept'] = 'application/json'; } if (options.method !== 'GET' && options.method !== 'HEAD') { options.headers['Content-Length'] = Buffer.byteLength(body); } var opt = { auth: uri.auth, host: uri.hostname, port: uri.port || (protocol === http ? 80 : 443), path: uri.path, method: options.method, headers: options.headers }; var req = protocol.request(opt) , response = new Stream; req.on('error', function(err) { if (callback) { callback(err); } else { response.emit('error', err); } }); req.on('response', function(res) { var decoder = new StringDecoder('utf8') , done = false , body = ''; function end() { if (done) return; done = true; if (callback) { res.body = body; if (options.json) { try { body = JSON.parse(body); } catch (e) { ; } } callback(null, res, body); } else { response.emit('end'); } res.socket.removeListener('error', error); res.socket.removeListener('end', end); } function error(err) { res.destroy(); if (callback) { callback(err); } else { response.emit('error', err); } } res.on('data', function(data) { if (callback) { body += decoder.write(data); } else { response.emit('data', data); } }); res.on('error', error); res.socket.on('error', error); res.on('end', end); // An agent socket's `end` sometimes // wont be emitted on the response. res.socket.on('end', end); }); req.end(body); return response; } /** * Execute */ function main(argv, callback) { if (!callback) { callback = argv; argv = null; } console.log('Retrieving root certs from: %s', certUrl); return getRootCerts(function(err, certs) { var file = path.resolve(__dirname, '..', 'lib', 'common', 'RootCerts.js'); return fs.writeFile(file, certs, function(err) { if (err) return callback(err); console.log('Root cert code generated at: %s.', file); return callback(); }); }); } if (!module.parent) { process.title = 'root-certs'; main(process.argv.slice(), function(err, code) { if (err) throw err; return process.exit(code || 0); }); } else { module.exports = main; }