"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const types_1 = require("@deepstream/types");
const utils_1 = require("../../../utils/utils");
/**
 * This authentication handler reads a list of users and their associated password (either
 * hashed or in cleartext ) from a json file. This can be useful to authenticate smaller amounts
 * of clients with static credentials, e.g. backend provider that write to publicly readable records
 */
class FileBasedAuthentication extends types_1.DeepstreamPlugin {
    /**
    * Creates the class, reads and validates the users.json file
    */
    constructor(settings, services) {
        super();
        this.settings = settings;
        this.services = services;
        this.description = 'File Authentication';
        this.hashSettings = {
            iterations: this.settings.iterations,
            keyLength: this.settings.keyLength,
            algorithm: this.settings.hash
        };
        this.validateSettings(settings);
        this.base64KeyLength = 4 * Math.ceil(this.settings.keyLength / 3);
    }
    async whenReady() {
    }
    /**
    * Main interface. Authenticates incoming connections
    */
    async isValidUser(connectionData, authData) {
        const missingUsername = typeof authData.username !== 'string';
        const missingPassword = typeof authData.password !== 'string';
        if (missingPassword || missingUsername) {
            if (this.settings.reportInvalidParameters) {
                return {
                    isValid: false,
                    clientData: { error: 'missing authentication parameter: username or/and password' }
                };
            }
            else {
                return null;
            }
        }
        const userData = this.settings.users[authData.username];
        if (!userData) {
            return null;
        }
        const actualPassword = this.settings.hash ? userData.password.substr(0, this.base64KeyLength) : userData.password;
        let expectedPassword = authData.password;
        if (typeof this.settings.hash === 'string') {
            ({ hash: expectedPassword } = await utils_1.createHash(authData.password, this.hashSettings, userData.password.substr(this.base64KeyLength)));
            expectedPassword = expectedPassword.toString('base64');
        }
        if (actualPassword === expectedPassword) {
            return {
                isValid: true,
                id: authData.username,
                serverData: typeof userData.serverData === 'undefined' ? null : userData.serverData,
                clientData: typeof userData.clientData === 'undefined' ? null : userData.clientData,
            };
        }
        return { isValid: false };
    }
    /**
    * Called initially to validate the user provided settings
    */
    validateSettings(settings) {
        try {
            if (settings.hash) {
                utils_1.validateMap(settings, true, {
                    hash: 'string',
                    iterations: 'number',
                    keyLength: 'number',
                });
                utils_1.validateHashingAlgorithm(settings.hash);
            }
        }
        catch (e) {
            this.services.logger.fatal(types_1.EVENT.PLUGIN_INITIALIZATION_ERROR, 'Validating settings failed for file auth', e.message);
        }
        if (Object.keys(settings.users).length === 0) {
            this.services.logger.fatal(types_1.EVENT.PLUGIN_INITIALIZATION_ERROR, 'no users present in user file');
            return;
        }
        for (const username in this.settings.users) {
            if (typeof settings.users[username].password !== 'string') {
                this.services.logger.fatal(types_1.EVENT.PLUGIN_INITIALIZATION_ERROR, `missing password for ${username}`);
            }
        }
    }
}
exports.FileBasedAuthentication = FileBasedAuthentication;
//# sourceMappingURL=file-based-authentication.js.map