diff --git a/web/src/stream_data.ts b/web/src/stream_data.ts index 54575a832f..c0a9374d8c 100644 --- a/web/src/stream_data.ts +++ b/web/src/stream_data.ts @@ -519,6 +519,50 @@ export function has_metadata_access(sub: StreamSubscription): boolean { return false; } +export function has_content_access(sub: StreamSubscription): boolean { + if (sub.is_web_public) { + return true; + } + + if (page_params.is_spectator) { + return false; + } + + if (sub.subscribed) { + return true; + } + + if (!has_metadata_access(sub)) { + return false; + } + + if (current_user.is_guest) { + /* istanbul ignore next */ + return false; + } + + // This is after the is_guest check, because this setting has + // allow_everyone_group=false. TODO: Consider adding a + // is_user_in_setting_group wrapper abstraction that handles this detail automatically. + const can_add_subscribers = user_groups.is_user_in_setting_group( + sub.can_add_subscribers_group, + people.my_current_user_id(), + ); + if (can_add_subscribers) { + return true; + } + + if (sub.invite_only) { + return false; + } + + // We do not do an admin check here since having admin permissions + // to a private channel does not give user access to that channel's + // content. + + return true; +} + function can_administer_accessible_channel(sub: StreamSubscription): boolean { if (current_user.is_admin) { return true; diff --git a/web/tests/stream_data.test.cjs b/web/tests/stream_data.test.cjs index 348466fa45..cf85ede812 100644 --- a/web/tests/stream_data.test.cjs +++ b/web/tests/stream_data.test.cjs @@ -1543,3 +1543,80 @@ test("has_metadata_access", ({override}) => { social.subscribed = true; assert.equal(stream_data.has_metadata_access(social), true); }); + +test("has_content_access", ({override}) => { + const social = { + subscribed: false, + color: "red", + name: "social", + stream_id: 2, + is_muted: false, + invite_only: false, + history_public_to_subscribers: false, + can_add_subscribers_group: nobody_group.id, + can_administer_channel_group: nobody_group.id, + }; + + assert.equal(stream_data.has_content_access(social), true); + + social.is_web_public = true; + assert.equal(stream_data.has_content_access(social), true); + page_params.is_spectator = true; + assert.equal(stream_data.has_content_access(social), true); + + social.is_web_public = false; + page_params.is_spectator = true; + assert.equal(stream_data.has_content_access(social), false); + page_params.is_spectator = false; + assert.equal(stream_data.has_content_access(social), true); + + // Permission to administer a private channel should not give + // content access when unsubscribed. + assert.equal(stream_data.has_content_access(social), true); + social.invite_only = true; + social.subscribed = false; + assert.equal(stream_data.has_content_access(social), false); + override(current_user, "is_admin", true); + assert.equal(stream_data.has_content_access(social), false); + override(current_user, "is_admin", false); + + // Channel admins should not have content access to a private + // channel when unsubscribed. + social.can_administer_channel_group = me_group.id; + social.subscribed = true; + assert.equal(stream_data.has_content_access(social), true); + social.subscribed = false; + assert.equal(stream_data.has_content_access(social), false); + social.can_administer_channel_group = nobody_group.id; + + // Guest should not have content access to a channel they are not + // subscribed to. + social.invite_only = false; + override(current_user, "is_guest", true); + social.subscribed = true; + assert.equal(stream_data.has_content_access(social), true); + social.subscribed = false; + assert.equal(stream_data.has_content_access(social), false); + // Unless it's a web-public channel + social.is_web_public = true; + assert.equal(stream_data.has_content_access(social), true); + social.is_web_public = false; + assert.equal(stream_data.has_content_access(social), false); + override(current_user, "is_guest", false); + assert.equal(stream_data.has_content_access(social), true); + social.invite_only = true; + + assert.equal(stream_data.has_content_access(social), false); + social.subscribed = true; + assert.equal(stream_data.has_content_access(social), true); + + social.invite_only = true; + assert.equal(stream_data.has_content_access(social), true); + social.subscribed = false; + assert.equal(stream_data.has_content_access(social), false); + + assert.equal(stream_data.has_content_access(social), false); + social.can_add_subscribers_group = me_group.id; + assert.equal(stream_data.has_content_access(social), true); + social.can_add_subscribers_group = nobody_group.id; +});