From a2522888b234ec9bd5ac08e34e751e285662f583 Mon Sep 17 00:00:00 2001 From: Sheogorath Date: Wed, 26 Feb 2020 14:52:55 +0100 Subject: [PATCH] Remove PDF export As we already decleared in earlier versions, this patch removes PDF export entirely. It's a not acceptable security risk for every CodiMD instance. The current implementation allowed to extract arbitary files from the CodiMD host and therefore leaking secrets from a `/etc/passwd` to CodiMD's own config files and all secrets contained in it. Thanks to Joona for finding this vulnerability in August last year, which lead to an emergency disabling of PDF exports in 1.5.0. Signed-off-by: Sheogorath --- app.json | 4 ---- docs/configuration-config-file.md | 1 - docs/configuration-env-vars.md | 1 - docs/dev/api.md | 3 +-- docs/dev/openapi.yml | 23 --------------------- docs/setup/docker-linuxserver.md | 2 +- lib/app.js | 1 - lib/config/default.js | 1 - lib/config/environment.js | 1 - lib/config/hackmdEnvironment.js | 3 +-- lib/config/index.js | 7 ------- lib/config/oldDefault.js | 3 +-- lib/web/note/actions.js | 32 ----------------------------- lib/web/note/controller.ts | 8 -------- package.json | 1 - public/js/index.js | 2 -- public/js/lib/editor/ui-elements.js | 3 +-- public/views/codimd/header.ejs | 8 -------- 18 files changed, 5 insertions(+), 99 deletions(-) diff --git a/app.json b/app.json index 8642e0b28..63d6b323b 100644 --- a/app.json +++ b/app.json @@ -127,10 +127,6 @@ "CMD_IMGUR_CLIENTID": { "description": "Imgur API client id", "required": false - }, - "CMD_ALLOW_PDF_EXPORT": { - "description": "Enable or disable PDF exports", - "required": false } }, "addons": [ diff --git a/docs/configuration-config-file.md b/docs/configuration-config-file.md index d26d24f61..e01922594 100644 --- a/docs/configuration-config-file.md +++ b/docs/configuration-config-file.md @@ -24,7 +24,6 @@ to `config.json` before filling in your own details. | variables | example values | description | | --------- | ------ | ----------- | -| `allowPDFExport` | `true` | Whether or not PDF export is offered. | | `db` | `{ "dialect": "sqlite", "storage": "./db.codimd.sqlite" }` | set the db configs, [see more here](http://sequelize.readthedocs.org/en/latest/api/sequelize/) | | `dbURL` | `mysql://localhost:3306/database` | Set the db in URL style. If set, then the relevant `db` config entries will be overridden. | | `forbiddenNoteIDs` | `['robots.txt']` | disallow creation of notes, even if `allowFreeUrl` is `true` | diff --git a/docs/configuration-env-vars.md b/docs/configuration-env-vars.md index 41695517f..81a878b1f 100644 --- a/docs/configuration-env-vars.md +++ b/docs/configuration-env-vars.md @@ -28,7 +28,6 @@ defaultNotePath can't be set from env-vars | variable | example value | description | | -------- | ------------- | ----------- | -| `CMD_ALLOW_PDF_EXPORT` | `true` or `false` | Enable or disable PDF exports | | `CMD_CONFIG_FILE` | `/path/to/config.json` | optional override for the path to CodiMD's config file | | `CMD_DB_URL` | `mysql://localhost:3306/database` | Set the db in URL style. If set, then the relevant `db` config entries will be overridden. | | `CMD_LOGLEVEL` | `info`, `debug` ... | Defines what kind of logs are provided to stdout. | diff --git a/docs/dev/api.md b/docs/dev/api.md index 4c1365b5b..c27e1d4a6 100644 --- a/docs/dev/api.md +++ b/docs/dev/api.md @@ -5,7 +5,7 @@ For code-autogeneration there is an OpenAPIv3-compatible description available [ ## Notes These endpoints create notes, return information about them or export them. -You have to replace _\_ with either the alias or id of a note you want to work on. +You have to replace _\_ with either the alias or id of a note you want to work on. | Endpoint | HTTP-Method | Description | |---|---|---| @@ -13,7 +13,6 @@ You have to replace _\_ with either the alias or id of a note you want to | `/new` | `POST` | **Imports some markdown data into a new note.**
A random id will be assigned and the content will equal to the body of the received HTTP-request. The `Content-Type: text/markdown` header should be set on this request. | | `/new/` | `POST` | **Imports some markdown data into a new note with a given alias.**
This endpoint equals to the above one except that the alias from the url will be assigned to the note if [FreeURL-mode](../configuration-env-vars.md#users-and-privileges) is enabled. | | `//download` or `/s//download` | `GET` | **Returns the raw markdown content of a note.** | -| `//pdf` | `GET` | **Returns a generated pdf version of the note.**
If pdf-support is disabled, a HTTP 403 will be returned.
_Please note: Currently pdf export is disabled generally because of a security problem with it._ | | `//publish` | `GET` | **Redirects to the published version of the note.** | | `//slide` | `GET` | **Redirects to the slide-presentation of the note.**
This is only useful on notes which are designed to be slides. | | `//info` | `GET` | **Returns metadata about the note.**
This includes the title and description of the note as well as the creation date and viewcount. The data is returned as a JSON object. | diff --git a/docs/dev/openapi.yml b/docs/dev/openapi.yml index 4d3e31f6d..66e161beb 100644 --- a/docs/dev/openapi.yml +++ b/docs/dev/openapi.yml @@ -89,29 +89,6 @@ paths: 'text/plain': example: my-note - /{note}/pdf: - get: - tags: - - note - summary: Returns a generated pdf version of the note. - description: 'If pdf-support is disabled, a HTTP 403 will be returned.
_Please note: Currently pdf export is disabled generally because of a security problem with it._' - responses: - 200: - description: The generated pdf version of the note - content: - 'application/pdf': - example: binary - 404: - description: Note does not exist - parameters: - - name: note - in: path - required: true - description: The note which should be exported as pdf - content: - 'text/plain': - example: my-note - /{note}/publish: get: tags: diff --git a/docs/setup/docker-linuxserver.md b/docs/setup/docker-linuxserver.md index f99176e8e..2b6c09738 100644 --- a/docs/setup/docker-linuxserver.md +++ b/docs/setup/docker-linuxserver.md @@ -2,7 +2,7 @@ LinuxServer.io CodiMD Image === [![LinuxServer.io Discord](https://img.shields.io/discord/354974912613449730.svg?logo=discord&label=LSIO%20Discord&style=flat-square)](https://discord.gg/YWrKVTn)[![container version badge](https://images.microbadger.com/badges/version/linuxserver/codimd.svg)](https://microbadger.com/images/linuxserver/codimd "Get your own version badge on microbadger.com")[![container image size badge](https://images.microbadger.com/badges/image/linuxserver/codimd.svg)](https://microbadger.com/images/linuxserver/codimd "Get your own version badge on microbadger.com")![Docker Pulls](https://img.shields.io/docker/pulls/linuxserver/codimd.svg)![Docker Stars](https://img.shields.io/docker/stars/linuxserver/codimd.svg)[![Build Status](https://ci.linuxserver.io/buildStatus/icon?job=Docker-Pipeline-Builders/docker-codimd/master)](https://ci.linuxserver.io/job/Docker-Pipeline-Builders/job/docker-codimd/job/master/)[![LinuxServer.io CI summary](https://lsio-ci.ams3.digitaloceanspaces.com/linuxserver/codimd/latest/badge.svg)](https://lsio-ci.ams3.digitaloceanspaces.com/linuxserver/codimd/latest/index.html) -[LinuxServer.io](https://linuxserver.io) have created an Ubuntu-based multi-arch container image for x86-64, arm64 and armhf which supports PDF export from all architectures using [PhantomJS](https://phantomjs.org/). +[LinuxServer.io](https://linuxserver.io) have created an Ubuntu-based multi-arch container image for x86-64, arm64 and armhf. - It supports all the environment variables detailed in the [configuration documentation](../configuration-env-vars.md) to modify it according to your needs. diff --git a/lib/app.js b/lib/app.js index 69b78871a..6b1db1aa9 100644 --- a/lib/app.js +++ b/lib/app.js @@ -182,7 +182,6 @@ app.locals.serverURL = config.serverURL app.locals.sourceURL = config.sourceURL app.locals.allowAnonymous = config.allowAnonymous app.locals.allowAnonymousEdits = config.allowAnonymousEdits -app.locals.allowPDFExport = config.allowPDFExport app.locals.authProviders = { facebook: config.isFacebookEnable, twitter: config.isTwitterEnable, diff --git a/lib/config/default.js b/lib/config/default.js index bb51f3e2a..46c89a4f3 100644 --- a/lib/config/default.js +++ b/lib/config/default.js @@ -153,7 +153,6 @@ module.exports = { email: true, allowEmailRegister: true, allowGravatar: true, - allowPDFExport: true, openID: false, // linkifyHeaderStyle - How is a header text converted into a link id. // Header Example: "3.1. Good Morning my Friend! - Do you have 5$?" diff --git a/lib/config/environment.js b/lib/config/environment.js index 5be42c65d..d7dff6727 100644 --- a/lib/config/environment.js +++ b/lib/config/environment.js @@ -129,7 +129,6 @@ module.exports = { email: toBooleanConfig(process.env.CMD_EMAIL), allowEmailRegister: toBooleanConfig(process.env.CMD_ALLOW_EMAIL_REGISTER), allowGravatar: toBooleanConfig(process.env.CMD_ALLOW_GRAVATAR), - allowPDFExport: toBooleanConfig(process.env.CMD_ALLOW_PDF_EXPORT), openID: toBooleanConfig(process.env.CMD_OPENID), linkifyHeaderStyle: process.env.CMD_LINKIFY_HEADER_STYLE } diff --git a/lib/config/hackmdEnvironment.js b/lib/config/hackmdEnvironment.js index 26141f50a..e7795b458 100644 --- a/lib/config/hackmdEnvironment.js +++ b/lib/config/hackmdEnvironment.js @@ -115,6 +115,5 @@ module.exports = { } }, email: toBooleanConfig(process.env.HMD_EMAIL), - allowEmailRegister: toBooleanConfig(process.env.HMD_ALLOW_EMAIL_REGISTER), - allowPDFExport: toBooleanConfig(process.env.HMD_ALLOW_PDF_EXPORT) + allowEmailRegister: toBooleanConfig(process.env.HMD_ALLOW_EMAIL_REGISTER) } diff --git a/lib/config/index.js b/lib/config/index.js index 1e2b8e898..cee9cd73f 100644 --- a/lib/config/index.js +++ b/lib/config/index.js @@ -119,7 +119,6 @@ config.isGitLabEnable = config.gitlab.clientID && config.gitlab.clientSecret config.isLDAPEnable = config.ldap.url config.isSAMLEnable = config.saml.idpSsoUrl config.isOAuth2Enable = config.oauth2.clientID && config.oauth2.clientSecret -config.isPDFExportEnable = config.allowPDFExport // Check gitlab api version if (config.gitlab && config.gitlab.version !== 'v4' && config.gitlab.version !== 'v3') { @@ -188,12 +187,6 @@ switch (config.imageUploadType) { ] } -// Disable PDF export due to security issue -if (config.allowPDFExport) { - config.allowPDFExport = false - logger.warn('PDF export was disabled for this release to mitigate a critical security issue. This feature will hopefully become available again in future releases.') -} - // generate correct path config.sslCAPath.forEach(function (capath, i, array) { array[i] = path.resolve(appRootPath, capath) diff --git a/lib/config/oldDefault.js b/lib/config/oldDefault.js index 90942951d..738ad9f7d 100644 --- a/lib/config/oldDefault.js +++ b/lib/config/oldDefault.js @@ -37,6 +37,5 @@ module.exports = { // document documentmaxlength: undefined, imageuploadtype: undefined, - allowemailregister: undefined, - allowpdfexport: undefined + allowemailregister: undefined } diff --git a/lib/web/note/actions.js b/lib/web/note/actions.js index 9ff7fedbf..80572194f 100644 --- a/lib/web/note/actions.js +++ b/lib/web/note/actions.js @@ -4,7 +4,6 @@ const config = require('../../config') const errors = require('../../errors') const fs = require('fs') const shortId = require('shortid') -const markdownpdf = require('markdown-pdf') const moment = require('moment') const querystring = require('querystring') @@ -33,37 +32,6 @@ exports.getInfo = function getInfo (req, res, note) { res.send(data) } -exports.createPDF = function createPDF (req, res, note) { - const url = config.serverURL || 'http://' + req.get('host') - const body = note.content - const extracted = models.Note.extractMeta(body) - let content = extracted.markdown - const title = models.Note.decodeTitle(note.title) - - if (!fs.existsSync(config.tmpPath)) { - fs.mkdirSync(config.tmpPath) - } - const path = config.tmpPath + '/' + Date.now() + '.pdf' - content = content.replace(/\]\(\//g, '](' + url + '/') - markdownpdf().from.string(content).to(path, function () { - if (!fs.existsSync(path)) { - logger.error('PDF seems to not be generated as expected. File doesn\'t exist: ' + path) - return errors.errorInternalError(res) - } - const stream = fs.createReadStream(path) - let filename = title - // Be careful of special characters - filename = encodeURIComponent(filename) - // Ideally this should strip them - res.setHeader('Content-disposition', 'attachment; filename="' + filename + '.pdf"') - res.setHeader('Cache-Control', 'private') - res.setHeader('Content-Type', 'application/pdf; charset=UTF-8') - res.setHeader('X-Robots-Tag', 'noindex, nofollow') // prevent crawling - stream.pipe(res) - fs.unlinkSync(path) - }) -} - exports.createGist = function createGist (req, res, note) { const data = { client_id: config.github.clientID, diff --git a/lib/web/note/controller.ts b/lib/web/note/controller.ts index d59d2d80b..503511889 100644 --- a/lib/web/note/controller.ts +++ b/lib/web/note/controller.ts @@ -111,14 +111,6 @@ export module NoteController { case 'info': noteActions.getInfo(req, res, note); break; - case 'pdf': - if (config.allowPDFExport) { - noteActions.createPDF(req, res, note) - } else { - logger.error('PDF export failed: Disabled by config. Set "allowPDFExport: true" to enable. Check the documentation for details'); - errors.errorForbidden(res) - } - break; case 'gist': noteActions.createGist(req, res, note); break; diff --git a/package.json b/package.json index 0b7ffc3dd..c69229921 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,6 @@ "markdown-it-regexp": "^0.4.0", "markdown-it-sub": "^1.0.0", "markdown-it-sup": "^1.0.0", - "markdown-pdf": "^10.0.0", "mathjax": "~2.7.6", "mermaid": "~8.4.6", "meta-marked": "git+https://github.com/codimd/meta-marked#semver:^0.4.5", diff --git a/public/js/index.js b/public/js/index.js index de3c8a6df..ca28c3c89 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -941,8 +941,6 @@ ui.toolbar.download.rawhtml.click(function (e) { e.stopPropagation() exportToRawHTML(ui.area.markdown) }) -// pdf -ui.toolbar.download.pdf.attr('download', '').attr('href', noteurl + '/pdf') // export to dropbox ui.toolbar.export.dropbox.click(function () { var filename = renderFilename(ui.area.markdown) + '.md' diff --git a/public/js/lib/editor/ui-elements.js b/public/js/lib/editor/ui-elements.js index ce19436bf..b1e3b5cb1 100644 --- a/public/js/lib/editor/ui-elements.js +++ b/public/js/lib/editor/ui-elements.js @@ -17,8 +17,7 @@ export const getUIElements = () => ({ download: { markdown: $('.ui-download-markdown'), html: $('.ui-download-html'), - rawhtml: $('.ui-download-raw-html'), - pdf: $('.ui-download-pdf-beta') + rawhtml: $('.ui-download-raw-html') }, export: { dropbox: $('.ui-save-dropbox'), diff --git a/public/views/codimd/header.ejs b/public/views/codimd/header.ejs index 6bf37804d..d313a2e5e 100644 --- a/public/views/codimd/header.ejs +++ b/public/views/codimd/header.ejs @@ -63,10 +63,6 @@
  • <%= __('Raw HTML') %>
  • - <% if(typeof allowPDFExport !== 'undefined' && allowPDFExport) {%> -
  • PDF (Beta) -
  • - <% } %>
  • Help
  • @@ -162,10 +158,6 @@
  • <%= __('Raw HTML') %>
  • - <% if(typeof allowPDFExport !== 'undefined' && allowPDFExport) {%> -
  • PDF (Beta) -
  • - <% } %>