w3pk 0.10.2 → 0.10.4
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/README.md +1 -8
- package/dist/chainlist/index.d.mts +96 -0
- package/dist/chainlist/index.d.ts +96 -0
- package/dist/index.d.mts +237 -113
- package/dist/index.d.ts +237 -113
- package/dist/index.js +31 -31
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +31 -31
- package/dist/index.mjs.map +1 -1
- package/dist/zk/index.js +3 -3
- package/dist/zk/index.js.map +1 -1
- package/dist/zk/index.mjs +4 -4
- package/dist/zk/index.mjs.map +1 -1
- package/dist/zk/utils.js +3 -3
- package/dist/zk/utils.js.map +1 -1
- package/dist/zk/utils.mjs +3 -3
- package/dist/zk/utils.mjs.map +1 -1
- package/docs/API_REFERENCE.md +191 -38
- package/docs/ARCHITECTURE.md +14 -13
- package/docs/BROWSER_COMPATIBILITY.md +24 -0
- package/docs/INTEGRATION_GUIDELINES.md +45 -20
- package/docs/PORTABILITY.md +66 -0
- package/docs/POST_QUANTUM.md +236 -1468
- package/docs/QUICK_START.md +4 -4
- package/docs/RECOVERY.md +93 -49
- package/docs/SECURITY.md +65 -58
- package/docs/notes/IFRAME_IMPLEMENTATION_PLAN.md +197 -0
- package/docs/notes/JULY_13_ROADMAP.md +29 -0
- package/docs/notes/NOTES.md +333 -0
- package/docs/notes/SIWE_IMPLEMENTATION.md +129 -0
- package/docs/notes/SYNCING_ACROSS_DEVICES.md +127 -0
- package/docs/notes/ethereum-post-quantum-roadmap.md +213 -0
- package/docs/notes/wulong-building-finding.md +109 -0
- package/package.json +43 -25
|
@@ -36,13 +36,13 @@ await w3pk.getAddress()
|
|
|
36
36
|
|
|
37
37
|
### Don't Import Internal Classes
|
|
38
38
|
|
|
39
|
-
Internal implementation classes like `WalletSigner`, `SessionManager`, `
|
|
39
|
+
Internal implementation classes like `WalletSigner`, `SessionManager`, `LocalStorageWalletStorage`, etc. are **not part of the public API** and may change without notice:
|
|
40
40
|
|
|
41
41
|
```typescript
|
|
42
42
|
// ❌ Don't do this - internal APIs
|
|
43
43
|
import { WalletSigner } from 'w3pk/wallet/signing'
|
|
44
44
|
import { SessionManager } from 'w3pk/core/session'
|
|
45
|
-
import {
|
|
45
|
+
import { LocalStorageWalletStorage } from 'w3pk/wallet/storage'
|
|
46
46
|
|
|
47
47
|
// ✅ Do this instead - public SDK API
|
|
48
48
|
import { createWeb3Passkey } from 'w3pk'
|
|
@@ -90,9 +90,9 @@ const auth2 = await w3pk.signAuthorization({
|
|
|
90
90
|
```typescript
|
|
91
91
|
// ❌ Don't use internal WalletSigner class directly
|
|
92
92
|
import { WalletSigner } from 'w3pk/wallet/signing'
|
|
93
|
-
import {
|
|
93
|
+
import { LocalStorageWalletStorage } from 'w3pk/wallet/storage'
|
|
94
94
|
|
|
95
|
-
const storage = new
|
|
95
|
+
const storage = new LocalStorageWalletStorage()
|
|
96
96
|
const signer = new WalletSigner(storage)
|
|
97
97
|
|
|
98
98
|
// This bypasses session management and requires manual credential handling
|
|
@@ -120,6 +120,7 @@ await signer.signAuthorization(
|
|
|
120
120
|
|
|
121
121
|
**Backup & Recovery:**
|
|
122
122
|
- `createBackupFile()` - Create encrypted backup
|
|
123
|
+
- `confirmRecoveryPhraseBackup()` - Record that the user wrote down the recovery phrase
|
|
123
124
|
- `restoreFromBackupFile()` - Restore from backup
|
|
124
125
|
- `setupSocialRecovery()` - Split backup among guardians
|
|
125
126
|
- `recoverFromGuardians()` - Recover from guardian shares
|
|
@@ -696,6 +697,8 @@ const result = await w3pk.signMessage(message, {
|
|
|
696
697
|
})
|
|
697
698
|
```
|
|
698
699
|
|
|
700
|
+
SIWE works in STANDARD, STRICT and YOLO modes; PRIMARY mode throws. Get the address with the same mode and tag you sign with. In production, have the server issue the nonce and tie it to the address, as EIP-4361 recommends; see [examples/siwe-login.ts](../examples/siwe-login.ts).
|
|
701
|
+
|
|
699
702
|
**Use for:**
|
|
700
703
|
- Web3 authentication flows
|
|
701
704
|
- App login
|
|
@@ -1220,23 +1223,46 @@ async function promptBackupOptions() {
|
|
|
1220
1223
|
|
|
1221
1224
|
### Allow Users Multiple Backup Options
|
|
1222
1225
|
|
|
1223
|
-
**Critical:** Users should set up at least one backup method immediately after registration.
|
|
1226
|
+
**Critical:** Users should set up at least one backup method immediately after registration. Browser storage can be wiped (eviction, Safari's 7-day cap, clearing site data), and a wallet without a backup is then lost for good.
|
|
1227
|
+
|
|
1228
|
+
`evictionRisk` tells you whether this browser is likely to wipe the wallet: it is `true` on WebKit (every iOS browser, Safari and other WebKit browsers on desktop) in a tab whose storage is not persisted, and `false` in a home-screen app, once storage is persisted, and on Chromium and Firefox. Use it to choose how hard to push:
|
|
1229
|
+
|
|
1230
|
+
- `!hasBackup && evictionRisk`: block the app until the user backs up
|
|
1231
|
+
- `!hasBackup` otherwise: show a dismissible banner
|
|
1232
|
+
- On iOS, also suggest "Add to Home Screen": home-screen apps are exempt from Safari's 7-day cap
|
|
1224
1233
|
|
|
1225
1234
|
```typescript
|
|
1226
|
-
// ✅
|
|
1227
|
-
|
|
1228
|
-
const status = await w3pk.getBackupStatus()
|
|
1235
|
+
// ✅ Ask for a backup right after registration
|
|
1236
|
+
const { hasBackup, evictionRisk } = await w3pk.register({ username })
|
|
1229
1237
|
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1238
|
+
if (!hasBackup) {
|
|
1239
|
+
// Blocking where the browser may wipe the wallet, dismissible otherwise
|
|
1240
|
+
// "Back up now": a backup file, or the recovery phrase written down
|
|
1241
|
+
const choice = await showBackupNowPrompt({ blocking: evictionRisk })
|
|
1234
1242
|
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1243
|
+
if (choice === 'file') {
|
|
1244
|
+
const { blob, filename } = await w3pk.createBackupFile('password', password)
|
|
1245
|
+
downloadFile(blob, filename)
|
|
1246
|
+
} else if (choice === 'phrase') {
|
|
1247
|
+
await showRecoveryPhrase()
|
|
1248
|
+
await w3pk.confirmRecoveryPhraseBackup()
|
|
1238
1249
|
}
|
|
1239
1250
|
}
|
|
1251
|
+
|
|
1252
|
+
// ✅ Keep warning while no backup exists
|
|
1253
|
+
async function checkBackup() {
|
|
1254
|
+
const status = await w3pk.getBackupStatus()
|
|
1255
|
+
|
|
1256
|
+
if (!status.hasBackup && status.evictionRisk) {
|
|
1257
|
+
showBackupGate() // blocking; on iOS, suggest "Add to Home Screen"
|
|
1258
|
+
} else if (!status.hasBackup) {
|
|
1259
|
+
showBackupWarning() // the score is capped at 20 ('vulnerable')
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
console.log('Security Score:', status.securityScore.total)
|
|
1263
|
+
console.log('Backup methods:', status.methods) // 'file' | 'qr' | 'phrase'
|
|
1264
|
+
console.log('Last backup:', status.lastBackupAt)
|
|
1265
|
+
}
|
|
1240
1266
|
```
|
|
1241
1267
|
|
|
1242
1268
|
### Three-Layer Backup Strategy
|
|
@@ -1252,7 +1278,7 @@ Encourage users to enable multiple backup methods:
|
|
|
1252
1278
|
// - Microsoft Account (Windows/Edge)
|
|
1253
1279
|
|
|
1254
1280
|
const status = await w3pk.getBackupStatus()
|
|
1255
|
-
if (status.
|
|
1281
|
+
if (status.passkeySync.enabled) {
|
|
1256
1282
|
console.log('✅ Passkey synced to cloud')
|
|
1257
1283
|
}
|
|
1258
1284
|
```
|
|
@@ -1316,11 +1342,10 @@ async function setupSocialRecovery() {
|
|
|
1316
1342
|
// Check backup status regularly
|
|
1317
1343
|
async function checkBackupReminder() {
|
|
1318
1344
|
const status = await w3pk.getBackupStatus()
|
|
1319
|
-
const daysSinceRegistration = calculateDaysSince(
|
|
1345
|
+
const daysSinceRegistration = calculateDaysSince(registeredAt) // tracked by your app
|
|
1320
1346
|
|
|
1321
1347
|
// Remind users who haven't set up backup
|
|
1322
|
-
if (!status.
|
|
1323
|
-
!status.securityScore.hasSocialRecovery) {
|
|
1348
|
+
if (!status.hasBackup) {
|
|
1324
1349
|
|
|
1325
1350
|
if (daysSinceRegistration === 1) {
|
|
1326
1351
|
showBackupReminder('urgent')
|
|
@@ -1413,7 +1438,7 @@ const strictWallet = await w3pk.deriveWallet('STRICT')
|
|
|
1413
1438
|
|
|
1414
1439
|
**Persistent Session Security:**
|
|
1415
1440
|
- STANDARD / YOLO: persistent sessions allowed. STRICT: ❌ NEVER allowed.
|
|
1416
|
-
- Time-limited expiration; origin-isolated via
|
|
1441
|
+
- Time-limited expiration; origin-isolated via localStorage.
|
|
1417
1442
|
- ⚠️ The at-rest key is derived from **public** credential metadata in the same browser profile, not an authenticator secret — a persistent session is **decryptable by anyone who can read this origin's storage**, for the whole duration it's enabled. "Remember Me" is a UX-for-security trade-off that widens the exposure window; it does not add a new trust dependency beyond the origin-code integrity you already rely on. Keep the duration short for higher-value wallets and don't enable on shared devices.
|
|
1418
1443
|
- Decide this deliberately against your threat model: **[SECURITY.md → At-Rest Encryption](./SECURITY.md#at-rest-encryption-what-it-protects-and-what-it-doesnt)**.
|
|
1419
1444
|
|
package/docs/PORTABILITY.md
CHANGED
|
@@ -9,10 +9,12 @@ This guide explains how to move, backup, and link your W3PK wallet across differ
|
|
|
9
9
|
- [For End-Users](#for-end-users)
|
|
10
10
|
- [Linking an External Wallet (MetaMask, etc.)](#linking-an-external-wallet-metamask-etc)
|
|
11
11
|
- [Creating and Restoring Backups](#creating-and-restoring-backups)
|
|
12
|
+
- [Moving Your Wallet to a New Device](#moving-your-wallet-to-a-new-device)
|
|
12
13
|
- [Extracting Your Mnemonic](#extracting-your-mnemonic)
|
|
13
14
|
- [For Developers](#for-developers)
|
|
14
15
|
- [Implementing External Wallet Linking](#implementing-external-wallet-linking)
|
|
15
16
|
- [Implementing Backup/Restore Features](#implementing-backuprestore-features)
|
|
17
|
+
- [Implementing Device Sync](#implementing-device-sync)
|
|
16
18
|
- [Building Mnemonic Export Tools](#building-mnemonic-export-tools)
|
|
17
19
|
|
|
18
20
|
---
|
|
@@ -99,6 +101,21 @@ Your backup contains:
|
|
|
99
101
|
|
|
100
102
|
---
|
|
101
103
|
|
|
104
|
+
### Moving Your Wallet to a New Device
|
|
105
|
+
|
|
106
|
+
If your passkey syncs to the new device (iCloud Keychain on Apple devices, Google Password Manager on Android and Chrome), you can move your wallet without a password:
|
|
107
|
+
|
|
108
|
+
1. **On the device that has your wallet**, choose "Sync to another device" (or similar) and confirm with your passkey
|
|
109
|
+
2. **Transfer the sync file**: scan the QR code, or send the file by AirDrop, email, etc.
|
|
110
|
+
3. **On the new device**, open the app, load the sync file and confirm with the same passkey
|
|
111
|
+
4. **Done**: your wallet is on the new device, with the same address
|
|
112
|
+
|
|
113
|
+
The sync file can't be opened with the file alone: it also takes your passkey and your fingerprint or face. Still, keep it private and delete it once the sync is done.
|
|
114
|
+
|
|
115
|
+
**When it doesn't work**: this needs a browser that supports the passkey PRF extension (Chrome 108+, Safari 17+ / iOS 17+; not Firefox), and passkeys only sync within one ecosystem (Apple or Google). In other cases, use a password-encrypted backup: the app asks for a password when it creates the sync file, and the new device asks for the same password.
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
102
119
|
### Extracting Your Mnemonic
|
|
103
120
|
|
|
104
121
|
If you need to import your W3PK wallet into another wallet application (like MetaMask, Trust Wallet, etc.), you can extract your mnemonic phrase.
|
|
@@ -378,6 +395,55 @@ See [src/core/sdk.ts](../src/core/sdk.ts) for implementation details of `createB
|
|
|
378
395
|
|
|
379
396
|
---
|
|
380
397
|
|
|
398
|
+
### Implementing Device Sync
|
|
399
|
+
|
|
400
|
+
`exportForSync()` makes a sync file encrypted with a key derived from the passkey's [WebAuthn PRF](https://w3c.github.io/webauthn/#prf-extension) output (`encryptionMethod: 'prf'`). Any device where the passkey synced restores it with one prompt and no password, even a fresh device with no data for the passkey.
|
|
401
|
+
|
|
402
|
+
```typescript
|
|
403
|
+
// Device A, logged in: one passkey prompt
|
|
404
|
+
const { blob, filename, qrCode } = await sdk.exportForSync()
|
|
405
|
+
|
|
406
|
+
// Device B, logged out: one passkey prompt, restricted to the file's passkey
|
|
407
|
+
const { ethereumAddress } = await sdk.importFromSync(syncData)
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
`syncWalletWithPasskey(syncData)` restores the same files and also takes password backups.
|
|
411
|
+
|
|
412
|
+
**Password fallback**: PRF works in Chrome 108+ and Safari 17+ / iOS 17+, not in Firefox. Without it, `exportForSync()` throws `PrfUnsupportedError`. Pass a password to fall back to a password backup, which the new device restores with `syncWalletWithPasskey(syncData, password)`:
|
|
413
|
+
|
|
414
|
+
```typescript
|
|
415
|
+
import { PrfUnsupportedError } from 'w3pk'
|
|
416
|
+
|
|
417
|
+
let sync
|
|
418
|
+
try {
|
|
419
|
+
sync = await sdk.exportForSync()
|
|
420
|
+
} catch (error) {
|
|
421
|
+
if (!(error instanceof PrfUnsupportedError)) throw error
|
|
422
|
+
sync = await sdk.exportForSync(await askUserForPassword())
|
|
423
|
+
}
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
Or pass the password up front: `exportForSync(password)` uses it only when PRF is unavailable. Passkeys sync within one ecosystem only (Apple or Google), so moving between ecosystems also takes a password backup.
|
|
427
|
+
|
|
428
|
+
**PRF sync file structure:**
|
|
429
|
+
|
|
430
|
+
```json
|
|
431
|
+
{
|
|
432
|
+
"createdAt": "2026-10-25T10:30:00.000Z",
|
|
433
|
+
"ethereumAddress": "0x...",
|
|
434
|
+
"encryptedMnemonic": "base64(iv || AES-256-GCM ciphertext)",
|
|
435
|
+
"encryptionMethod": "prf",
|
|
436
|
+
"credential": { "id": "passkey credential id", "publicKey": "base64url SPKI" },
|
|
437
|
+
"prfSalt": "base64url, 32 random bytes",
|
|
438
|
+
"username": "alice",
|
|
439
|
+
"addressChecksum": "..."
|
|
440
|
+
}
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
The key is HKDF-SHA256 over the PRF output evaluated at `SHA-256("w3pk-prf-sync-v1" || prfSalt)`. The public key doesn't decrypt anything; the new device needs it for later logins and checks it against the assertion's signature. The file fits in a QR code (`generateSyncQR()`).
|
|
444
|
+
|
|
445
|
+
---
|
|
446
|
+
|
|
381
447
|
### Building Mnemonic Export Tools
|
|
382
448
|
|
|
383
449
|
For advanced users who need to export their mnemonic to use in other wallets, W3PK provides a standalone extraction tool.
|