From b962bc9227091e85a7df77478c2d0004774cb566 Mon Sep 17 00:00:00 2001 From: Fabio Ribeiro Date: Thu, 22 May 2025 10:48:34 +0200 Subject: [PATCH 1/8] fix: Create item with tax (#377) When the `tax-per-item` is enabled and also has a tax added, during the item creation, the price + tax returns an amount as float making the database fail. To fix this was necessary to round the result. --- resources/scripts/admin/views/items/Create.vue | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/resources/scripts/admin/views/items/Create.vue b/resources/scripts/admin/views/items/Create.vue index 1e97f727..6ed7badd 100644 --- a/resources/scripts/admin/views/items/Create.vue +++ b/resources/scripts/admin/views/items/Create.vue @@ -184,7 +184,7 @@ const taxes = computed({ return { ...tax, tax_type_id: tax.id, - tax_name: `${tax.name} (${tax.calculation_type === 'fixed' + tax_name: `${tax.name} (${tax.calculation_type === 'fixed' ? new Intl.NumberFormat(undefined, { style: 'currency', currency: companyStore.selectedCompanyCurrency.code @@ -209,7 +209,7 @@ const getTaxTypes = computed(() => { return { ...tax, tax_type_id: tax.id, - tax_name: `${tax.name} (${tax.calculation_type === 'fixed' + tax_name: `${tax.name} (${tax.calculation_type === 'fixed' ? new Intl.NumberFormat(undefined, { style: 'currency', currency: companyStore.selectedCompanyCurrency.code @@ -292,7 +292,7 @@ async function submitItem() { tax_type_id: tax.tax_type_id, calculation_type: tax.calculation_type, fixed_amount: tax.fixed_amount, - amount: tax.calculation_type === 'fixed' ? tax.fixed_amount : price.value * tax.percent, + amount: tax.calculation_type === 'fixed' ? tax.fixed_amount : Math.round(price.value * tax.percent), percent: tax.percent, name: tax.name, collective_tax: 0, From e832c7661a1d41c17ad00bec846aa09979d0aa82 Mon Sep 17 00:00:00 2001 From: Leo Date: Thu, 12 Jun 2025 06:48:01 +1000 Subject: [PATCH 2/8] Fix: Heroicons v1 leftovers (#374) Change the getOrderBy's button. Using Heroicons v2 Change the SortAscendingIcon to BarsArrowUpIcon Change the SortDescendingIcon to BarsArrowDownIcon --- resources/scripts/admin/views/invoices/View.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/scripts/admin/views/invoices/View.vue b/resources/scripts/admin/views/invoices/View.vue index 5e816c7a..111ae9ce 100644 --- a/resources/scripts/admin/views/invoices/View.vue +++ b/resources/scripts/admin/views/invoices/View.vue @@ -391,8 +391,8 @@ onSearched = debounce(onSearched, 500) - - + + From 73d4ac1eb194d74cecae3677658c19059b946c34 Mon Sep 17 00:00:00 2001 From: Fabio Ribeiro Date: Wed, 11 Jun 2025 22:56:56 +0200 Subject: [PATCH 3/8] fix: Payment confirmation error (#376) Error caused when using Payments module, when try Stripe redirects back to InvoiceShelf, and the module calls the InvoiceShelf `generatePayment`. Relates #369 --- app/Models/Payment.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Models/Payment.php b/app/Models/Payment.php index ac9506c6..763a880b 100644 --- a/app/Models/Payment.php +++ b/app/Models/Payment.php @@ -459,7 +459,7 @@ class Payment extends Model implements HasMedia ->setNextNumbers(); $data['payment_number'] = $serial->getNextNumber(); - $data['payment_date'] = Carbon::now()->format('y-m-d'); + $data['payment_date'] = Carbon::now(); $data['amount'] = $invoice->total; $data['invoice_id'] = $invoice->id; $data['payment_method_id'] = request()->payment_method_id; From bf0d98c69c1ce15fc3e2c7dcede34edaa9e87d90 Mon Sep 17 00:00:00 2001 From: Fabio Ribeiro Date: Wed, 11 Jun 2025 23:23:19 +0200 Subject: [PATCH 4/8] fix: Backup Job (#375) Since `laravel-backup` major version was updated 8 to 9, the backup ability was compromised, the main reason is the change on the method contract from `BackupFactory` that now the `createFromArray` no longer exists. --- app/Jobs/CreateBackupJob.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/Jobs/CreateBackupJob.php b/app/Jobs/CreateBackupJob.php index f21fba98..8504f7c1 100644 --- a/app/Jobs/CreateBackupJob.php +++ b/app/Jobs/CreateBackupJob.php @@ -8,6 +8,7 @@ use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; +use Spatie\Backup\Config\Config; use Spatie\Backup\Tasks\Backup\BackupJobFactory; class CreateBackupJob implements ShouldQueue @@ -41,7 +42,8 @@ class CreateBackupJob implements ShouldQueue config(['backup.backup.destination.disks' => [$prefix.$fileDisk->driver]]); - $backupJob = BackupJobFactory::createFromArray(config('backup')); + $config = Config::fromArray(config('backup')); + $backupJob = BackupJobFactory::createFromConfig($config); if (! defined('SIGINT')) { $backupJob->disableSignals(); } From 8e96d3e97284d99275bfa6f97fb1367a9cbd170b Mon Sep 17 00:00:00 2001 From: Loduis Madariaga Barrios Date: Thu, 28 Aug 2025 02:44:34 -0500 Subject: [PATCH 5/8] fix(csrf-token): add leading dot to session domain cookie. (#224) * fix(csrf-token): add leading dot to session domain cookie. * refactor: remove generate key, upgrade axios and keep session domain in null. * refactor: fix PSR-12 code styles for PHP 8.2 compatibility. --------- Co-authored-by: Darko Gjorgjijoski <5760249+gdarko@users.noreply.github.com> --- .env.example | 3 +- .../DatabaseConfigurationController.php | 5 +- app/Space/EnvironmentManager.php | 51 ++++++++++++++++--- composer.lock | 2 +- config/sanctum.php | 48 ----------------- package.json | 2 +- .../scripts/admin/stores/installation.js | 2 +- .../views/installation/Step4VerifyDomain.vue | 2 +- .../installation/database/MysqlDatabase.vue | 2 +- .../installation/database/PgsqlDatabase.vue | 2 +- .../installation/database/SqliteDatabase.vue | 2 +- resources/scripts/plugins/axios.js | 4 +- routes/web.php | 3 +- 13 files changed, 59 insertions(+), 69 deletions(-) delete mode 100644 config/sanctum.php diff --git a/.env.example b/.env.example index 699b6495..c78d9e93 100644 --- a/.env.example +++ b/.env.example @@ -4,7 +4,7 @@ APP_DEBUG=true APP_NAME="InvoiceShelf" APP_LOG_LEVEL=debug APP_TIMEZONE=UTC -APP_URL=http://invoiceshelf.test +APP_URL= APP_LOCALE=en APP_FALLBACK_LOCALE=en @@ -49,7 +49,6 @@ PUSHER_APP_ID= PUSHER_KEY= PUSHER_SECRET= -SANCTUM_STATEFUL_DOMAINS=invoiceshelf.test TRUSTED_PROXIES="*" CRON_JOB_AUTH_TOKEN="" diff --git a/app/Http/Controllers/V1/Installation/DatabaseConfigurationController.php b/app/Http/Controllers/V1/Installation/DatabaseConfigurationController.php index 5c640349..c66cab1c 100644 --- a/app/Http/Controllers/V1/Installation/DatabaseConfigurationController.php +++ b/app/Http/Controllers/V1/Installation/DatabaseConfigurationController.php @@ -29,7 +29,10 @@ class DatabaseConfigurationController extends Controller $results = $this->environmentManager->saveDatabaseVariables($request); if (array_key_exists('success', $results)) { - Artisan::call('key:generate --force'); + // Automatically regenerating the key is disabled to prevent complications in the wizard process. + // This can cause issues with the CSRF token, resulting in "Token Mismatch" or "Invalid CSRF Token" errors. + // It is recommended that the user manually generates the key before running the wizard to ensure application security and stability. + // Artisan::call('key:generate --force'); Artisan::call('optimize:clear'); Artisan::call('config:clear'); Artisan::call('cache:clear'); diff --git a/app/Space/EnvironmentManager.php b/app/Space/EnvironmentManager.php index 05d2cbb5..2e3aea14 100755 --- a/app/Space/EnvironmentManager.php +++ b/app/Space/EnvironmentManager.php @@ -104,14 +104,22 @@ class EnvironmentManager */ public function saveDatabaseVariables(DatabaseEnvironmentRequest $request) { + $appUrl = $request->get('app_url'); + if ($appUrl !== config('app.url')) { + config(['app.url' => $appUrl]); + } + [$sanctumDomain, $sessionDomain] = $this->getDomains( + $request->getHttpHost() + ); $dbEnv = [ - 'APP_URL' => $request->get('app_url'), + 'APP_URL' => $appUrl, 'APP_LOCALE' => $request->get('app_locale'), 'DB_CONNECTION' => $request->get('database_connection'), - 'SANCTUM_STATEFUL_DOMAINS' => $request->get('app_domain'), - 'SESSION_DOMAIN' => explode(':', $request->get('app_domain'))[0], + 'SESSION_DOMAIN' => $sessionDomain, ]; - + if ($sanctumDomain !== null) { + $dbEnv['SANCTUM_STATEFUL_DOMAINS'] = $sanctumDomain; + } if ($dbEnv['DB_CONNECTION'] != 'sqlite') { if ($request->has('database_username') && $request->has('database_password')) { $dbEnv['DB_HOST'] = $request->get('database_hostname'); @@ -462,10 +470,16 @@ class EnvironmentManager public function saveDomainVariables(DomainEnvironmentRequest $request) { try { - $this->updateEnv([ - 'SANCTUM_STATEFUL_DOMAINS' => $request->get('app_domain'), - 'SESSION_DOMAIN' => explode(':', $request->get('app_domain'))[0], - ]); + [$sanctumDomain, $sessionDomain] = $this->getDomains( + $request->get('app_domain') + ); + $domainEnv = [ + 'SESSION_DOMAIN' => $sessionDomain, + ]; + if ($sanctumDomain !== null) { + $domainEnv['SANCTUM_STATEFUL_DOMAINS'] = $sanctumDomain; + } + $this->updateEnv($domainEnv); } catch (Exception $e) { return [ 'error' => 'domain_verification_failed', @@ -505,4 +519,25 @@ class EnvironmentManager file_put_contents($this->envPath, trim($formatted)); } + + private function getDomains(string $requestDomain): array + { + $appUrl = config('app.url'); + + $port = parse_url($appUrl, PHP_URL_PORT); + $currentDomain = parse_url($appUrl, PHP_URL_HOST).( + $port ? ':'.$port : '' + ); + + $requestHost = parse_url($requestDomain, PHP_URL_HOST) ?: $requestDomain; + + $isSame = $currentDomain === $requestDomain; + + return [ + $isSame && env('SANCTUM_STATEFUL_DOMAINS', false) === false ? + null : $requestDomain, + $isSame && env('SESSION_DOMAIN', false) === null ? + null : $requestHost, + ]; + } } diff --git a/composer.lock b/composer.lock index 730429a3..752a47a8 100644 --- a/composer.lock +++ b/composer.lock @@ -12363,4 +12363,4 @@ }, "platform-dev": {}, "plugin-api-version": "2.6.0" -} +} \ No newline at end of file diff --git a/config/sanctum.php b/config/sanctum.php deleted file mode 100644 index 8c94e2a9..00000000 --- a/config/sanctum.php +++ /dev/null @@ -1,48 +0,0 @@ - explode(',', env('SANCTUM_STATEFUL_DOMAINS', 'localhost,127.0.0.1,127.0.0.1:8000,::1')), - - /* - |-------------------------------------------------------------------------- - | Expiration Minutes - |-------------------------------------------------------------------------- - | - | This value controls the number of minutes until an issued token will be - | considered expired. If this value is null, personal access tokens do - | not expire. This won't tweak the lifetime of first-party sessions. - | - */ - - 'expiration' => null, - - /* - |-------------------------------------------------------------------------- - | Sanctum Middleware - |-------------------------------------------------------------------------- - | - | When authenticating your first-party SPA with Sanctum you may need to - | customize some of the middleware Sanctum uses while processing the - | request. You may change the middleware listed below as required. - | - */ - - 'middleware' => [ - 'authenticate_session' => Laravel\Sanctum\Http\Middleware\AuthenticateSession::class, - 'encrypt_cookies' => Illuminate\Cookie\Middleware\EncryptCookies::class, - 'validate_csrf_token' => Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class, - ], - -]; diff --git a/package.json b/package.json index 3f10edc1..b4d8e108 100644 --- a/package.json +++ b/package.json @@ -60,4 +60,4 @@ "vue-router": "^4.5.0", "vuedraggable": "^4.1.0" } -} +} \ No newline at end of file diff --git a/resources/scripts/admin/stores/installation.js b/resources/scripts/admin/stores/installation.js index 4d937df7..8c63fac5 100644 --- a/resources/scripts/admin/stores/installation.js +++ b/resources/scripts/admin/stores/installation.js @@ -185,7 +185,7 @@ export const useInstallationStore = (useWindow = false) => { }) }, - checkAutheticated() { + checkAuthenticated() { return new Promise((resolve, reject) => { axios .get(`/api/v1/auth/check`) diff --git a/resources/scripts/admin/views/installation/Step4VerifyDomain.vue b/resources/scripts/admin/views/installation/Step4VerifyDomain.vue index ec48d085..e4eee4be 100644 --- a/resources/scripts/admin/views/installation/Step4VerifyDomain.vue +++ b/resources/scripts/admin/views/installation/Step4VerifyDomain.vue @@ -87,7 +87,7 @@ async function verifyDomain() { try { await installationStore.setInstallationDomain(formData) await installationStore.installationLogin() - let driverRes = await installationStore.checkAutheticated() + let driverRes = await installationStore.checkAuthenticated() if (driverRes.data) { emit('next', 4) diff --git a/resources/scripts/admin/views/installation/database/MysqlDatabase.vue b/resources/scripts/admin/views/installation/database/MysqlDatabase.vue index 60d309b8..a0b422f8 100644 --- a/resources/scripts/admin/views/installation/database/MysqlDatabase.vue +++ b/resources/scripts/admin/views/installation/database/MysqlDatabase.vue @@ -1,6 +1,6 @@