app_permission_statistics 0.1.1

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.
@@ -0,0 +1,317 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'core_ext/inflector'
4
+ require_relative 'core_ext/try'
5
+
6
+ require 'openssl'
7
+ require 'cfpropertylist'
8
+
9
+ module AppPermissionStatistics
10
+
11
+ # .mobileprovision file parser
12
+ class MobileProvision
13
+ def initialize(path)
14
+ @path = path
15
+ end
16
+
17
+ def name
18
+ mobileprovision.try(:[], 'Name')
19
+ end
20
+
21
+ def app_name
22
+ mobileprovision.try(:[], 'AppIDName')
23
+ end
24
+
25
+ def type
26
+ return :development if development?
27
+ return :adhoc if adhoc?
28
+ return :appstore if appstore?
29
+ return :enterprise if enterprise?
30
+ end
31
+
32
+ def platforms
33
+ return unless platforms = mobileprovision.try(:[], 'Platform')
34
+
35
+ platforms.map do |v|
36
+ v = 'macOS' if v == 'OSX'
37
+ v.downcase.to_sym
38
+ end
39
+ end
40
+
41
+ def platform
42
+ platforms[0]
43
+ end
44
+
45
+ def devices
46
+ mobileprovision.try(:[], 'ProvisionedDevices')
47
+ end
48
+
49
+ def team_identifier
50
+ mobileprovision.try(:[], 'TeamIdentifier')
51
+ end
52
+
53
+ def team_name
54
+ mobileprovision.try(:[], 'TeamName')
55
+ end
56
+
57
+ def profile_name
58
+ mobileprovision.try(:[], 'Name')
59
+ end
60
+
61
+ def created_date
62
+ mobileprovision.try(:[], 'CreationDate')
63
+ end
64
+
65
+ def expired_date
66
+ mobileprovision.try(:[], 'ExpirationDate')
67
+ end
68
+
69
+ def entitlements
70
+ mobileprovision.try(:[], 'Entitlements')
71
+ end
72
+
73
+ def developer_certs
74
+ certs = mobileprovision.try(:[], 'DeveloperCertificates')
75
+ return if certs.empty?
76
+
77
+ certs.each_with_object([]) do |cert, obj|
78
+ obj << DeveloperCertificate.new(cert)
79
+ end
80
+ end
81
+
82
+ # Detect is development type of mobileprovision
83
+ #
84
+ # related link: https://stackoverflow.com/questions/1003066/what-does-get-task-allow-do-in-xcode
85
+ def development?
86
+ case platform.downcase.to_sym
87
+ when :ios
88
+ entitlements['get-task-allow'] == true
89
+ when :macos
90
+ !devices.nil?
91
+ else
92
+ raise Error, "Not implement with platform: #{platform}"
93
+ end
94
+ end
95
+
96
+ # Detect app store type
97
+ #
98
+ # related link: https://developer.apple.com/library/archive/qa/qa1830/_index.html
99
+ def appstore?
100
+ case platform.downcase.to_sym
101
+ when :ios
102
+ !development? && entitlements.key?('beta-reports-active')
103
+ when :macos
104
+ !development?
105
+ else
106
+ raise Error, "Not implement with platform: #{platform}"
107
+ end
108
+ end
109
+
110
+ def adhoc?
111
+ return false if platform == :macos # macOS no need adhoc
112
+
113
+ !development? && !devices.nil?
114
+ end
115
+
116
+ def enterprise?
117
+ return false if platform == :macos # macOS no need adhoc
118
+
119
+ !development? && !adhoc? && !appstore?
120
+ end
121
+ alias inhouse? enterprise?
122
+
123
+ # Enabled Capabilites
124
+ #
125
+ # Related link: https://developer.apple.com/help/account/reference/supported-capabilities-ios
126
+ def enabled_capabilities
127
+ capabilities = Hash.new
128
+ entitlements.each do |key, value|
129
+ case key
130
+ when 'com.apple.developer.game-center'
131
+ capabilities['Game Center'] = {
132
+ key => value
133
+ }
134
+ when 'keychain-access-groups'
135
+ capabilities['Keychain sharing'] = {
136
+ key => value
137
+ }
138
+ when 'aps-environment'
139
+ capabilities['Push Notifications'] = {
140
+ key => value
141
+ }
142
+ when 'com.apple.developer.applesignin'
143
+ capabilities['Sign In with Apple'] = {
144
+ key => value
145
+ }
146
+ when 'com.apple.developer.siri'
147
+ capabilities['SiriKit'] = {
148
+ key => value
149
+ }
150
+ when 'com.apple.security.application-groups'
151
+ capabilities['App Groups'] = {
152
+ key => value
153
+ }
154
+ when 'com.apple.developer.associated-domains'
155
+ capabilities['Associated Domains'] = {
156
+ key => value
157
+ }
158
+ when 'com.apple.developer.default-data-protection'
159
+ capabilities['Data Protection'] = {
160
+ key => value
161
+ }
162
+ when 'com.apple.developer.networking.networkextension'
163
+ capabilities ['Network Extensions'] = {
164
+ key => value
165
+ }
166
+ when 'com.apple.developer.networking.vpn.api'
167
+ capabilities ['Personal VPN'] = {
168
+ key => value
169
+ }
170
+ when 'com.apple.developer.healthkit',
171
+ 'com.apple.developer.healthkit.access'
172
+ capabilities['HealthKit'] = {
173
+ 'com.apple.developer.healthkit' => entitlements['com.apple.developer.healthkit'],
174
+ 'com.apple.developer.healthkit.access' => entitlements['com.apple.developer.healthkit.access'],
175
+ } unless capabilities.include?('HealthKit')
176
+ when 'com.apple.developer.icloud-services',
177
+ 'com.apple.developer.icloud-container-identifiers'
178
+ capabilities['iCloud'] = {
179
+ 'com.apple.developer.icloud-services' => entitlements['com.apple.developer.icloud-services'],
180
+ 'com.apple.developer.icloud-container-identifiers' => entitlements['com.apple.developer.icloud-container-identifiers'],
181
+ } unless capabilities.include?('iCloud')
182
+ when 'com.apple.developer.in-app-payments'
183
+ capabilities['Apple Pay'] = {
184
+ key => value
185
+ }
186
+ when 'com.apple.developer.homekit'
187
+ capabilities['HomeKit'] = {
188
+ key => value
189
+ }
190
+ when 'com.apple.developer.user-fonts'
191
+ capabilities['Fonts'] = {
192
+ key => value
193
+ }
194
+ when 'com.apple.developer.pass-type-identifiers'
195
+ capabilities['Wallet'] = {
196
+ key => value
197
+ }
198
+ when 'inter-app-audio'
199
+ capabilities['Inter-App Audio'] = {
200
+ key => value
201
+ }
202
+ when 'com.apple.developer.networking.multipath'
203
+ capabilities['Multipath'] = {
204
+ key => value
205
+ }
206
+ when 'com.apple.developer.authentication-services.autofill-credential-provider'
207
+ capabilities['AutoFill Credential Provider'] = {
208
+ key => value
209
+ }
210
+ when 'com.apple.developer.networking.wifi-info'
211
+ capabilities['Access WiFi Information'] = {
212
+ key => value
213
+ }
214
+ when 'com.apple.external-accessory.wireless-configuration'
215
+ capabilities['Wireless Accessory Configuration'] = {
216
+ key => value
217
+ }
218
+ when 'com.apple.developer.kernel.extended-virtual-addressing'
219
+ capabilities['Extended Virtual Address Space'] = {
220
+ key => value
221
+ }
222
+ when 'com.apple.developer.nfc.readersession.formats'
223
+ capabilities['NFC Tag Reading'] = {
224
+ key => value
225
+ }
226
+ when 'com.apple.developer.ClassKit-environment'
227
+ capabilities['ClassKit'] = {
228
+ key => value
229
+ }
230
+ when 'com.apple.developer.networking.HotspotConfiguration'
231
+ capabilities['Hotspot'] = {
232
+ key => value
233
+ }
234
+ when 'com.apple.developer.devicecheck.appattest-environment'
235
+ capabilities['App Attest'] = {
236
+ key => value
237
+ }
238
+ when 'com.apple.developer.coremedia.hls.low-latency'
239
+ capabilities['Low Latency HLS'] = {
240
+ key => value
241
+ }
242
+ when 'com.apple.developer.associated-domains.mdm-managed'
243
+ capabilities['MDM Managed Associated Domains'] = {
244
+ key => value
245
+ }
246
+ end
247
+ end
248
+ capabilities
249
+ end
250
+
251
+
252
+ def [](key)
253
+ mobileprovision.try(:[], key.to_s)
254
+ end
255
+
256
+ def empty?
257
+ mobileprovision.nil?
258
+ end
259
+
260
+ def mobileprovision
261
+ return @mobileprovision = nil unless File.exist?(@path)
262
+
263
+ data = File.read(@path)
264
+ data = strip_plist_wrapper(data) unless bplist?(data)
265
+ list = CFPropertyList::List.new(data: data).value
266
+ @mobileprovision = CFPropertyList.native_types(list)
267
+ rescue CFFormatError
268
+ @mobileprovision = nil
269
+ end
270
+
271
+ def method_missing(method_name, *args, &block)
272
+ mobileprovision.try(:[], method_name.to_s.ai_camelcase) ||
273
+ mobileprovision.send(method_name) ||
274
+ super
275
+ end
276
+
277
+ def respond_to_missing?(method_name, *args)
278
+ mobileprovision.key?(method_name.to_s.ai_camelcase) ||
279
+ mobileprovision.respond_to?(method_name) ||
280
+ super
281
+ end
282
+
283
+ private
284
+
285
+ def bplist?(raw)
286
+ raw[0..5] == 'bplist'
287
+ end
288
+
289
+ def strip_plist_wrapper(raw)
290
+ end_tag = '</plist>'
291
+ start_point = raw.index('<?xml version=')
292
+ end_point = raw.index(end_tag) + end_tag.size - 1
293
+ raw[start_point..end_point]
294
+ end
295
+
296
+ # Developer Certificate
297
+ class DeveloperCertificate
298
+ attr_reader :raw
299
+
300
+ def initialize(data)
301
+ @raw = OpenSSL::X509::Certificate.new(data)
302
+ end
303
+
304
+ def name
305
+ @raw.subject.to_a.find { |name, _, _| name == 'CN' }[1].force_encoding('UTF-8')
306
+ end
307
+
308
+ def created_date
309
+ @raw.not_after
310
+ end
311
+
312
+ def expired_date
313
+ @raw.not_before
314
+ end
315
+ end
316
+ end
317
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AppPermissionStatistics
4
+ VERSION = "0.1.1"
5
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "app_permission_statistics/version"
4
+ require_relative "app_permission_statistics/analyze"
5
+ require_relative "app_permission_statistics/extracter"
6
+
7
+ module AppPermissionStatistics
8
+
9
+ class Actuator
10
+ extend Forwardable
11
+ attr_reader :file
12
+ attr_reader :compare_file
13
+ attr_reader :store_path
14
+ attr_reader :report_path
15
+
16
+ def initialize(file,compare_file, report_path: nil,store_path: nil)
17
+ @file = file
18
+ @compare_file = compare_file
19
+ @report_path = report_path
20
+ @store_path = store_path
21
+ end
22
+
23
+ def run
24
+ compare_extracter = Extracter.new(@compare_file , @store_path)
25
+ if compare_extracter.plistInfo.identifier != extracter.plistInfo.identifier
26
+ abort("compared files have different plist identifier")
27
+ end
28
+ if Gem::Version.new(compare_extracter.plistInfo.version) == Gem::Version.new(extracter.plistInfo.version)
29
+ abort("compared files plist version is same")
30
+ end
31
+ compare_extracter.extract_update
32
+ extracter.extract_update
33
+ analyzer.analyze
34
+ extracter.clear!
35
+ compare_extracter.clear!
36
+ end
37
+
38
+ def extracter
39
+ @extracter ||= Extracter.new(@file , @store_path)
40
+ end
41
+
42
+ def analyzer
43
+ identifier = @extracter.plistInfo.identifier
44
+ @analyzer ||= Analyzer.new(identifier,@report_path,@store_path)
45
+ end
46
+
47
+ end
48
+
49
+ end
metadata ADDED
@@ -0,0 +1,127 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: app_permission_statistics
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - bin
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-04-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: yaml
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: crimp
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: CFPropertyList
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "<"
46
+ - !ruby/object:Gem::Version
47
+ version: 3.1.0
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: 2.3.4
51
+ type: :runtime
52
+ prerelease: false
53
+ version_requirements: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - "<"
56
+ - !ruby/object:Gem::Version
57
+ version: 3.1.0
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: 2.3.4
61
+ - !ruby/object:Gem::Dependency
62
+ name: bundler
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '1.12'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '1.12'
75
+ description: app permission statistics from ipas
76
+ email:
77
+ - tang.bin@olaola.chat
78
+ executables:
79
+ - app_permission_statistics
80
+ extensions: []
81
+ extra_rdoc_files: []
82
+ files:
83
+ - ".DS_Store"
84
+ - ".gitignore"
85
+ - Gemfile
86
+ - Gemfile.lock
87
+ - README.md
88
+ - Rakefile
89
+ - analyze_report
90
+ - app_permission_statistics.gemspec
91
+ - bin/app_permission_statistics
92
+ - bin/setup
93
+ - lib/app_permission_statistics.rb
94
+ - lib/app_permission_statistics/analyze.rb
95
+ - lib/app_permission_statistics/core_ext/inflector.rb
96
+ - lib/app_permission_statistics/core_ext/try.rb
97
+ - lib/app_permission_statistics/entitlements.rb
98
+ - lib/app_permission_statistics/extracter.rb
99
+ - lib/app_permission_statistics/helper.rb
100
+ - lib/app_permission_statistics/info_plist.rb
101
+ - lib/app_permission_statistics/mobile_provision.rb
102
+ - lib/app_permission_statistics/version.rb
103
+ homepage: https://github.com/olaola-chat/cli-app_permission_statistics.git
104
+ licenses: []
105
+ metadata:
106
+ homepage_uri: https://github.com/olaola-chat/cli-app_permission_statistics.git
107
+ source_code_uri: https://github.com/olaola-chat/cli-app_permission_statistics.git
108
+ post_install_message:
109
+ rdoc_options: []
110
+ require_paths:
111
+ - lib
112
+ required_ruby_version: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: 2.3.0
117
+ required_rubygems_version: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ requirements: []
123
+ rubygems_version: 3.2.3
124
+ signing_key:
125
+ specification_version: 4
126
+ summary: app permission statistics
127
+ test_files: []