@oneuptime/common 11.6.0 → 11.6.2
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/AnalyticsModels/AnalyticsBaseModel/AnalyticsBaseModel.ts +41 -24
- package/Models/AnalyticsModels/Index.ts +4 -0
- package/Models/AnalyticsModels/KubernetesCostAllocation.ts +842 -0
- package/Models/AnalyticsModels/MetricBaselineHourly.ts +2 -0
- package/Models/AnalyticsModels/MetricItemAggMV1m.ts +5 -2
- package/Models/AnalyticsModels/MetricItemAggMV1mByContainer.ts +5 -2
- package/Models/AnalyticsModels/MetricItemAggMV1mByHostV2.ts +5 -2
- package/Models/AnalyticsModels/MetricItemAggMV1mByK8sCluster.ts +5 -2
- package/Models/AnalyticsModels/MetricItemAggMV1mByService.ts +5 -2
- package/Models/AnalyticsModels/NetworkFlow.ts +54 -0
- package/Models/AnalyticsModels/SloHistory.ts +240 -0
- package/Models/DatabaseModels/Index.ts +20 -0
- package/Models/DatabaseModels/NetworkDevice.ts +453 -6
- package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +7 -6
- package/Models/DatabaseModels/NetworkEndpoint.ts +753 -0
- package/Models/DatabaseModels/NetworkSite.ts +1155 -0
- package/Models/DatabaseModels/NetworkSiteAssignmentRule.ts +517 -0
- package/Models/DatabaseModels/NetworkSiteLink.ts +611 -0
- package/Models/DatabaseModels/NetworkSiteStatusTimeline.ts +520 -0
- package/Models/DatabaseModels/NetworkSiteType.ts +499 -0
- package/Models/DatabaseModels/ServiceLevelObjective.ts +1106 -0
- package/Models/DatabaseModels/ServiceLevelObjectiveBurnRateRule.ts +762 -0
- package/Models/DatabaseModels/ServiceLevelObjectiveOwnerTeam.ts +444 -0
- package/Models/DatabaseModels/ServiceLevelObjectiveOwnerUser.ts +443 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1784757142154-AddNetworkSiteHierarchyAndEndpoints.ts +359 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1784897317860-AddNetworkSiteAlerting.ts +48 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1784970388777-AddNetworkDevicePollingColumns.ts +65 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1784986826214-AddNetworkSiteTypeTable.ts +88 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1784987015619-AddServiceLevelObjective.ts +391 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +10 -0
- package/Server/Services/AnalyticsDatabaseService.ts +38 -10
- package/Server/Services/Index.ts +24 -0
- package/Server/Services/KubernetesCostAllocationService.ts +14 -0
- package/Server/Services/MetricService.ts +21 -2
- package/Server/Services/MonitorService.ts +22 -0
- package/Server/Services/NetworkDeviceService.ts +438 -2
- package/Server/Services/NetworkEndpointService.ts +414 -0
- package/Server/Services/NetworkSiteAssignmentRuleService.ts +98 -0
- package/Server/Services/NetworkSiteLinkService.ts +10 -0
- package/Server/Services/NetworkSiteService.ts +1254 -0
- package/Server/Services/NetworkSiteStatusTimelineService.ts +10 -0
- package/Server/Services/NetworkSiteTypeService.ts +10 -0
- package/Server/Services/ProjectService.ts +122 -2
- package/Server/Services/ServiceLevelObjectiveBurnRateRuleService.ts +457 -0
- package/Server/Services/ServiceLevelObjectiveOwnerTeamService.ts +10 -0
- package/Server/Services/ServiceLevelObjectiveOwnerUserService.ts +10 -0
- package/Server/Services/ServiceLevelObjectiveService.ts +677 -0
- package/Server/Services/SloHistoryService.ts +101 -0
- package/Server/Services/UserNotificationSettingService.ts +37 -0
- package/Server/Types/AnalyticsDatabase/AggregateBy.ts +9 -0
- package/Server/Types/Database/Permissions/OwnerTableRegistry.ts +15 -0
- package/Server/Utils/AnalyticsDatabase/Statement.ts +39 -3
- package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +128 -52
- package/Server/Utils/Memory.ts +9 -1
- package/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.ts +190 -12
- package/Server/Utils/Monitor/Data/OuiVendors.json +6920 -0
- package/Server/Utils/Monitor/DnsResolutionCache.ts +129 -0
- package/Server/Utils/Monitor/MonitorResource.ts +4 -30
- package/Server/Utils/Monitor/NetworkDeviceHydrationUtil.ts +214 -39
- package/Server/Utils/Monitor/NetworkDeviceMetricUtil.ts +343 -0
- package/Server/Utils/Monitor/NetworkDeviceWalkUtil.ts +251 -0
- package/Server/Utils/Monitor/NetworkInventoryUtil.ts +176 -142
- package/Server/Utils/Monitor/OuiLookupUtil.ts +49 -0
- package/Server/Utils/Monitor/SnmpInterfaceRateUtil.ts +17 -13
- package/Server/Utils/WhatsAppTemplateUtil.ts +7 -3
- package/Tests/Models/AnalyticsModels/AnalyticsBaseModel.test.ts +122 -0
- package/Tests/Models/AnalyticsModels/KubernetesCostAllocation.test.ts +135 -0
- package/Tests/Models/NetworkSiteHierarchy.test.ts +134 -0
- package/Tests/Server/Services/AnalyticsDatabaseService.test.ts +239 -0
- package/Tests/Server/Services/KubernetesCostAllocationAggregate.test.ts +338 -0
- package/Tests/Server/Services/MetricServiceAggregate.test.ts +142 -0
- package/Tests/Server/Services/NetworkDeviceSiteAssignment.test.ts +484 -0
- package/Tests/Server/Services/NetworkEndpointServiceUpsert.test.ts +686 -0
- package/Tests/Server/Services/NetworkSiteAssignmentRuleService.test.ts +185 -0
- package/Tests/Server/Services/NetworkSiteService.test.ts +1354 -0
- package/Tests/Server/Services/ServiceLevelObjectiveBurnRateRuleService.test.ts +1313 -0
- package/Tests/Server/Services/ServiceLevelObjectiveService.test.ts +1988 -0
- package/Tests/Server/Utils/AnalyticsDatabase/ClusterAwareSchema.test.ts +164 -3
- package/Tests/Server/Utils/AnalyticsDatabase/Statement.test.ts +22 -0
- package/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.ts +503 -0
- package/Tests/Server/Utils/Encryption.test.ts +70 -0
- package/Tests/Server/Utils/FileAttachmentMarkdownUtil.test.ts +225 -0
- package/Tests/Server/Utils/JsonWebToken.test.ts +175 -0
- package/Tests/Server/Utils/LocalFile.test.ts +258 -0
- package/Tests/Server/Utils/Memory.test.ts +213 -0
- package/Tests/Server/Utils/Monitor/Criteria/LogMonitorCriteria.test.ts +30 -0
- package/Tests/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.test.ts +385 -0
- package/Tests/Server/Utils/Monitor/DnsResolutionCache.test.ts +194 -0
- package/Tests/Server/Utils/Monitor/NetworkDeviceHydrationUtil.test.ts +155 -0
- package/Tests/Server/Utils/Monitor/NetworkDeviceWalkUtil.test.ts +600 -0
- package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +151 -124
- package/Tests/Server/Utils/Monitor/SnmpInterfaceRateUtil.test.ts +496 -0
- package/Tests/Server/Utils/MonitorCriteriaDataExtractor.test.ts +175 -0
- package/Tests/Server/Utils/MonitorCriteriaMessageFormatter.test.ts +282 -0
- package/Tests/Server/Utils/OuiLookupUtil.test.ts +59 -0
- package/Tests/Server/Utils/SeriesResourceLabels.test.ts +117 -0
- package/Tests/Server/Utils/StackTraceParser.test.ts +370 -0
- package/Tests/Server/Utils/Stream.test.ts +87 -0
- package/Tests/Server/Utils/ValidateGlobalProviderProjectTeams.test.ts +221 -0
- package/Tests/Server/Utils/WhatsAppTemplateUtil.test.ts +199 -0
- package/Tests/Types/Database/CompareOperatorWireSerialization.test.ts +33 -0
- package/Tests/Types/Email.test.ts +198 -0
- package/Tests/Types/HashCode.test.ts +41 -0
- package/Tests/Types/Kubernetes/KubernetesObjectParser.test.ts +177 -0
- package/Tests/Types/Log/LogQueryParser.test.ts +186 -0
- package/Tests/Types/Log/LogQueryToFilter.test.ts +111 -0
- package/Tests/Types/Monitor/MonitorStepNetworkDeviceMonitor.test.ts +141 -1
- package/Tests/Types/Monitor/MonitorType.test.ts +59 -1
- package/Tests/Types/Monitor/NetworkDeviceAlertPack.test.ts +97 -0
- package/Tests/Types/Monitor/SnmpEndpointDiscovery.test.ts +151 -0
- package/Tests/Types/Monitor/SnmpVendorTemplate.test.ts +110 -6
- package/Tests/Types/NetworkSite/DefaultNetworkSiteType.test.ts +129 -0
- package/Tests/Types/SerializableObjectDictionary.test.ts +166 -0
- package/Tests/Types/Time/RangeStartAndEndDateTime.test.ts +98 -0
- package/Tests/Types/WebsiteRequest.test.ts +230 -0
- package/Tests/UI/Components/EntityFilterRoundTrip.test.tsx +103 -0
- package/Tests/UI/Components/ModelTable/BaseModelTableUrlState.test.tsx +612 -0
- package/Tests/UI/Components/ModelTable/FilterDataToQuery.test.ts +275 -0
- package/Tests/UI/Utils/LogExport.test.ts +159 -0
- package/Tests/UI/Utils/Navigation.test.ts +183 -0
- package/Tests/UI/Utils/TableFilterUrlState.test.ts +539 -0
- package/Tests/UI/Utils/TableViewUrlState.test.ts +272 -0
- package/Tests/Utils/Base64.test.ts +51 -0
- package/Tests/Utils/Boolean.test.ts +76 -0
- package/Tests/Utils/Crypto.test.ts +48 -0
- package/Tests/Utils/Dashboard/DashboardSloComponent.test.ts +259 -0
- package/Tests/Utils/Dashboard/ModelQueryVariableInterpolation.test.ts +162 -0
- package/Tests/Utils/Dashboard/VariableInterpolation.test.ts +197 -0
- package/Tests/Utils/Enum.test.ts +54 -0
- package/Tests/Utils/IpCanonicalUtil.test.ts +85 -0
- package/Tests/Utils/Metrics/MetricSeriesFingerprint.test.ts +160 -0
- package/Tests/Utils/Monitor/EndpointAttachmentUtil.test.ts +836 -0
- package/Tests/Utils/Monitor/MonitorMetricType.test.ts +218 -0
- package/Tests/Utils/Monitor/NetworkTopologyUtil.test.ts +447 -0
- package/Tests/Utils/NetworkSite/CidrMatchUtil.test.ts +440 -0
- package/Tests/Utils/NetworkSite/MaterializedPathUtil.test.ts +205 -0
- package/Tests/Utils/NetworkSite/SiteStatusRollupUtil.test.ts +221 -0
- package/Tests/Utils/NetworkSite/SiteUptimeUtil.test.ts +283 -0
- package/Tests/Utils/ObjectUtil.test.ts +30 -0
- package/Tests/Utils/Slo/SloStatusColor.test.ts +89 -0
- package/Tests/Utils/Slo/SloUtil.test.ts +1980 -0
- package/Tests/Utils/Slo/SloWidgetFormat.test.ts +605 -0
- package/Tests/Utils/TechStack.test.ts +50 -0
- package/Tests/Utils/Traces/CriticalPath.test.ts +178 -0
- package/Tests/Utils/ValueFormatter.test.ts +305 -0
- package/Types/AnalyticsDatabase/AnalyticsTableName.ts +10 -0
- package/Types/AnalyticsDatabase/TableColumn.ts +23 -0
- package/Types/BaseDatabase/EqualTo.ts +9 -1
- package/Types/BaseDatabase/EqualToOrNull.ts +9 -1
- package/Types/BaseDatabase/NotEqual.ts +9 -1
- package/Types/Dashboard/DashboardComponentType.ts +1 -0
- package/Types/Dashboard/DashboardComponents/ComponentArgument.ts +1 -0
- package/Types/Dashboard/DashboardComponents/DashboardSloComponent.ts +42 -0
- package/Types/Dashboard/DashboardTemplates.ts +214 -0
- package/Types/Email/EmailTemplateType.ts +2 -0
- package/Types/Kubernetes/KubernetesCostIngest.ts +79 -0
- package/Types/Monitor/CriteriaFilter.ts +9 -0
- package/Types/Monitor/MonitorStep.ts +5 -8
- package/Types/Monitor/MonitorStepNetworkDeviceMonitor.ts +27 -5
- package/Types/Monitor/MonitorType.ts +15 -5
- package/Types/Monitor/SnmpMonitor/ArpEntry.ts +14 -0
- package/Types/Monitor/SnmpMonitor/FdbEntry.ts +18 -0
- package/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.ts +10 -3
- package/Types/Monitor/SnmpMonitor/NetworkTopology.ts +31 -5
- package/Types/Monitor/SnmpMonitor/SnmpMonitorResponse.ts +12 -0
- package/Types/Monitor/SnmpMonitor/SnmpVendorTemplate.ts +231 -3
- package/Types/NetworkSite/DefaultNetworkSiteType.ts +20 -0
- package/Types/NotificationSetting/NotificationSettingEventType.ts +4 -0
- package/Types/Permission.ts +449 -0
- package/Types/ServiceLevelObjective/SliType.ts +6 -0
- package/Types/ServiceLevelObjective/SloMultiMonitorMode.ts +6 -0
- package/Types/ServiceLevelObjective/SloStatus.ts +9 -0
- package/Types/ServiceLevelObjective/SloWindowType.ts +6 -0
- package/Types/Telemetry/ServiceType.ts +1 -0
- package/UI/Components/Filters/EntityFilter.tsx +16 -0
- package/UI/Components/Filters/FilterViewer.tsx +22 -5
- package/UI/Components/List/List.tsx +8 -0
- package/UI/Components/ModelTable/BaseModelTable.tsx +309 -106
- package/UI/Components/ModelTable/FilterDataToQuery.ts +172 -0
- package/UI/Components/Navbar/NavBar.tsx +16 -2
- package/UI/Components/Navbar/NavBarMenuModal.tsx +3 -3
- package/UI/Utils/Navigation.ts +10 -0
- package/UI/Utils/TableFilterUrlState.ts +204 -17
- package/UI/Utils/TableViewUrlState.ts +165 -0
- package/Utils/Dashboard/Components/DashboardSloComponent.ts +114 -0
- package/Utils/Dashboard/Components/Index.ts +7 -0
- package/Utils/IpCanonicalUtil.ts +134 -0
- package/Utils/Monitor/EndpointAttachmentUtil.ts +508 -0
- package/Utils/Monitor/NetworkTopologyUtil.ts +157 -5
- package/Utils/NetworkSite/CidrMatchUtil.ts +296 -0
- package/Utils/NetworkSite/MaterializedPathUtil.ts +115 -0
- package/Utils/NetworkSite/SiteStatusRollupUtil.ts +97 -0
- package/Utils/NetworkSite/SiteUptimeUtil.ts +111 -0
- package/Utils/Slo/SloStatusColor.ts +54 -0
- package/Utils/Slo/SloUtil.ts +637 -0
- package/Utils/Slo/SloWidgetFormat.ts +383 -0
- package/build/dist/Models/AnalyticsModels/AnalyticsBaseModel/AnalyticsBaseModel.js +25 -20
- package/build/dist/Models/AnalyticsModels/AnalyticsBaseModel/AnalyticsBaseModel.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/Index.js +4 -0
- package/build/dist/Models/AnalyticsModels/Index.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/KubernetesCostAllocation.js +713 -0
- package/build/dist/Models/AnalyticsModels/KubernetesCostAllocation.js.map +1 -0
- package/build/dist/Models/AnalyticsModels/MetricBaselineHourly.js +2 -0
- package/build/dist/Models/AnalyticsModels/MetricBaselineHourly.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/MetricItemAggMV1m.js +5 -2
- package/build/dist/Models/AnalyticsModels/MetricItemAggMV1m.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByContainer.js +5 -2
- package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByContainer.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByHostV2.js +5 -2
- package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByHostV2.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByK8sCluster.js +5 -2
- package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByK8sCluster.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByService.js +5 -2
- package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByService.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/NetworkFlow.js +44 -0
- package/build/dist/Models/AnalyticsModels/NetworkFlow.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/SloHistory.js +215 -0
- package/build/dist/Models/AnalyticsModels/SloHistory.js.map +1 -0
- package/build/dist/Models/DatabaseModels/Index.js +20 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDevice.js +458 -6
- package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js +0 -6
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkEndpoint.js +779 -0
- package/build/dist/Models/DatabaseModels/NetworkEndpoint.js.map +1 -0
- package/build/dist/Models/DatabaseModels/NetworkSite.js +1180 -0
- package/build/dist/Models/DatabaseModels/NetworkSite.js.map +1 -0
- package/build/dist/Models/DatabaseModels/NetworkSiteAssignmentRule.js +534 -0
- package/build/dist/Models/DatabaseModels/NetworkSiteAssignmentRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/NetworkSiteLink.js +629 -0
- package/build/dist/Models/DatabaseModels/NetworkSiteLink.js.map +1 -0
- package/build/dist/Models/DatabaseModels/NetworkSiteStatusTimeline.js +538 -0
- package/build/dist/Models/DatabaseModels/NetworkSiteStatusTimeline.js.map +1 -0
- package/build/dist/Models/DatabaseModels/NetworkSiteType.js +522 -0
- package/build/dist/Models/DatabaseModels/NetworkSiteType.js.map +1 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjective.js +1124 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjective.js.map +1 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveBurnRateRule.js +769 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveBurnRateRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerTeam.js +460 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerTeam.js.map +1 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerUser.js +459 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerUser.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784757142154-AddNetworkSiteHierarchyAndEndpoints.js +130 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784757142154-AddNetworkSiteHierarchyAndEndpoints.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784897317860-AddNetworkSiteAlerting.js +31 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784897317860-AddNetworkSiteAlerting.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784970388777-AddNetworkDevicePollingColumns.js +36 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784970388777-AddNetworkDevicePollingColumns.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784986826214-AddNetworkSiteTypeTable.js +49 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784986826214-AddNetworkSiteTypeTable.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784987015619-AddServiceLevelObjective.js +140 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784987015619-AddServiceLevelObjective.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +10 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/AnalyticsDatabaseService.js +32 -7
- package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +24 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/KubernetesCostAllocationService.js +12 -0
- package/build/dist/Server/Services/KubernetesCostAllocationService.js.map +1 -0
- package/build/dist/Server/Services/MetricService.js +21 -3
- package/build/dist/Server/Services/MetricService.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +19 -0
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceService.js +351 -1
- package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
- package/build/dist/Server/Services/NetworkEndpointService.js +319 -0
- package/build/dist/Server/Services/NetworkEndpointService.js.map +1 -0
- package/build/dist/Server/Services/NetworkSiteAssignmentRuleService.js +90 -0
- package/build/dist/Server/Services/NetworkSiteAssignmentRuleService.js.map +1 -0
- package/build/dist/Server/Services/NetworkSiteLinkService.js +9 -0
- package/build/dist/Server/Services/NetworkSiteLinkService.js.map +1 -0
- package/build/dist/Server/Services/NetworkSiteService.js +1038 -0
- package/build/dist/Server/Services/NetworkSiteService.js.map +1 -0
- package/build/dist/Server/Services/NetworkSiteStatusTimelineService.js +9 -0
- package/build/dist/Server/Services/NetworkSiteStatusTimelineService.js.map +1 -0
- package/build/dist/Server/Services/NetworkSiteTypeService.js +9 -0
- package/build/dist/Server/Services/NetworkSiteTypeService.js.map +1 -0
- package/build/dist/Server/Services/ProjectService.js +98 -2
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/ServiceLevelObjectiveBurnRateRuleService.js +358 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveBurnRateRuleService.js.map +1 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveOwnerTeamService.js +9 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveOwnerTeamService.js.map +1 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveOwnerUserService.js +9 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveOwnerUserService.js.map +1 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveService.js +582 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveService.js.map +1 -0
- package/build/dist/Server/Services/SloHistoryService.js +77 -0
- package/build/dist/Server/Services/SloHistoryService.js.map +1 -0
- package/build/dist/Server/Services/UserNotificationSettingService.js +20 -0
- package/build/dist/Server/Services/UserNotificationSettingService.js.map +1 -1
- package/build/dist/Server/Types/AnalyticsDatabase/AggregateBy.js +9 -0
- package/build/dist/Server/Types/AnalyticsDatabase/AggregateBy.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js +15 -0
- package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js +31 -0
- package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +105 -52
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
- package/build/dist/Server/Utils/Memory.js +9 -1
- package/build/dist/Server/Utils/Memory.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js +132 -10
- package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Data/OuiVendors.json +6920 -0
- package/build/dist/Server/Utils/Monitor/DnsResolutionCache.js +77 -0
- package/build/dist/Server/Utils/Monitor/DnsResolutionCache.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorResource.js +21 -41
- package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js +152 -40
- package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js +262 -0
- package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js +201 -0
- package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +152 -120
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/OuiLookupUtil.js +44 -0
- package/build/dist/Server/Utils/Monitor/OuiLookupUtil.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/SnmpInterfaceRateUtil.js +10 -10
- package/build/dist/Server/Utils/Monitor/SnmpInterfaceRateUtil.js.map +1 -1
- package/build/dist/Server/Utils/WhatsAppTemplateUtil.js +5 -0
- package/build/dist/Server/Utils/WhatsAppTemplateUtil.js.map +1 -1
- package/build/dist/Types/AnalyticsDatabase/AnalyticsTableName.js +10 -0
- package/build/dist/Types/AnalyticsDatabase/AnalyticsTableName.js.map +1 -1
- package/build/dist/Types/AnalyticsDatabase/TableColumn.js +7 -0
- package/build/dist/Types/AnalyticsDatabase/TableColumn.js.map +1 -1
- package/build/dist/Types/BaseDatabase/EqualTo.js +9 -1
- package/build/dist/Types/BaseDatabase/EqualTo.js.map +1 -1
- package/build/dist/Types/BaseDatabase/EqualToOrNull.js +9 -1
- package/build/dist/Types/BaseDatabase/EqualToOrNull.js.map +1 -1
- package/build/dist/Types/BaseDatabase/NotEqual.js +9 -1
- package/build/dist/Types/BaseDatabase/NotEqual.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardComponentType.js +1 -0
- package/build/dist/Types/Dashboard/DashboardComponentType.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js +1 -0
- package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardSloComponent.js +23 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardSloComponent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardTemplates.js +205 -0
- package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
- package/build/dist/Types/Email/EmailTemplateType.js +1 -0
- package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
- package/build/dist/Types/Kubernetes/KubernetesCostIngest.js +21 -0
- package/build/dist/Types/Kubernetes/KubernetesCostIngest.js.map +1 -0
- package/build/dist/Types/Monitor/CriteriaFilter.js +1 -0
- package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStep.js +5 -5
- package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepNetworkDeviceMonitor.js +8 -0
- package/build/dist/Types/Monitor/MonitorStepNetworkDeviceMonitor.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorType.js +15 -5
- package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
- package/build/dist/Types/Monitor/SnmpMonitor/ArpEntry.js +2 -0
- package/build/dist/Types/Monitor/SnmpMonitor/ArpEntry.js.map +1 -0
- package/build/dist/Types/Monitor/SnmpMonitor/FdbEntry.js +2 -0
- package/build/dist/Types/Monitor/SnmpMonitor/FdbEntry.js.map +1 -0
- package/build/dist/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.js +9 -3
- package/build/dist/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.js.map +1 -1
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpVendorTemplate.js +217 -3
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpVendorTemplate.js.map +1 -1
- package/build/dist/Types/NetworkSite/DefaultNetworkSiteType.js +21 -0
- package/build/dist/Types/NetworkSite/DefaultNetworkSiteType.js.map +1 -0
- package/build/dist/Types/NotificationSetting/NotificationSettingEventType.js +3 -0
- package/build/dist/Types/NotificationSetting/NotificationSettingEventType.js.map +1 -1
- package/build/dist/Types/Permission.js +409 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/ServiceLevelObjective/SliType.js +7 -0
- package/build/dist/Types/ServiceLevelObjective/SliType.js.map +1 -0
- package/build/dist/Types/ServiceLevelObjective/SloMultiMonitorMode.js +7 -0
- package/build/dist/Types/ServiceLevelObjective/SloMultiMonitorMode.js.map +1 -0
- package/build/dist/Types/ServiceLevelObjective/SloStatus.js +10 -0
- package/build/dist/Types/ServiceLevelObjective/SloStatus.js.map +1 -0
- package/build/dist/Types/ServiceLevelObjective/SloWindowType.js +7 -0
- package/build/dist/Types/ServiceLevelObjective/SloWindowType.js.map +1 -0
- package/build/dist/Types/Telemetry/ServiceType.js +1 -0
- package/build/dist/Types/Telemetry/ServiceType.js.map +1 -1
- package/build/dist/UI/Components/Filters/EntityFilter.js +15 -0
- package/build/dist/UI/Components/Filters/EntityFilter.js.map +1 -1
- package/build/dist/UI/Components/Filters/FilterViewer.js +19 -4
- package/build/dist/UI/Components/Filters/FilterViewer.js.map +1 -1
- package/build/dist/UI/Components/List/List.js +1 -1
- package/build/dist/UI/Components/List/List.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +235 -89
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/FilterDataToQuery.js +96 -0
- package/build/dist/UI/Components/ModelTable/FilterDataToQuery.js.map +1 -0
- package/build/dist/UI/Components/Navbar/NavBar.js +14 -2
- package/build/dist/UI/Components/Navbar/NavBar.js.map +1 -1
- package/build/dist/UI/Components/Navbar/NavBarMenuModal.js +3 -2
- package/build/dist/UI/Components/Navbar/NavBarMenuModal.js.map +1 -1
- package/build/dist/UI/Utils/Navigation.js +9 -0
- package/build/dist/UI/Utils/Navigation.js.map +1 -1
- package/build/dist/UI/Utils/TableFilterUrlState.js +159 -15
- package/build/dist/UI/Utils/TableFilterUrlState.js.map +1 -1
- package/build/dist/UI/Utils/TableViewUrlState.js +103 -0
- package/build/dist/UI/Utils/TableViewUrlState.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardSloComponent.js +93 -0
- package/build/dist/Utils/Dashboard/Components/DashboardSloComponent.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/Index.js +4 -0
- package/build/dist/Utils/Dashboard/Components/Index.js.map +1 -1
- package/build/dist/Utils/IpCanonicalUtil.js +110 -0
- package/build/dist/Utils/IpCanonicalUtil.js.map +1 -0
- package/build/dist/Utils/Monitor/EndpointAttachmentUtil.js +311 -0
- package/build/dist/Utils/Monitor/EndpointAttachmentUtil.js.map +1 -0
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +98 -5
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
- package/build/dist/Utils/NetworkSite/CidrMatchUtil.js +222 -0
- package/build/dist/Utils/NetworkSite/CidrMatchUtil.js.map +1 -0
- package/build/dist/Utils/NetworkSite/MaterializedPathUtil.js +89 -0
- package/build/dist/Utils/NetworkSite/MaterializedPathUtil.js.map +1 -0
- package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js +60 -0
- package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js.map +1 -0
- package/build/dist/Utils/NetworkSite/SiteUptimeUtil.js +76 -0
- package/build/dist/Utils/NetworkSite/SiteUptimeUtil.js.map +1 -0
- package/build/dist/Utils/Slo/SloStatusColor.js +18 -0
- package/build/dist/Utils/Slo/SloStatusColor.js.map +1 -0
- package/build/dist/Utils/Slo/SloUtil.js +393 -0
- package/build/dist/Utils/Slo/SloUtil.js.map +1 -0
- package/build/dist/Utils/Slo/SloWidgetFormat.js +174 -0
- package/build/dist/Utils/Slo/SloWidgetFormat.js.map +1 -0
- package/package.json +2 -2
- package/Types/Dashboard/DashboardComponents/Index.ts +0 -7
- package/build/dist/Types/Dashboard/DashboardComponents/Index.js +0 -8
- package/build/dist/Types/Dashboard/DashboardComponents/Index.js.map +0 -1
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
2
|
+
import File from "../../../Models/DatabaseModels/File";
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
* FileService reaches Postgres, so it is faked. The behaviour worth pinning is
|
|
6
|
+
* the util's own bookkeeping: it de-duplicates ids before querying, but then
|
|
7
|
+
* renders from the ORIGINAL id list, so a duplicated id renders twice. The
|
|
8
|
+
* tests below state that explicitly rather than leaving it to be discovered.
|
|
9
|
+
*/
|
|
10
|
+
const findByMock: jest.Mock = jest.fn();
|
|
11
|
+
|
|
12
|
+
jest.mock("../../../Server/Services/FileService", () => {
|
|
13
|
+
return {
|
|
14
|
+
__esModule: true,
|
|
15
|
+
default: {
|
|
16
|
+
findBy: (...args: Array<unknown>) => {
|
|
17
|
+
return findByMock(...args);
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
import FileAttachmentMarkdownUtil from "../../../Server/Utils/FileAttachmentMarkdownUtil";
|
|
24
|
+
|
|
25
|
+
type MakeFileFunction = (data: { id: string; name?: string }) => File;
|
|
26
|
+
|
|
27
|
+
const makeFile: MakeFileFunction = (data: {
|
|
28
|
+
id: string;
|
|
29
|
+
name?: string;
|
|
30
|
+
}): File => {
|
|
31
|
+
const file: File = new File();
|
|
32
|
+
file._id = data.id;
|
|
33
|
+
|
|
34
|
+
if (data.name !== undefined) {
|
|
35
|
+
file.name = data.name;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return file;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
describe("FileAttachmentMarkdownUtil.buildAttachmentMarkdown", () => {
|
|
42
|
+
const modelId: ObjectID = ObjectID.generate();
|
|
43
|
+
const attachmentApiPath: string = "/incident/attachment";
|
|
44
|
+
|
|
45
|
+
beforeEach(() => {
|
|
46
|
+
findByMock.mockReset();
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("should return an empty string when there are no attachment ids", async () => {
|
|
50
|
+
expect(
|
|
51
|
+
await FileAttachmentMarkdownUtil.buildAttachmentMarkdown({
|
|
52
|
+
modelId,
|
|
53
|
+
attachmentIds: [],
|
|
54
|
+
attachmentApiPath,
|
|
55
|
+
}),
|
|
56
|
+
).toEqual("");
|
|
57
|
+
|
|
58
|
+
expect(findByMock).not.toHaveBeenCalled();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test("should return an empty string when there is no model id", async () => {
|
|
62
|
+
expect(
|
|
63
|
+
await FileAttachmentMarkdownUtil.buildAttachmentMarkdown({
|
|
64
|
+
modelId: undefined as unknown as ObjectID,
|
|
65
|
+
attachmentIds: [ObjectID.generate()],
|
|
66
|
+
attachmentApiPath,
|
|
67
|
+
}),
|
|
68
|
+
).toEqual("");
|
|
69
|
+
|
|
70
|
+
expect(findByMock).not.toHaveBeenCalled();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test("should return an empty string when no files are found", async () => {
|
|
74
|
+
findByMock.mockResolvedValue([]);
|
|
75
|
+
|
|
76
|
+
expect(
|
|
77
|
+
await FileAttachmentMarkdownUtil.buildAttachmentMarkdown({
|
|
78
|
+
modelId,
|
|
79
|
+
attachmentIds: [ObjectID.generate()],
|
|
80
|
+
attachmentApiPath,
|
|
81
|
+
}),
|
|
82
|
+
).toEqual("");
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test("should render a markdown link per file", async () => {
|
|
86
|
+
const first: ObjectID = ObjectID.generate();
|
|
87
|
+
const second: ObjectID = ObjectID.generate();
|
|
88
|
+
|
|
89
|
+
findByMock.mockResolvedValue([
|
|
90
|
+
makeFile({ id: first.toString(), name: "runbook.pdf" }),
|
|
91
|
+
makeFile({ id: second.toString(), name: "screenshot.png" }),
|
|
92
|
+
]);
|
|
93
|
+
|
|
94
|
+
const markdown: string =
|
|
95
|
+
await FileAttachmentMarkdownUtil.buildAttachmentMarkdown({
|
|
96
|
+
modelId,
|
|
97
|
+
attachmentIds: [first, second],
|
|
98
|
+
attachmentApiPath,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
expect(markdown).toContain("**Attachments:**");
|
|
102
|
+
expect(markdown).toContain(`[runbook.pdf](`);
|
|
103
|
+
expect(markdown).toContain(`[screenshot.png](`);
|
|
104
|
+
expect(markdown).toContain(`${modelId.toString()}/${first.toString()}`);
|
|
105
|
+
expect(markdown).toContain(`${modelId.toString()}/${second.toString()}`);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test("should render links in the order the ids were given, not the order they were found", async () => {
|
|
109
|
+
const first: ObjectID = ObjectID.generate();
|
|
110
|
+
const second: ObjectID = ObjectID.generate();
|
|
111
|
+
|
|
112
|
+
// The database returns them the other way round.
|
|
113
|
+
findByMock.mockResolvedValue([
|
|
114
|
+
makeFile({ id: second.toString(), name: "second.txt" }),
|
|
115
|
+
makeFile({ id: first.toString(), name: "first.txt" }),
|
|
116
|
+
]);
|
|
117
|
+
|
|
118
|
+
const markdown: string =
|
|
119
|
+
await FileAttachmentMarkdownUtil.buildAttachmentMarkdown({
|
|
120
|
+
modelId,
|
|
121
|
+
attachmentIds: [first, second],
|
|
122
|
+
attachmentApiPath,
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
expect(markdown.indexOf("first.txt")).toBeLessThan(
|
|
126
|
+
markdown.indexOf("second.txt"),
|
|
127
|
+
);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test("should skip ids that have no matching file", async () => {
|
|
131
|
+
const found: ObjectID = ObjectID.generate();
|
|
132
|
+
const missing: ObjectID = ObjectID.generate();
|
|
133
|
+
|
|
134
|
+
findByMock.mockResolvedValue([
|
|
135
|
+
makeFile({ id: found.toString(), name: "found.txt" }),
|
|
136
|
+
]);
|
|
137
|
+
|
|
138
|
+
const markdown: string =
|
|
139
|
+
await FileAttachmentMarkdownUtil.buildAttachmentMarkdown({
|
|
140
|
+
modelId,
|
|
141
|
+
attachmentIds: [found, missing],
|
|
142
|
+
attachmentApiPath,
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
expect(markdown).toContain("found.txt");
|
|
146
|
+
expect(markdown).not.toContain(missing.toString());
|
|
147
|
+
expect(markdown.split("\n- ").length - 1).toEqual(1);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
test("should query each distinct id only once", async () => {
|
|
151
|
+
const id: ObjectID = ObjectID.generate();
|
|
152
|
+
|
|
153
|
+
findByMock.mockResolvedValue([
|
|
154
|
+
makeFile({ id: id.toString(), name: "a.txt" }),
|
|
155
|
+
]);
|
|
156
|
+
|
|
157
|
+
await FileAttachmentMarkdownUtil.buildAttachmentMarkdown({
|
|
158
|
+
modelId,
|
|
159
|
+
attachmentIds: [id, id, id],
|
|
160
|
+
attachmentApiPath,
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
const query: Record<string, unknown> = (
|
|
164
|
+
findByMock.mock.calls[0]![0] as Record<string, Record<string, unknown>>
|
|
165
|
+
)["query"]!;
|
|
166
|
+
|
|
167
|
+
expect(JSON.stringify(query)).toContain(id.toString());
|
|
168
|
+
// De-duplicated: the id must appear exactly once in the query.
|
|
169
|
+
expect(JSON.stringify(query).split(id.toString()).length - 1).toEqual(1);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
test("should still render a duplicated id once per occurrence", async () => {
|
|
173
|
+
/*
|
|
174
|
+
* De-duplication happens for the lookup only; rendering walks the original
|
|
175
|
+
* attachmentIds array. Pinning current behaviour so a change here is a
|
|
176
|
+
* deliberate one.
|
|
177
|
+
*/
|
|
178
|
+
const id: ObjectID = ObjectID.generate();
|
|
179
|
+
|
|
180
|
+
findByMock.mockResolvedValue([
|
|
181
|
+
makeFile({ id: id.toString(), name: "a.txt" }),
|
|
182
|
+
]);
|
|
183
|
+
|
|
184
|
+
const markdown: string =
|
|
185
|
+
await FileAttachmentMarkdownUtil.buildAttachmentMarkdown({
|
|
186
|
+
modelId,
|
|
187
|
+
attachmentIds: [id, id],
|
|
188
|
+
attachmentApiPath,
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
expect(markdown.split("a.txt").length - 1).toEqual(2);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
test("should fall back to 'Attachment' when a file has no name", async () => {
|
|
195
|
+
const id: ObjectID = ObjectID.generate();
|
|
196
|
+
|
|
197
|
+
findByMock.mockResolvedValue([makeFile({ id: id.toString() })]);
|
|
198
|
+
|
|
199
|
+
const markdown: string =
|
|
200
|
+
await FileAttachmentMarkdownUtil.buildAttachmentMarkdown({
|
|
201
|
+
modelId,
|
|
202
|
+
attachmentIds: [id],
|
|
203
|
+
attachmentApiPath,
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
expect(markdown).toContain("[Attachment](");
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
test("should build the route from the given api path", async () => {
|
|
210
|
+
const id: ObjectID = ObjectID.generate();
|
|
211
|
+
|
|
212
|
+
findByMock.mockResolvedValue([
|
|
213
|
+
makeFile({ id: id.toString(), name: "a.txt" }),
|
|
214
|
+
]);
|
|
215
|
+
|
|
216
|
+
const markdown: string =
|
|
217
|
+
await FileAttachmentMarkdownUtil.buildAttachmentMarkdown({
|
|
218
|
+
modelId,
|
|
219
|
+
attachmentIds: [id],
|
|
220
|
+
attachmentApiPath: "/alert/attachment",
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
expect(markdown).toContain("/alert/attachment/");
|
|
224
|
+
});
|
|
225
|
+
});
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import JSONWebToken from "../../../Server/Utils/JsonWebToken";
|
|
2
|
+
import { EncryptionSecret } from "../../../Server/EnvironmentConfig";
|
|
3
|
+
import BadDataException from "../../../Types/Exception/BadDataException";
|
|
4
|
+
import Email from "../../../Types/Email";
|
|
5
|
+
import { JSONObject } from "../../../Types/JSON";
|
|
6
|
+
import JSONWebTokenData from "../../../Types/JsonWebTokenData";
|
|
7
|
+
import Name from "../../../Types/Name";
|
|
8
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
9
|
+
import Timezone from "../../../Types/Timezone";
|
|
10
|
+
import jwt from "jsonwebtoken";
|
|
11
|
+
import { generateKeyPairSync } from "crypto";
|
|
12
|
+
|
|
13
|
+
describe("JSONWebToken", () => {
|
|
14
|
+
const userId: ObjectID = ObjectID.generate();
|
|
15
|
+
const sessionId: ObjectID = ObjectID.generate();
|
|
16
|
+
const email: Email = new Email("jwt-test@oneuptime.com");
|
|
17
|
+
|
|
18
|
+
describe("signJsonPayload / decodeJsonPayload", () => {
|
|
19
|
+
test("should round trip a json payload", () => {
|
|
20
|
+
const token: string = JSONWebToken.signJsonPayload(
|
|
21
|
+
{ hello: "world" },
|
|
22
|
+
300,
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
const decoded: JSONObject = JSONWebToken.decodeJsonPayload(token);
|
|
26
|
+
|
|
27
|
+
expect(decoded["hello"]).toEqual("world");
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test("should set an expiry claim on the token", () => {
|
|
31
|
+
const token: string = JSONWebToken.signJsonPayload(
|
|
32
|
+
{ hello: "world" },
|
|
33
|
+
300,
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const decoded: JSONObject = JSONWebToken.decodeJsonPayload(token);
|
|
37
|
+
|
|
38
|
+
expect(decoded["exp"]).toBeDefined();
|
|
39
|
+
expect(decoded["iat"]).toBeDefined();
|
|
40
|
+
expect((decoded["exp"] as number) - (decoded["iat"] as number)).toEqual(
|
|
41
|
+
300,
|
|
42
|
+
);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test("should throw when the token was signed with a different secret", () => {
|
|
46
|
+
const token: string = jwt.sign({ hello: "world" }, "some-other-secret", {
|
|
47
|
+
expiresIn: 300,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
expect(() => {
|
|
51
|
+
return JSONWebToken.decodeJsonPayload(token);
|
|
52
|
+
}).toThrow();
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
describe("signUserLoginToken / decode", () => {
|
|
57
|
+
test("should round trip user login token data", () => {
|
|
58
|
+
const token: string = JSONWebToken.signUserLoginToken({
|
|
59
|
+
tokenData: {
|
|
60
|
+
userId: userId,
|
|
61
|
+
email: email,
|
|
62
|
+
name: new Name("Test User"),
|
|
63
|
+
timezone: Timezone.AsiaKolkata,
|
|
64
|
+
isMasterAdmin: true,
|
|
65
|
+
isGlobalLogin: true,
|
|
66
|
+
sessionId: sessionId,
|
|
67
|
+
},
|
|
68
|
+
expiresInSeconds: 300,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const decoded: JSONWebTokenData = JSONWebToken.decode(token);
|
|
72
|
+
|
|
73
|
+
expect(decoded.userId.toString()).toEqual(userId.toString());
|
|
74
|
+
expect(decoded.email.toString()).toEqual(email.toString());
|
|
75
|
+
expect(decoded.name?.toString()).toEqual("Test User");
|
|
76
|
+
expect(decoded.isMasterAdmin).toBe(true);
|
|
77
|
+
expect(decoded.isGlobalLogin).toBe(true);
|
|
78
|
+
expect(decoded.sessionId?.toString()).toEqual(sessionId.toString());
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test("should leave sessionId undefined when it was not signed", () => {
|
|
82
|
+
const token: string = JSONWebToken.sign({
|
|
83
|
+
data: {
|
|
84
|
+
userId: userId,
|
|
85
|
+
email: email,
|
|
86
|
+
name: new Name("Test User"),
|
|
87
|
+
isMasterAdmin: false,
|
|
88
|
+
isGlobalLogin: false,
|
|
89
|
+
} as JSONWebTokenData,
|
|
90
|
+
expiresInSeconds: 300,
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const decoded: JSONWebTokenData = JSONWebToken.decode(token);
|
|
94
|
+
|
|
95
|
+
expect(decoded.sessionId).toBeUndefined();
|
|
96
|
+
expect(decoded.isMasterAdmin).toBe(false);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test("should decode a status page private user token", () => {
|
|
100
|
+
const statusPageId: ObjectID = ObjectID.generate();
|
|
101
|
+
|
|
102
|
+
const token: string = JSONWebToken.signJsonPayload(
|
|
103
|
+
{
|
|
104
|
+
userId: userId.toString(),
|
|
105
|
+
email: email.toString(),
|
|
106
|
+
statusPageId: statusPageId.toString(),
|
|
107
|
+
},
|
|
108
|
+
300,
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
const decoded: JSONWebTokenData = JSONWebToken.decode(token);
|
|
112
|
+
|
|
113
|
+
expect(decoded.statusPageId?.toString()).toEqual(statusPageId.toString());
|
|
114
|
+
// Status page users are never master admins.
|
|
115
|
+
expect(decoded.isMasterAdmin).toBe(false);
|
|
116
|
+
expect(decoded.name?.toString()).toEqual("User");
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test("should throw BadDataException for a malformed token", () => {
|
|
120
|
+
expect(() => {
|
|
121
|
+
return JSONWebToken.decode("not-a-token");
|
|
122
|
+
}).toThrow(BadDataException);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test("should throw BadDataException for an expired token", () => {
|
|
126
|
+
const expiredToken: string = jwt.sign(
|
|
127
|
+
{ userId: userId.toString(), email: email.toString() },
|
|
128
|
+
EncryptionSecret.toString(),
|
|
129
|
+
{ expiresIn: -10 },
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
expect(() => {
|
|
133
|
+
return JSONWebToken.decode(expiredToken);
|
|
134
|
+
}).toThrow(BadDataException);
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
describe("sign", () => {
|
|
139
|
+
test("should wrap a plain string payload under a data claim", () => {
|
|
140
|
+
const token: string = JSONWebToken.sign({
|
|
141
|
+
data: "just-a-string",
|
|
142
|
+
expiresInSeconds: 300,
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
expect(JSONWebToken.decodeJsonPayload(token)["data"]).toEqual(
|
|
146
|
+
"just-a-string",
|
|
147
|
+
);
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
describe("signWithPrivateKey", () => {
|
|
152
|
+
test("should sign with RS256 and be verifiable with the public key", () => {
|
|
153
|
+
const { privateKey, publicKey } = generateKeyPairSync("rsa", {
|
|
154
|
+
modulusLength: 2048,
|
|
155
|
+
publicKeyEncoding: { type: "spki", format: "pem" },
|
|
156
|
+
privateKeyEncoding: { type: "pkcs8", format: "pem" },
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
const token: string = JSONWebToken.signWithPrivateKey(
|
|
160
|
+
{ sub: "oauth-subject" },
|
|
161
|
+
privateKey,
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
const header: JSONObject = JSON.parse(
|
|
165
|
+
Buffer.from(token.split(".")[0]!, "base64").toString("utf8"),
|
|
166
|
+
);
|
|
167
|
+
expect(header["alg"]).toEqual("RS256");
|
|
168
|
+
|
|
169
|
+
const verified: JSONObject = jwt.verify(token, publicKey, {
|
|
170
|
+
algorithms: ["RS256"],
|
|
171
|
+
}) as JSONObject;
|
|
172
|
+
expect(verified["sub"]).toEqual("oauth-subject");
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
});
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import LocalFile from "../../../Server/Utils/LocalFile";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import os from "os";
|
|
4
|
+
import path from "path";
|
|
5
|
+
|
|
6
|
+
/*
|
|
7
|
+
* These run against a real temp directory rather than a mocked `fs`: the
|
|
8
|
+
* behaviour worth pinning down here is what the wrappers do with the
|
|
9
|
+
* filesystem's own answers — ENOENT resolving to false instead of throwing,
|
|
10
|
+
* delete being a no-op on a missing path, directory-vs-file discrimination —
|
|
11
|
+
* and a mock would just re-state the implementation.
|
|
12
|
+
*/
|
|
13
|
+
describe("LocalFile", () => {
|
|
14
|
+
let workDir: string = "";
|
|
15
|
+
|
|
16
|
+
beforeEach(async () => {
|
|
17
|
+
workDir = await fs.promises.mkdtemp(
|
|
18
|
+
path.join(os.tmpdir(), "oneuptime-localfile-test-"),
|
|
19
|
+
);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
afterEach(async () => {
|
|
23
|
+
await fs.promises.rm(workDir, { recursive: true, force: true });
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
describe("sanitizeFilePath", () => {
|
|
27
|
+
test("should collapse double slashes", () => {
|
|
28
|
+
expect(LocalFile.sanitizeFilePath("/a//b//c.txt")).toEqual("/a/b/c.txt");
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test("should leave a clean path untouched", () => {
|
|
32
|
+
expect(LocalFile.sanitizeFilePath("/a/b/c.txt")).toEqual("/a/b/c.txt");
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test("should not touch the scheme separator of a url-like path", () => {
|
|
36
|
+
// Only "//" is collapsed, so "://" becomes ":/" — pinning current behaviour.
|
|
37
|
+
expect(LocalFile.sanitizeFilePath("https://example.com/a")).toEqual(
|
|
38
|
+
"https:/example.com/a",
|
|
39
|
+
);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
describe("getFileExtension", () => {
|
|
44
|
+
test("should return the lowercased extension", () => {
|
|
45
|
+
expect(LocalFile.getFileExtension("/tmp/report.PDF")).toEqual("pdf");
|
|
46
|
+
expect(LocalFile.getFileExtension("archive.tar.gz")).toEqual("gz");
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("should return the whole name when there is no dot", () => {
|
|
50
|
+
// No dot means split() yields one segment, which is the name itself.
|
|
51
|
+
expect(LocalFile.getFileExtension("Makefile")).toEqual("makefile");
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test("should return an empty string for a trailing dot", () => {
|
|
55
|
+
expect(LocalFile.getFileExtension("weird.")).toEqual("");
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
describe("write / read", () => {
|
|
60
|
+
test("should round trip file contents", async () => {
|
|
61
|
+
const filePath: string = path.join(workDir, "note.txt");
|
|
62
|
+
|
|
63
|
+
await LocalFile.write(filePath, "hello world");
|
|
64
|
+
|
|
65
|
+
expect(await LocalFile.read(filePath)).toEqual("hello world");
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test("should overwrite existing contents", async () => {
|
|
69
|
+
const filePath: string = path.join(workDir, "note.txt");
|
|
70
|
+
|
|
71
|
+
await LocalFile.write(filePath, "first");
|
|
72
|
+
await LocalFile.write(filePath, "second");
|
|
73
|
+
|
|
74
|
+
expect(await LocalFile.read(filePath)).toEqual("second");
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test("should read the same bytes back as a buffer", async () => {
|
|
78
|
+
const filePath: string = path.join(workDir, "note.txt");
|
|
79
|
+
|
|
80
|
+
await LocalFile.write(filePath, "buffer me");
|
|
81
|
+
|
|
82
|
+
const buffer: Buffer = await LocalFile.readAsBuffer(filePath);
|
|
83
|
+
|
|
84
|
+
expect(Buffer.isBuffer(buffer)).toBe(true);
|
|
85
|
+
expect(buffer.toString("utf-8")).toEqual("buffer me");
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test("should reject when reading a file that does not exist", async () => {
|
|
89
|
+
await expect(
|
|
90
|
+
LocalFile.read(path.join(workDir, "missing.txt")),
|
|
91
|
+
).rejects.toThrow();
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
describe("doesFileExist / doesDirectoryExist", () => {
|
|
96
|
+
test("should report an existing file as a file and not a directory", async () => {
|
|
97
|
+
const filePath: string = path.join(workDir, "note.txt");
|
|
98
|
+
await LocalFile.write(filePath, "x");
|
|
99
|
+
|
|
100
|
+
expect(await LocalFile.doesFileExist(filePath)).toBe(true);
|
|
101
|
+
expect(await LocalFile.doesDirectoryExist(filePath)).toBe(false);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test("should report an existing directory as a directory and not a file", async () => {
|
|
105
|
+
expect(await LocalFile.doesDirectoryExist(workDir)).toBe(true);
|
|
106
|
+
expect(await LocalFile.doesFileExist(workDir)).toBe(false);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test("should resolve false rather than throwing for a missing path", async () => {
|
|
110
|
+
const missing: string = path.join(workDir, "nope");
|
|
111
|
+
|
|
112
|
+
expect(await LocalFile.doesFileExist(missing)).toBe(false);
|
|
113
|
+
expect(await LocalFile.doesDirectoryExist(missing)).toBe(false);
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
describe("makeDirectory", () => {
|
|
118
|
+
test("should create nested directories", async () => {
|
|
119
|
+
const nested: string = path.join(workDir, "a", "b", "c");
|
|
120
|
+
|
|
121
|
+
await LocalFile.makeDirectory(nested);
|
|
122
|
+
|
|
123
|
+
expect(await LocalFile.doesDirectoryExist(nested)).toBe(true);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
test("should be idempotent", async () => {
|
|
127
|
+
const dir: string = path.join(workDir, "a");
|
|
128
|
+
|
|
129
|
+
await LocalFile.makeDirectory(dir);
|
|
130
|
+
await LocalFile.makeDirectory(dir);
|
|
131
|
+
|
|
132
|
+
expect(await LocalFile.doesDirectoryExist(dir)).toBe(true);
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
describe("deleteFile", () => {
|
|
137
|
+
test("should delete an existing file", async () => {
|
|
138
|
+
const filePath: string = path.join(workDir, "note.txt");
|
|
139
|
+
await LocalFile.write(filePath, "x");
|
|
140
|
+
|
|
141
|
+
await LocalFile.deleteFile(filePath);
|
|
142
|
+
|
|
143
|
+
expect(await LocalFile.doesFileExist(filePath)).toBe(false);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test("should be a no-op for a missing file", async () => {
|
|
147
|
+
await expect(
|
|
148
|
+
LocalFile.deleteFile(path.join(workDir, "missing.txt")),
|
|
149
|
+
).resolves.toBeUndefined();
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
describe("deleteDirectory", () => {
|
|
154
|
+
test("should remove a directory and its contents", async () => {
|
|
155
|
+
const dir: string = path.join(workDir, "a");
|
|
156
|
+
await LocalFile.makeDirectory(dir);
|
|
157
|
+
await LocalFile.write(path.join(dir, "note.txt"), "x");
|
|
158
|
+
|
|
159
|
+
await LocalFile.deleteDirectory(dir);
|
|
160
|
+
|
|
161
|
+
expect(await LocalFile.doesDirectoryExist(dir)).toBe(false);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
test("should be a no-op for a missing directory", async () => {
|
|
165
|
+
await expect(
|
|
166
|
+
LocalFile.deleteDirectory(path.join(workDir, "missing")),
|
|
167
|
+
).resolves.toBeUndefined();
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
describe("deleteAllDataInDirectory", () => {
|
|
172
|
+
test("should empty the directory but keep it in place", async () => {
|
|
173
|
+
const dir: string = path.join(workDir, "a");
|
|
174
|
+
await LocalFile.makeDirectory(path.join(dir, "nested"));
|
|
175
|
+
await LocalFile.write(path.join(dir, "note.txt"), "x");
|
|
176
|
+
|
|
177
|
+
await LocalFile.deleteAllDataInDirectory(dir);
|
|
178
|
+
|
|
179
|
+
expect(await LocalFile.doesDirectoryExist(dir)).toBe(true);
|
|
180
|
+
expect(await LocalFile.readDirectory(dir)).toEqual([]);
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
test("should be a no-op for a missing directory", async () => {
|
|
184
|
+
await expect(
|
|
185
|
+
LocalFile.deleteAllDataInDirectory(path.join(workDir, "missing")),
|
|
186
|
+
).resolves.toBeUndefined();
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
describe("getListOfDirectories", () => {
|
|
191
|
+
test("should return only directories, not files", async () => {
|
|
192
|
+
await LocalFile.makeDirectory(path.join(workDir, "alpha"));
|
|
193
|
+
await LocalFile.makeDirectory(path.join(workDir, "beta"));
|
|
194
|
+
await LocalFile.write(path.join(workDir, "note.txt"), "x");
|
|
195
|
+
|
|
196
|
+
const directories: Array<string> = (
|
|
197
|
+
await LocalFile.getListOfDirectories(workDir)
|
|
198
|
+
).sort();
|
|
199
|
+
|
|
200
|
+
expect(directories).toEqual(["alpha", "beta"]);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
test("should return an empty array for a directory with no subdirectories", async () => {
|
|
204
|
+
await LocalFile.write(path.join(workDir, "note.txt"), "x");
|
|
205
|
+
|
|
206
|
+
expect(await LocalFile.getListOfDirectories(workDir)).toEqual([]);
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
test("should reject for a missing directory", async () => {
|
|
210
|
+
await expect(
|
|
211
|
+
LocalFile.getListOfDirectories(path.join(workDir, "missing")),
|
|
212
|
+
).rejects.toThrow();
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
describe("copyFile", () => {
|
|
217
|
+
test("should copy contents to the destination", async () => {
|
|
218
|
+
const source: string = path.join(workDir, "source.txt");
|
|
219
|
+
const destination: string = path.join(workDir, "destination.txt");
|
|
220
|
+
await LocalFile.write(source, "copy me");
|
|
221
|
+
|
|
222
|
+
await LocalFile.copyFile({ source, destination });
|
|
223
|
+
|
|
224
|
+
expect(await LocalFile.read(destination)).toEqual("copy me");
|
|
225
|
+
// The source must survive a copy.
|
|
226
|
+
expect(await LocalFile.doesFileExist(source)).toBe(true);
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
test("should reject when the source does not exist", async () => {
|
|
230
|
+
await expect(
|
|
231
|
+
LocalFile.copyFile({
|
|
232
|
+
source: path.join(workDir, "missing.txt"),
|
|
233
|
+
destination: path.join(workDir, "destination.txt"),
|
|
234
|
+
}),
|
|
235
|
+
).rejects.toThrow();
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
describe("copyDirectory", () => {
|
|
240
|
+
test("should copy a directory tree recursively", async () => {
|
|
241
|
+
const source: string = path.join(workDir, "source");
|
|
242
|
+
const destination: string = path.join(workDir, "destination");
|
|
243
|
+
|
|
244
|
+
await LocalFile.makeDirectory(path.join(source, "nested"));
|
|
245
|
+
await LocalFile.write(path.join(source, "top.txt"), "top");
|
|
246
|
+
await LocalFile.write(path.join(source, "nested", "deep.txt"), "deep");
|
|
247
|
+
|
|
248
|
+
await LocalFile.copyDirectory({ source, destination });
|
|
249
|
+
|
|
250
|
+
expect(await LocalFile.read(path.join(destination, "top.txt"))).toEqual(
|
|
251
|
+
"top",
|
|
252
|
+
);
|
|
253
|
+
expect(
|
|
254
|
+
await LocalFile.read(path.join(destination, "nested", "deep.txt")),
|
|
255
|
+
).toEqual("deep");
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
});
|