Skip to content

Commit

Permalink
feat: errors introducing error codes and refactoring Apollo errors
Browse files Browse the repository at this point in the history
Signed-off-by: Curtish <ch@curtish.me>
  • Loading branch information
curtis-h committed Aug 19, 2024
1 parent 7e563b8 commit b4ddac3
Show file tree
Hide file tree
Showing 16 changed files with 190 additions and 228 deletions.
98 changes: 39 additions & 59 deletions src/apollo/Apollo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@ import {
StorableKey,
KeyRestoration,
} from "../domain";
import {
MnemonicLengthException,
MnemonicWordException,
} from "../domain/models/errors/Mnemonic";

import { Ed25519PrivateKey } from "./utils/Ed25519PrivateKey";
import { X25519PrivateKey } from "./utils/X25519PrivateKey";
Expand All @@ -30,7 +26,7 @@ import { Secp256k1PublicKey } from "./utils/Secp256k1PublicKey";
import { Ed25519PublicKey } from "./utils/Ed25519PublicKey";
import { X25519PublicKey } from "./utils/X25519PublicKey";

import { notEmptyString } from "../utils";
import { isEmpty, notEmptyString } from "../utils";
import ApolloPKG from "@hyperledger/identus-apollo";
import { PrismDerivationPath } from "../domain/models/derivation/schemas/PrismDerivation";

Expand Down Expand Up @@ -154,13 +150,11 @@ export default class Apollo implements ApolloInterface, KeyRestoration {
const mnemonicString = mnemonics.join(" ");

if (mnemonics.length != 12 && mnemonics.length != 24) {
throw new MnemonicLengthException(
"Word list must be 12 or 24 words in length"
);
throw new ApolloError.MnemonicLengthError();
}

if (!bip39.validateMnemonic(mnemonicString, wordlist)) {
throw new MnemonicWordException(`Invalid mnemonic word/s`);
throw new ApolloError.MnemonicWordError(mnemonics);
}

const seed = Mnemonic.createSeed(mnemonics, `mnemonic${passphrase}`);
Expand Down Expand Up @@ -215,45 +209,42 @@ export default class Apollo implements ApolloInterface, KeyRestoration {
createPublicKey(parameters: {
[name: KeyProperties | string]: any;
}): PublicKey {
if (!parameters[KeyProperties.type]) {
throw new ApolloError.InvalidKeyType(
parameters[KeyProperties.type],
Object.values(KeyTypes)
);
const keyType = parameters[KeyProperties.type];
const keyCurve = parameters[KeyProperties.curve];

if (isEmpty(keyType)) {
throw new ApolloError.InvalidKeyType(keyType);
}
if (!parameters[KeyProperties.curve]) {
throw new ApolloError.InvalidKeyCurve(
parameters[KeyProperties.curve],
Object.values(Curve)
);

if (isEmpty(keyCurve)) {
throw new ApolloError.InvalidKeyCurve(keyCurve);
}
const keyType = parameters[KeyProperties.type];
const { curve } = getKeyCurveByNameAndIndex(
parameters[KeyProperties.curve]
);

const { curve } = getKeyCurveByNameAndIndex(keyCurve);
const keyData = parameters[KeyProperties.rawKey];

if (keyType === KeyTypes.EC) {
if (curve === Curve.ED25519) {
if (keyData) {
return new Ed25519PublicKey(keyData);
}
throw new ApolloError.InvalidPrivateKey("Missing raw bytes");

throw new ApolloError.MissingKeyParameters(KeyProperties.rawKey);
}

if (curve === Curve.SECP256K1) {
if (keyData) {
return new Secp256k1PublicKey(keyData);
} else {
const xData = parameters[KeyProperties.curvePointX];
const yData = parameters[KeyProperties.curvePointY];

if (xData && yData) {
return Secp256k1PublicKey.secp256k1FromByteCoordinates(
xData,
yData
);
return Secp256k1PublicKey.secp256k1FromByteCoordinates(xData, yData);
}
}
throw new ApolloError.InvalidPrivateKey("Missing raw bytes or coordinates");

throw new ApolloError.MissingKeyParameters(KeyProperties.rawKey, KeyProperties.curvePointX, KeyProperties.curvePointY);
}
}

Expand All @@ -262,11 +253,12 @@ export default class Apollo implements ApolloInterface, KeyRestoration {
if (keyData) {
return new X25519PublicKey(keyData);
}
throw new ApolloError.InvalidPrivateKey("Missing raw bytes");

throw new ApolloError.MissingKeyParameters(KeyProperties.rawKey);
}
}

throw new ApolloError.InvalidKeyType(keyType, Object.values(KeyTypes));
throw new ApolloError.MissingKeyParameters(KeyProperties.rawKey);
}

/**
Expand Down Expand Up @@ -329,23 +321,18 @@ export default class Apollo implements ApolloInterface, KeyRestoration {
createPrivateKey(parameters: {
[name: KeyProperties | string]: any;
}): PrivateKey {
if (!parameters[KeyProperties.type]) {
throw new ApolloError.InvalidKeyType(
parameters[KeyProperties.type],
Object.values(KeyTypes)
);
const keyType = parameters[KeyProperties.type];
const keyCurve = parameters[KeyProperties.curve];

if (isEmpty(keyType)) {
throw new ApolloError.InvalidKeyType(keyType);
}
if (!parameters[KeyProperties.curve]) {
throw new ApolloError.InvalidKeyCurve(
parameters[KeyProperties.curve],
Object.values(Curve)
);

if (isEmpty(keyCurve)) {
throw new ApolloError.InvalidKeyCurve(keyCurve);
}

const keyType = parameters[KeyProperties.type];
const { curve } = getKeyCurveByNameAndIndex(
parameters[KeyProperties.curve]
);
const { curve } = getKeyCurveByNameAndIndex(parameters[KeyProperties.curve]);
const keyData = parameters[KeyProperties.rawKey];

if (keyType === KeyTypes.EC) {
Expand All @@ -356,14 +343,10 @@ export default class Apollo implements ApolloInterface, KeyRestoration {

const seedHex = parameters[KeyProperties.seed];
if (notEmptyString(seedHex)) {

const derivationIndex = parameters[KeyProperties.index] ?? "0";
const derivationParam = parameters[KeyProperties.derivationPath];
const defaultPath: string = derivationParam ?? PrismDerivationPath.init(derivationIndex).toString();


const seed = Int8Array.from(Buffer.from(seedHex, "hex"));

const hdKey = ApolloSDK.derivation.EdHDKey.Companion.initFromSeed(seed);
const baseKey = new Ed25519PrivateKey(Uint8Array.from(hdKey.privateKey));

Expand All @@ -375,12 +358,12 @@ export default class Apollo implements ApolloInterface, KeyRestoration {
const privateKey = baseKey.derive(defaultPath);
return privateKey;
}

return baseKey;
}

const keyPair = Ed25519KeyPair.generateKeyPair();
return keyPair.privateKey;

}

if (curve === Curve.SECP256K1) {
Expand All @@ -389,11 +372,11 @@ export default class Apollo implements ApolloInterface, KeyRestoration {
}

const seedHex = parameters[KeyProperties.seed];
if (!seedHex) {
throw new ApolloError.MissingKeyParameters(["seed"]);
if (isEmpty(seedHex)) {
throw new ApolloError.MissingKeyParameters(KeyProperties.seed);
}
const seed = Buffer.from(seedHex, "hex");

const seed = Buffer.from(seedHex, "hex");
const derivationIndex = parameters[KeyProperties.index] ?? "0";
const derivationParam = parameters[KeyProperties.derivationPath];
const defaultPath: string = derivationParam ?? PrismDerivationPath.init(
Expand All @@ -407,11 +390,11 @@ export default class Apollo implements ApolloInterface, KeyRestoration {
);

if (hdKey.privateKey == null) {
throw new ApolloError.MissingPrivateKey();
throw new ApolloError.ApolloLibError("Key generated incorrectly: missing privateKey");
}

if (hdKey.chainCode == null) {
throw new ApolloError.MissingChainCode();
throw new ApolloError.ApolloLibError("Key generated incorrectly: missing chainCode");
}

const baseKey = new Secp256k1PrivateKey(Uint8Array.from(hdKey.privateKey));
Expand All @@ -425,7 +408,6 @@ export default class Apollo implements ApolloInterface, KeyRestoration {
}

return baseKey;

}
}

Expand Down Expand Up @@ -454,12 +436,10 @@ export default class Apollo implements ApolloInterface, KeyRestoration {

const keyPair = X25519KeyPair.generateKeyPair();
return keyPair.privateKey;


}
}

throw new ApolloError.InvalidKeyType(keyType, Object.values(KeyTypes));
throw new ApolloError.InvalidKeyType(keyType);
}

restorePrivateKey(key: StorableKey): PrivateKey {
Expand Down
2 changes: 1 addition & 1 deletion src/apollo/utils/Ed25519PrivateKey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export class Ed25519PrivateKey extends PrivateKey implements DerivableKey, Expor
derive(derivationPath: string): PrivateKey {
const chainCodeHex = this.getProperty(KeyProperties.chainCode);
if (!chainCodeHex) {
throw new ApolloError.MissingKeyParameters([KeyProperties.chainCode]);
throw new ApolloError.MissingKeyParameters(KeyProperties.chainCode);
}
const derivationPathStr = derivationPath.toString();
const skRaw = Int8Array.from(this.raw);
Expand Down
9 changes: 5 additions & 4 deletions src/apollo/utils/Secp256k1PrivateKey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,9 @@ export class Secp256k1PrivateKey

constructor(nativeValue: Uint8Array) {
if (nativeValue.length !== ECConfig.PRIVATE_KEY_BYTE_SIZE) {
throw new ApolloError.ECPublicKeyInitialization();
throw new ApolloError.KeyInitializationError(`Invalid byte size: ${ECConfig.PRIVATE_KEY_BYTE_SIZE} exptected, ${nativeValue.length} given`);
}

super();

this.keySpecification.set(KeyProperties.curve, Curve.SECP256K1);
Expand All @@ -54,7 +55,7 @@ export class Secp256k1PrivateKey
derive(derivationPath: string): Secp256k1PrivateKey {
const chainCodeHex = this.getProperty(KeyProperties.chainCode);
if (!chainCodeHex) {
throw new ApolloError.MissingKeyParameters([KeyProperties.chainCode]);
throw new ApolloError.MissingKeyParameters(KeyProperties.chainCode);
}
const chaincode = Buffer.from(chainCodeHex, "hex");
const derivationPathStr = derivationPath.toString();
Expand All @@ -67,7 +68,7 @@ export class Secp256k1PrivateKey
);
const derivedKey = hdKey.derive(derivationPathStr);
if (derivedKey.privateKey == null) {
throw new ApolloError.MissingPrivateKey();
throw new ApolloError.ApolloLibError("Key generated incorrectly: missing privateKey");
}
const privateKey = new Secp256k1PrivateKey(Buffer.from(derivedKey.privateKey));
privateKey.keySpecification.set(KeyProperties.derivationPath, Buffer.from(derivationPathStr).toString("hex"));
Expand Down Expand Up @@ -104,7 +105,7 @@ export class Secp256k1PrivateKey

static secp256k1FromBytes(encoded: Uint8Array): Secp256k1PrivateKey {
if (encoded.length !== ECConfig.PRIVATE_KEY_BYTE_SIZE) {
throw new ApolloError.ECPublicKeyInitialization();
throw new ApolloError.KeyInitializationError(`Invalid byte size: ${ECConfig.PRIVATE_KEY_BYTE_SIZE} exptected, ${encoded.length} given`);
}
const bnprv = new BN(encoded);
return new Secp256k1PrivateKey(Uint8Array.from(bnprv.toArray()));
Expand Down
2 changes: 1 addition & 1 deletion src/apollo/utils/Secp256k1PublicKey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export class Secp256k1PublicKey extends PublicKey implements StorableKey, Export
nativeValue.at(0) === 0x04;

if (!isCompressed && !isUnCompressed) {
throw new ApolloError.ECPublicKeyInitialization();
throw new ApolloError.KeyInitializationError(`Invalid key bytes`);
}
this.keySpecification.set(KeyProperties.curve, Curve.SECP256K1);
this.keySpecification.set("compressed", isCompressed ? "true" : "false");
Expand Down
41 changes: 19 additions & 22 deletions src/apollo/utils/derivation/DerivationPath.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,21 @@ export class DerivationPath {
}

get axes(): DerivationAxis[] {
return this.paths.map((path) => new DerivationAxis(path))
return this.paths.map((path) => new DerivationAxis(path));
}

get index() {
return DerivationPath.callBackOrThrow(
this.derivations,
this.paths,
(path) => path.index
)
);
}

at(index: number): number {
const num = this.paths.at(index);
if (num !== undefined) {
return num
return num;
}
throw new ApolloError.InvalidDerivationPath("DerivationPathErr Incompatible Derivation schema");
}
Expand All @@ -34,7 +34,7 @@ export class DerivationPath {
this.derivations,
this.paths,
(path) => path.schema
)
);
}

derive(axis: DerivationAxis): DerivationPath {
Expand All @@ -56,7 +56,7 @@ export class DerivationPath {
this.derivations,
this.paths,
(path) => `m/${path.axes.map((axis) => axis.toString()).join("/")}`
)
);
}

/**
Expand All @@ -66,23 +66,20 @@ export class DerivationPath {
* optionally a ' added after to mark hardened axis e.g. m/21/37'/0
*/
static fromPath(path: string, derivations: DerivationClass[]): DerivationPath {
try {
if (typeof path === "string") {
const splitPath = path.split("/");
if (splitPath.at(0)?.trim().toLowerCase() !== "m") {
throw new ApolloError.InvalidDerivationPath("Path needs to start with m or M");
}
const paths = splitPath.slice(1).map(DerivationPath.parseAxis).map((a) => a.number);
return DerivationPath.callBackOrThrow(
derivations,
paths,
(path) => new DerivationPath(path.axes.map((a) => a.number), derivations)
)
if (typeof path === "string") {
const splitPath = path.split("/");
if (splitPath.at(0)?.trim().toLowerCase() !== "m") {
throw new ApolloError.InvalidDerivationPath("Path needs to start with m or M");
}
throw new ApolloError.InvalidDerivationPath(`Derivation path should be string`)
} catch (err) {
throw new ApolloError.InvalidDerivationPath(`DerivationPathErr ${(err as Error).message}`)
const paths = splitPath.slice(1).map(DerivationPath.parseAxis).map((a) => a.number);
return DerivationPath.callBackOrThrow(
derivations,
paths,
(path) => new DerivationPath(path.axes.map((a) => a.number), derivations)
);
}
throw new ApolloError.InvalidDerivationPath(`Derivation path should be string`);

}

private static parseAxis(axis: string): DerivationAxis {
Expand All @@ -104,7 +101,7 @@ export class DerivationPath {
return path;
} catch (err) {
if (!(err instanceof ApolloError.InvalidDerivationPath)) {
throw err
throw err;
}
}
}
Expand All @@ -123,4 +120,4 @@ export class DerivationPath {
throw new ApolloError.InvalidDerivationPath("DerivationPathErr Incompatible Derivation schema");
}

}
}
2 changes: 1 addition & 1 deletion src/castor/did/prismDID/PrismDIDPublicKey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export class PrismDIDPublicKey {
this.fromEd25519ORX25519Proto(apollo, proto)
);
} else {
throw new ApolloError.InvalidKeyCurve(curve, Object.values(Curve))
throw new ApolloError.InvalidKeyCurve(curve);
}
}

Expand Down
Loading

0 comments on commit b4ddac3

Please sign in to comment.