wip users

This commit is contained in:
Daniël 2024-06-09 15:16:29 +02:00
parent 9e1bde7475
commit 54ddddf855
15 changed files with 2805 additions and 23 deletions

View file

@ -24,3 +24,9 @@ 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. # 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_NAME_LENGTH=10
FILE_MAX_SIZE_MB=30 FILE_MAX_SIZE_MB=30
# Database related settings
DATABASE_URL=mysql://user:password@localhost:3306/filehost
DIALECT=mysql # or sqlite
SQLITE_STORAGE=filehost.sqlite
SESSION_SECRET=your_secret_key

19
config/database.config.js Normal file
View file

@ -0,0 +1,19 @@
const { Sequelize } = require("sequelize");
require("dotenv").config();
let sequelize;
if (process.env.DIALECT === "sqlite") {
sequelize = new Sequelize({
dialect: "sqlite",
storage: process.env.SQLITE_STORAGE,
logging: false,
});
} else {
sequelize = new Sequelize(process.env.DATABASE_URL, {
dialect: process.env.DIALECT,
logging: false,
});
}
module.exports = sequelize;

View file

@ -0,0 +1,31 @@
const { DataTypes } = require("sequelize");
const sequelize = require("../../config/database.config");
const File = sequelize.define("File", {
filename: {
type: DataTypes.STRING,
allowNull: false,
},
originalFileName: {
type: DataTypes.STRING,
allowNull: false,
},
size: {
type: DataTypes.INTEGER,
allowNull: false,
},
md5: {
type: DataTypes.STRING,
allowNull: false,
},
labels: {
type: DataTypes.ARRAY(DataTypes.STRING),
allowNull: false,
},
userId: {
type: DataTypes.INTEGER,
allowNull: false,
},
});
module.exports = File;

View file

@ -0,0 +1,16 @@
const { DataTypes } = require("sequelize");
const sequelize = require("../../config/database.config");
const User = sequelize.define("User", {
username: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
},
password: {
type: DataTypes.STRING,
allowNull: false,
},
});
module.exports = User;

BIN
filehost.sqlite Normal file

Binary file not shown.

View file

@ -1,5 +1,9 @@
require("dotenv").config(); require("dotenv").config();
const express = require("express"); const express = require("express");
const session = require("express-session");
const path = require("path");
const sequelize = require("./config/database.config");
const authRoutes = require("./routes/auth.routes");
const fileRoutes = require("./routes/file.routes"); const fileRoutes = require("./routes/file.routes");
const helmet = require("helmet"); const helmet = require("helmet");
@ -8,6 +12,17 @@ const port = process.env.PORT;
const hosterEmail = process.env.HOSTER_EMAIL; const hosterEmail = process.env.HOSTER_EMAIL;
app.set("view engine", "ejs"); app.set("view engine", "ejs");
app.use(express.urlencoded({ extended: true }));
app.use(express.static(path.join(__dirname, "public")));
app.use(
session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
}),
);
app.use(authRoutes);
app.use(fileRoutes); app.use(fileRoutes);
app.use(helmet()); app.use(helmet());
@ -25,6 +40,11 @@ app.get("/", async (req, res) => {
}); });
}); });
app.listen(port, () => { sequelize
console.log(`Server is running on port ${port}`); .sync()
}); .then(() => {
app.listen(port, () => {
console.log("Server is running on port", port);
});
})
.catch((err) => console.log(err));

View file

@ -0,0 +1,16 @@
const bcrypt = require("bcryptjs");
const User = require("../database/models/user.model");
const authenticate = async (req, res, next) => {
const { username, password } = req.body;
const user = await User.findOne({ where: { username } });
if (user && bcrypt.compareSync(password, user.password)) {
req.session.userId = user.id;
next();
} else {
res.status(401).send("Authentication failed");
}
};
module.exports = authenticate;

2573
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -10,21 +10,28 @@
}, },
"dependencies": { "dependencies": {
"aws-sdk": "^2.1632.0", "aws-sdk": "^2.1632.0",
"bcryptjs": "^2.4.3",
"dotenv": "^16.4.5", "dotenv": "^16.4.5",
"ejs": "^3.1.10", "ejs": "^3.1.10",
"express": "^4.19.2", "express": "^4.19.2",
"express-rate-limit": "^7.3.1", "express-rate-limit": "^7.3.1",
"express-session": "^1.18.0",
"express-slow-down": "^2.0.3", "express-slow-down": "^2.0.3",
"helmet": "^7.1.0", "helmet": "^7.1.0",
"mime-types": "^2.1.35", "mime-types": "^2.1.35",
"multer": "^1.4.5-lts.1", "multer": "^1.4.5-lts.1",
"nanoid": "^3.3.7" "mysql2": "^3.10.0",
"nanoid": "^3.3.7",
"sequelize": "^6.37.3",
"sqlite3": "^5.1.7"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.24.6", "@babel/core": "^7.24.6",
"@babel/preset-env": "^7.24.6", "@babel/preset-env": "^7.24.6",
"babel-jest": "^29.7.0", "babel-jest": "^29.7.0",
"jest": "^29.7.0", "jest": "^29.7.0",
"nodemon": "^3.1.3",
"sequelize-cli": "^6.6.2",
"supertest": "^7.0.0" "supertest": "^7.0.0"
} }
} }

1
public/test.txt Normal file
View file

@ -0,0 +1 @@
Hello, world!

23
routes/auth.routes.js Normal file
View file

@ -0,0 +1,23 @@
const express = require("express");
const bcrypt = require("bcryptjs");
const User = require("../database/models/user.model");
const authenticate = require("../middlewares/auth.middleware");
const router = express.Router();
router.post("/register", async (req, res) => {
const { username, password } = req.body;
const hashedPassword = bcrypt.hashSync(password, 10);
await User.create({ username, password: hashedPassword });
res.redirect("/login");
});
router.post("/login", authenticate, (req, res) => {
res.redirect("/dashboard");
});
router.get("/logout", (req, res) => {
req.session.destroy();
res.redirect("/login");
});
module.exports = router;

View file

@ -23,4 +23,10 @@ const authenticate = (req, res, next) => {
router.post("/upload", authenticate, uploadFile); router.post("/upload", authenticate, uploadFile);
router.get("/u/:filename", getFile); router.get("/u/:filename", getFile);
router.get("/files", async (req, res) => {
const userId = req.session.userId;
const files = await File.findAll({ where: { userId } });
res.render("files", { files });
});
module.exports = router; module.exports = router;

34
views/auth/login.ejs Normal file
View file

@ -0,0 +1,34 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login</title>
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
<style>
.bg-gray-custom { background-color: #181818; }
.coffee-color { color: #C084FC; }
.bg-coffee-color { background-color: #C084FC; }
</style>
</head>
<body class="bg-gray-custom 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">Login</h1>
</header>
<main class="w-full max-w-md bg-coffee-color p-8 rounded-lg shadow-lg">
<form action="/login" method="POST">
<div class="mb-4">
<label for="username" class="block text-sm font-medium">Username</label>
<input type="text" name="username" id="username" class="w-full p-2 mt-1 rounded">
</div>
<div class="mb-4">
<label for="password" class="block text-sm font-medium">Password</label>
<input type="password" name="password" id="password" class="w-full p-2 mt-1 rounded">
</div>
<button type="submit" class="w-full bg-gray-900 text-white p-2 rounded">Login</button>
</form>
</main>
</div>
</body>
</html>

34
views/auth/register.ejs Normal file
View file

@ -0,0 +1,34 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Register</title>
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
<style>
.bg-gray-custom { background-color: #181818; }
.coffee-color { color: #C084FC; }
.bg-coffee-color { background-color: #C084FC; }
</style>
</head>
<body class="bg-gray-custom 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">Register</h1>
</header>
<main class="w-full max-w-md bg-coffee-color p-8 rounded-lg shadow-lg">
<form action="/register" method="POST">
<div class="mb-4">
<label for="username" class="block text-sm font-medium">Username</label>
<input type="text" name="username" id="username" class="w-full p-2 mt-1 rounded">
</div>
<div class="mb-4">
<label for="password" class="block text-sm font-medium">Password</label>
<input type="password" name="password" id="password" class="w-full p-2 mt-1 rounded">
</div>
<button type="submit" class="w-full bg-gray-900 text-white p-2 rounded">Register</button>
</form>
</main>
</div>
</body>
</html>

34
views/files.ejs Normal file
View file

@ -0,0 +1,34 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Your Files</title>
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
<style>
.bg-gray-custom { background-color: #181818; }
.coffee-color { color: #C084FC; }
.bg-coffee-color { background-color: #C084FC; }
</style>
</head>
<body class="bg-gray-custom 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">Your Files</h1>
</header>
<main class="w-full max-w-2xl bg-coffee-color p-8 rounded-lg shadow-lg">
<section class="mb-8">
<h2 class="text-3xl font-semibold mb-4 border-b border-white pb-2">Files</h2>
<form action="/files" method="GET" class="mb-4">
<input type="text" name="search" placeholder="Search by filename" class="w-full p-2 rounded">
</form>
<ul>
<% files.forEach(file => { %>
<li class="mb-2"><%= file.filename %> - <%= file.size %> MB</li>
<% }) %>
</ul>
</section>
</main>
</div>
</body>
</html>