gitlab-org--gitlab-foss/app/models/gpg_key.rb

132 lines
3.3 KiB
Ruby
Raw Normal View History

2017-02-22 11:49:17 +00:00
class GpgKey < ActiveRecord::Base
KEY_PREFIX = '-----BEGIN PGP PUBLIC KEY BLOCK-----'.freeze
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
belongs_to :parent, class_name: 'GpgKey'
has_many :gpg_signatures
has_many :subkeys, class_name: 'GpgKey', foreign_key: :parent_id, dependent: :destroy
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: {
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}'"
},
unless: :parent_id?
2017-02-22 11:49:17 +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) }
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, unless: :parent_id?
after_commit :update_invalid_gpg_signatures, on: :create
after_save :generate_subkeys, unless: :parent_id?
2017-02-22 11:49:17 +00:00
def primary_keyid
super&.upcase
end
def fingerprint
super&.upcase
end
def key
parent_id? ? parent.key : super
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
def user_infos
@user_infos ||= Gitlab::Gpg.user_infos_from_key(key)
end
def verified_user_infos
user_infos.select do |user_info|
user.verified_email?(user_info[:email])
end
2017-02-22 14:37:49 +00:00
end
def emails_with_verified_status
user_infos.map do |user_info|
2017-02-24 20:28:26 +00:00
[
user_info[:email],
user.verified_email?(user_info[: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
def verified?
emails_with_verified_status.values.any?
end
def verified_and_belongs_to_email?(email)
emails_with_verified_status.fetch(email.downcase, false)
end
def update_invalid_gpg_signatures
InvalidGpgSignatureUpdateWorker.perform_async(self.id)
end
def revoke
2017-08-30 11:27:40 +00:00
GpgSignature
.where(gpg_key: self)
.where.not(verification_status: GpgSignature.verification_statuses[:unknown_key])
.update_all(
gpg_key_id: nil,
verification_status: GpgSignature.verification_statuses[:unknown_key],
updated_at: Time.zone.now
)
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
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
def generate_subkeys
gpg_subkeys = Gitlab::Gpg.subkeys_from_key(key)
gpg_subkeys[primary_keyid].each do |subkey_data|
unless subkeys.where(fingerprint: subkey_data[:fingerprint]).exists?
subkeys.create!(
user: user,
primary_keyid: subkey_data[:keyid],
fingerprint: subkey_data[:fingerprint]
)
end
end
end
2017-02-22 11:49:17 +00:00
end