mirror of
https://github.com/dreamhunter2333/cloudflare_temp_email.git
synced 2026-09-05 07:27:27 +08:00
feat: use common function handleListQuery when query by page (#220)
This commit is contained in:
@@ -371,8 +371,15 @@ onBeforeUnmount(() => {
|
|||||||
</template>
|
</template>
|
||||||
{{ t('reply') }}
|
{{ t('reply') }}
|
||||||
</n-button>
|
</n-button>
|
||||||
|
<n-button size="small" tertiary type="info" @click="showTextMail = !showTextMail">
|
||||||
|
{{ showTextMail ? t('showHtmlMail') : t('showTextMail') }}
|
||||||
|
</n-button>
|
||||||
</n-space>
|
</n-space>
|
||||||
<div v-html="curMail.message" style="margin-top: 10px;"></div>
|
<pre v-if="showTextMail" style="margin-top: 10px;">{{ curMail.text }}</pre>
|
||||||
|
<iframe v-else-if="useIframeShowMail" :srcdoc="curMail.message"
|
||||||
|
style="margin-top: 10px;width: 100%; height: 100%;">
|
||||||
|
</iframe>
|
||||||
|
<div v-else v-html="curMail.message" style="margin-top: 10px;"></div>
|
||||||
</n-card>
|
</n-card>
|
||||||
</n-drawer-content>
|
</n-drawer-content>
|
||||||
</n-drawer>
|
</n-drawer>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { CONSTANTS } from '../constants';
|
import { CONSTANTS } from '../constants';
|
||||||
import { getJsonSetting, saveSetting, checkUserPassword, getDomains } from '../utils';
|
import { getJsonSetting, saveSetting, checkUserPassword, getDomains } from '../utils';
|
||||||
import { UserSettings, GeoData, UserInfo } from "../models";
|
import { UserSettings, GeoData, UserInfo } from "../models";
|
||||||
|
import { handleListQuery } from '../common'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
getSetting: async (c) => {
|
getSetting: async (c) => {
|
||||||
@@ -29,49 +30,23 @@ export default {
|
|||||||
},
|
},
|
||||||
getUsers: async (c) => {
|
getUsers: async (c) => {
|
||||||
const { limit, offset, query } = c.req.query();
|
const { limit, offset, query } = c.req.query();
|
||||||
if (!limit || limit < 0 || limit > 100) {
|
|
||||||
return c.text("Invalid limit", 400)
|
|
||||||
}
|
|
||||||
if (!offset || offset < 0) {
|
|
||||||
return c.text("Invalid offset", 400)
|
|
||||||
}
|
|
||||||
if (query) {
|
if (query) {
|
||||||
const { results } = await c.env.DB.prepare(
|
return await handleListQuery(c,
|
||||||
`SELECT u.id, u.user_email, u.created_at, u.updated_at,`
|
`SELECT u.id, u.user_email, u.created_at, u.updated_at,`
|
||||||
+ ` (SELECT COUNT(*) FROM users_address WHERE user_id = u.id) AS address_count`
|
+ ` (SELECT COUNT(*) FROM users_address WHERE user_id = u.id) AS address_count`
|
||||||
+ ` FROM users u`
|
+ ` FROM users u`
|
||||||
+ ` where u.user_email like ?`
|
+ ` where u.user_email like ?`,
|
||||||
+ ` order by u.id desc limit ? offset ?`
|
`SELECT count(*) as count FROM users where user_email like ?`,
|
||||||
).bind(`%${query}%`, limit, offset).all();
|
[`%${query}%`], limit, offset
|
||||||
let count = 0;
|
);
|
||||||
if (offset == 0) {
|
|
||||||
const { count: userCount } = await c.env.DB.prepare(
|
|
||||||
`SELECT count(*) as count FROM users where user_email like ?`
|
|
||||||
).bind(`%${query}%`).first();
|
|
||||||
count = userCount;
|
|
||||||
}
|
|
||||||
return c.json({
|
|
||||||
results: results,
|
|
||||||
count: count
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
const { results } = await c.env.DB.prepare(
|
return await handleListQuery(c,
|
||||||
`SELECT u.id, u.user_email, u.created_at, u.updated_at,`
|
`SELECT u.id, u.user_email, u.created_at, u.updated_at,`
|
||||||
+ ` (SELECT COUNT(*) FROM users_address WHERE user_id = u.id) AS address_count`
|
+ ` (SELECT COUNT(*) FROM users_address WHERE user_id = u.id) AS address_count`
|
||||||
+ ` FROM users u`
|
+ ` FROM users u`,
|
||||||
+ ` order by u.id desc limit ? offset ?`
|
`SELECT count(*) as count FROM users`,
|
||||||
).bind(limit, offset).all();
|
[], limit, offset
|
||||||
let count = 0;
|
);
|
||||||
if (offset == 0) {
|
|
||||||
const { count: userCount } = await c.env.DB.prepare(
|
|
||||||
`SELECT count(*) as count FROM users`
|
|
||||||
).first();
|
|
||||||
count = userCount;
|
|
||||||
}
|
|
||||||
return c.json({
|
|
||||||
results: results,
|
|
||||||
count: count
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
createUser: async (c) => {
|
createUser: async (c) => {
|
||||||
const { email, password } = await c.req.json();
|
const { email, password } = await c.req.json();
|
||||||
|
|||||||
@@ -10,51 +10,25 @@ const api = new Hono()
|
|||||||
|
|
||||||
api.get('/admin/address', async (c) => {
|
api.get('/admin/address', async (c) => {
|
||||||
const { limit, offset, query } = c.req.query();
|
const { limit, offset, query } = c.req.query();
|
||||||
if (!limit || limit < 0 || limit > 100) {
|
|
||||||
return c.text("Invalid limit", 400)
|
|
||||||
}
|
|
||||||
if (!offset || offset < 0) {
|
|
||||||
return c.text("Invalid offset", 400)
|
|
||||||
}
|
|
||||||
if (query) {
|
if (query) {
|
||||||
const { results } = await c.env.DB.prepare(
|
return await handleListQuery(c,
|
||||||
`SELECT a.*,`
|
`SELECT a.*,`
|
||||||
+ ` (SELECT COUNT(*) FROM raw_mails WHERE address = a.name) AS mail_count,`
|
+ ` (SELECT COUNT(*) FROM raw_mails WHERE address = a.name) AS mail_count,`
|
||||||
+ ` (SELECT COUNT(*) FROM sendbox WHERE address = a.name) AS send_count`
|
+ ` (SELECT COUNT(*) FROM sendbox WHERE address = a.name) AS send_count`
|
||||||
+ ` FROM address a`
|
+ ` FROM address a`
|
||||||
+ ` where name like ?`
|
+ ` where name like ?`,
|
||||||
+ ` order by id desc limit ? offset ?`
|
`SELECT count(*) as count FROM address where name like ?`,
|
||||||
).bind(`%${query}%`, limit, offset).all();
|
[`%${query}%`], limit, offset
|
||||||
let count = 0;
|
);
|
||||||
if (offset == 0) {
|
|
||||||
const { count: addressCount } = await c.env.DB.prepare(
|
|
||||||
`SELECT count(*) as count FROM address where name like ?`
|
|
||||||
).bind(`%${query}%`).first();
|
|
||||||
count = addressCount;
|
|
||||||
}
|
|
||||||
return c.json({
|
|
||||||
results: results,
|
|
||||||
count: count
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
const { results } = await c.env.DB.prepare(
|
return await handleListQuery(c,
|
||||||
`SELECT a.*,`
|
`SELECT a.*,`
|
||||||
+ ` (SELECT COUNT(*) FROM raw_mails WHERE address = a.name) AS mail_count,`
|
+ ` (SELECT COUNT(*) FROM raw_mails WHERE address = a.name) AS mail_count,`
|
||||||
+ ` (SELECT COUNT(*) FROM sendbox WHERE address = a.name) AS send_count`
|
+ ` (SELECT COUNT(*) FROM sendbox WHERE address = a.name) AS send_count`
|
||||||
+ ` FROM address a`
|
+ ` FROM address a`,
|
||||||
+ ` order by id desc limit ? offset ?`
|
`SELECT count(*) as count FROM address`,
|
||||||
).bind(limit, offset).all();
|
[], limit, offset
|
||||||
let count = 0;
|
);
|
||||||
if (offset == 0) {
|
|
||||||
const { count: addressCount } = await c.env.DB.prepare(
|
|
||||||
`SELECT count(*) as count FROM address`
|
|
||||||
).first();
|
|
||||||
count = addressCount;
|
|
||||||
}
|
|
||||||
return c.json({
|
|
||||||
results: results,
|
|
||||||
count: count
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
api.post('/admin/new_address', async (c) => {
|
api.post('/admin/new_address', async (c) => {
|
||||||
@@ -100,7 +74,7 @@ api.get('/admin/show_password/:id', async (c) => {
|
|||||||
const jwt = await Jwt.sign({
|
const jwt = await Jwt.sign({
|
||||||
address: name,
|
address: name,
|
||||||
address_id: id
|
address_id: id
|
||||||
}, c.env.JWT_SECRET)
|
}, c.env.JWT_SECRET, "HS256")
|
||||||
return c.json({
|
return c.json({
|
||||||
jwt: jwt
|
jwt: jwt
|
||||||
})
|
})
|
||||||
@@ -184,42 +158,18 @@ api.post('/admin/address_sender', async (c) => {
|
|||||||
|
|
||||||
api.get('/admin/sendbox', async (c) => {
|
api.get('/admin/sendbox', async (c) => {
|
||||||
const { address, limit, offset } = c.req.query();
|
const { address, limit, offset } = c.req.query();
|
||||||
if (!limit || limit < 0 || limit > 100) {
|
if (address) {
|
||||||
return c.text("Invalid limit", 400)
|
return await handleListQuery(c,
|
||||||
|
`SELECT * FROM sendbox where address = ? `,
|
||||||
|
`SELECT count(*) as count FROM sendbox where address = ? `,
|
||||||
|
[address], limit, offset
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (!offset || offset < 0) {
|
return await handleListQuery(c,
|
||||||
return c.text("Invalid offset", 400)
|
`SELECT * FROM sendbox `,
|
||||||
}
|
`SELECT count(*) as count FROM sendbox `,
|
||||||
if (!address) {
|
[], limit, offset
|
||||||
const { results } = await c.env.DB.prepare(
|
);
|
||||||
`SELECT * FROM sendbox order by id desc limit ? offset ?`
|
|
||||||
).bind(limit, offset).all();
|
|
||||||
let count = 0;
|
|
||||||
if (offset == 0) {
|
|
||||||
const { count: mailCount } = await c.env.DB.prepare(
|
|
||||||
`SELECT count(*) as count FROM sendbox`
|
|
||||||
).first();
|
|
||||||
count = mailCount;
|
|
||||||
}
|
|
||||||
return c.json({
|
|
||||||
results: results,
|
|
||||||
count: count
|
|
||||||
})
|
|
||||||
}
|
|
||||||
const { results } = await c.env.DB.prepare(
|
|
||||||
`SELECT * FROM sendbox where address = ? order by id desc limit ? offset ?`
|
|
||||||
).bind(address, limit, offset).all();
|
|
||||||
let count = 0;
|
|
||||||
if (offset == 0) {
|
|
||||||
const { count: mailCount } = await c.env.DB.prepare(
|
|
||||||
`SELECT count(*) as count FROM sendbox where address = ?`
|
|
||||||
).bind(address).first();
|
|
||||||
count = mailCount;
|
|
||||||
}
|
|
||||||
return c.json({
|
|
||||||
results: results,
|
|
||||||
count: count
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
api.get('/admin/statistics', async (c) => {
|
api.get('/admin/statistics', async (c) => {
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { Hono } from 'hono'
|
||||||
|
|
||||||
|
import { getDomains, getPasswords, getBooleanValue } from './utils';
|
||||||
|
|
||||||
|
const api = new Hono()
|
||||||
|
|
||||||
|
api.get('/open_api/settings', async (c) => {
|
||||||
|
// check header x-custom-auth
|
||||||
|
let needAuth = false;
|
||||||
|
const passwords = getPasswords(c);
|
||||||
|
if (passwords && passwords.length > 0) {
|
||||||
|
const auth = c.req.raw.headers.get("x-custom-auth");
|
||||||
|
needAuth = !passwords.includes(auth);
|
||||||
|
}
|
||||||
|
return c.json({
|
||||||
|
"prefix": c.env.PREFIX,
|
||||||
|
"domains": getDomains(c),
|
||||||
|
"needAuth": needAuth,
|
||||||
|
"adminContact": c.env.ADMIN_CONTACT,
|
||||||
|
"enableUserCreateEmail": getBooleanValue(c.env.ENABLE_USER_CREATE_EMAIL),
|
||||||
|
"enableUserDeleteEmail": getBooleanValue(c.env.ENABLE_USER_DELETE_EMAIL),
|
||||||
|
"enableAutoReply": getBooleanValue(c.env.ENABLE_AUTO_REPLY),
|
||||||
|
"copyright": c.env.COPYRIGHT,
|
||||||
|
"cfTurnstileSiteKey": c.env.CF_TURNSTILE_SITE_KEY,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
export { api }
|
||||||
@@ -48,7 +48,7 @@ export const newAddress = async (c, name, domain, enablePrefix) => {
|
|||||||
const jwt = await Jwt.sign({
|
const jwt = await Jwt.sign({
|
||||||
address: name,
|
address: name,
|
||||||
address_id: address_id
|
address_id: address_id
|
||||||
}, c.env.JWT_SECRET)
|
}, c.env.JWT_SECRET, "HS256")
|
||||||
return c.json({
|
return c.json({
|
||||||
jwt: jwt
|
jwt: jwt
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
import { Hono } from 'hono'
|
import { Hono } from 'hono'
|
||||||
|
|
||||||
|
import { getBooleanValue, getJsonSetting, checkCfTurnstile } from '../utils';
|
||||||
|
import { newAddress, handleListQuery } from '../common'
|
||||||
|
import { CONSTANTS } from '../constants'
|
||||||
import auto_reply from './auto_reply'
|
import auto_reply from './auto_reply'
|
||||||
|
|
||||||
const api = new Hono()
|
const api = new Hono()
|
||||||
@@ -7,4 +10,137 @@ const api = new Hono()
|
|||||||
api.get('/api/auto_reply', auto_reply.getAutoReply)
|
api.get('/api/auto_reply', auto_reply.getAutoReply)
|
||||||
api.post('/api/auto_reply', auto_reply.saveAutoReply)
|
api.post('/api/auto_reply', auto_reply.saveAutoReply)
|
||||||
|
|
||||||
|
api.get('/api/mails', async (c) => {
|
||||||
|
const { address } = c.get("jwtPayload")
|
||||||
|
if (!address) {
|
||||||
|
return c.json({ "error": "No address" }, 400)
|
||||||
|
}
|
||||||
|
const { limit, offset } = c.req.query();
|
||||||
|
return await handleListQuery(c,
|
||||||
|
`SELECT * FROM raw_mails where address = ?`,
|
||||||
|
`SELECT count(*) as count FROM raw_mails where address = ?`,
|
||||||
|
[address], limit, offset
|
||||||
|
);
|
||||||
|
})
|
||||||
|
|
||||||
|
api.delete('/api/mails/:id', async (c) => {
|
||||||
|
if (!getBooleanValue(c.env.ENABLE_USER_DELETE_EMAIL)) {
|
||||||
|
return c.text("User delete email is disabled", 403)
|
||||||
|
}
|
||||||
|
const { address } = c.get("jwtPayload")
|
||||||
|
const { id } = c.req.param();
|
||||||
|
const { success } = await c.env.DB.prepare(
|
||||||
|
`DELETE FROM raw_mails WHERE address = ? and id = ? `
|
||||||
|
).bind(address, id).run();
|
||||||
|
return c.json({
|
||||||
|
success: success
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
api.get('/api/settings', async (c) => {
|
||||||
|
const { address, address_id } = c.get("jwtPayload")
|
||||||
|
if (address_id && address_id > 0) {
|
||||||
|
try {
|
||||||
|
const db_address_id = await c.env.DB.prepare(
|
||||||
|
`SELECT id FROM address where id = ? `
|
||||||
|
).bind(address_id).first("id");
|
||||||
|
if (!db_address_id) {
|
||||||
|
return c.text("Invalid address", 400)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
return c.text("Invalid address", 400)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// check address id
|
||||||
|
try {
|
||||||
|
if (!address_id) {
|
||||||
|
const db_address_id = await c.env.DB.prepare(
|
||||||
|
`SELECT id FROM address where name = ? `
|
||||||
|
).bind(address).first("id");
|
||||||
|
if (!db_address_id) {
|
||||||
|
return c.text("Invalid address", 400)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
return c.text("Invalid address", 400)
|
||||||
|
}
|
||||||
|
// update address updated_at
|
||||||
|
try {
|
||||||
|
c.env.DB.prepare(
|
||||||
|
`UPDATE address SET updated_at = datetime('now') where name = ?`
|
||||||
|
).bind(address).run();
|
||||||
|
} catch (e) {
|
||||||
|
console.warn("Failed to update address")
|
||||||
|
}
|
||||||
|
const { count: mailCountV1 } = await c.env.DB.prepare(
|
||||||
|
`SELECT count(*) as count FROM mails where address = ?`
|
||||||
|
).bind(address).first();
|
||||||
|
const balance = await c.env.DB.prepare(
|
||||||
|
`SELECT balance FROM address_sender
|
||||||
|
where address = ? and enabled = 1`
|
||||||
|
).bind(address).first("balance");
|
||||||
|
return c.json({
|
||||||
|
address: address,
|
||||||
|
has_v1_mails: mailCountV1 && mailCountV1 > 0,
|
||||||
|
send_balance: balance || 0,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
api.post('/api/new_address', async (c) => {
|
||||||
|
if (!getBooleanValue(c.env.ENABLE_USER_CREATE_EMAIL)) {
|
||||||
|
return c.text("New address is disabled", 403)
|
||||||
|
}
|
||||||
|
let { name, domain, cf_token } = await c.req.json();
|
||||||
|
// check cf turnstile
|
||||||
|
try {
|
||||||
|
await checkCfTurnstile(c, cf_token);
|
||||||
|
} catch (error) {
|
||||||
|
return c.text("Failed to check cf turnstile", 500)
|
||||||
|
}
|
||||||
|
// if no name, generate random name
|
||||||
|
if (!name) {
|
||||||
|
name = Math.random().toString(36).substring(2, 15);
|
||||||
|
}
|
||||||
|
// check name block list
|
||||||
|
try {
|
||||||
|
const value = await getJsonSetting(c, CONSTANTS.ADDRESS_BLOCK_LIST_KEY);
|
||||||
|
const blockList = value || [];
|
||||||
|
if (blockList.some((item) => name.includes(item))) {
|
||||||
|
return c.text(`Name[${name}]is blocked`, 400)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
return newAddress(c, name, domain, true);
|
||||||
|
})
|
||||||
|
|
||||||
|
api.delete('/api/delete_address', async (c) => {
|
||||||
|
if (!getBooleanValue(c.env.ENABLE_USER_DELETE_EMAIL)) {
|
||||||
|
return c.text("User delete email is disabled", 403)
|
||||||
|
}
|
||||||
|
const { address, address_id } = c.get("jwtPayload")
|
||||||
|
let name = address;
|
||||||
|
const { success } = await c.env.DB.prepare(
|
||||||
|
`DELETE FROM address WHERE name = ? `
|
||||||
|
).bind(name).run();
|
||||||
|
if (!success) {
|
||||||
|
return c.text("Failed to delete address", 500)
|
||||||
|
}
|
||||||
|
const { success: mailSuccess } = await c.env.DB.prepare(
|
||||||
|
`DELETE FROM raw_mails WHERE address = ? `
|
||||||
|
).bind(address).run();
|
||||||
|
if (!mailSuccess) {
|
||||||
|
return c.text("Failed to delete mails", 500)
|
||||||
|
}
|
||||||
|
const { success: sendAccess } = await c.env.DB.prepare(
|
||||||
|
`DELETE FROM address_sender WHERE address = ? `
|
||||||
|
).bind(address).run();
|
||||||
|
const { success: addressSuccess } = await c.env.DB.prepare(
|
||||||
|
`DELETE FROM users_address WHERE address_id = ? `
|
||||||
|
).bind(address_id).run();
|
||||||
|
return c.json({
|
||||||
|
success: success && mailSuccess && sendAccess && addressSuccess
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
export { api }
|
export { api }
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import { Jwt } from 'hono/utils/jwt'
|
|||||||
import { CONSTANTS } from '../constants'
|
import { CONSTANTS } from '../constants'
|
||||||
import { getJsonSetting, getDomains } from '../utils';
|
import { getJsonSetting, getDomains } from '../utils';
|
||||||
import { GeoData } from '../models'
|
import { GeoData } from '../models'
|
||||||
|
import { handleListQuery } from '../common'
|
||||||
|
|
||||||
|
|
||||||
const api = new Hono()
|
const api = new Hono()
|
||||||
|
|
||||||
@@ -112,8 +114,7 @@ export const sendMail = async (c, address, reqJson) => {
|
|||||||
// update balance
|
// update balance
|
||||||
try {
|
try {
|
||||||
const { success } = await c.env.DB.prepare(
|
const { success } = await c.env.DB.prepare(
|
||||||
`UPDATE address_sender SET balance = balance - 1
|
`UPDATE address_sender SET balance = balance - 1 where address = ?`
|
||||||
where address = ?`
|
|
||||||
).bind(address).run();
|
).bind(address).run();
|
||||||
if (!success) {
|
if (!success) {
|
||||||
console.warn(`Failed to update balance for ${address}`);
|
console.warn(`Failed to update balance for ${address}`);
|
||||||
@@ -171,27 +172,11 @@ const getSendbox = async (c, address, limit, offset) => {
|
|||||||
if (!address) {
|
if (!address) {
|
||||||
return c.json({ "error": "No address" }, 400)
|
return c.json({ "error": "No address" }, 400)
|
||||||
}
|
}
|
||||||
if (!limit || limit < 0 || limit > 100) {
|
return await handleListQuery(c,
|
||||||
return c.text("Invalid limit", 400)
|
`SELECT * FROM sendbox where address = ? `,
|
||||||
}
|
`SELECT count(*) as count FROM sendbox where address = ? `,
|
||||||
if (!offset || offset < 0) {
|
[address], limit, offset
|
||||||
return c.text("Invalid offset", 400)
|
);
|
||||||
}
|
|
||||||
const { results } = await c.env.DB.prepare(
|
|
||||||
`SELECT * FROM sendbox where address = ?
|
|
||||||
order by id desc limit ? offset ?`
|
|
||||||
).bind(address, limit, offset).all();
|
|
||||||
let count = 0;
|
|
||||||
if (offset == 0) {
|
|
||||||
const { count: mailCount } = await c.env.DB.prepare(
|
|
||||||
`SELECT count(*) as count FROM sendbox where address = ?`
|
|
||||||
).bind(address).first();
|
|
||||||
count = mailCount;
|
|
||||||
}
|
|
||||||
return c.json({
|
|
||||||
results: results,
|
|
||||||
count: count
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
api.get('/api/sendbox', async (c) => {
|
api.get('/api/sendbox', async (c) => {
|
||||||
|
|||||||
@@ -1,181 +0,0 @@
|
|||||||
import { Hono } from 'hono'
|
|
||||||
|
|
||||||
import {
|
|
||||||
getDomains, getPasswords, getBooleanValue, getJsonSetting,
|
|
||||||
checkCfTurnstile
|
|
||||||
} from './utils';
|
|
||||||
import { newAddress } from './common'
|
|
||||||
import { CONSTANTS } from './constants'
|
|
||||||
|
|
||||||
const api = new Hono()
|
|
||||||
|
|
||||||
api.get('/api/mails', async (c) => {
|
|
||||||
const { address } = c.get("jwtPayload")
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
if (!offset || offset < 0) {
|
|
||||||
return c.text("Invalid offset", 400)
|
|
||||||
}
|
|
||||||
const { results } = await c.env.DB.prepare(
|
|
||||||
`SELECT * FROM raw_mails where address = ? order by id desc limit ? offset ?`
|
|
||||||
).bind(address, limit, offset).all();
|
|
||||||
let count = 0;
|
|
||||||
if (offset == 0) {
|
|
||||||
const { count: mailCount } = await c.env.DB.prepare(
|
|
||||||
`SELECT count(*) as count FROM raw_mails where address = ?`
|
|
||||||
).bind(address).first();
|
|
||||||
count = mailCount;
|
|
||||||
}
|
|
||||||
return c.json({
|
|
||||||
results: results,
|
|
||||||
count: count
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
api.delete('/api/mails/:id', async (c) => {
|
|
||||||
if (!getBooleanValue(c.env.ENABLE_USER_DELETE_EMAIL)) {
|
|
||||||
return c.text("User delete email is disabled", 403)
|
|
||||||
}
|
|
||||||
const { address } = c.get("jwtPayload")
|
|
||||||
const { id } = c.req.param();
|
|
||||||
const { success } = await c.env.DB.prepare(
|
|
||||||
`DELETE FROM raw_mails WHERE address = ? and id = ?`
|
|
||||||
).bind(address, id).run();
|
|
||||||
return c.json({
|
|
||||||
success: success
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
api.get('/api/settings', async (c) => {
|
|
||||||
const { address, address_id } = c.get("jwtPayload")
|
|
||||||
if (address_id && address_id > 0) {
|
|
||||||
try {
|
|
||||||
const db_address_id = await c.env.DB.prepare(
|
|
||||||
`SELECT id FROM address where id = ?`
|
|
||||||
).bind(address_id).first("id");
|
|
||||||
if (!db_address_id) {
|
|
||||||
return c.text("Invalid address", 400)
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
return c.text("Invalid address", 400)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// check address id
|
|
||||||
try {
|
|
||||||
if (!address_id) {
|
|
||||||
const db_address_id = await c.env.DB.prepare(
|
|
||||||
`SELECT id FROM address where name = ?`
|
|
||||||
).bind(address).first("id");
|
|
||||||
if (!db_address_id) {
|
|
||||||
return c.text("Invalid address", 400)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
return c.text("Invalid address", 400)
|
|
||||||
}
|
|
||||||
// update address updated_at
|
|
||||||
try {
|
|
||||||
c.env.DB.prepare(
|
|
||||||
`UPDATE address SET updated_at = datetime('now') where name = ?`
|
|
||||||
).bind(address).run();
|
|
||||||
} catch (e) {
|
|
||||||
console.warn("Failed to update address")
|
|
||||||
}
|
|
||||||
const { count: mailCountV1 } = await c.env.DB.prepare(
|
|
||||||
`SELECT count(*) as count FROM mails where address = ?`
|
|
||||||
).bind(address).first();
|
|
||||||
const balance = await c.env.DB.prepare(
|
|
||||||
`SELECT balance FROM address_sender
|
|
||||||
where address = ? and enabled = 1`
|
|
||||||
).bind(address).first("balance");
|
|
||||||
return c.json({
|
|
||||||
address: address,
|
|
||||||
has_v1_mails: mailCountV1 && mailCountV1 > 0,
|
|
||||||
send_balance: balance || 0,
|
|
||||||
});
|
|
||||||
})
|
|
||||||
|
|
||||||
api.get('/open_api/settings', async (c) => {
|
|
||||||
// check header x-custom-auth
|
|
||||||
let needAuth = false;
|
|
||||||
const passwords = getPasswords(c);
|
|
||||||
if (passwords && passwords.length > 0) {
|
|
||||||
const auth = c.req.raw.headers.get("x-custom-auth");
|
|
||||||
needAuth = !passwords.includes(auth);
|
|
||||||
}
|
|
||||||
return c.json({
|
|
||||||
"prefix": c.env.PREFIX,
|
|
||||||
"domains": getDomains(c),
|
|
||||||
"needAuth": needAuth,
|
|
||||||
"adminContact": c.env.ADMIN_CONTACT,
|
|
||||||
"enableUserCreateEmail": getBooleanValue(c.env.ENABLE_USER_CREATE_EMAIL),
|
|
||||||
"enableUserDeleteEmail": getBooleanValue(c.env.ENABLE_USER_DELETE_EMAIL),
|
|
||||||
"enableAutoReply": getBooleanValue(c.env.ENABLE_AUTO_REPLY),
|
|
||||||
"copyright": c.env.COPYRIGHT,
|
|
||||||
"cfTurnstileSiteKey": c.env.CF_TURNSTILE_SITE_KEY,
|
|
||||||
});
|
|
||||||
})
|
|
||||||
|
|
||||||
api.post('/api/new_address', async (c) => {
|
|
||||||
if (!getBooleanValue(c.env.ENABLE_USER_CREATE_EMAIL)) {
|
|
||||||
return c.text("New address is disabled", 403)
|
|
||||||
}
|
|
||||||
let { name, domain, cf_token } = await c.req.json();
|
|
||||||
// check cf turnstile
|
|
||||||
try {
|
|
||||||
await checkCfTurnstile(c, cf_token);
|
|
||||||
} catch (error) {
|
|
||||||
return c.text("Failed to check cf turnstile", 500)
|
|
||||||
}
|
|
||||||
// if no name, generate random name
|
|
||||||
if (!name) {
|
|
||||||
name = Math.random().toString(36).substring(2, 15);
|
|
||||||
}
|
|
||||||
// check name block list
|
|
||||||
try {
|
|
||||||
const value = await getJsonSetting(c, CONSTANTS.ADDRESS_BLOCK_LIST_KEY);
|
|
||||||
const blockList = value || [];
|
|
||||||
if (blockList.some((item) => name.includes(item))) {
|
|
||||||
return c.text(`Name [${name}] is blocked`, 400)
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
return newAddress(c, name, domain, true);
|
|
||||||
})
|
|
||||||
|
|
||||||
api.delete('/api/delete_address', async (c) => {
|
|
||||||
if (!getBooleanValue(c.env.ENABLE_USER_DELETE_EMAIL)) {
|
|
||||||
return c.text("User delete email is disabled", 403)
|
|
||||||
}
|
|
||||||
const { address, address_id } = c.get("jwtPayload")
|
|
||||||
let name = address;
|
|
||||||
const { success } = await c.env.DB.prepare(
|
|
||||||
`DELETE FROM address WHERE name = ? `
|
|
||||||
).bind(name).run();
|
|
||||||
if (!success) {
|
|
||||||
return c.text("Failed to delete address", 500)
|
|
||||||
}
|
|
||||||
const { success: mailSuccess } = await c.env.DB.prepare(
|
|
||||||
`DELETE FROM raw_mails WHERE address = ? `
|
|
||||||
).bind(address).run();
|
|
||||||
if (!mailSuccess) {
|
|
||||||
return c.text("Failed to delete mails", 500)
|
|
||||||
}
|
|
||||||
const { success: sendAccess } = await c.env.DB.prepare(
|
|
||||||
`DELETE FROM address_sender WHERE address = ? `
|
|
||||||
).bind(address).run();
|
|
||||||
const { success: addressSuccess } = await c.env.DB.prepare(
|
|
||||||
`DELETE FROM users_address WHERE address_id = ?`
|
|
||||||
).bind(address_id).run();
|
|
||||||
return c.json({
|
|
||||||
success: success && mailSuccess && sendAccess && addressSuccess
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
export { api }
|
|
||||||
@@ -131,7 +131,7 @@ export default {
|
|||||||
const jwt = await Jwt.sign({
|
const jwt = await Jwt.sign({
|
||||||
address: name,
|
address: name,
|
||||||
address_id: address_id
|
address_id: address_id
|
||||||
}, c.env.JWT_SECRET)
|
}, c.env.JWT_SECRET, "HS256")
|
||||||
return c.json({
|
return c.json({
|
||||||
jwt: jwt
|
jwt: jwt
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ export default {
|
|||||||
// 30 days expire in seconds
|
// 30 days expire in seconds
|
||||||
exp: Math.floor(Date.now() / 1000) + 30 * 24 * 60 * 60,
|
exp: Math.floor(Date.now() / 1000) + 30 * 24 * 60 * 60,
|
||||||
iat: Math.floor(Date.now() / 1000),
|
iat: Math.floor(Date.now() / 1000),
|
||||||
}, c.env.JWT_SECRET)
|
}, c.env.JWT_SECRET, "HS256")
|
||||||
return c.json({
|
return c.json({
|
||||||
jwt: jwt
|
jwt: jwt
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import { cors } from 'hono/cors';
|
|||||||
import { jwt } from 'hono/jwt'
|
import { jwt } from 'hono/jwt'
|
||||||
import { Jwt } from 'hono/utils/jwt'
|
import { Jwt } from 'hono/utils/jwt'
|
||||||
|
|
||||||
import { api } from './router';
|
import { api as commonApi } from './commom_api';
|
||||||
import { api as MailsApi } from './mails_api'
|
import { api as mailsApi } from './mails_api'
|
||||||
import { api as userApi } from './user_api';
|
import { api as userApi } from './user_api';
|
||||||
import { api as adminApi } from './admin_api';
|
import { api as adminApi } from './admin_api';
|
||||||
import { api as apiV1 } from './deprecated';
|
import { api as apiV1 } from './deprecated';
|
||||||
@@ -101,8 +101,8 @@ app.use('/admin/*', async (c, next) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
app.route('/', api)
|
app.route('/', commonApi)
|
||||||
app.route('/', MailsApi)
|
app.route('/', mailsApi)
|
||||||
app.route('/', userApi)
|
app.route('/', userApi)
|
||||||
app.route('/', adminApi)
|
app.route('/', adminApi)
|
||||||
app.route('/', apiV1)
|
app.route('/', apiV1)
|
||||||
|
|||||||
Reference in New Issue
Block a user