@oneuptime/common 12.0.12 → 12.0.14
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/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.ts +32 -5
- package/Models/DatabaseModels/NetworkDevice.ts +64 -0
- package/Models/DatabaseModels/OnCallDutyPolicySchedule.ts +14 -0
- package/Models/DatabaseModels/StatusPage.ts +59 -0
- package/Models/DatabaseModels/StatusPageOidc.ts +2 -0
- package/Models/DatabaseModels/UserCall.ts +94 -3
- package/Models/DatabaseModels/UserEmail.ts +94 -3
- package/Models/DatabaseModels/UserIncomingCallNumber.ts +94 -3
- package/Models/DatabaseModels/UserPush.ts +37 -0
- package/Models/DatabaseModels/UserSMS.ts +94 -3
- package/Models/DatabaseModels/UserWhatsApp.ts +93 -2
- package/Models/DatabaseModels/WorkspaceProjectAuthToken.ts +19 -2
- package/Server/API/AIChatAPI.ts +55 -56
- package/Server/API/BaseAPI.ts +79 -14
- package/Server/API/CommonAPI.ts +89 -0
- package/Server/API/MicrosoftTeamsAPI.ts +20 -9
- package/Server/API/SlackAPI.ts +13 -10
- package/Server/API/StatusPageAPI.ts +2197 -2128
- package/Server/API/TelemetryAPI.ts +72 -3
- package/Server/API/UserCallAPI.ts +53 -45
- package/Server/API/UserEmailAPI.ts +53 -44
- package/Server/API/UserIncomingCallNumberAPI.ts +48 -38
- package/Server/API/UserNotificationMethodAdminAPI.ts +481 -0
- package/Server/API/UserPushAPI.ts +126 -2
- package/Server/API/UserSmsAPI.ts +53 -44
- package/Server/API/UserWhatsAppAPI.ts +53 -50
- package/Server/Infrastructure/Postgres/SchemaMigrations/1787142779538-MigrationName.ts +154 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1787156982416-MigrationName.ts +17 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1787500000000-AddEnableSearchEngineIndexingToStatusPage.ts +30 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1787600000000-AddNetworkDeviceReachabilityColumns.ts +47 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1787700000000-FixTotpOtpUrlAlgorithm.ts +45 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +10 -0
- package/Server/Middleware/UserAuthorization.ts +11 -2
- package/Server/Middleware/VerificationCodeRateLimit.ts +586 -0
- package/Server/Services/AnalyticsDatabaseService.ts +169 -0
- package/Server/Services/ApiKeyPermissionService.ts +116 -2
- package/Server/Services/DatabaseService.ts +118 -6
- package/Server/Services/LogAggregationService.ts +39 -0
- package/Server/Services/LogService.ts +21 -0
- package/Server/Services/NetworkSiteService.ts +12 -0
- package/Server/Services/PushNotificationService.ts +127 -12
- package/Server/Services/SpanService.ts +21 -0
- package/Server/Services/TeamMemberService.ts +53 -13
- package/Server/Services/TraceAggregationService.ts +15 -0
- package/Server/Services/UserCallService.ts +55 -24
- package/Server/Services/UserEmailService.ts +83 -17
- package/Server/Services/UserIncomingCallNumberService.ts +49 -85
- package/Server/Services/UserNotificationMethodAdminService.ts +1527 -0
- package/Server/Services/UserNotificationRuleService.ts +26 -0
- package/Server/Services/UserPushService.ts +89 -0
- package/Server/Services/UserSmsService.ts +50 -17
- package/Server/Services/UserWhatsAppService.ts +48 -15
- package/Server/Services/WorkspaceNotificationRuleService.ts +172 -220
- package/Server/Types/AnalyticsDatabase/ModelPermission.ts +9 -0
- package/Server/Types/Database/Permissions/AccessControlPermission.ts +47 -16
- package/Server/Types/Database/QueryHelper.ts +30 -0
- package/Server/Utils/APIKey/AccessPermission.ts +16 -40
- package/Server/Utils/AnalyticsDatabase/QuerySettingsHelper.ts +59 -0
- package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +144 -0
- package/Server/Utils/ChannelVerification.ts +510 -0
- package/Server/Utils/LogRedaction.ts +576 -0
- package/Server/Utils/Logger.ts +123 -46
- package/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.ts +13 -16
- package/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.ts +94 -23
- package/Server/Utils/Monitor/MonitorAlert.ts +24 -21
- package/Server/Utils/Monitor/MonitorIncident.ts +21 -18
- package/Server/Utils/Monitor/MonitorResource.ts +29 -9
- package/Server/Utils/Monitor/MonitorResourceContext.ts +107 -0
- package/Server/Utils/Monitor/MonitorStepResourceIdentity.ts +442 -0
- package/Server/Utils/Monitor/NetworkInventoryUtil.ts +28 -7
- package/Server/Utils/Monitor/SeriesResourceLabels.ts +3 -3
- package/Server/Utils/Monitor/SeriesResourceLinker.ts +96 -28
- package/Server/Utils/SessionReplay/SessionReplayGateCacheStore.ts +56 -10
- package/Server/Utils/StartServer.ts +30 -9
- package/Server/Utils/StatusPageSearchEngineIndexing.ts +33 -0
- package/Server/Utils/Telemetry/ResourceEntityFilter.ts +441 -0
- package/Server/Utils/TotpAuth.ts +137 -9
- package/Server/Utils/UserRegistrationToken.ts +182 -0
- package/Server/Utils/VerificationCode.ts +134 -0
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +488 -46
- package/Tests/App/Dashboard/AdminNotificationRulesPage.test.tsx +173 -94
- package/Tests/App/Dashboard/AdminUserNotificationMethodsPage.test.tsx +1151 -0
- package/Tests/App/Dashboard/AdminUserOnCallPages.test.tsx +905 -0
- package/Tests/App/Dashboard/DashboardCommandPalette.test.tsx +338 -0
- package/Tests/App/Dashboard/InvestigationPanel.test.tsx +1 -1
- package/Tests/App/Dashboard/MonitorTypePicker.test.tsx +328 -0
- package/Tests/App/StatusPage/StatusPageIndexPageRobotsMeta.test.ts +130 -0
- package/Tests/Models/DatabaseModels/DatabaseBaseModelToJSONObjectCache.test.ts +180 -0
- package/Tests/Models/StatusPageEnableSearchEngineIndexing.test.ts +157 -0
- package/Tests/Models/UserPushCriticalAlertColumn.test.ts +172 -0
- package/Tests/Server/API/AIChatCancelAndFeedback.test.ts +23 -1
- package/Tests/Server/API/AIChatRouteAuthorization.test.ts +785 -0
- package/Tests/Server/API/BaseAPIApiKeyAuth.test.ts +21 -8
- package/Tests/Server/API/BaseAPIGetListParallel.test.ts +519 -0
- package/Tests/Server/API/CommonAPIAuthGuard.test.ts +290 -0
- package/Tests/Server/API/MicrosoftTeamsManifest.test.ts +7 -1
- package/Tests/Server/API/NotificationChannelVerificationAPI.test.ts +543 -0
- package/Tests/Server/API/StatusPageOverviewCache.test.ts +474 -0
- package/Tests/Server/API/StatusPageSeoSearchEngineIndexing.test.ts +189 -0
- package/Tests/Server/API/UserIncomingCallNumberApi.test.ts +108 -18
- package/Tests/Server/API/UserNotificationMethodAdminAPI.test.ts +963 -0
- package/Tests/Server/API/UserPushCriticalAlertsApi.test.ts +114 -0
- package/Tests/Server/API/UserSmsApi.test.ts +107 -14
- package/Tests/Server/API/UserTotpAuthAPI.test.ts +427 -0
- package/Tests/Server/Infrastructure/InMemoryTTLCache.test.ts +158 -0
- package/Tests/Server/Infrastructure/Postgres/DeviceRoleAndDeclaredLinkParentMigration.test.ts +9 -60
- package/Tests/Server/Infrastructure/Postgres/FixTotpOtpUrlAlgorithmMigration.test.ts +315 -0
- package/Tests/Server/Middleware/ProjectAuthorizationApiKeyMiddleware.test.ts +24 -15
- package/Tests/Server/Middleware/UserAuthorization.test.ts +79 -0
- package/Tests/Server/Middleware/VerificationCodeRateLimit.test.ts +775 -0
- package/Tests/Server/Services/AddNetworkDeviceReachabilityColumnsMigration.test.ts +280 -0
- package/Tests/Server/Services/AnalyticsDatabasePaginationStability.test.ts +33 -13
- package/Tests/Server/Services/AnalyticsDatabaseSortKeyBoundary.test.ts +658 -0
- package/Tests/Server/Services/ApiKeyPermissionService.test.ts +347 -0
- package/Tests/Server/Services/CriticalOnCallAlertDelivery.test.ts +458 -0
- package/Tests/Server/Services/CriticalPushAlertPayload.test.ts +301 -0
- package/Tests/Server/Services/DatabaseServiceAtomicIncrement.test.ts +143 -0
- package/Tests/Server/Services/DatabaseServiceUpdateDebugLogging.test.ts +282 -0
- package/Tests/Server/Services/DeliverNotificationForRuleExtraction.test.ts +1 -0
- package/Tests/Server/Services/LogAggregationScanMemory.test.ts +421 -0
- package/Tests/Server/Services/LogAggregationService.test.ts +2 -2
- package/Tests/Server/Services/NetworkSiteService.test.ts +56 -2
- package/Tests/Server/Services/NotificationChannelCodeIssuance.test.ts +401 -0
- package/Tests/Server/Services/PushNotificationDeliveryOptions.test.ts +204 -0
- package/Tests/Server/Services/TeamMemberAutoAcceptInvitation.test.ts +21 -1
- package/Tests/Server/Services/TeamMemberInviteRegistrationToken.test.ts +290 -0
- package/Tests/Server/Services/TelemetryResourceFacetFilters.test.ts +267 -0
- package/Tests/Server/Services/UserNotificationMethodAdminService.test.ts +948 -0
- package/Tests/Server/Services/UserNotificationRuleExecuteItem.test.ts +1 -0
- package/Tests/Server/Services/UserPushCriticalAlertToggle.test.ts +255 -0
- package/Tests/Server/Services/UserTotpAuthEnrolment.test.ts +218 -0
- package/Tests/Server/Services/WorkspaceNotificationRuleTestRuleChannels.test.ts +702 -0
- package/Tests/Server/TestingUtils/AuthenticatorApp.ts +248 -0
- package/Tests/Server/Types/Database/Permissions/AccessControlPermission.test.ts +165 -0
- package/Tests/Server/Types/Database/Permissions/NotificationChannelVerificationColumns.test.ts +135 -0
- package/Tests/Server/Types/Database/Permissions/OnCallScheduleRelationSelect.test.ts +504 -0
- package/Tests/Server/Types/Database/QueryHelperFindWithSameTextAnyOf.test.ts +91 -0
- package/Tests/Server/Types/Workflow/Components/JsonToText.test.ts +384 -0
- package/Tests/Server/Types/Workflow/Components/MergeJson.test.ts +403 -0
- package/Tests/Server/Utils/APIKey/AccessPermission.test.ts +48 -36
- package/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.ts +213 -0
- package/Tests/Server/Utils/Browser.test.ts +162 -0
- package/Tests/Server/Utils/ChannelVerification.test.ts +689 -0
- package/Tests/Server/Utils/Express.test.ts +371 -0
- package/Tests/Server/Utils/LogRedaction.test.ts +415 -0
- package/Tests/Server/Utils/LoggerCredentialLeak.test.ts +245 -0
- package/Tests/Server/Utils/Monitor/Criteria/CustomCodeMonitorCriteria.test.ts +707 -0
- package/Tests/Server/Utils/Monitor/Criteria/DnsMonitorCriteria.test.ts +698 -0
- package/Tests/Server/Utils/Monitor/Criteria/IncomingEmailBodyCriteria.test.ts +243 -0
- package/Tests/Server/Utils/Monitor/Criteria/IncomingRequestBodyCriteria.test.ts +278 -0
- package/Tests/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.test.ts +374 -4
- package/Tests/Server/Utils/Monitor/MonitorAlertResourceLinking.test.ts +160 -20
- package/Tests/Server/Utils/Monitor/MonitorDependencySuppressionCreatorSkip.test.ts +13 -8
- package/Tests/Server/Utils/Monitor/MonitorIncidentResourceLinking.test.ts +162 -18
- package/Tests/Server/Utils/Monitor/MonitorResourceContext.test.ts +349 -0
- package/Tests/Server/Utils/Monitor/MonitorResourceIngestedStepSelection.test.ts +455 -0
- package/Tests/Server/Utils/Monitor/MonitorStepResourceIdentity.test.ts +690 -0
- package/Tests/Server/Utils/Monitor/MonitorSummaryPersistence.test.ts +7 -2
- package/Tests/Server/Utils/Monitor/NetworkDeviceReachabilityRoundTrip.test.ts +369 -0
- package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +86 -8
- package/Tests/Server/Utils/Monitor/SeriesResourceLinker.test.ts +92 -18
- package/Tests/Server/Utils/PrivacyFilterUtil.test.ts +64 -0
- package/Tests/Server/Utils/PushNotificationUtilCreators.test.ts +267 -0
- package/Tests/Server/Utils/SessionReplay/SessionReplayGateCacheStore.test.ts +207 -0
- package/Tests/Server/Utils/StartServerBodyVerify.test.ts +335 -0
- package/Tests/Server/Utils/StatusPageSearchEngineIndexing.test.ts +60 -0
- package/Tests/Server/Utils/Telemetry/OneuptimeLabel.test.ts +439 -0
- package/Tests/Server/Utils/Telemetry/ResourceEntityFilter.test.ts +435 -0
- package/Tests/Server/Utils/TotpAuth.test.ts +719 -0
- package/Tests/Server/Utils/UserRegistrationToken.test.ts +322 -0
- package/Tests/Server/Utils/VerificationCode.test.ts +296 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsChannelSend.test.ts +607 -62
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsInstalledTeamIdSpace.test.ts +778 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsTeamInstalls.test.ts +44 -10
- package/Tests/Types/API/HostnameFromAuthority.test.ts +164 -0
- package/Tests/Types/AutoRemediation/AutoRemediationSuggestionStatus.test.ts +192 -0
- package/Tests/Types/Call/CallRequest.test.ts +189 -0
- package/Tests/Types/Dashboard/DashboardSize.test.ts +226 -0
- package/Tests/Types/Database/AccessControl/ColumnAccessControlCache.test.ts +344 -0
- package/Tests/Types/Database/DatabasePropertyFindOperator.test.ts +518 -0
- package/Tests/Types/Database/TableColumnMetadataCache.test.ts +286 -0
- package/Tests/Types/Incident/IncidentSlaStatus.test.ts +191 -0
- package/Tests/Types/Metrics/MetricDashboardMetricType.test.ts +278 -0
- package/Tests/Types/Metrics/MetricPipelineRuleType.test.ts +517 -0
- package/Tests/Types/Monitor/IncomingMonitorDefaultCriteria.test.ts +470 -0
- package/Tests/Types/Monitor/MonitorCriteriaInstance.test.ts +6 -4
- package/Tests/Types/Monitor/MonitorStep.test.ts +100 -0
- package/Tests/Types/Monitor/MonitorTypeKeywords.test.ts +360 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCatalog.test.ts +262 -5
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCoverage.test.ts +1 -1
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +1 -1
- package/Tests/Types/Monitor/ServiceAlertTemplates.test.ts +905 -0
- package/Tests/Types/Service/ServiceLanguage.test.ts +255 -0
- package/Tests/Types/StatusPage/SearchEngineIndexing.test.ts +86 -0
- package/Tests/Types/Telemetry/ResourceEntityFacet.test.ts +254 -0
- package/Tests/Types/TextRandomGeneration.test.ts +211 -0
- package/Tests/UI/Components/Button.test.tsx +175 -1
- package/Tests/UI/Components/CardSelect.test.tsx +1021 -0
- package/Tests/UI/Components/CodeBlockLanguages.test.tsx +236 -0
- package/Tests/UI/Components/CommandPalette/CommandPalette.test.tsx +568 -0
- package/Tests/UI/Components/CommandPalette/CommandPaletteKeyboard.test.tsx +239 -0
- package/Tests/UI/Components/CommandPalette/CommandPaletteProviders.test.tsx +400 -0
- package/Tests/UI/Components/CommandPalette/PaletteFilter.test.ts +234 -0
- package/Tests/UI/Components/CommandPalette/RecentCommands.test.ts +97 -0
- package/Tests/UI/Components/CountModelSideMenuItemGuard.test.tsx +198 -0
- package/Tests/UI/Components/FeedItemSafeMode.test.tsx +1 -1
- package/Tests/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.test.ts +267 -0
- package/Tests/UI/Components/List.test.tsx +9 -2
- package/Tests/UI/Components/ListLoadingStates.test.tsx +173 -0
- package/Tests/UI/Components/MarkdownLazy.test.tsx +113 -0
- package/Tests/UI/Components/MarkdownMermaidRetry.test.tsx +110 -0
- package/Tests/UI/Components/MasterPage.test.tsx +36 -1
- package/Tests/UI/Components/ModelTable/useCustomFieldColumns.test.tsx +8 -0
- package/Tests/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.test.ts +692 -0
- package/Tests/UI/Components/MoreMenuMotion.test.tsx +118 -0
- package/Tests/UI/Components/NavBarCommandKGating.test.tsx +178 -0
- package/Tests/UI/Components/OrderedStatesList.test.tsx +19 -2
- package/Tests/UI/Components/SideOverMotion.test.tsx +109 -0
- package/Tests/UI/Components/Skeleton.test.tsx +71 -0
- package/Tests/UI/Components/TableLoadingStates.test.tsx +279 -0
- package/Tests/UI/Components/Tabs.test.tsx +24 -0
- package/Tests/UI/Components/Toast.test.tsx +130 -7
- package/Tests/UI/Components/ToastStacking.test.tsx +198 -0
- package/Tests/UI/Utils/Dropdown.test.ts +423 -0
- package/Tests/UI/Utils/ModelAPITenantHeader.test.ts +122 -0
- package/Tests/UI/Utils/ModelListCache.test.ts +338 -0
- package/Tests/UI/Utils/ProjectListCacheInvalidation.test.ts +225 -0
- package/Tests/Utils/API.test.ts +16 -2
- package/Tests/Utils/Dashboard/Components/DashboardKubernetesResourceListShared.test.ts +347 -0
- package/Tests/Utils/Dashboard/Components/DashboardListSharedArgs.test.ts +259 -0
- package/Tests/Utils/Dashboard/Components/DashboardMonitorListComponent.test.ts +466 -0
- package/Tests/Utils/Monitor/MonitorMetricType.test.ts +66 -1
- package/Tests/Utils/Monitor/NetworkTopologyUtil.test.ts +115 -6
- package/Tests/Utils/NetworkDevice/DeviceReachabilityUtil.test.ts +610 -0
- package/Tests/Utils/NetworkSite/SiteStatusRollupUtil.test.ts +114 -45
- package/Tests/Utils/Rum/UrlScrubberSegments.test.ts +362 -0
- package/Types/API/Hostname.ts +79 -0
- package/Types/Database/AccessControl/ColumnAccessControl.ts +33 -11
- package/Types/Database/AccessControl/ColumnBillingAccessControl.ts +33 -11
- package/Types/Database/DatabaseProperty.ts +38 -0
- package/Types/Database/TableColumn.ts +34 -7
- package/Types/Email/EmailTemplateType.ts +1 -0
- package/Types/Events/Recurring.ts +16 -1
- package/Types/Monitor/MonitorCriteriaInstance.ts +41 -20
- package/Types/Monitor/MonitorStep.ts +13 -1
- package/Types/Monitor/MonitorType.ts +345 -40
- package/Types/Monitor/Recommendation/MonitorRecommendationCatalog.ts +131 -8
- package/Types/Monitor/Recommendation/MonitorRecommendationTypes.ts +48 -8
- package/Types/Monitor/SSLMonitor/SslMonitorResponse.ts +43 -0
- package/Types/Monitor/ServiceAlertTemplates.ts +1352 -0
- package/Types/Permission.ts +35 -0
- package/Types/PushNotification/AndroidNotificationChannel.ts +26 -0
- package/Types/PushNotification/PushNotificationMessage.ts +15 -0
- package/Types/PushNotification/PushNotificationRequest.ts +8 -16
- package/Types/Service/ServiceLanguage.ts +144 -0
- package/Types/StatusPage/SearchEngineIndexing.ts +61 -0
- package/Types/Telemetry/ResourceEntityFacet.ts +211 -0
- package/Types/Text.ts +111 -19
- package/UI/Components/Button/Button.tsx +27 -14
- package/UI/Components/CardSelect/CardSelect.tsx +714 -105
- package/UI/Components/CodeBlock/CodeBlock.tsx +54 -7
- package/UI/Components/CodeBlock/LanguageRegistry.ts +103 -0
- package/UI/Components/CommandPalette/CommandPalette.tsx +790 -0
- package/UI/Components/CommandPalette/PaletteFilter.ts +196 -0
- package/UI/Components/CommandPalette/PaletteRow.tsx +173 -0
- package/UI/Components/CommandPalette/RecentCommands.ts +57 -0
- package/UI/Components/CommandPalette/Types.ts +49 -0
- package/UI/Components/CommandPalette/UseProviderSearch.ts +129 -0
- package/UI/Components/Dropdown/Dropdown.tsx +6 -1
- package/UI/Components/EmptyState/EmptyState.tsx +8 -1
- package/UI/Components/Feed/FeedItem.tsx +1 -1
- package/UI/Components/Footer/Footer.tsx +32 -6
- package/UI/Components/Forms/Fields/FormField.tsx +3 -0
- package/UI/Components/Forms/Types/Field.ts +8 -0
- package/UI/Components/List/List.tsx +37 -5
- package/UI/Components/List/ListSkeleton.tsx +54 -0
- package/UI/Components/Loader/PageLoader.tsx +29 -8
- package/UI/Components/LogsViewer/components/LogsAnalyticsView.tsx +26 -4
- package/UI/Components/Markdown.tsx/LazyMarkdownViewer.tsx +23 -2
- package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +71 -26
- package/UI/Components/MasterPage/MasterPage.tsx +24 -11
- package/UI/Components/Modal/Modal.tsx +2 -2
- package/UI/Components/ModelTable/BaseModelTable.tsx +1 -1
- package/UI/Components/ModelTable/useCustomFieldColumns.ts +11 -5
- package/UI/Components/MoreMenu/MoreMenu.tsx +39 -1
- package/UI/Components/Navbar/NavBar.tsx +14 -1
- package/UI/Components/OrderedStatesList/OrderedStatesList.tsx +50 -5
- package/UI/Components/SideMenu/CountModelSideMenuItem.tsx +40 -1
- package/UI/Components/SideOver/SideOver.tsx +37 -2
- package/UI/Components/Skeleton/Skeleton.tsx +53 -0
- package/UI/Components/Table/Table.tsx +74 -44
- package/UI/Components/Table/TableSkeletonRows.tsx +141 -0
- package/UI/Components/Tabs/Tab.tsx +1 -1
- package/UI/Components/Toast/Toast.tsx +118 -53
- package/UI/Components/Toast/ToastInit.tsx +82 -32
- package/UI/Styles/Theme.css +40 -0
- package/UI/Utils/ModelAPI/ModelAPI.ts +20 -10
- package/UI/Utils/ModelListCache.ts +188 -0
- package/UI/Utils/Project.ts +29 -0
- package/Utils/API.ts +6 -1
- package/Utils/Monitor/MonitorMetricType.ts +16 -1
- package/Utils/Monitor/NetworkTopologyUtil.ts +60 -8
- package/Utils/NetworkDevice/DeviceReachabilityUtil.ts +262 -0
- package/Utils/NetworkSite/SiteStatusRollupUtil.ts +41 -24
- package/Utils/Telemetry/CrossSignalScope.ts +75 -4
- package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js +20 -4
- package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDevice.js +66 -0
- package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js +14 -0
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPage.js +60 -0
- package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageOidc.js +2 -0
- package/build/dist/Models/DatabaseModels/StatusPageOidc.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserCall.js +101 -3
- package/build/dist/Models/DatabaseModels/UserCall.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserEmail.js +101 -3
- package/build/dist/Models/DatabaseModels/UserEmail.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserIncomingCallNumber.js +101 -3
- package/build/dist/Models/DatabaseModels/UserIncomingCallNumber.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserPush.js +38 -0
- package/build/dist/Models/DatabaseModels/UserPush.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserSMS.js +101 -3
- package/build/dist/Models/DatabaseModels/UserSMS.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserWhatsApp.js +100 -2
- package/build/dist/Models/DatabaseModels/UserWhatsApp.js.map +1 -1
- package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
- package/build/dist/Server/API/AIChatAPI.js +48 -35
- package/build/dist/Server/API/AIChatAPI.js.map +1 -1
- package/build/dist/Server/API/BaseAPI.js +69 -13
- package/build/dist/Server/API/BaseAPI.js.map +1 -1
- package/build/dist/Server/API/CommonAPI.js +59 -0
- package/build/dist/Server/API/CommonAPI.js.map +1 -1
- package/build/dist/Server/API/MicrosoftTeamsAPI.js +20 -6
- package/build/dist/Server/API/MicrosoftTeamsAPI.js.map +1 -1
- package/build/dist/Server/API/SlackAPI.js +13 -10
- package/build/dist/Server/API/SlackAPI.js.map +1 -1
- package/build/dist/Server/API/StatusPageAPI.js +745 -673
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/API/TelemetryAPI.js +34 -3
- package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
- package/build/dist/Server/API/UserCallAPI.js +42 -38
- package/build/dist/Server/API/UserCallAPI.js.map +1 -1
- package/build/dist/Server/API/UserEmailAPI.js +42 -38
- package/build/dist/Server/API/UserEmailAPI.js.map +1 -1
- package/build/dist/Server/API/UserIncomingCallNumberAPI.js +37 -32
- package/build/dist/Server/API/UserIncomingCallNumberAPI.js.map +1 -1
- package/build/dist/Server/API/UserNotificationMethodAdminAPI.js +341 -0
- package/build/dist/Server/API/UserNotificationMethodAdminAPI.js.map +1 -0
- package/build/dist/Server/API/UserPushAPI.js +95 -2
- package/build/dist/Server/API/UserPushAPI.js.map +1 -1
- package/build/dist/Server/API/UserSmsAPI.js +42 -38
- package/build/dist/Server/API/UserSmsAPI.js.map +1 -1
- package/build/dist/Server/API/UserWhatsAppAPI.js +42 -40
- package/build/dist/Server/API/UserWhatsAppAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787142779538-MigrationName.js +89 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787142779538-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787156982416-MigrationName.js +12 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787156982416-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787500000000-AddEnableSearchEngineIndexingToStatusPage.js +23 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787500000000-AddEnableSearchEngineIndexingToStatusPage.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787600000000-AddNetworkDeviceReachabilityColumns.js +34 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787600000000-AddNetworkDeviceReachabilityColumns.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787700000000-FixTotpOtpUrlAlgorithm.js +40 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787700000000-FixTotpOtpUrlAlgorithm.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +10 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Middleware/UserAuthorization.js +6 -2
- package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
- package/build/dist/Server/Middleware/VerificationCodeRateLimit.js +393 -0
- package/build/dist/Server/Middleware/VerificationCodeRateLimit.js.map +1 -0
- package/build/dist/Server/Services/AnalyticsDatabaseService.js +136 -0
- package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
- package/build/dist/Server/Services/ApiKeyPermissionService.js +90 -1
- package/build/dist/Server/Services/ApiKeyPermissionService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +89 -6
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/LogAggregationService.js +7 -0
- package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
- package/build/dist/Server/Services/LogService.js +16 -0
- package/build/dist/Server/Services/LogService.js.map +1 -1
- package/build/dist/Server/Services/NetworkSiteService.js +12 -0
- package/build/dist/Server/Services/NetworkSiteService.js.map +1 -1
- package/build/dist/Server/Services/PushNotificationService.js +69 -30
- package/build/dist/Server/Services/PushNotificationService.js.map +1 -1
- package/build/dist/Server/Services/SpanService.js +16 -0
- package/build/dist/Server/Services/SpanService.js.map +1 -1
- package/build/dist/Server/Services/TeamMemberService.js +43 -7
- package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
- package/build/dist/Server/Services/TraceAggregationService.js +2 -0
- package/build/dist/Server/Services/TraceAggregationService.js.map +1 -1
- package/build/dist/Server/Services/UserCallService.js +54 -22
- package/build/dist/Server/Services/UserCallService.js.map +1 -1
- package/build/dist/Server/Services/UserEmailService.js +78 -17
- package/build/dist/Server/Services/UserEmailService.js.map +1 -1
- package/build/dist/Server/Services/UserIncomingCallNumberService.js +45 -74
- package/build/dist/Server/Services/UserIncomingCallNumberService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationMethodAdminService.js +1117 -0
- package/build/dist/Server/Services/UserNotificationMethodAdminService.js.map +1 -0
- package/build/dist/Server/Services/UserNotificationRuleService.js +20 -0
- package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Services/UserPushService.js +77 -0
- package/build/dist/Server/Services/UserPushService.js.map +1 -1
- package/build/dist/Server/Services/UserSmsService.js +50 -17
- package/build/dist/Server/Services/UserSmsService.js.map +1 -1
- package/build/dist/Server/Services/UserWhatsAppService.js +48 -15
- package/build/dist/Server/Services/UserWhatsAppService.js.map +1 -1
- package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +137 -164
- package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js +9 -0
- package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/AccessControlPermission.js +21 -13
- package/build/dist/Server/Types/Database/Permissions/AccessControlPermission.js.map +1 -1
- package/build/dist/Server/Types/Database/QueryHelper.js +27 -0
- package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
- package/build/dist/Server/Utils/APIKey/AccessPermission.js +9 -32
- package/build/dist/Server/Utils/APIKey/AccessPermission.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/QuerySettingsHelper.js +46 -0
- package/build/dist/Server/Utils/AnalyticsDatabase/QuerySettingsHelper.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +87 -0
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
- package/build/dist/Server/Utils/ChannelVerification.js +348 -0
- package/build/dist/Server/Utils/ChannelVerification.js.map +1 -0
- package/build/dist/Server/Utils/LogRedaction.js +449 -0
- package/build/dist/Server/Utils/LogRedaction.js.map +1 -0
- package/build/dist/Server/Utils/Logger.js +98 -45
- package/build/dist/Server/Utils/Logger.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.js +13 -12
- package/build/dist/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.js +65 -13
- package/build/dist/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js +20 -17
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js +17 -14
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorResource.js +20 -3
- package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorResourceContext.js +95 -0
- package/build/dist/Server/Utils/Monitor/MonitorResourceContext.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorStepResourceIdentity.js +313 -0
- package/build/dist/Server/Utils/Monitor/MonitorStepResourceIdentity.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +27 -7
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +3 -3
- package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js +67 -26
- package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js.map +1 -1
- package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCacheStore.js +29 -10
- package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCacheStore.js.map +1 -1
- package/build/dist/Server/Utils/StartServer.js +10 -7
- package/build/dist/Server/Utils/StartServer.js.map +1 -1
- package/build/dist/Server/Utils/StatusPageSearchEngineIndexing.js +24 -0
- package/build/dist/Server/Utils/StatusPageSearchEngineIndexing.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js +311 -0
- package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js.map +1 -0
- package/build/dist/Server/Utils/TotpAuth.js +127 -8
- package/build/dist/Server/Utils/TotpAuth.js.map +1 -1
- package/build/dist/Server/Utils/UserRegistrationToken.js +170 -0
- package/build/dist/Server/Utils/UserRegistrationToken.js.map +1 -0
- package/build/dist/Server/Utils/VerificationCode.js +120 -0
- package/build/dist/Server/Utils/VerificationCode.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +366 -37
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
- package/build/dist/Types/API/Hostname.js +63 -0
- package/build/dist/Types/API/Hostname.js.map +1 -1
- package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js +20 -6
- package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js.map +1 -1
- package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js +20 -6
- package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js.map +1 -1
- package/build/dist/Types/Database/DatabaseProperty.js +38 -0
- package/build/dist/Types/Database/DatabaseProperty.js.map +1 -1
- package/build/dist/Types/Database/TableColumn.js +24 -6
- package/build/dist/Types/Database/TableColumn.js.map +1 -1
- package/build/dist/Types/Email/EmailTemplateType.js +1 -0
- package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
- package/build/dist/Types/Events/Recurring.js +13 -1
- package/build/dist/Types/Events/Recurring.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +42 -21
- package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStep.js +9 -1
- package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorType.js +330 -31
- package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js +77 -5
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js +18 -6
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js.map +1 -1
- package/build/dist/Types/Monitor/ServiceAlertTemplates.js +1028 -0
- package/build/dist/Types/Monitor/ServiceAlertTemplates.js.map +1 -0
- package/build/dist/Types/Permission.js +33 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/PushNotification/AndroidNotificationChannel.js +27 -0
- package/build/dist/Types/PushNotification/AndroidNotificationChannel.js.map +1 -0
- package/build/dist/Types/Service/ServiceLanguage.js +96 -0
- package/build/dist/Types/Service/ServiceLanguage.js.map +1 -0
- package/build/dist/Types/StatusPage/SearchEngineIndexing.js +55 -0
- package/build/dist/Types/StatusPage/SearchEngineIndexing.js.map +1 -0
- package/build/dist/Types/Telemetry/ResourceEntityFacet.js +156 -0
- package/build/dist/Types/Telemetry/ResourceEntityFacet.js.map +1 -0
- package/build/dist/Types/Text.js +82 -17
- package/build/dist/Types/Text.js.map +1 -1
- package/build/dist/UI/Components/Button/Button.js +22 -14
- package/build/dist/UI/Components/Button/Button.js.map +1 -1
- package/build/dist/UI/Components/CardSelect/CardSelect.js +360 -40
- package/build/dist/UI/Components/CardSelect/CardSelect.js.map +1 -1
- package/build/dist/UI/Components/CodeBlock/CodeBlock.js +35 -3
- package/build/dist/UI/Components/CodeBlock/CodeBlock.js.map +1 -1
- package/build/dist/UI/Components/CodeBlock/LanguageRegistry.js +57 -0
- package/build/dist/UI/Components/CodeBlock/LanguageRegistry.js.map +1 -0
- package/build/dist/UI/Components/CommandPalette/CommandPalette.js +439 -0
- package/build/dist/UI/Components/CommandPalette/CommandPalette.js.map +1 -0
- package/build/dist/UI/Components/CommandPalette/PaletteFilter.js +135 -0
- package/build/dist/UI/Components/CommandPalette/PaletteFilter.js.map +1 -0
- package/build/dist/UI/Components/CommandPalette/PaletteRow.js +83 -0
- package/build/dist/UI/Components/CommandPalette/PaletteRow.js.map +1 -0
- package/build/dist/UI/Components/CommandPalette/RecentCommands.js +47 -0
- package/build/dist/UI/Components/CommandPalette/RecentCommands.js.map +1 -0
- package/build/dist/UI/Components/CommandPalette/Types.js +2 -0
- package/build/dist/UI/Components/CommandPalette/Types.js.map +1 -0
- package/build/dist/UI/Components/CommandPalette/UseProviderSearch.js +88 -0
- package/build/dist/UI/Components/CommandPalette/UseProviderSearch.js.map +1 -0
- package/build/dist/UI/Components/Dropdown/Dropdown.js +6 -1
- package/build/dist/UI/Components/Dropdown/Dropdown.js.map +1 -1
- package/build/dist/UI/Components/EmptyState/EmptyState.js +1 -1
- package/build/dist/UI/Components/EmptyState/EmptyState.js.map +1 -1
- package/build/dist/UI/Components/Feed/FeedItem.js +1 -1
- package/build/dist/UI/Components/Feed/FeedItem.js.map +1 -1
- package/build/dist/UI/Components/Footer/Footer.js +7 -4
- package/build/dist/UI/Components/Footer/Footer.js.map +1 -1
- package/build/dist/UI/Components/Forms/Fields/FormField.js +1 -1
- package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
- package/build/dist/UI/Components/List/List.js +19 -5
- package/build/dist/UI/Components/List/List.js.map +1 -1
- package/build/dist/UI/Components/List/ListSkeleton.js +21 -0
- package/build/dist/UI/Components/List/ListSkeleton.js.map +1 -0
- package/build/dist/UI/Components/Loader/PageLoader.js +15 -5
- package/build/dist/UI/Components/Loader/PageLoader.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js +16 -3
- package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js.map +1 -1
- package/build/dist/UI/Components/Markdown.tsx/LazyMarkdownViewer.js +13 -1
- package/build/dist/UI/Components/Markdown.tsx/LazyMarkdownViewer.js.map +1 -1
- package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +52 -25
- package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
- package/build/dist/UI/Components/MasterPage/MasterPage.js +10 -2
- package/build/dist/UI/Components/MasterPage/MasterPage.js.map +1 -1
- package/build/dist/UI/Components/Modal/Modal.js +2 -2
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +1 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/useCustomFieldColumns.js +9 -2
- package/build/dist/UI/Components/ModelTable/useCustomFieldColumns.js.map +1 -1
- package/build/dist/UI/Components/MoreMenu/MoreMenu.js +32 -1
- package/build/dist/UI/Components/MoreMenu/MoreMenu.js.map +1 -1
- package/build/dist/UI/Components/Navbar/NavBar.js +5 -1
- package/build/dist/UI/Components/Navbar/NavBar.js.map +1 -1
- package/build/dist/UI/Components/OrderedStatesList/OrderedStatesList.js +29 -5
- package/build/dist/UI/Components/OrderedStatesList/OrderedStatesList.js.map +1 -1
- package/build/dist/UI/Components/SideMenu/CountModelSideMenuItem.js +23 -1
- package/build/dist/UI/Components/SideMenu/CountModelSideMenuItem.js.map +1 -1
- package/build/dist/UI/Components/SideOver/SideOver.js +23 -2
- package/build/dist/UI/Components/SideOver/SideOver.js.map +1 -1
- package/build/dist/UI/Components/Skeleton/Skeleton.js +23 -0
- package/build/dist/UI/Components/Skeleton/Skeleton.js.map +1 -0
- package/build/dist/UI/Components/Table/Table.js +35 -24
- package/build/dist/UI/Components/Table/Table.js.map +1 -1
- package/build/dist/UI/Components/Table/TableSkeletonRows.js +52 -0
- package/build/dist/UI/Components/Table/TableSkeletonRows.js.map +1 -0
- package/build/dist/UI/Components/Tabs/Tab.js +1 -1
- package/build/dist/UI/Components/Tabs/Tab.js.map +1 -1
- package/build/dist/UI/Components/Toast/Toast.js +77 -23
- package/build/dist/UI/Components/Toast/Toast.js.map +1 -1
- package/build/dist/UI/Components/Toast/ToastInit.js +37 -15
- package/build/dist/UI/Components/Toast/ToastInit.js.map +1 -1
- package/build/dist/UI/Utils/ModelAPI/ModelAPI.js +18 -9
- package/build/dist/UI/Utils/ModelAPI/ModelAPI.js.map +1 -1
- package/build/dist/UI/Utils/ModelListCache.js +126 -0
- package/build/dist/UI/Utils/ModelListCache.js.map +1 -0
- package/build/dist/UI/Utils/Project.js +24 -1
- package/build/dist/UI/Utils/Project.js.map +1 -1
- package/build/dist/Utils/API.js +6 -1
- package/build/dist/Utils/API.js.map +1 -1
- package/build/dist/Utils/Monitor/MonitorMetricType.js +13 -1
- package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +34 -7
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
- package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js +177 -0
- package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js.map +1 -0
- package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js +23 -27
- package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js.map +1 -1
- package/build/dist/Utils/Telemetry/CrossSignalScope.js +44 -4
- package/build/dist/Utils/Telemetry/CrossSignalScope.js.map +1 -1
- package/jest.config.json +1 -1
- package/package.json +2 -3
- package/Server/Utils/Monitor/MonitorClusterContext.ts +0 -182
- package/Tests/__mocks__/otpauth.js +0 -30
- package/build/dist/Server/Utils/Monitor/MonitorClusterContext.js +0 -141
- package/build/dist/Server/Utils/Monitor/MonitorClusterContext.js.map +0 -1
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
2
|
+
import PositiveNumber from "../../../Types/PositiveNumber";
|
|
3
|
+
import { JSONObject } from "../../../Types/JSON";
|
|
4
|
+
import HostModel from "../../../Models/DatabaseModels/Host";
|
|
5
|
+
import DockerHostModel from "../../../Models/DatabaseModels/DockerHost";
|
|
6
|
+
import PodmanHostModel from "../../../Models/DatabaseModels/PodmanHost";
|
|
7
|
+
import KubernetesClusterModel from "../../../Models/DatabaseModels/KubernetesCluster";
|
|
8
|
+
import HostService from "../../Services/HostService";
|
|
9
|
+
import DockerHostService from "../../Services/DockerHostService";
|
|
10
|
+
import PodmanHostService from "../../Services/PodmanHostService";
|
|
11
|
+
import KubernetesClusterService from "../../Services/KubernetesClusterService";
|
|
12
|
+
import {
|
|
13
|
+
keyForHost,
|
|
14
|
+
keyForKubernetesCluster,
|
|
15
|
+
} from "../../../Utils/Telemetry/EntityKey";
|
|
16
|
+
import {
|
|
17
|
+
ResourceEntityFacetSelections,
|
|
18
|
+
isResourceEntityFacetKey,
|
|
19
|
+
parseResourceEntityFacetSelections,
|
|
20
|
+
} from "../../../Types/Telemetry/ResourceEntityFacet";
|
|
21
|
+
import Includes from "../../../Types/BaseDatabase/Includes";
|
|
22
|
+
import TableColumnType from "../../../Types/AnalyticsDatabase/TableColumnType";
|
|
23
|
+
import { SQL, Statement } from "../AnalyticsDatabase/Statement";
|
|
24
|
+
import logger from "../Logger";
|
|
25
|
+
import CaptureSpan from "./CaptureSpan";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* One resource facet's selection, compiled into the three ways a signal row
|
|
29
|
+
* can prove membership of that resource. The three are OR-ed together; a
|
|
30
|
+
* row matching any of them belongs to the selected resource.
|
|
31
|
+
*
|
|
32
|
+
* - `entityIds` -> `primaryEntityId IN (...)`. Agent-ingested telemetry
|
|
33
|
+
* has the resource as its primary entity, so its id is
|
|
34
|
+
* literally in the column. Also the only thing that
|
|
35
|
+
* matches rows written before `entityKeys` existed.
|
|
36
|
+
* - `entityKeys` -> `hasAny(entityKeys, [...])`. The general membership
|
|
37
|
+
* read: OTLP telemetry primary-keyed on its Service
|
|
38
|
+
* still carries the host / cluster key here.
|
|
39
|
+
* - `attribute*` -> `attributes['resource.<attr>'] IN (...)`. The
|
|
40
|
+
* pre-`entityKeys` fallback, mirroring the entityScope
|
|
41
|
+
* contract the resource detail pages already use, so
|
|
42
|
+
* rows ingested before the column shipped (no backfill
|
|
43
|
+
* by decision) keep matching.
|
|
44
|
+
*/
|
|
45
|
+
export interface ResourceEntityScope {
|
|
46
|
+
entityIds: Array<string>;
|
|
47
|
+
entityKeys: Array<string>;
|
|
48
|
+
attributeKey?: string | undefined;
|
|
49
|
+
attributeValues?: Array<string> | undefined;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
interface ResourceFacetDefinition {
|
|
53
|
+
/** Signal attribute the identifying value is stamped under. */
|
|
54
|
+
attributeKey: string;
|
|
55
|
+
/** Read-side entity-key helper, mirroring the ingest-side resolver. */
|
|
56
|
+
entityKeyFor: (projectId: string, identifier: string) => string;
|
|
57
|
+
findIdentifiers: (data: {
|
|
58
|
+
projectId: ObjectID;
|
|
59
|
+
ids: Array<ObjectID>;
|
|
60
|
+
}) => Promise<Array<string>>;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/*
|
|
64
|
+
* `Host` / `DockerHost` / `PodmanHost` all key on the canonicalized
|
|
65
|
+
* `host.name` (see `HostService.findOrCreateByHostIdentifier` and its
|
|
66
|
+
* Docker / Podman siblings), which is exactly the Host entity's identity —
|
|
67
|
+
* so all three resolve through `keyForHost`. A Kubernetes cluster keys on
|
|
68
|
+
* `k8s.cluster.name` (`InventoryItem.k8sClusterIdentity`).
|
|
69
|
+
*
|
|
70
|
+
* The Docker / Podman facets need this as much as the Kubernetes one does:
|
|
71
|
+
* `getServiceNameFromAttributes` synthesises a per-container service name
|
|
72
|
+
* for agent-collected container telemetry, so those rows are primary-keyed
|
|
73
|
+
* on a Service too and an id-only predicate finds almost nothing.
|
|
74
|
+
*
|
|
75
|
+
* Resolving them to the Host entity means "Docker Host web-1" also matches
|
|
76
|
+
* non-container telemetry from web-1 when the Infrastructure agent runs
|
|
77
|
+
* alongside. That is the machine the facet names, so the wider match is the
|
|
78
|
+
* honest reading — and it is the only identity an OTLP resource carries;
|
|
79
|
+
* DockerHost / PodmanHost are inventory-mirrored types that no resource
|
|
80
|
+
* ever declares (see EntityType).
|
|
81
|
+
*/
|
|
82
|
+
const FACET_DEFINITIONS: Record<string, ResourceFacetDefinition> = {
|
|
83
|
+
hostId: {
|
|
84
|
+
attributeKey: "resource.host.name",
|
|
85
|
+
entityKeyFor: keyForHost,
|
|
86
|
+
findIdentifiers: async (data: {
|
|
87
|
+
projectId: ObjectID;
|
|
88
|
+
ids: Array<ObjectID>;
|
|
89
|
+
}): Promise<Array<string>> => {
|
|
90
|
+
const rows: Array<HostModel> = await HostService.findBy({
|
|
91
|
+
query: { projectId: data.projectId, _id: new Includes(data.ids) },
|
|
92
|
+
select: { hostIdentifier: true },
|
|
93
|
+
limit: new PositiveNumber(data.ids.length),
|
|
94
|
+
skip: new PositiveNumber(0),
|
|
95
|
+
props: { isRoot: true },
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
return rows.map((row: HostModel): string => {
|
|
99
|
+
return row.hostIdentifier || "";
|
|
100
|
+
});
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
dockerHostId: {
|
|
104
|
+
attributeKey: "resource.host.name",
|
|
105
|
+
entityKeyFor: keyForHost,
|
|
106
|
+
findIdentifiers: async (data: {
|
|
107
|
+
projectId: ObjectID;
|
|
108
|
+
ids: Array<ObjectID>;
|
|
109
|
+
}): Promise<Array<string>> => {
|
|
110
|
+
const rows: Array<DockerHostModel> = await DockerHostService.findBy({
|
|
111
|
+
query: { projectId: data.projectId, _id: new Includes(data.ids) },
|
|
112
|
+
select: { hostIdentifier: true },
|
|
113
|
+
limit: new PositiveNumber(data.ids.length),
|
|
114
|
+
skip: new PositiveNumber(0),
|
|
115
|
+
props: { isRoot: true },
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
return rows.map((row: DockerHostModel): string => {
|
|
119
|
+
return row.hostIdentifier || "";
|
|
120
|
+
});
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
podmanHostId: {
|
|
124
|
+
attributeKey: "resource.host.name",
|
|
125
|
+
entityKeyFor: keyForHost,
|
|
126
|
+
findIdentifiers: async (data: {
|
|
127
|
+
projectId: ObjectID;
|
|
128
|
+
ids: Array<ObjectID>;
|
|
129
|
+
}): Promise<Array<string>> => {
|
|
130
|
+
const rows: Array<PodmanHostModel> = await PodmanHostService.findBy({
|
|
131
|
+
query: { projectId: data.projectId, _id: new Includes(data.ids) },
|
|
132
|
+
select: { hostIdentifier: true },
|
|
133
|
+
limit: new PositiveNumber(data.ids.length),
|
|
134
|
+
skip: new PositiveNumber(0),
|
|
135
|
+
props: { isRoot: true },
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
return rows.map((row: PodmanHostModel): string => {
|
|
139
|
+
return row.hostIdentifier || "";
|
|
140
|
+
});
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
kubernetesClusterId: {
|
|
144
|
+
attributeKey: "resource.k8s.cluster.name",
|
|
145
|
+
entityKeyFor: keyForKubernetesCluster,
|
|
146
|
+
findIdentifiers: async (data: {
|
|
147
|
+
projectId: ObjectID;
|
|
148
|
+
ids: Array<ObjectID>;
|
|
149
|
+
}): Promise<Array<string>> => {
|
|
150
|
+
const rows: Array<KubernetesClusterModel> =
|
|
151
|
+
await KubernetesClusterService.findBy({
|
|
152
|
+
query: { projectId: data.projectId, _id: new Includes(data.ids) },
|
|
153
|
+
select: { clusterIdentifier: true },
|
|
154
|
+
limit: new PositiveNumber(data.ids.length),
|
|
155
|
+
skip: new PositiveNumber(0),
|
|
156
|
+
props: { isRoot: true },
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
return rows.map((row: KubernetesClusterModel): string => {
|
|
160
|
+
return row.clusterIdentifier || "";
|
|
161
|
+
});
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Append the resolved resource scopes to a hand-written aggregation
|
|
168
|
+
* statement (the Log / Trace histogram, facet and analytics queries, which
|
|
169
|
+
* build SQL directly rather than through StatementGenerator).
|
|
170
|
+
*
|
|
171
|
+
* Emits one `AND ( ... OR ... )` group per scope, mirroring exactly what
|
|
172
|
+
* StatementGenerator compiles for the list query — the chart and the list
|
|
173
|
+
* must agree on which rows a facet selects, or the histogram tells a
|
|
174
|
+
* different story than the rows underneath it.
|
|
175
|
+
*
|
|
176
|
+
* A scope with no usable branch appends nothing rather than an empty
|
|
177
|
+
* `IN ()`: an unresolvable filter must not silently match zero rows.
|
|
178
|
+
*/
|
|
179
|
+
export function appendResourceScopeFilters(
|
|
180
|
+
statement: Statement,
|
|
181
|
+
scopes: Array<ResourceEntityScope> | undefined,
|
|
182
|
+
): void {
|
|
183
|
+
if (!scopes || scopes.length === 0) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
for (const scope of scopes) {
|
|
188
|
+
if (!scope) {
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const branches: Array<Statement> = [];
|
|
193
|
+
|
|
194
|
+
const entityIds: Array<string> = (scope.entityIds || []).filter(
|
|
195
|
+
(id: string): boolean => {
|
|
196
|
+
return typeof id === "string" && id.length > 0;
|
|
197
|
+
},
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
if (entityIds.length > 0) {
|
|
201
|
+
branches.push(
|
|
202
|
+
SQL`primaryEntityId IN (${{
|
|
203
|
+
type: TableColumnType.ObjectID,
|
|
204
|
+
value: new Includes(entityIds),
|
|
205
|
+
}})`,
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const entityKeys: Array<string> = (scope.entityKeys || []).filter(
|
|
210
|
+
(entityKey: string): boolean => {
|
|
211
|
+
return typeof entityKey === "string" && entityKey.length > 0;
|
|
212
|
+
},
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
if (entityKeys.length > 0) {
|
|
216
|
+
branches.push(
|
|
217
|
+
SQL`hasAny(entityKeys, ${{
|
|
218
|
+
type: TableColumnType.ArrayText,
|
|
219
|
+
value: entityKeys,
|
|
220
|
+
}})`,
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const attributeValues: Array<string> = (scope.attributeValues || []).filter(
|
|
225
|
+
(attributeValue: string): boolean => {
|
|
226
|
+
return typeof attributeValue === "string" && attributeValue.length > 0;
|
|
227
|
+
},
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
if (scope.attributeKey && attributeValues.length > 0) {
|
|
231
|
+
branches.push(
|
|
232
|
+
SQL`attributes[${{
|
|
233
|
+
type: TableColumnType.Text,
|
|
234
|
+
value: scope.attributeKey,
|
|
235
|
+
}}] IN (${{
|
|
236
|
+
type: TableColumnType.Text,
|
|
237
|
+
value: new Includes(attributeValues),
|
|
238
|
+
}})`,
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (branches.length === 0) {
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
statement.append(SQL` AND (`);
|
|
247
|
+
|
|
248
|
+
for (const [index, branch] of branches.entries()) {
|
|
249
|
+
if (index > 0) {
|
|
250
|
+
statement.append(SQL` OR `);
|
|
251
|
+
}
|
|
252
|
+
statement.append(branch);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
statement.append(SQL`)`);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
export default class ResourceEntityFilter {
|
|
260
|
+
/**
|
|
261
|
+
* Read the `resourceFilters` field off a request body (or an analytics
|
|
262
|
+
* query record) into the canonical selection shape. Delegates to the
|
|
263
|
+
* isomorphic parser so the browser and the server agree on exactly which
|
|
264
|
+
* selections are well-formed.
|
|
265
|
+
*/
|
|
266
|
+
public static parseSelections(
|
|
267
|
+
source: JSONObject | undefined | null,
|
|
268
|
+
): ResourceEntityFacetSelections {
|
|
269
|
+
return parseResourceEntityFacetSelections(source);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Compile each facet's selected ids into a scope. One scope per facet, so
|
|
274
|
+
* the caller ANDs them: selecting a cluster and a host means "in that
|
|
275
|
+
* cluster AND on that host", which is what a reader expects of two
|
|
276
|
+
* independent filter groups.
|
|
277
|
+
*
|
|
278
|
+
* The identifier lookup is best-effort: if Postgres is unreachable or an
|
|
279
|
+
* id no longer resolves, the scope keeps its `entityIds` branch and
|
|
280
|
+
* simply loses the entity-key one. That degrades to today's behavior
|
|
281
|
+
* rather than dropping the constraint (which would silently widen the
|
|
282
|
+
* result set).
|
|
283
|
+
*/
|
|
284
|
+
@CaptureSpan()
|
|
285
|
+
public static async resolveScopes(data: {
|
|
286
|
+
projectId: ObjectID;
|
|
287
|
+
selections: ResourceEntityFacetSelections;
|
|
288
|
+
}): Promise<Array<ResourceEntityScope>> {
|
|
289
|
+
const facetKeys: Array<string> = Object.keys(data.selections).filter(
|
|
290
|
+
(key: string): boolean => {
|
|
291
|
+
return (
|
|
292
|
+
isResourceEntityFacetKey(key) &&
|
|
293
|
+
(data.selections[key] || []).length > 0
|
|
294
|
+
);
|
|
295
|
+
},
|
|
296
|
+
);
|
|
297
|
+
|
|
298
|
+
if (facetKeys.length === 0) {
|
|
299
|
+
return [];
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
return Promise.all(
|
|
303
|
+
facetKeys.map(async (facetKey: string): Promise<ResourceEntityScope> => {
|
|
304
|
+
return ResourceEntityFilter.resolveOne({
|
|
305
|
+
projectId: data.projectId,
|
|
306
|
+
facetKey,
|
|
307
|
+
ids: data.selections[facetKey] || [],
|
|
308
|
+
});
|
|
309
|
+
}),
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Query key the client puts the raw selected ids under, and the key the
|
|
315
|
+
* compiled scopes are written to. Kept together so the rewrite below is
|
|
316
|
+
* the only thing that has to know the pair.
|
|
317
|
+
*/
|
|
318
|
+
public static readonly QUERY_FILTER_KEY: string = "resourceFilters";
|
|
319
|
+
public static readonly QUERY_SCOPE_KEY: string = "resourceEntityScopes";
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Rewrite an analytics list query in place: consume the client-sent
|
|
323
|
+
* `resourceFilters` ids and replace them with the resolved
|
|
324
|
+
* `resourceEntityScopes` that StatementGenerator compiles.
|
|
325
|
+
*
|
|
326
|
+
* The compiled key is always rebuilt from scratch — a client cannot
|
|
327
|
+
* hand-craft one, so the only way a scope reaches the SQL is through this
|
|
328
|
+
* resolver. (It could only ever narrow rows, but leaving one authoritative
|
|
329
|
+
* writer keeps the predicate auditable.)
|
|
330
|
+
*
|
|
331
|
+
* Without a tenant the identifier lookup cannot be project-scoped, so the
|
|
332
|
+
* scope keeps its id branch and drops the entity-key one: narrower than
|
|
333
|
+
* the request asked for, never wider.
|
|
334
|
+
*/
|
|
335
|
+
@CaptureSpan()
|
|
336
|
+
public static async rewriteAnalyticsQuery(data: {
|
|
337
|
+
query: Record<string, unknown> | undefined;
|
|
338
|
+
projectId?: ObjectID | undefined;
|
|
339
|
+
}): Promise<void> {
|
|
340
|
+
const query: Record<string, unknown> | undefined = data.query;
|
|
341
|
+
|
|
342
|
+
if (!query || typeof query !== "object") {
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
const raw: unknown = query[ResourceEntityFilter.QUERY_FILTER_KEY];
|
|
347
|
+
|
|
348
|
+
delete query[ResourceEntityFilter.QUERY_FILTER_KEY];
|
|
349
|
+
delete query[ResourceEntityFilter.QUERY_SCOPE_KEY];
|
|
350
|
+
|
|
351
|
+
if (raw === undefined || raw === null) {
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
const selections: ResourceEntityFacetSelections =
|
|
356
|
+
ResourceEntityFilter.parseSelections(raw as JSONObject);
|
|
357
|
+
|
|
358
|
+
if (Object.keys(selections).length === 0) {
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
if (!data.projectId) {
|
|
363
|
+
query[ResourceEntityFilter.QUERY_SCOPE_KEY] = Object.keys(selections).map(
|
|
364
|
+
(facetKey: string): ResourceEntityScope => {
|
|
365
|
+
return { entityIds: selections[facetKey] || [], entityKeys: [] };
|
|
366
|
+
},
|
|
367
|
+
);
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
const scopes: Array<ResourceEntityScope> =
|
|
372
|
+
await ResourceEntityFilter.resolveScopes({
|
|
373
|
+
projectId: data.projectId,
|
|
374
|
+
selections,
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
if (scopes.length > 0) {
|
|
378
|
+
query[ResourceEntityFilter.QUERY_SCOPE_KEY] = scopes;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
private static async resolveOne(data: {
|
|
383
|
+
projectId: ObjectID;
|
|
384
|
+
facetKey: string;
|
|
385
|
+
ids: Array<string>;
|
|
386
|
+
}): Promise<ResourceEntityScope> {
|
|
387
|
+
const scope: ResourceEntityScope = {
|
|
388
|
+
entityIds: data.ids,
|
|
389
|
+
entityKeys: [],
|
|
390
|
+
};
|
|
391
|
+
|
|
392
|
+
const definition: ResourceFacetDefinition | undefined =
|
|
393
|
+
FACET_DEFINITIONS[data.facetKey];
|
|
394
|
+
|
|
395
|
+
if (!definition) {
|
|
396
|
+
return scope;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
let identifiers: Array<string> = [];
|
|
400
|
+
|
|
401
|
+
try {
|
|
402
|
+
identifiers = await definition.findIdentifiers({
|
|
403
|
+
projectId: data.projectId,
|
|
404
|
+
ids: data.ids.map((id: string): ObjectID => {
|
|
405
|
+
return new ObjectID(id);
|
|
406
|
+
}),
|
|
407
|
+
});
|
|
408
|
+
} catch (err: unknown) {
|
|
409
|
+
logger.warn(
|
|
410
|
+
`Could not resolve ${data.facetKey} identifiers for the entity-key filter; falling back to primaryEntityId only: ${err}`,
|
|
411
|
+
);
|
|
412
|
+
return scope;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
const uniqueIdentifiers: Array<string> = Array.from(
|
|
416
|
+
new Set(
|
|
417
|
+
identifiers.filter((identifier: string): boolean => {
|
|
418
|
+
return identifier.trim().length > 0;
|
|
419
|
+
}),
|
|
420
|
+
),
|
|
421
|
+
);
|
|
422
|
+
|
|
423
|
+
if (uniqueIdentifiers.length === 0) {
|
|
424
|
+
return scope;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
const projectIdString: string = data.projectId.toString();
|
|
428
|
+
|
|
429
|
+
scope.entityKeys = Array.from(
|
|
430
|
+
new Set(
|
|
431
|
+
uniqueIdentifiers.map((identifier: string): string => {
|
|
432
|
+
return definition.entityKeyFor(projectIdString, identifier);
|
|
433
|
+
}),
|
|
434
|
+
),
|
|
435
|
+
);
|
|
436
|
+
scope.attributeKey = definition.attributeKey;
|
|
437
|
+
scope.attributeValues = uniqueIdentifiers;
|
|
438
|
+
|
|
439
|
+
return scope;
|
|
440
|
+
}
|
|
441
|
+
}
|
package/Server/Utils/TotpAuth.ts
CHANGED
|
@@ -2,6 +2,63 @@ import Email from "../../Types/Email";
|
|
|
2
2
|
import * as OTPAuth from "otpauth";
|
|
3
3
|
import CaptureSpan from "./Telemetry/CaptureSpan";
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* The HMAC algorithm every new enrolment is issued with.
|
|
7
|
+
*
|
|
8
|
+
* RFC 6238 fixes SHA1 as the default and every authenticator implements it.
|
|
9
|
+
* The `algorithm` parameter in an otpauth:// URI is, in practice, advisory:
|
|
10
|
+
* Google Authenticator and Microsoft Authenticator parse the URI, ignore the
|
|
11
|
+
* parameter, and compute SHA1 anyway. A server that issues `algorithm=SHA256`
|
|
12
|
+
* therefore hands those apps a QR code they will silently mis-implement — the
|
|
13
|
+
* app shows a confident six digits, the server computes a completely different
|
|
14
|
+
* six digits, and enrolment can never succeed no matter how many codes the
|
|
15
|
+
* user tries. That is the failure this constant exists to prevent.
|
|
16
|
+
*
|
|
17
|
+
* SHA1 is not a weakness here. HMAC-SHA1 is unaffected by the collision
|
|
18
|
+
* attacks that retired SHA1 for signatures (RFC 6234 / RFC 2104), and the
|
|
19
|
+
* output is truncated to six digits over a 30 second window regardless — the
|
|
20
|
+
* brute-force surface is the 10^6 code space, not the hash.
|
|
21
|
+
*/
|
|
22
|
+
export const DefaultTotpAlgorithm: string = "SHA1";
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Algorithms a submitted token is checked against, in order.
|
|
26
|
+
*
|
|
27
|
+
* OneUptime issued `SHA256` enrolments before this was understood. Those
|
|
28
|
+
* secrets are still in the database and still work in the minority of apps
|
|
29
|
+
* that do honour the parameter (1Password, Bitwarden, Aegis, FreeOTP), so
|
|
30
|
+
* dropping SHA256 from verification would lock those accounts out of their
|
|
31
|
+
* own logins.
|
|
32
|
+
*
|
|
33
|
+
* The cost is exactly one bit: two algorithms across the validation window
|
|
34
|
+
* means twice as many six-digit strings are accepted at any instant. Against
|
|
35
|
+
* a 10^6 code space that is still a vanishing fraction, and the tests pin the
|
|
36
|
+
* bound so it cannot quietly grow.
|
|
37
|
+
*
|
|
38
|
+
* Retiring SHA256 needs more than time passing. Nothing on the row records
|
|
39
|
+
* which algorithm the user's app actually computes, so "no legacy rows remain"
|
|
40
|
+
* is not a question the database can answer today — removing it means either
|
|
41
|
+
* storing the algorithm that verified, or accepting that some long-dormant
|
|
42
|
+
* account re-enrols instead of logging in.
|
|
43
|
+
*/
|
|
44
|
+
export const SupportedTotpAlgorithms: Array<string> = ["SHA1", "SHA256"];
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Number of 30 second steps either side of now that a token is accepted for.
|
|
48
|
+
*
|
|
49
|
+
* Three steps is +/- 90 seconds, which absorbs ordinary phone/server clock
|
|
50
|
+
* drift and the user typing the last digit as the code rolls over.
|
|
51
|
+
*/
|
|
52
|
+
export const TotpValidationWindow: number = 3;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Number of digits in a token, and the length of the time step in seconds.
|
|
56
|
+
* Both are the values Google Authenticator assumes, and — like `algorithm` —
|
|
57
|
+
* both are parameters it ignores when told anything else.
|
|
58
|
+
*/
|
|
59
|
+
export const TotpDigits: number = 6;
|
|
60
|
+
export const TotpPeriodInSeconds: number = 30;
|
|
61
|
+
|
|
5
62
|
/**
|
|
6
63
|
* Utility class for handling TOTP authentication.
|
|
7
64
|
*/
|
|
@@ -21,7 +78,11 @@ export default class TotpAuth {
|
|
|
21
78
|
}
|
|
22
79
|
|
|
23
80
|
@CaptureSpan()
|
|
24
|
-
public static getTotp(data: {
|
|
81
|
+
public static getTotp(data: {
|
|
82
|
+
secret: string;
|
|
83
|
+
email: Email;
|
|
84
|
+
algorithm?: string | undefined;
|
|
85
|
+
}): OTPAuth.TOTP {
|
|
25
86
|
const totp: OTPAuth.TOTP = new OTPAuth.TOTP({
|
|
26
87
|
// Provider or service the account is associated with.
|
|
27
88
|
issuer: "OneUptime",
|
|
@@ -30,11 +91,11 @@ export default class TotpAuth {
|
|
|
30
91
|
email: data.email,
|
|
31
92
|
}),
|
|
32
93
|
// Algorithm used for the HMAC function.
|
|
33
|
-
algorithm:
|
|
94
|
+
algorithm: data.algorithm || DefaultTotpAlgorithm,
|
|
34
95
|
// Length of the generated tokens.
|
|
35
|
-
digits:
|
|
96
|
+
digits: TotpDigits,
|
|
36
97
|
// Interval of time for which a token is valid, in seconds.
|
|
37
|
-
period:
|
|
98
|
+
period: TotpPeriodInSeconds,
|
|
38
99
|
// Arbitrary key encoded in Base32 or OTPAuth.Secret instance.
|
|
39
100
|
secret: data.secret,
|
|
40
101
|
});
|
|
@@ -42,6 +103,33 @@ export default class TotpAuth {
|
|
|
42
103
|
return totp;
|
|
43
104
|
}
|
|
44
105
|
|
|
106
|
+
/**
|
|
107
|
+
* Strips the formatting authenticator apps add for readability.
|
|
108
|
+
*
|
|
109
|
+
* Google Authenticator renders a code as "123 456" and both the iOS and
|
|
110
|
+
* Android clipboards keep that space when the user copies it. Rejecting the
|
|
111
|
+
* paste is a self-inflicted "Invalid code" for a user who supplied exactly
|
|
112
|
+
* the right secret material, so the separators are removed before the token
|
|
113
|
+
* is compared. Anything that is not a digit is dropped, which also covers
|
|
114
|
+
* the hyphen some apps use and stray whitespace from a trimmed paste.
|
|
115
|
+
*
|
|
116
|
+
* @param token - The raw token as submitted.
|
|
117
|
+
* @returns The token reduced to its digits.
|
|
118
|
+
*/
|
|
119
|
+
@CaptureSpan()
|
|
120
|
+
public static normalizeToken(token: string): string {
|
|
121
|
+
/*
|
|
122
|
+
* The token arrives straight off a JSON body, so it is only a string
|
|
123
|
+
* because the client chose to send one. A number or an object here must
|
|
124
|
+
* fail verification, not throw out of `.replace` and surface as a 500.
|
|
125
|
+
*/
|
|
126
|
+
if (typeof token !== "string" || !token) {
|
|
127
|
+
return "";
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return token.replace(/\D/g, "");
|
|
131
|
+
}
|
|
132
|
+
|
|
45
133
|
/**
|
|
46
134
|
* Verifies if a given token matches the provided secret key.
|
|
47
135
|
* @param data - The data object containing the secret key and token.
|
|
@@ -53,13 +141,49 @@ export default class TotpAuth {
|
|
|
53
141
|
token: string;
|
|
54
142
|
email: Email;
|
|
55
143
|
}): boolean {
|
|
56
|
-
const { secret,
|
|
144
|
+
const { secret, email } = data;
|
|
57
145
|
|
|
58
|
-
|
|
146
|
+
if (!secret) {
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
59
149
|
|
|
60
|
-
const
|
|
150
|
+
const token: string = this.normalizeToken(data.token);
|
|
61
151
|
|
|
62
|
-
|
|
152
|
+
/*
|
|
153
|
+
* otpauth compares the submitted string against the codes it generates,
|
|
154
|
+
* so a token of the wrong length can never match — but it would still be
|
|
155
|
+
* run through one HMAC per algorithm per window step first. Reject it up
|
|
156
|
+
* front instead.
|
|
157
|
+
*/
|
|
158
|
+
if (token.length !== TotpDigits) {
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
for (const algorithm of SupportedTotpAlgorithms) {
|
|
163
|
+
let totp: OTPAuth.TOTP;
|
|
164
|
+
|
|
165
|
+
try {
|
|
166
|
+
totp = this.getTotp({ secret, email, algorithm });
|
|
167
|
+
} catch {
|
|
168
|
+
/*
|
|
169
|
+
* A secret that is not valid base32 throws in the OTPAuth.Secret
|
|
170
|
+
* constructor. That is a corrupt row, not a wrong code, and it fails
|
|
171
|
+
* identically for every algorithm — so stop rather than repeat it.
|
|
172
|
+
*/
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const delta: number | null = totp.validate({
|
|
177
|
+
token,
|
|
178
|
+
window: TotpValidationWindow,
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
if (delta !== null) {
|
|
182
|
+
return true;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return false;
|
|
63
187
|
}
|
|
64
188
|
|
|
65
189
|
/**
|
|
@@ -74,7 +198,11 @@ export default class TotpAuth {
|
|
|
74
198
|
}): string {
|
|
75
199
|
const { secret, userEmail } = data;
|
|
76
200
|
|
|
77
|
-
const totp: OTPAuth.TOTP = this.getTotp({
|
|
201
|
+
const totp: OTPAuth.TOTP = this.getTotp({
|
|
202
|
+
secret,
|
|
203
|
+
email: userEmail,
|
|
204
|
+
algorithm: DefaultTotpAlgorithm,
|
|
205
|
+
});
|
|
78
206
|
|
|
79
207
|
return totp.toString();
|
|
80
208
|
}
|