mirror of
https://github.com/dreamhunter2333/cloudflare_temp_email.git
synced 2026-09-07 08:27:08 +08:00
feat: add address activity disable switch (#1138)
* feat: add address activity disable switch * style: separate address activity disable guards * docs: clarify address activity switch behavior
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
|
||||
### Features
|
||||
|
||||
- feat: |Worker| 新增 `DISABLE_ADDRESS_UPDATED_AT`,可关闭单地址及用户批量的主动保活刷新,并禁止内置手动及定时不活跃地址清理,降低 D1 写入量
|
||||
- feat: |Frontend| 新增 `VITE_DEFAULT_LANG` 构建变量,并支持通过 `index.html` 运行时配置覆盖前端设置
|
||||
- feat: |兑换码| 新增角色、发信额度及专属邮箱兑换与管理,完善并发保护和表单提示
|
||||
- feat: |邮件| 新增可选的已读/未读状态,支持点击邮件自动已读和手动切换状态
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
### Features
|
||||
|
||||
- feat: |Worker| Add `DISABLE_ADDRESS_UPDATED_AT` to disable individual and user-wide address activity keep-alive updates and built-in manual/scheduled inactive-address cleanup, reducing D1 writes
|
||||
- feat: |Frontend| Add the `VITE_DEFAULT_LANG` build variable and support overriding frontend settings through runtime configuration in `index.html`
|
||||
- feat: |Redemption Codes| Add role, sending-credit and custom-mailbox redemption with Admin management, concurrency protection and form validation
|
||||
- feat: |Mail| Add optional read/unread status with click-to-read and manual status switching
|
||||
|
||||
@@ -38,6 +38,7 @@ When `ADMIN_API_IP_WHITELIST` is unset or empty, source IPs are not restricted.
|
||||
| `MIN_ADDRESS_LEN` | Number | Minimum length of `email address` name | `1` |
|
||||
| `MAX_ADDRESS_LEN` | Number | Maximum length of `email address` name | `30` |
|
||||
| `DISABLE_CUSTOM_ADDRESS_NAME` | Text/JSON | Disable custom email address names, if set to true, users cannot enter custom names and they will be auto-generated | `true` |
|
||||
| `DISABLE_ADDRESS_UPDATED_AT` | Text/JSON | Defaults to `false`. Set to `true` to skip individual and bulk activity timestamp updates triggered by user settings, mailbox access, sending mail, and other address activity. Initial timestamps for new addresses and password generation/change/reset behavior, including their `updated_at` updates, remain unchanged. Manual `/admin/cleanup` requests with `cleanType=inactiveAddress` return `403`; scheduled tasks skip that type and continue other cleanup. Cleanup by creation time, other cleanup types, and administrator-defined SQL are unaffected. Set back to `false` to restore normal behavior without backfilling activity from the disabled period | `true` |
|
||||
| `ADDRESS_CHECK_REGEX` | Text | Regular expression for `email address` name, used for validation only | `^(?!.*admin).*` |
|
||||
| `ADDRESS_REGEX` | Text | Regular expression to replace illegal symbols in `email address` name, symbols not in the regex will be replaced. Default is `[^a-z0-9]` if not set. Use with caution as some symbols may prevent email reception | `[^a-z0-9]` |
|
||||
| `DEFAULT_DOMAINS` | JSON | Default domains available to users (not logged in or users without assigned roles) | `["awsl.uk", "dreamhunter2333.xyz"]` |
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
| `MIN_ADDRESS_LEN` | 数字 | `邮箱名称` 的最小长度 | `1` |
|
||||
| `MAX_ADDRESS_LEN` | 数字 | `邮箱名称` 的最大长度 | `30` |
|
||||
| `DISABLE_CUSTOM_ADDRESS_NAME` | 文本/JSON | 禁用自定义邮箱地址名称,如果设置为 true,则用户无法输入自定义邮箱名称,将由后台自动生成 | `true` |
|
||||
| `DISABLE_ADDRESS_UPDATED_AT` | 文本/JSON | 默认 `false`。设为 `true` 时跳过用户设置、邮箱访问、发信等触发的单地址及批量活跃时间更新。创建地址的初始时间、生成/修改/重置密码及其 `updated_at` 更新不变。手动 `/admin/cleanup` 的 `cleanType=inactiveAddress` 返回 `403`,定时任务跳过该项并继续其他清理;按创建时间清理、其他清理类型及管理员自定义 SQL 不受影响。改回 `false` 恢复原有行为,不补齐禁用期间的活跃记录 | `true` |
|
||||
| `ADDRESS_CHECK_REGEX` | 文本 | `邮箱名称` 的正则表达式, 只用于检查 | `^(?!.*admin).*` |
|
||||
| `ADDRESS_REGEX` | 文本 | `邮箱名称` 替换非法符号的正则表达式, 不在其中的符号将被替换,如果不设置,默认为 `[^a-z0-9]`, 需谨慎使用, 有些符号可能导致无法收件 | `[^a-z0-9]` |
|
||||
| `DEFAULT_DOMAINS` | JSON | 默认用户可用的域名(未登录或未分配角色的用户) | `["awsl.uk", "dreamhunter2333.xyz"]` |
|
||||
|
||||
@@ -98,7 +98,11 @@ export default {
|
||||
const msgs = i18n.getMessagesbyContext(c);
|
||||
const { cleanType, cleanDays } = await c.req.json();
|
||||
try {
|
||||
await cleanup(c, cleanType, cleanDays);
|
||||
const success = await cleanup(c, cleanType, cleanDays);
|
||||
// Report disabled cleanup as forbidden rather than successful.
|
||||
if (!success) {
|
||||
return c.text(msgs.InactiveAddressCleanupDisabledMsg, 403);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return c.text(`${msgs.OperationFailedMsg}: ${(error as Error).message}`, 500)
|
||||
|
||||
@@ -246,6 +246,8 @@ export function updateAddressUpdatedAt(
|
||||
if (!address) {
|
||||
return;
|
||||
}
|
||||
// Skip activity timestamp writes when activity tracking is disabled.
|
||||
if (getBooleanValue(c.env.DISABLE_ADDRESS_UPDATED_AT)) return;
|
||||
// update address updated_at asynchronously
|
||||
c.executionCtx.waitUntil((async () => {
|
||||
try {
|
||||
@@ -268,6 +270,8 @@ export function updateUserAddressesUpdatedAt(
|
||||
if (!userId) {
|
||||
return;
|
||||
}
|
||||
// Apply the same activity tracking switch to bulk updates.
|
||||
if (getBooleanValue(c.env.DISABLE_ADDRESS_UPDATED_AT)) return;
|
||||
c.executionCtx.waitUntil((async () => {
|
||||
try {
|
||||
await c.env.DB.prepare(
|
||||
@@ -494,6 +498,10 @@ export const cleanup = async (
|
||||
cleanType: string | undefined | null,
|
||||
cleanDays: number | undefined | null
|
||||
): Promise<boolean> => {
|
||||
// Frozen activity timestamps cannot reliably identify inactive addresses.
|
||||
if (cleanType === "inactiveAddress" && getBooleanValue(c.env.DISABLE_ADDRESS_UPDATED_AT)) {
|
||||
return false;
|
||||
}
|
||||
const msgs = i18n.getMessagesbyContext(c);
|
||||
if (!cleanType || typeof cleanDays !== 'number' || cleanDays < 0 || cleanDays > 1000) {
|
||||
throw new Error(msgs.InvalidCleanupConfigMsg)
|
||||
|
||||
@@ -88,6 +88,7 @@ const messages: LocaleMessages = {
|
||||
EnableSendMailForDomainMsg: "Please enable SEND_MAIL for this domain first",
|
||||
InvalidCleanupConfigMsg: "Invalid cleanType or cleanDays",
|
||||
InvalidCleanTypeMsg: "Invalid cleanType",
|
||||
InactiveAddressCleanupDisabledMsg: "Address activity updates are disabled; cleanup by inactivity is not allowed",
|
||||
EnableKVForMailVerifyMsg: "Please enable KV first if you want to enable mail verify",
|
||||
VerifyMailDomainInvalidMsg: "VerifyMailSender domain must be in",
|
||||
InvalidMaxAddressCountMsg: "Invalid maxAddressCount",
|
||||
|
||||
@@ -86,6 +86,7 @@ export type LocaleMessages = {
|
||||
EnableSendMailForDomainMsg: string
|
||||
InvalidCleanupConfigMsg: string
|
||||
InvalidCleanTypeMsg: string
|
||||
InactiveAddressCleanupDisabledMsg: string
|
||||
EnableKVForMailVerifyMsg: string
|
||||
VerifyMailDomainInvalidMsg: string
|
||||
InvalidMaxAddressCountMsg: string
|
||||
|
||||
@@ -88,6 +88,7 @@ const messages: LocaleMessages = {
|
||||
EnableSendMailForDomainMsg: "请先为此域名启用 SEND_MAIL",
|
||||
InvalidCleanupConfigMsg: "无效的 cleanType 或 cleanDays",
|
||||
InvalidCleanTypeMsg: "无效的 cleanType",
|
||||
InactiveAddressCleanupDisabledMsg: "已禁用地址活跃时间更新,不能按不活跃时间清理地址",
|
||||
EnableKVForMailVerifyMsg: "如果要启用邮件验证,请先启用 KV",
|
||||
VerifyMailDomainInvalidMsg: "验证邮件发送者域名必须在",
|
||||
InvalidMaxAddressCountMsg: "无效的 maxAddressCount",
|
||||
|
||||
Vendored
+1
@@ -42,6 +42,7 @@ type Bindings = {
|
||||
RANDOM_SUBDOMAIN_DOMAINS: string | string[] | undefined
|
||||
RANDOM_SUBDOMAIN_LENGTH: string | number | undefined
|
||||
DISABLE_CUSTOM_ADDRESS_NAME: string | boolean | undefined
|
||||
DISABLE_ADDRESS_UPDATED_AT: string | boolean | undefined
|
||||
CREATE_ADDRESS_DEFAULT_DOMAIN_FIRST: string | boolean | undefined
|
||||
ADMIN_USER_ROLE: string | undefined
|
||||
USER_DEFAULT_ROLE: string | UserRole | undefined
|
||||
|
||||
@@ -41,6 +41,8 @@ PREFIX = "tmp"
|
||||
# MAX_ADDRESS_LEN = 30
|
||||
# Disable custom email address name, if set true, users cannot input custom email name, will auto generate
|
||||
# DISABLE_CUSTOM_ADDRESS_NAME = true
|
||||
# Disable address activity keep-alive updates and built-in manual/scheduled cleanup by inactivity. Defaults to false.
|
||||
# DISABLE_ADDRESS_UPDATED_AT = true
|
||||
# IF YOU WANT TO MAKE YOUR SITE PRIVATE, UNCOMMENT THE FOLLOWING LINES
|
||||
# PASSWORDS = ["123", "456"]
|
||||
# For admin panel
|
||||
|
||||
Reference in New Issue
Block a user