LibreChat/api/server/controllers/auth/PasskeyController.js
Marco Beretta 4c6ea7e981
🔐 fix: Hash Passwords on a Worker Pool and Surface API Key Lookup Failures (#17261)
* fix: Hash Off the Event Loop and Surface API Key Lookup Failures

Registration, email verification, password reset and verification resends
hashed and compared with bcryptjs's synchronous calls. bcryptjs is pure
JavaScript, so each call blocked the event loop for every request in the
process. They now use the promise APIs, and the password reset
dependencies are async.

validateAgentApiKey caught its own query failures and returned null, so a
database outage answered remote callers with 401 Invalid API key. It now
lets the failure reach requireApiKeyAuth, which answers with a 500.

* fix: Run bcrypt on a Worker Pool in packages/api

bcryptjs's promise API still computes on the main thread, only in chunks
of up to 100 ms, so concurrent registrations and resets kept stalling
unrelated requests (four cost-10 hashes delayed a 5 ms timer by about
190 ms). hashSecret and compareSecret now run bcryptjs on a small
worker_threads pool in packages/api, and AuthService.js calls them.

* feat: Configure the Password Hashing Worker Count

* fix: Verify Login and Step-Up Passwords on the Hash Pool
2026-10-19 22:13:31 +02:00

23 lines
898 B
JavaScript

const { CacheKeys } = require('librechat-data-provider');
const { createPasskeyHandlers, compareSecret } = require('@librechat/api');
const { checkBan } = require('~/server/middleware');
const { getLogStores } = require('~/cache');
const { getAppConfig } = require('~/server/services/Config/app');
const db = require('~/models');
module.exports = createPasskeyHandlers({
checkBan,
compare: compareSecret,
getChallengeCache: () => getLogStores(CacheKeys.PASSKEY_CHALLENGE),
getAppConfig,
getUserById: db.getUserById,
updateUser: db.updateUser,
createPasskey: db.createPasskey,
deletePasskey: db.deletePasskey,
renamePasskey: db.renamePasskey,
recordPasskeyUse: db.recordPasskeyUse,
findPasskeysByUser: db.findPasskeysByUser,
countPasskeysByUser: db.countPasskeysByUser,
findPasskeyByCredentialId: db.findPasskeyByCredentialId,
recordAuditEntry: db.recordAuditEntry,
});