rubyzip 3.1.0 → 3.1.1
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/Changelog.md +13 -0
- data/README.md +2 -1
- data/Rakefile +4 -6
- data/lib/zip/crypto/aes_encryption.rb +2 -1
- data/lib/zip/crypto/decrypted_io.rb +12 -21
- data/lib/zip/crypto/null_encryption.rb +0 -10
- data/lib/zip/crypto/traditional_encryption.rb +2 -0
- data/lib/zip/dos_time.rb +3 -2
- data/lib/zip/file.rb +2 -4
- data/lib/zip/filesystem/file.rb +4 -3
- data/lib/zip/inflater.rb +4 -3
- data/lib/zip/input_stream.rb +17 -11
- data/lib/zip/ioextras/abstract_input_stream.rb +3 -2
- data/lib/zip/null_decompressor.rb +3 -2
- data/lib/zip/pass_thru_decompressor.rb +4 -3
- data/lib/zip/streamable_stream.rb +1 -1
- data/lib/zip/version.rb +1 -1
- data/lib/zip.rb +1 -0
- data/rubyzip.gemspec +3 -3
- data/samples/gtk_ruby_zip.rb +1 -1
- data/samples/qtzip.rb +1 -1
- metadata +11 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 869a32fef1374d44c2d01fcf90d92d10760ceb619cbc2ccb545f7753503efee4
|
4
|
+
data.tar.gz: 9eb0b0601572717187029c44fbcfdd7fa3a47005d869d8aea2b36ab465b18de5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8cc3d0b1cb58eabdafb91db1cc8e7a2ef3932bcaf993df9a8c21ae261d480ffa43d431111faa11f5e19e52aa59a70e14a4724bbd174a8628a7ffacb48119ccdb
|
7
|
+
data.tar.gz: 1171566d3c91b07b01e3f5fe77e9d098f6c5fa6f94891cf289c1edbaa35bbe2a3a96165bebfcb7b35f2d41eedb268b13e90aab27683cd05175ea0ffbc9a485c6
|
data/Changelog.md
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
# 3.1.1 (2025-09-26)
|
2
|
+
|
3
|
+
- Improve the IO pipeline when decompressing. [#649](https://github.com/rubyzip/rubyzip/pull/649) (which also fixes [#647](https://github.com/rubyzip/rubyzip/issues/647))
|
4
|
+
|
5
|
+
Tooling/internal:
|
6
|
+
|
7
|
+
- Improve the `DecryptedIo` class with various updates and optimizations.
|
8
|
+
- Remove the `NullDecrypter` class.
|
9
|
+
- Properly convert the test suite to use minitest.
|
10
|
+
- Move all test helper code into separate files.
|
11
|
+
- Updates to the Actions CI, including new OS versions.
|
12
|
+
- Update rubocop versions and fix resultant cop failures. [#646](https://github.com/rubyzip/rubyzip/pull/646)
|
13
|
+
|
1
14
|
# 3.1.0 (2025-09-06)
|
2
15
|
|
3
16
|
- Support AES decryption. [#579](https://github.com/rubyzip/rubyzip/pull/579) and [#645](https://github.com/rubyzip/rubyzip/pull/645)
|
data/README.md
CHANGED
@@ -3,7 +3,8 @@
|
|
3
3
|
[](http://badge.fury.io/rb/rubyzip)
|
4
4
|
[](https://github.com/rubyzip/rubyzip/actions/workflows/tests.yml)
|
5
5
|
[](https://github.com/rubyzip/rubyzip/actions/workflows/lint.yml)
|
6
|
-
[](https://github.com/rubocop/rubocop)
|
7
|
+
[](https://qlty.sh/gh/rubyzip/projects/rubyzip)
|
7
8
|
[](https://coveralls.io/r/rubyzip/rubyzip?branch=master)
|
8
9
|
|
9
10
|
Rubyzip is a ruby library for reading and writing zip files.
|
data/Rakefile
CHANGED
@@ -1,17 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'bundler/gem_tasks'
|
4
|
-
require '
|
4
|
+
require 'minitest/test_task'
|
5
5
|
require 'rdoc/task'
|
6
6
|
require 'rubocop/rake_task'
|
7
7
|
|
8
8
|
task default: :test
|
9
9
|
|
10
|
-
|
11
|
-
test.
|
12
|
-
test.
|
13
|
-
test.pattern = 'test/**/*_test.rb'
|
14
|
-
test.verbose = true
|
10
|
+
Minitest::TestTask.create do |test|
|
11
|
+
test.framework = 'require "simplecov"'
|
12
|
+
test.test_globs = 'test/**/*_test.rb'
|
15
13
|
end
|
16
14
|
|
17
15
|
RDoc::Task.new do |rdoc|
|
@@ -112,7 +112,8 @@ module Zip
|
|
112
112
|
@hmac = OpenSSL::HMAC.new(enc_hmac_key, OpenSSL::Digest.new('SHA1'))
|
113
113
|
end
|
114
114
|
|
115
|
-
def check_integrity(
|
115
|
+
def check_integrity!(io)
|
116
|
+
auth_code = io.read(AUTHENTICATION_CODE_LENGTH)
|
116
117
|
raise Error, 'Integrity fault' if @hmac.digest[0...AUTHENTICATION_CODE_LENGTH] != auth_code
|
117
118
|
end
|
118
119
|
end
|
@@ -7,48 +7,39 @@ module Zip
|
|
7
7
|
def initialize(io, decrypter, compressed_size)
|
8
8
|
@io = io
|
9
9
|
@decrypter = decrypter
|
10
|
-
@
|
11
|
-
@
|
10
|
+
@bytes_remaining = compressed_size
|
11
|
+
@buffer = +''
|
12
12
|
end
|
13
13
|
|
14
14
|
def read(length = nil, outbuf = +'')
|
15
|
-
return (length.nil? || length.zero? ? '' : nil) if eof
|
15
|
+
return (length.nil? || length.zero? ? '' : nil) if eof?
|
16
16
|
|
17
|
-
while length.nil? || (buffer.bytesize < length)
|
17
|
+
while length.nil? || (@buffer.bytesize < length)
|
18
18
|
break if input_finished?
|
19
19
|
|
20
|
-
buffer << produce_input
|
20
|
+
@buffer << produce_input
|
21
21
|
end
|
22
22
|
|
23
|
-
|
24
|
-
@decrypter.check_integrity(@io.read(::Zip::AESEncryption::AUTHENTICATION_CODE_LENGTH))
|
25
|
-
end
|
23
|
+
@decrypter.check_integrity!(@io) if input_finished?
|
26
24
|
|
27
|
-
outbuf.replace(buffer.slice!(0...(length || buffer.bytesize)))
|
25
|
+
outbuf.replace(@buffer.slice!(0...(length || @buffer.bytesize)))
|
28
26
|
end
|
29
27
|
|
30
28
|
private
|
31
29
|
|
32
|
-
def eof
|
33
|
-
buffer.empty? && input_finished?
|
34
|
-
end
|
35
|
-
|
36
|
-
def buffer
|
37
|
-
@buffer ||= +''
|
38
|
-
end
|
39
|
-
|
40
|
-
def pos
|
41
|
-
@io.tell - @offset
|
30
|
+
def eof?
|
31
|
+
@buffer.empty? && input_finished?
|
42
32
|
end
|
43
33
|
|
44
34
|
def input_finished?
|
45
|
-
|
35
|
+
!@bytes_remaining.positive?
|
46
36
|
end
|
47
37
|
|
48
38
|
def produce_input
|
49
|
-
chunk_size = [
|
39
|
+
chunk_size = [@bytes_remaining, CHUNK_SIZE].min
|
50
40
|
return '' unless chunk_size.positive?
|
51
41
|
|
42
|
+
@bytes_remaining -= chunk_size
|
52
43
|
@decrypter.decrypt(@io.read(chunk_size))
|
53
44
|
end
|
54
45
|
end
|
@@ -28,16 +28,6 @@ module Zip
|
|
28
28
|
|
29
29
|
def reset!; end
|
30
30
|
end
|
31
|
-
|
32
|
-
class NullDecrypter < Decrypter # :nodoc:
|
33
|
-
include NullEncryption
|
34
|
-
|
35
|
-
def decrypt(data)
|
36
|
-
data
|
37
|
-
end
|
38
|
-
|
39
|
-
def reset!(_header); end
|
40
|
-
end
|
41
31
|
end
|
42
32
|
|
43
33
|
# Copyright (C) 2002, 2003 Thomas Sondergaard
|
data/lib/zip/dos_time.rb
CHANGED
@@ -21,7 +21,7 @@ module Zip
|
|
21
21
|
def absolute_time?
|
22
22
|
# If absolute time is not set, we can assume it is an absolute time
|
23
23
|
# because times do have timezone information by default.
|
24
|
-
@absolute_time.nil?
|
24
|
+
@absolute_time.nil? || @absolute_time
|
25
25
|
end
|
26
26
|
|
27
27
|
def to_binary_dos_time
|
@@ -36,7 +36,8 @@ module Zip
|
|
36
36
|
((year - 1980) << 9)
|
37
37
|
end
|
38
38
|
|
39
|
-
|
39
|
+
# Deprecated. Remove for version 4.
|
40
|
+
def dos_equals(other) # rubocop:disable Naming/PredicateMethod
|
40
41
|
warn 'Zip::DOSTime#dos_equals is deprecated. Use `==` instead.'
|
41
42
|
self == other
|
42
43
|
end
|
data/lib/zip/file.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'fileutils'
|
3
4
|
require 'forwardable'
|
4
5
|
|
5
6
|
require_relative 'file_split'
|
@@ -98,7 +99,6 @@ module Zip
|
|
98
99
|
restore_permissions: DEFAULT_RESTORE_OPTIONS[:restore_permissions],
|
99
100
|
restore_times: DEFAULT_RESTORE_OPTIONS[:restore_times],
|
100
101
|
compression_level: ::Zip.default_compression)
|
101
|
-
|
102
102
|
zf = ::Zip::File.new(file_name, create: create,
|
103
103
|
restore_ownership: restore_ownership,
|
104
104
|
restore_permissions: restore_permissions,
|
@@ -123,7 +123,6 @@ module Zip
|
|
123
123
|
restore_permissions: DEFAULT_RESTORE_OPTIONS[:restore_permissions],
|
124
124
|
restore_times: DEFAULT_RESTORE_OPTIONS[:restore_times],
|
125
125
|
compression_level: ::Zip.default_compression)
|
126
|
-
|
127
126
|
unless IO_METHODS.map { |method| io.respond_to?(method) }.all? || io.kind_of?(String)
|
128
127
|
raise 'Zip::File.open_buffer expects a String or IO-like argument' \
|
129
128
|
"(responds to #{IO_METHODS.join(', ')}). Found: #{io.class}"
|
@@ -191,7 +190,6 @@ module Zip
|
|
191
190
|
extra: nil, compressed_size: nil, crc: nil,
|
192
191
|
compression_method: nil, compression_level: nil,
|
193
192
|
size: nil, time: nil, &a_proc)
|
194
|
-
|
195
193
|
new_entry =
|
196
194
|
if entry.kind_of?(Entry)
|
197
195
|
entry
|
@@ -412,7 +410,7 @@ module Zip
|
|
412
410
|
::File.chmod(@file_permissions, name) unless @create
|
413
411
|
end
|
414
412
|
ensure
|
415
|
-
|
413
|
+
FileUtils.rm_f(tmp_filename)
|
416
414
|
end
|
417
415
|
end
|
418
416
|
end
|
data/lib/zip/filesystem/file.rb
CHANGED
@@ -27,7 +27,7 @@ module Zip
|
|
27
27
|
|
28
28
|
def unix_mode_cmp(filename, mode)
|
29
29
|
e = find_entry(filename)
|
30
|
-
e.fstype == FSTYPE_UNIX && (
|
30
|
+
e.fstype == FSTYPE_UNIX && (e.external_file_attributes >> 16).anybits?(mode)
|
31
31
|
rescue Errno::ENOENT
|
32
32
|
false
|
33
33
|
end
|
@@ -102,10 +102,11 @@ module Zip
|
|
102
102
|
@mapped_zip.get_entry(filename).size
|
103
103
|
end
|
104
104
|
|
105
|
-
# Returns nil for not found and nil for directories
|
105
|
+
# Returns nil for not found and nil for directories.
|
106
|
+
# We disable the cop here for compatibility with `::File.size?`.
|
106
107
|
def size?(filename)
|
107
108
|
entry = @mapped_zip.find_entry(filename)
|
108
|
-
entry.nil? || entry.directory? ? nil : entry.size
|
109
|
+
entry.nil? || entry.directory? ? nil : entry.size # rubocop:disable Style/ReturnNilInPredicateMethodDefinition
|
109
110
|
end
|
110
111
|
|
111
112
|
def chown(owner, group, *filenames)
|
data/lib/zip/inflater.rb
CHANGED
@@ -10,7 +10,7 @@ module Zip
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def read(length = nil, outbuf = +'')
|
13
|
-
return (length.nil? || length.zero? ? '' : nil) if eof
|
13
|
+
return (length.nil? || length.zero? ? '' : nil) if eof?
|
14
14
|
|
15
15
|
while length.nil? || (@buffer.bytesize < length)
|
16
16
|
break if input_finished?
|
@@ -21,11 +21,12 @@ module Zip
|
|
21
21
|
outbuf.replace(@buffer.slice!(0...(length || @buffer.bytesize)))
|
22
22
|
end
|
23
23
|
|
24
|
-
def eof
|
24
|
+
def eof?
|
25
25
|
@buffer.empty? && input_finished?
|
26
26
|
end
|
27
27
|
|
28
|
-
|
28
|
+
# Alias for compatibility. Remove for version 4.
|
29
|
+
alias eof eof?
|
29
30
|
|
30
31
|
private
|
31
32
|
|
data/lib/zip/input_stream.rb
CHANGED
@@ -55,7 +55,7 @@ module Zip
|
|
55
55
|
super()
|
56
56
|
@archive_io = get_io(context, offset)
|
57
57
|
@decompressor = ::Zip::NullDecompressor
|
58
|
-
@decrypter = decrypter
|
58
|
+
@decrypter = decrypter
|
59
59
|
@current_entry = nil
|
60
60
|
@complete_entry = nil
|
61
61
|
end
|
@@ -135,21 +135,27 @@ module Zip
|
|
135
135
|
@current_entry = ::Zip::Entry.read_local_entry(@archive_io)
|
136
136
|
return if @current_entry.nil?
|
137
137
|
|
138
|
-
if @current_entry.encrypted? && @decrypter.kind_of?(NullDecrypter)
|
139
|
-
raise Error,
|
140
|
-
'A password is required to decode this zip file'
|
141
|
-
end
|
142
|
-
|
143
138
|
if @current_entry.incomplete? && @current_entry.compressed_size == 0 && !@complete_entry
|
144
139
|
raise StreamingError, @current_entry
|
145
140
|
end
|
146
141
|
|
147
|
-
@
|
148
|
-
@decompressor = get_decompressor
|
142
|
+
@decompressor = assemble_io
|
149
143
|
flush
|
150
144
|
@current_entry
|
151
145
|
end
|
152
146
|
|
147
|
+
def assemble_io # :nodoc:
|
148
|
+
io = if @current_entry.encrypted?
|
149
|
+
raise Error, 'A password is required to decode this zip file.' if @decrypter.nil?
|
150
|
+
|
151
|
+
get_decrypted_io
|
152
|
+
else
|
153
|
+
@archive_io
|
154
|
+
end
|
155
|
+
|
156
|
+
get_decompressor(io)
|
157
|
+
end
|
158
|
+
|
153
159
|
def get_decrypted_io # :nodoc:
|
154
160
|
header = @archive_io.read(@decrypter.header_bytesize)
|
155
161
|
@decrypter.reset!(header)
|
@@ -170,7 +176,7 @@ module Zip
|
|
170
176
|
::Zip::DecryptedIo.new(@archive_io, @decrypter, compressed_size)
|
171
177
|
end
|
172
178
|
|
173
|
-
def get_decompressor # :nodoc:
|
179
|
+
def get_decompressor(io) # :nodoc:
|
174
180
|
return ::Zip::NullDecompressor if @current_entry.nil?
|
175
181
|
|
176
182
|
decompressed_size =
|
@@ -188,7 +194,7 @@ module Zip
|
|
188
194
|
raise ::Zip::CompressionMethodError, @current_entry.compression_method
|
189
195
|
end
|
190
196
|
|
191
|
-
decompressor_class.new(
|
197
|
+
decompressor_class.new(io, decompressed_size)
|
192
198
|
end
|
193
199
|
|
194
200
|
def produce_input # :nodoc:
|
@@ -196,7 +202,7 @@ module Zip
|
|
196
202
|
end
|
197
203
|
|
198
204
|
def input_finished? # :nodoc:
|
199
|
-
@decompressor.eof
|
205
|
+
@decompressor.eof?
|
200
206
|
end
|
201
207
|
end
|
202
208
|
end
|
@@ -117,11 +117,12 @@ module Zip
|
|
117
117
|
|
118
118
|
alias each each_line
|
119
119
|
|
120
|
-
def eof
|
120
|
+
def eof?
|
121
121
|
@output_buffer.empty? && input_finished?
|
122
122
|
end
|
123
123
|
|
124
|
-
|
124
|
+
# Alias for compatibility. Remove for version 4.
|
125
|
+
alias eof eof?
|
125
126
|
end
|
126
127
|
end
|
127
128
|
end
|
@@ -8,7 +8,7 @@ module Zip
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def read(length = nil, outbuf = +'')
|
11
|
-
return (length.nil? || length.zero? ? '' : nil) if eof
|
11
|
+
return (length.nil? || length.zero? ? '' : nil) if eof?
|
12
12
|
|
13
13
|
if length.nil? || (@read_so_far + length) > decompressed_size
|
14
14
|
length = decompressed_size - @read_so_far
|
@@ -18,11 +18,12 @@ module Zip
|
|
18
18
|
input_stream.read(length, outbuf)
|
19
19
|
end
|
20
20
|
|
21
|
-
def eof
|
21
|
+
def eof?
|
22
22
|
@read_so_far >= decompressed_size
|
23
23
|
end
|
24
24
|
|
25
|
-
|
25
|
+
# Alias for compatibility. Remove for version 4.
|
26
|
+
alias eof eof?
|
26
27
|
end
|
27
28
|
|
28
29
|
::Zip::Decompressor.register(::Zip::COMPRESSION_METHOD_STORE, ::Zip::PassThruDecompressor)
|
data/lib/zip/version.rb
CHANGED
data/lib/zip.rb
CHANGED
data/rubyzip.gemspec
CHANGED
@@ -31,9 +31,9 @@ Gem::Specification.new do |s|
|
|
31
31
|
s.add_development_dependency 'minitest', '~> 5.25'
|
32
32
|
s.add_development_dependency 'rake', '~> 13.2'
|
33
33
|
s.add_development_dependency 'rdoc', '~> 6.11'
|
34
|
-
s.add_development_dependency 'rubocop', '~> 1.
|
35
|
-
s.add_development_dependency 'rubocop-performance', '~> 1.
|
36
|
-
s.add_development_dependency 'rubocop-rake', '~> 0.
|
34
|
+
s.add_development_dependency 'rubocop', '~> 1.80.2'
|
35
|
+
s.add_development_dependency 'rubocop-performance', '~> 1.26.0'
|
36
|
+
s.add_development_dependency 'rubocop-rake', '~> 0.7.1'
|
37
37
|
s.add_development_dependency 'simplecov', '~> 0.22.0'
|
38
38
|
s.add_development_dependency 'simplecov-lcov', '~> 0.8'
|
39
39
|
end
|
data/samples/gtk_ruby_zip.rb
CHANGED
data/samples/qtzip.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubyzip
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.1.
|
4
|
+
version: 3.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Haines
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2025-09-
|
13
|
+
date: 2025-09-26 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: minitest
|
@@ -60,42 +60,42 @@ dependencies:
|
|
60
60
|
requirements:
|
61
61
|
- - "~>"
|
62
62
|
- !ruby/object:Gem::Version
|
63
|
-
version: 1.
|
63
|
+
version: 1.80.2
|
64
64
|
type: :development
|
65
65
|
prerelease: false
|
66
66
|
version_requirements: !ruby/object:Gem::Requirement
|
67
67
|
requirements:
|
68
68
|
- - "~>"
|
69
69
|
- !ruby/object:Gem::Version
|
70
|
-
version: 1.
|
70
|
+
version: 1.80.2
|
71
71
|
- !ruby/object:Gem::Dependency
|
72
72
|
name: rubocop-performance
|
73
73
|
requirement: !ruby/object:Gem::Requirement
|
74
74
|
requirements:
|
75
75
|
- - "~>"
|
76
76
|
- !ruby/object:Gem::Version
|
77
|
-
version: 1.
|
77
|
+
version: 1.26.0
|
78
78
|
type: :development
|
79
79
|
prerelease: false
|
80
80
|
version_requirements: !ruby/object:Gem::Requirement
|
81
81
|
requirements:
|
82
82
|
- - "~>"
|
83
83
|
- !ruby/object:Gem::Version
|
84
|
-
version: 1.
|
84
|
+
version: 1.26.0
|
85
85
|
- !ruby/object:Gem::Dependency
|
86
86
|
name: rubocop-rake
|
87
87
|
requirement: !ruby/object:Gem::Requirement
|
88
88
|
requirements:
|
89
89
|
- - "~>"
|
90
90
|
- !ruby/object:Gem::Version
|
91
|
-
version: 0.
|
91
|
+
version: 0.7.1
|
92
92
|
type: :development
|
93
93
|
prerelease: false
|
94
94
|
version_requirements: !ruby/object:Gem::Requirement
|
95
95
|
requirements:
|
96
96
|
- - "~>"
|
97
97
|
- !ruby/object:Gem::Version
|
98
|
-
version: 0.
|
98
|
+
version: 0.7.1
|
99
99
|
- !ruby/object:Gem::Dependency
|
100
100
|
name: simplecov
|
101
101
|
requirement: !ruby/object:Gem::Requirement
|
@@ -197,9 +197,9 @@ licenses:
|
|
197
197
|
- BSD-2-Clause
|
198
198
|
metadata:
|
199
199
|
bug_tracker_uri: https://github.com/rubyzip/rubyzip/issues
|
200
|
-
changelog_uri: https://github.com/rubyzip/rubyzip/blob/v3.1.
|
201
|
-
documentation_uri: https://www.rubydoc.info/gems/rubyzip/3.1.
|
202
|
-
source_code_uri: https://github.com/rubyzip/rubyzip/tree/v3.1.
|
200
|
+
changelog_uri: https://github.com/rubyzip/rubyzip/blob/v3.1.1/Changelog.md
|
201
|
+
documentation_uri: https://www.rubydoc.info/gems/rubyzip/3.1.1
|
202
|
+
source_code_uri: https://github.com/rubyzip/rubyzip/tree/v3.1.1
|
203
203
|
wiki_uri: https://github.com/rubyzip/rubyzip/wiki
|
204
204
|
rubygems_mfa_required: 'true'
|
205
205
|
post_install_message:
|