Skip to content

Commit

Permalink
feat(Account): Add verify-message command to account module
Browse files Browse the repository at this point in the history
Add validation and specific error for too long messages
Add option `--filePath` to sign/verify using filesystem
Cover by test's
  • Loading branch information
nduchak committed Apr 2, 2020
1 parent 7399377 commit f26de1e
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 9 deletions.
15 changes: 14 additions & 1 deletion bin/aecli-account.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,26 @@ program
//
// You can use this command to sign message
//
// Example: `aecli account sign ./myWalletKeyFile Hello --password testpassword`
// Example: `aecli account sign-message ./myWalletKeyFile Hello --password testpassword`
program
.command('sign-message <wallet_path> [data...]')
.option('--filePath [path]', 'Specify the path to the file for signing(ignore command message argument and use file instead)')
.description('Create a transaction to another wallet')
.action(async (walletPath, data, ...arguments) => await Account.signMessage(walletPath, data, utils.cli.getCmdFromArguments(arguments)))


// ## Initialize `verify-message` command
//
// You can use this command to sign message
//
// Example: `aecli account verify-message ./myWalletKeyFile asd1dasfadfsdasdasdasHexSig... Hello --password testpassword`
program
.command('verify-message <wallet_path> <hexSignature> [data...]')
.option('--filePath [path]', 'Specify the path to the file(ignore comm and message argument and use file instead)')
.description('Create a transaction to another wallet')
.action(async (walletPath, hexSignature, data, ...arguments) => await Account.verifyMessage(walletPath, hexSignature, data, utils.cli.getCmdFromArguments(arguments)))


// ## Initialize `balance` command
//
// You can use this command to retrieve balance of account
Expand Down
45 changes: 38 additions & 7 deletions bin/commands/account.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,23 @@ import { HASH_TYPES } from '../utils/constant'
import { exit, initClientByWalletFile } from '../utils/cli'
import { handleApiError } from '../utils/errors'
import { print, printError, printTransaction, printUnderscored } from '../utils/print'
import { checkPref } from '../utils/helpers'
import { checkPref, readFile } from '../utils/helpers'
import { PROMPT_TYPE, prompt } from '../utils/prompt'

// ## `Sign` function
// this function allow you to `sign` transaction's
// ## `Sign message` function
// this function allow you to `sign` arbitrary data
async function signMessage (walletPath, data = [], options) {
const { json } = options
const { json, filePath } = options
const dataForSign = filePath ? readFile(filePath) : data.reduce((acc, el, i) => `${acc}${i === 0 ? el : ' ' + el}`, '')
try {
// Get `keyPair` by `walletPath`, decrypt using password and initialize `Account` flavor with this `keyPair`
if (dataForSign.length >= 0xFD) throw new Error('Message too long!')
const client = await initClientByWalletFile(walletPath, { ...options, accountOnly: true })
const dataForSign = data.reduce((acc, el, i) => `${acc}${i === 0 ? el : ' ' + el}`, '')
await handleApiError(async () => {
const signedMessage = await client.signMessage(dataForSign)
const address = await client.address()
const result = {
data: dataForSign,
data: typeof dataForSign !== 'string' ? Array.from(dataForSign) : dataForSign,
address,
signature: Array.from(signedMessage),
signatureHex: Buffer.from(signedMessage).toString('hex')
Expand All @@ -63,6 +64,35 @@ async function signMessage (walletPath, data = [], options) {
}
}

// ## `Verify` function
// this function allow you to `verify` signed data
async function verifyMessage (walletPath, hexSignature, data = [], options) {
const { json, filePath } = options
const dataForVerify = filePath ? readFile(filePath) : data.reduce((acc, el, i) => `${acc}${i === 0 ? el : ' ' + el}`, '')
try {
// Get `keyPair` by `walletPath`, decrypt using password and initialize `Account` flavor with this `keyPair`
if (dataForVerify.length >= 0xFD) throw new Error('Message too long!')
const client = await initClientByWalletFile(walletPath, { ...options, accountOnly: true })
await handleApiError(async () => {
const isCorrect = await client.verifyMessage(dataForVerify, hexSignature)
const result = {
data: typeof dataForVerify !== 'string' ? Array.from(dataForVerify) : dataForVerify,
isCorrect
}
if (json) {
print(result)
} else {
printUnderscored('Valid signature', isCorrect)
printUnderscored('Data', dataForVerify)
}
exit()
})
} catch (e) {
printError(e.message)
exit(1)
}
}

// ## `Sign` function
// this function allow you to `sign` transaction's
async function sign (walletPath, tx, options) {
Expand Down Expand Up @@ -327,5 +357,6 @@ export const Account = {
sign,
transferFunds,
generateKeyPairs,
signMessage
signMessage,
verifyMessage
}
35 changes: 34 additions & 1 deletion test/cli/account.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,20 @@ plan(1000000000)

describe.only('CLI Account Module', function () {
configure(this)

let sig
let sigFromFile
const fileName = 'testData'
const fileData = 'Hello world!'
let wallet

before(async function () {
// Spend tokens for wallet
fs.writeFileSync(fileName, fileData)
wallet = await ready(this)
})
after(function () {
// Remove wallet files
if (fs.existsSync(fileName)) { fs.unlinkSync(fileName) }
if (fs.existsSync(walletName)) { fs.unlinkSync(walletName) }
if (fs.existsSync(`${walletName}.pub`)) { fs.unlinkSync(`${walletName}.pub`) }
})
Expand Down Expand Up @@ -110,4 +115,32 @@ describe.only('CLI Account Module', function () {
const accounts = JSON.parse(await execute(['account', 'generate', 2, '--forcePrompt', '--json'], { withOutReject: true }))
accounts.length.should.be.equal(2)
})
it('Sign message', async () => {
const data = 'Hello world'
const signedMessage = JSON.parse(await execute(['account', 'sign-message', WALLET_NAME, data, '--json', '--password', 'test'], { withOutReject: false }))
const signedUsingSDK = Array.from(await wallet.signMessage(data))
sig = signedMessage.signatureHex
signedMessage.data.should.be.equal(data)
signedMessage.address.should.be.equal(await wallet.address())
Array.isArray(signedMessage.signature).should.be.equal(true)
signedMessage.signature.toString().should.be.equal(signedUsingSDK.toString())
signedMessage.signatureHex.should.be.a('string')
})
it('Sign message using file', async () => {
const { data, signature, signatureHex, address } = JSON.parse(await execute(['account', 'sign-message', WALLET_NAME, '--json', '--filePath', fileName, '--password', 'test']))
const signedUsingSDK = Array.from(await wallet.signMessage(data))
sigFromFile = signatureHex
signature.toString().should.be.equal(signedUsingSDK.toString())
data.toString().should.be.equal(Array.from(Buffer.from(fileData)).toString())
address.should.be.equal(await wallet.address())
Array.isArray(signature).should.be.equal(true)
signatureHex.should.be.a('string')
})
it('verify message', async () => {
const data = 'Hello world'
const verify = JSON.parse(await execute(['account', 'verify-message', WALLET_NAME, sig ,data, '--json', '--password', 'test'], { withOutReject: false }))
verify.isCorrect.should.be.equal(true)
const verifyFromFile = JSON.parse(await execute(['account', 'verify-message', WALLET_NAME, sigFromFile , '--json', '--password', 'test', '--filePath', fileName], { withOutReject: false }))
verifyFromFile.isCorrect.should.be.equal(true)
})
})

0 comments on commit f26de1e

Please sign in to comment.