conexys-elements 1.1.2 → 1.1.23

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 (254) hide show
  1. package/README.md +462 -125
  2. package/dist/Auth.d.ts +0 -0
  3. package/dist/Auth.d.ts.map +0 -0
  4. package/dist/ThemeContext.d.ts +0 -0
  5. package/dist/ThemeContext.d.ts.map +0 -0
  6. package/dist/components/AppDataSettings.d.ts +0 -0
  7. package/dist/components/AppDataSettings.d.ts.map +0 -0
  8. package/dist/components/AppDataSettingsHTML.d.ts +0 -0
  9. package/dist/components/AppDataSettingsHTML.d.ts.map +1 -1
  10. package/dist/components/AppError.d.ts +0 -0
  11. package/dist/components/AppError.d.ts.map +0 -0
  12. package/dist/components/AppFormFields.d.ts +1 -1
  13. package/dist/components/AppFormFields.d.ts.map +1 -1
  14. package/dist/components/AppFormFieldsFromConfig.d.ts +0 -0
  15. package/dist/components/AppFormFieldsFromConfig.d.ts.map +0 -0
  16. package/dist/components/AppFormFieldsNoUser.d.ts +0 -0
  17. package/dist/components/AppFormFieldsNoUser.d.ts.map +1 -1
  18. package/dist/components/AppFormFieldsTable.d.ts +0 -0
  19. package/dist/components/AppFormFieldsTable.d.ts.map +1 -1
  20. package/dist/components/AppHeaderPage.d.ts +0 -0
  21. package/dist/components/AppHeaderPage.d.ts.map +1 -1
  22. package/dist/components/AppHeaderPage404.d.ts +0 -0
  23. package/dist/components/AppHeaderPage404.d.ts.map +0 -0
  24. package/dist/components/AppSetHeaderTitle.d.ts +0 -0
  25. package/dist/components/AppSetHeaderTitle.d.ts.map +0 -0
  26. package/dist/components/BackendStatus/BackendOfflinePage.d.ts +0 -0
  27. package/dist/components/BackendStatus/BackendOfflinePage.d.ts.map +0 -0
  28. package/dist/components/BackendStatus/BackendStatusProvider.d.ts +0 -0
  29. package/dist/components/BackendStatus/BackendStatusProvider.d.ts.map +0 -0
  30. package/dist/components/BackendStatus/index.d.ts +0 -0
  31. package/dist/components/BackendStatus/index.d.ts.map +0 -0
  32. package/dist/components/ErrorBoundary.d.ts +0 -0
  33. package/dist/components/ErrorBoundary.d.ts.map +0 -0
  34. package/dist/components/NotFound.d.ts +0 -0
  35. package/dist/components/NotFound.d.ts.map +0 -0
  36. package/dist/components/PermissionGate.d.ts +0 -0
  37. package/dist/components/PermissionGate.d.ts.map +0 -0
  38. package/dist/components/Uservalidationerror.d.ts +0 -0
  39. package/dist/components/Uservalidationerror.d.ts.map +0 -0
  40. package/dist/components/dialog/AppDialogModal.d.ts +0 -0
  41. package/dist/components/dialog/AppDialogModal.d.ts.map +0 -0
  42. package/dist/components/form/RenderForm.d.ts +0 -0
  43. package/dist/components/form/RenderForm.d.ts.map +0 -0
  44. package/dist/components/form/components/Button.d.ts +0 -0
  45. package/dist/components/form/components/Button.d.ts.map +0 -0
  46. package/dist/components/form/components/Checkbox.d.ts +0 -0
  47. package/dist/components/form/components/Checkbox.d.ts.map +0 -0
  48. package/dist/components/form/components/FormLogin.d.ts +0 -0
  49. package/dist/components/form/components/FormLogin.d.ts.map +0 -0
  50. package/dist/components/form/components/Heading.d.ts +0 -0
  51. package/dist/components/form/components/Heading.d.ts.map +0 -0
  52. package/dist/components/form/components/Image.d.ts +0 -0
  53. package/dist/components/form/components/Image.d.ts.map +0 -0
  54. package/dist/components/form/components/Info.d.ts +0 -0
  55. package/dist/components/form/components/Info.d.ts.map +1 -1
  56. package/dist/components/form/components/InputFile.d.ts +0 -0
  57. package/dist/components/form/components/InputFile.d.ts.map +0 -0
  58. package/dist/components/form/components/InputPassword.d.ts +0 -0
  59. package/dist/components/form/components/InputPassword.d.ts.map +0 -0
  60. package/dist/components/form/components/InputText.d.ts +0 -0
  61. package/dist/components/form/components/InputText.d.ts.map +1 -1
  62. package/dist/components/form/components/InputWYSIWYG.d.ts +0 -0
  63. package/dist/components/form/components/InputWYSIWYG.d.ts.map +1 -1
  64. package/dist/components/form/components/Radiobutton.d.ts +0 -0
  65. package/dist/components/form/components/Radiobutton.d.ts.map +0 -0
  66. package/dist/components/form/components/Select.d.ts +0 -0
  67. package/dist/components/form/components/Select.d.ts.map +0 -0
  68. package/dist/components/form/components/Switch.d.ts +0 -0
  69. package/dist/components/form/components/Switch.d.ts.map +0 -0
  70. package/dist/components/form/components/Text.d.ts +0 -0
  71. package/dist/components/form/components/Text.d.ts.map +0 -0
  72. package/dist/components/form/components/index.d.ts +0 -0
  73. package/dist/components/form/components/index.d.ts.map +0 -0
  74. package/dist/components/form/components/validation/Validation.d.ts +4 -1
  75. package/dist/components/form/components/validation/Validation.d.ts.map +1 -1
  76. package/dist/components/index.d.ts +0 -0
  77. package/dist/components/index.d.ts.map +0 -0
  78. package/dist/components/login/LanguageSet.d.ts +0 -0
  79. package/dist/components/login/LanguageSet.d.ts.map +1 -1
  80. package/dist/components/theme/Card.d.ts +0 -0
  81. package/dist/components/theme/Card.d.ts.map +0 -0
  82. package/dist/components/theme/CardDashboard.d.ts +0 -0
  83. package/dist/components/theme/CardDashboard.d.ts.map +0 -0
  84. package/dist/components/theme/CardUser.d.ts +0 -0
  85. package/dist/components/theme/CardUser.d.ts.map +0 -0
  86. package/dist/components/theme/Loading.d.ts +0 -0
  87. package/dist/components/theme/Loading.d.ts.map +0 -0
  88. package/dist/components/theme/MailTemplateWidget.d.ts +0 -0
  89. package/dist/components/theme/MailTemplateWidget.d.ts.map +1 -1
  90. package/dist/components/theme/Mailbox.d.ts +0 -0
  91. package/dist/components/theme/Mailbox.d.ts.map +1 -1
  92. package/dist/components/theme/MessagesBlock.d.ts +0 -0
  93. package/dist/components/theme/MessagesBlock.d.ts.map +0 -0
  94. package/dist/components/theme/Timeline.d.ts +0 -0
  95. package/dist/components/theme/Timeline.d.ts.map +0 -0
  96. package/dist/components/theme/UserWidget.d.ts +0 -0
  97. package/dist/components/theme/UserWidget.d.ts.map +1 -1
  98. package/dist/components/theme/index.d.ts +0 -0
  99. package/dist/components/theme/index.d.ts.map +0 -0
  100. package/dist/config/ConexysConfig.d.ts +0 -0
  101. package/dist/config/ConexysConfig.d.ts.map +0 -0
  102. package/dist/constants/global.d.ts +0 -0
  103. package/dist/constants/global.d.ts.map +1 -1
  104. package/dist/context/PermissionContext.d.ts +0 -0
  105. package/dist/context/PermissionContext.d.ts.map +0 -0
  106. package/dist/hooks/FormHooksNormal.d.ts +1 -1
  107. package/dist/hooks/FormHooksNormal.d.ts.map +1 -1
  108. package/dist/hooks/FormHooksNormalGetPost.d.ts +0 -0
  109. package/dist/hooks/FormHooksNormalGetPost.d.ts.map +1 -1
  110. package/dist/hooks/FormHooksNormalMulti.d.ts +0 -0
  111. package/dist/hooks/FormHooksNormalMulti.d.ts.map +0 -0
  112. package/dist/hooks/FormHooksNormalNoUser.d.ts +0 -0
  113. package/dist/hooks/FormHooksNormalNoUser.d.ts.map +1 -1
  114. package/dist/hooks/FormHooksUpload.d.ts +0 -0
  115. package/dist/hooks/FormHooksUpload.d.ts.map +1 -1
  116. package/dist/hooks/FormHooksUploadPatch.d.ts +0 -0
  117. package/dist/hooks/FormHooksUploadPatch.d.ts.map +1 -1
  118. package/dist/hooks/MRT_Localization.d.ts +0 -0
  119. package/dist/hooks/MRT_Localization.d.ts.map +0 -0
  120. package/dist/hooks/useFingerprintJS.d.ts +0 -0
  121. package/dist/hooks/useFingerprintJS.d.ts.map +0 -0
  122. package/dist/hooks/useLanguageSync.d.ts +0 -0
  123. package/dist/hooks/useLanguageSync.d.ts.map +0 -0
  124. package/dist/hooks/usePermission.d.ts +0 -0
  125. package/dist/hooks/usePermission.d.ts.map +0 -0
  126. package/dist/hooks/useSocket.d.ts +0 -0
  127. package/dist/hooks/useSocket.d.ts.map +1 -1
  128. package/dist/hooks/useZoomPrevention.d.ts +0 -0
  129. package/dist/hooks/useZoomPrevention.d.ts.map +0 -0
  130. package/dist/index.css +0 -0
  131. package/dist/index.css.map +1 -1
  132. package/dist/index.d.ts +1 -0
  133. package/dist/index.d.ts.map +1 -1
  134. package/dist/index.esm.css +0 -0
  135. package/dist/index.esm.css.map +1 -1
  136. package/dist/index.esm.js +3285 -273
  137. package/dist/index.esm.js.map +1 -1
  138. package/dist/index.js +3285 -272
  139. package/dist/index.js.map +1 -1
  140. package/dist/services/deleteFormService.d.ts +0 -0
  141. package/dist/services/deleteFormService.d.ts.map +1 -1
  142. package/dist/services/deleteService.d.ts +0 -0
  143. package/dist/services/deleteService.d.ts.map +1 -1
  144. package/dist/services/deleteServiceExtended.d.ts +0 -0
  145. package/dist/services/deleteServiceExtended.d.ts.map +0 -0
  146. package/dist/services/getService.d.ts +0 -0
  147. package/dist/services/getService.d.ts.map +1 -1
  148. package/dist/services/getServiceExtended.d.ts +0 -0
  149. package/dist/services/getServiceExtended.d.ts.map +1 -1
  150. package/dist/services/patchFormService.d.ts +0 -0
  151. package/dist/services/patchFormService.d.ts.map +1 -1
  152. package/dist/services/patchService.d.ts +0 -0
  153. package/dist/services/patchService.d.ts.map +1 -1
  154. package/dist/services/patchServiceExtended.d.ts +0 -0
  155. package/dist/services/patchServiceExtended.d.ts.map +0 -0
  156. package/dist/services/postFormService.d.ts +0 -0
  157. package/dist/services/postFormService.d.ts.map +1 -1
  158. package/dist/services/postFormServiceGetPost.d.ts +0 -0
  159. package/dist/services/postFormServiceGetPost.d.ts.map +1 -1
  160. package/dist/services/postService.d.ts +0 -0
  161. package/dist/services/postService.d.ts.map +1 -1
  162. package/dist/services/postServiceExtended.d.ts +0 -0
  163. package/dist/services/postServiceExtended.d.ts.map +1 -1
  164. package/dist/services/restoreFormService.d.ts +0 -0
  165. package/dist/services/restoreFormService.d.ts.map +1 -1
  166. package/dist/shared/baseFingerprintService.d.ts +0 -0
  167. package/dist/shared/baseFingerprintService.d.ts.map +0 -0
  168. package/dist/shared/crudtable/ActionButtons.d.ts +0 -0
  169. package/dist/shared/crudtable/ActionButtons.d.ts.map +0 -0
  170. package/dist/shared/crudtable/Table.d.ts +0 -0
  171. package/dist/shared/crudtable/Table.d.ts.map +0 -0
  172. package/dist/shared/crudtable/useTableData.d.ts +0 -0
  173. package/dist/shared/crudtable/useTableData.d.ts.map +0 -0
  174. package/dist/shared/crudtable/useTableDataInstall.d.ts +0 -0
  175. package/dist/shared/crudtable/useTableDataInstall.d.ts.map +0 -0
  176. package/dist/shared/sharedComponentsAPI.d.ts +0 -0
  177. package/dist/shared/sharedComponentsAPI.d.ts.map +0 -0
  178. package/dist/shared/sharedServicesAPI.d.ts +0 -0
  179. package/dist/shared/sharedServicesAPI.d.ts.map +1 -1
  180. package/dist/types/auth.types.d.ts +1 -1
  181. package/dist/types/auth.types.d.ts.map +1 -1
  182. package/dist/types/common/form.types.d.ts +0 -0
  183. package/dist/types/common/form.types.d.ts.map +0 -0
  184. package/dist/types/common/index.d.ts +0 -0
  185. package/dist/types/common/index.d.ts.map +0 -0
  186. package/dist/types/common/props.types.d.ts +0 -0
  187. package/dist/types/common/props.types.d.ts.map +0 -0
  188. package/dist/types/common/request.types.d.ts +1 -0
  189. package/dist/types/common/request.types.d.ts.map +1 -1
  190. package/dist/types/common/service.types.d.ts +0 -0
  191. package/dist/types/common/service.types.d.ts.map +0 -0
  192. package/dist/types/common/user.types.d.ts +0 -0
  193. package/dist/types/common/user.types.d.ts.map +0 -0
  194. package/dist/types/components/appFormFields.types.d.ts +1 -0
  195. package/dist/types/components/appFormFields.types.d.ts.map +1 -1
  196. package/dist/types/components/appFormFieldsFromConfig.types.d.ts +0 -0
  197. package/dist/types/components/appFormFieldsFromConfig.types.d.ts.map +0 -0
  198. package/dist/types/components/appFormFieldsNoUser.types.d.ts +0 -0
  199. package/dist/types/components/appFormFieldsNoUser.types.d.ts.map +0 -0
  200. package/dist/types/components/appFormFieldsTable.types.d.ts +0 -0
  201. package/dist/types/components/appFormFieldsTable.types.d.ts.map +0 -0
  202. package/dist/types/components/backendStatus.types.d.ts +0 -0
  203. package/dist/types/components/backendStatus.types.d.ts.map +0 -0
  204. package/dist/types/components/components.types.d.ts +0 -0
  205. package/dist/types/components/components.types.d.ts.map +0 -0
  206. package/dist/types/components/dialog.types.d.ts +0 -0
  207. package/dist/types/components/dialog.types.d.ts.map +0 -0
  208. package/dist/types/components/form.types.d.ts +16 -0
  209. package/dist/types/components/form.types.d.ts.map +1 -1
  210. package/dist/types/components/login.types.d.ts +0 -0
  211. package/dist/types/components/login.types.d.ts.map +0 -0
  212. package/dist/types/components/pages.types.d.ts +0 -0
  213. package/dist/types/components/pages.types.d.ts.map +0 -0
  214. package/dist/types/components/theme.types.d.ts +0 -0
  215. package/dist/types/components/theme.types.d.ts.map +0 -0
  216. package/dist/types/hooks/formHooksNormal.types.d.ts +0 -0
  217. package/dist/types/hooks/formHooksNormal.types.d.ts.map +0 -0
  218. package/dist/types/hooks/formHooksNormalGetPost.types.d.ts +0 -0
  219. package/dist/types/hooks/formHooksNormalGetPost.types.d.ts.map +0 -0
  220. package/dist/types/hooks/formHooksNormalMulti.types.d.ts +0 -0
  221. package/dist/types/hooks/formHooksNormalMulti.types.d.ts.map +0 -0
  222. package/dist/types/hooks/formHooksNormalNoUser.types.d.ts +0 -0
  223. package/dist/types/hooks/formHooksNormalNoUser.types.d.ts.map +0 -0
  224. package/dist/types/hooks/formHooksUpload.types.d.ts +0 -0
  225. package/dist/types/hooks/formHooksUpload.types.d.ts.map +0 -0
  226. package/dist/types/hooks/mrt_Localization.types.d.ts +0 -0
  227. package/dist/types/hooks/mrt_Localization.types.d.ts.map +0 -0
  228. package/dist/types/permission.types.d.ts +0 -0
  229. package/dist/types/permission.types.d.ts.map +0 -0
  230. package/dist/types/services/postFormService.types.d.ts +0 -0
  231. package/dist/types/services/postFormService.types.d.ts.map +0 -0
  232. package/dist/types/services/postFormServiceGetPost.types.d.ts +0 -0
  233. package/dist/types/services/postFormServiceGetPost.types.d.ts.map +0 -0
  234. package/dist/types/services/postServiceExtended.types.d.ts +0 -0
  235. package/dist/types/services/postServiceExtended.types.d.ts.map +0 -0
  236. package/dist/types/shared/crudtable.types.d.ts +0 -0
  237. package/dist/types/shared/crudtable.types.d.ts.map +0 -0
  238. package/dist/types/themecontext.types.d.ts +0 -0
  239. package/dist/types/themecontext.types.d.ts.map +0 -0
  240. package/dist/types/utilities/generateRandomPassword.types.d.ts +0 -0
  241. package/dist/types/utilities/generateRandomPassword.types.d.ts.map +0 -0
  242. package/dist/utilities/GenerateRandomPassword.d.ts +0 -0
  243. package/dist/utilities/GenerateRandomPassword.d.ts.map +0 -0
  244. package/dist/utilities/authStorage.d.ts +9 -5
  245. package/dist/utilities/authStorage.d.ts.map +1 -1
  246. package/dist/utilities/authStorage2.d.ts +20 -0
  247. package/dist/utilities/authStorage2.d.ts.map +1 -0
  248. package/dist/utilities/checkAuth.d.ts +0 -0
  249. package/dist/utilities/checkAuth.d.ts.map +1 -1
  250. package/dist/utilities/logConsole.d.ts +0 -0
  251. package/dist/utilities/logConsole.d.ts.map +0 -0
  252. package/dist/utilities/sanitizeHtml.d.ts +2 -0
  253. package/dist/utilities/sanitizeHtml.d.ts.map +1 -0
  254. package/package.json +83 -82
package/dist/index.esm.js CHANGED
@@ -53,7 +53,30 @@ import { Stack, Button as Button$4, useTheme, darken, lighten } from '@mui/mater
53
53
  import { useMaterialReactTable, MaterialReactTable } from 'material-react-table';
54
54
  import { io } from 'socket.io-client';
55
55
 
56
- const Url = window.restAPI || '';
56
+ const REST_API_KEY = 'restAPI';
57
+ function resolveRestAPI() {
58
+ let value;
59
+ if (typeof window !== 'undefined') {
60
+ const existing = window[REST_API_KEY];
61
+ if (typeof existing === 'string' && existing.length > 0) {
62
+ value = existing;
63
+ } else {
64
+ value = '';
65
+ }
66
+ try {
67
+ Object.defineProperty(window, REST_API_KEY, {
68
+ value,
69
+ writable: false,
70
+ configurable: false,
71
+ enumerable: true
72
+ });
73
+ } catch {}
74
+ } else {
75
+ value = '';
76
+ }
77
+ return value;
78
+ }
79
+ const Url = resolveRestAPI();
57
80
 
58
81
  const logConsole = (configLogs, type, message, ...args) => {
59
82
  if (!configLogs) return;
@@ -96,6 +119,159 @@ const logConsole = (configLogs, type, message, ...args) => {
96
119
  }
97
120
  };
98
121
 
122
+ const config$4 = {
123
+ headers: {
124
+ 'Content-Type': 'application/json'
125
+ }
126
+ };
127
+ const TYPE_SESSION_CACHE_KEY = 'cx_type_session';
128
+ const COOKIE_AUTH_MARKER = 'cookie';
129
+ let USE_COOKIES_FOR_AUTH = false;
130
+ let SESSION_EXPIRATION = 365;
131
+ let isConfigInitialized = false;
132
+ let initPromise = null;
133
+ let isFetching = false;
134
+ const getCachedTypeSession = () => {
135
+ try {
136
+ return localStorage.getItem(TYPE_SESSION_CACHE_KEY);
137
+ } catch {
138
+ return null;
139
+ }
140
+ };
141
+ const resetAuthConfig = () => {
142
+ initPromise = null;
143
+ isConfigInitialized = false;
144
+ isFetching = false;
145
+ };
146
+ const setCachedTypeSession = value => {
147
+ try {
148
+ localStorage.setItem(TYPE_SESSION_CACHE_KEY, value);
149
+ } catch {}
150
+ };
151
+ const fetchTypeSession = async configLogs => {
152
+ const baseURL = Url + 'getsettings';
153
+ try {
154
+ await serviceData(baseURL, {
155
+ keys: 'type_session'
156
+ }, config$4, value => {
157
+ const resolved = value && typeof value === 'string' ? value : 'localstorage';
158
+ USE_COOKIES_FOR_AUTH = resolved === 'cookie';
159
+ setCachedTypeSession(resolved);
160
+ }, configLogs);
161
+ } catch (error) {
162
+ logConsole(configLogs, 'error', 'Error loading authentication configuration:', error);
163
+ }
164
+ };
165
+ const initializeAuthConfig = configLogs => {
166
+ if (isConfigInitialized) return Promise.resolve();
167
+ if (initPromise) return initPromise;
168
+ initPromise = (async () => {
169
+ if (isConfigInitialized) return;
170
+ const cached = getCachedTypeSession();
171
+ if (cached !== null) {
172
+ USE_COOKIES_FOR_AUTH = cached === 'cookie';
173
+ isConfigInitialized = true;
174
+ return;
175
+ }
176
+ if (isFetching) return;
177
+ isFetching = true;
178
+ try {
179
+ await fetchTypeSession(configLogs);
180
+ isConfigInitialized = true;
181
+ } finally {
182
+ isFetching = false;
183
+ initPromise = null;
184
+ }
185
+ })();
186
+ return initPromise;
187
+ };
188
+ const refreshTypeSessionFromDB = async configLogs => {
189
+ if (initPromise && !isFetching) {
190
+ await initPromise;
191
+ } else if (isFetching) {
192
+ if (initPromise) await initPromise;
193
+ }
194
+ if (isFetching) {
195
+ if (initPromise) await initPromise;
196
+ return;
197
+ }
198
+ isFetching = true;
199
+ initPromise = (async () => {
200
+ try {
201
+ await fetchTypeSession(configLogs);
202
+ isConfigInitialized = true;
203
+ } finally {
204
+ isFetching = false;
205
+ initPromise = null;
206
+ }
207
+ })();
208
+ await initPromise;
209
+ };
210
+ const authStorage = {
211
+ initialize(configLogs) {
212
+ return initializeAuthConfig(configLogs);
213
+ },
214
+ getSessionTypeValue(_configLogs) {
215
+ return 'cookie';
216
+ },
217
+ async setAuthToken(_token, _configLogs) {
218
+ localStorage.removeItem('cxauthxc');
219
+ this.deleteCookie('cxauthxc');
220
+ },
221
+ getAuthToken(_configLogs) {
222
+ return COOKIE_AUTH_MARKER;
223
+ },
224
+ hasActiveSession(_configLogs) {
225
+ const sessionId = this.getCookie('cx_session');
226
+ const csrfToken = this.getCookie('csrf_token');
227
+ return sessionId !== null && sessionId !== '' && csrfToken !== null && csrfToken !== '';
228
+ },
229
+ getCsrfToken() {
230
+ return this.getCookie('csrf_token');
231
+ },
232
+ async setSessionId(sessionId, _configLogs) {
233
+ this.setCookie('cx_session', sessionId, SESSION_EXPIRATION);
234
+ localStorage.removeItem('cx_session');
235
+ },
236
+ getSessionId(_configLogs) {
237
+ return this.getCookie('cx_session');
238
+ },
239
+ refreshTypeSession(configLogs) {
240
+ return refreshTypeSessionFromDB(configLogs);
241
+ },
242
+ async removeAuthData(configLogs) {
243
+ this.deleteCookie('cxauthxc');
244
+ this.deleteCookie('cx_session');
245
+ this.deleteCookie('csrf_token');
246
+ localStorage.removeItem('cxauthxc');
247
+ localStorage.removeItem('cx_session');
248
+ try {
249
+ localStorage.removeItem(TYPE_SESSION_CACHE_KEY);
250
+ } catch {}
251
+ resetAuthConfig();
252
+ },
253
+ setCookie(name, value, days) {
254
+ const date = new Date();
255
+ date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
256
+ const expires = `expires=${date.toUTCString()}`;
257
+ const secure = window.location.protocol === 'https:' ? ';Secure' : '';
258
+ document.cookie = `${name}=${value};${expires};path=/;SameSite=Strict${secure}`;
259
+ },
260
+ getCookie(name) {
261
+ const nameEQ = `${name}=`;
262
+ const ca = document.cookie.split(';');
263
+ for (let i = 0; i < ca.length; i++) {
264
+ let c = ca[i];
265
+ while (c.charAt(0) === ' ') c = c.substring(1, c.length);
266
+ if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length);
267
+ }
268
+ return null;
269
+ },
270
+ deleteCookie(name) {
271
+ document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 UTC;path=/;`;
272
+ }
273
+ };
274
+
99
275
  const postservice = async (datauser, configLogs) => {
100
276
  const postURL = Url + datauser.postServerURL;
101
277
  const {
@@ -104,19 +280,25 @@ const postservice = async (datauser, configLogs) => {
104
280
  cxauthxc,
105
281
  ...requestData
106
282
  } = datauser;
283
+ const xSessionType = authStorage.getSessionTypeValue(configLogs);
107
284
  let config;
108
285
  if (authorization === true || authorization === 'true') {
109
286
  config = {
287
+ withCredentials: true,
110
288
  headers: {
111
289
  Authorization: `Bearer ${cxauthxc}`,
290
+ 'X-CSRF-Token': authStorage.getCsrfToken() || '',
112
291
  'X-Session-ID': datauser.sessionID || '',
113
292
  'X-Fingerprint': datauser.fingerprint || '',
293
+ 'X-Session-Type': xSessionType,
114
294
  'Content-Type': 'application/json'
115
295
  }
116
296
  };
117
297
  } else {
118
298
  config = {
299
+ withCredentials: true,
119
300
  headers: {
301
+ 'X-CSRF-Token': authStorage.getCsrfToken() || '',
120
302
  'Content-Type': 'application/json'
121
303
  }
122
304
  };
@@ -144,22 +326,27 @@ const deleteservice = async (datauser, configLogs) => {
144
326
  cxauthxc,
145
327
  ...requestData
146
328
  } = datauser;
329
+ const xSessionType = authStorage.getSessionTypeValue(configLogs);
147
330
  let headers;
148
331
  if (authorization === true || authorization === 'true') {
149
332
  headers = {
150
333
  Authorization: `Bearer ${cxauthxc}`,
334
+ 'X-CSRF-Token': authStorage.getCsrfToken() || '',
151
335
  'X-Session-ID': datauser.sessionID || '',
152
336
  'X-Fingerprint': datauser.fingerprint || '',
337
+ 'X-Session-Type': xSessionType,
153
338
  'Content-Type': 'application/json'
154
339
  };
155
340
  } else {
156
341
  headers = {
342
+ 'X-CSRF-Token': authStorage.getCsrfToken() || '',
157
343
  'Content-Type': 'application/json'
158
344
  };
159
345
  }
160
346
  logConsole(configLogs, 'debug', '[Payload] ', requestData);
161
347
  try {
162
348
  const response = await axios.delete(deleteURL, {
349
+ withCredentials: true,
163
350
  headers,
164
351
  data: requestData
165
352
  });
@@ -174,6 +361,7 @@ const deleteservice = async (datauser, configLogs) => {
174
361
 
175
362
  const getservice = async (datauser, configLogs) => {
176
363
  const getURL = Url + datauser.postServerURL;
364
+ const xSessionType = authStorage.getSessionTypeValue(configLogs);
177
365
  const {
178
366
  authorization,
179
367
  postServerURL,
@@ -185,15 +373,18 @@ const getservice = async (datauser, configLogs) => {
185
373
  let config;
186
374
  if (authorization === true || authorization === 'true') {
187
375
  config = {
376
+ withCredentials: true,
188
377
  headers: {
189
378
  Authorization: `Bearer ${cxauthxc}`,
190
379
  'X-Session-ID': sessionID || '',
191
- 'X-Fingerprint': fingerprint || ''
380
+ 'X-Fingerprint': fingerprint || '',
381
+ 'X-Session-Type': xSessionType
192
382
  },
193
383
  params: requestData
194
384
  };
195
385
  } else {
196
386
  config = {
387
+ withCredentials: true,
197
388
  params: requestData
198
389
  };
199
390
  }
@@ -235,101 +426,6 @@ const getOrSetFingerprint = async (fpHash = '', configLogs) => {
235
426
  return await loadFingerprint(configLogs);
236
427
  };
237
428
 
238
- const config$4 = {
239
- headers: {
240
- 'Content-Type': 'application/json'
241
- }
242
- };
243
- let USE_COOKIES_FOR_AUTH = false;
244
- let SESSION_EXPIRATION = 365;
245
- let isConfigInitialized = false;
246
- let initPromise = null;
247
- const initializeAuthConfig = configLogs => {
248
- if (initPromise) return initPromise;
249
- initPromise = (async () => {
250
- if (isConfigInitialized) return;
251
- const baseURL = Url + 'getsettings';
252
- try {
253
- await serviceData(baseURL, {
254
- keys: 'type_session'
255
- }, config$4, value => {
256
- USE_COOKIES_FOR_AUTH = value === 'cookie';
257
- isConfigInitialized = true;
258
- }, configLogs);
259
- } catch (error) {
260
- logConsole(configLogs, 'error', 'Error loading authentication configuration:', error);
261
- } finally {
262
- isConfigInitialized = true;
263
- }
264
- })();
265
- return initPromise;
266
- };
267
- const authStorage = {
268
- initialize(configLogs) {
269
- return initializeAuthConfig(configLogs);
270
- },
271
- setAuthToken(token, configLogs) {
272
- initializeAuthConfig(configLogs);
273
- if (USE_COOKIES_FOR_AUTH) {
274
- this.setCookie('cxauthxc', token, SESSION_EXPIRATION);
275
- } else {
276
- localStorage.setItem('cxauthxc', token);
277
- }
278
- },
279
- getAuthToken(configLogs) {
280
- initializeAuthConfig(configLogs);
281
- if (USE_COOKIES_FOR_AUTH) {
282
- return this.getCookie('cxauthxc');
283
- }
284
- return localStorage.getItem('cxauthxc');
285
- },
286
- setSessionId(sessionId, configLogs) {
287
- initializeAuthConfig(configLogs);
288
- if (USE_COOKIES_FOR_AUTH) {
289
- this.setCookie('cx_session', sessionId, SESSION_EXPIRATION);
290
- } else {
291
- localStorage.setItem('cx_session', sessionId);
292
- }
293
- },
294
- getSessionId(configLogs) {
295
- initializeAuthConfig(configLogs);
296
- if (USE_COOKIES_FOR_AUTH) {
297
- return this.getCookie('cx_session');
298
- }
299
- return localStorage.getItem('cx_session');
300
- },
301
- removeAuthData(configLogs) {
302
- initializeAuthConfig(configLogs);
303
- if (USE_COOKIES_FOR_AUTH) {
304
- this.deleteCookie('cxauthxc');
305
- this.deleteCookie('cx_session');
306
- } else {
307
- localStorage.removeItem('cxauthxc');
308
- localStorage.removeItem('cx_session');
309
- }
310
- },
311
- setCookie(name, value, days) {
312
- const date = new Date();
313
- date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
314
- const expires = `expires=${date.toUTCString()}`;
315
- const secure = window.location.protocol === 'https:' ? ';Secure' : '';
316
- document.cookie = `${name}=${value};${expires};path=/;SameSite=Strict${secure}`;
317
- },
318
- getCookie(name) {
319
- const nameEQ = `${name}=`;
320
- const ca = document.cookie.split(';');
321
- for (let i = 0; i < ca.length; i++) {
322
- let c = ca[i];
323
- while (c.charAt(0) === ' ') c = c.substring(1, c.length);
324
- if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length);
325
- }
326
- return null;
327
- },
328
- deleteCookie(name) {
329
- document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 UTC;path=/;`;
330
- }
331
- };
332
-
333
429
  const handleError$3 = (err, t, configLogs, setIsError, setMessageerror) => {
334
430
  let errorMessage;
335
431
  if (!err?.response) {
@@ -357,7 +453,15 @@ const servicePostBasic = async (fpHash = '', sessionID, baseURL, config, setData
357
453
  };
358
454
  logConsole(configLogs, 'debug', '[Payload] ', key);
359
455
  try {
360
- const response = await axios.post(baseURL, key, config);
456
+ const response = await axios.post(baseURL, key, {
457
+ ...config,
458
+ withCredentials: true,
459
+ headers: {
460
+ ...(config?.headers || {}),
461
+ 'X-Session-Type': authStorage.getSessionTypeValue(configLogs),
462
+ 'X-CSRF-Token': authStorage.getCsrfToken() || ''
463
+ }
464
+ });
361
465
  logConsole(configLogs, 'info', '[Request] ', baseURL);
362
466
  logConsole(configLogs, 'data', '', response.data);
363
467
  setData(response.data);
@@ -369,7 +473,15 @@ const servicePostBasic = async (fpHash = '', sessionID, baseURL, config, setData
369
473
  const serviceData = async (baseURL, key, config, setData, configLogs) => {
370
474
  logConsole(configLogs, 'debug', '[Payload] ', key);
371
475
  try {
372
- const response = await axios.post(baseURL, key, config);
476
+ const response = await axios.post(baseURL, key, {
477
+ ...config,
478
+ withCredentials: true,
479
+ headers: {
480
+ ...(config?.headers || {}),
481
+ 'X-Session-Type': authStorage.getSessionTypeValue(configLogs),
482
+ 'X-CSRF-Token': authStorage.getCsrfToken() || ''
483
+ }
484
+ });
373
485
  logConsole(configLogs, 'info', '[Request] ', baseURL);
374
486
  logConsole(configLogs, 'data', '', response.data);
375
487
  const responseData = response.data;
@@ -407,7 +519,14 @@ const servicePost = async (fpHash = '', sessionID, id, permission, postURL, conf
407
519
  } else {
408
520
  logConsole(configLogs, 'debug', '[Payload] ', key);
409
521
  try {
410
- const response = await axios.post(postURL1, key, config);
522
+ const response = await axios.post(postURL1, key, {
523
+ ...config,
524
+ withCredentials: true,
525
+ headers: {
526
+ ...(config?.headers || {}),
527
+ 'X-CSRF-Token': authStorage.getCsrfToken() || ''
528
+ }
529
+ });
411
530
  logConsole(configLogs, 'info', '[Request] ', postURL1);
412
531
  logConsole(configLogs, 'data', '', response.data);
413
532
  setPost(response.data);
@@ -490,8 +609,16 @@ const servicePostData = async (fpHash = '', sessionID, id, permission, postURL,
490
609
  } else {
491
610
  logConsole(configLogs, 'debug', '[Payload] ', key);
492
611
  try {
493
- const response = await axios.post(postURL1, key, config);
612
+ const response = await axios.post(postURL1, key, {
613
+ ...config,
614
+ withCredentials: true,
615
+ headers: {
616
+ ...(config?.headers || {}),
617
+ 'X-CSRF-Token': authStorage.getCsrfToken() || ''
618
+ }
619
+ });
494
620
  logConsole(configLogs, 'info', '[Request] ', postURL1);
621
+ logConsole(configLogs, 'data', '', response.data);
495
622
  setPost(response.data);
496
623
  } catch (error) {
497
624
  logConsole(configLogs, 'error', '', error);
@@ -525,11 +652,6 @@ const serviceLogout = async (fpHash = '', sessionID, cxauthxc, t, setAuthTokens,
525
652
  const userLanguage = localStorage.getItem('userLanguage');
526
653
  const displaymode = localStorage.getItem('displaymode');
527
654
  const displayzoom = localStorage.getItem('displayzoom');
528
- localStorage.clear();
529
- authStorage.removeAuthData(configLogs);
530
- if (userLanguage) localStorage.setItem('userLanguage', userLanguage);
531
- if (displaymode) localStorage.setItem('displaymode', displaymode);
532
- if (displayzoom) localStorage.setItem('displayzoom', displayzoom);
533
655
  await postService.postservice({
534
656
  sessionID,
535
657
  cxauthxc,
@@ -537,6 +659,10 @@ const serviceLogout = async (fpHash = '', sessionID, cxauthxc, t, setAuthTokens,
537
659
  authorization: true,
538
660
  fingerprint: visitorIdHash
539
661
  }, configLogs);
662
+ authStorage.removeAuthData(configLogs);
663
+ if (userLanguage) localStorage.setItem('userLanguage', userLanguage);
664
+ if (displaymode) localStorage.setItem('displaymode', displaymode);
665
+ if (displayzoom) localStorage.setItem('displayzoom', displayzoom);
540
666
  setAuthTokens('');
541
667
  } catch (err) {
542
668
  const errorMessage = handleError$3(err, t, configLogs);
@@ -566,119 +692,2785 @@ const serviceFavorites = async (type = '', fpHash = '', sessionID, postURL, cxau
566
692
  } else {
567
693
  unreadcount = await postService.postservice(requestData, configLogs);
568
694
  }
569
- if (unreadcount && typeof unreadcount === 'object' && 'data' in unreadcount && !Array.isArray(unreadcount)) {
570
- setPost(unreadcount.data);
695
+ if (unreadcount && typeof unreadcount === 'object' && 'data' in unreadcount && !Array.isArray(unreadcount)) {
696
+ setPost(unreadcount.data);
697
+ } else {
698
+ setPost(unreadcount);
699
+ }
700
+ logConsole(configLogs, 'data', '', unreadcount);
701
+ const favoriteValue = unreadcount && typeof unreadcount === 'object' && 'data' in unreadcount && !Array.isArray(unreadcount) ? unreadcount.data : unreadcount;
702
+ if (type === 'get' && favoriteValue === true) {
703
+ setColor('#ffcd38');
704
+ } else if (type === 'set') {
705
+ setColor('#ffcd38');
706
+ localStorage.setItem('favoritessynch01', 'true');
707
+ localStorage.setItem('favoritessynch02', 'true');
708
+ window.dispatchEvent(new Event('favorites'));
709
+ } else if (type === 'del') {
710
+ setColor('');
711
+ localStorage.setItem('favoritessynch01', 'true');
712
+ localStorage.setItem('favoritessynch02', 'true');
713
+ window.dispatchEvent(new Event('favorites'));
714
+ }
715
+ setIsError(false);
716
+ } catch (err) {
717
+ setError(true);
718
+ handleError$3(err, t, configLogs, setIsError, setMessageerror);
719
+ } finally {
720
+ setLoading(false);
721
+ }
722
+ };
723
+ const serviceGetFavorites = async (fpHash = '', sessionID, postURL, cxauthxc, t, setPost, setIsError, setError, setMessageerror, setLoading, configLogs, ...rest) => {
724
+ const visitorIdHash = await getOrSetFingerprint(fpHash);
725
+ try {
726
+ const requestData = {
727
+ ...rest[0],
728
+ sessionID,
729
+ cxauthxc,
730
+ postServerURL: postURL,
731
+ authorization: true,
732
+ fingerprint: visitorIdHash
733
+ };
734
+ const unreadcount = await getservice(requestData, configLogs);
735
+ const responseData = unreadcount && typeof unreadcount === 'object' && 'data' in unreadcount && !Array.isArray(unreadcount) ? unreadcount.data : unreadcount;
736
+ setPost(responseData);
737
+ localStorage.setItem('favoritessynch03', JSON.stringify(responseData));
738
+ logConsole(configLogs, 'data', '', unreadcount);
739
+ setIsError(false);
740
+ } catch (err) {
741
+ setError(true);
742
+ handleError$3(err, t, configLogs, setIsError, setMessageerror);
743
+ } finally {
744
+ setLoading(false);
745
+ }
746
+ };
747
+
748
+ const defaultConfig$3 = {
749
+ enableLogs: false,
750
+ enableLogsError: false,
751
+ enableLogsWarning: false,
752
+ enableLogsInfo: false,
753
+ enableLogsData: false,
754
+ enableLogsDebug: false,
755
+ developmentMode: false
756
+ };
757
+ const ConexysConfigContext = /*#__PURE__*/createContext(defaultConfig$3);
758
+ const ConexysConfigProvider = ({
759
+ children,
760
+ config = {}
761
+ }) => {
762
+ const mergedConfig = {
763
+ ...defaultConfig$3,
764
+ ...config
765
+ };
766
+ return /*#__PURE__*/React__default.createElement(ConexysConfigContext.Provider, {
767
+ value: mergedConfig
768
+ }, children);
769
+ };
770
+ const useConexysConfig = () => {
771
+ return useContext(ConexysConfigContext);
772
+ };
773
+ const isDevelopmentMode = config => {
774
+ return config.developmentMode;
775
+ };
776
+
777
+ const config$3 = {
778
+ headers: {
779
+ 'Content-Type': 'application/json'
780
+ }
781
+ };
782
+ function AppDataSettings({
783
+ keys
784
+ }) {
785
+ const configLogs = useConexysConfig();
786
+ const postURL = Url + 'getsettings';
787
+ const [post, setPost] = useState(null);
788
+ const [error, setError] = useState(false);
789
+ const hasFetched = useRef(false);
790
+ const fetchData = useCallback(async () => {
791
+ if (hasFetched.current) return;
792
+ hasFetched.current = true;
793
+ try {
794
+ await serviceData(postURL, {
795
+ keys: keys
796
+ }, config$3, setPost, configLogs);
797
+ } catch (err) {
798
+ setError(true);
799
+ logConsole(configLogs, 'error', 'Error fetching data:', err);
800
+ console.error('Error fetching data:', err);
801
+ }
802
+ }, []);
803
+ useEffect(() => {
804
+ fetchData();
805
+ }, [fetchData]);
806
+ if (!post) return null;
807
+ return /*#__PURE__*/React__default.createElement(React__default.Fragment, null, error ? /*#__PURE__*/React__default.createElement("div", null, "Error loading data") : post);
808
+ }
809
+
810
+ /*! @license DOMPurify 3.4.14 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.14/LICENSE */
811
+
812
+ function _arrayLikeToArray(r, a) {
813
+ (null == a || a > r.length) && (a = r.length);
814
+ for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
815
+ return n;
816
+ }
817
+ function _arrayWithHoles(r) {
818
+ if (Array.isArray(r)) return r;
819
+ }
820
+ function _iterableToArrayLimit(r, l) {
821
+ var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
822
+ if (null != t) {
823
+ var e,
824
+ n,
825
+ i,
826
+ u,
827
+ a = [],
828
+ f = true,
829
+ o = false;
830
+ try {
831
+ if (i = (t = t.call(r)).next, 0 === l) ; else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);
832
+ } catch (r) {
833
+ o = true, n = r;
834
+ } finally {
835
+ try {
836
+ if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return;
837
+ } finally {
838
+ if (o) throw n;
839
+ }
840
+ }
841
+ return a;
842
+ }
843
+ }
844
+ function _nonIterableRest() {
845
+ throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
846
+ }
847
+ function _slicedToArray(r, e) {
848
+ return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest();
849
+ }
850
+ function _unsupportedIterableToArray(r, a) {
851
+ if (r) {
852
+ if ("string" == typeof r) return _arrayLikeToArray(r, a);
853
+ var t = {}.toString.call(r).slice(8, -1);
854
+ return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
855
+ }
856
+ }
857
+
858
+ const entries = Object.entries,
859
+ setPrototypeOf = Object.setPrototypeOf,
860
+ isFrozen = Object.isFrozen,
861
+ getPrototypeOf = Object.getPrototypeOf,
862
+ getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
863
+ let freeze = Object.freeze,
864
+ seal = Object.seal,
865
+ create = Object.create; // eslint-disable-line import/no-mutable-exports
866
+ let _ref = typeof Reflect !== 'undefined' && Reflect,
867
+ apply = _ref.apply,
868
+ construct = _ref.construct;
869
+ if (!freeze) {
870
+ freeze = function freeze(x) {
871
+ return x;
872
+ };
873
+ }
874
+ if (!seal) {
875
+ seal = function seal(x) {
876
+ return x;
877
+ };
878
+ }
879
+ if (!apply) {
880
+ apply = function apply(func, thisArg) {
881
+ for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
882
+ args[_key - 2] = arguments[_key];
883
+ }
884
+ return func.apply(thisArg, args);
885
+ };
886
+ }
887
+ if (!construct) {
888
+ construct = function construct(Func) {
889
+ for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
890
+ args[_key2 - 1] = arguments[_key2];
891
+ }
892
+ return new Func(...args);
893
+ };
894
+ }
895
+ const arrayForEach = unapply(Array.prototype.forEach);
896
+ const arrayLastIndexOf = unapply(Array.prototype.lastIndexOf);
897
+ const arrayPop = unapply(Array.prototype.pop);
898
+ const arrayPush = unapply(Array.prototype.push);
899
+ const arraySplice = unapply(Array.prototype.splice);
900
+ const arrayIsArray = Array.isArray;
901
+ const stringToLowerCase = unapply(String.prototype.toLowerCase);
902
+ const stringToString = unapply(String.prototype.toString);
903
+ const stringMatch = unapply(String.prototype.match);
904
+ const stringReplace = unapply(String.prototype.replace);
905
+ const stringIndexOf = unapply(String.prototype.indexOf);
906
+ const stringTrim = unapply(String.prototype.trim);
907
+ const numberToString = unapply(Number.prototype.toString);
908
+ const booleanToString = unapply(Boolean.prototype.toString);
909
+ const bigintToString = typeof BigInt === 'undefined' ? null : unapply(BigInt.prototype.toString);
910
+ const symbolToString = typeof Symbol === 'undefined' ? null : unapply(Symbol.prototype.toString);
911
+ const objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty);
912
+ const objectToString = unapply(Object.prototype.toString);
913
+ const regExpTest = unapply(RegExp.prototype.test);
914
+ const typeErrorCreate = unconstruct(TypeError);
915
+ /**
916
+ * Creates a new function that calls the given function with a specified thisArg and arguments.
917
+ *
918
+ * @param func - The function to be wrapped and called.
919
+ * @returns A new function that calls the given function with a specified thisArg and arguments.
920
+ */
921
+ function unapply(func) {
922
+ return function (thisArg) {
923
+ if (thisArg instanceof RegExp) {
924
+ thisArg.lastIndex = 0;
925
+ }
926
+ for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
927
+ args[_key3 - 1] = arguments[_key3];
928
+ }
929
+ return apply(func, thisArg, args);
930
+ };
931
+ }
932
+ /**
933
+ * Creates a new function that constructs an instance of the given constructor function with the provided arguments.
934
+ *
935
+ * @param func - The constructor function to be wrapped and called.
936
+ * @returns A new function that constructs an instance of the given constructor function with the provided arguments.
937
+ */
938
+ function unconstruct(Func) {
939
+ return function () {
940
+ for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {
941
+ args[_key4] = arguments[_key4];
942
+ }
943
+ return construct(Func, args);
944
+ };
945
+ }
946
+ /**
947
+ * Add properties to a lookup table
948
+ *
949
+ * @param set - The set to which elements will be added.
950
+ * @param array - The array containing elements to be added to the set.
951
+ * @param transformCaseFunc - An optional function to transform the case of each element before adding to the set.
952
+ * @returns The modified set with added elements.
953
+ */
954
+ function addToSet(set, array) {
955
+ let transformCaseFunc = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : stringToLowerCase;
956
+ if (setPrototypeOf) {
957
+ // Make 'in' and truthy checks like Boolean(set.constructor)
958
+ // independent of any properties defined on Object.prototype.
959
+ // Prevent prototype setters from intercepting set as a this value.
960
+ setPrototypeOf(set, null);
961
+ }
962
+ if (!arrayIsArray(array)) {
963
+ return set;
964
+ }
965
+ let l = array.length;
966
+ while (l--) {
967
+ let element = array[l];
968
+ if (typeof element === 'string') {
969
+ const lcElement = transformCaseFunc(element);
970
+ if (lcElement !== element) {
971
+ // Config presets (e.g. tags.js, attrs.js) are immutable.
972
+ if (!isFrozen(array)) {
973
+ array[l] = lcElement;
974
+ }
975
+ element = lcElement;
976
+ }
977
+ }
978
+ set[element] = true;
979
+ }
980
+ return set;
981
+ }
982
+ /**
983
+ * Clean up an array to harden against CSPP
984
+ *
985
+ * @param array - The array to be cleaned.
986
+ * @returns The cleaned version of the array
987
+ */
988
+ function cleanArray(array) {
989
+ for (let index = 0; index < array.length; index++) {
990
+ const isPropertyExist = objectHasOwnProperty(array, index);
991
+ if (!isPropertyExist) {
992
+ array[index] = null;
993
+ }
994
+ }
995
+ return array;
996
+ }
997
+ /**
998
+ * Shallow clone an object
999
+ *
1000
+ * @param object - The object to be cloned.
1001
+ * @returns A new object that copies the original.
1002
+ */
1003
+ function clone(object) {
1004
+ const newObject = create(null);
1005
+ for (const _ref2 of entries(object)) {
1006
+ var _ref3 = _slicedToArray(_ref2, 2);
1007
+ const property = _ref3[0];
1008
+ const value = _ref3[1];
1009
+ const isPropertyExist = objectHasOwnProperty(object, property);
1010
+ if (isPropertyExist) {
1011
+ if (arrayIsArray(value)) {
1012
+ newObject[property] = cleanArray(value);
1013
+ } else if (value && typeof value === 'object' && value.constructor === Object) {
1014
+ newObject[property] = clone(value);
1015
+ } else {
1016
+ newObject[property] = value;
1017
+ }
1018
+ }
1019
+ }
1020
+ return newObject;
1021
+ }
1022
+ /**
1023
+ * Convert non-node values into strings without depending on direct property access.
1024
+ *
1025
+ * @param value - The value to stringify.
1026
+ * @returns A string representation of the provided value.
1027
+ */
1028
+ function stringifyValue(value) {
1029
+ switch (typeof value) {
1030
+ case 'string':
1031
+ {
1032
+ return value;
1033
+ }
1034
+ case 'number':
1035
+ {
1036
+ return numberToString(value);
1037
+ }
1038
+ case 'boolean':
1039
+ {
1040
+ return booleanToString(value);
1041
+ }
1042
+ case 'bigint':
1043
+ {
1044
+ return bigintToString ? bigintToString(value) : '0';
1045
+ }
1046
+ case 'symbol':
1047
+ {
1048
+ return symbolToString ? symbolToString(value) : 'Symbol()';
1049
+ }
1050
+ case 'undefined':
1051
+ {
1052
+ return objectToString(value);
1053
+ }
1054
+ case 'function':
1055
+ case 'object':
1056
+ {
1057
+ if (value === null) {
1058
+ return objectToString(value);
1059
+ }
1060
+ const valueAsRecord = value;
1061
+ const valueToString = lookupGetter(valueAsRecord, 'toString');
1062
+ if (typeof valueToString === 'function') {
1063
+ const stringified = valueToString(valueAsRecord);
1064
+ return typeof stringified === 'string' ? stringified : objectToString(stringified);
1065
+ }
1066
+ return objectToString(value);
1067
+ }
1068
+ default:
1069
+ {
1070
+ return objectToString(value);
1071
+ }
1072
+ }
1073
+ }
1074
+ /**
1075
+ * This method automatically checks if the prop is function or getter and behaves accordingly.
1076
+ *
1077
+ * @param object - The object to look up the getter function in its prototype chain.
1078
+ * @param prop - The property name for which to find the getter function.
1079
+ * @returns The getter function found in the prototype chain or a fallback function.
1080
+ */
1081
+ function lookupGetter(object, prop) {
1082
+ while (object !== null) {
1083
+ const desc = getOwnPropertyDescriptor(object, prop);
1084
+ if (desc) {
1085
+ if (desc.get) {
1086
+ return unapply(desc.get);
1087
+ }
1088
+ if (typeof desc.value === 'function') {
1089
+ return unapply(desc.value);
1090
+ }
1091
+ }
1092
+ object = getPrototypeOf(object);
1093
+ }
1094
+ function fallbackValue() {
1095
+ return null;
1096
+ }
1097
+ return fallbackValue;
1098
+ }
1099
+ function isRegex(value) {
1100
+ try {
1101
+ regExpTest(value, '');
1102
+ return true;
1103
+ } catch (_unused) {
1104
+ return false;
1105
+ }
1106
+ }
1107
+
1108
+ const html$1 = freeze(['a', 'abbr', 'acronym', 'address', 'area', 'article', 'aside', 'audio', 'b', 'bdi', 'bdo', 'big', 'blink', 'blockquote', 'body', 'br', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'content', 'data', 'datalist', 'dd', 'decorator', 'del', 'details', 'dfn', 'dialog', 'dir', 'div', 'dl', 'dt', 'element', 'em', 'fieldset', 'figcaption', 'figure', 'font', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'i', 'img', 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'main', 'map', 'mark', 'marquee', 'menu', 'menuitem', 'meter', 'nav', 'nobr', 'ol', 'optgroup', 'option', 'output', 'p', 'picture', 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'search', 'section', 'select', 'shadow', 'slot', 'small', 'source', 'spacer', 'span', 'strike', 'strong', 'style', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th', 'thead', 'time', 'tr', 'track', 'tt', 'u', 'ul', 'var', 'video', 'wbr']);
1109
+ const svg$1 = freeze(['svg', 'a', 'altglyph', 'altglyphdef', 'altglyphitem', 'animatecolor', 'animatemotion', 'animatetransform', 'circle', 'clippath', 'defs', 'desc', 'ellipse', 'enterkeyhint', 'exportparts', 'filter', 'font', 'g', 'glyph', 'glyphref', 'hkern', 'image', 'inputmode', 'line', 'lineargradient', 'marker', 'mask', 'metadata', 'mpath', 'part', 'path', 'pattern', 'polygon', 'polyline', 'radialgradient', 'rect', 'stop', 'style', 'switch', 'symbol', 'text', 'textpath', 'title', 'tref', 'tspan', 'view', 'vkern']);
1110
+ const svgFilters = freeze(['feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feDropShadow', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feImage', 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence']);
1111
+ // List of SVG elements that are disallowed by default.
1112
+ // We still need to know them so that we can do namespace
1113
+ // checks properly in case one wants to add them to
1114
+ // allow-list.
1115
+ const svgDisallowed = freeze(['animate', 'color-profile', 'cursor', 'discard', 'font-face', 'font-face-format', 'font-face-name', 'font-face-src', 'font-face-uri', 'foreignobject', 'hatch', 'hatchpath', 'mesh', 'meshgradient', 'meshpatch', 'meshrow', 'missing-glyph', 'script', 'set', 'solidcolor', 'unknown', 'use']);
1116
+ const mathMl$1 = freeze(['math', 'menclose', 'merror', 'mfenced', 'mfrac', 'mglyph', 'mi', 'mlabeledtr', 'mmultiscripts', 'mn', 'mo', 'mover', 'mpadded', 'mphantom', 'mroot', 'mrow', 'ms', 'mspace', 'msqrt', 'mstyle', 'msub', 'msup', 'msubsup', 'mtable', 'mtd', 'mtext', 'mtr', 'munder', 'munderover', 'mprescripts']);
1117
+ // Similarly to SVG, we want to know all MathML elements,
1118
+ // even those that we disallow by default.
1119
+ const mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'none']);
1120
+ const text = freeze(['#text']);
1121
+
1122
+ const html = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'command', 'commandfor', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'exportparts', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inert', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'nonce', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'part', 'pattern', 'placeholder', 'playsinline', 'popover', 'popovertarget', 'popovertargetaction', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'slot', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'wrap', 'xmlns']);
1123
+ const svg = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'amplitude', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clippathunits', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cx', 'cy', 'd', 'dx', 'dy', 'diffuseconstant', 'direction', 'display', 'divisor', 'dominant-baseline', 'dur', 'edgemode', 'elevation', 'end', 'exponent', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'filterunits', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'glyphref', 'gradientunits', 'gradienttransform', 'height', 'href', 'id', 'image-rendering', 'in', 'in2', 'intercept', 'k', 'k1', 'k2', 'k3', 'k4', 'kerning', 'keypoints', 'keysplines', 'keytimes', 'lang', 'lengthadjust', 'letter-spacing', 'kernelmatrix', 'kernelunitlength', 'lighting-color', 'local', 'marker-end', 'marker-mid', 'marker-start', 'markerheight', 'markerunits', 'markerwidth', 'maskcontentunits', 'maskunits', 'max', 'mask', 'mask-type', 'media', 'method', 'mode', 'min', 'name', 'numoctaves', 'offset', 'operator', 'opacity', 'order', 'orient', 'orientation', 'origin', 'overflow', 'paint-order', 'path', 'pathlength', 'patterncontentunits', 'patterntransform', 'patternunits', 'pointer-events', 'points', 'preservealpha', 'preserveaspectratio', 'primitiveunits', 'r', 'rx', 'ry', 'radius', 'refx', 'refy', 'repeatcount', 'repeatdur', 'restart', 'result', 'rotate', 'scale', 'seed', 'shape-rendering', 'slope', 'specularconstant', 'specularexponent', 'spreadmethod', 'startoffset', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'systemlanguage', 'tabindex', 'tablevalues', 'targetx', 'targety', 'transform', 'transform-origin', 'text-anchor', 'text-decoration', 'text-orientation', 'text-rendering', 'textlength', 'type', 'u1', 'u2', 'unicode', 'values', 'vector-effect', 'viewbox', 'visibility', 'version', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'width', 'word-spacing', 'wrap', 'writing-mode', 'xchannelselector', 'ychannelselector', 'x', 'x1', 'x2', 'xmlns', 'y', 'y1', 'y2', 'z', 'zoomandpan']);
1124
+ const mathMl = freeze(['accent', 'accentunder', 'align', 'bevelled', 'close', 'columnalign', 'columnlines', 'columnspacing', 'columnspan', 'denomalign', 'depth', 'dir', 'display', 'displaystyle', 'encoding', 'fence', 'frame', 'height', 'href', 'id', 'largeop', 'length', 'linethickness', 'lquote', 'lspace', 'mathbackground', 'mathcolor', 'mathsize', 'mathvariant', 'maxsize', 'minsize', 'movablelimits', 'notation', 'numalign', 'open', 'rowalign', 'rowlines', 'rowspacing', 'rowspan', 'rspace', 'rquote', 'scriptlevel', 'scriptminsize', 'scriptsizemultiplier', 'selection', 'separator', 'separators', 'stretchy', 'subscriptshift', 'supscriptshift', 'symmetric', 'voffset', 'width', 'xmlns']);
1125
+ const xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);
1126
+
1127
+ const MUSTACHE_EXPR = seal(/{{[\w\W]*|^[\w\W]*}}/g);
1128
+ const ERB_EXPR = seal(/<%[\w\W]*|^[\w\W]*%>/g);
1129
+ const TMPLIT_EXPR = seal(/\${[\w\W]*/g);
1130
+ const DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]+$/); // eslint-disable-line no-useless-escape
1131
+ const ARIA_ATTR = seal(/^aria-[\-\w]+$/); // eslint-disable-line no-useless-escape
1132
+ const IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i // eslint-disable-line no-useless-escape
1133
+ );
1134
+ const IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i);
1135
+ const ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g // eslint-disable-line no-control-regex
1136
+ );
1137
+ const DOCTYPE_NAME = seal(/^html$/i);
1138
+ const CUSTOM_ELEMENT = seal(/^[a-z][.\w]*(-[.\w]+)+$/i);
1139
+ // Markup-significant character probes used by _sanitizeElements.
1140
+ // Shared module-level instances are safe despite the sticky /g flags:
1141
+ // unapply() resets lastIndex for RegExp receivers before every call.
1142
+ const ELEMENT_MARKUP_PROBE = seal(/<[/\w!]/g);
1143
+ const COMMENT_MARKUP_PROBE = seal(/<[/\w]/g);
1144
+ const FALLBACK_TAG_CLOSE = seal(/<\/no(script|embed|frames)/i);
1145
+ const SELF_CLOSING_TAG = seal(/\/>/i);
1146
+
1147
+ // https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
1148
+ const NODE_TYPE = {
1149
+ element: 1,
1150
+ attribute: 2,
1151
+ text: 3,
1152
+ cdataSection: 4,
1153
+ entityReference: 5,
1154
+ // Deprecated
1155
+ entityNode: 6,
1156
+ // Deprecated
1157
+ processingInstruction: 7,
1158
+ comment: 8,
1159
+ document: 9,
1160
+ documentType: 10,
1161
+ documentFragment: 11,
1162
+ notation: 12 // Deprecated
1163
+ };
1164
+ /* HTML-namespace elements whose child text nodes are serialized *literally*
1165
+ (unescaped) by the HTML fragment-serialization algorithm. Two reparse-mXSS
1166
+ shapes ride on that literal serialization:
1167
+ (a) an element child - a tree the HTML parser can never build, but the DOM
1168
+ API and an XML/XHTML parse can - after which a `</tag>`-bearing text
1169
+ sibling breaks the element open on reparse; and
1170
+ (b) text-only content that already carries the element's OWN end tag, e.g.
1171
+ `<style>...</style><img onerror=x>` built as a node, which the literal
1172
+ serializer emits verbatim for the HTML parser to re-open.
1173
+ Shape (a) is handled by the firstElementChild branch in _isUnsafeNode; shape
1174
+ (b) by the LITERAL_TEXT_CLOSE probe. Both read textContent (the raw-serialized
1175
+ form for these elements) rather than innerHTML, because an XML/XHTML working
1176
+ document serializes innerHTML with `<` escaped, which silently blinds the
1177
+ innerHTML-based probes (rule 1's second probe and FALLBACK_TAG_CLOSE) there.
1178
+ `script` is never allow-listed, but is kept here so the guard matches the
1179
+ serializer's own literal-text list exactly. */
1180
+ const LITERAL_TEXT_ELEMENT_NAMES = ['style', 'script', 'xmp', 'iframe', 'noembed', 'noframes', 'plaintext', 'noscript'];
1181
+ const LITERAL_TEXT_ELEMENTS = freeze(addToSet({}, LITERAL_TEXT_ELEMENT_NAMES));
1182
+ /* Per-element end-tag matcher. On an HTML reparse the ONLY token that
1183
+ terminates a literal-text element's raw content is its own end tag; a foreign
1184
+ literal-text close (e.g. `</xmp>` sitting inside `<style>`) does not break
1185
+ out, so matching is per-element, not a shared alternation. The lookahead
1186
+ requires an HTML tag-name terminator (whitespace, `/` or `>`) so a longer
1187
+ name such as `</styles` is not mistaken for `</style`. */
1188
+ const LITERAL_TEXT_CLOSE = function () {
1189
+ const map = {};
1190
+ arrayForEach(LITERAL_TEXT_ELEMENT_NAMES, name => {
1191
+ map[name] = seal(new RegExp('</' + name + '(?=[\\t\\n\\f\\r />])', 'i'));
1192
+ });
1193
+ return freeze(map);
1194
+ }();
1195
+ const getGlobal = function getGlobal() {
1196
+ return typeof window === 'undefined' ? null : window;
1197
+ };
1198
+ /**
1199
+ * Creates a no-op policy for internal use only.
1200
+ * Don't export this function outside this module!
1201
+ * @param trustedTypes The policy factory.
1202
+ * @param purifyHostElement The Script element used to load DOMPurify (to determine policy name suffix).
1203
+ * @return The policy created (or null, if Trusted Types
1204
+ * are not supported or creating the policy failed).
1205
+ */
1206
+ const _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, purifyHostElement) {
1207
+ if (typeof trustedTypes !== 'object' || typeof trustedTypes.createPolicy !== 'function') {
1208
+ return null;
1209
+ }
1210
+ // Allow the callers to control the unique policy name
1211
+ // by adding a data-tt-policy-suffix to the script element with the DOMPurify.
1212
+ // Policy creation with duplicate names throws in Trusted Types.
1213
+ let suffix = null;
1214
+ const ATTR_NAME = 'data-tt-policy-suffix';
1215
+ if (purifyHostElement && purifyHostElement.hasAttribute(ATTR_NAME)) {
1216
+ suffix = purifyHostElement.getAttribute(ATTR_NAME);
1217
+ }
1218
+ const policyName = 'dompurify' + (suffix ? '#' + suffix : '');
1219
+ try {
1220
+ return trustedTypes.createPolicy(policyName, {
1221
+ createHTML(html) {
1222
+ return html;
1223
+ },
1224
+ createScriptURL(scriptUrl) {
1225
+ return scriptUrl;
1226
+ }
1227
+ });
1228
+ } catch (_) {
1229
+ // Policy creation failed (most likely another DOMPurify script has
1230
+ // already run). Skip creating the policy, as this will only cause errors
1231
+ // if TT are enforced.
1232
+ console.warn('TrustedTypes policy ' + policyName + ' could not be created.');
1233
+ return null;
1234
+ }
1235
+ };
1236
+ const _createHooksMap = function _createHooksMap() {
1237
+ return {
1238
+ afterSanitizeAttributes: [],
1239
+ afterSanitizeElements: [],
1240
+ afterSanitizeShadowDOM: [],
1241
+ beforeSanitizeAttributes: [],
1242
+ beforeSanitizeElements: [],
1243
+ beforeSanitizeShadowDOM: [],
1244
+ uponSanitizeAttribute: [],
1245
+ uponSanitizeElement: [],
1246
+ uponSanitizeShadowNode: []
1247
+ };
1248
+ };
1249
+ /**
1250
+ * Resolve a set-valued configuration option: a fresh set built from
1251
+ * cfg[key] when it is an own array property (seeded with a clone of
1252
+ * options.base when given, case-normalized via options.transform),
1253
+ * the fallback set otherwise.
1254
+ *
1255
+ * @param cfg the cloned, prototype-free configuration object
1256
+ * @param key the configuration property to read
1257
+ * @param fallback the set to use when the option is absent or not an array
1258
+ * @param options transform and optional base set to merge into
1259
+ * @returns the resolved set
1260
+ */
1261
+ const _resolveSetOption = function _resolveSetOption(cfg, key, fallback, options) {
1262
+ return objectHasOwnProperty(cfg, key) && arrayIsArray(cfg[key]) ? addToSet(options.base ? clone(options.base) : {}, cfg[key], options.transform) : fallback;
1263
+ };
1264
+ /**
1265
+ * Resolve an object-valued configuration option: a prototype-free clone
1266
+ * of cfg[key] when it is an own, truthy object property, else a fresh
1267
+ * fallback built by makeFallback (fresh on every parse, so a previous
1268
+ * parse can never leak state into the next one).
1269
+ *
1270
+ * @param cfg the cloned, prototype-free configuration object
1271
+ * @param key the configuration property to read
1272
+ * @param makeFallback builds the fallback value when the option is absent
1273
+ * @returns the resolved object
1274
+ */
1275
+ const _resolveObjectOption = function _resolveObjectOption(cfg, key, makeFallback) {
1276
+ const value = objectHasOwnProperty(cfg, key) ? cfg[key] : undefined;
1277
+ return value && typeof value === 'object' ? clone(value) : makeFallback();
1278
+ };
1279
+ function createDOMPurify() {
1280
+ let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
1281
+ const DOMPurify = root => createDOMPurify(root);
1282
+ DOMPurify.version = '3.4.14';
1283
+ DOMPurify.removed = [];
1284
+ if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document || !window.Element) {
1285
+ // Not running in a browser, provide a factory function
1286
+ // so that you can pass your own Window
1287
+ DOMPurify.isSupported = false;
1288
+ return DOMPurify;
1289
+ }
1290
+ let document = window.document;
1291
+ const originalDocument = document;
1292
+ const currentScript = originalDocument.currentScript;
1293
+ window.DocumentFragment;
1294
+ const HTMLTemplateElement = window.HTMLTemplateElement,
1295
+ Node = window.Node,
1296
+ Element = window.Element,
1297
+ NodeFilter = window.NodeFilter,
1298
+ _window$NamedNodeMap = window.NamedNodeMap;
1299
+ _window$NamedNodeMap === void 0 ? window.NamedNodeMap || window.MozNamedAttrMap : _window$NamedNodeMap;
1300
+ window.HTMLFormElement;
1301
+ const DOMParser = window.DOMParser,
1302
+ trustedTypes = window.trustedTypes;
1303
+ const ElementPrototype = Element.prototype;
1304
+ const cloneNode = lookupGetter(ElementPrototype, 'cloneNode');
1305
+ const remove = lookupGetter(ElementPrototype, 'remove');
1306
+ const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');
1307
+ const getChildNodes = lookupGetter(ElementPrototype, 'childNodes');
1308
+ const getParentNode = lookupGetter(ElementPrototype, 'parentNode');
1309
+ const getShadowRoot = lookupGetter(ElementPrototype, 'shadowRoot');
1310
+ const getAttributes = lookupGetter(ElementPrototype, 'attributes');
1311
+ const getNodeType = Node && Node.prototype ? lookupGetter(Node.prototype, 'nodeType') : null;
1312
+ const getNodeName = Node && Node.prototype ? lookupGetter(Node.prototype, 'nodeName') : null;
1313
+ const getOwnerDocument = Node && Node.prototype ? lookupGetter(Node.prototype, 'ownerDocument') : null;
1314
+ /* Clobber-safe nodeType / nodeName reads through the cached Node.prototype
1315
+ getters, with a direct-property fallback for environments that lack
1316
+ Node.prototype. Sites that need a different fallback (e.g. _isClobbered
1317
+ returns early on a null name) intentionally keep their own reads. */
1318
+ const _readNodeType = function _readNodeType(node) {
1319
+ return getNodeType ? getNodeType(node) : node.nodeType;
1320
+ };
1321
+ const _readNodeName = function _readNodeName(node) {
1322
+ return getNodeName ? getNodeName(node) : node.nodeName;
1323
+ };
1324
+ // As per issue #47, the web-components registry is inherited by a
1325
+ // new document created via createHTMLDocument. As per the spec
1326
+ // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)
1327
+ // a new empty registry is used when creating a template contents owner
1328
+ // document, so we use that as our parent document to ensure nothing
1329
+ // is inherited.
1330
+ if (typeof HTMLTemplateElement === 'function') {
1331
+ const template = document.createElement('template');
1332
+ if (template.content && template.content.ownerDocument) {
1333
+ document = template.content.ownerDocument;
1334
+ }
1335
+ }
1336
+ let trustedTypesPolicy;
1337
+ let emptyHTML = '';
1338
+ // The instance's own internal Trusted Types policy. Unlike a caller-supplied
1339
+ // `TRUSTED_TYPES_POLICY`, this is created at most once — Trusted Types throws
1340
+ // on duplicate policy names — and is the only policy allowed to persist
1341
+ // across configurations and survive `clearConfig()`.
1342
+ let defaultTrustedTypesPolicy;
1343
+ let defaultTrustedTypesPolicyResolved = false;
1344
+ // Tracks whether we are already inside a call to the configured Trusted Types
1345
+ // policy (`createHTML` or `createScriptURL`). If a supplied policy callback
1346
+ // itself calls `DOMPurify.sanitize` (the cause of #1422), `sanitize` would
1347
+ // re-enter the policy and recurse until the stack overflows. We detect that
1348
+ // re-entry and throw a clear, actionable error instead. The guard is shared
1349
+ // across both callbacks, because either one re-entering `sanitize` triggers
1350
+ // the same unbounded recursion.
1351
+ let IN_TRUSTED_TYPES_POLICY = 0;
1352
+ const _assertNotInTrustedTypesPolicy = function _assertNotInTrustedTypesPolicy() {
1353
+ if (IN_TRUSTED_TYPES_POLICY > 0) {
1354
+ throw typeErrorCreate('A configured TRUSTED_TYPES_POLICY callback (createHTML or ' + 'createScriptURL) must not call DOMPurify.sanitize, as that causes ' + 'infinite recursion. Do not pass a policy whose callbacks wrap ' + 'DOMPurify as TRUSTED_TYPES_POLICY; see the "DOMPurify and Trusted ' + 'Types" section of the README.');
1355
+ }
1356
+ };
1357
+ const _createTrustedHTML = function _createTrustedHTML(html) {
1358
+ _assertNotInTrustedTypesPolicy();
1359
+ IN_TRUSTED_TYPES_POLICY++;
1360
+ try {
1361
+ return trustedTypesPolicy.createHTML(html);
1362
+ } finally {
1363
+ IN_TRUSTED_TYPES_POLICY--;
1364
+ }
1365
+ };
1366
+ const _createTrustedScriptURL = function _createTrustedScriptURL(scriptUrl) {
1367
+ _assertNotInTrustedTypesPolicy();
1368
+ IN_TRUSTED_TYPES_POLICY++;
1369
+ try {
1370
+ return trustedTypesPolicy.createScriptURL(scriptUrl);
1371
+ } finally {
1372
+ IN_TRUSTED_TYPES_POLICY--;
1373
+ }
1374
+ };
1375
+ // Lazily resolve (and cache) the instance's internal default policy.
1376
+ // Resolution is attempted at most once: a successful `createPolicy` cannot be
1377
+ // repeated (Trusted Types throws on duplicate names), and a failed or
1378
+ // unsupported attempt must not be retried on every parse.
1379
+ const _getDefaultTrustedTypesPolicy = function _getDefaultTrustedTypesPolicy() {
1380
+ if (!defaultTrustedTypesPolicyResolved) {
1381
+ defaultTrustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, currentScript);
1382
+ defaultTrustedTypesPolicyResolved = true;
1383
+ }
1384
+ return defaultTrustedTypesPolicy;
1385
+ };
1386
+ const _document = document,
1387
+ implementation = _document.implementation,
1388
+ createNodeIterator = _document.createNodeIterator,
1389
+ createDocumentFragment = _document.createDocumentFragment,
1390
+ getElementsByTagName = _document.getElementsByTagName;
1391
+ const importNode = originalDocument.importNode;
1392
+ let hooks = _createHooksMap();
1393
+ /**
1394
+ * Expose whether this browser supports running the full DOMPurify.
1395
+ */
1396
+ DOMPurify.isSupported = typeof entries === 'function' && typeof getParentNode === 'function' && implementation && implementation.createHTMLDocument !== undefined;
1397
+ const MUSTACHE_EXPR$1 = MUSTACHE_EXPR,
1398
+ ERB_EXPR$1 = ERB_EXPR,
1399
+ TMPLIT_EXPR$1 = TMPLIT_EXPR,
1400
+ DATA_ATTR$1 = DATA_ATTR,
1401
+ ARIA_ATTR$1 = ARIA_ATTR,
1402
+ IS_SCRIPT_OR_DATA$1 = IS_SCRIPT_OR_DATA,
1403
+ ATTR_WHITESPACE$1 = ATTR_WHITESPACE,
1404
+ CUSTOM_ELEMENT$1 = CUSTOM_ELEMENT;
1405
+ let IS_ALLOWED_URI$1 = IS_ALLOWED_URI;
1406
+ /**
1407
+ * We consider the elements and attributes below to be safe. Ideally
1408
+ * don't add any new ones but feel free to remove unwanted ones.
1409
+ */
1410
+ /* allowed element names */
1411
+ let ALLOWED_TAGS = null;
1412
+ const DEFAULT_ALLOWED_TAGS = addToSet({}, [...html$1, ...svg$1, ...svgFilters, ...mathMl$1, ...text]);
1413
+ /* Allowed attribute names */
1414
+ let ALLOWED_ATTR = null;
1415
+ const DEFAULT_ALLOWED_ATTR = addToSet({}, [...html, ...svg, ...mathMl, ...xml]);
1416
+ /*
1417
+ * Configure how DOMPurify should handle custom elements and their attributes as well as customized built-in elements.
1418
+ * @property {RegExp|Function|null} tagNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any custom elements)
1419
+ * @property {RegExp|Function|null} attributeNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any attributes not on the allow list)
1420
+ * @property {boolean} allowCustomizedBuiltInElements allow custom elements derived from built-ins if they pass CUSTOM_ELEMENT_HANDLING.tagNameCheck. Default: `false`.
1421
+ */
1422
+ let CUSTOM_ELEMENT_HANDLING = Object.seal(create(null, {
1423
+ tagNameCheck: {
1424
+ writable: true,
1425
+ configurable: false,
1426
+ enumerable: true,
1427
+ value: null
1428
+ },
1429
+ attributeNameCheck: {
1430
+ writable: true,
1431
+ configurable: false,
1432
+ enumerable: true,
1433
+ value: null
1434
+ },
1435
+ allowCustomizedBuiltInElements: {
1436
+ writable: true,
1437
+ configurable: false,
1438
+ enumerable: true,
1439
+ value: false
1440
+ }
1441
+ }));
1442
+ /* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */
1443
+ let FORBID_TAGS = null;
1444
+ /* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */
1445
+ let FORBID_ATTR = null;
1446
+ /* Config object to store ADD_TAGS/ADD_ATTR functions (when used as functions) */
1447
+ const EXTRA_ELEMENT_HANDLING = Object.seal(create(null, {
1448
+ tagCheck: {
1449
+ writable: true,
1450
+ configurable: false,
1451
+ enumerable: true,
1452
+ value: null
1453
+ },
1454
+ attributeCheck: {
1455
+ writable: true,
1456
+ configurable: false,
1457
+ enumerable: true,
1458
+ value: null
1459
+ }
1460
+ }));
1461
+ /* Decide if ARIA attributes are okay */
1462
+ let ALLOW_ARIA_ATTR = true;
1463
+ /* Decide if custom data attributes are okay */
1464
+ let ALLOW_DATA_ATTR = true;
1465
+ /* Decide if unknown protocols are okay */
1466
+ let ALLOW_UNKNOWN_PROTOCOLS = false;
1467
+ /* Decide if self-closing tags in attributes are allowed.
1468
+ * Usually removed due to a mXSS issue in jQuery 3.0 */
1469
+ let ALLOW_SELF_CLOSE_IN_ATTR = true;
1470
+ /* Output should be safe for common template engines.
1471
+ * This means, DOMPurify removes data attributes, mustaches and ERB
1472
+ */
1473
+ let SAFE_FOR_TEMPLATES = false;
1474
+ /* Output should be safe even for XML used within HTML and alike.
1475
+ * This means, DOMPurify removes comments when containing risky content.
1476
+ */
1477
+ let SAFE_FOR_XML = true;
1478
+ /* Decide if document with <html>... should be returned */
1479
+ let WHOLE_DOCUMENT = false;
1480
+ /* Track whether config is already set on this instance of DOMPurify. */
1481
+ let SET_CONFIG = false;
1482
+ /* Pristine allowlist bindings captured at setConfig() time. On the
1483
+ * persistent-config path sanitize() restores the sets from these before
1484
+ * the per-walk hook clone-guard, so a hook's in-call widening cannot
1485
+ * carry across calls. Null until setConfig() is called; reset by
1486
+ * clearConfig(). */
1487
+ let SET_CONFIG_ALLOWED_TAGS = null;
1488
+ let SET_CONFIG_ALLOWED_ATTR = null;
1489
+ /* Decide if all elements (e.g. style, script) must be children of
1490
+ * document.body. By default, browsers might move them to document.head */
1491
+ let FORCE_BODY = false;
1492
+ /* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html
1493
+ * string (or a TrustedHTML object if Trusted Types are supported).
1494
+ * If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead
1495
+ */
1496
+ let RETURN_DOM = false;
1497
+ /* Decide if a DOM `DocumentFragment` should be returned, instead of a html
1498
+ * string (or a TrustedHTML object if Trusted Types are supported) */
1499
+ let RETURN_DOM_FRAGMENT = false;
1500
+ /* Try to return a Trusted Type object instead of a string, return a string in
1501
+ * case Trusted Types are not supported */
1502
+ let RETURN_TRUSTED_TYPE = false;
1503
+ /* Output should be free from DOM clobbering attacks?
1504
+ * This sanitizes markups named with colliding, clobberable built-in DOM APIs.
1505
+ */
1506
+ let SANITIZE_DOM = true;
1507
+ /* Achieve full DOM Clobbering protection by isolating the namespace of named
1508
+ * properties and JS variables, mitigating attacks that abuse the HTML/DOM spec rules.
1509
+ *
1510
+ * HTML/DOM spec rules that enable DOM Clobbering:
1511
+ * - Named Access on Window (§7.3.3)
1512
+ * - DOM Tree Accessors (§3.1.5)
1513
+ * - Form Element Parent-Child Relations (§4.10.3)
1514
+ * - Iframe srcdoc / Nested WindowProxies (§4.8.5)
1515
+ * - HTMLCollection (§4.2.10.2)
1516
+ *
1517
+ * Namespace isolation is implemented by prefixing `id` and `name` attributes
1518
+ * with a constant string, i.e., `user-content-`
1519
+ */
1520
+ let SANITIZE_NAMED_PROPS = false;
1521
+ const SANITIZE_NAMED_PROPS_PREFIX = 'user-content-';
1522
+ /* Keep element content when removing element? */
1523
+ let KEEP_CONTENT = true;
1524
+ /* If a `Node` is passed to sanitize(), then performs sanitization in-place instead
1525
+ * of importing it into a new Document and returning a sanitized copy */
1526
+ let IN_PLACE = false;
1527
+ /* Allow usage of profiles like html, svg and mathMl */
1528
+ let USE_PROFILES = {};
1529
+ /* Tags to ignore content of when KEEP_CONTENT is true */
1530
+ let FORBID_CONTENTS = null;
1531
+ const DEFAULT_FORBID_CONTENTS = addToSet({}, ['annotation-xml', 'audio', 'colgroup', 'desc', 'foreignobject', 'head', 'iframe', 'math', 'mi', 'mn', 'mo', 'ms', 'mtext', 'noembed', 'noframes', 'noscript', 'plaintext', 'script',
1532
+ // <selectedcontent> mirrors the selected <option>'s subtree, cloned by
1533
+ // the UA (customizable <select>) — including any on* handlers — and the
1534
+ // engine re-mirrors synchronously whenever a removal changes which
1535
+ // option/selectedcontent is current, even inside DOMPurify's inert
1536
+ // DOMParser document. Hoisting its children on removal re-inserts a fresh
1537
+ // mirror target ahead of the walk, which the engine refills, looping
1538
+ // forever (DoS) and amplifying output. Dropping its content on removal
1539
+ // (rather than hoisting) breaks that cascade; the content is a duplicate
1540
+ // of the option, which is sanitized on its own. See campaign-3 F1/F6.
1541
+ 'selectedcontent', 'style', 'svg', 'template', 'thead', 'title', 'video', 'xmp']);
1542
+ /* Tags that are safe for data: URIs */
1543
+ let DATA_URI_TAGS = null;
1544
+ const DEFAULT_DATA_URI_TAGS = addToSet({}, ['audio', 'video', 'img', 'source', 'image', 'track']);
1545
+ /* Attributes safe for values like "javascript:" */
1546
+ let URI_SAFE_ATTRIBUTES = null;
1547
+ const DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'role', 'summary', 'title', 'value', 'style', 'xmlns']);
1548
+ const MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';
1549
+ const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
1550
+ const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
1551
+ /* Document namespace */
1552
+ let NAMESPACE = HTML_NAMESPACE;
1553
+ let IS_EMPTY_INPUT = false;
1554
+ /* Allowed XHTML+XML namespaces */
1555
+ let ALLOWED_NAMESPACES = null;
1556
+ const DEFAULT_ALLOWED_NAMESPACES = addToSet({}, [MATHML_NAMESPACE, SVG_NAMESPACE, HTML_NAMESPACE], stringToString);
1557
+ const DEFAULT_MATHML_TEXT_INTEGRATION_POINTS = freeze(['mi', 'mo', 'mn', 'ms', 'mtext']);
1558
+ let MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, DEFAULT_MATHML_TEXT_INTEGRATION_POINTS);
1559
+ const DEFAULT_HTML_INTEGRATION_POINTS = freeze(['annotation-xml']);
1560
+ let HTML_INTEGRATION_POINTS = addToSet({}, DEFAULT_HTML_INTEGRATION_POINTS);
1561
+ // Certain elements are allowed in both SVG and HTML
1562
+ // namespace. We need to specify them explicitly
1563
+ // so that they don't get erroneously deleted from
1564
+ // HTML namespace.
1565
+ const COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, ['title', 'style', 'font', 'a', 'script']);
1566
+ /* Parsing of strict XHTML documents */
1567
+ let PARSER_MEDIA_TYPE = null;
1568
+ const SUPPORTED_PARSER_MEDIA_TYPES = ['application/xhtml+xml', 'text/html'];
1569
+ const DEFAULT_PARSER_MEDIA_TYPE = 'text/html';
1570
+ let transformCaseFunc = null;
1571
+ /* Keep a reference to config to pass to hooks */
1572
+ let CONFIG = null;
1573
+ /* Ideally, do not touch anything below this line */
1574
+ /* ______________________________________________ */
1575
+ const formElement = document.createElement('form');
1576
+ const isRegexOrFunction = function isRegexOrFunction(testValue) {
1577
+ return testValue instanceof RegExp || testValue instanceof Function;
1578
+ };
1579
+ /**
1580
+ * _parseConfig
1581
+ *
1582
+ * @param cfg optional config literal
1583
+ */
1584
+ // eslint-disable-next-line complexity
1585
+ const _parseConfig = function _parseConfig() {
1586
+ let cfg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
1587
+ if (CONFIG && CONFIG === cfg) {
1588
+ return;
1589
+ }
1590
+ /* Shield configuration object from tampering */
1591
+ if (!cfg || typeof cfg !== 'object') {
1592
+ cfg = {};
1593
+ }
1594
+ /* Shield configuration object from prototype pollution */
1595
+ cfg = clone(cfg);
1596
+ PARSER_MEDIA_TYPE =
1597
+ // eslint-disable-next-line unicorn/prefer-includes
1598
+ SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? DEFAULT_PARSER_MEDIA_TYPE : cfg.PARSER_MEDIA_TYPE;
1599
+ // HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.
1600
+ transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? stringToString : stringToLowerCase;
1601
+ /* Set configuration parameters */
1602
+ ALLOWED_TAGS = _resolveSetOption(cfg, 'ALLOWED_TAGS', DEFAULT_ALLOWED_TAGS, {
1603
+ transform: transformCaseFunc
1604
+ });
1605
+ ALLOWED_ATTR = _resolveSetOption(cfg, 'ALLOWED_ATTR', DEFAULT_ALLOWED_ATTR, {
1606
+ transform: transformCaseFunc
1607
+ });
1608
+ ALLOWED_NAMESPACES = _resolveSetOption(cfg, 'ALLOWED_NAMESPACES', DEFAULT_ALLOWED_NAMESPACES, {
1609
+ transform: stringToString
1610
+ });
1611
+ URI_SAFE_ATTRIBUTES = _resolveSetOption(cfg, 'ADD_URI_SAFE_ATTR', DEFAULT_URI_SAFE_ATTRIBUTES, {
1612
+ transform: transformCaseFunc,
1613
+ base: DEFAULT_URI_SAFE_ATTRIBUTES
1614
+ });
1615
+ DATA_URI_TAGS = _resolveSetOption(cfg, 'ADD_DATA_URI_TAGS', DEFAULT_DATA_URI_TAGS, {
1616
+ transform: transformCaseFunc,
1617
+ base: DEFAULT_DATA_URI_TAGS
1618
+ });
1619
+ FORBID_CONTENTS = _resolveSetOption(cfg, 'FORBID_CONTENTS', DEFAULT_FORBID_CONTENTS, {
1620
+ transform: transformCaseFunc
1621
+ });
1622
+ FORBID_TAGS = _resolveSetOption(cfg, 'FORBID_TAGS', clone({}), {
1623
+ transform: transformCaseFunc
1624
+ });
1625
+ FORBID_ATTR = _resolveSetOption(cfg, 'FORBID_ATTR', clone({}), {
1626
+ transform: transformCaseFunc
1627
+ });
1628
+ USE_PROFILES = objectHasOwnProperty(cfg, 'USE_PROFILES') ? cfg.USE_PROFILES && typeof cfg.USE_PROFILES === 'object' ? clone(cfg.USE_PROFILES) : cfg.USE_PROFILES : false;
1629
+ ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true
1630
+ ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true
1631
+ ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false
1632
+ ALLOW_SELF_CLOSE_IN_ATTR = cfg.ALLOW_SELF_CLOSE_IN_ATTR !== false; // Default true
1633
+ SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; // Default false
1634
+ SAFE_FOR_XML = cfg.SAFE_FOR_XML !== false; // Default true
1635
+ WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; // Default false
1636
+ RETURN_DOM = cfg.RETURN_DOM || false; // Default false
1637
+ RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; // Default false
1638
+ RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false; // Default false
1639
+ FORCE_BODY = cfg.FORCE_BODY || false; // Default false
1640
+ SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true
1641
+ SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false; // Default false
1642
+ KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true
1643
+ IN_PLACE = cfg.IN_PLACE || false; // Default false
1644
+ IS_ALLOWED_URI$1 = isRegex(cfg.ALLOWED_URI_REGEXP) ? cfg.ALLOWED_URI_REGEXP : IS_ALLOWED_URI; // Default regexp
1645
+ NAMESPACE = typeof cfg.NAMESPACE === 'string' ? cfg.NAMESPACE : HTML_NAMESPACE; // Default HTML namespace
1646
+ MATHML_TEXT_INTEGRATION_POINTS = _resolveObjectOption(cfg, 'MATHML_TEXT_INTEGRATION_POINTS', () => addToSet({}, DEFAULT_MATHML_TEXT_INTEGRATION_POINTS) // Default built-in map
1647
+ );
1648
+ HTML_INTEGRATION_POINTS = _resolveObjectOption(cfg, 'HTML_INTEGRATION_POINTS', () => addToSet({}, DEFAULT_HTML_INTEGRATION_POINTS) // Default built-in map
1649
+ );
1650
+ const customElementHandling = _resolveObjectOption(cfg, 'CUSTOM_ELEMENT_HANDLING', () => create(null));
1651
+ CUSTOM_ELEMENT_HANDLING = create(null);
1652
+ if (objectHasOwnProperty(customElementHandling, 'tagNameCheck') && isRegexOrFunction(customElementHandling.tagNameCheck)) {
1653
+ CUSTOM_ELEMENT_HANDLING.tagNameCheck = customElementHandling.tagNameCheck; // Default undefined
1654
+ }
1655
+ if (objectHasOwnProperty(customElementHandling, 'attributeNameCheck') && isRegexOrFunction(customElementHandling.attributeNameCheck)) {
1656
+ CUSTOM_ELEMENT_HANDLING.attributeNameCheck = customElementHandling.attributeNameCheck; // Default undefined
1657
+ }
1658
+ if (objectHasOwnProperty(customElementHandling, 'allowCustomizedBuiltInElements') && typeof customElementHandling.allowCustomizedBuiltInElements === 'boolean') {
1659
+ CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = customElementHandling.allowCustomizedBuiltInElements; // Default undefined
1660
+ }
1661
+ seal(CUSTOM_ELEMENT_HANDLING);
1662
+ if (SAFE_FOR_TEMPLATES) {
1663
+ ALLOW_DATA_ATTR = false;
1664
+ }
1665
+ if (RETURN_DOM_FRAGMENT) {
1666
+ RETURN_DOM = true;
1667
+ }
1668
+ /* Parse profile info */
1669
+ if (USE_PROFILES) {
1670
+ ALLOWED_TAGS = addToSet({}, text);
1671
+ ALLOWED_ATTR = create(null);
1672
+ if (USE_PROFILES.html === true) {
1673
+ addToSet(ALLOWED_TAGS, html$1);
1674
+ addToSet(ALLOWED_ATTR, html);
1675
+ }
1676
+ if (USE_PROFILES.svg === true) {
1677
+ addToSet(ALLOWED_TAGS, svg$1);
1678
+ addToSet(ALLOWED_ATTR, svg);
1679
+ addToSet(ALLOWED_ATTR, xml);
1680
+ }
1681
+ if (USE_PROFILES.svgFilters === true) {
1682
+ addToSet(ALLOWED_TAGS, svgFilters);
1683
+ addToSet(ALLOWED_ATTR, svg);
1684
+ addToSet(ALLOWED_ATTR, xml);
1685
+ }
1686
+ if (USE_PROFILES.mathMl === true) {
1687
+ addToSet(ALLOWED_TAGS, mathMl$1);
1688
+ addToSet(ALLOWED_ATTR, mathMl);
1689
+ addToSet(ALLOWED_ATTR, xml);
1690
+ }
1691
+ }
1692
+ /* Always reset function-based ADD_TAGS / ADD_ATTR checks to prevent
1693
+ * leaking across calls when switching from function to array config */
1694
+ EXTRA_ELEMENT_HANDLING.tagCheck = null;
1695
+ EXTRA_ELEMENT_HANDLING.attributeCheck = null;
1696
+ /* Merge configuration parameters */
1697
+ if (objectHasOwnProperty(cfg, 'ADD_TAGS')) {
1698
+ if (typeof cfg.ADD_TAGS === 'function') {
1699
+ EXTRA_ELEMENT_HANDLING.tagCheck = cfg.ADD_TAGS;
1700
+ } else if (arrayIsArray(cfg.ADD_TAGS)) {
1701
+ if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
1702
+ ALLOWED_TAGS = clone(ALLOWED_TAGS);
1703
+ }
1704
+ addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);
1705
+ }
1706
+ }
1707
+ if (objectHasOwnProperty(cfg, 'ADD_ATTR')) {
1708
+ if (typeof cfg.ADD_ATTR === 'function') {
1709
+ EXTRA_ELEMENT_HANDLING.attributeCheck = cfg.ADD_ATTR;
1710
+ } else if (arrayIsArray(cfg.ADD_ATTR)) {
1711
+ if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {
1712
+ ALLOWED_ATTR = clone(ALLOWED_ATTR);
1713
+ }
1714
+ addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);
1715
+ }
1716
+ }
1717
+ if (objectHasOwnProperty(cfg, 'ADD_FORBID_CONTENTS') && arrayIsArray(cfg.ADD_FORBID_CONTENTS)) {
1718
+ if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
1719
+ FORBID_CONTENTS = clone(FORBID_CONTENTS);
1720
+ }
1721
+ addToSet(FORBID_CONTENTS, cfg.ADD_FORBID_CONTENTS, transformCaseFunc);
1722
+ }
1723
+ /* Add #text in case KEEP_CONTENT is set to true */
1724
+ if (KEEP_CONTENT) {
1725
+ ALLOWED_TAGS['#text'] = true;
1726
+ }
1727
+ /* Add html, head and body to ALLOWED_TAGS in case WHOLE_DOCUMENT is true */
1728
+ if (WHOLE_DOCUMENT) {
1729
+ addToSet(ALLOWED_TAGS, ['html', 'head', 'body']);
1730
+ }
1731
+ /* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286, #365 */
1732
+ if (ALLOWED_TAGS.table) {
1733
+ addToSet(ALLOWED_TAGS, ['tbody']);
1734
+ delete FORBID_TAGS.tbody;
1735
+ }
1736
+ // Re-derive the active Trusted Types policy from this configuration on
1737
+ // every parse. The active policy must never be sticky closure state that
1738
+ // outlives the config that set it: a caller-supplied policy left in place
1739
+ // after `clearConfig()` — or after a later call that supplied none, or
1740
+ // `TRUSTED_TYPES_POLICY: null` — could sign a subsequent "default"
1741
+ // `RETURN_TRUSTED_TYPE` result with a foreign, possibly unsafe policy.
1742
+ // See GHSA-vxr8-fq34-vvx9.
1743
+ if (cfg.TRUSTED_TYPES_POLICY) {
1744
+ if (typeof cfg.TRUSTED_TYPES_POLICY.createHTML !== 'function') {
1745
+ throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');
1746
+ }
1747
+ if (typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL !== 'function') {
1748
+ throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');
1749
+ }
1750
+ // A caller-supplied policy applies to this configuration only.
1751
+ const previousTrustedTypesPolicy = trustedTypesPolicy;
1752
+ trustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY;
1753
+ // Sign local variables required by `sanitize`. If the supplied policy's
1754
+ // `createHTML` is circular (i.e. it calls `DOMPurify.sanitize`), this
1755
+ // throws via the re-entrancy guard. Restore the previous policy first so
1756
+ // the instance is not left in a poisoned state. See #1422.
1757
+ try {
1758
+ emptyHTML = _createTrustedHTML('');
1759
+ } catch (error) {
1760
+ trustedTypesPolicy = previousTrustedTypesPolicy;
1761
+ throw error;
1762
+ }
1763
+ } else if (cfg.TRUSTED_TYPES_POLICY === null) {
1764
+ // Explicit opt-out for this call: perform no Trusted Types signing and
1765
+ // create nothing (so a strict `trusted-types` CSP that disallows a
1766
+ // `dompurify` policy can still call `sanitize` from inside its own
1767
+ // policy — see #1422). Resetting to `undefined` rather than a sticky
1768
+ // `null` also drops any previously retained caller policy, so it cannot
1769
+ // resurface on a later call, while still allowing the next config-less
1770
+ // call to restore the internal default policy. See GHSA-vxr8-fq34-vvx9.
1771
+ trustedTypesPolicy = undefined;
1772
+ emptyHTML = '';
1773
+ } else {
1774
+ // No policy supplied: keep the currently active policy if one is set — a
1775
+ // previously supplied policy is intentionally sticky across config-less
1776
+ // calls — otherwise fall back to the instance's own internal policy,
1777
+ // created at most once. (A policy supplied for a *single* call still
1778
+ // lingers by design; what must not linger is a policy whose configuration
1779
+ // has been torn down via `clearConfig()`, which restores the default.)
1780
+ if (trustedTypesPolicy === undefined) {
1781
+ trustedTypesPolicy = _getDefaultTrustedTypesPolicy();
1782
+ }
1783
+ // Sign internal variables only when a policy is active. A falsy policy
1784
+ // (Trusted Types unsupported, creation failed, or an explicit opt-out)
1785
+ // leaves `emptyHTML` as a plain string, so we never call `.createHTML` on
1786
+ // a non-policy and throw. See #1422.
1787
+ if (trustedTypesPolicy && typeof emptyHTML === 'string') {
1788
+ emptyHTML = _createTrustedHTML('');
1789
+ }
1790
+ }
1791
+ // Prevent further manipulation of configuration.
1792
+ // Not available in IE8, Safari 5, etc.
1793
+ if (freeze) {
1794
+ freeze(cfg);
1795
+ }
1796
+ CONFIG = cfg;
1797
+ };
1798
+ /* Keep track of all possible SVG and MathML tags
1799
+ * so that we can perform the namespace checks
1800
+ * correctly. */
1801
+ const ALL_SVG_TAGS = addToSet({}, [...svg$1, ...svgFilters, ...svgDisallowed]);
1802
+ const ALL_MATHML_TAGS = addToSet({}, [...mathMl$1, ...mathMlDisallowed]);
1803
+ /**
1804
+ * Namespace rules for an element in the SVG namespace.
1805
+ *
1806
+ * @param tagName the element's lowercase tag name
1807
+ * @param parent the (possibly simulated) parent node
1808
+ * @param parentTagName the parent's lowercase tag name
1809
+ * @returns true if a spec-compliant parser could produce this element
1810
+ */
1811
+ const _checkSvgNamespace = function _checkSvgNamespace(tagName, parent, parentTagName) {
1812
+ // The only way to switch from HTML namespace to SVG
1813
+ // is via <svg>. If it happens via any other tag, then
1814
+ // it should be killed.
1815
+ if (parent.namespaceURI === HTML_NAMESPACE) {
1816
+ return tagName === 'svg';
1817
+ }
1818
+ // The only way to switch from MathML to SVG is via <svg>
1819
+ // if the parent is either <annotation-xml> or a MathML
1820
+ // text integration point.
1821
+ if (parent.namespaceURI === MATHML_NAMESPACE) {
1822
+ return tagName === 'svg' && (parentTagName === 'annotation-xml' || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]);
1823
+ }
1824
+ // We only allow elements that are defined in SVG
1825
+ // spec. All others are disallowed in SVG namespace.
1826
+ return Boolean(ALL_SVG_TAGS[tagName]);
1827
+ };
1828
+ /**
1829
+ * Namespace rules for an element in the MathML namespace.
1830
+ *
1831
+ * @param tagName the element's lowercase tag name
1832
+ * @param parent the (possibly simulated) parent node
1833
+ * @param parentTagName the parent's lowercase tag name
1834
+ * @returns true if a spec-compliant parser could produce this element
1835
+ */
1836
+ const _checkMathMlNamespace = function _checkMathMlNamespace(tagName, parent, parentTagName) {
1837
+ // The only way to switch from HTML namespace to MathML
1838
+ // is via <math>. If it happens via any other tag, then
1839
+ // it should be killed.
1840
+ if (parent.namespaceURI === HTML_NAMESPACE) {
1841
+ return tagName === 'math';
1842
+ }
1843
+ // The only way to switch from SVG to MathML is via
1844
+ // <math> and HTML integration points
1845
+ if (parent.namespaceURI === SVG_NAMESPACE) {
1846
+ return tagName === 'math' && HTML_INTEGRATION_POINTS[parentTagName];
1847
+ }
1848
+ // We only allow elements that are defined in MathML
1849
+ // spec. All others are disallowed in MathML namespace.
1850
+ return Boolean(ALL_MATHML_TAGS[tagName]);
1851
+ };
1852
+ /**
1853
+ * Namespace rules for an element in the HTML namespace.
1854
+ *
1855
+ * @param tagName the element's lowercase tag name
1856
+ * @param parent the (possibly simulated) parent node
1857
+ * @param parentTagName the parent's lowercase tag name
1858
+ * @returns true if a spec-compliant parser could produce this element
1859
+ */
1860
+ const _checkHtmlNamespace = function _checkHtmlNamespace(tagName, parent, parentTagName) {
1861
+ // The only way to switch from SVG to HTML is via
1862
+ // HTML integration points, and from MathML to HTML
1863
+ // is via MathML text integration points
1864
+ if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) {
1865
+ return false;
1866
+ }
1867
+ if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) {
1868
+ return false;
1869
+ }
1870
+ // We disallow tags that are specific for MathML
1871
+ // or SVG and should never appear in HTML namespace
1872
+ return !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]);
1873
+ };
1874
+ /**
1875
+ * @param element a DOM element whose namespace is being checked
1876
+ * @returns Return false if the element has a
1877
+ * namespace that a spec-compliant parser would never
1878
+ * return. Return true otherwise.
1879
+ */
1880
+ const _checkValidNamespace = function _checkValidNamespace(element) {
1881
+ let parent = getParentNode(element);
1882
+ // In JSDOM, if we're inside shadow DOM, then parentNode
1883
+ // can be null. We just simulate parent in this case.
1884
+ if (!parent || !parent.tagName) {
1885
+ parent = {
1886
+ namespaceURI: NAMESPACE,
1887
+ tagName: 'template'
1888
+ };
1889
+ }
1890
+ const tagName = stringToLowerCase(element.tagName);
1891
+ const parentTagName = stringToLowerCase(parent.tagName);
1892
+ if (!ALLOWED_NAMESPACES[element.namespaceURI]) {
1893
+ return false;
1894
+ }
1895
+ if (element.namespaceURI === SVG_NAMESPACE) {
1896
+ return _checkSvgNamespace(tagName, parent, parentTagName);
1897
+ }
1898
+ if (element.namespaceURI === MATHML_NAMESPACE) {
1899
+ return _checkMathMlNamespace(tagName, parent, parentTagName);
1900
+ }
1901
+ if (element.namespaceURI === HTML_NAMESPACE) {
1902
+ return _checkHtmlNamespace(tagName, parent, parentTagName);
1903
+ }
1904
+ // For XHTML and XML documents that support custom namespaces
1905
+ if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && ALLOWED_NAMESPACES[element.namespaceURI]) {
1906
+ return true;
1907
+ }
1908
+ // The code should never reach this place (this means
1909
+ // that the element somehow got namespace that is not
1910
+ // HTML, SVG, MathML or allowed via ALLOWED_NAMESPACES).
1911
+ // Return false just in case.
1912
+ return false;
1913
+ };
1914
+ /**
1915
+ * _forceRemove
1916
+ *
1917
+ * @param node a DOM node
1918
+ */
1919
+ const _forceRemove = function _forceRemove(node) {
1920
+ arrayPush(DOMPurify.removed, {
1921
+ element: node
1922
+ });
1923
+ try {
1924
+ // eslint-disable-next-line unicorn/prefer-dom-node-remove
1925
+ getParentNode(node).removeChild(node);
1926
+ } catch (_) {
1927
+ /* The normal detach failed — this is reached for a parentless node
1928
+ (getParentNode() is null, so .removeChild throws). Element.prototype
1929
+ .remove() is itself a spec no-op on a parentless node, so a recorded
1930
+ "removal" would otherwise hand the caller back an intact,
1931
+ payload-bearing node (e.g. a detached IN_PLACE root the mXSS canary or
1932
+ the style-with-element-child rule decided to kill). Fail closed by
1933
+ throwing — exactly as a clobbered root does at the IN_PLACE entry —
1934
+ rather than trying to "neutralize" the node via its own methods.
1935
+ Neutralizing would mean calling getAttributeNames()/removeAttribute()
1936
+ on the node, both of which a <form> root can clobber via a named child
1937
+ (and _isClobbered does not even probe getAttributeNames), so the
1938
+ neutralize step could itself be silently defeated, leaving the payload
1939
+ intact. A throw touches only the cached, clobber-safe remove() and
1940
+ getParentNode(). Generalizes GHSA-r47g-fvhr-h676 (clobbered-form root)
1941
+ to every root-kill reason. REPORT-3.
1942
+ This lives inside the catch, so it never fires for a normally-removed
1943
+ in-tree node: those have a parent, removeChild() succeeds, and the
1944
+ catch is not entered. Only a kept (parentless) root reaches here. */
1945
+ remove(node);
1946
+ if (!getParentNode(node)) {
1947
+ throw typeErrorCreate('a node selected for removal could not be detached from its tree ' + 'and cannot be safely returned; refusing to sanitize in place');
1948
+ }
1949
+ }
1950
+ };
1951
+ /**
1952
+ * _stripAttributeNode
1953
+ *
1954
+ * Remove a single Attr node case/namespace-exactly on an attribute-teardown
1955
+ * path. Name-based removeAttribute() ASCII-lowercases its lookup key for an
1956
+ * HTML element in an HTML document and so silently misses a case-preserved
1957
+ * handler (e.g. `ONERROR` off an XML/XHTML import) - the same defect
1958
+ * _removeAttribute() was fixed for, which a name-based call would reintroduce
1959
+ * on these IN_PLACE teardown paths. Unlike _removeAttribute this does not
1960
+ * record into DOMPurify.removed: the neutralize passes intentionally do not
1961
+ * book-keep. A clobbered/detached node falls back to best-effort name-based
1962
+ * removal.
1963
+ *
1964
+ * @param element the element to strip the attribute from
1965
+ * @param attribute the Attr node to remove
1966
+ * @param name the attribute's name, for the fallback path
1967
+ */
1968
+ const _stripAttributeNode = function _stripAttributeNode(element, attribute, name) {
1969
+ try {
1970
+ element.removeAttributeNode(attribute);
1971
+ } catch (_) {
1972
+ try {
1973
+ element.removeAttribute(name);
1974
+ } catch (_) {}
1975
+ }
1976
+ };
1977
+ /**
1978
+ * _neutralizeRoot
1979
+ *
1980
+ * Fail-closed teardown of an in-place root after the sanitize walk aborts
1981
+ * (campaign-3 F2). An internal throw mid-walk — e.g. a page-registered
1982
+ * custom element's reaction detaches a node so `_forceRemove`'s deliberate
1983
+ * parentless guard throws, or any other re-entrant engine mutation — would
1984
+ * otherwise leave the caller's *live* tree half-sanitized, with everything
1985
+ * after the abort point still carrying its handlers. There is no safe way
1986
+ * to resume the walk (the tree mutated under us), so we strip the root bare:
1987
+ * remove every child and every attribute, then let the caller's catch see
1988
+ * the original error. Clobber-safe (cached `remove`/`childNodes`/`attributes`
1989
+ * getters; the root was already clobber-pre-flighted at the IN_PLACE entry).
1990
+ *
1991
+ * @param root the in-place root to empty
1992
+ */
1993
+ const _neutralizeRoot = function _neutralizeRoot(root) {
1994
+ /* Strip every disallowed attribute (on* handlers included) off the whole
1995
+ subtree BEFORE detaching anything. Detaching first would hand back
1996
+ handler-bearing originals (e.g. an already-loading `<img onerror>`)
1997
+ whose queued resource event still fires in page scope after we throw.
1998
+ Clobber-safe reads; a doomed clobbered node's own attributes are
1999
+ irrelevant while its non-clobbered descendants are reached and scrubbed. */
2000
+ _neutralizeSubtree(root);
2001
+ const childNodes = getChildNodes(root);
2002
+ if (childNodes) {
2003
+ const snapshot = [];
2004
+ arrayForEach(childNodes, child => {
2005
+ arrayPush(snapshot, child);
2006
+ });
2007
+ arrayForEach(snapshot, child => {
2008
+ try {
2009
+ remove(child);
2010
+ } catch (_) {
2011
+ /* Best-effort teardown; a still-attached child is handled below */
2012
+ }
2013
+ });
2014
+ }
2015
+ const attributes = getAttributes(root);
2016
+ if (attributes) {
2017
+ for (let i = attributes.length - 1; i >= 0; --i) {
2018
+ const attribute = attributes[i];
2019
+ const name = attribute && attribute.name;
2020
+ if (typeof name === 'string') {
2021
+ _stripAttributeNode(root, attribute, name);
2022
+ }
2023
+ }
2024
+ }
2025
+ };
2026
+ /**
2027
+ * _removeAttribute
2028
+ *
2029
+ * Name-based getAttributeNode()/removeAttribute() ASCII-lowercase their
2030
+ * lookup key for HTML elements in an HTML document, so they silently miss an
2031
+ * attribute whose stored qualified name still contains uppercase ASCII
2032
+ * letters. That happens when the node came from a case-preserving source
2033
+ * (an XML/XHTML document imported via importNode(), or createAttributeNS()),
2034
+ * where e.g. `ONERROR` survives the walk: the policy check lowercases to
2035
+ * `onerror` and rejects it, but `removeAttribute('ONERROR')` looks up
2036
+ * `onerror` and finds nothing. Remove the exact Attr node instead, which is
2037
+ * case- and namespace-exact, and fall back to name-based removal only when
2038
+ * the caller could not supply the node.
2039
+ *
2040
+ * @param name an Attribute name
2041
+ * @param element a DOM node
2042
+ * @param attr the exact Attr node to remove, when the caller has it
2043
+ */
2044
+ const _removeAttribute = function _removeAttribute(name, element, attr) {
2045
+ if (!attr) {
2046
+ try {
2047
+ attr = element.getAttributeNode(name);
2048
+ } catch (_) {
2049
+ attr = null;
2050
+ }
2051
+ }
2052
+ arrayPush(DOMPurify.removed, {
2053
+ attribute: attr || null,
2054
+ from: element
2055
+ });
2056
+ try {
2057
+ if (attr) {
2058
+ element.removeAttributeNode(attr);
2059
+ } else {
2060
+ element.removeAttribute(name);
2061
+ }
2062
+ } catch (_) {
2063
+ /* Clobbered or already-detached node - best-effort fall back to a
2064
+ name-based removal so the "is" handling below still runs. */
2065
+ try {
2066
+ element.removeAttribute(name);
2067
+ } catch (_) {}
2068
+ }
2069
+ // We void attribute values for unremovable "is" attributes
2070
+ if (name === 'is') {
2071
+ if (RETURN_DOM || RETURN_DOM_FRAGMENT) {
2072
+ try {
2073
+ _forceRemove(element);
2074
+ } catch (_) {}
2075
+ } else {
2076
+ try {
2077
+ element.setAttribute(name, '');
2078
+ } catch (_) {}
2079
+ }
2080
+ }
2081
+ };
2082
+ /**
2083
+ * _stripDisallowedAttributes
2084
+ *
2085
+ * Removes every attribute the active configuration does not allow from a
2086
+ * single element, using the same allowlist as the main attribute pass (so
2087
+ * `on*` handlers go, but no `/^on/` blocklist is introduced). Used only to
2088
+ * neutralise nodes that are being discarded from an in-place tree.
2089
+ *
2090
+ * @param element the element to strip
2091
+ */
2092
+ const _stripDisallowedAttributes = function _stripDisallowedAttributes(element) {
2093
+ const attributes = getAttributes(element);
2094
+ if (!attributes) {
2095
+ return;
2096
+ }
2097
+ for (let i = attributes.length - 1; i >= 0; --i) {
2098
+ const attribute = attributes[i];
2099
+ const name = attribute && attribute.name;
2100
+ if (typeof name !== 'string' || ALLOWED_ATTR[transformCaseFunc(name)]) {
2101
+ continue;
2102
+ }
2103
+ _stripAttributeNode(element, attribute, name);
2104
+ }
2105
+ };
2106
+ /**
2107
+ * _neutralizeSubtree
2108
+ *
2109
+ * Completes the audit-5 F1 fix across every removal path. The KEEP_CONTENT
2110
+ * move-hoist neutralises only disallowed-tag removals; clobber, mXSS-canary,
2111
+ * namespace, comment, processing-instruction and KEEP_CONTENT:false removals
2112
+ * all drop their subtree wholesale via `_forceRemove`. On the IN_PLACE path
2113
+ * those dropped nodes are detached from the caller's LIVE tree but a
2114
+ * handler-bearing original among them (an `<img onerror>`/`<video>` that was
2115
+ * loading) keeps its queued resource event, which fires in page scope after
2116
+ * sanitize returns. This walks a removed subtree and strips every attribute
2117
+ * the active configuration does not allow — so `on*` handlers are cancelled
2118
+ * through the SAME allowlist that governs kept nodes, not a separate `/^on/`
2119
+ * blocklist. Run synchronously before sanitize returns, i.e. before any
2120
+ * queued event can fire. Hook-free by design: these nodes leave the output,
2121
+ * so firing attribute hooks for them would be surprising. Clobber-safe reads;
2122
+ * a doomed clobbered node may shadow `removeAttribute` (its own attributes are
2123
+ * irrelevant — it is discarded — while its non-clobbered descendants, e.g.
2124
+ * the `<img>`, are reached and scrubbed).
2125
+ *
2126
+ * @param root the root of a removed subtree to neutralise
2127
+ */
2128
+ const _neutralizeSubtree = function _neutralizeSubtree(root) {
2129
+ const stack = [root];
2130
+ while (stack.length > 0) {
2131
+ const node = stack.pop();
2132
+ const nodeType = _readNodeType(node);
2133
+ if (nodeType === NODE_TYPE.element) {
2134
+ _stripDisallowedAttributes(node);
2135
+ }
2136
+ const childNodes = getChildNodes(node);
2137
+ if (childNodes) {
2138
+ for (let i = childNodes.length - 1; i >= 0; --i) {
2139
+ stack.push(childNodes[i]);
2140
+ }
2141
+ }
2142
+ }
2143
+ };
2144
+ /**
2145
+ * _neutralizePatchLinkage
2146
+ *
2147
+ * IN_PLACE entry pre-pass (declarative-partial-updates / streaming
2148
+ * hardening, https://github.com/WICG/declarative-partial-updates).
2149
+ *
2150
+ * The main walk strips patch linkage (`for`/`patchsrc`) and removes range
2151
+ * markers (PIs / markup comments) node-by-node, in document order, AS it
2152
+ * reaches each node. On a live in-place root that leaves a window: from the
2153
+ * moment the root is connected until the walk arrives at a given node, that
2154
+ * node's linkage is live. A patch applied on connection/stream can fire as
2155
+ * a microtask during the walk and inject or teleport an unsanitized DOM
2156
+ * range into a region the iterator has already passed and will not revisit,
2157
+ * so the post-return "tree is sanitized" contract is violated. Sweep the
2158
+ * whole tree once up front and sever every linkage before the walk begins,
2159
+ * closing that window.
2160
+ *
2161
+ * This CANNOT undo a patch that already fired before sanitize ran — that is
2162
+ * the irreducible "do not IN_PLACE a live-connected attacker tree" caveat —
2163
+ * but it closes everything from sanitize-start onward. Gated on SAFE_FOR_XML
2164
+ * to group with the rest of the declarative-partial-updates handling and
2165
+ * stay overridable, consistent with the codebase.
2166
+ *
2167
+ * Clobber-safe traversal (cached childNodes getter); per-node try/catch so a
2168
+ * clobbered root cannot defeat the sweep of its non-clobbered descendants.
2169
+ *
2170
+ * NOTE (pending real-Chrome confirmation, see test/declarative-patch-probe
2171
+ * .html Q1): this mirrors the existing policy of keeping `for` on
2172
+ * <label>/<output>. If the shipping feature can drive a patch through a
2173
+ * surviving `for`-on-label/output + `id` pair, this pre-pass and the
2174
+ * attribute check at _isBasicCustomElement's caller must additionally drop
2175
+ * that pair on the IN_PLACE path. Left as-is until the taxonomy is verified.
2176
+ *
2177
+ * @param root the in-place root to sweep
2178
+ */
2179
+ /**
2180
+ * Central policy for declarative-partial-updates patch-linkage attributes,
2181
+ * shared by the _neutralizePatchLinkage pre-pass and _isValidAttribute so
2182
+ * the two sites cannot drift: `patchsrc` always links, `for` links
2183
+ * everywhere except on <label>/<output>, and the whole policy is gated on
2184
+ * SAFE_FOR_XML (see the rationale block in _isValidAttribute).
2185
+ *
2186
+ * @param lcName the transformCaseFunc'd attribute name
2187
+ * @param lcTag the transformCaseFunc'd tag name of the carrying element
2188
+ * @return true if the attribute is patch linkage and must be dropped
2189
+ */
2190
+ const _isPatchLinkageAttribute = function _isPatchLinkageAttribute(lcName, lcTag) {
2191
+ if (!SAFE_FOR_XML) {
2192
+ return false;
2193
+ }
2194
+ if (lcName === 'patchsrc') {
2195
+ return true;
2196
+ }
2197
+ return lcName === 'for' && lcTag !== 'label' && lcTag !== 'output';
2198
+ };
2199
+ const _neutralizePatchLinkage = function _neutralizePatchLinkage(root) {
2200
+ if (!SAFE_FOR_XML) {
2201
+ return;
2202
+ }
2203
+ const stack = [root];
2204
+ while (stack.length > 0) {
2205
+ const node = stack.pop();
2206
+ const nodeType = _readNodeType(node);
2207
+ /* Remove range markers (the target side of a patch linkage): every
2208
+ processing instruction, and any markup-bearing comment. */
2209
+ if (nodeType === NODE_TYPE.processingInstruction || nodeType === NODE_TYPE.comment && regExpTest(COMMENT_MARKUP_PROBE, node.data)) {
2210
+ try {
2211
+ remove(node);
2212
+ } catch (_) {
2213
+ /* Best-effort */
2214
+ }
2215
+ continue;
2216
+ }
2217
+ /* Strip patch-source attributes (the source side) off elements. */
2218
+ if (nodeType === NODE_TYPE.element) {
2219
+ const element = node;
2220
+ const lcTag = transformCaseFunc(_readNodeName(node));
2221
+ try {
2222
+ if (element.hasAttribute && element.hasAttribute('patchsrc')) {
2223
+ element.removeAttribute('patchsrc');
2224
+ }
2225
+ if (element.hasAttribute && element.hasAttribute('for') && _isPatchLinkageAttribute('for', lcTag)) {
2226
+ element.removeAttribute('for');
2227
+ }
2228
+ } catch (_) {
2229
+ /* Clobbered removeAttribute/hasAttribute on a doomed node — ignore */
2230
+ }
2231
+ }
2232
+ const childNodes = getChildNodes(node);
2233
+ if (childNodes) {
2234
+ for (let i = childNodes.length - 1; i >= 0; --i) {
2235
+ stack.push(childNodes[i]);
2236
+ }
2237
+ }
2238
+ }
2239
+ };
2240
+ /**
2241
+ * _initDocument
2242
+ *
2243
+ * @param dirty - a string of dirty markup
2244
+ * @return a DOM, filled with the dirty markup
2245
+ */
2246
+ const _initDocument = function _initDocument(dirty) {
2247
+ /* Create a HTML document */
2248
+ let doc = null;
2249
+ let leadingWhitespace = null;
2250
+ if (FORCE_BODY) {
2251
+ dirty = '<remove></remove>' + dirty;
2252
+ } else {
2253
+ /* If FORCE_BODY isn't used, leading whitespace needs to be preserved manually */
2254
+ const matches = stringMatch(dirty, /^[\r\n\t ]+/);
2255
+ leadingWhitespace = matches && matches[0];
2256
+ }
2257
+ if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && NAMESPACE === HTML_NAMESPACE) {
2258
+ // Root of XHTML doc must contain xmlns declaration (see https://www.w3.org/TR/xhtml1/normative.html#strict)
2259
+ dirty = '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>' + dirty + '</body></html>';
2260
+ }
2261
+ const dirtyPayload = trustedTypesPolicy ? _createTrustedHTML(dirty) : dirty;
2262
+ /*
2263
+ * Use the DOMParser API by default, fallback later if needs be
2264
+ * DOMParser not work for svg when has multiple root element.
2265
+ */
2266
+ if (NAMESPACE === HTML_NAMESPACE) {
2267
+ try {
2268
+ doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE);
2269
+ } catch (_) {}
2270
+ }
2271
+ /* Use createHTMLDocument in case DOMParser is not available */
2272
+ if (!doc || !doc.documentElement) {
2273
+ doc = implementation.createDocument(NAMESPACE, 'template', null);
2274
+ try {
2275
+ doc.documentElement.innerHTML = IS_EMPTY_INPUT ? emptyHTML : dirtyPayload;
2276
+ } catch (_) {
2277
+ // Syntax error if dirtyPayload is invalid xml
2278
+ }
2279
+ }
2280
+ const body = doc.body || doc.documentElement;
2281
+ if (dirty && leadingWhitespace) {
2282
+ body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null);
2283
+ }
2284
+ /* Work on whole document or just its body */
2285
+ if (NAMESPACE === HTML_NAMESPACE) {
2286
+ return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];
2287
+ }
2288
+ return WHOLE_DOCUMENT ? doc.documentElement : body;
2289
+ };
2290
+ /**
2291
+ * Creates a NodeIterator object that you can use to traverse filtered lists of nodes or elements in a document.
2292
+ *
2293
+ * @param root The root element or node to start traversing on.
2294
+ * @return The created NodeIterator
2295
+ */
2296
+ const _createNodeIterator = function _createNodeIterator(root) {
2297
+ /* Read ownerDocument through the cached Node.prototype getter, never the
2298
+ direct property. HTMLFormElement has [LegacyOverrideBuiltIns], so a
2299
+ clobbering child (<input name="ownerDocument"> or a form-associated
2300
+ external input) shadows the prototype getter and makes a direct read
2301
+ return that <input>. createNodeIterator.call(<input>, ...) then throws
2302
+ "Illegal invocation", and on the IN_PLACE path that throw lands before
2303
+ the walk's fail-closed barrier - leaving the caller's live tree, with
2304
+ any already-armed handler in it, un-neutralized. The cached getter
2305
+ returns the real Document regardless of the clobber. */
2306
+ const doc = getOwnerDocument ? getOwnerDocument(root) : root.ownerDocument;
2307
+ return createNodeIterator.call(doc || root, root,
2308
+ // eslint-disable-next-line no-bitwise
2309
+ NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT | NodeFilter.SHOW_PROCESSING_INSTRUCTION | NodeFilter.SHOW_CDATA_SECTION, null);
2310
+ };
2311
+ /**
2312
+ * Replace template expression syntax (mustache, ERB, template
2313
+ * literal) with a space; shared by all SAFE_FOR_TEMPLATES scrub
2314
+ * sites. Order matters: mustache, then ERB, then template literal.
2315
+ *
2316
+ * @param value the string to scrub
2317
+ * @returns the scrubbed string
2318
+ */
2319
+ const _stripTemplateExpressions = function _stripTemplateExpressions(value) {
2320
+ value = stringReplace(value, MUSTACHE_EXPR$1, ' ');
2321
+ value = stringReplace(value, ERB_EXPR$1, ' ');
2322
+ value = stringReplace(value, TMPLIT_EXPR$1, ' ');
2323
+ return value;
2324
+ };
2325
+ /**
2326
+ * Strip template-engine expressions ({{...}}, ${...}, <%...%>) from the
2327
+ * character data of an element subtree. Used as the final safety net for
2328
+ * SAFE_FOR_TEMPLATES on every DOM-returning code path so that expressions
2329
+ * which only form after text-node normalization (e.g. fragments split across
2330
+ * stripped elements) cannot survive into a template-evaluating framework.
2331
+ *
2332
+ * Walks text/comment/CDATA/processing-instruction nodes and mutates `.data`
2333
+ * in place rather than round-tripping through innerHTML. This preserves
2334
+ * descendant node references (important for IN_PLACE callers), avoids a
2335
+ * serialize/reparse cycle, and reads literal character data — which means
2336
+ * `<%...%>` in text content matches the ERB regex against its real bytes
2337
+ * instead of the HTML-entity-escaped form innerHTML would produce.
2338
+ *
2339
+ * Attribute values are not visited here; SAFE_FOR_TEMPLATES handling for
2340
+ * attributes is performed during the per-node `_sanitizeAttributes` pass.
2341
+ *
2342
+ * @param node The root element whose character data should be scrubbed.
2343
+ */
2344
+ const _scrubTemplateExpressions2 = function _scrubTemplateExpressions(node) {
2345
+ var _node$querySelectorAl;
2346
+ node.normalize();
2347
+ /* Clobber-safe ownerDocument read, same reasoning as _createNodeIterator:
2348
+ under SAFE_FOR_TEMPLATES this runs on the live IN_PLACE root, which may
2349
+ carry a form-named-getter override of ownerDocument. */
2350
+ const doc = getOwnerDocument ? getOwnerDocument(node) : node.ownerDocument;
2351
+ const walker = createNodeIterator.call(doc || node, node,
2352
+ // eslint-disable-next-line no-bitwise
2353
+ NodeFilter.SHOW_TEXT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_CDATA_SECTION | NodeFilter.SHOW_PROCESSING_INSTRUCTION, null);
2354
+ let currentNode = walker.nextNode();
2355
+ while (currentNode) {
2356
+ currentNode.data = _stripTemplateExpressions(currentNode.data);
2357
+ currentNode = walker.nextNode();
2358
+ }
2359
+ // NodeIterator does not descend into <template>.content per the DOM spec,
2360
+ // so we must explicitly recurse into each template's content fragment,
2361
+ // mirroring the approach used by _sanitizeShadowDOM.
2362
+ const templates = (_node$querySelectorAl = node.querySelectorAll) === null || _node$querySelectorAl === void 0 ? void 0 : _node$querySelectorAl.call(node, 'template');
2363
+ if (templates) {
2364
+ arrayForEach(templates, tmpl => {
2365
+ if (_isDocumentFragment(tmpl.content)) {
2366
+ _scrubTemplateExpressions2(tmpl.content);
2367
+ }
2368
+ });
2369
+ }
2370
+ };
2371
+ /**
2372
+ * _isClobbered
2373
+ *
2374
+ * Detect DOM-clobbering on HTMLFormElement nodes. Form is the only HTML
2375
+ * interface with [LegacyOverrideBuiltIns]; a descendant element with a
2376
+ * `name` attribute matching a prototype property shadows that property
2377
+ * on direct reads. We use this check at the IN_PLACE entry-point and
2378
+ * during attribute sanitization to refuse clobbered forms.
2379
+ *
2380
+ * @param element element to check for clobbering attacks
2381
+ * @return true if clobbered, false if safe
2382
+ */
2383
+ const _isClobbered = function _isClobbered(element) {
2384
+ // Realm-independent tag-name probe. If we can't determine the tag
2385
+ // name at all, we can't reason about clobbering — return false
2386
+ // (the caller's other defences still apply).
2387
+ const realTagName = getNodeName ? getNodeName(element) : null;
2388
+ if (typeof realTagName !== 'string') {
2389
+ return false;
2390
+ }
2391
+ if (transformCaseFunc(realTagName) !== 'form') {
2392
+ return false;
2393
+ }
2394
+ return typeof element.nodeName !== 'string' || typeof element.textContent !== 'string' || typeof element.removeChild !== 'function' ||
2395
+ // Realm-safe NamedNodeMap detection: equality against the cached
2396
+ // prototype getter. Clobbered .attributes (e.g. <input name="attributes">)
2397
+ // makes the direct read diverge from the cached read; a clean form
2398
+ // (same-realm OR foreign-realm) has both reads pointing at the same
2399
+ // canonical NamedNodeMap.
2400
+ element.attributes !== getAttributes(element) || typeof element.removeAttribute !== 'function' || typeof element.setAttribute !== 'function' || typeof element.namespaceURI !== 'string' || typeof element.insertBefore !== 'function' || typeof element.hasChildNodes !== 'function' ||
2401
+ // NodeType clobbering probe. Cached Node.prototype.nodeType getter
2402
+ // returns the integer 1 for any Element regardless of realm; direct
2403
+ // read on a clobbered form (e.g. <input name="nodeType">) returns
2404
+ // the named child element. Cheap addition — nodeType is read from
2405
+ // an internal slot, no serialization cost — and removes a residual
2406
+ // clobbering surface used by several mXSS / PI / comment branches
2407
+ // in _sanitizeElements that compare currentNode.nodeType directly.
2408
+ element.nodeType !== getNodeType(element) ||
2409
+ // HTMLFormElement has [LegacyOverrideBuiltIns]: a descendant named
2410
+ // "childNodes" shadows the prototype getter. Direct reads of
2411
+ // form.childNodes from a clobbered form return the named child
2412
+ // instead of the real NodeList, so any walk that reads it directly
2413
+ // skips the form's real children. Compare the direct read to the
2414
+ // cached Node.prototype getter — when the form's named-property
2415
+ // getter intercepts the read, the two values differ and we flag
2416
+ // the form. This catches every clobbering child type (input,
2417
+ // select, etc.) regardless of whether the named child happens to
2418
+ // carry a numeric .length, which a typeof-based probe would miss
2419
+ // (e.g. HTMLSelectElement.length is a defined unsigned-long).
2420
+ element.childNodes !== getChildNodes(element);
2421
+ };
2422
+ /**
2423
+ * Checks whether the given value is a DocumentFragment from any realm.
2424
+ *
2425
+ * The realm-independent replacement reads `nodeType` through the cached
2426
+ * Node.prototype getter and compares to the DOCUMENT_FRAGMENT_NODE
2427
+ * constant (11). nodeType is a numeric value resolved from the node's
2428
+ * internal slot, identical across realms for the same kind of node.
2429
+ *
2430
+ * @param value object to check
2431
+ * @return true if value is a DocumentFragment-shaped node from any realm
2432
+ */
2433
+ const _isDocumentFragment = function _isDocumentFragment(value) {
2434
+ if (!getNodeType || typeof value !== 'object' || value === null) {
2435
+ return false;
2436
+ }
2437
+ try {
2438
+ return getNodeType(value) === NODE_TYPE.documentFragment;
2439
+ } catch (_) {
2440
+ return false;
2441
+ }
2442
+ };
2443
+ /**
2444
+ * Checks whether the given object is a DOM node, including nodes that
2445
+ * originate from a different window/realm (e.g. an iframe's
2446
+ * contentDocument). The previous `value instanceof Node` check was
2447
+ * realm-bound: nodes from a different window failed it, causing
2448
+ * sanitize() to silently stringify them and reset IN_PLACE to false,
2449
+ * returning the original node unsanitized. See GHSA-4w3q-35jp-p934.
2450
+ *
2451
+ * @param value object to check whether it's a DOM node
2452
+ * @return true if value is a DOM node from any realm
2453
+ */
2454
+ const _isNode = function _isNode(value) {
2455
+ if (!getNodeType || typeof value !== 'object' || value === null) {
2456
+ return false;
2457
+ }
2458
+ try {
2459
+ return typeof getNodeType(value) === 'number';
2460
+ } catch (_) {
2461
+ return false;
2462
+ }
2463
+ };
2464
+ function _executeHooks(hooks, currentNode, data) {
2465
+ if (hooks.length === 0) {
2466
+ return;
2467
+ }
2468
+ arrayForEach(hooks, hook => {
2469
+ hook.call(DOMPurify, currentNode, data, CONFIG);
2470
+ });
2471
+ }
2472
+ /**
2473
+ * Structural-threat checks that condemn a node regardless of the
2474
+ * allowlists: mXSS via namespace confusion, risky CSS construction,
2475
+ * processing instructions, markup-bearing comments. Pure predicate;
2476
+ * the caller removes. Check order is load-bearing.
2477
+ *
2478
+ * @param currentNode the node to inspect
2479
+ * @param tagName the node's transformCaseFunc'd tag name
2480
+ * @return true if the node must be removed
2481
+ */
2482
+ const _isUnsafeNode = function _isUnsafeNode(currentNode, tagName) {
2483
+ /* Detect mXSS attempts abusing namespace confusion */
2484
+ if (SAFE_FOR_XML && currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && regExpTest(ELEMENT_MARKUP_PROBE, currentNode.textContent) && regExpTest(ELEMENT_MARKUP_PROBE, currentNode.innerHTML)) {
2485
+ return true;
2486
+ }
2487
+ /* Remove rawtext/literal-text elements whose literal serialization
2488
+ re-opens markup on an HTML reparse - shapes (a) and (b) documented at
2489
+ LITERAL_TEXT_ELEMENTS. Both are invisible to rule 1 above (which
2490
+ self-disables once there is an element child, and whose second probe
2491
+ reads the innerHTML an XML/XHTML document serializes escaped), which
2492
+ is why both probes here read textContent instead. Previously only
2493
+ `style`-with-element-child was covered; every element in
2494
+ LITERAL_TEXT_ELEMENTS shares this literal serialization and is
2495
+ equally affected. */
2496
+ if (SAFE_FOR_XML && currentNode.namespaceURI === HTML_NAMESPACE && LITERAL_TEXT_ELEMENTS[tagName] && (_isNode(currentNode.firstElementChild) || typeof currentNode.textContent === 'string' && regExpTest(LITERAL_TEXT_CLOSE[tagName], currentNode.textContent))) {
2497
+ return true;
2498
+ }
2499
+ /* Remove any occurrence of processing instructions */
2500
+ if (currentNode.nodeType === NODE_TYPE.processingInstruction) {
2501
+ return true;
2502
+ }
2503
+ /* Remove any kind of possibly harmful comments */
2504
+ if (SAFE_FOR_XML && currentNode.nodeType === NODE_TYPE.comment && regExpTest(COMMENT_MARKUP_PROBE, currentNode.data)) {
2505
+ return true;
2506
+ }
2507
+ return false;
2508
+ };
2509
+ /**
2510
+ * Evaluate a CUSTOM_ELEMENT_HANDLING check (a RegExp or a predicate
2511
+ * function, per the validation in _parseConfig) against a name.
2512
+ * Additional arguments are forwarded to predicate functions - the
2513
+ * attributeNameCheck predicate receives the tag name as its second
2514
+ * argument. A null/absent check never matches.
2515
+ *
2516
+ * @param check the configured tagNameCheck / attributeNameCheck value
2517
+ * @param name the name to test
2518
+ * @param args extra arguments forwarded to a predicate function
2519
+ * @return true if the check matches the name
2520
+ */
2521
+ const _matchesNameCheck = function _matchesNameCheck(check, name) {
2522
+ if (check instanceof RegExp) {
2523
+ return regExpTest(check, name);
2524
+ }
2525
+ if (check instanceof Function) {
2526
+ for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
2527
+ args[_key - 2] = arguments[_key];
2528
+ }
2529
+ return Boolean(check(name, ...args));
2530
+ }
2531
+ return false;
2532
+ };
2533
+ /**
2534
+ * Handle a node whose tag is forbidden or not allowlisted: keep
2535
+ * allowed custom elements (false return exits _sanitizeElements
2536
+ * early - the namespace and fallback-tag removal checks are
2537
+ * intentionally skipped for kept custom elements), else hoist
2538
+ * content per KEEP_CONTENT and remove.
2539
+ *
2540
+ * A kept custom element is the ONLY case in which this function
2541
+ * returns false, so the caller uses that return value to run the
2542
+ * afterSanitizeElements hook on the kept element and keep the
2543
+ * element-hook lifecycle consistent with normal allowlisted
2544
+ * elements (GHSA-c2j3-45gr-mqc4).
2545
+ *
2546
+ * @param currentNode the disallowed node
2547
+ * @param tagName the node's transformCaseFunc'd tag name
2548
+ * @return true if the node was removed, false if kept
2549
+ */
2550
+ const _sanitizeDisallowedNode = function _sanitizeDisallowedNode(currentNode, tagName, root) {
2551
+ /* Check if we have a custom element to handle */
2552
+ if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName) && _matchesNameCheck(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) {
2553
+ return false;
2554
+ }
2555
+ /* Keep content except for bad-listed elements.
2556
+ Use the cached prototype getters exclusively — the previous code
2557
+ had `|| currentNode.parentNode` / `|| currentNode.childNodes`
2558
+ fallbacks, but the cached getters always return the canonical
2559
+ value (or null for a real parent-less node), so the fallback
2560
+ path was dead in safe cases and a clobbering surface in unsafe
2561
+ ones. Falsy cached results stay falsy; the `if (childNodes &&
2562
+ parentNode)` check already gates correctly. */
2563
+ if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
2564
+ const parentNode = getParentNode(currentNode);
2565
+ const childNodes = getChildNodes(currentNode);
2566
+ if (childNodes && parentNode) {
2567
+ const childCount = childNodes.length;
2568
+ /* Hoist by moving each child up one level rather than deep-cloning
2569
+ it. Moving transfers every descendant exactly once, so a chain of
2570
+ nested disallowed elements costs O(n) instead of the O(n^2) that
2571
+ re-cloning the shrinking subtree at each level produced; it also
2572
+ empties the removed original, so `DOMPurify.removed` no longer
2573
+ pins whole subtrees. Moving preserves the in-place guarantee too:
2574
+ an original carrying already-queued resource events (`<img
2575
+ onerror>`, `<video>`/`<audio>` error, lazy/`onload`, …) is
2576
+ relocated and sanitised rather than left detached but still armed.
2577
+ The sole case that must clone is removing the walk root itself.
2578
+ The result is serialised from the root's subtree, so a restrictive
2579
+ ALLOWED_TAGS that strips the root (`body` on the string path) must
2580
+ leave the content inside it, which only cloning does. In IN_PLACE
2581
+ the root is pre-validated as an allowed tag and so is never removed
2582
+ here, so that path always takes the move branch.
2583
+ `childNodes` is live; a tail-to-head walk keeps `childNodes[i]`
2584
+ valid whether we move (drops the trailing entry) or clone (leaves
2585
+ the list intact). */
2586
+ for (let i = childCount - 1; i >= 0; --i) {
2587
+ const hoisted = currentNode === root ? cloneNode(childNodes[i], true) : childNodes[i];
2588
+ parentNode.insertBefore(hoisted, getNextSibling(currentNode));
2589
+ }
2590
+ }
2591
+ }
2592
+ _forceRemove(currentNode);
2593
+ return true;
2594
+ };
2595
+ /**
2596
+ * Fork a hook-mutable allowlist off its shared binding the first time a
2597
+ * (possibly lazily-installed) uponSanitize* hook is about to see it, so the
2598
+ * hook cannot widen the per-instance default or the setConfig binding by
2599
+ * reference and leak past the call. Returns the set unchanged once it is
2600
+ * already call-local, so repeated calls across elements are idempotent.
2601
+ *
2602
+ * @param hookList the uponSanitize* hook array for this event
2603
+ * @param set the current ALLOWED_TAGS / ALLOWED_ATTR binding
2604
+ * @param defaultSet the per-instance DEFAULT_ALLOWED_* constant
2605
+ * @param setConfigSet the captured setConfig() binding, or null
2606
+ * @return a call-local clone if a hook is present and set is still shared,
2607
+ * else set unchanged
2608
+ */
2609
+ const _forkSharedAllowlist = function _forkSharedAllowlist(hookList, set, defaultSet, setConfigSet) {
2610
+ if (hookList.length === 0) {
2611
+ return set;
2612
+ }
2613
+ return set === defaultSet || set === setConfigSet ? clone(set) : set;
2614
+ };
2615
+ /**
2616
+ * Shared guard for a node that a hook has detached from the walk tree,
2617
+ * used after each element-hook site in _sanitizeElements. Detaching is a
2618
+ * long-standing user pattern (issue #469; draw.io-style foreignObject
2619
+ * filtering). Per the cached, unclobberable parentNode getter the node is
2620
+ * genuinely out of the tree, so it can reach neither the serialized
2621
+ * output nor an IN_PLACE live tree; treat it as removed and stop
2622
+ * processing it. Without this guard, the unsafe-node / namespace checks
2623
+ * would call _forceRemove on a parentless node and hit the REPORT-3
2624
+ * fail-closed throw — which exists for nodes DOMPurify wants gone but
2625
+ * *cannot* detach (clobbered / parentless roots), the opposite of a node
2626
+ * that is already safely gone. The walk root is exempt: a detached
2627
+ * IN_PLACE root is legitimate input and must still be fully sanitized,
2628
+ * and a kill-decision on it must keep hitting the REPORT-3 throw.
2629
+ *
2630
+ * Nodes detached by hooks stay the hook's responsibility for placement:
2631
+ * they are not recorded in DOMPurify.removed, so the post-walk IN_PLACE
2632
+ * pass (which iterates DOMPurify.removed) does not reach them. But a
2633
+ * hook-detached subtree can still hold a queued resource-event handler -
2634
+ * e.g. an <img onload> that began loading when the caller built the live
2635
+ * tree - which fires in page scope after sanitize returns even though the
2636
+ * handler never reached the returned tree. That is the audit-5 F1 hazard,
2637
+ * and the documented node.remove() hook pattern walks straight into it.
2638
+ * So on the IN_PLACE path we neutralize the detached subtree inline,
2639
+ * stripping its non-allow-listed attributes before returning, exactly as
2640
+ * the post-walk pass does for _forceRemove'd subtrees.
2641
+ *
2642
+ * @param currentNode the node a hook may have detached
2643
+ * @param root the current walk root
2644
+ * @return true if the node is detached and now handled, false otherwise
2645
+ */
2646
+ const _handleHookDetachedNode = function _handleHookDetachedNode(currentNode, root) {
2647
+ if (currentNode === root || getParentNode(currentNode) !== null) {
2648
+ return false;
2649
+ }
2650
+ if (IN_PLACE) {
2651
+ _neutralizeSubtree(currentNode);
2652
+ }
2653
+ return true;
2654
+ };
2655
+ /**
2656
+ * _sanitizeElements
2657
+ *
2658
+ * @protect nodeName
2659
+ * @protect textContent
2660
+ * @protect removeChild
2661
+ * @param currentNode to check for permission to exist
2662
+ * @return true if node was killed, false if left alive
2663
+ */
2664
+ const _sanitizeElements = function _sanitizeElements(currentNode, root) {
2665
+ /* Execute a hook if present */
2666
+ _executeHooks(hooks.beforeSanitizeElements, currentNode, null);
2667
+ /* A hook may have detached the node - treat it as removed (see
2668
+ _handleHookDetachedNode for the full rationale). */
2669
+ if (_handleHookDetachedNode(currentNode, root)) {
2670
+ return true;
2671
+ }
2672
+ /* Check if element is clobbered or can clobber */
2673
+ if (_isClobbered(currentNode)) {
2674
+ _forceRemove(currentNode);
2675
+ return true;
2676
+ }
2677
+ /* Now let's check the element's type and name */
2678
+ const tagName = transformCaseFunc(_readNodeName(currentNode));
2679
+ /* Close the pre-walk clone-guard's timing gap: an uponSanitizeElement
2680
+ hook may have been installed after that guard sampled the hook arrays
2681
+ (e.g. lazily from beforeSanitizeElements), leaving ALLOWED_TAGS still
2682
+ aliasing a shared binding that a widening hook would mutate by
2683
+ reference. Fork it before exposing it to the hook. */
2684
+ ALLOWED_TAGS = _forkSharedAllowlist(hooks.uponSanitizeElement, ALLOWED_TAGS, DEFAULT_ALLOWED_TAGS, SET_CONFIG_ALLOWED_TAGS);
2685
+ /* Execute a hook if present */
2686
+ _executeHooks(hooks.uponSanitizeElement, currentNode, {
2687
+ tagName,
2688
+ allowedTags: ALLOWED_TAGS
2689
+ });
2690
+ /* The uponSanitizeElement hook may have detached the node, exactly as
2691
+ above (see _handleHookDetachedNode for the full rationale). */
2692
+ if (_handleHookDetachedNode(currentNode, root)) {
2693
+ return true;
2694
+ }
2695
+ /* Remove mXSS vectors, processing instructions and risky comments */
2696
+ if (_isUnsafeNode(currentNode, tagName)) {
2697
+ _forceRemove(currentNode);
2698
+ return true;
2699
+ }
2700
+ /* Remove element if anything forbids its presence */
2701
+ if (FORBID_TAGS[tagName] || !(EXTRA_ELEMENT_HANDLING.tagCheck instanceof Function && EXTRA_ELEMENT_HANDLING.tagCheck(tagName)) && !ALLOWED_TAGS[tagName]) {
2702
+ const removed = _sanitizeDisallowedNode(currentNode, tagName, root);
2703
+ /* A false return means the node is a custom element kept via
2704
+ CUSTOM_ELEMENT_HANDLING - the only keep path through
2705
+ _sanitizeDisallowedNode. Run afterSanitizeElements on it so the
2706
+ element-hook lifecycle matches normal allowlisted elements: a
2707
+ security policy applied in this hook (e.g. stripping an attribute
2708
+ from every surviving element) must not silently skip kept custom
2709
+ elements (GHSA-c2j3-45gr-mqc4). This mirrors the normal-element
2710
+ tail below - the hook runs, then the walker's subsequent
2711
+ _sanitizeAttributes pass sanitizes the element's attributes. The
2712
+ deliberately skipped namespace and fallback-tag removal checks stay
2713
+ skipped; they are removal decisions, not the hook contract. */
2714
+ if (removed === false) {
2715
+ _executeHooks(hooks.afterSanitizeElements, currentNode, null);
2716
+ }
2717
+ return removed;
2718
+ }
2719
+ /* Check whether element has a valid namespace.
2720
+ Realm-safe check (GHSA-hpcv-96wg-7vj8): use the cached Node.prototype
2721
+ nodeType getter rather than `instanceof Element`, which is realm-
2722
+ bound and short-circuits to false for any node minted in a different
2723
+ realm — letting a foreign-realm element with a forbidden namespace
2724
+ slip past the namespace check entirely. */
2725
+ const nt = _readNodeType(currentNode);
2726
+ if (nt === NODE_TYPE.element && !_checkValidNamespace(currentNode)) {
2727
+ _forceRemove(currentNode);
2728
+ return true;
2729
+ }
2730
+ /* Make sure that older browsers don't get fallback-tag mXSS */
2731
+ if ((tagName === 'noscript' || tagName === 'noembed' || tagName === 'noframes') && regExpTest(FALLBACK_TAG_CLOSE, currentNode.innerHTML)) {
2732
+ _forceRemove(currentNode);
2733
+ return true;
2734
+ }
2735
+ /* Sanitize element content to be template-safe */
2736
+ if (SAFE_FOR_TEMPLATES && currentNode.nodeType === NODE_TYPE.text) {
2737
+ /* Get the element's text content */
2738
+ const content = _stripTemplateExpressions(currentNode.textContent);
2739
+ if (currentNode.textContent !== content) {
2740
+ arrayPush(DOMPurify.removed, {
2741
+ element: currentNode.cloneNode()
2742
+ });
2743
+ currentNode.textContent = content;
2744
+ }
2745
+ }
2746
+ /* Execute a hook if present */
2747
+ _executeHooks(hooks.afterSanitizeElements, currentNode, null);
2748
+ return false;
2749
+ };
2750
+ /**
2751
+ * _isValidAttribute
2752
+ *
2753
+ * @param lcTag Lowercase tag name of containing element.
2754
+ * @param lcName Lowercase attribute name.
2755
+ * @param value Attribute value.
2756
+ * @return Returns true if `value` is valid, otherwise false.
2757
+ */
2758
+ // eslint-disable-next-line complexity
2759
+ const _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {
2760
+ /* FORBID_ATTR must always win, even if ADD_ATTR predicate would allow it */
2761
+ if (FORBID_ATTR[lcName]) {
2762
+ return false;
2763
+ }
2764
+ /* Reject declarative-partial-updates patch-linkage attributes
2765
+ (https://github.com/WICG/declarative-partial-updates).
2766
+ Empirical note (Chrome 150, verified — see
2767
+ test/declarative-patch-probe-v3.html): expansion is NOT applied after
2768
+ sanitization. For the string path it fires during sanitize()'s own
2769
+ parse, so the walk sees and sanitizes the fully materialized expanded
2770
+ tree — teleports into MathML/SVG integration points included; a
2771
+ weaponized `<template for>`->`<img onerror>` comes back with the handler
2772
+ stripped. For the IN_PLACE path it fires on connection, before the walk.
2773
+ Either way DOMPurify is NOT blind to the patch.
2774
+ This removal is therefore defense-in-depth rather than the sole barrier:
2775
+ it prevents live linkage from surviving into the OUTPUT and re-expanding
2776
+ in the caller's context, and keeps behaviour deterministic if a future
2777
+ engine defers expansion. `for` is legitimate only on <label>/<output>;
2778
+ anywhere else (notably <template for>) it links the element to a patch
2779
+ target and teleports or removes an arbitrary DOM range by id/marker name.
2780
+ `patchsrc` fetches remote markup and is treated as a script-loading
2781
+ mechanism (CSP). Gated on SAFE_FOR_XML so the removal groups with the
2782
+ other structural-threat checks and stays overridable, consistent with
2783
+ the rest of the codebase. PI range markers are already removed by
2784
+ _isUnsafeNode. */
2785
+ if (_isPatchLinkageAttribute(lcName, lcTag)) {
2786
+ return false;
2787
+ }
2788
+ /* Make sure attribute cannot clobber */
2789
+ if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
2790
+ return false;
2791
+ }
2792
+ const nameIsPermitted = ALLOWED_ATTR[lcName] || EXTRA_ELEMENT_HANDLING.attributeCheck instanceof Function && EXTRA_ELEMENT_HANDLING.attributeCheck(lcName, lcTag);
2793
+ /* Allow valid data-* attributes: At least one character after "-"
2794
+ (https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)
2795
+ XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)
2796
+ We don't need to check the value; it's always URI safe. */
2797
+ if (ALLOW_DATA_ATTR && regExpTest(DATA_ATTR$1, lcName)) {
2798
+ return true;
2799
+ }
2800
+ /* Allow valid aria-* attributes, the value is always URI safe */
2801
+ if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR$1, lcName)) {
2802
+ return true;
2803
+ }
2804
+ /* A name outside the allowlist is acceptable on custom-element terms
2805
+ only. The value checks below are intentionally skipped in that case:
2806
+ if the user supplied a tagNameCheck we also allow derived custom
2807
+ elements using the same test, and attributes passing the configured
2808
+ attributeNameCheck are allowed as custom elements define these at
2809
+ their own discretion. */
2810
+ if (!nameIsPermitted) {
2811
+ return (
2812
+ // Condition a) covers a basically valid custom element tag name whose
2813
+ // tag passes the configured tagNameCheck and whose attribute name
2814
+ // passes the configured attributeNameCheck ...
2815
+ _isBasicCustomElement(lcTag) && _matchesNameCheck(CUSTOM_ELEMENT_HANDLING.tagNameCheck, lcTag) && _matchesNameCheck(CUSTOM_ELEMENT_HANDLING.attributeNameCheck, lcName, lcTag) ||
2816
+ // Condition b) covers an `is` attribute whose value passes the
2817
+ // configured tagNameCheck while customized built-in elements are
2818
+ // allowed.
2819
+ lcName === 'is' && CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements && _matchesNameCheck(CUSTOM_ELEMENT_HANDLING.tagNameCheck, value)
2820
+ );
2821
+ }
2822
+ /* Check value is safe. First, is attr inert? If so, is safe */
2823
+ if (URI_SAFE_ATTRIBUTES[lcName]) {
2824
+ return true;
2825
+ }
2826
+ /* Check no script, data or unknown possibly unsafe URI
2827
+ unless we know URI values are safe for that attribute */
2828
+ if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE$1, ''))) {
2829
+ return true;
2830
+ }
2831
+ /* Keep image data URIs alive if src/xlink:href is allowed */
2832
+ /* Further prevent gadget XSS for dynamically built script tags */
2833
+ if ((lcName === 'src' || lcName === 'xlink:href' || lcName === 'href') && lcTag !== 'script' && stringIndexOf(value, 'data:') === 0 && DATA_URI_TAGS[lcTag]) {
2834
+ return true;
2835
+ }
2836
+ /* Allow unknown protocols: This provides support for links that
2837
+ are handled by protocol handlers which may be unknown ahead of
2838
+ time, e.g. fb:, spotify: */
2839
+ if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA$1, stringReplace(value, ATTR_WHITESPACE$1, ''))) {
2840
+ return true;
2841
+ }
2842
+ /* Only an empty (binary) value remains safe at this point;
2843
+ anything else is presumed unsafe, do not add it back */
2844
+ return !value;
2845
+ };
2846
+ /* Names the HTML spec reserves from valid-custom-element-name; these must
2847
+ * never be treated as basic custom elements even when a permissive
2848
+ * CUSTOM_ELEMENT_HANDLING.tagNameCheck is configured. */
2849
+ const RESERVED_CUSTOM_ELEMENT_NAMES = addToSet({}, ['annotation-xml', 'color-profile', 'font-face', 'font-face-format', 'font-face-name', 'font-face-src', 'font-face-uri', 'missing-glyph']);
2850
+ /**
2851
+ * _isBasicCustomElement
2852
+ * checks if at least one dash is included in tagName, and it's not the first char
2853
+ * for more sophisticated checking see https://github.com/sindresorhus/validate-element-name
2854
+ *
2855
+ * @param tagName name of the tag of the node to sanitize
2856
+ * @returns Returns true if the tag name meets the basic criteria for a custom element, otherwise false.
2857
+ */
2858
+ const _isBasicCustomElement = function _isBasicCustomElement(tagName) {
2859
+ return !RESERVED_CUSTOM_ELEMENT_NAMES[stringToLowerCase(tagName)] && regExpTest(CUSTOM_ELEMENT$1, tagName);
2860
+ };
2861
+ /**
2862
+ * Wrap an attribute value in the matching Trusted Types object when
2863
+ * the active policy requires it. Namespaced attributes pass through
2864
+ * unchanged (no TT support yet, see
2865
+ * https://bugs.chromium.org/p/chromium/issues/detail?id=1305293).
2866
+ *
2867
+ * @param lcTag lowercase tag name of the containing element
2868
+ * @param lcName lowercase attribute name
2869
+ * @param namespaceURI the attribute's namespace, if any
2870
+ * @param value the attribute value to wrap
2871
+ * @return the value, wrapped when Trusted Types demand it
2872
+ */
2873
+ const _applyTrustedTypesToAttribute = function _applyTrustedTypesToAttribute(lcTag, lcName, namespaceURI, value) {
2874
+ if (trustedTypesPolicy && typeof trustedTypes === 'object' && typeof trustedTypes.getAttributeType === 'function' && !namespaceURI) {
2875
+ switch (trustedTypes.getAttributeType(lcTag, lcName)) {
2876
+ case 'TrustedHTML':
2877
+ {
2878
+ return _createTrustedHTML(value);
2879
+ }
2880
+ case 'TrustedScriptURL':
2881
+ {
2882
+ return _createTrustedScriptURL(value);
2883
+ }
2884
+ }
2885
+ }
2886
+ return value;
2887
+ };
2888
+ /**
2889
+ * Write a modified attribute value back onto the element. On
2890
+ * success, re-probe for clobbering introduced by the new value and
2891
+ * remove the element when found; otherwise pop the removal entry
2892
+ * recorded by the earlier _removeAttribute (long-standing pairing
2893
+ * with the SANITIZE_NAMED_PROPS path - do not "fix" casually). On
2894
+ * failure, remove the attribute instead.
2895
+ *
2896
+ * @param currentNode the element carrying the attribute
2897
+ * @param name the attribute name as present on the element
2898
+ * @param namespaceURI the attribute's namespace, if any
2899
+ * @param value the new attribute value
2900
+ */
2901
+ const _setAttributeValue = function _setAttributeValue(currentNode, name, namespaceURI, value) {
2902
+ try {
2903
+ if (namespaceURI) {
2904
+ currentNode.setAttributeNS(namespaceURI, name, value);
2905
+ } else {
2906
+ /* Fallback to setAttribute() for browser-unrecognized namespaces e.g. "x-schema". */
2907
+ currentNode.setAttribute(name, value);
2908
+ }
2909
+ if (_isClobbered(currentNode)) {
2910
+ _forceRemove(currentNode);
2911
+ } else {
2912
+ arrayPop(DOMPurify.removed);
2913
+ }
2914
+ } catch (_) {
2915
+ _removeAttribute(name, currentNode);
2916
+ }
2917
+ };
2918
+ /**
2919
+ * _sanitizeAttributes
2920
+ *
2921
+ * @protect attributes
2922
+ * @protect nodeName
2923
+ * @protect removeAttribute
2924
+ * @protect setAttribute
2925
+ *
2926
+ * @param currentNode to sanitize
2927
+ */
2928
+ const _sanitizeAttributes = function _sanitizeAttributes(currentNode) {
2929
+ /* Execute a hook if present */
2930
+ _executeHooks(hooks.beforeSanitizeAttributes, currentNode, null);
2931
+ const attributes = currentNode.attributes;
2932
+ /* Check if we have attributes; if not we might have a text node */
2933
+ if (!attributes || _isClobbered(currentNode)) {
2934
+ return;
2935
+ }
2936
+ /* Same lazy-install guard as uponSanitizeElement (see there): fork the
2937
+ attribute allowlist off its shared binding before a hook can see it. */
2938
+ ALLOWED_ATTR = _forkSharedAllowlist(hooks.uponSanitizeAttribute, ALLOWED_ATTR, DEFAULT_ALLOWED_ATTR, SET_CONFIG_ALLOWED_ATTR);
2939
+ const hookEvent = {
2940
+ attrName: '',
2941
+ attrValue: '',
2942
+ keepAttr: true,
2943
+ allowedAttributes: ALLOWED_ATTR,
2944
+ forceKeepAttr: undefined
2945
+ };
2946
+ let l = attributes.length;
2947
+ const lcTag = transformCaseFunc(currentNode.nodeName);
2948
+ /* Go backwards over all attributes; safely remove bad ones */
2949
+ while (l--) {
2950
+ const attr = attributes[l];
2951
+ const name = attr.name,
2952
+ namespaceURI = attr.namespaceURI,
2953
+ attrValue = attr.value;
2954
+ const lcName = transformCaseFunc(name);
2955
+ const initValue = attrValue;
2956
+ let value = name === 'value' ? initValue : stringTrim(initValue);
2957
+ /* Execute a hook if present */
2958
+ hookEvent.attrName = lcName;
2959
+ hookEvent.attrValue = value;
2960
+ hookEvent.keepAttr = true;
2961
+ hookEvent.forceKeepAttr = undefined; // Allows developers to see this is a property they can set
2962
+ _executeHooks(hooks.uponSanitizeAttribute, currentNode, hookEvent);
2963
+ value = hookEvent.attrValue;
2964
+ /* Full DOM Clobbering protection via namespace isolation,
2965
+ * Prefix id and name attributes with `user-content-`
2966
+ */
2967
+ if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name') && stringIndexOf(value, SANITIZE_NAMED_PROPS_PREFIX) !== 0) {
2968
+ // Remove the attribute with this value
2969
+ _removeAttribute(name, currentNode, attr);
2970
+ // Prefix the value and later re-create the attribute with the sanitized value
2971
+ value = SANITIZE_NAMED_PROPS_PREFIX + value;
2972
+ }
2973
+ // Else: already prefixed, leave the attribute alone — the prefix is
2974
+ // itself the clobbering protection, and re-applying it is incorrect.
2975
+ /* Work around a security issue with comments inside attributes */
2976
+ if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|script|title|xmp|textarea|noscript|iframe|noembed|noframes)/i, value)) {
2977
+ _removeAttribute(name, currentNode, attr);
2978
+ continue;
2979
+ }
2980
+ /* Make sure we cannot easily use animated hrefs, even if animations are allowed */
2981
+ if (lcName === 'attributename' && stringMatch(value, 'href')) {
2982
+ _removeAttribute(name, currentNode, attr);
2983
+ continue;
2984
+ }
2985
+ /* Did the hooks force-keep the attribute? */
2986
+ if (hookEvent.forceKeepAttr) {
2987
+ continue;
2988
+ }
2989
+ /* Did the hooks approve of the attribute? */
2990
+ if (!hookEvent.keepAttr) {
2991
+ _removeAttribute(name, currentNode, attr);
2992
+ continue;
2993
+ }
2994
+ /* Work around a security issue in jQuery 3.0 */
2995
+ if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(SELF_CLOSING_TAG, value)) {
2996
+ _removeAttribute(name, currentNode, attr);
2997
+ continue;
2998
+ }
2999
+ /* Sanitize attribute content to be template-safe */
3000
+ if (SAFE_FOR_TEMPLATES) {
3001
+ value = _stripTemplateExpressions(value);
3002
+ }
3003
+ /* Is `value` valid for this attribute? */
3004
+ if (!_isValidAttribute(lcTag, lcName, value)) {
3005
+ _removeAttribute(name, currentNode, attr);
3006
+ continue;
3007
+ }
3008
+ /* Handle attributes that require Trusted Types */
3009
+ value = _applyTrustedTypesToAttribute(lcTag, lcName, namespaceURI, value);
3010
+ /* Handle invalid data-* attribute set by try-catching it */
3011
+ if (value !== initValue) {
3012
+ _setAttributeValue(currentNode, name, namespaceURI, value);
3013
+ }
3014
+ }
3015
+ /* Execute a hook if present */
3016
+ _executeHooks(hooks.afterSanitizeAttributes, currentNode, null);
3017
+ };
3018
+ /**
3019
+ * _sanitizeShadowDOM
3020
+ *
3021
+ * @param fragment to iterate over recursively
3022
+ */
3023
+ const _sanitizeShadowDOM2 = function _sanitizeShadowDOM(fragment) {
3024
+ let shadowNode = null;
3025
+ const shadowIterator = _createNodeIterator(fragment);
3026
+ /* Execute a hook if present */
3027
+ _executeHooks(hooks.beforeSanitizeShadowDOM, fragment, null);
3028
+ while (shadowNode = shadowIterator.nextNode()) {
3029
+ /* Execute a hook if present */
3030
+ _executeHooks(hooks.uponSanitizeShadowNode, shadowNode, null);
3031
+ /* Sanitize tags and elements */
3032
+ _sanitizeElements(shadowNode, fragment);
3033
+ /* Check attributes next */
3034
+ _sanitizeAttributes(shadowNode);
3035
+ /* Deep shadow DOM detected.
3036
+ Realm-safe check (GHSA-hpcv-96wg-7vj8): use nodeType against the
3037
+ DOCUMENT_FRAGMENT_NODE constant rather than instanceof, so we
3038
+ recurse into <template>.content from foreign realms too. */
3039
+ if (_isDocumentFragment(shadowNode.content)) {
3040
+ _sanitizeShadowDOM2(shadowNode.content);
3041
+ }
3042
+ /* An element iterated here may itself host an attached
3043
+ shadow root. The default NodeIterator does not enter shadow
3044
+ trees, so a shadow root nested inside template.content was
3045
+ previously reached by no walk at all (the pre-pass at
3046
+ _sanitizeAttachedShadowRoots descends via childNodes, which
3047
+ doesn't enter template.content; the template-content recursion
3048
+ above iterates the content but never inspected shadowRoot).
3049
+ Walk it explicitly. The nodeType guard avoids reading
3050
+ shadowRoot off text / comment / CDATA / PI nodes that the
3051
+ iterator also surfaces. */
3052
+ if (_readNodeType(shadowNode) === NODE_TYPE.element) {
3053
+ const innerSr = getShadowRoot(shadowNode);
3054
+ if (_isDocumentFragment(innerSr)) {
3055
+ _sanitizeAttachedShadowRoots(innerSr);
3056
+ _sanitizeShadowDOM2(innerSr);
3057
+ }
3058
+ }
3059
+ }
3060
+ /* Execute a hook if present */
3061
+ _executeHooks(hooks.afterSanitizeShadowDOM, fragment, null);
3062
+ };
3063
+ /**
3064
+ * _sanitizeAttachedShadowRoots
3065
+ *
3066
+ * Walks `root` and feeds every attached shadow root we encounter into
3067
+ * the existing _sanitizeShadowDOM pipeline. The default node iterator
3068
+ * does not descend into shadow trees, so nodes inside an attached
3069
+ * shadow root would otherwise be skipped entirely.
3070
+ *
3071
+ * Two real input paths put attached shadow roots in front of us:
3072
+ * 1. IN_PLACE on a DOM node that already has shadow roots attached.
3073
+ * 2. DOM-node input where importNode(dirty, true) deep-clones the
3074
+ * shadow root because it was created with `clonable: true`.
3075
+ *
3076
+ * This pass runs once, up front, so the main iteration loop (and the
3077
+ * existing _sanitizeShadowDOM template-content recursion) stay
3078
+ * untouched — string-input paths are not affected.
3079
+ *
3080
+ * @param root the subtree root to walk for attached shadow roots
3081
+ */
3082
+ const _sanitizeAttachedShadowRoots = function _sanitizeAttachedShadowRoots(root) {
3083
+ /* Iterative (explicit stack) rather than per-child recursion. DOM APIs
3084
+ impose no depth cap, so an attacker-shaped tree (JSON/CRDT/editor data
3085
+ built straight into the DOM — the IN_PLACE surface) deeper than the JS
3086
+ call-stack budget would otherwise overflow native recursion here and
3087
+ throw at the IN_PLACE entry pre-pass, before a single node is
3088
+ sanitized, leaving the caller's live tree untouched (fail-open). See
3089
+ campaign-3 F4. A heap stack keeps depth off the call stack.
3090
+ Each work item is either a node to descend into, or a deferred
3091
+ `_sanitizeShadowDOM` for an already-walked shadow root. The deferred
3092
+ form preserves the original post-order discipline: a shadow root's
3093
+ nested shadow roots are discovered before the outer shadow is
3094
+ sanitized (which may remove hosts). Pushes are in reverse of the
3095
+ desired processing order (LIFO): template content, then children, then
3096
+ the shadow-sanitize, then the shadow walk — so the order matches the
3097
+ previous recursion exactly. */
3098
+ const stack = [{
3099
+ node: root,
3100
+ shadow: null
3101
+ }];
3102
+ while (stack.length > 0) {
3103
+ const item = stack.pop();
3104
+ /* Deferred shadow-DOM sanitisation: runs after its subtree was walked. */
3105
+ if (item.shadow) {
3106
+ _sanitizeShadowDOM2(item.shadow);
3107
+ continue;
3108
+ }
3109
+ const node = item.node;
3110
+ const nodeType = _readNodeType(node);
3111
+ const isElement = nodeType === NODE_TYPE.element;
3112
+ /* (pushed last → processed first) Children, snapshotted in reverse so
3113
+ the first child is processed first. Snapshotting matters because a
3114
+ hook may detach siblings mid-walk. */
3115
+ const childNodes = getChildNodes(node);
3116
+ if (childNodes) {
3117
+ for (let i = childNodes.length - 1; i >= 0; --i) {
3118
+ stack.push({
3119
+ node: childNodes[i],
3120
+ shadow: null
3121
+ });
3122
+ }
3123
+ }
3124
+ /* (pushed before children → processed after them, matching the old
3125
+ "template content last" order) When the node is a <template>,
3126
+ descend into its content. */
3127
+ if (isElement) {
3128
+ const rootName = getNodeName ? getNodeName(node) : null;
3129
+ if (typeof rootName === 'string' && transformCaseFunc(rootName) === 'template') {
3130
+ const content = node.content;
3131
+ if (_isDocumentFragment(content)) {
3132
+ stack.push({
3133
+ node: content,
3134
+ shadow: null
3135
+ });
3136
+ }
3137
+ }
3138
+ }
3139
+ /* Shadow root (processed first): walk its subtree, then sanitise it.
3140
+ Realm-safe check (GHSA-hpcv-96wg-7vj8): nodeType-based detection
3141
+ rather than `instanceof DocumentFragment`, which is realm-bound and
3142
+ silently skipped foreign-realm shadow roots (e.g.
3143
+ iframe.contentDocument attachShadow). */
3144
+ if (isElement) {
3145
+ const sr = getShadowRoot(node);
3146
+ if (_isDocumentFragment(sr)) {
3147
+ /* Push the deferred sanitise first so it pops after the shadow
3148
+ walk we push next, i.e. nested shadow roots are discovered
3149
+ before this one is sanitised. */
3150
+ stack.push({
3151
+ node: null,
3152
+ shadow: sr
3153
+ }, {
3154
+ node: sr,
3155
+ shadow: null
3156
+ });
3157
+ }
3158
+ }
3159
+ }
3160
+ };
3161
+ // eslint-disable-next-line complexity
3162
+ DOMPurify.sanitize = function (dirty) {
3163
+ let cfg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
3164
+ let body = null;
3165
+ let importedNode = null;
3166
+ let currentNode = null;
3167
+ let returnNode = null;
3168
+ /* Make sure we have a string to sanitize.
3169
+ DO NOT return early, as this will return the wrong type if
3170
+ the user has requested a DOM object rather than a string */
3171
+ IS_EMPTY_INPUT = !dirty;
3172
+ if (IS_EMPTY_INPUT) {
3173
+ dirty = '<!-->';
3174
+ }
3175
+ /* Stringify, in case dirty is an object */
3176
+ if (typeof dirty !== 'string' && !_isNode(dirty)) {
3177
+ dirty = stringifyValue(dirty);
3178
+ if (typeof dirty !== 'string') {
3179
+ throw typeErrorCreate('dirty is not a string, aborting');
3180
+ }
3181
+ }
3182
+ /* Return dirty HTML if DOMPurify cannot run */
3183
+ if (!DOMPurify.isSupported) {
3184
+ return dirty;
3185
+ }
3186
+ /* Assign config vars */
3187
+ if (SET_CONFIG) {
3188
+ /* Persistent setConfig() path: _parseConfig is skipped, so the sets are
3189
+ * not re-derived per call. Restore them from the pristine bindings
3190
+ * captured at setConfig() time so a previous call's hook clone (mutated
3191
+ * below) does not carry over. */
3192
+ ALLOWED_TAGS = SET_CONFIG_ALLOWED_TAGS;
3193
+ ALLOWED_ATTR = SET_CONFIG_ALLOWED_ATTR;
571
3194
  } else {
572
- setPost(unreadcount);
3195
+ _parseConfig(cfg);
3196
+ }
3197
+ /* Clone the hook-mutable allowlists before the walk whenever an
3198
+ * uponSanitize* hook is registered. The hook event exposes ALLOWED_TAGS
3199
+ * and ALLOWED_ATTR by reference (as allowedTags / allowedAttributes), so
3200
+ * a hook that widens them would otherwise mutate the shared set
3201
+ * permanently: across later calls and across every element. Cloning per
3202
+ * walk keeps documented in-call widening working while scoping it to the
3203
+ * call. A single guard for both config paths - the per-call path rebinds
3204
+ * the sets in _parseConfig each call, the persistent path restores them
3205
+ * from the captured bindings just above - so the two cannot diverge. */
3206
+ if (hooks.uponSanitizeElement.length > 0 || hooks.uponSanitizeAttribute.length > 0) {
3207
+ ALLOWED_TAGS = clone(ALLOWED_TAGS);
3208
+ }
3209
+ if (hooks.uponSanitizeAttribute.length > 0) {
3210
+ ALLOWED_ATTR = clone(ALLOWED_ATTR);
3211
+ }
3212
+ /* Clean up removed elements */
3213
+ DOMPurify.removed = [];
3214
+ /* Resolve IN_PLACE for this call without mutating persistent config.
3215
+ Writing the IN_PLACE closure variable here leaks under setConfig(),
3216
+ where _parseConfig is skipped on later calls: a single string call would
3217
+ disable in-place mode for every subsequent node call, returning a
3218
+ sanitized copy while leaving the caller's node — which in-place callers
3219
+ keep using and whose return value they ignore — unsanitized. REPORT-2. */
3220
+ const inPlace = IN_PLACE && typeof dirty !== 'string' && _isNode(dirty);
3221
+ if (inPlace) {
3222
+ /* Declarative-partial-updates / streaming pre-pass: sever every patch
3223
+ linkage across the live tree BEFORE the walk, so no patch can fire
3224
+ mid-walk and inject into an already-processed region. Runs first, so
3225
+ it also covers the forbidden/clobbered roots that throw below. */
3226
+ _neutralizePatchLinkage(dirty);
3227
+ /* Do some early pre-sanitization to avoid unsafe root nodes.
3228
+ Read nodeName through the cached prototype getter — a clobbering
3229
+ child named "nodeName" on the form root would otherwise shadow
3230
+ the property and let this check skip the root-allowlist
3231
+ validation entirely. */
3232
+ const nn = _readNodeName(dirty);
3233
+ if (typeof nn === 'string') {
3234
+ const tagName = transformCaseFunc(nn);
3235
+ if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
3236
+ /* Fail closed on a live root: neutralize handlers/children before
3237
+ throwing, exactly as the mid-walk abort path does. */
3238
+ _neutralizeRoot(dirty);
3239
+ throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place');
3240
+ }
3241
+ }
3242
+ /* Pre-flight the root through _isClobbered. The iterator-driven
3243
+ removal path can not detach a parent-less root: _forceRemove
3244
+ falls through to Element.prototype.remove(), which per spec
3245
+ is a no-op on a node with no parent. A clobbered root would
3246
+ then survive the main loop with its attributes uninspected,
3247
+ because _sanitizeAttributes early-returns on _isClobbered. The
3248
+ result would be an attacker-controlled form, complete with any
3249
+ event-handler attributes the caller passed in, handed back to
3250
+ the application unsanitized. Refuse to sanitize such a root
3251
+ the same way we refuse a forbidden tag. GHSA-r47g-fvhr-h676. */
3252
+ if (_isClobbered(dirty)) {
3253
+ /* Fail closed on a live clobbered root before throwing.
3254
+ _neutralizeRoot's reads are clobber-safe (cached getters); the
3255
+ form's non-clobbered descendants, e.g. an armed <img>, are scrubbed. */
3256
+ _neutralizeRoot(dirty);
3257
+ throw typeErrorCreate('root node is clobbered and cannot be sanitized in-place');
3258
+ }
3259
+ /* Sanitize attached shadow roots before the main iterator runs.
3260
+ The iterator does not descend into shadow trees. Same fail-closed
3261
+ barrier as the main walk (campaign-3 F2): a custom-element reaction
3262
+ inside a shadow root could abort this pre-pass before the walk runs,
3263
+ which would otherwise leave the entire live tree unsanitized. */
3264
+ try {
3265
+ _sanitizeAttachedShadowRoots(dirty);
3266
+ } catch (error) {
3267
+ _neutralizeRoot(dirty);
3268
+ throw error;
3269
+ }
3270
+ } else if (_isNode(dirty)) {
3271
+ /* If dirty is a DOM element, append to an empty document to avoid
3272
+ elements being stripped by the parser */
3273
+ body = _initDocument('<!---->');
3274
+ importedNode = body.ownerDocument.importNode(dirty, true);
3275
+ if (importedNode.nodeType === NODE_TYPE.element && importedNode.nodeName === 'BODY') {
3276
+ /* Node is already a body, use as is */
3277
+ body = importedNode;
3278
+ } else if (importedNode.nodeName === 'HTML') {
3279
+ body = importedNode;
3280
+ } else {
3281
+ // eslint-disable-next-line unicorn/prefer-dom-node-append
3282
+ body.appendChild(importedNode);
3283
+ }
3284
+ /* Clonable shadow roots are deep-cloned by importNode(); sanitize
3285
+ them before the main iterator runs, since the iterator does not
3286
+ descend into shadow trees. The walk routes every read through a
3287
+ cached prototype getter so clobbering descendants on a form root
3288
+ cannot hide a shadow host from this pass. */
3289
+ _sanitizeAttachedShadowRoots(importedNode);
3290
+ } else {
3291
+ /* Exit directly if we have nothing to do */
3292
+ if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT &&
3293
+ // eslint-disable-next-line unicorn/prefer-includes
3294
+ dirty.indexOf('<') === -1) {
3295
+ return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? _createTrustedHTML(dirty) : dirty;
3296
+ }
3297
+ /* Initialize the document to work on */
3298
+ body = _initDocument(dirty);
3299
+ /* Check we have a DOM node from the data */
3300
+ if (!body) {
3301
+ return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : '';
3302
+ }
573
3303
  }
574
- logConsole(configLogs, 'data', '', unreadcount);
575
- const favoriteValue = unreadcount && typeof unreadcount === 'object' && 'data' in unreadcount && !Array.isArray(unreadcount) ? unreadcount.data : unreadcount;
576
- if (type === 'get' && favoriteValue === true) {
577
- setColor('#ffcd38');
578
- } else if (type === 'set') {
579
- setColor('#ffcd38');
580
- localStorage.setItem('favoritessynch01', 'true');
581
- localStorage.setItem('favoritessynch02', 'true');
582
- window.dispatchEvent(new Event('favorites'));
583
- } else if (type === 'del') {
584
- setColor('');
585
- localStorage.setItem('favoritessynch01', 'true');
586
- localStorage.setItem('favoritessynch02', 'true');
587
- window.dispatchEvent(new Event('favorites'));
3304
+ /* Remove first element node (ours) if FORCE_BODY is set */
3305
+ if (body && FORCE_BODY) {
3306
+ _forceRemove(body.firstChild);
3307
+ }
3308
+ /* Get node iterator */
3309
+ const walkRoot = inPlace ? dirty : body;
3310
+ /* Now start iterating over the created document.
3311
+ The walk runs inside an exception barrier (campaign-3 F2): a re-entrant
3312
+ engine/custom-element mutation can detach a node mid-walk so
3313
+ `_forceRemove`'s parentless guard throws, aborting the loop. Without the
3314
+ barrier the caller's in-place tree would be left half-sanitized with the
3315
+ unvisited tail still armed. _createNodeIterator itself is inside the
3316
+ barrier too: constructing the iterator dereferences the root's document,
3317
+ and any failure there (e.g. an exotic/clobbered root) must still fail
3318
+ closed rather than skip the neutralize. On any throw we fail closed -
3319
+ strip the in-place root bare - then rethrow so the existing throw
3320
+ contract is preserved. (String/DOM-copy paths never return the partial
3321
+ body, so the propagating throw is already fail-closed there.) */
3322
+ try {
3323
+ const nodeIterator = _createNodeIterator(walkRoot);
3324
+ while (currentNode = nodeIterator.nextNode()) {
3325
+ /* Sanitize tags and elements */
3326
+ _sanitizeElements(currentNode, walkRoot);
3327
+ /* Check attributes next */
3328
+ _sanitizeAttributes(currentNode);
3329
+ /* Shadow DOM detected, sanitize it.
3330
+ Realm-safe check (GHSA-hpcv-96wg-7vj8): nodeType-based detection
3331
+ instead of instanceof, so foreign-realm <template>.content is
3332
+ walked correctly. */
3333
+ if (_isDocumentFragment(currentNode.content)) {
3334
+ _sanitizeShadowDOM2(currentNode.content);
3335
+ }
3336
+ }
3337
+ } catch (error) {
3338
+ if (inPlace) {
3339
+ _neutralizeRoot(dirty);
3340
+ /* Nodes _forceRemove'd earlier in the aborted walk are already
3341
+ detached from the root, so _neutralizeRoot's subtree pass does not
3342
+ reach them. Defuse them too, mirroring the success-path loop below. */
3343
+ arrayForEach(DOMPurify.removed, entry => {
3344
+ if (entry.element) {
3345
+ _neutralizeSubtree(entry.element);
3346
+ }
3347
+ });
3348
+ }
3349
+ throw error;
588
3350
  }
589
- setIsError(false);
590
- } catch (err) {
591
- setError(true);
592
- handleError$3(err, t, configLogs, setIsError, setMessageerror);
593
- } finally {
594
- setLoading(false);
595
- }
596
- };
597
- const serviceGetFavorites = async (fpHash = '', sessionID, postURL, cxauthxc, t, setPost, setIsError, setError, setMessageerror, setLoading, configLogs, ...rest) => {
598
- const visitorIdHash = await getOrSetFingerprint(fpHash);
599
- try {
600
- const requestData = {
601
- ...rest[0],
602
- sessionID,
603
- cxauthxc,
604
- postServerURL: postURL,
605
- authorization: true,
606
- fingerprint: visitorIdHash
607
- };
608
- const unreadcount = await getservice(requestData, configLogs);
609
- const responseData = unreadcount && typeof unreadcount === 'object' && 'data' in unreadcount && !Array.isArray(unreadcount) ? unreadcount.data : unreadcount;
610
- setPost(responseData);
611
- localStorage.setItem('favoritessynch03', JSON.stringify(responseData));
612
- logConsole(configLogs, 'data', '', unreadcount);
613
- setIsError(false);
614
- } catch (err) {
615
- setError(true);
616
- handleError$3(err, t, configLogs, setIsError, setMessageerror);
617
- } finally {
618
- setLoading(false);
619
- }
620
- };
621
-
622
- const defaultConfig$3 = {
623
- enableLogs: false,
624
- enableLogsError: false,
625
- enableLogsWarning: false,
626
- enableLogsInfo: false,
627
- enableLogsData: false,
628
- enableLogsDebug: false,
629
- developmentMode: false
630
- };
631
- const ConexysConfigContext = /*#__PURE__*/createContext(defaultConfig$3);
632
- const ConexysConfigProvider = ({
633
- children,
634
- config = {}
635
- }) => {
636
- const mergedConfig = {
637
- ...defaultConfig$3,
638
- ...config
3351
+ /* If we sanitized `dirty` in-place, return it. */
3352
+ if (inPlace) {
3353
+ /* Fail-closed completion of the audit-5 F1 fix: every node removed from
3354
+ the caller's live tree is detached but may still hold a queued
3355
+ resource-event handler that fires in page scope after we return. The
3356
+ move-hoist covers only disallowed-tag KEEP_CONTENT removals; strip the
3357
+ non-allow-listed attributes off every other removed subtree (clobber,
3358
+ mXSS, namespace, comments, KEEP_CONTENT:false, …) so those handlers are
3359
+ cancelled before any event can fire. Runs synchronously, pre-return. */
3360
+ arrayForEach(DOMPurify.removed, entry => {
3361
+ if (entry.element) {
3362
+ _neutralizeSubtree(entry.element);
3363
+ }
3364
+ });
3365
+ if (SAFE_FOR_TEMPLATES) {
3366
+ _scrubTemplateExpressions2(dirty);
3367
+ }
3368
+ return dirty;
3369
+ }
3370
+ /* Return sanitized string or DOM */
3371
+ if (RETURN_DOM) {
3372
+ if (SAFE_FOR_TEMPLATES) {
3373
+ _scrubTemplateExpressions2(body);
3374
+ }
3375
+ if (RETURN_DOM_FRAGMENT) {
3376
+ returnNode = createDocumentFragment.call(body.ownerDocument);
3377
+ while (body.firstChild) {
3378
+ // eslint-disable-next-line unicorn/prefer-dom-node-append
3379
+ returnNode.appendChild(body.firstChild);
3380
+ }
3381
+ } else {
3382
+ returnNode = body;
3383
+ }
3384
+ if (ALLOWED_ATTR.shadowroot || ALLOWED_ATTR.shadowrootmode) {
3385
+ /*
3386
+ AdoptNode() is not used because internal state is not reset
3387
+ (e.g. the past names map of a HTMLFormElement), this is safe
3388
+ in theory but we would rather not risk another attack vector.
3389
+ The state that is cloned by importNode() is explicitly defined
3390
+ by the specs.
3391
+ */
3392
+ returnNode = importNode.call(originalDocument, returnNode, true);
3393
+ }
3394
+ return returnNode;
3395
+ }
3396
+ let serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;
3397
+ /* Serialize doctype if allowed */
3398
+ if (WHOLE_DOCUMENT && ALLOWED_TAGS['!doctype'] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) {
3399
+ serializedHTML = '<!DOCTYPE ' + body.ownerDocument.doctype.name + '>\n' + serializedHTML;
3400
+ }
3401
+ /* Sanitize final string template-safe */
3402
+ if (SAFE_FOR_TEMPLATES) {
3403
+ serializedHTML = _stripTemplateExpressions(serializedHTML);
3404
+ }
3405
+ return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? _createTrustedHTML(serializedHTML) : serializedHTML;
3406
+ };
3407
+ DOMPurify.setConfig = function () {
3408
+ let cfg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
3409
+ _parseConfig(cfg);
3410
+ SET_CONFIG = true;
3411
+ SET_CONFIG_ALLOWED_TAGS = ALLOWED_TAGS;
3412
+ SET_CONFIG_ALLOWED_ATTR = ALLOWED_ATTR;
3413
+ };
3414
+ DOMPurify.clearConfig = function () {
3415
+ CONFIG = null;
3416
+ SET_CONFIG = false;
3417
+ SET_CONFIG_ALLOWED_TAGS = null;
3418
+ SET_CONFIG_ALLOWED_ATTR = null;
3419
+ // Drop any caller-supplied Trusted Types policy so it cannot poison later
3420
+ // `RETURN_TRUSTED_TYPE` output. The internal default policy (cached, and
3421
+ // never recreated — Trusted Types throws on duplicate names) is restored by
3422
+ // the next `_parseConfig`. See GHSA-vxr8-fq34-vvx9.
3423
+ trustedTypesPolicy = defaultTrustedTypesPolicy;
3424
+ emptyHTML = '';
3425
+ };
3426
+ DOMPurify.isValidAttribute = function (tag, attr, value) {
3427
+ /* Initialize shared config vars if necessary. */
3428
+ if (!CONFIG) {
3429
+ _parseConfig({});
3430
+ }
3431
+ const lcTag = transformCaseFunc(tag);
3432
+ const lcName = transformCaseFunc(attr);
3433
+ return _isValidAttribute(lcTag, lcName, value);
3434
+ };
3435
+ DOMPurify.addHook = function (entryPoint, hookFunction) {
3436
+ if (typeof hookFunction !== 'function') {
3437
+ return;
3438
+ }
3439
+ /* Reject unknown entry points. Without this, a non-hook key (e.g.
3440
+ * '__proto__') indexes off the prototype chain rather than a real
3441
+ * hook array, and arrayPush then writes to Object.prototype. Guard
3442
+ * with an own-property check against the known hook names. */
3443
+ if (!objectHasOwnProperty(hooks, entryPoint)) {
3444
+ return;
3445
+ }
3446
+ arrayPush(hooks[entryPoint], hookFunction);
639
3447
  };
640
- return /*#__PURE__*/React__default.createElement(ConexysConfigContext.Provider, {
641
- value: mergedConfig
642
- }, children);
643
- };
644
- const useConexysConfig = () => {
645
- return useContext(ConexysConfigContext);
646
- };
647
- const isDevelopmentMode = config => {
648
- return config.developmentMode;
649
- };
650
-
651
- const config$3 = {
652
- headers: {
653
- 'Content-Type': 'application/json'
654
- }
655
- };
656
- function AppDataSettings({
657
- keys
658
- }) {
659
- const configLogs = useConexysConfig();
660
- const postURL = Url + 'getsettings';
661
- const [post, setPost] = useState(null);
662
- const [error, setError] = useState(false);
663
- const hasFetched = useRef(false);
664
- const fetchData = useCallback(async () => {
665
- if (hasFetched.current) return;
666
- hasFetched.current = true;
667
- try {
668
- await serviceData(postURL, {
669
- keys: keys
670
- }, config$3, setPost, configLogs);
671
- } catch (err) {
672
- setError(true);
673
- logConsole(configLogs, 'error', 'Error fetching data:', err);
674
- console.error('Error fetching data:', err);
3448
+ DOMPurify.removeHook = function (entryPoint, hookFunction) {
3449
+ if (!objectHasOwnProperty(hooks, entryPoint)) {
3450
+ return undefined;
675
3451
  }
676
- }, []);
677
- useEffect(() => {
678
- fetchData();
679
- }, [fetchData]);
680
- if (!post) return null;
681
- return /*#__PURE__*/React__default.createElement(React__default.Fragment, null, error ? /*#__PURE__*/React__default.createElement("div", null, "Error loading data") : post);
3452
+ if (hookFunction !== undefined) {
3453
+ const index = arrayLastIndexOf(hooks[entryPoint], hookFunction);
3454
+ return index === -1 ? undefined : arraySplice(hooks[entryPoint], index, 1)[0];
3455
+ }
3456
+ return arrayPop(hooks[entryPoint]);
3457
+ };
3458
+ DOMPurify.removeHooks = function (entryPoint) {
3459
+ if (!objectHasOwnProperty(hooks, entryPoint)) {
3460
+ return;
3461
+ }
3462
+ hooks[entryPoint] = [];
3463
+ };
3464
+ DOMPurify.removeAllHooks = function () {
3465
+ hooks = _createHooksMap();
3466
+ };
3467
+ return DOMPurify;
3468
+ }
3469
+ var purify = createDOMPurify();
3470
+
3471
+ function sanitizeHtml(html) {
3472
+ if (!html) return '';
3473
+ return purify.sanitize(html);
682
3474
  }
683
3475
 
684
3476
  const config$2 = {
@@ -713,7 +3505,7 @@ function AppDataSettingsHTML({
713
3505
  if (!htmlString) return null;
714
3506
  return /*#__PURE__*/React__default.createElement(React__default.Fragment, null, error ? (/*#__PURE__*/React__default.createElement("div", null, "Error loading data")) : (/*#__PURE__*/React__default.createElement("div", {
715
3507
  dangerouslySetInnerHTML: {
716
- __html: htmlString
3508
+ __html: sanitizeHtml(htmlString)
717
3509
  }
718
3510
  })));
719
3511
  }
@@ -807,14 +3599,18 @@ const postFormService$1 = async (datauser, configLogs) => {
807
3599
  }
808
3600
  }
809
3601
  const dataload = [restData, valueToPush];
3602
+ const xSessionType = authStorage.getSessionTypeValue(configLogs);
810
3603
  let config;
811
3604
  let datasend;
812
3605
  if (authorization === true) {
813
3606
  config = {
3607
+ withCredentials: true,
814
3608
  headers: {
815
3609
  Authorization: `Bearer ${datauser.cxauthxc}`,
3610
+ 'X-CSRF-Token': authStorage.getCsrfToken() || '',
816
3611
  'X-Session-ID': datauser.sessionID || '',
817
3612
  'X-Fingerprint': datauser.fingerprint || '',
3613
+ 'X-Session-Type': xSessionType,
818
3614
  'Content-Type': 'application/json'
819
3615
  }
820
3616
  };
@@ -834,7 +3630,9 @@ const postFormService$1 = async (datauser, configLogs) => {
834
3630
  }
835
3631
  } else {
836
3632
  config = {
3633
+ withCredentials: true,
837
3634
  headers: {
3635
+ 'X-CSRF-Token': authStorage.getCsrfToken() || '',
838
3636
  'Content-Type': 'application/json'
839
3637
  }
840
3638
  };
@@ -888,14 +3686,18 @@ const patchFormService$1 = async (datauser, configLogs) => {
888
3686
  }
889
3687
  }
890
3688
  const dataload = [restData, valueToPush];
3689
+ const xSessionType = authStorage.getSessionTypeValue(configLogs);
891
3690
  let config;
892
3691
  let datasend;
893
3692
  if (authorization === true) {
894
3693
  config = {
3694
+ withCredentials: true,
895
3695
  headers: {
896
3696
  Authorization: `Bearer ${datauser.cxauthxc}`,
3697
+ 'X-CSRF-Token': authStorage.getCsrfToken() || '',
897
3698
  'X-Session-ID': datauser.sessionID || '',
898
3699
  'X-Fingerprint': datauser.fingerprint || '',
3700
+ 'X-Session-Type': xSessionType,
899
3701
  'Content-Type': 'application/json'
900
3702
  }
901
3703
  };
@@ -915,7 +3717,9 @@ const patchFormService$1 = async (datauser, configLogs) => {
915
3717
  }
916
3718
  } else {
917
3719
  config = {
3720
+ withCredentials: true,
918
3721
  headers: {
3722
+ 'X-CSRF-Token': authStorage.getCsrfToken() || '',
919
3723
  'Content-Type': 'application/json'
920
3724
  }
921
3725
  };
@@ -952,11 +3756,15 @@ const deleteFormService$1 = async (datauser, configLogs) => {
952
3756
  ...datasend
953
3757
  } = datauser;
954
3758
  const logs = configLogs || defaultConfig$2;
3759
+ const xSessionType = authStorage.getSessionTypeValue(logs);
955
3760
  const config = {
3761
+ withCredentials: true,
956
3762
  headers: {
957
3763
  Authorization: `Bearer ${cxauthxc}`,
3764
+ 'X-CSRF-Token': authStorage.getCsrfToken() || '',
958
3765
  'X-Session-ID': datauser.sessionID || '',
959
3766
  'X-Fingerprint': datauser.fingerprint || '',
3767
+ 'X-Session-Type': xSessionType,
960
3768
  'Content-Type': 'application/json'
961
3769
  }
962
3770
  };
@@ -995,11 +3803,15 @@ const restoreFormService$1 = async (datauser, configLogs) => {
995
3803
  ...datasend
996
3804
  } = datauser;
997
3805
  const logs = configLogs || defaultConfig$1;
3806
+ const xSessionType = authStorage.getSessionTypeValue(logs);
998
3807
  const config = {
3808
+ withCredentials: true,
999
3809
  headers: {
1000
3810
  Authorization: `Bearer ${cxauthxc}`,
3811
+ 'X-CSRF-Token': authStorage.getCsrfToken() || '',
1001
3812
  'X-Session-ID': datauser.sessionID || '',
1002
3813
  'X-Fingerprint': datauser.fingerprint || '',
3814
+ 'X-Session-Type': xSessionType,
1003
3815
  'Content-Type': 'application/json'
1004
3816
  }
1005
3817
  };
@@ -1018,7 +3830,7 @@ var restoreFormService = {
1018
3830
  restoreFormService: restoreFormService$1
1019
3831
  };
1020
3832
 
1021
- const useCustomForm$3 = (fpHash, postServerURL, getServerURL, deleteServerURL, id, restoreServerURL, feedback, method = 'post', restoreMethod = 'post', fetchMethod = 'post') => {
3833
+ const useCustomForm$3 = (fpHash, postServerURL, getServerURL, deleteServerURL, id, restoreServerURL, feedback, method = 'post', restoreMethod = 'post', fetchMethod = 'post', allowEmptyIdFetch = false) => {
1022
3834
  const configLogs = useConexysConfig();
1023
3835
  const [t] = useTranslation('global');
1024
3836
  const MySwal = withReactContent(SweetAlert2);
@@ -1030,16 +3842,19 @@ const useCustomForm$3 = (fpHash, postServerURL, getServerURL, deleteServerURL, i
1030
3842
  const [error, setError] = useState(false);
1031
3843
  const cxauthxc = authStorage.getAuthToken(configLogs) || '';
1032
3844
  const sessionID = authStorage.getSessionId(configLogs) || '';
3845
+ const xSessionType = authStorage.getSessionTypeValue(configLogs);
1033
3846
  const iditem = id;
1034
3847
  const authorization = true;
1035
3848
  const updateDataUser = async visitorIdHash => {
1036
3849
  const getProfile = Url + 'getprofile';
1037
3850
  try {
1038
3851
  const response = await axios.get(getProfile, {
3852
+ withCredentials: true,
1039
3853
  headers: {
1040
3854
  Authorization: `Bearer ${cxauthxc}`,
1041
3855
  'X-Session-ID': sessionID,
1042
3856
  'X-Fingerprint': visitorIdHash,
3857
+ 'X-Session-Type': xSessionType,
1043
3858
  'Content-Type': 'application/json'
1044
3859
  }
1045
3860
  });
@@ -1185,6 +4000,7 @@ const useCustomForm$3 = (fpHash, postServerURL, getServerURL, deleteServerURL, i
1185
4000
  Authorization: `Bearer ${cxauthxc}`,
1186
4001
  'X-Session-ID': sessionID,
1187
4002
  'X-Fingerprint': fpHash,
4003
+ 'X-Session-Type': xSessionType,
1188
4004
  'Content-Type': 'application/json'
1189
4005
  }
1190
4006
  }), [cxauthxc, sessionID, fpHash]);
@@ -1197,7 +4013,7 @@ const useCustomForm$3 = (fpHash, postServerURL, getServerURL, deleteServerURL, i
1197
4013
  useEffect(() => {
1198
4014
  const setFp = async () => {
1199
4015
  setCheckdata(false);
1200
- if (id !== '') {
4016
+ if (id !== '' || allowEmptyIdFetch) {
1201
4017
  const visitorIdHash = await getOrSetFingerprint(fpHash, configLogs);
1202
4018
  const key = {
1203
4019
  sessionID: sessionID,
@@ -1207,11 +4023,21 @@ const useCustomForm$3 = (fpHash, postServerURL, getServerURL, deleteServerURL, i
1207
4023
  try {
1208
4024
  let response;
1209
4025
  if (fetchMethod === 'get') {
1210
- const url = getServerURL + id;
1211
- response = await axios.get(url, config);
4026
+ const url = id !== '' ? getServerURL + id : getServerURL;
4027
+ response = await axios.get(url, {
4028
+ ...config,
4029
+ withCredentials: true
4030
+ });
1212
4031
  logConsole(configLogs, 'info', '[Request] ', url);
1213
4032
  } else {
1214
- response = await axios.post(getServerURL, key, config);
4033
+ response = await axios.post(getServerURL, key, {
4034
+ ...config,
4035
+ withCredentials: true,
4036
+ headers: {
4037
+ ...(config?.headers || {}),
4038
+ 'X-CSRF-Token': authStorage.getCsrfToken() || ''
4039
+ }
4040
+ });
1215
4041
  logConsole(configLogs, 'info', '[Request] ', getServerURL);
1216
4042
  }
1217
4043
  const responseData = response.data;
@@ -1227,7 +4053,7 @@ const useCustomForm$3 = (fpHash, postServerURL, getServerURL, deleteServerURL, i
1227
4053
  }
1228
4054
  };
1229
4055
  setFp();
1230
- }, [id]);
4056
+ }, [id, allowEmptyIdFetch]);
1231
4057
  return {
1232
4058
  handleFormSubmit,
1233
4059
  handleInputChange,
@@ -1256,17 +4082,20 @@ function AppFormFields({
1256
4082
  permission,
1257
4083
  show,
1258
4084
  feedback,
1259
- method = 'post'
4085
+ method = 'post',
4086
+ allowEmptyIdFetch = false
1260
4087
  }) {
1261
4088
  const configLogs = useConexysConfig();
1262
4089
  const [t] = useTranslation('global');
1263
4090
  const authTokens = authStorage.getAuthToken(configLogs) || '';
1264
4091
  const authTokensSes = authStorage.getSessionId(configLogs) || '';
4092
+ const xSessionType = authStorage.getSessionTypeValue(configLogs);
1265
4093
  const config = useMemo(() => ({
1266
4094
  headers: {
1267
4095
  Authorization: `Bearer ${authTokens}`,
1268
4096
  'X-Session-ID': authTokensSes,
1269
4097
  'X-Fingerprint': fpHash,
4098
+ 'X-Session-Type': xSessionType,
1270
4099
  'Content-Type': 'application/json'
1271
4100
  }
1272
4101
  }), [authTokens, authTokensSes, fpHash]);
@@ -1293,7 +4122,7 @@ function AppFormFields({
1293
4122
  formInputs,
1294
4123
  handleInputChange,
1295
4124
  handleFormSubmit
1296
- } = useCustomForm$3(fpHash, postServerURL1, getServerURL1, deleteServerURL1, id1, '', feedback, method, 'post', 'get');
4125
+ } = useCustomForm$3(fpHash, postServerURL1, getServerURL1, deleteServerURL1, id1, '', feedback, method, 'post', 'get', allowEmptyIdFetch);
1297
4126
  if (!post) return null;
1298
4127
  const dataform = JSON.parse(post.data);
1299
4128
  let permissionstatus;
@@ -1456,6 +4285,7 @@ const useCustomForm$2 = (postServerURL, setAuth, message, dependencies = {}) =>
1456
4285
  const {
1457
4286
  setAuthTokens
1458
4287
  } = typeof externalUseAuth === 'function' ? externalUseAuth() : externalUseAuth || useAuth();
4288
+ const xSessionType = authStorage.getSessionTypeValue(configLogs);
1459
4289
  const [t] = useTranslation('global');
1460
4290
  const MySwal = withReactContent(SweetAlert2);
1461
4291
  const [formInputs, setFormInputs] = useState({});
@@ -1512,11 +4342,14 @@ const useCustomForm$2 = (postServerURL, setAuth, message, dependencies = {}) =>
1512
4342
  try {
1513
4343
  const postServerURL2 = Url + 'authTwostep';
1514
4344
  const config = {
4345
+ withCredentials: true,
1515
4346
  headers: {
1516
4347
  Authorization: `Bearer ${dataform.auth}`,
1517
4348
  'X-Session-ID': dataform.sessionid,
1518
4349
  'X-Fingerprint': dataform.fingerprint || visitorId,
1519
- 'Content-Type': 'application/json'
4350
+ 'X-Session-Type': xSessionType,
4351
+ 'Content-Type': 'application/json',
4352
+ 'X-CSRF-Token': authStorage.getCsrfToken() || ''
1520
4353
  }
1521
4354
  };
1522
4355
  const dataload = [dataform, visitorId, login];
@@ -1632,11 +4465,17 @@ const getServiceBasic = async (fpHash = '', sessionID, baseURL, config, setData,
1632
4465
  sessionID,
1633
4466
  fingerprint: visitorIdHash
1634
4467
  };
4468
+ const xSessionType = authStorage.getSessionTypeValue(configLogs);
1635
4469
  logConsole(configLogs, 'debug', '[Params] ', key);
1636
4470
  try {
1637
4471
  const response = await axios.get(baseURL, {
1638
4472
  ...config,
1639
- params: key
4473
+ withCredentials: true,
4474
+ params: key,
4475
+ headers: {
4476
+ ...(config?.headers || {}),
4477
+ 'X-Session-Type': xSessionType
4478
+ }
1640
4479
  });
1641
4480
  logConsole(configLogs, 'info', '[Request] ', baseURL);
1642
4481
  logConsole(configLogs, 'data', '', response.data);
@@ -1676,7 +4515,12 @@ const getServiceData = async (baseURL, params, config, setData, configLogs) => {
1676
4515
  try {
1677
4516
  const response = await axios.get(baseURL, {
1678
4517
  ...config,
1679
- params
4518
+ withCredentials: true,
4519
+ params,
4520
+ headers: {
4521
+ ...(config?.headers || {}),
4522
+ 'X-Session-Type': authStorage.getSessionTypeValue(configLogs)
4523
+ }
1680
4524
  });
1681
4525
  logConsole(configLogs, 'debug', '[Params] ', params);
1682
4526
  logConsole(configLogs, 'info', '[Request] ', baseURL);
@@ -1706,11 +4550,13 @@ function AppFormFieldsNoUser({
1706
4550
  const [fingerprint, setFingerprint] = useState('');
1707
4551
  const authTokens = authStorage.getAuthToken(configLogs) || '';
1708
4552
  const authTokensSes = authStorage.getSessionId(configLogs) || '';
4553
+ const xSessionType = authStorage.getSessionTypeValue(configLogs);
1709
4554
  const config = useMemo(() => ({
1710
4555
  headers: {
1711
4556
  Authorization: `Bearer ${authTokens}`,
1712
4557
  'X-Session-ID': authTokensSes,
1713
4558
  'X-Fingerprint': fingerprint,
4559
+ 'X-Session-Type': xSessionType,
1714
4560
  'Content-Type': 'application/json'
1715
4561
  }
1716
4562
  }), [authTokens, authTokensSes, fingerprint]);
@@ -1824,11 +4670,13 @@ function AppFormFieldsTable({
1824
4670
  const [t] = useTranslation('global');
1825
4671
  const authTokens = authStorage.getAuthToken(configLogs) || '';
1826
4672
  const authTokensSes = authStorage.getSessionId(configLogs) || '';
4673
+ const xSessionType = authStorage.getSessionTypeValue(configLogs);
1827
4674
  useMemo(() => ({
1828
4675
  headers: {
1829
4676
  Authorization: `Bearer ${authTokens}`,
1830
4677
  'X-Session-ID': authTokensSes,
1831
4678
  'X-Fingerprint': fpHash,
4679
+ 'X-Session-Type': xSessionType,
1832
4680
  'Content-Type': 'application/json'
1833
4681
  }
1834
4682
  }), [authTokens, authTokensSes, fpHash]);
@@ -1952,7 +4800,9 @@ function AppFormFieldsTable({
1952
4800
  maxLength: block.maxlength || block.validate && block.validate.maxLength,
1953
4801
  pattern: block.pattern || block.validate && block.validate.pattern
1954
4802
  },
1955
- items: block.items || []
4803
+ items: block.items || [],
4804
+ itemID: id1,
4805
+ adminCheck: show === 'admin'
1956
4806
  }, nouser || '')), additionalfields1.content.body.map(block => RenderForm({
1957
4807
  component: block.component,
1958
4808
  type: block.type,
@@ -1981,7 +4831,9 @@ function AppFormFieldsTable({
1981
4831
  maxLength: block.maxlength || block.validate && block.validate.maxLength,
1982
4832
  pattern: block.pattern || block.validate && block.validate.pattern
1983
4833
  },
1984
- items: block.items || []
4834
+ items: block.items || [],
4835
+ itemID: id1,
4836
+ adminCheck: show === 'admin'
1985
4837
  }, nouser || '')));
1986
4838
  }
1987
4839
 
@@ -5800,11 +8652,9 @@ function GenIcon(data) {
5800
8652
  }
5801
8653
  function IconBase(props) {
5802
8654
  var elem = conf => {
5803
- var {
5804
- attr,
5805
- size,
5806
- title
5807
- } = props,
8655
+ var attr = props.attr,
8656
+ size = props.size,
8657
+ title = props.title,
5808
8658
  svgProps = _objectWithoutProperties(props, _excluded);
5809
8659
  var computedSize = size || conf.size || "1em";
5810
8660
  var className;
@@ -6148,6 +8998,9 @@ function Mailbox({
6148
8998
  theObj,
6149
8999
  t
6150
9000
  }) {
9001
+ const safeObj = {
9002
+ __html: sanitizeHtml(theObj.__html)
9003
+ };
6151
9004
  return /*#__PURE__*/React__default.createElement("div", {
6152
9005
  className: "mailbox-email",
6153
9006
  style: {
@@ -6174,7 +9027,7 @@ function Mailbox({
6174
9027
  }), ' ', msgTarget)), /*#__PURE__*/React__default.createElement("div", {
6175
9028
  className: "card-body"
6176
9029
  }, /*#__PURE__*/React__default.createElement("div", {
6177
- dangerouslySetInnerHTML: theObj
9030
+ dangerouslySetInnerHTML: safeObj
6178
9031
  })), /*#__PURE__*/React__default.createElement("div", {
6179
9032
  className: "card-footer"
6180
9033
  }, /*#__PURE__*/React__default.createElement("p", {
@@ -6226,7 +9079,7 @@ function MailTemplateWidget({
6226
9079
  setIsError(false);
6227
9080
  }, []);
6228
9081
  const theObj = {
6229
- __html: getthemedata.html || ''
9082
+ __html: sanitizeHtml(getthemedata.html) || ''
6230
9083
  };
6231
9084
  logConsole(configLogs, 'data', '', getthemedata);
6232
9085
  return /*#__PURE__*/React__default.createElement(React__default.Fragment, null, /*#__PURE__*/React__default.createElement(Loading, {
@@ -6765,7 +9618,7 @@ function UserWidget({
6765
9618
  setIsError(false);
6766
9619
  };
6767
9620
  const theObj = {
6768
- __html: datauserdata.biography || ''
9621
+ __html: sanitizeHtml(datauserdata.biography) || ''
6769
9622
  };
6770
9623
  return /*#__PURE__*/React__default.createElement(React__default.Fragment, null, /*#__PURE__*/React__default.createElement(Loading, {
6771
9624
  error: error,
@@ -6782,7 +9635,7 @@ function UserWidget({
6782
9635
  className: "solid short"
6783
9636
  }), /*#__PURE__*/React__default.createElement("ul", {
6784
9637
  className: "simple-todo-list mt-3"
6785
- }, /*#__PURE__*/React__default.createElement("li", null, /*#__PURE__*/React__default.createElement("b", null, t('login.username')), ": ", datauserdata.username), /*#__PURE__*/React__default.createElement("li", null, /*#__PURE__*/React__default.createElement("b", null, t('login.email')), ": ", datauserdata.email), /*#__PURE__*/React__default.createElement("li", null, /*#__PURE__*/React__default.createElement("b", null, t('login.name')), ": ", datauserdata.name), /*#__PURE__*/React__default.createElement("li", null, /*#__PURE__*/React__default.createElement("b", null, t('login.lastname')), ": ", datauserdata.lastname), /*#__PURE__*/React__default.createElement("li", null, /*#__PURE__*/React__default.createElement("b", null, t('User.type_of_user')), ": ", datausertype)))), /*#__PURE__*/React__default.createElement(Snackbar, {
9638
+ }, /*#__PURE__*/React__default.createElement("li", null, /*#__PURE__*/React__default.createElement("b", null, t('login.username')), ": ", datauserdata.username), /*#__PURE__*/React__default.createElement("li", null, /*#__PURE__*/React__default.createElement("b", null, t('login.name')), ": ", datauserdata.name), /*#__PURE__*/React__default.createElement("li", null, /*#__PURE__*/React__default.createElement("b", null, t('login.lastname')), ": ", datauserdata.lastname), /*#__PURE__*/React__default.createElement("li", null, /*#__PURE__*/React__default.createElement("b", null, t('User.type_of_user')), ": ", datausertype)))), /*#__PURE__*/React__default.createElement(Snackbar, {
6786
9639
  open: isError,
6787
9640
  autoHideDuration: 6000,
6788
9641
  onClose: handleClose,
@@ -6817,16 +9670,32 @@ const AppHeaderPage = ({
6817
9670
  const [color, setColor] = useState('');
6818
9671
  const [getfavorites, setFavoritesList] = useState('');
6819
9672
  const hasFetched = useRef(false);
6820
- const cxauthxc = authStorage.getAuthToken(configLogs) || '';
6821
- const sessionID = authStorage.getSessionId(configLogs) || '';
9673
+ const [token, setToken] = useState('');
9674
+ const [sessionId, setSessionId] = useState('');
9675
+ const [authReady, setAuthReady] = useState(false);
9676
+ useEffect(() => {
9677
+ let cancelled = false;
9678
+ authStorage.initialize(configLogs).then(() => {
9679
+ if (cancelled) return;
9680
+ setToken(authStorage.getAuthToken(configLogs) || '');
9681
+ setSessionId(authStorage.getSessionId(configLogs) || '');
9682
+ setAuthReady(true);
9683
+ });
9684
+ return () => {
9685
+ cancelled = true;
9686
+ };
9687
+ }, []);
9688
+ const cxauthxc = token;
9689
+ const sessionID = sessionId;
6822
9690
  const hash = window.location.pathname;
6823
9691
  useEffect(() => {
9692
+ if (!authReady) return;
6824
9693
  if (hasFetched.current) return;
6825
9694
  hasFetched.current = true;
6826
9695
  serviceFavorites('get', fpHash, sessionID, 'getfavorites', cxauthxc, t, setFavoritesList, setIsError, setError, setMessageerror, setLoading, setColor, configLogs, {
6827
9696
  url: hash
6828
9697
  });
6829
- }, []);
9698
+ }, [authReady, fpHash, sessionID, cxauthxc, t, hash, configLogs]);
6830
9699
  const handleClickMenuRigth = useCallback(() => {
6831
9700
  setOpenMenuRigth(prev => !prev);
6832
9701
  const themeElement = document.getElementById('themeclass');
@@ -7683,7 +10552,7 @@ const Info = ({
7683
10552
  texthtml
7684
10553
  } = block;
7685
10554
  const theObj = {
7686
- __html: texthtml
10555
+ __html: sanitizeHtml(texthtml)
7687
10556
  };
7688
10557
  return /*#__PURE__*/React__default.createElement("div", {
7689
10558
  className: ref
@@ -7699,9 +10568,9 @@ const Info = ({
7699
10568
 
7700
10569
  // THIS FILE IS AUTO GENERATED
7701
10570
  function MdCloudUpload (props) {
7702
- return GenIcon({"attr":{"viewBox":"0 0 24 24"},"child":[{"tag":"path","attr":{"fill":"none","d":"M0 0h24v24H0z"},"child":[]},{"tag":"path","attr":{"d":"M19.35 10.04A7.49 7.49 0 0 0 12 4C9.11 4 6.6 5.64 5.35 8.04A5.994 5.994 0 0 0 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM14 13v4h-4v-4H7l5-5 5 5h-3z"},"child":[]}]})(props);
10571
+ return GenIcon({"attr":{"viewBox":"0 0 24 24"},"child":[{"tag":"path","attr":{"fill":"none","d":"M0 0h24v24H0z"},"child":[]},{"tag":"path","attr":{"d":"M19.35 10.04A7.49 7.49 0 0 0 12 4C9.11 4 6.6 5.64 5.35 8.04A5.994 5.994 0 0 0 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96M14 13v4h-4v-4H7l5-5 5 5z"},"child":[]}]})(props);
7703
10572
  }function MdDelete (props) {
7704
- return GenIcon({"attr":{"viewBox":"0 0 24 24"},"child":[{"tag":"path","attr":{"fill":"none","d":"M0 0h24v24H0z"},"child":[]},{"tag":"path","attr":{"d":"M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"},"child":[]}]})(props);
10573
+ return GenIcon({"attr":{"viewBox":"0 0 24 24"},"child":[{"tag":"path","attr":{"fill":"none","d":"M0 0h24v24H0z"},"child":[]},{"tag":"path","attr":{"d":"M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6zM19 4h-3.5l-1-1h-5l-1 1H5v2h14z"},"child":[]}]})(props);
7705
10574
  }
7706
10575
 
7707
10576
  // THIS FILE IS AUTO GENERATED
@@ -8013,6 +10882,8 @@ const InputPassword = ({
8013
10882
 
8014
10883
  const postURLusername = Url + 'checkusername';
8015
10884
  const postURLmail = Url + 'checkmail';
10885
+ const postURLAdminUsername = Url + 'admincheckusername';
10886
+ const postURLAdminMail = Url + 'admincheckmail';
8016
10887
  const config$1 = {
8017
10888
  headers: {
8018
10889
  'Content-Type': 'application/json'
@@ -8030,7 +10901,14 @@ const checkExistsUsername = async ({
8030
10901
  try {
8031
10902
  const {
8032
10903
  data
8033
- } = await axios.post(postURLusername, requestData, config$1);
10904
+ } = await axios.post(postURLusername, requestData, {
10905
+ ...config$1,
10906
+ withCredentials: true,
10907
+ headers: {
10908
+ ...(config$1?.headers || {}),
10909
+ 'X-CSRF-Token': authStorage.getCsrfToken() || ''
10910
+ }
10911
+ });
8034
10912
  logConsole(configLogs, 'info', '[Request] ', postURLusername);
8035
10913
  logConsole(configLogs, 'data', '', data.result);
8036
10914
  return data.result === 'Valid';
@@ -8052,7 +10930,14 @@ const checkExistsMail = async ({
8052
10930
  try {
8053
10931
  const {
8054
10932
  data
8055
- } = await axios.post(postURLmail, requestData, config$1);
10933
+ } = await axios.post(postURLmail, requestData, {
10934
+ ...config$1,
10935
+ withCredentials: true,
10936
+ headers: {
10937
+ ...(config$1?.headers || {}),
10938
+ 'X-CSRF-Token': authStorage.getCsrfToken() || ''
10939
+ }
10940
+ });
8056
10941
  logConsole(configLogs, 'info', '[Request] ', postURLmail);
8057
10942
  logConsole(configLogs, 'data', '', data.result);
8058
10943
  return data.result === 'Valid';
@@ -8062,6 +10947,70 @@ const checkExistsMail = async ({
8062
10947
  return false;
8063
10948
  }
8064
10949
  };
10950
+ const checkExistsUsernameAdmin = async ({
10951
+ username,
10952
+ itemID
10953
+ }, configLogs) => {
10954
+ const requestData = {
10955
+ username,
10956
+ itemID
10957
+ };
10958
+ logConsole(configLogs, 'debug', '[Payload admincheckusername] ', requestData);
10959
+ try {
10960
+ const {
10961
+ data
10962
+ } = await axios.post(postURLAdminUsername, requestData, {
10963
+ ...config$1,
10964
+ withCredentials: true,
10965
+ headers: {
10966
+ ...(config$1?.headers || {}),
10967
+ 'X-CSRF-Token': authStorage.getCsrfToken() || ''
10968
+ }
10969
+ });
10970
+ logConsole(configLogs, 'info', '[Request] ', postURLAdminUsername);
10971
+ logConsole(configLogs, 'data', '', data);
10972
+ return data;
10973
+ } catch (err) {
10974
+ logConsole(configLogs, 'error', '', err);
10975
+ console.error(err);
10976
+ return {
10977
+ available: false,
10978
+ isCurrent: false
10979
+ };
10980
+ }
10981
+ };
10982
+ const checkExistsMailAdmin = async ({
10983
+ email,
10984
+ itemID
10985
+ }, configLogs) => {
10986
+ const requestData = {
10987
+ email,
10988
+ itemID
10989
+ };
10990
+ logConsole(configLogs, 'debug', '[Payload admincheckmail] ', requestData);
10991
+ try {
10992
+ const {
10993
+ data
10994
+ } = await axios.post(postURLAdminMail, requestData, {
10995
+ ...config$1,
10996
+ withCredentials: true,
10997
+ headers: {
10998
+ ...(config$1?.headers || {}),
10999
+ 'X-CSRF-Token': authStorage.getCsrfToken() || ''
11000
+ }
11001
+ });
11002
+ logConsole(configLogs, 'info', '[Request] ', postURLAdminMail);
11003
+ logConsole(configLogs, 'data', '', data);
11004
+ return data;
11005
+ } catch (err) {
11006
+ logConsole(configLogs, 'error', '', err);
11007
+ console.error(err);
11008
+ return {
11009
+ available: false,
11010
+ isCurrent: false
11011
+ };
11012
+ }
11013
+ };
8065
11014
 
8066
11015
  const InputText = /*#__PURE__*/React__default.memo(({
8067
11016
  block
@@ -8071,7 +11020,7 @@ const InputText = /*#__PURE__*/React__default.memo(({
8071
11020
  const [errors, setError] = useState(false);
8072
11021
  const [texterror, setTextError] = useState('');
8073
11022
  const handleInputBlur = useCallback(async event => {
8074
- const session = localStorage.getItem('cx_session') || '';
11023
+ const session = authStorage.getSessionId(configLogs) || '';
8075
11024
  const value = event.target.value;
8076
11025
  const setErrorState = (error, message) => {
8077
11026
  setError(error);
@@ -8080,22 +11029,44 @@ const InputText = /*#__PURE__*/React__default.memo(({
8080
11029
  };
8081
11030
  try {
8082
11031
  if (block.validate.check === 'email' && value) {
8083
- const mailexist = await checkExistsMail({
8084
- email: value,
8085
- sessionID: session
8086
- }, configLogs);
8087
- if (!mailexist) {
8088
- setErrorState(true, t('error.email_already_exists'));
8089
- return;
11032
+ if (block.adminCheck) {
11033
+ const mailAdmin = await checkExistsMailAdmin({
11034
+ email: value,
11035
+ itemID: block.itemID
11036
+ }, configLogs);
11037
+ if (!mailAdmin.available && !mailAdmin.isCurrent) {
11038
+ setErrorState(true, t('error.email_already_exists'));
11039
+ return;
11040
+ }
11041
+ } else {
11042
+ const mailexist = await checkExistsMail({
11043
+ email: value,
11044
+ sessionID: session
11045
+ }, configLogs);
11046
+ if (!mailexist) {
11047
+ setErrorState(true, t('error.email_already_exists'));
11048
+ return;
11049
+ }
8090
11050
  }
8091
11051
  } else if (block.validate.check === 'username' && value) {
8092
- const usernameExist = await checkExistsUsername({
8093
- username: value,
8094
- sessionID: session
8095
- }, configLogs);
8096
- if (!usernameExist) {
8097
- setErrorState(true, t('error.username_is_not_valid'));
8098
- return;
11052
+ if (block.adminCheck) {
11053
+ const usernameAdmin = await checkExistsUsernameAdmin({
11054
+ username: value,
11055
+ itemID: block.itemID
11056
+ }, configLogs);
11057
+ if (!usernameAdmin.available && !usernameAdmin.isCurrent) {
11058
+ setErrorState(true, t('error.username_already_exists'));
11059
+ return;
11060
+ }
11061
+ } else {
11062
+ const usernameExist = await checkExistsUsername({
11063
+ username: value,
11064
+ sessionID: session
11065
+ }, configLogs);
11066
+ if (!usernameExist) {
11067
+ setErrorState(true, t('error.username_is_not_valid'));
11068
+ return;
11069
+ }
8099
11070
  }
8100
11071
  }
8101
11072
  if (block.validate.minLength && value.length < block.validate.minLength) {
@@ -8194,6 +11165,8 @@ const InputWYSIWYG = /*#__PURE__*/React__default.memo(({
8194
11165
  const editor = useRef(null);
8195
11166
  const config = useMemo(() => ({
8196
11167
  readonly: false,
11168
+ toolbarAdaptive: false,
11169
+ allowTags: ['p', 'br', 'b', 'strong', 'i', 'em', 'u', 's', 'ul', 'ol', 'li', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'code', 'pre', 'a', 'img', 'hr', 'table', 'thead', 'tbody', 'tr', 'th', 'td', 'div', 'span'],
8197
11170
  placeholder: textEditor && textEditor !== '<p><br></p>' || block.value && block.value !== '<p><br></p>' ? '' : t('general.start_typings') || 'Start typings...',
8198
11171
  language: t('language.name')
8199
11172
  }), [t, textEditor, block.value]);
@@ -8627,7 +11600,10 @@ const LanguageSet = () => {
8627
11600
  hasFetched.current = true;
8628
11601
  const fetchLanguages = async () => {
8629
11602
  try {
8630
- const response = await axios.get(postURL, config);
11603
+ const response = await axios.get(postURL, {
11604
+ ...config,
11605
+ withCredentials: true
11606
+ });
8631
11607
  logConsole(configLogs, 'info', '[Request] ', postURL);
8632
11608
  const langData = Array.isArray(response.data) ? {
8633
11609
  data: response.data
@@ -9690,19 +12666,25 @@ const postFormServiceGetPost$1 = async (datauser, configLogs) => {
9690
12666
  formData.append('iditem', iditem);
9691
12667
  formData.append('sessionID', sessionID);
9692
12668
  formData.append('fingerprint', fingerprint);
12669
+ const xSessionType = authStorage.getSessionTypeValue(configLogs || defaultConfig);
9693
12670
  let config;
9694
12671
  if (authorization === true) {
9695
12672
  config = {
12673
+ withCredentials: true,
9696
12674
  headers: {
9697
12675
  Authorization: `Bearer ${cxauthxc}`,
12676
+ 'X-CSRF-Token': authStorage.getCsrfToken() || '',
9698
12677
  'X-Session-ID': sessionID,
9699
12678
  'X-Fingerprint': fingerprint,
12679
+ 'X-Session-Type': xSessionType,
9700
12680
  'Content-Type': 'multipart/form-data'
9701
12681
  }
9702
12682
  };
9703
12683
  } else {
9704
12684
  config = {
12685
+ withCredentials: true,
9705
12686
  headers: {
12687
+ 'X-CSRF-Token': authStorage.getCsrfToken() || '',
9706
12688
  'Content-Type': 'multipart/form-data'
9707
12689
  }
9708
12690
  };
@@ -9738,6 +12720,7 @@ const useCustomForm$1 = (fpHash, postServerURL, getServerURL, deleteServerURL, i
9738
12720
  const [error, setError] = useState(false);
9739
12721
  const cxauthxc = authStorage.getAuthToken(configLogs) || '';
9740
12722
  const sessionID = authStorage.getSessionId(configLogs) || '';
12723
+ const xSessionType = authStorage.getSessionTypeValue(configLogs);
9741
12724
  const iditem = id;
9742
12725
  const authorization = true;
9743
12726
  const handleFormSubmit = async event => {
@@ -9859,6 +12842,7 @@ const useCustomForm$1 = (fpHash, postServerURL, getServerURL, deleteServerURL, i
9859
12842
  Authorization: `Bearer ${cxauthxc}`,
9860
12843
  'X-Session-ID': sessionID,
9861
12844
  'X-Fingerprint': fpHash,
12845
+ 'X-Session-Type': xSessionType,
9862
12846
  'Content-Type': 'application/json'
9863
12847
  }
9864
12848
  }), [cxauthxc, sessionID, fpHash]);
@@ -9875,6 +12859,7 @@ const useCustomForm$1 = (fpHash, postServerURL, getServerURL, deleteServerURL, i
9875
12859
  await getOrSetFingerprint(fpHash, configLogs);
9876
12860
  try {
9877
12861
  const response = await axios.get(getServerURL, {
12862
+ withCredentials: true,
9878
12863
  headers: config.headers,
9879
12864
  params: {
9880
12865
  itemID: id
@@ -10135,8 +13120,8 @@ const initializeSharedServices = () => {
10135
13120
  },
10136
13121
  getAuthData: () => {
10137
13122
  return {
10138
- sessionID: localStorage.getItem('cx_session'),
10139
- authToken: localStorage.getItem('cxauthxc')
13123
+ sessionID: authStorage.getSessionId(configLogs),
13124
+ authToken: authStorage.getAuthToken(configLogs)
10140
13125
  };
10141
13126
  }
10142
13127
  };
@@ -10167,19 +13152,25 @@ const patchservice = async (datauser, configLogs) => {
10167
13152
  cxauthxc,
10168
13153
  ...requestData
10169
13154
  } = datauser;
13155
+ const xSessionType = authStorage.getSessionTypeValue(configLogs);
10170
13156
  let config;
10171
13157
  if (authorization === true || authorization === 'true') {
10172
13158
  config = {
13159
+ withCredentials: true,
10173
13160
  headers: {
10174
13161
  Authorization: `Bearer ${cxauthxc}`,
13162
+ 'X-CSRF-Token': authStorage.getCsrfToken() || '',
10175
13163
  'X-Session-ID': datauser.sessionID || '',
10176
13164
  'X-Fingerprint': datauser.fingerprint || '',
13165
+ 'X-Session-Type': xSessionType,
10177
13166
  'Content-Type': 'application/json'
10178
13167
  }
10179
13168
  };
10180
13169
  } else {
10181
13170
  config = {
13171
+ withCredentials: true,
10182
13172
  headers: {
13173
+ 'X-CSRF-Token': authStorage.getCsrfToken() || '',
10183
13174
  'Content-Type': 'application/json'
10184
13175
  }
10185
13176
  };
@@ -10290,9 +13281,8 @@ const serviceDelete2 = async (fpHash = '', sessionID, deleteURL, cxauthxc, t, se
10290
13281
  };
10291
13282
 
10292
13283
  const checkAuth = configLogs => {
10293
- const cxauthxc = authStorage.getAuthToken(configLogs) || '';
10294
- const sessionID = authStorage.getSessionId(configLogs) || '';
10295
- if (cxauthxc === '' || sessionID === '' || cxauthxc === null || sessionID === null) {
13284
+ const hasSession = authStorage.hasActiveSession(configLogs);
13285
+ if (!hasSession) {
10296
13286
  localStorage.removeItem('datauser');
10297
13287
  localStorage.removeItem('sidebarleft');
10298
13288
  localStorage.removeItem('cxl0k2mw');
@@ -10333,6 +13323,7 @@ const useCustomForm = (fpHash, getServerURL, postServerURL, feedback, id, reset
10333
13323
  const [error, setError] = useState(false);
10334
13324
  const cxauthxc = authStorage.getAuthToken(configLogs) || '';
10335
13325
  const sessionID = authStorage.getSessionId(configLogs) || '';
13326
+ const xSessionType = authStorage.getSessionTypeValue(configLogs);
10336
13327
  const authorization = true;
10337
13328
  const handleFormSubmit = async event => {
10338
13329
  const visitorIdHash = await getOrSetFingerprint(fpHash, configLogs);
@@ -10429,6 +13420,7 @@ const useCustomForm = (fpHash, getServerURL, postServerURL, feedback, id, reset
10429
13420
  Authorization: `Bearer ${cxauthxc}`,
10430
13421
  'X-Session-ID': sessionID,
10431
13422
  'X-Fingerprint': fpHash,
13423
+ 'X-Session-Type': xSessionType,
10432
13424
  'Content-Type': 'application/json'
10433
13425
  }
10434
13426
  }), [cxauthxc, sessionID, fpHash]);
@@ -10441,7 +13433,14 @@ const useCustomForm = (fpHash, getServerURL, postServerURL, feedback, id, reset
10441
13433
  fingerprint: visitorIdHash
10442
13434
  };
10443
13435
  try {
10444
- const response = await axios.post(getServerURL, key, config);
13436
+ const response = await axios.post(getServerURL, key, {
13437
+ ...config,
13438
+ withCredentials: true,
13439
+ headers: {
13440
+ ...(config?.headers || {}),
13441
+ 'X-CSRF-Token': authStorage.getCsrfToken() || ''
13442
+ }
13443
+ });
10445
13444
  logConsole(configLogs, 'info', '[Request] ', getServerURL);
10446
13445
  const responseData = response.data;
10447
13446
  const formData = Array.isArray(responseData) ? responseData[0] : typeof responseData?.data === 'object' && responseData.data !== null ? Array.isArray(responseData.data) ? responseData.data[0] : responseData.data : responseData;
@@ -10476,6 +13475,7 @@ const useCustomFormPatch = (fpHash, getServerURL, patchServerURL, feedback, id,
10476
13475
  const [error, setError] = useState(false);
10477
13476
  const cxauthxc = authStorage.getAuthToken(configLogs) || '';
10478
13477
  const sessionID = authStorage.getSessionId(configLogs) || '';
13478
+ const xSessionType = authStorage.getSessionTypeValue(configLogs);
10479
13479
  const authorization = true;
10480
13480
  const handleFormSubmit = async event => {
10481
13481
  const visitorIdHash = await getOrSetFingerprint(fpHash, configLogs);
@@ -10572,6 +13572,7 @@ const useCustomFormPatch = (fpHash, getServerURL, patchServerURL, feedback, id,
10572
13572
  Authorization: `Bearer ${cxauthxc}`,
10573
13573
  'X-Session-ID': sessionID,
10574
13574
  'X-Fingerprint': fpHash,
13575
+ 'X-Session-Type': xSessionType,
10575
13576
  'Content-Type': 'application/json'
10576
13577
  }
10577
13578
  }), [cxauthxc, sessionID, fpHash]);
@@ -10584,7 +13585,14 @@ const useCustomFormPatch = (fpHash, getServerURL, patchServerURL, feedback, id,
10584
13585
  fingerprint: visitorIdHash
10585
13586
  };
10586
13587
  try {
10587
- const response = await axios.post(getServerURL, key, config);
13588
+ const response = await axios.post(getServerURL, key, {
13589
+ ...config,
13590
+ withCredentials: true,
13591
+ headers: {
13592
+ ...(config?.headers || {}),
13593
+ 'X-CSRF-Token': authStorage.getCsrfToken() || ''
13594
+ }
13595
+ });
10588
13596
  logConsole(configLogs, 'info', '[Request] ', getServerURL);
10589
13597
  const responseData = response.data;
10590
13598
  const formData = Array.isArray(responseData) ? responseData[0] : typeof responseData?.data === 'object' && responseData.data !== null ? Array.isArray(responseData.data) ? responseData.data[0] : responseData.data : responseData;
@@ -10692,7 +13700,7 @@ const useZoomPrevention = () => {
10692
13700
  };
10693
13701
 
10694
13702
  const getWsBaseUrl = () => {
10695
- const restApi = window.restAPI || 'http://localhost:3001/restapi/';
13703
+ const restApi = Url || 'http://localhost:3001/restapi/';
10696
13704
  return restApi.replace(/\/restapi\/?$/, '');
10697
13705
  };
10698
13706
  const useSocket = () => {
@@ -10709,12 +13717,16 @@ const useSocket = () => {
10709
13717
  logConsole(configLogs, 'warn', '[WS] ', 'No hay token, no se conecta WebSocket');
10710
13718
  return;
10711
13719
  }
13720
+ const isCookieMode = authStorage.getSessionTypeValue(configLogs) === 'cookie';
10712
13721
  const wsUrl = getWsBaseUrl();
10713
13722
  logConsole(configLogs, 'info', '[WS] ', `Conectando a ${wsUrl}...`);
10714
13723
  const socket = io(wsUrl, {
10715
- auth: {
10716
- token
10717
- },
13724
+ ...(isCookieMode ? {} : {
13725
+ auth: {
13726
+ token
13727
+ }
13728
+ }),
13729
+ withCredentials: true,
10718
13730
  transports: ['websocket', 'polling'],
10719
13731
  reconnection: true,
10720
13732
  reconnectionAttempts: Infinity,
@@ -10910,5 +13922,5 @@ function usePermissionContext() {
10910
13922
  return ctx;
10911
13923
  }
10912
13924
 
10913
- export { ActionButtons, AppDataSettings, AppDataSettingsHTML, AppDialogModal, AppError, AppFormFields, AppFormFieldsFromConfig, AppFormFieldsNoUser, AppFormFieldsTable, AppHeaderPage, AppHeaderPage404, AppSetHeaderTitle, AuthContext, BackendOfflinePage, BackendStatusProvider, Button, Card, CardDashboard, CardUser, Checkbox, ConexysConfigProvider, ErrorBoundary, GenerateRandomPassword, Heading, Image, Info, InputFile, InputPassword, InputText, InputWYSIWYG, LanguageSet, Loading, MRT_Localization, MailTemplateWidget, Mailbox, MessagesBlock, NotFound, PermissionGate, PermissionProvider, Radiobutton, RenderForm, Select, Switch, Table, Text, ThemeContextProvider, Timeline, Url, UserWidget, Uservalidationerror, authStorage, checkAuth, deleteFormService, deleteservice, getOrSetFingerprint, getServiceBasic, getServiceData, getservice, getservice2, initializeSharedComponents, initializeSharedServices, isDevelopmentMode, logConsole, patchFormService, patchservice, postFormService, postservice, serviceData, serviceDelete2, serviceFavorites, serviceGetFavorites, serviceLockscreen, serviceLogout, servicePatch2, servicePost, servicePost2, servicePostBasic, servicePostData, useAuth, useBackendStatus, useConexysConfig, useCustomForm$1 as useCustomFormGetPost, useCustomFormMulti, useCustomForm$3 as useCustomFormNormal, useCustomForm$2 as useCustomFormNormalNoUser, useCustomForm as useCustomFormUpload, useCustomFormPatch as useCustomFormUploadPatch, useFingerprintJS, useLanguageSync, usePermission, usePermissionContext, useSocket, useTableData, useTableDataInstall, useZoomPrevention };
13925
+ export { ActionButtons, AppDataSettings, AppDataSettingsHTML, AppDialogModal, AppError, AppFormFields, AppFormFieldsFromConfig, AppFormFieldsNoUser, AppFormFieldsTable, AppHeaderPage, AppHeaderPage404, AppSetHeaderTitle, AuthContext, BackendOfflinePage, BackendStatusProvider, Button, Card, CardDashboard, CardUser, Checkbox, ConexysConfigProvider, ErrorBoundary, GenerateRandomPassword, Heading, Image, Info, InputFile, InputPassword, InputText, InputWYSIWYG, LanguageSet, Loading, MRT_Localization, MailTemplateWidget, Mailbox, MessagesBlock, NotFound, PermissionGate, PermissionProvider, Radiobutton, RenderForm, Select, Switch, Table, Text, ThemeContextProvider, Timeline, Url, UserWidget, Uservalidationerror, authStorage, checkAuth, deleteFormService, deleteservice, getOrSetFingerprint, getServiceBasic, getServiceData, getservice, getservice2, initializeSharedComponents, initializeSharedServices, isDevelopmentMode, logConsole, patchFormService, patchservice, postFormService, postservice, sanitizeHtml, serviceData, serviceDelete2, serviceFavorites, serviceGetFavorites, serviceLockscreen, serviceLogout, servicePatch2, servicePost, servicePost2, servicePostBasic, servicePostData, useAuth, useBackendStatus, useConexysConfig, useCustomForm$1 as useCustomFormGetPost, useCustomFormMulti, useCustomForm$3 as useCustomFormNormal, useCustomForm$2 as useCustomFormNormalNoUser, useCustomForm as useCustomFormUpload, useCustomFormPatch as useCustomFormUploadPatch, useFingerprintJS, useLanguageSync, usePermission, usePermissionContext, useSocket, useTableData, useTableDataInstall, useZoomPrevention };
10914
13926
  //# sourceMappingURL=index.esm.js.map