@oneuptime/common 13.0.7 → 13.0.8
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/OnCallDutyPolicyScheduleCalendarFeed.ts +1 -1
- package/Models/DatabaseModels/ProjectOnCallCalendarFeed.ts +1 -1
- package/Models/DatabaseModels/UserOnCallCalendarFeed.ts +1 -1
- package/Server/API/AIBillingAPI.ts +1 -0
- package/Server/API/AIInsightAPI.ts +1 -4
- package/Server/API/AIInvestigationAPI.ts +1 -4
- package/Server/API/AIReadinessAPI.ts +4 -5
- package/Server/API/AlertAPI.ts +1 -0
- package/Server/API/AutoRemediationAPI.ts +1 -4
- package/Server/API/BaseAPI.ts +13 -0
- package/Server/API/BaseAnalyticsAPI.ts +80 -9
- package/Server/API/BillingAPI.ts +2 -0
- package/Server/API/BillingInvoiceAPI.ts +1 -0
- package/Server/API/BillingPaymentMethodAPI.ts +2 -0
- package/Server/API/CodeFixRunAPI.ts +1 -3
- package/Server/API/CommonAPI.ts +68 -4
- package/Server/API/DashboardAPI.ts +12 -12
- package/Server/API/GlobalConfigAPI.ts +17 -0
- package/Server/API/IncidentAPI.ts +2 -0
- package/Server/API/IncidentEpisodeAPI.ts +1 -0
- package/Server/API/NotificationAPI.ts +1 -0
- package/Server/API/OnCallCalendarAPI.ts +4 -5
- package/Server/API/OnCallDutyPolicyAPI.ts +7 -0
- package/Server/API/OnCallReadinessAPI.ts +4 -1
- package/Server/API/OnCallScheduleTimelineAPI.ts +731 -0
- package/Server/API/ProjectAPI.ts +1 -0
- package/Server/API/ScheduledMaintenanceAPI.ts +1 -0
- package/Server/API/StatusPageAPI.ts +161 -32
- package/Server/API/TeamMemberAPI.ts +3 -0
- package/Server/API/UserCallAPI.ts +2 -0
- package/Server/API/UserEmailAPI.ts +2 -0
- package/Server/API/UserIncomingCallNumberAPI.ts +2 -0
- package/Server/API/UserMicrosoftTeamsAPI.ts +1 -0
- package/Server/API/UserSlackAPI.ts +1 -0
- package/Server/API/UserSmsAPI.ts +2 -0
- package/Server/API/UserTotpAuthAPI.ts +1 -0
- package/Server/API/UserWebAuthnAPI.ts +2 -0
- package/Server/API/UserWebhookAPI.ts +1 -0
- package/Server/API/UserWhatsAppAPI.ts +2 -0
- package/Server/Middleware/MasterAdminAuthorization.ts +13 -2
- package/Server/Middleware/UserAuthorization.ts +79 -5
- package/Server/Services/ApiKeyPermissionService.ts +101 -4
- package/Server/Services/DatabaseService.ts +245 -0
- package/Server/Services/DetectionRuleService.ts +5 -4
- package/Server/Services/OnCallDutyPolicyChildService.ts +261 -0
- package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +2 -2
- package/Server/Services/OnCallDutyPolicyEscalationRuleService.ts +2 -2
- package/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.ts +2 -2
- package/Server/Services/OnCallDutyPolicyEscalationRuleUserService.ts +2 -2
- package/Server/Services/PayAsYouGoBillingService.ts +23 -28
- package/Server/Services/ProjectService.ts +18 -0
- package/Server/Services/RumSessionPinService.ts +274 -22
- package/Server/Services/TeamPermissionService.ts +120 -26
- package/Server/Services/ThreatIntelFeedService.ts +6 -3
- package/Server/Types/Database/Permissions/BasePermission.ts +9 -7
- package/Server/Types/Database/Permissions/Index.ts +75 -11
- package/Server/Types/Database/Permissions/TablePermission.ts +24 -28
- package/Server/Utils/AI/AIChatPrivacyFilter.ts +8 -0
- package/Server/Utils/AI/AIRunPrivacyFilter.ts +8 -0
- package/Server/Utils/MasterAdminPageAccess.ts +61 -0
- package/Server/Utils/Monitor/MonitorAlert.ts +3 -1
- package/Server/Utils/Monitor/MonitorIncident.ts +3 -1
- package/Server/Utils/OnCall/OnCallCalendarFeedRenderer.ts +1 -1
- package/Server/Utils/Realtime.ts +163 -45
- package/Server/Utils/SecurityEvent/DetectionRuleEvaluator.ts +11 -28
- package/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepair.ts +170 -0
- package/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.ts +1 -1
- package/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelFeedPoller.ts +6 -2
- package/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelMatcher.ts +10 -9
- package/Tests/App/Dashboard/AffectedResourcesPicker.test.tsx +1059 -0
- package/Tests/App/Dashboard/AffectedResourcesPickerEditForm.test.tsx +376 -0
- package/Tests/App/Dashboard/AffectedResourcesPickerHiddenTypes.test.tsx +757 -0
- package/Tests/App/Dashboard/AffectedResourcesSummaryStep.test.tsx +307 -0
- package/Tests/App/Dashboard/ArgumentsFormGroupByUnlistedAttributes.test.tsx +131 -0
- package/Tests/App/Dashboard/DashboardHeaderRequests.test.tsx +1 -1
- package/Tests/App/Dashboard/DashboardMonitorLabelVariable.test.tsx +9 -1
- package/Tests/App/Dashboard/DashboardVariableAllContract.test.tsx +24 -0
- package/Tests/App/Dashboard/DashboardVariableSelector.test.tsx +162 -8
- package/Tests/App/Dashboard/EntityFilterDropdownArchivedSlos.test.tsx +105 -6
- package/Tests/App/Dashboard/EntityFilterDropdownUnlistedSelection.test.tsx +434 -0
- package/Tests/App/Dashboard/EscalationRuleReadiness.test.tsx +276 -1
- package/Tests/App/Dashboard/OnCallCalendarFeedSideMenus.test.tsx +9 -1
- package/Tests/App/Dashboard/PayAsYouGoConsentGate.test.tsx +58 -42
- package/Tests/App/Dashboard/PayAsYouGoNotices.test.tsx +42 -5
- package/Tests/App/Dashboard/ResourceAuditLogsSideMenus.test.tsx +34 -23
- package/Tests/App/Dashboard/ScheduleTimeline.test.tsx +1580 -0
- package/Tests/App/Dashboard/ScheduleTimelineAPI.test.ts +280 -0
- package/Tests/App/Dashboard/ScheduleTimelineModel.test.ts +673 -0
- package/Tests/App/Dashboard/SecurityEventConnectionDiagnostics.test.tsx +95 -68
- package/Tests/App/Dashboard/SecurityEventsDetectionRulesPage.test.tsx +86 -3
- package/Tests/App/Dashboard/SecurityEventsEmptyState.test.tsx +28 -3
- package/Tests/App/Dashboard/SecurityEventsExplorer.test.tsx +761 -0
- package/Tests/App/Dashboard/SecurityEventsGuideContent.test.ts +1313 -0
- package/Tests/App/Dashboard/SecurityEventsHowItWorksCard.test.tsx +536 -0
- package/Tests/App/Dashboard/SecurityEventsNoResults.test.tsx +222 -0
- package/Tests/App/Dashboard/SecurityEventsThreatIntelPage.test.tsx +199 -0
- package/Tests/App/Dashboard/SecurityEventsVolumeChart.test.tsx +321 -0
- package/Tests/App/Dashboard/SloOverviewHero.test.tsx +171 -36
- package/Tests/App/Dashboard/SloViewSideMenu.test.tsx +215 -0
- package/Tests/App/Dashboard/SloViewSideMenuCounts.test.tsx +40 -3
- package/Tests/App/PublicDashboard/DashboardVariableSelector.test.tsx +12 -4
- package/Tests/App/PublicDashboard/PublicDashboardWidgetListAuth.test.tsx +623 -0
- package/Tests/Models/OnCallCalendarFeedModels.test.ts +23 -1
- package/Tests/Server/API/AIChatRouteAuthorization.test.ts +138 -5
- package/Tests/Server/API/AIGenerationProjectAIToggle.test.ts +187 -0
- package/Tests/Server/API/AIInvestigationAvailabilityAuthorization.test.ts +51 -3
- package/Tests/Server/API/AIInvestigationEvidenceAPI.test.ts +55 -2
- package/Tests/Server/API/BaseAnalyticsAPIAggregateCache.test.ts +729 -0
- package/Tests/Server/API/BillingPayAsYouGoStatus.test.ts +93 -7
- package/Tests/Server/API/BillingPaymentMethodAPI.test.ts +36 -3
- package/Tests/Server/API/CommonAPIAuthGuard.test.ts +1003 -24
- package/Tests/Server/API/DashboardPublicRateLimit.test.ts +6 -3
- package/Tests/Server/API/ExpiredSessionAIRoutes.test.ts +708 -0
- package/Tests/Server/API/ExpiredSessionCustomRoutes.test.ts +928 -0
- package/Tests/Server/API/ExpiredSessionMonitorTemplate.test.ts +319 -0
- package/Tests/Server/API/ExpiredSessionOnCallDutyPolicy.test.ts +336 -0
- package/Tests/Server/API/ExpiredSessionRouteGuards.test.ts +820 -0
- package/Tests/Server/API/GlobalConfigLicense.test.ts +140 -0
- package/Tests/Server/API/NotificationChannelVerificationAPI.test.ts +115 -12
- package/Tests/Server/API/OnCallCalendarAPI.test.ts +375 -8
- package/Tests/Server/API/OnCallReadinessAPI.test.ts +175 -17
- package/Tests/Server/API/OnCallScheduleTimelineAPI.test.ts +1513 -0
- package/Tests/Server/API/OnCallSetupReminderAPI.test.ts +119 -7
- package/Tests/Server/API/ProjectScopedCustomRouteAuth.test.ts +111 -4
- package/Tests/Server/API/PublicRouteInvalidAccessToken.test.ts +615 -0
- package/Tests/Server/API/SecurityEventAttributesAPI.test.ts +89 -2
- package/Tests/Server/API/SessionReplayAPI.test.ts +121 -0
- package/Tests/Server/API/StatusPageMasterPasswordRateLimit.test.ts +4 -2
- package/Tests/Server/API/StatusPagePostmortemVisibility.test.ts +441 -0
- package/Tests/Server/API/StatusPageTestEmailReportAuth.test.ts +664 -0
- package/Tests/Server/API/TeamMemberRemoveUserFromProjectAPI.test.ts +7 -0
- package/Tests/Server/API/UserIncomingCallNumberApi.test.ts +6 -0
- package/Tests/Server/API/UserNotificationSettingAPI.test.ts +65 -4
- package/Tests/Server/API/UserProjectsAPI.test.ts +63 -3
- package/Tests/Server/API/UserTotpAuthAPI.test.ts +48 -2
- package/Tests/Server/API/UserWebAuthnAuthenticationOptionsRoute.test.ts +11 -2
- package/Tests/Server/API/UserWebAuthnBackupCodeMinting.test.ts +46 -3
- package/Tests/Server/API/UserWebAuthnPasskeyAPI.test.ts +18 -2
- package/Tests/Server/API/ZZVerifyChatsAuth.test.ts +24 -7
- package/Tests/Server/Middleware/ExpiredSessionUserMiddleware.test.ts +563 -0
- package/Tests/Server/Middleware/MasterAdminAuthorization.test.ts +299 -19
- package/Tests/Server/Middleware/PublicRouteUserMiddleware.test.ts +453 -0
- package/Tests/Server/Services/AIChatPrivacyPin.test.ts +24 -0
- package/Tests/Server/Services/ApiKeyPermissionSecurity.test.ts +2 -0
- package/Tests/Server/Services/ApiKeyPermissionService.test.ts +3 -3
- package/Tests/Server/Services/DatabaseServiceCreateSuppliedId.test.ts +147 -0
- package/Tests/Server/Services/DatabaseServiceLoginBeforeHooks.test.ts +1078 -0
- package/Tests/Server/Services/DatabaseServiceTenantRelationGuard.test.ts +259 -0
- package/Tests/Server/Services/DatabaseServiceWriteOperatorValues.test.ts +147 -0
- package/Tests/Server/Services/MonitorPayAsYouGoBilling.test.ts +115 -1
- package/Tests/Server/Services/OnCallChildCreateAuthorizationPostgres.test.ts +711 -0
- package/Tests/Server/Services/OnCallDutyPolicyChildService.test.ts +733 -0
- package/Tests/Server/Services/PayAsYouGoBillingService.test.ts +190 -140
- package/Tests/Server/Services/PayAsYouGoStripeRateLimitBudget.test.ts +4 -9
- package/Tests/Server/Services/PermissionBlockDeletion.test.ts +780 -0
- package/Tests/Server/Services/PermissionBlockDeletionPostgres.test.ts +628 -0
- package/Tests/Server/Services/ProjectServiceCreateSubscriptionStarted.test.ts +77 -1
- package/Tests/Server/Services/RumSessionPinCreatePermission.test.ts +715 -0
- package/Tests/Server/Services/TeamMemberMultiTenantReadPostgres.test.ts +394 -0
- package/Tests/Server/Services/TeamPrivilegeEscalation.test.ts +6 -0
- package/Tests/Server/Services/TelemetryPayAsYouGoBilling.test.ts +131 -0
- package/Tests/Server/Services/UserNotificationRuleAdminGuards.test.ts +13 -2
- package/Tests/Server/Types/Database/Permissions/ModelPermissionAnonymousRefusal.test.ts +518 -0
- package/Tests/Server/Types/Database/Permissions/MultiTenantPermissions.test.ts +350 -0
- package/Tests/Server/Types/Database/Permissions/OnCallCalendarFeedPermissions.test.ts +282 -25
- package/Tests/Server/Types/Database/Permissions/TableLevelBlockPermission.test.ts +459 -0
- package/Tests/Server/Utils/AI/AIRunPrivacyFilter.test.ts +101 -9
- package/Tests/Server/Utils/AI/ChatAgentHelpers.test.ts +88 -4
- package/Tests/Server/Utils/AI/Toolbox/ExceptionTools.test.ts +459 -0
- package/Tests/Server/Utils/AI/Toolbox/LogTools.test.ts +794 -0
- package/Tests/Server/Utils/AI/Toolbox/RecentChangesTools.test.ts +574 -0
- package/Tests/Server/Utils/AI/Toolbox/SecurityEventTools.test.ts +596 -0
- package/Tests/Server/Utils/CaptchaRequestAndLogging.test.ts +395 -0
- package/Tests/Server/Utils/MasterAdminPageAccess.test.ts +251 -0
- package/Tests/Server/Utils/Monitor/MonitorActionTimestamps.test.ts +616 -0
- package/Tests/Server/Utils/Realtime.test.ts +502 -0
- package/Tests/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsConnectorSeverity.test.ts +216 -0
- package/Tests/Server/Utils/SecurityEvent/DetectionRuleEvaluator.test.ts +142 -0
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepair.test.ts +140 -0
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepairClickhouseIntegration.test.ts +542 -0
- package/Tests/Server/Utils/Telemetry/ChangeEventRow.test.ts +743 -0
- package/Tests/Server/Utils/Telemetry/RuntimeMetrics.test.ts +465 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/Messages/Alert.test.ts +202 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/Messages/Incident.test.ts +194 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/Messages/ScheduledMaintenance.test.ts +231 -0
- package/Tests/Server/Utils/Workspace/Slack/Messages/Alert.test.ts +194 -0
- package/Tests/Server/Utils/Workspace/Slack/Messages/AlertEpisode.test.ts +194 -0
- package/Tests/Server/Utils/Workspace/Slack/Messages/Incident.test.ts +194 -0
- package/Tests/Server/Utils/Workspace/Slack/Messages/IncidentEpisode.test.ts +194 -0
- package/Tests/Server/Utils/Workspace/Slack/Messages/ScheduledMaintenance.test.ts +247 -0
- package/Tests/Types/AI/AIInsightEvidence.test.ts +206 -0
- package/Tests/Types/BaseDatabase/DatabaseCommonInteractionPropsUtilAnonymous.test.ts +144 -0
- package/Tests/Types/Call/CallProvider.test.ts +528 -0
- package/Tests/Types/Kubernetes/KubernetesCostIngest.test.ts +236 -0
- package/Tests/Types/OnCallDutyPolicy/ScheduleTimeline.test.ts +736 -0
- package/Tests/Types/OnCallDutyPolicy/ScheduleTimelineLayout.test.ts +996 -0
- package/Tests/Types/SecurityEvent/SigmaRule.test.ts +142 -0
- package/Tests/Types/Workflow/Components/JSON.test.ts +182 -0
- package/Tests/UI/Components/BasicFormDropdownNormalization.test.tsx +116 -1
- package/Tests/UI/Components/Dropdown/DropdownAsyncOptions.test.tsx +81 -0
- package/Tests/UI/Components/EditionLabelLicenseRefresh.test.tsx +89 -1
- package/Tests/UI/Components/EventAttachmentList.test.tsx +174 -0
- package/Tests/UI/Components/Forms/BasicFormBurnRateTemplateDefaults.test.tsx +395 -0
- package/Tests/UI/Components/Forms/BasicFormCollapsibleSections.test.tsx +286 -0
- package/Tests/UI/Components/Forms/FormSummary.test.tsx +128 -0
- package/Tests/UI/Components/ModelTable/BaseModelTableQueryChange.test.tsx +365 -0
- package/Tests/UI/Components/OpenAuthenticatedUrl.test.ts +358 -0
- package/Tests/UI/Components/SessionAwareImage.test.tsx +496 -0
- package/Tests/UI/Components/TelemetryHistogramZeroBuckets.test.tsx +190 -0
- package/Tests/UI/Components/TooltipInteractive.test.tsx +97 -0
- package/Tests/UI/MicrosoftTeams/MicrosoftTeamsChatsCardInstallGuidance.test.tsx +1 -1
- package/Tests/UI/Monitor/EvaluationLogListTimestamps.test.tsx +367 -0
- package/Tests/UI/Utils/API/BaseAPIRefreshSession.test.ts +1087 -0
- package/Tests/UI/Utils/API/DashboardHost.ts +12 -0
- package/Tests/UI/Utils/API/FakeAxiosServer.ts +183 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +10 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +2 -0
- package/Tests/UI/Utils/Cookie.test.ts +440 -0
- package/Tests/UI/Utils/ModelAPIRequestClient.test.ts +278 -0
- package/Tests/UI/Utils/Navigation.test.ts +33 -0
- package/Tests/UI/Utils/PricingPlan.test.ts +295 -0
- package/Tests/UI/Utils/Realtime.test.ts +759 -0
- package/Tests/UI/Utils/Telemetry/Telemetry.test.ts +500 -0
- package/Tests/Utils/APIInstanceDispatch.test.ts +311 -0
- package/Tests/Utils/SecurityEvent/GoogleSecOpsAlertNormalizerSeverity.test.ts +565 -0
- package/Types/BaseDatabase/DatabaseCommonInteractionPropsUtil.ts +40 -0
- package/Types/Monitor/MonitorEvaluationSummary.ts +3 -0
- package/Types/OnCallDutyPolicy/ScheduleTimeline.ts +507 -0
- package/Types/OnCallDutyPolicy/ScheduleTimelineLayout.ts +589 -0
- package/Types/Realtime/EventName.ts +11 -0
- package/Types/SecurityEvent/DetectionFindingConstants.ts +14 -0
- package/Types/SecurityEvent/OcsfSeverity.ts +31 -26
- package/Types/SecurityEvent/SigmaRule.ts +51 -0
- package/Types/SecurityEvent/ThreatIntelConstants.ts +18 -0
- package/UI/Components/AttachmentList/EventAttachmentList.tsx +30 -2
- package/UI/Components/Dashboard/DashboardVariableControl.tsx +12 -2
- package/UI/Components/Dropdown/Dropdown.tsx +6 -1
- package/UI/Components/EditionLabel/EditionLabel.tsx +12 -0
- package/UI/Components/EventItem/EventItem.tsx +12 -1
- package/UI/Components/Forms/BasicForm.tsx +151 -126
- package/UI/Components/Forms/CollapsibleFormSection.tsx +63 -0
- package/UI/Components/Forms/Fields/FormField.tsx +10 -4
- package/UI/Components/Forms/FormSummary.tsx +7 -0
- package/UI/Components/Forms/Types/Field.ts +10 -0
- package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +2 -1
- package/UI/Components/Markdown.tsx/SessionAwareImage.tsx +122 -0
- package/UI/Components/ModelTable/BaseModelTable.tsx +34 -5
- package/UI/Components/ModelTable/TableView.tsx +1 -1
- package/UI/Components/TelemetryViewer/components/TelemetryHistogram.tsx +8 -1
- package/UI/Components/Tooltip/Tooltip.tsx +8 -1
- package/UI/Utils/API/API.ts +173 -12
- package/UI/Utils/API/RequestOptions.ts +11 -0
- package/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.ts +31 -7
- package/UI/Utils/ModelAPI/ModelAPI.ts +30 -9
- package/UI/Utils/Navigation.ts +9 -0
- package/UI/Utils/OpenAuthenticatedUrl.ts +154 -0
- package/UI/Utils/Realtime.ts +176 -30
- package/Utils/API.ts +14 -5
- package/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.ts +157 -7
- package/Utils/SecurityEvent/Sigma/SigmaRuleParser.ts +9 -17
- package/Utils/Slo/SloBurnRateTemplate.ts +2 -2
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.js +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ProjectOnCallCalendarFeed.js +1 -1
- package/build/dist/Models/DatabaseModels/ProjectOnCallCalendarFeed.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserOnCallCalendarFeed.js +1 -1
- package/build/dist/Models/DatabaseModels/UserOnCallCalendarFeed.js.map +1 -1
- package/build/dist/Server/API/AIBillingAPI.js +1 -1
- package/build/dist/Server/API/AIBillingAPI.js.map +1 -1
- package/build/dist/Server/API/AIInsightAPI.js +1 -4
- package/build/dist/Server/API/AIInsightAPI.js.map +1 -1
- package/build/dist/Server/API/AIInvestigationAPI.js +1 -4
- package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
- package/build/dist/Server/API/AIReadinessAPI.js +1 -3
- package/build/dist/Server/API/AIReadinessAPI.js.map +1 -1
- package/build/dist/Server/API/AlertAPI.js +1 -1
- package/build/dist/Server/API/AlertAPI.js.map +1 -1
- package/build/dist/Server/API/AutoRemediationAPI.js +1 -4
- package/build/dist/Server/API/AutoRemediationAPI.js.map +1 -1
- package/build/dist/Server/API/BaseAPI.js +12 -0
- package/build/dist/Server/API/BaseAPI.js.map +1 -1
- package/build/dist/Server/API/BaseAnalyticsAPI.js +55 -10
- package/build/dist/Server/API/BaseAnalyticsAPI.js.map +1 -1
- package/build/dist/Server/API/BillingAPI.js +2 -2
- package/build/dist/Server/API/BillingAPI.js.map +1 -1
- package/build/dist/Server/API/BillingInvoiceAPI.js +1 -1
- package/build/dist/Server/API/BillingInvoiceAPI.js.map +1 -1
- package/build/dist/Server/API/BillingPaymentMethodAPI.js +2 -2
- package/build/dist/Server/API/BillingPaymentMethodAPI.js.map +1 -1
- package/build/dist/Server/API/CodeFixRunAPI.js +1 -3
- package/build/dist/Server/API/CodeFixRunAPI.js.map +1 -1
- package/build/dist/Server/API/CommonAPI.js +50 -5
- package/build/dist/Server/API/CommonAPI.js.map +1 -1
- package/build/dist/Server/API/DashboardAPI.js +12 -12
- package/build/dist/Server/API/DashboardAPI.js.map +1 -1
- package/build/dist/Server/API/GlobalConfigAPI.js +12 -0
- package/build/dist/Server/API/GlobalConfigAPI.js.map +1 -1
- package/build/dist/Server/API/IncidentAPI.js +2 -2
- package/build/dist/Server/API/IncidentAPI.js.map +1 -1
- package/build/dist/Server/API/IncidentEpisodeAPI.js +1 -1
- package/build/dist/Server/API/IncidentEpisodeAPI.js.map +1 -1
- package/build/dist/Server/API/NotificationAPI.js +1 -1
- package/build/dist/Server/API/NotificationAPI.js.map +1 -1
- package/build/dist/Server/API/OnCallCalendarAPI.js +1 -4
- package/build/dist/Server/API/OnCallCalendarAPI.js.map +1 -1
- package/build/dist/Server/API/OnCallDutyPolicyAPI.js +6 -0
- package/build/dist/Server/API/OnCallDutyPolicyAPI.js.map +1 -1
- package/build/dist/Server/API/OnCallReadinessAPI.js +4 -1
- package/build/dist/Server/API/OnCallReadinessAPI.js.map +1 -1
- package/build/dist/Server/API/OnCallScheduleTimelineAPI.js +494 -0
- package/build/dist/Server/API/OnCallScheduleTimelineAPI.js.map +1 -0
- package/build/dist/Server/API/ProjectAPI.js +1 -1
- package/build/dist/Server/API/ProjectAPI.js.map +1 -1
- package/build/dist/Server/API/ScheduledMaintenanceAPI.js +1 -1
- package/build/dist/Server/API/ScheduledMaintenanceAPI.js.map +1 -1
- package/build/dist/Server/API/StatusPageAPI.js +125 -33
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/API/TeamMemberAPI.js +3 -3
- package/build/dist/Server/API/TeamMemberAPI.js.map +1 -1
- package/build/dist/Server/API/UserCallAPI.js +2 -2
- package/build/dist/Server/API/UserCallAPI.js.map +1 -1
- package/build/dist/Server/API/UserEmailAPI.js +2 -2
- package/build/dist/Server/API/UserEmailAPI.js.map +1 -1
- package/build/dist/Server/API/UserIncomingCallNumberAPI.js +2 -2
- package/build/dist/Server/API/UserIncomingCallNumberAPI.js.map +1 -1
- package/build/dist/Server/API/UserMicrosoftTeamsAPI.js +1 -1
- package/build/dist/Server/API/UserMicrosoftTeamsAPI.js.map +1 -1
- package/build/dist/Server/API/UserSlackAPI.js +1 -1
- package/build/dist/Server/API/UserSlackAPI.js.map +1 -1
- package/build/dist/Server/API/UserSmsAPI.js +2 -2
- package/build/dist/Server/API/UserSmsAPI.js.map +1 -1
- package/build/dist/Server/API/UserTotpAuthAPI.js +1 -1
- package/build/dist/Server/API/UserTotpAuthAPI.js.map +1 -1
- package/build/dist/Server/API/UserWebAuthnAPI.js +2 -2
- package/build/dist/Server/API/UserWebAuthnAPI.js.map +1 -1
- package/build/dist/Server/API/UserWebhookAPI.js +1 -1
- package/build/dist/Server/API/UserWebhookAPI.js.map +1 -1
- package/build/dist/Server/API/UserWhatsAppAPI.js +2 -2
- package/build/dist/Server/API/UserWhatsAppAPI.js.map +1 -1
- package/build/dist/Server/Middleware/MasterAdminAuthorization.js +11 -2
- package/build/dist/Server/Middleware/MasterAdminAuthorization.js.map +1 -1
- package/build/dist/Server/Middleware/UserAuthorization.js +64 -4
- package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
- package/build/dist/Server/Services/ApiKeyPermissionService.js +80 -4
- package/build/dist/Server/Services/ApiKeyPermissionService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +171 -0
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/DetectionRuleService.js +4 -4
- package/build/dist/Server/Services/DetectionRuleService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyChildService.js +170 -0
- package/build/dist/Server/Services/OnCallDutyPolicyChildService.js.map +1 -0
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +2 -2
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js +2 -2
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.js +2 -2
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js +2 -2
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js.map +1 -1
- package/build/dist/Server/Services/PayAsYouGoBillingService.js +20 -27
- package/build/dist/Server/Services/PayAsYouGoBillingService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +17 -0
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/RumSessionPinService.js +180 -16
- package/build/dist/Server/Services/RumSessionPinService.js.map +1 -1
- package/build/dist/Server/Services/TeamPermissionService.js +89 -27
- package/build/dist/Server/Services/TeamPermissionService.js.map +1 -1
- package/build/dist/Server/Services/ThreatIntelFeedService.js +5 -4
- package/build/dist/Server/Services/ThreatIntelFeedService.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/BasePermission.js +9 -6
- package/build/dist/Server/Types/Database/Permissions/BasePermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/Index.js +60 -6
- package/build/dist/Server/Types/Database/Permissions/Index.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/TablePermission.js +14 -13
- package/build/dist/Server/Types/Database/Permissions/TablePermission.js.map +1 -1
- package/build/dist/Server/Utils/AI/AIChatPrivacyFilter.js +7 -0
- package/build/dist/Server/Utils/AI/AIChatPrivacyFilter.js.map +1 -1
- package/build/dist/Server/Utils/AI/AIRunPrivacyFilter.js +7 -0
- package/build/dist/Server/Utils/AI/AIRunPrivacyFilter.js.map +1 -1
- package/build/dist/Server/Utils/MasterAdminPageAccess.js +39 -0
- package/build/dist/Server/Utils/MasterAdminPageAccess.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js +3 -1
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js +3 -1
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
- package/build/dist/Server/Utils/Realtime.js +126 -37
- package/build/dist/Server/Utils/Realtime.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js +7 -25
- package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepair.js +127 -0
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepair.js.map +1 -0
- package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js +1 -1
- package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelFeedPoller.js +3 -2
- package/build/dist/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelFeedPoller.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelMatcher.js +4 -8
- package/build/dist/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelMatcher.js.map +1 -1
- package/build/dist/Types/BaseDatabase/DatabaseCommonInteractionPropsUtil.js +31 -1
- package/build/dist/Types/BaseDatabase/DatabaseCommonInteractionPropsUtil.js.map +1 -1
- package/build/dist/Types/OnCallDutyPolicy/ScheduleTimeline.js +321 -0
- package/build/dist/Types/OnCallDutyPolicy/ScheduleTimeline.js.map +1 -0
- package/build/dist/Types/OnCallDutyPolicy/ScheduleTimelineLayout.js +372 -0
- package/build/dist/Types/OnCallDutyPolicy/ScheduleTimelineLayout.js.map +1 -0
- package/build/dist/Types/Realtime/EventName.js +10 -0
- package/build/dist/Types/Realtime/EventName.js.map +1 -1
- package/build/dist/Types/SecurityEvent/DetectionFindingConstants.js +11 -0
- package/build/dist/Types/SecurityEvent/DetectionFindingConstants.js.map +1 -1
- package/build/dist/Types/SecurityEvent/OcsfSeverity.js +30 -25
- package/build/dist/Types/SecurityEvent/OcsfSeverity.js.map +1 -1
- package/build/dist/Types/SecurityEvent/SigmaRule.js +47 -0
- package/build/dist/Types/SecurityEvent/SigmaRule.js.map +1 -1
- package/build/dist/Types/SecurityEvent/ThreatIntelConstants.js +14 -0
- package/build/dist/Types/SecurityEvent/ThreatIntelConstants.js.map +1 -1
- package/build/dist/UI/Components/AttachmentList/EventAttachmentList.js +9 -4
- package/build/dist/UI/Components/AttachmentList/EventAttachmentList.js.map +1 -1
- package/build/dist/UI/Components/Dashboard/DashboardVariableControl.js +10 -2
- package/build/dist/UI/Components/Dashboard/DashboardVariableControl.js.map +1 -1
- package/build/dist/UI/Components/Dropdown/Dropdown.js +5 -1
- package/build/dist/UI/Components/Dropdown/Dropdown.js.map +1 -1
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js +11 -0
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
- package/build/dist/UI/Components/EventItem/EventItem.js +2 -2
- package/build/dist/UI/Components/EventItem/EventItem.js.map +1 -1
- package/build/dist/UI/Components/Forms/BasicForm.js +70 -64
- package/build/dist/UI/Components/Forms/BasicForm.js.map +1 -1
- package/build/dist/UI/Components/Forms/CollapsibleFormSection.js +27 -0
- package/build/dist/UI/Components/Forms/CollapsibleFormSection.js.map +1 -0
- package/build/dist/UI/Components/Forms/Fields/FormField.js +10 -7
- package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
- package/build/dist/UI/Components/Forms/FormSummary.js +7 -0
- package/build/dist/UI/Components/Forms/FormSummary.js.map +1 -1
- package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +2 -1
- package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
- package/build/dist/UI/Components/Markdown.tsx/SessionAwareImage.js +84 -0
- package/build/dist/UI/Components/Markdown.tsx/SessionAwareImage.js.map +1 -0
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +14 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/TableView.js +1 -1
- package/build/dist/UI/Components/ModelTable/TableView.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js +8 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js.map +1 -1
- package/build/dist/UI/Components/Tooltip/Tooltip.js +2 -1
- package/build/dist/UI/Components/Tooltip/Tooltip.js.map +1 -1
- package/build/dist/UI/Utils/API/API.js +143 -19
- package/build/dist/UI/Utils/API/API.js.map +1 -1
- package/build/dist/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.js +21 -7
- package/build/dist/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.js.map +1 -1
- package/build/dist/UI/Utils/ModelAPI/ModelAPI.js +26 -9
- package/build/dist/UI/Utils/ModelAPI/ModelAPI.js.map +1 -1
- package/build/dist/UI/Utils/Navigation.js +8 -0
- package/build/dist/UI/Utils/Navigation.js.map +1 -1
- package/build/dist/UI/Utils/OpenAuthenticatedUrl.js +92 -0
- package/build/dist/UI/Utils/OpenAuthenticatedUrl.js.map +1 -0
- package/build/dist/UI/Utils/Realtime.js +120 -15
- package/build/dist/UI/Utils/Realtime.js.map +1 -1
- package/build/dist/Utils/API.js +13 -5
- package/build/dist/Utils/API.js.map +1 -1
- package/build/dist/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.js +123 -6
- package/build/dist/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.js.map +1 -1
- package/build/dist/Utils/SecurityEvent/Sigma/SigmaRuleParser.js +4 -18
- package/build/dist/Utils/SecurityEvent/Sigma/SigmaRuleParser.js.map +1 -1
- package/build/dist/Utils/Slo/SloBurnRateTemplate.js +2 -2
- package/package.json +1 -1
|
@@ -0,0 +1,563 @@
|
|
|
1
|
+
import CommonAPI from "../../../Server/API/CommonAPI";
|
|
2
|
+
import UserMiddleware from "../../../Server/Middleware/UserAuthorization";
|
|
3
|
+
import {
|
|
4
|
+
ExpressResponse,
|
|
5
|
+
NextFunction,
|
|
6
|
+
OneUptimeRequest,
|
|
7
|
+
} from "../../../Server/Utils/Express";
|
|
8
|
+
import Response from "../../../Server/Utils/Response";
|
|
9
|
+
import Dictionary from "../../../Types/Dictionary";
|
|
10
|
+
import Exception from "../../../Types/Exception/Exception";
|
|
11
|
+
import ExceptionCode from "../../../Types/Exception/ExceptionCode";
|
|
12
|
+
import NotAuthenticatedException from "../../../Types/Exception/NotAuthenticatedException";
|
|
13
|
+
import NotAuthorizedException from "../../../Types/Exception/NotAuthorizedException";
|
|
14
|
+
import JSONWebTokenData from "../../../Types/JsonWebTokenData";
|
|
15
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
16
|
+
import Permission, {
|
|
17
|
+
UserPermission,
|
|
18
|
+
UserTenantAccessPermission,
|
|
19
|
+
} from "../../../Types/Permission";
|
|
20
|
+
import UserType from "../../../Types/UserType";
|
|
21
|
+
import { getJestSpyOn } from "../../Spy";
|
|
22
|
+
import { afterEach, beforeEach, describe, expect, test } from "@jest/globals";
|
|
23
|
+
|
|
24
|
+
/*
|
|
25
|
+
* The request-level half of the expired-session fix.
|
|
26
|
+
*
|
|
27
|
+
* THE BUG
|
|
28
|
+
*
|
|
29
|
+
* The access-token cookie's maxAge is the JWT's own 15 minute lifetime, so a
|
|
30
|
+
* Dashboard tab left open longer than that sends its next request with no
|
|
31
|
+
* token at all. getUserMiddleware does not refuse such a request: it marks it
|
|
32
|
+
* UserType.Public and lets it through, because plenty of routes (status pages,
|
|
33
|
+
* public dashboards, CRUD reads of Public-permission models) are meant to be
|
|
34
|
+
* reachable anonymously. Whatever runs next decides.
|
|
35
|
+
*
|
|
36
|
+
* The browser client (Common/UI/Utils/API/API.ts) refreshes the session and
|
|
37
|
+
* replays the request ONLY on a 401. Everything that refused the anonymous
|
|
38
|
+
* request with anything else - a 422 NotAuthorizedException ("You are not
|
|
39
|
+
* authorized to access this project's data", "Project ID is required to
|
|
40
|
+
* access this resource") or a 400 - surfaced as a hard error to a user whose
|
|
41
|
+
* only problem was an idle tab.
|
|
42
|
+
*
|
|
43
|
+
* WHAT THIS FILE PINS
|
|
44
|
+
*
|
|
45
|
+
* 1. isAnonymousRequest is exactly "getUserMiddleware found neither a token
|
|
46
|
+
* nor an API key": userType unset or Public. API keys and master admins
|
|
47
|
+
* are credentials, not anonymity.
|
|
48
|
+
* 2. requireUserAuthentication answers an anonymous request with a 401 and
|
|
49
|
+
* admits every credentialed one - including API keys, so automation on
|
|
50
|
+
* the routes that gained this guard keeps working.
|
|
51
|
+
* 3. requirePermission asks "who are you?" BEFORE "which project?" and
|
|
52
|
+
* "what may you do?". An anonymous request with no tenant used to get
|
|
53
|
+
* the 422 "Project ID is required"; it now gets the 401, because no
|
|
54
|
+
* answer about tenants or permissions means anything until the caller
|
|
55
|
+
* has credentials. Every refusal of a credentialed caller is unchanged.
|
|
56
|
+
*
|
|
57
|
+
* Response.sendErrorResponse is spied on and silenced, so the assertion is on
|
|
58
|
+
* the exception the middleware chose - its class and its code - rather than
|
|
59
|
+
* on how Express would serialize it.
|
|
60
|
+
*/
|
|
61
|
+
|
|
62
|
+
const AUTHENTICATION_REQUIRED_MESSAGE: string =
|
|
63
|
+
"Authentication required. Please log in to access this resource.";
|
|
64
|
+
|
|
65
|
+
const PROJECT_ID: ObjectID = new ObjectID(
|
|
66
|
+
"11111111-1111-4111-8111-111111111111",
|
|
67
|
+
);
|
|
68
|
+
const OTHER_PROJECT_ID: ObjectID = new ObjectID(
|
|
69
|
+
"22222222-2222-4222-8222-222222222222",
|
|
70
|
+
);
|
|
71
|
+
const USER_ID: ObjectID = new ObjectID("33333333-3333-4333-8333-333333333333");
|
|
72
|
+
|
|
73
|
+
type RequestFixture = {
|
|
74
|
+
userType?: UserType | undefined;
|
|
75
|
+
tenantId?: ObjectID | undefined;
|
|
76
|
+
userAuthorization?: Partial<JSONWebTokenData> | undefined;
|
|
77
|
+
userTenantAccessPermission?:
|
|
78
|
+
| Dictionary<UserTenantAccessPermission>
|
|
79
|
+
| undefined;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
type BuildRequestFunction = (fixture: RequestFixture) => OneUptimeRequest;
|
|
83
|
+
|
|
84
|
+
const buildRequest: BuildRequestFunction = (
|
|
85
|
+
fixture: RequestFixture,
|
|
86
|
+
): OneUptimeRequest => {
|
|
87
|
+
return {
|
|
88
|
+
headers: {},
|
|
89
|
+
params: {},
|
|
90
|
+
query: {},
|
|
91
|
+
body: {},
|
|
92
|
+
...fixture,
|
|
93
|
+
} as unknown as OneUptimeRequest;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
type TenantPermissionFunction = (data: {
|
|
97
|
+
projectId: ObjectID;
|
|
98
|
+
permissions: Array<Permission>;
|
|
99
|
+
}) => Dictionary<UserTenantAccessPermission>;
|
|
100
|
+
|
|
101
|
+
const tenantPermission: TenantPermissionFunction = (data: {
|
|
102
|
+
projectId: ObjectID;
|
|
103
|
+
permissions: Array<Permission>;
|
|
104
|
+
}): Dictionary<UserTenantAccessPermission> => {
|
|
105
|
+
return {
|
|
106
|
+
[data.projectId.toString()]: {
|
|
107
|
+
_type: "UserTenantAccessPermission",
|
|
108
|
+
projectId: data.projectId,
|
|
109
|
+
permissions: data.permissions.map(
|
|
110
|
+
(permission: Permission): UserPermission => {
|
|
111
|
+
return {
|
|
112
|
+
_type: "UserPermission",
|
|
113
|
+
permission: permission,
|
|
114
|
+
labelIds: [],
|
|
115
|
+
};
|
|
116
|
+
},
|
|
117
|
+
),
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
type MiddlewareCallResult = {
|
|
123
|
+
nextCalls: Array<Array<unknown>>;
|
|
124
|
+
sentError: Exception | undefined;
|
|
125
|
+
sendErrorCallCount: number;
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
type MiddlewareFunction = (
|
|
129
|
+
req: OneUptimeRequest,
|
|
130
|
+
res: ExpressResponse,
|
|
131
|
+
next: NextFunction,
|
|
132
|
+
) => Promise<void>;
|
|
133
|
+
|
|
134
|
+
type CallMiddlewareFunction = (
|
|
135
|
+
middleware: MiddlewareFunction,
|
|
136
|
+
req: OneUptimeRequest,
|
|
137
|
+
) => Promise<MiddlewareCallResult>;
|
|
138
|
+
|
|
139
|
+
const callMiddleware: CallMiddlewareFunction = async (
|
|
140
|
+
middleware: MiddlewareFunction,
|
|
141
|
+
req: OneUptimeRequest,
|
|
142
|
+
): Promise<MiddlewareCallResult> => {
|
|
143
|
+
const res: ExpressResponse = {
|
|
144
|
+
status: jest.fn().mockReturnThis(),
|
|
145
|
+
json: jest.fn().mockReturnThis(),
|
|
146
|
+
send: jest.fn().mockReturnThis(),
|
|
147
|
+
} as unknown as ExpressResponse;
|
|
148
|
+
|
|
149
|
+
const next: jest.Mock = jest.fn();
|
|
150
|
+
|
|
151
|
+
await middleware(req, res, next as unknown as NextFunction);
|
|
152
|
+
|
|
153
|
+
const errorCalls: Array<Array<unknown>> = (
|
|
154
|
+
Response.sendErrorResponse as unknown as jest.Mock
|
|
155
|
+
).mock.calls as Array<Array<unknown>>;
|
|
156
|
+
|
|
157
|
+
return {
|
|
158
|
+
nextCalls: next.mock.calls as Array<Array<unknown>>,
|
|
159
|
+
sentError: errorCalls[0]?.[2] as Exception | undefined,
|
|
160
|
+
sendErrorCallCount: errorCalls.length,
|
|
161
|
+
};
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
type ExpectRefusedFunction = (result: MiddlewareCallResult) => void;
|
|
165
|
+
|
|
166
|
+
const expectUnauthenticated: ExpectRefusedFunction = (
|
|
167
|
+
result: MiddlewareCallResult,
|
|
168
|
+
): void => {
|
|
169
|
+
expect(result.nextCalls).toHaveLength(0);
|
|
170
|
+
expect(result.sendErrorCallCount).toBe(1);
|
|
171
|
+
expect(result.sentError).toBeInstanceOf(NotAuthenticatedException);
|
|
172
|
+
expect(result.sentError?.code).toBe(ExceptionCode.NotAuthenticatedException);
|
|
173
|
+
expect(result.sentError?.code).toBe(401);
|
|
174
|
+
expect(result.sentError?.message).toBe(AUTHENTICATION_REQUIRED_MESSAGE);
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
type ExpectForbiddenFunction = (
|
|
178
|
+
result: MiddlewareCallResult,
|
|
179
|
+
message: string,
|
|
180
|
+
) => void;
|
|
181
|
+
|
|
182
|
+
const expectNotAuthorized: ExpectForbiddenFunction = (
|
|
183
|
+
result: MiddlewareCallResult,
|
|
184
|
+
message: string,
|
|
185
|
+
): void => {
|
|
186
|
+
expect(result.nextCalls).toHaveLength(0);
|
|
187
|
+
expect(result.sendErrorCallCount).toBe(1);
|
|
188
|
+
expect(result.sentError).toBeInstanceOf(NotAuthorizedException);
|
|
189
|
+
expect(result.sentError?.code).toBe(ExceptionCode.NotAuthorizedException);
|
|
190
|
+
expect(result.sentError?.code).toBe(422);
|
|
191
|
+
expect(result.sentError?.message).toBe(message);
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
type ExpectPassedFunction = (result: MiddlewareCallResult) => void;
|
|
195
|
+
|
|
196
|
+
const expectPassed: ExpectPassedFunction = (
|
|
197
|
+
result: MiddlewareCallResult,
|
|
198
|
+
): void => {
|
|
199
|
+
expect(result.sendErrorCallCount).toBe(0);
|
|
200
|
+
expect(result.nextCalls).toHaveLength(1);
|
|
201
|
+
// next() with an argument is Express's error path, not a pass.
|
|
202
|
+
expect(result.nextCalls[0]).toEqual([]);
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
beforeEach(() => {
|
|
206
|
+
jest.clearAllMocks();
|
|
207
|
+
|
|
208
|
+
getJestSpyOn(Response, "sendErrorResponse").mockImplementation(() => {
|
|
209
|
+
return undefined as never;
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
afterEach(() => {
|
|
214
|
+
jest.restoreAllMocks();
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
describe("UserMiddleware.AUTHENTICATION_REQUIRED_MESSAGE", () => {
|
|
218
|
+
/*
|
|
219
|
+
* The request-level and the props-level refusal are two halves of one
|
|
220
|
+
* contract with the client, and a user who hits one route and then another
|
|
221
|
+
* should not see two different sentences for the same expired session.
|
|
222
|
+
*/
|
|
223
|
+
test("is the same sentence CommonAPI uses", () => {
|
|
224
|
+
expect(UserMiddleware.AUTHENTICATION_REQUIRED_MESSAGE).toBe(
|
|
225
|
+
AUTHENTICATION_REQUIRED_MESSAGE,
|
|
226
|
+
);
|
|
227
|
+
expect(UserMiddleware.AUTHENTICATION_REQUIRED_MESSAGE).toBe(
|
|
228
|
+
CommonAPI.AUTHENTICATION_REQUIRED_MESSAGE,
|
|
229
|
+
);
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
describe("UserMiddleware.isAnonymousRequest", () => {
|
|
234
|
+
test.each([
|
|
235
|
+
["no userType at all (getUserMiddleware never ran)", undefined, true],
|
|
236
|
+
["UserType.Public (no token, no API key)", UserType.Public, true],
|
|
237
|
+
["UserType.User (a decoded session)", UserType.User, false],
|
|
238
|
+
["UserType.API (a project API key)", UserType.API, false],
|
|
239
|
+
[
|
|
240
|
+
"UserType.MasterAdmin (a master admin session)",
|
|
241
|
+
UserType.MasterAdmin,
|
|
242
|
+
false,
|
|
243
|
+
],
|
|
244
|
+
])(
|
|
245
|
+
"%s -> anonymous: %p",
|
|
246
|
+
(_label: string, userType: UserType | undefined, expected: boolean) => {
|
|
247
|
+
expect(
|
|
248
|
+
UserMiddleware.isAnonymousRequest(buildRequest({ userType: userType })),
|
|
249
|
+
).toBe(expected);
|
|
250
|
+
},
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
/*
|
|
254
|
+
* The decision keys on userType alone, which is what getUserMiddleware
|
|
255
|
+
* sets. Stray session-shaped data on a Public request (a tenant, a
|
|
256
|
+
* userAuthorization object, a permission map) must not promote it.
|
|
257
|
+
*/
|
|
258
|
+
test("ignores session-shaped data on a Public request", () => {
|
|
259
|
+
expect(
|
|
260
|
+
UserMiddleware.isAnonymousRequest(
|
|
261
|
+
buildRequest({
|
|
262
|
+
userType: UserType.Public,
|
|
263
|
+
tenantId: PROJECT_ID,
|
|
264
|
+
userAuthorization: { userId: USER_ID },
|
|
265
|
+
userTenantAccessPermission: tenantPermission({
|
|
266
|
+
projectId: PROJECT_ID,
|
|
267
|
+
permissions: [Permission.ProjectOwner],
|
|
268
|
+
}),
|
|
269
|
+
}),
|
|
270
|
+
),
|
|
271
|
+
).toBe(true);
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
/*
|
|
275
|
+
* A master admin session carries no userId requirement here, and an API
|
|
276
|
+
* key carries no userId at all. Neither is anonymous.
|
|
277
|
+
*/
|
|
278
|
+
test("does not need a userId to call a request credentialed", () => {
|
|
279
|
+
expect(
|
|
280
|
+
UserMiddleware.isAnonymousRequest(
|
|
281
|
+
buildRequest({ userType: UserType.API }),
|
|
282
|
+
),
|
|
283
|
+
).toBe(false);
|
|
284
|
+
expect(
|
|
285
|
+
UserMiddleware.isAnonymousRequest(
|
|
286
|
+
buildRequest({ userType: UserType.MasterAdmin }),
|
|
287
|
+
),
|
|
288
|
+
).toBe(false);
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
describe("UserMiddleware.requireUserAuthentication", () => {
|
|
293
|
+
test.each([
|
|
294
|
+
["no userType", undefined],
|
|
295
|
+
["UserType.Public", UserType.Public],
|
|
296
|
+
])(
|
|
297
|
+
"answers a request with %s with a 401",
|
|
298
|
+
async (_label: string, userType: UserType | undefined) => {
|
|
299
|
+
const result: MiddlewareCallResult = await callMiddleware(
|
|
300
|
+
UserMiddleware.requireUserAuthentication as MiddlewareFunction,
|
|
301
|
+
buildRequest({ userType: userType, tenantId: PROJECT_ID }),
|
|
302
|
+
);
|
|
303
|
+
|
|
304
|
+
expectUnauthenticated(result);
|
|
305
|
+
},
|
|
306
|
+
);
|
|
307
|
+
|
|
308
|
+
test.each([
|
|
309
|
+
["a signed-in user", UserType.User, { userId: USER_ID }],
|
|
310
|
+
["a project API key", UserType.API, undefined],
|
|
311
|
+
[
|
|
312
|
+
"a master admin",
|
|
313
|
+
UserType.MasterAdmin,
|
|
314
|
+
{ userId: USER_ID, isMasterAdmin: true },
|
|
315
|
+
],
|
|
316
|
+
])(
|
|
317
|
+
"lets %s through",
|
|
318
|
+
async (
|
|
319
|
+
_label: string,
|
|
320
|
+
userType: UserType,
|
|
321
|
+
userAuthorization: Partial<JSONWebTokenData> | undefined,
|
|
322
|
+
) => {
|
|
323
|
+
const result: MiddlewareCallResult = await callMiddleware(
|
|
324
|
+
UserMiddleware.requireUserAuthentication as MiddlewareFunction,
|
|
325
|
+
buildRequest({
|
|
326
|
+
userType: userType,
|
|
327
|
+
tenantId: PROJECT_ID,
|
|
328
|
+
userAuthorization: userAuthorization,
|
|
329
|
+
}),
|
|
330
|
+
);
|
|
331
|
+
|
|
332
|
+
expectPassed(result);
|
|
333
|
+
},
|
|
334
|
+
);
|
|
335
|
+
|
|
336
|
+
/*
|
|
337
|
+
* This guard is presence-only. Tenant and permission checks belong to
|
|
338
|
+
* whatever follows it, so a credentialed request with no tenant is still
|
|
339
|
+
* let through here - the refusal, if any, comes later and stays a 4xx the
|
|
340
|
+
* client treats as final.
|
|
341
|
+
*/
|
|
342
|
+
test("does not look at the tenant", async () => {
|
|
343
|
+
const result: MiddlewareCallResult = await callMiddleware(
|
|
344
|
+
UserMiddleware.requireUserAuthentication as MiddlewareFunction,
|
|
345
|
+
buildRequest({ userType: UserType.User, userAuthorization: {} }),
|
|
346
|
+
);
|
|
347
|
+
|
|
348
|
+
expectPassed(result);
|
|
349
|
+
});
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
describe("UserMiddleware.requirePermission", () => {
|
|
353
|
+
const guard: MiddlewareFunction = UserMiddleware.requirePermission({
|
|
354
|
+
permissions: [Permission.ProjectOwner, Permission.ProjectAdmin],
|
|
355
|
+
}) as MiddlewareFunction;
|
|
356
|
+
|
|
357
|
+
describe("an anonymous request", () => {
|
|
358
|
+
test.each([
|
|
359
|
+
["no userType", undefined],
|
|
360
|
+
["UserType.Public", UserType.Public],
|
|
361
|
+
])(
|
|
362
|
+
"with %s and a tenant gets a 401",
|
|
363
|
+
async (_label: string, userType: UserType | undefined) => {
|
|
364
|
+
const result: MiddlewareCallResult = await callMiddleware(
|
|
365
|
+
guard,
|
|
366
|
+
buildRequest({ userType: userType, tenantId: PROJECT_ID }),
|
|
367
|
+
);
|
|
368
|
+
|
|
369
|
+
expectUnauthenticated(result);
|
|
370
|
+
},
|
|
371
|
+
);
|
|
372
|
+
|
|
373
|
+
/*
|
|
374
|
+
* The ordering this change is about. This request used to get
|
|
375
|
+
* "Project ID is required to access this resource." (422). The tenantid
|
|
376
|
+
* header is the Dashboard's, not the session's, so its absence says
|
|
377
|
+
* nothing about why the caller is anonymous - and a 422 here would stop
|
|
378
|
+
* the client from refreshing a session that is merely expired.
|
|
379
|
+
*/
|
|
380
|
+
test.each([
|
|
381
|
+
["no userType", undefined],
|
|
382
|
+
["UserType.Public", UserType.Public],
|
|
383
|
+
])(
|
|
384
|
+
"with %s and NO tenant still gets the 401, not the tenant 422",
|
|
385
|
+
async (_label: string, userType: UserType | undefined) => {
|
|
386
|
+
const result: MiddlewareCallResult = await callMiddleware(
|
|
387
|
+
guard,
|
|
388
|
+
buildRequest({ userType: userType }),
|
|
389
|
+
);
|
|
390
|
+
|
|
391
|
+
expectUnauthenticated(result);
|
|
392
|
+
expect(result.sentError?.message).not.toBe(
|
|
393
|
+
"Project ID is required to access this resource.",
|
|
394
|
+
);
|
|
395
|
+
},
|
|
396
|
+
);
|
|
397
|
+
|
|
398
|
+
/*
|
|
399
|
+
* Permission data that somehow survived onto an anonymous request is not
|
|
400
|
+
* a credential. Only userType is.
|
|
401
|
+
*/
|
|
402
|
+
test("gets a 401 even when it carries a matching permission map", async () => {
|
|
403
|
+
const result: MiddlewareCallResult = await callMiddleware(
|
|
404
|
+
guard,
|
|
405
|
+
buildRequest({
|
|
406
|
+
userType: UserType.Public,
|
|
407
|
+
tenantId: PROJECT_ID,
|
|
408
|
+
userTenantAccessPermission: tenantPermission({
|
|
409
|
+
projectId: PROJECT_ID,
|
|
410
|
+
permissions: [Permission.ProjectOwner],
|
|
411
|
+
}),
|
|
412
|
+
}),
|
|
413
|
+
);
|
|
414
|
+
|
|
415
|
+
expectUnauthenticated(result);
|
|
416
|
+
});
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
describe("a master admin", () => {
|
|
420
|
+
test("bypasses the tenant and permission checks", async () => {
|
|
421
|
+
const result: MiddlewareCallResult = await callMiddleware(
|
|
422
|
+
guard,
|
|
423
|
+
buildRequest({
|
|
424
|
+
userType: UserType.MasterAdmin,
|
|
425
|
+
userAuthorization: { userId: USER_ID, isMasterAdmin: true },
|
|
426
|
+
}),
|
|
427
|
+
);
|
|
428
|
+
|
|
429
|
+
expectPassed(result);
|
|
430
|
+
});
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
describe("a signed-in user (unchanged refusals)", () => {
|
|
434
|
+
test("without a tenant gets the 422 'Project ID is required'", async () => {
|
|
435
|
+
const result: MiddlewareCallResult = await callMiddleware(
|
|
436
|
+
guard,
|
|
437
|
+
buildRequest({
|
|
438
|
+
userType: UserType.User,
|
|
439
|
+
userAuthorization: { userId: USER_ID },
|
|
440
|
+
}),
|
|
441
|
+
);
|
|
442
|
+
|
|
443
|
+
expectNotAuthorized(
|
|
444
|
+
result,
|
|
445
|
+
"Project ID is required to access this resource.",
|
|
446
|
+
);
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
test("with no permissions in the tenant gets a 422", async () => {
|
|
450
|
+
const result: MiddlewareCallResult = await callMiddleware(
|
|
451
|
+
guard,
|
|
452
|
+
buildRequest({
|
|
453
|
+
userType: UserType.User,
|
|
454
|
+
tenantId: PROJECT_ID,
|
|
455
|
+
userAuthorization: { userId: USER_ID },
|
|
456
|
+
userTenantAccessPermission: tenantPermission({
|
|
457
|
+
projectId: OTHER_PROJECT_ID,
|
|
458
|
+
permissions: [Permission.ProjectOwner],
|
|
459
|
+
}),
|
|
460
|
+
}),
|
|
461
|
+
);
|
|
462
|
+
|
|
463
|
+
expectNotAuthorized(
|
|
464
|
+
result,
|
|
465
|
+
"You do not have permission to access this project.",
|
|
466
|
+
);
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
test("without the required permission gets a 422", async () => {
|
|
470
|
+
const result: MiddlewareCallResult = await callMiddleware(
|
|
471
|
+
guard,
|
|
472
|
+
buildRequest({
|
|
473
|
+
userType: UserType.User,
|
|
474
|
+
tenantId: PROJECT_ID,
|
|
475
|
+
userAuthorization: { userId: USER_ID },
|
|
476
|
+
userTenantAccessPermission: tenantPermission({
|
|
477
|
+
projectId: PROJECT_ID,
|
|
478
|
+
permissions: [Permission.ProjectMember],
|
|
479
|
+
}),
|
|
480
|
+
}),
|
|
481
|
+
);
|
|
482
|
+
|
|
483
|
+
expectNotAuthorized(
|
|
484
|
+
result,
|
|
485
|
+
"You do not have the required permission to perform this action.",
|
|
486
|
+
);
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
test.each([Permission.ProjectOwner, Permission.ProjectAdmin])(
|
|
490
|
+
"with %s is let through",
|
|
491
|
+
async (permission: Permission) => {
|
|
492
|
+
const result: MiddlewareCallResult = await callMiddleware(
|
|
493
|
+
guard,
|
|
494
|
+
buildRequest({
|
|
495
|
+
userType: UserType.User,
|
|
496
|
+
tenantId: PROJECT_ID,
|
|
497
|
+
userAuthorization: { userId: USER_ID },
|
|
498
|
+
userTenantAccessPermission: tenantPermission({
|
|
499
|
+
projectId: PROJECT_ID,
|
|
500
|
+
permissions: [Permission.ProjectMember, permission],
|
|
501
|
+
}),
|
|
502
|
+
}),
|
|
503
|
+
);
|
|
504
|
+
|
|
505
|
+
expectPassed(result);
|
|
506
|
+
},
|
|
507
|
+
);
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
/*
|
|
511
|
+
* A project API key is a credential: it is not anonymous, so it is judged
|
|
512
|
+
* on its tenant and permissions like a user, and keeps exactly the answers
|
|
513
|
+
* it had before this change.
|
|
514
|
+
*/
|
|
515
|
+
describe("a project API key (unchanged)", () => {
|
|
516
|
+
test("without a tenant gets the 422 'Project ID is required'", async () => {
|
|
517
|
+
const result: MiddlewareCallResult = await callMiddleware(
|
|
518
|
+
guard,
|
|
519
|
+
buildRequest({ userType: UserType.API }),
|
|
520
|
+
);
|
|
521
|
+
|
|
522
|
+
expectNotAuthorized(
|
|
523
|
+
result,
|
|
524
|
+
"Project ID is required to access this resource.",
|
|
525
|
+
);
|
|
526
|
+
});
|
|
527
|
+
|
|
528
|
+
test("with the required permission is let through", async () => {
|
|
529
|
+
const result: MiddlewareCallResult = await callMiddleware(
|
|
530
|
+
guard,
|
|
531
|
+
buildRequest({
|
|
532
|
+
userType: UserType.API,
|
|
533
|
+
tenantId: PROJECT_ID,
|
|
534
|
+
userTenantAccessPermission: tenantPermission({
|
|
535
|
+
projectId: PROJECT_ID,
|
|
536
|
+
permissions: [Permission.ProjectAdmin],
|
|
537
|
+
}),
|
|
538
|
+
}),
|
|
539
|
+
);
|
|
540
|
+
|
|
541
|
+
expectPassed(result);
|
|
542
|
+
});
|
|
543
|
+
|
|
544
|
+
test("without the required permission gets a 422", async () => {
|
|
545
|
+
const result: MiddlewareCallResult = await callMiddleware(
|
|
546
|
+
guard,
|
|
547
|
+
buildRequest({
|
|
548
|
+
userType: UserType.API,
|
|
549
|
+
tenantId: PROJECT_ID,
|
|
550
|
+
userTenantAccessPermission: tenantPermission({
|
|
551
|
+
projectId: PROJECT_ID,
|
|
552
|
+
permissions: [Permission.ProjectMember],
|
|
553
|
+
}),
|
|
554
|
+
}),
|
|
555
|
+
);
|
|
556
|
+
|
|
557
|
+
expectNotAuthorized(
|
|
558
|
+
result,
|
|
559
|
+
"You do not have the required permission to perform this action.",
|
|
560
|
+
);
|
|
561
|
+
});
|
|
562
|
+
});
|
|
563
|
+
});
|