feat: store trusted senders in a dedicated JMAP address book #176
This commit is contained in:
@@ -888,6 +888,9 @@ export function EmailViewer({
|
||||
const attachmentPosition = useSettingsStore((state) => state.attachmentPosition);
|
||||
const addTrustedSender = useSettingsStore((state) => state.addTrustedSender);
|
||||
const isSenderTrusted = useSettingsStore((state) => state.isSenderTrusted);
|
||||
const trustedSendersAddressBook = useSettingsStore((state) => state.trustedSendersAddressBook);
|
||||
const isTrustedAddressBookSender = useContactStore((state) => state.isTrustedAddressBookSender);
|
||||
const addToTrustedSendersBook = useContactStore((state) => state.addToTrustedSendersBook);
|
||||
const emailKeywords = useSettingsStore((state) => state.emailKeywords);
|
||||
const toolbarPosition = useSettingsStore((state) => state.toolbarPosition);
|
||||
const showToolbarLabels = useSettingsStore((state) => state.showToolbarLabels);
|
||||
@@ -2311,9 +2314,11 @@ export function EmailViewer({
|
||||
// Use shared sanitization config as base (more secure)
|
||||
const sanitizeConfig = { ...EMAIL_SANITIZE_CONFIG };
|
||||
|
||||
// Check if sender is trusted
|
||||
// Check if sender is trusted (localStorage list or address book)
|
||||
const senderEmail = email.from?.[0]?.email?.toLowerCase();
|
||||
const senderIsTrusted = senderEmail ? isSenderTrusted(senderEmail) : false;
|
||||
const senderIsTrusted = senderEmail
|
||||
? isSenderTrusted(senderEmail) || (trustedSendersAddressBook && isTrustedAddressBookSender(senderEmail))
|
||||
: false;
|
||||
|
||||
// Block external content based on policy:
|
||||
// 'allow' = never block, 'block' = always block (unless trusted), 'ask' = block until user allows or trusted
|
||||
@@ -2420,7 +2425,7 @@ export function EmailViewer({
|
||||
html: '<p style="color: var(--color-muted-foreground);">No content available</p>',
|
||||
isHtml: false
|
||||
};
|
||||
}, [email, allowExternalContent, hasBlockedContent, externalContentPolicy, isSenderTrusted, cidBlobUrls]);
|
||||
}, [email, allowExternalContent, hasBlockedContent, externalContentPolicy, isSenderTrusted, isTrustedAddressBookSender, trustedSendersAddressBook, cidBlobUrls]);
|
||||
|
||||
// Override email content with S/MIME decrypted content when available
|
||||
const effectiveEmailContent = useMemo(() => {
|
||||
@@ -4565,7 +4570,11 @@ export function EmailViewer({
|
||||
onClick={() => {
|
||||
const senderEmail = email.from?.[0]?.email;
|
||||
if (senderEmail) {
|
||||
addTrustedSender(senderEmail);
|
||||
if (trustedSendersAddressBook && client) {
|
||||
addToTrustedSendersBook(client, senderEmail).catch(console.error);
|
||||
} else {
|
||||
addTrustedSender(senderEmail);
|
||||
}
|
||||
setAllowExternalContent(true);
|
||||
}
|
||||
}}
|
||||
|
||||
@@ -31,6 +31,7 @@ import {
|
||||
} from "lucide-react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useSettingsStore } from "@/stores/settings-store";
|
||||
import { useContactStore } from "@/stores/contact-store";
|
||||
import { useAuthStore } from "@/stores/auth-store";
|
||||
import { isFilePreviewable } from "@/lib/file-preview";
|
||||
|
||||
@@ -84,6 +85,9 @@ export function ThreadConversationView({
|
||||
const externalContentPolicy = useSettingsStore((state) => state.externalContentPolicy);
|
||||
const addTrustedSender = useSettingsStore((state) => state.addTrustedSender);
|
||||
const isSenderTrusted = useSettingsStore((state) => state.isSenderTrusted);
|
||||
const trustedSendersAddressBook = useSettingsStore((state) => state.trustedSendersAddressBook);
|
||||
const isTrustedAddressBookSender = useContactStore((state) => state.isTrustedAddressBookSender);
|
||||
const addToTrustedSendersBook = useContactStore((state) => state.addToTrustedSendersBook);
|
||||
|
||||
// Track which emails are expanded (most recent by default)
|
||||
const [expandedIds, setExpandedIds] = useState<Set<string>>(new Set());
|
||||
@@ -164,7 +168,9 @@ export function ThreadConversationView({
|
||||
<div className="space-y-3" style={{ padding: 'var(--density-card-p)' }}>
|
||||
{emails.map((email, index) => {
|
||||
const senderEmail = email.from?.[0]?.email?.toLowerCase();
|
||||
const senderIsTrusted = senderEmail ? isSenderTrusted(senderEmail) : false;
|
||||
const senderIsTrusted = senderEmail
|
||||
? isSenderTrusted(senderEmail) || (trustedSendersAddressBook && isTrustedAddressBookSender(senderEmail))
|
||||
: false;
|
||||
return (
|
||||
<EmailCard
|
||||
key={email.id}
|
||||
@@ -175,7 +181,11 @@ export function ThreadConversationView({
|
||||
onToggleExpanded={() => toggleExpanded(email.id)}
|
||||
onAllowExternal={() => toggleAllowExternal(email.id)}
|
||||
onTrustSender={senderEmail ? () => {
|
||||
addTrustedSender(senderEmail);
|
||||
if (trustedSendersAddressBook && client) {
|
||||
addToTrustedSendersBook(client, senderEmail).catch(console.error);
|
||||
} else {
|
||||
addTrustedSender(senderEmail);
|
||||
}
|
||||
toggleAllowExternal(email.id);
|
||||
} : undefined}
|
||||
onReply={onReply ? () => onReply(email) : undefined}
|
||||
|
||||
Reference in New Issue
Block a user