diff --git a/backend/package-lock.json b/backend/package-lock.json index c736a2c..1a0cb8e 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -19,7 +19,8 @@ "mongoose": "^9.3.0", "multer": "^2.1.1", "nodemon": "^3.1.14", - "passport": "^0.7.0" + "passport": "^0.7.0", + "passport-jwt": "^4.0.1" } }, "node_modules/@mongodb-js/saslprep": { @@ -1256,6 +1257,16 @@ "url": "https://github.com/sponsors/jaredhanson" } }, + "node_modules/passport-jwt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/passport-jwt/-/passport-jwt-4.0.1.tgz", + "integrity": "sha512-UCKMDYhNuGOBE9/9Ycuoyh7vP6jpeTp/+sfMJl7nLff/t6dps+iaeE0hhNkKN8/HZHcJ7lCdOyDxHdDoxoSvdQ==", + "license": "MIT", + "dependencies": { + "jsonwebtoken": "^9.0.0", + "passport-strategy": "^1.0.0" + } + }, "node_modules/passport-strategy": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", diff --git a/backend/package.json b/backend/package.json index 8bd69b9..dc5f417 100644 --- a/backend/package.json +++ b/backend/package.json @@ -20,6 +20,7 @@ "mongoose": "^9.3.0", "multer": "^2.1.1", "nodemon": "^3.1.14", - "passport": "^0.7.0" + "passport": "^0.7.0", + "passport-jwt": "^4.0.1" } } diff --git a/backend/src/index.js b/backend/src/index.js index f15f5d4..99a0467 100644 --- a/backend/src/index.js +++ b/backend/src/index.js @@ -26,6 +26,9 @@ app.use(express.urlencoded({ // connect database connectDB(); +app.use(passport.initialize()); +require('./services/passport')(passport); + // CORS app.use(cookieParser()); diff --git a/backend/src/routes/user.js b/backend/src/routes/user.js index fabd5e2..3c1a548 100644 --- a/backend/src/routes/user.js +++ b/backend/src/routes/user.js @@ -15,24 +15,44 @@ const User = require("../models/User"); const upload = require("../services/storage"); - -// Admin registers new user -router.post('/register', isAdmin, async (req, res) => { +router.post('/register', async (req, res) => { try { - let setupCode = crypto.randomBytes(64).toString('base64url'); - + const existsAdmin = !!(await User.findOne({ admin: true })); + const { + username, + email, + name, + password + } = req.body; + + // Check if email or username already exists + const existingUser = await User.findOne({ + $or: [ + { email: email }, + { username: username } + ] + }); + + if (existingUser) { + return res.json({ + status: "error", + msg: "register.errors.email-username-exists" + }); + } + + const salt = await bcrypt.genSalt(10); 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 + admin: !existsAdmin, + name: name, + username: username, + email: email, + password: await bcrypt.hash(password, salt) }); await user.save(); res.json({ status: "ok", code: setupCode }); } catch (err) { - res.json({ status: "error", msg: "internal" }); + res.json({ status: "error", msg: "errors.internal" }); } }); @@ -85,21 +105,21 @@ router.post('/setup', rateLimitMiddleware, async (req, res) => { // Login post router.post('/login', rateLimitMiddleware, async (req, res) => { - const { username, password } = req.body; + const { usermail, password } = req.body; - if (!(username && password)) { - return res.json({ status: "error", msg: "params" }); + if (!(usermail && password)) { + return res.json({ status: "error", msg: "login.errors.params" }); } try { - const user = await User.findOne({ username }); + const user = await User.findOne({ $or: [{ username: usermail }, { email: usermail }] }); if (!user) { - return res.json({ status: "error", msg: "wrong" }); + return res.json({ status: "error", msg: "login.errors.invalid-credentials" }); } const isMatch = await bcrypt.compare(password, user.password); if (!isMatch) { - return res.json({ status: "error", msg: "wrong" }); + return res.json({ status: "error", msg: "login.errors.invalid-credentials" }); } const payload = { @@ -120,7 +140,7 @@ router.post('/login', rateLimitMiddleware, async (req, res) => { res.json({ status: "ok", token, msg: "success" }); } catch (err) { - res.json({ status: "error", msg: "internal" }); + res.json({ status: "error", msg: "errors.internal" }); } }); diff --git a/backend/src/services/passport.js b/backend/src/services/passport.js new file mode 100644 index 0000000..22f286f --- /dev/null +++ b/backend/src/services/passport.js @@ -0,0 +1,25 @@ +const JwtStrategy = require('passport-jwt').Strategy; +const ExtractJwt = require('passport-jwt').ExtractJwt; + +const User = require('../models/User'); +const key = require('./keys').secret; + +const opts = { + jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), + secretOrKey: key +}; + +module.exports = passport => { + passport.use( + new JwtStrategy(opts, async (jwt_payload, done) => { + try { + const user = await User.findById(jwt_payload._id); + if (user) return done(null, user); + return done(null, false); + } catch (err) { + console.log(err); + return done(err, false); + } + }) + ) +} \ No newline at end of file