MSC4380: Invite blocking (#31268)

* Initial implementation of MSC4380

* fix lint

* Update InviteRulesAccountSetting-test

* add some docs

* `block_all` -> `default_action`

* Add a unit test for BlockInvitesConfigController
This commit is contained in:
Richard van der Hoff
2025-11-27 18:42:58 +00:00
committed by GitHub
parent 5869c519ed
commit 1c684489da
7 changed files with 294 additions and 50 deletions

View File

@@ -15,32 +15,57 @@ import SettingsStore from "../../../../../settings/SettingsStore";
import { SettingLevel } from "../../../../../settings/SettingLevel";
import LabelledToggleSwitch from "../../../elements/LabelledToggleSwitch";
/**
* A settings component which allows the user to enable/disable invite blocking.
*
* Uses whichever of MSC4155 and MSC4380 is available on the server; if neither is available, the toggle is disabled. If
* both are available, the toggle will use MSC4380 to block invites.
*/
export const InviteRulesAccountSetting: FC = () => {
const rules = useSettingValue("inviteRules");
const settingsDisabled = SettingsStore.disabledMessage("inviteRules");
const msc4155Rules = useSettingValue("inviteRules");
const msc4380BlockInvites = useSettingValue("blockInvites");
const msc4155Disabled = SettingsStore.disabledMessage("inviteRules");
const msc4380Disabled = SettingsStore.disabledMessage("blockInvites");
const [busy, setBusy] = useState(false);
const onChange = useCallback(async (checked: boolean) => {
try {
setBusy(true);
await SettingsStore.setValue("inviteRules", null, SettingLevel.ACCOUNT, {
allBlocked: !checked,
});
} catch (ex) {
logger.error(`Unable to set invite rules`, ex);
} finally {
setBusy(false);
}
}, []);
const onChange = useCallback(
async (allowInvites: boolean) => {
try {
setBusy(true);
if (allowInvites) {
// When allowing invites, clear the block setting on both bits of account data.
await SettingsStore.setValue("blockInvites", null, SettingLevel.ACCOUNT, false);
await SettingsStore.setValue("inviteRules", null, SettingLevel.ACCOUNT, { allBlocked: false });
} else {
// When blocking invites, prefer MSC4380 over MSC4155.
if (!msc4380Disabled) {
await SettingsStore.setValue("blockInvites", null, SettingLevel.ACCOUNT, true);
} else if (!msc4155Disabled) {
await SettingsStore.setValue("inviteRules", null, SettingLevel.ACCOUNT, { allBlocked: true });
}
}
} catch (ex) {
logger.error(`Unable to set invite rules`, ex);
} finally {
setBusy(false);
}
},
[msc4155Disabled, msc4380Disabled, setBusy],
);
const disabledMessage = msc4155Disabled && msc4380Disabled;
const invitesBlocked = (!msc4155Disabled && msc4155Rules.allBlocked) || (!msc4380Disabled && msc4380BlockInvites);
return (
<Root className="mx_MediaPreviewAccountSetting_Form">
<LabelledToggleSwitch
className="mx_MediaPreviewAccountSetting_ToggleSwitch"
label={_t("settings|invite_controls|default_label")}
value={!rules.allBlocked}
value={!invitesBlocked}
onChange={onChange}
tooltip={settingsDisabled}
disabled={!!settingsDisabled || busy}
tooltip={disabledMessage}
disabled={!!disabledMessage || busy}
/>
</Root>
);