Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change "whitelist" to "allowlist" #31066

Merged
merged 14 commits into from
Jun 19, 2020
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build/change-version.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ function main(args) {
'vendor'
])
const INCLUDED_EXTENSIONS = new Set([
// This extension whitelist is how we avoid modifying binary files
// This extension allowlist is how we avoid modifying binary files
'',
'.css',
'.html',
Expand Down
12 changes: 6 additions & 6 deletions js/src/tooltip.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
typeCheckConfig
} from './util/index'
import {
DefaultWhitelist,
DefaultAllowlist,
sanitizeHtml
} from './util/sanitizer'
import Data from './dom/data'
Expand All @@ -38,7 +38,7 @@ const DATA_KEY = 'bs.tooltip'
const EVENT_KEY = `.${DATA_KEY}`
const CLASS_PREFIX = 'bs-tooltip'
const BSCLS_PREFIX_REGEX = new RegExp(`(^|\\s)${CLASS_PREFIX}\\S+`, 'g')
const DISALLOWED_ATTRIBUTES = ['sanitize', 'whiteList', 'sanitizeFn']
const DISALLOWED_ATTRIBUTES = ['sanitize', 'allowList', 'sanitizeFn']

const DefaultType = {
animation: 'boolean',
Expand All @@ -55,7 +55,7 @@ const DefaultType = {
boundary: '(string|element)',
sanitize: 'boolean',
sanitizeFn: '(null|function)',
whiteList: 'object',
allowList: 'object',
popperConfig: '(null|object)'
}

Expand Down Expand Up @@ -84,7 +84,7 @@ const Default = {
boundary: 'scrollParent',
sanitize: true,
sanitizeFn: null,
whiteList: DefaultWhitelist,
allowList: DefaultAllowlist,
popperConfig: null
}

Expand Down Expand Up @@ -428,7 +428,7 @@ class Tooltip {

if (this.config.html) {
if (this.config.sanitize) {
content = sanitizeHtml(content, this.config.whiteList, this.config.sanitizeFn)
content = sanitizeHtml(content, this.config.allowList, this.config.sanitizeFn)
}

element.innerHTML = content
Expand Down Expand Up @@ -711,7 +711,7 @@ class Tooltip {
typeCheckConfig(NAME, config, this.constructor.DefaultType)

if (config.sanitize) {
config.template = sanitizeHtml(config.template, config.whiteList, config.sanitizeFn)
config.template = sanitizeHtml(config.template, config.allowList, config.sanitizeFn)
}

return config
Expand Down
12 changes: 6 additions & 6 deletions js/src/util/sanitizer.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ const allowedAttribute = (attr, allowedAttributeList) => {
return false
}

export const DefaultWhitelist = {
export const DefaultAllowlist = {
// Global attributes allowed on any supplied element below.
'*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],
a: ['target', 'href', 'title', 'rel'],
Expand Down Expand Up @@ -89,7 +89,7 @@ export const DefaultWhitelist = {
ul: []
}

export function sanitizeHtml(unsafeHtml, whiteList, sanitizeFn) {
export function sanitizeHtml(unsafeHtml, allowList, sanitizeFn) {
if (!unsafeHtml.length) {
return unsafeHtml
}
Expand All @@ -100,24 +100,24 @@ export function sanitizeHtml(unsafeHtml, whiteList, sanitizeFn) {

const domParser = new window.DOMParser()
const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html')
const whitelistKeys = Object.keys(whiteList)
const allowlistKeys = Object.keys(allowList)
const elements = [].concat(...createdDocument.body.querySelectorAll('*'))

for (let i = 0, len = elements.length; i < len; i++) {
const el = elements[i]
const elName = el.nodeName.toLowerCase()

if (whitelistKeys.indexOf(elName) === -1) {
if (allowlistKeys.indexOf(elName) === -1) {
el.parentNode.removeChild(el)

continue
}

const attributeList = [].concat(...el.attributes)
const whitelistedAttributes = [].concat(whiteList['*'] || [], whiteList[elName] || [])
const allowedAttributes = [].concat(allowList['*'] || [], allowList[elName] || [])

attributeList.forEach(attr => {
if (!allowedAttribute(attr, whitelistedAttributes)) {
if (!allowedAttribute(attr, allowedAttributes)) {
el.removeAttribute(attr.nodeName)
}
})
Expand Down
14 changes: 7 additions & 7 deletions js/tests/unit/util/sanitizer.spec.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { DefaultWhitelist, sanitizeHtml } from '../../../src/util/sanitizer'
import { DefaultAllowlist, sanitizeHtml } from '../../../src/util/sanitizer'

describe('Sanitizer', () => {
describe('sanitizeHtml', () => {
it('should return the same on empty string', () => {
const empty = ''

const result = sanitizeHtml(empty, DefaultWhitelist, null)
const result = sanitizeHtml(empty, DefaultAllowlist, null)

expect(result).toEqual(empty)
})
Expand All @@ -18,7 +18,7 @@ describe('Sanitizer', () => {
'</div>'
].join('')

const result = sanitizeHtml(template, DefaultWhitelist, null)
const result = sanitizeHtml(template, DefaultAllowlist, null)

expect(result.indexOf('script') === -1).toEqual(true)
})
Expand All @@ -30,20 +30,20 @@ describe('Sanitizer', () => {
'</div>'
].join('')

const result = sanitizeHtml(template, DefaultWhitelist, null)
const result = sanitizeHtml(template, DefaultAllowlist, null)

expect(result.indexOf('aria-pressed') !== -1).toEqual(true)
expect(result.indexOf('class="test"') !== -1).toEqual(true)
})

it('should remove not whitelist tags', () => {
it('should remove tags not in allowlist', () => {
const template = [
'<div>',
' <script>alert(7)</script>',
'</div>'
].join('')

const result = sanitizeHtml(template, DefaultWhitelist, null)
const result = sanitizeHtml(template, DefaultAllowlist, null)

expect(result.indexOf('<script>') === -1).toEqual(true)
})
Expand All @@ -61,7 +61,7 @@ describe('Sanitizer', () => {

spyOn(DOMParser.prototype, 'parseFromString')

const result = sanitizeHtml(template, DefaultWhitelist, mySanitize)
const result = sanitizeHtml(template, DefaultAllowlist, mySanitize)

expect(result).toEqual(template)
expect(DOMParser.prototype.parseFromString).not.toHaveBeenCalled()
Expand Down
6 changes: 3 additions & 3 deletions site/content/docs/5.0/components/popovers.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,15 +142,15 @@ To allow keyboard users to activate your popovers, you should only add them to H

While you can insert rich, structured HTML in popovers with the `html` option, we strongly recommend that you avoid adding an excessive amount of content. The way popovers currently work is that, once displayed, their content is tied to the trigger element with the `aria-describedby` attribute. As a result, the entirety of the popover's content will be announced to assistive technology users as one long, uninterrupted stream.

Additionally, while it is possible to also include interactive controls (such as form elements or links) in your popover (by adding these elements to the `whiteList` or allowed attributes and tags), be aware that currently the popover does not manage keyboard focus order. When a keyboard user opens a popover, focus remains on the triggering element, and as the popover usually does not immediately follow the trigger in the document's structure, there is no guarantee that moving forward/pressing <kbd>TAB</kbd> will move a keyboard user into the popover itself. In short, simply adding interactive controls to a popover is likely to make these controls unreachable/unusable for keyboard users and users of assistive technologies, or at the very least make for an illogical overall focus order. In these cases, consider using a modal dialog instead.
Additionally, while it is possible to also include interactive controls (such as form elements or links) in your popover (by adding these elements to the `allowList` of allowed attributes and tags), be aware that currently the popover does not manage keyboard focus order. When a keyboard user opens a popover, focus remains on the triggering element, and as the popover usually does not immediately follow the trigger in the document's structure, there is no guarantee that moving forward/pressing <kbd>TAB</kbd> will move a keyboard user into the popover itself. In short, simply adding interactive controls to a popover is likely to make these controls unreachable/unusable for keyboard users and users of assistive technologies, or at the very least make for an illogical overall focus order. In these cases, consider using a modal dialog instead.
{{< /callout >}}

### Options

Options can be passed via data attributes or JavaScript. For data attributes, append the option name to `data-`, as in `data-animation=""`.

{{< callout warning >}}
Note that for security reasons the `sanitize`, `sanitizeFn` and `whiteList` options cannot be supplied using data attributes.
Note that for security reasons the `sanitize`, `sanitizeFn`, and `allowList` options cannot be supplied using data attributes.
{{< /callout >}}

<table class="table">
Expand Down Expand Up @@ -270,7 +270,7 @@ Note that for security reasons the `sanitize`, `sanitizeFn` and `whiteList` opti
<td>Enable or disable the sanitization. If activated <code>'template'</code>, <code>'content'</code> and <code>'title'</code> options will be sanitized.</td>
</tr>
<tr>
<td>whiteList</td>
<td>allowList</td>
<td>object</td>
<td><a href="{{< docsref "/getting-started/javascript#sanitizer" >}}">Default value</a></td>
<td>Object which contains allowed attributes and tags</td>
Expand Down
4 changes: 2 additions & 2 deletions site/content/docs/5.0/components/tooltips.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ Elements with the `disabled` attribute aren't interactive, meaning users cannot
Options can be passed via data attributes or JavaScript. For data attributes, append the option name to `data-`, as in `data-animation=""`.

{{< callout warning >}}
Note that for security reasons the `sanitize`, `sanitizeFn` and `whiteList` options cannot be supplied using data attributes.
Note that for security reasons the `sanitize`, `sanitizeFn`, and `allowList` options cannot be supplied using data attributes.
{{< /callout >}}

<table class="table">
Expand Down Expand Up @@ -278,7 +278,7 @@ Note that for security reasons the `sanitize`, `sanitizeFn` and `whiteList` opti
<td>Enable or disable the sanitization. If activated <code>'template'</code> and <code>'title'</code> options will be sanitized.</td>
</tr>
<tr>
<td>whiteList</td>
<td>allowList</td>
<td>object</td>
<td><a href="{{< docsref "/getting-started/javascript#sanitizer" >}}">Default value</a></td>
<td>Object which contains allowed attributes and tags</td>
Expand Down
14 changes: 7 additions & 7 deletions site/content/docs/5.0/getting-started/javascript.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,11 +161,11 @@ Bootstrap's plugins don't fall back particularly gracefully when JavaScript is d

Tooltips and Popovers use our built-in sanitizer to sanitize options which accept HTML.

The default `whiteList` value is the following:
The default `allowList` value is the following:

{{< highlight js >}}
var ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i
var DefaultWhitelist = {
var DefaultAllowlist = {
// Global attributes allowed on any supplied element below.
'*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],
a: ['target', 'href', 'title', 'rel'],
Expand Down Expand Up @@ -200,21 +200,21 @@ var DefaultWhitelist = {
}
{{< /highlight >}}

If you want to add new values to this default `whiteList` you can do the following:
If you want to add new values to this default `allowList` you can do the following:

{{< highlight js >}}
var myDefaultWhiteList = bootstrap.Tooltip.Default.whiteList
var myDefaultAllowList = bootstrap.Tooltip.Default.allowList

// To allow table elements
myDefaultWhiteList.table = []
myDefaultAllowList.table = []

// To allow td elements and data-option attributes on td elements
myDefaultWhiteList.td = ['data-option']
myDefaultAllowList.td = ['data-option']

// You can push your custom regex to validate your attributes.
// Be careful about your regular expressions being too lax
var myCustomRegex = /^data-my-app-[\w-]+/
myDefaultWhiteList['*'].push(myCustomRegex)
myDefaultAllowList['*'].push(myCustomRegex)
{{< /highlight >}}

If you want to bypass our sanitizer because you prefer to use a dedicated library, for example [DOMPurify](https://www.npmjs.com/package/dompurify), you should do the following:
Expand Down
2 changes: 2 additions & 0 deletions site/content/docs/5.0/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,10 +172,12 @@ Badges were overhauled to better differentiate themselves from buttons and to be
### Popovers

- Renamed `.arrow` to `.popover-arrow`
- Renamed `whiteList` option to `allowList`

### Tooltips

- Renamed `.arrow` to `.tooltip-arrow`
- Renamed `whiteList` option to `allowList`

## Accessibility

Expand Down