-
Notifications
You must be signed in to change notification settings - Fork 204
Bug 2050896 - Add secure bug link to PGP email body #2735
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -499,15 +499,26 @@ sub _make_secure { | |
| body => _tct_encrypt($tct, $to_encrypt, $bug_id) | ||
| ), | ||
| ); | ||
| $email->parts_set(\@new_parts); | ||
| my $new_boundary = $email->{ct}{attributes}{boundary}; | ||
|
|
||
| # Redo the old content type header with the new boundaries | ||
| # and other information needed for PGP | ||
| $email->header_set("Content-Type", | ||
| "multipart/encrypted; " | ||
| . "protocol=\"application/pgp-encrypted\"; " | ||
| . "boundary=\"$new_boundary\""); | ||
| # Keep the PGP/MIME payload as a standards-compliant two-part | ||
| # multipart/encrypted message. For fully secure bugmail, wrap it in a | ||
| # multipart/mixed message with a plaintext link so clients which do not | ||
| # expose the OpenPGP armour comment (notably Gmail) provide a usable | ||
| # route back to the bug. | ||
| my $encrypted_part = Email::MIME->create( | ||
| attributes => {content_type => 'multipart/encrypted'}, | ||
| parts => \@new_parts, | ||
| ); | ||
| _set_pgp_content_type($encrypted_part); | ||
|
|
||
| if ($sanitize_subject && $bug_id) { | ||
| _wrap_pgp_bugmail($email, $encrypted_part, _bug_url($bug_id)); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. medium — PGP/MIME is no longer the top-level content type for secure bugmail. RFC 3156 clients that only auto-detect This is the deliberate trade-off of the PR, but it changes the shape of all fully-secure bugmail for all PGP users in order to fix a Gmail-only presentation problem. Worth confirming against the MUAs BMO's secure-mail users actually run before landing.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, this makes the tradeoff unacceptable for this change. Adding some preference that controls this seems like more work than it's worth. A Firefox extension that adds a link would probably be easier (but only benefits those who install it). I've actually installed Flowcrypt (Gmail GPG plugin) again. :-/ I had hoped we could expose a Gmail-friendly cleartext link while preserving normal behavior for existing PGP/MIME clients, but that does not appear possible within the expected MIME structure. I don’t want to change secure-mail behavior for every PGP user, or risk degraded handling in clients such as Outlook/GpgOL, solely to improve Gmail’s presentation. I’m going to abandon this approach and close the PR. Thank you for the detailed compatibility analysis. |
||
| } | ||
| else { | ||
| # Preserve the original top-level PGP/MIME structure for all other | ||
| # encrypted mail, such as private-comment notifications. | ||
| $email->parts_set(\@new_parts); | ||
| _set_pgp_content_type($email); | ||
| } | ||
| } | ||
| else { | ||
| _fix_encoding($email); | ||
|
|
@@ -597,8 +608,7 @@ sub _make_secure { | |
| sub _tct_encrypt { | ||
| my ($tct, $text, $bug_id) = @_; | ||
|
|
||
| my $comment = Bugzilla->localconfig->urlbase | ||
| . ($bug_id ? 'show_bug.cgi?id=' . $bug_id : ''); | ||
| my $comment = _bug_url($bug_id); | ||
| my $encrypted; | ||
| my $ok = eval { $encrypted = $tct->encrypt($text, $comment)->get; 1 }; | ||
| if (!$ok) { | ||
|
|
@@ -614,6 +624,36 @@ sub _tct_encrypt { | |
| return $encrypted; | ||
| } | ||
|
|
||
| sub _bug_url { | ||
| my ($bug_id) = @_; | ||
| return Bugzilla->localconfig->urlbase | ||
| . ($bug_id ? 'show_bug.cgi?id=' . $bug_id : ''); | ||
| } | ||
|
|
||
| sub _wrap_pgp_bugmail { | ||
| my ($email, $encrypted_part, $bug_url) = @_; | ||
|
|
||
| my $link_part = Email::MIME->create( | ||
| attributes => { | ||
| content_type => 'text/plain', | ||
| charset => 'UTF-8', | ||
| encoding => 'quoted-printable', | ||
| }, | ||
| body_str => "View this bug: $bug_url\n", | ||
| ); | ||
| $email->parts_set([$link_part, $encrypted_part]); | ||
| $email->content_type_set('multipart/mixed'); | ||
| } | ||
|
|
||
| sub _set_pgp_content_type { | ||
| my ($email) = @_; | ||
| my $boundary = $email->{ct}{attributes}{boundary}; | ||
| $email->header_set("Content-Type", | ||
| "multipart/encrypted; " | ||
| . "protocol=\"application/pgp-encrypted\"; " | ||
| . "boundary=\"$boundary\""); | ||
| } | ||
|
|
||
| # Insert the subject into the part's body, as the subject of the message will | ||
| # be sanitized. | ||
| # XXX this incorrectly assumes all parts of the message are the body | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| # This Source Code Form is subject to the terms of the Mozilla Public | ||
| # License, v. 2.0. If a copy of the MPL was not distributed with this | ||
| # file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
|
|
||
| package main; | ||
|
|
||
| use strict; | ||
| use warnings; | ||
| use 5.10.1; | ||
| use lib qw(. lib local/lib/perl5 extensions/SecureMail/lib); | ||
|
|
||
| use Test::More; | ||
| use Email::MIME; | ||
|
|
||
| BEGIN { | ||
| *Bugzilla::Extension::SecureMail::NAME = sub { 1 }; | ||
| } | ||
|
|
||
| my $extension = './extensions/SecureMail/Extension.pm'; | ||
| require $extension; | ||
|
|
||
| my $email = Email::MIME->create( | ||
| attributes => {content_type => 'multipart/alternative'}, | ||
| parts => [], | ||
| ); | ||
| my $control_part = Email::MIME->create( | ||
| attributes => { | ||
| content_type => 'application/pgp-encrypted', | ||
| encoding => '7bit', | ||
| }, | ||
| body => "Version: 1\n", | ||
| ); | ||
| my $data_part = Email::MIME->create( | ||
| attributes => { | ||
| content_type => 'application/octet-stream', | ||
| encoding => '7bit', | ||
| }, | ||
| body => 'encrypted data', | ||
| ); | ||
| my $encrypted_part = Email::MIME->create( | ||
| attributes => {content_type => 'multipart/encrypted'}, | ||
| parts => [$control_part, $data_part], | ||
| ); | ||
|
|
||
| Bugzilla::Extension::SecureMail::_wrap_pgp_bugmail( | ||
| $email, | ||
| $encrypted_part, | ||
| 'https://bugzilla.example/show_bug.cgi?id=123', | ||
| ); | ||
|
|
||
| like($email->content_type, qr{\Amultipart/mixed(?:;|\z)}, | ||
| 'outer message is multipart/mixed'); | ||
| my @outer_parts = $email->parts; | ||
| is(scalar @outer_parts, 2, 'outer message contains the link and encrypted message'); | ||
| like($outer_parts[0]->content_type, qr{\Atext/plain(?:;|\z)}, | ||
| 'first part is plaintext'); | ||
| like($outer_parts[0]->body_str, | ||
| qr{\AView this bug: https://bugzilla\.example/show_bug\.cgi\?id=123\r?\n\z}, | ||
| 'plaintext part contains the bug URL'); | ||
| like($outer_parts[1]->content_type, qr{\Amultipart/encrypted(?:;|\z)}, | ||
| 'second part is the PGP/MIME message'); | ||
| my @encrypted_parts = $outer_parts[1]->parts; | ||
| is(scalar @encrypted_parts, 2, 'PGP/MIME message retains its two required parts'); | ||
| is($encrypted_parts[0]->content_type, 'application/pgp-encrypted', | ||
| 'first PGP/MIME part is the control information'); | ||
| is($encrypted_parts[1]->content_type, 'application/octet-stream', | ||
| 'second PGP/MIME part is encrypted data'); | ||
|
|
||
| my $unwrapped_email = Email::MIME->create( | ||
| attributes => {content_type => 'multipart/alternative'}, | ||
| parts => [], | ||
| ); | ||
| $unwrapped_email->parts_set([$control_part, $data_part]); | ||
| Bugzilla::Extension::SecureMail::_set_pgp_content_type($unwrapped_email); | ||
| my ($boundary) = $unwrapped_email->header('Content-Type') =~ /boundary="([^"]+)"/; | ||
| is($boundary, $unwrapped_email->{ct}{attributes}{boundary}, | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. low — this assertion cannot fail.
More importantly, the test file never calls |
||
| 'unwrapped PGP/MIME header declares its own generated boundary'); | ||
| like($unwrapped_email->as_string, qr/--\Q$boundary\E/, | ||
| 'unwrapped PGP/MIME body uses its declared boundary'); | ||
|
|
||
| done_testing; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
low —
$encrypted_partis built unconditionally, then discarded on theelsepath.Email::MIME->create(parts => \@new_parts)runs a fullparts_set(serialize every part) plusfill_parts(re-parse the result) — for a bug with large attachments that is a multi-MB round trip — and the object is thrown away for every private-comment notification, whine mail, password mail, andX-Bugzilla-Encryptmail.Move the
create+_set_pgp_content_type($encrypted_part)inside theif ($sanitize_subject && $bug_id)branch.