@pasosdejesus/m 0.23.0 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/CHANGELOG.md +47 -0
- package/dist/e2e/env.test.js +13 -0
- package/dist/e2e/env.test.js.map +1 -1
- package/dist/e2e/full-wallet.d.ts +41 -0
- package/dist/e2e/full-wallet.d.ts.map +1 -0
- package/dist/e2e/full-wallet.js +138 -0
- package/dist/e2e/full-wallet.js.map +1 -0
- package/dist/e2e/full-wallet.test.d.ts +2 -0
- package/dist/e2e/full-wallet.test.d.ts.map +1 -0
- package/dist/e2e/full-wallet.test.js +37 -0
- package/dist/e2e/full-wallet.test.js.map +1 -0
- package/dist/e2e/index.d.ts +5 -1
- package/dist/e2e/index.d.ts.map +1 -1
- package/dist/e2e/index.js +2 -0
- package/dist/e2e/index.js.map +1 -1
- package/dist/e2e/local-node.d.ts +22 -0
- package/dist/e2e/local-node.d.ts.map +1 -0
- package/dist/e2e/local-node.js +144 -0
- package/dist/e2e/local-node.js.map +1 -0
- package/dist/e2e/local-node.test.d.ts +2 -0
- package/dist/e2e/local-node.test.d.ts.map +1 -0
- package/dist/e2e/local-node.test.js +43 -0
- package/dist/e2e/local-node.test.js.map +1 -0
- package/dist/e2e/signer.test.d.ts +2 -0
- package/dist/e2e/signer.test.d.ts.map +1 -0
- package/dist/e2e/signer.test.js +57 -0
- package/dist/e2e/signer.test.js.map +1 -0
- package/dist/e2e/wallet-mock.d.ts +18 -3
- package/dist/e2e/wallet-mock.d.ts.map +1 -1
- package/dist/e2e/wallet-mock.js +22 -10
- package/dist/e2e/wallet-mock.js.map +1 -1
- package/dist/e2e/wallet-mock.test.js +7 -7
- package/dist/e2e/wallet-mock.test.js.map +1 -1
- package/dist/tasks/wallet.d.ts.map +1 -1
- package/dist/tasks/wallet.js +14 -25
- package/dist/tasks/wallet.js.map +1 -1
- package/dist/test-utils/index.d.ts +1 -0
- package/dist/test-utils/index.d.ts.map +1 -1
- package/dist/test-utils/index.js +1 -0
- package/dist/test-utils/index.js.map +1 -1
- package/dist/test-utils/wallet-mocks.d.ts +44 -0
- package/dist/test-utils/wallet-mocks.d.ts.map +1 -0
- package/dist/test-utils/wallet-mocks.js +114 -0
- package/dist/test-utils/wallet-mocks.js.map +1 -0
- package/dist/test-utils/wallet-mocks.test.d.ts +2 -0
- package/dist/test-utils/wallet-mocks.test.d.ts.map +1 -0
- package/dist/test-utils/wallet-mocks.test.js +55 -0
- package/dist/test-utils/wallet-mocks.test.js.map +1 -0
- package/dist/test-utils/wallet-setup.d.ts +2 -0
- package/dist/test-utils/wallet-setup.d.ts.map +1 -0
- package/dist/test-utils/wallet-setup.js +23 -0
- package/dist/test-utils/wallet-setup.js.map +1 -0
- package/dist/test-utils/wallet-setup.test.d.ts +2 -0
- package/dist/test-utils/wallet-setup.test.d.ts.map +1 -0
- package/dist/test-utils/wallet-setup.test.js +18 -0
- package/dist/test-utils/wallet-setup.test.js.map +1 -0
- package/dist/wallet/biometric.d.ts +33 -0
- package/dist/wallet/biometric.d.ts.map +1 -0
- package/dist/wallet/biometric.js +88 -0
- package/dist/wallet/biometric.js.map +1 -0
- package/dist/wallet/biometric.test.d.ts +2 -0
- package/dist/wallet/biometric.test.d.ts.map +1 -0
- package/dist/wallet/biometric.test.js +44 -0
- package/dist/wallet/biometric.test.js.map +1 -0
- package/dist/wallet/crypto.d.ts +42 -0
- package/dist/wallet/crypto.d.ts.map +1 -0
- package/dist/wallet/crypto.js +127 -0
- package/dist/wallet/crypto.js.map +1 -0
- package/dist/wallet/crypto.test.d.ts +2 -0
- package/dist/wallet/crypto.test.d.ts.map +1 -0
- package/dist/wallet/crypto.test.js +34 -0
- package/dist/wallet/crypto.test.js.map +1 -0
- package/dist/wallet/destinations.d.ts +20 -0
- package/dist/wallet/destinations.d.ts.map +1 -0
- package/dist/wallet/destinations.js +98 -0
- package/dist/wallet/destinations.js.map +1 -0
- package/dist/wallet/destinations.test.d.ts +2 -0
- package/dist/wallet/destinations.test.d.ts.map +1 -0
- package/dist/wallet/destinations.test.js +34 -0
- package/dist/wallet/destinations.test.js.map +1 -0
- package/dist/wallet/external-provider.d.ts +33 -0
- package/dist/wallet/external-provider.d.ts.map +1 -0
- package/dist/wallet/external-provider.js +108 -0
- package/dist/wallet/external-provider.js.map +1 -0
- package/dist/wallet/external-provider.test.d.ts +2 -0
- package/dist/wallet/external-provider.test.d.ts.map +1 -0
- package/dist/wallet/external-provider.test.js +44 -0
- package/dist/wallet/external-provider.test.js.map +1 -0
- package/dist/wallet/index.d.ts +14 -0
- package/dist/wallet/index.d.ts.map +1 -0
- package/dist/wallet/index.js +24 -0
- package/dist/wallet/index.js.map +1 -0
- package/dist/wallet/indexeddb.test.d.ts +2 -0
- package/dist/wallet/indexeddb.test.d.ts.map +1 -0
- package/dist/wallet/indexeddb.test.js +28 -0
- package/dist/wallet/indexeddb.test.js.map +1 -0
- package/dist/wallet/kdf.test.d.ts +2 -0
- package/dist/wallet/kdf.test.d.ts.map +1 -0
- package/dist/wallet/kdf.test.js +54 -0
- package/dist/wallet/kdf.test.js.map +1 -0
- package/dist/wallet/provider.d.ts +38 -0
- package/dist/wallet/provider.d.ts.map +1 -0
- package/dist/wallet/provider.js +285 -0
- package/dist/wallet/provider.js.map +1 -0
- package/dist/wallet/provider.test.d.ts +2 -0
- package/dist/wallet/provider.test.d.ts.map +1 -0
- package/dist/wallet/provider.test.js +170 -0
- package/dist/wallet/provider.test.js.map +1 -0
- package/dist/wallet/signer.d.ts +55 -0
- package/dist/wallet/signer.d.ts.map +1 -0
- package/dist/wallet/signer.js +91 -0
- package/dist/wallet/signer.js.map +1 -0
- package/dist/wallet/signer.test.d.ts +2 -0
- package/dist/wallet/signer.test.d.ts.map +1 -0
- package/dist/wallet/signer.test.js +62 -0
- package/dist/wallet/signer.test.js.map +1 -0
- package/dist/wallet/siwe.d.ts +2 -0
- package/dist/wallet/siwe.d.ts.map +1 -0
- package/dist/wallet/siwe.js +5 -0
- package/dist/wallet/siwe.js.map +1 -0
- package/dist/wallet/storage/file.d.ts +19 -0
- package/dist/wallet/storage/file.d.ts.map +1 -0
- package/dist/wallet/storage/file.js +48 -0
- package/dist/wallet/storage/file.js.map +1 -0
- package/dist/wallet/storage/idb.d.ts +25 -0
- package/dist/wallet/storage/idb.d.ts.map +1 -0
- package/dist/wallet/storage/idb.js +58 -0
- package/dist/wallet/storage/idb.js.map +1 -0
- package/dist/wallet/storage/index.d.ts +5 -0
- package/dist/wallet/storage/index.d.ts.map +1 -0
- package/dist/wallet/storage/index.js +4 -0
- package/dist/wallet/storage/index.js.map +1 -0
- package/dist/wallet/storage/indexeddb.d.ts +8 -0
- package/dist/wallet/storage/indexeddb.d.ts.map +1 -0
- package/dist/wallet/storage/indexeddb.js +18 -0
- package/dist/wallet/storage/indexeddb.js.map +1 -0
- package/dist/wallet/storage/memory.d.ts +10 -0
- package/dist/wallet/storage/memory.d.ts.map +1 -0
- package/dist/wallet/storage/memory.js +19 -0
- package/dist/wallet/storage/memory.js.map +1 -0
- package/dist/wallet/storage.test.d.ts +2 -0
- package/dist/wallet/storage.test.d.ts.map +1 -0
- package/dist/wallet/storage.test.js +103 -0
- package/dist/wallet/storage.test.js.map +1 -0
- package/dist/wallet/types.d.ts +69 -0
- package/dist/wallet/types.d.ts.map +1 -0
- package/dist/wallet/types.js +6 -0
- package/dist/wallet/types.js.map +1 -0
- package/dist/wallet/wallet.d.ts +81 -0
- package/dist/wallet/wallet.d.ts.map +1 -0
- package/dist/wallet/wallet.js +358 -0
- package/dist/wallet/wallet.js.map +1 -0
- package/dist/wallet/wallet.test.d.ts +2 -0
- package/dist/wallet/wallet.test.d.ts.map +1 -0
- package/dist/wallet/wallet.test.js +150 -0
- package/dist/wallet/wallet.test.js.map +1 -0
- package/dist/wallet/web-authn.d.ts +78 -0
- package/dist/wallet/web-authn.d.ts.map +1 -0
- package/dist/wallet/web-authn.js +250 -0
- package/dist/wallet/web-authn.js.map +1 -0
- package/package.json +14 -4
- package/src/e2e/README.md +51 -0
- package/src/wallet/README.md +96 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.test.d.ts","sourceRoot":"","sources":["../../src/wallet/crypto.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { KDF_ITERATIONS, decryptSecret, encryptSecret, fromBase64, toBase64 } from './crypto.js';
|
|
3
|
+
describe('crypto', () => {
|
|
4
|
+
it('round-trips a secret with the password', async () => {
|
|
5
|
+
const secret = await encryptSecret('0x' + 'ab'.repeat(32), '123456');
|
|
6
|
+
expect(secret.kdf.name).toBe('PBKDF2');
|
|
7
|
+
expect(secret.kdf.hash).toBe('SHA-256');
|
|
8
|
+
expect(secret.kdf.iterations).toBe(KDF_ITERATIONS);
|
|
9
|
+
expect(secret.cipher.name).toBe('AES-GCM');
|
|
10
|
+
expect(secret.kdf.salt).not.toBe('');
|
|
11
|
+
expect(secret.cipher.iv).not.toBe('');
|
|
12
|
+
expect(secret.cipher.data).not.toContain('ab'.repeat(32));
|
|
13
|
+
await expect(decryptSecret(secret, '123456')).resolves.toBe('0x' + 'ab'.repeat(32));
|
|
14
|
+
});
|
|
15
|
+
it('uses 600,000 PBKDF2 iterations', () => {
|
|
16
|
+
expect(KDF_ITERATIONS).toBe(600_000);
|
|
17
|
+
});
|
|
18
|
+
it('uses a fresh salt and IV per encryption', async () => {
|
|
19
|
+
const first = await encryptSecret('secret', '123456');
|
|
20
|
+
const second = await encryptSecret('secret', '123456');
|
|
21
|
+
expect(first.kdf.salt).not.toBe(second.kdf.salt);
|
|
22
|
+
expect(first.cipher.iv).not.toBe(second.cipher.iv);
|
|
23
|
+
expect(first.cipher.data).not.toBe(second.cipher.data);
|
|
24
|
+
});
|
|
25
|
+
it('rejects a wrong password', async () => {
|
|
26
|
+
const secret = await encryptSecret('secret', '123456');
|
|
27
|
+
await expect(decryptSecret(secret, '654321')).rejects.toThrow(/Wrong password/i);
|
|
28
|
+
});
|
|
29
|
+
it('round-trips base64 helpers', () => {
|
|
30
|
+
const bytes = new Uint8Array([0, 1, 2, 250, 255]);
|
|
31
|
+
expect(Array.from(fromBase64(toBase64(bytes)))).toEqual([0, 1, 2, 250, 255]);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
//# sourceMappingURL=crypto.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.test.js","sourceRoot":"","sources":["../../src/wallet/crypto.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Destinations this wallet has already sent funds to (R-#253).
|
|
3
|
+
*
|
|
4
|
+
* A **new** destination always requires the device gesture, even inside the grace
|
|
5
|
+
* window of `USER_VERIFICATION_GRACE_MS`: that stops an automated or hostile flow
|
|
6
|
+
* from draining the wallet to an address the user never used. Repeated transfers to
|
|
7
|
+
* a known address stay silent within the window.
|
|
8
|
+
*
|
|
9
|
+
* Stored per wallet address in `localStorage` (not a secret; only addresses), with
|
|
10
|
+
* an in-memory fallback when `localStorage` is unavailable (private mode, Node).
|
|
11
|
+
*/
|
|
12
|
+
/** Overrides the storage-key prefix (a consumer keeps its own namespace). */
|
|
13
|
+
export declare function setDestinationsPrefix(value: string): void;
|
|
14
|
+
/** Whether the wallet has already sent funds to `destination`. */
|
|
15
|
+
export declare function isKnownDestination(wallet: string, destination: string): boolean;
|
|
16
|
+
/** Records `destination` for `wallet` after a successful transfer. */
|
|
17
|
+
export declare function rememberDestination(wallet: string, destination: string): void;
|
|
18
|
+
/** Forgets every destination (tests, and when the wallet is deleted). */
|
|
19
|
+
export declare function clearDestinations(wallet?: string): void;
|
|
20
|
+
//# sourceMappingURL=destinations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"destinations.d.ts","sourceRoot":"","sources":["../../src/wallet/destinations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,6EAA6E;AAC7E,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAEzD;AA+BD,kEAAkE;AAClE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAG/E;AAED,sEAAsE;AACtE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAc7E;AAED,yEAAyE;AACzE,wBAAgB,iBAAiB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAiBvD"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Destinations this wallet has already sent funds to (R-#253).
|
|
3
|
+
*
|
|
4
|
+
* A **new** destination always requires the device gesture, even inside the grace
|
|
5
|
+
* window of `USER_VERIFICATION_GRACE_MS`: that stops an automated or hostile flow
|
|
6
|
+
* from draining the wallet to an address the user never used. Repeated transfers to
|
|
7
|
+
* a known address stay silent within the window.
|
|
8
|
+
*
|
|
9
|
+
* Stored per wallet address in `localStorage` (not a secret; only addresses), with
|
|
10
|
+
* an in-memory fallback when `localStorage` is unavailable (private mode, Node).
|
|
11
|
+
*/
|
|
12
|
+
/** Namespace of the `localStorage` keys (a consumer sets its own with `setDestinationsPrefix`). */
|
|
13
|
+
let prefix = 'pasosdejesus-m-wallet.destinations.';
|
|
14
|
+
/** Overrides the storage-key prefix (a consumer keeps its own namespace). */
|
|
15
|
+
export function setDestinationsPrefix(value) {
|
|
16
|
+
if (value)
|
|
17
|
+
prefix = value;
|
|
18
|
+
}
|
|
19
|
+
/** Cap so the list cannot grow without bound. */
|
|
20
|
+
const MAX_DESTINATIONS = 200;
|
|
21
|
+
const memory = new Map();
|
|
22
|
+
function storage() {
|
|
23
|
+
try {
|
|
24
|
+
return globalThis.localStorage ?? null;
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function load(wallet) {
|
|
31
|
+
const key = wallet.toLowerCase();
|
|
32
|
+
const cached = memory.get(key);
|
|
33
|
+
if (cached)
|
|
34
|
+
return cached;
|
|
35
|
+
const set = new Set();
|
|
36
|
+
const raw = storage()?.getItem(prefix + key);
|
|
37
|
+
if (raw) {
|
|
38
|
+
try {
|
|
39
|
+
for (const item of JSON.parse(raw))
|
|
40
|
+
set.add(String(item).toLowerCase());
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
// Lista corrupta: se empieza de cero (sólo provoca pedir el gesto de nuevo).
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
memory.set(key, set);
|
|
47
|
+
return set;
|
|
48
|
+
}
|
|
49
|
+
/** Whether the wallet has already sent funds to `destination`. */
|
|
50
|
+
export function isKnownDestination(wallet, destination) {
|
|
51
|
+
if (!wallet || !destination)
|
|
52
|
+
return false;
|
|
53
|
+
return load(wallet).has(destination.toLowerCase());
|
|
54
|
+
}
|
|
55
|
+
/** Records `destination` for `wallet` after a successful transfer. */
|
|
56
|
+
export function rememberDestination(wallet, destination) {
|
|
57
|
+
if (!wallet || !destination)
|
|
58
|
+
return;
|
|
59
|
+
const set = load(wallet);
|
|
60
|
+
set.add(destination.toLowerCase());
|
|
61
|
+
while (set.size > MAX_DESTINATIONS) {
|
|
62
|
+
const first = set.values().next().value;
|
|
63
|
+
if (first === undefined)
|
|
64
|
+
break;
|
|
65
|
+
set.delete(first);
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
storage()?.setItem(prefix + wallet.toLowerCase(), JSON.stringify([...set]));
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
// Sin persistencia: queda sólo en memoria (se pedirá el gesto tras recargar).
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/** Forgets every destination (tests, and when the wallet is deleted). */
|
|
75
|
+
export function clearDestinations(wallet) {
|
|
76
|
+
if (wallet) {
|
|
77
|
+
memory.delete(wallet.toLowerCase());
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
memory.clear();
|
|
81
|
+
}
|
|
82
|
+
const s = storage();
|
|
83
|
+
if (!s)
|
|
84
|
+
return;
|
|
85
|
+
try {
|
|
86
|
+
for (let i = s.length - 1; i >= 0; i -= 1) {
|
|
87
|
+
const key = s.key(i);
|
|
88
|
+
if (!key?.startsWith(prefix))
|
|
89
|
+
continue;
|
|
90
|
+
if (!wallet || key === prefix + wallet.toLowerCase())
|
|
91
|
+
s.removeItem(key);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
// Nada que limpiar.
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=destinations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"destinations.js","sourceRoot":"","sources":["../../src/wallet/destinations.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"destinations.test.d.ts","sourceRoot":"","sources":["../../src/wallet/destinations.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it } from 'vitest';
|
|
2
|
+
import { clearDestinations, isKnownDestination, rememberDestination, setDestinationsPrefix, } from './destinations.js';
|
|
3
|
+
const WALLET = '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266';
|
|
4
|
+
const OTHER = '0x70997970C51812dc3A010C7d01b50e0d17dc79C8';
|
|
5
|
+
describe('destinations (R-#253)', () => {
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
setDestinationsPrefix('m-wallet-test.destinations.');
|
|
8
|
+
clearDestinations();
|
|
9
|
+
});
|
|
10
|
+
it('treats an unseen address as new', () => {
|
|
11
|
+
expect(isKnownDestination(WALLET, OTHER)).toBe(false);
|
|
12
|
+
});
|
|
13
|
+
it('remembers an address, case-insensitively', () => {
|
|
14
|
+
rememberDestination(WALLET, OTHER);
|
|
15
|
+
expect(isKnownDestination(WALLET, OTHER)).toBe(true);
|
|
16
|
+
expect(isKnownDestination(WALLET, OTHER.toLowerCase())).toBe(true);
|
|
17
|
+
});
|
|
18
|
+
it('keeps the list per wallet', () => {
|
|
19
|
+
rememberDestination(WALLET, OTHER);
|
|
20
|
+
expect(isKnownDestination('0x0000000000000000000000000000000000000001', OTHER)).toBe(false);
|
|
21
|
+
});
|
|
22
|
+
it('is false for empty input', () => {
|
|
23
|
+
expect(isKnownDestination('', OTHER)).toBe(false);
|
|
24
|
+
expect(isKnownDestination(WALLET, '')).toBe(false);
|
|
25
|
+
});
|
|
26
|
+
it('clears one wallet without touching the others', () => {
|
|
27
|
+
rememberDestination(WALLET, OTHER);
|
|
28
|
+
rememberDestination('0x0000000000000000000000000000000000000001', OTHER);
|
|
29
|
+
clearDestinations(WALLET);
|
|
30
|
+
expect(isKnownDestination(WALLET, OTHER)).toBe(false);
|
|
31
|
+
expect(isKnownDestination('0x0000000000000000000000000000000000000001', OTHER)).toBe(true);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
//# sourceMappingURL=destinations.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"destinations.test.js","sourceRoot":"","sources":["../../src/wallet/destinations.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AACzD,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,mBAAmB,CAAA;AAE1B,MAAM,MAAM,GAAG,4CAA4C,CAAA;AAC3D,MAAM,KAAK,GAAG,4CAA4C,CAAA;AAE1D,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,UAAU,CAAC,GAAG,EAAE;QACd,qBAAqB,CAAC,6BAA6B,CAAC,CAAA;QACpD,iBAAiB,EAAE,CAAA;IACrB,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACzC,MAAM,CAAC,kBAAkB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IACvD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QAClD,mBAAmB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;QAClC,MAAM,CAAC,kBAAkB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACpD,MAAM,CAAC,kBAAkB,CAAC,MAAM,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACpE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACnC,mBAAmB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;QAClC,MAAM,CAAC,kBAAkB,CAAC,4CAA4C,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAC7F,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE;QAClC,MAAM,CAAC,kBAAkB,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACjD,MAAM,CAAC,kBAAkB,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IACpD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,mBAAmB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;QAClC,mBAAmB,CAAC,4CAA4C,EAAE,KAAK,CAAC,CAAA;QACxE,iBAAiB,CAAC,MAAM,CAAC,CAAA;QACzB,MAAM,CAAC,kBAAkB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACrD,MAAM,CAAC,kBAAkB,CAAC,4CAA4C,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC5F,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Eip1193Provider } from './types.js';
|
|
2
|
+
export interface AnnouncedProvider {
|
|
3
|
+
uuid: string;
|
|
4
|
+
name: string;
|
|
5
|
+
rdns: string;
|
|
6
|
+
icon?: string;
|
|
7
|
+
provider: Eip1193Provider;
|
|
8
|
+
}
|
|
9
|
+
export interface ExternalProviderState {
|
|
10
|
+
provider: Eip1193Provider | null;
|
|
11
|
+
announced: AnnouncedProvider[];
|
|
12
|
+
/** De dónde salió el proveedor elegido (`window.ethereum`, EIP-6963 o ninguno). */
|
|
13
|
+
source: ExternalProviderSource;
|
|
14
|
+
/** rdns del anuncio elegido; `null` si es `window.ethereum`. */
|
|
15
|
+
rdns: string | null;
|
|
16
|
+
}
|
|
17
|
+
export type ExternalProviderSource = 'window.ethereum' | 'eip6963' | null;
|
|
18
|
+
/** Suscribe un listener (para `useSyncExternalStore` del consumidor). */
|
|
19
|
+
export declare function subscribeExternalProvider(listener: () => void): () => void;
|
|
20
|
+
/** Snapshot actual del store (para `useSyncExternalStore`). */
|
|
21
|
+
export declare function getExternalProviderSnapshot(): ExternalProviderState;
|
|
22
|
+
/** Effective injected provider, or `null` (also callable outside React). */
|
|
23
|
+
export declare function getExternalProvider(): Eip1193Provider | null;
|
|
24
|
+
/**
|
|
25
|
+
* Valor para `wallet_source` cuando la sesión se inicia con una billetera inyectada:
|
|
26
|
+
* `eip6963:<rdns>` si llegó por anuncio, `window.ethereum` si es el objeto clásico y
|
|
27
|
+
* `unknown` si todavía no hay proveedor.
|
|
28
|
+
*/
|
|
29
|
+
export declare function externalWalletSource(): string;
|
|
30
|
+
export declare function getAnnouncedProviders(): AnnouncedProvider[];
|
|
31
|
+
/** Test-only: forgets the listeners and the chosen provider. */
|
|
32
|
+
export declare function resetExternalProviderForTests(): void;
|
|
33
|
+
//# sourceMappingURL=external-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"external-provider.d.ts","sourceRoot":"","sources":["../../src/wallet/external-provider.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAEjD,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,eAAe,CAAA;CAC1B;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,eAAe,GAAG,IAAI,CAAA;IAChC,SAAS,EAAE,iBAAiB,EAAE,CAAA;IAC9B,mFAAmF;IACnF,MAAM,EAAE,sBAAsB,CAAA;IAC9B,gEAAgE;IAChE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CACpB;AAED,MAAM,MAAM,sBAAsB,GAAG,iBAAiB,GAAG,SAAS,GAAG,IAAI,CAAA;AAuEzE,yEAAyE;AACzE,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAM1E;AAED,+DAA+D;AAC/D,wBAAgB,2BAA2B,IAAI,qBAAqB,CAInE;AAED,4EAA4E;AAC5E,wBAAgB,mBAAmB,IAAI,eAAe,GAAG,IAAI,CAI5D;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAM7C;AAED,wBAAgB,qBAAqB,IAAI,iBAAiB,EAAE,CAG3D;AAED,gEAAgE;AAChE,wBAAgB,6BAA6B,IAAI,IAAI,CAIpD"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
const EMPTY = { provider: null, announced: [], source: null, rdns: null };
|
|
2
|
+
let state = EMPTY;
|
|
3
|
+
let started = false;
|
|
4
|
+
const listeners = new Set();
|
|
5
|
+
function emit(partial) {
|
|
6
|
+
state = { ...state, ...partial };
|
|
7
|
+
for (const listener of listeners)
|
|
8
|
+
listener();
|
|
9
|
+
}
|
|
10
|
+
function injected() {
|
|
11
|
+
if (typeof window === 'undefined')
|
|
12
|
+
return null;
|
|
13
|
+
return window.ethereum ?? null;
|
|
14
|
+
}
|
|
15
|
+
/** Sticky choice: `window.ethereum` when it exists, otherwise the announcement. */
|
|
16
|
+
function choose() {
|
|
17
|
+
if (state.provider)
|
|
18
|
+
return;
|
|
19
|
+
const direct = injected();
|
|
20
|
+
if (direct) {
|
|
21
|
+
emit({ provider: direct, source: 'window.ethereum', rdns: null });
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (state.announced[0]) {
|
|
25
|
+
emit({ provider: state.announced[0].provider, source: 'eip6963', rdns: state.announced[0].rdns });
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function start() {
|
|
29
|
+
if (started || typeof window === 'undefined')
|
|
30
|
+
return;
|
|
31
|
+
started = true;
|
|
32
|
+
window.addEventListener('eip6963:announceProvider', (event) => {
|
|
33
|
+
const detail = event.detail;
|
|
34
|
+
if (!detail?.provider)
|
|
35
|
+
return;
|
|
36
|
+
const rdns = detail.info?.rdns ?? detail.info?.name ?? 'unknown';
|
|
37
|
+
const announced = [
|
|
38
|
+
...state.announced.filter((item) => item.rdns !== rdns),
|
|
39
|
+
{
|
|
40
|
+
uuid: detail.info?.uuid ?? rdns,
|
|
41
|
+
name: detail.info?.name ?? rdns,
|
|
42
|
+
rdns,
|
|
43
|
+
icon: detail.info?.icon,
|
|
44
|
+
provider: detail.provider,
|
|
45
|
+
},
|
|
46
|
+
];
|
|
47
|
+
emit({ announced });
|
|
48
|
+
choose();
|
|
49
|
+
});
|
|
50
|
+
window.addEventListener('ethereum#initialized', choose);
|
|
51
|
+
window.dispatchEvent(new Event('eip6963:requestProvider'));
|
|
52
|
+
// Algunas WebViews inyectan tarde: reintentar un rato y una vez al primer gesto.
|
|
53
|
+
let attempts = 0;
|
|
54
|
+
const timer = window.setInterval(() => {
|
|
55
|
+
attempts += 1;
|
|
56
|
+
choose();
|
|
57
|
+
if (attempts >= 8)
|
|
58
|
+
window.clearInterval(timer);
|
|
59
|
+
}, 400);
|
|
60
|
+
for (const eventName of ['pointerdown', 'keydown', 'focus', 'visibilitychange']) {
|
|
61
|
+
window.addEventListener(eventName, choose, { once: true });
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/** Suscribe un listener (para `useSyncExternalStore` del consumidor). */
|
|
65
|
+
export function subscribeExternalProvider(listener) {
|
|
66
|
+
start();
|
|
67
|
+
listeners.add(listener);
|
|
68
|
+
return () => {
|
|
69
|
+
listeners.delete(listener);
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/** Snapshot actual del store (para `useSyncExternalStore`). */
|
|
73
|
+
export function getExternalProviderSnapshot() {
|
|
74
|
+
start();
|
|
75
|
+
choose();
|
|
76
|
+
return state;
|
|
77
|
+
}
|
|
78
|
+
/** Effective injected provider, or `null` (also callable outside React). */
|
|
79
|
+
export function getExternalProvider() {
|
|
80
|
+
start();
|
|
81
|
+
choose();
|
|
82
|
+
return state.provider;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Valor para `wallet_source` cuando la sesión se inicia con una billetera inyectada:
|
|
86
|
+
* `eip6963:<rdns>` si llegó por anuncio, `window.ethereum` si es el objeto clásico y
|
|
87
|
+
* `unknown` si todavía no hay proveedor.
|
|
88
|
+
*/
|
|
89
|
+
export function externalWalletSource() {
|
|
90
|
+
start();
|
|
91
|
+
choose();
|
|
92
|
+
if (state.source === 'eip6963')
|
|
93
|
+
return state.rdns ? `eip6963:${state.rdns}` : 'eip6963:unknown';
|
|
94
|
+
if (state.source === 'window.ethereum')
|
|
95
|
+
return 'window.ethereum';
|
|
96
|
+
return 'unknown';
|
|
97
|
+
}
|
|
98
|
+
export function getAnnouncedProviders() {
|
|
99
|
+
start();
|
|
100
|
+
return state.announced;
|
|
101
|
+
}
|
|
102
|
+
/** Test-only: forgets the listeners and the chosen provider. */
|
|
103
|
+
export function resetExternalProviderForTests() {
|
|
104
|
+
state = EMPTY;
|
|
105
|
+
started = false;
|
|
106
|
+
listeners.clear();
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=external-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"external-provider.js","sourceRoot":"","sources":["../../src/wallet/external-provider.ts"],"names":[],"mappings":"AAmCA,MAAM,KAAK,GAA0B,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAA;AAEhG,IAAI,KAAK,GAA0B,KAAK,CAAA;AACxC,IAAI,OAAO,GAAG,KAAK,CAAA;AACnB,MAAM,SAAS,GAAG,IAAI,GAAG,EAAc,CAAA;AAEvC,SAAS,IAAI,CAAC,OAAuC;IACnD,KAAK,GAAG,EAAE,GAAG,KAAK,EAAE,GAAG,OAAO,EAAE,CAAA;IAChC,KAAK,MAAM,QAAQ,IAAI,SAAS;QAAE,QAAQ,EAAE,CAAA;AAC9C,CAAC;AAED,SAAS,QAAQ;IACf,IAAI,OAAO,MAAM,KAAK,WAAW;QAAE,OAAO,IAAI,CAAA;IAC9C,OAAQ,MAAyC,CAAC,QAAQ,IAAI,IAAI,CAAA;AACpE,CAAC;AAED,mFAAmF;AACnF,SAAS,MAAM;IACb,IAAI,KAAK,CAAC,QAAQ;QAAE,OAAM;IAC1B,MAAM,MAAM,GAAG,QAAQ,EAAE,CAAA;IACzB,IAAI,MAAM,EAAE,CAAC;QACX,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;QACjE,OAAM;IACR,CAAC;IACD,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;QACvB,IAAI,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAA;IACnG,CAAC;AACH,CAAC;AAED,SAAS,KAAK;IACZ,IAAI,OAAO,IAAI,OAAO,MAAM,KAAK,WAAW;QAAE,OAAM;IACpD,OAAO,GAAG,IAAI,CAAA;IAEd,MAAM,CAAC,gBAAgB,CAAC,0BAA0B,EAAE,CAAC,KAAK,EAAE,EAAE;QAC5D,MAAM,MAAM,GAAI,KAGb,CAAC,MAAM,CAAA;QACV,IAAI,CAAC,MAAM,EAAE,QAAQ;YAAE,OAAM;QAC7B,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,EAAE,IAAI,IAAI,MAAM,CAAC,IAAI,EAAE,IAAI,IAAI,SAAS,CAAA;QAChE,MAAM,SAAS,GAAG;YAChB,GAAG,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC;YACvD;gBACE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,IAAI,IAAI,IAAI;gBAC/B,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,IAAI,IAAI,IAAI;gBAC/B,IAAI;gBACJ,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,IAAI;gBACvB,QAAQ,EAAE,MAAM,CAAC,QAAQ;aAC1B;SACF,CAAA;QACD,IAAI,CAAC,EAAE,SAAS,EAAE,CAAC,CAAA;QACnB,MAAM,EAAE,CAAA;IACV,CAAC,CAAC,CAAA;IAEF,MAAM,CAAC,gBAAgB,CAAC,sBAAsB,EAAE,MAAM,CAAC,CAAA;IACvD,MAAM,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC,CAAA;IAE1D,iFAAiF;IACjF,IAAI,QAAQ,GAAG,CAAC,CAAA;IAChB,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC,GAAG,EAAE;QACpC,QAAQ,IAAI,CAAC,CAAA;QACb,MAAM,EAAE,CAAA;QACR,IAAI,QAAQ,IAAI,CAAC;YAAE,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAAA;IAChD,CAAC,EAAE,GAAG,CAAC,CAAA;IACP,KAAK,MAAM,SAAS,IAAI,CAAC,aAAa,EAAE,SAAS,EAAE,OAAO,EAAE,kBAAkB,CAAC,EAAE,CAAC;QAChF,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;IAC5D,CAAC;AACH,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,yBAAyB,CAAC,QAAoB;IAC5D,KAAK,EAAE,CAAA;IACP,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IACvB,OAAO,GAAG,EAAE;QACV,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;IAC5B,CAAC,CAAA;AACH,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,2BAA2B;IACzC,KAAK,EAAE,CAAA;IACP,MAAM,EAAE,CAAA;IACR,OAAO,KAAK,CAAA;AACd,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,mBAAmB;IACjC,KAAK,EAAE,CAAA;IACP,MAAM,EAAE,CAAA;IACR,OAAO,KAAK,CAAC,QAAQ,CAAA;AACvB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB;IAClC,KAAK,EAAE,CAAA;IACP,MAAM,EAAE,CAAA;IACR,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,iBAAiB,CAAA;IAC/F,IAAI,KAAK,CAAC,MAAM,KAAK,iBAAiB;QAAE,OAAO,iBAAiB,CAAA;IAChE,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,MAAM,UAAU,qBAAqB;IACnC,KAAK,EAAE,CAAA;IACP,OAAO,KAAK,CAAC,SAAS,CAAA;AACxB,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,6BAA6B;IAC3C,KAAK,GAAG,KAAK,CAAA;IACb,OAAO,GAAG,KAAK,CAAA;IACf,SAAS,CAAC,KAAK,EAAE,CAAA;AACnB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"external-provider.test.d.ts","sourceRoot":"","sources":["../../src/wallet/external-provider.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
+
import { externalWalletSource, getAnnouncedProviders, getExternalProvider, resetExternalProviderForTests, } from './external-provider.js';
|
|
4
|
+
const provider = () => ({ request: async () => null });
|
|
5
|
+
function announce(p, info) {
|
|
6
|
+
window.dispatchEvent(new CustomEvent('eip6963:announceProvider', {
|
|
7
|
+
detail: { info: { uuid: info.rdns, ...info }, provider: p },
|
|
8
|
+
}));
|
|
9
|
+
}
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
vi.useFakeTimers();
|
|
12
|
+
delete window.ethereum;
|
|
13
|
+
resetExternalProviderForTests();
|
|
14
|
+
});
|
|
15
|
+
afterEach(() => {
|
|
16
|
+
vi.useRealTimers();
|
|
17
|
+
delete window.ethereum;
|
|
18
|
+
});
|
|
19
|
+
describe('external-provider (EIP-6963)', () => {
|
|
20
|
+
it('prefers window.ethereum when it exists', () => {
|
|
21
|
+
const injected = provider();
|
|
22
|
+
window.ethereum = injected;
|
|
23
|
+
resetExternalProviderForTests();
|
|
24
|
+
expect(getExternalProvider()).toBe(injected);
|
|
25
|
+
expect(externalWalletSource()).toBe('window.ethereum');
|
|
26
|
+
});
|
|
27
|
+
it('resolves a late EIP-6963 announcement when there is no window.ethereum', () => {
|
|
28
|
+
const announced = provider();
|
|
29
|
+
expect(getExternalProvider()).toBeNull();
|
|
30
|
+
announce(announced, { name: 'Rabby', rdns: 'io.rabby' });
|
|
31
|
+
expect(getExternalProvider()).toBe(announced);
|
|
32
|
+
expect(externalWalletSource()).toBe('eip6963:io.rabby');
|
|
33
|
+
expect(getAnnouncedProviders().map((item) => item.rdns)).toContain('io.rabby');
|
|
34
|
+
});
|
|
35
|
+
it('stays on the first provider (the choice is sticky)', () => {
|
|
36
|
+
const first = provider();
|
|
37
|
+
const second = provider();
|
|
38
|
+
getExternalProvider();
|
|
39
|
+
announce(first, { name: 'One', rdns: 'one' });
|
|
40
|
+
announce(second, { name: 'Two', rdns: 'two' });
|
|
41
|
+
expect(getExternalProvider()).toBe(first);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
//# sourceMappingURL=external-provider.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"external-provider.test.js","sourceRoot":"","sources":["../../src/wallet/external-provider.test.ts"],"names":[],"mappings":"AAAA,4BAA4B;AAC5B,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AACxE,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,EACnB,6BAA6B,GAC9B,MAAM,wBAAwB,CAAA;AAG/B,MAAM,QAAQ,GAAG,GAAoB,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,CAAA;AAEvE,SAAS,QAAQ,CAAC,CAAkB,EAAE,IAAoC;IACxE,MAAM,CAAC,aAAa,CAClB,IAAI,WAAW,CAAC,0BAA0B,EAAE;QAC1C,MAAM,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE;KAC5D,CAAC,CACH,CAAA;AACH,CAAC;AAED,UAAU,CAAC,GAAG,EAAE;IACd,EAAE,CAAC,aAAa,EAAE,CAAA;IAClB,OAAQ,MAAiC,CAAC,QAAQ,CAAA;IAClD,6BAA6B,EAAE,CAAA;AACjC,CAAC,CAAC,CAAA;AAEF,SAAS,CAAC,GAAG,EAAE;IACb,EAAE,CAAC,aAAa,EAAE,CAAA;IAClB,OAAQ,MAAiC,CAAC,QAAQ,CAAA;AACpD,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,8BAA8B,EAAE,GAAG,EAAE;IAC5C,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,MAAM,QAAQ,GAAG,QAAQ,EAAE,CAC1B;QAAC,MAAyC,CAAC,QAAQ,GAAG,QAAQ,CAAA;QAC/D,6BAA6B,EAAE,CAAA;QAC/B,MAAM,CAAC,mBAAmB,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QAC5C,MAAM,CAAC,oBAAoB,EAAE,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAA;IACxD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,wEAAwE,EAAE,GAAG,EAAE;QAChF,MAAM,SAAS,GAAG,QAAQ,EAAE,CAAA;QAC5B,MAAM,CAAC,mBAAmB,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAA;QACxC,QAAQ,CAAC,SAAS,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAA;QAExD,MAAM,CAAC,mBAAmB,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QAC7C,MAAM,CAAC,oBAAoB,EAAE,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAA;QACvD,MAAM,CAAC,qBAAqB,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAA;IAChF,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;QAC5D,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAA;QACxB,MAAM,MAAM,GAAG,QAAQ,EAAE,CAAA;QACzB,mBAAmB,EAAE,CAAA;QACrB,QAAQ,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;QAC7C,QAAQ,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;QAC9C,MAAM,CAAC,mBAAmB,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAC3C,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export { createWallet, importWallet, unlockWallet, lockWallet, deleteWallet, currentLockEpoch, hasWallet, getWalletInfo, setWalletChain, isValidPassword, enableBiometricUnlock, hasBiometricUnlock, unlockWithBiometric, disableBiometricUnlock, exportMnemonic, exportPrivateKey, isUnlocked, getUnlockedAccount, getUnlockedInfo, signMessage, signTypedData, signTransaction, } from './wallet.js';
|
|
2
|
+
export { signSIWE } from './siwe.js';
|
|
3
|
+
export { addressFromMnemonic, accountFromMnemonic, accountFromPrivateKey, assertValidMnemonic, isValidMnemonic, newMnemonic, normalizeMnemonic, privateKeyFromMnemonic, keccak, type PrivateKey, } from './signer.js';
|
|
4
|
+
export { encryptSecret, decryptSecret, sha256, toBase64, fromBase64, wipe, KDF_ITERATIONS, KDF_ITERATIONS_FLOOR, KDF_ITERATIONS_CEILING, KDF_BUDGET_MS, calibrateIterations, normalizePassword, type EncryptedSecret, } from './crypto.js';
|
|
5
|
+
export { detectPlatformSupport, createPrfCredential, evaluatePrf, deriveWrappingKey, setRpName, USER_VERIFICATION_GRACE_MS, markUserVerified, clearUserVerification, hasRecentUserVerification, signalUnknownCredential, isUserCancelledError, type PlatformSupport, type PrfCredential, } from './web-authn.js';
|
|
6
|
+
export { type BiometricRecord, readBiometricRecord, writeBiometricRecord, deleteBiometricRecord, forgetBiometricCredential, sealWithPrfSecret, unsealWithPrfSecret, } from './biometric.js';
|
|
7
|
+
export { getInAppWalletProvider, extractDestination, requireFundsConfirmation, emitAccountsChanged, type ProviderOptions, } from './provider.js';
|
|
8
|
+
export { isKnownDestination, rememberDestination, clearDestinations, setDestinationsPrefix, } from './destinations.js';
|
|
9
|
+
export { getExternalProvider, externalWalletSource, getAnnouncedProviders, subscribeExternalProvider, getExternalProviderSnapshot, resetExternalProviderForTests, type AnnouncedProvider, type ExternalProviderState, type ExternalProviderSource, } from './external-provider.js';
|
|
10
|
+
export { MemoryStorage } from './storage/memory.js';
|
|
11
|
+
export { IndexedDBStorage } from './storage/indexeddb.js';
|
|
12
|
+
export { setWalletDbName, getWalletDbName, DB_NAME } from './storage/idb.js';
|
|
13
|
+
export { CHAIN_IDS, DEFAULT_CHAIN, type ChainName, type CreateWalletOptions, type ImportWalletOptions, type StorageAdapter, type StoredWallet, type WalletInfo, type Eip1193Provider, type Eip1193RequestArgs, } from './types.js';
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/wallet/index.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,gBAAgB,EAChB,SAAS,EACT,aAAa,EACb,cAAc,EACd,eAAe,EACf,qBAAqB,EACrB,kBAAkB,EAClB,mBAAmB,EACnB,sBAAsB,EACtB,cAAc,EACd,gBAAgB,EAChB,UAAU,EACV,kBAAkB,EAClB,eAAe,EACf,WAAW,EACX,aAAa,EACb,eAAe,GAChB,MAAM,aAAa,CAAA;AAEpB,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAEpC,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,mBAAmB,EACnB,eAAe,EACf,WAAW,EACX,iBAAiB,EACjB,sBAAsB,EACtB,MAAM,EACN,KAAK,UAAU,GAChB,MAAM,aAAa,CAAA;AAEpB,OAAO,EACL,aAAa,EACb,aAAa,EACb,MAAM,EACN,QAAQ,EACR,UAAU,EACV,IAAI,EACJ,cAAc,EACd,oBAAoB,EACpB,sBAAsB,EACtB,aAAa,EACb,mBAAmB,EACnB,iBAAiB,EACjB,KAAK,eAAe,GACrB,MAAM,aAAa,CAAA;AAGpB,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,WAAW,EACX,iBAAiB,EACjB,SAAS,EACT,0BAA0B,EAC1B,gBAAgB,EAChB,qBAAqB,EACrB,yBAAyB,EACzB,uBAAuB,EACvB,oBAAoB,EACpB,KAAK,eAAe,EACpB,KAAK,aAAa,GACnB,MAAM,gBAAgB,CAAA;AAEvB,OAAO,EACL,KAAK,eAAe,EACpB,mBAAmB,EACnB,oBAAoB,EACpB,qBAAqB,EACrB,yBAAyB,EACzB,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,gBAAgB,CAAA;AAGvB,OAAO,EACL,sBAAsB,EACtB,kBAAkB,EAClB,wBAAwB,EACxB,mBAAmB,EACnB,KAAK,eAAe,GACrB,MAAM,eAAe,CAAA;AACtB,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,mBAAmB,CAAA;AAG1B,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,qBAAqB,EACrB,yBAAyB,EACzB,2BAA2B,EAC3B,6BAA6B,EAC7B,KAAK,iBAAiB,EACtB,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,GAC5B,MAAM,wBAAwB,CAAA;AAE/B,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AACzD,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAE5E,OAAO,EACL,SAAS,EACT,aAAa,EACb,KAAK,SAAS,EACd,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,KAAK,kBAAkB,GACxB,MAAM,YAAY,CAAA"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// @pasosdejesus/m/wallet — núcleo compartido de billetera (`m/REQ/14`).
|
|
2
|
+
//
|
|
3
|
+
// Sin React y sin Kysely: mnemónica (BIP39), derivación, firma, cifrado en reposo
|
|
4
|
+
// (PBKDF2 + AES-GCM), almacenamiento intercambiable, estado de la billetera in-app,
|
|
5
|
+
// provider EIP-1193, verificación del usuario (WebAuthn L1/L2), destinos y el
|
|
6
|
+
// resolutor del proveedor inyectado (EIP-6963). Lo usan el CLI de `m` y los
|
|
7
|
+
// consumidores (learn.tg, sivel3, stable-sl).
|
|
8
|
+
export { createWallet, importWallet, unlockWallet, lockWallet, deleteWallet, currentLockEpoch, hasWallet, getWalletInfo, setWalletChain, isValidPassword, enableBiometricUnlock, hasBiometricUnlock, unlockWithBiometric, disableBiometricUnlock, exportMnemonic, exportPrivateKey, isUnlocked, getUnlockedAccount, getUnlockedInfo, signMessage, signTypedData, signTransaction, } from './wallet.js';
|
|
9
|
+
export { signSIWE } from './siwe.js';
|
|
10
|
+
export { addressFromMnemonic, accountFromMnemonic, accountFromPrivateKey, assertValidMnemonic, isValidMnemonic, newMnemonic, normalizeMnemonic, privateKeyFromMnemonic, keccak, } from './signer.js';
|
|
11
|
+
export { encryptSecret, decryptSecret, sha256, toBase64, fromBase64, wipe, KDF_ITERATIONS, KDF_ITERATIONS_FLOOR, KDF_ITERATIONS_CEILING, KDF_BUDGET_MS, calibrateIterations, normalizePassword, } from './crypto.js';
|
|
12
|
+
// Capa L1/L2: gesto WebAuthn y sello con el secreto PRF.
|
|
13
|
+
export { detectPlatformSupport, createPrfCredential, evaluatePrf, deriveWrappingKey, setRpName, USER_VERIFICATION_GRACE_MS, markUserVerified, clearUserVerification, hasRecentUserVerification, signalUnknownCredential, isUserCancelledError, } from './web-authn.js';
|
|
14
|
+
export { readBiometricRecord, writeBiometricRecord, deleteBiometricRecord, forgetBiometricCredential, sealWithPrfSecret, unsealWithPrfSecret, } from './biometric.js';
|
|
15
|
+
// Provider EIP-1193 de la billetera in-app y destinos conocidos.
|
|
16
|
+
export { getInAppWalletProvider, extractDestination, requireFundsConfirmation, emitAccountsChanged, } from './provider.js';
|
|
17
|
+
export { isKnownDestination, rememberDestination, clearDestinations, setDestinationsPrefix, } from './destinations.js';
|
|
18
|
+
// Resolutor del proveedor inyectado (EIP-6963) — graduado de learn.tg.
|
|
19
|
+
export { getExternalProvider, externalWalletSource, getAnnouncedProviders, subscribeExternalProvider, getExternalProviderSnapshot, resetExternalProviderForTests, } from './external-provider.js';
|
|
20
|
+
export { MemoryStorage } from './storage/memory.js';
|
|
21
|
+
export { IndexedDBStorage } from './storage/indexeddb.js';
|
|
22
|
+
export { setWalletDbName, getWalletDbName, DB_NAME } from './storage/idb.js';
|
|
23
|
+
export { CHAIN_IDS, DEFAULT_CHAIN, } from './types.js';
|
|
24
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/wallet/index.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,EAAE;AACF,kFAAkF;AAClF,oFAAoF;AACpF,8EAA8E;AAC9E,4EAA4E;AAC5E,8CAA8C;AAC9C,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,gBAAgB,EAChB,SAAS,EACT,aAAa,EACb,cAAc,EACd,eAAe,EACf,qBAAqB,EACrB,kBAAkB,EAClB,mBAAmB,EACnB,sBAAsB,EACtB,cAAc,EACd,gBAAgB,EAChB,UAAU,EACV,kBAAkB,EAClB,eAAe,EACf,WAAW,EACX,aAAa,EACb,eAAe,GAChB,MAAM,aAAa,CAAA;AAEpB,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAEpC,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,mBAAmB,EACnB,eAAe,EACf,WAAW,EACX,iBAAiB,EACjB,sBAAsB,EACtB,MAAM,GAEP,MAAM,aAAa,CAAA;AAEpB,OAAO,EACL,aAAa,EACb,aAAa,EACb,MAAM,EACN,QAAQ,EACR,UAAU,EACV,IAAI,EACJ,cAAc,EACd,oBAAoB,EACpB,sBAAsB,EACtB,aAAa,EACb,mBAAmB,EACnB,iBAAiB,GAElB,MAAM,aAAa,CAAA;AAEpB,yDAAyD;AACzD,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,WAAW,EACX,iBAAiB,EACjB,SAAS,EACT,0BAA0B,EAC1B,gBAAgB,EAChB,qBAAqB,EACrB,yBAAyB,EACzB,uBAAuB,EACvB,oBAAoB,GAGrB,MAAM,gBAAgB,CAAA;AAEvB,OAAO,EAEL,mBAAmB,EACnB,oBAAoB,EACpB,qBAAqB,EACrB,yBAAyB,EACzB,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,gBAAgB,CAAA;AAEvB,iEAAiE;AACjE,OAAO,EACL,sBAAsB,EACtB,kBAAkB,EAClB,wBAAwB,EACxB,mBAAmB,GAEpB,MAAM,eAAe,CAAA;AACtB,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,mBAAmB,CAAA;AAE1B,uEAAuE;AACvE,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,qBAAqB,EACrB,yBAAyB,EACzB,2BAA2B,EAC3B,6BAA6B,GAI9B,MAAM,wBAAwB,CAAA;AAE/B,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AACzD,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAE5E,OAAO,EACL,SAAS,EACT,aAAa,GASd,MAAM,YAAY,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"indexeddb.test.d.ts","sourceRoot":"","sources":["../../src/wallet/indexeddb.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { beforeAll, describe, expect, it } from 'vitest';
|
|
2
|
+
import { installIndexedDB } from '../test-utils/wallet-mocks.js';
|
|
3
|
+
import { IndexedDBStorage } from './storage/indexeddb.js';
|
|
4
|
+
const record = {
|
|
5
|
+
version: 1,
|
|
6
|
+
address: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
|
|
7
|
+
chain: 'celoSepolia',
|
|
8
|
+
createdAt: 1,
|
|
9
|
+
kdf: { name: 'PBKDF2', hash: 'SHA-256', iterations: 600_000, salt: 'AA==' },
|
|
10
|
+
cipher: { name: 'AES-GCM', iv: 'BB==', data: 'CC==' },
|
|
11
|
+
};
|
|
12
|
+
beforeAll(async () => {
|
|
13
|
+
await installIndexedDB();
|
|
14
|
+
});
|
|
15
|
+
describe('IndexedDBStorage', () => {
|
|
16
|
+
it('stores, reads and deletes the encrypted record', async () => {
|
|
17
|
+
const storage = new IndexedDBStorage();
|
|
18
|
+
await storage.delete();
|
|
19
|
+
expect(await storage.has()).toBe(false);
|
|
20
|
+
expect(await storage.get()).toBeNull();
|
|
21
|
+
await storage.set(record);
|
|
22
|
+
expect(await storage.has()).toBe(true);
|
|
23
|
+
expect(await storage.get()).toEqual(record);
|
|
24
|
+
await storage.delete();
|
|
25
|
+
expect(await storage.has()).toBe(false);
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
//# sourceMappingURL=indexeddb.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"indexeddb.test.js","sourceRoot":"","sources":["../../src/wallet/indexeddb.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAA;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAGzD,MAAM,MAAM,GAAiB;IAC3B,OAAO,EAAE,CAAC;IACV,OAAO,EAAE,4CAA4C;IACrD,KAAK,EAAE,aAAa;IACpB,SAAS,EAAE,CAAC;IACZ,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE;IAC3E,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE;CACtD,CAAA;AAED,SAAS,CAAC,KAAK,IAAI,EAAE;IACnB,MAAM,gBAAgB,EAAE,CAAA;AAC1B,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,EAAE,CAAC,gDAAgD,EAAE,KAAK,IAAI,EAAE;QAC9D,MAAM,OAAO,GAAG,IAAI,gBAAgB,EAAE,CAAA;QACtC,MAAM,OAAO,CAAC,MAAM,EAAE,CAAA;QAEtB,MAAM,CAAC,MAAM,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACvC,MAAM,CAAC,MAAM,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAA;QAEtC,MAAM,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;QACzB,MAAM,CAAC,MAAM,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACtC,MAAM,CAAC,MAAM,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;QAE3C,MAAM,OAAO,CAAC,MAAM,EAAE,CAAA;QACtB,MAAM,CAAC,MAAM,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IACzC,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kdf.test.d.ts","sourceRoot":"","sources":["../../src/wallet/kdf.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { KDF_ITERATIONS_CEILING, KDF_ITERATIONS_FLOOR, calibrateIterations, decryptSecret, encryptSecret, normalizePassword, } from './crypto.js';
|
|
3
|
+
describe('password normalization (R-#251)', () => {
|
|
4
|
+
it('trims and applies NFKD', () => {
|
|
5
|
+
expect(normalizePassword(' correct horse ')).toBe('correct horse');
|
|
6
|
+
expect(normalizePassword('café')).toBe('cafe\u0301');
|
|
7
|
+
expect(normalizePassword('clave')).toBe('clave');
|
|
8
|
+
});
|
|
9
|
+
it('is idempotent', () => {
|
|
10
|
+
const once = normalizePassword(' ñandú ');
|
|
11
|
+
expect(normalizePassword(once)).toBe(once);
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
describe('KDF calibration (R-#251)', () => {
|
|
15
|
+
it('never goes below the historical floor', async () => {
|
|
16
|
+
const slow = async () => 5000;
|
|
17
|
+
expect(await calibrateIterations(slow, 400)).toBe(KDF_ITERATIONS_FLOOR);
|
|
18
|
+
});
|
|
19
|
+
it('scales the count up to the budget on a fast device', async () => {
|
|
20
|
+
const fast = async () => 100;
|
|
21
|
+
expect(await calibrateIterations(fast, 400)).toBe(KDF_ITERATIONS_FLOOR * 4);
|
|
22
|
+
});
|
|
23
|
+
it('clamps at the ceiling so a slow phone cannot hang', async () => {
|
|
24
|
+
const instant = async () => 0.01;
|
|
25
|
+
expect(await calibrateIterations(instant, 400)).toBe(KDF_ITERATIONS_CEILING);
|
|
26
|
+
});
|
|
27
|
+
it('falls back to the floor when the measurement fails', async () => {
|
|
28
|
+
const broken = async () => { throw new Error('no crypto'); };
|
|
29
|
+
expect(await calibrateIterations(broken)).toBe(KDF_ITERATIONS_FLOOR);
|
|
30
|
+
const nonsense = async () => 0;
|
|
31
|
+
expect(await calibrateIterations(nonsense)).toBe(KDF_ITERATIONS_FLOOR);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
describe('record work factor (R-#251)', () => {
|
|
35
|
+
it('stores the iteration count it was asked for', async () => {
|
|
36
|
+
const secret = await encryptSecret('{"v":1}', 'clave-de-prueba', 1234);
|
|
37
|
+
expect(secret.kdf.iterations).toBe(1234);
|
|
38
|
+
expect(await decryptSecret(secret, 'clave-de-prueba')).toBe('{"v":1}');
|
|
39
|
+
});
|
|
40
|
+
it('uses the historical count by default', async () => {
|
|
41
|
+
const secret = await encryptSecret('{"v":1}', 'clave-de-prueba');
|
|
42
|
+
expect(secret.kdf.iterations).toBe(KDF_ITERATIONS_FLOOR);
|
|
43
|
+
});
|
|
44
|
+
it('opens a record whose password was written with spaces or accents', async () => {
|
|
45
|
+
const secret = await encryptSecret('{"v":1}', 'café con leche');
|
|
46
|
+
expect(await decryptSecret(secret, ' café con leche ')).toBe('{"v":1}');
|
|
47
|
+
expect(await decryptSecret(secret, 'cafe\u0301 con leche')).toBe('{"v":1}');
|
|
48
|
+
});
|
|
49
|
+
it('still rejects a wrong password', async () => {
|
|
50
|
+
const secret = await encryptSecret('{"v":1}', 'clave-de-prueba');
|
|
51
|
+
await expect(decryptSecret(secret, 'otra-clave')).rejects.toThrow(/Wrong password/);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
//# sourceMappingURL=kdf.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kdf.test.js","sourceRoot":"","sources":["../../src/wallet/kdf.test.ts"],"names":[],"mappings":"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"}
|