101 Commits
Author SHA1 Message Date
Daniel Hiller b581a97c2c feat: Show how many cards a list holds
A board level switch, off by default. With it on, each list puts its card
count on the add-card button. Useful to a board that is being kept to a size
and noise to one that is not, which is why it is a choice rather than always
on.

The count is every card in the list, not the ones a filter leaves visible.
Those answer different questions: how full is this list, versus how many match
what I am looking at right now. The first is the one a counter is for, and it
is also what the same switch counts in Pro, so a board keeps its meaning
across an upgrade.

The column matches Pro's name, type and default, so the setting survives that
upgrade rather than being dropped on the way.
2026-09-17 03:51:40 +02:00
Daniel Hiller 3edce1cc04 fix: Date the webhook scope migration after the one before it
The file came in named 20260502000000, which sorts ahead of the TOTP attempt
limit from August. Knex records migrations in the order it runs them, so the
last row in the table is not the same on every instance: a fresh install runs
both in name order and ends on the August one, while an instance that already
had it runs only this one and ends here.

Pro reads that last row to recognise which Community version it is upgrading
from, and it can only carry one name per version. Renaming to a timestamp
after the August migration makes the last row the same everywhere.

The rename is safe while this is only a few commits old on master and in no
tag. Anyone who pulled in that window and already ran it would see knex offer
it a second time.
2026-09-17 02:38:56 +02:00
Daniel Hiller 35f14b479c Merge pull request #1650 from symonbaikov/feature/webhook-scope-filter
feat: filter webhooks per project, board, and account
2026-09-17 02:00:30 +02:00
Daniel Hiller 8236cde954 fix: Keep the seed from refusing to start an instance that already ran
The validation added with the admin user checks reached further than intended.
The seed runs on every container start, not only on the first, and it threw on
three conditions that are normal on a second start.

The worst was the check for an existing user: after the first start the
default admin exists by definition, so every restart after that ended in a
container that would not come up. The insert is wrapped in a try and falls
back to an update precisely because it is meant to run again, and that path
was never reached.

The other two were narrower but the same shape. `validator.isEmail` rejects
`admin@localhost`, which is a common value in self-hosted setups, so an
instance that had been running for a year would stop coming up after the
upgrade.

None of it throws now. Bad input is reported on stderr and skipped, the way
an invalid username already was, and a username that belongs to someone else
is left alone rather than taken. `db:create-admin-user` keeps the strict
validation, which is where a person is there to read it and type again.
2026-09-17 00:48:08 +02:00
Daniel Hiller caa3f720e9 Merge pull request #1723 from AymanAlSuleihi/fix/create-admin-user-seed-validation
fix: Create admin user seed validation
2026-09-17 00:44:37 +02:00
Daniel Hiller de4d768831 fix: close the gaps a security review found in the default install
Reported against 2.2.1 by someone reading the source. Every finding held.

**Sign-in had no ceiling.** Failures were logged with the caller's address
and nothing more. Two counters now — one per address, one per account —
because the two attacks look different: one source working through many
accounts is caught by the first, many sources working on one account by the
second, and behind a proxy only the second still means anything.

The count is kept in the process that serves the request. PLANKA needs no
Redis and the stock deployment is one container; run several and each keeps
its own count, which multiplies the ceiling by their number. That trade is
written where the limits are configured.

**The second factor could be guessed at leisure.** Six digits, and a
pending token that stayed valid for its full ten minutes however many codes
were wrong. Wrong codes are now counted on the session row — in the
database, so the count survives a restart and holds across every process —
and when the budget is spent the session is destroyed. After that even the
right code is refused and the login starts over from the password.

**Avatars, background images and favicons** checked the token's signature
and nothing else, so a revoked session, a deactivated account or a changed
password all kept working there for as long as the signature lasted, which
is a year by default. The five checks the API makes now live in one helper
that both use, rather than the shortened copy that had drifted from it.

**A link attachment's favicon** was fetched from wherever the URL pointed.
Storing a link is harmless — it is a string the user typed — but fetching
its icon is a request the server makes to an address the user chose, and
whether an icon came back reported on what is reachable from inside the
network. Server-side fetches now refuse private, loopback and link-local
addresses, `169.254.169.254` among them. The attachment is still created:
linking to an internal wiki is a legitimate thing to do, and it was the
server's own request that had to stop.

**The signing key.** Our own compose file ships `notsecretkey`, and it is
printed in the documentation — so on any instance that copied it, anyone can
sign a token for any account. PLANKA now says so on every start, and keeps
saying it, along with a key that is missing or shorter than 32 characters.
The placeholder carries the warning inline, where it is copied from.

**The backup script** wrote password hashes, live sessions, TOTP secrets and
SMTP credentials to an unencrypted archive. `BACKUP_PASSPHRASE` now encrypts
it, and without one the script says what it just put on disk. It also says
what it is — an example for the stock compose stack, not a backup concept —
and names the window between the database dump and the file copy, which no
ordering closes.
2026-08-28 20:55:54 +02:00
Daniel Hiller d7da44efe4 feat: Add script to clean orphaned reference records
Instances that accumulated project managers, favorites, board memberships
or board subscriptions pointing at a project or board that no longer exists
had no way to find or clear them.

The script reports by default and only deletes with `--apply`, which first
asks whether a backup exists and refuses outright without a terminal to ask
on. It removes nothing but reference rows: structural orphans such as a
board without a project carry user content, and a membership whose
denormalized project is stale still grants real access to an existing
board, so both are reported and left alone.
2026-08-26 09:31:18 +02:00
Daniel Hiller 3ef87a8603 feat: Add configurable auto logout on inactivity
Users can pick an inactivity timeout in their preferences. A warning
appears 30 seconds before, and activity or a logout is synchronised
across open tabs.
2026-08-08 00:24:16 +02:00
Daniel Hiller 2e4904f77d feat: Add two-factor authentication via TOTP
Adds TOTP setup with QR code, login challenge, recovery codes and
trusted devices that let a browser skip the second factor for 30
days. Admins can reset another user's second factor by confirming
with their own password.
2026-08-07 20:11:55 +02:00
Daniel Hiller 36aa732fec feat: Remove OIDC and SSO support
Existing SSO accounts have no local password, so the migration
deactivates them before dropping is_sso_user and the
identity_provider_user table.
2026-08-07 19:15:43 +02:00
Ayman c587a1441d fix: Add password validation for admin user seeding process 2026-07-08 08:05:00 +01:00
Ayman aeb3456091 refactor: Replace while true with flag based validation 2026-07-08 07:42:04 +01:00
Ayman 2f5252faad fix: Add email uniqueness check to admin user seeding process 2026-07-08 07:17:39 +01:00
Ayman 7fbc2ea737 fix: Add username uniqueness check to admin user seeding 2026-07-08 07:17:32 +01:00
Ayman 0a2641db84 fix: Add email validation to admin user seeding process 2026-07-08 07:17:26 +01:00
Ayman 062cc3c347 fix: Add name length validation to admin user seeding process 2026-07-08 07:17:14 +01:00
Ayman 1d523cdab5 fix: Add username validation to admin user seeding process 2026-07-08 07:17:05 +01:00
Symon 05979a460f feat: filter webhooks per project, board, and account
Adds optional project, board, and acting-user scope to each webhook so
events from a specific board or project can be routed to a single
endpoint without an external automation tool in the middle (closes
#1457).

A webhook now fires for an event only when every set scope matches:
empty scope still means "fire for everything", keeping existing
webhooks working unchanged. Scope filtering is centralized in the
sendWebhooks helper, which auto-derives projectId/boardId from the
event payload, so existing call sites are untouched.
2026-05-02 10:31:30 +03:00
Maksim Eltyshev c342d2edd7 feat: Add ability to display card ages 2026-03-18 09:42:20 +01:00
Maksim Eltyshev b2e3aac314 chore: Upgrade data structure only if S3 is enabled 2026-02-10 18:52:25 +01:00
Maksim Eltyshev 8c4859fed5 chore: Sync upgrade script with latest changes 2026-02-10 18:34:26 +01:00
Maksim Eltyshev 450bd875c1 chore: Update server dependencies 2026-02-04 12:53:15 +01:00
Maksim Eltyshev 052edc9fb1 feat: Migrate file storage to unified data directory 2026-01-31 20:27:15 +01:00
Maksim Eltyshev ffdb7254b3 fix: Enable favorites by default 2026-01-25 18:37:56 +01:00
Maksim Eltyshev b2c4c530c6 fix: Fix variable name in seeder 2026-01-23 11:42:40 +01:00
Maksim Eltyshev 1264fd5715 feat: Add internal runtime configuration 2026-01-22 18:02:42 +01:00
Maksim Eltyshev a60f8e3c3e chore: Rename for consistency 2026-01-13 17:52:31 +01:00
Maksim Eltyshev 4f5f5ddad4 feat: Display last updates in About modal 2025-12-17 15:49:33 +01:00
Maksim Eltyshev c058df8fc4 fix: Rename GIN indexes 2025-11-27 19:31:11 +01:00
Samuel b4cbd32bf2 feat: Add API key authentication (#1254)
Closes #945
2025-11-06 20:56:48 +01:00
Maksim Eltyshev c6f4dcdb70 feat: Add ability to configure and test SMTP via UI 2025-09-22 20:35:13 +02:00
Maksim Eltyshev 984b789e2e feat: Add board setting to expand task lists by default
Closes #683, closes #1333
2025-09-05 23:21:08 +02:00
Steven Correia 37bd4d1349 feat: Restore toggleable due dates (#1332) 2025-09-05 13:55:20 +02:00
Maksim Eltyshev 4d77a1f596 feat: Track storage usage 2025-08-23 00:03:20 +02:00
Maksim Eltyshev 2f4bcb0583 feat: Add legal requirements (#1306) 2025-08-21 15:10:02 +02:00
Maksim Eltyshev 48e261ffc4 fix: Improve upgrade script, log statuses
Closes #1280
2025-08-04 20:51:40 +02:00
Symon Baikov d8fbf2f909 feat: Add ability to hide completed tasks (#1210) 2025-07-21 18:33:02 +02:00
Maksim Eltyshev 230f50e3d9 feat: Add ability to link tasks to cards 2025-07-11 01:04:02 +02:00
Maksim Eltyshev 709a0d1758 feat: Persist closed state per card 2025-07-09 17:45:47 +02:00
Maksim Eltyshev b22dba0d11 feat: Move webhooks configuration from environment variable to UI 2025-07-04 22:04:11 +02:00
Maksim Eltyshev 46f4d5c1f8 fix: Canonicalize locale codes 2025-06-03 12:46:06 +02:00
Hannes 4049b4c396 feat: Display comments total on front of cards (#1146)
Closes #1136
2025-05-23 17:31:28 +02:00
Maksim Eltyshev 86cfd155f2 feat: Add board activity log 2025-05-22 23:14:46 +02:00
Maksim Eltyshev 777ff467f3 fix: Prevent upgrade script from running other migrations 2025-05-22 16:40:46 +02:00
Maksim Eltyshev 652c5e9475 fix: Use batch inserts to avoid query size limits 2025-05-19 17:27:18 +02:00
Maksim Eltyshev 2ee1166747 feat: Version 2
Closes #627, closes #1047
2025-05-10 02:09:06 +02:00
Lukas Corona 4821d407a7 feat: Ability to set list color indicator (#1033)
Closes #840
2025-02-25 15:58:59 +01:00
Maksim Eltyshev 97f4c0ab0d fix: Secure S3 attachments, bump SDK, refactoring
Closes #673
2024-11-12 15:58:22 +01:00
Nguyễn Hải Quang f20a3d50f5 feat: Add S3 support for uploads (#938) 2024-11-11 14:59:18 +01:00
Maksim Eltyshev 50519f1bcd feat: Additional httpOnly token for enhanced security in browsers 2024-09-01 09:31:04 +02:00