|
|
@@ -0,0 +1,76 @@
|
|
|
+const router = require('express').Router();
|
|
|
+const bcrypt = require('bcryptjs');
|
|
|
+const jwt = require('jsonwebtoken');
|
|
|
+const { User } = require('../models');
|
|
|
+let config;
|
|
|
+try { config = require('../../config'); } catch(e) { config = { jwt: { secret: 'dev', expiresIn: '7d' } }; }
|
|
|
+const { requireAuth } = require('../middleware/auth');
|
|
|
+
|
|
|
+router.post('/register', async (req, res) => {
|
|
|
+ try {
|
|
|
+ const { login, email, password } = req.body;
|
|
|
+ if (!login || !/^[a-zA-Z0-9_]{3,32}$/.test(login)) {
|
|
|
+ return res.status(400).json({ error: 'Login must be 3-32 alphanumeric characters or underscores' });
|
|
|
+ }
|
|
|
+ if (!password || password.length < 6) {
|
|
|
+ return res.status(400).json({ error: 'Password must be at least 6 characters' });
|
|
|
+ }
|
|
|
+ const existing = await User.findOne({ where: { login } });
|
|
|
+ if (existing) return res.status(409).json({ error: 'Login already taken' });
|
|
|
+
|
|
|
+ const count = await User.count();
|
|
|
+ const isAdmin = count === 0;
|
|
|
+ const isActive = count === 0;
|
|
|
+
|
|
|
+ const passwordHash = await bcrypt.hash(password, 12);
|
|
|
+ const user = await User.create({
|
|
|
+ login, email: email || null, passwordHash, isAdmin, isActive
|
|
|
+ });
|
|
|
+
|
|
|
+ res.status(201).json({
|
|
|
+ id: user.id, login: user.login, email: user.email,
|
|
|
+ isAdmin: user.isAdmin, isActive: user.isActive
|
|
|
+ });
|
|
|
+ } catch (e) {
|
|
|
+ console.error(e);
|
|
|
+ res.status(500).json({ error: 'Server error' });
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+router.post('/login', async (req, res) => {
|
|
|
+ try {
|
|
|
+ const { login, password } = req.body;
|
|
|
+ const user = await User.findOne({ where: { login } });
|
|
|
+ if (!user) return res.status(401).json({ error: 'Invalid credentials' });
|
|
|
+
|
|
|
+ const valid = await bcrypt.compare(password, user.passwordHash);
|
|
|
+ if (!valid) return res.status(401).json({ error: 'Invalid credentials' });
|
|
|
+
|
|
|
+ if (!user.isActive) return res.status(403).json({ error: 'Account not yet activated by admin' });
|
|
|
+
|
|
|
+ const token = jwt.sign(
|
|
|
+ { id: user.id, login: user.login, isAdmin: user.isAdmin },
|
|
|
+ config.jwt.secret,
|
|
|
+ { expiresIn: config.jwt.expiresIn }
|
|
|
+ );
|
|
|
+
|
|
|
+ res.json({ token, user: { id: user.id, login: user.login, isAdmin: user.isAdmin, isActive: user.isActive } });
|
|
|
+ } catch (e) {
|
|
|
+ console.error(e);
|
|
|
+ res.status(500).json({ error: 'Server error' });
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+router.get('/me', requireAuth, async (req, res) => {
|
|
|
+ try {
|
|
|
+ const user = await User.findByPk(req.user.id, {
|
|
|
+ attributes: ['id', 'login', 'email', 'isAdmin', 'isActive', 'createdAt']
|
|
|
+ });
|
|
|
+ if (!user) return res.status(404).json({ error: 'User not found' });
|
|
|
+ res.json(user);
|
|
|
+ } catch (e) {
|
|
|
+ res.status(500).json({ error: 'Server error' });
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+module.exports = router;
|