This commit is contained in:
2026-04-26 00:08:27 +02:00
parent 92074e7f60
commit c3e5448597
40 changed files with 1783 additions and 54 deletions

175
backend/src/routes/user.js Normal file
View File

@@ -0,0 +1,175 @@
const express = require('express')
const router = express.Router();
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const passport = require('passport');
const secret = require('../services/keys').secret;
const rateLimitMiddleware = require("../services/rate-limiter");
const crypto = require("crypto");
const { isAdmin } = require('../services/middleware');
const User = require("../models/User");
const upload = require("../services/storage");
// Admin registers new user
router.post('/register', isAdmin, async (req, res) => {
try {
let setupCode = crypto.randomBytes(64).toString('base64url');
let user = new User({
admin: false,
name: crypto.randomBytes(16).toString('base64url'),
username: crypto.randomBytes(16).toString('base64url'),
email: crypto.randomBytes(16).toString('base64url'),
setupCode
});
await user.save();
res.json({ status: "ok", code: setupCode });
} catch (err) {
res.json({ status: "error", msg: "internal" });
}
});
// User gets if setup account exists given the query code
router.get('/verify-setup', async (req, res) => {
try {
const user = await User.findOne({ setupCode: req.query.code });
if (user) {
res.json({ status: "ok", code: req.query.code });
} else {
res.json({ status: "error", msg: "not-exists" });
}
} catch (err) {
res.json({ status: "error", msg: "internal" });
}
});
// User posts the parameters of his new account given by admin
router.post('/setup', rateLimitMiddleware, async (req, res) => {
const { name, username, email, password } = req.body;
const setupCode = req.query.code;
if (!(name && username && email && password && setupCode)) {
return res.json({ status: "error", msg: "params" });
}
try {
const user = await User.findOne({ setupCode });
if (!user) {
return res.json({ status: "error", msg: "not-found" });
}
const sameUser = await User.findOne({ email });
if (sameUser) {
return res.json({ status: "error", msg: "already-email" });
}
const salt = await bcrypt.genSalt(10);
user.password = await bcrypt.hash(password, salt);
user.username = username;
user.email = email;
user.setupCode = undefined;
await user.save();
res.json({ status: "ok" });
} catch (err) {
res.json({ status: "error", msg: "internal" });
}
});
// Login post
router.post('/login', rateLimitMiddleware, async (req, res) => {
const { username, password } = req.body;
if (!(username && password)) {
return res.json({ status: "error", msg: "params" });
}
try {
const user = await User.findOne({ username });
if (!user) {
return res.json({ status: "error", msg: "wrong" });
}
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) {
return res.json({ status: "error", msg: "wrong" });
}
const payload = {
_id: user._id,
username: user.username,
name: user.name,
email: user.email,
admin: user.admin,
settings: user.settings
};
const token = await new Promise((resolve, reject) => {
jwt.sign(payload, secret, { expiresIn: 172800 }, (err, token) => {
if (err) reject(err);
else resolve(token);
});
});
res.json({ status: "ok", token, msg: "success" });
} catch (err) {
res.json({ status: "error", msg: "internal" });
}
});
// Upload avatar post
router.post("/upload-avatar", upload.single("image"), passport.authenticate('jwt', {session: false}), async (req, res) => {
try {
const imageName = req.file.filename;
await User.updateOne(req.user, { image: imageName });
res.json({ status: "ok", msg: "uploaded" });
} catch (err) {
res.json({ status: "error", msg: "internal" });
}
});
router.get("/retrieve-avatar", async (req, res) => {
try {
const data = await User.findOne({ username: req.query.username });
res.json({ status: "ok", image: data.image });
} catch (err) {
res.json({ status: "error" });
}
});
router.get("/has-admin", async (req, res) => {
try {
const data = await User.findOne({ admin: true });
if (data) res.json({ status: "ok" });
else res.json({ status: "init" });
} catch (err) {
res.json({ status: "error" });
}
});
router.post("/update-settings", passport.authenticate('jwt', {session: false}), async (req, res) => {
try {
await User.updateOne(req.user, { settings: req.body.settings });
res.json({ status: "ok", settings: req.body.settings });
} catch (err) {
res.json({ status: "error", msg: "internal" });
}
});
router.get('/get-settings', passport.authenticate('jwt', {session: false}), async (req, res) => {
try {
const data = await User.findOne(req.user);
res.json({ status: "ok", settings: data.settings });
} catch (err) {
res.json({ status: "error", msg: "internal" });
}
});
module.exports = router;