@le-space/p2pass 0.1.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.
Files changed (46) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +258 -0
  3. package/dist/backup/registry-backup.d.ts +26 -0
  4. package/dist/backup/registry-backup.js +51 -0
  5. package/dist/identity/identity-service.d.ts +116 -0
  6. package/dist/identity/identity-service.js +524 -0
  7. package/dist/identity/mode-detector.d.ts +29 -0
  8. package/dist/identity/mode-detector.js +124 -0
  9. package/dist/identity/signing-preference.d.ts +30 -0
  10. package/dist/identity/signing-preference.js +55 -0
  11. package/dist/index.d.ts +15 -0
  12. package/dist/index.js +91 -0
  13. package/dist/p2p/setup.d.ts +48 -0
  14. package/dist/p2p/setup.js +283 -0
  15. package/dist/recovery/ipns-key.d.ts +41 -0
  16. package/dist/recovery/ipns-key.js +127 -0
  17. package/dist/recovery/manifest.d.ts +106 -0
  18. package/dist/recovery/manifest.js +243 -0
  19. package/dist/registry/device-registry.d.ts +122 -0
  20. package/dist/registry/device-registry.js +275 -0
  21. package/dist/registry/index.d.ts +3 -0
  22. package/dist/registry/index.js +46 -0
  23. package/dist/registry/manager.d.ts +76 -0
  24. package/dist/registry/manager.js +376 -0
  25. package/dist/registry/pairing-protocol.d.ts +61 -0
  26. package/dist/registry/pairing-protocol.js +653 -0
  27. package/dist/ucan/storacha-auth.d.ts +45 -0
  28. package/dist/ucan/storacha-auth.js +164 -0
  29. package/dist/ui/StorachaFab.svelte +134 -0
  30. package/dist/ui/StorachaFab.svelte.d.ts +23 -0
  31. package/dist/ui/StorachaIntegration.svelte +2467 -0
  32. package/dist/ui/StorachaIntegration.svelte.d.ts +23 -0
  33. package/dist/ui/fonts/dm-mono-400.ttf +0 -0
  34. package/dist/ui/fonts/dm-mono-500.ttf +0 -0
  35. package/dist/ui/fonts/dm-sans-400.ttf +0 -0
  36. package/dist/ui/fonts/dm-sans-500.ttf +0 -0
  37. package/dist/ui/fonts/dm-sans-600.ttf +0 -0
  38. package/dist/ui/fonts/dm-sans-700.ttf +0 -0
  39. package/dist/ui/fonts/epilogue-400.ttf +0 -0
  40. package/dist/ui/fonts/epilogue-500.ttf +0 -0
  41. package/dist/ui/fonts/epilogue-600.ttf +0 -0
  42. package/dist/ui/fonts/epilogue-700.ttf +0 -0
  43. package/dist/ui/fonts/storacha-fonts.css +152 -0
  44. package/dist/ui/storacha-backup.d.ts +44 -0
  45. package/dist/ui/storacha-backup.js +218 -0
  46. package/package.json +112 -0
@@ -0,0 +1,275 @@
1
+ /**
2
+ * Multi-Device Registry for OrbitDB WebAuthn
3
+ *
4
+ * Manages a KV store of registered devices, UCAN delegations, and encrypted
5
+ * Ed25519 archives using OrbitDBAccessController so write access can be
6
+ * dynamically granted to new devices.
7
+ *
8
+ * Key prefixes:
9
+ * (none) — device entries (keyed by sha256(credentialId))
10
+ * delegation: — UCAN delegation proofs
11
+ * archive: — encrypted Ed25519 archives
12
+ * keypair: — Ed25519 keypair metadata (publicKey + DID, no private key)
13
+ *
14
+ * Copied from orbitdb-identity-provider-webauthn-did/src/multi-device/device-registry.js
15
+ * and extended with delegation + archive + keypair storage.
16
+ */
17
+
18
+ import { OrbitDBAccessController } from '@orbitdb/core';
19
+
20
+ /**
21
+ * Convert P-256 x/y byte arrays from a WebAuthn attestation into JWK format.
22
+ * @param {Uint8Array} x - 32-byte x coordinate
23
+ * @param {Uint8Array} y - 32-byte y coordinate
24
+ * @returns {Object} JWK object
25
+ */
26
+ export function coseToJwk(x, y) {
27
+ const toBase64url = (bytes) =>
28
+ btoa(String.fromCharCode(...bytes))
29
+ .replace(/\+/g, '-')
30
+ .replace(/\//g, '_')
31
+ .replace(/=/g, '');
32
+
33
+ return {
34
+ kty: 'EC',
35
+ crv: 'P-256',
36
+ x: toBase64url(x),
37
+ y: toBase64url(y),
38
+ };
39
+ }
40
+
41
+ /**
42
+ * Hash a string to a 64-char lowercase hex key for DB storage.
43
+ * @param {string} input - string to hash
44
+ * @returns {Promise<string>} 64-char hex string
45
+ */
46
+ export async function hashCredentialId(input) {
47
+ const bytes = new TextEncoder().encode(input);
48
+ const hash = await crypto.subtle.digest('SHA-256', bytes);
49
+ return Array.from(new Uint8Array(hash))
50
+ .map((b) => b.toString(16).padStart(2, '0'))
51
+ .join('');
52
+ }
53
+
54
+ /**
55
+ * Open (or create) the multi-device registry KV database.
56
+ *
57
+ * @param {Object} orbitdb - OrbitDB instance
58
+ * @param {string} ownerIdentityId - Ed25519 DID of the device creating the registry
59
+ * @param {string} [address] - Existing DB address to reopen (for Device B)
60
+ * @returns {Promise<Object>} Opened OrbitDB KeyValue database
61
+ */
62
+ export async function openDeviceRegistry(orbitdb, ownerIdentityId, address = null) {
63
+ if (address) {
64
+ return await orbitdb.open(address, {
65
+ type: 'keyvalue',
66
+ sync: true,
67
+ });
68
+ }
69
+
70
+ return await orbitdb.open('multi-device-registry', {
71
+ type: 'keyvalue',
72
+ sync: true,
73
+ AccessController: OrbitDBAccessController({ write: [orbitdb.identity.id, ownerIdentityId] }),
74
+ });
75
+ }
76
+
77
+ // ---------------------------------------------------------------------------
78
+ // Device entries
79
+ // ---------------------------------------------------------------------------
80
+
81
+ /**
82
+ * Register a device entry in the registry.
83
+ * @param {Object} db - OrbitDB KV database
84
+ * @param {Object} entry - { credential_id, public_key, device_label, created_at, status, ed25519_did }
85
+ */
86
+ export async function registerDevice(db, entry) {
87
+ const key = await hashCredentialId(entry.credential_id);
88
+ const existing = await db.get(key);
89
+ if (existing) return;
90
+ await db.put(key, entry);
91
+ }
92
+
93
+ /**
94
+ * List all registered devices from the registry.
95
+ * @param {Object} db - OrbitDB KV database
96
+ * @returns {Promise<Array>} Array of device entry objects
97
+ */
98
+ export async function listDevices(db) {
99
+ const all = await db.all();
100
+ return all
101
+ .filter(
102
+ (e) =>
103
+ !e.key?.startsWith?.('delegation:') &&
104
+ !e.key?.startsWith?.('archive:') &&
105
+ !e.key?.startsWith?.('keypair:')
106
+ )
107
+ .map((e) => e.value);
108
+ }
109
+
110
+ /**
111
+ * Look up a device by its credential ID.
112
+ * @param {Object} db - OrbitDB KV database
113
+ * @param {string} credentialId - base64url credential ID
114
+ * @returns {Promise<Object|null>}
115
+ */
116
+ export async function getDeviceByCredentialId(db, credentialId) {
117
+ const key = await hashCredentialId(credentialId);
118
+ return (await db.get(key)) || null;
119
+ }
120
+
121
+ /**
122
+ * Look up a device by its Ed25519 DID.
123
+ * @param {Object} db - OrbitDB KV database
124
+ * @param {string} did - Ed25519 DID (did:key:z6Mk...)
125
+ * @returns {Promise<Object|null>}
126
+ */
127
+ export async function getDeviceByDID(db, did) {
128
+ const all = await db.all();
129
+ const found = all.find((e) => e.value.ed25519_did === did);
130
+ return found ? found.value : null;
131
+ }
132
+
133
+ /**
134
+ * Grant write access to a new device DID via OrbitDBAccessController.
135
+ * @param {Object} db - OrbitDB KV database (must use OrbitDBAccessController)
136
+ * @param {string} did - Ed25519 DID of the new device
137
+ */
138
+ export async function grantDeviceWriteAccess(db, did) {
139
+ await db.access.grant('write', did);
140
+ }
141
+
142
+ /**
143
+ * Revoke write access from a device DID and mark its registry entry as 'revoked'.
144
+ * @param {Object} db - OrbitDB KV database
145
+ * @param {string} did - Ed25519 DID to revoke
146
+ */
147
+ export async function revokeDeviceAccess(db, did) {
148
+ await db.access.revoke('write', did);
149
+ const entry = await getDeviceByDID(db, did);
150
+ if (entry) {
151
+ const key = await hashCredentialId(entry.credential_id);
152
+ await db.put(key, { ...entry, status: 'revoked' });
153
+ }
154
+ }
155
+
156
+ // ---------------------------------------------------------------------------
157
+ // UCAN delegation entries
158
+ // ---------------------------------------------------------------------------
159
+
160
+ /**
161
+ * Store a UCAN delegation in the registry.
162
+ * @param {Object} db - OrbitDB KV database
163
+ * @param {string} delegationBase64 - raw delegation string
164
+ * @param {string} [spaceDid] - Storacha space DID
165
+ * @param {string} [label] - human-readable label
166
+ */
167
+ export async function storeDelegationEntry(db, delegationBase64, spaceDid, label) {
168
+ const hash = await hashCredentialId(delegationBase64);
169
+ const key = `delegation:${hash}`;
170
+ await db.put(key, {
171
+ delegation: delegationBase64,
172
+ space_did: spaceDid || '',
173
+ label: label || 'default',
174
+ created_at: Date.now(),
175
+ });
176
+ }
177
+
178
+ /**
179
+ * List all stored UCAN delegations.
180
+ * @param {Object} db - OrbitDB KV database
181
+ * @returns {Promise<Array>}
182
+ */
183
+ export async function listDelegations(db) {
184
+ const all = await db.all();
185
+ return all.filter((e) => e.key?.startsWith?.('delegation:')).map((e) => e.value);
186
+ }
187
+
188
+ /**
189
+ * Get a specific delegation by its base64 string.
190
+ * @param {Object} db - OrbitDB KV database
191
+ * @param {string} delegationBase64
192
+ * @returns {Promise<Object|null>}
193
+ */
194
+ export async function getDelegation(db, delegationBase64) {
195
+ const hash = await hashCredentialId(delegationBase64);
196
+ return (await db.get(`delegation:${hash}`)) || null;
197
+ }
198
+
199
+ /**
200
+ * Remove a delegation from the registry.
201
+ * @param {Object} db - OrbitDB KV database
202
+ * @param {string} delegationBase64
203
+ */
204
+ export async function removeDelegation(db, delegationBase64) {
205
+ const hash = await hashCredentialId(delegationBase64);
206
+ await db.del(`delegation:${hash}`);
207
+ }
208
+
209
+ // ---------------------------------------------------------------------------
210
+ // Encrypted Ed25519 archive entries
211
+ // ---------------------------------------------------------------------------
212
+
213
+ /**
214
+ * Store an encrypted Ed25519 archive in the registry.
215
+ * @param {Object} db - OrbitDB KV database
216
+ * @param {string} did - Ed25519 DID
217
+ * @param {string} ciphertext - hex-encoded ciphertext
218
+ * @param {string} iv - hex-encoded IV
219
+ */
220
+ export async function storeArchiveEntry(db, did, ciphertext, iv) {
221
+ await db.put(`archive:${did}`, {
222
+ ciphertext,
223
+ iv,
224
+ did,
225
+ created_at: Date.now(),
226
+ });
227
+ }
228
+
229
+ /**
230
+ * Get an encrypted archive entry by DID.
231
+ * @param {Object} db - OrbitDB KV database
232
+ * @param {string} did
233
+ * @returns {Promise<Object|null>}
234
+ */
235
+ export async function getArchiveEntry(db, did) {
236
+ return (await db.get(`archive:${did}`)) || null;
237
+ }
238
+
239
+ // ---------------------------------------------------------------------------
240
+ // Keypair metadata entries
241
+ // ---------------------------------------------------------------------------
242
+
243
+ /**
244
+ * Store Ed25519 keypair metadata (no private key) in the registry.
245
+ * @param {Object} db - OrbitDB KV database
246
+ * @param {string} did - Ed25519 DID
247
+ * @param {string} publicKeyHex - hex-encoded public key
248
+ */
249
+ export async function storeKeypairEntry(db, did, publicKeyHex) {
250
+ await db.put(`keypair:${did}`, {
251
+ publicKey: publicKeyHex,
252
+ did,
253
+ created_at: Date.now(),
254
+ });
255
+ }
256
+
257
+ /**
258
+ * Get keypair metadata by DID.
259
+ * @param {Object} db - OrbitDB KV database
260
+ * @param {string} did
261
+ * @returns {Promise<Object|null>}
262
+ */
263
+ export async function getKeypairEntry(db, did) {
264
+ return (await db.get(`keypair:${did}`)) || null;
265
+ }
266
+
267
+ /**
268
+ * List all stored keypair entries.
269
+ * @param {Object} db - OrbitDB KV database
270
+ * @returns {Promise<Array>}
271
+ */
272
+ export async function listKeypairs(db) {
273
+ const all = await db.all();
274
+ return all.filter((e) => e.key?.startsWith?.('keypair:')).map((e) => e.value);
275
+ }
@@ -0,0 +1,3 @@
1
+ export { MultiDeviceManager } from "./manager.js";
2
+ export { openDeviceRegistry, registerDevice, listDevices, getDeviceByCredentialId, getDeviceByDID, grantDeviceWriteAccess, revokeDeviceAccess, hashCredentialId, coseToJwk, storeDelegationEntry, listDelegations, getDelegation, removeDelegation, storeArchiveEntry, getArchiveEntry, storeKeypairEntry, getKeypairEntry, listKeypairs } from "./device-registry.js";
3
+ export { LINK_DEVICE_PROTOCOL, registerLinkDeviceHandler, unregisterLinkDeviceHandler, sendPairingRequest, detectDeviceLabel, sortPairingMultiaddrs, filterPairingDialMultiaddrs, pairingFlow, PAIRING_HINT_ADDR_CAP } from "./pairing-protocol.js";
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Registry — Multi-device linking, credential storage, and UCAN delegation sync.
3
+ *
4
+ * Re-exports device registry, pairing protocol, and manager.
5
+ */
6
+
7
+ // Device registry + extended storage (delegations, archives, keypairs)
8
+ export {
9
+ openDeviceRegistry,
10
+ registerDevice,
11
+ listDevices,
12
+ getDeviceByCredentialId,
13
+ getDeviceByDID,
14
+ grantDeviceWriteAccess,
15
+ revokeDeviceAccess,
16
+ hashCredentialId,
17
+ coseToJwk,
18
+ // Delegation storage
19
+ storeDelegationEntry,
20
+ listDelegations,
21
+ getDelegation,
22
+ removeDelegation,
23
+ // Archive storage
24
+ storeArchiveEntry,
25
+ getArchiveEntry,
26
+ // Keypair metadata storage
27
+ storeKeypairEntry,
28
+ getKeypairEntry,
29
+ listKeypairs,
30
+ } from './device-registry.js';
31
+
32
+ // Pairing protocol
33
+ export {
34
+ LINK_DEVICE_PROTOCOL,
35
+ registerLinkDeviceHandler,
36
+ unregisterLinkDeviceHandler,
37
+ sendPairingRequest,
38
+ detectDeviceLabel,
39
+ sortPairingMultiaddrs,
40
+ filterPairingDialMultiaddrs,
41
+ pairingFlow,
42
+ PAIRING_HINT_ADDR_CAP,
43
+ } from './pairing-protocol.js';
44
+
45
+ // Manager
46
+ export { MultiDeviceManager } from './manager.js';
@@ -0,0 +1,76 @@
1
+ export class MultiDeviceManager {
2
+ /**
3
+ * @param {string|{ peerId: string, multiaddrs?: string[] }} payload
4
+ * @returns {{ peerId: string, multiaddrs: string[] }}
5
+ */
6
+ static _normalizeLinkPayload(payload: string | {
7
+ peerId: string;
8
+ multiaddrs?: string[];
9
+ }): {
10
+ peerId: string;
11
+ multiaddrs: string[];
12
+ };
13
+ static create(config: any): Promise<MultiDeviceManager>;
14
+ static createFromExisting(config: any): Promise<MultiDeviceManager>;
15
+ _credential: any;
16
+ _orbitdb: any;
17
+ _ipfs: any;
18
+ _libp2p: any;
19
+ _identity: any;
20
+ _devicesDb: Object | null;
21
+ _dbAddress: any;
22
+ _onPairingRequest: any;
23
+ _onDeviceLinked: any;
24
+ _onDeviceJoined: any;
25
+ _listenersSetup: boolean;
26
+ _init(config: any): Promise<void>;
27
+ _getPublicKey(): Object | null;
28
+ _finalizeDb(): Promise<void>;
29
+ createNew(): Promise<{
30
+ dbAddress: any;
31
+ identity: any;
32
+ }>;
33
+ _setupSyncListeners(): Promise<void>;
34
+ _waitForEntries(timeoutMs?: number): Promise<void>;
35
+ openExistingDb(dbAddress: any): Promise<{
36
+ dbAddress: any;
37
+ identity: any;
38
+ }>;
39
+ /**
40
+ * Link to Device A by peer id. Uses addresses already in libp2p’s peer store (e.g. from pubsub
41
+ * discovery + autodial). Optional legacy shape: `{ peerId, multiaddrs }` for explicit dials.
42
+ * @param {string|{ peerId: string, multiaddrs?: string[] }} qrPayload
43
+ */
44
+ linkToDevice(qrPayload: string | {
45
+ peerId: string;
46
+ multiaddrs?: string[];
47
+ }): Promise<{
48
+ type: "rejected";
49
+ reason: string;
50
+ } | {
51
+ type: string;
52
+ dbAddress: any;
53
+ }>;
54
+ getDevicesDb(): Object | null;
55
+ getPeerInfo(): {
56
+ peerId: any;
57
+ multiaddrs: any[];
58
+ };
59
+ listDevices(): Promise<any[]>;
60
+ syncDevices(): Promise<void>;
61
+ revokeDevice(did: any): Promise<void>;
62
+ processIncomingPairingRequest(requestMsg: any): Promise<{
63
+ type: string;
64
+ orbitdbAddress: any;
65
+ reason?: undefined;
66
+ } | {
67
+ type: string;
68
+ reason: string;
69
+ orbitdbAddress?: undefined;
70
+ }>;
71
+ /** Get the underlying registry DB (for extended operations like delegation storage). */
72
+ getRegistryDb(): Object | null;
73
+ /** Get the registry DB address. */
74
+ getDbAddress(): any;
75
+ close(): Promise<void>;
76
+ }