"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.saveToken = exports.revokeToken = exports.getUser = exports.getRefreshToken = exports.getClient = exports.getAccessToken = void 0;
const tslib_1 = require("tslib");
const oauth2_server_1 = require("@node-oauth/oauth2-server");
const plugin_manager_1 = require("../plugins/plugin-manager");
const core_utils_1 = require("../../../shared/core-utils");
const logger_1 = require("../../helpers/logger");
const config_1 = require("../../initializers/config");
const oauth_client_1 = require("../../models/oauth/oauth-client");
const oauth_token_1 = require("../../models/oauth/oauth-token");
const user_1 = require("../../models/user/user");
const local_actor_1 = require("../local-actor");
const user_2 = require("../user");
const tokens_cache_1 = require("./tokens-cache");
function getAccessToken(bearerToken) {
    return tslib_1.__awaiter(this, void 0, void 0, function* () {
        logger_1.logger.debug('Getting access token (bearerToken: ' + bearerToken + ').');
        if (!bearerToken)
            return undefined;
        let tokenModel;
        if (tokens_cache_1.TokensCache.Instance.hasToken(bearerToken)) {
            tokenModel = tokens_cache_1.TokensCache.Instance.getByToken(bearerToken);
        }
        else {
            tokenModel = yield oauth_token_1.OAuthTokenModel.getByTokenAndPopulateUser(bearerToken);
            if (tokenModel)
                tokens_cache_1.TokensCache.Instance.setToken(tokenModel);
        }
        if (!tokenModel)
            return undefined;
        if (tokenModel.User.pluginAuth) {
            const valid = yield plugin_manager_1.PluginManager.Instance.isTokenValid(tokenModel, 'access');
            if (valid !== true)
                return undefined;
        }
        return tokenModel;
    });
}
exports.getAccessToken = getAccessToken;
function getClient(clientId, clientSecret) {
    logger_1.logger.debug('Getting Client (clientId: ' + clientId + ', clientSecret: ' + clientSecret + ').');
    return oauth_client_1.OAuthClientModel.getByIdAndSecret(clientId, clientSecret);
}
exports.getClient = getClient;
function getRefreshToken(refreshToken) {
    return tslib_1.__awaiter(this, void 0, void 0, function* () {
        logger_1.logger.debug('Getting RefreshToken (refreshToken: ' + refreshToken + ').');
        const tokenInfo = yield oauth_token_1.OAuthTokenModel.getByRefreshTokenAndPopulateClient(refreshToken);
        if (!tokenInfo)
            return undefined;
        const tokenModel = tokenInfo.token;
        if (tokenModel.User.pluginAuth) {
            const valid = yield plugin_manager_1.PluginManager.Instance.isTokenValid(tokenModel, 'refresh');
            if (valid !== true)
                return undefined;
        }
        return tokenInfo;
    });
}
exports.getRefreshToken = getRefreshToken;
function getUser(usernameOrEmail, password, bypassLogin) {
    return tslib_1.__awaiter(this, void 0, void 0, function* () {
        if (bypassLogin && bypassLogin.bypass === true) {
            logger_1.logger.info('Bypassing oauth login by plugin %s.', bypassLogin.pluginName);
            let user = yield user_1.UserModel.loadByEmail(bypassLogin.user.email);
            if (!user)
                user = yield createUserFromExternal(bypassLogin.pluginName, bypassLogin.user);
            if (!user)
                throw new oauth2_server_1.AccessDeniedError('Cannot create such user: an actor with that name already exists.');
            if (user.pluginAuth !== null) {
                if (user.pluginAuth !== bypassLogin.pluginName) {
                    logger_1.logger.info('Cannot bypass oauth login by plugin %s because %s has another plugin auth method (%s).', bypassLogin.pluginName, bypassLogin.user.email, user.pluginAuth);
                    return null;
                }
                checkUserValidityOrThrow(user);
                return user;
            }
        }
        logger_1.logger.debug('Getting User (username/email: ' + usernameOrEmail + ', password: ******).');
        const user = yield user_1.UserModel.loadByUsernameOrEmail(usernameOrEmail);
        if (!user || user.pluginAuth !== null || !password)
            return null;
        const passwordMatch = yield user.isPasswordMatch(password);
        if (passwordMatch !== true)
            return null;
        checkUserValidityOrThrow(user);
        if (config_1.CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION && user.emailVerified === false) {
            throw new oauth2_server_1.AccessDeniedError('User email is not verified.');
        }
        return user;
    });
}
exports.getUser = getUser;
function revokeToken(tokenInfo, options = {}) {
    return tslib_1.__awaiter(this, void 0, void 0, function* () {
        const { req, explicitLogout } = options;
        const token = yield oauth_token_1.OAuthTokenModel.getByRefreshTokenAndPopulateUser(tokenInfo.refreshToken);
        if (token) {
            let redirectUrl;
            if (explicitLogout === true && token.User.pluginAuth && token.authName) {
                redirectUrl = yield plugin_manager_1.PluginManager.Instance.onLogout(token.User.pluginAuth, token.authName, token.User, req);
            }
            tokens_cache_1.TokensCache.Instance.clearCacheByToken(token.accessToken);
            token.destroy()
                .catch(err => logger_1.logger.error('Cannot destroy token when revoking token.', { err }));
            return { success: true, redirectUrl };
        }
        return { success: false };
    });
}
exports.revokeToken = revokeToken;
function saveToken(token, client, user, options = {}) {
    return tslib_1.__awaiter(this, void 0, void 0, function* () {
        const { refreshTokenAuthName, bypassLogin } = options;
        let authName = null;
        if ((bypassLogin === null || bypassLogin === void 0 ? void 0 : bypassLogin.bypass) === true) {
            authName = bypassLogin.authName;
        }
        else if (refreshTokenAuthName) {
            authName = refreshTokenAuthName;
        }
        logger_1.logger.debug('Saving token ' + token.accessToken + ' for client ' + client.id + ' and user ' + user.id + '.');
        const tokenToCreate = {
            accessToken: token.accessToken,
            accessTokenExpiresAt: token.accessTokenExpiresAt,
            refreshToken: token.refreshToken,
            refreshTokenExpiresAt: token.refreshTokenExpiresAt,
            authName,
            oAuthClientId: client.id,
            userId: user.id
        };
        const tokenCreated = yield oauth_token_1.OAuthTokenModel.create(tokenToCreate);
        user.lastLoginDate = new Date();
        yield user.save();
        return {
            accessToken: tokenCreated.accessToken,
            accessTokenExpiresAt: tokenCreated.accessTokenExpiresAt,
            refreshToken: tokenCreated.refreshToken,
            refreshTokenExpiresAt: tokenCreated.refreshTokenExpiresAt,
            client,
            user,
            accessTokenExpiresIn: buildExpiresIn(tokenCreated.accessTokenExpiresAt),
            refreshTokenExpiresIn: buildExpiresIn(tokenCreated.refreshTokenExpiresAt)
        };
    });
}
exports.saveToken = saveToken;
function createUserFromExternal(pluginAuth, options) {
    return tslib_1.__awaiter(this, void 0, void 0, function* () {
        const username = yield (0, local_actor_1.findAvailableLocalActorName)(options.username);
        const userToCreate = (0, user_2.buildUser)(Object.assign(Object.assign({}, (0, core_utils_1.pick)(options, ['email', 'role'])), { username, emailVerified: null, password: null, pluginAuth }));
        const { user } = yield (0, user_2.createUserAccountAndChannelAndPlaylist)({
            userToCreate,
            userDisplayName: options.displayName
        });
        return user;
    });
}
function checkUserValidityOrThrow(user) {
    if (user.blocked)
        throw new oauth2_server_1.AccessDeniedError('User is blocked.');
}
function buildExpiresIn(expiresAt) {
    return Math.floor((expiresAt.getTime() - new Date().getTime()) / 1000);
}
//# sourceMappingURL=oauth-model.js.map