app-info 2.8.5 → 3.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/dependabot.yml +12 -7
- data/.github/workflows/ci.yml +3 -1
- data/.rubocop.yml +31 -11
- data/CHANGELOG.md +22 -0
- data/Gemfile +7 -1
- data/README.md +64 -9
- data/Rakefile +11 -0
- data/app_info.gemspec +12 -3
- data/lib/app_info/aab.rb +58 -39
- data/lib/app_info/android/signature.rb +114 -0
- data/lib/app_info/android/signatures/base.rb +49 -0
- data/lib/app_info/android/signatures/info.rb +152 -0
- data/lib/app_info/android/signatures/v1.rb +59 -0
- data/lib/app_info/android/signatures/v2.rb +117 -0
- data/lib/app_info/android/signatures/v3.rb +127 -0
- data/lib/app_info/android/signatures/v4.rb +14 -0
- data/lib/app_info/apk.rb +43 -46
- data/lib/app_info/certificate.rb +181 -0
- data/lib/app_info/const.rb +41 -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 +72 -0
- data/lib/app_info/dsym/macho.rb +55 -0
- data/lib/app_info/dsym.rb +27 -134
- data/lib/app_info/error.rb +7 -1
- data/lib/app_info/file.rb +23 -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 -126
- data/lib/app_info/info_plist.rb +14 -6
- data/lib/app_info/ipa/framework.rb +4 -4
- data/lib/app_info/ipa.rb +41 -36
- data/lib/app_info/macos.rb +34 -26
- data/lib/app_info/mobile_provision.rb +19 -30
- data/lib/app_info/pe.rb +226 -0
- data/lib/app_info/png_uncrush.rb +5 -4
- data/lib/app_info/proguard.rb +11 -17
- data/lib/app_info/protobuf/manifest.rb +1 -2
- data/lib/app_info/protobuf/models/Configuration_pb.rb +1 -0
- data/lib/app_info/protobuf/models/README.md +7 -0
- data/lib/app_info/protobuf/models/Resources_pb.rb +2 -0
- data/lib/app_info/protobuf/resources.rb +5 -5
- data/lib/app_info/version.rb +1 -1
- data/lib/app_info.rb +88 -45
- metadata +46 -35
data/lib/app_info/macos.rb
CHANGED
@@ -7,7 +7,7 @@ require 'cfpropertylist'
|
|
7
7
|
|
8
8
|
module AppInfo
|
9
9
|
# MacOS App parser
|
10
|
-
class Macos
|
10
|
+
class Macos < File
|
11
11
|
include Helper::HumanFileSize
|
12
12
|
include Helper::Archive
|
13
13
|
extend Forwardable
|
@@ -21,18 +21,26 @@ module AppInfo
|
|
21
21
|
APPSTORE = 'AppStore'
|
22
22
|
end
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
24
|
+
# return file size
|
25
|
+
# @example Read file size in integer
|
26
|
+
# aab.size # => 3618865
|
27
|
+
#
|
28
|
+
# @example Read file size in human readabale
|
29
|
+
# aab.size(human_size: true) # => '3.45 MB'
|
30
|
+
#
|
31
|
+
# @param [Boolean] human_size Convert integer value to human readable.
|
32
|
+
# @return [Integer, String]
|
28
33
|
def size(human_size: false)
|
29
34
|
file_to_human_size(@file, human_size: human_size)
|
30
35
|
end
|
31
36
|
|
32
|
-
def
|
37
|
+
def file_type
|
38
|
+
Format::MACOS
|
39
|
+
end
|
40
|
+
|
41
|
+
def platform
|
33
42
|
Platform::MACOS
|
34
43
|
end
|
35
|
-
alias file_type os
|
36
44
|
|
37
45
|
def_delegators :info, :macos?, :iphone?, :ipad?, :universal?, :build_version, :name,
|
38
46
|
:release_version, :identifier, :bundle_id, :display_name,
|
@@ -56,14 +64,14 @@ module AppInfo
|
|
56
64
|
end
|
57
65
|
|
58
66
|
def stored?
|
59
|
-
File.exist?(store_path)
|
67
|
+
::File.exist?(store_path)
|
60
68
|
end
|
61
69
|
|
62
70
|
def icons(convert: true)
|
63
71
|
return unless icon_file
|
64
72
|
|
65
73
|
data = {
|
66
|
-
name: File.basename(icon_file),
|
74
|
+
name: ::File.basename(icon_file),
|
67
75
|
file: icon_file
|
68
76
|
}
|
69
77
|
|
@@ -72,7 +80,7 @@ module AppInfo
|
|
72
80
|
end
|
73
81
|
|
74
82
|
def archs
|
75
|
-
return unless File.exist?(binary_path)
|
83
|
+
return unless ::File.exist?(binary_path)
|
76
84
|
|
77
85
|
file = MachO.open(binary_path)
|
78
86
|
case file
|
@@ -97,25 +105,25 @@ module AppInfo
|
|
97
105
|
end
|
98
106
|
|
99
107
|
def mobileprovision?
|
100
|
-
File.exist?(mobileprovision_path)
|
108
|
+
::File.exist?(mobileprovision_path)
|
101
109
|
end
|
102
110
|
|
103
111
|
def mobileprovision_path
|
104
|
-
@mobileprovision_path ||= File.join(app_path, 'Contents', 'embedded.provisionprofile')
|
112
|
+
@mobileprovision_path ||= ::File.join(app_path, 'Contents', 'embedded.provisionprofile')
|
105
113
|
end
|
106
114
|
|
107
115
|
def store_path
|
108
|
-
@store_path ||= File.join(app_path, 'Contents', '_MASReceipt', 'receipt')
|
116
|
+
@store_path ||= ::File.join(app_path, 'Contents', '_MASReceipt', 'receipt')
|
109
117
|
end
|
110
118
|
|
111
119
|
def binary_path
|
112
120
|
return @binary_path if @binary_path
|
113
121
|
|
114
|
-
base_path = File.join(app_path, 'Contents', 'MacOS')
|
122
|
+
base_path = ::File.join(app_path, 'Contents', 'MacOS')
|
115
123
|
binary = info['CFBundleExecutable']
|
116
|
-
return File.join(base_path, binary) if binary
|
124
|
+
return ::File.join(base_path, binary) if binary
|
117
125
|
|
118
|
-
@binary_path ||= Dir.glob(File.join(base_path, '*')).first
|
126
|
+
@binary_path ||= Dir.glob(::File.join(base_path, '*')).first
|
119
127
|
end
|
120
128
|
|
121
129
|
def info
|
@@ -123,11 +131,11 @@ module AppInfo
|
|
123
131
|
end
|
124
132
|
|
125
133
|
def info_path
|
126
|
-
@info_path ||= File.join(app_path, 'Contents', 'Info.plist')
|
134
|
+
@info_path ||= ::File.join(app_path, 'Contents', 'Info.plist')
|
127
135
|
end
|
128
136
|
|
129
137
|
def app_path
|
130
|
-
@app_path ||= Dir.glob(File.join(contents, '*.app')).first
|
138
|
+
@app_path ||= Dir.glob(::File.join(contents, '*.app')).first
|
131
139
|
end
|
132
140
|
|
133
141
|
def clear!
|
@@ -137,14 +145,14 @@ module AppInfo
|
|
137
145
|
|
138
146
|
@contents = nil
|
139
147
|
@app_path = nil
|
140
|
-
@
|
148
|
+
@binary_path = nil
|
141
149
|
@info_path = nil
|
142
150
|
@info = nil
|
143
151
|
@icons = nil
|
144
152
|
end
|
145
153
|
|
146
154
|
def contents
|
147
|
-
@contents ||= unarchive(@file,
|
155
|
+
@contents ||= unarchive(@file, prefix: 'macos')
|
148
156
|
end
|
149
157
|
|
150
158
|
private
|
@@ -155,8 +163,8 @@ module AppInfo
|
|
155
163
|
info.icons.each do |key|
|
156
164
|
next unless value = info[key]
|
157
165
|
|
158
|
-
file = File.join(app_path, 'Contents', 'Resources', "#{value}.icns")
|
159
|
-
next unless File.file?(file)
|
166
|
+
file = ::File.join(app_path, 'Contents', 'Resources', "#{value}.icns")
|
167
|
+
next unless ::File.file?(file)
|
160
168
|
|
161
169
|
return @icon_file = file
|
162
170
|
end
|
@@ -173,14 +181,14 @@ module AppInfo
|
|
173
181
|
file = data[:file]
|
174
182
|
reader = Icns::Reader.new(file)
|
175
183
|
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')
|
184
|
+
dest_filename = "#{::File.basename(file, '.icns')}_#{size}x#{size}.png"
|
185
|
+
dest_file = tempdir(::File.join(::File.dirname(file), dest_filename), prefix: 'converted')
|
178
186
|
next unless icon_data = reader.image(size: size)
|
179
187
|
|
180
|
-
File.write(dest_file, icon_data, encoding: Encoding::BINARY)
|
188
|
+
::File.write(dest_file, icon_data, encoding: Encoding::BINARY)
|
181
189
|
|
182
190
|
data[:sets] << {
|
183
|
-
name: File.basename(dest_filename),
|
191
|
+
name: ::File.basename(dest_filename),
|
184
192
|
file: dest_file,
|
185
193
|
dimensions: ImageSize.path(dest_file).size
|
186
194
|
}
|
@@ -5,9 +5,9 @@ require 'cfpropertylist'
|
|
5
5
|
|
6
6
|
module AppInfo
|
7
7
|
# .mobileprovision file parser
|
8
|
-
class MobileProvision
|
9
|
-
def
|
10
|
-
|
8
|
+
class MobileProvision < File
|
9
|
+
def file_type
|
10
|
+
Format::MOBILEPROVISION
|
11
11
|
end
|
12
12
|
|
13
13
|
def name
|
@@ -66,12 +66,22 @@ module AppInfo
|
|
66
66
|
mobileprovision.try(:[], 'Entitlements')
|
67
67
|
end
|
68
68
|
|
69
|
+
# return developer certificates.
|
70
|
+
#
|
71
|
+
# @deprecated Use {#certificates} instead of this method.
|
69
72
|
def developer_certs
|
73
|
+
certificates
|
74
|
+
end
|
75
|
+
|
76
|
+
# return developer certificates.
|
77
|
+
#
|
78
|
+
# @return [Array<Certificate>]
|
79
|
+
def certificates
|
70
80
|
certs = mobileprovision.try(:[], 'DeveloperCertificates')
|
71
81
|
return if certs.empty?
|
72
82
|
|
73
|
-
certs.each_with_object([]) do |
|
74
|
-
obj <<
|
83
|
+
certs.each_with_object([]) do |cert_data, obj|
|
84
|
+
obj << Certificate.parse(cert_data)
|
75
85
|
end
|
76
86
|
end
|
77
87
|
|
@@ -142,10 +152,10 @@ module AppInfo
|
|
142
152
|
when 'com.apple.developer.networking.vpn.api'
|
143
153
|
capabilities << 'Personal VPN'
|
144
154
|
when 'com.apple.developer.healthkit',
|
145
|
-
|
155
|
+
'com.apple.developer.healthkit.access'
|
146
156
|
capabilities << 'HealthKit' unless capabilities.include?('HealthKit')
|
147
157
|
when 'com.apple.developer.icloud-services',
|
148
|
-
|
158
|
+
'com.apple.developer.icloud-container-identifiers'
|
149
159
|
capabilities << 'iCloud' unless capabilities.include?('iCloud')
|
150
160
|
when 'com.apple.developer.in-app-payments'
|
151
161
|
capabilities << 'Apple Pay'
|
@@ -201,9 +211,9 @@ module AppInfo
|
|
201
211
|
end
|
202
212
|
|
203
213
|
def mobileprovision
|
204
|
-
return @mobileprovision = nil unless File.exist?(@
|
214
|
+
return @mobileprovision = nil unless ::File.exist?(@file)
|
205
215
|
|
206
|
-
data = File.read(@
|
216
|
+
data = ::File.read(@file)
|
207
217
|
data = strip_plist_wrapper(data) unless bplist?(data)
|
208
218
|
list = CFPropertyList::List.new(data: data).value
|
209
219
|
@mobileprovision = CFPropertyList.native_types(list)
|
@@ -235,26 +245,5 @@ module AppInfo
|
|
235
245
|
end_point = raw.index(end_tag) + end_tag.size - 1
|
236
246
|
raw[start_point..end_point]
|
237
247
|
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
248
|
end
|
260
249
|
end
|
data/lib/app_info/pe.rb
ADDED
@@ -0,0 +1,226 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'pedump'
|
4
|
+
require 'fileutils'
|
5
|
+
require 'forwardable'
|
6
|
+
|
7
|
+
module AppInfo
|
8
|
+
# Windows PE parser
|
9
|
+
#
|
10
|
+
# @see https://learn.microsoft.com/zh-cn/windows/win32/debug/pe-format Microsoft PE Format
|
11
|
+
class PE < File
|
12
|
+
include Helper::HumanFileSize
|
13
|
+
include Helper::Archive
|
14
|
+
extend Forwardable
|
15
|
+
|
16
|
+
ARCH = {
|
17
|
+
0x014c => 'x86',
|
18
|
+
0x0200 => 'Intel Itanium',
|
19
|
+
0x8664 => 'x64',
|
20
|
+
0x1c0 => 'arm',
|
21
|
+
0xaa64 => 'arm64',
|
22
|
+
0x5032 => 'RISC-v 32',
|
23
|
+
0x5064 => 'RISC-v 64',
|
24
|
+
0x5128 => 'RISC-v 128'
|
25
|
+
}.freeze
|
26
|
+
|
27
|
+
def file_type
|
28
|
+
Format::PE
|
29
|
+
end
|
30
|
+
|
31
|
+
def platform
|
32
|
+
Platform::WINDOWS
|
33
|
+
end
|
34
|
+
|
35
|
+
# return file size
|
36
|
+
# @example Read file size in integer
|
37
|
+
# aab.size # => 3618865
|
38
|
+
#
|
39
|
+
# @example Read file size in human readabale
|
40
|
+
# aab.size(human_size: true) # => '3.45 MB'
|
41
|
+
#
|
42
|
+
# @param [Boolean] human_size Convert integer value to human readable.
|
43
|
+
# @return [Integer, String]
|
44
|
+
def size(human_size: false)
|
45
|
+
file_to_human_size(@file, human_size: human_size)
|
46
|
+
end
|
47
|
+
|
48
|
+
def binary_size(human_size: false)
|
49
|
+
file_to_human_size(binary_file, human_size: human_size)
|
50
|
+
end
|
51
|
+
|
52
|
+
def_delegators :version_info, :product_name, :product_version, :company_name, :assembly_version
|
53
|
+
|
54
|
+
alias name product_name
|
55
|
+
alias release_version product_version
|
56
|
+
alias build_version assembly_version
|
57
|
+
|
58
|
+
def archs
|
59
|
+
ARCH[image_file_header.Machine] || 'unknown'
|
60
|
+
end
|
61
|
+
alias architectures archs
|
62
|
+
|
63
|
+
def imports
|
64
|
+
@imports ||= pe.imports.each_with_object({}) do |import, obj|
|
65
|
+
obj[import.module_name] = import.first_thunk.map(&:name).compact
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def icons
|
70
|
+
@icons ||= lambda {
|
71
|
+
# Fetch the largest size icon
|
72
|
+
files = []
|
73
|
+
pe.resources&.find_all do |res|
|
74
|
+
next unless res.type == 'ICON'
|
75
|
+
|
76
|
+
filename = "#{::File.basename(file, '.*')}-#{res.type}-#{res.id}.bmp"
|
77
|
+
icon_file = tempdir(filename, prefix: 'pe', system: true)
|
78
|
+
mask_icon_file = icon_file.sub('.bmp', '.mask.bmp')
|
79
|
+
|
80
|
+
begin
|
81
|
+
::File.open(icon_file, 'wb') do |f|
|
82
|
+
f << res.restore_bitmap(io)
|
83
|
+
end
|
84
|
+
|
85
|
+
if res.bitmap_mask(io)
|
86
|
+
mask_icon_file = icon_file.sub('.bmp', '.mask.bmp')
|
87
|
+
::File.open(mask_icon_file, 'wb') do |f|
|
88
|
+
f << res.bitmap_mask(io)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
rescue StandardError => e
|
92
|
+
# ignore pedump throws any exception.
|
93
|
+
raise e unless e.backtrace.first.include?('pedump')
|
94
|
+
|
95
|
+
FileUtils.rm_f(icon_file)
|
96
|
+
ensure
|
97
|
+
next unless ::File.exist?(icon_file)
|
98
|
+
|
99
|
+
mask_file = ::File.exist?(mask_icon_file) ? mask_icon_file : nil
|
100
|
+
files << icon_metadata(icon_file, mask_file: mask_file)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
files
|
105
|
+
}.call
|
106
|
+
end
|
107
|
+
|
108
|
+
def pe
|
109
|
+
@pe ||= lambda {
|
110
|
+
pe = PEdump.new(io)
|
111
|
+
pe.logger.level = Logger::FATAL # ignore :warn logger output
|
112
|
+
pe
|
113
|
+
}.call
|
114
|
+
end
|
115
|
+
|
116
|
+
def version_info
|
117
|
+
@version_info ||= VersionInfo.new(pe.version_info)
|
118
|
+
end
|
119
|
+
|
120
|
+
def clear!
|
121
|
+
@io = nil
|
122
|
+
@pe = nil
|
123
|
+
@icons = nil
|
124
|
+
@imports = nil
|
125
|
+
end
|
126
|
+
|
127
|
+
def binary_file
|
128
|
+
@binary_file ||= lambda {
|
129
|
+
file_io = ::File.open(@file, 'rb')
|
130
|
+
return @file unless file_io.read(100) =~ AppInfo::ZIP_RETGEX
|
131
|
+
|
132
|
+
zip_file = Zip::File.open(@file)
|
133
|
+
zip_entry = zip_file.glob('*.exe').first
|
134
|
+
raise NotFoundWinBinraryError, 'Not found .exe file in archive file' if zip_entry.nil?
|
135
|
+
|
136
|
+
exe_file = tempdir(zip_entry.name, prefix: 'pe-exe', system: true)
|
137
|
+
zip_entry.extract(exe_file)
|
138
|
+
zip_file.close
|
139
|
+
|
140
|
+
return exe_file
|
141
|
+
}.call
|
142
|
+
end
|
143
|
+
|
144
|
+
private
|
145
|
+
|
146
|
+
def image_file_header
|
147
|
+
@image_file_header ||= pe.pe.image_file_header
|
148
|
+
end
|
149
|
+
|
150
|
+
def icon_metadata(file, mask_file: nil)
|
151
|
+
{
|
152
|
+
name: ::File.basename(file),
|
153
|
+
file: file,
|
154
|
+
mask: mask_file,
|
155
|
+
dimensions: ImageSize.path(file).size
|
156
|
+
}
|
157
|
+
end
|
158
|
+
|
159
|
+
def io
|
160
|
+
@io ||= ::File.open(binary_file, 'rb')
|
161
|
+
end
|
162
|
+
|
163
|
+
# VersionInfo class
|
164
|
+
#
|
165
|
+
# Ref: https://learn.microsoft.com/zh-cn/windows/win32/menurc/versioninfo-resource
|
166
|
+
class VersionInfo
|
167
|
+
def initialize(raw)
|
168
|
+
@raw = raw
|
169
|
+
end
|
170
|
+
|
171
|
+
def company_name
|
172
|
+
@company_name ||= value_of('CompanyName')
|
173
|
+
end
|
174
|
+
|
175
|
+
def product_name
|
176
|
+
@product_name ||= value_of('ProductName')
|
177
|
+
end
|
178
|
+
|
179
|
+
def product_version
|
180
|
+
@product_version ||= value_of('ProductVersion')
|
181
|
+
end
|
182
|
+
|
183
|
+
def assembly_version
|
184
|
+
@assembly_version ||= value_of('Assembly Version')
|
185
|
+
end
|
186
|
+
|
187
|
+
def file_version
|
188
|
+
@file_version ||= value_of('FileVersion')
|
189
|
+
end
|
190
|
+
|
191
|
+
def file_description
|
192
|
+
@file_description ||= value_of('FileDescription')
|
193
|
+
end
|
194
|
+
|
195
|
+
def copyright
|
196
|
+
@copyright ||= value_of('LegalCopyright')
|
197
|
+
end
|
198
|
+
|
199
|
+
private
|
200
|
+
|
201
|
+
def value_of(key)
|
202
|
+
info.each do |v|
|
203
|
+
return v[:Value] if v[:szKey] == key.to_s
|
204
|
+
end
|
205
|
+
|
206
|
+
nil
|
207
|
+
end
|
208
|
+
|
209
|
+
def info
|
210
|
+
return @info if @info
|
211
|
+
|
212
|
+
@raw.each do |item|
|
213
|
+
next unless item.is_a?(PEdump::VS_VERSIONINFO)
|
214
|
+
|
215
|
+
versions = item[:Children].select { |v| v.is_a?(PEdump::StringFileInfo) }
|
216
|
+
next if versions.empty?
|
217
|
+
|
218
|
+
@info = versions[0][:Children][0][:Children]
|
219
|
+
return @info
|
220
|
+
end
|
221
|
+
|
222
|
+
@info = []
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
data/lib/app_info/png_uncrush.rb
CHANGED
@@ -7,9 +7,10 @@ require 'zlib'
|
|
7
7
|
require 'stringio'
|
8
8
|
|
9
9
|
module AppInfo
|
10
|
+
# Decompress iOS Png image file.
|
11
|
+
# @see https://github.com/swcai/iphone-png-normalizer swcai/iphone-png-normalizer
|
12
|
+
# @author Wenwei Cai
|
10
13
|
class PngUncrush
|
11
|
-
class Error < StandardError; end
|
12
|
-
|
13
14
|
class FormatError < Error; end
|
14
15
|
|
15
16
|
class PngReader # :nodoc:
|
@@ -69,7 +70,7 @@ module AppInfo
|
|
69
70
|
end
|
70
71
|
|
71
72
|
def initialize(filename)
|
72
|
-
@io = PngReader.new(File.open(filename))
|
73
|
+
@io = PngReader.new(::File.open(filename))
|
73
74
|
raise FormatError, 'not a png file' unless @io.png?
|
74
75
|
end
|
75
76
|
|
@@ -125,7 +126,7 @@ module AppInfo
|
|
125
126
|
end
|
126
127
|
|
127
128
|
def write_file(path, content)
|
128
|
-
File.write(path, content, encoding: Encoding::BINARY)
|
129
|
+
::File.write(path, content, encoding: Encoding::BINARY)
|
129
130
|
true
|
130
131
|
end
|
131
132
|
|
data/lib/app_info/proguard.rb
CHANGED
@@ -5,37 +5,31 @@ require 'rexml/document'
|
|
5
5
|
|
6
6
|
module AppInfo
|
7
7
|
# Proguard parser
|
8
|
-
class Proguard
|
8
|
+
class Proguard < File
|
9
9
|
include Helper::Archive
|
10
10
|
|
11
11
|
NAMESPACE = UUIDTools::UUID.sha1_create(UUIDTools::UUID_DNS_NAMESPACE, 'icyleaf.com')
|
12
12
|
|
13
|
-
attr_reader :file
|
14
|
-
|
15
|
-
def initialize(file)
|
16
|
-
@file = file
|
17
|
-
end
|
18
|
-
|
19
13
|
def file_type
|
20
|
-
|
14
|
+
Format::PROGUARD
|
21
15
|
end
|
22
16
|
|
23
17
|
def uuid
|
24
18
|
# Similar to https://docs.sentry.io/workflow/debug-files/#proguard-uuids
|
25
|
-
UUIDTools::UUID.sha1_create(NAMESPACE, File.read(mapping_path)).to_s
|
19
|
+
UUIDTools::UUID.sha1_create(NAMESPACE, ::File.read(mapping_path)).to_s
|
26
20
|
end
|
27
21
|
alias debug_id uuid
|
28
22
|
|
29
23
|
def mapping?
|
30
|
-
File.exist?(mapping_path)
|
24
|
+
::File.exist?(mapping_path)
|
31
25
|
end
|
32
26
|
|
33
27
|
def manifest?
|
34
|
-
File.exist?(manifest_path)
|
28
|
+
::File.exist?(manifest_path)
|
35
29
|
end
|
36
30
|
|
37
31
|
def symbol?
|
38
|
-
File.exist?(symbol_path)
|
32
|
+
::File.exist?(symbol_path)
|
39
33
|
end
|
40
34
|
alias resource? symbol?
|
41
35
|
|
@@ -68,24 +62,24 @@ module AppInfo
|
|
68
62
|
def manifest
|
69
63
|
return unless manifest?
|
70
64
|
|
71
|
-
@manifest ||= REXML::Document.new(File.new(manifest_path))
|
65
|
+
@manifest ||= REXML::Document.new(::File.new(manifest_path))
|
72
66
|
end
|
73
67
|
|
74
68
|
def mapping_path
|
75
|
-
@mapping_path ||= Dir.glob(File.join(contents, '*mapping*.txt')).first
|
69
|
+
@mapping_path ||= Dir.glob(::File.join(contents, '*mapping*.txt')).first
|
76
70
|
end
|
77
71
|
|
78
72
|
def manifest_path
|
79
|
-
@manifest_path ||= File.join(contents, 'AndroidManifest.xml')
|
73
|
+
@manifest_path ||= ::File.join(contents, 'AndroidManifest.xml')
|
80
74
|
end
|
81
75
|
|
82
76
|
def symbol_path
|
83
|
-
@symbol_path ||= File.join(contents, 'R.txt')
|
77
|
+
@symbol_path ||= ::File.join(contents, 'R.txt')
|
84
78
|
end
|
85
79
|
alias resource_path symbol_path
|
86
80
|
|
87
81
|
def contents
|
88
|
-
@contents ||= unarchive(@file,
|
82
|
+
@contents ||= unarchive(@file, prefix: 'proguard')
|
89
83
|
end
|
90
84
|
|
91
85
|
def clear!
|
@@ -7,7 +7,7 @@ require 'app_info/core_ext'
|
|
7
7
|
module AppInfo
|
8
8
|
module Protobuf
|
9
9
|
class Base
|
10
|
-
include Helper::
|
10
|
+
include Helper::GenerateClass
|
11
11
|
|
12
12
|
def initialize(doc, resources = nil)
|
13
13
|
@resources = resources
|
@@ -222,7 +222,6 @@ module AppInfo
|
|
222
222
|
|
223
223
|
type ||= name.split('.')[2]
|
224
224
|
raise ProtobufParseError, 'Not found intent type' unless TYPES.include?(type)
|
225
|
-
|
226
225
|
return false unless intent = send(type.to_sym)
|
227
226
|
|
228
227
|
values = intent.select { |e| e.name == name }
|
@@ -9,6 +9,13 @@ protoc --ruby_out=. Resources.proto
|
|
9
9
|
protoc --ruby_out=. Configuration.proto
|
10
10
|
```
|
11
11
|
|
12
|
+
## Decode
|
13
|
+
|
14
|
+
```bash
|
15
|
+
protoc --decode=aapt.pb.ResourceTable Resources.proto < aab/base/BundleConfig.pb > BundleConfig.txt
|
16
|
+
protoc --decode=aapt.pb.ResourceTable Resources.proto < aab/base/native.pb > native.txt
|
17
|
+
```
|
18
|
+
|
12
19
|
## Resouces
|
13
20
|
|
14
21
|
`Configuration.proto` and `Resources.proto` can be found in aapt2's github:
|
@@ -322,7 +322,9 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
|
|
322
322
|
end
|
323
323
|
end
|
324
324
|
|
325
|
+
# @!visibility private
|
325
326
|
module Aapt
|
327
|
+
|
326
328
|
module Pb
|
327
329
|
StringPool = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("aapt.pb.StringPool").msgclass
|
328
330
|
SourcePosition = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("aapt.pb.SourcePosition").msgclass
|
@@ -12,7 +12,7 @@ module AppInfo
|
|
12
12
|
new(doc)
|
13
13
|
end
|
14
14
|
|
15
|
-
include Helper::
|
15
|
+
include Helper::Protobuf
|
16
16
|
|
17
17
|
attr_reader :packages, :tool_fingerprint
|
18
18
|
|
@@ -53,7 +53,7 @@ module AppInfo
|
|
53
53
|
end
|
54
54
|
|
55
55
|
class Package
|
56
|
-
include Helper::
|
56
|
+
include Helper::GenerateClass
|
57
57
|
|
58
58
|
attr_reader :name, :types
|
59
59
|
|
@@ -113,14 +113,14 @@ module AppInfo
|
|
113
113
|
end
|
114
114
|
|
115
115
|
class Entry
|
116
|
+
include Helper::GenerateClass
|
117
|
+
|
116
118
|
def self.parse_from(type, package)
|
117
119
|
type.entry.each_with_object([]) do |entry, obj|
|
118
120
|
obj << Entry.new(entry, package)
|
119
121
|
end
|
120
122
|
end
|
121
123
|
|
122
|
-
include Helper::Defines
|
123
|
-
|
124
124
|
attr_reader :name, :values
|
125
125
|
|
126
126
|
def initialize(doc, package)
|
@@ -155,7 +155,7 @@ module AppInfo
|
|
155
155
|
end
|
156
156
|
|
157
157
|
class Value
|
158
|
-
include Helper::
|
158
|
+
include Helper::Protobuf
|
159
159
|
extend Forwardable
|
160
160
|
|
161
161
|
attr_reader :locale, :config, :original_value, :value, :type
|
data/lib/app_info/version.rb
CHANGED