@abraca/dabra 1.1.2 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/abracadabra-provider.cjs +313 -143
- package/dist/abracadabra-provider.cjs.map +1 -1
- package/dist/abracadabra-provider.esm.js +313 -143
- package/dist/abracadabra-provider.esm.js.map +1 -1
- package/dist/index.d.ts +81 -43
- package/package.json +1 -1
- package/src/BackgroundSyncManager.ts +2 -2
- package/src/CryptoIdentityKeystore.ts +335 -203
- package/src/IdentityDoc.ts +2 -2
- package/src/webrtc/AbracadabraWebRTC.ts +61 -29
- package/src/webrtc/types.ts +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -531,72 +531,105 @@ declare class AbracadabraClient {
|
|
|
531
531
|
/**
|
|
532
532
|
* CryptoIdentityKeystore
|
|
533
533
|
*
|
|
534
|
-
* Per-
|
|
535
|
-
*
|
|
534
|
+
* Per-user Ed25519 keypair derived deterministically from a synced WebAuthn
|
|
535
|
+
* passkey's PRF extension output. The same passkey on any device produces the
|
|
536
|
+
* same identity — no private key storage needed.
|
|
536
537
|
*
|
|
537
|
-
*
|
|
538
|
-
*
|
|
539
|
-
* credential, and stores the ciphertext in IndexedDB.
|
|
538
|
+
* Derivation chain:
|
|
539
|
+
* Synced Passkey → PRF(constant salt) → HKDF-SHA256 → Ed25519 seed → keypair
|
|
540
540
|
*
|
|
541
|
-
*
|
|
541
|
+
* IndexedDB is used only as a lightweight cache for the public key and
|
|
542
|
+
* credential ID. Loss of IndexedDB is non-catastrophic — a passkey assertion
|
|
543
|
+
* re-derives everything.
|
|
544
|
+
*
|
|
545
|
+
* Dependencies: @noble/ed25519, @noble/hashes (for HKDF), @noble/curves (for X25519)
|
|
542
546
|
*/
|
|
543
547
|
declare class CryptoIdentityKeystore {
|
|
544
548
|
/**
|
|
545
|
-
*
|
|
546
|
-
*
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
*
|
|
551
|
-
*
|
|
549
|
+
* Check whether the platform supports WebAuthn with PRF extension.
|
|
550
|
+
* Call this before offering the "Secure with Passkey" option.
|
|
551
|
+
*/
|
|
552
|
+
static isPrfAvailable(): Promise<boolean>;
|
|
553
|
+
/**
|
|
554
|
+
* Create a synced discoverable passkey and derive the Ed25519 identity from
|
|
555
|
+
* its PRF output. The passkey is stored in the platform credential manager
|
|
556
|
+
* (e.g. iCloud Keychain) and syncs across devices automatically.
|
|
552
557
|
*
|
|
553
|
-
*
|
|
554
|
-
*
|
|
555
|
-
* @param rpName - Human-readable relying party name.
|
|
558
|
+
* Returns the base64url-encoded public key, X25519 public key, and credential ID.
|
|
559
|
+
* The caller must register the public key with the server.
|
|
556
560
|
*/
|
|
557
561
|
register(username: string, rpId: string, rpName: string): Promise<{
|
|
558
562
|
publicKey: string;
|
|
559
563
|
x25519PublicKey: string;
|
|
564
|
+
credentialId: string;
|
|
560
565
|
}>;
|
|
561
566
|
/**
|
|
562
|
-
* Sign a base64url-encoded challenge using the
|
|
563
|
-
*
|
|
564
|
-
* This triggers a WebAuthn assertion (biometric / PIN prompt) to unlock the
|
|
565
|
-
* private key via PRF → HKDF → AES-GCM decryption. The private key is
|
|
566
|
-
* wiped from memory after signing.
|
|
567
|
+
* Sign a base64url-encoded challenge using the Ed25519 key derived from
|
|
568
|
+
* a passkey assertion. Triggers a WebAuthn prompt (biometric / PIN).
|
|
567
569
|
*
|
|
568
570
|
* @param challengeB64 - base64url-encoded challenge bytes from the server.
|
|
571
|
+
* @param credentialIdHint - optional credential ID to select a specific passkey.
|
|
569
572
|
* @returns base64url-encoded Ed25519 signature (64 bytes).
|
|
570
573
|
*/
|
|
571
|
-
sign(challengeB64: string): Promise<string>;
|
|
572
|
-
/** Returns the stored base64url public key, or null if no identity exists. */
|
|
573
|
-
getPublicKey(): Promise<string | null>;
|
|
574
|
+
sign(challengeB64: string, credentialIdHint?: string): Promise<string>;
|
|
574
575
|
/**
|
|
575
|
-
* Returns the
|
|
576
|
+
* Returns the cached base64url public key, or null if no identity is cached.
|
|
576
577
|
*
|
|
577
|
-
*
|
|
578
|
-
*
|
|
579
|
-
* a
|
|
578
|
+
* Does NOT trigger a WebAuthn prompt. If the cache is empty (e.g. IndexedDB
|
|
579
|
+
* cleared), returns null — the identity can be recovered via sign() or
|
|
580
|
+
* a fresh register() with the same synced passkey.
|
|
580
581
|
*/
|
|
581
|
-
|
|
582
|
-
/**
|
|
582
|
+
getPublicKey(credentialIdHint?: string): Promise<string | null>;
|
|
583
|
+
/**
|
|
584
|
+
* Returns the locally-cached username label, or null if no identity is cached.
|
|
585
|
+
*/
|
|
586
|
+
getUsername(credentialIdHint?: string): Promise<string | null>;
|
|
587
|
+
/**
|
|
588
|
+
* Updates the cached username for a given credential (or the first cached identity).
|
|
589
|
+
* Call this after the user sets/changes their display name so it persists across devices.
|
|
590
|
+
*/
|
|
591
|
+
setUsername(username: string, credentialIdHint?: string): Promise<void>;
|
|
592
|
+
/** Returns true if an identity is cached in IndexedDB. */
|
|
583
593
|
hasIdentity(): Promise<boolean>;
|
|
584
|
-
/** Remove
|
|
594
|
+
/** Remove cached identity record(s) from IndexedDB. The passkey itself
|
|
595
|
+
* remains in the platform credential store. */
|
|
585
596
|
clear(): Promise<void>;
|
|
586
597
|
/**
|
|
587
|
-
* Returns the X25519 public key derived from the
|
|
588
|
-
* Does NOT require WebAuthn — computed from the
|
|
589
|
-
*
|
|
590
|
-
* since nobleEd25519Curves.utils.toMontgomery only needs the public key.
|
|
591
|
-
* Returns null if no identity is stored.
|
|
598
|
+
* Returns the X25519 public key derived from the cached Ed25519 public key.
|
|
599
|
+
* Does NOT require WebAuthn — computed from the cached public key only.
|
|
600
|
+
* Returns null if no identity is cached.
|
|
592
601
|
*/
|
|
593
602
|
getX25519PublicKey(): Promise<Uint8Array | null>;
|
|
594
603
|
/**
|
|
595
|
-
* Returns the X25519 private key derived from the
|
|
596
|
-
* Requires WebAuthn assertion to
|
|
604
|
+
* Returns the X25519 private key derived from the Ed25519 seed.
|
|
605
|
+
* Requires a WebAuthn assertion to get the PRF output.
|
|
597
606
|
* The caller MUST wipe the returned Uint8Array after use.
|
|
598
607
|
*/
|
|
599
|
-
getX25519PrivateKey(): Promise<Uint8Array>;
|
|
608
|
+
getX25519PrivateKey(credentialIdHint?: string): Promise<Uint8Array>;
|
|
609
|
+
/**
|
|
610
|
+
* Trigger a WebAuthn assertion to derive (or re-derive) the identity and
|
|
611
|
+
* update the IndexedDB cache. Returns the public key and credential ID.
|
|
612
|
+
*
|
|
613
|
+
* Use this when the cache is empty but you need the public key before
|
|
614
|
+
* signing (e.g. to send it to the server for the challenge request).
|
|
615
|
+
*/
|
|
616
|
+
deriveIdentity(credentialIdHint?: string): Promise<{
|
|
617
|
+
publicKey: string;
|
|
618
|
+
credentialId: string;
|
|
619
|
+
}>;
|
|
620
|
+
/**
|
|
621
|
+
* List all cached credential IDs. Useful for account switching UI.
|
|
622
|
+
*/
|
|
623
|
+
listCachedIdentities(): Promise<{
|
|
624
|
+
credentialId: string;
|
|
625
|
+
publicKey: string;
|
|
626
|
+
username: string;
|
|
627
|
+
}[]>;
|
|
628
|
+
/**
|
|
629
|
+
* Perform a WebAuthn assertion with PRF, derive the Ed25519 seed, and
|
|
630
|
+
* update the IndexedDB cache. Returns the seed (caller MUST wipe it).
|
|
631
|
+
*/
|
|
632
|
+
private _assertAndDerive;
|
|
600
633
|
}
|
|
601
634
|
//#endregion
|
|
602
635
|
//#region packages/provider/src/DocKeyManager.d.ts
|
|
@@ -1725,7 +1758,7 @@ interface BackgroundSyncManagerOptions {
|
|
|
1725
1758
|
syncTimeout?: number;
|
|
1726
1759
|
/** Pre-cache file blobs after syncing a doc. Default: true. */
|
|
1727
1760
|
prefetchFiles?: boolean;
|
|
1728
|
-
/** Delay (ms) between starting each doc sync to avoid server pressure. Default:
|
|
1761
|
+
/** Delay (ms) between starting each doc sync to avoid server pressure. Default: 200. */
|
|
1729
1762
|
throttleMs?: number;
|
|
1730
1763
|
/** Max retries for failed docs within a single syncAll() run. Default: 2. */
|
|
1731
1764
|
maxRetries?: number;
|
|
@@ -2032,7 +2065,7 @@ interface AbracadabraWebRTCConfiguration {
|
|
|
2032
2065
|
* When provided, all data channel messages (except key-exchange) are
|
|
2033
2066
|
* encrypted with AES-256-GCM using X25519 ECDH-derived session keys.
|
|
2034
2067
|
*/
|
|
2035
|
-
e2ee?: E2EEIdentity;
|
|
2068
|
+
e2ee?: E2EEIdentity | (() => Promise<E2EEIdentity>);
|
|
2036
2069
|
/** WebSocket polyfill for signaling (e.g. for Node.js). */
|
|
2037
2070
|
WebSocketPolyfill?: any;
|
|
2038
2071
|
}
|
|
@@ -2093,6 +2126,9 @@ declare class AbracadabraWebRTC extends EventEmitter {
|
|
|
2093
2126
|
private fileChannels;
|
|
2094
2127
|
private e2eeChannels;
|
|
2095
2128
|
private readonly config;
|
|
2129
|
+
/** Cached resolved E2EE identity (lazily resolved from factory on first peer connect). */
|
|
2130
|
+
private _resolvedE2ee;
|
|
2131
|
+
private _resolveE2eePromise;
|
|
2096
2132
|
readonly peers: Map<string, PeerState>;
|
|
2097
2133
|
localPeerId: string | null;
|
|
2098
2134
|
isConnected: boolean;
|
|
@@ -2129,6 +2165,8 @@ declare class AbracadabraWebRTC extends EventEmitter {
|
|
|
2129
2165
|
private removePeer;
|
|
2130
2166
|
private removeAllPeers;
|
|
2131
2167
|
private createPeerConnection;
|
|
2168
|
+
/** Resolve the E2EE identity, supporting both pre-resolved objects and lazy factories. */
|
|
2169
|
+
private resolveE2ee;
|
|
2132
2170
|
private attachDataHandlers;
|
|
2133
2171
|
private startDataSync;
|
|
2134
2172
|
private initiateConnection;
|
|
@@ -2502,8 +2540,8 @@ interface IdentityDocConfiguration {
|
|
|
2502
2540
|
*/
|
|
2503
2541
|
webrtc?: {
|
|
2504
2542
|
/** Server URL to use for signaling (any connected server works). */signalingServerUrl: string; /** Token for the signaling server. */
|
|
2505
|
-
token: string | (() => string) | (() => Promise<string>); /** E2EE identity for the data channel. */
|
|
2506
|
-
e2ee?: E2EEIdentity; /** ICE servers. */
|
|
2543
|
+
token: string | (() => string) | (() => Promise<string>); /** E2EE identity for the data channel. Accepts a factory for lazy derivation. */
|
|
2544
|
+
e2ee?: E2EEIdentity | (() => Promise<E2EEIdentity>); /** ICE servers. */
|
|
2507
2545
|
iceServers?: RTCIceServer[];
|
|
2508
2546
|
};
|
|
2509
2547
|
/** Disable IndexedDB offline store. */
|
package/package.json
CHANGED
|
@@ -38,7 +38,7 @@ export interface BackgroundSyncManagerOptions {
|
|
|
38
38
|
syncTimeout?: number;
|
|
39
39
|
/** Pre-cache file blobs after syncing a doc. Default: true. */
|
|
40
40
|
prefetchFiles?: boolean;
|
|
41
|
-
/** Delay (ms) between starting each doc sync to avoid server pressure. Default:
|
|
41
|
+
/** Delay (ms) between starting each doc sync to avoid server pressure. Default: 200. */
|
|
42
42
|
throttleMs?: number;
|
|
43
43
|
/** Max retries for failed docs within a single syncAll() run. Default: 2. */
|
|
44
44
|
maxRetries?: number;
|
|
@@ -100,7 +100,7 @@ export class BackgroundSyncManager extends EventEmitter {
|
|
|
100
100
|
concurrency: opts?.concurrency ?? 2,
|
|
101
101
|
syncTimeout: opts?.syncTimeout ?? 15_000,
|
|
102
102
|
prefetchFiles: opts?.prefetchFiles ?? true,
|
|
103
|
-
throttleMs: opts?.throttleMs ??
|
|
103
|
+
throttleMs: opts?.throttleMs ?? 200,
|
|
104
104
|
maxRetries: opts?.maxRetries ?? 2,
|
|
105
105
|
};
|
|
106
106
|
|