Use the account's stored sponsor at buy time, not just the cookie
/api/sponsor (which the buy flow reads to set sponsorIdIfNew) resolved ONLY the iap.sponsor cookie. A member whose join cookie was absent at buy time (different device, cleared cookies, return visit) resolved to 0 and activated on-chain as their own root instead of under their real sponsor — irreversible. Prefer the logged-in account's stored sponsorRef, cookie only as anonymous fallback, matching /api/me. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -418,7 +418,13 @@ const server = http.createServer(async (req, res) => {
|
||||
} catch (e) { return json(res, 200, { found: false, rpcError: true }); }
|
||||
}
|
||||
if (p === '/api/sponsor' && req.method === 'GET') {
|
||||
const tok = parseCookies(req)['iap.sponsor'] || '';
|
||||
// The account's stored sponsor is authoritative — it persists across
|
||||
// devices, cleared cookies, and return visits. Fall back to the first-touch
|
||||
// cookie only for anonymous visitors with no account sponsor yet. (Reading
|
||||
// the cookie alone was orphaning buyers to root when the cookie was absent.)
|
||||
const s = await auth.fromRequest(req);
|
||||
const acct = s && s.email ? await accounts.byEmail(s.email) : null;
|
||||
const tok = (acct && acct.sponsorRef) || parseCookies(req)['iap.sponsor'] || '';
|
||||
const sponsorId = await resolveSponsorToken(tok);
|
||||
let name = null, avatarUrl = null;
|
||||
if (tok) {
|
||||
|
||||
Reference in New Issue
Block a user