2014-01-17 09:11:56 +01:00
require 'open-uri'
2014-02-20 10:34:22 +01:00
require 'net/ftp'
2014-01-17 09:11:56 +01:00
require 'tempfile'
2014-02-20 10:34:22 +01:00
if RUBY_VERSION == '1.8.7'
# Mothers cry, puppies die and Ruby 1.8.7's open-uri needs to be
# monkeypatched to support passing in :ftp_passive_mode.
2014-03-16 12:44:05 +01:00
require File . expand_path ( File . join ( File . dirname ( __FILE__ ) , '..' , '..' , '..' ,
'puppet_x' , 'apt_key' , 'patch_openuri.rb' ) )
2014-02-20 10:34:22 +01:00
OpenURI :: Options . merge! ( { :ftp_active_mode = > false , } )
end
2014-01-17 09:11:56 +01:00
Puppet :: Type . type ( :apt_key ) . provide ( :apt_key ) do
confine :osfamily = > :debian
defaultfor :osfamily = > :debian
commands :apt_key = > 'apt-key'
2015-03-06 17:14:40 +01:00
commands :gpg = > '/usr/bin/gpg'
2014-01-17 09:11:56 +01:00
def self . instances
2015-03-15 23:33:22 +01:00
cli_args = [ 'adv' , '--list-keys' , '--with-colons' , '--fingerprint' , '--fixed-list-mode' ]
2014-09-04 04:00:57 +02:00
2014-06-26 14:26:02 +02:00
if RUBY_VERSION > '1.8.7'
2014-09-04 04:00:57 +02:00
key_output = apt_key ( cli_args ) . encode ( 'UTF-8' , 'binary' , :invalid = > :replace , :undef = > :replace , :replace = > '' )
2014-06-26 14:26:02 +02:00
else
2014-09-04 04:00:57 +02:00
key_output = apt_key ( cli_args )
2014-06-26 14:26:02 +02:00
end
2014-09-04 04:00:57 +02:00
pub_line , fpr_line = nil
2014-07-09 13:06:40 +02:00
key_array = key_output . split ( " \n " ) . collect do | line |
2014-09-04 04:00:57 +02:00
if line . start_with? ( 'pub' )
pub_line = line
elsif line . start_with? ( 'fpr' )
fpr_line = line
end
next unless ( pub_line and fpr_line )
line_hash = key_line_hash ( pub_line , fpr_line )
# reset everything
pub_line , fpr_line = nil
2014-01-17 09:11:56 +01:00
expired = false
if line_hash [ :key_expiry ]
2015-03-15 23:33:22 +01:00
expired = Time . now > = line_hash [ :key_expiry ]
2014-01-17 09:11:56 +01:00
end
new (
2014-09-04 04:00:57 +02:00
:name = > line_hash [ :key_fingerprint ] ,
2015-01-14 00:54:10 +01:00
:id = > line_hash [ :key_long ] ,
2014-09-04 04:00:57 +02:00
:fingerprint = > line_hash [ :key_fingerprint ] ,
:short = > line_hash [ :key_short ] ,
:long = > line_hash [ :key_long ] ,
:ensure = > :present ,
:expired = > expired ,
2015-03-15 23:33:22 +01:00
:expiry = > line_hash [ :key_expiry ] . nil? ? nil : line_hash [ :key_expiry ] . strftime ( " %Y-%m-%d " ) ,
2014-09-04 04:00:57 +02:00
:size = > line_hash [ :key_size ] ,
:type = > line_hash [ :key_type ] ,
2015-03-15 23:33:22 +01:00
:created = > line_hash [ :key_created ] . strftime ( " %Y-%m-%d " )
2014-01-17 09:11:56 +01:00
)
end
key_array . compact!
end
def self . prefetch ( resources )
apt_keys = instances
resources . keys . each do | name |
2014-09-04 04:00:57 +02:00
if name . length == 40
if provider = apt_keys . find { | key | key . fingerprint == name }
resources [ name ] . provider = provider
end
elsif name . length == 16
if provider = apt_keys . find { | key | key . long == name }
resources [ name ] . provider = provider
end
elsif name . length == 8
if provider = apt_keys . find { | key | key . short == name }
resources [ name ] . provider = provider
end
2014-01-17 09:11:56 +01:00
end
end
end
2014-09-04 04:00:57 +02:00
def self . key_line_hash ( pub_line , fpr_line )
pub_split = pub_line . split ( ':' )
fpr_split = fpr_line . split ( ':' )
2014-01-17 09:11:56 +01:00
2014-09-04 04:00:57 +02:00
fingerprint = fpr_split . last
2014-01-17 09:11:56 +01:00
return_hash = {
2014-09-04 04:00:57 +02:00
:key_fingerprint = > fingerprint ,
:key_long = > fingerprint [ - 16 .. - 1 ] , # last 16 characters of fingerprint
:key_short = > fingerprint [ - 8 .. - 1 ] , # last 8 characters of fingerprint
:key_size = > pub_split [ 2 ] ,
:key_type = > nil ,
2015-03-15 23:33:22 +01:00
:key_created = > Time . at ( pub_split [ 5 ] . to_i ) ,
:key_expiry = > pub_split [ 6 ] . empty? ? nil : Time . at ( pub_split [ 6 ] . to_i ) ,
2014-01-17 09:11:56 +01:00
}
2014-09-04 04:00:57 +02:00
# set key type based on types defined in /usr/share/doc/gnupg/DETAILS.gz
case pub_split [ 3 ]
when " 1 "
return_hash [ :key_type ] = :rsa
when " 17 "
return_hash [ :key_type ] = :dsa
when " 18 "
return_hash [ :key_type ] = :ecc
when " 19 "
return_hash [ :key_type ] = :ecdsa
end
2014-01-17 09:11:56 +01:00
2014-09-04 04:00:57 +02:00
return return_hash
2014-01-17 09:11:56 +01:00
end
def source_to_file ( value )
2014-11-14 05:25:46 +01:00
parsedValue = URI :: parse ( value )
if parsedValue . scheme . nil?
2014-01-17 09:11:56 +01:00
fail ( " The file #{ value } does not exist " ) unless File . exists? ( value )
value
else
begin
2014-11-14 05:25:46 +01:00
key = parsedValue . read
2014-02-20 10:34:22 +01:00
rescue OpenURI :: HTTPError , Net :: FTPPermError = > e
2014-01-17 09:11:56 +01:00
fail ( " #{ e . message } for #{ resource [ :source ] } " )
rescue SocketError
fail ( " could not resolve #{ resource [ :source ] } " )
else
tempfile ( key )
end
end
end
def tempfile ( content )
file = Tempfile . new ( 'apt_key' )
file . write content
file . close
2015-03-06 17:14:40 +01:00
#confirm that the fingerprint from the file, matches the long key that is in the manifest
if name . size == 40
if File . executable? command ( :gpg )
extracted_key = execute ( [ " #{ command ( :gpg ) } --with-fingerprint --with-colons #{ file . path } | awk -F: '/^fpr:/ { print $10 }' " ] , :failonfail = > false )
extracted_key = extracted_key . chomp
if extracted_key != name
2015-03-15 23:47:15 +01:00
fail ( " The id in your manifest #{ resource [ :name ] } and the fingerprint from content/source do not match. Please check there is not an error in the id or check the content/source is legitimate. " )
2015-03-06 17:14:40 +01:00
end
else
2015-03-15 23:47:15 +01:00
warning ( '/usr/bin/gpg cannot be found for verification of the id.' )
end
2015-03-06 17:14:40 +01:00
end
2014-01-17 09:11:56 +01:00
file . path
end
def exists?
@property_hash [ :ensure ] == :present
end
def create
command = [ ]
if resource [ :source ] . nil? and resource [ :content ] . nil?
# Breaking up the command like this is needed because it blows up
# if --recv-keys isn't the last argument.
command . push ( 'adv' , '--keyserver' , resource [ :server ] )
2015-03-18 20:51:37 +01:00
unless resource [ :options ] . nil?
command . push ( '--keyserver-options' , resource [ :options ] )
2014-01-17 09:11:56 +01:00
end
command . push ( '--recv-keys' , resource [ :id ] )
elsif resource [ :content ]
command . push ( 'add' , tempfile ( resource [ :content ] ) )
elsif resource [ :source ]
command . push ( 'add' , source_to_file ( resource [ :source ] ) )
# In case we really screwed up, better safe than sorry.
else
fail ( " an unexpected condition occurred while trying to add the key: #{ resource [ :id ] } " )
end
apt_key ( command )
@property_hash [ :ensure ] = :present
end
def destroy
2015-01-14 00:54:10 +01:00
begin
2015-01-14 08:43:13 +01:00
apt_key ( 'del' , resource . provider . short )
r = execute ( [ " #{ command ( :apt_key ) } list | grep '/ #{ resource . provider . short } \s ' " ] , :failonfail = > false )
2015-01-14 00:54:10 +01:00
end while r . exitstatus == 0
2014-01-17 09:11:56 +01:00
@property_hash . clear
end
def read_only ( value )
fail ( 'This is a read-only property.' )
end
mk_resource_methods
# Needed until PUP-1470 is fixed and we can drop support for Puppet versions
# before that.
def expired
@property_hash [ :expired ]
end
# Alias the setters of read-only properties
# to the read_only function.
alias :created = :read_only
alias :expired = :read_only
alias :expiry = :read_only
alias :size = :read_only
alias :type = :read_only
end