2017-02-22 11:49:17 +00:00
|
|
|
class GpgKey < ActiveRecord::Base
|
|
|
|
KEY_PREFIX = '-----BEGIN PGP PUBLIC KEY BLOCK-----'.freeze
|
2017-07-26 13:47:00 +00:00
|
|
|
KEY_SUFFIX = '-----END PGP PUBLIC KEY BLOCK-----'.freeze
|
2017-02-22 11:49:17 +00:00
|
|
|
|
2017-07-20 13:44:15 +00:00
|
|
|
include ShaAttribute
|
|
|
|
|
|
|
|
sha_attribute :primary_keyid
|
|
|
|
sha_attribute :fingerprint
|
|
|
|
|
2017-02-22 11:49:17 +00:00
|
|
|
belongs_to :user
|
2017-07-20 14:33:44 +00:00
|
|
|
has_many :gpg_signatures
|
2017-02-22 11:49:17 +00:00
|
|
|
|
2017-07-05 12:03:36 +00:00
|
|
|
validates :user, presence: true
|
|
|
|
|
2017-02-22 11:49:17 +00:00
|
|
|
validates :key,
|
|
|
|
presence: true,
|
|
|
|
uniqueness: true,
|
|
|
|
format: {
|
2017-07-26 13:47:00 +00:00
|
|
|
with: /\A#{KEY_PREFIX}((?!#{KEY_PREFIX})(?!#{KEY_SUFFIX}).)+#{KEY_SUFFIX}\Z/m,
|
|
|
|
message: "is invalid. A valid public GPG key begins with '#{KEY_PREFIX}' and ends with '#{KEY_SUFFIX}'"
|
2017-02-22 11:49:17 +00:00
|
|
|
}
|
|
|
|
|
2017-02-22 15:22:39 +00:00
|
|
|
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) }
|
|
|
|
|
2017-06-13 11:46:43 +00:00
|
|
|
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
|
2017-07-05 12:23:23 +00:00
|
|
|
after_commit :update_invalid_gpg_signatures, on: :create
|
|
|
|
after_commit :notify_user, on: :create
|
2017-02-22 11:49:17 +00:00
|
|
|
|
2017-07-25 14:23:52 +00:00
|
|
|
def primary_keyid
|
|
|
|
super&.upcase
|
|
|
|
end
|
|
|
|
|
|
|
|
def fingerprint
|
|
|
|
super&.upcase
|
|
|
|
end
|
|
|
|
|
2017-02-22 11:49:17 +00:00
|
|
|
def key=(value)
|
2017-07-25 18:35:44 +00:00
|
|
|
super(value&.strip)
|
2017-02-22 11:49:17 +00:00
|
|
|
end
|
|
|
|
|
2017-07-13 13:22:15 +00:00
|
|
|
def user_infos
|
|
|
|
@user_infos ||= Gitlab::Gpg.user_infos_from_key(key)
|
|
|
|
end
|
|
|
|
|
|
|
|
def verified_user_infos
|
|
|
|
user_infos.select do |user_info|
|
|
|
|
user_info[:email] == user.email
|
|
|
|
end
|
2017-02-22 14:37:49 +00:00
|
|
|
end
|
|
|
|
|
2017-02-28 14:25:12 +00:00
|
|
|
def emails_with_verified_status
|
2017-07-13 13:22:15 +00:00
|
|
|
user_infos.map do |user_info|
|
2017-02-24 20:28:26 +00:00
|
|
|
[
|
2017-07-13 13:22:15 +00:00
|
|
|
user_info[:email],
|
|
|
|
user_info[:email] == user.email
|
2017-02-24 20:28:26 +00:00
|
|
|
]
|
2017-07-05 11:16:50 +00:00
|
|
|
end.to_h
|
2017-02-24 20:28:26 +00:00
|
|
|
end
|
|
|
|
|
2017-06-15 07:57:50 +00:00
|
|
|
def verified?
|
|
|
|
emails_with_verified_status.any? { |_email, verified| verified }
|
|
|
|
end
|
|
|
|
|
2017-06-15 13:07:44 +00:00
|
|
|
def update_invalid_gpg_signatures
|
2017-06-22 12:18:01 +00:00
|
|
|
InvalidGpgSignatureUpdateWorker.perform_async(self.id)
|
2017-06-15 13:07:44 +00:00
|
|
|
end
|
|
|
|
|
2017-07-12 05:59:28 +00:00
|
|
|
def revoke
|
2017-07-25 19:14:14 +00:00
|
|
|
GpgSignature.where(gpg_key: self, valid_signature: true).update_all(
|
|
|
|
gpg_key_id: nil,
|
|
|
|
valid_signature: false,
|
|
|
|
updated_at: Time.zone.now
|
|
|
|
)
|
2017-07-12 05:59:28 +00:00
|
|
|
|
|
|
|
destroy
|
|
|
|
end
|
|
|
|
|
2017-02-22 11:49:17 +00:00
|
|
|
private
|
|
|
|
|
|
|
|
def extract_fingerprint
|
|
|
|
# we can assume that the result only contains one item as the validation
|
|
|
|
# only allows one key
|
2017-02-22 16:20:42 +00:00
|
|
|
self.fingerprint = Gitlab::Gpg.fingerprints_from_key(key).first
|
2017-02-22 11:49:17 +00:00
|
|
|
end
|
2017-02-22 17:36:25 +00:00
|
|
|
|
2017-06-13 11:46:43 +00:00
|
|
|
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
|
|
|
|
|
2017-02-28 09:49:59 +00:00
|
|
|
def notify_user
|
2017-07-05 12:23:23 +00:00
|
|
|
NotificationService.new.new_gpg_key(self)
|
2017-06-22 12:18:01 +00:00
|
|
|
end
|
2017-02-22 11:49:17 +00:00
|
|
|
end
|