Fix transaction search account scope bypass (#1460)

Ensure accessible_account_ids filtering is applied whenever account scope is provided, including empty arrays, so users with no shared accounts cannot see family-wide transactions.

Also make totals robust when scoped queries return no rows and add regression tests for both visibility and totals behavior with empty accessible account lists.
This commit is contained in:
Juan José Mata
2026-04-13 21:23:59 +02:00
committed by GitHub
parent aacbb5ef3b
commit 69827dada8
2 changed files with 28 additions and 7 deletions

View File

@@ -29,8 +29,8 @@ class Transaction::Search
# This already joins entries + accounts. To avoid expensive double-joins, don't join them again (causes full table scan)
query = family.transactions.merge(Entry.excluding_split_parents)
# Scope to accessible accounts when provided
query = query.where(entries: { account_id: accessible_account_ids }) if accessible_account_ids&.any?
# Scope to accessible accounts when provided (including an empty array, which should yield no results)
query = query.where(entries: { account_id: accessible_account_ids }) unless accessible_account_ids.nil?
query = apply_active_accounts_filter(query, active_accounts_only)
query = apply_category_filter(query, categories)
@@ -88,11 +88,11 @@ class Transaction::Search
.take
Totals.new(
count: result.transactions_count.to_i,
income_money: Money.new(result.income_total, family.currency),
expense_money: Money.new(result.expense_total, family.currency),
transfer_inflow_money: Money.new(result.transfer_inflow_total, family.currency),
transfer_outflow_money: Money.new(result.transfer_outflow_total, family.currency)
count: result&.transactions_count.to_i,
income_money: Money.new((result&.income_total || 0), family.currency),
expense_money: Money.new((result&.expense_total || 0), family.currency),
transfer_inflow_money: Money.new((result&.transfer_inflow_total || 0), family.currency),
transfer_outflow_money: Money.new((result&.transfer_outflow_total || 0), family.currency)
)
end
end

View File

@@ -625,4 +625,25 @@ class Transaction::SearchTest < ActiveSupport::TestCase
end
end
end
test "empty accessible_account_ids yields no visible transactions" do
create_transaction(account: @checking_account, amount: 100)
search = Transaction::Search.new(@family, filters: {}, accessible_account_ids: [])
assert_empty search.transactions_scope
end
test "totals handles empty accessible_account_ids without raising" do
create_transaction(account: @checking_account, amount: 100)
search = Transaction::Search.new(@family, filters: {}, accessible_account_ids: [])
totals = search.totals
assert_equal 0, totals.count
assert_equal Money.new(0, @family.currency), totals.expense_money
assert_equal Money.new(0, @family.currency), totals.income_money
assert_equal Money.new(0, @family.currency), totals.transfer_inflow_money
assert_equal Money.new(0, @family.currency), totals.transfer_outflow_money
end
end