ipa_utilities 0.0.2
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.
- checksums.yaml +7 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +24 -0
- data/README.md +95 -0
- data/bin/ipa_utilities +256 -0
- data/ipa_utilities.gemspec +23 -0
- data/lib/ipa_utilities/IpaUtilities.rb +63 -0
- data/lib/ipa_utilities/Parsers.rb +138 -0
- data/lib/ipa_utilities/version.rb +3 -0
- data/lib/ipa_utilities.rb +3 -0
- data/lib/resources/Original.Entitlements.plist +10 -0
- metadata +111 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: dd225108fd52aee28d1e055391c0d5f0ddca5706
|
4
|
+
data.tar.gz: 9be62f69f6eef418085b630d5eaf017ece66fb65
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 01811aa704bac5d8c1f4a7d59aa6c9e4447795eace874e5ad657a0af17d8a4cd724ad28eaba94bd7c1508b9b0e650dcf2e1fcaa4302f03ca0d514f071a2fe757
|
7
|
+
data.tar.gz: 8460af87b77f427a1a58d88d6aca7446badfc760629d5b9426c14f80ea25b3b65cb117e190a40bded7732e313e461b59e62148cbe6e0f33a357ba3443889cd2f
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
ipa_utilities (0.0.1)
|
5
|
+
CFPropertyList (~> 2.2)
|
6
|
+
colorize (~> 0.7)
|
7
|
+
commander (~> 4.1)
|
8
|
+
json (~> 1.8)
|
9
|
+
|
10
|
+
GEM
|
11
|
+
remote: https://rubygems.org/
|
12
|
+
specs:
|
13
|
+
CFPropertyList (2.2.8)
|
14
|
+
colorize (0.7.3)
|
15
|
+
commander (4.2.0)
|
16
|
+
highline (~> 1.6.11)
|
17
|
+
highline (1.6.21)
|
18
|
+
json (1.8.1)
|
19
|
+
|
20
|
+
PLATFORMS
|
21
|
+
ruby
|
22
|
+
|
23
|
+
DEPENDENCIES
|
24
|
+
ipa_utilities!
|
data/README.md
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
# ipa_utilities
|
2
|
+
|
3
|
+
Simple ruby gem to execute common ipa utilities, such as verify integrity, convert certificate formats, re-signs an ipa using a new provision profile and more.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
$ gem install ipa_utilities
|
8
|
+
|
9
|
+
## Command Line Tool
|
10
|
+
`ipa_utilities` is available as a command line tool. the main functionalities are described bellow:
|
11
|
+
|
12
|
+
For help use
|
13
|
+
|
14
|
+
ipa_utilities -h
|
15
|
+
# works for any of the verbs bellow
|
16
|
+
ipa_utilities verify -h
|
17
|
+
|
18
|
+
#### verify
|
19
|
+
ipa_utilities verify verb is used to verify the integrity and signature of an ipa file
|
20
|
+
|
21
|
+
ipa_utilities verify ipa_path
|
22
|
+
ipa_utilities verify ipa_path -c apns_certificate_path
|
23
|
+
ipa_utilities verify ipa_path -c apns_certificate_path -d device_UDID
|
24
|
+
|
25
|
+
By using the `-c apns_certificate_path` you can cross reference the ipa APNS environment with the APNS_Certificate passed
|
26
|
+
|
27
|
+
By passing a device UDID using `-d UDID` option, you can verify if the UDID is included in the embedded provision profile
|
28
|
+
|
29
|
+
#### certificate
|
30
|
+
|
31
|
+
ipa_utilities certificate ipa_path
|
32
|
+
This command will return the name of the APNS certificate that will be used with for the current ipa, it will also search the keychain for the existence of the certificate returned
|
33
|
+
|
34
|
+
#### convert
|
35
|
+
|
36
|
+
ipa_utilities convert p12_path
|
37
|
+
Convert verb helps in converting a P12 formatted identity file to a PEM file to be used with your APNS server implementation
|
38
|
+
|
39
|
+
Use `-o out_path` to select the save location
|
40
|
+
|
41
|
+
#### resign
|
42
|
+
|
43
|
+
ipa_utilities resign ipa_path -p new_provision_path
|
44
|
+
Re-Signs the ipa using the new `new_provision_path`
|
45
|
+
|
46
|
+
Use `-o out_path` to select the save location
|
47
|
+
|
48
|
+
## Ruby Classes
|
49
|
+
|
50
|
+
#### `IpaUtilities`
|
51
|
+
`IpaUtilities` contains high level ipa bound operations:
|
52
|
+
|
53
|
+
ipa = IpaUtilities.new ipa_path
|
54
|
+
|
55
|
+
- `ipa.unzip` to unzip the ipa
|
56
|
+
- `ipa.zip path` zip the ipa to a specific location
|
57
|
+
- `ipa.verifyCodeSign` verifies the code sign for the unzipped ipa
|
58
|
+
- `ipa.parse` create and return a `ProvisionParser` object that is used to query the embedded provision profile
|
59
|
+
|
60
|
+
#### `ProvisionParser`
|
61
|
+
`ProvisionParser` used to query a provision profile
|
62
|
+
|
63
|
+
parser = ProvisionParser.new provision_profile_path
|
64
|
+
|
65
|
+
- `parser.uuid` returns the UUID of the provision profile
|
66
|
+
- `parser.signingIdentities` returns the signing identities from the certificate object within the the provision profile
|
67
|
+
- `parser.certificates` returns the array of the certificates
|
68
|
+
- `parser.provisionedDevices` returns array of devices included in the provision profile
|
69
|
+
- `parser.isAPNSProduction` reads the entitlements and checks for APNS environment
|
70
|
+
- `parser.isBuildRelease`, `isBuildStoreDistribution` reads `get-task-allow` fro the - entitlements
|
71
|
+
- `parser.appBundleID` returns the
|
72
|
+
- `parser.teamName` returns the team name
|
73
|
+
- `parser.teamIdentifier` returns the team identifier
|
74
|
+
|
75
|
+
#### `PemParser`
|
76
|
+
`PemParser` reads a PEM formatted certificate files
|
77
|
+
|
78
|
+
pem = PemParser.new pem_path
|
79
|
+
|
80
|
+
- `name` the common name of the certificate
|
81
|
+
- `isAPNS` checks if the pem is APNS
|
82
|
+
- `isProduction` check if the certificate is for production
|
83
|
+
- `bundleID` return the bundle id from the certificate
|
84
|
+
|
85
|
+
## Contact
|
86
|
+
|
87
|
+
Omar Abdelhafith
|
88
|
+
|
89
|
+
- http://nsomar.com
|
90
|
+
- http://twitter.com/ifnottrue
|
91
|
+
- o.arrabi@me.com
|
92
|
+
|
93
|
+
## License
|
94
|
+
|
95
|
+
ipa_utilities is available under the MIT license.
|
data/bin/ipa_utilities
ADDED
@@ -0,0 +1,256 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'commander/import'
|
4
|
+
require 'colorize'
|
5
|
+
require 'ipa_utilities'
|
6
|
+
|
7
|
+
HighLine.track_eof = false
|
8
|
+
Signal.trap("INT") {}
|
9
|
+
|
10
|
+
program :version, IpaVersion::VERSION
|
11
|
+
program :description, 'A command-line interface for dealing with ipas'
|
12
|
+
|
13
|
+
program :help, 'Author', 'Omar Abdelhafith <o.arrabi@me.com>'
|
14
|
+
program :help, 'Website', 'http://nsomar.com'
|
15
|
+
program :help_formatter, :compact
|
16
|
+
|
17
|
+
global_option('--verbose') { $verbose = true }
|
18
|
+
$verbose = true
|
19
|
+
|
20
|
+
default_command :help
|
21
|
+
|
22
|
+
command :verify do |c|
|
23
|
+
c.syntax = 'ipa_utils verify ipa_path [...]'
|
24
|
+
c.summary = 'Verifies the ipa provision and signature information'
|
25
|
+
|
26
|
+
c.example 'description', 'ipa_utils verify ipa_path'
|
27
|
+
c.option '-c', '--certificate certificate', 'Path of the push notification PEM certificate'
|
28
|
+
c.option '-d', '--device udid', 'UDID of device to check if its included in embedded provision profile'
|
29
|
+
|
30
|
+
c.action do |args, options|
|
31
|
+
|
32
|
+
path = checkArgs args, "ipa"
|
33
|
+
exit unless path
|
34
|
+
|
35
|
+
certificate = options.certificate
|
36
|
+
device = options.device
|
37
|
+
|
38
|
+
begin
|
39
|
+
errors = 0
|
40
|
+
puts
|
41
|
+
|
42
|
+
ipa = IpaUtilities.new path
|
43
|
+
ipa.unzipAndParse
|
44
|
+
|
45
|
+
parser = ipa.provisionParser
|
46
|
+
|
47
|
+
puts "Reading general information"
|
48
|
+
puts "Application Bundle ID " + parser.appBundleID.green
|
49
|
+
puts "APNS Enviroment: " + parser.apnsEnviroment.green
|
50
|
+
puts "App Enviroment: " + parser.buildEnviroment.green
|
51
|
+
puts
|
52
|
+
|
53
|
+
puts "Verifying bundle signature " + ipa.verifyCodeSign
|
54
|
+
|
55
|
+
status = parser.isAPNSandAppSameEnviroment ? "Yes".green : "No".red
|
56
|
+
puts "Checking embedde provision profile APNS Entitlement vs App enviroments"
|
57
|
+
puts "Is App and APNS on same enviroment: " + status
|
58
|
+
|
59
|
+
if parser.isAPNSandAppSameEnviroment
|
60
|
+
gateway = parser.isAPNSProduction ? "gateway.push.apple.com:2195".green : "gateway.sandbox.push.apple.com:2195".green
|
61
|
+
puts "APNS connection gateway: " + gateway
|
62
|
+
else
|
63
|
+
appStatus = parser.isBuildRelease ? "false (Release)" : "true (debug)"
|
64
|
+
apnStatus = parser.apnsEnviroment
|
65
|
+
puts "The application was build with get-task-allow set to #{appStatus} while the aps-environment is set to #{apnStatus}, To fix this issue regenerated the provision profile from apple developer then rebuild the app using it".red
|
66
|
+
errors += 1
|
67
|
+
end
|
68
|
+
|
69
|
+
if certificate
|
70
|
+
puts
|
71
|
+
puts "Checking certificates"
|
72
|
+
# puts parser.signingIdentities
|
73
|
+
pem = PemParser.new certificate
|
74
|
+
|
75
|
+
if pem.isAPNS
|
76
|
+
puts "Certificate Name " + pem.name.green
|
77
|
+
puts "Certificate Enviroment: " + "#{pem.enviroment}".green
|
78
|
+
puts "Certificate Bundle ID: " + "#{pem.bundleID}".green
|
79
|
+
|
80
|
+
status = parser.appBundleID == pem.bundleID ? "Yes".green : "No".red
|
81
|
+
errors += 1 if parser.appBundleID != pem.bundleID
|
82
|
+
|
83
|
+
puts "Certificate bundleId identical to app #{status}"
|
84
|
+
|
85
|
+
status = pem.isProduction == parser.isAPNSProduction ? "Yes".green : "No".red
|
86
|
+
puts "Is provided certificate correct for passed ipa: " + status
|
87
|
+
|
88
|
+
if pem.isProduction != parser.isAPNSProduction
|
89
|
+
puts "The application was build with a provision profile containing aps-environment in #{apnStatus} enviroment while the passed certificate environment is set to #{pem.enviroment}\nTo fix this issue either export the correct iOS Push #{pem.enviroment} certificate from keychain or rebuild your app with the correct provision profile".red
|
90
|
+
errors += 1
|
91
|
+
end
|
92
|
+
else
|
93
|
+
apnStatus = parser.apnsEnviroment
|
94
|
+
puts "The passed certificate is not an APNS certificate".red
|
95
|
+
errors += 1
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
if device
|
101
|
+
puts
|
102
|
+
puts "Checking provisioned devices"
|
103
|
+
|
104
|
+
if parser.isBuildDistro
|
105
|
+
puts "Distribution build do not contain provisioned devices".red
|
106
|
+
errors += 1
|
107
|
+
else
|
108
|
+
puts "Embedded profile contains " + "#{parser.provisionedDevices.count}".green + " devices"
|
109
|
+
status = parser.provisionedDevices.include?(device) ? "Device with UDID #{device} found".green :
|
110
|
+
"Device with UDID #{device} not found".red
|
111
|
+
puts status
|
112
|
+
errors += 1 if !parser.provisionedDevices.include?(device)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
puts
|
117
|
+
puts "No errors encountered".green if errors == 0
|
118
|
+
puts "#{errors} errors encountered!".red if errors > 0
|
119
|
+
|
120
|
+
ensure
|
121
|
+
ipa.cleanUp
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
command :convert do |c|
|
127
|
+
c.syntax = 'ipa_utils convert p12_path [...]'
|
128
|
+
c.summary = 'Convert a p12 to PEM'
|
129
|
+
|
130
|
+
c.example 'description', 'ipa_utils convert p12_file_path'
|
131
|
+
c.option '-o', '--out outpath', 'Out put file for the Pem file'
|
132
|
+
# c.option '-d', '--device udid', 'UDID of device to check if its included in embedded provision profile'
|
133
|
+
|
134
|
+
c.action do |args, options|
|
135
|
+
|
136
|
+
path = checkArgs args, "p12"
|
137
|
+
exit unless path
|
138
|
+
|
139
|
+
outpath = options.out || "~/Desktop/out.pem"
|
140
|
+
|
141
|
+
begin
|
142
|
+
|
143
|
+
puts
|
144
|
+
puts "Converting P12 to Pem"
|
145
|
+
system "openssl pkcs12 -in #{path} -out #{outpath} -nodes -clcerts"
|
146
|
+
puts "Pem saved at " + outpath.green
|
147
|
+
|
148
|
+
ensure
|
149
|
+
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
command :certificate do |c|
|
155
|
+
c.syntax = 'ipa_utils certificate ipa [...]'
|
156
|
+
c.summary = 'fetch the correct push identity from the provided ipa (WIP)'
|
157
|
+
|
158
|
+
c.example 'description', 'ipa_utils certificate ipa_path (WIP)'
|
159
|
+
|
160
|
+
c.action do |args, options|
|
161
|
+
|
162
|
+
path = checkArgs args, "ipa"
|
163
|
+
exit unless path
|
164
|
+
|
165
|
+
begin
|
166
|
+
#Todo
|
167
|
+
puts
|
168
|
+
ipa = IpaUtilities.new path
|
169
|
+
ipa.unzipAndParse
|
170
|
+
parser = ipa.provisionParser
|
171
|
+
|
172
|
+
apnsEnviroment = parser.isAPNSProduction ? "Production" : "Development"
|
173
|
+
identityName = "Apple #{apnsEnviroment} IOS Push Services: #{parser.appBundleID}"
|
174
|
+
|
175
|
+
puts "Searching Keychain for identity " + identityName.green
|
176
|
+
|
177
|
+
identities = `security find-identity -v -p ssl-client`
|
178
|
+
puts "Item found please export it from your keychain".green if identities.lines.index{|s| s.include?(identityName)}
|
179
|
+
puts "Item couldnt be found in your keychain".red if !identities.lines.index{|s| s.include?(identityName)}
|
180
|
+
|
181
|
+
ensure
|
182
|
+
ipa.cleanUp
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
command :resign do |c|
|
188
|
+
c.syntax = 'ipa_utils resign ipa -p new_profile'
|
189
|
+
c.summary = 'Resigns the passed ipa to the new passed profile'
|
190
|
+
|
191
|
+
c.example 'description', 'ipa_utils certificate ipa_path -p profile'
|
192
|
+
c.option '-p', '--profile profile', 'Path of the provision profile to use'
|
193
|
+
c.option '-o', '--out outpath', 'Out put file for the Pem file'
|
194
|
+
|
195
|
+
c.action do |args, options|
|
196
|
+
|
197
|
+
puts
|
198
|
+
|
199
|
+
path = checkArgs args, "ipa"
|
200
|
+
exit unless path
|
201
|
+
|
202
|
+
profile = options.profile
|
203
|
+
if !profile
|
204
|
+
say_error "pass a profile with -p profile-path"
|
205
|
+
exit
|
206
|
+
end
|
207
|
+
|
208
|
+
exit unless checkFileExists "provision profile", profile
|
209
|
+
|
210
|
+
outpath = options.out || "~/Desktop/resigned.ipa"
|
211
|
+
|
212
|
+
begin
|
213
|
+
|
214
|
+
ipa = IpaUtilities.new path
|
215
|
+
|
216
|
+
ipa.unzipAndParse
|
217
|
+
ipa.deleteOldSignature
|
218
|
+
|
219
|
+
parser = ipa.provisionParser
|
220
|
+
|
221
|
+
puts "Copying the new provision profile to app bundle"
|
222
|
+
system "cp \"#{profile}\" \"Payload/#{ipa.bundleName}/embedded.mobileprovision\""
|
223
|
+
|
224
|
+
puts "Writing Entitlements.plist"
|
225
|
+
File.write "Entitlements.plist", parser.entitlementForSigning
|
226
|
+
|
227
|
+
buildName = parser.isBuildRelease ? "Distribution" : "Development"
|
228
|
+
system "codesign -s \"iPhone #{buildName}: #{parser.teamName} (#{parser.teamIdentifier})\" --entitlements Entitlements.plist \"Payload/DummyApp.app\" -f"
|
229
|
+
|
230
|
+
puts
|
231
|
+
ipa.zip outpath
|
232
|
+
|
233
|
+
ensure
|
234
|
+
ipa.cleanUp
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
def checkArgs args, title
|
240
|
+
if args.nil? || args.empty?
|
241
|
+
say_error "Path to #{title} is required"
|
242
|
+
return nil
|
243
|
+
end
|
244
|
+
|
245
|
+
checkFileExists title, args.first
|
246
|
+
end
|
247
|
+
|
248
|
+
def checkFileExists title, path
|
249
|
+
|
250
|
+
if !File.exist?path
|
251
|
+
say_error "Couldn't find #{title} with path #{path}"
|
252
|
+
return nil
|
253
|
+
end
|
254
|
+
|
255
|
+
path
|
256
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
$:.push File.expand_path("../lib", __FILE__)
|
2
|
+
require "ipa_utilities/version"
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = 'ipa_utilities'
|
6
|
+
s.version = IpaVersion::VERSION
|
7
|
+
s.date = '2014-07-16'
|
8
|
+
s.summary = "Utilities and library to handle useful ipa operations"
|
9
|
+
s.description = "ipa_utilities is a gem that helps in execute common ipa operations, such as verify, resign and others"
|
10
|
+
s.authors = ["Omar Abdelhafith"]
|
11
|
+
s.email = 'o.arrabi@me.com'
|
12
|
+
s.files = Dir["./**/*"].reject { |file| file =~ /\.\/(bin|log|pkg|script|spec|test|vendor)/ }
|
13
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
14
|
+
s.require_paths = ["lib"]
|
15
|
+
|
16
|
+
s.add_dependency "commander", "~> 4.1"
|
17
|
+
s.add_dependency "json", '~> 1.8'
|
18
|
+
s.add_dependency "CFPropertyList", '~> 2.2'
|
19
|
+
s.add_dependency "colorize", '~> 0.7'
|
20
|
+
|
21
|
+
s.homepage = 'http://nsomar.com'
|
22
|
+
s.license = 'MIT'
|
23
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'cfpropertylist'
|
2
|
+
require 'pathname'
|
3
|
+
require 'base64'
|
4
|
+
require 'colorize'
|
5
|
+
require 'ipa_utilities/Parsers'
|
6
|
+
|
7
|
+
class IpaUtilities
|
8
|
+
attr :provisionParser
|
9
|
+
|
10
|
+
def initialize ipaPath
|
11
|
+
pn = Pathname.new(ipaPath)
|
12
|
+
@ipaPath = pn.dirname
|
13
|
+
@ipaName = pn.basename
|
14
|
+
@fullPath = ipaPath
|
15
|
+
end
|
16
|
+
|
17
|
+
def unzip
|
18
|
+
say "Unzipping " + @fullPath.green if $verbose
|
19
|
+
system "unzip #{@fullPath} > log.txt"
|
20
|
+
end
|
21
|
+
|
22
|
+
def zip path
|
23
|
+
say "Zipping " + @fullPath.green if $verbose
|
24
|
+
system "zip -qr \"_new.ipa\" Payload"
|
25
|
+
system "cp _new.ipa #{path}"
|
26
|
+
say "Resigned ipa saved at " + path.green if $verbose
|
27
|
+
end
|
28
|
+
|
29
|
+
def bundleName
|
30
|
+
Dir.entries("Payload").last
|
31
|
+
end
|
32
|
+
|
33
|
+
def verifyCodeSign
|
34
|
+
result = `codesign -v Payload/#{bundleName} 2>&1`
|
35
|
+
result.empty? ? "Signature Valid\n".green : "Signature Not Valid\n".red + result.red if $verbose
|
36
|
+
end
|
37
|
+
|
38
|
+
def parse
|
39
|
+
@provisionPath = "Payload/#{bundleName}/embedded.mobileprovision"
|
40
|
+
@provisionParser = ProvisionParser.new @provisionPath
|
41
|
+
end
|
42
|
+
|
43
|
+
def unzipAndParse
|
44
|
+
unzip
|
45
|
+
puts "App bundle name is " + bundleName.green if $verbose
|
46
|
+
|
47
|
+
parse
|
48
|
+
say "Reading provision profile at "+ @provisionPath.green if $verbose
|
49
|
+
puts if $verbose
|
50
|
+
end
|
51
|
+
|
52
|
+
def deleteOldSignature
|
53
|
+
system "rm -rf Payload/*.app/_CodeSignature"
|
54
|
+
puts "Deleting old code sign file" if $verbose
|
55
|
+
end
|
56
|
+
|
57
|
+
def cleanUp
|
58
|
+
system "rm -rf Payload"
|
59
|
+
system "rm -rf tmp.plist"
|
60
|
+
system "rm -rf Entitlements.plist"
|
61
|
+
system "rm -rf _new.ipa"
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
class PemParser
|
2
|
+
|
3
|
+
def initialize file
|
4
|
+
@identity = PemParser.signingIdentitiesWithFile(file).first
|
5
|
+
end
|
6
|
+
|
7
|
+
def name
|
8
|
+
@identity
|
9
|
+
end
|
10
|
+
|
11
|
+
def isAPNS
|
12
|
+
@identity.include?("IOS Push Services")
|
13
|
+
end
|
14
|
+
|
15
|
+
def isProduction
|
16
|
+
!@identity.include?("Development")
|
17
|
+
end
|
18
|
+
|
19
|
+
def enviroment
|
20
|
+
isProduction ? "Production" : "Development (Sandbox)"
|
21
|
+
end
|
22
|
+
|
23
|
+
def bundleID
|
24
|
+
/: (.*?)$/.match(@identity).captures.first
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.signingIdentitiesWithBase64 base64
|
28
|
+
string = "-----BEGIN CERTIFICATE-----\n"
|
29
|
+
string += base64
|
30
|
+
string += "-----END CERTIFICATE-----"
|
31
|
+
|
32
|
+
File.write("cer.pem", string)
|
33
|
+
|
34
|
+
pem = `openssl x509 -text -in cer.pem`
|
35
|
+
|
36
|
+
system "rm -rf cer.pem"
|
37
|
+
|
38
|
+
identity = /CN=(.*?),/.match(pem).captures
|
39
|
+
identity
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.signingIdentitiesWithFile file
|
43
|
+
pem = `openssl x509 -text -in #{file}`
|
44
|
+
identity = /CN=(.*?),/.match(pem).captures
|
45
|
+
identity
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class ProvisionParser
|
50
|
+
|
51
|
+
def initialize provisionPath
|
52
|
+
@provisionPath = provisionPath
|
53
|
+
parse
|
54
|
+
end
|
55
|
+
|
56
|
+
def parse
|
57
|
+
# read mobileprovision and convert it to plist
|
58
|
+
`security cms -D -i #{@provisionPath} > tmp.plist`
|
59
|
+
|
60
|
+
# Get info from plist
|
61
|
+
plist = CFPropertyList::List.new
|
62
|
+
plist = CFPropertyList::List.new(:file => "tmp.plist")
|
63
|
+
@data = CFPropertyList.native_types(plist.value)
|
64
|
+
end
|
65
|
+
|
66
|
+
def uuid
|
67
|
+
@data["UUID"]
|
68
|
+
end
|
69
|
+
|
70
|
+
def signingIdentities
|
71
|
+
|
72
|
+
arr = []
|
73
|
+
|
74
|
+
certificates.each do |var|
|
75
|
+
arr << PemParser.signingIdentitiesWithBase64(Base64.encode64(var))
|
76
|
+
end
|
77
|
+
|
78
|
+
arr
|
79
|
+
end
|
80
|
+
|
81
|
+
def certificates
|
82
|
+
@data["DeveloperCertificates"]
|
83
|
+
end
|
84
|
+
|
85
|
+
def provisionedDevices
|
86
|
+
@data["ProvisionedDevices"]
|
87
|
+
end
|
88
|
+
|
89
|
+
def isAPNSProduction
|
90
|
+
@data["Entitlements"]["aps-environment"] == "production"
|
91
|
+
end
|
92
|
+
|
93
|
+
def isBuildRelease
|
94
|
+
@data["Entitlements"]["get-task-allow"] == false
|
95
|
+
end
|
96
|
+
|
97
|
+
def isBuildDistro
|
98
|
+
@data["ProvisionedDevices"].nil?
|
99
|
+
end
|
100
|
+
|
101
|
+
def isAPNSandAppSameEnviroment
|
102
|
+
isBuildRelease == isAPNSProduction
|
103
|
+
end
|
104
|
+
|
105
|
+
def appBundleID
|
106
|
+
var = @data["Entitlements"]["application-identifier"]
|
107
|
+
var.slice!(@data["TeamIdentifier"].first + ".")
|
108
|
+
var
|
109
|
+
end
|
110
|
+
|
111
|
+
def teamName
|
112
|
+
@data["TeamName"]
|
113
|
+
end
|
114
|
+
|
115
|
+
def teamIdentifier
|
116
|
+
@data["Entitlements"]["com.apple.developer.team-identifier"]
|
117
|
+
end
|
118
|
+
|
119
|
+
def apnsEnviroment
|
120
|
+
isAPNSProduction ? "Production" : "Development (Sandbox)"
|
121
|
+
end
|
122
|
+
|
123
|
+
def buildEnviroment
|
124
|
+
if isBuildRelease
|
125
|
+
isBuildDistro ? "Distribution" : "AdHoc"
|
126
|
+
else
|
127
|
+
"Development"
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def entitlementForSigning
|
132
|
+
filePath = File.expand_path "#{__FILE__}/../../resources/Original.Entitlements.plist"
|
133
|
+
file = File.read filePath
|
134
|
+
file.sub! "BUNDLE_ID", "#{teamIdentifier}.#{appBundleID}"
|
135
|
+
file.sub! "GET_TASK_ALLOW", isBuildRelease ? "false" : "true"
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
3
|
+
<plist version="1.0">
|
4
|
+
<dict>
|
5
|
+
<key>application-identifier</key>
|
6
|
+
<string>BUNDLE_ID</string>
|
7
|
+
<key>get-task-allow</key>
|
8
|
+
<GET_TASK_ALLOW/>
|
9
|
+
</dict>
|
10
|
+
</plist>
|
metadata
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ipa_utilities
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Omar Abdelhafith
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-07-16 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: commander
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.1'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '4.1'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: json
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.8'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.8'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: CFPropertyList
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '2.2'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '2.2'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: colorize
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.7'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.7'
|
69
|
+
description: ipa_utilities is a gem that helps in execute common ipa operations, such
|
70
|
+
as verify, resign and others
|
71
|
+
email: o.arrabi@me.com
|
72
|
+
executables:
|
73
|
+
- ipa_utilities
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- "./Gemfile"
|
78
|
+
- "./Gemfile.lock"
|
79
|
+
- "./README.md"
|
80
|
+
- "./ipa_utilities.gemspec"
|
81
|
+
- "./lib/ipa_utilities.rb"
|
82
|
+
- "./lib/ipa_utilities/IpaUtilities.rb"
|
83
|
+
- "./lib/ipa_utilities/Parsers.rb"
|
84
|
+
- "./lib/ipa_utilities/version.rb"
|
85
|
+
- "./lib/resources/Original.Entitlements.plist"
|
86
|
+
- bin/ipa_utilities
|
87
|
+
homepage: http://nsomar.com
|
88
|
+
licenses:
|
89
|
+
- MIT
|
90
|
+
metadata: {}
|
91
|
+
post_install_message:
|
92
|
+
rdoc_options: []
|
93
|
+
require_paths:
|
94
|
+
- lib
|
95
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
requirements: []
|
106
|
+
rubyforge_project:
|
107
|
+
rubygems_version: 2.3.0
|
108
|
+
signing_key:
|
109
|
+
specification_version: 4
|
110
|
+
summary: Utilities and library to handle useful ipa operations
|
111
|
+
test_files: []
|