Fix FLEXIAPI-410 Modernize the Middleware and application stack to fit with...

This commit is contained in:
Timothée Jaussoin 2025-11-12 14:50:07 +00:00
parent 98d9d76225
commit fe265a972d
20 changed files with 423 additions and 753 deletions

View file

@ -1,117 +0,0 @@
<?php
/*
Flexisip Account Manager is a set of tools to manage SIP accounts.
Copyright (C) 2020 Belledonne Communications SARL, All rights reserved.
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 <http://www.gnu.org/licenses/>.
*/
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
/**
* The application's global HTTP middleware stack.
*
* These middleware are run during every request to your application.
*
* @var array
*/
protected $middleware = [
\App\Http\Middleware\TrustProxies::class,
\App\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class
];
/**
* The application's route middleware groups.
*
* @var array
*/
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\Localization::class,
'space.check'
],
'api' => [
'throttle:600,1', // move to 600 instead of 60
'bindings',
'validate_json',
'localization',
'space.check'
],
];
/**
* The application's route middleware.
*
* These middleware may be assigned to groups or used individually.
*
* @var array
*/
protected $middlewareAliases = [
'auth.admin' => \App\Http\Middleware\AuthenticateAdmin::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'auth.check_blocked' => \App\Http\Middleware\CheckBlocked::class,
'auth.digest_or_key' => \App\Http\Middleware\AuthenticateDigestOrKey::class,
'auth.jwt' => \App\Http\Middleware\AuthenticateJWT::class,
'auth.super_admin' => \App\Http\Middleware\AuthenticateSuperAdmin::class,
'auth' => \App\Http\Middleware\Authenticate::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'cookie.encrypt' => \App\Http\Middleware\EncryptCookies::class,
'cookie' => \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
'feature.carddav_user_credentials' => \App\Http\Middleware\IsCardDavCredentialsEnabled::class,
'feature.intercom' => \App\Http\Middleware\IsIntercomFeatures::class,
'feature.phone_registration' => \App\Http\Middleware\IsPhoneRegistration::class,
'feature.public_registration' => \App\Http\Middleware\IsPublicRegistration::class,
'feature.web_panel_enabled' => \App\Http\Middleware\IsWebPanelEnabled::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'localization' => \App\Http\Middleware\Localization::class,
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'space.check' => \App\Http\Middleware\SpaceCheck::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'validate_json' => \App\Http\Middleware\ValidateJSON::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
];
/**
* The priority-sorted list of middleware.
*
* This forces non-global middleware to always be in the given order.
*
* @var array
*/
protected $middlewarePriority = [
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\Illuminate\Routing\Middleware\ThrottleRequests::class,
\Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\Illuminate\Auth\Middleware\Authorize::class,
];
}

View file

@ -99,8 +99,7 @@ class AuthenticateJWT
return $next($request);
}
if (
!empty(config('app.account_authentication_bearer'))
if (!empty(config('app.account_authentication_bearer'))
// Bypass the JWT auth if we have an API Key
&& !$request->header('x-api-key')
&& !$request->cookie('x-api-key')

View file

@ -1,17 +0,0 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode as Middleware;
class CheckForMaintenanceMode extends Middleware
{
/**
* The URIs that should be reachable while maintenance mode is enabled.
*
* @var array
*/
protected $except = [
//
];
}

View file

@ -1,17 +0,0 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Cookie\Middleware\EncryptCookies as Middleware;
class EncryptCookies extends Middleware
{
/**
* The names of the cookies that should not be encrypted.
*
* @var array
*/
protected $except = [
//
];
}

View file

@ -14,6 +14,6 @@ class IsCardDavCredentialsEnabled
return $next($request);
}
return abort(403, 'CardDav Credentials features disabled');
abort(403, 'CardDav Credentials features disabled');
}
}

View file

@ -31,6 +31,6 @@ class IsPublicRegistration
return $next($request);
}
return abort(404, 'Public registration disabled');
abort(404, 'Public registration disabled');
}
}

View file

@ -13,14 +13,14 @@ class SpaceCheck
public function handle(Request $request, Closure $next): Response
{
if (empty(config('app.root_host'))) {
return abort(503, 'APP_ROOT_HOST is not configured');
abort(503, 'APP_ROOT_HOST is not configured');
}
$space = Space::where('host', config('app.sip_domain') ?? request()->host())->first();
if ($space != null) {
if (!str_ends_with($space->host, config('app.root_host'))) {
return abort(503, 'The APP_ROOT_HOST configured does not match with the current root domain');
abort(503, 'The APP_ROOT_HOST configured does not match with the current root domain');
}
$request->merge(['space' => $space]);
@ -53,6 +53,6 @@ class SpaceCheck
return $next($request);
}
return abort(404, 'Host not configured');
abort(404, 'Host not configured');
}
}

View file

@ -1,18 +0,0 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\TrimStrings as Middleware;
class TrimStrings extends Middleware
{
/**
* The names of the attributes that should not be trimmed.
*
* @var array
*/
protected $except = [
'password',
'password_confirmation',
];
}

View file

@ -1,28 +0,0 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Http\Middleware\TrustProxies as Middleware;
use Illuminate\Http\Request;
class TrustProxies extends Middleware
{
/**
* The trusted proxies for this application.
*
* @var array|string
*/
protected $proxies;
/**
* The headers that should be used to detect proxies.
*
* @var int
*/
protected $headers =
Request::HEADER_X_FORWARDED_FOR |
Request::HEADER_X_FORWARDED_HOST |
Request::HEADER_X_FORWARDED_PORT |
Request::HEADER_X_FORWARDED_PROTO |
Request::HEADER_X_FORWARDED_AWS_ELB;
}

View file

@ -1,24 +0,0 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
class VerifyCsrfToken extends Middleware
{
/**
* Indicates whether the XSRF-TOKEN cookie should be set on the response.
*
* @var bool
*/
protected $addHttpCookie = true;
/**
* The URIs that should be excluded from CSRF verification.
*
* @var array
*/
protected $except = [
//
];
}

View file

@ -1,53 +1,18 @@
#!/usr/bin/env php
<?php
use Illuminate\Foundation\Application;
use Symfony\Component\Console\Input\ArgvInput;
define('LARAVEL_START', microtime(true));
/*
|--------------------------------------------------------------------------
| Register The Auto Loader
|--------------------------------------------------------------------------
|
| Composer provides a convenient, automatically generated class loader
| for our application. We just need to utilize it! We'll require it
| into the script here so that we do not have to worry about the
| loading of any our classes "manually". Feels great to relax.
|
*/
// Register the Composer autoloader...
require __DIR__.'/vendor/autoload.php';
// Bootstrap Laravel and handle the command...
/** @var Application $app */
$app = require_once __DIR__.'/bootstrap/app.php';
/*
|--------------------------------------------------------------------------
| Run The Artisan Application
|--------------------------------------------------------------------------
|
| When we run the console application, the current CLI command will be
| executed in this console and the response sent back to a terminal
| or another output device for the developers. Here goes nothing!
|
*/
$kernel = $app->make(Illuminate\Contracts\Console\Kernel::class);
$status = $kernel->handle(
$input = new Symfony\Component\Console\Input\ArgvInput,
new Symfony\Component\Console\Output\ConsoleOutput
);
/*
|--------------------------------------------------------------------------
| Shutdown The Application
|--------------------------------------------------------------------------
|
| Once Artisan has finished running, we will fire off the shutdown events
| so that any final work may be done by the application before we shut
| down the process. This is the last thing to happen to the request.
|
*/
$kernel->terminate($input, $status);
$status = $app->handleCommand(new ArgvInput);
exit($status);

View file

@ -1,55 +1,50 @@
<?php
/*
|--------------------------------------------------------------------------
| Create The Application
|--------------------------------------------------------------------------
|
| The first thing we will do is create a new Laravel application instance
| which serves as the "glue" for all the components of Laravel, and is
| the IoC container for the system binding all of the various parts.
|
*/
use App\Http\Middleware\Authenticate;
use App\Http\Middleware\AuthenticateAdmin;
use App\Http\Middleware\AuthenticateDigestOrKey;
use App\Http\Middleware\AuthenticateJWT;
use App\Http\Middleware\AuthenticateSuperAdmin;
use App\Http\Middleware\CheckBlocked;
use App\Http\Middleware\IsCardDavCredentialsEnabled;
use App\Http\Middleware\IsIntercomFeatures;
use App\Http\Middleware\IsPhoneRegistration;
use App\Http\Middleware\IsPublicRegistration;
use App\Http\Middleware\IsWebPanelEnabled;
use App\Http\Middleware\Localization;
use App\Http\Middleware\SpaceCheck;
use App\Http\Middleware\ValidateJSON;
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
$app = new Illuminate\Foundation\Application(
$_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
);
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__ . '/../routes/web.php',
commands: __DIR__ . '/../routes/console.php',
health: '/up',
)
->withMiddleware(function (Middleware $middleware) {
$middleware->append(SpaceCheck::class);
$middleware->append(Localization::class);
$middleware->api(append: [ValidateJSON::class]);
/*
|--------------------------------------------------------------------------
| Bind Important Interfaces
|--------------------------------------------------------------------------
|
| Next, we need to bind some important interfaces into the container so
| we will be able to resolve them when needed. The kernels serve the
| incoming requests to this application from both the web and CLI.
|
*/
$middleware->alias([
'auth.admin' => AuthenticateAdmin::class,
'auth.check_blocked' => CheckBlocked::class,
'auth.digest_or_key' => AuthenticateDigestOrKey::class,
'auth.jwt' => AuthenticateJWT::class,
'auth.super_admin' => AuthenticateSuperAdmin::class,
'auth' => Authenticate::class,
'feature.carddav_user_credentials' => IsCardDavCredentialsEnabled::class,
'feature.intercom' => IsIntercomFeatures::class,
'feature.phone_registration' => IsPhoneRegistration::class,
'feature.public_registration' => IsPublicRegistration::class,
'feature.web_panel_enabled' => IsWebPanelEnabled::class,
]);
})
->withExceptions(function (Exceptions $exceptions) {
//
})->create();
$app->singleton(
Illuminate\Contracts\Http\Kernel::class,
App\Http\Kernel::class
);
$app->singleton(
Illuminate\Contracts\Console\Kernel::class,
App\Console\Kernel::class
);
$app->singleton(
Illuminate\Contracts\Debug\ExceptionHandler::class,
App\Exceptions\Handler::class
);
/*
|--------------------------------------------------------------------------
| Return The Application
|--------------------------------------------------------------------------
|
| This script returns the application instance. The instance is given to
| the calling script so we can separate the building of the instances
| from the actual running of the application and sending responses.
|
*/
return $app;

553
flexiapi/composer.lock generated

File diff suppressed because it is too large Load diff

Binary file not shown.

View file

@ -97,10 +97,7 @@
<exclude-pattern>*/migrations/*</exclude-pattern>
<exclude-pattern>*/config/*</exclude-pattern>
<exclude-pattern>*/public/index.php</exclude-pattern>
<exclude-pattern>*/Middleware/*</exclude-pattern>
<exclude-pattern>*/Console/Kernel.php</exclude-pattern>
<exclude-pattern>*/Exceptions/Handler.php</exclude-pattern>
<exclude-pattern>*/Http/Kernel.php</exclude-pattern>
<exclude-pattern>*/Providers/*</exclude-pattern>
<arg name="colors"/>

View file

@ -1,60 +1,20 @@
<?php
/**
* Laravel - A PHP Framework For Web Artisans
*
* @package Laravel
* @author Taylor Otwell <taylor@laravel.com>
*/
use Illuminate\Foundation\Application;
use Illuminate\Http\Request;
define('LARAVEL_START', microtime(true));
/*
|--------------------------------------------------------------------------
| Register The Auto Loader
|--------------------------------------------------------------------------
|
| Composer provides a convenient, automatically generated class loader for
| our application. We just need to utilize it! We'll simply require it
| into the script here so that we don't have to worry about manual
| loading any of our classes later on. It feels great to relax.
|
*/
// Determine if the application is in maintenance mode...
if (file_exists($maintenance = __DIR__.'/../storage/framework/maintenance.php')) {
require $maintenance;
}
// Register the Composer autoloader...
require __DIR__.'/../vendor/autoload.php';
/*
|--------------------------------------------------------------------------
| Turn On The Lights
|--------------------------------------------------------------------------
|
| We need to illuminate PHP development, so let us turn on the lights.
| This bootstraps the framework and gets it ready for use, then it
| will load up this application so that we can run it and send
| the responses back to the browser and delight our users.
|
*/
// Bootstrap Laravel and handle the request...
/** @var Application $app */
$app = require_once __DIR__.'/../bootstrap/app.php';
/*
|--------------------------------------------------------------------------
| Run The Application
|--------------------------------------------------------------------------
|
| Once we have the application, we can handle the incoming request
| through the kernel, and send the associated response back to
| the client's browser allowing them to enjoy the creative
| and wonderful application we have prepared for them.
|
*/
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
$response = $kernel->handle(
$request = Illuminate\Http\Request::capture()
);
$response->send();
$kernel->terminate($request, $response);
$app->handleRequest(Request::capture());

View file

@ -17,80 +17,98 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
use App\Http\Controllers\Api\Account\AccountController;
use App\Http\Controllers\Api\Account\ApiKeyController;
use App\Http\Controllers\Api\Account\AuthTokenController;
use App\Http\Controllers\Api\Account\ContactController;
use App\Http\Controllers\Api\Account\CreationRequestToken;
use App\Http\Controllers\Api\Account\CreationTokenController;
use App\Http\Controllers\Api\Account\DeviceController;
use App\Http\Controllers\Api\Account\EmailController;
use App\Http\Controllers\Api\Account\PasswordController;
use App\Http\Controllers\Api\Account\PhoneController;
use App\Http\Controllers\Api\Account\PushNotificationController;
use App\Http\Controllers\Api\Account\RecoveryTokenController;
use App\Http\Controllers\Api\Account\VcardsStorageController;
use App\Http\Controllers\Api\Admin\Account\ActionController;
use App\Http\Controllers\Api\Admin\Account\CardDavCredentialsController;
use App\Http\Controllers\Api\Admin\Account\ContactController;
use App\Http\Controllers\Api\Admin\Account\ContactController as AdminContactController;
use App\Http\Controllers\Api\Admin\Account\CreationTokenController as AdminCreationTokenController;
use App\Http\Controllers\Api\Admin\Account\DictionaryController;
use App\Http\Controllers\Api\Admin\Account\TypeController;
use App\Http\Controllers\Api\Admin\AccountController as AdminAccountController;
use App\Http\Controllers\Api\Admin\ContactsListController;
use App\Http\Controllers\Api\Admin\ExternalAccountController;
use App\Http\Controllers\Api\Admin\MessageController;
use App\Http\Controllers\Api\Admin\Space\CardDavServerController;
use App\Http\Controllers\Api\Admin\Space\EmailServerController;
use App\Http\Controllers\Api\Admin\SpaceController;
use App\Http\Controllers\Api\Admin\VcardsStorageController as AdminVcardsStorageController;
use App\Http\Controllers\Api\ApiController;
use App\Http\Controllers\Api\PhoneCountryController;
use App\Http\Controllers\Api\PingController;
use App\Http\Controllers\Api\StatisticsCallController;
use App\Http\Controllers\Api\StatisticsMessageController;
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
use Illuminate\Http\Request;
Route::get('/', 'Api\ApiController@documentation')->name('api');
Route::get('/', [ApiController::class, 'documentation'])->name('api');
Route::middleware('auth:api')->get('/user', function (Request $request) {
return $request->user();
});
Route::get('ping', 'Api\PingController@ping');
Route::get('ping', [PingController::class, 'ping']);
Route::post('account_creation_request_tokens', 'Api\Account\CreationRequestToken@create');
Route::post('account_creation_tokens/send-by-push', 'Api\Account\CreationTokenController@sendByPush');
Route::post('account_creation_tokens/using-account-creation-request-token', 'Api\Account\CreationTokenController@usingAccountRequestToken');
Route::post('accounts/with-account-creation-token', 'Api\Account\AccountController@store');
Route::post('account_recovery_tokens/send-by-push', 'Api\Account\RecoveryTokenController@sendByPush');
Route::post('account_creation_request_tokens', [CreationRequestToken::class, 'create']);
Route::post('account_creation_tokens/send-by-push', [CreationTokenController::class, 'sendByPush']);
Route::post('account_creation_tokens/using-account-creation-request-token', [CreationTokenController::class, 'usingAccountRequestToken']);
Route::post('accounts/with-account-creation-token', [AccountController::class, 'store']);
Route::post('account_recovery_tokens/send-by-push', [RecoveryTokenController::class, 'sendByPush']);
Route::get('accounts/{sip}/info', 'Api\Account\AccountController@info');
Route::get('accounts/{sip}/info', [AccountController::class, 'info']);
Route::post('accounts/auth_token', 'Api\Account\AuthTokenController@store');
Route::post('accounts/auth_token', [AuthTokenController::class, 'store']);
Route::get('accounts/me/api_key/{auth_token}', 'Api\Account\ApiKeyController@generateFromToken')->middleware('cookie', 'cookie.encrypt');
Route::get('accounts/me/api_key/{auth_token}', [ApiKeyController::class, 'generateFromToken'])->middleware(AddQueuedCookiesToResponse::class);
Route::get('phone_countries', 'Api\PhoneCountryController@index');
Route::get('phone_countries', [PhoneCountryController::class, 'index']);
Route::group(['middleware' => ['auth.jwt', 'auth.digest_or_key', 'auth.check_blocked']], function () {
Route::get('accounts/auth_token/{auth_token}/attach', 'Api\Account\AuthTokenController@attach');
Route::post('account_creation_tokens/consume', 'Api\Account\CreationTokenController@consume');
Route::get('accounts/auth_token/{auth_token}/attach', [AuthTokenController::class, 'attach']);
Route::post('account_creation_tokens/consume', [CreationTokenController::class, 'consume']);
Route::post('push_notification', 'Api\Account\PushNotificationController@push');
Route::post('push_notification', [PushNotificationController::class, 'push']);
Route::prefix('accounts/me')->group(function () {
Route::get('api_key', 'Api\Account\ApiKeyController@generate')->middleware('cookie', 'cookie.encrypt');
Route::get('api_key', [ApiKeyController::class, 'generate'])->middleware(AddQueuedCookiesToResponse::class);
Route::get('services/turn', 'Api\Account\AccountController@turnService');
Route::get('services/turn', [AccountController::class, 'turnService']);
Route::get('/', 'Api\Account\AccountController@show');
Route::delete('/', 'Api\Account\AccountController@delete');
Route::get('provision', 'Api\Account\AccountController@provision');
Route::get('/', [AccountController::class, 'show']);
Route::delete('/', [AccountController::class, 'delete']);
Route::get('provision', [AccountController::class, 'provision']);
Route::post('phone/request', 'Api\Account\PhoneController@requestUpdate');
Route::post('phone', 'Api\Account\PhoneController@update');
Route::post('phone/request', [PhoneController::class, 'requestUpdate']);
Route::post('phone', [PhoneController::class, 'update']);
Route::get('devices', 'Api\Account\DeviceController@index');
Route::delete('devices/{uuid}', 'Api\Account\DeviceController@destroy');
Route::get('devices', [DeviceController::class, 'index']);
Route::delete('devices/{uuid}', [DeviceController::class, 'destroy']);
Route::post('email/request', 'Api\Account\EmailController@requestUpdate');
Route::post('email', 'Api\Account\EmailController@update');
Route::post('email/request', [EmailController::class, 'requestUpdate']);
Route::post('email', [EmailController::class, 'update']);
Route::post('password', 'Api\Account\PasswordController@update');
Route::post('password', [PasswordController::class, 'update']);
Route::get('contacts/{sip}', 'Api\Account\ContactController@show');
Route::get('contacts', 'Api\Account\ContactController@index');
Route::get('contacts/{sip}', [ContactController::class, 'show']);
Route::get('contacts', [ContactController::class, 'index']);
Route::apiResource('vcards-storage', VcardsStorageController::class);
});
Route::group(['middleware' => ['auth.admin']], function () {
if (!empty(config('app.linphone_daemon_unix_pipe'))) {
Route::post('messages', 'Api\Admin\MessageController@send');
Route::post('messages', [MessageController::class, 'send']);
}
// Super admin
@ -107,7 +125,7 @@ Route::group(['middleware' => ['auth.jwt', 'auth.digest_or_key', 'auth.check_blo
});
// Account creation token
Route::post('account_creation_tokens', 'Api\Admin\Account\CreationTokenController@create');
Route::post('account_creation_tokens', [AdminCreationTokenController::class, 'create']);
// Accounts
Route::prefix('accounts')->controller(AdminAccountController::class)->group(function () {
@ -127,8 +145,8 @@ Route::group(['middleware' => ['auth.jwt', 'auth.digest_or_key', 'auth.check_blo
Route::get('{sip}/search', 'search');
Route::get('{email}/search-by-email', 'searchByEmail');
Route::get('{account_id}/devices', 'Api\Admin\DeviceController@index');
Route::delete('{account_id}/devices/{uuid}', 'Api\Admin\DeviceController@destroy');
Route::get('{account_id}/devices', [DeviceController::class, 'index']);
Route::delete('{account_id}/devices/{uuid}', [DeviceController::class, 'destroy']);
Route::post('{account_id}/types/{type_id}', 'typeAdd');
Route::delete('{account_id}/types/{type_id}', 'typeRemove');
@ -138,7 +156,7 @@ Route::group(['middleware' => ['auth.jwt', 'auth.digest_or_key', 'auth.check_blo
});
// Account contacts
Route::prefix('accounts/{id}/contacts')->controller(ContactController::class)->group(function () {
Route::prefix('accounts/{id}/contacts')->controller(AdminContactController::class)->group(function () {
Route::get('/', 'index');
Route::get('{contact_id}', 'show');
Route::post('{contact_id}', 'add');

View file

@ -1,18 +1,4 @@
<?php
use Illuminate\Foundation\Inspiring;
/*
|--------------------------------------------------------------------------
| Console Routes
|--------------------------------------------------------------------------
|
| This file is where you may define all of your Closure based console
| commands. Each Closure is bound to a command instance allowing a
| simple approach to interacting with each command's IO methods.
|
*/
Artisan::command('inspire', function () {
$this->comment(Inspiring::quote());
})->describe('Display an inspiring quote');
use Illuminate\Support\Facades\Schedule;

View file

@ -17,8 +17,12 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
use App\Http\Controllers\AboutController;
use App\Http\Controllers\Account\AccountController;
use App\Http\Controllers\Account\ApiKeyController;
use App\Http\Controllers\Account\AuthenticateController;
use App\Http\Controllers\Account\AuthTokenController;
use App\Http\Controllers\Account\ContactVcardController;
use App\Http\Controllers\Account\CreationRequestTokenController;
use App\Http\Controllers\Account\DeviceController;
use App\Http\Controllers\Account\EmailController;
@ -26,6 +30,8 @@ use App\Http\Controllers\Account\PasswordController;
use App\Http\Controllers\Account\PhoneController;
use App\Http\Controllers\Account\ProvisioningController;
use App\Http\Controllers\Account\RecoveryController;
use App\Http\Controllers\Account\RegisterController;
use App\Http\Controllers\Account\VcardsStorageController;
use App\Http\Controllers\Admin\AccountController as AdminAccountController;
use App\Http\Controllers\Admin\Account\AccountTypeController;
use App\Http\Controllers\Admin\Account\ActionController;
@ -51,18 +57,18 @@ use App\Http\Controllers\Admin\StatisticsController;
use Illuminate\Support\Facades\Route;
Route::redirect('/', 'login')->name('account.home');
Route::get('about', 'AboutController@about')->name('about');
Route::get('about', [AboutController::class, 'about'])->name('about');
Route::middleware(['feature.web_panel_enabled'])->group(function () {
Route::get('wizard/{provisioning_token}', 'Account\ProvisioningController@wizard')->name('provisioning.wizard');
Route::get('wizard/{provisioning_token}', [ProvisioningController::class, 'wizard'])->name('provisioning.wizard');
Route::get('login', 'Account\AuthenticateController@login')->name('account.login');
Route::post('authenticate', 'Account\AuthenticateController@authenticate')->name('account.authenticate');
Route::get('authenticate/qrcode/{token?}', 'Account\AuthenticateController@loginAuthToken')->name('account.authenticate.auth_token');
Route::get('logout', 'Account\AuthenticateController@logout')->name('account.logout');
Route::get('login', [AuthenticateController::class, 'login'])->name('account.login');
Route::post('authenticate', [AuthenticateController::class, 'authenticate'])->name('account.authenticate');
Route::get('authenticate/qrcode/{token?}', [AuthenticateController::class, 'loginAuthToken'])->name('account.authenticate.auth_token');
Route::get('logout', [AuthenticateController::class, 'logout'])->name('account.logout');
Route::get('reset_password/{token}', 'Account\ResetPasswordEmailController@change')->name('account.reset_password_email.change');
Route::post('reset_password', 'Account\ResetPasswordEmailController@reset')->name('account.reset_password_email.reset');
Route::get('reset_password/{token}', [ResetPasswordEmailController::class, 'change'])->name('account.reset_password_email.change');
Route::post('reset_password', [ResetPasswordEmailController::class, 'reset'])->name('account.reset_password_email.reset');
Route::prefix('creation_token')->controller(CreationRequestTokenController::class)->group(function () {
Route::get('check/{token}', 'check')->name('account.creation_request_token.check');
@ -71,15 +77,15 @@ Route::middleware(['feature.web_panel_enabled'])->group(function () {
});
Route::group(['middleware' => ['auth.jwt', 'auth.digest_or_key']], function () {
Route::get('provisioning/me', 'Account\ProvisioningController@me')->name('provisioning.me');
Route::get('provisioning/me', [ProvisioningController::class, 'me'])->name('provisioning.me');
// vCard 4.0
Route::get('contacts/vcard/{sip}', 'Account\ContactVcardController@show')->name('account.contacts.vcard.show');
Route::get('contacts/vcard', 'Account\ContactVcardController@index')->name('account.contacts.vcard.index');
Route::get('contacts/vcard/{sip}', [ContactVcardController::class, 'show'])->name('account.contacts.vcard.show');
Route::get('contacts/vcard', [ContactVcardController::class, 'index'])->name('account.contacts.vcard.index');
// vCards Storage
Route::get('vcards-storage/{uuid}', 'Account\VcardsStorageController@show')->name('account.vcards-storage.show');
Route::get('vcards-storage/', 'Account\VcardsStorageController@index')->name('account.vcards-storage.index');
Route::get('vcards-storage/{uuid}', [VcardsStorageController::class, 'show'])->name('account.vcards-storage.show');
Route::get('vcards-storage/', [VcardsStorageController::class, 'index'])->name('account.vcards-storage.index');
});
Route::name('provisioning.')->prefix('provisioning')->controller(ProvisioningController::class)->group(function () {
@ -95,11 +101,11 @@ Route::middleware(['feature.web_panel_enabled'])->group(function () {
Route::redirect('register', 'register/email')->name('account.register');
Route::middleware(['feature.phone_registration'])->group(function () {
Route::get('register/phone', 'Account\RegisterController@registerPhone')->name('account.register.phone');
Route::get('register/phone', [RegisterController::class, 'registerPhone'])->name('account.register.phone');
});
Route::get('register/email', 'Account\RegisterController@registerEmail')->name('account.register.email');
Route::post('accounts', 'Account\AccountController@store')->name('account.store');
Route::get('register/email', [RegisterController::class, 'registerEmail'])->name('account.register.email');
Route::post('accounts', [AccountController::class, 'store'])->name('account.store');
});
Route::prefix('recovery')->controller(RecoveryController::class)->group(function () {
@ -110,7 +116,7 @@ Route::middleware(['feature.web_panel_enabled'])->group(function () {
});
Route::name('account.')->middleware(['auth', 'auth.check_blocked'])->group(function () {
Route::get('blocked', 'Account\AccountController@blocked')->name('blocked');
Route::get('blocked', [AccountController::class, 'blocked'])->name('blocked');
Route::prefix('email')->controller(EmailController::class)->group(function () {
Route::get('change', 'change')->name('email.change');
@ -151,19 +157,19 @@ Route::middleware(['feature.web_panel_enabled'])->group(function () {
Route::post('/', 'update')->name('update');
});
Route::post('auth_tokens', 'Account\AuthTokenController@create')->name('auth_tokens.create');
Route::get('auth_tokens/auth/external/{token}', 'Account\AuthTokenController@authExternal')->name('auth_tokens.auth.external');
Route::post('auth_tokens', [AuthTokenController::class, 'create'])->name('auth_tokens.create');
Route::get('auth_tokens/auth/external/{token}', [AuthTokenController::class, 'authExternal'])->name('auth_tokens.auth.external');
});
Route::get('auth_tokens/qrcode/{token}', 'Account\AuthTokenController@qrcode')->name('auth_tokens.qrcode');
Route::get('auth_tokens/auth/{token}', 'Account\AuthTokenController@auth')->name('auth_tokens.auth');
Route::get('auth_tokens/qrcode/{token}', [AuthTokenController::class, 'qrcode'])->name('auth_tokens.qrcode');
Route::get('auth_tokens/auth/{token}', [AuthTokenController::class, 'auth'])->name('auth_tokens.auth');
Route::name('admin.')->prefix('admin')->middleware(['auth.admin', 'auth.check_blocked'])->group(function () {
Route::name('spaces.')->prefix('spaces')->group(function () {
Route::get('me', 'Admin\SpaceController@me')->name('me');
Route::get('{space}/configuration', 'Admin\SpaceController@configuration')->name('configuration');
Route::put('{space}/configuration', 'Admin\SpaceController@configurationUpdate')->name('configuration.update');
Route::get('{space}/integration', 'Admin\SpaceController@integration')->name('integration');
Route::get('me', [SpaceController::class, 'me'])->name('me');
Route::get('{space}/configuration', [SpaceController::class, 'configuration'])->name('configuration');
Route::put('{space}/configuration', [SpaceController::class, 'configurationUpdate'])->name('configuration.update');
Route::get('{space}/integration', [SpaceController::class, 'integration'])->name('integration');
Route::name('email.')->prefix('{space}/email')->controller(EmailServerController::class)->group(function () {
Route::get('/', 'show')->name('show');
@ -172,7 +178,7 @@ Route::middleware(['feature.web_panel_enabled'])->group(function () {
Route::delete('/', 'destroy')->name('destroy');
});
Route::resource('{space}/carddavs', CardDavServerController::class, ['except' => ['index', 'show']]);
Route::get('{space}/carddavs/{carddav}/delete', 'Admin\Space\CardDavServerController@delete')->name('carddavs.delete');
Route::get('{space}/carddavs/{carddav}/delete', [CardDavServerController::class, 'delete'])->name('carddavs.delete');
});
Route::name('api_keys.')->prefix('api_keys')->controller(AdminApiKeyController::class)->group(function () {
@ -185,10 +191,10 @@ Route::middleware(['feature.web_panel_enabled'])->group(function () {
Route::middleware(['auth.super_admin'])->group(function () {
Route::resource('spaces', SpaceController::class);
Route::get('spaces/delete/{id}', 'Admin\SpaceController@delete')->name('spaces.delete');
Route::get('spaces/delete/{id}', [SpaceController::class, 'delete'])->name('spaces.delete');
Route::get('spaces/{space}/administration', 'Admin\SpaceController@administration')->name('spaces.administration');
Route::put('spaces/{space}/administration', 'Admin\SpaceController@administrationUpdate')->name('spaces.administration.update');
Route::get('spaces/{space}/administration', [SpaceController::class, 'administration'])->name('spaces.administration');
Route::put('spaces/{space}/administration', [SpaceController::class, 'administrationUpdate'])->name('spaces.administration.update');
Route::name('phone_countries.')->controller(PhoneCountryController::class)->prefix('phone_countries')->group(function () {
Route::get('/', 'index')->name('index');
@ -286,7 +292,7 @@ Route::middleware(['feature.web_panel_enabled'])->group(function () {
});
Route::resource('{account}/carddavs', CardDavCredentialsController::class, ['only' => ['create', 'store', 'destroy']]);
Route::get('{account}/carddavs/{carddav}/delete', 'Admin\Account\CardDavCredentialsController@delete')->name('carddavs.delete');
Route::get('{account}/carddavs/{carddav}/delete', [CardDavCredentialsController::class, 'delete'])->name('carddavs.delete');
Route::name('dictionary.')->prefix('{account}/dictionary')->controller(DictionaryController::class)->group(function () {
Route::get('create', 'create')->name('create');

View file

@ -43,6 +43,8 @@ class ApiAccountCreationTokenTest extends TestCase
public function testInvalidJSON()
{
Space::factory()->create();
$this->call(
$this->method,
$this->tokenRoute,