wekan/server/methods/lockedUsers.js
Lauri Ojansivu ae0d059b6f Feature: Added brute force login protection settings to Admin Panel/People/Locked Users.
Added filtering of Admin Panel/People/People: All Users/Locked Users Only/Active/Not Active.
Added visual indicators: red lock icon for locked users, green check for active users, and red X for inactive users.
Added "Unlock All" button to quickly unlock all brute force locked users.
Added ability to toggle user active status directly from the People page.
Moved lockout settings from environment variables to database so admins can configure the lockout thresholds directly in the UI.

Thanks to xet7.
2025-08-05 00:31:43 +03:00

107 lines
2.9 KiB
JavaScript

import { ReactiveCache } from '/imports/reactiveCache';
// Method to find locked users and release them if needed
Meteor.methods({
getLockedUsers() {
// Check if user has admin rights
const userId = Meteor.userId();
if (!userId) {
throw new Meteor.Error('error-invalid-user', 'Invalid user');
}
const user = ReactiveCache.getUser(userId);
if (!user || !user.isAdmin) {
throw new Meteor.Error('error-not-allowed', 'Not allowed');
}
// Current time to check against unlockTime
const currentTime = Number(new Date());
// Find users that are locked (known users)
const lockedUsers = Meteor.users.find(
{
'services.accounts-lockout.unlockTime': {
$gt: currentTime,
}
},
{
fields: {
_id: 1,
username: 1,
emails: 1,
'services.accounts-lockout.unlockTime': 1,
'services.accounts-lockout.failedAttempts': 1
}
}
).fetch();
// Format the results for the UI
return lockedUsers.map(user => {
const email = user.emails && user.emails.length > 0 ? user.emails[0].address : 'No email';
const remainingLockTime = Math.round((user.services['accounts-lockout'].unlockTime - currentTime) / 1000);
return {
_id: user._id,
username: user.username || 'No username',
email,
failedAttempts: user.services['accounts-lockout'].failedAttempts || 0,
unlockTime: user.services['accounts-lockout'].unlockTime,
remainingLockTime // in seconds
};
});
},
unlockUser(userId) {
// Check if user has admin rights
const adminId = Meteor.userId();
if (!adminId) {
throw new Meteor.Error('error-invalid-user', 'Invalid user');
}
const admin = ReactiveCache.getUser(adminId);
if (!admin || !admin.isAdmin) {
throw new Meteor.Error('error-not-allowed', 'Not allowed');
}
// Make sure the user to unlock exists
const userToUnlock = Meteor.users.findOne(userId);
if (!userToUnlock) {
throw new Meteor.Error('error-user-not-found', 'User not found');
}
// Unlock the user
Meteor.users.update(
{ _id: userId },
{
$unset: {
'services.accounts-lockout': 1
}
}
);
return true;
},
unlockAllUsers() {
// Check if user has admin rights
const adminId = Meteor.userId();
if (!adminId) {
throw new Meteor.Error('error-invalid-user', 'Invalid user');
}
const admin = ReactiveCache.getUser(adminId);
if (!admin || !admin.isAdmin) {
throw new Meteor.Error('error-not-allowed', 'Not allowed');
}
// Unlock all users
Meteor.users.update(
{ 'services.accounts-lockout.unlockTime': { $exists: true } },
{
$unset: {
'services.accounts-lockout': 1
}
},
{ multi: true }
);
return true;
}
});