Drop PHP 8.0 support & Fix unique validation rules

This commit is contained in:
Bubka 2023-03-25 00:20:39 +01:00
parent fe5dce8d38
commit ad8db3ae3b
9 changed files with 1263 additions and 1315 deletions

2
Dockerfile vendored
View File

@ -1,7 +1,7 @@
ARG BUILDPLATFORM=linux/amd64
ARG TARGETPLATFORM
ARG ALPINE_VERSION=3.16
ARG PHP_VERSION=8.0-alpine${ALPINE_VERSION}
ARG PHP_VERSION=8.1-alpine${ALPINE_VERSION}
ARG COMPOSER_VERSION=2.3
ARG SUPERVISORD_VERSION=v0.7.3

View File

@ -32,7 +32,7 @@ I created it because :
* Edit accounts, even the imported ones
* Generate TOTP and HOTP security codes and Steam Guard codes
2FAuth is currently fully localized in English and French. See [Contributing](#Contributing) if you want to help on adding more languages.
2FAuth is currently fully localized in English and French. See [Contributing](#contributing) if you want to help on adding more languages.
## Security
@ -60,7 +60,7 @@ Sensitive data stored in the database can be encrypted to protect them against d
## Requirements
* [![Requires PHP8](https://img.shields.io/badge/php-^8.0-red.svg?style=flat-square)](https://secure.php.net/downloads.php)
* [![Requires PHP8](https://img.shields.io/badge/php-^8.1-red.svg?style=flat-square)](https://secure.php.net/downloads.php)
* See [Laravel server requirements](https://laravel.com/docs/7.x/installation#server-requirements)
* Any database [supported by Laravel](https://laravel.com/docs/7.x/database)

View File

@ -4,6 +4,7 @@ namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\Rule;
class UserUpdateRequest extends FormRequest
{
@ -25,8 +26,18 @@ class UserUpdateRequest extends FormRequest
public function rules()
{
return [
'name' => 'unique:App\Models\User,name|required|string|max:255',
'email' => 'unique:App\Models\User,email|required|string|email|max:255',
'name' => [
'required',
'string',
'max:255',
Rule::unique('users')->ignore($this->user()->id),
],
'email' => [
'required',
'email',
'max:255',
Rule::unique('users')->ignore($this->user()->id),
],
'password' => 'required',
];
}

View File

@ -8,7 +8,7 @@
],
"license": "MIT",
"require": {
"php": "^8.0.2",
"php": "^8.1",
"ext-bcmath": "*",
"ext-ctype": "*",
"ext-dom": "*",
@ -21,34 +21,30 @@
"ext-tokenizer": "*",
"ext-xml": "*",
"chillerlan/php-qrcode": "^4.3",
"laragear/webauthn": "^1.1.0",
"laragear/webauthn": "^1.2.0",
"doctormckay/steam-totp": "^1.0",
"doctrine/dbal": "^3.4",
"fruitcake/laravel-cors": "^2.0",
"google/protobuf": "^3.21",
"guzzlehttp/guzzle": "^7.2",
"khanamiryan/qrcode-detector-decoder": "^1.0.5",
"khanamiryan/qrcode-detector-decoder": "^2.0.2",
"laravel/framework": "^9.0",
"laravel/passport": "^11.2",
"laravel/tinker": "^2.7",
"laravel/ui": "^3.0",
"paragonie/constant_time_encoding": "^2.6",
"spatie/eloquent-sortable": "^4.0.1",
"spomky-labs/otphp": "^10.0"
"spomky-labs/otphp": "^11.0"
},
"require-dev": {
"barryvdh/laravel-ide-helper": "^2.12",
"fakerphp/faker": "^1.20",
"laravel/pint": "^1.2",
"barryvdh/laravel-ide-helper": "^2.13",
"fakerphp/faker": "^1.21",
"laravel/pint": "^1.6",
"mockery/mockery": "^1.5",
"nunomaduro/collision": "^6.1",
"nunomaduro/larastan": "^2.0",
"phpstan/phpstan": "^1.8",
"phpunit/phpunit": "^9.5",
"spatie/laravel-ignition": "^1.0"
},
"conflict": {
"khanamiryan/qrcode-detector-decoder": "~1.0.6"
"nunomaduro/larastan": "^2.5",
"phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^9.6",
"spatie/laravel-ignition": "^1.6"
},
"config": {
"optimize-autoloader": true,
@ -85,17 +81,17 @@
"post-create-project-cmd": [
"@php artisan key:generate --ansi"
],
"test" : [
"test": [
"php artisan config:clear",
"vendor/bin/phpunit"
],
"test-mysql" : [
"test-mysql": [
"php artisan config:clear",
"vendor/bin/phpunit -c phpunit-mysql.xml"
],
"test-coverage-html" : [
"test-coverage-html": [
"@putenv XDEBUG_MODE=coverage",
"vendor/bin/phpunit --coverage-html tests/Coverage/"
]
}
}
}

2396
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -30,7 +30,7 @@ We assume your current directory is `/yourpath`.
chmod 700 2fauth
```
💁 if you feel like using another ID, you can [build the image with build arguments](#Build-the-image-with-build-arguments).
💁 if you feel like using another ID, you can [build the image with build arguments](#build-the-image-with-build-arguments).
1. Run the container interactively:
@ -102,7 +102,7 @@ There are the following build arguments you can use to customize the image using
| `UID` | 1000 | The UID of the user to run the container as |
| `GID` | 1000 | The GID of the user to run the container as |
| `DEBIAN_VERSION` | `buster-slim` | The Debian version to use |
| `PHP_VERSION` | `8.0-buster` | The PHP version to use to get composer dependencies |
| `PHP_VERSION` | `8.1-buster` | The PHP version to use to get composer dependencies |
| `COMPOSER_VERSION` | `2.3` | The version of composer to use |
| `SUPERVISORD_VERSION` | `v0.7.3` | The version of supervisord to use |
| `VERSION` | `unknown` | The version of the image |
@ -112,7 +112,7 @@ There are the following build arguments you can use to customize the image using
#### Mail settings
> Refer your email provider documentation to configure your mail settings
>
>
> Set a value for every available setting to avoid issue
| Build argument | Recommendation | Description |

View File

@ -4,8 +4,8 @@ This applies to Debian Buster, but similar instructions should apply for other D
## What we will do
- We will use PHP 8.0
- We will use version v3.3.0 of 2fauth
- We will use PHP 8.1
- We will use version v4.0.0 of 2fauth
- We will setup to use an Sqlite database
- We will use Nginx and PHP-FPM to serve our site on port `8000`
- We will run all this as user `www-data` without root
@ -22,11 +22,11 @@ This applies to Debian Buster, but similar instructions should apply for other D
```bash
apt-get install -y --no-install-recommends \
php8.0 \
php8.0-sqlite3 php8.0-mysql \
php-xml php8.0-gd php8.0-mbstring \
php8.1 \
php8.1-sqlite3 php8.1-mysql \
php-xml php8.1-gd php8.1-mbstring \
unzip wget ca-certificates \
php8.0-fpm nginx
php8.1-fpm nginx
```
## Download the code
@ -71,7 +71,7 @@ http {
error_page 404 /index.php;
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.0-fpm.sock;
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
@ -129,7 +129,7 @@ chmod 500 /usr/local/bin/composer
startretries=0
[program:php-fpm]
command=/usr/sbin/php-fpm8.0 -F
command=/usr/sbin/php-fpm8.1 -F
[program:nginx]
command=/usr/sbin/nginx -g 'daemon off;'
@ -155,14 +155,14 @@ chmod 500 /usr/local/bin/composer
```bash
mkdir -p /run/php /www/data/.composer
touch /run/nginx.pid /var/log/php8.0-fpm.log
touch /run/nginx.pid /var/log/php8.1-fpm.log
chown -R www-data \
/var/log/php8.0-fpm.log \
/var/log/php8.1-fpm.log \
/run/nginx.pid \
/run/php \
/www/data/.composer
chmod 700 /run/php /www/data/.composer
chmod 600 /var/log/php8.0-fpm.log
chmod 600 /var/log/php8.1-fpm.log
```
## Change user

View File

@ -63,6 +63,60 @@ class UserControllerTest extends FeatureTestCase
]);
}
/**
* @test
*/
public function test_update_user_without_changing_email_returns_success()
{
$response = $this->actingAs($this->user, 'web-guard')
->json('PUT', '/user', [
'name' => self::NEW_USERNAME,
'email' => $this->user->email,
'password' => self::PASSWORD,
])
->assertOk()
->assertExactJson([
'name' => self::NEW_USERNAME,
'id' => $this->user->id,
'email' => $this->user->email,
'is_admin' => false,
]);
$this->assertDatabaseHas('users', [
'name' => self::NEW_USERNAME,
'id' => $this->user->id,
'email' => $this->user->email,
'is_admin' => false,
]);
}
/**
* @test
*/
public function test_update_user_without_changing_name_returns_success()
{
$response = $this->actingAs($this->user, 'web-guard')
->json('PUT', '/user', [
'name' => $this->user->name,
'email' => self::NEW_EMAIL,
'password' => self::PASSWORD,
])
->assertOk()
->assertExactJson([
'name' => $this->user->name,
'id' => $this->user->id,
'email' => self::NEW_EMAIL,
'is_admin' => false,
]);
$this->assertDatabaseHas('users', [
'name' => $this->user->name,
'id' => $this->user->id,
'email' => self::NEW_EMAIL,
'is_admin' => false,
]);
}
/**
* @test
*/

View File

@ -7,6 +7,7 @@ use App\Models\User;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;
use Mockery;
use Tests\FeatureTestCase;
/**
@ -35,12 +36,18 @@ class UserUpdateRequestTest extends FeatureTestCase
*/
public function test_valid_data(array $data) : void
{
User::factory()->create([
/**
* @var \App\Models\User|\Illuminate\Contracts\Auth\Authenticatable
*/
$user = User::factory()->create([
'name' => 'Jane',
'email' => 'jane@example.com',
]);
$request = new UserUpdateRequest();
$request = Mockery::mock(UserUpdateRequest::class)->makePartial();
$request->shouldReceive('user')
->andReturn($user);
$validator = Validator::make($data, $request->rules());
$this->assertFalse($validator->fails());
@ -57,6 +64,16 @@ class UserUpdateRequestTest extends FeatureTestCase
'email' => 'john@example.com',
'password' => 'MyPassword',
]],
[[
'name' => 'John',
'email' => 'jane@example.com',
'password' => 'MyPassword',
]],
[[
'name' => 'Jane',
'email' => 'john@example.com',
'password' => 'MyPassword',
]],
];
}
@ -65,12 +82,23 @@ class UserUpdateRequestTest extends FeatureTestCase
*/
public function test_invalid_data(array $data) : void
{
User::factory()->create([
/**
* @var \App\Models\User|\Illuminate\Contracts\Auth\Authenticatable
*/
$user = User::factory()->create([
'name' => 'Jane',
'email' => 'jane@example.com',
]);
$request = new UserUpdateRequest();
User::factory()->create([
'name' => 'Bob',
'email' => 'bob@example.com',
]);
$request = Mockery::mock(UserUpdateRequest::class)->makePartial();
$request->shouldReceive('user')
->andReturn($user);
$validator = Validator::make($data, $request->rules());
$this->assertTrue($validator->fails());
@ -83,8 +111,13 @@ class UserUpdateRequestTest extends FeatureTestCase
{
return [
[[
'name' => 'John',
'email' => 'jane@example.com', // unique
'name' => 'Jane',
'email' => 'bob@example.com', // unique
'password' => 'MyPassword',
]],
[[
'name' => 'Bob', // unique
'email' => 'jane@example.com',
'password' => 'MyPassword',
]],
[[