mirror of
https://github.com/tompro/sattle.git
synced 2026-10-26 01:49:58 +00:00
Formatting
This commit is contained in:
+55
-55
@@ -8,11 +8,11 @@
|
||||
// under different record ids, spent-wins) happens after decrypt in
|
||||
// bearers.ts's mergeBearers, exactly as with a file backup.
|
||||
|
||||
import type {RestoreResult} from '../storage/backup'
|
||||
import {applyBackup} from '../storage/backup'
|
||||
import {linkingPubKeyHex} from '../keys'
|
||||
import type { RestoreResult } from '../storage/backup';
|
||||
import { applyBackup } from '../storage/backup';
|
||||
import { linkingPubKeyHex } from '../keys';
|
||||
|
||||
import type {BackupPart, BackupPartPayload, NostrEvent} from './events'
|
||||
import type { BackupPart, BackupPartPayload, NostrEvent } from './events';
|
||||
import {
|
||||
BACKUP_EVENT_KIND,
|
||||
BACKUP_PARTS,
|
||||
@@ -21,18 +21,18 @@ import {
|
||||
deriveBackupKey,
|
||||
dTagOf,
|
||||
parseBackupEvent,
|
||||
} from './events'
|
||||
import type {BackupTransport} from './transport'
|
||||
import {defaultTransport} from './transport'
|
||||
} from './events';
|
||||
import type { BackupTransport } from './transport';
|
||||
import { defaultTransport } from './transport';
|
||||
|
||||
export type PublishBackupOptions = {
|
||||
transport?: BackupTransport
|
||||
createdAt?: number
|
||||
}
|
||||
transport?: BackupTransport;
|
||||
createdAt?: number;
|
||||
};
|
||||
|
||||
export type PublishBackupResult = {
|
||||
published: BackupPart[]
|
||||
}
|
||||
published: BackupPart[];
|
||||
};
|
||||
|
||||
// builds and publishes one event per part present in `parts`
|
||||
export const publishBackup = async (
|
||||
@@ -41,26 +41,26 @@ export const publishBackup = async (
|
||||
relays: string[],
|
||||
options: PublishBackupOptions = {},
|
||||
): Promise<PublishBackupResult> => {
|
||||
const at = options.createdAt ?? Math.floor(Date.now() / 1000)
|
||||
const present = BACKUP_PARTS.filter((part) => parts[part] !== undefined)
|
||||
if (present.length === 0) return {published: []}
|
||||
const transport = options.transport ?? (await defaultTransport())
|
||||
const published: BackupPart[] = []
|
||||
const at = options.createdAt ?? Math.floor(Date.now() / 1000);
|
||||
const present = BACKUP_PARTS.filter((part) => parts[part] !== undefined);
|
||||
if (present.length === 0) return { published: [] };
|
||||
const transport = options.transport ?? (await defaultTransport());
|
||||
const published: BackupPart[] = [];
|
||||
for (const part of present) {
|
||||
const payload = parts[part]
|
||||
if (payload === undefined) continue
|
||||
await transport.publish(relays, buildBackupEvent(secretKey, part, payload, at))
|
||||
published.push(part)
|
||||
const payload = parts[part];
|
||||
if (payload === undefined) continue;
|
||||
await transport.publish(relays, buildBackupEvent(secretKey, part, payload, at));
|
||||
published.push(part);
|
||||
}
|
||||
return {published}
|
||||
}
|
||||
return { published };
|
||||
};
|
||||
|
||||
export type FetchBackupOptions = {
|
||||
// the pubkey alone can fetch the ciphertext, but only the key holder
|
||||
// reads it - decryption is part of fetching
|
||||
secretKey: Uint8Array
|
||||
transport?: BackupTransport
|
||||
}
|
||||
secretKey: Uint8Array;
|
||||
transport?: BackupTransport;
|
||||
};
|
||||
|
||||
// fetches the newest valid event per d-tag and decrypts it. Honest relays
|
||||
// already replace addressable events, but a stale or misbehaving relay may
|
||||
@@ -71,49 +71,49 @@ export const fetchBackup = async (
|
||||
relays: string[],
|
||||
options: FetchBackupOptions,
|
||||
): Promise<Partial<BackupPartPayload>> => {
|
||||
const transport = options.transport ?? (await defaultTransport())
|
||||
const transport = options.transport ?? (await defaultTransport());
|
||||
const events = await transport.fetch(relays, {
|
||||
kinds: [BACKUP_EVENT_KIND],
|
||||
authors: [pubkey],
|
||||
})
|
||||
const byTag = new Map<string, NostrEvent[]>()
|
||||
});
|
||||
const byTag = new Map<string, NostrEvent[]>();
|
||||
for (const event of events) {
|
||||
const d = dTagOf(event)
|
||||
if (!d) continue
|
||||
const candidates = byTag.get(d)
|
||||
if (candidates) candidates.push(event)
|
||||
else byTag.set(d, [event])
|
||||
const d = dTagOf(event);
|
||||
if (!d) continue;
|
||||
const candidates = byTag.get(d);
|
||||
if (candidates) candidates.push(event);
|
||||
else byTag.set(d, [event]);
|
||||
}
|
||||
const parts: Partial<BackupPartPayload> = {}
|
||||
const parts: Partial<BackupPartPayload> = {};
|
||||
for (const candidates of byTag.values()) {
|
||||
// a hostile relay may serve a tampered "newest" copy - walk
|
||||
// newest-first and take the first that validates and decrypts
|
||||
candidates.sort((a, b) => b.created_at - a.created_at)
|
||||
candidates.sort((a, b) => b.created_at - a.created_at);
|
||||
for (const event of candidates) {
|
||||
const parsed = parseBackupEvent(options.secretKey, event)
|
||||
if (!parsed) continue
|
||||
const parsed = parseBackupEvent(options.secretKey, event);
|
||||
if (!parsed) continue;
|
||||
switch (parsed.part) {
|
||||
case 'notes':
|
||||
parts.notes = {bearers: parsed.bearers, nextByHost: parsed.nextByHost}
|
||||
break
|
||||
parts.notes = { bearers: parsed.bearers, nextByHost: parsed.nextByHost };
|
||||
break;
|
||||
case 'mints':
|
||||
parts.mints = parsed.trustedMints
|
||||
break
|
||||
parts.mints = parsed.trustedMints;
|
||||
break;
|
||||
case 'settings':
|
||||
parts.settings = parsed.settings
|
||||
break
|
||||
parts.settings = parsed.settings;
|
||||
break;
|
||||
}
|
||||
break
|
||||
break;
|
||||
}
|
||||
}
|
||||
return parts
|
||||
}
|
||||
return parts;
|
||||
};
|
||||
|
||||
export type NostrRestoreResult = RestoreResult & {
|
||||
// which d-tags carried a valid payload at all - lets the caller
|
||||
// distinguish "nothing backed up yet" from "restored an empty wallet"
|
||||
found: BackupPart[]
|
||||
}
|
||||
found: BackupPart[];
|
||||
};
|
||||
|
||||
// The restore path end to end: re-derive the backup key from the linking
|
||||
// key (the holder already re-entered the seed phrase to get that far),
|
||||
@@ -124,13 +124,13 @@ export type NostrRestoreResult = RestoreResult & {
|
||||
export const restoreFromNostr = async (
|
||||
linkingPrivKey: Uint8Array,
|
||||
relays: string[],
|
||||
options: {transport?: BackupTransport} = {},
|
||||
options: { transport?: BackupTransport } = {},
|
||||
): Promise<NostrRestoreResult> => {
|
||||
const secretKey = deriveBackupKey(linkingPrivKey)
|
||||
const secretKey = deriveBackupKey(linkingPrivKey);
|
||||
const parts = await fetchBackup(backupPubkey(secretKey), relays, {
|
||||
secretKey,
|
||||
transport: options.transport,
|
||||
})
|
||||
});
|
||||
const result = await applyBackup(
|
||||
{
|
||||
type: 'sattle-backup',
|
||||
@@ -142,9 +142,9 @@ export const restoreFromNostr = async (
|
||||
settings: parts.settings,
|
||||
},
|
||||
linkingPubKeyHex(linkingPrivKey),
|
||||
)
|
||||
);
|
||||
return {
|
||||
...result,
|
||||
found: BACKUP_PARTS.filter((part) => parts[part] !== undefined),
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user