-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMain.ts
More file actions
122 lines (100 loc) · 3.93 KB
/
Main.ts
File metadata and controls
122 lines (100 loc) · 3.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import validator from "validator";
import {request} from "undici";
import fetch from "node-fetch";
import Express from 'express';
const app = Express();
import dotenv from "dotenv";
const auth = dotenv.config({path: "./.env"});
if (!auth?.parsed || auth?.error) {
throw "Unable to access .env file";
};
const bunnyEndpoint = `https://se.storage.bunnycdn.com/${auth.parsed["STORAGE_ZONE_NAME"]}`;
// basic security
import helmet from "helmet";
app.use(helmet());
app.use(Express.json({strict: true, type: "application/json"}))
// OK
app.get("/", (_, res) => {
return res.sendStatus(200);
});
// post content to cdn
app.post("/", async (req, res) => {
try {
// we use a simple authorization, whoever had the key will be able to post content to cdn
if (process.env.npm_lifecycle_event !== "dev") { // ignore auth if dev mode
if (!auth?.parsed?.["AUTH"]) {
return res.status(500).send("unable to retrieve private key from backend");
};
const authorization = req.headers.authorization;
if (!authorization || authorization !== auth.parsed["AUTH"]) {
return res.status(403).send("unauthorized");
};
};
// because this server is specialized for discord bot, we use guild ID as a folder name
if (req.body?.guildID && !req.body.guildID?.match(/^(\d){17,21}$/gim)) {
return res.status(400).send("invalid discord guild id");
};
// the value of "content" is url
if (!req.body.content || !validator.isURL(req.body.content, { require_protocol: true })) {
return res.status(400).send("invalid url");
};
let mimeType = {
"image/jpg": "jpg",
"image/jpeg": "jpeg",
"image/png": "png",
"image/webp": "webp",
"video/mp4": "mp4",
"video/mpeg": "mpeg",
"video/webm": "webm",
"image/gif": "gif"
};
// content processing
const content = await request(req.body.content);
if (!content || content.statusCode >= 400) {
console.error("content error", content.statusCode, await content.body.text());
return res.status(400).send("unable to fetch the content");
};
if (!content?.headers?.["content-type"] || !mimeType[content.headers["content-type"]]) {
return res.status(400).send("invalid content type");
};
const processedContent = Buffer.from(await content.body.arrayBuffer());
// upload to bunny
if (!auth?.parsed?.BUNNY_API_PASS) {
return res.status(500).send("unable to retrieve centre private key");
};
const randomFileName = generateString(randomNumber(8, 16)) + "." + mimeType[content.headers["content-type"]];
let filenamePath = `discord/${req.body.guildID}/${randomFileName}`;
// uploaded by cDev team
if (!req.body.guildID) {
filenamePath = `official/${randomFileName}`;
};
const bunnyPost = await fetch(bunnyEndpoint + "/" + filenamePath, {
method: 'PUT',
body: processedContent,
headers: {
"AccessKey": auth.parsed.BUNNY_API_PASS,
"content-type": "application/octet-stream"
}
});
if (!bunnyPost || bunnyPost.status >= 400) {
console.error("centre error", await bunnyPost.text());
return res.status(500).send("unable to post the content to centre");
};
// console.log(bunnyPost.status, await bunnyPost.json());
return res.status(200).send(`https://cdn.cdev.shop/${filenamePath}`);
} catch (error) {
console.error(error);
return res.status(500).send("something went wrong in the background");
};
});
const PORT = +auth.parsed.PORT;
app.listen(PORT, () => {
console.log("Media: Connected with port", PORT)
});
function generateString(length: number) {
const characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-";
return [...Array(length || 16)].map(_ => characters[~~(Math.random() * characters.length)]).join('');
};
function randomNumber(min: number, max: number) {
return Math.floor(Math.random() * (Math.floor(max) - Math.ceil(min)) + Math.ceil(min));
};