"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.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