Commit b8280522 authored by Senk Ju's avatar Senk Ju

update

parent 430611e9
Pipeline #66 failed with stages
......@@ -20,8 +20,9 @@ const app = express();
const uidGen = new uidGenerator(uidGenerator.BASE64, 8);
const imageFolder = path.join(__dirname, "images");
const possibleUrlStyles = ["query", "param"];
var userRateLimits = {};
let userRateLimits = {};
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
......@@ -38,28 +39,27 @@ function endRequest(code, message, res) {
}
async function encryptBuffer(buffer, password) {
var cipher = crypto.createCipher(config.encryption.algorithm, password)
var encrypted = Buffer.concat([cipher.update(buffer), cipher.final()]);
let cipher = crypto.createCipher(config.encryption.algorithm, password)
let encrypted = Buffer.concat([cipher.update(buffer), cipher.final()]);
return encrypted;
}
async function decryptFile(filePath, password) {
var fileBuffer = await readFile(filePath);
var decipher = crypto.createDecipher(config.encryption.algorithm, password)
var decrypted = Buffer.concat([decipher.update(fileBuffer), decipher.final()]);
let fileBuffer = await readFile(filePath);
let decipher = crypto.createDecipher(config.encryption.algorithm, password)
let decrypted = Buffer.concat([decipher.update(fileBuffer), decipher.final()]);
return decrypted;
}
setInterval(() => {
userRateLimits = {};
}, 1000 * 60 * config.rateLimit.delay);
function getRandomIndex(array) {
return array[~~(array.length * Math.random())];
}
app.get("/:filename", async (req, res) => {
var filename = req.params.filename;
var fileMime = mime.lookup(filename);
var filePath = path.join(imageFolder, filename);
var password = req.query.key;
async function decrypt(req, res, filename, password) {
let fileMime = mime.lookup(filename);
let filePath = path.join(imageFolder, filename);
if (await !existsFile(filePath) || filename.includes("/") || filename.includes("\\")) {
endRequest(404, "File not found!", res);
......@@ -67,7 +67,7 @@ app.get("/:filename", async (req, res) => {
}
try {
var decryptedFile = await decryptFile(filePath, password);
let decryptedFile = await decryptFile(filePath, password);
res.writeHead(200, {
"Content-Type": fileMime,
......@@ -78,13 +78,43 @@ app.get("/:filename", async (req, res) => {
} catch (err) {
endRequest(500, "Failed to decrypt file!", res);
}
}
setInterval(() => {
userRateLimits = {};
}, 1000 * 60 * config.rateLimit.delay);
app.get("/:filename", async (req, res) => {
let filename = req.params.filename;
let password = req.query.key;
await decrypt(req, res, filename, password);
});
app.get("/:filename/:password", async (req, res) => {
let filename = req.params.filename;
let password = req.params.password;
await decrypt(req, res, filename, password);
});
app.post("/upload", async (req, res) => {
var file = req.files.file;
var userKey = req.body.userKey;
var password = req.body.password;
var fileExtension = path.extname(file.name);
let file = req.files.file;
let userKey = req.body.userKey;
let password = req.body.password;
let fileExtension = path.extname(file.name);
let domain;
let urlStyle = "query";
if (req.body.urlStyle && possibleUrlStyles.includes(req.body.urlStyle)) {
urlStyle = req.body.urlStyle;
}
try {
domain = getRandomIndex(JSON.parse(req.body.domains));
} catch (err) {
domain = "axolotl.club";
}
if (!file) {
endRequest(500, "No image posted!", res);
......@@ -106,48 +136,79 @@ app.post("/upload", async (req, res) => {
return;
}
var fileSize = file.data.length / 1000000;
(userRateLimits.userKey) ? userRateLimits.userKey += fileSize : userRateLimits.userKey = fileSize;
if (!domain) {
domain = getRandomIndex(config.availableDomains);
}
let fileSize = file.data.length / 1000000;
if (userRateLimits[userKey]) {
userRateLimits[userKey].bytesUploaded += fileSize;
userRateLimits[userKey].filesUploaded += 1;
} else {
userRateLimits[userKey] = {
bytesUploaded: fileSize,
filesUploaded: 1
}
}
if (userRateLimits.userKey > config.rateLimit.amount) {
if (userRateLimits[userKey].bytesUploaded > config.rateLimit.amount || userRateLimits[userKey].filesUploaded > 250) {
endRequest(500, "You have been ratelimited. Please try again later.", res);
return;
}
let imageFolderFile;
let filename;
do {
var filename = await uidGen.generate() + fileExtension;
var imageFolderFile = path.join(imageFolder, filename);
filename = await uidGen.generate() + fileExtension;
imageFolderFile = path.join(imageFolder, filename);
} while (await existsFile(imageFolderFile));
try {
var encryptedFile = await encryptBuffer(file.data, password);
let encryptedFile = await encryptBuffer(file.data, password);
await writeFile(imageFolderFile, encryptedFile);
res.end(`https://axolotl.club/${filename}?key=${password}`);
switch (urlStyle) {
case "query":
res.end(`https://${domain}/${filename}?key=${password}`);
break;
case "param":
res.end(`https://${domain}/${filename}/${password}`);
break;
}
} catch (err) {
console.log(err)
endRequest(500, "Failed to encrypt file.", res);
}
});
app.get("/", async (req, res) => {
var uploadedImages = await readdir(imageFolder);
var fileCount = uploadedImages.length.toLocaleString();
var usersCount = config.userKeys.length.toLocaleString();
let uploadedImages = await readdir(imageFolder);
let fileCount = uploadedImages.length.toLocaleString();
let usersCount = config.userKeys.length.toLocaleString();
var totalSize = 0;
for (image of uploadedImages) {
var fileStat = await fileStats(path.join(imageFolder, image));
let totalSize = 0;
for (let image of uploadedImages) {
let fileStat = await fileStats(path.join(imageFolder, image));
totalSize += fileStat.size;
}
let recentlyUploadedCount = 0;
for (let user in userRateLimits) {
recentlyUploadedCount += userRateLimits[user].filesUploaded;
}
totalSize = (totalSize / 1000000).toFixed(2);
res.render("index", {
statistics: {
count: fileCount,
users: usersCount,
size: totalSize
size: totalSize,
recentlyUploadedCount: recentlyUploadedCount,
delay: config.rateLimit.delay
}
});
......@@ -156,3 +217,4 @@ app.get("/", async (req, res) => {
app.listen(config.webserver.port, () => {
console.log("Server running on port", config.webserver.port);
});
......@@ -13,6 +13,7 @@
max-width: 100%;
text-align: center;
padding-top: 20px;
margin-bottom: 20px;
}
h1 {
......@@ -22,11 +23,12 @@
textarea {
margin: 0 auto;
width: 100%;
height: 144px;
max-width: 90%;
resize: none;
box-sizing: border-box;
overflow: hidden;
height: max-content;
height: 220px;
}
img {
......@@ -62,22 +64,46 @@
<p><b>ShareX Config</b></p>
<textarea readonly>
{
"DestinationType": "ImageUploader",
"RequestURL": "https://axolotl.club/upload",
"FileFormName": "file",
"Arguments": {
"password": "%ra%ra%ra%ra%ra%ra%ra%ra%ra%ra%ra%ra%ra%ra",
"userKey": "your-user-key"
}
}
</textarea>
"Version": "12.4.1",
"DestinationType": "ImageUploader",
"RequestMethod": "POST",
"RequestURL": "https://axolotl.club/upload",
"Body": "MultipartFormData",
"Arguments": {
"password": "%ra%ra%ra%ra%ra%ra%ra%ra%ra%ra%ra%ra%ra%ra",
"userKey": "your-user-key",
"urlStyle": "query",
"domains": "[\"axolotl.club\", \"axolotl.us\"]"
},
"FileFormName": "file"
}</textarea>
<p><b>Statistics</b></p>
Images uploaded: <%-statistics.count%><br>
Storage used: <%-statistics.size%>MB<br>
Recently uploaded (<%-statistics.delay%> Min): <%-statistics.recentlyUploadedCount%><br>
Users: <%-statistics.users%>
<div class="footer">Made by Senk Ju (not Frozen >:C)</div>
<p><b>Available Domains</b></p>
axolotl.club<br>
axolotl.church<br>
axolotl.lol<br>
axolotl.pics<br>
axolotl.us<br>
axolotl.vip<br>
i.axo.im
<p><b>Available URL Styles</b></p>
query: Produces URLs like /filename?key=password<br>
param: Produces URLs like /filename/password
<p><b>How to use Custom Domains</b></p>
Just set the following A-Record for one of your (sub-)domains<br>
and add it to the domain array: 137.74.235.49
<p><b>Contact</b></p>
If you also want an API key or think that an image should be <br>
deleted, contact me via <a href="mailto:senkju4@gmail.com">email</a> or <a href="https://twitter.com/senkju">Twitter DM</a>.
</div>
</body>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment