@oneuptime/common 14.0.7 → 14.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Models/DatabaseModels/Incident.ts +267 -1
- package/Models/DatabaseModels/IncidentCustomField.ts +202 -0
- package/Models/DatabaseModels/IncidentEpisode.ts +30 -0
- package/Models/DatabaseModels/IncidentTemplate.ts +126 -1
- package/Models/DatabaseModels/StatusPage.ts +55 -0
- package/Models/DatabaseModels/StatusPageSubscriber.ts +128 -0
- package/Server/API/IncidentAPI.ts +162 -0
- package/Server/API/StatusPageAPI.ts +487 -171
- package/Server/API/StatusPageSubscriberAPI.ts +63 -15
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795300000000-SkipHiddenIncidentCreatedNotifications.ts +49 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795400000000-AddIncidentStatusPageScope.ts +108 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795500000000-AddIncidentTemplateStatusPageScopeFlag.ts +33 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795600000000-AddStatusPageSubscriberUnsubscribeToken.ts +51 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795700000000-AddStatusPageSubscriberIsAddedByTeam.ts +33 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795800000000-AddIncidentCustomFieldCreateAndNotificationSettings.ts +168 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795900000000-AddSubscriberNotificationClaimedAt.ts +44 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +14 -0
- package/Server/Infrastructure/Semaphore.ts +10 -0
- package/Server/Middleware/IdentityRateLimit.ts +108 -3
- package/Server/Middleware/SubscriberNotificationPreviewRateLimit.ts +237 -0
- package/Server/Middleware/SubscriberNotificationTestSendRateLimit.ts +304 -0
- package/Server/Services/DatabaseService.ts +93 -10
- package/Server/Services/IncidentCustomFieldService.ts +276 -1
- package/Server/Services/IncidentEpisodePublicNoteService.ts +28 -0
- package/Server/Services/IncidentEpisodeService.ts +15 -0
- package/Server/Services/IncidentEpisodeStateTimelineService.ts +27 -1
- package/Server/Services/IncidentPublicNoteService.ts +30 -1
- package/Server/Services/IncidentService.ts +1535 -65
- package/Server/Services/IncidentStateTimelineService.ts +13 -0
- package/Server/Services/IncidentTemplateService.ts +109 -0
- package/Server/Services/ScheduledMaintenancePublicNoteService.ts +30 -1
- package/Server/Services/ScheduledMaintenanceService.ts +68 -18
- package/Server/Services/SmsService.ts +10 -0
- package/Server/Services/StatusPageService.ts +65 -8
- package/Server/Services/StatusPageSubscriberNotificationTemplateService.ts +299 -37
- package/Server/Services/StatusPageSubscriberNotificationTemplateStatusPageService.ts +129 -0
- package/Server/Services/StatusPageSubscriberService.ts +1161 -64
- package/Server/Types/Markdown.ts +153 -6
- package/Server/Types/Workflow/Components/Email.ts +61 -2
- package/Server/Utils/CustomField/CustomFieldRename.ts +378 -0
- package/Server/Utils/DataSource/EgressGuard.ts +66 -21
- package/Server/Utils/Mail/PinnedSmtpSocket.ts +130 -0
- package/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.ts +10 -0
- package/Server/Utils/SSRFProtection.ts +76 -16
- package/Server/Utils/StatusPage/IncidentStatusPageScope.ts +948 -0
- package/Server/Utils/StatusPage/IncidentSubscriberAudienceBuilder.ts +656 -0
- package/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.ts +805 -0
- package/Server/Utils/StatusPage/StatusPageExclusion.ts +18 -0
- package/Server/Utils/StatusPage/StatusPageReadAccess.ts +125 -0
- package/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.ts +151 -0
- package/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.ts +70 -0
- package/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.ts +421 -0
- package/Server/Utils/StatusPage/SubscriberNotificationClaim.ts +107 -0
- package/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.ts +1049 -0
- package/Server/Utils/StatusPage/SubscriberNotificationFanOut.ts +180 -0
- package/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.ts +839 -0
- package/Server/Utils/StatusPage/SubscriberNotificationResendAccess.ts +393 -0
- package/Server/Utils/StatusPage/SubscriberNotificationRunLimit.ts +246 -0
- package/Server/Utils/StatusPage/SubscriberNotificationTiming.ts +133 -0
- package/Server/Utils/StatusPage/SubscriberTemplateIncidentRecordAccess.ts +215 -0
- package/Server/Utils/StatusPageResource.ts +51 -20
- package/Server/Utils/VM/VMAPI.ts +1 -0
- package/Server/Utils/VM/VMRunner.ts +10 -0
- package/Server/Utils/Workflow/OAuth2TokenClient.ts +10 -0
- package/Server/Views/Partials/SensitiveUrlToken.ejs +8 -5
- package/Tests/App/Accounts/RegisterVerifyEmail.test.tsx +748 -0
- package/Tests/App/Accounts/ResendVerificationEmail.test.tsx +1222 -0
- package/Tests/App/Accounts/VerificationEmailResendUtils.test.ts +797 -0
- package/Tests/App/Accounts/VerifyEmailPending.test.tsx +538 -0
- package/Tests/App/Accounts/VerifyEmailResend.test.tsx +779 -0
- package/Tests/App/Dashboard/CustomFieldsSettingsIncidentOptions.test.tsx +357 -0
- package/Tests/App/Dashboard/EventNotes.test.tsx +776 -0
- package/Tests/App/Dashboard/EventNotesPages.test.tsx +119 -0
- package/Tests/App/Dashboard/EventNotesUtil.test.ts +116 -17
- package/Tests/App/Dashboard/EventOverviewPages.test.tsx +242 -5
- package/Tests/App/Dashboard/IncidentChangeStateNotifyDefault.test.tsx +91 -1
- package/Tests/App/Dashboard/IncidentCreateDetailsStep.test.tsx +643 -0
- package/Tests/App/Dashboard/IncidentCreateFromAlerts.test.tsx +8 -1
- package/Tests/App/Dashboard/IncidentCreateStatusPageScope.test.tsx +601 -0
- package/Tests/App/Dashboard/IncidentCustomFieldTemplateVariables.test.tsx +386 -0
- package/Tests/App/Dashboard/IncidentNoteTemplatePlaceholders.test.tsx +124 -0
- package/Tests/App/Dashboard/IncidentNoteTemplateVariablesLoader.test.ts +305 -0
- package/Tests/App/Dashboard/IncidentOverviewNotifyDefault.test.tsx +112 -0
- package/Tests/App/Dashboard/IncidentSettingsRenotifyOnPublish.test.tsx +674 -0
- package/Tests/App/Dashboard/IncidentSettingsStatusPageScope.test.tsx +1051 -0
- package/Tests/App/Dashboard/IncidentTemplateCustomFields.test.tsx +384 -0
- package/Tests/App/Dashboard/IncidentTemplateStatusPageScopeCard.test.tsx +215 -0
- package/Tests/App/Dashboard/PublicNotePagesNotifyDefault.test.tsx +113 -1
- package/Tests/App/Dashboard/SubscriberAudienceSummary.test.tsx +512 -0
- package/Tests/App/Dashboard/SubscriberNotificationPreviewModal.test.tsx +837 -0
- package/Tests/App/Dashboard/SubscriberNotificationStatusLabel.test.tsx +88 -0
- package/Tests/App/Dashboard/SubscriberNotificationStatusResend.test.tsx +473 -0
- package/Tests/App/Dashboard/SubscriberTemplateLivePreview.test.tsx +196 -0
- package/Tests/App/Dashboard/TeamAddedSubscribersUnsubscribedNotice.test.tsx +248 -0
- package/Tests/App/SensitiveUrlTokenBootstrap.test.ts +64 -3
- package/Tests/App/StatusPage/StatusPageUnsubscribePage.test.tsx +412 -0
- package/Tests/Models/IncidentCustomFieldApiSchemaContract.test.ts +217 -0
- package/Tests/Models/IncidentCustomFieldCreateSettingsColumns.test.ts +252 -0
- package/Tests/Models/StatusPageSubscriberUnsubscribeColumns.test.ts +218 -0
- package/Tests/Server/API/ExpiredSessionRouteGuards.test.ts +7 -0
- package/Tests/Server/API/IncidentSubscriberAudienceAPI.test.ts +1408 -0
- package/Tests/Server/API/StatusPageIncidentScope.test.ts +1868 -0
- package/Tests/Server/API/StatusPageIncidentScopePostgres.test.ts +790 -0
- package/Tests/Server/API/StatusPageManageSubscriptionRecipient.test.ts +10 -1
- package/Tests/Server/API/StatusPageManageSubscriptionTemplateVariables.test.ts +206 -18
- package/Tests/Server/API/StatusPagePostmortemVisibility.test.ts +14 -2
- package/Tests/Server/API/StatusPageSubscriberCreateResponse.test.ts +217 -0
- package/Tests/Server/API/StatusPageSubscriberOwnership.test.ts +103 -2
- package/Tests/Server/API/StatusPageUnsubscribeAPI.test.ts +396 -0
- package/Tests/Server/Infrastructure/Postgres/AddIncidentStatusPageScopeMigration.test.ts +395 -0
- package/Tests/Server/Infrastructure/Postgres/AddIncidentTemplateStatusPageScopeFlagMigration.test.ts +150 -0
- package/Tests/Server/Infrastructure/Postgres/AddSubscriberNotificationClaimedAtMigration.test.ts +156 -0
- package/Tests/Server/Infrastructure/Postgres/SkipHiddenIncidentCreatedNotificationsMigration.test.ts +410 -0
- package/Tests/Server/Middleware/IdentityRateLimit.test.ts +551 -1
- package/Tests/Server/Middleware/SubscriberNotificationPreviewRateLimit.test.ts +238 -0
- package/Tests/Server/Middleware/SubscriberNotificationTestSendRateLimit.test.ts +245 -0
- package/Tests/Server/Services/AddStatusPageSubscriberUnsubscribeTokenMigration.test.ts +152 -0
- package/Tests/Server/Services/CrossProjectRelationWriteGuard.test.ts +221 -36
- package/Tests/Server/Services/DatabaseServiceCompareAndSetColumns.test.ts +191 -0
- package/Tests/Server/Services/IncidentCreatedRenotifyOnPublish.test.ts +681 -0
- package/Tests/Server/Services/IncidentCreatedResend.test.ts +775 -0
- package/Tests/Server/Services/IncidentCustomFieldRenamePostgres.test.ts +713 -0
- package/Tests/Server/Services/IncidentCustomFieldService.test.ts +751 -0
- package/Tests/Server/Services/IncidentCustomFieldValueValidation.test.ts +556 -0
- package/Tests/Server/Services/IncidentStatusPageScope.test.ts +2971 -0
- package/Tests/Server/Services/IncidentStatusPageScopeFeed.test.ts +131 -0
- package/Tests/Server/Services/IncidentStatusPageScopePostgres.test.ts +625 -0
- package/Tests/Server/Services/IncidentTemplateCustomFieldsCopy.test.ts +311 -0
- package/Tests/Server/Services/IncidentTemplateStatusPageScope.test.ts +363 -0
- package/Tests/Server/Services/PublicNoteEditFeedEventType.test.ts +213 -0
- package/Tests/Server/Services/PublicNoteResendAccess.test.ts +994 -0
- package/Tests/Server/Services/ScheduledMaintenanceSubscriberTemplateFormats.test.ts +289 -9
- package/Tests/Server/Services/SmsServiceFailIfNotSent.test.ts +67 -0
- package/Tests/Server/Services/StatusPageReportIncidentCounts.test.ts +610 -0
- package/Tests/Server/Services/StatusPageSubscriberAudienceCounts.test.ts +201 -0
- package/Tests/Server/Services/StatusPageSubscriberAudienceCountsPostgres.test.ts +271 -0
- package/Tests/Server/Services/StatusPageSubscriberConfirmationTemplateEscaping.test.ts +200 -0
- package/Tests/Server/Services/StatusPageSubscriberNotificationLogRedaction.test.ts +54 -0
- package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateCompile.test.ts +37 -0
- package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateIncidentRecordAccess.test.ts +772 -0
- package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateLookup.test.ts +506 -0
- package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateLookupPostgres.test.ts +261 -0
- package/Tests/Server/Services/StatusPageSubscriberReport.test.ts +21 -5
- package/Tests/Server/Services/StatusPageSubscriberUnsubscribe.test.ts +1618 -0
- package/Tests/Server/Services/StatusPageSubscriberUnsubscribeLinkSenders.test.ts +373 -0
- package/Tests/Server/Services/StatusPageSubscriberUnsubscribePostgres.test.ts +388 -0
- package/Tests/Server/Services/SubscriberNotificationInFlightRequeue.test.ts +500 -0
- package/Tests/Server/Types/MarkdownEmailLinks.test.ts +320 -0
- package/Tests/Server/Types/Workflow/Components/Email.test.ts +491 -1
- package/Tests/Server/Types/Workflow/Components/EmailSmtpPinning.test.ts +398 -0
- package/Tests/Server/Utils/CustomField/CustomFieldRename.test.ts +586 -0
- package/Tests/Server/Utils/DataSource/EgressGuard.test.ts +246 -10
- package/Tests/Server/Utils/DataSource/EgressGuardDeploymentConfig.test.ts +226 -0
- package/Tests/Server/Utils/DataSource/EgressGuardPinning.test.ts +131 -0
- package/Tests/Server/Utils/DataSource/HttpFetch.test.ts +4 -0
- package/Tests/Server/Utils/EgressPolicyEnvironment.ts +45 -0
- package/Tests/Server/Utils/Mail/PinnedSmtpSocket.test.ts +409 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaObservationBuilderUnits.test.ts +23 -0
- package/Tests/Server/Utils/SSRFProtection.test.ts +4 -0
- package/Tests/Server/Utils/SSRFProtectionCloudServiceAddresses.test.ts +4 -0
- package/Tests/Server/Utils/SSRFProtectionPrivateNetwork.test.ts +4 -0
- package/Tests/Server/Utils/SSRFProtectionResolutionDetail.test.ts +314 -0
- package/Tests/Server/Utils/StatusPage/IncidentStatusPageScope.test.ts +1699 -0
- package/Tests/Server/Utils/StatusPage/IncidentStatusPageScopeQueriesPostgres.test.ts +508 -0
- package/Tests/Server/Utils/StatusPage/IncidentSubscriberAudienceCallerPermission.test.ts +246 -0
- package/Tests/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.test.ts +1348 -0
- package/Tests/Server/Utils/StatusPage/StatusPageReadAccess.test.ts +221 -0
- package/Tests/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.test.ts +132 -0
- package/Tests/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.test.ts +155 -0
- package/Tests/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.test.ts +708 -0
- package/Tests/Server/Utils/StatusPage/SubscriberNotificationClaim.test.ts +255 -0
- package/Tests/Server/Utils/StatusPage/SubscriberNotificationClaimPostgres.test.ts +528 -0
- package/Tests/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.test.ts +1238 -0
- package/Tests/Server/Utils/StatusPage/SubscriberNotificationFanOut.test.ts +472 -0
- package/Tests/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.test.ts +1168 -0
- package/Tests/Server/Utils/StatusPage/SubscriberNotificationRunLimit.test.ts +275 -0
- package/Tests/Server/Utils/StatusPage/SubscriberNotificationTiming.test.ts +131 -0
- package/Tests/Server/Utils/StatusPageResource.test.ts +98 -0
- package/Tests/Server/Utils/VM/VMRunnerPrivateNetworkWiring.test.ts +17 -0
- package/Tests/Server/Utils/VM/VMRunnerSsrf.test.ts +75 -0
- package/Tests/Types/CustomField/CustomFieldSavedViews.test.ts +247 -0
- package/Tests/Types/CustomField/CustomFieldTemplateValues.test.ts +186 -0
- package/Tests/Types/CustomField/CustomFieldTypeCorrespondence.test.ts +48 -0
- package/Tests/Types/CustomField/CustomFieldValueFormat.test.ts +215 -0
- package/Tests/Types/CustomField/CustomFieldValueValidator.test.ts +343 -0
- package/Tests/Types/CustomField/CustomFieldVariableKey.test.ts +364 -0
- package/Tests/Types/SafeHtml.test.ts +102 -0
- package/Tests/Types/StatusPage/IncidentCreatedRenotify.test.ts +419 -0
- package/Tests/Types/StatusPage/IncidentCreatedResend.test.ts +118 -0
- package/Tests/Types/StatusPage/IncidentScopeAddedPagesNotification.test.ts +558 -0
- package/Tests/Types/StatusPage/IncidentSubscriberAudience.test.ts +284 -0
- package/Tests/Types/StatusPage/StatusPageSubscriberUnsubscribe.test.ts +341 -0
- package/Tests/Types/StatusPage/SubscriberNotificationPreview.test.ts +196 -0
- package/Tests/Types/StatusPage/SubscriberNotificationResend.test.ts +201 -0
- package/Tests/Types/StatusPage/SubscriberNotificationTemplateCompiler.test.ts +277 -0
- package/Tests/Types/StatusPage/SubscriberNotificationTemplatePreview.test.ts +179 -0
- package/Tests/Types/StatusPage/SubscriberNotificationTemplateVariables.test.ts +324 -0
- package/Tests/Types/StatusPage/SubscriberUpdateNotification.test.ts +60 -13
- package/Tests/UI/Components/CustomFields/CustomFieldFormFields.test.ts +432 -0
- package/Tests/UI/Components/CustomFields/CustomFieldModelFormFields.test.tsx +685 -0
- package/Tests/UI/Components/CustomFields/CustomFieldsDetailOrder.test.tsx +469 -0
- package/Tests/UI/Components/Forms/ModelFormCustomFieldInputs.test.tsx +325 -0
- package/Tests/UI/Components/Forms/ModelFormDropdownOptionsRefused.test.tsx +358 -0
- package/Tests/UI/Components/ModelTable/CustomFieldColumns.test.tsx +22 -0
- package/Tests/UI/Monitor/NetworkPathView.test.tsx +289 -0
- package/Tests/Utils/Incident/IncidentNoteTemplateVariables.test.ts +623 -0
- package/Tests/Utils/Markdown/MarkdownEscape.test.ts +89 -0
- package/Tests/Utils/ProbeNetworkFailureUtil.test.ts +992 -0
- package/Tests/Utils/RequestFailedDetails.test.ts +575 -0
- package/Types/CustomField/CustomFieldOrder.ts +55 -0
- package/Types/CustomField/CustomFieldSavedViews.ts +225 -0
- package/Types/CustomField/CustomFieldTemplateMerge.ts +71 -0
- package/Types/CustomField/CustomFieldType.ts +14 -0
- package/Types/CustomField/CustomFieldValueFormat.ts +161 -0
- package/Types/CustomField/CustomFieldValueValidator.ts +488 -0
- package/Types/CustomField/CustomFieldVariableKey.ts +211 -0
- package/Types/SafeHtml.ts +93 -0
- package/Types/StatusPage/IncidentCreatedRenotify.ts +224 -0
- package/Types/StatusPage/IncidentCreatedResend.ts +108 -0
- package/Types/StatusPage/IncidentScopeAddedPagesNotification.ts +343 -0
- package/Types/StatusPage/IncidentSubscriberAudience.ts +332 -0
- package/Types/StatusPage/StatusPageSubscriberUnsubscribe.ts +405 -0
- package/Types/StatusPage/SubscriberNotificationInterruption.ts +32 -0
- package/Types/StatusPage/SubscriberNotificationPreview.ts +322 -0
- package/Types/StatusPage/SubscriberNotificationResend.ts +132 -0
- package/Types/StatusPage/SubscriberNotificationTemplateCompiler.ts +180 -0
- package/Types/StatusPage/SubscriberNotificationTemplatePreview.ts +301 -0
- package/Types/StatusPage/SubscriberNotificationTemplateVariables.ts +217 -4
- package/Types/StatusPage/SubscriberUpdateNotification.ts +32 -11
- package/UI/Components/CustomFields/CustomFieldFormFields.ts +317 -0
- package/UI/Components/CustomFields/CustomFieldModelFormFields.tsx +395 -0
- package/UI/Components/CustomFields/CustomFieldsDetail.tsx +95 -55
- package/UI/Components/Forms/ModelForm.tsx +70 -8
- package/UI/Components/Forms/Validation.ts +1 -1
- package/UI/Components/ModelFormModal/ModelFormModal.tsx +2 -4
- package/UI/Components/ModelTable/AnalyticsModelTable.tsx +2 -6
- package/UI/Components/ModelTable/BaseModelTable.tsx +9 -8
- package/UI/Components/ModelTable/CustomFieldColumns.tsx +14 -1
- package/UI/Components/ModelTable/ModelTable.tsx +6 -7
- package/UI/Utils/SensitiveUrlToken.ts +10 -5
- package/Utils/API.ts +247 -2
- package/Utils/Incident/IncidentNoteTemplateVariables.ts +304 -0
- package/Utils/Markdown/MarkdownEscape.ts +65 -0
- package/Utils/ProbeNetworkFailureUtil.ts +673 -0
- package/build/dist/Models/DatabaseModels/Incident.js +267 -1
- package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentCustomField.js +207 -1
- package/build/dist/Models/DatabaseModels/IncidentCustomField.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentEpisode.js +31 -0
- package/build/dist/Models/DatabaseModels/IncidentEpisode.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentTemplate.js +124 -1
- package/build/dist/Models/DatabaseModels/IncidentTemplate.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPage.js +56 -0
- package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageSubscriber.js +131 -0
- package/build/dist/Models/DatabaseModels/StatusPageSubscriber.js.map +1 -1
- package/build/dist/Server/API/IncidentAPI.js +100 -1
- package/build/dist/Server/API/IncidentAPI.js.map +1 -1
- package/build/dist/Server/API/StatusPageAPI.js +417 -176
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/API/StatusPageSubscriberAPI.js +52 -13
- package/build/dist/Server/API/StatusPageSubscriberAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795300000000-SkipHiddenIncidentCreatedNotifications.js +41 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795300000000-SkipHiddenIncidentCreatedNotifications.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795400000000-AddIncidentStatusPageScope.js +57 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795400000000-AddIncidentStatusPageScope.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795500000000-AddIncidentTemplateStatusPageScopeFlag.js +23 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795500000000-AddIncidentTemplateStatusPageScopeFlag.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795600000000-AddStatusPageSubscriberUnsubscribeToken.js +40 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795600000000-AddStatusPageSubscriberUnsubscribeToken.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795700000000-AddStatusPageSubscriberIsAddedByTeam.js +26 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795700000000-AddStatusPageSubscriberIsAddedByTeam.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795800000000-AddIncidentCustomFieldCreateAndNotificationSettings.js +89 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795800000000-AddIncidentCustomFieldCreateAndNotificationSettings.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795900000000-AddSubscriberNotificationClaimedAt.js +29 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795900000000-AddSubscriberNotificationClaimedAt.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +14 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Infrastructure/Semaphore.js +3 -0
- package/build/dist/Server/Infrastructure/Semaphore.js.map +1 -1
- package/build/dist/Server/Middleware/IdentityRateLimit.js +89 -3
- package/build/dist/Server/Middleware/IdentityRateLimit.js.map +1 -1
- package/build/dist/Server/Middleware/SubscriberNotificationPreviewRateLimit.js +149 -0
- package/build/dist/Server/Middleware/SubscriberNotificationPreviewRateLimit.js.map +1 -0
- package/build/dist/Server/Middleware/SubscriberNotificationTestSendRateLimit.js +190 -0
- package/build/dist/Server/Middleware/SubscriberNotificationTestSendRateLimit.js.map +1 -0
- package/build/dist/Server/Services/DatabaseService.js +56 -7
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/IncidentCustomFieldService.js +204 -8
- package/build/dist/Server/Services/IncidentCustomFieldService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js +24 -0
- package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeService.js +14 -0
- package/build/dist/Server/Services/IncidentEpisodeService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeStateTimelineService.js +26 -0
- package/build/dist/Server/Services/IncidentEpisodeStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentPublicNoteService.js +26 -1
- package/build/dist/Server/Services/IncidentPublicNoteService.js.map +1 -1
- package/build/dist/Server/Services/IncidentService.js +1052 -0
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/IncidentStateTimelineService.js +12 -0
- package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentTemplateService.js +83 -0
- package/build/dist/Server/Services/IncidentTemplateService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js +26 -1
- package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceService.js +47 -17
- package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
- package/build/dist/Server/Services/SmsService.js +2 -22
- package/build/dist/Server/Services/SmsService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageService.js +47 -9
- package/build/dist/Server/Services/StatusPageService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateService.js +237 -32
- package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateStatusPageService.js +109 -0
- package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateStatusPageService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageSubscriberService.js +925 -99
- package/build/dist/Server/Services/StatusPageSubscriberService.js.map +1 -1
- package/build/dist/Server/Types/Markdown.js +110 -6
- package/build/dist/Server/Types/Markdown.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/Email.js +55 -6
- package/build/dist/Server/Types/Workflow/Components/Email.js.map +1 -1
- package/build/dist/Server/Utils/CustomField/CustomFieldRename.js +211 -0
- package/build/dist/Server/Utils/CustomField/CustomFieldRename.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/EgressGuard.js +41 -12
- package/build/dist/Server/Utils/DataSource/EgressGuard.js.map +1 -1
- package/build/dist/Server/Utils/Mail/PinnedSmtpSocket.js +101 -0
- package/build/dist/Server/Utils/Mail/PinnedSmtpSocket.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js +9 -0
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js.map +1 -1
- package/build/dist/Server/Utils/SSRFProtection.js +48 -6
- package/build/dist/Server/Utils/SSRFProtection.js.map +1 -1
- package/build/dist/Server/Utils/StatusPage/IncidentStatusPageScope.js +631 -0
- package/build/dist/Server/Utils/StatusPage/IncidentStatusPageScope.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/IncidentSubscriberAudienceBuilder.js +403 -0
- package/build/dist/Server/Utils/StatusPage/IncidentSubscriberAudienceBuilder.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.js +451 -0
- package/build/dist/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/StatusPageExclusion.js +13 -0
- package/build/dist/Server/Utils/StatusPage/StatusPageExclusion.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/StatusPageReadAccess.js +91 -0
- package/build/dist/Server/Utils/StatusPage/StatusPageReadAccess.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.js +101 -0
- package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.js +47 -0
- package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.js +273 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationClaim.js +73 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationClaim.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.js +722 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationFanOut.js +102 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationFanOut.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.js +527 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationResendAccess.js +278 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationResendAccess.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationRunLimit.js +137 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationRunLimit.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationTiming.js +103 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationTiming.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberTemplateIncidentRecordAccess.js +114 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberTemplateIncidentRecordAccess.js.map +1 -0
- package/build/dist/Server/Utils/StatusPageResource.js +39 -7
- package/build/dist/Server/Utils/StatusPageResource.js.map +1 -1
- package/build/dist/Server/Utils/VM/VMAPI.js.map +1 -1
- package/build/dist/Server/Utils/VM/VMRunner.js +1 -0
- package/build/dist/Server/Utils/VM/VMRunner.js.map +1 -1
- package/build/dist/Server/Utils/Workflow/OAuth2TokenClient.js +3 -0
- package/build/dist/Server/Utils/Workflow/OAuth2TokenClient.js.map +1 -1
- package/build/dist/Types/CustomField/CustomFieldOrder.js +36 -0
- package/build/dist/Types/CustomField/CustomFieldOrder.js.map +1 -0
- package/build/dist/Types/CustomField/CustomFieldSavedViews.js +135 -0
- package/build/dist/Types/CustomField/CustomFieldSavedViews.js.map +1 -0
- package/build/dist/Types/CustomField/CustomFieldTemplateMerge.js +27 -0
- package/build/dist/Types/CustomField/CustomFieldTemplateMerge.js.map +1 -0
- package/build/dist/Types/CustomField/CustomFieldType.js +12 -0
- package/build/dist/Types/CustomField/CustomFieldType.js.map +1 -1
- package/build/dist/Types/CustomField/CustomFieldValueFormat.js +126 -0
- package/build/dist/Types/CustomField/CustomFieldValueFormat.js.map +1 -0
- package/build/dist/Types/CustomField/CustomFieldValueValidator.js +280 -0
- package/build/dist/Types/CustomField/CustomFieldValueValidator.js.map +1 -0
- package/build/dist/Types/CustomField/CustomFieldVariableKey.js +150 -0
- package/build/dist/Types/CustomField/CustomFieldVariableKey.js.map +1 -0
- package/build/dist/Types/SafeHtml.js +84 -0
- package/build/dist/Types/SafeHtml.js.map +1 -0
- package/build/dist/Types/StatusPage/IncidentCreatedRenotify.js +117 -0
- package/build/dist/Types/StatusPage/IncidentCreatedRenotify.js.map +1 -0
- package/build/dist/Types/StatusPage/IncidentCreatedResend.js +86 -0
- package/build/dist/Types/StatusPage/IncidentCreatedResend.js.map +1 -0
- package/build/dist/Types/StatusPage/IncidentScopeAddedPagesNotification.js +246 -0
- package/build/dist/Types/StatusPage/IncidentScopeAddedPagesNotification.js.map +1 -0
- package/build/dist/Types/StatusPage/IncidentSubscriberAudience.js +183 -0
- package/build/dist/Types/StatusPage/IncidentSubscriberAudience.js.map +1 -0
- package/build/dist/Types/StatusPage/StatusPageSubscriberUnsubscribe.js +277 -0
- package/build/dist/Types/StatusPage/StatusPageSubscriberUnsubscribe.js.map +1 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationInterruption.js +27 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationInterruption.js.map +1 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationPreview.js +190 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationPreview.js.map +1 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationResend.js +102 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationResend.js.map +1 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationTemplateCompiler.js +97 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationTemplateCompiler.js.map +1 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationTemplatePreview.js +175 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationTemplatePreview.js.map +1 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationTemplateVariables.js +144 -4
- package/build/dist/Types/StatusPage/SubscriberNotificationTemplateVariables.js.map +1 -1
- package/build/dist/Types/StatusPage/SubscriberUpdateNotification.js +29 -9
- package/build/dist/Types/StatusPage/SubscriberUpdateNotification.js.map +1 -1
- package/build/dist/UI/Components/CustomFields/CustomFieldFormFields.js +169 -0
- package/build/dist/UI/Components/CustomFields/CustomFieldFormFields.js.map +1 -0
- package/build/dist/UI/Components/CustomFields/CustomFieldModelFormFields.js +212 -0
- package/build/dist/UI/Components/CustomFields/CustomFieldModelFormFields.js.map +1 -0
- package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +64 -49
- package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
- package/build/dist/UI/Components/Forms/ModelForm.js +39 -5
- package/build/dist/UI/Components/Forms/ModelForm.js.map +1 -1
- package/build/dist/UI/Components/Forms/Validation.js +1 -1
- package/build/dist/UI/Components/Forms/Validation.js.map +1 -1
- package/build/dist/UI/Components/ModelFormModal/ModelFormModal.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/AnalyticsModelTable.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +2 -2
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js +13 -1
- package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/ModelTable.js +1 -1
- package/build/dist/UI/Components/ModelTable/ModelTable.js.map +1 -1
- package/build/dist/UI/Utils/SensitiveUrlToken.js +10 -5
- package/build/dist/UI/Utils/SensitiveUrlToken.js.map +1 -1
- package/build/dist/Utils/API.js +177 -1
- package/build/dist/Utils/API.js.map +1 -1
- package/build/dist/Utils/Incident/IncidentNoteTemplateVariables.js +155 -0
- package/build/dist/Utils/Incident/IncidentNoteTemplateVariables.js.map +1 -0
- package/build/dist/Utils/Markdown/MarkdownEscape.js +48 -0
- package/build/dist/Utils/Markdown/MarkdownEscape.js.map +1 -1
- package/build/dist/Utils/ProbeNetworkFailureUtil.js +460 -0
- package/build/dist/Utils/ProbeNetworkFailureUtil.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import Redis from "../Infrastructure/Redis";
|
|
2
|
+
import logger from "../Utils/Logger";
|
|
3
|
+
import Response from "../Utils/Response";
|
|
4
|
+
import ObjectID from "../../Types/ObjectID";
|
|
5
|
+
import ServiceUnavailableException from "../../Types/Exception/ServiceUnavailableException";
|
|
6
|
+
import TooManyRequestsException from "../../Types/Exception/TooManyRequestsException";
|
|
7
|
+
/*
|
|
8
|
+
* Request limiting for "Send test to me" (POST /send-test on the subscriber
|
|
9
|
+
* notification preview router), which emails the signed-in user the status
|
|
10
|
+
* page subscriber email they are previewing.
|
|
11
|
+
*
|
|
12
|
+
* The route only ever sends to the caller's own verified account email, so
|
|
13
|
+
* what this bounds is volume: every allowed request is a real email, through
|
|
14
|
+
* the status page's own SMTP server or the instance's mail provider, and
|
|
15
|
+
* nothing else stops a script (or a held-down button) from sending hundreds.
|
|
16
|
+
* The counter is per user, across every project, status page and incident:
|
|
17
|
+
* a user is one inbox.
|
|
18
|
+
*
|
|
19
|
+
* THIS FAILS CLOSED
|
|
20
|
+
*
|
|
21
|
+
* If Redis is unreachable, the test is refused with "try again later". That
|
|
22
|
+
* is the opposite of the choice VerificationCodeRateLimit makes, and the
|
|
23
|
+
* difference is what else bounds the requests: there, the code's expiry, its
|
|
24
|
+
* attempt counter and the resend cooldown all live in Postgres and stay in
|
|
25
|
+
* force; here this counter is the only bound on how much mail is sent. A
|
|
26
|
+
* test email is a convenience, and a Redis blip costs nothing but a retry.
|
|
27
|
+
*/
|
|
28
|
+
export var SubscriberNotificationTestSendRateLimitOutcome;
|
|
29
|
+
(function (SubscriberNotificationTestSendRateLimitOutcome) {
|
|
30
|
+
SubscriberNotificationTestSendRateLimitOutcome["Allowed"] = "allowed";
|
|
31
|
+
SubscriberNotificationTestSendRateLimitOutcome["RateLimited"] = "rate-limited";
|
|
32
|
+
// Redis is unreachable, so the limit cannot be honoured.
|
|
33
|
+
SubscriberNotificationTestSendRateLimitOutcome["CounterUnavailable"] = "counter-unavailable";
|
|
34
|
+
})(SubscriberNotificationTestSendRateLimitOutcome || (SubscriberNotificationTestSendRateLimitOutcome = {}));
|
|
35
|
+
const KEY_PREFIX = "subnotiftest:rl:";
|
|
36
|
+
/*
|
|
37
|
+
* Counter keys outlive their window by one full window, so a request landing
|
|
38
|
+
* on a boundary cannot read a key that was reclaimed mid-window.
|
|
39
|
+
*/
|
|
40
|
+
const TTL_MULTIPLIER = 2;
|
|
41
|
+
// How often the "counter unavailable" condition may be logged.
|
|
42
|
+
const COUNTER_UNAVAILABLE_LOG_INTERVAL_MS = 60 * 1000;
|
|
43
|
+
class SubscriberNotificationTestSendRateLimit {
|
|
44
|
+
// The limit in force, for tests and for operators' diagnostics.
|
|
45
|
+
static getConfig() {
|
|
46
|
+
return Object.assign({}, SubscriberNotificationTestSendRateLimit.config);
|
|
47
|
+
}
|
|
48
|
+
/*
|
|
49
|
+
* The signed-in user the request is billed to. The route sits behind
|
|
50
|
+
* UserMiddleware.requireUserAuthentication, so there always is one; if
|
|
51
|
+
* somehow there is not, every such request shares one bucket rather than
|
|
52
|
+
* each getting its own.
|
|
53
|
+
*/
|
|
54
|
+
static resolveUserKey(req) {
|
|
55
|
+
var _a;
|
|
56
|
+
const userId = (_a = req === null || req === void 0 ? void 0 : req.userAuthorization) === null || _a === void 0 ? void 0 : _a.userId;
|
|
57
|
+
if (!userId) {
|
|
58
|
+
return "anonymous";
|
|
59
|
+
}
|
|
60
|
+
const key = userId.toString().toLowerCase();
|
|
61
|
+
return ObjectID.isValidUUID(key) ? key : "invalid";
|
|
62
|
+
}
|
|
63
|
+
/*
|
|
64
|
+
* Count this request against the user and decide. The counter is
|
|
65
|
+
* incremented on every request, a rejected one included, so a caller who
|
|
66
|
+
* keeps trying keeps their window pinned rather than getting a fresh
|
|
67
|
+
* allowance for free.
|
|
68
|
+
*/
|
|
69
|
+
static async consume(data) {
|
|
70
|
+
const client = Redis.getClient();
|
|
71
|
+
if (!client || !Redis.isConnected()) {
|
|
72
|
+
return {
|
|
73
|
+
outcome: SubscriberNotificationTestSendRateLimitOutcome.CounterUnavailable,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
const config = SubscriberNotificationTestSendRateLimit.config;
|
|
77
|
+
const windowMs = config.windowSeconds * 1000;
|
|
78
|
+
const windowIndex = Math.floor(Date.now() / windowMs);
|
|
79
|
+
const counterKey = `${KEY_PREFIX}u:${data.userKey}:${windowIndex}`;
|
|
80
|
+
try {
|
|
81
|
+
const count = await client.incr(counterKey);
|
|
82
|
+
if (typeof count !== "number") {
|
|
83
|
+
throw new Error("Rate limit counter returned a non-numeric value");
|
|
84
|
+
}
|
|
85
|
+
/*
|
|
86
|
+
* The expiry is set only by the request that created the key: setting
|
|
87
|
+
* it on every increment would slide the window for as long as the
|
|
88
|
+
* requests keep coming.
|
|
89
|
+
*/
|
|
90
|
+
if (count === 1) {
|
|
91
|
+
await client.expire(counterKey, config.windowSeconds * TTL_MULTIPLIER);
|
|
92
|
+
}
|
|
93
|
+
if (count > config.perUserLimit) {
|
|
94
|
+
return {
|
|
95
|
+
outcome: SubscriberNotificationTestSendRateLimitOutcome.RateLimited,
|
|
96
|
+
retryAfterSeconds: SubscriberNotificationTestSendRateLimit.getSecondsUntilWindowEnd(config.windowSeconds),
|
|
97
|
+
isFirstRejectionInWindow: count === config.perUserLimit + 1,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
outcome: SubscriberNotificationTestSendRateLimitOutcome.Allowed,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
catch (err) {
|
|
105
|
+
if (SubscriberNotificationTestSendRateLimit.shouldLogCounterUnavailable()) {
|
|
106
|
+
logger.warn(`SubscriberNotificationTestSendRateLimit: counter failed for user ${data.userKey}`);
|
|
107
|
+
logger.warn(err);
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
outcome: SubscriberNotificationTestSendRateLimitOutcome.CounterUnavailable,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/*
|
|
115
|
+
* Express middleware. Register after UserMiddleware (the counter is per
|
|
116
|
+
* user) and before the handler, so a flood is refused before it reads a
|
|
117
|
+
* single row.
|
|
118
|
+
*/
|
|
119
|
+
static getMiddleware() {
|
|
120
|
+
return async (req, res, next) => {
|
|
121
|
+
const userKey = SubscriberNotificationTestSendRateLimit.resolveUserKey(req);
|
|
122
|
+
const decision = await SubscriberNotificationTestSendRateLimit.consume({
|
|
123
|
+
userKey: userKey,
|
|
124
|
+
});
|
|
125
|
+
if (decision.outcome ===
|
|
126
|
+
SubscriberNotificationTestSendRateLimitOutcome.RateLimited) {
|
|
127
|
+
if (decision.retryAfterSeconds) {
|
|
128
|
+
SubscriberNotificationTestSendRateLimit.setRetryAfterHeader(res, decision.retryAfterSeconds);
|
|
129
|
+
}
|
|
130
|
+
if (decision.isFirstRejectionInWindow) {
|
|
131
|
+
logger.warn(`SubscriberNotificationTestSendRateLimit: rejected test emails from user ${userKey} for the rest of this window`);
|
|
132
|
+
}
|
|
133
|
+
return Response.sendErrorResponse(req, res, new TooManyRequestsException("You have sent yourself too many test emails. Please try again later."));
|
|
134
|
+
}
|
|
135
|
+
if (decision.outcome ===
|
|
136
|
+
SubscriberNotificationTestSendRateLimitOutcome.CounterUnavailable) {
|
|
137
|
+
// Fails closed: see the note at the top of this file.
|
|
138
|
+
if (SubscriberNotificationTestSendRateLimit.shouldLogCounterUnavailable()) {
|
|
139
|
+
logger.warn("SubscriberNotificationTestSendRateLimit: rate limit counter unavailable, refusing test emails");
|
|
140
|
+
}
|
|
141
|
+
return Response.sendErrorResponse(req, res, new ServiceUnavailableException("Test emails cannot be sent right now. Please try again in a few minutes."));
|
|
142
|
+
}
|
|
143
|
+
return next();
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
/*
|
|
147
|
+
* Remaining seconds in the current fixed window, so a refused caller is
|
|
148
|
+
* told to come back when the window actually rolls. The preview limiter
|
|
149
|
+
* (SubscriberNotificationPreviewRateLimit) counts in the same fixed
|
|
150
|
+
* windows, and uses this too.
|
|
151
|
+
*/
|
|
152
|
+
static getSecondsUntilWindowEnd(windowSeconds) {
|
|
153
|
+
const windowMs = windowSeconds * 1000;
|
|
154
|
+
const msIntoWindow = Date.now() % windowMs;
|
|
155
|
+
return Math.max(1, Math.ceil((windowMs - msIntoWindow) / 1000));
|
|
156
|
+
}
|
|
157
|
+
/*
|
|
158
|
+
* A Redis outage means every request takes the unavailable path; one log
|
|
159
|
+
* line per interval makes the condition visible without burying the rest.
|
|
160
|
+
*/
|
|
161
|
+
static shouldLogCounterUnavailable() {
|
|
162
|
+
const now = Date.now();
|
|
163
|
+
if (now -
|
|
164
|
+
SubscriberNotificationTestSendRateLimit.counterUnavailableLastLoggedAt <
|
|
165
|
+
COUNTER_UNAVAILABLE_LOG_INTERVAL_MS) {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
SubscriberNotificationTestSendRateLimit.counterUnavailableLastLoggedAt =
|
|
169
|
+
now;
|
|
170
|
+
return true;
|
|
171
|
+
}
|
|
172
|
+
static setRetryAfterHeader(res, retryAfterSeconds) {
|
|
173
|
+
const setHeader = res["setHeader"];
|
|
174
|
+
if (typeof setHeader === "function") {
|
|
175
|
+
setHeader.call(res, "Retry-After", String(retryAfterSeconds));
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
/*
|
|
180
|
+
* Ten test emails a quarter of an hour: someone checking each status
|
|
181
|
+
* page's email in turn, or trying a template change a few times, is
|
|
182
|
+
* nowhere near it.
|
|
183
|
+
*/
|
|
184
|
+
SubscriberNotificationTestSendRateLimit.config = {
|
|
185
|
+
windowSeconds: 15 * 60,
|
|
186
|
+
perUserLimit: 10,
|
|
187
|
+
};
|
|
188
|
+
SubscriberNotificationTestSendRateLimit.counterUnavailableLastLoggedAt = 0;
|
|
189
|
+
export default SubscriberNotificationTestSendRateLimit;
|
|
190
|
+
//# sourceMappingURL=SubscriberNotificationTestSendRateLimit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SubscriberNotificationTestSendRateLimit.js","sourceRoot":"","sources":["../../../../Server/Middleware/SubscriberNotificationTestSendRateLimit.ts"],"names":[],"mappings":"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"}
|
|
@@ -2677,6 +2677,44 @@ class DatabaseService extends BaseService {
|
|
|
2677
2677
|
* caller of this path gets it, including ones not written yet.
|
|
2678
2678
|
*/
|
|
2679
2679
|
async updateColumnsByIdWithoutHooks(input) {
|
|
2680
|
+
const statement = this.buildColumnsByIdUpdateStatement(input, "updateColumnsByIdWithoutHooks");
|
|
2681
|
+
if (!statement) {
|
|
2682
|
+
return;
|
|
2683
|
+
}
|
|
2684
|
+
const sql = `UPDATE "${statement.tableName}" SET ${statement.setSql} WHERE ${statement.whereSql}`;
|
|
2685
|
+
await this.getRepository().manager.query(sql, statement.params);
|
|
2686
|
+
}
|
|
2687
|
+
/*
|
|
2688
|
+
* The same single-statement, hook-free, no-version-bump write as
|
|
2689
|
+
* `updateColumnsByIdWithoutHooks` with its `expectedData` guard, which
|
|
2690
|
+
* also says whether it happened: true when the row matched every expected
|
|
2691
|
+
* value and was written, false when another writer had changed it first
|
|
2692
|
+
* (or it no longer exists).
|
|
2693
|
+
*
|
|
2694
|
+
* This is what lets two workers race for one row and have exactly one of
|
|
2695
|
+
* them win - a job claiming a Pending notification by moving it to
|
|
2696
|
+
* InProgress, say, where both would otherwise send it. The check and the
|
|
2697
|
+
* write are one statement, so there is no window between them.
|
|
2698
|
+
*
|
|
2699
|
+
* The UPDATE sits in a CTE so the statement is a SELECT of the rows it
|
|
2700
|
+
* wrote (see updateColumnsByIdIfUnlockedWithoutHooks for why a bare
|
|
2701
|
+
* UPDATE ... RETURNING cannot tell the two cases apart through TypeORM).
|
|
2702
|
+
*/
|
|
2703
|
+
async compareAndSetColumnsByIdWithoutHooks(input) {
|
|
2704
|
+
const statement = this.buildColumnsByIdUpdateStatement(input, "compareAndSetColumnsByIdWithoutHooks");
|
|
2705
|
+
if (!statement) {
|
|
2706
|
+
return false;
|
|
2707
|
+
}
|
|
2708
|
+
const sql = `WITH "updated" AS (UPDATE "${statement.tableName}" SET ${statement.setSql} WHERE ${statement.whereSql} RETURNING "${statement.primaryColumnName}") SELECT "${statement.primaryColumnName}" FROM "updated"`;
|
|
2709
|
+
const result = await this.getRepository().manager.query(sql, statement.params);
|
|
2710
|
+
return Array.isArray(result) && result.length > 0;
|
|
2711
|
+
}
|
|
2712
|
+
/*
|
|
2713
|
+
* The SET and WHERE clauses of a hook-free write to one row by id, with
|
|
2714
|
+
* every value bound as a parameter. Null when there is nothing to set.
|
|
2715
|
+
* `methodName` is the public method the errors are reported under.
|
|
2716
|
+
*/
|
|
2717
|
+
buildColumnsByIdUpdateStatement(input, methodName) {
|
|
2680
2718
|
var _a;
|
|
2681
2719
|
if (!input.id) {
|
|
2682
2720
|
throw new BadDataException("id is required");
|
|
@@ -2695,7 +2733,7 @@ class DatabaseService extends BaseService {
|
|
|
2695
2733
|
for (const [propertyName, value] of Object.entries(data)) {
|
|
2696
2734
|
const column = metadata.findColumnWithPropertyName(propertyName);
|
|
2697
2735
|
if (!column) {
|
|
2698
|
-
throw new BadDataException(
|
|
2736
|
+
throw new BadDataException(`${methodName}: unknown column "${propertyName}" on "${metadata.tableName}"`);
|
|
2699
2737
|
}
|
|
2700
2738
|
/*
|
|
2701
2739
|
* PartialEntity permits `() => string` SQL-expression values, but this
|
|
@@ -2704,7 +2742,7 @@ class DatabaseService extends BaseService {
|
|
|
2704
2742
|
* loudly rather than binding a function object.
|
|
2705
2743
|
*/
|
|
2706
2744
|
if (typeof value === "function") {
|
|
2707
|
-
throw new BadDataException(
|
|
2745
|
+
throw new BadDataException(`${methodName}: SQL-expression values are not supported (column "${propertyName}"); pass a literal value.`);
|
|
2708
2746
|
}
|
|
2709
2747
|
/*
|
|
2710
2748
|
* Run the value through the driver's persist path so column
|
|
@@ -2717,7 +2755,7 @@ class DatabaseService extends BaseService {
|
|
|
2717
2755
|
setClauses.push(`"${column.databaseName}" = $${params.length}`);
|
|
2718
2756
|
}
|
|
2719
2757
|
if (setClauses.length === 0) {
|
|
2720
|
-
return;
|
|
2758
|
+
return null;
|
|
2721
2759
|
}
|
|
2722
2760
|
// The raw path has no entity machinery to touch updateDate — do it here.
|
|
2723
2761
|
if (metadata.updateDateColumn && !input.skipUpdateDateColumn) {
|
|
@@ -2731,16 +2769,21 @@ class DatabaseService extends BaseService {
|
|
|
2731
2769
|
for (const [propertyName, value] of Object.entries((input.expectedData || {}))) {
|
|
2732
2770
|
const column = metadata.findColumnWithPropertyName(propertyName);
|
|
2733
2771
|
if (!column) {
|
|
2734
|
-
throw new BadDataException(
|
|
2772
|
+
throw new BadDataException(`${methodName}: unknown expected column "${propertyName}" on "${metadata.tableName}"`);
|
|
2735
2773
|
}
|
|
2736
2774
|
if (typeof value === "function") {
|
|
2737
|
-
throw new BadDataException(
|
|
2775
|
+
throw new BadDataException(`${methodName}: SQL-expression expected values are not supported (column "${propertyName}"); pass a literal value.`);
|
|
2738
2776
|
}
|
|
2739
2777
|
params.push(driver.preparePersistentValue(value, column));
|
|
2740
2778
|
whereClauses.push(`"${column.databaseName}" IS NOT DISTINCT FROM $${params.length}`);
|
|
2741
2779
|
}
|
|
2742
|
-
|
|
2743
|
-
|
|
2780
|
+
return {
|
|
2781
|
+
tableName: metadata.tableName,
|
|
2782
|
+
primaryColumnName: primaryColumnName,
|
|
2783
|
+
setSql: setClauses.join(", "),
|
|
2784
|
+
whereSql: whereClauses.join(" AND "),
|
|
2785
|
+
params: params,
|
|
2786
|
+
};
|
|
2744
2787
|
}
|
|
2745
2788
|
/*
|
|
2746
2789
|
* Same single-statement, hook-free, no-version-bump write as
|
|
@@ -3122,6 +3165,12 @@ __decorate([
|
|
|
3122
3165
|
__metadata("design:paramtypes", [Object]),
|
|
3123
3166
|
__metadata("design:returntype", Promise)
|
|
3124
3167
|
], DatabaseService.prototype, "updateColumnsByIdWithoutHooks", null);
|
|
3168
|
+
__decorate([
|
|
3169
|
+
CaptureSpan(),
|
|
3170
|
+
__metadata("design:type", Function),
|
|
3171
|
+
__metadata("design:paramtypes", [Object]),
|
|
3172
|
+
__metadata("design:returntype", Promise)
|
|
3173
|
+
], DatabaseService.prototype, "compareAndSetColumnsByIdWithoutHooks", null);
|
|
3125
3174
|
__decorate([
|
|
3126
3175
|
CaptureSpan(),
|
|
3127
3176
|
__metadata("design:type", Function),
|