@oneuptime/common 12.0.6 → 12.0.7
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/AIInsight.ts +1 -1
- package/Models/DatabaseModels/DatabaseBaseModel/FileModel.ts +2 -3
- package/Models/DatabaseModels/DeletedProject.ts +595 -0
- package/Models/DatabaseModels/Index.ts +2 -0
- package/Models/DatabaseModels/Monitor.ts +111 -0
- package/Models/DatabaseModels/Project.ts +3 -3
- package/Models/DatabaseModels/WorkspaceProjectAuthToken.ts +19 -1
- package/Server/API/FileAPI.ts +15 -2
- package/Server/API/MicrosoftTeamsAPI.ts +6 -1
- package/Server/API/ProjectAPI.ts +214 -0
- package/Server/API/StatusPageAPI.ts +39 -6
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786446545142-MigrationName.ts +50 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786449497966-AddMonitorDependency.ts +67 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786461136170-AddDeletedProjectTable.ts +39 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
- package/Server/Services/AIAgentService.ts +20 -0
- package/Server/Services/DashboardDomainService.ts +73 -28
- package/Server/Services/DatabaseService.ts +1 -0
- package/Server/Services/DeletedProjectService.ts +138 -0
- package/Server/Services/FileService.ts +61 -0
- package/Server/Services/IncidentEpisodePublicNoteService.ts +18 -0
- package/Server/Services/IncidentPublicNoteService.ts +18 -0
- package/Server/Services/Index.ts +2 -0
- package/Server/Services/MonitorService.ts +311 -0
- package/Server/Services/ProbeService.ts +20 -0
- package/Server/Services/ProjectService.ts +297 -1
- package/Server/Services/PushNotificationService.ts +71 -0
- package/Server/Services/ScheduledMaintenancePublicNoteService.ts +18 -0
- package/Server/Services/StatusPageAnnouncementService.ts +53 -0
- package/Server/Services/StatusPageDomainService.ts +73 -28
- package/Server/Services/TeamMemberService.ts +117 -12
- package/Server/Services/TelemetryIngestionKeyService.ts +1 -0
- package/Server/Services/UserWebhookService.ts +34 -109
- package/Server/Services/WorkspaceNotificationRuleService.ts +69 -0
- package/Server/Services/WorkspaceProjectAuthTokenService.ts +37 -1
- package/Server/Types/Database/DeleteById.ts +2 -0
- package/Server/Types/Database/DeleteOneBy.ts +6 -0
- package/Server/Types/Domain.ts +41 -0
- package/Server/Types/Workflow/Components/API/Delete.ts +2 -1
- package/Server/Types/Workflow/Components/API/Get.ts +2 -1
- package/Server/Types/Workflow/Components/API/Patch.ts +2 -1
- package/Server/Types/Workflow/Components/API/Post.ts +2 -1
- package/Server/Types/Workflow/Components/API/Put.ts +2 -1
- package/Server/Types/Workflow/Components/API/Utils.ts +41 -2
- package/Server/Types/Workflow/Components/BaseModel/CreateManyBaseModel.ts +25 -19
- package/Server/Types/Workflow/Components/BaseModel/CreateOneBaseModel.ts +6 -5
- package/Server/Types/Workflow/Components/BaseModel/DeleteManyBaseModel.ts +32 -14
- package/Server/Types/Workflow/Components/BaseModel/DeleteOneBaseModel.ts +31 -13
- package/Server/Types/Workflow/Components/BaseModel/FindManyBaseModel.ts +29 -20
- package/Server/Types/Workflow/Components/BaseModel/FindOneBaseModel.ts +28 -21
- package/Server/Types/Workflow/Components/BaseModel/LogComponentError.ts +89 -0
- package/Server/Types/Workflow/Components/BaseModel/ModelArguments.ts +208 -0
- package/Server/Types/Workflow/Components/BaseModel/OnTriggerBaseModel.ts +11 -0
- package/Server/Types/Workflow/Components/BaseModel/UpdateManyBaseModel.ts +41 -18
- package/Server/Types/Workflow/Components/BaseModel/UpdateOneBaseModel.ts +45 -19
- package/Server/Types/Workflow/Components/Discord/SendMessageToChannel.ts +16 -9
- package/Server/Types/Workflow/Components/IncomingWebhookUtils.ts +66 -0
- package/Server/Types/Workflow/Components/MicrosoftTeams/SendMessageToChannel.ts +15 -9
- package/Server/Types/Workflow/Components/Slack/SendMessageToChannel.ts +17 -0
- package/Server/Utils/AI/Chat/ObservabilityChatPrompt.ts +1 -1
- package/Server/Utils/AI/CodeFix/CodeAgentWorkspaceGuard.ts +171 -0
- package/Server/Utils/AI/SRE/FixFromIncidentTaskTrigger.ts +3 -3
- package/Server/Utils/AI/SRE/Insights/FixRouting.ts +3 -2
- package/Server/Utils/AI/SRE/TelemetryImprovementTaskTrigger.ts +1 -1
- package/Server/Utils/AI/Toolbox/CodeWriteTools.ts +6 -6
- package/Server/Utils/CodeRepository/GitHub/GitHub.ts +43 -5
- package/Server/Utils/DataSource/EgressGuard.ts +176 -16
- package/Server/Utils/DataSource/HttpFetch.ts +6 -45
- package/Server/Utils/Execute.ts +8 -0
- package/Server/Utils/InlineImageAccessTokenSync.ts +23 -0
- package/Server/Utils/LLM/LLMService.ts +57 -12
- package/Server/Utils/Monitor/MonitorAlert.ts +40 -0
- package/Server/Utils/Monitor/MonitorDependencySuppression.ts +192 -0
- package/Server/Utils/Monitor/MonitorIncident.ts +40 -0
- package/Server/Utils/Monitor/MonitorResource.ts +36 -0
- package/Server/Utils/Response.ts +142 -6
- package/Server/Utils/SSRFProtection.ts +273 -60
- package/Server/Utils/StartServer.ts +8 -0
- package/Server/Utils/VM/VMRunner.ts +88 -1
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +555 -49
- package/Server/Utils/Workspace/Slack/Slack.ts +25 -2
- package/Server/Utils/Workspace/WorkspaceBase.ts +6 -0
- package/Tests/App/Dashboard/DangerZone.test.tsx +334 -0
- package/Tests/App/Dashboard/DashboardVariableAllContract.test.tsx +539 -0
- package/Tests/App/Dashboard/DashboardVariableSelector.test.tsx +678 -0
- package/Tests/App/Dashboard/DashboardVariablesDiscard.test.tsx +706 -0
- package/Tests/App/Dashboard/DashboardVariablesModal.test.tsx +508 -0
- package/Tests/App/PublicDashboard/DashboardVariableSelector.test.tsx +470 -0
- package/Tests/App/StatusPage/StatusPageDetailPagesNotFound.test.tsx +308 -0
- package/Tests/Models/DatabaseModels/DeletedProjectModel.test.ts +251 -0
- package/Tests/Models/DatabaseModels/SavedViewJSONColumnTuples.test.ts +115 -0
- package/Tests/Server/API/FileAPIAccessControl.test.ts +316 -0
- package/Tests/Server/API/ProjectAPI.test.ts +299 -1
- package/Tests/Server/API/ProjectAPIAdjustBalance.test.ts +459 -0
- package/Tests/Server/API/ProjectAPIAdjustBalanceBillingDisabled.test.ts +177 -0
- package/Tests/Server/Services/DatabaseServiceDeletionReason.test.ts +123 -0
- package/Tests/Server/Services/DeletedProjectService.test.ts +415 -0
- package/Tests/Server/Services/DeletedProjectServiceSelfHosted.test.ts +70 -0
- package/Tests/Server/Services/DomainSubdomainHooks.test.ts +94 -0
- package/Tests/Server/Services/FileIsPublicBooleanMigration.test.ts +244 -0
- package/Tests/Server/Services/FileServiceMimeType.test.ts +89 -0
- package/Tests/Server/Services/MonitorServiceDependencyValidation.test.ts +702 -0
- package/Tests/Server/Services/ProjectServiceAdjustBalance.test.ts +615 -0
- package/Tests/Server/Services/ProjectServiceDeleteAudit.test.ts +406 -0
- package/Tests/Server/Services/PublishTimeImageVisibility.test.ts +450 -0
- package/Tests/Server/Services/TeamMemberAutoAcceptInvitation.test.ts +669 -0
- package/Tests/Server/Services/UserWebhookSSRF.test.ts +174 -0
- package/Tests/Server/Services/WebPushEndpointAllowlist.test.ts +133 -0
- package/Tests/Server/Services/WorkspaceProjectAuthTokenRepoint.test.ts +618 -0
- package/Tests/Server/Types/Workflow/Components/ApiComponentErrorPort.test.ts +26 -1
- package/Tests/Server/Types/Workflow/Components/ApiComponentSsrf.test.ts +215 -0
- package/Tests/Server/Types/Workflow/Components/BaseModelDatabaseComponents.test.ts +742 -0
- package/Tests/Server/Types/Workflow/Components/ChatWebhookComponents.test.ts +256 -0
- package/Tests/Server/Types/Workflow/Components/ModelArguments.test.ts +371 -0
- package/Tests/Server/Utils/AI/CodeAgentCommandGuard.test.ts +204 -0
- package/Tests/Server/Utils/AI/CodeAgentWriteLimits.test.ts +213 -0
- package/Tests/Server/Utils/AI/CodeWriteTools.test.ts +52 -5
- package/Tests/Server/Utils/AI/LLMServiceBaseUrl.test.ts +3 -0
- package/Tests/Server/Utils/AI/LLMServiceEgressGuard.test.ts +315 -0
- package/Tests/Server/Utils/AI/LLMServiceModelCompatibility.test.ts +3 -0
- package/Tests/Server/Utils/AI/LLMServiceRequestPolicy.test.ts +17 -5
- package/Tests/Server/Utils/AI/LLMServiceToolCalling.test.ts +14 -1
- package/Tests/Server/Utils/AI/ObservabilityChatPrompt.test.ts +35 -0
- package/Tests/Server/Utils/AI/StubLLMEgressGuard.ts +25 -0
- package/Tests/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.test.ts +62 -7
- package/Tests/Server/Utils/DataSource/EgressGuard.test.ts +69 -0
- package/Tests/Server/Utils/DataSource/EgressGuardPinning.test.ts +330 -0
- package/Tests/Server/Utils/GitHubCreatePullRequestWithToken.test.ts +393 -0
- package/Tests/Server/Utils/InlineImageAccessTokenSync.test.ts +202 -0
- package/Tests/Server/Utils/Monitor/MonitorDependencySuppression.test.ts +811 -0
- package/Tests/Server/Utils/Monitor/MonitorDependencySuppressionCreatorSkip.test.ts +604 -0
- package/Tests/Server/Utils/ResponseSendFileResponse.test.ts +192 -0
- package/Tests/Server/Utils/SSRFProtectionBypasses.test.ts +406 -0
- package/Tests/Server/Utils/VM/VMRunnerSsrf.test.ts +194 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsChannelSend.test.ts +1169 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsChannelsList.test.ts +2 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsTeamInstalls.test.ts +1605 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsTenantResolution.test.ts +1218 -0
- package/Tests/Types/AI/AIChatMessageStatus.test.ts +79 -0
- package/Tests/Types/AI/AIInsightStatus.test.ts +40 -0
- package/Tests/Types/API/HostnameAuthorityParsing.test.ts +157 -0
- package/Tests/Types/Dashboard/DashboardTemplateInvariants.test.ts +27 -0
- package/Tests/Types/DataSource/DataSourceLimits.test.ts +71 -0
- package/Tests/Types/DataSource/DataSourceType.test.ts +181 -0
- package/Tests/Types/DomainSubdomainValidation.test.ts +90 -0
- package/Tests/Types/JSONFunctions.test.ts +252 -1
- package/Tests/Types/Monitor/SnmpMonitor/SnmpAuthProtocol.test.ts +61 -0
- package/Tests/Types/Monitor/SnmpMonitor/SnmpPrivProtocol.test.ts +62 -0
- package/Tests/Types/Monitor/SnmpMonitor/SnmpSecurityLevel.test.ts +68 -0
- package/Tests/Types/Monitor/SnmpMonitor/SnmpVersion.test.ts +51 -0
- package/Tests/UI/Components/404.test.tsx +1 -1
- package/Tests/UI/Components/Alert.test.tsx +1 -1
- package/Tests/UI/Components/Badge.test.tsx +1 -1
- package/Tests/UI/Components/BasicForm.test.tsx +39 -10
- package/Tests/UI/Components/Button.test.tsx +1 -1
- package/Tests/UI/Components/Card.test.tsx +1 -1
- package/Tests/UI/Components/Charts/AxisTickColor.test.tsx +1 -1
- package/Tests/UI/Components/ColorViewer.test.tsx +1 -1
- package/Tests/UI/Components/ComponentsModal.test.tsx +7 -1
- package/Tests/UI/Components/DictionaryOfStrings.test.tsx +1 -1
- package/Tests/UI/Components/Dropdown.test.tsx +1 -1
- package/Tests/UI/Components/FilePicker.test.tsx +1 -1
- package/Tests/UI/Components/HiddenText.test.tsx +1 -1
- package/Tests/UI/Components/Input.test.tsx +1 -1
- package/Tests/UI/Components/Loader.test.tsx +1 -1
- package/Tests/UI/Components/LogTimeRangePicker.test.tsx +1 -1
- package/Tests/UI/Components/MasterPage.test.tsx +1 -1
- package/Tests/UI/Components/ModalPortalDismissal.test.tsx +489 -0
- package/Tests/UI/Components/ModelDelete.test.tsx +214 -0
- package/Tests/UI/Components/ModelTable/BaseModelTableBulkSelectAll.test.tsx +1 -1
- package/Tests/UI/Components/ModelTable/BaseModelTableColumnCustomization.test.tsx +1 -1
- package/Tests/UI/Components/ModelTable/BaseModelTableSearchLabels.test.tsx +1 -1
- package/Tests/UI/Components/ModelTable/BaseModelTableUrlState.test.tsx +1 -1
- package/Tests/UI/Components/ModelTable/CustomFieldColumns.test.tsx +1 -1
- package/Tests/UI/Components/NavBar.test.tsx +1 -1
- package/Tests/UI/Components/OperatorSelectorKeyboard.test.tsx +1 -1
- package/Tests/UI/Components/Pagination.test.tsx +1 -1
- package/Tests/UI/Components/Pill.test.tsx +1 -1
- package/Tests/UI/Components/Probe.test.tsx +1 -1
- package/Tests/UI/Components/ProgressBar.test.tsx +1 -1
- package/Tests/UI/Components/RadioButtons.test.tsx +1 -1
- package/Tests/UI/Components/SideMenuItem.test.tsx +1 -1
- package/Tests/UI/Components/SideOver.test.tsx +500 -6
- package/Tests/UI/Components/Tabs.test.tsx +1 -1
- package/Tests/UI/Components/TelemetrySearchBar.test.tsx +1 -1
- package/Tests/UI/Components/TelemetryTimeRangePicker.test.tsx +1 -1
- package/Tests/UI/Components/TextArea.test.tsx +1 -1
- package/Tests/UI/Components/Toast.test.tsx +1 -1
- package/Tests/UI/Components/Toggle.test.tsx +1 -1
- package/Tests/UI/Components/TopSection.test.tsx +1 -1
- package/Tests/UI/Components/UseLiveLogsRefresh.test.tsx +1 -1
- package/Tests/UI/Rum/ReplayScrubber.test.tsx +1 -1
- package/Tests/UI/Rum/ReplayStage.test.tsx +1 -1
- package/Tests/UI/Telemetry/TelemetrySnapshotWindowAlert.test.tsx +1 -1
- package/Tests/UI/Utils/LocalStorageArrayRoundTrip.test.ts +72 -0
- package/Tests/Utils/Dashboard/HtmlWidgetDocument.test.ts +19 -2
- package/Tests/Utils/Dashboard/ModelQueryVariableInterpolation.test.ts +44 -0
- package/Tests/Utils/Dashboard/VariableInterpolation.test.ts +288 -5
- package/Tests/Utils/Dashboard/VariableUrlState.test.ts +42 -0
- package/Tests/Utils/DataSource/DataSourceQueryText.test.ts +27 -0
- package/Tests/Utils/LegacySerializedArray.test.ts +139 -0
- package/Tests/Utils/Monitor/MonitorDependencyRule.test.ts +190 -0
- package/Tests/Utils/Realtime.test.ts +78 -0
- package/Tests/Utils/Telemetry/SavedViewFilters.test.ts +246 -0
- package/Tests/__mocks__/i18next-browser-languagedetector.js +21 -0
- package/Types/AI/FixPullRequestCiStatus.ts +1 -1
- package/Types/AI/FixVerificationStatus.ts +2 -2
- package/Types/API/Hostname.ts +92 -4
- package/Types/API/URL.ts +43 -25
- package/Types/Billing/BalanceAdjustmentType.ts +14 -0
- package/Types/Billing/ProjectBalanceType.ts +13 -0
- package/Types/Domain.ts +26 -0
- package/Types/File/MimeType.ts +11 -0
- package/Types/JSONFunctions.ts +15 -0
- package/Types/Telemetry/TelemetrySavedViewState.ts +9 -1
- package/Types/Workflow/Components/BaseModel.ts +92 -28
- package/Typings/Index.d.ts +12 -0
- package/UI/Components/GanttChart/ChartContainer.tsx +4 -3
- package/UI/Components/Modal/ConfirmModal.tsx +10 -5
- package/UI/Components/Modal/Modal.tsx +27 -47
- package/UI/Components/ModelDelete/ModelDelete.tsx +23 -6
- package/UI/Components/SideOver/SideOver.tsx +195 -68
- package/UI/Utils/PageScrollLock.ts +66 -0
- package/Utils/Dashboard/HtmlWidgetDocument.ts +4 -2
- package/Utils/Dashboard/VariableInterpolation.ts +19 -1
- package/Utils/LegacySerializedArray.ts +60 -0
- package/Utils/Monitor/MonitorDependencyRule.ts +88 -0
- package/Utils/Telemetry/SavedViewFilters.ts +88 -0
- package/build/dist/Models/DatabaseModels/AIInsight.js +1 -1
- package/build/dist/Models/DatabaseModels/AIInsight.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DatabaseBaseModel/FileModel.js +2 -3
- package/build/dist/Models/DatabaseModels/DatabaseBaseModel/FileModel.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DeletedProject.js +640 -0
- package/build/dist/Models/DatabaseModels/DeletedProject.js.map +1 -0
- package/build/dist/Models/DatabaseModels/Index.js +2 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Monitor.js +106 -0
- package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Project.js +3 -3
- package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
- package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
- package/build/dist/Server/API/FileAPI.js +14 -2
- package/build/dist/Server/API/FileAPI.js.map +1 -1
- package/build/dist/Server/API/MicrosoftTeamsAPI.js +6 -1
- package/build/dist/Server/API/MicrosoftTeamsAPI.js.map +1 -1
- package/build/dist/Server/API/ProjectAPI.js +157 -4
- package/build/dist/Server/API/ProjectAPI.js.map +1 -1
- package/build/dist/Server/API/StatusPageAPI.js +27 -3
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786446545142-MigrationName.js +34 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786446545142-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786449497966-AddMonitorDependency.js +30 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786449497966-AddMonitorDependency.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786461136170-AddDeletedProjectTable.js +20 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786461136170-AddDeletedProjectTable.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/AIAgentService.js +17 -0
- package/build/dist/Server/Services/AIAgentService.js.map +1 -1
- package/build/dist/Server/Services/DashboardDomainService.js +55 -18
- package/build/dist/Server/Services/DashboardDomainService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +1 -0
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/DeletedProjectService.js +124 -0
- package/build/dist/Server/Services/DeletedProjectService.js.map +1 -0
- package/build/dist/Server/Services/FileService.js +52 -0
- package/build/dist/Server/Services/FileService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js +10 -1
- package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js.map +1 -1
- package/build/dist/Server/Services/IncidentPublicNoteService.js +10 -1
- package/build/dist/Server/Services/IncidentPublicNoteService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +2 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +232 -0
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/ProbeService.js +17 -0
- package/build/dist/Server/Services/ProbeService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +228 -6
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/PushNotificationService.js +56 -0
- package/build/dist/Server/Services/PushNotificationService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js +10 -1
- package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageAnnouncementService.js +54 -0
- package/build/dist/Server/Services/StatusPageAnnouncementService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageDomainService.js +55 -18
- package/build/dist/Server/Services/StatusPageDomainService.js.map +1 -1
- package/build/dist/Server/Services/TeamMemberService.js +97 -6
- package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryIngestionKeyService.js +1 -0
- package/build/dist/Server/Services/TelemetryIngestionKeyService.js.map +1 -1
- package/build/dist/Server/Services/UserWebhookService.js +31 -87
- package/build/dist/Server/Services/UserWebhookService.js.map +1 -1
- package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +65 -0
- package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js +23 -0
- package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js.map +1 -1
- package/build/dist/Server/Types/Domain.js +37 -0
- package/build/dist/Server/Types/Domain.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Delete.js +2 -1
- package/build/dist/Server/Types/Workflow/Components/API/Delete.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Get.js +2 -1
- package/build/dist/Server/Types/Workflow/Components/API/Get.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Patch.js +2 -1
- package/build/dist/Server/Types/Workflow/Components/API/Patch.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Post.js +2 -1
- package/build/dist/Server/Types/Workflow/Components/API/Post.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Put.js +2 -1
- package/build/dist/Server/Types/Workflow/Components/API/Put.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Utils.js +35 -2
- package/build/dist/Server/Types/Workflow/Components/API/Utils.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/BaseModel/CreateManyBaseModel.js +15 -11
- package/build/dist/Server/Types/Workflow/Components/BaseModel/CreateManyBaseModel.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/BaseModel/CreateOneBaseModel.js +2 -3
- package/build/dist/Server/Types/Workflow/Components/BaseModel/CreateOneBaseModel.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/BaseModel/DeleteManyBaseModel.js +21 -10
- package/build/dist/Server/Types/Workflow/Components/BaseModel/DeleteManyBaseModel.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/BaseModel/DeleteOneBaseModel.js +21 -10
- package/build/dist/Server/Types/Workflow/Components/BaseModel/DeleteOneBaseModel.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/BaseModel/FindManyBaseModel.js +18 -13
- package/build/dist/Server/Types/Workflow/Components/BaseModel/FindManyBaseModel.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/BaseModel/FindOneBaseModel.js +18 -13
- package/build/dist/Server/Types/Workflow/Components/BaseModel/FindOneBaseModel.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/BaseModel/LogComponentError.js +43 -0
- package/build/dist/Server/Types/Workflow/Components/BaseModel/LogComponentError.js.map +1 -0
- package/build/dist/Server/Types/Workflow/Components/BaseModel/ModelArguments.js +116 -0
- package/build/dist/Server/Types/Workflow/Components/BaseModel/ModelArguments.js.map +1 -0
- package/build/dist/Server/Types/Workflow/Components/BaseModel/OnTriggerBaseModel.js +7 -0
- package/build/dist/Server/Types/Workflow/Components/BaseModel/OnTriggerBaseModel.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/BaseModel/UpdateManyBaseModel.js +24 -13
- package/build/dist/Server/Types/Workflow/Components/BaseModel/UpdateManyBaseModel.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/BaseModel/UpdateOneBaseModel.js +27 -13
- package/build/dist/Server/Types/Workflow/Components/BaseModel/UpdateOneBaseModel.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/Discord/SendMessageToChannel.js +14 -6
- package/build/dist/Server/Types/Workflow/Components/Discord/SendMessageToChannel.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/IncomingWebhookUtils.js +42 -0
- package/build/dist/Server/Types/Workflow/Components/IncomingWebhookUtils.js.map +1 -0
- package/build/dist/Server/Types/Workflow/Components/MicrosoftTeams/SendMessageToChannel.js +15 -6
- package/build/dist/Server/Types/Workflow/Components/MicrosoftTeams/SendMessageToChannel.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/Slack/SendMessageToChannel.js +10 -2
- package/build/dist/Server/Types/Workflow/Components/Slack/SendMessageToChannel.js.map +1 -1
- package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js +1 -1
- package/build/dist/Server/Utils/AI/CodeFix/CodeAgentWorkspaceGuard.js +141 -0
- package/build/dist/Server/Utils/AI/CodeFix/CodeAgentWorkspaceGuard.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/Insights/FixRouting.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/TelemetryImprovementTaskTrigger.js +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/CodeWriteTools.js +6 -6
- package/build/dist/Server/Utils/AI/Toolbox/CodeWriteTools.js.map +1 -1
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js +39 -5
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js.map +1 -1
- package/build/dist/Server/Utils/DataSource/EgressGuard.js +94 -10
- package/build/dist/Server/Utils/DataSource/EgressGuard.js.map +1 -1
- package/build/dist/Server/Utils/DataSource/HttpFetch.js +1 -19
- package/build/dist/Server/Utils/DataSource/HttpFetch.js.map +1 -1
- package/build/dist/Server/Utils/Execute.js +2 -2
- package/build/dist/Server/Utils/Execute.js.map +1 -1
- package/build/dist/Server/Utils/InlineImageAccessTokenSync.js +13 -0
- package/build/dist/Server/Utils/InlineImageAccessTokenSync.js.map +1 -1
- package/build/dist/Server/Utils/LLM/LLMService.js +43 -12
- package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js +44 -24
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorDependencySuppression.js +158 -0
- package/build/dist/Server/Utils/Monitor/MonitorDependencySuppression.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js +50 -30
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorResource.js +32 -0
- package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
- package/build/dist/Server/Utils/Response.js +112 -5
- package/build/dist/Server/Utils/Response.js.map +1 -1
- package/build/dist/Server/Utils/SSRFProtection.js +219 -53
- package/build/dist/Server/Utils/SSRFProtection.js.map +1 -1
- package/build/dist/Server/Utils/StartServer.js +7 -0
- package/build/dist/Server/Utils/StartServer.js.map +1 -1
- package/build/dist/Server/Utils/VM/VMRunner.js +73 -1
- package/build/dist/Server/Utils/VM/VMRunner.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +445 -43
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/Slack/Slack.js +18 -1
- package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/WorkspaceBase.js.map +1 -1
- package/build/dist/Types/AI/FixPullRequestCiStatus.js +1 -1
- package/build/dist/Types/AI/FixVerificationStatus.js +2 -2
- package/build/dist/Types/API/Hostname.js +73 -4
- package/build/dist/Types/API/Hostname.js.map +1 -1
- package/build/dist/Types/API/URL.js +42 -24
- package/build/dist/Types/API/URL.js.map +1 -1
- package/build/dist/Types/Billing/BalanceAdjustmentType.js +15 -0
- package/build/dist/Types/Billing/BalanceAdjustmentType.js.map +1 -0
- package/build/dist/Types/Billing/ProjectBalanceType.js +14 -0
- package/build/dist/Types/Billing/ProjectBalanceType.js.map +1 -0
- package/build/dist/Types/Domain.js +22 -0
- package/build/dist/Types/Domain.js.map +1 -1
- package/build/dist/Types/File/MimeType.js +11 -0
- package/build/dist/Types/File/MimeType.js.map +1 -1
- package/build/dist/Types/JSONFunctions.js +14 -0
- package/build/dist/Types/JSONFunctions.js.map +1 -1
- package/build/dist/Types/Workflow/Components/BaseModel.js +83 -28
- package/build/dist/Types/Workflow/Components/BaseModel.js.map +1 -1
- package/build/dist/UI/Components/GanttChart/ChartContainer.js +4 -3
- package/build/dist/UI/Components/GanttChart/ChartContainer.js.map +1 -1
- package/build/dist/UI/Components/Modal/ConfirmModal.js +3 -1
- package/build/dist/UI/Components/Modal/ConfirmModal.js.map +1 -1
- package/build/dist/UI/Components/Modal/Modal.js +24 -34
- package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
- package/build/dist/UI/Components/ModelDelete/ModelDelete.js +11 -6
- package/build/dist/UI/Components/ModelDelete/ModelDelete.js.map +1 -1
- package/build/dist/UI/Components/SideOver/SideOver.js +105 -30
- package/build/dist/UI/Components/SideOver/SideOver.js.map +1 -1
- package/build/dist/UI/Utils/PageScrollLock.js +52 -0
- package/build/dist/UI/Utils/PageScrollLock.js.map +1 -0
- package/build/dist/Utils/Dashboard/HtmlWidgetDocument.js +4 -2
- package/build/dist/Utils/Dashboard/HtmlWidgetDocument.js.map +1 -1
- package/build/dist/Utils/Dashboard/VariableInterpolation.js +19 -1
- package/build/dist/Utils/Dashboard/VariableInterpolation.js.map +1 -1
- package/build/dist/Utils/LegacySerializedArray.js +51 -0
- package/build/dist/Utils/LegacySerializedArray.js.map +1 -0
- package/build/dist/Utils/Monitor/MonitorDependencyRule.js +47 -0
- package/build/dist/Utils/Monitor/MonitorDependencyRule.js.map +1 -0
- package/build/dist/Utils/Telemetry/SavedViewFilters.js +52 -0
- package/build/dist/Utils/Telemetry/SavedViewFilters.js.map +1 -0
- package/jest.config.json +3 -0
- package/package.json +1 -1
- package/tsconfig.json +3 -1
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
import CreateBy from "../Types/Database/CreateBy";
|
|
2
2
|
import DeleteBy from "../Types/Database/DeleteBy";
|
|
3
|
-
import
|
|
3
|
+
import UpdateBy from "../Types/Database/UpdateBy";
|
|
4
|
+
import { OnCreate, OnDelete, OnUpdate } from "../Types/Database/Hooks";
|
|
4
5
|
import GreenlockUtil from "../Utils/Greenlock/Greenlock";
|
|
5
6
|
import logger, { LogAttributes } from "../Utils/Logger";
|
|
6
7
|
import DatabaseService from "./DatabaseService";
|
|
7
8
|
import DomainService from "./DomainService";
|
|
8
9
|
import HTTPErrorResponse from "../../Types/API/HTTPErrorResponse";
|
|
9
10
|
import HTTPResponse from "../../Types/API/HTTPResponse";
|
|
10
|
-
import URL from "../../Types/API/URL";
|
|
11
11
|
import LIMIT_MAX from "../../Types/Database/LimitMax";
|
|
12
12
|
import BadDataException from "../../Types/Exception/BadDataException";
|
|
13
13
|
import { JSONObject } from "../../Types/JSON";
|
|
14
14
|
import ObjectID from "../../Types/ObjectID";
|
|
15
|
-
import API from "../../Utils/API";
|
|
16
15
|
import AcmeCertificate from "../../Models/DatabaseModels/AcmeCertificate";
|
|
17
16
|
import DomainModel from "../../Models/DatabaseModels/Domain";
|
|
18
17
|
import StatusPageDomain from "../../Models/DatabaseModels/StatusPageDomain";
|
|
@@ -22,11 +21,60 @@ import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
|
22
21
|
import { StatusPageCNameRecord } from "../EnvironmentConfig";
|
|
23
22
|
import Domain from "../Types/Domain";
|
|
24
23
|
|
|
24
|
+
const STATUS_PAGE_DOMAIN_EGRESS_LABEL: string = "Status page domain";
|
|
25
|
+
|
|
25
26
|
export class Service extends DatabaseService<StatusPageDomain> {
|
|
26
27
|
public constructor() {
|
|
27
28
|
super(StatusPageDomain);
|
|
28
29
|
}
|
|
29
30
|
|
|
31
|
+
/*
|
|
32
|
+
* Normalize a submitted subdomain and reject anything that is not a plain
|
|
33
|
+
* DNS label chain.
|
|
34
|
+
*
|
|
35
|
+
* fullDomain is built as `${subdomain}.${baseDomain}` and then interpolated
|
|
36
|
+
* into "https://" + fullDomain + "/status-page-api/..." — and URL parsing
|
|
37
|
+
* treats everything before the first "/" as the host. Without this check a
|
|
38
|
+
* subdomain of "169.254.169.254/latest/meta-data/#" hands an attacker the
|
|
39
|
+
* host, the port and the path of a request the certificate cron then makes
|
|
40
|
+
* unattended, every 15 minutes, from inside the cluster.
|
|
41
|
+
*/
|
|
42
|
+
private static normalizeAndValidateSubdomain(
|
|
43
|
+
subdomain: string | undefined,
|
|
44
|
+
): string {
|
|
45
|
+
const normalized: string = subdomain?.trim().toLowerCase() || "";
|
|
46
|
+
|
|
47
|
+
// "@" is the documented way to ask for the root domain.
|
|
48
|
+
if (normalized === "" || normalized === "@") {
|
|
49
|
+
return "";
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (!Domain.isValidSubdomain(normalized)) {
|
|
53
|
+
throw new BadDataException(
|
|
54
|
+
`Subdomain ${normalized} is not valid. Use a plain subdomain such as "status" — schemes, ports, paths and "/" are not allowed.`,
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return normalized;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
@CaptureSpan()
|
|
62
|
+
protected override async onBeforeUpdate(
|
|
63
|
+
updateBy: UpdateBy<StatusPageDomain>,
|
|
64
|
+
): Promise<OnUpdate<StatusPageDomain>> {
|
|
65
|
+
/*
|
|
66
|
+
* Create-time validation alone leaves the value editable afterwards —
|
|
67
|
+
* subdomain is ProjectMember-updatable.
|
|
68
|
+
*/
|
|
69
|
+
if (updateBy.data.subdomain !== undefined) {
|
|
70
|
+
updateBy.data.subdomain = Service.normalizeAndValidateSubdomain(
|
|
71
|
+
updateBy.data.subdomain as string,
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return { updateBy, carryForward: null };
|
|
76
|
+
}
|
|
77
|
+
|
|
30
78
|
@CaptureSpan()
|
|
31
79
|
protected override async onBeforeCreate(
|
|
32
80
|
createBy: CreateBy<StatusPageDomain>,
|
|
@@ -48,14 +96,11 @@ export class Service extends DatabaseService<StatusPageDomain> {
|
|
|
48
96
|
);
|
|
49
97
|
}
|
|
50
98
|
|
|
51
|
-
|
|
52
|
-
createBy.data.subdomain
|
|
53
|
-
|
|
54
|
-
if (normalizedSubdomain === "@") {
|
|
55
|
-
normalizedSubdomain = "";
|
|
56
|
-
}
|
|
99
|
+
createBy.data.subdomain = Service.normalizeAndValidateSubdomain(
|
|
100
|
+
createBy.data.subdomain,
|
|
101
|
+
);
|
|
57
102
|
|
|
58
|
-
createBy.data.subdomain
|
|
103
|
+
const normalizedSubdomain: string = createBy.data.subdomain;
|
|
59
104
|
|
|
60
105
|
if (domain) {
|
|
61
106
|
const baseDomain: string =
|
|
@@ -231,13 +276,13 @@ export class Service extends DatabaseService<StatusPageDomain> {
|
|
|
231
276
|
): Promise<boolean> {
|
|
232
277
|
try {
|
|
233
278
|
const result: HTTPErrorResponse | HTTPResponse<JSONObject> =
|
|
234
|
-
await
|
|
235
|
-
url:
|
|
279
|
+
await Domain.getForDomainVerification({
|
|
280
|
+
url:
|
|
236
281
|
"https://" +
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
282
|
+
fulldomain +
|
|
283
|
+
"/status-page-api/cname-verification/" +
|
|
284
|
+
token,
|
|
285
|
+
targetLabel: STATUS_PAGE_DOMAIN_EGRESS_LABEL,
|
|
241
286
|
});
|
|
242
287
|
|
|
243
288
|
if (result.isFailure()) {
|
|
@@ -320,13 +365,13 @@ export class Service extends DatabaseService<StatusPageDomain> {
|
|
|
320
365
|
|
|
321
366
|
try {
|
|
322
367
|
const result: HTTPErrorResponse | HTTPResponse<JSONObject> =
|
|
323
|
-
await
|
|
324
|
-
url:
|
|
368
|
+
await Domain.getForDomainVerification({
|
|
369
|
+
url:
|
|
325
370
|
"http://" +
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
371
|
+
fullDomain +
|
|
372
|
+
"/status-page-api/cname-verification/" +
|
|
373
|
+
token,
|
|
374
|
+
targetLabel: STATUS_PAGE_DOMAIN_EGRESS_LABEL,
|
|
330
375
|
});
|
|
331
376
|
|
|
332
377
|
logger.debug("CNAME verification result", {
|
|
@@ -353,13 +398,13 @@ export class Service extends DatabaseService<StatusPageDomain> {
|
|
|
353
398
|
|
|
354
399
|
try {
|
|
355
400
|
const resultHttps: HTTPErrorResponse | HTTPResponse<JSONObject> =
|
|
356
|
-
await
|
|
357
|
-
url:
|
|
401
|
+
await Domain.getForDomainVerification({
|
|
402
|
+
url:
|
|
358
403
|
"https://" +
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
404
|
+
fullDomain +
|
|
405
|
+
"/status-page-api/cname-verification/" +
|
|
406
|
+
token,
|
|
407
|
+
targetLabel: STATUS_PAGE_DOMAIN_EGRESS_LABEL,
|
|
363
408
|
});
|
|
364
409
|
|
|
365
410
|
logger.debug("CNAME verification result for https", {
|
|
@@ -120,10 +120,40 @@ export class TeamMemberService extends DatabaseService<TeamMember> {
|
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
-
|
|
123
|
+
/*
|
|
124
|
+
* Only internal writes (isRoot) and a master admin acting from the Admin
|
|
125
|
+
* Dashboard may create a membership that is already accepted - that is the
|
|
126
|
+
* "accept the invitation automatically" checkbox on the admin invite forms.
|
|
127
|
+
*
|
|
128
|
+
* Everyone else invites, and the invited person accepts for themselves. A
|
|
129
|
+
* project admin who could accept on someone's behalf would be able to pull
|
|
130
|
+
* an account into their project - and into whatever the team's permissions
|
|
131
|
+
* grant - without that person ever agreeing to it.
|
|
132
|
+
*/
|
|
133
|
+
const canCreateAcceptedInvitation: boolean = Boolean(
|
|
134
|
+
createBy.props.isRoot || createBy.props.isMasterAdmin,
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
if (!canCreateAcceptedInvitation) {
|
|
124
138
|
createBy.data.hasAcceptedInvitation = false;
|
|
125
139
|
}
|
|
126
140
|
|
|
141
|
+
const isInvitationAcceptedOnCreate: boolean = Boolean(
|
|
142
|
+
createBy.data.hasAcceptedInvitation,
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
/*
|
|
146
|
+
* The acceptance timestamp is stamped here rather than taken from the
|
|
147
|
+
* request, so it can never disagree with hasAcceptedInvitation - a row that
|
|
148
|
+
* says "Member" with no accepted-at date, or an accepted-at date on a row
|
|
149
|
+
* that is still only invited.
|
|
150
|
+
*/
|
|
151
|
+
if (isInvitationAcceptedOnCreate) {
|
|
152
|
+
createBy.data.invitationAcceptedAt = OneUptimeDate.getCurrentDate();
|
|
153
|
+
} else {
|
|
154
|
+
delete createBy.data.invitationAcceptedAt;
|
|
155
|
+
}
|
|
156
|
+
|
|
127
157
|
if (createBy.miscDataProps && createBy.miscDataProps["email"]) {
|
|
128
158
|
const email: Email = new Email(createBy.miscDataProps["email"] as string);
|
|
129
159
|
|
|
@@ -221,10 +251,18 @@ export class TeamMemberService extends DatabaseService<TeamMember> {
|
|
|
221
251
|
.addQueryParam("email", email.toString(), true)
|
|
222
252
|
.toString(),
|
|
223
253
|
isNewUser: isNewUser.toString(),
|
|
254
|
+
/*
|
|
255
|
+
* An auto-accepted member has nothing left to accept, so the
|
|
256
|
+
* template drops the "sign in to accept your invitation" framing
|
|
257
|
+
* and tells them they are already in.
|
|
258
|
+
*/
|
|
259
|
+
isInvitationAccepted: isInvitationAcceptedOnCreate.toString(),
|
|
224
260
|
projectName: project.name!,
|
|
225
261
|
homeUrl: new URL(httpProtocol, host).toString(),
|
|
226
262
|
},
|
|
227
|
-
subject:
|
|
263
|
+
subject: isInvitationAcceptedOnCreate
|
|
264
|
+
? "You have been added to " + project.name
|
|
265
|
+
: "You have been invited to " + project.name,
|
|
228
266
|
},
|
|
229
267
|
{
|
|
230
268
|
projectId: createBy.data.projectId!,
|
|
@@ -283,6 +321,65 @@ export class TeamMemberService extends DatabaseService<TeamMember> {
|
|
|
283
321
|
);
|
|
284
322
|
}
|
|
285
323
|
|
|
324
|
+
/*
|
|
325
|
+
* The per-project notification defaults a member gets the moment their
|
|
326
|
+
* membership becomes accepted, whether that happened by them accepting the
|
|
327
|
+
* invitation or by a master admin accepting it for them on create. Without
|
|
328
|
+
* these, an auto-accepted member is a member who is never notified about
|
|
329
|
+
* anything.
|
|
330
|
+
*
|
|
331
|
+
* Skipped for an unverified email: UserService adds the defaults for every
|
|
332
|
+
* accepted membership once the address is verified.
|
|
333
|
+
*
|
|
334
|
+
* Best effort. Both helpers below are idempotent, and by the time either
|
|
335
|
+
* caller runs, the membership row is already committed - failing the write
|
|
336
|
+
* that created it would report "invite failed" for a member who exists.
|
|
337
|
+
*/
|
|
338
|
+
@CaptureSpan()
|
|
339
|
+
private async addDefaultNotificationSettingsAndRules(data: {
|
|
340
|
+
userId: ObjectID;
|
|
341
|
+
projectId: ObjectID;
|
|
342
|
+
user?: User | undefined;
|
|
343
|
+
}): Promise<void> {
|
|
344
|
+
try {
|
|
345
|
+
const user: User | null =
|
|
346
|
+
data.user ||
|
|
347
|
+
(await UserService.findOneById({
|
|
348
|
+
id: data.userId,
|
|
349
|
+
select: {
|
|
350
|
+
email: true,
|
|
351
|
+
isEmailVerified: true,
|
|
352
|
+
},
|
|
353
|
+
props: {
|
|
354
|
+
isRoot: true,
|
|
355
|
+
},
|
|
356
|
+
}));
|
|
357
|
+
|
|
358
|
+
if (!user || !user.isEmailVerified || !user.email) {
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
await UserNotificationSettingService.addDefaultNotificationSettingsForUser(
|
|
363
|
+
data.userId,
|
|
364
|
+
data.projectId,
|
|
365
|
+
);
|
|
366
|
+
|
|
367
|
+
await UserNotificationRuleService.addDefaultNotificationRuleForUser(
|
|
368
|
+
data.projectId,
|
|
369
|
+
data.userId,
|
|
370
|
+
user.email,
|
|
371
|
+
);
|
|
372
|
+
} catch (err) {
|
|
373
|
+
logger.error(
|
|
374
|
+
err as Error,
|
|
375
|
+
{
|
|
376
|
+
projectId: data.projectId.toString(),
|
|
377
|
+
userId: data.userId.toString(),
|
|
378
|
+
} as LogAttributes,
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
286
383
|
@CaptureSpan()
|
|
287
384
|
protected override async onCreateSuccess(
|
|
288
385
|
onCreate: OnCreate<TeamMember>,
|
|
@@ -297,6 +394,18 @@ export class TeamMemberService extends DatabaseService<TeamMember> {
|
|
|
297
394
|
onCreate.createBy.data.projectId!,
|
|
298
395
|
);
|
|
299
396
|
|
|
397
|
+
/*
|
|
398
|
+
* A membership created already accepted never goes through the
|
|
399
|
+
* accept-invitation update, so it would otherwise miss the defaults that
|
|
400
|
+
* hook adds.
|
|
401
|
+
*/
|
|
402
|
+
if (createdItem.hasAcceptedInvitation) {
|
|
403
|
+
await this.addDefaultNotificationSettingsAndRules({
|
|
404
|
+
userId: onCreate.createBy.data.userId!,
|
|
405
|
+
projectId: onCreate.createBy.data.projectId!,
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
|
|
300
409
|
// Activation event for marketing funnels, attributed to the inviter.
|
|
301
410
|
ProductAnalytics.captureForUser({
|
|
302
411
|
userId: onCreate.createBy.props.userId,
|
|
@@ -339,16 +448,12 @@ export class TeamMemberService extends DatabaseService<TeamMember> {
|
|
|
339
448
|
for (const item of items) {
|
|
340
449
|
await this.refreshTokens(item.userId!, item.projectId!);
|
|
341
450
|
|
|
342
|
-
if (updateBy.data.hasAcceptedInvitation
|
|
343
|
-
await
|
|
344
|
-
item.userId!,
|
|
345
|
-
item.projectId!,
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
item.projectId!,
|
|
349
|
-
item.userId!,
|
|
350
|
-
item.user?.email as Email,
|
|
351
|
-
);
|
|
451
|
+
if (updateBy.data.hasAcceptedInvitation) {
|
|
452
|
+
await this.addDefaultNotificationSettingsAndRules({
|
|
453
|
+
userId: item.userId!,
|
|
454
|
+
projectId: item.projectId!,
|
|
455
|
+
user: item.user,
|
|
456
|
+
});
|
|
352
457
|
}
|
|
353
458
|
}
|
|
354
459
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import CreateBy from "../Types/Database/CreateBy";
|
|
2
2
|
import DeleteBy from "../Types/Database/DeleteBy";
|
|
3
|
-
import
|
|
3
|
+
import UpdateBy from "../Types/Database/UpdateBy";
|
|
4
|
+
import { OnCreate, OnDelete, OnUpdate } from "../Types/Database/Hooks";
|
|
4
5
|
import DatabaseService from "./DatabaseService";
|
|
5
6
|
import UserNotificationRuleService from "./UserNotificationRuleService";
|
|
6
7
|
import LIMIT_MAX from "../../Types/Database/LimitMax";
|
|
@@ -8,8 +9,19 @@ import BadDataException from "../../Types/Exception/BadDataException";
|
|
|
8
9
|
import Model from "../../Models/DatabaseModels/UserWebhook";
|
|
9
10
|
import URL from "../../Types/API/URL";
|
|
10
11
|
import logger from "../Utils/Logger";
|
|
12
|
+
import SSRFProtection from "../Utils/SSRFProtection";
|
|
11
13
|
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
12
14
|
|
|
15
|
+
/*
|
|
16
|
+
* URL validation here used to be a hand-rolled copy of the SSRF blocklist that
|
|
17
|
+
* had drifted weaker than the original (it compared the host with the port
|
|
18
|
+
* still attached, and never resolved DNS). Everything that actually sends one
|
|
19
|
+
* of these webhooks goes through WebhookService, which calls
|
|
20
|
+
* SSRFProtection.validateWebhookTargetIsSafe — so the copy bought nothing and
|
|
21
|
+
* would have been read as "this is checked". Both hooks now call the same
|
|
22
|
+
* guard the sender does, which fails the write early instead of at delivery.
|
|
23
|
+
*/
|
|
24
|
+
|
|
13
25
|
export class Service extends DatabaseService<Model> {
|
|
14
26
|
public constructor() {
|
|
15
27
|
super(Model);
|
|
@@ -27,7 +39,7 @@ export class Service extends DatabaseService<Model> {
|
|
|
27
39
|
throw new BadDataException("Webhook name is required");
|
|
28
40
|
}
|
|
29
41
|
|
|
30
|
-
|
|
42
|
+
await SSRFProtection.validateWebhookTargetIsSafe(createBy.data.webhookUrl);
|
|
31
43
|
|
|
32
44
|
return {
|
|
33
45
|
createBy,
|
|
@@ -35,6 +47,26 @@ export class Service extends DatabaseService<Model> {
|
|
|
35
47
|
};
|
|
36
48
|
}
|
|
37
49
|
|
|
50
|
+
@CaptureSpan()
|
|
51
|
+
protected override async onBeforeUpdate(
|
|
52
|
+
updateBy: UpdateBy<Model>,
|
|
53
|
+
): Promise<OnUpdate<Model>> {
|
|
54
|
+
/*
|
|
55
|
+
* Create-time validation on its own is not a control: the URL is
|
|
56
|
+
* editable afterwards.
|
|
57
|
+
*/
|
|
58
|
+
const webhookUrl: unknown = updateBy.data.webhookUrl;
|
|
59
|
+
|
|
60
|
+
if (typeof webhookUrl === "string" || webhookUrl instanceof URL) {
|
|
61
|
+
await SSRFProtection.validateWebhookTargetIsSafe(webhookUrl);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
updateBy,
|
|
66
|
+
carryForward: null,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
38
70
|
@CaptureSpan()
|
|
39
71
|
protected override async onCreateSuccess(
|
|
40
72
|
_onCreate: OnCreate<Model>,
|
|
@@ -96,113 +128,6 @@ export class Service extends DatabaseService<Model> {
|
|
|
96
128
|
carryForward: null,
|
|
97
129
|
};
|
|
98
130
|
}
|
|
99
|
-
|
|
100
|
-
private validateWebhookUrl(rawUrl: string): void {
|
|
101
|
-
let parsed: URL;
|
|
102
|
-
try {
|
|
103
|
-
parsed = URL.fromString(rawUrl);
|
|
104
|
-
} catch {
|
|
105
|
-
throw new BadDataException("Webhook URL is not a valid URL");
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const protocolValue: string = parsed.protocol.toString().toLowerCase();
|
|
109
|
-
if (protocolValue !== "http://" && protocolValue !== "https://") {
|
|
110
|
-
throw new BadDataException(
|
|
111
|
-
"Webhook URL must use http or https protocol.",
|
|
112
|
-
);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const hostname: string = parsed.hostname.hostname.toLowerCase();
|
|
116
|
-
|
|
117
|
-
if (!hostname) {
|
|
118
|
-
throw new BadDataException("Webhook URL must include a host.");
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
if (isBlockedHostnameLiteral(hostname)) {
|
|
122
|
-
throw new BadDataException(
|
|
123
|
-
"Webhook URL points to a private, loopback, or link-local address and is not allowed.",
|
|
124
|
-
);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function isBlockedHostnameLiteral(hostname: string): boolean {
|
|
130
|
-
if (
|
|
131
|
-
hostname === "localhost" ||
|
|
132
|
-
hostname.endsWith(".localhost") ||
|
|
133
|
-
hostname === "metadata.google.internal"
|
|
134
|
-
) {
|
|
135
|
-
return true;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// IPv4 literal check
|
|
139
|
-
const ipv4Match: RegExpMatchArray | null = hostname.match(
|
|
140
|
-
/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/,
|
|
141
|
-
);
|
|
142
|
-
if (ipv4Match) {
|
|
143
|
-
const octets: Array<number> = [
|
|
144
|
-
Number(ipv4Match[1]),
|
|
145
|
-
Number(ipv4Match[2]),
|
|
146
|
-
Number(ipv4Match[3]),
|
|
147
|
-
Number(ipv4Match[4]),
|
|
148
|
-
];
|
|
149
|
-
|
|
150
|
-
if (
|
|
151
|
-
octets.some((o: number) => {
|
|
152
|
-
return o < 0 || o > 255;
|
|
153
|
-
})
|
|
154
|
-
) {
|
|
155
|
-
return true;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// 0.0.0.0/8
|
|
159
|
-
if (octets[0] === 0) {
|
|
160
|
-
return true;
|
|
161
|
-
}
|
|
162
|
-
// 127.0.0.0/8 loopback
|
|
163
|
-
if (octets[0] === 127) {
|
|
164
|
-
return true;
|
|
165
|
-
}
|
|
166
|
-
// 10.0.0.0/8
|
|
167
|
-
if (octets[0] === 10) {
|
|
168
|
-
return true;
|
|
169
|
-
}
|
|
170
|
-
// 172.16.0.0/12
|
|
171
|
-
if (octets[0] === 172 && (octets[1]! & 0xf0) === 16) {
|
|
172
|
-
return true;
|
|
173
|
-
}
|
|
174
|
-
// 192.168.0.0/16
|
|
175
|
-
if (octets[0] === 192 && octets[1] === 168) {
|
|
176
|
-
return true;
|
|
177
|
-
}
|
|
178
|
-
// 169.254.0.0/16 link-local (incl. cloud metadata)
|
|
179
|
-
if (octets[0] === 169 && octets[1] === 254) {
|
|
180
|
-
return true;
|
|
181
|
-
}
|
|
182
|
-
// 100.64.0.0/10 carrier-grade NAT
|
|
183
|
-
if (octets[0] === 100 && (octets[1]! & 0xc0) === 64) {
|
|
184
|
-
return true;
|
|
185
|
-
}
|
|
186
|
-
return false;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// IPv6 literal — block loopback, link-local, unique-local
|
|
190
|
-
if (hostname.includes(":")) {
|
|
191
|
-
const stripped: string = hostname.replace(/^\[|\]$/g, "");
|
|
192
|
-
if (stripped === "::1" || stripped === "::") {
|
|
193
|
-
return true;
|
|
194
|
-
}
|
|
195
|
-
if (stripped.startsWith("fe80:") || stripped.startsWith("fe80::")) {
|
|
196
|
-
return true;
|
|
197
|
-
}
|
|
198
|
-
if (IPV6_UNIQUE_LOCAL_REGEX.test(stripped)) {
|
|
199
|
-
return true;
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
return false;
|
|
204
131
|
}
|
|
205
132
|
|
|
206
|
-
const IPV6_UNIQUE_LOCAL_REGEX: RegExp = /^f[cd][0-9a-f]{2}:/;
|
|
207
|
-
|
|
208
133
|
export default new Service();
|
|
@@ -309,6 +309,20 @@ export class Service extends DatabaseService<WorkspaceNotificationRule> {
|
|
|
309
309
|
|
|
310
310
|
// Check for errors in the response
|
|
311
311
|
if (res.errors && res.errors.length > 0) {
|
|
312
|
+
/*
|
|
313
|
+
* Record the failure before throwing. Test sends used to throw
|
|
314
|
+
* straight out of here, so a failed test left no trace in
|
|
315
|
+
* Notification Logs and support had no way to see what Microsoft
|
|
316
|
+
* or Slack actually said.
|
|
317
|
+
*/
|
|
318
|
+
await this.logTestSendFailures({
|
|
319
|
+
projectId: data.projectId,
|
|
320
|
+
workspaceType: res.workspaceType,
|
|
321
|
+
errors: res.errors,
|
|
322
|
+
message: messageSummary,
|
|
323
|
+
userId: data.testByUserId,
|
|
324
|
+
});
|
|
325
|
+
|
|
312
326
|
const errorMessages: Array<string> = res.errors.map(
|
|
313
327
|
(error: { channel: WorkspaceChannel; error: string }) => {
|
|
314
328
|
return `Channel ${error.channel.name}: ${error.error}`;
|
|
@@ -408,6 +422,20 @@ export class Service extends DatabaseService<WorkspaceNotificationRule> {
|
|
|
408
422
|
|
|
409
423
|
// Check for errors in the response
|
|
410
424
|
if (res.errors && res.errors.length > 0) {
|
|
425
|
+
/*
|
|
426
|
+
* Record the failure before throwing. Test sends used to throw
|
|
427
|
+
* straight out of here, so a failed test left no trace in
|
|
428
|
+
* Notification Logs and support had no way to see what Microsoft
|
|
429
|
+
* or Slack actually said.
|
|
430
|
+
*/
|
|
431
|
+
await this.logTestSendFailures({
|
|
432
|
+
projectId: data.projectId,
|
|
433
|
+
workspaceType: res.workspaceType,
|
|
434
|
+
errors: res.errors,
|
|
435
|
+
message: messageSummary,
|
|
436
|
+
userId: data.testByUserId,
|
|
437
|
+
});
|
|
438
|
+
|
|
411
439
|
const errorMessages: Array<string> = res.errors.map(
|
|
412
440
|
(error: { channel: WorkspaceChannel; error: string }) => {
|
|
413
441
|
return `Channel ${error.channel.name}: ${error.error}`;
|
|
@@ -540,6 +568,47 @@ export class Service extends DatabaseService<WorkspaceNotificationRule> {
|
|
|
540
568
|
}
|
|
541
569
|
}
|
|
542
570
|
|
|
571
|
+
/*
|
|
572
|
+
* Persist per-destination failures from a test send so they show up in
|
|
573
|
+
* Settings > Notification Logs alongside real notification failures. Real
|
|
574
|
+
* sends already log; test sends threw before reaching any logging, which
|
|
575
|
+
* meant the one action an admin takes to diagnose a broken integration was
|
|
576
|
+
* also the only one that recorded nothing.
|
|
577
|
+
*
|
|
578
|
+
* Best-effort: a logging failure must never mask the underlying send error.
|
|
579
|
+
*/
|
|
580
|
+
@CaptureSpan()
|
|
581
|
+
private async logTestSendFailures(data: {
|
|
582
|
+
projectId: ObjectID;
|
|
583
|
+
workspaceType: WorkspaceType;
|
|
584
|
+
errors: Array<{ channel: WorkspaceChannel; error: string }>;
|
|
585
|
+
message: string;
|
|
586
|
+
userId: ObjectID;
|
|
587
|
+
}): Promise<void> {
|
|
588
|
+
for (const error of data.errors) {
|
|
589
|
+
try {
|
|
590
|
+
const log: WorkspaceNotificationLog = new WorkspaceNotificationLog();
|
|
591
|
+
log.projectId = data.projectId;
|
|
592
|
+
log.workspaceType = data.workspaceType;
|
|
593
|
+
log.channelId = error.channel.id;
|
|
594
|
+
log.channelName = error.channel.name;
|
|
595
|
+
log.message = data.message;
|
|
596
|
+
log.status = WorkspaceNotificationStatus.Error;
|
|
597
|
+
log.statusMessage = error.error;
|
|
598
|
+
log.userId = data.userId;
|
|
599
|
+
log.actionType = WorkspaceNotificationActionType.SendMessage;
|
|
600
|
+
|
|
601
|
+
await WorkspaceNotificationLogService.create({
|
|
602
|
+
data: log,
|
|
603
|
+
props: { isRoot: true },
|
|
604
|
+
});
|
|
605
|
+
} catch (err) {
|
|
606
|
+
logger.error("Could not write test-send failure to notification log:");
|
|
607
|
+
logger.error(err);
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
|
|
543
612
|
@CaptureSpan()
|
|
544
613
|
public async archiveWorkspaceChannels(data: {
|
|
545
614
|
projectId: ObjectID;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import ObjectID from "../../Types/ObjectID";
|
|
2
|
-
import WorkspaceType
|
|
2
|
+
import WorkspaceType, {
|
|
3
|
+
getWorkspaceTypeDisplayName,
|
|
4
|
+
} from "../../Types/Workspace/WorkspaceType";
|
|
3
5
|
import DatabaseService from "./DatabaseService";
|
|
4
6
|
import Model, {
|
|
5
7
|
WorkspaceMiscData,
|
|
@@ -7,6 +9,7 @@ import Model, {
|
|
|
7
9
|
import { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
|
|
8
10
|
import BadDataException from "../../Types/Exception/BadDataException";
|
|
9
11
|
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
12
|
+
import logger from "../Utils/Logger";
|
|
10
13
|
|
|
11
14
|
export class Service extends DatabaseService<Model> {
|
|
12
15
|
public constructor() {
|
|
@@ -112,12 +115,45 @@ export class Service extends DatabaseService<Model> {
|
|
|
112
115
|
},
|
|
113
116
|
select: {
|
|
114
117
|
_id: true,
|
|
118
|
+
workspaceProjectId: true,
|
|
115
119
|
},
|
|
116
120
|
props: {
|
|
117
121
|
isRoot: true,
|
|
118
122
|
},
|
|
119
123
|
});
|
|
120
124
|
|
|
125
|
+
/*
|
|
126
|
+
* A project stores exactly one workspace (one Microsoft tenant / one Slack
|
|
127
|
+
* team). Re-running the connect flow from a DIFFERENT workspace used to
|
|
128
|
+
* silently repoint the project, which breaks every existing notification
|
|
129
|
+
* rule and orphans the bot conversations captured under the old workspace —
|
|
130
|
+
* with no error and nothing in the logs.
|
|
131
|
+
*
|
|
132
|
+
* Refuse instead, and tell the admin to disconnect first if the change is
|
|
133
|
+
* deliberate.
|
|
134
|
+
*/
|
|
135
|
+
if (
|
|
136
|
+
projectAuth &&
|
|
137
|
+
projectAuth.workspaceProjectId &&
|
|
138
|
+
projectAuth.workspaceProjectId !== data.workspaceProjectId
|
|
139
|
+
) {
|
|
140
|
+
logger.error(
|
|
141
|
+
`Refusing to repoint ${data.workspaceType} for project ${data.projectId.toString()} from workspace ${projectAuth.workspaceProjectId} to ${data.workspaceProjectId}.`,
|
|
142
|
+
{
|
|
143
|
+
projectId: data.projectId.toString(),
|
|
144
|
+
workspaceType: data.workspaceType,
|
|
145
|
+
},
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
const workspaceName: string = getWorkspaceTypeDisplayName(
|
|
149
|
+
data.workspaceType,
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
throw new BadDataException(
|
|
153
|
+
`This OneUptime project is already connected to a different ${workspaceName} workspace. Disconnect the existing ${workspaceName} connection in Project Settings before connecting a new one.`,
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
121
157
|
if (!projectAuth) {
|
|
122
158
|
projectAuth = new Model();
|
|
123
159
|
|
|
@@ -5,5 +5,7 @@ import User from "../../../Models/DatabaseModels/User";
|
|
|
5
5
|
export default interface DeleteById {
|
|
6
6
|
id: ObjectID;
|
|
7
7
|
deletedByUser?: User;
|
|
8
|
+
// See DeleteOneBy.deletionReason - passed straight through to the hooks.
|
|
9
|
+
deletionReason?: string | undefined;
|
|
8
10
|
props: DatabaseCommonInteractionProps;
|
|
9
11
|
}
|
|
@@ -6,5 +6,11 @@ import User from "../../../Models/DatabaseModels/User";
|
|
|
6
6
|
export default interface DeleteOneBy<TBaseModel extends BaseModel> {
|
|
7
7
|
query: Query<TBaseModel>;
|
|
8
8
|
deletedByUser?: User | undefined;
|
|
9
|
+
/*
|
|
10
|
+
* Free-text reason the caller gave for the delete. Never persisted on the
|
|
11
|
+
* row being deleted (it is about to be gone) - it rides through to the
|
|
12
|
+
* delete hooks, which are the last place that can record it anywhere.
|
|
13
|
+
*/
|
|
14
|
+
deletionReason?: string | undefined;
|
|
9
15
|
props: DatabaseCommonInteractionProps;
|
|
10
16
|
}
|