rosa-build/app/models/key_pair.rb

113 lines
3.7 KiB
Ruby
Raw Normal View History

2012-12-20 15:00:30 +00:00
# -*- encoding : utf-8 -*-
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
attr_encrypted :secret, :key => APP_CONFIG['secret_key']
2012-07-13 12:18:12 +01:00
2012-12-20 17:36:32 +00:00
validates :repository_id, :user_id, :presence => true
validates :secret, :presence => true, :length => { :maximum => 10000 }, :on => :create
validates :public, :presence => true, :length => { :maximum => 10000 }, :on => :create
2012-07-13 12:18:12 +01: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
before_create :set_key_id
2012-12-24 10:20:09 +00:00
after_create :resign_rpms,
2012-12-24 10:53:20 +00:00
:unless => Proc.new { |key_pair| key_pair.repository.platform.personal? }
2012-07-30 20:07:49 +01:00
protected
def set_key_id
self.key_id = @fingerprint
2012-12-21 18:59:07 +00:00
end
def resign_rpms
platform = repository.platform
type = platform.distrib_type
Resque.push(
"publish_build_list_container_#{type}_worker",
'class' => "AbfWorker::PublishBuildListContainer#{type.capitalize}Worker",
'args' => [{
:id => id,
:arch => 'x86_64',
:distrib_type => type,
:platform => {
:platform_path => "#{platform.path}/repository",
:released => platform.released
},
:repository => {
:name => repository.name,
:id => repository.id
},
:type => :resign,
:save_results => false,
:time_living => 2400 # 40 min
}]
)
end
def check_keys
2012-12-20 15:00:30 +00:00
dir = Dir.mktmpdir
begin
open("#{dir}/pubring.txt", "w") { |f| f.write self.public }
system "gpg --homedir #{dir} --dearmor < #{dir}/pubring.txt > #{dir}/pubring.gpg"
open("#{dir}/secring.txt", "w") { |f| f.write self.secret }
system "gpg --homedir #{dir} --dearmor < #{dir}/secring.txt > #{dir}/secring.gpg"
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.contains_#{field}_key")
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