@dao-xyz/peerbit
Version:
Distributed p2p database on IPFS
103 lines • 4.29 kB
JavaScript
import { Ed25519Keypair, Keypair, X25519PublicKey, } from "@dao-xyz/peerbit-crypto";
import { AccessError, X25519Keypair, } from "@dao-xyz/peerbit-crypto";
import { keysPBM } from "@libp2p/crypto/keys";
import { identity } from "multiformats/hashes/identity";
import { base58btc } from "multiformats/bases/base58";
import { Cache } from "@dao-xyz/cache";
import createError from "err-code";
export class FastKeychain {
identityKeypair;
defaultEncryptionKeypair;
keychain;
keychainCache = new Cache({ max: 1000 });
constructor(identityKeypair, defaultEncryptionKeypair, keychain) {
this.identityKeypair = identityKeypair;
this.defaultEncryptionKeypair = defaultEncryptionKeypair;
this.keychain = keychain;
}
static async create(identityKeypair, keychain) {
const fk = new FastKeychain(identityKeypair, await X25519Keypair.from(identityKeypair), keychain);
// Import peerId to keychain so it can be easily accessible
try {
await fk.importKeypair(fk.identityKeypair);
}
catch (error) {
if (error.code === "ERR_KEY_ALREADY_EXISTS") {
return fk;
}
throw error;
}
return fk;
}
keychainKeyIdFromPublicKey(publicKey) {
const bytes = keysPBM.PublicKey.encode({
Type: keysPBM.KeyType.Ed25519,
Data: publicKey.publicKey,
}).subarray();
const encoding = identity.digest(bytes);
return base58btc.encode(encoding.bytes).substring(1);
}
exportKeypair = async (publicKey) => {
/* const id = keychainKeyIdFromPublicKey(publicKey);
const key = await keychain.findKeyById(id);
const password = "default-password";
const pem = await keychain.exportKey(key.name, password);
const privateKey = await importKey(pem, password);
return new X25519Keypair({
publicKey: new X25519PublicKey({ publicKey: privateKey.public.bytes }),
secretKey: new X25519SecretKey({
secretKey: privateKey.bytes.slice(0, 32),
}),
}); */
const key = base58btc.encode(publicKey.bytes);
const cached = this.keychainCache.get(key);
if (cached === null) {
throw createError(new Error("Key declared null in cache"), "ERR_NOT_FOUND");
}
else if (cached instanceof Keypair) {
return cached;
}
const peerId = await this.keychain.exportPeerId(key);
return (publicKey instanceof X25519PublicKey
? X25519Keypair.fromPeerId(peerId)
: Ed25519Keypair.fromPeerId(peerId));
};
importKeypair = async (keypair) => {
const receiverKeyPeerId = await keypair.toPeerId();
const edKey = base58btc.encode(keypair.publicKey.bytes);
const xKeypair = await X25519Keypair.from(keypair);
const xKey = base58btc.encode(xKeypair.publicKey.bytes);
this.keychainCache.add(edKey, xKeypair);
this.keychainCache.add(xKey, xKeypair);
// import as ed
await this.keychain.importPeer(edKey, receiverKeyPeerId);
// import as x so we can decrypt messages with this public key (if recieved any)
await this.keychain.importPeer(xKey, receiverKeyPeerId);
};
// Arrow function is used so we can reference this function and use 'this' without .bind(self)
getAnyKeypair = async (publicKeys) => {
for (let i = 0; i < publicKeys.length; i++) {
try {
const key = await this.exportKeypair(publicKeys[i]);
if (key && key instanceof X25519Keypair) {
return {
index: i,
keypair: key,
};
}
}
catch (error) {
// Key missing
if (error.code !== "ERR_NOT_FOUND") {
throw error;
}
}
}
throw new AccessError("Failed to access key");
};
// Arrow function is used so we can reference this function and use 'this' without .bind(self)
getEncryptionKeypair = () => {
return this.defaultEncryptionKeypair;
};
}
//# sourceMappingURL=encryption.js.map