diff --git a/.ci/php-cs-fixer/composer.lock b/.ci/php-cs-fixer/composer.lock index bd60a4a9cb..753cec5164 100644 --- a/.ci/php-cs-fixer/composer.lock +++ b/.ci/php-cs-fixer/composer.lock @@ -407,23 +407,23 @@ }, { "name": "fidry/cpu-core-counter", - "version": "1.3.0", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/theofidry/cpu-core-counter.git", - "reference": "db9508f7b1474469d9d3c53b86f817e344732678" + "reference": "7cbeb03e286fa81b2bbe0e6bd6b8a27c71a3144d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/db9508f7b1474469d9d3c53b86f817e344732678", - "reference": "db9508f7b1474469d9d3c53b86f817e344732678", + "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/7cbeb03e286fa81b2bbe0e6bd6b8a27c71a3144d", + "reference": "7cbeb03e286fa81b2bbe0e6bd6b8a27c71a3144d", "shasum": "" }, "require": { "php": "^7.2 || ^8.0" }, "require-dev": { - "fidry/makefile": "^0.2.0", + "fidry/makefile": "^0.2.0 || ^1.1.2", "fidry/php-cs-fixer-config": "^1.1.2", "phpstan/extension-installer": "^1.2.0", "phpstan/phpstan": "^2.0", @@ -431,6 +431,7 @@ "phpstan/phpstan-phpunit": "^2.0", "phpstan/phpstan-strict-rules": "^2.0", "phpunit/phpunit": "^8.5.31 || ^9.5.26", + "symfony/polyfill-mbstring": "^1.33", "webmozarts/strict-phpunit": "^7.5" }, "type": "library", @@ -456,7 +457,7 @@ ], "support": { "issues": "https://github.com/theofidry/cpu-core-counter/issues", - "source": "https://github.com/theofidry/cpu-core-counter/tree/1.3.0" + "source": "https://github.com/theofidry/cpu-core-counter/tree/1.4.0" }, "funding": [ { @@ -464,7 +465,7 @@ "type": "github" } ], - "time": "2025-08-14T07:29:31+00:00" + "time": "2026-09-27T17:40:20+00:00" }, { "name": "friendsofphp/php-cs-fixer", diff --git a/app/Api/V1/Controllers/Insight/Income/TagController.php b/app/Api/V1/Controllers/Insight/Income/TagController.php index df99eef909..94be2ae461 100644 --- a/app/Api/V1/Controllers/Insight/Income/TagController.php +++ b/app/Api/V1/Controllers/Insight/Income/TagController.php @@ -158,7 +158,10 @@ final class TagController extends Controller 'currency_id' => (string) $foreignCurrencyId, 'currency_code' => $journal['foreign_currency_code'], ]; - $response[$foreignKey]['difference'] = bcadd((string) $response[$foreignKey]['difference'], Steam::positive($journal['foreign_amount'])); + $response[$foreignKey]['difference'] = bcadd( + (string) $response[$foreignKey]['difference'], + Steam::positive($journal['foreign_amount']) + ); $response[$foreignKey]['difference_float'] = (float) $response[$foreignKey]['difference']; } } diff --git a/app/Api/V1/Controllers/Insight/Transfer/TagController.php b/app/Api/V1/Controllers/Insight/Transfer/TagController.php index f92a7aa9f0..b7b85fd376 100644 --- a/app/Api/V1/Controllers/Insight/Transfer/TagController.php +++ b/app/Api/V1/Controllers/Insight/Transfer/TagController.php @@ -155,7 +155,10 @@ final class TagController extends Controller 'currency_id' => (string) $foreignCurrencyId, 'currency_code' => $journal['foreign_currency_code'], ]; - $response[$foreignKey]['difference'] = bcadd((string) $response[$foreignKey]['difference'], Steam::positive($journal['foreign_amount'])); + $response[$foreignKey]['difference'] = bcadd( + (string) $response[$foreignKey]['difference'], + Steam::positive($journal['foreign_amount']) + ); $response[$foreignKey]['difference_float'] = (float) $response[$foreignKey]['difference']; // intentional float } } diff --git a/app/Http/Controllers/Budget/BudgetLimitController.php b/app/Http/Controllers/Budget/BudgetLimitController.php index 2edb4f5531..d461374baa 100644 --- a/app/Http/Controllers/Budget/BudgetLimitController.php +++ b/app/Http/Controllers/Budget/BudgetLimitController.php @@ -198,7 +198,13 @@ final class BudgetLimitController extends Controller if ($request->expectsJson()) { $array = $limit->toArray(); // add some extra metadata: - $spentArr = $this->opsRepository->sumExpenses($limit->start_date, $limit->end_date, null, new Collection()->push($budget), $currency); + $spentArr = $this->opsRepository->sumExpenses( + $limit->start_date, + $limit->end_date, + null, + new Collection()->push($budget), + $currency + ); $array['spent'] = $spentArr[$currency->id]['sum'] ?? '0'; $array['left_formatted'] = Amount::formatAnything($limit->transactionCurrency, bcadd($array['spent'], (string) $array['amount'])); $array['amount_formatted'] = Amount::formatAnything($limit->transactionCurrency, $limit['amount']); diff --git a/app/Http/Controllers/Budget/IndexController.php b/app/Http/Controllers/Budget/IndexController.php index 65429e59c1..52c6f900e3 100644 --- a/app/Http/Controllers/Budget/IndexController.php +++ b/app/Http/Controllers/Budget/IndexController.php @@ -272,7 +272,10 @@ final class IndexController extends Controller if (array_key_exists($currency->id, $spentArr) && array_key_exists('sum', $spentArr[$currency->id])) { $array['spent'][$currency->id]['spent'] = $spentArr[$currency->id]['sum']; - $array['spent'][$currency->id]['spent_outside'] = Steam::negative(bcsub($spentInLimits[$currency->id], $spentArr[$currency->id]['sum'])); + $array['spent'][$currency->id]['spent_outside'] = Steam::negative(bcsub( + $spentInLimits[$currency->id], + $spentArr[$currency->id]['sum'] + )); $array['spent'][$currency->id]['currency_id'] = $currency->id; $array['spent'][$currency->id]['currency_symbol'] = $currency->symbol; $array['spent'][$currency->id]['currency_decimal_places'] = $currency->decimal_places; diff --git a/app/Http/Controllers/Chart/BudgetController.php b/app/Http/Controllers/Chart/BudgetController.php index ad724137dc..f4b32fe5c5 100644 --- a/app/Http/Controllers/Chart/BudgetController.php +++ b/app/Http/Controllers/Chart/BudgetController.php @@ -539,7 +539,13 @@ final class BudgetController extends Controller } // get spent amount in this period for this currency. - $sum = $this->opsRepository->sumExpenses($currentStart, $currentEnd, $accounts, new Collection()->push($budget), $currency); + $sum = $this->opsRepository->sumExpenses( + $currentStart, + $currentEnd, + $accounts, + new Collection()->push($budget), + $currency + ); $amount = Steam::positive($sum[$currency->id]['sum'] ?? '0'); $chartData[0]['entries'][$title] = Steam::bcround($amount, $currency->decimal_places); diff --git a/app/Jobs/CreateAutoBudgetLimits.php b/app/Jobs/CreateAutoBudgetLimits.php index 476da65ac3..affea656a0 100644 --- a/app/Jobs/CreateAutoBudgetLimits.php +++ b/app/Jobs/CreateAutoBudgetLimits.php @@ -132,7 +132,13 @@ class CreateAutoBudgetLimits implements ShouldQueue // if has one, calculate expenses and use that as a base. $repository = app(OperationsRepositoryInterface::class); $repository->setUser($autoBudget->budget->user); - $spent = $repository->sumExpenses($previousStart, $previousEnd, null, new Collection()->push($autoBudget->budget), $autoBudget->transactionCurrency); + $spent = $repository->sumExpenses( + $previousStart, + $previousEnd, + null, + new Collection()->push($autoBudget->budget), + $autoBudget->transactionCurrency + ); $currencyId = $autoBudget->transaction_currency_id; $spentAmount = $spent[$currencyId]['sum'] ?? '0'; Log::debug(sprintf('Spent in previous budget period (%s-%s) is %s', $previousStart->format('Y-m-d'), $previousEnd->format('Y-m-d'), $spentAmount)); @@ -222,7 +228,13 @@ class CreateAutoBudgetLimits implements ShouldQueue // if has one, calculate expenses and use that as a base. $repository = app(OperationsRepositoryInterface::class); $repository->setUser($autoBudget->budget->user); - $spent = $repository->sumExpenses($previousStart, $previousEnd, null, new Collection()->push($autoBudget->budget), $autoBudget->transactionCurrency); + $spent = $repository->sumExpenses( + $previousStart, + $previousEnd, + null, + new Collection()->push($autoBudget->budget), + $autoBudget->transactionCurrency + ); $currencyId = $autoBudget->transaction_currency_id; $spentAmount = $spent[$currencyId]['sum'] ?? '0'; Log::debug(sprintf('Spent in previous budget period (%s-%s) is %s', $previousStart->format('Y-m-d'), $previousEnd->format('Y-m-d'), $spentAmount)); diff --git a/app/Support/Http/Controllers/AugumentData.php b/app/Support/Http/Controllers/AugumentData.php index a3a940b1ba..a507156873 100644 --- a/app/Support/Http/Controllers/AugumentData.php +++ b/app/Support/Http/Controllers/AugumentData.php @@ -222,7 +222,14 @@ trait AugumentData $currentEnd->addMonth(); } // primary currency amount. - $expenses = $opsRepository->sumExpenses($currentStart, $currentEnd, null, $budgetCollection, $entry->transactionCurrency, $this->convertToPrimary); + $expenses = $opsRepository->sumExpenses( + $currentStart, + $currentEnd, + null, + $budgetCollection, + $entry->transactionCurrency, + $this->convertToPrimary + ); $spent = $expenses[$currency->id]['sum'] ?? '0'; $entry->pc_spent = $spent; diff --git a/app/Support/JsonApi/Enrichments/RecurringEnrichment.php b/app/Support/JsonApi/Enrichments/RecurringEnrichment.php index d0c09bf027..2428353cb0 100644 --- a/app/Support/JsonApi/Enrichments/RecurringEnrichment.php +++ b/app/Support/JsonApi/Enrichments/RecurringEnrichment.php @@ -354,7 +354,11 @@ class RecurringEnrichment implements EnrichmentInterface /** @var RecurrenceRepetition $repetition */ foreach ($set as $repetition) { - $recurrence = $this->collection->filter(static fn (Recurrence $item): bool => (int) $item->id === (int) $repetition->recurrence_id)->first(); + $recurrence = $this->collection->filter( + static fn (Recurrence $item): bool => (int) $item->id === (int) $repetition->recurrence_id + ) + ->first() + ; $fromDate = clone ($recurrence->latest_date ?? $recurrence->first_date); $recurrenceId = (int) $repetition->recurrence_id; $repId = (int) $repetition->id; diff --git a/bootstrap/app.php b/bootstrap/app.php index 9187403fc9..64be6caca3 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -65,7 +65,6 @@ use PragmaRX\Google2FALaravel\Middleware as MFAMiddleware; bcscale(12); - $app = Application::configure(basePath: dirname(__DIR__)) ->withRouting( web : __DIR__ . '/../routes/web.php', @@ -114,7 +113,7 @@ $app = Application::configure(basePath: dirname(__DIR__)) 'auth:api', Binder::class, CatchBlockedUsers::class, - ] + ] ); $middleware->appendToGroup('api_basic', [AcceptHeaders::class, Binder::class]); @@ -135,6 +134,10 @@ $app = Application::configure(basePath: dirname(__DIR__)) Range::class, InterestingMessage::class, ]); + $middleware->appendToGroup('2fa-check', [ + Authenticate::class, + MFAMiddleware::class, + ]); // This middleware is added to ensure that the user is not only logged in and // authenticated (with MFA and everything), but also admin. $middleware->appendToGroup('api-admin', [ @@ -143,7 +146,7 @@ $app = Application::configure(basePath: dirname(__DIR__)) $middleware->appendToGroup('admin', [ IsAdmin::class, Range::class, - InterestingMessage::class + InterestingMessage::class, ]); // if the user is not logged in, this group applies. diff --git a/changelog.md b/changelog.md index 02dbfe8b91..c21ab81e32 100644 --- a/changelog.md +++ b/changelog.md @@ -3,6 +3,12 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## v6.7.6 - 2026-09-28 + +### Fixed + +- [Issue 12908](https://github.com/firefly-iii/firefly-iii/issues/12908) (OAuth redirect breaks due to broken function call) reported by @OutOfSpoons + ## v6.7.5 - 2026-09-28 diff --git a/composer.lock b/composer.lock index cc1e0193c2..6995d5a086 100644 --- a/composer.lock +++ b/composer.lock @@ -3640,16 +3640,16 @@ }, { "name": "nesbot/carbon", - "version": "3.14.0", + "version": "3.14.1", "source": { "type": "git", "url": "https://github.com/CarbonPHP/carbon.git", - "reference": "0023eaa2c9110e47446dd512a263c69c40cd41f2" + "reference": "34e9109535165bf1d7ff17a610492372ae73a896" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/0023eaa2c9110e47446dd512a263c69c40cd41f2", - "reference": "0023eaa2c9110e47446dd512a263c69c40cd41f2", + "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/34e9109535165bf1d7ff17a610492372ae73a896", + "reference": "34e9109535165bf1d7ff17a610492372ae73a896", "shasum": "" }, "require": { @@ -3741,7 +3741,7 @@ "type": "tidelift" } ], - "time": "2026-09-12T20:45:19+00:00" + "time": "2026-09-27T12:07:26+00:00" }, { "name": "nette/schema", diff --git a/config/firefly.php b/config/firefly.php index 655559b97b..635d85e261 100644 --- a/config/firefly.php +++ b/config/firefly.php @@ -78,8 +78,8 @@ return [ 'running_balance_column' => (bool)env_default_when_empty(env('USE_RUNNING_BALANCE'), true), // this is only the default value, is not used. // see cer.php for exchange rates feature flag. ], -'version' => '6.7.5', -'build_time' => 1790506772, +'version' => '6.7.6', +'build_time' => 1790572120, 'api_version' => '2.1.0', // field is no longer used. 'db_version' => 28, // field is no longer used. diff --git a/config/passport.php b/config/passport.php index bf65b0a926..c3e9e53b74 100644 --- a/config/passport.php +++ b/config/passport.php @@ -58,7 +58,7 @@ return [ 'secret' => env('PASSPORT_PERSONAL_ACCESS_CLIENT_SECRET'), ], - 'middleware' => ['web', 'user-full-auth'], + 'middleware' => [], 'connection' => env('PASSPORT_CONNECTION'), ]; diff --git a/package-lock.json b/package-lock.json index 5b2fc97e05..e2420c6a99 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2972,9 +2972,9 @@ } }, "node_modules/prettier": { - "version": "3.9.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.8.tgz", - "integrity": "sha512-WRFq3Wn3WId7LLROfMLdH7xaFr2jR62wU8nLO6rQUOLOxNZUviyJQs1M0iIhLexSFy+L+w0ch66wtoO2jRjG0A==", + "version": "3.9.9", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.9.tgz", + "integrity": "sha512-Z/CJHIkdujO/OtN7nXUii0Rf3VT5SRuhjBA82Xvu2XhBUgX3nhP67T0LHceBdQLex7OOFGTox+Q5Yg8Jk2Qivg==", "dev": true, "license": "MIT", "bin": { @@ -3670,7 +3670,7 @@ "concurrently": "^10", "laravel-vite-plugin": "^3.1", "postcss": "^8.5.14", - "prettier": "3.9.8", + "prettier": "3.9.9", "sass": "^1", "tailwindcss": "^4.0.0", "vite": "^8.0.0", diff --git a/resources/assets/v3/package.json b/resources/assets/v3/package.json index 3b15318f91..bacbb34b8f 100644 --- a/resources/assets/v3/package.json +++ b/resources/assets/v3/package.json @@ -36,7 +36,7 @@ "concurrently": "^10", "laravel-vite-plugin": "^3.1", "postcss": "^8.5.14", - "prettier": "3.9.8", + "prettier": "3.9.9", "sass": "^1", "tailwindcss": "^4.0.0", "vite": "^8.0.0", diff --git a/routes/web.php b/routes/web.php index 537a6616ad..a72cf70175 100644 --- a/routes/web.php +++ b/routes/web.php @@ -30,6 +30,19 @@ if (!defined('DATEFORMAT')) { } // new Passport routes. +Route::group( + [ + 'as' => 'passport.', + 'prefix' => 'oauth', + 'middleware' => ['2fa-check'], + 'namespace' => 'Laravel\Passport\Http\Controllers', + ], + function (): void { + Route::get('/authorize', ['uses' => 'AuthorizationController@authorize', 'as' => 'authorizations.authorize']); + } +); + + Route::group( [ 'as' => 'passport.', @@ -39,8 +52,7 @@ Route::group( ], function (): void { // routes with no extra middleware - // Route::post('/token', ['uses' => '\Laravel\Passport\Http\Controllers\AccessTokenController@issueToken', 'as' => 'token', 'middleware' => 'throttle']); - // Route::get('/authorize', ['uses' => 'AuthorizationController@authorize', 'as' => 'authorizations.authorize', 'middleware' => 'user-full-auth']); + // Route::post('/token', ['uses' => '\Laravel\Passport\Http\Controllers\AccessTokenController@issueToken', 'as' => 'token', 'middleware' => 'throttle']); // personal access tokens: Route::post('/personal-access-tokens', ['uses' => 'FireflyIII\Http\Controllers\Profile\OAuthController@storePersonalAccessToken', 'as' => 'personal.tokens.store']);