@lukasrosario/account
Version:
Base Account SDK
103 lines (86 loc) • 2.83 kB
text/typescript
import { store } from ':store/store.js';
import {
deriveSharedSecret,
exportKeyToHexString,
generateKeyPair,
importKeyFromHexString,
} from ':util/cipher.js';
interface StorageItem {
storageKey: string;
keyType: 'public' | 'private';
}
const OWN_PRIVATE_KEY = {
storageKey: 'ownPrivateKey',
keyType: 'private',
} as const;
const OWN_PUBLIC_KEY = {
storageKey: 'ownPublicKey',
keyType: 'public',
} as const;
const PEER_PUBLIC_KEY = {
storageKey: 'peerPublicKey',
keyType: 'public',
} as const;
export class SCWKeyManager {
private ownPrivateKey: CryptoKey | null = null;
private ownPublicKey: CryptoKey | null = null;
private peerPublicKey: CryptoKey | null = null;
private sharedSecret: CryptoKey | null = null;
async getOwnPublicKey(): Promise<CryptoKey> {
await this.loadKeysIfNeeded();
return this.ownPublicKey!;
}
// returns null if the shared secret is not yet derived
async getSharedSecret(): Promise<CryptoKey | null> {
await this.loadKeysIfNeeded();
return this.sharedSecret;
}
async setPeerPublicKey(key: CryptoKey) {
this.sharedSecret = null;
this.peerPublicKey = key;
await this.storeKey(PEER_PUBLIC_KEY, key);
await this.loadKeysIfNeeded();
}
async clear() {
this.ownPrivateKey = null;
this.ownPublicKey = null;
this.peerPublicKey = null;
this.sharedSecret = null;
store.keys.clear();
}
private async generateKeyPair() {
const newKeyPair = await generateKeyPair();
this.ownPrivateKey = newKeyPair.privateKey;
this.ownPublicKey = newKeyPair.publicKey;
await this.storeKey(OWN_PRIVATE_KEY, newKeyPair.privateKey);
await this.storeKey(OWN_PUBLIC_KEY, newKeyPair.publicKey);
}
private async loadKeysIfNeeded() {
if (this.ownPrivateKey === null) {
this.ownPrivateKey = await this.loadKey(OWN_PRIVATE_KEY);
}
if (this.ownPublicKey === null) {
this.ownPublicKey = await this.loadKey(OWN_PUBLIC_KEY);
}
if (this.ownPrivateKey === null || this.ownPublicKey === null) {
await this.generateKeyPair();
}
if (this.peerPublicKey === null) {
this.peerPublicKey = await this.loadKey(PEER_PUBLIC_KEY);
}
if (this.sharedSecret === null) {
if (this.ownPrivateKey === null || this.peerPublicKey === null) return;
this.sharedSecret = await deriveSharedSecret(this.ownPrivateKey, this.peerPublicKey);
}
}
// storage methods
private async loadKey(item: StorageItem): Promise<CryptoKey | null> {
const key = store.keys.get(item.storageKey);
if (!key) return null;
return importKeyFromHexString(item.keyType, key);
}
private async storeKey(item: StorageItem, key: CryptoKey) {
const hexString = await exportKeyToHexString(item.keyType, key);
store.keys.set(item.storageKey, hexString);
}
}