Skip to content

Commit

Permalink
Restructure to be purely ZipArchive-based (#17)
Browse files Browse the repository at this point in the history
* Restructure to be purely ZipArchive-based

* Remove non-required RDONLY-mode in testing

* Update scrutinizer.yml

* Update readme

* Another scrutinizer-update

* Fix spacing-issue
  • Loading branch information
olssonm authored Dec 5, 2020
1 parent 8e71542 commit 824f330
Show file tree
Hide file tree
Showing 10 changed files with 99 additions and 153 deletions.
9 changes: 9 additions & 0 deletions .scrutinizer.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
filter:
excluded_paths: [tests/*]

build:
environment:
php:
version: 7.4

# see https://pecl.php.net/
pecl_extensions:
- zip

checks:
php:
remove_extra_empty_lines: true
Expand Down
12 changes: 6 additions & 6 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,6 @@ script:

jobs:
include:
- php: 7.2.24
env:
- ILLUMINATE_VERSION=7.0.*
- php: 7.2.24
env:
- ILLUMINATE_VERSION=^6.0
- php: 7.3
env:
- ILLUMINATE_VERSION=^6.0
Expand All @@ -34,3 +28,9 @@ jobs:
- php: 7.4
env:
- ILLUMINATE_VERSION=^8.0
- php: 8.0
env:
- ILLUMINATE_VERSION=^7.0
- php: 8.0
env:
- ILLUMINATE_VERSION=^8.0
24 changes: 11 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,20 @@ Backup Shield simply listens for when the .zip-file generated by Laravel-backup

*Using older versions of Laravel? Check out the [v1 branch](https://github.com/olssonm/laravel-backup-shield/tree/v1) (for Laravel 5.2) and the [v2 branch](https://github.com/olssonm/laravel-backup-shield/tree/v2).*

## Requirements

`php: 7.3|^8.0`
`ext-zip: ^1.14`
`laravel: ^6|^7|^8`

An appropriate zip-extension should be come with your PHP-install since PHP 7.2. If you for some reason don't have it installed – and don't want to install/upgrade it – look a versions prior to v3.4 of this package.

## Installation

```bash
composer require olssonm/laravel-backup-shield
```

Please note that `spatie/laravel-backup: "^6"` and `laravel/framework: "^6.0|^7.0"` requires PHP 7.2.

## Configuration

Publish your configuration using `php artisan vendor:publish` and select `BackupShieldServiceProvider`. Or directly via ```php artisan vendor:publish --provider="Olssonm\BackupShield\BackupShieldServiceProvider"```.
Expand All @@ -47,22 +53,14 @@ Set to `NULL` if you want to keep your backup without a password.

Set your type of encryption. Available options are:

`\Olssonm\BackupShield\Encryption::ENCRYPTION_DEFAULT` (PHP < 7.2: PKWARE/ZipCrypto, PHP >= 7.2: AES 128)
`\Olssonm\BackupShield\Encryption::ENCRYPTION_DEFAULT` (AES 128)
`\Olssonm\BackupShield\Encryption::ENCRYPTION_WINZIP_AES_128` (AES 128)
`\Olssonm\BackupShield\Encryption::ENCRYPTION_WINZIP_AES_192` (AES 192)
`\Olssonm\BackupShield\Encryption::ENCRYPTION_WINZIP_AES_256` (AES 256)

**Important information regarding encryption**

Using the `ENCRYPTION_DEFAULT` (PKWARE/ZipCrypto) crypto gives you the best portability as most operating systems can natively unzip the file – however, ZipCrypto might be weak. The Winzip AES-methods on the other hand might require a separate app and/or licence to be able to unzip depending on your OS; suggestions for macOS are [Keka](http://www.kekaosx.com/en/) and [Stuffit Expander](https://itunes.apple.com/us/app/stuffit-expander-16/id919269455).

Also to note is that when zipping very large files ZipCrypto might be very inefficient as the entire data-set will have to be loaded into memory to perform the encryption, if the zipped file's content is bigger than your available RAM you *will* run out of memory.

#### Differences when using PHP < 7.2 and PHP >= 7.2

Since PHP 7.2 (coupled with zip-extension >= 1.14.0) PHP can natively password-protect .zip-files via the ZipArchive-methods. If these conditions are met, ZipArchive is used. Else, the package will automatically use the [nelexa/zip](https://github.com/Ne-Lexa/php-zip)-package.
#### Regarding the layered archive

The former might be less memory-intensive.
This package adds the backup-zip created by spatie/laravel-backup inside a new password protected archive. This is to disable its contents to be able to be viewed without a password – instead only backup.zip will be displayed. Becouse, even without a password, a zip's contents (i.e. the file- and folder names) can be extracted.

## Testing

Expand Down
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@
}
],
"require": {
"php": "^7.2",
"php": "^7.3|^8.0",
"ext-zip": "^1.14.0",
"illuminate/support": "^6.0|^7.0|^8.0",
"nelexa/zip": "3.3",
"spatie/laravel-backup": "~6.0"
},
"require-dev": {
Expand Down
7 changes: 0 additions & 7 deletions src/BackupShieldServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Event;

use Olssonm\BackupShield\Factories\Password;
use Olssonm\BackupShield\Encryption;

use Spatie\Backup\Events\BackupZipWasCreated;
use Olssonm\BackupShield\Listeners\PasswordProtectZip;

Expand Down Expand Up @@ -61,10 +58,6 @@ public function boot() : void
*/
public function register() : void
{
$this->app->singleton('Olssonm\BackupShield\Encryption', function ($app) {
return new \Olssonm\BackupShield\Encryption;
});

$this->mergeConfigFrom(
$this->config, 'backup-shield'
);
Expand Down
55 changes: 5 additions & 50 deletions src/Encryption.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@

namespace Olssonm\BackupShield;

use PhpZip\ZipFile;

use \ZipArchive;
use ZipArchive;

class Encryption
{
Expand All @@ -13,69 +11,26 @@ class Encryption
*
* @var string
*/
const ENCRYPTION_DEFAULT = 'default';
const ENCRYPTION_DEFAULT = ZipArchive::EM_AES_128;

/**
* AES-128 encryption contants
*
* @var string
*/
const ENCRYPTION_WINZIP_AES_128 = 'aes_128';
const ENCRYPTION_WINZIP_AES_128 = ZipArchive::EM_AES_128;

/**
* AES-192 encryption contants
*
* @var string
*/
const ENCRYPTION_WINZIP_AES_192 = 'aes_192';
const ENCRYPTION_WINZIP_AES_192 = ZipArchive::EM_AES_192;

/**
* AES-256 encryption contants
*
* @var string
*/
const ENCRYPTION_WINZIP_AES_256 = 'aes_256';

/**
* ZipArchive encryption constants; stores as simple string for PHP < 7.2
* backwards compatability
*
* @var array
*/
private $zipArchiveOptions = [
self::ENCRYPTION_DEFAULT => '257',
self::ENCRYPTION_WINZIP_AES_128 => '257',
self::ENCRYPTION_WINZIP_AES_192 => '258',
self::ENCRYPTION_WINZIP_AES_256 => '259',
];

/**
* ZipFile encryption constants
*
* @var array
*/
private $zipFileOptions = [
self::ENCRYPTION_DEFAULT => \PhpZip\Constants\ZipEncryptionMethod::PKWARE,
self::ENCRYPTION_WINZIP_AES_128 => \PhpZip\Constants\ZipEncryptionMethod::WINZIP_AES_128,
self::ENCRYPTION_WINZIP_AES_192 => \PhpZip\Constants\ZipEncryptionMethod::WINZIP_AES_192,
self::ENCRYPTION_WINZIP_AES_256 => \PhpZip\Constants\ZipEncryptionMethod::WINZIP_AES_256,
];

/**
* Retrive appropriate encryption constant
*
* @param string $type
* @param string $engine
* @return mixed
*/
public function getEncryptionConstant($type, $engine)
{
if ($engine == 'ZipArchive' && isset($this->zipArchiveOptions[$type])) {
return $this->zipArchiveOptions[$type];
} elseif ($engine == 'ZipFile' && isset($this->zipFileOptions[$type])) {
return $this->zipFileOptions[$type];
} else {
throw new \Exception("Encryption key not set or invalid value", 1);
}
}
const ENCRYPTION_WINZIP_AES_256 = ZipArchive::EM_AES_256;
}
57 changes: 11 additions & 46 deletions src/Factories/Password.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@

use Illuminate\Support\Collection;
use Olssonm\BackupShield\Encryption;
use PhpZip\ZipFile;
use PhpZip\Constants\ZipCompressionMethod;

use \ZipArchive;

class Password
Expand All @@ -27,77 +26,43 @@ class Password
/**
* Read the .zip, apply password and encryption, then rewrite the file
*
* @param Encryption $encryption
* @param string $path
*/
function __construct(Encryption $encryption, string $path)
function __construct(string $path)
{
$this->password = config('backup-shield.password');

if (!$this->password) {
// If no password is set, just return the backup-path
if (!$this->password) {
return $this->path = $path;
}

// If ZipArchive is enabled
if (class_exists('ZipArchive') && in_array('setEncryptionIndex', get_class_methods('ZipArchive'))) {
consoleOutput()->info('Applying password and encryption to zip using ZipArchive...');
$this->makeZipArchive($encryption, $path);
}

// Fall back on PHP-driven ZipFile
else {
consoleOutput()->info('Applying password and encryption to zip using ZipFile...');
$this->makeZipFile($encryption, $path);
}
consoleOutput()->info('Applying password and encryption to zip using ZipArchive...');

$this->makeZip($path);

consoleOutput()->info('Successfully applied password and encryption to zip.');
}

/**
* Use native PHP ZipArchive
*
* @param Encryption $encryption
* @return void
*/
protected function makeZipArchive(Encryption $encryption, string $path) : void
protected function makeZip(string $path): void
{
$encryptionConstant = $encryption->getEncryptionConstant(
config('backup-shield.encryption'),
'ZipArchive'
);
$encryption = config('backup-shield.encryption');

$zipArchive = new ZipArchive;

$zipArchive->open($path, ZipArchive::OVERWRITE);
$zipArchive->addFile($path, 'backup.zip');
$zipArchive->setPassword($this->password);
Collection::times($zipArchive->numFiles, function ($i) use ($zipArchive, $encryptionConstant) {
$zipArchive->setEncryptionIndex($i - 1, $encryptionConstant);
Collection::times($zipArchive->numFiles, function($i) use ($zipArchive, $encryption) {
$zipArchive->setEncryptionIndex($i - 1, $encryption);
});
$zipArchive->close();

$this->path = $path;
}

/**
* Use PhpZip\ZipFile-package to create the zip
*
* @param Encryption $encryption
* @return void
*/
protected function makeZipFile(Encryption $encryption, string $path) : void
{
$encryptionConstant = $encryption->getEncryptionConstant(
config('backup-shield.encryption'),
'ZipFile'
);

$zipFile = new ZipFile();
$zipFile->addFile($path, 'backup.zip', ZipCompressionMethod::DEFLATED);
$zipFile->setPassword($this->password, $encryptionConstant);
$zipFile->saveAsFile($path);
$zipFile->close();

$this->path = $path;
}
}
2 changes: 1 addition & 1 deletion src/Listeners/PasswordProtectZip.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ public function __construct()
*/
public function handle(BackupZipWasCreated $event) : string
{
return (new Password(new \Olssonm\BackupShield\Encryption, $event->pathToZip))->path;
return (new Password($event->pathToZip))->path;
}
}
2 changes: 1 addition & 1 deletion src/config/backup-shield.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
'encryption' => \Olssonm\BackupShield\Encryption::ENCRYPTION_DEFAULT

// Available encryption methods:
// \Olssonm\BackupShield\Encryption::ENCRYPTION_DEFAULT (PHP < 7.2: PKWARE/ZipCrypto, PHP >= 7.2: AES 128)
// \Olssonm\BackupShield\Encryption::ENCRYPTION_DEFAULT (AES 128)
// \Olssonm\BackupShield\Encryption::ENCRYPTION_WINZIP_AES_128 (AES 128)
// \Olssonm\BackupShield\Encryption::ENCRYPTION_WINZIP_AES_192 (AES 192)
// \Olssonm\BackupShield\Encryption::ENCRYPTION_WINZIP_AES_256 (AES 256)
Expand Down
Loading

0 comments on commit 824f330

Please sign in to comment.