@oneuptime/common 13.0.8 → 14.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (333) hide show
  1. package/Models/AnalyticsModels/AuditLog.ts +23 -15
  2. package/Models/DatabaseModels/GlobalConfig.ts +24 -0
  3. package/Models/DatabaseModels/Monitor.ts +3 -2
  4. package/Models/DatabaseModels/MonitorTemplate.ts +2 -1
  5. package/Scripts/generate-service-worker.js +65 -4
  6. package/Server/API/BaseAPI.ts +26 -5
  7. package/Server/API/GlobalConfigAPI.ts +228 -462
  8. package/Server/API/ProjectOIDC.ts +25 -16
  9. package/Server/API/ProjectSSO.ts +24 -16
  10. package/Server/API/StatusPageAPI.ts +100 -42
  11. package/Server/API/TeamMemberAPI.ts +10 -1
  12. package/Server/Enterprise/EnterpriseEdition.ts +649 -0
  13. package/Server/Enterprise/EnterpriseFeature.ts +48 -0
  14. package/Server/Enterprise/EnterpriseLicenseSnapshot.ts +192 -0
  15. package/Server/Enterprise/EnterpriseServerModule.ts +233 -0
  16. package/Server/EnvironmentConfig.ts +147 -2
  17. package/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.ts +25 -0
  18. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
  19. package/Server/Middleware/UserAuthorization.ts +38 -16
  20. package/Server/Services/AuditLogService.ts +84 -1079
  21. package/Server/Services/EnterpriseLicenseService.ts +38 -0
  22. package/Server/Services/GlobalConfigService.ts +80 -1
  23. package/Server/Services/MonitorProbeService.ts +116 -20
  24. package/Server/Services/MonitorService.ts +56 -4
  25. package/Server/Services/MonitorStatusTimelineService.ts +284 -0
  26. package/Server/Services/MonitorTemplateService.ts +26 -0
  27. package/Server/Services/ProjectService.ts +284 -0
  28. package/Server/Services/RumSessionPinService.ts +25 -6
  29. package/Server/Services/StatusPagePrivateUserService.ts +7 -3
  30. package/Server/Services/StatusPageService.ts +78 -1
  31. package/Server/Services/TeamMemberService.ts +11 -0
  32. package/Server/Services/TeamService.ts +10 -0
  33. package/Server/Services/UserService.ts +10 -17
  34. package/Server/Types/Database/Permissions/CreatePermission.ts +15 -0
  35. package/Server/Types/Database/Permissions/EditionPermission.ts +208 -18
  36. package/Server/Types/Database/Permissions/TablePermission.ts +10 -3
  37. package/Server/Types/Database/Permissions/UpdatePermission.ts +29 -0
  38. package/Server/Types/Markdown.ts +41 -0
  39. package/Server/Utils/CommunityEditionSsoReport.ts +361 -0
  40. package/Server/Utils/EditionEnforcement.ts +233 -0
  41. package/Server/Utils/FrontendEnvironment.ts +41 -2
  42. package/Server/Utils/InstanceHealth/RedisHealth.ts +12 -277
  43. package/Server/Utils/Monitor/AffectedResourceList.ts +190 -0
  44. package/Server/Utils/Monitor/Criteria/EvaluateOverTime.ts +10 -1
  45. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +543 -333
  46. package/Server/Utils/Monitor/MonitoringIntervalValidator.ts +116 -0
  47. package/Server/Utils/Workspace/Slack/Slack.ts +423 -10
  48. package/Tests/App/Accounts/LoginPasskey.test.tsx +18 -0
  49. package/Tests/App/Accounts/LoginSsoEdition.test.tsx +616 -0
  50. package/Tests/App/AdminDashboard/AdminAuthenticationSsoEdition.test.tsx +217 -0
  51. package/Tests/App/AdminDashboard/AdminEnterprisePluginPage.test.tsx +357 -0
  52. package/Tests/App/AdminDashboard/EnterpriseLicensesShell.test.tsx +214 -0
  53. package/Tests/App/AdminDashboard/GlobalSSOEnterpriseShells.test.tsx +271 -0
  54. package/Tests/App/AdminDashboard/HealthShells.test.tsx +659 -0
  55. package/Tests/App/Dashboard/AuditLogsAndComplianceShells.test.tsx +572 -0
  56. package/Tests/App/Dashboard/EnterpriseFeatureUpgrade.test.tsx +547 -0
  57. package/Tests/App/Dashboard/EnterprisePluginPage.test.tsx +667 -0
  58. package/Tests/App/Dashboard/IdentityEnterpriseShells.test.tsx +319 -0
  59. package/Tests/App/Dashboard/OnboardingSsoEmptyState.test.tsx +185 -0
  60. package/Tests/App/Dashboard/SecurityEventConnectionDiagnostics.test.tsx +45 -9
  61. package/Tests/App/Dashboard/SecurityEventDetailPanel.test.tsx +399 -0
  62. package/Tests/App/Dashboard/SecurityEventListRow.test.tsx +214 -0
  63. package/Tests/App/Dashboard/SecurityEventsEmptyState.test.tsx +1 -83
  64. package/Tests/App/Dashboard/SecurityEventsNavTabs.test.tsx +248 -0
  65. package/Tests/App/Dashboard/SecurityEventsViewer.test.tsx +1203 -0
  66. package/Tests/App/Dashboard/UserEmailCallSites.test.tsx +11 -91
  67. package/Tests/App/StatusPage/StatusPageSsoEmptyState.test.tsx +319 -0
  68. package/Tests/Helpers/RefreshAwareApiScan.ts +757 -0
  69. package/Tests/Helpers/TenantScopedRequestScan.ts +515 -0
  70. package/Tests/Scripts/GenerateServiceWorker.test.ts +931 -0
  71. package/Tests/Server/API/BaseAPICreateItemDoesNotMutateModel.test.ts +130 -0
  72. package/Tests/Server/API/GlobalConfigLicense.test.ts +742 -497
  73. package/Tests/Server/API/OnCallReadinessAPI.test.ts +35 -909
  74. package/Tests/Server/API/SsoProviderListingsEdition.test.ts +432 -0
  75. package/Tests/Server/API/TeamMemberLeaveScimLockEdition.test.ts +252 -0
  76. package/Tests/Server/Enterprise/EnterpriseEdition.test.ts +824 -0
  77. package/Tests/Server/Enterprise/EnterpriseFeatureActive.test.ts +643 -0
  78. package/Tests/Server/Enterprise/EnterpriseLicenseSnapshot.test.ts +294 -0
  79. package/Tests/Server/Enterprise/EnterpriseModelFeatureMap.test.ts +93 -0
  80. package/Tests/Server/Enterprise/EnterpriseOnlyModulesLiveInEe.test.ts +582 -0
  81. package/Tests/Server/Enterprise/EnterpriseServerModule.test.ts +247 -0
  82. package/Tests/Server/Enterprise/FakeEnterpriseModule.ts +502 -0
  83. package/Tests/Server/Enterprise/TestBillingFlag.ts +70 -0
  84. package/Tests/Server/EnvironmentConfigEnterpriseEdition.test.ts +314 -0
  85. package/Tests/Server/Infrastructure/ContainerBootConfiguration.test.ts +289 -0
  86. package/Tests/Server/Infrastructure/E2EClickHouseFixtureAccess.test.ts +5 -1
  87. package/Tests/Server/Middleware/UserAuthorization.test.ts +37 -2
  88. package/Tests/Server/Middleware/UserAuthorizationEditionEnforcement.test.ts +516 -0
  89. package/Tests/Server/Services/AuditLogService.test.ts +460 -990
  90. package/Tests/Server/Services/CreateAndReadResponsesKeepIds.test.ts +263 -0
  91. package/Tests/Server/Services/EnterpriseLicenseServiceKeyGeneration.test.ts +151 -0
  92. package/Tests/Server/Services/GlobalConfigServiceLicenseColumns.test.ts +357 -0
  93. package/Tests/Server/Services/MonitorDestinationInfoIPv6.test.ts +101 -0
  94. package/Tests/Server/Services/MonitorProbeServiceIntervalScheduling.test.ts +333 -0
  95. package/Tests/Server/Services/MonitorStatusTimelineDailyAggregates.test.ts +303 -0
  96. package/Tests/Server/Services/ProjectServiceAuditLogLicense.test.ts +701 -0
  97. package/Tests/Server/Services/ProjectServiceAuditLogSettingsCache.test.ts +31 -35
  98. package/Tests/Server/Services/ScimPushGroupsTeamLocksEdition.test.ts +431 -0
  99. package/Tests/Server/Services/SsoRequirementReadMasking.test.ts +419 -0
  100. package/Tests/Server/Services/SsoRequirementWriteGuard.test.ts +769 -0
  101. package/Tests/Server/Services/StatusPagePrivateUserInvitationPolicy.test.ts +94 -0
  102. package/Tests/Server/Services/UserAuthenticationService.test.ts +35 -0
  103. package/Tests/Server/Services/UserServiceSeatLimit.test.ts +94 -56
  104. package/Tests/Server/Types/Database/Permissions/EditionPermission.test.ts +1823 -0
  105. package/Tests/Server/Types/Markdown.test.ts +181 -0
  106. package/Tests/Server/Utils/CommunityEditionSsoReport.test.ts +565 -0
  107. package/Tests/Server/Utils/EditionEnforcement.test.ts +303 -0
  108. package/Tests/Server/Utils/FrontendEnvironment.test.ts +367 -0
  109. package/Tests/Server/Utils/InstanceHealth/RedisHealth.test.ts +38 -418
  110. package/Tests/Server/Utils/Monitor/AffectedResourceList.test.ts +518 -0
  111. package/Tests/Server/Utils/Monitor/Criteria/EvaluateOverTime.test.ts +24 -4
  112. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +934 -96
  113. package/Tests/Server/Utils/Monitor/MonitoringIntervalValidator.test.ts +188 -0
  114. package/Tests/Server/Utils/Workspace/Slack/SlackMarkdownSectionSplit.test.ts +1209 -0
  115. package/Tests/Types/API/HostnameFromAuthority.test.ts +20 -10
  116. package/Tests/Types/API/HostnameIPv6.test.ts +149 -0
  117. package/Tests/Types/Database/CanonicalModelInstance.test.ts +190 -0
  118. package/Tests/UI/Components/EditionLabelLapseCopy.ts +104 -0
  119. package/Tests/UI/Components/EditionLabelLicenseManagerWiring.test.tsx +254 -0
  120. package/Tests/UI/Components/EditionLabelLicenseRefresh.test.tsx +84 -178
  121. package/Tests/UI/Components/EditionLabelLicenseStatus.test.tsx +1586 -0
  122. package/Tests/UI/Components/EditionLabelLicenseWritesGuard.test.tsx +157 -0
  123. package/Tests/UI/Components/Graphs/DayUptimeGraph.test.tsx +49 -2
  124. package/Tests/UI/Components/MarkdownConverters.test.ts +684 -0
  125. package/Tests/UI/Components/ModelListEmptyState.test.tsx +289 -0
  126. package/Tests/UI/Components/TelemetryViewer/TelemetryViewerEmptyContent.test.tsx +131 -0
  127. package/Tests/UI/EsbuildEnterpriseAlias.test.ts +1127 -0
  128. package/Tests/Utils/HostAddressUtil.test.ts +138 -0
  129. package/Tests/Utils/Monitor/MonitorDestinationUtil.test.ts +313 -0
  130. package/Tests/Utils/Monitor/MonitoringIntervalUtil.test.ts +304 -0
  131. package/Tests/Utils/StatusPage/UptimeDailyAggregateUtil.test.ts +248 -0
  132. package/Types/API/Hostname.ts +63 -16
  133. package/Types/Database/AccessControl/ColumnAccessControl.ts +19 -7
  134. package/Types/Database/AccessControl/ColumnBillingAccessControl.ts +19 -7
  135. package/Types/Database/AccessControl/OwnerOnlyColumn.ts +15 -6
  136. package/Types/Database/CanonicalModelInstance.ts +102 -0
  137. package/Types/Database/TableColumn.ts +20 -6
  138. package/Types/EnterpriseLicense/EnterpriseLicensePeriods.ts +29 -0
  139. package/Types/IP/IPv6.ts +6 -1
  140. package/Types/Monitor/MonitorStep.ts +6 -1
  141. package/Types/Monitor/ProxmoxAlertTemplates.ts +1 -1
  142. package/Types/StatusPage/UptimeDailyAggregate.ts +110 -0
  143. package/UI/Components/EditionLabel/EditionLabel.tsx +796 -1195
  144. package/UI/Components/EditionLabel/LicenseManager.ts +119 -0
  145. package/UI/Components/Graphs/DayUptimeGraph.tsx +123 -15
  146. package/UI/Components/Markdown.tsx/MarkdownConverters.ts +0 -0
  147. package/UI/Components/ModelList/ModelList.tsx +11 -1
  148. package/UI/Components/MonitorGraphs/Uptime.tsx +69 -0
  149. package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +28 -12
  150. package/UI/esbuild-enterprise.js +263 -0
  151. package/Utils/EnterpriseLicense/EnterpriseLicenseUsage.ts +7 -2
  152. package/Utils/HostAddressUtil.ts +94 -0
  153. package/Utils/Monitor/MonitorDestinationUtil.ts +157 -0
  154. package/Utils/Monitor/MonitoringIntervalUtil.ts +436 -0
  155. package/Utils/StatusPage/UptimeDailyAggregateUtil.ts +192 -0
  156. package/build/dist/Models/AnalyticsModels/AuditLog.js +23 -15
  157. package/build/dist/Models/AnalyticsModels/AuditLog.js.map +1 -1
  158. package/build/dist/Models/DatabaseModels/GlobalConfig.js +25 -0
  159. package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
  160. package/build/dist/Models/DatabaseModels/Monitor.js +2 -2
  161. package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
  162. package/build/dist/Models/DatabaseModels/MonitorTemplate.js +2 -1
  163. package/build/dist/Models/DatabaseModels/MonitorTemplate.js.map +1 -1
  164. package/build/dist/Server/API/BaseAPI.js +26 -5
  165. package/build/dist/Server/API/BaseAPI.js.map +1 -1
  166. package/build/dist/Server/API/GlobalConfigAPI.js +148 -344
  167. package/build/dist/Server/API/GlobalConfigAPI.js.map +1 -1
  168. package/build/dist/Server/API/ProjectOIDC.js +24 -16
  169. package/build/dist/Server/API/ProjectOIDC.js.map +1 -1
  170. package/build/dist/Server/API/ProjectSSO.js +24 -16
  171. package/build/dist/Server/API/ProjectSSO.js.map +1 -1
  172. package/build/dist/Server/API/StatusPageAPI.js +93 -43
  173. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  174. package/build/dist/Server/API/TeamMemberAPI.js +8 -1
  175. package/build/dist/Server/API/TeamMemberAPI.js.map +1 -1
  176. package/build/dist/Server/Enterprise/EnterpriseEdition.js +466 -0
  177. package/build/dist/Server/Enterprise/EnterpriseEdition.js.map +1 -0
  178. package/build/dist/Server/Enterprise/EnterpriseFeature.js +39 -0
  179. package/build/dist/Server/Enterprise/EnterpriseFeature.js.map +1 -0
  180. package/build/dist/Server/Enterprise/EnterpriseLicenseSnapshot.js +70 -0
  181. package/build/dist/Server/Enterprise/EnterpriseLicenseSnapshot.js.map +1 -0
  182. package/build/dist/Server/Enterprise/EnterpriseServerModule.js +84 -0
  183. package/build/dist/Server/Enterprise/EnterpriseServerModule.js.map +1 -0
  184. package/build/dist/Server/EnvironmentConfig.js +84 -2
  185. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  186. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.js +18 -0
  187. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.js.map +1 -0
  188. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
  189. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  190. package/build/dist/Server/Middleware/UserAuthorization.js +30 -11
  191. package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
  192. package/build/dist/Server/Services/AuditLogService.js +71 -740
  193. package/build/dist/Server/Services/AuditLogService.js.map +1 -1
  194. package/build/dist/Server/Services/EnterpriseLicenseService.js +34 -0
  195. package/build/dist/Server/Services/EnterpriseLicenseService.js.map +1 -1
  196. package/build/dist/Server/Services/GlobalConfigService.js +63 -0
  197. package/build/dist/Server/Services/GlobalConfigService.js.map +1 -1
  198. package/build/dist/Server/Services/MonitorProbeService.js +90 -17
  199. package/build/dist/Server/Services/MonitorProbeService.js.map +1 -1
  200. package/build/dist/Server/Services/MonitorService.js +45 -4
  201. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  202. package/build/dist/Server/Services/MonitorStatusTimelineService.js +242 -0
  203. package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
  204. package/build/dist/Server/Services/MonitorTemplateService.js +16 -0
  205. package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
  206. package/build/dist/Server/Services/ProjectService.js +214 -0
  207. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  208. package/build/dist/Server/Services/RumSessionPinService.js +24 -6
  209. package/build/dist/Server/Services/RumSessionPinService.js.map +1 -1
  210. package/build/dist/Server/Services/StatusPagePrivateUserService.js +7 -3
  211. package/build/dist/Server/Services/StatusPagePrivateUserService.js.map +1 -1
  212. package/build/dist/Server/Services/StatusPageService.js +71 -0
  213. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  214. package/build/dist/Server/Services/TeamMemberService.js +10 -0
  215. package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
  216. package/build/dist/Server/Services/TeamService.js +9 -0
  217. package/build/dist/Server/Services/TeamService.js.map +1 -1
  218. package/build/dist/Server/Services/UserService.js +10 -16
  219. package/build/dist/Server/Services/UserService.js.map +1 -1
  220. package/build/dist/Server/Types/Database/Permissions/CreatePermission.js +10 -0
  221. package/build/dist/Server/Types/Database/Permissions/CreatePermission.js.map +1 -1
  222. package/build/dist/Server/Types/Database/Permissions/EditionPermission.js +154 -14
  223. package/build/dist/Server/Types/Database/Permissions/EditionPermission.js.map +1 -1
  224. package/build/dist/Server/Types/Database/Permissions/TablePermission.js +10 -3
  225. package/build/dist/Server/Types/Database/Permissions/TablePermission.js.map +1 -1
  226. package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js +17 -0
  227. package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js.map +1 -1
  228. package/build/dist/Server/Types/Markdown.js +31 -0
  229. package/build/dist/Server/Types/Markdown.js.map +1 -1
  230. package/build/dist/Server/Utils/CommunityEditionSsoReport.js +223 -0
  231. package/build/dist/Server/Utils/CommunityEditionSsoReport.js.map +1 -0
  232. package/build/dist/Server/Utils/EditionEnforcement.js +187 -0
  233. package/build/dist/Server/Utils/EditionEnforcement.js.map +1 -0
  234. package/build/dist/Server/Utils/FrontendEnvironment.js +31 -2
  235. package/build/dist/Server/Utils/FrontendEnvironment.js.map +1 -1
  236. package/build/dist/Server/Utils/InstanceHealth/RedisHealth.js +6 -193
  237. package/build/dist/Server/Utils/InstanceHealth/RedisHealth.js.map +1 -1
  238. package/build/dist/Server/Utils/Monitor/AffectedResourceList.js +96 -0
  239. package/build/dist/Server/Utils/Monitor/AffectedResourceList.js.map +1 -0
  240. package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js +8 -1
  241. package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js.map +1 -1
  242. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +449 -261
  243. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  244. package/build/dist/Server/Utils/Monitor/MonitoringIntervalValidator.js +88 -0
  245. package/build/dist/Server/Utils/Monitor/MonitoringIntervalValidator.js.map +1 -0
  246. package/build/dist/Server/Utils/Workspace/Slack/Slack.js +331 -11
  247. package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
  248. package/build/dist/Types/API/Hostname.js +59 -11
  249. package/build/dist/Types/API/Hostname.js.map +1 -1
  250. package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js +19 -7
  251. package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js.map +1 -1
  252. package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js +19 -7
  253. package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js.map +1 -1
  254. package/build/dist/Types/Database/AccessControl/OwnerOnlyColumn.js +13 -6
  255. package/build/dist/Types/Database/AccessControl/OwnerOnlyColumn.js.map +1 -1
  256. package/build/dist/Types/Database/CanonicalModelInstance.js +88 -0
  257. package/build/dist/Types/Database/CanonicalModelInstance.js.map +1 -0
  258. package/build/dist/Types/Database/TableColumn.js +19 -6
  259. package/build/dist/Types/Database/TableColumn.js.map +1 -1
  260. package/build/dist/Types/EnterpriseLicense/EnterpriseLicensePeriods.js +28 -0
  261. package/build/dist/Types/EnterpriseLicense/EnterpriseLicensePeriods.js.map +1 -0
  262. package/build/dist/Types/IP/IPv6.js +6 -1
  263. package/build/dist/Types/IP/IPv6.js.map +1 -1
  264. package/build/dist/Types/Monitor/MonitorStep.js +5 -0
  265. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  266. package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js +1 -1
  267. package/build/dist/Types/StatusPage/UptimeDailyAggregate.js +32 -0
  268. package/build/dist/Types/StatusPage/UptimeDailyAggregate.js.map +1 -0
  269. package/build/dist/UI/Components/EditionLabel/EditionLabel.js +414 -585
  270. package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
  271. package/build/dist/UI/Components/EditionLabel/LicenseManager.js +2 -0
  272. package/build/dist/UI/Components/EditionLabel/LicenseManager.js.map +1 -0
  273. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js +90 -17
  274. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js.map +1 -1
  275. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js +0 -0
  276. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js.map +1 -1
  277. package/build/dist/UI/Components/ModelList/ModelList.js +4 -1
  278. package/build/dist/UI/Components/ModelList/ModelList.js.map +1 -1
  279. package/build/dist/UI/Components/MonitorGraphs/Uptime.js +42 -1
  280. package/build/dist/UI/Components/MonitorGraphs/Uptime.js.map +1 -1
  281. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +2 -2
  282. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
  283. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js +6 -2
  284. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js.map +1 -1
  285. package/build/dist/Utils/HostAddressUtil.js +80 -0
  286. package/build/dist/Utils/HostAddressUtil.js.map +1 -0
  287. package/build/dist/Utils/Monitor/MonitorDestinationUtil.js +127 -0
  288. package/build/dist/Utils/Monitor/MonitorDestinationUtil.js.map +1 -0
  289. package/build/dist/Utils/Monitor/MonitoringIntervalUtil.js +374 -0
  290. package/build/dist/Utils/Monitor/MonitoringIntervalUtil.js.map +1 -0
  291. package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js +148 -0
  292. package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js.map +1 -0
  293. package/jest.config.json +3 -1
  294. package/package.json +1 -1
  295. package/test-setup.sh +103 -34
  296. package/tsconfig.json +13 -0
  297. package/Server/API/EnterpriseLicenseAPI.ts +0 -925
  298. package/Server/API/TeamComplianceAPI.ts +0 -158
  299. package/Server/Middleware/SCIMAuthorization.ts +0 -141
  300. package/Server/Services/TeamComplianceService.ts +0 -733
  301. package/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.ts +0 -186
  302. package/Server/Utils/InstanceHealth/PostgresHealth.ts +0 -286
  303. package/Tests/App/AdminDashboard/EnterpriseLicenseInstanceActivity.test.tsx +0 -451
  304. package/Tests/App/Dashboard/AuditLogsTable.test.tsx +0 -598
  305. package/Tests/App/Dashboard/SecurityEventsExplorer.test.tsx +0 -761
  306. package/Tests/App/Dashboard/SecurityEventsSideMenu.test.tsx +0 -247
  307. package/Tests/App/Dashboard/SecurityEventsTableColumns.test.tsx +0 -382
  308. package/Tests/App/Dashboard/SecurityEventsVolumeChart.test.tsx +0 -321
  309. package/Tests/Server/API/EnterpriseLicenseReportUserCount.test.ts +0 -1851
  310. package/Tests/Server/Middleware/SCIMAuthorization.test.ts +0 -525
  311. package/Tests/Server/Services/TeamComplianceServiceBehaviour.test.ts +0 -1845
  312. package/Tests/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.test.ts +0 -495
  313. package/Tests/Server/Utils/InstanceHealth/PostgresHealth.test.ts +0 -337
  314. package/Tests/Utils/EnterpriseLicenseSeats.test.ts +0 -576
  315. package/Tests/Utils/EnterpriseLicenseSync.test.ts +0 -568
  316. package/Utils/EnterpriseLicense/EnterpriseLicenseSeats.ts +0 -287
  317. package/Utils/EnterpriseLicense/EnterpriseLicenseSync.ts +0 -244
  318. package/build/dist/Server/API/EnterpriseLicenseAPI.js +0 -646
  319. package/build/dist/Server/API/EnterpriseLicenseAPI.js.map +0 -1
  320. package/build/dist/Server/API/TeamComplianceAPI.js +0 -111
  321. package/build/dist/Server/API/TeamComplianceAPI.js.map +0 -1
  322. package/build/dist/Server/Middleware/SCIMAuthorization.js +0 -124
  323. package/build/dist/Server/Middleware/SCIMAuthorization.js.map +0 -1
  324. package/build/dist/Server/Services/TeamComplianceService.js +0 -537
  325. package/build/dist/Server/Services/TeamComplianceService.js.map +0 -1
  326. package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js +0 -145
  327. package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js.map +0 -1
  328. package/build/dist/Server/Utils/InstanceHealth/PostgresHealth.js +0 -194
  329. package/build/dist/Server/Utils/InstanceHealth/PostgresHealth.js.map +0 -1
  330. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js +0 -168
  331. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js.map +0 -1
  332. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSync.js +0 -174
  333. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSync.js.map +0 -1
@@ -12,26 +12,58 @@ import BaseAPI from "./BaseAPI";
12
12
  import GlobalConfig from "../../Models/DatabaseModels/GlobalConfig";
13
13
  import ObjectID from "../../Types/ObjectID";
14
14
  import { JSONObject } from "../../Types/JSON";
15
- import BadDataException from "../../Types/Exception/BadDataException";
16
- import API from "../../Utils/API";
17
- import HTTPErrorResponse from "../../Types/API/HTTPErrorResponse";
18
- import HTTPResponse from "../../Types/API/HTTPResponse";
19
- import PartialEntity from "../../Types/Database/PartialEntity";
20
- import {
21
- AppVersion,
22
- DisableUpdateCheck,
23
- EnterpriseLicenseValidationUrl,
24
- Host,
25
- } from "../EnvironmentConfig";
15
+ import Select from "../Types/Database/Select";
16
+ import { AppVersion, DisableUpdateCheck } from "../EnvironmentConfig";
26
17
  import EnterpriseLicenseInstanceSummary from "../../Types/EnterpriseLicense/EnterpriseLicenseInstanceSummary";
27
18
  import VersionUtil from "../../Utils/VersionUtil";
28
19
  import UserMiddleware from "../Middleware/UserAuthorization";
29
20
  import NotAuthenticatedException from "../../Types/Exception/NotAuthenticatedException";
30
- import MasterAdminAuthorization from "../Middleware/MasterAdminAuthorization";
31
- import EnterpriseLicenseSeatUtil from "../Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil";
32
- import { SeatUsage } from "../../Utils/EnterpriseLicense/EnterpriseLicenseSeats";
33
- import UserService from "../Services/UserService";
34
- import PositiveNumber from "../../Types/PositiveNumber";
21
+ import EnterpriseEdition from "../Enterprise/EnterpriseEdition";
22
+ import {
23
+ EnterpriseLicenseSnapshot,
24
+ EnterpriseLicenseSnapshotUtil,
25
+ SeatUsage,
26
+ } from "../Enterprise/EnterpriseLicenseSnapshot";
27
+
28
+ /*
29
+ * Who is asking for the license state, which decides how much of it they get.
30
+ *
31
+ * master-admin everything, including the license key, the token, the
32
+ * instance topology, this installation's version and seat
33
+ * usage - the things a master admin needs to manage the
34
+ * license and nobody else has any business reading.
35
+ * public anybody else, signed in or not (this route also serves the
36
+ * signed-out login page): only what the edition pill shows.
37
+ */
38
+ export type LicenseResponseAudience = "master-admin" | "public";
39
+
40
+ export interface BuildLicenseResponseData {
41
+ audience: LicenseResponseAudience;
42
+ // Whether the enterprise module is loaded in this process.
43
+ isEnterpriseEditionLoaded: boolean;
44
+ // The license snapshot, or null on the Community Edition.
45
+ snapshot: EnterpriseLicenseSnapshot | null;
46
+ /*
47
+ * The GlobalConfig row, selected with LICENSE_RESPONSE_CONFIG_SELECT. Only
48
+ * read for the master-admin audience.
49
+ */
50
+ config: GlobalConfig | null;
51
+ // Seat usage as the license client enforces it. Only for master admins.
52
+ seatUsage: SeatUsage | null;
53
+ }
54
+
55
+ // Everything buildLicenseResponse reads off the GlobalConfig row.
56
+ export const LICENSE_RESPONSE_CONFIG_SELECT: Select<GlobalConfig> = {
57
+ enterpriseLicenseKey: true,
58
+ enterpriseLicenseToken: true,
59
+ enterpriseLicenseCurrentUserCount: true,
60
+ enterpriseLicenseUserCountUpdatedAt: true,
61
+ enterpriseLicenseInstances: true,
62
+ instanceId: true,
63
+ latestReleaseVersion: true,
64
+ latestReleasePublishedAt: true,
65
+ latestReleaseCheckedAt: true,
66
+ };
35
67
 
36
68
  export default class GlobalConfigAPI extends BaseAPI<
37
69
  GlobalConfig,
@@ -66,6 +98,20 @@ export default class GlobalConfigAPI extends BaseAPI<
66
98
  },
67
99
  );
68
100
 
101
+ /*
102
+ * The license state of this installation, for the edition pill and the
103
+ * license dialog.
104
+ *
105
+ * This route stays in core so the Community Edition can still serve the
106
+ * version and update-check half of the dialog. The license half comes
107
+ * from the Enterprise license client through EnterpriseEdition; activating
108
+ * and refreshing a license (the POSTs on this path) are served by the
109
+ * Enterprise module itself (ee/Server/License).
110
+ *
111
+ * This route also serves the login page (before sign-in), so it cannot
112
+ * require authentication outright. Anybody but a master admin gets only
113
+ * what the edition pill shows - see buildLicenseResponse.
114
+ */
69
115
  this.router.get(
70
116
  `${new this.entityType().getCrudApiPath()?.toString()}/license`,
71
117
  UserMiddleware.getUserMiddleware,
@@ -87,484 +133,190 @@ export default class GlobalConfigAPI extends BaseAPI<
87
133
  );
88
134
  }
89
135
 
90
- const config: GlobalConfig | null =
91
- await GlobalConfigService.findOneById({
92
- id: ObjectID.getZeroObjectID(),
93
- select: {
94
- enterpriseCompanyName: true,
95
- enterpriseLicenseExpiresAt: true,
96
- enterpriseLicenseKey: true,
97
- enterpriseLicenseToken: true,
98
- enterpriseLicenseIsEvaluation: true,
99
- enterpriseLicenseUserLimit: true,
100
- enterpriseLicenseCurrentUserCount: true,
101
- enterpriseLicenseUserCountUpdatedAt: true,
102
- enterpriseLicenseInstances: true,
103
- instanceId: true,
104
- latestReleaseVersion: true,
105
- latestReleasePublishedAt: true,
106
- latestReleaseCheckedAt: true,
107
- },
108
- props: {
109
- isRoot: true,
110
- },
111
- });
112
-
113
- /*
114
- * This route also serves the login page (before sign-in), so it
115
- * cannot require authentication outright. Anonymous callers only
116
- * get enough to render the edition pill — the license key, token
117
- * and instance topology require a signed-in user.
118
- */
119
- const isAuthenticatedUser: boolean = Boolean(
120
- (req as OneUptimeRequest).userAuthorization?.userId,
121
- );
136
+ const audience: LicenseResponseAudience =
137
+ GlobalConfigAPI.getLicenseResponseAudience(req);
138
+ const isEnterpriseEditionLoaded: boolean =
139
+ EnterpriseEdition.isLoaded();
122
140
 
123
- const licenseValid: boolean = Boolean(
124
- config?.enterpriseLicenseToken &&
125
- config?.enterpriseLicenseExpiresAt &&
126
- config.enterpriseLicenseExpiresAt.getTime() > Date.now(),
127
- );
141
+ const snapshot: EnterpriseLicenseSnapshot | null =
142
+ isEnterpriseEditionLoaded
143
+ ? await EnterpriseEdition.getLicenseSnapshot()
144
+ : null;
128
145
 
129
146
  /*
130
- * What the seat limit actually means on this installation right now,
131
- * as opposed to what oneuptime.com last reported. Only for signed-in
132
- * callers: it is derived from the live User table, and an anonymous
133
- * visitor on the login page has no business being told how close this
134
- * server is to refusing new accounts.
147
+ * Only a master admin's response carries anything read from the row
148
+ * or derived from the live User table, so nobody else costs a read.
135
149
  */
136
- const seatUsage: SeatUsage | null = isAuthenticatedUser
137
- ? await EnterpriseLicenseSeatUtil.getSeatUsageForLoadedGlobalConfig(
138
- {
139
- config: config,
140
- getLocalUserCount: GlobalConfigAPI.getLocalUserCount,
141
- },
142
- )
143
- : null;
144
-
145
- const responseBody: JSONObject = {
146
- companyName: config?.enterpriseCompanyName || null,
147
- expiresAt: config?.enterpriseLicenseExpiresAt
148
- ? config.enterpriseLicenseExpiresAt.toISOString()
149
- : null,
150
- licenseKey: isAuthenticatedUser
151
- ? config?.enterpriseLicenseKey || null
152
- : null,
153
- token: isAuthenticatedUser
154
- ? config?.enterpriseLicenseToken || null
155
- : null,
156
- licenseValid: licenseValid,
157
- /*
158
- * Whether this is an evaluation/testing license. Benign like the
159
- * company name and expiry, so it is not gated behind sign-in — the
160
- * edition modal shows the evaluation notice to anyone who opens it.
161
- */
162
- isEvaluationLicense: Boolean(config?.enterpriseLicenseIsEvaluation),
163
- userLimit:
164
- typeof config?.enterpriseLicenseUserLimit === "number"
165
- ? config.enterpriseLicenseUserLimit
166
- : null,
167
- currentUserCount:
168
- typeof config?.enterpriseLicenseCurrentUserCount === "number"
169
- ? config.enterpriseLicenseCurrentUserCount
170
- : null,
171
- userCountUpdatedAt: config?.enterpriseLicenseUserCountUpdatedAt
172
- ? config.enterpriseLicenseUserCountUpdatedAt.toISOString()
173
- : null,
174
- instances:
175
- isAuthenticatedUser &&
176
- Array.isArray(config?.enterpriseLicenseInstances)
177
- ? config.enterpriseLicenseInstances
178
- : [],
179
- instanceId:
180
- isAuthenticatedUser && config?.instanceId
181
- ? config.instanceId.toString()
182
- : null,
183
- /*
184
- * Which build this installation runs, and whether a newer one has
185
- * been released, are gated the same way as the instance topology:
186
- * telling an anonymous visitor on the login page that this server
187
- * is behind on patches advertises an unpatched target.
188
- */
189
- currentVersion: isAuthenticatedUser ? AppVersion : null,
190
- latestVersion: isAuthenticatedUser
191
- ? config?.latestReleaseVersion || null
192
- : null,
193
- latestVersionPublishedAt:
194
- isAuthenticatedUser && config?.latestReleasePublishedAt
195
- ? config.latestReleasePublishedAt.toISOString()
196
- : null,
197
- latestVersionCheckedAt:
198
- isAuthenticatedUser && config?.latestReleaseCheckedAt
199
- ? config.latestReleaseCheckedAt.toISOString()
200
- : null,
201
- isUpdateAvailable: isAuthenticatedUser
202
- ? VersionUtil.isUpdateAvailable({
203
- currentVersion: AppVersion,
204
- latestVersion: config?.latestReleaseVersion,
150
+ const config: GlobalConfig | null =
151
+ audience === "master-admin"
152
+ ? await GlobalConfigService.findOneById({
153
+ id: ObjectID.getZeroObjectID(),
154
+ select: LICENSE_RESPONSE_CONFIG_SELECT,
155
+ props: {
156
+ isRoot: true,
157
+ },
205
158
  })
206
- : false,
207
- /*
208
- * Lets the modal say "update checks are off" instead of "has not
209
- * checked yet", which would be a promise the installation is never
210
- * going to keep.
211
- */
212
- isUpdateCheckDisabled: isAuthenticatedUser
213
- ? DisableUpdateCheck
214
- : false,
215
- ...GlobalConfigAPI.getSeatUsageResponseFields(seatUsage),
216
- };
217
-
218
- return Response.sendJsonObjectResponse(req, res, responseBody);
219
- } catch (err) {
220
- next(err);
221
- }
222
- },
223
- );
224
-
225
- /*
226
- * Activating (or replacing) the license key for the whole installation.
227
- *
228
- * Master admin only. This writes the terms that bound how many users the
229
- * installation may have, so anyone who can reach it can change the seat
230
- * limit UserService now enforces. It used to run on
231
- * UserMiddleware.getUserMiddleware, which lets anonymous callers through
232
- * (it has to — the GET above serves the signed-out login page), so the
233
- * route was in practice unauthenticated.
234
- */
235
- this.router.post(
236
- `${new this.entityType().getCrudApiPath()?.toString()}/license`,
237
- MasterAdminAuthorization.isAuthorizedMasterAdminMiddleware,
238
- async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => {
239
- try {
240
- const licenseKey: string =
241
- (req.body["licenseKey"] as string | undefined)?.trim() || "";
242
-
243
- if (!licenseKey) {
244
- throw new BadDataException("License key is required");
245
- }
246
-
247
- const responseBody: JSONObject =
248
- await this.validateAndStoreLicenseKey(licenseKey);
249
-
250
- return Response.sendJsonObjectResponse(req, res, responseBody);
159
+ : null;
160
+
161
+ const seatUsage: SeatUsage | null =
162
+ audience === "master-admin" && isEnterpriseEditionLoaded
163
+ ? await EnterpriseEdition.getSeatUsage()
164
+ : null;
165
+
166
+ return Response.sendJsonObjectResponse(
167
+ req,
168
+ res,
169
+ GlobalConfigAPI.buildLicenseResponse({
170
+ audience,
171
+ isEnterpriseEditionLoaded,
172
+ snapshot,
173
+ config,
174
+ seatUsage,
175
+ }),
176
+ );
251
177
  } catch (err) {
252
178
  next(err);
253
179
  }
254
180
  },
255
181
  );
182
+ }
256
183
 
257
- /*
258
- * Re-fetch the license this installation already holds.
259
- *
260
- * The seat limit and the expiry live on oneuptime.com and can change on
261
- * any day — a customer buys ten more seats at noon. The daily report job
262
- * picks that up eventually; this is the button an administrator presses
263
- * when "eventually" is not good enough, and it is the only way to apply a
264
- * change without re-typing the key.
265
- *
266
- * Deliberately takes no license key: it uses the stored one. A refresh
267
- * that accepted a key would be an activation with a friendlier name, and
268
- * would let a mistyped key replace a working license by accident.
269
- */
270
- this.router.post(
271
- `${new this.entityType().getCrudApiPath()?.toString()}/license/refresh`,
272
- MasterAdminAuthorization.isAuthorizedMasterAdminMiddleware,
273
- async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => {
274
- try {
275
- const config: GlobalConfig | null =
276
- await GlobalConfigService.findOneById({
277
- id: ObjectID.getZeroObjectID(),
278
- select: {
279
- enterpriseLicenseKey: true,
280
- },
281
- props: {
282
- isRoot: true,
283
- },
284
- });
285
-
286
- const licenseKey: string = config?.enterpriseLicenseKey?.trim() || "";
287
-
288
- if (!licenseKey) {
289
- throw new BadDataException(
290
- "This installation does not have an enterprise license key yet. Enter a license key to activate it first.",
291
- );
292
- }
293
-
294
- const responseBody: JSONObject =
295
- await this.validateAndStoreLicenseKey(licenseKey);
296
-
297
- return Response.sendJsonObjectResponse(req, res, responseBody);
298
- } catch (err) {
299
- next(err);
300
- }
301
- },
302
- );
184
+ /*
185
+ * A master admin is recognised from the verified access token that
186
+ * UserMiddleware.getUserMiddleware decoded. Anything else - no token, an
187
+ * API key, a status-page user, a signed-in project member - is "public".
188
+ */
189
+ public static getLicenseResponseAudience(
190
+ req: ExpressRequest,
191
+ ): LicenseResponseAudience {
192
+ return (req as OneUptimeRequest).userAuthorization?.isMasterAdmin === true
193
+ ? "master-admin"
194
+ : "public";
303
195
  }
304
196
 
305
197
  /*
306
- * Ask oneuptime.com what this license key is worth today, and mirror the
307
- * answer into GlobalConfig.
198
+ * The body of GET /global-config/license, and of the Enterprise license
199
+ * client's activation and refresh responses, so the three can never
200
+ * disagree on a field.
308
201
  *
309
- * Shared by activation and refresh so the two cannot drift: the whole point
310
- * of refresh is that it applies exactly what activation would have applied,
311
- * and a second hand-written copy of this mapping is how the seat limit came
312
- * to be dropped on the floor by the daily report job before.
202
+ * licenseValid is true for a valid license AND one in its grace period:
203
+ * grace means nothing has changed yet, and the dialog must not tell an
204
+ * administrator the license is gone while everything still works.
313
205
  */
314
- private async validateAndStoreLicenseKey(
315
- licenseKey: string,
316
- ): Promise<JSONObject> {
317
- const globalConfigId: ObjectID = ObjectID.getZeroObjectID();
318
-
319
- const existingConfig: GlobalConfig | null =
320
- await GlobalConfigService.findOneById({
321
- id: globalConfigId,
322
- select: {
323
- _id: true,
324
- instanceId: true,
325
- },
326
- props: {
327
- isRoot: true,
328
- ignoreHooks: true,
329
- },
330
- });
331
-
332
- /*
333
- * Send this instance's id and host along with the key so the
334
- * license server registers this instance against the license and
335
- * it shows up in the instance list on all instances that share
336
- * the license.
337
- */
338
- const instanceId: ObjectID =
339
- existingConfig?.instanceId || ObjectID.generate();
340
-
341
- const validationResponse: HTTPResponse<JSONObject> | HTTPErrorResponse =
342
- await API.post<JSONObject>({
343
- url: EnterpriseLicenseValidationUrl,
344
- data: {
345
- licenseKey,
346
- instanceId: instanceId.toString(),
347
- host: Host,
348
- /*
349
- * Sent here as well as from the daily report job so the version
350
- * lands on the license server the moment the key is validated,
351
- * rather than up to 24 hours later.
352
- */
353
- version: AppVersion,
354
- },
355
- });
356
-
357
- if (!validationResponse.isSuccess()) {
358
- const errorMessage: string =
359
- validationResponse instanceof HTTPErrorResponse
360
- ? validationResponse.message || "Failed to validate license key."
361
- : "Failed to validate license key.";
362
- throw new BadDataException(errorMessage);
363
- }
364
-
365
- const payload: JSONObject = validationResponse.data as JSONObject;
366
-
367
- const companyNameRaw: string =
368
- (payload["companyName"] as string | undefined)?.trim() || "";
369
- const expiresAtRaw: string =
370
- (payload["expiresAt"] as string | undefined) || "";
371
- const licenseKeyRaw: string =
372
- (payload["licenseKey"] as string | undefined)?.trim() || licenseKey;
373
- const licenseToken: string = (payload["token"] as string | undefined) || "";
374
-
375
- let licenseExpiry: Date | undefined = undefined;
376
- if (expiresAtRaw) {
377
- const parsedDate: Date = new Date(expiresAtRaw);
378
-
379
- if (Number.isNaN(parsedDate.getTime())) {
380
- throw new BadDataException(
381
- "License expiration returned from server is invalid.",
382
- );
383
- }
384
-
385
- licenseExpiry = parsedDate;
386
- }
387
-
388
- const userLimitRaw: unknown = payload["userLimit"];
389
- const userLimit: number | null =
390
- typeof userLimitRaw === "number" && Number.isFinite(userLimitRaw)
391
- ? userLimitRaw
392
- : null;
393
-
394
- const currentUserCountRaw: unknown = payload["currentUserCount"];
395
- const currentUserCount: number | null =
396
- typeof currentUserCountRaw === "number" &&
397
- Number.isFinite(currentUserCountRaw)
398
- ? currentUserCountRaw
399
- : null;
400
-
401
- const userCountUpdatedAtRaw: string | undefined = payload[
402
- "userCountUpdatedAt"
403
- ] as string | undefined;
404
- let userCountUpdatedAt: Date | null = null;
405
- if (userCountUpdatedAtRaw) {
406
- const parsedReportedAt: Date = new Date(userCountUpdatedAtRaw);
407
- if (!Number.isNaN(parsedReportedAt.getTime())) {
408
- userCountUpdatedAt = parsedReportedAt;
409
- }
410
- }
411
-
412
- const isEvaluationLicense: boolean =
413
- payload["isEvaluationLicense"] === true;
414
-
415
- const instances: Array<EnterpriseLicenseInstanceSummary> = Array.isArray(
416
- payload["instances"],
417
- )
418
- ? (payload["instances"] as Array<EnterpriseLicenseInstanceSummary>)
419
- : [];
420
-
421
- const updatePayload: PartialEntity<GlobalConfig> = {
422
- enterpriseCompanyName: companyNameRaw || null,
423
- enterpriseLicenseKey: licenseKeyRaw || null,
424
- enterpriseLicenseExpiresAt: licenseExpiry || null,
425
- enterpriseLicenseToken: licenseToken || null,
426
- enterpriseLicenseIsEvaluation: isEvaluationLicense,
427
- enterpriseLicenseUserLimit: userLimit,
428
- enterpriseLicenseCurrentUserCount: currentUserCount,
429
- enterpriseLicenseUserCountUpdatedAt: userCountUpdatedAt,
430
- enterpriseLicenseInstances: instances,
206
+ public static buildLicenseResponse(
207
+ data: BuildLicenseResponseData,
208
+ ): JSONObject {
209
+ const snapshot: EnterpriseLicenseSnapshot | null =
210
+ data.isEnterpriseEditionLoaded ? data.snapshot : null;
211
+
212
+ const publicFields: JSONObject = {
213
+ edition: data.isEnterpriseEditionLoaded ? "enterprise" : "community",
214
+ status: snapshot ? snapshot.status : null,
215
+ verification: snapshot ? snapshot.verification : null,
216
+ graceReason: snapshot?.graceReason || null,
217
+ licenseValid: EnterpriseLicenseSnapshotUtil.isUsable(snapshot),
218
+ companyName: snapshot?.companyName || null,
219
+ expiresAt: GlobalConfigAPI.toIsoString(snapshot?.expiresAt),
220
+ graceEndsAt: GlobalConfigAPI.toIsoString(snapshot?.graceEndsAt),
221
+ isEvaluation: Boolean(snapshot?.isEvaluation),
222
+ // The name older dialogs read; same value as isEvaluation.
223
+ isEvaluationLicense: Boolean(snapshot?.isEvaluation),
224
+ /*
225
+ * Which enterprise features the license covers: "all", or the
226
+ * EnterpriseFeature values it lists (null on the Community Edition).
227
+ * A valid license that leaves a feature out stops that feature (see
228
+ * EnterpriseEdition.isFeatureActive), which licenseValid alone cannot
229
+ * tell a screen.
230
+ */
231
+ features: GlobalConfigAPI.toFeaturesResponse(snapshot),
431
232
  };
432
233
 
433
- if (!existingConfig?.instanceId) {
434
- // Installs that predate instance ids: persist the one we generated.
435
- updatePayload.instanceId = instanceId;
234
+ if (data.audience !== "master-admin") {
235
+ return publicFields;
436
236
  }
437
237
 
438
- if (existingConfig) {
439
- await GlobalConfigService.updateOneById({
440
- id: globalConfigId,
441
- data: updatePayload,
442
- props: {
443
- isRoot: true,
444
- ignoreHooks: true,
445
- },
446
- });
447
- } else {
448
- const newConfig: GlobalConfig = new GlobalConfig();
449
- newConfig.id = globalConfigId;
450
-
451
- if (companyNameRaw) {
452
- newConfig.enterpriseCompanyName = companyNameRaw;
453
- }
454
-
455
- if (licenseKeyRaw) {
456
- newConfig.enterpriseLicenseKey = licenseKeyRaw;
457
- }
458
-
459
- if (licenseToken) {
460
- newConfig.enterpriseLicenseToken = licenseToken;
461
- }
462
-
463
- newConfig.enterpriseLicenseIsEvaluation = isEvaluationLicense;
464
-
465
- if (licenseExpiry) {
466
- newConfig.enterpriseLicenseExpiresAt = licenseExpiry;
467
- }
468
-
469
- if (userLimit !== null) {
470
- newConfig.enterpriseLicenseUserLimit = userLimit;
471
- }
472
-
473
- if (currentUserCount !== null) {
474
- newConfig.enterpriseLicenseCurrentUserCount = currentUserCount;
475
- }
476
-
477
- if (userCountUpdatedAt) {
478
- newConfig.enterpriseLicenseUserCountUpdatedAt = userCountUpdatedAt;
479
- }
480
-
481
- newConfig.enterpriseLicenseInstances = instances;
482
- newConfig.instanceId = instanceId;
483
-
484
- await GlobalConfigService.create({
485
- data: newConfig,
486
- props: {
487
- isRoot: true,
488
- ignoreHooks: true,
489
- },
490
- });
491
- }
238
+ const config: GlobalConfig | null = data.config;
492
239
 
493
240
  /*
494
- * Seat usage recomputed from what was just stored, so the dialog that
495
- * triggered this can show the new limit against the real user count
496
- * without a second round trip - and so an administrator who just bought
497
- * seats sees them land.
241
+ * The license columns mean nothing on the Community Edition (a leftover
242
+ * key from an earlier Enterprise image licenses nothing here), so only
243
+ * the version half of the dialog is filled in there.
498
244
  */
499
- const seatUsage: SeatUsage | null =
500
- await GlobalConfigAPI.getSeatUsageForResponse({
501
- userLimit: userLimit,
502
- currentUserCount: currentUserCount,
503
- instances: instances,
504
- instanceId: instanceId,
505
- });
245
+ const licenseConfig: GlobalConfig | null = snapshot ? config : null;
246
+
247
+ const licenseToken: string | null =
248
+ licenseConfig?.enterpriseLicenseToken || null;
249
+ const licenseKey: string | null =
250
+ licenseConfig?.enterpriseLicenseKey || null;
506
251
 
507
252
  return {
508
- companyName: companyNameRaw || null,
509
- expiresAt: licenseExpiry ? licenseExpiry.toISOString() : null,
510
- licenseKey: licenseKeyRaw || null,
511
- token: licenseToken || null,
512
- isEvaluationLicense: isEvaluationLicense,
513
- userLimit: userLimit,
514
- currentUserCount: currentUserCount,
515
- userCountUpdatedAt: userCountUpdatedAt
516
- ? userCountUpdatedAt.toISOString()
253
+ ...publicFields,
254
+ message: snapshot?.message || null,
255
+ licenseKey: licenseKey,
256
+ token: licenseToken,
257
+ /*
258
+ * "offline" when the license was activated by pasting a signed token:
259
+ * such an installation holds no license key and never calls home.
260
+ */
261
+ activationMode: licenseToken ? (licenseKey ? "online" : "offline") : null,
262
+ // From the signed claims for a verified license, else the stored column.
263
+ userLimit:
264
+ typeof snapshot?.userLimit === "number" ? snapshot.userLimit : null,
265
+ currentUserCount:
266
+ typeof licenseConfig?.enterpriseLicenseCurrentUserCount === "number"
267
+ ? licenseConfig.enterpriseLicenseCurrentUserCount
268
+ : null,
269
+ userCountUpdatedAt: GlobalConfigAPI.toIsoString(
270
+ licenseConfig?.enterpriseLicenseUserCountUpdatedAt,
271
+ ),
272
+ instances: Array.isArray(licenseConfig?.enterpriseLicenseInstances)
273
+ ? (licenseConfig?.enterpriseLicenseInstances as Array<EnterpriseLicenseInstanceSummary>)
274
+ : [],
275
+ instanceId: licenseConfig?.instanceId
276
+ ? licenseConfig.instanceId.toString()
517
277
  : null,
518
- instances: instances,
519
- instanceId: instanceId.toString(),
520
- ...GlobalConfigAPI.getSeatUsageResponseFields(seatUsage),
278
+ /*
279
+ * Which build this installation runs, and whether a newer one has been
280
+ * released. Master admins only: telling anybody else that this server
281
+ * is behind on patches advertises an unpatched target.
282
+ */
283
+ currentVersion: AppVersion,
284
+ latestVersion: config?.latestReleaseVersion || null,
285
+ latestVersionPublishedAt: GlobalConfigAPI.toIsoString(
286
+ config?.latestReleasePublishedAt,
287
+ ),
288
+ latestVersionCheckedAt: GlobalConfigAPI.toIsoString(
289
+ config?.latestReleaseCheckedAt,
290
+ ),
291
+ isUpdateAvailable: VersionUtil.isUpdateAvailable({
292
+ currentVersion: AppVersion,
293
+ latestVersion: config?.latestReleaseVersion,
294
+ }),
295
+ /*
296
+ * Lets the dialog say "update checks are off" instead of "has not
297
+ * checked yet", which would be a promise the installation is never
298
+ * going to keep.
299
+ */
300
+ isUpdateCheckDisabled: DisableUpdateCheck,
301
+ ...GlobalConfigAPI.getSeatUsageResponseFields(
302
+ snapshot ? data.seatUsage : null,
303
+ ),
521
304
  };
522
305
  }
523
306
 
524
- /*
525
- * Seat usage built from license terms held in memory rather than re-read
526
- * from the database. Used right after a write, where re-reading would race
527
- * the write it is describing.
528
- */
529
- private static async getSeatUsageForResponse(data: {
530
- userLimit: number | null;
531
- currentUserCount: number | null;
532
- instances: Array<EnterpriseLicenseInstanceSummary>;
533
- instanceId: ObjectID;
534
- }): Promise<SeatUsage | null> {
535
- const config: GlobalConfig = new GlobalConfig();
536
- config.instanceId = data.instanceId;
537
- config.enterpriseLicenseInstances = data.instances;
538
-
539
- if (data.userLimit !== null) {
540
- config.enterpriseLicenseUserLimit = data.userLimit;
307
+ // The license's features for a response: "all", a copy of the list, or null.
308
+ public static toFeaturesResponse(
309
+ snapshot: EnterpriseLicenseSnapshot | null,
310
+ ): "all" | Array<string> | null {
311
+ if (!snapshot) {
312
+ return null;
541
313
  }
542
314
 
543
- if (data.currentUserCount !== null) {
544
- config.enterpriseLicenseCurrentUserCount = data.currentUserCount;
315
+ if (snapshot.features === "all") {
316
+ return "all";
545
317
  }
546
318
 
547
- return EnterpriseLicenseSeatUtil.getSeatUsageForLoadedGlobalConfig({
548
- config: config,
549
- getLocalUserCount: GlobalConfigAPI.getLocalUserCount,
550
- });
551
- }
552
-
553
- /*
554
- * How many users exist on this installation right now. Deliberately the live
555
- * count rather than the last reported one: the number an administrator is
556
- * about to act on is the number that decides whether the next invitation
557
- * goes through.
558
- */
559
- private static async getLocalUserCount(): Promise<number> {
560
- const userCount: PositiveNumber = await UserService.countBy({
561
- query: {},
562
- props: {
563
- isRoot: true,
564
- },
565
- });
566
-
567
- return userCount.toNumber();
319
+ return Array.isArray(snapshot.features) ? [...snapshot.features] : [];
568
320
  }
569
321
 
570
322
  /*
@@ -573,7 +325,7 @@ export default class GlobalConfigAPI extends BaseAPI<
573
325
  * "this installation does not enforce them" by which fields are missing:
574
326
  * isSeatLimitEnforced is the single flag that answers that.
575
327
  */
576
- private static getSeatUsageResponseFields(
328
+ public static getSeatUsageResponseFields(
577
329
  seatUsage: SeatUsage | null,
578
330
  ): JSONObject {
579
331
  if (!seatUsage || !seatUsage.isEnforced) {
@@ -592,4 +344,18 @@ export default class GlobalConfigAPI extends BaseAPI<
592
344
  canAddMoreUsers: seatUsage.hasSeatForNewUser,
593
345
  };
594
346
  }
347
+
348
+ private static toIsoString(value: Date | null | undefined): string | null {
349
+ if (!value) {
350
+ return null;
351
+ }
352
+
353
+ const date: Date = value instanceof Date ? value : new Date(value);
354
+
355
+ if (Number.isNaN(date.getTime())) {
356
+ return null;
357
+ }
358
+
359
+ return date.toISOString();
360
+ }
595
361
  }