Skip to content

Commit

Permalink
Merge pull request #30 from declandewet/escape
Browse files Browse the repository at this point in the history
implement sanitization
  • Loading branch information
Declan de Wet authored Nov 23, 2016
2 parents cd6a1e5 + ff6d7cc commit ad1bad1
Show file tree
Hide file tree
Showing 5 changed files with 320 additions and 253 deletions.
25 changes: 23 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
> **Please note** that this project is still in very early alpha development and is *not* considered to be production ready.
> **You have been warned.** There is no sanitization yet, hardly any tests, and you might find some bugs.
> **You have been warned.** There might still be a few bugs and many tests have yet to be written.
<p align="center">
<img src="http://imgur.com/258WtHI.png" alt="vue-meta">
Expand Down Expand Up @@ -90,7 +90,7 @@ These properties, when set on a deeply nested component, will cleverly overwrite
# Disclaimer

**Please note** that this project is still in very early alpha development and is *not* considered to be production ready.
**You have been warned.** There is no sanitization yet, hardly any tests, and you might find some bugs.
**You have been warned.** There might still be a few bugs and many tests have yet to be written.

# Installation

Expand Down Expand Up @@ -506,6 +506,27 @@ Each item in the array maps to a newly-created `<noscript>` element, where objec
<noscript>This website requires JavaScript.</noscript>
```

#### `__dangerouslyDisableSanitizers` ([String])

By default, `vue-meta` sanitizes HTML entities in _every_ property. You can disable this behaviour on a per-property basis using `__dangerouslyDisableSantizers`. Just pass it a list of properties you want sanitization to be disabled on:

```js
{
metaInfo: {
title: '<I will be sanitized>',
meta: [{ vmid: 'description', name: 'description', content: '& I will not be <sanitized>'}],
__dangerouslyDisableSanitizers: ['meta']
}
}
```

```html
<title>&lt;I will be sanitized&gt;</title>
<meta vmid="description" name="description" content="& I will not be <sanitized>">
```

:warning: **Using this option is not recommended unless you know exactly what you are doing.** By disabling sanitization, you are opening potential vectors for attacks such as SQL injection & Cross-Site Scripting (XSS). Be very careful to not compromise your application.

#### `changed` (Function)

Will be called when the client `metaInfo` updates/changes. Receives the following parameters:
Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
"bugs": "https://github.com/declandewet/vue-meta/issues",
"dependencies": {
"deepmerge": "^1.2.0",
"lodash.escape": "^4.0.1",
"lodash.isplainobject": "^4.0.6",
"object-assign": "^4.1.0"
},
"devDependencies": {
Expand Down Expand Up @@ -52,6 +54,7 @@
"vue": "^2.0.3",
"vue-loader": "^10.0.0",
"vue-router": "^2.0.1",
"vue-template-compiler": "^2.1.0",
"vuex": "^2.0.0",
"webpack": "beta",
"webpack-dev-server": "beta"
Expand Down
38 changes: 35 additions & 3 deletions src/shared/getMetaInfo.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import deepmerge from 'deepmerge'
import escapeHTML from 'lodash.escape'
import isPlainObject from 'lodash.isplainobject'
import isArray from './isArray'
import getComponentOption from './getComponentOption'

export default function _getMetaInfo (options = {}) {
Expand All @@ -23,11 +26,12 @@ export default function _getMetaInfo (options = {}) {
link: [],
style: [],
script: [],
noscript: []
noscript: [],
__dangerouslyDisableSanitizers: []
}

// collect & aggregate all metaInfo $options
const info = getComponentOption({
let info = getComponentOption({
component,
option: keyName,
deep: true,
Expand Down Expand Up @@ -73,6 +77,34 @@ export default function _getMetaInfo (options = {}) {
info.base = Object.keys(info.base).length ? [info.base] : []
}

return deepmerge(defaultInfo, info)
// sanitizes potentially dangerous characters
const escape = (info) => Object.keys(info).reduce((escaped, key) => {
const ref = info.__dangerouslyDisableSanitizers
const isDisabled = ref && ref.indexOf(key) > -1
const val = info[key]
if (!isDisabled) {
if (typeof val === 'string') {
escaped[key] = escapeHTML(val)
} else if (isPlainObject(val)) {
escaped[key] = escape(val)
} else if (isArray(val)) {
escaped[key] = val.map(escape)
} else {
escaped[key] = val
}
} else {
escaped[key] = val
}

return escaped
}, {})

// merge with defaults
info = deepmerge(defaultInfo, info)

// begin sanitization
info = escape(info)

return info
}
}
10 changes: 10 additions & 0 deletions src/shared/isArray.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* checks if passed argument is an array
* @param {any} arr - the object to check
* @return {Boolean} - true if `arr` is an array
*/
export default function isArray (arr) {
return Array.isArray
? Array.isArray(arr)
: Object.prototype.toString.call(arr) === '[object Array]'
}
Loading

0 comments on commit ad1bad1

Please sign in to comment.