mirror of
https://github.com/9technologygroup/patchmon.net.git
synced 2025-11-12 18:06:39 +00:00
Added mfa and css enhancements
This commit is contained in:
@@ -344,6 +344,14 @@ router.post('/login', [
|
||||
{ email: username }
|
||||
],
|
||||
isActive: true
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
username: true,
|
||||
email: true,
|
||||
passwordHash: true,
|
||||
role: true,
|
||||
tfaEnabled: true
|
||||
}
|
||||
});
|
||||
|
||||
@@ -357,6 +365,15 @@ router.post('/login', [
|
||||
return res.status(401).json({ error: 'Invalid credentials' });
|
||||
}
|
||||
|
||||
// Check if TFA is enabled
|
||||
if (user.tfaEnabled) {
|
||||
return res.status(200).json({
|
||||
message: 'TFA verification required',
|
||||
requiresTfa: true,
|
||||
username: user.username
|
||||
});
|
||||
}
|
||||
|
||||
// Update last login
|
||||
await prisma.user.update({
|
||||
where: { id: user.id },
|
||||
@@ -382,6 +399,102 @@ router.post('/login', [
|
||||
}
|
||||
});
|
||||
|
||||
// TFA verification for login
|
||||
router.post('/verify-tfa', [
|
||||
body('username').notEmpty().withMessage('Username is required'),
|
||||
body('token').isLength({ min: 6, max: 6 }).withMessage('Token must be 6 digits'),
|
||||
body('token').isNumeric().withMessage('Token must contain only numbers')
|
||||
], async (req, res) => {
|
||||
try {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) {
|
||||
return res.status(400).json({ errors: errors.array() });
|
||||
}
|
||||
|
||||
const { username, token } = req.body;
|
||||
|
||||
// Find user
|
||||
const user = await prisma.user.findFirst({
|
||||
where: {
|
||||
OR: [
|
||||
{ username },
|
||||
{ email: username }
|
||||
],
|
||||
isActive: true,
|
||||
tfaEnabled: true
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
username: true,
|
||||
email: true,
|
||||
role: true,
|
||||
tfaSecret: true,
|
||||
tfaBackupCodes: true
|
||||
}
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
return res.status(401).json({ error: 'Invalid credentials or TFA not enabled' });
|
||||
}
|
||||
|
||||
// Verify TFA token using the TFA routes logic
|
||||
const speakeasy = require('speakeasy');
|
||||
|
||||
// Check if it's a backup code
|
||||
const backupCodes = user.tfaBackupCodes ? JSON.parse(user.tfaBackupCodes) : [];
|
||||
const isBackupCode = backupCodes.includes(token);
|
||||
|
||||
let verified = false;
|
||||
|
||||
if (isBackupCode) {
|
||||
// Remove the used backup code
|
||||
const updatedBackupCodes = backupCodes.filter(code => code !== token);
|
||||
await prisma.user.update({
|
||||
where: { id: user.id },
|
||||
data: {
|
||||
tfaBackupCodes: JSON.stringify(updatedBackupCodes)
|
||||
}
|
||||
});
|
||||
verified = true;
|
||||
} else {
|
||||
// Verify TOTP token
|
||||
verified = speakeasy.totp.verify({
|
||||
secret: user.tfaSecret,
|
||||
encoding: 'base32',
|
||||
token: token,
|
||||
window: 2
|
||||
});
|
||||
}
|
||||
|
||||
if (!verified) {
|
||||
return res.status(401).json({ error: 'Invalid verification code' });
|
||||
}
|
||||
|
||||
// Update last login
|
||||
await prisma.user.update({
|
||||
where: { id: user.id },
|
||||
data: { lastLogin: new Date() }
|
||||
});
|
||||
|
||||
// Generate token
|
||||
const jwtToken = generateToken(user.id);
|
||||
|
||||
res.json({
|
||||
message: 'Login successful',
|
||||
token: jwtToken,
|
||||
user: {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
email: user.email,
|
||||
role: user.role
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('TFA verification error:', error);
|
||||
res.status(500).json({ error: 'TFA verification failed' });
|
||||
}
|
||||
});
|
||||
|
||||
// Get current user profile
|
||||
router.get('/profile', authenticateToken, async (req, res) => {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user