summaryrefslogtreecommitdiff
path: root/spec/lib/gitlab/email/hook/smime_signature_interceptor_spec.rb
blob: 31ba48e9df1b775b02952696785f87a60631e944 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# frozen_string_literal: true

require 'spec_helper'

describe Gitlab::Email::Hook::SmimeSignatureInterceptor do
  include SmimeHelper

  # certs generation is an expensive operation and they are used read-only,
  # so we share them as instance variables in all tests
  before :context do
    @root_ca = generate_root
    @intermediate_ca = generate_intermediate(signer_ca: @root_ca)
    @cert = generate_cert(signer_ca: @intermediate_ca)
  end

  let(:root_certificate) do
    Gitlab::Email::Smime::Certificate.new(@root_ca[:key], @root_ca[:cert])
  end

  let(:intermediate_certificate) do
    Gitlab::Email::Smime::Certificate.new(@intermediate_ca[:key], @intermediate_ca[:cert])
  end

  let(:certificate) do
    Gitlab::Email::Smime::Certificate.new(@cert[:key], @cert[:cert], [intermediate_certificate.cert])
  end

  let(:mail_body) { "signed hello with Unicode €áø and\r\n newlines\r\n" }

  let(:mail) do
    ActionMailer::Base.mail(to: 'test@example.com',
                            from: 'info@example.com',
                            content_transfer_encoding: 'quoted-printable',
                            content_type: 'text/plain; charset=UTF-8',
                            body: mail_body)
  end

  before do
    allow(Gitlab::Email::Smime::Certificate).to receive_messages(from_files: certificate)

    Mail.register_interceptor(described_class)
    mail.deliver_now
  end

  after do
    Mail.unregister_interceptor(described_class)
  end

  it 'signs the email appropriately with SMIME' do
    expect(mail.header['To'].value).to eq('test@example.com')
    expect(mail.header['From'].value).to eq('info@example.com')
    expect(mail.header['Content-Type'].value).to match('multipart/signed').and match('protocol="application/x-pkcs7-signature"')

    # verify signature and obtain pkcs7 encoded content
    p7enc = Gitlab::Email::Smime::Signer.verify_signature(
      ca_certs: root_certificate.cert,
      signed_data: mail.encoded)

    expect(p7enc).not_to be_nil

    # re-verify signature from a new Mail object content
    # See https://gitlab.com/gitlab-org/gitlab/issues/197386
    p7_re_enc = Gitlab::Email::Smime::Signer.verify_signature(
      ca_certs: root_certificate.cert,
      signed_data: Mail.new(mail).encoded)

    expect(p7_re_enc).not_to be_nil

    # envelope in a Mail object and obtain the body
    decoded_mail = Mail.new(p7enc.data)

    expect(decoded_mail.body.decoded.dup.force_encoding(decoded_mail.charset)).to eq(mail_body)
  end
end