TODO: update vault.service.ts. Use MNEMONIC workflow to create real private_key_shard and content_inner_encrypted
82 lines
2.9 KiB
TypeScript
82 lines
2.9 KiB
TypeScript
/**
|
||
* Vault Service: 为 /assets/create 生成 private_key_shard 与 content_inner_encrypted
|
||
*
|
||
* 流程(与后端 test_scenario / SentinelVault 一致):
|
||
* 1. 用 SSS 生成助记词并分片 → 选一个分片作为 private_key_shard(存后端,继承时返回)
|
||
* 2. 用助记词派生 AES 密钥,对明文做 AES-GCM 加密 → content_inner_encrypted(hex 字符串)
|
||
*
|
||
* 使用方式:在任意页面调用 createVaultPayload(plaintext, wordList),得到可直接传给 assetsService.createAsset 的字段。
|
||
*/
|
||
|
||
import {
|
||
generateVaultKeys,
|
||
serializeShare,
|
||
type SSSShare,
|
||
type VaultKeyData,
|
||
} from '../utils/sss';
|
||
import { deriveKey, encryptDataGCM, bytesToHex } from '../utils/vaultCrypto';
|
||
|
||
export interface CreateVaultPayloadResult {
|
||
/** 传给后端的 private_key_shard(存一个 SSS 分片的序列化字符串,如云端分片) */
|
||
private_key_shard: string;
|
||
/** 传给后端的 content_inner_encrypted(AES-GCM 密文的 hex) */
|
||
content_inner_encrypted: string;
|
||
/** 本次生成的助记词(用户需妥善保管,恢复时需任意 2 个分片) */
|
||
mnemonic: string[];
|
||
/** 三个分片:device / cloud / heir,可与后端返回的 server_shard 组合恢复助记词 */
|
||
shares: SSSShare[];
|
||
}
|
||
|
||
export interface CreateAssetPayloadResult {
|
||
title: string;
|
||
type: string;
|
||
private_key_shard: string;
|
||
content_inner_encrypted: string;
|
||
}
|
||
|
||
/**
|
||
* 生成金库:助记词 + SSS 分片 + 内层加密内容
|
||
* @param plaintext 要加密的明文(如遗产说明、账号密码等)
|
||
* @param wordList 助记词词表(与 sss 使用的词表一致)
|
||
* @param shareIndexForServer 哪个分片存后端,0=device, 1=cloud, 2=heir,默认 1(云端)
|
||
*/
|
||
export async function createVaultPayload(
|
||
plaintext: string,
|
||
wordList: readonly string[],
|
||
shareIndexForServer: 0 | 1 | 2 = 1
|
||
): Promise<CreateVaultPayloadResult> {
|
||
const { mnemonic, shares }: VaultKeyData = generateVaultKeys(wordList, 12);
|
||
const mnemonicPhrase = mnemonic.join(' ');
|
||
const key = await deriveKey(mnemonicPhrase);
|
||
const encrypted = await encryptDataGCM(key, plaintext);
|
||
const content_inner_encrypted = bytesToHex(encrypted);
|
||
const shareForServer = shares[shareIndexForServer];
|
||
const private_key_shard = serializeShare(shareForServer);
|
||
|
||
return {
|
||
private_key_shard,
|
||
content_inner_encrypted,
|
||
mnemonic,
|
||
shares,
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 生成可直接用于 POST /assets/create 的请求体(含 title / type)
|
||
*/
|
||
export async function createAssetPayload(
|
||
title: string,
|
||
plaintext: string,
|
||
wordList: readonly string[],
|
||
assetType: string = 'note',
|
||
shareIndexForServer: 0 | 1 | 2 = 1
|
||
): Promise<CreateAssetPayloadResult> {
|
||
const vault = await createVaultPayload(plaintext, wordList, shareIndexForServer);
|
||
return {
|
||
title,
|
||
type: assetType,
|
||
private_key_shard: vault.private_key_shard,
|
||
content_inner_encrypted: vault.content_inner_encrypted,
|
||
};
|
||
}
|