Commit Graph

717 Commits

Author SHA1 Message Date
Joakim Svensson
0482e5b3c0 Add Invite Agent action to editor menu and allow CSP connect-src 2026-09-14 20:06:04 +02:00
Erik Michelson
02c6c08bd3 fix(upload): invalid check for upload content
Signed-off-by: Erik Michelson <github@erik.michelson.eu>
2026-08-21 22:25:12 +02:00
Erik Michelson
486fcfef67 chore(deps): upgrade archiver to 8.0.0
Signed-off-by: Erik Michelson <github@erik.michelson.eu>
2026-08-21 22:25:12 +02:00
Philip Molares
788676aba4 refactor: umzug
allow umzug v3 to work with the umzug v2 migrations

Signed-off-by: Philip Molares <philip.molares@udo.edu>
2026-08-21 20:30:00 +02:00
Erik Michelson
074f7251e9 fix(deps): update scrypt import to ESM
Signed-off-by: Erik Michelson <github@erik.michelson.eu>
2026-08-21 20:05:02 +02:00
Philip Molares
65b39de212 refactor: formidable usage
Instead of a single image or an array formidable now always returns an array of files.

Signed-off-by: Philip Molares <philip.molares@udo.edu>
2026-08-21 18:31:13 +02:00
Erik Michelson
b7c46b0a90 fix(image-upload): make imageRouter ESM ready
Signed-off-by: Erik Michelson <github@erik.michelson.eu>
2026-08-21 18:09:35 +02:00
Erik Michelson
da2c065e59 fix(realtime): check for online users before clearing note
The disconnect handler for the realtime connection checks whether the
disconnecting socket was the last user for that note. If that's the
case and the note had unsaved changes, it persists them to the database
which is an async progress. In the callback of this async progress, the
note and all its pending changes (should be empty) are deleted.
However, when the user reconnects quickly because of a flaky
connection, it could happen that they create new pending changes before
the database saving finished. As there was no additional "no-users"
check before clearing the note, this could lead to content loss.

Signed-off-by: Erik Michelson <github@erik.michelson.eu>
2026-08-21 13:22:17 +02:00
Tony Chau
ffcf79ef07 fix: open links in new tab
The addition of external link warning has changed the behavior of
opening links from opening in a new tab to opening in the same tab.
This restores the old behavior and opens all links in a new tab.

Signed-off-by: Tony Chau <90050474+fo5for@users.noreply.github.com>
2026-08-21 12:20:11 +02:00
Erik Michelson
0dda149c7f fix(permissions): ignore unknown permission values
The permission checks did not check for unknown permission values
submitted to the server. This allowed bypassing permission checks
under certain circumstances. However, this is not as critical as
it might sound at first, since checks guard that only the owner
can modify note permissions and the owner already has always
full permission to their note.

Signed-off-by: Erik Michelson <github@erik.michelson.eu>
2026-07-24 21:39:28 +02:00
Erik Michelson
2391e406cb chore(config): remove unused allowOrigin config option
Signed-off-by: Erik Michelson <github@erik.michelson.eu>
2026-07-22 22:54:36 +02:00
Philip Molares
0749c31100 refactor: remove Temp
This was a very old way of migrating the history and is no longer needed.

Signed-off-by: Philip Molares <philip.molares@udo.edu>
2026-07-22 22:54:36 +02:00
Erik Michelson
0ebf0dbc6b feat: add config option to disable external link warning
Since it is heavily requested by users, this adds a new config option
to disable the previously introduced external link warning.
Be aware however, that disabling this config option weakens the
security of your HedgeDoc instance and is therefore only recommended
for closed trustworthy user groups.

Signed-off-by: Erik Michelson <github@erik.michelson.eu>
2026-07-19 14:40:36 +02:00
Tobias Dillig
1e75f7462d feat: add 'image/webp' to allowed upload MIME types
Signed-off-by: Tobias Dillig <tobias.dillig@frachtwerk.de>
2026-07-04 22:25:43 +02:00
Tobi
e4d5124211 feat(external-links): add whitelist to bypass redirect page (#6548)
Signed-off-by: Tobias Dillig <tobias.dillig@frachtwerk.de>
Signed-off-by: Tobi <tldev-de@users.noreply.github.com>
2026-06-25 17:16:27 +02:00
Erik Michelson
c489497e45 refactor(frontmatter): constrain frontmatter object after parsing
This change removes the meta-marked dependency which solely was
used for extracting the frontmatter, which is possible as well
with one function. Furthermore, this introduces constraints to
objects resulting from frontmatter parsing and enforces them in
order to prevent attacks like a yaml bomb (massive alias expansion).
This change should resolve a possible DoS attack.

Signed-off-by: Erik Michelson <github@erik.michelson.eu>
2026-06-18 23:56:45 +02:00
Erik Michelson
fbd7307f16 fix(gist-export): validate OAuth2 state and redirect URI
The state of the OAuth2 response was not verified.
In theory an attacker could use this to extract the contents of a note.

Co-authored-by: Philip Molares <philip.molares@udo.edu>
Signed-off-by: Erik Michelson <github@erik.michelson.eu>
2026-06-18 23:56:45 +02:00
Erik Michelson
dd40a6c04b fix(auth): sanitize email addresses
Previously, maliciously crafted email addresses
could be used to sneak HTML code into the HedgeDoc
editor, since HedgeDoc uses the local part of the
address as a display name for users.
We're now sanitizing this using DOMPurify.

Co-authored-by: Philip Molares <philip.molares@udo.edu>
Signed-off-by: Erik Michelson <github@erik.michelson.eu>
2026-06-18 23:56:45 +02:00
Philip Molares
8891d75baa feat(rate-limit): add more config options
Allow the admin to specify the rate-limits for user signup / login
Allow the admin to specify if Cloudflare specific rate-limit functionality should be used or not

Signed-off-by: Philip Molares <philip.molares@udo.edu>
2026-06-17 21:08:07 +02:00
Erik Michelson
814271dc0b feat(editor): add external link warning page
A malicious user could modify a valid looking link (for example of the editor UI)
to point to a malicous site, by using overlays and CSS. Since CSS should stay
enabled, we need to make the user aware of possible risks when leaving the
HedgeDoc instance, in order to protect them from credential-theft.

This commit adds a new interstitial page for external links, that shows the
target URL and asks the user, whether they really want to continue.

Signed-off-by: Erik Michelson <github@erik.michelson.eu>
2026-06-10 20:15:09 +02:00
Erik Michelson
5a5e12a693 fix(ot): keep pendingOps in StaleWithBuffer during applyClient
Co-authored-by: Philip Molares <philip.molares@udo.edu>
Signed-off-by: Erik Michelson <github@erik.michelson.eu>
2026-03-24 21:12:41 +01:00
bxff
65bf11554a fix: buffer operations in Stale/StaleWithBuffer instead of throwing (#6342)
When 5+ users edit concurrently, revision gaps trigger the Stale state
which throws 'Ignored server-side change.' on incoming operations. This
causes document divergence, silent data corruption, and eventually
force-resets that discard local edits.

Changes:
- Stale/StaleWithBuffer.applyServer: buffer incoming operations instead
  of throwing, apply them sequentially after missing ops arrive
- Stale.applyClient: carry pendingOps to StaleWithBuffer on transition
- editor-socketio-server: retry-based force-reset (3 failures) instead
  of immediate nuclear reset on any OT error
- hex2rgb: defensive null checks for old non-hex color records

Signed-off-by: bxff <51504045+bxff@users.noreply.github.com>
2026-03-24 21:12:41 +01:00
Philip Molares
7e2a783161 fix(realtime): aboard finishConnection if user is missing
This can happen if the user disconnects during connection creation.

See #6101

Signed-off-by: Philip Molares <philip.molares@udo.edu>
2026-02-21 23:47:53 +01:00
Erik Michelson
fd4d5bfbd1 fix(editor): always use random hex colors
chance.color() can output all valid CSS
values for colors, including rgba() syntax and predefined color
names. Due to the usage of hex2rgb and other methods, this can
break the editor. This commit ensures that all randomly generated
colors are specified in hex format.

Signed-off-by: Erik Michelson <github@erik.michelson.eu>
2026-02-18 19:43:33 +01:00
Erik Michelson
f910000d2b feat(security): sanitize SVG files on upload
Signed-off-by: Erik Michelson <github@erik.michelson.eu>
2026-02-04 20:27:41 +01:00
Erik Michelson
35f36fccba fix(auth): add state parameters and PKCE support
Only the OAuth2 auth strategy was using the state parameter,
which should be used as described in the RFC. The other
auth strategies such as GitHub, GitLab or Google were lacking
the state parameter.
This change adds the required state parameter as well as
enabling PKCE support on providers where it's possible.

Signed-off-by: Erik Michelson <github@erik.michelson.eu>
2025-12-05 22:06:30 +01:00
Philip Molares
bc2075ae9d refactor: use user-token for historyDelete too
Previously, the user token was only used for the endpoint
to delete the user itself. This commit adds that token to
the history deletion as well.

Signed-off-by: Philip Molares <philip.molares@udo.edu>
2025-11-26 19:28:53 +01:00
Erik Michelson
9a45d1e2a9 chore(deps): upgrade dependencies, remove some unnecessary ones
This commit upgrades dependencies that are more or less trivial
to update, e.g. because they didn't have major version bumps or
simply didn't break anything. There are some dependencies which
have not been upgraded since this would have required larger
refactorings. This includes especially the markdown-it ecosystem
and the webpack ecosystem.
The largest refactorings in this commit come from the bump of
socket.io v2 to v4 which changed the handling of the connected
socket list for instance.

This commit further removes some outdated and/or unnecessary
dependencies. This includes the String.js library which is
unmaintained for 9 years and has some CVEs. We mainly used
this library for their escapeHTML and unescapeHTML methods.
This can be done using native DOM APIs nowadays, which is also
considered more safe since it is the same logic that the
browser itself uses.
Since we target Node 18 and above, we can also rely on the
built-in fetch function instead of the node-fetch package.
The current version of Chance.js includes a method for
generating a random color now too, so we don't need the
package randomcolor anymore.

Signed-off-by: Erik Michelson <github@erik.michelson.eu>
2025-11-24 14:32:24 +01:00
Erik Michelson
637c451486 fix: use nanoid instead of shortid
shortid is deprecated and they recommend nanoid instead.
We're not sure if this has to do with possible name
collisions or enumerability, but to be sure and on the
safe side, we're changing this. nanoid seems quite safe
since it uses node's crypto module underneath.

Signed-off-by: Erik Michelson <github@erik.michelson.eu>
2025-11-22 01:05:50 +01:00
Erik Michelson
6d970dbafd feat(config): allow restriction and disabling of uploads
Previously, image uploads were always allowed, unless `CMD_ALLOW_ANONYMOUS=false` and `CMD_ALLOW_ANONYMOUS_EDITS=false`.
This PR adds a new config option `CMD_ENABLE_UPLOADS` to configure image uploads independently. There are three different modes: `all` (everyone can upload, guests too), `registered` (only registered and logged-in users can upload images), and `none` to completely disable image uploads.
The default value is non-breaking as it is `all`, unless the config `CMD_ALLOW_ANONYMOUS=false` and `CMD_ALLOW_ANONYMOUS_EDITS=false` is set, in which case the value is `registered`.
The UI will reflect the setting and either show or hide the upload button.

Signed-off-by: Erik Michelson <github@erik.michelson.eu>
2025-11-15 22:54:57 +01:00
Daniel Koschützki
c94ccfb6de fix: Dont return toobusy errors for healthchecks.
If running with an orchestrator that restarts hedgedoc on failing
healthchecks, this causes it to enter a crashloop.

toobusy -> gets restarted -> everyone refreshes -> toobusy

Signed-off-by: Daniel Koschützki <daniel.koschuetzki@adfinis.com>
2025-08-14 15:31:09 +02:00
Erik Michelson
ce66f33a6d feat(config): warning if both saml signing options are disabled
Co-authored-by: Philip Molares <philip.molares@udo.edu>
Signed-off-by: Erik Michelson <github@erik.michelson.eu>
2025-04-10 00:21:55 +02:00
Erik Michelson
3f520ea59a refactor(embeds): drop slideshare, use vimeo api, tighten CSP
The slideshare integration was broken for quite a while already,
as slideshare doesn't seem to have a good replacement, we're
dropping it in the same manner as speakerdeck was dropped some
time ago. This means the special syntax now just renders a plain
link. This commit gets rid of the vimdo oembed API too which
allowed JSONP injection. Instead we're using the normal vimeo
video metadata API.

Co-authored-by: Philip Molares <philip.molares@udo.edu>
Signed-off-by: Erik Michelson <github@erik.michelson.eu>
2025-04-10 00:21:55 +02:00
Erik Michelson
0636b5c20b refactor: use iframes for gist embedding instead of gist-embed
The used library gist-embed relies on GitHub Gist's JSONP
endpoint which is a risk for XSS injection. By adding untrusted
content from GitHub into the DOM it also follows very bad
practises. Using the iframe embedding has the disadvantage of
not having the proper height for the frame auto-loaded, but
the security benefits are worth it.

Signed-off-by: Erik Michelson <github@erik.michelson.eu>
2025-04-10 00:21:55 +02:00
Erik Michelson
cc74351846 feat(saml): add config options to set required signings
Signed-off-by: Erik Michelson <github@erik.michelson.eu>
2025-04-09 21:49:00 +02:00
Philip Molares
a8d5cb754c fix(oauth2): verify user id exists
Signed-off-by: Philip Molares <philip.molares@udo.edu>
2025-02-14 21:09:03 +01:00
Erik Michelson
fb6218ed82 fix(saml): change SAML attribute default, verify that a NameID is defined
Signed-off-by: Erik Michelson <github@erik.michelson.eu>
Signed-off-by: Philip Molares <philip.molares@udo.edu>
2025-02-14 21:09:03 +01:00
Erik Michelson
1a5030dbc1 fix(saml): adapt for new package @node-saml/passport-saml
Signed-off-by: Erik Michelson <github@erik.michelson.eu>
2025-02-14 21:09:03 +01:00
Erik Michelson
72c233b233 fix: set HSTS preload attribute to false by default
See <https://hstspreload.org/#opt-in> for more information
why this is important.

Signed-off-by: Erik Michelson <github@erik.michelson.eu>
2025-02-01 22:56:38 +01:00
Philip Molares
c437366c33 chore(eslint): run eslint --fix
Signed-off-by: Philip Molares <philip.molares@udo.edu>
2025-02-01 22:15:54 +01:00
Erik Michelson
6e9940c85f refactor: use common error message
Signed-off-by: Erik Michelson <github@erik.michelson.eu>
2025-02-01 21:12:08 +01:00
Erik Michelson
876ebad1f3 feat: rate-limiting
Signed-off-by: Erik Michelson <github@erik.michelson.eu>
2025-02-01 21:12:08 +01:00
Dominik Rimpf
980bc71a65 fix(csp): allow 'data:' images in pads
Signed-off-by: Dominik Rimpf <dev@drimpf.de>
2024-12-18 19:09:05 +01:00
Lautaro Alvarez
4fdab806a3 fix(oauth2): Fix crash when profile fields are missing (#5850)
Co-authored-by: Lautaro Alvarez <lautaro@grava.digital>
2024-11-01 15:21:10 +01:00
David Mehren
380587b7fd Ensure case-sensitive DB queries on MySQL/MariaDB
MySQLs string comparisons are case-insensitive by default.
This allows to hide notes by creating a new note with an alias that
equals the lower-cased alias of another note.
The new note is returned first by MySQL, so the original one is not
accessible anymore.

This fixes the problem by using an explicit binary comparison in the
affected queries.

See https://dev.mysql.com/doc/refman/8.0/en/case-sensitivity.html

Signed-off-by: David Mehren <git@herrmehren.de>
2024-09-01 13:54:18 +02:00
David Mehren
1f8f09c539 fix(deps): use meta-marked from NPM
Signed-off-by: David Mehren <git@herrmehren.de>
2024-08-31 18:44:35 +02:00
Erik Michelson
858d7bf5d1 feat: option to disable note creation
The abuse of the demo instance required us to disallow note creation

Signed-off-by: Erik Michelson <github@erik.michelson.eu>
Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
2024-07-21 11:03:35 +02:00
Erik Michelson
c85b11463d fix(minio): metadata as object not string
A change in the minio JS SDK resulted in uploads being stored
with a defect metadata object in minio, resulting in all
files served as application/octet-stream. This was caused as
the fifth argument to putObject is a metadata object and not
the content-type alone anymore.

Signed-off-by: Erik Michelson <github@erik.michelson.eu>
2024-06-20 21:58:17 +02:00
Sheogorath
1f1b2bd386 fix(oauth2): Fix crash in rolesClaim extraction
This patch adds a try-catch around the rolesClaim extraction to prevent
full crashes of HedgeDoc when a user profile is read, that doesn't
contain any such claim, which can happen with some IdPs, like Keycloak,
that omit the attribute when it's empty.

As a result an authorized user would crash the entire server, which is
definitely unintended behaviour. The simply try-catch should resolve the
issue and make sure that roles is always defined even if the
`extractProfileAttribute` call fails.

Signed-off-by: Sheogorath <sheogorath@shivering-isles.com>
2023-10-19 19:34:44 +02:00
Tilman Vatteroth
cd26aaa86e fix: use better already-exist check in note creation
Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
2023-07-18 23:18:21 +02:00