mirror of
https://github.com/BigBodyCobain/Shadowbroker.git
synced 2026-07-30 23:47:27 +02:00
117 lines
2.2 KiB
TypeScript
117 lines
2.2 KiB
TypeScript
import { deriveSharedSecret, getNodeIdentity } from '@/mesh/meshIdentity';
|
|
import { hmacSha256 } from '@/mesh/meshDeadDrop';
|
|
import { deriveWormholeSasPhrase, isWormholeReady } from '@/mesh/wormholeIdentityClient';
|
|
|
|
const SAS_WORDS = [
|
|
'able',
|
|
'acid',
|
|
'aged',
|
|
'also',
|
|
'area',
|
|
'army',
|
|
'atom',
|
|
'aunt',
|
|
'away',
|
|
'baby',
|
|
'back',
|
|
'bake',
|
|
'ball',
|
|
'band',
|
|
'bank',
|
|
'base',
|
|
'bean',
|
|
'bear',
|
|
'belt',
|
|
'bird',
|
|
'book',
|
|
'boom',
|
|
'boot',
|
|
'boss',
|
|
'bowl',
|
|
'burn',
|
|
'cafe',
|
|
'calm',
|
|
'camp',
|
|
'card',
|
|
'cash',
|
|
'cell',
|
|
'chat',
|
|
'city',
|
|
'clay',
|
|
'cloud',
|
|
'coin',
|
|
'cool',
|
|
'crew',
|
|
'data',
|
|
'dawn',
|
|
'desk',
|
|
'dome',
|
|
'door',
|
|
'dust',
|
|
'eagle',
|
|
'east',
|
|
'easy',
|
|
'echo',
|
|
'edge',
|
|
'envy',
|
|
'fair',
|
|
'farm',
|
|
'fast',
|
|
'file',
|
|
'flag',
|
|
'foam',
|
|
'fold',
|
|
'food',
|
|
'game',
|
|
'gate',
|
|
'gear',
|
|
'glow',
|
|
'gold',
|
|
];
|
|
|
|
function sasContext(peerId: string): string | null {
|
|
const identity = getNodeIdentity();
|
|
if (!identity) return null;
|
|
const ids = [identity.nodeId, peerId].sort().join('|');
|
|
return ids;
|
|
}
|
|
|
|
function bytesToWords(bytes: Uint8Array, count: number): string[] {
|
|
const out: string[] = [];
|
|
let acc = 0;
|
|
let accBits = 0;
|
|
for (const b of bytes) {
|
|
acc = (acc << 8) | b;
|
|
accBits += 8;
|
|
while (accBits >= 6 && out.length < count) {
|
|
const idx = (acc >> (accBits - 6)) & 0x3f;
|
|
out.push(SAS_WORDS[idx]);
|
|
accBits -= 6;
|
|
}
|
|
if (out.length >= count) break;
|
|
}
|
|
return out;
|
|
}
|
|
|
|
export async function deriveSasPhrase(
|
|
peerId: string,
|
|
peerDhPub: string,
|
|
words: number = 8,
|
|
peerRef?: string,
|
|
): Promise<string> {
|
|
const resolvedPeerRef = String(peerRef || peerId || '').trim();
|
|
if (await isWormholeReady()) {
|
|
const result = await deriveWormholeSasPhrase(peerId, peerDhPub, words, resolvedPeerRef).catch(() => null);
|
|
if (result?.ok && result.phrase) {
|
|
return String(result.phrase || '');
|
|
}
|
|
}
|
|
const ctx = sasContext(resolvedPeerRef);
|
|
if (!ctx) return '';
|
|
const secret = await deriveSharedSecret(peerDhPub);
|
|
const digest = await hmacSha256(secret, `sb_sas|v1|${ctx}`);
|
|
const bytes = new Uint8Array(digest);
|
|
const phrase = bytesToWords(bytes, words);
|
|
return phrase.join(' ');
|
|
}
|