araharah-executor
b1d8768866
fix(03-04): web_app menu button on deployed origin + wire CTA actions on both denied-shaped cards
2026-10-23 01:00:27 +08:00
araharah-executor
8b39ea70c3
feat(03-04): Worker [assets] binding + one-command deploy + D-14 build-artifact gate
...
- wrangler.jsonc assets block serves ../web/dist; run_worker_first keeps /api/* + /telegram/* on the Worker (D-13)
- root npm run deploy = build theme → web → bot wrangler deploy + set-webhook (D-15); dev = build + wrangler dev --port 8787 --local (D-12)
- vite.config.ts dual-build: __ARAHARAH_HARNESS__ define keyed on --mode harness, separate dist/dist-harness outDirs
- main.ts guard unchanged; ambient constant declared once in web/src/vite-env.d.ts
- build-artifact.test.mjs BA1..BA6: zero CDN refs, self-hosted fonts, MapLibre worker, inlined style, no mock installer in ANY emitted file (HTML included)
2026-10-23 00:15:26 +08:00
araharah-executor
ecaf242d0e
feat(03-01): GEO-02 server half both directions — chat-keyboard fallback + GET /api/location + POST /api/location-fallback (claim-scoped)
...
- handlers/location-fallback.ts: requestLocationFallback (ReplyKeyboardMarkup request_location:true copy from strings.ts), recordSharedPin, registerLocationFallback (filters message.location, T-03-03)
- strings.ts: awaitingPin/shareLocationButton/pinReceived in en+ms (CS1 parity) — all bot copy stays in strings.ts
- bot.ts: createBot threads env.chat_sessions into the fallback handler; optional client fetch seam for tests; one-caller rule documented
- webhook.ts: GET /api/location relay + POST /api/location-fallback trigger, both resolve chat_id & locale from getClaimByToken CLAIM, never client input (T-03-01/26/27); telegram-send failure is category-only 502 (T-03-28)
- location-pin.test.mjs: LP1–LP14 (TTL contract, range guard, cross-user isolation both routes, locale split); LP12/LP13 patch node-fetch's cached default (grammy's node shim transport), then restore
- CS4 scope untouched (handlers/ not scanned); CS1 parity automatic
2026-10-22 23:33:01 +08:00
araharah-executor
4fbbb0b516
feat(03-01): TTL-only KV location-pin layer under the existing privacy gates (GEO-03, PRIV-02)
...
- kv/location-pin.ts mirrors sessions.ts shape: writePin/getPin/clearPin, key loc:<chat_id> (chat-scoped, claim-derived — never user-id scoped across keys)
- PIN_TTL_SECONDS=300; writePin is the only write path, expirationTtl on the same line referencing the named constant
- getPin is a defensive read: parse guard + shape guard + |lat|<=90 / |lon|<=180 range guard (V5 Input Validation) — corrupt records return null
- privacy.test.mjs: storageModules now scans kv/location-pin.ts, so PG1 (same-line TTL) and PG2 (no persistence-shaped exports) apply automatically
2026-10-22 23:25:59 +08:00
araharah-executor
af691ae40e
fix(02-bot-skeleton-initdata-security): WR-03 honest rotate-on-new invariant + best-effort post-mint reconciliation (fold in IN-01b dead branch, IN-01c Phase-4 notes)
2026-10-22 20:21:11 +08:00
araharah-executor
3ea1fdd932
fix(02-bot-skeleton-initdata-security): WR-02 fail-closed /telegram/webhook — unarmed WEBHOOK_SECRET rejects (constant 500, category-only log) before grammY's accept-everything compare
2026-10-22 20:18:34 +08:00
araharah-executor
8995498bff
fix(02-bot-skeleton-initdata-security): WR-01 cap /api/session body at 4 KB before JSON split (413, category-only logs)
2026-10-22 20:17:34 +08:00
araharah-executor
d600d6e71a
fix(02-03): set-webhook auto-appends /telegram/webhook to a pathless URL
...
- Deploy walkthrough revealed a bare workers.dev origin setWebhook answers ok but drops updates at / (404)
- Normalize WEBHOOK_URL: no path -> append /telegram/webhook; invalid URL -> fail fast, never echo values (T-02-04)
- .dev.vars.example documents the path expectation
2026-10-22 19:56:24 +08:00
araharah-executor
492a97bd89
fix(02-03): wire chat_sessions KV namespace id (created via wrangler kv namespace create)
...
- Replace KV_ID_PLACEHOLDER with real namespace id (non-secret, account-scoped)
- Closes the deliberate deploy-checkpoint input from task 2
2026-10-22 18:45:44 +08:00
araharah-executor
df3b7d65c1
feat(02-03): Worker entry — webhook route + /api/session security gate + deploy plumbing (D-11, D-14, D-16, D-17)
...
- src/webhook.ts: routes exactly /telegram/webhook (grammY cloudflare-mod
adapter, constant-time secret-token auth against env.WEBHOOK_SECRET) and
POST /api/session (validateInitData → 401 category-only rejections →
mintSession one-time token; single mint path, no extra branch — T-02-01/02/06)
- D-14: the only log statement is '[initdata] rejected: <category>' — no
payload, ids, or timestamps
- scripts/set-webhook.mjs: setWebhook with secret_token + allowed_updates
[message], secrets read from gitignored .dev.vars, token never echoed
- bot deploy script chains wrangler deploy + set-webhook; wrangler.jsonc
gains workers_dev (webhook URL target); KV id stays placeholder for the
deploy checkpoint
- verified: 27/27 tests, typecheck clean, wrangler deploy --dry-run exit 0
2026-10-22 11:49:43 +08:00
araharah-executor
b4393fbcf3
feat(02-03): strings module + text-only command surface with Malay aliases (D-01..D-05)
...
- src/i18n/strings.ts: single copy source of truth, en + ms identical
key-sets, clinical/honest start + privacy copy, pickLocale fallback rule
- /start /mula, /help, /privacy /privasi handlers: plain text replies with
link previews disabled, zero menu/button surface (D-02, grep-gated)
- createBot(env) factory registers exactly the phase command stack
- scripts/register-commands.mjs: one-time setMyCommands, two scopes
(default + language_code ms), descriptions derived from helpMenu —
no inline copy, no future-command stubs (D-03/D-05)
- test/commands.test.mjs: CS1-CS6 gates — locale parity, pickLocale
matrix, PRIV-01 copy gate vs never-facts + TTL wording, D-02 structural
grep, D-03 menu gap-freedom, D-04 alias completeness (27 passing)
2026-10-22 11:48:50 +08:00
araharah-executor
e9aec5833b
feat(02-02): TTL-only KV sessions with rotate-on-new + PRIV-02 storage gates (D-06/D-07/D-08/D-14)
...
- sessions.ts: mintSession (crypto.randomUUID opaque token, T-02-05), rotate-on-new deletes prior session record via chat pointer (D-07), both puts carry expirationTtl: SESSION_TTL_SECONDS on the call line (PRIV-02)
- SESSION_TTL_SECONDS = 900 pairs the session envelope with the D-13 freshness window
- SessionClaim is exactly D-08: user_id, chat_id, issued_at, language_code — nothing else serializes to storage
- sessions.test.mjs: in-memory KV fake asserting finite expirationTtl on every put; D-08 key-set equality; rotate removes old token; expired-token → null (D-14 class)
- privacy.test.mjs: PG1 same-line expirationTtl source gate (auto-tightens to webhook.ts when plan 03 adds it) + PG2 no persistence-shaped exports
- 18/18 PASS across initdata + sessions + privacy suites; full plan GREEN
2026-10-22 11:43:20 +08:00
araharah-executor
54bffe728c
feat(02-02): validateInitData — SubtleCrypto HMAC core with rejection classes (D-13, D-14)
...
- GREENs the plan-01 RED vector suite: T1-T7 all PASS (10/10 cases)
- Telegram-verified two-step key derivation: secretKey = HMAC(botToken, key=salt), checkHex = HMAC(dataCheckString, secretKey bytes)
- Sort by field name, hash/signature excluded, values decoded once with '+' literal (no URLSearchParams)
- Rejection precedence: malformed (hash/user.id/auth_date) -> tampered (timing-safe hex compare) -> stale (>900s, D-13)
- Hand-rolled WebAppInitUser/WebAppInitChat types (grammy ships none); zero deps of any kind — pure (raw, botToken, opts)
2026-10-22 11:41:46 +08:00
araharah-executor
fc5001a4eb
test(02-01): hand-rolled harness + RED initdata vector suite (D-12, TDD RED)
...
- bot/test/harness.mjs: zero-dep registry (test(name, fn))
- bot/test/runner.mjs: auto-discovers *.test.mjs, suite-load failure -> FAIL case, exit 0 iff all green
- bot/test/initdata.test.mjs: T1-T7 vector contract signed via node:crypto in-suite
(T1 known-good, T2 tampered, T3 stale 3600s, T4 boundary 899/901, T5 order-independence,
T6a-c malformed, T7 RFC-4231 node:crypto independence pin)
- demonstrated RED: 8 FAILs / exit 1 against missing src/security/initdata.ts; GREEN lands in plan 02
2026-10-22 11:38:06 +08:00
araharah-executor
c9b6ba402d
feat(02-01): bot workspace scaffold with Env contract (D-09/D-10/D-11/D-15)
...
- bot/ npm workspace sibling to theme/: grammy ^1.46.0, wrangler ^4.151.3, TS ^5.9.3
- src/config.ts exports Env (BOT_TOKEN, WEBHOOK_SECRET, chat_sessions KVNamespace)
- wrangler.jsonc: main src/webhook.ts + chat_sessions KV binding (id filled in plan 03)
- .gitignore ships .dev.vars/.wrangler/ in the same commit as .dev.vars.example (D-17)
- root delegate scripts bot:test/typecheck/dev/deploy/commands
2026-10-22 11:35:54 +08:00