Automatically adjust history visibility when making a room private (#30713)

* Refactor StyledRadioButton to provide proper labels.

* Automatically change history settings to members only if room is made private

* Add tests

* lint

* lint further

* Fix clickable buttons

* Revert functional component-ing

* text tweaks

* update snapshots

* Add unit test for history vis changes

* lint

* Update snapshots

* Fix flakes

* lint
This commit is contained in:
Will Hunt
2025-09-08 15:54:15 +01:00
committed by GitHub
parent 6d05bfc4c5
commit 6b510a535b
8 changed files with 239 additions and 25 deletions

View File

@@ -35,7 +35,6 @@ export interface JoinRuleSettingsProps {
closeSettingsFn(): void;
onError(error: unknown): void;
beforeChange?(joinRule: JoinRule): Promise<boolean>; // if returns false then aborts the change
aliasWarning?: ReactNode;
disabledOptions?: Set<JoinRule>;
hiddenOptions?: Set<JoinRule>;
recommendedOption?: JoinRule;
@@ -44,7 +43,6 @@ export interface JoinRuleSettingsProps {
const JoinRuleSettings: React.FC<JoinRuleSettingsProps> = ({
room,
promptUpgrade,
aliasWarning,
onError,
beforeChange,
closeSettingsFn,
@@ -209,12 +207,7 @@ const JoinRuleSettings: React.FC<JoinRuleSettingsProps> = ({
{
value: JoinRule.Public,
label: withRecommendLabel(_t("common|public"), JoinRule.Public),
description: (
<>
{_t("room_settings|security|join_rule_public_description")}
{aliasWarning}
</>
),
description: <>{_t("room_settings|security|join_rule_public_description")}</>,
},
];

View File

@@ -251,19 +251,28 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
private renderJoinRule(): JSX.Element {
const room = this.props.room;
let aliasWarning: JSX.Element | undefined;
if (room.getJoinRule() === JoinRule.Public && !this.state.hasAliases) {
aliasWarning = (
<div className="mx_SecurityRoomSettingsTab_warning">
<WarningIcon width={15} height={15} />
<span>{_t("room_settings|security|public_without_alias_warning")}</span>
</div>
);
}
const description = _t("room_settings|security|join_rule_description", {
roomName: room.name,
});
const isPublic = room.getJoinRule() === JoinRule.Public;
const description = (
<>
<p>
{_t("room_settings|security|join_rule_description", {
roomName: room.name,
})}
</p>
{isPublic && this.state.history === HistoryVisibility.WorldReadable && (
<div className="mx_SecurityRoomSettingsTab_warning">
<WarningIcon width={15} height={15} />
<span>{_t("room_settings|security|join_rule_world_readable_description")}</span>
</div>
)}
{isPublic && !this.state.hasAliases && (
<div className="mx_SecurityRoomSettingsTab_warning">
<WarningIcon width={15} height={15} />
<span>{_t("room_settings|security|public_without_alias_warning")}</span>
</div>
)}
</>
);
let advanced: JSX.Element | undefined;
if (room.getJoinRule() === JoinRule.Public) {
@@ -290,7 +299,6 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
onError={this.onJoinRuleChangeError}
closeSettingsFn={this.props.closeSettingsFn}
promptUpgrade={true}
aliasWarning={aliasWarning}
/>
{advanced}
</SettingsFieldset>
@@ -342,6 +350,57 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
if (!confirm) return false;
}
// If the room is going from public to private AND the room is join readable, we want to encourage the user
// to change the history visibility.
const currentlyPublic = this.props.room.getJoinRule() === JoinRule.Public;
if (this.state.history === HistoryVisibility.WorldReadable && currentlyPublic && joinRule !== JoinRule.Public) {
const client = this.context;
const canChangeHistory = this.props.room.currentState?.mayClientSendStateEvent(
EventType.RoomHistoryVisibility,
client,
);
// If we can't change the history visibility, then don't allow the join rule transition. This is a unlikely occurance
// and if this is the case, a room administator should step in.
if (!canChangeHistory) {
const dialog = Modal.createDialog(ErrorDialog, {
title: _t(
"room_settings|security|cannot_change_to_private_due_to_missing_history_visiblity_permissions|title",
),
description: (
<p>
{_t(
"room_settings|security|cannot_change_to_private_due_to_missing_history_visiblity_permissions|description",
)}
</p>
),
});
await dialog.finished;
return false;
}
// Adjust the history visibility first.
try {
await this.context.sendStateEvent(
this.props.room.roomId,
EventType.RoomHistoryVisibility,
{
history_visibility: HistoryVisibility.Shared,
},
"",
);
this.setState({ history: HistoryVisibility.Shared });
} catch (ex) {
logger.error("Failed to change history visibility", ex);
Modal.createDialog(ErrorDialog, {
title: _t("common|error"),
description: _t("error|update_history_visibility"),
});
// If we fail to update the history visibility
return false;
}
}
return true;
};

View File

@@ -1128,6 +1128,7 @@
"tls": "Can't connect to homeserver - please check your connectivity, ensure your <a>homeserver's SSL certificate</a> is trusted, and that a browser extension is not blocking requests.",
"unknown": "Unknown error",
"unknown_error_code": "unknown error code",
"update_history_visibility": "Failed to change history visibility",
"update_power_level": "Failed to change power level"
},
"error_app_open_in_another_tab": "Switch to the other tab to connect to %(brand)s. This tab can now be closed.",
@@ -2385,6 +2386,10 @@
"users_default": "Default role"
},
"security": {
"cannot_change_to_private_due_to_missing_history_visiblity_permissions": {
"description": "You do not have permissions to alter the history visibility of the room. This is dangerous as it could allow unjoined users to read messages.",
"title": "Cannot make room private"
},
"enable_encryption_confirm_description": "Once enabled, encryption for a room cannot be disabled. Messages sent in an encrypted room cannot be seen by the server, only by the participants of the room. Enabling encryption may prevent many bots and bridges from working correctly. <a>Learn more about encryption.</a>",
"enable_encryption_confirm_title": "Enable encryption?",
"enable_encryption_public_room_confirm_description_1": "<b>It's not recommended to add encryption to public rooms.</b> Anyone can find and join public rooms, so anyone can read messages in them. You'll get none of the benefits of encryption, and you won't be able to turn it off later. Encrypting messages in a public room will make receiving and sending messages slower.",
@@ -2402,7 +2407,7 @@
"history_visibility_joined": "Members only (since they joined)",
"history_visibility_legend": "Who can read history?",
"history_visibility_shared": "Members only (since the point in time of selecting this option)",
"history_visibility_warning": "Changes to who can read history will only apply to future messages in this room. The visibility of existing history will be unchanged.",
"history_visibility_warning": "The visibility of existing history will not be changed.",
"history_visibility_world_readable": "Anyone",
"join_rule_description": "Decide who can join %(roomName)s.",
"join_rule_invite": "Private (invite only)",
@@ -2445,6 +2450,7 @@
"other": "Updating spaces... (%(progress)s out of %(count)s)"
},
"join_rule_upgrade_upgrading_room": "Upgrading room",
"join_rule_world_readable_description": "Changing who can join the room will change the visibility of future messages too.",
"public_without_alias_warning": "To link to this room, please add an address.",
"publish_room": "Make this room visible in the public room directory.",
"publish_space": "Make this space visible in the public room directory.",