From a05e1ba48e4b7ec41bcdecb62dcf0d9e4fe3e86b Mon Sep 17 00:00:00 2001 From: Kgothatso Date: Sun, 1 Dec 2019 00:08:28 +0200 Subject: [PATCH] Add sign command which can perform actions --- lib/commands/sign.js | 57 +++++++++++++++++++++++++++++ lib/core/logic/authentication.js | 60 +++++++++++++++++++++++++++++++ lib/core/logic/register.js | 62 ++++++++++++++++++++++++++++++++ 3 files changed, 179 insertions(+) create mode 100644 lib/commands/sign.js create mode 100644 lib/core/logic/authentication.js create mode 100644 lib/core/logic/register.js diff --git a/lib/commands/sign.js b/lib/commands/sign.js new file mode 100644 index 0000000..674256a --- /dev/null +++ b/lib/commands/sign.js @@ -0,0 +1,57 @@ +const registrationLogic = require('../core/logic/register'); +const authenticationLogic = require('../core/logic/authentication'); + + +module.exports.description = "Sign message/challenge." + +module.exports.builder = (yargs) => { + return yargs + .usage(`Usage: $0 sign [options]`) + .help(false) + .version(false) + .option('challenge', { + describe: 'Challenge to sign', + type: 'string' + }) + .demandOption(['challenge']) + .argv; +} + +module.exports.handler = (argv) => { + console.log("Sign challenge."); + + const challengeArgument = argv["challenge"].js || argv["challenge"]; + + const challenge = JSON.parse(challengeArgument); + // Parse Action + try { + const request = JSON.parse(challenge.message); + + if(request.action != undefined) { + switch(request.action) { + case "register": + // Ask user if they want to register with service + registrationLogic.registration(challenge, request); + break; + case "authenticate": + // Ask user if they want to authenticate with service + authenticationLogic.authenticate(challenge, request, argv) + break; + default: + // Tell user that action is unsupported + // ask if they want to sign regardless if they want to continue any way. + break; + } + } else { + // No action provided... should just sign + console.log("No action required."); + } + // TODO: Validate lock-definition is of the correct format... + + } catch(e) { + // Should just be signed... + console.error("challenge.messsage isn't json Object") + } + + +} \ No newline at end of file diff --git a/lib/core/logic/authentication.js b/lib/core/logic/authentication.js new file mode 100644 index 0000000..943fb02 --- /dev/null +++ b/lib/core/logic/authentication.js @@ -0,0 +1,60 @@ +const persistence = require("../persistence/persistence"); +const cryptoUtil = require("../cryptoUtil"); + +module.exports.authenticate = function(challenge, authenticationRequest, argv) { + persistence().LoadDB() + .then(db => { + const url = argv.url || authenticationRequest.url; + const userIdentifier = argv.userIdentifier || authenticationRequest.userIdentifier; + // TODO validate lock definition has all the parameters we need + // TODO: validate serviceExtendedPublicKey + console.log("Looking for"); + console.log("url: ", url); + console.log("userIdentifier: ", userIdentifier); + + return db.Lock.findOne({ + where: { + url: url, + userIdentifier: userIdentifier + }, + include: [ + { + association: db.Lock.ExtendedPublicKey, + require: true, + include: [ + { + association: db.ExtendedPublicKey.Key, // TODO rename key to wallet + required: true + } + ] + } + ] + }) + .then(lock => { + if(lock) { + // Sign the message with the key that corresponds with this lock... + const verification = cryptoUtil.verifyChallenge( + lock.serviceExtendedPublicKey, + challenge + ); + + if (verification) { + const encryptedKey = lock.extendedPublicKey.key.encryptedPrivateKey; + const iv = lock.extendedPublicKey.key.iv; + const password = "vanished"; + const walletXpriv = cryptoUtil.decrypt(encryptedKey, password, iv); + + var challengeDerivationPath = `${lock.extendedPublicKey.derivationPath}/${challenge.derivationPath.split("c/")[1]}`; + + const signature = cryptoUtil.signMessage(walletXpriv, challengeDerivationPath, challenge.message) + console.log("Signature: ", signature.toString('hex')); + } else { + console.error("Challenge not signed by registered service."); + } + + } else { + console.error("Failed to find a lock with these parameters"); + } + }) + }) +} diff --git a/lib/core/logic/register.js b/lib/core/logic/register.js new file mode 100644 index 0000000..33d16f0 --- /dev/null +++ b/lib/core/logic/register.js @@ -0,0 +1,62 @@ +const persistence = require("../persistence/persistence"); +const cryptoUtil = require("../cryptoUtil"); + +module.exports.registration = function(challenge, registerationRequest) { + persistence().LoadDB() + .then(db => { + // TODO validate lock definition has all the parameters we need + // TODO: validate serviceExtendedPublicKey + const verification = cryptoUtil.verifyChallenge( + registerationRequest.serviceExtendedPublicKey, + challenge + ); + if(verification) { + return db.ExtendedPublicKey.findOne({ + where: { + xpub: challenge.xpub + }, + include: [ + { + association: db.ExtendedPublicKey.Key // TODO: update this to wallet + } + ] + }).then(extendedPublicKey => { + if (extendedPublicKey) { + const encryptedKey = extendedPublicKey.key.encryptedPrivateKey; + const iv = extendedPublicKey.key.iv; + const password = "vanished"; + const walletXpriv = cryptoUtil.decrypt(encryptedKey, password, iv); + + var challengeDerivationPath = `${extendedPublicKey.derivationPath}/${challenge.derivationPath.split("c/")[1]}`; + + const signature = cryptoUtil.signMessage(walletXpriv, challengeDerivationPath, challenge.message) + + + // TODO: save lock + return db.Lock.create({ + userIdentifier: registerationRequest.userIdentifier, + url: registerationRequest.url, + serviceExtendedPublicKey: registerationRequest.serviceExtendedPublicKey, + signature: signature.toString('hex'), + message: challenge.message, + extendedPublicKeyId: extendedPublicKey.id + }) + } else { + console.error("Sorry we can't create a lock with xpub: ", challenge.xpub); + return null; + } + }).then(lock => { + if(lock) { + console.log("Lock: ", lock.id); + console.log("Signature: ", lock.signature); + } else { + console.error("Failed to create the lock."); + } + + }) + } else { + console.error("Challenge not signed by service"); + } + + }) +}