fix(security): keep inbox access filtering on the participating scope (#15207)
An agent who is removed from an inbox could still see that inbox's conversations under the **Participating** filter. Removing an agent from an inbox does not delete the conversation participant records they already had, and the participating filter was ignoring inbox access entirely — so those conversations stayed visible indefinitely. The filter now respects inbox access like every other conversation filter. ## Linear Ticket - https://linear.app/chatwoot/issue/CW-6923 ## How to reproduce 1. Add an agent to two inboxes, A and B. 2. As that agent, become a participant on a conversation in inbox B (open it, or get added as a participant). 3. Remove the agent from inbox B in Settings → Inboxes → Collaborators. 4. Log in as the agent and open Conversations → Participating. 5. The inbox B conversation is still listed, and is openable. ## What changed `ConversationFinder#filter_by_conversation_type` **replaced** `@conversations` with `current_user.participating_conversations` for the `participating` type, discarding the inbox/permission-filtered scope built up by `Conversations::PermissionFilterService` immediately before it. It now narrows the existing scope by participating ids instead, so permission filtering survives.
This commit is contained in:
committed by
GitHub
parent
e3e35ab7e1
commit
0df9508893
@@ -290,5 +290,35 @@ describe ConversationFinder do
|
||||
expect(result[:conversations].length).to be 2
|
||||
end
|
||||
end
|
||||
|
||||
context 'with participating' do
|
||||
let(:params) { { status: 'open', assignee_type: 'all', conversation_type: 'participating' } }
|
||||
|
||||
it 'excludes participating conversations from inboxes the user no longer has access to' do
|
||||
accessible_conversation = create(:conversation, account: account, inbox: inbox)
|
||||
revoked_conversation = create(:conversation, account: account, inbox: restricted_inbox)
|
||||
revoked_membership = create(:inbox_member, user: user_1, inbox: restricted_inbox)
|
||||
create(:conversation_participant, user: user_1, conversation: accessible_conversation, account: account)
|
||||
create(:conversation_participant, user: user_1, conversation: revoked_conversation, account: account)
|
||||
revoked_membership.destroy!
|
||||
|
||||
result = conversation_finder.perform
|
||||
|
||||
expect(result[:conversations].map(&:id)).to contain_exactly(accessible_conversation.id)
|
||||
end
|
||||
|
||||
it 'excludes the inaccessible conversation from the meta counts too' do
|
||||
accessible_conversation = create(:conversation, account: account, inbox: inbox)
|
||||
revoked_conversation = create(:conversation, account: account, inbox: restricted_inbox)
|
||||
revoked_membership = create(:inbox_member, user: user_1, inbox: restricted_inbox)
|
||||
create(:conversation_participant, user: user_1, conversation: accessible_conversation, account: account)
|
||||
create(:conversation_participant, user: user_1, conversation: revoked_conversation, account: account)
|
||||
revoked_membership.destroy!
|
||||
|
||||
result = conversation_finder.perform_meta_only
|
||||
|
||||
expect(result[:count][:all_count]).to eq 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user