@oneuptime/common 12.0.13 → 12.0.14
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/OnCallDutyPolicySchedule.ts +14 -0
- package/Models/DatabaseModels/UserCall.ts +94 -3
- package/Models/DatabaseModels/UserEmail.ts +94 -3
- package/Models/DatabaseModels/UserIncomingCallNumber.ts +94 -3
- package/Models/DatabaseModels/UserPush.ts +37 -0
- package/Models/DatabaseModels/UserSMS.ts +94 -3
- package/Models/DatabaseModels/UserWhatsApp.ts +93 -2
- package/Server/API/BaseAPI.ts +79 -14
- package/Server/API/UserCallAPI.ts +53 -45
- package/Server/API/UserEmailAPI.ts +53 -44
- package/Server/API/UserIncomingCallNumberAPI.ts +48 -38
- package/Server/API/UserNotificationMethodAdminAPI.ts +481 -0
- package/Server/API/UserPushAPI.ts +126 -2
- package/Server/API/UserSmsAPI.ts +53 -44
- package/Server/API/UserWhatsAppAPI.ts +53 -50
- package/Server/Infrastructure/Postgres/SchemaMigrations/1787142779538-MigrationName.ts +154 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1787156982416-MigrationName.ts +17 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1787700000000-FixTotpOtpUrlAlgorithm.ts +45 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
- package/Server/Middleware/VerificationCodeRateLimit.ts +586 -0
- package/Server/Services/AnalyticsDatabaseService.ts +169 -0
- package/Server/Services/DatabaseService.ts +101 -0
- package/Server/Services/LogAggregationService.ts +5 -0
- package/Server/Services/PushNotificationService.ts +127 -12
- package/Server/Services/TeamMemberService.ts +53 -13
- package/Server/Services/UserCallService.ts +55 -24
- package/Server/Services/UserEmailService.ts +83 -17
- package/Server/Services/UserIncomingCallNumberService.ts +49 -85
- package/Server/Services/UserNotificationMethodAdminService.ts +1527 -0
- package/Server/Services/UserNotificationRuleService.ts +26 -0
- package/Server/Services/UserPushService.ts +89 -0
- package/Server/Services/UserSmsService.ts +50 -17
- package/Server/Services/UserWhatsAppService.ts +48 -15
- package/Server/Types/Database/QueryHelper.ts +30 -0
- package/Server/Utils/AnalyticsDatabase/QuerySettingsHelper.ts +59 -0
- package/Server/Utils/ChannelVerification.ts +510 -0
- package/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.ts +13 -16
- package/Server/Utils/Monitor/MonitorAlert.ts +24 -21
- package/Server/Utils/Monitor/MonitorIncident.ts +21 -18
- package/Server/Utils/Monitor/MonitorResourceContext.ts +107 -0
- package/Server/Utils/Monitor/MonitorStepResourceIdentity.ts +442 -0
- package/Server/Utils/Monitor/SeriesResourceLabels.ts +3 -3
- package/Server/Utils/Monitor/SeriesResourceLinker.ts +96 -28
- package/Server/Utils/TotpAuth.ts +137 -9
- package/Server/Utils/UserRegistrationToken.ts +182 -0
- package/Server/Utils/VerificationCode.ts +134 -0
- package/Tests/App/Dashboard/AdminNotificationRulesPage.test.tsx +173 -94
- package/Tests/App/Dashboard/AdminUserNotificationMethodsPage.test.tsx +1151 -0
- package/Tests/App/Dashboard/AdminUserOnCallPages.test.tsx +905 -0
- package/Tests/App/Dashboard/DashboardCommandPalette.test.tsx +338 -0
- package/Tests/App/Dashboard/InvestigationPanel.test.tsx +1 -1
- package/Tests/App/Dashboard/MonitorTypePicker.test.tsx +28 -0
- package/Tests/Models/UserPushCriticalAlertColumn.test.ts +172 -0
- package/Tests/Server/API/BaseAPIGetListParallel.test.ts +519 -0
- package/Tests/Server/API/NotificationChannelVerificationAPI.test.ts +543 -0
- package/Tests/Server/API/UserIncomingCallNumberApi.test.ts +108 -18
- package/Tests/Server/API/UserNotificationMethodAdminAPI.test.ts +963 -0
- package/Tests/Server/API/UserPushCriticalAlertsApi.test.ts +114 -0
- package/Tests/Server/API/UserSmsApi.test.ts +107 -14
- package/Tests/Server/API/UserTotpAuthAPI.test.ts +427 -0
- package/Tests/Server/Infrastructure/Postgres/FixTotpOtpUrlAlgorithmMigration.test.ts +315 -0
- package/Tests/Server/Middleware/VerificationCodeRateLimit.test.ts +775 -0
- package/Tests/Server/Services/AddNetworkDeviceReachabilityColumnsMigration.test.ts +10 -62
- package/Tests/Server/Services/AnalyticsDatabasePaginationStability.test.ts +33 -13
- package/Tests/Server/Services/AnalyticsDatabaseSortKeyBoundary.test.ts +658 -0
- package/Tests/Server/Services/CriticalOnCallAlertDelivery.test.ts +458 -0
- package/Tests/Server/Services/CriticalPushAlertPayload.test.ts +301 -0
- package/Tests/Server/Services/DatabaseServiceAtomicIncrement.test.ts +143 -0
- package/Tests/Server/Services/DeliverNotificationForRuleExtraction.test.ts +1 -0
- package/Tests/Server/Services/LogAggregationScanMemory.test.ts +421 -0
- package/Tests/Server/Services/LogAggregationService.test.ts +2 -2
- package/Tests/Server/Services/NotificationChannelCodeIssuance.test.ts +401 -0
- package/Tests/Server/Services/PushNotificationDeliveryOptions.test.ts +204 -0
- package/Tests/Server/Services/TeamMemberAutoAcceptInvitation.test.ts +21 -1
- package/Tests/Server/Services/TeamMemberInviteRegistrationToken.test.ts +290 -0
- package/Tests/Server/Services/UserNotificationMethodAdminService.test.ts +948 -0
- package/Tests/Server/Services/UserNotificationRuleExecuteItem.test.ts +1 -0
- package/Tests/Server/Services/UserPushCriticalAlertToggle.test.ts +255 -0
- package/Tests/Server/Services/UserTotpAuthEnrolment.test.ts +218 -0
- package/Tests/Server/TestingUtils/AuthenticatorApp.ts +248 -0
- package/Tests/Server/Types/Database/Permissions/NotificationChannelVerificationColumns.test.ts +135 -0
- package/Tests/Server/Types/Database/Permissions/OnCallScheduleRelationSelect.test.ts +504 -0
- package/Tests/Server/Types/Database/QueryHelperFindWithSameTextAnyOf.test.ts +91 -0
- package/Tests/Server/Types/Workflow/Components/JsonToText.test.ts +384 -0
- package/Tests/Server/Types/Workflow/Components/MergeJson.test.ts +403 -0
- package/Tests/Server/Utils/Browser.test.ts +162 -0
- package/Tests/Server/Utils/ChannelVerification.test.ts +689 -0
- package/Tests/Server/Utils/Express.test.ts +371 -0
- package/Tests/Server/Utils/Monitor/Criteria/CustomCodeMonitorCriteria.test.ts +707 -0
- package/Tests/Server/Utils/Monitor/Criteria/DnsMonitorCriteria.test.ts +698 -0
- package/Tests/Server/Utils/Monitor/Criteria/IncomingEmailBodyCriteria.test.ts +243 -0
- package/Tests/Server/Utils/Monitor/Criteria/IncomingRequestBodyCriteria.test.ts +278 -0
- package/Tests/Server/Utils/Monitor/MonitorAlertResourceLinking.test.ts +160 -20
- package/Tests/Server/Utils/Monitor/MonitorDependencySuppressionCreatorSkip.test.ts +13 -8
- package/Tests/Server/Utils/Monitor/MonitorIncidentResourceLinking.test.ts +162 -18
- package/Tests/Server/Utils/Monitor/MonitorResourceContext.test.ts +349 -0
- package/Tests/Server/Utils/Monitor/MonitorStepResourceIdentity.test.ts +690 -0
- package/Tests/Server/Utils/Monitor/MonitorSummaryPersistence.test.ts +7 -2
- package/Tests/Server/Utils/Monitor/SeriesResourceLinker.test.ts +92 -18
- package/Tests/Server/Utils/PushNotificationUtilCreators.test.ts +267 -0
- package/Tests/Server/Utils/Telemetry/OneuptimeLabel.test.ts +439 -0
- package/Tests/Server/Utils/TotpAuth.test.ts +719 -0
- package/Tests/Server/Utils/UserRegistrationToken.test.ts +322 -0
- package/Tests/Server/Utils/VerificationCode.test.ts +296 -0
- package/Tests/Types/AutoRemediation/AutoRemediationSuggestionStatus.test.ts +192 -0
- package/Tests/Types/Call/CallRequest.test.ts +189 -0
- package/Tests/Types/Dashboard/DashboardSize.test.ts +226 -0
- package/Tests/Types/Incident/IncidentSlaStatus.test.ts +191 -0
- package/Tests/Types/Metrics/MetricDashboardMetricType.test.ts +278 -0
- package/Tests/Types/Metrics/MetricPipelineRuleType.test.ts +517 -0
- package/Tests/Types/Monitor/IncomingMonitorDefaultCriteria.test.ts +470 -0
- package/Tests/Types/Monitor/MonitorCriteriaInstance.test.ts +6 -4
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCatalog.test.ts +262 -5
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCoverage.test.ts +1 -1
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +1 -1
- package/Tests/Types/Monitor/ServiceAlertTemplates.test.ts +905 -0
- package/Tests/Types/Service/ServiceLanguage.test.ts +255 -0
- package/Tests/Types/TextRandomGeneration.test.ts +211 -0
- package/Tests/UI/Components/Button.test.tsx +175 -1
- package/Tests/UI/Components/CodeBlockLanguages.test.tsx +236 -0
- package/Tests/UI/Components/CommandPalette/CommandPalette.test.tsx +568 -0
- package/Tests/UI/Components/CommandPalette/CommandPaletteKeyboard.test.tsx +239 -0
- package/Tests/UI/Components/CommandPalette/CommandPaletteProviders.test.tsx +400 -0
- package/Tests/UI/Components/CommandPalette/PaletteFilter.test.ts +234 -0
- package/Tests/UI/Components/CommandPalette/RecentCommands.test.ts +97 -0
- package/Tests/UI/Components/CountModelSideMenuItemGuard.test.tsx +198 -0
- package/Tests/UI/Components/FeedItemSafeMode.test.tsx +1 -1
- package/Tests/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.test.ts +267 -0
- package/Tests/UI/Components/List.test.tsx +9 -2
- package/Tests/UI/Components/ListLoadingStates.test.tsx +173 -0
- package/Tests/UI/Components/MarkdownLazy.test.tsx +113 -0
- package/Tests/UI/Components/MarkdownMermaidRetry.test.tsx +110 -0
- package/Tests/UI/Components/ModelTable/useCustomFieldColumns.test.tsx +8 -0
- package/Tests/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.test.ts +692 -0
- package/Tests/UI/Components/MoreMenuMotion.test.tsx +118 -0
- package/Tests/UI/Components/NavBarCommandKGating.test.tsx +178 -0
- package/Tests/UI/Components/OrderedStatesList.test.tsx +19 -2
- package/Tests/UI/Components/SideOverMotion.test.tsx +109 -0
- package/Tests/UI/Components/Skeleton.test.tsx +71 -0
- package/Tests/UI/Components/TableLoadingStates.test.tsx +279 -0
- package/Tests/UI/Components/Tabs.test.tsx +24 -0
- package/Tests/UI/Components/Toast.test.tsx +130 -7
- package/Tests/UI/Components/ToastStacking.test.tsx +198 -0
- package/Tests/UI/Utils/Dropdown.test.ts +423 -0
- package/Tests/UI/Utils/ModelAPITenantHeader.test.ts +122 -0
- package/Tests/UI/Utils/ModelListCache.test.ts +338 -0
- package/Tests/UI/Utils/ProjectListCacheInvalidation.test.ts +225 -0
- package/Tests/Utils/API.test.ts +16 -2
- package/Tests/Utils/Dashboard/Components/DashboardKubernetesResourceListShared.test.ts +347 -0
- package/Tests/Utils/Dashboard/Components/DashboardListSharedArgs.test.ts +259 -0
- package/Tests/Utils/Dashboard/Components/DashboardMonitorListComponent.test.ts +466 -0
- package/Tests/Utils/Rum/UrlScrubberSegments.test.ts +362 -0
- package/Types/Email/EmailTemplateType.ts +1 -0
- package/Types/Monitor/MonitorCriteriaInstance.ts +41 -20
- package/Types/Monitor/Recommendation/MonitorRecommendationCatalog.ts +131 -8
- package/Types/Monitor/Recommendation/MonitorRecommendationTypes.ts +48 -8
- package/Types/Monitor/ServiceAlertTemplates.ts +1352 -0
- package/Types/Permission.ts +35 -0
- package/Types/PushNotification/AndroidNotificationChannel.ts +26 -0
- package/Types/PushNotification/PushNotificationMessage.ts +15 -0
- package/Types/PushNotification/PushNotificationRequest.ts +8 -16
- package/Types/Service/ServiceLanguage.ts +144 -0
- package/Types/Text.ts +111 -19
- package/UI/Components/Button/Button.tsx +27 -14
- package/UI/Components/CodeBlock/CodeBlock.tsx +54 -7
- package/UI/Components/CodeBlock/LanguageRegistry.ts +103 -0
- package/UI/Components/CommandPalette/CommandPalette.tsx +790 -0
- package/UI/Components/CommandPalette/PaletteFilter.ts +196 -0
- package/UI/Components/CommandPalette/PaletteRow.tsx +173 -0
- package/UI/Components/CommandPalette/RecentCommands.ts +57 -0
- package/UI/Components/CommandPalette/Types.ts +49 -0
- package/UI/Components/CommandPalette/UseProviderSearch.ts +129 -0
- package/UI/Components/Dropdown/Dropdown.tsx +6 -1
- package/UI/Components/Feed/FeedItem.tsx +1 -1
- package/UI/Components/List/List.tsx +37 -5
- package/UI/Components/List/ListSkeleton.tsx +54 -0
- package/UI/Components/Markdown.tsx/LazyMarkdownViewer.tsx +6 -1
- package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +71 -26
- package/UI/Components/Modal/Modal.tsx +2 -2
- package/UI/Components/ModelTable/BaseModelTable.tsx +1 -1
- package/UI/Components/ModelTable/useCustomFieldColumns.ts +11 -5
- package/UI/Components/MoreMenu/MoreMenu.tsx +39 -1
- package/UI/Components/Navbar/NavBar.tsx +14 -1
- package/UI/Components/OrderedStatesList/OrderedStatesList.tsx +50 -5
- package/UI/Components/SideMenu/CountModelSideMenuItem.tsx +40 -1
- package/UI/Components/SideOver/SideOver.tsx +37 -2
- package/UI/Components/Skeleton/Skeleton.tsx +53 -0
- package/UI/Components/Table/Table.tsx +74 -44
- package/UI/Components/Table/TableSkeletonRows.tsx +141 -0
- package/UI/Components/Tabs/Tab.tsx +1 -1
- package/UI/Components/Toast/Toast.tsx +118 -53
- package/UI/Components/Toast/ToastInit.tsx +82 -32
- package/UI/Styles/Theme.css +40 -0
- package/UI/Utils/ModelAPI/ModelAPI.ts +20 -10
- package/UI/Utils/ModelListCache.ts +188 -0
- package/UI/Utils/Project.ts +29 -0
- package/Utils/API.ts +6 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js +14 -0
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserCall.js +101 -3
- package/build/dist/Models/DatabaseModels/UserCall.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserEmail.js +101 -3
- package/build/dist/Models/DatabaseModels/UserEmail.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserIncomingCallNumber.js +101 -3
- package/build/dist/Models/DatabaseModels/UserIncomingCallNumber.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserPush.js +38 -0
- package/build/dist/Models/DatabaseModels/UserPush.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserSMS.js +101 -3
- package/build/dist/Models/DatabaseModels/UserSMS.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserWhatsApp.js +100 -2
- package/build/dist/Models/DatabaseModels/UserWhatsApp.js.map +1 -1
- package/build/dist/Server/API/BaseAPI.js +69 -13
- package/build/dist/Server/API/BaseAPI.js.map +1 -1
- package/build/dist/Server/API/UserCallAPI.js +42 -38
- package/build/dist/Server/API/UserCallAPI.js.map +1 -1
- package/build/dist/Server/API/UserEmailAPI.js +42 -38
- package/build/dist/Server/API/UserEmailAPI.js.map +1 -1
- package/build/dist/Server/API/UserIncomingCallNumberAPI.js +37 -32
- package/build/dist/Server/API/UserIncomingCallNumberAPI.js.map +1 -1
- package/build/dist/Server/API/UserNotificationMethodAdminAPI.js +341 -0
- package/build/dist/Server/API/UserNotificationMethodAdminAPI.js.map +1 -0
- package/build/dist/Server/API/UserPushAPI.js +95 -2
- package/build/dist/Server/API/UserPushAPI.js.map +1 -1
- package/build/dist/Server/API/UserSmsAPI.js +42 -38
- package/build/dist/Server/API/UserSmsAPI.js.map +1 -1
- package/build/dist/Server/API/UserWhatsAppAPI.js +42 -40
- package/build/dist/Server/API/UserWhatsAppAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787142779538-MigrationName.js +89 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787142779538-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787156982416-MigrationName.js +12 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787156982416-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787700000000-FixTotpOtpUrlAlgorithm.js +40 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787700000000-FixTotpOtpUrlAlgorithm.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Middleware/VerificationCodeRateLimit.js +393 -0
- package/build/dist/Server/Middleware/VerificationCodeRateLimit.js.map +1 -0
- package/build/dist/Server/Services/AnalyticsDatabaseService.js +136 -0
- package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +74 -0
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/LogAggregationService.js +5 -0
- package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
- package/build/dist/Server/Services/PushNotificationService.js +69 -30
- package/build/dist/Server/Services/PushNotificationService.js.map +1 -1
- package/build/dist/Server/Services/TeamMemberService.js +43 -7
- package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
- package/build/dist/Server/Services/UserCallService.js +54 -22
- package/build/dist/Server/Services/UserCallService.js.map +1 -1
- package/build/dist/Server/Services/UserEmailService.js +78 -17
- package/build/dist/Server/Services/UserEmailService.js.map +1 -1
- package/build/dist/Server/Services/UserIncomingCallNumberService.js +45 -74
- package/build/dist/Server/Services/UserIncomingCallNumberService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationMethodAdminService.js +1117 -0
- package/build/dist/Server/Services/UserNotificationMethodAdminService.js.map +1 -0
- package/build/dist/Server/Services/UserNotificationRuleService.js +20 -0
- package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Services/UserPushService.js +77 -0
- package/build/dist/Server/Services/UserPushService.js.map +1 -1
- package/build/dist/Server/Services/UserSmsService.js +50 -17
- package/build/dist/Server/Services/UserSmsService.js.map +1 -1
- package/build/dist/Server/Services/UserWhatsAppService.js +48 -15
- package/build/dist/Server/Services/UserWhatsAppService.js.map +1 -1
- package/build/dist/Server/Types/Database/QueryHelper.js +27 -0
- package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/QuerySettingsHelper.js +46 -0
- package/build/dist/Server/Utils/AnalyticsDatabase/QuerySettingsHelper.js.map +1 -1
- package/build/dist/Server/Utils/ChannelVerification.js +348 -0
- package/build/dist/Server/Utils/ChannelVerification.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.js +13 -12
- package/build/dist/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js +20 -17
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js +17 -14
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorResourceContext.js +95 -0
- package/build/dist/Server/Utils/Monitor/MonitorResourceContext.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorStepResourceIdentity.js +313 -0
- package/build/dist/Server/Utils/Monitor/MonitorStepResourceIdentity.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +3 -3
- package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js +67 -26
- package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js.map +1 -1
- package/build/dist/Server/Utils/TotpAuth.js +127 -8
- package/build/dist/Server/Utils/TotpAuth.js.map +1 -1
- package/build/dist/Server/Utils/UserRegistrationToken.js +170 -0
- package/build/dist/Server/Utils/UserRegistrationToken.js.map +1 -0
- package/build/dist/Server/Utils/VerificationCode.js +120 -0
- package/build/dist/Server/Utils/VerificationCode.js.map +1 -0
- package/build/dist/Types/Email/EmailTemplateType.js +1 -0
- package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +42 -21
- package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js +77 -5
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js +18 -6
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js.map +1 -1
- package/build/dist/Types/Monitor/ServiceAlertTemplates.js +1028 -0
- package/build/dist/Types/Monitor/ServiceAlertTemplates.js.map +1 -0
- package/build/dist/Types/Permission.js +33 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/PushNotification/AndroidNotificationChannel.js +27 -0
- package/build/dist/Types/PushNotification/AndroidNotificationChannel.js.map +1 -0
- package/build/dist/Types/Service/ServiceLanguage.js +96 -0
- package/build/dist/Types/Service/ServiceLanguage.js.map +1 -0
- package/build/dist/Types/Text.js +82 -17
- package/build/dist/Types/Text.js.map +1 -1
- package/build/dist/UI/Components/Button/Button.js +22 -14
- package/build/dist/UI/Components/Button/Button.js.map +1 -1
- package/build/dist/UI/Components/CodeBlock/CodeBlock.js +35 -3
- package/build/dist/UI/Components/CodeBlock/CodeBlock.js.map +1 -1
- package/build/dist/UI/Components/CodeBlock/LanguageRegistry.js +57 -0
- package/build/dist/UI/Components/CodeBlock/LanguageRegistry.js.map +1 -0
- package/build/dist/UI/Components/CommandPalette/CommandPalette.js +439 -0
- package/build/dist/UI/Components/CommandPalette/CommandPalette.js.map +1 -0
- package/build/dist/UI/Components/CommandPalette/PaletteFilter.js +135 -0
- package/build/dist/UI/Components/CommandPalette/PaletteFilter.js.map +1 -0
- package/build/dist/UI/Components/CommandPalette/PaletteRow.js +83 -0
- package/build/dist/UI/Components/CommandPalette/PaletteRow.js.map +1 -0
- package/build/dist/UI/Components/CommandPalette/RecentCommands.js +47 -0
- package/build/dist/UI/Components/CommandPalette/RecentCommands.js.map +1 -0
- package/build/dist/UI/Components/CommandPalette/Types.js +2 -0
- package/build/dist/UI/Components/CommandPalette/Types.js.map +1 -0
- package/build/dist/UI/Components/CommandPalette/UseProviderSearch.js +88 -0
- package/build/dist/UI/Components/CommandPalette/UseProviderSearch.js.map +1 -0
- package/build/dist/UI/Components/Dropdown/Dropdown.js +6 -1
- package/build/dist/UI/Components/Dropdown/Dropdown.js.map +1 -1
- package/build/dist/UI/Components/Feed/FeedItem.js +1 -1
- package/build/dist/UI/Components/Feed/FeedItem.js.map +1 -1
- package/build/dist/UI/Components/List/List.js +19 -5
- package/build/dist/UI/Components/List/List.js.map +1 -1
- package/build/dist/UI/Components/List/ListSkeleton.js +21 -0
- package/build/dist/UI/Components/List/ListSkeleton.js.map +1 -0
- package/build/dist/UI/Components/Markdown.tsx/LazyMarkdownViewer.js.map +1 -1
- package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +52 -25
- package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
- package/build/dist/UI/Components/Modal/Modal.js +2 -2
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +1 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/useCustomFieldColumns.js +9 -2
- package/build/dist/UI/Components/ModelTable/useCustomFieldColumns.js.map +1 -1
- package/build/dist/UI/Components/MoreMenu/MoreMenu.js +32 -1
- package/build/dist/UI/Components/MoreMenu/MoreMenu.js.map +1 -1
- package/build/dist/UI/Components/Navbar/NavBar.js +5 -1
- package/build/dist/UI/Components/Navbar/NavBar.js.map +1 -1
- package/build/dist/UI/Components/OrderedStatesList/OrderedStatesList.js +29 -5
- package/build/dist/UI/Components/OrderedStatesList/OrderedStatesList.js.map +1 -1
- package/build/dist/UI/Components/SideMenu/CountModelSideMenuItem.js +23 -1
- package/build/dist/UI/Components/SideMenu/CountModelSideMenuItem.js.map +1 -1
- package/build/dist/UI/Components/SideOver/SideOver.js +23 -2
- package/build/dist/UI/Components/SideOver/SideOver.js.map +1 -1
- package/build/dist/UI/Components/Skeleton/Skeleton.js +23 -0
- package/build/dist/UI/Components/Skeleton/Skeleton.js.map +1 -0
- package/build/dist/UI/Components/Table/Table.js +35 -24
- package/build/dist/UI/Components/Table/Table.js.map +1 -1
- package/build/dist/UI/Components/Table/TableSkeletonRows.js +52 -0
- package/build/dist/UI/Components/Table/TableSkeletonRows.js.map +1 -0
- package/build/dist/UI/Components/Tabs/Tab.js +1 -1
- package/build/dist/UI/Components/Tabs/Tab.js.map +1 -1
- package/build/dist/UI/Components/Toast/Toast.js +77 -23
- package/build/dist/UI/Components/Toast/Toast.js.map +1 -1
- package/build/dist/UI/Components/Toast/ToastInit.js +37 -15
- package/build/dist/UI/Components/Toast/ToastInit.js.map +1 -1
- package/build/dist/UI/Utils/ModelAPI/ModelAPI.js +18 -9
- package/build/dist/UI/Utils/ModelAPI/ModelAPI.js.map +1 -1
- package/build/dist/UI/Utils/ModelListCache.js +126 -0
- package/build/dist/UI/Utils/ModelListCache.js.map +1 -0
- package/build/dist/UI/Utils/Project.js +24 -1
- package/build/dist/UI/Utils/Project.js.map +1 -1
- package/build/dist/Utils/API.js +6 -1
- package/build/dist/Utils/API.js.map +1 -1
- package/jest.config.json +1 -1
- package/package.json +2 -3
- package/Server/Utils/Monitor/MonitorClusterContext.ts +0 -182
- package/Tests/__mocks__/otpauth.js +0 -30
- package/build/dist/Server/Utils/Monitor/MonitorClusterContext.js +0 -141
- package/build/dist/Server/Utils/Monitor/MonitorClusterContext.js.map +0 -1
|
@@ -1,18 +1,36 @@
|
|
|
1
1
|
import UserMiddleware from "../Middleware/UserAuthorization";
|
|
2
|
+
import VerificationCodeRateLimit, { VerificationCodeRateLimitBucket, } from "../Middleware/VerificationCodeRateLimit";
|
|
2
3
|
import UserEmailService from "../Services/UserEmailService";
|
|
3
|
-
import
|
|
4
|
+
import ChannelVerification, { ChannelVerificationOutcome, } from "../Utils/ChannelVerification";
|
|
4
5
|
import Response from "../Utils/Response";
|
|
5
|
-
import logger, { getLogAttributesFromRequest } from "../Utils/Logger";
|
|
6
6
|
import BaseAPI from "./BaseAPI";
|
|
7
7
|
import BadDataException from "../../Types/Exception/BadDataException";
|
|
8
8
|
import ObjectID from "../../Types/ObjectID";
|
|
9
9
|
import UserEmail from "../../Models/DatabaseModels/UserEmail";
|
|
10
|
+
import UserNotificationRuleService from "../Services/UserNotificationRuleService";
|
|
11
|
+
import logger, { getLogAttributesFromRequest } from "../Utils/Logger";
|
|
12
|
+
/*
|
|
13
|
+
* The verify and resend routes for this notification channel.
|
|
14
|
+
*
|
|
15
|
+
* Neither the checking of a submitted code nor the issuing of a new one lives
|
|
16
|
+
* here, on purpose. The state machine is shared by all five channels
|
|
17
|
+
* (Common/Server/Utils/ChannelVerification.ts) so that a control added for one
|
|
18
|
+
* of them cannot quietly go missing on another — which is exactly what went
|
|
19
|
+
* wrong before: five hand-written copies of "compare the column, set
|
|
20
|
+
* isVerified", none of which expired the code, counted attempts, or refused a
|
|
21
|
+
* caller running the comparison a million times against somebody else's phone
|
|
22
|
+
* number.
|
|
23
|
+
*
|
|
24
|
+
* What is left here is the HTTP shape: reject malformed bodies, run the rate
|
|
25
|
+
* limiter before anything costs a database read, and turn the outcome into a
|
|
26
|
+
* response.
|
|
27
|
+
*/
|
|
10
28
|
export default class UserEmailAPI extends BaseAPI {
|
|
11
29
|
constructor() {
|
|
12
30
|
var _a, _b;
|
|
13
31
|
super(UserEmail, UserEmailService);
|
|
14
|
-
this.router.post(`${(_a = new this.entityType().getCrudApiPath()) === null || _a === void 0 ? void 0 : _a.toString()}/verify`, UserMiddleware.getUserMiddleware, async (req, res, next) => {
|
|
15
|
-
var _a
|
|
32
|
+
this.router.post(`${(_a = new this.entityType().getCrudApiPath()) === null || _a === void 0 ? void 0 : _a.toString()}/verify`, UserMiddleware.getUserMiddleware, VerificationCodeRateLimit.getMiddleware(VerificationCodeRateLimitBucket.Verify), async (req, res, next) => {
|
|
33
|
+
var _a;
|
|
16
34
|
try {
|
|
17
35
|
req = req;
|
|
18
36
|
if (!req.body.itemId) {
|
|
@@ -21,45 +39,26 @@ export default class UserEmailAPI extends BaseAPI {
|
|
|
21
39
|
if (!req.body.code) {
|
|
22
40
|
return Response.sendErrorResponse(req, res, new BadDataException("Invalid code"));
|
|
23
41
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
id: req.body["itemId"],
|
|
27
|
-
props: {
|
|
28
|
-
isRoot: true,
|
|
29
|
-
},
|
|
30
|
-
select: {
|
|
31
|
-
userId: true,
|
|
32
|
-
projectId: true,
|
|
33
|
-
verificationCode: true,
|
|
34
|
-
},
|
|
35
|
-
});
|
|
36
|
-
if (!item) {
|
|
37
|
-
return Response.sendErrorResponse(req, res, new BadDataException("Item not found"));
|
|
38
|
-
}
|
|
39
|
-
//check user id
|
|
40
|
-
if (((_a = item.userId) === null || _a === void 0 ? void 0 : _a.toString()) !==
|
|
41
|
-
((_c = (_b = req === null || req === void 0 ? void 0 : req.userAuthorization) === null || _b === void 0 ? void 0 : _b.userId) === null || _c === void 0 ? void 0 : _c.toString())) {
|
|
42
|
+
const userId = (_a = req === null || req === void 0 ? void 0 : req.userAuthorization) === null || _a === void 0 ? void 0 : _a.userId;
|
|
43
|
+
if (!userId) {
|
|
42
44
|
return Response.sendErrorResponse(req, res, new BadDataException("Invalid user ID"));
|
|
43
45
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
props: {
|
|
50
|
-
isRoot: true,
|
|
51
|
-
},
|
|
52
|
-
data: {
|
|
53
|
-
isVerified: true,
|
|
54
|
-
},
|
|
46
|
+
const result = await ChannelVerification.verifyCode({
|
|
47
|
+
service: this.service,
|
|
48
|
+
itemId: new ObjectID(req.body["itemId"].toString()),
|
|
49
|
+
userId: userId,
|
|
50
|
+
code: req.body["code"].toString(),
|
|
55
51
|
});
|
|
56
|
-
|
|
52
|
+
if (result.outcome !== ChannelVerificationOutcome.Verified) {
|
|
53
|
+
return Response.sendErrorResponse(req, res, ChannelVerification.getFailureException(result.outcome));
|
|
54
|
+
}
|
|
55
|
+
/* Create default notification rules for this verified email */
|
|
57
56
|
try {
|
|
58
57
|
await UserNotificationRuleService.addDefaultNotificationRulesForVerifiedMethod({
|
|
59
|
-
projectId: new ObjectID(
|
|
60
|
-
userId: new ObjectID(
|
|
58
|
+
projectId: new ObjectID(result.projectId.toString()),
|
|
59
|
+
userId: new ObjectID(result.userId.toString()),
|
|
61
60
|
notificationMethod: {
|
|
62
|
-
userEmailId:
|
|
61
|
+
userEmailId: result.itemId,
|
|
63
62
|
},
|
|
64
63
|
});
|
|
65
64
|
}
|
|
@@ -73,7 +72,7 @@ export default class UserEmailAPI extends BaseAPI {
|
|
|
73
72
|
}
|
|
74
73
|
});
|
|
75
74
|
this.router.post(`${(_b = new this.entityType()
|
|
76
|
-
.getCrudApiPath()) === null || _b === void 0 ? void 0 : _b.toString()}/resend-verification-code`, UserMiddleware.getUserMiddleware, async (req, res, next) => {
|
|
75
|
+
.getCrudApiPath()) === null || _b === void 0 ? void 0 : _b.toString()}/resend-verification-code`, UserMiddleware.getUserMiddleware, VerificationCodeRateLimit.getMiddleware(VerificationCodeRateLimitBucket.Resend), async (req, res, next) => {
|
|
77
76
|
var _a, _b, _c;
|
|
78
77
|
try {
|
|
79
78
|
req = req;
|
|
@@ -92,6 +91,11 @@ export default class UserEmailAPI extends BaseAPI {
|
|
|
92
91
|
if (!item) {
|
|
93
92
|
return Response.sendErrorResponse(req, res, new BadDataException("Item not found"));
|
|
94
93
|
}
|
|
94
|
+
/*
|
|
95
|
+
* A caller may only ask for a code to be sent to a row they own.
|
|
96
|
+
* Without this the resend route is a way to make somebody else's
|
|
97
|
+
* device ring on demand.
|
|
98
|
+
*/
|
|
95
99
|
if (((_a = item.userId) === null || _a === void 0 ? void 0 : _a.toString()) !==
|
|
96
100
|
((_c = (_b = req === null || req === void 0 ? void 0 : req.userAuthorization) === null || _b === void 0 ? void 0 : _b.userId) === null || _c === void 0 ? void 0 : _c.toString())) {
|
|
97
101
|
return Response.sendErrorResponse(req, res, new BadDataException("Invalid user ID"));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UserEmailAPI.js","sourceRoot":"","sources":["../../../../Server/API/UserEmailAPI.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,MAAM,iCAAiC,CAAC;AAC7D,OAAO,
|
|
1
|
+
{"version":3,"file":"UserEmailAPI.js","sourceRoot":"","sources":["../../../../Server/API/UserEmailAPI.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,14 +1,33 @@
|
|
|
1
1
|
import UserMiddleware from "../Middleware/UserAuthorization";
|
|
2
|
+
import VerificationCodeRateLimit, { VerificationCodeRateLimitBucket, } from "../Middleware/VerificationCodeRateLimit";
|
|
2
3
|
import UserIncomingCallNumberService from "../Services/UserIncomingCallNumberService";
|
|
4
|
+
import ChannelVerification, { ChannelVerificationOutcome, } from "../Utils/ChannelVerification";
|
|
3
5
|
import Response from "../Utils/Response";
|
|
4
6
|
import BaseAPI from "./BaseAPI";
|
|
5
7
|
import BadDataException from "../../Types/Exception/BadDataException";
|
|
8
|
+
import ObjectID from "../../Types/ObjectID";
|
|
6
9
|
import UserIncomingCallNumber from "../../Models/DatabaseModels/UserIncomingCallNumber";
|
|
10
|
+
/*
|
|
11
|
+
* The verify and resend routes for this notification channel.
|
|
12
|
+
*
|
|
13
|
+
* Neither the checking of a submitted code nor the issuing of a new one lives
|
|
14
|
+
* here, on purpose. The state machine is shared by all five channels
|
|
15
|
+
* (Common/Server/Utils/ChannelVerification.ts) so that a control added for one
|
|
16
|
+
* of them cannot quietly go missing on another — which is exactly what went
|
|
17
|
+
* wrong before: five hand-written copies of "compare the column, set
|
|
18
|
+
* isVerified", none of which expired the code, counted attempts, or refused a
|
|
19
|
+
* caller running the comparison a million times against somebody else's phone
|
|
20
|
+
* number.
|
|
21
|
+
*
|
|
22
|
+
* What is left here is the HTTP shape: reject malformed bodies, run the rate
|
|
23
|
+
* limiter before anything costs a database read, and turn the outcome into a
|
|
24
|
+
* response.
|
|
25
|
+
*/
|
|
7
26
|
export default class UserIncomingCallNumberAPI extends BaseAPI {
|
|
8
27
|
constructor() {
|
|
9
28
|
super(UserIncomingCallNumber, UserIncomingCallNumberService);
|
|
10
|
-
this.router.post(`/user-incoming-call-number/verify`, UserMiddleware.getUserMiddleware, async (req, res, next) => {
|
|
11
|
-
var _a
|
|
29
|
+
this.router.post(`/user-incoming-call-number/verify`, UserMiddleware.getUserMiddleware, VerificationCodeRateLimit.getMiddleware(VerificationCodeRateLimitBucket.Verify), async (req, res, next) => {
|
|
30
|
+
var _a;
|
|
12
31
|
try {
|
|
13
32
|
req = req;
|
|
14
33
|
if (!req.body.itemId) {
|
|
@@ -17,44 +36,26 @@ export default class UserIncomingCallNumberAPI extends BaseAPI {
|
|
|
17
36
|
if (!req.body.code) {
|
|
18
37
|
return Response.sendErrorResponse(req, res, new BadDataException("Invalid code"));
|
|
19
38
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
id: req.body["itemId"],
|
|
23
|
-
props: {
|
|
24
|
-
isRoot: true,
|
|
25
|
-
},
|
|
26
|
-
select: {
|
|
27
|
-
userId: true,
|
|
28
|
-
verificationCode: true,
|
|
29
|
-
},
|
|
30
|
-
});
|
|
31
|
-
if (!item) {
|
|
32
|
-
return Response.sendErrorResponse(req, res, new BadDataException("Item not found"));
|
|
33
|
-
}
|
|
34
|
-
// Check user ID
|
|
35
|
-
if (((_a = item.userId) === null || _a === void 0 ? void 0 : _a.toString()) !==
|
|
36
|
-
((_c = (_b = req === null || req === void 0 ? void 0 : req.userAuthorization) === null || _b === void 0 ? void 0 : _b.userId) === null || _c === void 0 ? void 0 : _c.toString())) {
|
|
39
|
+
const userId = (_a = req === null || req === void 0 ? void 0 : req.userAuthorization) === null || _a === void 0 ? void 0 : _a.userId;
|
|
40
|
+
if (!userId) {
|
|
37
41
|
return Response.sendErrorResponse(req, res, new BadDataException("Invalid user ID"));
|
|
38
42
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
props: {
|
|
45
|
-
isRoot: true,
|
|
46
|
-
},
|
|
47
|
-
data: {
|
|
48
|
-
isVerified: true,
|
|
49
|
-
},
|
|
43
|
+
const result = await ChannelVerification.verifyCode({
|
|
44
|
+
service: this.service,
|
|
45
|
+
itemId: new ObjectID(req.body["itemId"].toString()),
|
|
46
|
+
userId: userId,
|
|
47
|
+
code: req.body["code"].toString(),
|
|
50
48
|
});
|
|
49
|
+
if (result.outcome !== ChannelVerificationOutcome.Verified) {
|
|
50
|
+
return Response.sendErrorResponse(req, res, ChannelVerification.getFailureException(result.outcome));
|
|
51
|
+
}
|
|
51
52
|
return Response.sendEmptySuccessResponse(req, res);
|
|
52
53
|
}
|
|
53
54
|
catch (err) {
|
|
54
55
|
return next(err);
|
|
55
56
|
}
|
|
56
57
|
});
|
|
57
|
-
this.router.post(`/user-incoming-call-number/resend-verification-code`, UserMiddleware.getUserMiddleware, async (req, res, next) => {
|
|
58
|
+
this.router.post(`/user-incoming-call-number/resend-verification-code`, UserMiddleware.getUserMiddleware, VerificationCodeRateLimit.getMiddleware(VerificationCodeRateLimitBucket.Resend), async (req, res, next) => {
|
|
58
59
|
var _a, _b, _c;
|
|
59
60
|
try {
|
|
60
61
|
req = req;
|
|
@@ -73,7 +74,11 @@ export default class UserIncomingCallNumberAPI extends BaseAPI {
|
|
|
73
74
|
if (!item) {
|
|
74
75
|
return Response.sendErrorResponse(req, res, new BadDataException("Item not found"));
|
|
75
76
|
}
|
|
76
|
-
|
|
77
|
+
/*
|
|
78
|
+
* A caller may only ask for a code to be sent to a row they own.
|
|
79
|
+
* Without this the resend route is a way to make somebody else's
|
|
80
|
+
* device ring on demand.
|
|
81
|
+
*/
|
|
77
82
|
if (((_a = item.userId) === null || _a === void 0 ? void 0 : _a.toString()) !==
|
|
78
83
|
((_c = (_b = req === null || req === void 0 ? void 0 : req.userAuthorization) === null || _b === void 0 ? void 0 : _b.userId) === null || _c === void 0 ? void 0 : _c.toString())) {
|
|
79
84
|
return Response.sendErrorResponse(req, res, new BadDataException("Invalid user ID"));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UserIncomingCallNumberAPI.js","sourceRoot":"","sources":["../../../../Server/API/UserIncomingCallNumberAPI.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,MAAM,iCAAiC,CAAC;AAC7D,OAAO,6BAEN,MAAM,2CAA2C,CAAC;AAOnD,OAAO,QAAQ,MAAM,mBAAmB,CAAC;AACzC,OAAO,OAAO,MAAM,WAAW,CAAC;AAChC,OAAO,gBAAgB,MAAM,wCAAwC,CAAC;AACtE,OAAO,sBAAsB,MAAM,oDAAoD,CAAC;AAExF,MAAM,CAAC,OAAO,OAAO,yBAA0B,SAAQ,OAGtD;IACC;QACE,KAAK,CAAC,sBAAsB,EAAE,6BAA6B,CAAC,CAAC;QAE7D,IAAI,CAAC,MAAM,CAAC,IAAI,CACd,mCAAmC,EACnC,cAAc,CAAC,iBAAiB,EAChC,KAAK,EAAE,GAAmB,EAAE,GAAoB,EAAE,IAAkB,EAAE,EAAE;;YACtE,IAAI,CAAC;gBACH,GAAG,GAAG,GAAuB,CAAC;gBAE9B,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;oBACrB,OAAO,QAAQ,CAAC,iBAAiB,CAC/B,GAAG,EACH,GAAG,EACH,IAAI,gBAAgB,CAAC,iBAAiB,CAAC,CACxC,CAAC;gBACJ,CAAC;gBAED,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;oBACnB,OAAO,QAAQ,CAAC,iBAAiB,CAC/B,GAAG,EACH,GAAG,EACH,IAAI,gBAAgB,CAAC,cAAc,CAAC,CACrC,CAAC;gBACJ,CAAC;gBAED,
|
|
1
|
+
{"version":3,"file":"UserIncomingCallNumberAPI.js","sourceRoot":"","sources":["../../../../Server/API/UserIncomingCallNumberAPI.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
import UserMiddleware from "../Middleware/UserAuthorization";
|
|
2
|
+
import UserNotificationMethodAdminService from "../Services/UserNotificationMethodAdminService";
|
|
3
|
+
import TeamMemberService from "../Services/TeamMemberService";
|
|
4
|
+
import Express from "../Utils/Express";
|
|
5
|
+
import Response from "../Utils/Response";
|
|
6
|
+
import CommonAPI from "./CommonAPI";
|
|
7
|
+
import DatabaseCommonInteractionPropsUtil, { PermissionType, } from "../../Types/BaseDatabase/DatabaseCommonInteractionPropsUtil";
|
|
8
|
+
import BadDataException from "../../Types/Exception/BadDataException";
|
|
9
|
+
import NotAuthorizedException from "../../Types/Exception/NotAuthorizedException";
|
|
10
|
+
import ObjectID from "../../Types/ObjectID";
|
|
11
|
+
import Permission from "../../Types/Permission";
|
|
12
|
+
/*
|
|
13
|
+
* Managing another project member's notification methods over HTTP.
|
|
14
|
+
*
|
|
15
|
+
* Everything this router does is done by UserNotificationMethodAdminService,
|
|
16
|
+
* which holds the whole of the reasoning about masking, verification and the
|
|
17
|
+
* owner's mail. This file is transport and AUTHORISATION, and the authorisation
|
|
18
|
+
* is the part worth reading, because the usual reasoning does not apply here.
|
|
19
|
+
*
|
|
20
|
+
* The seven notification method models are scoped to the person who owns the
|
|
21
|
+
* device, and they stay that way — see the essay at the top of UserEmail.ts.
|
|
22
|
+
* The service therefore does its reads and writes with `isRoot: true`, which
|
|
23
|
+
* means the model's own TableAccessControl never runs on this path AND THESE
|
|
24
|
+
* HANDLERS ARE THE ONLY GATE UNDERNEATH. UserMiddleware.getUserMiddleware is
|
|
25
|
+
* not that gate: it admits anonymous callers as UserType.Public and calls
|
|
26
|
+
* next(), and the tenant id it attaches comes straight off the caller-supplied
|
|
27
|
+
* `tenantid` header before any authorisation runs.
|
|
28
|
+
*
|
|
29
|
+
* So every route below asserts, itself, in this order:
|
|
30
|
+
*
|
|
31
|
+
* 1. the caller is a signed-in member of the project they named
|
|
32
|
+
* (CommonAPI.assertAuthenticatedProjectMember, which checks the caller
|
|
33
|
+
* against that same header);
|
|
34
|
+
* 2. the caller holds a permission that lets them act on other people's
|
|
35
|
+
* accounts in it (assertCanManageUserNotificationMethods below), EXCEPT on
|
|
36
|
+
* the read, which additionally lets a person read their own; and
|
|
37
|
+
* 3. the user named in the path is a member of that same project — enforced
|
|
38
|
+
* again inside the service, on purpose, so the service is safe for any
|
|
39
|
+
* caller and not only for this router.
|
|
40
|
+
*
|
|
41
|
+
* WHY THE READ IS SEPARATELY GATED FROM THE WRITES. Reading the masked list is
|
|
42
|
+
* a disclosure ("this person has an unverified SMS"), and the readiness surface
|
|
43
|
+
* already discloses exactly that to every project member. Writing is an ACTION
|
|
44
|
+
* on somebody else's account. Those are different questions and the router does
|
|
45
|
+
* not answer them with one permission.
|
|
46
|
+
*/
|
|
47
|
+
const router = Express.getRouter();
|
|
48
|
+
/*
|
|
49
|
+
* Who may LOOK at another member's notification methods.
|
|
50
|
+
*
|
|
51
|
+
* The same triple the admin rules page uses, and for the same reason: existing
|
|
52
|
+
* project teams are seeded with ROLES, never with individual granular
|
|
53
|
+
* permissions, so a permission introduced in this release is held by nobody at
|
|
54
|
+
* all until an administrator explicitly grants it. A gate naming only the
|
|
55
|
+
* granular permission would ship a feature that is dead on arrival for every
|
|
56
|
+
* project that already exists — the owner of a project would open the page and
|
|
57
|
+
* be told they may not look at it.
|
|
58
|
+
*/
|
|
59
|
+
const READ_PERMISSIONS = [
|
|
60
|
+
Permission.ProjectOwner,
|
|
61
|
+
Permission.ProjectAdmin,
|
|
62
|
+
Permission.ReadProjectUserNotificationRule,
|
|
63
|
+
];
|
|
64
|
+
/*
|
|
65
|
+
* Who may ADD or REMOVE one.
|
|
66
|
+
*
|
|
67
|
+
* Deliberately NOT EditProjectUserNotificationRule. Repairing somebody's rules
|
|
68
|
+
* and putting a new address on their account are different powers with
|
|
69
|
+
* different blast radii: the first re-points pages between devices that person
|
|
70
|
+
* has already proved they hold, the second introduces a device nobody has
|
|
71
|
+
* proved anything about. An installation that wants to hand out the first
|
|
72
|
+
* without the second must be able to, so this is its own permission.
|
|
73
|
+
*/
|
|
74
|
+
const MANAGE_PERMISSIONS = [
|
|
75
|
+
Permission.ProjectOwner,
|
|
76
|
+
Permission.ProjectAdmin,
|
|
77
|
+
Permission.ManageProjectUserNotificationMethod,
|
|
78
|
+
];
|
|
79
|
+
/*
|
|
80
|
+
* The permission check, read the way the rest of the API reads permissions.
|
|
81
|
+
*
|
|
82
|
+
* getUserPermissions(Allow) rather than indexing userTenantAccessPermission
|
|
83
|
+
* directly, and that is not a stylistic preference. That dictionary's entries
|
|
84
|
+
* hold GRANTS AND DENIALS in one array, discriminated only by
|
|
85
|
+
* `isBlockPermission`, so mapping it raw would count a team's explicit BLOCK of
|
|
86
|
+
* ProjectAdmin as a grant of it — the admin action that restricts a team would
|
|
87
|
+
* be the thing that handed it this endpoint.
|
|
88
|
+
*
|
|
89
|
+
* Every refusal in this file reuses one sentence, so an under-privileged member
|
|
90
|
+
* cannot tell "you may not do this" apart from "you are not in this project"
|
|
91
|
+
* and use the difference to probe.
|
|
92
|
+
*/
|
|
93
|
+
function assertHasAnyPermission(databaseProps, allowed) {
|
|
94
|
+
if (databaseProps.isMasterAdmin) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const permissions = DatabaseCommonInteractionPropsUtil.getUserPermissions(databaseProps, PermissionType.Allow).map((userPermission) => {
|
|
98
|
+
return userPermission.permission;
|
|
99
|
+
});
|
|
100
|
+
const isAllowed = permissions.some((permission) => {
|
|
101
|
+
return allowed.includes(permission);
|
|
102
|
+
});
|
|
103
|
+
if (!isAllowed) {
|
|
104
|
+
throw new NotAuthorizedException("You are not authorized to access this project's data.");
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/*
|
|
108
|
+
* Project membership for the user NAMED IN THE PATH, not the caller.
|
|
109
|
+
*
|
|
110
|
+
* Without it these routes are a cross-project probe: the service's reads are
|
|
111
|
+
* projectId-scoped and would come back empty for a stranger, but a write path
|
|
112
|
+
* that skipped this would let somebody holding ProjectAdmin on one throwaway
|
|
113
|
+
* project act on a user id belonging to any other.
|
|
114
|
+
*
|
|
115
|
+
* The rejection reuses the router's single refusal sentence so a caller cannot
|
|
116
|
+
* tell "this user exists but is in another project" apart from "this user does
|
|
117
|
+
* not exist", and therefore cannot enumerate users through it. The service
|
|
118
|
+
* repeats the check with its own wording once the caller is past this point.
|
|
119
|
+
*/
|
|
120
|
+
async function assertUserBelongsToProject(userId, projectId) {
|
|
121
|
+
const memberships = await TeamMemberService.findBy({
|
|
122
|
+
query: {
|
|
123
|
+
userId: userId,
|
|
124
|
+
projectId: projectId,
|
|
125
|
+
},
|
|
126
|
+
select: {
|
|
127
|
+
_id: true,
|
|
128
|
+
},
|
|
129
|
+
limit: 1,
|
|
130
|
+
skip: 0,
|
|
131
|
+
props: {
|
|
132
|
+
isRoot: true,
|
|
133
|
+
},
|
|
134
|
+
});
|
|
135
|
+
if (memberships.length === 0) {
|
|
136
|
+
throw new NotAuthorizedException("You are not authorized to access this project's data.");
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
/*
|
|
140
|
+
* ObjectID's constructor accepts any string, so an unvalidated path segment
|
|
141
|
+
* would travel all the way to a query that matches nothing and read as "this
|
|
142
|
+
* user has no notification methods" rather than as "you sent nonsense".
|
|
143
|
+
*/
|
|
144
|
+
function readObjectIdParam(req, name) {
|
|
145
|
+
const raw = req.params[name] || "";
|
|
146
|
+
ObjectID.validateUUID(raw);
|
|
147
|
+
return new ObjectID(raw);
|
|
148
|
+
}
|
|
149
|
+
function readStringFromBody(req, name) {
|
|
150
|
+
const body = (req.body || {});
|
|
151
|
+
const raw = body[name];
|
|
152
|
+
if (typeof raw !== "string" || !raw.trim()) {
|
|
153
|
+
throw new BadDataException(`${name} is required.`);
|
|
154
|
+
}
|
|
155
|
+
return raw.trim();
|
|
156
|
+
}
|
|
157
|
+
/*
|
|
158
|
+
* ObjectID.toJSON() serialises to `{ _type: "ObjectID", value: "..." }`, which
|
|
159
|
+
* is right for model payloads the client parses back through JSONFunctions but
|
|
160
|
+
* wrong for a hand-rolled response body. Ids are flattened to plain strings, the
|
|
161
|
+
* same way OnCallReadinessAPI does it, so the browser can read `methodId`
|
|
162
|
+
* without knowing about ObjectID at all.
|
|
163
|
+
*
|
|
164
|
+
* `maskedIdentifier` is copied and nothing else is: there is no raw field on
|
|
165
|
+
* the service's view type to leak, which is deliberate — a future change would
|
|
166
|
+
* have to widen that contract in the open rather than slip a phone number
|
|
167
|
+
* through a boolean flag here.
|
|
168
|
+
*/
|
|
169
|
+
function serializeMethod(method) {
|
|
170
|
+
return {
|
|
171
|
+
methodId: method.methodId.toString(),
|
|
172
|
+
methodType: method.methodType,
|
|
173
|
+
maskedIdentifier: method.maskedIdentifier,
|
|
174
|
+
isVerified: method.isVerified,
|
|
175
|
+
isAdminAddable: method.isAdminAddable,
|
|
176
|
+
createdAt: method.createdAt ? method.createdAt.toISOString() : undefined,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
/*
|
|
180
|
+
* Every notification method this user has, masked.
|
|
181
|
+
*
|
|
182
|
+
* A member reading their OWN row is allowed through without the admin
|
|
183
|
+
* permission. The page behind this is reachable from the project's user list,
|
|
184
|
+
* and a person looking at themselves there is reading rows the self-serve
|
|
185
|
+
* settings pages already show them in full.
|
|
186
|
+
*/
|
|
187
|
+
router.get("/user-notification-method-admin/user/:userId", UserMiddleware.getUserMiddleware, async (req, res, next) => {
|
|
188
|
+
try {
|
|
189
|
+
const databaseProps = await CommonAPI.getDatabaseCommonInteractionProps(req);
|
|
190
|
+
const projectId = CommonAPI.assertAuthenticatedProjectMember(databaseProps);
|
|
191
|
+
const userId = readObjectIdParam(req, "userId");
|
|
192
|
+
const isSelf = Boolean(databaseProps.userId) &&
|
|
193
|
+
databaseProps.userId.toString() === userId.toString();
|
|
194
|
+
if (!isSelf) {
|
|
195
|
+
assertHasAnyPermission(databaseProps, READ_PERMISSIONS);
|
|
196
|
+
}
|
|
197
|
+
await assertUserBelongsToProject(userId, projectId);
|
|
198
|
+
const methods = await UserNotificationMethodAdminService.listMethodsForUser({
|
|
199
|
+
projectId: projectId,
|
|
200
|
+
userId: userId,
|
|
201
|
+
});
|
|
202
|
+
return Response.sendJsonObjectResponse(req, res, {
|
|
203
|
+
methods: methods.map(serializeMethod),
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
catch (err) {
|
|
207
|
+
next(err);
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
/*
|
|
211
|
+
* Add a notification method to this user's account.
|
|
212
|
+
*
|
|
213
|
+
* The row lands UNVERIFIED and a verification code goes to the address itself,
|
|
214
|
+
* which is what keeps this from being a way to redirect somebody's pages: the
|
|
215
|
+
* verify endpoints refuse anybody but the row's owner, so the administrator who
|
|
216
|
+
* just typed the value in cannot complete it. See the service header.
|
|
217
|
+
*/
|
|
218
|
+
router.post("/user-notification-method-admin/user/:userId", UserMiddleware.getUserMiddleware, async (req, res, next) => {
|
|
219
|
+
try {
|
|
220
|
+
const databaseProps = await CommonAPI.getDatabaseCommonInteractionProps(req);
|
|
221
|
+
const projectId = CommonAPI.assertAuthenticatedProjectMember(databaseProps);
|
|
222
|
+
/*
|
|
223
|
+
* Both gates run before the body is read. A route that validates a
|
|
224
|
+
* payload for a caller it is about to refuse has told that caller
|
|
225
|
+
* something about the payload format.
|
|
226
|
+
*/
|
|
227
|
+
assertHasAnyPermission(databaseProps, MANAGE_PERMISSIONS);
|
|
228
|
+
const userId = readObjectIdParam(req, "userId");
|
|
229
|
+
await assertUserBelongsToProject(userId, projectId);
|
|
230
|
+
const methodType = readStringFromBody(req, "methodType");
|
|
231
|
+
const value = readStringFromBody(req, "value");
|
|
232
|
+
const created = await UserNotificationMethodAdminService.addMethodForUser({
|
|
233
|
+
projectId: projectId,
|
|
234
|
+
targetUserId: userId,
|
|
235
|
+
/*
|
|
236
|
+
* The actor the SERVER resolved, never anything from the body. This
|
|
237
|
+
* value names somebody in an audit entry and in a mail to the account
|
|
238
|
+
* holder, so a body-supplied one would let a caller sign their own
|
|
239
|
+
* change with a colleague's name.
|
|
240
|
+
*/
|
|
241
|
+
actorUserId: databaseProps.userId,
|
|
242
|
+
methodType: methodType,
|
|
243
|
+
value: value,
|
|
244
|
+
props: databaseProps,
|
|
245
|
+
});
|
|
246
|
+
return Response.sendJsonObjectResponse(req, res, serializeMethod(created));
|
|
247
|
+
}
|
|
248
|
+
catch (err) {
|
|
249
|
+
next(err);
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
/*
|
|
253
|
+
* What removing this method would cost, before anybody confirms it.
|
|
254
|
+
*
|
|
255
|
+
* Read-only, and gated as a WRITE rather than as a read: the numbers it returns
|
|
256
|
+
* are about this user's rule coverage, and the only reason to ask for them is
|
|
257
|
+
* that you are about to delete something.
|
|
258
|
+
*/
|
|
259
|
+
router.get("/user-notification-method-admin/user/:userId/:methodType/:methodId/deletion-impact", UserMiddleware.getUserMiddleware, async (req, res, next) => {
|
|
260
|
+
try {
|
|
261
|
+
const databaseProps = await CommonAPI.getDatabaseCommonInteractionProps(req);
|
|
262
|
+
const projectId = CommonAPI.assertAuthenticatedProjectMember(databaseProps);
|
|
263
|
+
assertHasAnyPermission(databaseProps, MANAGE_PERMISSIONS);
|
|
264
|
+
const userId = readObjectIdParam(req, "userId");
|
|
265
|
+
await assertUserBelongsToProject(userId, projectId);
|
|
266
|
+
const methodId = readObjectIdParam(req, "methodId");
|
|
267
|
+
const preview = await UserNotificationMethodAdminService.getDeletionPreview({
|
|
268
|
+
projectId: projectId,
|
|
269
|
+
targetUserId: userId,
|
|
270
|
+
methodType: req.params["methodType"] || "",
|
|
271
|
+
methodId: methodId,
|
|
272
|
+
});
|
|
273
|
+
return Response.sendJsonObjectResponse(req, res, preview);
|
|
274
|
+
}
|
|
275
|
+
catch (err) {
|
|
276
|
+
next(err);
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
/*
|
|
280
|
+
* Send the verification code again, to the device.
|
|
281
|
+
*
|
|
282
|
+
* Discloses nothing — the code goes to the address on the row, which is the one
|
|
283
|
+
* thing on it the administrator cannot read — and it is the lever that makes
|
|
284
|
+
* adding a method on somebody's behalf actually finish: "I added your work
|
|
285
|
+
* mobile, here is another code" rather than re-typing the number.
|
|
286
|
+
*/
|
|
287
|
+
router.post("/user-notification-method-admin/user/:userId/:methodType/:methodId/resend-verification-code", UserMiddleware.getUserMiddleware, async (req, res, next) => {
|
|
288
|
+
try {
|
|
289
|
+
const databaseProps = await CommonAPI.getDatabaseCommonInteractionProps(req);
|
|
290
|
+
const projectId = CommonAPI.assertAuthenticatedProjectMember(databaseProps);
|
|
291
|
+
assertHasAnyPermission(databaseProps, MANAGE_PERMISSIONS);
|
|
292
|
+
const userId = readObjectIdParam(req, "userId");
|
|
293
|
+
await assertUserBelongsToProject(userId, projectId);
|
|
294
|
+
const methodId = readObjectIdParam(req, "methodId");
|
|
295
|
+
await UserNotificationMethodAdminService.resendVerificationCodeForUser({
|
|
296
|
+
projectId: projectId,
|
|
297
|
+
targetUserId: userId,
|
|
298
|
+
methodType: req.params["methodType"] || "",
|
|
299
|
+
methodId: methodId,
|
|
300
|
+
});
|
|
301
|
+
return Response.sendEmptySuccessResponse(req, res);
|
|
302
|
+
}
|
|
303
|
+
catch (err) {
|
|
304
|
+
next(err);
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
/*
|
|
308
|
+
* Remove one of this user's notification methods.
|
|
309
|
+
*
|
|
310
|
+
* DELETE rather than a POST to a /delete path, because it is one, and because
|
|
311
|
+
* the id it names is the only thing that identifies the row — there is no body
|
|
312
|
+
* to get out of step with the URL.
|
|
313
|
+
*
|
|
314
|
+
* Every rule pointing at this method goes with it (the foreign keys are all
|
|
315
|
+
* onDelete: "CASCADE"), which is why the preview route above exists and why the
|
|
316
|
+
* owner is always mailed about this one.
|
|
317
|
+
*/
|
|
318
|
+
router.delete("/user-notification-method-admin/user/:userId/:methodType/:methodId", UserMiddleware.getUserMiddleware, async (req, res, next) => {
|
|
319
|
+
try {
|
|
320
|
+
const databaseProps = await CommonAPI.getDatabaseCommonInteractionProps(req);
|
|
321
|
+
const projectId = CommonAPI.assertAuthenticatedProjectMember(databaseProps);
|
|
322
|
+
assertHasAnyPermission(databaseProps, MANAGE_PERMISSIONS);
|
|
323
|
+
const userId = readObjectIdParam(req, "userId");
|
|
324
|
+
await assertUserBelongsToProject(userId, projectId);
|
|
325
|
+
const methodId = readObjectIdParam(req, "methodId");
|
|
326
|
+
await UserNotificationMethodAdminService.deleteMethodForUser({
|
|
327
|
+
projectId: projectId,
|
|
328
|
+
targetUserId: userId,
|
|
329
|
+
actorUserId: databaseProps.userId,
|
|
330
|
+
methodType: req.params["methodType"] || "",
|
|
331
|
+
methodId: methodId,
|
|
332
|
+
props: databaseProps,
|
|
333
|
+
});
|
|
334
|
+
return Response.sendEmptySuccessResponse(req, res);
|
|
335
|
+
}
|
|
336
|
+
catch (err) {
|
|
337
|
+
next(err);
|
|
338
|
+
}
|
|
339
|
+
});
|
|
340
|
+
export default router;
|
|
341
|
+
//# sourceMappingURL=UserNotificationMethodAdminAPI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UserNotificationMethodAdminAPI.js","sourceRoot":"","sources":["../../../../Server/API/UserNotificationMethodAdminAPI.ts"],"names":[],"mappings":"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"}
|