Skip to content
Snippets Groups Projects

Wizard key public

Closed ty kayn requested to merge tykayn/duniter:wizard-key-public into dev
1 file
+ 162
158
Compare changes
  • Side-by-side
  • Inline
+ 162
158
@@ -22,164 +22,168 @@ const yaml = require('js-yaml');
export const KeypairDependency = {
duniter: {
methods: {
scrypt: Scrypt
},
cliOptions: [
{ value: '--salt <salt>', desc: 'Salt to generate the keypair' },
{ value: '--passwd <password>', desc: 'Password to generate the keypair' },
{ value: '--keyN <N>', desc: 'Scrypt `N` parameter. Defaults to 4096.', parser: parseInt },
{ value: '--keyr <r>', desc: 'Scrypt `N` parameter. Defaults to 16.', parser: parseInt },
{ value: '--keyp <p>', desc: 'Scrypt `N` parameter. Defaults to 1.', parser: parseInt },
{ value: '--keyprompt', desc: 'Force to use the keypair given by user prompt.' },
{ value: '--keyfile <filepath>', desc: 'Force to use the keypair of the given YAML file. File must contain `pub:` and `sec:` fields.' }
],
wizard: {
'key': promptKey
},
onReset: {
config: (conf:ConfDTO, program:any, logger:any, confDAL:any) => confDAL.coreFS.remove('keyring.yml')
},
cli: [{
name: 'pub',
desc: 'Shows the node public key',
logs: false,
onConfiguredExecute: async (server:Server, conf:ConfDTO) => {
console.log(conf.pair.pub)
}
}, {
name: 'sec',
desc: 'Shows the node secret key',
logs: false,
onConfiguredExecute: async (server:Server, conf:ConfDTO) => {
console.log(conf.pair.sec)
}
}],
config: {
/*****
* Tries to load a specific parameter `conf.pair`
*/
onLoading: async (conf:KeypairConfDTO, program:any, logger:any, confDAL:any) => {
if ((program.keyN || program.keyr || program.keyp) && !(program.salt && program.passwd)) {
throw Error('Missing --salt and --passwd options along with --keyN|keyr|keyp option');
}
// If we have salt and password, convert it to keypair
if (program.salt || program.passwd) {
const salt = program.salt || '';
const key = program.passwd || '';
conf.pair = await Scrypt(salt, key);
}
// If no keypair has been loaded, try the default .yml file
if (!conf.pair || !conf.pair.pub || !conf.pair.sec) {
const ymlContent = await confDAL.coreFS.read('keyring.yml')
conf.pair = yaml.safeLoad(ymlContent);
}
// If no keypair has been loaded or derived from salt/key, generate a random one
if (!conf.pair || !conf.pair.pub || !conf.pair.sec) {
conf.pair = randomKey().json()
}
// With the --keyprompt option, temporarily use a keypair given from CLI prompt (it won't be stored)
if (program.keyprompt) {
// Backup of the current pair
conf.oldPair = {
pub: conf.pair.pub,
sec: conf.pair.sec
};
// Ask the for the session key
await promptKey(conf, program);
}
// With the --keyfile option, temporarily use a keypair given from file system (content won't be stored)
if (program.keyfile) {
// Backup of the current pair
conf.oldPair = {
pub: conf.pair.pub,
sec: conf.pair.sec
};
// Load file content
const doc = yaml.safeLoad(fs.readFileSync(program.keyfile, 'utf8'));
if (!doc || !doc.pub || !doc.sec) {
throw 'Could not load full keyring from file';
}
conf.pair = {
pub: doc.pub,
sec: doc.sec
}
}
},
beforeSave: async (conf:KeypairConfDTO, program:any, logger:any, confDAL:any) => {
if ((program.keyprompt || program.keyfile) && conf.oldPair) {
// Don't store the given key, but only the default/saved one
conf.pair = {
pub: conf.oldPair.pub,
sec: conf.oldPair.sec
};
}
delete conf.oldPair;
// We save the key in a separate file
const keyring = 'pub: "' + conf.pair.pub + '"\n' +
'sec: "' + conf.pair.sec + '"'
await confDAL.coreFS.write('keyring.yml', keyring)
// We never want to store salt, password or keypair in the conf.json file
delete conf.salt;
delete conf.passwd;
delete conf.pair;
}
}
}
duniter: {
methods: {
scrypt: Scrypt
},
cliOptions: [
{value: '--salt <salt>', desc: 'Salt to generate the keypair'},
{value: '--passwd <password>', desc: 'Password to generate the keypair'},
{value: '--keyN <N>', desc: 'Scrypt `N` parameter. Defaults to 4096.', parser: parseInt},
{value: '--keyr <r>', desc: 'Scrypt `N` parameter. Defaults to 16.', parser: parseInt},
{value: '--keyp <p>', desc: 'Scrypt `N` parameter. Defaults to 1.', parser: parseInt},
{value: '--keyprompt', desc: 'Force to use the keypair given by user prompt.'},
{
value: '--keyfile <filepath>',
desc: 'Force to use the keypair of the given YAML file. File must contain `pub:` and `sec:` fields.'
}
],
wizard: {
'key': promptKey
},
onReset: {
config: (conf: ConfDTO, program: any, logger: any, confDAL: any) => confDAL.coreFS.remove('keyring.yml')
},
cli: [{
name: 'pub',
desc: 'Shows the node public key',
logs: false,
onConfiguredExecute: async (server: Server, conf: ConfDTO) => {
console.log(conf.pair.pub)
}
}, {
name: 'sec',
desc: 'Shows the node secret key',
logs: false,
onConfiguredExecute: async (server: Server, conf: ConfDTO) => {
console.log(conf.pair.sec)
}
}],
config: {
/*****
* Tries to load a specific parameter `conf.pair`
*/
onLoading: async (conf: KeypairConfDTO, program: any, logger: any, confDAL: any) => {
if ((program.keyN || program.keyr || program.keyp) && !(program.salt && program.passwd)) {
throw Error('Missing --salt and --passwd options along with --keyN|keyr|keyp option');
}
// If we have salt and password, convert it to keypair
if (program.salt || program.passwd) {
const salt = program.salt || '';
const key = program.passwd || '';
conf.pair = await Scrypt(salt, key);
}
// If no keypair has been loaded, try the default .yml file
if (!conf.pair || !conf.pair.pub || !conf.pair.sec) {
const ymlContent = await confDAL.coreFS.read('keyring.yml')
conf.pair = yaml.safeLoad(ymlContent);
}
// If no keypair has been loaded or derived from salt/key, generate a random one
if (!conf.pair || !conf.pair.pub || !conf.pair.sec) {
conf.pair = randomKey().json()
}
// With the --keyprompt option, temporarily use a keypair given from CLI prompt (it won't be stored)
if (program.keyprompt) {
// Backup of the current pair
conf.oldPair = {
pub: conf.pair.pub,
sec: conf.pair.sec
};
// Ask the for the session key
await promptKey(conf, program);
}
// With the --keyfile option, temporarily use a keypair given from file system (content won't be stored)
if (program.keyfile) {
// Backup of the current pair
conf.oldPair = {
pub: conf.pair.pub,
sec: conf.pair.sec
};
// Load file content
const doc = yaml.safeLoad(fs.readFileSync(program.keyfile, 'utf8'));
if (!doc || !doc.pub || !doc.sec) {
throw 'Could not load full keyring from file';
}
conf.pair = {
pub: doc.pub,
sec: doc.sec
}
}
},
beforeSave: async (conf: KeypairConfDTO, program: any, logger: any, confDAL: any) => {
if ((program.keyprompt || program.keyfile) && conf.oldPair) {
// Don't store the given key, but only the default/saved one
conf.pair = {
pub: conf.oldPair.pub,
sec: conf.oldPair.sec
};
}
delete conf.oldPair;
// We save the key in a separate file
const keyring = 'pub: "' + conf.pair.pub + '"\n' +
'sec: "' + conf.pair.sec + '"'
await confDAL.coreFS.write('keyring.yml', keyring)
// We never want to store salt, password or keypair in the conf.json file
delete conf.salt;
delete conf.passwd;
delete conf.pair;
}
}
}
};
async function promptKey (conf:KeypairConfDTO, program:any) {
const changeKeypair = !conf.pair || !conf.pair.pub || !conf.pair.sec;
const answersWantToChange = await inquirer.prompt([{
type: "confirm",
name: "change",
message: "Modify your keypair?",
default: changeKeypair
}]);
if (answersWantToChange.change) {
const obfuscatedSalt = (program.salt || "").replace(/./g, '*');
const answersSalt = await inquirer.prompt([{
type: "password",
name: "salt",
message: "Key's salt",
default: obfuscatedSalt || undefined
}]);
const obfuscatedPasswd = (program.passwd || "").replace(/./g, '*');
const answersPasswd = await inquirer.prompt([{
type: "password",
name: "passwd",
message: "Key\'s password",
default: obfuscatedPasswd || undefined
}]);
const keepOldSalt = obfuscatedSalt.length > 0 && obfuscatedSalt == answersSalt.salt;
const keepOldPasswd = obfuscatedPasswd.length > 0 && obfuscatedPasswd == answersPasswd.passwd;
const salt = keepOldSalt ? program.salt : answersSalt.salt;
const passwd = keepOldPasswd ? program.passwd : answersPasswd.passwd;
conf.pair = await Scrypt(salt, passwd)
}
async function promptKey(conf: KeypairConfDTO, program: any) {
const changeKeypair = !conf.pair || !conf.pair.pub || !conf.pair.sec;
const answersWantToChange = await inquirer.prompt([{
type: "confirm",
name: "change",
message: `This node's current public key is: ${conf.pair.pub}
Modify your keypair?`,
default: changeKeypair
}]);
if (answersWantToChange.change) {
const obfuscatedSalt = (program.salt || "").replace(/./g, '*');
const answersSalt = await inquirer.prompt([{
type: "password",
name: "salt",
message: "Key's salt",
default: obfuscatedSalt || undefined
}]);
const obfuscatedPasswd = (program.passwd || "").replace(/./g, '*');
const answersPasswd = await inquirer.prompt([{
type: "password",
name: "passwd",
message: "Key\'s password",
default: obfuscatedPasswd || undefined
}]);
const keepOldSalt = obfuscatedSalt.length > 0 && obfuscatedSalt == answersSalt.salt;
const keepOldPasswd = obfuscatedPasswd.length > 0 && obfuscatedPasswd == answersPasswd.passwd;
const salt = keepOldSalt ? program.salt : answersSalt.salt;
const passwd = keepOldPasswd ? program.passwd : answersPasswd.passwd;
conf.pair = await Scrypt(salt, passwd)
}
}
Loading