summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexis Reigel <mail@koffeinfrei.org>2017-02-22 12:49:17 +0100
committerAlexis Reigel <mail@koffeinfrei.org>2017-07-27 15:40:40 +0200
commitfbf1fd1a204a24aef2b80473ec64a520ed2a2dfc (patch)
treeeb1656bf0a16ab379b1ac1a5cd8cf86bf771b0c1
parent28bb5e3d53a585b1fb958d1d91622da0a038bea8 (diff)
downloadgitlab-ce-fbf1fd1a204a24aef2b80473ec64a520ed2a2dfc.tar.gz
add gpg key model
-rw-r--r--app/models/gpg_key.rb35
-rw-r--r--db/migrate/20170222111732_create_gpg_keys.rb13
-rw-r--r--db/schema.rb11
-rw-r--r--spec/models/gpg_key_spec.rb41
4 files changed, 100 insertions, 0 deletions
diff --git a/app/models/gpg_key.rb b/app/models/gpg_key.rb
new file mode 100644
index 00000000000..16de0b542d7
--- /dev/null
+++ b/app/models/gpg_key.rb
@@ -0,0 +1,35 @@
+class GpgKey < ActiveRecord::Base
+ KEY_PREFIX = '-----BEGIN PGP PUBLIC KEY BLOCK-----'.freeze
+
+ belongs_to :user
+
+ validates :fingerprint,
+ presence: true,
+ uniqueness: true
+
+ validates :key,
+ presence: true,
+ uniqueness: true,
+ format: {
+ with: /\A#{KEY_PREFIX}((?!#{KEY_PREFIX}).)+\Z/m
+ }
+
+ before_validation :extract_fingerprint
+
+ def key=(value)
+ value.strip! unless value.blank?
+ write_attribute(:key, value)
+ end
+
+ private
+
+ def extract_fingerprint
+ import = GPGME::Key.import(key)
+
+ return if import.considered == 0
+
+ # we can assume that the result only contains one item as the validation
+ # only allows one key
+ self.fingerprint = import.imports.first.fingerprint
+ end
+end
diff --git a/db/migrate/20170222111732_create_gpg_keys.rb b/db/migrate/20170222111732_create_gpg_keys.rb
new file mode 100644
index 00000000000..1b8b7a91fe1
--- /dev/null
+++ b/db/migrate/20170222111732_create_gpg_keys.rb
@@ -0,0 +1,13 @@
+class CreateGpgKeys < ActiveRecord::Migration
+ DOWNTIME = false
+
+ def change
+ create_table :gpg_keys do |t|
+ t.string :fingerprint
+ t.text :key
+ t.references :user, index: true, foreign_key: true
+
+ t.timestamps_with_timezone null: false
+ end
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 1ec25c7d46f..54f98559243 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -540,6 +540,16 @@ ActiveRecord::Schema.define(version: 20170725145659) do
add_index "forked_project_links", ["forked_to_project_id"], name: "index_forked_project_links_on_forked_to_project_id", unique: true, using: :btree
+ create_table "gpg_keys", force: :cascade do |t|
+ t.string "fingerprint"
+ t.text "key"
+ t.integer "user_id"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ end
+
+ add_index "gpg_keys", ["user_id"], name: "index_gpg_keys_on_user_id", using: :btree
+
create_table "identities", force: :cascade do |t|
t.string "extern_uid"
t.string "provider"
@@ -1602,6 +1612,7 @@ ActiveRecord::Schema.define(version: 20170725145659) do
add_foreign_key "environments", "projects", name: "fk_d1c8c1da6a", on_delete: :cascade
add_foreign_key "events", "projects", name: "fk_0434b48643", on_delete: :cascade
add_foreign_key "forked_project_links", "projects", column: "forked_to_project_id", name: "fk_434510edb0", on_delete: :cascade
+ add_foreign_key "gpg_keys", "users"
add_foreign_key "issue_assignees", "issues", name: "fk_b7d881734a", on_delete: :cascade
add_foreign_key "issue_assignees", "users", name: "fk_5e0c8d9154", on_delete: :cascade
add_foreign_key "issue_metrics", "issues", on_delete: :cascade
diff --git a/spec/models/gpg_key_spec.rb b/spec/models/gpg_key_spec.rb
new file mode 100644
index 00000000000..02623c52fa6
--- /dev/null
+++ b/spec/models/gpg_key_spec.rb
@@ -0,0 +1,41 @@
+require 'rails_helper'
+
+describe GpgKey do
+ describe "associations" do
+ it { is_expected.to belong_to(:user) }
+ end
+
+ describe "validation" do
+ it { is_expected.to validate_presence_of(:fingerprint) }
+
+ it { is_expected.to validate_presence_of(:key) }
+ it { is_expected.to validate_uniqueness_of(:key) }
+ it { is_expected.to allow_value("-----BEGIN PGP PUBLIC KEY BLOCK-----\nkey").for(:key) }
+ it { is_expected.not_to allow_value("-----BEGIN PGP PUBLIC KEY BLOCK-----\nkey\n-----BEGIN PGP PUBLIC KEY BLOCK-----").for(:key) }
+ it { is_expected.not_to allow_value('BEGIN PGP').for(:key) }
+ end
+
+ context 'callbacks' do
+ describe 'extract_fingerprint' do
+ it 'extracts the fingerprint from the gpg key', :gpg do
+ gpg_key = described_class.new(key: GpgHelpers.public_key)
+ gpg_key.valid?
+ expect(gpg_key.fingerprint).to eq '4F4840A503964251CF7D7F5DC728AF10972E97C0'
+ end
+ end
+ end
+
+ describe '#key=' do
+ it 'strips white spaces' do
+ key = <<~KEY.strip
+ -----BEGIN PGP PUBLIC KEY BLOCK-----
+ Version: GnuPG v1
+
+ mQENBFMOSOgBCADFCYxmnXFbrDhfvlf03Q/bQuT+nZu46BFGbo7XkUjDowFXJQhP
+ -----END PGP PUBLIC KEY BLOCK-----
+ KEY
+
+ expect(described_class.new(key: " #{key} ").key).to eq(key)
+ end
+ end
+end