Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: Introduce a PharFactory and rework InvalidPhar #972

Merged
merged 8 commits into from
Apr 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions fixtures/phar/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
How those files were created:

empty-pdf.pdf: open a text editor and export as PDF.
simple.zip: create a sample.txt file and compress it `$ zip -r`.
simple.tar & simple.tar.{gz|bz2}:

```php
$phar = new PharData('simple.tar');
$phar->addFile('sample.txt');

$phar->compress(Phar::GZ);
// ...
```

simple.tar.phar & simple.tar.{gz|bz2}.phar: copied the tar variant and added ".phar" manually

simple.phar:

```php
$phar = new Phar('simple-phar.phar');
$phar->addFile('sample.php');
```

corrupted-phar-no-halt-compiler.phar: copied `simple-phar.phar` and removed the `__HALT_COMPILER(); ?>` token.
corrupted-simple.zip: copied `simple.zip`, opened it in a text editor and added "3 " at the beginning of the file

empty-file.{zip|phar}: created an empty file and renamed it

simple-phar-openssl-sign.phar:
- https://www.php.net/manual/en/phar.setsignaturealgorithm.php
- use the key in `openssl-keys`

corrupted-phar-altered-stub.phar: vim the file and add a comment in the stub section
corrupted-phar-altered-binary.phar: open the file in the text editor and add characters after the part identified as an included file
Binary file added fixtures/phar/corrupted-phar-altered-binary.phar
Binary file not shown.
Binary file added fixtures/phar/corrupted-phar-altered-binary.tar
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added fixtures/phar/corrupted-phar-altered-stub.phar
Binary file not shown.
Binary file added fixtures/phar/corrupted-phar-altered-stub.tar
Binary file not shown.
Binary file added fixtures/phar/corrupted-simple.zip
Binary file not shown.
Binary file not shown.
Empty file added fixtures/phar/empty-file.phar
Empty file.
Empty file added fixtures/phar/empty-file.zip
Empty file.
Binary file added fixtures/phar/empty-pdf.pdf
Binary file not shown.
5 changes: 5 additions & 0 deletions fixtures/phar/openssl-keys/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
```sh
$ cd to this directory
$ openssl genrsa -out private-key.pem 2048
$ openssl rsa -in private-key.pem -outform PEM -pubout -out public-key.pem
```
27 changes: 27 additions & 0 deletions fixtures/phar/openssl-keys/private-key.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAywa2fvnQ9yrS6ooOycSCYe775MTRq71mujt/c7U52VHbNAcR
5bYZ0WV+IgJLqRxSjasUbfrTfMzuW6Ge7kdqrAmzR3Y1LX4uRrvd3J9LnhR5ATd5
ujrHkaS8HVHVVC2xOEUn4Yeo23xOsWYKqDjuDlcZXtjPMofXZBVwX8h9rtWCuLlA
qyP4UbcFD4YsSHuVlAIl5SxM0xtYrdkjpENaYTzJswBDtxfJ5uN7IzwL5C6arbPR
w16RvloldvkkVqAkZrNUbdDCG4QQ86lTo0tgrALcaNK0VDRYmd2jwJK6sOjJpI0z
i+/yLGih4cVenmXQzSXm0qbH9Is4E45PaNATmQIDAQABAoIBAD2WA7Xwwdq4OtK6
nlHGMmbSv8Zdjdyyz36encLTroClvADEREGSQ7KpPuHCIIFj/gbLZp8V/yFUaNmS
5UsSjuEw8Bk1Wlw6cn8ybdKG38FMJIih82LygadEeWvLbxLh6WhQUhCvviEWTCiz
83ekDVJ8SU3kJrYFTuklN7lWcAmgX7gptiOa8j71u8SCG1jnqSr4LJRNfZ6zVEvk
58hMU/4svy6D55k6i6qz/mwoytfVh73BzJyj5IATByJg/oWdilLIP2GjoQGW0eaQ
Q3ZdthiHnllT1fTUV48sO1D5lFwmOSYidaF/00wyHlvRIL24JtAMyDOi/8rbHl2W
i6oZFaECgYEA/XJf9/pzW6LOnMN/n0qG/64NA40NT59hR8erTDYeiR6v8yXujS+U
oz3xyAsswNBRBcGA5vywAGjYwFiZbv15DTA7GkKu0oldzr4g5Peas8LAlk3pcQQt
aa6HZ6Oh4lOe1osZ7bb9LMdv9/7o2bwWfPCVh/NrFZ3E6a+zsMMlXxMCgYEAzRJO
YsnP9QxYdLu5fryaawJFL16wA4kDerVvn2ymDMWuw9zeVM1UutXdSZn5xnw31MBl
d+5WXpkXZkkFjlKB2bTxWUFy373vM7ed799+Pfu6gqrnAXm4RiFfXxJ5EcZVhb23
uziz3kXkpSyGpXPc60usmCUJyq3Jlkmfx746HCMCgYEAvzIpc8lcfSS0+U4CWQjA
DuIery8Ze5egq6XVdAjfwFGGKsfSzm+2ke+JFoBXop2EgfMYayj1HVn7Kh+soC5X
w7s+2vCzMeCvA+gqqJCiBDpHTxw3nyqnl7IyM90dor+yc+c8CDijhcRuk4eZ4agi
zt4v7/+SKRx8EE6cIB0XdEECgYAYDnWzkQkcLf6ScxMnkuhqdTG4hNsRDxmhY3dc
tFomVWpS/631NMEjycLTx4RNjHTgOFGu5/6pyju8fARy1ar15wwI9GyNYrKU1o1o
fkdI7ibK/VFsEuNTFschWAFr3GBb+A19oQE4qepQlhCViCn6UD5G+tFTPV/QiYJ8
5AvdEQKBgQD6OkB2NyKJ5DJI82KoOwbMkuIfsXqgIbiX2g62n+hSyyoiMmxueYMU
Vmq9dweP+M4HLHLT0fMh5eR7QZ8iOalBCWoaHSyqaP9G9Kyw1ZshWwgSMXLFTVIr
qpZwdFlNb7xh8rieubvgkkr4orp+HUOg5b00ZyLIYXWsR0/qOXL++Q==
-----END RSA PRIVATE KEY-----
9 changes: 9 additions & 0 deletions fixtures/phar/openssl-keys/public-key.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAywa2fvnQ9yrS6ooOycSC
Ye775MTRq71mujt/c7U52VHbNAcR5bYZ0WV+IgJLqRxSjasUbfrTfMzuW6Ge7kdq
rAmzR3Y1LX4uRrvd3J9LnhR5ATd5ujrHkaS8HVHVVC2xOEUn4Yeo23xOsWYKqDju
DlcZXtjPMofXZBVwX8h9rtWCuLlAqyP4UbcFD4YsSHuVlAIl5SxM0xtYrdkjpENa
YTzJswBDtxfJ5uN7IzwL5C6arbPRw16RvloldvkkVqAkZrNUbdDCG4QQ86lTo0tg
rALcaNK0VDRYmd2jwJK6sOjJpI0zi+/yLGih4cVenmXQzSXm0qbH9Is4E45PaNAT
mQIDAQAB
-----END PUBLIC KEY-----
5 changes: 5 additions & 0 deletions fixtures/phar/openssl-pass-keys/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
```sh
$ cd to this directory
$ openssl genrsa -passout pass:hello -out private-key.pem 2048
$ openssl rsa -in private-key.pem -outform PEM -pubout -out public-key.pem
```
1 change: 1 addition & 0 deletions fixtures/phar/openssl-pass-keys/passphrase
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
hello
27 changes: 27 additions & 0 deletions fixtures/phar/openssl-pass-keys/private-key.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAtjbkpfXljNb3CqIqaEdFrKsIkN0mW+DcJh/XPQ8HQrfQ4/uX
ji8cYBxXj9OX3kwcuzid1nl2fIWJD4nAtVtvsr6+Hgc/gzIakgJpsHjuPm82CgrC
0mZyI5peAc1t0oCl3Uo7bp3bq0wghWmuuUwVIj4jfaEUbmwKUsJYgIDaMokZYP5C
Nx6NYeNAMcG+69v9r4u6/7ePnPeNUURda0/HpIKz+c9UwJwha83v9HhL1FD9RwBW
BwR5pVtfnt/JAh/jKAcO0niZMa6R28nQXSFo6iEREViRhkmvCKwdSzkKUhwYarFy
4nBc7gOu6Ny5cU8MFSF6MHY392bcnc0EXSdzRwIDAQABAoIBADRDCE+leIJtwYt2
Oa2RC6XbpGhQVckydFIm/cgQgGedazeImM56KqxSVLb23G8w62izc2npipdqgYZI
X1Jk+GOPG95m+8t4WnCYapHoDYUwxpIYxgoswf3+L4pazm364hfXS7aNZkz6V7WM
O0YAUWtx4SIOSlrleAyGm3W3/11Qw1+Eyfg51htCu26O9tlssn7roCq3dIPHNklb
NheLZSHjEaKHUQiYFOrkCootNgqFcoE9VxVZN9sfa8IDkbUd7egeAwJ+v3nwNMEo
KpAFxpChUPsXNLcCvZ/c43ektNv+2GXoySktBrfBQSVbin7J7RGa6sgHFgGyYtES
hP+mmLkCgYEA3K0HDHFDZvKeFeKHIwnbhSaPUNRNBDbOJ8QuAaWW6RX424NUyzH7
QlZkg9kJVTqVO8vOVBPVph9tZNfegH7MMTpr/N6kt7cfGu9dEcFGUTT//DddjPKG
8qwgZx7nXEByzWRiiGsuzkEivaiwrr4URmJsZfqROvAnZih46Xd5gY0CgYEA02HF
iMEiAZtmCFbZrPE/dfBlFzXeBL4vsBhIR8TifngzQuADs8Old73XSFAdqtcwsJkC
htYu/KYDPaRFiGeoXYCLWhKjOEO4YXti9MiMptN870HIkzVDtutSiKMMgFADlT0t
cF7LIFJrnUeuM9NZ/UjN/y7o3pCsgS8ad7kp8SMCgYABNXVvbQNogfW5uvbwizJH
pXFtiOwvFLnGX/28hpKwDi3BzhNd1ZVBxMViL4Msk1iT7kbgEQe/lDZ+MeyHGaq2
rlI/HV0boIYsGJmS6lMfSMIKOKdriTySAb1fszyjNbsrQtyDUMr92D9/eHgXTPVB
eXKMkHXRM9WTaq9W4A+rVQKBgQDG2Rvs6NonrtsODz2YTh4HwYwniHoB9jOAMWeV
dCYpGMQILhnteqfm+8RQd2VhOCvKhTX2R/hNnZJA446xoemlg+4TXqMCo9oIgfz2
Ds8ZhKvrmvOnX50Cr16lwNRaxGqKctGS+umUz1QC0dKTWEg4V8vJOYTBElHk+L2q
UJqfBwKBgQCpzKR84yPVWpX8oQaZN5oWEi44w7dZ5yQLk41c/IZZ9mcolEvApayp
Y8Yuhj4tQUvAfwVPGiFQCHl3BRvlSQUkg90zXc4o198/RxSV2m1zGfmvKFknRr8W
DSPulzWiYQBgefa4hTMVqzTpOcU+t8hmTU5TbC0WeySaUco5i1asMw==
-----END RSA PRIVATE KEY-----
9 changes: 9 additions & 0 deletions fixtures/phar/openssl-pass-keys/public-key.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtjbkpfXljNb3CqIqaEdF
rKsIkN0mW+DcJh/XPQ8HQrfQ4/uXji8cYBxXj9OX3kwcuzid1nl2fIWJD4nAtVtv
sr6+Hgc/gzIakgJpsHjuPm82CgrC0mZyI5peAc1t0oCl3Uo7bp3bq0wghWmuuUwV
Ij4jfaEUbmwKUsJYgIDaMokZYP5CNx6NYeNAMcG+69v9r4u6/7ePnPeNUURda0/H
pIKz+c9UwJwha83v9HhL1FD9RwBWBwR5pVtfnt/JAh/jKAcO0niZMa6R28nQXSFo
6iEREViRhkmvCKwdSzkKUhwYarFy4nBc7gOu6Ny5cU8MFSF6MHY392bcnc0EXSdz
RwIDAQAB
-----END PUBLIC KEY-----
Binary file added fixtures/phar/simple-phar-md5-sign.phar
Binary file not shown.
Binary file not shown.
Binary file not shown.
Empty file.
Binary file not shown.
Binary file added fixtures/phar/simple-phar-openssl-sign.phar
Binary file not shown.
9 changes: 9 additions & 0 deletions fixtures/phar/simple-phar-openssl-sign.phar.pubkey
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAywa2fvnQ9yrS6ooOycSC
Ye775MTRq71mujt/c7U52VHbNAcR5bYZ0WV+IgJLqRxSjasUbfrTfMzuW6Ge7kdq
rAmzR3Y1LX4uRrvd3J9LnhR5ATd5ujrHkaS8HVHVVC2xOEUn4Yeo23xOsWYKqDju
DlcZXtjPMofXZBVwX8h9rtWCuLlAqyP4UbcFD4YsSHuVlAIl5SxM0xtYrdkjpENa
YTzJswBDtxfJ5uN7IzwL5C6arbPRw16RvloldvkkVqAkZrNUbdDCG4QQ86lTo0tg
rALcaNK0VDRYmd2jwJK6sOjJpI0zi+/yLGih4cVenmXQzSXm0qbH9Is4E45PaNAT
mQIDAQAB
-----END PUBLIC KEY-----
Binary file added fixtures/phar/simple-phar-openssl-sign.tar
Binary file not shown.
Binary file added fixtures/phar/simple-phar-sha1-sign.phar
Binary file not shown.
Binary file added fixtures/phar/simple-phar-sha256-sign.phar
Binary file not shown.
Binary file added fixtures/phar/simple-phar-sha512-sign.phar
Binary file not shown.
Binary file added fixtures/phar/simple-phar.phar
Binary file not shown.
Binary file added fixtures/phar/simple.tar
Binary file not shown.
Binary file added fixtures/phar/simple.tar.bz2
Binary file not shown.
Binary file added fixtures/phar/simple.tar.bz2.phar
Binary file not shown.
Binary file added fixtures/phar/simple.tar.gz
Binary file not shown.
Binary file added fixtures/phar/simple.tar.gz.phar
Binary file not shown.
Binary file added fixtures/phar/simple.tar.phar
Binary file not shown.
Binary file added fixtures/phar/simple.zip
Binary file not shown.
Binary file added fixtures/phar/simple.zip.phar
Binary file not shown.
2 changes: 1 addition & 1 deletion src/Console/Command/Extract.php
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ private static function createPhar(string $file, string $tmpFile): Phar|PharData
try {
return new Phar($tmpFile);
} catch (UnexpectedValueException $cannotCreatePhar) {
throw InvalidPhar::create($file, $cannotCreatePhar);
throw InvalidPhar::forPhar($file, $cannotCreatePhar);
}
}
}
114 changes: 114 additions & 0 deletions src/Phar/PharFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
<?php

declare(strict_types=1);

/*
* This file is part of the box project.
*
* (c) Kevin Herrera <kevin@herrera.io>
* Théo Fidry <theo.fidry@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

namespace KevinGH\Box\Phar;

use KevinGH\Box\Pharaoh\InvalidPhar;
use Phar;
use PharData;
use Symfony\Component\Filesystem\Path;
use Throwable;
use function file_exists;

/**
* Factory class to instantiate an _existing_ file (i.e. not to create a brand-new PHAR object).
* It is a thin wrapper around the native PHP constructor but with more friendly errors upon failure.
*/
final class PharFactory
{
private function __construct()
{
}

/**
* @throws InvalidPhar
*/
public static function create(string $file): Phar|PharData
{
if (!Path::isLocal($file)) {
// This is needed as otherwise Phar::__construct() does correctly bail out on a URL
// path, but not on other non-local variants, e.g. FTPS, which case it may fail still
// but after a timeout, which is too slow.
throw InvalidPhar::fileNotLocal($file);
}

if (!file_exists($file)) {
// We need to check this case since the goal of this factory is to instantiate an existing
// PHAR, not create a new one.
throw InvalidPhar::fileNotFound($file);
}

try {
return new Phar($file);
} catch (Throwable $cannotCreatePhar) {
// Continue
}

try {
return new PharData($file);
} catch (Throwable) {
throw InvalidPhar::forPharAndPharData($file, $cannotCreatePhar);
}
}

/**
* @throws InvalidPhar
*/
public static function createPhar(string $file): Phar
{
if (!Path::isLocal($file)) {
// This is needed as otherwise Phar::__construct() does correctly bail out on a URL
// path, but not on other non-local variants, e.g. FTPS, which case it may fail still
// but after a timeout, which is too slow.
throw InvalidPhar::fileNotLocal($file);
}

if (!file_exists($file)) {
// We need to check this case since the goal of this factory is to instantiate an existing
// PHAR, not create a new one.
throw InvalidPhar::fileNotFound($file);
}

try {
return new Phar($file);
} catch (Throwable $throwable) {
throw InvalidPhar::forPhar($file, $throwable);
}
}

/**
* @throws InvalidPhar
*/
public static function createPharData(string $file): PharData
{
if (!Path::isLocal($file)) {
// This is needed as otherwise Phar::__construct() does correctly bail out on a URL
// path, but not on other non-local variants, e.g. FTPS, which case it may fail still
// but after a timeout, which is too slow.
throw InvalidPhar::fileNotLocal($file);
}

if (!file_exists($file)) {
// We need to check this case since the goal of this factory is to instantiate an existing
// PHAR, not create a new one.
throw InvalidPhar::fileNotFound($file);
}

try {
return new PharData($file);
} catch (Throwable $throwable) {
throw InvalidPhar::forPharData($file, $throwable);
}
}
}
Loading