From 8341cae28f1463655005a19a756e18c90198fe31 Mon Sep 17 00:00:00 2001 From: Dream Hunter Date: Fri, 6 Mar 2026 14:06:49 +0800 Subject: [PATCH] fix: support admin auth for Telegram MiniApp mail viewing (#875) * fix: support admin auth for Telegram MiniApp mail viewing (#852) Admin users configured in miniAppUrl can now view emails via the MiniApp without needing Telegram initData auth. The getMail endpoint reads the x-admin-auth header (already sent by the frontend) to bypass Telegram auth and address permission checks for admin users. Co-Authored-By: Claude Opus 4.6 * refactor: extract isAdmin() as shared utility function Reuse the x-admin-auth header check logic across worker.ts and miniapp.ts via a common isAdmin() helper in utils.ts. Co-Authored-By: Claude Opus 4.6 * refactor: rename isAdmin to checkIsAdmin for consistency Co-Authored-By: Claude Opus 4.6 * fix: address PR review comments - Remove unused getAdminPasswords import from worker.ts - Return 404 when admin queries a non-existent mail Co-Authored-By: Claude Opus 4.6 --------- Co-authored-by: Claude Opus 4.6 --- CHANGELOG.md | 1 + CHANGELOG_EN.md | 1 + worker/src/telegram_api/miniapp.ts | 11 ++++++++++- worker/src/utils.ts | 8 ++++++++ worker/src/worker.ts | 12 ++++-------- 5 files changed, 24 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa1d676f..2025fd7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ ### Bug Fixes +- fix: |Telegram| 修复 admin 用户通过 Telegram MiniApp 查看邮件时报 `Auth date expired` 的问题,支持 admin 密码认证查看邮件 - fix: |Admin API| 修复 `/admin/account_settings` 在未配置 KV 且 `fromBlockList` 为空时触发 `Cannot read properties of undefined (reading 'put')` 的问题 - fix: |数据库| 修复 `DB_INIT_QUERIES` 缺少 `idx_raw_mails_message_id` 索引导致 `UPDATE raw_mails ... WHERE message_id = ?` 全表扫描的问题,同步 `schema.sql` 与初始化代码,新增 v0.0.6 迁移逻辑 - fix: |文档| 修复 User Mail API 文档中错误使用 `x-admin-auth` 的问题,改为正确的 `x-user-token` diff --git a/CHANGELOG_EN.md b/CHANGELOG_EN.md index aed8d05d..06632dcf 100644 --- a/CHANGELOG_EN.md +++ b/CHANGELOG_EN.md @@ -15,6 +15,7 @@ ### Bug Fixes +- fix: |Telegram| Fix admin users unable to view emails via Telegram MiniApp due to `Auth date expired` error, support admin password auth for viewing emails - fix: |Admin API| Fix `/admin/account_settings` throwing `Cannot read properties of undefined (reading 'put')` when KV is not configured and `fromBlockList` is empty - fix: |Database| Fix missing `idx_raw_mails_message_id` index in `DB_INIT_QUERIES` causing full table scan on `UPDATE raw_mails ... WHERE message_id = ?`, sync `schema.sql` with init code, add v0.0.6 migration - fix: |Docs| Fix User Mail API documentation incorrectly using `x-admin-auth`, changed to correct `x-user-token` diff --git a/worker/src/telegram_api/miniapp.ts b/worker/src/telegram_api/miniapp.ts index 96764dc8..d737aa6d 100644 --- a/worker/src/telegram_api/miniapp.ts +++ b/worker/src/telegram_api/miniapp.ts @@ -2,7 +2,7 @@ import { Context } from "hono"; import { Jwt } from 'hono/utils/jwt' import { CONSTANTS } from "../constants"; import { bindTelegramAddress, jwtListToAddressData, tgUserNewAddress, unbindTelegramAddress } from "./common"; -import { checkCfTurnstile } from "../utils"; +import { checkCfTurnstile, checkIsAdmin } from "../utils"; import { TelegramSettings } from "./settings"; import i18n from "../i18n"; @@ -131,6 +131,15 @@ async function getMail(c: Context): Promise { const { initData, mailId } = await c.req.json(); const msgs = i18n.getMessagesbyContext(c); try { + if (checkIsAdmin(c)) { + const result = await c.env.DB.prepare( + `SELECT * FROM raw_mails where id = ?` + ).bind(mailId).first(); + if (!result) { + return c.text("Mail not found", 404); + } + return c.json(result); + } const userId = await checkTelegramAuth(c, initData); const jwtList = await c.env.KV.get(`${CONSTANTS.TG_KV_PREFIX}:${userId}`, 'json') || []; const { addressList, addressIdMap } = await jwtListToAddressData(c, jwtList, msgs); diff --git a/worker/src/utils.ts b/worker/src/utils.ts index 73541fba..405ce1a6 100644 --- a/worker/src/utils.ts +++ b/worker/src/utils.ts @@ -216,6 +216,13 @@ export const getAdminPasswords = (c: Context): string[] => { return c.env.ADMIN_PASSWORDS.filter((item) => item.length > 0); } +export const checkIsAdmin = (c: Context): boolean => { + const adminPasswords = getAdminPasswords(c); + if (!adminPasswords.length) return false; + const adminAuth = c.req.raw.headers.get("x-admin-auth"); + return !!adminAuth && adminPasswords.includes(adminAuth); +} + export const getEnvStringList = (value: string | string[] | undefined): string[] => { if (!value) { return []; @@ -359,6 +366,7 @@ export default { getAnotherWorkerList, getPasswords, getAdminPasswords, + checkIsAdmin, getEnvStringList, sendAdminInternalMail, checkCfTurnstile, diff --git a/worker/src/worker.ts b/worker/src/worker.ts index 7f2541b6..6a229335 100644 --- a/worker/src/worker.ts +++ b/worker/src/worker.ts @@ -13,7 +13,7 @@ import { api as telegramApi } from './telegram_api' import i18n from './i18n'; import { email } from './email'; import { scheduled } from './scheduled'; -import { getAdminPasswords, getPasswords, getBooleanValue, getStringArray } from './utils'; +import { getPasswords, getBooleanValue, getStringArray, checkIsAdmin } from './utils'; import { checkAccessControl } from './ip_blacklist'; const API_PATHS = [ @@ -215,13 +215,9 @@ app.use('/user_api/*', async (c, next) => { app.use('/admin/*', async (c, next) => { // check header x-admin-auth - const adminPasswords = getAdminPasswords(c); - if (adminPasswords && adminPasswords.length > 0) { - const adminAuth = c.req.raw.headers.get("x-admin-auth"); - if (adminAuth && adminPasswords.includes(adminAuth)) { - await next(); - return; - } + if (checkIsAdmin(c)) { + await next(); + return; } const lang = c.req.raw.headers.get("x-lang") || c.env.DEFAULT_LANG; const msgs = i18n.getMessages(lang);