Skip to content

Commit

Permalink
feat: added html sanitizer for remote rendering (#1128)
Browse files Browse the repository at this point in the history
Co-authored-by: Joe Pea <joe@trusktr.io>
  • Loading branch information
anikethsaha and trusktr committed Jun 17, 2020
1 parent 0bf03f5 commit 714ef29
Show file tree
Hide file tree
Showing 8 changed files with 2,074 additions and 1,071 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Expand Up @@ -19,6 +19,7 @@ module.exports = {
rules: {
'prettier/prettier': ['error'],
camelcase: ['warn'],
'no-useless-escape': ['warn'],
curly: ['error', 'all'],
'dot-notation': ['error'],
eqeqeq: ['error'],
Expand Down
3,075 changes: 2,007 additions & 1,068 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion package.json
Expand Up @@ -57,6 +57,7 @@
"*.js": "eslint --fix"
},
"dependencies": {
"dompurify": "^2.0.8",
"marked": "^0.7.0",
"medium-zoom": "^1.0.5",
"opencollective-postinstall": "^2.0.2",
Expand All @@ -82,7 +83,7 @@
"esm": "^3.1.4",
"husky": "^3.1.0",
"jsdom": "^16.2.2",
"lerna": "^3.17.0",
"lerna": "^3.22.1",
"lint-staged": "^10.1.2",
"live-server": "^1.2.1",
"mkdirp": "^0.5.1",
Expand Down
31 changes: 29 additions & 2 deletions packages/docsify-server-renderer/index.js
Expand Up @@ -3,6 +3,7 @@ import { resolve, basename } from 'path';
import resolvePathname from 'resolve-pathname';
import fetch from 'node-fetch';
import debug from 'debug';
import DOMPurify from 'dompurify';
import { AbstractHistory } from '../../src/core/router/history/abstract';
import { Compiler } from '../../src/core/render/compiler';
import { isAbsolutePath } from '../../src/core/router/util';
Expand All @@ -13,6 +14,32 @@ function cwd(...args) {
return resolve(process.cwd(), ...args);
}

function isExternal(url) {
let match = url.match(
/^([^:\/?#]+:)?(?:\/\/([^\/?#]*))?([^?#]+)?(\?[^#]*)?(#.*)?/
);
if (
typeof match[1] === 'string' &&
match[1].length > 0 &&
match[1].toLowerCase() !== location.protocol
) {
return true;
}
if (
typeof match[2] === 'string' &&
match[2].length > 0 &&
match[2].replace(
new RegExp(
':(' + { 'http:': 80, 'https:': 443 }[location.protocol] + ')?$'
),
''
) !== location.host
) {
return true;
}
return false;
}

function mainTpl(config) {
let html = `<nav class="app-nav${
config.repo ? '' : ' no-badge'
Expand Down Expand Up @@ -60,6 +87,7 @@ export default class Renderer {

async renderToString(url) {
this.url = url = this.router.parse(url).path;
this.isRemoteUrl = isExternal(this.url);
const { loadSidebar, loadNavbar, coverpage } = this.config;

const mainFile = this._getPath(url);
Expand Down Expand Up @@ -95,9 +123,8 @@ export default class Renderer {
this._renderHtml('cover', await this._render(coverFile), 'cover');
}

const html = this.html;
const html = this.isRemoteUrl ? DOMPurify.sanitize(this.html) : this.html;
this.html = this.template;

return html;
}

Expand Down
5 changes: 5 additions & 0 deletions packages/docsify-server-renderer/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/docsify-server-renderer/package.json
Expand Up @@ -17,6 +17,7 @@
"dependencies": {
"debug": "^4.1.1",
"docsify": "^4.11.2",
"dompurify": "^2.0.8",
"node-fetch": "^2.6.0",
"resolve-pathname": "^3.0.0"
}
Expand Down
27 changes: 27 additions & 0 deletions src/core/fetch/index.js
Expand Up @@ -20,6 +20,32 @@ function loadNested(path, qs, file, next, vm, first) {
).then(next, _ => loadNested(path, qs, file, next, vm));
}

function isExternal(url) {
let match = url.match(
/^([^:\/?#]+:)?(?:\/\/([^\/?#]*))?([^?#]+)?(\?[^#]*)?(#.*)?/
);
if (
typeof match[1] === 'string' &&
match[1].length > 0 &&
match[1].toLowerCase() !== location.protocol
) {
return true;
}
if (
typeof match[2] === 'string' &&
match[2].length > 0 &&
match[2].replace(
new RegExp(
':(' + { 'http:': 80, 'https:': 443 }[location.protocol] + ')?$'
),
''
) !== location.host
) {
return true;
}
return false;
}

export function fetchMixin(proto) {
let last;

Expand Down Expand Up @@ -84,6 +110,7 @@ export function fetchMixin(proto) {
const file = this.router.getFile(path);
const req = request(file + qs, true, requestHeaders);

this.isRemoteUrl = isExternal(file);
// Current page is html
this.isHTML = /\.html$/g.test(file);

Expand Down
2 changes: 2 additions & 0 deletions src/core/render/index.js
@@ -1,5 +1,6 @@
/* eslint-disable no-unused-vars */
import tinydate from 'tinydate';
import DOMPurify from 'dompurify';
import * as dom from '../util/dom';
import cssVars from '../util/polyfill/css-vars';
import { callHook } from '../init/lifecycle';
Expand Down Expand Up @@ -172,6 +173,7 @@ export function renderMixin(proto) {
},
tokens => {
html = this.compiler.compile(tokens);
html = this.isRemoteUrl ? DOMPurify.sanitize(html) : html;
callback();
next();
}
Expand Down

1 comment on commit 714ef29

@vercel
Copy link

@vercel vercel bot commented on 714ef29 Jun 17, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.