5 use RT::Test tests => 492;
7 plan skip_all => 'GnuPG required.'
8 unless eval 'use GnuPG::Interface; 1';
9 plan skip_all => 'gpg executable is required.'
10 unless RT::Test->find_executable('gpg');
13 use RT::Action::SendEmail;
14 use File::Temp qw(tempdir);
16 RT::Test->set_mail_catcher;
18 use_ok('RT::Crypt::GnuPG');
20 RT->Config->Set( GnuPG =>
22 OutgoingMessagesFormat => 'RFC',
25 RT->Config->Set( GnuPGOptions =>
26 homedir => scalar tempdir( CLEANUP => 1 ),
27 passphrase => 'rt-test',
28 'no-permission-warning' => undef,
29 'trust-model' => 'always',
31 RT->Config->Set( 'MailPlugins' => 'Auth::MailFrom', 'Auth::GnuPG' );
33 RT::Test->import_gnupg_key('rt-recipient@example.com');
34 RT::Test->import_gnupg_key('rt-test@example.com', 'public');
36 my $queue = RT::Test->load_or_create_queue(
38 CorrespondAddress => 'rt-recipient@example.com',
39 CommentAddress => 'rt-recipient@example.com',
41 ok $queue && $queue->id, 'loaded or created queue';
44 Principal => 'Everyone',
45 Right => ['CreateTicket', 'ShowTicket', 'SeeQueue', 'ReplyToTicket', 'ModifyTicket'],
48 my ($baseurl, $m) = RT::Test->started_ok;
49 ok $m->login, 'logged in';
55 { Sign => 1, Encrypt => 1 },
63 signed_encrypted => [],
66 diag "check in read-only mode that queue's props influence create/update ticket pages" if $ENV{TEST_VERBOSE};
68 foreach my $variant ( @variants ) {
69 set_queue_crypt_options( %$variant );
70 $m->goto_create_ticket( $queue );
71 $m->form_name('TicketCreate');
72 if ( $variant->{'Encrypt'} ) {
73 ok $m->value('Encrypt', 2), "encrypt tick box is checked";
75 ok !$m->value('Encrypt', 2), "encrypt tick box is unchecked";
77 if ( $variant->{'Sign'} ) {
78 ok $m->value('Sign', 2), "sign tick box is checked";
80 ok !$m->value('Sign', 2), "sign tick box is unchecked";
84 # to avoid encryption/signing during create
85 set_queue_crypt_options();
87 my $ticket = RT::Ticket->new( $RT::SystemUser );
88 my ($id) = $ticket->Create(
91 Requestor => 'rt-test@example.com',
93 ok $id, 'ticket created';
95 foreach my $variant ( @variants ) {
96 set_queue_crypt_options( %$variant );
97 $m->goto_ticket( $id );
98 $m->follow_link_ok({text => 'Reply'}, '-> reply');
100 if ( $variant->{'Encrypt'} ) {
101 ok $m->value('Encrypt', 2), "encrypt tick box is checked";
103 ok !$m->value('Encrypt', 2), "encrypt tick box is unchecked";
105 if ( $variant->{'Sign'} ) {
106 ok $m->value('Sign', 2), "sign tick box is checked";
108 ok !$m->value('Sign', 2), "sign tick box is unchecked";
113 # create a ticket for each combination
114 foreach my $queue_set ( @variants ) {
115 set_queue_crypt_options( %$queue_set );
116 foreach my $ticket_set ( @variants ) {
117 create_a_ticket( %$ticket_set );
123 my $ticket = RT::Ticket->new( $RT::SystemUser );
124 ($tid) = $ticket->Create(
127 Requestor => 'rt-test@example.com',
129 ok $tid, 'ticket created';
132 # again for each combination add a reply message
133 foreach my $queue_set ( @variants ) {
134 set_queue_crypt_options( %$queue_set );
135 foreach my $ticket_set ( @variants ) {
136 update_ticket( $tid, %$ticket_set );
141 # ------------------------------------------------------------------------------
142 # now delete all keys from the keyring and put back secret/pub pair for rt-test@
143 # and only public key for rt-recipient@ so we can verify signatures and decrypt
144 # like we are on another side recieve emails
145 # ------------------------------------------------------------------------------
147 unlink $_ foreach glob( RT->Config->Get('GnuPGOptions')->{'homedir'} ."/*" );
148 RT::Test->import_gnupg_key('rt-recipient@example.com', 'public');
149 RT::Test->import_gnupg_key('rt-test@example.com');
151 $queue = RT::Test->load_or_create_queue(
152 Name => 'Regression',
153 CorrespondAddress => 'rt-test@example.com',
154 CommentAddress => 'rt-test@example.com',
156 ok $queue && $queue->id, 'changed props of the queue';
158 foreach my $mail ( map cleanup_headers($_), @{ $mail{'plain'} } ) {
159 my ($status, $id) = RT::Test->send_via_mailgate($mail);
160 is ($status >> 8, 0, "The mail gateway exited normally");
161 ok ($id, "got id of a newly created ticket - $id");
163 my $tick = RT::Ticket->new( $RT::SystemUser );
165 ok ($tick->id, "loaded ticket #$id");
167 my $txn = $tick->Transactions->First;
168 my ($msg, @attachments) = @{$txn->Attachments->ItemsArrayRef};
170 ok !$msg->GetHeader('X-RT-Privacy'), "RT's outgoing mail has no crypto";
171 is $msg->GetHeader('X-RT-Incoming-Encryption'), 'Not encrypted',
172 "RT's outgoing mail looks not encrypted";
173 ok !$msg->GetHeader('X-RT-Incoming-Signature'),
174 "RT's outgoing mail looks not signed";
176 like $msg->Content, qr/Some content/, "RT's mail includes copy of ticket text";
179 foreach my $mail ( map cleanup_headers($_), @{ $mail{'signed'} } ) {
180 my ($status, $id) = RT::Test->send_via_mailgate($mail);
181 is ($status >> 8, 0, "The mail gateway exited normally");
182 ok ($id, "got id of a newly created ticket - $id");
184 my $tick = RT::Ticket->new( $RT::SystemUser );
186 ok ($tick->id, "loaded ticket #$id");
188 my $txn = $tick->Transactions->First;
189 my ($msg, @attachments) = @{$txn->Attachments->ItemsArrayRef};
191 is $msg->GetHeader('X-RT-Privacy'), 'PGP',
192 "RT's outgoing mail has crypto";
193 is $msg->GetHeader('X-RT-Incoming-Encryption'), 'Not encrypted',
194 "RT's outgoing mail looks not encrypted";
195 like $msg->GetHeader('X-RT-Incoming-Signature'),
196 qr/<rt-recipient\@example.com>/,
197 "RT's outgoing mail looks signed";
199 like $attachments[0]->Content, qr/Some content/,
200 "RT's mail includes copy of ticket text";
203 foreach my $mail ( map cleanup_headers($_), @{ $mail{'encrypted'} } ) {
204 my ($status, $id) = RT::Test->send_via_mailgate($mail);
205 is ($status >> 8, 0, "The mail gateway exited normally");
206 ok ($id, "got id of a newly created ticket - $id");
208 my $tick = RT::Ticket->new( $RT::SystemUser );
210 ok ($tick->id, "loaded ticket #$id");
212 my $txn = $tick->Transactions->First;
213 my ($msg, @attachments) = @{$txn->Attachments->ItemsArrayRef};
215 is $msg->GetHeader('X-RT-Privacy'), 'PGP',
216 "RT's outgoing mail has crypto";
217 is $msg->GetHeader('X-RT-Incoming-Encryption'), 'Success',
218 "RT's outgoing mail looks encrypted";
219 ok !$msg->GetHeader('X-RT-Incoming-Signature'),
220 "RT's outgoing mail looks not signed";
222 like $attachments[0]->Content, qr/Some content/,
223 "RT's mail includes copy of ticket text";
226 foreach my $mail ( map cleanup_headers($_), @{ $mail{'signed_encrypted'} } ) {
227 my ($status, $id) = RT::Test->send_via_mailgate($mail);
228 is ($status >> 8, 0, "The mail gateway exited normally");
229 ok ($id, "got id of a newly created ticket - $id");
231 my $tick = RT::Ticket->new( $RT::SystemUser );
233 ok ($tick->id, "loaded ticket #$id");
235 my $txn = $tick->Transactions->First;
236 my ($msg, @attachments) = @{$txn->Attachments->ItemsArrayRef};
238 is $msg->GetHeader('X-RT-Privacy'), 'PGP',
239 "RT's outgoing mail has crypto";
240 is $msg->GetHeader('X-RT-Incoming-Encryption'), 'Success',
241 "RT's outgoing mail looks encrypted";
242 like $msg->GetHeader('X-RT-Incoming-Signature'),
243 qr/<rt-recipient\@example.com>/,
244 "RT's outgoing mail looks signed";
246 like $attachments[0]->Content, qr/Some content/,
247 "RT's mail includes copy of ticket text";
250 sub create_a_ticket {
253 RT::Test->clean_caught_mails;
255 $m->goto_create_ticket( $queue );
256 $m->form_name('TicketCreate');
257 $m->field( Subject => 'test' );
258 $m->field( Requestors => 'rt-test@example.com' );
259 $m->field( Content => 'Some content' );
261 foreach ( qw(Sign Encrypt) ) {
265 $m->untick( $_ => 1 );
270 is $m->status, 200, "request successful";
272 unlike($m->content, qr/unable to sign outgoing email messages/);
274 $m->get_ok('/'); # ensure that the mail has been processed
276 my @mail = RT::Test->fetch_caught_mails;
277 check_text_emails( \%args, @mail );
284 RT::Test->clean_caught_mails;
286 ok $m->goto_ticket( $tid ), "UI -> ticket #$tid";
287 $m->follow_link_ok( { text => 'Reply' }, 'ticket -> reply' );
289 $m->field( UpdateContent => 'Some content' );
291 foreach ( qw(Sign Encrypt) ) {
295 $m->untick( $_ => 1 );
299 $m->click('SubmitTicket');
300 is $m->status, 200, "request successful";
301 $m->content_like(qr/Message recorded/, 'Message recorded') or diag $m->content;
303 $m->get_ok('/'); # ensure that the mail has been processed
305 my @mail = RT::Test->fetch_caught_mails;
306 check_text_emails( \%args, @mail );
309 sub check_text_emails {
310 my %args = %{ shift @_ };
313 ok scalar @mail, "got some mail";
314 for my $mail (@mail) {
315 if ( $args{'Encrypt'} ) {
316 unlike $mail, qr/Some content/, "outgoing email was encrypted";
318 like $mail, qr/Some content/, "outgoing email was not encrypted";
320 if ( $args{'Sign'} && $args{'Encrypt'} ) {
321 like $mail, qr/BEGIN PGP MESSAGE/, 'outgoing email was signed';
322 } elsif ( $args{'Sign'} ) {
323 like $mail, qr/SIGNATURE/, 'outgoing email was signed';
325 unlike $mail, qr/SIGNATURE/, 'outgoing email was not signed';
328 if ( $args{'Sign'} && $args{'Encrypt'} ) {
329 push @{ $mail{'signed_encrypted'} }, @mail;
330 } elsif ( $args{'Sign'} ) {
331 push @{ $mail{'signed'} }, @mail;
332 } elsif ( $args{'Encrypt'} ) {
333 push @{ $mail{'encrypted'} }, @mail;
335 push @{ $mail{'plain'} }, @mail;
339 sub cleanup_headers {
341 # strip id from subject to create new ticket
342 $mail =~ s/^(Subject:)\s*\[.*?\s+#\d+\]\s*/$1 /m;
343 # strip several headers
344 foreach my $field ( qw(Message-ID X-RT-Original-Encoding RT-Originator RT-Ticket X-RT-Loop-Prevention) ) {
345 $mail =~ s/^$field:.*?\n(?! |\t)//gmsi;
350 sub set_queue_crypt_options {
352 $m->get_ok("/Admin/Queues/Modify.html?id=". $queue->id);
353 $m->form_with_fields('Sign', 'Encrypt');
354 foreach my $opt ('Sign', 'Encrypt') {
358 $m->untick($opt => 1);