From d35b2766ab45a210035a750157dda5a9d646f0a6 Mon Sep 17 00:00:00 2001 From: jash Date: Fri, 2 Nov 2018 20:48:28 +0100 Subject: [PATCH] added creation of gatekeeper certs. cert is also added to clientKeys.7z to be used with curl or some other web browser. Using this cert on the client will prevent man in the middle attacks --- dist/setup.sh | 12 +++- install/Dockerfile | 2 +- .../generators/app/index.js | 39 ++++++++++++- .../generators/app/lib/cert.js | 56 +++++++++++++++++++ .../app/prompters/010_gatekeeper.js | 9 ++- .../app/templates/gatekeeper/cert.pem | 1 + .../app/templates/gatekeeper/key.pem | 1 + 7 files changed, 114 insertions(+), 6 deletions(-) create mode 100644 install/generator-cyphernode/generators/app/lib/cert.js create mode 100644 install/generator-cyphernode/generators/app/templates/gatekeeper/cert.pem create mode 100644 install/generator-cyphernode/generators/app/templates/gatekeeper/key.pem diff --git a/dist/setup.sh b/dist/setup.sh index 9ed8b9d..8fca0c6 100755 --- a/dist/setup.sh +++ b/dist/setup.sh @@ -116,7 +116,7 @@ echo ' modify_permissions() { - local directories=("installer" "gatekeeper" "lightning" "bitcoin" "docker-compose.yaml") + local directories=("installer" "gatekeeper" "lightning" "bitcoin" "docker-compose.yaml $BITCOIN_DATAPATH" "$LIGHTNING_DATAPATH" "$PROXY_DATAPATH" "$GATEKEEPER_DATAPATH") for d in "${directories[@]}" do if [[ -e $d ]]; then @@ -282,9 +282,19 @@ install_docker() { fi if [ -d $GATEKEEPER_DATAPATH ]; then + if [[ ! -d $GATEKEEPER_DATAPATH/certs ]]; then + mkdir $GATEKEEPER_DATAPATH/certs + fi + + if [[ ! -d $GATEKEEPER_DATAPATH/private ]]; then + mkdir $GATEKEEPER_DATAPATH/private + fi + copy_file $sourceDataPath/gatekeeper/api.properties $GATEKEEPER_DATAPATH/api.properties 1 ${sudo} copy_file $sourceDataPath/gatekeeper/keys.properties $GATEKEEPER_DATAPATH/keys.properties 1 ${sudo} copy_file $sourceDataPath/gatekeeper/ip-whitelist.conf $GATEKEEPER_DATAPATH/ip-whitelist.conf 1 ${sudo} + copy_file $sourceDataPath/gatekeeper/cert.pem $GATEKEEPER_DATAPATH/certs/cert.pem 1 ${sudo} + copy_file $sourceDataPath/gatekeeper/key.pem $GATEKEEPER_DATAPATH/private/key.pem 1 ${sudo} fi if [ ! -d $PROXY_DATAPATH ]; then diff --git a/install/Dockerfile b/install/Dockerfile index eb4ff04..182f6d6 100644 --- a/install/Dockerfile +++ b/install/Dockerfile @@ -1,6 +1,6 @@ FROM node:alpine -RUN apk add --update bash su-exec p7zip nano && rm -rf /var/cache/apk/* +RUN apk add --update bash su-exec p7zip openssl && rm -rf /var/cache/apk/* RUN mkdir -p /app RUN mkdir /.config RUN chmod a+rwx /.config diff --git a/install/generator-cyphernode/generators/app/index.js b/install/generator-cyphernode/generators/app/index.js index bdf822b..00c0aed 100644 --- a/install/generator-cyphernode/generators/app/index.js +++ b/install/generator-cyphernode/generators/app/index.js @@ -8,6 +8,7 @@ const path = require("path"); const coinstring = require('coinstring'); const Archive = require('./lib/archive.js'); const ApiKey = require('./lib/apikey.js'); +const Cert = require('./lib/cert.js'); const featureChoices = require('./features.json'); const uaCommentRegexp = /^[a-zA-Z0-9 \.,:_\-\?\/@]+$/; // TODO: look for spec of unsafe chars @@ -220,7 +221,6 @@ module.exports = class extends Generator { async configuring() { if( this.props.gatekeeper_recreatekeys || this.props.gatekeeper_keys.configEntries.length===0 ) { - delete this.props.gatekeeper_recreatekeys; const apikey = new ApiKey(); let configEntries = []; @@ -248,7 +248,29 @@ module.exports = class extends Generator { configEntries: configEntries, clientInformation: clientInformation } - } + } + + if( this.props.gatekeeper_recreatecert || + !this.props.gatekeeper_sslcert || + !this.props.gatekeeper_sslkey ) { + const cert = new Cert(); + console.log(chalk.bold.green( '☕ Generating gatekeeper cert. This may take a while ☕' )); + try { + const result = await cert.create(); + if( result.code === 0 ) { + this.props.gatekeeper_sslkey = result.key.toString(); + this.props.gatekeeper_sslcert = result.cert.toString(); + } else { + console.log(chalk.bold.red( 'error! Gatekeeper cert was not created' )); + } + } catch( err ) { + console.log(chalk.bold.red( 'error! Gatekeeper cert was not created' )); + } + } + + delete this.props.gatekeeper_recreatecert; + delete this.props.gatekeeper_recreatekeys; + } async writing() { @@ -282,6 +304,9 @@ module.exports = class extends Generator { if( !await archive.writeEntry( 'keys.txt', this.props.gatekeeper_keys.clientInformation.join('\n') ) ) { console.log(chalk.bold.red( 'error! Client gatekeeper key archive was not written' )); } + if( !await archive.writeEntry( 'cacert.pem', this.props.gatekeeper_sslcert ) ) { + console.log(chalk.bold.red( 'error! Client gatekeeper key archive was not written' )); + } } } @@ -298,6 +323,12 @@ module.exports = class extends Generator { this.props.gatekeeper_keys.configEntries.length > 0; } + _hasCert() { + return this.props && + this.props.gatekeeper_sslkey && + this.props.gatekeeper_sslcert + } + _assignConfigDefaults() { this.props = Object.assign( { features: [], @@ -326,7 +357,9 @@ module.exports = class extends Generator { lightning_implementation: 'c-lightning', lightning_datapath: '', lightning_nodename: '', - lightning_nodecolor: '' + lightning_nodecolor: '', + gatekeeper_sslcert: '', + gatekeeper_sslkey: '' }, this.props ); this.props.default_username = process.env.DEFAULT_USER || ''; } diff --git a/install/generator-cyphernode/generators/app/lib/cert.js b/install/generator-cyphernode/generators/app/lib/cert.js new file mode 100644 index 0000000..7108dab --- /dev/null +++ b/install/generator-cyphernode/generators/app/lib/cert.js @@ -0,0 +1,56 @@ +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'); + +module.exports = class Cert { + + constructor( options ) { + options = options || {}; + this.args = options.args || { subj: '/CN=localhost', days: 3650 }; + } + + async create() { + + let args = defaultArgs.slice(); + + const certFileTmp = tmp.fileSync(); + const keyFileTmp = tmp.fileSync(); + + args.push( '-out' ); + args.push( certFileTmp.name ); + args.push( '-keyout' ); + args.push( keyFileTmp.name ); + + for( let k in this.args ) { + args.push( '-'+k); + args.push( this.args[k] ); + } + + const openssl = spawn('openssl', args, { stdio: ['ignore','ignore','ignore'] } ); + + let code = await new Promise( function(resolve, reject) { + openssl.on('exit', (code) => { + resolve(code); + }); + }); + + const cert = fs.readFileSync( certFileTmp.name ); + const key = fs.readFileSync( keyFileTmp.name ); + + certFileTmp.removeCallback(); + keyFileTmp.removeCallback(); + + return { + code: code, + key: key, + cert: cert + } + } + + getFullPath() { + return path.join( this.folder, this.filename ); + } + +} diff --git a/install/generator-cyphernode/generators/app/prompters/010_gatekeeper.js b/install/generator-cyphernode/generators/app/prompters/010_gatekeeper.js index 3f0beb7..ad6cabb 100644 --- a/install/generator-cyphernode/generators/app/prompters/010_gatekeeper.js +++ b/install/generator-cyphernode/generators/app/prompters/010_gatekeeper.js @@ -31,6 +31,13 @@ module.exports = { default: false, message: prefix()+'Recreate gatekeeper keys?'+utils._getHelp('gatekeeper_recreatekeys') }, + { + when: utils._hasCert, + type: 'confirm', + name: 'gatekeeper_recreatecert', + default: false, + message: prefix()+'Recreate gatekeeper ssl cert?'+utils._getHelp('gatekeeper_recreatecert') + }, { type: 'confirm', name: 'gatekeeper_edit_ipwhitelist', @@ -67,6 +74,6 @@ module.exports = { }]; }, templates: function( props ) { - return [ 'keys.properties', 'api.properties', 'ip-whitelist.conf' ]; + return [ 'keys.properties', 'api.properties', 'ip-whitelist.conf', 'cert.pem', 'key.pem' ]; } }; \ No newline at end of file diff --git a/install/generator-cyphernode/generators/app/templates/gatekeeper/cert.pem b/install/generator-cyphernode/generators/app/templates/gatekeeper/cert.pem new file mode 100644 index 0000000..a1bab17 --- /dev/null +++ b/install/generator-cyphernode/generators/app/templates/gatekeeper/cert.pem @@ -0,0 +1 @@ +<%- gatekeeper_sslcert %> \ No newline at end of file diff --git a/install/generator-cyphernode/generators/app/templates/gatekeeper/key.pem b/install/generator-cyphernode/generators/app/templates/gatekeeper/key.pem new file mode 100644 index 0000000..affc9b4 --- /dev/null +++ b/install/generator-cyphernode/generators/app/templates/gatekeeper/key.pem @@ -0,0 +1 @@ +<%- gatekeeper_sslkey %> \ No newline at end of file