Commit Graph
180 Commits
Author SHA1 Message Date
kolaente f77a1f9ea0 feat: add basic auth config for health endpoints 2026-11-03 09:12:02 +01:00
kolaente d21a67cdfe feat(config): add keyed legal links and deprecate imprinturl/privacyurl
legal.<link key>.text and legal.<link key>.url define any number of legal
links, configured the same way as OpenID providers, so env vars like
VIKUNJA_LEGAL_FOOBAR_TEXT work. legal.imprinturl and legal.privacyurl keep
working but log a deprecation warning.
2026-10-28 23:02:31 +01:00
kolaente 5aec8b21a7 fix(config): re-anchor database, log and plugin paths to the final rootpath 2026-10-20 15:13:02 +02:00
kolaente bf8859bab3 fix(migration): cap the number of items one import may create 2026-10-20 15:13:02 +02:00
kolaenteandTink 33bd1c9afe feat(ldap): match users and groups by an immutable directory id
Add auth.ldap.attribute.id. When set (e.g. objectGUID on AD, entryUUID
on OpenLDAP), users and teams are matched by that attribute instead of
the login name and the group DN, so renaming or moving them in the
directory no longer creates duplicate accounts or new teams without the
old shares.

AD's binary objectGUID is formatted as a canonical GUID string; other
attributes must be printable text. Existing accounts and teams are
switched to the new id on the next login. An empty option keeps the old
behaviour.
2026-10-19 13:42:19 +02:00
Mohd Quamar TyagiandGitHub 9dffe78277 fix(user): fallback empty user timezone to valid UTC location (#3965) (#3991) 2026-09-30 21:26:06 +00:00
kolaente dddaf71600 refactor(config): drop the no-op empty license.key default 2026-09-30 20:45:07 +02:00
kolaente 3f547976f8 fix(config): migrate deprecated webhooks.* keys after loading the config
The migration to outgoingrequests.* ran while setting defaults, before
the config file and environment were read, so it only ever saw default
values. webhooks.proxyurl, webhooks.proxypassword and
webhooks.allownonroutableips have been ignored since they were
deprecated.
2026-09-30 20:45:07 +02:00
kolaenteandTink 68ac9eaa99 fix(migration): judge an abandoned claim by a heartbeat, not by start time
The claim timeout was measured from started_at, so a long import either
kept a dead claim for a day (the old 24h default) or had its slot taken
over while still running. A running migration now refreshes heartbeat_at
at a tenth of the timeout, clamped to 1s..30s, and a claim only counts as
stale once its last beat is older than the timeout. Rows that never beat
fall back to started_at. The default timeout drops to 5m accordingly.

Also bind the stale cutoff in the configured timezone: xorm writes times in
the engine's zone but binds query args as-is, which broke the comparison on
SQLite.
2026-09-15 16:59:37 +02:00
kolaente 6b0797e471 feat(config): default per-category log levels to log.level
databaselevel, httplevel, eventslevel and maillevel now inherit
log.level unless set explicitly. databaselevel previously defaulted
to WARNING and now follows log.level (INFO by default).
2026-09-06 21:35:20 +02:00
kolaente 1bce3df923 feat(log): add log.httplevel and log requests by status
The http request logger had a hardcoded DEBUG level, so every request
was emitted at INFO with no way to filter it short of turning the http
log off entirely. Add log.httplevel like the other categories and log
requests by status: INFO for success, WARNING for 4xx, ERROR for 5xx.

Resolves #3781
2026-09-06 21:35:20 +02:00
kolaente 6c959c995d feat(metrics): optional Go profiler endpoint at /debug/pprof
Vikunja's release binary is stripped and the image has no shell, so nothing
on the API side can be profiled from the outside. metrics.pprof (default
false, requires metrics.enabled) mounts Go's pprof handlers at their
canonical path, behind the same basic auth as /metrics when username and
password are set. Explicit handlers instead of the net/http/pprof blank
import, which would register on http.DefaultServeMux unconditionally.
2026-09-06 16:36:51 +02:00
kolaente e8da5b7412 perf(db): default connection lifetime 30 min instead of 10 s
database.maxconnectionlifetime is in milliseconds, so the default of 10000
recycled every pooled connection after ten seconds. Under load that is a
reconnect storm (32 fresh backends every 10 s with a pool of 32) and, more
importantly, it throws away the per-connection prepared statement cache and
the backend's plan cache, so nearly every statement is parsed and planned
again. Measured with pgx on a 3000-user load test: planning time stayed at
0.8 ms per request, more than the execution time, because no prepared
statement outlived the connection.

Thirty minutes keeps connections fresh enough to follow a failover or DNS
change and long enough for the caches to pay off.
2026-09-06 09:43:40 +02:00
kolaente 7b4b6046ca fix(migration): bound vikunja file imports
Preflight over the declared uncompressed sizes (overflow-safe), a file
count cap and a per-user storage quota bound the import before
anything is read; the actual decompressed bytes are still counted
against the same budget while reading. Attachments and backgrounds
now stream through a lazy provider: one zip entry is decompressed
into a private temp file at a time. A failed import deletes the file
blobs it wrote, which were orphaned for every migrator before.
2026-08-31 18:37:03 +02:00
kolaente c41a04d811 fix(migration): cap csv rows while decoding 2026-08-31 18:37:03 +02:00
kolaente 7fafe3738b fix(routes): rate limit basic auth failures 2026-08-31 18:37:03 +02:00
kolaente 784f388252 fix(migration): serialize imports per user 2026-08-31 18:37:03 +02:00
kolaenteandTink f42d1a6ca9 test: stop leaking config overrides between tests
Capturing a config value before init returns "", and Key.Set writes at viper's
override level, which outranks defaults. Restoring a captured value therefore
pinned database.path to "" for the rest of the process, and TestRestore resolved
it to the bare rootpath and failed with "is a directory".

Only visible when VIKUNJA_TESTS_USE_CONFIG=1, which CI sets for every database
except sqlite-in-memory, which is why every test-api job failed while local runs
passed. ResetForTests restores genuine fresh-process state instead.
2026-08-29 20:27:06 +02:00
TinkandGitHub f299a11d7d feat(cmd): add --config flag to pin the config file (#3652) 2026-08-29 17:10:01 +02:00
kolaente 62f3e2f76b fix(ratelimit): give session renewal its own budget
The refresh-token and OAuth token endpoints shared the 10 requests/minute
floor that protects login, register and password reset. Access tokens live
for 10 minutes, so every client renews its session several times an hour --
and behind a reverse proxy `service.ipextractionmethod` defaults to `direct`,
which keys all of them to the proxy's address. Routine renewals therefore
used up the login budget, and users got "Too many requests" when signing in.
This hit the desktop app hardest: it exchanges its authorization code on the
very same endpoint it refreshes tokens on.

Renewal now has a separate limiter with its own `ratelimit.tokenrefreshlimit`
setting, defaulting to 60 requests/minute. Both limits stay enforced.
2026-08-18 14:01:06 +02:00
kolaenteandkolaente a59872be2f fix(config): apply deprecated service.jwtsecret to service.secret
service.secret had an unconditional random default, and viper's IsSet
reports defaults as set. The deprecation branch therefore always took the
"both keys are set" path and never copied service.jwtsecret over, so
instances configured with the old key silently got a fresh random secret
on every start — flaky 401s across replicas.

The random fallback is now generated after the config file and env are
read, so an empty service.secret unambiguously means "not configured".
2026-07-26 15:59:40 +00:00
maximilizeandGitHub 4f86f21316 fix(filters): resolve relative and absolute date filters in UTC (#3181) 🤖🤖🤖 (#3229) 2026-07-19 13:31:21 +02:00
kolaente dd82549f17 chore(config): disable icon changes by default
We have recieved feedback from enterprise users who found this to be very unprofessional not not worthy of enterprise software. Therefore, we made the difficult decision to disable icon changes by default. We're looking into adding more clues that transport the same message but are less obvious.
2026-07-15 12:19:41 +02:00
karl Einzigerandkolaente 0efae572cd fix(auth): use binddn as group sync dn instead of userbind 2026-06-27 15:12:10 +00:00
kolaenteandkolaente 95084087a5 feat(config): add audit logging config keys 2026-06-12 08:56:08 +00:00
Claudeandkolaente d9a5958bb8 feat: always enable bot users
Removes the `service.enablebotusers` config flag, the matching
`bot_users_enabled` field on /info, and the now-unused
`ErrBotUsersDisabled` error. Bot user routes and the frontend
settings tab are now always available.

https://claude.ai/code/session_01VhAR6xnoCdG1fpX52bzaCC
2026-05-04 10:38:53 +00:00
kolaenteandkolaente 4c3f0231e9 feat(config): add service.enablebotusers flag 2026-05-01 14:44:10 +00:00
kolaenteandkolaente 35f183979c feat: add license comments for agents and humans 2026-04-15 10:32:37 +00:00
kolaenteandkolaente ecc2243513 feat(config): add license.key configuration option
Add license key configuration under the license section. When empty or
absent, Vikunja runs in community mode with no licensed features.
2026-04-15 10:32:37 +00:00
Rhys McNeillandkolaente 699c766049 fix: add timeouts to Gravatar, Unsplash, and SSRF-safe HTTP clients 2026-04-09 07:31:08 +00:00
kolaenteandkolaente 3db410933e feat(plugins): add plugin config options
Add configuration keys:
- plugins.enabled (default: false)
- plugins.dir (default: <rootpath>/plugins)
- plugins.loader (default: native, validated at startup)

Register yaegi loader via blank import in initialize package.
2026-03-30 20:44:46 +00:00
Jacek Galowiczandkolaente b2ddd2753c config: Expand environment variables in some.config.value.path.file inputs for better secret management 2026-03-30 14:22:39 +00:00
kolaenteandGitHub 83bac15841 feat: rename ServiceJWTSecret to ServiceSecret with deprecation (#2502) 2026-03-30 12:07:01 +02:00
kolaenteandkolaente f96b53fe99 feat: add outgoingrequests config keys for centralized SSRF protection 2026-03-23 16:34:22 +00:00
kolaenteandkolaente ddd9ef5f22 style: fix alignment in config key declarations 2026-03-20 11:08:00 +00:00
kolaenteandkolaente 26324a740a feat: add service.ipextractionmethod and service.trustedproxies config options 2026-03-20 11:08:00 +00:00
kolaente 37fdd088d6 feat(config): add webhooks.allownonroutableips setting 2026-03-19 15:18:06 +01:00
kolaente a043940e14 refactor: use config.ResolvePath for all rootpath-relative paths
Replaces ad-hoc path joining in files, config value loading, and
default config values with the centralized ResolvePath function.
2026-03-09 16:02:05 +01:00
kolaente 2a7165aaba refactor: add centralized ResolvePath for rootpath-relative paths 2026-03-09 16:02:05 +01:00
kolaente d3cbc4fc4f fix: prefer working directory for service.rootpath default
When running as a systemd service, the binary is often in /usr/local/bin
but WorkingDirectory points to a data directory like /var/lib/vikunja.
Previously, rootpath defaulted to the binary's directory, causing
Vikunja to attempt creating files/db in /usr/local/bin.

Now os.Getwd() is preferred, which respects systemd's WorkingDirectory
and is the intuitive default for all deployment scenarios.
2026-03-09 16:02:05 +01:00
TinkandGitHub 40bcf2b36f fix: validate default settings timezone on startup (#2345) 2026-03-03 12:16:37 +00:00
kolaente a5b1a90c42 refactor: remove typesense support
Typesense was an optional external search backend. This commit fully
removes the integration, leaving the database searcher as the only
search implementation.

Changes:
- Delete pkg/models/typesense.go (core integration)
- Delete pkg/cmd/index.go (CLI command for indexing)
- Simplify task search to always use database searcher
- Remove Typesense event listeners for task sync
- Remove TypesenseSync model registration
- Remove Typesense config keys and defaults
- Remove Typesense doctor health check
- Remove Typesense initialization from startup
- Clean up benchmark test
- Add migration to drop typesense_sync table
- Remove golangci-lint suppression for typesense.go
- Remove typesense-go dependency
2026-02-25 12:15:28 +01:00
kolaente a6bdeb67b0 feat: add jwtttlshort config key for session tokens
Adds ServiceJWTTTLShort (default 600s) to control the lifetime of
short-lived JWTs issued during token refresh. The existing jwtttl
and jwtttllong keys remain for session expiry and long sessions.
2026-02-25 10:30:25 +01:00
kolaenteandGitHub b6974ffcfd feat: add UNSIGNED-PAYLOAD config option for S3-compatible stores (#2205)
Adds `files.s3.disablesigning` config option that sends
`UNSIGNED-PAYLOAD` instead of computing SHA256 hashes for S3 request
signing which fixes `XAmzContentSHA256Mismatch` errors with
S3-compatible providers like Ceph RadosGW and Clever Cloud Cellar

Resolves https://github.com/go-vikunja/vikunja/issues/2181
2026-02-08 15:03:19 +00:00
rhclaytoandGitHub c5969d9898 feat: add configurable gravatar-compatible base URL (#2083)
This adds the ability to set a base URL for a Gravatar-compatible avatar
service (Gravatar itself, or Libravatar, for instance). The default will
be www.gravatar.com, so nothing will change from current behaviour unless
the user explicitly configures another URL.

Resolves #2082
2026-01-13 14:58:08 +01:00
kolaenteandGitHub 4afd223cd3 fix(files): upload should work with vhost style (#1994)
resolves https://github.com/go-vikunja/vikunja/issues/1905
2025-12-16 20:32:15 +00:00
kolaente dcfd096588 feat: allow setting dark custom logo
Resolves https://github.com/go-vikunja/vikunja/issues/1799
2025-11-12 21:07:01 +01:00
Weijie ZhaoandGitHub bc1368abcc feat: add S3 file storage support (#1688) 2025-11-06 08:37:04 +01:00
kolaenteandGitHub ec89b08fd5 fix(attachments): extend upload file size to form data (#1577)
Resolves https://github.com/go-vikunja/vikunja/issues/1494
2025-09-30 22:23:07 +00:00
kolaenteandGitHub e29561e49c fix: require publicurl when cors enabled (#1351) 2025-08-29 20:51:31 +00:00