diff --git a/CHANGELOG.fr.md b/CHANGELOG.fr.md index bdda49c6ceb976d13893df6e7992d7b7cbbc1cb1..448826a02b014899406d9515c42f1544eea13f69 100644 --- a/CHANGELOG.fr.md +++ b/CHANGELOG.fr.md @@ -13,6 +13,10 @@ et ce projet adhère au [versionnage sémantique](https://semver.org/spec/v2.0.0 ## [Non-publié/Non-Stabilisé] (par [1000i100]) +## [Version 3.4.1] - 2022-11-20 (par [1000i100]) +### Corrections +- checkKey envoi désormais des erreurs nommées, utilisable pour guider les usagers. + ## [Version 3.4.0] - 2022-11-15 (par [1000i100]) ### Ajouté - crypto.textEncrypt(jsonMessage, senderPrivateKey, receiverPubKey) retourne un json format cesium+ avec `jsonMessage.title` et `jsonMessage.content` chiffrés. @@ -101,8 +105,9 @@ et ce projet adhère au [versionnage sémantique](https://semver.org/spec/v2.0.0 - intégration des librairies de crypto nécessaires - calcul de la clef publique correspondant à chaque combinaison de secrets saisie, et comparaison à la clef publique de référence. -[Non-publié/Non-Stabilisé]: https://git.duniter.org/libs/g1lib.js/-/compare/v3.4.0...main +[Non-publié/Non-Stabilisé]: https://git.duniter.org/libs/g1lib.js/-/compare/v3.4.1...main +[Version 3.4.1]: https://git.duniter.org/libs/g1lib.js/-/compare/v3.4.0...v3.4.1 [Version 3.4.0]: https://git.duniter.org/libs/g1lib.js/-/compare/v3.3.3...v3.4.0 [Version 3.3.3]: https://git.duniter.org/libs/g1lib.js/-/compare/v3.3.2...v3.3.3 [Version 3.3.2]: https://git.duniter.org/libs/g1lib.js/-/compare/v3.3.1...v3.3.2 diff --git a/npm/package.json b/npm/package.json index df79b1f275a7c7fba6b44887fcd9253987357f0a..277098002b7697316fff7a38953cff31fe8dbcf4 100644 --- a/npm/package.json +++ b/npm/package.json @@ -1,6 +1,6 @@ { "name": "g1lib", - "version": "3.4.0", + "version": "3.4.1", "description": "An ubiquitous static javascript toolbox lib for Ǧ1 / Duniter ecosystem with reliability in mind.", "main": "nodejs/all.mjs", "browser": "browser/all.mjs", diff --git a/src/crypto.mjs b/src/crypto.mjs index cac959e77e4e88e45542717ed928ed6a2861b609..36d66f6d625bc29eaef275d90e4838afdb8e8802 100644 --- a/src/crypto.mjs +++ b/src/crypto.mjs @@ -121,14 +121,25 @@ export function onlyPubKey(pubKeyWithChecksum){ if (pubKey2checksum(b58pubKey, true, false, false) === checkSum) return b58pubKey; if (pubKey2checksum(b58pubKey, false, true, false) === checkSum) return b58pubKey; if (pubKey2checksum(b58pubKey, true, true, false) === checkSum) return b58pubKey; - throw new Error('Bad checksum'); + throw new CustomError('bad_checksum','Bad checksum'); } export function isDuniterPubKey(b58pubKey){ return /^[A-HJ-NP-Za-km-z1-9]{43,44}$/.test(b58pubKey) && b58.decode(b58pubKey).length <=32; } +export function checkDuniterPubKey(b58pubKey){ + if(b58pubKey.length<43) throw new CustomError('too_short','Too short, see rfc/0009_Duniter_Blockchain_Protocol_V11.md#public-key for details.'); + if(b58pubKey.length>44) throw new CustomError('too_long','Base58 string too long, see rfc/0009_Duniter_Blockchain_Protocol_V11.md#public-key for details.'); + if(!/^[A-HJ-NP-Za-km-z1-9]+$/.test(b58pubKey)) throw new CustomError('not_b58', 'Character out of base 58, see rfc/0009_Duniter_Blockchain_Protocol_V11.md#public-key for details.'); + if(b58.decode(b58pubKey).length > 32) throw new CustomError('too_long','binary key too long, see rfc/0009_Duniter_Blockchain_Protocol_V11.md#public-key for details.'); + return true; +} export function checkEd25519PubKey(b58pubKey){ const binPubKey = pubKey2bin(b58pubKey); - ed25519.Point.fromHex(binPubKey); + try{ + ed25519.Point.fromHex(binPubKey); + } catch (err){ + throw new CustomError('bad_ed25519_point',`Invalid public key : not a valid ed25519 point RFC8032 5.1.3 https://www.rfc-editor.org/rfc/rfc8032#page-11 Internal:${err}`); + } return true; } export function isEd25519PubKey(b58pubKey){ @@ -138,11 +149,19 @@ export function isEd25519PubKey(b58pubKey){ } export function checkKey(pubKey, checkRawPubKey= true) { - const binPubKey = pubKey2bin(pubKey) - const b58pubKey = b58.encode(binPubKey); + if(!pubKey) throw new CustomError('empty','Invalid public key : empty input.') + let b58pubKey; + try { + const binPubKey = pubKey2bin(pubKey) + b58pubKey = b58.encode(binPubKey); + } catch (err){ + if(err.message.match(/base58/)) throw new CustomError('not_b58', 'Character out of base 58, see rfc/0009_Duniter_Blockchain_Protocol_V11.md#public-key for details.'); + if(err.message.match(/out of bounds/)) throw new CustomError('too_long','Binary key too long, see rfc/0009_Duniter_Blockchain_Protocol_V11.md#public-key for details.'); + throw err; + } if(!checkRawPubKey) return true; - if(!isDuniterPubKey(b58pubKey)) throw new Error("Invalid public key : this string don't follow rfc/0009_Duniter_Blockchain_Protocol_V11.md#public-key"); - if(!isEd25519PubKey(b58pubKey)) throw new Error("Invalid public key : not a valid ed25519 point RFC8032 5.1.3 https://www.rfc-editor.org/rfc/rfc8032#page-11"); + checkDuniterPubKey(b58pubKey); + checkEd25519PubKey(b58pubKey); return true; } export function isPubKey(pubKey){ @@ -229,3 +248,9 @@ export function textDecrypt(jsonMessage, receiverPrivateKey){ if(jsonMessage.title) res.title = decrypt(jsonMessage.title); return res; } +class CustomError extends Error { + constructor(name, message) { + super(message); + this.name = name; + } +} diff --git a/src/crypto.test.mjs b/src/crypto.test.mjs index 2c45600463d3c1169e7371f44ccf5de969b144dd..6c07e9b88a4dca01f685b9f4ce9f010220d66ef1 100644 --- a/src/crypto.test.mjs +++ b/src/crypto.test.mjs @@ -128,8 +128,12 @@ test("isEd25519PubKey fail if point is not on ed25519", (t) => t.false(app.isEd2 test('checkKey accept valid pubKey with no checksum', t => t.true(app.checkKey(pubKey))); -test('checkKey throw if invalid pubkey is given', t => t.throws(() => app.checkKey(pubKey.replace(/6/,'9')))); -test('checkKey throw if empty pubkey is given', t => t.throws(() => app.checkKey(''))); +test('checkKey throw if empty pubkey is given', t => t.throws(() => app.checkKey(''),{name:'empty'})); +test('checkKey throw if under_sized string is given', t => t.throws(() => app.checkKey('test'),{name:'too_short'})); +test('checkKey throw if over_sized string is given', t => t.throws(() => app.checkKey(pubKey+pubKey),{name:'too_long'})); +test('checkKey throw if invalid pubkey is given (not on ed25519 curve)', t => t.throws(() => app.checkKey(pubKey.replace(/6/,'9')),{name:'bad_ed25519_point'})); +test('checkKey throw if checksum is incorrect', t => t.throws(() => app.checkKey(`${pubKey}:111`),{name:'bad_checksum'})); +test('checkKey throw if not b58 string is given', t => t.throws(() => app.checkKey(`___`),{name:'not_b58'})); test('checkKey accept valid binary pubKey', t => t.true(app.checkKey(app.b58.decode(pubKey))));