diff options
-rw-r--r-- | app/models/gpg_key.rb | 21 | ||||
-rw-r--r-- | db/migrate/20170926050624_add_parent_id_to_gpg_keys.rb | 10 | ||||
-rw-r--r-- | db/schema.rb | 1 | ||||
-rw-r--r-- | lib/gitlab/gpg.rb | 21 |
4 files changed, 51 insertions, 2 deletions
diff --git a/app/models/gpg_key.rb b/app/models/gpg_key.rb index 54bd5b68777..cbf01183969 100644 --- a/app/models/gpg_key.rb +++ b/app/models/gpg_key.rb @@ -9,6 +9,7 @@ class GpgKey < ActiveRecord::Base belongs_to :user has_many :gpg_signatures + has_many :subkeys, class_name: 'GpgKey', foreign_key: :parent_id, dependent: :destroy validates :user, presence: true @@ -18,7 +19,8 @@ class GpgKey < ActiveRecord::Base 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? validates :fingerprint, presence: true, @@ -34,8 +36,9 @@ class GpgKey < ActiveRecord::Base # the error about the fingerprint unless: -> { errors.has_key?(:key) } - before_validation :extract_fingerprint, :extract_primary_keyid + 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? def primary_keyid super&.upcase @@ -106,4 +109,18 @@ class GpgKey < ActiveRecord::Base # 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 end diff --git a/db/migrate/20170926050624_add_parent_id_to_gpg_keys.rb b/db/migrate/20170926050624_add_parent_id_to_gpg_keys.rb new file mode 100644 index 00000000000..ef7675be106 --- /dev/null +++ b/db/migrate/20170926050624_add_parent_id_to_gpg_keys.rb @@ -0,0 +1,10 @@ +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class AddParentIdToGpgKeys < ActiveRecord::Migration + DOWNTIME = false + + def change + add_column :gpg_keys, :parent_id, :integer + end +end diff --git a/db/schema.rb b/db/schema.rb index 17be774e9de..9b1457c9a03 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -586,6 +586,7 @@ ActiveRecord::Schema.define(version: 20171004121444) do t.binary "primary_keyid" t.binary "fingerprint" t.text "key" + t.integer "parent_id" end add_index "gpg_keys", ["fingerprint"], name: "index_gpg_keys_on_fingerprint", unique: true, using: :btree diff --git a/lib/gitlab/gpg.rb b/lib/gitlab/gpg.rb index 0d5039ddf5f..be22a9e0fe2 100644 --- a/lib/gitlab/gpg.rb +++ b/lib/gitlab/gpg.rb @@ -34,6 +34,27 @@ module Gitlab end end + def subkeys_from_key(key) + using_tmp_keychain do + fingerprints = CurrentKeyChain.fingerprints_from_key(key) + raw_keys = GPGME::Key.find(:public, fingerprints) + grouped_subkeys = Hash.new { |h, k| h[k] = [] } + + raw_keys.each_with_object(grouped_subkeys).each do |raw_key, subkeys| + primary_subkey_id = raw_key.primary_subkey.keyid + + raw_key.subkeys.each do |subkey| + # Skip if current subkey is a master key + next if primary_subkey_id == subkey.keyid + # Skip if it isn't a sign key + next if subkey.capability.exclude?(:sign) + + subkeys[primary_subkey_id] << { keyid: subkey.keyid, fingerprint: subkey.fingerprint } + end + end + end + end + def user_infos_from_key(key) using_tmp_keychain do fingerprints = CurrentKeyChain.fingerprints_from_key(key) |