👀 好きコードに (worker.js)

This commit is contained in:
ひでまる 2025-03-11 14:22:17 +09:00
parent 040f0c74a5
commit aaf9a6dd20

View file

@ -1,13 +1,18 @@
// @ts-check
// いじりやすいようにここに変数を集約させたい // いじりやすいようにここに変数を集約させたい
const BLOCKLIST = ["hacker@example.com", "spammer@example.com"]; const BLOCKLIST = ["hacker@example.com", "spammer@example.com"];
const FORWARD_TO = "mymail@example.com"; const FORWARD_TO = "mymail@example.com";
const WEBHOOK_URL = "https://discord.com/api/webhooks/xxx/xxx"; const WEBHOOK_URL = "https://discord.com/api/webhooks/xxx/xxx";
// trendcreate icon // trendcreate icon
const WEBHOOK_ICON = "https://git.v-sli.me/HidemaruOwO/email-worker/raw/branch/main/assets/webhook_icon.jpg"; const WEBHOOK_ICON =
"https://git.v-sli.me/HidemaruOwO/email-worker/raw/branch/main/assets/webhook_icon.jpg";
// mail letter icon // mail letter icon
const AUTHOR_ICON = "https://git.v-sli.me/HidemaruOwO/email-worker/raw/branch/main/assets/email_icon.png"; const AUTHOR_ICON =
"https://git.v-sli.me/HidemaruOwO/email-worker/raw/branch/main/assets/email_icon.png";
// cloudflare icon // cloudflare icon
const FOOTER_ICON = "https://git.v-sli.me/HidemaruOwO/email-worker/raw/branch/main/assets/cloudflare_icon.ico"; const FOOTER_ICON =
"https://git.v-sli.me/HidemaruOwO/email-worker/raw/branch/main/assets/cloudflare_icon.ico";
export default { export default {
async email(message, env, ctx) { async email(message, env, ctx) {
@ -17,63 +22,67 @@ export default {
} }
try { try {
const [text] = await Promise.all([ const [result] = await Promise.all([
getMailText(message), notify(message),
message.forward(FORWARD_TO) message.forward(FORWARD_TO),
]); ]);
const result = await notify(message.headers.get("from"), message.headers.get('subject'), text, message.headers.get("date"));
if (!result.ok) { if (!result.ok) {
console.log(await result.text()) console.log(await result.text());
console.log(await result.json()) console.log(await result.json());
return; return;
} }
} catch (err) { } catch (err) {
console.error("処理エラー:", err); console.error("処理エラー:", err);
} }
} },
}; };
async function notify(from, subject, text, date) { // async function notify(from, subject, text, date) {
async function notify(message) {
const from = message.headers.get("from");
const subject = message.headers.get("subject");
const date = message.headers.get("date");
const text = await getMailText(message);
const payload = { const payload = {
username: "contact@trendcreate.net", username: "contact@trendcreate.net",
avatar_url: WEBHOOK_ICON, avatar_url: WEBHOOK_ICON,
content: `**${from}**からお問い合わせメールが届いております。`, content: `**${from}**からお問い合わせメールが届いております。`,
embeds: [{ embeds: [
author: {name: from || "名前なし", icon_url: AUTHOR_ICON}, {
author: { name: from || "名前なし", icon_url: AUTHOR_ICON },
title: `**${subject || "件名なし"}**`, title: `**${subject || "件名なし"}**`,
description: text || "本文はありません。", description: text || "本文はありません。",
timestamp: new Date(date).toISOString(), timestamp: new Date(date).toISOString(),
footer: { footer: {
text: 'Powered by Cloudflare Worker and Email Routing', text: "Powered by Cloudflare Worker and Email Routing",
icon_url: FOOTER_ICON icon_url: FOOTER_ICON,
} },
}], },
],
}; };
// console.log(JSON.stringify(payload)) // console.log(JSON.stringify(payload))
try { try {
const result = await fetch(WEBHOOK_URL, { const result = await fetch(WEBHOOK_URL, {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload) body: JSON.stringify(payload),
}); });
return result; return result;
} catch (err) { } catch (err) {
console.log(err) console.log(err);
throw new Error(err) throw new Error(err);
} }
return;
} }
async function getMailText(message) { async function getMailText(message) {
try { try {
const buf = await readStream(message.raw); const buf = await readStream(message.raw);
if (buf === "NO_CONTENT") { if (buf === "NO_CONTENT") {
return "" return "";
} }
return parseEmail(buf); return parseEmail(buf);
} catch (err) { } catch (err) {
@ -83,7 +92,7 @@ async function getMailText(message) {
async function readStream(stream) { async function readStream(stream) {
if (typeof stream === "undefined") { if (typeof stream === "undefined") {
return "NO_CONTENT" return "NO_CONTENT";
} }
const chunks = []; const chunks = [];
@ -109,9 +118,9 @@ async function readStream(stream) {
function parseEmail(buffer) { function parseEmail(buffer) {
const text = new TextDecoder().decode(buffer); const text = new TextDecoder().decode(buffer);
const headerEnd = text.indexOf('\r\n\r\n'); const headerEnd = text.indexOf("\r\n\r\n");
if (headerEnd === -1) return ''; if (headerEnd === -1) return "";
const header = text.substring(0, headerEnd); const header = text.substring(0, headerEnd);
const body = text.substring(headerEnd + 4); const body = text.substring(headerEnd + 4);
@ -124,15 +133,15 @@ function parseEmail(buffer) {
const parts = body.split(boundary); const parts = body.split(boundary);
for (const part of parts) { for (const part of parts) {
if (part.includes('Content-Type: text/plain')) { if (part.includes("Content-Type: text/plain")) {
const isBase64 = part.includes('Content-Transfer-Encoding: base64'); const isBase64 = part.includes("Content-Transfer-Encoding: base64");
const partBody = part.split('\r\n\r\n')[1]?.trim(); const partBody = part.split("\r\n\r\n")[1]?.trim();
if (!partBody) continue; if (!partBody) continue;
if (isBase64) { if (isBase64) {
try { try {
const cleanBase64 = partBody.replace(/[\r\n\s]/g, ''); const cleanBase64 = partBody.replace(/[\r\n\s]/g, "");
return decodeBase64(cleanBase64); return decodeBase64(cleanBase64);
} catch { } catch {
continue; continue;
@ -143,7 +152,7 @@ function parseEmail(buffer) {
} }
} }
return ''; return "";
} }
function decodeBase64(base64) { function decodeBase64(base64) {
@ -156,3 +165,4 @@ function decodeBase64(base64) {
return new TextDecoder().decode(bytes); return new TextDecoder().decode(bytes);
} }