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

twbs / bootstrap / 4463571712

pending completion
4463571712

push

github

GitHub
Proposal to use `scroll-margin-top` instead of introducing padding and negative margin (#38220)

662 of 722 branches covered (91.69%)

Branch coverage included in aggregate %.

2020 of 2070 relevant lines covered (97.58%)

318.18 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 (v5.3.0-alpha1): 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
const ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i
4✔
20

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

28
/**
29
 * A pattern that matches safe data URLs. Only matches image, video and audio types.
30
 *
31
 * Shout-out to Angular https://github.com/angular/angular/blob/12.2.x/packages/core/src/sanitization/url_sanitizer.ts
32
 */
33
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✔
34

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

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

43
    return true
276✔
44
  }
45

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

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

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

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

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

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

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

104
      continue
2✔
105
    }
106

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

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

117
  return createdDocument.body.innerHTML
90✔
118
}
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