Skip to content
This repository has been archived by the owner on Jul 23, 2024. It is now read-only.

Commit

Permalink
Merge pull request #365 from klaytn/release/v1.5.2
Browse files Browse the repository at this point in the history
[Master] release/v1.5.2 QA Sign-off
  • Loading branch information
jimni1222 authored Oct 23, 2020
2 parents 1300c8f + e2cffed commit 1baaaf7
Show file tree
Hide file tree
Showing 12 changed files with 129 additions and 33 deletions.
1 change: 1 addition & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ function Caver(provider, net) {
}

Caver.utils = utils
Caver.abi = abi
Caver.providers = providers

module.exports = Caver
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "caver-js",
"version": "1.5.1",
"version": "1.5.2",
"description": "caver-js is a JavaScript API library that allows developers to interact with a Klaytn node",
"main": "index.js",
"scripts": {
Expand Down
1 change: 1 addition & 0 deletions packages/caver-core-helpers/src/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ const txErrorTable = {

module.exports = {
InvalidConnection: host => new Error(`CONNECTION ERROR: Couldn't connect to node ${host}.`),
RequestFailed: err => new Error(`Request failed: ${err}`),
ConnectionTimeout: ms => new Error(`CONNECTION TIMEOUT: timeout of ${ms}ms achived`),
ConnectionNotOpenError: event => {
const error = new Error('connection not open on send()')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,12 @@ HttpProvider.prototype.send = function(payload, callback) {
try {
result = JSON.parse(result)
} catch (e) {
console.error(`Invalid JSON RPC response: ${JSON.stringify(request.responseText)}`)
error = errors.InvalidResponse(request.responseText)
if (request.responseText === '') {
error = errors.RequestFailed(request.statusText)
} else {
console.error(`Invalid JSON RPC response: ${JSON.stringify(request.responseText)}`)
error = errors.InvalidResponse(request.responseText)
}
}
}

Expand Down
8 changes: 4 additions & 4 deletions packages/caver-klay/caver-klay-accounts/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -263,9 +263,9 @@ function encryptKey(privateKey, password, options) {
throw new Error('Unsupported cipher')
}

const ciphertext = Buffer.concat([cipher.update(Buffer.from(privateKeyArray[i].replace('0x', ''), 'hex')), cipher.final()])
const ciphertext = Buffer.from([...cipher.update(Buffer.from(privateKeyArray[i].replace('0x', ''), 'hex')), ...cipher.final()])

const mac = utils.sha3(Buffer.concat([derivedKey.slice(16, 32), Buffer.from(ciphertext, 'hex')])).replace('0x', '')
const mac = utils.sha3(Buffer.from([...derivedKey.slice(16, 32), ...ciphertext])).replace('0x', '')

encryptedArray.push({
ciphertext: ciphertext.toString('hex'),
Expand Down Expand Up @@ -1473,13 +1473,13 @@ Accounts.prototype.decrypt = function(v3Keystore, password, nonStrict) {

const ciphertext = Buffer.from(encrypted.ciphertext, 'hex')

const mac = utils.sha3(Buffer.concat([derivedKey.slice(16, 32), ciphertext])).replace('0x', '')
const mac = utils.sha3(Buffer.from([...derivedKey.slice(16, 32), ...ciphertext])).replace('0x', '')
if (mac !== encrypted.mac) {
throw new Error('Key derivation failed - possibly wrong password')
}

const decipher = cryp.createDecipheriv(encrypted.cipher, derivedKey.slice(0, 16), Buffer.from(encrypted.cipherparams.iv, 'hex'))
decryptedArray.push(`0x${Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString('hex')}`)
decryptedArray.push(`0x${Buffer.from([...decipher.update(ciphertext), ...decipher.final()]).toString('hex')}`)
}
return decryptedArray.length === 1 ? decryptedArray[0] : decryptedArray
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,27 @@ class AbstractTransaction {
this._signatures = refineSignatures(sigs, this.type === TX_TYPE_STRING.TxTypeLegacyTransaction)
}

/**
* Returns the RLP-encoded string of this transaction (i.e., rawTransaction).
* This method has to be overrided in classes which extends AbstractTransaction.
*
* @return {string}
*/
getRLPEncoding() {
throw new Error(`Not implemented.`)
}

/**
* Returns the RLP-encoded string to make the signature of this transaction.
* This method has to be overrided in classes which extends AbstractTransaction.
* getCommonRLPEncodingForSignature is used in getRLPEncodingForSignature.
*
* @return {string}
*/
getCommonRLPEncodingForSignature() {
throw new Error(`Not implemented.`)
}

/**
* Signs to the transaction with private key(s) in the `key`.
* @async
Expand Down Expand Up @@ -288,18 +309,6 @@ class AbstractTransaction {
return RLP.encode([this.getCommonRLPEncodingForSignature(), Bytes.fromNat(this.chainId), '0x', '0x'])
}

/**
* Returns the RLP-encoded string to make the signature of this transaction.
* This method has to be overrided in classes which extends AbstractTransaction.
* getCommonRLPEncodingForSignature is used in getRLPEncodingForSignature.
*
* @return {string}
*/
// eslint-disable-next-line class-methods-use-this
getCommonRLPEncodingForSignature() {
throw new Error('getCommonRLPEncodingForSignature has to be implemented')
}

/**
* Fills empty optional transaction properties(gasPrice, nonce, chainId).
*/
Expand Down
8 changes: 7 additions & 1 deletion packages/caver-utils/src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -714,6 +714,7 @@ const xyPointFromPublicKey = pub => {
if (isCompressedPublicKey(publicKey)) publicKey = decompressPublicKey(pub)

publicKey = publicKey.replace('0x', '')
if (publicKey.length === 130 && publicKey.slice(0, 2) === '04') publicKey = publicKey.slice(2)
if (publicKey.length !== 128) throw Error('Invalid public key') // + 2 means '0x'

const pubX = `0x${publicKey.slice(0, 64).replace(/^0+/, '')}`
Expand Down Expand Up @@ -851,6 +852,8 @@ const getTxTypeStringFromRawTransaction = rawTransaction => {
const isValidPublicKey = publicKey => {
let pubString = publicKey.replace('0x', '')

if (pubString.length === 130 && pubString.slice(0, 2) === '04') pubString = pubString.slice(2)

if (pubString.length !== 66 && pubString.length !== 128) return false

if (pubString.length === 66 && !isCompressedPublicKey(pubString)) return false
Expand Down Expand Up @@ -897,7 +900,10 @@ const compressPublicKey = uncompressedPublicKey => {
}

const decompressPublicKey = compressedPublicKey => {
if (!isCompressedPublicKey(compressedPublicKey)) return compressedPublicKey
if (!isCompressedPublicKey(compressedPublicKey)) {
if (!isValidPublicKey(compressedPublicKey)) throw new Error(`Invalid public key`)
return compressedPublicKey
}

const compressedWithoutPrefix = compressedPublicKey.replace('0x', '')

Expand Down
44 changes: 42 additions & 2 deletions packages/caver-wallet/src/keyring/abstractKeyring.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,53 @@ class AbstractKeyring {
this._address = utils.addHexPrefix(addressInput).toLowerCase()
}

/**
* signs with transactionHash with a key and returns signature(s).
* This method has to be overrided in classes which extends AbstractKeyring.
*
* @return {Array.<string>|Array.<Array.<string>>}
*/
sign(transactionHash, chainId, role, index) {
throw new Error(`Not implemented.`)
}

/**
* signs with hashed message and returns result object that includes `signatures`, `message` and `messageHash`.
* This method has to be overrided in classes which extends AbstractKeyring.
*
* @return {object}
*/
signMessage(message, role, index) {
throw new Error(`Not implemented.`)
}

/**
* encrypts a keyring and returns a keystore v4 object.
* This method has to be overrided in classes which extends AbstractKeyring.
*
* @return {object}
*/
encrypt(password, options = {}) {
throw new Error(`Not implemented.`)
}

/**
* returns a copied singleKeyring instance.
* This method has to be overrided in classes which extends AbstractKeyring.
*
* @return {AbstractKeyring}
*/
copy() {
throw new Error(`Not implemented.`)
}

/**
* returns KlaytnWalletKey format. If keyring uses more than one private key, this function will throw error.
*
* @return {string}
*/
getKlaytnWalletKey() {
throw new Error(`The keyring cannot be exported in KlaytnWalletKey format. Use keyring.encrypt.`)
throw new Error(`Not supported for this class.`)
}

/**
Expand All @@ -63,7 +103,7 @@ class AbstractKeyring {
* @return {object}
*/
encryptV3(password, options) {
throw new Error(`This keyring cannot be encrypted keystore v3. use 'keyring.encrypt(password)'.`)
throw new Error(`Not supported for this class. Use 'keyring.encrypt(password)'.`)
}

/**
Expand Down
14 changes: 7 additions & 7 deletions packages/caver-wallet/src/keyring/keyringHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const scrypt = require('scrypt-js')
const uuid = require('uuid')
const cryp = typeof global === 'undefined' ? require('crypto-browserify') : require('crypto')
const utils = require('../../../caver-utils')
const PrivateKey = require('./privateKey')

const KEY_ROLE = {
roleTransactionKey: 0,
Expand Down Expand Up @@ -102,13 +103,13 @@ const decryptKey = (encryptedArray, password) => {

const ciphertext = Buffer.from(encrypted.ciphertext, 'hex')

const mac = utils.sha3(Buffer.concat([derivedKey.slice(16, 32), ciphertext])).replace('0x', '')
const mac = utils.sha3(Buffer.from([...derivedKey.slice(16, 32), ...ciphertext])).replace('0x', '')
if (mac !== encrypted.mac) {
throw new Error('Key derivation failed - possibly wrong password')
}

const decipher = cryp.createDecipheriv(encrypted.cipher, derivedKey.slice(0, 16), Buffer.from(encrypted.cipherparams.iv, 'hex'))
decryptedArray.push(`0x${Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString('hex')}`)
decryptedArray.push(`0x${Buffer.from([...decipher.update(ciphertext), ...decipher.final()]).toString('hex')}`)
}
return decryptedArray
}
Expand Down Expand Up @@ -162,12 +163,11 @@ const encryptKey = (privateKey, password, options) => {
throw new Error('Unsupported cipher')
}

const ciphertext = Buffer.concat([
cipher.update(Buffer.from(privateKeyArray[i].privateKey.replace('0x', ''), 'hex')),
cipher.final(),
])
let prv = privateKeyArray[i]
if (privateKeyArray[i] instanceof PrivateKey) prv = privateKeyArray[i].privateKey
const ciphertext = Buffer.from([...cipher.update(Buffer.from(prv.replace('0x', ''), 'hex')), ...cipher.final()])

const mac = utils.sha3(Buffer.concat([derivedKey.slice(16, 32), Buffer.from(ciphertext, 'hex')])).replace('0x', '')
const mac = utils.sha3(Buffer.from([...derivedKey.slice(16, 32), ...ciphertext])).replace('0x', '')

encryptedArray.push({
ciphertext: ciphertext.toString('hex'),
Expand Down
21 changes: 21 additions & 0 deletions test/compressionPublicKey.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ const testCases = [
'0x77e05dd93cdd6362f8648447f33d5676cbc5f42f4c4946ae1ad62bd4c0c4f3570b1a104b67d1cd169bbf61dd557f15ab5ee8b661326096954caddadf34ae6ac8',
compressed: '0x0277e05dd93cdd6362f8648447f33d5676cbc5f42f4c4946ae1ad62bd4c0c4f357',
},
{
// Test with 04 uncompressed prefixed public key string
uncompressed:
'0x04019b186993b620455077b6bc37bf61666725d8d87ab33eb113ac0414cd48d78ff46e5ea48c6f22e8f19a77e5dbba9d209df60cbcb841b7e3e81fe444ba829831',
compressed: '0x03019b186993b620455077b6bc37bf61666725d8d87ab33eb113ac0414cd48d78f',
},
]

describe('caver.utils.compressPublicKey', () => {
Expand All @@ -71,6 +77,7 @@ describe('caver.utils.compressPublicKey', () => {
expect(caver.utils.compressPublicKey(testCases[4].uncompressed)).to.equal(testCases[4].compressed)
expect(caver.utils.compressPublicKey(testCases[5].uncompressed)).to.equal(testCases[5].compressed)
expect(caver.utils.compressPublicKey(testCases[6].uncompressed)).to.equal(testCases[6].compressed)
expect(caver.utils.compressPublicKey(testCases[7].uncompressed)).to.equal(testCases[7].compressed)
})

it('CAVERJS-UNIT-SER-023 : Should return same one with the argument if the argument is compressed public key', () => {
Expand All @@ -81,6 +88,13 @@ describe('caver.utils.compressPublicKey', () => {
expect(caver.utils.compressPublicKey(testCases[4].compressed)).to.equal(testCases[4].compressed)
expect(caver.utils.compressPublicKey(testCases[5].compressed)).to.equal(testCases[5].compressed)
expect(caver.utils.compressPublicKey(testCases[6].compressed)).to.equal(testCases[6].compressed)
expect(caver.utils.compressPublicKey(testCases[7].compressed)).to.equal(testCases[7].compressed)
})

it('CAVERJS-UNIT-SER-068: Should throw error if public key is invalid', () => {
const invalidFormat = '0x019b186993b620455077b6bc37bf61666725d8d87ab33eb113ac0414cd48d78f'
const expectedError = `Invalid public key`
expect(() => caver.utils.compressPublicKey(invalidFormat)).to.throw(expectedError)
})
})

Expand Down Expand Up @@ -126,4 +140,11 @@ describe('caver.utils.decompressPublicKey', () => {
expect(caver.utils.decompressPublicKey(testCases[5].uncompressed)).to.equal(testCases[5].uncompressed)
expect(caver.utils.decompressPublicKey(testCases[6].uncompressed)).to.equal(testCases[6].uncompressed)
})

it('CAVERJS-UNIT-SER-069: Should throw error if public key is invalid', () => {
const invalidFormat =
'0xe05dd93cdd6362f8648447f33d5676cbc5f42f4c4946ae1ad62bd4c0c4f3570b1a104b67d1cd169bbf61dd557f15ab5ee8b661326096954caddadf34ae6ac8'
const expectedError = `Invalid public key`
expect(() => caver.utils.compressPublicKey(invalidFormat)).to.throw(expectedError)
})
})
14 changes: 14 additions & 0 deletions test/packages/caver.utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -1157,11 +1157,14 @@ describe('caver.utils.xyPointFromPublicKey', () => {
'0x12b97e6756861ac0257a240d985d761cee9ca7719a29c233c644cfcc421885000c8e4c69cdb71665377b9e8ffb702355ca53917e66c7444619049c3dd0252ab6'
const publicKey4 =
'0x05b3b58259770871a1cc18534f2d438935fa2dcdb04116cbfbde8adfe858c23e50047c5aea3c2f55de7de04203f8fe8ccc3b491029338d038a7ef6d6903b302e'
const publicKey5 =
'0x04019b186993b620455077b6bc37bf61666725d8d87ab33eb113ac0414cd48d78ff46e5ea48c6f22e8f19a77e5dbba9d209df60cbcb841b7e3e81fe444ba829831'

const xyPoint1 = caver.utils.xyPointFromPublicKey(publicKey1)
const xyPoint2 = caver.utils.xyPointFromPublicKey(publicKey2)
const xyPoint3 = caver.utils.xyPointFromPublicKey(publicKey3)
const xyPoint4 = caver.utils.xyPointFromPublicKey(publicKey4)
const xyPoint5 = caver.utils.xyPointFromPublicKey(publicKey5)

expect(xyPoint1[0]).to.equals('0x46241c7524030e5b44fff78021e35227d708c8630757b35090d56527b615f60')
expect(xyPoint1[1]).to.equals('0x5b8d366782c86dee49356be574e1172f75ef5ce5d03b6e8c17dbf10f3fa2d9a3')
Expand All @@ -1174,6 +1177,9 @@ describe('caver.utils.xyPointFromPublicKey', () => {

expect(xyPoint4[0]).to.equals('0x5b3b58259770871a1cc18534f2d438935fa2dcdb04116cbfbde8adfe858c23e')
expect(xyPoint4[1]).to.equals('0x50047c5aea3c2f55de7de04203f8fe8ccc3b491029338d038a7ef6d6903b302e')

expect(xyPoint5[0]).to.equals('0x19b186993b620455077b6bc37bf61666725d8d87ab33eb113ac0414cd48d78f')
expect(xyPoint5[1]).to.equals('0xf46e5ea48c6f22e8f19a77e5dbba9d209df60cbcb841b7e3e81fe444ba829831')
})

it('CAVERJS-UNIT-ETC-209: caver.utils.xyPointFromPublicKey should return x, y point with compressed public key', () => {
Expand Down Expand Up @@ -1260,6 +1266,14 @@ describe('caver.utils.isValidPublicKey', () => {
const isValid = caver.utils.isValidPublicKey(pub)
expect(isValid).to.be.false
})

it('CAVERJS-UNIT-ETC-253: caver.utils.isValidPublicKey should true with 04 uncompressed prefixed public key string', () => {
const pub =
'0x04019b186993b620455077b6bc37bf61666725d8d87ab33eb113ac0414cd48d78ff46e5ea48c6f22e8f19a77e5dbba9d209df60cbcb841b7e3e81fe444ba829831'

const isValid = caver.utils.isValidPublicKey(pub)
expect(isValid).to.be.true
})
})

describe('caver.utils.isValidRole', () => {
Expand Down
8 changes: 4 additions & 4 deletions test/packages/caver.wallet.keyring.js
Original file line number Diff line number Diff line change
Expand Up @@ -1414,15 +1414,15 @@ describe('keyring.getKlaytnWalletKey', () => {

context('CAVERJS-UNIT-KEYRING-110: keyring type: multiSig', () => {
it('should throw error when keyring has multiple keys', () => {
const expectedError = `The keyring cannot be exported in KlaytnWalletKey format. Use keyring.encrypt.`
const expectedError = `Not supported for this class.`

expect(() => multiSig.getKlaytnWalletKey()).to.throw(expectedError)
})
})

context('CAVERJS-UNIT-KEYRING-111: keyring type: roleBased', () => {
it('should throw error when keyring has multiple keys', () => {
const expectedError = `The keyring cannot be exported in KlaytnWalletKey format. Use keyring.encrypt.`
const expectedError = `Not supported for this class.`

expect(() => roleBased.getKlaytnWalletKey()).to.throw(expectedError)
})
Expand Down Expand Up @@ -1686,15 +1686,15 @@ describe('keyring.encryptV3', () => {
context('CAVERJS-UNIT-KEYRING-135: keyring type: multiSig, input: password', () => {
it('should throw error when keyring use multiple private key', () => {
const password = 'password'
const expectedError = `This keyring cannot be encrypted keystore v3. use 'keyring.encrypt(password)'.`
const expectedError = `Not supported for this class. Use 'keyring.encrypt(password)'.`
expect(() => multiSig.encryptV3(password)).to.throw(expectedError)
})
})

context('CAVERJS-UNIT-KEYRING-136: keyring type: roleBased, input: password', () => {
it('should throw error when keyring use different private keys by roles', () => {
const password = 'password'
const expectedError = `This keyring cannot be encrypted keystore v3. use 'keyring.encrypt(password)'.`
const expectedError = `Not supported for this class. Use 'keyring.encrypt(password)'.`
expect(() => roleBased.encryptV3(password)).to.throw(expectedError)
})
})
Expand Down

0 comments on commit 1baaaf7

Please sign in to comment.