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

fix: use a more intuitive err-code #278

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@
"@libp2p/interface-keys": "^1.0.2",
"@noble/ed25519": "^1.6.0",
"@noble/secp256k1": "^1.5.4",
"err-code": "^3.0.1",
"coderra": "github:tabcat/coderra",
"multiformats": "^9.4.5",
"node-forge": "^1.1.0",
"protons-runtime": "^3.1.0",
Expand Down
4 changes: 2 additions & 2 deletions src/aes/cipher-mode.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import errcode from 'err-code'
import CodeError from 'coderra'

const CIPHER_MODES = {
16: 'aes-128-ctr',
Expand All @@ -11,5 +11,5 @@ export function cipherMode (key: Uint8Array) {
}

const modes = Object.entries(CIPHER_MODES).map(([k, v]) => `${k} (${v})`).join(' / ')
throw errcode(new Error(`Invalid key length ${key.length} bytes. Must be ${modes}`), 'ERR_INVALID_KEY_LENGTH')
throw new CodeError(`Invalid key length ${key.length} bytes. Must be ${modes}`, 'ERR_INVALID_KEY_LENGTH')
}
12 changes: 6 additions & 6 deletions src/keys/ecdh-browser.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import errcode from 'err-code'
import CodeError from 'coderra'
import webcrypto from '../webcrypto.js'
import { base64urlToBuffer } from '../util.js'
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
Expand All @@ -17,7 +17,7 @@ const names = curveTypes.join(' / ')

export async function generateEphmeralKeyPair (curve: string) {
if (curve !== 'P-256' && curve !== 'P-384' && curve !== 'P-521') {
throw errcode(new Error(`Unknown curve: ${curve}. Must be ${names}`), 'ERR_INVALID_CURVE')
throw new CodeError(`Unknown curve: ${curve}. Must be ${names}`, 'ERR_INVALID_CURVE')
}

const pair = await webcrypto.get().subtle.generateKey(
Expand Down Expand Up @@ -94,11 +94,11 @@ const curveLengths = {
// go-ipfs uses)
function marshalPublicKey (jwk: JsonWebKey) {
if (jwk.crv == null || jwk.x == null || jwk.y == null) {
throw errcode(new Error('JWK was missing components'), 'ERR_INVALID_PARAMETERS')
throw new CodeError('JWK was missing components', 'ERR_INVALID_PARAMETERS')
}

if (jwk.crv !== 'P-256' && jwk.crv !== 'P-384' && jwk.crv !== 'P-521') {
throw errcode(new Error(`Unknown curve: ${jwk.crv}. Must be ${names}`), 'ERR_INVALID_CURVE')
throw new CodeError(`Unknown curve: ${jwk.crv}. Must be ${names}`, 'ERR_INVALID_CURVE')
}

const byteLen = curveLengths[jwk.crv]
Expand All @@ -113,13 +113,13 @@ function marshalPublicKey (jwk: JsonWebKey) {
// Unmarshal converts a point, serialized by Marshal, into an jwk encoded key
function unmarshalPublicKey (curve: string, key: Uint8Array) {
if (curve !== 'P-256' && curve !== 'P-384' && curve !== 'P-521') {
throw errcode(new Error(`Unknown curve: ${curve}. Must be ${names}`), 'ERR_INVALID_CURVE')
throw new CodeError(`Unknown curve: ${curve}. Must be ${names}`, 'ERR_INVALID_CURVE')
}

const byteLen = curveLengths[curve]

if (!uint8ArrayEquals(key.slice(0, 1), Uint8Array.from([4]))) {
throw errcode(new Error('Cannot unmarshal public key - invalid key format'), 'ERR_INVALID_KEY_FORMAT')
throw new CodeError('Cannot unmarshal public key - invalid key format', 'ERR_INVALID_KEY_FORMAT')
}

return {
Expand Down
4 changes: 2 additions & 2 deletions src/keys/ecdh.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import crypto from 'crypto'
import errcode from 'err-code'
import CodeError from 'coderra'
import type { ECDHKey, ECDHKeyPair } from './interface.js'

const curves = {
Expand All @@ -13,7 +13,7 @@ const names = curveTypes.join(' / ')

export async function generateEphmeralKeyPair (curve: string): Promise<ECDHKey> { // eslint-disable-line require-await
if (curve !== 'P-256' && curve !== 'P-384' && curve !== 'P-521') {
throw errcode(new Error(`Unknown curve: ${curve}. Must be ${names}`), 'ERR_INVALID_CURVE')
throw new CodeError(`Unknown curve: ${curve}. Must be ${names}`, 'ERR_INVALID_CURVE')
}

const ecdh = crypto.createECDH(curves[curve])
Expand Down
6 changes: 3 additions & 3 deletions src/keys/ed25519-class.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import errcode from 'err-code'
import CodeError from 'coderra'
import { equals as uint8ArrayEquals } from 'uint8arrays/equals'
import { sha256 } from 'multiformats/hashes/sha2'
import { base58btc } from 'multiformats/bases/base58'
Expand Down Expand Up @@ -101,7 +101,7 @@ export class Ed25519PrivateKey {
if (format === 'libp2p-key') {
return await exporter(this.bytes, password)
} else {
throw errcode(new Error(`export format '${format}' is not supported`), 'ERR_INVALID_EXPORT_FORMAT')
throw new CodeError(`export format '${format}' is not supported`, 'ERR_INVALID_EXPORT_FORMAT')
}
}
}
Expand Down Expand Up @@ -139,7 +139,7 @@ export async function generateKeyPairFromSeed (seed: Uint8Array) {
function ensureKey (key: Uint8Array, length: number) {
key = Uint8Array.from(key ?? [])
if (key.length !== length) {
throw errcode(new Error(`Key must be a Uint8Array of length ${length}, got ${key.length}`), 'ERR_INVALID_KEY_TYPE')
throw new CodeError(`Key must be a Uint8Array of length ${length}, got ${key.length}`, 'ERR_INVALID_KEY_TYPE')
}
return key
}
8 changes: 4 additions & 4 deletions src/keys/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import 'node-forge/lib/asn1.js'
import 'node-forge/lib/pbe.js'
// @ts-expect-error types are missing
import forge from 'node-forge/lib/forge.js'
import errcode from 'err-code'
import CodeError from 'coderra'
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
import { keyStretcher } from './key-stretcher.js'
import generateEphemeralKeyPair from './ephemeral-keys.js'
Expand All @@ -27,7 +27,7 @@ export const supportedKeys = {

function unsupportedKey (type: string) {
const supported = Object.keys(supportedKeys).join(' / ')
return errcode(new Error(`invalid or unsupported key type ${type}. Must be ${supported}`), 'ERR_UNSUPPORTED_KEY_TYPE')
return new CodeError(`invalid or unsupported key type ${type}. Must be ${supported}`, 'ERR_UNSUPPORTED_KEY_TYPE')
}

function typeToKey (type: string) {
Expand All @@ -49,7 +49,7 @@ export async function generateKeyPair (type: KeyTypes, bits?: number): Promise<P
// seed is a 32 byte uint8array
export async function generateKeyPairFromSeed (type: KeyTypes, seed: Uint8Array, bits?: number): Promise<PrivateKey> { // eslint-disable-line require-await
if (type.toLowerCase() !== 'ed25519') {
throw errcode(new Error('Seed key derivation is unimplemented for RSA or secp256k1'), 'ERR_UNSUPPORTED_KEY_DERIVATION_TYPE')
throw new CodeError('Seed key derivation is unimplemented for RSA or secp256k1', 'ERR_UNSUPPORTED_KEY_DERIVATION_TYPE')
}

return await Ed25519.generateKeyPairFromSeed(seed)
Expand Down Expand Up @@ -121,7 +121,7 @@ export async function importKey (encryptedKey: string, password: string): Promis
// Only rsa supports pem right now
const key = forge.pki.decryptRsaPrivateKey(encryptedKey, password)
if (key === null) {
throw errcode(new Error('Cannot read the key, most likely the password is wrong or not a RSA key'), 'ERR_CANNOT_DECRYPT_PEM')
throw new CodeError('Cannot read the key, most likely the password is wrong or not a RSA key', 'ERR_CANNOT_DECRYPT_PEM')
}
let der = forge.asn1.toDer(forge.pki.privateKeyToAsn1(key))
der = uint8ArrayFromString(der.getBytes(), 'ascii')
Expand Down
6 changes: 3 additions & 3 deletions src/keys/key-stretcher.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import errcode from 'err-code'
import CodeError from 'coderra'
import { concat as uint8ArrayConcat } from 'uint8arrays/concat'
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
import * as hmac from '../hmac/index.js'
Expand Down Expand Up @@ -27,11 +27,11 @@ export async function keyStretcher (cipherType: 'AES-128' | 'AES-256' | 'Blowfis

if (cipher == null) {
const allowed = Object.keys(cipherMap).join(' / ')
throw errcode(new Error(`unknown cipher type '${cipherType}'. Must be ${allowed}`), 'ERR_INVALID_CIPHER_TYPE')
throw new CodeError(`unknown cipher type '${cipherType}'. Must be ${allowed}`, 'ERR_INVALID_CIPHER_TYPE')
}

if (hash == null) {
throw errcode(new Error('missing hash type'), 'ERR_MISSING_HASH_TYPE')
throw new CodeError('missing hash type', 'ERR_MISSING_HASH_TYPE')
}

const cipherKeySize = cipher.keySize
Expand Down
4 changes: 2 additions & 2 deletions src/keys/rsa-browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
import * as utils from './rsa-utils.js'
import { jwk2pub, jwk2priv } from './jwk2pem.js'
import errcode from 'err-code'
import CodeError from 'coderra'

export { utils }

Expand Down Expand Up @@ -102,7 +102,7 @@ export async function hashAndVerify (key: JsonWebKey, sig: Uint8Array, msg: Uint

async function exportKey (pair: CryptoKeyPair) {
if (pair.privateKey == null || pair.publicKey == null) {
throw errcode(new Error('Private and public key are required'), 'ERR_INVALID_PARAMETERS')
throw new CodeError('Private and public key are required', 'ERR_INVALID_PARAMETERS')
}

return await Promise.all([
Expand Down
6 changes: 3 additions & 3 deletions src/keys/rsa-class.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

import { sha256 } from 'multiformats/hashes/sha2'
import errcode from 'err-code'
import CodeError from 'coderra'
import { equals as uint8ArrayEquals } from 'uint8arrays/equals'
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
import 'node-forge/lib/sha512.js'
Expand Down Expand Up @@ -66,7 +66,7 @@ export class RsaPrivateKey {

get public () {
if (this._publicKey == null) {
throw errcode(new Error('public key not provided'), 'ERR_PUBKEY_NOT_PROVIDED')
throw new CodeError('public key not provided', 'ERR_PUBKEY_NOT_PROVIDED')
}

return new RsaPublicKey(this._publicKey)
Expand Down Expand Up @@ -128,7 +128,7 @@ export class RsaPrivateKey {
} else if (format === 'libp2p-key') {
return await exporter(this.bytes, password)
} else {
throw errcode(new Error(`export format '${format}' is not supported`), 'ERR_INVALID_EXPORT_FORMAT')
throw new CodeError(`export format '${format}' is not supported`, 'ERR_INVALID_EXPORT_FORMAT')
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/keys/rsa-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import forge from 'node-forge/lib/forge.js'
import { bigIntegerToUintBase64url, base64urlToBigInteger } from './../util.js'
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
import errcode from 'err-code'
import CodeError from 'coderra'

// Convert a PKCS#1 in ASN1 DER format to a JWK key
export function pkcs1ToJwk (bytes: Uint8Array): JsonWebKey {
Expand All @@ -30,7 +30,7 @@ export function pkcs1ToJwk (bytes: Uint8Array): JsonWebKey {
// Convert a JWK key into PKCS#1 in ASN1 DER format
export function jwkToPkcs1 (jwk: JsonWebKey) {
if (jwk.n == null || jwk.e == null || jwk.d == null || jwk.p == null || jwk.q == null || jwk.dp == null || jwk.dq == null || jwk.qi == null) {
throw errcode(new Error('JWK was missing components'), 'ERR_INVALID_PARAMETERS')
throw new CodeError('JWK was missing components', 'ERR_INVALID_PARAMETERS')
}

const asn1 = forge.pki.privateKeyToAsn1({
Expand Down Expand Up @@ -62,7 +62,7 @@ export function pkixToJwk (bytes: Uint8Array): JsonWebKey {
// Convert a JWK key to PKCIX in ASN1 DER format
export function jwkToPkix (jwk: JsonWebKey) {
if (jwk.n == null || jwk.e == null) {
throw errcode(new Error('JWK was missing components'), 'ERR_INVALID_PARAMETERS')
throw new CodeError('JWK was missing components', 'ERR_INVALID_PARAMETERS')
}

const asn1 = forge.pki.publicKeyToAsn1({
Expand Down
4 changes: 2 additions & 2 deletions src/keys/rsa.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import crypto from 'crypto'
import { promisify } from 'util'
import errcode from 'err-code'
import CodeError from 'coderra'
import randomBytes from '../random-bytes.js'
import * as utils from './rsa-utils.js'
import type { JWKKeyPair } from './interface.js'
Expand Down Expand Up @@ -28,7 +28,7 @@ export async function generateKey (bits: number): Promise<JWKKeyPair> { // eslin
// Takes a jwk key
export async function unmarshalPrivateKey (key: JsonWebKey): Promise<JWKKeyPair> { // eslint-disable-line require-await
if (key == null) {
throw errcode(new Error('Missing key parameter'), 'ERR_MISSING_KEY')
throw new CodeError('Missing key parameter', 'ERR_MISSING_KEY')
}
return {
privateKey: key,
Expand Down
4 changes: 2 additions & 2 deletions src/keys/secp256k1-class.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { sha256 } from 'multiformats/hashes/sha2'
import errcode from 'err-code'
import CodeError from 'coderra'
import { equals as uint8ArrayEquals } from 'uint8arrays/equals'
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
import * as crypto from './secp256k1.js'
Expand Down Expand Up @@ -99,7 +99,7 @@ export class Secp256k1PrivateKey {
if (format === 'libp2p-key') {
return await exporter(this.bytes, password)
} else {
throw errcode(new Error(`export format '${format}' is not supported`), 'ERR_INVALID_EXPORT_FORMAT')
throw new CodeError(`export format '${format}' is not supported`, 'ERR_INVALID_EXPORT_FORMAT')
}
}
}
Expand Down
17 changes: 11 additions & 6 deletions src/keys/secp256k1.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import errcode from 'err-code'
import CodeError from 'coderra'
import * as secp from '@noble/secp256k1'
import { sha256 } from 'multiformats/hashes/sha2'

Expand All @@ -18,7 +18,8 @@ export async function hashAndSign (key: Uint8Array, msg: Uint8Array) {
try {
return await secp.sign(digest, key)
} catch (err) {
throw errcode(err, 'ERR_INVALID_INPUT')
const { message } = err as Error
throw new CodeError(message, 'ERR_INVALID_INPUT')
}
}

Expand All @@ -30,7 +31,8 @@ export async function hashAndVerify (key: Uint8Array, sig: Uint8Array, msg: Uint
const { digest } = await sha256.digest(msg)
return secp.verify(sig, digest, key)
} catch (err) {
throw errcode(err, 'ERR_INVALID_INPUT')
const { message } = err as Error
throw new CodeError(message, 'ERR_INVALID_INPUT')
}
}

Expand All @@ -48,22 +50,25 @@ export function validatePrivateKey (key: Uint8Array) {
try {
secp.getPublicKey(key, true)
} catch (err) {
throw errcode(err, 'ERR_INVALID_PRIVATE_KEY')
const { message } = err as Error
throw new CodeError(message, 'ERR_INVALID_PRIVATE_KEY')
}
}

export function validatePublicKey (key: Uint8Array) {
try {
secp.Point.fromHex(key)
} catch (err) {
throw errcode(err, 'ERR_INVALID_PUBLIC_KEY')
const { message } = err as Error
throw new CodeError(message, 'ERR_INVALID_PUBLIC_KEY')
}
}

export function computePublicKey (privateKey: Uint8Array) {
try {
return secp.getPublicKey(privateKey, true)
} catch (err) {
throw errcode(err, 'ERR_INVALID_PRIVATE_KEY')
const { message } = err as Error
throw new CodeError(message, 'ERR_INVALID_PRIVATE_KEY')
}
}
4 changes: 2 additions & 2 deletions src/pbkdf2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import forgePbkdf2 from 'node-forge/lib/pbkdf2.js'
// @ts-expect-error types are missing
import forgeUtil from 'node-forge/lib/util.js'
import errcode from 'err-code'
import CodeError from 'coderra'

/**
* Maps an IPFS hash name to its node-forge equivalent.
Expand All @@ -23,7 +23,7 @@ const hashName = {
export default function pbkdf2 (password: string, salt: string, iterations: number, keySize: number, hash: string): string {
if (hash !== 'sha1' && hash !== 'sha2-256' && hash !== 'sha2-512') {
const types = Object.keys(hashName).join(' / ')
throw errcode(new Error(`Hash '${hash}' is unknown or not supported. Must be ${types}`), 'ERR_UNSUPPORTED_HASH_TYPE')
throw new CodeError(`Hash '${hash}' is unknown or not supported. Must be ${types}`, 'ERR_UNSUPPORTED_HASH_TYPE')
}

const hasher = hashName[hash]
Expand Down
4 changes: 2 additions & 2 deletions src/random-bytes.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { utils } from '@noble/secp256k1'
import errcode from 'err-code'
import CodeError from 'coderra'

export default function randomBytes (length: number): Uint8Array {
if (isNaN(length) || length <= 0) {
throw errcode(new Error('random bytes length must be a Number bigger than 0'), 'ERR_INVALID_LENGTH')
throw new CodeError('random bytes length must be a Number bigger than 0', 'ERR_INVALID_LENGTH')
}
return utils.randomBytes(length)
}