feat: telegram bot unbind && delete address (#254)

This commit is contained in:
Dream Hunter
2024-05-20 13:23:41 +08:00
committed by GitHub
parent c00382259a
commit 69771fc1d1
19 changed files with 261 additions and 89 deletions

159
worker/src/common.ts Normal file
View File

@@ -0,0 +1,159 @@
import { Context } from 'hono';
import { Jwt } from 'hono/utils/jwt'
import { getDomains, getStringValue } from './utils';
import { HonoCustomType } from './types';
import { CONSTANTS } from './constants';
import { unbindTelegramByAddress } from './telegram_api/common';
export const newAddress = async (
c: Context<HonoCustomType>,
name: string, domain: string | undefined | null,
enablePrefix: boolean
): Promise<{ address: string, jwt: string }> => {
// remove special characters
name = name.replace(/[^a-zA-Z0-9.]/g, '')
// check name length
if (name.length < 0) {
throw new Error("Name too short")
}
// create address
if (enablePrefix) {
name = getStringValue(c.env.PREFIX) + name;
}
if (name.length >= 30) {
throw new Error("Name too long (max 30)")
}
// check domain, generate random domain
const domains = getDomains(c);
if (!domain || !domains.includes(domain)) {
domain = domains[Math.floor(Math.random() * domains.length)];
}
// create address
name = name + "@" + domain;
try {
const { success } = await c.env.DB.prepare(
`INSERT INTO address(name) VALUES(?)`
).bind(name).run();
if (!success) {
throw new Error("Failed to create address")
}
} catch (e) {
if (e.message && e.message.includes("UNIQUE")) {
throw new Error("Address already exists")
}
throw new Error("Failed to create address")
}
const address_id = await c.env.DB.prepare(
`SELECT id FROM address where name = ?`
).bind(name).first<number>("id");
// create jwt
const jwt = await Jwt.sign({
address: name,
address_id: address_id
}, c.env.JWT_SECRET, "HS256")
return {
jwt: jwt,
address: name,
}
}
export const cleanup = async (
c: Context<HonoCustomType>,
cleanType: string | undefined | null,
cleanDays: number | undefined | null
): Promise<boolean> => {
if (!cleanType || !cleanDays || cleanDays < 0 || cleanDays > 30) {
throw new Error("Invalid cleanType or cleanDays")
}
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 name from address) AND created_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:
throw new Error("Invalid cleanType")
}
return true;
}
/**
* TODO: need senbox delete?
*/
export const deleteAddressWithData = async (
c: Context<HonoCustomType>,
address: string | undefined | null,
address_id: number | undefined | null
): Promise<boolean> => {
if (!address && !address_id) {
throw new Error("Address or address_id required")
}
// get address_id or address
if (!address_id) {
address_id = await c.env.DB.prepare(
`SELECT id FROM address where name = ?`
).bind(address).first<number>("id");
} else if (!address) {
address = await c.env.DB.prepare(
`SELECT name FROM address where id = ?`
).bind(address_id).first<string>("name");
}
// check address again
if (!address || !address_id) {
throw new Error("Can't find address");
}
// unbind telegram
await unbindTelegramByAddress(c, address);
// delete address and related data
const { success: mailSuccess } = await c.env.DB.prepare(
`DELETE FROM raw_mails WHERE address = ? `
).bind(address).run();
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();
const { success } = await c.env.DB.prepare(
`DELETE FROM address WHERE name = ? `
).bind(address).run();
if (!success || !mailSuccess || !addressSuccess || !sendAccess) {
throw new Error("Failed to delete address")
}
return true;
}
export const handleListQuery = async (
c: Context<HonoCustomType>,
query: string, countQuery: string, params: string[],
limit: number | undefined | null,
offset: number | undefined | null
): Promise<Response> => {
if (!limit || limit < 0 || limit > 100) {
return c.text("Invalid limit", 400)
}
if (!offset || offset < 0) {
return c.text("Invalid offset", 400)
}
const resultsQuery = `${query} order by id desc limit ? offset ?`;
const { results } = await c.env.DB.prepare(resultsQuery).bind(
...params, limit, offset
).all();
const count = offset == 0 ? await c.env.DB.prepare(
countQuery
).bind(...params).first("count") : 0;
return c.json({ results, count });
}