rosa-build/app/models/key_pair.rb

83 lines
2.8 KiB
Ruby
Raw Normal View History

require 'open3'
2012-07-13 12:18:12 +01:00
class KeyPair < ActiveRecord::Base
belongs_to :repository
belongs_to :user
attr_accessor :fingerprint
2012-07-13 12:18:12 +01:00
attr_accessible :public, :secret, :repository_id
2014-01-21 04:51:49 +00:00
attr_encrypted :secret, key: APP_CONFIG['keys']['key_pair_secret_key']
2012-07-13 12:18:12 +01:00
2014-01-21 04:51:49 +00:00
validates :repository_id, :user_id, presence: true
validates :secret, :public, presence: true, length: { maximum: 10000 }, on: :create
2012-07-13 12:18:12 +01:00
2014-03-11 12:40:44 +00:00
validates :repository_id, uniqueness: { message: I18n.t("activerecord.errors.key_pair.repo_key_exists") }
validate :check_keys
2012-07-30 20:07:49 +01:00
2013-01-16 15:16:42 +00:00
before_create { |record| record.key_id = @fingerprint }
after_create { |record| record.repository.resign }
2012-07-30 20:07:49 +01:00
protected
def check_keys
2013-11-15 19:02:19 +00:00
dir = Dir.mktmpdir 'keys-', APP_CONFIG['tmpfs_path']
2012-12-20 15:00:30 +00:00
begin
2013-01-17 20:51:12 +00:00
%w(pubring secring).each do |kind|
filename = "#{dir}/#{kind}"
open("#{filename}.txt", "w") { |f| f.write self.send(kind == 'pubring' ? :public : :secret) }
system "gpg --homedir #{dir} --dearmor < #{filename}.txt > #{filename}.gpg"
end
2012-12-20 15:00:30 +00:00
public_key = get_info_of_key "#{dir}/pubring.gpg"
secret_key = get_info_of_key "#{dir}/secring.gpg"
if correct_key?(public_key, :public) & correct_key?(secret_key, :secret)
if public_key[:fingerprint] != secret_key[:fingerprint]
errors.add :secret, I18n.t('activerecord.errors.key_pair.wrong_keys')
else
stdin, stdout, stderr = Open3.popen3("echo '\n\n\n\n\nsave' | LC_ALL=en gpg --command-fd 0 --homedir #{dir} --edit-key #{secret_key[:keyid]} passwd")
2012-12-20 15:00:30 +00:00
output = stderr.read
if output =~ /Invalid\spassphrase/
2012-12-20 15:00:30 +00:00
errors.add :secret, I18n.t('activerecord.errors.key_pair.key_has_passphrase')
else
@fingerprint = secret_key[:fingerprint]
end
end
end
2012-12-20 15:00:30 +00:00
ensure
# remove the directory.
FileUtils.remove_entry_secure dir
2012-07-30 20:07:49 +01:00
end
2012-07-13 12:18:12 +01:00
end
2012-12-20 15:00:30 +00:00
def correct_key?(info, field)
if info.empty? || info[:type].blank? || info[:fingerprint].blank? || info[:keyid].blank?
errors.add field, I18n.t('activerecord.errors.key_pair.wrong_key')
2012-12-20 15:00:30 +00:00
return false
else
if info[:type] != field
errors.add field, I18n.t("activerecord.errors.key_pair.wrong_#{field}_key")
2012-12-20 15:00:30 +00:00
return false
end
end
2012-12-20 15:00:30 +00:00
return true
end
def get_info_of_key(file_path)
results = {}
str = %x[ gpg --with-fingerprint #{file_path} | sed -n 1,2p]
info = str.strip.split("\n")
if info.size == 2
results[:fingerprint] = info[1].gsub(/.*\=/, '').strip.gsub(/\s/, ':')
results[:type] = info[0] =~ /^pub\s/ ? :public : nil
results[:type] ||= info[0] =~ /^sec\s/ ? :secret : nil
if keyid = info[0].match(/\/[\w]+\s/)
results[:keyid] = keyid[0].strip[1..-1]
end
end
2012-12-20 15:00:30 +00:00
return results
2012-07-30 20:07:49 +01:00
end
2012-07-13 12:18:12 +01:00
end