123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595 |
- # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
- require 'rails_helper'
- RSpec.describe 'Ticket zoom > Secure mailing', authenticated_as: :authenticate, type: :system do
- shared_examples 'secure mailing received mail' do
- context 'when receiving mail' do
- describe 'article meta information' do
- context 'when result is success' do
- let(:article) do
- create(:ticket_article, preferences: {
- security: {
- type: 'S/MIME',
- encryption: {
- success: true,
- comment: 'COMMENT_ENCRYPT_SUCCESS',
- },
- sign: {
- success: true,
- comment: 'COMMENT_SIGN_SUCCESS',
- },
- }
- }, ticket: ticket)
- end
- it 'shows encryption/sign information' do
- visit "#ticket/zoom/#{article.ticket.id}"
- within :active_ticket_article, article do
- within '.alert--blank' do
- expect(page).to have_css('svg.icon-lock')
- .and(have_css('svg.icon-signed'))
- end
- end
- open_article_meta
- within :active_ticket_article, article do
- within '.article-meta-value', text: %r{S/MIME} do
- expect(page).to have_css('span', text: 'Encrypted')
- .and(have_css('span', text: 'Signed'))
- .and(have_css('span[title=COMMENT_ENCRYPT_SUCCESS]'))
- .and(have_css('span[title=COMMENT_SIGN_SUCCESS]'))
- end
- end
- end
- end
- context 'when result is sign block only' do
- let(:article) do
- create(:ticket_article, preferences: {
- security: {
- type: 'S/MIME',
- sign: {
- success: true,
- comment: 'COMMENT_SIGN_SUCCESS',
- },
- }
- }, ticket: ticket)
- end
- it 'shows sign but no encryption information' do
- visit "#ticket/zoom/#{article.ticket.id}"
- within :active_ticket_article, article do
- within '.alert--blank' do
- expect(page).to have_no_css('svg.icon-lock')
- .and(have_css('svg.icon-signed'))
- end
- end
- open_article_meta
- within :active_ticket_article, article do
- within '.article-meta-value', text: %r{S/MIME} do
- expect(page).to have_no_css('span', text: 'Encrypted')
- .and(have_no_css('span', text: 'Encryption error'))
- .and(have_css('span', text: 'Signed'))
- .and(have_css('span[title=COMMENT_SIGN_SUCCESS]'))
- end
- end
- end
- end
- context 'when result is encryption block and sign block without comment' do
- let(:article) do
- create(:ticket_article, preferences: {
- security: {
- type: 'S/MIME',
- encryption: {
- success: true,
- comment: 'COMMENT_ENCRYPT_SUCCESS',
- },
- sign: {
- success: false
- },
- }
- }, ticket: ticket)
- end
- it 'shows encryption but no sign information' do
- visit "#ticket/zoom/#{article.ticket.id}"
- within :active_ticket_article, article do
- within '.alert--blank' do
- expect(page).to have_css('svg.icon-lock')
- .and(have_no_css('svg.icon-signed'))
- end
- end
- open_article_meta
- within :active_ticket_article, article do
- within '.article-meta-value', text: %r{S/MIME} do
- expect(page).to have_no_css('span', text: 'Signed')
- .and(have_no_css('span', text: 'Sign error'))
- .and(have_no_css('span', text: 'Encryption error'))
- .and(have_css('span', text: 'Encrypted'))
- .and(have_css('span[title=COMMENT_ENCRYPT_SUCCESS]'))
- end
- end
- end
- end
- context 'when result is error' do
- let(:article) do
- create(:ticket_article, preferences: {
- security: {
- type: 'S/MIME',
- encryption: {
- success: false,
- comment: 'Encryption failed because XXX',
- },
- sign: {
- success: false,
- comment: 'Sign failed because XXX',
- },
- }
- }, ticket: ticket)
- end
- it 'shows create information about encryption/sign failed' do
- visit "#ticket/zoom/#{article.ticket.id}"
- within :active_ticket_article, article do
- expect(page).to have_css('svg.icon-not-signed')
- expect(page).to have_css('div.alert.alert--warning', text: 'Encryption failed because XXX')
- .and(have_css('div.alert.alert--warning', text: 'Sign failed because XXX'))
- end
- open_article_meta
- within :active_ticket_article, article do
- within '.article-meta-value', text: %r{S/MIME} do
- expect(page).to have_css('span', text: 'Encryption error')
- .and(have_css('span', text: 'Sign error'))
- .and(have_css('span[title="Encryption failed because XXX"]'))
- .and(have_css('span[title="Sign failed because XXX"]'))
- end
- end
- end
- end
- end
- context 'when certificate not present at time of arrival' do
- let(:mail) do
- secure_mailing_1 = create(secure_mailing_factory_name, :with_private, fixture: system_email_address)
- secure_mailing_2 = create(secure_mailing_factory_name, :with_private, fixture: sender_email_address)
- mail = Channel::EmailBuild.build(
- from: sender_email_address,
- to: system_email_address,
- body: 'somebody with some text',
- content_type: 'text/plain',
- security: {
- type: secure_mailing_type_name,
- sign: {
- success: true,
- },
- encryption: {
- success: true,
- },
- },
- )
- secure_mailing_1.destroy
- secure_mailing_2.destroy
- mail
- end
- it 'does retry successfully' do
- parsed_mail = Channel::EmailParser.new.parse(mail.to_s)
- ticket, article, _user, _mail = Channel::EmailParser.new.process({ group_id: group.id }, parsed_mail['raw'])
- expect(Ticket::Article.find(article.id).body).to eq('no visible content')
- create(secure_mailing_factory_name, fixture: sender_email_address)
- create(secure_mailing_factory_name, :with_private, fixture: system_email_address)
- visit "#ticket/zoom/#{ticket.id}"
- expect(page).to have_no_css('.article-content', text: 'somebody with some text')
- click '.js-securityRetryProcess'
- expect(page).to have_css('.article-content', text: 'somebody with some text')
- end
- it 'does fail on retry (S/MIME function buttons no longer working in tickets #3957)' do
- parsed_mail = Channel::EmailParser.new.parse(mail.to_s)
- ticket, article, _user, _mail = Channel::EmailParser.new.process({ group_id: group.id }, parsed_mail['raw'])
- expect(Ticket::Article.find(article.id).body).to eq('no visible content')
- visit "#ticket/zoom/#{ticket.id}"
- expect(page).to have_no_css('.article-content', text: 'somebody with some text')
- click '.js-securityRetryProcess'
- expect(page).to have_css('#notify', text: secure_mailing_decryption_failed_message)
- end
- end
- end
- end
- shared_examples 'secure mailing replying' do
- context 'when replying', authenticated_as: :setup_and_authenticate do
- def setup_and_authenticate
- create(:ticket_article, ticket: ticket, from: customer.email)
- create(secure_mailing_factory_name, :with_private, fixture: system_email_address)
- create(secure_mailing_factory_name, fixture: sender_email_address)
- authenticate
- end
- it 'plain' do
- visit "#ticket/zoom/#{ticket.id}"
- all('a[data-type=emailReply]').last.click
- find('.articleNewEdit-body').send_keys('Test')
- expect(page).to have_css('.js-securityEncrypt.btn--active')
- .and(have_css('.js-securitySign.btn--active'))
- click '.js-securityEncrypt'
- click '.js-securitySign'
- click '.js-submit'
- expect(page).to have_css('.ticket-article-item', count: 2)
- expect(Ticket::Article.last.preferences['security']['encryption']['success']).to be_nil
- expect(Ticket::Article.last.preferences['security']['sign']['success']).to be_nil
- end
- it 'signed' do
- visit "#ticket/zoom/#{ticket.id}"
- all('a[data-type=emailReply]').last.click
- find('.articleNewEdit-body').send_keys('Test')
- expect(page).to have_css('.js-securityEncrypt.btn--active')
- expect(page).to have_css('.js-securitySign.btn--active')
- click '.js-securityEncrypt'
- click '.js-submit'
- expect(page).to have_css('.ticket-article-item', count: 2)
- expect(Ticket::Article.last.preferences).to include(
- 'security' => include(
- 'encryption' => be_empty,
- 'sign' => include('success' => be_truthy),
- )
- )
- end
- it 'encrypted' do
- visit "#ticket/zoom/#{ticket.id}"
- all('a[data-type=emailReply]').last.click
- find('.articleNewEdit-body').send_keys('Test')
- expect(page).to have_css('.js-securityEncrypt.btn--active')
- expect(page).to have_css('.js-securitySign.btn--active')
- click '.js-securitySign'
- click '.js-submit'
- expect(page).to have_css('.ticket-article-item', count: 2)
- expect(Ticket::Article.last.preferences).to include(
- 'security' => include(
- 'encryption' => include('success' => be_truthy),
- 'sign' => be_empty,
- )
- )
- end
- it 'signed and encrypted' do
- visit "#ticket/zoom/#{ticket.id}"
- all('a[data-type=emailReply]').last.click
- find('.articleNewEdit-body').send_keys('Test')
- expect(page).to have_css('.js-securityEncrypt.btn--active')
- expect(page).to have_css('.js-securitySign.btn--active')
- click '.js-submit'
- expect(page).to have_css('.ticket-article-item', count: 2)
- expect(Ticket::Article.last.preferences).to include(
- 'security' => include(
- 'encryption' => include('success' => be_truthy),
- 'sign' => include('success' => be_truthy),
- )
- )
- end
- end
- end
- shared_examples 'secure mailing group behavior' do
- describe 'Group default behavior', authenticated_as: :setup_and_authenticate do
- let(:secure_mailing_config) { {} }
- def setup_and_authenticate
- Setting.set(secure_mailing_config_name, secure_mailing_config)
- create(:ticket_article, ticket: ticket, from: customer.email)
- create(secure_mailing_factory_name, :with_private, fixture: system_email_address)
- create(secure_mailing_factory_name, fixture: sender_email_address)
- authenticate
- end
- shared_examples 'security defaults example' do |sign:, encrypt:|
- it "security defaults sign: #{sign}, encrypt: #{encrypt}" do
- within(:active_content) do
- if sign
- expect(page).to have_css('.js-securitySign.btn--active')
- else
- expect(page).to have_no_css('.js-securitySign.btn--active')
- end
- if encrypt
- expect(page).to have_css('.js-securityEncrypt.btn--active')
- else
- expect(page).to have_no_css('.js-securityEncrypt.btn--active')
- end
- end
- end
- end
- shared_examples 'security defaults' do |sign:, encrypt:|
- before do
- visit "#ticket/zoom/#{ticket.id}"
- within(:active_content) do
- all('a[data-type=emailReply]').last.click
- find('.articleNewEdit-body').send_keys('Test')
- end
- end
- include_examples 'security defaults example', sign: sign, encrypt: encrypt
- end
- shared_examples 'security defaults group change' do |sign:, encrypt:|
- before do
- visit "#ticket/zoom/#{ticket.id}"
- within(:active_content) do
- all('a[data-type=emailReply]').last.click
- find('.articleNewEdit-body').send_keys('Test')
- set_tree_select_value('group_id', new_group.name)
- end
- end
- include_examples 'security defaults example', sign: sign, encrypt: encrypt
- end
- context 'when not configured' do
- it_behaves_like 'security defaults', sign: true, encrypt: true
- end
- context 'when configuration present' do
- let(:secure_mailing_config) do
- {
- 'group_id' => group_defaults
- }
- end
- let(:group_defaults) do
- {
- 'default_encryption' => {
- group.id.to_s => default_encryption,
- },
- 'default_sign' => {
- group.id.to_s => default_sign,
- }
- }
- end
- let(:default_sign) { true }
- let(:default_encryption) { true }
- shared_examples 'sign and encrypt variations' do |check_examples_name|
- it_behaves_like check_examples_name, sign: true, encrypt: true
- context 'when no value present' do
- let(:group_defaults) { {} }
- it_behaves_like check_examples_name, sign: true, encrypt: true
- end
- context 'when signing is disabled' do
- let(:default_sign) { false }
- it_behaves_like check_examples_name, sign: false, encrypt: true
- end
- context 'when encryption is disabled' do
- let(:default_encryption) { false }
- it_behaves_like check_examples_name, sign: true, encrypt: false
- end
- end
- context 'when same Group' do
- it_behaves_like 'sign and encrypt variations', 'security defaults'
- end
- context 'when Group change' do
- let(:new_group) { create(:group, email_address: email_address) }
- let(:agent_groups) { [group, new_group] }
- let(:group_defaults) do
- {
- 'default_encryption' => {
- new_group.id.to_s => default_encryption,
- },
- 'default_sign' => {
- new_group.id.to_s => default_sign,
- }
- }
- end
- it_behaves_like 'sign and encrypt variations', 'security defaults group change'
- end
- end
- end
- end
- describe 'S/MIME active', authenticated_as: :authenticate do
- let(:system_email_address) { 'smime1@example.com' }
- let(:email_address) { create(:email_address, email: system_email_address) }
- let(:group) { create(:group, email_address: email_address) }
- let(:agent_groups) { [group] }
- let(:agent) { create(:agent, groups: agent_groups) }
- let(:secure_mailing_factory_name) { :smime_certificate }
- let(:secure_mailing_config_name) { :smime_config }
- let(:secure_mailing_type_name) { 'S/MIME' }
- let(:secure_mailing_decryption_failed_message) { 'Decryption failed! The private key for decryption could not be found.' }
- let(:sender_email_address) { 'smime2@example.com' }
- let(:customer) { create(:customer, email: sender_email_address) }
- let(:ticket) { create(:ticket, group: group, owner: agent, customer: customer) }
- def authenticate
- Setting.set('smime_integration', true)
- agent
- end
- include_examples 'secure mailing received mail'
- include_examples 'secure mailing replying'
- include_examples 'secure mailing group behavior'
- end
- describe 'PGP active', authenticated_as: :authenticate do
- let(:system_email_address) { 'pgp1@example.com' }
- let(:email_address) { create(:email_address, email: system_email_address) }
- let(:group) { create(:group, email_address: email_address) }
- let(:agent_groups) { [group] }
- let(:agent) { create(:agent, groups: agent_groups) }
- let(:secure_mailing_factory_name) { :pgp_key }
- let(:secure_mailing_config_name) { :pgp_config }
- let(:secure_mailing_type_name) { 'PGP' }
- let(:secure_mailing_decryption_failed_message) { 'Decryption failed! The private PGP key could not be found.' }
- let(:sender_email_address) { 'pgp2@example.com' }
- let(:customer) { create(:customer, email: sender_email_address) }
- let(:ticket) { create(:ticket, group: group, owner: agent, customer: customer) }
- def authenticate
- Setting.set('pgp_integration', true)
- agent
- end
- include_examples 'secure mailing received mail'
- include_examples 'secure mailing replying'
- include_examples 'secure mailing group behavior'
- end
- context 'with both PGP and S/MIME integration', authenticated_as: :authenticate do
- def authenticate
- Setting.set('pgp_integration', true)
- Setting.set('smime_integration', true)
- agent
- end
- let(:system_email_address) { 'pgp+smime-sender@example.com' }
- let(:recipient_email_address) { 'pgp+smime-recipient@example.com' }
- let(:email_address) { create(:email_address, email: system_email_address) }
- let(:group) { create(:group, email_address: email_address) }
- let(:agent) { create(:agent, groups: [group]) }
- let(:customer) { create(:customer, email: recipient_email_address) }
- let(:ticket) { create(:ticket, group: group, owner: agent, customer: customer) }
- shared_examples 'showing security type switcher' do
- it 'shows security type switcher' do
- visit "#ticket/zoom/#{ticket.id}"
- within(:active_content) do
- all('a[data-type=emailReply]').last.click
- expect(page).to have_css('.btn', text: 'PGP')
- .and(have_css('.btn.btn--active', text: 'S/MIME')) # preferred
- end
- end
- end
- context 'with no certificates nor keys present' do
- before do
- create(:ticket_article, ticket: ticket, from: customer.email)
- end
- it_behaves_like 'showing security type switcher'
- end
- context 'with certificates and keys present' do
- before do
- create(:ticket_article, ticket: ticket, from: customer.email)
- create(:pgp_key, :with_private, fixture: system_email_address)
- create(:pgp_key, fixture: recipient_email_address)
- create(:smime_certificate, :with_private, fixture: system_email_address)
- create(:smime_certificate, fixture: recipient_email_address)
- end
- it_behaves_like 'showing security type switcher'
- it 'switches between security types' do
- visit "#ticket/zoom/#{ticket.id}"
- within(:active_content) do
- all('a[data-type=emailReply]').last.click
- # Wait until the security options check AJAX call is ready.
- expect(page).to have_css('div.js-securityEncrypt.btn--active')
- .and(have_css('div.js-securitySign.btn--active'))
- expect(page).to have_css('.btn', text: 'PGP')
- .and(have_css('.btn.btn--active', text: 'S/MIME')) # preferred
- expect(find('.js-securityEncryptComment')['title']).to eq('The certificates for pgp+smime-recipient@example.com were found.')
- expect(find('.js-securitySignComment')['title']).to eq('The certificate for pgp+smime-sender@example.com was found.')
- click '.btn', text: 'PGP'
- # Wait until the security options check AJAX call is ready.
- expect(page).to have_css('div.js-securityEncrypt.btn--active')
- .and(have_css('div.js-securitySign.btn--active'))
- expect(page).to have_no_css('.btn.btn--active', text: 'S/MIME')
- .and(have_css('.btn.btn--active', text: 'PGP'))
- expect(find('.js-securityEncryptComment')['title']).to eq('The PGP keys for pgp+smime-recipient@example.com were found.')
- expect(find('.js-securitySignComment')['title']).to eq('The PGP key for pgp+smime-sender@example.com was found.')
- end
- end
- end
- end
- end
|