gpg_key.rb 2.13 KB
Newer Older
Alexis Reigel's avatar
Alexis Reigel committed
1
class GpgKey < ActiveRecord::Base
2
3
  include AfterCommitQueue

Alexis Reigel's avatar
Alexis Reigel committed
4
5
6
  KEY_PREFIX = '-----BEGIN PGP PUBLIC KEY BLOCK-----'.freeze

  belongs_to :user
7
  has_many :gpg_signatures, dependent: :nullify
Alexis Reigel's avatar
Alexis Reigel committed
8

9
10
  validates :user, presence: true

Alexis Reigel's avatar
Alexis Reigel committed
11
12
13
14
  validates :key,
    presence: true,
    uniqueness: true,
    format: {
15
16
      with: /\A#{KEY_PREFIX}((?!#{KEY_PREFIX}).)+\Z/m,
      message: "is invalid. A valid public GPG key begins with '#{KEY_PREFIX}'"
Alexis Reigel's avatar
Alexis Reigel committed
17
18
    }

19
20
21
22
23
24
25
  validates :fingerprint,
    presence: true,
    uniqueness: true,
    # only validate when the `key` is valid, as we don't want the user to show
    # the error about the fingerprint
    unless: -> { errors.has_key?(:key) }

26
27
28
29
30
31
32
33
  validates :primary_keyid,
    presence: true,
    uniqueness: true,
    # only validate when the `key` is valid, as we don't want the user to show
    # the error about the fingerprint
    unless: -> { errors.has_key?(:key) }

  before_validation :extract_fingerprint, :extract_primary_keyid
34
  after_create :update_invalid_gpg_signatures_after_create
35
  after_create :notify_user
Alexis Reigel's avatar
Alexis Reigel committed
36
37
38
39
40
41

  def key=(value)
    value.strip! unless value.blank?
    write_attribute(:key, value)
  end

Alexis Reigel's avatar
Alexis Reigel committed
42
  def emails
43
44
45
    @emails ||= Gitlab::Gpg.emails_from_key(key)
  end

Alexis Reigel's avatar
Alexis Reigel committed
46
  def emails_with_verified_status
47
    emails.map do |email|
Alexis Reigel's avatar
Alexis Reigel committed
48
49
      [
        email,
Alexis Reigel's avatar
Alexis Reigel committed
50
        email == user.email
Alexis Reigel's avatar
Alexis Reigel committed
51
      ]
Alexis Reigel's avatar
Alexis Reigel committed
52
    end.to_h
Alexis Reigel's avatar
Alexis Reigel committed
53
54
  end

55
56
57
58
  def verified?
    emails_with_verified_status.any? { |_email, verified| verified }
  end

59
  def update_invalid_gpg_signatures
60
    InvalidGpgSignatureUpdateWorker.perform_async(self.id)
61
62
  end

Alexis Reigel's avatar
Alexis Reigel committed
63
64
65
66
67
  private

  def extract_fingerprint
    # we can assume that the result only contains one item as the validation
    # only allows one key
68
    self.fingerprint = Gitlab::Gpg.fingerprints_from_key(key).first
Alexis Reigel's avatar
Alexis Reigel committed
69
  end
70

71
72
73
74
75
76
  def extract_primary_keyid
    # we can assume that the result only contains one item as the validation
    # only allows one key
    self.primary_keyid = Gitlab::Gpg.primary_keyids_from_key(key).first
  end

77
78
79
  def notify_user
    run_after_commit { NotificationService.new.new_gpg_key(self) }
  end
80
81
82
83

  def update_invalid_gpg_signatures_after_create
    run_after_commit { update_invalid_gpg_signatures }
  end
Alexis Reigel's avatar
Alexis Reigel committed
84
end