sign_pass 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/bin/rsign_pass +42 -0
- data/lib/sign_pass.rb +229 -0
- metadata +58 -0
data/bin/rsign_pass
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'sign_pass'
|
4
|
+
require 'optparse'
|
5
|
+
|
6
|
+
options = {}
|
7
|
+
optparse = OptionParser.new do |opts|
|
8
|
+
# Set a banner, displayed at the top of the screen
|
9
|
+
opts.banner = "Usage: rsign_pass -p /path/to/pass/directory -c /path/to/ssl/certificate -w certififcate-password -o /path/for/output/file"
|
10
|
+
|
11
|
+
options[:pass_path] = ""
|
12
|
+
opts.on('-p', '--pass FILE', String, 'Path to the pass directory') do |file|
|
13
|
+
puts file
|
14
|
+
options[:pass_path] = file
|
15
|
+
end
|
16
|
+
|
17
|
+
opts.on('-c', '--certificate FILE', String, 'Path to the certificate') do |file|
|
18
|
+
options[:certificate] = file
|
19
|
+
end
|
20
|
+
|
21
|
+
opts.on('-w', '--password PASSWORD', String, 'Certificate password') do |password|
|
22
|
+
options[:certificate_password] = password
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
opts.on('-o', '--output FILE', String, 'File location for the output') do |file|
|
27
|
+
options[:output] = file
|
28
|
+
end
|
29
|
+
|
30
|
+
opts.on('-f', '--force', 'Force pass signing by removing manifest and signiture if needed') do |b|
|
31
|
+
options[:force_pass_signing] = b
|
32
|
+
end
|
33
|
+
|
34
|
+
opts.on('-h', '--help', 'Display this screen') do
|
35
|
+
puts opts
|
36
|
+
exit
|
37
|
+
end
|
38
|
+
end
|
39
|
+
optparse.parse!
|
40
|
+
pass = SignPass.new(options[:pass_path], options[:certificate], options[:certificate_password], options[:output])
|
41
|
+
puts options[:force_pass_signing]
|
42
|
+
pass.sign_pass!(options[:force_pass_signing])
|
data/lib/sign_pass.rb
ADDED
@@ -0,0 +1,229 @@
|
|
1
|
+
#
|
2
|
+
# File: sign_pass.rb
|
3
|
+
#
|
4
|
+
# Abstract: Pass Server reference implementation
|
5
|
+
#
|
6
|
+
# Version: 1.0
|
7
|
+
#
|
8
|
+
# Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. ("Apple")
|
9
|
+
# in consideration of your agreement to the following terms, and your use,
|
10
|
+
# installation, modification or redistribution of this Apple software
|
11
|
+
# constitutes acceptance of these terms. If you do not agree with these
|
12
|
+
# terms, please do not use, install, modify or redistribute this Apple
|
13
|
+
# software.
|
14
|
+
#
|
15
|
+
# In consideration of your agreement to abide by the following terms, and
|
16
|
+
# subject to these terms, Apple grants you a personal, non - exclusive
|
17
|
+
# license, under Apple's copyrights in this original Apple software ( the
|
18
|
+
# "Apple Software" ), to use, reproduce, modify and redistribute the Apple
|
19
|
+
# Software, with or without modifications, in source and / or binary forms;
|
20
|
+
# provided that if you redistribute the Apple Software in its entirety and
|
21
|
+
# without modifications, you must retain this notice and the following text
|
22
|
+
# and disclaimers in all such redistributions of the Apple Software. Neither
|
23
|
+
# the name, trademarks, service marks or logos of Apple Inc. may be used to
|
24
|
+
# endorse or promote products derived from the Apple Software without specific
|
25
|
+
# prior written permission from Apple. Except as expressly stated in this
|
26
|
+
# notice, no other rights or licenses, express or implied, are granted by
|
27
|
+
# Apple herein, including but not limited to any patent rights that may be
|
28
|
+
# infringed by your derivative works or by other works in which the Apple
|
29
|
+
# Software may be incorporated.
|
30
|
+
#
|
31
|
+
# The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
|
32
|
+
# WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
|
33
|
+
# WARRANTIES OF NON - INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
|
34
|
+
# PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION
|
35
|
+
# ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
36
|
+
#
|
37
|
+
# IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
|
38
|
+
# CONSEQUENTIAL DAMAGES ( INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
39
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
40
|
+
# INTERRUPTION ) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION
|
41
|
+
# AND / OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER
|
42
|
+
# UNDER THEORY OF CONTRACT, TORT ( INCLUDING NEGLIGENCE ), STRICT LIABILITY OR
|
43
|
+
# OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
44
|
+
#
|
45
|
+
# Copyright ( C ) 2012 Apple Inc. All Rights Reserved.
|
46
|
+
#
|
47
|
+
|
48
|
+
require 'rubygems'
|
49
|
+
require 'fileutils'
|
50
|
+
require 'tmpdir'
|
51
|
+
require 'digest/sha1'
|
52
|
+
require 'json'
|
53
|
+
require 'openssl'
|
54
|
+
require 'zip/zip'
|
55
|
+
require 'zip/zipfilesystem'
|
56
|
+
|
57
|
+
|
58
|
+
class SignPass
|
59
|
+
attr_accessor :pass_url, :certificate_url, :certificate_password, :output_url, :compress_into_zip_file, :temporary_directory, :temporary_path, :manifest_url, :signature_url, :wwdr_intermediate_certificate_path
|
60
|
+
|
61
|
+
|
62
|
+
def initialize(pass_url, certificate_url, certificate_password, wwdr_intermediate_certificate_path, output_url, compress_into_zip_file=true)
|
63
|
+
self.pass_url = pass_url
|
64
|
+
self.certificate_url = certificate_url
|
65
|
+
self.certificate_password = certificate_password
|
66
|
+
self.wwdr_intermediate_certificate_path = wwdr_intermediate_certificate_path
|
67
|
+
self.output_url = output_url
|
68
|
+
self.compress_into_zip_file = compress_into_zip_file
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
def sign_pass!(force_clean_raw_pass=false)
|
73
|
+
# Validate that requested contents are not a signed and expanded pass archive.
|
74
|
+
self.validate_directory_as_unsigned_raw_pass(force_clean_raw_pass)
|
75
|
+
|
76
|
+
# Get a temporary place to stash the pass contents
|
77
|
+
self.create_temporary_directory
|
78
|
+
|
79
|
+
# Make a copy of the pass contents to the temporary folder
|
80
|
+
self.copy_pass_to_temporary_location
|
81
|
+
|
82
|
+
# Clean out the unneeded .DS_Store files
|
83
|
+
self.clean_ds_store_files
|
84
|
+
|
85
|
+
# Build the json manifest
|
86
|
+
self.generate_json_manifest
|
87
|
+
|
88
|
+
# Sign the manifest
|
89
|
+
self.sign_manifest
|
90
|
+
|
91
|
+
# Package pass
|
92
|
+
self.compress_pass_file
|
93
|
+
|
94
|
+
# Clean up the temp directory
|
95
|
+
#self.delete_temp_dir
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
# private
|
100
|
+
|
101
|
+
# Ensures that the raw pass directory does not contain signatures
|
102
|
+
def validate_directory_as_unsigned_raw_pass(force_clean=false)
|
103
|
+
if force_clean
|
104
|
+
force_clean_raw_pass
|
105
|
+
end
|
106
|
+
|
107
|
+
has_manifiest = File.exists?(File.join(self.pass_url, "/manifest.json"))
|
108
|
+
puts "Raw pass has manifest? #{has_manifiest}"
|
109
|
+
|
110
|
+
has_signiture = File.exists?(File.join(self.pass_url, "/signature"))
|
111
|
+
puts "Raw pass has signature? #{has_signiture}"
|
112
|
+
|
113
|
+
if has_signiture || has_manifiest
|
114
|
+
raise RuntimeError, "#{self.pass_url} contains pass signing artificats that need to be removed before signing."
|
115
|
+
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def force_clean_raw_pass
|
120
|
+
puts "Force cleaning the raw pass directory."
|
121
|
+
if File.exists?(File.join(self.pass_url, "/manifest.json"))
|
122
|
+
File.delete(File.join(self.pass_url, "/manifest.json"))
|
123
|
+
end
|
124
|
+
|
125
|
+
if File.exists?(File.join(self.pass_url, "/signature"))
|
126
|
+
File.delete(File.join(self.pass_url, "/signature"))
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
|
131
|
+
|
132
|
+
# Creates a temporary place to work with the pass files without polluting the original
|
133
|
+
def create_temporary_directory
|
134
|
+
self.temporary_directory = Dir.mktmpdir
|
135
|
+
puts "Creating temp dir at #{self.temporary_directory}"
|
136
|
+
self.temporary_path = self.temporary_directory + "/" + self.pass_url.split("/").last
|
137
|
+
|
138
|
+
# Check if the directory exists
|
139
|
+
if File.directory?(self.temporary_path)
|
140
|
+
# Need to clean up the directory
|
141
|
+
FileUtils.rm_rf(self.temporary_path)
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
# Copies the pass contents to the temporary location
|
147
|
+
def copy_pass_to_temporary_location
|
148
|
+
puts "Copying pass to temp directory."
|
149
|
+
FileUtils.cp_r(self.pass_url, self.temporary_directory)
|
150
|
+
end
|
151
|
+
|
152
|
+
|
153
|
+
# Removes .DS_Store files if they exist
|
154
|
+
def clean_ds_store_files
|
155
|
+
puts "Cleaning .DS_Store files"
|
156
|
+
Dir.glob(self.temporary_path + "**/.DS_Store").each do |file|
|
157
|
+
File.delete(file)
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
161
|
+
|
162
|
+
|
163
|
+
# Creates a json manifest where each files contents has a SHA1 hash
|
164
|
+
def generate_json_manifest
|
165
|
+
puts "Generating JSON manifest"
|
166
|
+
manifest = {}
|
167
|
+
# Gather all the files and generate a sha1 hash
|
168
|
+
Dir.glob(self.temporary_path + "/**").each do |file|
|
169
|
+
manifest[File.basename(file)] = Digest::SHA1.hexdigest(File.read(file))
|
170
|
+
end
|
171
|
+
|
172
|
+
# Write the hash dictionary out to a manifest file
|
173
|
+
self.manifest_url = self.temporary_path + "/manifest.json"
|
174
|
+
File.open(self.manifest_url, "w") do |f|
|
175
|
+
f.write(manifest.to_json)
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
179
|
+
|
180
|
+
def sign_manifest
|
181
|
+
puts "Signing the manifest"
|
182
|
+
# Import the certificate
|
183
|
+
p12_certificate = OpenSSL::PKCS12::new(File.read(self.certificate_url), self.certificate_password)
|
184
|
+
wwdr_certificate = OpenSSL::X509::Certificate.new(File.read(self.wwdr_intermediate_certificate_path))
|
185
|
+
|
186
|
+
# Sign the data
|
187
|
+
flag = OpenSSL::PKCS7::BINARY|OpenSSL::PKCS7::DETACHED
|
188
|
+
signed = OpenSSL::PKCS7::sign(p12_certificate.certificate, p12_certificate.key, File.read(self.manifest_url), [wwdr_certificate], flag)
|
189
|
+
|
190
|
+
# Create an output path for the signed data
|
191
|
+
self.signature_url = self.temporary_path + "/signature"
|
192
|
+
|
193
|
+
# Write out the data
|
194
|
+
File.open(self.signature_url, "w") do |f|
|
195
|
+
f.syswrite signed.to_der
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def compress_pass_file
|
200
|
+
puts "Compressing the pass"
|
201
|
+
zipped_file = File.open(self.output_url, "w")
|
202
|
+
|
203
|
+
Zip::ZipOutputStream.open(zipped_file.path) do |z|
|
204
|
+
Dir.glob(self.temporary_path + "/**").each do |file|
|
205
|
+
z.put_next_entry(File.basename(file))
|
206
|
+
z.print IO.read(file)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
zipped_file
|
210
|
+
end
|
211
|
+
|
212
|
+
def delete_temp_dir
|
213
|
+
FileUtils.rm_rf(self.temporary_path)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
|
218
|
+
|
219
|
+
|
220
|
+
|
221
|
+
|
222
|
+
|
223
|
+
|
224
|
+
|
225
|
+
|
226
|
+
|
227
|
+
|
228
|
+
|
229
|
+
|
metadata
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sign_pass
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Apple
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-08-09 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rubyzip
|
16
|
+
requirement: &70275300012040 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.9.5
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70275300012040
|
25
|
+
description: A ruby implementation of the pass signing and packaging utility.
|
26
|
+
email: developer@apple.com
|
27
|
+
executables:
|
28
|
+
- rsign_pass
|
29
|
+
extensions: []
|
30
|
+
extra_rdoc_files: []
|
31
|
+
files:
|
32
|
+
- lib/sign_pass.rb
|
33
|
+
- bin/rsign_pass
|
34
|
+
homepage: http://www.apple.com
|
35
|
+
licenses: []
|
36
|
+
post_install_message:
|
37
|
+
rdoc_options: []
|
38
|
+
require_paths:
|
39
|
+
- lib
|
40
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
47
|
+
none: false
|
48
|
+
requirements:
|
49
|
+
- - ! '>='
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '0'
|
52
|
+
requirements: []
|
53
|
+
rubyforge_project:
|
54
|
+
rubygems_version: 1.8.10
|
55
|
+
signing_key:
|
56
|
+
specification_version: 3
|
57
|
+
summary: Packages and signs passes.
|
58
|
+
test_files: []
|