indexing: record protected subject when indexing cleartext

When indexing the cleartext of an encrypted message, record any
protected subject in the database, which should make it findable and
visible in search.

Signed-off-by: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
This commit is contained in:
Daniel Kahn Gillmor 2019-05-27 18:40:28 -04:00 committed by David Bremner
parent b7b553e732
commit 5c3a44681f
4 changed files with 61 additions and 9 deletions

View file

@ -367,13 +367,15 @@ _index_content_type (notmuch_message_t *message, GMimeObject *part)
static void static void
_index_encrypted_mime_part (notmuch_message_t *message, notmuch_indexopts_t *indexopts, _index_encrypted_mime_part (notmuch_message_t *message, notmuch_indexopts_t *indexopts,
GMimeMultipartEncrypted *part); GMimeMultipartEncrypted *part,
_notmuch_message_crypto_t *msg_crypto);
/* Callback to generate terms for each mime part of a message. */ /* Callback to generate terms for each mime part of a message. */
static void static void
_index_mime_part (notmuch_message_t *message, _index_mime_part (notmuch_message_t *message,
notmuch_indexopts_t *indexopts, notmuch_indexopts_t *indexopts,
GMimeObject *part) GMimeObject *part,
_notmuch_message_crypto_t *msg_crypto)
{ {
GMimeStream *stream, *filter; GMimeStream *stream, *filter;
GMimeFilter *discard_non_term_filter; GMimeFilter *discard_non_term_filter;
@ -403,6 +405,8 @@ _index_mime_part (notmuch_message_t *message,
_notmuch_message_add_term (message, "tag", "encrypted"); _notmuch_message_add_term (message, "tag", "encrypted");
for (i = 0; i < g_mime_multipart_get_count (multipart); i++) { for (i = 0; i < g_mime_multipart_get_count (multipart); i++) {
notmuch_status_t status;
GMimeObject *child;
if (GMIME_IS_MULTIPART_SIGNED (multipart)) { if (GMIME_IS_MULTIPART_SIGNED (multipart)) {
/* Don't index the signature, but index its content type. */ /* Don't index the signature, but index its content type. */
if (i == GMIME_MULTIPART_SIGNED_SIGNATURE) { if (i == GMIME_MULTIPART_SIGNED_SIGNATURE) {
@ -419,7 +423,8 @@ _index_mime_part (notmuch_message_t *message,
g_mime_multipart_get_part (multipart, i)); g_mime_multipart_get_part (multipart, i));
if (i == GMIME_MULTIPART_ENCRYPTED_CONTENT) { if (i == GMIME_MULTIPART_ENCRYPTED_CONTENT) {
_index_encrypted_mime_part(message, indexopts, _index_encrypted_mime_part(message, indexopts,
GMIME_MULTIPART_ENCRYPTED (part)); GMIME_MULTIPART_ENCRYPTED (part),
msg_crypto);
} else { } else {
if (i != GMIME_MULTIPART_ENCRYPTED_VERSION) { if (i != GMIME_MULTIPART_ENCRYPTED_VERSION) {
_notmuch_database_log (notmuch_message_get_database (message), _notmuch_database_log (notmuch_message_get_database (message),
@ -428,8 +433,13 @@ _index_mime_part (notmuch_message_t *message,
} }
continue; continue;
} }
_index_mime_part (message, indexopts, child = g_mime_multipart_get_part (multipart, i);
g_mime_multipart_get_part (multipart, i)); status = _notmuch_message_crypto_potential_payload (msg_crypto, child, part, i);
if (status)
_notmuch_database_log (notmuch_message_get_database (message),
"Warning: failed to mark the potential cryptographic payload (%s).\n",
notmuch_status_to_string (status));
_index_mime_part (message, indexopts, child, msg_crypto);
} }
return; return;
} }
@ -439,7 +449,7 @@ _index_mime_part (notmuch_message_t *message,
mime_message = g_mime_message_part_get_message (GMIME_MESSAGE_PART (part)); mime_message = g_mime_message_part_get_message (GMIME_MESSAGE_PART (part));
_index_mime_part (message, indexopts, g_mime_message_get_mime_part (mime_message)); _index_mime_part (message, indexopts, g_mime_message_get_mime_part (mime_message), msg_crypto);
return; return;
} }
@ -516,7 +526,8 @@ _index_mime_part (notmuch_message_t *message,
static void static void
_index_encrypted_mime_part (notmuch_message_t *message, _index_encrypted_mime_part (notmuch_message_t *message,
notmuch_indexopts_t *indexopts, notmuch_indexopts_t *indexopts,
GMimeMultipartEncrypted *encrypted_data) GMimeMultipartEncrypted *encrypted_data,
_notmuch_message_crypto_t *msg_crypto)
{ {
notmuch_status_t status; notmuch_status_t status;
GError *err = NULL; GError *err = NULL;
@ -553,6 +564,10 @@ _index_encrypted_mime_part (notmuch_message_t *message,
return; return;
} }
if (decrypt_result) { if (decrypt_result) {
status = _notmuch_message_crypto_successful_decryption (msg_crypto);
if (status)
_notmuch_database_log_append (notmuch, "failed to mark the message as decrypted (%s)\n",
notmuch_status_to_string (status));
if (get_sk) { if (get_sk) {
status = notmuch_message_add_property (message, "session-key", status = notmuch_message_add_property (message, "session-key",
g_mime_decrypt_result_get_session_key (decrypt_result)); g_mime_decrypt_result_get_session_key (decrypt_result));
@ -562,7 +577,8 @@ _index_encrypted_mime_part (notmuch_message_t *message,
} }
g_object_unref (decrypt_result); g_object_unref (decrypt_result);
} }
_index_mime_part (message, indexopts, clear); status = _notmuch_message_crypto_potential_payload (msg_crypto, clear, GMIME_OBJECT (encrypted_data), GMIME_MULTIPART_ENCRYPTED_CONTENT);
_index_mime_part (message, indexopts, clear, msg_crypto);
g_object_unref (clear); g_object_unref (clear);
status = notmuch_message_add_property (message, "index.decryption", "success"); status = notmuch_message_add_property (message, "index.decryption", "success");
@ -606,6 +622,7 @@ _notmuch_message_index_file (notmuch_message_t *message,
InternetAddressList *addresses; InternetAddressList *addresses;
const char *subject; const char *subject;
notmuch_status_t status; notmuch_status_t status;
_notmuch_message_crypto_t *msg_crypto;
status = _notmuch_message_file_get_mime_message (message_file, status = _notmuch_message_file_get_mime_message (message_file,
&mime_message); &mime_message);
@ -628,7 +645,14 @@ _notmuch_message_index_file (notmuch_message_t *message,
status = _notmuch_message_index_user_headers (message, mime_message); status = _notmuch_message_index_user_headers (message, mime_message);
_index_mime_part (message, indexopts, g_mime_message_get_mime_part (mime_message)); msg_crypto = _notmuch_message_crypto_new (NULL);
_index_mime_part (message, indexopts, g_mime_message_get_mime_part (mime_message), msg_crypto);
if (msg_crypto && msg_crypto->payload_subject) {
_notmuch_message_gen_terms (message, "subject", msg_crypto->payload_subject);
_notmuch_message_update_subject (message, msg_crypto->payload_subject);
}
talloc_free (msg_crypto);
return NOTMUCH_STATUS_SUCCESS; return NOTMUCH_STATUS_SUCCESS;
} }

View file

@ -1238,6 +1238,14 @@ _notmuch_message_set_header_values (notmuch_message_t *message,
message->modified = true; message->modified = true;
} }
void
_notmuch_message_update_subject (notmuch_message_t *message,
const char *subject)
{
message->doc.add_value (NOTMUCH_VALUE_SUBJECT, subject);
message->modified = true;
}
/* Upgrade a message to support NOTMUCH_FEATURE_LAST_MOD. The caller /* Upgrade a message to support NOTMUCH_FEATURE_LAST_MOD. The caller
* must call _notmuch_message_sync. */ * must call _notmuch_message_sync. */
void void

View file

@ -325,6 +325,10 @@ _notmuch_message_set_header_values (notmuch_message_t *message,
const char *from, const char *from,
const char *subject); const char *subject);
void
_notmuch_message_update_subject (notmuch_message_t *message,
const char *subject);
void void
_notmuch_message_upgrade_last_mod (notmuch_message_t *message); _notmuch_message_upgrade_last_mod (notmuch_message_t *message);

View file

@ -83,4 +83,20 @@ test_json_nodes <<<"$output" \
'subject:["original"]["headers"]["Subject"]="This is a protected header"' \ 'subject:["original"]["headers"]["Subject"]="This is a protected header"' \
'reply-subject:["reply-headers"]["Subject"]="Re: Subject Unavailable"' 'reply-subject:["reply-headers"]["Subject"]="Re: Subject Unavailable"'
test_begin_subtest "protected subject is not indexed by default"
output=$(notmuch search --output=messages 'subject:"This is a protected header"')
test_expect_equal "$output" ''
test_begin_subtest "reindex message with protected header"
test_expect_success 'notmuch reindex --decrypt=true id:protected-header@crypto.notmuchmail.org'
test_begin_subtest "protected subject is indexed when cleartext is indexed"
output=$(notmuch search --output=messages 'subject:"This is a protected header"')
test_expect_equal "$output" 'id:protected-header@crypto.notmuchmail.org'
test_begin_subtest "indexed protected subject is visible in search"
output=$(notmuch search --format=json 'id:protected-header@crypto.notmuchmail.org')
test_json_nodes <<<"$output" \
'subject:[0]["subject"]="This is a protected header"'
test_done test_done