Commit Graph
84 Commits
Author SHA1 Message Date
Herculino Trotta e2f26b3629 fix(sharing): enforce object-level authorization outside the rules app
The rules endpoints were one instance of a pattern repeated across every
SharedObject-backed app. Route the rest through the same helper.

DCA entries were the worst case and are strictly wider than the reported
rules bug: DCAEntry has an unscoped default manager, so filtering by
strategy__id alone reached entries on strategies the caller could not see
at all. No public or shared strategy was needed -- only a guessable
integer. strategy_entry_add/edit/delete now resolve through the parent
strategy with via="strategy".

Every SharedObject delete view carried an inverted condition:

    if obj.owner != request.user and request.user in obj.shared_with.all():
        obj.shared_with.remove(request.user)
    else:
        obj.delete()

An object its owner had made public matched neither branch's intent and
fell through to delete(), so any authenticated user could destroy it.
Confirmed reachable for accounts, account groups, categories, tags,
entities and DCA strategies. The owner now deletes, a shared user revokes
only their own access, and anyone else gets a 403.

The API viewsets had no object-level check at all. DjangoModelPermissions
gated them shut for ordinary users, who hold no model permissions, so this
was not reachable in a default install -- but the check belongs there
regardless, and a user granted change_account in the admin could write any
visible account. SharedObjectPermission adds it for the SharedObject
viewsets, leaving reads to SharedObjectManager.

account_toggle_untracked only flips the calling user's own row in the
untracked_by m2m, so it takes READ rather than EDIT.

Refs GHSA-83g9-vjqf-2j5q
2026-09-01 23:15:41 -03:00
Herculino Trotta 039ad225d3 test(rules): cover object-level authorization for transaction rules
Regression tests for GHSA-83g9-vjqf-2j5q, one per endpoint the advisory
named plus the delete and view paths found alongside them: a non-owner
gets 403 on every mutation of a public or shared rule, and the object is
asserted unchanged afterwards.

Also covers the parts that are easy to regress in the other direction:
shared users keep read access, a shared user deleting only revokes their
own access, unowned rules stay claimable, and children of invisible rules
answer 404 rather than 403.

SharedObjectPredicateParityTests asserts is_visible_to agrees with
SharedObjectManager across every owner/visibility/shared combination.
The manager builds a Q and the predicate tests an instance, so they
cannot share an implementation and can otherwise drift apart.
2026-09-01 21:43:13 -03:00
Herculino Trotta 18d4ab7d11 fix(rules): enforce object-level authorization on rule endpoints
SharedObjectManager scopes querysets to what a user may see, which
includes other people's public and shared-with-them objects. Several
mutating rule endpoints treated that visibility as permission to write.

Generalise get_owned_object_or_403 into get_shared_object_or_error, which
takes an explicit access level instead of inferring one:

- READ requires the object to be visible; denial is 404 so the response
  does not confirm that an id exists.
- EDIT requires ownership; denial is 403, but only after the visibility
  check, so 403 never leaks the existence of an invisible object. This
  matters for TransactionRuleAction, whose manager is unscoped.

The previous owner_path resolved to a User and discarded the object, so
it could not express visibility at all. via= now points at the governing
SharedObject and is resolved with a plain getattr, so an unresolvable
path raises instead of silently granting access.

is_visible_to/is_editable_by replace is_accessible_by, which was never
called and tested visibility == "shared", a value that does not exist in
Visibility.

Also fixes two further holes in the same module:

- transaction_rule_delete fell through to delete() whenever the caller
  was not in shared_with, so any user could delete a public rule. Now
  only the owner deletes; a shared user revokes their own access.
- transaction_rule_view was read-only but is now explicitly READ, so
  rules shared with a user stay viewable.

The activate/deactivate control is hidden for rules the user does not
own, instead of rendering a button that always fails.

Refs GHSA-83g9-vjqf-2j5q
2026-09-01 21:25:46 -03:00
Herculino Trotta cd48edddab feat(transactions): add htmx filter presets 2026-08-16 01:40:11 -03:00
Herculino Trotta 9e135560fe feat(transactions): add filter preset model 2026-08-16 01:40:03 -03:00
Herculino Trotta 33f0904a0f feat(dca): add chart zoom navigation 2026-08-15 15:10:10 -03:00
Herculino Trotta 8e09f3e8d8 feat(net-worth): add consolidated chart lines 2026-08-15 14:36:13 -03:00
Herculino Trotta 3bd16602a0 fix(tools:calculator): prevent close button from drifiting to the right 2026-08-15 11:41:15 -03:00
Herculino Trotta f9eab3ce17 fix(docker:dev): handle CRLF endings on vite entrypoint 2026-08-15 01:32:02 -03:00
Herculino Trotta ea3e9fd68f feat(monthly): show asset accounts/currencies on specific sumaries 2026-08-15 01:30:57 -03:00
Herculino Trotta 743951a862 feat(automatic-exchange-rates): Add Yahoo Finance as a provider via yfinance 2026-07-18 15:42:51 -03:00
Herculino Trotta 75f23168ab feat(docker:dev): npm dependencies are installed when container starts 2026-07-17 21:29:45 -03:00
Herculino Trotta 5a80a3b1d3 feat: replace mp3 sounds with cuelume; deprecate volume setting 2026-07-17 21:28:13 -03:00
Herculino Trotta 83286fff5f fix(air-datepicker): unwrap Vite locale modules so it doesn't default to russian 2026-07-10 17:49:46 -03:00
Herculino Trotta 106d721279 feat: add demo mode tests to ensure API is disabled on it 2026-06-27 18:02:31 -03:00
Herculino Trotta d0e9c05283 feat: disable oauth and token creation while on demo mode 2026-06-27 18:02:03 -03:00
Herculino Trotta 7f5a91c11f fix: wrong Guam timezone string 2026-06-27 17:56:24 -03:00
Herculino Trotta 009a7038c8 style: improve api token box look 2026-06-27 17:56:05 -03:00
Herculino Trotta ae115cca15 feat(tom-select): clear input after picking on a multi-item select 2026-06-12 23:32:17 -03:00
Herculino Trotta 6987b54dba chore: bump python and node dependencies 2026-06-06 05:14:26 -03:00
Herculino Trotta 0ee32724f1 style(toas): move toast to the top of offcanvas 2026-06-06 04:33:23 -03:00
Herculino Trotta 6a19381672 feat(transactions): add attachments 2026-06-06 04:33:06 -03:00
Herculino Trotta d72ff3cdf5 fix(rules): allow category expressions to clear categories 2026-05-02 16:16:27 -03:00
Herculino Trotta 63c69e5c6a test(api): expect unauthorized for anonymous requests 2026-05-02 16:16:08 -03:00
Herculino Trotta 78171183cc test(currencies): avoid test discovery collision 2026-05-02 16:15:48 -03:00
Herculino Trotta 34a2b6bfd4 fix(procrastinate): close Django connections around jobs 2026-05-02 16:15:26 -03:00
Herculino Trotta 8fc11b0acf feat(transactions): hide filter on page load to prevent flashing 2026-05-01 00:07:43 -03:00
Herculino Trotta 9a30a0d3c0 chore: bump versions and other minor things 2026-05-01 00:07:15 -03:00
Herculino Trotta 10eecd09ff fix(frontend): hyperscript not working correctly for offcanvas and modals 2026-04-30 23:16:19 -03:00
Herculino Trotta 2cfb3fb12e fix(frontend): bootstrap-grid-plugin broke 2026-04-30 23:03:42 -03:00
Herculino TrottaandCopilot dc76ed3156 fix(tom-select): dropdown covers select field when height increases
Co-authored-by: Copilot <copilot@github.com>
2026-04-23 23:29:42 -03:00
Herculino Trotta 80da9142f1 fix: pulltorefresh enabled globally 2026-02-15 23:36:23 -03:00
Herculino Trotta c787565c04 refactor: move help_text to model definition 2026-02-15 23:22:52 -03:00
Herculino Trotta 0413921dbe fix: migrations set default as 0 instead of null 2026-02-15 23:22:10 -03:00
Herculino Trotta ea097ab6f0 feat(auth): trust OIDC connections and connect them with local accounts 2026-02-15 14:41:45 -03:00
Herculino Trotta 27e85c4776 feat(frontend): add pull to refresh for iOS PWA 2026-02-15 11:34:28 -03:00
Herculino Trotta ea5d86dbf8 fix: allauth not sending https redirect_uri 2026-02-11 21:42:00 -03:00
Herculino Trotta a1d3539e3c feat: add allauth logging 2026-02-11 21:41:17 -03:00
Herculino Trotta 41adb37fdb feat: add reload button to the HTMX error popup 2026-02-01 22:25:47 -03:00
Herculino Trotta 24a1ef2d0a fix: add encoding to qif preset 2026-01-25 16:57:00 -03:00
Herculino Trotta d5bbad7887 feat: add QIF import 2026-01-25 16:46:56 -03:00
Herculino Trotta 49cac0588e add tests and fix missing get_queryset 2026-01-11 12:20:27 +01:00
Herculino Trotta 1a0412264a add tests and fix missing get_queryset 2026-01-10 17:42:37 -03:00
Herculino Trotta 50e5492ea1 feat(automatic-exchange-rate): track unsuccessful runs 2026-01-10 14:10:21 -03:00
Herculino Trotta b074ef7929 feat: add late section to monthly and all views (w/ default ordering) 2026-01-10 02:52:46 -03:00
Herculino Trotta ff4bd79634 fix(dca): strategy api endpoint returns nothing 2026-01-09 23:51:31 -03:00
Herculino Trotta dd6a390e6b fix(transactions): empty internal_id raises duplicate error when editing via django admin 2026-01-09 23:25:13 -03:00
Herculino Trotta b455a0251a fix(import_restore): unable to restore installment plans when there's multiple accounts with the same name 2025-12-30 21:59:29 -03:00
Herculino Trotta 6c90e1bb7f refactor: improve month by month and year by year value display 2025-12-30 21:58:12 -03:00
Herculino Trotta 39f66b620a feat(insights): new month by month insight 2025-12-28 22:57:29 -03:00
Herculino Trotta 92cf526b76 feat(insights): new year by year insight 2025-12-28 22:55:58 -03:00
Herculino Trotta 700d35b5d5 feat(tests): add tests for monthly summaries 2025-12-28 13:36:21 -03:00
Herculino Trotta 01f91352d6 feat(transactions:filter): make montlhy summary filter-aware 2025-12-28 13:20:25 -03:00
Herculino Trotta a2871d5289 feat(transactions:filter): add filter for muted and unmuted transactions 2025-12-28 13:09:41 -03:00
Herculino Trotta 2076903740 refactor: order management lists by name instead of id 2025-12-27 23:43:57 -03:00
Herculino Trotta 7ea9d56132 docs: update uv.lock 2025-12-27 20:11:36 -03:00
Herculino Trotta 3699c6c671 docs: remove version from pyproject.yml 2025-12-27 19:58:46 -03:00
Herculino Trotta d7c255aa14 refactor: remove build context from production image 2025-12-27 19:53:57 -03:00
Herculino Trotta d17b9d5736 fix: dev image fails due to the environment being overwritten at runtime 2025-12-26 10:30:22 -03:00
Herculino Trotta c7ff6db0bf feat(app): add sanity checks for env variables 2025-12-26 09:55:57 -03:00
Herculino Trotta 05ede58c36 fix: "lax" deduplication fails if the comparison field has a numeric value 2025-12-20 00:17:22 -03:00
Herculino Trotta b0101dae1a fix: input fields with text inside looks wrong 2025-12-20 00:08:56 -03:00
Herculino Trotta edcad37926 fix: recurring transactions not adding entities or tags to created transactions 2025-12-19 23:55:30 -03:00
Herculino Trotta 94f5c25829 fix: datepicker doesn't recalculate position when changing view mode 2025-12-19 22:21:03 -03:00
Herculino Trotta 3dce9e1c55 feat: speedup startup by moving collectstatic to the Dockerfile 2025-12-19 22:13:05 -03:00
Herculino Trotta 0545fb7651 fix: try to fix stale database connections (again) 2025-12-19 21:59:55 -03:00
Herculino Trotta f918351303 fix: user settings form 2025-12-14 12:47:36 -03:00
Herculino Trotta 8f06c06d32 fix: extra space on some translations 2025-12-14 11:56:20 -03:00
Herculino Trotta 67f79effab feat: improve text for rules 2025-12-14 11:43:52 -03:00
Herculino Trotta c168886968 feat: improve text for rules 2025-12-14 11:42:51 -03:00
Herculino Trotta 4aa29545ec feat: remove bootstrap's collapses; improve animations 2025-12-14 11:06:55 -03:00
Herculino Trotta cf7d4b1404 feat: improve transactions action bar animation 2025-12-13 20:47:51 -03:00
Herculino Trotta 606e6b3843 fix(style): demo mode close button is place incorrectly 2025-12-13 16:45:57 -03:00
Herculino Trotta 29b6ee3af3 feat: add "invert selection" option to transactions action bar 2025-12-13 16:35:53 -03:00
Herculino Trotta 938c128d07 fix: show muted transactions/categories on account and currency flow. 2025-12-13 16:18:19 -03:00
Herculino Trotta dc33fda5d3 feat: prevent background tasks from running all at once 2025-12-13 15:07:38 -03:00
Herculino Trotta e8e1144fdd fix(api): inefficient transaction update operation 2025-12-07 13:53:30 -03:00
Herculino Trotta d3a816d91b feat(api): add endpoints for importing files and getting account balance 2025-12-07 00:32:18 -03:00
Herculino Trotta c55d688956 fix(import:v1): always_* types for is_paid and type requires assigning a source 2025-12-06 17:52:46 -03:00
Herculino Trotta 01ea0de4b3 fix: decouple DEBUG env variable from vite dev server 2025-12-06 17:32:34 -03:00
Herculino Trotta 92f7bcfd9e fix: try to fix "the connection is closed" db errors 2025-12-06 16:46:33 -03:00
Herculino Trotta aed3fb11fe feat: accept query params on standalone add transaction page 2025-12-06 16:17:37 -03:00
Herculino Trotta b6f52458db chore: bump dependencies 2025-12-06 14:22:56 -03:00
Herculino Trotta a43e3d158f chore: bump dependencies for safety 2025-12-06 14:02:37 -03:00