added support for api key generation

This commit is contained in:
jash
2018-10-21 16:15:01 +02:00
committed by kexkey
parent 6972b811d9
commit ec10e8dc1e
4 changed files with 172 additions and 3 deletions

View File

@@ -8,6 +8,7 @@ const path = require("path");
const featureChoices = require(path.join(__dirname, "features.json"));
const coinstring = require('coinstring');
const Archive = require('./lib/archive.js');
const ApiKey = require('./lib/apikey.js');
const uaCommentRegexp = /^[a-zA-Z0-9 \.,:_\-\?\/@]+$/; // TODO: look for spec of unsafe chars
const userRegexp = /^[a-zA-Z0-9\._\-]+$/;
@@ -163,6 +164,9 @@ module.exports = class extends Generator {
return;
}
// save auth key password to check if it changed
this.auth_clientkeyspassword = this.props.auth_clientkeyspassword;
let prompts = [];
for( let m of prompters ) {
prompts = prompts.concat(m.prompts(this));
@@ -173,12 +177,46 @@ module.exports = class extends Generator {
});
}
writing() {
const configJsonString = JSON.stringify(this.props);
async configuring() {
if( this.props.auth_recreatekeys || !this.props.auth_keys ) {
delete this.props.auth_recreatekeys;
const apikey = new ApiKey();
let configEntries = [];
let clientInformation = [];
apikey.setId('001');
apikey.setGroups(['watcher']);
await apikey.randomiseKey();
configEntries.push(apikey.getConfigEntry());
clientInformation.push(apikey.getClientInformation());
apikey.setId('002');
apikey.setGroups(['watcher','spender']);
await apikey.randomiseKey();
configEntries.push(apikey.getConfigEntry());
clientInformation.push(apikey.getClientInformation());
apikey.setId('003');
apikey.setGroups(['watcher','spender','admin']);
await apikey.randomiseKey();
configEntries.push(apikey.getConfigEntry());
clientInformation.push(apikey.getClientInformation());
this.props.auth_keys = {
configEntries: configEntries,
clientInformation: clientInformation
}
}
}
async writing() {
const configJsonString = JSON.stringify(this.props, null, 4);
const archive = new Archive( this.destinationPath('config.7z'), this.configurationPassword );
if( !archive.writeEntry( 'config.json', configJsonString ) ) {
console.log(chalk.bold.red( 'error! config archive was not written' ));
console.log(chalk.bold.red( 'error! Config archive was not written' ));
}
for( let m of prompters ) {
@@ -192,6 +230,19 @@ module.exports = class extends Generator {
);
}
}
if( this.props.auth_keys && this.props.auth_keys.clientInformation ) {
if( this.auth_clientkeyspassword !== this.props.auth_clientkeyspassword ) {
fs.unlinkSync( this.destinationPath('clientKeys.7z') );
}
const archive = new Archive( this.destinationPath('clientKeys.7z'), this.props.auth_clientkeyspassword );
if( !archive.writeEntry( 'keys.txt', this.props.auth_keys.clientInformation.join('\n') ) ) {
console.log(chalk.bold.red( 'error! Client auth key archive was not written' ));
}
}
}
install() {
@@ -199,6 +250,10 @@ module.exports = class extends Generator {
/* some utils */
_clientAuthKeysArchiveExists() {
return fs.existsSync( this.destinationPath('clientKeys.7z') );
}
_assignConfigDefaults( props ) {
props.derivation_path = this.props.derivation_path || '0/n';
props.installer = this.props.installer ||  'docker';

View File

@@ -0,0 +1,76 @@
const spawn = require('child_process').spawn;
module.exports = class ApiKey {
constructor( id, groups, key, script ) {
this.setId(id || '001');
this.setGroups(groups || ['admin'] );
this.setScript(script || 'eval ugroups_${kapi_id}=${kapi_groups};eval ukey_${kapi_id}=${kapi_key}' );
this.setKey(key);
}
setGroups( groups ) {
this.groups = groups;
}
setId( id ) {
this.id = id;
}
setScript( script ) {
this.script = script;
}
setKey( key ) {
this.key = key;
}
async randomiseKey() {
try {
//const dd = spawn('/bin/dd if=/dev/urandom bs=32 count=1 | /usr/bin/xxd -pc 32');
const dd = spawn("dd if=/dev/urandom bs=32 count=1 | xxd -pc32", [], {stdio: ['ignore', 'pipe', 'ignore' ], shell: true} );
const result = await new Promise( function(resolve, reject ) {
let result = '';
dd.stdout.on('data', function( a,b,c) {
let chunk = a.toString().trim();
result += chunk;
});
dd.stdout.on('end', function() {
result = result.replace(/[^a-zA-Z0-9]/,'');
resolve(result);
});
dd.stdout.on('error', function(err) {
console.log(err);
reject(err);
})
});
this.key = result;
} catch( err ) {
console.log( err );
return;
}
}
getKey() {
return this.key;
}
getConfigEntry() {
if( !this.key ) {
return;
}
return `kapi_id="${this.id}";kapi_key="${this.key}";kapi_groups="${this.groups.join(',')}";${this.script}`;
}
getClientInformation() {
return `${this.id}=${this.key}`;
}
}
//dd if=/dev/urandom bs=32 count=1 2> /dev/null | xxd -pc 32

View File

@@ -0,0 +1,37 @@
const chalk = require('chalk');
const name = 'authentication';
const capitalise = function( txt ) {
return txt.charAt(0).toUpperCase() + txt.substr(1);
};
const prefix = function() {
return chalk.bold.red(capitalise(name)+': ');
};
module.exports = {
name: function() {
return name;
},
prompts: function( utils ) {
// TODO: delete clientKeys archive when password chnages
return [{
type: 'password',
name: 'auth_clientkeyspassword',
default: utils._getDefault( 'auth_clientkeyspassword' ),
message: prefix()+'Enter a password to protect your client keys with'+'\n',
filter: utils._trimFilter,
validate: utils._notEmptyValidator
},
{
type: 'confirm',
name: 'auth_recreatekeys',
default: false,
message: prefix()+'Recreate auth keys?'+'\n'
}];
},
templates: function( props ) {
return [ 'keys.properties' ];
}
};

View File

@@ -0,0 +1 @@
<%- auth_keys.configEntries.join('\n') %>