Skip to content

Commit

Permalink
Merge pull request #76 from InjoyDeng/main
Browse files Browse the repository at this point in the history
  • Loading branch information
icyleaf authored Aug 7, 2024
2 parents 7e92056 + 9845129 commit 1070100
Show file tree
Hide file tree
Showing 22 changed files with 523 additions and 168 deletions.
91 changes: 11 additions & 80 deletions lib/app_info.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
require 'app_info/file'
require 'app_info/info_plist'
require 'app_info/mobile_provision'
require 'app_info/pack_info'

require 'app_info/apple'
require 'app_info/macos'
Expand All @@ -21,16 +22,23 @@
require 'app_info/apk'
require 'app_info/aab'

require 'app_info/harmonyos'
require 'app_info/happ'
require 'app_info/hap'

require 'app_info/proguard'
require 'app_info/dsym'

require 'app_info/pe'
require 'app_info/file_type_detection'

# fix invaild date format warnings
# fix invalid date format warnings
Zip.warn_invalid_date = false

# AppInfo Module
module AppInfo
extend FileTypeDetection

class << self
# Get a new parser for automatic
def parse(file)
Expand All @@ -40,6 +48,8 @@ def parse(file)
when Format::IPA then IPA.new(file)
when Format::APK then APK.new(file)
when Format::AAB then AAB.new(file)
when Format::HAP then HAP.new(file)
when Format::HAPP then HAPP.new(file)
when Format::MOBILEPROVISION then MobileProvision.new(file)
when Format::DSYM then DSYM.new(file)
when Format::PROGUARD then Proguard.new(file)
Expand All @@ -61,89 +71,10 @@ def parse?(file)
file_type(file) != Format::UNKNOWN
end

# Detect file type by read file header
#
# TODO: This can be better solution, if anyone knows, tell me please.
def file_type(file)
header_hex = ::File.read(file, 100)
case header_hex
when ZIP_RETGEX
detect_zip_file(file)
when PE_REGEX
Format::PE
when PLIST_REGEX, BPLIST_REGEX
Format::MOBILEPROVISION
else
Format::UNKNOWN
end
end

def logger
@logger ||= Logger.new($stdout, level: :warn)
end

attr_writer :logger

private

# :nodoc:
def detect_zip_file(file)
Zip.warn_invalid_date = false
zip_file = Zip::File.open(file)

return Format::PROGUARD if proguard_clues?(zip_file)
return Format::APK if apk_clues?(zip_file)
return Format::AAB if aab_clues?(zip_file)
return Format::MACOS if macos_clues?(zip_file)
return Format::PE if pe_clues?(zip_file)
return Format::UNKNOWN unless clue = other_clues?(zip_file)

clue
ensure
zip_file.close
end

# :nodoc:
def proguard_clues?(zip_file)
!zip_file.glob('*mapping*.txt').empty?
end

# :nodoc:
def apk_clues?(zip_file)
!zip_file.find_entry('AndroidManifest.xml').nil? &&
!zip_file.find_entry('classes.dex').nil?
end

# :nodoc:
def aab_clues?(zip_file)
!zip_file.find_entry('base/manifest/AndroidManifest.xml').nil? &&
!zip_file.find_entry('BundleConfig.pb').nil?
end

# :nodoc:
def macos_clues?(zip_file)
!zip_file.glob('*/Contents/MacOS/*').empty? &&
!zip_file.glob('*/Contents/Info.plist').empty?
end

# :nodoc:
def pe_clues?(zip_file)
!zip_file.glob('*.exe').empty?
end

# :nodoc:
def other_clues?(zip_file)
zip_file.each do |f|
path = f.name

return Format::IPA if path.include?('Payload/') && path.end_with?('Info.plist')
return Format::DSYM if path.include?('Contents/Resources/DWARF/')
end
end
end

ZIP_RETGEX = /^\x50\x4b\x03\x04/.freeze
PE_REGEX = /^MZ/.freeze
PLIST_REGEX = /\x3C\x3F\x78\x6D\x6C/.freeze
BPLIST_REGEX = /^\x62\x70\x6C\x69\x73\x74/.freeze
end
10 changes: 5 additions & 5 deletions lib/app_info/android.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,15 @@ def platform
# @return [Symbol] {Device}
def device
if watch?
Device::WATCH
Device::Google::WATCH
elsif television?
Device::TELEVISION
Device::Google::TELEVISION
elsif automotive?
Device::AUTOMOTIVE
Device::Google::AUTOMOTIVE
elsif tablet?
Device::TABLET
Device::Google::TABLET
else
Device::PHONE
Device::Google::PHONE
end
end

Expand Down
86 changes: 58 additions & 28 deletions lib/app_info/const.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ module Format
AAB = :aab
PROGUARD = :proguard

# HarmonyOS

HAP = :hap
HAPP = :app

# Windows

PE = :pe
Expand All @@ -35,6 +40,7 @@ module Manufacturer
APPLE = :apple
GOOGLE = :google
MICROSOFT = :microsoft
HUAWEI = :huawei
end

# Platform
Expand All @@ -44,36 +50,60 @@ module Platform
ANDROID = :android
APPLETV = :appletv
WINDOWS = :windows
HARMONYOS = :harmonyos
end

# Apple Device Type
# Device Type
module Device
# macOS
MACOS = :macos

# Apple iPhone
IPHONE = :iphone
# Apple iPad
IPAD = :ipad
# Apple Universal (iPhone and iPad)
UNIVERSAL = :universal
# Apple TV
APPLETV = :appletv
# Apple Watch (TODO: not implemented yet)
IWATCH = :iwatch

# Android Phone
PHONE = :phone
# Android Tablet (TODO: not implemented yet)
TABLET = :tablet
# Android Watch
WATCH = :watch
# Android TV
TELEVISION = :television
# Android Car Automotive
AUTOMOTIVE = :automotive

# Windows
WINDOWS = :windows
module Apple
# macOS
MACOS = :macos

# Apple iPhone
IPHONE = :iphone
# Apple iPad
IPAD = :ipad
# Apple Universal (iPhone and iPad)
UNIVERSAL = :universal
# Apple TV
APPLETV = :appletv
# Apple Watch (TODO: not implemented yet)
IWATCH = :iwatch
end

module Google
# Android Phone
PHONE = :phone
# Android Tablet (TODO: not implemented yet)
TABLET = :tablet
# Android Watch
WATCH = :watch
# Android TV
TELEVISION = :television
# Android Car Automotive
AUTOMOTIVE = :automotive
end

module Huawei
# HarmonyOS Default
DEFAULT = :default
# HarmonyOS Phone
PHONE = :phone
# HarmonyOS Tablet
TABLET = :tablet
# HarmonyOS TV
TV = :tv
# HarmonyOS wearable
WEARABLE = :wearable
# HarmonyOS Car
CAR = :car
# HarmonyOS 2-in-1 tablet and laptop
TWO_IN_ONE = :two_in_one
end

module Microsoft
# Windows
WINDOWS = :windows
end
end
end
111 changes: 111 additions & 0 deletions lib/app_info/file_type_detection.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# frozen_string_literal: true

module AppInfo
module FileTypeDetection
# Detect file type by reading file header
#
# TODO: This can be better solution, if anyone knows, tell me please.
def file_type(file)
header_hex = ::File.read(file, 100)
case header_hex
when ZIP_RETGEX
detect_zip_file(file)
when PE_REGEX
Format::PE
when PLIST_REGEX, BPLIST_REGEX
Format::MOBILEPROVISION
else
Format::UNKNOWN
end
end

private

# Detect file type for zip files
def detect_zip_file(file)
Zip.warn_invalid_date = false
zip_file = Zip::File.open(file)

return Format::PROGUARD if proguard_clues?(zip_file)
return Format::APK if apk_clues?(zip_file)
return Format::AAB if aab_clues?(zip_file)
return Format::MACOS if macos_clues?(zip_file)
return Format::PE if pe_clues?(zip_file)
return Format::HAP if hap_clues?(zip_file)
return Format::HAPP if happ_clues?(zip_file)
return Format::UNKNOWN unless clue = other_clues?(zip_file)

clue
ensure
zip_file.close
end

# Check for Proguard clues in zip file
def proguard_clues?(zip_file)
!zip_file.glob('*mapping*.txt').empty?
end

# Check for APK clues in zip file
def apk_clues?(zip_file)
!zip_file.find_entry('AndroidManifest.xml').nil? &&
!zip_file.find_entry('classes.dex').nil?
end

# Check for AAB clues in zip file
def aab_clues?(zip_file)
!zip_file.find_entry('base/manifest/AndroidManifest.xml').nil? &&
!zip_file.find_entry('BundleConfig.pb').nil?
end

# Check for macOS clues in zip file
def macos_clues?(zip_file)
!zip_file.glob('*/Contents/MacOS/*').empty? &&
!zip_file.glob('*/Contents/Info.plist').empty?
end

# Check for PE clues in zip file
def pe_clues?(zip_file)
!zip_file.glob('*.exe').empty?
end

# Check for HAP clues in zip file
def hap_clues?(zip_file)
!zip_file.find_entry('pack.info').nil? && !zip_file.find_entry('module.json').nil?
end

# Check for HAPP clues in zip file
def happ_clues?(zip_file)
pack_info_count = 0
hap_count = 0

zip_file.each do |f|
path = f.name

if path == 'pack.info'
pack_info_count += 1
elsif path.end_with?('.hap')
hap_count += 1
else
return false
end
end

pack_info_count == 1 && hap_count >= 1
end

# Check for other clues in zip file
def other_clues?(zip_file)
zip_file.each do |f|
path = f.name

return Format::IPA if path.include?('Payload/') && path.end_with?('Info.plist')
return Format::DSYM if path.include?('Contents/Resources/DWARF/')
end
end

ZIP_RETGEX = /^\x50\x4b\x03\x04/.freeze
PE_REGEX = /^MZ/.freeze
PLIST_REGEX = /\x3C\x3F\x78\x6D\x6C/.freeze
BPLIST_REGEX = /^\x62\x70\x6C\x69\x73\x74/.freeze
end
end
Loading

0 comments on commit 1070100

Please sign in to comment.