@instructure/outcomes-ui 3.2.4 → 3.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (481) hide show
  1. package/es/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  2. package/es/components/OutcomeCheckbox/index.js +1 -0
  3. package/es/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  4. package/es/components/OutcomeSelectionList/index.js +1 -0
  5. package/es/lib/__tests__/sanitize.test.js +132 -10
  6. package/es/lib/sanitize.js +22 -26
  7. package/es/translated/ar/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  8. package/es/translated/ar/components/OutcomeCheckbox/index.js +1 -0
  9. package/es/translated/ar/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  10. package/es/translated/ar/components/OutcomeSelectionList/index.js +1 -0
  11. package/es/translated/ar/lib/__tests__/sanitize.test.js +132 -10
  12. package/es/translated/ar/lib/sanitize.js +22 -26
  13. package/es/translated/ca/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  14. package/es/translated/ca/components/OutcomeCheckbox/index.js +1 -0
  15. package/es/translated/ca/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  16. package/es/translated/ca/components/OutcomeSelectionList/index.js +1 -0
  17. package/es/translated/ca/lib/__tests__/sanitize.test.js +132 -10
  18. package/es/translated/ca/lib/sanitize.js +22 -26
  19. package/es/translated/cy/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  20. package/es/translated/cy/components/OutcomeCheckbox/index.js +1 -0
  21. package/es/translated/cy/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  22. package/es/translated/cy/components/OutcomeSelectionList/index.js +1 -0
  23. package/es/translated/cy/lib/__tests__/sanitize.test.js +132 -10
  24. package/es/translated/cy/lib/sanitize.js +22 -26
  25. package/es/translated/da/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  26. package/es/translated/da/components/OutcomeCheckbox/index.js +1 -0
  27. package/es/translated/da/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  28. package/es/translated/da/components/OutcomeSelectionList/index.js +1 -0
  29. package/es/translated/da/lib/__tests__/sanitize.test.js +132 -10
  30. package/es/translated/da/lib/sanitize.js +22 -26
  31. package/es/translated/da-x-k12/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  32. package/es/translated/da-x-k12/components/OutcomeCheckbox/index.js +1 -0
  33. package/es/translated/da-x-k12/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  34. package/es/translated/da-x-k12/components/OutcomeSelectionList/index.js +1 -0
  35. package/es/translated/da-x-k12/lib/__tests__/sanitize.test.js +132 -10
  36. package/es/translated/da-x-k12/lib/sanitize.js +22 -26
  37. package/es/translated/de/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  38. package/es/translated/de/components/OutcomeCheckbox/index.js +1 -0
  39. package/es/translated/de/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  40. package/es/translated/de/components/OutcomeSelectionList/index.js +1 -0
  41. package/es/translated/de/lib/__tests__/sanitize.test.js +132 -10
  42. package/es/translated/de/lib/sanitize.js +22 -26
  43. package/es/translated/en/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  44. package/es/translated/en/components/OutcomeCheckbox/index.js +1 -0
  45. package/es/translated/en/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  46. package/es/translated/en/components/OutcomeSelectionList/index.js +1 -0
  47. package/es/translated/en/lib/__tests__/sanitize.test.js +132 -10
  48. package/es/translated/en/lib/sanitize.js +22 -26
  49. package/es/translated/en-AU/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  50. package/es/translated/en-AU/components/OutcomeCheckbox/index.js +1 -0
  51. package/es/translated/en-AU/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  52. package/es/translated/en-AU/components/OutcomeSelectionList/index.js +1 -0
  53. package/es/translated/en-AU/lib/__tests__/sanitize.test.js +132 -10
  54. package/es/translated/en-AU/lib/sanitize.js +22 -26
  55. package/es/translated/en-AU-x-unimelb/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  56. package/es/translated/en-AU-x-unimelb/components/OutcomeCheckbox/index.js +1 -0
  57. package/es/translated/en-AU-x-unimelb/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  58. package/es/translated/en-AU-x-unimelb/components/OutcomeSelectionList/index.js +1 -0
  59. package/es/translated/en-AU-x-unimelb/lib/__tests__/sanitize.test.js +132 -10
  60. package/es/translated/en-AU-x-unimelb/lib/sanitize.js +22 -26
  61. package/es/translated/en-CA/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  62. package/es/translated/en-CA/components/OutcomeCheckbox/index.js +1 -0
  63. package/es/translated/en-CA/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  64. package/es/translated/en-CA/components/OutcomeSelectionList/index.js +1 -0
  65. package/es/translated/en-CA/lib/__tests__/sanitize.test.js +132 -10
  66. package/es/translated/en-CA/lib/sanitize.js +22 -26
  67. package/es/translated/en-CY/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  68. package/es/translated/en-CY/components/OutcomeCheckbox/index.js +1 -0
  69. package/es/translated/en-CY/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  70. package/es/translated/en-CY/components/OutcomeSelectionList/index.js +1 -0
  71. package/es/translated/en-CY/lib/__tests__/sanitize.test.js +132 -10
  72. package/es/translated/en-CY/lib/sanitize.js +22 -26
  73. package/es/translated/en-GB/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  74. package/es/translated/en-GB/components/OutcomeCheckbox/index.js +1 -0
  75. package/es/translated/en-GB/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  76. package/es/translated/en-GB/components/OutcomeSelectionList/index.js +1 -0
  77. package/es/translated/en-GB/lib/__tests__/sanitize.test.js +132 -10
  78. package/es/translated/en-GB/lib/sanitize.js +22 -26
  79. package/es/translated/en-GB-x-ukhe/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  80. package/es/translated/en-GB-x-ukhe/components/OutcomeCheckbox/index.js +1 -0
  81. package/es/translated/en-GB-x-ukhe/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  82. package/es/translated/en-GB-x-ukhe/components/OutcomeSelectionList/index.js +1 -0
  83. package/es/translated/en-GB-x-ukhe/lib/__tests__/sanitize.test.js +132 -10
  84. package/es/translated/en-GB-x-ukhe/lib/sanitize.js +22 -26
  85. package/es/translated/en-IE/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  86. package/es/translated/en-IE/components/OutcomeCheckbox/index.js +1 -0
  87. package/es/translated/en-IE/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  88. package/es/translated/en-IE/components/OutcomeSelectionList/index.js +1 -0
  89. package/es/translated/en-IE/lib/__tests__/sanitize.test.js +132 -10
  90. package/es/translated/en-IE/lib/sanitize.js +22 -26
  91. package/es/translated/es/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  92. package/es/translated/es/components/OutcomeCheckbox/index.js +1 -0
  93. package/es/translated/es/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  94. package/es/translated/es/components/OutcomeSelectionList/index.js +1 -0
  95. package/es/translated/es/lib/__tests__/sanitize.test.js +132 -10
  96. package/es/translated/es/lib/sanitize.js +22 -26
  97. package/es/translated/es-ES/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  98. package/es/translated/es-ES/components/OutcomeCheckbox/index.js +1 -0
  99. package/es/translated/es-ES/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  100. package/es/translated/es-ES/components/OutcomeSelectionList/index.js +1 -0
  101. package/es/translated/es-ES/lib/__tests__/sanitize.test.js +132 -10
  102. package/es/translated/es-ES/lib/sanitize.js +22 -26
  103. package/es/translated/es_ES/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  104. package/es/translated/es_ES/components/OutcomeCheckbox/index.js +1 -0
  105. package/es/translated/es_ES/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  106. package/es/translated/es_ES/components/OutcomeSelectionList/index.js +1 -0
  107. package/es/translated/es_ES/lib/__tests__/sanitize.test.js +132 -10
  108. package/es/translated/es_ES/lib/sanitize.js +22 -26
  109. package/es/translated/fi/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  110. package/es/translated/fi/components/OutcomeCheckbox/index.js +1 -0
  111. package/es/translated/fi/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  112. package/es/translated/fi/components/OutcomeSelectionList/index.js +1 -0
  113. package/es/translated/fi/lib/__tests__/sanitize.test.js +132 -10
  114. package/es/translated/fi/lib/sanitize.js +22 -26
  115. package/es/translated/fr/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  116. package/es/translated/fr/components/OutcomeCheckbox/index.js +1 -0
  117. package/es/translated/fr/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  118. package/es/translated/fr/components/OutcomeSelectionList/index.js +1 -0
  119. package/es/translated/fr/lib/__tests__/sanitize.test.js +132 -10
  120. package/es/translated/fr/lib/sanitize.js +22 -26
  121. package/es/translated/fr-CA/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  122. package/es/translated/fr-CA/components/OutcomeCheckbox/index.js +1 -0
  123. package/es/translated/fr-CA/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  124. package/es/translated/fr-CA/components/OutcomeSelectionList/index.js +1 -0
  125. package/es/translated/fr-CA/lib/__tests__/sanitize.test.js +132 -10
  126. package/es/translated/fr-CA/lib/sanitize.js +22 -26
  127. package/es/translated/ht/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  128. package/es/translated/ht/components/OutcomeCheckbox/index.js +1 -0
  129. package/es/translated/ht/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  130. package/es/translated/ht/components/OutcomeSelectionList/index.js +1 -0
  131. package/es/translated/ht/lib/__tests__/sanitize.test.js +132 -10
  132. package/es/translated/ht/lib/sanitize.js +22 -26
  133. package/es/translated/is/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  134. package/es/translated/is/components/OutcomeCheckbox/index.js +1 -0
  135. package/es/translated/is/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  136. package/es/translated/is/components/OutcomeSelectionList/index.js +1 -0
  137. package/es/translated/is/lib/__tests__/sanitize.test.js +132 -10
  138. package/es/translated/is/lib/sanitize.js +22 -26
  139. package/es/translated/it/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  140. package/es/translated/it/components/OutcomeCheckbox/index.js +1 -0
  141. package/es/translated/it/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  142. package/es/translated/it/components/OutcomeSelectionList/index.js +1 -0
  143. package/es/translated/it/lib/__tests__/sanitize.test.js +132 -10
  144. package/es/translated/it/lib/sanitize.js +22 -26
  145. package/es/translated/ja/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  146. package/es/translated/ja/components/OutcomeCheckbox/index.js +1 -0
  147. package/es/translated/ja/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  148. package/es/translated/ja/components/OutcomeSelectionList/index.js +1 -0
  149. package/es/translated/ja/lib/__tests__/sanitize.test.js +132 -10
  150. package/es/translated/ja/lib/sanitize.js +22 -26
  151. package/es/translated/mi/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  152. package/es/translated/mi/components/OutcomeCheckbox/index.js +1 -0
  153. package/es/translated/mi/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  154. package/es/translated/mi/components/OutcomeSelectionList/index.js +1 -0
  155. package/es/translated/mi/lib/__tests__/sanitize.test.js +132 -10
  156. package/es/translated/mi/lib/sanitize.js +22 -26
  157. package/es/translated/nb/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  158. package/es/translated/nb/components/OutcomeCheckbox/index.js +1 -0
  159. package/es/translated/nb/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  160. package/es/translated/nb/components/OutcomeSelectionList/index.js +1 -0
  161. package/es/translated/nb/lib/__tests__/sanitize.test.js +132 -10
  162. package/es/translated/nb/lib/sanitize.js +22 -26
  163. package/es/translated/nb-x-k12/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  164. package/es/translated/nb-x-k12/components/OutcomeCheckbox/index.js +1 -0
  165. package/es/translated/nb-x-k12/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  166. package/es/translated/nb-x-k12/components/OutcomeSelectionList/index.js +1 -0
  167. package/es/translated/nb-x-k12/lib/__tests__/sanitize.test.js +132 -10
  168. package/es/translated/nb-x-k12/lib/sanitize.js +22 -26
  169. package/es/translated/nl/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  170. package/es/translated/nl/components/OutcomeCheckbox/index.js +1 -0
  171. package/es/translated/nl/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  172. package/es/translated/nl/components/OutcomeSelectionList/index.js +1 -0
  173. package/es/translated/nl/lib/__tests__/sanitize.test.js +132 -10
  174. package/es/translated/nl/lib/sanitize.js +22 -26
  175. package/es/translated/pl/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  176. package/es/translated/pl/components/OutcomeCheckbox/index.js +1 -0
  177. package/es/translated/pl/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  178. package/es/translated/pl/components/OutcomeSelectionList/index.js +1 -0
  179. package/es/translated/pl/lib/__tests__/sanitize.test.js +132 -10
  180. package/es/translated/pl/lib/sanitize.js +22 -26
  181. package/es/translated/pt/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  182. package/es/translated/pt/components/OutcomeCheckbox/index.js +1 -0
  183. package/es/translated/pt/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  184. package/es/translated/pt/components/OutcomeSelectionList/index.js +1 -0
  185. package/es/translated/pt/lib/__tests__/sanitize.test.js +132 -10
  186. package/es/translated/pt/lib/sanitize.js +22 -26
  187. package/es/translated/pt-BR/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  188. package/es/translated/pt-BR/components/OutcomeCheckbox/index.js +1 -0
  189. package/es/translated/pt-BR/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  190. package/es/translated/pt-BR/components/OutcomeSelectionList/index.js +1 -0
  191. package/es/translated/pt-BR/lib/__tests__/sanitize.test.js +132 -10
  192. package/es/translated/pt-BR/lib/sanitize.js +22 -26
  193. package/es/translated/ru/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  194. package/es/translated/ru/components/OutcomeCheckbox/index.js +1 -0
  195. package/es/translated/ru/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  196. package/es/translated/ru/components/OutcomeSelectionList/index.js +1 -0
  197. package/es/translated/ru/lib/__tests__/sanitize.test.js +132 -10
  198. package/es/translated/ru/lib/sanitize.js +22 -26
  199. package/es/translated/sl/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  200. package/es/translated/sl/components/OutcomeCheckbox/index.js +1 -0
  201. package/es/translated/sl/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  202. package/es/translated/sl/components/OutcomeSelectionList/index.js +1 -0
  203. package/es/translated/sl/lib/__tests__/sanitize.test.js +132 -10
  204. package/es/translated/sl/lib/sanitize.js +22 -26
  205. package/es/translated/sv/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  206. package/es/translated/sv/components/OutcomeCheckbox/index.js +1 -0
  207. package/es/translated/sv/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  208. package/es/translated/sv/components/OutcomeSelectionList/index.js +1 -0
  209. package/es/translated/sv/lib/__tests__/sanitize.test.js +132 -10
  210. package/es/translated/sv/lib/sanitize.js +22 -26
  211. package/es/translated/sv-x-k12/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  212. package/es/translated/sv-x-k12/components/OutcomeCheckbox/index.js +1 -0
  213. package/es/translated/sv-x-k12/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  214. package/es/translated/sv-x-k12/components/OutcomeSelectionList/index.js +1 -0
  215. package/es/translated/sv-x-k12/lib/__tests__/sanitize.test.js +132 -10
  216. package/es/translated/sv-x-k12/lib/sanitize.js +22 -26
  217. package/es/translated/th/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  218. package/es/translated/th/components/OutcomeCheckbox/index.js +1 -0
  219. package/es/translated/th/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  220. package/es/translated/th/components/OutcomeSelectionList/index.js +1 -0
  221. package/es/translated/th/lib/__tests__/sanitize.test.js +132 -10
  222. package/es/translated/th/lib/sanitize.js +22 -26
  223. package/es/translated/vi/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  224. package/es/translated/vi/components/OutcomeCheckbox/index.js +1 -0
  225. package/es/translated/vi/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  226. package/es/translated/vi/components/OutcomeSelectionList/index.js +1 -0
  227. package/es/translated/vi/lib/__tests__/sanitize.test.js +132 -10
  228. package/es/translated/vi/lib/sanitize.js +22 -26
  229. package/es/translated/zh-Hans/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  230. package/es/translated/zh-Hans/components/OutcomeCheckbox/index.js +1 -0
  231. package/es/translated/zh-Hans/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  232. package/es/translated/zh-Hans/components/OutcomeSelectionList/index.js +1 -0
  233. package/es/translated/zh-Hans/lib/__tests__/sanitize.test.js +132 -10
  234. package/es/translated/zh-Hans/lib/sanitize.js +22 -26
  235. package/es/translated/zh-Hant/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  236. package/es/translated/zh-Hant/components/OutcomeCheckbox/index.js +1 -0
  237. package/es/translated/zh-Hant/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  238. package/es/translated/zh-Hant/components/OutcomeSelectionList/index.js +1 -0
  239. package/es/translated/zh-Hant/lib/__tests__/sanitize.test.js +132 -10
  240. package/es/translated/zh-Hant/lib/sanitize.js +22 -26
  241. package/lib/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  242. package/lib/components/OutcomeCheckbox/index.js +1 -0
  243. package/lib/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  244. package/lib/components/OutcomeSelectionList/index.js +1 -0
  245. package/lib/lib/__tests__/sanitize.test.js +132 -10
  246. package/lib/lib/sanitize.js +22 -26
  247. package/lib/translated/ar/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  248. package/lib/translated/ar/components/OutcomeCheckbox/index.js +1 -0
  249. package/lib/translated/ar/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  250. package/lib/translated/ar/components/OutcomeSelectionList/index.js +1 -0
  251. package/lib/translated/ar/lib/__tests__/sanitize.test.js +132 -10
  252. package/lib/translated/ar/lib/sanitize.js +22 -26
  253. package/lib/translated/ca/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  254. package/lib/translated/ca/components/OutcomeCheckbox/index.js +1 -0
  255. package/lib/translated/ca/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  256. package/lib/translated/ca/components/OutcomeSelectionList/index.js +1 -0
  257. package/lib/translated/ca/lib/__tests__/sanitize.test.js +132 -10
  258. package/lib/translated/ca/lib/sanitize.js +22 -26
  259. package/lib/translated/cy/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  260. package/lib/translated/cy/components/OutcomeCheckbox/index.js +1 -0
  261. package/lib/translated/cy/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  262. package/lib/translated/cy/components/OutcomeSelectionList/index.js +1 -0
  263. package/lib/translated/cy/lib/__tests__/sanitize.test.js +132 -10
  264. package/lib/translated/cy/lib/sanitize.js +22 -26
  265. package/lib/translated/da/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  266. package/lib/translated/da/components/OutcomeCheckbox/index.js +1 -0
  267. package/lib/translated/da/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  268. package/lib/translated/da/components/OutcomeSelectionList/index.js +1 -0
  269. package/lib/translated/da/lib/__tests__/sanitize.test.js +132 -10
  270. package/lib/translated/da/lib/sanitize.js +22 -26
  271. package/lib/translated/da-x-k12/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  272. package/lib/translated/da-x-k12/components/OutcomeCheckbox/index.js +1 -0
  273. package/lib/translated/da-x-k12/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  274. package/lib/translated/da-x-k12/components/OutcomeSelectionList/index.js +1 -0
  275. package/lib/translated/da-x-k12/lib/__tests__/sanitize.test.js +132 -10
  276. package/lib/translated/da-x-k12/lib/sanitize.js +22 -26
  277. package/lib/translated/de/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  278. package/lib/translated/de/components/OutcomeCheckbox/index.js +1 -0
  279. package/lib/translated/de/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  280. package/lib/translated/de/components/OutcomeSelectionList/index.js +1 -0
  281. package/lib/translated/de/lib/__tests__/sanitize.test.js +132 -10
  282. package/lib/translated/de/lib/sanitize.js +22 -26
  283. package/lib/translated/en/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  284. package/lib/translated/en/components/OutcomeCheckbox/index.js +1 -0
  285. package/lib/translated/en/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  286. package/lib/translated/en/components/OutcomeSelectionList/index.js +1 -0
  287. package/lib/translated/en/lib/__tests__/sanitize.test.js +132 -10
  288. package/lib/translated/en/lib/sanitize.js +22 -26
  289. package/lib/translated/en-AU/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  290. package/lib/translated/en-AU/components/OutcomeCheckbox/index.js +1 -0
  291. package/lib/translated/en-AU/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  292. package/lib/translated/en-AU/components/OutcomeSelectionList/index.js +1 -0
  293. package/lib/translated/en-AU/lib/__tests__/sanitize.test.js +132 -10
  294. package/lib/translated/en-AU/lib/sanitize.js +22 -26
  295. package/lib/translated/en-AU-x-unimelb/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  296. package/lib/translated/en-AU-x-unimelb/components/OutcomeCheckbox/index.js +1 -0
  297. package/lib/translated/en-AU-x-unimelb/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  298. package/lib/translated/en-AU-x-unimelb/components/OutcomeSelectionList/index.js +1 -0
  299. package/lib/translated/en-AU-x-unimelb/lib/__tests__/sanitize.test.js +132 -10
  300. package/lib/translated/en-AU-x-unimelb/lib/sanitize.js +22 -26
  301. package/lib/translated/en-CA/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  302. package/lib/translated/en-CA/components/OutcomeCheckbox/index.js +1 -0
  303. package/lib/translated/en-CA/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  304. package/lib/translated/en-CA/components/OutcomeSelectionList/index.js +1 -0
  305. package/lib/translated/en-CA/lib/__tests__/sanitize.test.js +132 -10
  306. package/lib/translated/en-CA/lib/sanitize.js +22 -26
  307. package/lib/translated/en-CY/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  308. package/lib/translated/en-CY/components/OutcomeCheckbox/index.js +1 -0
  309. package/lib/translated/en-CY/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  310. package/lib/translated/en-CY/components/OutcomeSelectionList/index.js +1 -0
  311. package/lib/translated/en-CY/lib/__tests__/sanitize.test.js +132 -10
  312. package/lib/translated/en-CY/lib/sanitize.js +22 -26
  313. package/lib/translated/en-GB/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  314. package/lib/translated/en-GB/components/OutcomeCheckbox/index.js +1 -0
  315. package/lib/translated/en-GB/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  316. package/lib/translated/en-GB/components/OutcomeSelectionList/index.js +1 -0
  317. package/lib/translated/en-GB/lib/__tests__/sanitize.test.js +132 -10
  318. package/lib/translated/en-GB/lib/sanitize.js +22 -26
  319. package/lib/translated/en-GB-x-ukhe/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  320. package/lib/translated/en-GB-x-ukhe/components/OutcomeCheckbox/index.js +1 -0
  321. package/lib/translated/en-GB-x-ukhe/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  322. package/lib/translated/en-GB-x-ukhe/components/OutcomeSelectionList/index.js +1 -0
  323. package/lib/translated/en-GB-x-ukhe/lib/__tests__/sanitize.test.js +132 -10
  324. package/lib/translated/en-GB-x-ukhe/lib/sanitize.js +22 -26
  325. package/lib/translated/en-IE/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  326. package/lib/translated/en-IE/components/OutcomeCheckbox/index.js +1 -0
  327. package/lib/translated/en-IE/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  328. package/lib/translated/en-IE/components/OutcomeSelectionList/index.js +1 -0
  329. package/lib/translated/en-IE/lib/__tests__/sanitize.test.js +132 -10
  330. package/lib/translated/en-IE/lib/sanitize.js +22 -26
  331. package/lib/translated/es/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  332. package/lib/translated/es/components/OutcomeCheckbox/index.js +1 -0
  333. package/lib/translated/es/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  334. package/lib/translated/es/components/OutcomeSelectionList/index.js +1 -0
  335. package/lib/translated/es/lib/__tests__/sanitize.test.js +132 -10
  336. package/lib/translated/es/lib/sanitize.js +22 -26
  337. package/lib/translated/es-ES/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  338. package/lib/translated/es-ES/components/OutcomeCheckbox/index.js +1 -0
  339. package/lib/translated/es-ES/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  340. package/lib/translated/es-ES/components/OutcomeSelectionList/index.js +1 -0
  341. package/lib/translated/es-ES/lib/__tests__/sanitize.test.js +132 -10
  342. package/lib/translated/es-ES/lib/sanitize.js +22 -26
  343. package/lib/translated/es_ES/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  344. package/lib/translated/es_ES/components/OutcomeCheckbox/index.js +1 -0
  345. package/lib/translated/es_ES/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  346. package/lib/translated/es_ES/components/OutcomeSelectionList/index.js +1 -0
  347. package/lib/translated/es_ES/lib/__tests__/sanitize.test.js +132 -10
  348. package/lib/translated/es_ES/lib/sanitize.js +22 -26
  349. package/lib/translated/fi/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  350. package/lib/translated/fi/components/OutcomeCheckbox/index.js +1 -0
  351. package/lib/translated/fi/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  352. package/lib/translated/fi/components/OutcomeSelectionList/index.js +1 -0
  353. package/lib/translated/fi/lib/__tests__/sanitize.test.js +132 -10
  354. package/lib/translated/fi/lib/sanitize.js +22 -26
  355. package/lib/translated/fr/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  356. package/lib/translated/fr/components/OutcomeCheckbox/index.js +1 -0
  357. package/lib/translated/fr/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  358. package/lib/translated/fr/components/OutcomeSelectionList/index.js +1 -0
  359. package/lib/translated/fr/lib/__tests__/sanitize.test.js +132 -10
  360. package/lib/translated/fr/lib/sanitize.js +22 -26
  361. package/lib/translated/fr-CA/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  362. package/lib/translated/fr-CA/components/OutcomeCheckbox/index.js +1 -0
  363. package/lib/translated/fr-CA/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  364. package/lib/translated/fr-CA/components/OutcomeSelectionList/index.js +1 -0
  365. package/lib/translated/fr-CA/lib/__tests__/sanitize.test.js +132 -10
  366. package/lib/translated/fr-CA/lib/sanitize.js +22 -26
  367. package/lib/translated/ht/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  368. package/lib/translated/ht/components/OutcomeCheckbox/index.js +1 -0
  369. package/lib/translated/ht/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  370. package/lib/translated/ht/components/OutcomeSelectionList/index.js +1 -0
  371. package/lib/translated/ht/lib/__tests__/sanitize.test.js +132 -10
  372. package/lib/translated/ht/lib/sanitize.js +22 -26
  373. package/lib/translated/is/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  374. package/lib/translated/is/components/OutcomeCheckbox/index.js +1 -0
  375. package/lib/translated/is/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  376. package/lib/translated/is/components/OutcomeSelectionList/index.js +1 -0
  377. package/lib/translated/is/lib/__tests__/sanitize.test.js +132 -10
  378. package/lib/translated/is/lib/sanitize.js +22 -26
  379. package/lib/translated/it/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  380. package/lib/translated/it/components/OutcomeCheckbox/index.js +1 -0
  381. package/lib/translated/it/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  382. package/lib/translated/it/components/OutcomeSelectionList/index.js +1 -0
  383. package/lib/translated/it/lib/__tests__/sanitize.test.js +132 -10
  384. package/lib/translated/it/lib/sanitize.js +22 -26
  385. package/lib/translated/ja/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  386. package/lib/translated/ja/components/OutcomeCheckbox/index.js +1 -0
  387. package/lib/translated/ja/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  388. package/lib/translated/ja/components/OutcomeSelectionList/index.js +1 -0
  389. package/lib/translated/ja/lib/__tests__/sanitize.test.js +132 -10
  390. package/lib/translated/ja/lib/sanitize.js +22 -26
  391. package/lib/translated/mi/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  392. package/lib/translated/mi/components/OutcomeCheckbox/index.js +1 -0
  393. package/lib/translated/mi/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  394. package/lib/translated/mi/components/OutcomeSelectionList/index.js +1 -0
  395. package/lib/translated/mi/lib/__tests__/sanitize.test.js +132 -10
  396. package/lib/translated/mi/lib/sanitize.js +22 -26
  397. package/lib/translated/nb/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  398. package/lib/translated/nb/components/OutcomeCheckbox/index.js +1 -0
  399. package/lib/translated/nb/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  400. package/lib/translated/nb/components/OutcomeSelectionList/index.js +1 -0
  401. package/lib/translated/nb/lib/__tests__/sanitize.test.js +132 -10
  402. package/lib/translated/nb/lib/sanitize.js +22 -26
  403. package/lib/translated/nb-x-k12/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  404. package/lib/translated/nb-x-k12/components/OutcomeCheckbox/index.js +1 -0
  405. package/lib/translated/nb-x-k12/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  406. package/lib/translated/nb-x-k12/components/OutcomeSelectionList/index.js +1 -0
  407. package/lib/translated/nb-x-k12/lib/__tests__/sanitize.test.js +132 -10
  408. package/lib/translated/nb-x-k12/lib/sanitize.js +22 -26
  409. package/lib/translated/nl/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  410. package/lib/translated/nl/components/OutcomeCheckbox/index.js +1 -0
  411. package/lib/translated/nl/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  412. package/lib/translated/nl/components/OutcomeSelectionList/index.js +1 -0
  413. package/lib/translated/nl/lib/__tests__/sanitize.test.js +132 -10
  414. package/lib/translated/nl/lib/sanitize.js +22 -26
  415. package/lib/translated/pl/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  416. package/lib/translated/pl/components/OutcomeCheckbox/index.js +1 -0
  417. package/lib/translated/pl/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  418. package/lib/translated/pl/components/OutcomeSelectionList/index.js +1 -0
  419. package/lib/translated/pl/lib/__tests__/sanitize.test.js +132 -10
  420. package/lib/translated/pl/lib/sanitize.js +22 -26
  421. package/lib/translated/pt/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  422. package/lib/translated/pt/components/OutcomeCheckbox/index.js +1 -0
  423. package/lib/translated/pt/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  424. package/lib/translated/pt/components/OutcomeSelectionList/index.js +1 -0
  425. package/lib/translated/pt/lib/__tests__/sanitize.test.js +132 -10
  426. package/lib/translated/pt/lib/sanitize.js +22 -26
  427. package/lib/translated/pt-BR/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  428. package/lib/translated/pt-BR/components/OutcomeCheckbox/index.js +1 -0
  429. package/lib/translated/pt-BR/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  430. package/lib/translated/pt-BR/components/OutcomeSelectionList/index.js +1 -0
  431. package/lib/translated/pt-BR/lib/__tests__/sanitize.test.js +132 -10
  432. package/lib/translated/pt-BR/lib/sanitize.js +22 -26
  433. package/lib/translated/ru/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  434. package/lib/translated/ru/components/OutcomeCheckbox/index.js +1 -0
  435. package/lib/translated/ru/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  436. package/lib/translated/ru/components/OutcomeSelectionList/index.js +1 -0
  437. package/lib/translated/ru/lib/__tests__/sanitize.test.js +132 -10
  438. package/lib/translated/ru/lib/sanitize.js +22 -26
  439. package/lib/translated/sl/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  440. package/lib/translated/sl/components/OutcomeCheckbox/index.js +1 -0
  441. package/lib/translated/sl/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  442. package/lib/translated/sl/components/OutcomeSelectionList/index.js +1 -0
  443. package/lib/translated/sl/lib/__tests__/sanitize.test.js +132 -10
  444. package/lib/translated/sl/lib/sanitize.js +22 -26
  445. package/lib/translated/sv/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  446. package/lib/translated/sv/components/OutcomeCheckbox/index.js +1 -0
  447. package/lib/translated/sv/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  448. package/lib/translated/sv/components/OutcomeSelectionList/index.js +1 -0
  449. package/lib/translated/sv/lib/__tests__/sanitize.test.js +132 -10
  450. package/lib/translated/sv/lib/sanitize.js +22 -26
  451. package/lib/translated/sv-x-k12/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  452. package/lib/translated/sv-x-k12/components/OutcomeCheckbox/index.js +1 -0
  453. package/lib/translated/sv-x-k12/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  454. package/lib/translated/sv-x-k12/components/OutcomeSelectionList/index.js +1 -0
  455. package/lib/translated/sv-x-k12/lib/__tests__/sanitize.test.js +132 -10
  456. package/lib/translated/sv-x-k12/lib/sanitize.js +22 -26
  457. package/lib/translated/th/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  458. package/lib/translated/th/components/OutcomeCheckbox/index.js +1 -0
  459. package/lib/translated/th/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  460. package/lib/translated/th/components/OutcomeSelectionList/index.js +1 -0
  461. package/lib/translated/th/lib/__tests__/sanitize.test.js +132 -10
  462. package/lib/translated/th/lib/sanitize.js +22 -26
  463. package/lib/translated/vi/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  464. package/lib/translated/vi/components/OutcomeCheckbox/index.js +1 -0
  465. package/lib/translated/vi/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  466. package/lib/translated/vi/components/OutcomeSelectionList/index.js +1 -0
  467. package/lib/translated/vi/lib/__tests__/sanitize.test.js +132 -10
  468. package/lib/translated/vi/lib/sanitize.js +22 -26
  469. package/lib/translated/zh-Hans/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  470. package/lib/translated/zh-Hans/components/OutcomeCheckbox/index.js +1 -0
  471. package/lib/translated/zh-Hans/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  472. package/lib/translated/zh-Hans/components/OutcomeSelectionList/index.js +1 -0
  473. package/lib/translated/zh-Hans/lib/__tests__/sanitize.test.js +132 -10
  474. package/lib/translated/zh-Hans/lib/sanitize.js +22 -26
  475. package/lib/translated/zh-Hant/components/OutcomeCheckbox/__tests__/index.test.js +5 -2
  476. package/lib/translated/zh-Hant/components/OutcomeCheckbox/index.js +1 -0
  477. package/lib/translated/zh-Hant/components/OutcomeSelectionList/__tests__/index.test.js +1 -0
  478. package/lib/translated/zh-Hant/components/OutcomeSelectionList/index.js +1 -0
  479. package/lib/translated/zh-Hant/lib/__tests__/sanitize.test.js +132 -10
  480. package/lib/translated/zh-Hant/lib/sanitize.js +22 -26
  481. package/package.json +2 -2
@@ -1,16 +1,138 @@
1
1
  import { expect } from 'chai';
2
2
  import { sanitizeHtml } from "../sanitize.js";
3
- describe('sanitizeForHtml', function () {
4
- it('cleans invalid tags', function () {
5
- var invalid = '<monkey>tag isn\'t closed';
6
- expect(sanitizeHtml(invalid)).to.include('</monkey>');
3
+ describe('sanitizeHtml', function () {
4
+ describe('equation images (Canvas-specific)', function () {
5
+ it('rewrites /equation_images src to absolute canvas URL', function () {
6
+ var equationImage = 'Some text with an <img src="/equation_images/image" />';
7
+ expect(sanitizeHtml(equationImage)).to.include('canvas.instructure.com/equation_images/image');
8
+ });
9
+ it('adds vertical-align style to equation images', function () {
10
+ var equationImage = '<img src="/equation_images/abc" />';
11
+ expect(sanitizeHtml(equationImage)).to.include('vertical-align: middle');
12
+ });
13
+ it('leaves non-equation image src untouched', function () {
14
+ var otherImage = '<img src="/another_image">';
15
+ var out = sanitizeHtml(otherImage);
16
+ expect(out).to.include('src="/another_image"');
17
+ expect(out).to.not.include('canvas.instructure.com');
18
+ });
7
19
  });
8
- it('replaces equation images', function () {
9
- var equationImage = 'Some text with an <img src="/equation_images/image" />';
10
- expect(sanitizeHtml(equationImage)).to.include('canvas.instructure.com/equation_images/image');
20
+ describe('null / empty input handling', function () {
21
+ it('returns empty string for null', function () {
22
+ expect(sanitizeHtml(null)).to.equal('');
23
+ });
24
+ it('returns empty string for undefined', function () {
25
+ expect(sanitizeHtml(void 0)).to.equal('');
26
+ });
27
+ it('returns empty string for empty string', function () {
28
+ expect(sanitizeHtml('')).to.equal('');
29
+ });
11
30
  });
12
- it('leaves other images alone', function () {
13
- var otherImage = 'Some text with <img src="/another_image" />';
14
- expect(sanitizeHtml(otherImage)).to.eq(otherImage);
31
+ describe('XSS - script execution vectors', function () {
32
+ it('strips <script> tags', function () {
33
+ var xss = 'Hello<script>alert(1)</script>World';
34
+ var out = sanitizeHtml(xss);
35
+ expect(out).to.not.include('<script');
36
+ expect(out).to.not.include('alert(1)');
37
+ });
38
+ it('strips inline event handlers (onerror)', function () {
39
+ var xss = '<img src="x" onerror="alert(1)">';
40
+ var out = sanitizeHtml(xss);
41
+ expect(out).to.not.match(/onerror/i);
42
+ expect(out).to.not.include('alert(1)');
43
+ });
44
+ it('strips inline event handlers (onclick)', function () {
45
+ var xss = '<a href="#" onclick="alert(1)">click</a>';
46
+ var out = sanitizeHtml(xss);
47
+ expect(out).to.not.match(/onclick/i);
48
+ });
49
+ it('strips inline event handlers (onload on svg)', function () {
50
+ var xss = '<svg onload="alert(1)"></svg>';
51
+ var out = sanitizeHtml(xss);
52
+ expect(out).to.not.match(/onload/i);
53
+ expect(out).to.not.include('alert(1)');
54
+ });
55
+ it('strips javascript: URLs in href', function () {
56
+ // eslint-disable-next-line no-script-url
57
+ var xss = '<a href="javascript:alert(1)">x</a>';
58
+ var out = sanitizeHtml(xss);
59
+ expect(out).to.not.match(/javascript:/i);
60
+ });
61
+ it('strips javascript: URLs in img src', function () {
62
+ // eslint-disable-next-line no-script-url
63
+ var xss = '<img src="javascript:alert(1)">';
64
+ var out = sanitizeHtml(xss);
65
+ expect(out).to.not.match(/javascript:/i);
66
+ });
67
+ it('strips data: URLs that contain HTML/JS in iframe src', function () {
68
+ var xss = '<iframe src="data:text/html,<script>alert(1)</script>"></iframe>';
69
+ var out = sanitizeHtml(xss);
70
+ expect(out).to.not.include('alert(1)');
71
+ });
72
+ it('strips <object> tags', function () {
73
+ var xss = '<object data="evil.swf"></object>';
74
+ expect(sanitizeHtml(xss)).to.not.include('<object');
75
+ });
76
+ it('strips <embed> tags', function () {
77
+ var xss = '<embed src="evil.swf">';
78
+ expect(sanitizeHtml(xss)).to.not.include('<embed');
79
+ });
80
+ it('strips <form> tags (CSRF / phishing surface)', function () {
81
+ var xss = '<form action="https://evil.com"><input name=x></form>';
82
+ expect(sanitizeHtml(xss)).to.not.include('<form');
83
+ });
84
+ it('strips style tags (CSS-based exfil / clickjacking)', function () {
85
+ var xss = '<style>body{background:url(//evil.com/?c=)}</style>';
86
+ expect(sanitizeHtml(xss)).to.not.include('<style');
87
+ });
88
+ it('strips <meta http-equiv refresh> redirects', function () {
89
+ var xss = '<meta http-equiv="refresh" content="0;url=https://evil.com">';
90
+ expect(sanitizeHtml(xss)).to.not.include('<meta');
91
+ });
92
+ it('strips <base> tag (can rewrite all relative URLs)', function () {
93
+ var xss = '<base href="https://evil.com/">';
94
+ expect(sanitizeHtml(xss)).to.not.include('<base');
95
+ });
96
+ it('strips encoded onerror payloads', function () {
97
+ var xss = '<img src=x onerror=&#97;&#108;&#101;&#114;&#116;(1)>';
98
+ var out = sanitizeHtml(xss);
99
+ expect(out).to.not.match(/onerror/i);
100
+ });
101
+ it('strips mixed-case obfuscated script tags', function () {
102
+ var xss = '<ScRiPt>alert(1)</sCrIpT>';
103
+ var out = sanitizeHtml(xss);
104
+ expect(out).to.not.match(/<script/i);
105
+ expect(out).to.not.include('alert(1)');
106
+ });
107
+ });
108
+ describe('benign HTML (should be preserved)', function () {
109
+ it('preserves basic formatting tags', function () {
110
+ var html = '<p>Hello <strong>world</strong> <em>!</em></p>';
111
+ expect(sanitizeHtml(html)).to.equal(html);
112
+ });
113
+ it('preserves links with safe http(s) hrefs', function () {
114
+ var html = '<a href="https://example.com">link</a>';
115
+ expect(sanitizeHtml(html)).to.include('href="https://example.com"');
116
+ });
117
+ it('preserves lists', function () {
118
+ var html = '<ul><li>a</li><li>b</li></ul>';
119
+ expect(sanitizeHtml(html)).to.equal(html);
120
+ });
121
+ it('preserves Canvas RCE iframes (Studio / media embeds)', function () {
122
+ var html = '<iframe src="https://canvas.instructure.com/media_objects_iframe/123" ' + 'allowfullscreen="" allow="fullscreen" frameborder="0" ' + 'data-media-id="123" data-media-type="video"></iframe>';
123
+ var out = sanitizeHtml(html);
124
+ expect(out).to.include('<iframe');
125
+ expect(out).to.include('data-media-id="123"');
126
+ expect(out).to.include('data-media-type="video"');
127
+ expect(out).to.include('allowfullscreen');
128
+ });
129
+ });
130
+ describe('link hardening', function () {
131
+ it('adds rel="noopener noreferrer" to target=_blank links', function () {
132
+ var html = '<a href="https://example.com" target="_blank">x</a>';
133
+ var out = sanitizeHtml(html);
134
+ expect(out).to.match(/rel=["'][^"']*noopener[^"']*["']/);
135
+ expect(out).to.match(/rel=["'][^"']*noreferrer[^"']*["']/);
136
+ });
15
137
  });
16
138
  });
@@ -1,29 +1,25 @@
1
- import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
2
- import libSanitizeHtml from 'sanitize-html';
3
- function transformEquationImage(tagName, attribs) {
4
- return {
5
- tagName: tagName,
6
- attribs: _objectSpread(_objectSpread({}, attribs), {}, {
7
- src: "https://canvas.instructure.com".concat(attribs.src),
8
- style: 'vertical-align: middle'
9
- })
10
- };
11
- }
12
- function transformImage(tagName, attribs) {
13
- if (attribs.src != null && attribs.src.indexOf('/equation_images') === 0) {
14
- return transformEquationImage(tagName, attribs);
1
+ import DOMPurify from 'dompurify';
2
+ var CONFIG = {
3
+ ADD_TAGS: ['iframe'],
4
+ ADD_ATTR: ['allowfullscreen', 'allow', 'frameborder', 'sandbox', 'target', 'data-media-id', 'data-media-type'],
5
+ FORBID_TAGS: ['form', 'input', 'button', 'textarea', 'select', 'option']
6
+ };
7
+
8
+ // Rewrite Canvas equation-image relative URLs to absolute,
9
+ // preserving the previous behavior of this module.
10
+ DOMPurify.addHook('afterSanitizeAttributes', function (node) {
11
+ if (node.tagName === 'IMG') {
12
+ var src = node.getAttribute('src') || '';
13
+ if (src.indexOf('/equation_images') === 0) {
14
+ node.setAttribute('src', "https://canvas.instructure.com".concat(src));
15
+ node.setAttribute('style', 'vertical-align: middle');
16
+ }
17
+ }
18
+ // Harden links opened in a new tab against tab-nabbing.
19
+ if (node.tagName === 'A' && node.getAttribute('target') === '_blank') {
20
+ node.setAttribute('rel', 'noopener noreferrer');
15
21
  }
16
- return {
17
- tagName: tagName,
18
- attribs: attribs
19
- };
20
- }
22
+ });
21
23
  export function sanitizeHtml(html) {
22
- return libSanitizeHtml(html, {
23
- allowedTags: false,
24
- allowedAttributes: false,
25
- transformTags: {
26
- img: transformImage
27
- }
28
- });
24
+ return DOMPurify.sanitize(html == null ? '' : html, CONFIG);
29
25
  }
@@ -23,10 +23,13 @@ describe('OutcomeCheckbox', function () {
23
23
  }, props);
24
24
  }
25
25
  it('renders a checkbox', function () {
26
- var wrapper = mount( /*#__PURE__*/React.createElement(OutcomeCheckbox, makeProps()), {
26
+ var props = makeProps();
27
+ var wrapper = mount( /*#__PURE__*/React.createElement(OutcomeCheckbox, props), {
27
28
  disableLifecycleMethods: true
28
29
  });
29
- expect(wrapper.find(Checkbox)).to.have.length(1);
30
+ var checkbox = wrapper.find(Checkbox);
31
+ expect(checkbox).to.have.length(1);
32
+ expect(checkbox.prop('id')).to.equal("outcome-select-".concat(props.outcome.id));
30
33
  });
31
34
  it('renders outcome title in link', function () {
32
35
  var props = makeProps();
@@ -48,6 +48,7 @@ var OutcomeCheckbox = (_dec = withStyle(generateStyle, generateComponentTheme),
48
48
  css: this.props.styles.checkbox,
49
49
  className: "OutcomeSelector"
50
50
  }, jsx(Checkbox, {
51
+ id: "outcome-select-".concat(id),
51
52
  value: id,
52
53
  checked: this.selected(),
53
54
  onChange: function onChange() {
@@ -68,6 +68,7 @@ describe('OutcomeSelectionList', function () {
68
68
  });
69
69
  // Enzyme finds extra Checkbox components because of the instui decorator on the component
70
70
  expect(wrapper.find('Checkbox[value="selectAll"]')).to.have.length(3);
71
+ expect(wrapper.find('Checkbox[value="selectAll"]').at(0).prop('id')).to.equal('outcome-select-all');
71
72
  });
72
73
  it('renders select all as unchecked when no outcomes selected', function () {
73
74
  var wrapper = mount( /*#__PURE__*/React.createElement(OutcomeSelectionList, makeProps()), {
@@ -77,6 +77,7 @@ var OutcomeSelectionList = (_dec = withStyle(generateStyle, generateComponentThe
77
77
  }, jsx("div", {
78
78
  css: this.props.styles.checkbox
79
79
  }, jsx(Checkbox, {
80
+ id: "outcome-select-all",
80
81
  value: "selectAll",
81
82
  checked: this.allSelected(),
82
83
  onChange: function onChange() {
@@ -1,16 +1,138 @@
1
1
  import { expect } from 'chai';
2
2
  import { sanitizeHtml } from "../sanitize.js";
3
- describe('sanitizeForHtml', function () {
4
- it('cleans invalid tags', function () {
5
- var invalid = '<monkey>tag isn\'t closed';
6
- expect(sanitizeHtml(invalid)).to.include('</monkey>');
3
+ describe('sanitizeHtml', function () {
4
+ describe('equation images (Canvas-specific)', function () {
5
+ it('rewrites /equation_images src to absolute canvas URL', function () {
6
+ var equationImage = 'Some text with an <img src="/equation_images/image" />';
7
+ expect(sanitizeHtml(equationImage)).to.include('canvas.instructure.com/equation_images/image');
8
+ });
9
+ it('adds vertical-align style to equation images', function () {
10
+ var equationImage = '<img src="/equation_images/abc" />';
11
+ expect(sanitizeHtml(equationImage)).to.include('vertical-align: middle');
12
+ });
13
+ it('leaves non-equation image src untouched', function () {
14
+ var otherImage = '<img src="/another_image">';
15
+ var out = sanitizeHtml(otherImage);
16
+ expect(out).to.include('src="/another_image"');
17
+ expect(out).to.not.include('canvas.instructure.com');
18
+ });
7
19
  });
8
- it('replaces equation images', function () {
9
- var equationImage = 'Some text with an <img src="/equation_images/image" />';
10
- expect(sanitizeHtml(equationImage)).to.include('canvas.instructure.com/equation_images/image');
20
+ describe('null / empty input handling', function () {
21
+ it('returns empty string for null', function () {
22
+ expect(sanitizeHtml(null)).to.equal('');
23
+ });
24
+ it('returns empty string for undefined', function () {
25
+ expect(sanitizeHtml(void 0)).to.equal('');
26
+ });
27
+ it('returns empty string for empty string', function () {
28
+ expect(sanitizeHtml('')).to.equal('');
29
+ });
11
30
  });
12
- it('leaves other images alone', function () {
13
- var otherImage = 'Some text with <img src="/another_image" />';
14
- expect(sanitizeHtml(otherImage)).to.eq(otherImage);
31
+ describe('XSS - script execution vectors', function () {
32
+ it('strips <script> tags', function () {
33
+ var xss = 'Hello<script>alert(1)</script>World';
34
+ var out = sanitizeHtml(xss);
35
+ expect(out).to.not.include('<script');
36
+ expect(out).to.not.include('alert(1)');
37
+ });
38
+ it('strips inline event handlers (onerror)', function () {
39
+ var xss = '<img src="x" onerror="alert(1)">';
40
+ var out = sanitizeHtml(xss);
41
+ expect(out).to.not.match(/onerror/i);
42
+ expect(out).to.not.include('alert(1)');
43
+ });
44
+ it('strips inline event handlers (onclick)', function () {
45
+ var xss = '<a href="#" onclick="alert(1)">click</a>';
46
+ var out = sanitizeHtml(xss);
47
+ expect(out).to.not.match(/onclick/i);
48
+ });
49
+ it('strips inline event handlers (onload on svg)', function () {
50
+ var xss = '<svg onload="alert(1)"></svg>';
51
+ var out = sanitizeHtml(xss);
52
+ expect(out).to.not.match(/onload/i);
53
+ expect(out).to.not.include('alert(1)');
54
+ });
55
+ it('strips javascript: URLs in href', function () {
56
+ // eslint-disable-next-line no-script-url
57
+ var xss = '<a href="javascript:alert(1)">x</a>';
58
+ var out = sanitizeHtml(xss);
59
+ expect(out).to.not.match(/javascript:/i);
60
+ });
61
+ it('strips javascript: URLs in img src', function () {
62
+ // eslint-disable-next-line no-script-url
63
+ var xss = '<img src="javascript:alert(1)">';
64
+ var out = sanitizeHtml(xss);
65
+ expect(out).to.not.match(/javascript:/i);
66
+ });
67
+ it('strips data: URLs that contain HTML/JS in iframe src', function () {
68
+ var xss = '<iframe src="data:text/html,<script>alert(1)</script>"></iframe>';
69
+ var out = sanitizeHtml(xss);
70
+ expect(out).to.not.include('alert(1)');
71
+ });
72
+ it('strips <object> tags', function () {
73
+ var xss = '<object data="evil.swf"></object>';
74
+ expect(sanitizeHtml(xss)).to.not.include('<object');
75
+ });
76
+ it('strips <embed> tags', function () {
77
+ var xss = '<embed src="evil.swf">';
78
+ expect(sanitizeHtml(xss)).to.not.include('<embed');
79
+ });
80
+ it('strips <form> tags (CSRF / phishing surface)', function () {
81
+ var xss = '<form action="https://evil.com"><input name=x></form>';
82
+ expect(sanitizeHtml(xss)).to.not.include('<form');
83
+ });
84
+ it('strips style tags (CSS-based exfil / clickjacking)', function () {
85
+ var xss = '<style>body{background:url(//evil.com/?c=)}</style>';
86
+ expect(sanitizeHtml(xss)).to.not.include('<style');
87
+ });
88
+ it('strips <meta http-equiv refresh> redirects', function () {
89
+ var xss = '<meta http-equiv="refresh" content="0;url=https://evil.com">';
90
+ expect(sanitizeHtml(xss)).to.not.include('<meta');
91
+ });
92
+ it('strips <base> tag (can rewrite all relative URLs)', function () {
93
+ var xss = '<base href="https://evil.com/">';
94
+ expect(sanitizeHtml(xss)).to.not.include('<base');
95
+ });
96
+ it('strips encoded onerror payloads', function () {
97
+ var xss = '<img src=x onerror=&#97;&#108;&#101;&#114;&#116;(1)>';
98
+ var out = sanitizeHtml(xss);
99
+ expect(out).to.not.match(/onerror/i);
100
+ });
101
+ it('strips mixed-case obfuscated script tags', function () {
102
+ var xss = '<ScRiPt>alert(1)</sCrIpT>';
103
+ var out = sanitizeHtml(xss);
104
+ expect(out).to.not.match(/<script/i);
105
+ expect(out).to.not.include('alert(1)');
106
+ });
107
+ });
108
+ describe('benign HTML (should be preserved)', function () {
109
+ it('preserves basic formatting tags', function () {
110
+ var html = '<p>Hello <strong>world</strong> <em>!</em></p>';
111
+ expect(sanitizeHtml(html)).to.equal(html);
112
+ });
113
+ it('preserves links with safe http(s) hrefs', function () {
114
+ var html = '<a href="https://example.com">link</a>';
115
+ expect(sanitizeHtml(html)).to.include('href="https://example.com"');
116
+ });
117
+ it('preserves lists', function () {
118
+ var html = '<ul><li>a</li><li>b</li></ul>';
119
+ expect(sanitizeHtml(html)).to.equal(html);
120
+ });
121
+ it('preserves Canvas RCE iframes (Studio / media embeds)', function () {
122
+ var html = '<iframe src="https://canvas.instructure.com/media_objects_iframe/123" ' + 'allowfullscreen="" allow="fullscreen" frameborder="0" ' + 'data-media-id="123" data-media-type="video"></iframe>';
123
+ var out = sanitizeHtml(html);
124
+ expect(out).to.include('<iframe');
125
+ expect(out).to.include('data-media-id="123"');
126
+ expect(out).to.include('data-media-type="video"');
127
+ expect(out).to.include('allowfullscreen');
128
+ });
129
+ });
130
+ describe('link hardening', function () {
131
+ it('adds rel="noopener noreferrer" to target=_blank links', function () {
132
+ var html = '<a href="https://example.com" target="_blank">x</a>';
133
+ var out = sanitizeHtml(html);
134
+ expect(out).to.match(/rel=["'][^"']*noopener[^"']*["']/);
135
+ expect(out).to.match(/rel=["'][^"']*noreferrer[^"']*["']/);
136
+ });
15
137
  });
16
138
  });
@@ -1,29 +1,25 @@
1
- import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
2
- import libSanitizeHtml from 'sanitize-html';
3
- function transformEquationImage(tagName, attribs) {
4
- return {
5
- tagName: tagName,
6
- attribs: _objectSpread(_objectSpread({}, attribs), {}, {
7
- src: "https://canvas.instructure.com".concat(attribs.src),
8
- style: 'vertical-align: middle'
9
- })
10
- };
11
- }
12
- function transformImage(tagName, attribs) {
13
- if (attribs.src != null && attribs.src.indexOf('/equation_images') === 0) {
14
- return transformEquationImage(tagName, attribs);
1
+ import DOMPurify from 'dompurify';
2
+ var CONFIG = {
3
+ ADD_TAGS: ['iframe'],
4
+ ADD_ATTR: ['allowfullscreen', 'allow', 'frameborder', 'sandbox', 'target', 'data-media-id', 'data-media-type'],
5
+ FORBID_TAGS: ['form', 'input', 'button', 'textarea', 'select', 'option']
6
+ };
7
+
8
+ // Rewrite Canvas equation-image relative URLs to absolute,
9
+ // preserving the previous behavior of this module.
10
+ DOMPurify.addHook('afterSanitizeAttributes', function (node) {
11
+ if (node.tagName === 'IMG') {
12
+ var src = node.getAttribute('src') || '';
13
+ if (src.indexOf('/equation_images') === 0) {
14
+ node.setAttribute('src', "https://canvas.instructure.com".concat(src));
15
+ node.setAttribute('style', 'vertical-align: middle');
16
+ }
17
+ }
18
+ // Harden links opened in a new tab against tab-nabbing.
19
+ if (node.tagName === 'A' && node.getAttribute('target') === '_blank') {
20
+ node.setAttribute('rel', 'noopener noreferrer');
15
21
  }
16
- return {
17
- tagName: tagName,
18
- attribs: attribs
19
- };
20
- }
22
+ });
21
23
  export function sanitizeHtml(html) {
22
- return libSanitizeHtml(html, {
23
- allowedTags: false,
24
- allowedAttributes: false,
25
- transformTags: {
26
- img: transformImage
27
- }
28
- });
24
+ return DOMPurify.sanitize(html == null ? '' : html, CONFIG);
29
25
  }
@@ -23,10 +23,13 @@ describe('OutcomeCheckbox', function () {
23
23
  }, props);
24
24
  }
25
25
  it('renders a checkbox', function () {
26
- var wrapper = mount( /*#__PURE__*/React.createElement(OutcomeCheckbox, makeProps()), {
26
+ var props = makeProps();
27
+ var wrapper = mount( /*#__PURE__*/React.createElement(OutcomeCheckbox, props), {
27
28
  disableLifecycleMethods: true
28
29
  });
29
- expect(wrapper.find(Checkbox)).to.have.length(1);
30
+ var checkbox = wrapper.find(Checkbox);
31
+ expect(checkbox).to.have.length(1);
32
+ expect(checkbox.prop('id')).to.equal("outcome-select-".concat(props.outcome.id));
30
33
  });
31
34
  it('renders outcome title in link', function () {
32
35
  var props = makeProps();
@@ -48,6 +48,7 @@ var OutcomeCheckbox = (_dec = withStyle(generateStyle, generateComponentTheme),
48
48
  css: this.props.styles.checkbox,
49
49
  className: "OutcomeSelector"
50
50
  }, jsx(Checkbox, {
51
+ id: "outcome-select-".concat(id),
51
52
  value: id,
52
53
  checked: this.selected(),
53
54
  onChange: function onChange() {
@@ -68,6 +68,7 @@ describe('OutcomeSelectionList', function () {
68
68
  });
69
69
  // Enzyme finds extra Checkbox components because of the instui decorator on the component
70
70
  expect(wrapper.find('Checkbox[value="selectAll"]')).to.have.length(3);
71
+ expect(wrapper.find('Checkbox[value="selectAll"]').at(0).prop('id')).to.equal('outcome-select-all');
71
72
  });
72
73
  it('renders select all as unchecked when no outcomes selected', function () {
73
74
  var wrapper = mount( /*#__PURE__*/React.createElement(OutcomeSelectionList, makeProps()), {
@@ -77,6 +77,7 @@ var OutcomeSelectionList = (_dec = withStyle(generateStyle, generateComponentThe
77
77
  }, jsx("div", {
78
78
  css: this.props.styles.checkbox
79
79
  }, jsx(Checkbox, {
80
+ id: "outcome-select-all",
80
81
  value: "selectAll",
81
82
  checked: this.allSelected(),
82
83
  onChange: function onChange() {
@@ -1,16 +1,138 @@
1
1
  import { expect } from 'chai';
2
2
  import { sanitizeHtml } from "../sanitize.js";
3
- describe('sanitizeForHtml', function () {
4
- it('cleans invalid tags', function () {
5
- var invalid = '<monkey>tag isn\'t closed';
6
- expect(sanitizeHtml(invalid)).to.include('</monkey>');
3
+ describe('sanitizeHtml', function () {
4
+ describe('equation images (Canvas-specific)', function () {
5
+ it('rewrites /equation_images src to absolute canvas URL', function () {
6
+ var equationImage = 'Some text with an <img src="/equation_images/image" />';
7
+ expect(sanitizeHtml(equationImage)).to.include('canvas.instructure.com/equation_images/image');
8
+ });
9
+ it('adds vertical-align style to equation images', function () {
10
+ var equationImage = '<img src="/equation_images/abc" />';
11
+ expect(sanitizeHtml(equationImage)).to.include('vertical-align: middle');
12
+ });
13
+ it('leaves non-equation image src untouched', function () {
14
+ var otherImage = '<img src="/another_image">';
15
+ var out = sanitizeHtml(otherImage);
16
+ expect(out).to.include('src="/another_image"');
17
+ expect(out).to.not.include('canvas.instructure.com');
18
+ });
7
19
  });
8
- it('replaces equation images', function () {
9
- var equationImage = 'Some text with an <img src="/equation_images/image" />';
10
- expect(sanitizeHtml(equationImage)).to.include('canvas.instructure.com/equation_images/image');
20
+ describe('null / empty input handling', function () {
21
+ it('returns empty string for null', function () {
22
+ expect(sanitizeHtml(null)).to.equal('');
23
+ });
24
+ it('returns empty string for undefined', function () {
25
+ expect(sanitizeHtml(void 0)).to.equal('');
26
+ });
27
+ it('returns empty string for empty string', function () {
28
+ expect(sanitizeHtml('')).to.equal('');
29
+ });
11
30
  });
12
- it('leaves other images alone', function () {
13
- var otherImage = 'Some text with <img src="/another_image" />';
14
- expect(sanitizeHtml(otherImage)).to.eq(otherImage);
31
+ describe('XSS - script execution vectors', function () {
32
+ it('strips <script> tags', function () {
33
+ var xss = 'Hello<script>alert(1)</script>World';
34
+ var out = sanitizeHtml(xss);
35
+ expect(out).to.not.include('<script');
36
+ expect(out).to.not.include('alert(1)');
37
+ });
38
+ it('strips inline event handlers (onerror)', function () {
39
+ var xss = '<img src="x" onerror="alert(1)">';
40
+ var out = sanitizeHtml(xss);
41
+ expect(out).to.not.match(/onerror/i);
42
+ expect(out).to.not.include('alert(1)');
43
+ });
44
+ it('strips inline event handlers (onclick)', function () {
45
+ var xss = '<a href="#" onclick="alert(1)">click</a>';
46
+ var out = sanitizeHtml(xss);
47
+ expect(out).to.not.match(/onclick/i);
48
+ });
49
+ it('strips inline event handlers (onload on svg)', function () {
50
+ var xss = '<svg onload="alert(1)"></svg>';
51
+ var out = sanitizeHtml(xss);
52
+ expect(out).to.not.match(/onload/i);
53
+ expect(out).to.not.include('alert(1)');
54
+ });
55
+ it('strips javascript: URLs in href', function () {
56
+ // eslint-disable-next-line no-script-url
57
+ var xss = '<a href="javascript:alert(1)">x</a>';
58
+ var out = sanitizeHtml(xss);
59
+ expect(out).to.not.match(/javascript:/i);
60
+ });
61
+ it('strips javascript: URLs in img src', function () {
62
+ // eslint-disable-next-line no-script-url
63
+ var xss = '<img src="javascript:alert(1)">';
64
+ var out = sanitizeHtml(xss);
65
+ expect(out).to.not.match(/javascript:/i);
66
+ });
67
+ it('strips data: URLs that contain HTML/JS in iframe src', function () {
68
+ var xss = '<iframe src="data:text/html,<script>alert(1)</script>"></iframe>';
69
+ var out = sanitizeHtml(xss);
70
+ expect(out).to.not.include('alert(1)');
71
+ });
72
+ it('strips <object> tags', function () {
73
+ var xss = '<object data="evil.swf"></object>';
74
+ expect(sanitizeHtml(xss)).to.not.include('<object');
75
+ });
76
+ it('strips <embed> tags', function () {
77
+ var xss = '<embed src="evil.swf">';
78
+ expect(sanitizeHtml(xss)).to.not.include('<embed');
79
+ });
80
+ it('strips <form> tags (CSRF / phishing surface)', function () {
81
+ var xss = '<form action="https://evil.com"><input name=x></form>';
82
+ expect(sanitizeHtml(xss)).to.not.include('<form');
83
+ });
84
+ it('strips style tags (CSS-based exfil / clickjacking)', function () {
85
+ var xss = '<style>body{background:url(//evil.com/?c=)}</style>';
86
+ expect(sanitizeHtml(xss)).to.not.include('<style');
87
+ });
88
+ it('strips <meta http-equiv refresh> redirects', function () {
89
+ var xss = '<meta http-equiv="refresh" content="0;url=https://evil.com">';
90
+ expect(sanitizeHtml(xss)).to.not.include('<meta');
91
+ });
92
+ it('strips <base> tag (can rewrite all relative URLs)', function () {
93
+ var xss = '<base href="https://evil.com/">';
94
+ expect(sanitizeHtml(xss)).to.not.include('<base');
95
+ });
96
+ it('strips encoded onerror payloads', function () {
97
+ var xss = '<img src=x onerror=&#97;&#108;&#101;&#114;&#116;(1)>';
98
+ var out = sanitizeHtml(xss);
99
+ expect(out).to.not.match(/onerror/i);
100
+ });
101
+ it('strips mixed-case obfuscated script tags', function () {
102
+ var xss = '<ScRiPt>alert(1)</sCrIpT>';
103
+ var out = sanitizeHtml(xss);
104
+ expect(out).to.not.match(/<script/i);
105
+ expect(out).to.not.include('alert(1)');
106
+ });
107
+ });
108
+ describe('benign HTML (should be preserved)', function () {
109
+ it('preserves basic formatting tags', function () {
110
+ var html = '<p>Hello <strong>world</strong> <em>!</em></p>';
111
+ expect(sanitizeHtml(html)).to.equal(html);
112
+ });
113
+ it('preserves links with safe http(s) hrefs', function () {
114
+ var html = '<a href="https://example.com">link</a>';
115
+ expect(sanitizeHtml(html)).to.include('href="https://example.com"');
116
+ });
117
+ it('preserves lists', function () {
118
+ var html = '<ul><li>a</li><li>b</li></ul>';
119
+ expect(sanitizeHtml(html)).to.equal(html);
120
+ });
121
+ it('preserves Canvas RCE iframes (Studio / media embeds)', function () {
122
+ var html = '<iframe src="https://canvas.instructure.com/media_objects_iframe/123" ' + 'allowfullscreen="" allow="fullscreen" frameborder="0" ' + 'data-media-id="123" data-media-type="video"></iframe>';
123
+ var out = sanitizeHtml(html);
124
+ expect(out).to.include('<iframe');
125
+ expect(out).to.include('data-media-id="123"');
126
+ expect(out).to.include('data-media-type="video"');
127
+ expect(out).to.include('allowfullscreen');
128
+ });
129
+ });
130
+ describe('link hardening', function () {
131
+ it('adds rel="noopener noreferrer" to target=_blank links', function () {
132
+ var html = '<a href="https://example.com" target="_blank">x</a>';
133
+ var out = sanitizeHtml(html);
134
+ expect(out).to.match(/rel=["'][^"']*noopener[^"']*["']/);
135
+ expect(out).to.match(/rel=["'][^"']*noreferrer[^"']*["']/);
136
+ });
15
137
  });
16
138
  });