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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 35509386f8425f29ea466dbcb1ce12cf54be230f9b4668d4ad2f5ac9b4a4b1b5
|
4
|
+
data.tar.gz: 6f3f87d116877fd058a9f479de6b0aa789d74c255f832f5db132446e6250b82e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b62671980b8d9e7a854523e24311af90e78b807023b65aa1d417159717c3119c34beef4e589638d3fa3708820c8732a1c82859f8b2194477a90548dfd0611b0a
|
7
|
+
data.tar.gz: dc22e6f681b64658bacd6206c3cb7bdceb4afac7fac9332af230563930d8df24da1b95336647c25f7f84537c7716804d5d27e7409baa08b30e5f436e3a505c16
|
data/.github/dependabot.yml
CHANGED
@@ -1,9 +1,14 @@
|
|
1
1
|
version: 2
|
2
2
|
updates:
|
3
|
-
- package-ecosystem: bundler
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
3
|
+
- package-ecosystem: bundler
|
4
|
+
directory: "/"
|
5
|
+
schedule:
|
6
|
+
interval: daily
|
7
|
+
time: "21:00"
|
8
|
+
timezone: Asia/Shanghai
|
9
|
+
open-pull-requests-limit: 10
|
10
|
+
|
11
|
+
- package-ecosystem: "github-actions"
|
12
|
+
directory: "/"
|
13
|
+
schedule:
|
14
|
+
interval: "daily"
|
data/.github/workflows/ci.yml
CHANGED
data/.rubocop.yml
CHANGED
@@ -27,6 +27,22 @@ AllCops:
|
|
27
27
|
- 'lib/app_info/protobuf/models/*_pb.rb'
|
28
28
|
- 'main.rb'
|
29
29
|
|
30
|
+
Layout/LineLength:
|
31
|
+
Max: 100
|
32
|
+
Exclude:
|
33
|
+
- 'lib/app_info/helper/signatures.rb'
|
34
|
+
|
35
|
+
Lint/AssignmentInCondition:
|
36
|
+
Enabled: false
|
37
|
+
|
38
|
+
Lint/UnusedMethodArgument:
|
39
|
+
Exclude:
|
40
|
+
- 'lib/app_info/file.rb'
|
41
|
+
|
42
|
+
Lint/UselessAssignment:
|
43
|
+
Exclude:
|
44
|
+
- 'lib/app_info/android/signatures/v3.rb'
|
45
|
+
|
30
46
|
Metrics/AbcSize:
|
31
47
|
Max: 100
|
32
48
|
|
@@ -36,13 +52,15 @@ Metrics/BlockLength:
|
|
36
52
|
- 'lib/app_info/mobile_provision.rb'
|
37
53
|
|
38
54
|
Metrics/MethodLength:
|
39
|
-
Max:
|
55
|
+
Max: 30
|
40
56
|
Exclude:
|
41
|
-
- 'lib/app_info/png_uncrush.rb'
|
42
57
|
- 'lib/app_info/mobile_provision.rb'
|
58
|
+
- 'lib/app_info/android/signatures/v2.rb'
|
59
|
+
- 'lib/app_info/android/signatures/v3.rb'
|
43
60
|
|
44
|
-
|
45
|
-
|
61
|
+
Metrics/ParameterLists:
|
62
|
+
Exclude:
|
63
|
+
- 'lib/app_info/helper/signatures.rb'
|
46
64
|
|
47
65
|
Metrics/ClassLength:
|
48
66
|
CountComments: false
|
@@ -54,12 +72,16 @@ Metrics/CyclomaticComplexity:
|
|
54
72
|
Metrics/PerceivedComplexity:
|
55
73
|
Max: 18
|
56
74
|
|
57
|
-
|
58
|
-
|
75
|
+
Metrics/BlockNesting:
|
76
|
+
Exclude:
|
77
|
+
- 'lib/app_info/dsym.rb'
|
59
78
|
|
60
79
|
Style/Documentation:
|
61
80
|
Enabled: false
|
62
81
|
|
82
|
+
Style/ClassAndModuleChildren:
|
83
|
+
Enabled: false
|
84
|
+
|
63
85
|
Style/PerlBackrefs:
|
64
86
|
Exclude:
|
65
87
|
- 'lib/app_info/core_ext/string/inflector.rb'
|
@@ -67,10 +89,8 @@ Style/PerlBackrefs:
|
|
67
89
|
Style/DocumentDynamicEvalDefinition:
|
68
90
|
Enabled: false
|
69
91
|
|
70
|
-
Metrics/BlockNesting:
|
71
|
-
Exclude:
|
72
|
-
- 'lib/app_info/dsym.rb'
|
73
|
-
|
74
|
-
|
75
92
|
Style/SlicingWithRange:
|
76
93
|
Enabled: false
|
94
|
+
|
95
|
+
Style/ClassVars:
|
96
|
+
Enabled: false
|
data/CHANGELOG.md
CHANGED
@@ -9,6 +9,28 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
9
9
|
|
10
10
|
> List all changes before release a new version.
|
11
11
|
|
12
|
+
## [3.0.0.beta1] (2023-04-?)
|
13
|
+
|
14
|
+
### Added
|
15
|
+
|
16
|
+
- New Windows PE format parser. [#47](https://github.com/icyleaf/app_info/pull/47)
|
17
|
+
- Android parser add v2, v3 scheme signature support. [#55](https://github.com/icyleaf/app_info/pull/55]
|
18
|
+
- dSYM parer accept multi dSYM target in a zip file. [#56](https://github.com/icyleaf/app_info/pull/56)
|
19
|
+
|
20
|
+
### Changed
|
21
|
+
|
22
|
+
- Add `AppInfo::File` base class for all parsers.
|
23
|
+
- Add `AppInfo::Certifiate` X509 certificate wrapped and apply in Android/MobileProvision.
|
24
|
+
- Remove `AppInfo::MobileProvision::DeveloperCertificate` class, use `AppInfo::Certifiate` instead.
|
25
|
+
- Remove `.sign_version` method in Android parser.
|
26
|
+
- Remove duplice `AppInfo::AndroidDevice` class.
|
27
|
+
- Deprecate `.signs` and `.certifiates` methods in Android parser, use `.signatures` instead.
|
28
|
+
- Deprecate `.developer_certs` method in MobileProvision parser, use `.certificates` instead.
|
29
|
+
|
30
|
+
### Fixed
|
31
|
+
|
32
|
+
- Fixed minor typo.
|
33
|
+
|
12
34
|
## [2.8.5] (2023-03-16)
|
13
35
|
|
14
36
|
### Fixed
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -5,7 +5,8 @@
|
|
5
5
|
[](https://rubygems.org/gems/app_info)
|
6
6
|
[](LICENSE)
|
7
7
|
|
8
|
-
Teardown tool for mobile app (ipa, apk and aab file), macOS app
|
8
|
+
Teardown tool for mobile app (ipa, apk and aab file), macOS app, dSYM.zip file and Windows PE file.
|
9
|
+
Analysis metedata like version, name, icon etc.
|
9
10
|
|
10
11
|
## Support
|
11
12
|
|
@@ -16,10 +17,13 @@ Teardown tool for mobile app (ipa, apk and aab file), macOS app and dSYM.zip fil
|
|
16
17
|
- `.ipa`
|
17
18
|
- `Info.plist` file
|
18
19
|
- `.mobileprovision`/`.provisionprofile` file
|
19
|
-
-
|
20
|
+
- macOS App file (archived by starnd pkzip format)
|
20
21
|
- `.app.zip`
|
21
|
-
-
|
22
|
+
- dSYMs file (archived by starnd pkzip format)
|
22
23
|
- `.dSYM.zip`
|
24
|
+
- Windows PE file
|
25
|
+
- `.exe`
|
26
|
+
- `.zip` (binary in a zip file)
|
23
27
|
|
24
28
|
<hr />
|
25
29
|
|
@@ -65,6 +69,8 @@ parser = AppInfo.parse('android.aab')
|
|
65
69
|
parser = AppInfo.parse('u-u-i-d.mobileprovision')
|
66
70
|
parser = AppInfo.parse('macOS.App.zip')
|
67
71
|
parser = AppInfo.parse('App.dSYm.zip')
|
72
|
+
parser = AppInfo.parse('win.exe')
|
73
|
+
parser = AppInfo.parse('win.zip')
|
68
74
|
|
69
75
|
# If detect file type failed, you can parse in other way
|
70
76
|
parser = AppInfo::IPA.new('iphone.ipa')
|
@@ -74,6 +80,7 @@ parser = AppInfo::InfoPlist.new('Info.plist')
|
|
74
80
|
parser = AppInfo::MobileProvision.new('uuid.mobileprovision')
|
75
81
|
parser = AppInfo::Macos.new('App.dSYm.zip')
|
76
82
|
parser = AppInfo::DSYM.new('App.dSYm.zip')
|
83
|
+
parser = AppInfo::PE.new('win.exe')
|
77
84
|
```
|
78
85
|
|
79
86
|
### iOS
|
@@ -220,12 +227,8 @@ android.deep_links
|
|
220
227
|
android.schemes
|
221
228
|
# => ['appinfo']
|
222
229
|
|
223
|
-
# get
|
224
|
-
android.
|
225
|
-
# => [...]
|
226
|
-
|
227
|
-
# get certificate list (only v1 sign)
|
228
|
-
android.certificates
|
230
|
+
# get v1-v3 scheme singature information (included unverified certificate and more)
|
231
|
+
android.signatures
|
229
232
|
# => [...]
|
230
233
|
```
|
231
234
|
|
@@ -313,6 +316,58 @@ dsym.machos.each do |macho|
|
|
313
316
|
end
|
314
317
|
```
|
315
318
|
|
319
|
+
### Windows
|
320
|
+
|
321
|
+
Accept any PE format file, such like `.exe` or `.exe` binary fin a zip file.
|
322
|
+
|
323
|
+
```ruby
|
324
|
+
win = AppInfo.parse('win.exe')
|
325
|
+
|
326
|
+
# get given file size
|
327
|
+
win.size
|
328
|
+
# => 3093823
|
329
|
+
|
330
|
+
# get given file size in human reable.
|
331
|
+
win.size(human_size: true)
|
332
|
+
# => 29 MB
|
333
|
+
|
334
|
+
# get given file size
|
335
|
+
win.binary_size
|
336
|
+
# => 20940
|
337
|
+
|
338
|
+
# get given file size in human reable.
|
339
|
+
win.size(human_size: true)
|
340
|
+
# => 20 MB
|
341
|
+
|
342
|
+
# get product name
|
343
|
+
win.name
|
344
|
+
# => AppInfo
|
345
|
+
|
346
|
+
# get app company name
|
347
|
+
win.company_name
|
348
|
+
# => EWS Studio
|
349
|
+
|
350
|
+
# get app product version (alias to release_version)
|
351
|
+
win.product_version
|
352
|
+
# => 1.0.0
|
353
|
+
|
354
|
+
# get app assembly version (alias to build_version)
|
355
|
+
win.assembly_version
|
356
|
+
# => 1.0.0
|
357
|
+
|
358
|
+
# detect architecture(s)
|
359
|
+
win.archs
|
360
|
+
# => x64
|
361
|
+
|
362
|
+
# get all imports files
|
363
|
+
win.imports
|
364
|
+
# => [KERNEL32.dll, ...]
|
365
|
+
|
366
|
+
# get app icons (bmp format image)
|
367
|
+
win.icons
|
368
|
+
# => [{:name=>"ICON.bmp", :file=>"{path}/ICON.bmp"}, :dimensions=>[64, 64]}, ...]
|
369
|
+
```
|
370
|
+
|
316
371
|
## CLI Shell (Interactive console)
|
317
372
|
|
318
373
|
It is possible to use this gem as a command line interface to parse mobile app:
|
data/Rakefile
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
$LOAD_PATH.unshift File.expand_path('lib', __dir__)
|
4
4
|
require 'app_info'
|
5
|
+
require 'yard'
|
5
6
|
require 'bundler/gem_tasks'
|
6
7
|
require 'rspec/core/rake_task'
|
7
8
|
require 'rubocop/rake_task'
|
@@ -9,3 +10,13 @@ require 'rubocop/rake_task'
|
|
9
10
|
RSpec::Core::RakeTask.new(:spec)
|
10
11
|
|
11
12
|
task default: :spec
|
13
|
+
|
14
|
+
task :doc do
|
15
|
+
YARD::Rake::YardocTask.new do |t|
|
16
|
+
t.files = ['lib/**/*.rb', 'README.md', 'LICENSE']
|
17
|
+
# t.options = ['--any', '--extra', '--opts'] # optional
|
18
|
+
# t.stats_options = ['--list-undoc'] # optional
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
|
data/app_info.gemspec
CHANGED
@@ -23,14 +23,23 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.add_dependency 'CFPropertyList', '< 3.1.0', '>= 2.3.4'
|
24
24
|
spec.add_dependency 'image_size', '>= 1.5', '< 3.3'
|
25
25
|
spec.add_dependency 'ruby-macho', '>= 1.4', '< 4'
|
26
|
-
spec.add_dependency 'android_parser', '~> 2.
|
26
|
+
spec.add_dependency 'android_parser', '~> 2.6.0'
|
27
27
|
spec.add_dependency 'rubyzip', '>= 1.2', '< 3.0'
|
28
28
|
spec.add_dependency 'uuidtools', '>= 2.1.5', '< 2.3.0'
|
29
29
|
spec.add_dependency 'icns', '~> 0.2.0'
|
30
|
+
spec.add_dependency 'pedump', '~> 0.6.2'
|
30
31
|
spec.add_dependency 'google-protobuf', '>= 3.19.4', '< 3.23.0'
|
31
32
|
|
32
33
|
spec.add_development_dependency 'bundler', '>= 1.12'
|
33
34
|
spec.add_development_dependency 'rake', '>= 10.0'
|
34
|
-
|
35
|
-
spec.
|
35
|
+
|
36
|
+
spec.post_install_message = <<~ENDBANNER
|
37
|
+
AppInfo 3.0 is coming!
|
38
|
+
**********************
|
39
|
+
The public API of some AppInfo classes has been changed.
|
40
|
+
|
41
|
+
Please ensure that your Gemfiles and .gemspecs are suitably restrictive
|
42
|
+
to avoid an unexpected breakage when 3.0 is released (e.g. ~> 2.8.5).
|
43
|
+
See https://github.com/icyleaf/app_info for details.
|
44
|
+
ENDBANNER
|
36
45
|
end
|
data/lib/app_info/aab.rb
CHANGED
@@ -5,8 +5,8 @@ require 'image_size'
|
|
5
5
|
require 'forwardable'
|
6
6
|
|
7
7
|
module AppInfo
|
8
|
-
# Parse APK file
|
9
|
-
class AAB
|
8
|
+
# Parse APK file parser
|
9
|
+
class AAB < File
|
10
10
|
include Helper::HumanFileSize
|
11
11
|
extend Forwardable
|
12
12
|
|
@@ -25,38 +25,52 @@ module AppInfo
|
|
25
25
|
BASE_MANIFEST = "#{BASE_PATH}/manifest/AndroidManifest.xml"
|
26
26
|
BASE_RESOURCES = "#{BASE_PATH}/resources.pb"
|
27
27
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
28
|
+
# return file size
|
29
|
+
# @example Read file size in integer
|
30
|
+
# aab.size # => 3618865
|
31
|
+
#
|
32
|
+
# @example Read file size in human readabale
|
33
|
+
# aab.size(human_size: true) # => '3.45 MB'
|
34
|
+
#
|
35
|
+
# @param [Boolean] human_size Convert integer value to human readable.
|
36
|
+
# @return [Integer, String]
|
32
37
|
def size(human_size: false)
|
33
38
|
file_to_human_size(@file, human_size: human_size)
|
34
39
|
end
|
35
40
|
|
36
|
-
|
41
|
+
# @return [Symbol] {Format::AAB}
|
42
|
+
def file_type
|
43
|
+
Format::AAB
|
44
|
+
end
|
45
|
+
|
46
|
+
# @return [String] {Platform::ANDROID}
|
47
|
+
def platform
|
37
48
|
Platform::ANDROID
|
38
49
|
end
|
39
|
-
alias file_type os
|
40
50
|
|
41
51
|
def_delegators :manifest, :version_name, :deep_links, :schemes
|
42
52
|
|
43
53
|
alias release_version version_name
|
44
54
|
|
55
|
+
# @return [String]
|
45
56
|
def package_name
|
46
57
|
manifest.package
|
47
58
|
end
|
48
59
|
alias identifier package_name
|
49
60
|
alias bundle_id package_name
|
50
61
|
|
62
|
+
# @return [String]
|
51
63
|
def version_code
|
52
64
|
manifest.version_code.to_s
|
53
65
|
end
|
54
66
|
alias build_version version_code
|
55
67
|
|
68
|
+
# @return [String]
|
56
69
|
def name
|
57
70
|
manifest.label
|
58
71
|
end
|
59
72
|
|
73
|
+
# @return [String] {Device}
|
60
74
|
def device_type
|
61
75
|
if wear?
|
62
76
|
Device::WATCH
|
@@ -78,33 +92,40 @@ module AppInfo
|
|
78
92
|
# .size >= 1
|
79
93
|
# end
|
80
94
|
|
95
|
+
# @return [Boolean]
|
81
96
|
def wear?
|
82
97
|
!!use_features&.include?('android.hardware.type.watch')
|
83
98
|
end
|
84
99
|
|
100
|
+
# @return [Boolean]
|
85
101
|
def tv?
|
86
102
|
!!use_features&.include?('android.software.leanback')
|
87
103
|
end
|
88
104
|
|
105
|
+
# @return [Boolean]
|
89
106
|
def automotive?
|
90
107
|
!!use_features&.include?('android.hardware.type.automotive')
|
91
108
|
end
|
92
109
|
|
110
|
+
# @return [String]
|
93
111
|
def min_sdk_version
|
94
112
|
manifest.uses_sdk.min_sdk_version
|
95
113
|
end
|
96
114
|
alias min_os_version min_sdk_version
|
97
115
|
|
116
|
+
# @return [String]
|
98
117
|
def target_sdk_version
|
99
118
|
manifest.uses_sdk.target_sdk_version
|
100
119
|
end
|
101
120
|
|
121
|
+
# @return [Array<String>]
|
102
122
|
def use_features
|
103
123
|
return [] unless manifest.respond_to?(:uses_feature)
|
104
124
|
|
105
125
|
@use_features ||= manifest&.uses_feature&.map(&:name)
|
106
126
|
end
|
107
127
|
|
128
|
+
# @return [Array<String>]
|
108
129
|
def use_permissions
|
109
130
|
return [] unless manifest.respond_to?(:uses_permission)
|
110
131
|
|
@@ -123,36 +144,25 @@ module AppInfo
|
|
123
144
|
@components ||= manifest.components.transform_values
|
124
145
|
end
|
125
146
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
# 'v2'
|
132
|
-
# when ?
|
133
|
-
# https://source.android.com/security/apksigning/v3?hl=zh-cn
|
134
|
-
# 'v3'
|
135
|
-
'unknown'
|
147
|
+
# Return multi version certifiates of signatures
|
148
|
+
# @return [Array<Hash>] signatures
|
149
|
+
# @see AppInfo::Android::Signature.verify
|
150
|
+
def signatures
|
151
|
+
@signatures ||= Android::Signature.verify(self)
|
136
152
|
end
|
137
153
|
|
154
|
+
# Legacy v1 scheme signatures, it will remove soon.
|
155
|
+
# @deprecated Use {#signatures}
|
156
|
+
# @return [Array<OpenSSL::PKCS7, nil>] signatures
|
138
157
|
def signs
|
139
|
-
|
140
|
-
|
141
|
-
@signs = []
|
142
|
-
each_file do |path, data|
|
143
|
-
# find META-INF/xxx.{RSA|DSA}
|
144
|
-
next unless path =~ %r{^META-INF/} && data.unpack('CC') == [0x30, 0x82]
|
145
|
-
|
146
|
-
@signs << APK::Sign.new(path, OpenSSL::PKCS7.new(data))
|
147
|
-
end
|
148
|
-
|
149
|
-
@signs
|
158
|
+
@signs ||= v1sign&.signatures || []
|
150
159
|
end
|
151
160
|
|
161
|
+
# Legacy v1 scheme certificates, it will remove soon.
|
162
|
+
# @deprecated Use {#signatures}
|
163
|
+
# @return [Array<OpenSSL::PKCS7, nil>] certificates
|
152
164
|
def certificates
|
153
|
-
@certificates ||=
|
154
|
-
obj << APK::Certificate.new(sign.path, sign.sign.certificates[0])
|
155
|
-
end
|
165
|
+
@certificates ||= v1sign&.certificates || []
|
156
166
|
end
|
157
167
|
|
158
168
|
def each_file
|
@@ -171,7 +181,7 @@ module AppInfo
|
|
171
181
|
end
|
172
182
|
|
173
183
|
def entry(name, base_path: BASE_PATH)
|
174
|
-
entry = @zip.find_entry(File.join(base_path, name))
|
184
|
+
entry = @zip.find_entry(::File.join(base_path, name))
|
175
185
|
raise NotFoundError, "'#{name}'" if entry.nil?
|
176
186
|
|
177
187
|
entry
|
@@ -182,25 +192,28 @@ module AppInfo
|
|
182
192
|
@manifest ||= Protobuf::Manifest.parse(io, resource)
|
183
193
|
end
|
184
194
|
|
195
|
+
# @return [Protobuf::Resources]
|
185
196
|
def resource
|
186
197
|
io = zip.read(zip.find_entry(BASE_RESOURCES))
|
187
198
|
@resource ||= Protobuf::Resources.parse(io)
|
188
199
|
end
|
189
200
|
|
201
|
+
# @return [Zip::File]
|
190
202
|
def zip
|
191
203
|
@zip ||= Zip::File.open(@file)
|
192
204
|
end
|
193
205
|
|
206
|
+
# @return [Array<Hash>]
|
194
207
|
def icons
|
195
208
|
@icons ||= manifest.icons.each_with_object([]) do |res, obj|
|
196
209
|
path = res.value
|
197
|
-
filename = File.basename(path)
|
198
|
-
filepath = File.join(contents, File.dirname(path))
|
199
|
-
file = File.join(filepath, filename)
|
210
|
+
filename = ::File.basename(path)
|
211
|
+
filepath = ::File.join(contents, ::File.dirname(path))
|
212
|
+
file = ::File.join(filepath, filename)
|
200
213
|
FileUtils.mkdir_p filepath
|
201
214
|
|
202
215
|
binary_data = read_file(path)
|
203
|
-
File.write(file, binary_data, encoding: Encoding::BINARY)
|
216
|
+
::File.write(file, binary_data, encoding: Encoding::BINARY)
|
204
217
|
|
205
218
|
obj << {
|
206
219
|
name: filename,
|
@@ -223,13 +236,19 @@ module AppInfo
|
|
223
236
|
end
|
224
237
|
|
225
238
|
def contents
|
226
|
-
@contents ||= File.join(Dir.mktmpdir, "AppInfo-android-#{SecureRandom.hex}")
|
239
|
+
@contents ||= ::File.join(Dir.mktmpdir, "AppInfo-android-#{SecureRandom.hex}")
|
227
240
|
end
|
228
241
|
|
229
242
|
private
|
230
243
|
|
244
|
+
def v1sign
|
245
|
+
@v1sign ||= Android::Signature::V1.verify(self)
|
246
|
+
rescue Android::Signature::NotFoundError
|
247
|
+
nil
|
248
|
+
end
|
249
|
+
|
231
250
|
def xml_file?(file)
|
232
|
-
File.extname(file) == '.xml'
|
251
|
+
::File.extname(file) == '.xml'
|
233
252
|
end
|
234
253
|
|
235
254
|
# TODO: how to convert xml content after decode protoubufed content
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AppInfo
|
4
|
+
module Android
|
5
|
+
# Android Signature
|
6
|
+
#
|
7
|
+
# Support digest and length:
|
8
|
+
#
|
9
|
+
# RSA:1024、2048、4096、8192、16384
|
10
|
+
# EC:NIST P-256、P-384、P-521
|
11
|
+
# DSA:1024、2048、3072
|
12
|
+
module Signature
|
13
|
+
class VersionError < Error; end
|
14
|
+
class SecurityError < Error; end
|
15
|
+
class NotFoundError < NotFoundError; end
|
16
|
+
|
17
|
+
module Version
|
18
|
+
V1 = 1
|
19
|
+
V2 = 2
|
20
|
+
V3 = 3
|
21
|
+
V4 = 4
|
22
|
+
end
|
23
|
+
|
24
|
+
# All registerd verions to verify
|
25
|
+
#
|
26
|
+
# key is the version
|
27
|
+
# value is the class
|
28
|
+
@versions = {}
|
29
|
+
|
30
|
+
class << self
|
31
|
+
# Verify Android Signature
|
32
|
+
#
|
33
|
+
# @example Get unverified v1 certificates, verified v2 certificates,
|
34
|
+
# and not found v3 certificate
|
35
|
+
#
|
36
|
+
# signature.versions(parser)
|
37
|
+
# # => [
|
38
|
+
# # {
|
39
|
+
# # version: 1,
|
40
|
+
# # verified: false,
|
41
|
+
# # certificates: [<AppInfo::Certificate>, ...],
|
42
|
+
# # verifier: AppInfo::Androig::Signature
|
43
|
+
# # },
|
44
|
+
# # {
|
45
|
+
# # version: 2,
|
46
|
+
# # verified: false,
|
47
|
+
# # certificates: [<AppInfo::Certificate>, ...],
|
48
|
+
# # verifier: AppInfo::Androig::Signature
|
49
|
+
# # },
|
50
|
+
# # {
|
51
|
+
# # version: 3
|
52
|
+
# # }
|
53
|
+
# # ]
|
54
|
+
# @todo version 4 no implantation yet
|
55
|
+
# @param [AppInfo::File] parser
|
56
|
+
# @param [Version, Integer] min_version
|
57
|
+
# @return [Array<Hash>] versions
|
58
|
+
def verify(parser, min_version: Version::V4)
|
59
|
+
min_version = min_version.to_i if min_version.is_a?(String)
|
60
|
+
if min_version && min_version > Version::V4
|
61
|
+
raise VersionError,
|
62
|
+
"No signature found in #{min_version} scheme or newer for android file"
|
63
|
+
end
|
64
|
+
|
65
|
+
if min_version.zero?
|
66
|
+
raise VersionError,
|
67
|
+
"Unkonwn version: #{min_version}, avaiables in 1/2/3 and 4 (no implantation yet)"
|
68
|
+
end
|
69
|
+
|
70
|
+
# try full version signatures if min_version is nil
|
71
|
+
versions = min_version.downto(Version::V1).each_with_object([]) do |version, signatures|
|
72
|
+
next unless kclass = fetch(version)
|
73
|
+
|
74
|
+
data = { version: version }
|
75
|
+
begin
|
76
|
+
verifier = kclass.verify(parser)
|
77
|
+
data[:verified] = verifier.verified
|
78
|
+
data[:certificates] = verifier.certificates
|
79
|
+
data[:verifier] = verifier
|
80
|
+
rescue SecurityError, NotFoundError
|
81
|
+
# not this version, try the low version
|
82
|
+
ensure
|
83
|
+
signatures << data
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
versions.sort_by { |entry| entry[:version] }
|
88
|
+
end
|
89
|
+
|
90
|
+
def registered
|
91
|
+
@versions.keys
|
92
|
+
end
|
93
|
+
|
94
|
+
def register(version, verifier)
|
95
|
+
@versions[version] = verifier
|
96
|
+
end
|
97
|
+
|
98
|
+
def fetch(version)
|
99
|
+
@versions[version]
|
100
|
+
end
|
101
|
+
|
102
|
+
def exist?(version)
|
103
|
+
@versions.key?(version)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
UINT32_MAX_VALUE = 2_147_483_647
|
108
|
+
UINT32_SIZE = 4
|
109
|
+
UINT64_SIZE = 8
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
require 'app_info/android/signatures/base'
|