@rapidmx/web-client 0.20.0 → 0.22.0
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/README.md +415 -381
- package/apps/admin/_layout.tsx +2 -2
- package/apps/admin/audit-log/index.tsx +4 -4
- package/apps/admin/branding/index.tsx +39 -39
- package/apps/admin/data-requests/index.tsx +482 -482
- package/apps/admin/distribution-lists/[uid].tsx +3 -3
- package/apps/admin/distribution-lists/index.tsx +4 -4
- package/apps/admin/distribution-lists/new/index.tsx +5 -5
- package/apps/admin/domains/[uid].tsx +166 -166
- package/apps/admin/domains/index.tsx +4 -4
- package/apps/admin/domains/new/index.tsx +5 -5
- package/apps/admin/encryption-policy/index.tsx +1 -1
- package/apps/admin/escrow-scopes/[uid].tsx +350 -350
- package/apps/admin/escrow-scopes/index.tsx +4 -4
- package/apps/admin/escrow-scopes/new/index.tsx +5 -5
- package/apps/admin/index.tsx +129 -129
- package/apps/admin/ingest-queue/index.tsx +4 -4
- package/apps/admin/mailbox-policy/index.tsx +1 -1
- package/apps/admin/mailboxes/[uid].tsx +271 -271
- package/apps/admin/mailboxes/new/index.tsx +30 -30
- package/apps/admin/plugins/index.tsx +15 -15
- package/apps/admin/quarantine/index.tsx +5 -5
- package/apps/admin/retention-policy/index.tsx +39 -39
- package/apps/admin/signing-certificates/index.tsx +343 -343
- package/apps/admin/transport-rules/[uid].tsx +5 -5
- package/apps/admin/transport-rules/_transportRuleConfig.tsx +3 -3
- package/apps/admin/transport-rules/index.tsx +4 -4
- package/apps/admin/transport-rules/new/index.tsx +5 -5
- package/apps/escrow/_layout.tsx +1 -1
- package/apps/escrow/audit-log/index.tsx +196 -196
- package/apps/escrow/index.tsx +4 -4
- package/apps/escrow/matters/[uid].tsx +621 -621
- package/apps/escrow/matters/new/index.tsx +6 -6
- package/apps/shared/appearance/AppearanceForm.tsx +3 -3
- package/apps/shared/appearance/AppearanceHead.tsx +1 -1
- package/apps/shared/appearance/AppearanceProvider.tsx +3 -3
- package/apps/shared/appearance/appearanceCache.ts +1 -1
- package/apps/shared/appearance/appearanceContext.ts +1 -1
- package/apps/shared/appearance/theme.ts +1 -1
- package/apps/shared/auth/adminAccess.ts +99 -99
- package/apps/shared/calendar/bookingPlugin.ts +1 -1
- package/apps/shared/calendar/calendarLiveUpdates.ts +1 -1
- package/apps/shared/calendar/calendarReminders.ts +1 -1
- package/apps/shared/calendar/useCalendarReminders.ts +1 -1
- package/apps/shared/components/admin/diagnostics/DiagnosticsManager.tsx +1 -1
- package/apps/shared/components/admin/diagnostics/InstalledPlugins.tsx +2 -2
- package/apps/shared/components/admin/diagnostics/LogsPanel.tsx +2 -2
- package/apps/shared/components/admin/diagnostics/PackagesTable.tsx +1 -1
- package/apps/shared/components/admin/diagnostics/RuntimePanel.tsx +1 -1
- package/apps/shared/components/admin/diagnostics/SystemPanel.tsx +2 -2
- package/apps/shared/components/admin/diagnostics/VersionsPanel.tsx +1 -1
- package/apps/shared/components/admin/diagnostics/diagnosticsApi.ts +1 -1
- package/apps/shared/components/admin/diagnostics/format.ts +1 -1
- package/apps/shared/components/admin/diagnostics/logClient.ts +1 -1
- package/apps/shared/components/admin/distributionLists/MemberListCard.tsx +4 -4
- package/apps/shared/components/admin/elevation.ts +1 -1
- package/apps/shared/components/admin/escrowScopes/EscrowScopeKeyAndHoldersFields.tsx +3 -3
- package/apps/shared/components/admin/layout/AdminShell.tsx +384 -384
- package/apps/shared/components/admin/mailboxes/EraseLeftoverDataDialog.tsx +238 -238
- package/apps/shared/components/admin/mailboxes/EscrowScopeCard.tsx +154 -152
- package/apps/shared/components/admin/mailboxes/LeftoverMailboxesSection.tsx +194 -194
- package/apps/shared/components/admin/mailboxes/MailboxTable.tsx +1 -1
- package/apps/shared/components/admin/mailboxes/ResourceSettingsCard.tsx +19 -14
- package/apps/shared/components/admin/mailboxes/ShareAccessCard.tsx +5 -5
- package/apps/shared/components/admin/settings/BrandingForm.tsx +423 -423
- package/apps/shared/components/admin/settings/DomainDnsSetup.tsx +5 -5
- package/apps/shared/components/admin/settings/EncryptionPolicyForm.tsx +119 -119
- package/apps/shared/components/admin/settings/LoadedSettingsForm.tsx +2 -2
- package/apps/shared/components/admin/settings/MailboxCreateForm.tsx +32 -27
- package/apps/shared/components/admin/settings/MailboxPolicyForm.tsx +198 -198
- package/apps/shared/components/admin/settings/PluginsManager.tsx +2093 -2093
- package/apps/shared/components/admin/settings/RetentionPolicyForm.tsx +182 -182
- package/apps/shared/components/admin/setup/EscrowSetupStep.tsx +288 -288
- package/apps/shared/components/admin/setup/SetupWizard.tsx +450 -446
- package/apps/shared/components/admin/signOut.ts +1 -1
- package/apps/shared/components/admin/usePagedList.tsx +129 -129
- package/apps/shared/components/calendar/AppointmentQuickForm.tsx +3 -3
- package/apps/shared/components/calendar/CalendarListSidebar.tsx +3 -3
- package/apps/shared/components/calendar/DescriptionEditor.tsx +1 -1
- package/apps/shared/components/calendar/EventDescriptionView.tsx +1 -1
- package/apps/shared/components/calendar/EventDetails.tsx +16 -14
- package/apps/shared/components/calendar/EventEditor.tsx +54 -39
- package/apps/shared/components/calendar/EventExpandedForm.tsx +3 -3
- package/apps/shared/components/calendar/EventFormParts.tsx +2 -2
- package/apps/shared/components/calendar/EventModal.tsx +206 -206
- package/apps/shared/components/calendar/EventQuickForm.tsx +3 -3
- package/apps/shared/components/calendar/EventShell.tsx +1 -1
- package/apps/shared/components/calendar/FindATime.tsx +6 -4
- package/apps/shared/components/calendar/GuestInput.tsx +2 -2
- package/apps/shared/components/calendar/MonthView.tsx +185 -185
- package/apps/shared/components/calendar/QuickCreateFaces.tsx +1 -1
- package/apps/shared/components/calendar/QuickFaceFrame.tsx +1 -1
- package/apps/shared/components/calendar/RecurrenceEditor.tsx +227 -227
- package/apps/shared/components/calendar/RequestChangeForm.tsx +8 -6
- package/apps/shared/components/calendar/ResourcePicker.tsx +7 -5
- package/apps/shared/components/calendar/SplitDayView.tsx +144 -144
- package/apps/shared/components/calendar/TaskQuickForm.tsx +23 -18
- package/apps/shared/components/calendar/TimeGridView.tsx +246 -246
- package/apps/shared/components/calendar/allDay.ts +124 -124
- package/apps/shared/components/calendar/eventDialogFields.ts +3 -3
- package/apps/shared/components/calendar/eventForm.ts +3 -3
- package/apps/shared/components/calendar/eventFormat.ts +3 -3
- package/apps/shared/components/calendar/findTimeGrid.ts +2 -2
- package/apps/shared/components/calendar/layout/CalendarShell.tsx +11 -9
- package/apps/shared/components/contacts/ContactDetailPane.tsx +4 -4
- package/apps/shared/components/contacts/ContactForm.tsx +393 -383
- package/apps/shared/components/contacts/ContactsSidebar.tsx +7 -5
- package/apps/shared/components/contacts/ContactsToolbar.tsx +103 -103
- package/apps/shared/components/contacts/KeyChangeReview.tsx +5 -5
- package/apps/shared/components/contacts/contactKeys.ts +3 -3
- package/apps/shared/components/contacts/layout/ContactsShell.tsx +9 -7
- package/apps/shared/components/escrow/layout/EscrowShell.tsx +155 -155
- package/apps/shared/components/forms/StringListField.tsx +1 -1
- package/apps/shared/components/layout/AppShell.tsx +465 -461
- package/apps/shared/components/layout/BrandingChrome.tsx +1 -1
- package/apps/shared/components/layout/KeyEnrollmentGate.tsx +398 -398
- package/apps/shared/components/layout/MailboxProvisioning.tsx +170 -168
- package/apps/shared/components/layout/RecoveryCodeUnlock.tsx +9 -9
- package/apps/shared/components/layout/ResponsiveToolbar.tsx +315 -315
- package/apps/shared/components/layout/ThemeSwitch.tsx +84 -84
- package/apps/shared/components/layout/UnlockPromptProvider.tsx +6 -6
- package/apps/shared/components/layout/UserMenu.tsx +441 -439
- package/apps/shared/components/mail/ConversationList.tsx +334 -332
- package/apps/shared/components/mail/ConversationThreadPane.tsx +624 -613
- package/apps/shared/components/mail/InviteCard.tsx +11 -9
- package/apps/shared/components/mail/LazyReadingPane.tsx +2 -2
- package/apps/shared/components/mail/MailAddress.tsx +1 -1
- package/apps/shared/components/mail/MailListToolbar.tsx +2 -2
- package/apps/shared/components/mail/MailSelectionBar.tsx +240 -240
- package/apps/shared/components/mail/MenuButton.tsx +404 -404
- package/apps/shared/components/mail/MessageDetailPane.tsx +1759 -1757
- package/apps/shared/components/mail/MoveToFolderDialog.tsx +8 -6
- package/apps/shared/components/mail/OutboxRowStatus.tsx +1 -1
- package/apps/shared/components/mail/PermanentDeleteDialog.tsx +2 -2
- package/apps/shared/components/mail/compose/ComposeContext.tsx +323 -312
- package/apps/shared/components/mail/compose/ComposeToolbar.tsx +422 -422
- package/apps/shared/components/mail/compose/ComposeWindow.tsx +1709 -1681
- package/apps/shared/components/mail/compose/ComposeWindowPlaceholder.tsx +4 -4
- package/apps/shared/components/mail/compose/EmojiPicker.tsx +2 -2
- package/apps/shared/components/mail/compose/GifPicker.tsx +3 -3
- package/apps/shared/components/mail/compose/RecipientInput.tsx +1 -1
- package/apps/shared/components/mail/compose/RichTextEditor.tsx +147 -147
- package/apps/shared/components/mail/compose/ScheduleSendPicker.tsx +1 -1
- package/apps/shared/components/mail/compose/composeFlushRegistry.ts +60 -60
- package/apps/shared/components/mail/compose/encryptionRequirement.ts +2 -2
- package/apps/shared/components/mail/compose/quotedBody.ts +161 -161
- package/apps/shared/components/mail/compose/recipients.ts +1 -1
- package/apps/shared/components/mail/invite/InviteRowChip.tsx +2 -2
- package/apps/shared/components/mail/invite/InviteRsvpPopover.tsx +9 -7
- package/apps/shared/components/mail/invite/InviteTimeline.tsx +1 -1
- package/apps/shared/components/mail/invite/ProposeTimeForm.tsx +2 -2
- package/apps/shared/components/mail/invite/inviteFormat.ts +2 -2
- package/apps/shared/components/mail/invite/inviteStore.ts +14 -6
- package/apps/shared/components/mail/labelMenu.tsx +9 -7
- package/apps/shared/components/mail/layout/MailShell.tsx +4 -4
- package/apps/shared/components/mail/listPreferences.ts +2 -2
- package/apps/shared/components/mail/pinnedSigners.ts +45 -19
- package/apps/shared/components/mail/reading/EncryptedBody.tsx +2 -2
- package/apps/shared/components/mail/reading/MessageBody.tsx +6 -6
- package/apps/shared/components/mail/reading/MessageCard.tsx +3 -3
- package/apps/shared/components/mail/reading/MessageMoreMenu.tsx +258 -258
- package/apps/shared/components/mail/reading/MessageSourceDialog.tsx +79 -79
- package/apps/shared/components/mail/reading/PendingMessageCard.tsx +1 -1
- package/apps/shared/components/mail/reading/bodyContent.ts +3 -3
- package/apps/shared/components/mail/reading/bodyHtml.ts +1 -1
- package/apps/shared/components/mail/reading/messageExport.ts +59 -59
- package/apps/shared/components/mail/reading/printMessage.ts +99 -99
- package/apps/shared/components/mail/reading/useMessageActions.ts +450 -443
- package/apps/shared/components/mail/unreadStyle.tsx +1 -1
- package/apps/shared/components/mail/verificationSeals.ts +129 -125
- package/apps/shared/components/mail/writableMailboxes.ts +14 -7
- package/apps/shared/components/rules/RuleBuilder.tsx +311 -311
- package/apps/shared/components/settings/SigningCertificateCard.tsx +344 -344
- package/apps/shared/components/settings/layout/SettingsShell.tsx +8 -6
- package/apps/shared/components/sharing/PrincipalListField.tsx +1 -1
- package/apps/shared/components/sharing/PrincipalPicker.tsx +1 -1
- package/apps/shared/components/sharing/PrincipalResolver.tsx +4 -4
- package/apps/shared/components/tasks/TasksSidebar.tsx +7 -5
- package/apps/shared/components/tasks/layout/TasksShell.tsx +9 -7
- package/apps/shared/keyboard/GlobalShortcuts.tsx +51 -51
- package/apps/shared/keyboard/ShortcutProvider.tsx +62 -62
- package/apps/shared/keyboard/ShortcutsDialog.tsx +84 -84
- package/apps/shared/keyboard/dispatch.ts +124 -124
- package/apps/shared/keyboard/format.ts +89 -89
- package/apps/shared/keyboard/keymap.ts +114 -114
- package/apps/shared/keyboard/registry.ts +65 -65
- package/apps/shared/keyboard/targets.ts +79 -79
- package/apps/shared/mail/findWellKnownFolderUid.ts +6 -4
- package/apps/shared/mail/folderCounts.ts +8 -4
- package/apps/shared/mail/folderOfType.ts +51 -49
- package/apps/shared/mail/folderTree.ts +143 -143
- package/apps/shared/mail/listAllPages.ts +39 -39
- package/apps/shared/mail/listSnapshots.ts +2 -2
- package/apps/shared/mail/messageReadState.ts +6 -5
- package/apps/shared/mail/newMailNotifications.ts +171 -171
- package/apps/shared/mail/outbox/composeBridge.ts +2 -2
- package/apps/shared/mail/outbox/outboxState.ts +1 -1
- package/apps/shared/mail/outbox/outgoingReplies.ts +2 -2
- package/apps/shared/mail/outbox/sendDecision.ts +2 -2
- package/apps/shared/mail/outbox/sendJob.ts +450 -445
- package/apps/shared/mail/outbox/sendOutcomes.ts +160 -155
- package/apps/shared/mail/outbox/useOutboxStatus.ts +5 -3
- package/apps/shared/mail/permanentDelete.ts +8 -7
- package/apps/shared/mail/primaryMailbox.ts +1 -1
- package/apps/shared/mail/reportNotices.ts +66 -66
- package/apps/shared/mail/senderBlocking.ts +157 -141
- package/apps/shared/mail/useMailConnection.ts +207 -205
- package/apps/shared/mail/useMailLiveUpdates.ts +277 -277
- package/apps/shared/mail/useMailboxUpdateAccess.ts +84 -60
- package/apps/shared/mail/useMarkMessageRead.ts +54 -47
- package/apps/shared/mail/useNewMailNotifications.ts +178 -178
- package/apps/shared/mail/usePermanentDelete.tsx +5 -3
- package/apps/shared/navigation/pageTitle.ts +1 -1
- package/apps/shared/notifications/NotificationCenter.tsx +1 -1
- package/apps/shared/notifications/NotificationHistoryDialog.tsx +2 -2
- package/apps/shared/notifications/apiErrors.ts +2 -2
- package/apps/shared/notifications/pushStatus.ts +1 -1
- package/apps/shared/notifications/store.ts +560 -560
- package/apps/shared/notifications/systemErrors.ts +1 -1
- package/apps/shared/search/LocalIndexLifecycle.tsx +120 -114
- package/apps/shared/search/crossMailboxSearch.ts +3 -3
- package/apps/shared/search/localIndexBuilder.ts +493 -481
- package/apps/shared/search/localIndexKey.ts +1 -1
- package/apps/shared/search/localIndexRpcClient.ts +150 -30
- package/apps/shared/search/localIndexTransport.ts +84 -0
- package/apps/shared/search/localIndexWorker.ts +1 -1
- package/apps/shared/search/searchTier2.ts +3 -3
- package/apps/shared/signing/enrollmentStorage.ts +33 -33
- package/apps/shared/signing/enrollmentTracker.ts +385 -385
- package/apps/shared/signing/enrollmentView.ts +251 -251
- package/apps/shared/signing/signingInfo.ts +1 -1
- package/apps/shared/signing/useNow.ts +19 -19
- package/apps/shared/signing/useSigningEnrollmentWatcher.ts +92 -90
- package/apps/shared/styles/app.css +387 -396
- package/apps/www/_layout.tsx +2 -2
- package/apps/www/calendar/index.tsx +583 -581
- package/apps/www/contacts/[uid].tsx +114 -112
- package/apps/www/contacts/index.tsx +19 -17
- package/apps/www/index.tsx +3021 -3012
- package/apps/www/messages/[uid].tsx +141 -139
- package/apps/www/settings/auto-reply/index.tsx +138 -136
- package/apps/www/settings/blocked-senders/index.tsx +305 -303
- package/apps/www/settings/encryption/index.tsx +1296 -1290
- package/apps/www/settings/filters/[uid].tsx +184 -179
- package/apps/www/settings/filters/_mailFilterRuleConfig.tsx +2 -2
- package/apps/www/settings/filters/index.tsx +105 -105
- package/apps/www/settings/filters/new/index.tsx +167 -165
- package/apps/www/settings/labels/index.tsx +209 -207
- package/apps/www/settings/privacy/index.tsx +499 -495
- package/apps/www/settings/profile/index.tsx +256 -251
- package/apps/www/settings/read-receipts/index.tsx +155 -150
- package/apps/www/settings/sharing/index.tsx +259 -259
- package/apps/www/settings/signatures/[uid].tsx +175 -175
- package/apps/www/settings/signatures/index.tsx +91 -91
- package/apps/www/settings/signatures/new/index.tsx +138 -138
- package/apps/www/settings/signatures/signatureDefaults.ts +1 -1
- package/apps/www/tasks/index.tsx +659 -654
- package/dist/apps/admin/_layout.d.ts +1 -1
- package/dist/apps/admin/_layout.js +1 -1
- package/dist/apps/admin/audit-log/index.d.ts +1 -1
- package/dist/apps/admin/audit-log/index.js +4 -4
- package/dist/apps/admin/branding/index.js +3 -3
- package/dist/apps/admin/data-requests/index.js +8 -8
- package/dist/apps/admin/distribution-lists/[uid].js +3 -3
- package/dist/apps/admin/distribution-lists/index.js +4 -4
- package/dist/apps/admin/distribution-lists/new/index.js +5 -5
- package/dist/apps/admin/domains/[uid].js +6 -6
- package/dist/apps/admin/domains/index.js +4 -4
- package/dist/apps/admin/domains/new/index.js +5 -5
- package/dist/apps/admin/encryption-policy/index.js +1 -1
- package/dist/apps/admin/escrow-scopes/[uid].d.ts +1 -1
- package/dist/apps/admin/escrow-scopes/[uid].js +7 -7
- package/dist/apps/admin/escrow-scopes/index.js +4 -4
- package/dist/apps/admin/escrow-scopes/new/index.js +5 -5
- package/dist/apps/admin/index.js +6 -6
- package/dist/apps/admin/ingest-queue/index.js +4 -4
- package/dist/apps/admin/mailbox-policy/index.js +1 -1
- package/dist/apps/admin/mailboxes/[uid].js +5 -5
- package/dist/apps/admin/quarantine/index.js +5 -5
- package/dist/apps/admin/retention-policy/index.js +3 -3
- package/dist/apps/admin/signing-certificates/index.js +5 -5
- package/dist/apps/admin/transport-rules/[uid].js +5 -5
- package/dist/apps/admin/transport-rules/_transportRuleConfig.d.ts +1 -1
- package/dist/apps/admin/transport-rules/_transportRuleConfig.js +2 -2
- package/dist/apps/admin/transport-rules/index.js +4 -4
- package/dist/apps/admin/transport-rules/new/index.js +5 -5
- package/dist/apps/escrow/_layout.d.ts +1 -1
- package/dist/apps/escrow/audit-log/index.d.ts +1 -1
- package/dist/apps/escrow/audit-log/index.js +4 -4
- package/dist/apps/escrow/index.js +4 -4
- package/dist/apps/escrow/matters/[uid].js +10 -10
- package/dist/apps/escrow/matters/new/index.js +6 -6
- package/dist/apps/shared/appearance/AppearanceForm.js +3 -3
- package/dist/apps/shared/appearance/AppearanceHead.js +1 -1
- package/dist/apps/shared/appearance/AppearanceProvider.d.ts +1 -1
- package/dist/apps/shared/appearance/AppearanceProvider.js +3 -3
- package/dist/apps/shared/appearance/appearanceCache.d.ts +1 -1
- package/dist/apps/shared/appearance/appearanceCache.js +1 -1
- package/dist/apps/shared/appearance/appearanceContext.d.ts +1 -1
- package/dist/apps/shared/appearance/theme.d.ts +1 -1
- package/dist/apps/shared/auth/adminAccess.js +1 -1
- package/dist/apps/shared/calendar/bookingPlugin.js +1 -1
- package/dist/apps/shared/calendar/calendarLiveUpdates.d.ts +1 -1
- package/dist/apps/shared/calendar/calendarReminders.d.ts +1 -1
- package/dist/apps/shared/calendar/useCalendarReminders.js +1 -1
- package/dist/apps/shared/components/admin/diagnostics/DiagnosticsManager.js +1 -1
- package/dist/apps/shared/components/admin/diagnostics/InstalledPlugins.d.ts +1 -1
- package/dist/apps/shared/components/admin/diagnostics/InstalledPlugins.js +2 -2
- package/dist/apps/shared/components/admin/diagnostics/LogsPanel.js +2 -2
- package/dist/apps/shared/components/admin/diagnostics/PackagesTable.js +1 -1
- package/dist/apps/shared/components/admin/diagnostics/RuntimePanel.js +1 -1
- package/dist/apps/shared/components/admin/diagnostics/SystemPanel.js +2 -2
- package/dist/apps/shared/components/admin/diagnostics/VersionsPanel.js +1 -1
- package/dist/apps/shared/components/admin/diagnostics/diagnosticsApi.js +1 -1
- package/dist/apps/shared/components/admin/diagnostics/format.js +1 -1
- package/dist/apps/shared/components/admin/diagnostics/logClient.js +1 -1
- package/dist/apps/shared/components/admin/distributionLists/MemberListCard.d.ts +1 -1
- package/dist/apps/shared/components/admin/distributionLists/MemberListCard.js +4 -4
- package/dist/apps/shared/components/admin/elevation.js +1 -1
- package/dist/apps/shared/components/admin/escrowScopes/EscrowScopeKeyAndHoldersFields.js +3 -3
- package/dist/apps/shared/components/admin/layout/AdminShell.d.ts +1 -1
- package/dist/apps/shared/components/admin/layout/AdminShell.js +8 -8
- package/dist/apps/shared/components/admin/mailboxes/EraseLeftoverDataDialog.d.ts +1 -1
- package/dist/apps/shared/components/admin/mailboxes/EraseLeftoverDataDialog.js +6 -6
- package/dist/apps/shared/components/admin/mailboxes/EscrowScopeCard.d.ts +1 -1
- package/dist/apps/shared/components/admin/mailboxes/EscrowScopeCard.js +10 -8
- package/dist/apps/shared/components/admin/mailboxes/LeftoverMailboxesSection.js +4 -4
- package/dist/apps/shared/components/admin/mailboxes/MailboxTable.d.ts +1 -1
- package/dist/apps/shared/components/admin/mailboxes/ResourceSettingsCard.d.ts +1 -1
- package/dist/apps/shared/components/admin/mailboxes/ResourceSettingsCard.js +7 -5
- package/dist/apps/shared/components/admin/mailboxes/ShareAccessCard.js +5 -5
- package/dist/apps/shared/components/admin/settings/BrandingForm.d.ts +1 -1
- package/dist/apps/shared/components/admin/settings/BrandingForm.js +8 -8
- package/dist/apps/shared/components/admin/settings/DomainDnsSetup.d.ts +1 -1
- package/dist/apps/shared/components/admin/settings/DomainDnsSetup.js +5 -5
- package/dist/apps/shared/components/admin/settings/EncryptionPolicyForm.d.ts +1 -1
- package/dist/apps/shared/components/admin/settings/EncryptionPolicyForm.js +4 -4
- package/dist/apps/shared/components/admin/settings/LoadedSettingsForm.js +2 -2
- package/dist/apps/shared/components/admin/settings/MailboxCreateForm.d.ts +1 -1
- package/dist/apps/shared/components/admin/settings/MailboxCreateForm.js +14 -12
- package/dist/apps/shared/components/admin/settings/MailboxPolicyForm.d.ts +1 -1
- package/dist/apps/shared/components/admin/settings/MailboxPolicyForm.js +4 -4
- package/dist/apps/shared/components/admin/settings/PluginsManager.js +5 -5
- package/dist/apps/shared/components/admin/settings/RetentionPolicyForm.d.ts +1 -1
- package/dist/apps/shared/components/admin/settings/RetentionPolicyForm.js +5 -5
- package/dist/apps/shared/components/admin/setup/EscrowSetupStep.js +7 -7
- package/dist/apps/shared/components/admin/setup/SetupWizard.js +26 -22
- package/dist/apps/shared/components/admin/signOut.js +1 -1
- package/dist/apps/shared/components/admin/usePagedList.js +2 -2
- package/dist/apps/shared/components/calendar/AppointmentQuickForm.js +3 -3
- package/dist/apps/shared/components/calendar/CalendarListSidebar.d.ts +1 -1
- package/dist/apps/shared/components/calendar/CalendarListSidebar.js +2 -2
- package/dist/apps/shared/components/calendar/DescriptionEditor.js +1 -1
- package/dist/apps/shared/components/calendar/EventDescriptionView.js +1 -1
- package/dist/apps/shared/components/calendar/EventDetails.d.ts +2 -2
- package/dist/apps/shared/components/calendar/EventDetails.js +16 -14
- package/dist/apps/shared/components/calendar/EventEditor.d.ts +2 -2
- package/dist/apps/shared/components/calendar/EventEditor.js +22 -20
- package/dist/apps/shared/components/calendar/EventExpandedForm.js +2 -2
- package/dist/apps/shared/components/calendar/EventFormParts.d.ts +1 -1
- package/dist/apps/shared/components/calendar/EventFormParts.js +1 -1
- package/dist/apps/shared/components/calendar/EventModal.d.ts +2 -2
- package/dist/apps/shared/components/calendar/EventModal.js +3 -3
- package/dist/apps/shared/components/calendar/EventQuickForm.js +3 -3
- package/dist/apps/shared/components/calendar/EventShell.js +1 -1
- package/dist/apps/shared/components/calendar/FindATime.js +6 -4
- package/dist/apps/shared/components/calendar/GuestInput.d.ts +2 -2
- package/dist/apps/shared/components/calendar/MonthView.d.ts +1 -1
- package/dist/apps/shared/components/calendar/MonthView.js +1 -1
- package/dist/apps/shared/components/calendar/QuickCreateFaces.js +1 -1
- package/dist/apps/shared/components/calendar/QuickFaceFrame.js +1 -1
- package/dist/apps/shared/components/calendar/RecurrenceEditor.d.ts +1 -1
- package/dist/apps/shared/components/calendar/RecurrenceEditor.js +1 -1
- package/dist/apps/shared/components/calendar/RequestChangeForm.js +8 -6
- package/dist/apps/shared/components/calendar/ResourcePicker.d.ts +1 -1
- package/dist/apps/shared/components/calendar/ResourcePicker.js +7 -5
- package/dist/apps/shared/components/calendar/SplitDayView.d.ts +1 -1
- package/dist/apps/shared/components/calendar/TaskQuickForm.d.ts +1 -1
- package/dist/apps/shared/components/calendar/TaskQuickForm.js +9 -7
- package/dist/apps/shared/components/calendar/TimeGridView.d.ts +1 -1
- package/dist/apps/shared/components/calendar/TimeGridView.js +1 -1
- package/dist/apps/shared/components/calendar/allDay.d.ts +2 -2
- package/dist/apps/shared/components/calendar/allDay.js +1 -1
- package/dist/apps/shared/components/calendar/eventDialogFields.d.ts +2 -2
- package/dist/apps/shared/components/calendar/eventDialogFields.js +2 -2
- package/dist/apps/shared/components/calendar/eventForm.d.ts +3 -3
- package/dist/apps/shared/components/calendar/eventFormat.d.ts +1 -1
- package/dist/apps/shared/components/calendar/eventFormat.js +2 -2
- package/dist/apps/shared/components/calendar/findTimeGrid.d.ts +1 -1
- package/dist/apps/shared/components/calendar/findTimeGrid.js +1 -1
- package/dist/apps/shared/components/calendar/layout/CalendarShell.d.ts +1 -1
- package/dist/apps/shared/components/calendar/layout/CalendarShell.js +11 -9
- package/dist/apps/shared/components/contacts/ContactDetailPane.d.ts +1 -1
- package/dist/apps/shared/components/contacts/ContactDetailPane.js +2 -2
- package/dist/apps/shared/components/contacts/ContactForm.d.ts +2 -2
- package/dist/apps/shared/components/contacts/ContactForm.js +12 -8
- package/dist/apps/shared/components/contacts/ContactsSidebar.d.ts +1 -1
- package/dist/apps/shared/components/contacts/ContactsSidebar.js +7 -5
- package/dist/apps/shared/components/contacts/KeyChangeReview.d.ts +1 -1
- package/dist/apps/shared/components/contacts/KeyChangeReview.js +5 -5
- package/dist/apps/shared/components/contacts/contactKeys.d.ts +2 -2
- package/dist/apps/shared/components/contacts/contactKeys.js +2 -2
- package/dist/apps/shared/components/contacts/layout/ContactsShell.d.ts +1 -1
- package/dist/apps/shared/components/contacts/layout/ContactsShell.js +9 -7
- package/dist/apps/shared/components/escrow/layout/EscrowShell.js +7 -7
- package/dist/apps/shared/components/forms/StringListField.js +1 -1
- package/dist/apps/shared/components/layout/AppShell.d.ts +2 -2
- package/dist/apps/shared/components/layout/AppShell.js +14 -10
- package/dist/apps/shared/components/layout/BrandingChrome.d.ts +1 -1
- package/dist/apps/shared/components/layout/KeyEnrollmentGate.d.ts +1 -1
- package/dist/apps/shared/components/layout/KeyEnrollmentGate.js +9 -9
- package/dist/apps/shared/components/layout/MailboxProvisioning.js +8 -6
- package/dist/apps/shared/components/layout/RecoveryCodeUnlock.d.ts +1 -1
- package/dist/apps/shared/components/layout/RecoveryCodeUnlock.js +9 -9
- package/dist/apps/shared/components/layout/UnlockPromptProvider.d.ts +2 -2
- package/dist/apps/shared/components/layout/UnlockPromptProvider.js +5 -5
- package/dist/apps/shared/components/layout/UserMenu.js +6 -4
- package/dist/apps/shared/components/mail/ConversationList.d.ts +2 -2
- package/dist/apps/shared/components/mail/ConversationList.js +6 -4
- package/dist/apps/shared/components/mail/ConversationThreadPane.d.ts +3 -3
- package/dist/apps/shared/components/mail/ConversationThreadPane.js +13 -11
- package/dist/apps/shared/components/mail/InviteCard.js +10 -8
- package/dist/apps/shared/components/mail/LazyReadingPane.js +2 -2
- package/dist/apps/shared/components/mail/MailAddress.d.ts +1 -1
- package/dist/apps/shared/components/mail/MailAddress.js +1 -1
- package/dist/apps/shared/components/mail/MailListToolbar.d.ts +2 -2
- package/dist/apps/shared/components/mail/MailSelectionBar.d.ts +2 -2
- package/dist/apps/shared/components/mail/MenuButton.js +1 -1
- package/dist/apps/shared/components/mail/MessageDetailPane.d.ts +3 -3
- package/dist/apps/shared/components/mail/MessageDetailPane.js +30 -28
- package/dist/apps/shared/components/mail/MoveToFolderDialog.d.ts +1 -1
- package/dist/apps/shared/components/mail/MoveToFolderDialog.js +8 -6
- package/dist/apps/shared/components/mail/OutboxRowStatus.d.ts +1 -1
- package/dist/apps/shared/components/mail/PermanentDeleteDialog.js +2 -2
- package/dist/apps/shared/components/mail/compose/ComposeContext.d.ts +10 -1
- package/dist/apps/shared/components/mail/compose/ComposeContext.js +4 -2
- package/dist/apps/shared/components/mail/compose/ComposeWindow.d.ts +7 -1
- package/dist/apps/shared/components/mail/compose/ComposeWindow.js +54 -31
- package/dist/apps/shared/components/mail/compose/ComposeWindowPlaceholder.js +4 -4
- package/dist/apps/shared/components/mail/compose/EmojiPicker.js +2 -2
- package/dist/apps/shared/components/mail/compose/GifPicker.js +3 -3
- package/dist/apps/shared/components/mail/compose/RecipientInput.d.ts +1 -1
- package/dist/apps/shared/components/mail/compose/RecipientInput.js +1 -1
- package/dist/apps/shared/components/mail/compose/ScheduleSendPicker.js +1 -1
- package/dist/apps/shared/components/mail/compose/encryptionRequirement.d.ts +2 -2
- package/dist/apps/shared/components/mail/compose/encryptionRequirement.js +1 -1
- package/dist/apps/shared/components/mail/compose/quotedBody.d.ts +3 -3
- package/dist/apps/shared/components/mail/compose/quotedBody.js +3 -3
- package/dist/apps/shared/components/mail/compose/recipients.d.ts +1 -1
- package/dist/apps/shared/components/mail/invite/InviteRowChip.d.ts +1 -1
- package/dist/apps/shared/components/mail/invite/InviteRsvpPopover.d.ts +1 -1
- package/dist/apps/shared/components/mail/invite/InviteRsvpPopover.js +9 -7
- package/dist/apps/shared/components/mail/invite/InviteTimeline.d.ts +1 -1
- package/dist/apps/shared/components/mail/invite/ProposeTimeForm.d.ts +1 -1
- package/dist/apps/shared/components/mail/invite/ProposeTimeForm.js +1 -1
- package/dist/apps/shared/components/mail/invite/inviteFormat.d.ts +2 -2
- package/dist/apps/shared/components/mail/invite/inviteStore.d.ts +9 -3
- package/dist/apps/shared/components/mail/invite/inviteStore.js +13 -6
- package/dist/apps/shared/components/mail/labelMenu.d.ts +1 -1
- package/dist/apps/shared/components/mail/labelMenu.js +9 -7
- package/dist/apps/shared/components/mail/layout/MailShell.d.ts +1 -1
- package/dist/apps/shared/components/mail/layout/MailShell.js +3 -3
- package/dist/apps/shared/components/mail/listPreferences.d.ts +2 -2
- package/dist/apps/shared/components/mail/listPreferences.js +1 -1
- package/dist/apps/shared/components/mail/pinnedSigners.d.ts +12 -5
- package/dist/apps/shared/components/mail/pinnedSigners.js +37 -18
- package/dist/apps/shared/components/mail/reading/EncryptedBody.js +2 -2
- package/dist/apps/shared/components/mail/reading/MessageBody.d.ts +2 -2
- package/dist/apps/shared/components/mail/reading/MessageBody.js +4 -4
- package/dist/apps/shared/components/mail/reading/MessageCard.d.ts +1 -1
- package/dist/apps/shared/components/mail/reading/MessageCard.js +2 -2
- package/dist/apps/shared/components/mail/reading/MessageSourceDialog.js +3 -3
- package/dist/apps/shared/components/mail/reading/PendingMessageCard.js +1 -1
- package/dist/apps/shared/components/mail/reading/bodyContent.d.ts +2 -2
- package/dist/apps/shared/components/mail/reading/bodyContent.js +2 -2
- package/dist/apps/shared/components/mail/reading/bodyHtml.js +1 -1
- package/dist/apps/shared/components/mail/reading/messageExport.js +1 -1
- package/dist/apps/shared/components/mail/reading/printMessage.d.ts +2 -2
- package/dist/apps/shared/components/mail/reading/printMessage.js +11 -11
- package/dist/apps/shared/components/mail/reading/useMessageActions.d.ts +1 -1
- package/dist/apps/shared/components/mail/reading/useMessageActions.js +18 -16
- package/dist/apps/shared/components/mail/unreadStyle.d.ts +1 -1
- package/dist/apps/shared/components/mail/verificationSeals.d.ts +27 -6
- package/dist/apps/shared/components/mail/verificationSeals.js +15 -11
- package/dist/apps/shared/components/mail/writableMailboxes.d.ts +8 -3
- package/dist/apps/shared/components/mail/writableMailboxes.js +12 -6
- package/dist/apps/shared/components/rules/RuleBuilder.js +1 -1
- package/dist/apps/shared/components/settings/SigningCertificateCard.d.ts +1 -1
- package/dist/apps/shared/components/settings/SigningCertificateCard.js +3 -3
- package/dist/apps/shared/components/settings/layout/SettingsShell.d.ts +1 -1
- package/dist/apps/shared/components/settings/layout/SettingsShell.js +8 -6
- package/dist/apps/shared/components/sharing/PrincipalListField.d.ts +1 -1
- package/dist/apps/shared/components/sharing/PrincipalPicker.d.ts +1 -1
- package/dist/apps/shared/components/sharing/PrincipalPicker.js +1 -1
- package/dist/apps/shared/components/sharing/PrincipalResolver.d.ts +1 -1
- package/dist/apps/shared/components/sharing/PrincipalResolver.js +3 -3
- package/dist/apps/shared/components/tasks/TasksSidebar.d.ts +1 -1
- package/dist/apps/shared/components/tasks/TasksSidebar.js +7 -5
- package/dist/apps/shared/components/tasks/layout/TasksShell.d.ts +1 -1
- package/dist/apps/shared/components/tasks/layout/TasksShell.js +9 -7
- package/dist/apps/shared/keyboard/ShortcutsDialog.js +1 -1
- package/dist/apps/shared/mail/findWellKnownFolderUid.d.ts +5 -3
- package/dist/apps/shared/mail/findWellKnownFolderUid.js +5 -4
- package/dist/apps/shared/mail/folderCounts.d.ts +1 -1
- package/dist/apps/shared/mail/folderCounts.js +6 -4
- package/dist/apps/shared/mail/folderOfType.d.ts +3 -2
- package/dist/apps/shared/mail/folderOfType.js +4 -4
- package/dist/apps/shared/mail/folderTree.d.ts +1 -1
- package/dist/apps/shared/mail/listSnapshots.d.ts +2 -2
- package/dist/apps/shared/mail/messageReadState.d.ts +4 -3
- package/dist/apps/shared/mail/messageReadState.js +5 -5
- package/dist/apps/shared/mail/newMailNotifications.d.ts +1 -1
- package/dist/apps/shared/mail/newMailNotifications.js +1 -1
- package/dist/apps/shared/mail/outbox/composeBridge.d.ts +2 -2
- package/dist/apps/shared/mail/outbox/outboxState.d.ts +1 -1
- package/dist/apps/shared/mail/outbox/outgoingReplies.d.ts +2 -2
- package/dist/apps/shared/mail/outbox/sendDecision.d.ts +2 -2
- package/dist/apps/shared/mail/outbox/sendDecision.js +1 -1
- package/dist/apps/shared/mail/outbox/sendJob.d.ts +10 -6
- package/dist/apps/shared/mail/outbox/sendJob.js +39 -35
- package/dist/apps/shared/mail/outbox/sendOutcomes.d.ts +6 -3
- package/dist/apps/shared/mail/outbox/sendOutcomes.js +19 -15
- package/dist/apps/shared/mail/outbox/useOutboxStatus.js +5 -3
- package/dist/apps/shared/mail/permanentDelete.d.ts +4 -3
- package/dist/apps/shared/mail/permanentDelete.js +8 -8
- package/dist/apps/shared/mail/primaryMailbox.d.ts +1 -1
- package/dist/apps/shared/mail/primaryMailbox.js +1 -1
- package/dist/apps/shared/mail/reportNotices.d.ts +1 -1
- package/dist/apps/shared/mail/senderBlocking.d.ts +5 -4
- package/dist/apps/shared/mail/senderBlocking.js +19 -16
- package/dist/apps/shared/mail/useMailConnection.d.ts +1 -1
- package/dist/apps/shared/mail/useMailConnection.js +12 -10
- package/dist/apps/shared/mail/useMailLiveUpdates.d.ts +2 -2
- package/dist/apps/shared/mail/useMailLiveUpdates.js +2 -2
- package/dist/apps/shared/mail/useMailboxUpdateAccess.d.ts +3 -2
- package/dist/apps/shared/mail/useMailboxUpdateAccess.js +31 -10
- package/dist/apps/shared/mail/useMarkMessageRead.d.ts +1 -1
- package/dist/apps/shared/mail/useMarkMessageRead.js +5 -3
- package/dist/apps/shared/mail/useNewMailNotifications.d.ts +1 -1
- package/dist/apps/shared/mail/usePermanentDelete.d.ts +1 -1
- package/dist/apps/shared/mail/usePermanentDelete.js +4 -2
- package/dist/apps/shared/navigation/pageTitle.d.ts +1 -1
- package/dist/apps/shared/notifications/NotificationCenter.js +1 -1
- package/dist/apps/shared/notifications/NotificationHistoryDialog.js +2 -2
- package/dist/apps/shared/notifications/apiErrors.js +2 -2
- package/dist/apps/shared/notifications/pushStatus.js +1 -1
- package/dist/apps/shared/notifications/systemErrors.js +1 -1
- package/dist/apps/shared/search/LocalIndexLifecycle.d.ts +2 -2
- package/dist/apps/shared/search/LocalIndexLifecycle.js +15 -10
- package/dist/apps/shared/search/crossMailboxSearch.d.ts +1 -1
- package/dist/apps/shared/search/crossMailboxSearch.js +2 -2
- package/dist/apps/shared/search/localIndexBuilder.d.ts +4 -3
- package/dist/apps/shared/search/localIndexBuilder.js +15 -12
- package/dist/apps/shared/search/localIndexKey.js +1 -1
- package/dist/apps/shared/search/localIndexRpcClient.d.ts +43 -31
- package/dist/apps/shared/search/localIndexRpcClient.js +113 -20
- package/dist/apps/shared/search/localIndexTransport.d.ts +77 -0
- package/dist/apps/shared/search/localIndexTransport.js +1 -0
- package/dist/apps/shared/search/localIndexWorker.d.ts +1 -1
- package/dist/apps/shared/search/searchTier2.d.ts +3 -3
- package/dist/apps/shared/signing/enrollmentTracker.d.ts +1 -1
- package/dist/apps/shared/signing/enrollmentTracker.js +3 -3
- package/dist/apps/shared/signing/enrollmentView.d.ts +1 -1
- package/dist/apps/shared/signing/signingInfo.d.ts +1 -1
- package/dist/apps/shared/signing/signingInfo.js +1 -1
- package/dist/apps/shared/signing/useSigningEnrollmentWatcher.d.ts +1 -1
- package/dist/apps/shared/signing/useSigningEnrollmentWatcher.js +5 -3
- package/dist/apps/shared/styles/app.css +387 -396
- package/dist/apps/www/_layout.d.ts +1 -1
- package/dist/apps/www/_layout.js +1 -1
- package/dist/apps/www/calendar/index.d.ts +1 -1
- package/dist/apps/www/calendar/index.js +20 -18
- package/dist/apps/www/contacts/[uid].d.ts +1 -1
- package/dist/apps/www/contacts/[uid].js +8 -6
- package/dist/apps/www/contacts/index.d.ts +1 -1
- package/dist/apps/www/contacts/index.js +19 -17
- package/dist/apps/www/index.d.ts +1 -1
- package/dist/apps/www/index.js +54 -50
- package/dist/apps/www/messages/[uid].d.ts +1 -1
- package/dist/apps/www/messages/[uid].js +11 -9
- package/dist/apps/www/settings/appearance/index.d.ts +1 -1
- package/dist/apps/www/settings/auto-reply/index.d.ts +1 -1
- package/dist/apps/www/settings/auto-reply/index.js +6 -4
- package/dist/apps/www/settings/blocked-senders/index.d.ts +1 -1
- package/dist/apps/www/settings/blocked-senders/index.js +6 -4
- package/dist/apps/www/settings/encryption/index.d.ts +1 -1
- package/dist/apps/www/settings/encryption/index.js +31 -29
- package/dist/apps/www/settings/filters/[uid].d.ts +1 -1
- package/dist/apps/www/settings/filters/[uid].js +11 -9
- package/dist/apps/www/settings/filters/_mailFilterRuleConfig.d.ts +2 -2
- package/dist/apps/www/settings/filters/index.d.ts +1 -1
- package/dist/apps/www/settings/filters/index.js +4 -4
- package/dist/apps/www/settings/filters/new/index.d.ts +1 -1
- package/dist/apps/www/settings/filters/new/index.js +10 -8
- package/dist/apps/www/settings/labels/index.d.ts +1 -1
- package/dist/apps/www/settings/labels/index.js +12 -10
- package/dist/apps/www/settings/privacy/index.d.ts +1 -1
- package/dist/apps/www/settings/privacy/index.js +18 -14
- package/dist/apps/www/settings/profile/index.d.ts +1 -1
- package/dist/apps/www/settings/profile/index.js +7 -5
- package/dist/apps/www/settings/read-receipts/index.d.ts +1 -1
- package/dist/apps/www/settings/read-receipts/index.js +5 -3
- package/dist/apps/www/settings/sharing/index.d.ts +1 -1
- package/dist/apps/www/settings/sharing/index.js +6 -6
- package/dist/apps/www/settings/signatures/[uid].d.ts +1 -1
- package/dist/apps/www/settings/signatures/[uid].js +5 -5
- package/dist/apps/www/settings/signatures/index.d.ts +1 -1
- package/dist/apps/www/settings/signatures/index.js +4 -4
- package/dist/apps/www/settings/signatures/new/index.d.ts +1 -1
- package/dist/apps/www/settings/signatures/new/index.js +4 -4
- package/dist/apps/www/settings/signatures/signatureDefaults.d.ts +1 -1
- package/dist/apps/www/settings/signatures/signatureDefaults.js +1 -1
- package/dist/apps/www/tasks/index.d.ts +1 -1
- package/dist/apps/www/tasks/index.js +17 -15
- package/dist/lib/admin/auditLogApi.d.ts +32 -0
- package/dist/lib/admin/auditLogApi.js +27 -0
- package/dist/lib/admin/distributionListsApi.d.ts +47 -0
- package/dist/lib/admin/distributionListsApi.js +34 -0
- package/dist/lib/admin/domainsApi.d.ts +75 -0
- package/dist/lib/admin/domainsApi.js +44 -0
- package/dist/lib/admin/escrowAccessRequestsApi.d.ts +79 -0
- package/dist/lib/admin/escrowAccessRequestsApi.js +46 -0
- package/dist/lib/admin/escrowAuditLogApi.d.ts +66 -0
- package/dist/lib/admin/escrowAuditLogApi.js +31 -0
- package/dist/lib/admin/escrowScopesApi.d.ts +78 -0
- package/dist/lib/admin/escrowScopesApi.js +50 -0
- package/dist/lib/admin/leftoverMailboxApi.d.ts +73 -0
- package/dist/lib/admin/leftoverMailboxApi.js +67 -0
- package/dist/lib/admin/mailboxPolicyApi.d.ts +27 -0
- package/dist/lib/admin/mailboxPolicyApi.js +21 -0
- package/dist/lib/admin/matterExportApi.d.ts +40 -0
- package/dist/lib/admin/matterExportApi.js +39 -0
- package/dist/lib/admin/matterSearchApi.d.ts +20 -0
- package/dist/lib/admin/matterSearchApi.js +27 -0
- package/dist/lib/admin/mattersApi.d.ts +56 -0
- package/dist/lib/admin/mattersApi.js +40 -0
- package/dist/lib/admin/pluginsApi.d.ts +265 -0
- package/dist/lib/admin/pluginsApi.js +102 -0
- package/dist/lib/admin/retentionPolicyApi.d.ts +32 -0
- package/dist/lib/admin/retentionPolicyApi.js +29 -0
- package/dist/lib/admin/setupApi.d.ts +23 -0
- package/dist/lib/admin/setupApi.js +26 -0
- package/dist/lib/admin/transportRulesApi.d.ts +66 -0
- package/dist/lib/admin/transportRulesApi.js +43 -0
- package/dist/lib/appearance/preferencesApi.d.ts +128 -0
- package/dist/lib/appearance/preferencesApi.js +257 -0
- package/dist/lib/auth/profileApi.d.ts +33 -0
- package/dist/lib/auth/profileApi.js +52 -0
- package/dist/lib/auth/session.d.ts +70 -0
- package/dist/lib/auth/session.js +210 -0
- package/dist/lib/branding/brandingApi.d.ts +47 -0
- package/dist/lib/branding/brandingApi.js +61 -0
- package/dist/lib/branding/useBranding.d.ts +23 -0
- package/dist/lib/branding/useBranding.js +65 -0
- package/dist/lib/calendar/calendarApi.d.ts +230 -0
- package/dist/lib/calendar/calendarApi.js +106 -0
- package/dist/lib/calendar/calendarColors.d.ts +18 -0
- package/dist/lib/calendar/calendarColors.js +39 -0
- package/dist/lib/calendar/calendarDragIds.d.ts +42 -0
- package/dist/lib/calendar/calendarDragIds.js +92 -0
- package/dist/lib/calendar/calendarMutations.d.ts +68 -0
- package/dist/lib/calendar/calendarMutations.js +190 -0
- package/dist/lib/calendar/eventDescription.d.ts +43 -0
- package/dist/lib/calendar/eventDescription.js +195 -0
- package/dist/lib/calendar/freeBusyApi.d.ts +100 -0
- package/dist/lib/calendar/freeBusyApi.js +119 -0
- package/dist/lib/calendar/inviteApi.d.ts +121 -0
- package/dist/lib/calendar/inviteApi.js +54 -0
- package/dist/lib/calendar/recurrence.d.ts +60 -0
- package/dist/lib/calendar/recurrence.js +225 -0
- package/dist/lib/components/avatar/ContactAvatar.d.ts +8 -0
- package/dist/lib/components/avatar/ContactAvatar.js +26 -0
- package/dist/lib/components/buttons/Button.d.ts +9 -0
- package/dist/lib/components/buttons/Button.js +14 -0
- package/dist/lib/components/buttons/CopyButton.d.ts +18 -0
- package/dist/lib/components/buttons/CopyButton.js +14 -0
- package/dist/lib/components/feedback/Alert.d.ts +4 -0
- package/dist/lib/components/feedback/Alert.js +4 -0
- package/dist/lib/components/feedback/Skeleton.d.ts +21 -0
- package/dist/lib/components/feedback/Skeleton.js +14 -0
- package/dist/lib/components/forms/FormField.d.ts +8 -0
- package/dist/lib/components/forms/FormField.js +5 -0
- package/dist/lib/components/navigation/BottomTabBar.d.ts +27 -0
- package/dist/lib/components/navigation/BottomTabBar.js +32 -0
- package/dist/lib/components/overlays/Drawer.d.ts +20 -0
- package/dist/lib/components/overlays/Drawer.js +27 -0
- package/dist/lib/components/overlays/Modal.d.ts +17 -0
- package/dist/lib/components/overlays/Modal.js +25 -0
- package/dist/lib/components/overlays/PopoverPortal.d.ts +23 -0
- package/dist/lib/components/overlays/PopoverPortal.js +53 -0
- package/dist/lib/components/overlays/overlayStack.d.ts +31 -0
- package/dist/lib/components/overlays/overlayStack.js +143 -0
- package/dist/lib/components/pickers/MiniDatePicker.d.ts +13 -0
- package/dist/lib/components/pickers/MiniDatePicker.js +42 -0
- package/dist/lib/contacts/contactsApi.d.ts +174 -0
- package/dist/lib/contacts/contactsApi.js +139 -0
- package/dist/lib/contacts/vcard.d.ts +23 -0
- package/dist/lib/contacts/vcard.js +179 -0
- package/dist/lib/crypto/composeSecurity.d.ts +67 -0
- package/dist/lib/crypto/composeSecurity.js +93 -0
- package/dist/lib/crypto/encoding.d.ts +9 -0
- package/dist/lib/crypto/encoding.js +32 -0
- package/dist/lib/crypto/escrowKeys.d.ts +25 -0
- package/dist/lib/crypto/escrowKeys.js +59 -0
- package/dist/lib/crypto/idleTimeout.d.ts +16 -0
- package/dist/lib/crypto/idleTimeout.js +47 -0
- package/dist/lib/crypto/keySession.d.ts +159 -0
- package/dist/lib/crypto/keySession.js +367 -0
- package/dist/lib/crypto/keys.d.ts +50 -0
- package/dist/lib/crypto/keys.js +89 -0
- package/dist/lib/crypto/keyvaultApi.d.ts +394 -0
- package/dist/lib/crypto/keyvaultApi.js +350 -0
- package/dist/lib/crypto/masterKey.d.ts +59 -0
- package/dist/lib/crypto/masterKey.js +104 -0
- package/dist/lib/crypto/masterKeyWraps.d.ts +108 -0
- package/dist/lib/crypto/masterKeyWraps.js +228 -0
- package/dist/lib/crypto/messageSecurity.d.ts +248 -0
- package/dist/lib/crypto/messageSecurity.js +367 -0
- package/dist/lib/crypto/mime.d.ts +143 -0
- package/dist/lib/crypto/mime.js +504 -0
- package/dist/lib/crypto/passkeyUnlock.d.ts +20 -0
- package/dist/lib/crypto/passkeyUnlock.js +79 -0
- package/dist/lib/crypto/passwordUnlock.d.ts +39 -0
- package/dist/lib/crypto/passwordUnlock.js +73 -0
- package/dist/lib/crypto/recoveryCode.d.ts +28 -0
- package/dist/lib/crypto/recoveryCode.js +86 -0
- package/dist/lib/crypto/signingProviderApi.d.ts +95 -0
- package/dist/lib/crypto/signingProviderApi.js +60 -0
- package/dist/lib/crypto/smime.d.ts +128 -0
- package/dist/lib/crypto/smime.js +402 -0
- package/dist/lib/crypto/smimeMessage.d.ts +132 -0
- package/dist/lib/crypto/smimeMessage.js +341 -0
- package/dist/lib/crypto/useIdleKeyTimeout.d.ts +10 -0
- package/dist/lib/crypto/useIdleKeyTimeout.js +163 -0
- package/dist/lib/crypto/verificationSeal.d.ts +56 -0
- package/dist/lib/crypto/verificationSeal.js +220 -0
- package/dist/lib/mail/compose/composeQuoting.d.ts +88 -0
- package/dist/lib/mail/compose/composeQuoting.js +204 -0
- package/dist/lib/mail/compose/emojiData.d.ts +9 -0
- package/dist/lib/mail/compose/emojiData.js +18 -0
- package/dist/lib/mail/compose/giphyApi.d.ts +17 -0
- package/dist/lib/mail/compose/giphyApi.js +20 -0
- package/dist/lib/mail/conversationsApi.d.ts +80 -0
- package/dist/lib/mail/conversationsApi.js +44 -0
- package/dist/lib/mail/dataExportApi.d.ts +50 -0
- package/dist/lib/mail/dataExportApi.js +40 -0
- package/dist/lib/mail/directoryApi.d.ts +49 -0
- package/dist/lib/mail/directoryApi.js +101 -0
- package/dist/lib/mail/erasureRequestApi.d.ts +45 -0
- package/dist/lib/mail/erasureRequestApi.js +43 -0
- package/dist/lib/mail/flaggedMessages.d.ts +22 -0
- package/dist/lib/mail/flaggedMessages.js +73 -0
- package/dist/lib/mail/focusedInboxOverridesApi.d.ts +37 -0
- package/dist/lib/mail/focusedInboxOverridesApi.js +34 -0
- package/dist/lib/mail/labelsApi.d.ts +47 -0
- package/dist/lib/mail/labelsApi.js +38 -0
- package/dist/lib/mail/mailAddress.d.ts +27 -0
- package/dist/lib/mail/mailAddress.js +54 -0
- package/dist/lib/mail/mailApi.d.ts +850 -0
- package/dist/lib/mail/mailApi.js +602 -0
- package/dist/lib/mail/mailDetailHooks.d.ts +10 -0
- package/dist/lib/mail/mailDetailHooks.js +53 -0
- package/dist/lib/mail/mailFilterRulesApi.d.ts +76 -0
- package/dist/lib/mail/mailFilterRulesApi.js +45 -0
- package/dist/lib/mail/mailSignaturesApi.d.ts +49 -0
- package/dist/lib/mail/mailSignaturesApi.js +42 -0
- package/dist/lib/mail/mailboxAccessApi.d.ts +74 -0
- package/dist/lib/mail/mailboxAccessApi.js +56 -0
- package/dist/lib/mail/mailboxImportApi.d.ts +53 -0
- package/dist/lib/mail/mailboxImportApi.js +51 -0
- package/dist/lib/mail/messageBodySanitizer.d.ts +16 -0
- package/dist/lib/mail/messageBodySanitizer.js +118 -0
- package/dist/lib/mail/pushClient.d.ts +106 -0
- package/dist/lib/mail/pushClient.js +317 -0
- package/dist/lib/mail/sendEvents.d.ts +33 -0
- package/dist/lib/mail/sendEvents.js +44 -0
- package/dist/lib/mail/sendFailure.d.ts +16 -0
- package/dist/lib/mail/sendFailure.js +86 -0
- package/dist/lib/mail/senderListsApi.d.ts +69 -0
- package/dist/lib/mail/senderListsApi.js +126 -0
- package/dist/lib/search/queryGrammar.d.ts +51 -0
- package/dist/lib/search/queryGrammar.js +111 -0
- package/dist/lib/search/searchApi.d.ts +100 -0
- package/dist/lib/search/searchApi.js +107 -0
- package/dist/lib/search/searchScoring.d.ts +34 -0
- package/dist/lib/search/searchScoring.js +44 -0
- package/dist/lib/search/searchTier3.d.ts +64 -0
- package/dist/lib/search/searchTier3.js +335 -0
- package/dist/lib/tasks/tasksApi.d.ts +85 -0
- package/dist/lib/tasks/tasksApi.js +55 -0
- package/dist/lib/util/api.d.ts +160 -0
- package/dist/lib/util/api.js +251 -0
- package/dist/lib/util/apiClientContext.d.ts +7 -0
- package/dist/lib/util/apiClientContext.js +32 -0
- package/dist/lib/util/apiQuery.d.ts +32 -0
- package/dist/lib/util/apiQuery.js +42 -0
- package/dist/lib/util/clipboard.d.ts +7 -0
- package/dist/lib/util/clipboard.js +56 -0
- package/dist/lib/util/dateInput.d.ts +6 -0
- package/dist/lib/util/dateInput.js +14 -0
- package/dist/lib/util/timeZone.d.ts +12 -0
- package/dist/lib/util/timeZone.js +32 -0
- package/dist/lib/util/useCopyToClipboard.d.ts +12 -0
- package/dist/lib/util/useCopyToClipboard.js +34 -0
- package/dist/lib/util/useIsMobile.d.ts +10 -0
- package/dist/lib/util/useIsMobile.js +29 -0
- package/dist/lib/videoconf/videoMeetingsApi.d.ts +116 -0
- package/dist/lib/videoconf/videoMeetingsApi.js +49 -0
- package/lib/admin/auditLogApi.ts +48 -0
- package/lib/admin/distributionListsApi.ts +77 -0
- package/lib/admin/domainsApi.ts +113 -0
- package/lib/admin/escrowAccessRequestsApi.ts +110 -0
- package/lib/admin/escrowAuditLogApi.ts +101 -0
- package/lib/admin/escrowScopesApi.ts +112 -0
- package/lib/admin/leftoverMailboxApi.ts +120 -0
- package/lib/admin/mailboxPolicyApi.ts +38 -0
- package/lib/admin/matterExportApi.ts +62 -0
- package/lib/admin/matterSearchApi.ts +35 -0
- package/lib/admin/mattersApi.ts +86 -0
- package/lib/admin/pluginsApi.ts +339 -0
- package/lib/admin/retentionPolicyApi.ts +46 -0
- package/lib/admin/setupApi.ts +40 -0
- package/lib/admin/transportRulesApi.ts +106 -0
- package/lib/appearance/preferencesApi.ts +335 -0
- package/lib/auth/profileApi.ts +77 -0
- package/lib/auth/session.ts +238 -0
- package/lib/branding/brandingApi.ts +97 -0
- package/lib/branding/useBranding.ts +81 -0
- package/lib/calendar/calendarApi.ts +309 -0
- package/lib/calendar/calendarColors.ts +45 -0
- package/lib/calendar/calendarDragIds.ts +112 -0
- package/lib/calendar/calendarMutations.ts +236 -0
- package/lib/calendar/eventDescription.ts +211 -0
- package/lib/calendar/freeBusyApi.ts +197 -0
- package/lib/calendar/inviteApi.ts +154 -0
- package/lib/calendar/recurrence.ts +285 -0
- package/lib/components/avatar/ContactAvatar.tsx +47 -0
- package/lib/components/buttons/Button.tsx +40 -0
- package/lib/components/buttons/CopyButton.tsx +45 -0
- package/lib/components/feedback/Alert.tsx +13 -0
- package/lib/components/feedback/Skeleton.tsx +38 -0
- package/lib/components/forms/FormField.tsx +23 -0
- package/lib/components/navigation/BottomTabBar.tsx +66 -0
- package/lib/components/overlays/Drawer.tsx +72 -0
- package/lib/components/overlays/Modal.tsx +64 -0
- package/lib/components/overlays/PopoverPortal.tsx +74 -0
- package/lib/components/overlays/overlayStack.ts +165 -0
- package/lib/components/pickers/MiniDatePicker.tsx +90 -0
- package/lib/contacts/contactsApi.ts +289 -0
- package/lib/contacts/vcard.ts +197 -0
- package/lib/crypto/composeSecurity.ts +140 -0
- package/lib/crypto/encoding.ts +36 -0
- package/lib/crypto/escrowKeys.ts +74 -0
- package/lib/crypto/idleTimeout.ts +49 -0
- package/lib/crypto/keySession.ts +483 -0
- package/lib/crypto/keys.ts +105 -0
- package/lib/crypto/keyvaultApi.ts +674 -0
- package/lib/crypto/masterKey.ts +134 -0
- package/lib/crypto/masterKeyWraps.ts +269 -0
- package/lib/crypto/messageSecurity.ts +600 -0
- package/lib/crypto/mime.ts +568 -0
- package/lib/crypto/passkeyUnlock.ts +103 -0
- package/lib/crypto/passwordUnlock.ts +98 -0
- package/lib/crypto/recoveryCode.ts +93 -0
- package/lib/crypto/signingProviderApi.ts +135 -0
- package/lib/crypto/smime.ts +459 -0
- package/lib/crypto/smimeMessage.ts +491 -0
- package/lib/crypto/useIdleKeyTimeout.ts +176 -0
- package/lib/crypto/verificationSeal.ts +288 -0
- package/lib/mail/compose/composeQuoting.ts +243 -0
- package/lib/mail/compose/emojiData.ts +34 -0
- package/lib/mail/compose/giphyApi.ts +31 -0
- package/lib/mail/conversationsApi.ts +123 -0
- package/lib/mail/dataExportApi.ts +73 -0
- package/lib/mail/directoryApi.ts +161 -0
- package/lib/mail/erasureRequestApi.ts +71 -0
- package/lib/mail/flaggedMessages.ts +80 -0
- package/lib/mail/focusedInboxOverridesApi.ts +64 -0
- package/lib/mail/labelsApi.ts +71 -0
- package/lib/mail/mailAddress.ts +76 -0
- package/lib/mail/mailApi.ts +1286 -0
- package/lib/mail/mailDetailHooks.ts +57 -0
- package/lib/mail/mailFilterRulesApi.ts +116 -0
- package/lib/mail/mailSignaturesApi.ts +84 -0
- package/lib/mail/mailboxAccessApi.ts +106 -0
- package/lib/mail/mailboxImportApi.ts +87 -0
- package/lib/mail/messageBodySanitizer.ts +129 -0
- package/lib/mail/pushClient.ts +375 -0
- package/lib/mail/sendEvents.ts +72 -0
- package/lib/mail/sendFailure.ts +98 -0
- package/lib/mail/senderListsApi.ts +161 -0
- package/lib/search/queryGrammar.ts +179 -0
- package/lib/search/searchApi.ts +199 -0
- package/lib/search/searchScoring.ts +46 -0
- package/lib/search/searchTier3.ts +406 -0
- package/lib/tasks/tasksApi.ts +128 -0
- package/lib/util/api.ts +318 -0
- package/lib/util/apiClientContext.ts +35 -0
- package/lib/util/apiQuery.ts +61 -0
- package/lib/util/clipboard.ts +55 -0
- package/lib/util/dateInput.ts +15 -0
- package/lib/util/timeZone.ts +33 -0
- package/lib/util/useCopyToClipboard.ts +48 -0
- package/lib/util/useIsMobile.ts +34 -0
- package/lib/videoconf/videoMeetingsApi.ts +144 -0
- package/package.json +10 -4
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
// Copyright (C) 2026 Jean-Philippe Steinmetz
|
|
3
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
5
|
+
/** Typed wrappers over `@rapidmx/restapi`'s `/mail/contacts` REST surface — see `mailApi.ts`'s own header
|
|
6
|
+
* comment for the shared ACL/authorization model every wrapper file here follows. */
|
|
7
|
+
|
|
8
|
+
import { ApiClient, withClient } from "../util/api.js";
|
|
9
|
+
import { ListParams, buildQuery } from "../util/apiQuery.js";
|
|
10
|
+
import {
|
|
11
|
+
type EncryptionPreference,
|
|
12
|
+
type KeyConflict,
|
|
13
|
+
type PreviousKey,
|
|
14
|
+
type PublicKey,
|
|
15
|
+
type RejectedKey,
|
|
16
|
+
signingKeyFingerprints,
|
|
17
|
+
} from "../crypto/keyvaultApi.js";
|
|
18
|
+
|
|
19
|
+
export type ContactAddressKind = "home" | "work" | "other";
|
|
20
|
+
|
|
21
|
+
export interface ContactEmail {
|
|
22
|
+
address: string;
|
|
23
|
+
type: ContactAddressKind;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface ContactPhone {
|
|
27
|
+
phoneNumber: string;
|
|
28
|
+
type: ContactAddressKind;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface ContactPostalAddress {
|
|
32
|
+
street?: string;
|
|
33
|
+
city?: string;
|
|
34
|
+
state?: string;
|
|
35
|
+
postalCode?: string;
|
|
36
|
+
country?: string;
|
|
37
|
+
type: ContactAddressKind;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface Contact {
|
|
41
|
+
uid: string;
|
|
42
|
+
version: number;
|
|
43
|
+
dateCreated: string;
|
|
44
|
+
dateModified: string;
|
|
45
|
+
mailboxUid: string;
|
|
46
|
+
folderUid: string;
|
|
47
|
+
/** The `ContactList` (group) this contact belongs to, if any. */
|
|
48
|
+
contactListUid?: string;
|
|
49
|
+
displayName: string;
|
|
50
|
+
givenName?: string;
|
|
51
|
+
surname?: string;
|
|
52
|
+
emails: ContactEmail[];
|
|
53
|
+
phones: ContactPhone[];
|
|
54
|
+
addresses: ContactPostalAddress[];
|
|
55
|
+
company?: string;
|
|
56
|
+
jobTitle?: string;
|
|
57
|
+
notes?: string;
|
|
58
|
+
photoBlobKey?: string;
|
|
59
|
+
sourceUid?: string;
|
|
60
|
+
/** Whether the caller has starred/favorited this contact. Absent is equivalent to `false`. */
|
|
61
|
+
favorite?: boolean;
|
|
62
|
+
/** Free-form category labels (Outlook-style colored categories) applied to this contact, if any. */
|
|
63
|
+
categories?: string[];
|
|
64
|
+
/** Present (and `true`) only when fetched via `listDeletedContacts()` — a soft-deleted `RecoverableBaseEntity`
|
|
65
|
+
* record still exists server-side so it can be restored, per `@rapidmx/restapi`'s own soft-delete model. */
|
|
66
|
+
deleted?: boolean;
|
|
67
|
+
/** This contact's known encryption preference, per `specs/end-to-end_encryption.md` — discovered
|
|
68
|
+
* via `crypto/keyvaultApi.ts`'s `lookupKeys()` at compose time, never fetched on message receipt
|
|
69
|
+
* (that would leak read timing to the sender's server). */
|
|
70
|
+
encryptPreference?: EncryptionPreference;
|
|
71
|
+
/** This contact's pinned public keys. Trust is TOFU (trust-on-first-use) — see `keyConflicts` for what
|
|
72
|
+
* happens when a newly observed key differs from one of these. */
|
|
73
|
+
keys?: PublicKey[];
|
|
74
|
+
/** Observed keys that conflict with the currently pinned key of the same `useType`, at most one per `useType` —
|
|
75
|
+
* each blocks silent acceptance until the user resolves it (`keyvaultApi.ts`'s `resolveKeyConflict()`, the spec's
|
|
76
|
+
* Key Conflict Handling). The pinned `keys` are retained unchanged while a conflict is set. */
|
|
77
|
+
keyConflicts?: KeyConflict[];
|
|
78
|
+
/** Keys that were pinned before and replaced (by the user accepting a conflict, or by restapi's automatic
|
|
79
|
+
* same-issuer renewal of an expired or revoked key), newest first, at most 5 per `useType`. Signing keys here
|
|
80
|
+
* still count as trusted signers — see `signingKeyFingerprints()`. */
|
|
81
|
+
previousKeys?: PreviousKey[];
|
|
82
|
+
/** Keys the user rejected when resolving a conflict. */
|
|
83
|
+
rejectedKeys?: RejectedKey[];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Lists a folder's contacts, alphabetically by display name. Never includes soft-deleted contacts — see
|
|
87
|
+
* `listDeletedContacts()` for those. */
|
|
88
|
+
export function listContacts(folderUid: string, params: ListParams = {}, client?: ApiClient): Promise<Contact[]> {
|
|
89
|
+
return withClient(client, `/mail/contacts?${buildQuery(params, { folderUid, sort: JSON.stringify({ displayName: "ASC" }) })}`);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function contactsMatching(contacts: Contact[], address: string): Contact[] {
|
|
93
|
+
const wanted = address.trim().toLowerCase();
|
|
94
|
+
return contacts.filter((contact) => contact.emails.some((email) => email.address.trim().toLowerCase() === wanted));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** The trusted signing-key fingerprints of every contact in `contacts` with an email equal (case-insensitively) to
|
|
98
|
+
* `address`: each contact's pinned `keys` and its `previousKeys`, so mail signed before a key rotation still verifies -
|
|
99
|
+
* see `keyvaultApi.ts`'s `signingKeyFingerprints()` for the rules (expired and superseded keys kept, compromised or reasonless revoked keys excluded). De-duplicated;
|
|
100
|
+
* `[]` when no contact matches or none has a trusted signing key. */
|
|
101
|
+
export function pinnedSigningFingerprintsFor(contacts: Contact[], address: string): string[] {
|
|
102
|
+
return [...new Set(contactsMatching(contacts, address).flatMap((contact) => signingKeyFingerprints(contact.keys, contact.previousKeys)))];
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** Page size and page cap for `fetchPinnedSigningFingerprints()` and `fetchSignerKeyState()` (500 is restapi's own
|
|
106
|
+
* `limit` cap). */
|
|
107
|
+
export const PINNED_FINGERPRINT_PAGE_SIZE = 500;
|
|
108
|
+
export const PINNED_FINGERPRINT_MAX_PAGES = 20;
|
|
109
|
+
|
|
110
|
+
/** Every contact in `folderUids`, paged (`PINNED_FINGERPRINT_PAGE_SIZE`, at most `PINNED_FINGERPRINT_MAX_PAGES` pages
|
|
111
|
+
* per folder). A plain contacts read - never a Discovery lookup. */
|
|
112
|
+
async function listContactsInFolders(folderUids: string[], client?: ApiClient): Promise<Contact[]> {
|
|
113
|
+
const contacts: Contact[] = [];
|
|
114
|
+
for (const folderUid of folderUids) {
|
|
115
|
+
for (let page = 0; page < PINNED_FINGERPRINT_MAX_PAGES; page++) {
|
|
116
|
+
const batch = await listContacts(folderUid, { limit: PINNED_FINGERPRINT_PAGE_SIZE, page }, client);
|
|
117
|
+
contacts.push(...batch);
|
|
118
|
+
if (batch.length < PINNED_FINGERPRINT_PAGE_SIZE) {
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return contacts;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Fetches the trusted signing-key fingerprints (pinned and previous - see `pinnedSigningFingerprintsFor()`) for a
|
|
128
|
+
* message sender's `address` from the contacts in `folderUids` (the reader's contacts folders), for
|
|
129
|
+
* `evaluateMessageSecurity()`'s `pinnedSignerFingerprints`. Reads only what is already stored on the reader's own
|
|
130
|
+
* contacts - never triggers a Discovery lookup, which must not happen on message receipt (it would leak read timing to
|
|
131
|
+
* the sender's server). Pages through each folder (`PINNED_FINGERPRINT_PAGE_SIZE`, at most
|
|
132
|
+
* `PINNED_FINGERPRINT_MAX_PAGES` pages per folder). A caller rendering many messages should cache the contact list and
|
|
133
|
+
* use `pinnedSigningFingerprintsFor()` instead.
|
|
134
|
+
*/
|
|
135
|
+
export async function fetchPinnedSigningFingerprints(folderUids: string[], address: string, client?: ApiClient): Promise<string[]> {
|
|
136
|
+
return pinnedSigningFingerprintsFor(await listContactsInFolders(folderUids, client), address);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** A sender's stored signing-key state, for a key-changed comparison - see `signerKeyStateFor()`. */
|
|
140
|
+
export interface SignerKeyState {
|
|
141
|
+
/** The currently pinned signing keys (every `useType: "sign"` key, revoked and expired ones included, so a UI can
|
|
142
|
+
* show their dates and status), de-duplicated by fingerprint. */
|
|
143
|
+
pinned: PublicKey[];
|
|
144
|
+
/** Previously pinned signing keys, newest `replacedAt` first, de-duplicated by fingerprint. */
|
|
145
|
+
previous: PreviousKey[];
|
|
146
|
+
/** The first unresolved signing-key conflict found, if any. */
|
|
147
|
+
conflict?: KeyConflict;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function uniqueByFingerprint<T extends PublicKey>(keys: T[]): T[] {
|
|
151
|
+
const seen = new Set<string>();
|
|
152
|
+
return keys.filter((key) => {
|
|
153
|
+
const fingerprint = key.fingerprint.toLowerCase();
|
|
154
|
+
if (seen.has(fingerprint)) {
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
seen.add(fingerprint);
|
|
158
|
+
return true;
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/** The signing-key state of every contact in `contacts` with an email equal (case-insensitively) to `address`, merged -
|
|
163
|
+
* what a UI needs to compare a `signer_key_changed` message's certificate with the pinned and previous keys (their
|
|
164
|
+
* fingerprints and `notBefore`/`notAfter`/`revokedAt`/`replacedAt` dates) before calling `resolveKeyConflict()`. Empty
|
|
165
|
+
* `pinned`/`previous` and no `conflict` when no contact matches. */
|
|
166
|
+
export function signerKeyStateFor(contacts: Contact[], address: string): SignerKeyState {
|
|
167
|
+
const matching = contactsMatching(contacts, address);
|
|
168
|
+
const pinned = uniqueByFingerprint(matching.flatMap((contact) => (contact.keys ?? []).filter((key) => key.useType === "sign")));
|
|
169
|
+
const previous = uniqueByFingerprint(
|
|
170
|
+
matching.flatMap((contact) => (contact.previousKeys ?? []).filter((key) => key.useType === "sign")).sort((a, b) => b.replacedAt - a.replacedAt),
|
|
171
|
+
);
|
|
172
|
+
const conflict = matching.flatMap((contact) => contact.keyConflicts ?? []).find((entry) => entry.useType === "sign");
|
|
173
|
+
return { pinned, previous, ...(conflict ? { conflict } : {}) };
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/** Fetches `signerKeyStateFor()` for `address` from the contacts in `folderUids`, paging exactly like
|
|
177
|
+
* `fetchPinnedSigningFingerprints()`. Reads only stored contacts - never triggers a Discovery lookup. */
|
|
178
|
+
export async function fetchSignerKeyState(folderUids: string[], address: string, client?: ApiClient): Promise<SignerKeyState> {
|
|
179
|
+
return signerKeyStateFor(await listContactsInFolders(folderUids, client), address);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Lists a folder's soft-deleted contacts
|
|
184
|
+
(for an Outlook-style "Deleted" view) — `deleted` is an ordinary
|
|
185
|
+
* queryable field on `Contact` (a `RecoverableBaseEntity`), so this is the same `find()` the plain listing
|
|
186
|
+
* above uses, just constrained to `deleted: true` instead of the framework's own default of excluding them.
|
|
187
|
+
*
|
|
188
|
+
* Read-only for now — deliberately no `restoreContact()`: `@rapidmx/restapi`'s generic
|
|
189
|
+
* `BaseScopedChildRoute.update()` looks the target record up via a plain `findOne()` with no
|
|
190
|
+
* `includeDeleted` option, so it 404s on an already-deleted record before ever reaching the point where
|
|
191
|
+
* setting `deleted: false` would matter. Restoring would need a real fix in `@rapidmx/restapi` itself
|
|
192
|
+
* (passing `includeDeleted: true` into that lookup) — out of scope for this pass; the "Deleted" view here
|
|
193
|
+
* is browse-only until that lands.
|
|
194
|
+
*/
|
|
195
|
+
export function listDeletedContacts(folderUid: string, params: ListParams = {}, client?: ApiClient): Promise<Contact[]> {
|
|
196
|
+
return withClient(
|
|
197
|
+
client,
|
|
198
|
+
`/mail/contacts?${buildQuery(params, { folderUid, deleted: "true", sort: JSON.stringify({ displayName: "ASC" }) })}`,
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export function getContact(uid: string, client?: ApiClient): Promise<Contact> {
|
|
203
|
+
return withClient(client, `/mail/contacts/${encodeURIComponent(uid)}`);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export interface ContactInput {
|
|
207
|
+
mailboxUid: string;
|
|
208
|
+
folderUid: string;
|
|
209
|
+
contactListUid?: string;
|
|
210
|
+
displayName: string;
|
|
211
|
+
givenName?: string;
|
|
212
|
+
surname?: string;
|
|
213
|
+
emails?: ContactEmail[];
|
|
214
|
+
phones?: ContactPhone[];
|
|
215
|
+
addresses?: ContactPostalAddress[];
|
|
216
|
+
company?: string;
|
|
217
|
+
jobTitle?: string;
|
|
218
|
+
notes?: string;
|
|
219
|
+
favorite?: boolean;
|
|
220
|
+
categories?: string[];
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export function createContact(input: ContactInput, client?: ApiClient): Promise<Contact> {
|
|
224
|
+
return withClient(client, "/mail/contacts", {
|
|
225
|
+
method: "POST",
|
|
226
|
+
body: JSON.stringify({ emails: [], phones: [], addresses: [], ...input }),
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export interface UpdateContactInput extends ContactInput {
|
|
231
|
+
uid: string;
|
|
232
|
+
version: number;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/** A minimal contact update: only `uid`/`version` are required, every other field is sent only if
|
|
236
|
+
* present. The server merges just the fields in the body and rejects server-managed ones
|
|
237
|
+
* (`dateCreated`/`dateModified`/etc.), so prefer sending only what actually changed over a whole
|
|
238
|
+
* fetched `Contact`. An `UpdateContactInput` is also a valid `ContactPatch`. */
|
|
239
|
+
export type ContactPatch = Partial<Contact> & Pick<Contact, "uid" | "version">;
|
|
240
|
+
|
|
241
|
+
export function updateContact(patch: ContactPatch, client?: ApiClient): Promise<Contact> {
|
|
242
|
+
return withClient(client, `/mail/contacts/${encodeURIComponent(patch.uid)}`, {
|
|
243
|
+
method: "PUT",
|
|
244
|
+
body: JSON.stringify(patch),
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/** Thin `updateContact()` wrapper for toggling favorite/star status — same pattern as `mailApi.ts`'s
|
|
249
|
+
* `setMessageRead()`/`tasksApi.ts`'s `setTaskCompleted()`. Sends only `uid`/`version`/`favorite`, never
|
|
250
|
+
* the rest of `contact` (the server rejects its managed fields). */
|
|
251
|
+
export function setContactFavorite(contact: Contact, favorite: boolean, client?: ApiClient): Promise<Contact> {
|
|
252
|
+
return updateContact({ uid: contact.uid, version: contact.version, favorite }, client);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export function deleteContact(uid: string, version: number, client?: ApiClient): Promise<void> {
|
|
256
|
+
return withClient(client, `/mail/contacts/${encodeURIComponent(uid)}?version=${version}`, { method: "DELETE" });
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
export interface ContactList {
|
|
260
|
+
uid: string;
|
|
261
|
+
version: number;
|
|
262
|
+
dateCreated: string;
|
|
263
|
+
dateModified: string;
|
|
264
|
+
mailboxUid: string;
|
|
265
|
+
name: string;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/** Lists a mailbox's contact lists (Outlook-style "Your contact lists"), alphabetically by name. */
|
|
269
|
+
export function listContactLists(mailboxUid: string, params: ListParams = {}, client?: ApiClient): Promise<ContactList[]> {
|
|
270
|
+
return withClient(client, `/mail/contact-lists?${buildQuery(params, { mailboxUid, sort: JSON.stringify({ name: "ASC" }) })}`);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
export function createContactList(input: { mailboxUid: string; name: string }, client?: ApiClient): Promise<ContactList> {
|
|
274
|
+
return withClient(client, "/mail/contact-lists", { method: "POST", body: JSON.stringify(input) });
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
export function updateContactList(
|
|
278
|
+
input: { uid: string; version: number; name: string },
|
|
279
|
+
client?: ApiClient,
|
|
280
|
+
): Promise<ContactList> {
|
|
281
|
+
return withClient(client, `/mail/contact-lists/${encodeURIComponent(input.uid)}`, {
|
|
282
|
+
method: "PUT",
|
|
283
|
+
body: JSON.stringify(input),
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
export function deleteContactList(uid: string, version: number, client?: ApiClient): Promise<void> {
|
|
288
|
+
return withClient(client, `/mail/contact-lists/${encodeURIComponent(uid)}?version=${version}`, { method: "DELETE" });
|
|
289
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
// Copyright (C) 2026 Jean-Philippe Steinmetz
|
|
3
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
5
|
+
/**
|
|
6
|
+
* Pure client-side vCard 3.0 generate/parse — `@rapidmx/restapi` has no vCard import/export support of its
|
|
7
|
+
* own, and Outlook's Contacts UI treats this as a purely local file-format concern (a `.vcf` file never
|
|
8
|
+
* touches the server as anything but ordinary `Contact` field values), so there's nothing to add there.
|
|
9
|
+
*/
|
|
10
|
+
import type { Contact, ContactAddressKind, ContactInput } from "./contactsApi.js";
|
|
11
|
+
|
|
12
|
+
/** Escapes a text value (RFC 6350 §3.4): backslash, comma and semicolon are backslash-escaped, and every
|
|
13
|
+
* line break - CRLF, bare CR or bare LF - becomes `\n`, so a value can never break the content line. */
|
|
14
|
+
function escapeVCardValue(value: string): string {
|
|
15
|
+
return value
|
|
16
|
+
.replace(/\\/g, "\\\\")
|
|
17
|
+
.replace(/,/g, "\\,")
|
|
18
|
+
.replace(/;/g, "\\;")
|
|
19
|
+
.replace(/\r\n|\r|\n/g, "\\n");
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Unescapes a text value in a single pass, so an escaped backslash followed by `n` (`\\n`) stays a
|
|
23
|
+
* literal backslash + `n` instead of becoming a newline. `\n`/`\N` is a newline; any other escaped
|
|
24
|
+
* character is itself. */
|
|
25
|
+
function unescapeVCardValue(value: string): string {
|
|
26
|
+
return value.replace(/\\([\s\S])/g, (_match, ch: string) => (ch === "n" || ch === "N" ? "\n" : ch));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Splits a structured value (`N`, `ADR`) on its unescaped `;` separators, then unescapes each component. */
|
|
30
|
+
function splitStructuredValue(value: string): string[] {
|
|
31
|
+
const components: string[] = [];
|
|
32
|
+
let current = "";
|
|
33
|
+
for (let i = 0; i < value.length; i++) {
|
|
34
|
+
const ch = value[i];
|
|
35
|
+
if (ch === "\\" && i + 1 < value.length) {
|
|
36
|
+
current += ch + value[++i];
|
|
37
|
+
} else if (ch === ";") {
|
|
38
|
+
components.push(unescapeVCardValue(current));
|
|
39
|
+
current = "";
|
|
40
|
+
} else {
|
|
41
|
+
current += ch;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
components.push(unescapeVCardValue(current));
|
|
45
|
+
return components;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Builds a single vCard 3.0 record for one contact. */
|
|
49
|
+
export function contactToVCard(contact: Contact): string {
|
|
50
|
+
const lines: string[] = ["BEGIN:VCARD", "VERSION:3.0"];
|
|
51
|
+
lines.push(`N:${escapeVCardValue(contact.surname ?? "")};${escapeVCardValue(contact.givenName ?? "")};;;`);
|
|
52
|
+
lines.push(`FN:${escapeVCardValue(contact.displayName)}`);
|
|
53
|
+
if (contact.company) {
|
|
54
|
+
lines.push(`ORG:${escapeVCardValue(contact.company)}`);
|
|
55
|
+
}
|
|
56
|
+
if (contact.jobTitle) {
|
|
57
|
+
lines.push(`TITLE:${escapeVCardValue(contact.jobTitle)}`);
|
|
58
|
+
}
|
|
59
|
+
for (const email of contact.emails) {
|
|
60
|
+
lines.push(`EMAIL;TYPE=${email.type.toUpperCase()}:${escapeVCardValue(email.address)}`);
|
|
61
|
+
}
|
|
62
|
+
for (const phone of contact.phones) {
|
|
63
|
+
lines.push(`TEL;TYPE=${phone.type.toUpperCase()}:${escapeVCardValue(phone.phoneNumber)}`);
|
|
64
|
+
}
|
|
65
|
+
for (const address of contact.addresses) {
|
|
66
|
+
const parts = [
|
|
67
|
+
"",
|
|
68
|
+
"",
|
|
69
|
+
address.street ?? "",
|
|
70
|
+
address.city ?? "",
|
|
71
|
+
address.state ?? "",
|
|
72
|
+
address.postalCode ?? "",
|
|
73
|
+
address.country ?? "",
|
|
74
|
+
];
|
|
75
|
+
lines.push(`ADR;TYPE=${address.type.toUpperCase()}:${parts.map(escapeVCardValue).join(";")}`);
|
|
76
|
+
}
|
|
77
|
+
if (contact.notes) {
|
|
78
|
+
lines.push(`NOTE:${escapeVCardValue(contact.notes)}`);
|
|
79
|
+
}
|
|
80
|
+
lines.push("END:VCARD");
|
|
81
|
+
return lines.join("\r\n");
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Builds a single `.vcf` file's text content from multiple contacts (one `BEGIN:VCARD`/`END:VCARD` block
|
|
85
|
+
* per contact — the standard way multiple vCards share one file). */
|
|
86
|
+
export function contactsToVCardFile(contacts: Contact[]): string {
|
|
87
|
+
return contacts.map(contactToVCard).join("\r\n");
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** A parsed vCard's fields, shaped as a partial `ContactInput` missing only the `mailboxUid`/`folderUid`
|
|
91
|
+
* scope (the caller supplies those, since they're not part of the vCard format itself). */
|
|
92
|
+
export type ParsedVCardContact = Omit<ContactInput, "mailboxUid" | "folderUid">;
|
|
93
|
+
|
|
94
|
+
/** Index of the content line's name/value separator: the first `:` outside a quoted parameter value. */
|
|
95
|
+
function valueSeparatorIndex(line: string): number {
|
|
96
|
+
let inQuotes = false;
|
|
97
|
+
for (let i = 0; i < line.length; i++) {
|
|
98
|
+
if (line[i] === '"') {
|
|
99
|
+
inQuotes = !inQuotes;
|
|
100
|
+
} else if (line[i] === ":" && !inQuotes) {
|
|
101
|
+
return i;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return -1;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Maps a property's type parameters onto `ContactAddressKind`: every `TYPE=` value (vCard 3/4, including
|
|
109
|
+
* comma lists and quoted lists like `TYPE="work,voice"`) plus vCard 2.1's bare parameters (`EMAIL;WORK:`)
|
|
110
|
+
* are collected case-insensitively; `work` wins, then `home`, and anything else (`internet`, `cell`,
|
|
111
|
+
* `pref`, no type at all) is `other`.
|
|
112
|
+
*/
|
|
113
|
+
function normalizeType(params: string[]): ContactAddressKind {
|
|
114
|
+
const tokens = new Set<string>();
|
|
115
|
+
for (const param of params) {
|
|
116
|
+
const eq = param.indexOf("=");
|
|
117
|
+
const name = eq === -1 ? "TYPE" : param.slice(0, eq).trim().toUpperCase();
|
|
118
|
+
if (name !== "TYPE") {
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
for (const token of param.slice(eq + 1).replace(/"/g, "").split(",")) {
|
|
122
|
+
tokens.add(token.trim().toLowerCase());
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return tokens.has("work") ? "work" : tokens.has("home") ? "home" : "other";
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Parses one or more vCard 2.1/3.0/4.0 records from a `.vcf` file's text content. Deliberately tolerant of
|
|
130
|
+
* fields this app doesn't model (PHOTO, BDAY, etc. — silently ignored) and of the `TYPE=` parameter being
|
|
131
|
+
* absent (defaults to "other") — real-world exported vCards vary a lot in exactly which optional parameters
|
|
132
|
+
* they include. Folded lines (a line break followed by a space or tab) are unfolded first; property group
|
|
133
|
+
* prefixes (`item1.EMAIL`, as Apple Contacts writes) are ignored; `TYPE` values are normalized (see
|
|
134
|
+
* `normalizeType()`); structured values are split on unescaped `;` only.
|
|
135
|
+
*/
|
|
136
|
+
export function parseVCards(text: string): ParsedVCardContact[] {
|
|
137
|
+
// Unfold first, then split only on a line that is exactly BEGIN:VCARD - a NOTE (or a folded line) that
|
|
138
|
+
// merely contains the text "BEGIN:VCARD" must not start a bogus record.
|
|
139
|
+
const unfolded = text.replace(/(?:\r\n|\r|\n)[ \t]/g, "");
|
|
140
|
+
const cards = unfolded.split(/^[ \t]*BEGIN:VCARD[ \t]*$/im).slice(1);
|
|
141
|
+
return cards.map((card) => {
|
|
142
|
+
const contact: ParsedVCardContact = { displayName: "", emails: [], phones: [], addresses: [] };
|
|
143
|
+
const lines = card.split(/\r\n|\r|\n/);
|
|
144
|
+
for (const rawLine of lines) {
|
|
145
|
+
const line = rawLine.trim();
|
|
146
|
+
const colonIndex = valueSeparatorIndex(line);
|
|
147
|
+
if (colonIndex === -1) {
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
const key = line.slice(0, colonIndex);
|
|
151
|
+
const rawValue = line.slice(colonIndex + 1);
|
|
152
|
+
const value = unescapeVCardValue(rawValue);
|
|
153
|
+
const [groupedName, ...params] = key.split(";");
|
|
154
|
+
const name = groupedName.slice(groupedName.lastIndexOf(".") + 1).toUpperCase();
|
|
155
|
+
const type = normalizeType(params);
|
|
156
|
+
|
|
157
|
+
switch (name) {
|
|
158
|
+
case "FN":
|
|
159
|
+
contact.displayName = value;
|
|
160
|
+
break;
|
|
161
|
+
case "N": {
|
|
162
|
+
const [surname, given] = splitStructuredValue(rawValue);
|
|
163
|
+
if (surname) contact.surname = surname;
|
|
164
|
+
if (given) contact.givenName = given;
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
case "ORG":
|
|
168
|
+
// ORG is structured too (organization;unit;...) - only the organization name is modeled.
|
|
169
|
+
contact.company = splitStructuredValue(rawValue)[0];
|
|
170
|
+
break;
|
|
171
|
+
case "TITLE":
|
|
172
|
+
contact.jobTitle = value;
|
|
173
|
+
break;
|
|
174
|
+
case "EMAIL":
|
|
175
|
+
contact.emails!.push({ address: value, type });
|
|
176
|
+
break;
|
|
177
|
+
case "TEL":
|
|
178
|
+
contact.phones!.push({ phoneNumber: value, type });
|
|
179
|
+
break;
|
|
180
|
+
case "ADR": {
|
|
181
|
+
const [, , street, city, state, postalCode, country] = splitStructuredValue(rawValue);
|
|
182
|
+
contact.addresses!.push({ street, city, state, postalCode, country, type });
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
case "NOTE":
|
|
186
|
+
contact.notes = value;
|
|
187
|
+
break;
|
|
188
|
+
default:
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
if (!contact.displayName) {
|
|
193
|
+
contact.displayName = [contact.givenName, contact.surname].filter(Boolean).join(" ") || "Unnamed contact";
|
|
194
|
+
}
|
|
195
|
+
return contact;
|
|
196
|
+
});
|
|
197
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
// Copyright (C) 2026 Jean-Philippe Steinmetz
|
|
3
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
5
|
+
/**
|
|
6
|
+
* Compose-time decision logic for `specs/end-to-end_encryption.md`'s Digital Signatures and Encryption
|
|
7
|
+
* sections — kept as pure, side-effect-free functions (no `fetch`, no crypto) precisely so the actual
|
|
8
|
+
* discovery round trip (`keyvaultApi.ts`'s `lookupKeys()`) and MIME assembly (`smimeMessage.ts`) stay in
|
|
9
|
+
* the caller (`ComposeWindow.tsx`), which owns the async orchestration and error handling; this module
|
|
10
|
+
* only decides *what* a compose window should do once it has the facts.
|
|
11
|
+
*
|
|
12
|
+
* **Recipient tier classification is a client-side approximation.** The spec's three tiers
|
|
13
|
+
* (`specs/end-to-end_encryption.md`'s "Terminology": same-organisation / federated peer / external) are
|
|
14
|
+
* a server-side administrative concept - "the specific RapidMX server and the domains it controls" - that
|
|
15
|
+
* `@rapidmx/restapi` 0.6.0 does not actually expose to the client (`KeyLookupResult`/`KeyringUpdate`
|
|
16
|
+
* carry no tier field; confirmed by reading `util/KeyringUtils.ts`). `classifyRecipientTier()` below
|
|
17
|
+
* approximates it as "same domain as the sender's own address" vs. "a domain discovery found keys for"
|
|
18
|
+
* vs. "everything else" - the same domain-suffix heuristic used elsewhere for this class of judgment,
|
|
19
|
+
* not a guarantee. A real fix would be a restapi endpoint exposing which domains a server actually
|
|
20
|
+
* controls; until then this is a disclosed approximation, not a silent one.
|
|
21
|
+
*/
|
|
22
|
+
import { findActivePublicKey, type EncryptionPolicy, type KeyLookupResult, type PolicyState, type PublicKey } from "./keyvaultApi.js";
|
|
23
|
+
|
|
24
|
+
export type RecipientTier = "sameOrg" | "federated" | "external";
|
|
25
|
+
|
|
26
|
+
/** See this module's own doc comment for why this is an approximation, not an authoritative classification. */
|
|
27
|
+
export function classifyRecipientTier(ownAddress: string, recipientAddress: string, hasDiscoveredKeys: boolean): RecipientTier {
|
|
28
|
+
const ownDomain = ownAddress.split("@")[1]?.toLowerCase();
|
|
29
|
+
const recipientDomain = recipientAddress.split("@")[1]?.toLowerCase();
|
|
30
|
+
if (ownDomain && recipientDomain && ownDomain === recipientDomain) {
|
|
31
|
+
return "sameOrg";
|
|
32
|
+
}
|
|
33
|
+
return hasDiscoveredKeys ? "federated" : "external";
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function policyStateForTier(policy: EncryptionPolicy, tier: RecipientTier): PolicyState {
|
|
37
|
+
switch (tier) {
|
|
38
|
+
case "sameOrg":
|
|
39
|
+
return policy.encryptSameOrg;
|
|
40
|
+
case "federated":
|
|
41
|
+
return policy.encryptFederated;
|
|
42
|
+
case "external":
|
|
43
|
+
return policy.encryptExternal;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface RecipientEncryptionStatus {
|
|
48
|
+
address: string;
|
|
49
|
+
tier: RecipientTier;
|
|
50
|
+
/** The recipient's currently-active encryption certificate, if they have published (and this device
|
|
51
|
+
* has discovered) one. */
|
|
52
|
+
encryptCert?: PublicKey;
|
|
53
|
+
/** Whether this recipient *can* be encrypted to at all right now - false when there's no usable key,
|
|
54
|
+
* or the tier's policy is `prohibited`. */
|
|
55
|
+
canEncrypt: boolean;
|
|
56
|
+
/** Whether encryption should default ON for this recipient specifically: per spec, "MUST default to
|
|
57
|
+
* on only when both parties advertise mutual" AND the tier's policy is `automatic`. */
|
|
58
|
+
autoEncrypt: boolean;
|
|
59
|
+
/** Set (non-undefined) exactly when policy blocks encryption outright for this recipient's tier - the
|
|
60
|
+
* spec: "the client MUST explain why encryption is unavailable rather than silently omitting the
|
|
61
|
+
* control." `undefined` in every other case, including "no key found," which is not a policy block. */
|
|
62
|
+
prohibitedReason?: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Per-recipient encryption eligibility, given this device's own encryption preference and the
|
|
66
|
+
* system-wide policy. One entry per (address, lookup result) pair the caller already resolved via
|
|
67
|
+
* `lookupKeys()` - this function does no discovery itself. */
|
|
68
|
+
export function resolveRecipientEncryption(
|
|
69
|
+
ownAddress: string,
|
|
70
|
+
ownPrefersMutual: boolean,
|
|
71
|
+
policy: EncryptionPolicy,
|
|
72
|
+
recipientAddress: string,
|
|
73
|
+
lookup: KeyLookupResult | undefined,
|
|
74
|
+
): RecipientEncryptionStatus {
|
|
75
|
+
const encryptCert = lookup ? findActivePublicKey(lookup.keys, "encrypt") : undefined;
|
|
76
|
+
const tier = classifyRecipientTier(ownAddress, recipientAddress, !!lookup && lookup.keys.length > 0);
|
|
77
|
+
const policyState = policyStateForTier(policy, tier);
|
|
78
|
+
|
|
79
|
+
if (policyState === "prohibited") {
|
|
80
|
+
return {
|
|
81
|
+
address: recipientAddress,
|
|
82
|
+
tier,
|
|
83
|
+
encryptCert,
|
|
84
|
+
canEncrypt: false,
|
|
85
|
+
autoEncrypt: false,
|
|
86
|
+
prohibitedReason: "Your organization's encryption policy does not allow encrypting messages to this recipient.",
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (!encryptCert) {
|
|
91
|
+
return { address: recipientAddress, tier, canEncrypt: false, autoEncrypt: false };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const recipientPrefersMutual = lookup?.encryptPreference?.preferEncrypt === "mutual";
|
|
95
|
+
const mutual = ownPrefersMutual && recipientPrefersMutual;
|
|
96
|
+
return {
|
|
97
|
+
address: recipientAddress,
|
|
98
|
+
tier,
|
|
99
|
+
encryptCert,
|
|
100
|
+
canEncrypt: true,
|
|
101
|
+
autoEncrypt: policyState === "automatic" && mutual,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export interface MessageEncryptionDecision {
|
|
106
|
+
/** Whether the compose window's encryption toggle should default to checked - true only when every
|
|
107
|
+
* recipient independently defaults to encrypted. Seeds the toggle's *initial* state only; the user
|
|
108
|
+
* can still turn it on manually even when this is false, subject to `canEncryptAll`. */
|
|
109
|
+
autoEncrypt: boolean;
|
|
110
|
+
/** Every recipient the message *could* be encrypted to right now. */
|
|
111
|
+
canEncryptAll: boolean;
|
|
112
|
+
/** Recipients that cannot currently be encrypted to (no key, or policy-prohibited) - the spec's
|
|
113
|
+
* "Multiple Recipients" all-or-nothing case: when this is non-empty and the user still wants
|
|
114
|
+
* encryption, the client MUST offer to send in plaintext or remove these recipients, never split. */
|
|
115
|
+
blockedRecipients: RecipientEncryptionStatus[];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** Combines every recipient's individual status into the one decision a compose window's UI actually
|
|
119
|
+
* needs: whether to default the toggle on, and whether an all-or-nothing prompt is required. */
|
|
120
|
+
export function decideMessageEncryption(recipients: RecipientEncryptionStatus[]): MessageEncryptionDecision {
|
|
121
|
+
if (recipients.length === 0) {
|
|
122
|
+
return { autoEncrypt: false, canEncryptAll: false, blockedRecipients: [] };
|
|
123
|
+
}
|
|
124
|
+
const blockedRecipients = recipients.filter((r) => !r.canEncrypt);
|
|
125
|
+
return {
|
|
126
|
+
autoEncrypt: recipients.every((r) => r.autoEncrypt),
|
|
127
|
+
canEncryptAll: blockedRecipients.length === 0,
|
|
128
|
+
blockedRecipients,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** Detects list traffic per the spec's "Mailing lists" note under Digital Signatures: a footer a list
|
|
133
|
+
* appends after signing invalidates the signature, so the client MAY suppress signing for it. `headers`
|
|
134
|
+
* is whatever the caller already has on hand (e.g. a `Contact`'s known list-membership flag) - this
|
|
135
|
+
* module has no way to inspect list membership itself, so it just applies the rule to inputs the caller
|
|
136
|
+
* supplies. Currently unused by any caller (no UI surfaces distribution-list membership to compose yet -
|
|
137
|
+
* a disclosed gap, not a silent one; see this module's own file-level doc comment). */
|
|
138
|
+
export function isLikelyMailingList(headers: { listId?: string; listUnsubscribe?: string }): boolean {
|
|
139
|
+
return !!(headers.listId || headers.listUnsubscribe);
|
|
140
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
// Copyright (C) 2026 Jean-Philippe Steinmetz
|
|
3
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
5
|
+
/**
|
|
6
|
+
* Plain base64/base64url <-> `Uint8Array` conversions shared by every `crypto/*` module. Deliberately
|
|
7
|
+
* `Buffer`-free — this code runs in a browser tab and an Electron renderer alike, and `Buffer` is not
|
|
8
|
+
* guaranteed to exist in either without a bundler polyfill.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export function toBase64(bytes: Uint8Array): string {
|
|
12
|
+
let binary = "";
|
|
13
|
+
for (const byte of bytes) {
|
|
14
|
+
binary += String.fromCharCode(byte);
|
|
15
|
+
}
|
|
16
|
+
return btoa(binary);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function fromBase64(base64: string): Uint8Array {
|
|
20
|
+
const binary = atob(base64);
|
|
21
|
+
const bytes = new Uint8Array(binary.length);
|
|
22
|
+
for (let i = 0; i < binary.length; i++) {
|
|
23
|
+
bytes[i] = binary.charCodeAt(i);
|
|
24
|
+
}
|
|
25
|
+
return bytes;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function toBase64Url(bytes: Uint8Array): string {
|
|
29
|
+
return toBase64(bytes).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function fromBase64Url(base64url: string): Uint8Array {
|
|
33
|
+
const padded = base64url.replace(/-/g, "+").replace(/_/g, "/");
|
|
34
|
+
const padding = padded.length % 4 === 0 ? "" : "=".repeat(4 - (padded.length % 4));
|
|
35
|
+
return fromBase64(padded + padding);
|
|
36
|
+
}
|