@oneaddress/setup 1.3.2 → 1.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +178 -12
- 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.4" : "?";
|
|
860
860
|
function printCompactHeader() {
|
|
861
861
|
const INNER = 42;
|
|
862
862
|
const TOP = fn("\u250C") + dm("\u2500".repeat(INNER)) + fn("\u2510");
|
|
@@ -1426,6 +1426,29 @@ app.post('/webhook', async (req: Request, res: Response) => {
|
|
|
1426
1426
|
return res.status(200).json({ ok: true });
|
|
1427
1427
|
}
|
|
1428
1428
|
|
|
1429
|
+
// \u2500\u2500 address.test / address.test-dispatch: OneAddress connection-verification
|
|
1430
|
+
// A fabricated test record wrapped to your key. Reaching this line proves
|
|
1431
|
+
// PARTNER_PRIVATE_KEY_PEM decrypted it: a wrong key would have failed the D5
|
|
1432
|
+
// decrypt above and returned 422, never here. Answer { verification: true },
|
|
1433
|
+
// which is what the receiver-verification and go-live checks look for. Return
|
|
1434
|
+
// anything else (including the forward-compat skip below) and the check reads
|
|
1435
|
+
// as "answered but could not decrypt", which is not what happened.
|
|
1436
|
+
if (event === 'address.test' || event === 'address.test-dispatch') {
|
|
1437
|
+
const index = typeof body.index === 'number' ? body.index : undefined;
|
|
1438
|
+
// Print the decrypted record as a verification line for the connection-
|
|
1439
|
+
// verification flow. The portal's verify page asks you to copy these lines
|
|
1440
|
+
// (shaped "N | name | address") out of this console and paste them at the
|
|
1441
|
+
// verify URL in your instruction email; decorative lines around them are
|
|
1442
|
+
// ignored, so pasting the whole block is fine. Returning { verification:true }
|
|
1443
|
+
// is what the go-live and receiver-verification decrypt proofs look for.
|
|
1444
|
+
const a = address as { street?: unknown; suburb?: unknown; state?: unknown; postcode?: unknown };
|
|
1445
|
+
const oneLine = [a.street, [a.suburb, a.state, a.postcode].filter(Boolean).join(' ')]
|
|
1446
|
+
.filter(Boolean).join(', ');
|
|
1447
|
+
console.log(\`[webhook] \${event} verification probe decrypted OK\`);
|
|
1448
|
+
console.log(\`[verification] \${index ?? '?'} | \${ctx.name} | \${oneLine}\`);
|
|
1449
|
+
return res.status(200).json({ verification: true, index });
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1429
1452
|
// Unknown event \u2014 acknowledge (forward compatibility)
|
|
1430
1453
|
console.log(\`[webhook] Unknown event "\${event}" \u2014 acknowledged\`);
|
|
1431
1454
|
return res.status(200).json({ ok: true, skipped: true });
|
|
@@ -1892,10 +1915,15 @@ async def webhook(request: Request) -> Response:
|
|
|
1892
1915
|
session_share = body.get("session_key_share")
|
|
1893
1916
|
legacy_enc = body.get("address_encrypted")
|
|
1894
1917
|
|
|
1918
|
+
# Decrypted display name, captured for the connection-verification probe
|
|
1919
|
+
# below. Identity comes ONLY from decryption, never a cleartext wire field.
|
|
1920
|
+
verified_name = ""
|
|
1921
|
+
|
|
1895
1922
|
if isinstance(session_envelope, str) and isinstance(session_share, dict):
|
|
1896
1923
|
try:
|
|
1897
1924
|
data = _decrypt_session(session_share, session_envelope, PRIVATE_KEY, PARTNER_ID)
|
|
1898
1925
|
address = data.get("new_address", {})
|
|
1926
|
+
verified_name = data.get("verified_name", "") or ""
|
|
1899
1927
|
except Exception as e:
|
|
1900
1928
|
print(f"[webhook] D5 decryption failed \u2014 check OA_PRIVATE_KEY_PEM matches key_id "
|
|
1901
1929
|
f"{session_share.get('key_id', '?')}: {e}")
|
|
@@ -1904,6 +1932,7 @@ async def webhook(request: Request) -> Response:
|
|
|
1904
1932
|
elif isinstance(legacy_enc, dict):
|
|
1905
1933
|
try:
|
|
1906
1934
|
address = _decrypt_address(legacy_enc, PRIVATE_KEY, PARTNER_ID)
|
|
1935
|
+
verified_name = address.get("fullName", "") or ""
|
|
1907
1936
|
except Exception as e:
|
|
1908
1937
|
print(f"[webhook] Decryption error (check OA_PRIVATE_KEY_PEM): {e}")
|
|
1909
1938
|
return Response(content='{"ok":false,"error":"decryption failed - partner key mismatch"}',
|
|
@@ -1960,6 +1989,25 @@ async def webhook(request: Request) -> Response:
|
|
|
1960
1989
|
except Exception as e:
|
|
1961
1990
|
print(f"[webhook] Callback POST failed: {e}")
|
|
1962
1991
|
|
|
1992
|
+
elif event in ("address.test", "address.test-dispatch"):
|
|
1993
|
+
# OneAddress connection-verification probe. Reaching here means the D5
|
|
1994
|
+
# decrypt above succeeded (a wrong key returned 422), which is exactly
|
|
1995
|
+
# what the check proves, so answer verification=true. Anything else reads
|
|
1996
|
+
# as "answered but could not decrypt", which is not what happened. We also
|
|
1997
|
+
# print the decrypted record as a "N | name | address" line: the portal's
|
|
1998
|
+
# verify page asks you to copy these lines from this console and paste
|
|
1999
|
+
# them at the verify URL in your instruction email. Decorative lines are
|
|
2000
|
+
# ignored, so pasting the whole block is fine.
|
|
2001
|
+
idx = body.get("index")
|
|
2002
|
+
_locality = " ".join(str(x) for x in [address.get("suburb", ""),
|
|
2003
|
+
address.get("state", ""),
|
|
2004
|
+
address.get("postcode", "")] if x)
|
|
2005
|
+
one_line = ", ".join(str(p) for p in [address.get("street", ""), _locality] if p)
|
|
2006
|
+
print(f"[webhook] {event} verification probe decrypted OK")
|
|
2007
|
+
print(f"[verification] {idx if idx is not None else '?'} | {verified_name} | {one_line}")
|
|
2008
|
+
return Response(content=json.dumps({"verification": True, "index": body.get("index")}),
|
|
2009
|
+
media_type="application/json")
|
|
2010
|
+
|
|
1963
2011
|
else:
|
|
1964
2012
|
print(f"[webhook] Unknown event '{event}' \u2014 acknowledged")
|
|
1965
2013
|
|
|
@@ -2517,6 +2565,26 @@ public class OneAddressWebhookController {
|
|
|
2517
2565
|
} else if ("address.verify".equals(event)) {
|
|
2518
2566
|
handleAddressVerify(body, address, accountNumber, verifiedName, knownNames);
|
|
2519
2567
|
if (dispatchId != null && !dispatchId.isBlank()) store.markProcessed(dispatchId, "verify");
|
|
2568
|
+
} else if ("address.test".equals(event) || "address.test-dispatch".equals(event)) {
|
|
2569
|
+
// OneAddress connection-verification probe. Reaching here means the
|
|
2570
|
+
// D5 decrypt above succeeded (a wrong key returned 422), which is
|
|
2571
|
+
// what the check proves, so answer verification=true. We also print
|
|
2572
|
+
// the decrypted record as a "N | name | address" line: the portal's
|
|
2573
|
+
// verify page asks you to copy these lines from this console and
|
|
2574
|
+
// paste them at the verify URL in your instruction email.
|
|
2575
|
+
if (dispatchId != null && !dispatchId.isBlank()) store.markProcessed(dispatchId, "verification:ok");
|
|
2576
|
+
Object idx = body.get("index");
|
|
2577
|
+
java.util.function.Function<String, String> fld = k -> {
|
|
2578
|
+
Object v = address.get(k);
|
|
2579
|
+
return v == null ? "" : String.valueOf(v);
|
|
2580
|
+
};
|
|
2581
|
+
String oaLoc = java.util.stream.Stream.of(fld.apply("suburb"), fld.apply("state"), fld.apply("postcode"))
|
|
2582
|
+
.filter(s -> !s.isBlank()).collect(java.util.stream.Collectors.joining(" "));
|
|
2583
|
+
String oaLine = java.util.stream.Stream.of(fld.apply("street"), oaLoc)
|
|
2584
|
+
.filter(s -> !s.isBlank()).collect(java.util.stream.Collectors.joining(", "));
|
|
2585
|
+
log.info("[OneAddress] {} verification probe decrypted OK", event);
|
|
2586
|
+
log.info("[verification] {} | {} | {}", idx == null ? "?" : idx, verifiedName, oaLine);
|
|
2587
|
+
return ResponseEntity.ok("{\\"verification\\":true,\\"index\\":" + (idx == null ? "null" : idx.toString()) + "}");
|
|
2520
2588
|
} else {
|
|
2521
2589
|
log.info("[OneAddress] skipping unknown event: {}", event);
|
|
2522
2590
|
if (dispatchId != null && !dispatchId.isBlank()) store.markProcessed(dispatchId, "ignored:unknown-event");
|
|
@@ -3285,7 +3353,11 @@ app.MapPost("/webhooks/oneaddress", async (HttpRequest request) =>
|
|
|
3285
3353
|
|
|
3286
3354
|
var eventType = body.TryGetProperty("event", out var evtEl) ? evtEl.GetString() : null;
|
|
3287
3355
|
|
|
3288
|
-
|
|
3356
|
+
// address.test / address.test-dispatch (the connection-verification probe)
|
|
3357
|
+
// must pass this guard so it reaches the decrypt below; a wrong key then
|
|
3358
|
+
// returns 422 and only a real decrypt reaches the verification answer.
|
|
3359
|
+
if (eventType != "address.updated" && eventType != "address.verify"
|
|
3360
|
+
&& eventType != "address.test" && eventType != "address.test-dispatch")
|
|
3289
3361
|
{
|
|
3290
3362
|
app.Logger.LogInformation("[OneAddress] skipping unknown event: {EventType}", eventType);
|
|
3291
3363
|
return Results.Json(new { ok = true, skipped = true });
|
|
@@ -3366,6 +3438,27 @@ app.MapPost("/webhooks/oneaddress", async (HttpRequest request) =>
|
|
|
3366
3438
|
app.Logger.LogWarning("[OneAddress] dispatch {DispatchId} received before but never completed \u2014 reprocessing", dispatchId);
|
|
3367
3439
|
}
|
|
3368
3440
|
|
|
3441
|
+
if (eventType == "address.test" || eventType == "address.test-dispatch")
|
|
3442
|
+
{
|
|
3443
|
+
// OneAddress connection-verification probe. Reaching here means the D5
|
|
3444
|
+
// decrypt above succeeded (a wrong key returned 422), which is what the
|
|
3445
|
+
// check proves, so answer verification=true. We also print the decrypted
|
|
3446
|
+
// record as a "N | name | address" line: the portal's verify page asks
|
|
3447
|
+
// you to copy these lines from this console and paste them at the verify
|
|
3448
|
+
// URL in your instruction email.
|
|
3449
|
+
int? index = body.TryGetProperty("index", out var idxEl) && idxEl.ValueKind == JsonValueKind.Number
|
|
3450
|
+
? idxEl.GetInt32() : (int?)null;
|
|
3451
|
+
static string OaStr(JsonElement a, string k) =>
|
|
3452
|
+
a.TryGetProperty(k, out var el) && el.ValueKind == JsonValueKind.String ? (el.GetString() ?? "") : "";
|
|
3453
|
+
var oaLoc = string.Join(" ", new[] { OaStr(address, "suburb"), OaStr(address, "state"), OaStr(address, "postcode") }
|
|
3454
|
+
.Where(s => !string.IsNullOrWhiteSpace(s)));
|
|
3455
|
+
var oaLine = string.Join(", ", new[] { OaStr(address, "street"), oaLoc }
|
|
3456
|
+
.Where(s => !string.IsNullOrWhiteSpace(s)));
|
|
3457
|
+
app.Logger.LogInformation("[OneAddress] {EventType} verification probe decrypted OK", eventType);
|
|
3458
|
+
app.Logger.LogInformation("[verification] {Line}", (index?.ToString() ?? "?") + " | " + verifiedName + " | " + oaLine);
|
|
3459
|
+
return Results.Json(new { verification = true, index });
|
|
3460
|
+
}
|
|
3461
|
+
|
|
3369
3462
|
if (eventType == "address.updated")
|
|
3370
3463
|
{
|
|
3371
3464
|
// Work FIRST, respond after. Acknowledging before the write commits
|
|
@@ -4203,6 +4296,41 @@ func main() {
|
|
|
4203
4296
|
_ = store.MarkProcessed(dispatch, "verify:"+result)
|
|
4204
4297
|
}
|
|
4205
4298
|
|
|
4299
|
+
case "address.test", "address.test-dispatch":
|
|
4300
|
+
// OneAddress connection-verification probe. Reaching this case means the
|
|
4301
|
+
// decrypt above succeeded (a wrong key returned 422), which is what the
|
|
4302
|
+
// check proves, so answer verification=true rather than the ok:true below.
|
|
4303
|
+
// We also print the decrypted record as a "N | name | address" line: the
|
|
4304
|
+
// portal's verify page asks you to copy these lines from this console and
|
|
4305
|
+
// paste them at the verify URL in your instruction email.
|
|
4306
|
+
log.Printf("[webhook] %s verification probe decrypted OK", event)
|
|
4307
|
+
if dispatch != "" {
|
|
4308
|
+
_ = store.MarkProcessed(dispatch, "verification:ok")
|
|
4309
|
+
}
|
|
4310
|
+
var idx any = nil
|
|
4311
|
+
if v, ok := parsed["index"]; ok {
|
|
4312
|
+
idx = v
|
|
4313
|
+
}
|
|
4314
|
+
var locParts []string
|
|
4315
|
+
for _, s := range []string{str(address, "suburb"), str(address, "state"), str(address, "postcode")} {
|
|
4316
|
+
if s != "" {
|
|
4317
|
+
locParts = append(locParts, s)
|
|
4318
|
+
}
|
|
4319
|
+
}
|
|
4320
|
+
var lineParts []string
|
|
4321
|
+
for _, s := range []string{str(address, "street"), strings.Join(locParts, " ")} {
|
|
4322
|
+
if s != "" {
|
|
4323
|
+
lineParts = append(lineParts, s)
|
|
4324
|
+
}
|
|
4325
|
+
}
|
|
4326
|
+
idxStr := "?"
|
|
4327
|
+
if idx != nil {
|
|
4328
|
+
idxStr = fmt.Sprintf("%v", idx)
|
|
4329
|
+
}
|
|
4330
|
+
log.Printf("[verification] %s | %s | %s", idxStr, verifiedName, strings.Join(lineParts, ", "))
|
|
4331
|
+
jsonResp(w, 200, map[string]any{"verification": true, "index": idx})
|
|
4332
|
+
return
|
|
4333
|
+
|
|
4206
4334
|
default:
|
|
4207
4335
|
log.Printf("[webhook] Unknown event %q \u2014 acknowledged", event)
|
|
4208
4336
|
if dispatch != "" {
|
|
@@ -4869,7 +4997,11 @@ Route::post('/webhook', function (Request $request): Response {
|
|
|
4869
4997
|
|
|
4870
4998
|
$eventType = $body['event'] ?? '';
|
|
4871
4999
|
|
|
4872
|
-
|
|
5000
|
+
// address.test / address.test-dispatch (the connection-verification probe)
|
|
5001
|
+
// must pass this guard so it reaches the decrypt below; a wrong key then
|
|
5002
|
+
// returns 422 and only a real decrypt reaches the verification answer.
|
|
5003
|
+
if ($eventType !== 'address.updated' && $eventType !== 'address.verify'
|
|
5004
|
+
&& $eventType !== 'address.test' && $eventType !== 'address.test-dispatch') {
|
|
4873
5005
|
return response()->json(['ok' => true, 'skipped' => true]);
|
|
4874
5006
|
}
|
|
4875
5007
|
|
|
@@ -5038,6 +5170,22 @@ Route::post('/webhook', function (Request $request): Response {
|
|
|
5038
5170
|
}
|
|
5039
5171
|
}
|
|
5040
5172
|
|
|
5173
|
+
if ($eventType === 'address.test' || $eventType === 'address.test-dispatch') {
|
|
5174
|
+
// OneAddress connection-verification probe. Reaching here means the D5
|
|
5175
|
+
// decrypt above succeeded (a wrong key returned 422), which is what the
|
|
5176
|
+
// check proves, so answer verification=true. We also print the decrypted
|
|
5177
|
+
// record as a "N | name | address" line: the portal's verify page asks
|
|
5178
|
+
// you to copy these lines from this console and paste them at the verify
|
|
5179
|
+
// URL in your instruction email.
|
|
5180
|
+
$oaAddr = is_array($address) ? $address : [];
|
|
5181
|
+
$oaKeep = static fn($s) => $s !== null && $s !== '';
|
|
5182
|
+
$oaLoc = implode(' ', array_filter([$oaAddr['suburb'] ?? '', $oaAddr['state'] ?? '', $oaAddr['postcode'] ?? ''], $oaKeep));
|
|
5183
|
+
$oaLine = implode(', ', array_filter([$oaAddr['street'] ?? '', $oaLoc], $oaKeep));
|
|
5184
|
+
\\Log::info('[OneAddress] verification probe decrypted OK', ['event' => $eventType]);
|
|
5185
|
+
\\Log::info('[verification] ' . ($body['index'] ?? '?') . ' | ' . $verifiedName . ' | ' . $oaLine);
|
|
5186
|
+
return response()->json(['verification' => true, 'index' => $body['index'] ?? null]);
|
|
5187
|
+
}
|
|
5188
|
+
|
|
5041
5189
|
if ($eventType === 'address.updated') {
|
|
5042
5190
|
// Work FIRST, respond after. Acknowledging before the write commits
|
|
5043
5191
|
// marks the dispatch delivered on a failure that is never retried.
|
|
@@ -5224,7 +5372,7 @@ async function scaffold(platform, outputDir, partnerId, webhookSecret, webhookUr
|
|
|
5224
5372
|
|
|
5225
5373
|
// src/register.ts
|
|
5226
5374
|
var import_node_crypto = require("crypto");
|
|
5227
|
-
var PKG_VERSION = true ? "1.3.
|
|
5375
|
+
var PKG_VERSION = true ? "1.3.4" : "dev";
|
|
5228
5376
|
var REGISTER_URL = "https://partners.oneaddress.io/api/partner/installs";
|
|
5229
5377
|
function hmacSha256(secret, message) {
|
|
5230
5378
|
return (0, import_node_crypto.createHmac)("sha256", secret).update(message).digest("hex");
|
|
@@ -6284,21 +6432,36 @@ Continuing will overwrite it.`
|
|
|
6284
6432
|
s4.start("Starting Cloudflare Tunnel");
|
|
6285
6433
|
onCleanup(stopTunnel);
|
|
6286
6434
|
try {
|
|
6287
|
-
|
|
6435
|
+
let tunnel = await startTunnel(3001);
|
|
6288
6436
|
webhookUrl = `${tunnel.url}/webhook`;
|
|
6289
6437
|
tunnelBase = tunnel.url;
|
|
6290
6438
|
s4.stop(`Tunnel active: ${tunnel.url}`);
|
|
6291
6439
|
M2.warn(
|
|
6292
|
-
"IMPORTANT: This tunnel URL is temporary
|
|
6440
|
+
"IMPORTANT: This tunnel URL is temporary. It lives only while this wizard\nkeeps running, and every run gets a new address. Before going to production,\ndeploy to a permanent server and update the webhook URL in the portal."
|
|
6293
6441
|
);
|
|
6294
6442
|
const s4b = Y2();
|
|
6295
6443
|
s4b.start("Waiting for the tunnel to start routing");
|
|
6296
|
-
|
|
6297
|
-
webhookReady
|
|
6298
|
-
|
|
6299
|
-
|
|
6444
|
+
webhookReady = await waitForTunnelReady(tunnel.url);
|
|
6445
|
+
if (!webhookReady) {
|
|
6446
|
+
s4b.stop("First tunnel is slow to route, trying a fresh one");
|
|
6447
|
+
stopTunnel();
|
|
6448
|
+
tunnel = await startTunnel(3001);
|
|
6449
|
+
webhookUrl = `${tunnel.url}/webhook`;
|
|
6450
|
+
tunnelBase = tunnel.url;
|
|
6451
|
+
const s4c = Y2();
|
|
6452
|
+
s4c.start(`Waiting for the new tunnel to route: ${tunnel.url}`);
|
|
6453
|
+
webhookReady = await waitForTunnelReady(tunnel.url, { budgetMs: 45e3 });
|
|
6454
|
+
s4c.stop(webhookReady ? "Tunnel is routing" : "Tunnel still not routing");
|
|
6455
|
+
} else {
|
|
6456
|
+
s4b.stop("Tunnel is routing");
|
|
6457
|
+
}
|
|
6458
|
+
if (!webhookReady) {
|
|
6300
6459
|
M2.warn(
|
|
6301
|
-
|
|
6460
|
+
`The tunnel edge is still not routing after a retry. This is almost always
|
|
6461
|
+
one of two things, and neither is your server (it is running on :3001):
|
|
6462
|
+
1. Open ${tunnel.url}/health in a browser. If it never loads, your network
|
|
6463
|
+
is blocking cloudflared and no wait will fix it, so try a different network.
|
|
6464
|
+
2. The tunnel only lives while this wizard runs, so keep this window open.`
|
|
6302
6465
|
);
|
|
6303
6466
|
}
|
|
6304
6467
|
} catch (err) {
|
|
@@ -6341,7 +6504,10 @@ Continuing will overwrite it.`
|
|
|
6341
6504
|
}
|
|
6342
6505
|
if (!webhookReady) {
|
|
6343
6506
|
M2.warn(
|
|
6344
|
-
|
|
6507
|
+
`Skipping the conformance checks: the tunnel edge is not routing.
|
|
6508
|
+
Your server is fine, it is running on :3001. This is either your network
|
|
6509
|
+
blocking cloudflared (open ${tunnelBase}/health in a browser to check) or the
|
|
6510
|
+
tunnel needing this wizard to stay open. Re-run once that URL loads in a browser.`
|
|
6345
6511
|
);
|
|
6346
6512
|
} else {
|
|
6347
6513
|
M2.info("");
|