@oneaddress/setup 1.3.1 → 1.3.2
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/index.js +85 -22
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -856,7 +856,7 @@ var _R = ["\u2588\u2588\u2588\u2588\u2588\u2588 ", "\u2588\u2588 \u2588\u2588"
|
|
|
856
856
|
var _S = [" \u2588\u2588\u2588\u2588\u2588\u2588", "\u2588\u2588 ", "\u2588\u2588 ", " \u2588\u2588\u2588\u2588\u2588 ", " \u2588\u2588", " \u2588\u2588", "\u2588\u2588\u2588\u2588\u2588\u2588 "];
|
|
857
857
|
var ONE_ROWS = Array.from({ length: 7 }, (_3, i) => [_O[i], _N[i], _E[i]].join(" "));
|
|
858
858
|
var ADDR_ROWS = Array.from({ length: 7 }, (_3, i) => [_A[i], _D2[i], _D2[i], _R[i], _E[i], _S[i], _S[i]].join(" "));
|
|
859
|
-
var WIZARD_VERSION = true ? "1.3.
|
|
859
|
+
var WIZARD_VERSION = true ? "1.3.2" : "?";
|
|
860
860
|
function printCompactHeader() {
|
|
861
861
|
const INNER = 42;
|
|
862
862
|
const TOP = fn("\u250C") + dm("\u2500".repeat(INNER)) + fn("\u2510");
|
|
@@ -5224,7 +5224,7 @@ async function scaffold(platform, outputDir, partnerId, webhookSecret, webhookUr
|
|
|
5224
5224
|
|
|
5225
5225
|
// src/register.ts
|
|
5226
5226
|
var import_node_crypto = require("crypto");
|
|
5227
|
-
var PKG_VERSION = true ? "1.3.
|
|
5227
|
+
var PKG_VERSION = true ? "1.3.2" : "dev";
|
|
5228
5228
|
var REGISTER_URL = "https://partners.oneaddress.io/api/partner/installs";
|
|
5229
5229
|
function hmacSha256(secret, message) {
|
|
5230
5230
|
return (0, import_node_crypto.createHmac)("sha256", secret).update(message).digest("hex");
|
|
@@ -5648,7 +5648,7 @@ async function resolveBinary() {
|
|
|
5648
5648
|
return downloadCloudflared();
|
|
5649
5649
|
}
|
|
5650
5650
|
async function waitForTunnelReady(url, opts = {}) {
|
|
5651
|
-
const budgetMs = opts.budgetMs ??
|
|
5651
|
+
const budgetMs = opts.budgetMs ?? 6e4;
|
|
5652
5652
|
const intervalMs = opts.intervalMs ?? 1500;
|
|
5653
5653
|
const attemptTimeoutMs = opts.attemptTimeoutMs ?? 4e3;
|
|
5654
5654
|
const doFetch = opts.fetchImpl ?? fetch;
|
|
@@ -5766,6 +5766,26 @@ async function getVerifiesAccountReference(partnerId, webhookSecret, onError) {
|
|
|
5766
5766
|
return void 0;
|
|
5767
5767
|
}
|
|
5768
5768
|
}
|
|
5769
|
+
async function verifyWebhookSecret(partnerId, webhookSecret) {
|
|
5770
|
+
try {
|
|
5771
|
+
const ts = String(Math.floor(Date.now() / 1e3));
|
|
5772
|
+
const sig = (0, import_node_crypto4.createHmac)("sha256", webhookSecret).update(`${ts}.`).digest("hex");
|
|
5773
|
+
const res = await fetch(PORTAL_API, {
|
|
5774
|
+
method: "GET",
|
|
5775
|
+
headers: {
|
|
5776
|
+
"X-OneAddress-Timestamp": ts,
|
|
5777
|
+
"X-OneAddress-Signature": sig,
|
|
5778
|
+
"X-OneAddress-Partner": partnerId
|
|
5779
|
+
},
|
|
5780
|
+
signal: AbortSignal.timeout(8e3)
|
|
5781
|
+
});
|
|
5782
|
+
if (res.ok) return "ok";
|
|
5783
|
+
if (res.status === 401 || res.status === 403) return "bad_secret";
|
|
5784
|
+
return "unreachable";
|
|
5785
|
+
} catch {
|
|
5786
|
+
return "unreachable";
|
|
5787
|
+
}
|
|
5788
|
+
}
|
|
5769
5789
|
async function registerWebhookUrl(partnerId, webhookSecret, webhookUrl) {
|
|
5770
5790
|
try {
|
|
5771
5791
|
const body = JSON.stringify({ webhook_url: webhookUrl });
|
|
@@ -6033,14 +6053,42 @@ async function main() {
|
|
|
6033
6053
|
M2.info(" 2. Scaffold a working webhook server for your platform");
|
|
6034
6054
|
M2.info(" 3. Get it live with a passing conformance check \u2014 in under 5 minutes");
|
|
6035
6055
|
M2.info("\nOpen partners.oneaddress.io \u2192 My Profile to find the two values below.\n");
|
|
6036
|
-
|
|
6037
|
-
|
|
6038
|
-
|
|
6039
|
-
|
|
6040
|
-
|
|
6056
|
+
let secret;
|
|
6057
|
+
for (let attempt = 1; ; attempt++) {
|
|
6058
|
+
const webhookSecret = await ge({
|
|
6059
|
+
message: attempt === 1 ? "Your Webhook signing secret (min 20 chars)" : `Your Webhook signing secret (attempt ${attempt})`,
|
|
6060
|
+
validate: (v2) => {
|
|
6061
|
+
if (!v2.trim()) return "Webhook signing secret is required";
|
|
6062
|
+
if (v2.length < 20) return "That looks too short \u2014 paste the full secret from My Profile";
|
|
6063
|
+
}
|
|
6064
|
+
});
|
|
6065
|
+
assertNotCancelled(webhookSecret);
|
|
6066
|
+
secret = webhookSecret.trim();
|
|
6067
|
+
const sv = Y2();
|
|
6068
|
+
sv.start("Checking your Webhook signing secret");
|
|
6069
|
+
const check = await verifyWebhookSecret(pid, secret);
|
|
6070
|
+
if (check === "ok") {
|
|
6071
|
+
sv.stop("Webhook signing secret verified");
|
|
6072
|
+
break;
|
|
6041
6073
|
}
|
|
6042
|
-
|
|
6043
|
-
|
|
6074
|
+
if (check === "unreachable") {
|
|
6075
|
+
sv.stop("Could not verify the secret against the portal, continuing");
|
|
6076
|
+
M2.warn(
|
|
6077
|
+
"Could not reach the portal to check your Webhook signing secret. Continuing.\nIf live dispatches later fail signature verification, re-check it at\npartners.oneaddress.io -> Webhook -> Webhook signing secret."
|
|
6078
|
+
);
|
|
6079
|
+
break;
|
|
6080
|
+
}
|
|
6081
|
+
sv.stop("That Webhook signing secret was rejected");
|
|
6082
|
+
if (attempt >= 3) {
|
|
6083
|
+
xe(
|
|
6084
|
+
"The Webhook signing secret did not match after three tries.\nRegenerate it at partners.oneaddress.io -> Webhook -> Webhook signing secret\n(use Revoke and regenerate, not Rotate), then run the wizard again."
|
|
6085
|
+
);
|
|
6086
|
+
process.exit(1);
|
|
6087
|
+
}
|
|
6088
|
+
M2.error(
|
|
6089
|
+
"The portal rejected that secret (HTTP 401): it does not match the one on your profile.\nRegenerate it at partners.oneaddress.io -> Webhook -> Webhook signing secret\n(use Revoke and regenerate, not Rotate), copy the value shown once, and paste it here."
|
|
6090
|
+
);
|
|
6091
|
+
}
|
|
6044
6092
|
const privateKeyRaw = await he({
|
|
6045
6093
|
message: "Your ECDH Private Key",
|
|
6046
6094
|
placeholder: "Paste the base64 key body from My Profile, or enter a path to the .pem file",
|
|
@@ -6052,7 +6100,6 @@ async function main() {
|
|
|
6052
6100
|
}
|
|
6053
6101
|
});
|
|
6054
6102
|
assertNotCancelled(privateKeyRaw);
|
|
6055
|
-
const secret = webhookSecret.trim();
|
|
6056
6103
|
const normalised = normalisePrivateKey(privateKeyRaw.trim());
|
|
6057
6104
|
if (normalised.error) {
|
|
6058
6105
|
xe(`Private key parse failed unexpectedly: ${normalised.error}`);
|
|
@@ -6177,6 +6224,8 @@ async function main() {
|
|
|
6177
6224
|
if (start.output) M2.warn(start.output.slice(0, 600));
|
|
6178
6225
|
}
|
|
6179
6226
|
let webhookUrl = "";
|
|
6227
|
+
let webhookReady = true;
|
|
6228
|
+
let tunnelBase = null;
|
|
6180
6229
|
let existingUrlReason = "";
|
|
6181
6230
|
const existingUrlResult = await getExistingWebhookUrl(pid, secret, (r2) => {
|
|
6182
6231
|
existingUrlReason = r2;
|
|
@@ -6237,6 +6286,7 @@ Continuing will overwrite it.`
|
|
|
6237
6286
|
try {
|
|
6238
6287
|
const tunnel = await startTunnel(3001);
|
|
6239
6288
|
webhookUrl = `${tunnel.url}/webhook`;
|
|
6289
|
+
tunnelBase = tunnel.url;
|
|
6240
6290
|
s4.stop(`Tunnel active: ${tunnel.url}`);
|
|
6241
6291
|
M2.warn(
|
|
6242
6292
|
"IMPORTANT: This tunnel URL is temporary \u2014 it expires when this process stops.\nBefore going to production, deploy to a permanent server and update the webhook URL in the portal."
|
|
@@ -6244,10 +6294,11 @@ Continuing will overwrite it.`
|
|
|
6244
6294
|
const s4b = Y2();
|
|
6245
6295
|
s4b.start("Waiting for the tunnel to start routing");
|
|
6246
6296
|
const ready = await waitForTunnelReady(tunnel.url);
|
|
6247
|
-
|
|
6297
|
+
webhookReady = ready;
|
|
6298
|
+
s4b.stop(ready ? "Tunnel is routing" : "Tunnel is slow to come online");
|
|
6248
6299
|
if (!ready) {
|
|
6249
6300
|
M2.warn(
|
|
6250
|
-
"The tunnel edge has not answered yet.
|
|
6301
|
+
"The tunnel edge has not answered yet. This is a Cloudflare warmup delay,\nnot your server, which is running on :3001. The wizard will wait once more\nbefore the conformance checks so a cold tunnel does not read as a failure."
|
|
6251
6302
|
);
|
|
6252
6303
|
}
|
|
6253
6304
|
} catch (err) {
|
|
@@ -6282,16 +6333,28 @@ Continuing will overwrite it.`
|
|
|
6282
6333
|
});
|
|
6283
6334
|
}
|
|
6284
6335
|
if (webhookUrl) {
|
|
6285
|
-
|
|
6286
|
-
|
|
6287
|
-
|
|
6288
|
-
|
|
6289
|
-
|
|
6290
|
-
|
|
6291
|
-
if (
|
|
6292
|
-
M2.
|
|
6293
|
-
"
|
|
6336
|
+
if (!webhookReady && tunnelBase) {
|
|
6337
|
+
const sr = Y2();
|
|
6338
|
+
sr.start("Waiting for the tunnel to start routing");
|
|
6339
|
+
webhookReady = await waitForTunnelReady(tunnelBase, { budgetMs: 2e4 });
|
|
6340
|
+
sr.stop(webhookReady ? "Tunnel is routing" : "Tunnel still not routing");
|
|
6341
|
+
}
|
|
6342
|
+
if (!webhookReady) {
|
|
6343
|
+
M2.warn(
|
|
6344
|
+
"Skipping the conformance checks: the Cloudflare tunnel edge has not come online.\nThis is a tunnel warmup delay, not your server, which is running on :3001.\nRe-run the wizard, or run `npm test` once the tunnel URL responds in a browser."
|
|
6294
6345
|
);
|
|
6346
|
+
} else {
|
|
6347
|
+
M2.info("");
|
|
6348
|
+
const s6 = Y2();
|
|
6349
|
+
s6.start("Running conformance checks");
|
|
6350
|
+
await new Promise((r2) => setTimeout(r2, 200));
|
|
6351
|
+
s6.stop("Conformance checks:");
|
|
6352
|
+
await runConformance(webhookUrl, pid, secret);
|
|
6353
|
+
if (verifiesAccountReference) {
|
|
6354
|
+
M2.info(
|
|
6355
|
+
"You have declared that your receiver matches the account reference itself.\nRun `npm test` to include check-14, which sends an account reference that matches\nnothing and fails a receiver that reports it as applied. The three checks above\ncover signing and replay only."
|
|
6356
|
+
);
|
|
6357
|
+
}
|
|
6295
6358
|
}
|
|
6296
6359
|
}
|
|
6297
6360
|
const summary = [
|