payload 3.89.0-internal.95c9cba → 3.90.0

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 (468) hide show
  1. package/dist/admin/forms/Field.d.ts +2 -0
  2. package/dist/admin/forms/Field.d.ts.map +1 -1
  3. package/dist/admin/forms/Field.js.map +1 -1
  4. package/dist/admin/forms/Form.d.ts +2 -0
  5. package/dist/admin/forms/Form.d.ts.map +1 -1
  6. package/dist/admin/forms/Form.js.map +1 -1
  7. package/dist/admin/functions/index.d.ts +3 -1
  8. package/dist/admin/functions/index.d.ts.map +1 -1
  9. package/dist/admin/functions/index.js.map +1 -1
  10. package/dist/admin/views/dashboard.d.ts +1 -1
  11. package/dist/admin/views/dashboard.d.ts.map +1 -1
  12. package/dist/admin/views/dashboard.js.map +1 -1
  13. package/dist/auth/applyUserReadAccess.d.ts +15 -0
  14. package/dist/auth/applyUserReadAccess.d.ts.map +1 -0
  15. package/dist/auth/applyUserReadAccess.js +41 -0
  16. package/dist/auth/applyUserReadAccess.js.map +1 -0
  17. package/dist/auth/baseFields/apiKey/canCreateOrUpdateAPIKey.d.ts +4 -0
  18. package/dist/auth/baseFields/apiKey/canCreateOrUpdateAPIKey.d.ts.map +1 -0
  19. package/dist/auth/baseFields/apiKey/canCreateOrUpdateAPIKey.js +20 -0
  20. package/dist/auth/baseFields/apiKey/canCreateOrUpdateAPIKey.js.map +1 -0
  21. package/dist/auth/baseFields/apiKey/encryptAPIKey.d.ts +4 -0
  22. package/dist/auth/baseFields/apiKey/encryptAPIKey.d.ts.map +1 -0
  23. package/dist/auth/baseFields/apiKey/encryptAPIKey.js +16 -0
  24. package/dist/auth/baseFields/apiKey/encryptAPIKey.js.map +1 -0
  25. package/dist/auth/baseFields/apiKey/index.d.ts +6 -0
  26. package/dist/auth/baseFields/apiKey/index.d.ts.map +1 -0
  27. package/dist/auth/baseFields/apiKey/index.js +112 -0
  28. package/dist/auth/baseFields/apiKey/index.js.map +1 -0
  29. package/dist/auth/baseFields/apiKey/omitAPIKey.d.ts +4 -0
  30. package/dist/auth/baseFields/apiKey/omitAPIKey.d.ts.map +1 -0
  31. package/dist/auth/baseFields/apiKey/omitAPIKey.js +8 -0
  32. package/dist/auth/baseFields/apiKey/omitAPIKey.js.map +1 -0
  33. package/dist/auth/baseFields/apiKey/omitAPIKeyIndex.d.ts +4 -0
  34. package/dist/auth/baseFields/apiKey/omitAPIKeyIndex.d.ts.map +1 -0
  35. package/dist/auth/baseFields/apiKey/omitAPIKeyIndex.js +5 -0
  36. package/dist/auth/baseFields/apiKey/omitAPIKeyIndex.js.map +1 -0
  37. package/dist/auth/baseFields/apiKey/omitEncryptedAPIKey.d.ts +4 -0
  38. package/dist/auth/baseFields/apiKey/omitEncryptedAPIKey.d.ts.map +1 -0
  39. package/dist/auth/baseFields/apiKey/omitEncryptedAPIKey.js +5 -0
  40. package/dist/auth/baseFields/apiKey/omitEncryptedAPIKey.js.map +1 -0
  41. package/dist/auth/baseFields/apiKey/setAPIKeyIndex.d.ts +4 -0
  42. package/dist/auth/baseFields/apiKey/setAPIKeyIndex.d.ts.map +1 -0
  43. package/dist/auth/baseFields/apiKey/setAPIKeyIndex.js +17 -0
  44. package/dist/auth/baseFields/apiKey/setAPIKeyIndex.js.map +1 -0
  45. package/dist/auth/baseFields/auth.d.ts +1 -0
  46. package/dist/auth/baseFields/auth.d.ts.map +1 -1
  47. package/dist/auth/baseFields/auth.js +9 -0
  48. package/dist/auth/baseFields/auth.js.map +1 -1
  49. package/dist/auth/defaultUnlockAccess.d.ts +3 -0
  50. package/dist/auth/defaultUnlockAccess.d.ts.map +1 -0
  51. package/dist/auth/defaultUnlockAccess.js +8 -0
  52. package/dist/auth/defaultUnlockAccess.js.map +1 -0
  53. package/dist/auth/endpoints/index.d.ts +1 -0
  54. package/dist/auth/endpoints/index.d.ts.map +1 -1
  55. package/dist/auth/endpoints/index.js +8 -0
  56. package/dist/auth/endpoints/index.js.map +1 -1
  57. package/dist/auth/endpoints/revealAPIKey.d.ts +7 -0
  58. package/dist/auth/endpoints/revealAPIKey.d.ts.map +1 -0
  59. package/dist/auth/endpoints/revealAPIKey.js +120 -0
  60. package/dist/auth/endpoints/revealAPIKey.js.map +1 -0
  61. package/dist/auth/executeAccess.d.ts +3 -1
  62. package/dist/auth/executeAccess.d.ts.map +1 -1
  63. package/dist/auth/executeAccess.js +2 -1
  64. package/dist/auth/executeAccess.js.map +1 -1
  65. package/dist/auth/getAuthFields.d.ts +1 -1
  66. package/dist/auth/getAuthFields.d.ts.map +1 -1
  67. package/dist/auth/getAuthFields.js +7 -4
  68. package/dist/auth/getAuthFields.js.map +1 -1
  69. package/dist/auth/getFieldsToSign.d.ts.map +1 -1
  70. package/dist/auth/getFieldsToSign.js +17 -10
  71. package/dist/auth/getFieldsToSign.js.map +1 -1
  72. package/dist/auth/getFieldsToSign.spec.js +114 -0
  73. package/dist/auth/getFieldsToSign.spec.js.map +1 -0
  74. package/dist/auth/jwt.d.ts.map +1 -1
  75. package/dist/auth/jwt.js +2 -0
  76. package/dist/auth/jwt.js.map +1 -1
  77. package/dist/auth/jwt.spec.js +24 -0
  78. package/dist/auth/jwt.spec.js.map +1 -0
  79. package/dist/auth/jwtAuth.d.ts +9 -0
  80. package/dist/auth/jwtAuth.d.ts.map +1 -0
  81. package/dist/auth/jwtAuth.js +8 -0
  82. package/dist/auth/jwtAuth.js.map +1 -0
  83. package/dist/auth/operations/auth.d.ts.map +1 -1
  84. package/dist/auth/operations/auth.js +2 -1
  85. package/dist/auth/operations/auth.js.map +1 -1
  86. package/dist/auth/operations/forgotPassword.d.ts.map +1 -1
  87. package/dist/auth/operations/forgotPassword.js +95 -7
  88. package/dist/auth/operations/forgotPassword.js.map +1 -1
  89. package/dist/auth/operations/local/auth.js +3 -1
  90. package/dist/auth/operations/local/auth.js.map +1 -1
  91. package/dist/auth/operations/login.d.ts.map +1 -1
  92. package/dist/auth/operations/login.js +48 -26
  93. package/dist/auth/operations/login.js.map +1 -1
  94. package/dist/auth/operations/refresh.d.ts.map +1 -1
  95. package/dist/auth/operations/refresh.js +32 -9
  96. package/dist/auth/operations/refresh.js.map +1 -1
  97. package/dist/auth/operations/registerFirstUser.d.ts.map +1 -1
  98. package/dist/auth/operations/registerFirstUser.js +3 -4
  99. package/dist/auth/operations/registerFirstUser.js.map +1 -1
  100. package/dist/auth/operations/resetPassword.d.ts.map +1 -1
  101. package/dist/auth/operations/resetPassword.js +31 -22
  102. package/dist/auth/operations/resetPassword.js.map +1 -1
  103. package/dist/auth/operations/unlock.d.ts.map +1 -1
  104. package/dist/auth/operations/unlock.js +1 -0
  105. package/dist/auth/operations/unlock.js.map +1 -1
  106. package/dist/auth/strategies/apiKey.d.ts.map +1 -1
  107. package/dist/auth/strategies/apiKey.js +15 -1
  108. package/dist/auth/strategies/apiKey.js.map +1 -1
  109. package/dist/auth/strategies/jwt.d.ts.map +1 -1
  110. package/dist/auth/strategies/jwt.js +61 -10
  111. package/dist/auth/strategies/jwt.js.map +1 -1
  112. package/dist/auth/strategies/jwt.spec.js +281 -0
  113. package/dist/auth/strategies/jwt.spec.js.map +1 -0
  114. package/dist/auth/strategies/local/authenticate.d.ts +5 -1
  115. package/dist/auth/strategies/local/authenticate.d.ts.map +1 -1
  116. package/dist/auth/strategies/local/authenticate.js +8 -3
  117. package/dist/auth/strategies/local/authenticate.js.map +1 -1
  118. package/dist/auth/strategies/local/authenticate.spec.js +37 -10
  119. package/dist/auth/strategies/local/authenticate.spec.js.map +1 -1
  120. package/dist/auth/strategies/local/generatePasswordSaltHash.d.ts +9 -1
  121. package/dist/auth/strategies/local/generatePasswordSaltHash.d.ts.map +1 -1
  122. package/dist/auth/strategies/local/generatePasswordSaltHash.js +61 -34
  123. package/dist/auth/strategies/local/generatePasswordSaltHash.js.map +1 -1
  124. package/dist/auth/types.d.ts +16 -1
  125. package/dist/auth/types.d.ts.map +1 -1
  126. package/dist/auth/types.js.map +1 -1
  127. package/dist/collections/config/client.d.ts +1 -0
  128. package/dist/collections/config/client.d.ts.map +1 -1
  129. package/dist/collections/config/client.js +3 -0
  130. package/dist/collections/config/client.js.map +1 -1
  131. package/dist/collections/config/defaults.d.ts.map +1 -1
  132. package/dist/collections/config/defaults.js +4 -2
  133. package/dist/collections/config/defaults.js.map +1 -1
  134. package/dist/collections/config/sanitize.d.ts.map +1 -1
  135. package/dist/collections/config/sanitize.js +17 -6
  136. package/dist/collections/config/sanitize.js.map +1 -1
  137. package/dist/collections/endpoints/index.d.ts +1 -0
  138. package/dist/collections/endpoints/index.d.ts.map +1 -1
  139. package/dist/collections/endpoints/index.js +6 -5
  140. package/dist/collections/endpoints/index.js.map +1 -1
  141. package/dist/collections/operations/create.d.ts.map +1 -1
  142. package/dist/collections/operations/create.js +105 -8
  143. package/dist/collections/operations/create.js.map +1 -1
  144. package/dist/collections/operations/deleteByID.js +13 -13
  145. package/dist/collections/operations/deleteByID.js.map +1 -1
  146. package/dist/collections/operations/findDistinct.d.ts.map +1 -1
  147. package/dist/collections/operations/findDistinct.js +96 -18
  148. package/dist/collections/operations/findDistinct.js.map +1 -1
  149. package/dist/collections/operations/restoreVersion.d.ts.map +1 -1
  150. package/dist/collections/operations/restoreVersion.js +47 -13
  151. package/dist/collections/operations/restoreVersion.js.map +1 -1
  152. package/dist/collections/operations/update.d.ts.map +1 -1
  153. package/dist/collections/operations/update.js +123 -23
  154. package/dist/collections/operations/update.js.map +1 -1
  155. package/dist/collections/operations/updateByID.d.ts.map +1 -1
  156. package/dist/collections/operations/updateByID.js +62 -2
  157. package/dist/collections/operations/updateByID.js.map +1 -1
  158. package/dist/collections/operations/utilities/update.d.ts.map +1 -1
  159. package/dist/collections/operations/utilities/update.js +71 -15
  160. package/dist/collections/operations/utilities/update.js.map +1 -1
  161. package/dist/config/orderable/index.d.ts.map +1 -1
  162. package/dist/config/orderable/index.js +67 -14
  163. package/dist/config/orderable/index.js.map +1 -1
  164. package/dist/config/sanitize.d.ts.map +1 -1
  165. package/dist/config/sanitize.js +1 -1
  166. package/dist/config/sanitize.js.map +1 -1
  167. package/dist/config/types.d.ts +13 -1
  168. package/dist/config/types.d.ts.map +1 -1
  169. package/dist/config/types.js.map +1 -1
  170. package/dist/database/getLocalizedPaths.d.ts +2 -1
  171. package/dist/database/getLocalizedPaths.d.ts.map +1 -1
  172. package/dist/database/getLocalizedPaths.js +12 -3
  173. package/dist/database/getLocalizedPaths.js.map +1 -1
  174. package/dist/database/isNestedRelationshipQuery.d.ts +9 -0
  175. package/dist/database/isNestedRelationshipQuery.d.ts.map +1 -0
  176. package/dist/database/isNestedRelationshipQuery.js +14 -0
  177. package/dist/database/isNestedRelationshipQuery.js.map +1 -0
  178. package/dist/database/prefixWherePaths.d.ts +6 -0
  179. package/dist/database/prefixWherePaths.d.ts.map +1 -0
  180. package/dist/database/prefixWherePaths.js +19 -0
  181. package/dist/database/prefixWherePaths.js.map +1 -0
  182. package/dist/database/prefixWherePaths.spec.js +46 -0
  183. package/dist/database/prefixWherePaths.spec.js.map +1 -0
  184. package/dist/database/queryValidation/validateQueryPaths.d.ts +2 -1
  185. package/dist/database/queryValidation/validateQueryPaths.d.ts.map +1 -1
  186. package/dist/database/queryValidation/validateQueryPaths.js +4 -1
  187. package/dist/database/queryValidation/validateQueryPaths.js.map +1 -1
  188. package/dist/database/queryValidation/validateSearchParams.d.ts +2 -1
  189. package/dist/database/queryValidation/validateSearchParams.d.ts.map +1 -1
  190. package/dist/database/queryValidation/validateSearchParams.js +82 -4
  191. package/dist/database/queryValidation/validateSearchParams.js.map +1 -1
  192. package/dist/database/types.d.ts +5 -0
  193. package/dist/database/types.d.ts.map +1 -1
  194. package/dist/database/types.js.map +1 -1
  195. package/dist/email/normalizeSendEmailOptions.js.map +1 -1
  196. package/dist/email/types.d.ts +4 -1
  197. package/dist/email/types.d.ts.map +1 -1
  198. package/dist/email/types.js.map +1 -1
  199. package/dist/exports/internal.d.ts +7 -0
  200. package/dist/exports/internal.d.ts.map +1 -1
  201. package/dist/exports/internal.js +7 -1
  202. package/dist/exports/internal.js.map +1 -1
  203. package/dist/exports/shared.d.ts +3 -0
  204. package/dist/exports/shared.d.ts.map +1 -1
  205. package/dist/exports/shared.js +3 -0
  206. package/dist/exports/shared.js.map +1 -1
  207. package/dist/fields/config/types.d.ts +7 -5
  208. package/dist/fields/config/types.d.ts.map +1 -1
  209. package/dist/fields/config/types.js.map +1 -1
  210. package/dist/fields/hooks/beforeChange/index.d.ts +7 -1
  211. package/dist/fields/hooks/beforeChange/index.d.ts.map +1 -1
  212. package/dist/fields/hooks/beforeChange/index.js +4 -2
  213. package/dist/fields/hooks/beforeChange/index.js.map +1 -1
  214. package/dist/fields/hooks/beforeChange/index.spec.js +206 -0
  215. package/dist/fields/hooks/beforeChange/index.spec.js.map +1 -0
  216. package/dist/fields/hooks/beforeChange/promise.d.ts +2 -1
  217. package/dist/fields/hooks/beforeChange/promise.d.ts.map +1 -1
  218. package/dist/fields/hooks/beforeChange/promise.js +51 -9
  219. package/dist/fields/hooks/beforeChange/promise.js.map +1 -1
  220. package/dist/fields/hooks/beforeChange/traverseFields.d.ts +2 -1
  221. package/dist/fields/hooks/beforeChange/traverseFields.d.ts.map +1 -1
  222. package/dist/fields/hooks/beforeChange/traverseFields.js +3 -2
  223. package/dist/fields/hooks/beforeChange/traverseFields.js.map +1 -1
  224. package/dist/fields/hooks/beforeDuplicate/promise.d.ts.map +1 -1
  225. package/dist/fields/hooks/beforeDuplicate/promise.js +4 -0
  226. package/dist/fields/hooks/beforeDuplicate/promise.js.map +1 -1
  227. package/dist/fields/hooks/beforeValidate/getFallbackValue.d.ts +2 -1
  228. package/dist/fields/hooks/beforeValidate/getFallbackValue.d.ts.map +1 -1
  229. package/dist/fields/hooks/beforeValidate/getFallbackValue.js +2 -2
  230. package/dist/fields/hooks/beforeValidate/getFallbackValue.js.map +1 -1
  231. package/dist/fields/hooks/beforeValidate/index.d.ts +6 -1
  232. package/dist/fields/hooks/beforeValidate/index.d.ts.map +1 -1
  233. package/dist/fields/hooks/beforeValidate/index.js +3 -1
  234. package/dist/fields/hooks/beforeValidate/index.js.map +1 -1
  235. package/dist/fields/hooks/beforeValidate/index.spec.js +90 -0
  236. package/dist/fields/hooks/beforeValidate/index.spec.js.map +1 -0
  237. package/dist/fields/hooks/beforeValidate/promise.d.ts +6 -1
  238. package/dist/fields/hooks/beforeValidate/promise.d.ts.map +1 -1
  239. package/dist/fields/hooks/beforeValidate/promise.js +23 -8
  240. package/dist/fields/hooks/beforeValidate/promise.js.map +1 -1
  241. package/dist/fields/hooks/beforeValidate/traverseFields.d.ts +6 -1
  242. package/dist/fields/hooks/beforeValidate/traverseFields.d.ts.map +1 -1
  243. package/dist/fields/hooks/beforeValidate/traverseFields.js +3 -1
  244. package/dist/fields/hooks/beforeValidate/traverseFields.js.map +1 -1
  245. package/dist/fields/validations.d.ts.map +1 -1
  246. package/dist/fields/validations.js +3 -1
  247. package/dist/fields/validations.js.map +1 -1
  248. package/dist/globals/operations/restoreVersion.d.ts.map +1 -1
  249. package/dist/globals/operations/restoreVersion.js +45 -11
  250. package/dist/globals/operations/restoreVersion.js.map +1 -1
  251. package/dist/globals/operations/update.d.ts.map +1 -1
  252. package/dist/globals/operations/update.js +95 -16
  253. package/dist/globals/operations/update.js.map +1 -1
  254. package/dist/index.bundled.d.ts +146 -48
  255. package/dist/index.d.ts +4 -1
  256. package/dist/index.d.ts.map +1 -1
  257. package/dist/index.js +3 -2
  258. package/dist/index.js.map +1 -1
  259. package/dist/preferences/config.d.ts.map +1 -1
  260. package/dist/preferences/config.js +2 -1
  261. package/dist/preferences/config.js.map +1 -1
  262. package/dist/query-presets/access.d.ts.map +1 -1
  263. package/dist/query-presets/access.js +2 -1
  264. package/dist/query-presets/access.js.map +1 -1
  265. package/dist/queues/config/collection.d.ts.map +1 -1
  266. package/dist/queues/config/collection.js +6 -0
  267. package/dist/queues/config/collection.js.map +1 -1
  268. package/dist/queues/config/types/index.d.ts +4 -1
  269. package/dist/queues/config/types/index.d.ts.map +1 -1
  270. package/dist/queues/config/types/index.js.map +1 -1
  271. package/dist/queues/endpoints/handleSchedules.d.ts.map +1 -1
  272. package/dist/queues/endpoints/handleSchedules.js +2 -1
  273. package/dist/queues/endpoints/handleSchedules.js.map +1 -1
  274. package/dist/queues/endpoints/run.d.ts.map +1 -1
  275. package/dist/queues/endpoints/run.js +2 -1
  276. package/dist/queues/endpoints/run.js.map +1 -1
  277. package/dist/uploads/assertClientUploadAccess.d.ts +7 -0
  278. package/dist/uploads/assertClientUploadAccess.d.ts.map +1 -0
  279. package/dist/uploads/assertClientUploadAccess.js +27 -0
  280. package/dist/uploads/assertClientUploadAccess.js.map +1 -0
  281. package/dist/uploads/assertClientUploadAllowed.d.ts +11 -0
  282. package/dist/uploads/assertClientUploadAllowed.d.ts.map +1 -0
  283. package/dist/uploads/assertClientUploadAllowed.js +46 -0
  284. package/dist/uploads/assertClientUploadAllowed.js.map +1 -0
  285. package/dist/uploads/assertClientUploadAllowed.spec.js +91 -0
  286. package/dist/uploads/assertClientUploadAllowed.spec.js.map +1 -0
  287. package/dist/uploads/checkFileRestrictions.d.ts +4 -1
  288. package/dist/uploads/checkFileRestrictions.d.ts.map +1 -1
  289. package/dist/uploads/checkFileRestrictions.js +66 -26
  290. package/dist/uploads/checkFileRestrictions.js.map +1 -1
  291. package/dist/uploads/clientUploadReceipt.d.ts +23 -0
  292. package/dist/uploads/clientUploadReceipt.d.ts.map +1 -0
  293. package/dist/uploads/clientUploadReceipt.js +55 -0
  294. package/dist/uploads/clientUploadReceipt.js.map +1 -0
  295. package/dist/uploads/deleteAssociatedFiles.d.ts.map +1 -1
  296. package/dist/uploads/deleteAssociatedFiles.js +33 -8
  297. package/dist/uploads/deleteAssociatedFiles.js.map +1 -1
  298. package/dist/uploads/deleteAssociatedFiles.spec.js +124 -0
  299. package/dist/uploads/deleteAssociatedFiles.spec.js.map +1 -0
  300. package/dist/uploads/detectSvgFromXml.d.ts +1 -3
  301. package/dist/uploads/detectSvgFromXml.d.ts.map +1 -1
  302. package/dist/uploads/detectSvgFromXml.js +3 -40
  303. package/dist/uploads/detectSvgFromXml.js.map +1 -1
  304. package/dist/uploads/endpoints/getFile.d.ts.map +1 -1
  305. package/dist/uploads/endpoints/getFile.js +5 -3
  306. package/dist/uploads/endpoints/getFile.js.map +1 -1
  307. package/dist/uploads/fetchAPI-multipart/handlers.d.ts +2 -2
  308. package/dist/uploads/fetchAPI-multipart/handlers.d.ts.map +1 -1
  309. package/dist/uploads/fetchAPI-multipart/handlers.js +18 -5
  310. package/dist/uploads/fetchAPI-multipart/handlers.js.map +1 -1
  311. package/dist/uploads/fetchAPI-multipart/index.d.ts.map +1 -1
  312. package/dist/uploads/fetchAPI-multipart/index.js +24 -2
  313. package/dist/uploads/fetchAPI-multipart/index.js.map +1 -1
  314. package/dist/uploads/fetchAPI-multipart/processMultipart.d.ts +0 -6
  315. package/dist/uploads/fetchAPI-multipart/processMultipart.d.ts.map +1 -1
  316. package/dist/uploads/fetchAPI-multipart/processMultipart.js +146 -126
  317. package/dist/uploads/fetchAPI-multipart/processMultipart.js.map +1 -1
  318. package/dist/uploads/fetchAPI-multipart/processMultipart.spec.js +663 -0
  319. package/dist/uploads/fetchAPI-multipart/processMultipart.spec.js.map +1 -0
  320. package/dist/uploads/generateFileData.d.ts +3 -1
  321. package/dist/uploads/generateFileData.d.ts.map +1 -1
  322. package/dist/uploads/generateFileData.js +29 -16
  323. package/dist/uploads/generateFileData.js.map +1 -1
  324. package/dist/uploads/getBaseFields.d.ts.map +1 -1
  325. package/dist/uploads/getBaseFields.js +3 -1
  326. package/dist/uploads/getBaseFields.js.map +1 -1
  327. package/dist/uploads/getExternalFile.d.ts +1 -1
  328. package/dist/uploads/getExternalFile.d.ts.map +1 -1
  329. package/dist/uploads/getExternalFile.js +60 -15
  330. package/dist/uploads/getExternalFile.js.map +1 -1
  331. package/dist/uploads/getFileFromClientUpload.d.ts +2 -2
  332. package/dist/uploads/getFileFromClientUpload.d.ts.map +1 -1
  333. package/dist/uploads/getFileFromClientUpload.js +4 -4
  334. package/dist/uploads/getFileFromClientUpload.js.map +1 -1
  335. package/dist/uploads/getFileFromClientUpload.spec.js +62 -0
  336. package/dist/uploads/getFileFromClientUpload.spec.js.map +1 -1
  337. package/dist/uploads/getFileTypeFallback.d.ts.map +1 -1
  338. package/dist/uploads/getFileTypeFallback.js +3 -1
  339. package/dist/uploads/getFileTypeFallback.js.map +1 -1
  340. package/dist/uploads/getFileTypeIdentity.d.ts +19 -0
  341. package/dist/uploads/getFileTypeIdentity.d.ts.map +1 -0
  342. package/dist/uploads/getFileTypeIdentity.js +34 -0
  343. package/dist/uploads/getFileTypeIdentity.js.map +1 -0
  344. package/dist/uploads/getFileTypeIdentity.spec.js +43 -0
  345. package/dist/uploads/getFileTypeIdentity.spec.js.map +1 -0
  346. package/dist/uploads/isProcessableImage.d.ts +2 -0
  347. package/dist/uploads/isProcessableImage.d.ts.map +1 -0
  348. package/dist/uploads/isProcessableImage.js +7 -0
  349. package/dist/uploads/isProcessableImage.js.map +1 -0
  350. package/dist/uploads/safeFetch.d.ts.map +1 -1
  351. package/dist/uploads/safeFetch.js +3 -2
  352. package/dist/uploads/safeFetch.js.map +1 -1
  353. package/dist/uploads/sanitizeUploadData.d.ts +26 -0
  354. package/dist/uploads/sanitizeUploadData.d.ts.map +1 -0
  355. package/dist/uploads/sanitizeUploadData.js +159 -0
  356. package/dist/uploads/sanitizeUploadData.js.map +1 -0
  357. package/dist/uploads/sanitizeUploadData.spec.js +255 -0
  358. package/dist/uploads/sanitizeUploadData.spec.js.map +1 -0
  359. package/dist/uploads/types.d.ts +11 -3
  360. package/dist/uploads/types.d.ts.map +1 -1
  361. package/dist/uploads/types.js.map +1 -1
  362. package/dist/uploads/unlinkClientUploadTempFile.d.ts +20 -0
  363. package/dist/uploads/unlinkClientUploadTempFile.d.ts.map +1 -0
  364. package/dist/uploads/unlinkClientUploadTempFile.js +30 -0
  365. package/dist/uploads/unlinkClientUploadTempFile.js.map +1 -0
  366. package/dist/uploads/unlinkTempFiles.d.ts.map +1 -1
  367. package/dist/uploads/unlinkTempFiles.js +7 -9
  368. package/dist/uploads/unlinkTempFiles.js.map +1 -1
  369. package/dist/uploads/unlinkTempFiles.spec.js +61 -1
  370. package/dist/uploads/unlinkTempFiles.spec.js.map +1 -1
  371. package/dist/uploads/uploadContentSecurityPolicy.d.ts +2 -0
  372. package/dist/uploads/uploadContentSecurityPolicy.d.ts.map +1 -0
  373. package/dist/uploads/uploadContentSecurityPolicy.js +3 -0
  374. package/dist/uploads/uploadContentSecurityPolicy.js.map +1 -0
  375. package/dist/uploads/validateISOBaseMediaFile.d.ts +4 -0
  376. package/dist/uploads/validateISOBaseMediaFile.d.ts.map +1 -0
  377. package/dist/uploads/validateISOBaseMediaFile.js +91 -0
  378. package/dist/uploads/validateISOBaseMediaFile.js.map +1 -0
  379. package/dist/uploads/validateISOBaseMediaFile.spec.js +130 -0
  380. package/dist/uploads/validateISOBaseMediaFile.spec.js.map +1 -0
  381. package/dist/uploads/validateSvg.d.ts +10 -4
  382. package/dist/uploads/validateSvg.d.ts.map +1 -1
  383. package/dist/uploads/validateSvg.js +280 -40
  384. package/dist/uploads/validateSvg.js.map +1 -1
  385. package/dist/uploads/validateSvg.spec.js +123 -0
  386. package/dist/uploads/validateSvg.spec.js.map +1 -0
  387. package/dist/uploads/validateUploadFilename.d.ts +3 -0
  388. package/dist/uploads/validateUploadFilename.d.ts.map +1 -0
  389. package/dist/uploads/validateUploadFilename.js +13 -0
  390. package/dist/uploads/validateUploadFilename.js.map +1 -0
  391. package/dist/uploads/validateUploadFilename.spec.js +24 -0
  392. package/dist/uploads/validateUploadFilename.spec.js.map +1 -0
  393. package/dist/utilities/addDataAndFileToRequest.d.ts.map +1 -1
  394. package/dist/utilities/addDataAndFileToRequest.js +28 -1
  395. package/dist/utilities/addDataAndFileToRequest.js.map +1 -1
  396. package/dist/utilities/addDataAndFileToRequest.spec.js +158 -0
  397. package/dist/utilities/addDataAndFileToRequest.spec.js.map +1 -1
  398. package/dist/utilities/createPayloadRequest.d.ts.map +1 -1
  399. package/dist/utilities/createPayloadRequest.js +2 -1
  400. package/dist/utilities/createPayloadRequest.js.map +1 -1
  401. package/dist/utilities/deepCopyObject.d.ts.map +1 -1
  402. package/dist/utilities/deepCopyObject.js +110 -19
  403. package/dist/utilities/deepCopyObject.js.map +1 -1
  404. package/dist/utilities/deepCopyObject.spec.js +216 -0
  405. package/dist/utilities/deepCopyObject.spec.js.map +1 -0
  406. package/dist/utilities/fieldPath.d.ts +13 -0
  407. package/dist/utilities/fieldPath.d.ts.map +1 -0
  408. package/dist/utilities/fieldPath.js +51 -0
  409. package/dist/utilities/fieldPath.js.map +1 -0
  410. package/dist/utilities/fieldPath.spec.js +155 -0
  411. package/dist/utilities/fieldPath.spec.js.map +1 -0
  412. package/dist/utilities/getEntityPermissions/getEntityPermissions.d.ts.map +1 -1
  413. package/dist/utilities/getEntityPermissions/getEntityPermissions.js +2 -0
  414. package/dist/utilities/getEntityPermissions/getEntityPermissions.js.map +1 -1
  415. package/dist/utilities/getObjectDotNotation.d.ts.map +1 -1
  416. package/dist/utilities/getObjectDotNotation.js +7 -1
  417. package/dist/utilities/getObjectDotNotation.js.map +1 -1
  418. package/dist/utilities/getObjectDotNotation.spec.js +33 -0
  419. package/dist/utilities/getObjectDotNotation.spec.js.map +1 -0
  420. package/dist/utilities/getSafeRedirect.spec.js +14 -0
  421. package/dist/utilities/getSafeRedirect.spec.js.map +1 -1
  422. package/dist/utilities/getTopLevelFieldNames.d.ts +2 -0
  423. package/dist/utilities/getTopLevelFieldNames.d.ts.map +1 -0
  424. package/dist/utilities/getTopLevelFieldNames.js +3 -0
  425. package/dist/utilities/getTopLevelFieldNames.js.map +1 -0
  426. package/dist/utilities/getTopLevelFieldNames.spec.js +18 -0
  427. package/dist/utilities/getTopLevelFieldNames.spec.js.map +1 -0
  428. package/dist/utilities/handleEndpoints.js +1 -1
  429. package/dist/utilities/handleEndpoints.js.map +1 -1
  430. package/dist/utilities/parseParams/index.d.ts.map +1 -1
  431. package/dist/utilities/parseParams/index.js +3 -1
  432. package/dist/utilities/parseParams/index.js.map +1 -1
  433. package/dist/utilities/parseParams/index.spec.js +8 -0
  434. package/dist/utilities/parseParams/index.spec.js.map +1 -1
  435. package/dist/utilities/traverseFields.d.ts.map +1 -1
  436. package/dist/utilities/traverseFields.js +5 -14
  437. package/dist/utilities/traverseFields.js.map +1 -1
  438. package/dist/utilities/unflatten.d.ts.map +1 -1
  439. package/dist/utilities/unflatten.js +21 -9
  440. package/dist/utilities/unflatten.js.map +1 -1
  441. package/dist/utilities/unflatten.spec.js +38 -0
  442. package/dist/utilities/unflatten.spec.js.map +1 -0
  443. package/dist/utilities/wrapInternalEndpoints.d.ts.map +1 -1
  444. package/dist/utilities/wrapInternalEndpoints.js +10 -3
  445. package/dist/utilities/wrapInternalEndpoints.js.map +1 -1
  446. package/dist/utilities/wrapInternalEndpoints.spec.js +124 -0
  447. package/dist/utilities/wrapInternalEndpoints.spec.js.map +1 -0
  448. package/dist/versions/allLocalesPublicationStatus.d.ts +38 -0
  449. package/dist/versions/allLocalesPublicationStatus.d.ts.map +1 -0
  450. package/dist/versions/allLocalesPublicationStatus.js +57 -0
  451. package/dist/versions/allLocalesPublicationStatus.js.map +1 -0
  452. package/dist/versions/getLatestGlobalVersion.d.ts.map +1 -1
  453. package/dist/versions/getLatestGlobalVersion.js +10 -2
  454. package/dist/versions/getLatestGlobalVersion.js.map +1 -1
  455. package/dist/versions/getRestoredStatusesToAuthorize.d.ts +9 -0
  456. package/dist/versions/getRestoredStatusesToAuthorize.d.ts.map +1 -0
  457. package/dist/versions/getRestoredStatusesToAuthorize.js +22 -0
  458. package/dist/versions/getRestoredStatusesToAuthorize.js.map +1 -0
  459. package/dist/versions/getRestoredStatusesToAuthorize.spec.js +50 -0
  460. package/dist/versions/getRestoredStatusesToAuthorize.spec.js.map +1 -0
  461. package/dist/versions/schedule/job.d.ts +2 -2
  462. package/dist/versions/schedule/job.d.ts.map +1 -1
  463. package/dist/versions/schedule/job.js +11 -7
  464. package/dist/versions/schedule/job.js.map +1 -1
  465. package/dist/versions/schedule/types.d.ts +5 -1
  466. package/dist/versions/schedule/types.d.ts.map +1 -1
  467. package/dist/versions/schedule/types.js.map +1 -1
  468. package/package.json +4 -2
@@ -0,0 +1,130 @@
1
+ import fs from 'fs/promises';
2
+ import { randomUUID } from 'crypto';
3
+ import { fileTypeFromBuffer } from 'file-type';
4
+ import os from 'os';
5
+ import path from 'path';
6
+ import { afterEach, describe, expect, it } from 'vitest';
7
+ import { isISOBaseMediaMimeType, validateISOBaseMediaBuffer, validateISOBaseMediaFile } from './validateISOBaseMediaFile.js';
8
+ const tempFiles = [];
9
+ const box = (type, content = Buffer.alloc(0), size = content.length + 8)=>{
10
+ const header = Buffer.alloc(8);
11
+ header.writeUInt32BE(size);
12
+ header.write(type, 4, 4, 'latin1');
13
+ return Buffer.concat([
14
+ header,
15
+ content
16
+ ]);
17
+ };
18
+ const extendedBox = (type, content)=>{
19
+ const header = Buffer.alloc(16);
20
+ header.writeUInt32BE(1);
21
+ header.write(type, 4, 4, 'latin1');
22
+ header.writeBigUInt64BE(BigInt(content.length + 16), 8);
23
+ return Buffer.concat([
24
+ header,
25
+ content
26
+ ]);
27
+ };
28
+ const fileTypeContent = (brand = 'avif')=>{
29
+ const content = Buffer.alloc(12);
30
+ content.write(brand, 0, 4, 'latin1');
31
+ content.write(brand, 8, 4, 'latin1');
32
+ return content;
33
+ };
34
+ const validFile = (brand = 'avif')=>Buffer.concat([
35
+ box('ftyp', fileTypeContent(brand)),
36
+ box('free')
37
+ ]);
38
+ afterEach(async ()=>{
39
+ await Promise.all(tempFiles.splice(0).map((filePath)=>fs.unlink(filePath)));
40
+ });
41
+ describe('ISO base media file validation', ()=>{
42
+ it.each([
43
+ 'audio/mp4',
44
+ 'audio/x-m4a',
45
+ 'image/avif',
46
+ 'image/heic',
47
+ 'image/heic-sequence',
48
+ 'image/heif',
49
+ 'image/heif-sequence',
50
+ 'image/x-canon-cr3',
51
+ 'video/3gpp',
52
+ 'video/3gpp2',
53
+ 'video/mp4',
54
+ 'video/quicktime',
55
+ 'video/x-m4v'
56
+ ])('should identify %s as an ISO base media type', (mimeType)=>{
57
+ expect(isISOBaseMediaMimeType(mimeType)).toBe(true);
58
+ });
59
+ it('should preserve unrelated media types', ()=>{
60
+ expect(isISOBaseMediaMimeType('image/png')).toBe(false);
61
+ });
62
+ it('should accept normal and extended file type boxes', async ()=>{
63
+ await expect(validateISOBaseMediaBuffer(validFile())).resolves.toBe(true);
64
+ await expect(validateISOBaseMediaBuffer(Buffer.concat([
65
+ extendedBox('ftyp', fileTypeContent('heic')),
66
+ box('free')
67
+ ]))).resolves.toBe(true);
68
+ });
69
+ it('should accept a final box that extends to the end of the file', async ()=>{
70
+ const finalBox = box('mdat', Buffer.from('reference'), 0);
71
+ await expect(validateISOBaseMediaBuffer(Buffer.concat([
72
+ box('ftyp', fileTypeContent()),
73
+ finalBox
74
+ ]))).resolves.toBe(true);
75
+ });
76
+ it.each([
77
+ 'free',
78
+ 'mdat',
79
+ 'moov',
80
+ 'wide'
81
+ ])('should accept a QuickTime file beginning with %s', async (type)=>{
82
+ const content = Buffer.concat([
83
+ box(type),
84
+ box('mdat', Buffer.from('reference'))
85
+ ]);
86
+ await expect(fileTypeFromBuffer(content)).resolves.toMatchObject({
87
+ mime: 'video/quicktime'
88
+ });
89
+ await expect(validateISOBaseMediaBuffer(content)).resolves.toBe(true);
90
+ });
91
+ it.each([
92
+ [
93
+ 'missing following box',
94
+ box('ftyp', fileTypeContent())
95
+ ],
96
+ [
97
+ 'file type box extending to end',
98
+ box('ftyp', fileTypeContent(), 0)
99
+ ],
100
+ [
101
+ 'short file type payload',
102
+ box('ftyp', Buffer.from('avif'), 12)
103
+ ],
104
+ [
105
+ 'unaligned compatible brands',
106
+ box('ftyp', Buffer.alloc(9), 17)
107
+ ],
108
+ [
109
+ 'box extending beyond the file',
110
+ box('ftyp', fileTypeContent(), 128)
111
+ ],
112
+ [
113
+ 'trailing partial header',
114
+ Buffer.concat([
115
+ validFile(),
116
+ Buffer.alloc(4)
117
+ ])
118
+ ]
119
+ ])('should reject %s', async (_, content)=>{
120
+ await expect(validateISOBaseMediaBuffer(content)).resolves.toBe(false);
121
+ });
122
+ it('should validate file-backed uploads without loading the full file', async ()=>{
123
+ const filePath = path.join(os.tmpdir(), `payload-media-${randomUUID()}`);
124
+ tempFiles.push(filePath);
125
+ await fs.writeFile(filePath, validFile('mif1'));
126
+ await expect(validateISOBaseMediaFile(filePath)).resolves.toBe(true);
127
+ });
128
+ });
129
+
130
+ //# sourceMappingURL=validateISOBaseMediaFile.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/uploads/validateISOBaseMediaFile.spec.ts"],"sourcesContent":["import fs from 'fs/promises'\nimport { randomUUID } from 'crypto'\nimport { fileTypeFromBuffer } from 'file-type'\nimport os from 'os'\nimport path from 'path'\nimport { afterEach, describe, expect, it } from 'vitest'\n\nimport {\n isISOBaseMediaMimeType,\n validateISOBaseMediaBuffer,\n validateISOBaseMediaFile,\n} from './validateISOBaseMediaFile.js'\n\nconst tempFiles: string[] = []\n\nconst box = (type: string, content = Buffer.alloc(0), size = content.length + 8): Buffer => {\n const header = Buffer.alloc(8)\n header.writeUInt32BE(size)\n header.write(type, 4, 4, 'latin1')\n return Buffer.concat([header, content])\n}\n\nconst extendedBox = (type: string, content: Buffer): Buffer => {\n const header = Buffer.alloc(16)\n header.writeUInt32BE(1)\n header.write(type, 4, 4, 'latin1')\n header.writeBigUInt64BE(BigInt(content.length + 16), 8)\n return Buffer.concat([header, content])\n}\n\nconst fileTypeContent = (brand = 'avif'): Buffer => {\n const content = Buffer.alloc(12)\n content.write(brand, 0, 4, 'latin1')\n content.write(brand, 8, 4, 'latin1')\n return content\n}\n\nconst validFile = (brand = 'avif'): Buffer =>\n Buffer.concat([box('ftyp', fileTypeContent(brand)), box('free')])\n\nafterEach(async () => {\n await Promise.all(tempFiles.splice(0).map((filePath) => fs.unlink(filePath)))\n})\n\ndescribe('ISO base media file validation', () => {\n it.each([\n 'audio/mp4',\n 'audio/x-m4a',\n 'image/avif',\n 'image/heic',\n 'image/heic-sequence',\n 'image/heif',\n 'image/heif-sequence',\n 'image/x-canon-cr3',\n 'video/3gpp',\n 'video/3gpp2',\n 'video/mp4',\n 'video/quicktime',\n 'video/x-m4v',\n ])('should identify %s as an ISO base media type', (mimeType) => {\n expect(isISOBaseMediaMimeType(mimeType)).toBe(true)\n })\n\n it('should preserve unrelated media types', () => {\n expect(isISOBaseMediaMimeType('image/png')).toBe(false)\n })\n\n it('should accept normal and extended file type boxes', async () => {\n await expect(validateISOBaseMediaBuffer(validFile())).resolves.toBe(true)\n await expect(\n validateISOBaseMediaBuffer(\n Buffer.concat([extendedBox('ftyp', fileTypeContent('heic')), box('free')]),\n ),\n ).resolves.toBe(true)\n })\n\n it('should accept a final box that extends to the end of the file', async () => {\n const finalBox = box('mdat', Buffer.from('reference'), 0)\n await expect(\n validateISOBaseMediaBuffer(Buffer.concat([box('ftyp', fileTypeContent()), finalBox])),\n ).resolves.toBe(true)\n })\n\n it.each(['free', 'mdat', 'moov', 'wide'])(\n 'should accept a QuickTime file beginning with %s',\n async (type) => {\n const content = Buffer.concat([box(type), box('mdat', Buffer.from('reference'))])\n await expect(fileTypeFromBuffer(content)).resolves.toMatchObject({ mime: 'video/quicktime' })\n await expect(validateISOBaseMediaBuffer(content)).resolves.toBe(true)\n },\n )\n\n it.each([\n ['missing following box', box('ftyp', fileTypeContent())],\n ['file type box extending to end', box('ftyp', fileTypeContent(), 0)],\n ['short file type payload', box('ftyp', Buffer.from('avif'), 12)],\n ['unaligned compatible brands', box('ftyp', Buffer.alloc(9), 17)],\n ['box extending beyond the file', box('ftyp', fileTypeContent(), 128)],\n ['trailing partial header', Buffer.concat([validFile(), Buffer.alloc(4)])],\n ])('should reject %s', async (_, content) => {\n await expect(validateISOBaseMediaBuffer(content)).resolves.toBe(false)\n })\n\n it('should validate file-backed uploads without loading the full file', async () => {\n const filePath = path.join(os.tmpdir(), `payload-media-${randomUUID()}`)\n tempFiles.push(filePath)\n await fs.writeFile(filePath, validFile('mif1'))\n\n await expect(validateISOBaseMediaFile(filePath)).resolves.toBe(true)\n })\n})\n"],"names":["fs","randomUUID","fileTypeFromBuffer","os","path","afterEach","describe","expect","it","isISOBaseMediaMimeType","validateISOBaseMediaBuffer","validateISOBaseMediaFile","tempFiles","box","type","content","Buffer","alloc","size","length","header","writeUInt32BE","write","concat","extendedBox","writeBigUInt64BE","BigInt","fileTypeContent","brand","validFile","Promise","all","splice","map","filePath","unlink","each","mimeType","toBe","resolves","finalBox","from","toMatchObject","mime","_","join","tmpdir","push","writeFile"],"mappings":"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"}
@@ -1,6 +1,12 @@
1
- /**
2
- * Validate SVG content for security vulnerabilities
3
- * Detects and blocks malicious patterns commonly used in SVG-based attacks
4
- */
1
+ export type SvgInspection = {
2
+ isSafe: boolean;
3
+ isSvg: boolean;
4
+ isValid: boolean;
5
+ };
6
+ export declare function inspectSvg(buffer: Buffer): SvgInspection;
7
+ export declare function inspectSvgFile(filePath: string, options?: {
8
+ highWaterMark?: number;
9
+ }): Promise<SvgInspection>;
10
+ /** Validate SVG content by parsing its XML structure and rejecting active content. */
5
11
  export declare function validateSvg(buffer: Buffer): boolean;
6
12
  //# sourceMappingURL=validateSvg.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"validateSvg.d.ts","sourceRoot":"","sources":["../../src/uploads/validateSvg.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAqDnD"}
1
+ {"version":3,"file":"validateSvg.d.ts","sourceRoot":"","sources":["../../src/uploads/validateSvg.ts"],"names":[],"mappings":"AAuEA,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,OAAO,CAAA;IACf,KAAK,EAAE,OAAO,CAAA;IACd,OAAO,EAAE,OAAO,CAAA;CACjB,CAAA;AAmMD,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,CAiBxD;AAED,wBAAsB,cAAc,CAClC,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,GACnC,OAAO,CAAC,aAAa,CAAC,CAiCxB;AAED,sFAAsF;AACtF,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEnD"}
@@ -1,46 +1,286 @@
1
- /**
2
- * Validate SVG content for security vulnerabilities
3
- * Detects and blocks malicious patterns commonly used in SVG-based attacks
4
- */ export function validateSvg(buffer) {
1
+ import { createReadStream } from 'fs';
2
+ import sax from 'sax';
3
+ import { TextDecoder } from 'util';
4
+ const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
5
+ const blockedElements = new Set([
6
+ 'embed',
7
+ 'foreignobject',
8
+ 'iframe',
9
+ 'object',
10
+ 'script'
11
+ ]);
12
+ const animationElements = new Set([
13
+ 'animate',
14
+ 'animatemotion',
15
+ 'animatetransform',
16
+ 'set'
17
+ ]);
18
+ const animationValueAttributes = new Set([
19
+ 'by',
20
+ 'from',
21
+ 'to',
22
+ 'values'
23
+ ]);
24
+ const urlAttributes = new Set([
25
+ 'data',
26
+ 'href',
27
+ 'src'
28
+ ]);
29
+ const urlFunctionAttributes = new Set([
30
+ 'clip-path',
31
+ 'cursor',
32
+ 'fill',
33
+ 'filter',
34
+ 'marker',
35
+ 'marker-end',
36
+ 'marker-mid',
37
+ 'marker-start',
38
+ 'mask',
39
+ 'stroke'
40
+ ]);
41
+ const getLocalName = (name)=>{
42
+ const separator = name.lastIndexOf(':');
43
+ return (separator === -1 ? name : name.slice(separator + 1)).toLowerCase();
44
+ };
45
+ const getPrefix = (name)=>{
46
+ const separator = name.indexOf(':');
47
+ return separator === -1 ? '' : name.slice(0, separator);
48
+ };
49
+ const hasBlockedURL = (value)=>{
50
+ let normalizedValue = '';
51
+ for (const character of value){
52
+ const codePoint = character.codePointAt(0);
53
+ if (codePoint && codePoint > 0x20 && codePoint !== 0x7f) {
54
+ normalizedValue += character;
55
+ }
56
+ }
57
+ normalizedValue = normalizedValue.toLowerCase();
58
+ return normalizedValue.includes('javascript:') || normalizedValue.includes('data:text/html') || normalizedValue.includes('data:image/svg+xml');
59
+ };
60
+ const decodeCSSValue = (value)=>value.replace(/\/\*[\s\S]*?\*\//g, '').replace(/\\\r\n|\\[\n\r\f]/g, '').replace(/\\([\da-f]{1,6})\s?|\\(.)/gi, (_match, hexadecimal, escapedCharacter)=>{
61
+ if (hexadecimal) {
62
+ const codePoint = Number.parseInt(hexadecimal, 16);
63
+ return codePoint > 0 && codePoint <= 0x10ffff ? String.fromCodePoint(codePoint) : '';
64
+ }
65
+ return escapedCharacter || '';
66
+ });
67
+ const hasBlockedStyles = (value)=>{
68
+ const decodedValue = decodeCSSValue(value);
69
+ return decodedValue.toLowerCase().includes('@import') || hasBlockedURL(decodedValue);
70
+ };
71
+ const getXMLDecoder = (buffer)=>{
72
+ if (buffer[0] === 0xff && buffer[1] === 0xfe || buffer[0] === 0x3c && buffer[1] === 0x00 && buffer[2] === 0x3f && buffer[3] === 0x00) {
73
+ return new TextDecoder('utf-16le');
74
+ }
75
+ if (buffer[0] === 0xfe && buffer[1] === 0xff || buffer[0] === 0x00 && buffer[1] === 0x3c && buffer[2] === 0x00 && buffer[3] === 0x3f) {
76
+ return new TextDecoder('utf-16be');
77
+ }
78
+ return new TextDecoder('utf-8');
79
+ };
80
+ const createSvgInspector = ()=>{
81
+ // sax's namespace mode walks prototype chains at every close tag. Payload only needs to resolve
82
+ // the root SVG namespace; active descendants and attributes are checked by local name.
83
+ const saxWithBufferLength = sax;
84
+ const maxBufferLength = saxWithBufferLength.MAX_BUFFER_LENGTH;
85
+ let parser;
86
+ try {
87
+ saxWithBufferLength.MAX_BUFFER_LENGTH = Number.POSITIVE_INFINITY;
88
+ parser = sax.parser(true, {
89
+ position: false,
90
+ strictEntities: true,
91
+ xmlns: false
92
+ });
93
+ } finally{
94
+ saxWithBufferLength.MAX_BUFFER_LENGTH = maxBufferLength;
95
+ }
96
+ let attributes = [];
97
+ const elementNames = [];
98
+ let isSafe = true;
99
+ let isSvg = false;
100
+ let isValid = true;
101
+ let rootElementSeen = false;
102
+ let styleContent = null;
103
+ let styleElementDepth = 0;
104
+ parser.onerror = (error)=>{
105
+ throw error;
106
+ };
107
+ parser.onprocessinginstruction = ({ name })=>{
108
+ if (name.toLowerCase() === 'xml-stylesheet') {
109
+ isSafe = false;
110
+ }
111
+ };
112
+ parser.ondoctype = (doctype)=>{
113
+ if (doctype.includes('[') || /<!entity/i.test(doctype)) {
114
+ isSafe = false;
115
+ }
116
+ };
117
+ parser.onopentagstart = (tag)=>{
118
+ attributes = [];
119
+ // sax stores attributes in a normal object and calls its hasOwnProperty method. Use a guarded
120
+ // null-prototype object so valid XML attributes with object-property names remain supported.
121
+ const saxAttributes = Object.create(null);
122
+ tag.attributes = new Proxy(saxAttributes, {
123
+ get: (target, property, receiver)=>{
124
+ if (property === 'hasOwnProperty') {
125
+ return (name)=>Object.prototype.hasOwnProperty.call(target, name);
126
+ }
127
+ return Reflect.get(target, property, receiver);
128
+ }
129
+ });
130
+ };
131
+ parser.onattribute = (attribute)=>{
132
+ attributes.push(attribute);
133
+ };
134
+ parser.onopentag = (tag)=>{
135
+ const localName = getLocalName(tag.name);
136
+ elementNames.push(localName);
137
+ if (!rootElementSeen) {
138
+ rootElementSeen = true;
139
+ const prefix = getPrefix(tag.name);
140
+ const namespaceAttribute = prefix ? `xmlns:${prefix}` : 'xmlns';
141
+ const namespace = attributes.find(({ name })=>name === namespaceAttribute)?.value;
142
+ isSvg = localName === 'svg' && namespace === SVG_NAMESPACE;
143
+ if (!isSvg) {
144
+ isSafe = false;
145
+ }
146
+ }
147
+ if (blockedElements.has(localName)) {
148
+ isSafe = false;
149
+ }
150
+ if (localName === 'style') {
151
+ styleElementDepth += 1;
152
+ if (styleElementDepth === 1) {
153
+ styleContent = '';
154
+ }
155
+ }
156
+ if (animationElements.has(localName)) {
157
+ const targetAttribute = attributes.find(({ name })=>getLocalName(name).toLowerCase() === 'attributename')?.value.trim();
158
+ const targetName = targetAttribute ? getLocalName(targetAttribute) : '';
159
+ const values = attributes.filter(({ name })=>animationValueAttributes.has(getLocalName(name))).map(({ value })=>value).join(';');
160
+ if (/^on[a-z]/.test(targetName) || urlAttributes.has(targetName) && hasBlockedURL(values) || targetName === 'style' && hasBlockedStyles(values) || urlFunctionAttributes.has(targetName) && hasBlockedStyles(values)) {
161
+ isSafe = false;
162
+ }
163
+ }
164
+ for (const attribute of attributes){
165
+ const attributeName = getLocalName(attribute.name);
166
+ if (/^on[a-z]/.test(attributeName)) {
167
+ isSafe = false;
168
+ }
169
+ if (attributeName === 'style' && hasBlockedStyles(attribute.value)) {
170
+ isSafe = false;
171
+ }
172
+ if (urlAttributes.has(attributeName) && hasBlockedURL(attribute.value)) {
173
+ isSafe = false;
174
+ }
175
+ if (urlFunctionAttributes.has(attributeName) && /url\s*\(/i.test(attribute.value) && hasBlockedStyles(attribute.value)) {
176
+ isSafe = false;
177
+ }
178
+ }
179
+ };
180
+ parser.onclosetag = ()=>{
181
+ if (elementNames.pop() === 'style') {
182
+ if (styleElementDepth === 1 && styleContent && hasBlockedStyles(styleContent)) {
183
+ isSafe = false;
184
+ }
185
+ styleElementDepth -= 1;
186
+ if (styleElementDepth === 0) {
187
+ styleContent = null;
188
+ }
189
+ }
190
+ };
191
+ const collectStyleContent = (value)=>{
192
+ if (styleElementDepth > 0 && styleContent !== null) {
193
+ styleContent += value;
194
+ }
195
+ };
196
+ parser.ontext = collectStyleContent;
197
+ parser.oncdata = collectStyleContent;
198
+ return {
199
+ close: ()=>{
200
+ parser.close();
201
+ if (!rootElementSeen) {
202
+ throw new Error('Missing root element');
203
+ }
204
+ },
205
+ getResult: ()=>({
206
+ isSafe: rootElementSeen && isSafe && isValid,
207
+ isSvg,
208
+ isValid
209
+ }),
210
+ hasNonSvgRoot: ()=>rootElementSeen && !isSvg,
211
+ markInvalid: ()=>{
212
+ isValid = false;
213
+ },
214
+ write: (value)=>parser.write(value)
215
+ };
216
+ };
217
+ export function inspectSvg(buffer) {
218
+ const inspector = createSvgInspector();
219
+ const decoder = getXMLDecoder(buffer);
5
220
  try {
6
- const content = buffer.toString('utf8');
7
- const dangerousPatterns = [
8
- // Script tags
9
- /<script[\s>]/i,
10
- /<\/script>/i,
11
- // Event handlers (onclick, onload, onerror, etc.)
12
- /\son\w+\s*=/i,
13
- // JavaScript URLs
14
- /javascript:/i,
15
- /data:text\/html/i,
16
- // Foreign objects (can embed HTML)
17
- /<foreignObject[\s>]/i,
18
- // Embedded iframes
19
- /<iframe[\s>]/i,
20
- // Embedded objects and embeds
21
- /<object[\s>]/i,
22
- /<embed[\s>]/i,
23
- // Base64 encoded scripts (common obfuscation technique)
24
- /data:image\/svg\+xml;base64,[\w+/]*PHNjcmlwdA/i,
25
- // XLink href with javascript (deprecated but still dangerous)
26
- /xlink:href\s*=\s*["']javascript:/i,
27
- // Import statements
28
- /@import/i,
29
- // External resource references that could be dangerous
30
- /<!ENTITY/i,
31
- /<!DOCTYPE[^>]*\[/i,
32
- // Attempt to use CDATA to hide scripts
33
- /<!\[CDATA\[[\s\S]*<script/i
34
- ];
35
- for (const pattern of dangerousPatterns){
36
- if (pattern.test(content)) {
37
- return false;
38
- }
39
- }
40
- return true;
221
+ for(let offset = 0; offset < buffer.length; offset += 64 * 1024){
222
+ inspector.write(decoder.decode(buffer.subarray(offset, offset + 64 * 1024), {
223
+ stream: true
224
+ }));
225
+ if (inspector.hasNonSvgRoot()) {
226
+ return inspector.getResult();
227
+ }
228
+ }
229
+ inspector.write(decoder.decode());
230
+ inspector.close();
231
+ return inspector.getResult();
41
232
  } catch (_error) {
42
- return false;
233
+ inspector.markInvalid();
234
+ return {
235
+ ...inspector.getResult(),
236
+ isSafe: false
237
+ };
43
238
  }
44
239
  }
240
+ export async function inspectSvgFile(filePath, options) {
241
+ const inspector = createSvgInspector();
242
+ let decoder = null;
243
+ let prefix = Buffer.alloc(0);
244
+ try {
245
+ for await (const chunk of createReadStream(filePath, options)){
246
+ let content = chunk;
247
+ if (!decoder) {
248
+ prefix = Buffer.concat([
249
+ prefix,
250
+ content
251
+ ]);
252
+ if (prefix.length < 4) {
253
+ continue;
254
+ }
255
+ decoder = getXMLDecoder(prefix);
256
+ content = prefix;
257
+ }
258
+ inspector.write(decoder.decode(content, {
259
+ stream: true
260
+ }));
261
+ if (inspector.hasNonSvgRoot()) {
262
+ return inspector.getResult();
263
+ }
264
+ }
265
+ decoder ??= getXMLDecoder(prefix);
266
+ if (prefix.length > 0 && prefix.length < 4) {
267
+ inspector.write(decoder.decode(prefix, {
268
+ stream: true
269
+ }));
270
+ }
271
+ inspector.write(decoder.decode());
272
+ inspector.close();
273
+ return inspector.getResult();
274
+ } catch (_error) {
275
+ inspector.markInvalid();
276
+ return {
277
+ ...inspector.getResult(),
278
+ isSafe: false
279
+ };
280
+ }
281
+ }
282
+ /** Validate SVG content by parsing its XML structure and rejecting active content. */ export function validateSvg(buffer) {
283
+ return inspectSvg(buffer).isSafe;
284
+ }
45
285
 
46
286
  //# sourceMappingURL=validateSvg.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/uploads/validateSvg.ts"],"sourcesContent":["/**\n * Validate SVG content for security vulnerabilities\n * Detects and blocks malicious patterns commonly used in SVG-based attacks\n */\nexport function validateSvg(buffer: Buffer): boolean {\n try {\n const content = buffer.toString('utf8')\n\n const dangerousPatterns = [\n // Script tags\n /<script[\\s>]/i,\n /<\\/script>/i,\n\n // Event handlers (onclick, onload, onerror, etc.)\n /\\son\\w+\\s*=/i,\n\n // JavaScript URLs\n /javascript:/i,\n /data:text\\/html/i,\n\n // Foreign objects (can embed HTML)\n /<foreignObject[\\s>]/i,\n\n // Embedded iframes\n /<iframe[\\s>]/i,\n\n // Embedded objects and embeds\n /<object[\\s>]/i,\n /<embed[\\s>]/i,\n\n // Base64 encoded scripts (common obfuscation technique)\n /data:image\\/svg\\+xml;base64,[\\w+/]*PHNjcmlwdA/i, // <script in base64\n\n // XLink href with javascript (deprecated but still dangerous)\n /xlink:href\\s*=\\s*[\"']javascript:/i,\n\n // Import statements\n /@import/i,\n\n // External resource references that could be dangerous\n /<!ENTITY/i,\n /<!DOCTYPE[^>]*\\[/i, // DOCTYPE with internal subset\n\n // Attempt to use CDATA to hide scripts\n /<!\\[CDATA\\[[\\s\\S]*<script/i,\n ]\n\n for (const pattern of dangerousPatterns) {\n if (pattern.test(content)) {\n return false\n }\n }\n\n return true\n } catch (_error) {\n return false\n }\n}\n"],"names":["validateSvg","buffer","content","toString","dangerousPatterns","pattern","test","_error"],"mappings":"AAAA;;;CAGC,GACD,OAAO,SAASA,YAAYC,MAAc;IACxC,IAAI;QACF,MAAMC,UAAUD,OAAOE,QAAQ,CAAC;QAEhC,MAAMC,oBAAoB;YACxB,cAAc;YACd;YACA;YAEA,kDAAkD;YAClD;YAEA,kBAAkB;YAClB;YACA;YAEA,mCAAmC;YACnC;YAEA,mBAAmB;YACnB;YAEA,8BAA8B;YAC9B;YACA;YAEA,wDAAwD;YACxD;YAEA,8DAA8D;YAC9D;YAEA,oBAAoB;YACpB;YAEA,uDAAuD;YACvD;YACA;YAEA,uCAAuC;YACvC;SACD;QAED,KAAK,MAAMC,WAAWD,kBAAmB;YACvC,IAAIC,QAAQC,IAAI,CAACJ,UAAU;gBACzB,OAAO;YACT;QACF;QAEA,OAAO;IACT,EAAE,OAAOK,QAAQ;QACf,OAAO;IACT;AACF"}
1
+ {"version":3,"sources":["../../src/uploads/validateSvg.ts"],"sourcesContent":["import { createReadStream } from 'fs'\nimport sax, { type SAXOptions } from 'sax'\nimport { TextDecoder } from 'util'\n\nconst SVG_NAMESPACE = 'http://www.w3.org/2000/svg'\n\nconst blockedElements = new Set(['embed', 'foreignobject', 'iframe', 'object', 'script'])\nconst animationElements = new Set(['animate', 'animatemotion', 'animatetransform', 'set'])\nconst animationValueAttributes = new Set(['by', 'from', 'to', 'values'])\nconst urlAttributes = new Set(['data', 'href', 'src'])\nconst urlFunctionAttributes = new Set([\n 'clip-path',\n 'cursor',\n 'fill',\n 'filter',\n 'marker',\n 'marker-end',\n 'marker-mid',\n 'marker-start',\n 'mask',\n 'stroke',\n])\n\nconst getLocalName = (name: string): string => {\n const separator = name.lastIndexOf(':')\n return (separator === -1 ? name : name.slice(separator + 1)).toLowerCase()\n}\n\nconst getPrefix = (name: string): string => {\n const separator = name.indexOf(':')\n return separator === -1 ? '' : name.slice(0, separator)\n}\n\nconst hasBlockedURL = (value: string): boolean => {\n let normalizedValue = ''\n\n for (const character of value) {\n const codePoint = character.codePointAt(0)\n if (codePoint && codePoint > 0x20 && codePoint !== 0x7f) {\n normalizedValue += character\n }\n }\n\n normalizedValue = normalizedValue.toLowerCase()\n\n return (\n normalizedValue.includes('javascript:') ||\n normalizedValue.includes('data:text/html') ||\n normalizedValue.includes('data:image/svg+xml')\n )\n}\n\nconst decodeCSSValue = (value: string): string =>\n value\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, '')\n .replace(/\\\\\\r\\n|\\\\[\\n\\r\\f]/g, '')\n .replace(/\\\\([\\da-f]{1,6})\\s?|\\\\(.)/gi, (_match, hexadecimal, escapedCharacter) => {\n if (hexadecimal) {\n const codePoint = Number.parseInt(hexadecimal, 16)\n return codePoint > 0 && codePoint <= 0x10ffff ? String.fromCodePoint(codePoint) : ''\n }\n\n return escapedCharacter || ''\n })\n\nconst hasBlockedStyles = (value: string): boolean => {\n const decodedValue = decodeCSSValue(value)\n\n return decodedValue.toLowerCase().includes('@import') || hasBlockedURL(decodedValue)\n}\n\nexport type SvgInspection = {\n isSafe: boolean\n isSvg: boolean\n isValid: boolean\n}\n\nconst getXMLDecoder = (buffer: Buffer): TextDecoder => {\n if (\n (buffer[0] === 0xff && buffer[1] === 0xfe) ||\n (buffer[0] === 0x3c && buffer[1] === 0x00 && buffer[2] === 0x3f && buffer[3] === 0x00)\n ) {\n return new TextDecoder('utf-16le')\n }\n\n if (\n (buffer[0] === 0xfe && buffer[1] === 0xff) ||\n (buffer[0] === 0x00 && buffer[1] === 0x3c && buffer[2] === 0x00 && buffer[3] === 0x3f)\n ) {\n return new TextDecoder('utf-16be')\n }\n\n return new TextDecoder('utf-8')\n}\n\nconst createSvgInspector = () => {\n // sax's namespace mode walks prototype chains at every close tag. Payload only needs to resolve\n // the root SVG namespace; active descendants and attributes are checked by local name.\n const saxWithBufferLength = sax as { MAX_BUFFER_LENGTH: number } & typeof sax\n const maxBufferLength = saxWithBufferLength.MAX_BUFFER_LENGTH\n let parser: ReturnType<typeof sax.parser>\n try {\n saxWithBufferLength.MAX_BUFFER_LENGTH = Number.POSITIVE_INFINITY\n parser = sax.parser(true, {\n position: false,\n strictEntities: true,\n xmlns: false,\n } as { strictEntities: boolean } & SAXOptions)\n } finally {\n saxWithBufferLength.MAX_BUFFER_LENGTH = maxBufferLength\n }\n\n let attributes: Array<{ name: string; value: string }> = []\n const elementNames: string[] = []\n let isSafe = true\n let isSvg = false\n let isValid = true\n let rootElementSeen = false\n let styleContent: null | string = null\n let styleElementDepth = 0\n\n parser.onerror = (error) => {\n throw error\n }\n\n parser.onprocessinginstruction = ({ name }) => {\n if (name.toLowerCase() === 'xml-stylesheet') {\n isSafe = false\n }\n }\n\n parser.ondoctype = (doctype) => {\n if (doctype.includes('[') || /<!entity/i.test(doctype)) {\n isSafe = false\n }\n }\n\n parser.onopentagstart = (tag) => {\n attributes = []\n\n // sax stores attributes in a normal object and calls its hasOwnProperty method. Use a guarded\n // null-prototype object so valid XML attributes with object-property names remain supported.\n const saxAttributes = Object.create(null) as typeof tag.attributes\n tag.attributes = new Proxy(saxAttributes, {\n get: (target, property, receiver) => {\n if (property === 'hasOwnProperty') {\n return (name: string) => Object.prototype.hasOwnProperty.call(target, name)\n }\n\n return Reflect.get(target, property, receiver)\n },\n })\n }\n\n parser.onattribute = (attribute) => {\n attributes.push(attribute)\n }\n\n parser.onopentag = (tag) => {\n const localName = getLocalName(tag.name)\n elementNames.push(localName)\n\n if (!rootElementSeen) {\n rootElementSeen = true\n const prefix = getPrefix(tag.name)\n const namespaceAttribute = prefix ? `xmlns:${prefix}` : 'xmlns'\n const namespace = attributes.find(({ name }) => name === namespaceAttribute)?.value\n isSvg = localName === 'svg' && namespace === SVG_NAMESPACE\n if (!isSvg) {\n isSafe = false\n }\n }\n\n if (blockedElements.has(localName)) {\n isSafe = false\n }\n\n if (localName === 'style') {\n styleElementDepth += 1\n if (styleElementDepth === 1) {\n styleContent = ''\n }\n }\n\n if (animationElements.has(localName)) {\n const targetAttribute = attributes\n .find(({ name }) => getLocalName(name).toLowerCase() === 'attributename')\n ?.value.trim()\n const targetName = targetAttribute ? getLocalName(targetAttribute) : ''\n const values = attributes\n .filter(({ name }) => animationValueAttributes.has(getLocalName(name)))\n .map(({ value }) => value)\n .join(';')\n\n if (\n /^on[a-z]/.test(targetName) ||\n (urlAttributes.has(targetName) && hasBlockedURL(values)) ||\n (targetName === 'style' && hasBlockedStyles(values)) ||\n (urlFunctionAttributes.has(targetName) && hasBlockedStyles(values))\n ) {\n isSafe = false\n }\n }\n\n for (const attribute of attributes) {\n const attributeName = getLocalName(attribute.name)\n\n if (/^on[a-z]/.test(attributeName)) {\n isSafe = false\n }\n\n if (attributeName === 'style' && hasBlockedStyles(attribute.value)) {\n isSafe = false\n }\n\n if (urlAttributes.has(attributeName) && hasBlockedURL(attribute.value)) {\n isSafe = false\n }\n\n if (\n urlFunctionAttributes.has(attributeName) &&\n /url\\s*\\(/i.test(attribute.value) &&\n hasBlockedStyles(attribute.value)\n ) {\n isSafe = false\n }\n }\n }\n\n parser.onclosetag = () => {\n if (elementNames.pop() === 'style') {\n if (styleElementDepth === 1 && styleContent && hasBlockedStyles(styleContent)) {\n isSafe = false\n }\n styleElementDepth -= 1\n if (styleElementDepth === 0) {\n styleContent = null\n }\n }\n }\n\n const collectStyleContent = (value: string) => {\n if (styleElementDepth > 0 && styleContent !== null) {\n styleContent += value\n }\n }\n\n parser.ontext = collectStyleContent\n parser.oncdata = collectStyleContent\n\n return {\n close: () => {\n parser.close()\n if (!rootElementSeen) {\n throw new Error('Missing root element')\n }\n },\n getResult: (): SvgInspection => ({\n isSafe: rootElementSeen && isSafe && isValid,\n isSvg,\n isValid,\n }),\n hasNonSvgRoot: (): boolean => rootElementSeen && !isSvg,\n markInvalid: () => {\n isValid = false\n },\n write: (value: string) => parser.write(value),\n }\n}\n\nexport function inspectSvg(buffer: Buffer): SvgInspection {\n const inspector = createSvgInspector()\n const decoder = getXMLDecoder(buffer)\n try {\n for (let offset = 0; offset < buffer.length; offset += 64 * 1024) {\n inspector.write(decoder.decode(buffer.subarray(offset, offset + 64 * 1024), { stream: true }))\n if (inspector.hasNonSvgRoot()) {\n return inspector.getResult()\n }\n }\n inspector.write(decoder.decode())\n inspector.close()\n return inspector.getResult()\n } catch (_error) {\n inspector.markInvalid()\n return { ...inspector.getResult(), isSafe: false }\n }\n}\n\nexport async function inspectSvgFile(\n filePath: string,\n options?: { highWaterMark?: number },\n): Promise<SvgInspection> {\n const inspector = createSvgInspector()\n let decoder: null | TextDecoder = null\n let prefix = Buffer.alloc(0)\n\n try {\n for await (const chunk of createReadStream(filePath, options)) {\n let content: Buffer = chunk\n if (!decoder) {\n prefix = Buffer.concat([prefix, content])\n if (prefix.length < 4) {\n continue\n }\n decoder = getXMLDecoder(prefix)\n content = prefix\n }\n\n inspector.write(decoder.decode(content, { stream: true }))\n if (inspector.hasNonSvgRoot()) {\n return inspector.getResult()\n }\n }\n decoder ??= getXMLDecoder(prefix)\n if (prefix.length > 0 && prefix.length < 4) {\n inspector.write(decoder.decode(prefix, { stream: true }))\n }\n inspector.write(decoder.decode())\n inspector.close()\n return inspector.getResult()\n } catch (_error) {\n inspector.markInvalid()\n return { ...inspector.getResult(), isSafe: false }\n }\n}\n\n/** Validate SVG content by parsing its XML structure and rejecting active content. */\nexport function validateSvg(buffer: Buffer): boolean {\n return inspectSvg(buffer).isSafe\n}\n"],"names":["createReadStream","sax","TextDecoder","SVG_NAMESPACE","blockedElements","Set","animationElements","animationValueAttributes","urlAttributes","urlFunctionAttributes","getLocalName","name","separator","lastIndexOf","slice","toLowerCase","getPrefix","indexOf","hasBlockedURL","value","normalizedValue","character","codePoint","codePointAt","includes","decodeCSSValue","replace","_match","hexadecimal","escapedCharacter","Number","parseInt","String","fromCodePoint","hasBlockedStyles","decodedValue","getXMLDecoder","buffer","createSvgInspector","saxWithBufferLength","maxBufferLength","MAX_BUFFER_LENGTH","parser","POSITIVE_INFINITY","position","strictEntities","xmlns","attributes","elementNames","isSafe","isSvg","isValid","rootElementSeen","styleContent","styleElementDepth","onerror","error","onprocessinginstruction","ondoctype","doctype","test","onopentagstart","tag","saxAttributes","Object","create","Proxy","get","target","property","receiver","prototype","hasOwnProperty","call","Reflect","onattribute","attribute","push","onopentag","localName","prefix","namespaceAttribute","namespace","find","has","targetAttribute","trim","targetName","values","filter","map","join","attributeName","onclosetag","pop","collectStyleContent","ontext","oncdata","close","Error","getResult","hasNonSvgRoot","markInvalid","write","inspectSvg","inspector","decoder","offset","length","decode","subarray","stream","_error","inspectSvgFile","filePath","options","Buffer","alloc","chunk","content","concat","validateSvg"],"mappings":"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"}