Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,7 @@ test.describe("Roles & Permissions room settings tab", () => {

await settingsGroupAccess.getByText("Private (invite only)").click();
// Element should have automatically set the room to "sharing" history visibility
await expect(
settingsGroupHistory.getByText("Members only (since the point in time of selecting this option)"),
).toBeChecked();
await expect(settingsGroupHistory.getByText("Members (full history)")).toBeChecked();
},
);

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -419,36 +419,60 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
const state = this.props.room.currentState;
const canChangeHistory = state?.mayClientSendStateEvent(EventType.RoomHistoryVisibility, client);

const options = [
{
value: HistoryVisibility.Shared,
label: _t("room_settings|security|history_visibility_shared"),
},
{
// Map 'joined' to 'invited' for display purposes
const displayHistory = history === HistoryVisibility.Joined ? HistoryVisibility.Invited : history;

const isPublicRoom = this.props.room.getJoinRule() === JoinRule.Public;
const isEncrypted = this.state.encrypted;

const options: Array<{ value: HistoryVisibility; label: string }> = [];

// Show "invited" when room's join rule is NOT public OR E2EE is turned on, or if currently selected
if (
!isPublicRoom ||
isEncrypted ||
history === HistoryVisibility.Invited ||
history === HistoryVisibility.Joined
) {
options.push({
value: HistoryVisibility.Invited,
label: _t("room_settings|security|history_visibility_invited"),
},
{
value: HistoryVisibility.Joined,
label: _t("room_settings|security|history_visibility_joined"),
},
];
});
}

// World readable doesn't make sense for encrypted rooms
if (!this.state.encrypted || history === HistoryVisibility.WorldReadable) {
options.unshift({
// Always show "shared" option
options.push({
value: HistoryVisibility.Shared,
label: _t("room_settings|security|history_visibility_shared"),
});

// Show "world_readable" when (is public AND not encrypted) OR currently selected
if ((isPublicRoom && !isEncrypted) || history === HistoryVisibility.WorldReadable) {
options.push({
value: HistoryVisibility.WorldReadable,
label: _t("room_settings|security|history_visibility_world_readable"),
});
}

const description = _t("room_settings|security|history_visibility_warning");
const description = (
<>
{_t(
"room_settings|security|history_visibility_warning",
{},
{
a: (sub) => (
<ExternalLink href="https://element.io/en/help#e2ee-history-sharing">{sub}</ExternalLink>
),
},
)}
</>
);

return (
<SettingsFieldset legend={_t("room_settings|security|history_visibility_legend")} description={description}>
<StyledRadioGroup
name="historyVis"
value={history}
value={displayHistory}
onChange={this.onHistoryRadioToggle}
disabled={!canChangeHistory}
definitions={options}
Expand Down
9 changes: 4 additions & 5 deletions src/i18n/strings/en_EN.json
Original file line number Diff line number Diff line change
Expand Up @@ -2431,12 +2431,11 @@
"error_join_rule_change_title": "Failed to update the join rules",
"error_join_rule_change_unknown": "Unknown failure",
"guest_access_warning": "People with supported clients will be able to join the room without having a registered account.",
"history_visibility_invited": "Members only (since they were invited)",
"history_visibility_joined": "Members only (since they joined)",
"history_visibility_invited": "Members since invited",
"history_visibility_legend": "Who can read history?",
"history_visibility_shared": "Members only (since the point in time of selecting this option)",
"history_visibility_warning": "The visibility of existing history will not be changed.",
"history_visibility_world_readable": "Anyone",
"history_visibility_shared": "Members (full history)",
"history_visibility_warning": "Changes won't affect past messages, only new ones. <a>Learn more</a>",
"history_visibility_world_readable": "Anyone (history is public)\n",
"join_rule_description": "Decide who can join %(roomName)s.",
"join_rule_invite": "Private (invite only)",
"join_rule_invite_description": "Only invited people can join.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,76 @@ describe("<SecurityRoomSettingsTab />", () => {
expect(screen.getByDisplayValue(HistoryVisibility.Shared)).toBeChecked();
expect(logger.error).toHaveBeenCalledWith("oups");
});

it("maps 'joined' history visibility to 'invited' for display", () => {
const room = new Room(roomId, client, userId);
setRoomStateEvents(room, undefined, undefined, HistoryVisibility.Joined);

getComponent(room);

// Should display as 'invited' even though underlying value is 'joined'
expect(screen.getByDisplayValue(HistoryVisibility.Invited)).toBeChecked();
// Should not have a 'joined' option visible
expect(screen.queryByDisplayValue(HistoryVisibility.Joined)).not.toBeInTheDocument();
});

it("shows 'invited' option for non-public rooms", () => {
const room = new Room(roomId, client, userId);
setRoomStateEvents(room, JoinRule.Invite);

getComponent(room);

expect(screen.getByDisplayValue(HistoryVisibility.Invited)).toBeInTheDocument();
});

it("shows 'invited' option for encrypted rooms even if public", async () => {
const room = new Room(roomId, client, userId);
jest.spyOn(client.getCrypto()!, "isEncryptionEnabledInRoom").mockResolvedValue(true);
setRoomStateEvents(room, JoinRule.Public);

getComponent(room);

await waitFor(() => expect(screen.getByDisplayValue(HistoryVisibility.Invited)).toBeInTheDocument());
});

it("does not show 'invited' option for public unencrypted rooms unless selected", async () => {
const room = new Room(roomId, client, userId);
setRoomStateEvents(room, JoinRule.Public, undefined, HistoryVisibility.Shared);

getComponent(room);

await waitFor(() => expect(screen.queryByDisplayValue(HistoryVisibility.Invited)).not.toBeInTheDocument());
});

it("shows 'world_readable' option for public unencrypted rooms", async () => {
const room = new Room(roomId, client, userId);
setRoomStateEvents(room, JoinRule.Public);

getComponent(room);

await waitFor(() => expect(screen.getByDisplayValue(HistoryVisibility.WorldReadable)).toBeInTheDocument());
});

it("does not show 'world_readable' option for private encrypted rooms unless selected", async () => {
const room = new Room(roomId, client, userId);
jest.spyOn(client.getCrypto()!, "isEncryptionEnabledInRoom").mockResolvedValue(true);
setRoomStateEvents(room, JoinRule.Invite);

getComponent(room);

await waitFor(() =>
expect(screen.queryByDisplayValue(HistoryVisibility.WorldReadable)).not.toBeInTheDocument(),
);
});

it("always shows 'shared' option", () => {
const room = new Room(roomId, client, userId);
setRoomStateEvents(room);

getComponent(room);

expect(screen.getByDisplayValue(HistoryVisibility.Shared)).toBeInTheDocument();
});
});

describe("encryption", () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,32 @@ exports[`<SecurityRoomSettingsTab /> history visibility uses shared as default h
<div
class="mx_SettingsSubsection_text"
>
The visibility of existing history will not be changed.
<span>
Changes won't affect past messages, only new ones.
<a
class="mx_ExternalLink"
href="https://element.io/en/help#e2ee-history-sharing"
rel="noreferrer noopener"
target="_blank"
>
Learn more
<svg
class="mx_ExternalLink_icon"
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M5 3h6a1 1 0 1 1 0 2H5v14h14v-6a1 1 0 1 1 2 0v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2"
/>
<path
d="M15 3h5a1 1 0 0 1 1 1v5a1 1 0 1 1-2 0V6.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L17.586 5H15a1 1 0 1 1 0-2"
/>
</svg>
</a>
</span>
</div>
</div>
<div
Expand All @@ -25,18 +50,18 @@ exports[`<SecurityRoomSettingsTab /> history visibility uses shared as default h
class="mx_StyledRadioButton mx_StyledRadioButton_enabled"
>
<input
id="historyVis-world_readable"
id="historyVis-invited"
name="historyVis"
type="radio"
value="world_readable"
value="invited"
/>
<div>
<div />
</div>
<div
class="mx_StyledRadioButton_content"
>
Anyone
Members since invited
</div>
<div
class="mx_StyledRadioButton_spacer"
Expand All @@ -58,49 +83,7 @@ exports[`<SecurityRoomSettingsTab /> history visibility uses shared as default h
<div
class="mx_StyledRadioButton_content"
>
Members only (since the point in time of selecting this option)
</div>
<div
class="mx_StyledRadioButton_spacer"
/>
</label>
<label
class="mx_StyledRadioButton mx_StyledRadioButton_enabled"
>
<input
id="historyVis-invited"
name="historyVis"
type="radio"
value="invited"
/>
<div>
<div />
</div>
<div
class="mx_StyledRadioButton_content"
>
Members only (since they were invited)
</div>
<div
class="mx_StyledRadioButton_spacer"
/>
</label>
<label
class="mx_StyledRadioButton mx_StyledRadioButton_enabled"
>
<input
id="historyVis-joined"
name="historyVis"
type="radio"
value="joined"
/>
<div>
<div />
</div>
<div
class="mx_StyledRadioButton_content"
>
Members only (since they joined)
Members (full history)
</div>
<div
class="mx_StyledRadioButton_spacer"
Expand Down
Loading