mirror of
https://github.com/aljazceru/cyphernode.git
synced 2025-12-26 17:15:08 +01:00
126 lines
2.7 KiB
JavaScript
126 lines
2.7 KiB
JavaScript
const fs = require('fs');
|
||
const spawn = require('child_process').spawn;
|
||
const defaultArgs = ['req', '-x509', '-newkey', 'rsa:4096', '-nodes'];
|
||
const path = require('path');
|
||
const tmp = require('tmp');
|
||
const validator = require('validator');
|
||
|
||
const confTmpl = `
|
||
[req]
|
||
distinguished_name = req_distinguished_name
|
||
x509_extensions = v3_ca
|
||
prompt = no
|
||
[req_distinguished_name]
|
||
CN = %PRIMARY_CN%
|
||
[v3_ca]
|
||
subjectAltName = @alt_names
|
||
[alt_names]
|
||
%ALT_DOMAINS%
|
||
%ALT_IPS%
|
||
`;
|
||
|
||
const domainTmpl = 'DNS.%#% = %DOMAIN%';
|
||
const ipTmpl = 'IP.%#% = %IP%';
|
||
|
||
const standardCNs = ['127.0.0.1','localhost','gatekeeper'];
|
||
|
||
module.exports = class Cert {
|
||
|
||
constructor( options ) {
|
||
options = options || {};
|
||
this.args = options.args || { days: 3650 };
|
||
}
|
||
|
||
cns( cnsString ) {
|
||
if( !cnsString ) {
|
||
return standardCNs;
|
||
}
|
||
const cns = cnsString.split(',').map(e=>e.trim().toLowerCase()).filter(e=>!!e);
|
||
|
||
if( cns.length ) {
|
||
return standardCNs.concat(cns);
|
||
}
|
||
return standardCNs;
|
||
}
|
||
|
||
buildConfig( cns ) {
|
||
|
||
let ips = [];
|
||
let domains = [];
|
||
|
||
for( let cn of cns ) {
|
||
if( validator.isIP(cn) ) {
|
||
ips.push( cn );
|
||
} else {
|
||
domains.push( cn );
|
||
}
|
||
}
|
||
|
||
let conf = confTmpl;
|
||
|
||
if( !domains.length ) {
|
||
domains.push('localhost');
|
||
}
|
||
|
||
conf = conf.replace( '%PRIMARY_CN%', domains[0] )
|
||
|
||
let domainCount = 0;
|
||
domains = domains.map( d => domainTmpl.replace( '%#%', ++domainCount ).replace('%DOMAIN%', d) );
|
||
conf = conf.replace( '%ALT_DOMAINS%', domains.join('\n') || '' )
|
||
|
||
let ipCount = 0;
|
||
ips = ips.map( ip => ipTmpl.replace( '%#%', ++ipCount ).replace('%IP%', ip) );
|
||
conf = conf.replace( '%ALT_IPS%', ips.join('\n') || '' )
|
||
|
||
return conf;
|
||
}
|
||
|
||
async create( cns ) {
|
||
if (!cns || !cns.length) {
|
||
throw 'No cns';
|
||
}
|
||
|
||
let args = defaultArgs.slice();
|
||
|
||
const certFileTmp = tmp.fileSync();
|
||
const keyFileTmp = tmp.fileSync();
|
||
const confFileTmp = tmp.fileSync();
|
||
|
||
args.push( '-out' );
|
||
args.push( certFileTmp.name );
|
||
args.push( '-keyout' );
|
||
args.push( keyFileTmp.name );
|
||
args.push( '-config' );
|
||
args.push( confFileTmp.name );
|
||
|
||
for( let k in this.args ) {
|
||
args.push( '-'+k);
|
||
args.push( this.args[k] );
|
||
}
|
||
|
||
const conf = this.buildConfig( cns );
|
||
fs.writeFileSync( confFileTmp.name, conf );
|
||
|
||
|
||
let code = await new Promise( function(resolve, reject) {
|
||
const openssl = spawn('openssl', args, { stdio: ['ignore', 'ignore', 'ignore'] } );
|
||
openssl.on('exit', (code) => {
|
||
resolve(code);
|
||
});
|
||
});
|
||
|
||
const cert = fs.readFileSync( certFileTmp.name );
|
||
const key = fs.readFileSync( keyFileTmp.name );
|
||
|
||
certFileTmp.removeCallback();
|
||
keyFileTmp.removeCallback();
|
||
confFileTmp.removeCallback();
|
||
|
||
return {
|
||
code: code,
|
||
key: key,
|
||
cert: cert
|
||
}
|
||
}
|
||
};
|