w3pk 0.7.2 → 0.7.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 +4 -9
- package/dist/index.d.mts +13 -15
- package/dist/index.d.ts +13 -15
- package/dist/index.js +19 -19
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +19 -19
- package/dist/index.mjs.map +1 -1
- package/docs/API_REFERENCE.md +1900 -0
- package/docs/QUICK_START.md +65 -249
- package/docs/RECOVERY.md +100 -21
- package/docs/SECURITY.md +1024 -65
- package/package.json +2 -3
- package/dist/chainlist/index.d.mts +0 -96
- package/dist/chainlist/index.d.ts +0 -96
- package/docs/BROWSER_COMPATIBILITY.md +0 -300
- package/docs/BUNDLE_SIZES.md +0 -157
- package/docs/CHAINLIST.md +0 -293
- package/docs/ERC5564_FLOW_DIAGRAM.md +0 -525
- package/docs/ERC5564_STEALTH_ADDRESSES.md +0 -763
- package/docs/MIGRATION.md +0 -298
- package/docs/QR_CODE.md +0 -1887
- package/docs/ZK_INTEGRATION_GUIDE.md +0 -727
- package/docs/index.html +0 -400
package/README.md
CHANGED
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
Passwordless Web3 authentication SDK with encrypted wallets and privacy features.
|
|
7
7
|
|
|
8
|
-
**
|
|
8
|
+
- **Live demo: [w3pk.w3hc.org](https://w3pk.w3hc.org)**
|
|
9
|
+
- [Quick start](./docs/QUICK_START.md)
|
|
9
10
|
|
|
10
11
|
## Install
|
|
11
12
|
```bash
|
|
@@ -39,7 +40,6 @@ const rpcUrl = endpoints[0]
|
|
|
39
40
|
|
|
40
41
|
## Features
|
|
41
42
|
|
|
42
|
-
**Core (Included)**
|
|
43
43
|
- 🔐 Passwordless authentication (WebAuthn/FIDO2)
|
|
44
44
|
- 🔒 Client-only biometric-gated wallet encryption (AES-GCM-256)
|
|
45
45
|
- ⏱️ Session management (configurable duration, prevents repeated prompts)
|
|
@@ -289,14 +289,9 @@ See [Recovery Guide](./docs/RECOVERY.md) for complete documentation.
|
|
|
289
289
|
## Documentation
|
|
290
290
|
|
|
291
291
|
- [Quick Start Guide](./docs/QUICK_START.md) - Get started in 5 minutes
|
|
292
|
-
- [
|
|
293
|
-
- [Browser Compatibility](./docs/BROWSER_COMPATIBILITY.md) - Supported browsers, devices, and OS versions
|
|
292
|
+
- [API Reference](./docs/API_REFERENCE.md) - Complete API documentation
|
|
294
293
|
- [Security Architecture](./docs/SECURITY.md) - Integration best practices
|
|
295
|
-
- [
|
|
296
|
-
- [ERC-5564 Flow Diagrams](./docs/ERC5564_FLOW_DIAGRAM.md) - Visual explanations of how stealth addresses work
|
|
297
|
-
- [RPC Endpoints](./docs/CHAINLIST.md) - Chainlist integration guide
|
|
298
|
-
- [ZK Integration Guide](./docs/ZK_INTEGRATION_GUIDE.md) - Zero-knowledge proofs (optional)
|
|
299
|
-
- [Bundle Size Comparison](./docs/BUNDLE_SIZES.md) - Core vs ZK bundle sizes
|
|
294
|
+
- [Recovery & Backup System](./docs/RECOVERY.md) - Three-layer backup architecture
|
|
300
295
|
|
|
301
296
|
## Contributing
|
|
302
297
|
|
package/dist/index.d.mts
CHANGED
|
@@ -21,8 +21,6 @@ interface StealthKeys {
|
|
|
21
21
|
viewingKey: string;
|
|
22
22
|
/** Spending private key (32 bytes) */
|
|
23
23
|
spendingKey: string;
|
|
24
|
-
/** @deprecated Legacy meta-address format (kept for backward compatibility) */
|
|
25
|
-
metaAddress?: string;
|
|
26
24
|
}
|
|
27
25
|
/**
|
|
28
26
|
* ERC-5564 Stealth Address Generation Result
|
|
@@ -34,10 +32,6 @@ interface StealthAddressResult$1 {
|
|
|
34
32
|
ephemeralPubKey: string;
|
|
35
33
|
/** View tag (1 byte) for efficient scanning */
|
|
36
34
|
viewTag: string;
|
|
37
|
-
/** @deprecated Use ephemeralPubKey instead */
|
|
38
|
-
ephemeralPubkey?: string;
|
|
39
|
-
/** @deprecated Sender doesn't get the private key in ERC-5564 */
|
|
40
|
-
stealthPrivkey?: string;
|
|
41
35
|
}
|
|
42
36
|
/**
|
|
43
37
|
* ERC-5564 Parse/Check Result
|
|
@@ -108,9 +102,18 @@ declare function checkStealthAddress(viewingKey: string, spendingPubKey: string,
|
|
|
108
102
|
*/
|
|
109
103
|
declare function computeStealthPrivateKey(viewingKey: string, spendingKey: string, ephemeralPubKey: string): string;
|
|
110
104
|
/**
|
|
111
|
-
*
|
|
105
|
+
* ERC-5564: Check if user can control a stealth address
|
|
106
|
+
* Verifies that the user's keys can derive the correct private key for a stealth address.
|
|
107
|
+
*
|
|
108
|
+
* @param viewingKey - Recipient's viewing private key
|
|
109
|
+
* @param spendingKey - Recipient's spending private key
|
|
110
|
+
* @param spendingPubKey - Recipient's spending public key (compressed)
|
|
111
|
+
* @param ephemeralPubKey - Ephemeral public key from announcement
|
|
112
|
+
* @param stealthAddress - The stealth address to verify control of
|
|
113
|
+
* @param viewTag - View tag from announcement (optional, for optimization)
|
|
114
|
+
* @returns True if the user can control the stealth address
|
|
112
115
|
*/
|
|
113
|
-
declare function canControlStealthAddress(viewingKey: string, spendingKey: string,
|
|
116
|
+
declare function canControlStealthAddress(viewingKey: string, spendingKey: string, spendingPubKey: string, ephemeralPubKey: string, stealthAddress: string, viewTag?: string): boolean;
|
|
114
117
|
|
|
115
118
|
/**
|
|
116
119
|
* ERC-5564 Stealth Address Module for w3pk SDK
|
|
@@ -132,8 +135,6 @@ interface StealthAddressResult {
|
|
|
132
135
|
ephemeralPublicKey: string;
|
|
133
136
|
/** View tag (1 byte) for efficient scanning */
|
|
134
137
|
viewTag: string;
|
|
135
|
-
/** @deprecated Legacy field - sender doesn't get the private key in ERC-5564 */
|
|
136
|
-
stealthPrivateKey?: string;
|
|
137
138
|
}
|
|
138
139
|
/**
|
|
139
140
|
* ERC-5564 Announcement (what gets published on-chain)
|
|
@@ -552,10 +553,6 @@ declare class Web3Passkey {
|
|
|
552
553
|
* @param hours - Session duration in hours
|
|
553
554
|
*/
|
|
554
555
|
setSessionDuration(hours: number): void;
|
|
555
|
-
/**
|
|
556
|
-
* SDK version
|
|
557
|
-
*/
|
|
558
|
-
get version(): string;
|
|
559
556
|
}
|
|
560
557
|
|
|
561
558
|
/**
|
|
@@ -852,10 +849,11 @@ declare class SocialRecoveryManager {
|
|
|
852
849
|
generateGuardianInvite(guardian: Guardian): Promise<GuardianInvite>;
|
|
853
850
|
/**
|
|
854
851
|
* Generate QR code from share data
|
|
852
|
+
* Uses 'qrcode' library if available, falls back to canvas text
|
|
855
853
|
*/
|
|
856
854
|
private generateQRCode;
|
|
857
855
|
/**
|
|
858
|
-
* Create
|
|
856
|
+
* Create fallback QR representation
|
|
859
857
|
*/
|
|
860
858
|
private createPlaceholderQR;
|
|
861
859
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -21,8 +21,6 @@ interface StealthKeys {
|
|
|
21
21
|
viewingKey: string;
|
|
22
22
|
/** Spending private key (32 bytes) */
|
|
23
23
|
spendingKey: string;
|
|
24
|
-
/** @deprecated Legacy meta-address format (kept for backward compatibility) */
|
|
25
|
-
metaAddress?: string;
|
|
26
24
|
}
|
|
27
25
|
/**
|
|
28
26
|
* ERC-5564 Stealth Address Generation Result
|
|
@@ -34,10 +32,6 @@ interface StealthAddressResult$1 {
|
|
|
34
32
|
ephemeralPubKey: string;
|
|
35
33
|
/** View tag (1 byte) for efficient scanning */
|
|
36
34
|
viewTag: string;
|
|
37
|
-
/** @deprecated Use ephemeralPubKey instead */
|
|
38
|
-
ephemeralPubkey?: string;
|
|
39
|
-
/** @deprecated Sender doesn't get the private key in ERC-5564 */
|
|
40
|
-
stealthPrivkey?: string;
|
|
41
35
|
}
|
|
42
36
|
/**
|
|
43
37
|
* ERC-5564 Parse/Check Result
|
|
@@ -108,9 +102,18 @@ declare function checkStealthAddress(viewingKey: string, spendingPubKey: string,
|
|
|
108
102
|
*/
|
|
109
103
|
declare function computeStealthPrivateKey(viewingKey: string, spendingKey: string, ephemeralPubKey: string): string;
|
|
110
104
|
/**
|
|
111
|
-
*
|
|
105
|
+
* ERC-5564: Check if user can control a stealth address
|
|
106
|
+
* Verifies that the user's keys can derive the correct private key for a stealth address.
|
|
107
|
+
*
|
|
108
|
+
* @param viewingKey - Recipient's viewing private key
|
|
109
|
+
* @param spendingKey - Recipient's spending private key
|
|
110
|
+
* @param spendingPubKey - Recipient's spending public key (compressed)
|
|
111
|
+
* @param ephemeralPubKey - Ephemeral public key from announcement
|
|
112
|
+
* @param stealthAddress - The stealth address to verify control of
|
|
113
|
+
* @param viewTag - View tag from announcement (optional, for optimization)
|
|
114
|
+
* @returns True if the user can control the stealth address
|
|
112
115
|
*/
|
|
113
|
-
declare function canControlStealthAddress(viewingKey: string, spendingKey: string,
|
|
116
|
+
declare function canControlStealthAddress(viewingKey: string, spendingKey: string, spendingPubKey: string, ephemeralPubKey: string, stealthAddress: string, viewTag?: string): boolean;
|
|
114
117
|
|
|
115
118
|
/**
|
|
116
119
|
* ERC-5564 Stealth Address Module for w3pk SDK
|
|
@@ -132,8 +135,6 @@ interface StealthAddressResult {
|
|
|
132
135
|
ephemeralPublicKey: string;
|
|
133
136
|
/** View tag (1 byte) for efficient scanning */
|
|
134
137
|
viewTag: string;
|
|
135
|
-
/** @deprecated Legacy field - sender doesn't get the private key in ERC-5564 */
|
|
136
|
-
stealthPrivateKey?: string;
|
|
137
138
|
}
|
|
138
139
|
/**
|
|
139
140
|
* ERC-5564 Announcement (what gets published on-chain)
|
|
@@ -552,10 +553,6 @@ declare class Web3Passkey {
|
|
|
552
553
|
* @param hours - Session duration in hours
|
|
553
554
|
*/
|
|
554
555
|
setSessionDuration(hours: number): void;
|
|
555
|
-
/**
|
|
556
|
-
* SDK version
|
|
557
|
-
*/
|
|
558
|
-
get version(): string;
|
|
559
556
|
}
|
|
560
557
|
|
|
561
558
|
/**
|
|
@@ -852,10 +849,11 @@ declare class SocialRecoveryManager {
|
|
|
852
849
|
generateGuardianInvite(guardian: Guardian): Promise<GuardianInvite>;
|
|
853
850
|
/**
|
|
854
851
|
* Generate QR code from share data
|
|
852
|
+
* Uses 'qrcode' library if available, falls back to canvas text
|
|
855
853
|
*/
|
|
856
854
|
private generateQRCode;
|
|
857
855
|
/**
|
|
858
|
-
* Create
|
|
856
|
+
* Create fallback QR representation
|
|
859
857
|
*/
|
|
860
858
|
private createPlaceholderQR;
|
|
861
859
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var Rt=Object.create;var Z=Object.defineProperty;var xt=Object.getOwnPropertyDescriptor;var It=Object.getOwnPropertyNames;var Bt=Object.getPrototypeOf,Tt=Object.prototype.hasOwnProperty;var u=(s,e)=>()=>(s&&(e=s(s=0)),e);var S=(s,e)=>{for(var t in e)Z(s,t,{get:e[t],enumerable:!0})},Qe=(s,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of It(e))!Tt.call(s,n)&&n!==t&&Z(s,n,{get:()=>e[n],enumerable:!(r=xt(e,n))||r.enumerable});return s};var B=(s,e,t)=>(t=s!=null?Rt(Bt(s)):{},Qe(e||!s||!s.__esModule?Z(t,"default",{value:s,enumerable:!0}):t,s)),Dt=s=>Qe(Z({},"__esModule",{value:!0}),s);var g,k,T,d,y,h,X,w=u(()=>{"use strict";g=class extends Error{constructor(t,r,n){super(t);this.code=r;this.originalError=n;this.name="Web3PasskeyError"}},k=class extends g{constructor(e,t){super(e,"AUTHENTICATION_ERROR",t),this.name="AuthenticationError"}},T=class extends g{constructor(e,t){super(e,"REGISTRATION_ERROR",t),this.name="RegistrationError"}},d=class extends g{constructor(e,t){super(e,"WALLET_ERROR",t),this.name="WalletError"}},y=class extends g{constructor(e,t){super(e,"CRYPTO_ERROR",t),this.name="CryptoError"}},h=class extends g{constructor(e,t){super(e,"STORAGE_ERROR",t),this.name="StorageError"}},X=class extends g{constructor(t,r,n){super(t,"API_ERROR",n);this.statusCode=r;this.name="ApiError"}}});var _={};S(_,{CredentialStorage:()=>C});var re,ne,C,R=u(()=>{"use strict";w();re="w3pk_credential_",ne="w3pk_credential_index",C=class{constructor(e){if(e)this.storage=e;else if(typeof window<"u"&&window.localStorage)this.storage=window.localStorage;else throw new h("localStorage is not available")}saveCredential(e){try{let t=`${re}${e.id}`;this.storage.setItem(t,JSON.stringify(e)),this.addToIndex(e.id)}catch(t){throw new h("Failed to save credential",t)}}getCredentialById(e){try{let t=`${re}${e}`,r=this.storage.getItem(t);return r?JSON.parse(r):null}catch(t){throw new h("Failed to retrieve credential",t)}}getCredentialByUsername(e){try{return this.getAllCredentials().find(r=>r.username===e)||null}catch(t){throw new h("Failed to retrieve credential",t)}}getCredentialByAddress(e){try{return this.getAllCredentials().find(r=>r.ethereumAddress.toLowerCase()===e.toLowerCase())||null}catch(t){throw new h("Failed to retrieve credential",t)}}getAllCredentials(){try{return this.getIndex().map(t=>this.getCredentialById(t)).filter(t=>t!==null)}catch(e){throw new h("Failed to retrieve credentials",e)}}userExists(e){return this.getCredentialByUsername(e)!==null}updateLastUsed(e){try{let t=this.getCredentialById(e);t&&(t.lastUsed=Date.now(),this.saveCredential(t))}catch(t){throw new h("Failed to update timestamp",t)}}deleteCredential(e){try{let t=`${re}${e}`;this.storage.removeItem(t),this.removeFromIndex(e)}catch(t){throw new h("Failed to delete credential",t)}}clearAll(){try{this.getIndex().forEach(t=>{let r=`${re}${t}`;this.storage.removeItem(r)}),this.storage.removeItem(ne)}catch(e){throw new h("Failed to clear credentials",e)}}getIndex(){try{let e=this.storage.getItem(ne);return e?JSON.parse(e):[]}catch{return[]}}addToIndex(e){let t=this.getIndex();t.includes(e)||(t.push(e),this.storage.setItem(ne,JSON.stringify(t)))}removeFromIndex(e){let r=this.getIndex().filter(n=>n!==e);this.storage.setItem(ne,JSON.stringify(r))}}});var xe={};S(xe,{decryptData:()=>le,deriveEncryptionKey:()=>Lt,deriveEncryptionKeyFromSignature:()=>qt,deriveEncryptionKeyFromWebAuthn:()=>x,encryptData:()=>de,generateChallenge:()=>Gt});async function x(s,e){try{let t=e?`w3pk-v4:${s}:${e}`:`w3pk-v4:${s}`,r=await crypto.subtle.digest("SHA-256",new TextEncoder().encode(t)),n=await crypto.subtle.importKey("raw",r,{name:"PBKDF2"},!1,["deriveKey"]),o=await crypto.subtle.digest("SHA-256",new TextEncoder().encode("w3pk-salt-v4"));return crypto.subtle.deriveKey({name:"PBKDF2",salt:new Uint8Array(o),iterations:21e4,hash:"SHA-256"},n,{name:"AES-GCM",length:256},!1,["encrypt","decrypt"])}catch(t){throw new y("Failed to derive encryption key from WebAuthn",t)}}async function Lt(s,e){try{let t=e?`w3pk-v2:${s}:${e}`:`w3pk-v2:${s}`,r=await crypto.subtle.digest("SHA-256",new TextEncoder().encode(t)),n=await crypto.subtle.importKey("raw",r,{name:"PBKDF2"},!1,["deriveKey"]),o=await crypto.subtle.digest("SHA-256",new TextEncoder().encode("w3pk-salt-v2"));return crypto.subtle.deriveKey({name:"PBKDF2",salt:new Uint8Array(o),iterations:21e4,hash:"SHA-256"},n,{name:"AES-GCM",length:256},!1,["encrypt","decrypt"])}catch(t){throw new y("Failed to derive encryption key",t)}}async function qt(s,e){try{if(typeof window<"u"&&window.PublicKeyCredential)return x(e);let t=await crypto.subtle.digest("SHA-256",s),r=await crypto.subtle.importKey("raw",t,{name:"PBKDF2"},!1,["deriveKey"]),n=await crypto.subtle.digest("SHA-256",new TextEncoder().encode("w3pk-salt-v3:"+e));return crypto.subtle.deriveKey({name:"PBKDF2",salt:new Uint8Array(n),iterations:21e4,hash:"SHA-256"},r,{name:"AES-GCM",length:256},!1,["encrypt","decrypt"])}catch(t){throw new y("Failed to derive encryption key",t)}}function Gt(){let s=new Uint8Array(32);return crypto.getRandomValues(s),btoa(String.fromCharCode(...s)).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}async function de(s,e){try{let t=crypto.getRandomValues(new Uint8Array(12)),r=new TextEncoder().encode(s),n=await crypto.subtle.encrypt({name:"AES-GCM",iv:t},e,r),o=new Uint8Array(t.length+n.byteLength);return o.set(t),o.set(new Uint8Array(n),t.length),btoa(String.fromCharCode(...o))}catch(t){throw new y("Failed to encrypt data",t)}}async function le(s,e){try{if(!s||s.length<16)throw new Error("Invalid encrypted data: too small");let t=new Uint8Array(atob(s).split("").map(i=>i.charCodeAt(0)));if(t.length<12)throw new Error("Invalid encrypted data: missing IV");let r=t.slice(0,12),n=t.slice(12);if(n.length===0)throw new Error("Invalid encrypted data: no content");let o=await crypto.subtle.decrypt({name:"AES-GCM",iv:r},e,n);return new TextDecoder().decode(o)}catch(t){throw new y(`Data decryption failed: ${t instanceof Error?t.message:"Unknown error"}`,t)}}var ue=u(()=>{"use strict";w()});var A,Te=u(()=>{"use strict";A=class{constructor(){this.dbName="Web3PasskeyBackup";this.version=1;this.db=null}async init(){return typeof indexedDB>"u"?Promise.resolve():new Promise((e,t)=>{let r=indexedDB.open(this.dbName,this.version);r.onerror=()=>t(r.error),r.onsuccess=()=>{this.db=r.result,e()},r.onupgradeneeded=n=>{let o=n.target.result;if(!o.objectStoreNames.contains("backups")){let i=o.createObjectStore("backups",{keyPath:"id"});i.createIndex("ethereumAddress","ethereumAddress",{unique:!1}),i.createIndex("method","method",{unique:!1}),i.createIndex("createdAt","createdAt",{unique:!1})}}})}async storeBackupMetadata(e){return this.db||await this.init(),this.db?new Promise((t,r)=>{let i=this.db.transaction(["backups"],"readwrite").objectStore("backups").put(e);i.onsuccess=()=>t(),i.onerror=()=>r(i.error)}):Promise.resolve()}async getBackupsByAddress(e){return this.db||await this.init(),this.db?new Promise((t,r)=>{let c=this.db.transaction(["backups"],"readonly").objectStore("backups").index("ethereumAddress").getAll(e);c.onsuccess=()=>t(c.result),c.onerror=()=>r(c.error)}):Promise.resolve([])}async getBackupById(e){return this.db||await this.init(),this.db?new Promise((t,r)=>{let i=this.db.transaction(["backups"],"readonly").objectStore("backups").get(e);i.onsuccess=()=>t(i.result||null),i.onerror=()=>r(i.error)}):Promise.resolve(null)}async deleteBackup(e){return this.db||await this.init(),this.db?new Promise((t,r)=>{let i=this.db.transaction(["backups"],"readwrite").objectStore("backups").delete(e);i.onsuccess=()=>t(),i.onerror=()=>r(i.error)}):Promise.resolve()}async getBackupCountByMethod(e){return this.db||await this.init(),this.db?new Promise((t,r)=>{let c=this.db.transaction(["backups"],"readonly").objectStore("backups").index("method").count(e);c.onsuccess=()=>t(c.result),c.onerror=()=>r(c.error)}):Promise.resolve(0)}}});var Fe={};S(Fe,{decryptWithPassword:()=>lt,deriveAddressChecksum:()=>b,deriveKeyFromPassword:()=>ge,encryptWithPassword:()=>M,getDeviceFingerprint:()=>f,validatePasswordStrength:()=>fe});async function ge(s,e,t=31e4){let n=new TextEncoder().encode(s),o=await crypto.subtle.importKey("raw",n,"PBKDF2",!1,["deriveBits","deriveKey"]);return crypto.subtle.deriveKey({name:"PBKDF2",salt:e,iterations:t,hash:"SHA-256"},o,{name:"AES-GCM",length:256},!1,["encrypt","decrypt"])}async function M(s,e,t){let n=await ge(e,t,31e4),i=new TextEncoder().encode(s),c=crypto.getRandomValues(new Uint8Array(12)),a=await crypto.subtle.encrypt({name:"AES-GCM",iv:c},n,i);return{encrypted:j(a),iv:j(c),salt:j(t),iterations:31e4}}async function lt(s,e,t,r,n=31e4){let o=De(t),i=await ge(e,o,n),c=De(r),a=De(s),l=await crypto.subtle.decrypt({name:"AES-GCM",iv:c},i,a);return new TextDecoder().decode(l)}async function f(){let e=[navigator.userAgent,navigator.language,new Date().getTimezoneOffset().toString(),screen.width+"x"+screen.height,screen.colorDepth.toString()].join("|"),r=new TextEncoder().encode(e),n=await crypto.subtle.digest("SHA-256",r);return j(n)}async function b(s){let t=new TextEncoder().encode(s.toLowerCase()),r=await crypto.subtle.digest("SHA-256",t);return j(r).substring(0,16)}function fe(s){let e=[],t=0;return s.length<12?e.push("Password must be at least 12 characters"):t+=25,/[A-Z]/.test(s)?t+=15:e.push("Add at least one uppercase letter"),/[a-z]/.test(s)?t+=15:e.push("Add at least one lowercase letter"),/[0-9]/.test(s)?t+=15:e.push("Add at least one number"),/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(s)?t+=15:e.push("Add at least one special character"),s.length>=16&&(t+=10),s.length>=20&&(t+=5),["password","12345678","qwerty","abc123","password123","admin","letmein"].some(n=>s.toLowerCase().includes(n))&&(e.push("Password is too common"),t=Math.min(t,25)),{valid:t>=50&&e.length===0,score:Math.min(t,100),feedback:e}}function j(s){let e=s instanceof Uint8Array?s:new Uint8Array(s),t="";for(let r=0;r<e.byteLength;r++)t+=String.fromCharCode(e[r]);return btoa(t)}function De(s){let e=atob(s),t=new Uint8Array(e.length);for(let r=0;r<e.length;r++)t[r]=e.charCodeAt(r);return t}var E=u(()=>{"use strict"});var K,Me=u(()=>{"use strict";E();K=class{async createZipBackup(e,t,r){let n=fe(r.password);if(!n.valid)throw new Error(`Weak password: ${n.feedback.join(", ")}`);let o=crypto.getRandomValues(new Uint8Array(32)),i=await M(e,r.password,o),c=r.deviceBinding?await f():void 0,a={id:crypto.randomUUID(),ethereumAddress:t,method:"zip",createdAt:Date.now(),deviceFingerprint:c,addressChecksum:await b(t)},l={version:1,encrypted:i.encrypted,iv:i.iv,salt:i.salt,iterations:i.iterations,metadata:a,deviceFingerprint:c},p=new Map;return p.set("recovery-phrase.txt.enc",JSON.stringify(l,null,2)),p.set("metadata.json",JSON.stringify({address:t,createdAt:new Date(a.createdAt).toISOString(),backupId:a.id,addressChecksum:a.addressChecksum},null,2)),r.includeInstructions!==!1&&p.set("RECOVERY_INSTRUCTIONS.txt",this.getRecoveryInstructions()),{blob:await this.createSimpleZip(p),metadata:a}}async createSimpleZip(e){let t={};return e.forEach((r,n)=>{t[n]=r}),new Blob([JSON.stringify(t,null,2)],{type:"application/json"})}getRecoveryInstructions(){return`
|
|
1
|
+
"use strict";var Kt=Object.create;var ie=Object.defineProperty;var Ut=Object.getOwnPropertyDescriptor;var Ot=Object.getOwnPropertyNames;var Wt=Object.getPrototypeOf,Nt=Object.prototype.hasOwnProperty;var u=(s,e)=>()=>(s&&(e=s(s=0)),e);var S=(s,e)=>{for(var t in e)ie(s,t,{get:e[t],enumerable:!0})},tt=(s,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of Ot(e))!Nt.call(s,n)&&n!==t&&ie(s,n,{get:()=>e[n],enumerable:!(r=Ut(e,n))||r.enumerable});return s};var T=(s,e,t)=>(t=s!=null?Kt(Wt(s)):{},tt(e||!s||!s.__esModule?ie(t,"default",{value:s,enumerable:!0}):t,s)),Lt=s=>tt(ie({},"__esModule",{value:!0}),s);var m,k,D,d,h,y,ce,w=u(()=>{"use strict";m=class extends Error{constructor(t,r,n){super(t);this.code=r;this.originalError=n;this.name="Web3PasskeyError"}},k=class extends m{constructor(e,t){super(e,"AUTHENTICATION_ERROR",t),this.name="AuthenticationError"}},D=class extends m{constructor(e,t){super(e,"REGISTRATION_ERROR",t),this.name="RegistrationError"}},d=class extends m{constructor(e,t){super(e,"WALLET_ERROR",t),this.name="WalletError"}},h=class extends m{constructor(e,t){super(e,"CRYPTO_ERROR",t),this.name="CryptoError"}},y=class extends m{constructor(e,t){super(e,"STORAGE_ERROR",t),this.name="StorageError"}},ce=class extends m{constructor(t,r,n){super(t,"API_ERROR",n);this.statusCode=r;this.name="ApiError"}}});function R(s){try{let e=s.replace(/-/g,"+").replace(/_/g,"/"),t=(4-e.length%4)%4;e+="=".repeat(t);let r=atob(e),n=new Uint8Array(r.length);for(let o=0;o<r.length;o++)n[o]=r.charCodeAt(o);return n.buffer}catch(e){throw new Error(`Failed to decode base64url string: ${e instanceof Error?e.message:"Invalid format"}`)}}function A(s){let e=s instanceof Uint8Array?s:new Uint8Array(s),t="";for(let r=0;r<e.length;r++)t+=String.fromCharCode(e[r]);return btoa(t).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}function F(s){try{let e=s.replace(/-/g,"+").replace(/_/g,"/"),t=(4-e.length%4)%4;return e+="=".repeat(t),atob(e)}catch(e){throw new Error(`Failed to decode base64 string: ${e instanceof Error?e.message:"Invalid format"}`)}}var J=u(()=>{"use strict"});var Ke={};S(Ke,{decryptData:()=>Z,decryptMetadata:()=>pe,deriveEncryptionKey:()=>qt,deriveEncryptionKeyFromWebAuthn:()=>M,encryptData:()=>z,encryptMetadata:()=>ue,generateChallenge:()=>$t,hashCredentialId:()=>K,hashPublicKey:()=>Me});async function M(s,e){try{let t=e?`w3pk-v4:${s}:${e}`:`w3pk-v4:${s}`,r=await crypto.subtle.digest("SHA-256",new TextEncoder().encode(t)),n=await crypto.subtle.importKey("raw",r,{name:"PBKDF2"},!1,["deriveKey"]),o=await crypto.subtle.digest("SHA-256",new TextEncoder().encode("w3pk-salt-v4"));return crypto.subtle.deriveKey({name:"PBKDF2",salt:new Uint8Array(o),iterations:21e4,hash:"SHA-256"},n,{name:"AES-GCM",length:256},!1,["encrypt","decrypt"])}catch(t){throw new h("Failed to derive encryption key from WebAuthn",t)}}async function qt(s,e){try{let t=e?`w3pk-v2:${s}:${e}`:`w3pk-v2:${s}`,r=await crypto.subtle.digest("SHA-256",new TextEncoder().encode(t)),n=await crypto.subtle.importKey("raw",r,{name:"PBKDF2"},!1,["deriveKey"]),o=await crypto.subtle.digest("SHA-256",new TextEncoder().encode("w3pk-salt-v2"));return crypto.subtle.deriveKey({name:"PBKDF2",salt:new Uint8Array(o),iterations:21e4,hash:"SHA-256"},n,{name:"AES-GCM",length:256},!1,["encrypt","decrypt"])}catch(t){throw new h("Failed to derive encryption key",t)}}function $t(){let s=new Uint8Array(32);return crypto.getRandomValues(s),A(s)}async function z(s,e){try{let t=crypto.getRandomValues(new Uint8Array(12)),r=new TextEncoder().encode(s),n=await crypto.subtle.encrypt({name:"AES-GCM",iv:t},e,r),o=new Uint8Array(t.length+n.byteLength);o.set(t),o.set(new Uint8Array(n),t.length);let a="";for(let i=0;i<o.length;i++)a+=String.fromCharCode(o[i]);return btoa(a)}catch(t){throw new h("Failed to encrypt data",t)}}async function Z(s,e){try{if(!s||s.length<16)throw new Error("Invalid encrypted data: too small");let t=F(s),r=new Uint8Array(t.length);for(let i=0;i<t.length;i++)r[i]=t.charCodeAt(i);if(r.length<12)throw new Error("Invalid encrypted data: missing IV");let n=r.slice(0,12),o=r.slice(12);if(o.length===0)throw new Error("Invalid encrypted data: no content");let a=await crypto.subtle.decrypt({name:"AES-GCM",iv:n},e,o);return new TextDecoder().decode(a)}catch(t){throw new h(`Data decryption failed: ${t instanceof Error?t.message:"Unknown error"}`,t)}}async function K(s){try{let e=await crypto.subtle.digest("SHA-256",new TextEncoder().encode(`w3pk-cred-id:${s}`));return A(e)}catch(e){throw new h("Failed to hash credential ID",e)}}async function Me(s){try{let e=await crypto.subtle.digest("SHA-256",new TextEncoder().encode(s));return A(e)}catch(e){throw new h("Failed to hash public key",e)}}async function ue(s,e){return z(s,e)}async function pe(s,e){return Z(s,e)}var X=u(()=>{"use strict";w();J()});var ee={};S(ee,{CredentialStorage:()=>x});async function st(s){let e=new TextEncoder().encode(`w3pk-metadata-v1:${s}`),t=await crypto.subtle.digest("SHA-256",e),r=await crypto.subtle.importKey("raw",t,{name:"PBKDF2"},!1,["deriveKey"]);return await crypto.subtle.deriveKey({name:"PBKDF2",salt:new TextEncoder().encode("w3pk-metadata-salt-v1"),iterations:1e5,hash:"SHA-256"},r,{name:"AES-GCM",length:256},!1,["encrypt","decrypt"])}var he,ye,x,I=u(()=>{"use strict";w();X();he="w3pk_credential_",ye="w3pk_credential_index";x=class{constructor(e){if(e)this.storage=e;else if(typeof window<"u"&&window.localStorage)this.storage=window.localStorage;else throw new y("localStorage is not available")}async saveCredential(e){try{let t=await st(e.id),r=await K(e.id),n={id:r,encryptedUsername:await ue(e.username,t),encryptedAddress:await ue(e.ethereumAddress,t),publicKeyFingerprint:await Me(e.publicKey),createdAt:e.createdAt,lastUsed:e.lastUsed},o=`${he}${r}`;this.storage.setItem(o,JSON.stringify(n)),await this.addToIndex(e.id)}catch(t){throw new y("Failed to save credential",t)}}async getCredentialById(e){try{let t=await K(e),r=`${he}${t}`,n=this.storage.getItem(r);if(!n)return null;let o=JSON.parse(n),a=await st(e);return{id:e,publicKey:"",username:await pe(o.encryptedUsername,a),ethereumAddress:await pe(o.encryptedAddress,a),createdAt:o.createdAt,lastUsed:o.lastUsed}}catch(t){throw new y("Failed to retrieve credential",t)}}async getCredentialByUsername(e){try{return(await this.getAllCredentials()).find(r=>r.username===e)||null}catch(t){throw new y("Failed to retrieve credential",t)}}async getCredentialByAddress(e){try{return(await this.getAllCredentials()).find(r=>r.ethereumAddress.toLowerCase()===e.toLowerCase())||null}catch(t){throw new y("Failed to retrieve credential",t)}}async getAllCredentials(){try{let e=await this.getIndex();return(await Promise.all(e.map(async r=>await this.getCredentialById(r)))).filter(r=>r!==null)}catch(e){throw new y("Failed to retrieve credentials",e)}}async userExists(e){return await this.getCredentialByUsername(e)!==null}async updateLastUsed(e){try{let t=await this.getCredentialById(e);t&&(t.lastUsed=Date.now(),await this.saveCredential(t))}catch(t){throw new y("Failed to update timestamp",t)}}async deleteCredential(e){try{let t=await K(e),r=`${he}${t}`;this.storage.removeItem(r),await this.removeFromIndex(e)}catch(t){throw new y("Failed to delete credential",t)}}async clearAll(){try{let e=await this.getIndex();(await Promise.all(e.map(async r=>await K(r)))).forEach(r=>{let n=`${he}${r}`;this.storage.removeItem(n)}),this.storage.removeItem(ye)}catch(e){throw new y("Failed to clear credentials",e)}}async getIndex(){try{let e=this.storage.getItem(ye);return e?JSON.parse(e):[]}catch{return[]}}async addToIndex(e){let t=await this.getIndex();t.includes(e)||(t.push(e),this.storage.setItem(ye,JSON.stringify(t)))}async removeFromIndex(e){let r=(await this.getIndex()).filter(n=>n!==e);this.storage.setItem(ye,JSON.stringify(r))}}});var E,We=u(()=>{"use strict";E=class{constructor(){this.dbName="Web3PasskeyBackup";this.version=1;this.db=null}async init(){return typeof indexedDB>"u"?Promise.resolve():new Promise((e,t)=>{let r=indexedDB.open(this.dbName,this.version);r.onerror=()=>t(r.error),r.onsuccess=()=>{this.db=r.result,e()},r.onupgradeneeded=n=>{let o=n.target.result;if(!o.objectStoreNames.contains("backups")){let a=o.createObjectStore("backups",{keyPath:"id"});a.createIndex("ethereumAddress","ethereumAddress",{unique:!1}),a.createIndex("method","method",{unique:!1}),a.createIndex("createdAt","createdAt",{unique:!1})}}})}async storeBackupMetadata(e){return this.db||await this.init(),this.db?new Promise((t,r)=>{let a=this.db.transaction(["backups"],"readwrite").objectStore("backups").put(e);a.onsuccess=()=>t(),a.onerror=()=>r(a.error)}):Promise.resolve()}async getBackupsByAddress(e){return this.db||await this.init(),this.db?new Promise((t,r)=>{let i=this.db.transaction(["backups"],"readonly").objectStore("backups").index("ethereumAddress").getAll(e);i.onsuccess=()=>t(i.result),i.onerror=()=>r(i.error)}):Promise.resolve([])}async getBackupById(e){return this.db||await this.init(),this.db?new Promise((t,r)=>{let a=this.db.transaction(["backups"],"readonly").objectStore("backups").get(e);a.onsuccess=()=>t(a.result||null),a.onerror=()=>r(a.error)}):Promise.resolve(null)}async deleteBackup(e){return this.db||await this.init(),this.db?new Promise((t,r)=>{let a=this.db.transaction(["backups"],"readwrite").objectStore("backups").delete(e);a.onsuccess=()=>t(),a.onerror=()=>r(a.error)}):Promise.resolve()}async getBackupCountByMethod(e){return this.db||await this.init(),this.db?new Promise((t,r)=>{let i=this.db.transaction(["backups"],"readonly").objectStore("backups").index("method").count(e);i.onsuccess=()=>t(i.result),i.onerror=()=>r(i.error)}):Promise.resolve(0)}}});var Le={};S(Le,{decryptWithPassword:()=>wt,deriveAddressChecksum:()=>b,deriveKeyFromPassword:()=>ke,encryptWithPassword:()=>W,getDeviceFingerprint:()=>f,validatePasswordStrength:()=>Ae});async function ke(s,e,t=31e4){let n=new TextEncoder().encode(s),o=await crypto.subtle.importKey("raw",n,"PBKDF2",!1,["deriveBits","deriveKey"]);return crypto.subtle.deriveKey({name:"PBKDF2",salt:e,iterations:t,hash:"SHA-256"},o,{name:"AES-GCM",length:256},!1,["encrypt","decrypt"])}async function W(s,e,t){let n=await ke(e,t,31e4),a=new TextEncoder().encode(s),i=crypto.getRandomValues(new Uint8Array(12)),c=await crypto.subtle.encrypt({name:"AES-GCM",iv:i},n,a);return{encrypted:se(c),iv:se(i),salt:se(t),iterations:31e4}}async function wt(s,e,t,r,n=31e4){let o=Ne(t),a=await ke(e,o,n),i=Ne(r),c=Ne(s),l=await crypto.subtle.decrypt({name:"AES-GCM",iv:i},a,c);return new TextDecoder().decode(l)}async function f(){let e=[navigator.userAgent,navigator.language,new Date().getTimezoneOffset().toString(),screen.width+"x"+screen.height,screen.colorDepth.toString()].join("|"),r=new TextEncoder().encode(e),n=await crypto.subtle.digest("SHA-256",r);return se(n)}async function b(s){let t=new TextEncoder().encode(s.toLowerCase()),r=await crypto.subtle.digest("SHA-256",t);return se(r).substring(0,16)}function Ae(s){let e=[],t=0;return s.length<12?e.push("Password must be at least 12 characters"):t+=25,/[A-Z]/.test(s)?t+=15:e.push("Add at least one uppercase letter"),/[a-z]/.test(s)?t+=15:e.push("Add at least one lowercase letter"),/[0-9]/.test(s)?t+=15:e.push("Add at least one number"),/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(s)?t+=15:e.push("Add at least one special character"),s.length>=16&&(t+=10),s.length>=20&&(t+=5),["password","12345678","qwerty","abc123","password123","admin","letmein"].some(n=>s.toLowerCase().includes(n))&&(e.push("Password is too common"),t=Math.min(t,25)),{valid:t>=50&&e.length===0,score:Math.min(t,100),feedback:e}}function se(s){let e=s instanceof Uint8Array?s:new Uint8Array(s),t="";for(let r=0;r<e.byteLength;r++)t+=String.fromCharCode(e[r]);return btoa(t)}function Ne(s){let e=F(s),t=new Uint8Array(e.length);for(let r=0;r<e.length;r++)t[r]=e.charCodeAt(r);return t}var P=u(()=>{"use strict";J()});var N,qe=u(()=>{"use strict";P();N=class{async createZipBackup(e,t,r){let n=Ae(r.password);if(!n.valid)throw new Error(`Weak password: ${n.feedback.join(", ")}`);let o=crypto.getRandomValues(new Uint8Array(32)),a=await W(e,r.password,o),i=r.deviceBinding?await f():void 0,c={id:crypto.randomUUID(),ethereumAddress:t,method:"zip",createdAt:Date.now(),deviceFingerprint:i,addressChecksum:await b(t)},l={version:1,encrypted:a.encrypted,iv:a.iv,salt:a.salt,iterations:a.iterations,metadata:c,deviceFingerprint:i},p=new Map;return p.set("recovery-phrase.txt.enc",JSON.stringify(l,null,2)),p.set("metadata.json",JSON.stringify({address:t,createdAt:new Date(c.createdAt).toISOString(),backupId:c.id,addressChecksum:c.addressChecksum},null,2)),r.includeInstructions!==!1&&p.set("RECOVERY_INSTRUCTIONS.txt",this.getRecoveryInstructions()),{blob:await this.createSimpleZip(p),metadata:c}}async createSimpleZip(e){let t={};return e.forEach((r,n)=>{t[n]=r}),new Blob([JSON.stringify(t,null,2)],{type:"application/json"})}getRecoveryInstructions(){return`
|
|
2
2
|
W3PK WALLET RECOVERY INSTRUCTIONS
|
|
3
3
|
=================================
|
|
4
4
|
|
|
@@ -64,7 +64,7 @@ Visit: https://docs.w3pk.org/recovery
|
|
|
64
64
|
Email: support@w3pk.org
|
|
65
65
|
|
|
66
66
|
Generated: ${new Date().toISOString()}
|
|
67
|
-
`}async restoreFromZipBackup(e,t){let r=JSON.parse(e);if(r.version!==1)throw new Error("Unsupported backup version");let{decryptWithPassword:n}=await Promise.resolve().then(()=>(
|
|
67
|
+
`}async restoreFromZipBackup(e,t){let r=JSON.parse(e);if(r.version!==1)throw new Error("Unsupported backup version");let{decryptWithPassword:n}=await Promise.resolve().then(()=>(P(),Le)),o=await n(r.encrypted,t,r.salt,r.iv,r.iterations),{Wallet:a}=await import("ethers"),i=a.fromPhrase(o);if(await b(i.address)!==r.metadata.addressChecksum)throw new Error("Address checksum mismatch - corrupted backup or wrong password");return{mnemonic:o,metadata:r.metadata}}}});var L,$e=u(()=>{"use strict";P();L=class{async createQRBackup(e,t,r={}){let n=r.errorCorrection||"H",o;if(r.password){let l=crypto.getRandomValues(new Uint8Array(32)),p=await W(e,r.password,l);o={version:1,type:"encrypted",data:p.encrypted,iv:p.iv,salt:p.salt,iterations:p.iterations,checksum:await b(t)}}else o={version:1,type:"plain",data:e,checksum:await b(t)};let a=JSON.stringify(o),i=await this.generateQRCode(a,n),c=this.getInstructions(t,!!r.password);return{qrCodeDataURL:i,rawData:a,instructions:c}}async generateQRCode(e,t){try{return await(await import("qrcode")).default.toDataURL(e,{errorCorrectionLevel:t,width:512,margin:2})}catch{return this.createFallbackQRDataURL(e)}}createFallbackQRDataURL(e){if(typeof document>"u")return`data:text/plain;base64,${Buffer.from(e).toString("base64")}`;let t=document.createElement("canvas");t.width=512,t.height=512;let r=t.getContext("2d");if(!r)throw new Error("Canvas not supported");r.fillStyle="white",r.fillRect(0,0,512,512),r.fillStyle="black",r.font="12px monospace",r.textAlign="center",r.textBaseline="middle";let n=this.wrapText(e,50),o=14,a=256-n.length*o/2;return n.forEach((i,c)=>{r.fillText(i,256,a+c*o)}),r.font="bold 16px sans-serif",r.fillText('Install "qrcode" package for QR codes',256,480),t.toDataURL("image/png")}wrapText(e,t){let r=[];for(let n=0;n<e.length;n+=t)r.push(e.substring(n,n+t));return r}getInstructions(e,t){return`
|
|
68
68
|
W3PK QR CODE BACKUP
|
|
69
69
|
==================
|
|
70
70
|
|
|
@@ -140,13 +140,13 @@ If QR code is lost/damaged, you can still recover using:
|
|
|
140
140
|
|
|
141
141
|
Generated by w3pk Recovery System
|
|
142
142
|
https://docs.w3pk.org/recovery
|
|
143
|
-
`}async restoreFromQR(e,t){let r=JSON.parse(e);if(r.version!==1)throw new Error("Unsupported QR backup version");let n;if(r.type==="encrypted"){if(!t)throw new Error("Password required for encrypted QR backup");let{decryptWithPassword:
|
|
143
|
+
`}async restoreFromQR(e,t){let r=JSON.parse(e);if(r.version!==1)throw new Error("Unsupported QR backup version");let n;if(r.type==="encrypted"){if(!t)throw new Error("Password required for encrypted QR backup");let{decryptWithPassword:c}=await Promise.resolve().then(()=>(P(),Le));n=await c(r.data,t,r.salt,r.iv,r.iterations)}else if(r.type==="plain")n=r.data;else throw new Error("Unknown QR backup type");let{Wallet:o}=await import("ethers"),a=o.fromPhrase(n);if(await b(a.address)!==r.checksum)throw new Error("Address checksum mismatch - corrupted QR or wrong password");return{mnemonic:n,ethereumAddress:a.address}}}});var q,vt=u(()=>{"use strict";We();qe();$e();q=class{constructor(){this.storage=new E,this.zipCreator=new N,this.qrCreator=new L}async getBackupStatus(e){let t=await this.storage.getBackupsByAddress(e),r=await this.detectPasskeySync(),n=t.map(a=>({id:a.id,method:a.method,location:"local",createdAt:a.createdAt,deviceFingerprint:a.deviceFingerprint}));return{passkeySync:r,recoveryPhrase:{verified:!1,verificationCount:0,encryptedBackups:n},securityScore:this.calculateSecurityScore(r,n)}}async detectPasskeySync(){if(typeof navigator>"u")return{enabled:!1,deviceCount:0,lastSyncTime:void 0,platform:"unknown"};let e=navigator.userAgent.toLowerCase(),t="unknown";e.includes("mac")||e.includes("iphone")||e.includes("ipad")?t="apple":e.includes("android")?t="google":e.includes("windows")&&(t="microsoft");let r=await this.checkResidentKeySupport();return{enabled:r,deviceCount:1,lastSyncTime:r?Date.now():void 0,platform:t}}async checkResidentKeySupport(){if(typeof window>"u"||!window.PublicKeyCredential)return!1;try{return await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable()}catch{return!1}}calculateSecurityScore(e,t){let r={passkeyActive:e.enabled?20:0,passkeyMultiDevice:e.deviceCount>1?10:0,phraseVerified:0,encryptedBackup:t.length>0?20:0,socialRecovery:0},n=Object.values(r).reduce((i,c)=>i+c,0),o,a;return n<=20?(o="vulnerable",a='Create encrypted backup to reach "protected" (40+ pts)'):n<=50?(o="protected",a='Set up social recovery to reach "secured" (70+ pts)'):n<=80?(o="secured",a='Enable all methods to reach "fort-knox" (100 pts)'):(o="fort-knox",a="Maximum security achieved! \u{1F3C6}"),{total:n,breakdown:r,level:o,nextMilestone:a}}async createZipBackup(e,t,r){let{blob:n,metadata:o}=await this.zipCreator.createZipBackup(e,t,r);return await this.storage.storeBackupMetadata(o),n}async createQRBackup(e,t,r){let{qrCodeDataURL:n,rawData:o,instructions:a}=await this.qrCreator.createQRBackup(e,t,r),i={id:crypto.randomUUID(),ethereumAddress:t,method:"qr",createdAt:Date.now(),addressChecksum:JSON.parse(o).checksum};return await this.storage.storeBackupMetadata(i),{qrCodeDataURL:n,instructions:a}}async restoreFromZipBackup(e,t){let{mnemonic:r,metadata:n}=await this.zipCreator.restoreFromZipBackup(e,t);return{mnemonic:r,ethereumAddress:n.ethereumAddress}}async restoreFromQR(e,t){return await this.qrCreator.restoreFromQR(e,t)}async simulateRecoveryScenario(e,t){let r=[];switch(e.type){case"lost-device":t.passkeySync.enabled&&t.passkeySync.deviceCount>1&&r.push({method:"Passkey Sync (iCloud/Google)",success:!0,time:"5 minutes",requirements:["Sign in to cloud account","Authenticate on new device"]}),t.recoveryPhrase.encryptedBackups.length>0&&r.push({method:"Encrypted ZIP Backup",success:!0,time:"2 minutes",requirements:["Backup file","Password"]}),t.socialRecovery?.enabled&&r.push({method:"Social Recovery",success:!0,time:"24 hours",requirements:[`${t.socialRecovery.threshold} guardian shares`]});break;case"lost-phrase":t.passkeySync.enabled&&r.push({method:"Passkey (current device)",success:!0,time:"instant",requirements:["Current device","Biometric/PIN"]}),t.socialRecovery?.enabled&&r.push({method:"Social Recovery",success:!0,time:"24 hours",requirements:[`${t.socialRecovery.threshold} guardian shares`]});break;case"lost-both":t.passkeySync.enabled&&t.passkeySync.deviceCount>1&&r.push({method:"Passkey Sync",success:!0,time:"5 minutes",requirements:["Cloud account access","New device"]}),t.socialRecovery?.enabled&&r.push({method:"Social Recovery",success:!0,time:"24 hours",requirements:[`${t.socialRecovery.threshold} guardian shares`]});break;case"switch-platform":t.recoveryPhrase.encryptedBackups.length>0&&r.push({method:"Encrypted Backup",success:!0,time:"2 minutes",requirements:["Backup file","Password"]}),t.socialRecovery?.enabled&&r.push({method:"Social Recovery",success:!0,time:"24 hours",requirements:[`${t.socialRecovery.threshold} guardian shares`]});break}let n=r.length>0&&r.some(a=>a.success),o="";return n?(o=`\u2705 You're safe! ${r.length} way${r.length>1?"s":""} to recover.
|
|
144
144
|
|
|
145
145
|
`,o+=`Available recovery methods:
|
|
146
|
-
`,r.forEach(
|
|
146
|
+
`,r.forEach(a=>{o+=`- ${a.method} (~${a.time})
|
|
147
147
|
`})):(o=`\u274C Wallet cannot be recovered in this scenario.
|
|
148
148
|
|
|
149
|
-
`,o+="Recommendation: Set up at least 2 backup methods to prevent total loss."),{scenario:e,success:n,availableMethods:r,timeEstimate:n?r[0].time:"N/A",educationalNote:o}}}});var
|
|
149
|
+
`,o+="Recommendation: Set up at least 2 backup methods to prevent total loss."),{scenario:e,success:n,availableMethods:r,timeEstimate:n?r[0].time:"N/A",educationalNote:o}}}});var bt=u(()=>{"use strict"});var $={};S($,{BackupManager:()=>q,BackupStorage:()=>E,QRBackupCreator:()=>L,ZipBackupCreator:()=>N,decryptWithPassword:()=>wt,deriveAddressChecksum:()=>b,deriveKeyFromPassword:()=>ke,encryptWithPassword:()=>W,getDeviceFingerprint:()=>f,validatePasswordStrength:()=>Ae});var B=u(()=>{"use strict";vt();We();qe();$e();bt();P()});function rr(){let s=new Uint8Array(1);return crypto.getRandomValues(s),s[0]}function Ge(s,e,t){if(e>t)throw new Error("Threshold cannot be greater than total shares");if(e<2)throw new Error("Threshold must be at least 2");if(t>255)throw new Error("Cannot create more than 255 shares");let r=[];for(let n=0;n<t;n++)r[n]=new Uint8Array(s.length+1),r[n][0]=n+1;for(let n=0;n<s.length;n++){let a=[s[n]];for(let i=1;i<e;i++)a.push(rr());for(let i=0;i<t;i++){let c=i+1,l=Ee.evaluatePolynomial(a,c);r[i][n+1]=l}}return r}function Ye(s,e){if(s.length<e)throw new Error(`Need at least ${e} shares to recover secret, got ${s.length}`);let t=s.slice(0,e),r=t[0].length;for(let a of t)if(a.length!==r)throw new Error("All shares must have the same length");let n=r-1,o=new Uint8Array(n);for(let a=0;a<n;a++){let i=[];for(let c of t)i.push({x:c[0],y:c[a+1]});o[a]=Ee.interpolate(i)}return o}function He(s){return new TextEncoder().encode(s)}function _e(s){return new TextDecoder().decode(s)}function Ve(s){return Array.from(s).map(e=>e.toString(16).padStart(2,"0")).join("")}function Qe(s){let e=new Uint8Array(s.length/2);for(let t=0;t<s.length;t+=2)e[t/2]=parseInt(s.substring(t,t+2),16);return e}var C,Ee,je=u(()=>{"use strict";C=class C{static multiply(e,t){return e===0||t===0?0:this.EXP_TABLE[(this.LOG_TABLE[e]+this.LOG_TABLE[t])%255]}static divide(e,t){if(t===0)throw new Error("Division by zero in GF(256)");return e===0?0:this.EXP_TABLE[(this.LOG_TABLE[e]-this.LOG_TABLE[t]+255)%255]}static add(e,t){return e^t}static evaluatePolynomial(e,t){let r=0;for(let n=e.length-1;n>=0;n--)r=this.add(this.multiply(r,t),e[n]);return r}static interpolate(e){let t=0;for(let r=0;r<e.length;r++){let n=e[r].y,o=1;for(let a=0;a<e.length;a++)r!==a&&(n=this.multiply(n,e[a].x),o=this.multiply(o,this.add(e[r].x,e[a].x)));t=this.add(t,this.divide(n,o))}return t}};C.LOG_TABLE=[],C.EXP_TABLE=[],(()=>{let e=(r,n)=>{let o=0;for(let a=0;a<8;a++){n&1&&(o^=r);let i=r&128;r<<=1,i&&(r^=283),n>>=1}return o&255},t=1;for(let r=0;r<255;r++)C.EXP_TABLE[r]=t,C.LOG_TABLE[t]=r,t=e(t,3);C.EXP_TABLE[255]=C.EXP_TABLE[0]})();Ee=C});var St,G,kt=u(()=>{"use strict";je();St=new Map,G=class{constructor(){this.storageKey="w3pk_social_recovery"}getItem(e){return typeof localStorage<"u"?localStorage.getItem(e):St.get(e)||null}setItem(e,t){typeof localStorage<"u"?localStorage.setItem(e,t):St.set(e,t)}async setupSocialRecovery(e,t,r,n){if(n>r.length)throw new Error("Threshold cannot be greater than number of guardians");if(n<2)throw new Error("Threshold must be at least 2");if(r.length>255)throw new Error("Cannot have more than 255 guardians");let o=He(e),a=Ge(o,n,r.length),i=r.map((l,p)=>({id:crypto.randomUUID(),name:l.name,email:l.email,phone:l.phone,shareEncrypted:Ve(a[p]),status:"pending",addedAt:Date.now()})),c={threshold:n,totalGuardians:r.length,guardians:i,createdAt:Date.now(),ethereumAddress:t};return this.setItem(this.storageKey,JSON.stringify(c)),i}getSocialRecoveryConfig(){let e=this.getItem(this.storageKey);if(!e)return null;try{return JSON.parse(e)}catch{return null}}async generateGuardianInvite(e){let t=this.getSocialRecoveryConfig();if(!t)throw new Error("Social recovery not configured");let r=t.guardians.findIndex(c=>c.id===e.id);if(r===-1)throw new Error("Guardian not found");let n={version:1,guardianId:e.id,guardianName:e.name,guardianIndex:r+1,totalGuardians:t.totalGuardians,threshold:t.threshold,share:e.shareEncrypted,ethereumAddress:t.ethereumAddress,createdAt:t.createdAt},o=JSON.stringify(n),a=await this.generateQRCode(o),i=this.getGuardianExplainer(e.name,r+1,t.totalGuardians,t.threshold);return{guardianId:e.id,qrCode:a,shareCode:o,explainer:i}}async generateQRCode(e){try{return await(await import("qrcode")).toDataURL(e,{errorCorrectionLevel:"H",width:512,margin:2})}catch{return this.createPlaceholderQR(e)}}createPlaceholderQR(e){if(typeof document>"u")return`data:text/plain;base64,${Buffer.from(e).toString("base64")}`;let t=document.createElement("canvas");t.width=512,t.height=512;let r=t.getContext("2d");return r?(r.fillStyle="white",r.fillRect(0,0,512,512),r.fillStyle="black",r.font="bold 20px sans-serif",r.textAlign="center",r.textBaseline="middle",r.fillText("Guardian Recovery Share",256,100),r.font="14px monospace",r.fillText('Install "qrcode" for QR codes',256,480),r.font="10px monospace",this.wrapText(e.substring(0,200)+"...",60).forEach((o,a)=>{r.fillText(o,256,150+a*12)}),t.toDataURL("image/png")):""}wrapText(e,t){let r=[];for(let n=0;n<e.length;n+=t)r.push(e.substring(n,n+t));return r}getGuardianExplainer(e,t,r,n){return`
|
|
150
150
|
\u{1F6E1}\uFE0F GUARDIAN RECOVERY SHARE
|
|
151
151
|
|
|
152
152
|
Dear ${e},
|
|
@@ -234,7 +234,7 @@ Thank you for being a trusted guardian!
|
|
|
234
234
|
|
|
235
235
|
NEED HELP?
|
|
236
236
|
Visit: https://docs.w3pk.org/social-recovery
|
|
237
|
-
`}async recoverFromGuardians(e){let t=this.getSocialRecoveryConfig();if(!t)throw new Error("Social recovery not configured");if(e.length<t.threshold)throw new Error(`Need at least ${t.threshold} shares, got ${e.length}`);let n=e.map(l=>{let p=JSON.parse(l);return{guardianId:p.guardianId,share:p.share,index:p.guardianIndex}}).map(l=>
|
|
237
|
+
`}async recoverFromGuardians(e){let t=this.getSocialRecoveryConfig();if(!t)throw new Error("Social recovery not configured");if(e.length<t.threshold)throw new Error(`Need at least ${t.threshold} shares, got ${e.length}`);let n=e.map(l=>{let p=JSON.parse(l);return{guardianId:p.guardianId,share:p.share,index:p.guardianIndex}}).map(l=>Qe(l.share)),o=Ye(n,t.threshold),a=_e(o),{Wallet:i}=await import("ethers"),c=i.fromPhrase(a);if(c.address.toLowerCase()!==t.ethereumAddress.toLowerCase())throw new Error("Recovered address does not match - invalid shares");return{mnemonic:a,ethereumAddress:c.address}}getRecoveryProgress(e){let t=this.getSocialRecoveryConfig();if(!t)throw new Error("Social recovery not configured");let r=new Set(e.map(n=>{try{return JSON.parse(n).guardianId}catch{return null}}).filter(Boolean));return{collected:r.size,required:t.threshold,guardians:t.guardians.map(n=>({id:n.id,name:n.name,hasProvided:r.has(n.id)})),canRecover:r.size>=t.threshold}}markGuardianVerified(e){let t=this.getSocialRecoveryConfig();if(!t)throw new Error("Social recovery not configured");let r=t.guardians.find(n=>n.id===e);if(!r)throw new Error("Guardian not found");r.status="active",r.lastVerified=Date.now(),this.setItem(this.storageKey,JSON.stringify(t))}revokeGuardian(e){let t=this.getSocialRecoveryConfig();if(!t)throw new Error("Social recovery not configured");let r=t.guardians.find(n=>n.id===e);if(!r)throw new Error("Guardian not found");r.status="revoked",this.setItem(this.storageKey,JSON.stringify(t))}async addGuardian(e,t){let r=this.getSocialRecoveryConfig();if(!r)throw new Error("Social recovery not configured");let n=[...r.guardians.filter(a=>a.status!=="revoked").map(a=>({name:a.name,email:a.email,phone:a.phone})),t],o=await this.setupSocialRecovery(e,r.ethereumAddress,n,r.threshold);return o[o.length-1]}}});var At=u(()=>{"use strict"});var Pe={};S(Pe,{SocialRecoveryManager:()=>G,bytesToHex:()=>Ve,bytesToString:()=>_e,combineShares:()=>Ye,hexToBytes:()=>Qe,splitSecret:()=>Ge,stringToBytes:()=>He});var oe=u(()=>{"use strict";kt();je();At()});var Y,Et=u(()=>{"use strict";P();Y=class{async createSyncPackage(e,t,r){let n=await f(),{deriveEncryptionKeyFromWebAuthn:o,encryptData:a}=await Promise.resolve().then(()=>(X(),Ke)),i=await o(t,r),c=await a(e,i),l=this.detectSyncMethod();return{id:crypto.randomUUID(),encryptedData:c,deviceFingerprints:[n],syncMethod:l,version:1,updatedAt:Date.now()}}detectSyncMethod(){let e=navigator.userAgent.toLowerCase();return e.includes("mac")||e.includes("iphone")||e.includes("ipad")?"icloud":e.includes("android")||e.includes("chrome")?"google":e.includes("windows")?"microsoft":"custom"}async restoreFromSync(e,t,r){let{deriveEncryptionKeyFromWebAuthn:n,decryptData:o}=await Promise.resolve().then(()=>(X(),Ke)),a=await n(t,r),i=await o(e.encryptedData,a),c=await f();return e.deviceFingerprints.includes(c)||(e.deviceFingerprints.push(c),e.updatedAt=Date.now()),i}async getSetupFlow(){return{success:!1,steps:[{title:"1. Authenticate on New Device",action:"Use Touch ID/Face ID",educational:"Your passkey is automatically synced via iCloud/Google",status:"waiting"},{title:"2. Decrypt Wallet Data",action:"System validates device",educational:"Only your trusted devices can decrypt the wallet",status:"waiting"},{title:"3. Verify Recovery",action:"Check partial address",educational:"Confirm address matches your wallet",status:"waiting"},{title:"4. Ready!",action:"Wallet synced",educational:"All devices now have access",status:"waiting"}]}}getSyncExplainer(){return`
|
|
238
238
|
HOW CROSS-DEVICE SYNC WORKS
|
|
239
239
|
===========================
|
|
240
240
|
|
|
@@ -315,14 +315,14 @@ If passkey doesn't sync:
|
|
|
315
315
|
Think of it like:
|
|
316
316
|
\u{1F511} Passkey = Your car key (syncs via keychain)
|
|
317
317
|
\u{1F697} Wallet = Your car (locked, needs key to start)
|
|
318
|
-
`}}});var
|
|
318
|
+
`}}});var H,Pt=u(()=>{"use strict";P();H=class{constructor(){this.storageKey="w3pk_devices"}async registerDevice(){let e={id:await f(),name:this.getDeviceName(),platform:this.detectPlatform(),lastActive:Date.now(),trusted:!0,canRevoke:!1},t=await this.getDevices(),r=t.find(n=>n.id===e.id);return r?(r.lastActive=Date.now(),localStorage.setItem(this.storageKey,JSON.stringify(t))):(t.push(e),localStorage.setItem(this.storageKey,JSON.stringify(t))),e}async getDevices(){let e=localStorage.getItem(this.storageKey);if(!e)return[];try{return JSON.parse(e)}catch{return[]}}async getSyncStatus(){let e=await this.getDevices(),t=await f();e.forEach(o=>{o.canRevoke=o.id!==t}),e.sort((o,a)=>a.lastActive-o.lastActive);let r=this.detectPlatform(),n=e.length>1?Math.max(...e.map(o=>o.lastActive)):void 0;return{enabled:e.length>1,devices:e,lastSyncTime:n,platform:this.getPlatformName(r)}}async revokeDevice(e){let t=await this.getDevices(),r=await f();if(e===r)throw new Error("Cannot revoke current device");let n=t.filter(o=>o.id!==e);localStorage.setItem(this.storageKey,JSON.stringify(n))}async updateLastActive(){let e=await this.getDevices(),t=await f(),r=e.find(n=>n.id===t);r&&(r.lastActive=Date.now(),localStorage.setItem(this.storageKey,JSON.stringify(e)))}getDeviceName(){let e=this.detectPlatform(),t=navigator.userAgent;if(e==="ios")return t.includes("iPhone")?"iPhone":t.includes("iPad")?"iPad":t.includes("iPod")?"iPod":"iOS Device";if(e==="android"){let r=t.match(/Android.*;\s([^)]+)\)/);return r?r[1]:"Android Device"}return e==="macos"?"Mac":e==="windows"?"Windows PC":e==="linux"?"Linux PC":"Unknown Device"}detectPlatform(){let e=navigator.userAgent.toLowerCase();return e.includes("iphone")||e.includes("ipad")||e.includes("ipod")?"ios":e.includes("android")?"android":e.includes("mac")?"macos":e.includes("windows")?"windows":e.includes("linux")?"linux":"unknown"}getPlatformName(e){switch(e){case"ios":return"iOS (iCloud Keychain)";case"android":return"Android (Google)";case"macos":return"macOS (iCloud Keychain)";case"windows":return"Windows (Microsoft)";case"linux":return"Linux";default:return"Unknown"}}async getDeviceListFormatted(){let e=await this.getSyncStatus();if(e.devices.length===0)return"No devices registered";let t=`Your Devices (${e.devices.length}):
|
|
319
319
|
|
|
320
|
-
`;return e.devices.forEach((r,n)=>{let o=Date.now()-r.lastActive,
|
|
320
|
+
`;return e.devices.forEach((r,n)=>{let o=Date.now()-r.lastActive,a=this.formatTimeDiff(o);t+=`${n+1}. ${r.name}
|
|
321
321
|
`,t+=` Platform: ${this.getPlatformName(r.platform)}
|
|
322
|
-
`,t+=` Last active: ${
|
|
322
|
+
`,t+=` Last active: ${a}
|
|
323
323
|
`,t+=` ${r.canRevoke?"":"(Current device)"}
|
|
324
324
|
|
|
325
|
-
`}),t}formatTimeDiff(e){let t=Math.floor(e/1e3),r=Math.floor(t/60),n=Math.floor(r/60),o=Math.floor(n/24);return o>0?`${o} day${o>1?"s":""} ago`:n>0?`${n} hour${n>1?"s":""} ago`:r>0?`${r} minute${r>1?"s":""} ago`:"just now"}}});var
|
|
325
|
+
`}),t}formatTimeDiff(e){let t=Math.floor(e/1e3),r=Math.floor(t/60),n=Math.floor(r/60),o=Math.floor(n/24);return o>0?`${o} day${o>1?"s":""} ago`:n>0?`${n} hour${n>1?"s":""} ago`:r>0?`${r} minute${r>1?"s":""} ago`:"just now"}}});var _,Ct=u(()=>{"use strict";_=class{async detectSyncCapabilities(){let e=this.detectPlatform(),t=await this.checkPasskeySync(),r=this.estimateDeviceCount();return{passkeysSync:t,platform:e,estimatedDevices:r,syncEnabled:t&&e!=="none"}}detectPlatform(){let e=navigator.userAgent.toLowerCase();return e.includes("mac")||e.includes("iphone")||e.includes("ipad")||e.includes("ipod")?"apple":e.includes("android")?"google":e.includes("windows")?"microsoft":"none"}async checkPasskeySync(){if(!window.PublicKeyCredential)return!1;try{return await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable()}catch{return!1}}estimateDeviceCount(){return 1}getPlatformEducation(e){switch(e){case"apple":return`
|
|
326
326
|
\u{1F34E} Apple iCloud Keychain
|
|
327
327
|
|
|
328
328
|
Your passkey automatically syncs across:
|
|
@@ -401,7 +401,7 @@ This ensures you can recover if:
|
|
|
401
401
|
- Device is lost/stolen
|
|
402
402
|
- Device is damaged
|
|
403
403
|
- You switch devices
|
|
404
|
-
`}}getSyncInstructions(e){switch(e){case"apple":return["Open Settings on your iPhone/iPad/Mac","Tap your name at the top",'Tap "iCloud"','Enable "Keychain"','Enable "iCloud Backup" (recommended)'];case"google":return["Open Chrome Settings",'Click "You and Google"','Enable "Sync"','Ensure "Passwords" is checked',"Sign in on other devices with same Google account"];case"microsoft":return["Windows Hello sync is limited","Consider using:","- Encrypted ZIP backup","- Social recovery","- Cloud backup (password-protected)"];case"none":return["Platform sync not available","Use alternative backup methods:","- Create encrypted ZIP backup","- Set up social recovery","- Save recovery phrase securely"]}}}});var
|
|
404
|
+
`}}getSyncInstructions(e){switch(e){case"apple":return["Open Settings on your iPhone/iPad/Mac","Tap your name at the top",'Tap "iCloud"','Enable "Keychain"','Enable "iCloud Backup" (recommended)'];case"google":return["Open Chrome Settings",'Click "You and Google"','Enable "Sync"','Ensure "Passwords" is checked',"Sign in on other devices with same Google account"];case"microsoft":return["Windows Hello sync is limited","Consider using:","- Encrypted ZIP backup","- Social recovery","- Cloud backup (password-protected)"];case"none":return["Platform sync not available","Use alternative backup methods:","- Create encrypted ZIP backup","- Set up social recovery","- Save recovery phrase securely"]}}}});var Rt=u(()=>{"use strict"});var Je={};S(Je,{DeviceManager:()=>H,PlatformDetector:()=>_,VaultSync:()=>Y});var Ce=u(()=>{"use strict";Et();Pt();Ct();Rt()});var V,xt=u(()=>{"use strict";V=class{getScenarios(){return[{type:"lost-device",description:"Your phone fell in the ocean"},{type:"lost-phrase",description:"Your paper backup burned in a fire"},{type:"lost-both",description:"Phone stolen AND forgot recovery phrase"},{type:"switch-platform",description:"Switching from iPhone to Android"}]}async simulateScenario(e,t){let r=[];switch(e.type){case"lost-device":t.passkeySync.enabled&&t.passkeySync.deviceCount>1&&r.push({method:`Passkey Sync (${t.passkeySync.platform})`,success:!0,time:"5 minutes",requirements:["Sign in to cloud account on new device","Authenticate with biometric/PIN"]}),t.recoveryPhrase.encryptedBackups.length>0&&t.recoveryPhrase.encryptedBackups.forEach(a=>{r.push({method:`Encrypted ${a.method.toUpperCase()} Backup`,success:!0,time:"2 minutes",requirements:["Backup file/QR code","Backup password"]})}),t.socialRecovery?.enabled&&r.push({method:"Social Recovery",success:!0,time:"24 hours",requirements:[`Contact ${t.socialRecovery.threshold} guardians`,"Collect shares from guardians","Verify identity with each guardian"]});break;case"lost-phrase":t.passkeySync.enabled&&r.push({method:"Passkey (current device)",success:!0,time:"Instant",requirements:["Access to current device","Biometric/PIN authentication"]}),t.passkeySync.deviceCount>1&&r.push({method:"Passkey Sync",success:!0,time:"5 minutes",requirements:["Any synced device","Biometric authentication"]}),t.recoveryPhrase.encryptedBackups.length>0&&r.push({method:"Encrypted Backup",success:!0,time:"2 minutes",requirements:["Backup file","Password"]}),t.socialRecovery?.enabled&&r.push({method:"Social Recovery",success:!0,time:"24 hours",requirements:[`${t.socialRecovery.threshold} guardian shares`]});break;case"lost-both":t.passkeySync.deviceCount>1&&r.push({method:"Passkey Sync",success:!0,time:"5 minutes",requirements:["Cloud account access","New device","Biometric setup"]}),t.socialRecovery?.enabled&&r.push({method:"Social Recovery",success:!0,time:"24 hours",requirements:[`${t.socialRecovery.threshold} guardian shares`,"Identity verification with guardians"]});break;case"switch-platform":t.recoveryPhrase.encryptedBackups.length>0&&r.push({method:"Encrypted Backup",success:!0,time:"2 minutes",requirements:["Backup file","Password"]}),t.socialRecovery?.enabled&&r.push({method:"Social Recovery",success:!0,time:"24 hours",requirements:[`${t.socialRecovery.threshold} guardian shares`]});break}let n=r.length>0,o=this.getEducationalNote(e,r,t);return{scenario:e,success:n,availableMethods:r,timeEstimate:n?this.estimateFastestRecovery(r):"Cannot recover",educationalNote:o}}estimateFastestRecovery(e){let t=e.map(r=>r.time.toLowerCase());if(t.some(r=>r.includes("instant")))return"Instant";if(t.some(r=>r.includes("minute"))){let r=t.filter(n=>n.includes("minute")).map(n=>parseInt(n));return`${Math.min(...r)} minutes`}return t.some(r=>r.includes("hour"))?"24 hours":"Unknown"}getEducationalNote(e,t,r){if(t.length===0)return`
|
|
405
405
|
\u274C WALLET CANNOT BE RECOVERED
|
|
406
406
|
|
|
407
407
|
Scenario: ${e.description}
|
|
@@ -442,10 +442,10 @@ Scenario: ${e.description}
|
|
|
442
442
|
|
|
443
443
|
`;return n+=`Available recovery methods (${t.length}):
|
|
444
444
|
|
|
445
|
-
`,t.forEach((o,
|
|
445
|
+
`,t.forEach((o,a)=>{n+=`${a+1}. ${o.method}
|
|
446
446
|
`,n+=` \u23F1 Time: ~${o.time}
|
|
447
447
|
`,n+=` Requirements:
|
|
448
|
-
`,o.requirements.forEach(
|
|
448
|
+
`,o.requirements.forEach(i=>{n+=` - ${i}
|
|
449
449
|
`}),n+=`
|
|
450
450
|
`}),n+=`
|
|
451
451
|
RECOMMENDATIONS:
|
|
@@ -457,19 +457,19 @@ RECOMMENDATIONS:
|
|
|
457
457
|
`,r.socialRecovery?.enabled||(n+=` Consider adding social recovery for maximum security.
|
|
458
458
|
`)):(n+=`\u{1F7E2} Excellent! You have ${t.length} recovery methods.
|
|
459
459
|
`,n+=` Your wallet is well-protected!
|
|
460
|
-
`),n}async runInteractiveTest(e){let t=this.getScenarios(),r=[];for(let
|
|
460
|
+
`),n}async runInteractiveTest(e){let t=this.getScenarios(),r=[];for(let i of t){let c=await this.simulateScenario(i,e);r.push(c)}let n=r.filter(i=>i.success).length,o=n/t.length*100,a="";return o===100?a=`\u{1F3C6} PERFECT SCORE!
|
|
461
461
|
|
|
462
462
|
You can recover in ALL scenarios.
|
|
463
|
-
Your wallet is extremely well-protected!`:o>=75?
|
|
463
|
+
Your wallet is extremely well-protected!`:o>=75?a=`\u{1F7E2} GREAT JOB!
|
|
464
464
|
|
|
465
465
|
You can recover in ${n}/${t.length} scenarios.
|
|
466
|
-
Consider adding more backup methods for complete coverage.`:o>=50?
|
|
466
|
+
Consider adding more backup methods for complete coverage.`:o>=50?a=`\u{1F7E1} GOOD START!
|
|
467
467
|
|
|
468
468
|
You can recover in ${n}/${t.length} scenarios.
|
|
469
|
-
Add more backup methods to improve security.`:
|
|
469
|
+
Add more backup methods to improve security.`:a=`\u26A0\uFE0F AT RISK!
|
|
470
470
|
|
|
471
471
|
You can only recover in ${n}/${t.length} scenarios.
|
|
472
|
-
Urgently add backup methods to protect your wallet!`,{scenarios:r,overallScore:o,feedback:
|
|
472
|
+
Urgently add backup methods to protect your wallet!`,{scenarios:r,overallScore:o,feedback:a}}}});function ze(s){return Re[s]||null}function Ze(){return Object.keys(Re)}function Xe(s){let e=s.toLowerCase();return Object.values(Re).filter(t=>t.title.toLowerCase().includes(e)||t.content.toLowerCase().includes(e))}var Re,It=u(()=>{"use strict";Re={whatIsPasskey:{title:"What is a Passkey?",content:`
|
|
473
473
|
Think of a passkey like your house smart lock:
|
|
474
474
|
|
|
475
475
|
\u{1F511} Traditional Key (Password):
|
|
@@ -773,5 +773,5 @@ STORAGE OPTIONS:
|
|
|
773
773
|
- Email to yourself
|
|
774
774
|
|
|
775
775
|
The encryption makes it safe even in cloud!
|
|
776
|
-
`}}});var ke={};S(ke,{RecoverySimulator:()=>$,educationalModules:()=>Se,getAllTopics:()=>He,getExplainer:()=>Ye,searchExplainers:()=>_e});var z=u(()=>{"use strict";bt();St()});var Xt={};S(Xt,{ApiError:()=>X,AuthenticationError:()=>k,BackupManager:()=>U,BackupStorage:()=>A,CryptoError:()=>y,DeviceManager:()=>q,PlatformDetector:()=>G,RecoverySimulator:()=>$,RegistrationError:()=>T,SocialRecoveryManager:()=>N,StealthAddressModule:()=>F,StorageError:()=>h,VaultSync:()=>L,WalletError:()=>d,Web3Passkey:()=>Y,Web3PasskeyError:()=>g,assertEthereumAddress:()=>ee,assertMnemonic:()=>je,assertUsername:()=>te,canControlStealthAddress:()=>it,checkStealthAddress:()=>Q,computeStealthPrivateKey:()=>he,createWalletFromMnemonic:()=>et,createWeb3Passkey:()=>kt,default:()=>Zt,deriveStealthKeys:()=>D,deriveWalletFromMnemonic:()=>ce,generateBIP39Wallet:()=>ae,generateStealthAddress:()=>pe,getAllTopics:()=>He,getExplainer:()=>Ye,isStrongPassword:()=>Je,searchExplainers:()=>_e,validateEthereumAddress:()=>Pe,validateMnemonic:()=>Re,validateUsername:()=>Ce});module.exports=Dt(Xt);var ze=require("@simplewebauthn/browser");w();function Pe(s){return/^0x[a-fA-F0-9]{40}$/.test(s)}function Ce(s){return s.length>=3&&s.length<=50}function Re(s){let e=s.trim().split(/\s+/);return e.length===12||e.length===24}function ee(s){if(!Pe(s))throw new Error("Invalid Ethereum address format")}function te(s){if(!Ce(s))throw new Error("Username must be between 3 and 50 characters")}function je(s){if(!Re(s))throw new Error("Invalid mnemonic: must be 12 or 24 words")}function Je(s){if(s.length<12)return!1;let e=/[A-Z]/.test(s),t=/[a-z]/.test(s),r=/[0-9]/.test(s),n=/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(s);return!(!e||!t||!r||!n||["password","12345678","qwerty","abc123","password123","admin","letmein"].some(i=>s.toLowerCase().includes(i)))}R();function Ft(){let s=new Uint8Array(32);return crypto.getRandomValues(s),btoa(String.fromCharCode(...s)).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}async function Ze(s){try{let{username:e,ethereumAddress:t}=s;te(e),ee(t);let r=new C;if(r.userExists(e))throw new Error("Username already registered");let o={challenge:Ft(),rp:{name:"w3pk",id:window.location.hostname},user:{id:e,name:e,displayName:e},pubKeyCredParams:[{type:"public-key",alg:-7},{type:"public-key",alg:-257}],authenticatorSelection:{authenticatorAttachment:"platform",userVerification:"required",residentKey:"required",requireResidentKey:!0},timeout:6e4,attestation:"none"},i=await(0,ze.startRegistration)({optionsJSON:o}),c=i.response.publicKey;if(!c)throw new Error("Public key not returned from authenticator");r.saveCredential({id:i.id,publicKey:c,username:e,ethereumAddress:t,createdAt:Date.now(),lastUsed:Date.now()}),console.log("[register] Credential response:",i.response);let a=i.response.attestationObject;if(console.log("[register] Attestation object:",a),!a)throw new Error("Attestation object not returned from authenticator");let l=Mt(a);return console.log("[register] Attestation buffer length:",l.byteLength),{signature:l}}catch(e){throw new T(e instanceof Error?e.message:"Registration failed",e)}}function Mt(s){let e=s.replace(/-/g,"+").replace(/_/g,"/"),t=atob(e),r=new Uint8Array(t.length);for(let n=0;n<t.length;n++)r[n]=t.charCodeAt(n);return r.buffer}var Xe=require("@simplewebauthn/browser");w();R();function Kt(){let s=new Uint8Array(32);return crypto.getRandomValues(s),btoa(String.fromCharCode(...s)).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}async function oe(){try{let s=new C,t={challenge:Kt(),rpId:window.location.hostname,userVerification:"required",timeout:6e4},r=await(0,Xe.startAuthentication)({optionsJSON:t}),n=s.getCredentialById(r.id);if(!n)throw new Error("Credential not found");if(!await Ot(r,n))throw new Error("Signature verification failed");s.updateLastUsed(n.id);let i=se(r.response.signature);return{verified:!0,user:{username:n.username,ethereumAddress:n.ethereumAddress,credentialId:n.id},signature:i}}catch(s){throw new k(s instanceof Error?s.message:"Authentication failed",s)}}async function Ot(s,e){try{let t=se(e.publicKey),r=await crypto.subtle.importKey("spki",t,{name:"ECDSA",namedCurve:"P-256"},!1,["verify"]),n=se(s.response.authenticatorData),o=s.response.clientDataJSON,i;o.startsWith("eyJ")?i=atob(o.replace(/-/g,"+").replace(/_/g,"/")):i=o;let c=await crypto.subtle.digest("SHA-256",new TextEncoder().encode(i)),a=new Uint8Array(n.byteLength+c.byteLength);a.set(new Uint8Array(n),0),a.set(new Uint8Array(c),n.byteLength);let l=se(s.response.signature),p=Ut(new Uint8Array(l));return await crypto.subtle.verify({name:"ECDSA",hash:"SHA-256"},r,p,a)}catch(t){return console.error("Signature verification error:",t),!1}}function se(s){let e=s.replace(/-/g,"+").replace(/_/g,"/"),t=atob(e),r=new Uint8Array(t.length);for(let n=0;n<t.length;n++)r[n]=t.charCodeAt(n);return r.buffer}function Ut(s){let e=2;e++;let t=s[e++];t>32&&(e++,t--);let r=s.slice(e,e+t);e+=t,e++;let n=s[e++];n>32&&(e++,n--);let o=s.slice(e,e+n),i=new Uint8Array(64);return i.set(r,32-r.length),i.set(o,64-o.length),i.buffer}w();var Wt="Web3PasskeyWallet",Nt=1,v="wallets",ie=class{constructor(){this.db=null}async init(){return new Promise((e,t)=>{let r=indexedDB.open(Wt,Nt);r.onerror=()=>t(new h("Failed to open database",r.error)),r.onsuccess=()=>{this.db=r.result,e()},r.onupgradeneeded=()=>{let n=r.result;n.objectStoreNames.contains(v)||n.createObjectStore(v,{keyPath:"ethereumAddress"})}})}async store(e){return this.db||await this.init(),new Promise((t,r)=>{let i=this.db.transaction([v],"readwrite").objectStore(v).put(e);i.onerror=()=>r(new h("Failed to store wallet data",i.error)),i.onsuccess=()=>t()})}async retrieve(e){return this.db||await this.init(),new Promise((t,r)=>{let i=this.db.transaction([v],"readonly").objectStore(v).get(e);i.onerror=()=>r(new h("Failed to retrieve wallet data",i.error)),i.onsuccess=()=>t(i.result||null)})}async delete(e){return this.db||await this.init(),new Promise((t,r)=>{let i=this.db.transaction([v],"readwrite").objectStore(v).delete(e);i.onerror=()=>r(new h("Failed to delete wallet data",i.error)),i.onsuccess=()=>t()})}async clear(){return this.db||await this.init(),new Promise((e,t)=>{let o=this.db.transaction([v],"readwrite").objectStore(v).clear();o.onerror=()=>t(new h("Failed to clear wallet data",o.error)),o.onsuccess=()=>e()})}};var V=require("ethers");w();function ae(){try{let s=V.ethers.Wallet.createRandom().mnemonic;if(!s)throw new Error("Failed to generate mnemonic");let e=s.phrase;return{address:V.ethers.HDNodeWallet.fromPhrase(e,void 0,"m/44'/60'/0'/0/0").address,mnemonic:e}}catch(s){throw new d("Wallet generation failed",s)}}function et(s){try{if(!s||s.trim().split(/\s+/).length<12)throw new Error("Invalid mnemonic: must be at least 12 words");return V.ethers.HDNodeWallet.fromPhrase(s.trim(),void 0,"m/44'/60'/0'/0/0")}catch(e){throw new d(`Wallet creation failed: ${e instanceof Error?e.message:"Invalid mnemonic"}`,e)}}function ce(s,e=0){try{if(!s||s.trim().split(/\s+/).length<12)throw new Error("Invalid mnemonic: must be at least 12 words");if(e<0||!Number.isInteger(e))throw new Error("Index must be a non-negative integer");let t=`m/44'/60'/0'/0/${e}`,r=V.ethers.HDNodeWallet.fromPhrase(s.trim(),void 0,t);return{address:r.address,privateKey:r.privateKey}}catch(t){throw new d(`HD wallet derivation failed: ${t instanceof Error?t.message:"Unknown error"}`,t)}}ue();w();var m=require("ethers");w();function D(s){try{let e=m.ethers.HDNodeWallet.fromPhrase(s,void 0,"m/44'/60'/1'/0/0"),t=m.ethers.HDNodeWallet.fromPhrase(s,void 0,"m/44'/60'/1'/0/1"),r=t.signingKey.compressedPublicKey,n=e.signingKey.compressedPublicKey,o=r+n.slice(2),i=Yt(e.signingKey.publicKey,t.signingKey.publicKey);return{stealthMetaAddress:o,spendingPubKey:r,viewingPubKey:n,viewingKey:e.privateKey,spendingKey:t.privateKey,metaAddress:i}}catch(e){throw new y("Failed to derive stealth keys",e)}}function pe(s){try{let e="0x"+s.slice(2,68),t="0x"+s.slice(68),r=m.ethers.Wallet.createRandom(),n=r.signingKey.compressedPublicKey,o=Ie(r.privateKey,t),i=m.ethers.keccak256(o),c="0x"+i.slice(2,4),a=st(e,nt(i));return{stealthAddress:ot(a),ephemeralPubKey:n,viewTag:c,ephemeralPubkey:n}}catch(e){throw new y("Failed to generate stealth address",e)}}function Q(s,e,t,r,n){try{let o=Ie(s,t),i=m.ethers.keccak256(o);if(n&&("0x"+i.slice(2,4)).toLowerCase()!==n.toLowerCase())return{isForUser:!1};let c=st(e,nt(i)),a=ot(c);return a.toLowerCase()!==r.toLowerCase()?{isForUser:!1}:{isForUser:!0,stealthAddress:a}}catch{return{isForUser:!1}}}function he(s,e,t){try{let r=Ie(s,t),n=m.ethers.keccak256(r);return $t(e,n)}catch(r){throw new y("Failed to compute stealth private key",r)}}function Ie(s,e){try{return new m.ethers.Wallet(s).signingKey.computeSharedSecret(e)}catch(t){throw new y("Failed to compute shared secret",t)}}function nt(s){try{return new m.ethers.Wallet(s).signingKey.compressedPublicKey}catch(e){throw new y("Failed to multiply generator by scalar",e)}}function st(s,e){try{let t=m.ethers.SigningKey.computePublicKey(s,!1),r=m.ethers.SigningKey.computePublicKey(e,!1),n=BigInt("0x"+t.slice(4,68)),o=BigInt("0x"+t.slice(68)),i=BigInt("0x"+r.slice(4,68)),c=BigInt("0x"+r.slice(68)),a=BigInt("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F");if(n===i&&o===c){let Et=3n*n*n%a,Pt=2n*o%a,Ee=Et*rt(Pt,a)%a,Ve=(Ee*Ee-2n*n)%a,Ct=(Ee*(n-Ve)-o)%a;return tt((Ve+a)%a,(Ct+a)%a)}let l=((c-o)%a+a)%a,p=((i-n)%a+a)%a,H=l*rt(p,a)%a,Ae=(H*H-n-i)%a,At=(H*(n-Ae)-o)%a;return tt((Ae+a)%a,(At+a)%a)}catch(t){throw new y("Failed to add public keys",t)}}function $t(s,e){try{let t=BigInt("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"),r=BigInt(s),n=BigInt(e);return"0x"+((r+n)%t).toString(16).padStart(64,"0")}catch(t){throw new y("Failed to add private keys",t)}}function tt(s,e){return"0x"+(e%2n===0n?"02":"03")+s.toString(16).padStart(64,"0")}function rt(s,e){s=(s%e+e)%e;let[t,r]=[s,e],[n,o]=[1n,0n];for(;r!==0n;){let i=t/r;[t,r]=[r,t-i*r],[n,o]=[o,n-i*o]}return(n%e+e)%e}function ot(s){try{let e=m.ethers.SigningKey.computePublicKey(s,!1),t=m.ethers.keccak256("0x"+e.slice(4));return m.ethers.getAddress("0x"+t.slice(-40))}catch(e){throw new y("Failed to derive address from public key",e)}}function Yt(s,e){let t=m.ethers.solidityPackedKeccak256(["bytes","bytes"],[s,e]);return m.ethers.getAddress("0x"+t.slice(26))}function it(s,e,t,r){let n=new m.ethers.Wallet(e);return Q(s,n.signingKey.compressedPublicKey,t,r).isForUser}var F=class{constructor(e,t){this.getMnemonic=t}async generateStealthAddress(e){try{let t=await this.getMnemonic(e?.requireAuth),r=D(t),n=pe(r.stealthMetaAddress);return{stealthAddress:n.stealthAddress,ephemeralPublicKey:n.ephemeralPubKey,viewTag:n.viewTag}}catch(t){throw new g("Failed to generate stealth address","STEALTH_GENERATION_ERROR",t)}}async parseAnnouncement(e,t){try{let r=await this.getMnemonic(t?.requireAuth),n=D(r),o=Q(n.viewingKey,n.spendingPubKey,e.ephemeralPublicKey,e.stealthAddress,e.viewTag);if(!o.isForUser)return{isForUser:!1};let i=he(n.viewingKey,n.spendingKey,e.ephemeralPublicKey);return{isForUser:!0,stealthAddress:o.stealthAddress,stealthPrivateKey:i}}catch(r){throw new g("Failed to parse announcement","ANNOUNCEMENT_PARSE_ERROR",r)}}async scanAnnouncements(e,t){let r=[];for(let n of e){let o=await this.parseAnnouncement(n,t);o.isForUser&&r.push(o)}return r}async getKeys(e){try{let t=await this.getMnemonic(e?.requireAuth);return D(t)}catch(t){throw new g("Failed to get stealth keys","STEALTH_KEYS_ERROR",t)}}async getStealthMetaAddress(e){try{return(await this.getKeys(e)).stealthMetaAddress}catch(t){throw new g("Failed to get stealth meta-address","STEALTH_META_ADDRESS_ERROR",t)}}get isAvailable(){return!0}};var ye=class{constructor(e=1){this.session=null;this.sessionDuration=e*60*60*1e3}startSession(e,t){let r=Date.now()+this.sessionDuration;this.session={mnemonic:e,expiresAt:r,credentialId:t}}getMnemonic(){return this.session?Date.now()>this.session.expiresAt?(this.clearSession(),null):this.session.mnemonic:null}getCredentialId(){return this.session?Date.now()>this.session.expiresAt?(this.clearSession(),null):this.session.credentialId:null}isActive(){return this.getMnemonic()!==null}getRemainingTime(){return this.session?Date.now()>this.session.expiresAt?(this.clearSession(),0):Math.floor((this.session.expiresAt-Date.now())/1e3):0}extendSession(){if(!this.session)throw new Error("No active session to extend");if(Date.now()>this.session.expiresAt)throw this.clearSession(),new Error("Session expired, cannot extend");this.session.expiresAt=Date.now()+this.sessionDuration}clearSession(){this.session&&(this.session.mnemonic="0".repeat(this.session.mnemonic.length)),this.session=null}setSessionDuration(e){this.sessionDuration=e*60*60*1e3}};var Be={debug:!1,sessionDuration:1,onError:s=>{Be.debug&&console.error("[w3pk]",s)}};w();var at="https://chainid.network/chains.json";var me=null,Ht=[/\$\{[\w_]+\}/i,/\{[\w_]+\}/i,/<[\w_]+>/i,/YOUR[-_]?API[-_]?KEY/i,/INSERT[-_]?API[-_]?KEY/i,/API[-_]?KEY[-_]?HERE/i];function _t(s){return Ht.some(e=>e.test(s))}async function Vt(s=at){let e=await fetch(s);if(!e.ok)throw new Error(`Failed to fetch chains data: ${e.status} ${e.statusText}`);return await e.json()}async function Qt(s){let e=s?.chainsJsonUrl??at,t=s?.cacheDuration??36e5,r=Date.now();if(me&&r-me.timestamp<t)return me.data;let n=await Vt(e);return me={data:n,timestamp:r},n}async function ct(s,e){let r=(await Qt(e)).find(n=>n.chainId===s);return r?r.rpc.filter(n=>!_t(n)&&!n.startsWith("wss://")&&!n.startsWith("ws://")):[]}var jt=new Set([1,10,8453,42161,57073,100,42220,137,42,15,40,41,44,46,47,50,51,56,61,71,82,83,95,97,112,123,130,146,151,153,171,180,183,185,195,215,228,247,248,252,261,267,291,293,311,332,336,395,401,416,466,480,488,510,545,634,647,648,747,831,919,938,945,957,964,970,980,995,997,1001,1003,1024,1030,1114,1125,1135,1149,1188,1284,1285,1287,1300,1301,1315,1337,1338,1339,1424,1514,1687,1727,1729,1740,1750,1829,1868,1946,1961,1962,1969,1989,1995,2017,2020,2031,2043,2109,2241,2340,2345,2440,2522,2559,2649,3068,3109,3338,3502,3799,3888,3889,4e3,4048,4078,4162,4201,4202,4460,4488,4661,4689,4690,4888,5e3,5003,5124,5234,5330,5424,5522,6283,6342,6398,6678,6806,6934,6942,6969,7117,7171,7200,7208,7368,7518,7668,7672,7744,7771,7869,7897,8008,8118,8217,8408,8700,8726,8727,8844,8880,8881,8882,8889,9372,9496,9700,9745,9746,9899,9990,9996,10011,10085,10143,10200,11221,11501,11504,11891,13370,14853,16602,16661,17e3,18880,18881,19991,21e3,21816,21912,25327,32323,33401,34443,41923,42170,43111,44787,47805,48898,48900,49049,49088,5e4,50312,53302,53456,53457,55244,56288,59141,60808,60850,62320,62850,64002,71402,72080,73114,73115,75338,78281,80002,80008,80069,80094,80451,80931,84532,88899,91342,92278,94524,96970,97476,97477,98985,100021,100501,101010,102030,102031,102032,112358,120893,121212,121213,121214,121215,129399,161803,175188,192940,193939,198989,212013,222222,240241,325e3,355110,355113,421614,555777,560048,656476,713715,743111,747474,763373,763375,777777,806582,808813,810180,839999,888991,2019775,2222222,4278608,5734951,6666689,6985385,7080969,7777777,9999999,11142220,11155111,11155420,11155931,16969696,19850818,20180427,20250825,28122024,34949059,37084624,52164803,61022448,79479957,96969696,420420421,420420422,888888888,974399131,999999999,1020352220,1273227453,1313161560,1350216234,1380996178,1417429182,1444673419,1482601649,1564830818,2046399126,11297108099,11297108109,88153591557,123420000220,123420001114]);async function Jt(s,e=1e4){try{let t=new AbortController,r=setTimeout(()=>t.abort(),e),n=await fetch(s,{method:"POST",headers:{"Content-Type":"application/json"},signal:t.signal,body:JSON.stringify({jsonrpc:"2.0",method:"eth_estimateGas",params:[{from:"0xdeadbeef00000000000000000000000000000000",to:"0xdeadbeef00000000000000000000000000000000",data:"0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",value:"0x0"},"latest",{"0xdeadbeef00000000000000000000000000000000":{code:"0xef01000000000000000000000000000000000000000001"}}],id:1})});if(clearTimeout(r),!n.ok)return!1;let o=await n.json();if(o.error){let i=(o.error.message||"").toLowerCase();return!["unsupported","not supported","unknown","invalid","unrecognized","does not support","not implemented"].some(a=>i.includes(a))}return o.result!==void 0}catch{return!1}}async function dt(s,e,t){if(jt.has(s))return!0;let r=t?.maxEndpoints||3,n=t?.timeout||1e4;try{let o=await e(s);if(o.length===0)return!1;let i=o.slice(0,r);for(let c of i)if(await Jt(c,n))return!0;return!1}catch{return!1}}var Y=class{constructor(e={}){this.currentUser=null;this.currentWallet=null;this.config={...Be,...e},this.walletStorage=new ie,this.sessionManager=new ye(e.sessionDuration||1),e.stealthAddresses!==void 0&&(this.stealth=new F(e.stealthAddresses,t=>this.getMnemonicFromSession(t)))}async loadZKModule(){if(this.zkModule)return this.zkModule;try{let e=new Function("path","return import(path)"),{ZKProofModule:t}=await e("w3pk/zk"),r=this.config.zkProofs||{};return this.zkModule=new t(r),this.zkModule}catch{throw new Error("ZK module not available. Install dependencies: npm install snarkjs circomlibjs")}}async getMnemonicFromSession(e=!1){if(!e){let l=this.sessionManager.getMnemonic();if(l)return l}if(!this.currentUser)throw new d("Must be authenticated. Call login() first.");let t=await this.walletStorage.retrieve(this.currentUser.ethereumAddress);if(!t)throw new d("No wallet found. Generate a wallet first.");if(!(await oe()).user)throw new d("Authentication failed");let i=new(await Promise.resolve().then(()=>(R(),_))).CredentialStorage().getCredentialById(t.credentialId)?.publicKey,c=await x(t.credentialId,i),a=await le(t.encryptedMnemonic,c);return this.sessionManager.startSession(a,t.credentialId),a}async register(e){try{this.currentWallet?.address||await this.generateWallet();let t=this.currentWallet.address,r=this.currentWallet.mnemonic;await Ze({username:e.username,ethereumAddress:t}),this.currentUser={id:t,username:e.username,displayName:e.username,ethereumAddress:t};let o=new(await Promise.resolve().then(()=>(R(),_))).CredentialStorage().getCredentialByAddress(t);if(!o)throw new d("Credential not found after registration");let i=o.id,c=o.publicKey,a=await x(i,c),l=await de(r,a);return await this.walletStorage.store({ethereumAddress:this.currentUser.ethereumAddress,encryptedMnemonic:l,credentialId:i,createdAt:Date.now()}),this.sessionManager.startSession(r,i),this.currentWallet={address:t,mnemonic:r},this.config.onAuthStateChanged?.(!0,this.currentUser),{address:t,username:e.username}}catch(t){throw this.config.onError?.(t),t}}async login(){try{let e=await oe();if(!e.verified||!e.user)throw new k("Login failed");this.currentUser={id:e.user.ethereumAddress,username:e.user.username,displayName:e.user.username,ethereumAddress:e.user.ethereumAddress};let t=await this.walletStorage.retrieve(this.currentUser.ethereumAddress);if(!t)throw new d("No wallet found for this user. You may need to register first.");let o=new(await Promise.resolve().then(()=>(R(),_))).CredentialStorage().getCredentialById(t.credentialId)?.publicKey,i=await x(t.credentialId,o),c=await le(t.encryptedMnemonic,i);return this.sessionManager.startSession(c,t.credentialId),this.config.onAuthStateChanged?.(!0,this.currentUser),this.currentUser}catch(e){throw this.config.onError?.(e),e}}async logout(){this.currentUser=null,this.currentWallet=null,this.sessionManager.clearSession(),this.config.onAuthStateChanged?.(!1,void 0)}get isAuthenticated(){return this.currentUser!==null}get user(){return this.currentUser}async generateWallet(){try{let e=ae();return this.currentWallet={address:e.address,mnemonic:e.mnemonic},{mnemonic:e.mnemonic}}catch(e){throw this.config.onError?.(e),new d("Failed to generate wallet",e)}}async deriveWallet(e,t){try{if(!this.currentUser)throw new d("Must be authenticated to derive wallet");let r=await this.getMnemonicFromSession(t?.requireAuth),n=ce(r,e);return{address:n.address,privateKey:n.privateKey}}catch(r){throw this.config.onError?.(r),new d("Failed to derive wallet",r)}}async exportMnemonic(e){try{if(!this.currentUser)throw new d("Must be authenticated to export mnemonic");return await this.getMnemonicFromSession(e?.requireAuth)}catch(t){throw this.config.onError?.(t),new d("Failed to export mnemonic",t)}}async importMnemonic(e){try{if(!this.currentUser)throw new d("Must be authenticated to import mnemonic");if(!e||e.trim().split(/\s+/).length<12)throw new d("Invalid mnemonic: must be at least 12 words");let t=await oe();if(!t.user)throw new d("Authentication failed");let r=t.user.credentialId,i=new(await Promise.resolve().then(()=>(R(),_))).CredentialStorage().getCredentialById(r)?.publicKey,c=await x(r,i),a=await de(e.trim(),c);await this.walletStorage.store({ethereumAddress:this.currentUser.ethereumAddress,encryptedMnemonic:a,credentialId:r,createdAt:Date.now()}),this.currentWallet={address:this.currentUser.ethereumAddress,mnemonic:e.trim()},this.sessionManager.startSession(e.trim(),r)}catch(t){throw this.config.onError?.(t),new d("Failed to import mnemonic",t)}}async signMessage(e,t){try{if(!this.currentUser)throw new d("Must be authenticated to sign message");let r=await this.getMnemonicFromSession(t?.requireAuth),{Wallet:n}=await import("ethers");return await n.fromPhrase(r).signMessage(e)}catch(r){throw this.config.onError?.(r),new d("Failed to sign message",r)}}async getEndpoints(e){return ct(e)}async supportsEIP7702(e,t){return dt(e,this.getEndpoints.bind(this),t)}get zk(){return new Proxy({},{get:(e,t)=>async(...r)=>(await this.loadZKModule())[t](...r)})}async getBackupStatus(){if(!this.currentUser)throw new d("Must be authenticated to check backup status");let{BackupManager:e}=await Promise.resolve().then(()=>(I(),W));return new e().getBackupStatus(this.currentUser.ethereumAddress)}async createZipBackup(e,t){if(!this.currentUser)throw new d("Must be authenticated to create backup");let r=await this.getMnemonicFromSession(!0),{BackupManager:n}=await Promise.resolve().then(()=>(I(),W));return new n().createZipBackup(r,this.currentUser.ethereumAddress,{password:e,...t})}async createQRBackup(e,t){if(!this.currentUser)throw new d("Must be authenticated to create backup");let r=await this.getMnemonicFromSession(!0),{BackupManager:n}=await Promise.resolve().then(()=>(I(),W));return new n().createQRBackup(r,this.currentUser.ethereumAddress,{password:e,...t})}async setupSocialRecovery(e,t){if(!this.currentUser)throw new d("Must be authenticated to set up social recovery");let r=await this.getMnemonicFromSession(!0),{SocialRecoveryManager:n}=await Promise.resolve().then(()=>(J(),ve));return new n().setupSocialRecovery(r,this.currentUser.ethereumAddress,e,t)}async generateGuardianInvite(e){let{SocialRecoveryManager:t}=await Promise.resolve().then(()=>(J(),ve)),r=new t,n=r.getSocialRecoveryConfig();if(!n)throw new d("Social recovery not configured");let o=n.guardians.find(i=>i.id===e);if(!o)throw new d("Guardian not found");return r.generateGuardianInvite(o)}async recoverFromGuardians(e){let{SocialRecoveryManager:t}=await Promise.resolve().then(()=>(J(),ve));return new t().recoverFromGuardians(e)}async restoreFromBackup(e,t){let{BackupManager:r}=await Promise.resolve().then(()=>(I(),W));return new r().restoreFromZipBackup(e,t)}async restoreFromQR(e,t){let{BackupManager:r}=await Promise.resolve().then(()=>(I(),W));return new r().restoreFromQR(e,t)}async getSyncStatus(){let{DeviceManager:e}=await Promise.resolve().then(()=>(be(),$e));return new e().getSyncStatus()}async detectSyncCapabilities(){let{PlatformDetector:e}=await Promise.resolve().then(()=>(be(),$e));return new e().detectSyncCapabilities()}async simulateRecoveryScenario(e){if(!this.currentUser)throw new d("Must be authenticated to run recovery simulation");let t=await this.getBackupStatus(),{RecoverySimulator:r}=await Promise.resolve().then(()=>(z(),ke));return new r().simulateScenario(e,t)}async runRecoveryTest(){if(!this.currentUser)throw new d("Must be authenticated to run recovery test");let e=await this.getBackupStatus(),{RecoverySimulator:t}=await Promise.resolve().then(()=>(z(),ke));return new t().runInteractiveTest(e)}async getEducation(e){let{getExplainer:t}=await Promise.resolve().then(()=>(z(),ke)),r=t(e);if(!r)throw new d(`Unknown education topic: ${e}`);return r}hasActiveSession(){return this.sessionManager.isActive()}getSessionRemainingTime(){return this.sessionManager.getRemainingTime()}extendSession(){try{this.sessionManager.extendSession()}catch(e){throw new d("Cannot extend session",e)}}clearSession(){this.sessionManager.clearSession()}setSessionDuration(e){this.sessionManager.setSessionDuration(e)}get version(){return"0.7.2"}};w();I();J();be();z();function kt(s={}){return new Y(s)}var Zt=kt;
|
|
776
|
+
`}}});var xe={};S(xe,{RecoverySimulator:()=>V,educationalModules:()=>Re,getAllTopics:()=>Ze,getExplainer:()=>ze,searchExplainers:()=>Xe});var ae=u(()=>{"use strict";xt();It()});var sr={};S(sr,{ApiError:()=>ce,AuthenticationError:()=>k,BackupManager:()=>q,BackupStorage:()=>E,CryptoError:()=>h,DeviceManager:()=>H,PlatformDetector:()=>_,RecoverySimulator:()=>V,RegistrationError:()=>D,SocialRecoveryManager:()=>G,StealthAddressModule:()=>O,StorageError:()=>y,VaultSync:()=>Y,WalletError:()=>d,Web3Passkey:()=>Q,Web3PasskeyError:()=>m,assertEthereumAddress:()=>de,assertMnemonic:()=>rt,assertUsername:()=>le,canControlStealthAddress:()=>ut,checkStealthAddress:()=>re,computeStealthPrivateKey:()=>ne,createWalletFromMnemonic:()=>ct,createWeb3Passkey:()=>Bt,default:()=>nr,deriveStealthKeys:()=>U,deriveWalletFromMnemonic:()=>we,generateBIP39Wallet:()=>fe,generateStealthAddress:()=>ve,getAllTopics:()=>Ze,getExplainer:()=>ze,isStrongPassword:()=>nt,searchExplainers:()=>Xe,validateEthereumAddress:()=>Te,validateMnemonic:()=>Fe,validateUsername:()=>De});module.exports=Lt(sr);var ot=require("@simplewebauthn/browser");w();function Te(s){return/^0x[a-fA-F0-9]{40}$/.test(s)}function De(s){return s.length>=3&&s.length<=50}function Fe(s){let e=s.trim().split(/\s+/);return e.length===12||e.length===24}function de(s){if(!Te(s))throw new Error("Invalid Ethereum address format")}function le(s){if(!De(s))throw new Error("Username must be between 3 and 50 characters")}function rt(s){if(!Fe(s))throw new Error("Invalid mnemonic: must be 12 or 24 words")}function nt(s){if(s.length<12)return!1;let e=/[A-Z]/.test(s),t=/[a-z]/.test(s),r=/[0-9]/.test(s),n=/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(s);return!(!e||!t||!r||!n||["password","12345678","qwerty","abc123","password123","admin","letmein"].some(a=>s.toLowerCase().includes(a)))}I();J();function Gt(){let s=new Uint8Array(32);return crypto.getRandomValues(s),A(s)}async function at(s){try{let{username:e,ethereumAddress:t}=s;le(e),de(t);let r=new x;if(await r.userExists(e))throw new Error("Username already registered");let o={challenge:Gt(),rp:{name:"w3pk",id:window.location.hostname},user:{id:e,name:e,displayName:e},pubKeyCredParams:[{type:"public-key",alg:-7},{type:"public-key",alg:-257}],authenticatorSelection:{authenticatorAttachment:"platform",userVerification:"required",residentKey:"required",requireResidentKey:!0},timeout:6e4,attestation:"none"},a=await(0,ot.startRegistration)({optionsJSON:o}),i=a.response.publicKey;if(!i)throw new Error("Public key not returned from authenticator");await r.saveCredential({id:a.id,publicKey:i,username:e,ethereumAddress:t,createdAt:Date.now(),lastUsed:Date.now()}),console.log("[register] Credential response:",a.response);let c=a.response.attestationObject;if(console.log("[register] Attestation object:",c),!c)throw new Error("Attestation object not returned from authenticator");let l=R(c);return console.log("[register] Attestation buffer length:",l.byteLength),{signature:l}}catch(e){throw new D(e instanceof Error?e.message:"Registration failed",e)}}var it=require("@simplewebauthn/browser");w();I();J();function Yt(){let s=new Uint8Array(32);return crypto.getRandomValues(s),A(s)}async function me(){try{let s=new x,t={challenge:Yt(),rpId:window.location.hostname,userVerification:"required",timeout:6e4},r=await(0,it.startAuthentication)({optionsJSON:t}),n=await s.getCredentialById(r.id);if(!n)throw new Error("Credential not found");if(!await Ht(r,n))throw new Error("Signature verification failed");await s.updateLastUsed(n.id);let a=R(r.response.signature);return{verified:!0,user:{username:n.username,ethereumAddress:n.ethereumAddress,credentialId:n.id},signature:a}}catch(s){throw new k(s instanceof Error?s.message:"Authentication failed",s)}}async function Ht(s,e){try{let t=R(e.publicKey),r=await crypto.subtle.importKey("spki",t,{name:"ECDSA",namedCurve:"P-256"},!1,["verify"]),n=R(s.response.authenticatorData),o=s.response.clientDataJSON,a;o.startsWith("eyJ")?a=F(o):a=o;let i=await crypto.subtle.digest("SHA-256",new TextEncoder().encode(a)),c=new Uint8Array(n.byteLength+i.byteLength);c.set(new Uint8Array(n),0),c.set(new Uint8Array(i),n.byteLength);let l=R(s.response.signature),p=_t(new Uint8Array(l));return await crypto.subtle.verify({name:"ECDSA",hash:"SHA-256"},r,p,c)}catch(t){return console.error("Signature verification error:",t),!1}}function _t(s){let e=2;e++;let t=s[e++];t>32&&(e++,t--);let r=s.slice(e,e+t);e+=t,e++;let n=s[e++];n>32&&(e++,n--);let o=s.slice(e,e+n),a=new Uint8Array(64);return a.set(r,32-r.length),a.set(o,64-o.length),a.buffer}w();var Vt="Web3PasskeyWallet",Qt=1,v="wallets",ge=class{constructor(){this.db=null}async init(){return new Promise((e,t)=>{let r=indexedDB.open(Vt,Qt);r.onerror=()=>t(new y("Failed to open database",r.error)),r.onsuccess=()=>{this.db=r.result,e()},r.onupgradeneeded=()=>{let n=r.result;n.objectStoreNames.contains(v)||n.createObjectStore(v,{keyPath:"ethereumAddress"})}})}async store(e){return this.db||await this.init(),new Promise((t,r)=>{let a=this.db.transaction([v],"readwrite").objectStore(v).put(e);a.onerror=()=>r(new y("Failed to store wallet data",a.error)),a.onsuccess=()=>t()})}async retrieve(e){return this.db||await this.init(),new Promise((t,r)=>{let a=this.db.transaction([v],"readonly").objectStore(v).get(e);a.onerror=()=>r(new y("Failed to retrieve wallet data",a.error)),a.onsuccess=()=>t(a.result||null)})}async delete(e){return this.db||await this.init(),new Promise((t,r)=>{let a=this.db.transaction([v],"readwrite").objectStore(v).delete(e);a.onerror=()=>r(new y("Failed to delete wallet data",a.error)),a.onsuccess=()=>t()})}async clear(){return this.db||await this.init(),new Promise((e,t)=>{let o=this.db.transaction([v],"readwrite").objectStore(v).clear();o.onerror=()=>t(new y("Failed to clear wallet data",o.error)),o.onsuccess=()=>e()})}};var te=require("ethers");w();function fe(){try{let s=te.ethers.Wallet.createRandom().mnemonic;if(!s)throw new Error("Failed to generate mnemonic");let e=s.phrase;return{address:te.ethers.HDNodeWallet.fromPhrase(e,void 0,"m/44'/60'/0'/0/0").address,mnemonic:e}}catch(s){throw new d("Wallet generation failed",s)}}function ct(s){try{if(!s||s.trim().split(/\s+/).length<12)throw new Error("Invalid mnemonic: must be at least 12 words");return te.ethers.HDNodeWallet.fromPhrase(s.trim(),void 0,"m/44'/60'/0'/0/0")}catch(e){throw new d(`Wallet creation failed: ${e instanceof Error?e.message:"Invalid mnemonic"}`,e)}}function we(s,e=0){try{if(!s||s.trim().split(/\s+/).length<12)throw new Error("Invalid mnemonic: must be at least 12 words");if(e<0||!Number.isInteger(e))throw new Error("Index must be a non-negative integer");let t=`m/44'/60'/0'/0/${e}`,r=te.ethers.HDNodeWallet.fromPhrase(s.trim(),void 0,t);return{address:r.address,privateKey:r.privateKey}}catch(t){throw new d(`HD wallet derivation failed: ${t instanceof Error?t.message:"Unknown error"}`,t)}}X();w();var g=require("ethers");w();function U(s){try{let e=g.ethers.HDNodeWallet.fromPhrase(s,void 0,"m/44'/60'/1'/0/0"),t=g.ethers.HDNodeWallet.fromPhrase(s,void 0,"m/44'/60'/1'/0/1"),r=t.signingKey.compressedPublicKey,n=e.signingKey.compressedPublicKey;return{stealthMetaAddress:r+n.slice(2),spendingPubKey:r,viewingPubKey:n,viewingKey:e.privateKey,spendingKey:t.privateKey}}catch(e){throw new h("Failed to derive stealth keys",e)}}function ve(s){try{let e="0x"+s.slice(2,68),t="0x"+s.slice(68),r=g.ethers.Wallet.createRandom(),n=r.signingKey.compressedPublicKey,o=Ue(r.privateKey,t),a=g.ethers.keccak256(o),i="0x"+a.slice(2,4),c=ht(e,pt(a));return{stealthAddress:yt(c),ephemeralPubKey:n,viewTag:i}}catch(e){throw new h("Failed to generate stealth address",e)}}function re(s,e,t,r,n){try{let o=Ue(s,t),a=g.ethers.keccak256(o);if(n&&("0x"+a.slice(2,4)).toLowerCase()!==n.toLowerCase())return{isForUser:!1};let i=ht(e,pt(a)),c=yt(i);return c.toLowerCase()!==r.toLowerCase()?{isForUser:!1}:{isForUser:!0,stealthAddress:c}}catch{return{isForUser:!1}}}function ne(s,e,t){try{let r=Ue(s,t),n=g.ethers.keccak256(r);return jt(e,n)}catch(r){throw new h("Failed to compute stealth private key",r)}}function ut(s,e,t,r,n,o){try{if(!re(s,t,r,n,o).isForUser)return!1;let i=ne(s,e,r);return new g.ethers.Wallet(i).address.toLowerCase()===n.toLowerCase()}catch{return!1}}function Ue(s,e){try{return new g.ethers.Wallet(s).signingKey.computeSharedSecret(e)}catch(t){throw new h("Failed to compute shared secret",t)}}function pt(s){try{return new g.ethers.Wallet(s).signingKey.compressedPublicKey}catch(e){throw new h("Failed to multiply generator by scalar",e)}}function ht(s,e){try{let t=g.ethers.SigningKey.computePublicKey(s,!1),r=g.ethers.SigningKey.computePublicKey(e,!1),n=BigInt("0x"+t.slice(4,68)),o=BigInt("0x"+t.slice(68)),a=BigInt("0x"+r.slice(4,68)),i=BigInt("0x"+r.slice(68)),c=BigInt("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F");if(n===a&&o===i){let Dt=3n*n*n%c,Ft=2n*o%c,Be=Dt*lt(Ft,c)%c,et=(Be*Be-2n*n)%c,Mt=(Be*(n-et)-o)%c;return dt((et+c)%c,(Mt+c)%c)}let l=((i-o)%c+c)%c,p=((a-n)%c+c)%c,j=l*lt(p,c)%c,Ie=(j*j-n-a)%c,Tt=(j*(n-Ie)-o)%c;return dt((Ie+c)%c,(Tt+c)%c)}catch(t){throw new h("Failed to add public keys",t)}}function jt(s,e){try{let t=BigInt("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"),r=BigInt(s),n=BigInt(e);return"0x"+((r+n)%t).toString(16).padStart(64,"0")}catch(t){throw new h("Failed to add private keys",t)}}function dt(s,e){return"0x"+(e%2n===0n?"02":"03")+s.toString(16).padStart(64,"0")}function lt(s,e){s=(s%e+e)%e;let[t,r]=[s,e],[n,o]=[1n,0n];for(;r!==0n;){let a=t/r;[t,r]=[r,t-a*r],[n,o]=[o,n-a*o]}return(n%e+e)%e}function yt(s){try{let e=g.ethers.SigningKey.computePublicKey(s,!1),t=g.ethers.keccak256("0x"+e.slice(4));return g.ethers.getAddress("0x"+t.slice(-40))}catch(e){throw new h("Failed to derive address from public key",e)}}var O=class{constructor(e,t){this.getMnemonic=t}async generateStealthAddress(e){try{let t=await this.getMnemonic(e?.requireAuth),r=U(t),n=ve(r.stealthMetaAddress);return{stealthAddress:n.stealthAddress,ephemeralPublicKey:n.ephemeralPubKey,viewTag:n.viewTag}}catch(t){throw new m("Failed to generate stealth address","STEALTH_GENERATION_ERROR",t)}}async parseAnnouncement(e,t){try{let r=await this.getMnemonic(t?.requireAuth),n=U(r),o=re(n.viewingKey,n.spendingPubKey,e.ephemeralPublicKey,e.stealthAddress,e.viewTag);if(!o.isForUser)return{isForUser:!1};let a=ne(n.viewingKey,n.spendingKey,e.ephemeralPublicKey);return{isForUser:!0,stealthAddress:o.stealthAddress,stealthPrivateKey:a}}catch(r){throw new m("Failed to parse announcement","ANNOUNCEMENT_PARSE_ERROR",r)}}async scanAnnouncements(e,t){let r=[];for(let n of e){let o=await this.parseAnnouncement(n,t);o.isForUser&&r.push(o)}return r}async getKeys(e){try{let t=await this.getMnemonic(e?.requireAuth);return U(t)}catch(t){throw new m("Failed to get stealth keys","STEALTH_KEYS_ERROR",t)}}async getStealthMetaAddress(e){try{return(await this.getKeys(e)).stealthMetaAddress}catch(t){throw new m("Failed to get stealth meta-address","STEALTH_META_ADDRESS_ERROR",t)}}get isAvailable(){return!0}};var be=class{constructor(e=1){this.session=null;this.sessionDuration=e*60*60*1e3}startSession(e,t){let r=Date.now()+this.sessionDuration;this.session={mnemonic:e,expiresAt:r,credentialId:t}}getMnemonic(){return this.session?Date.now()>this.session.expiresAt?(this.clearSession(),null):this.session.mnemonic:null}getCredentialId(){return this.session?Date.now()>this.session.expiresAt?(this.clearSession(),null):this.session.credentialId:null}isActive(){return this.getMnemonic()!==null}getRemainingTime(){return this.session?Date.now()>this.session.expiresAt?(this.clearSession(),0):Math.floor((this.session.expiresAt-Date.now())/1e3):0}extendSession(){if(!this.session)throw new Error("No active session to extend");if(Date.now()>this.session.expiresAt)throw this.clearSession(),new Error("Session expired, cannot extend");this.session.expiresAt=Date.now()+this.sessionDuration}clearSession(){this.session&&(this.session.mnemonic="0".repeat(this.session.mnemonic.length)),this.session=null}setSessionDuration(e){this.sessionDuration=e*60*60*1e3}};var Oe={debug:!1,sessionDuration:1,onError:s=>{Oe.debug&&console.error("[w3pk]",s)}};w();var mt="https://chainid.network/chains.json";var Se=null,Jt=[/\$\{[\w_]+\}/i,/\{[\w_]+\}/i,/<[\w_]+>/i,/YOUR[-_]?API[-_]?KEY/i,/INSERT[-_]?API[-_]?KEY/i,/API[-_]?KEY[-_]?HERE/i];function zt(s){return Jt.some(e=>e.test(s))}async function Zt(s=mt){let e=await fetch(s);if(!e.ok)throw new Error(`Failed to fetch chains data: ${e.status} ${e.statusText}`);return await e.json()}async function Xt(s){let e=s?.chainsJsonUrl??mt,t=s?.cacheDuration??36e5,r=Date.now();if(Se&&r-Se.timestamp<t)return Se.data;let n=await Zt(e);return Se={data:n,timestamp:r},n}async function gt(s,e){let r=(await Xt(e)).find(n=>n.chainId===s);return r?r.rpc.filter(n=>!zt(n)&&!n.startsWith("wss://")&&!n.startsWith("ws://")):[]}var er=new Set([1,10,8453,42161,57073,100,42220,137,42,15,40,41,44,46,47,50,51,56,61,71,82,83,95,97,112,123,130,146,151,153,171,180,183,185,195,215,228,247,248,252,261,267,291,293,311,332,336,395,401,416,466,480,488,510,545,634,647,648,747,831,919,938,945,957,964,970,980,995,997,1001,1003,1024,1030,1114,1125,1135,1149,1188,1284,1285,1287,1300,1301,1315,1337,1338,1339,1424,1514,1687,1727,1729,1740,1750,1829,1868,1946,1961,1962,1969,1989,1995,2017,2020,2031,2043,2109,2241,2340,2345,2440,2522,2559,2649,3068,3109,3338,3502,3799,3888,3889,4e3,4048,4078,4162,4201,4202,4460,4488,4661,4689,4690,4888,5e3,5003,5124,5234,5330,5424,5522,6283,6342,6398,6678,6806,6934,6942,6969,7117,7171,7200,7208,7368,7518,7668,7672,7744,7771,7869,7897,8008,8118,8217,8408,8700,8726,8727,8844,8880,8881,8882,8889,9372,9496,9700,9745,9746,9899,9990,9996,10011,10085,10143,10200,11221,11501,11504,11891,13370,14853,16602,16661,17e3,18880,18881,19991,21e3,21816,21912,25327,32323,33401,34443,41923,42170,43111,44787,47805,48898,48900,49049,49088,5e4,50312,53302,53456,53457,55244,56288,59141,60808,60850,62320,62850,64002,71402,72080,73114,73115,75338,78281,80002,80008,80069,80094,80451,80931,84532,88899,91342,92278,94524,96970,97476,97477,98985,100021,100501,101010,102030,102031,102032,112358,120893,121212,121213,121214,121215,129399,161803,175188,192940,193939,198989,212013,222222,240241,325e3,355110,355113,421614,555777,560048,656476,713715,743111,747474,763373,763375,777777,806582,808813,810180,839999,888991,2019775,2222222,4278608,5734951,6666689,6985385,7080969,7777777,9999999,11142220,11155111,11155420,11155931,16969696,19850818,20180427,20250825,28122024,34949059,37084624,52164803,61022448,79479957,96969696,420420421,420420422,888888888,974399131,999999999,1020352220,1273227453,1313161560,1350216234,1380996178,1417429182,1444673419,1482601649,1564830818,2046399126,11297108099,11297108109,88153591557,123420000220,123420001114]);async function tr(s,e=1e4){try{let t=new AbortController,r=setTimeout(()=>t.abort(),e),n=await fetch(s,{method:"POST",headers:{"Content-Type":"application/json"},signal:t.signal,body:JSON.stringify({jsonrpc:"2.0",method:"eth_estimateGas",params:[{from:"0xdeadbeef00000000000000000000000000000000",to:"0xdeadbeef00000000000000000000000000000000",data:"0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",value:"0x0"},"latest",{"0xdeadbeef00000000000000000000000000000000":{code:"0xef01000000000000000000000000000000000000000001"}}],id:1})});if(clearTimeout(r),!n.ok)return!1;let o=await n.json();if(o.error){let a=(o.error.message||"").toLowerCase();return!["unsupported","not supported","unknown","invalid","unrecognized","does not support","not implemented"].some(c=>a.includes(c))}return o.result!==void 0}catch{return!1}}async function ft(s,e,t){if(er.has(s))return!0;let r=t?.maxEndpoints||3,n=t?.timeout||1e4;try{let o=await e(s);if(o.length===0)return!1;let a=o.slice(0,r);for(let i of a)if(await tr(i,n))return!0;return!1}catch{return!1}}var Q=class{constructor(e={}){this.currentUser=null;this.currentWallet=null;this.config={...Oe,...e},this.walletStorage=new ge,this.sessionManager=new be(e.sessionDuration||1),e.stealthAddresses!==void 0&&(this.stealth=new O(e.stealthAddresses,t=>this.getMnemonicFromSession(t)))}async loadZKModule(){if(this.zkModule)return this.zkModule;try{let e=new Function("path","return import(path)"),{ZKProofModule:t}=await e("w3pk/zk"),r=this.config.zkProofs||{};return this.zkModule=new t(r),this.zkModule}catch{throw new Error("ZK module not available. Install dependencies: npm install snarkjs circomlibjs")}}async getMnemonicFromSession(e=!1){if(!e){let l=this.sessionManager.getMnemonic();if(l)return l}if(!this.currentUser)throw new d("Must be authenticated. Call login() first.");let t=await this.walletStorage.retrieve(this.currentUser.ethereumAddress);if(!t)throw new d("No wallet found. Generate a wallet first.");if(!(await me()).user)throw new d("Authentication failed");let a=(await new(await Promise.resolve().then(()=>(I(),ee))).CredentialStorage().getCredentialById(t.credentialId))?.publicKey,i=await M(t.credentialId,a),c=await Z(t.encryptedMnemonic,i);return this.sessionManager.startSession(c,t.credentialId),c}async register(e){try{this.currentWallet?.address||await this.generateWallet();let t=this.currentWallet.address,r=this.currentWallet.mnemonic;await at({username:e.username,ethereumAddress:t}),this.currentUser={id:t,username:e.username,displayName:e.username,ethereumAddress:t};let o=await new(await Promise.resolve().then(()=>(I(),ee))).CredentialStorage().getCredentialByAddress(t);if(!o)throw new d("Credential not found after registration");let a=o.id,i=o.publicKey,c=await M(a,i),l=await z(r,c);return await this.walletStorage.store({ethereumAddress:this.currentUser.ethereumAddress,encryptedMnemonic:l,credentialId:a,createdAt:Date.now()}),this.sessionManager.startSession(r,a),this.currentWallet={address:t,mnemonic:r},this.config.onAuthStateChanged?.(!0,this.currentUser),{address:t,username:e.username}}catch(t){throw this.config.onError?.(t),t}}async login(){try{let e=await me();if(!e.verified||!e.user)throw new k("Login failed");this.currentUser={id:e.user.ethereumAddress,username:e.user.username,displayName:e.user.username,ethereumAddress:e.user.ethereumAddress};let t=await this.walletStorage.retrieve(this.currentUser.ethereumAddress);if(!t)throw new d("No wallet found for this user. You may need to register first.");let o=(await new(await Promise.resolve().then(()=>(I(),ee))).CredentialStorage().getCredentialById(t.credentialId))?.publicKey,a=await M(t.credentialId,o),i=await Z(t.encryptedMnemonic,a);return this.sessionManager.startSession(i,t.credentialId),this.config.onAuthStateChanged?.(!0,this.currentUser),this.currentUser}catch(e){throw this.config.onError?.(e),e}}async logout(){this.currentUser=null,this.currentWallet=null,this.sessionManager.clearSession(),this.config.onAuthStateChanged?.(!1,void 0)}get isAuthenticated(){return this.currentUser!==null}get user(){return this.currentUser}async generateWallet(){try{let e=fe();return this.currentWallet={address:e.address,mnemonic:e.mnemonic},{mnemonic:e.mnemonic}}catch(e){throw this.config.onError?.(e),new d("Failed to generate wallet",e)}}async deriveWallet(e,t){try{if(!this.currentUser)throw new d("Must be authenticated to derive wallet");let r=await this.getMnemonicFromSession(t?.requireAuth),n=we(r,e);return{address:n.address,privateKey:n.privateKey}}catch(r){throw this.config.onError?.(r),new d("Failed to derive wallet",r)}}async exportMnemonic(e){try{if(!this.currentUser)throw new d("Must be authenticated to export mnemonic");return await this.getMnemonicFromSession(e?.requireAuth)}catch(t){throw this.config.onError?.(t),new d("Failed to export mnemonic",t)}}async importMnemonic(e){try{if(!this.currentUser)throw new d("Must be authenticated to import mnemonic");if(!e||e.trim().split(/\s+/).length<12)throw new d("Invalid mnemonic: must be at least 12 words");let t=await me();if(!t.user)throw new d("Authentication failed");let r=t.user.credentialId,a=(await new(await Promise.resolve().then(()=>(I(),ee))).CredentialStorage().getCredentialById(r))?.publicKey,i=await M(r,a),c=await z(e.trim(),i);await this.walletStorage.store({ethereumAddress:this.currentUser.ethereumAddress,encryptedMnemonic:c,credentialId:r,createdAt:Date.now()}),this.currentWallet={address:this.currentUser.ethereumAddress,mnemonic:e.trim()},this.sessionManager.startSession(e.trim(),r)}catch(t){throw this.config.onError?.(t),new d("Failed to import mnemonic",t)}}async signMessage(e,t){try{if(!this.currentUser)throw new d("Must be authenticated to sign message");let r=await this.getMnemonicFromSession(t?.requireAuth),{Wallet:n}=await import("ethers");return await n.fromPhrase(r).signMessage(e)}catch(r){throw this.config.onError?.(r),new d("Failed to sign message",r)}}async getEndpoints(e){return gt(e)}async supportsEIP7702(e,t){return ft(e,this.getEndpoints.bind(this),t)}get zk(){return new Proxy({},{get:(e,t)=>async(...r)=>(await this.loadZKModule())[t](...r)})}async getBackupStatus(){if(!this.currentUser)throw new d("Must be authenticated to check backup status");let{BackupManager:e}=await Promise.resolve().then(()=>(B(),$));return new e().getBackupStatus(this.currentUser.ethereumAddress)}async createZipBackup(e,t){if(!this.currentUser)throw new d("Must be authenticated to create backup");let r=await this.getMnemonicFromSession(!0),{BackupManager:n}=await Promise.resolve().then(()=>(B(),$));return new n().createZipBackup(r,this.currentUser.ethereumAddress,{password:e,...t})}async createQRBackup(e,t){if(!this.currentUser)throw new d("Must be authenticated to create backup");let r=await this.getMnemonicFromSession(!0),{BackupManager:n}=await Promise.resolve().then(()=>(B(),$));return new n().createQRBackup(r,this.currentUser.ethereumAddress,{password:e,...t})}async setupSocialRecovery(e,t){if(!this.currentUser)throw new d("Must be authenticated to set up social recovery");let r=await this.getMnemonicFromSession(!0),{SocialRecoveryManager:n}=await Promise.resolve().then(()=>(oe(),Pe));return new n().setupSocialRecovery(r,this.currentUser.ethereumAddress,e,t)}async generateGuardianInvite(e){let{SocialRecoveryManager:t}=await Promise.resolve().then(()=>(oe(),Pe)),r=new t,n=r.getSocialRecoveryConfig();if(!n)throw new d("Social recovery not configured");let o=n.guardians.find(a=>a.id===e);if(!o)throw new d("Guardian not found");return r.generateGuardianInvite(o)}async recoverFromGuardians(e){let{SocialRecoveryManager:t}=await Promise.resolve().then(()=>(oe(),Pe));return new t().recoverFromGuardians(e)}async restoreFromBackup(e,t){let{BackupManager:r}=await Promise.resolve().then(()=>(B(),$));return new r().restoreFromZipBackup(e,t)}async restoreFromQR(e,t){let{BackupManager:r}=await Promise.resolve().then(()=>(B(),$));return new r().restoreFromQR(e,t)}async getSyncStatus(){let{DeviceManager:e}=await Promise.resolve().then(()=>(Ce(),Je));return new e().getSyncStatus()}async detectSyncCapabilities(){let{PlatformDetector:e}=await Promise.resolve().then(()=>(Ce(),Je));return new e().detectSyncCapabilities()}async simulateRecoveryScenario(e){if(!this.currentUser)throw new d("Must be authenticated to run recovery simulation");let t=await this.getBackupStatus(),{RecoverySimulator:r}=await Promise.resolve().then(()=>(ae(),xe));return new r().simulateScenario(e,t)}async runRecoveryTest(){if(!this.currentUser)throw new d("Must be authenticated to run recovery test");let e=await this.getBackupStatus(),{RecoverySimulator:t}=await Promise.resolve().then(()=>(ae(),xe));return new t().runInteractiveTest(e)}async getEducation(e){let{getExplainer:t}=await Promise.resolve().then(()=>(ae(),xe)),r=t(e);if(!r)throw new d(`Unknown education topic: ${e}`);return r}hasActiveSession(){return this.sessionManager.isActive()}getSessionRemainingTime(){return this.sessionManager.getRemainingTime()}extendSession(){try{this.sessionManager.extendSession()}catch(e){throw new d("Cannot extend session",e)}}clearSession(){this.sessionManager.clearSession()}setSessionDuration(e){this.sessionManager.setSessionDuration(e)}};w();B();oe();Ce();ae();function Bt(s={}){return new Q(s)}var nr=Bt;
|
|
777
777
|
//# sourceMappingURL=index.js.map
|