// SPDX-FileCopyrightText: 2023 XWiki CryptPad Team <contact@cryptpad.org> and contributors
//
// SPDX-License-Identifier: AGPL-3.0-or-later

const Block = require("../commands/block");
const MFA = require("../storage/mfa");
const Util = require("../common-util");
const Sessions = require("../storage/sessions");

const Commands = module.exports;

var isValidBlockId = Block.isValidBlockId;

// Read the MFA settings for the given public key
const checkMFA = (Env, publicKey, cb) => {
    // Success if we can't get the MFA settings
    MFA.read(Env, publicKey, function (err, content) {
        if (err) {
            if (err.code !== "ENOENT") {
                Env.Log.error('TOTP_VALIDATE_MFA_READ', {
                    error: err,
                    publicKey: publicKey,
                });
            }
            return void cb();
        }

        var parsed = Util.tryParse(content);
        if (!parsed) { return void cb(); }

        cb("NOT_ALLOWED");
    });
};

// Make sure the block is not protected by MFA but don't do anything else
const check = Commands.MFA_CHECK = function (Env, body, cb) {
    var { publicKey } = body;
    if (!isValidBlockId(publicKey)) { return void cb("INVALID_KEY"); }
    checkMFA(Env, publicKey, cb);
};
check.complete = function (Env, body, cb) { cb(); };

// Write a login block IFF
// 1. You can sign for the block's public key
// 2. the block is not protected by MFA
// Note: the internal WRITE_LOGIN_BLOCK will check is you're allowed to create this block
const writeBlock = Commands.WRITE_BLOCK = function (Env, body, cb) {
    const { publicKey, content } = body;

    // they must provide a valid block public key
    if (!isValidBlockId(publicKey)) { return void cb("INVALID_KEY"); }
    if (publicKey !== content.publicKey) { return void cb("INVALID_KEY"); }

    // check MFA
    checkMFA(Env, publicKey, cb);
};

writeBlock.complete = function (Env, body, cb) {
    const { publicKey, content, session } = body;
    Block.writeLoginBlock(Env, content, (err) => {
        if (err) { return void cb(err); }

        if (!session) { return void cb(); }

        const proof = Util.tryParse(content.registrationProof);
        const oldKey = proof && proof[0];
        Sessions.update(Env, publicKey, oldKey, session, "", cb);
    });
};

// Remove a login block IFF
// 1. You can sign for the block's public key
// 2. the block is not protected by MFA
const removeBlock = Commands.REMOVE_BLOCK = function (Env, body, cb) {
    const { publicKey } = body;

    // they must provide a valid block public key
    if (!isValidBlockId(publicKey)) { return void cb("INVALID_KEY"); }

    // check MFA
    checkMFA(Env, publicKey, cb);
};

removeBlock.complete = function (Env, body, cb) {
    const { publicKey, edPublic, reason } = body;
    Block.removeLoginBlock(Env, publicKey, reason, edPublic, cb);
};

// Get an upload cookie
// Get a cookie allowing you to upload to the blobstage of your user
const uploadCookie = Commands.UPLOAD_COOKIE = function (Env, body, cb) {
    const { publicKey } = body;

    // they must provide a valid public key
    if (publicKey && typeof(publicKey) === "string"
        && publicKey.length === 44) {
        return cb();
    }

    cb("INVALID_KEY");
};

uploadCookie.complete = function (Env, body, cb) {
    const { publicKey } = body;

    const safeKey = Util.escapeKeyCharacters(publicKey);
    Env.blobStore.uploadCookie(safeKey, (err, cookie) => {
        if (err) { return void cb(err); }
        cb(void 0, {cookie});
    });
};


