• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

twbs / bootstrap / 4658914237

10 Apr 2023 03:49PM CUT coverage: 96.059%. Remained the same
4658914237

Pull #38219

github

GitHub
Merge b371d6eef into 3d84e60d6
Pull Request #38219: Docs: consistent usage of CSS sections in /helpers, /layout

662 of 722 branches covered (91.69%)

Branch coverage included in aggregate %.

2019 of 2069 relevant lines covered (97.58%)

205.9 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.56
/js/src/util/sanitizer.js
1
/**
2
 * --------------------------------------------------------------------------
3
 * Bootstrap util/sanitizer.js
4
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
5
 * --------------------------------------------------------------------------
6
 */
7

8
const uriAttributes = new Set([
4✔
9
  'background',
10
  'cite',
11
  'href',
12
  'itemtype',
13
  'longdesc',
14
  'poster',
15
  'src',
16
  'xlink:href'
17
])
18

19
/**
20
 * A pattern that recognizes a commonly useful subset of URLs that are safe.
21
 *
22
 * Shout-out to Angular https://github.com/angular/angular/blob/12.2.x/packages/core/src/sanitization/url_sanitizer.ts
23
 */
24
const SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file|sms):|[^#&/:?]*(?:[#/?]|$))/i
4✔
25

26
/**
27
 * A pattern that matches safe data URLs. Only matches image, video and audio types.
28
 *
29
 * Shout-out to Angular https://github.com/angular/angular/blob/12.2.x/packages/core/src/sanitization/url_sanitizer.ts
30
 */
31
const DATA_URL_PATTERN = /^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[\d+/a-z]+=*$/i
4✔
32

33
const allowedAttribute = (attribute, allowedAttributeList) => {
4✔
34
  const attributeName = attribute.nodeName.toLowerCase()
288✔
35

36
  if (allowedAttributeList.includes(attributeName)) {
288✔
37
    if (uriAttributes.has(attributeName)) {
283✔
38
      return Boolean(SAFE_URL_PATTERN.test(attribute.nodeValue) || DATA_URL_PATTERN.test(attribute.nodeValue))
7✔
39
    }
40

41
    return true
276✔
42
  }
43

44
  // Check if a regular expression validates the attribute.
45
  return allowedAttributeList.filter(attributeRegex => attributeRegex instanceof RegExp)
48✔
46
    .some(regex => regex.test(attributeName))
6✔
47
}
48

49
// js-docs-start allow-list
50
const ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i
4✔
51

52
export const DefaultAllowlist = {
4✔
53
  // Global attributes allowed on any supplied element below.
54
  '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],
55
  a: ['target', 'href', 'title', 'rel'],
56
  area: [],
57
  b: [],
58
  br: [],
59
  col: [],
60
  code: [],
61
  div: [],
62
  em: [],
63
  hr: [],
64
  h1: [],
65
  h2: [],
66
  h3: [],
67
  h4: [],
68
  h5: [],
69
  h6: [],
70
  i: [],
71
  img: ['src', 'srcset', 'alt', 'title', 'width', 'height'],
72
  li: [],
73
  ol: [],
74
  p: [],
75
  pre: [],
76
  s: [],
77
  small: [],
78
  span: [],
79
  sub: [],
80
  sup: [],
81
  strong: [],
82
  u: [],
83
  ul: []
84
}
85
// js-docs-end allow-list
86

87
export function sanitizeHtml(unsafeHtml, allowList, sanitizeFunction) {
88
  if (!unsafeHtml.length) {
92✔
89
    return unsafeHtml
1✔
90
  }
91

92
  if (sanitizeFunction && typeof sanitizeFunction === 'function') {
91✔
93
    return sanitizeFunction(unsafeHtml)
1✔
94
  }
95

96
  const domParser = new window.DOMParser()
90✔
97
  const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html')
90✔
98
  const elements = [].concat(...createdDocument.body.querySelectorAll('*'))
90✔
99

100
  for (const element of elements) {
90✔
101
    const elementName = element.nodeName.toLowerCase()
251✔
102

103
    if (!Object.keys(allowList).includes(elementName)) {
251✔
104
      element.remove()
2✔
105

106
      continue
2✔
107
    }
108

109
    const attributeList = [].concat(...element.attributes)
249✔
110
    const allowedAttributes = [].concat(allowList['*'] || [], allowList[elementName] || [])
249!
111

112
    for (const attribute of attributeList) {
249✔
113
      if (!allowedAttribute(attribute, allowedAttributes)) {
288✔
114
        element.removeAttribute(attribute.nodeName)
6✔
115
      }
116
    }
117
  }
118

119
  return createdDocument.body.innerHTML
90✔
120
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc