13225 Commits

Author SHA1 Message Date
kolaente
b365be1881 chore: v2.2.0 release preparations v2.2.0 2026-03-20 13:40:18 +01:00
kolaente
1f2aef776c test: verify CalDAV token auth bypasses TOTP check
Add a CalDAV token fixture (kind=4) for user10 who has TOTP enabled,
and implement the previously-skipped test proving token-based auth
still works when TOTP is active.
2026-03-20 12:22:27 +00:00
kolaente
1ed813caf0 fix: update TOTP fixtures and tests to avoid conflicts with existing enrollment tests
- user10 gets enabled TOTP (for CalDAV 2FA test)
- user1 gets enrolled-but-not-enabled TOTP (for existing QR/settings tests)
- TOTP enrollment test uses user2 (no TOTP fixture) instead of user1
2026-03-20 12:22:27 +00:00
kolaente
659e73af05 fix: use user10 instead of user1 for TOTP fixture to avoid breaking login tests 2026-03-20 12:22:27 +00:00
kolaente
cdf5d30a42 fix: reject CalDAV basic auth when TOTP is enabled 2026-03-20 12:22:27 +00:00
kolaente
a66bda2f51 test: register totp fixture in test setup 2026-03-20 12:22:27 +00:00
kolaente
bda16e770f test: add failing test for CalDAV 2FA bypass via basic auth 2026-03-20 12:22:27 +00:00
kolaente
27ef92b9bf test: add TOTP fixture data for user1 2026-03-20 12:22:27 +00:00
kolaente
b7a1408098 fix: use require.Error instead of assert.Error for error assertions 2026-03-20 11:41:28 +00:00
kolaente
4b91e5efa1 refactor: rename checkProjectBackgroundWriteRights to checkProjectBackgroundWritePermissions 2026-03-20 11:41:28 +00:00
kolaente
49419619bd fix: only enforce task_id check when TaskID is provided
Internal callers (reactions) look up comments by ID without knowing
the task. The IDOR protection is still effective because ReadOne
always has TaskID set from the URL parameter.
2026-03-20 11:41:28 +00:00
kolaente
f066eb3ea4 fix: require CanUpdate for project background deletion
RemoveProjectBackground previously used checkProjectBackgroundRights
which only checks CanRead, allowing read-only users to delete project
backgrounds. Added checkProjectBackgroundWriteRights that checks
CanUpdate and use it in RemoveProjectBackground.

Ref: GHSA-564f-wx8x-878h
2026-03-20 11:41:28 +00:00
kolaente
f60f3af70b test: add failing test for project background delete with read-only access
Proves that a user with read-only access to a project can delete its
background image. The test expects a 403 Forbidden but the operation
proceeds because RemoveProjectBackground only checks CanRead.

Adds fixture entry giving user 15 read-only access to project 35
(which has a background_file_id).

Ref: GHSA-564f-wx8x-878h
2026-03-20 11:41:28 +00:00
kolaente
bc6d843ed4 fix: verify comment belongs to task in URL to prevent IDOR
Add task_id check to getTaskCommentSimple so that a comment can only
be loaded if it actually belongs to the task specified in the URL.
Previously, any valid comment ID could be read through any accessible
task endpoint.

Ref: GHSA-mr3j-p26x-72x4
2026-03-20 11:41:28 +00:00
kolaente
2da89258e5 test: add failing test for task comment IDOR
Proves that a user can read a comment from an inaccessible task by
supplying an accessible task ID in the URL. Comment 18 belongs to
task 34 (owned by user 13), but testuser1 can read it via task 1.

Ref: GHSA-mr3j-p26x-72x4
2026-03-20 11:41:28 +00:00
kolaente
be0aaa7060 fix: adapt image preview DoS protection to new FileStorage interface
File.File is now io.ReadCloser (no Seek). Buffer the file bytes
once via io.ReadAll, then use bytes.NewReader for both DecodeConfig
and Decode. Test updated to use io.NopCloser instead of afero.
2026-03-20 11:34:41 +00:00
kolaente
af61d0f1a0 fix: reject images exceeding 50M pixels before decode 2026-03-20 11:34:41 +00:00
kolaente
f7592e2cfd test: add failing test for image preview with oversized dimensions 2026-03-20 11:34:41 +00:00
kolaente
82c24a826a fix(desktop): block same-window navigation to external origins 2026-03-20 11:30:09 +00:00
kolaente
b9d4d5e4ac fix(desktop): validate URL schemes before shell.openExternal 2026-03-20 11:30:09 +00:00
kolaente
23de2197fd fix(desktop): disable nodeIntegration and enable contextIsolation/sandbox 2026-03-20 11:30:09 +00:00
kolaente
89923ebe70 fix: update test expectations for new disabled user fixture
- TestListUsers expects 17 users (was 16)
- TestCleanupOldTokens expects 3 old tokens deleted (was 2)
2026-03-20 11:23:21 +00:00
kolaente
049f4a6be4 fix: prevent email confirmation from re-enabling admin-disabled accounts 2026-03-20 11:23:21 +00:00
kolaente
2260d763b5 test: add web test for disabled user password reset rejection 2026-03-20 11:23:21 +00:00
kolaente
241b0e80b6 test: add tests for disabled user password reset prevention 2026-03-20 11:23:21 +00:00
kolaente
708ccab895 fix: reject password reset token requests for disabled users 2026-03-20 11:23:21 +00:00
kolaente
d8570c603d fix: prevent password reset from re-enabling admin-disabled accounts 2026-03-20 11:23:21 +00:00
kolaente
4c80932b64 fix: block login for StatusAccountLocked users 2026-03-20 11:23:21 +00:00
kolaente
7792bf6cea refactor: use StatusAccountLocked for TOTP lockouts 2026-03-20 11:23:21 +00:00
kolaente
f42a045bdc feat: add StatusAccountLocked user status for TOTP lockouts 2026-03-20 11:23:21 +00:00
kolaente
ddd9ef5f22 style: fix alignment in config key declarations 2026-03-20 11:08:00 +00:00
kolaente
015a172c2a docs: document IP extraction and trusted proxy config options 2026-03-20 11:08:00 +00:00
kolaente
a498dd6991 fix: configure Echo IPExtractor to prevent rate limit bypass via spoofed headers 2026-03-20 11:08:00 +00:00
kolaente
26324a740a feat: add service.ipextractionmethod and service.trustedproxies config options 2026-03-20 11:08:00 +00:00
kolaente
763d25ca18 feat(ci): enable merge queue trigger 2026-03-20 11:53:08 +01:00
kolaente
17eccd848f test: add FileStat assertion to validate storage path in attachment test 2026-03-20 10:59:44 +01:00
kolaente
4cd63f93a4 fix: use file mime type instead of hardcoded application/zip in S3 export 2026-03-20 10:59:44 +01:00
kolaente
0e1f44e57e refactor: replace afero with FileStorage interface
Replace the github.com/spf13/afero dependency with a purpose-built
FileStorage interface (Open, Write, Stat, Remove, MkdirAll) with three
implementations: localStorage (with basePath), s3Storage (with key
prefix), and memStorage (for tests).

Each implementation owns its base path — callers pass only file IDs.
Delete s3fs.go, change File.File from afero.File to io.ReadCloser,
and fix duplication flows to buffer content for seeking.
2026-03-20 10:59:44 +01:00
maggch
b0ede53c05 fix: handle S3 backend in user export download
http.ServeContent requires io.ReadSeeker which S3 files don't support.
Add S3 branch using io.Copy with explicit headers, matching the pattern
already used in task attachment downloads.

Refs: #2347

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-20 10:59:44 +01:00
maggch
b065c62007 feat: replace afero-s3 with minimal S3 afero.Fs implementation
Replace the third-party afero-s3 library (and its temporary fork) with
a minimal in-tree afero.Fs implementation (~200 lines) that only supports
the three S3 operations Vikunja actually uses: Open (GetObject), Remove
(DeleteObject), and Stat (HeadObject).

The s3File implementation lazily opens a GetObject stream on first Read
and supports Seek by closing and re-opening the stream from the new offset,
matching the behavior of the fixed afero-s3 fork.

All other afero.Fs/File methods return ErrS3NotSupported since they are
never called in the S3 code path (writes already use direct PutObject).

This removes the fclairamb/afero-s3 dependency and the temporary replace
directive in go.mod entirely.

Closes #2347

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-20 10:59:44 +01:00
kolaente
c81b0eb463 fix(attachments): sync kanban store and task ref on attachment changes
When attachments are uploaded (either via file picker or pasting into
the description editor), update both the local task ref and the kanban
store so that the attachment list and kanban card icons stay in sync.
2026-03-20 10:38:47 +01:00
kolaente
ade91c92db refactor(attachments): remove global attachment store
The attachment store was a global singleton shared between concurrent
TaskDetailView instances, causing a race condition when navigating
between tasks via related tasks from the Kanban view. Attachments
now live on the task ref like every other task field.
2026-03-20 10:38:47 +01:00
kolaente
2675bcb56c refactor(attachments): use local state instead of global attachment store
TaskDetailView now computes hasAttachments from the task ref and
handles the update:attachments emit from the Attachments component.
2026-03-20 10:38:47 +01:00
kolaente
eaec206301 refactor(attachments): return uploaded attachments instead of writing to store
uploadFiles now returns the array of uploaded IAttachment objects
so callers can handle state updates themselves.
2026-03-20 10:38:47 +01:00
kolaente
5dbc906d47 refactor(attachments): read from task prop instead of global store
The Attachments component now reads attachments from its task prop
and emits update:attachments events instead of using the global
attachment store singleton.
2026-03-20 10:38:47 +01:00
Henry Cole
e7f1e99878 fix(caldav): use /dav/projects/ as home to make iOS/MacOS reminders work (#2417)
Resolves issue #475 by modifying CalDAV discovery so Apple Reminders can
use /dav/projects/ as the home set without exposing that synthetic path
as a real task list, preserving the existing principal-based flow. This
is because Apple Reminders defaults back to the /dav/projects/ URL,
rather than accepting the /dav/principals/username/ URL specified in
Vikunja.

Resolves #475
2026-03-20 09:33:56 +00:00
renovate[bot]
9c3fa8e91b chore(deps): update dependency stylelint to v17.5.0 2026-03-20 10:17:24 +01:00
Frederick [Bot]
de1d5d1241 chore(i18n): update translations via Crowdin 2026-03-20 01:14:18 +00:00
kolaente
629b6d447c test(webhooks): allow non-routable IPs in E2E tests
E2E tests use httptest.NewServer bound to 127.0.0.1, which is now
blocked by default SSRF protection. Opt in to non-routable IPs.
2026-03-19 15:18:06 +01:00
kolaente
8d9bc3e65e feat(webhooks): add built-in SSRF protection using daenney/ssrf
Block webhook requests to non-globally-routable IP addresses by default.
Uses net.Dialer.Control hook to validate resolved IPs against IANA
Special Purpose Registries after DNS resolution, preventing DNS rebinding.

Configurable via webhooks.allownonroutableips (default: false).
2026-03-19 15:18:06 +01:00