aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--names/server.js4
-rw-r--r--nwcpush/server.js15
-rw-r--r--src/features/messages.js7
3 files changed, 23 insertions, 3 deletions
diff --git a/names/server.js b/names/server.js
index 6588108..971108c 100644
--- a/names/server.js
+++ b/names/server.js
@@ -520,7 +520,9 @@ async function settleLoop() {
if (CFG.push && CFG.push.url && state.names[name]) {
fetch(`${CFG.push.url}/notify`, {
method: 'POST', headers: { 'content-type': 'application/json' },
- body: JSON.stringify({ token: CFG.push.token, pubkey: state.names[name].pubkey, amountSat: sat }),
+ // this registrar's own network, so the notifier delivers only to the
+ // payee's devices on it (a seed makes the same pubkey on both nets)
+ body: JSON.stringify({ token: CFG.push.token, pubkey: state.names[name].pubkey, amountSat: sat, net: CFG.forwarder?.network || 'mainnet' }),
}).catch(() => {});
}
// ...and POST to their webhook, if they registered one
diff --git a/nwcpush/server.js b/nwcpush/server.js
index 7efebb1..61cab60 100644
--- a/nwcpush/server.js
+++ b/nwcpush/server.js
@@ -331,9 +331,18 @@ const server = Bun.serve({
if (!CFG.notifyToken || body?.token !== CFG.notifyToken) return json({ error: 'forbidden' }, 403);
const pk = body?.pubkey;
if (!/^[0-9a-f]{64}$/.test(pk || '')) return json({ error: 'pubkey required' }, 400);
+ // Network scoping: the same pubkey exists on mainnet and staging, so a
+ // payment goes only to devices on its own network. A device that hasn't
+ // re-registered since this shipped has net=null and still gets it (so
+ // no one goes dark mid-rollout); once both sides send a net, mismatches
+ // are filtered. A caller that omits net pushes to everyone (legacy).
+ const wantNet = typeof body.net === 'string' ? body.net : null;
let n = 0;
for (const [id, r] of Object.entries(notifyRegs)) {
- if ((r.ptags || []).includes(pk)) { pushNotify(id, r, 'payment', { amountSat: Number(body.amountSat) || undefined }).catch(() => {}); n++; }
+ if (!(r.ptags || []).includes(pk)) continue;
+ if (wantNet && r.net && r.net !== wantNet) continue;
+ pushNotify(id, r, 'payment', { amountSat: Number(body.amountSat) || undefined }).catch(() => {});
+ n++;
}
return json({ ok: true, devices: n });
}
@@ -367,6 +376,10 @@ const server = Bun.serve({
ptags: hex(body.notify.ptags, 8),
authors: hex(body.notify.authors, 64),
reasons,
+ // the network this device is on: the same seed yields the same
+ // pubkey on mainnet and staging, so a payment push is delivered
+ // only to devices on the payment's network (see /notify)
+ net: typeof body.notify.net === 'string' ? body.notify.net.slice(0, 16) : null,
};
persist();
resubscribeNotify();
diff --git a/src/features/messages.js b/src/features/messages.js
index a370097..582bf3b 100644
--- a/src/features/messages.js
+++ b/src/features/messages.js
@@ -999,7 +999,12 @@ export function messagesFeature(ctx) {
// never sends what the user turned off (a suppressed-but-delivered push
// would earn Chrome's generic "updated in background" nag instead)
const reasons = { payment: s.reasons?.payment !== false, dm: s.reasons?.dm !== false };
- return { ptags: myPubkeys(), authors, reasons };
+ // Stamp the network: the same seed makes the same nostr pubkey on mainnet
+ // AND staging, so without this the notifier fans a mainnet payment push
+ // out to the staging PWA's subscription too — and tapping it opened
+ // staging. The notifier now delivers a payment only to registrations on
+ // the payment's own network.
+ return { ptags: myPubkeys(), authors, reasons, net: getNetwork() };
}
const roomNotify = (cid) => !!st().notify[cid];