@oneuptime/common 12.0.30 → 12.0.31
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/SecurityEvent.ts +48 -16
- package/Models/AnalyticsModels/ThreatIntelIndicator.ts +10 -5
- package/Models/DatabaseModels/AlertSeverity.ts +44 -0
- package/Models/DatabaseModels/DetectionRule.ts +16 -5
- package/Models/DatabaseModels/GoogleSecOpsConnection.ts +14 -5
- package/Models/DatabaseModels/IncidentSeverity.ts +44 -0
- package/Models/DatabaseModels/Index.ts +2 -0
- package/Models/DatabaseModels/NetworkDevice.ts +113 -3
- package/Models/DatabaseModels/NetworkDeviceAutoImportRule.ts +88 -0
- package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +22 -0
- package/Models/DatabaseModels/NetworkDeviceOidTemplate.ts +499 -0
- package/Models/DatabaseModels/ThreatIntelFeed.ts +16 -5
- package/Server/API/GlobalConfigAPI.ts +362 -183
- package/Server/API/TelemetryAPI.ts +42 -4
- package/Server/EnvironmentConfig.ts +112 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1790500000000-AddNetworkDeviceOidTemplate.ts +59 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1790600000000-AddAutoImportRuleOidTemplate.ts +25 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
- package/Server/Middleware/MultipartFormData.ts +118 -32
- package/Server/Services/AlertEpisodeLabelRuleEngineService.ts +9 -1
- package/Server/Services/AlertEpisodeOnCallRuleEngineService.ts +9 -1
- package/Server/Services/AlertEpisodeOwnerRuleEngineService.ts +9 -1
- package/Server/Services/AlertEpisodePrivacyRuleEngineService.ts +9 -1
- package/Server/Services/AlertGroupingEngineService.ts +9 -1
- package/Server/Services/AlertLabelRuleEngineService.ts +9 -1
- package/Server/Services/AlertOnCallRuleEngineService.ts +9 -1
- package/Server/Services/AlertOwnerRuleEngineService.ts +9 -1
- package/Server/Services/AlertPrivacyRuleEngineService.ts +9 -1
- package/Server/Services/AlertReminderRuleService.ts +9 -1
- package/Server/Services/AutoRemediationRuleEngineService.ts +9 -1
- package/Server/Services/CephClusterLabelRuleEngineService.ts +9 -1
- package/Server/Services/CephClusterOwnerRuleEngineService.ts +9 -1
- package/Server/Services/CloudResourceLabelRuleEngineService.ts +9 -1
- package/Server/Services/CloudResourceOwnerRuleEngineService.ts +9 -1
- package/Server/Services/DashboardLabelRuleEngineService.ts +9 -1
- package/Server/Services/DashboardOwnerRuleEngineService.ts +9 -1
- package/Server/Services/DockerHostLabelRuleEngineService.ts +9 -1
- package/Server/Services/DockerHostOwnerRuleEngineService.ts +9 -1
- package/Server/Services/DockerSwarmClusterLabelRuleEngineService.ts +9 -1
- package/Server/Services/DockerSwarmClusterOwnerRuleEngineService.ts +9 -1
- package/Server/Services/HostLabelRuleEngineService.ts +9 -1
- package/Server/Services/HostOwnerRuleEngineService.ts +9 -1
- package/Server/Services/IncidentEpisodeLabelRuleEngineService.ts +9 -1
- package/Server/Services/IncidentEpisodeOnCallRuleEngineService.ts +9 -1
- package/Server/Services/IncidentEpisodeOwnerRuleEngineService.ts +9 -1
- package/Server/Services/IncidentEpisodePrivacyRuleEngineService.ts +9 -1
- package/Server/Services/IncidentGroupingEngineService.ts +9 -1
- package/Server/Services/IncidentLabelRuleEngineService.ts +9 -1
- package/Server/Services/IncidentOnCallRuleEngineService.ts +9 -1
- package/Server/Services/IncidentOwnerRuleEngineService.ts +9 -1
- package/Server/Services/IncidentPrivacyRuleEngineService.ts +9 -1
- package/Server/Services/IncidentReminderRuleService.ts +9 -1
- package/Server/Services/IncidentSlaRuleService.ts +9 -1
- package/Server/Services/IncomingCallPolicyLabelRuleEngineService.ts +9 -1
- package/Server/Services/IncomingCallPolicyOwnerRuleEngineService.ts +9 -1
- package/Server/Services/Index.ts +2 -0
- package/Server/Services/IoTFleetLabelRuleEngineService.ts +9 -1
- package/Server/Services/IoTFleetOwnerRuleEngineService.ts +9 -1
- package/Server/Services/KubernetesClusterLabelRuleEngineService.ts +9 -1
- package/Server/Services/KubernetesClusterOwnerRuleEngineService.ts +9 -1
- package/Server/Services/KubernetesResourceService.ts +5 -1
- package/Server/Services/MonitorLabelRuleEngineService.ts +9 -1
- package/Server/Services/MonitorOwnerRuleEngineService.ts +9 -1
- package/Server/Services/NetworkDeviceAutoImportRuleEngineService.ts +35 -0
- package/Server/Services/NetworkDeviceAutoImportRuleService.ts +96 -0
- package/Server/Services/NetworkDeviceLabelRuleEngineService.ts +9 -1
- package/Server/Services/NetworkDeviceOidTemplateService.ts +201 -0
- package/Server/Services/NetworkDeviceOwnerRuleEngineService.ts +9 -1
- package/Server/Services/NetworkDeviceService.ts +209 -1
- package/Server/Services/OnCallDutyPolicyLabelRuleEngineService.ts +9 -1
- package/Server/Services/OnCallDutyPolicyOwnerRuleEngineService.ts +9 -1
- package/Server/Services/OnCallDutyPolicyScheduleLabelRuleEngineService.ts +9 -1
- package/Server/Services/OnCallDutyPolicyScheduleOwnerRuleEngineService.ts +9 -1
- package/Server/Services/PodmanHostLabelRuleEngineService.ts +9 -1
- package/Server/Services/PodmanHostOwnerRuleEngineService.ts +9 -1
- package/Server/Services/ProxmoxClusterLabelRuleEngineService.ts +9 -1
- package/Server/Services/ProxmoxClusterOwnerRuleEngineService.ts +9 -1
- package/Server/Services/RumApplicationLabelRuleEngineService.ts +9 -1
- package/Server/Services/RumApplicationOwnerRuleEngineService.ts +9 -1
- package/Server/Services/RunbookLabelRuleEngineService.ts +9 -1
- package/Server/Services/RunbookOwnerRuleEngineService.ts +9 -1
- package/Server/Services/RunbookRuleEngineService.ts +9 -1
- package/Server/Services/ScheduledMaintenanceLabelRuleEngineService.ts +9 -1
- package/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.ts +9 -1
- package/Server/Services/ScheduledMaintenanceReminderRuleService.ts +9 -1
- package/Server/Services/ServerlessFunctionLabelRuleEngineService.ts +9 -1
- package/Server/Services/ServerlessFunctionOwnerRuleEngineService.ts +9 -1
- package/Server/Services/ServiceLabelRuleEngineService.ts +9 -1
- package/Server/Services/ServiceOwnerRuleEngineService.ts +9 -1
- package/Server/Services/StatusPageLabelRuleEngineService.ts +9 -1
- package/Server/Services/StatusPageMonitorRuleEngineService.ts +7 -0
- package/Server/Services/StatusPageOwnerRuleEngineService.ts +9 -1
- package/Server/Services/TelemetrySourceMapService.ts +266 -23
- package/Server/Services/UserService.ts +27 -0
- package/Server/Services/WorkflowLabelRuleEngineService.ts +9 -1
- package/Server/Services/WorkflowOwnerRuleEngineService.ts +9 -1
- package/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.ts +186 -0
- package/Server/Utils/Monitor/CapturedMetricAttributeUtil.ts +245 -0
- package/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.ts +21 -2
- package/Server/Utils/Monitor/MonitorMetricUtil.ts +55 -21
- package/Server/Utils/Monitor/MonitorTemplateUtil.ts +32 -0
- package/Server/Utils/Monitor/NetworkDeviceMetricUtil.ts +15 -2
- package/Server/Utils/Monitor/NetworkDeviceWalkUtil.ts +18 -1
- package/Server/Utils/Monitor/NetworkInventoryUtil.ts +10 -0
- package/Server/Utils/Monitor/SeriesResourceLabels.ts +34 -0
- package/Server/Utils/Rules/RuleEngineRuleRead.ts +48 -0
- package/Server/Utils/Telemetry/ExceptionSanitizer.ts +14 -1
- package/Server/Utils/Telemetry/LogExceptionExtractor.ts +14 -2
- package/Server/Utils/Telemetry/SourceMapResolver.ts +16 -5
- package/Server/Utils/Telemetry/StackTraceParser.ts +399 -0
- package/Tests/App/Dashboard/EventOverlayHook.test.tsx +125 -0
- package/Tests/App/Dashboard/HeaderImageAssets.test.tsx +93 -0
- package/Tests/App/Dashboard/OnCallReadinessSurfaces.test.tsx +3 -3
- package/Tests/App/Dashboard/UserElementEmail.test.tsx +12 -4
- package/Tests/App/Dashboard/UserEmailCallSites.test.tsx +1 -1
- package/Tests/Models/DatabaseModels/DomainRoleTierCoverage.test.ts +14 -0
- package/Tests/Models/DatabaseModels/ModelRegistryInvariants.test.ts +469 -0
- package/Tests/Models/SecurityDomainAccessControl.test.ts +429 -0
- package/Tests/Server/API/GlobalConfigLicense.test.ts +657 -0
- package/Tests/Server/API/SecurityEventAttributesAPI.test.ts +84 -6
- package/Tests/Server/API/TelemetryResolveStackTraceAPI.test.ts +805 -0
- package/Tests/Server/Infrastructure/Postgres/AddOnCallCalendarFeedsMigration.test.ts +32 -7
- package/Tests/Server/Middleware/IdentityRateLimit.test.ts +1144 -0
- package/Tests/Server/Middleware/MultipartFormData.test.ts +618 -3
- package/Tests/Server/Services/MonitorLabelRuleEngineScale.test.ts +520 -0
- package/Tests/Server/Services/NetworkDeviceOidTemplateService.test.ts +332 -0
- package/Tests/Server/Services/NetworkDeviceOidTemplateWriteGuards.test.ts +409 -0
- package/Tests/Server/Services/RuleEngineRuleFetchLimit.test.ts +239 -0
- package/Tests/Server/Services/TelemetrySourceMapService.test.ts +1210 -2
- package/Tests/Server/Services/UserServiceSeatLimit.test.ts +182 -0
- package/Tests/Server/Types/AnalyticsDatabase/SecurityEventModelPermission.test.ts +255 -0
- package/Tests/Server/Types/Database/Permissions/ReadBlockPermission.test.ts +212 -0
- package/Tests/Server/Types/Database/Permissions/SecurityRoleAccess.test.ts +413 -0
- package/Tests/Server/Utils/CodeRepository.test.ts +689 -0
- package/Tests/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.test.ts +495 -0
- package/Tests/Server/Utils/ExceptionSanitizer.test.ts +77 -0
- package/Tests/Server/Utils/Monitor/CapturedMetricAttributeUtil.test.ts +284 -0
- package/Tests/Server/Utils/Monitor/MonitorCustomMetricAttributes.test.ts +503 -0
- package/Tests/Server/Utils/Monitor/MonitorTemplatePrototypePollution.test.ts +106 -0
- package/Tests/Server/Utils/Monitor/NetworkDeviceWalkLogWritePath.test.ts +33 -4
- package/Tests/Server/Utils/Monitor/NetworkDeviceWalkUtil.test.ts +14 -4
- package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +44 -0
- package/Tests/Server/Utils/OpenAPISpec.test.ts +536 -0
- package/Tests/Server/Utils/Rules/RuleEngineRuleRead.test.ts +115 -0
- package/Tests/Server/Utils/StackTraceParser.test.ts +610 -0
- package/Tests/Server/Utils/Telemetry/LogExceptionExtractor.test.ts +0 -0
- package/Tests/Server/Utils/Telemetry/SourceMapLimits.test.ts +656 -0
- package/Tests/Server/Utils/Telemetry/SourceMapResolver.test.ts +100 -0
- package/Tests/Types/Monitor/SnmpMonitor/SnmpOidListUtil.test.ts +454 -0
- package/Tests/Types/SecurityRolePermissions.test.ts +193 -0
- package/Tests/UI/Components/Charts/AnnotationLayout.test.ts +773 -0
- package/Tests/UI/Components/Charts/ChartAnnotationRail.test.tsx +789 -0
- package/Tests/UI/Components/Charts/ChartBucketIdentity.test.ts +254 -0
- package/Tests/UI/Components/Charts/TimeAnnotation.test.ts +471 -0
- package/Tests/UI/Components/EditionLabelLicenseRefresh.test.tsx +405 -0
- package/Tests/UI/Components/ErrorMessageRefreshControl.test.tsx +83 -0
- package/Tests/UI/Components/MarkdownConverters.test.ts +686 -0
- package/Tests/UI/Components/ModelTable/BaseModelTableDeleteAndEmptyStates.test.tsx +341 -0
- package/Tests/UI/Components/OrderedStatesList.test.tsx +5 -5
- package/Tests/UI/Components/PendingProjectInvitations.test.tsx +1 -1
- package/Tests/UI/Components/TableSortAndMobileColumns.test.tsx +195 -0
- package/Tests/UI/Components/XAxis.test.ts +270 -5
- package/Tests/UI/Components/XAxisDaylightSaving.test.ts +113 -0
- package/Tests/UI/Styles/ChartFocusRing.test.ts +153 -0
- package/Tests/UI/Styles/ChartFocusRingCoverage.test.tsx +377 -0
- package/Tests/UI/Styles/ThemeStylesheet.ts +162 -0
- package/Tests/Utils/EnterpriseLicenseSeats.test.ts +507 -0
- package/Tests/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.test.ts +951 -1
- package/Tests/Utils/NetworkDiscovery/DiscoveredHostUtil.test.ts +238 -0
- package/Tests/Utils/NetworkDiscovery/DiscoveryReverseDnsChain.test.ts +1056 -0
- package/Tests/Utils/NetworkDiscovery/ReverseDnsNameUtil.test.ts +882 -0
- package/Types/Date.ts +39 -0
- package/Types/Monitor/SnmpMonitor/SnmpOidListUtil.ts +333 -0
- package/Types/Permission.ts +96 -0
- package/Types/Rum/SessionReplay.ts +21 -0
- package/Types/Telemetry/SourceMap.ts +8 -0
- package/UI/Components/Charts/ChartLibrary/Annotations/AnnotationHoverCard.tsx +176 -0
- package/UI/Components/Charts/ChartLibrary/Annotations/AnnotationLayout.ts +745 -0
- package/UI/Components/Charts/ChartLibrary/Annotations/ChartAnnotationLayer.tsx +576 -0
- package/UI/Components/Charts/ChartLibrary/Annotations/UseChartAnnotations.tsx +204 -0
- package/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.tsx +491 -544
- package/UI/Components/Charts/ChartLibrary/BarChart/BarChart.tsx +324 -372
- package/UI/Components/Charts/ChartLibrary/LineChart/LineChart.tsx +487 -540
- package/UI/Components/Charts/ChartLibrary/Types/FormattedReferenceRegion.ts +7 -3
- package/UI/Components/Charts/ChartLibrary/Types/FormattedTimeReferenceLine.ts +14 -3
- package/UI/Components/Charts/Types/ChartEventKind.ts +13 -0
- package/UI/Components/Charts/Types/ReferenceRegionProps.ts +6 -0
- package/UI/Components/Charts/Types/TimeReferenceLineProps.ts +20 -3
- package/UI/Components/Charts/Utils/TimeAnnotation.ts +69 -35
- package/UI/Components/Charts/Utils/XAxis.ts +125 -18
- package/UI/Components/EditionLabel/EditionLabel.tsx +280 -26
- package/UI/Components/ErrorMessage/ErrorMessage.tsx +21 -10
- package/UI/Components/Feed/FeedItem.tsx +4 -5
- package/UI/Components/Header/HeaderIconDropdownButton.tsx +1 -2
- package/UI/Components/Header/UserProfile/UserProfile.tsx +1 -2
- package/UI/Components/Image/Image.tsx +20 -3
- package/UI/Components/Markdown.tsx/MarkdownConverters.ts +0 -0
- package/UI/Components/MemberRoleAssignment/MemberRoleAssignment.tsx +1 -2
- package/UI/Components/ModelTable/BaseModelTable.tsx +150 -24
- package/UI/Components/Table/TableHeader.tsx +64 -48
- package/UI/Components/Table/TableRow.tsx +13 -3
- package/UI/Styles/Theme.css +38 -0
- package/Utils/EnterpriseLicense/EnterpriseLicenseSeats.ts +271 -0
- package/Utils/NetworkDiscovery/AutoImportRuleMatcher.ts +6 -0
- package/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.ts +141 -10
- package/Utils/NetworkDiscovery/DiscoveredHostUtil.ts +55 -3
- package/Utils/NetworkDiscovery/ReverseDnsNameUtil.ts +151 -0
- package/Utils/Rules/RuleEngineLimits.ts +32 -0
- package/build/dist/Models/AnalyticsModels/SecurityEvent.js +48 -16
- package/build/dist/Models/AnalyticsModels/SecurityEvent.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/ThreatIntelIndicator.js +10 -5
- package/build/dist/Models/AnalyticsModels/ThreatIntelIndicator.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AlertSeverity.js +46 -1
- package/build/dist/Models/DatabaseModels/AlertSeverity.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DetectionRule.js +16 -5
- package/build/dist/Models/DatabaseModels/DetectionRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/GoogleSecOpsConnection.js +14 -5
- package/build/dist/Models/DatabaseModels/GoogleSecOpsConnection.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentSeverity.js +46 -1
- package/build/dist/Models/DatabaseModels/IncidentSeverity.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +2 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDevice.js +115 -3
- package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceAutoImportRule.js +88 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceAutoImportRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceOidTemplate.js +519 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceOidTemplate.js.map +1 -0
- package/build/dist/Models/DatabaseModels/ThreatIntelFeed.js +16 -5
- package/build/dist/Models/DatabaseModels/ThreatIntelFeed.js.map +1 -1
- package/build/dist/Server/API/GlobalConfigAPI.js +293 -176
- package/build/dist/Server/API/GlobalConfigAPI.js.map +1 -1
- package/build/dist/Server/API/TelemetryAPI.js +31 -3
- package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +83 -0
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790500000000-AddNetworkDeviceOidTemplate.js +26 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790500000000-AddNetworkDeviceOidTemplate.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790600000000-AddAutoImportRuleOidTemplate.js +14 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790600000000-AddAutoImportRuleOidTemplate.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +4 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Middleware/MultipartFormData.js +93 -28
- package/build/dist/Server/Middleware/MultipartFormData.js.map +1 -1
- package/build/dist/Server/Services/AlertEpisodeLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AlertEpisodeLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertEpisodeOnCallRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AlertEpisodeOnCallRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertEpisodeOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AlertEpisodeOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertEpisodePrivacyRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AlertEpisodePrivacyRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertGroupingEngineService.js +8 -1
- package/build/dist/Server/Services/AlertGroupingEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AlertLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertOnCallRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AlertOnCallRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AlertOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertPrivacyRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AlertPrivacyRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertReminderRuleService.js +8 -1
- package/build/dist/Server/Services/AlertReminderRuleService.js.map +1 -1
- package/build/dist/Server/Services/AutoRemediationRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AutoRemediationRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/CephClusterLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/CephClusterLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/CephClusterOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/CephClusterOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/CloudResourceLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/CloudResourceLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/CloudResourceOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/CloudResourceOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/DashboardLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/DashboardLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/DashboardOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/DashboardOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/DockerHostLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/DockerHostLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/DockerHostOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/DockerHostOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/DockerSwarmClusterLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/DockerSwarmClusterLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/DockerSwarmClusterOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/DockerSwarmClusterOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/HostLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/HostLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/HostOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/HostOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentEpisodeLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeOnCallRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentEpisodeOnCallRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentEpisodeOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodePrivacyRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentEpisodePrivacyRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentGroupingEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentGroupingEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentOnCallRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentOnCallRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentPrivacyRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentPrivacyRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentReminderRuleService.js +8 -1
- package/build/dist/Server/Services/IncidentReminderRuleService.js.map +1 -1
- package/build/dist/Server/Services/IncidentSlaRuleService.js +8 -1
- package/build/dist/Server/Services/IncidentSlaRuleService.js.map +1 -1
- package/build/dist/Server/Services/IncomingCallPolicyLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncomingCallPolicyLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncomingCallPolicyOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncomingCallPolicyOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +2 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/IoTFleetLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IoTFleetLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IoTFleetOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IoTFleetOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/KubernetesClusterLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/KubernetesClusterLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/KubernetesClusterOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/KubernetesClusterOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/KubernetesResourceService.js +5 -1
- package/build/dist/Server/Services/KubernetesResourceService.js.map +1 -1
- package/build/dist/Server/Services/MonitorLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/MonitorLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/MonitorOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/MonitorOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js +30 -21
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js +64 -0
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceOidTemplateService.js +180 -0
- package/build/dist/Server/Services/NetworkDeviceOidTemplateService.js.map +1 -0
- package/build/dist/Server/Services/NetworkDeviceOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/NetworkDeviceOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceService.js +154 -1
- package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/OnCallDutyPolicyLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/OnCallDutyPolicyOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/PodmanHostLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/PodmanHostLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/PodmanHostOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/PodmanHostOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ProxmoxClusterLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/ProxmoxClusterLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ProxmoxClusterOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/ProxmoxClusterOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/RumApplicationLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/RumApplicationLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/RumApplicationOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/RumApplicationOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/RunbookLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/RunbookLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/RunbookOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/RunbookOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/RunbookRuleEngineService.js +8 -1
- package/build/dist/Server/Services/RunbookRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/ScheduledMaintenanceLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceReminderRuleService.js +8 -1
- package/build/dist/Server/Services/ScheduledMaintenanceReminderRuleService.js.map +1 -1
- package/build/dist/Server/Services/ServerlessFunctionLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/ServerlessFunctionLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ServerlessFunctionOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/ServerlessFunctionOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ServiceLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/ServiceLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ServiceOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/ServiceOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/StatusPageLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js +6 -0
- package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/StatusPageOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/TelemetrySourceMapService.js +213 -19
- package/build/dist/Server/Services/TelemetrySourceMapService.js.map +1 -1
- package/build/dist/Server/Services/UserService.js +25 -0
- package/build/dist/Server/Services/UserService.js.map +1 -1
- package/build/dist/Server/Services/WorkflowLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/WorkflowLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/WorkflowOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/WorkflowOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js +145 -0
- package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/CapturedMetricAttributeUtil.js +201 -0
- package/build/dist/Server/Utils/Monitor/CapturedMetricAttributeUtil.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js +19 -2
- package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +42 -23
- package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +29 -0
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js +11 -2
- package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js +16 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +10 -0
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +33 -0
- package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js.map +1 -1
- package/build/dist/Server/Utils/Rules/RuleEngineRuleRead.js +37 -0
- package/build/dist/Server/Utils/Rules/RuleEngineRuleRead.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/ExceptionSanitizer.js +12 -1
- package/build/dist/Server/Utils/Telemetry/ExceptionSanitizer.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/LogExceptionExtractor.js +14 -2
- package/build/dist/Server/Utils/Telemetry/LogExceptionExtractor.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/SourceMapResolver.js +15 -5
- package/build/dist/Server/Utils/Telemetry/SourceMapResolver.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/StackTraceParser.js +307 -0
- package/build/dist/Server/Utils/Telemetry/StackTraceParser.js.map +1 -1
- package/build/dist/Types/Date.js +27 -0
- package/build/dist/Types/Date.js.map +1 -1
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpOidListUtil.js +253 -0
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpOidListUtil.js.map +1 -0
- package/build/dist/Types/Permission.js +86 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Rum/SessionReplay.js +19 -0
- package/build/dist/Types/Rum/SessionReplay.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/AnnotationHoverCard.js +83 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/AnnotationHoverCard.js.map +1 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/AnnotationLayout.js +531 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/AnnotationLayout.js.map +1 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/ChartAnnotationLayer.js +264 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/ChartAnnotationLayer.js.map +1 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/UseChartAnnotations.js +122 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/UseChartAnnotations.js.map +1 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js +213 -233
- package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js +139 -152
- package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js +212 -232
- package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/Types/ChartEventKind.js +14 -0
- package/build/dist/UI/Components/Charts/Types/ChartEventKind.js.map +1 -0
- package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js +57 -28
- package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js.map +1 -1
- package/build/dist/UI/Components/Charts/Utils/XAxis.js +103 -17
- package/build/dist/UI/Components/Charts/Utils/XAxis.js.map +1 -1
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js +198 -23
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
- package/build/dist/UI/Components/ErrorMessage/ErrorMessage.js +15 -5
- package/build/dist/UI/Components/ErrorMessage/ErrorMessage.js.map +1 -1
- package/build/dist/UI/Components/Feed/FeedItem.js +4 -5
- package/build/dist/UI/Components/Feed/FeedItem.js.map +1 -1
- package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js +1 -2
- package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js.map +1 -1
- package/build/dist/UI/Components/Header/UserProfile/UserProfile.js.map +1 -1
- package/build/dist/UI/Components/Image/Image.js +6 -1
- package/build/dist/UI/Components/Image/Image.js.map +1 -1
- package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js +0 -0
- package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js.map +1 -1
- package/build/dist/UI/Components/MemberRoleAssignment/MemberRoleAssignment.js +1 -2
- package/build/dist/UI/Components/MemberRoleAssignment/MemberRoleAssignment.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +104 -23
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/Table/TableHeader.js +20 -22
- package/build/dist/UI/Components/Table/TableHeader.js.map +1 -1
- package/build/dist/UI/Components/Table/TableRow.js +13 -4
- package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js +153 -0
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/AutoImportRuleMatcher.js.map +1 -1
- package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js +127 -7
- package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js.map +1 -1
- package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js +50 -3
- package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js.map +1 -1
- package/build/dist/Utils/NetworkDiscovery/ReverseDnsNameUtil.js +132 -0
- package/build/dist/Utils/NetworkDiscovery/ReverseDnsNameUtil.js.map +1 -0
- package/build/dist/Utils/Rules/RuleEngineLimits.js +31 -0
- package/build/dist/Utils/Rules/RuleEngineLimits.js.map +1 -0
- package/jest.config.json +1 -0
- package/package.json +2 -2
|
@@ -43,15 +43,21 @@ jest.setTimeout(180_000);
|
|
|
43
43
|
*/
|
|
44
44
|
|
|
45
45
|
import MultipartFormDataMiddleware, {
|
|
46
|
+
getMultipartFormDataMiddleware,
|
|
46
47
|
MAX_MULTIPART_FIELDS,
|
|
47
48
|
MAX_MULTIPART_FIELD_BYTES,
|
|
48
49
|
MAX_MULTIPART_FILES,
|
|
49
50
|
MAX_MULTIPART_FILE_BYTES,
|
|
50
51
|
} from "../../../Server/Middleware/MultipartFormData";
|
|
52
|
+
import {
|
|
53
|
+
SourceMapMaxFilesPerRequest,
|
|
54
|
+
SourceMapMaxFileSizeInBytes,
|
|
55
|
+
} from "../../../Server/EnvironmentConfig";
|
|
51
56
|
import {
|
|
52
57
|
ExpressRequest,
|
|
53
58
|
ExpressResponse,
|
|
54
59
|
NextFunction,
|
|
60
|
+
RequestHandler,
|
|
55
61
|
} from "../../../Server/Utils/Express";
|
|
56
62
|
import Exception from "../../../Types/Exception/Exception";
|
|
57
63
|
import ExceptionCode from "../../../Types/Exception/ExceptionCode";
|
|
@@ -95,11 +101,33 @@ interface Outcome {
|
|
|
95
101
|
nextCalls: number;
|
|
96
102
|
}
|
|
97
103
|
|
|
104
|
+
interface RunOptions {
|
|
105
|
+
/*
|
|
106
|
+
* Which handler to drive. Defaults to the shared export, so every call
|
|
107
|
+
* written before getMultipartFormDataMiddleware existed still reads as
|
|
108
|
+
* "the middleware".
|
|
109
|
+
*/
|
|
110
|
+
middleware?: RequestHandler;
|
|
111
|
+
/*
|
|
112
|
+
* Override the Content-Type header, for the one case that needs a
|
|
113
|
+
* multipart request busboy cannot parse at all.
|
|
114
|
+
*/
|
|
115
|
+
contentType?: string;
|
|
116
|
+
}
|
|
117
|
+
|
|
98
118
|
/*
|
|
99
119
|
* Drive the middleware with a real multipart body over a real Readable, so
|
|
100
120
|
* busboy does the parsing it does in production rather than being faked.
|
|
101
121
|
*/
|
|
102
|
-
function run(
|
|
122
|
+
function run(
|
|
123
|
+
parts: Array<MultipartPart>,
|
|
124
|
+
options?: RunOptions,
|
|
125
|
+
): Promise<Outcome> {
|
|
126
|
+
const middleware: RequestHandler =
|
|
127
|
+
options && options.middleware
|
|
128
|
+
? options.middleware
|
|
129
|
+
: MultipartFormDataMiddleware;
|
|
130
|
+
|
|
103
131
|
const body: Buffer = buildMultipartBody(parts);
|
|
104
132
|
|
|
105
133
|
const req: Readable & {
|
|
@@ -109,7 +137,10 @@ function run(parts: Array<MultipartPart>): Promise<Outcome> {
|
|
|
109
137
|
} = Readable.from([body]) as never;
|
|
110
138
|
|
|
111
139
|
req.headers = {
|
|
112
|
-
"content-type":
|
|
140
|
+
"content-type":
|
|
141
|
+
options && options.contentType
|
|
142
|
+
? options.contentType
|
|
143
|
+
: `multipart/form-data; boundary=${BOUNDARY}`,
|
|
113
144
|
"content-length": String(body.length),
|
|
114
145
|
};
|
|
115
146
|
|
|
@@ -123,7 +154,7 @@ function run(parts: Array<MultipartPart>): Promise<Outcome> {
|
|
|
123
154
|
return new Promise<Outcome>((resolve: (value: Outcome) => void): void => {
|
|
124
155
|
let nextCalls: number = 0;
|
|
125
156
|
|
|
126
|
-
|
|
157
|
+
middleware(req as unknown as ExpressRequest, res, ((
|
|
127
158
|
err?: unknown,
|
|
128
159
|
): void => {
|
|
129
160
|
nextCalls++;
|
|
@@ -136,6 +167,23 @@ function run(parts: Array<MultipartPart>): Promise<Outcome> {
|
|
|
136
167
|
});
|
|
137
168
|
}
|
|
138
169
|
|
|
170
|
+
/*
|
|
171
|
+
* `count` one-byte files. The count limits are what these fixtures probe, so
|
|
172
|
+
* the payload per file is deliberately trivial.
|
|
173
|
+
*/
|
|
174
|
+
function tinyFiles(count: number): Array<MultipartPart> {
|
|
175
|
+
return Array.from(
|
|
176
|
+
{ length: count },
|
|
177
|
+
(_v: unknown, i: number): MultipartPart => {
|
|
178
|
+
return {
|
|
179
|
+
name: `f${i}`,
|
|
180
|
+
value: Buffer.from("x"),
|
|
181
|
+
filename: `f${i}.bin`,
|
|
182
|
+
};
|
|
183
|
+
},
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
139
187
|
function files(outcome: Outcome): Array<{ fieldname: string; buffer: Buffer }> {
|
|
140
188
|
return (outcome.req.files || []) as Array<{
|
|
141
189
|
fieldname: string;
|
|
@@ -155,6 +203,24 @@ describe("MultipartFormData - the limits are set where they were reasoned about"
|
|
|
155
203
|
expect(Number.isFinite(MAX_MULTIPART_FILES)).toBe(true);
|
|
156
204
|
expect(Number.isFinite(MAX_MULTIPART_FIELDS)).toBe(true);
|
|
157
205
|
});
|
|
206
|
+
|
|
207
|
+
test("the source map env knobs cannot be configured past these two ceilings", () => {
|
|
208
|
+
/*
|
|
209
|
+
* Common/Server/EnvironmentConfig.ts clamps SOURCE_MAP_MAX_FILES_PER_REQUEST
|
|
210
|
+
* to 50 and SOURCE_MAP_MAX_FILE_SIZE_BYTES to 50 MiB, and repeats both as
|
|
211
|
+
* literals rather than importing them - config has no business pulling in
|
|
212
|
+
* multer and express. That copy is the thing this pins: if either constant
|
|
213
|
+
* here moves DOWN, the config default silently becomes unenforceable and
|
|
214
|
+
* multer starts aborting requests the config layer thought it had accepted
|
|
215
|
+
* (a 413 where the operator was promised a 400).
|
|
216
|
+
*/
|
|
217
|
+
expect(SourceMapMaxFilesPerRequest).toBeLessThanOrEqual(
|
|
218
|
+
MAX_MULTIPART_FILES,
|
|
219
|
+
);
|
|
220
|
+
expect(SourceMapMaxFileSizeInBytes).toBeLessThanOrEqual(
|
|
221
|
+
MAX_MULTIPART_FILE_BYTES,
|
|
222
|
+
);
|
|
223
|
+
});
|
|
158
224
|
});
|
|
159
225
|
|
|
160
226
|
describe("MultipartFormData - normal bodies still parse", () => {
|
|
@@ -296,3 +362,552 @@ describe("MultipartFormData - breaches answer 413, not 500", () => {
|
|
|
296
362
|
expect(outcome.nextCalls).toBe(1);
|
|
297
363
|
});
|
|
298
364
|
});
|
|
365
|
+
|
|
366
|
+
/*
|
|
367
|
+
* getMultipartFormDataMiddleware exists so the source map upload route can
|
|
368
|
+
* hold itself to SOURCE_MAP_MAX_FILES_PER_REQUEST files instead of the shared
|
|
369
|
+
* 50. Two properties matter more than the count itself:
|
|
370
|
+
*
|
|
371
|
+
* - it is DOWNWARD only. Every route mounting this parses before its own
|
|
372
|
+
* auth check, so MAX_MULTIPART_FILES is the ceiling an unauthenticated
|
|
373
|
+
* caller is held to across all of them. A knob that could raise it would
|
|
374
|
+
* widen the pre-auth memory surface of routes that never asked for it.
|
|
375
|
+
* - narrowing is per route. It builds a SECOND multer instance rather than
|
|
376
|
+
* reconfiguring the shared one, so a tighter source map route must not
|
|
377
|
+
* make Pyroscope ingest or inbound email tighter by proxy.
|
|
378
|
+
*/
|
|
379
|
+
describe("getMultipartFormDataMiddleware - nothing to narrow means the shared instance", () => {
|
|
380
|
+
test("asking for exactly the shared ceiling hands back the default export itself", () => {
|
|
381
|
+
/*
|
|
382
|
+
* Identity, not equivalence: a fresh middleware here would be a second
|
|
383
|
+
* multer with a second memoryStorage for no behavioural difference, and
|
|
384
|
+
* this function is documented as build-once-at-module-scope precisely
|
|
385
|
+
* because instances are not free.
|
|
386
|
+
*/
|
|
387
|
+
expect(
|
|
388
|
+
getMultipartFormDataMiddleware({ maxFiles: MAX_MULTIPART_FILES }),
|
|
389
|
+
).toBe(MultipartFormDataMiddleware);
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
test("one file above the ceiling is clamped back onto the default export", () => {
|
|
393
|
+
expect(
|
|
394
|
+
getMultipartFormDataMiddleware({ maxFiles: MAX_MULTIPART_FILES + 1 }),
|
|
395
|
+
).toBe(MultipartFormDataMiddleware);
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
test("absurd, unbounded and fractional requests above the ceiling all clamp onto the default export", () => {
|
|
399
|
+
/*
|
|
400
|
+
* The clamp is what turns a misconfigured SOURCE_MAP_MAX_FILES_PER_REQUEST
|
|
401
|
+
* into a no-op instead of a widened pre-auth surface, so every shape an
|
|
402
|
+
* operator could plausibly produce has to land on the shared instance.
|
|
403
|
+
*
|
|
404
|
+
* Written against MAX_MULTIPART_FILES rather than the number it happens
|
|
405
|
+
* to hold, so raising the shared ceiling does not quietly turn these into
|
|
406
|
+
* assertions about a value that is no longer above it.
|
|
407
|
+
*/
|
|
408
|
+
for (const attempted of [
|
|
409
|
+
MAX_MULTIPART_FILES + 1,
|
|
410
|
+
MAX_MULTIPART_FILES + 0.5,
|
|
411
|
+
MAX_MULTIPART_FILES * 2,
|
|
412
|
+
1000,
|
|
413
|
+
Number.MAX_SAFE_INTEGER,
|
|
414
|
+
Number.POSITIVE_INFINITY,
|
|
415
|
+
]) {
|
|
416
|
+
expect(getMultipartFormDataMiddleware({ maxFiles: attempted })).toBe(
|
|
417
|
+
MultipartFormDataMiddleware,
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
test("no attempted value yields a middleware that accepts more than MAX_MULTIPART_FILES files", async () => {
|
|
423
|
+
/*
|
|
424
|
+
* The identity checks above prove the fast path was taken; this proves
|
|
425
|
+
* the property those checks are a proxy for. If the clamp were ever
|
|
426
|
+
* dropped, an instance built for 1000 files would happily buffer 51 of
|
|
427
|
+
* them before auth - so drive the returned handler with one file more
|
|
428
|
+
* than the shared ceiling and require the 413 either way.
|
|
429
|
+
*/
|
|
430
|
+
for (const attempted of [
|
|
431
|
+
MAX_MULTIPART_FILES + 1,
|
|
432
|
+
MAX_MULTIPART_FILES * 2,
|
|
433
|
+
MAX_MULTIPART_FILES * 10,
|
|
434
|
+
Number.MAX_SAFE_INTEGER,
|
|
435
|
+
Number.POSITIVE_INFINITY,
|
|
436
|
+
]) {
|
|
437
|
+
const middleware: RequestHandler = getMultipartFormDataMiddleware({
|
|
438
|
+
maxFiles: attempted,
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
const outcome: Outcome = await run(tinyFiles(MAX_MULTIPART_FILES + 1), {
|
|
442
|
+
middleware: middleware,
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
expect((outcome.error as Exception).code).toBe(
|
|
446
|
+
ExceptionCode.PayloadTooLargeException,
|
|
447
|
+
);
|
|
448
|
+
expect((outcome.error as Exception).message).toContain(
|
|
449
|
+
"LIMIT_FILE_COUNT",
|
|
450
|
+
);
|
|
451
|
+
}
|
|
452
|
+
});
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
describe("getMultipartFormDataMiddleware - a narrowed instance is narrower, and only for itself", () => {
|
|
456
|
+
const narrow: RequestHandler = getMultipartFormDataMiddleware({
|
|
457
|
+
maxFiles: 2,
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
test("a genuinely narrower request builds its own handler, not the shared one", () => {
|
|
461
|
+
expect(narrow).not.toBe(MultipartFormDataMiddleware);
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
test("exactly its own file limit is accepted", async () => {
|
|
465
|
+
const outcome: Outcome = await run(tinyFiles(2), { middleware: narrow });
|
|
466
|
+
|
|
467
|
+
expect(outcome.error).toBeUndefined();
|
|
468
|
+
expect(files(outcome)).toHaveLength(2);
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
test("one file under its limit is accepted", async () => {
|
|
472
|
+
const outcome: Outcome = await run(tinyFiles(1), { middleware: narrow });
|
|
473
|
+
|
|
474
|
+
expect(outcome.error).toBeUndefined();
|
|
475
|
+
expect(files(outcome)).toHaveLength(1);
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
test("one file over its limit answers 413, not the shared 50-file limit", async () => {
|
|
479
|
+
const outcome: Outcome = await run(tinyFiles(3), { middleware: narrow });
|
|
480
|
+
|
|
481
|
+
expect(outcome.error).toBeInstanceOf(Exception);
|
|
482
|
+
expect((outcome.error as Exception).code).toBe(
|
|
483
|
+
ExceptionCode.PayloadTooLargeException,
|
|
484
|
+
);
|
|
485
|
+
expect((outcome.error as Exception).code).toBe(413);
|
|
486
|
+
expect((outcome.error as Exception).message).toContain("LIMIT_FILE_COUNT");
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
test("the very same three files still pass the default middleware", async () => {
|
|
490
|
+
/*
|
|
491
|
+
* The regression this guards: narrowing one route by mutating the shared
|
|
492
|
+
* multer's limits would look identical in the test above and quietly cut
|
|
493
|
+
* Pyroscope ingest and SendGrid inbound email down to two files each.
|
|
494
|
+
*/
|
|
495
|
+
const outcome: Outcome = await run(tinyFiles(3));
|
|
496
|
+
|
|
497
|
+
expect(outcome.error).toBeUndefined();
|
|
498
|
+
expect(files(outcome)).toHaveLength(3);
|
|
499
|
+
});
|
|
500
|
+
|
|
501
|
+
test("the default middleware still accepts a full 50 files after a narrower one exists", async () => {
|
|
502
|
+
const outcome: Outcome = await run(tinyFiles(MAX_MULTIPART_FILES));
|
|
503
|
+
|
|
504
|
+
expect(outcome.error).toBeUndefined();
|
|
505
|
+
expect(files(outcome)).toHaveLength(MAX_MULTIPART_FILES);
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
test("the narrowed instance stays narrow after the default has been used", async () => {
|
|
509
|
+
/*
|
|
510
|
+
* The mirror image of the leak: two multer instances sharing mutable
|
|
511
|
+
* limits would drift in whichever direction ran last, so re-drive the
|
|
512
|
+
* narrow one after the 50-file body above.
|
|
513
|
+
*/
|
|
514
|
+
const outcome: Outcome = await run(tinyFiles(3), { middleware: narrow });
|
|
515
|
+
|
|
516
|
+
expect((outcome.error as Exception).message).toContain("LIMIT_FILE_COUNT");
|
|
517
|
+
});
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
describe("getMultipartFormDataMiddleware - the low end clamps up to 1, never to zero", () => {
|
|
521
|
+
test("maxFiles: 0 still accepts a file", async () => {
|
|
522
|
+
/*
|
|
523
|
+
* multer reads `files: 0` as "no files at all", which would turn a
|
|
524
|
+
* misconfigured SOURCE_MAP_MAX_FILES_PER_REQUEST into a route that 413s
|
|
525
|
+
* every upload. Clamping up to 1 keeps the route working, degraded, and
|
|
526
|
+
* the parse still bounded.
|
|
527
|
+
*/
|
|
528
|
+
const middleware: RequestHandler = getMultipartFormDataMiddleware({
|
|
529
|
+
maxFiles: 0,
|
|
530
|
+
});
|
|
531
|
+
|
|
532
|
+
const outcome: Outcome = await run(tinyFiles(1), {
|
|
533
|
+
middleware: middleware,
|
|
534
|
+
});
|
|
535
|
+
|
|
536
|
+
expect(outcome.error).toBeUndefined();
|
|
537
|
+
expect(files(outcome)).toHaveLength(1);
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
test("maxFiles: 0 rejects the second file, so it clamped to 1 rather than to the default", async () => {
|
|
541
|
+
const middleware: RequestHandler = getMultipartFormDataMiddleware({
|
|
542
|
+
maxFiles: 0,
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
const outcome: Outcome = await run(tinyFiles(2), {
|
|
546
|
+
middleware: middleware,
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
expect((outcome.error as Exception).code).toBe(
|
|
550
|
+
ExceptionCode.PayloadTooLargeException,
|
|
551
|
+
);
|
|
552
|
+
expect((outcome.error as Exception).message).toContain("LIMIT_FILE_COUNT");
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
test("a negative maxFiles behaves exactly like 1", async () => {
|
|
556
|
+
const middleware: RequestHandler = getMultipartFormDataMiddleware({
|
|
557
|
+
maxFiles: -5,
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
const accepted: Outcome = await run(tinyFiles(1), {
|
|
561
|
+
middleware: middleware,
|
|
562
|
+
});
|
|
563
|
+
const rejected: Outcome = await run(tinyFiles(2), {
|
|
564
|
+
middleware: middleware,
|
|
565
|
+
});
|
|
566
|
+
|
|
567
|
+
expect(accepted.error).toBeUndefined();
|
|
568
|
+
expect(files(accepted)).toHaveLength(1);
|
|
569
|
+
expect((rejected.error as Exception).code).toBe(
|
|
570
|
+
ExceptionCode.PayloadTooLargeException,
|
|
571
|
+
);
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
test("clamped-up values are still their own handler, not the shared one", () => {
|
|
575
|
+
expect(getMultipartFormDataMiddleware({ maxFiles: 0 })).not.toBe(
|
|
576
|
+
MultipartFormDataMiddleware,
|
|
577
|
+
);
|
|
578
|
+
expect(getMultipartFormDataMiddleware({ maxFiles: -5 })).not.toBe(
|
|
579
|
+
MultipartFormDataMiddleware,
|
|
580
|
+
);
|
|
581
|
+
});
|
|
582
|
+
});
|
|
583
|
+
|
|
584
|
+
/*
|
|
585
|
+
* The DOMAIN is clamped, not only the range.
|
|
586
|
+
*
|
|
587
|
+
* busboy's file-count check is `files === filesLimit` - an equality against a
|
|
588
|
+
* counter that only ever holds whole numbers. A fractional or NaN limit
|
|
589
|
+
* therefore never matches anything: it does not narrow the parse, it removes
|
|
590
|
+
* the file bound outright and leaves an unauthenticated caller free to send as
|
|
591
|
+
* many files as it likes. That is the precise widening this function exists to
|
|
592
|
+
* prevent, so Math.floor and the finite check are load-bearing rather than
|
|
593
|
+
* defensive tidiness.
|
|
594
|
+
*
|
|
595
|
+
* Latent as things stand - the only caller passes the value through
|
|
596
|
+
* parsePositiveIntegerFromEnv, which rejects "1.5" and garbage before it gets
|
|
597
|
+
* here. Pinned anyway, because the function is exported and the next caller
|
|
598
|
+
* may not come through the config layer at all.
|
|
599
|
+
*/
|
|
600
|
+
describe("getMultipartFormDataMiddleware - a non-integer maxFiles cannot unbound the parse", () => {
|
|
601
|
+
test("a fractional maxFiles narrows to the whole number below it", async () => {
|
|
602
|
+
const middleware: RequestHandler = getMultipartFormDataMiddleware({
|
|
603
|
+
maxFiles: 2.5,
|
|
604
|
+
});
|
|
605
|
+
|
|
606
|
+
const accepted: Outcome = await run(tinyFiles(2), {
|
|
607
|
+
middleware: middleware,
|
|
608
|
+
});
|
|
609
|
+
const rejected: Outcome = await run(tinyFiles(3), {
|
|
610
|
+
middleware: middleware,
|
|
611
|
+
});
|
|
612
|
+
|
|
613
|
+
expect(accepted.error).toBeUndefined();
|
|
614
|
+
expect(files(accepted)).toHaveLength(2);
|
|
615
|
+
/*
|
|
616
|
+
* The half is what matters: handed 2.5 straight to multer, this third
|
|
617
|
+
* file arrives with no error at all.
|
|
618
|
+
*/
|
|
619
|
+
expect((rejected.error as Exception).code).toBe(
|
|
620
|
+
ExceptionCode.PayloadTooLargeException,
|
|
621
|
+
);
|
|
622
|
+
expect((rejected.error as Exception).message).toContain("LIMIT_FILE_COUNT");
|
|
623
|
+
});
|
|
624
|
+
|
|
625
|
+
test("a fractional maxFiles above the ceiling is still bounded by the ceiling", async () => {
|
|
626
|
+
const middleware: RequestHandler = getMultipartFormDataMiddleware({
|
|
627
|
+
maxFiles: MAX_MULTIPART_FILES + 0.5,
|
|
628
|
+
});
|
|
629
|
+
|
|
630
|
+
const outcome: Outcome = await run(tinyFiles(MAX_MULTIPART_FILES + 1), {
|
|
631
|
+
middleware: middleware,
|
|
632
|
+
});
|
|
633
|
+
|
|
634
|
+
expect((outcome.error as Exception).code).toBe(
|
|
635
|
+
ExceptionCode.PayloadTooLargeException,
|
|
636
|
+
);
|
|
637
|
+
expect((outcome.error as Exception).message).toContain("LIMIT_FILE_COUNT");
|
|
638
|
+
});
|
|
639
|
+
|
|
640
|
+
test("NaN falls back to the shared ceiling rather than removing the file bound", async () => {
|
|
641
|
+
/*
|
|
642
|
+
* NaN survives every comparison a naive clamp makes - Math.min(NaN, 50)
|
|
643
|
+
* and Math.max(1, NaN) are both NaN - so it would reach multer intact and
|
|
644
|
+
* silently uncap the route. It has to land on the shared instance instead.
|
|
645
|
+
*/
|
|
646
|
+
const middleware: RequestHandler = getMultipartFormDataMiddleware({
|
|
647
|
+
maxFiles: Number.NaN,
|
|
648
|
+
});
|
|
649
|
+
|
|
650
|
+
expect(middleware).toBe(MultipartFormDataMiddleware);
|
|
651
|
+
|
|
652
|
+
const outcome: Outcome = await run(tinyFiles(MAX_MULTIPART_FILES + 1), {
|
|
653
|
+
middleware: middleware,
|
|
654
|
+
});
|
|
655
|
+
|
|
656
|
+
expect((outcome.error as Exception).code).toBe(
|
|
657
|
+
ExceptionCode.PayloadTooLargeException,
|
|
658
|
+
);
|
|
659
|
+
expect((outcome.error as Exception).message).toContain("LIMIT_FILE_COUNT");
|
|
660
|
+
});
|
|
661
|
+
});
|
|
662
|
+
|
|
663
|
+
describe("getMultipartFormDataMiddleware - narrowing files changes nothing else", () => {
|
|
664
|
+
const narrow: RequestHandler = getMultipartFormDataMiddleware({
|
|
665
|
+
maxFiles: 2,
|
|
666
|
+
});
|
|
667
|
+
|
|
668
|
+
test("its own file-count limit does not relax the shared size ceiling", async () => {
|
|
669
|
+
const outcome: Outcome = await run(
|
|
670
|
+
[
|
|
671
|
+
{
|
|
672
|
+
name: "big",
|
|
673
|
+
value: Buffer.alloc(MAX_MULTIPART_FILE_BYTES + 1),
|
|
674
|
+
filename: "big.bin",
|
|
675
|
+
},
|
|
676
|
+
],
|
|
677
|
+
{ middleware: narrow },
|
|
678
|
+
);
|
|
679
|
+
|
|
680
|
+
expect((outcome.error as Exception).code).toBe(
|
|
681
|
+
ExceptionCode.PayloadTooLargeException,
|
|
682
|
+
);
|
|
683
|
+
expect((outcome.error as Exception).message).toContain("LIMIT_FILE_SIZE");
|
|
684
|
+
});
|
|
685
|
+
|
|
686
|
+
test("the shared size ceiling is INCLUSIVE, and a narrowed instance lands on the same byte", async () => {
|
|
687
|
+
/*
|
|
688
|
+
* busboy truncates a file the moment its byte count REACHES fileSize,
|
|
689
|
+
* so the middleware hands it MAX_MULTIPART_FILE_BYTES + 1 to make the
|
|
690
|
+
* constant itself an inclusive maximum.
|
|
691
|
+
*
|
|
692
|
+
* Worth pinning rather than glossing: EnvironmentConfig clamps
|
|
693
|
+
* SOURCE_MAP_MAX_FILE_SIZE_BYTES to exactly MAX_MULTIPART_FILE_BYTES and
|
|
694
|
+
* SourceMapIngestService rejects only what is STRICTLY over it, so a map
|
|
695
|
+
* of precisely that many bytes is one the service means to accept -- and
|
|
696
|
+
* before the +1 the parser killed it first, turning the 400 the endpoint
|
|
697
|
+
* documents into a 413 it never saw. Narrowing the file COUNT must not
|
|
698
|
+
* move that boundary either.
|
|
699
|
+
*/
|
|
700
|
+
// One allocation, driven through both instances - it is 50 MiB.
|
|
701
|
+
const atLimit: Buffer = Buffer.alloc(MAX_MULTIPART_FILE_BYTES);
|
|
702
|
+
|
|
703
|
+
const atCeiling: Outcome = await run(
|
|
704
|
+
[{ name: "atlimit", value: atLimit, filename: "atlimit.bin" }],
|
|
705
|
+
{ middleware: narrow },
|
|
706
|
+
);
|
|
707
|
+
|
|
708
|
+
expect(atCeiling.error).toBeUndefined();
|
|
709
|
+
expect(files(atCeiling)[0]!.buffer.length).toBe(MAX_MULTIPART_FILE_BYTES);
|
|
710
|
+
|
|
711
|
+
// The shared instance is the baseline the narrowed one must match.
|
|
712
|
+
const sharedAtCeiling: Outcome = await run([
|
|
713
|
+
{ name: "atlimit", value: atLimit, filename: "atlimit.bin" },
|
|
714
|
+
]);
|
|
715
|
+
|
|
716
|
+
expect(sharedAtCeiling.error).toBeUndefined();
|
|
717
|
+
expect(files(sharedAtCeiling)[0]!.buffer.length).toBe(
|
|
718
|
+
MAX_MULTIPART_FILE_BYTES,
|
|
719
|
+
);
|
|
720
|
+
|
|
721
|
+
const overCeiling: Outcome = await run(
|
|
722
|
+
[
|
|
723
|
+
{
|
|
724
|
+
name: "overlimit",
|
|
725
|
+
value: Buffer.alloc(MAX_MULTIPART_FILE_BYTES + 1),
|
|
726
|
+
filename: "overlimit.bin",
|
|
727
|
+
},
|
|
728
|
+
],
|
|
729
|
+
{ middleware: narrow },
|
|
730
|
+
);
|
|
731
|
+
|
|
732
|
+
expect((overCeiling.error as Exception).code).toBe(
|
|
733
|
+
ExceptionCode.PayloadTooLargeException,
|
|
734
|
+
);
|
|
735
|
+
expect((overCeiling.error as Exception).message).toContain(
|
|
736
|
+
"LIMIT_FILE_SIZE",
|
|
737
|
+
);
|
|
738
|
+
});
|
|
739
|
+
|
|
740
|
+
test("the shared field-value ceiling still applies", async () => {
|
|
741
|
+
const outcome: Outcome = await run(
|
|
742
|
+
[{ name: "html", value: Buffer.alloc(MAX_MULTIPART_FIELD_BYTES + 1) }],
|
|
743
|
+
{ middleware: narrow },
|
|
744
|
+
);
|
|
745
|
+
|
|
746
|
+
expect((outcome.error as Exception).code).toBe(
|
|
747
|
+
ExceptionCode.PayloadTooLargeException,
|
|
748
|
+
);
|
|
749
|
+
expect((outcome.error as Exception).message).toContain("LIMIT_FIELD_VALUE");
|
|
750
|
+
});
|
|
751
|
+
|
|
752
|
+
test("the whole shared field allowance still parses alongside its files", async () => {
|
|
753
|
+
/*
|
|
754
|
+
* `parts` is files + fields, so a narrowed instance has to carry the
|
|
755
|
+
* field allowance over rather than deriving the part budget from its own
|
|
756
|
+
* file count. Leaving parts at 2 - or at anything near it - would make
|
|
757
|
+
* the part count the effective limit, and the source map route would
|
|
758
|
+
* start 413ing bodies whose field count the shared config says are fine.
|
|
759
|
+
*/
|
|
760
|
+
const outcome: Outcome = await run(
|
|
761
|
+
[
|
|
762
|
+
...Array.from(
|
|
763
|
+
{ length: MAX_MULTIPART_FIELDS },
|
|
764
|
+
(_v: unknown, i: number): MultipartPart => {
|
|
765
|
+
return { name: `k${i}`, value: Buffer.from("v") };
|
|
766
|
+
},
|
|
767
|
+
),
|
|
768
|
+
...tinyFiles(1),
|
|
769
|
+
],
|
|
770
|
+
{ middleware: narrow },
|
|
771
|
+
);
|
|
772
|
+
|
|
773
|
+
expect(outcome.error).toBeUndefined();
|
|
774
|
+
expect(
|
|
775
|
+
Object.keys(outcome.req.body as Record<string, unknown>),
|
|
776
|
+
).toHaveLength(MAX_MULTIPART_FIELDS);
|
|
777
|
+
expect(files(outcome)).toHaveLength(1);
|
|
778
|
+
});
|
|
779
|
+
|
|
780
|
+
test("its full file count fits alongside one field short of the allowance", async () => {
|
|
781
|
+
const outcome: Outcome = await run(
|
|
782
|
+
[
|
|
783
|
+
...Array.from(
|
|
784
|
+
{ length: MAX_MULTIPART_FIELDS - 1 },
|
|
785
|
+
(_v: unknown, i: number): MultipartPart => {
|
|
786
|
+
return { name: `k${i}`, value: Buffer.from("v") };
|
|
787
|
+
},
|
|
788
|
+
),
|
|
789
|
+
...tinyFiles(2),
|
|
790
|
+
],
|
|
791
|
+
{ middleware: narrow },
|
|
792
|
+
);
|
|
793
|
+
|
|
794
|
+
expect(outcome.error).toBeUndefined();
|
|
795
|
+
expect(files(outcome)).toHaveLength(2);
|
|
796
|
+
});
|
|
797
|
+
|
|
798
|
+
test("the maximal body - the full file AND field allowance - is accepted", async () => {
|
|
799
|
+
/*
|
|
800
|
+
* busboy starts its part counter at -1 to account for the opening
|
|
801
|
+
* boundary and then fires partsLimit when the counter REACHES the limit,
|
|
802
|
+
* so a raw `parts: n` admits only n - 1. That used to reject a body
|
|
803
|
+
* carrying the file limit AND the field limit in full with
|
|
804
|
+
* LIMIT_PART_COUNT, though neither of those limits was breached -- the
|
|
805
|
+
* exact thing the comment on `parts` says must not happen. The
|
|
806
|
+
* middleware now converts it, so the maximal body parses.
|
|
807
|
+
*
|
|
808
|
+
* Pinned on BOTH instances so the narrowed one is provably no tighter
|
|
809
|
+
* than the shared one: a narrowing that also stole a part would show up
|
|
810
|
+
* here rather than in production.
|
|
811
|
+
*/
|
|
812
|
+
const fields: (count: number) => Array<MultipartPart> = (
|
|
813
|
+
count: number,
|
|
814
|
+
): Array<MultipartPart> => {
|
|
815
|
+
return Array.from(
|
|
816
|
+
{ length: count },
|
|
817
|
+
(_v: unknown, i: number): MultipartPart => {
|
|
818
|
+
return { name: `k${i}`, value: Buffer.from("v") };
|
|
819
|
+
},
|
|
820
|
+
);
|
|
821
|
+
};
|
|
822
|
+
|
|
823
|
+
const narrowed: Outcome = await run(
|
|
824
|
+
[...fields(MAX_MULTIPART_FIELDS), ...tinyFiles(2)],
|
|
825
|
+
{ middleware: narrow },
|
|
826
|
+
);
|
|
827
|
+
|
|
828
|
+
expect(narrowed.error).toBeUndefined();
|
|
829
|
+
expect(files(narrowed)).toHaveLength(2);
|
|
830
|
+
|
|
831
|
+
const shared: Outcome = await run([
|
|
832
|
+
...fields(MAX_MULTIPART_FIELDS),
|
|
833
|
+
...tinyFiles(MAX_MULTIPART_FILES),
|
|
834
|
+
]);
|
|
835
|
+
|
|
836
|
+
expect(shared.error).toBeUndefined();
|
|
837
|
+
expect(files(shared)).toHaveLength(MAX_MULTIPART_FILES);
|
|
838
|
+
});
|
|
839
|
+
|
|
840
|
+
test("one file past the maximal body is LIMIT_FILE_COUNT, not LIMIT_PART_COUNT", async () => {
|
|
841
|
+
/*
|
|
842
|
+
* The counts stay the limits that actually speak. Raising `parts` to
|
|
843
|
+
* admit the maximal body must not push the parts limit down onto a body
|
|
844
|
+
* that breaches the file allowance -- the caller needs to be told which
|
|
845
|
+
* allowance they exceeded.
|
|
846
|
+
*/
|
|
847
|
+
const outcome: Outcome = await run(
|
|
848
|
+
Array.from(
|
|
849
|
+
{ length: MAX_MULTIPART_FIELDS },
|
|
850
|
+
(_v: unknown, i: number): MultipartPart => {
|
|
851
|
+
return { name: `k${i}`, value: Buffer.from("v") };
|
|
852
|
+
},
|
|
853
|
+
).concat(tinyFiles(MAX_MULTIPART_FILES + 1)),
|
|
854
|
+
);
|
|
855
|
+
|
|
856
|
+
expect((outcome.error as Exception).code).toBe(
|
|
857
|
+
ExceptionCode.PayloadTooLargeException,
|
|
858
|
+
);
|
|
859
|
+
expect((outcome.error as Exception).message).toContain("LIMIT_FILE_COUNT");
|
|
860
|
+
});
|
|
861
|
+
|
|
862
|
+
test("one field too many is still LIMIT_FIELD_COUNT, not LIMIT_PART_COUNT", async () => {
|
|
863
|
+
const outcome: Outcome = await run(
|
|
864
|
+
Array.from(
|
|
865
|
+
{ length: MAX_MULTIPART_FIELDS + 1 },
|
|
866
|
+
(_v: unknown, i: number): MultipartPart => {
|
|
867
|
+
return { name: `k${i}`, value: Buffer.from("v") };
|
|
868
|
+
},
|
|
869
|
+
),
|
|
870
|
+
{ middleware: narrow },
|
|
871
|
+
);
|
|
872
|
+
|
|
873
|
+
expect((outcome.error as Exception).code).toBe(
|
|
874
|
+
ExceptionCode.PayloadTooLargeException,
|
|
875
|
+
);
|
|
876
|
+
expect((outcome.error as Exception).message).toContain("LIMIT_FIELD_COUNT");
|
|
877
|
+
});
|
|
878
|
+
|
|
879
|
+
test("next() is called exactly once on a breach here too", async () => {
|
|
880
|
+
const outcome: Outcome = await run(tinyFiles(3), { middleware: narrow });
|
|
881
|
+
|
|
882
|
+
expect(outcome.nextCalls).toBe(1);
|
|
883
|
+
});
|
|
884
|
+
|
|
885
|
+
test("a non-multer error passes straight through instead of becoming a 413", async () => {
|
|
886
|
+
/*
|
|
887
|
+
* A multipart Content-Type with no boundary makes busboy throw during
|
|
888
|
+
* construction, which multer hands to next() as a plain Error. That is a
|
|
889
|
+
* malformed request, not an oversized one, and the error mapping both
|
|
890
|
+
* instances share must not launder it into a PayloadTooLargeException -
|
|
891
|
+
* doing so would report every parser failure as "you sent too much".
|
|
892
|
+
*/
|
|
893
|
+
const outcome: Outcome = await run(tinyFiles(1), {
|
|
894
|
+
middleware: narrow,
|
|
895
|
+
contentType: "multipart/form-data",
|
|
896
|
+
});
|
|
897
|
+
|
|
898
|
+
expect(outcome.error).toBeInstanceOf(Error);
|
|
899
|
+
expect(outcome.error).not.toBeInstanceOf(Exception);
|
|
900
|
+
expect((outcome.error as Error).message).toContain("Boundary not found");
|
|
901
|
+
expect(outcome.nextCalls).toBe(1);
|
|
902
|
+
});
|
|
903
|
+
|
|
904
|
+
test("the default middleware treats that same non-multer error identically", async () => {
|
|
905
|
+
const outcome: Outcome = await run(tinyFiles(1), {
|
|
906
|
+
contentType: "multipart/form-data",
|
|
907
|
+
});
|
|
908
|
+
|
|
909
|
+
expect(outcome.error).toBeInstanceOf(Error);
|
|
910
|
+
expect(outcome.error).not.toBeInstanceOf(Exception);
|
|
911
|
+
expect((outcome.error as Error).message).toContain("Boundary not found");
|
|
912
|
+
});
|
|
913
|
+
});
|