@oneaddress/setup 1.1.9 → 1.2.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.
Files changed (3) hide show
  1. package/README.md +2 -2
  2. package/dist/index.js +43 -17
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -48,8 +48,8 @@ From the [Partner Portal](https://partners.oneaddress.io) → My Profile → Int
48
48
  ## Documentation
49
49
 
50
50
  - [Partner Portal](https://partners.oneaddress.io)
51
- - [Protocol Specification](https://github.com/oneaddress-io/oneaddress-app/blob/main/docs/integration/SPEC.md)
52
- - [Service Level Objectives](https://github.com/oneaddress-io/oneaddress-app/blob/main/docs/integration/SLOS.md)
51
+ - [Protocol Specification](https://github.com/oneaddress-io/oneaddress-app/blob/main/docs/integrations/SPEC.md)
52
+ - [Service Level Objectives](https://github.com/oneaddress-io/oneaddress-app/blob/main/docs/integrations/SLOS.md)
53
53
 
54
54
  ## Issues
55
55
 
package/dist/index.js CHANGED
@@ -835,7 +835,7 @@ var _R = ["\u2588\u2588\u2588\u2588\u2588\u2588 ", "\u2588\u2588 \u2588\u2588"
835
835
  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 "];
836
836
  var ONE_ROWS = Array.from({ length: 7 }, (_2, i) => [_O[i], _N[i], _E[i]].join(" "));
837
837
  var ADDR_ROWS = Array.from({ length: 7 }, (_2, i) => [_A[i], _D2[i], _D2[i], _R[i], _E[i], _S[i], _S[i]].join(" "));
838
- var WIZARD_VERSION = true ? "1.1.9" : "?";
838
+ var WIZARD_VERSION = true ? "1.2.0" : "?";
839
839
  function printHeader() {
840
840
  const BAR_LEN = 85;
841
841
  const TOP_BAR = fn("\u250C") + dm("\u2500".repeat(BAR_LEN)) + fn("\u2510");
@@ -860,7 +860,7 @@ function printHeader() {
860
860
  console.log("");
861
861
  }
862
862
  function stripAnsi(s) {
863
- return s.replace(/\x1b\[[0-9;]*m/g, "");
863
+ return s.replaceAll(/\x1b\[[0-9;]*m/g, "");
864
864
  }
865
865
 
866
866
  // src/scaffold.ts
@@ -1091,7 +1091,13 @@ if (nodeMajor < 22 || (nodeMajor === 22 && nodeMinor < 5)) {
1091
1091
 
1092
1092
  import 'dotenv/config';
1093
1093
  import express, { Request, Response } from 'express';
1094
- import { verifySignature, decryptAddress, isFreshTimestamp } from '@oneaddress/partner-sdk';
1094
+ import {
1095
+ verifySignature,
1096
+ decryptAddress,
1097
+ decryptSession,
1098
+ isFreshTimestamp,
1099
+ type SessionKeyShare,
1100
+ } from '@oneaddress/partner-sdk';
1095
1101
  import { saveAddress, verifyAddress } from './store.js';
1096
1102
 
1097
1103
  const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET ?? '';
@@ -1137,23 +1143,43 @@ app.post('/webhook', async (req: Request, res: Response) => {
1137
1143
  }
1138
1144
  if (dispatch) seenDispatches.add(dispatch);
1139
1145
 
1140
- // 5. Decrypt address payload
1141
- const encPayload = body.address_encrypted as {
1146
+ // 5. Decrypt address payload. Two shapes possible:
1147
+ // (a) D5 (new, 2026+): body.session_envelope + body.session_key_share.
1148
+ // (b) Legacy: body.address_encrypted.
1149
+ // A webhook will carry exactly one shape. If you've registered multiple
1150
+ // versioned keys (D5 supports key rotation with 90-day overlap), look up
1151
+ // the right private key by session_key_share.key_id from your key store.
1152
+ // This scaffold uses a single PARTNER_PRIVATE_KEY_PEM for simplicity \u2014
1153
+ // production deployments should hold a Map<key_id, privateKeyPem>.
1154
+ let address: Record<string, unknown>;
1155
+
1156
+ const sessionEnvelope = typeof body.session_envelope === 'string' ? body.session_envelope : null;
1157
+ const sessionKeyShare = body.session_key_share as SessionKeyShare | undefined;
1158
+ const legacyPayload = body.address_encrypted as {
1142
1159
  ephemeralPublicKey: string; iv: string; ciphertext: string; hkdfSalt?: string;
1143
1160
  } | null;
1144
1161
 
1145
- if (!encPayload) {
1162
+ if (sessionEnvelope && sessionKeyShare) {
1163
+ // D5 \u2014 call decryptSession. Wrong key_id / wrong partner_id / tampered
1164
+ // ciphertext all surface as an AES-GCM authentication-tag error.
1165
+ try {
1166
+ const data = await decryptSession(sessionKeyShare, sessionEnvelope, PARTNER_PRIVATE_KEY, PARTNER_ID);
1167
+ address = data.new_address as unknown as Record<string, unknown>;
1168
+ } catch (err) {
1169
+ console.error('[webhook] D5 decryption failed \u2014 check PARTNER_PRIVATE_KEY_PEM matches key_id', sessionKeyShare.key_id, ':', err);
1170
+ return res.status(200).json({ ok: true, note: 'Received \u2014 D5 decryption pending key setup' });
1171
+ }
1172
+ } else if (legacyPayload) {
1173
+ try {
1174
+ address = await decryptAddress(legacyPayload, PARTNER_PRIVATE_KEY, PARTNER_ID);
1175
+ } catch (err) {
1176
+ console.error('[webhook] Decryption failed \u2014 check PARTNER_PRIVATE_KEY_PEM in .env:', err);
1177
+ return res.status(200).json({ ok: true, note: 'Received \u2014 decryption pending key setup' });
1178
+ }
1179
+ } else {
1146
1180
  return res.status(200).json({ ok: true, note: 'No encrypted payload' });
1147
1181
  }
1148
1182
 
1149
- let address: Record<string, unknown>;
1150
- try {
1151
- address = await decryptAddress(encPayload, PARTNER_PRIVATE_KEY, PARTNER_ID);
1152
- } catch (err) {
1153
- console.error('[webhook] Decryption failed \u2014 check PARTNER_PRIVATE_KEY_PEM in .env:', err);
1154
- return res.status(200).json({ ok: true, note: 'Received \u2014 decryption pending key setup' });
1155
- }
1156
-
1157
1183
  const event = body.event as string;
1158
1184
  const customer = body.customer as { email?: string; name?: string } | undefined;
1159
1185
  const ctx = { email: customer?.email ?? '', name: customer?.name ?? '' };
@@ -3393,7 +3419,7 @@ function normalisePrivateKey(raw) {
3393
3419
  if (!(0, import_node_fs4.existsSync)(abs)) return { pem: "", error: `File not found: ${abs}` };
3394
3420
  return normalisePrivateKey((0, import_node_fs4.readFileSync)(abs, "utf8"));
3395
3421
  }
3396
- const unescaped = trimmed.replace(/\\n/g, "\n");
3422
+ const unescaped = trimmed.replaceAll(/\\n/g, "\n");
3397
3423
  if (unescaped.includes("-----BEGIN PRIVATE KEY-----")) {
3398
3424
  return { pem: unescaped };
3399
3425
  }
@@ -3413,7 +3439,7 @@ function normalisePrivateKey(raw) {
3413
3439
  if (b64Lines.length === 0) return { pem: "", error: "Could not extract key body from the OneAddress PEM file" };
3414
3440
  return wrapAsPkcs8(b64Lines.join(""));
3415
3441
  }
3416
- const b64clean = trimmed.replace(/\s+/g, "");
3442
+ const b64clean = trimmed.replaceAll(/\s+/g, "");
3417
3443
  if (/^[A-Za-z0-9+/]+=*$/.test(b64clean) && b64clean.length >= 50) {
3418
3444
  return wrapAsPkcs8(b64clean);
3419
3445
  }
@@ -3650,7 +3676,7 @@ Continuing will overwrite it.`
3650
3676
  `Files in: ${outDir}`
3651
3677
  ].join("\n");
3652
3678
  const nextSteps = [
3653
- "1. Trigger a live event: update your address at app.oneaddress.io\n \u2192 src/store.ts will save it to data.db automatically",
3679
+ "1. Trigger a live event: update your address at oneaddress.io\n \u2192 src/store.ts will save it to data.db automatically",
3654
3680
  "2. View your database: open data.db with DB Browser for SQLite\n (free download at sqlitebrowser.org)",
3655
3681
  "3. For production: swap src/store.ts for your real database (Postgres, MySQL, etc.)\n then deploy and update the webhook URL in the portal",
3656
3682
  "4. Questions? partners.oneaddress.io or partners@oneaddress.io"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oneaddress/setup",
3
- "version": "1.1.9",
3
+ "version": "1.2.0",
4
4
  "description": "Interactive setup wizard for OneAddress partner webhook integrations",
5
5
  "main": "dist/index.js",
6
6
  "bin": {