@prosopo/account 2.8.0 → 2.8.36
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/.turbo/turbo-build$colon$cjs.log +10 -6
- package/.turbo/turbo-build$colon$tsc.log +18 -14
- package/.turbo/turbo-build.log +11 -7
- package/CHANGELOG.md +344 -0
- package/dist/cjs/extension/ExtensionWeb2.cjs +5 -4
- package/dist/cjs/workers/CryptoWorkerManager.cjs +9 -0
- package/dist/extension/ExtensionWeb2.d.ts.map +1 -1
- package/dist/extension/ExtensionWeb2.js +6 -5
- package/dist/extension/ExtensionWeb2.js.map +1 -1
- package/dist/workers/CryptoWorkerManager.d.ts +1 -0
- package/dist/workers/CryptoWorkerManager.d.ts.map +1 -1
- package/dist/workers/CryptoWorkerManager.js +9 -0
- package/dist/workers/CryptoWorkerManager.js.map +1 -1
- package/package.json +9 -8
- package/src/custom.d.ts +44 -0
- package/src/extension/Extension.ts +29 -0
- package/src/extension/ExtensionWeb2.ts +121 -0
- package/src/extension/ExtensionWeb3.ts +60 -0
- package/src/index.ts +16 -0
- package/src/workers/CryptoWorkerManager.ts +225 -0
- package/src/workers/cryptoWorker.ts +79 -0
- package/src/workers/index.ts +18 -0
- package/tsconfig.cjs.json +37 -0
- package/tsconfig.json +40 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/tsconfig.types.json +9 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CryptoWorkerManager.js","sourceRoot":"","sources":["../../src/workers/CryptoWorkerManager.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"CryptoWorkerManager.js","sourceRoot":"","sources":["../../src/workers/CryptoWorkerManager.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prosopo/account",
|
|
3
|
-
"version": "2.8.
|
|
3
|
+
"version": "2.8.36",
|
|
4
4
|
"description": "Services and Utils for Prosopo account gen and management",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -36,7 +36,8 @@
|
|
|
36
36
|
},
|
|
37
37
|
"repository": {
|
|
38
38
|
"type": "git",
|
|
39
|
-
"url": "git+
|
|
39
|
+
"url": "git+https://github.com/prosopo/captcha.git",
|
|
40
|
+
"directory": "packages/account"
|
|
40
41
|
},
|
|
41
42
|
"author": "Prosopo Limited",
|
|
42
43
|
"license": "Apache-2.0",
|
|
@@ -50,15 +51,15 @@
|
|
|
50
51
|
"@polkadot/extension-inject": "0.62.3",
|
|
51
52
|
"@polkadot/util": "13.5.7",
|
|
52
53
|
"@polkadot/util-crypto": "13.5.7",
|
|
53
|
-
"@prosopo/common": "3.1.
|
|
54
|
-
"@prosopo/fingerprint": "2.6.
|
|
55
|
-
"@prosopo/keyring": "2.9.
|
|
56
|
-
"@prosopo/types": "3.
|
|
57
|
-
"@prosopo/util": "3.2.
|
|
54
|
+
"@prosopo/common": "3.1.38",
|
|
55
|
+
"@prosopo/fingerprint": "2.6.31",
|
|
56
|
+
"@prosopo/keyring": "2.9.35",
|
|
57
|
+
"@prosopo/types": "4.3.1",
|
|
58
|
+
"@prosopo/util": "3.2.15",
|
|
58
59
|
"@prosopo/util-crypto": "13.5.29"
|
|
59
60
|
},
|
|
60
61
|
"devDependencies": {
|
|
61
|
-
"@prosopo/config": "3.3.
|
|
62
|
+
"@prosopo/config": "3.3.1",
|
|
62
63
|
"@types/node": "22.10.2",
|
|
63
64
|
"@vitest/coverage-v8": "3.2.4",
|
|
64
65
|
"concurrently": "9.0.1",
|
package/src/custom.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// Copyright 2021-2026 Prosopo (UK) Ltd.
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
// For all modules ending in the Vite-specific "?raw" query parameter
|
|
15
|
+
|
|
16
|
+
declare module "*?raw" {
|
|
17
|
+
// The content of the file will be imported as a string.
|
|
18
|
+
const content: string;
|
|
19
|
+
export default content;
|
|
20
|
+
}
|
|
21
|
+
// 1. Declare the module pattern for any file path ending in "?worker&inline"
|
|
22
|
+
declare module "*?worker&inline" {
|
|
23
|
+
// 2. Define the type of the default export.
|
|
24
|
+
// The default export is a constructor function that returns a Worker instance.
|
|
25
|
+
|
|
26
|
+
// The syntax is: new () => Worker
|
|
27
|
+
// This tells TypeScript: "This export is a class/constructor that, when called with 'new', produces an object of type Worker."
|
|
28
|
+
const WorkerConstructor: {
|
|
29
|
+
new (): Worker;
|
|
30
|
+
// You can also add constructor overloads if you pass specific options, like { type: "module" }
|
|
31
|
+
new (options?: WorkerOptions): Worker;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export default WorkerConstructor;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Optional: Add the declaration for the non-inline version just in case
|
|
38
|
+
declare module "*?worker" {
|
|
39
|
+
const WorkerConstructor: {
|
|
40
|
+
new (): Worker;
|
|
41
|
+
new (options?: WorkerOptions): Worker;
|
|
42
|
+
};
|
|
43
|
+
export default WorkerConstructor;
|
|
44
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Copyright 2021-2026 Prosopo (UK) Ltd.
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
import type { Account, ProcaptchaClientConfigOutput } from "@prosopo/types";
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Class to interface with accounts.
|
|
18
|
+
*/
|
|
19
|
+
export abstract class Extension {
|
|
20
|
+
/**
|
|
21
|
+
* Find an account given an address.
|
|
22
|
+
* @returns the account
|
|
23
|
+
* @throws if the account is not found
|
|
24
|
+
* @param config
|
|
25
|
+
*/
|
|
26
|
+
public abstract getAccount(
|
|
27
|
+
config: ProcaptchaClientConfigOutput,
|
|
28
|
+
): Promise<Account>;
|
|
29
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
// Copyright 2021-2026 Prosopo (UK) Ltd.
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
|
|
15
|
+
import Signer from "@polkadot/extension-base/page/Signer";
|
|
16
|
+
import type { InjectedAccount } from "@polkadot/extension-inject/types";
|
|
17
|
+
import type { InjectedExtension } from "@polkadot/extension-inject/types";
|
|
18
|
+
import { stringToU8a } from "@polkadot/util";
|
|
19
|
+
import { getFingerprint, prefetchFingerprint } from "@prosopo/fingerprint";
|
|
20
|
+
import { Keyring } from "@prosopo/keyring";
|
|
21
|
+
import type { KeyringPair } from "@prosopo/types";
|
|
22
|
+
import type { Account, ProcaptchaClientConfigOutput } from "@prosopo/types";
|
|
23
|
+
import { u8aToHex, version } from "@prosopo/util";
|
|
24
|
+
import { hexHash } from "@prosopo/util-crypto";
|
|
25
|
+
import type { KeypairType } from "@prosopo/util-crypto";
|
|
26
|
+
import { getCryptoWorkerManager } from "../workers/CryptoWorkerManager.js";
|
|
27
|
+
import { Extension } from "./Extension.js";
|
|
28
|
+
|
|
29
|
+
prefetchFingerprint();
|
|
30
|
+
getCryptoWorkerManager().prewarm();
|
|
31
|
+
|
|
32
|
+
const EntropyToMnemonicLoader = async () =>
|
|
33
|
+
(await import("@prosopo/util-crypto")).entropyToMnemonic;
|
|
34
|
+
|
|
35
|
+
type AccountWithKeyPair = InjectedAccount & { keypair: KeyringPair };
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Class for interfacing with web3 accounts.
|
|
39
|
+
*/
|
|
40
|
+
export class ExtensionWeb2 extends Extension {
|
|
41
|
+
public async getAccount(
|
|
42
|
+
config: ProcaptchaClientConfigOutput,
|
|
43
|
+
): Promise<Account> {
|
|
44
|
+
const account = await this.createAccount(config);
|
|
45
|
+
const extension: InjectedExtension = this.createExtension(account);
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
account,
|
|
49
|
+
extension,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private createExtension(account: AccountWithKeyPair): InjectedExtension {
|
|
54
|
+
const signer = new Signer(async () => {
|
|
55
|
+
return;
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// signing carried out by the keypair. Signs the data with the private key, creating a signature. Other people can verify this signature given the message and the public key, proving that the message was indeed signed by account and proving ownership of the account.
|
|
59
|
+
signer.signRaw = async (payload) => {
|
|
60
|
+
const signature = account.keypair.sign(payload.data);
|
|
61
|
+
return {
|
|
62
|
+
id: 1, // the id of the request to sign. This should be incremented each time and adjust the signature, but we're hacking around this. Hence the signature will always be the same given the same payload.
|
|
63
|
+
signature: u8aToHex(signature) as `0x${string}`,
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
accounts: {
|
|
69
|
+
get: async () => {
|
|
70
|
+
// there is only ever 1 account
|
|
71
|
+
return [account];
|
|
72
|
+
},
|
|
73
|
+
subscribe: () => {
|
|
74
|
+
// do nothing, there will never be account changes
|
|
75
|
+
return () => {
|
|
76
|
+
return;
|
|
77
|
+
};
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
name: "procaptcha-web2",
|
|
81
|
+
version,
|
|
82
|
+
signer,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
private async createAccount(
|
|
87
|
+
config: ProcaptchaClientConfigOutput,
|
|
88
|
+
): Promise<AccountWithKeyPair> {
|
|
89
|
+
const browserEntropy = await getFingerprint();
|
|
90
|
+
|
|
91
|
+
// hash the entropy and remove 0x
|
|
92
|
+
const entropy = hexHash(browserEntropy, 128).slice(2);
|
|
93
|
+
|
|
94
|
+
const u8Entropy = stringToU8a(entropy);
|
|
95
|
+
|
|
96
|
+
let mnemonic: string;
|
|
97
|
+
|
|
98
|
+
// Try to use Web Worker for entropy-to-mnemonic conversion to avoid blocking
|
|
99
|
+
try {
|
|
100
|
+
const workerManager = getCryptoWorkerManager();
|
|
101
|
+
mnemonic = await workerManager.entropyToMnemonic(u8Entropy);
|
|
102
|
+
} catch (workerError) {
|
|
103
|
+
const entropyToMnemonic = await EntropyToMnemonicLoader();
|
|
104
|
+
mnemonic = entropyToMnemonic(u8Entropy);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const type: KeypairType = "sr25519";
|
|
108
|
+
const keyring = new Keyring({
|
|
109
|
+
type,
|
|
110
|
+
});
|
|
111
|
+
const keypair = keyring.addFromMnemonic(mnemonic);
|
|
112
|
+
const address = keypair.address;
|
|
113
|
+
return {
|
|
114
|
+
address,
|
|
115
|
+
name: address,
|
|
116
|
+
keypair,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export default ExtensionWeb2;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// Copyright 2021-2026 Prosopo (UK) Ltd.
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
|
|
15
|
+
import { web3Enable } from "@polkadot/extension-dapp";
|
|
16
|
+
import type { InjectedExtension } from "@polkadot/extension-inject/types";
|
|
17
|
+
import { cryptoWaitReady } from "@polkadot/util-crypto";
|
|
18
|
+
import { ProsopoError } from "@prosopo/common";
|
|
19
|
+
import type { Account, ProcaptchaClientConfigOutput } from "@prosopo/types";
|
|
20
|
+
import { Extension } from "./Extension.js";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Class for interfacing with web3 accounts.
|
|
24
|
+
*/
|
|
25
|
+
export class ExtensionWeb3 extends Extension {
|
|
26
|
+
public async getAccount(
|
|
27
|
+
config: ProcaptchaClientConfigOutput,
|
|
28
|
+
): Promise<Account> {
|
|
29
|
+
const { dappName, userAccountAddress: address } = config;
|
|
30
|
+
|
|
31
|
+
if (!address) {
|
|
32
|
+
throw new ProsopoError("WIDGET.NO_ACCOUNTS_FOUND", {
|
|
33
|
+
context: { error: "No account address provided" },
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
await cryptoWaitReady();
|
|
38
|
+
|
|
39
|
+
// enable access to all extensions
|
|
40
|
+
const extensions: InjectedExtension[] = await web3Enable(dappName);
|
|
41
|
+
if (extensions.length === 0) {
|
|
42
|
+
throw new ProsopoError("WIDGET.NO_EXTENSION_FOUND");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// search through all extensions for the one that has the account
|
|
46
|
+
for (const extension of extensions) {
|
|
47
|
+
const accounts = await extension.accounts.get();
|
|
48
|
+
const account = accounts.find((account) => account.address === address);
|
|
49
|
+
if (account) {
|
|
50
|
+
return { account, extension };
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
throw new ProsopoError("WIDGET.ACCOUNT_NOT_FOUND", {
|
|
55
|
+
context: { error: `No account found matching ${address}` },
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export default ExtensionWeb3;
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Copyright 2021-2026 Prosopo (UK) Ltd.
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
export * from "./extension/Extension.js";
|
|
15
|
+
export * from "./extension/ExtensionWeb2.js";
|
|
16
|
+
export * from "./extension/ExtensionWeb3.js";
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
// Copyright 2021-2026 Prosopo (UK) Ltd.
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
|
|
15
|
+
import CryptoWorkerConstructor from "./cryptoWorker.js?worker&inline";
|
|
16
|
+
|
|
17
|
+
interface CryptoWorkerMessage {
|
|
18
|
+
taskId: string;
|
|
19
|
+
task: string;
|
|
20
|
+
data: Record<string, string | Uint8Array>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface CryptoWorkerResponse {
|
|
24
|
+
taskId: string;
|
|
25
|
+
result?: Record<string, string>;
|
|
26
|
+
error?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Manages Web Worker for cryptographic operations to prevent blocking the main thread
|
|
31
|
+
*/
|
|
32
|
+
export class CryptoWorkerManager {
|
|
33
|
+
private worker: Worker | null = null;
|
|
34
|
+
private isInitializing = false;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Initialize the worker
|
|
38
|
+
*/
|
|
39
|
+
private async initWorker(): Promise<void> {
|
|
40
|
+
if (this.worker || this.isInitializing) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
this.isInitializing = true;
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
this.worker = new CryptoWorkerConstructor({ type: "module" });
|
|
48
|
+
|
|
49
|
+
// Add an IMMEDIATE global error handler for initialization failures (e.g., failed parsing)
|
|
50
|
+
this.worker.onerror = (errorEvent: ErrorEvent) => {
|
|
51
|
+
// Terminate the failed worker and mark for re-initialization
|
|
52
|
+
this.cleanup();
|
|
53
|
+
// The specific runTask/testWorker promise will reject via their local handleError
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// Test if worker is working
|
|
57
|
+
await this.testWorker();
|
|
58
|
+
} catch (error) {
|
|
59
|
+
this.cleanup(); // Clean up if instantiation itself fails
|
|
60
|
+
throw error; // Re-throw to propagate failure
|
|
61
|
+
} finally {
|
|
62
|
+
// We don't want to set isInitializing to false here if the worker started,
|
|
63
|
+
// but we can if the test fails or construction fails.
|
|
64
|
+
if (!this.worker) {
|
|
65
|
+
this.isInitializing = false;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Test if the worker is functioning properly
|
|
72
|
+
*/
|
|
73
|
+
private async testWorker(): Promise<void> {
|
|
74
|
+
if (!this.worker) {
|
|
75
|
+
throw new Error("Worker not initialized");
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const worker = this.worker;
|
|
79
|
+
|
|
80
|
+
return new Promise((resolve, reject) => {
|
|
81
|
+
const testTimeout = setTimeout(() => {
|
|
82
|
+
// Clean up event listeners on timeout
|
|
83
|
+
worker.removeEventListener("message", handleMessage);
|
|
84
|
+
worker.removeEventListener("error", handleError);
|
|
85
|
+
reject(new Error("Worker test timeout"));
|
|
86
|
+
}, 5000);
|
|
87
|
+
|
|
88
|
+
const handleMessage = (event: MessageEvent) => {
|
|
89
|
+
const { taskId, error, result } = event.data;
|
|
90
|
+
if (taskId === "test") {
|
|
91
|
+
clearTimeout(testTimeout);
|
|
92
|
+
worker.removeEventListener("message", handleMessage);
|
|
93
|
+
worker.removeEventListener("error", handleError); // Also remove error listener
|
|
94
|
+
|
|
95
|
+
if (error || result !== "ready") {
|
|
96
|
+
reject(
|
|
97
|
+
new Error(
|
|
98
|
+
`Worker test failed: ${error || 'Did not return "ready"'}`,
|
|
99
|
+
),
|
|
100
|
+
);
|
|
101
|
+
} else {
|
|
102
|
+
resolve();
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const handleError = (error: ErrorEvent) => {
|
|
108
|
+
clearTimeout(testTimeout);
|
|
109
|
+
worker.removeEventListener("message", handleMessage);
|
|
110
|
+
worker.removeEventListener("error", handleError);
|
|
111
|
+
reject(
|
|
112
|
+
new Error(`Worker test failed with error event: ${error.message}`),
|
|
113
|
+
);
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
worker.addEventListener("message", handleMessage);
|
|
117
|
+
worker.addEventListener("error", handleError); // Catch errors during test
|
|
118
|
+
|
|
119
|
+
// Send a test message
|
|
120
|
+
worker.postMessage({ taskId: "test", task: "test", data: {} });
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Eagerly spawn the worker so the first runTask() doesn't pay the
|
|
126
|
+
* worker-spawn + module-parse cost. Failures are swallowed because
|
|
127
|
+
* runTask() will reattempt initWorker() on demand.
|
|
128
|
+
*/
|
|
129
|
+
prewarm(): void {
|
|
130
|
+
this.initWorker().catch(() => {});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Run a task in the Web Worker
|
|
135
|
+
*/
|
|
136
|
+
async runTask<T>(
|
|
137
|
+
task: string,
|
|
138
|
+
data: Record<string, string | Uint8Array>,
|
|
139
|
+
): Promise<T> {
|
|
140
|
+
await this.initWorker();
|
|
141
|
+
|
|
142
|
+
if (!this.worker) {
|
|
143
|
+
throw new Error("Failed to initialize worker");
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const worker = this.worker;
|
|
147
|
+
|
|
148
|
+
return new Promise((resolve, reject) => {
|
|
149
|
+
const taskId = Math.random().toString(36).substr(2, 9);
|
|
150
|
+
const timeoutId = setTimeout(() => {
|
|
151
|
+
// Clean up listeners on timeout
|
|
152
|
+
worker.removeEventListener("message", handleMessage);
|
|
153
|
+
worker.removeEventListener("error", handleError);
|
|
154
|
+
reject(new Error(`Worker task ${task} timeout (Task ID: ${taskId})`));
|
|
155
|
+
}, 10000);
|
|
156
|
+
|
|
157
|
+
const handleMessage = (event: MessageEvent<CryptoWorkerResponse>) => {
|
|
158
|
+
if (event.data.taskId === taskId) {
|
|
159
|
+
clearTimeout(timeoutId);
|
|
160
|
+
worker.removeEventListener("message", handleMessage);
|
|
161
|
+
worker.removeEventListener("error", handleError);
|
|
162
|
+
|
|
163
|
+
if (event.data.error) {
|
|
164
|
+
// Reject with the error message sent back by the worker
|
|
165
|
+
reject(new Error(`Worker task failed: ${event.data.error}`));
|
|
166
|
+
} else {
|
|
167
|
+
resolve(event.data.result as T); // Type assertion for clean resolution
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
const handleError = (error: ErrorEvent) => {
|
|
173
|
+
clearTimeout(timeoutId);
|
|
174
|
+
worker.removeEventListener("message", handleMessage);
|
|
175
|
+
worker.removeEventListener("error", handleError);
|
|
176
|
+
// Reject on global worker error while task is pending
|
|
177
|
+
reject(new Error(`Worker error during task: ${error.message}`));
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
worker.addEventListener("message", handleMessage);
|
|
181
|
+
worker.addEventListener("error", handleError);
|
|
182
|
+
|
|
183
|
+
const message: CryptoWorkerMessage = { taskId, task, data };
|
|
184
|
+
worker.postMessage(message);
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Convert entropy to mnemonic using Web Worker
|
|
190
|
+
*/
|
|
191
|
+
async entropyToMnemonic(entropy: Uint8Array): Promise<string> {
|
|
192
|
+
return this.runTask<string>("entropyToMnemonic", { entropy });
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Clean up worker resources
|
|
197
|
+
*/
|
|
198
|
+
private cleanup(): void {
|
|
199
|
+
if (this.worker) {
|
|
200
|
+
this.worker.terminate();
|
|
201
|
+
}
|
|
202
|
+
this.worker = null;
|
|
203
|
+
this.isInitializing = false;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Public dispose method
|
|
208
|
+
*/
|
|
209
|
+
public dispose(): void {
|
|
210
|
+
this.cleanup();
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Create a singleton instance for reuse
|
|
215
|
+
let workerManagerInstance: CryptoWorkerManager | null = null;
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Get the singleton CryptoWorkerManager instance
|
|
219
|
+
*/
|
|
220
|
+
export function getCryptoWorkerManager(): CryptoWorkerManager {
|
|
221
|
+
if (!workerManagerInstance) {
|
|
222
|
+
workerManagerInstance = new CryptoWorkerManager();
|
|
223
|
+
}
|
|
224
|
+
return workerManagerInstance;
|
|
225
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// Copyright 2021-2026 Prosopo (UK) Ltd.
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
|
|
15
|
+
// cryptoWorker.ts
|
|
16
|
+
|
|
17
|
+
import { entropyToMnemonic } from "@prosopo/util-crypto";
|
|
18
|
+
|
|
19
|
+
interface CryptoWorkerMessage {
|
|
20
|
+
taskId: string;
|
|
21
|
+
task: "entropyToMnemonic" | "test";
|
|
22
|
+
data: {
|
|
23
|
+
entropy?: Uint8Array;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface CryptoWorkerResponse {
|
|
28
|
+
taskId: string;
|
|
29
|
+
result?: string;
|
|
30
|
+
error?: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// The main message listener runs in the worker's global scope
|
|
34
|
+
self.addEventListener(
|
|
35
|
+
"message",
|
|
36
|
+
async (event: MessageEvent<CryptoWorkerMessage>) => {
|
|
37
|
+
const { taskId, task, data } = event.data;
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
let result: string;
|
|
41
|
+
|
|
42
|
+
switch (task) {
|
|
43
|
+
case "test":
|
|
44
|
+
// Respond to test message to confirm worker is ready
|
|
45
|
+
result = "ready";
|
|
46
|
+
break;
|
|
47
|
+
case "entropyToMnemonic":
|
|
48
|
+
if (!data.entropy) {
|
|
49
|
+
throw new Error("Entropy data is required");
|
|
50
|
+
}
|
|
51
|
+
result = await processEntropyToMnemonic(data.entropy);
|
|
52
|
+
break;
|
|
53
|
+
default:
|
|
54
|
+
throw new Error(`Unknown task: ${task}`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const response: CryptoWorkerResponse = { taskId, result };
|
|
58
|
+
self.postMessage(response);
|
|
59
|
+
} catch (error) {
|
|
60
|
+
const response: CryptoWorkerResponse = {
|
|
61
|
+
taskId,
|
|
62
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
63
|
+
};
|
|
64
|
+
self.postMessage(response);
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
// Helper function remains async for consistency, even if entropyToMnemonic is sync
|
|
70
|
+
async function processEntropyToMnemonic(entropy: Uint8Array): Promise<string> {
|
|
71
|
+
try {
|
|
72
|
+
// Convert entropy to mnemonic (Vite/Rollup ensures this import is resolved and bundled)
|
|
73
|
+
return entropyToMnemonic(entropy);
|
|
74
|
+
} catch (error) {
|
|
75
|
+
throw new Error(
|
|
76
|
+
`Failed to process entropy: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Copyright 2021-2026 Prosopo (UK) Ltd.
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
|
|
15
|
+
export {
|
|
16
|
+
CryptoWorkerManager,
|
|
17
|
+
getCryptoWorkerManager,
|
|
18
|
+
} from "./CryptoWorkerManager.js";
|