This flag indicates the intent of the client to protect the subject
line, which allows "notmuch reply" to safely emit the earlier
message's encrypted subject without risking leaking it in the clear in
the reply.

Obviously, it should only be used by a client that *will* protect the
subject line.  This feels clumsier than i'd like, but we really don't
want to be the ones who leak data on the wire that had been protected
otherwise, and this seems like a safe way to ensure that the MUA is
capable.
---
 doc/man1/notmuch-reply.rst     | 12 ++++++++++++
 notmuch-client.h               |  4 +++-
 notmuch-reply.c                | 20 ++++++++++++--------
 notmuch-show.c                 |  9 ++++++++-
 test/T356-protected-headers.sh |  7 +++++++
 5 files changed, 42 insertions(+), 10 deletions(-)

diff --git a/doc/man1/notmuch-reply.rst b/doc/man1/notmuch-reply.rst
index c893ba04..08aadba6 100644
--- a/doc/man1/notmuch-reply.rst
+++ b/doc/man1/notmuch-reply.rst
@@ -70,6 +70,18 @@ Supported options for **reply** include
         order, and copy values from the first that contains something
         other than only the user's addresses.
 
+``--protected-subject=(true|false)``
+
+    Indicates that the replying client plans to protect (hide) the
+    subject in the subsequent reply.  When replying to an encrypted
+    message that itself has an encrypted subject, **notmuch**
+    **reply** needs to propose a subject for the new reply e-mail.  If
+    the client can handle protected subjects safely (if this flag is
+    set to ``true``), then the cleartext subject will be proposed.
+    Otherwise, the external (dummy) subject is proposed, to avoid
+    leaking the previously protected subject on reply. Defaults to
+    ``false``.
+
 ``--decrypt=(false|auto|true)``
 
     If ``true``, decrypt any MIME encrypted parts found in the
diff --git a/notmuch-client.h b/notmuch-client.h
index 0af96986..014fa064 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -235,7 +235,9 @@ typedef enum {
     /* typical "notmuch show" or other standard output: */
     HEADERS_FORMAT_NORMAL = 0,
     /* set only if this is being generated as a reply: */
-    HEADERS_FORMAT_REPLY = 1 << 0
+    HEADERS_FORMAT_REPLY = 1 << 0,
+    /* set only if the invoking MUA will responsibly protect the subject line 
*/
+    HEADERS_FORMAT_PROTECTED_SUBJECT = 1 << 1
 } notmuch_headers_format_flags;
 
 
diff --git a/notmuch-reply.c b/notmuch-reply.c
index 749eac6d..d1092ce9 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -612,7 +612,8 @@ static int do_reply(notmuch_config_t *config,
                    notmuch_query_t *query,
                    notmuch_show_params_t *params,
                    int format,
-                   bool reply_all)
+                   bool reply_all,
+                   bool protected_subject)
 {
     GMimeMessage *reply;
     mime_node_t *node;
@@ -659,18 +660,19 @@ static int do_reply(notmuch_config_t *config,
            return 1;
 
        if (format == FORMAT_JSON || format == FORMAT_SEXP) {
+           notmuch_headers_format_flags flags = HEADERS_FORMAT_REPLY;
            sp->begin_map (sp);
 
-           /* The headers of the reply message we've created */
-           sp->map_key (sp, "reply-headers");
-           /* FIXME: send msg_crypto here to avoid killing the
-            * subject line on reply to encrypted messages! */
-           format_headers_sprinter (sp, reply, HEADERS_FORMAT_REPLY, NULL);
-
            /* Start the original */
            sp->map_key (sp, "original");
            format_part_sprinter (config, sp, node, true, false);
 
+           /* The headers of the reply message we've created */
+           sp->map_key (sp, "reply-headers");
+           if (protected_subject)
+               flags |= HEADERS_FORMAT_PROTECTED_SUBJECT;
+           format_headers_sprinter (sp, reply, flags, 
mime_node_get_message_crypto_status (node));
+
            /* End */
            sp->end (sp);
        } else {
@@ -699,6 +701,7 @@ notmuch_reply_command (notmuch_config_t *config, int argc, 
char *argv[])
     notmuch_database_t *notmuch;
     notmuch_query_t *query;
     char *query_string;
+    bool protected_subject = false;
     int opt_index;
     notmuch_show_params_t params = {
        .part = -1,
@@ -715,6 +718,7 @@ notmuch_reply_command (notmuch_config_t *config, int argc, 
char *argv[])
                                  { "headers-only", FORMAT_HEADERS_ONLY },
                                  { 0, 0 } } },
        { .opt_int = &notmuch_format_version, .name = "format-version" },
+       { .opt_bool = &protected_subject, .name = "protected-subject" },
        { .opt_keyword = &reply_all, .name = "reply-to", .keywords =
          (notmuch_keyword_t []){ { "all", true },
                                  { "sender", false },
@@ -764,7 +768,7 @@ notmuch_reply_command (notmuch_config_t *config, int argc, 
char *argv[])
        return EXIT_FAILURE;
     }
 
-    if (do_reply (config, query, &params, format, reply_all) != 0)
+    if (do_reply (config, query, &params, format, reply_all, 
protected_subject) != 0)
        return EXIT_FAILURE;
 
     _notmuch_crypto_cleanup (&params.crypto);
diff --git a/notmuch-show.c b/notmuch-show.c
index 799940f8..88e1be7a 100644
--- a/notmuch-show.c
+++ b/notmuch-show.c
@@ -209,8 +209,15 @@ format_headers_sprinter (sprinter_t *sp, GMimeMessage 
*message,
     sp->begin_map (sp);
 
     sp->map_key (sp, "Subject");
-    if (msg_crypto && msg_crypto->payload_subject) {
+    if (msg_crypto && msg_crypto->payload_subject &&
+       !(flags & HEADERS_FORMAT_REPLY))
        sp->string (sp, msg_crypto->payload_subject);
+    else if ((msg_crypto && msg_crypto->payload_subject &&
+             (flags & HEADERS_FORMAT_PROTECTED_SUBJECT))) {
+       if (strncasecmp (msg_crypto->payload_subject, "Re:", 3) == 0)
+           sp->string (sp, msg_crypto->payload_subject);
+       else
+           sp->string (sp, talloc_asprintf (local, "Re: %s", 
msg_crypto->payload_subject));
     } else
        sp->string (sp, g_mime_message_get_subject (message));
 
diff --git a/test/T356-protected-headers.sh b/test/T356-protected-headers.sh
index 687681ff..a77dae6d 100755
--- a/test/T356-protected-headers.sh
+++ b/test/T356-protected-headers.sh
@@ -85,4 +85,11 @@ test_json_nodes <<<"$output" \
                 'subject:["original"]["headers"]["Subject"]="This is a 
protected header"' \
                 'reply-subject:["reply-headers"]["Subject"]="Re: encrypted 
message"'
 
+test_begin_subtest "emit protected subject in reply when client is safe"
+output=$(notmuch reply --decrypt=true --format=json --protected-subject 
id:protected-hea...@crypto.notmuchmail.org)
+test_json_nodes <<<"$output" \
+                'crypto:["original"]["crypto"]={"decrypted": {"status": 
"full", "masked-headers": {"Subject": "encrypted message"}}}' \
+                'subject:["original"]["headers"]["Subject"]="This is a 
protected header"' \
+                'reply-subject:["reply-headers"]["Subject"]="Re: This is a 
protected header"'
+
 test_done
-- 
2.17.0

_______________________________________________
notmuch mailing list
notmuch@notmuchmail.org
https://notmuchmail.org/mailman/listinfo/notmuch

Reply via email to