@spirobel/monero-wallet-api 0.5.5 → 0.6.1
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/actionlog/actionLogOpened.d.ts +96 -1
- package/dist/actionlog/actionLogOpened.js +386 -1
- package/dist/actionlog/actionLogTypes.d.ts +114 -0
- package/dist/actionlog/actionLogTypes.js +198 -0
- package/dist/actionlog/backend/idbBackend.d.ts +13 -0
- package/dist/actionlog/backend/idbBackend.js +109 -0
- package/dist/actionlog/backend/jsonlBackend.d.ts +19 -0
- package/dist/actionlog/backend/jsonlBackend.js +110 -0
- package/dist/actionlog/backend/memoryBackend.d.ts +11 -0
- package/dist/actionlog/backend/memoryBackend.js +31 -0
- package/dist/actionlog/backend/sqliteBackend.d.ts +14 -0
- package/dist/actionlog/backend/sqliteBackend.js +96 -0
- package/dist/actionlog/backend.d.ts +12 -0
- package/dist/actionlog/backend.js +1 -0
- package/dist/actionlog/idbBackend.d.ts +19 -0
- package/dist/actionlog/idbBackend.js +98 -0
- package/dist/actionlog/jsonlBackend.d.ts +19 -0
- package/dist/actionlog/jsonlBackend.js +75 -0
- package/dist/actionlog/memoryBackend.d.ts +14 -0
- package/dist/actionlog/memoryBackend.js +38 -0
- package/dist/actionlog/openMaps.d.ts +11 -0
- package/dist/actionlog/openMaps.js +32 -0
- package/dist/actionlog/sqliteBackend.d.ts +18 -0
- package/dist/actionlog/sqliteBackend.js +105 -0
- package/dist/actionlog/toolContext.d.ts +36 -0
- package/dist/actionlog/toolContext.js +1 -0
- package/dist/actionlog/types.d.ts +62 -0
- package/dist/actionlog/types.js +62 -0
- package/dist/io/logging.js +1 -1
- package/dist/multisig/escrow.js +1 -1
- package/dist/scanning-syncing/backgroundWorker.js +1 -1
- package/dist/scanning-syncing/blocksbuffer/blocksBufferFetchLoop.d.ts +1 -1
- package/dist/scanning-syncing/blocksbuffer/blocksBufferFetchLoop.js +1 -1
- package/dist/scanning-syncing/blocksbuffer/blocksbufferCoordination.d.ts +1 -1
- package/dist/scanning-syncing/blocksbuffer/blocksbufferCoordination.js +2 -2
- package/dist/scanning-syncing/connectionStatus.d.ts +3 -1
- package/dist/scanning-syncing/connectionStatus.js +38 -3
- package/dist/scanning-syncing/connectionStatusOpened.d.ts +1 -1
- package/dist/scanning-syncing/connectionStatusOpened.js +2 -11
- package/dist/scanning-syncing/openWallet.js +1 -1
- package/dist/scanning-syncing/scanresult/computeKeyImage.d.ts +1 -1
- package/dist/scanning-syncing/scanresult/scanCache.d.ts +6 -2
- package/dist/scanning-syncing/scanresult/scanCache.js +12 -3
- package/dist/scanning-syncing/scanresult/scanCacheOpened.d.ts +47 -2
- package/dist/scanning-syncing/scanresult/scanCacheOpened.js +328 -47
- package/dist/scanning-syncing/scanresult/scanCoordination.d.ts +3 -2
- package/dist/scanning-syncing/scanresult/scanCoordination.js +42 -6
- package/dist/scanning-syncing/scanresult/scanLoop.d.ts +1 -1
- package/dist/scanning-syncing/scanresult/scanLoop.js +1 -1
- package/dist/scanning-syncing/scanresult/scanResult.d.ts +1 -1
- package/dist/scanning-syncing/scanresult/scanResult.js +18 -13
- package/dist/scanning-syncing/scanresult/scanStats.d.ts +1 -1
- package/dist/scanning-syncing/scanresult/scanStats.js +9 -6
- package/dist/scanning-syncing/worker-entrypoints/worker.js +1 -1
- package/dist/scanning-syncing/worker-mains/cpubound-main.js +1 -1
- package/dist/scanning-syncing/worker-mains/multisig-main.d.ts +1 -1
- package/dist/scanning-syncing/worker-mains/multisig-main.js +1 -1
- package/dist/scanning-syncing/worker-mains/worker.js +1 -1
- package/dist/scansettings/scanSettings.js +1 -1
- package/dist/scansettings/scanSettingsOpened.d.ts +1 -1
- package/dist/scansettings/scanSettingsOpened.js +1 -1
- package/dist/send-functionality/inputSelection.d.ts +1 -1
- package/dist/send-functionality/transactionBuilding.d.ts +1 -1
- package/dist/tools/calls/001.d.ts +20 -0
- package/dist/tools/calls/001.js +236 -0
- package/dist/tools/calls/002-content.d.ts +46 -0
- package/dist/tools/calls/002-content.js +135 -0
- package/dist/tools/calls/002-fail-cleanup.d.ts +27 -0
- package/dist/tools/calls/002-fail-cleanup.js +60 -0
- package/dist/tools/calls/002.d.ts +64 -0
- package/dist/tools/calls/002.js +353 -0
- package/dist/tools/content.d.ts +22 -0
- package/dist/tools/content.js +41 -0
- package/dist/tools/counterparty.d.ts +3 -0
- package/dist/tools/counterparty.js +1 -0
- package/dist/tools/download-public-suffix.d.ts +1 -0
- package/dist/tools/download-public-suffix.js +20 -0
- package/dist/tools/globals.d.ts +196 -0
- package/dist/tools/globals.js +14 -0
- package/dist/tools/monero-tools-content.d.ts +29 -0
- package/dist/tools/monero-tools-content.js +80 -0
- package/dist/tools/monero-tools.d.ts +27 -52
- package/dist/tools/monero-tools.js +127 -222
- package/dist/tools/public-suffix-list.d.ts +1 -0
- package/dist/tools/public-suffix-list.js +10336 -0
- package/dist/tools/runtimeMessages.d.ts +4 -0
- package/dist/tools/runtimeMessages.js +18 -0
- package/dist/tools/toolActionLogContext.d.ts +33 -0
- package/dist/tools/toolActionLogContext.js +1 -0
- package/dist/tools/toolArm.d.ts +47 -0
- package/dist/tools/toolArm.js +1 -0
- package/dist/tools/ui.d.ts +2 -0
- package/dist/tools/ui.js +1 -0
- package/dist/tools/worker.d.ts +1 -0
- package/dist/tools/worker.js +1 -0
- package/dist/viewpair/ViewPair.d.ts +3 -3
- package/dist/viewpair/ViewPair.js +2 -2
- package/dist/wasm-processing/wasmFile.js +2 -2
- package/dist/{api.d.ts → xmr3.d.ts} +4 -0
- package/dist/{api.js → xmr3.js} +3 -0
- package/package.json +13 -6
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DistributedKeyGenerator, type DkgParticipateParams, type DkgVerifyParams } from "../../
|
|
1
|
+
import { DistributedKeyGenerator, type DkgParticipateParams, type DkgVerifyParams } from "../../xmr3";
|
|
2
2
|
export type MultiSigParticipateCall = {
|
|
3
3
|
type: "multisig-call";
|
|
4
4
|
functionName: "participate";
|
|
@@ -2,7 +2,7 @@ import { coordinatorMainWorker, requestCoordinatorShutdown, } from "./coordinato
|
|
|
2
2
|
import { handleCpuboundScanTry, sendFromCpuWorker } from "./cpubound-main";
|
|
3
3
|
import { log, setupLoggingPath } from "../../io/logging";
|
|
4
4
|
import { multisigMainWorkerCall } from "./multisig-main";
|
|
5
|
-
import { DistributedKeyGenerator, SCAN_SETTINGS_STORE_NAME_DEFAULT, } from "../../
|
|
5
|
+
import { DistributedKeyGenerator, SCAN_SETTINGS_STORE_NAME_DEFAULT, } from "../../xmr3";
|
|
6
6
|
self.onerror = (e) => self.postMessage({ type: "ERROR", payload: e });
|
|
7
7
|
self.addEventListener("unhandledrejection", (e) => self.postMessage({ type: "ERROR", payload: e.reason }));
|
|
8
8
|
let SCAN_SETTINGS_PATH;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type LogSetting, type PossibleLogs } from "../io/logging";
|
|
2
|
-
import { type ScanSetting, type ScanSettingOpened } from "../
|
|
2
|
+
import { type ScanSetting, type ScanSettingOpened } from "../xmr3";
|
|
3
3
|
export declare class ScanSettingsOpened {
|
|
4
4
|
private _scan_settings_path;
|
|
5
5
|
private _pathPrefix;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { LOCAL_NODE_DEFAULT_URL } from "../node-interaction/nodeUrl";
|
|
2
2
|
import { LOGGING_FUNCTIONS, } from "../io/logging";
|
|
3
|
-
import { getPathPrefix, makeSpendKeyFromSeed, makeViewKey, openScanSettingsFile, parseAddress, SCAN_SETTINGS_STORE_NAME_DEFAULT, SUB_ADDRESS_INDEX_DEFAULT_VALUE, walletSettingsPlusKeys, writeEnvLineToDotEnvRefresh, writeScanSettings, writeViewKeyToDotEnv, } from "../
|
|
3
|
+
import { getPathPrefix, makeSpendKeyFromSeed, makeViewKey, openScanSettingsFile, parseAddress, SCAN_SETTINGS_STORE_NAME_DEFAULT, SUB_ADDRESS_INDEX_DEFAULT_VALUE, walletSettingsPlusKeys, writeEnvLineToDotEnvRefresh, writeScanSettings, writeViewKeyToDotEnv, } from "../xmr3";
|
|
4
4
|
export class ScanSettingsOpened {
|
|
5
5
|
_scan_settings_path;
|
|
6
6
|
_pathPrefix;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type ToolArm } from "../globals";
|
|
2
|
+
export type SendTransactionTool = {
|
|
3
|
+
tool_id: "001";
|
|
4
|
+
payload: SendTransactionToolPayload;
|
|
5
|
+
};
|
|
6
|
+
export type SendTransactionToolPayload = {
|
|
7
|
+
address: string;
|
|
8
|
+
amount: string;
|
|
9
|
+
no_check: boolean;
|
|
10
|
+
};
|
|
11
|
+
export type IsPayAddressKnown = (address: string) => boolean | Promise<boolean>;
|
|
12
|
+
declare function validate_route(deps: {
|
|
13
|
+
isPayAddressKnown: IsPayAddressKnown;
|
|
14
|
+
}): (req: Request) => Promise<Response>;
|
|
15
|
+
export declare function amountForChainSend(amount: string): string;
|
|
16
|
+
type Tool001CounterpartyExtra = {
|
|
17
|
+
validate_route: typeof validate_route;
|
|
18
|
+
};
|
|
19
|
+
declare const tool001: ToolArm<SendTransactionToolPayload, Tool001CounterpartyExtra>;
|
|
20
|
+
export default tool001;
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { convertAmountBigInt, convertAmountBigIntThrows, } from "../../send-functionality/conversion";
|
|
2
|
+
import { TOOL_MAGIC_STRING, } from "../globals";
|
|
3
|
+
function recognize_parse(args) {
|
|
4
|
+
const amount = args[1];
|
|
5
|
+
const address = args[3];
|
|
6
|
+
// trailing _no_check splits into ["no", "check"] after underscore split
|
|
7
|
+
const no_check = args.length >= 6 &&
|
|
8
|
+
args[args.length - 2] === "no" &&
|
|
9
|
+
args[args.length - 1] === "check";
|
|
10
|
+
try {
|
|
11
|
+
convertAmountBigIntThrows(amount);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
if (address && amount) {
|
|
17
|
+
return {
|
|
18
|
+
tool_id: "001",
|
|
19
|
+
payload: { address, amount, no_check },
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
function make(payload) {
|
|
25
|
+
convertAmountBigIntThrows(payload.amount);
|
|
26
|
+
const base = `${TOOL_MAGIC_STRING}001_amount_${payload.amount}_address_${payload.address}`;
|
|
27
|
+
return payload.no_check ? `${base}_no_check` : base;
|
|
28
|
+
}
|
|
29
|
+
async function validate_check(invo) {
|
|
30
|
+
const tool = invo.tool;
|
|
31
|
+
if (tool.tool_id !== "001")
|
|
32
|
+
return "unverified";
|
|
33
|
+
if (tool.payload.no_check)
|
|
34
|
+
return "unverified";
|
|
35
|
+
const link = invo[invo.found_in];
|
|
36
|
+
const invo_link = new URL(link);
|
|
37
|
+
const checkUrl = `${invo_link.origin}/monerochan001/${tool.payload.address}`;
|
|
38
|
+
try {
|
|
39
|
+
const result = (await (await fetch(checkUrl)).json());
|
|
40
|
+
if (result &&
|
|
41
|
+
typeof result === "object" &&
|
|
42
|
+
"valid_address" in result &&
|
|
43
|
+
result.valid_address === true) {
|
|
44
|
+
return "valid";
|
|
45
|
+
}
|
|
46
|
+
return "invalid";
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return "invalid";
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const ADDRESS_VALID_RESPONSE = {
|
|
53
|
+
valid_address: true,
|
|
54
|
+
};
|
|
55
|
+
const ADDRESS_INVALID_RESPONSE = {
|
|
56
|
+
valid_address: false,
|
|
57
|
+
};
|
|
58
|
+
function addressFromMonerochan001Req(req) {
|
|
59
|
+
const r = req;
|
|
60
|
+
if (r.params?.address)
|
|
61
|
+
return decodeURIComponent(r.params.address);
|
|
62
|
+
const m = new URL(req.url).pathname.match(/monerochan001\/([^/]+)\/?$/);
|
|
63
|
+
return m?.[1] ? decodeURIComponent(m[1]) : "";
|
|
64
|
+
}
|
|
65
|
+
async function handleAddressCheck(req, deps) {
|
|
66
|
+
const address = addressFromMonerochan001Req(req);
|
|
67
|
+
if (!address)
|
|
68
|
+
return Response.json(ADDRESS_INVALID_RESPONSE);
|
|
69
|
+
const known = await deps.isPayAddressKnown(address);
|
|
70
|
+
return Response.json(known ? ADDRESS_VALID_RESPONSE : ADDRESS_INVALID_RESPONSE);
|
|
71
|
+
}
|
|
72
|
+
function validate_route(deps) {
|
|
73
|
+
return (req) => handleAddressCheck(req, deps);
|
|
74
|
+
}
|
|
75
|
+
function flatFromParsed(invo) {
|
|
76
|
+
const p = invo.tool.payload;
|
|
77
|
+
return {
|
|
78
|
+
invocationId: invo.invocation_id,
|
|
79
|
+
toolId: "001",
|
|
80
|
+
amount: p.amount,
|
|
81
|
+
address: p.address,
|
|
82
|
+
no_check: p.no_check,
|
|
83
|
+
context_domain: invo.context_domain,
|
|
84
|
+
destination_domain: invo.destination_domain,
|
|
85
|
+
context_href: invo.context_href,
|
|
86
|
+
found_in: invo.found_in,
|
|
87
|
+
link: invo.link,
|
|
88
|
+
linkText: invo.linkText,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/** first toolCall state transition: session_start invoked. */
|
|
92
|
+
async function invoke_write(ctx, invo) {
|
|
93
|
+
if (invo.tool.tool_id !== "001")
|
|
94
|
+
return;
|
|
95
|
+
const flat = flatFromParsed(invo);
|
|
96
|
+
await ctx.log.append({
|
|
97
|
+
type: "session_start",
|
|
98
|
+
stage: "invoked",
|
|
99
|
+
...flat,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
/** second toolCall state transition: validate_result validated. */
|
|
103
|
+
async function validate_write(ctx, invo) {
|
|
104
|
+
if (invo.tool.tool_id !== "001")
|
|
105
|
+
return;
|
|
106
|
+
const flat = flatFromParsed(invo);
|
|
107
|
+
await ctx.log.append({
|
|
108
|
+
type: "validate_result",
|
|
109
|
+
stage: "validated",
|
|
110
|
+
...flat,
|
|
111
|
+
valid: invo.valid,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
export function amountForChainSend(amount) {
|
|
115
|
+
return convertAmountBigInt(amount).toString();
|
|
116
|
+
}
|
|
117
|
+
function alreadyAccepted(type) {
|
|
118
|
+
return (type === "accept" ||
|
|
119
|
+
type === "execute_start" ||
|
|
120
|
+
type === "execute_error" ||
|
|
121
|
+
type === "execute_result" ||
|
|
122
|
+
type === "dismiss" ||
|
|
123
|
+
type === "aborted");
|
|
124
|
+
}
|
|
125
|
+
/** third toolCall state transition: accept accepted. */
|
|
126
|
+
async function accept_yes(ctx, invocationId, args) {
|
|
127
|
+
const invo = await ctx.log.invocation(invocationId);
|
|
128
|
+
if (!invo || alreadyAccepted(invo.lastType))
|
|
129
|
+
return;
|
|
130
|
+
const address = String(args.address ?? invo.address ?? "");
|
|
131
|
+
const amount = String(args.amount ?? invo.amount ?? "");
|
|
132
|
+
const wallet_to_send_from_pa = String(args.wallet_to_send_from_pa ?? "");
|
|
133
|
+
await ctx.log.append({
|
|
134
|
+
type: "accept",
|
|
135
|
+
stage: "accepted",
|
|
136
|
+
invocationId,
|
|
137
|
+
toolId: "001",
|
|
138
|
+
address,
|
|
139
|
+
amount,
|
|
140
|
+
wallet_to_send_from_pa,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
/** fourth toolCall state transition: execute_start executed. fifth: execute_result executed. */
|
|
144
|
+
async function execute_run(ctx, invocationId, args) {
|
|
145
|
+
const invo = await ctx.log.invocation(invocationId);
|
|
146
|
+
if (!invo) {
|
|
147
|
+
console.error("send with no invocation");
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
const address = String(args.address ?? invo.address ?? "");
|
|
151
|
+
const amount = String(args.amount ?? invo.amount ?? "");
|
|
152
|
+
const wallet_to_send_from_pa = String(args.wallet_to_send_from_pa ?? invo.wallet_to_send_from_pa ?? "");
|
|
153
|
+
const toolId = "001";
|
|
154
|
+
await ctx.log.append({
|
|
155
|
+
type: "execute_start",
|
|
156
|
+
stage: "executed",
|
|
157
|
+
invocationId,
|
|
158
|
+
toolId,
|
|
159
|
+
address,
|
|
160
|
+
amount,
|
|
161
|
+
wallet_to_send_from_pa,
|
|
162
|
+
});
|
|
163
|
+
let ok = false;
|
|
164
|
+
let error;
|
|
165
|
+
try {
|
|
166
|
+
const wallets = ctx.getWallets?.();
|
|
167
|
+
const wallet = wallets?.wallets?.find((w) => w.primary_address === wallet_to_send_from_pa);
|
|
168
|
+
if (!wallet)
|
|
169
|
+
throw new Error("wallet not found");
|
|
170
|
+
await wallet.makeSignSendTransaction({
|
|
171
|
+
payments: [{ address, amount: amountForChainSend(amount) }],
|
|
172
|
+
invocationId,
|
|
173
|
+
});
|
|
174
|
+
ok = true;
|
|
175
|
+
}
|
|
176
|
+
catch (e) {
|
|
177
|
+
console.error(e);
|
|
178
|
+
ok = false;
|
|
179
|
+
error = e instanceof Error ? e.message : String(e);
|
|
180
|
+
}
|
|
181
|
+
await ctx.log.append({
|
|
182
|
+
type: "execute_result",
|
|
183
|
+
stage: "executed",
|
|
184
|
+
invocationId,
|
|
185
|
+
toolId,
|
|
186
|
+
ok,
|
|
187
|
+
...(error ? { error } : {}),
|
|
188
|
+
address,
|
|
189
|
+
amount,
|
|
190
|
+
wallet_to_send_from_pa,
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
/** toolCall state transition: dismiss accepted. */
|
|
194
|
+
async function accept_no(ctx, invocationId) {
|
|
195
|
+
const invo = await ctx.log.invocation(invocationId);
|
|
196
|
+
// once the user accepted, execution is in flight. a late dismiss (the send
|
|
197
|
+
// plate clears the form right after execute) must not flip the entry to dismissed
|
|
198
|
+
if (!invo ||
|
|
199
|
+
invo.lastType === "dismiss" ||
|
|
200
|
+
invo.lastType === "accept" ||
|
|
201
|
+
invo.lastType === "execute_start" ||
|
|
202
|
+
invo.lastType === "execute_result" ||
|
|
203
|
+
invo.lastType === "aborted") {
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
await ctx.log.append({
|
|
207
|
+
type: "dismiss",
|
|
208
|
+
stage: "accepted",
|
|
209
|
+
invocationId,
|
|
210
|
+
toolId: "001",
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
const tool001 = {
|
|
214
|
+
permissions: ["spend"],
|
|
215
|
+
ui: {
|
|
216
|
+
openTitle: "payment link",
|
|
217
|
+
acceptLabel: "SEND",
|
|
218
|
+
dismissLabel: "DISMISS",
|
|
219
|
+
},
|
|
220
|
+
content: {
|
|
221
|
+
recognize_parse,
|
|
222
|
+
validate_check,
|
|
223
|
+
},
|
|
224
|
+
worker: {
|
|
225
|
+
invoke_write,
|
|
226
|
+
validate_write,
|
|
227
|
+
accept_yes,
|
|
228
|
+
accept_no,
|
|
229
|
+
execute_run,
|
|
230
|
+
},
|
|
231
|
+
counterparty: {
|
|
232
|
+
make,
|
|
233
|
+
validate_route,
|
|
234
|
+
},
|
|
235
|
+
};
|
|
236
|
+
export default tool001;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* content-script-safe 002 surface (no scansettings / atomicWrite / indexedDB).
|
|
3
|
+
*/
|
|
4
|
+
import { type ToolInvocationValidity } from "../globals";
|
|
5
|
+
import type { ToolInvocationForValidate } from "../toolArm";
|
|
6
|
+
export type CreateAndShareViewOnlyWalletTool = {
|
|
7
|
+
tool_id: "002";
|
|
8
|
+
payload: CreateAndShareViewOnlyWalletToolPayload;
|
|
9
|
+
};
|
|
10
|
+
export type CreateAndShareViewOnlyWalletToolPayload = {
|
|
11
|
+
wallet_slot: number;
|
|
12
|
+
};
|
|
13
|
+
export declare function parseCreateAndShareViewOnlyWalletToolArgs(args: string[]): CreateAndShareViewOnlyWalletTool | null;
|
|
14
|
+
export declare function createCreateAndShareViewOnlyWalletToolLink(wallet_slot?: number): string;
|
|
15
|
+
export declare function make002ToolLink(wallet_slot?: number): string;
|
|
16
|
+
export declare function makeFromPayload(payload: CreateAndShareViewOnlyWalletToolPayload): string;
|
|
17
|
+
export declare function validate(invo: ToolInvocationForValidate): ToolInvocationValidity;
|
|
18
|
+
export type ShareViewkeyPayload = {
|
|
19
|
+
viewkey: string;
|
|
20
|
+
primary_address: string;
|
|
21
|
+
tool_invo: {
|
|
22
|
+
tool: {
|
|
23
|
+
tool_id: string;
|
|
24
|
+
payload: {
|
|
25
|
+
wallet_slot: number;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
found_in: "link" | "linkText";
|
|
29
|
+
link: string;
|
|
30
|
+
linkText: string;
|
|
31
|
+
valid: ToolInvocationValidity;
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
export type ShareViewkeyResult = {
|
|
35
|
+
ok: boolean;
|
|
36
|
+
successUrl: string | null;
|
|
37
|
+
error?: string;
|
|
38
|
+
};
|
|
39
|
+
export type ShareViewkey002Pruned = {
|
|
40
|
+
viewkey: string;
|
|
41
|
+
primary_address: string;
|
|
42
|
+
wallet_slot: number;
|
|
43
|
+
};
|
|
44
|
+
export declare function shareViewKey002(payload: ShareViewkeyPayload): Promise<ShareViewkeyResult>;
|
|
45
|
+
export declare function potentialSuccessRedirect002(payload: ShareViewkeyPayload): Promise<ShareViewkeyResult | undefined>;
|
|
46
|
+
export declare function afterValidate(invo: ToolInvocationForValidate): void;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* content-script-safe 002 surface (no scansettings / atomicWrite / indexedDB).
|
|
3
|
+
*/
|
|
4
|
+
import { TOOL_MAGIC_STRING, } from "../globals";
|
|
5
|
+
export function parseCreateAndShareViewOnlyWalletToolArgs(args) {
|
|
6
|
+
const wallet_slot = args[5];
|
|
7
|
+
if (wallet_slot && !isNaN(parseInt(wallet_slot))) {
|
|
8
|
+
return {
|
|
9
|
+
tool_id: "002",
|
|
10
|
+
payload: {
|
|
11
|
+
wallet_slot: parseInt(wallet_slot),
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
export function createCreateAndShareViewOnlyWalletToolLink(wallet_slot) {
|
|
18
|
+
wallet_slot = Number(wallet_slot) || 0;
|
|
19
|
+
return `${TOOL_MAGIC_STRING}002_create_and_share_viewkey_slot_${wallet_slot}`;
|
|
20
|
+
}
|
|
21
|
+
export function make002ToolLink(wallet_slot) {
|
|
22
|
+
return createCreateAndShareViewOnlyWalletToolLink(wallet_slot);
|
|
23
|
+
}
|
|
24
|
+
export function makeFromPayload(payload) {
|
|
25
|
+
return createCreateAndShareViewOnlyWalletToolLink(payload.wallet_slot);
|
|
26
|
+
}
|
|
27
|
+
export function validate(invo) {
|
|
28
|
+
if (invo.tool.tool_id !== "002")
|
|
29
|
+
return "unverified";
|
|
30
|
+
if (invo.context_domain == invo.destination_domain)
|
|
31
|
+
return "valid";
|
|
32
|
+
return "invalid";
|
|
33
|
+
}
|
|
34
|
+
export async function shareViewKey002(payload) {
|
|
35
|
+
const invo = payload.tool_invo;
|
|
36
|
+
if (invo.tool.tool_id !== "002")
|
|
37
|
+
return {
|
|
38
|
+
ok: false,
|
|
39
|
+
successUrl: null,
|
|
40
|
+
};
|
|
41
|
+
if (invo.valid !== "valid")
|
|
42
|
+
return {
|
|
43
|
+
ok: false,
|
|
44
|
+
successUrl: null,
|
|
45
|
+
};
|
|
46
|
+
const link = invo[invo.found_in];
|
|
47
|
+
const invo_link = new URL(link);
|
|
48
|
+
const shareVKUrl = `${invo_link.origin}/monerochan002/`;
|
|
49
|
+
try {
|
|
50
|
+
const result = await fetch(shareVKUrl, {
|
|
51
|
+
method: "POST",
|
|
52
|
+
headers: { "Content-Type": "application/json" },
|
|
53
|
+
body: JSON.stringify({
|
|
54
|
+
viewkey: payload.viewkey,
|
|
55
|
+
primary_address: payload.primary_address,
|
|
56
|
+
wallet_slot: invo.tool.payload.wallet_slot,
|
|
57
|
+
}),
|
|
58
|
+
});
|
|
59
|
+
if (result.ok) {
|
|
60
|
+
const data = (await result.json());
|
|
61
|
+
if (data && typeof data === "object" && "ok" in data && data.ok === true) {
|
|
62
|
+
return {
|
|
63
|
+
ok: true,
|
|
64
|
+
successUrl: data.successUrl ?? null,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
ok: false,
|
|
69
|
+
successUrl: null,
|
|
70
|
+
error: "counterparty rejected share",
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
ok: false,
|
|
75
|
+
successUrl: null,
|
|
76
|
+
error: `share post failed ${result.status}`,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
catch (e) {
|
|
80
|
+
return {
|
|
81
|
+
ok: false,
|
|
82
|
+
successUrl: null,
|
|
83
|
+
error: e instanceof Error ? e.message : String(e),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
export async function potentialSuccessRedirect002(payload) {
|
|
88
|
+
const shareVKresult = await shareViewKey002(payload);
|
|
89
|
+
if (shareVKresult.ok && shareVKresult.successUrl) {
|
|
90
|
+
window.location.href = shareVKresult.successUrl;
|
|
91
|
+
window.location.reload();
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
return shareVKresult;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
export function afterValidate(invo) {
|
|
98
|
+
const g = globalThis;
|
|
99
|
+
const rt = g.browser?.runtime ?? g.chrome?.runtime;
|
|
100
|
+
if (!rt)
|
|
101
|
+
return;
|
|
102
|
+
const port = rt.connect({ name: invo.invocation_id });
|
|
103
|
+
port.onMessage.addListener((msg) => {
|
|
104
|
+
const m = msg;
|
|
105
|
+
const k = m.kind ?? m.type;
|
|
106
|
+
if (k !== "shareViewkey" || !m.payload)
|
|
107
|
+
return;
|
|
108
|
+
void (async () => {
|
|
109
|
+
try {
|
|
110
|
+
const result = await potentialSuccessRedirect002(m.payload);
|
|
111
|
+
if (result) {
|
|
112
|
+
rt.sendMessage({
|
|
113
|
+
kind: "shareViewkeyFAILED",
|
|
114
|
+
payload: { ...m.payload, error: result.error },
|
|
115
|
+
}).catch(() => { });
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
rt.sendMessage({
|
|
119
|
+
kind: "shareViewkeyOK",
|
|
120
|
+
payload: { invocationId: invo.invocation_id },
|
|
121
|
+
}).catch(() => { });
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
catch (e) {
|
|
125
|
+
rt.sendMessage({
|
|
126
|
+
kind: "shareViewkeyFAILED",
|
|
127
|
+
payload: {
|
|
128
|
+
...m.payload,
|
|
129
|
+
error: e instanceof Error ? e.message : String(e),
|
|
130
|
+
},
|
|
131
|
+
}).catch(() => { });
|
|
132
|
+
}
|
|
133
|
+
})();
|
|
134
|
+
});
|
|
135
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** tool-owned path; host must not hardcode this name */
|
|
2
|
+
export declare const FAILED_SHARE_VIEW_RESTORE_PATH = "failed_share_view_restore.json";
|
|
3
|
+
export type FailedShareViewRestore = {
|
|
4
|
+
viewkey: string;
|
|
5
|
+
primary_address: string;
|
|
6
|
+
tool_invo: {
|
|
7
|
+
invocation_id: string;
|
|
8
|
+
context_domain: string;
|
|
9
|
+
context_href: string;
|
|
10
|
+
destination_domain: string;
|
|
11
|
+
found_in: "link" | "linkText";
|
|
12
|
+
link: string;
|
|
13
|
+
linkText: string;
|
|
14
|
+
timestamp: number;
|
|
15
|
+
valid: "valid" | "invalid" | "unverified";
|
|
16
|
+
tool: {
|
|
17
|
+
tool_id: string;
|
|
18
|
+
payload: {
|
|
19
|
+
wallet_slot?: number;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
export declare function readFailedShareViewRestore(): Promise<FailedShareViewRestore | null>;
|
|
25
|
+
export declare function clearFailedShareViewRestore(): Promise<void>;
|
|
26
|
+
export declare function removeWalletAfterShareFail(primary_address: string): Promise<void>;
|
|
27
|
+
export declare function persistFailedShareViewRestore(payload: FailedShareViewRestore): Promise<void>;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { atomicWrite } from "../../io/atomicWrite";
|
|
2
|
+
import { writeScanSettingsFileDefaultLocation } from "../../scansettings/scanSettings";
|
|
3
|
+
/** tool-owned path; host must not hardcode this name */
|
|
4
|
+
export const FAILED_SHARE_VIEW_RESTORE_PATH = "failed_share_view_restore.json";
|
|
5
|
+
const LEGACY_FAILED_SHARE_VIEW_RESTORE_PATH = "failed_wallet_restore_002.json";
|
|
6
|
+
export async function readFailedShareViewRestore() {
|
|
7
|
+
for (const path of [
|
|
8
|
+
FAILED_SHARE_VIEW_RESTORE_PATH,
|
|
9
|
+
LEGACY_FAILED_SHARE_VIEW_RESTORE_PATH,
|
|
10
|
+
]) {
|
|
11
|
+
try {
|
|
12
|
+
const text = await Bun.file(path).text().catch(() => undefined);
|
|
13
|
+
if (!text)
|
|
14
|
+
continue;
|
|
15
|
+
return JSON.parse(text);
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
// try next path
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
export async function clearFailedShareViewRestore() {
|
|
24
|
+
for (const path of [
|
|
25
|
+
FAILED_SHARE_VIEW_RESTORE_PATH,
|
|
26
|
+
LEGACY_FAILED_SHARE_VIEW_RESTORE_PATH,
|
|
27
|
+
]) {
|
|
28
|
+
try {
|
|
29
|
+
await Bun.file(path).delete();
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
// missing
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export async function removeWalletAfterShareFail(primary_address) {
|
|
37
|
+
await writeScanSettingsFileDefaultLocation({
|
|
38
|
+
async writeCallback(settings) {
|
|
39
|
+
const matching = settings.wallets.find((w) => w.primary_address === primary_address);
|
|
40
|
+
if (matching) {
|
|
41
|
+
await Bun.file(`${matching.primary_address}_cache.json`)
|
|
42
|
+
.delete()
|
|
43
|
+
.catch(() => { });
|
|
44
|
+
await Bun.file(`${matching.primary_address}_stats.json`)
|
|
45
|
+
.delete()
|
|
46
|
+
.catch(() => { });
|
|
47
|
+
}
|
|
48
|
+
settings.wallets = settings.wallets.filter((w) => w.primary_address !== primary_address);
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
export async function persistFailedShareViewRestore(payload) {
|
|
53
|
+
await atomicWrite(FAILED_SHARE_VIEW_RESTORE_PATH, JSON.stringify(payload, null, 2));
|
|
54
|
+
try {
|
|
55
|
+
await Bun.file(LEGACY_FAILED_SHARE_VIEW_RESTORE_PATH).delete();
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
// missing
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { type PortMessageByKind, type ToolArm } from "../globals";
|
|
2
|
+
export type CreateAndShareViewOnlyWalletTool = {
|
|
3
|
+
tool_id: "002";
|
|
4
|
+
payload: CreateAndShareViewOnlyWalletToolPayload;
|
|
5
|
+
};
|
|
6
|
+
export type CreateAndShareViewOnlyWalletToolPayload = {
|
|
7
|
+
wallet_slot: number;
|
|
8
|
+
};
|
|
9
|
+
export type ShareViewkeyPayload = PortMessageByKind["shareViewkey"];
|
|
10
|
+
export type ShareViewkeyResult = {
|
|
11
|
+
ok: boolean;
|
|
12
|
+
successUrl: string | null;
|
|
13
|
+
error?: string;
|
|
14
|
+
};
|
|
15
|
+
export type ShareViewkey002Pruned = {
|
|
16
|
+
viewkey: string;
|
|
17
|
+
primary_address: string;
|
|
18
|
+
wallet_slot: number;
|
|
19
|
+
};
|
|
20
|
+
/** mco surface used to save view wallet on share success */
|
|
21
|
+
export type ShareViewMco = {
|
|
22
|
+
wallets: {
|
|
23
|
+
primary_address: string;
|
|
24
|
+
wallet_slot?: number;
|
|
25
|
+
wallet_name?: string;
|
|
26
|
+
}[];
|
|
27
|
+
addViewWallet: (primary_address: string, view_key: string, fields?: {
|
|
28
|
+
wallet_name?: string;
|
|
29
|
+
wallet_slot?: number;
|
|
30
|
+
}) => Promise<void>;
|
|
31
|
+
setWalletName: (primary_address: string, name?: string) => Promise<void>;
|
|
32
|
+
setWalletSlot: (primary_address: string, slot?: number) => Promise<void>;
|
|
33
|
+
};
|
|
34
|
+
export type HandleShareOpts = {
|
|
35
|
+
successUrl?: string;
|
|
36
|
+
};
|
|
37
|
+
declare function execute_route(mco: ShareViewMco, opts?: HandleShareOpts): (req: Request) => Promise<Response>;
|
|
38
|
+
export type FailedShareViewRestore = {
|
|
39
|
+
viewkey: string;
|
|
40
|
+
primary_address: string;
|
|
41
|
+
error?: string;
|
|
42
|
+
tool_invo: {
|
|
43
|
+
invocation_id: string;
|
|
44
|
+
context_domain: string;
|
|
45
|
+
context_href: string;
|
|
46
|
+
destination_domain: string;
|
|
47
|
+
found_in: "link" | "linkText";
|
|
48
|
+
link: string;
|
|
49
|
+
linkText: string;
|
|
50
|
+
timestamp: number;
|
|
51
|
+
valid: "valid" | "invalid" | "unverified";
|
|
52
|
+
tool: {
|
|
53
|
+
tool_id: string;
|
|
54
|
+
payload: {
|
|
55
|
+
wallet_slot?: number;
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
type Tool002CounterpartyExtra = {
|
|
61
|
+
execute_route: typeof execute_route;
|
|
62
|
+
};
|
|
63
|
+
declare const tool002: ToolArm<CreateAndShareViewOnlyWalletToolPayload, Tool002CounterpartyExtra>;
|
|
64
|
+
export default tool002;
|