Commit Graph

179 Commits

Author SHA1 Message Date
kolaente
c7740fc4aa fix(user): use unique error code for ErrCodeAccountLocked
Was 1025 which collides with ErrorCodeInvalidTimezone. Changed to 1026.
2026-03-23 12:06:16 +00:00
kolaente
37394fb336 fix(user): use getUser directly for uniqueness checks in UpdateUser
The username and email uniqueness checks don't need status filtering —
they just need to know if the name/email exists regardless of account
status. Use getUser (which skips the status check) instead of the
public wrappers, reducing cyclomatic complexity back under the threshold.
2026-03-23 12:06:16 +00:00
kolaente
8409bdb120 refactor(user): export IsErrUserStatusError for use across packages
Make isErrUserStatusError public and replace all verbose
!IsErrAccountDisabled(err) && !IsErrAccountLocked(err) checks
with the shorter IsErrUserStatusError(err) call.
2026-03-23 12:06:16 +00:00
kolaente
525f5ee407 test: verify GetUserByID rejects disabled users and returns user with error 2026-03-23 12:06:16 +00:00
kolaente
91c0f386c6 fix(user): handle status errors in pkg/user callers, remove redundant checks 2026-03-23 12:06:16 +00:00
kolaente
04704e0fde fix(user): reject disabled/locked users in getUser by default
getUser now returns ErrAccountDisabled or ErrAccountLocked (alongside
the full user object) for users with StatusDisabled or StatusAccountLocked.
Callers that need disabled/locked users discard the error; all others
propagate it automatically.

GHSA-94xm-jj8x-3cr4
2026-03-23 12:06:16 +00:00
kolaente
be771289db feat(user): add ErrAccountLocked error type
Separate from ErrAccountDisabled so callers can distinguish between
admin-disabled accounts (no recovery) and locked accounts (recoverable
via password reset).
2026-03-23 12:06:16 +00:00
kolaente
0f98c19ab6 fix: add TTL-based expiry and cleanup for used TOTP passcode entries
Store a unix timestamp instead of a boolean, and treat entries older
than 90 seconds as expired. A background goroutine lazily cleans up
expired keys after each successful validation to prevent unbounded
growth in the keyvalue store.
2026-03-23 10:34:49 +00:00
kolaente
acafa6db10 fix: update TOTP reuse test to use user10 matching rebased fixture 2026-03-23 10:34:49 +00:00
kolaente
5f06e1dce5 fix: prevent TOTP passcode reuse within validity window
Store used TOTP passcodes in the keyvalue store after successful
validation. On subsequent validation attempts, check if the passcode
was already used for the same user and reject it with
ErrTOTPPasscodeUsed. This prevents replay attacks where an intercepted
TOTP code could be reused within its 30-second validity window.
2026-03-23 10:34:49 +00:00
kolaente
5591ca94ba test: add failing test for TOTP passcode reuse prevention
Add TestTOTPPasscodeCannotBeReused which verifies that a valid TOTP
passcode cannot be used twice within its validity window. Also add
ErrTOTPPasscodeUsed error type for the new behavior.
2026-03-23 10:34:49 +00:00
kolaente
de58f630ee test: add TOTP fixture and load it in user test bootstrap
Add a TOTP fixture for user1 with a known secret to enable
testing TOTP validation logic. Update InitTests to load the
totp fixture alongside users and user_tokens.
2026-03-23 10:34:49 +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
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
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
54c7c4aef2 refactor: move ListUsers tests from pkg/user to pkg/models
The ListUsers function now references team_members and teams tables
via a subquery for external team discoverability. The pkg/user test
environment only syncs user tables, so these tests need to run in
pkg/models which has the full schema and all fixtures.

Also adds new tests for the external team discoverability bypass
directly in the models package alongside the moved tests.
2026-03-04 20:32:11 +01:00
kolaente
28b913f29f feat: bypass discoverability settings for external team members 2026-03-04 20:32:11 +01:00
kolaente
3dd2ba4aa4 feat: register Vikunja tables with db package at init 2026-03-04 15:37:54 +01:00
kolaente
1f363dbd43 fix(events): defer event dispatch for user creation and task positions
Refs #2315
2026-03-03 12:46:34 +01:00
kolaente
39acdac531 fix(caldav): eliminate nested db session in CalDAV auth
checkUserCaldavTokens called user.GetCaldavTokens which creates its own
db.NewSession(), while the caller (BasicAuth) already holds an open
session. With SQLite this caused a deadlock because the second session
blocks on the write lock held by the first session in the same goroutine.

Add GetCaldavTokensWithSession that accepts an existing session and use
it from checkUserCaldavTokens.
2026-03-03 10:41:19 +01:00
kolaente
412215ee2f fix(auth): correctly delete older password reset tokens in cron 2026-02-27 14:44:26 +01:00
kolaente
5c2195f9fc fix(auth): remove password reset token after use 2026-02-27 14:44:26 +01:00
kolaente
89c17d3b23 feat(api): enforce password validation on reset and update flows
Add bcrypt_password validation to password reset and update endpoints:
- Add validation tag to PasswordReset.NewPassword struct field
- Add validation tag to UserPassword.NewPassword struct field
- Add c.Validate() calls in both handlers
- Fix off-by-one error in bcrypt_password validator (use <= 72 not < 72)

Password requirements: min 8 chars, max 72 bytes (bcrypt limit)
2026-02-25 13:44:56 +01:00
kolaente
2f680d041c fix: address review comments on session lifecycle
- user_export.go: Remove defer s.Close() from checkExportRequest since
  it returns the session to callers. Callers now own the session
  lifecycle with their own defer s.Close(). Close session on all error
  paths within checkExportRequest.

- user_delete.go: Close the read session immediately after Find() before
  the per-user deletion loop, avoiding a long-lived transaction holding
  locks unnecessarily.

- user/delete.go: Remove double s.Close() in notifyUsersScheduledForDeletion
  by closing immediately after Find() instead of using both defer and
  explicit close.

- caldav_token.go: Return nil token on Commit() error to prevent callers
  from using an unpersisted token.
2026-02-25 11:03:02 +01:00
kolaente
eea59c33c7 fix: isolate deletion notifications into per-user transactions
On Postgres, a failed operation puts the transaction in an error state
where subsequent operations fail. The previous loop with continue would
keep trying to use a broken transaction. Each user now gets its own
transaction so a single notification failure doesn't affect others.
2026-02-25 11:03:02 +01:00
kolaente
49bba7f830 fix: eliminate nested database sessions to prevent table locks
Refactor functions that created their own sessions when called from
within existing transactions, which caused "database table is locked"
errors in SQLite's shared-cache mode.

Changes:
- Add files.CreateWithSession() to reuse caller's session
- Refactor DeleteBackgroundFileIfExists() to accept session parameter
- Add variadic session parameter to notifications.Notify() and
  Notifiable.ShouldNotify() interface
- Update all Notify callers (~17 sites) to pass their session through
- Use files.CreateWithSession in SaveBackgroundFile and NewAttachment
- Fix test code to commit sessions before assertions
2026-02-25 11:03:02 +01:00
kolaente
c9c250fb1c fix: add missing Commit() to write callers
After NewSession() auto-begins a transaction, callers that perform
writes must explicitly call Commit() for changes to persist. Without
this, writes are silently rolled back when Close() is called.

Affected callers:
- user deletion notification cron
- caldav token generation/deletion
- token cleanup cron
- mark-all-notifications-read endpoint
- saved filter view cron
- project background delete
- typesense reindex
- export cleanup cron
- task last-updated listener
- saved filter view listener
- SSO team cleanup cron
- migration status start/finish
- background set/remove handlers
- orphaned task position cleanup
- file creation
2026-02-25 11:03:02 +01:00
kolaente
8ee069a2a3 feat: add session-based auth with refresh token rotation
- Login creates a server-side session and sets an HttpOnly refresh
  token cookie alongside the short-lived JWT
- POST /user/token/refresh exchanges the cookie for a new JWT and
  rotates the refresh token atomically
- POST /user/logout destroys the session and clears the cookie
- POST /user/token restricted to link share tokens only
- Session list (GET) and delete (DELETE) routes for /user/sessions
- All user sessions invalidated on password change and reset
- CORS configured to allow credentials for cross-origin cookies
- JWT 401 responses use structured error code 11 for client detection
- Refresh token cookie name constants annotated for gosec G101
2026-02-25 10:30:25 +01:00
kolaente
e90cb2631d fix(auth): remove unnecessary fields from JWT token payloads
Remove email, name, emailRemindersEnabled, and isLocalUser from user JWT
claims, and isLocalUser from link share JWT claims. These fields are never
used from the token - the backend always fetches the full user from the
database by ID, and the frontend fetches user data from the /user API
endpoint immediately after login.

Also simplify GetUserFromClaims to only extract id and username, and
remove the now-unnecessary email override in the frontend's
refreshUserInfo.
2026-02-08 21:30:07 +01:00
renovate[bot]
9a61453e86 fix(deps): update module github.com/labstack/echo/v4 to v5 (#2131)
Closes https://github.com/go-vikunja/vikunja/pull/2133

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: kolaente <k@knt.li>
2026-01-24 20:38:32 +01:00
Weijie Zhao
4fe0763010 fix: properly quote email sender names containing @ symbols (#1768)
When user names contain @ symbols, the email library fails to parse
the sender address format "Name @ Symbol via Vikunja <email@domain.com>".
This fix uses Go's net/mail.Address to properly format the sender
address according to RFC 5322, which automatically quotes names
containing special characters.

Fixes the error: "getting sender address: no FROM address set"
2025-11-07 11:44:24 +01:00
Panagiotis Papadopoulos
f83bd60915 fix: 403 http error code on failed login (#1756) 2025-11-06 08:40:46 +01:00
Dominik Pschenitschni
feb17792e4 fix(user): persist status on email updates (#1084) 2025-08-04 14:07:00 +00:00
kolaente
da0f6fb366 feat(auth): allow passing custom settings links to user account via openid claims 2025-08-03 13:25:32 +02:00
kolaente
9acba7a245 refactor: schedule user deletion 2025-08-01 17:06:02 +02:00
kolaente
4faf50a91f fix(user): ensure deletion tokens can only be used by the user who created them 2025-07-23 11:18:37 +02:00
kolaente
ca83ad1f98 feat: move to slog for logging 2025-07-21 18:15:39 +02:00
kolaente
42534cdd79 fix: don't panic when using api token when not correctly put into context (#1119) 2025-07-15 21:26:28 +00:00
Weijie Zhao
a214d68a44 feat(auth): sync avatar from OpenID providers (#821) 2025-06-16 15:59:31 +02:00
kolaente
59a0b9c40d feat(auth): require auth to fetch avatars (#930) 2025-06-14 13:12:41 +00:00
Dominik Pschenitschni
296577a875 fix: correct license header references (#882)
See originals:
- https://www.gnu.org/licenses/agpl-3.0.txt
- https://www.gnu.org/licenses/gpl-3.0.txt
2025-06-10 12:18:38 +02:00
Dominik Pschenitschni
8632bd2063 fix: TOTP account lock notification typo (#858) 2025-06-05 16:24:41 +02:00
kolaente
13d4e0e00d chore(utils): remove deprecated MakeRandomString function 2025-03-24 16:52:46 +01:00
kolaente
e3f006c527 fix(i18n): add missing translations 2025-03-20 17:41:45 +01:00
kolaente
5a93379d81 fix(ldap): update user name and email during login 2025-03-20 17:24:00 +01:00
kolaente
e12ebfebed feat(ldap): sync avatar from ldap 2025-03-18 18:28:54 +01:00