diff --git a/.ci/all.sh b/.ci/all.sh new file mode 100755 index 0000000000..e8a7f272e4 --- /dev/null +++ b/.ci/all.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +# +# all.sh +# Copyright (c) 2024 james@firefly-iii.org +# +# This file is part of Firefly III (https://github.com/firefly-iii). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# + +SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" + +$SCRIPT_DIR/phpcs.sh +$SCRIPT_DIR/phpstan.sh +$SCRIPT_DIR/phpmd.sh diff --git a/app/Api/V1/Requests/Models/Account/StoreRequest.php b/app/Api/V1/Requests/Models/Account/StoreRequest.php index 50a76d70e8..76049d4c14 100644 --- a/app/Api/V1/Requests/Models/Account/StoreRequest.php +++ b/app/Api/V1/Requests/Models/Account/StoreRequest.php @@ -26,6 +26,7 @@ namespace FireflyIII\Api\V1\Requests\Models\Account; use FireflyIII\Models\Location; use FireflyIII\Rules\IsBoolean; +use FireflyIII\Rules\IsValidPositiveAmount; use FireflyIII\Rules\UniqueAccountNumber; use FireflyIII\Rules\UniqueIban; use FireflyIII\Support\Request\AppendsLocationData; @@ -113,7 +114,7 @@ class StoreRequest extends FormRequest 'credit_card_type' => sprintf('nullable|in:%s|required_if:account_role,ccAsset', $ccPaymentTypes), 'monthly_payment_date' => 'nullable|date|required_if:account_role,ccAsset|required_if:credit_card_type,monthlyFull', 'liability_type' => 'nullable|required_if:type,liability|required_if:type,liabilities|in:loan,debt,mortgage', - 'liability_amount' => 'required_with:liability_start_date|min:0|numeric|max:1000000000', + 'liability_amount' => ['required_with:liability_start_date', new IsValidPositiveAmount()], 'liability_start_date' => 'required_with:liability_amount|date', 'liability_direction' => 'nullable|required_if:type,liability|required_if:type,liabilities|in:credit,debit', 'interest' => 'between:0,100|numeric', diff --git a/app/Api/V1/Requests/Models/AvailableBudget/Request.php b/app/Api/V1/Requests/Models/AvailableBudget/Request.php index e20e8513ac..5c653194e4 100644 --- a/app/Api/V1/Requests/Models/AvailableBudget/Request.php +++ b/app/Api/V1/Requests/Models/AvailableBudget/Request.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace FireflyIII\Api\V1\Requests\Models\AvailableBudget; use Carbon\Carbon; +use FireflyIII\Rules\IsValidPositiveAmount; use FireflyIII\Support\Request\ChecksLogin; use FireflyIII\Support\Request\ConvertsDataTypes; use Illuminate\Foundation\Http\FormRequest; @@ -62,7 +63,7 @@ class Request extends FormRequest return [ 'currency_id' => 'numeric|exists:transaction_currencies,id', 'currency_code' => 'min:3|max:51|exists:transaction_currencies,code', - 'amount' => 'numeric|gt:0|max:1000000000', + 'amount' => ['nullable', new IsValidPositiveAmount()], 'start' => 'date', 'end' => 'date', ]; diff --git a/app/Api/V1/Requests/Models/Bill/StoreRequest.php b/app/Api/V1/Requests/Models/Bill/StoreRequest.php index bc0ff0a208..a29f4106c8 100644 --- a/app/Api/V1/Requests/Models/Bill/StoreRequest.php +++ b/app/Api/V1/Requests/Models/Bill/StoreRequest.php @@ -25,6 +25,7 @@ declare(strict_types=1); namespace FireflyIII\Api\V1\Requests\Models\Bill; use FireflyIII\Rules\IsBoolean; +use FireflyIII\Rules\IsValidPositiveAmount; use FireflyIII\Support\Request\ChecksLogin; use FireflyIII\Support\Request\ConvertsDataTypes; use Illuminate\Foundation\Http\FormRequest; @@ -72,8 +73,8 @@ class StoreRequest extends FormRequest { return [ 'name' => 'between:1,255|uniqueObjectForUser:bills,name', - 'amount_min' => 'numeric|gt:0|required|max:1000000000', - 'amount_max' => 'numeric|gt:0|required|max:1000000000', + 'amount_min' => ['required', new IsValidPositiveAmount()], + 'amount_max' => ['required', new IsValidPositiveAmount()], 'currency_id' => 'numeric|exists:transaction_currencies,id', 'currency_code' => 'min:3|max:51|exists:transaction_currencies,code', 'date' => 'date|required', diff --git a/app/Api/V1/Requests/Models/Bill/UpdateRequest.php b/app/Api/V1/Requests/Models/Bill/UpdateRequest.php index 8965ff84d9..f5896eff17 100644 --- a/app/Api/V1/Requests/Models/Bill/UpdateRequest.php +++ b/app/Api/V1/Requests/Models/Bill/UpdateRequest.php @@ -26,6 +26,7 @@ namespace FireflyIII\Api\V1\Requests\Models\Bill; use FireflyIII\Models\Bill; use FireflyIII\Rules\IsBoolean; +use FireflyIII\Rules\IsValidPositiveAmount; use FireflyIII\Support\Request\ChecksLogin; use FireflyIII\Support\Request\ConvertsDataTypes; use Illuminate\Foundation\Http\FormRequest; @@ -75,8 +76,8 @@ class UpdateRequest extends FormRequest return [ 'name' => sprintf('between:1,255|uniqueObjectForUser:bills,name,%d', $bill->id), - 'amount_min' => 'numeric|gt:0|max:1000000000', - 'amount_max' => 'numeric|gt:0|max:1000000000', + 'amount_min' => ['nullable', new IsValidPositiveAmount()], + 'amount_max' => ['nullable', new IsValidPositiveAmount()], 'currency_id' => 'numeric|exists:transaction_currencies,id', 'currency_code' => 'min:3|max:51|exists:transaction_currencies,code', 'date' => 'date', diff --git a/app/Api/V1/Requests/Models/Budget/StoreRequest.php b/app/Api/V1/Requests/Models/Budget/StoreRequest.php index 62911d258b..2932342ddc 100644 --- a/app/Api/V1/Requests/Models/Budget/StoreRequest.php +++ b/app/Api/V1/Requests/Models/Budget/StoreRequest.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace FireflyIII\Api\V1\Requests\Models\Budget; use FireflyIII\Rules\IsBoolean; +use FireflyIII\Rules\IsValidPositiveAmount; use FireflyIII\Support\Request\ChecksLogin; use FireflyIII\Support\Request\ConvertsDataTypes; use FireflyIII\Validation\AutoBudget\ValidatesAutoBudgetRequest; @@ -74,7 +75,7 @@ class StoreRequest extends FormRequest 'notes' => 'nullable|between:1,65536', // auto budget info 'auto_budget_type' => 'in:reset,rollover,adjusted,none', - 'auto_budget_amount' => 'numeric|min:0|max:1000000000|required_if:auto_budget_type,reset|required_if:auto_budget_type,rollover|required_if:auto_budget_type,adjusted', + 'auto_budget_amount' => ['required_if:auto_budget_type,reset', 'required_if:auto_budget_type,rollover', 'required_if:auto_budget_type,adjusted', new IsValidPositiveAmount()], 'auto_budget_period' => 'in:daily,weekly,monthly,quarterly,half_year,yearly|required_if:auto_budget_type,reset|required_if:auto_budget_type,rollover|required_if:auto_budget_type,adjusted', ]; } diff --git a/app/Api/V1/Requests/Models/Budget/UpdateRequest.php b/app/Api/V1/Requests/Models/Budget/UpdateRequest.php index 08c7680f17..fb520d6a16 100644 --- a/app/Api/V1/Requests/Models/Budget/UpdateRequest.php +++ b/app/Api/V1/Requests/Models/Budget/UpdateRequest.php @@ -25,6 +25,7 @@ namespace FireflyIII\Api\V1\Requests\Models\Budget; use FireflyIII\Models\Budget; use FireflyIII\Rules\IsBoolean; +use FireflyIII\Rules\IsValidPositiveAmount; use FireflyIII\Support\Request\ChecksLogin; use FireflyIII\Support\Request\ConvertsDataTypes; use FireflyIII\Validation\AutoBudget\ValidatesAutoBudgetRequest; @@ -86,7 +87,7 @@ class UpdateRequest extends FormRequest 'auto_budget_type' => 'in:reset,rollover,adjusted,none', 'auto_budget_currency_id' => 'exists:transaction_currencies,id', 'auto_budget_currency_code' => 'exists:transaction_currencies,code', - 'auto_budget_amount' => 'min:0|max:1000000000', + 'auto_budget_amount' => ['nullable', new IsValidPositiveAmount()], 'auto_budget_period' => 'in:daily,weekly,monthly,quarterly,half_year,yearly', ]; } diff --git a/app/Api/V1/Requests/Models/BudgetLimit/StoreRequest.php b/app/Api/V1/Requests/Models/BudgetLimit/StoreRequest.php index 769648004a..a47e705ff8 100644 --- a/app/Api/V1/Requests/Models/BudgetLimit/StoreRequest.php +++ b/app/Api/V1/Requests/Models/BudgetLimit/StoreRequest.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace FireflyIII\Api\V1\Requests\Models\BudgetLimit; +use FireflyIII\Rules\IsValidPositiveAmount; use FireflyIII\Support\Request\ChecksLogin; use FireflyIII\Support\Request\ConvertsDataTypes; use Illuminate\Foundation\Http\FormRequest; @@ -57,7 +58,7 @@ class StoreRequest extends FormRequest return [ 'start' => 'required|before:end|date', 'end' => 'required|after:start|date', - 'amount' => 'required|gt:0|max:1000000000', + 'amount' => ['required', new IsValidPositiveAmount()], 'currency_id' => 'numeric|exists:transaction_currencies,id', 'currency_code' => 'min:3|max:51|exists:transaction_currencies,code', ]; diff --git a/app/Api/V1/Requests/Models/BudgetLimit/UpdateRequest.php b/app/Api/V1/Requests/Models/BudgetLimit/UpdateRequest.php index 637e884695..44921ac890 100644 --- a/app/Api/V1/Requests/Models/BudgetLimit/UpdateRequest.php +++ b/app/Api/V1/Requests/Models/BudgetLimit/UpdateRequest.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace FireflyIII\Api\V1\Requests\Models\BudgetLimit; use Carbon\Carbon; +use FireflyIII\Rules\IsValidPositiveAmount; use FireflyIII\Support\Request\ChecksLogin; use FireflyIII\Support\Request\ConvertsDataTypes; use Illuminate\Foundation\Http\FormRequest; @@ -61,7 +62,7 @@ class UpdateRequest extends FormRequest return [ 'start' => 'date', 'end' => 'date', - 'amount' => 'gt:0|max:1000000000', + 'amount' => ['nullable', new IsValidPositiveAmount()], 'currency_id' => 'numeric|exists:transaction_currencies,id', 'currency_code' => 'min:3|max:51|exists:transaction_currencies,code', ]; diff --git a/app/Api/V1/Requests/Models/PiggyBank/StoreRequest.php b/app/Api/V1/Requests/Models/PiggyBank/StoreRequest.php index f9125717a6..58aafada70 100644 --- a/app/Api/V1/Requests/Models/PiggyBank/StoreRequest.php +++ b/app/Api/V1/Requests/Models/PiggyBank/StoreRequest.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace FireflyIII\Api\V1\Requests\Models\PiggyBank; +use FireflyIII\Rules\IsValidPositiveAmount; use FireflyIII\Support\Request\ChecksLogin; use FireflyIII\Support\Request\ConvertsDataTypes; use Illuminate\Foundation\Http\FormRequest; @@ -64,11 +65,11 @@ class StoreRequest extends FormRequest { return [ 'name' => 'required|between:1,255|uniquePiggyBankForUser', - 'current_amount' => ['numeric', 'gte:0', 'lte:target_amount', 'max:1000000000'], + 'current_amount' => ['nullable', new IsValidPositiveAmount()], 'account_id' => 'required|numeric|belongsToUser:accounts,id', 'object_group_id' => 'numeric|belongsToUser:object_groups,id', 'object_group_title' => 'between:1,255', - 'target_amount' => ['numeric', 'gte:0', 'lte:target_amount', 'required', 'max:1000000000'], + 'target_amount' => ['required', new IsValidPositiveAmount()], 'start_date' => 'date|nullable', 'target_date' => 'date|nullable|after:start_date', 'notes' => 'max:65000', diff --git a/app/Api/V1/Requests/Models/PiggyBank/UpdateRequest.php b/app/Api/V1/Requests/Models/PiggyBank/UpdateRequest.php index 8350906fc5..f2abb703cc 100644 --- a/app/Api/V1/Requests/Models/PiggyBank/UpdateRequest.php +++ b/app/Api/V1/Requests/Models/PiggyBank/UpdateRequest.php @@ -25,6 +25,7 @@ namespace FireflyIII\Api\V1\Requests\Models\PiggyBank; use FireflyIII\Models\PiggyBank; use FireflyIII\Rules\IsAssetAccountId; +use FireflyIII\Rules\IsValidPositiveAmount; use FireflyIII\Rules\LessThanPiggyTarget; use FireflyIII\Support\Request\ChecksLogin; use FireflyIII\Support\Request\ConvertsDataTypes; @@ -69,8 +70,8 @@ class UpdateRequest extends FormRequest return [ 'name' => 'between:1,255|uniquePiggyBankForUser:'.$piggyBank->id, - 'current_amount' => ['numeric', 'gte:0', new LessThanPiggyTarget(), 'max:1000000000'], - 'target_amount' => 'numeric|gte:0|max:1000000000', + 'current_amount' => ['nullable', new LessThanPiggyTarget(), new IsValidPositiveAmount()], + 'target_amount' => ['nullable', new IsValidPositiveAmount()], 'start_date' => 'date|nullable', 'target_date' => 'date|nullable|after:start_date', 'notes' => 'max:65000', diff --git a/app/Api/V1/Requests/Models/Recurrence/StoreRequest.php b/app/Api/V1/Requests/Models/Recurrence/StoreRequest.php index 00cc6273ee..dfdec0eb6f 100644 --- a/app/Api/V1/Requests/Models/Recurrence/StoreRequest.php +++ b/app/Api/V1/Requests/Models/Recurrence/StoreRequest.php @@ -25,6 +25,7 @@ namespace FireflyIII\Api\V1\Requests\Models\Recurrence; use FireflyIII\Rules\BelongsUser; use FireflyIII\Rules\IsBoolean; +use FireflyIII\Rules\IsValidPositiveAmount; use FireflyIII\Support\Request\ChecksLogin; use FireflyIII\Support\Request\ConvertsDataTypes; use FireflyIII\Support\Request\GetRecurrenceData; @@ -92,8 +93,8 @@ class StoreRequest extends FormRequest 'repetitions.*.weekend' => 'numeric|min:1|max:4', 'transactions.*.description' => 'required|between:1,255', - 'transactions.*.amount' => 'required|numeric|gt:0|max:1000000000', - 'transactions.*.foreign_amount' => 'nullable|numeric|gt:0|max:1000000000', + 'transactions.*.amount' => ['required', new IsValidPositiveAmount()], + 'transactions.*.foreign_amount' => ['nullable', new IsValidPositiveAmount()], 'transactions.*.currency_id' => 'nullable|numeric|exists:transaction_currencies,id', 'transactions.*.currency_code' => 'nullable|min:3|max:51|exists:transaction_currencies,code', 'transactions.*.foreign_currency_id' => 'nullable|numeric|exists:transaction_currencies,id', diff --git a/app/Api/V1/Requests/Models/Recurrence/UpdateRequest.php b/app/Api/V1/Requests/Models/Recurrence/UpdateRequest.php index 6efb5f0699..111f915303 100644 --- a/app/Api/V1/Requests/Models/Recurrence/UpdateRequest.php +++ b/app/Api/V1/Requests/Models/Recurrence/UpdateRequest.php @@ -26,6 +26,7 @@ namespace FireflyIII\Api\V1\Requests\Models\Recurrence; use FireflyIII\Models\Recurrence; use FireflyIII\Rules\BelongsUser; use FireflyIII\Rules\IsBoolean; +use FireflyIII\Rules\IsValidPositiveAmount; use FireflyIII\Support\Request\ChecksLogin; use FireflyIII\Support\Request\ConvertsDataTypes; use FireflyIII\Support\Request\GetRecurrenceData; @@ -99,8 +100,8 @@ class UpdateRequest extends FormRequest 'repetitions.*.weekend' => 'nullable|numeric|min:1|max:4', 'transactions.*.description' => 'between:1,255', - 'transactions.*.amount' => 'numeric|gt:0|max:1000000000', - 'transactions.*.foreign_amount' => 'nullable|numeric|gt:0|max:1000000000', + 'transactions.*.amount' => [new IsValidPositiveAmount()], + 'transactions.*.foreign_amount' => ['nullable', new IsValidPositiveAmount()], 'transactions.*.currency_id' => 'nullable|numeric|exists:transaction_currencies,id', 'transactions.*.currency_code' => 'nullable|min:3|max:51|exists:transaction_currencies,code', 'transactions.*.foreign_currency_id' => 'nullable|numeric|exists:transaction_currencies,id', @@ -164,15 +165,15 @@ class UpdateRequest extends FormRequest } if (array_key_exists('moment', $repetition)) { - $current['moment'] = (string)$repetition['moment']; + $current['moment'] = (string) $repetition['moment']; } if (array_key_exists('skip', $repetition)) { - $current['skip'] = (int)$repetition['skip']; + $current['skip'] = (int) $repetition['skip']; } if (array_key_exists('weekend', $repetition)) { - $current['weekend'] = (int)$repetition['weekend']; + $current['weekend'] = (int) $repetition['weekend']; } $return[] = $current; } diff --git a/app/Api/V1/Requests/Models/Transaction/StoreRequest.php b/app/Api/V1/Requests/Models/Transaction/StoreRequest.php index 0a5127aedc..aac847328a 100644 --- a/app/Api/V1/Requests/Models/Transaction/StoreRequest.php +++ b/app/Api/V1/Requests/Models/Transaction/StoreRequest.php @@ -27,6 +27,7 @@ namespace FireflyIII\Api\V1\Requests\Models\Transaction; use FireflyIII\Rules\BelongsUser; use FireflyIII\Rules\IsBoolean; use FireflyIII\Rules\IsDateOrTime; +use FireflyIII\Rules\IsValidPositiveAmount; use FireflyIII\Support\NullArrayObject; use FireflyIII\Support\Request\AppendsLocationData; use FireflyIII\Support\Request\ChecksLogin; @@ -92,8 +93,8 @@ class StoreRequest extends FormRequest 'transactions.*.foreign_currency_code' => 'min:3|max:51|exists:transaction_currencies,code|nullable', // amount - 'transactions.*.amount' => 'required|numeric|gt:0|max:1000000000', - 'transactions.*.foreign_amount' => 'numeric|max:1000000000|gt:0|', + 'transactions.*.amount' => ['required', new IsValidPositiveAmount()], + 'transactions.*.foreign_amount' => ['nullable', new IsValidPositiveAmount()], // description 'transactions.*.description' => 'nullable|between:1,1000', diff --git a/app/Api/V1/Requests/Models/Transaction/UpdateRequest.php b/app/Api/V1/Requests/Models/Transaction/UpdateRequest.php index 501534115f..201da4c38c 100644 --- a/app/Api/V1/Requests/Models/Transaction/UpdateRequest.php +++ b/app/Api/V1/Requests/Models/Transaction/UpdateRequest.php @@ -29,6 +29,7 @@ use FireflyIII\Models\TransactionGroup; use FireflyIII\Rules\BelongsUser; use FireflyIII\Rules\IsBoolean; use FireflyIII\Rules\IsDateOrTime; +use FireflyIII\Rules\IsValidPositiveAmount; use FireflyIII\Support\Request\ChecksLogin; use FireflyIII\Support\Request\ConvertsDataTypes; use FireflyIII\Validation\GroupValidation; @@ -115,8 +116,8 @@ class UpdateRequest extends FormRequest 'transactions.*.foreign_currency_code' => 'nullable|min:3|max:51|exists:transaction_currencies,code', // amount - 'transactions.*.amount' => 'numeric|gt:0|max:100000000000', - 'transactions.*.foreign_amount' => 'nullable|numeric|gte:0|max:1000000000', + 'transactions.*.amount' => ['nullable', new IsValidPositiveAmount()], + 'transactions.*.foreign_amount' => ['nullable', new IsValidPositiveAmount()], // description 'transactions.*.description' => 'nullable|between:1,1000', diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php index e5c7056abc..2c086c4057 100644 --- a/app/Http/Controllers/Controller.php +++ b/app/Http/Controllers/Controller.php @@ -28,9 +28,7 @@ use FireflyIII\Support\Http\Controllers\UserNavigation; use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Illuminate\Foundation\Bus\DispatchesJobs; use Illuminate\Foundation\Validation\ValidatesRequests; -use Illuminate\Http\UploadedFile; use Illuminate\Routing\Controller as BaseController; -use Illuminate\Support\Facades\Log; /** * Class Controller. diff --git a/app/Http/Requests/AccountFormRequest.php b/app/Http/Requests/AccountFormRequest.php index 7095db6a26..7fb0f3755e 100644 --- a/app/Http/Requests/AccountFormRequest.php +++ b/app/Http/Requests/AccountFormRequest.php @@ -26,6 +26,7 @@ namespace FireflyIII\Http\Requests; use FireflyIII\Enums\UserRoleEnum; use FireflyIII\Models\Account; use FireflyIII\Models\Location; +use FireflyIII\Rules\IsValidAmount; use FireflyIII\Rules\UniqueIban; use FireflyIII\Support\Request\AppendsLocationData; use FireflyIII\Support\Request\ChecksLogin; @@ -101,11 +102,11 @@ class AccountFormRequest extends FormRequest $ccPaymentTypes = implode(',', array_keys(config('firefly.ccTypes'))); $rules = [ 'name' => 'required|max:1024|min:1|uniqueAccountForUser', - 'opening_balance' => 'numeric|nullable|max:1000000000|min:-1000000000', + 'opening_balance' => ['nullable', new IsValidAmount()], 'opening_balance_date' => 'date|required_with:opening_balance|nullable', 'iban' => ['iban', 'nullable', new UniqueIban(null, $this->convertString('objectType'))], 'BIC' => 'bic|nullable', - 'virtual_balance' => 'numeric|nullable|max:1000000000|min:-1000000000', + 'virtual_balance' => ['nullable', new IsValidAmount()], 'currency_id' => 'exists:transaction_currencies,id', 'account_number' => 'between:1,255|uniqueAccountNumberForUser|nullable', 'account_role' => 'in:'.$accountRoles, diff --git a/app/Http/Requests/BillStoreRequest.php b/app/Http/Requests/BillStoreRequest.php index 9f46401736..c5fa73bf98 100644 --- a/app/Http/Requests/BillStoreRequest.php +++ b/app/Http/Requests/BillStoreRequest.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace FireflyIII\Http\Requests; +use FireflyIII\Rules\IsValidPositiveAmount; use FireflyIII\Support\Request\ChecksLogin; use FireflyIII\Support\Request\ConvertsDataTypes; use Illuminate\Foundation\Http\FormRequest; @@ -64,8 +65,8 @@ class BillStoreRequest extends FormRequest { return [ 'name' => 'required|between:1,255|uniqueObjectForUser:bills,name', - 'amount_min' => 'required|numeric|gt:0|max:1000000000', - 'amount_max' => 'required|numeric|gt:0|max:1000000000', + 'amount_min' => ['required', new IsValidPositiveAmount()], + 'amount_max' => ['required', new IsValidPositiveAmount()], 'transaction_currency_id' => 'required|exists:transaction_currencies,id', 'date' => 'required|date', 'notes' => 'between:1,65536|nullable', diff --git a/app/Http/Requests/BillUpdateRequest.php b/app/Http/Requests/BillUpdateRequest.php index c8189282ed..485cf0cc47 100644 --- a/app/Http/Requests/BillUpdateRequest.php +++ b/app/Http/Requests/BillUpdateRequest.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace FireflyIII\Http\Requests; use FireflyIII\Models\Bill; +use FireflyIII\Rules\IsValidPositiveAmount; use FireflyIII\Support\Request\ChecksLogin; use FireflyIII\Support\Request\ConvertsDataTypes; use Illuminate\Foundation\Http\FormRequest; @@ -68,8 +69,8 @@ class BillUpdateRequest extends FormRequest return [ 'name' => sprintf('required|between:1,255|uniqueObjectForUser:bills,name,%d', $bill->id), - 'amount_min' => 'required|numeric|gt:0|max:1000000000', - 'amount_max' => 'required|numeric|gt:0|max:1000000000', + 'amount_min' => ['required', new IsValidPositiveAmount()], + 'amount_max' => ['required', new IsValidPositiveAmount()], 'transaction_currency_id' => 'required|exists:transaction_currencies,id', 'date' => 'required|date', 'bill_end_date' => 'nullable|date', diff --git a/app/Http/Requests/BudgetFormStoreRequest.php b/app/Http/Requests/BudgetFormStoreRequest.php index c50aeeaaf8..5200ff8544 100644 --- a/app/Http/Requests/BudgetFormStoreRequest.php +++ b/app/Http/Requests/BudgetFormStoreRequest.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace FireflyIII\Http\Requests; +use FireflyIII\Rules\IsValidPositiveAmount; use FireflyIII\Support\Request\ChecksLogin; use FireflyIII\Support\Request\ConvertsDataTypes; use FireflyIII\Validation\AutoBudget\ValidatesAutoBudgetRequest; @@ -64,7 +65,7 @@ class BudgetFormStoreRequest extends FormRequest 'active' => 'numeric|between:0,1', 'auto_budget_type' => 'numeric|integer|gte:0|lte:3', 'auto_budget_currency_id' => 'exists:transaction_currencies,id', - 'auto_budget_amount' => 'min:0|max:1000000000|required_if:auto_budget_type,1|required_if:auto_budget_type,2', + 'auto_budget_amount' => ['required_if:auto_budget_type,1', 'required_if:auto_budget_type,2', new IsValidPositiveAmount()], 'auto_budget_period' => 'in:daily,weekly,monthly,quarterly,half_year,yearly', 'notes' => 'between:1,65536|nullable', ]; diff --git a/app/Http/Requests/BudgetFormUpdateRequest.php b/app/Http/Requests/BudgetFormUpdateRequest.php index 3c25e55306..486f614fe4 100644 --- a/app/Http/Requests/BudgetFormUpdateRequest.php +++ b/app/Http/Requests/BudgetFormUpdateRequest.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace FireflyIII\Http\Requests; use FireflyIII\Models\Budget; +use FireflyIII\Rules\IsValidPositiveAmount; use FireflyIII\Support\Request\ChecksLogin; use FireflyIII\Support\Request\ConvertsDataTypes; use FireflyIII\Validation\AutoBudget\ValidatesAutoBudgetRequest; @@ -73,7 +74,7 @@ class BudgetFormUpdateRequest extends FormRequest 'active' => 'numeric|between:0,1', 'auto_budget_type' => 'numeric|integer|gte:0|lte:31', 'auto_budget_currency_id' => 'exists:transaction_currencies,id', - 'auto_budget_amount' => 'min:0|max:1000000000|required_if:auto_budget_type,1|required_if:auto_budget_type,2|numeric', + 'auto_budget_amount' => ['required_if:auto_budget_type,1', 'required_if:auto_budget_type,2|numeric', new IsValidPositiveAmount()], 'auto_budget_period' => 'in:daily,weekly,monthly,quarterly,half_year,yearly', 'notes' => 'between:1,65536|nullable', ]; diff --git a/app/Http/Requests/BudgetIncomeRequest.php b/app/Http/Requests/BudgetIncomeRequest.php index a89b818c3f..06575c0e19 100644 --- a/app/Http/Requests/BudgetIncomeRequest.php +++ b/app/Http/Requests/BudgetIncomeRequest.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace FireflyIII\Http\Requests; +use FireflyIII\Rules\IsValidPositiveAmount; use FireflyIII\Support\Request\ChecksLogin; use Illuminate\Foundation\Http\FormRequest; @@ -40,7 +41,7 @@ class BudgetIncomeRequest extends FormRequest { // fixed return [ - 'amount' => 'numeric|required|min:0|max:1000000000', + 'amount' => ['required', new IsValidPositiveAmount()], 'start' => 'required|date|before:end', 'end' => 'required|date|after:start', ]; diff --git a/app/Http/Requests/NewUserFormRequest.php b/app/Http/Requests/NewUserFormRequest.php index 2d4c3396b8..9955455972 100644 --- a/app/Http/Requests/NewUserFormRequest.php +++ b/app/Http/Requests/NewUserFormRequest.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace FireflyIII\Http\Requests; +use FireflyIII\Rules\IsValidAmount; use FireflyIII\Support\Request\ChecksLogin; use FireflyIII\Support\Request\ConvertsDataTypes; use Illuminate\Foundation\Http\FormRequest; @@ -43,9 +44,9 @@ class NewUserFormRequest extends FormRequest // fixed return [ 'bank_name' => 'required|between:1,200', - 'bank_balance' => 'required|numeric|max:1000000000|min:-1000000000', - 'savings_balance' => 'numeric|max:1000000000|min:-1000000000', - 'credit_card_limit' => 'numeric|max:1000000000|min:-1000000000', + 'bank_balance' => ['required', new IsValidAmount()], + 'savings_balance' => ['nullable', new IsValidAmount()], + 'credit_card_limit' => ['nullable', new IsValidAmount()], 'amount_currency_id_bank_balance' => 'exists:transaction_currencies,id', 'amount_currency_id_savings_balance' => 'exists:transaction_currencies,id', 'amount_currency_id_credit_card_limit' => 'exists:transaction_currencies,id', diff --git a/app/Http/Requests/PiggyBankStoreRequest.php b/app/Http/Requests/PiggyBankStoreRequest.php index 03be27f855..0892ae75bc 100644 --- a/app/Http/Requests/PiggyBankStoreRequest.php +++ b/app/Http/Requests/PiggyBankStoreRequest.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace FireflyIII\Http\Requests; +use FireflyIII\Rules\IsValidPositiveAmount; use FireflyIII\Support\Request\ChecksLogin; use FireflyIII\Support\Request\ConvertsDataTypes; use Illuminate\Foundation\Http\FormRequest; @@ -59,7 +60,7 @@ class PiggyBankStoreRequest extends FormRequest return [ 'name' => 'required|between:1,255|uniquePiggyBankForUser', 'account_id' => 'required|belongsToUser:accounts', - 'targetamount' => 'nullable|numeric|max:1000000000|min:-1000000000', + 'targetamount' => ['nullable', new IsValidPositiveAmount()], 'startdate' => 'date', 'targetdate' => 'date|nullable', 'order' => 'integer|min:1', diff --git a/app/Http/Requests/PiggyBankUpdateRequest.php b/app/Http/Requests/PiggyBankUpdateRequest.php index a67170dcc5..6b61cf084a 100644 --- a/app/Http/Requests/PiggyBankUpdateRequest.php +++ b/app/Http/Requests/PiggyBankUpdateRequest.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace FireflyIII\Http\Requests; use FireflyIII\Models\PiggyBank; +use FireflyIII\Rules\IsValidPositiveAmount; use FireflyIII\Support\Request\ChecksLogin; use FireflyIII\Support\Request\ConvertsDataTypes; use Illuminate\Foundation\Http\FormRequest; @@ -63,7 +64,7 @@ class PiggyBankUpdateRequest extends FormRequest return [ 'name' => sprintf('required|between:1,255|uniquePiggyBankForUser:%d', $piggy->id), 'account_id' => 'required|belongsToUser:accounts', - 'targetamount' => 'nullable|numeric|max:1000000000|min:-1000000000', + 'targetamount' => ['nullable', new IsValidPositiveAmount()], 'startdate' => 'date', 'targetdate' => 'date|nullable', 'order' => 'integer|max:65536|min:1', diff --git a/app/Http/Requests/ReconciliationStoreRequest.php b/app/Http/Requests/ReconciliationStoreRequest.php index f02bdb365a..4a73ca8ee8 100644 --- a/app/Http/Requests/ReconciliationStoreRequest.php +++ b/app/Http/Requests/ReconciliationStoreRequest.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace FireflyIII\Http\Requests; +use FireflyIII\Rules\IsValidAmount; use FireflyIII\Rules\ValidJournals; use FireflyIII\Support\Request\ChecksLogin; use FireflyIII\Support\Request\ConvertsDataTypes; @@ -67,9 +68,9 @@ class ReconciliationStoreRequest extends FormRequest return [ 'start' => 'required|date', 'end' => 'required|date', - 'startBalance' => 'numeric|max:1000000000|min:-1000000000', - 'endBalance' => 'numeric|max:1000000000|min:-1000000000', - 'difference' => 'required|numeric|max:1000000000|min:-1000000000', + 'startBalance' => ['nullable', new IsValidAmount()], + 'endBalance' => ['nullable', new IsValidAmount()], + 'difference' => ['required', new IsValidAmount()], 'journals' => [new ValidJournals()], 'reconcile' => 'required|in:create,nothing', ]; diff --git a/app/Http/Requests/RecurrenceFormRequest.php b/app/Http/Requests/RecurrenceFormRequest.php index c6921aba68..fb4187e512 100644 --- a/app/Http/Requests/RecurrenceFormRequest.php +++ b/app/Http/Requests/RecurrenceFormRequest.php @@ -27,6 +27,7 @@ use FireflyIII\Exceptions\FireflyException; use FireflyIII\Factory\CategoryFactory; use FireflyIII\Models\Recurrence; use FireflyIII\Models\TransactionType; +use FireflyIII\Rules\IsValidPositiveAmount; use FireflyIII\Rules\ValidRecurrenceRepetitionType; use FireflyIII\Rules\ValidRecurrenceRepetitionValue; use FireflyIII\Support\Request\ChecksLogin; @@ -171,7 +172,7 @@ class RecurrenceFormRequest extends FormRequest 'transaction_description' => 'required|between:1,255', 'transaction_type' => 'required|in:withdrawal,deposit,transfer', 'transaction_currency_id' => 'required|exists:transaction_currencies,id', - 'amount' => 'numeric|required|gt:0|max:1000000000', + 'amount' => ['required', new IsValidPositiveAmount()], // mandatory account info: 'source_id' => 'numeric|belongsToUser:accounts,id|nullable', 'source_name' => 'between:1,255|nullable', @@ -179,7 +180,7 @@ class RecurrenceFormRequest extends FormRequest 'destination_name' => 'between:1,255|nullable', // foreign amount data: - 'foreign_amount' => 'nullable|gt:0|max:1000000000', + 'foreign_amount' => ['nullable', new IsValidPositiveAmount()], // optional fields: 'budget_id' => 'mustExist:budgets,id|belongsToUser:budgets,id|nullable', diff --git a/app/Rules/IsValidAmount.php b/app/Rules/IsValidAmount.php new file mode 100644 index 0000000000..6210fc8b13 --- /dev/null +++ b/app/Rules/IsValidAmount.php @@ -0,0 +1,58 @@ +emptyString($value)) { + $fail('validation.filled')->translate(); + Log::debug(sprintf('IsValidAmount: "%s" cannot be empty.', $value)); + return; + } + + // must be a number: + if(!$this->isValidNumber($value)) { + $fail('validation.numeric')->translate(); + Log::debug(sprintf('IsValidAmount: "%s" is not a number.', $value)); + return; + } + + // must not be scientific notation: + if($this->scientificNumber($value)) { + $fail('validation.scientific_notation')->translate(); + Log::debug(sprintf('IsValidAmount: "%s" cannot be in the scientific notation.', $value)); + return; + } + + // must be more than minus a lots: + if($this->lessThanLots($value)) { + $amount = bcmul('-1', self::BIG_AMOUNT); + $fail('validation.gte.numeric')->translate(['value' => $amount]); + Log::debug(sprintf('IsValidAmount: "%s" must be more than %s.', $value, $amount)); + return; + } + + // must be less than 100 million and 1709: + if($this->moreThanLots($value)) { + Log::debug(sprintf('IsValidPositiveAmount: "%s" must be more than %s.', $value, self::BIG_AMOUNT)); + $fail('validation.lte.numeric')->translate(['value' => self::BIG_AMOUNT]); + } + Log::debug(sprintf('IsValidAmount: "%s" is a valid positive amount.', $value)); + } +} diff --git a/app/Rules/IsValidPositiveAmount.php b/app/Rules/IsValidPositiveAmount.php new file mode 100644 index 0000000000..f6e4020ed2 --- /dev/null +++ b/app/Rules/IsValidPositiveAmount.php @@ -0,0 +1,54 @@ +emptyString($value)) { + $fail('validation.filled')->translate(); + Log::debug(sprintf('IsValidPositiveAmount: "%s" cannot be empty.', $value)); + + return; + } + + // must be a number: + if(!$this->isValidNumber($value)) { + $fail('validation.numeric')->translate(); + Log::debug(sprintf('IsValidPositiveAmount: "%s" is not a number.', $value)); + return; + } + // must not be scientific notation: + if($this->scientificNumber($value)) { + $fail('validation.scientific_notation')->translate(); + Log::debug(sprintf('IsValidPositiveAmount: "%s" cannot be in the scientific notation.', $value)); + return; + } + // must be more than zero: + if($this->lessOrEqualToZero($value)) { + $fail('validation.more_than_zero')->translate(); + Log::debug(sprintf('IsValidPositiveAmount: "%s" must be more than zero.', $value)); + return; + } + // must be less than 100 million and 1709: + if($this->moreThanLots($value)) { + Log::debug(sprintf('IsValidPositiveAmount: "%s" must be less than %s.', $value, self::BIG_AMOUNT)); + $fail('validation.lte.numeric')->translate(['value' => self::BIG_AMOUNT]); + } + Log::debug(sprintf('IsValidPositiveAmount: "%s" is a valid positive amount.', $value)); + } +} diff --git a/app/Support/Validation/ValidatesAmountsTrait.php b/app/Support/Validation/ValidatesAmountsTrait.php new file mode 100644 index 0000000000..29f8d337d1 --- /dev/null +++ b/app/Support/Validation/ValidatesAmountsTrait.php @@ -0,0 +1,61 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Support\Validation; + +trait ValidatesAmountsTrait +{ + protected const string BIG_AMOUNT = '100001709'; + + final protected function emptyString(string $value): bool + { + return '' === $value; + } + + final protected function isValidNumber(string $value): bool + { + return is_numeric($value); + } + + final protected function scientificNumber(string $value): bool + { + return str_contains(strtoupper($value), 'E'); + } + + final protected function lessOrEqualToZero(string $value): bool + { + return -1 === bccomp($value, '0') || 0 === bccomp($value, '0'); + } + + final protected function moreThanLots(string $value): bool + { + return 1 === bccomp($value, self::BIG_AMOUNT) || 0 === bccomp($value, self::BIG_AMOUNT); + } + + final protected function lessThanLots(string $value): bool + { + $amount = bcmul('-1', self::BIG_AMOUNT); + + return -1 === bccomp($value, $amount) || 0 === bccomp($value, $amount); + } +} diff --git a/app/Validation/AutoBudget/ValidatesAutoBudgetRequest.php b/app/Validation/AutoBudget/ValidatesAutoBudgetRequest.php index 4c159d9f93..7076524c90 100644 --- a/app/Validation/AutoBudget/ValidatesAutoBudgetRequest.php +++ b/app/Validation/AutoBudget/ValidatesAutoBudgetRequest.php @@ -37,6 +37,8 @@ trait ValidatesAutoBudgetRequest { $data = $validator->getData(); $type = $data['auto_budget_type'] ?? ''; + + /** @var null|float|int|string $amount */ $amount = array_key_exists('auto_budget_amount', $data) ? $data['auto_budget_amount'] : null; $period = array_key_exists('auto_budget_period', $data) ? $data['auto_budget_period'] : null; $currencyId = array_key_exists('auto_budget_currency_id', $data) ? (int) $data['auto_budget_currency_id'] : null; @@ -47,12 +49,13 @@ trait ValidatesAutoBudgetRequest if ('' === $type || 0 === $type) { return; } + // TODO lots of duplicates with number validator. // TODO should be present at more places, stop scientific notification - if (str_contains(strtoupper($amount), 'E')) { + if (str_contains(strtoupper((string)$amount), 'E')) { $amount = ''; } // basic float check: - if (!is_numeric($amount) || '' === $amount) { + if (!is_numeric($amount) || '' === (string) $amount) { $validator->errors()->add('auto_budget_amount', (string) trans('validation.amount_required_for_auto_budget')); return; @@ -70,8 +73,6 @@ trait ValidatesAutoBudgetRequest // too big amount if ((int) $amount > 268435456) { $validator->errors()->add('auto_budget_amount', (string) trans('validation.amount_required_for_auto_budget')); - - return; } } } diff --git a/resources/lang/en_US/validation.php b/resources/lang/en_US/validation.php index e2dfc845e0..70e9752b58 100644 --- a/resources/lang/en_US/validation.php +++ b/resources/lang/en_US/validation.php @@ -34,6 +34,7 @@ return [ 'invalid_query_currency' => 'Your query contains accounts that have different currency settings, which is not allowed.', 'iban' => 'This is not a valid IBAN.', 'zero_or_more' => 'The value cannot be negative.', + 'more_than_zero' => 'The value must be more than zero.', 'no_asset_account' => 'This is not an asset account.', 'date_or_time' => 'The value must be a valid date or time value (ISO 8601).', 'source_equals_destination' => 'The source account equals the destination account.', @@ -124,6 +125,7 @@ return [ 'min.array' => 'The :attribute must have at least :min items.', 'not_in' => 'The selected :attribute is invalid.', 'numeric' => 'The :attribute must be a number.', + 'scientific_notation' => 'The :attribute cannot use the scientific notation.', 'numeric_native' => 'The native amount must be a number.', 'numeric_destination' => 'The destination amount must be a number.', 'numeric_source' => 'The source amount must be a number.',