app-info 2.8.5 → 3.0.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) 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 +33 -11
  5. data/CHANGELOG.md +34 -1
  6. data/Gemfile +7 -1
  7. data/README.md +68 -13
  8. data/Rakefile +11 -0
  9. data/app_info.gemspec +12 -3
  10. data/lib/app_info/aab.rb +48 -108
  11. data/lib/app_info/android/signature.rb +114 -0
  12. data/lib/app_info/android/signatures/base.rb +53 -0
  13. data/lib/app_info/android/signatures/info.rb +158 -0
  14. data/lib/app_info/android/signatures/v1.rb +63 -0
  15. data/lib/app_info/android/signatures/v2.rb +121 -0
  16. data/lib/app_info/android/signatures/v3.rb +131 -0
  17. data/lib/app_info/android/signatures/v4.rb +18 -0
  18. data/lib/app_info/android.rb +162 -0
  19. data/lib/app_info/apk.rb +54 -111
  20. data/lib/app_info/apple.rb +192 -0
  21. data/lib/app_info/certificate.rb +175 -0
  22. data/lib/app_info/const.rb +75 -0
  23. data/lib/app_info/core_ext/object/try.rb +3 -1
  24. data/lib/app_info/core_ext/string/inflector.rb +2 -0
  25. data/lib/app_info/dsym/debug_info.rb +72 -0
  26. data/lib/app_info/dsym/macho.rb +55 -0
  27. data/lib/app_info/dsym.rb +31 -135
  28. data/lib/app_info/error.rb +2 -2
  29. data/lib/app_info/file.rb +49 -0
  30. data/lib/app_info/helper/archive.rb +37 -0
  31. data/lib/app_info/helper/file_size.rb +25 -0
  32. data/lib/app_info/helper/generate_class.rb +29 -0
  33. data/lib/app_info/helper/protobuf.rb +12 -0
  34. data/lib/app_info/helper/signatures.rb +229 -0
  35. data/lib/app_info/helper.rb +5 -126
  36. data/lib/app_info/info_plist.rb +66 -29
  37. data/lib/app_info/ipa/framework.rb +4 -4
  38. data/lib/app_info/ipa.rb +61 -135
  39. data/lib/app_info/macos.rb +54 -102
  40. data/lib/app_info/mobile_provision.rb +67 -49
  41. data/lib/app_info/pe.rb +260 -0
  42. data/lib/app_info/png_uncrush.rb +24 -4
  43. data/lib/app_info/proguard.rb +29 -16
  44. data/lib/app_info/protobuf/manifest.rb +6 -3
  45. data/lib/app_info/protobuf/models/Configuration_pb.rb +1 -0
  46. data/lib/app_info/protobuf/models/README.md +7 -0
  47. data/lib/app_info/protobuf/models/Resources_pb.rb +2 -0
  48. data/lib/app_info/protobuf/resources.rb +5 -5
  49. data/lib/app_info/version.rb +1 -1
  50. data/lib/app_info.rb +90 -46
  51. metadata +48 -35
data/lib/app_info/ipa.rb CHANGED
@@ -6,179 +6,106 @@ require 'forwardable'
6
6
  require 'cfpropertylist'
7
7
 
8
8
  module AppInfo
9
- # IPA parser
10
- class IPA
11
- include Helper::HumanFileSize
12
- include Helper::Archive
13
- extend Forwardable
14
-
15
- attr_reader :file
16
-
17
- # iOS Export types
18
- module ExportType
19
- DEBUG = 'Debug'
20
- ADHOC = 'AdHoc'
21
- ENTERPRISE = 'Enterprise'
22
- RELEASE = 'Release'
23
- UNKOWN = nil
24
-
25
- INHOUSE = 'Enterprise' # Rename and Alias to enterprise
26
- end
27
-
28
- def initialize(file)
29
- @file = file
30
- end
31
-
32
- def size(human_size: false)
33
- file_to_human_size(@file, human_size: human_size)
34
- end
35
-
36
- def os
37
- Platform::IOS
38
- end
39
- alias file_type os
40
-
41
- def_delegators :info, :iphone?, :ipad?, :universal?, :build_version, :name,
42
- :release_version, :identifier, :bundle_id, :display_name,
43
- :bundle_name, :min_sdk_version, :min_os_version, :device_type
44
-
45
- def_delegators :mobileprovision, :devices, :team_name, :team_identifier,
46
- :profile_name, :expired_date
47
-
48
- def distribution_name
49
- "#{profile_name} - #{team_name}" if profile_name && team_name
50
- end
51
-
52
- def release_type
53
- if stored?
54
- ExportType::RELEASE
55
- else
56
- build_type
57
- end
58
- end
59
-
60
- def build_type
61
- if mobileprovision?
62
- if devices
63
- ExportType::ADHOC
64
- else
65
- ExportType::ENTERPRISE
66
- end
67
- else
68
- ExportType::DEBUG
69
- end
70
- end
71
-
72
- def archs
73
- return unless File.exist?(bundle_path)
74
-
75
- file = MachO.open(bundle_path)
76
- case file
77
- when MachO::MachOFile
78
- [file.cpusubtype]
79
- else
80
- file.machos.each_with_object([]) do |arch, obj|
81
- obj << arch.cpusubtype
82
- end
83
- end
84
- end
85
- alias architectures archs
86
-
9
+ class IPA < Apple
10
+ # Full icons metadata
11
+ # @example
12
+ # aab.icons
13
+ # # => [
14
+ # # {
15
+ # # name: 'icon.png',
16
+ # # file: '/path/to/icon.png',
17
+ # # uncrushed_file: '/path/to/uncrushed_icon.png',
18
+ # # dimensions: [64, 64]
19
+ # # },
20
+ # # {
21
+ # # name: 'icon1.png',
22
+ # # file: '/path/to/icon1.png',
23
+ # # uncrushed_file: '/path/to/uncrushed_icon1.png',
24
+ # # dimensions: [120, 120]
25
+ # # }
26
+ # # ]
27
+ # @return [Array<Hash{Symbol => String, Array<Integer>}>] icons paths of icons
87
28
  def icons(uncrush: true)
88
29
  @icons ||= icons_path.each_with_object([]) do |file, obj|
89
30
  obj << build_icon_metadata(file, uncrush: uncrush)
90
31
  end
91
32
  end
92
33
 
34
+ # @return [Boolean]
93
35
  def stored?
94
36
  !!metadata?
95
37
  end
96
38
 
39
+ # @return [Array<Plugin>]
97
40
  def plugins
98
41
  @plugins ||= Plugin.parse(app_path)
99
42
  end
100
43
 
44
+ # @return [Array<Framework>]
101
45
  def frameworks
102
46
  @frameworks ||= Framework.parse(app_path)
103
47
  end
104
48
 
105
- def hide_developer_certificates
106
- mobileprovision.delete('DeveloperCertificates') if mobileprovision?
107
- end
108
-
109
- def mobileprovision
110
- return unless mobileprovision?
111
- return @mobileprovision if @mobileprovision
112
-
113
- @mobileprovision = MobileProvision.new(mobileprovision_path)
114
- end
115
-
116
- def mobileprovision?
117
- File.exist?(mobileprovision_path)
118
- end
119
-
49
+ # @return [String]
120
50
  def mobileprovision_path
121
51
  filename = 'embedded.mobileprovision'
122
- @mobileprovision_path ||= File.join(@file, filename)
123
- unless File.exist?(@mobileprovision_path)
124
- @mobileprovision_path = File.join(app_path, filename)
52
+ @mobileprovision_path ||= ::File.join(@file, filename)
53
+ unless ::File.exist?(@mobileprovision_path)
54
+ @mobileprovision_path = ::File.join(app_path, filename)
125
55
  end
126
56
 
127
57
  @mobileprovision_path
128
58
  end
129
59
 
60
+ # @return [CFPropertyList]
130
61
  def metadata
131
62
  return unless metadata?
132
63
 
133
64
  @metadata ||= CFPropertyList.native_types(CFPropertyList::List.new(file: metadata_path).value)
134
65
  end
135
66
 
67
+ # @return [Boolean]
136
68
  def metadata?
137
- File.exist?(metadata_path)
69
+ ::File.exist?(metadata_path)
138
70
  end
139
71
 
72
+ # @return [String]
140
73
  def metadata_path
141
- @metadata_path ||= File.join(contents, 'iTunesMetadata.plist')
74
+ @metadata_path ||= ::File.join(contents, 'iTunesMetadata.plist')
142
75
  end
143
76
 
144
- def bundle_path
145
- @bundle_path ||= File.join(app_path, info.bundle_name)
146
- end
147
-
148
- def info
149
- @info ||= InfoPlist.new(info_path)
77
+ # @return [String]
78
+ def binary_path
79
+ @binary_path ||= ::File.join(app_path, info.bundle_name)
150
80
  end
151
81
 
82
+ # @return [String]
152
83
  def info_path
153
- @info_path ||= File.join(app_path, 'Info.plist')
84
+ @info_path ||= ::File.join(app_path, 'Info.plist')
154
85
  end
155
86
 
87
+ # @return [String]
156
88
  def app_path
157
- @app_path ||= Dir.glob(File.join(contents, 'Payload', '*.app')).first
89
+ @app_path ||= Dir.glob(::File.join(contents, 'Payload', '*.app')).first
158
90
  end
159
91
 
160
- IPHONE_KEY = 'CFBundleIcons'
161
- IPAD_KEY = 'CFBundleIcons~ipad'
162
-
92
+ # @return [Array<String>]
163
93
  def icons_path
164
- return @icons_path if @icons_path
165
-
166
- @icons_path = []
167
- icon_keys.each do |name|
168
- filenames = info.try(:[], name)
169
- .try(:[], 'CFBundlePrimaryIcon')
170
- .try(:[], 'CFBundleIconFiles')
171
-
172
- next if filenames.nil? || filenames.empty?
173
-
174
- filenames.each do |filename|
175
- Dir.glob(File.join(app_path, "#{filename}*")).find_all.each do |file|
176
- @icons_path << file
94
+ @icons_path ||= lambda {
95
+ icon_keys.each_with_object([]) do |name, icons|
96
+ filenames = info.try(:[], name)
97
+ .try(:[], 'CFBundlePrimaryIcon')
98
+ .try(:[], 'CFBundleIconFiles')
99
+
100
+ next if filenames.nil? || filenames.empty?
101
+
102
+ filenames.each do |filename|
103
+ Dir.glob(::File.join(app_path, "#{filename}*")).find_all.each do |file|
104
+ icons << file
105
+ end
177
106
  end
178
107
  end
179
- end
180
-
181
- @icons_path
108
+ }.call
182
109
  end
183
110
 
184
111
  def clear!
@@ -196,17 +123,13 @@ module AppInfo
196
123
  @icons = nil
197
124
  end
198
125
 
199
- def contents
200
- @contents ||= unarchive(@file, path: 'ios')
201
- end
202
-
203
126
  private
204
127
 
205
128
  def build_icon_metadata(file, uncrush: true)
206
129
  uncrushed_file = uncrush ? uncrush_png(file) : nil
207
130
 
208
131
  {
209
- name: File.basename(file),
132
+ name: ::File.basename(file),
210
133
  file: file,
211
134
  uncrushed_file: uncrushed_file,
212
135
  dimensions: PngUncrush.dimensions(file)
@@ -217,16 +140,19 @@ module AppInfo
217
140
  def uncrush_png(src_file)
218
141
  dest_file = tempdir(src_file, prefix: 'uncrushed')
219
142
  PngUncrush.decompress(src_file, dest_file)
220
- File.exist?(dest_file) ? dest_file : nil
143
+ ::File.exist?(dest_file) ? dest_file : nil
221
144
  end
222
145
 
146
+ IPHONE_KEY = 'CFBundleIcons'
147
+ IPAD_KEY = 'CFBundleIcons~ipad'
148
+
223
149
  def icon_keys
224
- @icon_keys ||= case device_type
225
- when 'iPhone'
150
+ @icon_keys ||= case device
151
+ when Device::IPHONE
226
152
  [IPHONE_KEY]
227
- when 'iPad'
153
+ when Device::IPAD
228
154
  [IPAD_KEY]
229
- when 'Universal'
155
+ when Device::UNIVERSAL
230
156
  [IPHONE_KEY, IPAD_KEY]
231
157
  end
232
158
  end
@@ -7,63 +7,42 @@ require 'cfpropertylist'
7
7
 
8
8
  module AppInfo
9
9
  # MacOS App parser
10
- class Macos
11
- include Helper::HumanFileSize
12
- include Helper::Archive
13
- extend Forwardable
14
-
15
- attr_reader :file
16
-
17
- # macOS Export types
18
- module ExportType
19
- DEBUG = 'Debug'
20
- RELEASE = 'Release'
21
- APPSTORE = 'AppStore'
22
- end
23
-
24
- def initialize(file)
25
- @file = file
26
- end
27
-
28
- def size(human_size: false)
29
- file_to_human_size(@file, human_size: human_size)
30
- end
31
-
32
- def os
33
- Platform::MACOS
34
- end
35
- alias file_type os
36
-
37
- def_delegators :info, :macos?, :iphone?, :ipad?, :universal?, :build_version, :name,
38
- :release_version, :identifier, :bundle_id, :display_name,
39
- :bundle_name, :min_system_version, :min_os_version, :device_type
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
- def archs
75
- return unless File.exist?(binary_path)
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
- @binrary_path = nil
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
  }