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.
- checksums.yaml +7 -0
- data/.DS_Store +0 -0
- data/.gitignore +8 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +33 -0
- data/README.md +124 -0
- data/Rakefile +4 -0
- data/analyze_report +481 -0
- data/app_permission_statistics.gemspec +39 -0
- data/bin/app_permission_statistics +41 -0
- data/bin/setup +8 -0
- data/lib/app_permission_statistics/analyze.rb +220 -0
- data/lib/app_permission_statistics/core_ext/inflector.rb +35 -0
- data/lib/app_permission_statistics/core_ext/try.rb +112 -0
- data/lib/app_permission_statistics/entitlements.rb +185 -0
- data/lib/app_permission_statistics/extracter.rb +135 -0
- data/lib/app_permission_statistics/helper.rb +90 -0
- data/lib/app_permission_statistics/info_plist.rb +202 -0
- data/lib/app_permission_statistics/mobile_provision.rb +317 -0
- data/lib/app_permission_statistics/version.rb +5 -0
- data/lib/app_permission_statistics.rb +49 -0
- metadata +127 -0
@@ -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,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: []
|