"use strict";
// Copyright 2022 - 2024 Gnuxie <Gnuxie@protonmail.com>
// Copyright 2019 - 2021 The Matrix.org Foundation C.I.C.
//
// SPDX-License-Identifier: Apache-2.0
//
// SPDX-FileAttributionText: <text>
// This modified file incorporates work from mjolnir
// https://github.com/matrix-org/mjolnir
// </text>
Object.defineProperty(exports, "__esModule", { value: true });
exports.DraupnirListProtectionsCommand = exports.DraupnirProtectionsCapabilityResetCommand = exports.DraupnirProtectionsConfigResetCommand = exports.DraupnirProtectionsConfigRemoveCommand = exports.DraupnirProtectionsConfigAddCommand = exports.DraupnirProtectionsConfigSetCommand = exports.DraupnirProtectionsDisableCommand = exports.DraupnirProtectionsEnableCommand = void 0;
const matrix_protection_suite_1 = require("matrix-protection-suite");
const interface_manager_1 = require("@the-draupnir-project/interface-manager");
const typescript_result_1 = require("@gnuxie/typescript-result");
const DraupnirCommandPrerequisites_1 = require("./DraupnirCommandPrerequisites");
const PersistentConfigRenderer_1 = require("../safemode/PersistentConfigRenderer");
const ConfigHooks_1 = require("../protections/ConfigHooks");
exports.DraupnirProtectionsEnableCommand = (0, interface_manager_1.describeCommand)({
    summary: "Enable a named protection.",
    parameters: (0, interface_manager_1.tuple)({
        name: "protection name",
        acceptor: interface_manager_1.StringPresentationType,
    }),
    async executor(draupnir, _info, _keywords, _rest, protectionName) {
        const protectionDescription = (0, matrix_protection_suite_1.findProtection)(protectionName);
        if (protectionDescription === undefined) {
            return matrix_protection_suite_1.ActionError.Result(`Couldn't find a protection named ${protectionName}`);
        }
        return await draupnir.protectedRoomsSet.protections.addProtection(protectionDescription, draupnir.protectedRoomsSet, draupnir);
    },
});
DraupnirCommandPrerequisites_1.DraupnirInterfaceAdaptor.describeRenderer(exports.DraupnirProtectionsEnableCommand, {
    JSXRenderer(result) {
        if ((0, typescript_result_1.isOk)(result)) {
            return (0, matrix_protection_suite_1.Ok)(undefined);
        }
        if (result.error instanceof matrix_protection_suite_1.ConfigParseError) {
            return (0, matrix_protection_suite_1.Ok)(interface_manager_1.DeadDocumentJSX.JSXFactory("root", null,
                interface_manager_1.DeadDocumentJSX.JSXFactory("p", null,
                    "Use the ",
                    interface_manager_1.DeadDocumentJSX.JSXFactory("code", null, "!draupnir protections show"),
                    " and",
                    " ",
                    interface_manager_1.DeadDocumentJSX.JSXFactory("code", null, "!draupnir protections config remove"),
                    " commands to modify invalid values. Alternatively reset the protection settings to default with ",
                    interface_manager_1.DeadDocumentJSX.JSXFactory("code", null, "!draupnir protections config reset"),
                    "."),
                result.error.mostRelevantElaboration,
                interface_manager_1.DeadDocumentJSX.JSXFactory("br", null),
                PersistentConfigRenderer_1.StandardPersistentConfigRenderer.renderConfigStatus({
                    description: result.error.configDescription,
                    data: result.error.config,
                    error: result.error,
                })));
        }
        // let the default renderer handle the error.
        return (0, matrix_protection_suite_1.Ok)(undefined);
    },
});
exports.DraupnirProtectionsDisableCommand = (0, interface_manager_1.describeCommand)({
    summary: "Disable a named protection.",
    parameters: (0, interface_manager_1.tuple)({
        name: "protection name",
        acceptor: interface_manager_1.StringPresentationType,
    }),
    async executor(draupnir, _info, _keywords, _rest, protectionName) {
        const protectionDescription = (0, matrix_protection_suite_1.findProtection)(protectionName);
        if (protectionDescription === undefined) {
            return matrix_protection_suite_1.ActionError.Result(`Couldn't find a protection named ${protectionName}`);
        }
        if (!draupnir.protectedRoomsSet.protections.isEnabledProtection(protectionDescription)) {
            return matrix_protection_suite_1.ActionError.Result(`The protection named ${protectionDescription.name} is currently disabled`);
        }
        return await draupnir.protectedRoomsSet.protections.removeProtection(protectionDescription);
    },
});
DraupnirCommandPrerequisites_1.DraupnirInterfaceAdaptor.describeRenderer(exports.DraupnirProtectionsDisableCommand, {
    isAlwaysSupposedToUseDefaultRenderer: true,
});
const CommonProtectionSettingParameters = (0, interface_manager_1.tuple)({
    name: "protection name",
    acceptor: interface_manager_1.StringPresentationType,
    description: "The name of the protection to be modified.",
}, {
    name: "setting name",
    acceptor: interface_manager_1.StringPresentationType,
    description: "The name of the setting within the protection config to modify.",
});
exports.DraupnirProtectionsConfigSetCommand = (0, interface_manager_1.describeCommand)({
    summary: "Set a new value for the protection setting, if the setting is a collection then this will write over the entire collection.",
    parameters: (0, interface_manager_1.tuple)(...CommonProtectionSettingParameters, {
        name: "new value",
        acceptor: interface_manager_1.TopPresentationSchema,
        description: "The new value to give the protection setting",
    }),
    async executor({ protectionsManager, protectionContext, protectedRoomsSet, }, _info, _keywords, _rest, protectionName, settingName, value) {
        const detailsResult = await findSettingDetailsForCommand(protectionsManager, protectionName, settingName);
        if ((0, matrix_protection_suite_1.isError)(detailsResult)) {
            return detailsResult;
        }
        const details = detailsResult.ok;
        const newSettings = details.description
            .toMirror()
            .setValue(details.previousSettings, settingName, value);
        if ((0, matrix_protection_suite_1.isError)(newSettings)) {
            return newSettings;
        }
        return await changeSettingsForCommands(protectionContext, protectedRoomsSet, protectionsManager, details, settingName, newSettings.ok);
    },
});
exports.DraupnirProtectionsConfigAddCommand = (0, interface_manager_1.describeCommand)({
    summary: "Add an item to a collection protection setting.",
    parameters: (0, interface_manager_1.tuple)(...CommonProtectionSettingParameters, {
        name: "item",
        acceptor: interface_manager_1.TopPresentationSchema,
        description: "An item to add to the collection setting.",
    }),
    async executor({ protectionsManager, protectionContext, protectedRoomsSet, }, _info, _keywords, _rest, protectionName, settingName, value) {
        const detailsResult = await findSettingDetailsForCommand(protectionsManager, protectionName, settingName);
        if ((0, matrix_protection_suite_1.isError)(detailsResult)) {
            return detailsResult;
        }
        const details = detailsResult.ok;
        const propertyDescription = details.description.getPropertyDescription(settingName);
        if (!propertyDescription.isArray) {
            return matrix_protection_suite_1.ActionError.Result(`${protectionName}'s setting ${settingName} is not a collection protection setting, and cannot be used with the add or remove commands.`);
        }
        const newSettings = details.description
            .toMirror()
            // We technically need to print the argument "readbly" but i don't think
            // we have a way to do that.
            // at least without getting the argument from the argument stream in
            // interface-manager so that we still have its presentation type.
            .addSerializedItem(details.previousSettings, settingName, String(value));
        if ((0, matrix_protection_suite_1.isError)(newSettings)) {
            return newSettings;
        }
        return await changeSettingsForCommands(protectionContext, protectedRoomsSet, protectionsManager, details, settingName, newSettings.ok);
    },
});
exports.DraupnirProtectionsConfigRemoveCommand = (0, interface_manager_1.describeCommand)({
    summary: "Remove an item from a collection protection setting.",
    parameters: (0, interface_manager_1.tuple)(...CommonProtectionSettingParameters, {
        name: "item",
        acceptor: interface_manager_1.TopPresentationSchema,
        description: "An item to add to the collection setting.",
    }),
    async executor({ protectionsManager, protectionContext, protectedRoomsSet, }, _info, _keywords, _rest, protectionName, settingName, value) {
        const detailsResult = await findSettingDetailsForCommand(protectionsManager, protectionName, settingName);
        if ((0, matrix_protection_suite_1.isError)(detailsResult)) {
            return detailsResult;
        }
        const details = detailsResult.ok;
        const settingDescription = details.description;
        const propertyDescription = settingDescription.getPropertyDescription(settingName);
        if (!propertyDescription.isArray) {
            return matrix_protection_suite_1.ActionError.Result(`${protectionName}'s setting ${settingName} is not a collection protection setting, and cannot be used with the add or remove commands.`);
        }
        const newSettings = settingDescription
            .toMirror()
            .filterItems(details.previousSettings, settingName, (item) => item !== value);
        return await changeSettingsForCommands(protectionContext, protectedRoomsSet, protectionsManager, details, 
        // Yeha I know this sucks but either fix it or fuck off, it'll be fine.
        settingName, newSettings.ok);
    },
});
function renderSettingChangeSummary(summary) {
    const renderProperty = (value) => {
        if (Array.isArray(value)) {
            return value.join(", ");
        }
        return String(value);
    };
    return (interface_manager_1.DeadDocumentJSX.JSXFactory("fragment", null,
        "Setting ",
        summary.propertyKey,
        " changed from",
        " ",
        interface_manager_1.DeadDocumentJSX.JSXFactory("code", null, renderProperty(summary.oldValue)),
        " to",
        " ",
        interface_manager_1.DeadDocumentJSX.JSXFactory("code", null, renderProperty(summary.newValue))));
}
for (const command of [
    exports.DraupnirProtectionsConfigAddCommand,
    exports.DraupnirProtectionsConfigSetCommand,
    exports.DraupnirProtectionsConfigRemoveCommand,
]) {
    DraupnirCommandPrerequisites_1.DraupnirInterfaceAdaptor.describeRenderer(command, {
        JSXRenderer(result) {
            if ((0, matrix_protection_suite_1.isError)(result)) {
                return (0, matrix_protection_suite_1.Ok)(undefined);
            }
            return (0, matrix_protection_suite_1.Ok)(interface_manager_1.DeadDocumentJSX.JSXFactory("root", null, renderSettingChangeSummary(result.ok)));
        },
    });
    DraupnirCommandPrerequisites_1.DraupnirContextToCommandContextTranslator.registerTranslation(command, function (draupnir) {
        return {
            protectionContext: draupnir,
            protectionsManager: draupnir.protectedRoomsSet.protections,
            protectedRoomsSet: draupnir.protectedRoomsSet,
        };
    });
}
function findProtectionDescriptionForCommand(protectionName) {
    const protectionDescription = (0, matrix_protection_suite_1.findProtection)(protectionName);
    if (protectionDescription === undefined) {
        return matrix_protection_suite_1.ActionError.Result(`Couldn't find a protection named ${protectionName}`);
    }
    return (0, matrix_protection_suite_1.Ok)(protectionDescription);
}
async function findSettingDetailsForCommand(protectionsManager, protectionName, settingName) {
    const protectionDescription = findProtectionDescriptionForCommand(protectionName);
    if ((0, matrix_protection_suite_1.isError)(protectionDescription)) {
        return protectionDescription;
    }
    const previousSettings = await protectionsManager.getProtectionSettings(protectionDescription.ok);
    if ((0, matrix_protection_suite_1.isError)(previousSettings)) {
        return previousSettings;
    }
    return (0, matrix_protection_suite_1.Ok)({
        protectionDescription: protectionDescription.ok,
        propertyKey: settingName,
        description: protectionDescription.ok.protectionSettings,
        previousSettings: previousSettings.ok,
    });
}
// So I'm thinking instead that we're going to move to the PersistentConfigData
// thingy for protection settings. Wouldn't it make sense to make a plan for that,
// consider how recovery would work, and how to unit test evertyhing, then
// do that.
async function changeSettingsForCommands(context, protectedRoomsSet, protectionsManager, details, settingName, newSettings) {
    const changeResult = await protectedRoomsSet.protections.changeProtectionSettings(details.protectionDescription, protectedRoomsSet, context, newSettings);
    if ((0, matrix_protection_suite_1.isError)(changeResult)) {
        return changeResult;
    }
    return (0, matrix_protection_suite_1.Ok)({
        description: details.description,
        oldValue: details.previousSettings[settingName],
        newValue: newSettings[settingName],
        propertyKey: settingName,
    });
}
function sortProtectionsListByEnabledAndAlphanumerical(summaries) {
    return summaries.sort((a, b) => {
        if (a.isEnabled && !b.isEnabled) {
            return -1;
        }
        if (!a.isEnabled && b.isEnabled) {
            return 1;
        }
        return a.description.name.localeCompare(b.description.name);
    });
}
exports.DraupnirProtectionsConfigResetCommand = (0, interface_manager_1.describeCommand)({
    summary: "Reset the protection settings for a named protection",
    parameters: (0, interface_manager_1.tuple)({
        name: "protection name",
        acceptor: interface_manager_1.StringPresentationType,
        description: "The name of the protection to be modified.",
    }),
    async executor(draupnir, _info, _keywords, _rest, protectionName) {
        const protectionDescription = (0, matrix_protection_suite_1.findProtection)(protectionName);
        if (protectionDescription === undefined) {
            return matrix_protection_suite_1.ActionError.Result(`Couldn't find a protection named ${protectionName}`);
        }
        const newSettings = protectionDescription.protectionSettings.getDefaultConfig();
        return await draupnir.protectedRoomsSet.protections.changeProtectionSettings(protectionDescription, draupnir.protectedRoomsSet, draupnir, newSettings);
    },
});
DraupnirCommandPrerequisites_1.DraupnirInterfaceAdaptor.describeRenderer(exports.DraupnirProtectionsConfigResetCommand, {
    isAlwaysSupposedToUseDefaultRenderer: true,
});
exports.DraupnirProtectionsCapabilityResetCommand = (0, interface_manager_1.describeCommand)({
    summary: "Use the default set of capabilies for the named protection",
    parameters: (0, interface_manager_1.tuple)({
        name: "protection name",
        acceptor: interface_manager_1.StringPresentationType,
        description: "The name of the protection to be modified.",
    }),
    async executor(draupnir, _info, _keywords, _rest, protectionName) {
        const protectionDescription = (0, matrix_protection_suite_1.findProtection)(protectionName);
        if (protectionDescription === undefined) {
            return matrix_protection_suite_1.ActionError.Result(`Couldn't find a protection named ${protectionName}`);
        }
        return await draupnir.protectedRoomsSet.protections.changeCapabilityProviderSet(protectionDescription, draupnir.protectedRoomsSet, draupnir, protectionDescription.defaultCapabilities);
    },
});
DraupnirCommandPrerequisites_1.DraupnirInterfaceAdaptor.describeRenderer(exports.DraupnirProtectionsCapabilityResetCommand, {
    isAlwaysSupposedToUseDefaultRenderer: true,
});
exports.DraupnirListProtectionsCommand = (0, interface_manager_1.describeCommand)({
    summary: "List all available protections.",
    parameters: [],
    async executor(draupnir) {
        const enabledProtections = draupnir.protectedRoomsSet.protections.allProtections;
        const summaries = [];
        for (const protectionDescription of (0, matrix_protection_suite_1.getAllProtections)()) {
            if (draupnir.synapseHTTPAntispam === undefined &&
                ConfigHooks_1.ServerAdminProtections.includes(protectionDescription)) {
                continue; // these protections will error if enabled
            }
            const enabledProtection = enabledProtections.find((p) => p.description.name === protectionDescription.name);
            if (enabledProtection !== undefined) {
                summaries.push({
                    description: protectionDescription,
                    protection: enabledProtection,
                    isEnabled: true,
                });
            }
            else {
                summaries.push({
                    description: protectionDescription,
                    isEnabled: false,
                });
            }
        }
        return (0, matrix_protection_suite_1.Ok)(sortProtectionsListByEnabledAndAlphanumerical(summaries));
    },
});
DraupnirCommandPrerequisites_1.DraupnirInterfaceAdaptor.describeRenderer(exports.DraupnirListProtectionsCommand, {
    JSXRenderer(result) {
        if ((0, matrix_protection_suite_1.isError)(result)) {
            return (0, matrix_protection_suite_1.Ok)(undefined);
        }
        return (0, matrix_protection_suite_1.Ok)(interface_manager_1.DeadDocumentJSX.JSXFactory("root", null, renderProtectionsSummary(result.ok)));
    },
});
function renderProtectionsSummary(protectionsSummary) {
    return (interface_manager_1.DeadDocumentJSX.JSXFactory("fragment", null,
        "To show details about a specific protection, use",
        " ",
        interface_manager_1.DeadDocumentJSX.JSXFactory("code", null,
            "!draupnir protections show ",
            "<",
            "protection name",
            ">"),
        " ",
        "command.",
        interface_manager_1.DeadDocumentJSX.JSXFactory("br", null),
        "Available protections:",
        interface_manager_1.DeadDocumentJSX.JSXFactory("ul", null, protectionsSummary.map((summary) => (interface_manager_1.DeadDocumentJSX.JSXFactory("li", null,
            summary.isEnabled ? "🟢 (enabled)" : "🔴 (disabled)",
            interface_manager_1.DeadDocumentJSX.JSXFactory("code", null, summary.description.name),
            " -",
            " ",
            summary.description.description))))));
}
//# sourceMappingURL=ProtectionsCommands.js.map