Skip to content
This repository was archived by the owner on May 27, 2022. It is now read-only.

Commit 26e9cb8

Browse files
authored
Merge pull request #16 from Slamdunk/filter_read_write_mode
stream_filter_append: configure STREAM_FILTER_READ as is the only method used
2 parents 8059a6c + 88bd5e9 commit 26e9cb8

15 files changed

+197
-59
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
"league/flysystem-adapter-test-utilities": "^2.3.1",
2525
"malukenho/mcbumpface": "^1.1.5",
2626
"phpunit/phpunit": "^9.5.10",
27-
"vimeo/psalm": "^4.12.0"
27+
"vimeo/psalm": "^4.13.1"
2828
},
2929
"autoload": {
3030
"psr-4": {

infection.json.dist

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@
3535
"sodium_memzero\\(.+\\);"
3636
]
3737
},
38+
"Identical": {
39+
"ignoreSourceCodeByRegex": [
40+
"if \\('' === \\$this->buffer && !\\$closing\\) {"
41+
]
42+
},
3843
"LessThanOrEqualTo": {
3944
"ignoreSourceCodeByRegex": [
4045
"while \\(self::ENCRYPT_READ_BYTES <= \\\\strlen\\(\\$this->buffer\\) || \\$closing\\) {"
@@ -64,7 +69,8 @@
6469
"UnwrapSubstr": {
6570
"ignoreSourceCodeByRegex": [
6671
".+ = substr\\(\\$this->buffer,( 0,)? \\$(read|write)ChunkSize\\);",
67-
"\\$header = substr\\(\\$this->buffer, 0, self::HEADER_LENGTH\\);"
72+
"\\$header = substr\\(\\$this->buffer, 0, self::HEADER_LENGTH\\);",
73+
"\\$data = substr\\(\\$data, 0, \\$dataDescriptorPosition\\);"
6874
]
6975
}
7076
},

psalm-baseline.xml

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<files psalm-version="4.12.0@e42bc4a23f67acba28a23bb09c348e2ff38a1d87">
2+
<files psalm-version="4.13.1@5cf660f63b548ccd4a56f62d916ee4d6028e01a3">
33
<file src="src/Gzip/GzipStreamFilter.php">
44
<InvalidPropertyAssignmentValue occurrences="2">
55
<code>deflate_init(ZLIB_ENCODING_RAW)</code>
@@ -28,7 +28,8 @@
2828
<code>$key</code>
2929
<code>$mode</code>
3030
</MissingConstructor>
31-
<UndefinedThisPropertyFetch occurrences="2">
31+
<UndefinedThisPropertyFetch occurrences="3">
32+
<code>$this-&gt;stream</code>
3233
<code>$this-&gt;stream</code>
3334
<code>$this-&gt;stream</code>
3435
</UndefinedThisPropertyFetch>
@@ -38,9 +39,10 @@
3839
<code>deflate_init(ZLIB_ENCODING_RAW)</code>
3940
<code>inflate_init(ZLIB_ENCODING_RAW)</code>
4041
</InvalidPropertyAssignmentValue>
41-
<MissingConstructor occurrences="4">
42+
<MissingConstructor occurrences="5">
4243
<code>$crc</code>
4344
<code>$filename</code>
45+
<code>$inflateMethod</code>
4446
<code>$mode</code>
4547
<code>$time</code>
4648
</MissingConstructor>
@@ -91,18 +93,13 @@
9193
</UnusedFunctionCall>
9294
</file>
9395
<file src="test/IntegrationTest.php">
94-
<PropertyNotSetInConstructor occurrences="6">
95-
<code>$key</code>
96+
<PropertyNotSetInConstructor occurrences="5">
9697
<code>IntegrationTest</code>
9798
<code>IntegrationTest</code>
9899
<code>IntegrationTest</code>
99100
<code>IntegrationTest</code>
100101
<code>IntegrationTest</code>
101102
</PropertyNotSetInConstructor>
102-
<RedundantPropertyInitializationCheck occurrences="2">
103-
<code>$this-&gt;key</code>
104-
<code>V1EncryptProxyAdapter::generateKey()</code>
105-
</RedundantPropertyInitializationCheck>
106103
</file>
107104
<file src="test/V1Encrypt/V1EncryptProxyAdapterTest.php">
108105
<PropertyNotSetInConstructor occurrences="5">

src/Gzip/GzipStreamFilter.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ public static function appendCompression(string $filename, $stream): void
7171
$resource = stream_filter_append(
7272
$stream,
7373
self::FILTERNAME_PREFIX.self::MODE_COMPRESS,
74-
STREAM_FILTER_ALL,
74+
STREAM_FILTER_READ,
7575
$filename
7676
);
7777
\assert(false !== $resource);
@@ -85,7 +85,7 @@ public static function appendDecompression(string $filename, $stream): void
8585
$resource = stream_filter_append(
8686
$stream,
8787
self::FILTERNAME_PREFIX.self::MODE_DECOMPRESS,
88-
STREAM_FILTER_ALL,
88+
STREAM_FILTER_READ,
8989
$filename
9090
);
9191
\assert(false !== $resource);
@@ -105,7 +105,7 @@ public function filter($in, $out, &$consumed, $closing): int
105105
$this->buffer .= $bucket->data;
106106
}
107107

108-
if ('' === $this->buffer) {
108+
if ('' === $this->buffer && !$closing) {
109109
return PSFS_FEED_ME;
110110
}
111111

src/V1Encrypt/V1EncryptStreamFilter.php

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public static function appendEncryption($stream, string $key): void
4343
$resource = stream_filter_append(
4444
$stream,
4545
self::FILTERNAME_PREFIX.self::MODE_ENCRYPT,
46-
STREAM_FILTER_ALL,
46+
STREAM_FILTER_READ,
4747
$key
4848
);
4949
\assert(false !== $resource);
@@ -57,7 +57,7 @@ public static function appendDecryption($stream, string $key): void
5757
$resource = stream_filter_append(
5858
$stream,
5959
self::FILTERNAME_PREFIX.self::MODE_DECRYPT,
60-
STREAM_FILTER_ALL,
60+
STREAM_FILTER_READ,
6161
$key
6262
);
6363
\assert(false !== $resource);
@@ -77,7 +77,7 @@ public function filter($in, $out, &$consumed, $closing): int
7777
$this->buffer .= $bucket->data;
7878
}
7979

80-
if ('' === $this->buffer) {
80+
if ('' === $this->buffer && !$closing) {
8181
return PSFS_FEED_ME;
8282
}
8383

@@ -111,12 +111,18 @@ public function onCreate(): bool
111111
*/
112112
private function encryptFilter($out, int &$consumed, bool $closing): void
113113
{
114-
$header = '';
115114
if (null === $this->state) {
116115
\assert(\is_string($this->key));
117116
[$this->state, $header] = sodium_crypto_secretstream_xchacha20poly1305_init_push($this->key);
118117
sodium_memzero($this->key);
119118
\assert(\is_string($header));
119+
120+
\assert(\is_resource($this->stream));
121+
$newBucket = stream_bucket_new(
122+
$this->stream,
123+
$header
124+
);
125+
stream_bucket_append($out, $newBucket);
120126
}
121127

122128
$readChunkSize = self::CHUNK_SIZE - SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES;
@@ -128,7 +134,7 @@ private function encryptFilter($out, int &$consumed, bool $closing): void
128134
if ($closing && '' === $this->buffer) {
129135
$tag = SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL;
130136
}
131-
$newBucketData = $header.sodium_crypto_secretstream_xchacha20poly1305_push(
137+
$newBucketData = sodium_crypto_secretstream_xchacha20poly1305_push(
132138
$this->state,
133139
$data,
134140
'',
@@ -143,7 +149,6 @@ private function encryptFilter($out, int &$consumed, bool $closing): void
143149
$consumed += \strlen($data);
144150
stream_bucket_append($out, $newBucket);
145151

146-
$header = '';
147152
if ($closing && '' === $this->buffer) {
148153
sodium_memzero($this->state);
149154

src/Zip/ZipStreamFilter.php

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ final class ZipStreamFilter extends php_user_filter
5252
private string $header = '';
5353
private ?HashContext $hashContext = null;
5454
private ?DeflateContext $deflateContext = null;
55+
private int $inflateMethod;
5556
private ?InflateContext $inflateContext = null;
5657

5758
private int $originalSize = 0;
@@ -81,7 +82,7 @@ public static function appendCompression(string $filename, $stream): void
8182
$resource = stream_filter_append(
8283
$stream,
8384
self::FILTERNAME_PREFIX.self::MODE_COMPRESS,
84-
STREAM_FILTER_ALL,
85+
STREAM_FILTER_READ,
8586
$filename
8687
);
8788
\assert(false !== $resource);
@@ -95,7 +96,7 @@ public static function appendDecompression(string $filename, $stream): void
9596
$resource = stream_filter_append(
9697
$stream,
9798
self::FILTERNAME_PREFIX.self::MODE_DECOMPRESS,
98-
STREAM_FILTER_ALL,
99+
STREAM_FILTER_READ,
99100
$filename
100101
);
101102
\assert(false !== $resource);
@@ -115,7 +116,7 @@ public function filter($in, $out, &$consumed, $closing): int
115116
$this->buffer .= $bucket->data;
116117
}
117118

118-
if ('' === $this->buffer) {
119+
if ('' === $this->buffer && !$closing) {
119120
return PSFS_FEED_ME;
120121
}
121122

@@ -285,9 +286,6 @@ private function compressFilter($out, int &$consumed, bool $closing): void
285286
private function decompressFilter($out, int &$consumed, bool $closing): void
286287
{
287288
if (null === $this->hashContext) {
288-
$this->hashContext = hash_init(self::HASH_ALGORITHM);
289-
$this->inflateContext = inflate_init(ZLIB_ENCODING_RAW);
290-
291289
$header = substr($this->buffer, 0, self::HEADER_LENGTH);
292290
$this->buffer = substr($this->buffer, self::HEADER_LENGTH);
293291
$arrayHeader = unpack('Vhead/vver/vbits/vmethod/Vtime/Vcrc/Vzlen/Vlen/vfilename/vfooter', $header);
@@ -296,13 +294,20 @@ private function decompressFilter($out, int &$consumed, bool $closing): void
296294
throw new RuntimeException('Stream is not Zip');
297295
}
298296

297+
\assert(\is_int($arrayHeader['method']));
298+
$this->inflateMethod = $arrayHeader['method'];
299299
\assert(\is_int($arrayHeader['filename']));
300300
$this->buffer = substr($this->buffer, $arrayHeader['filename']);
301301
\assert(\is_int($arrayHeader['footer']));
302302
$this->buffer = substr($this->buffer, $arrayHeader['footer']);
303303

304304
\assert(\is_int($arrayHeader['crc']));
305305
$this->crc = $arrayHeader['crc'];
306+
307+
$this->hashContext = hash_init(self::HASH_ALGORITHM);
308+
if (self::METHOD_DEFLATE === $this->inflateMethod) {
309+
$this->inflateContext = inflate_init(ZLIB_ENCODING_RAW);
310+
}
306311
}
307312

308313
$writeChunkSize = self::CHUNK_SIZE;
@@ -312,18 +317,26 @@ private function decompressFilter($out, int &$consumed, bool $closing): void
312317

313318
if ($closing && '' === $this->buffer) {
314319
$dataDescriptorPosition = strpos($data, pack('V', self::DATA_DESCRIPTOR_SIGNATURE));
315-
if (false !== $dataDescriptorPosition) {
320+
if (false === $dataDescriptorPosition) {
321+
$cdrFilePosition = strpos($data, pack('V', self::CDR_FILE_SIGNATURE));
322+
\assert(false !== $cdrFilePosition);
323+
$data = substr($data, 0, $cdrFilePosition);
324+
} else {
316325
$unpack = unpack('Vcrc', substr($data, $dataDescriptorPosition + 4, 4));
317326
\assert(\is_int($unpack['crc']));
318327
$this->crc = $unpack['crc'];
328+
$data = substr($data, 0, $dataDescriptorPosition);
319329
}
320330
}
321331

322-
$newBucketData = inflate_add(
323-
$this->inflateContext,
324-
$data,
325-
ZLIB_SYNC_FLUSH
326-
);
332+
$newBucketData = $data;
333+
if (self::METHOD_DEFLATE === $this->inflateMethod) {
334+
$newBucketData = inflate_add(
335+
$this->inflateContext,
336+
$data,
337+
ZLIB_SYNC_FLUSH
338+
);
339+
}
327340

328341
hash_update($this->hashContext, $newBucketData);
329342

test/AbstractFilesystemAdapterTestCase.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,9 @@ public function reading_multiple_files(): void
119119
static::assertSame('456', $adapter->read('path2.txt'));
120120
}
121121

122-
abstract protected function getRemoteFileSize(): int;
122+
abstract public function regression(): void;
123123

124-
abstract protected function regression(): void;
124+
abstract protected function getRemoteFileSize(): int;
125125

126126
protected static function createFilesystemAdapter(): FilesystemAdapter
127127
{

test/Gzip/GzipStreamFilterTest.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,28 @@ protected function setUp(): void
2020
GzipStreamFilter::register();
2121
}
2222

23+
/**
24+
* @test
25+
*/
26+
public function empty_stream(): void
27+
{
28+
$originalPlain = '';
29+
30+
$compressedStream = $this->streamFromContents($originalPlain);
31+
GzipStreamFilter::appendCompression('file.txt', $compressedStream);
32+
33+
$compressed = stream_get_contents($compressedStream);
34+
fclose($compressedStream);
35+
static::assertNotSame($originalPlain, $compressed);
36+
37+
$plainStream = $this->streamFromContents($compressed);
38+
GzipStreamFilter::appendDecompression('file.txt', $plainStream);
39+
40+
$plain = stream_get_contents($plainStream);
41+
fclose($plainStream);
42+
static::assertSame($originalPlain, $plain);
43+
}
44+
2345
/**
2446
* @test
2547
*/

0 commit comments

Comments
 (0)