Commit Graph

549 Commits

Author SHA1 Message Date
Dream Hunter
e7df77cac0 fix: update address timestamp on send mail and refactor TG attachment guard (#896)
fix: update address timestamp on send mail, refactor TG attachment guard

- Call updateAddressUpdatedAt after successful send mail to keep
  address activity timestamp up to date
- Refactor Telegram attachment push: replace early return with if block
  to prevent skipping future logic after attachment section

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 02:39:18 +08:00
Dream Hunter
9ee21da8a9 feat: support attachment push for Telegram and Webhook (#895)
* feat: support attachment push for Telegram and Webhook (#894)

- Parse email attachments via postal-mime in commonParseMail
- Send attachments via Telegram Bot API sendDocument after text message
- Include base64-encoded attachments in webhook payload
- Add e2e tests for webhook attachment push
- Add i18n messages for attachment-related notifications

Closes #894

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: remove user-facing error message for failed attachment send

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: remove unused i18n attachment messages

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: use sendMediaGroup for batch attachment sending

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: remove redundant commonParseMail call, use cached result

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: remove webhook attachment support, raw already contains attachments

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: use sendDocument for single attachment, sendMediaGroup for 2+

Telegram sendMediaGroup requires 2-10 items minimum. Use sendDocument
for single attachment case. Update CHANGELOG with 50MB limit info.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: batch sendMediaGroup in groups of 9, add attachments to wasm parser

Telegram sendMediaGroup supports 2-10 items. Batch large attachment
lists into groups of 9. Also add attachments field to commented-out
wasm parser for future compatibility.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add caption to attachment messages, update wasm patch

Add email sender and subject as caption on Telegram attachment messages.
Caption is shown on the first attachment only for sendMediaGroup.
Update wasm parser patch to include attachments field mapping, and fix
wasm comment to use correct field names (content_type, content as
Uint8Array directly).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: unify attachment sending with sendMediaGroup for all cases

sendMediaGroup works with 1+ files (tested). Remove sendDocument
special case and always use sendMediaGroup with batching.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: reduce sendMediaGroup batch size to 6

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: change WASM parse email comment from TODO to NOTE

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: regenerate wasm parser patch with attachments support

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add ENABLE_TG_PUSH_ATTACHMENT env var to control attachment push

Add environment variable to enable/disable Telegram attachment push
(default disabled). Update type definitions, wrangler template,
worker-vars docs (zh/en), telegram feature docs (zh/en), and
changelogs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 02:10:48 +08:00
Dream Hunter
5bb053fb7b chore: upgrade deps and GitHub Actions for Node.js 24 (#889)
chore: upgrade dependencies and GitHub Actions for Node.js 24 compatibility

Upgrade GitHub Actions to fix Node.js 20 deprecation warnings:
- actions/checkout v4 → v6
- actions/setup-node v4 → v6
- pnpm/action-setup v3 → v4
- docker/login-action v3 → v4
- docker/setup-qemu-action v3 → v4
- docker/setup-buildx-action v3 → v4
- docker/build-push-action v5 → v7
- node-version 20 → 22, pnpm 8 → 10

Upgrade project dependencies:
- frontend: vue 3.5.30, naive-ui 2.44.1, dompurify 3.3.3, @unhead/vue 2.1.12
- worker: hono 4.12.7, @cloudflare/workers-types, typescript-eslint 8.57.0
- all: wrangler 4.72.0

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 01:27:03 +08:00
Dream Hunter
7d880ef340 fix: user email regex setting visibility (#888)
fix: keep email regex option visible in user settings
2026-03-12 01:15:22 +08:00
Dream Hunter
e6cc8e2ffd feat: add Turnstile CAPTCHA for login forms (#767) (#885)
* feat: add Turnstile CAPTCHA for login forms (#767)

Add optional Turnstile verification for admin login, user login, and
address password login via ENABLE_LOGIN_TURNSTILE_CHECK env var.
Does not affect existing Turnstile on address creation / registration.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: add ENABLE_LOGIN_TURNSTILE_CHECK to wrangler.toml.template

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: ensure openSettings loaded before admin login modal

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add Turnstile to site access password and fix settings field name

- Add Turnstile to site access password modal in Header.vue
- Add /open_api/site_login endpoint for password + Turnstile verification
- Fix settings field name from enableTurnstileLogin to enableLoginTurnstileCheck

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: move login endpoints to open_api/auth.ts

Move /open_api/site_login and /open_api/admin_login from commom_api.ts
to a dedicated open_api/auth.ts file for better code organization.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: change Turnstile check failure status from 500 to 400

Turnstile validation failure is a client error, not a server error.
Change all Turnstile check error responses from 500 to 400.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: use unique IDs for multiple Turnstile instances

When multiple modals with Turnstile appear simultaneously (e.g., site
access + admin login), the hardcoded id="cf-turnstile" causes conflicts.
Generate a unique container ID per Turnstile instance to fix this.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: review fixes - cfToken separation, register Turnstile, error codes

- Separate cfToken refs in Login.vue to avoid token sharing between
  login and new address creation Turnstile instances
- Add Turnstile check to user registration endpoint (not just verify_code)
- Show Turnstile on register tab regardless of enableMailVerify
- Pass cf_token in register request body
- Fix site_login error message to use CustomAuthPasswordMsg
- Fix verifyCode Turnstile error status from 500 to 400
- Restore empty line in commom_api.ts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: separate register Turnstile logic for with/without mail verify

- With mail verify: verify_code already checks Turnstile, register
  skips Turnstile (token is one-time use)
- Without mail verify: register checks Turnstile directly
- Separate loginCfToken for login tab to avoid token sharing with
  register tab Turnstile

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: add enableLoginTurnstileCheck to store defaults, simplify changelog

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: add /open_api/credential_login for credential login verification

Add credential_login endpoint that verifies both Turnstile token and
JWT credential server-side, replacing the generic verify_turnstile
endpoint. Credential login now validates the JWT before accepting it.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: improve login endpoints - hash passwords, expose Turnstile refresh, fix status codes

- site_login/admin_login: always called, verify hashed password + optional Turnstile
- credential_login: always called, verify JWT + optional Turnstile
- Frontend sends hashed passwords instead of plaintext
- Turnstile component exposes refresh method via defineExpose
- Fix Turnstile error status 500→400 in mails_api and telegram_api

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: rename to ENABLE_GLOBAL_TURNSTILE_CHECK and add isGlobalTurnstileEnabled helper

- Rename ENABLE_LOGIN_TURNSTILE_CHECK -> ENABLE_GLOBAL_TURNSTILE_CHECK
- Add isGlobalTurnstileEnabled() in utils.ts: checks env var + Turnstile keys all present
- Backend settings returns enableGlobalTurnstileCheck computed from the helper
- All backend endpoints use isGlobalTurnstileEnabled(c) instead of raw env check
- Update all frontend refs, docs, changelog, and wrangler template

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: use utils.isGlobalTurnstileEnabled instead of named import

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test: add E2E tests for turnstile login endpoints

- Test all 3 new /open_api/* endpoints when ENABLE_GLOBAL_TURNSTILE_CHECK is disabled
- Verify settings returns enableGlobalTurnstileCheck: false
- Test admin_login with correct/wrong/empty hashed password
- Test site_login returns 401 when no PASSWORDS configured
- Test credential_login with valid JWT, invalid JWT, empty credential
- Test address_login with empty cf_token works when turnstile disabled
- Add ADMIN_PASSWORDS to E2E wrangler config for admin_login tests

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test: rename test file to login-endpoints.spec.ts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: validate JWT payload has address field in credential_login

Prevents user tokens or challenge tokens from being accepted as
address credentials since they share the same JWT_SECRET.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: refresh Turnstile token on login failure to allow retry

After a failed login attempt, the consumed Turnstile token is now
refreshed so users can retry without manually refreshing.
Also adds ref to signup Turnstile in UserLogin.vue to refresh after
verification code is sent (single-use token consumed).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: separate Turnstile tokens for signup and reset password flows

Split shared cfToken into signupCfToken and resetCfToken to prevent
single-use Turnstile token conflicts between signup tab and reset
password modal. Each flow now has its own token ref and refreshes
the correct Turnstile widget after use.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: update comments from "login turnstile" to "global turnstile"

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 00:47:26 +08:00
Dream Hunter
94c606959f docs: add webhook preset templates and Telegram push docs (#884)
docs: add webhook preset templates and Telegram per-user push docs (#769)

Add Telegram Bot, WeChat Work, Discord webhook preset templates to
frontend and documentation. Add per-user mail push and global push
documentation for Telegram Bot.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 21:45:05 +08:00
Dream Hunter
75236e6a53 fix: passkey user verification compatibility for v13 (#883)
fix: disable requireUserVerification for passkey auth compatibility

@simplewebauthn/server v13 defaults requireUserVerification to true,
causing "User verification required, but user could not be verified"
errors for existing passkeys and authenticators that don't enforce UV.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 03:06:54 +08:00
Dream Hunter
13c3879033 docs: update CLAUDE.md with auth, e2e, and architecture (#882)
docs: update CLAUDE.md with auth corrections, e2e testing, and architecture

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 02:25:13 +08:00
Dream Hunter
c5893a2944 chore: upgrade dependencies (#881)
* chore: upgrade dependencies

- dompurify 3.3.1 → 3.3.2
- naive-ui 2.43.2 → 2.44.0
- vue-i18n 11.2.8 → 11.3.0
- @cloudflare/workers-types 4.20260305.1 → 4.20260307.1
- @types/node 25.3.3 → 25.3.5
- wrangler 4.70.0 → 4.71.0 (all subprojects)

* feat: upgrade @simplewebauthn packages from v10 to v13

Breaking changes addressed:
- [v11] startRegistration/startAuthentication now take object param
- [v11] registrationInfo.credential replaces flat destructuring
- [v11] authenticator param renamed to credential in verifyAuthenticationResponse
- [v13] @simplewebauthn/types removed, types imported from @simplewebauthn/server

Packages:
- @simplewebauthn/server: 10.0.1 → 13.2.3
- @simplewebauthn/browser: 10.0.0 → 13.2.2
- @simplewebauthn/types: removed (deprecated)

* test: add passkey API E2E tests

- User registration and login flow
- register_request/authenticate_request return valid WebAuthn options
- authenticate_response with invalid credential returns 404
- register_response with invalid credential returns error
- Passkey list empty for new user
- Rename/delete operations with validation

* fix: use UI login instead of localStorage injection in browser passkey test

The localStorage approach doesn't work with VueUse's useStorage because
it doesn't detect external changes during page navigation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: hash password before registration to match frontend login behavior

The frontend hashes passwords with SHA-256 before sending to the API.
Registration via API must use the same hashed password so that UI login
matches the stored value.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: allow crypto.subtle in Docker browser tests

The frontend uses crypto.subtle for password hashing, which requires
a secure context (HTTPS or localhost). In Docker, the frontend runs
at http://frontend:5173 which is not a secure context. Add Chromium
flag to treat this origin as secure.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: serve frontend over HTTPS in Docker for WebAuthn secure context

WebAuthn (navigator.credentials) and crypto.subtle both require a
secure context (HTTPS or localhost). The Docker frontend was serving
over HTTP, making passkey operations impossible.

Changes:
- Generate self-signed cert in Dockerfile.frontend
- Configure Vite to serve over HTTPS
- Update FRONTEND_URL to https://
- Add ignoreHTTPSErrors to Playwright browser config
- Use localStorage injection for passkey test login

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: add Vite proxy to avoid mixed-content blocking in HTTPS Docker frontend

HTTPS pages cannot make HTTP API requests (mixed content). Add a Vite
proxy for all API paths so the browser makes same-origin HTTPS requests,
which Vite proxies to the HTTP worker server-to-server.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: store userJwt without JSON.stringify in localStorage

VueUse's useStorage with a string default uses raw string serialization
(no JSON wrapping). Using JSON.stringify added double quotes around the
JWT token, causing 401 Unauthorized from the worker.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: clean up passkey API test per review feedback

Remove unused variables and rename test to match actual behavior.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 02:18:17 +08:00
Dream Hunter
5f3762ef58 fix: auto-reply not triggering when source_prefix is empty (#880)
* fix: auto-reply not triggering when source_prefix is empty (#459)

- Empty source_prefix now matches all senders (was short-circuiting as falsy)
- Support regex matching with /pattern/ syntax in source_prefix
- Backward compatible: plain strings still use startsWith
- Use E2E_TEST_MODE switch to skip cloudflare:email import in tests
- Track reply() calls in E2E mock for testability

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: update auto-reply UI labels for regex support

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: update changelogs for auto-reply fix and regex feature

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: upgrade version to v1.5.0

- Update version number to 1.5.0 in all package.json files and constants.ts
- Split CHANGELOG: v1.4.0 entries finalized, new v1.5.0(main) section with auto-reply changes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: add error logging for invalid regex in auto-reply source_prefix

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: address CodeRabbit review suggestions

- Use const object instead of let for mock state tracking
- Add log when auto-reply subject/message falls back to defaults

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: add source_prefix regex syntax to auto-reply docs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 19:08:06 +08:00
Dream Hunter
10873e7887 feat: add release skill for automated GitHub release (#879)
* feat: add release skill for automated GitHub release creation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: use --notes-file instead of --notes for release creation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: add time-bound filter for PR collection in release skill

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: use hyphenated cache-clearing in release skill

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 01:36:19 +08:00
Bowl42
fca9bade48 feat: add webhook preset templates for Message Pusher, Bark, and ntfy (#877) v1.4.0 2026-03-06 19:53:08 +08:00
Dream Hunter
f5ca8afcce test: add E2E tests for webhook trigger on incoming mail (#878)
* test: add E2E tests for auto-reply trigger and webhook trigger

- Improve mock reply() in e2e_test_api.ts to send auto-replies via
  SMTP (WorkerMailer) so they reach Mailpit for verification
- Add auto-reply-trigger.spec.ts: verifies auto-reply is sent when
  incoming mail matches source_prefix, and NOT sent otherwise
- Add webhook-trigger.spec.ts: starts a temporary HTTP server to
  receive webhook calls, verifies payload on mail arrival

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: fallback EmailMessage for E2E auto-reply when cloudflare:email is unavailable

In wrangler dev mode without Email Routing binding, `import('cloudflare:email')`
throws, silently caught by auto_reply's try-catch. Add a fallback that constructs
a plain object with a ReadableStream `raw` property so the E2E mock reply() can
send the auto-reply via SMTP to Mailpit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: handle both \r\n and \n line endings in MIME parser for E2E tests

mimetext uses os.EOL which is \n on Linux (Docker). The parseMimeForReply
function only looked for \r\n, causing it to fail parsing the auto-reply
MIME content in the E2E environment.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: add debug logging and robust raw MIME extraction for E2E auto-reply

- auto_reply.ts: add fallback ReadableStream when cloudflare:email
  is unavailable, attach rawMime directly to replyMessage
- e2e_test_api.ts: try reading rawMime string first, then fallback
  to ReadableStream; add diagnostic console.log for CI debugging

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: skip sealed EmailMessage in E2E mode, await webhook server listen

- auto_reply.ts: use plain object with raw ReadableStream in E2E_TEST_MODE
  (cloudflare:email's EmailMessage is sealed, can't attach extra properties)
- e2e_test_api.ts: simplify mock reply() to read raw ReadableStream directly,
  add defensive check for from without @
- webhook-trigger.spec.ts: await server.listen to ensure socket is bound
  before sending requests (CodeRabbit review feedback)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: add missing await for async startWebhookReceiver in disabled test

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: drop auto-reply E2E test, clean up webhook test

- Remove auto-reply-trigger.spec.ts (cannot test without modifying
  production auto_reply.ts due to sealed EmailMessage from cloudflare:email)
- Clean up e2e_test_api.ts: remove WorkerMailer, MIME parsing, and SMTP
  reply logic that was only needed for auto-reply testing
- Improve webhook test: use dynamic port allocation (port 0) instead of
  hardcoded WEBHOOK_PORT to avoid port conflicts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test: assert webhook request path in E2E test

Add path assertion to verify webhook request hits /webhook endpoint,
preventing false positives from incorrect routing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 16:41:29 +08:00
Dream Hunter
8cf1150b15 feat: add STARTTLS support for SMTP proxy server (#876)
* feat: add STARTTLS support for SMTP proxy server

Add smtp_tls_cert and smtp_tls_key environment variables to enable
STARTTLS on the SMTP proxy server, matching existing IMAP TLS support.

Closes #249

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test: add E2E tests for SMTP/IMAP STARTTLS

- Add smtp-proxy-tls service with self-signed certs in docker-compose
- Add smtp-tls.spec.ts: SMTP STARTTLS send plain/HTML/auth tests
- Add imap-tls.spec.ts: IMAP STARTTLS login/list/select/fetch tests
- Register smtp-proxy project in playwright.config.ts
- Wait for TLS proxy readiness in docker-entrypoint.sh

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: enforce auth over TLS when STARTTLS is configured

- Set auth_require_tls conditionally based on tls_context presence
- Disable insecure SSLv2/SSLv3 protocols in TLS context

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: replace cert-gen service with inline cert generation

The cert-gen one-shot container was exiting immediately after
generating certificates, triggering --abort-on-container-exit
and stopping all services before tests could run.

Replace with an entrypoint script in smtp-proxy-tls that generates
the self-signed cert before starting the proxy server.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 15:05:29 +08:00
Dream Hunter
8341cae28f 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 <noreply@anthropic.com>

* 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 <noreply@anthropic.com>

* refactor: rename isAdmin to checkIsAdmin for consistency

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* 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 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 14:06:49 +08:00
Bowl42
635e0f4456 chore(deps): bump dompurify from 3.3.1 to 3.3.2 in /frontend (#874)
Security fix: XSS bypass via jsdom raw-text tag parsing,
prototype pollution with custom elements, and lenient config
parsing in _isValidAttribute.

Supersedes #872

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:46:57 +08:00
Bowl42
e81d46262d chore(deps): bump playwright from 1.49.0 to 1.58.2 (#873)
Update @playwright/test and Docker base image together to fix
CI failures caused by mismatched browser versions.

Closes #864

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 12:40:44 +08:00
Bowl42
13426b2fbd test: add E2E tests for webhook settings (#871)
* test: add E2E tests for webhook settings

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test: verify headers and body fields in webhook roundtrip test

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Dream Hunter <dreamhunter2333@gmail.com>
2026-03-06 11:35:04 +08:00
Dream Hunter
2a52fd35d5 refactor: modularize IMAP server with dual login, STARTTLS, and test suite (#859)
refactor: modularize IMAP server with fixes and E2E tests

- Modularize IMAP server into imap_server, imap_mailbox, imap_message,
  imap_http_client, parse_email, config, models
- Support dual login: JWT token and address+password via backend
- Add STARTTLS support with configurable TLS cert/key
- Fix FETCH/STORE returning UID instead of sequence number (RFC 3501)
- Implement IMessageFile.open() for correct BODY[] raw MIME delivery
- Add UIDNEXT to SELECT response via _cbSelectWork override
- Use per-restart UIDVALIDITY to force client resync
- Pass raw MIME to SimpleMessage for accurate RFC822.SIZE
- Fix SENT mailbox returning empty source
- Handle CREATE command gracefully for Thunderbird compatibility
- Add IMAP E2E tests: auth, LIST, SELECT, STATUS, FETCH, SEARCH,
  STORE, UID FETCH, BODY[] integrity, size, seq numbers, SENT mailbox
- Add SMTP E2E tests using nodemailer: send plain/HTML, auth failure,
  sendbox verification
- Add sendTestMail helper using admin/send_mail

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 11:08:10 +08:00
Dream Hunter
e38015a5b6 refactor: E2E tests use real email() handler (#870)
* refactor: add receive_mail E2E endpoint using real email() handler

Add /admin/test/receive_mail that constructs a mock ForwardableEmailMessage
and calls the real email() handler, so E2E tests exercise the full mail
processing pipeline. Extract both test endpoints into e2e_test_api.ts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: trigger CI

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 10:15:02 +08:00
Bowl42
f98bbce234 test: add E2E tests for auto-reply settings (#868)
* test: add E2E tests for auto-reply settings

Add auto-reply.spec.ts with two test cases:
- GET empty → POST save → GET verify saved fields
- POST with too-long subject returns 400

Enable ENABLE_AUTO_REPLY in E2E wrangler config.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test: add full fields and body assertion for too-long validation per review

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 00:22:25 +08:00
Dream Hunter
2f8183e024 fix: correct API path typo requset → request (#869)
* fix: correct API path typo `requset_send_mail_access` → `request_send_mail_access`

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: correct typo in send-access E2E test (requset → request)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 22:33:06 +08:00
Bowl42
e115b99271 test: add E2E test for clearing sent items (#867)
* test: add E2E test for clearing sent items

Add clear-sent.spec.ts verifying:
- Send a mail → verify it appears in sendbox → clear sent items → verify sendbox is empty

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test: remove unused address variable

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 22:09:17 +08:00
Bowl42
12ab6e1430 test: add E2E test for duplicate send access request (#866)
* test: add E2E test for duplicate send access request

Add send-access.spec.ts verifying:
- First request succeeds and balance matches DEFAULT_SEND_BALANCE
- Duplicate request returns 400 (UNIQUE constraint)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test: assert response body contains 'Already' for duplicate send access

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 22:09:08 +08:00
Bowl42
6e6e3f0877 test: add E2E tests for fetching single mail by ID (#865)
Add mail-detail.spec.ts with two test cases:
- Fetch a seeded mail by ID and verify fields (id, address, source, raw)
- Fetch non-existent mail ID returns null

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 22:09:02 +08:00
Bowl42
286dfabd5f test: add E2E tests for address password login (#863) 2026-03-05 21:43:07 +08:00
Bowl42
aaae21e92e test: add E2E tests for mail deletion and inbox clearing (#862) 2026-03-05 20:53:10 +08:00
Dream Hunter
3df55dce91 chore: upgrade dependencies across all subprojects (#861) 2026-03-05 20:27:59 +08:00
Bowl42
13b009f6ab test: add Dockerized E2E test environment with Playwright + Mailpit (#860) 2026-03-05 20:12:43 +08:00
Bowl42
0c337a1942 fix: sanitize mail content in reply/forward to prevent XSS (#857)
* fix: sanitize mail content in reply/forward to prevent XSS

- Add DOMPurify to sanitize HTML email content (whitelist-based)
- Add escapeHtml for plain text content (escape &<>"')
- Guard mail.originalSource with fallback to empty string
- Add jsdom for vitest DOM environment (DOMPurify requires DOM)
- Add XSS regression tests (script tags, event handlers, HTML escape)
- Add contentType assertion for empty message fallback case

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test: add XSS sanitization E2E screenshots

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: remove temporary screenshots from tree

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: normalize escapeHtml input and add forward text escape test

- escapeHtml: convert input via String(str ?? '') to handle non-string values
- Add test for plain text forward with special chars (<, &, >)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 23:30:43 +08:00
Bowl42
372f7b4149 fix: preserve HTML content when replying to HTML emails (#856)
* fix: preserve HTML content when replying to HTML emails (#728)

Reply was using curMail.text (plain text) instead of curMail.message (HTML),
causing loss of original email formatting. Forward already used HTML correctly.

Now reply prefers HTML content with plain text fallback, matching forward behavior.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test: add vitest unit tests for reply/forward mail logic

Extract buildReplyModel and buildForwardModel into testable utility
functions and add 13 unit tests covering HTML content preservation,
plain text fallback, sender parsing, and subject formatting.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: remove unnecessary vitest exclude config

The e2e files have been deleted, so the test.exclude config in
vite.config.js is no longer needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: revert unnecessary trailing comma in vite.config.js

Restore vite.config.js to match main exactly — no changes needed
for this PR.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test: add e2e screenshots for PR review

Screenshots from local Playwright test showing:
1. HTML email rendered correctly in inbox
2. Reply editor preserving HTML content in blockquote

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: remove temporary test screenshots

Screenshots have been posted as PR comment, no longer needed in tree.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: use html contentType for HTML email replies instead of rich

wangEditor (rich text editor) strips block-level HTML tags inside
blockquote, losing all formatting. Use contentType 'html' for HTML
email replies (matching forward behavior) so content is edited as
raw HTML in a textarea, preserving all formatting.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test: update e2e screenshots showing HTML formatting preserved

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: remove temporary screenshots from tree

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test: add SMTP send flow E2E screenshots with mailpit

Screenshots showing complete SMTP HTML email reply flow:
1. View rich HTML email (gradient headers, tables, badges)
2. Reply compose with HTML mode (textarea, not wangEditor)
3. Sent box showing preserved HTML formatting
4. Mailpit inbox receiving the SMTP email
5. Mailpit email detail with full HTML rendering

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: remove temporary SMTP test screenshots from tree

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 22:51:27 +08:00
Bowl42
abad88b986 fix: improve email content readability in dark mode (#855) 2026-03-04 20:52:19 +08:00
Dream Hunter
928a35b7cb docs: update CLAUDE.md and remove AGENTS.md (#854)
Consolidate AGENTS.md into CLAUDE.md with enhanced guidance:
- Add post-task checklist requiring changelog and docs updates
- Add auth headers reference
- Add squash merge convention

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 10:06:43 +08:00
Dream Hunter
006ddf4aa4 docs: sync changelog with recent changes (#853)
- Add Status menu button feature entry to both CN/EN changelogs
- Add missing Improvements entries to EN changelog (IP lookup link, VitePress i18n fix)

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 02:19:30 +08:00
Dream Hunter
f55e8c9818 feat: add configurable Status menu button (#851) 2026-03-03 12:58:49 +08:00
Dream Hunter
4ef4c0d938 Fix links in English README for consistency 2026-03-02 18:05:34 +08:00
Dream Hunter
f4255f33a1 Fix language links in README.md 2026-03-02 18:05:06 +08:00
Dream Hunter
a2d37b8183 docs: add private site password hint to all API docs (#850)
docs: add x-custom-auth private site password hint to all API docs

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 18:04:27 +08:00
Dream Hunter
9b7a80ef54 fix: add missing message_id index to DB init and migration (#849)
fix: add missing message_id index to DB_INIT_QUERIES and migration

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:34:26 +08:00
Dream Hunter
a5e5fceab5 fix: prevent account_settings KV.put on empty fromBlockList (#847)
* fix: avoid KV.put when fromBlockList is empty

* docs: update English changelog for account_settings fix
2026-03-02 00:27:24 +08:00
Dream Hunter
0df74ee5cc docs: improve SEO and redirect root to /zh/ (#846)
docs: improve SEO meta tags and redirect root to /zh/

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 15:23:43 +08:00
Dream Hunter
2b33d953fa docs: fix i18n language switch path error (#845)
docs: fix i18n language switch by using dual prefix locales

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 15:16:47 +08:00
Dream Hunter
1f969738f5 docs: add Windows .env file note for VITE_IS_TELEGRAM (#844) 2026-02-25 14:31:05 +08:00
Dream Hunter
4b378ca710 ci: optimize workflows with parallel jobs and conditional checks (#843)
* ci: optimize workflows with parallel jobs and conditional checks

* ci: add sync and tag triggers to frontend_pagefunction_deploy
2026-02-25 14:20:26 +08:00
Dream Hunter
bafd003cbd chore: upgrade dependencies (#842)
chore: upgrade dependencies across frontend, worker, pages and docs

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 14:05:12 +08:00
Dream Hunter
723e1fe75d feat: add ip.im link for source IP in admin account list (#841) 2026-02-25 13:59:53 +08:00
Dream Hunter
566c6536d1 docs: fix user API auth and add admin delete API docs (#836) 2026-02-16 15:49:26 +08:00
Dream Hunter
bde08b9d55 feat: add email regex validation for user registration (#835) 2026-02-16 12:40:20 +08:00
Dream Hunter
56351ed963 style: improve empty state display for inbox and sent box (#831)
- Add different messages based on mail count (empty vs select)
- Add semantic icons (InboxRound for inbox, SendRound for sent)
- Unify list container height to min-height: 60vh; max-height: 100vh
- Update CHANGELOG for v1.4.0

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 23:47:49 +08:00
Dream Hunter
9583f0e1c5 feat: upgrade version to v1.4.0 (#830) 2026-02-02 22:15:58 +08:00