Fixed multiple bugs
This commit is contained in:
@@ -23,26 +23,24 @@ const activate = async (req, res, next) => {
|
||||
}
|
||||
};
|
||||
|
||||
const loginUser = async (req, res) => {
|
||||
const { username, password } = req.body;
|
||||
const user = await User.findOne({ where: { username } });
|
||||
if (!user || !(await user.validatePassword(password))) {
|
||||
return res.status(401).json({ message: 'Ungültige Anmeldedaten' });
|
||||
const loginUser = async (req, res, next) => {
|
||||
try {
|
||||
const { email, password } = req.body;
|
||||
const result = await login(email, password);
|
||||
res.status(200).json(result);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
const token = jwt.sign({ userId: user.id }, process.env.JWT_SECRET, { expiresIn: '1h' });
|
||||
await UserToken.create({
|
||||
userId: user.id,
|
||||
token,
|
||||
expiresAt: new Date(Date.now() + 3600 * 1000),
|
||||
});
|
||||
res.json({ token });
|
||||
};
|
||||
|
||||
const logoutUser = async (req, res) => {
|
||||
const token = req.headers['authorization']?.split(' ')[1];
|
||||
if (!token) return res.status(400).json({ message: 'Token fehlt' });
|
||||
await UserToken.destroy({ where: { token } });
|
||||
res.json({ message: 'Logout erfolgreich' });
|
||||
const logoutUser = async (req, res, next) => {
|
||||
try {
|
||||
const token = req.headers['authorization']?.split(' ')[1];
|
||||
const result = await logout(token);
|
||||
res.status(200).json(result);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
};
|
||||
|
||||
export { registerUser, activate, loginUser, logoutUser };
|
||||
|
||||
@@ -1,18 +1,23 @@
|
||||
import User from '../models/User.js';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import UserToken from '../models/UserToken.js';
|
||||
|
||||
export const authenticate = async (req, res, next) => {
|
||||
try {
|
||||
const { userid: userId, authcode: authCode } = req.headers;
|
||||
if (!userId || !authCode) {
|
||||
return res.status(401).json({ error: 'Unauthorized: Missing credentials' });
|
||||
}
|
||||
const user = await User.findOne({ where: { email: userId, authCode: authCode } });
|
||||
if (!user) {
|
||||
return res.status(401).json({ error: 'Unauthorized: Invalid credentials' });
|
||||
}
|
||||
next();
|
||||
} catch(error) {
|
||||
console.log(error);
|
||||
return res.status(500).json({ error: 'Internal Server Error at auth' });
|
||||
let token = req.headers['authorization']?.split(' ')[1];
|
||||
if (!token) {
|
||||
token = req.headers['authcode'];
|
||||
}
|
||||
if (!token) {
|
||||
return res.status(401).json({ error: 'Unauthorized: Token fehlt' });
|
||||
}
|
||||
try {
|
||||
const decoded = jwt.verify(token, process.env.JWT_SECRET);
|
||||
const tokenRecord = await UserToken.findOne({ where: { token } });
|
||||
if (!tokenRecord || tokenRecord.expiresAt < new Date()) {
|
||||
return res.status(401).json({ error: 'Unauthorized: Invalid credentials' });
|
||||
}
|
||||
req.user = { id: decoded.userId };
|
||||
next();
|
||||
} catch (err) {
|
||||
return res.status(401).json({ error: 'Unauthorized: Invalid credentials' });
|
||||
}
|
||||
};
|
||||
@@ -63,4 +63,8 @@ const User = sequelize.define('User', {
|
||||
},
|
||||
});
|
||||
|
||||
User.prototype.validatePassword = function(password) {
|
||||
return bcrypt.compare(password, this.password);
|
||||
};
|
||||
|
||||
export default User;
|
||||
|
||||
@@ -27,6 +27,7 @@ import TournamentMember from './TournamentMember.js';
|
||||
import TournamentMatch from './TournamentMatch.js';
|
||||
import TournamentResult from './TournamentResult.js';
|
||||
import Accident from './Accident.js';
|
||||
import UserToken from './UserToken.js';
|
||||
|
||||
User.hasMany(Log, { foreignKey: 'userId' });
|
||||
Log.belongsTo(User, { foreignKey: 'userId' });
|
||||
@@ -203,4 +204,5 @@ export {
|
||||
TournamentMatch,
|
||||
TournamentResult,
|
||||
Accident,
|
||||
UserToken,
|
||||
};
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
DiaryNote, DiaryTag, MemberDiaryTag, DiaryDateTag, DiaryMemberNote, DiaryMemberTag,
|
||||
PredefinedActivity, DiaryDateActivity, Match, League, Team, Group,
|
||||
GroupActivity, Tournament, TournamentGroup, TournamentMatch, TournamentResult,
|
||||
TournamentMember, Accident
|
||||
TournamentMember, Accident, UserToken
|
||||
} from './models/index.js';
|
||||
import authRoutes from './routes/authRoutes.js';
|
||||
import clubRoutes from './routes/clubRoutes.js';
|
||||
@@ -99,6 +99,7 @@ app.get('*', (req, res) => {
|
||||
await TournamentMatch.sync({ alter: true });
|
||||
await TournamentResult.sync({ alter: true });
|
||||
await Accident.sync({ alter: true });
|
||||
await UserToken.sync({ alter: true });
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`Server is running on http://localhost:${port}`);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import bcrypt from 'bcrypt';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import User from '../models/User.js';
|
||||
import UserToken from '../models/UserToken.js';
|
||||
import { sendActivationEmail } from './emailService.js';
|
||||
|
||||
const register = async (email, password) => {
|
||||
@@ -25,22 +26,28 @@ const activateUser = async (activationCode) => {
|
||||
};
|
||||
|
||||
const login = async (email, password) => {
|
||||
if (!email || !password) {
|
||||
throw { status: 400, message: 'Email und Passwort sind erforderlich.' };
|
||||
}
|
||||
const user = await User.findOne({ where: { email } });
|
||||
if (!user || !user.isActive) throw new Error('Invalid email or password.');
|
||||
const isPasswordValid = await bcrypt.compare(password, user.password);
|
||||
if (!isPasswordValid) throw new Error('Invalid email or password!');
|
||||
const token = jwt.sign({ userId: user.hashedId }, process.env.JWT_SECRET, { expiresIn: '1h' });
|
||||
user.authCode = token;
|
||||
await user.save();
|
||||
if (!user || !(await bcrypt.compare(password, user.password))) {
|
||||
throw { status: 401, message: 'Ungültige Anmeldedaten' };
|
||||
}
|
||||
const token = jwt.sign({ userId: user.id }, process.env.JWT_SECRET, { expiresIn: '1h' });
|
||||
await UserToken.create({
|
||||
userId: user.id,
|
||||
token,
|
||||
expiresAt: new Date(Date.now() + 3600 * 1000),
|
||||
});
|
||||
return { token };
|
||||
};
|
||||
|
||||
const logout = async(userId, authToken) => {
|
||||
const user = await User.findOne({ where: { id: userId, authToken: authToken }});
|
||||
if (!user) {
|
||||
throw new Error('not found');
|
||||
const logout = async (token) => {
|
||||
if (!token) {
|
||||
throw { status: 400, message: 'Token fehlt' };
|
||||
}
|
||||
user.update({ authToken: null });
|
||||
}
|
||||
await UserToken.destroy({ where: { token } });
|
||||
return { message: 'Logout erfolgreich' };
|
||||
};
|
||||
|
||||
export { register, activateUser, login, logout };
|
||||
|
||||
@@ -1,24 +1,45 @@
|
||||
import User from '../models/User.js'
|
||||
import UserClub from '../models/UserClub.js';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { Op } from 'sequelize';
|
||||
import User from '../models/User.js';
|
||||
import UserToken from '../models/UserToken.js';
|
||||
import UserClub from '../models/UserClub.js'; // <-- hier hinzufügen
|
||||
import HttpError from '../exceptions/HttpError.js';
|
||||
import { config } from 'dotenv';
|
||||
config(); // sorgt dafür, dass process.env.JWT_SECRET geladen wird
|
||||
|
||||
export const getUserByToken = async(token) => {
|
||||
export const getUserByToken = async (token) => {
|
||||
try {
|
||||
const user = await User.findOne({
|
||||
where: [
|
||||
{auth_code: token}
|
||||
]
|
||||
});
|
||||
return user;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
const err = new HttpError('noaccess', 403);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
// 1. JWT validieren
|
||||
const payload = jwt.verify(token, process.env.JWT_SECRET);
|
||||
|
||||
export const hasUserClubAccess = async(userId, clubId) => {
|
||||
// 2. Token-Eintrag prüfen (existiert und nicht abgelaufen)
|
||||
const stored = await UserToken.findOne({
|
||||
where: {
|
||||
token,
|
||||
expiresAt: { [Op.gt]: new Date() }
|
||||
}
|
||||
});
|
||||
if (!stored) {
|
||||
throw new HttpError('Token abgelaufen oder ungültig', 401);
|
||||
}
|
||||
|
||||
// 3. User laden
|
||||
const user = await User.findByPk(payload.userId);
|
||||
if (!user) {
|
||||
throw new HttpError('Benutzer nicht gefunden', 404);
|
||||
}
|
||||
|
||||
return user;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
// Falls es ein HttpError ist, einfach weiterwerfen
|
||||
if (err instanceof HttpError) throw err;
|
||||
// ansonsten pauschal „noaccess“
|
||||
throw new HttpError('noaccess', 403);
|
||||
}
|
||||
};
|
||||
|
||||
export const hasUserClubAccess = async (userId, clubId) => {
|
||||
try {
|
||||
console.log('[hasUserClubAccess]');
|
||||
const userClub = await UserClub.findOne({
|
||||
@@ -29,23 +50,23 @@ export const hasUserClubAccess = async(userId, clubId) => {
|
||||
}
|
||||
});
|
||||
return userClub !== null;
|
||||
} catch(error) {
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
throw new HttpError('notfound', 500);
|
||||
}
|
||||
console.log('---- no user found');
|
||||
}
|
||||
|
||||
export const checkAccess = async(userToken, clubId) => {
|
||||
export const checkAccess = async (userToken, clubId) => {
|
||||
try {
|
||||
const user = await getUserByToken(userToken);
|
||||
if (!await hasUserClubAccess(user.id, clubId)) {
|
||||
const hasAccess = await hasUserClubAccess(user.id, clubId);
|
||||
if (!hasAccess) {
|
||||
console.log('no club access');
|
||||
const err = new HttpError('noaccess', 403);
|
||||
throw err;
|
||||
throw new HttpError('noaccess', 403);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
throw error;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user