mirror of
https://github.com/dreamhunter2333/cloudflare_temp_email.git
synced 2026-05-11 09:59:46 +08:00
feat: add NO_LIMIT_SEND_ROLE (#373)
This commit is contained in:
@@ -5,7 +5,8 @@
|
||||
|
||||
- Docs: Update new-address-api.md (#360)
|
||||
- feat: worker 增加 `ADMIN_USER_ROLE` 配置, 用于配置管理员用户角色,此角色的用户可访问 admin 管理页面 (#363)
|
||||
- feat: worker 增加 `SHOW_GITHUB` 配置, 用于配置是否显示 github 链接
|
||||
- feat: worker 增加 `DISABLE_SHOW_GITHUB` 配置, 用于配置是否显示 github 链接
|
||||
- feat: worker 增加 `NO_LIMIT_SEND_ROLE` 配置, 用于配置可以无限发送邮件的角色
|
||||
|
||||
## v0.6.1
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ export const useGlobalState = createGlobalState(
|
||||
cfTurnstileSiteKey: '',
|
||||
enableWebhook: false,
|
||||
isS3Enabled: false,
|
||||
showGithub: false,
|
||||
showGithub: true,
|
||||
})
|
||||
const settings = ref({
|
||||
fetched: false,
|
||||
|
||||
@@ -109,9 +109,10 @@ ENABLE_AUTO_REPLY = false
|
||||
# ENABLE_WEBHOOK = true
|
||||
# Footer text
|
||||
# COPYRIGHT = "Dream Hunter"
|
||||
# SHOW_GITHUB = true # Show GitHub link
|
||||
# DISABLE_SHOW_GITHUB = true # Disable Show GitHub link
|
||||
# default send balance, if not set, it will be 0
|
||||
# DEFAULT_SEND_BALANCE = 1
|
||||
# NO_LIMIT_SEND_ROLE = "vip" # the role which can send emails without limit
|
||||
# Turnstile verification configuration
|
||||
# CF_TURNSTILE_SITE_KEY = ""
|
||||
# CF_TURNSTILE_SECRET_KEY = ""
|
||||
|
||||
@@ -80,9 +80,10 @@ ENABLE_AUTO_REPLY = false
|
||||
# ENABLE_WEBHOOK = true
|
||||
# 前端界面页脚文本
|
||||
# COPYRIGHT = "Dream Hunter"
|
||||
# SHOW_GITHUB = true # 是否显示 GitHub 链接
|
||||
# DISABLE_SHOW_GITHUB = true # 是否显示 GitHub 链接
|
||||
# 默认发送邮件余额,如果不设置,将为 0
|
||||
# DEFAULT_SEND_BALANCE = 1
|
||||
# NO_LIMIT_SEND_ROLE = "vip" # 可以无限发送邮件的角色
|
||||
# Turnstile 人机验证配置
|
||||
# CF_TURNSTILE_SITE_KEY = ""
|
||||
# CF_TURNSTILE_SECRET_KEY = ""
|
||||
|
||||
@@ -35,7 +35,7 @@ api.get('/open_api/settings', async (c) => {
|
||||
"enableWebhook": getBooleanValue(c.env.ENABLE_WEBHOOK),
|
||||
"isS3Enabled": isS3Enabled(c),
|
||||
"version": CONSTANTS.VERSION,
|
||||
"showGithub": getBooleanValue(c.env.SHOW_GITHUB),
|
||||
"showGithub": !getBooleanValue(c.env.DISABLE_SHOW_GITHUB),
|
||||
});
|
||||
})
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Hono } from 'hono'
|
||||
|
||||
import { HonoCustomType } from "../types";
|
||||
import { getBooleanValue, getJsonSetting, checkCfTurnstile } from '../utils';
|
||||
import { getBooleanValue, getJsonSetting, checkCfTurnstile, getStringValue } from '../utils';
|
||||
import { newAddress, handleListQuery, deleteAddressWithData, getAddressPrefix, getAllowDomains } from '../common'
|
||||
import { CONSTANTS } from '../constants'
|
||||
import auto_reply from './auto_reply'
|
||||
@@ -49,6 +49,7 @@ api.delete('/api/mails/:id', async (c) => {
|
||||
|
||||
api.get('/api/settings', async (c) => {
|
||||
const { address, address_id } = c.get("jwtPayload")
|
||||
const user_role = c.get("userRolePayload")
|
||||
if (address_id && address_id > 0) {
|
||||
try {
|
||||
const db_address_id = await c.env.DB.prepare(
|
||||
@@ -82,7 +83,8 @@ api.get('/api/settings', async (c) => {
|
||||
} catch (e) {
|
||||
console.warn("Failed to update address")
|
||||
}
|
||||
const balance = await c.env.DB.prepare(
|
||||
const is_no_limit_send_balance = user_role && user_role === getStringValue(c.env.NO_LIMIT_SEND_ROLE);
|
||||
const balance = is_no_limit_send_balance ? 99999 : await c.env.DB.prepare(
|
||||
`SELECT balance FROM address_sender where address = ? and enabled = 1`
|
||||
).bind(address).first("balance");
|
||||
return c.json({
|
||||
|
||||
@@ -4,7 +4,7 @@ import { createMimeMessage } from 'mimetext';
|
||||
import { Resend } from 'resend';
|
||||
|
||||
import { CONSTANTS } from '../constants'
|
||||
import { getJsonSetting, getDomains, getIntValue, getBooleanValue } from '../utils';
|
||||
import { getJsonSetting, getDomains, getIntValue, getBooleanValue, getStringValue } from '../utils';
|
||||
import { GeoData } from '../models'
|
||||
import { handleListQuery } from '../common'
|
||||
import { HonoCustomType } from '../types';
|
||||
@@ -105,13 +105,17 @@ export const sendMail = async (
|
||||
if (!domains.includes(mailDomain)) {
|
||||
throw new Error("Invalid domain")
|
||||
}
|
||||
// check permission
|
||||
const balance = await c.env.DB.prepare(
|
||||
`SELECT balance FROM address_sender
|
||||
const user_role = c.get("userRolePayload");
|
||||
const is_no_limit_send_balance = user_role && user_role === getStringValue(c.env.NO_LIMIT_SEND_ROLE);
|
||||
if (!is_no_limit_send_balance) {
|
||||
// check permission
|
||||
const balance = await c.env.DB.prepare(
|
||||
`SELECT balance FROM address_sender
|
||||
where address = ? and enabled = 1`
|
||||
).bind(address).first<number>("balance");
|
||||
if (!balance || balance <= 0) {
|
||||
throw new Error("No balance")
|
||||
).bind(address).first<number>("balance");
|
||||
if (!balance || balance <= 0) {
|
||||
throw new Error("No balance")
|
||||
}
|
||||
}
|
||||
const {
|
||||
from_name, to_mail, to_name,
|
||||
@@ -154,7 +158,7 @@ export const sendMail = async (
|
||||
throw new Error("Please enable resend or verified address list")
|
||||
}
|
||||
// update balance
|
||||
if (!sendByVerifiedAddressList) {
|
||||
if (!sendByVerifiedAddressList && !is_no_limit_send_balance) {
|
||||
try {
|
||||
const { success } = await c.env.DB.prepare(
|
||||
`UPDATE address_sender SET balance = balance - 1 where address = ?`
|
||||
|
||||
6
worker/src/types.d.ts
vendored
6
worker/src/types.d.ts
vendored
@@ -33,9 +33,10 @@ export type Bindings = {
|
||||
ENABLE_USER_DELETE_EMAIL: string | boolean | undefined
|
||||
ENABLE_INDEX_ABOUT: string | boolean | undefined
|
||||
DEFAULT_SEND_BALANCE: number | string | undefined
|
||||
NO_LIMIT_SEND_ROLE: string | undefined | null
|
||||
ADMIN_CONTACT: string | undefined
|
||||
COPYRIGHT: string | undefined
|
||||
SHOW_GITHUB: string | boolean | undefined
|
||||
DISABLE_SHOW_GITHUB: string | boolean | undefined
|
||||
FORWARD_ADDRESS_LIST: string | string[] | undefined
|
||||
|
||||
// s3 config
|
||||
@@ -72,7 +73,8 @@ type UserPayload = {
|
||||
|
||||
type Variables = {
|
||||
userPayload: UserPayload,
|
||||
jwtPayload: JwtPayload
|
||||
userRolePayload: string | undefined | null,
|
||||
jwtPayload: JwtPayload,
|
||||
}
|
||||
|
||||
type HonoCustomType = {
|
||||
|
||||
@@ -75,6 +75,26 @@ const checkUserPayload = async (
|
||||
}
|
||||
}
|
||||
|
||||
const checkoutUserRolePayload = async (
|
||||
c: Context<HonoCustomType>
|
||||
): Promise<void> => {
|
||||
try {
|
||||
const token = c.req.raw.headers.get("x-user-access-token");
|
||||
if (!token) return;
|
||||
const payload = await Jwt.verify(token, c.env.JWT_SECRET, "HS256");
|
||||
// check expired
|
||||
if (!payload.exp) return;
|
||||
// exp is in seconds
|
||||
if (payload.exp < Math.floor(Date.now() / 1000)) {
|
||||
return;
|
||||
}
|
||||
if (typeof payload?.user_role !== "string") return;
|
||||
c.set("userRolePayload", payload.user_role);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
// api auth
|
||||
app.use('/api/*', async (c, next) => {
|
||||
// check header x-custom-auth
|
||||
@@ -90,6 +110,11 @@ app.use('/api/*', async (c, next) => {
|
||||
await next();
|
||||
return;
|
||||
}
|
||||
if (c.req.path.startsWith("/api/settings")
|
||||
|| c.req.path.startsWith("/api/send_mail")
|
||||
) {
|
||||
await checkoutUserRolePayload(c);
|
||||
}
|
||||
return jwt({ secret: c.env.JWT_SECRET, alg: "HS256" })(c, next);
|
||||
});
|
||||
// user_api auth
|
||||
|
||||
@@ -51,7 +51,7 @@ ENABLE_AUTO_REPLY = false
|
||||
# ENABLE_WEBHOOK = true
|
||||
# Footer text
|
||||
# COPYRIGHT = "Dream Hunter"
|
||||
# SHOW_GITHUB = true
|
||||
# DISABLE_SHOW_GITHUB = true
|
||||
# default send balance, if not set, it will be 0
|
||||
# DEFAULT_SEND_BALANCE = 1
|
||||
# Turnstile verification
|
||||
|
||||
Reference in New Issue
Block a user