app-info 2.8.5 → 3.0.0.beta1
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 +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