@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
|
@@ -1,287 +0,0 @@
|
|
|
1
|
-
import EnterpriseLicenseInstanceSummary from "../../Types/EnterpriseLicense/EnterpriseLicenseInstanceSummary";
|
|
2
|
-
|
|
3
|
-
/*
|
|
4
|
-
* Everything the seat calculation needs, taken as plain values so this file
|
|
5
|
-
* stays a pure function the tests can drive directly. The server reads these
|
|
6
|
-
* off GlobalConfig; the browser reads them off the /global-config/license
|
|
7
|
-
* response.
|
|
8
|
-
*/
|
|
9
|
-
export interface SeatUsageInput {
|
|
10
|
-
/*
|
|
11
|
-
* The seat limit mirrored from oneuptime.com. Null, undefined or anything
|
|
12
|
-
* that is not a positive whole number means "no limit to enforce" — see
|
|
13
|
-
* getSeatUsage for why zero is included in that.
|
|
14
|
-
*/
|
|
15
|
-
userLimit?: number | null | undefined;
|
|
16
|
-
|
|
17
|
-
/*
|
|
18
|
-
* Users that exist on THIS installation right now. The live number, counted
|
|
19
|
-
* at the moment of the check rather than taken from the last daily report,
|
|
20
|
-
* because the whole point of enforcement is to catch the user who is being
|
|
21
|
-
* added a second after the report was sent.
|
|
22
|
-
*/
|
|
23
|
-
localUserCount: number;
|
|
24
|
-
|
|
25
|
-
/*
|
|
26
|
-
* Unique users across every instance sharing this license, as oneuptime.com
|
|
27
|
-
* last computed it. Up to a day stale, and only meaningful for a customer
|
|
28
|
-
* running more than one instance on one key.
|
|
29
|
-
*/
|
|
30
|
-
aggregatedUserCount?: number | null | undefined;
|
|
31
|
-
|
|
32
|
-
/*
|
|
33
|
-
* Per-instance breakdown from the same report. Used only to work out how
|
|
34
|
-
* much of aggregatedUserCount belongs to OTHER instances.
|
|
35
|
-
*/
|
|
36
|
-
instances?: Array<EnterpriseLicenseInstanceSummary> | null | undefined;
|
|
37
|
-
|
|
38
|
-
// This installation's own instance id, so it can find itself in `instances`.
|
|
39
|
-
thisInstanceId?: string | null | undefined;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export interface SeatUsage {
|
|
43
|
-
/*
|
|
44
|
-
* False when the license carries no usable seat limit. Every other field is
|
|
45
|
-
* still filled in — a caller that wants to display usage can, it just must
|
|
46
|
-
* not block anything.
|
|
47
|
-
*/
|
|
48
|
-
isEnforced: boolean;
|
|
49
|
-
|
|
50
|
-
// The limit actually being enforced, or null when there is none.
|
|
51
|
-
userLimit: number | null;
|
|
52
|
-
|
|
53
|
-
/*
|
|
54
|
-
* The best estimate of how many licensed seats are consumed right now,
|
|
55
|
-
* across every instance on this license. See getSeatUsage for how it is
|
|
56
|
-
* derived and which way it is allowed to be wrong.
|
|
57
|
-
*/
|
|
58
|
-
seatsInUse: number;
|
|
59
|
-
|
|
60
|
-
// Null when there is no limit. Never negative — a breach reads as 0 free.
|
|
61
|
-
seatsRemaining: number | null;
|
|
62
|
-
|
|
63
|
-
/*
|
|
64
|
-
* The single question enforcement asks. True whenever there is no limit, so
|
|
65
|
-
* a caller can use this on its own without re-checking isEnforced.
|
|
66
|
-
*/
|
|
67
|
-
hasSeatForNewUser: boolean;
|
|
68
|
-
|
|
69
|
-
/*
|
|
70
|
-
* How many of seatsInUse are users this installation has never seen. Zero
|
|
71
|
-
* whenever the topology is not known well enough to say, which is the
|
|
72
|
-
* conservative answer — see getSeatUsage.
|
|
73
|
-
*/
|
|
74
|
-
seatsUsedByOtherInstances: number;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export default class EnterpriseLicenseSeatsUtil {
|
|
78
|
-
/*
|
|
79
|
-
* How many seats are in use, and whether one more user fits.
|
|
80
|
-
*
|
|
81
|
-
* The awkward part is that a license is shared by every instance the
|
|
82
|
-
* customer runs, and only oneuptime.com can deduplicate users across them —
|
|
83
|
-
* the same person on staging and production is one seat. So this instance
|
|
84
|
-
* has two numbers and neither one is the answer on its own:
|
|
85
|
-
*
|
|
86
|
-
* localUserCount live, but blind to the customer's other instances.
|
|
87
|
-
* aggregatedUserCount complete, but up to a day old, so it does not know
|
|
88
|
-
* about anyone added since the last daily report —
|
|
89
|
-
* including the user being added right now.
|
|
90
|
-
*
|
|
91
|
-
* Combining them needs to know how much of the aggregate is NOT ours, which
|
|
92
|
-
* is what the per-instance breakdown is for: subtract our own last reported
|
|
93
|
-
* count from the aggregate and what is left is other instances. Add the live
|
|
94
|
-
* local count back and the result is current on this instance and complete
|
|
95
|
-
* on the others.
|
|
96
|
-
*
|
|
97
|
-
* When the breakdown does not say — an older license server that sends no
|
|
98
|
-
* instance list, an instance that has never registered — there is nothing to
|
|
99
|
-
* subtract, and the fallback is the larger of the two numbers on their own.
|
|
100
|
-
* That is the only case where the stale aggregate decides anything: with a
|
|
101
|
-
* usable breakdown it is deliberately NOT maxed in, because it would then
|
|
102
|
-
* outvote the live count in the one direction that hurts. Free twenty seats
|
|
103
|
-
* by deleting twenty users and a stale aggregate would go on refusing new
|
|
104
|
-
* ones until the next daily report.
|
|
105
|
-
*
|
|
106
|
-
* Which way it is allowed to be wrong: under-enforcing is recoverable (the
|
|
107
|
-
* next daily report corrects the count, and the breach emails already go
|
|
108
|
-
* out), over-enforcing locks a paying customer out of their own instance.
|
|
109
|
-
* So every "I cannot tell" branch below resolves towards under-enforcing.
|
|
110
|
-
*/
|
|
111
|
-
public static getSeatUsage(input: SeatUsageInput): SeatUsage {
|
|
112
|
-
const userLimit: number | null = this.parseUserLimit(input.userLimit);
|
|
113
|
-
const localUserCount: number = this.parseCount(input.localUserCount) ?? 0;
|
|
114
|
-
const aggregatedUserCount: number | null = this.parseCount(
|
|
115
|
-
input.aggregatedUserCount,
|
|
116
|
-
);
|
|
117
|
-
|
|
118
|
-
/*
|
|
119
|
-
* Null means the report is not complete enough to attribute seats to
|
|
120
|
-
* anybody, which is a different thing from attributing zero to them.
|
|
121
|
-
*/
|
|
122
|
-
const otherInstanceSeats: number | null = this.getSeatsUsedByOtherInstances(
|
|
123
|
-
{
|
|
124
|
-
aggregatedUserCount: aggregatedUserCount,
|
|
125
|
-
instances: input.instances,
|
|
126
|
-
thisInstanceId: input.thisInstanceId,
|
|
127
|
-
},
|
|
128
|
-
);
|
|
129
|
-
|
|
130
|
-
const seatsUsedByOtherInstances: number = otherInstanceSeats ?? 0;
|
|
131
|
-
|
|
132
|
-
const seatsInUse: number =
|
|
133
|
-
otherInstanceSeats === null
|
|
134
|
-
? Math.max(localUserCount, aggregatedUserCount ?? 0)
|
|
135
|
-
: otherInstanceSeats + localUserCount;
|
|
136
|
-
|
|
137
|
-
if (userLimit === null) {
|
|
138
|
-
return {
|
|
139
|
-
isEnforced: false,
|
|
140
|
-
userLimit: null,
|
|
141
|
-
seatsInUse: seatsInUse,
|
|
142
|
-
seatsRemaining: null,
|
|
143
|
-
hasSeatForNewUser: true,
|
|
144
|
-
seatsUsedByOtherInstances: seatsUsedByOtherInstances,
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
return {
|
|
149
|
-
isEnforced: true,
|
|
150
|
-
userLimit: userLimit,
|
|
151
|
-
seatsInUse: seatsInUse,
|
|
152
|
-
seatsRemaining: Math.max(0, userLimit - seatsInUse),
|
|
153
|
-
hasSeatForNewUser: seatsInUse < userLimit,
|
|
154
|
-
seatsUsedByOtherInstances: seatsUsedByOtherInstances,
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/*
|
|
159
|
-
* The message an administrator reads when a seat could not be taken. Built
|
|
160
|
-
* here rather than at each throw site so the invite form, the signup form
|
|
161
|
-
* and SSO/SCIM provisioning all explain the same thing the same way, and so
|
|
162
|
-
* the tests can assert on it without copying the wording.
|
|
163
|
-
*/
|
|
164
|
-
public static getSeatLimitReachedMessage(data: {
|
|
165
|
-
seatsInUse: number;
|
|
166
|
-
userLimit: number;
|
|
167
|
-
}): string {
|
|
168
|
-
return (
|
|
169
|
-
`This OneUptime installation has reached the ${data.userLimit.toLocaleString()}-user ` +
|
|
170
|
-
`limit of its enterprise license (${data.seatsInUse.toLocaleString()} in use). New users ` +
|
|
171
|
-
`cannot be invited, signed up or provisioned until a seat is freed up or the license is ` +
|
|
172
|
-
`expanded. Contact sales@oneuptime.com to add seats, then use "Refresh license" in the ` +
|
|
173
|
-
`edition dialog to apply the new limit.`
|
|
174
|
-
);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/*
|
|
178
|
-
* The part of the aggregate that belongs to instances other than this one,
|
|
179
|
-
* or null when the report does not say.
|
|
180
|
-
*
|
|
181
|
-
* Null rather than zero, because the two lead somewhere different: zero means
|
|
182
|
-
* "this installation is the only one holding seats", and null means "the
|
|
183
|
-
* report cannot be decomposed, fall back to comparing the two totals". Every
|
|
184
|
-
* missing or unusable field lands on null.
|
|
185
|
-
*
|
|
186
|
-
* In particular, an instance list that does not contain us is NOT treated as
|
|
187
|
-
* "then all of the aggregate is somebody else's". That reading is right for a
|
|
188
|
-
* genuinely unregistered instance, and catastrophic for an instance whose id
|
|
189
|
-
* changed after its users were already counted under the old one: it would
|
|
190
|
-
* count this installation's users twice and lock it out.
|
|
191
|
-
*/
|
|
192
|
-
private static getSeatsUsedByOtherInstances(data: {
|
|
193
|
-
aggregatedUserCount: number | null;
|
|
194
|
-
instances?: Array<EnterpriseLicenseInstanceSummary> | null | undefined;
|
|
195
|
-
thisInstanceId?: string | null | undefined;
|
|
196
|
-
}): number | null {
|
|
197
|
-
const aggregatedUserCount: number | null = data.aggregatedUserCount;
|
|
198
|
-
|
|
199
|
-
if (aggregatedUserCount === null) {
|
|
200
|
-
return null;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
if (!Array.isArray(data.instances) || data.instances.length === 0) {
|
|
204
|
-
return null;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
const thisInstanceId: string =
|
|
208
|
-
typeof data.thisInstanceId === "string" ? data.thisInstanceId.trim() : "";
|
|
209
|
-
|
|
210
|
-
if (!thisInstanceId) {
|
|
211
|
-
return null;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
const thisInstance: EnterpriseLicenseInstanceSummary | undefined =
|
|
215
|
-
data.instances.find(
|
|
216
|
-
(instance: EnterpriseLicenseInstanceSummary): boolean => {
|
|
217
|
-
return Boolean(instance) && instance.instanceId === thisInstanceId;
|
|
218
|
-
},
|
|
219
|
-
);
|
|
220
|
-
|
|
221
|
-
if (!thisInstance) {
|
|
222
|
-
return null;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
/*
|
|
226
|
-
* The active-only aggregate contains none of this installation's stale
|
|
227
|
-
* reported users. Subtracting that old count would remove users belonging
|
|
228
|
-
* to active instances and under-enforce the license. Treat the complete
|
|
229
|
-
* aggregate as other-instance usage. We also cannot add the two counts:
|
|
230
|
-
* the same users may exist on both this installation and active ones.
|
|
231
|
-
* Return null to use the existing uncertainty fallback, which takes the
|
|
232
|
-
* larger complete-or-live total without subtracting or double-counting.
|
|
233
|
-
*
|
|
234
|
-
* Undefined retains the legacy behavior for responses from older license
|
|
235
|
-
* servers that did not send activity provenance.
|
|
236
|
-
*/
|
|
237
|
-
if (thisInstance.isCountedTowardsUsage === false) {
|
|
238
|
-
return null;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
const ownReportedCount: number | null = this.parseCount(
|
|
242
|
-
thisInstance.userCount,
|
|
243
|
-
);
|
|
244
|
-
|
|
245
|
-
if (ownReportedCount === null) {
|
|
246
|
-
return null;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
return Math.max(0, aggregatedUserCount - ownReportedCount);
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
/*
|
|
253
|
-
* A limit is only a limit when it is a positive whole number.
|
|
254
|
-
*
|
|
255
|
-
* Zero is deliberately read as "no limit" rather than "no seats at all",
|
|
256
|
-
* matching every other place in the product that measures seat usage
|
|
257
|
-
* (the license modal, the breach notification job). A license that really
|
|
258
|
-
* grants nobody an account is not a thing OneUptime issues, and reading a
|
|
259
|
-
* stray zero the other way would leave an installation unable to create even
|
|
260
|
-
* its first user.
|
|
261
|
-
*/
|
|
262
|
-
private static parseUserLimit(value: unknown): number | null {
|
|
263
|
-
if (
|
|
264
|
-
typeof value !== "number" ||
|
|
265
|
-
!Number.isFinite(value) ||
|
|
266
|
-
!Number.isInteger(value) ||
|
|
267
|
-
value <= 0
|
|
268
|
-
) {
|
|
269
|
-
return null;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
return value;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
private static parseCount(value: unknown): number | null {
|
|
276
|
-
if (
|
|
277
|
-
typeof value !== "number" ||
|
|
278
|
-
!Number.isFinite(value) ||
|
|
279
|
-
!Number.isInteger(value) ||
|
|
280
|
-
value < 0
|
|
281
|
-
) {
|
|
282
|
-
return null;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
return value;
|
|
286
|
-
}
|
|
287
|
-
}
|
|
@@ -1,244 +0,0 @@
|
|
|
1
|
-
import GlobalConfig from "../../Models/DatabaseModels/GlobalConfig";
|
|
2
|
-
import PartialEntity from "../../Types/Database/PartialEntity";
|
|
3
|
-
import EnterpriseLicenseInstanceSummary from "../../Types/EnterpriseLicense/EnterpriseLicenseInstanceSummary";
|
|
4
|
-
import { JSONObject } from "../../Types/JSON";
|
|
5
|
-
|
|
6
|
-
export interface EnterpriseLicenseSyncResult {
|
|
7
|
-
/*
|
|
8
|
-
* Only the columns the license server actually spoke about. A column the
|
|
9
|
-
* response did not mention is absent from this object, so updateOneById
|
|
10
|
-
* leaves whatever is stored alone.
|
|
11
|
-
*/
|
|
12
|
-
updateData: PartialEntity<GlobalConfig>;
|
|
13
|
-
|
|
14
|
-
/*
|
|
15
|
-
* Fields the server sent in a shape this build cannot use. Returned rather
|
|
16
|
-
* than logged so this stays a pure function the tests can drive directly;
|
|
17
|
-
* the caller decides how loud to be about them.
|
|
18
|
-
*/
|
|
19
|
-
warnings: Array<string>;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/*
|
|
23
|
-
* Maps a license-server response (from /enterprise-license/validate or
|
|
24
|
-
* /enterprise-license/report-user-count) onto the GlobalConfig columns a
|
|
25
|
-
* self-hosted installation mirrors locally.
|
|
26
|
-
*
|
|
27
|
-
* Every field is three-state, and the distinction is the whole contract:
|
|
28
|
-
*
|
|
29
|
-
* key absent - the license server did not speak about this field. That is
|
|
30
|
-
* what an oneuptime.com older than this build looks like, so
|
|
31
|
-
* the stored value is left exactly as it is. Collapsing this
|
|
32
|
-
* to null is how a daily report would wipe a perfectly good
|
|
33
|
-
* license expiry and take the installation down.
|
|
34
|
-
* null - the server explicitly says "there is no value". Written as
|
|
35
|
-
* null, so clearing a seat limit on oneuptime.com actually
|
|
36
|
-
* clears it on the customer's installation.
|
|
37
|
-
* a value - validated, then written.
|
|
38
|
-
*
|
|
39
|
-
* Anything that is neither absent, null, nor a usable value is treated as
|
|
40
|
-
* absent and reported as a warning: a malformed response must never be able
|
|
41
|
-
* to corrupt license state that was correct a moment ago.
|
|
42
|
-
*/
|
|
43
|
-
export default class EnterpriseLicenseSyncUtil {
|
|
44
|
-
/*
|
|
45
|
-
* The license key is deliberately NOT synced. The installation authenticates
|
|
46
|
-
* with the key it already holds, and a response must never be able to swap
|
|
47
|
-
* it for another one.
|
|
48
|
-
*/
|
|
49
|
-
public static getGlobalConfigUpdateFromLicenseResponse(data: {
|
|
50
|
-
payload: JSONObject;
|
|
51
|
-
/*
|
|
52
|
-
* Used as the "user count as of" stamp when the server reports a count but
|
|
53
|
-
* no timestamp for it. Passed in rather than read from the clock so the
|
|
54
|
-
* function stays pure.
|
|
55
|
-
*/
|
|
56
|
-
reportedAt: Date;
|
|
57
|
-
}): EnterpriseLicenseSyncResult {
|
|
58
|
-
const payload: JSONObject = data.payload || {};
|
|
59
|
-
const updateData: PartialEntity<GlobalConfig> = {};
|
|
60
|
-
const warnings: Array<string> = [];
|
|
61
|
-
|
|
62
|
-
/*
|
|
63
|
-
* The seat limit. This is the field customers change on oneuptime.com and
|
|
64
|
-
* then wait for: without it here, buying seats never reaches the
|
|
65
|
-
* installation that is enforcing the old number.
|
|
66
|
-
*/
|
|
67
|
-
if (this.isPresent(payload, "userLimit")) {
|
|
68
|
-
const rawUserLimit: unknown = payload["userLimit"];
|
|
69
|
-
|
|
70
|
-
if (rawUserLimit === null) {
|
|
71
|
-
updateData.enterpriseLicenseUserLimit = null;
|
|
72
|
-
} else if (this.isNonNegativeInteger(rawUserLimit)) {
|
|
73
|
-
updateData.enterpriseLicenseUserLimit = rawUserLimit as number;
|
|
74
|
-
} else {
|
|
75
|
-
warnings.push(
|
|
76
|
-
`Ignored userLimit "${String(
|
|
77
|
-
rawUserLimit,
|
|
78
|
-
)}" from the license server: it is not a non-negative whole number.`,
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/*
|
|
84
|
-
* The count and its timestamp move together: a count with a stamp from a
|
|
85
|
-
* previous report would read as "confirmed today", which is the exact
|
|
86
|
-
* lie this whole sync exists to stop telling.
|
|
87
|
-
*/
|
|
88
|
-
if (this.isPresent(payload, "currentUserCount")) {
|
|
89
|
-
const rawUserCount: unknown = payload["currentUserCount"];
|
|
90
|
-
|
|
91
|
-
if (this.isNonNegativeInteger(rawUserCount)) {
|
|
92
|
-
updateData.enterpriseLicenseCurrentUserCount = rawUserCount as number;
|
|
93
|
-
updateData.enterpriseLicenseUserCountUpdatedAt =
|
|
94
|
-
this.parseDate(payload["userCountUpdatedAt"]) || data.reportedAt;
|
|
95
|
-
} else if (rawUserCount === null) {
|
|
96
|
-
/*
|
|
97
|
-
* The server has never had a count for this license. Nothing useful to
|
|
98
|
-
* store, and blanking the last known count would be worse than keeping
|
|
99
|
-
* it, so leave both columns alone.
|
|
100
|
-
*/
|
|
101
|
-
warnings.push(
|
|
102
|
-
"The license server reported no user count for this license. Keeping the previously stored usage.",
|
|
103
|
-
);
|
|
104
|
-
} else {
|
|
105
|
-
warnings.push(
|
|
106
|
-
`Ignored currentUserCount "${String(
|
|
107
|
-
rawUserCount,
|
|
108
|
-
)}" from the license server: it is not a non-negative whole number. Keeping the previously stored usage.`,
|
|
109
|
-
);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/*
|
|
114
|
-
* Expiry drives licenseValid on the installation, so a renewal that never
|
|
115
|
-
* arrives here shows up as a license that expires on its original date
|
|
116
|
-
* however much the customer paid. Null is treated as absent on purpose: a
|
|
117
|
-
* report is not the place to strip an installation of its expiry.
|
|
118
|
-
*/
|
|
119
|
-
if (this.isPresent(payload, "expiresAt") && payload["expiresAt"] !== null) {
|
|
120
|
-
const expiresAt: Date | null = this.parseDate(payload["expiresAt"]);
|
|
121
|
-
|
|
122
|
-
if (expiresAt) {
|
|
123
|
-
updateData.enterpriseLicenseExpiresAt = expiresAt;
|
|
124
|
-
} else {
|
|
125
|
-
warnings.push(
|
|
126
|
-
`Ignored expiresAt "${String(
|
|
127
|
-
payload["expiresAt"],
|
|
128
|
-
)}" from the license server: it is not a date.`,
|
|
129
|
-
);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
if (this.isPresent(payload, "isEvaluationLicense")) {
|
|
134
|
-
const rawIsEvaluation: unknown = payload["isEvaluationLicense"];
|
|
135
|
-
|
|
136
|
-
if (typeof rawIsEvaluation === "boolean") {
|
|
137
|
-
updateData.enterpriseLicenseIsEvaluation = rawIsEvaluation;
|
|
138
|
-
} else {
|
|
139
|
-
warnings.push(
|
|
140
|
-
`Ignored isEvaluationLicense "${String(
|
|
141
|
-
rawIsEvaluation,
|
|
142
|
-
)}" from the license server: it is not a boolean.`,
|
|
143
|
-
);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
if (this.isPresent(payload, "companyName")) {
|
|
148
|
-
const companyName: string = this.parseNonEmptyString(
|
|
149
|
-
payload["companyName"],
|
|
150
|
-
);
|
|
151
|
-
|
|
152
|
-
/*
|
|
153
|
-
* An empty company name is what the server sends for a license with none
|
|
154
|
-
* set, and overwriting a good name with "" would be a visible regression
|
|
155
|
-
* in the modal. Only a real name is worth writing.
|
|
156
|
-
*/
|
|
157
|
-
if (companyName) {
|
|
158
|
-
updateData.enterpriseCompanyName = companyName;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/*
|
|
163
|
-
* The token is opaque here - it is signed with the license server's secret
|
|
164
|
-
* and this side only checks that it exists. It is never cleared: a license
|
|
165
|
-
* that has expired is legitimately issued no token, and clearing it on the
|
|
166
|
-
* way past would compound an expiry the customer may be about to renew.
|
|
167
|
-
*/
|
|
168
|
-
if (this.isPresent(payload, "token")) {
|
|
169
|
-
const token: string = this.parseNonEmptyString(payload["token"]);
|
|
170
|
-
|
|
171
|
-
if (token) {
|
|
172
|
-
updateData.enterpriseLicenseToken = token;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
if (this.isPresent(payload, "instances")) {
|
|
177
|
-
const rawInstances: unknown = payload["instances"];
|
|
178
|
-
|
|
179
|
-
if (Array.isArray(rawInstances)) {
|
|
180
|
-
updateData.enterpriseLicenseInstances =
|
|
181
|
-
rawInstances as Array<EnterpriseLicenseInstanceSummary>;
|
|
182
|
-
} else {
|
|
183
|
-
warnings.push(
|
|
184
|
-
"Ignored the instance list from the license server: it is not an array.",
|
|
185
|
-
);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
return {
|
|
190
|
-
updateData: updateData,
|
|
191
|
-
warnings: warnings,
|
|
192
|
-
};
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
/*
|
|
196
|
-
* Present means the key is on the object, even when it carries null or
|
|
197
|
-
* undefined. `"x" in payload` rather than a truthiness or undefined check,
|
|
198
|
-
* because "the server said null" and "the server said nothing" have to stay
|
|
199
|
-
* distinguishable all the way down.
|
|
200
|
-
*/
|
|
201
|
-
private static isPresent(payload: JSONObject, key: string): boolean {
|
|
202
|
-
if (!Object.prototype.hasOwnProperty.call(payload, key)) {
|
|
203
|
-
return false;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// An explicit undefined is indistinguishable from silence. Treat it as one.
|
|
207
|
-
return payload[key] !== undefined;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
private static isNonNegativeInteger(value: unknown): boolean {
|
|
211
|
-
return (
|
|
212
|
-
typeof value === "number" &&
|
|
213
|
-
Number.isFinite(value) &&
|
|
214
|
-
Number.isInteger(value) &&
|
|
215
|
-
value >= 0
|
|
216
|
-
);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
private static parseNonEmptyString(value: unknown): string {
|
|
220
|
-
if (typeof value !== "string") {
|
|
221
|
-
return "";
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
return value.trim();
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
private static parseDate(value: unknown): Date | null {
|
|
228
|
-
if (value instanceof Date) {
|
|
229
|
-
return Number.isNaN(value.getTime()) ? null : value;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
if (typeof value !== "string" || !value.trim()) {
|
|
233
|
-
return null;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
const parsed: Date = new Date(value.trim());
|
|
237
|
-
|
|
238
|
-
if (Number.isNaN(parsed.getTime())) {
|
|
239
|
-
return null;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
return parsed;
|
|
243
|
-
}
|
|
244
|
-
}
|