"use strict";
// This file is part of HFS - Copyright 2021-2023, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const apiMiddleware_1 = require("./apiMiddleware");
const perm_1 = require("./perm");
const lodash_1 = __importDefault(require("lodash"));
const const_1 = require("./const");
const auth_1 = require("./auth");
const misc_1 = require("./misc");
const api_vfs_1 = require("./api.vfs");
function prepareAccount(ac) {
    return ac && {
        ...lodash_1.default.omit(ac, ['password', 'hashed_password', 'srp']),
        username: ac.username, // omit won't copy it because it's a hidden prop
        hasPassword: (0, perm_1.accountHasPassword)(ac),
        isGroup: !(0, perm_1.accountHasLoginMethod)(ac),
        adminActualAccess: (0, perm_1.accountCanLoginAdmin)(ac),
        canLogin: (0, perm_1.accountHasLoginMethod)(ac) ? (0, perm_1.accountCanLogin)(ac) : undefined,
        canChangePassword: (0, perm_1.accountCanChangePassword)(ac),
        invalidated: auth_1.invalidateSessionBefore.get(ac.username),
        directMembers: Object.values(perm_1.accounts.get()).filter(a => a.belongs?.includes(ac.username)).map(x => x.username),
        members: (0, misc_1.with_)(Object.values(perm_1.accounts.get()), accounts => {
            const ret = [];
            let news = [ac.username];
            while (news.length) {
                news = accounts.filter(a => !ret.includes(a.username) && a.belongs?.some(x => news.includes(x))).map(x => x.username);
                ret.push(...news);
            }
            return lodash_1.default.uniq(ret).sort();
        })
    };
}
const ALLOWED_KEYS = ['admin', 'allow_net', 'auto_login_net', 'belongs', 'days_to_live', 'disable_password_change',
    'disabled', 'expire', 'ignore_limits', 'notes', 'password', 'redirect', 'require_password_change', 'username'];
exports.default = {
    get_usernames() {
        return { list: Object.keys(perm_1.accounts.get()) };
    },
    get_account({ username }, ctx) {
        (0, misc_1.apiAssertTypes)({ string: { username } });
        return prepareAccount((0, perm_1.getAccount)(username || (0, auth_1.getCurrentUsername)(ctx)))
            || new apiMiddleware_1.ApiError(const_1.HTTP_NOT_FOUND);
    },
    get_accounts() {
        return { list: (0, misc_1.onlyTruthy)(Object.values(perm_1.accounts.get()).map(prepareAccount)) };
    },
    get_admins() {
        return { list: lodash_1.default.filter(perm_1.accounts.get(), perm_1.accountCanLoginAdmin).map(ac => ac.username) };
    },
    async set_account({ username, changes }, ctx) {
        (0, misc_1.apiAssertTypes)({ string: { username } });
        const acc = (0, perm_1.getAccount)(username);
        if (!acc)
            return new apiMiddleware_1.ApiError(const_1.HTTP_BAD_REQUEST);
        await (0, perm_1.updateAccount)(acc, (0, api_vfs_1.pickProps)(changes, ALLOWED_KEYS));
        if (changes.username && ctx.session?.username === (0, perm_1.normalizeUsername)(username)) // update session if necessary
            ctx.session.username = (0, perm_1.normalizeUsername)(changes.username);
        return lodash_1.default.pick(acc, 'username');
    },
    async add_account({ overwrite, username, ...rest }) {
        (0, misc_1.apiAssertTypes)({ string: { username } });
        const existing = (0, perm_1.getAccount)(username);
        rest = (0, api_vfs_1.pickProps)(rest, ALLOWED_KEYS);
        if (existing) {
            if (!overwrite)
                return new apiMiddleware_1.ApiError(const_1.HTTP_CONFLICT);
            await (0, perm_1.updateAccount)(existing, rest);
            return lodash_1.default.pick(existing, 'username');
        }
        const acc = await (0, perm_1.addAccount)(username, rest);
        return acc ? lodash_1.default.pick(acc, 'username') : new apiMiddleware_1.ApiError(const_1.HTTP_BAD_REQUEST); // return username because it is normalized
    },
    del_account({ username }) {
        (0, misc_1.apiAssertTypes)({ string_array: { username } });
        if (Array.isArray(username)) {
            const errors = lodash_1.default.pickBy((0, misc_1.objFromKeys)(username, u => (0, perm_1.delAccount)(u) ? undefined : const_1.HTTP_NOT_FOUND));
            return lodash_1.default.isEmpty(errors) ? {} : { errors };
        }
        return (0, perm_1.delAccount)(username) ? {} : new apiMiddleware_1.ApiError(const_1.HTTP_NOT_FOUND);
    },
    invalidate_sessions({ username }) {
        (0, misc_1.apiAssertTypes)({ string: { username } });
        auth_1.invalidateSessionBefore.set((0, perm_1.normalizeUsername)(username), Date.now());
        return {};
    },
};
