app-info 3.0.0.beta1 → 3.0.0.beta3
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/.rubocop.yml +2 -0
- data/CHANGELOG.md +29 -3
- data/README.md +4 -4
- data/lib/app_info/aab.rb +57 -114
- data/lib/app_info/android/signature.rb +5 -5
- data/lib/app_info/android/signatures/base.rb +41 -37
- data/lib/app_info/android/signatures/info.rb +135 -129
- data/lib/app_info/android/signatures/v1.rb +56 -52
- data/lib/app_info/android/signatures/v2.rb +114 -110
- data/lib/app_info/android/signatures/v3.rb +124 -120
- data/lib/app_info/android/signatures/v4.rb +13 -9
- data/lib/app_info/android.rb +181 -0
- data/lib/app_info/apk.rb +68 -100
- data/lib/app_info/apple.rb +192 -0
- data/lib/app_info/certificate.rb +14 -19
- data/lib/app_info/const.rb +48 -13
- data/lib/app_info/dsym.rb +6 -3
- data/lib/app_info/error.rb +1 -7
- data/lib/app_info/file.rb +30 -4
- data/lib/app_info/helper/file_size.rb +1 -1
- data/lib/app_info/info_plist.rb +54 -25
- data/lib/app_info/ipa.rb +39 -118
- data/lib/app_info/macos.rb +38 -94
- data/lib/app_info/mobile_provision.rb +49 -20
- data/lib/app_info/pe.rb +103 -7
- data/lib/app_info/png_uncrush.rb +19 -0
- data/lib/app_info/proguard.rb +21 -2
- data/lib/app_info/protobuf/manifest.rb +5 -1
- data/lib/app_info/version.rb +1 -1
- data/lib/app_info.rb +4 -3
- metadata +4 -2
data/lib/app_info/ipa.rb
CHANGED
@@ -6,125 +6,47 @@ require 'forwardable'
|
|
6
6
|
require 'cfpropertylist'
|
7
7
|
|
8
8
|
module AppInfo
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
#
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
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]
|
37
|
-
def size(human_size: false)
|
38
|
-
file_to_human_size(@file, human_size: human_size)
|
39
|
-
end
|
40
|
-
|
41
|
-
def file_type
|
42
|
-
Format::IPA
|
43
|
-
end
|
44
|
-
|
45
|
-
def platform
|
46
|
-
Platform::IOS
|
47
|
-
end
|
48
|
-
|
49
|
-
def_delegators :info, :iphone?, :ipad?, :universal?, :build_version, :name,
|
50
|
-
:release_version, :identifier, :bundle_id, :display_name,
|
51
|
-
:bundle_name, :min_sdk_version, :min_os_version, :device_type
|
52
|
-
|
53
|
-
def_delegators :mobileprovision, :devices, :team_name, :team_identifier,
|
54
|
-
:profile_name, :expired_date
|
55
|
-
|
56
|
-
def distribution_name
|
57
|
-
"#{profile_name} - #{team_name}" if profile_name && team_name
|
58
|
-
end
|
59
|
-
|
60
|
-
def release_type
|
61
|
-
if stored?
|
62
|
-
ExportType::RELEASE
|
63
|
-
else
|
64
|
-
build_type
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
def build_type
|
69
|
-
if mobileprovision?
|
70
|
-
if devices
|
71
|
-
ExportType::ADHOC
|
72
|
-
else
|
73
|
-
ExportType::ENTERPRISE
|
74
|
-
end
|
75
|
-
else
|
76
|
-
ExportType::DEBUG
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
def archs
|
81
|
-
return unless ::File.exist?(bundle_path)
|
82
|
-
|
83
|
-
file = MachO.open(bundle_path)
|
84
|
-
case file
|
85
|
-
when MachO::MachOFile
|
86
|
-
[file.cpusubtype]
|
87
|
-
else
|
88
|
-
file.machos.each_with_object([]) do |arch, obj|
|
89
|
-
obj << arch.cpusubtype
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
93
|
-
alias architectures archs
|
94
|
-
|
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
|
95
28
|
def icons(uncrush: true)
|
96
29
|
@icons ||= icons_path.each_with_object([]) do |file, obj|
|
97
30
|
obj << build_icon_metadata(file, uncrush: uncrush)
|
98
31
|
end
|
99
32
|
end
|
100
33
|
|
34
|
+
# @return [Boolean]
|
101
35
|
def stored?
|
102
36
|
!!metadata?
|
103
37
|
end
|
104
38
|
|
39
|
+
# @return [Array<Plugin>]
|
105
40
|
def plugins
|
106
41
|
@plugins ||= Plugin.parse(app_path)
|
107
42
|
end
|
108
43
|
|
44
|
+
# @return [Array<Framework>]
|
109
45
|
def frameworks
|
110
46
|
@frameworks ||= Framework.parse(app_path)
|
111
47
|
end
|
112
48
|
|
113
|
-
|
114
|
-
mobileprovision.delete('DeveloperCertificates') if mobileprovision?
|
115
|
-
end
|
116
|
-
|
117
|
-
def mobileprovision
|
118
|
-
return unless mobileprovision?
|
119
|
-
return @mobileprovision if @mobileprovision
|
120
|
-
|
121
|
-
@mobileprovision = MobileProvision.new(mobileprovision_path)
|
122
|
-
end
|
123
|
-
|
124
|
-
def mobileprovision?
|
125
|
-
::File.exist?(mobileprovision_path)
|
126
|
-
end
|
127
|
-
|
49
|
+
# @return [String]
|
128
50
|
def mobileprovision_path
|
129
51
|
filename = 'embedded.mobileprovision'
|
130
52
|
@mobileprovision_path ||= ::File.join(@file, filename)
|
@@ -135,39 +57,39 @@ module AppInfo
|
|
135
57
|
@mobileprovision_path
|
136
58
|
end
|
137
59
|
|
60
|
+
# @return [CFPropertyList]
|
138
61
|
def metadata
|
139
62
|
return unless metadata?
|
140
63
|
|
141
64
|
@metadata ||= CFPropertyList.native_types(CFPropertyList::List.new(file: metadata_path).value)
|
142
65
|
end
|
143
66
|
|
67
|
+
# @return [Boolean]
|
144
68
|
def metadata?
|
145
69
|
::File.exist?(metadata_path)
|
146
70
|
end
|
147
71
|
|
72
|
+
# @return [String]
|
148
73
|
def metadata_path
|
149
74
|
@metadata_path ||= ::File.join(contents, 'iTunesMetadata.plist')
|
150
75
|
end
|
151
76
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
def info
|
157
|
-
@info ||= InfoPlist.new(info_path)
|
77
|
+
# @return [String]
|
78
|
+
def binary_path
|
79
|
+
@binary_path ||= ::File.join(app_path, info.bundle_name)
|
158
80
|
end
|
159
81
|
|
82
|
+
# @return [String]
|
160
83
|
def info_path
|
161
84
|
@info_path ||= ::File.join(app_path, 'Info.plist')
|
162
85
|
end
|
163
86
|
|
87
|
+
# @return [String]
|
164
88
|
def app_path
|
165
89
|
@app_path ||= Dir.glob(::File.join(contents, 'Payload', '*.app')).first
|
166
90
|
end
|
167
91
|
|
168
|
-
|
169
|
-
IPAD_KEY = 'CFBundleIcons~ipad'
|
170
|
-
|
92
|
+
# @return [Array<String>]
|
171
93
|
def icons_path
|
172
94
|
@icons_path ||= lambda {
|
173
95
|
icon_keys.each_with_object([]) do |name, icons|
|
@@ -201,10 +123,6 @@ module AppInfo
|
|
201
123
|
@icons = nil
|
202
124
|
end
|
203
125
|
|
204
|
-
def contents
|
205
|
-
@contents ||= unarchive(@file, prefix: 'ios')
|
206
|
-
end
|
207
|
-
|
208
126
|
private
|
209
127
|
|
210
128
|
def build_icon_metadata(file, uncrush: true)
|
@@ -225,13 +143,16 @@ module AppInfo
|
|
225
143
|
::File.exist?(dest_file) ? dest_file : nil
|
226
144
|
end
|
227
145
|
|
146
|
+
IPHONE_KEY = 'CFBundleIcons'
|
147
|
+
IPAD_KEY = 'CFBundleIcons~ipad'
|
148
|
+
|
228
149
|
def icon_keys
|
229
|
-
@icon_keys ||= case
|
230
|
-
when
|
150
|
+
@icon_keys ||= case device
|
151
|
+
when Device::IPHONE
|
231
152
|
[IPHONE_KEY]
|
232
|
-
when
|
153
|
+
when Device::IPAD
|
233
154
|
[IPAD_KEY]
|
234
|
-
when
|
155
|
+
when Device::UNIVERSAL
|
235
156
|
[IPHONE_KEY, IPAD_KEY]
|
236
157
|
end
|
237
158
|
end
|
data/lib/app_info/macos.rb
CHANGED
@@ -7,66 +7,37 @@ require 'cfpropertylist'
|
|
7
7
|
|
8
8
|
module AppInfo
|
9
9
|
# MacOS App parser
|
10
|
-
class Macos <
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
#
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
#
|
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'
|
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
|
+
# # ]
|
30
25
|
#
|
31
|
-
# @
|
32
|
-
#
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
:release_version, :identifier, :bundle_id, :display_name,
|
47
|
-
:bundle_name, :min_system_version, :min_os_version, :device_type
|
48
|
-
|
49
|
-
def_delegators :mobileprovision, :team_name, :team_identifier,
|
50
|
-
:profile_name, :expired_date
|
51
|
-
|
52
|
-
def distribution_name
|
53
|
-
"#{profile_name} - #{team_name}" if profile_name && team_name
|
54
|
-
end
|
55
|
-
|
56
|
-
def release_type
|
57
|
-
if stored?
|
58
|
-
ExportType::APPSTORE
|
59
|
-
elsif mobileprovision?
|
60
|
-
ExportType::RELEASE
|
61
|
-
else
|
62
|
-
ExportType::DEBUG
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
def stored?
|
67
|
-
::File.exist?(store_path)
|
68
|
-
end
|
69
|
-
|
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
|
70
41
|
def icons(convert: true)
|
71
42
|
return unless icon_file
|
72
43
|
|
@@ -79,43 +50,22 @@ module AppInfo
|
|
79
50
|
data
|
80
51
|
end
|
81
52
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
file = MachO.open(binary_path)
|
86
|
-
case file
|
87
|
-
when MachO::MachOFile
|
88
|
-
[file.cpusubtype]
|
89
|
-
else
|
90
|
-
file.machos.each_with_object([]) do |arch, obj|
|
91
|
-
obj << arch.cpusubtype
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
95
|
-
alias architectures archs
|
96
|
-
|
97
|
-
def hide_developer_certificates
|
98
|
-
mobileprovision.delete('DeveloperCertificates') if mobileprovision?
|
99
|
-
end
|
100
|
-
|
101
|
-
def mobileprovision
|
102
|
-
return unless mobileprovision?
|
103
|
-
|
104
|
-
@mobileprovision ||= MobileProvision.new(mobileprovision_path)
|
105
|
-
end
|
106
|
-
|
107
|
-
def mobileprovision?
|
108
|
-
::File.exist?(mobileprovision_path)
|
53
|
+
# @return [Boolean]
|
54
|
+
def stored?
|
55
|
+
::File.exist?(store_path)
|
109
56
|
end
|
110
57
|
|
58
|
+
# @return [String]
|
111
59
|
def mobileprovision_path
|
112
60
|
@mobileprovision_path ||= ::File.join(app_path, 'Contents', 'embedded.provisionprofile')
|
113
61
|
end
|
114
62
|
|
63
|
+
# @return [String]
|
115
64
|
def store_path
|
116
65
|
@store_path ||= ::File.join(app_path, 'Contents', '_MASReceipt', 'receipt')
|
117
66
|
end
|
118
67
|
|
68
|
+
# @return [String]
|
119
69
|
def binary_path
|
120
70
|
return @binary_path if @binary_path
|
121
71
|
|
@@ -126,14 +76,12 @@ module AppInfo
|
|
126
76
|
@binary_path ||= Dir.glob(::File.join(base_path, '*')).first
|
127
77
|
end
|
128
78
|
|
129
|
-
|
130
|
-
@info ||= InfoPlist.new(info_path)
|
131
|
-
end
|
132
|
-
|
79
|
+
# @return [String]
|
133
80
|
def info_path
|
134
81
|
@info_path ||= ::File.join(app_path, 'Contents', 'Info.plist')
|
135
82
|
end
|
136
83
|
|
84
|
+
# @return [String]
|
137
85
|
def app_path
|
138
86
|
@app_path ||= Dir.glob(::File.join(contents, '*.app')).first
|
139
87
|
end
|
@@ -151,10 +99,6 @@ module AppInfo
|
|
151
99
|
@icons = nil
|
152
100
|
end
|
153
101
|
|
154
|
-
def contents
|
155
|
-
@contents ||= unarchive(@file, prefix: 'macos')
|
156
|
-
end
|
157
|
-
|
158
102
|
private
|
159
103
|
|
160
104
|
def icon_file
|
@@ -4,20 +4,37 @@ require 'openssl'
|
|
4
4
|
require 'cfpropertylist'
|
5
5
|
|
6
6
|
module AppInfo
|
7
|
-
#
|
7
|
+
# Apple code signing: provisioning profile parser
|
8
|
+
# @see https://developer.apple.com/documentation/technotes/tn3125-inside-code-signing-provisioning-profiles
|
8
9
|
class MobileProvision < File
|
9
|
-
|
10
|
-
|
10
|
+
# @return [Symbol] {Manufacturer}
|
11
|
+
def manufacturer
|
12
|
+
Manufacturer::APPLE
|
11
13
|
end
|
12
14
|
|
15
|
+
# @return [Symbol] {Platform}
|
16
|
+
def platform
|
17
|
+
case platforms[0]
|
18
|
+
when :macos
|
19
|
+
Platform::MACOS
|
20
|
+
when :ios
|
21
|
+
Platform::IOS
|
22
|
+
else
|
23
|
+
raise NotImplementedError, "Unkonwn platform: #{platforms[0]}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# @return [String, nil]
|
13
28
|
def name
|
14
29
|
mobileprovision.try(:[], 'Name')
|
15
30
|
end
|
16
31
|
|
32
|
+
# @return [String, nil]
|
17
33
|
def app_name
|
18
34
|
mobileprovision.try(:[], 'AppIDName')
|
19
35
|
end
|
20
36
|
|
37
|
+
# @return [Symbol, nil]
|
21
38
|
def type
|
22
39
|
return :development if development?
|
23
40
|
return :adhoc if adhoc?
|
@@ -25,6 +42,7 @@ module AppInfo
|
|
25
42
|
return :enterprise if enterprise?
|
26
43
|
end
|
27
44
|
|
45
|
+
# @return [Array<Symbol>]
|
28
46
|
def platforms
|
29
47
|
return unless platforms = mobileprovision.try(:[], 'Platform')
|
30
48
|
|
@@ -34,34 +52,37 @@ module AppInfo
|
|
34
52
|
end
|
35
53
|
end
|
36
54
|
|
37
|
-
|
38
|
-
platforms[0]
|
39
|
-
end
|
40
|
-
|
55
|
+
# @return [Array<String>, nil]
|
41
56
|
def devices
|
42
57
|
mobileprovision.try(:[], 'ProvisionedDevices')
|
43
58
|
end
|
44
59
|
|
60
|
+
# @return [String, nil]
|
45
61
|
def team_identifier
|
46
62
|
mobileprovision.try(:[], 'TeamIdentifier')
|
47
63
|
end
|
48
64
|
|
65
|
+
# @return [String, nil]
|
49
66
|
def team_name
|
50
67
|
mobileprovision.try(:[], 'TeamName')
|
51
68
|
end
|
52
69
|
|
70
|
+
# @return [String, nil]
|
53
71
|
def profile_name
|
54
72
|
mobileprovision.try(:[], 'Name')
|
55
73
|
end
|
56
74
|
|
75
|
+
# @return [String, nil]
|
57
76
|
def created_date
|
58
77
|
mobileprovision.try(:[], 'CreationDate')
|
59
78
|
end
|
60
79
|
|
80
|
+
# @return [String, nil]
|
61
81
|
def expired_date
|
62
82
|
mobileprovision.try(:[], 'ExpirationDate')
|
63
83
|
end
|
64
84
|
|
85
|
+
# @return [Array<String>, nil]
|
65
86
|
def entitlements
|
66
87
|
mobileprovision.try(:[], 'Entitlements')
|
67
88
|
end
|
@@ -87,40 +108,44 @@ module AppInfo
|
|
87
108
|
|
88
109
|
# Detect is development type of mobileprovision
|
89
110
|
#
|
90
|
-
#
|
111
|
+
# @see https://stackoverflow.com/questions/1003066/what-does-get-task-allow-do-in-xcode
|
112
|
+
# @return [Boolea]
|
91
113
|
def development?
|
92
|
-
case platform
|
93
|
-
when
|
114
|
+
case platform
|
115
|
+
when Platform::IOS
|
94
116
|
entitlements['get-task-allow'] == true
|
95
|
-
when
|
117
|
+
when Platform::MACOS
|
96
118
|
!devices.nil?
|
97
119
|
else
|
98
|
-
raise
|
120
|
+
raise NotImplementedError, "Unknown platform: #{platform}"
|
99
121
|
end
|
100
122
|
end
|
101
123
|
|
102
124
|
# Detect app store type
|
103
125
|
#
|
104
|
-
#
|
126
|
+
# @see https://developer.apple.com/library/archive/qa/qa1830/_index.html
|
127
|
+
# @return [Boolea]
|
105
128
|
def appstore?
|
106
|
-
case platform
|
107
|
-
when
|
129
|
+
case platform
|
130
|
+
when Platform::IOS
|
108
131
|
!development? && entitlements.key?('beta-reports-active')
|
109
|
-
when
|
132
|
+
when Platform::MACOS
|
110
133
|
!development?
|
111
134
|
else
|
112
|
-
raise
|
135
|
+
raise NotImplementedError, "Unknown platform: #{platform}"
|
113
136
|
end
|
114
137
|
end
|
115
138
|
|
139
|
+
# @return [Boolea]
|
116
140
|
def adhoc?
|
117
|
-
return false if platform ==
|
141
|
+
return false if platform == Platform::MACOS # macOS no need adhoc
|
118
142
|
|
119
143
|
!development? && !devices.nil?
|
120
144
|
end
|
121
145
|
|
146
|
+
# @return [Boolea]
|
122
147
|
def enterprise?
|
123
|
-
return false if platform ==
|
148
|
+
return false if platform == Platform::MACOS # macOS no need adhoc
|
124
149
|
|
125
150
|
!development? && !adhoc? && !appstore?
|
126
151
|
end
|
@@ -128,7 +153,8 @@ module AppInfo
|
|
128
153
|
|
129
154
|
# Enabled Capabilites
|
130
155
|
#
|
131
|
-
#
|
156
|
+
# @see https://developer.apple.com/support/app-capabilities/
|
157
|
+
# @return [Array<String>]
|
132
158
|
def enabled_capabilities
|
133
159
|
capabilities = []
|
134
160
|
capabilities << 'In-App Purchase' << 'GameKit' if adhoc? || appstore?
|
@@ -202,14 +228,17 @@ module AppInfo
|
|
202
228
|
capabilities
|
203
229
|
end
|
204
230
|
|
231
|
+
# @return [String, nil]
|
205
232
|
def [](key)
|
206
233
|
mobileprovision.try(:[], key.to_s)
|
207
234
|
end
|
208
235
|
|
236
|
+
# @return [Boolea]
|
209
237
|
def empty?
|
210
238
|
mobileprovision.nil?
|
211
239
|
end
|
212
240
|
|
241
|
+
# @return [CFPropertyList]
|
213
242
|
def mobileprovision
|
214
243
|
return @mobileprovision = nil unless ::File.exist?(@file)
|
215
244
|
|