mirror of
https://github.com/filecoffee/filehost.git
synced 2024-11-13 19:49:56 +01:00
init
This commit is contained in:
parent
619521457a
commit
dc8cfd09fa
9 changed files with 1511 additions and 0 deletions
24
.env.example
Normal file
24
.env.example
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
# This can be 'local' or 's3'
|
||||||
|
STORAGE_MODE=local
|
||||||
|
|
||||||
|
# If you are using local storage, this is the path where the files will be uploaded
|
||||||
|
AWS_ACCESS_KEY_ID=your_aws_access_key_id
|
||||||
|
AWS_SECRET_ACCESS_KEY=your_aws_secret_access_key
|
||||||
|
AWS_REGION=your_aws_region
|
||||||
|
S3_BUCKET_NAME=your_s3_bucket_name
|
||||||
|
|
||||||
|
# If you are using local storage, this is the path where the files will be uploaded
|
||||||
|
LOCAL_UPLOAD_PATH=uploads
|
||||||
|
|
||||||
|
# This is the port where the server will run
|
||||||
|
PORT=3000
|
||||||
|
|
||||||
|
# Comma-separated list of API keys
|
||||||
|
API_KEYS=key1,key2,key3
|
||||||
|
|
||||||
|
# This is the maximum file size that can be uploaded and the max file name length. '-1' is unlimited file size, not recommended.
|
||||||
|
FILE_NAME_LENGTH=10
|
||||||
|
FILE_MAX_SIZE_MB=30
|
||||||
|
|
||||||
|
# Your email address
|
||||||
|
HOSTER_EMAIL=hoster@file.coffee
|
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -7,6 +7,10 @@ yarn-error.log*
|
||||||
lerna-debug.log*
|
lerna-debug.log*
|
||||||
.pnpm-debug.log*
|
.pnpm-debug.log*
|
||||||
|
|
||||||
|
|
||||||
|
/uploads/*
|
||||||
|
!/uploads/.gitkeep
|
||||||
|
|
||||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||||
|
|
||||||
|
|
139
index.js
Normal file
139
index.js
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
// index.js
|
||||||
|
require("dotenv").config();
|
||||||
|
const express = require("express");
|
||||||
|
const multer = require("multer");
|
||||||
|
const AWS = require("aws-sdk");
|
||||||
|
const fs = require("fs");
|
||||||
|
const path = require("path");
|
||||||
|
const mime = require("mime-types");
|
||||||
|
const ejs = require("ejs");
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
const port = process.env.PORT || 3000;
|
||||||
|
const storageMode = process.env.STORAGE_MODE || "local";
|
||||||
|
const apiKeys = process.env.API_KEYS.split(",");
|
||||||
|
const fileNameLength = parseInt(process.env.FILE_NAME_LENGTH, 10) || 10;
|
||||||
|
const fileMaxSizeMB = parseInt(process.env.FILE_MAX_SIZE_MB, 10);
|
||||||
|
const hosterEmail = process.env.HOSTER_EMAIL;
|
||||||
|
|
||||||
|
let totalUploads = 0;
|
||||||
|
let totalSize = 0;
|
||||||
|
|
||||||
|
app.set("view engine", "ejs");
|
||||||
|
|
||||||
|
const authenticate = (req, res, next) => {
|
||||||
|
const apiKey = req.headers["x-api-key"];
|
||||||
|
if (!apiKey || !apiKeys.includes(apiKey)) {
|
||||||
|
return res.status(403).json({ error: "Forbidden" });
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
|
||||||
|
const multerOptions = {
|
||||||
|
limits: fileMaxSizeMB === -1 ? {} : { fileSize: fileMaxSizeMB * 1024 * 1024 },
|
||||||
|
};
|
||||||
|
|
||||||
|
let upload;
|
||||||
|
|
||||||
|
const initializeUpload = async () => {
|
||||||
|
const { nanoid } = await import("nanoid");
|
||||||
|
|
||||||
|
if (storageMode === "local") {
|
||||||
|
const storage = multer.diskStorage({
|
||||||
|
destination: (req, file, cb) => {
|
||||||
|
cb(null, process.env.LOCAL_UPLOAD_PATH);
|
||||||
|
},
|
||||||
|
filename: (req, file, cb) => {
|
||||||
|
const ext = mime.extension(file.mimetype);
|
||||||
|
const randomName = nanoid(fileNameLength);
|
||||||
|
cb(null, `${randomName}.${ext}`);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
upload = multer({ storage: storage, ...multerOptions });
|
||||||
|
} else if (storageMode === "s3") {
|
||||||
|
const s3 = new AWS.S3({
|
||||||
|
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
|
||||||
|
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
|
||||||
|
region: process.env.AWS_REGION,
|
||||||
|
});
|
||||||
|
|
||||||
|
const storage = multer.memoryStorage();
|
||||||
|
upload = multer({ storage: storage, ...multerOptions });
|
||||||
|
|
||||||
|
app.post("/upload", authenticate, upload.single("file"), (req, res) => {
|
||||||
|
const ext = mime.extension(req.file.mimetype);
|
||||||
|
const randomName = nanoid(fileNameLength);
|
||||||
|
const params = {
|
||||||
|
Bucket: process.env.S3_BUCKET_NAME,
|
||||||
|
Key: `${randomName}.${ext}`,
|
||||||
|
Body: req.file.buffer,
|
||||||
|
ContentType: req.file.mimetype,
|
||||||
|
};
|
||||||
|
|
||||||
|
s3.upload(params, (err, data) => {
|
||||||
|
if (err) {
|
||||||
|
return res.status(500).json({ error: err.message });
|
||||||
|
}
|
||||||
|
totalUploads++;
|
||||||
|
totalSize += req.file.size / (1024 * 1024); // Convert bytes to MB
|
||||||
|
res
|
||||||
|
.status(200)
|
||||||
|
.json({ message: "File uploaded successfully", url: data.Location });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
throw new Error("Invalid STORAGE_MODE");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (storageMode === "local") {
|
||||||
|
app.post("/upload", authenticate, upload.single("file"), (req, res) => {
|
||||||
|
totalUploads++;
|
||||||
|
totalSize += req.file.size / (1024 * 1024); // Convert bytes to MB
|
||||||
|
res
|
||||||
|
.status(200)
|
||||||
|
.json({ message: "File uploaded successfully", path: req.file.path });
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get("/files/:filename", (req, res) => {
|
||||||
|
const filePath = path.join(
|
||||||
|
__dirname,
|
||||||
|
process.env.LOCAL_UPLOAD_PATH,
|
||||||
|
req.params.filename,
|
||||||
|
);
|
||||||
|
res.sendFile(filePath);
|
||||||
|
});
|
||||||
|
} else if (storageMode === "s3") {
|
||||||
|
app.get("/files/:filename", (req, res) => {
|
||||||
|
const params = {
|
||||||
|
Bucket: process.env.S3_BUCKET_NAME,
|
||||||
|
Key: req.params.filename,
|
||||||
|
};
|
||||||
|
|
||||||
|
s3.getObject(params, (err, data) => {
|
||||||
|
if (err) {
|
||||||
|
return res.status(500).json({ error: err.message });
|
||||||
|
}
|
||||||
|
res.writeHead(200, {
|
||||||
|
"Content-Type": data.ContentType,
|
||||||
|
"Content-Length": data.ContentLength,
|
||||||
|
});
|
||||||
|
res.write(data.Body);
|
||||||
|
res.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
app.get("/", (req, res) => {
|
||||||
|
res.render("index", {
|
||||||
|
totalUploads: totalUploads,
|
||||||
|
totalSize: totalSize.toFixed(2), // Format to 2 decimal places
|
||||||
|
hosterEmail: hosterEmail,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
app.listen(port, () => {
|
||||||
|
console.log(`Server is running on port ${port}`);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
initializeUpload();
|
1288
package-lock.json
generated
Normal file
1288
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
11
package.json
Normal file
11
package.json
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"aws-sdk": "^2.1632.0",
|
||||||
|
"dotenv": "^16.4.5",
|
||||||
|
"ejs": "^3.1.10",
|
||||||
|
"express": "^4.19.2",
|
||||||
|
"mime-types": "^2.1.35",
|
||||||
|
"multer": "^1.4.5-lts.1",
|
||||||
|
"nanoid": "^5.0.7"
|
||||||
|
}
|
||||||
|
}
|
8
sharex.sxcu
Normal file
8
sharex.sxcu
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"Name": "filehost by file.coffee",
|
||||||
|
"RequestType": "POST",
|
||||||
|
"RequestURL": "http://your-server-ip:3000/upload",
|
||||||
|
"FileFormName": "file",
|
||||||
|
"ResponseType": "Text",
|
||||||
|
"URL": "$json:url$"
|
||||||
|
}
|
0
src/app.js
Normal file
0
src/app.js
Normal file
0
uploads/.gitkeep
Normal file
0
uploads/.gitkeep
Normal file
37
views/index.ejs
Normal file
37
views/index.ejs
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>filehost by file.coffee</title>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
|
||||||
|
</head>
|
||||||
|
<body class="bg-gray-900 text-gray-100">
|
||||||
|
<div class="min-h-screen flex flex-col items-center justify-center p-6">
|
||||||
|
<header class="mb-12 text-center">
|
||||||
|
<h1 class="text-5xl font-extrabold mb-4">filehost</h1>
|
||||||
|
<p class="text-lg">by the creators of <a href="https://file.coffee" class="text-blue-400 hover:text-blue-600 transition duration-300">file.coffee</a>.</p>
|
||||||
|
</header>
|
||||||
|
<main class="w-full max-w-2xl bg-gray-800 p-8 rounded-lg shadow-lg">
|
||||||
|
<section class="mb-8">
|
||||||
|
<h2 class="text-3xl font-semibold mb-4 border-b border-gray-700 pb-2">Statistics</h2>
|
||||||
|
<div class="flex justify-between items-center mb-2">
|
||||||
|
<span>Total uploads:</span>
|
||||||
|
<span class="font-mono text-xl"><%= totalUploads %></span>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<span>Total size:</span>
|
||||||
|
<span class="font-mono text-xl"><%= totalSize %> MB</span>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<h2 class="text-3xl font-semibold mb-4 border-b border-gray-700 pb-2">Contact</h2>
|
||||||
|
<p>Contact the hoster: <a href="mailto:<%= hosterEmail %>" class="text-blue-400 hover:text-blue-600 transition duration-300"><%= hosterEmail %></a></p>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<footer class="mt-12 text-center">
|
||||||
|
<p>Want to host it yourself? <a href="https://github.com/filecoffee/filehost/tree/main" class="text-blue-400 hover:text-blue-600 transition duration-300">GitHub Repository</a></p>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in a new issue