@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.
Files changed (463) hide show
  1. package/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.ts +1 -1
  2. package/Models/DatabaseModels/ProjectOnCallCalendarFeed.ts +1 -1
  3. package/Models/DatabaseModels/UserOnCallCalendarFeed.ts +1 -1
  4. package/Server/API/AIBillingAPI.ts +1 -0
  5. package/Server/API/AIInsightAPI.ts +1 -4
  6. package/Server/API/AIInvestigationAPI.ts +1 -4
  7. package/Server/API/AIReadinessAPI.ts +4 -5
  8. package/Server/API/AlertAPI.ts +1 -0
  9. package/Server/API/AutoRemediationAPI.ts +1 -4
  10. package/Server/API/BaseAPI.ts +13 -0
  11. package/Server/API/BaseAnalyticsAPI.ts +80 -9
  12. package/Server/API/BillingAPI.ts +2 -0
  13. package/Server/API/BillingInvoiceAPI.ts +1 -0
  14. package/Server/API/BillingPaymentMethodAPI.ts +2 -0
  15. package/Server/API/CodeFixRunAPI.ts +1 -3
  16. package/Server/API/CommonAPI.ts +68 -4
  17. package/Server/API/DashboardAPI.ts +12 -12
  18. package/Server/API/GlobalConfigAPI.ts +17 -0
  19. package/Server/API/IncidentAPI.ts +2 -0
  20. package/Server/API/IncidentEpisodeAPI.ts +1 -0
  21. package/Server/API/NotificationAPI.ts +1 -0
  22. package/Server/API/OnCallCalendarAPI.ts +4 -5
  23. package/Server/API/OnCallDutyPolicyAPI.ts +7 -0
  24. package/Server/API/OnCallReadinessAPI.ts +4 -1
  25. package/Server/API/OnCallScheduleTimelineAPI.ts +731 -0
  26. package/Server/API/ProjectAPI.ts +1 -0
  27. package/Server/API/ScheduledMaintenanceAPI.ts +1 -0
  28. package/Server/API/StatusPageAPI.ts +161 -32
  29. package/Server/API/TeamMemberAPI.ts +3 -0
  30. package/Server/API/UserCallAPI.ts +2 -0
  31. package/Server/API/UserEmailAPI.ts +2 -0
  32. package/Server/API/UserIncomingCallNumberAPI.ts +2 -0
  33. package/Server/API/UserMicrosoftTeamsAPI.ts +1 -0
  34. package/Server/API/UserSlackAPI.ts +1 -0
  35. package/Server/API/UserSmsAPI.ts +2 -0
  36. package/Server/API/UserTotpAuthAPI.ts +1 -0
  37. package/Server/API/UserWebAuthnAPI.ts +2 -0
  38. package/Server/API/UserWebhookAPI.ts +1 -0
  39. package/Server/API/UserWhatsAppAPI.ts +2 -0
  40. package/Server/Middleware/MasterAdminAuthorization.ts +13 -2
  41. package/Server/Middleware/UserAuthorization.ts +79 -5
  42. package/Server/Services/ApiKeyPermissionService.ts +101 -4
  43. package/Server/Services/DatabaseService.ts +245 -0
  44. package/Server/Services/DetectionRuleService.ts +5 -4
  45. package/Server/Services/OnCallDutyPolicyChildService.ts +261 -0
  46. package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +2 -2
  47. package/Server/Services/OnCallDutyPolicyEscalationRuleService.ts +2 -2
  48. package/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.ts +2 -2
  49. package/Server/Services/OnCallDutyPolicyEscalationRuleUserService.ts +2 -2
  50. package/Server/Services/PayAsYouGoBillingService.ts +23 -28
  51. package/Server/Services/ProjectService.ts +18 -0
  52. package/Server/Services/RumSessionPinService.ts +274 -22
  53. package/Server/Services/TeamPermissionService.ts +120 -26
  54. package/Server/Services/ThreatIntelFeedService.ts +6 -3
  55. package/Server/Types/Database/Permissions/BasePermission.ts +9 -7
  56. package/Server/Types/Database/Permissions/Index.ts +75 -11
  57. package/Server/Types/Database/Permissions/TablePermission.ts +24 -28
  58. package/Server/Utils/AI/AIChatPrivacyFilter.ts +8 -0
  59. package/Server/Utils/AI/AIRunPrivacyFilter.ts +8 -0
  60. package/Server/Utils/MasterAdminPageAccess.ts +61 -0
  61. package/Server/Utils/Monitor/MonitorAlert.ts +3 -1
  62. package/Server/Utils/Monitor/MonitorIncident.ts +3 -1
  63. package/Server/Utils/OnCall/OnCallCalendarFeedRenderer.ts +1 -1
  64. package/Server/Utils/Realtime.ts +163 -45
  65. package/Server/Utils/SecurityEvent/DetectionRuleEvaluator.ts +11 -28
  66. package/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepair.ts +170 -0
  67. package/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.ts +1 -1
  68. package/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelFeedPoller.ts +6 -2
  69. package/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelMatcher.ts +10 -9
  70. package/Tests/App/Dashboard/AffectedResourcesPicker.test.tsx +1059 -0
  71. package/Tests/App/Dashboard/AffectedResourcesPickerEditForm.test.tsx +376 -0
  72. package/Tests/App/Dashboard/AffectedResourcesPickerHiddenTypes.test.tsx +757 -0
  73. package/Tests/App/Dashboard/AffectedResourcesSummaryStep.test.tsx +307 -0
  74. package/Tests/App/Dashboard/ArgumentsFormGroupByUnlistedAttributes.test.tsx +131 -0
  75. package/Tests/App/Dashboard/DashboardHeaderRequests.test.tsx +1 -1
  76. package/Tests/App/Dashboard/DashboardMonitorLabelVariable.test.tsx +9 -1
  77. package/Tests/App/Dashboard/DashboardVariableAllContract.test.tsx +24 -0
  78. package/Tests/App/Dashboard/DashboardVariableSelector.test.tsx +162 -8
  79. package/Tests/App/Dashboard/EntityFilterDropdownArchivedSlos.test.tsx +105 -6
  80. package/Tests/App/Dashboard/EntityFilterDropdownUnlistedSelection.test.tsx +434 -0
  81. package/Tests/App/Dashboard/EscalationRuleReadiness.test.tsx +276 -1
  82. package/Tests/App/Dashboard/OnCallCalendarFeedSideMenus.test.tsx +9 -1
  83. package/Tests/App/Dashboard/PayAsYouGoConsentGate.test.tsx +58 -42
  84. package/Tests/App/Dashboard/PayAsYouGoNotices.test.tsx +42 -5
  85. package/Tests/App/Dashboard/ResourceAuditLogsSideMenus.test.tsx +34 -23
  86. package/Tests/App/Dashboard/ScheduleTimeline.test.tsx +1580 -0
  87. package/Tests/App/Dashboard/ScheduleTimelineAPI.test.ts +280 -0
  88. package/Tests/App/Dashboard/ScheduleTimelineModel.test.ts +673 -0
  89. package/Tests/App/Dashboard/SecurityEventConnectionDiagnostics.test.tsx +95 -68
  90. package/Tests/App/Dashboard/SecurityEventsDetectionRulesPage.test.tsx +86 -3
  91. package/Tests/App/Dashboard/SecurityEventsEmptyState.test.tsx +28 -3
  92. package/Tests/App/Dashboard/SecurityEventsExplorer.test.tsx +761 -0
  93. package/Tests/App/Dashboard/SecurityEventsGuideContent.test.ts +1313 -0
  94. package/Tests/App/Dashboard/SecurityEventsHowItWorksCard.test.tsx +536 -0
  95. package/Tests/App/Dashboard/SecurityEventsNoResults.test.tsx +222 -0
  96. package/Tests/App/Dashboard/SecurityEventsThreatIntelPage.test.tsx +199 -0
  97. package/Tests/App/Dashboard/SecurityEventsVolumeChart.test.tsx +321 -0
  98. package/Tests/App/Dashboard/SloOverviewHero.test.tsx +171 -36
  99. package/Tests/App/Dashboard/SloViewSideMenu.test.tsx +215 -0
  100. package/Tests/App/Dashboard/SloViewSideMenuCounts.test.tsx +40 -3
  101. package/Tests/App/PublicDashboard/DashboardVariableSelector.test.tsx +12 -4
  102. package/Tests/App/PublicDashboard/PublicDashboardWidgetListAuth.test.tsx +623 -0
  103. package/Tests/Models/OnCallCalendarFeedModels.test.ts +23 -1
  104. package/Tests/Server/API/AIChatRouteAuthorization.test.ts +138 -5
  105. package/Tests/Server/API/AIGenerationProjectAIToggle.test.ts +187 -0
  106. package/Tests/Server/API/AIInvestigationAvailabilityAuthorization.test.ts +51 -3
  107. package/Tests/Server/API/AIInvestigationEvidenceAPI.test.ts +55 -2
  108. package/Tests/Server/API/BaseAnalyticsAPIAggregateCache.test.ts +729 -0
  109. package/Tests/Server/API/BillingPayAsYouGoStatus.test.ts +93 -7
  110. package/Tests/Server/API/BillingPaymentMethodAPI.test.ts +36 -3
  111. package/Tests/Server/API/CommonAPIAuthGuard.test.ts +1003 -24
  112. package/Tests/Server/API/DashboardPublicRateLimit.test.ts +6 -3
  113. package/Tests/Server/API/ExpiredSessionAIRoutes.test.ts +708 -0
  114. package/Tests/Server/API/ExpiredSessionCustomRoutes.test.ts +928 -0
  115. package/Tests/Server/API/ExpiredSessionMonitorTemplate.test.ts +319 -0
  116. package/Tests/Server/API/ExpiredSessionOnCallDutyPolicy.test.ts +336 -0
  117. package/Tests/Server/API/ExpiredSessionRouteGuards.test.ts +820 -0
  118. package/Tests/Server/API/GlobalConfigLicense.test.ts +140 -0
  119. package/Tests/Server/API/NotificationChannelVerificationAPI.test.ts +115 -12
  120. package/Tests/Server/API/OnCallCalendarAPI.test.ts +375 -8
  121. package/Tests/Server/API/OnCallReadinessAPI.test.ts +175 -17
  122. package/Tests/Server/API/OnCallScheduleTimelineAPI.test.ts +1513 -0
  123. package/Tests/Server/API/OnCallSetupReminderAPI.test.ts +119 -7
  124. package/Tests/Server/API/ProjectScopedCustomRouteAuth.test.ts +111 -4
  125. package/Tests/Server/API/PublicRouteInvalidAccessToken.test.ts +615 -0
  126. package/Tests/Server/API/SecurityEventAttributesAPI.test.ts +89 -2
  127. package/Tests/Server/API/SessionReplayAPI.test.ts +121 -0
  128. package/Tests/Server/API/StatusPageMasterPasswordRateLimit.test.ts +4 -2
  129. package/Tests/Server/API/StatusPagePostmortemVisibility.test.ts +441 -0
  130. package/Tests/Server/API/StatusPageTestEmailReportAuth.test.ts +664 -0
  131. package/Tests/Server/API/TeamMemberRemoveUserFromProjectAPI.test.ts +7 -0
  132. package/Tests/Server/API/UserIncomingCallNumberApi.test.ts +6 -0
  133. package/Tests/Server/API/UserNotificationSettingAPI.test.ts +65 -4
  134. package/Tests/Server/API/UserProjectsAPI.test.ts +63 -3
  135. package/Tests/Server/API/UserTotpAuthAPI.test.ts +48 -2
  136. package/Tests/Server/API/UserWebAuthnAuthenticationOptionsRoute.test.ts +11 -2
  137. package/Tests/Server/API/UserWebAuthnBackupCodeMinting.test.ts +46 -3
  138. package/Tests/Server/API/UserWebAuthnPasskeyAPI.test.ts +18 -2
  139. package/Tests/Server/API/ZZVerifyChatsAuth.test.ts +24 -7
  140. package/Tests/Server/Middleware/ExpiredSessionUserMiddleware.test.ts +563 -0
  141. package/Tests/Server/Middleware/MasterAdminAuthorization.test.ts +299 -19
  142. package/Tests/Server/Middleware/PublicRouteUserMiddleware.test.ts +453 -0
  143. package/Tests/Server/Services/AIChatPrivacyPin.test.ts +24 -0
  144. package/Tests/Server/Services/ApiKeyPermissionSecurity.test.ts +2 -0
  145. package/Tests/Server/Services/ApiKeyPermissionService.test.ts +3 -3
  146. package/Tests/Server/Services/DatabaseServiceCreateSuppliedId.test.ts +147 -0
  147. package/Tests/Server/Services/DatabaseServiceLoginBeforeHooks.test.ts +1078 -0
  148. package/Tests/Server/Services/DatabaseServiceTenantRelationGuard.test.ts +259 -0
  149. package/Tests/Server/Services/DatabaseServiceWriteOperatorValues.test.ts +147 -0
  150. package/Tests/Server/Services/MonitorPayAsYouGoBilling.test.ts +115 -1
  151. package/Tests/Server/Services/OnCallChildCreateAuthorizationPostgres.test.ts +711 -0
  152. package/Tests/Server/Services/OnCallDutyPolicyChildService.test.ts +733 -0
  153. package/Tests/Server/Services/PayAsYouGoBillingService.test.ts +190 -140
  154. package/Tests/Server/Services/PayAsYouGoStripeRateLimitBudget.test.ts +4 -9
  155. package/Tests/Server/Services/PermissionBlockDeletion.test.ts +780 -0
  156. package/Tests/Server/Services/PermissionBlockDeletionPostgres.test.ts +628 -0
  157. package/Tests/Server/Services/ProjectServiceCreateSubscriptionStarted.test.ts +77 -1
  158. package/Tests/Server/Services/RumSessionPinCreatePermission.test.ts +715 -0
  159. package/Tests/Server/Services/TeamMemberMultiTenantReadPostgres.test.ts +394 -0
  160. package/Tests/Server/Services/TeamPrivilegeEscalation.test.ts +6 -0
  161. package/Tests/Server/Services/TelemetryPayAsYouGoBilling.test.ts +131 -0
  162. package/Tests/Server/Services/UserNotificationRuleAdminGuards.test.ts +13 -2
  163. package/Tests/Server/Types/Database/Permissions/ModelPermissionAnonymousRefusal.test.ts +518 -0
  164. package/Tests/Server/Types/Database/Permissions/MultiTenantPermissions.test.ts +350 -0
  165. package/Tests/Server/Types/Database/Permissions/OnCallCalendarFeedPermissions.test.ts +282 -25
  166. package/Tests/Server/Types/Database/Permissions/TableLevelBlockPermission.test.ts +459 -0
  167. package/Tests/Server/Utils/AI/AIRunPrivacyFilter.test.ts +101 -9
  168. package/Tests/Server/Utils/AI/ChatAgentHelpers.test.ts +88 -4
  169. package/Tests/Server/Utils/AI/Toolbox/ExceptionTools.test.ts +459 -0
  170. package/Tests/Server/Utils/AI/Toolbox/LogTools.test.ts +794 -0
  171. package/Tests/Server/Utils/AI/Toolbox/RecentChangesTools.test.ts +574 -0
  172. package/Tests/Server/Utils/AI/Toolbox/SecurityEventTools.test.ts +596 -0
  173. package/Tests/Server/Utils/CaptchaRequestAndLogging.test.ts +395 -0
  174. package/Tests/Server/Utils/MasterAdminPageAccess.test.ts +251 -0
  175. package/Tests/Server/Utils/Monitor/MonitorActionTimestamps.test.ts +616 -0
  176. package/Tests/Server/Utils/Realtime.test.ts +502 -0
  177. package/Tests/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsConnectorSeverity.test.ts +216 -0
  178. package/Tests/Server/Utils/SecurityEvent/DetectionRuleEvaluator.test.ts +142 -0
  179. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepair.test.ts +140 -0
  180. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepairClickhouseIntegration.test.ts +542 -0
  181. package/Tests/Server/Utils/Telemetry/ChangeEventRow.test.ts +743 -0
  182. package/Tests/Server/Utils/Telemetry/RuntimeMetrics.test.ts +465 -0
  183. package/Tests/Server/Utils/Workspace/MicrosoftTeams/Messages/Alert.test.ts +202 -0
  184. package/Tests/Server/Utils/Workspace/MicrosoftTeams/Messages/Incident.test.ts +194 -0
  185. package/Tests/Server/Utils/Workspace/MicrosoftTeams/Messages/ScheduledMaintenance.test.ts +231 -0
  186. package/Tests/Server/Utils/Workspace/Slack/Messages/Alert.test.ts +194 -0
  187. package/Tests/Server/Utils/Workspace/Slack/Messages/AlertEpisode.test.ts +194 -0
  188. package/Tests/Server/Utils/Workspace/Slack/Messages/Incident.test.ts +194 -0
  189. package/Tests/Server/Utils/Workspace/Slack/Messages/IncidentEpisode.test.ts +194 -0
  190. package/Tests/Server/Utils/Workspace/Slack/Messages/ScheduledMaintenance.test.ts +247 -0
  191. package/Tests/Types/AI/AIInsightEvidence.test.ts +206 -0
  192. package/Tests/Types/BaseDatabase/DatabaseCommonInteractionPropsUtilAnonymous.test.ts +144 -0
  193. package/Tests/Types/Call/CallProvider.test.ts +528 -0
  194. package/Tests/Types/Kubernetes/KubernetesCostIngest.test.ts +236 -0
  195. package/Tests/Types/OnCallDutyPolicy/ScheduleTimeline.test.ts +736 -0
  196. package/Tests/Types/OnCallDutyPolicy/ScheduleTimelineLayout.test.ts +996 -0
  197. package/Tests/Types/SecurityEvent/SigmaRule.test.ts +142 -0
  198. package/Tests/Types/Workflow/Components/JSON.test.ts +182 -0
  199. package/Tests/UI/Components/BasicFormDropdownNormalization.test.tsx +116 -1
  200. package/Tests/UI/Components/Dropdown/DropdownAsyncOptions.test.tsx +81 -0
  201. package/Tests/UI/Components/EditionLabelLicenseRefresh.test.tsx +89 -1
  202. package/Tests/UI/Components/EventAttachmentList.test.tsx +174 -0
  203. package/Tests/UI/Components/Forms/BasicFormBurnRateTemplateDefaults.test.tsx +395 -0
  204. package/Tests/UI/Components/Forms/BasicFormCollapsibleSections.test.tsx +286 -0
  205. package/Tests/UI/Components/Forms/FormSummary.test.tsx +128 -0
  206. package/Tests/UI/Components/ModelTable/BaseModelTableQueryChange.test.tsx +365 -0
  207. package/Tests/UI/Components/OpenAuthenticatedUrl.test.ts +358 -0
  208. package/Tests/UI/Components/SessionAwareImage.test.tsx +496 -0
  209. package/Tests/UI/Components/TelemetryHistogramZeroBuckets.test.tsx +190 -0
  210. package/Tests/UI/Components/TooltipInteractive.test.tsx +97 -0
  211. package/Tests/UI/MicrosoftTeams/MicrosoftTeamsChatsCardInstallGuidance.test.tsx +1 -1
  212. package/Tests/UI/Monitor/EvaluationLogListTimestamps.test.tsx +367 -0
  213. package/Tests/UI/Utils/API/BaseAPIRefreshSession.test.ts +1087 -0
  214. package/Tests/UI/Utils/API/DashboardHost.ts +12 -0
  215. package/Tests/UI/Utils/API/FakeAxiosServer.ts +183 -0
  216. package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +10 -0
  217. package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +2 -0
  218. package/Tests/UI/Utils/Cookie.test.ts +440 -0
  219. package/Tests/UI/Utils/ModelAPIRequestClient.test.ts +278 -0
  220. package/Tests/UI/Utils/Navigation.test.ts +33 -0
  221. package/Tests/UI/Utils/PricingPlan.test.ts +295 -0
  222. package/Tests/UI/Utils/Realtime.test.ts +759 -0
  223. package/Tests/UI/Utils/Telemetry/Telemetry.test.ts +500 -0
  224. package/Tests/Utils/APIInstanceDispatch.test.ts +311 -0
  225. package/Tests/Utils/SecurityEvent/GoogleSecOpsAlertNormalizerSeverity.test.ts +565 -0
  226. package/Types/BaseDatabase/DatabaseCommonInteractionPropsUtil.ts +40 -0
  227. package/Types/Monitor/MonitorEvaluationSummary.ts +3 -0
  228. package/Types/OnCallDutyPolicy/ScheduleTimeline.ts +507 -0
  229. package/Types/OnCallDutyPolicy/ScheduleTimelineLayout.ts +589 -0
  230. package/Types/Realtime/EventName.ts +11 -0
  231. package/Types/SecurityEvent/DetectionFindingConstants.ts +14 -0
  232. package/Types/SecurityEvent/OcsfSeverity.ts +31 -26
  233. package/Types/SecurityEvent/SigmaRule.ts +51 -0
  234. package/Types/SecurityEvent/ThreatIntelConstants.ts +18 -0
  235. package/UI/Components/AttachmentList/EventAttachmentList.tsx +30 -2
  236. package/UI/Components/Dashboard/DashboardVariableControl.tsx +12 -2
  237. package/UI/Components/Dropdown/Dropdown.tsx +6 -1
  238. package/UI/Components/EditionLabel/EditionLabel.tsx +12 -0
  239. package/UI/Components/EventItem/EventItem.tsx +12 -1
  240. package/UI/Components/Forms/BasicForm.tsx +151 -126
  241. package/UI/Components/Forms/CollapsibleFormSection.tsx +63 -0
  242. package/UI/Components/Forms/Fields/FormField.tsx +10 -4
  243. package/UI/Components/Forms/FormSummary.tsx +7 -0
  244. package/UI/Components/Forms/Types/Field.ts +10 -0
  245. package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +2 -1
  246. package/UI/Components/Markdown.tsx/SessionAwareImage.tsx +122 -0
  247. package/UI/Components/ModelTable/BaseModelTable.tsx +34 -5
  248. package/UI/Components/ModelTable/TableView.tsx +1 -1
  249. package/UI/Components/TelemetryViewer/components/TelemetryHistogram.tsx +8 -1
  250. package/UI/Components/Tooltip/Tooltip.tsx +8 -1
  251. package/UI/Utils/API/API.ts +173 -12
  252. package/UI/Utils/API/RequestOptions.ts +11 -0
  253. package/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.ts +31 -7
  254. package/UI/Utils/ModelAPI/ModelAPI.ts +30 -9
  255. package/UI/Utils/Navigation.ts +9 -0
  256. package/UI/Utils/OpenAuthenticatedUrl.ts +154 -0
  257. package/UI/Utils/Realtime.ts +176 -30
  258. package/Utils/API.ts +14 -5
  259. package/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.ts +157 -7
  260. package/Utils/SecurityEvent/Sigma/SigmaRuleParser.ts +9 -17
  261. package/Utils/Slo/SloBurnRateTemplate.ts +2 -2
  262. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.js +1 -1
  263. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.js.map +1 -1
  264. package/build/dist/Models/DatabaseModels/ProjectOnCallCalendarFeed.js +1 -1
  265. package/build/dist/Models/DatabaseModels/ProjectOnCallCalendarFeed.js.map +1 -1
  266. package/build/dist/Models/DatabaseModels/UserOnCallCalendarFeed.js +1 -1
  267. package/build/dist/Models/DatabaseModels/UserOnCallCalendarFeed.js.map +1 -1
  268. package/build/dist/Server/API/AIBillingAPI.js +1 -1
  269. package/build/dist/Server/API/AIBillingAPI.js.map +1 -1
  270. package/build/dist/Server/API/AIInsightAPI.js +1 -4
  271. package/build/dist/Server/API/AIInsightAPI.js.map +1 -1
  272. package/build/dist/Server/API/AIInvestigationAPI.js +1 -4
  273. package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
  274. package/build/dist/Server/API/AIReadinessAPI.js +1 -3
  275. package/build/dist/Server/API/AIReadinessAPI.js.map +1 -1
  276. package/build/dist/Server/API/AlertAPI.js +1 -1
  277. package/build/dist/Server/API/AlertAPI.js.map +1 -1
  278. package/build/dist/Server/API/AutoRemediationAPI.js +1 -4
  279. package/build/dist/Server/API/AutoRemediationAPI.js.map +1 -1
  280. package/build/dist/Server/API/BaseAPI.js +12 -0
  281. package/build/dist/Server/API/BaseAPI.js.map +1 -1
  282. package/build/dist/Server/API/BaseAnalyticsAPI.js +55 -10
  283. package/build/dist/Server/API/BaseAnalyticsAPI.js.map +1 -1
  284. package/build/dist/Server/API/BillingAPI.js +2 -2
  285. package/build/dist/Server/API/BillingAPI.js.map +1 -1
  286. package/build/dist/Server/API/BillingInvoiceAPI.js +1 -1
  287. package/build/dist/Server/API/BillingInvoiceAPI.js.map +1 -1
  288. package/build/dist/Server/API/BillingPaymentMethodAPI.js +2 -2
  289. package/build/dist/Server/API/BillingPaymentMethodAPI.js.map +1 -1
  290. package/build/dist/Server/API/CodeFixRunAPI.js +1 -3
  291. package/build/dist/Server/API/CodeFixRunAPI.js.map +1 -1
  292. package/build/dist/Server/API/CommonAPI.js +50 -5
  293. package/build/dist/Server/API/CommonAPI.js.map +1 -1
  294. package/build/dist/Server/API/DashboardAPI.js +12 -12
  295. package/build/dist/Server/API/DashboardAPI.js.map +1 -1
  296. package/build/dist/Server/API/GlobalConfigAPI.js +12 -0
  297. package/build/dist/Server/API/GlobalConfigAPI.js.map +1 -1
  298. package/build/dist/Server/API/IncidentAPI.js +2 -2
  299. package/build/dist/Server/API/IncidentAPI.js.map +1 -1
  300. package/build/dist/Server/API/IncidentEpisodeAPI.js +1 -1
  301. package/build/dist/Server/API/IncidentEpisodeAPI.js.map +1 -1
  302. package/build/dist/Server/API/NotificationAPI.js +1 -1
  303. package/build/dist/Server/API/NotificationAPI.js.map +1 -1
  304. package/build/dist/Server/API/OnCallCalendarAPI.js +1 -4
  305. package/build/dist/Server/API/OnCallCalendarAPI.js.map +1 -1
  306. package/build/dist/Server/API/OnCallDutyPolicyAPI.js +6 -0
  307. package/build/dist/Server/API/OnCallDutyPolicyAPI.js.map +1 -1
  308. package/build/dist/Server/API/OnCallReadinessAPI.js +4 -1
  309. package/build/dist/Server/API/OnCallReadinessAPI.js.map +1 -1
  310. package/build/dist/Server/API/OnCallScheduleTimelineAPI.js +494 -0
  311. package/build/dist/Server/API/OnCallScheduleTimelineAPI.js.map +1 -0
  312. package/build/dist/Server/API/ProjectAPI.js +1 -1
  313. package/build/dist/Server/API/ProjectAPI.js.map +1 -1
  314. package/build/dist/Server/API/ScheduledMaintenanceAPI.js +1 -1
  315. package/build/dist/Server/API/ScheduledMaintenanceAPI.js.map +1 -1
  316. package/build/dist/Server/API/StatusPageAPI.js +125 -33
  317. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  318. package/build/dist/Server/API/TeamMemberAPI.js +3 -3
  319. package/build/dist/Server/API/TeamMemberAPI.js.map +1 -1
  320. package/build/dist/Server/API/UserCallAPI.js +2 -2
  321. package/build/dist/Server/API/UserCallAPI.js.map +1 -1
  322. package/build/dist/Server/API/UserEmailAPI.js +2 -2
  323. package/build/dist/Server/API/UserEmailAPI.js.map +1 -1
  324. package/build/dist/Server/API/UserIncomingCallNumberAPI.js +2 -2
  325. package/build/dist/Server/API/UserIncomingCallNumberAPI.js.map +1 -1
  326. package/build/dist/Server/API/UserMicrosoftTeamsAPI.js +1 -1
  327. package/build/dist/Server/API/UserMicrosoftTeamsAPI.js.map +1 -1
  328. package/build/dist/Server/API/UserSlackAPI.js +1 -1
  329. package/build/dist/Server/API/UserSlackAPI.js.map +1 -1
  330. package/build/dist/Server/API/UserSmsAPI.js +2 -2
  331. package/build/dist/Server/API/UserSmsAPI.js.map +1 -1
  332. package/build/dist/Server/API/UserTotpAuthAPI.js +1 -1
  333. package/build/dist/Server/API/UserTotpAuthAPI.js.map +1 -1
  334. package/build/dist/Server/API/UserWebAuthnAPI.js +2 -2
  335. package/build/dist/Server/API/UserWebAuthnAPI.js.map +1 -1
  336. package/build/dist/Server/API/UserWebhookAPI.js +1 -1
  337. package/build/dist/Server/API/UserWebhookAPI.js.map +1 -1
  338. package/build/dist/Server/API/UserWhatsAppAPI.js +2 -2
  339. package/build/dist/Server/API/UserWhatsAppAPI.js.map +1 -1
  340. package/build/dist/Server/Middleware/MasterAdminAuthorization.js +11 -2
  341. package/build/dist/Server/Middleware/MasterAdminAuthorization.js.map +1 -1
  342. package/build/dist/Server/Middleware/UserAuthorization.js +64 -4
  343. package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
  344. package/build/dist/Server/Services/ApiKeyPermissionService.js +80 -4
  345. package/build/dist/Server/Services/ApiKeyPermissionService.js.map +1 -1
  346. package/build/dist/Server/Services/DatabaseService.js +171 -0
  347. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  348. package/build/dist/Server/Services/DetectionRuleService.js +4 -4
  349. package/build/dist/Server/Services/DetectionRuleService.js.map +1 -1
  350. package/build/dist/Server/Services/OnCallDutyPolicyChildService.js +170 -0
  351. package/build/dist/Server/Services/OnCallDutyPolicyChildService.js.map +1 -0
  352. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +2 -2
  353. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
  354. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js +2 -2
  355. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js.map +1 -1
  356. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.js +2 -2
  357. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.js.map +1 -1
  358. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js +2 -2
  359. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js.map +1 -1
  360. package/build/dist/Server/Services/PayAsYouGoBillingService.js +20 -27
  361. package/build/dist/Server/Services/PayAsYouGoBillingService.js.map +1 -1
  362. package/build/dist/Server/Services/ProjectService.js +17 -0
  363. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  364. package/build/dist/Server/Services/RumSessionPinService.js +180 -16
  365. package/build/dist/Server/Services/RumSessionPinService.js.map +1 -1
  366. package/build/dist/Server/Services/TeamPermissionService.js +89 -27
  367. package/build/dist/Server/Services/TeamPermissionService.js.map +1 -1
  368. package/build/dist/Server/Services/ThreatIntelFeedService.js +5 -4
  369. package/build/dist/Server/Services/ThreatIntelFeedService.js.map +1 -1
  370. package/build/dist/Server/Types/Database/Permissions/BasePermission.js +9 -6
  371. package/build/dist/Server/Types/Database/Permissions/BasePermission.js.map +1 -1
  372. package/build/dist/Server/Types/Database/Permissions/Index.js +60 -6
  373. package/build/dist/Server/Types/Database/Permissions/Index.js.map +1 -1
  374. package/build/dist/Server/Types/Database/Permissions/TablePermission.js +14 -13
  375. package/build/dist/Server/Types/Database/Permissions/TablePermission.js.map +1 -1
  376. package/build/dist/Server/Utils/AI/AIChatPrivacyFilter.js +7 -0
  377. package/build/dist/Server/Utils/AI/AIChatPrivacyFilter.js.map +1 -1
  378. package/build/dist/Server/Utils/AI/AIRunPrivacyFilter.js +7 -0
  379. package/build/dist/Server/Utils/AI/AIRunPrivacyFilter.js.map +1 -1
  380. package/build/dist/Server/Utils/MasterAdminPageAccess.js +39 -0
  381. package/build/dist/Server/Utils/MasterAdminPageAccess.js.map +1 -0
  382. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +3 -1
  383. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  384. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +3 -1
  385. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  386. package/build/dist/Server/Utils/Realtime.js +126 -37
  387. package/build/dist/Server/Utils/Realtime.js.map +1 -1
  388. package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js +7 -25
  389. package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js.map +1 -1
  390. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepair.js +127 -0
  391. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepair.js.map +1 -0
  392. package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js +1 -1
  393. package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js.map +1 -1
  394. package/build/dist/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelFeedPoller.js +3 -2
  395. package/build/dist/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelFeedPoller.js.map +1 -1
  396. package/build/dist/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelMatcher.js +4 -8
  397. package/build/dist/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelMatcher.js.map +1 -1
  398. package/build/dist/Types/BaseDatabase/DatabaseCommonInteractionPropsUtil.js +31 -1
  399. package/build/dist/Types/BaseDatabase/DatabaseCommonInteractionPropsUtil.js.map +1 -1
  400. package/build/dist/Types/OnCallDutyPolicy/ScheduleTimeline.js +321 -0
  401. package/build/dist/Types/OnCallDutyPolicy/ScheduleTimeline.js.map +1 -0
  402. package/build/dist/Types/OnCallDutyPolicy/ScheduleTimelineLayout.js +372 -0
  403. package/build/dist/Types/OnCallDutyPolicy/ScheduleTimelineLayout.js.map +1 -0
  404. package/build/dist/Types/Realtime/EventName.js +10 -0
  405. package/build/dist/Types/Realtime/EventName.js.map +1 -1
  406. package/build/dist/Types/SecurityEvent/DetectionFindingConstants.js +11 -0
  407. package/build/dist/Types/SecurityEvent/DetectionFindingConstants.js.map +1 -1
  408. package/build/dist/Types/SecurityEvent/OcsfSeverity.js +30 -25
  409. package/build/dist/Types/SecurityEvent/OcsfSeverity.js.map +1 -1
  410. package/build/dist/Types/SecurityEvent/SigmaRule.js +47 -0
  411. package/build/dist/Types/SecurityEvent/SigmaRule.js.map +1 -1
  412. package/build/dist/Types/SecurityEvent/ThreatIntelConstants.js +14 -0
  413. package/build/dist/Types/SecurityEvent/ThreatIntelConstants.js.map +1 -1
  414. package/build/dist/UI/Components/AttachmentList/EventAttachmentList.js +9 -4
  415. package/build/dist/UI/Components/AttachmentList/EventAttachmentList.js.map +1 -1
  416. package/build/dist/UI/Components/Dashboard/DashboardVariableControl.js +10 -2
  417. package/build/dist/UI/Components/Dashboard/DashboardVariableControl.js.map +1 -1
  418. package/build/dist/UI/Components/Dropdown/Dropdown.js +5 -1
  419. package/build/dist/UI/Components/Dropdown/Dropdown.js.map +1 -1
  420. package/build/dist/UI/Components/EditionLabel/EditionLabel.js +11 -0
  421. package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
  422. package/build/dist/UI/Components/EventItem/EventItem.js +2 -2
  423. package/build/dist/UI/Components/EventItem/EventItem.js.map +1 -1
  424. package/build/dist/UI/Components/Forms/BasicForm.js +70 -64
  425. package/build/dist/UI/Components/Forms/BasicForm.js.map +1 -1
  426. package/build/dist/UI/Components/Forms/CollapsibleFormSection.js +27 -0
  427. package/build/dist/UI/Components/Forms/CollapsibleFormSection.js.map +1 -0
  428. package/build/dist/UI/Components/Forms/Fields/FormField.js +10 -7
  429. package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
  430. package/build/dist/UI/Components/Forms/FormSummary.js +7 -0
  431. package/build/dist/UI/Components/Forms/FormSummary.js.map +1 -1
  432. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +2 -1
  433. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
  434. package/build/dist/UI/Components/Markdown.tsx/SessionAwareImage.js +84 -0
  435. package/build/dist/UI/Components/Markdown.tsx/SessionAwareImage.js.map +1 -0
  436. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +14 -1
  437. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  438. package/build/dist/UI/Components/ModelTable/TableView.js +1 -1
  439. package/build/dist/UI/Components/ModelTable/TableView.js.map +1 -1
  440. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js +8 -1
  441. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js.map +1 -1
  442. package/build/dist/UI/Components/Tooltip/Tooltip.js +2 -1
  443. package/build/dist/UI/Components/Tooltip/Tooltip.js.map +1 -1
  444. package/build/dist/UI/Utils/API/API.js +143 -19
  445. package/build/dist/UI/Utils/API/API.js.map +1 -1
  446. package/build/dist/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.js +21 -7
  447. package/build/dist/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.js.map +1 -1
  448. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js +26 -9
  449. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js.map +1 -1
  450. package/build/dist/UI/Utils/Navigation.js +8 -0
  451. package/build/dist/UI/Utils/Navigation.js.map +1 -1
  452. package/build/dist/UI/Utils/OpenAuthenticatedUrl.js +92 -0
  453. package/build/dist/UI/Utils/OpenAuthenticatedUrl.js.map +1 -0
  454. package/build/dist/UI/Utils/Realtime.js +120 -15
  455. package/build/dist/UI/Utils/Realtime.js.map +1 -1
  456. package/build/dist/Utils/API.js +13 -5
  457. package/build/dist/Utils/API.js.map +1 -1
  458. package/build/dist/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.js +123 -6
  459. package/build/dist/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.js.map +1 -1
  460. package/build/dist/Utils/SecurityEvent/Sigma/SigmaRuleParser.js +4 -18
  461. package/build/dist/Utils/SecurityEvent/Sigma/SigmaRuleParser.js.map +1 -1
  462. package/build/dist/Utils/Slo/SloBurnRateTemplate.js +2 -2
  463. package/package.json +1 -1
@@ -0,0 +1,453 @@
1
+ import { EncryptionSecret } from "../../../Server/EnvironmentConfig";
2
+ import ProjectMiddleware from "../../../Server/Middleware/ProjectAuthorization";
3
+ import UserMiddleware from "../../../Server/Middleware/UserAuthorization";
4
+ import AccessTokenService from "../../../Server/Services/AccessTokenService";
5
+ import ProjectService from "../../../Server/Services/ProjectService";
6
+ import UserService from "../../../Server/Services/UserService";
7
+ import {
8
+ ExpressResponse,
9
+ NextFunction,
10
+ OneUptimeRequest,
11
+ } from "../../../Server/Utils/Express";
12
+ import JSONWebToken from "../../../Server/Utils/JsonWebToken";
13
+ import logger from "../../../Server/Utils/Logger";
14
+ import Response from "../../../Server/Utils/Response";
15
+ import Dictionary from "../../../Types/Dictionary";
16
+ import Email from "../../../Types/Email";
17
+ import Exception from "../../../Types/Exception/Exception";
18
+ import NotAuthenticatedException from "../../../Types/Exception/NotAuthenticatedException";
19
+ import Name from "../../../Types/Name";
20
+ import ObjectID from "../../../Types/ObjectID";
21
+ import { UserGlobalAccessPermission } from "../../../Types/Permission";
22
+ import UserType from "../../../Types/UserType";
23
+ import { getJestSpyOn } from "../../Spy";
24
+ import { afterEach, beforeEach, describe, expect, test } from "@jest/globals";
25
+ import jwt from "jsonwebtoken";
26
+
27
+ /*
28
+ * getPublicRouteUserMiddleware: getUserMiddleware for the public dashboard and
29
+ * public status page routes.
30
+ *
31
+ * THE BUG
32
+ *
33
+ * The host-wide dashboard access-token cookie reaches the public routes
34
+ * whenever the page is served from the dashboard's host. When that cookie is
35
+ * still in the browser but no longer decodes - the encryption secret was
36
+ * rotated, say - getUserMiddleware answered 401 "AccessToken is invalid or
37
+ * expired" before the route ever asked whether the dashboard was public. The
38
+ * public clients cannot refresh a dashboard session, so the 401 went straight
39
+ * to the login redirect: a reload loop on the preview route, and a password
40
+ * prompt for a master password the viewer had already entered.
41
+ *
42
+ * WHAT THIS FILE PINS
43
+ *
44
+ * 1. On the public variant, a token that does not decode is anonymity, not
45
+ * a refusal: UserType.Public, no identity, next().
46
+ * 2. Everything else is getUserMiddleware's behaviour: a good token is
47
+ * resolved the same way, an API key is still validated, no token is
48
+ * still anonymous.
49
+ * 3. getUserMiddleware itself, which every authenticated route mounts,
50
+ * still answers the same tokens with a 401.
51
+ *
52
+ * Tokens are signed and decoded with the real JSONWebToken, so "does not
53
+ * decode" means exactly what it means in production.
54
+ */
55
+
56
+ const INVALID_ACCESS_TOKEN_MESSAGE: string =
57
+ "AccessToken is invalid or expired. Please refresh your token.";
58
+
59
+ const USER_ID: ObjectID = new ObjectID("33333333-3333-4333-8333-333333333333");
60
+
61
+ type TokenPayloadFunction = () => Dictionary<string | boolean>;
62
+
63
+ const tokenPayload: TokenPayloadFunction = (): Dictionary<string | boolean> => {
64
+ return {
65
+ userId: USER_ID.toString(),
66
+ email: "viewer@example.com",
67
+ name: "Viewer",
68
+ isMasterAdmin: false,
69
+ isGlobalLogin: true,
70
+ sessionId: ObjectID.generate().toString(),
71
+ };
72
+ };
73
+
74
+ /*
75
+ * Each one well-formed enough to be sent as a session, none of them one this
76
+ * instance will accept.
77
+ */
78
+ const UNDECODABLE_TOKENS: Array<[string, () => string]> = [
79
+ [
80
+ "a token signed with a rotated-out encryption secret",
81
+ (): string => {
82
+ return jwt.sign(
83
+ tokenPayload(),
84
+ `${EncryptionSecret.toString()}-before-rotation`,
85
+ { expiresIn: 15 * 60 },
86
+ );
87
+ },
88
+ ],
89
+ [
90
+ "an expired token",
91
+ (): string => {
92
+ return jwt.sign(tokenPayload(), EncryptionSecret.toString(), {
93
+ expiresIn: -60,
94
+ });
95
+ },
96
+ ],
97
+ [
98
+ "a value that is not a JWT at all",
99
+ (): string => {
100
+ return "not-a-jwt";
101
+ },
102
+ ],
103
+ ];
104
+
105
+ type SignValidTokenFunction = (data?: { isMasterAdmin?: boolean }) => string;
106
+
107
+ const signValidToken: SignValidTokenFunction = (data?: {
108
+ isMasterAdmin?: boolean;
109
+ }): string => {
110
+ return JSONWebToken.signUserLoginToken({
111
+ tokenData: {
112
+ userId: USER_ID,
113
+ email: new Email("viewer@example.com"),
114
+ name: new Name("Viewer"),
115
+ timezone: null,
116
+ isMasterAdmin: Boolean(data?.isMasterAdmin),
117
+ isGlobalLogin: true,
118
+ sessionId: ObjectID.generate(),
119
+ },
120
+ expiresInSeconds: 15 * 60,
121
+ });
122
+ };
123
+
124
+ type BuildRequestFunction = (data: {
125
+ cookies?: Dictionary<string>;
126
+ headers?: Dictionary<string>;
127
+ }) => OneUptimeRequest;
128
+
129
+ /*
130
+ * Shaped like a public client's request: the public dashboard and status page
131
+ * clients send an empty tenantid header, so no tenant is resolved.
132
+ */
133
+ const buildRequest: BuildRequestFunction = (data: {
134
+ cookies?: Dictionary<string>;
135
+ headers?: Dictionary<string>;
136
+ }): OneUptimeRequest => {
137
+ return {
138
+ params: {},
139
+ query: {},
140
+ body: {},
141
+ cookies: data.cookies || {},
142
+ headers: { tenantid: "", ...(data.headers || {}) },
143
+ } as unknown as OneUptimeRequest;
144
+ };
145
+
146
+ type MiddlewareFunction = (
147
+ req: OneUptimeRequest,
148
+ res: ExpressResponse,
149
+ next: NextFunction,
150
+ ) => Promise<void>;
151
+
152
+ type MiddlewareCallResult = {
153
+ nextCalls: Array<Array<unknown>>;
154
+ sentError: Exception | undefined;
155
+ sendErrorCallCount: number;
156
+ headersSet: Array<Array<unknown>>;
157
+ };
158
+
159
+ type CallMiddlewareFunction = (
160
+ middleware: MiddlewareFunction,
161
+ req: OneUptimeRequest,
162
+ ) => Promise<MiddlewareCallResult>;
163
+
164
+ const callMiddleware: CallMiddlewareFunction = async (
165
+ middleware: MiddlewareFunction,
166
+ req: OneUptimeRequest,
167
+ ): Promise<MiddlewareCallResult> => {
168
+ const set: jest.Mock = jest.fn();
169
+ const res: ExpressResponse = { set } as unknown as ExpressResponse;
170
+ const next: jest.Mock = jest.fn();
171
+
172
+ await middleware(req, res, next as unknown as NextFunction);
173
+
174
+ const errorCalls: Array<Array<unknown>> = (
175
+ Response.sendErrorResponse as unknown as jest.Mock
176
+ ).mock.calls as Array<Array<unknown>>;
177
+
178
+ return {
179
+ nextCalls: next.mock.calls as Array<Array<unknown>>,
180
+ sentError: errorCalls[0]?.[2] as Exception | undefined,
181
+ sendErrorCallCount: errorCalls.length,
182
+ headersSet: set.mock.calls as Array<Array<unknown>>,
183
+ };
184
+ };
185
+
186
+ type ExpectServedAnonymouslyFunction = (
187
+ result: MiddlewareCallResult,
188
+ req: OneUptimeRequest,
189
+ ) => void;
190
+
191
+ const expectServedAnonymously: ExpectServedAnonymouslyFunction = (
192
+ result: MiddlewareCallResult,
193
+ req: OneUptimeRequest,
194
+ ): void => {
195
+ expect(result.sendErrorCallCount).toBe(0);
196
+ expect(result.nextCalls).toHaveLength(1);
197
+ // next() with an argument is Express's error path, not a pass.
198
+ expect(result.nextCalls[0]).toEqual([]);
199
+ expect(req.userType).toBe(UserType.Public);
200
+ expect(req.userAuthorization).toBeUndefined();
201
+ expect(UserMiddleware.isAnonymousRequest(req)).toBe(true);
202
+ };
203
+
204
+ type ExpectInvalidTokenRefusalFunction = (result: MiddlewareCallResult) => void;
205
+
206
+ const expectInvalidTokenRefusal: ExpectInvalidTokenRefusalFunction = (
207
+ result: MiddlewareCallResult,
208
+ ): void => {
209
+ expect(result.nextCalls).toHaveLength(0);
210
+ expect(result.sendErrorCallCount).toBe(1);
211
+ expect(result.sentError).toBeInstanceOf(NotAuthenticatedException);
212
+ expect(result.sentError?.code).toBe(401);
213
+ expect(result.sentError?.message).toBe(INVALID_ACCESS_TOKEN_MESSAGE);
214
+ };
215
+
216
+ const GLOBAL_PERMISSION: UserGlobalAccessPermission = {
217
+ _type: "UserGlobalAccessPermission",
218
+ projectIds: [],
219
+ globalPermissions: [],
220
+ };
221
+
222
+ let getUserGlobalAccessPermission: jest.SpyInstance;
223
+ let userUpdateLastActive: jest.SpyInstance;
224
+
225
+ beforeEach(() => {
226
+ jest.clearAllMocks();
227
+
228
+ getJestSpyOn(Response, "sendErrorResponse").mockImplementation(() => {
229
+ return undefined as never;
230
+ });
231
+ // JSONWebToken.decode logs every token it refuses.
232
+ getJestSpyOn(logger, "error").mockImplementation(() => {
233
+ return undefined;
234
+ });
235
+
236
+ getUserGlobalAccessPermission = getJestSpyOn(
237
+ AccessTokenService,
238
+ "getUserGlobalAccessPermission",
239
+ ).mockResolvedValue(GLOBAL_PERMISSION);
240
+ userUpdateLastActive = getJestSpyOn(
241
+ UserService,
242
+ "updateLastActive",
243
+ ).mockResolvedValue(undefined);
244
+ getJestSpyOn(ProjectService, "updateLastActive").mockResolvedValue(undefined);
245
+ });
246
+
247
+ afterEach(() => {
248
+ jest.restoreAllMocks();
249
+ });
250
+
251
+ describe("UserMiddleware.getPublicRouteUserMiddleware", () => {
252
+ describe("with an access token that does not decode", () => {
253
+ test.each(UNDECODABLE_TOKENS)(
254
+ "serves %s in the access-token cookie anonymously",
255
+ async (_label: string, token: () => string) => {
256
+ const req: OneUptimeRequest = buildRequest({
257
+ cookies: { "user-token": token() },
258
+ });
259
+
260
+ const result: MiddlewareCallResult = await callMiddleware(
261
+ UserMiddleware.getPublicRouteUserMiddleware as MiddlewareFunction,
262
+ req,
263
+ );
264
+
265
+ expectServedAnonymously(result, req);
266
+ },
267
+ );
268
+
269
+ test.each(UNDECODABLE_TOKENS)(
270
+ "serves %s in an Authorization: Bearer header anonymously",
271
+ async (_label: string, token: () => string) => {
272
+ const req: OneUptimeRequest = buildRequest({
273
+ headers: { authorization: `Bearer ${token()}` },
274
+ });
275
+
276
+ const result: MiddlewareCallResult = await callMiddleware(
277
+ UserMiddleware.getPublicRouteUserMiddleware as MiddlewareFunction,
278
+ req,
279
+ );
280
+
281
+ expectServedAnonymously(result, req);
282
+ },
283
+ );
284
+
285
+ /*
286
+ * Anonymous means anonymous: nothing about the undecodable token's
287
+ * claimed user is looked up, recorded, or sent back.
288
+ */
289
+ test("resolves no user, records no activity and sets no permission headers", async () => {
290
+ const req: OneUptimeRequest = buildRequest({
291
+ cookies: { "user-token": "not-a-jwt" },
292
+ });
293
+
294
+ const result: MiddlewareCallResult = await callMiddleware(
295
+ UserMiddleware.getPublicRouteUserMiddleware as MiddlewareFunction,
296
+ req,
297
+ );
298
+
299
+ expect(getUserGlobalAccessPermission).not.toHaveBeenCalled();
300
+ expect(userUpdateLastActive).not.toHaveBeenCalled();
301
+ expect(result.headersSet).toEqual([]);
302
+ expect(req.userGlobalAccessPermission).toBeUndefined();
303
+ expect(req.userTenantAccessPermission).toBeUndefined();
304
+ });
305
+
306
+ /*
307
+ * The request comes out exactly as anonymous as one with no token, so a
308
+ * guard behind it still refuses it. Mounting this middleware by mistake
309
+ * in front of an authenticated handler cannot promote a dead session.
310
+ */
311
+ test("leaves a request that requireUserAuthentication still refuses", async () => {
312
+ const req: OneUptimeRequest = buildRequest({
313
+ cookies: { "user-token": "not-a-jwt" },
314
+ });
315
+
316
+ await callMiddleware(
317
+ UserMiddleware.getPublicRouteUserMiddleware as MiddlewareFunction,
318
+ req,
319
+ );
320
+
321
+ const guarded: MiddlewareCallResult = await callMiddleware(
322
+ UserMiddleware.requireUserAuthentication as MiddlewareFunction,
323
+ req,
324
+ );
325
+
326
+ expect(guarded.nextCalls).toHaveLength(0);
327
+ expect(guarded.sentError).toBeInstanceOf(NotAuthenticatedException);
328
+ expect(guarded.sentError?.message).toBe(
329
+ UserMiddleware.AUTHENTICATION_REQUIRED_MESSAGE,
330
+ );
331
+ });
332
+ });
333
+
334
+ describe("otherwise behaves exactly like getUserMiddleware", () => {
335
+ test.each([
336
+ ["a signed-in user", false, UserType.User],
337
+ ["a master admin", true, UserType.MasterAdmin],
338
+ ])(
339
+ "resolves %s from a token that decodes",
340
+ async (_label: string, isMasterAdmin: boolean, userType: UserType) => {
341
+ const token: string = signValidToken({ isMasterAdmin });
342
+
343
+ const publicReq: OneUptimeRequest = buildRequest({
344
+ cookies: { "user-token": token },
345
+ });
346
+ const strictReq: OneUptimeRequest = buildRequest({
347
+ cookies: { "user-token": token },
348
+ });
349
+
350
+ const publicResult: MiddlewareCallResult = await callMiddleware(
351
+ UserMiddleware.getPublicRouteUserMiddleware as MiddlewareFunction,
352
+ publicReq,
353
+ );
354
+ const strictResult: MiddlewareCallResult = await callMiddleware(
355
+ UserMiddleware.getUserMiddleware as MiddlewareFunction,
356
+ strictReq,
357
+ );
358
+
359
+ expect(publicResult.sendErrorCallCount).toBe(0);
360
+ expect(publicResult.nextCalls).toEqual([[]]);
361
+ expect(publicReq.userType).toBe(userType);
362
+ expect(publicReq.userAuthorization?.userId.toString()).toBe(
363
+ USER_ID.toString(),
364
+ );
365
+ expect(publicReq.userGlobalAccessPermission).toEqual(GLOBAL_PERMISSION);
366
+
367
+ expect(publicReq.userType).toBe(strictReq.userType);
368
+ expect(publicReq.userAuthorization).toEqual(
369
+ strictReq.userAuthorization,
370
+ );
371
+ expect(publicReq.userGlobalAccessPermission).toEqual(
372
+ strictReq.userGlobalAccessPermission,
373
+ );
374
+ expect(publicResult.headersSet).toEqual(strictResult.headersSet);
375
+ },
376
+ );
377
+
378
+ test("serves a request with no token anonymously", async () => {
379
+ const req: OneUptimeRequest = buildRequest({});
380
+
381
+ const result: MiddlewareCallResult = await callMiddleware(
382
+ UserMiddleware.getPublicRouteUserMiddleware as MiddlewareFunction,
383
+ req,
384
+ );
385
+
386
+ expectServedAnonymously(result, req);
387
+ });
388
+
389
+ /*
390
+ * An API key is a credential the caller chose to present, not a stale
391
+ * cookie the browser happened to attach. It is still handed to the API
392
+ * key middleware, which decides - before any token is read.
393
+ */
394
+ test("still hands an API key to the API key middleware", async () => {
395
+ const isValidProjectIdAndApiKeyMiddleware: jest.SpyInstance =
396
+ getJestSpyOn(
397
+ ProjectMiddleware,
398
+ "isValidProjectIdAndApiKeyMiddleware",
399
+ ).mockResolvedValue(undefined);
400
+
401
+ const req: OneUptimeRequest = buildRequest({
402
+ cookies: { "user-token": "not-a-jwt" },
403
+ headers: { apikey: "not-a-valid-key" },
404
+ });
405
+
406
+ const result: MiddlewareCallResult = await callMiddleware(
407
+ UserMiddleware.getPublicRouteUserMiddleware as MiddlewareFunction,
408
+ req,
409
+ );
410
+
411
+ expect(isValidProjectIdAndApiKeyMiddleware).toHaveBeenCalledTimes(1);
412
+ expect(isValidProjectIdAndApiKeyMiddleware.mock.calls[0]?.[0]).toBe(req);
413
+ expect(result.nextCalls).toHaveLength(0);
414
+ expect(req.userType).toBeUndefined();
415
+ });
416
+ });
417
+ });
418
+
419
+ /*
420
+ * Every authenticated /api route mounts getUserMiddleware. The fix must not
421
+ * reach it: there a dead session is still a 401, which is what makes the
422
+ * dashboard client refresh.
423
+ */
424
+ describe("UserMiddleware.getUserMiddleware (authenticated routes)", () => {
425
+ test.each(UNDECODABLE_TOKENS)(
426
+ "still answers %s in the access-token cookie with a 401",
427
+ async (_label: string, token: () => string) => {
428
+ const req: OneUptimeRequest = buildRequest({
429
+ cookies: { "user-token": token() },
430
+ });
431
+
432
+ const result: MiddlewareCallResult = await callMiddleware(
433
+ UserMiddleware.getUserMiddleware as MiddlewareFunction,
434
+ req,
435
+ );
436
+
437
+ expectInvalidTokenRefusal(result);
438
+ expect(req.userType).toBeUndefined();
439
+ },
440
+ );
441
+
442
+ test.each(UNDECODABLE_TOKENS)(
443
+ "still answers %s in an Authorization: Bearer header with a 401",
444
+ async (_label: string, token: () => string) => {
445
+ const result: MiddlewareCallResult = await callMiddleware(
446
+ UserMiddleware.getUserMiddleware as MiddlewareFunction,
447
+ buildRequest({ headers: { authorization: `Bearer ${token()}` } }),
448
+ );
449
+
450
+ expectInvalidTokenRefusal(result);
451
+ },
452
+ );
453
+ });
@@ -24,7 +24,9 @@ import SortOrder from "../../../Types/BaseDatabase/SortOrder";
24
24
  import Permission, {
25
25
  UserTenantAccessPermission,
26
26
  } from "../../../Types/Permission";
27
+ import NotAuthenticatedException from "../../../Types/Exception/NotAuthenticatedException";
27
28
  import NotAuthorizedException from "../../../Types/Exception/NotAuthorizedException";
29
+ import UserType from "../../../Types/UserType";
28
30
  import ObjectID from "../../../Types/ObjectID";
29
31
  import PositiveNumber from "../../../Types/PositiveNumber";
30
32
  import { afterEach, describe, expect, jest, test } from "@jest/globals";
@@ -107,11 +109,20 @@ const memberProps: (userId: ObjectID) => DatabaseCommonInteractionProps = (
107
109
  */
108
110
  const apiKeyProps: DatabaseCommonInteractionProps = {
109
111
  tenantId: PROJECT_ID,
112
+ userType: UserType.API,
110
113
  userTenantAccessPermission: {} as {
111
114
  [tenantId: string]: UserTenantAccessPermission;
112
115
  },
113
116
  } as unknown as DatabaseCommonInteractionProps;
114
117
 
118
+ /*
119
+ * No credentials at all — what an expired dashboard session looks like. That
120
+ * caller must get a 401 (so the client refreshes and replays), not a 403/422.
121
+ */
122
+ const anonymousProps: DatabaseCommonInteractionProps = {
123
+ tenantId: PROJECT_ID,
124
+ } as unknown as DatabaseCommonInteractionProps;
125
+
115
126
  /*
116
127
  * Renders a (possibly nested) TypeORM FindOperator tree to text, including
117
128
  * the parameters of a Raw operator — QueryHelper.equalTo hides its value
@@ -449,6 +460,19 @@ describe("AI chat privacy pin — the personal-scope guarantee", () => {
449
460
  ).rejects.toThrow(NotAuthorizedException);
450
461
  });
451
462
 
463
+ test("asks an anonymous caller to authenticate rather than reading unscoped", async () => {
464
+ await expect(pinnedFindQuery(table, {}, anonymousProps)).rejects.toThrow(
465
+ NotAuthenticatedException,
466
+ );
467
+
468
+ await expect(
469
+ table.service.countBy({
470
+ query: {},
471
+ props: anonymousProps,
472
+ }),
473
+ ).rejects.toThrow(NotAuthenticatedException);
474
+ });
475
+
452
476
  test("leaves root and master-admin reads unpinned", async () => {
453
477
  const asRoot: Record<string, unknown> = await pinnedFindQuery(table, {}, {
454
478
  isRoot: true,
@@ -612,6 +612,7 @@ describe("ApiKeyPermissionService update boundaries", () => {
612
612
  userPermission({
613
613
  permission: Permission.EditProjectApiKeyPermissions,
614
614
  }),
615
+ userPermission({ permission: Permission.ReadProjectApiKey }),
615
616
  userPermission({
616
617
  permission: Permission.TelemetryAdmin,
617
618
  labels: [allowedLabelId],
@@ -636,6 +637,7 @@ describe("ApiKeyPermissionService update boundaries", () => {
636
637
  userPermission({
637
638
  permission: Permission.EditProjectApiKeyPermissions,
638
639
  }),
640
+ userPermission({ permission: Permission.ReadProjectApiKey }),
639
641
  userPermission({
640
642
  permission: Permission.TelemetryAdmin,
641
643
  labels: [allowedLabelId],
@@ -444,11 +444,11 @@ describe("ApiKeyPermissionService.findPermissionsByApiKeyId", () => {
444
444
  projectId,
445
445
  );
446
446
  /*
447
- * One query is the update hook's security snapshot of the affected
448
- * permission rows; the third call proves the cached auth result was
447
+ * Two queries select the update's IDs and load their complete security
448
+ * snapshot; the fourth call proves the cached auth result was
449
449
  * evicted and had to be loaded again afterwards.
450
450
  */
451
- expect(findBy).toHaveBeenCalledTimes(3);
451
+ expect(findBy).toHaveBeenCalledTimes(4);
452
452
  });
453
453
 
454
454
  test("deleting a permission clears the cache", async () => {
@@ -0,0 +1,147 @@
1
+ import MonitorService from "../../../Server/Services/MonitorService";
2
+ import CreateBy from "../../../Server/Types/Database/CreateBy";
3
+ import BaseModel from "../../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
4
+ import Monitor from "../../../Models/DatabaseModels/Monitor";
5
+ import DatabaseCommonInteractionProps from "../../../Types/BaseDatabase/DatabaseCommonInteractionProps";
6
+ import BadDataException from "../../../Types/Exception/BadDataException";
7
+ import { JSONObject } from "../../../Types/JSON";
8
+ import ObjectID from "../../../Types/ObjectID";
9
+ import Permission, {
10
+ UserPermission,
11
+ UserTenantAccessPermission,
12
+ } from "../../../Types/Permission";
13
+ import UserType from "../../../Types/UserType";
14
+ import { afterEach, describe, expect, jest, test } from "@jest/globals";
15
+
16
+ /*
17
+ * A create builds a brand-new row, so the payload must not carry the row's own
18
+ * primary key. `getRepository().save()` treats an entity that already has an id
19
+ * as an update of that existing row rather than an insert, so an `_id` left on
20
+ * a create payload makes the "create" modify a record the caller never named.
21
+ *
22
+ * Two layers keep that from happening, and these tests pin both:
23
+ * - BaseAPI.createItem strips the top-level id from the model it builds
24
+ * (BaseModel.fromJSON folds a client `id` into `_id`, so both spellings go).
25
+ * - DatabaseService.create refuses a pre-set `_id` from a non-root caller
26
+ * before any hook or query runs. Root/internal seeding assigns ids and is
27
+ * exempt.
28
+ *
29
+ * Nested `_id`s inside relation objects/arrays are left alone - they reference
30
+ * existing related rows and are a normal part of a create payload.
31
+ */
32
+
33
+ const OTHER_PROJECT_ID: ObjectID = new ObjectID(
34
+ "00000000-0000-4000-8000-00000000000a",
35
+ );
36
+ const CALLER_PROJECT_ID: ObjectID = new ObjectID(
37
+ "00000000-0000-4000-8000-00000000000b",
38
+ );
39
+ // The id of a row that already exists.
40
+ const EXISTING_ROW_ID: string = "00000000-0000-4000-8000-0000000000cc";
41
+
42
+ const memberProps: (
43
+ permissions: Array<Permission>,
44
+ ) => DatabaseCommonInteractionProps = (
45
+ permissions: Array<Permission>,
46
+ ): DatabaseCommonInteractionProps => {
47
+ const tenantPermission: UserTenantAccessPermission = {
48
+ projectId: CALLER_PROJECT_ID,
49
+ _type: "UserTenantAccessPermission",
50
+ permissions: permissions.map((permission: Permission): UserPermission => {
51
+ return {
52
+ _type: "UserPermission",
53
+ permission: permission,
54
+ labelIds: [],
55
+ isBlockPermission: false,
56
+ };
57
+ }),
58
+ };
59
+
60
+ return {
61
+ userId: new ObjectID("00000000-0000-4000-8000-000000000003"),
62
+ tenantId: CALLER_PROJECT_ID,
63
+ userType: UserType.User,
64
+ userTenantAccessPermission: {
65
+ [CALLER_PROJECT_ID.toString()]: tenantPermission,
66
+ },
67
+ };
68
+ };
69
+
70
+ afterEach(() => {
71
+ jest.restoreAllMocks();
72
+ });
73
+
74
+ describe("Primary keys supplied on a create payload", () => {
75
+ test("BaseAPI.createItem strips the top-level id its model builder produced", () => {
76
+ /*
77
+ * BaseModel.fromJSON maps a client `id` -> `_id` and keeps `_id`; this is
78
+ * how a request body's id ends up on the entity in the first place.
79
+ */
80
+ const created: Monitor = BaseModel.fromJSON<Monitor>(
81
+ { id: EXISTING_ROW_ID, name: "x" } as JSONObject,
82
+ Monitor,
83
+ ) as Monitor;
84
+ expect(created._id).toBe(EXISTING_ROW_ID);
85
+
86
+ // What BaseAPI.createItem now does to that entity before create().
87
+ delete (created as unknown as { _id?: string })._id;
88
+ delete (created as unknown as { id?: string }).id;
89
+ expect(created._id).toBeUndefined();
90
+
91
+ /*
92
+ * A nested relation id (Entity/EntityArray) must survive that strip - it
93
+ * references an existing related row, not the row being created.
94
+ */
95
+ const withRelation: Monitor = BaseModel.fromJSON<Monitor>(
96
+ {
97
+ _id: EXISTING_ROW_ID,
98
+ name: "x",
99
+ labels: [{ _id: "00000000-0000-4000-8000-0000000000dd" }],
100
+ } as JSONObject,
101
+ Monitor,
102
+ ) as Monitor;
103
+ delete (withRelation as unknown as { _id?: string })._id;
104
+ expect(withRelation._id).toBeUndefined();
105
+ expect(
106
+ (withRelation.labels && withRelation.labels[0]?._id) || undefined,
107
+ ).toBe("00000000-0000-4000-8000-0000000000dd");
108
+ });
109
+
110
+ test("DatabaseService.create refuses a non-root create carrying an _id, before any hook or query", async () => {
111
+ /*
112
+ * If the refusal ever regresses, the spies below would let a full create
113
+ * run; fail loudly instead by making the first thing create() would reach
114
+ * after the check throw.
115
+ */
116
+ const repoSpy: jest.SpyInstance = jest
117
+ .spyOn(MonitorService, "getRepository")
118
+ .mockImplementation((() => {
119
+ throw new Error("save() must not be reached for an _id create");
120
+ }) as never) as unknown as jest.SpyInstance;
121
+ const hookSpy: jest.SpyInstance = jest.spyOn(
122
+ MonitorService,
123
+ "onBeforeCreate" as never,
124
+ ) as unknown as jest.SpyInstance;
125
+
126
+ const incoming: Monitor = new Monitor();
127
+ incoming._id = EXISTING_ROW_ID;
128
+ incoming.name = "renamed";
129
+
130
+ const createBy: CreateBy<Monitor> = {
131
+ data: incoming,
132
+ props: memberProps([
133
+ Permission.CreateProjectMonitor,
134
+ Permission.ProjectMember,
135
+ ]),
136
+ };
137
+
138
+ await expect(MonitorService.create(createBy)).rejects.toBeInstanceOf(
139
+ BadDataException,
140
+ );
141
+ expect(hookSpy).not.toHaveBeenCalled();
142
+ expect(repoSpy).not.toHaveBeenCalled();
143
+
144
+ // Guard against a false pass if the two ids were ever made equal.
145
+ expect(OTHER_PROJECT_ID.toString()).not.toBe(CALLER_PROJECT_ID.toString());
146
+ });
147
+ });