mirror of
https://github.com/InvoiceShelf/InvoiceShelf.git
synced 2026-04-14 16:54:04 +00:00
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>
This commit is contained in:
committed by
GitHub
parent
bf0d98c69c
commit
8e96d3e972
@@ -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=""
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
2
composer.lock
generated
2
composer.lock
generated
@@ -12363,4 +12363,4 @@
|
||||
},
|
||||
"platform-dev": {},
|
||||
"plugin-api-version": "2.6.0"
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Stateful Domains
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Requests from the following domains / hosts will receive stateful API
|
||||
| authentication cookies. Typically, these should include your local
|
||||
| and production domains which access your API via a frontend SPA.
|
||||
|
|
||||
*/
|
||||
|
||||
'stateful' => 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,
|
||||
],
|
||||
|
||||
];
|
||||
@@ -60,4 +60,4 @@
|
||||
"vue-router": "^4.5.0",
|
||||
"vuedraggable": "^4.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -185,7 +185,7 @@ export const useInstallationStore = (useWindow = false) => {
|
||||
})
|
||||
},
|
||||
|
||||
checkAutheticated() {
|
||||
checkAuthenticated() {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
.get(`/api/v1/auth/check`)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<form action="" @submit.prevent="next">
|
||||
<div class="grid grid-cols-1 gap-5 md:grid-cols-2 lg:mb-6 md:mb-6">
|
||||
<div class="grid grid-cols-1 gap-5 md:grid-cols-2 mb-6">
|
||||
<BaseInputGroup
|
||||
:label="$t('wizard.database.app_url')"
|
||||
:error="v$.app_url.$error && v$.app_url.$errors[0].$message"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<form action="" @submit.prevent="next">
|
||||
<div class="grid grid-cols-1 gap-5 md:grid-cols-2 lg:mb-6 md:mb-6">
|
||||
<div class="grid grid-cols-1 gap-5 md:grid-cols-2 mb-6">
|
||||
<BaseInputGroup
|
||||
:label="$t('wizard.database.app_url')"
|
||||
:content-loading="isFetchingInitialData"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<form action="" @submit.prevent="next">
|
||||
<div class="grid grid-cols-1 gap-5 md:grid-cols-2 lg:mb-6 md:mb-6">
|
||||
<div class="grid grid-cols-1 gap-5 md:grid-cols-2 mb-6">
|
||||
<BaseInputGroup
|
||||
:label="$t('wizard.database.app_url')"
|
||||
:content-loading="isFetchingInitialData"
|
||||
|
||||
4
resources/scripts/plugins/axios.js
vendored
4
resources/scripts/plugins/axios.js
vendored
@@ -20,11 +20,11 @@ axios.interceptors.request.use(function (config) {
|
||||
const authToken = Ls.get('auth.token')
|
||||
|
||||
if (authToken) {
|
||||
config.headers.common.Authorization = authToken
|
||||
config.headers.Authorization = authToken
|
||||
}
|
||||
|
||||
if (companyId) {
|
||||
config.headers.common['company'] = companyId
|
||||
config.headers.company = companyId
|
||||
}
|
||||
|
||||
return config
|
||||
|
||||
@@ -113,7 +113,8 @@ Route::prefix('/customer')->group(function () {
|
||||
|
||||
Route::get('/installation', function () {
|
||||
return view('app');
|
||||
})->name('install')->middleware('redirect-if-installed');
|
||||
})->name('install')
|
||||
->middleware(['redirect-if-installed']);
|
||||
|
||||
// Move other http requests to the Vue App
|
||||
// -------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user