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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +12 -7
  3. data/.github/workflows/ci.yml +3 -1
  4. data/.rubocop.yml +31 -11
  5. data/CHANGELOG.md +22 -0
  6. data/Gemfile +7 -1
  7. data/README.md +64 -9
  8. data/Rakefile +11 -0
  9. data/app_info.gemspec +12 -3
  10. data/lib/app_info/aab.rb +58 -39
  11. data/lib/app_info/android/signature.rb +114 -0
  12. data/lib/app_info/android/signatures/base.rb +49 -0
  13. data/lib/app_info/android/signatures/info.rb +152 -0
  14. data/lib/app_info/android/signatures/v1.rb +59 -0
  15. data/lib/app_info/android/signatures/v2.rb +117 -0
  16. data/lib/app_info/android/signatures/v3.rb +127 -0
  17. data/lib/app_info/android/signatures/v4.rb +14 -0
  18. data/lib/app_info/apk.rb +43 -46
  19. data/lib/app_info/certificate.rb +181 -0
  20. data/lib/app_info/const.rb +41 -0
  21. data/lib/app_info/core_ext/object/try.rb +3 -1
  22. data/lib/app_info/core_ext/string/inflector.rb +2 -0
  23. data/lib/app_info/dsym/debug_info.rb +72 -0
  24. data/lib/app_info/dsym/macho.rb +55 -0
  25. data/lib/app_info/dsym.rb +27 -134
  26. data/lib/app_info/error.rb +7 -1
  27. data/lib/app_info/file.rb +23 -0
  28. data/lib/app_info/helper/archive.rb +37 -0
  29. data/lib/app_info/helper/file_size.rb +25 -0
  30. data/lib/app_info/helper/generate_class.rb +29 -0
  31. data/lib/app_info/helper/protobuf.rb +12 -0
  32. data/lib/app_info/helper/signatures.rb +229 -0
  33. data/lib/app_info/helper.rb +5 -126
  34. data/lib/app_info/info_plist.rb +14 -6
  35. data/lib/app_info/ipa/framework.rb +4 -4
  36. data/lib/app_info/ipa.rb +41 -36
  37. data/lib/app_info/macos.rb +34 -26
  38. data/lib/app_info/mobile_provision.rb +19 -30
  39. data/lib/app_info/pe.rb +226 -0
  40. data/lib/app_info/png_uncrush.rb +5 -4
  41. data/lib/app_info/proguard.rb +11 -17
  42. data/lib/app_info/protobuf/manifest.rb +1 -2
  43. data/lib/app_info/protobuf/models/Configuration_pb.rb +1 -0
  44. data/lib/app_info/protobuf/models/README.md +7 -0
  45. data/lib/app_info/protobuf/models/Resources_pb.rb +2 -0
  46. data/lib/app_info/protobuf/resources.rb +5 -5
  47. data/lib/app_info/version.rb +1 -1
  48. data/lib/app_info.rb +88 -45
  49. metadata +46 -35
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f9406b7552e0bea00883446b85250398c7818120de74d0d6d3545d7b9b0d7ef6
4
- data.tar.gz: a99bb2c55b4214ad72f8e6cf2e720199902fb37ad174b71bb5f9f4d529ba81a3
3
+ metadata.gz: 35509386f8425f29ea466dbcb1ce12cf54be230f9b4668d4ad2f5ac9b4a4b1b5
4
+ data.tar.gz: 6f3f87d116877fd058a9f479de6b0aa789d74c255f832f5db132446e6250b82e
5
5
  SHA512:
6
- metadata.gz: '018d93bb67f489d4908f0701285ee6c177a627f3b5c602e90c24629da25f91fc2f5cb9b091675d471741361211289b71ed7c1ab51402f30cea843126c9c6271c'
7
- data.tar.gz: 5eecd5818b12032898d33a14f74c43592d120ab751b2e4393591b0fd81e4df5cebb94342111478392fd84c5963f762de0383873c547176f74d546f7bfb7b8013
6
+ metadata.gz: b62671980b8d9e7a854523e24311af90e78b807023b65aa1d417159717c3119c34beef4e589638d3fa3708820c8732a1c82859f8b2194477a90548dfd0611b0a
7
+ data.tar.gz: dc22e6f681b64658bacd6206c3cb7bdceb4afac7fac9332af230563930d8df24da1b95336647c25f7f84537c7716804d5d27e7409baa08b30e5f436e3a505c16
@@ -1,9 +1,14 @@
1
1
  version: 2
2
2
  updates:
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
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"
@@ -1,8 +1,10 @@
1
1
  name: CI
2
2
  on:
3
3
  push:
4
+ paths-ignore:
5
+ - '*.md'
4
6
  branches:
5
- - master
7
+ - main
6
8
  pull_request:
7
9
 
8
10
  jobs:
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: 20
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
- Layout/LineLength:
45
- Max: 100
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
- Lint/AssignmentInCondition:
58
- Enabled: false
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
@@ -7,5 +7,11 @@ gemspec
7
7
 
8
8
  group :development do
9
9
  gem 'awesome_print'
10
- gem 'debug' # For ruby 3.0+
10
+ gem 'debug' # For ruby 3.0+\
11
+ gem 'yard'
12
+ end
13
+
14
+ group :development, :test do
15
+ gem 'rspec'
16
+ gem 'rubocop'
11
17
  end
data/README.md CHANGED
@@ -5,7 +5,8 @@
5
5
  [![Gem version](https://img.shields.io/gem/v/app-info.svg?style=flat)](https://rubygems.org/gems/app_info)
6
6
  [![License](https://img.shields.io/badge/license-MIT-red.svg?style=flat)](LICENSE)
7
7
 
8
- Teardown tool for mobile app (ipa, apk and aab file), macOS app and dSYM.zip file, analysis metedata like version, name, icon etc.
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
- - Zipped macOS App file
20
+ - macOS App file (archived by starnd pkzip format)
20
21
  - `.app.zip`
21
- - Zipped dSYMs file
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 sign list (only v1 sign)
224
- android.signs
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.5.1'
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
- spec.add_development_dependency 'rspec', '~> 3.0'
35
- spec.add_development_dependency 'rubocop', '~> 1.19'
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
- def initialize(file)
29
- @file = file
30
- end
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
- def os
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
- def sign_version
127
- return 'v1' unless signs.empty?
128
-
129
- # when ?
130
- # https://source.android.com/security/apksigning/v2?hl=zh-cn
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
- return @signs if @signs
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 ||= signs.each_with_object([]) do |sign, obj|
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'