feat: telegram mini app open mail from bot (#256)

This commit is contained in:
Dream Hunter
2024-05-21 02:03:06 +08:00
committed by GitHub
parent 69771fc1d1
commit 91d7896e65
21 changed files with 487 additions and 151 deletions

View File

@@ -1,8 +1,10 @@
import { Context } from "hono";
import { getBooleanValue } from "../utils";
import { HonoCustomType } from "../types";
export default {
getAutoReply: async (c) => {
getAutoReply: async (c: Context<HonoCustomType>) => {
if (!getBooleanValue(c.env.ENABLE_AUTO_REPLY)) {
return c.text("Auto reply is disabled", 403)
}
@@ -21,7 +23,7 @@ export default {
name: results.name,
})
},
saveAutoReply: async (c) => {
saveAutoReply: async (c: Context<HonoCustomType>) => {
if (!getBooleanValue(c.env.ENABLE_AUTO_REPLY)) {
return c.text("Auto reply is disabled", 403)
}

View File

@@ -1,12 +1,13 @@
import { Hono } from 'hono'
import { HonoCustomType } from "../types";
import { getBooleanValue, getJsonSetting, checkCfTurnstile } from '../utils';
import { newAddress, handleListQuery } from '../common'
import { newAddress, handleListQuery, deleteAddressWithData } from '../common'
import { CONSTANTS } from '../constants'
import auto_reply from './auto_reply'
import webhook_settings from './webhook_settings';
const api = new Hono()
export const api = new Hono<HonoCustomType>()
api.get('/api/auto_reply', auto_reply.getAutoReply)
api.post('/api/auto_reply', auto_reply.saveAutoReply)
@@ -103,7 +104,7 @@ api.post('/api/new_address', async (c) => {
// check name block list
try {
const value = await getJsonSetting(c, CONSTANTS.ADDRESS_BLOCK_LIST_KEY);
const blockList = value || [];
const blockList = (value || []) as string[];
if (blockList.some((item) => name.includes(item))) {
return c.text(`Name[${name}]is blocked`, 400)
}
@@ -114,37 +115,14 @@ api.post('/api/new_address', async (c) => {
const res = await newAddress(c, name, domain, true);
return c.json(res);
} catch (e) {
return c.text(`Failed create address: ${e.message}`, 400)
return c.text(`Failed create address: ${(e as Error).message}`, 400)
}
})
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();
const success = await deleteAddressWithData(c, address, address_id);
return c.json({
success: success && mailSuccess && sendAccess && addressSuccess
success: success
})
})
export { api }

View File

@@ -1,12 +1,13 @@
import { Hono } from 'hono'
import { Context, Hono } from 'hono'
import { Jwt } from 'hono/utils/jwt'
import { CONSTANTS } from '../constants'
import { getJsonSetting, getDomains } from '../utils';
import { GeoData } from '../models'
import { getJsonSetting, getDomains, getIntValue } from '../utils';
import { GeoData } from '../models/models'
import { handleListQuery } from '../common'
import { HonoCustomType } from '../types';
const api = new Hono()
export const api = new Hono<HonoCustomType>()
api.post('/api/requset_send_mail_access', async (c) => {
const { address } = c.get("jwtPayload")
@@ -14,7 +15,7 @@ api.post('/api/requset_send_mail_access', async (c) => {
return c.text("No address", 400)
}
try {
const default_balance = c.env.DEFAULT_SEND_BALANCE || 0;
const default_balance = getIntValue(c.env.DEFAULT_SEND_BALANCE, 0);
const { success } = await c.env.DB.prepare(
`INSERT INTO address_sender (address, balance, enabled) VALUES (?, ?, ?)`
).bind(
@@ -24,15 +25,22 @@ api.post('/api/requset_send_mail_access', async (c) => {
return c.text("Failed to request send mail access", 500)
}
} catch (e) {
if (e.message && e.message.includes("UNIQUE")) {
return c.text("Already requested", 400)
const message = (e as Error).message;
if (message && message.includes("UNIQUE")) {
throw new Error("Address already requested")
}
return c.text("Failed to request send mail access", 500)
}
return c.json({ status: "ok" })
})
export const sendMail = async (c, address, reqJson) => {
export const sendMail = async (
c: Context<HonoCustomType>, address: string,
reqJson: {
from_name: string, to_mail: string, to_name: string,
subject: string, content: string, is_html: boolean
}
) => {
if (!address) {
throw new Error("No address")
}
@@ -46,7 +54,7 @@ export const sendMail = async (c, address, reqJson) => {
const balance = await c.env.DB.prepare(
`SELECT balance FROM address_sender
where address = ? and enabled = 1`
).bind(address).first("balance");
).bind(address).first<number>("balance");
if (!balance || balance <= 0) {
throw new Error("No balance")
}
@@ -58,7 +66,7 @@ export const sendMail = async (c, address, reqJson) => {
throw new Error("Invalid to mail")
}
// check SEND_BLOCK_LIST_KEY
const sendBlockList = await getJsonSetting(c, CONSTANTS.SEND_BLOCK_LIST_KEY);
const sendBlockList = await getJsonSetting(c, CONSTANTS.SEND_BLOCK_LIST_KEY) as string[];
if (sendBlockList && sendBlockList.some((item) => to_mail.includes(item))) {
throw new Error("to_mail address is blocked")
}
@@ -124,12 +132,12 @@ export const sendMail = async (c, address, reqJson) => {
}
// save to sendbox
try {
if (body?.personalizations?.[0]?.dkim_private_key) {
delete body.personalizations[0].dkim_private_key;
if ((body as any)?.personalizations?.[0]?.dkim_private_key) {
delete (body as any).personalizations[0].dkim_private_key;
}
const reqIp = c.req.raw.headers.get("cf-connecting-ip")
const geoData = new GeoData(reqIp, c.req.raw.cf);
body.geoData = geoData;
const geoData = new GeoData(reqIp, c.req.raw.cf as any);
(body as any).geoData = geoData;
const { success: success2 } = await c.env.DB.prepare(
`INSERT INTO sendbox (address, raw) VALUES (?, ?)`
).bind(address, JSON.stringify(body)).run();
@@ -148,7 +156,7 @@ api.post('/api/send_mail', async (c) => {
await sendMail(c, address, reqJson);
} catch (e) {
console.error("Failed to send mail", e);
return c.text(`Failed to send mail ${e.message}`, 400)
return c.text(`Failed to send mail ${(e as Error).message}`, 400)
}
return c.json({ status: "ok" })
})
@@ -165,11 +173,14 @@ api.post('/external/api/send_mail', async (c) => {
return c.json({ status: "ok" })
} catch (e) {
console.error("Failed to send mail", e);
return c.text(`Failed to send mail ${e.message}`, 400)
return c.text(`Failed to send mail ${(e as Error).message}`, 400)
}
})
const getSendbox = async (c, address, limit, offset) => {
export const getSendbox = async (
c: Context<HonoCustomType>,
address: string, limit: string, offset: string
): Promise<Response> => {
if (!address) {
return c.json({ "error": "No address" }, 400)
}
@@ -185,5 +196,3 @@ api.get('/api/sendbox', async (c) => {
const { limit, offset } = c.req.query();
return getSendbox(c, address, limit, offset);
})
export { api, getSendbox }

View File

@@ -96,9 +96,9 @@ export async function trigerWebhook(
from: parsedEmail.from.address || "",
to: address,
headers: JSON.stringify(parsedEmail.headers, null, 2),
subject: parsedEmail.subject || "",
raw: raw_mail,
parsedText: parsedEmail.text || parsedEmail.html || ""
subject: JSON.stringify(parsedEmail.subject) || "",
raw: JSON.stringify(raw_mail),
parsedText: JSON.stringify(parsedEmail.text) || JSON.stringify(parsedEmail.html) || ""
});
if (!res.success) {
console.log(res.message);