app-info 2.0.0.beta3 → 2.0.0.beta4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,230 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'zip'
4
+ require 'pngdefry'
5
+ require 'fileutils'
6
+ require 'securerandom'
7
+ require 'cfpropertylist'
8
+ require 'app_info/util'
9
+ require 'app_info/core_ext/object/try'
10
+
11
+ module AppInfo
12
+ # IPA parser
13
+ class IPA
14
+ attr_reader :file
15
+
16
+ # iOS Export types
17
+ module ExportType
18
+ DEBUG = 'Debug'
19
+ ADHOC = 'AdHoc'
20
+ INHOUSE = 'inHouse'
21
+ RELEASE = 'Release'
22
+ UNKOWN = nil
23
+ end
24
+
25
+ def initialize(file)
26
+ @file = file
27
+ end
28
+
29
+ def size(humanable = false)
30
+ AppInfo::Util.file_size(@file, humanable)
31
+ end
32
+
33
+ def os
34
+ AppInfo::Platform::IOS
35
+ end
36
+ alias file_type os
37
+
38
+ def iphone?
39
+ info.iphone?
40
+ end
41
+
42
+ def ipad?
43
+ info.ipad?
44
+ end
45
+
46
+ def universal?
47
+ info.universal?
48
+ end
49
+
50
+ def build_version
51
+ info.build_version
52
+ end
53
+
54
+ def release_version
55
+ info.release_version
56
+ end
57
+
58
+ def identifier
59
+ info.identifier
60
+ end
61
+
62
+ def name
63
+ display_name || bundle_name
64
+ end
65
+
66
+ def display_name
67
+ info.display_name
68
+ end
69
+
70
+ def bundle_name
71
+ info.bundle_name
72
+ end
73
+
74
+ def icons
75
+ info.icons
76
+ end
77
+
78
+ #
79
+ # Return the minimum OS version for the given application
80
+ #
81
+ def min_sdk_version
82
+ info.min_sdk_version
83
+ end
84
+
85
+ def device_type
86
+ info.device_type
87
+ end
88
+
89
+ def devices
90
+ mobileprovision.devices
91
+ end
92
+
93
+ def team_name
94
+ mobileprovision.team_name
95
+ end
96
+
97
+ def team_identifier
98
+ mobileprovision.team_identifier
99
+ end
100
+
101
+ def profile_name
102
+ mobileprovision.profile_name
103
+ end
104
+
105
+ def expired_date
106
+ mobileprovision.expired_date
107
+ end
108
+
109
+ def distribution_name
110
+ "#{profile_name} - #{team_name}" if profile_name && team_name
111
+ end
112
+
113
+ def release_type
114
+ if stored?
115
+ ExportType::RELEASE
116
+ else
117
+ build_type
118
+ end
119
+ end
120
+
121
+ def build_type
122
+ if mobileprovision?
123
+ if devices
124
+ ExportType::ADHOC
125
+ else
126
+ ExportType::INHOUSE
127
+ end
128
+ else
129
+ ExportType::DEBUG
130
+ end
131
+ end
132
+
133
+ def stored?
134
+ metadata? ? true : false
135
+ end
136
+
137
+ def hide_developer_certificates
138
+ mobileprovision.delete('DeveloperCertificates') if mobileprovision?
139
+ end
140
+
141
+ def mobileprovision
142
+ return unless mobileprovision?
143
+ return @mobileprovision if @mobileprovision
144
+
145
+ @mobileprovision = MobileProvision.new(mobileprovision_path)
146
+ end
147
+
148
+ def mobileprovision?
149
+ File.exist?mobileprovision_path
150
+ end
151
+
152
+ def mobileprovision_path
153
+ filename = 'embedded.mobileprovision'
154
+ @mobileprovision_path ||= File.join(@file, filename)
155
+ unless File.exist?(@mobileprovision_path)
156
+ @mobileprovision_path = File.join(app_path, filename)
157
+ end
158
+
159
+ @mobileprovision_path
160
+ end
161
+
162
+ def metadata
163
+ return unless metadata?
164
+
165
+ @metadata ||= CFPropertyList.native_types(CFPropertyList::List.new(file: metadata_path).value)
166
+ end
167
+
168
+ def metadata?
169
+ File.exist?(metadata_path)
170
+ end
171
+
172
+ def metadata_path
173
+ @metadata_path ||= File.join(contents, 'iTunesMetadata.plist')
174
+ end
175
+
176
+ def info
177
+ @info ||= InfoPlist.new(app_path)
178
+ end
179
+
180
+ def app_path
181
+ @app_path ||= Dir.glob(File.join(contents, 'Payload', '*.app')).first
182
+ end
183
+
184
+ def cleanup!
185
+ return unless @contents
186
+
187
+ FileUtils.rm_rf(@contents)
188
+
189
+ @contents = nil
190
+ @icons = nil
191
+ @app_path = nil
192
+ @metadata = nil
193
+ @metadata_path = nil
194
+ @info = nil
195
+ end
196
+
197
+ alias bundle_id identifier
198
+
199
+ private
200
+
201
+ def contents
202
+ # source: https://github.com/soffes/lagunitas/blob/master/lib/lagunitas/ipa.rb
203
+ unless @contents
204
+ @contents = "#{Dir.mktmpdir}/AppInfo-ios-#{SecureRandom.hex}"
205
+ Zip::File.open(@file) do |zip_file|
206
+ zip_file.each do |f|
207
+ f_path = File.join(@contents, f.name)
208
+ zip_file.extract(f, f_path) unless File.exist?(f_path)
209
+ end
210
+ end
211
+ end
212
+
213
+ @contents
214
+ end
215
+
216
+ def icons_root_path
217
+ iphone = 'CFBundleIcons'
218
+ ipad = 'CFBundleIcons~ipad'
219
+
220
+ case device_type
221
+ when 'iPhone'
222
+ [iphone]
223
+ when 'iPad'
224
+ [ipad]
225
+ when 'Universal'
226
+ [iphone, ipad]
227
+ end
228
+ end
229
+ end
230
+ end
@@ -0,0 +1,133 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cfpropertylist'
4
+
5
+ module AppInfo
6
+ # iOS Info.plist parser
7
+ class InfoPlist
8
+ def initialize(app_path)
9
+ @app_path = app_path
10
+ end
11
+
12
+ def build_version
13
+ info.try(:[], 'CFBundleVersion')
14
+ end
15
+
16
+ def release_version
17
+ info.try(:[], 'CFBundleShortVersionString')
18
+ end
19
+
20
+ def identifier
21
+ info.try(:[], 'CFBundleIdentifier')
22
+ end
23
+ alias bundle_id identifier
24
+
25
+ def name
26
+ display_name || bundle_name
27
+ end
28
+
29
+ def display_name
30
+ info.try(:[], 'CFBundleDisplayName')
31
+ end
32
+
33
+ def bundle_name
34
+ info.try(:[], 'CFBundleName')
35
+ end
36
+
37
+ #
38
+ # Extract the Minimum OS Version from the Info.plist
39
+ #
40
+ def min_sdk_version
41
+ info.try(:[], 'MinimumOSVersion')
42
+ end
43
+
44
+ def icons
45
+ return @icons if @icons
46
+
47
+ @icons = []
48
+ icons_root_path.each do |name|
49
+ icon_array = info.try(:[], name)
50
+ .try(:[], 'CFBundlePrimaryIcon')
51
+ .try(:[], 'CFBundleIconFiles')
52
+
53
+ next if icon_array.nil? || icon_array.zero?
54
+
55
+ icon_array.each do |items|
56
+ Dir.glob(File.join(@app_path, "#{items}*")).find_all.each do |file|
57
+ dict = {
58
+ name: File.basename(file),
59
+ file: file,
60
+ dimensions: Pngdefry.dimensions(file)
61
+ }
62
+
63
+ @icons.push(dict)
64
+ end
65
+ end
66
+ end
67
+
68
+ @icons
69
+ end
70
+
71
+ def device_type
72
+ device_family = info.try(:[], 'UIDeviceFamily')
73
+ if device_family.length == 1
74
+ case device_family
75
+ when [1]
76
+ 'iPhone'
77
+ when [2]
78
+ 'iPad'
79
+ end
80
+ elsif device_family.length == 2 && device_family == [1, 2]
81
+ 'Universal'
82
+ end
83
+ end
84
+
85
+ def iphone?
86
+ device_type == 'iPhone'
87
+ end
88
+
89
+ def ipad?
90
+ device_type == 'iPad'
91
+ end
92
+
93
+ def universal?
94
+ device_type == 'Universal'
95
+ end
96
+
97
+ def release_type
98
+ if stored?
99
+ 'Store'
100
+ else
101
+ build_type
102
+ end
103
+ end
104
+
105
+ def [](key)
106
+ info.try(:[], key.to_s)
107
+ end
108
+
109
+ private
110
+
111
+ def info
112
+ @info ||= CFPropertyList.native_types(CFPropertyList::List.new(file: info_path).value)
113
+ end
114
+
115
+ def info_path
116
+ File.join(@app_path, 'Info.plist')
117
+ end
118
+
119
+ IPHONE_KEY = 'CFBundleIcons'
120
+ IPAD_KEY = 'CFBundleIcons~ipad'
121
+
122
+ def icons_root_path
123
+ case device_type
124
+ when 'iPhone'
125
+ [IPHONE_KEY]
126
+ when 'iPad'
127
+ [IPAD_KEY]
128
+ when 'Universal'
129
+ [IPHONE_KEY, IPAD_KEY]
130
+ end
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cfpropertylist'
4
+
5
+ module AppInfo
6
+ # .mobileprovision file parser
7
+ class MobileProvision
8
+ def initialize(path)
9
+ @path = path
10
+ end
11
+
12
+ def name
13
+ mobileprovision.try(:[], 'Name')
14
+ end
15
+
16
+ def app_name
17
+ mobileprovision.try(:[], 'AppIDName')
18
+ end
19
+
20
+ def devices
21
+ mobileprovision.try(:[], 'ProvisionedDevices')
22
+ end
23
+
24
+ def team_identifier
25
+ mobileprovision.try(:[], 'TeamIdentifier')
26
+ end
27
+
28
+ def team_name
29
+ mobileprovision.try(:[], 'TeamName')
30
+ end
31
+
32
+ def profile_name
33
+ mobileprovision.try(:[], 'Name')
34
+ end
35
+
36
+ def created_date
37
+ mobileprovision.try(:[], 'CreationDate')
38
+ end
39
+
40
+ def expired_date
41
+ mobileprovision.try(:[], 'ExpirationDate')
42
+ end
43
+
44
+ def entitlements
45
+ mobileprovision.try(:[], 'Entitlements')
46
+ end
47
+
48
+ def method_missing(method_name, *args, &block)
49
+ key = if method_name.to_s.include?('_')
50
+ method_name.to_s
51
+ .split('_')
52
+ .map(&:capitalize)
53
+ .join('')
54
+ else
55
+ method_name.to_s
56
+ end
57
+
58
+ mobileprovision.try(:[], key)
59
+ end
60
+
61
+ def empty?
62
+ mobileprovision.nil?
63
+ end
64
+
65
+ def mobileprovision
66
+ return @mobileprovision = nil unless File.exist?(@path)
67
+
68
+ data = File.read(@path)
69
+ data = strip_plist_wrapper(data) unless bplist?(data)
70
+ list = CFPropertyList::List.new(data: data).value
71
+ @mobileprovision = CFPropertyList.native_types(list)
72
+ rescue CFFormatError
73
+ @mobileprovision = nil
74
+ end
75
+
76
+ private
77
+
78
+ def bplist?(raw)
79
+ raw[0..5] == 'bplist'
80
+ end
81
+
82
+ def strip_plist_wrapper(raw)
83
+ end_tag = '</plist>'
84
+ start_point = raw.index('<?xml version=')
85
+ end_point = raw.index(end_tag) + end_tag.size - 1
86
+ raw[start_point..end_point]
87
+ end
88
+ end
89
+ end