mirror of
https://github.com/dreamhunter2333/cloudflare_temp_email.git
synced 2026-07-06 14:52:09 +08:00
feat: admin cleanup tab && admin sendbox tab (#126)
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { Hono } from 'hono'
|
||||
import { Jwt } from 'hono/utils/jwt'
|
||||
import { getSendbox } from './send_mail_api'
|
||||
|
||||
const api = new Hono()
|
||||
|
||||
@@ -179,6 +180,11 @@ api.post('/admin/address_sender', async (c) => {
|
||||
})
|
||||
})
|
||||
|
||||
api.get('/admin/sendbox', async (c) => {
|
||||
const { address, limit, offset } = c.req.query();
|
||||
return getSendbox(c, address, limit, offset);
|
||||
})
|
||||
|
||||
api.get('/admin/statistics', async (c) => {
|
||||
const { count: mailCountV1 } = await c.env.DB.prepare(`
|
||||
SELECT count(*) as count FROM mails`
|
||||
@@ -192,11 +198,51 @@ api.get('/admin/statistics', async (c) => {
|
||||
const { count: activeUserCount7days } = await c.env.DB.prepare(`
|
||||
SELECT count(*) as count FROM address where updated_at > datetime('now', '-7 day')`
|
||||
).first();
|
||||
const { count: sendMailCount } = await c.env.DB.prepare(`
|
||||
SELECT count(*) as count FROM sendbox`
|
||||
).first();
|
||||
return c.json({
|
||||
mailCount: (mailCountV1 || 0) + (mailCount || 0),
|
||||
userCount: addressCount,
|
||||
activeUserCount7days: activeUserCount7days
|
||||
activeUserCount7days: activeUserCount7days,
|
||||
sendMailCount: sendMailCount
|
||||
})
|
||||
});
|
||||
|
||||
api.post('/admin/cleanup', async (c) => {
|
||||
const { cleanType, cleanDays } = await c.req.json();
|
||||
if (!cleanType || !cleanDays || cleanDays < 0 || cleanDays > 30) {
|
||||
return c.text("Invalid cleanType or cleanDays", 400)
|
||||
}
|
||||
console.log(`Cleanup ${cleanType} before ${cleanDays} days`);
|
||||
switch (cleanType) {
|
||||
case "mails":
|
||||
await c.env.DB.prepare(`
|
||||
DELETE FROM raw_mails WHERE created_at < datetime('now', '-${cleanDays} day')`
|
||||
).run();
|
||||
break;
|
||||
case "mails_unknow":
|
||||
await c.env.DB.prepare(`
|
||||
DELETE FROM raw_mails WHERE address NOT IN
|
||||
(select concat('${c.env.PREFIX}', name) from address) AND created_at < datetime('now', '-${cleanDays} day')`
|
||||
).run();
|
||||
break;
|
||||
case "address":
|
||||
await c.env.DB.prepare(`
|
||||
DELETE FROM address WHERE updated_at < datetime('now', '-${cleanDays} day')`
|
||||
).run();
|
||||
break;
|
||||
case "sendbox":
|
||||
await c.env.DB.prepare(`
|
||||
DELETE FROM sendbox WHERE created_at < datetime('now', '-${cleanDays} day')`
|
||||
).run();
|
||||
break;
|
||||
default:
|
||||
return c.text("Invalid cleanType", 400)
|
||||
}
|
||||
return c.json({
|
||||
success: true
|
||||
})
|
||||
})
|
||||
|
||||
export { api }
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { Hono } from 'hono'
|
||||
import { Jwt } from 'hono/utils/jwt'
|
||||
|
||||
import { getDomains, getPasswords } from './utils';
|
||||
|
||||
const api = new Hono()
|
||||
|
||||
api.get('/api/mails', async (c) => {
|
||||
@@ -124,13 +126,14 @@ api.post('/api/settings', async (c) => {
|
||||
api.get('/open_api/settings', async (c) => {
|
||||
// check header x-custom-auth
|
||||
let needAuth = false;
|
||||
if (c.env.PASSWORDS && c.env.PASSWORDS.length > 0) {
|
||||
const passwords = getPasswords(c);
|
||||
if (passwords && passwords.length > 0) {
|
||||
const auth = c.req.raw.headers.get("x-custom-auth");
|
||||
needAuth = !c.env.PASSWORDS.includes(auth);
|
||||
needAuth = !passwords.includes(auth);
|
||||
}
|
||||
return c.json({
|
||||
"prefix": c.env.PREFIX,
|
||||
"domains": c.env.DOMAINS,
|
||||
"domains": getDomains(c),
|
||||
"needAuth": needAuth,
|
||||
});
|
||||
})
|
||||
@@ -151,8 +154,9 @@ api.get('/api/new_address', async (c) => {
|
||||
return c.text("Name too long (max 100)", 400)
|
||||
}
|
||||
// check domain, generate random domain
|
||||
if (!domain || !c.env.DOMAINS.includes(domain)) {
|
||||
domain = c.env.DOMAINS[Math.floor(Math.random() * c.env.DOMAINS.length)];
|
||||
const domains = getDomains(c);
|
||||
if (!domain || !domains.includes(domain)) {
|
||||
domain = domains[Math.floor(Math.random() * domains.length)];
|
||||
}
|
||||
// create address
|
||||
const emailAddress = c.env.PREFIX + name + "@" + domain
|
||||
|
||||
@@ -110,12 +110,10 @@ api.post('/api/send_mail', async (c) => {
|
||||
return c.json({ status: "ok" });
|
||||
})
|
||||
|
||||
api.get('/api/sendbox', async (c) => {
|
||||
const { address } = c.get("jwtPayload")
|
||||
const getSendbox = async (c, address, limit, offset) => {
|
||||
if (!address) {
|
||||
return c.json({ "error": "No address" }, 400)
|
||||
}
|
||||
const { limit, offset } = c.req.query();
|
||||
if (!limit || limit < 0 || limit > 100) {
|
||||
return c.text("Invalid limit", 400)
|
||||
}
|
||||
@@ -137,6 +135,12 @@ api.get('/api/sendbox', async (c) => {
|
||||
results: results,
|
||||
count: count
|
||||
})
|
||||
}
|
||||
|
||||
api.get('/api/sendbox', async (c) => {
|
||||
const { address } = c.get("jwtPayload")
|
||||
const { limit, offset } = c.req.query();
|
||||
return getSendbox(c, address, limit, offset);
|
||||
})
|
||||
|
||||
export { api }
|
||||
export { api, getSendbox }
|
||||
|
||||
47
worker/src/utils.js
Normal file
47
worker/src/utils.js
Normal file
@@ -0,0 +1,47 @@
|
||||
export const getDomains = (c) => {
|
||||
if (!c.env.DOMAINS) {
|
||||
return [];
|
||||
}
|
||||
// check if DOMAINS is an array, if not use json.parse
|
||||
if (!Array.isArray(c.env.DOMAINS)) {
|
||||
try {
|
||||
return JSON.parse(c.env.DOMAINS);
|
||||
} catch (e) {
|
||||
console.error("Failed to parse DOMAINS", e);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
return c.env.DOMAINS;
|
||||
}
|
||||
|
||||
export const getPasswords = (c) => {
|
||||
if (!c.env.PASSWORDS) {
|
||||
return [];
|
||||
}
|
||||
// check if PASSWORDS is an array, if not use json.parse
|
||||
if (!Array.isArray(c.env.PASSWORDS)) {
|
||||
try {
|
||||
return JSON.parse(c.env.PASSWORDS);
|
||||
} catch (e) {
|
||||
console.error("Failed to parse PASSWORDS", e);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
return c.env.PASSWORDS;
|
||||
}
|
||||
|
||||
export const getAdminPasswords = (c) => {
|
||||
if (!c.env.ADMIN_PASSWORDS) {
|
||||
return [];
|
||||
}
|
||||
// check if ADMIN_PASSWORDS is an array, if not use json.parse
|
||||
if (!Array.isArray(c.env.ADMIN_PASSWORDS)) {
|
||||
try {
|
||||
return JSON.parse(c.env.ADMIN_PASSWORDS);
|
||||
} catch (e) {
|
||||
console.error("Failed to parse ADMIN_PASSWORDS", e);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
return c.env.ADMIN_PASSWORDS;
|
||||
}
|
||||
@@ -7,14 +7,16 @@ import { api as adminApi } from './admin_api';
|
||||
import { api as apiV1 } from './api_v1';
|
||||
import { api as apiSendMail } from './send_mail_api'
|
||||
import { email } from './email';
|
||||
import { getAdminPasswords, getPasswords } from './utils';
|
||||
|
||||
const app = new Hono()
|
||||
app.use('/*', cors());
|
||||
app.use('/api/*', async (c, next) => {
|
||||
// check header x-custom-auth
|
||||
if (c.env.PASSWORDS && c.env.PASSWORDS.length > 0) {
|
||||
const passwords = getPasswords(c);
|
||||
if (passwords && passwords.length > 0) {
|
||||
const auth = c.req.raw.headers.get("x-custom-auth");
|
||||
if (!auth || !c.env.PASSWORDS.includes(auth)) {
|
||||
if (!auth || !passwords.includes(auth)) {
|
||||
return c.text("Need Password", 401)
|
||||
}
|
||||
}
|
||||
@@ -27,9 +29,10 @@ app.use('/api/*', async (c, next) => {
|
||||
|
||||
app.use('/admin/*', async (c, next) => {
|
||||
// check header x-admin-auth
|
||||
if (c.env.ADMIN_PASSWORDS && c.env.ADMIN_PASSWORDS.length > 0) {
|
||||
const adminPasswords = getAdminPasswords(c);
|
||||
if (adminPasswords && adminPasswords.length > 0) {
|
||||
const adminAuth = c.req.raw.headers.get("x-admin-auth");
|
||||
if (adminAuth && c.env.ADMIN_PASSWORDS.includes(adminAuth)) {
|
||||
if (adminAuth && adminPasswords.includes(adminAuth)) {
|
||||
await next();
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user