Migrate wekan-accounts-lockout to async API for Meteor 3.0

This commit is contained in:
Harry Adel 2026-01-29 20:12:00 +02:00
parent eb0c9ac1e6
commit 65ce948bb0
3 changed files with 59 additions and 59 deletions

View file

@ -2,7 +2,7 @@
Package.describe({
name: 'wekan-accounts-lockout',
version: '1.0.0',
version: '1.1.0',
summary: 'Meteor package for locking user accounts and stopping brute force attacks',
git: 'https://github.com/lucasantoniassi/meteor-accounts-lockout.git',
documentation: 'README.md',

View file

@ -9,12 +9,12 @@ class KnownUser {
this.settings = settings;
}
startup() {
async startup() {
if (!(this.unchangedSettings instanceof Function)) {
this.updateSettings();
}
this.scheduleUnlocksForLockedAccounts();
KnownUser.unlockAccountsIfLockoutAlreadyExpired();
await this.scheduleUnlocksForLockedAccounts();
await KnownUser.unlockAccountsIfLockoutAlreadyExpired();
this.hookIntoAccounts();
}
@ -49,7 +49,7 @@ class KnownUser {
}
}
scheduleUnlocksForLockedAccounts() {
async scheduleUnlocksForLockedAccounts() {
const lockedAccountsCursor = Meteor.users.find(
{
'services.accounts-lockout.unlockTime': {
@ -63,7 +63,7 @@ class KnownUser {
},
);
const currentTime = Number(new Date());
lockedAccountsCursor.forEach((user) => {
for await (const user of lockedAccountsCursor) {
let lockDuration = KnownUser.unlockTime(user) - currentTime;
if (lockDuration >= this.settings.lockoutPeriod) {
lockDuration = this.settings.lockoutPeriod * 1000;
@ -75,10 +75,10 @@ class KnownUser {
KnownUser.unlockAccount.bind(null, user._id),
lockDuration,
);
});
}
}
static unlockAccountsIfLockoutAlreadyExpired() {
static async unlockAccountsIfLockoutAlreadyExpired() {
const currentTime = Number(new Date());
const query = {
'services.accounts-lockout.unlockTime': {
@ -91,7 +91,7 @@ class KnownUser {
'services.accounts-lockout.failedAttempts': 0,
},
};
Meteor.users.update(query, data);
await Meteor.users.updateAsync(query, data);
}
hookIntoAccounts() {
@ -100,7 +100,7 @@ class KnownUser {
}
validateLoginAttempt(loginInfo) {
async validateLoginAttempt(loginInfo) {
if (
// don't interrupt non-password logins
loginInfo.type !== 'password' ||
@ -130,12 +130,12 @@ class KnownUser {
const canReset = (currentTime - firstFailedAttempt) > (1000 * this.settings.failureWindow);
if (canReset) {
failedAttempts = 1;
KnownUser.resetAttempts(failedAttempts, userId);
await KnownUser.resetAttempts(failedAttempts, userId);
}
const canIncrement = failedAttempts < this.settings.failuresBeforeLockout;
if (canIncrement) {
KnownUser.incrementAttempts(failedAttempts, userId);
await KnownUser.incrementAttempts(failedAttempts, userId);
}
const maxAttemptsAllowed = this.settings.failuresBeforeLockout;
@ -147,7 +147,7 @@ class KnownUser {
KnownUser.tooManyAttempts(duration);
}
if (failedAttempts === maxAttemptsAllowed) {
this.setNewUnlockTime(failedAttempts, userId);
await this.setNewUnlockTime(failedAttempts, userId);
let duration = this.settings.lockoutPeriod;
duration = Math.ceil(duration);
@ -161,7 +161,7 @@ class KnownUser {
);
}
static resetAttempts(
static async resetAttempts(
failedAttempts,
userId,
) {
@ -174,10 +174,10 @@ class KnownUser {
'services.accounts-lockout.firstFailedAttempt': currentTime,
},
};
Meteor.users.update(query, data);
await Meteor.users.updateAsync(query, data);
}
static incrementAttempts(
static async incrementAttempts(
failedAttempts,
userId,
) {
@ -189,10 +189,10 @@ class KnownUser {
'services.accounts-lockout.lastFailedAttempt': currentTime,
},
};
Meteor.users.update(query, data);
await Meteor.users.updateAsync(query, data);
}
setNewUnlockTime(
async setNewUnlockTime(
failedAttempts,
userId,
) {
@ -206,14 +206,14 @@ class KnownUser {
'services.accounts-lockout.unlockTime': newUnlockTime,
},
};
Meteor.users.update(query, data);
await Meteor.users.updateAsync(query, data);
Meteor.setTimeout(
KnownUser.unlockAccount.bind(null, userId),
this.settings.lockoutPeriod * 1000,
);
}
static onLogin(loginInfo) {
static async onLogin(loginInfo) {
if (loginInfo.type !== 'password') {
return;
}
@ -225,7 +225,7 @@ class KnownUser {
'services.accounts-lockout.failedAttempts': 0,
},
};
Meteor.users.update(query, data);
await Meteor.users.updateAsync(query, data);
}
static incorrectPassword(
@ -306,7 +306,7 @@ class KnownUser {
return firstFailedAttempt || 0;
}
static unlockAccount(userId) {
static async unlockAccount(userId) {
const query = { _id: userId };
const data = {
$unset: {
@ -314,7 +314,7 @@ class KnownUser {
'services.accounts-lockout.failedAttempts': 0,
},
};
Meteor.users.update(query, data);
await Meteor.users.updateAsync(query, data);
}
}

View file

@ -13,12 +13,12 @@ class UnknownUser {
this.settings = settings;
}
startup() {
async startup() {
if (!(this.settings instanceof Function)) {
this.updateSettings();
}
this.scheduleUnlocksForLockedAccounts();
this.unlockAccountsIfLockoutAlreadyExpired();
await this.scheduleUnlocksForLockedAccounts();
await this.unlockAccountsIfLockoutAlreadyExpired();
this.hookIntoAccounts();
}
@ -53,7 +53,7 @@ class UnknownUser {
}
}
scheduleUnlocksForLockedAccounts() {
async scheduleUnlocksForLockedAccounts() {
const lockedAccountsCursor = this.AccountsLockoutCollection.find(
{
'services.accounts-lockout.unlockTime': {
@ -67,8 +67,8 @@ class UnknownUser {
},
);
const currentTime = Number(new Date());
lockedAccountsCursor.forEach((connection) => {
let lockDuration = this.unlockTime(connection) - currentTime;
for await (const connection of lockedAccountsCursor) {
let lockDuration = await this.unlockTime(connection) - currentTime;
if (lockDuration >= this.settings.lockoutPeriod) {
lockDuration = this.settings.lockoutPeriod * 1000;
}
@ -79,10 +79,10 @@ class UnknownUser {
this.unlockAccount.bind(this, connection.clientAddress),
lockDuration,
);
});
}
}
unlockAccountsIfLockoutAlreadyExpired() {
async unlockAccountsIfLockoutAlreadyExpired() {
const currentTime = Number(new Date());
const query = {
'services.accounts-lockout.unlockTime': {
@ -95,7 +95,7 @@ class UnknownUser {
'services.accounts-lockout.failedAttempts': 0,
},
};
this.AccountsLockoutCollection.update(query, data);
await this.AccountsLockoutCollection.updateAsync(query, data);
}
hookIntoAccounts() {
@ -103,7 +103,7 @@ class UnknownUser {
Accounts.onLogin(this.onLogin.bind(this));
}
validateLoginAttempt(loginInfo) {
async validateLoginAttempt(loginInfo) {
// don't interrupt non-password logins
if (
loginInfo.type !== 'password' ||
@ -120,20 +120,20 @@ class UnknownUser {
}
const clientAddress = loginInfo.connection.clientAddress;
const unlockTime = this.unlockTime(loginInfo.connection);
let failedAttempts = 1 + this.failedAttempts(loginInfo.connection);
const firstFailedAttempt = this.firstFailedAttempt(loginInfo.connection);
const unlockTime = await this.unlockTime(loginInfo.connection);
let failedAttempts = 1 + await this.failedAttempts(loginInfo.connection);
const firstFailedAttempt = await this.firstFailedAttempt(loginInfo.connection);
const currentTime = Number(new Date());
const canReset = (currentTime - firstFailedAttempt) > (1000 * this.settings.failureWindow);
if (canReset) {
failedAttempts = 1;
this.resetAttempts(failedAttempts, clientAddress);
await this.resetAttempts(failedAttempts, clientAddress);
}
const canIncrement = failedAttempts < this.settings.failuresBeforeLockout;
if (canIncrement) {
this.incrementAttempts(failedAttempts, clientAddress);
await this.incrementAttempts(failedAttempts, clientAddress);
}
const maxAttemptsAllowed = this.settings.failuresBeforeLockout;
@ -145,7 +145,7 @@ class UnknownUser {
UnknownUser.tooManyAttempts(duration);
}
if (failedAttempts === maxAttemptsAllowed) {
this.setNewUnlockTime(failedAttempts, clientAddress);
await this.setNewUnlockTime(failedAttempts, clientAddress);
let duration = this.settings.lockoutPeriod;
duration = Math.ceil(duration);
@ -159,7 +159,7 @@ class UnknownUser {
);
}
resetAttempts(
async resetAttempts(
failedAttempts,
clientAddress,
) {
@ -172,10 +172,10 @@ class UnknownUser {
'services.accounts-lockout.firstFailedAttempt': currentTime,
},
};
this.AccountsLockoutCollection.upsert(query, data);
await this.AccountsLockoutCollection.upsertAsync(query, data);
}
incrementAttempts(
async incrementAttempts(
failedAttempts,
clientAddress,
) {
@ -187,10 +187,10 @@ class UnknownUser {
'services.accounts-lockout.lastFailedAttempt': currentTime,
},
};
this.AccountsLockoutCollection.upsert(query, data);
await this.AccountsLockoutCollection.upsertAsync(query, data);
}
setNewUnlockTime(
async setNewUnlockTime(
failedAttempts,
clientAddress,
) {
@ -204,14 +204,14 @@ class UnknownUser {
'services.accounts-lockout.unlockTime': newUnlockTime,
},
};
this.AccountsLockoutCollection.upsert(query, data);
await this.AccountsLockoutCollection.upsertAsync(query, data);
Meteor.setTimeout(
this.unlockAccount.bind(this, clientAddress),
this.settings.lockoutPeriod * 1000,
);
}
onLogin(loginInfo) {
async onLogin(loginInfo) {
if (loginInfo.type !== 'password') {
return;
}
@ -223,7 +223,7 @@ class UnknownUser {
'services.accounts-lockout.failedAttempts': 0,
},
};
this.AccountsLockoutCollection.update(query, data);
await this.AccountsLockoutCollection.updateAsync(query, data);
}
static userNotFound(
@ -264,14 +264,14 @@ class UnknownUser {
return unknownUsers || false;
}
findOneByConnection(connection) {
return this.AccountsLockoutCollection.findOne({
async findOneByConnection(connection) {
return await this.AccountsLockoutCollection.findOneAsync({
clientAddress: connection.clientAddress,
});
}
unlockTime(connection) {
connection = this.findOneByConnection(connection);
async unlockTime(connection) {
connection = await this.findOneByConnection(connection);
let unlockTime;
try {
unlockTime = connection.services['accounts-lockout'].unlockTime;
@ -281,8 +281,8 @@ class UnknownUser {
return unlockTime || 0;
}
failedAttempts(connection) {
connection = this.findOneByConnection(connection);
async failedAttempts(connection) {
connection = await this.findOneByConnection(connection);
let failedAttempts;
try {
failedAttempts = connection.services['accounts-lockout'].failedAttempts;
@ -292,8 +292,8 @@ class UnknownUser {
return failedAttempts || 0;
}
lastFailedAttempt(connection) {
connection = this.findOneByConnection(connection);
async lastFailedAttempt(connection) {
connection = await this.findOneByConnection(connection);
let lastFailedAttempt;
try {
lastFailedAttempt = connection.services['accounts-lockout'].lastFailedAttempt;
@ -303,8 +303,8 @@ class UnknownUser {
return lastFailedAttempt || 0;
}
firstFailedAttempt(connection) {
connection = this.findOneByConnection(connection);
async firstFailedAttempt(connection) {
connection = await this.findOneByConnection(connection);
let firstFailedAttempt;
try {
firstFailedAttempt = connection.services['accounts-lockout'].firstFailedAttempt;
@ -314,7 +314,7 @@ class UnknownUser {
return firstFailedAttempt || 0;
}
unlockAccount(clientAddress) {
async unlockAccount(clientAddress) {
const query = { clientAddress };
const data = {
$unset: {
@ -322,7 +322,7 @@ class UnknownUser {
'services.accounts-lockout.failedAttempts': 0,
},
};
this.AccountsLockoutCollection.update(query, data);
await this.AccountsLockoutCollection.updateAsync(query, data);
}
}