UNPKG

@fdm-monster/server

Version:

FDM Monster is a bulk OctoPrint manager to set up, configure and monitor 3D printers. Our aim is to provide extremely optimized websocket performance and reliability.

129 lines (128 loc) 6.07 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "AuthService", { enumerable: true, get: function() { return AuthService; } }); const _runtimeexceptions = require("../../exceptions/runtime.exceptions"); const _cryptoutils = require("../../utils/crypto.utils"); const _authorizationconstants = require("../../constants/authorization.constants"); const _node = require("@sentry/node"); class AuthService { userService; jwtService; settingsStore; refreshTokenService; logger; blacklistedJwtCache; constructor(loggerFactory, userService, jwtService, settingsStore, refreshTokenService){ this.userService = userService; this.jwtService = jwtService; this.settingsStore = settingsStore; this.refreshTokenService = refreshTokenService; this.blacklistedJwtCache = {}; this.logger = loggerFactory(AuthService.name); } async loginUser(username, password) { const userDoc = await this.userService.findRawByUsername(username); if (!userDoc) { throw new _runtimeexceptions.AuthenticationError("Login incorrect", _authorizationconstants.AUTH_ERROR_REASON.IncorrectCredentials); } const result = (0, _cryptoutils.comparePasswordHash)(password, userDoc.passwordHash); if (!result) { throw new _runtimeexceptions.AuthenticationError("Login incorrect", _authorizationconstants.AUTH_ERROR_REASON.IncorrectCredentials); } const userId = userDoc.id; const token = await this.signJwtToken(userId); await this.refreshTokenService.purgeOutdatedRefreshTokensByUserId(userId); await this.purgeOutdatedBlacklistedJwtCache(); const refreshToken = await this.refreshTokenService.createRefreshTokenForUserId(userId); return { token, refreshToken }; } async logoutUserId(userId, jwtToken) { await this.refreshTokenService.deleteRefreshTokenByUserId(userId); if (jwtToken?.length) { this.blacklistedJwtCache[jwtToken] = { userId, createdAt: Date.now() }; await this.purgeOutdatedBlacklistedJwtCache(); } } async purgeOutdatedBlacklistedJwtCache() { try { const { jwtExpiresIn } = await this.settingsStore.getCredentialSettings(); const now = Date.now(); const keys = Object.keys(this.blacklistedJwtCache); for (const key of keys){ const { createdAt } = this.blacklistedJwtCache[key]; if (now - createdAt > jwtExpiresIn) { delete this.blacklistedJwtCache[key]; } } } catch (err) { this.logger.error("Failed to purge blacklisted jwt cache", err); (0, _node.captureException)(err); } } async logoutUserRefreshToken(refreshToken) { const userRefreshToken = await this.getValidRefreshToken(refreshToken); await this.refreshTokenService.deleteRefreshTokenByUserId(userRefreshToken.userId); } async renewLoginByRefreshToken(refreshToken) { const userRefreshToken = await this.getValidRefreshToken(refreshToken); const userId = userRefreshToken.userId; const user = await this.userService.getUser(userId); if (!user) { await this.refreshTokenService.deleteRefreshToken(refreshToken); throw new _runtimeexceptions.AuthenticationError("User not found", _authorizationconstants.AUTH_ERROR_REASON.InvalidOrExpiredRefreshToken); } const token = await this.signJwtToken(userId); await this.increaseRefreshTokenAttemptsUsed(userRefreshToken.refreshToken); return token; } isJwtTokenBlacklisted(jwtToken) { return this.blacklistedJwtCache[jwtToken]; } async getValidRefreshToken(refreshToken) { const userRefreshToken = await this.refreshTokenService.getRefreshToken(refreshToken); if (Date.now() > userRefreshToken.expiresAt) { await this.refreshTokenService.deleteRefreshTokenByUserId(userRefreshToken.userId); throw new _runtimeexceptions.AuthenticationError("Refresh token expired, login required", _authorizationconstants.AUTH_ERROR_REASON.InvalidOrExpiredRefreshToken); } return userRefreshToken; } async increaseRefreshTokenAttemptsUsed(refreshToken) { const { refreshTokenAttempts } = await this.settingsStore.getCredentialSettings(); const userRefreshToken = await this.getValidRefreshToken(refreshToken); const attemptsUsed = userRefreshToken.refreshAttemptsUsed; if (refreshTokenAttempts !== -1) { if (attemptsUsed >= refreshTokenAttempts) { await this.refreshTokenService.deleteRefreshTokenByUserId(userRefreshToken.userId); throw new _runtimeexceptions.AuthenticationError("Refresh token attempts exceeded, login required", _authorizationconstants.AUTH_ERROR_REASON.InvalidOrExpiredRefreshToken); } } await this.refreshTokenService.updateRefreshTokenAttempts(refreshToken, attemptsUsed + 1); } async signJwtToken(userId) { const user = await this.userService.getUser(userId); if (!user) { throw new _runtimeexceptions.AuthenticationError("User not found", _authorizationconstants.AUTH_ERROR_REASON.InvalidOrExpiredRefreshToken); } if (user.needsPasswordChange) { throw new _runtimeexceptions.AuthenticationError("Password change required", _authorizationconstants.AUTH_ERROR_REASON.PasswordChangeRequired); } if (!user.isVerified) { throw new _runtimeexceptions.AuthenticationError("User is not verified yet", _authorizationconstants.AUTH_ERROR_REASON.AccountNotVerified); } return this.jwtService.signJwtToken(userId, user.username); } } //# sourceMappingURL=auth.service.js.map