@instructure/outcomes-ui 4.1.4 → 4.1.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 (322) hide show
  1. package/es/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  2. package/es/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  3. package/es/lib/__tests__/sanitize.test.js +133 -11
  4. package/es/lib/sanitize.js +22 -26
  5. package/es/translated/ar/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  6. package/es/translated/ar/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  7. package/es/translated/ar/lib/__tests__/sanitize.test.js +133 -11
  8. package/es/translated/ar/lib/sanitize.js +22 -26
  9. package/es/translated/ca/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  10. package/es/translated/ca/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  11. package/es/translated/ca/lib/__tests__/sanitize.test.js +133 -11
  12. package/es/translated/ca/lib/sanitize.js +22 -26
  13. package/es/translated/cy/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  14. package/es/translated/cy/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  15. package/es/translated/cy/lib/__tests__/sanitize.test.js +133 -11
  16. package/es/translated/cy/lib/sanitize.js +22 -26
  17. package/es/translated/da/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  18. package/es/translated/da/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  19. package/es/translated/da/lib/__tests__/sanitize.test.js +133 -11
  20. package/es/translated/da/lib/sanitize.js +22 -26
  21. package/es/translated/da-x-k12/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  22. package/es/translated/da-x-k12/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  23. package/es/translated/da-x-k12/lib/__tests__/sanitize.test.js +133 -11
  24. package/es/translated/da-x-k12/lib/sanitize.js +22 -26
  25. package/es/translated/de/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  26. package/es/translated/de/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  27. package/es/translated/de/lib/__tests__/sanitize.test.js +133 -11
  28. package/es/translated/de/lib/sanitize.js +22 -26
  29. package/es/translated/en/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  30. package/es/translated/en/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  31. package/es/translated/en/lib/__tests__/sanitize.test.js +133 -11
  32. package/es/translated/en/lib/sanitize.js +22 -26
  33. package/es/translated/en-AU/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  34. package/es/translated/en-AU/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  35. package/es/translated/en-AU/lib/__tests__/sanitize.test.js +133 -11
  36. package/es/translated/en-AU/lib/sanitize.js +22 -26
  37. package/es/translated/en-AU-x-unimelb/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  38. package/es/translated/en-AU-x-unimelb/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  39. package/es/translated/en-AU-x-unimelb/lib/__tests__/sanitize.test.js +133 -11
  40. package/es/translated/en-AU-x-unimelb/lib/sanitize.js +22 -26
  41. package/es/translated/en-CA/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  42. package/es/translated/en-CA/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  43. package/es/translated/en-CA/lib/__tests__/sanitize.test.js +133 -11
  44. package/es/translated/en-CA/lib/sanitize.js +22 -26
  45. package/es/translated/en-CY/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  46. package/es/translated/en-CY/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  47. package/es/translated/en-CY/lib/__tests__/sanitize.test.js +133 -11
  48. package/es/translated/en-CY/lib/sanitize.js +22 -26
  49. package/es/translated/en-GB/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  50. package/es/translated/en-GB/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  51. package/es/translated/en-GB/lib/__tests__/sanitize.test.js +133 -11
  52. package/es/translated/en-GB/lib/sanitize.js +22 -26
  53. package/es/translated/en-GB-x-ukhe/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  54. package/es/translated/en-GB-x-ukhe/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  55. package/es/translated/en-GB-x-ukhe/lib/__tests__/sanitize.test.js +133 -11
  56. package/es/translated/en-GB-x-ukhe/lib/sanitize.js +22 -26
  57. package/es/translated/en-IE/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  58. package/es/translated/en-IE/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  59. package/es/translated/en-IE/lib/__tests__/sanitize.test.js +133 -11
  60. package/es/translated/en-IE/lib/sanitize.js +22 -26
  61. package/es/translated/es/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  62. package/es/translated/es/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  63. package/es/translated/es/lib/__tests__/sanitize.test.js +133 -11
  64. package/es/translated/es/lib/sanitize.js +22 -26
  65. package/es/translated/es-ES/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  66. package/es/translated/es-ES/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  67. package/es/translated/es-ES/lib/__tests__/sanitize.test.js +133 -11
  68. package/es/translated/es-ES/lib/sanitize.js +22 -26
  69. package/es/translated/es_ES/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  70. package/es/translated/es_ES/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  71. package/es/translated/es_ES/lib/__tests__/sanitize.test.js +133 -11
  72. package/es/translated/es_ES/lib/sanitize.js +22 -26
  73. package/es/translated/fi/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  74. package/es/translated/fi/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  75. package/es/translated/fi/lib/__tests__/sanitize.test.js +133 -11
  76. package/es/translated/fi/lib/sanitize.js +22 -26
  77. package/es/translated/fr/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  78. package/es/translated/fr/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  79. package/es/translated/fr/lib/__tests__/sanitize.test.js +133 -11
  80. package/es/translated/fr/lib/sanitize.js +22 -26
  81. package/es/translated/fr-CA/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  82. package/es/translated/fr-CA/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  83. package/es/translated/fr-CA/lib/__tests__/sanitize.test.js +133 -11
  84. package/es/translated/fr-CA/lib/sanitize.js +22 -26
  85. package/es/translated/ht/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  86. package/es/translated/ht/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  87. package/es/translated/ht/lib/__tests__/sanitize.test.js +133 -11
  88. package/es/translated/ht/lib/sanitize.js +22 -26
  89. package/es/translated/is/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  90. package/es/translated/is/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  91. package/es/translated/is/lib/__tests__/sanitize.test.js +133 -11
  92. package/es/translated/is/lib/sanitize.js +22 -26
  93. package/es/translated/it/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  94. package/es/translated/it/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  95. package/es/translated/it/lib/__tests__/sanitize.test.js +133 -11
  96. package/es/translated/it/lib/sanitize.js +22 -26
  97. package/es/translated/ja/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  98. package/es/translated/ja/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  99. package/es/translated/ja/lib/__tests__/sanitize.test.js +133 -11
  100. package/es/translated/ja/lib/sanitize.js +22 -26
  101. package/es/translated/mi/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  102. package/es/translated/mi/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  103. package/es/translated/mi/lib/__tests__/sanitize.test.js +133 -11
  104. package/es/translated/mi/lib/sanitize.js +22 -26
  105. package/es/translated/nb/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  106. package/es/translated/nb/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  107. package/es/translated/nb/lib/__tests__/sanitize.test.js +133 -11
  108. package/es/translated/nb/lib/sanitize.js +22 -26
  109. package/es/translated/nb-x-k12/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  110. package/es/translated/nb-x-k12/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  111. package/es/translated/nb-x-k12/lib/__tests__/sanitize.test.js +133 -11
  112. package/es/translated/nb-x-k12/lib/sanitize.js +22 -26
  113. package/es/translated/nl/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  114. package/es/translated/nl/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  115. package/es/translated/nl/lib/__tests__/sanitize.test.js +133 -11
  116. package/es/translated/nl/lib/sanitize.js +22 -26
  117. package/es/translated/pl/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  118. package/es/translated/pl/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  119. package/es/translated/pl/lib/__tests__/sanitize.test.js +133 -11
  120. package/es/translated/pl/lib/sanitize.js +22 -26
  121. package/es/translated/pt/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  122. package/es/translated/pt/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  123. package/es/translated/pt/lib/__tests__/sanitize.test.js +133 -11
  124. package/es/translated/pt/lib/sanitize.js +22 -26
  125. package/es/translated/pt-BR/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  126. package/es/translated/pt-BR/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  127. package/es/translated/pt-BR/lib/__tests__/sanitize.test.js +133 -11
  128. package/es/translated/pt-BR/lib/sanitize.js +22 -26
  129. package/es/translated/ru/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  130. package/es/translated/ru/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  131. package/es/translated/ru/lib/__tests__/sanitize.test.js +133 -11
  132. package/es/translated/ru/lib/sanitize.js +22 -26
  133. package/es/translated/sl/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  134. package/es/translated/sl/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  135. package/es/translated/sl/lib/__tests__/sanitize.test.js +133 -11
  136. package/es/translated/sl/lib/sanitize.js +22 -26
  137. package/es/translated/sv/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  138. package/es/translated/sv/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  139. package/es/translated/sv/lib/__tests__/sanitize.test.js +133 -11
  140. package/es/translated/sv/lib/sanitize.js +22 -26
  141. package/es/translated/sv-x-k12/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  142. package/es/translated/sv-x-k12/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  143. package/es/translated/sv-x-k12/lib/__tests__/sanitize.test.js +133 -11
  144. package/es/translated/sv-x-k12/lib/sanitize.js +22 -26
  145. package/es/translated/th/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  146. package/es/translated/th/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  147. package/es/translated/th/lib/__tests__/sanitize.test.js +133 -11
  148. package/es/translated/th/lib/sanitize.js +22 -26
  149. package/es/translated/vi/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  150. package/es/translated/vi/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  151. package/es/translated/vi/lib/__tests__/sanitize.test.js +133 -11
  152. package/es/translated/vi/lib/sanitize.js +22 -26
  153. package/es/translated/zh-Hans/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  154. package/es/translated/zh-Hans/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  155. package/es/translated/zh-Hans/lib/__tests__/sanitize.test.js +133 -11
  156. package/es/translated/zh-Hans/lib/sanitize.js +22 -26
  157. package/es/translated/zh-Hant/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  158. package/es/translated/zh-Hant/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  159. package/es/translated/zh-Hant/lib/__tests__/sanitize.test.js +133 -11
  160. package/es/translated/zh-Hant/lib/sanitize.js +22 -26
  161. package/lib/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  162. package/lib/components/Gradebook/popovers/StudentPopover/index.d.ts.map +1 -1
  163. package/lib/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  164. package/lib/lib/__tests__/sanitize.test.js +132 -10
  165. package/lib/lib/sanitize.js +22 -26
  166. package/lib/translated/ar/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  167. package/lib/translated/ar/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  168. package/lib/translated/ar/lib/__tests__/sanitize.test.js +132 -10
  169. package/lib/translated/ar/lib/sanitize.js +22 -26
  170. package/lib/translated/ca/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  171. package/lib/translated/ca/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  172. package/lib/translated/ca/lib/__tests__/sanitize.test.js +132 -10
  173. package/lib/translated/ca/lib/sanitize.js +22 -26
  174. package/lib/translated/cy/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  175. package/lib/translated/cy/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  176. package/lib/translated/cy/lib/__tests__/sanitize.test.js +132 -10
  177. package/lib/translated/cy/lib/sanitize.js +22 -26
  178. package/lib/translated/da/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  179. package/lib/translated/da/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  180. package/lib/translated/da/lib/__tests__/sanitize.test.js +132 -10
  181. package/lib/translated/da/lib/sanitize.js +22 -26
  182. package/lib/translated/da-x-k12/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  183. package/lib/translated/da-x-k12/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  184. package/lib/translated/da-x-k12/lib/__tests__/sanitize.test.js +132 -10
  185. package/lib/translated/da-x-k12/lib/sanitize.js +22 -26
  186. package/lib/translated/de/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  187. package/lib/translated/de/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  188. package/lib/translated/de/lib/__tests__/sanitize.test.js +132 -10
  189. package/lib/translated/de/lib/sanitize.js +22 -26
  190. package/lib/translated/en/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  191. package/lib/translated/en/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  192. package/lib/translated/en/lib/__tests__/sanitize.test.js +132 -10
  193. package/lib/translated/en/lib/sanitize.js +22 -26
  194. package/lib/translated/en-AU/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  195. package/lib/translated/en-AU/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  196. package/lib/translated/en-AU/lib/__tests__/sanitize.test.js +132 -10
  197. package/lib/translated/en-AU/lib/sanitize.js +22 -26
  198. package/lib/translated/en-AU-x-unimelb/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  199. package/lib/translated/en-AU-x-unimelb/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  200. package/lib/translated/en-AU-x-unimelb/lib/__tests__/sanitize.test.js +132 -10
  201. package/lib/translated/en-AU-x-unimelb/lib/sanitize.js +22 -26
  202. package/lib/translated/en-CA/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  203. package/lib/translated/en-CA/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  204. package/lib/translated/en-CA/lib/__tests__/sanitize.test.js +132 -10
  205. package/lib/translated/en-CA/lib/sanitize.js +22 -26
  206. package/lib/translated/en-CY/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  207. package/lib/translated/en-CY/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  208. package/lib/translated/en-CY/lib/__tests__/sanitize.test.js +132 -10
  209. package/lib/translated/en-CY/lib/sanitize.js +22 -26
  210. package/lib/translated/en-GB/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  211. package/lib/translated/en-GB/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  212. package/lib/translated/en-GB/lib/__tests__/sanitize.test.js +132 -10
  213. package/lib/translated/en-GB/lib/sanitize.js +22 -26
  214. package/lib/translated/en-GB-x-ukhe/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  215. package/lib/translated/en-GB-x-ukhe/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  216. package/lib/translated/en-GB-x-ukhe/lib/__tests__/sanitize.test.js +132 -10
  217. package/lib/translated/en-GB-x-ukhe/lib/sanitize.js +22 -26
  218. package/lib/translated/en-IE/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  219. package/lib/translated/en-IE/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  220. package/lib/translated/en-IE/lib/__tests__/sanitize.test.js +132 -10
  221. package/lib/translated/en-IE/lib/sanitize.js +22 -26
  222. package/lib/translated/es/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  223. package/lib/translated/es/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  224. package/lib/translated/es/lib/__tests__/sanitize.test.js +132 -10
  225. package/lib/translated/es/lib/sanitize.js +22 -26
  226. package/lib/translated/es-ES/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  227. package/lib/translated/es-ES/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  228. package/lib/translated/es-ES/lib/__tests__/sanitize.test.js +132 -10
  229. package/lib/translated/es-ES/lib/sanitize.js +22 -26
  230. package/lib/translated/es_ES/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  231. package/lib/translated/es_ES/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  232. package/lib/translated/es_ES/lib/__tests__/sanitize.test.js +132 -10
  233. package/lib/translated/es_ES/lib/sanitize.js +22 -26
  234. package/lib/translated/fi/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  235. package/lib/translated/fi/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  236. package/lib/translated/fi/lib/__tests__/sanitize.test.js +132 -10
  237. package/lib/translated/fi/lib/sanitize.js +22 -26
  238. package/lib/translated/fr/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  239. package/lib/translated/fr/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  240. package/lib/translated/fr/lib/__tests__/sanitize.test.js +132 -10
  241. package/lib/translated/fr/lib/sanitize.js +22 -26
  242. package/lib/translated/fr-CA/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  243. package/lib/translated/fr-CA/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  244. package/lib/translated/fr-CA/lib/__tests__/sanitize.test.js +132 -10
  245. package/lib/translated/fr-CA/lib/sanitize.js +22 -26
  246. package/lib/translated/ht/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  247. package/lib/translated/ht/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  248. package/lib/translated/ht/lib/__tests__/sanitize.test.js +132 -10
  249. package/lib/translated/ht/lib/sanitize.js +22 -26
  250. package/lib/translated/is/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  251. package/lib/translated/is/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  252. package/lib/translated/is/lib/__tests__/sanitize.test.js +132 -10
  253. package/lib/translated/is/lib/sanitize.js +22 -26
  254. package/lib/translated/it/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  255. package/lib/translated/it/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  256. package/lib/translated/it/lib/__tests__/sanitize.test.js +132 -10
  257. package/lib/translated/it/lib/sanitize.js +22 -26
  258. package/lib/translated/ja/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  259. package/lib/translated/ja/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  260. package/lib/translated/ja/lib/__tests__/sanitize.test.js +132 -10
  261. package/lib/translated/ja/lib/sanitize.js +22 -26
  262. package/lib/translated/mi/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  263. package/lib/translated/mi/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  264. package/lib/translated/mi/lib/__tests__/sanitize.test.js +132 -10
  265. package/lib/translated/mi/lib/sanitize.js +22 -26
  266. package/lib/translated/nb/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  267. package/lib/translated/nb/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  268. package/lib/translated/nb/lib/__tests__/sanitize.test.js +132 -10
  269. package/lib/translated/nb/lib/sanitize.js +22 -26
  270. package/lib/translated/nb-x-k12/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  271. package/lib/translated/nb-x-k12/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  272. package/lib/translated/nb-x-k12/lib/__tests__/sanitize.test.js +132 -10
  273. package/lib/translated/nb-x-k12/lib/sanitize.js +22 -26
  274. package/lib/translated/nl/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  275. package/lib/translated/nl/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  276. package/lib/translated/nl/lib/__tests__/sanitize.test.js +132 -10
  277. package/lib/translated/nl/lib/sanitize.js +22 -26
  278. package/lib/translated/pl/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  279. package/lib/translated/pl/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  280. package/lib/translated/pl/lib/__tests__/sanitize.test.js +132 -10
  281. package/lib/translated/pl/lib/sanitize.js +22 -26
  282. package/lib/translated/pt/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  283. package/lib/translated/pt/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  284. package/lib/translated/pt/lib/__tests__/sanitize.test.js +132 -10
  285. package/lib/translated/pt/lib/sanitize.js +22 -26
  286. package/lib/translated/pt-BR/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  287. package/lib/translated/pt-BR/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  288. package/lib/translated/pt-BR/lib/__tests__/sanitize.test.js +132 -10
  289. package/lib/translated/pt-BR/lib/sanitize.js +22 -26
  290. package/lib/translated/ru/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  291. package/lib/translated/ru/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  292. package/lib/translated/ru/lib/__tests__/sanitize.test.js +132 -10
  293. package/lib/translated/ru/lib/sanitize.js +22 -26
  294. package/lib/translated/sl/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  295. package/lib/translated/sl/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  296. package/lib/translated/sl/lib/__tests__/sanitize.test.js +132 -10
  297. package/lib/translated/sl/lib/sanitize.js +22 -26
  298. package/lib/translated/sv/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  299. package/lib/translated/sv/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  300. package/lib/translated/sv/lib/__tests__/sanitize.test.js +132 -10
  301. package/lib/translated/sv/lib/sanitize.js +22 -26
  302. package/lib/translated/sv-x-k12/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  303. package/lib/translated/sv-x-k12/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  304. package/lib/translated/sv-x-k12/lib/__tests__/sanitize.test.js +132 -10
  305. package/lib/translated/sv-x-k12/lib/sanitize.js +22 -26
  306. package/lib/translated/th/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  307. package/lib/translated/th/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  308. package/lib/translated/th/lib/__tests__/sanitize.test.js +132 -10
  309. package/lib/translated/th/lib/sanitize.js +22 -26
  310. package/lib/translated/vi/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  311. package/lib/translated/vi/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  312. package/lib/translated/vi/lib/__tests__/sanitize.test.js +132 -10
  313. package/lib/translated/vi/lib/sanitize.js +22 -26
  314. package/lib/translated/zh-Hans/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  315. package/lib/translated/zh-Hans/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  316. package/lib/translated/zh-Hans/lib/__tests__/sanitize.test.js +132 -10
  317. package/lib/translated/zh-Hans/lib/sanitize.js +22 -26
  318. package/lib/translated/zh-Hant/components/Gradebook/popovers/StudentPopover/__tests__/index.test.js +99 -23
  319. package/lib/translated/zh-Hant/components/Gradebook/popovers/StudentPopover/index.js +4 -1
  320. package/lib/translated/zh-Hant/lib/__tests__/sanitize.test.js +132 -10
  321. package/lib/translated/zh-Hant/lib/sanitize.js +22 -26
  322. package/package.json +3 -3
@@ -254,80 +254,156 @@ describe('StudentPopover', function () {
254
254
  }, _callee0);
255
255
  })));
256
256
  });
257
- describe('Loading State', function () {
258
- it('shows a spinner when isLoading is true', /*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee1() {
259
- var _t6;
257
+ describe('Security', function () {
258
+ it('does not render the mastery report link for a javascript: URI', /*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee1() {
260
259
  return _regenerator().w(function (_context1) {
261
260
  while (1) switch (_context1.n) {
262
261
  case 0:
263
262
  renderComponent({
264
- isLoading: true
263
+ studentGradesUrl: 'javascript:alert(document.cookie)'
265
264
  });
266
265
  fireEvent.click(screen.getByTestId('student-cell-link'));
267
- _t6 = expect;
268
266
  _context1.n = 1;
269
- return screen.findByTitle('Loading user details');
267
+ return screen.findByText('Message');
270
268
  case 1:
271
- _t6(_context1.v).toBeInTheDocument();
269
+ expect(screen.queryByText('View Mastery Report')).not.toBeInTheDocument();
272
270
  case 2:
273
271
  return _context1.a(2);
274
272
  }
275
273
  }, _callee1);
276
274
  })));
277
- it('does not show student details when isLoading is true', /*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee10() {
275
+ it('does not render the mastery report link for a data: URI', /*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee10() {
278
276
  return _regenerator().w(function (_context10) {
279
277
  while (1) switch (_context10.n) {
280
278
  case 0:
281
279
  renderComponent({
282
- isLoading: true
280
+ studentGradesUrl: 'data:text/html,<script>alert(1)</script>'
283
281
  });
284
282
  fireEvent.click(screen.getByTestId('student-cell-link'));
285
283
  _context10.n = 1;
286
- return screen.findByTitle('Loading user details');
284
+ return screen.findByText('Message');
287
285
  case 1:
288
- expect(screen.queryByTestId('lmgb-student-popover-avatar')).not.toBeInTheDocument();
286
+ expect(screen.queryByText('View Mastery Report')).not.toBeInTheDocument();
289
287
  case 2:
290
288
  return _context10.a(2);
291
289
  }
292
290
  }, _callee10);
293
291
  })));
294
- });
295
- describe('Error State', function () {
296
- it('shows an error message when error prop is provided', /*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee11() {
297
- var _t7;
292
+ it('renders the mastery report link for a safe https URL', /*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee11() {
293
+ var safeUrl, masteryLink;
298
294
  return _regenerator().w(function (_context11) {
299
295
  while (1) switch (_context11.n) {
300
296
  case 0:
297
+ safeUrl = 'https://canvas.instructure.com/courses/123/grades/1';
301
298
  renderComponent({
302
- error: 'Failed to load student details'
299
+ studentGradesUrl: safeUrl
303
300
  });
304
301
  fireEvent.click(screen.getByTestId('student-cell-link'));
305
- _t7 = expect;
306
302
  _context11.n = 1;
307
- return screen.findByText('Failed to load student details');
303
+ return screen.findByText('View Mastery Report');
308
304
  case 1:
309
- _t7(_context11.v).toBeInTheDocument();
305
+ masteryLink = _context11.v;
306
+ expect(masteryLink.closest('a')).toHaveAttribute('href', safeUrl);
310
307
  case 2:
311
308
  return _context11.a(2);
312
309
  }
313
310
  }, _callee11);
314
311
  })));
315
- it('does not show student details when error is present', /*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee12() {
312
+ it('renders the mastery report link for a safe http URL', /*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee12() {
313
+ var safeUrl, masteryLink;
316
314
  return _regenerator().w(function (_context12) {
317
315
  while (1) switch (_context12.n) {
318
316
  case 0:
317
+ safeUrl = 'http://canvas.instructure.com/courses/123/grades/1';
319
318
  renderComponent({
320
- error: 'Something went wrong'
319
+ studentGradesUrl: safeUrl
321
320
  });
322
321
  fireEvent.click(screen.getByTestId('student-cell-link'));
323
322
  _context12.n = 1;
324
- return screen.findByText('Something went wrong');
323
+ return screen.findByText('View Mastery Report');
325
324
  case 1:
326
- expect(screen.queryByTestId('lmgb-student-popover-avatar')).not.toBeInTheDocument();
325
+ masteryLink = _context12.v;
326
+ expect(masteryLink.closest('a')).toHaveAttribute('href', safeUrl);
327
327
  case 2:
328
328
  return _context12.a(2);
329
329
  }
330
330
  }, _callee12);
331
331
  })));
332
332
  });
333
+ describe('Loading State', function () {
334
+ it('shows a spinner when isLoading is true', /*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee13() {
335
+ var _t6;
336
+ return _regenerator().w(function (_context13) {
337
+ while (1) switch (_context13.n) {
338
+ case 0:
339
+ renderComponent({
340
+ isLoading: true
341
+ });
342
+ fireEvent.click(screen.getByTestId('student-cell-link'));
343
+ _t6 = expect;
344
+ _context13.n = 1;
345
+ return screen.findByTitle('Loading user details');
346
+ case 1:
347
+ _t6(_context13.v).toBeInTheDocument();
348
+ case 2:
349
+ return _context13.a(2);
350
+ }
351
+ }, _callee13);
352
+ })));
353
+ it('does not show student details when isLoading is true', /*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee14() {
354
+ return _regenerator().w(function (_context14) {
355
+ while (1) switch (_context14.n) {
356
+ case 0:
357
+ renderComponent({
358
+ isLoading: true
359
+ });
360
+ fireEvent.click(screen.getByTestId('student-cell-link'));
361
+ _context14.n = 1;
362
+ return screen.findByTitle('Loading user details');
363
+ case 1:
364
+ expect(screen.queryByTestId('lmgb-student-popover-avatar')).not.toBeInTheDocument();
365
+ case 2:
366
+ return _context14.a(2);
367
+ }
368
+ }, _callee14);
369
+ })));
370
+ });
371
+ describe('Error State', function () {
372
+ it('shows an error message when error prop is provided', /*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee15() {
373
+ var _t7;
374
+ return _regenerator().w(function (_context15) {
375
+ while (1) switch (_context15.n) {
376
+ case 0:
377
+ renderComponent({
378
+ error: 'Failed to load student details'
379
+ });
380
+ fireEvent.click(screen.getByTestId('student-cell-link'));
381
+ _t7 = expect;
382
+ _context15.n = 1;
383
+ return screen.findByText('Failed to load student details');
384
+ case 1:
385
+ _t7(_context15.v).toBeInTheDocument();
386
+ case 2:
387
+ return _context15.a(2);
388
+ }
389
+ }, _callee15);
390
+ })));
391
+ it('does not show student details when error is present', /*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee16() {
392
+ return _regenerator().w(function (_context16) {
393
+ while (1) switch (_context16.n) {
394
+ case 0:
395
+ renderComponent({
396
+ error: 'Something went wrong'
397
+ });
398
+ fireEvent.click(screen.getByTestId('student-cell-link'));
399
+ _context16.n = 1;
400
+ return screen.findByText('Something went wrong');
401
+ case 1:
402
+ expect(screen.queryByTestId('lmgb-student-popover-avatar')).not.toBeInTheDocument();
403
+ case 2:
404
+ return _context16.a(2);
405
+ }
406
+ }, _callee16);
407
+ })));
408
+ });
333
409
  });
@@ -99,6 +99,9 @@ var MasteryScores = function MasteryScores(_ref2) {
99
99
  }, bucket.count)));
100
100
  }))));
101
101
  };
102
+ var isSafeUrl = function isSafeUrl(url) {
103
+ return /^(https?:\/\/|\/)/i.test(url);
104
+ };
102
105
  var Actions = function Actions(_ref3) {
103
106
  var studentGradesUrl = _ref3.studentGradesUrl;
104
107
  var _useState = useState(false),
@@ -121,7 +124,7 @@ var Actions = function Actions(_ref3) {
121
124
  borderWidth: "none small none none",
122
125
  width: "0px",
123
126
  height: "1.4rem"
124
- }), studentGradesUrl && /*#__PURE__*/React.createElement(Flex.Item, null, /*#__PURE__*/React.createElement(Link, {
127
+ }), studentGradesUrl && isSafeUrl(studentGradesUrl) && /*#__PURE__*/React.createElement(Flex.Item, null, /*#__PURE__*/React.createElement(Link, {
125
128
  href: studentGradesUrl,
126
129
  variant: "standalone"
127
130
  }, /*#__PURE__*/React.createElement(Text, {
@@ -1,16 +1,138 @@
1
- import { expect, describe, it } from '@jest/globals';
1
+ import { describe, expect, it } from '@jest/globals';
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)).toContain('</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)).toContain('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)).toContain('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).toContain('src="/another_image"');
17
+ expect(out).not.toContain('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)).toContain('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)).toBe('');
23
+ });
24
+ it('returns empty string for undefined', function () {
25
+ expect(sanitizeHtml(void 0)).toBe('');
26
+ });
27
+ it('returns empty string for empty string', function () {
28
+ expect(sanitizeHtml('')).toBe('');
29
+ });
11
30
  });
12
- it('leaves other images alone', function () {
13
- var otherImage = 'Some text with <img src="/another_image" />';
14
- expect(sanitizeHtml(otherImage)).toBe(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).not.toContain('<script');
36
+ expect(out).not.toContain('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).not.toMatch(/onerror/i);
42
+ expect(out).not.toContain('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).not.toMatch(/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).not.toMatch(/onload/i);
53
+ expect(out).not.toContain('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).not.toMatch(/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).not.toMatch(/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).not.toContain('alert(1)');
71
+ });
72
+ it('strips <object> tags', function () {
73
+ var xss = '<object data="evil.swf"></object>';
74
+ expect(sanitizeHtml(xss)).not.toContain('<object');
75
+ });
76
+ it('strips <embed> tags', function () {
77
+ var xss = '<embed src="evil.swf">';
78
+ expect(sanitizeHtml(xss)).not.toContain('<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)).not.toContain('<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)).not.toContain('<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)).not.toContain('<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)).not.toContain('<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).not.toMatch(/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).not.toMatch(/<script/i);
105
+ expect(out).not.toContain('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)).toBe(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)).toContain('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)).toBe(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).toContain('<iframe');
125
+ expect(out).toContain('data-media-id="123"');
126
+ expect(out).toContain('data-media-type="video"');
127
+ expect(out).toContain('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).toMatch(/rel=["'][^"']*noopener[^"']*["']/);
135
+ expect(out).toMatch(/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
  }
@@ -257,80 +257,156 @@ describe('StudentPopover', function () {
257
257
  }, _callee0);
258
258
  })));
259
259
  });
260
- describe('Loading State', function () {
261
- it('shows a spinner when isLoading is true', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/(0, _regenerator2.default)().m(function _callee1() {
262
- var _t6;
260
+ describe('Security', function () {
261
+ it('does not render the mastery report link for a javascript: URI', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/(0, _regenerator2.default)().m(function _callee1() {
263
262
  return (0, _regenerator2.default)().w(function (_context1) {
264
263
  while (1) switch (_context1.n) {
265
264
  case 0:
266
265
  renderComponent({
267
- isLoading: true
266
+ studentGradesUrl: 'javascript:alert(document.cookie)'
268
267
  });
269
268
  _react2.fireEvent.click(_react2.screen.getByTestId('student-cell-link'));
270
- _t6 = expect;
271
269
  _context1.n = 1;
272
- return _react2.screen.findByTitle('Loading user details');
270
+ return _react2.screen.findByText('Message');
273
271
  case 1:
274
- _t6(_context1.v).toBeInTheDocument();
272
+ expect(_react2.screen.queryByText('View Mastery Report')).not.toBeInTheDocument();
275
273
  case 2:
276
274
  return _context1.a(2);
277
275
  }
278
276
  }, _callee1);
279
277
  })));
280
- it('does not show student details when isLoading is true', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/(0, _regenerator2.default)().m(function _callee10() {
278
+ it('does not render the mastery report link for a data: URI', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/(0, _regenerator2.default)().m(function _callee10() {
281
279
  return (0, _regenerator2.default)().w(function (_context10) {
282
280
  while (1) switch (_context10.n) {
283
281
  case 0:
284
282
  renderComponent({
285
- isLoading: true
283
+ studentGradesUrl: 'data:text/html,<script>alert(1)</script>'
286
284
  });
287
285
  _react2.fireEvent.click(_react2.screen.getByTestId('student-cell-link'));
288
286
  _context10.n = 1;
289
- return _react2.screen.findByTitle('Loading user details');
287
+ return _react2.screen.findByText('Message');
290
288
  case 1:
291
- expect(_react2.screen.queryByTestId('lmgb-student-popover-avatar')).not.toBeInTheDocument();
289
+ expect(_react2.screen.queryByText('View Mastery Report')).not.toBeInTheDocument();
292
290
  case 2:
293
291
  return _context10.a(2);
294
292
  }
295
293
  }, _callee10);
296
294
  })));
297
- });
298
- describe('Error State', function () {
299
- it('shows an error message when error prop is provided', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/(0, _regenerator2.default)().m(function _callee11() {
300
- var _t7;
295
+ it('renders the mastery report link for a safe https URL', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/(0, _regenerator2.default)().m(function _callee11() {
296
+ var safeUrl, masteryLink;
301
297
  return (0, _regenerator2.default)().w(function (_context11) {
302
298
  while (1) switch (_context11.n) {
303
299
  case 0:
300
+ safeUrl = 'https://canvas.instructure.com/courses/123/grades/1';
304
301
  renderComponent({
305
- error: 'Failed to load student details'
302
+ studentGradesUrl: safeUrl
306
303
  });
307
304
  _react2.fireEvent.click(_react2.screen.getByTestId('student-cell-link'));
308
- _t7 = expect;
309
305
  _context11.n = 1;
310
- return _react2.screen.findByText('Failed to load student details');
306
+ return _react2.screen.findByText('View Mastery Report');
311
307
  case 1:
312
- _t7(_context11.v).toBeInTheDocument();
308
+ masteryLink = _context11.v;
309
+ expect(masteryLink.closest('a')).toHaveAttribute('href', safeUrl);
313
310
  case 2:
314
311
  return _context11.a(2);
315
312
  }
316
313
  }, _callee11);
317
314
  })));
318
- it('does not show student details when error is present', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/(0, _regenerator2.default)().m(function _callee12() {
315
+ it('renders the mastery report link for a safe http URL', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/(0, _regenerator2.default)().m(function _callee12() {
316
+ var safeUrl, masteryLink;
319
317
  return (0, _regenerator2.default)().w(function (_context12) {
320
318
  while (1) switch (_context12.n) {
321
319
  case 0:
320
+ safeUrl = 'http://canvas.instructure.com/courses/123/grades/1';
322
321
  renderComponent({
323
- error: 'Something went wrong'
322
+ studentGradesUrl: safeUrl
324
323
  });
325
324
  _react2.fireEvent.click(_react2.screen.getByTestId('student-cell-link'));
326
325
  _context12.n = 1;
327
- return _react2.screen.findByText('Something went wrong');
326
+ return _react2.screen.findByText('View Mastery Report');
328
327
  case 1:
329
- expect(_react2.screen.queryByTestId('lmgb-student-popover-avatar')).not.toBeInTheDocument();
328
+ masteryLink = _context12.v;
329
+ expect(masteryLink.closest('a')).toHaveAttribute('href', safeUrl);
330
330
  case 2:
331
331
  return _context12.a(2);
332
332
  }
333
333
  }, _callee12);
334
334
  })));
335
335
  });
336
+ describe('Loading State', function () {
337
+ it('shows a spinner when isLoading is true', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/(0, _regenerator2.default)().m(function _callee13() {
338
+ var _t6;
339
+ return (0, _regenerator2.default)().w(function (_context13) {
340
+ while (1) switch (_context13.n) {
341
+ case 0:
342
+ renderComponent({
343
+ isLoading: true
344
+ });
345
+ _react2.fireEvent.click(_react2.screen.getByTestId('student-cell-link'));
346
+ _t6 = expect;
347
+ _context13.n = 1;
348
+ return _react2.screen.findByTitle('Loading user details');
349
+ case 1:
350
+ _t6(_context13.v).toBeInTheDocument();
351
+ case 2:
352
+ return _context13.a(2);
353
+ }
354
+ }, _callee13);
355
+ })));
356
+ it('does not show student details when isLoading is true', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/(0, _regenerator2.default)().m(function _callee14() {
357
+ return (0, _regenerator2.default)().w(function (_context14) {
358
+ while (1) switch (_context14.n) {
359
+ case 0:
360
+ renderComponent({
361
+ isLoading: true
362
+ });
363
+ _react2.fireEvent.click(_react2.screen.getByTestId('student-cell-link'));
364
+ _context14.n = 1;
365
+ return _react2.screen.findByTitle('Loading user details');
366
+ case 1:
367
+ expect(_react2.screen.queryByTestId('lmgb-student-popover-avatar')).not.toBeInTheDocument();
368
+ case 2:
369
+ return _context14.a(2);
370
+ }
371
+ }, _callee14);
372
+ })));
373
+ });
374
+ describe('Error State', function () {
375
+ it('shows an error message when error prop is provided', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/(0, _regenerator2.default)().m(function _callee15() {
376
+ var _t7;
377
+ return (0, _regenerator2.default)().w(function (_context15) {
378
+ while (1) switch (_context15.n) {
379
+ case 0:
380
+ renderComponent({
381
+ error: 'Failed to load student details'
382
+ });
383
+ _react2.fireEvent.click(_react2.screen.getByTestId('student-cell-link'));
384
+ _t7 = expect;
385
+ _context15.n = 1;
386
+ return _react2.screen.findByText('Failed to load student details');
387
+ case 1:
388
+ _t7(_context15.v).toBeInTheDocument();
389
+ case 2:
390
+ return _context15.a(2);
391
+ }
392
+ }, _callee15);
393
+ })));
394
+ it('does not show student details when error is present', /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/(0, _regenerator2.default)().m(function _callee16() {
395
+ return (0, _regenerator2.default)().w(function (_context16) {
396
+ while (1) switch (_context16.n) {
397
+ case 0:
398
+ renderComponent({
399
+ error: 'Something went wrong'
400
+ });
401
+ _react2.fireEvent.click(_react2.screen.getByTestId('student-cell-link'));
402
+ _context16.n = 1;
403
+ return _react2.screen.findByText('Something went wrong');
404
+ case 1:
405
+ expect(_react2.screen.queryByTestId('lmgb-student-popover-avatar')).not.toBeInTheDocument();
406
+ case 2:
407
+ return _context16.a(2);
408
+ }
409
+ }, _callee16);
410
+ })));
411
+ });
336
412
  });
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/Gradebook/popovers/StudentPopover/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAY,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAcvD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAA;AAyB7D,KAAK,UAAU,GACX;IAAE,cAAc,EAAE,SAAS,CAAC;IAAC,SAAS,CAAC,EAAE,KAAK,CAAC;IAAC,WAAW,CAAC,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,EAAE,KAAK,CAAA;CAAE,GACvF;IAAE,cAAc,CAAC,EAAE,KAAK,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAE3F,KAAK,iBAAiB,GAClB;IAAE,qBAAqB,EAAE,SAAS,CAAC;IAAC,aAAa,CAAC,EAAE,KAAK,CAAA;CAAE,GAC3D;IAAE,qBAAqB,CAAC,EAAE,KAAK,CAAC;IAAC,aAAa,CAAC,EAAE,oBAAoB,CAAA;CAAE,CAAA;AAE3E,KAAK,UAAU,GACX;IAAE,eAAe,EAAE,SAAS,CAAC;IAAC,gBAAgB,CAAC,EAAE,KAAK,CAAA;CAAE,GACxD;IAAE,eAAe,CAAC,EAAE,KAAK,CAAC;IAAC,gBAAgB,EAAE,MAAM,CAAA;CAAE,CAAA;AAEzD,MAAM,MAAM,mBAAmB,GAAG;IAChC,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,sBAAsB,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,CAAA;CACtD,GAAG,UAAU,GAAG,iBAAiB,GAAG,UAAU,CAAA;AA2K/C,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAwFxD,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/Gradebook/popovers/StudentPopover/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAY,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAcvD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAA;AAyB7D,KAAK,UAAU,GACX;IAAE,cAAc,EAAE,SAAS,CAAC;IAAC,SAAS,CAAC,EAAE,KAAK,CAAC;IAAC,WAAW,CAAC,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,EAAE,KAAK,CAAA;CAAE,GACvF;IAAE,cAAc,CAAC,EAAE,KAAK,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAE3F,KAAK,iBAAiB,GAClB;IAAE,qBAAqB,EAAE,SAAS,CAAC;IAAC,aAAa,CAAC,EAAE,KAAK,CAAA;CAAE,GAC3D;IAAE,qBAAqB,CAAC,EAAE,KAAK,CAAC;IAAC,aAAa,CAAC,EAAE,oBAAoB,CAAA;CAAE,CAAA;AAE3E,KAAK,UAAU,GACX;IAAE,eAAe,EAAE,SAAS,CAAC;IAAC,gBAAgB,CAAC,EAAE,KAAK,CAAA;CAAE,GACxD;IAAE,eAAe,CAAC,EAAE,KAAK,CAAC;IAAC,gBAAgB,EAAE,MAAM,CAAA;CAAE,CAAA;AAEzD,MAAM,MAAM,mBAAmB,GAAG;IAChC,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,sBAAsB,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,CAAA;CACtD,GAAG,UAAU,GAAG,iBAAiB,GAAG,UAAU,CAAA;AA6K/C,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAwFxD,CAAA"}
@@ -108,6 +108,9 @@ var MasteryScores = function MasteryScores(_ref2) {
108
108
  }, bucket.count)));
109
109
  }))));
110
110
  };
111
+ var isSafeUrl = function isSafeUrl(url) {
112
+ return /^(https?:\/\/|\/)/i.test(url);
113
+ };
111
114
  var Actions = function Actions(_ref3) {
112
115
  var studentGradesUrl = _ref3.studentGradesUrl;
113
116
  var _useState = (0, _react.useState)(false),
@@ -130,7 +133,7 @@ var Actions = function Actions(_ref3) {
130
133
  borderWidth: "none small none none",
131
134
  width: "0px",
132
135
  height: "1.4rem"
133
- }), studentGradesUrl && /*#__PURE__*/_react.default.createElement(_uiFlex.Flex.Item, null, /*#__PURE__*/_react.default.createElement(_uiLink.Link, {
136
+ }), studentGradesUrl && isSafeUrl(studentGradesUrl) && /*#__PURE__*/_react.default.createElement(_uiFlex.Flex.Item, null, /*#__PURE__*/_react.default.createElement(_uiLink.Link, {
134
137
  href: studentGradesUrl,
135
138
  variant: "standalone"
136
139
  }, /*#__PURE__*/_react.default.createElement(_uiText.Text, {