@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
JavaScript
"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