Missions may place the token with {token} and name the embed host explicitly (Telegram Mini App launch links)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -124,7 +124,9 @@ const server = http.createServer(async (req, res) => {
|
|||||||
if (rewards.completed(me.memberId, m.id)) return json(res, 400, { error: 'You already completed this one.' });
|
if (rewards.completed(me.memberId, m.id)) return json(res, 400, { error: 'You already completed this one.' });
|
||||||
if (limited('start:' + me.memberId, 20, 3600000)) return json(res, 429, { error: 'Easy. Twenty starts an hour is plenty.' });
|
if (limited('start:' + me.memberId, 20, 3600000)) return json(res, 429, { error: 'Easy. Twenty starts an hour is plenty.' });
|
||||||
const t = missions.issue(me.memberId, m.id);
|
const t = missions.issue(me.memberId, m.id);
|
||||||
const url = m.url + (m.url.includes('?') ? '&' : '?') + 'ph=' + t.t;
|
// a mission URL may place the token itself with {token} (a Telegram Mini App takes it in
|
||||||
|
// ?startapp=, not as our own query string); otherwise it is appended as ?ph=
|
||||||
|
const url = m.url.includes('{token}') ? m.url.replace('{token}', t.t) : m.url + (m.url.includes('?') ? '&' : '?') + 'ph=' + t.t;
|
||||||
return json(res, 200, { ok: true, token: t.t, url, dwell: m.dwell || 30, expires: t.exp });
|
return json(res, 200, { ok: true, token: t.t, url, dwell: m.dwell || 30, expires: t.exp });
|
||||||
}
|
}
|
||||||
if (p === '/api/my/submit' && req.method === 'POST') {
|
if (p === '/api/my/submit' && req.method === 'POST') {
|
||||||
@@ -147,6 +149,8 @@ const server = http.createServer(async (req, res) => {
|
|||||||
const b = await readBody(req);
|
const b = await readBody(req);
|
||||||
const id = String(b.id || '').trim().toLowerCase().replace(/[^a-z0-9-]/g, '').slice(0, 40); if (!id) return json(res, 400, { error: 'id required' });
|
const id = String(b.id || '').trim().toLowerCase().replace(/[^a-z0-9-]/g, '').slice(0, 40); if (!id) return json(res, 400, { error: 'id required' });
|
||||||
let host = ''; try { host = new URL(String(b.url)).hostname.replace(/^www\./, ''); } catch (e) { return json(res, 400, { error: 'url must be a full https URL' }); }
|
let host = ''; try { host = new URL(String(b.url)).hostname.replace(/^www\./, ''); } catch (e) { return json(res, 400, { error: 'url must be a full https URL' }); }
|
||||||
|
// the origin the embed calls from can differ from the link (a t.me launch link opens a Mini App on its own host)
|
||||||
|
if (b.host) host = String(b.host).trim().toLowerCase().replace(/^https?:\/\//, '').replace(/^www\./, '').replace(/\/.*$/, '');
|
||||||
missions.save({ id, site: String(b.site || host).slice(0, 60), host, name: String(b.name || '').slice(0, 80), brief: String(b.brief || '').slice(0, 400), url: String(b.url), dwell: Math.max(5, Number(b.dwell) || 45), slots: Math.max(1, Number(b.slots) || 1), budget: Math.max(0, Number(b.budget) || 0), active: b.active !== false });
|
missions.save({ id, site: String(b.site || host).slice(0, 60), host, name: String(b.name || '').slice(0, 80), brief: String(b.brief || '').slice(0, 400), url: String(b.url), dwell: Math.max(5, Number(b.dwell) || 45), slots: Math.max(1, Number(b.slots) || 1), budget: Math.max(0, Number(b.budget) || 0), active: b.active !== false });
|
||||||
return json(res, 200, { ok: true, missions: missions.list() });
|
return json(res, 200, { ok: true, missions: missions.list() });
|
||||||
}
|
}
|
||||||
@@ -155,7 +159,7 @@ const server = http.createServer(async (req, res) => {
|
|||||||
if (p === '/api/admin/faucet/tick' && req.method === 'POST') { const r = await faucet.tick(notify); return json(res, 200, Object.assign(r, { balance: await faucet.balance() })); }
|
if (p === '/api/admin/faucet/tick' && req.method === 'POST') { const r = await faucet.tick(notify); return json(res, 200, Object.assign(r, { balance: await faucet.balance() })); }
|
||||||
if (p === '/api/admin/embed-test') { // mint a token for any mission so the embed can be tried without a hunter
|
if (p === '/api/admin/embed-test') { // mint a token for any mission so the embed can be tried without a hunter
|
||||||
const m = missions.get(String(u.searchParams.get('id') || '')); if (!m) return json(res, 404, { error: 'no such mission' });
|
const m = missions.get(String(u.searchParams.get('id') || '')); if (!m) return json(res, 404, { error: 'no such mission' });
|
||||||
const t = missions.issue(0, m.id); return json(res, 200, { url: m.url + (m.url.includes('?') ? '&' : '?') + 'ph=' + t.t, token: t.t, dwell: m.dwell });
|
const t = missions.issue(0, m.id); return json(res, 200, { url: m.url.includes('{token}') ? m.url.replace('{token}', t.t) : m.url + (m.url.includes('?') ? '&' : '?') + 'ph=' + t.t, token: t.t, dwell: m.dwell });
|
||||||
}
|
}
|
||||||
return json(res, 404, { error: 'No such admin call.' });
|
return json(res, 404, { error: 'No such admin call.' });
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user