diff --git a/app.js b/app.js index 656c50834..d41dbfbd7 100644 --- a/app.js +++ b/app.js @@ -203,6 +203,7 @@ app.locals.serverURL = config.serverURL app.locals.sourceURL = config.sourceURL app.locals.allowAnonymous = config.allowAnonymous app.locals.allowAnonymousEdits = config.allowAnonymousEdits +app.locals.disableNoteCreation = config.disableNoteCreation app.locals.authProviders = { facebook: config.isFacebookEnable, twitter: config.isTwitterEnable, diff --git a/docs/content/configuration.md b/docs/content/configuration.md index 7a955fabe..2d44b6805 100644 --- a/docs/content/configuration.md +++ b/docs/content/configuration.md @@ -110,6 +110,7 @@ these are rarely used for various reasons. | `allowAnonymousEdits` | `CMD_ALLOW_ANONYMOUS_EDITS` | **`false`** or `true` | If `allowAnonymous` is `false`: allow users to select `freely` permission, allowing guests to edit existing notes (default is `false`). | | `allowFreeURL` | `CMD_ALLOW_FREEURL` | **`false`** or `true` | Set to allow new note creation by accessing a nonexistent note URL. This is the behavior familiar from [Etherpad](https://github.com/ether/etherpad-lite). | | `requireFreeURLAuthentication` | `CMD_REQUIRE_FREEURL_AUTHENTICATION` | **`false`** or `true` | Set to require authentication for FreeURL mode style note creation. | +| `disableNoteCreation` | `CMD_DISABLE_NOTE_CREATION` | **`false`** or `true` | Set to `true` to disallow any person to create notes. | | `defaultPermission` | `CMD_DEFAULT_PERMISSION` | **`editable`**, `freely`, `limited`, `locked`, `protected` or `private` | Set notes default permission (only applied on signed-in users). | | `sessionName` | | **`connect.sid`** | Cookie session name. | | `sessionLife` | `CMD_SESSION_LIFE` | **`14 * 24 * 60 * 60 * 1000`**, `1209600000` (14 days) | Cookie session life time in milliseconds. | diff --git a/lib/config/default.js b/lib/config/default.js index f7df8f99e..d038e5311 100644 --- a/lib/config/default.js +++ b/lib/config/default.js @@ -35,6 +35,7 @@ module.exports = { allowAnonymousEdits: false, allowFreeURL: false, requireFreeURLAuthentication: false, + disableNoteCreation: false, forbiddenNoteIDs: ['robots.txt', 'favicon.ico', 'api', 'build', 'css', 'docs', 'fonts', 'js', 'uploads', 'vendor', 'views'], defaultPermission: 'editable', dbURL: '', diff --git a/lib/config/environment.js b/lib/config/environment.js index 31f3c6fc5..da50a660d 100644 --- a/lib/config/environment.js +++ b/lib/config/environment.js @@ -33,6 +33,7 @@ module.exports = { allowAnonymousEdits: toBooleanConfig(process.env.CMD_ALLOW_ANONYMOUS_EDITS), allowFreeURL: toBooleanConfig(process.env.CMD_ALLOW_FREEURL), requireFreeURLAuthentication: toBooleanConfig(process.env.CMD_REQUIRE_FREEURL_AUTHENTICATION), + disableNoteCreation: toBooleanConfig(process.env.CMD_DISABLE_NOTE_CREATION), forbiddenNoteIDs: toArrayConfig(process.env.CMD_FORBIDDEN_NOTE_IDS), defaultPermission: process.env.CMD_DEFAULT_PERMISSION, dbURL: process.env.CMD_DB_URL, diff --git a/lib/web/note/controller.js b/lib/web/note/controller.js index 6626782e0..9ac081b5a 100644 --- a/lib/web/note/controller.js +++ b/lib/web/note/controller.js @@ -82,6 +82,9 @@ exports.showNote = function (req, res, next) { } exports.createFromPOST = function (req, res, next) { + if (config.disableNoteCreation) { + return errors.errorForbidden(res) + } let body = '' if (req.body && req.body.length > config.documentMaxLength) { return errors.errorTooLong(res) diff --git a/lib/web/note/util.js b/lib/web/note/util.js index 6604ea35a..7be117bd8 100644 --- a/lib/web/note/util.js +++ b/lib/web/note/util.js @@ -19,7 +19,11 @@ exports.findNote = function (req, res, callback, include = null, createIfNotFoun include: include || null }).then(function (note) { if (!note && createIfNotFound) { - return exports.newNote(req, res, '') + if (config.disableNoteCreation) { + return errors.errorNotFound(res) + } else { + return exports.newNote(req, res, '') + } } if (!note && !createIfNotFound) { return errors.errorNotFound(res) diff --git a/public/docs/release-notes.md b/public/docs/release-notes.md index 24d8e0c95..f9e65c9ac 100644 --- a/public/docs/release-notes.md +++ b/public/docs/release-notes.md @@ -4,6 +4,7 @@ ### Enhancements - Add a pointer to Mermaid 9.1.7 documentation, which is what HedgeDoc 1 supports. +- Add `disableNoteCreation` config option for read-only instances ### Bugfixes - Fix a crash when having numeric-only values in opengraph frontmatter diff --git a/public/views/hedgedoc/header.ejs b/public/views/hedgedoc/header.ejs index ff58f1729..141959eb5 100644 --- a/public/views/hedgedoc/header.ejs +++ b/public/views/hedgedoc/header.ejs @@ -22,8 +22,10 @@ <i class="fa fa-caret-down"></i> </a> <ul class="dropdown-menu list" role="menu" aria-labelledby="menu"> + <% if (!disableNoteCreation) { %> <li role="presentation"><a role="menuitem" class="ui-new" tabindex="-1" href="<%- serverURL %>/new" target="_blank" rel="noopener"><i class="fa fa-plus fa-fw"></i> <%= __('New') %></a> </li> + <% } %> <li role="presentation"><a role="menuitem" class="ui-publish" tabindex="-1" href="#" target="_blank" rel="noopener"><i class="fa fa-share-square-o fa-fw"></i> <%= __('Publish') %></a> </li> <li class="divider"></li> @@ -112,11 +114,13 @@ </li> </ul> <ul class="nav navbar-nav navbar-right" style="padding:0;"> + <% if (!disableNoteCreation) { %> <li> <a href="<%- serverURL %>/new" target="_blank" rel="noopener" class="ui-new"> <i class="fa fa-plus"></i> <%= __('New') %> </a> </li> + <% } %> <li> <a href="#" target="_blank" rel="noopener" class="ui-publish"> <i class="fa fa-share-square-o"></i> <%= __('Publish') %> diff --git a/public/views/index/body.ejs b/public/views/index/body.ejs index 814ac49c1..41f37015b 100644 --- a/public/views/index/body.ejs +++ b/public/views/index/body.ejs @@ -12,7 +12,7 @@ <li class="ui-history<% if(signin) { %> active<% } %>"><a href="#"><%= __('History') %></a> </li> <div class="ui-signin" style="float: right; margin-top: 8px;<% if(signin) { %> display: none;<% } %>"> - <% if (allowAnonymous) { %> + <% if (allowAnonymous && !disableNoteCreation) { %> <a type="button" href="<%- serverURL %>/new" class="btn btn-sm btn-primary"><i class="fa fa-plus"></i> <%= __('New guest note') %></a> <% } %> <% if (authProviders.facebook || authProviders.twitter || authProviders.github || authProviders.gitlab || authProviders.mattermost || authProviders.dropbox || authProviders.google || authProviders.ldap || authProviders.saml || authProviders.oauth2 || authProviders.email) { %> @@ -20,7 +20,9 @@ <% } %> </div> <div class="ui-signout" style="float: right; margin-top: 8px;<% if(!signin) { %> display: none;<% } %>"> + <% if (!disableNoteCreation) { %> <a type="button" href="<%- serverURL %>/new" class="btn btn-sm btn-primary"><i class="fa fa-plus"></i> <%= __('New note') %></a> + <% } %> <span class="ui-profile dropdown pull-right"> <button id="profileLabel" class="btn btn-sm btn-link ui-profile-label" style="padding-right: 0;" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <img class="ui-avatar" width="20" height="20"><span class="hidden-xs hidden-sm"> <span class="ui-name"></span></span> <i class="fa fa-caret-down"></i>