libre-webui 0.22.1 → 0.23.1

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 (237) hide show
  1. package/backend/dist/index.d.ts.map +1 -1
  2. package/backend/dist/index.js +8 -0
  3. package/backend/dist/index.js.map +1 -1
  4. package/backend/dist/middleware/auth.d.ts +15 -1
  5. package/backend/dist/middleware/auth.d.ts.map +1 -1
  6. package/backend/dist/middleware/auth.js +153 -33
  7. package/backend/dist/middleware/auth.js.map +1 -1
  8. package/backend/dist/persistence/index.d.ts +1 -0
  9. package/backend/dist/persistence/index.d.ts.map +1 -1
  10. package/backend/dist/persistence/index.js.map +1 -1
  11. package/backend/dist/persistence/postgresMigrationRegistry.d.ts.map +1 -1
  12. package/backend/dist/persistence/postgresMigrationRegistry.js +2 -0
  13. package/backend/dist/persistence/postgresMigrationRegistry.js.map +1 -1
  14. package/backend/dist/persistence/postgresPersistence.d.ts.map +1 -1
  15. package/backend/dist/persistence/postgresPersistence.js +4 -0
  16. package/backend/dist/persistence/postgresPersistence.js.map +1 -1
  17. package/backend/dist/persistence/postgresSecurityRepositories.d.ts +7 -0
  18. package/backend/dist/persistence/postgresSecurityRepositories.d.ts.map +1 -0
  19. package/backend/dist/persistence/postgresSecurityRepositories.js +435 -0
  20. package/backend/dist/persistence/postgresSecurityRepositories.js.map +1 -0
  21. package/backend/dist/persistence/postgresTrustFoundationMigration.d.ts +8 -0
  22. package/backend/dist/persistence/postgresTrustFoundationMigration.d.ts.map +1 -0
  23. package/backend/dist/persistence/postgresTrustFoundationMigration.js +151 -0
  24. package/backend/dist/persistence/postgresTrustFoundationMigration.js.map +1 -0
  25. package/backend/dist/persistence/securityTypes.d.ts +196 -0
  26. package/backend/dist/persistence/securityTypes.d.ts.map +1 -0
  27. package/backend/dist/persistence/securityTypes.js +18 -0
  28. package/backend/dist/persistence/securityTypes.js.map +1 -0
  29. package/backend/dist/persistence/sqliteMigrations.d.ts +1 -0
  30. package/backend/dist/persistence/sqliteMigrations.d.ts.map +1 -1
  31. package/backend/dist/persistence/sqliteMigrations.js +311 -0
  32. package/backend/dist/persistence/sqliteMigrations.js.map +1 -1
  33. package/backend/dist/persistence/sqlitePersistence.d.ts.map +1 -1
  34. package/backend/dist/persistence/sqlitePersistence.js +3 -0
  35. package/backend/dist/persistence/sqlitePersistence.js.map +1 -1
  36. package/backend/dist/persistence/sqliteSecurityRepositories.d.ts +6 -0
  37. package/backend/dist/persistence/sqliteSecurityRepositories.d.ts.map +1 -0
  38. package/backend/dist/persistence/sqliteSecurityRepositories.js +497 -0
  39. package/backend/dist/persistence/sqliteSecurityRepositories.js.map +1 -0
  40. package/backend/dist/persistence/sqliteToPostgresMigration.d.ts.map +1 -1
  41. package/backend/dist/persistence/sqliteToPostgresMigration.js +55 -0
  42. package/backend/dist/persistence/sqliteToPostgresMigration.js.map +1 -1
  43. package/backend/dist/persistence/types.d.ts +4 -0
  44. package/backend/dist/persistence/types.d.ts.map +1 -1
  45. package/backend/dist/platform/jobs/domainJobHandlers.d.ts.map +1 -1
  46. package/backend/dist/platform/jobs/domainJobHandlers.js +7 -0
  47. package/backend/dist/platform/jobs/domainJobHandlers.js.map +1 -1
  48. package/backend/dist/routes/access.d.ts +3 -0
  49. package/backend/dist/routes/access.d.ts.map +1 -0
  50. package/backend/dist/routes/access.js +134 -0
  51. package/backend/dist/routes/access.js.map +1 -0
  52. package/backend/dist/routes/audit.d.ts +3 -0
  53. package/backend/dist/routes/audit.d.ts.map +1 -0
  54. package/backend/dist/routes/audit.js +82 -0
  55. package/backend/dist/routes/audit.js.map +1 -0
  56. package/backend/dist/routes/auth.d.ts.map +1 -1
  57. package/backend/dist/routes/auth.js +342 -14
  58. package/backend/dist/routes/auth.js.map +1 -1
  59. package/backend/dist/routes/groups.d.ts +3 -0
  60. package/backend/dist/routes/groups.d.ts.map +1 -0
  61. package/backend/dist/routes/groups.js +161 -0
  62. package/backend/dist/routes/groups.js.map +1 -0
  63. package/backend/dist/services/apiTokenService.d.ts +51 -0
  64. package/backend/dist/services/apiTokenService.d.ts.map +1 -0
  65. package/backend/dist/services/apiTokenService.js +220 -0
  66. package/backend/dist/services/apiTokenService.js.map +1 -0
  67. package/backend/dist/services/authService.d.ts +20 -4
  68. package/backend/dist/services/authService.d.ts.map +1 -1
  69. package/backend/dist/services/authService.js +44 -6
  70. package/backend/dist/services/authService.js.map +1 -1
  71. package/backend/dist/services/authSessionService.d.ts +34 -0
  72. package/backend/dist/services/authSessionService.d.ts.map +1 -0
  73. package/backend/dist/services/authSessionService.js +205 -0
  74. package/backend/dist/services/authSessionService.js.map +1 -0
  75. package/backend/dist/services/authorizationService.d.ts +64 -0
  76. package/backend/dist/services/authorizationService.d.ts.map +1 -0
  77. package/backend/dist/services/authorizationService.js +176 -0
  78. package/backend/dist/services/authorizationService.js.map +1 -0
  79. package/backend/dist/services/groupService.d.ts +27 -0
  80. package/backend/dist/services/groupService.d.ts.map +1 -0
  81. package/backend/dist/services/groupService.js +245 -0
  82. package/backend/dist/services/groupService.js.map +1 -0
  83. package/backend/dist/services/groupVectorPrincipalResolver.d.ts +12 -0
  84. package/backend/dist/services/groupVectorPrincipalResolver.d.ts.map +1 -0
  85. package/backend/dist/services/groupVectorPrincipalResolver.js +33 -0
  86. package/backend/dist/services/groupVectorPrincipalResolver.js.map +1 -0
  87. package/backend/dist/services/modelAccessService.d.ts +1 -0
  88. package/backend/dist/services/modelAccessService.d.ts.map +1 -1
  89. package/backend/dist/services/modelAccessService.js +3 -5
  90. package/backend/dist/services/modelAccessService.js.map +1 -1
  91. package/backend/dist/services/oauthSecurity.d.ts +12 -1
  92. package/backend/dist/services/oauthSecurity.d.ts.map +1 -1
  93. package/backend/dist/services/oauthSecurity.js +41 -0
  94. package/backend/dist/services/oauthSecurity.js.map +1 -1
  95. package/backend/dist/services/resourceGrantService.d.ts +28 -0
  96. package/backend/dist/services/resourceGrantService.d.ts.map +1 -0
  97. package/backend/dist/services/resourceGrantService.js +192 -0
  98. package/backend/dist/services/resourceGrantService.js.map +1 -0
  99. package/backend/dist/services/securityAuditService.d.ts +35 -0
  100. package/backend/dist/services/securityAuditService.d.ts.map +1 -0
  101. package/backend/dist/services/securityAuditService.js +159 -0
  102. package/backend/dist/services/securityAuditService.js.map +1 -0
  103. package/backend/dist/services/simpleGitHubOAuth.d.ts.map +1 -1
  104. package/backend/dist/services/simpleGitHubOAuth.js +4 -2
  105. package/backend/dist/services/simpleGitHubOAuth.js.map +1 -1
  106. package/backend/dist/services/simpleOidcOAuth.d.ts +62 -0
  107. package/backend/dist/services/simpleOidcOAuth.d.ts.map +1 -0
  108. package/backend/dist/services/simpleOidcOAuth.js +397 -0
  109. package/backend/dist/services/simpleOidcOAuth.js.map +1 -0
  110. package/backend/dist/services/webSearchService.d.ts +1 -0
  111. package/backend/dist/services/webSearchService.d.ts.map +1 -1
  112. package/backend/dist/services/webSearchService.js +3 -5
  113. package/backend/dist/services/webSearchService.js.map +1 -1
  114. package/backend/dist/services/websocketTicketService.d.ts +3 -1
  115. package/backend/dist/services/websocketTicketService.d.ts.map +1 -1
  116. package/backend/dist/services/websocketTicketService.js +4 -1
  117. package/backend/dist/services/websocketTicketService.js.map +1 -1
  118. package/backend/dist/services/workAccessService.d.ts +1 -0
  119. package/backend/dist/services/workAccessService.d.ts.map +1 -1
  120. package/backend/dist/services/workAccessService.js +3 -5
  121. package/backend/dist/services/workAccessService.js.map +1 -1
  122. package/backend/dist/services/workEventService.d.ts.map +1 -1
  123. package/backend/dist/services/workEventService.js +74 -18
  124. package/backend/dist/services/workEventService.js.map +1 -1
  125. package/backend/dist/services/workRuntimeService.d.ts +11 -0
  126. package/backend/dist/services/workRuntimeService.d.ts.map +1 -1
  127. package/backend/dist/services/workRuntimeService.js +78 -23
  128. package/backend/dist/services/workRuntimeService.js.map +1 -1
  129. package/backend/dist/websocketServer.d.ts.map +1 -1
  130. package/backend/dist/websocketServer.js +25 -1
  131. package/backend/dist/websocketServer.js.map +1 -1
  132. package/backend/dist/workTerminalServer.d.ts.map +1 -1
  133. package/backend/dist/workTerminalServer.js +19 -1
  134. package/backend/dist/workTerminalServer.js.map +1 -1
  135. package/backend/dist/worker.js +2 -0
  136. package/backend/dist/worker.js.map +1 -1
  137. package/backend/package.json +1 -1
  138. package/frontend/dist/artifact-runtime/.build-fingerprint +1 -1
  139. package/frontend/dist/assets/index-BXMQqOXF.js +11 -0
  140. package/frontend/dist/assets/index-DBaj1DRj.css +1 -0
  141. package/frontend/dist/index.html +11 -11
  142. package/frontend/dist/js/ArtifactContainer-BUjOZ5M5.js +1 -0
  143. package/frontend/dist/js/{ArtifactDemoPage-BDBXYv9l.js → ArtifactDemoPage-QRve-734.js} +1 -1
  144. package/frontend/dist/js/{ArtifactSandboxFrame-BN16NtKe.js → ArtifactSandboxFrame-DhvA-t-7.js} +2 -2
  145. package/frontend/dist/js/ArtifactSlideOutPanel-B8w1Orr1.js +1 -0
  146. package/frontend/dist/js/ChatPage-DKVwaYxn.js +23 -0
  147. package/frontend/dist/js/FirstTimeSetup-DaQveC0v.js +1 -0
  148. package/frontend/dist/js/{GalleryPage-CV_vbE7X.js → GalleryPage-Cz-VvarV.js} +1 -1
  149. package/frontend/dist/js/{HomePage-P-e7Huco.js → HomePage-DF9pZ5V5.js} +1 -1
  150. package/frontend/dist/js/{LibreClawPage-Cee06SUM.js → LibreClawPage-Dw8YQyFj.js} +1 -1
  151. package/frontend/dist/js/{ModelManagerModals-D7jIT3v1.js → ModelManagerModals-CZAWUxjI.js} +1 -1
  152. package/frontend/dist/js/{ModelSelector-DXucbvrz.js → ModelSelector-Cc91MEm4.js} +1 -1
  153. package/frontend/dist/js/ModelsPage-BgaQuCry.js +2 -0
  154. package/frontend/dist/js/{NotesPage-rEIPWGIb.js → NotesPage-CRAo-TFI.js} +1 -1
  155. package/frontend/dist/js/{PersonasPage-BXtepFuD.js → PersonasPage-DpN8DQkY.js} +2 -2
  156. package/frontend/dist/js/{PluginUsagePage-hhu8cxsu.js → PluginUsagePage-5PXXZXle.js} +1 -1
  157. package/frontend/dist/js/{RichMessageContent-DkiEvdSg.js → RichMessageContent-C67tFlr1.js} +1 -1
  158. package/frontend/dist/js/SettingsModal-BEzMSDlp.js +1 -0
  159. package/frontend/dist/js/SystemPage-FUnoW7Er.js +1 -0
  160. package/frontend/dist/js/UserManagementPage-SBsRbt0H.js +1 -0
  161. package/frontend/dist/js/WorkPage-D3ChSFo-.js +6 -0
  162. package/frontend/dist/js/api-Dw_IuHaz.js +14 -0
  163. package/frontend/dist/js/{appStore-DRSSjaHn.js → appStore-DAT2R-5p.js} +2 -2
  164. package/frontend/dist/js/ar-D0z0P4rC.js +2 -0
  165. package/frontend/dist/js/{authStore-BVykIRec.js → authStore-CwSMGkEM.js} +3 -3
  166. package/frontend/dist/js/bn-BYYU41A7.js +2 -0
  167. package/frontend/dist/js/chatStore-BK6YcouV.js +3 -0
  168. package/frontend/dist/js/{config-BTlPm-cZ.js → config-0eBxRk6E.js} +1 -1
  169. package/frontend/dist/js/cs-BFx6KNZe.js +2 -0
  170. package/frontend/dist/js/da-DSDuY5Du.js +2 -0
  171. package/frontend/dist/js/de-YqhP0FmX.js +2 -0
  172. package/frontend/dist/js/es-Dpr_y1cN.js +2 -0
  173. package/frontend/dist/js/{estree-CfYahF_d.js → estree-Db_NKIE7.js} +1 -1
  174. package/frontend/dist/js/fr-nVg_iAEC.js +2 -0
  175. package/frontend/dist/js/hi-gHKYCgkP.js +2 -0
  176. package/frontend/dist/js/{html-BJsDX1UZ.js → html-INl_p8N8.js} +1 -1
  177. package/frontend/dist/js/id-C_yID1Zk.js +2 -0
  178. package/frontend/dist/js/is-MoRPLbOM.js +2 -0
  179. package/frontend/dist/js/it-BZTscLxR.js +2 -0
  180. package/frontend/dist/js/ja-DpIbtmZq.js +2 -0
  181. package/frontend/dist/js/ko-LkWggmjU.js +2 -0
  182. package/frontend/dist/js/{markdown-GLyuUNig.js → markdown-DQbfLH11.js} +1 -1
  183. package/frontend/dist/js/{messageCodeStyles-BHddEFP1.js → messageCodeStyles-D7zXzjgH.js} +2 -2
  184. package/frontend/dist/js/ms-p3XiQSAo.js +2 -0
  185. package/frontend/dist/js/nl-sEHHO2Kb.js +2 -0
  186. package/frontend/dist/js/pl-D2GD6PDW.js +2 -0
  187. package/frontend/dist/js/pt-DPkn3GUn.js +2 -0
  188. package/frontend/dist/js/ru-C42iHrEd.js +2 -0
  189. package/frontend/dist/js/{standalone-Dh56V0YW.js → standalone-CFSd7xCM.js} +1 -1
  190. package/frontend/dist/js/sv-CGvHo4os.js +2 -0
  191. package/frontend/dist/js/th-BaDNpCdY.js +2 -0
  192. package/frontend/dist/js/tr-BHQvi1cN.js +2 -0
  193. package/frontend/dist/js/{typescript-DRy7A9w4.js → typescript-BIFKSiW0.js} +1 -1
  194. package/frontend/dist/js/{ui-CuY4IifA.js → ui-CS8EAgvS.js} +2 -2
  195. package/frontend/dist/js/{ui-vendor-D3Ahl1x5.js → ui-vendor-54SgntkX.js} +1 -1
  196. package/frontend/dist/js/uk-7pNGS1b2.js +2 -0
  197. package/frontend/dist/js/vi-DgAfh6mo.js +2 -0
  198. package/frontend/dist/js/{workApi-DHuYNHLf.js → workApi-DlmJ72dN.js} +2 -2
  199. package/frontend/dist/js/zh-FRTz6ZqA.js +2 -0
  200. package/package.json +2 -2
  201. package/frontend/dist/assets/index-Jtx9Amhz.js +0 -16
  202. package/frontend/dist/assets/index-kxtZQLV6.css +0 -1
  203. package/frontend/dist/js/ArtifactContainer-fZegtmva.js +0 -1
  204. package/frontend/dist/js/ArtifactSlideOutPanel-x1fS85Ww.js +0 -1
  205. package/frontend/dist/js/ChatPage-C_pXh7WN.js +0 -23
  206. package/frontend/dist/js/FirstTimeSetup-oRrlZnBm.js +0 -1
  207. package/frontend/dist/js/ModelsPage-C3_fZpMM.js +0 -2
  208. package/frontend/dist/js/SettingsModal-BNxCtJ51.js +0 -1
  209. package/frontend/dist/js/SystemPage-BvvKFuoG.js +0 -1
  210. package/frontend/dist/js/UserManagementPage-BccyR7si.js +0 -1
  211. package/frontend/dist/js/WorkPage-BgxrvY3I.js +0 -6
  212. package/frontend/dist/js/api-BvPDxsUQ.js +0 -14
  213. package/frontend/dist/js/ar-xTSvTq05.js +0 -2
  214. package/frontend/dist/js/bn-iYAsohEA.js +0 -2
  215. package/frontend/dist/js/chatStore-UPp5TV_t.js +0 -3
  216. package/frontend/dist/js/cs-YBHN88Hb.js +0 -2
  217. package/frontend/dist/js/da-D7qlLy_k.js +0 -2
  218. package/frontend/dist/js/de-DV671k2c.js +0 -2
  219. package/frontend/dist/js/es-kyBgzNq-.js +0 -2
  220. package/frontend/dist/js/fr-Cw1vut7I.js +0 -2
  221. package/frontend/dist/js/hi-DWEFC024.js +0 -2
  222. package/frontend/dist/js/id-DlMHjjy0.js +0 -2
  223. package/frontend/dist/js/is-B9E_a7dG.js +0 -2
  224. package/frontend/dist/js/it-DawmVbLC.js +0 -2
  225. package/frontend/dist/js/ja-DmVvwY3W.js +0 -2
  226. package/frontend/dist/js/ko-DzOPpkVs.js +0 -2
  227. package/frontend/dist/js/ms-DpsaOPht.js +0 -2
  228. package/frontend/dist/js/nl-B1d8W22n.js +0 -2
  229. package/frontend/dist/js/pl-nCncRVgt.js +0 -2
  230. package/frontend/dist/js/pt-DHw8fGuu.js +0 -2
  231. package/frontend/dist/js/ru-Derl_YP_.js +0 -2
  232. package/frontend/dist/js/sv-pJAfBVo0.js +0 -2
  233. package/frontend/dist/js/th-C_7fIGnk.js +0 -2
  234. package/frontend/dist/js/tr-CPqsJvaP.js +0 -2
  235. package/frontend/dist/js/uk-3o8P_kFi.js +0 -2
  236. package/frontend/dist/js/vi-Dv6N7OVD.js +0 -2
  237. package/frontend/dist/js/zh-qg5iqtPi.js +0 -2
@@ -0,0 +1,192 @@
1
+ /*
2
+ * Libre WebUI
3
+ * Copyright (C) 2025 Kroonen AI, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at:
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ /**
18
+ * Common resource grants (IAM-03).
19
+ *
20
+ * One private-by-default grant model for every shareable resource family:
21
+ * owner/user/group principals with read/write/admin permissions. Only the
22
+ * resource owner (or a principal holding an `admin` grant on it) may manage
23
+ * shares — the global administrator role deliberately confers no access to
24
+ * private content. Every grant mutation commits in the same transaction as
25
+ * its audit event.
26
+ */
27
+ import { randomUUID } from 'node:crypto';
28
+ import { getPersistence } from '../persistence/index.js';
29
+ import { encryptionService } from './encryptionService.js';
30
+ import { buildAuditEvent } from './securityAuditService.js';
31
+ import { authorize, isShareableResourceType, } from './authorizationService.js';
32
+ import { userModel } from '../models/userModel.js';
33
+ export class ResourceGrantError extends Error {
34
+ constructor(message, statusCode) {
35
+ super(message);
36
+ this.statusCode = statusCode;
37
+ this.name = 'ResourceGrantError';
38
+ }
39
+ }
40
+ const security = () => getPersistence(encryptionService).repositories.security;
41
+ const archive = () => getPersistence(encryptionService).repositories.resources.archive;
42
+ const isPermission = (value) => value === 'read' || value === 'write' || value === 'admin';
43
+ const isPrincipalType = (value) => value === 'user' || value === 'group';
44
+ /**
45
+ * Whether the actor may manage sharing for a resource: the owner always
46
+ * can; other users need an `admin` grant on that resource.
47
+ */
48
+ export const canManageGrants = async (actor, resourceType, resourceId) => {
49
+ const ownerUserId = await archive().ownerOf(resourceType, resourceId);
50
+ if (ownerUserId === null)
51
+ return { allowed: false, ownerUserId: null };
52
+ if (ownerUserId === actor.userId)
53
+ return { allowed: true, ownerUserId };
54
+ const decision = await authorize(actor, 'manage', {
55
+ type: resourceType,
56
+ id: resourceId,
57
+ ownerUserId,
58
+ });
59
+ return { allowed: decision.allowed, ownerUserId };
60
+ };
61
+ export const listGrantsForResource = async (actor, resourceType, resourceId) => {
62
+ if (!isShareableResourceType(resourceType)) {
63
+ throw new ResourceGrantError('Unknown resource type', 400);
64
+ }
65
+ const manage = await canManageGrants(actor, resourceType, resourceId);
66
+ if (!manage.allowed) {
67
+ // Non-enumerating: a denied caller learns nothing about existence.
68
+ throw new ResourceGrantError('Resource not found', 404);
69
+ }
70
+ return security().grants.listForResource(resourceType, resourceId);
71
+ };
72
+ export const createGrant = async (actor, input) => {
73
+ if (!isShareableResourceType(input.resourceType)) {
74
+ throw new ResourceGrantError('Unknown resource type', 400);
75
+ }
76
+ if (!isPrincipalType(input.principalType)) {
77
+ throw new ResourceGrantError('Unknown principal type', 400);
78
+ }
79
+ if (!isPermission(input.permission)) {
80
+ throw new ResourceGrantError('Unknown permission', 400);
81
+ }
82
+ const manage = await canManageGrants(actor, input.resourceType, input.resourceId);
83
+ if (!manage.allowed || manage.ownerUserId === null) {
84
+ throw new ResourceGrantError('Resource not found', 404);
85
+ }
86
+ if (input.principalType === 'user' &&
87
+ input.principalId === manage.ownerUserId) {
88
+ throw new ResourceGrantError('The owner already has full access', 400);
89
+ }
90
+ if (input.principalType === 'user') {
91
+ const principal = await userModel.getUserById(input.principalId);
92
+ if (!principal)
93
+ throw new ResourceGrantError('User not found', 404);
94
+ }
95
+ else {
96
+ const group = await security().groups.findById(input.principalId);
97
+ if (!group)
98
+ throw new ResourceGrantError('Group not found', 404);
99
+ }
100
+ const record = {
101
+ id: randomUUID(),
102
+ resource_type: input.resourceType,
103
+ resource_id: input.resourceId,
104
+ owner_user_id: manage.ownerUserId,
105
+ principal_type: input.principalType,
106
+ principal_id: input.principalId,
107
+ permission: input.permission,
108
+ created_by: actor.userId,
109
+ created_at: Date.now(),
110
+ };
111
+ const audit = buildAuditEvent({
112
+ action: 'grant.create',
113
+ result: 'success',
114
+ actorUserId: actor.userId,
115
+ targetType: input.resourceType,
116
+ targetId: input.resourceId,
117
+ details: {
118
+ principalType: input.principalType,
119
+ principalId: input.principalId,
120
+ permission: input.permission,
121
+ },
122
+ });
123
+ const persistence = getPersistence(encryptionService);
124
+ if (persistence.dialect === 'sqlite') {
125
+ await persistence.transaction(({ security: tx }) => {
126
+ tx.grants.upsert(record);
127
+ tx.audit.insert(audit);
128
+ return undefined;
129
+ });
130
+ return record;
131
+ }
132
+ await persistence.transaction(async ({ security: tx }) => {
133
+ await tx.grants.upsert(record);
134
+ await tx.audit.insert(audit);
135
+ });
136
+ return record;
137
+ };
138
+ export const deleteGrant = async (actor, grantId) => {
139
+ const record = await security().grants.findById(grantId);
140
+ if (!record)
141
+ return false;
142
+ if (!isShareableResourceType(record.resource_type)) {
143
+ throw new ResourceGrantError('Unknown resource type', 400);
144
+ }
145
+ const manage = await canManageGrants(actor, record.resource_type, record.resource_id);
146
+ // A principal may always remove a grant that points at itself
147
+ // (leave a share), even without manage rights.
148
+ const selfRemoval = record.principal_type === 'user' && record.principal_id === actor.userId;
149
+ if (!manage.allowed && !selfRemoval) {
150
+ throw new ResourceGrantError('Resource not found', 404);
151
+ }
152
+ const audit = buildAuditEvent({
153
+ action: 'grant.delete',
154
+ result: 'success',
155
+ actorUserId: actor.userId,
156
+ targetType: record.resource_type,
157
+ targetId: record.resource_id,
158
+ details: {
159
+ principalType: record.principal_type,
160
+ principalId: record.principal_id,
161
+ },
162
+ });
163
+ const persistence = getPersistence(encryptionService);
164
+ if (persistence.dialect === 'sqlite') {
165
+ return persistence.transaction(({ security: tx }) => {
166
+ const deleted = tx.grants.delete(grantId);
167
+ if (deleted)
168
+ tx.audit.insert(audit);
169
+ return deleted;
170
+ });
171
+ }
172
+ return persistence.transaction(async ({ security: tx }) => {
173
+ const deleted = await tx.grants.delete(grantId);
174
+ if (deleted)
175
+ await tx.audit.insert(audit);
176
+ return deleted;
177
+ });
178
+ };
179
+ /** Resources shared with the actor (directly or via groups). */
180
+ export const listGrantsForActor = async (actor) => {
181
+ const grants = [
182
+ ...(await security().grants.listForPrincipal('user', actor.userId)),
183
+ ];
184
+ const groups = await security().groups.listGroupIdsForUser(actor.userId);
185
+ for (const groupId of groups) {
186
+ grants.push(...(await security().grants.listForPrincipal('group', groupId)));
187
+ }
188
+ return grants;
189
+ };
190
+ /** Deletion hygiene: called when a resource is removed. */
191
+ export const deleteGrantsForResource = (resourceType, resourceId) => security().grants.deleteForResource(resourceType, resourceId);
192
+ //# sourceMappingURL=resourceGrantService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resourceGrantService.js","sourceRoot":"","sources":["../../src/services/resourceGrantService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import type { AuditResult, StoredSecurityAuditEventRecord } from '../persistence/index.js';
2
+ export type AuditActorKind = 'user' | 'api-token' | 'system' | 'anonymous';
3
+ export interface SecurityAuditEventInput {
4
+ action: string;
5
+ result: AuditResult;
6
+ actorUserId?: string | null;
7
+ actorKind?: AuditActorKind;
8
+ targetType?: string;
9
+ targetId?: string;
10
+ requestId?: string;
11
+ ipHash?: string | null;
12
+ details?: Record<string, unknown>;
13
+ }
14
+ export declare const auditRetentionMs: () => number;
15
+ /** Serialize event details with secret keys removed and size bounded. */
16
+ export declare const redactAuditDetails: (details: Record<string, unknown> | undefined) => string | null;
17
+ /** One-way IP digest: correlates events without storing addresses. */
18
+ export declare const hashClientIp: (ip: string | undefined) => string | null;
19
+ /** Build the persisted row shape for direct or transactional inserts. */
20
+ export declare const buildAuditEvent: (input: SecurityAuditEventInput) => StoredSecurityAuditEventRecord;
21
+ /**
22
+ * Best-effort audit write for observations. Never throws: an audit outage
23
+ * must not turn into an authentication or authorization outage.
24
+ */
25
+ export declare const recordAuditEvent: (input: SecurityAuditEventInput) => Promise<void>;
26
+ export declare const queryAuditEvents: (query: {
27
+ action?: string;
28
+ actorUserId?: string;
29
+ result?: AuditResult;
30
+ targetType?: string;
31
+ before?: number;
32
+ after?: number;
33
+ limit?: number;
34
+ }) => Promise<StoredSecurityAuditEventRecord[]>;
35
+ //# sourceMappingURL=securityAuditService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"securityAuditService.d.ts","sourceRoot":"","sources":["../../src/services/securityAuditService.ts"],"names":[],"mappings":"AAqCA,OAAO,KAAK,EACV,WAAW,EAEX,8BAA8B,EAC/B,MAAM,yBAAyB,CAAC;AAMjC,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,WAAW,GAAG,QAAQ,GAAG,WAAW,CAAC;AAE3E,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,WAAW,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAYD,eAAO,MAAM,gBAAgB,QAAO,MAOnC,CAAC;AAyBF,yEAAyE;AACzE,eAAO,MAAM,kBAAkB,YACpB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,KAC3C,MAAM,GAAG,IAYX,CAAC;AAEF,sEAAsE;AACtE,eAAO,MAAM,YAAY,OAAQ,MAAM,GAAG,SAAS,KAAG,MAAM,GAAG,IAG9D,CAAC;AAEF,yEAAyE;AACzE,eAAO,MAAM,eAAe,UACnB,uBAAuB,KAC7B,8BAYD,CAAC;AAgBH;;;GAGG;AACH,eAAO,MAAM,gBAAgB,UACpB,uBAAuB,KAC7B,OAAO,CAAC,IAAI,CAad,CAAC;AAEF,eAAO,MAAM,gBAAgB,UAAiB;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,KAAG,OAAO,CAAC,8BAA8B,EAAE,CAY3C,CAAC"}
@@ -0,0 +1,159 @@
1
+ /*
2
+ * Libre WebUI
3
+ * Copyright (C) 2025 Kroonen AI, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at:
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ /**
18
+ * Security audit log (AUDIT-01/02).
19
+ *
20
+ * Records security-sensitive actions and denials as append-only events that
21
+ * are separate from usage analytics. Details are redacted before persistence:
22
+ * secret-like keys are dropped, strings are truncated, and the serialized
23
+ * payload is capped, so prompts, passwords, tokens, and provider bodies can
24
+ * never enter the log.
25
+ *
26
+ * Two write paths exist:
27
+ * - `recordAuditEvent` for observations (logins, denials): best-effort, never
28
+ * throws, so a logging failure cannot block authentication.
29
+ * - `buildAuditEvent` + the transactional audit repositories for
30
+ * security-critical mutations (group/grant/token/user changes): the caller
31
+ * writes the event inside the same database transaction as the mutation,
32
+ * so the mutation cannot commit without its audit trail.
33
+ */
34
+ import { createHash, randomUUID } from 'node:crypto';
35
+ import { getPersistence } from '../persistence/index.js';
36
+ import { encryptionService } from './encryptionService.js';
37
+ import { createLogger } from '../utils/logger.js';
38
+ const logger = createLogger('services:security-audit');
39
+ const SECRET_KEY_PATTERN = /pass(word)?|secret|token|key|authorization|cookie|credential|bearer|jwt/i;
40
+ const MAX_DETAIL_STRING = 256;
41
+ const MAX_DETAIL_BYTES = 4096;
42
+ const MAX_DETAIL_DEPTH = 4;
43
+ const AUDIT_RETENTION_DAYS_DEFAULT = 180;
44
+ const PRUNE_EVERY_N_WRITES = 512;
45
+ let writesSincePrune = 0;
46
+ export const auditRetentionMs = () => {
47
+ const parsed = Number.parseInt(process.env.AUDIT_RETENTION_DAYS ?? '', 10);
48
+ const days = Number.isFinite(parsed) && parsed > 0
49
+ ? parsed
50
+ : AUDIT_RETENTION_DAYS_DEFAULT;
51
+ return days * 24 * 60 * 60 * 1000;
52
+ };
53
+ const redactValue = (value, depth) => {
54
+ if (value === null || value === undefined)
55
+ return value;
56
+ if (typeof value === 'string') {
57
+ return value.length > MAX_DETAIL_STRING
58
+ ? `${value.slice(0, MAX_DETAIL_STRING)}…`
59
+ : value;
60
+ }
61
+ if (typeof value === 'number' || typeof value === 'boolean')
62
+ return value;
63
+ if (depth >= MAX_DETAIL_DEPTH)
64
+ return '[truncated]';
65
+ if (Array.isArray(value)) {
66
+ return value.slice(0, 32).map(item => redactValue(item, depth + 1));
67
+ }
68
+ if (typeof value === 'object') {
69
+ const redacted = {};
70
+ for (const [key, item] of Object.entries(value)) {
71
+ if (SECRET_KEY_PATTERN.test(key))
72
+ continue;
73
+ redacted[key] = redactValue(item, depth + 1);
74
+ }
75
+ return redacted;
76
+ }
77
+ return String(value);
78
+ };
79
+ /** Serialize event details with secret keys removed and size bounded. */
80
+ export const redactAuditDetails = (details) => {
81
+ if (!details)
82
+ return null;
83
+ try {
84
+ const serialized = JSON.stringify(redactValue(details, 0));
85
+ if (!serialized || serialized === '{}')
86
+ return null;
87
+ if (Buffer.byteLength(serialized, 'utf8') > MAX_DETAIL_BYTES) {
88
+ return JSON.stringify({ truncated: true });
89
+ }
90
+ return serialized;
91
+ }
92
+ catch {
93
+ return null;
94
+ }
95
+ };
96
+ /** One-way IP digest: correlates events without storing addresses. */
97
+ export const hashClientIp = (ip) => {
98
+ if (!ip)
99
+ return null;
100
+ return createHash('sha256').update(ip).digest('hex').slice(0, 32);
101
+ };
102
+ /** Build the persisted row shape for direct or transactional inserts. */
103
+ export const buildAuditEvent = (input) => ({
104
+ id: randomUUID(),
105
+ occurred_at: Date.now(),
106
+ actor_user_id: input.actorUserId ?? null,
107
+ actor_kind: input.actorKind ?? (input.actorUserId ? 'user' : 'anonymous'),
108
+ action: input.action,
109
+ target_type: input.targetType ?? null,
110
+ target_id: input.targetId ?? null,
111
+ result: input.result,
112
+ request_id: input.requestId ?? null,
113
+ ip_hash: input.ipHash ?? null,
114
+ details: redactAuditDetails(input.details),
115
+ });
116
+ const pruneOpportunistically = async () => {
117
+ writesSincePrune += 1;
118
+ if (writesSincePrune < PRUNE_EVERY_N_WRITES)
119
+ return;
120
+ writesSincePrune = 0;
121
+ try {
122
+ const persistence = getPersistence(encryptionService);
123
+ await persistence.repositories.security.audit.deleteBefore(Date.now() - auditRetentionMs());
124
+ }
125
+ catch (error) {
126
+ logger.warn('Audit retention prune failed', { error });
127
+ }
128
+ };
129
+ /**
130
+ * Best-effort audit write for observations. Never throws: an audit outage
131
+ * must not turn into an authentication or authorization outage.
132
+ */
133
+ export const recordAuditEvent = async (input) => {
134
+ try {
135
+ const persistence = getPersistence(encryptionService);
136
+ await persistence.repositories.security.audit.insert(buildAuditEvent(input));
137
+ await pruneOpportunistically();
138
+ }
139
+ catch (error) {
140
+ logger.error('Failed to record security audit event', {
141
+ action: input.action,
142
+ error,
143
+ });
144
+ }
145
+ };
146
+ export const queryAuditEvents = async (query) => {
147
+ const persistence = getPersistence(encryptionService);
148
+ const bounded = {
149
+ ...(query.action ? { action: query.action } : {}),
150
+ ...(query.actorUserId ? { actorUserId: query.actorUserId } : {}),
151
+ ...(query.result ? { result: query.result } : {}),
152
+ ...(query.targetType ? { targetType: query.targetType } : {}),
153
+ ...(query.before !== undefined ? { before: query.before } : {}),
154
+ ...(query.after !== undefined ? { after: query.after } : {}),
155
+ limit: Math.min(Math.max(query.limit ?? 100, 1), 500),
156
+ };
157
+ return persistence.repositories.security.audit.query(bounded);
158
+ };
159
+ //# sourceMappingURL=securityAuditService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"securityAuditService.js","sourceRoot":"","sources":["../../src/services/securityAuditService.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"simpleGitHubOAuth.d.ts","sourceRoot":"","sources":["../../src/services/simpleGitHubOAuth.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAa,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAM/D,UAAU,aAAa;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,kBAAkB;IAC7B,cAEC;IAED,OAAO,KAAK,QAAQ,GAEnB;IAED,OAAO,KAAK,YAAY,GAEvB;IAED,OAAO,KAAK,WAAW,GAKtB;IAED;;OAEG;IACH,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAgBhC;IAED;;OAEG;IACH,YAAY,IAAI,OAAO,CAEtB;IAED;;OAEG;IACG,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiC/D;IAED;;OAEG;IACG,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CA2CvE;IAED;;OAEG;IACG,eAAe,CACnB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC;QAAE,IAAI,EAAE,UAAU,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAuBrD;IAED;;OAEG;IACG,WAAW,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAEpE;IAED;;OAEG;YACW,gBAAgB;CAiD/B;AAGD,eAAO,MAAM,kBAAkB,oBAA2B,CAAC"}
1
+ {"version":3,"file":"simpleGitHubOAuth.d.ts","sourceRoot":"","sources":["../../src/services/simpleGitHubOAuth.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAa,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAM/D,UAAU,aAAa;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,kBAAkB;IAC7B,cAEC;IAED,OAAO,KAAK,QAAQ,GAEnB;IAED,OAAO,KAAK,YAAY,GAEvB;IAED,OAAO,KAAK,WAAW,GAKtB;IAED;;OAEG;IACH,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAgBhC;IAED;;OAEG;IACH,YAAY,IAAI,OAAO,CAEtB;IAED;;OAEG;IACG,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiC/D;IAED;;OAEG;IACG,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CA2CvE;IAED;;OAEG;IACG,eAAe,CACnB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC;QAAE,IAAI,EAAE,UAAU,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAyBrD;IAED;;OAEG;IACG,WAAW,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAEpE;IAED;;OAEG;YACW,gBAAgB;CAiD/B;AAGD,eAAO,MAAM,kBAAkB,oBAA2B,CAAC"}
@@ -141,8 +141,10 @@ export class GitHubOAuthService {
141
141
  return null;
142
142
  if (user.status !== 'active')
143
143
  return null;
144
- // Generate JWT token
145
- const jwtToken = authService.generateToken(user);
144
+ // Issue a revocable session-bound JWT
145
+ const jwtToken = await authService.issueSession(user, {
146
+ kind: 'oauth:github',
147
+ });
146
148
  return { user, token: jwtToken };
147
149
  }
148
150
  catch (error) {
@@ -1 +1 @@
1
- {"version":3,"file":"simpleGitHubOAuth.js","sourceRoot":"","sources":["../../src/services/simpleGitHubOAuth.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"simpleGitHubOAuth.js","sourceRoot":"","sources":["../../src/services/simpleGitHubOAuth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ import { type UserPublic } from '../models/userModel.js';
2
+ interface DiscoveryDocument {
3
+ issuer: string;
4
+ authorization_endpoint: string;
5
+ token_endpoint: string;
6
+ jwks_uri: string;
7
+ userinfo_endpoint?: string;
8
+ }
9
+ export interface OidcClaims {
10
+ sub: string;
11
+ email?: string;
12
+ email_verified?: boolean;
13
+ preferred_username?: string;
14
+ name?: string;
15
+ nonce?: string;
16
+ [claim: string]: unknown;
17
+ }
18
+ export declare class OidcError extends Error {
19
+ readonly code: string;
20
+ constructor(message: string, code: string);
21
+ }
22
+ export declare class OidcOAuthService {
23
+ private discoveryCache;
24
+ private jwksCache;
25
+ private get issuerUrl();
26
+ private get clientId();
27
+ private get clientSecret();
28
+ private get callbackUrl();
29
+ private get scopes();
30
+ get displayName(): string;
31
+ private get allowedEmailDomains();
32
+ private get groupClaim();
33
+ private get adminGroups();
34
+ private get syncGroups();
35
+ isConfigured(): boolean;
36
+ discover(): Promise<DiscoveryDocument>;
37
+ /** PKCE pair for one flow. */
38
+ createPkcePair(): {
39
+ verifier: string;
40
+ challenge: string;
41
+ };
42
+ createNonce(): string;
43
+ getAuthUrl(state: string, nonce: string, codeChallenge: string): Promise<string>;
44
+ exchangeCode(code: string, verifier: string): Promise<{
45
+ idToken: string;
46
+ accessToken?: string;
47
+ }>;
48
+ private signingKeyFor;
49
+ /** Verify signature, issuer, audience, expiry, and nonce. */
50
+ verifyIdToken(idToken: string, expectedNonce: string): Promise<OidcClaims>;
51
+ private claimGroups;
52
+ private assertEmailPolicy;
53
+ private syncRoleAndGroups;
54
+ /**
55
+ * Resolve the verified claims to a Libre account: linked identity first,
56
+ * then policy-checked account creation. Never links by bare email.
57
+ */
58
+ processClaims(claims: OidcClaims): Promise<UserPublic>;
59
+ }
60
+ export declare const oidcOAuthService: OidcOAuthService;
61
+ export {};
62
+ //# sourceMappingURL=simpleOidcOAuth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"simpleOidcOAuth.d.ts","sourceRoot":"","sources":["../../src/services/simpleOidcOAuth.ts"],"names":[],"mappings":"AA+CA,OAAO,EAAa,KAAK,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAMpE,UAAU,iBAAiB;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,sBAAsB,EAAE,MAAM,CAAC;IAC/B,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B;AAED,qBAAa,SAAU,SAAQ,KAAK;IAGhC,QAAQ,CAAC,IAAI,EAAE,MAAM;IAFvB,YACE,OAAO,EAAE,MAAM,EACN,IAAI,EAAE,MAAM,EAItB;CACF;AAoBD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,cAAc,CAER;IACd,OAAO,CAAC,SAAS,CAEH;IAEd,OAAO,KAAK,SAAS,GAEpB;IAED,OAAO,KAAK,QAAQ,GAEnB;IAED,OAAO,KAAK,YAAY,GAEvB;IAED,OAAO,KAAK,WAAW,GAKtB;IAED,OAAO,KAAK,MAAM,GAEjB;IAED,IAAI,WAAW,IAAI,MAAM,CAExB;IAED,OAAO,KAAK,mBAAmB,GAK9B;IAED,OAAO,KAAK,UAAU,GAErB;IAED,OAAO,KAAK,WAAW,GAKtB;IAED,OAAO,KAAK,UAAU,GAErB;IAED,YAAY,IAAI,OAAO,CAEtB;IAEK,QAAQ,IAAI,OAAO,CAAC,iBAAiB,CAAC,CA8B3C;IAED,8BAA8B;IAC9B,cAAc,IAAI;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAIxD;IAED,WAAW,IAAI,MAAM,CAEpB;IAEK,UAAU,CACd,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,MAAM,CAAC,CAajB;IAEK,YAAY,CAChB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAwBpD;YAEa,aAAa;IAoC3B,6DAA6D;IACvD,aAAa,CACjB,OAAO,EAAE,MAAM,EACf,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,UAAU,CAAC,CAmCrB;IAED,OAAO,CAAC,WAAW;IAWnB,OAAO,CAAC,iBAAiB;YAiBX,iBAAiB;IAmD/B;;;OAGG;IACG,aAAa,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAqF3D;CACF;AAED,eAAO,MAAM,gBAAgB,kBAAyB,CAAC"}