Class: PassSigner

Inherits:
Object
  • Object
show all
Defined in:
lib/pass_signer.rb,
lib/pass_signer/version.rb

Defined Under Namespace

Classes: Error

Constant Summary collapse

VERSION =
"1.0.0"

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(pass_url, certificate_url, certificate_password, wwdr_intermediate_certificate_path, output_url, compress_into_zip_file = true) ⇒ PassSigner



16
17
18
19
20
21
22
23
# File 'lib/pass_signer.rb', line 16

def initialize(pass_url, certificate_url, certificate_password, wwdr_intermediate_certificate_path, output_url, compress_into_zip_file = true)
  self.pass_url                           = pass_url
  self.certificate_url                    = certificate_url
  self.certificate_password               = certificate_password
  self.wwdr_intermediate_certificate_path = wwdr_intermediate_certificate_path
  self.output_url                         = output_url
  self.compress_into_zip_file             = compress_into_zip_file
end

Instance Attribute Details

#certificate_passwordObject

Returns the value of attribute certificate_password.



14
15
16
# File 'lib/pass_signer.rb', line 14

def certificate_password
  @certificate_password
end

#certificate_urlObject

Returns the value of attribute certificate_url.



14
15
16
# File 'lib/pass_signer.rb', line 14

def certificate_url
  @certificate_url
end

#compress_into_zip_fileObject

Returns the value of attribute compress_into_zip_file.



14
15
16
# File 'lib/pass_signer.rb', line 14

def compress_into_zip_file
  @compress_into_zip_file
end

#manifest_urlObject

Returns the value of attribute manifest_url.



14
15
16
# File 'lib/pass_signer.rb', line 14

def manifest_url
  @manifest_url
end

#output_urlObject

Returns the value of attribute output_url.



14
15
16
# File 'lib/pass_signer.rb', line 14

def output_url
  @output_url
end

#pass_urlObject

Returns the value of attribute pass_url.



14
15
16
# File 'lib/pass_signer.rb', line 14

def pass_url
  @pass_url
end

#signature_urlObject

Returns the value of attribute signature_url.



14
15
16
# File 'lib/pass_signer.rb', line 14

def signature_url
  @signature_url
end

#temporary_directoryObject

Returns the value of attribute temporary_directory.



14
15
16
# File 'lib/pass_signer.rb', line 14

def temporary_directory
  @temporary_directory
end

#temporary_pathObject

Returns the value of attribute temporary_path.



14
15
16
# File 'lib/pass_signer.rb', line 14

def temporary_path
  @temporary_path
end

#wwdr_intermediate_certificate_pathObject

Returns the value of attribute wwdr_intermediate_certificate_path.



14
15
16
# File 'lib/pass_signer.rb', line 14

def wwdr_intermediate_certificate_path
  @wwdr_intermediate_certificate_path
end

Instance Method Details

#clean_ds_store_filesObject

Removes .DS_Store files if they exist



100
101
102
103
104
105
# File 'lib/pass_signer.rb', line 100

def clean_ds_store_files
  puts 'Cleaning .DS_Store files'
  Dir.glob(temporary_path + '**/.DS_Store').each do |file|
    File.delete(file)
  end
end

#compress_pass_fileObject



142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/pass_signer.rb', line 142

def compress_pass_file
  puts 'Compressing the pass'
  zipped_file = File.open(output_url, 'w')

  Zip::OutputStream.open(zipped_file.path) do |z|
    Dir.glob(temporary_path + '/**').each do |file|
      z.put_next_entry(File.basename(file))
      z.print IO.read(file)
    end
  end
  zipped_file
end

#copy_pass_to_temporary_locationObject

Copies the pass contents to the temporary location



94
95
96
97
# File 'lib/pass_signer.rb', line 94

def copy_pass_to_temporary_location
  puts 'Copying pass to temp directory.'
  FileUtils.cp_r(pass_url, temporary_directory)
end

#create_temporary_directoryObject

Creates a temporary place to work with the pass files without polluting the original



81
82
83
84
85
86
87
88
89
90
91
# File 'lib/pass_signer.rb', line 81

def create_temporary_directory
  self.temporary_directory = Dir.mktmpdir
  puts "Creating temp dir at #{temporary_directory}"
  self.temporary_path = temporary_directory + '/' + pass_url.split('/').last

  # Check if the directory exists
  if File.directory?(temporary_path)
    # Need to clean up the directory
    FileUtils.rm_rf(temporary_path)
  end
end

#delete_temp_dirObject



155
156
157
# File 'lib/pass_signer.rb', line 155

def delete_temp_dir
  FileUtils.rm_rf(temporary_path)
end

#force_clean_raw_passObject



69
70
71
72
73
74
75
76
77
78
# File 'lib/pass_signer.rb', line 69

def force_clean_raw_pass
  puts 'Force cleaning the raw pass directory.'
  if File.exist?(File.join(pass_url, '/manifest.json'))
    File.delete(File.join(pass_url, '/manifest.json'))
  end

  if File.exist?(File.join(pass_url, '/signature'))
    File.delete(File.join(pass_url, '/signature'))
  end
end

#generate_json_manifestObject

Creates a json manifest where each files contents has a SHA1 hash



108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/pass_signer.rb', line 108

def generate_json_manifest
  puts 'Generating JSON manifest'
  manifest = {}
  # Gather all the files and generate a sha1 hash
  Dir.glob(temporary_path + '/**').each do |file|
    manifest[File.basename(file)] = Digest::SHA1.hexdigest(File.read(file))
  end

  # Write the hash dictionary out to a manifest file
  self.manifest_url = temporary_path + '/manifest.json'
  File.open(manifest_url, 'w') do |f|
    f.write(manifest.to_json)
  end
end

#sign_manifestObject



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/pass_signer.rb', line 123

def sign_manifest
  puts 'Signing the manifest'
  # Import the certificates
  p12_certificate = OpenSSL::PKCS12.new(File.read(certificate_url), certificate_password)
  wwdr_certificate = OpenSSL::X509::Certificate.new(File.read(wwdr_intermediate_certificate_path))

  # Sign the data
  flag = OpenSSL::PKCS7::BINARY | OpenSSL::PKCS7::DETACHED
  signed = OpenSSL::PKCS7.sign(p12_certificate.certificate, p12_certificate.key, File.read(manifest_url), [wwdr_certificate], flag)

  # Create an output path for the signed data
  self.signature_url = temporary_path + '/signature'

  # Write out the data
  File.open(signature_url, 'w') do |f|
    f.syswrite signed.to_der
  end
end

#sign_pass!(force_clean_raw_pass = false) ⇒ Object



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/pass_signer.rb', line 25

def sign_pass!(force_clean_raw_pass = false)
  # Validate that requested contents are not a signed and expanded pass archive.
  validate_directory_as_unsigned_raw_pass(force_clean_raw_pass)

  # Get a temporary place to stash the pass contents
  create_temporary_directory

  # Make a copy of the pass contents to the temporary folder
  copy_pass_to_temporary_location

  # Clean out the unneeded .DS_Store files
  clean_ds_store_files

  # Build the json manifest
  generate_json_manifest

  # Sign the manifest
  sign_manifest

  # Package pass
  compress_pass_file

  # Clean up the temp directory
  # self.delete_temp_dir
end

#validate_directory_as_unsigned_raw_pass(force_clean = false) ⇒ Object

Ensures that the raw pass directory does not contain signatures



54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/pass_signer.rb', line 54

def validate_directory_as_unsigned_raw_pass(force_clean = false)
  force_clean_raw_pass if force_clean

  has_manifiest = File.exist?(File.join(pass_url, '/manifest.json'))
  puts "Raw pass has manifest? #{has_manifiest}"

  has_signiture = File.exist?(File.join(pass_url, '/signature'))
  puts "Raw pass has signature? #{has_signiture}"

  if has_signiture || has_manifiest
    raise "#{pass_url} contains pass signing artificats that need to be removed before signing."

  end
end