@oneuptime/common 13.0.8 → 14.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Models/AnalyticsModels/AuditLog.ts +23 -15
- package/Models/DatabaseModels/GlobalConfig.ts +24 -0
- package/Models/DatabaseModels/Index.ts +4 -0
- package/Models/DatabaseModels/Monitor.ts +3 -2
- package/Models/DatabaseModels/MonitorTemplate.ts +2 -1
- package/Models/DatabaseModels/ServiceLevelObjectiveFeed.ts +2 -0
- package/Models/DatabaseModels/ServiceLevelObjectiveLabelRule.ts +522 -0
- package/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.ts +38 -4
- package/Models/DatabaseModels/ServiceLevelObjectiveOwnerRule.ts +603 -0
- 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/1794100000000-AddSloLabelAndOwnerRules.ts +248 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1794200000000-AddSloMonitorRuleMonitorType.ts +19 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
- package/Server/Middleware/UserAuthorization.ts +38 -16
- package/Server/Services/AuditLogService.ts +84 -1079
- package/Server/Services/DatabaseService.ts +10 -0
- package/Server/Services/EnterpriseLicenseService.ts +38 -0
- package/Server/Services/GlobalConfigService.ts +80 -1
- package/Server/Services/Index.ts +4 -0
- package/Server/Services/MonitorProbeService.ts +116 -20
- package/Server/Services/MonitorService.ts +59 -6
- 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/ServiceLevelObjectiveLabelRuleEngineService.ts +385 -0
- package/Server/Services/ServiceLevelObjectiveLabelRuleService.ts +51 -0
- package/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.ts +92 -16
- package/Server/Services/ServiceLevelObjectiveMonitorRuleService.ts +36 -1
- package/Server/Services/ServiceLevelObjectiveOwnerRuleEngineService.ts +521 -0
- package/Server/Services/ServiceLevelObjectiveOwnerRuleService.ts +51 -0
- package/Server/Services/ServiceLevelObjectiveService.ts +28 -0
- 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/Types/Workflow/Components/Telegram/SendMessageToChat.ts +27 -1
- package/Server/Utils/AI/Toolbox/SloTools.ts +1 -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 +148 -0
- package/Server/Utils/Monitor/Criteria/CompareCriteria.ts +1 -1
- package/Server/Utils/Monitor/Criteria/EvaluateOverTime.ts +10 -1
- package/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.ts +1 -1
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +720 -465
- package/Server/Utils/Monitor/MonitoringIntervalValidator.ts +116 -0
- package/Server/Utils/Monitor/RootCauseList.ts +139 -0
- package/Server/Utils/Rules/RuleRun/RuleRunRegistry.ts +28 -0
- package/Server/Utils/Slo/SloRulePatternValidator.ts +42 -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/FeedFilterSortIntegration.test.tsx +1632 -0
- package/Tests/App/Dashboard/FeedOptionsLocales.test.ts +250 -0
- package/Tests/App/Dashboard/FeedOrdering.test.ts +279 -9
- package/Tests/App/Dashboard/IdentityEnterpriseShells.test.tsx +319 -0
- package/Tests/App/Dashboard/InvestigationFeedRefresh.test.tsx +60 -1
- package/Tests/App/Dashboard/InvestigationPanel.test.tsx +594 -3
- package/Tests/App/Dashboard/OnboardingSsoEmptyState.test.tsx +185 -0
- package/Tests/App/Dashboard/ProductOrientation.test.tsx +646 -0
- package/Tests/App/Dashboard/ResourceFeed.test.tsx +612 -2
- package/Tests/App/Dashboard/ResourceFeedPageWiring.test.ts +30 -0
- package/Tests/App/Dashboard/ResourceFeedPagesFilterSort.test.tsx +1202 -0
- package/Tests/App/Dashboard/ScheduledMaintenanceFeedRefresh.test.tsx +52 -1
- 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/SloFeed.test.tsx +106 -1
- package/Tests/App/Dashboard/SloMonitorRuleCriteria.test.tsx +566 -0
- package/Tests/App/Dashboard/SloNavigationWiring.test.tsx +6 -4
- package/Tests/App/Dashboard/SloNoticeBanner.test.tsx +186 -0
- package/Tests/App/Dashboard/SloOverviewKpiStrip.test.tsx +388 -44
- package/Tests/App/Dashboard/SloOverviewLayout.test.tsx +613 -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/Models/DatabaseModels/ResourceFeedModels.test.ts +0 -8
- package/Tests/Models/DatabaseModels/SloLabelAndOwnerRuleModels.test.ts +404 -0
- package/Tests/Models/DatabaseModels/SloOverhaulModels.test.ts +17 -1
- package/Tests/Models/DatabaseModels/StaticRuleCriteriaInheritance.test.ts +4 -2
- 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/Infrastructure/Postgres/AddConfigurableRuleCriteriaMigration.test.ts +3 -0
- package/Tests/Server/Infrastructure/Postgres/AddSloLabelAndOwnerRulesMigration.test.ts +407 -0
- package/Tests/Server/Infrastructure/Postgres/AddSloMonitorRuleMonitorTypeMigration.test.ts +171 -0
- package/Tests/Server/Infrastructure/Postgres/SloProductOverhaulMigration.test.ts +88 -4
- 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/DatabaseServiceRuleCriteriaValidation.test.ts +104 -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/RuleRun/LabelRuleEnginesGroupBRun.test.ts +48 -1
- package/Tests/Server/Services/RuleRun/OwnerRuleEnginesGroupBRun.test.ts +30 -0
- package/Tests/Server/Services/ScimPushGroupsTeamLocksEdition.test.ts +431 -0
- package/Tests/Server/Services/ServiceLevelObjectiveLabelAndOwnerRuleEngines.test.ts +1170 -0
- package/Tests/Server/Services/ServiceLevelObjectiveLabelAndOwnerRuleServices.test.ts +172 -0
- package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.test.ts +323 -0
- package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleService.test.ts +115 -0
- package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleTriggers.test.ts +21 -2
- package/Tests/Server/Services/ServiceLevelObjectiveMonitorTypePostgres.test.ts +480 -0
- package/Tests/Server/Services/ServiceLevelObjectiveService.test.ts +162 -0
- package/Tests/Server/Services/SsoRequirementReadMasking.test.ts +419 -0
- package/Tests/Server/Services/SsoRequirementWriteGuard.test.ts +769 -0
- package/Tests/Server/Services/StaticRuleCriteriaRuntimeCoverage.test.ts +45 -6
- 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/FeedEventTypeFilterQuery.test.ts +745 -0
- package/Tests/Server/Types/Database/Permissions/EditionPermission.test.ts +1823 -0
- package/Tests/Server/Types/Markdown.test.ts +183 -1
- package/Tests/Server/Types/Workflow/Components/ApiComponentSsrf.test.ts +49 -0
- package/Tests/Server/Types/Workflow/Components/TelegramSendMessageToChat.test.ts +331 -0
- package/Tests/Server/Utils/AI/SloTools.test.ts +10 -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/Criteria/MetricMonitorCriteriaAnomalyUnits.test.ts +1 -1
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +1339 -96
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorBreachingSamples.test.ts +1101 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorMetricUnits.test.ts +106 -80
- package/Tests/Server/Utils/Monitor/MonitoringIntervalValidator.test.ts +188 -0
- package/Tests/Server/Utils/Monitor/RootCauseList.test.ts +252 -0
- package/Tests/Server/Utils/Rules/RuleRun/RuleRunPermission.test.ts +154 -0
- package/Tests/Server/Utils/SSRFProtection.test.ts +111 -0
- package/Tests/Server/Utils/Slo/SloRulePatternValidator.test.ts +67 -0
- package/Tests/Server/Utils/VM/VMRunnerSsrf.test.ts +213 -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/API/Route.test.ts +56 -0
- package/Tests/Types/API/URLSchemeLikePath.test.ts +304 -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/FeedOptions.test.ts +1404 -0
- package/Tests/UI/Components/FeedOptionsButton.test.tsx +2603 -0
- package/Tests/UI/Components/Graphs/DayUptimeGraph.test.tsx +49 -2
- package/Tests/UI/Components/Icon.test.tsx +26 -0
- package/Tests/UI/Components/MarkdownConverters.test.ts +684 -0
- package/Tests/UI/Components/ModelListEmptyState.test.tsx +289 -0
- package/Tests/UI/Components/RuleCriteria/RuleCriteriaModelTable.test.tsx +3 -3
- package/Tests/UI/Components/TelemetryViewer/TelemetryViewerEmptyContent.test.tsx +131 -0
- package/Tests/UI/Components/useFeedItemsViewKey.test.tsx +1017 -0
- package/Tests/UI/Components/useFeedOptions.test.tsx +1107 -0
- package/Tests/UI/EsbuildEnterpriseAlias.test.ts +1127 -0
- package/Tests/Utils/HostAddressUtil.test.ts +138 -0
- package/Tests/Utils/LabelRuleImportExport.test.ts +102 -0
- package/Tests/Utils/Monitor/MonitorDestinationUtil.test.ts +313 -0
- package/Tests/Utils/Monitor/MonitoringIntervalUtil.test.ts +304 -0
- package/Tests/Utils/Slo/SloDuration.test.ts +115 -24
- package/Tests/Utils/Slo/SloHealth.test.ts +93 -10
- package/Tests/Utils/Slo/SloMonitorRuleCriteria.test.ts +109 -0
- package/Tests/Utils/Slo/SloOverviewText.test.ts +64 -0
- package/Tests/Utils/StatusPage/UptimeDailyAggregateUtil.test.ts +248 -0
- package/Types/API/Hostname.ts +63 -16
- package/Types/API/Route.ts +19 -2
- package/Types/API/URL.ts +26 -2
- 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/MetricMonitor/MetricCriteriaContext.ts +6 -5
- package/Types/Monitor/MetricMonitor/MetricMonitorResponse.ts +9 -0
- package/Types/Monitor/MonitorStep.ts +6 -1
- package/Types/Monitor/ProxmoxAlertTemplates.ts +1 -1
- package/Types/Permission.ts +90 -0
- package/Types/Rules/RuleCriteriaFieldRegistry.ts +11 -0
- package/Types/Rules/RuleRun.ts +4 -0
- 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/Feed/FeedOptions.ts +427 -0
- package/UI/Components/Feed/FeedOptionsButton.tsx +692 -0
- package/UI/Components/Feed/useFeedItems.ts +28 -9
- package/UI/Components/Feed/useFeedOptions.ts +225 -0
- package/UI/Components/Graphs/DayUptimeGraph.tsx +123 -15
- package/UI/Components/Icon/Icon.tsx +1 -1
- 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/LabelRuleImportExport.ts +27 -9
- package/Utils/Monitor/MetricValueFormatter.ts +2 -2
- package/Utils/Monitor/MonitorDestinationUtil.ts +157 -0
- package/Utils/Monitor/MonitoringIntervalUtil.ts +436 -0
- package/Utils/Rules/MonitorTypeRuleCriteria.ts +31 -0
- package/Utils/Slo/SloDuration.ts +22 -6
- package/Utils/Slo/SloHealth.ts +8 -7
- package/Utils/Slo/SloMonitorRuleCriteria.ts +33 -1
- package/Utils/Slo/SloOverviewText.ts +33 -0
- package/Utils/Slo/SloProjection.ts +4 -3
- 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/Index.js +4 -0
- package/build/dist/Models/DatabaseModels/Index.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/Models/DatabaseModels/ServiceLevelObjectiveFeed.js +2 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveFeed.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveLabelRule.js +530 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveLabelRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.js +39 -4
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerRule.js +612 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerRule.js.map +1 -0
- 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/1794100000000-AddSloLabelAndOwnerRules.js +93 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794100000000-AddSloLabelAndOwnerRules.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794200000000-AddSloMonitorRuleMonitorType.js +12 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794200000000-AddSloMonitorRuleMonitorType.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -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/DatabaseService.js +7 -0
- package/build/dist/Server/Services/DatabaseService.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/Index.js +4 -0
- package/build/dist/Server/Services/Index.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 +48 -6
- 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/ServiceLevelObjectiveLabelRuleEngineService.js +295 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleService.js +56 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleService.js.map +1 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.js +59 -14
- package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleService.js +22 -1
- package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleService.js.map +1 -1
- package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleEngineService.js +400 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleService.js +56 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleService.js.map +1 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveService.js +21 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveService.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/Types/Workflow/Components/Telegram/SendMessageToChat.js +20 -1
- package/build/dist/Server/Types/Workflow/Components/Telegram/SendMessageToChat.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/SloTools.js +1 -0
- package/build/dist/Server/Utils/AI/Toolbox/SloTools.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 +67 -0
- package/build/dist/Server/Utils/Monitor/AffectedResourceList.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js +1 -1
- 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/Criteria/MetricMonitorCriteria.js +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +585 -367
- 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/Monitor/RootCauseList.js +101 -0
- package/build/dist/Server/Utils/Monitor/RootCauseList.js.map +1 -0
- package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js +28 -0
- package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js.map +1 -1
- package/build/dist/Server/Utils/Slo/SloRulePatternValidator.js +28 -0
- package/build/dist/Server/Utils/Slo/SloRulePatternValidator.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/API/Route.js +18 -2
- package/build/dist/Types/API/Route.js.map +1 -1
- package/build/dist/Types/API/URL.js +23 -2
- package/build/dist/Types/API/URL.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/Permission.js +84 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js +11 -0
- package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js.map +1 -1
- package/build/dist/Types/Rules/RuleRun.js +4 -0
- package/build/dist/Types/Rules/RuleRun.js.map +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/Feed/FeedOptions.js +235 -0
- package/build/dist/UI/Components/Feed/FeedOptions.js.map +1 -0
- package/build/dist/UI/Components/Feed/FeedOptionsButton.js +346 -0
- package/build/dist/UI/Components/Feed/FeedOptionsButton.js.map +1 -0
- package/build/dist/UI/Components/Feed/useFeedItems.js +17 -7
- package/build/dist/UI/Components/Feed/useFeedItems.js.map +1 -1
- package/build/dist/UI/Components/Feed/useFeedOptions.js +130 -0
- package/build/dist/UI/Components/Feed/useFeedOptions.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/Icon/Icon.js +1 -1
- package/build/dist/UI/Components/Icon/Icon.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/LabelRuleImportExport.js +22 -6
- package/build/dist/Utils/LabelRuleImportExport.js.map +1 -1
- package/build/dist/Utils/Monitor/MetricValueFormatter.js +2 -2
- 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/Rules/MonitorTypeRuleCriteria.js +18 -0
- package/build/dist/Utils/Rules/MonitorTypeRuleCriteria.js.map +1 -0
- package/build/dist/Utils/Slo/SloDuration.js +13 -5
- package/build/dist/Utils/Slo/SloDuration.js.map +1 -1
- package/build/dist/Utils/Slo/SloHealth.js +8 -7
- package/build/dist/Utils/Slo/SloHealth.js.map +1 -1
- package/build/dist/Utils/Slo/SloMonitorRuleCriteria.js +16 -1
- package/build/dist/Utils/Slo/SloMonitorRuleCriteria.js.map +1 -1
- package/build/dist/Utils/Slo/SloOverviewText.js +16 -0
- package/build/dist/Utils/Slo/SloOverviewText.js.map +1 -1
- package/build/dist/Utils/Slo/SloProjection.js.map +1 -1
- 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
|
@@ -1,925 +0,0 @@
|
|
|
1
|
-
import EnterpriseLicense from "../../Models/DatabaseModels/EnterpriseLicense";
|
|
2
|
-
import EnterpriseLicenseInstance from "../../Models/DatabaseModels/EnterpriseLicenseInstance";
|
|
3
|
-
import BadDataException from "../../Types/Exception/BadDataException";
|
|
4
|
-
import PartialEntity from "../../Types/Database/PartialEntity";
|
|
5
|
-
import EnterpriseLicenseInstanceSummary from "../../Types/EnterpriseLicense/EnterpriseLicenseInstanceSummary";
|
|
6
|
-
import EnterpriseLicenseUsageSnapshot from "../../Types/EnterpriseLicense/EnterpriseLicenseUsageSnapshot";
|
|
7
|
-
import EnterpriseLicenseUserCountSource from "../../Types/EnterpriseLicense/EnterpriseLicenseUserCountSource";
|
|
8
|
-
import EnterpriseLicenseUsageUtil from "../../Utils/EnterpriseLicense/EnterpriseLicenseUsage";
|
|
9
|
-
import VersionUtil from "../../Utils/VersionUtil";
|
|
10
|
-
import LIMIT_MAX from "../../Types/Database/LimitMax";
|
|
11
|
-
import ObjectID from "../../Types/ObjectID";
|
|
12
|
-
import PositiveNumber from "../../Types/PositiveNumber";
|
|
13
|
-
import { JSONObject } from "../../Types/JSON";
|
|
14
|
-
import SortOrder from "../../Types/BaseDatabase/SortOrder";
|
|
15
|
-
import EnterpriseLicenseService, {
|
|
16
|
-
Service as EnterpriseLicenseServiceType,
|
|
17
|
-
} from "../Services/EnterpriseLicenseService";
|
|
18
|
-
import EnterpriseLicenseInstanceService from "../Services/EnterpriseLicenseInstanceService";
|
|
19
|
-
import UserMiddleware from "../Middleware/UserAuthorization";
|
|
20
|
-
import JSONWebToken from "../Utils/JsonWebToken";
|
|
21
|
-
import OneUptimeDate from "../../Types/Date";
|
|
22
|
-
import Response from "../Utils/Response";
|
|
23
|
-
import {
|
|
24
|
-
ExpressRequest,
|
|
25
|
-
ExpressResponse,
|
|
26
|
-
NextFunction,
|
|
27
|
-
} from "../Utils/Express";
|
|
28
|
-
import BaseAPI from "./BaseAPI";
|
|
29
|
-
import MasterAdminAuthorization from "../Middleware/MasterAdminAuthorization";
|
|
30
|
-
// import { Host } from "../EnvironmentConfig";
|
|
31
|
-
|
|
32
|
-
/*
|
|
33
|
-
* The license state every installation of a license key mirrors locally.
|
|
34
|
-
* Returned by both /validate and /report-user-count so that the daily report
|
|
35
|
-
* keeps a self-hosted installation current on its own.
|
|
36
|
-
*/
|
|
37
|
-
export interface LicenseTerms {
|
|
38
|
-
companyName: string;
|
|
39
|
-
// ISO 8601, or null for a license with no expiry set.
|
|
40
|
-
expiresAt: string | null;
|
|
41
|
-
licenseKey: string;
|
|
42
|
-
// Null means the license carries no seat limit.
|
|
43
|
-
userLimit: number | null;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export interface LicenseInstanceUpsert {
|
|
47
|
-
licenseId: ObjectID;
|
|
48
|
-
instanceId: string;
|
|
49
|
-
host: string | undefined;
|
|
50
|
-
// OneUptime version the instance is running. Absent on instances too old to report it.
|
|
51
|
-
oneuptimeVersion?: string | null | undefined;
|
|
52
|
-
// Usage fields are only set on report-user-count, not on validate.
|
|
53
|
-
userCount?: number | undefined;
|
|
54
|
-
userEmailHashes?: Array<string> | undefined;
|
|
55
|
-
masterAdminEmails?: Array<string> | undefined;
|
|
56
|
-
lastReportedAt?: Date | undefined;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
interface LicenseUsageReportResult {
|
|
60
|
-
reportedAt: Date;
|
|
61
|
-
instances: Array<EnterpriseLicenseInstance>;
|
|
62
|
-
currentUserCount: number;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
interface LicenseValidationResult {
|
|
66
|
-
instances: Array<EnterpriseLicenseInstance>;
|
|
67
|
-
currentUserCount: number | null;
|
|
68
|
-
userCountUpdatedAt: Date | null;
|
|
69
|
-
calculatedAt: Date;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/*
|
|
73
|
-
* Bounds how many instance rows one license key can register. Real customers
|
|
74
|
-
* run a handful of instances; this stops a leaked key from being used to
|
|
75
|
-
* fill the table with junk rows.
|
|
76
|
-
*/
|
|
77
|
-
const MAX_INSTANCES_PER_LICENSE: number = 100;
|
|
78
|
-
|
|
79
|
-
export default class EnterpriseLicenseAPI extends BaseAPI<
|
|
80
|
-
EnterpriseLicense,
|
|
81
|
-
EnterpriseLicenseServiceType
|
|
82
|
-
> {
|
|
83
|
-
public constructor() {
|
|
84
|
-
super(EnterpriseLicense, EnterpriseLicenseService);
|
|
85
|
-
|
|
86
|
-
/*
|
|
87
|
-
* The dashboard needs a count and instance statuses from one cutoff
|
|
88
|
-
* instant. Calculate both on the server so the per-user hashes used for
|
|
89
|
-
* cross-instance deduplication never have to be sent to the browser.
|
|
90
|
-
*/
|
|
91
|
-
this.router.get(
|
|
92
|
-
`${new this.entityType().getCrudApiPath()?.toString()}/:enterpriseLicenseId/active-usage`,
|
|
93
|
-
MasterAdminAuthorization.isAuthorizedMasterAdminMiddleware,
|
|
94
|
-
async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => {
|
|
95
|
-
try {
|
|
96
|
-
const licenseId: ObjectID = new ObjectID(
|
|
97
|
-
req.params["enterpriseLicenseId"] as string,
|
|
98
|
-
);
|
|
99
|
-
const snapshot: EnterpriseLicenseUsageSnapshot =
|
|
100
|
-
await EnterpriseLicenseService.runWithUsageAggregationLock({
|
|
101
|
-
licenseId,
|
|
102
|
-
fn: async (): Promise<EnterpriseLicenseUsageSnapshot> => {
|
|
103
|
-
/*
|
|
104
|
-
* A report updates its instance row and then the license-wide
|
|
105
|
-
* timestamp. Read both under the same lock so the dashboard
|
|
106
|
-
* can never combine the new instance state with the previous
|
|
107
|
-
* license state (or vice versa).
|
|
108
|
-
*/
|
|
109
|
-
const license: EnterpriseLicense | null =
|
|
110
|
-
await EnterpriseLicenseService.findOneById({
|
|
111
|
-
id: licenseId,
|
|
112
|
-
select: {
|
|
113
|
-
_id: true,
|
|
114
|
-
currentUserCount: true,
|
|
115
|
-
userCountUpdatedAt: true,
|
|
116
|
-
userCountSource: true,
|
|
117
|
-
legacyUserCount: true,
|
|
118
|
-
legacyUserCountUpdatedAt: true,
|
|
119
|
-
},
|
|
120
|
-
props: {
|
|
121
|
-
isRoot: true,
|
|
122
|
-
},
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
if (!license) {
|
|
126
|
-
throw new BadDataException("Enterprise license not found");
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
const instances: Array<EnterpriseLicenseInstance> =
|
|
130
|
-
await this.findLicenseInstances(licenseId);
|
|
131
|
-
const calculatedAt: Date = OneUptimeDate.getCurrentDate();
|
|
132
|
-
const activeInstances: Array<EnterpriseLicenseInstance> =
|
|
133
|
-
instances.filter(
|
|
134
|
-
(instance: EnterpriseLicenseInstance): boolean => {
|
|
135
|
-
return EnterpriseLicenseUsageUtil.isInstanceCountedTowardsUsage(
|
|
136
|
-
instance,
|
|
137
|
-
calculatedAt,
|
|
138
|
-
);
|
|
139
|
-
},
|
|
140
|
-
);
|
|
141
|
-
const currentUserCount: number | null =
|
|
142
|
-
EnterpriseLicenseUsageUtil.getEffectiveUserCount({
|
|
143
|
-
instances,
|
|
144
|
-
storedUserCount: license.currentUserCount,
|
|
145
|
-
storedUserCountUpdatedAt: license.userCountUpdatedAt,
|
|
146
|
-
storedUserCountSource: license.userCountSource,
|
|
147
|
-
legacyUserCount: license.legacyUserCount,
|
|
148
|
-
legacyUserCountUpdatedAt: license.legacyUserCountUpdatedAt,
|
|
149
|
-
now: calculatedAt,
|
|
150
|
-
});
|
|
151
|
-
const masterAdminEmailSet: Set<string> = new Set<string>();
|
|
152
|
-
|
|
153
|
-
for (const instance of instances) {
|
|
154
|
-
for (const email of instance.masterAdminEmails || []) {
|
|
155
|
-
const normalizedEmail: string = email.trim().toLowerCase();
|
|
156
|
-
|
|
157
|
-
if (normalizedEmail) {
|
|
158
|
-
masterAdminEmailSet.add(normalizedEmail);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
const masterAdminEmails: Array<string> =
|
|
164
|
-
Array.from(masterAdminEmailSet).sort();
|
|
165
|
-
const nextInstanceStatusChangeAt: Date | null =
|
|
166
|
-
activeInstances.reduce(
|
|
167
|
-
(
|
|
168
|
-
earliestChange: Date | null,
|
|
169
|
-
instance: EnterpriseLicenseInstance,
|
|
170
|
-
): Date | null => {
|
|
171
|
-
const lastCommunicatedAt: Date | undefined =
|
|
172
|
-
EnterpriseLicenseUsageUtil.getInstanceLastCommunicatedAt(
|
|
173
|
-
instance,
|
|
174
|
-
);
|
|
175
|
-
|
|
176
|
-
if (!lastCommunicatedAt) {
|
|
177
|
-
return earliestChange;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
const inactiveAt: Date = new Date(
|
|
181
|
-
lastCommunicatedAt.getTime() +
|
|
182
|
-
EnterpriseLicenseUsageUtil.InstanceUsageFreshnessInDays *
|
|
183
|
-
24 *
|
|
184
|
-
60 *
|
|
185
|
-
60 *
|
|
186
|
-
1000,
|
|
187
|
-
);
|
|
188
|
-
|
|
189
|
-
return !earliestChange || inactiveAt < earliestChange
|
|
190
|
-
? inactiveAt
|
|
191
|
-
: earliestChange;
|
|
192
|
-
},
|
|
193
|
-
null,
|
|
194
|
-
);
|
|
195
|
-
const usesActiveModernUsage: boolean =
|
|
196
|
-
EnterpriseLicenseUsageUtil.hasActiveReportedInstanceUsage(
|
|
197
|
-
instances,
|
|
198
|
-
calculatedAt,
|
|
199
|
-
);
|
|
200
|
-
let activeLegacyUsageUpdatedAt: Date | undefined;
|
|
201
|
-
|
|
202
|
-
if (!usesActiveModernUsage) {
|
|
203
|
-
if (
|
|
204
|
-
EnterpriseLicenseUsageUtil.isTimestampWithinUsageWindow(
|
|
205
|
-
license.legacyUserCountUpdatedAt,
|
|
206
|
-
calculatedAt,
|
|
207
|
-
)
|
|
208
|
-
) {
|
|
209
|
-
activeLegacyUsageUpdatedAt =
|
|
210
|
-
license.legacyUserCountUpdatedAt;
|
|
211
|
-
} else if (
|
|
212
|
-
!license.legacyUserCountUpdatedAt &&
|
|
213
|
-
license.userCountSource !==
|
|
214
|
-
EnterpriseLicenseUserCountSource.Instance &&
|
|
215
|
-
(license.userCountSource ===
|
|
216
|
-
EnterpriseLicenseUserCountSource.Legacy ||
|
|
217
|
-
!EnterpriseLicenseUsageUtil.hasReportedInstanceUsage(
|
|
218
|
-
instances,
|
|
219
|
-
)) &&
|
|
220
|
-
EnterpriseLicenseUsageUtil.isTimestampWithinUsageWindow(
|
|
221
|
-
license.userCountUpdatedAt,
|
|
222
|
-
calculatedAt,
|
|
223
|
-
)
|
|
224
|
-
) {
|
|
225
|
-
/*
|
|
226
|
-
* Compatibility for rows written before the dedicated
|
|
227
|
-
* legacy heartbeat columns were introduced.
|
|
228
|
-
*/
|
|
229
|
-
activeLegacyUsageUpdatedAt = license.userCountUpdatedAt;
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
const legacyUsageChangeAt: Date | null =
|
|
234
|
-
activeLegacyUsageUpdatedAt
|
|
235
|
-
? new Date(
|
|
236
|
-
activeLegacyUsageUpdatedAt.getTime() +
|
|
237
|
-
EnterpriseLicenseUsageUtil.InstanceUsageFreshnessInDays *
|
|
238
|
-
24 *
|
|
239
|
-
60 *
|
|
240
|
-
60 *
|
|
241
|
-
1000,
|
|
242
|
-
)
|
|
243
|
-
: null;
|
|
244
|
-
let nextUsageChangeAt: Date | null = nextInstanceStatusChangeAt;
|
|
245
|
-
|
|
246
|
-
if (
|
|
247
|
-
legacyUsageChangeAt &&
|
|
248
|
-
(!nextUsageChangeAt ||
|
|
249
|
-
legacyUsageChangeAt < nextUsageChangeAt)
|
|
250
|
-
) {
|
|
251
|
-
nextUsageChangeAt = legacyUsageChangeAt;
|
|
252
|
-
}
|
|
253
|
-
const usageReportTimestamps: Array<Date> = (
|
|
254
|
-
[
|
|
255
|
-
license.userCountUpdatedAt,
|
|
256
|
-
license.legacyUserCountUpdatedAt,
|
|
257
|
-
...instances.map(
|
|
258
|
-
(
|
|
259
|
-
instance: EnterpriseLicenseInstance,
|
|
260
|
-
): Date | undefined => {
|
|
261
|
-
return instance.lastReportedAt;
|
|
262
|
-
},
|
|
263
|
-
),
|
|
264
|
-
] as Array<Date | undefined>
|
|
265
|
-
).filter((timestamp: Date | undefined): timestamp is Date => {
|
|
266
|
-
return Boolean(timestamp);
|
|
267
|
-
});
|
|
268
|
-
const lastUsageReportedAt: Date | null =
|
|
269
|
-
usageReportTimestamps.reduce(
|
|
270
|
-
(latest: Date | null, timestamp: Date): Date => {
|
|
271
|
-
return !latest || timestamp > latest ? timestamp : latest;
|
|
272
|
-
},
|
|
273
|
-
null,
|
|
274
|
-
);
|
|
275
|
-
|
|
276
|
-
return {
|
|
277
|
-
currentUserCount,
|
|
278
|
-
activeInstanceIds: activeInstances.map(
|
|
279
|
-
(instance: EnterpriseLicenseInstance): string => {
|
|
280
|
-
return instance.id!.toString();
|
|
281
|
-
},
|
|
282
|
-
),
|
|
283
|
-
masterAdminEmails,
|
|
284
|
-
calculatedAt: calculatedAt.toISOString(),
|
|
285
|
-
lastUsageReportedAt:
|
|
286
|
-
lastUsageReportedAt?.toISOString() || null,
|
|
287
|
-
nextInstanceStatusChangeAt:
|
|
288
|
-
nextUsageChangeAt?.toISOString() || null,
|
|
289
|
-
};
|
|
290
|
-
},
|
|
291
|
-
});
|
|
292
|
-
|
|
293
|
-
return Response.sendJsonObjectResponse(
|
|
294
|
-
req,
|
|
295
|
-
res,
|
|
296
|
-
snapshot as unknown as JSONObject,
|
|
297
|
-
);
|
|
298
|
-
} catch (err) {
|
|
299
|
-
next(err);
|
|
300
|
-
}
|
|
301
|
-
},
|
|
302
|
-
);
|
|
303
|
-
|
|
304
|
-
this.router.post(
|
|
305
|
-
`${new this.entityType().getCrudApiPath()?.toString()}/validate`,
|
|
306
|
-
UserMiddleware.getUserMiddleware,
|
|
307
|
-
async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => {
|
|
308
|
-
try {
|
|
309
|
-
const licenseKey: string | undefined = req.body["licenseKey"];
|
|
310
|
-
|
|
311
|
-
if (!licenseKey) {
|
|
312
|
-
throw new BadDataException("License key is required");
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
//const serverHost: string = Host.toString();
|
|
316
|
-
|
|
317
|
-
/*
|
|
318
|
-
* if (!serverHost.includes("oneuptime.com")) {
|
|
319
|
-
* throw new BadDataException(
|
|
320
|
-
* "Enterprise license validation is only available on oneuptime.com",
|
|
321
|
-
* );
|
|
322
|
-
* }
|
|
323
|
-
*/
|
|
324
|
-
|
|
325
|
-
const license: EnterpriseLicense | null =
|
|
326
|
-
await EnterpriseLicenseService.findOneBy({
|
|
327
|
-
query: {
|
|
328
|
-
licenseKey: licenseKey,
|
|
329
|
-
},
|
|
330
|
-
select: {
|
|
331
|
-
_id: true,
|
|
332
|
-
companyName: true,
|
|
333
|
-
expiresAt: true,
|
|
334
|
-
licenseKey: true,
|
|
335
|
-
userLimit: true,
|
|
336
|
-
currentUserCount: true,
|
|
337
|
-
userCountUpdatedAt: true,
|
|
338
|
-
isEvaluationLicense: true,
|
|
339
|
-
},
|
|
340
|
-
props: {
|
|
341
|
-
isRoot: true,
|
|
342
|
-
},
|
|
343
|
-
});
|
|
344
|
-
|
|
345
|
-
if (!license) {
|
|
346
|
-
throw new BadDataException("License key is invalid");
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
if (!license.expiresAt) {
|
|
350
|
-
throw new BadDataException("License expiration is not set");
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
const now: number = Date.now();
|
|
354
|
-
const expiresAtMs: number = license.expiresAt.getTime();
|
|
355
|
-
const secondsUntilExpiry: number = Math.floor(
|
|
356
|
-
(expiresAtMs - now) / 1000,
|
|
357
|
-
);
|
|
358
|
-
|
|
359
|
-
if (secondsUntilExpiry <= 0) {
|
|
360
|
-
throw new BadDataException("License key has expired");
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
/*
|
|
364
|
-
* The validating instance sends its instanceId and host so it
|
|
365
|
-
* shows up in the instance list right away (usage is reported
|
|
366
|
-
* later by the daily job on the instance).
|
|
367
|
-
*/
|
|
368
|
-
const instanceId: string = this.parseShortText(
|
|
369
|
-
req.body["instanceId"],
|
|
370
|
-
);
|
|
371
|
-
const instanceHost: string = this.parseShortText(req.body["host"]);
|
|
372
|
-
const instanceVersion: string | null | undefined = this.parseVersion(
|
|
373
|
-
req.body["version"],
|
|
374
|
-
);
|
|
375
|
-
|
|
376
|
-
const validationResult: LicenseValidationResult =
|
|
377
|
-
await EnterpriseLicenseService.runWithUsageAggregationLock({
|
|
378
|
-
licenseId: license.id!,
|
|
379
|
-
fn: async (): Promise<LicenseValidationResult> => {
|
|
380
|
-
/*
|
|
381
|
-
* Registration is the instance's first communication and can
|
|
382
|
-
* keep an upgrade-era count in its grace window. Serialize it
|
|
383
|
-
* with reporting and reconciliation so a sweep cannot read the
|
|
384
|
-
* old rows, then overwrite the count after this row appears.
|
|
385
|
-
*/
|
|
386
|
-
if (instanceId) {
|
|
387
|
-
await this.upsertLicenseInstance({
|
|
388
|
-
licenseId: license.id!,
|
|
389
|
-
instanceId: instanceId,
|
|
390
|
-
host: instanceHost || undefined,
|
|
391
|
-
oneuptimeVersion: instanceVersion,
|
|
392
|
-
});
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
const instances: Array<EnterpriseLicenseInstance> =
|
|
396
|
-
await this.findLicenseInstances(license.id!);
|
|
397
|
-
const currentLicense: EnterpriseLicense | null =
|
|
398
|
-
await EnterpriseLicenseService.findOneById({
|
|
399
|
-
id: license.id!,
|
|
400
|
-
select: {
|
|
401
|
-
currentUserCount: true,
|
|
402
|
-
userCountUpdatedAt: true,
|
|
403
|
-
userCountSource: true,
|
|
404
|
-
legacyUserCount: true,
|
|
405
|
-
legacyUserCountUpdatedAt: true,
|
|
406
|
-
},
|
|
407
|
-
props: {
|
|
408
|
-
isRoot: true,
|
|
409
|
-
},
|
|
410
|
-
});
|
|
411
|
-
|
|
412
|
-
if (!currentLicense) {
|
|
413
|
-
throw new BadDataException("License key is invalid");
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
const calculatedAt: Date = OneUptimeDate.getCurrentDate();
|
|
417
|
-
const currentUserCount: number | null =
|
|
418
|
-
EnterpriseLicenseUsageUtil.getEffectiveUserCount({
|
|
419
|
-
instances,
|
|
420
|
-
storedUserCount: currentLicense.currentUserCount,
|
|
421
|
-
storedUserCountUpdatedAt: currentLicense.userCountUpdatedAt,
|
|
422
|
-
storedUserCountSource: currentLicense.userCountSource,
|
|
423
|
-
legacyUserCount: currentLicense.legacyUserCount,
|
|
424
|
-
legacyUserCountUpdatedAt:
|
|
425
|
-
currentLicense.legacyUserCountUpdatedAt,
|
|
426
|
-
now: calculatedAt,
|
|
427
|
-
});
|
|
428
|
-
|
|
429
|
-
return {
|
|
430
|
-
instances,
|
|
431
|
-
currentUserCount,
|
|
432
|
-
userCountUpdatedAt: currentLicense.userCountUpdatedAt || null,
|
|
433
|
-
calculatedAt,
|
|
434
|
-
};
|
|
435
|
-
},
|
|
436
|
-
});
|
|
437
|
-
|
|
438
|
-
const terms: LicenseTerms = this.getLicenseTerms(license);
|
|
439
|
-
|
|
440
|
-
const token: string | null = this.signLicenseToken(license);
|
|
441
|
-
|
|
442
|
-
return Response.sendJsonObjectResponse(req, res, {
|
|
443
|
-
companyName: terms.companyName,
|
|
444
|
-
expiresAt: terms.expiresAt,
|
|
445
|
-
licenseKey: terms.licenseKey,
|
|
446
|
-
userLimit: terms.userLimit,
|
|
447
|
-
currentUserCount: validationResult.currentUserCount,
|
|
448
|
-
userCountUpdatedAt: validationResult.userCountUpdatedAt
|
|
449
|
-
? validationResult.userCountUpdatedAt.toISOString()
|
|
450
|
-
: null,
|
|
451
|
-
isEvaluationLicense: Boolean(license.isEvaluationLicense),
|
|
452
|
-
instances: this.getInstanceSummaries(
|
|
453
|
-
validationResult.instances,
|
|
454
|
-
validationResult.calculatedAt,
|
|
455
|
-
),
|
|
456
|
-
token,
|
|
457
|
-
});
|
|
458
|
-
} catch (err) {
|
|
459
|
-
next(err);
|
|
460
|
-
}
|
|
461
|
-
},
|
|
462
|
-
);
|
|
463
|
-
|
|
464
|
-
this.router.post(
|
|
465
|
-
`${new this.entityType().getCrudApiPath()?.toString()}/report-user-count`,
|
|
466
|
-
async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => {
|
|
467
|
-
try {
|
|
468
|
-
const licenseKey: string | undefined = (
|
|
469
|
-
req.body["licenseKey"] as string | undefined
|
|
470
|
-
)?.trim();
|
|
471
|
-
const rawUserCount: unknown = req.body["userCount"];
|
|
472
|
-
|
|
473
|
-
if (!licenseKey) {
|
|
474
|
-
throw new BadDataException("License key is required");
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
const userCount: number = Number(rawUserCount);
|
|
478
|
-
|
|
479
|
-
if (
|
|
480
|
-
!Number.isFinite(userCount) ||
|
|
481
|
-
userCount < 0 ||
|
|
482
|
-
!Number.isInteger(userCount)
|
|
483
|
-
) {
|
|
484
|
-
throw new BadDataException(
|
|
485
|
-
"userCount must be a non-negative integer",
|
|
486
|
-
);
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
const license: EnterpriseLicense | null =
|
|
490
|
-
await EnterpriseLicenseService.findOneBy({
|
|
491
|
-
query: {
|
|
492
|
-
licenseKey: licenseKey,
|
|
493
|
-
},
|
|
494
|
-
/*
|
|
495
|
-
* The full set of terms, not just the usage columns: this
|
|
496
|
-
* response is what a self-hosted installation mirrors into its
|
|
497
|
-
* own GlobalConfig every day, so anything it is missing here is
|
|
498
|
-
* a field the customer keeps the stale value of until somebody
|
|
499
|
-
* re-types the license key by hand. Same indexed lookup either
|
|
500
|
-
* way.
|
|
501
|
-
*/
|
|
502
|
-
select: {
|
|
503
|
-
_id: true,
|
|
504
|
-
companyName: true,
|
|
505
|
-
expiresAt: true,
|
|
506
|
-
licenseKey: true,
|
|
507
|
-
userLimit: true,
|
|
508
|
-
isEvaluationLicense: true,
|
|
509
|
-
},
|
|
510
|
-
props: {
|
|
511
|
-
isRoot: true,
|
|
512
|
-
},
|
|
513
|
-
});
|
|
514
|
-
|
|
515
|
-
if (!license) {
|
|
516
|
-
throw new BadDataException("License key is invalid");
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
const instanceId: string = this.parseShortText(
|
|
520
|
-
req.body["instanceId"],
|
|
521
|
-
);
|
|
522
|
-
const instanceHost: string = this.parseShortText(req.body["host"]);
|
|
523
|
-
const instanceVersion: string | null | undefined = this.parseVersion(
|
|
524
|
-
req.body["version"],
|
|
525
|
-
);
|
|
526
|
-
const userEmailHashes: Array<string> =
|
|
527
|
-
EnterpriseLicenseUsageUtil.sanitizeUserEmailHashes(
|
|
528
|
-
req.body["userEmailHashes"],
|
|
529
|
-
);
|
|
530
|
-
const masterAdminEmails: Array<string> =
|
|
531
|
-
EnterpriseLicenseUsageUtil.sanitizeMasterAdminEmails(
|
|
532
|
-
req.body["masterAdminEmails"],
|
|
533
|
-
);
|
|
534
|
-
const usageReport: LicenseUsageReportResult =
|
|
535
|
-
await EnterpriseLicenseService.runWithUsageAggregationLock({
|
|
536
|
-
licenseId: license.id!,
|
|
537
|
-
fn: async (): Promise<LicenseUsageReportResult> => {
|
|
538
|
-
/*
|
|
539
|
-
* Capture this after acquiring the lock. Waiting reports can
|
|
540
|
-
* never complete later with an earlier timestamp, and the
|
|
541
|
-
* upsert/read/aggregate/write sequence is one serialized
|
|
542
|
-
* critical section across every API replica.
|
|
543
|
-
*/
|
|
544
|
-
const reportedAt: Date = OneUptimeDate.getCurrentDate();
|
|
545
|
-
|
|
546
|
-
if (instanceId) {
|
|
547
|
-
/*
|
|
548
|
-
* Multi-instance report: track usage per instance and count
|
|
549
|
-
* users uniquely across all instances of this license.
|
|
550
|
-
*/
|
|
551
|
-
await this.upsertLicenseInstance({
|
|
552
|
-
licenseId: license.id!,
|
|
553
|
-
instanceId: instanceId,
|
|
554
|
-
host: instanceHost || undefined,
|
|
555
|
-
oneuptimeVersion: instanceVersion,
|
|
556
|
-
userCount: userCount,
|
|
557
|
-
userEmailHashes: userEmailHashes,
|
|
558
|
-
masterAdminEmails: masterAdminEmails,
|
|
559
|
-
lastReportedAt: reportedAt,
|
|
560
|
-
});
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
const instances: Array<EnterpriseLicenseInstance> =
|
|
564
|
-
await this.findLicenseInstances(license.id!);
|
|
565
|
-
const hasActiveReportedInstanceUsage: boolean =
|
|
566
|
-
EnterpriseLicenseUsageUtil.hasActiveReportedInstanceUsage(
|
|
567
|
-
instances,
|
|
568
|
-
reportedAt,
|
|
569
|
-
);
|
|
570
|
-
const currentUserCount: number = hasActiveReportedInstanceUsage
|
|
571
|
-
? EnterpriseLicenseUsageUtil.getUniqueUserCount(
|
|
572
|
-
instances,
|
|
573
|
-
reportedAt,
|
|
574
|
-
)
|
|
575
|
-
: userCount;
|
|
576
|
-
const usageUpdate: PartialEntity<EnterpriseLicense> = {};
|
|
577
|
-
|
|
578
|
-
/*
|
|
579
|
-
* Legacy reports (no instanceId) drive the license-wide count
|
|
580
|
-
* only while no modern instance is active. Their separate
|
|
581
|
-
* heartbeat is always retained, though, so a legacy reporter
|
|
582
|
-
* can take over immediately when the last modern report ages
|
|
583
|
-
* out instead of disappearing until its next daily call.
|
|
584
|
-
*/
|
|
585
|
-
if (!instanceId) {
|
|
586
|
-
usageUpdate.legacyUserCount = userCount;
|
|
587
|
-
usageUpdate.legacyUserCountUpdatedAt = reportedAt;
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
if (instanceId || !hasActiveReportedInstanceUsage) {
|
|
591
|
-
usageUpdate.currentUserCount = currentUserCount;
|
|
592
|
-
usageUpdate.userCountUpdatedAt = reportedAt;
|
|
593
|
-
usageUpdate.userCountSource = instanceId
|
|
594
|
-
? EnterpriseLicenseUserCountSource.Instance
|
|
595
|
-
: EnterpriseLicenseUserCountSource.Legacy;
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
if (Object.keys(usageUpdate).length > 0) {
|
|
599
|
-
await EnterpriseLicenseService.updateOneById({
|
|
600
|
-
id: license.id!,
|
|
601
|
-
data: usageUpdate,
|
|
602
|
-
props: {
|
|
603
|
-
isRoot: true,
|
|
604
|
-
ignoreHooks: true,
|
|
605
|
-
},
|
|
606
|
-
});
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
return {
|
|
610
|
-
reportedAt,
|
|
611
|
-
instances,
|
|
612
|
-
currentUserCount,
|
|
613
|
-
};
|
|
614
|
-
},
|
|
615
|
-
});
|
|
616
|
-
|
|
617
|
-
const { reportedAt, instances, currentUserCount } = usageReport;
|
|
618
|
-
|
|
619
|
-
const terms: LicenseTerms = this.getLicenseTerms(license);
|
|
620
|
-
|
|
621
|
-
return Response.sendJsonObjectResponse(req, res, {
|
|
622
|
-
companyName: terms.companyName,
|
|
623
|
-
expiresAt: terms.expiresAt,
|
|
624
|
-
licenseKey: terms.licenseKey,
|
|
625
|
-
userLimit: terms.userLimit,
|
|
626
|
-
currentUserCount: currentUserCount,
|
|
627
|
-
userCountUpdatedAt: reportedAt.toISOString(),
|
|
628
|
-
isEvaluationLicense: Boolean(license.isEvaluationLicense),
|
|
629
|
-
instances: this.getInstanceSummaries(instances, reportedAt),
|
|
630
|
-
/*
|
|
631
|
-
* Null once the license has expired. Unlike /validate this route
|
|
632
|
-
* does not reject an expired license - the instance is still
|
|
633
|
-
* expected to report, and the expiry notification emails are built
|
|
634
|
-
* from what it reports - but it must not keep being handed a fresh
|
|
635
|
-
* token, and the expiresAt above is what tells it the truth.
|
|
636
|
-
*/
|
|
637
|
-
token: this.signLicenseToken(license),
|
|
638
|
-
});
|
|
639
|
-
} catch (err) {
|
|
640
|
-
next(err);
|
|
641
|
-
}
|
|
642
|
-
},
|
|
643
|
-
);
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
/*
|
|
647
|
-
* The license terms a self-hosted installation mirrors locally. Built in one
|
|
648
|
-
* place so /validate and /report-user-count cannot drift: the seat limit was
|
|
649
|
-
* missing from what an instance could refresh for exactly as long as the two
|
|
650
|
-
* responses were written out by hand, separately.
|
|
651
|
-
*/
|
|
652
|
-
private getLicenseTerms(license: EnterpriseLicense): LicenseTerms {
|
|
653
|
-
return {
|
|
654
|
-
companyName: license.companyName || "",
|
|
655
|
-
expiresAt: license.expiresAt ? license.expiresAt.toISOString() : null,
|
|
656
|
-
licenseKey: license.licenseKey || "",
|
|
657
|
-
userLimit:
|
|
658
|
-
typeof license.userLimit === "number" ? license.userLimit : null,
|
|
659
|
-
};
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
/*
|
|
663
|
-
* Signed with the license server's own secret, so it is opaque to the
|
|
664
|
-
* installation holding it - it is the proof that oneuptime.com recognized
|
|
665
|
-
* the key, and the instance only checks that it exists. An expired license
|
|
666
|
-
* gets none, which is why this returns null rather than a short-lived token.
|
|
667
|
-
*/
|
|
668
|
-
private signLicenseToken(license: EnterpriseLicense): string | null {
|
|
669
|
-
if (!license.expiresAt) {
|
|
670
|
-
return null;
|
|
671
|
-
}
|
|
672
|
-
|
|
673
|
-
const secondsUntilExpiry: number = Math.floor(
|
|
674
|
-
(license.expiresAt.getTime() - Date.now()) / 1000,
|
|
675
|
-
);
|
|
676
|
-
|
|
677
|
-
if (secondsUntilExpiry <= 0) {
|
|
678
|
-
return null;
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
const terms: LicenseTerms = this.getLicenseTerms(license);
|
|
682
|
-
|
|
683
|
-
return JSONWebToken.signJsonPayload(
|
|
684
|
-
{
|
|
685
|
-
companyName: terms.companyName,
|
|
686
|
-
expiresAt: terms.expiresAt,
|
|
687
|
-
licenseKey: terms.licenseKey,
|
|
688
|
-
userLimit: terms.userLimit,
|
|
689
|
-
},
|
|
690
|
-
Math.max(secondsUntilExpiry, 1),
|
|
691
|
-
);
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
private parseShortText(value: unknown): string {
|
|
695
|
-
if (typeof value !== "string") {
|
|
696
|
-
return "";
|
|
697
|
-
}
|
|
698
|
-
|
|
699
|
-
return value.trim().substring(0, 100);
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
/*
|
|
703
|
-
* report-user-count is unauthenticated, so the reported version is only
|
|
704
|
-
* stored when it is a version we could actually compare against a release —
|
|
705
|
-
* garbage never reaches the admin dashboard or the customer's modal.
|
|
706
|
-
*
|
|
707
|
-
* Three outcomes, and the callers depend on the distinction:
|
|
708
|
-
* undefined — the instance sent no version at all (it predates this
|
|
709
|
-
* field). Leave whatever is stored alone.
|
|
710
|
-
* null — it sent something, but not a version. Clear the stored
|
|
711
|
-
* value, so an instance rolled back to a build with no
|
|
712
|
-
* APP_VERSION stops advertising the version it used to run.
|
|
713
|
-
* string — a valid, canonical version to store.
|
|
714
|
-
*/
|
|
715
|
-
private parseVersion(value: unknown): string | null | undefined {
|
|
716
|
-
if (value === undefined || value === null) {
|
|
717
|
-
return undefined;
|
|
718
|
-
}
|
|
719
|
-
|
|
720
|
-
/*
|
|
721
|
-
* Canonicalized rather than passed through, so the stored string is never
|
|
722
|
-
* something the UIs would render with a doubled "v".
|
|
723
|
-
*/
|
|
724
|
-
return VersionUtil.canonicalize(value);
|
|
725
|
-
}
|
|
726
|
-
|
|
727
|
-
private async findLicenseInstances(
|
|
728
|
-
licenseId: ObjectID,
|
|
729
|
-
): Promise<Array<EnterpriseLicenseInstance>> {
|
|
730
|
-
return EnterpriseLicenseInstanceService.findBy({
|
|
731
|
-
query: {
|
|
732
|
-
enterpriseLicenseId: licenseId,
|
|
733
|
-
},
|
|
734
|
-
select: {
|
|
735
|
-
_id: true,
|
|
736
|
-
createdAt: true,
|
|
737
|
-
instanceId: true,
|
|
738
|
-
host: true,
|
|
739
|
-
userCount: true,
|
|
740
|
-
userEmailHashes: true,
|
|
741
|
-
masterAdminEmails: true,
|
|
742
|
-
lastReportedAt: true,
|
|
743
|
-
oneuptimeVersion: true,
|
|
744
|
-
},
|
|
745
|
-
sort: {
|
|
746
|
-
createdAt: SortOrder.Ascending,
|
|
747
|
-
},
|
|
748
|
-
skip: 0,
|
|
749
|
-
limit: LIMIT_MAX,
|
|
750
|
-
props: {
|
|
751
|
-
isRoot: true,
|
|
752
|
-
},
|
|
753
|
-
});
|
|
754
|
-
}
|
|
755
|
-
|
|
756
|
-
private getInstanceSummaries(
|
|
757
|
-
instances: Array<EnterpriseLicenseInstance>,
|
|
758
|
-
calculatedAt: Date,
|
|
759
|
-
): Array<EnterpriseLicenseInstanceSummary> {
|
|
760
|
-
return instances.map(
|
|
761
|
-
(
|
|
762
|
-
instance: EnterpriseLicenseInstance,
|
|
763
|
-
): EnterpriseLicenseInstanceSummary => {
|
|
764
|
-
return {
|
|
765
|
-
instanceId: instance.instanceId || "",
|
|
766
|
-
host: instance.host || null,
|
|
767
|
-
userCount:
|
|
768
|
-
typeof instance.userCount === "number" ? instance.userCount : null,
|
|
769
|
-
isCountedTowardsUsage:
|
|
770
|
-
EnterpriseLicenseUsageUtil.isInstanceCountedTowardsUsage(
|
|
771
|
-
instance,
|
|
772
|
-
calculatedAt,
|
|
773
|
-
),
|
|
774
|
-
lastReportedAt: instance.lastReportedAt
|
|
775
|
-
? instance.lastReportedAt.toISOString()
|
|
776
|
-
: null,
|
|
777
|
-
version: instance.oneuptimeVersion || null,
|
|
778
|
-
};
|
|
779
|
-
},
|
|
780
|
-
);
|
|
781
|
-
}
|
|
782
|
-
|
|
783
|
-
private async upsertLicenseInstance(
|
|
784
|
-
data: LicenseInstanceUpsert,
|
|
785
|
-
): Promise<void> {
|
|
786
|
-
const updated: boolean = await this.updateLicenseInstanceIfExists(data);
|
|
787
|
-
|
|
788
|
-
if (updated) {
|
|
789
|
-
return;
|
|
790
|
-
}
|
|
791
|
-
|
|
792
|
-
const instanceCount: PositiveNumber =
|
|
793
|
-
await EnterpriseLicenseInstanceService.countBy({
|
|
794
|
-
query: {
|
|
795
|
-
enterpriseLicenseId: data.licenseId,
|
|
796
|
-
},
|
|
797
|
-
props: {
|
|
798
|
-
isRoot: true,
|
|
799
|
-
},
|
|
800
|
-
});
|
|
801
|
-
|
|
802
|
-
if (instanceCount.toNumber() >= MAX_INSTANCES_PER_LICENSE) {
|
|
803
|
-
throw new BadDataException(
|
|
804
|
-
"Too many instances are registered for this license. Please contact support@oneuptime.com.",
|
|
805
|
-
);
|
|
806
|
-
}
|
|
807
|
-
|
|
808
|
-
const newInstance: EnterpriseLicenseInstance =
|
|
809
|
-
new EnterpriseLicenseInstance();
|
|
810
|
-
newInstance.enterpriseLicenseId = data.licenseId;
|
|
811
|
-
newInstance.instanceId = data.instanceId;
|
|
812
|
-
|
|
813
|
-
if (data.host !== undefined) {
|
|
814
|
-
newInstance.host = data.host;
|
|
815
|
-
}
|
|
816
|
-
|
|
817
|
-
// Null means "reported something that is not a version" — nothing to store.
|
|
818
|
-
if (data.oneuptimeVersion) {
|
|
819
|
-
newInstance.oneuptimeVersion = data.oneuptimeVersion;
|
|
820
|
-
}
|
|
821
|
-
|
|
822
|
-
if (data.userCount !== undefined) {
|
|
823
|
-
newInstance.userCount = data.userCount;
|
|
824
|
-
}
|
|
825
|
-
|
|
826
|
-
if (data.userEmailHashes !== undefined) {
|
|
827
|
-
newInstance.userEmailHashes = data.userEmailHashes;
|
|
828
|
-
}
|
|
829
|
-
|
|
830
|
-
if (data.masterAdminEmails !== undefined) {
|
|
831
|
-
newInstance.masterAdminEmails = data.masterAdminEmails;
|
|
832
|
-
}
|
|
833
|
-
|
|
834
|
-
if (data.lastReportedAt !== undefined) {
|
|
835
|
-
newInstance.lastReportedAt = data.lastReportedAt;
|
|
836
|
-
}
|
|
837
|
-
|
|
838
|
-
try {
|
|
839
|
-
await EnterpriseLicenseInstanceService.create({
|
|
840
|
-
data: newInstance,
|
|
841
|
-
props: {
|
|
842
|
-
isRoot: true,
|
|
843
|
-
},
|
|
844
|
-
});
|
|
845
|
-
} catch (err) {
|
|
846
|
-
/*
|
|
847
|
-
* A concurrent request created the row between our check and this
|
|
848
|
-
* insert — the unique index on (enterpriseLicenseId, instanceId)
|
|
849
|
-
* rejected the duplicate. Apply the report as an update instead.
|
|
850
|
-
*/
|
|
851
|
-
const retried: boolean = await this.updateLicenseInstanceIfExists(data);
|
|
852
|
-
|
|
853
|
-
if (!retried) {
|
|
854
|
-
throw err;
|
|
855
|
-
}
|
|
856
|
-
}
|
|
857
|
-
}
|
|
858
|
-
|
|
859
|
-
private async updateLicenseInstanceIfExists(
|
|
860
|
-
data: LicenseInstanceUpsert,
|
|
861
|
-
): Promise<boolean> {
|
|
862
|
-
const existingInstance: EnterpriseLicenseInstance | null =
|
|
863
|
-
await EnterpriseLicenseInstanceService.findOneBy({
|
|
864
|
-
query: {
|
|
865
|
-
enterpriseLicenseId: data.licenseId,
|
|
866
|
-
instanceId: data.instanceId,
|
|
867
|
-
},
|
|
868
|
-
select: {
|
|
869
|
-
_id: true,
|
|
870
|
-
},
|
|
871
|
-
props: {
|
|
872
|
-
isRoot: true,
|
|
873
|
-
},
|
|
874
|
-
});
|
|
875
|
-
|
|
876
|
-
if (!existingInstance) {
|
|
877
|
-
return false;
|
|
878
|
-
}
|
|
879
|
-
|
|
880
|
-
const updateData: PartialEntity<EnterpriseLicenseInstance> = {};
|
|
881
|
-
|
|
882
|
-
if (data.host !== undefined) {
|
|
883
|
-
updateData.host = data.host;
|
|
884
|
-
}
|
|
885
|
-
|
|
886
|
-
/*
|
|
887
|
-
* Null clears the column: an instance rebuilt onto a build with no
|
|
888
|
-
* APP_VERSION must stop advertising the version it used to run, because
|
|
889
|
-
* lastReportedAt is refreshed on the same request and would otherwise
|
|
890
|
-
* read as "confirmed running v11.5.13 as of today".
|
|
891
|
-
*/
|
|
892
|
-
if (data.oneuptimeVersion !== undefined) {
|
|
893
|
-
updateData.oneuptimeVersion = data.oneuptimeVersion;
|
|
894
|
-
}
|
|
895
|
-
|
|
896
|
-
if (data.userCount !== undefined) {
|
|
897
|
-
updateData.userCount = data.userCount;
|
|
898
|
-
}
|
|
899
|
-
|
|
900
|
-
if (data.userEmailHashes !== undefined) {
|
|
901
|
-
updateData.userEmailHashes = data.userEmailHashes;
|
|
902
|
-
}
|
|
903
|
-
|
|
904
|
-
if (data.masterAdminEmails !== undefined) {
|
|
905
|
-
updateData.masterAdminEmails = data.masterAdminEmails;
|
|
906
|
-
}
|
|
907
|
-
|
|
908
|
-
if (data.lastReportedAt !== undefined) {
|
|
909
|
-
updateData.lastReportedAt = data.lastReportedAt;
|
|
910
|
-
}
|
|
911
|
-
|
|
912
|
-
if (Object.keys(updateData).length > 0) {
|
|
913
|
-
await EnterpriseLicenseInstanceService.updateOneById({
|
|
914
|
-
id: existingInstance.id!,
|
|
915
|
-
data: updateData,
|
|
916
|
-
props: {
|
|
917
|
-
isRoot: true,
|
|
918
|
-
ignoreHooks: true,
|
|
919
|
-
},
|
|
920
|
-
});
|
|
921
|
-
}
|
|
922
|
-
|
|
923
|
-
return true;
|
|
924
|
-
}
|
|
925
|
-
}
|