mootool 0.2.2 → 0.2.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5a3b78029772e10d48f7e6c2937c241ff0783f03be555234cd77c5b72cbf10eb
4
- data.tar.gz: d1303b8e5bfdf05bb7a10c86d161fb5ffafa237586f25137e556a35f49b8ec75
3
+ metadata.gz: 4cfbbe3c322b64f68aa32ecfd9373b4158cabb53cec3c6ba392f6c8e1d9a7761
4
+ data.tar.gz: 9ec26119e06df11ccae1aa7eb28796db2d8a6b3af889ba20882ca22847274bff
5
5
  SHA512:
6
- metadata.gz: ae85a488ccf2023d087ae7fc3a6f63b09f3cff51a14555f0e49742e5556b33e898dbafd377ec481a42a23801eb4987155aad924e7e461b5578fff4efc215a35d
7
- data.tar.gz: bed2644636530b161772dc0fa430845fbebfcf057b1bdb47aa0b898129def0eeef0b0434bbea3922de9b88bf8b44d02cc8dd874f8329f7b976d03691c3e1bb84
6
+ metadata.gz: eeed0e6c5d966626700309b618f517169b14d643e76ba9af7f48d66e1c6fae173129011e81f425c9eb209d312f0007ce03be2978520df4d8ebbf1eef585d437a
7
+ data.tar.gz: 7501f0bd4de48f2decc42d5c62ebdcaedf3a9e1720c72a316060eb02a3943032f87120927ac3bebd3b3e068691e3ed42c27b833884141ffbb2ec6a3fdad30046
@@ -16,8 +16,9 @@ on:
16
16
  jobs:
17
17
  test:
18
18
 
19
- runs-on: ubuntu-22.04
19
+ runs-on: ubuntu-latest
20
20
  strategy:
21
+ fail-fast: false
21
22
  matrix:
22
23
  ruby-version: [ '3.0', '3.1.2', '3.2.0-preview1' ]
23
24
 
@@ -27,7 +28,7 @@ jobs:
27
28
  # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
28
29
  # change this to (see https://github.com/ruby/setup-ruby#versioning):
29
30
  # uses: ruby/setup-ruby@v1
30
- uses: ruby/setup-ruby@473e4d8fe5dd94ee328fdfca9f8c9c7afc9dae5e
31
+ uses: ruby/setup-ruby@v1
31
32
  with:
32
33
  ruby-version: ${{ matrix.ruby-version }}
33
34
  bundler-cache: true # runs 'bundle install' and caches installed gems automatically
data/Gemfile.lock CHANGED
@@ -1,8 +1,11 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- mootool (0.2.2)
4
+ mootool (0.2.5)
5
+ lzfse
6
+ lzss
5
7
  plist (~> 3)
8
+ ruby-lzma
6
9
  ruby-macho (~> 3)
7
10
  rubyzip (~> 2)
8
11
  sorbet-runtime (~> 0)
@@ -17,6 +20,8 @@ GEM
17
20
  docile (1.4.0)
18
21
  iniparse (1.5.0)
19
22
  json (2.6.2)
23
+ lzfse (0.0.1)
24
+ lzss (0.1)
20
25
  method_source (1.0.0)
21
26
  netrc (0.11.0)
22
27
  overcommit (0.59.1)
@@ -68,6 +73,7 @@ GEM
68
73
  rubocop (~> 1.0)
69
74
  rubocop-rspec (2.12.1)
70
75
  rubocop (~> 1.31)
76
+ ruby-lzma (0.4.3)
71
77
  ruby-macho (3.0.0)
72
78
  ruby-progressbar (1.11.0)
73
79
  rubyzip (2.3.2)
@@ -90,7 +96,7 @@ GEM
90
96
  sorbet (>= 0.5.9204)
91
97
  sorbet-runtime (>= 0.5.9204)
92
98
  thor (>= 0.19.2)
93
- tapioca (0.9.3)
99
+ tapioca (0.9.4)
94
100
  bundler (>= 1.17.3)
95
101
  netrc (>= 0.11.0)
96
102
  parallel (>= 1.21.0)
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'lzfse'
4
+ require 'lzma'
5
+ require 'compress/lzss'
6
+
7
+ module MooTool
8
+ # The magic Apple decompressor (as in it uses magics)
9
+ class Decompressor
10
+ COMPRESSION_LZSS = 'lzss'
11
+ COMPRESSION_LZVN = 'lzvn'
12
+ COMPRESSION_LZFSE = 'bvx2'
13
+ COMPRESSION_LZMA = 'lzma'
14
+
15
+ attr_reader :value
16
+
17
+ def initialize(data)
18
+ @value = case data[0..3]
19
+ when COMPRESSION_LZFSE
20
+ LZFSE.lzfse_decompress(data)
21
+ when COMPRESSION_LZVN
22
+ LZFSE.lzvn_decompress(data)
23
+ when COMPRESSION_LZSS
24
+ Compress::LZSS.decompress(data)
25
+ when COMPRESSION_LZMA
26
+ LZMA.decompress(data)
27
+ else
28
+ data
29
+ end
30
+ end
31
+ end
32
+ end
@@ -4,82 +4,114 @@
4
4
  require 'sorbet-runtime'
5
5
 
6
6
  module MooTool
7
- module Models
8
- # DeviceTree is a Apple Device Tree node that has been parsed
9
- class DeviceTree
10
- extend T::Sig
7
+ # DeviceTree is a Apple Device Tree node that has been parsed
8
+ class DeviceTree
9
+ extend T::Sig
10
+
11
+ NODE_FORMAT = 'VV'
12
+ PROP_FORMAT = 'A32V'
11
13
 
12
- NODE_FORMAT = 'VV'
13
- PROP_FORMAT = 'A32V'
14
+ PHANDLE_PROP = 'AAPL,phandle'
15
+ COMPATIBLE_PROP = 'compatible'
14
16
 
15
- # Represents a single node in the device tree
16
- class Node
17
- extend T::Sig
17
+ # Represents a single node in the device tree
18
+ class Node
19
+ extend T::Sig
18
20
 
19
- attr_reader :children, :properties
21
+ attr_reader :children, :properties
20
22
 
21
- sig { params(data: T.any(IO, StringIO)).void }
22
- def initialize(data)
23
- vals = T.must(data.read(8)).unpack(NODE_FORMAT)
24
- property_count = T.cast(vals[0], Integer)
25
- child_count = T.cast(vals[1], Integer)
23
+ sig { params(tree: DeviceTree, data: T.any(IO, StringIO)).void }
24
+ def initialize(tree, data)
25
+ @tree = tree
26
+ vals = T.must(data.read(8)).unpack(NODE_FORMAT)
27
+ property_count = T.cast(vals[0], Integer)
28
+ child_count = T.cast(vals[1], Integer)
26
29
 
27
- @properties = T.let({}, T::Hash[String, Property])
28
- @children = T.let([], T::Array[Node])
30
+ @properties = T.let({}, T::Hash[String, Property])
31
+ @children = T.let([], T::Array[Node])
29
32
 
30
- property_count.times do
31
- prop = Property.new(data)
32
- @properties[prop.name] = prop
33
- end
34
- child_count.times { @children << Node.new(data) }
33
+ property_count.times do
34
+ prop = Property.new(data)
35
+ @properties[prop.name] = prop
35
36
  end
37
+ child_count.times { @children << Node.new(tree, data) }
38
+
39
+ @tree.add_handle(self, @properties[PHANDLE_PROP].value) if @properties.key? PHANDLE_PROP
36
40
  end
37
41
 
38
- # Represents a single property and it's value
39
- class Property
40
- extend T::Sig
42
+ def to_h
43
+ props = @properties.transform_values(&:value)
44
+ if @children.any?
45
+ props.merge({ children: @children.map(&:to_h) })
46
+ else
47
+ props
48
+ end
49
+ end
50
+ end
41
51
 
42
- attr_accessor :name, :value
52
+ # Represents a single property and it's value
53
+ class Property
54
+ extend T::Sig
43
55
 
44
- sig { params(data: T.any(StringIO, IO)).void }
45
- def initialize(data)
46
- args = T.must(data.read(36)).unpack(PROP_FORMAT)
56
+ attr_accessor :name, :value
47
57
 
48
- @name = T.let(T.cast(args[0], String), String)
49
- @size = T.let(T.cast(args[1], Integer), Integer)
58
+ sig { params(data: T.any(StringIO, IO)).void }
59
+ def initialize(data)
60
+ args = T.must(data.read(36)).unpack(PROP_FORMAT)
50
61
 
51
- if @size & 0x80000000 != 0
52
- @template = true
53
- @size &= 0x7fffffff
54
- end
62
+ @name = T.let(T.cast(args[0], String), String)
63
+ @size = T.let(T.cast(args[1], Integer), Integer)
55
64
 
56
- @value = data.read(@size.align(4))
57
- @value = T.must(@value)[0..@size]
65
+ if @size & 0x80000000 != 0
66
+ @template = true
67
+ @size &= 0x7fffffff
58
68
  end
69
+
70
+ @value = T.must(data.read(@size.align(4)))[0..(@size - 1)]
71
+
72
+ normalize
59
73
  end
60
74
 
61
- attr_reader :root
75
+ private
62
76
 
63
- # @param [String] data
64
- sig { params(data: T.any(IO, String, StringIO, Pathname)).void }
65
- def initialize(data)
66
- case data
67
- when Pathname
68
- data = T.assert_type!(data, Pathname)
69
- @data = File.open(data.realpath, 'rb')
70
- when String
71
- data = T.assert_type!(data, String)
72
- @data = StringIO.new(data)
73
- when IO
74
- @data = T.cast(data, IO)
75
- end
76
- @root = Node.new(@data)
77
+ def normalize
78
+ @value = @value.split("\x00").map(&:chomp) if @name == COMPATIBLE_PROP
79
+ @value = @value.unpack1('V') if @size == 4
80
+
81
+ @value = @value.chomp("\x00") if @value.is_a?(String) && @value.count("\x00") == 1 && @value.end_with?("\x00")
77
82
  end
83
+ end
78
84
 
79
- sig { params(path: String).returns(DeviceTree) }
80
- def self.open(path)
81
- DeviceTree.new(Pathname.new(path))
85
+ attr_reader :root
86
+
87
+ # @param [String] data
88
+ sig { params(data: T.any(IO, String, StringIO, Pathname)).void }
89
+ def initialize(data)
90
+ @handles = {}
91
+ case data
92
+ when Pathname
93
+ data = T.assert_type!(data, Pathname)
94
+ @data = File.open(data.realpath, 'rb')
95
+ when String
96
+ data = T.assert_type!(data, String)
97
+ @data = StringIO.new(data)
98
+ when IO
99
+ @data = T.cast(data, IO)
82
100
  end
101
+ @root = Node.new(self, @data)
102
+ end
103
+
104
+ def add_handle(node, handle)
105
+ @handles[handle] = node
106
+ end
107
+
108
+ sig { params(path: String).returns(DeviceTree) }
109
+ def self.open(path)
110
+ MooTool::DeviceTree.new(Pathname.new(path))
111
+ end
112
+
113
+ def to_h
114
+ @root.to_h
83
115
  end
84
116
  end
85
117
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'openssl'
4
+ require_relative 'decompressor'
4
5
 
5
6
  module MooTool
6
7
  # Module for Apple's IMG4 encryption and signing format
@@ -18,12 +19,14 @@ module MooTool
18
19
  when 'IM4P'
19
20
  @type = @data.value[1].value
20
21
  @build = @data.value[2].value
21
- @payload = @data.value[3].value
22
+ @payload = MooTool::Decompressor.new(@data.value[3].value).value
22
23
  when 'IMG4', 'IM4M'
23
24
  raise 'Not implemented'
24
25
  else
25
26
  raise "Unknown IMG4 type #{@data.first.value}"
26
27
  end
28
+
29
+ @manifest = Manifest.new(@payload) if @payload.start_with?('IM4M')
27
30
  end
28
31
 
29
32
  def payload?
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MooTool
4
- VERSION = '0.2.2'
4
+ VERSION = '0.2.5'
5
5
  end
data/mootool.gemspec CHANGED
@@ -37,7 +37,10 @@ Gem::Specification.new do |spec|
37
37
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
38
38
  spec.require_paths = ['lib']
39
39
 
40
+ spec.add_runtime_dependency 'lzfse'
41
+ spec.add_runtime_dependency 'lzss'
40
42
  spec.add_runtime_dependency 'plist', '~> 3'
43
+ spec.add_runtime_dependency 'ruby-lzma'
41
44
  spec.add_runtime_dependency 'ruby-macho', '~> 3'
42
45
  spec.add_runtime_dependency 'rubyzip', '~> 2'
43
46
  spec.add_runtime_dependency 'sorbet-runtime', '~> 0'
metadata CHANGED
@@ -1,15 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mootool
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.2.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rick Mark
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-08-22 00:00:00.000000000 Z
11
+ date: 2022-08-24 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: lzfse
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: lzss
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
13
41
  - !ruby/object:Gem::Dependency
14
42
  name: plist
15
43
  requirement: !ruby/object:Gem::Requirement
@@ -24,6 +52,20 @@ dependencies:
24
52
  - - "~>"
25
53
  - !ruby/object:Gem::Version
26
54
  version: '3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: ruby-lzma
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
27
69
  - !ruby/object:Gem::Dependency
28
70
  name: ruby-macho
29
71
  requirement: !ruby/object:Gem::Requirement
@@ -104,6 +146,7 @@ files:
104
146
  - lib/mootool/controllers/kernel_collection.rb
105
147
  - lib/mootool/controllers/sections.rb
106
148
  - lib/mootool/core_extensions.rb
149
+ - lib/mootool/models/decompressor.rb
107
150
  - lib/mootool/models/device_tree.rb
108
151
  - lib/mootool/models/img4.rb
109
152
  - lib/mootool/models/ipsw.rb