You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

157 lines
4.4 KiB

import { IIdentifier } from "@veramo/core";
import { getRandomBytesSync } from "ethereum-cryptography/random";
import { entropyToMnemonic } from "ethereum-cryptography/bip39";
import { wordlist } from "ethereum-cryptography/bip39/wordlists/english";
import { HDNode } from "@ethersproject/hdnode";
import {
CONTACT_IMPORT_CONFIRM_URL_PATH_TIME_SAFARI,
createEndorserJwtForDid,
CONTACT_URL_PATH_ENDORSER_CH_OLD,
CONTACT_IMPORT_ONE_URL_PATH_TIME_SAFARI,
} from "@/libs/endorserServer";
import { DEFAULT_DID_PROVIDER_NAME } from "../veramo/setup";
import { decodeEndorserJwt } from "@/libs/crypto/vc";
export const DEFAULT_ROOT_DERIVATION_PATH = "m/84737769'/0'/0'/0'";
export const LOCAL_KMS_NAME = "local";
/**
*
*
* @param {string} address
* @param {string} publicHex
* @param {string} privateHex
* @param {string} derivationPath
* @return {*} {Omit<IIdentifier, 'provider'>}
*/
export const newIdentifier = (
address: string,
publicHex: string,
privateHex: string,
derivationPath: string,
): Omit<IIdentifier, keyof "provider"> => {
return {
did: DEFAULT_DID_PROVIDER_NAME + ":" + address,
keys: [
{
kid: publicHex,
kms: LOCAL_KMS_NAME,
meta: { derivationPath: derivationPath },
privateKeyHex: privateHex,
publicKeyHex: publicHex,
type: "Secp256k1",
},
],
provider: DEFAULT_DID_PROVIDER_NAME,
services: [],
};
};
/**
*
*
* @param {string} mnemonic
* @return {*} {[string, string, string, string]}
*/
export const deriveAddress = (
mnemonic: string,
derivationPath: string = DEFAULT_ROOT_DERIVATION_PATH,
): [string, string, string, string] => {
mnemonic = mnemonic.trim().toLowerCase();
const hdnode: HDNode = HDNode.fromMnemonic(mnemonic);
const rootNode: HDNode = hdnode.derivePath(derivationPath);
const privateHex = rootNode.privateKey.substring(2); // original starts with '0x'
const publicHex = rootNode.publicKey.substring(2); // original starts with '0x'
const address = rootNode.address;
return [address, privateHex, publicHex, derivationPath];
};
export const generateRandomBytes = (numBytes: number): Uint8Array => {
return getRandomBytesSync(numBytes);
};
/**
*
*
* @return {*} {string}
*/
export const generateSeed = (): string => {
const entropy: Uint8Array = getRandomBytesSync(32);
const mnemonic = entropyToMnemonic(entropy, wordlist);
return mnemonic;
};
/**
* Retrieve an access token, or "" if no DID is provided.
*
* @return {*}
*/
export const accessToken = async (did?: string) => {
if (did) {
const nowEpoch = Math.floor(Date.now() / 1000);
const endEpoch = nowEpoch + 60; // add one minute
const tokenPayload = { exp: endEpoch, iat: nowEpoch, iss: did };
return createEndorserJwtForDid(did, tokenPayload);
} else {
return "";
}
};
/**
@return payload of JWT pulled out of the URL and decoded:
{ iat: number, iss: string (DID), own: { name, publicEncKey (base64-encoded key) } }
Result may be a single contact or it may be { contacts: [ contact, ... ] }
*/
export const getContactPayloadFromJwtUrl = (jwtUrlText: string) => {
let jwtText = jwtUrlText;
const appImportConfirmUrlLoc = jwtText.indexOf(
CONTACT_IMPORT_CONFIRM_URL_PATH_TIME_SAFARI,
);
if (appImportConfirmUrlLoc > -1) {
jwtText = jwtText.substring(
appImportConfirmUrlLoc +
CONTACT_IMPORT_CONFIRM_URL_PATH_TIME_SAFARI.length,
);
}
const appImportOneUrlLoc = jwtText.indexOf(
CONTACT_IMPORT_ONE_URL_PATH_TIME_SAFARI,
);
if (appImportOneUrlLoc > -1) {
jwtText = jwtText.substring(
appImportOneUrlLoc + CONTACT_IMPORT_ONE_URL_PATH_TIME_SAFARI.length,
);
}
const endorserUrlPathLoc = jwtText.indexOf(CONTACT_URL_PATH_ENDORSER_CH_OLD);
if (endorserUrlPathLoc > -1) {
jwtText = jwtText.substring(
endorserUrlPathLoc + CONTACT_URL_PATH_ENDORSER_CH_OLD.length,
);
}
// JWT format: { header, payload, signature, data }
const jwt = decodeEndorserJwt(jwtText);
return jwt.payload;
};
export const nextDerivationPath = (origDerivPath: string) => {
let lastStr = origDerivPath.split("/").slice(-1)[0];
if (lastStr.endsWith("'")) {
lastStr = lastStr.slice(0, -1);
}
const lastNum = parseInt(lastStr, 10);
const newLastNum = lastNum + 1;
const newLastStr = newLastNum.toString() + (lastStr.endsWith("'") ? "'" : "");
const newDerivPath = origDerivPath
.split("/")
.slice(0, -1)
.concat([newLastStr])
.join("/");
return newDerivPath;
};