@oneuptime/common 12.0.9 → 12.0.11
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/NetworkDevice.ts +44 -0
- package/Models/DatabaseModels/NetworkDeviceLink.ts +116 -0
- package/Models/DatabaseModels/RunnerJob.ts +17 -2
- package/Server/API/LlmProviderAPI.ts +8 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1787400000000-AddDeviceRoleAndDeclaredLinkParent.ts +52 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
- package/Server/Services/NetworkDeviceLabelRuleEngineService.ts +240 -0
- package/Server/Services/NetworkDeviceLinkService.ts +338 -2
- package/Server/Services/NetworkDeviceService.ts +265 -12
- package/Server/Services/RunnerJobService.ts +24 -1
- package/Server/Types/Billing/MeteredPlan/AllMeteredPlans.ts +19 -5
- package/Server/Types/Database/JSONColumnQuery.ts +42 -4
- package/Server/Utils/LLM/LLMService.ts +108 -19
- package/Server/Utils/Monitor/MonitorAlert.ts +22 -115
- package/Server/Utils/Monitor/MonitorIncident.ts +7 -337
- package/Server/Utils/Monitor/MonitorMaintenanceSuppression.ts +27 -2
- package/Server/Utils/Monitor/SeriesResourceLabels.ts +32 -0
- package/Server/Utils/Monitor/SeriesResourceLinker.ts +469 -0
- package/Server/Utils/SSRFProtection.ts +5 -4
- package/Server/Utils/Telemetry/InventoryEntityRegistry.ts +186 -38
- package/Tests/App/AdminDashboard/AdminUsersBulkAddToProject.test.tsx +955 -0
- package/Tests/App/AdminDashboard/BulkAddUsersToProject.test.ts +778 -0
- package/Tests/App/AdminDashboard/BulkAddUsersToProjectModal.test.tsx +1051 -0
- package/Tests/App/Dashboard/AdminNotificationRulesPage.test.tsx +420 -112
- package/Tests/App/Dashboard/OnCallReadinessSurfaces.test.tsx +81 -6
- package/Tests/App/Dashboard/PayAsYouGoConsentGate.test.tsx +543 -0
- package/Tests/App/Dashboard/PayAsYouGoFreePlan.test.ts +125 -0
- package/Tests/App/Dashboard/PayAsYouGoNotices.test.tsx +612 -0
- package/Tests/App/Dashboard/SloWidgetChartRendering.test.tsx +536 -0
- package/Tests/App/Dashboard/UserElementEmail.test.tsx +447 -0
- package/Tests/App/Dashboard/UserEmailCallSites.test.tsx +284 -0
- package/Tests/Models/AnalyticsModels/CommonModel.test.ts +312 -0
- package/Tests/Server/Infrastructure/Postgres/DeviceRoleAndDeclaredLinkParentMigration.test.ts +250 -0
- package/Tests/Server/Infrastructure/Postgres/EpisodeMemberNotifyIndexesMigration.test.ts +46 -18
- package/Tests/Server/Services/NetworkDeviceLabelRuleRun.test.ts +618 -0
- package/Tests/Server/Services/NetworkDeviceLinkParentValidation.test.ts +1043 -0
- package/Tests/Server/Services/NetworkSiteAssignmentRuleRun.test.ts +706 -0
- package/Tests/Server/Services/RunnerJobEnqueue.test.ts +412 -0
- package/Tests/Server/Types/Billing/PayAsYouGoMeteredPricing.test.ts +125 -0
- package/Tests/Server/Types/Database/JSONColumnQuery.test.ts +508 -0
- package/Tests/Server/Utils/AI/LLMServiceRequestPolicy.test.ts +2 -2
- package/Tests/Server/Utils/AI/LLMServiceRetryPolicy.test.ts +450 -0
- package/Tests/Server/Utils/Monitor/MonitorAlertResourceLinking.test.ts +556 -0
- package/Tests/Server/Utils/Monitor/MonitorIncidentResourceLinking.test.ts +547 -0
- package/Tests/Server/Utils/Monitor/MonitorMaintenanceSuppression.test.ts +30 -0
- package/Tests/Server/Utils/Monitor/SeriesResourceLinker.test.ts +699 -0
- package/Tests/Server/Utils/SeriesResourceLabels.test.ts +55 -0
- package/Tests/Server/Utils/Telemetry/InventoryEntityRegistry.test.ts +668 -0
- package/Tests/Types/API/URLMalformedTolerance.test.ts +301 -0
- package/Tests/Types/API/URLTelScheme.test.ts +261 -0
- package/Tests/Types/API/URLUnsupportedScheme.test.ts +148 -0
- package/Tests/Types/Billing/PayAsYouGoPricing.test.ts +64 -0
- package/Tests/Types/CustomField/CustomFieldTypeCorrespondence.test.ts +107 -0
- package/Tests/Types/Monitor/MonitorType.test.ts +62 -0
- package/Tests/Types/NetworkAutomation/RuleRunResult.test.ts +184 -0
- package/Tests/Types/Runbook/RunbookStepType.test.ts +124 -0
- package/Tests/Types/Workflow/BaseModelComponents.test.ts +17 -0
- package/Tests/UI/Components/Button.test.tsx +279 -0
- package/Tests/UI/Components/Charts/ChartXAxisDataKey.test.tsx +256 -0
- package/Tests/UI/Components/Charts/DataPointUtil.test.ts +323 -0
- package/Tests/UI/Components/DictionaryValuePlaceholderAndSuggestions.test.tsx +595 -0
- package/Tests/UI/Components/Icon.test.tsx +57 -0
- package/Tests/UI/Components/List.test.tsx +20 -3
- package/Tests/UI/Components/LogsSavedViewsDropdown.test.tsx +304 -0
- package/Tests/UI/Components/LogsViewerClearSavedView.test.tsx +179 -0
- package/Tests/UI/Components/ModelTable/CustomFieldColumns.test.tsx +349 -1
- package/Tests/UI/Components/Pagination.test.tsx +721 -146
- package/Tests/UI/Components/PaginationIntegration.test.tsx +386 -0
- package/Tests/UI/Components/PaginationUtil.test.ts +417 -0
- package/Tests/UI/Components/TelemetrySavedViewsDropdown.test.tsx +343 -0
- package/Tests/UI/Components/Workflow/ColumnEditor/ColumnControl.test.ts +289 -0
- package/Tests/UI/Components/Workflow/ColumnEditor/ColumnOperators.test.ts +271 -0
- package/Tests/UI/Components/Workflow/ColumnEditor/ColumnRow.test.ts +119 -0
- package/Tests/UI/Components/Workflow/ColumnEditor/ColumnRowSerialization.test.ts +968 -0
- package/Tests/UI/Components/Workflow/ModelColumnEditor.render.test.tsx +766 -0
- package/Tests/UI/Utils/RunNetworkRule.test.ts +320 -0
- package/Tests/Utils/APIRetryPolicy.test.ts +823 -0
- package/Tests/Utils/Monitor/NetworkDeviceRoleUtil.test.ts +502 -0
- package/Tests/Utils/Monitor/NetworkTopologyDeclaredHierarchy.test.ts +759 -0
- package/Tests/Utils/NetworkAutomation/RuleRunSummary.test.ts +286 -0
- package/Tests/Utils/Schema/BaseSchema.test.ts +651 -0
- package/Types/API/Protocol.ts +9 -0
- package/Types/API/URL.ts +286 -20
- package/Types/Billing/PayAsYouGoPricing.ts +47 -0
- package/Types/CustomField/CustomFieldType.ts +28 -0
- package/Types/Monitor/MonitorType.ts +11 -0
- package/Types/Monitor/SnmpMonitor/NetworkTopology.ts +13 -0
- package/Types/NetworkAutomation/RuleRunResult.ts +121 -0
- package/Types/Runbook/RunbookStepType.ts +23 -0
- package/UI/Components/AutocompleteTextInput/AutocompleteTextInput.tsx +7 -0
- package/UI/Components/Button/Button.tsx +14 -22
- package/UI/Components/Charts/Area/AreaChart.tsx +4 -2
- package/UI/Components/Charts/Bar/BarChart.tsx +4 -2
- package/UI/Components/Charts/ChartLibrary/Types/ChartDataPoint.ts +13 -0
- package/UI/Components/Charts/Line/LineChart.tsx +4 -2
- package/UI/Components/Charts/Types/XAxis/XAxis.ts +6 -0
- package/UI/Components/Charts/Utils/DataPoint.ts +15 -12
- package/UI/Components/Dictionary/Dictionary.tsx +4 -39
- package/UI/Components/Icon/Icon.tsx +1 -1
- package/UI/Components/LogsViewer/LogsViewer.tsx +5 -1
- package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +8 -0
- package/UI/Components/LogsViewer/components/LogsPagination.tsx +29 -91
- package/UI/Components/LogsViewer/components/LogsViewerToolbar.tsx +2 -0
- package/UI/Components/LogsViewer/components/SavedViewsDropdown.tsx +66 -1
- package/UI/Components/ModelTable/CustomFieldColumns.tsx +55 -0
- package/UI/Components/Pagination/Pagination.tsx +373 -328
- package/UI/Components/Pagination/PaginationUtil.ts +263 -0
- package/UI/Components/Pagination/Screenshots/README.md +15 -0
- package/UI/Components/Pagination/Screenshots/pagination-before-after.png +0 -0
- package/UI/Components/Pagination/Screenshots/pagination-go-to-page-modal.png +0 -0
- package/UI/Components/Pagination/Screenshots/pagination-long-list.png +0 -0
- package/UI/Components/Pagination/Screenshots/pagination-mobile.png +0 -0
- package/UI/Components/Pagination/Screenshots/pagination-telemetry.png +0 -0
- package/UI/Components/TelemetryViewer/components/SavedViewsDropdown.tsx +66 -1
- package/UI/Components/TelemetryViewer/components/TelemetryPagination.tsx +38 -92
- package/UI/Components/TextArea/TextArea.tsx +3 -0
- package/UI/Components/Workflow/ArgumentsForm.tsx +18 -1
- package/UI/Components/Workflow/ColumnEditor/AddColumnDropdown.tsx +177 -0
- package/UI/Components/Workflow/ColumnEditor/ColumnConditionRow.tsx +243 -0
- package/UI/Components/Workflow/ColumnEditor/ColumnControl.ts +255 -0
- package/UI/Components/Workflow/ColumnEditor/ColumnFieldRow.tsx +178 -0
- package/UI/Components/Workflow/ColumnEditor/ColumnOperators.ts +206 -0
- package/UI/Components/Workflow/ColumnEditor/ColumnRow.ts +157 -0
- package/UI/Components/Workflow/ColumnEditor/ColumnRowSerialization.ts +517 -0
- package/UI/Components/Workflow/ColumnEditor/ColumnValueInput.tsx +482 -0
- package/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.tsx +131 -0
- package/UI/Components/Workflow/ColumnEditor/ModelRecordForm.tsx +163 -0
- package/UI/Components/Workflow/ModelColumnEditor.tsx +284 -100
- package/UI/Utils/NetworkAutomation/RunNetworkRule.ts +122 -0
- package/Utils/API.ts +243 -36
- package/Utils/Monitor/NetworkDeviceRoleUtil.ts +45 -0
- package/Utils/Monitor/NetworkTopologyUtil.ts +42 -2
- package/Utils/NetworkAutomation/RuleRunSummary.ts +147 -0
- package/build/dist/Models/DatabaseModels/NetworkDevice.js +45 -0
- package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceLink.js +115 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceLink.js.map +1 -1
- package/build/dist/Models/DatabaseModels/RunnerJob.js +17 -2
- package/build/dist/Models/DatabaseModels/RunnerJob.js.map +1 -1
- package/build/dist/Server/API/LlmProviderAPI.js +9 -1
- package/build/dist/Server/API/LlmProviderAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787400000000-AddDeviceRoleAndDeclaredLinkParent.js +33 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787400000000-AddDeviceRoleAndDeclaredLinkParent.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js +202 -0
- package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceLinkService.js +253 -1
- package/build/dist/Server/Services/NetworkDeviceLinkService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceService.js +223 -12
- package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
- package/build/dist/Server/Services/RunnerJobService.js +20 -2
- package/build/dist/Server/Services/RunnerJobService.js.map +1 -1
- package/build/dist/Server/Types/Billing/MeteredPlan/AllMeteredPlans.js +12 -5
- package/build/dist/Server/Types/Billing/MeteredPlan/AllMeteredPlans.js.map +1 -1
- package/build/dist/Server/Types/Database/JSONColumnQuery.js +40 -4
- package/build/dist/Server/Types/Database/JSONColumnQuery.js.map +1 -1
- package/build/dist/Server/Utils/LLM/LLMService.js +78 -22
- package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js +22 -98
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js +7 -254
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js +14 -2
- package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +27 -0
- package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js +285 -0
- package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js.map +1 -0
- package/build/dist/Server/Utils/SSRFProtection.js +5 -4
- package/build/dist/Server/Utils/SSRFProtection.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/InventoryEntityRegistry.js +128 -35
- package/build/dist/Server/Utils/Telemetry/InventoryEntityRegistry.js.map +1 -1
- package/build/dist/Types/API/Protocol.js +9 -0
- package/build/dist/Types/API/Protocol.js.map +1 -1
- package/build/dist/Types/API/URL.js +241 -18
- package/build/dist/Types/API/URL.js.map +1 -1
- package/build/dist/Types/Billing/PayAsYouGoPricing.js +41 -0
- package/build/dist/Types/Billing/PayAsYouGoPricing.js.map +1 -0
- package/build/dist/Types/CustomField/CustomFieldType.js +26 -0
- package/build/dist/Types/CustomField/CustomFieldType.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorType.js +10 -0
- package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
- package/build/dist/Types/NetworkAutomation/RuleRunResult.js +39 -0
- package/build/dist/Types/NetworkAutomation/RuleRunResult.js.map +1 -0
- package/build/dist/Types/Runbook/RunbookStepType.js +21 -0
- package/build/dist/Types/Runbook/RunbookStepType.js.map +1 -1
- package/build/dist/UI/Components/AutocompleteTextInput/AutocompleteTextInput.js +1 -1
- package/build/dist/UI/Components/AutocompleteTextInput/AutocompleteTextInput.js.map +1 -1
- package/build/dist/UI/Components/Button/Button.js +10 -16
- package/build/dist/UI/Components/Button/Button.js.map +1 -1
- package/build/dist/UI/Components/Charts/Area/AreaChart.js +2 -1
- package/build/dist/UI/Components/Charts/Area/AreaChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/Bar/BarChart.js +2 -1
- package/build/dist/UI/Components/Charts/Bar/BarChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/Types/ChartDataPoint.js +12 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Types/ChartDataPoint.js.map +1 -1
- package/build/dist/UI/Components/Charts/Line/LineChart.js +2 -1
- package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/Utils/DataPoint.js +17 -10
- package/build/dist/UI/Components/Charts/Utils/DataPoint.js.map +1 -1
- package/build/dist/UI/Components/Dictionary/Dictionary.js +4 -18
- package/build/dist/UI/Components/Dictionary/Dictionary.js.map +1 -1
- package/build/dist/UI/Components/Icon/Icon.js +1 -1
- package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js +3 -3
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +5 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsPagination.js +14 -44
- package/build/dist/UI/Components/LogsViewer/components/LogsPagination.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/SavedViewsDropdown.js +20 -2
- package/build/dist/UI/Components/LogsViewer/components/SavedViewsDropdown.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js +42 -0
- package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js.map +1 -1
- package/build/dist/UI/Components/Pagination/Pagination.js +174 -199
- package/build/dist/UI/Components/Pagination/Pagination.js.map +1 -1
- package/build/dist/UI/Components/Pagination/PaginationUtil.js +160 -0
- package/build/dist/UI/Components/Pagination/PaginationUtil.js.map +1 -0
- package/build/dist/UI/Components/TelemetryViewer/components/SavedViewsDropdown.js +20 -2
- package/build/dist/UI/Components/TelemetryViewer/components/SavedViewsDropdown.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryPagination.js +23 -47
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryPagination.js.map +1 -1
- package/build/dist/UI/Components/TextArea/TextArea.js +1 -1
- package/build/dist/UI/Components/TextArea/TextArea.js.map +1 -1
- package/build/dist/UI/Components/Workflow/ArgumentsForm.js +14 -2
- package/build/dist/UI/Components/Workflow/ArgumentsForm.js.map +1 -1
- package/build/dist/UI/Components/Workflow/ColumnEditor/AddColumnDropdown.js +86 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/AddColumnDropdown.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnConditionRow.js +119 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnConditionRow.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnControl.js +206 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnControl.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnFieldRow.js +57 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnFieldRow.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnOperators.js +150 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnOperators.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnRow.js +67 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnRow.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnRowSerialization.js +309 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnRowSerialization.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnValueInput.js +204 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnValueInput.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.js +66 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ModelRecordForm.js +83 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ModelRecordForm.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ModelColumnEditor.js +187 -68
- package/build/dist/UI/Components/Workflow/ModelColumnEditor.js.map +1 -1
- package/build/dist/UI/Utils/NetworkAutomation/RunNetworkRule.js +75 -0
- package/build/dist/UI/Utils/NetworkAutomation/RunNetworkRule.js.map +1 -0
- package/build/dist/Utils/API.js +175 -34
- package/build/dist/Utils/API.js.map +1 -1
- package/build/dist/Utils/Monitor/NetworkDeviceRoleUtil.js +37 -0
- package/build/dist/Utils/Monitor/NetworkDeviceRoleUtil.js.map +1 -1
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +25 -3
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
- package/build/dist/Utils/NetworkAutomation/RuleRunSummary.js +78 -0
- package/build/dist/Utils/NetworkAutomation/RuleRunSummary.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
import CephCluster from "../../../Models/DatabaseModels/CephCluster";
|
|
2
|
+
import DockerHost from "../../../Models/DatabaseModels/DockerHost";
|
|
3
|
+
import DockerSwarmCluster from "../../../Models/DatabaseModels/DockerSwarmCluster";
|
|
4
|
+
import Host from "../../../Models/DatabaseModels/Host";
|
|
5
|
+
import IoTFleet from "../../../Models/DatabaseModels/IoTFleet";
|
|
6
|
+
import KubernetesCluster from "../../../Models/DatabaseModels/KubernetesCluster";
|
|
7
|
+
import PodmanHost from "../../../Models/DatabaseModels/PodmanHost";
|
|
8
|
+
import ProxmoxCluster from "../../../Models/DatabaseModels/ProxmoxCluster";
|
|
9
|
+
import Service from "../../../Models/DatabaseModels/Service";
|
|
10
|
+
import Includes from "../../../Types/BaseDatabase/Includes";
|
|
11
|
+
import { LIMIT_PER_PROJECT } from "../../../Types/Database/LimitMax";
|
|
12
|
+
import { JSONObject } from "../../../Types/JSON";
|
|
13
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
14
|
+
import CephClusterService from "../../Services/CephClusterService";
|
|
15
|
+
import DockerHostService from "../../Services/DockerHostService";
|
|
16
|
+
import DockerSwarmClusterService from "../../Services/DockerSwarmClusterService";
|
|
17
|
+
import HostService from "../../Services/HostService";
|
|
18
|
+
import IoTFleetService from "../../Services/IoTFleetService";
|
|
19
|
+
import KubernetesClusterService from "../../Services/KubernetesClusterService";
|
|
20
|
+
import PodmanHostService from "../../Services/PodmanHostService";
|
|
21
|
+
import ProxmoxClusterService from "../../Services/ProxmoxClusterService";
|
|
22
|
+
import ServiceService from "../../Services/ServiceService";
|
|
23
|
+
import { MonitorClusterContext } from "./MonitorClusterContext";
|
|
24
|
+
import SeriesResourceLabels, {
|
|
25
|
+
SeriesResourceRefs,
|
|
26
|
+
} from "./SeriesResourceLabels";
|
|
27
|
+
|
|
28
|
+
/*
|
|
29
|
+
* A grouped monitor opens one alert/incident per breaching series, and
|
|
30
|
+
* each series carries the identity of the resource it came from in its
|
|
31
|
+
* labels. This module turns those labels into real, project-scoped
|
|
32
|
+
* resource rows and attaches them to the alert/incident, so "Affected
|
|
33
|
+
* Resources", the per-resource Activity tabs, the sidebar badge counts
|
|
34
|
+
* and the resource-owner/label inheritance rules all see the host (or
|
|
35
|
+
* cluster, or service) the event is actually about.
|
|
36
|
+
*
|
|
37
|
+
* Alerts and incidents MUST agree here. They used to disagree: the
|
|
38
|
+
* incident path resolved every resource type through the shared
|
|
39
|
+
* SeriesResourceLabels key map while the alert path read two hard-coded
|
|
40
|
+
* label spellings (`resource.host.name` / `host.name`) inline, so an
|
|
41
|
+
* alert grouped by the far more common `oneuptime.host.name` stamp
|
|
42
|
+
* linked nothing at all. Both paths now call this one module.
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
/*
|
|
46
|
+
* Structurally satisfied by both Alert and Incident — every relation
|
|
47
|
+
* below is declared identically on the two models. Typed with
|
|
48
|
+
* `| undefined` so the models' `public hosts?: Array<Host> = undefined;`
|
|
49
|
+
* shape stays assignable under exactOptionalPropertyTypes.
|
|
50
|
+
*/
|
|
51
|
+
export interface SeriesLinkableModel {
|
|
52
|
+
hosts?: Array<Host> | undefined;
|
|
53
|
+
dockerHosts?: Array<DockerHost> | undefined;
|
|
54
|
+
podmanHosts?: Array<PodmanHost> | undefined;
|
|
55
|
+
kubernetesClusters?: Array<KubernetesCluster> | undefined;
|
|
56
|
+
services?: Array<Service> | undefined;
|
|
57
|
+
proxmoxClusters?: Array<ProxmoxCluster> | undefined;
|
|
58
|
+
cephClusters?: Array<CephCluster> | undefined;
|
|
59
|
+
dockerSwarmClusters?: Array<DockerSwarmCluster> | undefined;
|
|
60
|
+
iotFleets?: Array<IoTFleet> | undefined;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/*
|
|
64
|
+
* Database ids of the resources one series points at, by type. Empty
|
|
65
|
+
* arrays for every type the series says nothing about.
|
|
66
|
+
*/
|
|
67
|
+
export interface SeriesResolvedResourceIds {
|
|
68
|
+
hostIds: Array<string>;
|
|
69
|
+
dockerHostIds: Array<string>;
|
|
70
|
+
podmanHostIds: Array<string>;
|
|
71
|
+
kubernetesClusterIds: Array<string>;
|
|
72
|
+
serviceIds: Array<string>;
|
|
73
|
+
proxmoxClusterIds: Array<string>;
|
|
74
|
+
cephClusterIds: Array<string>;
|
|
75
|
+
dockerSwarmClusterIds: Array<string>;
|
|
76
|
+
iotFleetIds: Array<string>;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/*
|
|
80
|
+
* One resource type's lookup recipe: where its ids and names come from
|
|
81
|
+
* in the extracted refs, which column its name maps to, and which
|
|
82
|
+
* service reads the table.
|
|
83
|
+
*/
|
|
84
|
+
interface ResourceResolutionSpec {
|
|
85
|
+
ids: Array<string>;
|
|
86
|
+
names: Array<string>;
|
|
87
|
+
nameColumn: string;
|
|
88
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
89
|
+
findBy: (args: any) => Promise<Array<{ _id?: string | undefined }>>;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export default class SeriesResourceLinker {
|
|
93
|
+
/*
|
|
94
|
+
* Resolve a series' labels to project-scoped database ids, without
|
|
95
|
+
* touching any model. Lookups are ALWAYS project-scoped: `isRoot`
|
|
96
|
+
* bypasses row-level access control, and a stale or hostile
|
|
97
|
+
* `oneuptime.*.id` stamp must never be able to pull a row in from
|
|
98
|
+
* another tenant.
|
|
99
|
+
*/
|
|
100
|
+
public static async resolveResourcesFromSeriesLabels(input: {
|
|
101
|
+
seriesLabels: JSONObject;
|
|
102
|
+
projectId: ObjectID;
|
|
103
|
+
}): Promise<SeriesResolvedResourceIds> {
|
|
104
|
+
const refs: SeriesResourceRefs = SeriesResourceLabels.extractResourceRefs(
|
|
105
|
+
input.seriesLabels,
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
/*
|
|
109
|
+
* Proxmox / Ceph / Docker Swarm / IoT carry no `oneuptime.*.id`
|
|
110
|
+
* stamp at ingest — they are addressable by name only — so their
|
|
111
|
+
* `ids` lists are empty by construction, not by omission.
|
|
112
|
+
*/
|
|
113
|
+
const specs: Array<ResourceResolutionSpec> = [
|
|
114
|
+
{
|
|
115
|
+
ids: refs.hostIds,
|
|
116
|
+
names: refs.hostNames,
|
|
117
|
+
nameColumn: "hostIdentifier",
|
|
118
|
+
findBy: HostService.findBy.bind(HostService),
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
ids: refs.dockerHostIds,
|
|
122
|
+
names: refs.dockerHostNames,
|
|
123
|
+
nameColumn: "hostIdentifier",
|
|
124
|
+
findBy: DockerHostService.findBy.bind(DockerHostService),
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
ids: refs.podmanHostIds,
|
|
128
|
+
names: refs.podmanHostNames,
|
|
129
|
+
nameColumn: "hostIdentifier",
|
|
130
|
+
findBy: PodmanHostService.findBy.bind(PodmanHostService),
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
ids: refs.kubernetesClusterIds,
|
|
134
|
+
names: refs.kubernetesClusterNames,
|
|
135
|
+
nameColumn: "clusterIdentifier",
|
|
136
|
+
findBy: KubernetesClusterService.findBy.bind(KubernetesClusterService),
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
ids: refs.serviceIds,
|
|
140
|
+
names: refs.serviceNames,
|
|
141
|
+
nameColumn: "name",
|
|
142
|
+
findBy: ServiceService.findBy.bind(ServiceService),
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
ids: [],
|
|
146
|
+
names: refs.proxmoxClusterNames,
|
|
147
|
+
nameColumn: "name",
|
|
148
|
+
findBy: ProxmoxClusterService.findBy.bind(ProxmoxClusterService),
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
ids: [],
|
|
152
|
+
names: refs.cephClusterNames,
|
|
153
|
+
nameColumn: "name",
|
|
154
|
+
findBy: CephClusterService.findBy.bind(CephClusterService),
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
ids: [],
|
|
158
|
+
names: refs.dockerSwarmClusterNames,
|
|
159
|
+
nameColumn: "name",
|
|
160
|
+
findBy: DockerSwarmClusterService.findBy.bind(
|
|
161
|
+
DockerSwarmClusterService,
|
|
162
|
+
),
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
ids: [],
|
|
166
|
+
names: refs.iotFleetNames,
|
|
167
|
+
nameColumn: "name",
|
|
168
|
+
findBy: IoTFleetService.findBy.bind(IoTFleetService),
|
|
169
|
+
},
|
|
170
|
+
];
|
|
171
|
+
|
|
172
|
+
const [
|
|
173
|
+
hostIds,
|
|
174
|
+
dockerHostIds,
|
|
175
|
+
podmanHostIds,
|
|
176
|
+
kubernetesClusterIds,
|
|
177
|
+
serviceIds,
|
|
178
|
+
proxmoxClusterIds,
|
|
179
|
+
cephClusterIds,
|
|
180
|
+
dockerSwarmClusterIds,
|
|
181
|
+
iotFleetIds,
|
|
182
|
+
] = await Promise.all(
|
|
183
|
+
specs.map((spec: ResourceResolutionSpec): Promise<Array<string>> => {
|
|
184
|
+
return this.resolveResourceIds({
|
|
185
|
+
ids: spec.ids,
|
|
186
|
+
names: spec.names,
|
|
187
|
+
nameColumn: spec.nameColumn,
|
|
188
|
+
projectId: input.projectId,
|
|
189
|
+
findBy: spec.findBy,
|
|
190
|
+
});
|
|
191
|
+
}),
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
return {
|
|
195
|
+
hostIds: hostIds || [],
|
|
196
|
+
dockerHostIds: dockerHostIds || [],
|
|
197
|
+
podmanHostIds: podmanHostIds || [],
|
|
198
|
+
kubernetesClusterIds: kubernetesClusterIds || [],
|
|
199
|
+
serviceIds: serviceIds || [],
|
|
200
|
+
proxmoxClusterIds: proxmoxClusterIds || [],
|
|
201
|
+
cephClusterIds: cephClusterIds || [],
|
|
202
|
+
dockerSwarmClusterIds: dockerSwarmClusterIds || [],
|
|
203
|
+
iotFleetIds: iotFleetIds || [],
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/*
|
|
208
|
+
* Resolve the series' resources and MERGE them onto the alert/incident.
|
|
209
|
+
* Merging (rather than assigning) matters because attachClusterContext
|
|
210
|
+
* writes the same four cluster relations from the monitor's step
|
|
211
|
+
* config; whichever runs second must not erase the other's work.
|
|
212
|
+
*
|
|
213
|
+
* Relations the series says nothing about are left untouched —
|
|
214
|
+
* `undefined`, not `[]` — so an ungrouped event and an event whose
|
|
215
|
+
* resource has been deleted both stay clean rather than persisting an
|
|
216
|
+
* empty join set.
|
|
217
|
+
*
|
|
218
|
+
* The attached rows are id-only stubs. Every in-memory consumer of a
|
|
219
|
+
* freshly created alert/incident reads ids (the owner-inheritance rule
|
|
220
|
+
* engine); anything that needs a name re-reads the persisted relation.
|
|
221
|
+
*/
|
|
222
|
+
public static async linkSeriesResourcesToModel(input: {
|
|
223
|
+
model: SeriesLinkableModel;
|
|
224
|
+
seriesLabels: JSONObject;
|
|
225
|
+
projectId: ObjectID;
|
|
226
|
+
}): Promise<void> {
|
|
227
|
+
const resolved: SeriesResolvedResourceIds =
|
|
228
|
+
await this.resolveResourcesFromSeriesLabels({
|
|
229
|
+
seriesLabels: input.seriesLabels,
|
|
230
|
+
projectId: input.projectId,
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
this.mergeResolvedIdsIntoModel({
|
|
234
|
+
model: input.model,
|
|
235
|
+
resolved: resolved,
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/*
|
|
240
|
+
* Attach the cluster ids resolved from the monitor's step config
|
|
241
|
+
* (Proxmox / Ceph / Docker Swarm / IoT), merging with — never
|
|
242
|
+
* overwriting — anything the series-label path already linked. Both
|
|
243
|
+
* paths can resolve the same cluster, so this dedupes by id. Unlike
|
|
244
|
+
* the label path this runs for ungrouped events too: those monitor
|
|
245
|
+
* types get their cluster identity from the step config alone.
|
|
246
|
+
*/
|
|
247
|
+
public static attachClusterContext(input: {
|
|
248
|
+
model: SeriesLinkableModel;
|
|
249
|
+
clusterContext: MonitorClusterContext;
|
|
250
|
+
}): void {
|
|
251
|
+
this.mergeResolvedIdsIntoModel({
|
|
252
|
+
model: input.model,
|
|
253
|
+
resolved: {
|
|
254
|
+
hostIds: [],
|
|
255
|
+
dockerHostIds: [],
|
|
256
|
+
podmanHostIds: [],
|
|
257
|
+
kubernetesClusterIds: [],
|
|
258
|
+
serviceIds: [],
|
|
259
|
+
proxmoxClusterIds: input.clusterContext.proxmoxClusterIds,
|
|
260
|
+
cephClusterIds: input.clusterContext.cephClusterIds,
|
|
261
|
+
dockerSwarmClusterIds: input.clusterContext.dockerSwarmClusterIds,
|
|
262
|
+
iotFleetIds: input.clusterContext.iotFleetIds,
|
|
263
|
+
},
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
private static mergeResolvedIdsIntoModel(input: {
|
|
268
|
+
model: SeriesLinkableModel;
|
|
269
|
+
resolved: SeriesResolvedResourceIds;
|
|
270
|
+
}): void {
|
|
271
|
+
const model: SeriesLinkableModel = input.model;
|
|
272
|
+
const resolved: SeriesResolvedResourceIds = input.resolved;
|
|
273
|
+
|
|
274
|
+
if (resolved.hostIds.length > 0) {
|
|
275
|
+
model.hosts = this.mergeById(model.hosts, resolved.hostIds, (): Host => {
|
|
276
|
+
return new Host();
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
if (resolved.dockerHostIds.length > 0) {
|
|
281
|
+
model.dockerHosts = this.mergeById(
|
|
282
|
+
model.dockerHosts,
|
|
283
|
+
resolved.dockerHostIds,
|
|
284
|
+
(): DockerHost => {
|
|
285
|
+
return new DockerHost();
|
|
286
|
+
},
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (resolved.podmanHostIds.length > 0) {
|
|
291
|
+
model.podmanHosts = this.mergeById(
|
|
292
|
+
model.podmanHosts,
|
|
293
|
+
resolved.podmanHostIds,
|
|
294
|
+
(): PodmanHost => {
|
|
295
|
+
return new PodmanHost();
|
|
296
|
+
},
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if (resolved.kubernetesClusterIds.length > 0) {
|
|
301
|
+
model.kubernetesClusters = this.mergeById(
|
|
302
|
+
model.kubernetesClusters,
|
|
303
|
+
resolved.kubernetesClusterIds,
|
|
304
|
+
(): KubernetesCluster => {
|
|
305
|
+
return new KubernetesCluster();
|
|
306
|
+
},
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
if (resolved.serviceIds.length > 0) {
|
|
311
|
+
model.services = this.mergeById(
|
|
312
|
+
model.services,
|
|
313
|
+
resolved.serviceIds,
|
|
314
|
+
(): Service => {
|
|
315
|
+
return new Service();
|
|
316
|
+
},
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
if (resolved.proxmoxClusterIds.length > 0) {
|
|
321
|
+
model.proxmoxClusters = this.mergeById(
|
|
322
|
+
model.proxmoxClusters,
|
|
323
|
+
resolved.proxmoxClusterIds,
|
|
324
|
+
(): ProxmoxCluster => {
|
|
325
|
+
return new ProxmoxCluster();
|
|
326
|
+
},
|
|
327
|
+
);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
if (resolved.cephClusterIds.length > 0) {
|
|
331
|
+
model.cephClusters = this.mergeById(
|
|
332
|
+
model.cephClusters,
|
|
333
|
+
resolved.cephClusterIds,
|
|
334
|
+
(): CephCluster => {
|
|
335
|
+
return new CephCluster();
|
|
336
|
+
},
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (resolved.dockerSwarmClusterIds.length > 0) {
|
|
341
|
+
model.dockerSwarmClusters = this.mergeById(
|
|
342
|
+
model.dockerSwarmClusters,
|
|
343
|
+
resolved.dockerSwarmClusterIds,
|
|
344
|
+
(): DockerSwarmCluster => {
|
|
345
|
+
return new DockerSwarmCluster();
|
|
346
|
+
},
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
if (resolved.iotFleetIds.length > 0) {
|
|
351
|
+
model.iotFleets = this.mergeById(
|
|
352
|
+
model.iotFleets,
|
|
353
|
+
resolved.iotFleetIds,
|
|
354
|
+
(): IoTFleet => {
|
|
355
|
+
return new IoTFleet();
|
|
356
|
+
},
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/*
|
|
362
|
+
* Append the ids that aren't attached yet, preserving whatever is
|
|
363
|
+
* already on the relation. A duplicate id in the array would violate
|
|
364
|
+
* the join table's composite primary key on save, so dedupe by the
|
|
365
|
+
* stringified `_id`.
|
|
366
|
+
*/
|
|
367
|
+
private static mergeById<T extends { _id?: string | undefined }>(
|
|
368
|
+
existing: Array<T> | undefined,
|
|
369
|
+
incomingIds: Array<string>,
|
|
370
|
+
create: () => T,
|
|
371
|
+
): Array<T> {
|
|
372
|
+
const merged: Array<T> = [...(existing || [])];
|
|
373
|
+
const seenIds: Set<string> = new Set<string>(
|
|
374
|
+
merged.map((item: T): string => {
|
|
375
|
+
return String(item._id);
|
|
376
|
+
}),
|
|
377
|
+
);
|
|
378
|
+
|
|
379
|
+
for (const id of incomingIds) {
|
|
380
|
+
if (seenIds.has(id)) {
|
|
381
|
+
continue;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
seenIds.add(id);
|
|
385
|
+
|
|
386
|
+
const item: T = create();
|
|
387
|
+
item._id = id;
|
|
388
|
+
merged.push(item);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
return merged;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/*
|
|
395
|
+
* Turn one resource type's ids and names into deduped database ids.
|
|
396
|
+
* Costs zero round-trips when the series carries neither, which is the
|
|
397
|
+
* common case for most of the nine types on any given series.
|
|
398
|
+
*
|
|
399
|
+
* Name matching is exact. Every identifier column read here is written
|
|
400
|
+
* by ingest from the same attribute the series label carries — host
|
|
401
|
+
* identifiers are canonicalized on both sides — so exact matching is
|
|
402
|
+
* what keeps a lookup from straying onto a neighbouring row.
|
|
403
|
+
*/
|
|
404
|
+
private static async resolveResourceIds(input: {
|
|
405
|
+
ids: Array<string>;
|
|
406
|
+
names: Array<string>;
|
|
407
|
+
nameColumn: string;
|
|
408
|
+
projectId: ObjectID;
|
|
409
|
+
/*
|
|
410
|
+
* Loosely typed because each resource service has its own
|
|
411
|
+
* `Query<TBaseModel>` shape and we deliberately abstract over
|
|
412
|
+
* them. We only need the row's `_id` back, which every model
|
|
413
|
+
* exposes via `DatabaseBaseModel`.
|
|
414
|
+
*/
|
|
415
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
416
|
+
findBy: (args: any) => Promise<Array<{ _id?: string | undefined }>>;
|
|
417
|
+
}): Promise<Array<string>> {
|
|
418
|
+
if (input.ids.length === 0 && input.names.length === 0) {
|
|
419
|
+
return [];
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
const resolved: Set<string> = new Set<string>();
|
|
423
|
+
|
|
424
|
+
const lookups: Array<Promise<Array<{ _id?: string | undefined }>>> = [];
|
|
425
|
+
|
|
426
|
+
if (input.ids.length > 0) {
|
|
427
|
+
lookups.push(
|
|
428
|
+
input.findBy({
|
|
429
|
+
query: {
|
|
430
|
+
projectId: input.projectId,
|
|
431
|
+
_id: new Includes(input.ids),
|
|
432
|
+
},
|
|
433
|
+
select: { _id: true },
|
|
434
|
+
skip: 0,
|
|
435
|
+
limit: LIMIT_PER_PROJECT,
|
|
436
|
+
props: { isRoot: true },
|
|
437
|
+
}),
|
|
438
|
+
);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
if (input.names.length > 0) {
|
|
442
|
+
lookups.push(
|
|
443
|
+
input.findBy({
|
|
444
|
+
query: {
|
|
445
|
+
projectId: input.projectId,
|
|
446
|
+
[input.nameColumn]: new Includes(input.names),
|
|
447
|
+
},
|
|
448
|
+
select: { _id: true },
|
|
449
|
+
skip: 0,
|
|
450
|
+
limit: LIMIT_PER_PROJECT,
|
|
451
|
+
props: { isRoot: true },
|
|
452
|
+
}),
|
|
453
|
+
);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
const buckets: Array<Array<{ _id?: string | undefined }>> =
|
|
457
|
+
await Promise.all(lookups);
|
|
458
|
+
|
|
459
|
+
for (const bucket of buckets) {
|
|
460
|
+
for (const row of bucket) {
|
|
461
|
+
if (row._id) {
|
|
462
|
+
resolved.add(String(row._id));
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
return Array.from(resolved);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
@@ -82,10 +82,11 @@ export default class SSRFProtection {
|
|
|
82
82
|
rawUrl: string | URL,
|
|
83
83
|
): Promise<void> {
|
|
84
84
|
/*
|
|
85
|
-
* URL.fromString only knows http/https/ws/wss/mongodb/mailto and
|
|
86
|
-
* DEFAULTS anything else to https - "file:///etc/passwd" comes
|
|
87
|
-
* host "file", not as a file: URL - so the protocol check below
|
|
88
|
-
* the scheme the caller actually wrote. Read it off the raw
|
|
85
|
+
* URL.fromString only knows http/https/ws/wss/mongodb/mailto/tel/sms and
|
|
86
|
+
* silently DEFAULTS anything else to https - "file:///etc/passwd" comes
|
|
87
|
+
* back as host "file", not as a file: URL - so the protocol check below
|
|
88
|
+
* never sees the scheme the caller actually wrote. Read it off the raw
|
|
89
|
+
* string first.
|
|
89
90
|
*
|
|
90
91
|
* The ":" must be followed by "/" or this would treat the host in a
|
|
91
92
|
* scheme-less "example.com:8080/hook" as a scheme and reject it.
|