Commit Graph
1139 Commits
Author SHA1 Message Date
dependabot[bot] 73cabf9e30 build(deps-dev): Bump js-yaml from 3.15.1 to 3.15.2 in /client
Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 3.15.1 to 3.15.2.
- [Changelog](https://github.com/nodeca/js-yaml/blob/3.15.2/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/3.15.1...3.15.2)

---
updated-dependencies:
- dependency-name: js-yaml
  dependency-version: 3.15.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-09-13 05:00:35 +00:00
Daniel Hiller 26b512193a chore: Translate the strings missing from every locale
Thirty-three locales were short the same sixty-six keys and had been since
2.2.1. Fifty-six of them are the two-factor setup and the auto-logout
preference; six are the two-factor challenge itself; the rest are the promo
strings the banner rotates through.

The six in `login.js` were the urgent ones. They render during sign-in, before
`core.js` is fetched, so a user with two-factor enabled met the whole challenge
in English — on the one screen they cannot get past without understanding it.
Three of those six exist in `core.js` as well and now read identically in both
files, which nothing checks and which two translators working from two files
would otherwise have got subtly different.

Plural forms follow each language rather than the English pair: Arabic carries
all six CLDR categories with the agreement its counting requires, Czech,
Polish, Russian, Slovak and Ukrainian four with the right case in each, and
Chinese, Japanese, Korean, Vietnamese and Indonesian only `other`, since a
`_one` variant would be a form i18next never reads.

Every file is additions only — no existing line was moved, reworded or
reformatted, so the diff shows what was missing and nothing else. Several
existing mistranslations turned up along the way and were left alone; they are
a separate concern from filling the gaps.
2026-09-08 19:54:41 +02:00
Daniel Hiller 9069b24cfb chore: Add a locale completeness check
An incomplete locale falls back to English at runtime, so a gap breaks nothing
and nobody notices it on their own. 2.2.1 shipped fifty-six user-facing strings
that existed only in English and German, and it took someone looking for
something else to find them. `npm run client:locales:check` compares every
locale against the reference and exits non-zero when one is behind.

It compares `login.js` and `core.js` separately and never merges them.
`login.js` is the embedded bundle and is all that exists until a session is
established, so a key present only in `core.js` is still missing from every
screen shown before login — the two-factor challenge among them. Merging the
two hides exactly that, which is how the six strings of the challenge stayed
English in thirty-three languages.

Keys are compared on their base name, with the CLDR plural category stripped,
because how many categories a language needs is a property of that language:
English has two, Japanese one, Arabic six. Comparing the suffixed names would
have demanded an English `_one` from Japanese, where i18next never reads it.
Each plural key is then checked against the categories the language itself
declares, through the same Intl.PluralRules that i18next resolves with — a
missing category falls back to `_other` silently, and Russian `few` and `many`
are reachable with counts a user really sees.

It is deliberately not part of `lint`: a pull request that adds a string is
expected to leave the other locales behind for a while, and a check that fails
every such request would only be switched off. This one belongs before a
release.
2026-09-08 19:54:27 +02:00
Daniel Hiller 76d3911d03 docs: Add a PLANKA Pro section to the README
Pro funds the Community edition, but the README mentioned it only in a single
line under How to Deploy. The new section sits between the demo and the key
features: what Pro adds, two buttons, four screenshots from 2.5.0, a
Community-versus-Pro table, and what an upgrade involves.

Every row of that table was checked against both codebases rather than taken
from the comparison matrix on the website, which carries cells that are
demonstrably wrong. The dangerous error is denying Community something it has,
because the reader has the opposite in front of them in their own instance —
so the stopwatch, webhooks, the REST API, custom fields, two-factor and the
notification providers are all marked as shared, and only what the code
actually gates is marked Pro. Where a claim could not be backed by the source
it was left out.

The upgrade paragraph names the releases the promote accepts as a snapshot
rather than as a standing fact, and points at the guide for the current list.
A hard-coded version window in the README of the repository whose version
keeps moving is wrong the moment the next minor ships, and nobody would
remember it was there.

The screenshots are referenced through raw.githubusercontent.com, so they
appear once this is pushed, the same way the logo and the demo already do.
2026-09-08 19:54:18 +02:00
Daniel Hiller 4e15748e4b feat: Widen the Pro banner rotation and split it by role
The banner still advertised the calendar, recurring cards and guest roles —
features from 2.3 — to everyone who ran an instance. It now carries nine
features up to 2.5.0, and the ten strings behind them sit in their
alphabetical place rather than in the middle of the two-factor block, where
the first three had ended up.

Who sees what now depends on the role. An admin can put a trial on their own
server today and a board user cannot, so admins get the trial line and land
on planka.app/trial while everyone else gets the overview on /pro. The
landing path is also what tells the two groups apart in the referral figures,
since nothing is measured in the app.

A full pass through nine features takes over two minutes, longer than most
visits, and the rotation restarted at the first entry on every load. The tail
of the list would have advertised nothing. The list now starts at an offset
picked per visit, which spreads the features over the visitors instead of over
the length of a session — the headline still opens every session, only the
feature that follows it varies.

The headline falls back per language. `proTrialSelfHosted` is new and exists
in two locales; `discoverPlankaPro` exists in all of them. Where the sharper
line is untranslated the softer one is used rather than a line of English, on
the one string that opens every session and fills every second slot. The link
still goes to the trial, and as translations land the check flips on its own.

The thirty-day dismissal is untouched, deliberately: any version-aware
dismissal would resurface the banner for every user at once on rollout,
because the entries already in local storage carry no version.
2026-09-08 19:54:07 +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 6def0330c2 chore: Move the changelog to the repository root
The release notes rendered in the about modal only existed as an asset
inside the client, where nothing outside a build would look for them. The
file moves to CHANGELOG.md at the root and the about modal reads it from
there, so the client build and the Docker image copy in the same file the
repository keeps.

An unreleased section collects the orphaned reference fixes and the
pagination fixes.
2026-08-26 10:15:56 +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 2d289cd3d5 fix: Make endless list pagination deterministic
The filtered branch of `getByEndlessListId` applied `LIMIT` without an
`ORDER BY`, so Postgres was free to hand back any matching rows. With a
search over 64 cards the first page returned the oldest ones and a full
cursor walk reached 60 of them across 149 rows — cards both skipped and
repeated. The query now orders the way the cursor reads it.

The cursor itself is validated as ISO 8601, which admits forms Postgres
rejects as a timestamp (`2026`, `2026-W35-3`, a comma as the decimal
separator), each of them a 500 from the adapter. It is normalized before
the query, and stays a string because the equality half of the cursor
reads a `Date` as an empty constraint.
2026-08-26 09:23:01 +02:00
Daniel Hiller 4add7e43af fix: Keep dangling project references from blanking the home view
`getManagerProjectsModelArray` mapped every project manager to its project
without checking that the project is in the store, so one row pointing at a
deleted project produced a null the caller then read `id` off — taking down
the whole home view. `getMembershipProjectsModelArray` had the same hole one
level up, destructuring `board.project` before testing `board`.

The projects endpoint fed exactly that state: it derived the id list for the
included records from the manager rows, so a `project_manager` row whose
project no longer exists shipped a manager for a project missing from `items`.
Board memberships had the same gap. Both id lists now come from the records
that actually exist.
2026-08-26 09:22:53 +02:00
Daniel Hiller 266246e242 chore: Update version 2026-08-10 18:28:48 +02:00
Daniel Hiller bd487e3f9f fix: Prevent path traversal in local file manager
The local file manager joined attacker-controlled path segments into the
uploads storage path without ensuring the result stayed under the uploads
root. Any authenticated user could read arbitrary files readable by the
Planka process (e.g. /etc/passwd, /app/.env) via `../` sequences on the
/user-avatars/*, /background-images/* and /favicons/* routes (CWE-22).

Resolve the path and enforce it stays within uploadsBasePath, centrally in
buildPath so every local file operation is covered. Additionally resolve
symlinks in read() and re-check containment, so a symlink inside the root
cannot be used to escape it.

Reported by Alpesh (github.com/Alpastx).
2026-08-10 03:00:29 +02:00
Daniel Hiller 2684198bf8 chore: Update version 2026-08-09 22:36:27 +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 a9d0c228df feat: Replace user edit popups with a single modal
Editing a user now opens a modal with an information tab and an API
key tab instead of a chain of popups. The user name in the list opens
it, and the admin two-factor reset moves in as well.
2026-08-08 00:16:35 +02:00
Daniel Hiller a6f6af8a6c fix: Replace Pro theme tokens with literal colors
The two-factor stylesheets were carried over from the Pro edition and
referenced CSS custom properties from its theme system, which this
edition does not define. They silently fell back to browser defaults.
2026-08-08 00:15:34 +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
Daniel Hiller a1f0a2b3fa chore: Update dependencies 2026-08-07 16:45:51 +02:00
Daniel Hiller ebb9d6879e ci: Align workflows with Node 24 2026-08-07 16:36:02 +02:00
Daniel Hiller 3a9eea3020 ci: Drop armv7 from Docker image builds 2026-08-07 16:30:19 +02:00
Daniel Hiller bec5dd1597 chore: Update dependencies
Bump Node to 24 in Dockerfile and Dockerfile.dev.
Bump sharp to 0.35, nodemailer to 9 and concurrently to 10.
Add overrides for body-parser, qs, multiparty, uuid, diff,
serialize-javascript, linkify-it and svgo to pull in security fixes
that upstream pins block.
Rename the sails patch to match 1.5.18.
2026-08-07 16:17:24 +02:00
Daniel Hiller 856768c45e Merge pull request #1670 from plankanban/dependabot/npm_and_yarn/client/tmp-0.2.7
build(deps): Bump tmp from 0.2.5 to 0.2.7 in /client
2026-06-03 16:10:18 +02:00
Daniel Hiller 93f504e412 Merge pull request #1672 from plankanban/dependabot/npm_and_yarn/server/multi-8c9a216550
build(deps): Bump ws, engine.io and socket.io-adapter in /server
2026-06-03 16:09:32 +02:00
dependabot[bot] 8940a1dfa6 build(deps): Bump ws, engine.io and socket.io-adapter in /server
Bumps [ws](https://github.com/websockets/ws), [engine.io](https://github.com/socketio/socket.io) and [socket.io-adapter](https://github.com/socketio/socket.io). These dependencies needed to be updated together.

Updates `ws` from 8.18.3 to 8.20.1
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/8.18.3...8.20.1)

Updates `engine.io` from 6.6.6 to 6.6.8
- [Release notes](https://github.com/socketio/socket.io/releases)
- [Changelog](https://github.com/socketio/socket.io/blob/main/CHANGELOG.md)
- [Commits](https://github.com/socketio/socket.io/compare/engine.io@6.6.6...engine.io@6.6.8)

Updates `socket.io-adapter` from 2.5.6 to 2.5.7
- [Release notes](https://github.com/socketio/socket.io/releases)
- [Changelog](https://github.com/socketio/socket.io/blob/main/CHANGELOG.md)
- [Commits](https://github.com/socketio/socket.io/compare/socket.io-adapter@2.5.6...socket.io-adapter@2.5.7)

---
updated-dependencies:
- dependency-name: ws
  dependency-version: 8.20.1
  dependency-type: indirect
- dependency-name: engine.io
  dependency-version: 6.6.8
  dependency-type: indirect
- dependency-name: socket.io-adapter
  dependency-version: 2.5.7
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-29 11:28:05 +00:00
dependabot[bot] 45119825f4 build(deps): Bump tmp from 0.2.5 to 0.2.7 in /client
Bumps [tmp](https://github.com/raszi/node-tmp) from 0.2.5 to 0.2.7.
- [Changelog](https://github.com/raszi/node-tmp/blob/master/CHANGELOG.md)
- [Commits](https://github.com/raszi/node-tmp/compare/v0.2.5...v0.2.7)

---
updated-dependencies:
- dependency-name: tmp
  dependency-version: 0.2.7
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-28 02:53:47 +00:00
Daniel Hiller a8dcd7cef3 chore: Remove global npm update step from build workflow 2026-04-18 15:23:53 +00:00
Daniel Hiller 6e2e6539d1 chore: Update what's new documentation 2026-04-18 15:19:56 +00:00
Daniel Hiller e429b478ca chore: Bump version to 2.1.1 and update release notes 2026-04-18 15:10:14 +00:00
Daniel Hiller 0e5dedd627 Merge pull request #1638 from plankanban/dependabot/npm_and_yarn/server/multi-e6e4b50ff7
build(deps): Bump underscore and @sailshq/nedb in /server
2026-04-18 16:23:01 +02:00
Daniel Hiller eb90b12b0e Merge pull request #1637 from plankanban/dependabot/npm_and_yarn/server/multi-c857c64966
build(deps): Bump path-to-regexp and @sailshq/router in /server
2026-04-18 16:22:59 +02:00
Daniel Hiller cd9ba8ff4f feat: Add Pro features discovery banner
Adds a dismissible banner in the topbar that informs users about
PLANKA Pro features.

- Dismissible per-user (stored in localStorage)
- Reappears after 30 days
- Rotates between main message and 3 feature highlights
- Links to planka.app/pro (with ref parameter for anonymous source attribution)
2026-04-18 13:32:22 +00:00
Daniel Hiller 4e23f3c8a9 refactor(docker): Remove global npm installation from Dockerfiles 2026-04-18 13:32:22 +00:00
dependabot[bot] a9f28b45f4 build(deps): Bump underscore and @sailshq/nedb in /server
Bumps [underscore](https://github.com/jashkenas/underscore) and [@sailshq/nedb](https://github.com/sailshq/nedb). These dependencies needed to be updated together.

Updates `underscore` from 1.13.1 to 1.13.8
- [Commits](https://github.com/jashkenas/underscore/compare/1.13.1...1.13.8)

Updates `@sailshq/nedb` from 1.8.3 to 1.8.4
- [Commits](https://github.com/sailshq/nedb/compare/v1.8.3...v1.8.4)

---
updated-dependencies:
- dependency-name: underscore
  dependency-version: 1.13.8
  dependency-type: indirect
- dependency-name: "@sailshq/nedb"
  dependency-version: 1.8.4
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-18 13:29:02 +00:00
dependabot[bot] d44e0dde93 build(deps): Bump path-to-regexp and @sailshq/router in /server
Bumps [path-to-regexp](https://github.com/pillarjs/path-to-regexp) and [@sailshq/router](https://github.com/sailshq/router). These dependencies needed to be updated together.

Updates `path-to-regexp` from 0.1.12 to 0.1.13
- [Release notes](https://github.com/pillarjs/path-to-regexp/releases)
- [Changelog](https://github.com/pillarjs/path-to-regexp/blob/v.0.1.13/History.md)
- [Commits](https://github.com/pillarjs/path-to-regexp/compare/v0.1.12...v.0.1.13)

Updates `@sailshq/router` from 1.3.10 to 1.3.11
- [Changelog](https://github.com/sailshq/router/blob/master/HISTORY.md)
- [Commits](https://github.com/sailshq/router/compare/v1.3.10...v1.3.11)

---
updated-dependencies:
- dependency-name: path-to-regexp
  dependency-version: 0.1.13
  dependency-type: indirect
- dependency-name: "@sailshq/router"
  dependency-version: 1.3.11
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-18 13:28:46 +00:00
Daniel Hiller 20eb57de4c Merge pull request #1635 from HannesOberreiter/fix/unicode-initials
fix: unicode/emoji characters in user avatar initials
2026-04-18 15:28:06 +02:00
Daniel Hiller 4ccc71419f Merge pull request #1551 from plankanban/dependabot/npm_and_yarn/client/multi-5543462fab
build(deps): Bump bn.js in /client
2026-04-18 15:28:04 +02:00
Daniel Hiller 0e93111e1b Merge pull request #1612 from plankanban/dependabot/npm_and_yarn/yaml-2.8.3
build(deps): Bump yaml from 2.8.2 to 2.8.3
2026-04-18 15:28:02 +02:00
Daniel Hiller 11f7814e87 Merge pull request #1611 from plankanban/dependabot/npm_and_yarn/client/yaml-2.8.3
build(deps): Bump yaml from 2.8.2 to 2.8.3 in /client
2026-04-18 15:27:59 +02:00
Daniel Hiller 9a4241e3d1 Merge pull request #1610 from plankanban/dependabot/npm_and_yarn/server/yaml-2.8.3
build(deps): Bump yaml from 2.8.2 to 2.8.3 in /server
2026-04-18 15:27:57 +02:00
Daniel Hiller 4fd164c81a Merge pull request #1627 from plankanban/dependabot/npm_and_yarn/client/vite-7.3.2
build(deps): Bump vite from 7.3.1 to 7.3.2 in /client
2026-04-18 15:27:55 +02:00
Daniel Hiller 5331f590a2 Merge pull request #1617 from plankanban/dependabot/npm_and_yarn/server/brace-expansion-1.1.13
build(deps): Bump brace-expansion from 1.1.12 to 1.1.13 in /server
2026-04-18 15:27:52 +02:00
Daniel Hiller 082b257a50 Merge pull request #1628 from plankanban/dependabot/npm_and_yarn/brace-expansion-2.0.3
build(deps): Bump brace-expansion from 2.0.2 to 2.0.3
2026-04-18 15:27:50 +02:00
Daniel Hiller fd0981b5b3 Merge pull request #1624 from plankanban/dependabot/npm_and_yarn/client/lodash-es-4.18.1
build(deps): Bump lodash-es from 4.17.23 to 4.18.1 in /client
2026-04-18 15:27:48 +02:00
Daniel Hiller 9b68d3fc30 Merge pull request #1630 from plankanban/dependabot/npm_and_yarn/client/lodash-4.18.1
build(deps): Bump lodash from 4.17.23 to 4.18.1 in /client
2026-04-18 15:27:46 +02:00
Daniel Hiller 922d70e289 Merge pull request #1629 from plankanban/dependabot/npm_and_yarn/server/lodash-4.18.1
build(deps): Bump lodash from 4.17.23 to 4.18.1 in /server
2026-04-18 15:27:43 +02:00
Daniel Hiller 40a3e436ad Merge pull request #1608 from plankanban/dependabot/npm_and_yarn/server/picomatch-2.3.2
build(deps): Bump picomatch from 2.3.1 to 2.3.2 in /server
2026-04-18 15:27:22 +02:00
Daniel Hiller 227332768c Merge pull request #1607 from plankanban/dependabot/npm_and_yarn/client/picomatch-2.3.2
build(deps-dev): Bump picomatch from 2.3.1 to 2.3.2 in /client
2026-04-18 15:27:19 +02:00
Daniel Hiller 555117912c Merge pull request #1631 from plankanban/dependabot/npm_and_yarn/server/nodemailer-8.0.5
build(deps): Bump nodemailer from 7.0.13 to 8.0.5 in /server
2026-04-18 15:27:11 +02:00
Daniel Hiller 9ba5f86073 Merge pull request #1632 from plankanban/dependabot/npm_and_yarn/server/multi-d854bddb60
build(deps): Bump fast-xml-parser and @aws-sdk/xml-builder in /server
2026-04-18 15:27:09 +02:00