167 Commits

Author SHA1 Message Date
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
kolaente
c6cade3aeb feat(i18n): automatically set language during registration 2025-03-02 13:21:24 +01:00
kolaente
250bb8ec99 fix(i18n): pass language to notification mail function 2025-03-02 12:29:31 +01:00
kolaente
e11a3026b9 feat: translate notifications 2025-03-02 11:41:38 +01:00
kolaente
65df9e5ef9 fix: return meaningful error message when selecting an invalid timezone 2025-02-21 17:20:51 +01:00
kolaente
38bb8de4f1 feat(auth): authenticate users via ldap 2025-01-28 09:59:08 +00:00
kolaente
88761db2b1 fix(auth): check for existence of field before casting
Resolves https://vikunja.sentry.io/share/issue/6a21a679011a40b290ac531dd96c2adc/
2025-01-22 09:45:14 +01:00
kolaente
2522cffa61 fix(auth): return proper error when a jwt claim contains wrong data
Resolves https://vikunja.sentry.io/share/issue/69b578ccc3794de58cecfc7b8291ae64/
2025-01-14 16:38:49 +01:00
kolaente
33b9917c7d fix(auth): return correct error when trying to do a user action as a link share
Resolves https://vikunja.sentry.io/share/issue/77f7aa4cda9442439deba3cfe2cb32c6/
2025-01-14 15:01:13 +01:00
kolaente
703a88e99f fix: lint 2024-12-17 10:53:18 +01:00
kolaente
4359819faf fix(auth): do not allow commas in usernames 2024-12-16 23:09:35 +01:00
kolaente
28a58303f0 fix(auth): convert to int when failed password value is not int
Resolves https://github.com/go-vikunja/vikunja/issues/377
2024-12-13 20:46:36 +01:00
kolaente
7055d7341c feat(sharing): add config so that users only find members of their teams
This adds a feature where you can enable users to only find members of teams they're part of. This makes the user search when sharing projects less confusing, because users only see other users they already know.
It is still possible to add users to teams with their email address, if they have that enabled in the user settings.
2024-10-28 11:08:06 +01:00