diff --git a/app/models/gpg_key.rb b/app/models/gpg_key.rb index 6d3537b6fcfbd7fcf753edfec7cbb2ef4b044483..ed09b44027c7a718d6f9c276342426e06bd022fd 100644 --- a/app/models/gpg_key.rb +++ b/app/models/gpg_key.rb @@ -40,17 +40,6 @@ class GpgKey < ActiveRecord::Base after_commit :update_invalid_gpg_signatures, on: :create after_create :generate_subkeys - def self.find_with_subkeys(fingerprint) - keys_table = arel_table - subkeys_table = GpgKeySubkey.arel_table - - condition = keys_table[:primary_keyid].eq(fingerprint).or( - subkeys_table[:keyid].eq(fingerprint) - ) - - joins(:subkeys).where(condition).first - end - def primary_keyid super&.upcase end diff --git a/app/models/gpg_key_subkey.rb b/app/models/gpg_key_subkey.rb index 4f967f1e47c9836073b7eda392c1e5677d925255..8222e5606aa24a5105865497e56b6455c626ddb4 100644 --- a/app/models/gpg_key_subkey.rb +++ b/app/models/gpg_key_subkey.rb @@ -1,3 +1,18 @@ class GpgKeySubkey < ActiveRecord::Base + include ShaAttribute + + sha_attribute :keyid + sha_attribute :fingerprint + belongs_to :gpg_key + + def method_missing(m, *a, &b) + return super unless gpg_key.respond_to?(m) + + gpg_key.public_send(m, *a, &b) # rubocop:disable GitlabSecurity/PublicSend + end + + def respond_to_missing?(method, include_private = false) + gpg_key.respond_to?(method, include_private) || super + end end diff --git a/app/models/gpg_signature.rb b/app/models/gpg_signature.rb index 1f047a32c84e377af75f262ae030e50955e819c1..c7f75288407745777cd94c55e44ef958e2b82936 100644 --- a/app/models/gpg_signature.rb +++ b/app/models/gpg_signature.rb @@ -15,11 +15,27 @@ class GpgSignature < ActiveRecord::Base belongs_to :project belongs_to :gpg_key + belongs_to :gpg_key_subkey validates :commit_sha, presence: true validates :project_id, presence: true validates :gpg_key_primary_keyid, presence: true + def gpg_key=(model) + case model + when GpgKey then super + when GpgKeySubkey then write_attribute(:gpg_key_subkey_id, model.id) + end + end + + def gpg_key + if gpg_key_id + super + elsif gpg_key_subkey_id + gpg_key_subkey + end + end + def gpg_key_primary_keyid super&.upcase end diff --git a/db/migrate/20170927232658_add_gpg_key_subkey_id_to_gpg_signatures.rb b/db/migrate/20170927232658_add_gpg_key_subkey_id_to_gpg_signatures.rb new file mode 100644 index 0000000000000000000000000000000000000000..74b43d732d54f00be007da031543ee5fb7954908 --- /dev/null +++ b/db/migrate/20170927232658_add_gpg_key_subkey_id_to_gpg_signatures.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 AddGpgKeySubkeyIdToGpgSignatures < ActiveRecord::Migration + DOWNTIME = false + + def change + add_reference(:gpg_signatures, :gpg_key_subkey, index: true, foreign_key: { on_delete: :nullify }) + end +end diff --git a/db/schema.rb b/db/schema.rb index 0d02e584d0c7815bbdbc70cce8e521534fb7308c..0beebc16cbb50c246547fa050b1afaac5ac493e6 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -610,11 +610,13 @@ ActiveRecord::Schema.define(version: 20171004121444) do t.text "gpg_key_user_name" t.text "gpg_key_user_email" t.integer "verification_status", limit: 2, default: 0, null: false + t.integer "gpg_key_subkey_id" end add_index "gpg_signatures", ["commit_sha"], name: "index_gpg_signatures_on_commit_sha", unique: true, using: :btree add_index "gpg_signatures", ["gpg_key_id"], name: "index_gpg_signatures_on_gpg_key_id", using: :btree add_index "gpg_signatures", ["gpg_key_primary_keyid"], name: "index_gpg_signatures_on_gpg_key_primary_keyid", using: :btree + add_index "gpg_signatures", ["gpg_key_subkey_id"], name: "index_gpg_signatures_on_gpg_key_subkey_id", using: :btree add_index "gpg_signatures", ["project_id"], name: "index_gpg_signatures_on_project_id", using: :btree create_table "identities", force: :cascade do |t| @@ -1736,6 +1738,7 @@ ActiveRecord::Schema.define(version: 20171004121444) do add_foreign_key "forked_project_links", "projects", column: "forked_to_project_id", name: "fk_434510edb0", on_delete: :cascade add_foreign_key "gpg_key_subkeys", "gpg_keys", on_delete: :cascade add_foreign_key "gpg_keys", "users", on_delete: :cascade + add_foreign_key "gpg_signatures", "gpg_key_subkeys", on_delete: :nullify add_foreign_key "gpg_signatures", "gpg_keys", on_delete: :nullify add_foreign_key "gpg_signatures", "projects", on_delete: :cascade add_foreign_key "issue_assignees", "issues", name: "fk_b7d881734a", on_delete: :cascade diff --git a/lib/gitlab/gpg/commit.rb b/lib/gitlab/gpg/commit.rb index 40274e139189e133df9faff08610497563a1a91e..5cbc836314f8c16447f62e820e97f87240b911a7 100644 --- a/lib/gitlab/gpg/commit.rb +++ b/lib/gitlab/gpg/commit.rb @@ -43,7 +43,7 @@ module Gitlab # key belonging to the keyid. # This way we can add the key to the temporary keychain and extract # the proper signature. - gpg_key = GpgKey.find_with_subkeys(verified_signature.fingerprint) + gpg_key = find_gpg_key(verified_signature.fingerprint) if gpg_key Gitlab::Gpg::CurrentKeyChain.add(gpg_key.key) @@ -74,7 +74,7 @@ module Gitlab commit_sha: @commit.sha, project: @commit.project, gpg_key: gpg_key, - gpg_key_primary_keyid: gpg_key&.primary_keyid || verified_signature.fingerprint, + gpg_key_primary_keyid: gpg_keyid(gpg_key) || verified_signature.fingerprint, gpg_key_user_name: user_infos[:name], gpg_key_user_email: user_infos[:email], verification_status: verification_status @@ -98,6 +98,16 @@ module Gitlab def user_infos(gpg_key) gpg_key&.verified_user_infos&.first || gpg_key&.user_infos&.first || {} end + + def gpg_keyid(gpg_key) + return nil unless gpg_key + + gpg_key.is_a?(GpgKey) ? gpg_key.primary_keyid : gpg_key.keyid + end + + def find_gpg_key(keyid) + GpgKey.find_by(primary_keyid: keyid) || GpgKeySubkey.find_by(keyid: keyid) + end end end end