app-info 2.8.2 → 3.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.
- checksums.yaml +4 -4
- data/.github/dependabot.yml +12 -7
- data/.github/workflows/ci.yml +7 -5
- data/.github/workflows/create_release.yml +15 -0
- data/.rubocop.yml +33 -11
- data/CHANGELOG.md +107 -1
- data/Gemfile +10 -5
- data/README.md +82 -15
- data/Rakefile +11 -0
- data/app_info.gemspec +14 -5
- data/lib/app_info/aab.rb +76 -110
- data/lib/app_info/android/signature.rb +114 -0
- data/lib/app_info/android/signatures/base.rb +53 -0
- data/lib/app_info/android/signatures/info.rb +158 -0
- data/lib/app_info/android/signatures/v1.rb +63 -0
- data/lib/app_info/android/signatures/v2.rb +121 -0
- data/lib/app_info/android/signatures/v3.rb +131 -0
- data/lib/app_info/android/signatures/v4.rb +18 -0
- data/lib/app_info/android.rb +181 -0
- data/lib/app_info/apk.rb +77 -112
- data/lib/app_info/apple.rb +192 -0
- data/lib/app_info/certificate.rb +176 -0
- data/lib/app_info/const.rb +76 -0
- data/lib/app_info/core_ext/object/try.rb +3 -1
- data/lib/app_info/core_ext/string/inflector.rb +2 -0
- data/lib/app_info/dsym/debug_info.rb +81 -0
- data/lib/app_info/dsym/macho.rb +62 -0
- data/lib/app_info/dsym.rb +35 -135
- data/lib/app_info/error.rb +3 -1
- data/lib/app_info/file.rb +49 -0
- data/lib/app_info/helper/archive.rb +37 -0
- data/lib/app_info/helper/file_size.rb +25 -0
- data/lib/app_info/helper/generate_class.rb +29 -0
- data/lib/app_info/helper/protobuf.rb +12 -0
- data/lib/app_info/helper/signatures.rb +229 -0
- data/lib/app_info/helper.rb +5 -128
- data/lib/app_info/info_plist.rb +66 -29
- data/lib/app_info/ipa/framework.rb +4 -4
- data/lib/app_info/ipa.rb +61 -135
- data/lib/app_info/macos.rb +54 -102
- data/lib/app_info/mobile_provision.rb +66 -48
- data/lib/app_info/pe.rb +322 -0
- data/lib/app_info/png_uncrush.rb +25 -5
- data/lib/app_info/proguard.rb +39 -22
- data/lib/app_info/protobuf/manifest.rb +22 -11
- data/lib/app_info/protobuf/models/Configuration_pb.rb +1 -0
- data/lib/app_info/protobuf/models/README.md +8 -1
- data/lib/app_info/protobuf/models/Resources.proto +51 -0
- data/lib/app_info/protobuf/models/Resources_pb.rb +42 -0
- data/lib/app_info/protobuf/resources.rb +5 -5
- data/lib/app_info/version.rb +1 -1
- data/lib/app_info.rb +93 -43
- metadata +57 -37
data/lib/app_info/macos.rb
CHANGED
@@ -7,63 +7,42 @@ require 'cfpropertylist'
|
|
7
7
|
|
8
8
|
module AppInfo
|
9
9
|
# MacOS App parser
|
10
|
-
class Macos
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
#
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
def_delegators :mobileprovision, :team_name, :team_identifier,
|
42
|
-
:profile_name, :expired_date
|
43
|
-
|
44
|
-
def distribution_name
|
45
|
-
"#{profile_name} - #{team_name}" if profile_name && team_name
|
46
|
-
end
|
47
|
-
|
48
|
-
def release_type
|
49
|
-
if stored?
|
50
|
-
ExportType::APPSTORE
|
51
|
-
elsif mobileprovision?
|
52
|
-
ExportType::RELEASE
|
53
|
-
else
|
54
|
-
ExportType::DEBUG
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def stored?
|
59
|
-
File.exist?(store_path)
|
60
|
-
end
|
61
|
-
|
10
|
+
class Macos < Apple
|
11
|
+
# @!method min_sdk_version
|
12
|
+
# @see InfoPlist#min_sdk_version
|
13
|
+
def_delegators :info, :min_system_version
|
14
|
+
|
15
|
+
# Full icons metadata
|
16
|
+
# @param [Boolean] convert Convert .icons to .png format
|
17
|
+
# @example uncovert .icons
|
18
|
+
# macos.icons
|
19
|
+
# # => [
|
20
|
+
# # {
|
21
|
+
# # name: 'icon.icns',
|
22
|
+
# # file: '/path/to/icon.icns',
|
23
|
+
# # }
|
24
|
+
# # ]
|
25
|
+
#
|
26
|
+
# @example coverted .icons
|
27
|
+
# macos.icons(convert: true)
|
28
|
+
# # => [
|
29
|
+
# # {
|
30
|
+
# # name: 'converted_icon_32x32.png',
|
31
|
+
# # file: '/path/to/converted_icon_32x32.png',
|
32
|
+
# # dimensions: [32, 32]
|
33
|
+
# # },
|
34
|
+
# # {
|
35
|
+
# # name: 'converted_icon_120x120.png',
|
36
|
+
# # file: '/path/to/converted_icon_120x120.png',
|
37
|
+
# # dimensions: [120, 120]
|
38
|
+
# # },
|
39
|
+
# # ]
|
40
|
+
# @return [Array<Hash{Symbol => String, Array<Integer>}>] icons paths of icons
|
62
41
|
def icons(convert: true)
|
63
42
|
return unless icon_file
|
64
43
|
|
65
44
|
data = {
|
66
|
-
name: File.basename(icon_file),
|
45
|
+
name: ::File.basename(icon_file),
|
67
46
|
file: icon_file
|
68
47
|
}
|
69
48
|
|
@@ -71,63 +50,40 @@ module AppInfo
|
|
71
50
|
data
|
72
51
|
end
|
73
52
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
file = MachO.open(binary_path)
|
78
|
-
case file
|
79
|
-
when MachO::MachOFile
|
80
|
-
[file.cpusubtype]
|
81
|
-
else
|
82
|
-
file.machos.each_with_object([]) do |arch, obj|
|
83
|
-
obj << arch.cpusubtype
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
alias architectures archs
|
88
|
-
|
89
|
-
def hide_developer_certificates
|
90
|
-
mobileprovision.delete('DeveloperCertificates') if mobileprovision?
|
91
|
-
end
|
92
|
-
|
93
|
-
def mobileprovision
|
94
|
-
return unless mobileprovision?
|
95
|
-
|
96
|
-
@mobileprovision ||= MobileProvision.new(mobileprovision_path)
|
97
|
-
end
|
98
|
-
|
99
|
-
def mobileprovision?
|
100
|
-
File.exist?(mobileprovision_path)
|
53
|
+
# @return [Boolean]
|
54
|
+
def stored?
|
55
|
+
::File.exist?(store_path)
|
101
56
|
end
|
102
57
|
|
58
|
+
# @return [String]
|
103
59
|
def mobileprovision_path
|
104
|
-
@mobileprovision_path ||= File.join(app_path, 'Contents', 'embedded.provisionprofile')
|
60
|
+
@mobileprovision_path ||= ::File.join(app_path, 'Contents', 'embedded.provisionprofile')
|
105
61
|
end
|
106
62
|
|
63
|
+
# @return [String]
|
107
64
|
def store_path
|
108
|
-
@store_path ||= File.join(app_path, 'Contents', '_MASReceipt', 'receipt')
|
65
|
+
@store_path ||= ::File.join(app_path, 'Contents', '_MASReceipt', 'receipt')
|
109
66
|
end
|
110
67
|
|
68
|
+
# @return [String]
|
111
69
|
def binary_path
|
112
70
|
return @binary_path if @binary_path
|
113
71
|
|
114
|
-
base_path = File.join(app_path, 'Contents', 'MacOS')
|
72
|
+
base_path = ::File.join(app_path, 'Contents', 'MacOS')
|
115
73
|
binary = info['CFBundleExecutable']
|
116
|
-
return File.join(base_path, binary) if binary
|
74
|
+
return ::File.join(base_path, binary) if binary
|
117
75
|
|
118
|
-
@binary_path ||= Dir.glob(File.join(base_path, '*')).first
|
119
|
-
end
|
120
|
-
|
121
|
-
def info
|
122
|
-
@info ||= InfoPlist.new(info_path)
|
76
|
+
@binary_path ||= Dir.glob(::File.join(base_path, '*')).first
|
123
77
|
end
|
124
78
|
|
79
|
+
# @return [String]
|
125
80
|
def info_path
|
126
|
-
@info_path ||= File.join(app_path, 'Contents', 'Info.plist')
|
81
|
+
@info_path ||= ::File.join(app_path, 'Contents', 'Info.plist')
|
127
82
|
end
|
128
83
|
|
84
|
+
# @return [String]
|
129
85
|
def app_path
|
130
|
-
@app_path ||= Dir.glob(File.join(contents, '*.app')).first
|
86
|
+
@app_path ||= Dir.glob(::File.join(contents, '*.app')).first
|
131
87
|
end
|
132
88
|
|
133
89
|
def clear!
|
@@ -137,16 +93,12 @@ module AppInfo
|
|
137
93
|
|
138
94
|
@contents = nil
|
139
95
|
@app_path = nil
|
140
|
-
@
|
96
|
+
@binary_path = nil
|
141
97
|
@info_path = nil
|
142
98
|
@info = nil
|
143
99
|
@icons = nil
|
144
100
|
end
|
145
101
|
|
146
|
-
def contents
|
147
|
-
@contents ||= unarchive(@file, path: 'macos')
|
148
|
-
end
|
149
|
-
|
150
102
|
private
|
151
103
|
|
152
104
|
def icon_file
|
@@ -155,8 +107,8 @@ module AppInfo
|
|
155
107
|
info.icons.each do |key|
|
156
108
|
next unless value = info[key]
|
157
109
|
|
158
|
-
file = File.join(app_path, 'Contents', 'Resources', "#{value}.icns")
|
159
|
-
next unless File.file?(file)
|
110
|
+
file = ::File.join(app_path, 'Contents', 'Resources', "#{value}.icns")
|
111
|
+
next unless ::File.file?(file)
|
160
112
|
|
161
113
|
return @icon_file = file
|
162
114
|
end
|
@@ -173,14 +125,14 @@ module AppInfo
|
|
173
125
|
file = data[:file]
|
174
126
|
reader = Icns::Reader.new(file)
|
175
127
|
Icns::SIZE_TO_TYPE.each do |size, _|
|
176
|
-
dest_filename = "#{File.basename(file, '.icns')}_#{size}x#{size}.png"
|
177
|
-
dest_file = tempdir(File.join(File.dirname(file), dest_filename), prefix: 'converted')
|
128
|
+
dest_filename = "#{::File.basename(file, '.icns')}_#{size}x#{size}.png"
|
129
|
+
dest_file = tempdir(::File.join(::File.dirname(file), dest_filename), prefix: 'converted')
|
178
130
|
next unless icon_data = reader.image(size: size)
|
179
131
|
|
180
|
-
File.write(dest_file, icon_data, encoding: Encoding::BINARY)
|
132
|
+
::File.write(dest_file, icon_data, encoding: Encoding::BINARY)
|
181
133
|
|
182
134
|
data[:sets] << {
|
183
|
-
name: File.basename(dest_filename),
|
135
|
+
name: ::File.basename(dest_filename),
|
184
136
|
file: dest_file,
|
185
137
|
dimensions: ImageSize.path(dest_file).size
|
186
138
|
}
|
@@ -4,20 +4,37 @@ require 'openssl'
|
|
4
4
|
require 'cfpropertylist'
|
5
5
|
|
6
6
|
module AppInfo
|
7
|
-
#
|
8
|
-
|
9
|
-
|
10
|
-
|
7
|
+
# Apple code signing: provisioning profile parser
|
8
|
+
# @see https://developer.apple.com/documentation/technotes/tn3125-inside-code-signing-provisioning-profiles
|
9
|
+
class MobileProvision < File
|
10
|
+
# @return [Symbol] {Manufacturer}
|
11
|
+
def manufacturer
|
12
|
+
Manufacturer::APPLE
|
11
13
|
end
|
12
14
|
|
15
|
+
# @return [Symbol] {Platform}
|
16
|
+
def platform
|
17
|
+
case platforms[0]
|
18
|
+
when :macos
|
19
|
+
Platform::MACOS
|
20
|
+
when :ios
|
21
|
+
Platform::IOS
|
22
|
+
else
|
23
|
+
raise NotImplementedError, "Unkonwn platform: #{platforms[0]}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# @return [String, nil]
|
13
28
|
def name
|
14
29
|
mobileprovision.try(:[], 'Name')
|
15
30
|
end
|
16
31
|
|
32
|
+
# @return [String, nil]
|
17
33
|
def app_name
|
18
34
|
mobileprovision.try(:[], 'AppIDName')
|
19
35
|
end
|
20
36
|
|
37
|
+
# @return [Symbol, nil]
|
21
38
|
def type
|
22
39
|
return :development if development?
|
23
40
|
return :adhoc if adhoc?
|
@@ -25,6 +42,7 @@ module AppInfo
|
|
25
42
|
return :enterprise if enterprise?
|
26
43
|
end
|
27
44
|
|
45
|
+
# @return [Array<Symbol>]
|
28
46
|
def platforms
|
29
47
|
return unless platforms = mobileprovision.try(:[], 'Platform')
|
30
48
|
|
@@ -34,83 +52,100 @@ module AppInfo
|
|
34
52
|
end
|
35
53
|
end
|
36
54
|
|
37
|
-
|
38
|
-
platforms[0]
|
39
|
-
end
|
40
|
-
|
55
|
+
# @return [Array<String>, nil]
|
41
56
|
def devices
|
42
57
|
mobileprovision.try(:[], 'ProvisionedDevices')
|
43
58
|
end
|
44
59
|
|
60
|
+
# @return [String, nil]
|
45
61
|
def team_identifier
|
46
62
|
mobileprovision.try(:[], 'TeamIdentifier')
|
47
63
|
end
|
48
64
|
|
65
|
+
# @return [String, nil]
|
49
66
|
def team_name
|
50
67
|
mobileprovision.try(:[], 'TeamName')
|
51
68
|
end
|
52
69
|
|
70
|
+
# @return [String, nil]
|
53
71
|
def profile_name
|
54
72
|
mobileprovision.try(:[], 'Name')
|
55
73
|
end
|
56
74
|
|
75
|
+
# @return [String, nil]
|
57
76
|
def created_date
|
58
77
|
mobileprovision.try(:[], 'CreationDate')
|
59
78
|
end
|
60
79
|
|
80
|
+
# @return [String, nil]
|
61
81
|
def expired_date
|
62
82
|
mobileprovision.try(:[], 'ExpirationDate')
|
63
83
|
end
|
64
84
|
|
85
|
+
# @return [Array<String>, nil]
|
65
86
|
def entitlements
|
66
87
|
mobileprovision.try(:[], 'Entitlements')
|
67
88
|
end
|
68
89
|
|
90
|
+
# return developer certificates.
|
91
|
+
#
|
92
|
+
# @deprecated Use {#certificates} instead of this method.
|
69
93
|
def developer_certs
|
94
|
+
certificates
|
95
|
+
end
|
96
|
+
|
97
|
+
# return developer certificates.
|
98
|
+
#
|
99
|
+
# @return [Array<Certificate>]
|
100
|
+
def certificates
|
70
101
|
certs = mobileprovision.try(:[], 'DeveloperCertificates')
|
71
102
|
return if certs.empty?
|
72
103
|
|
73
|
-
certs.each_with_object([]) do |
|
74
|
-
obj <<
|
104
|
+
certs.each_with_object([]) do |cert_data, obj|
|
105
|
+
obj << Certificate.parse(cert_data)
|
75
106
|
end
|
76
107
|
end
|
77
108
|
|
78
109
|
# Detect is development type of mobileprovision
|
79
110
|
#
|
80
|
-
#
|
111
|
+
# @see https://stackoverflow.com/questions/1003066/what-does-get-task-allow-do-in-xcode
|
112
|
+
# @return [Boolea]
|
81
113
|
def development?
|
82
|
-
case platform
|
83
|
-
when
|
114
|
+
case platform
|
115
|
+
when Platform::IOS
|
84
116
|
entitlements['get-task-allow'] == true
|
85
|
-
when
|
117
|
+
when Platform::MACOS
|
86
118
|
!devices.nil?
|
87
119
|
else
|
88
|
-
raise
|
120
|
+
raise NotImplementedError, "Unknown platform: #{platform}"
|
89
121
|
end
|
90
122
|
end
|
91
123
|
|
92
124
|
# Detect app store type
|
93
125
|
#
|
94
|
-
#
|
126
|
+
# @see https://developer.apple.com/library/archive/qa/qa1830/_index.html
|
127
|
+
# @return [Boolea]
|
95
128
|
def appstore?
|
96
|
-
case platform
|
97
|
-
when
|
129
|
+
case platform
|
130
|
+
when Platform::IOS
|
98
131
|
!development? && entitlements.key?('beta-reports-active')
|
99
|
-
when
|
132
|
+
when Platform::MACOS
|
100
133
|
!development?
|
101
134
|
else
|
102
|
-
raise
|
135
|
+
raise NotImplementedError, "Unknown platform: #{platform}"
|
103
136
|
end
|
104
137
|
end
|
105
138
|
|
139
|
+
# @return [Boolea]
|
106
140
|
def adhoc?
|
107
|
-
return false if platform ==
|
141
|
+
return false if platform == Platform::MACOS # macOS no need adhoc
|
108
142
|
|
109
143
|
!development? && !devices.nil?
|
110
144
|
end
|
111
145
|
|
146
|
+
# @return [Boolea]
|
112
147
|
def enterprise?
|
113
|
-
return false if platform ==
|
148
|
+
return false if platform == Platform::MACOS # macOS no need adhoc
|
114
149
|
|
115
150
|
!development? && !adhoc? && !appstore?
|
116
151
|
end
|
@@ -118,7 +153,8 @@ module AppInfo
|
|
118
153
|
|
119
154
|
# Enabled Capabilites
|
120
155
|
#
|
121
|
-
#
|
156
|
+
# @see https://developer.apple.com/support/app-capabilities/
|
157
|
+
# @return [Array<String>]
|
122
158
|
def enabled_capabilities
|
123
159
|
capabilities = []
|
124
160
|
capabilities << 'In-App Purchase' << 'GameKit' if adhoc? || appstore?
|
@@ -142,10 +178,10 @@ module AppInfo
|
|
142
178
|
when 'com.apple.developer.networking.vpn.api'
|
143
179
|
capabilities << 'Personal VPN'
|
144
180
|
when 'com.apple.developer.healthkit',
|
145
|
-
|
181
|
+
'com.apple.developer.healthkit.access'
|
146
182
|
capabilities << 'HealthKit' unless capabilities.include?('HealthKit')
|
147
183
|
when 'com.apple.developer.icloud-services',
|
148
|
-
|
184
|
+
'com.apple.developer.icloud-container-identifiers'
|
149
185
|
capabilities << 'iCloud' unless capabilities.include?('iCloud')
|
150
186
|
when 'com.apple.developer.in-app-payments'
|
151
187
|
capabilities << 'Apple Pay'
|
@@ -192,18 +228,21 @@ module AppInfo
|
|
192
228
|
capabilities
|
193
229
|
end
|
194
230
|
|
231
|
+
# @return [String, nil]
|
195
232
|
def [](key)
|
196
233
|
mobileprovision.try(:[], key.to_s)
|
197
234
|
end
|
198
235
|
|
236
|
+
# @return [Boolea]
|
199
237
|
def empty?
|
200
238
|
mobileprovision.nil?
|
201
239
|
end
|
202
240
|
|
241
|
+
# @return [CFPropertyList]
|
203
242
|
def mobileprovision
|
204
|
-
return @mobileprovision = nil unless File.exist?(@
|
243
|
+
return @mobileprovision = nil unless ::File.exist?(@file)
|
205
244
|
|
206
|
-
data = File.read(@
|
245
|
+
data = ::File.read(@file)
|
207
246
|
data = strip_plist_wrapper(data) unless bplist?(data)
|
208
247
|
list = CFPropertyList::List.new(data: data).value
|
209
248
|
@mobileprovision = CFPropertyList.native_types(list)
|
@@ -235,26 +274,5 @@ module AppInfo
|
|
235
274
|
end_point = raw.index(end_tag) + end_tag.size - 1
|
236
275
|
raw[start_point..end_point]
|
237
276
|
end
|
238
|
-
|
239
|
-
# Developer Certificate
|
240
|
-
class DeveloperCertificate
|
241
|
-
attr_reader :raw
|
242
|
-
|
243
|
-
def initialize(data)
|
244
|
-
@raw = OpenSSL::X509::Certificate.new(data)
|
245
|
-
end
|
246
|
-
|
247
|
-
def name
|
248
|
-
@raw.subject.to_a.find { |name, _, _| name == 'CN' }[1].force_encoding('UTF-8')
|
249
|
-
end
|
250
|
-
|
251
|
-
def created_date
|
252
|
-
@raw.not_after
|
253
|
-
end
|
254
|
-
|
255
|
-
def expired_date
|
256
|
-
@raw.not_before
|
257
|
-
end
|
258
|
-
end
|
259
277
|
end
|
260
278
|
end
|