Compare commits

...

10 Commits

Author SHA1 Message Date
34f6bb5d0f Update README.md 2026-09-14 20:06:04 +02:00
Joakim Svensson
1e2e22d238 Docker file och compose 2026-09-14 20:06:04 +02:00
Joakim Svensson
734171ded4 Docker file och compose 2026-09-14 20:06:04 +02:00
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
b933504071 chore(release): bump version numbers, authors, etc
Signed-off-by: Erik Michelson <github@erik.michelson.eu>
2026-08-21 23:40:50 +02:00
renovate[bot]
47a7cdf3f3 chore(deps): lock file maintenance
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-21 22:37:37 +02:00
renovate[bot]
43f414adc4 fix(deps): update dependency markdown-it to v14.3.0
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-21 22:27:02 +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
0e24145095 chore(deps): upgrade uuid to 14.0.2
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
21 changed files with 454 additions and 348 deletions

2
.gitignore vendored
View File

@@ -16,6 +16,8 @@ backups/
*.log *.log
*.sqlite *.sqlite
*~
# ignore config files # ignore config files
config.json config.json
.sequelizerc .sequelizerc

View File

@@ -35,3 +35,5 @@ Yannick Bungers <git@innay.de> Yannick Bungers <github@innay.de>
Renovate Bot <bot@renovateapp.com> renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Renovate Bot <bot@renovateapp.com> renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Tobias Dillig <tobias.dillig@frachtwerk.de> Tobi <tldev-de@users.noreply.github.com> Tobias Dillig <tobias.dillig@frachtwerk.de> Tobi <tldev-de@users.noreply.github.com>
Andreas Boesen <boesen@belwue.de> Andreas Boesen <618847+Happy86@users.noreply.github.com>

View File

@@ -10,7 +10,8 @@ Alexander Hesse <alexander.hesse@sandstorm-media.de>
Alexander Wellbrock <a.wellbrock@mailbox.org> Alexander Wellbrock <a.wellbrock@mailbox.org>
Amolith <amolith@nixnet.xyz> Amolith <amolith@nixnet.xyz>
Andre Julius <noromoron@gmail.com> Andre Julius <noromoron@gmail.com>
Andreas Boesen <618847+Happy86@users.noreply.github.com> Andreas Boesen <boesen@belwue.de>
Andy Piper <andypiper@users.noreply.github.com>
Antoine Aflalo <antoine@warrantymaster.com> Antoine Aflalo <antoine@warrantymaster.com>
aptalca <aptalca@users.noreply.github.com> aptalca <aptalca@users.noreply.github.com>
Augustin Trancart <augustin.trancart@oslandia.com> Augustin Trancart <augustin.trancart@oslandia.com>
@@ -193,6 +194,7 @@ Tobias Dillig <tobias.dillig@frachtwerk.de>
Tobias Kremer <tobias.kremer@gmail.com> Tobias Kremer <tobias.kremer@gmail.com>
Tom Wyckhuys <tomwyckhuys@gmail.com> Tom Wyckhuys <tomwyckhuys@gmail.com>
Toma Tasovac <ttasovac@humanistika.org> Toma Tasovac <ttasovac@humanistika.org>
Tony Chau <90050474+fo5for@users.noreply.github.com>
toshi0123 <7948737+toshi0123@users.noreply.github.com> toshi0123 <7948737+toshi0123@users.noreply.github.com>
Turakar <turakar23@gmail.com> Turakar <turakar23@gmail.com>
VaiTon <eyadlorenzo@gmail.com> VaiTon <eyadlorenzo@gmail.com>

33
Dockerfile Normal file
View File

@@ -0,0 +1,33 @@
############################
# 1) Builder: bygg HedgeDoc
############################
FROM node:18-alpine AS builder
WORKDIR /build
# H??mta din branch som tarball (ingen git beh??vs)
ADD https://git.sa6anw.se/sa6anw/hedgedoc/archive/refs/heads/hedgeagent/1.10.5.tar.gz /tmp/hedgedoc.tar.gz
RUN tar -xzf /tmp/hedgedoc.tar.gz --strip-components=1 \
&& rm /tmp/hedgedoc.tar.gz
# Installera deps + bygg frontend/backend
RUN corepack enable \
&& yarn install --immutable \
&& yarn build
########################################
# 2) Runtime: officiell HedgeDoc-image
########################################
FROM quay.io/hedgedoc/hedgedoc:1.10.5
USER root
# Ers??tt upstream-koden
RUN rm -rf /hedgedoc
# Kopiera f??rdigbyggd app med r??tt UID/GID
COPY --from=builder --chown=10000:10000 /build /hedgedoc
USER 10000

View File

@@ -1,3 +1,21 @@
# HedgeDoc-HedgeAgent
This is a customized version that makes it possible to invite an AI agent to a note via the menu. "Invite Agent" sends the `note_id` to hedgeagent.
To start an instance for development, the following is required:
1. ```cp config.json.example config.json ```
2. Update ```"domain": "change this" ```
3. ```.yarn/releases/yarn-4.12.0.cjs install```
4. ```.yarn/releases/yarn-4.12.0.cjs run build```
5. ```.yarn/releases/yarn-4.12.0.cjs start```
To start for production:
1. `docker compose up -d`
Note: Use UID 10000 for data folders.
---
![HedgeDoc Logo](docs/content/images/hedgedoc_logo_black.svg) ![HedgeDoc Logo](docs/content/images/hedgedoc_logo_black.svg)
# HedgeDoc # HedgeDoc

2
app.js
View File

@@ -274,7 +274,7 @@ app.use(require('./lib/web/baseRouter'))
app.use(require('./lib/web/statusRouter')) app.use(require('./lib/web/statusRouter'))
app.use(require('./lib/web/auth')) app.use(require('./lib/web/auth'))
app.use(require('./lib/web/historyRouter')) app.use(require('./lib/web/historyRouter'))
app.use(require('./lib/web/userRouter')) app.use(require('./lib/web/userRouter').default)
app.use(require('./lib/web/imageRouter').default) app.use(require('./lib/web/imageRouter').default)
app.use(require('./lib/web/note/router')) app.use(require('./lib/web/note/router'))

50
docker-compose.yaml Normal file
View File

@@ -0,0 +1,50 @@
services:
database:
image: postgres:13.4-alpine
environment:
- POSTGRES_USER=hedgedoc
- POSTGRES_PASSWORD=password
- POSTGRES_DB=hedgedoc
volumes:
- ./db:/var/lib/postgresql/data
restart: always
networks:
- internal
app:
build: .
image: hedgedoc-hedgeagent:1.10.5
container_name: hedgedoc
environment:
CMD_DB_URL: postgres://hedgedoc:password@database:5432/hedgedoc
CMD_PORT: "3000"
CMD_HOST: "0.0.0.0"
CMD_DOMAIN: hedgedoc.sa6anw.se
CMD_URL_ADDPORT: "false"
CMD_PROTOCOL_USESSL: "true"
CMD_EMAIL: "true"
CMD_ALLOW_EMAIL_REGISTER: "true"
volumes:
- ./uploads:/hedgedoc/public/uploads
restart: always
depends_on:
- database
# Since I use Caddy I don't need this
# ports:
# - "3000:3000"
## If you use Caddy like I do keep below
networks:
- internal
- proxy
labels:
caddy: hedgedoc.sa6anw.se
caddy.reverse_proxy: "{{upstreams 3000}}"
networks:
internal:
internal: true
proxy:
external: true
## If you don't, you can deleta all of this

View File

@@ -3,7 +3,7 @@ openapi: 3.0.1
info: info:
title: HedgeDoc title: HedgeDoc
description: HedgeDoc is an open source collaborative note editor. Several tasks of HedgeDoc can be automated through this API. description: HedgeDoc is an open source collaborative note editor. Several tasks of HedgeDoc can be automated through this API.
version: 1.11.1 version: 1.12.0
contact: contact:
name: HedgeDoc on GitHub name: HedgeDoc on GitHub
url: https://github.com/hedgedoc/hedgedoc url: https://github.com/hedgedoc/hedgedoc

View File

@@ -19,7 +19,7 @@ The easiest way to get started with HedgeDoc and Docker is to use the following
version: '3' version: '3'
services: services:
database: database:
image: postgres:17.7-alpine image: postgres:18.6-alpine
environment: environment:
- POSTGRES_USER=hedgedoc - POSTGRES_USER=hedgedoc
- POSTGRES_PASSWORD=password - POSTGRES_PASSWORD=password
@@ -29,7 +29,7 @@ services:
restart: always restart: always
app: app:
# Make sure to use the latest release from https://hedgedoc.org/latest-release # Make sure to use the latest release from https://hedgedoc.org/latest-release
image: quay.io/hedgedoc/hedgedoc:1.11.1 image: quay.io/hedgedoc/hedgedoc:1.12.0
environment: environment:
- CMD_DB_URL=postgres://hedgedoc:password@database:5432/hedgedoc - CMD_DB_URL=postgres://hedgedoc:password@database:5432/hedgedoc
- CMD_DOMAIN=localhost - CMD_DOMAIN=localhost

View File

@@ -19,7 +19,7 @@
1. Check if you meet the [requirements at the top of this document](#manual-installation). 1. Check if you meet the [requirements at the top of this document](#manual-installation).
2. Download the [latest release](https://hedgedoc.org/latest-release/) and extract it. 2. Download the [latest release](https://hedgedoc.org/latest-release/) and extract it.
<small>Alternatively, you can use Git to clone the repository and checkout a release, e.g. with `git clone -b 1.11.1 https://github.com/hedgedoc/hedgedoc.git`.</small> <small>Alternatively, you can use Git to clone the repository and checkout a release, e.g. with `git clone -b 1.12.0 https://github.com/hedgedoc/hedgedoc.git`.</small>
3. Enter the directory and execute `bin/setup`, which will install the dependencies and create example configs. 3. Enter the directory and execute `bin/setup`, which will install the dependencies and create example configs.
4. Configure HedgeDoc: To get started, you can use this minimal `config.json`: 4. Configure HedgeDoc: To get started, you can use this minimal `config.json`:
```json ```json
@@ -61,7 +61,7 @@ If you want to upgrade HedgeDoc from an older version, follow these steps:
and the latest release. and the latest release.
2. Fully stop your old HedgeDoc server. 2. Fully stop your old HedgeDoc server.
3. [Download](https://hedgedoc.org/latest-release/) the new release and extract it over the old directory. 3. [Download](https://hedgedoc.org/latest-release/) the new release and extract it over the old directory.
<small>If you use Git, you can check out the new tag with e.g. `git fetch origin && git checkout 1.11.1`</small> <small>If you use Git, you can check out the new tag with e.g. `git fetch origin && git checkout 1.12.0`</small>
5. Run `bin/setup`. This will take care of installing dependencies. It is safe to run on an existing installation. 5. Run `bin/setup`. This will take care of installing dependencies. It is safe to run on an existing installation.
6. *:octicons-light-bulb-16: If you used the release tarball for 1.7.0 or newer, this step can be skipped.* 6. *:octicons-light-bulb-16: If you used the release tarball for 1.7.0 or newer, this step can be skipped.*
Build the frontend bundle by running `yarn install --immutable` and `yarn build`. The extra `yarn install --immutable` is necessary as `bin/setup` does not install the build dependencies. Build the frontend bundle by running `yarn install --immutable` and `yarn build`. The extra `yarn install --immutable` is necessary as `bin/setup` does not install the build dependencies.

View File

@@ -7,7 +7,7 @@ const CspStrategy = {}
const defaultDirectives = { const defaultDirectives = {
defaultSrc: ['\'none\''], defaultSrc: ['\'none\''],
baseUri: ['\'self\''], baseUri: ['\'self\''],
connectSrc: ['\'self\'', buildDomainOriginWithProtocol(config, 'ws'), 'https://vimeo.com/api/v2/video/'], connectSrc: ['\'self\'', buildDomainOriginWithProtocol(config, 'ws'), 'https://vimeo.com/api/v2/video/', 'https://hedgeagent.sa6anw.se/add_note'],
fontSrc: ['\'self\''], fontSrc: ['\'self\''],
manifestSrc: ['\'self\''], manifestSrc: ['\'self\''],
frameSrc: ['\'self\'', 'https://player.vimeo.com', 'https://www.youtube.com', 'https://gist.github.com'], frameSrc: ['\'self\'', 'https://player.vimeo.com', 'https://www.youtube.com', 'https://gist.github.com'],

View File

@@ -130,9 +130,9 @@ imageRouter.post('/uploadimage', function (req, res) {
logger.error(`Image upload error: formidable error: ${err}`) logger.error(`Image upload error: formidable error: ${err}`)
rimraf.sync(tmpDir) rimraf.sync(tmpDir)
return errors.errorForbidden(res) return errors.errorForbidden(res)
} else if (!files.image || !files.image.length < 1 || !files.image[0].filepath) { } else if (!files.image || files.image.length < 1 || !files.image[0].filepath) {
logger.debug(`${JSON.stringify(files)}`) logger.debug(`${JSON.stringify(files)}`)
logger.error('Image upload error: Upload didn\'t contain file)') logger.error('Image upload error: Upload didn\'t contain file')
rimraf.sync(tmpDir) rimraf.sync(tmpDir)
return errors.errorBadRequest(res) return errors.errorBadRequest(res)
} else if (!(await checkUploadType(files.image[0].filepath))) { } else if (!(await checkUploadType(files.image[0].filepath))) {

View File

@@ -1,6 +1,9 @@
'use strict' 'use strict'
const archiver = require('archiver') import { ZipArchive } from 'archiver'
import { createRequire } from 'module'
const require = createRequire(import.meta.url)
const sanitizeFilename = require('sanitize-filename') const sanitizeFilename = require('sanitize-filename')
const async = require('async') const async = require('async')
const Router = require('express').Router const Router = require('express').Router
@@ -11,7 +14,8 @@ const models = require('../models')
const logger = require('../logger') const logger = require('../logger')
const { generateAvatar } = require('../letter-avatars') const { generateAvatar } = require('../letter-avatars')
const UserRouter = module.exports = Router() const UserRouter = Router()
export default UserRouter
// get me info // get me info
UserRouter.get('/me', function (req, res) { UserRouter.get('/me', function (req, res) {
@@ -71,7 +75,7 @@ UserRouter.get('/me/delete/:token?', function (req, res) {
UserRouter.get('/me/export', function (req, res) { UserRouter.get('/me/export', function (req, res) {
if (req.isAuthenticated()) { if (req.isAuthenticated()) {
// let output = fs.createWriteStream(__dirname + '/example.zip'); // let output = fs.createWriteStream(__dirname + '/example.zip');
const archive = archiver('zip', { const archive = new ZipArchive({
zlib: { level: 3 } // Sets the compression level. zlib: { level: 3 } // Sets the compression level.
}) })
res.setHeader('Content-Type', 'application/zip') res.setHeader('Content-Type', 'application/zip')

View File

@@ -40,6 +40,7 @@
"Extra": "Extra", "Extra": "Extra",
"Revision": "Revision", "Revision": "Revision",
"Slide Mode": "Slide Mode", "Slide Mode": "Slide Mode",
"Invite Agent": "Invite Agent",
"Export": "Export", "Export": "Export",
"Import": "Import", "Import": "Import",
"Clipboard": "Clipboard", "Clipboard": "Clipboard",

View File

@@ -40,6 +40,7 @@
"Extra": "Extra", "Extra": "Extra",
"Revision": "Revision", "Revision": "Revision",
"Slide Mode": "Slide Mode", "Slide Mode": "Slide Mode",
"Invite Agent": "Invite Agent",
"Export": "Exportera", "Export": "Exportera",
"Import": "Importera", "Import": "Importera",
"Clipboard": "Urklipp", "Clipboard": "Urklipp",

View File

@@ -1,6 +1,6 @@
{ {
"name": "HedgeDoc", "name": "HedgeDoc",
"version": "1.11.1", "version": "1.12.0",
"description": "The best platform to write and share markdown.", "description": "The best platform to write and share markdown.",
"main": "app.js", "main": "app.js",
"license": "AGPL-3.0", "license": "AGPL-3.0",
@@ -21,7 +21,7 @@
"@node-saml/passport-saml": "5.1.0", "@node-saml/passport-saml": "5.1.0",
"@passport-next/passport-openid": "1.0.0", "@passport-next/passport-openid": "1.0.0",
"Idle.Js": "git+https://github.com/shawnmclean/Idle.js#commit=2b57cc6e49d177b7ddce0cca00ef5cbe07453541", "Idle.Js": "git+https://github.com/shawnmclean/Idle.js#commit=2b57cc6e49d177b7ddce0cca00ef5cbe07453541",
"archiver": "7.0.1", "archiver": "8.0.0",
"async": "3.2.6", "async": "3.2.6",
"aws-sdk": "2.1693.0", "aws-sdk": "2.1693.0",
"azure-storage": "2.10.7", "azure-storage": "2.10.7",
@@ -55,7 +55,7 @@
"lutim": "1.0.3", "lutim": "1.0.3",
"lz-string": "git+https://github.com/hackmdio/lz-string.git#commit=6edfccb79cd8c210f03fd3bf18e41ca144fbeefb", "lz-string": "git+https://github.com/hackmdio/lz-string.git#commit=6edfccb79cd8c210f03fd3bf18e41ca144fbeefb",
"mariadb": "3.5.3", "mariadb": "3.5.3",
"markdown-it": "14.1.1", "markdown-it": "14.3.0",
"markdown-it-abbr": "2.0.0", "markdown-it-abbr": "2.0.0",
"markdown-it-container": "4.0.0", "markdown-it-container": "4.0.0",
"markdown-it-deflist": "4.0.0", "markdown-it-deflist": "4.0.0",
@@ -102,7 +102,7 @@
"store": "2.0.12", "store": "2.0.12",
"toobusy-js": "0.5.1", "toobusy-js": "0.5.1",
"umzug": "3.8.3", "umzug": "3.8.3",
"uuid": "11.1.1", "uuid": "14.0.2",
"validator": "13.15.35", "validator": "13.15.35",
"winston": "3.19.0", "winston": "3.19.0",
"xss": "1.0.15" "xss": "1.0.15"

View File

@@ -1,6 +1,14 @@
# Release Notes # Release Notes
## <i class="fa fa-tag"></i> 1.x.x <i class="fa fa-calendar-o"></i> UNRELEASED ## <i class="fa fa-tag"></i> 1.12.0 <i class="fa fa-calendar-o"></i> 2026-08-21
### Important changes
⚠️ **HedgeDoc 1.12.0 and onwards will require Node 20.17 or later in order to run.**
Since Node 18 security support was stopped over one year ago, we don't maintain backwards-compatability for that anymore.
Some syntax highlighting languages have been removed and/or changed. You can find more information in
[the highlight.js docs](https://highlightjs.readthedocs.io/en/latest/upgrade-11.html#built-in-set-of-common-languages).
### Enhancements ### Enhancements
@@ -8,9 +16,14 @@
### Bugfixes ### Bugfixes
- All links will be opened in new tabs instead of the same tab as the note. This was changed when the external link warning was implemented and now the old behavior is restored. - All links will be opened in new tabs instead of the same tab as the note. This was changed when the external link warning was implemented and now the old behavior is restored
- Fixed multiple bugs in the realtime connection handling that could lead to data-loss of users with a flaky connection - Fixed multiple bugs in the realtime connection handling that could lead to data-loss of users with a flaky connection
### Contributors
- [Tony Chau](https://github.com/fo5for)
- [Lars Kiesow](https://github.com/lkiesow)
## <i class="fa fa-tag"></i> 1.11.1 <i class="fa fa-calendar-o"></i> 2026-07-24 ## <i class="fa fa-tag"></i> 1.11.1 <i class="fa fa-calendar-o"></i> 2026-07-24
### Security fixes ### Security fixes

View File

@@ -1207,6 +1207,23 @@ ui.toolbar.publish.attr('href', noteurl + '/publish')
// extra // extra
// slide // slide
ui.toolbar.extra.slide.attr('href', noteurl + '/slide') ui.toolbar.extra.slide.attr('href', noteurl + '/slide')
// invite agent
ui.toolbar.extra.inviteAgent.click(function (e) {
e.preventDefault()
$.ajax({
url: 'https://hedgeagent.sa6anw.se/add_note',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify({ note_id: noteid }),
error: function (xhr, status, err) {
console.error('Invite agent failed:', status, err)
alert('Failed to invite agent.')
}
})
})
// download // download
// markdown // markdown
ui.toolbar.download.markdown.click(function (e) { ui.toolbar.download.markdown.click(function (e) {

View File

@@ -12,7 +12,8 @@ export const getUIElements = () => ({
publish: $('.ui-publish'), publish: $('.ui-publish'),
extra: { extra: {
revision: $('.ui-extra-revision'), revision: $('.ui-extra-revision'),
slide: $('.ui-extra-slide') slide: $('.ui-extra-slide'),
inviteAgent: $('.ui-invite-agent')
}, },
download: { download: {
markdown: $('.ui-download-markdown'), markdown: $('.ui-download-markdown'),

View File

@@ -34,6 +34,8 @@
</li> </li>
<li role="presentation"><a role="menuitem" class="ui-extra-slide" tabindex="-1" href="#" target="_blank" rel="noopener"><i class="fa fa-tv fa-fw"></i> <%= __('Slide Mode') %></a> <li role="presentation"><a role="menuitem" class="ui-extra-slide" tabindex="-1" href="#" target="_blank" rel="noopener"><i class="fa fa-tv fa-fw"></i> <%= __('Slide Mode') %></a>
</li> </li>
<li role="presentation"><a role="menuitem" class="ui-invite-agent" tabindex="-1" href="#"><i class="fa fa-robot fa-fw"></i> <%= __('Invite Agent') %></a>
</li>
<% if(enableGitHubGist || enableDropBoxSave || enableGitlabSnippets) { %> <% if(enableGitHubGist || enableDropBoxSave || enableGitlabSnippets) { %>
<li class="divider"></li> <li class="divider"></li>
<li class="dropdown-header"><%= __('Export') %></li> <li class="dropdown-header"><%= __('Export') %></li>
@@ -136,6 +138,8 @@
</li> </li>
<li role="presentation"><a role="menuitem" class="ui-extra-slide" tabindex="-1" href="#" target="_blank" rel="noopener"><i class="fa fa-tv fa-fw"></i> <%= __('Slide Mode') %></a> <li role="presentation"><a role="menuitem" class="ui-extra-slide" tabindex="-1" href="#" target="_blank" rel="noopener"><i class="fa fa-tv fa-fw"></i> <%= __('Slide Mode') %></a>
</li> </li>
<li role="presentation"><a role="menuitem" class="ui-invite-agent" tabindex="-1" href="#"><i class="fa fa-robot fa-fw"></i> <%= __('Invite Agent') %></a>
</li>
<% if(enableGitHubGist || enableDropBoxSave || enableGitlabSnippets) { %> <% if(enableGitHubGist || enableDropBoxSave || enableGitlabSnippets) { %>
<li class="divider"></li> <li class="divider"></li>
<li class="dropdown-header"><%= __('Export') %></li> <li class="dropdown-header"><%= __('Export') %></li>

614
yarn.lock

File diff suppressed because it is too large Load Diff