@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.
- package/Models/AnalyticsModels/AuditLog.ts +23 -15
- package/Models/DatabaseModels/GlobalConfig.ts +24 -0
- package/Models/DatabaseModels/Monitor.ts +3 -2
- package/Models/DatabaseModels/MonitorTemplate.ts +2 -1
- package/Scripts/generate-service-worker.js +65 -4
- package/Server/API/BaseAPI.ts +26 -5
- package/Server/API/GlobalConfigAPI.ts +228 -462
- package/Server/API/ProjectOIDC.ts +25 -16
- package/Server/API/ProjectSSO.ts +24 -16
- package/Server/API/StatusPageAPI.ts +100 -42
- package/Server/API/TeamMemberAPI.ts +10 -1
- package/Server/Enterprise/EnterpriseEdition.ts +649 -0
- package/Server/Enterprise/EnterpriseFeature.ts +48 -0
- package/Server/Enterprise/EnterpriseLicenseSnapshot.ts +192 -0
- package/Server/Enterprise/EnterpriseServerModule.ts +233 -0
- package/Server/EnvironmentConfig.ts +147 -2
- package/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.ts +25 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
- package/Server/Middleware/UserAuthorization.ts +38 -16
- package/Server/Services/AuditLogService.ts +84 -1079
- package/Server/Services/EnterpriseLicenseService.ts +38 -0
- package/Server/Services/GlobalConfigService.ts +80 -1
- package/Server/Services/MonitorProbeService.ts +116 -20
- package/Server/Services/MonitorService.ts +56 -4
- package/Server/Services/MonitorStatusTimelineService.ts +284 -0
- package/Server/Services/MonitorTemplateService.ts +26 -0
- package/Server/Services/ProjectService.ts +284 -0
- package/Server/Services/RumSessionPinService.ts +25 -6
- package/Server/Services/StatusPagePrivateUserService.ts +7 -3
- package/Server/Services/StatusPageService.ts +78 -1
- package/Server/Services/TeamMemberService.ts +11 -0
- package/Server/Services/TeamService.ts +10 -0
- package/Server/Services/UserService.ts +10 -17
- package/Server/Types/Database/Permissions/CreatePermission.ts +15 -0
- package/Server/Types/Database/Permissions/EditionPermission.ts +208 -18
- package/Server/Types/Database/Permissions/TablePermission.ts +10 -3
- package/Server/Types/Database/Permissions/UpdatePermission.ts +29 -0
- package/Server/Types/Markdown.ts +41 -0
- package/Server/Utils/CommunityEditionSsoReport.ts +361 -0
- package/Server/Utils/EditionEnforcement.ts +233 -0
- package/Server/Utils/FrontendEnvironment.ts +41 -2
- package/Server/Utils/InstanceHealth/RedisHealth.ts +12 -277
- package/Server/Utils/Monitor/AffectedResourceList.ts +190 -0
- package/Server/Utils/Monitor/Criteria/EvaluateOverTime.ts +10 -1
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +543 -333
- package/Server/Utils/Monitor/MonitoringIntervalValidator.ts +116 -0
- package/Server/Utils/Workspace/Slack/Slack.ts +423 -10
- package/Tests/App/Accounts/LoginPasskey.test.tsx +18 -0
- package/Tests/App/Accounts/LoginSsoEdition.test.tsx +616 -0
- package/Tests/App/AdminDashboard/AdminAuthenticationSsoEdition.test.tsx +217 -0
- package/Tests/App/AdminDashboard/AdminEnterprisePluginPage.test.tsx +357 -0
- package/Tests/App/AdminDashboard/EnterpriseLicensesShell.test.tsx +214 -0
- package/Tests/App/AdminDashboard/GlobalSSOEnterpriseShells.test.tsx +271 -0
- package/Tests/App/AdminDashboard/HealthShells.test.tsx +659 -0
- package/Tests/App/Dashboard/AuditLogsAndComplianceShells.test.tsx +572 -0
- package/Tests/App/Dashboard/EnterpriseFeatureUpgrade.test.tsx +547 -0
- package/Tests/App/Dashboard/EnterprisePluginPage.test.tsx +667 -0
- package/Tests/App/Dashboard/IdentityEnterpriseShells.test.tsx +319 -0
- package/Tests/App/Dashboard/OnboardingSsoEmptyState.test.tsx +185 -0
- package/Tests/App/Dashboard/SecurityEventConnectionDiagnostics.test.tsx +45 -9
- package/Tests/App/Dashboard/SecurityEventDetailPanel.test.tsx +399 -0
- package/Tests/App/Dashboard/SecurityEventListRow.test.tsx +214 -0
- package/Tests/App/Dashboard/SecurityEventsEmptyState.test.tsx +1 -83
- package/Tests/App/Dashboard/SecurityEventsNavTabs.test.tsx +248 -0
- package/Tests/App/Dashboard/SecurityEventsViewer.test.tsx +1203 -0
- package/Tests/App/Dashboard/UserEmailCallSites.test.tsx +11 -91
- package/Tests/App/StatusPage/StatusPageSsoEmptyState.test.tsx +319 -0
- package/Tests/Helpers/RefreshAwareApiScan.ts +757 -0
- package/Tests/Helpers/TenantScopedRequestScan.ts +515 -0
- package/Tests/Scripts/GenerateServiceWorker.test.ts +931 -0
- package/Tests/Server/API/BaseAPICreateItemDoesNotMutateModel.test.ts +130 -0
- package/Tests/Server/API/GlobalConfigLicense.test.ts +742 -497
- package/Tests/Server/API/OnCallReadinessAPI.test.ts +35 -909
- package/Tests/Server/API/SsoProviderListingsEdition.test.ts +432 -0
- package/Tests/Server/API/TeamMemberLeaveScimLockEdition.test.ts +252 -0
- package/Tests/Server/Enterprise/EnterpriseEdition.test.ts +824 -0
- package/Tests/Server/Enterprise/EnterpriseFeatureActive.test.ts +643 -0
- package/Tests/Server/Enterprise/EnterpriseLicenseSnapshot.test.ts +294 -0
- package/Tests/Server/Enterprise/EnterpriseModelFeatureMap.test.ts +93 -0
- package/Tests/Server/Enterprise/EnterpriseOnlyModulesLiveInEe.test.ts +582 -0
- package/Tests/Server/Enterprise/EnterpriseServerModule.test.ts +247 -0
- package/Tests/Server/Enterprise/FakeEnterpriseModule.ts +502 -0
- package/Tests/Server/Enterprise/TestBillingFlag.ts +70 -0
- package/Tests/Server/EnvironmentConfigEnterpriseEdition.test.ts +314 -0
- package/Tests/Server/Infrastructure/ContainerBootConfiguration.test.ts +289 -0
- package/Tests/Server/Infrastructure/E2EClickHouseFixtureAccess.test.ts +5 -1
- package/Tests/Server/Middleware/UserAuthorization.test.ts +37 -2
- package/Tests/Server/Middleware/UserAuthorizationEditionEnforcement.test.ts +516 -0
- package/Tests/Server/Services/AuditLogService.test.ts +460 -990
- package/Tests/Server/Services/CreateAndReadResponsesKeepIds.test.ts +263 -0
- package/Tests/Server/Services/EnterpriseLicenseServiceKeyGeneration.test.ts +151 -0
- package/Tests/Server/Services/GlobalConfigServiceLicenseColumns.test.ts +357 -0
- package/Tests/Server/Services/MonitorDestinationInfoIPv6.test.ts +101 -0
- package/Tests/Server/Services/MonitorProbeServiceIntervalScheduling.test.ts +333 -0
- package/Tests/Server/Services/MonitorStatusTimelineDailyAggregates.test.ts +303 -0
- package/Tests/Server/Services/ProjectServiceAuditLogLicense.test.ts +701 -0
- package/Tests/Server/Services/ProjectServiceAuditLogSettingsCache.test.ts +31 -35
- package/Tests/Server/Services/ScimPushGroupsTeamLocksEdition.test.ts +431 -0
- package/Tests/Server/Services/SsoRequirementReadMasking.test.ts +419 -0
- package/Tests/Server/Services/SsoRequirementWriteGuard.test.ts +769 -0
- package/Tests/Server/Services/StatusPagePrivateUserInvitationPolicy.test.ts +94 -0
- package/Tests/Server/Services/UserAuthenticationService.test.ts +35 -0
- package/Tests/Server/Services/UserServiceSeatLimit.test.ts +94 -56
- package/Tests/Server/Types/Database/Permissions/EditionPermission.test.ts +1823 -0
- package/Tests/Server/Types/Markdown.test.ts +181 -0
- package/Tests/Server/Utils/CommunityEditionSsoReport.test.ts +565 -0
- package/Tests/Server/Utils/EditionEnforcement.test.ts +303 -0
- package/Tests/Server/Utils/FrontendEnvironment.test.ts +367 -0
- package/Tests/Server/Utils/InstanceHealth/RedisHealth.test.ts +38 -418
- package/Tests/Server/Utils/Monitor/AffectedResourceList.test.ts +518 -0
- package/Tests/Server/Utils/Monitor/Criteria/EvaluateOverTime.test.ts +24 -4
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +934 -96
- package/Tests/Server/Utils/Monitor/MonitoringIntervalValidator.test.ts +188 -0
- package/Tests/Server/Utils/Workspace/Slack/SlackMarkdownSectionSplit.test.ts +1209 -0
- package/Tests/Types/API/HostnameFromAuthority.test.ts +20 -10
- package/Tests/Types/API/HostnameIPv6.test.ts +149 -0
- package/Tests/Types/Database/CanonicalModelInstance.test.ts +190 -0
- package/Tests/UI/Components/EditionLabelLapseCopy.ts +104 -0
- package/Tests/UI/Components/EditionLabelLicenseManagerWiring.test.tsx +254 -0
- package/Tests/UI/Components/EditionLabelLicenseRefresh.test.tsx +84 -178
- package/Tests/UI/Components/EditionLabelLicenseStatus.test.tsx +1586 -0
- package/Tests/UI/Components/EditionLabelLicenseWritesGuard.test.tsx +157 -0
- package/Tests/UI/Components/Graphs/DayUptimeGraph.test.tsx +49 -2
- package/Tests/UI/Components/MarkdownConverters.test.ts +684 -0
- package/Tests/UI/Components/ModelListEmptyState.test.tsx +289 -0
- package/Tests/UI/Components/TelemetryViewer/TelemetryViewerEmptyContent.test.tsx +131 -0
- package/Tests/UI/EsbuildEnterpriseAlias.test.ts +1127 -0
- package/Tests/Utils/HostAddressUtil.test.ts +138 -0
- package/Tests/Utils/Monitor/MonitorDestinationUtil.test.ts +313 -0
- package/Tests/Utils/Monitor/MonitoringIntervalUtil.test.ts +304 -0
- package/Tests/Utils/StatusPage/UptimeDailyAggregateUtil.test.ts +248 -0
- package/Types/API/Hostname.ts +63 -16
- package/Types/Database/AccessControl/ColumnAccessControl.ts +19 -7
- package/Types/Database/AccessControl/ColumnBillingAccessControl.ts +19 -7
- package/Types/Database/AccessControl/OwnerOnlyColumn.ts +15 -6
- package/Types/Database/CanonicalModelInstance.ts +102 -0
- package/Types/Database/TableColumn.ts +20 -6
- package/Types/EnterpriseLicense/EnterpriseLicensePeriods.ts +29 -0
- package/Types/IP/IPv6.ts +6 -1
- package/Types/Monitor/MonitorStep.ts +6 -1
- package/Types/Monitor/ProxmoxAlertTemplates.ts +1 -1
- package/Types/StatusPage/UptimeDailyAggregate.ts +110 -0
- package/UI/Components/EditionLabel/EditionLabel.tsx +796 -1195
- package/UI/Components/EditionLabel/LicenseManager.ts +119 -0
- package/UI/Components/Graphs/DayUptimeGraph.tsx +123 -15
- package/UI/Components/Markdown.tsx/MarkdownConverters.ts +0 -0
- package/UI/Components/ModelList/ModelList.tsx +11 -1
- package/UI/Components/MonitorGraphs/Uptime.tsx +69 -0
- package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +28 -12
- package/UI/esbuild-enterprise.js +263 -0
- package/Utils/EnterpriseLicense/EnterpriseLicenseUsage.ts +7 -2
- package/Utils/HostAddressUtil.ts +94 -0
- package/Utils/Monitor/MonitorDestinationUtil.ts +157 -0
- package/Utils/Monitor/MonitoringIntervalUtil.ts +436 -0
- package/Utils/StatusPage/UptimeDailyAggregateUtil.ts +192 -0
- package/build/dist/Models/AnalyticsModels/AuditLog.js +23 -15
- package/build/dist/Models/AnalyticsModels/AuditLog.js.map +1 -1
- package/build/dist/Models/DatabaseModels/GlobalConfig.js +25 -0
- package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Monitor.js +2 -2
- package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
- package/build/dist/Models/DatabaseModels/MonitorTemplate.js +2 -1
- package/build/dist/Models/DatabaseModels/MonitorTemplate.js.map +1 -1
- package/build/dist/Server/API/BaseAPI.js +26 -5
- package/build/dist/Server/API/BaseAPI.js.map +1 -1
- package/build/dist/Server/API/GlobalConfigAPI.js +148 -344
- package/build/dist/Server/API/GlobalConfigAPI.js.map +1 -1
- package/build/dist/Server/API/ProjectOIDC.js +24 -16
- package/build/dist/Server/API/ProjectOIDC.js.map +1 -1
- package/build/dist/Server/API/ProjectSSO.js +24 -16
- package/build/dist/Server/API/ProjectSSO.js.map +1 -1
- package/build/dist/Server/API/StatusPageAPI.js +93 -43
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/API/TeamMemberAPI.js +8 -1
- package/build/dist/Server/API/TeamMemberAPI.js.map +1 -1
- package/build/dist/Server/Enterprise/EnterpriseEdition.js +466 -0
- package/build/dist/Server/Enterprise/EnterpriseEdition.js.map +1 -0
- package/build/dist/Server/Enterprise/EnterpriseFeature.js +39 -0
- package/build/dist/Server/Enterprise/EnterpriseFeature.js.map +1 -0
- package/build/dist/Server/Enterprise/EnterpriseLicenseSnapshot.js +70 -0
- package/build/dist/Server/Enterprise/EnterpriseLicenseSnapshot.js.map +1 -0
- package/build/dist/Server/Enterprise/EnterpriseServerModule.js +84 -0
- package/build/dist/Server/Enterprise/EnterpriseServerModule.js.map +1 -0
- package/build/dist/Server/EnvironmentConfig.js +84 -2
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.js +18 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Middleware/UserAuthorization.js +30 -11
- package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
- package/build/dist/Server/Services/AuditLogService.js +71 -740
- package/build/dist/Server/Services/AuditLogService.js.map +1 -1
- package/build/dist/Server/Services/EnterpriseLicenseService.js +34 -0
- package/build/dist/Server/Services/EnterpriseLicenseService.js.map +1 -1
- package/build/dist/Server/Services/GlobalConfigService.js +63 -0
- package/build/dist/Server/Services/GlobalConfigService.js.map +1 -1
- package/build/dist/Server/Services/MonitorProbeService.js +90 -17
- package/build/dist/Server/Services/MonitorProbeService.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +45 -4
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/MonitorStatusTimelineService.js +242 -0
- package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
- package/build/dist/Server/Services/MonitorTemplateService.js +16 -0
- package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +214 -0
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/RumSessionPinService.js +24 -6
- package/build/dist/Server/Services/RumSessionPinService.js.map +1 -1
- package/build/dist/Server/Services/StatusPagePrivateUserService.js +7 -3
- package/build/dist/Server/Services/StatusPagePrivateUserService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageService.js +71 -0
- package/build/dist/Server/Services/StatusPageService.js.map +1 -1
- package/build/dist/Server/Services/TeamMemberService.js +10 -0
- package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
- package/build/dist/Server/Services/TeamService.js +9 -0
- package/build/dist/Server/Services/TeamService.js.map +1 -1
- package/build/dist/Server/Services/UserService.js +10 -16
- package/build/dist/Server/Services/UserService.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/CreatePermission.js +10 -0
- package/build/dist/Server/Types/Database/Permissions/CreatePermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/EditionPermission.js +154 -14
- package/build/dist/Server/Types/Database/Permissions/EditionPermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/TablePermission.js +10 -3
- package/build/dist/Server/Types/Database/Permissions/TablePermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js +17 -0
- package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js.map +1 -1
- package/build/dist/Server/Types/Markdown.js +31 -0
- package/build/dist/Server/Types/Markdown.js.map +1 -1
- package/build/dist/Server/Utils/CommunityEditionSsoReport.js +223 -0
- package/build/dist/Server/Utils/CommunityEditionSsoReport.js.map +1 -0
- package/build/dist/Server/Utils/EditionEnforcement.js +187 -0
- package/build/dist/Server/Utils/EditionEnforcement.js.map +1 -0
- package/build/dist/Server/Utils/FrontendEnvironment.js +31 -2
- package/build/dist/Server/Utils/FrontendEnvironment.js.map +1 -1
- package/build/dist/Server/Utils/InstanceHealth/RedisHealth.js +6 -193
- package/build/dist/Server/Utils/InstanceHealth/RedisHealth.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/AffectedResourceList.js +96 -0
- package/build/dist/Server/Utils/Monitor/AffectedResourceList.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js +8 -1
- package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +449 -261
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitoringIntervalValidator.js +88 -0
- package/build/dist/Server/Utils/Monitor/MonitoringIntervalValidator.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/Slack/Slack.js +331 -11
- package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
- package/build/dist/Types/API/Hostname.js +59 -11
- package/build/dist/Types/API/Hostname.js.map +1 -1
- package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js +19 -7
- package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js.map +1 -1
- package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js +19 -7
- package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js.map +1 -1
- package/build/dist/Types/Database/AccessControl/OwnerOnlyColumn.js +13 -6
- package/build/dist/Types/Database/AccessControl/OwnerOnlyColumn.js.map +1 -1
- package/build/dist/Types/Database/CanonicalModelInstance.js +88 -0
- package/build/dist/Types/Database/CanonicalModelInstance.js.map +1 -0
- package/build/dist/Types/Database/TableColumn.js +19 -6
- package/build/dist/Types/Database/TableColumn.js.map +1 -1
- package/build/dist/Types/EnterpriseLicense/EnterpriseLicensePeriods.js +28 -0
- package/build/dist/Types/EnterpriseLicense/EnterpriseLicensePeriods.js.map +1 -0
- package/build/dist/Types/IP/IPv6.js +6 -1
- package/build/dist/Types/IP/IPv6.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStep.js +5 -0
- package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
- package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js +1 -1
- package/build/dist/Types/StatusPage/UptimeDailyAggregate.js +32 -0
- package/build/dist/Types/StatusPage/UptimeDailyAggregate.js.map +1 -0
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js +414 -585
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
- package/build/dist/UI/Components/EditionLabel/LicenseManager.js +2 -0
- package/build/dist/UI/Components/EditionLabel/LicenseManager.js.map +1 -0
- package/build/dist/UI/Components/Graphs/DayUptimeGraph.js +90 -17
- package/build/dist/UI/Components/Graphs/DayUptimeGraph.js.map +1 -1
- package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js +0 -0
- package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js.map +1 -1
- package/build/dist/UI/Components/ModelList/ModelList.js +4 -1
- package/build/dist/UI/Components/ModelList/ModelList.js.map +1 -1
- package/build/dist/UI/Components/MonitorGraphs/Uptime.js +42 -1
- package/build/dist/UI/Components/MonitorGraphs/Uptime.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +2 -2
- package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js +6 -2
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js.map +1 -1
- package/build/dist/Utils/HostAddressUtil.js +80 -0
- package/build/dist/Utils/HostAddressUtil.js.map +1 -0
- package/build/dist/Utils/Monitor/MonitorDestinationUtil.js +127 -0
- package/build/dist/Utils/Monitor/MonitorDestinationUtil.js.map +1 -0
- package/build/dist/Utils/Monitor/MonitoringIntervalUtil.js +374 -0
- package/build/dist/Utils/Monitor/MonitoringIntervalUtil.js.map +1 -0
- package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js +148 -0
- package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js.map +1 -0
- package/jest.config.json +3 -1
- package/package.json +1 -1
- package/test-setup.sh +103 -34
- package/tsconfig.json +13 -0
- package/Server/API/EnterpriseLicenseAPI.ts +0 -925
- package/Server/API/TeamComplianceAPI.ts +0 -158
- package/Server/Middleware/SCIMAuthorization.ts +0 -141
- package/Server/Services/TeamComplianceService.ts +0 -733
- package/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.ts +0 -186
- package/Server/Utils/InstanceHealth/PostgresHealth.ts +0 -286
- package/Tests/App/AdminDashboard/EnterpriseLicenseInstanceActivity.test.tsx +0 -451
- package/Tests/App/Dashboard/AuditLogsTable.test.tsx +0 -598
- package/Tests/App/Dashboard/SecurityEventsExplorer.test.tsx +0 -761
- package/Tests/App/Dashboard/SecurityEventsSideMenu.test.tsx +0 -247
- package/Tests/App/Dashboard/SecurityEventsTableColumns.test.tsx +0 -382
- package/Tests/App/Dashboard/SecurityEventsVolumeChart.test.tsx +0 -321
- package/Tests/Server/API/EnterpriseLicenseReportUserCount.test.ts +0 -1851
- package/Tests/Server/Middleware/SCIMAuthorization.test.ts +0 -525
- package/Tests/Server/Services/TeamComplianceServiceBehaviour.test.ts +0 -1845
- package/Tests/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.test.ts +0 -495
- package/Tests/Server/Utils/InstanceHealth/PostgresHealth.test.ts +0 -337
- package/Tests/Utils/EnterpriseLicenseSeats.test.ts +0 -576
- package/Tests/Utils/EnterpriseLicenseSync.test.ts +0 -568
- package/Utils/EnterpriseLicense/EnterpriseLicenseSeats.ts +0 -287
- package/Utils/EnterpriseLicense/EnterpriseLicenseSync.ts +0 -244
- package/build/dist/Server/API/EnterpriseLicenseAPI.js +0 -646
- package/build/dist/Server/API/EnterpriseLicenseAPI.js.map +0 -1
- package/build/dist/Server/API/TeamComplianceAPI.js +0 -111
- package/build/dist/Server/API/TeamComplianceAPI.js.map +0 -1
- package/build/dist/Server/Middleware/SCIMAuthorization.js +0 -124
- package/build/dist/Server/Middleware/SCIMAuthorization.js.map +0 -1
- package/build/dist/Server/Services/TeamComplianceService.js +0 -537
- package/build/dist/Server/Services/TeamComplianceService.js.map +0 -1
- package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js +0 -145
- package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js.map +0 -1
- package/build/dist/Server/Utils/InstanceHealth/PostgresHealth.js +0 -194
- package/build/dist/Server/Utils/InstanceHealth/PostgresHealth.js.map +0 -1
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js +0 -168
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js.map +0 -1
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSync.js +0 -174
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSync.js.map +0 -1
|
@@ -0,0 +1,649 @@
|
|
|
1
|
+
import EnterpriseFeature from "./EnterpriseFeature";
|
|
2
|
+
import {
|
|
3
|
+
ENTERPRISE_LICENSE_TRIAL_PERIOD_IN_DAYS,
|
|
4
|
+
EnterpriseLicenseSnapshot,
|
|
5
|
+
EnterpriseLicenseSnapshotUtil,
|
|
6
|
+
SeatUsage,
|
|
7
|
+
} from "./EnterpriseLicenseSnapshot";
|
|
8
|
+
import EnterpriseServerModule, {
|
|
9
|
+
AuditLogRecorder,
|
|
10
|
+
} from "./EnterpriseServerModule";
|
|
11
|
+
/*
|
|
12
|
+
* EnvironmentConfig never imports anything under Server/Enterprise, so this
|
|
13
|
+
* import cannot form a cycle. IsBillingEnabled is only ever read inside a
|
|
14
|
+
* function body: the compiled CommonJS reads the live module binding at call
|
|
15
|
+
* time, which is what lets a test pin billing by mocking EnvironmentConfig.
|
|
16
|
+
*/
|
|
17
|
+
import { IsBillingEnabled } from "../EnvironmentConfig";
|
|
18
|
+
import logger from "../Utils/Logger";
|
|
19
|
+
import type { DatabaseBaseModelType } from "../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
|
|
20
|
+
import PaymentRequiredException from "../../Types/Exception/PaymentRequiredException";
|
|
21
|
+
|
|
22
|
+
/*
|
|
23
|
+
* Which enterprise feature each enterprise configuration model belongs to,
|
|
24
|
+
* keyed by table name. Kept here so the model files themselves stay unchanged;
|
|
25
|
+
* a model marked requiresEnterprise that is missing from this map is caught by
|
|
26
|
+
* the facade's test.
|
|
27
|
+
*/
|
|
28
|
+
const ENTERPRISE_FEATURE_BY_TABLE_NAME: ReadonlyMap<string, EnterpriseFeature> =
|
|
29
|
+
new Map<string, EnterpriseFeature>([
|
|
30
|
+
["GlobalSSO", EnterpriseFeature.SSO],
|
|
31
|
+
["GlobalOIDC", EnterpriseFeature.SSO],
|
|
32
|
+
["GlobalSSOProject", EnterpriseFeature.SSO],
|
|
33
|
+
["GlobalOIDCProject", EnterpriseFeature.SSO],
|
|
34
|
+
["ProjectSSO", EnterpriseFeature.SSO],
|
|
35
|
+
["ProjectOIDC", EnterpriseFeature.SSO],
|
|
36
|
+
["StatusPageSSO", EnterpriseFeature.SSO],
|
|
37
|
+
["StatusPageOIDC", EnterpriseFeature.SSO],
|
|
38
|
+
["ProjectSCIM", EnterpriseFeature.SCIM],
|
|
39
|
+
["StatusPageSCIM", EnterpriseFeature.SCIM],
|
|
40
|
+
["TeamComplianceSetting", EnterpriseFeature.TeamCompliance],
|
|
41
|
+
]);
|
|
42
|
+
|
|
43
|
+
/*
|
|
44
|
+
* The features whose RUNTIME behaviour stops when a self-hosted license
|
|
45
|
+
* lapses (see isFeatureActive), in the order the lapse log names them.
|
|
46
|
+
*/
|
|
47
|
+
export const RUNTIME_ENTERPRISE_FEATURES: ReadonlyArray<EnterpriseFeature> = [
|
|
48
|
+
EnterpriseFeature.SSO,
|
|
49
|
+
EnterpriseFeature.SCIM,
|
|
50
|
+
EnterpriseFeature.AuditLogs,
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
// How the lapse log names each feature.
|
|
54
|
+
const FEATURE_NAMES: ReadonlyMap<EnterpriseFeature, string> = new Map<
|
|
55
|
+
EnterpriseFeature,
|
|
56
|
+
string
|
|
57
|
+
>([
|
|
58
|
+
[EnterpriseFeature.SSO, "single sign-on (SSO)"],
|
|
59
|
+
[EnterpriseFeature.SCIM, "SCIM provisioning"],
|
|
60
|
+
[EnterpriseFeature.AuditLogs, "audit logging"],
|
|
61
|
+
[EnterpriseFeature.TeamCompliance, "team compliance"],
|
|
62
|
+
[EnterpriseFeature.InstanceHealth, "the OneUptime Health dashboards"],
|
|
63
|
+
]);
|
|
64
|
+
|
|
65
|
+
/*
|
|
66
|
+
* One change in which enterprise features are active, as isFeatureActive
|
|
67
|
+
* observed it. Reported once per change, to the log and to every listener
|
|
68
|
+
* registered with EnterpriseEdition.onFeatureStateChange.
|
|
69
|
+
*/
|
|
70
|
+
export interface EnterpriseFeatureStateChange {
|
|
71
|
+
// Features that were active and have stopped.
|
|
72
|
+
stopped: Array<EnterpriseFeature>;
|
|
73
|
+
// Features that were stopped and are active again.
|
|
74
|
+
resumed: Array<EnterpriseFeature>;
|
|
75
|
+
// The license snapshot the change was decided on.
|
|
76
|
+
snapshot: EnterpriseLicenseSnapshot;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export type EnterpriseFeatureStateListener = (
|
|
80
|
+
change: EnterpriseFeatureStateChange,
|
|
81
|
+
) => void;
|
|
82
|
+
|
|
83
|
+
/*
|
|
84
|
+
* The one place core asks "which edition is this, and what may it do?".
|
|
85
|
+
*
|
|
86
|
+
* Three questions, on purpose:
|
|
87
|
+
*
|
|
88
|
+
* isLoaded() the ee code is present in this process, whatever the
|
|
89
|
+
* license says. Decides which enterprise routers and
|
|
90
|
+
* jobs exist and which edition operators are told they
|
|
91
|
+
* run.
|
|
92
|
+
* isFeatureActive() the ee code is present AND the feature is licensed
|
|
93
|
+
* right now. Governs RUNTIME behaviour: SSO sign-in
|
|
94
|
+
* and "Require SSO for login" enforcement, SCIM
|
|
95
|
+
* provisioning and its team locks, audit-log
|
|
96
|
+
* recording. When a self-hosted license lapses these
|
|
97
|
+
* stop, exactly as on the Community Edition, and they
|
|
98
|
+
* resume without a restart when a license is
|
|
99
|
+
* activated. An UNKNOWN license state counts as
|
|
100
|
+
* active (see isFeatureActive).
|
|
101
|
+
* isFeatureAvailable() the license, failing closed. Governs creating and
|
|
102
|
+
* updating enterprise configuration, the enterprise
|
|
103
|
+
* admin Health dashboards and the query console.
|
|
104
|
+
*
|
|
105
|
+
* "Lapsed" means what isFeatureAvailableSync treats as unavailable with
|
|
106
|
+
* billing off: no license after the trial
|
|
107
|
+
* (ENTERPRISE_LICENSE_TRIAL_PERIOD_IN_DAYS, counted from
|
|
108
|
+
* GlobalConfig.enterpriseEditionFirstSeenAt), a license that expired more
|
|
109
|
+
* than the grace period (ENTERPRISE_LICENSE_GRACE_PERIOD_IN_DAYS, counted
|
|
110
|
+
* from its expiry) ago, an invalid license, or a license whose
|
|
111
|
+
* feature list leaves the feature out. During the trial and the grace period
|
|
112
|
+
* nothing stops. With billing on (OneUptime Cloud) both license questions
|
|
113
|
+
* answer yes whenever ee is loaded: plan tiers gate the features there.
|
|
114
|
+
*/
|
|
115
|
+
export default class EnterpriseEdition {
|
|
116
|
+
public static readonly COMMUNITY_EDITION_MESSAGE: string =
|
|
117
|
+
"This is a OneUptime Enterprise Edition feature and is not available in the Community Edition. " +
|
|
118
|
+
"Run the OneUptime Enterprise Edition image to use it. " +
|
|
119
|
+
"See https://oneuptime.com/enterprise/overview for details.";
|
|
120
|
+
|
|
121
|
+
public static readonly LICENSE_REQUIRED_MESSAGE: string =
|
|
122
|
+
"This OneUptime Enterprise feature needs a valid Enterprise license that includes it. " +
|
|
123
|
+
"Enterprise configuration you already have is kept and can still be viewed or deleted, " +
|
|
124
|
+
"but it cannot be created or changed until a master admin adds or renews the license " +
|
|
125
|
+
"from the edition label in the Admin Dashboard header.";
|
|
126
|
+
|
|
127
|
+
private static module: EnterpriseServerModule | null = null;
|
|
128
|
+
|
|
129
|
+
/*
|
|
130
|
+
* The last active/stopped answer isFeatureActive gave per feature, from a
|
|
131
|
+
* KNOWN license state. A feature never seen here counts as active: that is
|
|
132
|
+
* how the process starts (an unknown license state is active), so a license
|
|
133
|
+
* that is already lapsed at boot is reported like any other lapse.
|
|
134
|
+
*/
|
|
135
|
+
private static lastKnownFeatureState: Map<EnterpriseFeature, boolean> =
|
|
136
|
+
new Map<EnterpriseFeature, boolean>();
|
|
137
|
+
|
|
138
|
+
private static hasWarnedAboutUnreadLicense: boolean = false;
|
|
139
|
+
|
|
140
|
+
private static hasWarnedAboutUnreadableLicense: boolean = false;
|
|
141
|
+
|
|
142
|
+
private static hasWarnedAboutUnknownTrialStart: boolean = false;
|
|
143
|
+
|
|
144
|
+
private static featureStateListeners: Array<EnterpriseFeatureStateListener> =
|
|
145
|
+
[];
|
|
146
|
+
|
|
147
|
+
public static register(enterpriseModule: EnterpriseServerModule): void {
|
|
148
|
+
if (!enterpriseModule) {
|
|
149
|
+
throw new Error("EnterpriseEdition.register needs a module.");
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (EnterpriseEdition.module) {
|
|
153
|
+
throw new Error(
|
|
154
|
+
"An enterprise module is already registered. The enterprise module is loaded once per process.",
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
EnterpriseEdition.module = enterpriseModule;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
public static isLoaded(): boolean {
|
|
162
|
+
return EnterpriseEdition.module !== null;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
public static getModule(): EnterpriseServerModule | null {
|
|
166
|
+
return EnterpriseEdition.module;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/*
|
|
170
|
+
* Test suites only: forget the registered module, the feature states seen so
|
|
171
|
+
* far, the one-time warnings and the listeners, so the next test starts on
|
|
172
|
+
* a fresh Community Edition process.
|
|
173
|
+
*/
|
|
174
|
+
public static resetForTests(): void {
|
|
175
|
+
EnterpriseEdition.module = null;
|
|
176
|
+
EnterpriseEdition.lastKnownFeatureState.clear();
|
|
177
|
+
EnterpriseEdition.hasWarnedAboutUnreadLicense = false;
|
|
178
|
+
EnterpriseEdition.hasWarnedAboutUnreadableLicense = false;
|
|
179
|
+
EnterpriseEdition.hasWarnedAboutUnknownTrialStart = false;
|
|
180
|
+
EnterpriseEdition.featureStateListeners = [];
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/*
|
|
184
|
+
* Whether the feature's runtime behaviour runs right now: SSO sign-in and
|
|
185
|
+
* "Require SSO for login" enforcement (SSO), SCIM provisioning and its team
|
|
186
|
+
* locks (SCIM), audit-log recording (AuditLogs). Synchronous, because it is
|
|
187
|
+
* asked on every request that could need it; the license changes at runtime
|
|
188
|
+
* and routers are mounted once, so callers ask per request.
|
|
189
|
+
*
|
|
190
|
+
* no enterprise module false (the Community Edition)
|
|
191
|
+
* billing on true (OneUptime Cloud: plan tiers gate)
|
|
192
|
+
* license state UNKNOWN true: the first snapshot has not loaded yet,
|
|
193
|
+
* reading the cached one threw, or it says no
|
|
194
|
+
* license is installed but not when the trial
|
|
195
|
+
* started (the first-run stamp could not be
|
|
196
|
+
* read or written yet, so whether the trial
|
|
197
|
+
* is over is not known; see
|
|
198
|
+
* EnterpriseLicenseSnapshotUtil.isTrialStartUnknown).
|
|
199
|
+
* An unknown state must never lock anyone out
|
|
200
|
+
* or switch SSO enforcement off. The loader
|
|
201
|
+
* waits (bounded) for the first snapshot
|
|
202
|
+
* before any router is mounted, so the window
|
|
203
|
+
* is small. Warned about once per process.
|
|
204
|
+
* otherwise the license entitles the feature (valid or
|
|
205
|
+
* grace, feature included)
|
|
206
|
+
*
|
|
207
|
+
* A change of answer from a known state is logged once per change (a
|
|
208
|
+
* warning when features stop, info when they resume) and reported to the
|
|
209
|
+
* onFeatureStateChange listeners.
|
|
210
|
+
*/
|
|
211
|
+
public static isFeatureActive(feature: EnterpriseFeature): boolean {
|
|
212
|
+
const enterpriseModule: EnterpriseServerModule | null =
|
|
213
|
+
EnterpriseEdition.module;
|
|
214
|
+
|
|
215
|
+
if (!enterpriseModule) {
|
|
216
|
+
return false;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (IsBillingEnabled) {
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
let snapshot: EnterpriseLicenseSnapshot | null = null;
|
|
224
|
+
|
|
225
|
+
try {
|
|
226
|
+
snapshot = enterpriseModule.licensing.getCachedSnapshot();
|
|
227
|
+
} catch (err) {
|
|
228
|
+
if (!EnterpriseEdition.hasWarnedAboutUnreadableLicense) {
|
|
229
|
+
EnterpriseEdition.hasWarnedAboutUnreadableLicense = true;
|
|
230
|
+
logger.warn(
|
|
231
|
+
"EnterpriseEdition: could not read the cached license snapshot. Until it can be read, SSO, SCIM and audit logging keep running as if licensed. This warning is logged once per process.",
|
|
232
|
+
);
|
|
233
|
+
logger.warn(err);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return true;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (!snapshot) {
|
|
240
|
+
if (!EnterpriseEdition.hasWarnedAboutUnreadLicense) {
|
|
241
|
+
EnterpriseEdition.hasWarnedAboutUnreadLicense = true;
|
|
242
|
+
logger.warn(
|
|
243
|
+
"EnterpriseEdition: the license has not been read yet. Until it is, SSO, SCIM and audit logging keep running as if licensed. This warning is logged once per process.",
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return true;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (EnterpriseLicenseSnapshotUtil.isTrialStartUnknown(snapshot)) {
|
|
251
|
+
if (!EnterpriseEdition.hasWarnedAboutUnknownTrialStart) {
|
|
252
|
+
EnterpriseEdition.hasWarnedAboutUnknownTrialStart = true;
|
|
253
|
+
logger.warn(
|
|
254
|
+
/*
|
|
255
|
+
* Reachable both with no license at all and WITH one installed: a
|
|
256
|
+
* license whose expiry was never recorded falls back to this same
|
|
257
|
+
* trial (LicenseToken's classifyUnverifiedWithoutExpiry), so this
|
|
258
|
+
* must not assert that nothing is installed.
|
|
259
|
+
*/
|
|
260
|
+
`EnterpriseEdition: there is no license this installation can date, and the start of the ${ENTERPRISE_LICENSE_TRIAL_PERIOD_IN_DAYS}-day trial has not been recorded yet, so it is not known whether the trial is over. Until it is recorded, SSO, SCIM and audit logging keep running as if licensed. This warning is logged once per process.`,
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return true;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const isActive: boolean = EnterpriseLicenseSnapshotUtil.entitles(
|
|
268
|
+
snapshot,
|
|
269
|
+
feature,
|
|
270
|
+
);
|
|
271
|
+
|
|
272
|
+
if (EnterpriseEdition.getLastKnownFeatureState(feature) !== isActive) {
|
|
273
|
+
EnterpriseEdition.recordFeatureStateChange(snapshot, feature);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return isActive;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/*
|
|
280
|
+
* Registers a listener for changes in which features are active (see
|
|
281
|
+
* isFeatureActive). Called synchronously, from inside isFeatureActive, once
|
|
282
|
+
* per change; a listener that throws is logged and never breaks the caller.
|
|
283
|
+
* Returns a function that removes the listener.
|
|
284
|
+
*/
|
|
285
|
+
public static onFeatureStateChange(
|
|
286
|
+
listener: EnterpriseFeatureStateListener,
|
|
287
|
+
): () => void {
|
|
288
|
+
EnterpriseEdition.featureStateListeners.push(listener);
|
|
289
|
+
|
|
290
|
+
return (): void => {
|
|
291
|
+
EnterpriseEdition.featureStateListeners =
|
|
292
|
+
EnterpriseEdition.featureStateListeners.filter(
|
|
293
|
+
(registered: EnterpriseFeatureStateListener): boolean => {
|
|
294
|
+
return registered !== listener;
|
|
295
|
+
},
|
|
296
|
+
);
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/*
|
|
301
|
+
* Synchronous availability, for synchronous permission checks. Reads the
|
|
302
|
+
* module's cached snapshot; no snapshot yet, or any error, means false (fail
|
|
303
|
+
* closed: an enterprise configuration write is refused, never allowed by
|
|
304
|
+
* accident).
|
|
305
|
+
*/
|
|
306
|
+
public static isFeatureAvailableSync(feature: EnterpriseFeature): boolean {
|
|
307
|
+
const enterpriseModule: EnterpriseServerModule | null =
|
|
308
|
+
EnterpriseEdition.module;
|
|
309
|
+
|
|
310
|
+
if (!enterpriseModule) {
|
|
311
|
+
return false;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
if (IsBillingEnabled) {
|
|
315
|
+
return true;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
let snapshot: EnterpriseLicenseSnapshot | null = null;
|
|
319
|
+
|
|
320
|
+
try {
|
|
321
|
+
snapshot = enterpriseModule.licensing.getCachedSnapshot();
|
|
322
|
+
} catch (err) {
|
|
323
|
+
logger.warn(
|
|
324
|
+
"EnterpriseEdition: could not read the cached license snapshot; treating the feature as unavailable.",
|
|
325
|
+
);
|
|
326
|
+
logger.warn(err);
|
|
327
|
+
return false;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
return EnterpriseLicenseSnapshotUtil.entitles(snapshot, feature);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
public static async isFeatureAvailable(
|
|
334
|
+
feature: EnterpriseFeature,
|
|
335
|
+
): Promise<boolean> {
|
|
336
|
+
const enterpriseModule: EnterpriseServerModule | null =
|
|
337
|
+
EnterpriseEdition.module;
|
|
338
|
+
|
|
339
|
+
if (!enterpriseModule) {
|
|
340
|
+
return false;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
if (IsBillingEnabled) {
|
|
344
|
+
return true;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
const snapshot: EnterpriseLicenseSnapshot | null =
|
|
348
|
+
await EnterpriseEdition.getLicenseSnapshot();
|
|
349
|
+
|
|
350
|
+
return EnterpriseLicenseSnapshotUtil.entitles(snapshot, feature);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
public static assertFeatureAvailableSync(feature: EnterpriseFeature): void {
|
|
354
|
+
if (EnterpriseEdition.isFeatureAvailableSync(feature)) {
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
throw EnterpriseEdition.createUnavailableException();
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
public static async assertFeatureAvailable(
|
|
362
|
+
feature: EnterpriseFeature,
|
|
363
|
+
): Promise<void> {
|
|
364
|
+
if (await EnterpriseEdition.isFeatureAvailable(feature)) {
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
throw EnterpriseEdition.createUnavailableException();
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/*
|
|
372
|
+
* The license snapshot, or null on the Community Edition. A failed read falls
|
|
373
|
+
* back to the cached snapshot (the provider's last good one), then to null.
|
|
374
|
+
*/
|
|
375
|
+
public static async getLicenseSnapshot(): Promise<EnterpriseLicenseSnapshot | null> {
|
|
376
|
+
const enterpriseModule: EnterpriseServerModule | null =
|
|
377
|
+
EnterpriseEdition.module;
|
|
378
|
+
|
|
379
|
+
if (!enterpriseModule) {
|
|
380
|
+
return null;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
try {
|
|
384
|
+
return await enterpriseModule.licensing.getSnapshot();
|
|
385
|
+
} catch (err) {
|
|
386
|
+
logger.warn(
|
|
387
|
+
"EnterpriseEdition: could not load the license snapshot; falling back to the cached one.",
|
|
388
|
+
);
|
|
389
|
+
logger.warn(err);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
try {
|
|
393
|
+
return enterpriseModule.licensing.getCachedSnapshot();
|
|
394
|
+
} catch (err) {
|
|
395
|
+
logger.warn(err);
|
|
396
|
+
return null;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// Seat usage for display, or null on the Community Edition or on error.
|
|
401
|
+
public static async getSeatUsage(): Promise<SeatUsage | null> {
|
|
402
|
+
const enterpriseModule: EnterpriseServerModule | null =
|
|
403
|
+
EnterpriseEdition.module;
|
|
404
|
+
|
|
405
|
+
if (!enterpriseModule) {
|
|
406
|
+
return null;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
try {
|
|
410
|
+
return await enterpriseModule.licensing.getSeatUsage();
|
|
411
|
+
} catch (err) {
|
|
412
|
+
logger.warn("EnterpriseEdition: could not compute seat usage.");
|
|
413
|
+
logger.warn(err);
|
|
414
|
+
return null;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/*
|
|
419
|
+
* Throws when the license has no seat left for one more user. The Community
|
|
420
|
+
* Edition has no seat limit, so this is a no-op there. Errors from the
|
|
421
|
+
* provider propagate: refusing the new user IS the provider's answer.
|
|
422
|
+
*/
|
|
423
|
+
public static async assertSeatAvailableForNewUser(): Promise<void> {
|
|
424
|
+
const enterpriseModule: EnterpriseServerModule | null =
|
|
425
|
+
EnterpriseEdition.module;
|
|
426
|
+
|
|
427
|
+
if (!enterpriseModule) {
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
await enterpriseModule.licensing.assertSeatAvailableForNewUser();
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
/*
|
|
435
|
+
* The ee audit-log recorder, or null when there is none (CE). Handed out
|
|
436
|
+
* whatever the license says: the recorder itself asks
|
|
437
|
+
* isFeatureActive(AuditLogs) before recording each entry, so recording
|
|
438
|
+
* stops while the license is lapsed and resumes when it is renewed.
|
|
439
|
+
*/
|
|
440
|
+
public static getAuditLogRecorder(): AuditLogRecorder | null {
|
|
441
|
+
const enterpriseModule: EnterpriseServerModule | null =
|
|
442
|
+
EnterpriseEdition.module;
|
|
443
|
+
|
|
444
|
+
if (!enterpriseModule) {
|
|
445
|
+
return null;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
try {
|
|
449
|
+
return enterpriseModule.getAuditLogRecorder();
|
|
450
|
+
} catch (err) {
|
|
451
|
+
logger.error(
|
|
452
|
+
"EnterpriseEdition: the enterprise module failed to provide its audit log recorder.",
|
|
453
|
+
);
|
|
454
|
+
logger.error(err);
|
|
455
|
+
return null;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
public static getModelFeature(
|
|
460
|
+
modelType: DatabaseBaseModelType,
|
|
461
|
+
): EnterpriseFeature | null {
|
|
462
|
+
let tableName: string | null = null;
|
|
463
|
+
|
|
464
|
+
try {
|
|
465
|
+
tableName = new modelType().tableName;
|
|
466
|
+
} catch (err) {
|
|
467
|
+
logger.warn(err);
|
|
468
|
+
return null;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
return EnterpriseEdition.getFeatureForTableName(tableName);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
public static getFeatureForTableName(
|
|
475
|
+
tableName: string | null | undefined,
|
|
476
|
+
): EnterpriseFeature | null {
|
|
477
|
+
if (!tableName) {
|
|
478
|
+
return null;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
return ENTERPRISE_FEATURE_BY_TABLE_NAME.get(tableName) || null;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// Every table name the facade maps to a feature (for guard tests).
|
|
485
|
+
public static getMappedTableNames(): Array<string> {
|
|
486
|
+
return Array.from(ENTERPRISE_FEATURE_BY_TABLE_NAME.keys());
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// How the lapse log names a feature.
|
|
490
|
+
public static getFeatureName(feature: EnterpriseFeature): string {
|
|
491
|
+
return FEATURE_NAMES.get(feature) || feature;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
/*
|
|
495
|
+
* The log line for features that stopped, or null when none did. Public so
|
|
496
|
+
* the wording can be tested without driving a lapse.
|
|
497
|
+
*/
|
|
498
|
+
public static describeStoppedFeatures(
|
|
499
|
+
stopped: Array<EnterpriseFeature>,
|
|
500
|
+
snapshot: EnterpriseLicenseSnapshot,
|
|
501
|
+
): string | null {
|
|
502
|
+
if (stopped.length === 0) {
|
|
503
|
+
return null;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
const names: string = EnterpriseEdition.joinFeatureNames(stopped);
|
|
507
|
+
const verb: string = stopped.length === 1 ? "has" : "have";
|
|
508
|
+
const isUsable: boolean = EnterpriseLicenseSnapshotUtil.isUsable(snapshot);
|
|
509
|
+
|
|
510
|
+
const parts: Array<string> = [
|
|
511
|
+
isUsable
|
|
512
|
+
? `The OneUptime Enterprise license does not include ${names}: ${stopped.length === 1 ? "it" : "they"} ${verb} stopped until a license that includes ${stopped.length === 1 ? "it" : "them"} is activated.`
|
|
513
|
+
: `The OneUptime Enterprise license has lapsed (status: ${snapshot.status}): ${names} ${verb} stopped until a license is activated.`,
|
|
514
|
+
];
|
|
515
|
+
|
|
516
|
+
if (stopped.includes(EnterpriseFeature.SSO)) {
|
|
517
|
+
parts.push(
|
|
518
|
+
'"Require SSO for login" is not enforced meanwhile: users sign in with their password, and users who only ever signed in with SSO can reset their password.',
|
|
519
|
+
);
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
if (snapshot.message) {
|
|
523
|
+
parts.push(`License status: ${snapshot.message}`);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
parts.push(
|
|
527
|
+
"A master admin can activate or renew the license from the edition label in the Admin Dashboard header.",
|
|
528
|
+
);
|
|
529
|
+
|
|
530
|
+
return parts.join(" ");
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
// The log line for features that resumed, or null when none did.
|
|
534
|
+
public static describeResumedFeatures(
|
|
535
|
+
resumed: Array<EnterpriseFeature>,
|
|
536
|
+
): string | null {
|
|
537
|
+
if (resumed.length === 0) {
|
|
538
|
+
return null;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
return `The OneUptime Enterprise license covers ${EnterpriseEdition.joinFeatureNames(resumed)} again: ${resumed.length === 1 ? "it has" : "they have"} resumed.`;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
private static getLastKnownFeatureState(feature: EnterpriseFeature): boolean {
|
|
545
|
+
const known: boolean | undefined =
|
|
546
|
+
EnterpriseEdition.lastKnownFeatureState.get(feature);
|
|
547
|
+
|
|
548
|
+
return known === undefined ? true : known;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/*
|
|
552
|
+
* Called only when `trigger` changed state. Re-reads every runtime feature
|
|
553
|
+
* from the same snapshot, so a lapse that stops several of them is logged
|
|
554
|
+
* as one line and the others are not reported again on their next check.
|
|
555
|
+
*/
|
|
556
|
+
private static recordFeatureStateChange(
|
|
557
|
+
snapshot: EnterpriseLicenseSnapshot,
|
|
558
|
+
trigger: EnterpriseFeature,
|
|
559
|
+
): void {
|
|
560
|
+
const features: Array<EnterpriseFeature> = [...RUNTIME_ENTERPRISE_FEATURES];
|
|
561
|
+
|
|
562
|
+
if (!features.includes(trigger)) {
|
|
563
|
+
features.push(trigger);
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
const stopped: Array<EnterpriseFeature> = [];
|
|
567
|
+
const resumed: Array<EnterpriseFeature> = [];
|
|
568
|
+
|
|
569
|
+
for (const feature of features) {
|
|
570
|
+
const wasActive: boolean =
|
|
571
|
+
EnterpriseEdition.getLastKnownFeatureState(feature);
|
|
572
|
+
const isActive: boolean = EnterpriseLicenseSnapshotUtil.entitles(
|
|
573
|
+
snapshot,
|
|
574
|
+
feature,
|
|
575
|
+
);
|
|
576
|
+
|
|
577
|
+
EnterpriseEdition.lastKnownFeatureState.set(feature, isActive);
|
|
578
|
+
|
|
579
|
+
if (wasActive && !isActive) {
|
|
580
|
+
stopped.push(feature);
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
if (!wasActive && isActive) {
|
|
584
|
+
resumed.push(feature);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
try {
|
|
589
|
+
const stoppedMessage: string | null =
|
|
590
|
+
EnterpriseEdition.describeStoppedFeatures(stopped, snapshot);
|
|
591
|
+
|
|
592
|
+
if (stoppedMessage) {
|
|
593
|
+
logger.warn(stoppedMessage);
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
const resumedMessage: string | null =
|
|
597
|
+
EnterpriseEdition.describeResumedFeatures(resumed);
|
|
598
|
+
|
|
599
|
+
if (resumedMessage) {
|
|
600
|
+
logger.info(resumedMessage);
|
|
601
|
+
}
|
|
602
|
+
} catch {
|
|
603
|
+
// Logging must never change the answer isFeatureActive gives.
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
const change: EnterpriseFeatureStateChange = {
|
|
607
|
+
stopped,
|
|
608
|
+
resumed,
|
|
609
|
+
snapshot,
|
|
610
|
+
};
|
|
611
|
+
|
|
612
|
+
for (const listener of [...EnterpriseEdition.featureStateListeners]) {
|
|
613
|
+
try {
|
|
614
|
+
listener(change);
|
|
615
|
+
} catch (err) {
|
|
616
|
+
logger.error(
|
|
617
|
+
"EnterpriseEdition: a listener for enterprise feature state changes failed.",
|
|
618
|
+
);
|
|
619
|
+
logger.error(err);
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
private static joinFeatureNames(features: Array<EnterpriseFeature>): string {
|
|
625
|
+
const names: Array<string> = features.map(
|
|
626
|
+
(feature: EnterpriseFeature): string => {
|
|
627
|
+
return EnterpriseEdition.getFeatureName(feature);
|
|
628
|
+
},
|
|
629
|
+
);
|
|
630
|
+
|
|
631
|
+
if (names.length <= 1) {
|
|
632
|
+
return names.join("");
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
return `${names.slice(0, -1).join(", ")} and ${names[names.length - 1]}`;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
private static createUnavailableException(): PaymentRequiredException {
|
|
639
|
+
if (!EnterpriseEdition.isLoaded()) {
|
|
640
|
+
return new PaymentRequiredException(
|
|
641
|
+
EnterpriseEdition.COMMUNITY_EDITION_MESSAGE,
|
|
642
|
+
);
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
return new PaymentRequiredException(
|
|
646
|
+
EnterpriseEdition.LICENSE_REQUIRED_MESSAGE,
|
|
647
|
+
);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* The enterprise capabilities a OneUptime Enterprise license can entitle.
|
|
3
|
+
*
|
|
4
|
+
* The string values are part of the license format: a signed license carries
|
|
5
|
+
* a `features` claim that is either ["*"] (everything) or a subset of these
|
|
6
|
+
* values. Renaming a value therefore silently revokes that feature from every
|
|
7
|
+
* license already issued, so values are append-only.
|
|
8
|
+
*/
|
|
9
|
+
enum EnterpriseFeature {
|
|
10
|
+
SSO = "sso",
|
|
11
|
+
SCIM = "scim",
|
|
12
|
+
TeamCompliance = "team-compliance",
|
|
13
|
+
AuditLogs = "audit-logs",
|
|
14
|
+
InstanceHealth = "instance-health",
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const ALL_ENTERPRISE_FEATURES: ReadonlyArray<EnterpriseFeature> =
|
|
18
|
+
Object.values(EnterpriseFeature);
|
|
19
|
+
|
|
20
|
+
/*
|
|
21
|
+
* The license claim value that entitles every feature, including ones added
|
|
22
|
+
* after the license was issued.
|
|
23
|
+
*/
|
|
24
|
+
export const ENTERPRISE_FEATURE_WILDCARD: string = "*";
|
|
25
|
+
|
|
26
|
+
/*
|
|
27
|
+
* Narrows an untrusted string (a license claim, a request body) to a feature.
|
|
28
|
+
* Unknown values return null rather than throwing, so a license issued by a
|
|
29
|
+
* newer license server that names a feature this build has never heard of is
|
|
30
|
+
* still readable: the unknown name is simply not granted.
|
|
31
|
+
*/
|
|
32
|
+
export const parseEnterpriseFeature: (
|
|
33
|
+
value: unknown,
|
|
34
|
+
) => EnterpriseFeature | null = (value: unknown): EnterpriseFeature | null => {
|
|
35
|
+
if (typeof value !== "string") {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const match: EnterpriseFeature | undefined = ALL_ENTERPRISE_FEATURES.find(
|
|
40
|
+
(feature: EnterpriseFeature): boolean => {
|
|
41
|
+
return feature === value;
|
|
42
|
+
},
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
return match || null;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export default EnterpriseFeature;
|