mirror of
https://git.notmuchmail.org/git/notmuch
synced 2024-11-21 18:38:08 +01:00
crypto: index encrypted parts when indexopts try_decrypt is set.
If we see index options that ask us to decrypt when indexing a message, and we encounter an encrypted part, we'll try to descend into it. If we can decrypt, we add the property index.decryption=success. If we can't decrypt (or recognize the encrypted type of mail), we add the property index.decryption=failure. Note that a single message may have both values of the "index.decryption" property: "success" and "failure". For example, consider a message that includes multiple layers of encryption. If we manage to decrypt the outer layer ("index.decryption=success"), but fail on the inner layer ("index.decryption=failure"). Because of the property name, this will be automatically cleared (and possibly re-set) during re-indexing. This means it will subsequently correspond to the actual semantics of the stored index.
This commit is contained in:
parent
0bb05ff693
commit
4dfcc8c9b2
5 changed files with 112 additions and 12 deletions
|
@ -47,6 +47,32 @@ CONVENTIONS
|
|||
Any property with a key that starts with "index." will be removed (and
|
||||
possibly re-set) upon reindexing (see **notmuch-reindex(1)**).
|
||||
|
||||
MESSAGE PROPERTIES
|
||||
==================
|
||||
|
||||
The following properties are set by notmuch internally in the course
|
||||
of its normal activity.
|
||||
|
||||
**index.decryption**
|
||||
|
||||
If a message contains encrypted content, and notmuch tries to
|
||||
decrypt that content during indexing, it will add the property
|
||||
``index.decryption=success`` when the cleartext was successfully
|
||||
indexed. If notmuch attempts to decrypt any part of a message
|
||||
during indexing and that decryption attempt fails, it will add the
|
||||
property ``index.decryption=failure`` to the message.
|
||||
|
||||
Note that it's possible for a single message to have both
|
||||
``index.decryption=success`` and ``index.decryption=failure``.
|
||||
Consider an encrypted e-mail message that contains another
|
||||
encrypted e-mail message as an attachment -- if the outer message
|
||||
can be decrypted, but the attached part cannot, then both
|
||||
properties will be set on the message as a whole.
|
||||
|
||||
If notmuch never tried to decrypt an encrypted message during
|
||||
indexing (which is the default), then this property will not be
|
||||
set on that message.
|
||||
|
||||
SEE ALSO
|
||||
========
|
||||
|
||||
|
|
|
@ -546,7 +546,7 @@ notmuch_database_index_file (notmuch_database_t *notmuch,
|
|||
indexopts = def_indexopts;
|
||||
}
|
||||
|
||||
ret = _notmuch_message_index_file (message, message_file);
|
||||
ret = _notmuch_message_index_file (message, indexopts, message_file);
|
||||
if (ret)
|
||||
goto DONE;
|
||||
|
||||
|
|
91
lib/index.cc
91
lib/index.cc
|
@ -364,9 +364,15 @@ _index_content_type (notmuch_message_t *message, GMimeObject *part)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_index_encrypted_mime_part (notmuch_message_t *message, notmuch_indexopts_t *indexopts,
|
||||
GMimeContentType *content_type,
|
||||
GMimeMultipartEncrypted *part);
|
||||
|
||||
/* Callback to generate terms for each mime part of a message. */
|
||||
static void
|
||||
_index_mime_part (notmuch_message_t *message,
|
||||
notmuch_indexopts_t *indexopts,
|
||||
GMimeObject *part)
|
||||
{
|
||||
GMimeStream *stream, *filter;
|
||||
|
@ -385,6 +391,7 @@ _index_mime_part (notmuch_message_t *message,
|
|||
}
|
||||
|
||||
_index_content_type (message, part);
|
||||
content_type = g_mime_object_get_content_type (part);
|
||||
|
||||
if (GMIME_IS_MULTIPART (part)) {
|
||||
GMimeMultipart *multipart = GMIME_MULTIPART (part);
|
||||
|
@ -409,17 +416,21 @@ _index_mime_part (notmuch_message_t *message,
|
|||
}
|
||||
}
|
||||
if (GMIME_IS_MULTIPART_ENCRYPTED (multipart)) {
|
||||
/* Don't index encrypted parts, but index their content type. */
|
||||
_index_content_type (message,
|
||||
g_mime_multipart_get_part (multipart, i));
|
||||
if ((i != GMIME_MULTIPART_ENCRYPTED_VERSION) &&
|
||||
(i != GMIME_MULTIPART_ENCRYPTED_CONTENT)) {
|
||||
_notmuch_database_log (_notmuch_message_database (message),
|
||||
"Warning: Unexpected extra parts of multipart/encrypted.\n");
|
||||
if (i == GMIME_MULTIPART_ENCRYPTED_CONTENT) {
|
||||
_index_encrypted_mime_part(message, indexopts,
|
||||
content_type,
|
||||
GMIME_MULTIPART_ENCRYPTED (part));
|
||||
} else {
|
||||
if (i != GMIME_MULTIPART_ENCRYPTED_VERSION) {
|
||||
_notmuch_database_log (_notmuch_message_database (message),
|
||||
"Warning: Unexpected extra parts of multipart/encrypted.\n");
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
_index_mime_part (message,
|
||||
_index_mime_part (message, indexopts,
|
||||
g_mime_multipart_get_part (multipart, i));
|
||||
}
|
||||
return;
|
||||
|
@ -430,7 +441,7 @@ _index_mime_part (notmuch_message_t *message,
|
|||
|
||||
mime_message = g_mime_message_part_get_message (GMIME_MESSAGE_PART (part));
|
||||
|
||||
_index_mime_part (message, g_mime_message_get_mime_part (mime_message));
|
||||
_index_mime_part (message, indexopts, g_mime_message_get_mime_part (mime_message));
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -464,7 +475,6 @@ _index_mime_part (notmuch_message_t *message,
|
|||
|
||||
filter = g_mime_stream_filter_new (stream);
|
||||
|
||||
content_type = g_mime_object_get_content_type (part);
|
||||
discard_non_term_filter = notmuch_filter_discard_non_term_new (content_type);
|
||||
|
||||
g_mime_stream_filter_add (GMIME_STREAM_FILTER (filter),
|
||||
|
@ -502,8 +512,71 @@ _index_mime_part (notmuch_message_t *message,
|
|||
}
|
||||
}
|
||||
|
||||
/* descend (if desired) into the cleartext part of an encrypted MIME
|
||||
* part while indexing. */
|
||||
static void
|
||||
_index_encrypted_mime_part (notmuch_message_t *message,
|
||||
notmuch_indexopts_t *indexopts,
|
||||
g_mime_3_unused(GMimeContentType *content_type),
|
||||
GMimeMultipartEncrypted *encrypted_data)
|
||||
{
|
||||
notmuch_status_t status;
|
||||
GError *err = NULL;
|
||||
notmuch_database_t * notmuch = NULL;
|
||||
GMimeObject *clear = NULL;
|
||||
|
||||
if (!indexopts || !notmuch_indexopts_get_try_decrypt (indexopts))
|
||||
return;
|
||||
|
||||
notmuch = _notmuch_message_database (message);
|
||||
|
||||
#if (GMIME_MAJOR_VERSION < 3)
|
||||
{
|
||||
GMimeCryptoContext* crypto_ctx = NULL;
|
||||
const char *protocol = NULL;
|
||||
protocol = g_mime_content_type_get_parameter (content_type, "protocol");
|
||||
status = _notmuch_crypto_get_gmime_ctx_for_protocol (&(indexopts->crypto),
|
||||
protocol, &crypto_ctx);
|
||||
if (status) {
|
||||
_notmuch_database_log (notmuch, "Warning: setup failed for decrypting "
|
||||
"during indexing. (%d)\n", status);
|
||||
status = notmuch_message_add_property (message, "index.decryption", "failure");
|
||||
if (status)
|
||||
_notmuch_database_log_append (notmuch, "failed to add index.decryption "
|
||||
"property (%d)\n", status);
|
||||
return;
|
||||
}
|
||||
clear = g_mime_multipart_encrypted_decrypt(encrypted_data, crypto_ctx,
|
||||
NULL, &err);
|
||||
}
|
||||
#else
|
||||
clear = g_mime_multipart_encrypted_decrypt(encrypted_data, GMIME_DECRYPT_NONE, NULL,
|
||||
NULL, &err);
|
||||
#endif
|
||||
if (err) {
|
||||
_notmuch_database_log (notmuch, "Failed to decrypt during indexing. (%d:%d) [%s]\n",
|
||||
err->domain, err->code, err->message);
|
||||
g_error_free(err);
|
||||
/* Indicate that we failed to decrypt during indexing */
|
||||
status = notmuch_message_add_property (message, "index.decryption", "failure");
|
||||
if (status)
|
||||
_notmuch_database_log_append (notmuch, "failed to add index.decryption "
|
||||
"property (%d)\n", status);
|
||||
return;
|
||||
}
|
||||
_index_mime_part (message, indexopts, clear);
|
||||
g_object_unref (clear);
|
||||
|
||||
status = notmuch_message_add_property (message, "index.decryption", "success");
|
||||
if (status)
|
||||
_notmuch_database_log (notmuch, "failed to add index.decryption "
|
||||
"property (%d)\n", status);
|
||||
|
||||
}
|
||||
|
||||
notmuch_status_t
|
||||
_notmuch_message_index_file (notmuch_message_t *message,
|
||||
notmuch_indexopts_t *indexopts,
|
||||
notmuch_message_file_t *message_file)
|
||||
{
|
||||
GMimeMessage *mime_message;
|
||||
|
@ -531,7 +604,7 @@ _notmuch_message_index_file (notmuch_message_t *message,
|
|||
subject = g_mime_message_get_subject (mime_message);
|
||||
_notmuch_message_gen_terms (message, "subject", subject);
|
||||
|
||||
_index_mime_part (message, g_mime_message_get_mime_part (mime_message));
|
||||
_index_mime_part (message, indexopts, g_mime_message_get_mime_part (mime_message));
|
||||
|
||||
return NOTMUCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -1961,7 +1961,7 @@ _notmuch_message_frozen (notmuch_message_t *message)
|
|||
|
||||
notmuch_status_t
|
||||
notmuch_message_reindex (notmuch_message_t *message,
|
||||
notmuch_indexopts_t unused (*indexopts))
|
||||
notmuch_indexopts_t *indexopts)
|
||||
{
|
||||
notmuch_database_t *notmuch = NULL;
|
||||
notmuch_status_t ret = NOTMUCH_STATUS_SUCCESS;
|
||||
|
@ -2042,7 +2042,7 @@ notmuch_message_reindex (notmuch_message_t *message,
|
|||
if (found == 0)
|
||||
_notmuch_message_set_header_values (message, date, from, subject);
|
||||
|
||||
ret = _notmuch_message_index_file (message, message_file);
|
||||
ret = _notmuch_message_index_file (message, indexopts, message_file);
|
||||
|
||||
if (ret == NOTMUCH_STATUS_FILE_ERROR)
|
||||
continue;
|
||||
|
|
|
@ -448,6 +448,7 @@ _notmuch_database_link_message_to_parents (notmuch_database_t *notmuch,
|
|||
|
||||
notmuch_status_t
|
||||
_notmuch_message_index_file (notmuch_message_t *message,
|
||||
notmuch_indexopts_t *indexopts,
|
||||
notmuch_message_file_t *message_file);
|
||||
|
||||
/* messages.c */
|
||||
|
|
Loading…
Reference in a new issue