1
0
mirror of https://github.com/Bubka/2FAuth.git synced 2025-08-13 15:37:08 +02:00

Apply Laravel Pint fixes

This commit is contained in:
Bubka
2022-11-22 15:15:52 +01:00
parent d84dd6659e
commit d6fd8e3c52
178 changed files with 2409 additions and 2899 deletions
app
Api
Console
Events
Exceptions
Extensions
Facades
Factories
Helpers
Http
Listeners
Models
Notifications
Providers
Rules
Services
pint.json
tests
Api
Classes
CreatesApplication.php
Feature
FeatureTestCase.phpModelTestCase.phpTestCase.php
Unit

@ -2,18 +2,16 @@
namespace App\Api\v1\Controllers;
use App\Models\Group;
use App\Facades\Groups;
use App\Api\v1\Requests\GroupStoreRequest;
use App\Api\v1\Requests\GroupAssignRequest;
use App\Api\v1\Requests\GroupStoreRequest;
use App\Api\v1\Resources\GroupResource;
use App\Api\v1\Resources\TwoFAccountCollection;
use App\Facades\Groups;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\App;
use App\Models\Group;
class GroupController extends Controller
{
/**
* Display a listing of the resource.
*
@ -26,7 +24,6 @@ class GroupController extends Controller
return GroupResource::collection($groups);
}
/**
* Store a newly created resource in storage.
*
@ -44,7 +41,6 @@ class GroupController extends Controller
->setStatusCode(201);
}
/**
* Display the specified resource.
*
@ -56,7 +52,6 @@ class GroupController extends Controller
return new GroupResource($group);
}
/**
* Update the specified resource in storage.
*
@ -71,10 +66,8 @@ class GroupController extends Controller
Groups::update($group, $validated);
return new GroupResource($group);
}
/**
* Associate the specified accounts with the group
*
@ -89,10 +82,8 @@ class GroupController extends Controller
Groups::assign($validated['ids'], $group);
return new GroupResource($group);
}
/**
* Get accounts assign to the group
*
@ -104,10 +95,8 @@ class GroupController extends Controller
$twofaccounts = Groups::getAccounts($group);
return new TwoFAccountCollection($twofaccounts);
}
/**
* Remove the specified resource from storage.
*
@ -120,5 +109,4 @@ class GroupController extends Controller
return response()->json(null, 204);
}
}

@ -2,12 +2,11 @@
namespace App\Api\v1\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use App\Http\Controllers\Controller;
use App\Services\LogoService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Storage;
class IconController extends Controller
{
@ -31,7 +30,6 @@ class IconController extends Controller
: response()->json(['message' => __('errors.file_upload_failed')], 500);
}
/**
* Fetch a logo
*
@ -52,7 +50,6 @@ class IconController extends Controller
: response()->json(null, 204);
}
/**
* delete an icon
*

@ -2,15 +2,13 @@
namespace App\Api\v1\Controllers;
use App\Models\TwoFAccount;
use App\Facades\QrCode;
use App\Api\v1\Requests\QrCodeDecodeRequest;
use App\Facades\QrCode;
use App\Http\Controllers\Controller;
use App\Models\TwoFAccount;
class QrCodeController extends Controller
{
/**
* Show a QR code image
*
@ -24,7 +22,6 @@ class QrCodeController extends Controller
return response()->json(['qrcode' => QrCode::encode($uri)], 200);
}
/**
* Decode an uploaded QR Code image
*
@ -39,5 +36,4 @@ class QrCodeController extends Controller
? response()->json(['data' => QrCode::decode($file)], 200)
: response()->json(['message' => __('errors.file_upload_failed')], 500);
}
}

@ -2,12 +2,11 @@
namespace App\Api\v1\Controllers;
use App\Facades\Settings;
use App\Api\v1\Requests\SettingStoreRequest;
use App\Api\v1\Requests\SettingUpdateRequest;
use App\Facades\Settings;
use App\Http\Controllers\Controller;
class SettingController extends Controller
{
/**
@ -22,14 +21,13 @@ class SettingController extends Controller
$settings->each(function (mixed $item, string $key) use ($settingsResources) {
$settingsResources->push([
'key' => $key,
'value' => $item
'value' => $item,
]);
});
return response()->json($settingsResources->all(), 200);
}
/**
* Display a setting
*
@ -46,11 +44,10 @@ class SettingController extends Controller
return response()->json([
'key' => $settingName,
'value' => $setting
'value' => $setting,
], 200);
}
/**
* Store a setting
*
@ -65,11 +62,10 @@ class SettingController extends Controller
return response()->json([
'key' => $validated['key'],
'value' => $validated['value']
'value' => $validated['value'],
], 201);
}
/**
* Update a setting
*
@ -84,12 +80,10 @@ class SettingController extends Controller
return response()->json([
'key' => $settingName,
'value' => $validated['value']
'value' => $validated['value'],
], 200);
}
/**
* Delete a setting
*
@ -105,10 +99,10 @@ class SettingController extends Controller
}
$optionsConfig = config('2fauth.options');
if(array_key_exists($settingName, $optionsConfig)) {
if (array_key_exists($settingName, $optionsConfig)) {
return response()->json(
['message' => 'bad request',
'reason' => [__('errors.delete_user_setting_only')]
'reason' => [__('errors.delete_user_setting_only')],
], 400);
}
@ -116,5 +110,4 @@ class SettingController extends Controller
return response()->json(null, 204);
}
}

@ -2,26 +2,25 @@
namespace App\Api\v1\Controllers;
use App\Models\TwoFAccount;
use App\Api\v1\Requests\TwoFAccountBatchRequest;
use App\Api\v1\Requests\TwoFAccountDynamicRequest;
use App\Api\v1\Requests\TwoFAccountImportRequest;
use App\Api\v1\Requests\TwoFAccountReorderRequest;
use App\Api\v1\Requests\TwoFAccountStoreRequest;
use App\Api\v1\Requests\TwoFAccountUpdateRequest;
use App\Api\v1\Requests\TwoFAccountImportRequest;
use App\Api\v1\Requests\TwoFAccountBatchRequest;
use App\Api\v1\Requests\TwoFAccountUriRequest;
use App\Api\v1\Requests\TwoFAccountDynamicRequest;
use App\Api\v1\Resources\TwoFAccountCollection;
use App\Api\v1\Resources\TwoFAccountReadResource;
use App\Api\v1\Resources\TwoFAccountStoreResource;
use App\Facades\Groups;
use App\Facades\TwoFAccounts;
use Illuminate\Support\Arr;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Models\TwoFAccount;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
class TwoFAccountController extends Controller
{
/**
* List all resources
*
@ -32,12 +31,10 @@ class TwoFAccountController extends Controller
return new TwoFAccountCollection(TwoFAccount::ordered()->get());
}
/**
* Display a 2FA account
*
* @param \App\Models\TwoFAccount $twofaccount
*
* @return \App\Api\v1\Resources\TwoFAccountReadResource
*/
public function show(TwoFAccount $twofaccount)
@ -45,7 +42,6 @@ class TwoFAccountController extends Controller
return new TwoFAccountReadResource($twofaccount);
}
/**
* Store a new 2FA account
*
@ -65,8 +61,7 @@ class TwoFAccountController extends Controller
if (Arr::has($validated, 'uri')) {
$twofaccount->fillWithURI($validated['uri'], Arr::get($validated, 'custom_otp') === TwoFAccount::STEAM_TOTP);
}
else {
} else {
$twofaccount->fillWithOtpParameters($validated);
}
$twofaccount->save();
@ -79,8 +74,6 @@ class TwoFAccountController extends Controller
->setStatusCode(201);
}
/**
* Update a 2FA account
*
@ -98,10 +91,8 @@ class TwoFAccountController extends Controller
return (new TwoFAccountReadResource($twofaccount))
->response()
->setStatusCode(200);
}
/**
* Convert a migration resource to a valid TwoFAccounts collection
*
@ -118,13 +109,11 @@ class TwoFAccountController extends Controller
return $migrationResource instanceof \Illuminate\Http\UploadedFile
? new TwoFAccountCollection(TwoFAccounts::migrate($migrationResource->get()))
: response()->json(['message' => __('errors.file_upload_failed')], 500);
}
else {
} else {
return new TwoFAccountCollection(TwoFAccounts::migrate($request->payload));
}
}
/**
* Save 2FA accounts order
*
@ -140,7 +129,6 @@ class TwoFAccountController extends Controller
return response()->json(['message' => 'order saved'], 200);
}
/**
* Preview account using an uri, without any db moves
*
@ -155,7 +143,6 @@ class TwoFAccountController extends Controller
return new TwoFAccountStoreResource($twofaccount);
}
/**
* Get a One-Time Password
*
@ -173,15 +160,14 @@ class TwoFAccountController extends Controller
}
// The request input is an uri
else if ( $request->has('uri') ) {
elseif ($request->has('uri')) {
// return 404 if uri is provided with any parameter other than otp_type
if ((count($inputs) == 2 && $request->missing('custom_otp')) || count($inputs) > 2) {
return response()->json([
'message' => 'bad request',
'reason' => ['uri' => __('validation.onlyCustomOtpWithUri')]
'reason' => ['uri' => __('validation.onlyCustomOtpWithUri')],
], 400);
}
else {
} else {
$validatedData = $request->validate((new TwoFAccountUriRequest)->rules());
$twofaccount = new TwoFAccount;
$twofaccount->fillWithURI($validatedData['uri'], Arr::get($validatedData, 'custom_otp') === TwoFAccount::STEAM_TOTP, true);
@ -198,7 +184,6 @@ class TwoFAccountController extends Controller
return response()->json($twofaccount->getOTP(), 200);
}
/**
* A simple and light method to get the account count.
*
@ -207,12 +192,10 @@ class TwoFAccountController extends Controller
*/
public function count(Request $request)
{
return response()->json([ 'count' => TwoFAccount::count() ], 200);
return response()->json(['count' => TwoFAccount::count()], 200);
}
/**
*
* Withdraw one or more accounts from their group
*
* @param \App\Api\v1\Requests\TwoFAccountBatchRequest $request
@ -225,16 +208,15 @@ class TwoFAccountController extends Controller
if ($this->tooManyIds($validated['ids'])) {
return response()->json([
'message' => 'bad request',
'reason' => [__('errors.too_many_ids')]
'reason' => [__('errors.too_many_ids')],
], 400);
}
TwoFAccounts::withdraw($validated['ids']);
return response()->json([ 'message' => 'accounts withdrawn' ], 200);
return response()->json(['message' => 'accounts withdrawn'], 200);
}
/**
* Remove the specified resource from storage.
*
@ -248,7 +230,6 @@ class TwoFAccountController extends Controller
return response()->json(null, 204);
}
/**
* Remove the specified resources from storage.
*
@ -262,7 +243,7 @@ class TwoFAccountController extends Controller
if ($this->tooManyIds($validated['ids'])) {
return response()->json([
'message' => 'bad request',
'reason' => [__('errors.too_many_ids')]
'reason' => [__('errors.too_many_ids')],
], 400);
}
@ -271,7 +252,6 @@ class TwoFAccountController extends Controller
return response()->json(null, 204);
}
/**
* Checks ids length
*
@ -285,5 +265,4 @@ class TwoFAccountController extends Controller
return $nb > 99 ? true : false;
}
}

@ -2,9 +2,9 @@
namespace App\Api\v1\Controllers;
use App\Models\User;
use App\Api\v1\Resources\UserResource;
use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Http\Request;
class UserController extends Controller
@ -24,6 +24,5 @@ class UserController extends Controller
return $user
? new UserResource($user)
: response()->json(['name' => null], 200);
}
}

@ -26,7 +26,7 @@ class GroupAssignRequest extends FormRequest
{
return [
'ids' => 'required|array',
'ids.*' => 'integer'
'ids.*' => 'integer',
];
}
}

@ -2,8 +2,8 @@
namespace App\Api\v1\Requests;
use Illuminate\Support\Arr;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Auth;
class TwoFAccountDynamicRequest extends FormRequest
@ -32,7 +32,6 @@ class TwoFAccountDynamicRequest extends FormRequest
return $rules;
}
/**
* Prepare the data for validation.
*

@ -37,7 +37,6 @@ class TwoFAccountStoreRequest extends FormRequest
];
}
/**
* Prepare the data for validation.
*

@ -37,7 +37,6 @@ class TwoFAccountUpdateRequest extends FormRequest
];
}
/**
* Prepare the data for validation.
*

@ -30,7 +30,6 @@ class TwoFAccountUriRequest extends FormRequest
];
}
/**
* Prepare the data for validation.
*

@ -3,7 +3,6 @@
namespace App\Api\v1\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;
use App\Api\v1\Resources\TwoFAccountReadResource;
class TwoFAccountCollection extends ResourceCollection
{
@ -14,7 +13,6 @@ class TwoFAccountCollection extends ResourceCollection
*/
public $collects = TwoFAccountReadResource::class;
/**
* Transform the resource collection into an array.
*
@ -27,7 +25,7 @@ class TwoFAccountCollection extends ResourceCollection
// The underlying TwoFAccountReadResource hides the secret only when withSecret == false.
// When withSecret is provided the underlying resource will return secret according to the parameter value
// If no withSecret is set we force it to false to ensure the secret will not being returned.
if (!$request->has('withSecret')) {
if (! $request->has('withSecret')) {
$request->merge(['withSecret' => false]);
}

@ -31,13 +31,13 @@ class TwoFAccountStoreResource extends JsonResource
'service' => $this->service,
'icon' => $this->icon,
'secret' => $this->when(
!$request->has('withSecret') || (int) filter_var($request->input('withSecret'), FILTER_VALIDATE_BOOLEAN) == 1,
! $request->has('withSecret') || (int) filter_var($request->input('withSecret'), FILTER_VALIDATE_BOOLEAN) == 1,
$this->secret
),
'digits' => (int) $this->digits,
'algorithm' => $this->algorithm,
'period' => is_null($this->period) ? null : (int)$this->period,
'counter' => is_null($this->counter) ? null : (int)$this->counter
'period' => is_null($this->period) ? null : (int) $this->period,
'counter' => is_null($this->counter) ? null : (int) $this->counter,
];
}
}

@ -20,9 +20,9 @@ class UserResource extends JsonResource
public function toArray($request)
{
return [
'id' => $this->when(!is_null($request->user()), $this->id),
'id' => $this->when(! is_null($request->user()), $this->id),
'name' => $this->name,
'email' => $this->when(!is_null($request->user()), $this->email),
'email' => $this->when(! is_null($request->user()), $this->email),
];
}
}

@ -4,7 +4,6 @@ namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
class CheckDbConnection extends Command
{
@ -44,6 +43,7 @@ class CheckDbConnection extends Command
try {
DB::connection()->getPDO();
$this->line(DB::connection()->getDatabaseName());
return 1;
} catch (\Exception $e) {
return 0;

@ -42,12 +42,13 @@ class FixUnsplittedAccounts extends Command
*/
public function handle()
{
if (!Schema::hasColumn('twofaccounts', 'legacy_uri')) {
if (! Schema::hasColumn('twofaccounts', 'legacy_uri')) {
$this->comment('2fauth:fix-unsplitted-accounts is useful only after SplitTwofaccountsUriInMultipleColumns migration ran');
return;
} else {
$this->line('Fetching accounts...');
}
else $this->line('Fetching accounts...');
$twofaccounts = TwoFAccount::where('otp_type', '')
->where('secret', '')
@ -61,6 +62,7 @@ class FixUnsplittedAccounts extends Command
if ($twofaccounts->count() == 0) {
$this->info('Nothing to fix');
return;
}
@ -69,16 +71,14 @@ class FixUnsplittedAccounts extends Command
foreach ($twofaccounts as $twofaccount) {
if ($twofaccount->legacy_uri === __('errors.indecipherable')) {
$this->error(sprintf('Account #%d cannot be deciphered', $twofaccount->id));
}
else {
} else {
try {
// Get a consistent account
$twofaccount->fillWithURI($twofaccount->legacy_uri, false, true);
$twofaccount->save();
$this->info(sprintf('Account #%d fixed', $twofaccount->id));
}
catch (\Exception $ex) {
} catch (\Exception $ex) {
$this->error(sprintf('Error while updating account #%d', $twofaccount->id));
}
}

@ -2,8 +2,8 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Console\Commands\Utils\ResetTrait;
use Illuminate\Console\Command;
class ResetDemo extends Command
{
@ -40,15 +40,15 @@ class ResetDemo extends Command
*/
public function handle()
{
if( !config('2fauth.config.isDemoApp') ) {
if (! config('2fauth.config.isDemoApp')) {
$this->comment('2fauth:reset-demo can only run when isDemoApp option is On');
return;
}
if( $this->option('no-confirm') ) {
if ($this->option('no-confirm')) {
$demo = 'demo';
}
else {
} else {
$this->line('This will reset the app in order to run a clean and fresh demo.');
$demo = $this->ask('To prevent any mistake please type the word "demo" to go on');
}
@ -57,8 +57,7 @@ class ResetDemo extends Command
$this->resetIcons();
$this->resetDB('DemoSeeder');
$this->info('Demo app refreshed');
}
else {
} else {
$this->comment('Bad confirmation word, nothing appened');
}
}

@ -40,15 +40,15 @@ class ResetTesting extends Command
*/
public function handle()
{
if( !config('2fauth.config.isTestingApp') ) {
if (! config('2fauth.config.isTestingApp')) {
$this->comment('2fauth:reset-testing can only run when isTestingApp option is On');
return;
}
if( $this->option('no-confirm') ) {
if ($this->option('no-confirm')) {
$testing = 'testing';
}
else {
} else {
$this->line('This will reset the app in order to run a clean and fresh testing app.');
$testing = $this->ask('To prevent any mistake please type the word "testing" to go on');
}
@ -58,10 +58,8 @@ class ResetTesting extends Command
$this->resetDB('TestingSeeder');
$this->info('Testing app refreshed');
}
else {
} else {
$this->comment('Bad confirmation word, nothing appened');
}
}
}

File diff suppressed because one or more lines are too long

@ -2,7 +2,6 @@
namespace App\Console\Commands\Utils;
use App\Console\Commands\Utils\IconGenerator;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
@ -81,10 +80,9 @@ trait ResetTrait
protected function seedDB(string $seeder) : void
{
$this->callSilent('db:seed', [
'--class' => $seeder
'--class' => $seeder,
]);
$this->line('Database seeded');
}
}

@ -27,7 +27,7 @@ class Kernel extends ConsoleKernel
*/
protected function commands()
{
$this->load(__DIR__.'/Commands');
$this->load(__DIR__ . '/Commands');
require base_path('routes/console.php');
}

@ -44,64 +44,71 @@ class Handler extends ExceptionHandler
{
$this->renderable(function (\Symfony\Component\HttpKernel\Exception\NotFoundHttpException $exception, $request) {
return response()->json([
'message' => 'not found'], 404);
'message' => 'not found',
], 404);
});
$this->renderable(function (InvalidOtpParameterException $exception, $request) {
return response()->json([
'message' => 'invalid OTP parameters',
'reason' => [$exception->getMessage()]
'reason' => [$exception->getMessage()],
], 400);
});
$this->renderable(function (InvalidQrCodeException $exception, $request) {
return response()->json([
'message' => 'not a valid QR code'], 400);
'message' => 'not a valid QR code', ], 400);
});
$this->renderable(function (InvalidSecretException $exception, $request) {
return response()->json([
'message' => 'not a valid base32 encoded secret'], 400);
'message' => 'not a valid base32 encoded secret', ], 400);
});
$this->renderable(function (DbEncryptionException $exception, $request) {
return response()->json([
'message' => $exception->getMessage()], 400);
'message' => $exception->getMessage(), ], 400);
});
$this->renderable(function (InvalidMigrationDataException $exception, $request) {
return response()->json([
'message' => __('errors.invalid_x_migration', ['appname' => $exception->getMessage()])], 400);
'message' => __('errors.invalid_x_migration', ['appname' => $exception->getMessage()]),
], 400);
});
$this->renderable(function (UnsupportedMigrationException $exception, $request) {
return response()->json([
'message' => __('errors.unsupported_migration')], 400);
'message' => __('errors.unsupported_migration'),
], 400);
});
$this->renderable(function (EncryptedMigrationException $exception, $request) {
return response()->json([
'message' => __('errors.encrypted_migration')], 400);
'message' => __('errors.encrypted_migration'),
], 400);
});
$this->renderable(function (UndecipherableException $exception, $request) {
return response()->json([
'message' => __('errors.cannot_decipher_secret')], 400);
'message' => __('errors.cannot_decipher_secret'),
], 400);
});
$this->renderable(function (UnsupportedOtpTypeException $exception, $request) {
return response()->json([
'message' => __('errors.unsupported_otp_type')], 400);
'message' => __('errors.unsupported_otp_type'),
], 400);
});
$this->renderable(function (\Illuminate\Auth\AuthenticationException $exception, $request) {
if ($exception->guards() === ['reverse-proxy-guard']) {
return response()->json([
'message' => $exception->getMessage()], 407);
}
else {
'message' => $exception->getMessage(),
], 407);
} else {
return response()->json([
'message' => $exception->getMessage()], 401);
'message' => $exception->getMessage(),
], 401);
}
});
}

@ -6,10 +6,10 @@
namespace App\Extensions;
use App\Models\User;
use Exception;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Contracts\Auth\UserProvider;
use Illuminate\Support\Arr;
use Exception;
class RemoteUserProvider implements UserProvider
{
@ -23,7 +23,6 @@ class RemoteUserProvider implements UserProvider
// The downside of this approach is that we have to be sure that no change that needs
// to be persisted will be made to the user instance afterward (i.e through middlewares).
/**
* The currently authenticated user.
*
@ -31,7 +30,6 @@ class RemoteUserProvider implements UserProvider
*/
protected $user;
/**
* Get the In-memory user
*
@ -48,9 +46,8 @@ class RemoteUserProvider implements UserProvider
return $this->user;
}
/**
* @inheritDoc
* {@inheritDoc}
*/
public function retrieveById($identifier)
{
@ -67,7 +64,7 @@ class RemoteUserProvider implements UserProvider
}
/**
* @inheritDoc
* {@inheritDoc}
*
* @codeCoverageIgnore
*/
@ -77,7 +74,7 @@ class RemoteUserProvider implements UserProvider
}
/**
* @inheritDoc
* {@inheritDoc}
*
* @codeCoverageIgnore
*/
@ -87,7 +84,7 @@ class RemoteUserProvider implements UserProvider
}
/**
* @inheritDoc
* {@inheritDoc}
*
* @codeCoverageIgnore
*/
@ -97,7 +94,7 @@ class RemoteUserProvider implements UserProvider
}
/**
* @inheritDoc
* {@inheritDoc}
*
* @codeCoverageIgnore
*/

@ -2,8 +2,8 @@
namespace App\Extensions;
use Closure;
use App\Models\WebAuthnAuthenticatable;
use Closure;
use Illuminate\Auth\Passwords\PasswordBroker;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
@ -14,14 +14,13 @@ class WebauthnCredentialBroker extends PasswordBroker
*
* @param array $credentials
* @param \Closure|null $callback
*
* @return string
*/
public function sendResetLink(array $credentials, Closure $callback = null): string
public function sendResetLink(array $credentials, Closure $callback = null) : string
{
$user = $this->getUser($credentials);
if (!$user instanceof WebAuthnAuthenticatable) {
if (! $user instanceof WebAuthnAuthenticatable) {
return static::INVALID_USER;
}
@ -40,20 +39,18 @@ class WebauthnCredentialBroker extends PasswordBroker
return static::RESET_LINK_SENT;
}
/**
* Reset the password for the given token.
*
* @param array $credentials
* @param \Closure $callback
*
* @return \Illuminate\Contracts\Auth\CanResetPassword|string
*/
public function reset(array $credentials, Closure $callback)
{
$user = $this->validateReset($credentials);
if (!$user instanceof CanResetPasswordContract || !$user instanceof WebAuthnAuthenticatable) {
if (! $user instanceof CanResetPasswordContract || ! $user instanceof WebAuthnAuthenticatable) {
return $user;
}

@ -2,16 +2,16 @@
namespace App\Factories;
use App\Services\Migrators\GoogleAuthMigrator;
use App\Exceptions\EncryptedMigrationException;
use App\Exceptions\UnsupportedMigrationException;
use App\Services\Migrators\AegisMigrator;
use App\Services\Migrators\GoogleAuthMigrator;
use App\Services\Migrators\Migrator;
use App\Services\Migrators\PlainTextMigrator;
use App\Services\Migrators\TwoFASMigrator;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Validator;
use App\Exceptions\UnsupportedMigrationException;
use App\Exceptions\EncryptedMigrationException;
class MigratorFactory implements MigratorFactoryInterface
{
@ -25,21 +25,17 @@ class MigratorFactory implements MigratorFactoryInterface
{
if ($this->isAegisJSON($migrationPayload)) {
return App::make(AegisMigrator::class);
}
else if ($this->is2FASv2($migrationPayload)) {
} elseif ($this->is2FASv2($migrationPayload)) {
return App::make(TwoFASMigrator::class);
}
else if ($this->isGoogleAuth($migrationPayload)) {
} elseif ($this->isGoogleAuth($migrationPayload)) {
return App::make(GoogleAuthMigrator::class);
}
else if ($this->isPlainText($migrationPayload)) {
} elseif ($this->isPlainText($migrationPayload)) {
return App::make(PlainTextMigrator::class);
} else {
throw new UnsupportedMigrationException();
}
else throw new UnsupportedMigrationException();
}
/**
* Determine if a payload comes from Google Authenticator
*
@ -50,15 +46,15 @@ class MigratorFactory implements MigratorFactoryInterface
{
// - Google Auth migration URI : a string starting with otpauth-migration://offline?data= on a single line
$lines = preg_split('~\R~', $migrationPayload, -1 , PREG_SPLIT_NO_EMPTY);
$lines = preg_split('~\R~', $migrationPayload, -1, PREG_SPLIT_NO_EMPTY);
if (!$lines || count($lines) != 1)
if (! $lines || count($lines) != 1) {
return false;
}
return preg_match('/^otpauth-migration:\/\/offline\?data=.+$/', $lines[0]) == 1;
}
/**
* Determine if a payload is a plain text content
*
@ -70,14 +66,13 @@ class MigratorFactory implements MigratorFactoryInterface
// - Plain text : one or more otpauth URIs (otpauth://[t|h]otp/...), one per line
return Validator::make(
preg_split('~\R~', $migrationPayload, -1 , PREG_SPLIT_NO_EMPTY),
preg_split('~\R~', $migrationPayload, -1, PREG_SPLIT_NO_EMPTY),
[
'*' => 'regex:/^otpauth:\/\/[h,t]otp\//i',
]
)->passes();
}
/**
* Determine if a payload comes from Aegis Authenticator in JSON format
*
@ -107,15 +102,14 @@ class MigratorFactory implements MigratorFactoryInterface
if (Arr::has($json, 'db')) {
if (is_string($json['db']) && is_array(Arr::get($json, 'header.slots'))) {
throw new EncryptedMigrationException();
}
else {
} else {
return count(Validator::validate(
$json,
[
'db.entries.*.type' => 'required',
'db.entries.*.name' => 'required',
'db.entries.*.issuer' => 'required',
'db.entries.*.info' => 'required'
'db.entries.*.info' => 'required',
]
)) > 0;
}
@ -124,7 +118,6 @@ class MigratorFactory implements MigratorFactoryInterface
return false;
}
/**
* Determine if a payload comes from 2FAS Authenticator
*
@ -159,14 +152,13 @@ class MigratorFactory implements MigratorFactoryInterface
if (Arr::get($json, 'schemaVersion') == 2 && (Arr::has($json, 'services') || Arr::has($json, 'servicesEncrypted'))) {
if (Arr::has($json, 'servicesEncrypted')) {
throw new EncryptedMigrationException();
}
else {
} else {
return count(Validator::validate(
$json,
[
'services.*.secret' => 'required',
'services.*.name' => 'required',
'services.*.otp' => 'required'
'services.*.otp' => 'required',
]
)) > 0;
}
@ -174,5 +166,4 @@ class MigratorFactory implements MigratorFactoryInterface
return false;
}
}

@ -12,13 +12,18 @@ class Helpers
* @param string $extension
* @return string The filename
*/
public static function getUniqueFilename(string $extension): string
public static function getUniqueFilename(string $extension) : string
{
return Str::random(40).'.'.$extension;
return Str::random(40) . '.' . $extension;
}
public static function cleanVersionNumber(?string $release): string|false
/**
* Clean a version number string
*
* @param string|null $release
* @return string|false
*/
public static function cleanVersionNumber(?string $release) : string|false
{
return preg_match('/([[0-9][0-9\.]*[0-9])/', $release, $version) ? $version[0] : false;
}

@ -2,9 +2,9 @@
namespace App\Http\Controllers\Auth;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
use Illuminate\Http\Request;
class ForgotPasswordController extends Controller
{
@ -21,7 +21,6 @@ class ForgotPasswordController extends Controller
use SendsPasswordResetEmails;
/**
* Validate the email for the given request.
*

@ -2,17 +2,16 @@
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Http\Requests\LoginRequest;
use Carbon\Carbon;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Lang;
use App\Http\Requests\LoginRequest;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
class LoginController extends Controller
{
/*
@ -28,7 +27,6 @@ class LoginController extends Controller
use AuthenticatesUsers;
/**
* Handle a login request to the application.
*
@ -65,9 +63,9 @@ class LoginController extends Controller
return $this->sendFailedLoginResponse($request);
}
/**
* log out current user
*
* @param Request $request
* @return \Illuminate\Http\JsonResponse
*/
@ -79,7 +77,6 @@ class LoginController extends Controller
return response()->json(['message' => 'signed out'], Response::HTTP_OK);
}
/**
* Send the response after the user was authenticated.
*
@ -96,11 +93,10 @@ class LoginController extends Controller
return response()->json([
'message' => 'authenticated',
'name' => $name
'name' => $name,
], Response::HTTP_OK);
}
/**
* Get the failed login response instance.
*
@ -112,7 +108,6 @@ class LoginController extends Controller
return response()->json(['message' => 'unauthorised'], Response::HTTP_UNAUTHORIZED);
}
/**
* Redirect the user after determining they are locked out.
*
@ -128,7 +123,6 @@ class LoginController extends Controller
return response()->json(['message' => Lang::get('auth.throttle', ['seconds' => $seconds])], Response::HTTP_TOO_MANY_REQUESTS);
}
/**
* Get the needed authorization credentials from the request.
*
@ -145,7 +139,6 @@ class LoginController extends Controller
return $credentials;
}
/**
* The user has been authenticated.
*

@ -2,8 +2,8 @@
namespace App\Http\Controllers\Auth;
use App\Http\Requests\UserPatchPwdRequest;
use App\Http\Controllers\Controller;
use App\Http\Requests\UserPatchPwdRequest;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Log;
@ -20,12 +20,13 @@ class PasswordController extends Controller
{
$validated = $request->validated();
if (!Hash::check( $validated['currentPassword'], Auth::user()->password) ) {
if (! Hash::check($validated['currentPassword'], Auth::user()->password)) {
Log::notice('Password update failed: wrong password provided');
return response()->json(['message' => __('errors.wrong_current_password')], 400);
}
if (!config('2fauth.config.isDemoApp') ) {
if (! config('2fauth.config.isDemoApp')) {
$request->user()->update([
'password' => bcrypt($validated['password']),
]);

@ -2,12 +2,12 @@
namespace App\Http\Controllers\Auth;
use App\Models\User;
use App\Http\Requests\UserStoreRequest;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Hash;
use App\Http\Requests\UserStoreRequest;
use App\Models\User;
use Illuminate\Auth\Events\Registered;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Log;
class RegisterController extends Controller
@ -25,7 +25,6 @@ class RegisterController extends Controller
use RegistersUsers;
/**
* Handle a registration request for the application.
*
@ -46,7 +45,6 @@ class RegisterController extends Controller
], 201);
}
/**
* Create a new user instance after a valid registration.
*

@ -19,5 +19,4 @@ class ResetPasswordController extends Controller
*/
use ResetsPasswords;
}

@ -2,14 +2,14 @@
namespace App\Http\Controllers\Auth;
use App\Http\Requests\UserUpdateRequest;
use App\Http\Requests\UserDeleteRequest;
use App\Api\v1\Resources\UserResource;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\DB;
use App\Http\Requests\UserDeleteRequest;
use App\Http\Requests\UserUpdateRequest;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Log;
class UserController extends Controller
@ -25,12 +25,13 @@ class UserController extends Controller
$user = $request->user();
$validated = $request->validated();
if (!Hash::check( $request->password, Auth::user()->password) ) {
if (! Hash::check($request->password, Auth::user()->password)) {
Log::notice('Account update failed: wrong password provided');
return response()->json(['message' => __('errors.wrong_current_password')], 400);
}
if (!config('2fauth.config.isDemoApp') ) {
if (! config('2fauth.config.isDemoApp')) {
$user->update([
'name' => $validated['name'],
'email' => $validated['email'],
@ -41,7 +42,6 @@ class UserController extends Controller
return new UserResource($user);
}
/**
* Delete the user's account.
*
@ -53,7 +53,7 @@ class UserController extends Controller
Log::info('User deletion requested');
$validated = $request->validated();
if (!Hash::check( $validated['password'], Auth::user()->password) ) {
if (! Hash::check($validated['password'], Auth::user()->password)) {
return response()->json(['message' => __('errors.wrong_current_password')], 400);
}
@ -79,6 +79,7 @@ class UserController extends Controller
// @codeCoverageIgnoreStart
catch (\Throwable $e) {
Log::error('User deletion failed');
return response()->json(['message' => __('errors.user_deletion_failed')], 400);
}
// @codeCoverageIgnoreEnd

@ -2,26 +2,25 @@
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;
use App\Extensions\WebauthnCredentialBroker;
use Illuminate\Foundation\Auth\ResetsPasswords;
use Illuminate\Support\Facades\Password;
use App\Http\Controllers\Controller;
use App\Http\Requests\WebauthnDeviceLostRequest;
use Illuminate\Foundation\Auth\ResetsPasswords;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Password;
use Illuminate\Validation\ValidationException;
class WebAuthnDeviceLostController extends Controller
{
use ResetsPasswords;
/**
* Send a recovery email to the user.
*
* @param \App\Http\Requests\WebauthnDeviceLostRequest $request
* @param \App\Extensions\WebauthnCredentialBroker $broker
*
* @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse
*
* @throws \Illuminate\Validation\ValidationException
*/
public function sendRecoveryEmail(WebauthnDeviceLostRequest $request, WebauthnCredentialBroker $broker)
@ -35,14 +34,13 @@ class WebAuthnDeviceLostController extends Controller
: $this->sendRecoveryLinkFailedResponse($request, $response);
}
/**
* Get the response for a failed account recovery link.
*
* @param \Illuminate\Http\Request $request
* @param string $response
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse
*
* @throws \Illuminate\Validation\ValidationException
*/
protected function sendRecoveryLinkFailedResponse(Request $request, string $response)
@ -56,13 +54,11 @@ class WebAuthnDeviceLostController extends Controller
->withErrors(['email' => trans($response)]);
}
/**
* Get the response for a successful account recovery link.
*
* @param \Illuminate\Http\Request $request
* @param string $response
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse
*/
protected function sendRecoveryLinkResponse(Request $request, string $response)

@ -2,14 +2,14 @@
namespace App\Http\Controllers\Auth;
use App\Models\User;
use Illuminate\Http\JsonResponse;
use App\Http\Controllers\Controller;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Laragear\WebAuthn\Http\Requests\AssertionRequest;
use Laragear\WebAuthn\Http\Requests\AssertedRequest;
use Illuminate\Contracts\Support\Responsable;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
use Laragear\WebAuthn\Http\Requests\AssertedRequest;
use Laragear\WebAuthn\Http\Requests\AssertionRequest;
use Laragear\WebAuthn\WebAuthn;
class WebAuthnLoginController extends Controller
@ -31,7 +31,7 @@ class WebAuthnLoginController extends Controller
* @param \Laragear\WebAuthn\Http\Requests\AssertionRequest $request
* @return \Illuminate\Contracts\Support\Responsable|\Illuminate\Http\JsonResponse
*/
public function options(AssertionRequest $request): Responsable|JsonResponse
public function options(AssertionRequest $request) : Responsable|JsonResponse
{
switch (env('WEBAUTHN_USER_VERIFICATION')) {
case WebAuthn::USER_VERIFICATION_DISCOURAGED:
@ -50,11 +50,10 @@ class WebAuthnLoginController extends Controller
return $user
? $request->toVerify($user)
: response()->json([
'message' => 'no registered user'
'message' => 'no registered user',
], 400);
}
/**
* Log the user in.
*
@ -70,7 +69,7 @@ class WebAuthnLoginController extends Controller
// Some authenticators do not send a userHandle so we hack the response to be compliant
// with Larapass/webauthn-lib implementation that waits for a userHandle
if(!$response['userHandle']) {
if (! $response['userHandle']) {
$response['userHandle'] = User::getFromCredentialId($request->id)?->userHandle();
$request->merge(['response' => $response]);
}
@ -80,18 +79,17 @@ class WebAuthnLoginController extends Controller
if ($user) {
$this->authenticated($user);
return response()->noContent();
}
return response()->noContent(422);
}
/**
* The user has been authenticated.
*
* @param mixed $user
*
* @return void|\Illuminate\Http\JsonResponse
*/
protected function authenticated($user)

@ -4,13 +4,12 @@ namespace App\Http\Controllers\Auth;
use App\Facades\Settings;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Http\Requests\WebauthnRenameRequest;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
class WebAuthnManageController extends Controller
{
/**
* List all WebAuthn registered credentials
*
@ -23,7 +22,6 @@ class WebAuthnManageController extends Controller
return response()->json($allUserCredentials, 200);
}
/**
* Rename a WebAuthn credential
*
@ -42,13 +40,11 @@ class WebAuthnManageController extends Controller
], 200);
}
/**
* Remove the specified credential from storage.
*
* @param \Illuminate\Http\Request $request
* @param string|array $credential
*
* @return \Illuminate\Http\JsonResponse
*/
public function delete(Request $request, $credential)

@ -2,18 +2,17 @@
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Http\Requests\WebauthnRecoveryRequest;
use App\Extensions\WebauthnCredentialBroker;
use App\Facades\Settings;
use App\Http\Controllers\Controller;
use App\Http\Requests\WebauthnRecoveryRequest;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Foundation\Auth\ResetsPasswords;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;
use Illuminate\Support\Facades\Auth;
use Illuminate\Foundation\Auth\ResetsPasswords;
use Illuminate\Support\Facades\Password;
use Illuminate\Support\Facades\App;
use Illuminate\Validation\ValidationException;
class WebAuthnRecoveryController extends Controller
{
@ -25,8 +24,8 @@ class WebAuthnRecoveryController extends Controller
*
* @param \App\Http\Requests\WebauthnRecoveryRequest $request
* @param \App\Extensions\WebauthnCredentialBroker $broker
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse
*
* @throws \Illuminate\Validation\ValidationException
*/
public function recover(WebauthnRecoveryRequest $request, WebauthnCredentialBroker $broker)
@ -54,66 +53,57 @@ class WebAuthnRecoveryController extends Controller
$user->flushCredentials();
}
Settings::delete('useWebauthnOnly');
} else {
throw new AuthenticationException();
}
else throw new AuthenticationException();
}
);
return $response === Password::PASSWORD_RESET
? $this->sendRecoveryResponse($request, $response)
: $this->sendRecoveryFailedResponse($request, $response);
}
/**
* Check if the user has set to revoke all credentials.
*
* @param \App\Http\Requests\WebauthnRecoveryRequest $request
*
* @return bool|mixed
*/
protected function shouldRevokeAllCredentials(WebauthnRecoveryRequest $request): mixed
protected function shouldRevokeAllCredentials(WebauthnRecoveryRequest $request) : mixed
{
return filter_var($request->header('WebAuthn-Unique'), FILTER_VALIDATE_BOOLEAN)
?: $request->input('revokeAll', true);
}
/**
* Get the response for a successful account recovery.
*
* @param \Illuminate\Http\Request $request
* @param string $response
*
* @return \Illuminate\Http\JsonResponse
*
*/
protected function sendRecoveryResponse(Request $request, string $response): JsonResponse
protected function sendRecoveryResponse(Request $request, string $response) : JsonResponse
{
return response()->json(['message' => __('auth.webauthn.webauthn_login_disabled')]);
}
/**
* Get the response for a failed account recovery.
*
* @param \Illuminate\Http\Request $request
* @param string $response
*
* @return \Illuminate\Http\JsonResponse
* @throws \Illuminate\Validation\ValidationException
*
* @throws \Illuminate\Validation\ValidationException
*/
protected function sendRecoveryFailedResponse(Request $request, string $response): JsonResponse
protected function sendRecoveryFailedResponse(Request $request, string $response) : JsonResponse
{
switch ($response) {
case Password::INVALID_TOKEN:
throw ValidationException::withMessages(['token' => [__('auth.webauthn.invalid_reset_token')]]);
default:
throw ValidationException::withMessages(['email' => [trans($response)]]);
}
}
}

@ -17,7 +17,7 @@ class WebAuthnRegisterController extends Controller
* @param \Laragear\WebAuthn\Http\Requests\AttestationRequest $request
* @return \Illuminate\Contracts\Support\Responsable
*/
public function options(AttestationRequest $request): Responsable
public function options(AttestationRequest $request) : Responsable
{
switch (env('WEBAUTHN_USER_VERIFICATION')) {
case WebAuthn::USER_VERIFICATION_DISCOURAGED:
@ -34,14 +34,13 @@ class WebAuthnRegisterController extends Controller
->toCreate();
}
/**
* Registers a device for further WebAuthn authentication.
*
* @param \Laragear\WebAuthn\Http\Requests\AttestedRequest $request
* @return \Illuminate\Http\Response
*/
public function register(AttestedRequest $request): Response
public function register(AttestedRequest $request) : Response
{
$request->save();

@ -2,10 +2,10 @@
namespace App\Http\Controllers;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController;
class Controller extends BaseController
{

@ -2,16 +2,15 @@
namespace App\Http\Controllers;
use App\Events\ScanForNewReleaseCalled;
use App\Facades\Settings;
use Illuminate\Support\Facades\App;
use App\Events\ScanForNewReleaseCalled;
class SinglePageController extends Controller
{
/**
* return the main view
*
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
*/
public function index()
@ -21,13 +20,13 @@ class SinglePageController extends Controller
return view('landing')->with([
'appSettings' => Settings::all()->toJson(),
'appConfig' => collect([
'proxyAuth' => config("auth.defaults.guard") === 'reverse-proxy-guard' ? true : false,
'proxyLogoutUrl' => config("2fauth.config.proxyLogoutUrl") ? config("2fauth.config.proxyLogoutUrl") : false,
'proxyAuth' => config('auth.defaults.guard') === 'reverse-proxy-guard' ? true : false,
'proxyLogoutUrl' => config('2fauth.config.proxyLogoutUrl') ? config('2fauth.config.proxyLogoutUrl') : false,
])->toJson(),
'lang' => App::currentLocale(),
'isDemoApp' => config("2fauth.config.isDemoApp") ? 'true' : 'false',
'isTestingApp' => config("2fauth.config.isTestingApp") ? 'true' : 'false',
'locales' => collect(config("2fauth.locales"))->toJson() /** @phpstan-ignore-line */
'isDemoApp' => config('2fauth.config.isDemoApp') ? 'true' : 'false',
'isTestingApp' => config('2fauth.config.isTestingApp') ? 'true' : 'false',
'locales' => collect(config('2fauth.locales'))->toJson(), /** @phpstan-ignore-line */
]);
}
}

@ -2,9 +2,8 @@
namespace App\Http\Controllers;
use App\Services\ReleaseRadarService;
use App\Http\Controllers\Controller;
use App\Facades\Settings;
use App\Services\ReleaseRadarService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
@ -17,7 +16,7 @@ class SystemController extends Controller
*/
public function infos(Request $request)
{
$infos = array();
$infos = [];
$infos['Date'] = date(DATE_RFC2822);
$infos['userAgent'] = $request->header('user-agent');
// App info
@ -50,7 +49,6 @@ class SystemController extends Controller
return response()->json($infos);
}
/**
* Get latest release
*

@ -20,8 +20,7 @@ class Authenticate extends Middleware
if (empty($guards)) {
// Will retreive the default guard
$guards = [null];
}
else {
} else {
// We replace routes guard by the reverse proxy guard if necessary
$proxyGuard = 'reverse-proxy-guard';
@ -33,11 +32,11 @@ class Authenticate extends Middleware
foreach ($guards as $guard) {
if ($this->auth->guard($guard)->check()) {
$this->auth->shouldUse($guard);
return;
}
}
$this->unauthenticated($request, $guards);
}
}

@ -6,7 +6,6 @@ use Laravel\Passport\Http\Middleware\CreateFreshApiToken as CreateFreshApiToken;
class CustomCreateFreshApiToken extends CreateFreshApiToken
{
/**
* Determine if the request should receive a fresh token.
*
@ -15,6 +14,6 @@ class CustomCreateFreshApiToken extends CreateFreshApiToken
*/
protected function requestShouldReceiveFreshToken($request)
{
return !is_null($request->user($this->guard));
return ! is_null($request->user($this->guard));
}
}

@ -2,12 +2,12 @@
namespace App\Http\Middleware;
use Closure;
use App\Facades\Settings;
use Carbon\Carbon;
use Closure;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use App\Facades\Settings;
class KickOutInactiveUser
{
@ -38,7 +38,6 @@ class KickOutInactiveUser
// If user has been inactive longer than the allowed inactivity period
if ($kickUserAfterXSecond > 0 && $inactiveFor > $kickUserAfterXSecond) {
$user->last_seen_at = $now->format('Y-m-d H:i:s');
$user->save();

@ -2,8 +2,8 @@
namespace App\Http\Middleware;
use Closure;
use Carbon\Carbon;
use Closure;
use Illuminate\Support\Facades\Auth;
class LogUserLastSeen
@ -25,7 +25,7 @@ class LogUserLastSeen
// - Guest
// - User authenticated against a bearer token
// - User authenticated via a reverse-proxy
if (Auth::guard($guard)->check() && !$request->bearerToken() && config('auth.defaults.guard') !== 'reverse-proxy-guard') {
if (Auth::guard($guard)->check() && ! $request->bearerToken() && config('auth.defaults.guard') !== 'reverse-proxy-guard') {
Auth::guard($guard)->user()->last_seen_at = Carbon::now()->format('Y-m-d H:i:s');
Auth::guard($guard)->user()->save();
break;

@ -17,8 +17,7 @@ class RejectIfDemoMode
*/
public function handle($request, Closure $next)
{
if( config('2fauth.config.isDemoApp') ) {
if (config('2fauth.config.isDemoApp')) {
Log::info('Cannot request this action in Demo mode');
return response()->json(['message' => __('auth.forms.disabled_in_demo')], Response::HTTP_UNAUTHORIZED);

@ -20,7 +20,8 @@ class RejectIfReverseProxy
Log::info('Cannot request this action in Demo mode');
return response()->json([
'message' => __('errors.unsupported_with_reverseproxy')], 400);
'message' => __('errors.unsupported_with_reverseproxy'),
], 400);
}
return $next($request);

@ -2,9 +2,9 @@
namespace App\Http\Middleware;
use App\Facades\Settings;
use Closure;
use Illuminate\Support\Facades\App;
use App\Facades\Settings;
class SetLanguage
{
@ -26,16 +26,17 @@ class SetLanguage
// FI: Settings::get() always returns a fallback value
$lang = Settings::get('lang');
if($lang === 'browser') {
if ($lang === 'browser') {
$lang = config('app.fallback_locale');
$accepted = str_replace(' ', '', $request->header("Accept-Language"));
$accepted = str_replace(' ', '', $request->header('Accept-Language'));
if ($accepted && $accepted !== '*') {
$prefLocales = array_reduce(
array_diff(explode(',', $accepted), ['*']),
function ($res, $el) {
list($l, $q) = array_merge(explode(';q=', $el), [1]);
[$l, $q] = array_merge(explode(';q=', $el), [1]);
$res[$l] = (float) $q;
return $res;
},
[]

@ -26,7 +26,7 @@ class SkipIfAuthenticated
return response()->json([
'message' => 'authenticated',
'name' => $user
'name' => $user,
], 200);
}
}

@ -19,8 +19,7 @@ class TrustProxies extends Middleware
*
* @var int
*/
protected $headers =
Request::HEADER_X_FORWARDED_FOR |
protected $headers = Request::HEADER_X_FORWARDED_FOR |
Request::HEADER_X_FORWARDED_HOST |
Request::HEADER_X_FORWARDED_PORT |
Request::HEADER_X_FORWARDED_PROTO |

@ -2,10 +2,7 @@
namespace App\Http\Requests;
use Illuminate\Support\Facades\DB;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class LoginRequest extends FormRequest
{
@ -30,7 +27,7 @@ class LoginRequest extends FormRequest
'email' => [
'required',
'email',
new \App\Rules\CaseInsensitiveEmailExists
new \App\Rules\CaseInsensitiveEmailExists,
],
'password' => 'required|string',
];

@ -5,7 +5,6 @@ namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
class UserDeleteRequest extends FormRequest
{
/**

@ -3,7 +3,6 @@
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
class WebauthnDeviceLostRequest extends FormRequest
{
@ -28,7 +27,7 @@ class WebauthnDeviceLostRequest extends FormRequest
'email' => [
'required',
'email',
new \App\Rules\CaseInsensitiveEmailExists
new \App\Rules\CaseInsensitiveEmailExists,
],
];
}

@ -3,7 +3,6 @@
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
class WebauthnRecoveryRequest extends FormRequest
{

@ -2,8 +2,8 @@
namespace App\Listeners;
use App\Models\TwoFAccount;
use App\Events\GroupDeleting;
use App\Models\TwoFAccount;
use Illuminate\Support\Facades\Log;
class DissociateTwofaccountFromGroup
@ -28,7 +28,7 @@ class DissociateTwofaccountFromGroup
{
TwoFAccount::where('group_id', $event->group->id)
->update(
['group_id' => NULL]
['group_id' => null]
);
Log::info(sprintf('TwoFAccounts dissociated from group #%d', $event->group->id));

@ -4,22 +4,19 @@ namespace App\Listeners;
use App\Events\ScanForNewReleaseCalled;
use App\Services\ReleaseRadarService;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Log;
class ReleaseRadar
{
/**
* @var ReleaseRadarService $releaseRadar
* @var ReleaseRadarService
*/
protected $releaseRadar;
/**
* Create the event listener.
*
* @param \App\Services\ReleaseRadarService $releaseRadar
*
* @return void
*/
public function __construct(ReleaseRadarService $releaseRadar)
@ -27,7 +24,6 @@ class ReleaseRadar
$this->releaseRadar = $releaseRadar;
}
/**
* Handle the event.
*

@ -3,16 +3,15 @@
namespace App\Models;
use App\Events\GroupDeleting;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Log;
use Illuminate\Database\Eloquent\Factories\HasFactory;
/**
* @property int $twofaccounts_count
*/
class Group extends Model
{
use HasFactory;
/**
@ -22,7 +21,6 @@ class Group extends Model
*/
protected $fillable = ['name'];
/**
* The accessors to append to the model's array form.
*
@ -30,7 +28,6 @@ class Group extends Model
*/
protected $appends = [];
/**
* The attributes that should be hidden for arrays.
*
@ -38,7 +35,6 @@ class Group extends Model
*/
protected $hidden = ['created_at', 'updated_at'];
/**
* The attributes that should be cast.
*
@ -48,7 +44,6 @@ class Group extends Model
'twofaccounts_count' => 'integer',
];
/**
* The event map for the model.
*
@ -58,7 +53,6 @@ class Group extends Model
'deleting' => GroupDeleting::class,
];
/**
* Override The "booting" method of the model
*
@ -75,7 +69,6 @@ class Group extends Model
});
}
/**
* Get the TwoFAccounts of the group.
*

@ -4,7 +4,6 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Option extends Model
{
/**
@ -17,7 +16,6 @@ class Option extends Model
'value',
];
/**
* Indicates if the model should be timestamped.
*
@ -25,12 +23,10 @@ class Option extends Model
*/
public $timestamps = false;
/**
* Casts.
*
* @var array<string, string>
*/
protected $casts = [];
}

@ -2,9 +2,9 @@
namespace App\Models\Traits;
use Illuminate\Support\Str;
use App\Notifications\WebauthnRecoveryNotification;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Str;
/**
* @see \App\Models\WebAuthnAuthenticatable
@ -17,7 +17,7 @@ trait WebAuthnManageCredentials
*
* @return string
*/
public function userHandle(): string
public function userHandle() : string
{
// Laragear\WebAuthn uses Ramsey\Uuid\Uuid::fromString()->getHex()->toString()
// to obtain a UUID v4 with dashes removed and uses it as user_id (aka userHandle)
@ -28,7 +28,6 @@ trait WebAuthnManageCredentials
?? str_replace('-', '', Str::uuid()->toString());
}
/**
* Saves a new alias for a given WebAuthn credential.
*
@ -36,19 +35,18 @@ trait WebAuthnManageCredentials
* @param string $alias
* @return bool
*/
public function renameCredential(string $id, string $alias): bool
public function renameCredential(string $id, string $alias) : bool
{
return boolval($this->webAuthnCredentials()->whereKey($id)->update(['alias' => $alias]));
}
/**
* Removes one or more credentials previously registered.
*
* @param string|array $id
* @return void
*/
public function flushCredential($id): void
public function flushCredential($id) : void
{
if (! $this->relationLoaded('webAuthnCredentials')) {
$this->webAuthnCredentials()->whereKey($id)->delete();
@ -63,15 +61,13 @@ trait WebAuthnManageCredentials
}
}
/**
* Sends a webauthn recovery email to the user.
*
* @param string $token
*
* @return void
*/
public function sendWebauthnRecoveryNotification(string $token): void
public function sendWebauthnRecoveryNotification(string $token) : void
{
// $accountRecoveryNotification = new WebauthnRecoveryNotification($token);
// $accountRecoveryNotification->toMailUsing(null);
@ -92,6 +88,5 @@ trait WebAuthnManageCredentials
// });
$this->notify(new WebauthnRecoveryNotification($token));
}
}

@ -2,55 +2,62 @@
namespace App\Models;
use Exception;
use App\Services\LogoService;
use App\Facades\Settings;
use App\Models\Dto\TotpDto;
use App\Models\Dto\HotpDto;
use App\Events\TwoFAccountDeleted;
use App\Exceptions\InvalidSecretException;
use App\Exceptions\InvalidOtpParameterException;
use App\Exceptions\UnsupportedOtpTypeException;
use App\Exceptions\InvalidSecretException;
use App\Exceptions\UndecipherableException;
use Illuminate\Validation\ValidationException;
use Spatie\EloquentSortable\Sortable;
use Spatie\EloquentSortable\SortableTrait;
use OTPHP\TOTP;
use OTPHP\HOTP;
use OTPHP\Factory;
use SteamTotp\SteamTotp;
use App\Exceptions\UnsupportedOtpTypeException;
use App\Facades\Settings;
use App\Helpers\Helpers;
use App\Models\Dto\HotpDto;
use App\Models\Dto\TotpDto;
use App\Services\LogoService;
use Exception;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Validation\ValidationException;
use OTPHP\Factory;
use OTPHP\HOTP;
use OTPHP\TOTP;
use ParagonIE\ConstantTime\Base32;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Http;
use App\Helpers\Helpers;
use Spatie\EloquentSortable\Sortable;
use Spatie\EloquentSortable\SortableTrait;
use SteamTotp\SteamTotp;
class TwoFAccount extends Model implements Sortable
{
use SortableTrait, HasFactory;
const TOTP = 'totp';
const HOTP = 'hotp';
const STEAM_TOTP = 'steamtotp';
const SHA1 = 'sha1';
const MD5 = 'md5';
const SHA256 = 'sha256';
const SHA512 = 'sha512';
const DEFAULT_PERIOD = 30;
const DEFAULT_COUNTER = 0;
const DEFAULT_DIGITS = 6;
const DEFAULT_ALGORITHM = self::SHA1;
const DUPLICATE_ID = -1;
const FAKE_ID = -2;
private const IMAGELINK_STORAGE_PATH = 'imagesLink/';
@ -80,7 +87,6 @@ class TwoFAccount extends Model implements Sortable
// 'icon'
];
/**
* The table associated with the model.
*
@ -88,7 +94,6 @@ class TwoFAccount extends Model implements Sortable
*/
protected $table = 'twofaccounts';
/**
* The accessors to append to the model's array form.
*
@ -96,7 +101,6 @@ class TwoFAccount extends Model implements Sortable
*/
public $appends = [];
/**
* The model's default values for attributes.
*
@ -107,7 +111,6 @@ class TwoFAccount extends Model implements Sortable
'algorithm' => self::SHA1,
];
/**
* The attributes that should be hidden for arrays.
*
@ -115,7 +118,6 @@ class TwoFAccount extends Model implements Sortable
*/
protected $hidden = [];
/**
* The attributes that should be cast.
*
@ -123,7 +125,6 @@ class TwoFAccount extends Model implements Sortable
*/
protected $casts = [];
/**
* The event map for the model.
*
@ -133,7 +134,6 @@ class TwoFAccount extends Model implements Sortable
'deleted' => TwoFAccountDeleted::class,
];
/**
* Override The "booting" method of the model
*
@ -144,9 +144,15 @@ class TwoFAccount extends Model implements Sortable
parent::boot();
static::saving(function (TwoFAccount $twofaccount) {
if (!$twofaccount->legacy_uri) $twofaccount->legacy_uri = $twofaccount->getURI();
if ($twofaccount->otp_type == TwoFAccount::TOTP && !$twofaccount->period) $twofaccount->period = TwoFAccount::DEFAULT_PERIOD;
if ($twofaccount->otp_type == TwoFAccount::HOTP && !$twofaccount->counter) $twofaccount->counter = TwoFAccount::DEFAULT_COUNTER;
if (! $twofaccount->legacy_uri) {
$twofaccount->legacy_uri = $twofaccount->getURI();
}
if ($twofaccount->otp_type == TwoFAccount::TOTP && ! $twofaccount->period) {
$twofaccount->period = TwoFAccount::DEFAULT_PERIOD;
}
if ($twofaccount->otp_type == TwoFAccount::HOTP && ! $twofaccount->counter) {
$twofaccount->counter = TwoFAccount::DEFAULT_COUNTER;
}
});
// static::deleted(function ($model) {
@ -154,7 +160,6 @@ class TwoFAccount extends Model implements Sortable
// });
}
/**
* Settings for @spatie/eloquent-sortable package
*
@ -165,7 +170,6 @@ class TwoFAccount extends Model implements Sortable
'sort_when_creating' => true,
];
/**
* The OTP generator.
* Instanciated as null to keep the model light
@ -174,7 +178,6 @@ class TwoFAccount extends Model implements Sortable
*/
protected $generator = null;
/**
* Get legacy_uri attribute
*
@ -183,9 +186,9 @@ class TwoFAccount extends Model implements Sortable
*/
public function getLegacyUriAttribute($value)
{
return $this->decryptOrReturn($value);
}
/**
* Set legacy_uri attribute
*
@ -198,7 +201,6 @@ class TwoFAccount extends Model implements Sortable
$this->attributes['legacy_uri'] = $this->encryptOrReturn($value);
}
/**
* Get account attribute
*
@ -207,9 +209,9 @@ class TwoFAccount extends Model implements Sortable
*/
public function getAccountAttribute($value)
{
return $this->decryptOrReturn($value);
}
/**
* Set account attribute
*
@ -222,7 +224,6 @@ class TwoFAccount extends Model implements Sortable
$this->attributes['account'] = $this->encryptOrReturn($value);
}
/**
* Get secret attribute
*
@ -231,9 +232,9 @@ class TwoFAccount extends Model implements Sortable
*/
public function getSecretAttribute($value)
{
return $this->decryptOrReturn($value);
}
/**
* Set secret attribute
*
@ -246,7 +247,6 @@ class TwoFAccount extends Model implements Sortable
$this->attributes['secret'] = $this->encryptOrReturn($value);
}
/**
* Set digits attribute
*
@ -255,10 +255,9 @@ class TwoFAccount extends Model implements Sortable
*/
public function setDigitsAttribute($value)
{
$this->attributes['digits'] = !$value ? 6 : $value;
$this->attributes['digits'] = ! $value ? 6 : $value;
}
/**
* Set algorithm attribute
*
@ -267,10 +266,9 @@ class TwoFAccount extends Model implements Sortable
*/
public function setAlgorithmAttribute($value)
{
$this->attributes['algorithm'] = !$value ? self::SHA1 : strtolower($value);
$this->attributes['algorithm'] = ! $value ? self::SHA1 : strtolower($value);
}
/**
* Set period attribute
*
@ -279,10 +277,9 @@ class TwoFAccount extends Model implements Sortable
*/
public function setPeriodAttribute($value)
{
$this->attributes['period'] = !$value && $this->otp_type === self::TOTP ? self::DEFAULT_PERIOD : $value;
$this->attributes['period'] = ! $value && $this->otp_type === self::TOTP ? self::DEFAULT_PERIOD : $value;
}
/**
* Set counter attribute
*
@ -294,19 +291,19 @@ class TwoFAccount extends Model implements Sortable
$this->attributes['counter'] = blank($value) && $this->otp_type === self::HOTP ? self::DEFAULT_COUNTER : $value;
}
/**
* Returns a One-Time Password with its parameters
*
* @return TotpDto|HotpDto
*
* @throws InvalidSecretException The secret is not a valid base32 encoded string
* @throws UndecipherableException The secret cannot be deciphered
* @throws UnsupportedOtpTypeException The defined OTP type is not supported
* @throws InvalidOtpParameterException One OTP parameter is invalid
* @return TotpDto|HotpDto
*/
public function getOTP()
{
Log::info(sprintf('OTP requested for TwoFAccount (%s)', $this->id ? 'id:'.$this->id: 'preview'));
Log::info(sprintf('OTP requested for TwoFAccount (%s)', $this->id ? 'id:' . $this->id : 'preview'));
// Early exit if the model has an undecipherable secret
if (strtolower($this->secret) === __('errors.indecipherable')) {
@ -318,8 +315,7 @@ class TwoFAccount extends Model implements Sortable
$this->initGenerator();
try {
if ( $this->otp_type === self::HOTP ) {
if ($this->otp_type === self::HOTP) {
$OtpDto = new HotpDto();
$OtpDto->otp_type = $this->otp_type;
$counter = $this->generator->getParameter('counter');
@ -330,9 +326,7 @@ class TwoFAccount extends Model implements Sortable
if ($this->id) {
$this->save();
}
}
else {
} else {
$OtpDto = new TotpDto();
$OtpDto->otp_type = $this->otp_type;
$OtpDto->generated_at = time();
@ -342,12 +336,10 @@ class TwoFAccount extends Model implements Sortable
$OtpDto->period = $this->period;
}
Log::info(sprintf('New OTP generated for TwoFAccount (%s)', $this->id ? 'id:'.$this->id: 'preview'));
Log::info(sprintf('New OTP generated for TwoFAccount (%s)', $this->id ? 'id:' . $this->id : 'preview'));
return $OtpDto;
}
catch (\Exception|\Throwable $ex) {
} catch (\Exception|\Throwable $ex) {
Log::error('An error occured, OTP generation aborted');
// Currently a secret issue is the only possible exception thrown by OTPHP for this stack
// so it is Ok to send the corresponding 2FAuth exception.
@ -356,7 +348,6 @@ class TwoFAccount extends Model implements Sortable
}
}
/**
* Fill the model using an array of OTP parameters.
* Missing parameters will be set with default values
@ -385,11 +376,11 @@ class TwoFAccount extends Model implements Sortable
$this->enforceAsSteam();
}
if (!$this->icon && $skipIconFetching) {
if (! $this->icon && $skipIconFetching) {
$this->icon = $this->getDefaultIcon();
}
if (!$this->icon && Settings::get('getOfficialIcons') && !$skipIconFetching) {
if (! $this->icon && Settings::get('getOfficialIcons') && ! $skipIconFetching) {
$this->icon = $this->getDefaultIcon();
}
@ -398,7 +389,6 @@ class TwoFAccount extends Model implements Sortable
return $this;
}
/**
* Fill the model by parsing an otpauth URI
*
@ -409,20 +399,19 @@ class TwoFAccount extends Model implements Sortable
// First we instanciate the OTP generator
try {
$this->generator = Factory::loadFromProvisioningUri($uri);
}
catch (\Assert\AssertionFailedException|\Assert\InvalidArgumentException|\Exception|\Throwable $ex) {
} catch (\Assert\AssertionFailedException|\Assert\InvalidArgumentException|\Exception|\Throwable $ex) {
throw ValidationException::withMessages([
'uri' => __('validation.custom.uri.regex', ['attribute' => 'uri'])
'uri' => __('validation.custom.uri.regex', ['attribute' => 'uri']),
]);
}
// As loadFromProvisioningUri() accept URI without label (nor account nor service) we check
// that the account is set
if ( ! $this->generator->getLabel() ) {
if (! $this->generator->getLabel()) {
Log::error('URI passed to fillWithURI() must contain a label');
throw ValidationException::withMessages([
'label' => __('validation.custom.label.required')
'label' => __('validation.custom.label.required'),
]);
}
@ -443,7 +432,7 @@ class TwoFAccount extends Model implements Sortable
$this->icon = $this->storeImageAsIcon($this->generator->getParameter('image'));
}
if (!$this->icon && Settings::get('getOfficialIcons') && !$skipIconFetching) {
if (! $this->icon && Settings::get('getOfficialIcons') && ! $skipIconFetching) {
$this->icon = $this->getDefaultIcon();
}
@ -452,7 +441,6 @@ class TwoFAccount extends Model implements Sortable
return $this;
}
/**
* Sets model attributes to STEAM values
*/
@ -466,7 +454,6 @@ class TwoFAccount extends Model implements Sortable
Log::info(sprintf('TwoFAccount configured as Steam account'));
}
/**
* Returns the OTP type of the instanciated OTP generator
*
@ -477,7 +464,6 @@ class TwoFAccount extends Model implements Sortable
return Arr::get($this->generatorClassMap, get_class($this->generator));
}
/**
* Returns an otpauth URI built with model attribute values
*/
@ -488,9 +474,9 @@ class TwoFAccount extends Model implements Sortable
return $this->generator->getProvisioningUri();
}
/**
* Instanciates the OTP generator with model attribute values
*
* @throws UnsupportedOtpTypeException The defined OTP type is not supported
* @throws InvalidOtpParameterException One OTP parameter is invalid
*/
@ -524,14 +510,16 @@ class TwoFAccount extends Model implements Sortable
throw new UnsupportedOtpTypeException();
}
if ($this->service) $this->generator->setIssuer($this->service);
if ($this->account) $this->generator->setLabel($this->account);
if ($this->service) {
$this->generator->setIssuer($this->service);
}
catch (UnsupportedOtpTypeException $exception) {
if ($this->account) {
$this->generator->setLabel($this->account);
}
} catch (UnsupportedOtpTypeException $exception) {
Log::error(sprintf('%s is not an OTP type supported by the current generator', $this->otp_type));
throw $exception;
}
catch (\Exception|\Throwable $exception) {
} catch (\Exception|\Throwable $exception) {
throw new InvalidOtpParameterException($exception->getMessage());
}
}
@ -545,7 +533,7 @@ class TwoFAccount extends Model implements Sortable
{
try {
$path_parts = pathinfo($url);
$newFilename = Helpers::getUniqueFilename($path_parts['extension']); //Str::random(40).'.'.$path_parts['extension'];
$newFilename = Helpers::getUniqueFilename($path_parts['extension']);
$imageFile = self::IMAGELINK_STORAGE_PATH . $newFilename;
try {
@ -554,22 +542,19 @@ class TwoFAccount extends Model implements Sortable
if ($response->successful()) {
Storage::disk('imagesLink')->put($newFilename, $response->body());
}
}
catch (\Exception $exception) {
} catch (\Exception $exception) {
Log::error(sprintf('Cannot fetch imageLink at "%s"', $url));
}
if ( in_array(Storage::mimeType($imageFile), ['image/png', 'image/jpeg', 'image/webp', 'image/bmp'])
&& getimagesize(storage_path() . '/app/' . $imageFile) )
{
if (in_array(Storage::mimeType($imageFile), ['image/png', 'image/jpeg', 'image/webp', 'image/bmp'])
&& getimagesize(storage_path() . '/app/' . $imageFile)) {
// Should be a valid image, we move it to the icons disk
if (Storage::disk('icons')->put($newFilename, Storage::disk('imagesLink')->get($newFilename))) {
Storage::disk('imagesLink')->delete($newFilename);
}
Log::info(sprintf('Icon file %s stored', $newFilename));
}
else {
} else {
// @codeCoverageIgnoreStart
Storage::disk('imagesLink')->delete($newFilename);
throw new \Exception('Unsupported mimeType or missing image on storage');
@ -581,12 +566,12 @@ class TwoFAccount extends Model implements Sortable
// @codeCoverageIgnoreStart
catch (\Exception|\Throwable $ex) {
Log::error(sprintf('Icon storage failed: %s', $ex->getMessage()));
return null;
}
// @codeCoverageIgnoreEnd
}
/**
* Fetch a logo in the tfa directory and store it as a new stand alone icon
*
@ -599,28 +584,23 @@ class TwoFAccount extends Model implements Sortable
return Settings::get('getOfficialIcons') ? $logoService->getIcon($this->service) : null;
}
/**
* Returns an acceptable value
*/
private function decryptOrReturn(mixed $value) : mixed
{
// Decipher when needed
if ( Settings::get('useEncryption') && $value )
{
if (Settings::get('useEncryption') && $value) {
try {
return Crypt::decryptString($value);
}
catch (Exception $ex) {
} catch (Exception $ex) {
return __('errors.indecipherable');
}
}
else {
} else {
return $value;
}
}
/**
* Encrypt a value
*/
@ -629,5 +609,4 @@ class TwoFAccount extends Model implements Sortable
// should be replaced by laravel 8 attribute encryption casting
return Settings::get('useEncryption') ? Crypt::encryptString($value) : $value;
}
}

@ -2,14 +2,14 @@
namespace App\Models;
use Illuminate\Auth\Notifications\ResetPassword;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Laravel\Passport\HasApiTokens;
use Illuminate\Support\Facades\Log;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Laragear\WebAuthn\WebAuthnAuthentication;
use App\Models\Traits\WebAuthnManageCredentials;
use Illuminate\Auth\Notifications\ResetPassword;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\Log;
use Laragear\WebAuthn\WebAuthnAuthentication;
use Laravel\Passport\HasApiTokens;
class User extends Authenticatable implements WebAuthnAuthenticatable
{
@ -59,6 +59,7 @@ class User extends Authenticatable implements WebAuthnAuthenticatable
/**
* set Email attribute
*
* @param string $value
*/
public function setEmailAttribute($value) : void
@ -66,14 +67,13 @@ class User extends Authenticatable implements WebAuthnAuthenticatable
$this->attributes['email'] = strtolower($value);
}
/**
* Returns an WebAuthnAuthenticatable user from a given Credential ID.
*
* @param string $id
* @return WebAuthnAuthenticatable|null
*/
public static function getFromCredentialId(string $id): ?WebAuthnAuthenticatable
public static function getFromCredentialId(string $id) : ?WebAuthnAuthenticatable
{
return static::whereHas(
'webauthnCredentials',

@ -11,8 +11,7 @@ interface WebAuthnAuthenticatable extends Authenticatable
*
* @return string
*/
public function userHandle(): string;
public function userHandle() : string;
/**
* Saves a new alias for a given WebAuthn credential.
@ -21,8 +20,7 @@ interface WebAuthnAuthenticatable extends Authenticatable
* @param string $alias
* @return bool
*/
public function renameCredential(string $id, string $alias): bool;
public function renameCredential(string $id, string $alias) : bool;
/**
* Removes one or more credentials previously registered.
@ -30,8 +28,7 @@ interface WebAuthnAuthenticatable extends Authenticatable
* @param string|array $id
* @return void
*/
public function flushCredential($id): void;
public function flushCredential($id) : void;
/**
* Sends a webauthn recovery email to the user.
@ -39,5 +36,5 @@ interface WebAuthnAuthenticatable extends Authenticatable
* @param string $token
* @return void
*/
public function sendWebauthnRecoveryNotification(string $token): void;
public function sendWebauthnRecoveryNotification(string $token) : void;
}

@ -2,15 +2,14 @@
namespace App\Providers;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\ServiceProvider;
use Illuminate\Http\Resources\Json\JsonResource;
use Laravel\Passport\Console\ClientCommand;
use Laravel\Passport\Console\InstallCommand;
use Laravel\Passport\Console\KeysCommand;
class AppServiceProvider extends ServiceProvider
{
/**

@ -2,16 +2,15 @@
namespace App\Providers;
use App\Extensions\RemoteUserProvider;
use App\Extensions\WebauthnCredentialBroker;
use App\Facades\Settings;
use App\Services\Auth\ReverseProxyGuard;
use Illuminate\Auth\Passwords\DatabaseTokenRepository;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Auth;
use App\Services\Auth\ReverseProxyGuard;
use App\Extensions\RemoteUserProvider;
use App\Facades\Settings;
use Illuminate\Support\Facades\Config;
use RuntimeException;
use App\Extensions\WebauthnCredentialBroker;
use Illuminate\Auth\Passwords\DatabaseTokenRepository;
use Illuminate\Support\Str;
use RuntimeException;
class AuthServiceProvider extends ServiceProvider
{
@ -24,20 +23,19 @@ class AuthServiceProvider extends ServiceProvider
// 'App\Models\Model' => 'App\Policies\ModelPolicy',
];
/**
* Register the service provider.
*
* @return void
*
* @throws \Illuminate\Contracts\Container\BindingResolutionException
*/
public function register(): void
public function register() : void
{
$this->app->singleton(
WebauthnCredentialBroker::class,
static function ($app) {
if (!$config = $app['config']['auth.passwords.webauthn']) {
if (! $config = $app['config']['auth.passwords.webauthn']) {
throw new RuntimeException('You must set the [webauthn] key broker in [auth] config.');
}
@ -62,7 +60,6 @@ class AuthServiceProvider extends ServiceProvider
);
}
/**
* Register any authentication / authorization services.
*
@ -86,7 +83,6 @@ class AuthServiceProvider extends ServiceProvider
return new ReverseProxyGuard(Auth::createUserProvider($config['provider']));
});
// Previously we were using a custom user provider derived from the Larapass user provider
// in order to honor the "useWebauthnOnly" user option.
// Since Laragear\WebAuthn now replaces DarkGhostHunter\Larapass, the new approach is
@ -94,7 +90,7 @@ class AuthServiceProvider extends ServiceProvider
// with a custom closure that uses the "useWebauthnOnly" user option
Auth::provider(
'eloquent-webauthn',
static function (\Illuminate\Contracts\Foundation\Application $app, array $config): \Laragear\WebAuthn\Auth\WebAuthnUserProvider {
static function (\Illuminate\Contracts\Foundation\Application $app, array $config) : \Laragear\WebAuthn\Auth\WebAuthnUserProvider {
return new \Laragear\WebAuthn\Auth\WebAuthnUserProvider(
$app->make('hash'),
$config['model'],
@ -104,7 +100,6 @@ class AuthServiceProvider extends ServiceProvider
}
);
// Normally we should set the Passport routes here using Passport::routes().
// If so the passport routes would be set for both 'web' and 'api' middlewares without
// possibility to exclude the web middleware (we can only pass additional middlewares to Passport::routes())

@ -2,8 +2,8 @@
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Broadcast;
use Illuminate\Support\ServiceProvider;
class BroadcastServiceProvider extends ServiceProvider
{

@ -3,11 +3,11 @@
namespace App\Providers;
use App\Events\GroupDeleting;
use App\Events\TwoFAccountDeleted;
use App\Events\ScanForNewReleaseCalled;
use App\Listeners\ReleaseRadar;
use App\Events\TwoFAccountDeleted;
use App\Listeners\CleanIconStorage;
use App\Listeners\DissociateTwofaccountFromGroup;
use App\Listeners\ReleaseRadar;
use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;

@ -4,8 +4,8 @@ namespace App\Providers;
use App\Factories\MigratorFactory;
use App\Factories\MigratorFactoryInterface;
use App\Services\Migrators\GoogleAuthMigrator;
use App\Services\Migrators\AegisMigrator;
use App\Services\Migrators\GoogleAuthMigrator;
use App\Services\Migrators\PlainTextMigrator;
use App\Services\Migrators\TwoFASMigrator;
use Illuminate\Support\ServiceProvider;

@ -2,13 +2,13 @@
namespace App\Providers;
use App\Services\LogoService;
use App\Services\SettingService;
use App\Services\ReleaseRadarService;
use App\Services\TwoFAccountService;
use App\Factories\MigratorFactoryInterface;
use Illuminate\Support\ServiceProvider;
use App\Services\LogoService;
use App\Services\ReleaseRadarService;
use App\Services\SettingService;
use App\Services\TwoFAccountService;
use Illuminate\Contracts\Support\DeferrableProvider;
use Illuminate\Support\ServiceProvider;
class TwoFAuthServiceProvider extends ServiceProvider implements DeferrableProvider
{
@ -46,7 +46,6 @@ class TwoFAuthServiceProvider extends ServiceProvider implements DeferrableProvi
//
}
/**
* Get the services provided by the provider.
*

@ -30,12 +30,14 @@ class CaseInsensitiveEmailExists implements Rule
->whereRaw('email = \'' . strtolower($value) . '\'' . ('sqlite' === config('database.default') ? ' COLLATE NOCASE' : ''))
->first();
return !$user ? false : true;
return ! $user ? false : true;
}
/**
* Get the validation error message.
*
* @codeCoverageIgnore
*
* @return array|string
*/
public function message()

@ -5,9 +5,9 @@
namespace App\Services\Auth;
use Illuminate\Auth\GuardHelpers;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Contracts\Auth\UserProvider;
use Illuminate\Auth\GuardHelpers;
use Illuminate\Support\Facades\Log;
class ReverseProxyGuard implements Guard
@ -33,7 +33,7 @@ class ReverseProxyGuard implements Guard
}
/**
* @inheritDoc
* {@inheritDoc}
*/
public function user()
{
@ -47,17 +47,17 @@ class ReverseProxyGuard implements Guard
// Get the user identifier from $_SERVER or apache filtered headers
$remoteUserHeader = config('auth.auth_proxy_headers.user');
$remoteUserHeader = $remoteUserHeader ?: 'REMOTE_USER';
$identifier = array();
$identifier = [];
try {
$identifier['user'] = request()->server($remoteUserHeader) ?? apache_request_headers()[$remoteUserHeader] ?? null;
}
catch (\Throwable $e) {
} catch (\Throwable $e) {
$identifier['user'] = null;
}
if (!$identifier['user'] || is_array($identifier['user'])) {
if (! $identifier['user'] || is_array($identifier['user'])) {
Log::error(sprintf('Proxy remote-user header "%s" is empty or missing.', $remoteUserHeader));
return $this->user = null;
}
@ -66,9 +66,8 @@ class ReverseProxyGuard implements Guard
if ($remoteEmailHeader) {
try {
$remoteEmail = (string)(request()->server($remoteEmailHeader) ?? apache_request_headers()[$remoteEmailHeader] ?? null);
}
catch (\Throwable $e) {
$remoteEmail = (string) (request()->server($remoteEmailHeader) ?? apache_request_headers()[$remoteEmailHeader] ?? null);
} catch (\Throwable $e) {
$remoteEmail = null;
}

@ -2,12 +2,11 @@
namespace App\Services;
use App\Facades\Settings;
use App\Models\Group;
use App\Models\TwoFAccount;
use App\Facades\Settings;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\App;
class GroupService
{
@ -29,7 +28,7 @@ class GroupService
// Create the pseudo group
$allGroup = new Group([
'name' => __('commons.all')
'name' => __('commons.all'),
]);
$allGroup->id = 0;
@ -38,7 +37,6 @@ class GroupService
return $groups->prepend($allGroup);
}
/**
* Creates a group
*
@ -58,7 +56,6 @@ class GroupService
return $group;
}
/**
* Updates a group using a list of parameters
*
@ -77,7 +74,6 @@ class GroupService
return $group;
}
/**
* Deletes one or more groups
*
@ -112,7 +108,6 @@ class GroupService
return $deleted;
}
/**
* Assign one or more accounts to a group
*
@ -122,15 +117,15 @@ class GroupService
*/
public static function assign($ids, Group $group = null) : void
{
if (!$group) {
if (! $group) {
$group = self::defaultGroup();
}
if ($group) {
// saveMany() expect an iterable so we pass an array to
// find() to always obtain a list of TwoFAccount
if (!is_array($ids)) {
$ids = array($ids);
if (! is_array($ids)) {
$ids = [$ids];
}
$twofaccounts = TwoFAccount::find($ids);
@ -138,11 +133,11 @@ class GroupService
$group->loadCount('twofaccounts');
Log::info(sprintf('Twofaccounts #%s assigned to groups %s', implode(',#', $ids), var_export($group->name, true)));
} else {
Log::info('Cannot find a group to assign the TwoFAccounts to');
}
else Log::info('Cannot find a group to assign the TwoFAccounts to');
}
/**
* Finds twofaccounts assigned to the group
*
@ -156,7 +151,6 @@ class GroupService
return $twofaccounts;
}
/**
* Determines the destination group
*

@ -4,8 +4,8 @@ namespace App\Services;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
class LogoService
@ -25,13 +25,11 @@ class LogoService
*/
const TFA_URL = 'https://2fa.directory/api/v3/tfa.json';
public function __construct()
{
$this->setTfaCollection();
}
/**
* Fetch a logo for the given service and save it as an icon
*
@ -43,12 +41,13 @@ class LogoService
$logoFilename = $this->getLogo(strval($serviceName));
if ($logoFilename) {
$iconFilename = Str::random(40).'.svg';
return $this->copyToIcons($logoFilename, $iconFilename) ? $iconFilename : null;
}
else return null;
}
$iconFilename = Str::random(40) . '.svg';
return $this->copyToIcons($logoFilename, $iconFilename) ? $iconFilename : null;
} else {
return null;
}
}
/**
* Return the logo's filename for a given service
@ -59,16 +58,15 @@ class LogoService
protected function getLogo($serviceName)
{
$domain = $this->tfas->get($this->cleanDomain(strval($serviceName)));
$logoFilename = $domain.'.svg';
$logoFilename = $domain . '.svg';
if ($domain && !Storage::disk('logos')->exists($logoFilename)) {
if ($domain && ! Storage::disk('logos')->exists($logoFilename)) {
$this->fetchLogo($logoFilename);
}
return Storage::disk('logos')->exists($logoFilename) ? $logoFilename : null;
}
/**
* Build and set the TFA directoy collection
*
@ -90,7 +88,6 @@ class LogoService
: collect([]);
}
/**
* Fetch and cache fresh TFA.Directory data using the https://2fa.directory API
*
@ -104,22 +101,18 @@ class LogoService
$coll = collect(json_decode(htmlspecialchars_decode($response->body()), true)) /** @phpstan-ignore-line */
->mapWithKeys(function ($item, $key) {
return [
strtolower(head($item)) => $item[1]["domain"]
strtolower(head($item)) => $item[1]['domain'],
];
});
Storage::disk('logos')->put(self::TFA_JSON, $coll->toJson())
? Log::info('Fresh tfa.json saved to logos dir')
: Log::notice('Cannot save tfa.json to logos dir');
}
catch (\Exception $e) {
} catch (\Exception $e) {
Log::error('Caching of tfa.json failed');
}
}
/**
* Fetch and cache a logo from 2fa.Directory repository
*
@ -130,20 +123,18 @@ class LogoService
{
try {
$response = Http::retry(3, 100)
->get('https://raw.githubusercontent.com/2factorauth/twofactorauth/master/img/'.$logoFile[0].'/'.$logoFile);
->get('https://raw.githubusercontent.com/2factorauth/twofactorauth/master/img/' . $logoFile[0] . '/' . $logoFile);
if ($response->successful()) {
Storage::disk('logos')->put($logoFile, $response->body())
? Log::info(sprintf('Logo "%s" saved to logos dir.', $logoFile))
: Log::notice(sprintf('Cannot save logo "%s" to logos dir', $logoFile));
}
}
catch (\Exception $exception) {
} catch (\Exception $exception) {
Log::error(sprintf('Fetching of logo "%s" failed.', $logoFile));
}
}
/**
* Prepare and make some replacement to optimize logo fetching
*
@ -155,7 +146,6 @@ class LogoService
return strtolower(str_replace(['+'], ['plus'], $domain));
}
/**
* Copy a logo file to the icons disk with a new name
*

@ -2,15 +2,14 @@
namespace App\Services\Migrators;
use App\Services\Migrators\Migrator;
use Illuminate\Support\Collection;
use App\Models\TwoFAccount;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Arr;
use App\Exceptions\InvalidMigrationDataException;
use Illuminate\Support\Facades\Storage;
use App\Helpers\Helpers;
use App\Facades\TwoFAccounts;
use App\Helpers\Helpers;
use App\Models\TwoFAccount;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
class AegisMigrator extends Migrator
{
@ -33,7 +32,6 @@ class AegisMigrator extends Migrator
// }
// }
/**
* Convert migration data to a TwoFAccounts collection.
*
@ -49,11 +47,10 @@ class AegisMigrator extends Migrator
throw new InvalidMigrationDataException('Aegis');
}
$twofaccounts = array();
$twofaccounts = [];
foreach ($json['db']['entries'] as $key => $otp_parameters) {
$parameters = array();
$parameters = [];
$parameters['otp_type'] = $otp_parameters['type'] == 'steam' ? TwoFAccount::STEAM_TOTP : $otp_parameters['type'];
$parameters['service'] = $otp_parameters['issuer'];
$parameters['account'] = $otp_parameters['name'];
@ -92,17 +89,14 @@ class AegisMigrator extends Migrator
Log::info(sprintf('Image %s successfully stored for import', $filename));
}
}
}
catch (\Exception) {
} catch (\Exception) {
// we do nothing
}
try {
$twofaccounts[$key] = new TwoFAccount;
$twofaccounts[$key]->fillWithOtpParameters($parameters);
}
catch (\Exception $exception) {
} catch (\Exception $exception) {
Log::error(sprintf('Cannot instanciate a TwoFAccount object with OTP parameters from imported item #%s', $key));
Log::error($exception->getMessage());

@ -2,23 +2,21 @@
namespace App\Services\Migrators;
use Exception;
use App\Exceptions\InvalidMigrationDataException;
use App\Models\TwoFAccount;
use App\Services\Migrators\Migrator;
use Illuminate\Support\Collection;
use ParagonIE\ConstantTime\Base32;
use App\Protobuf\GAuthValueMapping;
use App\Protobuf\GoogleAuth\Payload;
use App\Protobuf\GoogleAuth\Payload\OtpType;
use App\Protobuf\GoogleAuth\Payload\Algorithm;
use App\Protobuf\GoogleAuth\Payload\DigitCount;
use App\Exceptions\InvalidMigrationDataException;
use App\Protobuf\GoogleAuth\Payload\OtpType;
use Exception;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use ParagonIE\ConstantTime\Base32;
class GoogleAuthMigrator extends Migrator
{
/**
* Convert Google Authenticator migration URI to a set of TwoFAccount objects.
*
@ -32,23 +30,21 @@ class GoogleAuthMigrator extends Migrator
$protobuf = new Payload();
$protobuf->mergeFromString($migrationData);
$otpParameters = $protobuf->getOtpParameters();
}
catch (Exception $ex) {
Log::error("Protobuf failed to get OTP parameters from provided migration URI");
} catch (Exception $ex) {
Log::error('Protobuf failed to get OTP parameters from provided migration URI');
Log::error($ex->getMessage());
throw new InvalidMigrationDataException('Google Authenticator');
}
$twofaccounts = array();
$twofaccounts = [];
foreach ($otpParameters->getIterator() as $key => $otp_parameters) {
try {
$parameters = array();
$parameters = [];
$parameters['otp_type'] = GAuthValueMapping::OTP_TYPE[OtpType::name($otp_parameters->getType())];
$parameters['service'] = $otp_parameters->getIssuer();
$parameters['account'] = str_replace($parameters['service'].':', '', $otp_parameters->getName());
$parameters['account'] = str_replace($parameters['service'] . ':', '', $otp_parameters->getName());
$parameters['secret'] = Base32::encodeUpper($otp_parameters->getSecret());
$parameters['algorithm'] = GAuthValueMapping::ALGORITHM[Algorithm::name($otp_parameters->getAlgorithm())];
$parameters['digits'] = GAuthValueMapping::DIGIT_COUNT[DigitCount::name($otp_parameters->getDigits())];
@ -57,9 +53,7 @@ class GoogleAuthMigrator extends Migrator
$twofaccounts[$key] = new TwoFAccount;
$twofaccounts[$key]->fillWithOtpParameters($parameters);
}
catch (Exception $exception) {
} catch (Exception $exception) {
Log::error(sprintf('Cannot instanciate a TwoFAccount object with OTP parameters from imported item #%s', $key));
Log::error($exception->getMessage());

@ -14,7 +14,6 @@ abstract class Migrator
*/
abstract public function migrate(mixed $migrationPayload) : Collection;
/**
* Pad a string to 8 chars min
*
@ -25,5 +24,4 @@ abstract class Migrator
{
return str_pad($string, 8, '=');
}
}

@ -2,17 +2,15 @@
namespace App\Services\Migrators;
use App\Services\Migrators\Migrator;
use Illuminate\Support\Collection;
use App\Models\TwoFAccount;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use App\Exceptions\InvalidMigrationDataException;
use App\Models\TwoFAccount;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
class PlainTextMigrator extends Migrator
{
/**
* Convert migration data to a TwoFAccounts collection.
*
@ -32,13 +30,10 @@ class PlainTextMigrator extends Migrator
}
foreach ($otpauthURIs as $key => $uri) {
try {
$twofaccounts[$key] = new TwoFAccount;
$twofaccounts[$key]->fillWithURI($uri);
}
catch (\Exception $exception) {
} catch (\Exception $exception) {
Log::error(sprintf('Cannot instanciate a TwoFAccount object with OTP parameters from imported item #%s', $key));
Log::error($exception->getMessage());

@ -2,12 +2,11 @@
namespace App\Services\Migrators;
use App\Services\Migrators\Migrator;
use Illuminate\Support\Collection;
use App\Models\TwoFAccount;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Arr;
use App\Exceptions\InvalidMigrationDataException;
use App\Models\TwoFAccount;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
class TwoFASMigrator extends Migrator
{
@ -65,7 +64,6 @@ class TwoFASMigrator extends Migrator
// "appVersionName": "3.20.1"
// }
/**
* Convert migration data to a TwoFAccounts collection.
*
@ -81,11 +79,10 @@ class TwoFASMigrator extends Migrator
throw new InvalidMigrationDataException('2FAS Auth');
}
$twofaccounts = array();
$twofaccounts = [];
foreach ($json['services'] as $key => $otp_parameters) {
$parameters = array();
$parameters = [];
$parameters['otp_type'] = $otp_parameters['otp']['tokenType'];
$parameters['service'] = $otp_parameters['name'];
$parameters['account'] = $otp_parameters['otp']['account'] ?? $parameters['service'];
@ -98,9 +95,7 @@ class TwoFASMigrator extends Migrator
try {
$twofaccounts[$key] = new TwoFAccount;
$twofaccounts[$key]->fillWithOtpParameters($parameters);
}
catch (\Exception $exception) {
} catch (\Exception $exception) {
Log::error(sprintf('Cannot instanciate a TwoFAccount object with 2FAS imported item #%s', $key));
Log::error($exception->getMessage());

@ -2,9 +2,10 @@
namespace App\Services;
use Zxing\QrReader;
use chillerlan\QRCode\QRCode;
use chillerlan\QRCode\QROptions;
use Illuminate\Support\Facades\Log;
use chillerlan\QRCode\{QRCode, QROptions};
use Zxing\QrReader;
class QrCodeService
{
@ -12,7 +13,6 @@ class QrCodeService
* Encode a string into a QR code image
*
* @param string $data The string to encode
*
* @return mixed
*/
public static function encode(string $data)
@ -29,7 +29,6 @@ class QrCodeService
return $qrcode->render($data);
}
/**
* Decode an uploaded QR code image
*
@ -41,7 +40,7 @@ class QrCodeService
$qrcode = new QrReader($file->get(), QrReader::SOURCE_TYPE_BLOB);
$data = urldecode($qrcode->text());
if(!$data) {
if (! $data) {
throw new \App\Exceptions\InvalidQrCodeException;
}

@ -21,7 +21,6 @@ class ReleaseRadarService
}
}
/**
* Run a manual release scan
*
@ -39,8 +38,7 @@ class ReleaseRadarService
*/
protected function newRelease() : false|string
{
if ($latestReleaseData = json_decode($this->getLatestReleaseData()))
{
if ($latestReleaseData = json_decode($this->getLatestReleaseData())) {
$githubVersion = Helpers::cleanVersionNumber($latestReleaseData->tag_name);
$installedVersion = Helpers::cleanVersionNumber(config('2fauth.version'));
@ -48,8 +46,7 @@ class ReleaseRadarService
Settings::set('latestRelease', $latestReleaseData->tag_name);
return $latestReleaseData->tag_name;
}
else {
} else {
Settings::delete('latestRelease');
}
@ -59,7 +56,6 @@ class ReleaseRadarService
return false;
}
/**
* Fetch releases on Github
*
@ -74,8 +70,7 @@ class ReleaseRadarService
if ($response->successful()) {
return $response->body();
}
}
catch (\Exception $exception) {
} catch (\Exception $exception) {
Log::error('cannot reach latestReleaseUrl endpoint');
}

@ -2,20 +2,19 @@
namespace App\Services;
use Throwable;
use Exception;
use App\Exceptions\DbEncryptionException;
use App\Models\Option;
use Exception;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\App;
use App\Exceptions\DbEncryptionException;
use Throwable;
class SettingService
{
/**
* All user settings
*
@ -23,7 +22,6 @@ class SettingService
*/
private Collection $settings;
/**
* Constructor
*/
@ -32,7 +30,6 @@ class SettingService
self::build();
}
/**
* Get a setting
*
@ -44,7 +41,6 @@ class SettingService
return $this->settings->get($setting);
}
/**
* Get all settings
*
@ -55,20 +51,18 @@ class SettingService
return $this->settings;
}
/**
* Set a setting
*
* @param string|array $setting A single setting name or an associative array of name:value settings
* @param string|int|boolean|null $value The value for single setting
* @param string|int|bool|null $value The value for single setting
*/
public function set($setting, $value = null) : void
{
$settings = is_array($setting) ? $setting : [$setting => $value];
foreach ($settings as $setting => $value) {
if( $setting === 'useEncryption')
{
if ($setting === 'useEncryption') {
$this->setEncryptionTo($value);
}
@ -83,7 +77,6 @@ class SettingService
self::build();
}
/**
* Delete a setting
*
@ -95,7 +88,6 @@ class SettingService
Log::info(sprintf('Setting %s deleted', var_export($name, true)));
}
/**
* Determine if the given setting has been customized by the user
*
@ -107,7 +99,6 @@ class SettingService
return DB::table('options')->where('key', $key)->exists();
}
/**
* Set the settings collection
*
@ -123,15 +114,13 @@ class SettingService
// Merge 2fauth/app config values as fallback values
$settings = collect(config('2fauth.options'))->merge($userOptions); /** @phpstan-ignore-line */
if(!Arr::has($settings, 'lang')) {
if (! Arr::has($settings, 'lang')) {
$settings['lang'] = 'browser';
}
$this->settings = $settings;
}
/**
* Replaces boolean by a patterned string as appstrack/laravel-options package does not support var type
*
@ -143,7 +132,6 @@ class SettingService
return is_bool($value) ? '{{' . $value . '}}' : $value;
}
/**
* Replaces patterned string that represent booleans with real booleans
*
@ -154,22 +142,20 @@ class SettingService
{
$value = is_numeric($value) ? (int) $value : $value;
if( $value === '{{}}' ) {
if ($value === '{{}}') {
return false;
}
else if( $value === '{{1}}' ) {
} elseif ($value === '{{1}}') {
return true;
}
else {
} else {
return $value;
}
}
/**
* Enable or Disable encryption of 2FAccounts sensible data
*
* @return void
*
* @throws DbEncryptionException Something failed, everything have been rolled back
*/
private function setEncryptionTo(bool $state) : void
@ -177,39 +163,37 @@ class SettingService
// We don't want the records to be encrypted/decrypted multiple successive times
$isInUse = $this->get('useEncryption');
if ($isInUse === !$state) {
if ($isInUse === ! $state) {
if ($this->updateRecords($state)) {
if ($state) {
Log::notice('Sensible data are now encrypted');
} else {
Log::notice('Sensible data are now decrypted');
}
else Log::notice('Sensible data are now decrypted');
}
else {
} else {
Log::warning('Some data cannot be encrypted/decrypted, the useEncryption setting remain unchanged');
throw new DbEncryptionException($state === true ? __('errors.error_during_encryption') : __('errors.error_during_decryption'));
}
}
}
/**
* Encrypt/Decrypt accounts in database
*
* @param boolean $encrypted Whether the record should be encrypted or not
* @return boolean Whether the operation completed successfully
* @param bool $encrypted Whether the record should be encrypted or not
* @return bool Whether the operation completed successfully
*/
private function updateRecords(bool $encrypted) : bool
{
$success = true;
$twofaccounts = DB::table('twofaccounts')->get();
$twofaccounts->each(function ($item, $key) use(&$success, $encrypted) {
$twofaccounts->each(function ($item, $key) use (&$success, $encrypted) {
try {
$item->legacy_uri = $encrypted ? Crypt::encryptString($item->legacy_uri) : Crypt::decryptString($item->legacy_uri);
$item->account = $encrypted ? Crypt::encryptString($item->account) : Crypt::decryptString($item->account);
$item->secret = $encrypted ? Crypt::encryptString($item->secret) : Crypt::decryptString($item->secret);
}
catch (Exception $ex) {
} catch (Exception $ex) {
$success = false;
// Exit the each iteration
return false;
@ -228,20 +212,23 @@ class SettingService
->update([
'legacy_uri' => $item->legacy_uri,
'account' => $item->account,
'secret' => $item->secret
'secret' => $item->secret,
]);
});
DB::commit();
return true;
}
// @codeCoverageIgnoreStart
catch (Throwable $ex) {
DB::rollBack();
return false;
}
// @codeCoverageIgnoreEnd
} else {
return false;
}
else return false;
}
}

@ -2,19 +2,18 @@
namespace App\Services;
use App\Models\TwoFAccount;
use App\Factories\MigratorFactoryInterface;
use Illuminate\Support\Facades\Log;
use App\Models\TwoFAccount;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
class TwoFAccountService
{
/**
* @var MigratorFactoryInterface $migratorFactory The Migration service
* @var MigratorFactoryInterface The Migration service
*/
protected $migratorFactory;
/**
* Constructor
*/
@ -23,7 +22,6 @@ class TwoFAccountService
$this->migratorFactory = $migratorFactory;
}
/**
* Withdraw one or more twofaccounts from their group
*
@ -40,13 +38,12 @@ class TwoFAccountService
TwoFAccount::whereIn('id', $ids)
->update(
['group_id' => NULL]
['group_id' => null]
);
Log::info(sprintf('TwoFAccounts #%s withdrawn', implode(',#', $ids)));
}
/**
* Convert a migration payload to a set of TwoFAccount objects
*
@ -61,7 +58,6 @@ class TwoFAccountService
return self::markAsDuplicate($twofaccounts);
}
/**
* Delete one or more twofaccounts
*
@ -73,13 +69,12 @@ class TwoFAccountService
// $ids as string could be a comma-separated list of ids
// so in this case we explode the string to an array
$ids = self::commaSeparatedToArray($ids);
Log::info(sprintf('Deletion of TwoFAccounts #%s requested', is_array($ids) ? implode(',#', $ids) : $ids ));
Log::info(sprintf('Deletion of TwoFAccounts #%s requested', is_array($ids) ? implode(',#', $ids) : $ids));
$deleted = TwoFAccount::destroy($ids);
return $deleted;
}
/**
* Return the given collection with items marked as Duplicates (using id=-1) if a similar record exists in database
*
@ -108,7 +103,6 @@ class TwoFAccountService
return $twofaccounts;
}
/**
* Explode a comma separated list of IDs to an array of IDs
*
@ -116,8 +110,7 @@ class TwoFAccountService
*/
private static function commaSeparatedToArray($ids) : mixed
{
if(is_string($ids))
{
if (is_string($ids)) {
$regex = "/^\d+(,{1}\d+)*$/";
if (preg_match($regex, $ids)) {
$ids = explode(',', $ids);

@ -1,3 +1,26 @@
{
"preset": "laravel"
"preset": "laravel",
"exclude": [
"app/Protobuf",
"bootstrap",
"config",
"database",
"public",
"resources"
],
"rules": {
"binary_operator_spaces": {
"default": "single_space",
"operators": {
"=>": "align_single_space_minimal",
"=": "align_single_space_minimal"
}
},
"concat_space": {
"spacing": "one"
},
"return_type_declaration": {
"space_before": "one"
}
}
}

@ -12,18 +12,16 @@ class UserControllerTest extends FeatureTestCase
*/
protected $user;
/**
* @test
*/
public function setUp(): void
public function setUp() : void
{
parent::setUp();
$this->user = User::factory()->create();
}
/**
* @test
*/
@ -39,7 +37,6 @@ class UserControllerTest extends FeatureTestCase
]);
}
/**
* @test
*/
@ -52,7 +49,6 @@ class UserControllerTest extends FeatureTestCase
]);
}
/**
* @test
*/
@ -69,5 +65,4 @@ class UserControllerTest extends FeatureTestCase
'email' => $this->user->email,
]);
}
}

@ -2,11 +2,10 @@
namespace Tests\Api\v1\Controllers;
use App\Models\User;
use App\Models\Group;
use Tests\FeatureTestCase;
use App\Models\TwoFAccount;
use App\Models\User;
use Tests\FeatureTestCase;
/**
* @covers \App\Api\v1\Controllers\GroupController
@ -19,18 +18,16 @@ class GroupControllerTest extends FeatureTestCase
*/
protected $user;
/**
* @test
*/
public function setUp(): void
public function setUp() : void
{
parent::setUp();
$this->user = User::factory()->create();
}
/**
* @test
*/
@ -47,7 +44,7 @@ class GroupControllerTest extends FeatureTestCase
'id',
'name',
'twofaccounts_count',
]
],
])
->assertJsonFragment([
'id' => 0,
@ -56,7 +53,6 @@ class GroupControllerTest extends FeatureTestCase
]);
}
/**
* @test
*/
@ -73,7 +69,6 @@ class GroupControllerTest extends FeatureTestCase
]);
}
/**
* @test
*/
@ -86,7 +81,6 @@ class GroupControllerTest extends FeatureTestCase
->assertStatus(422);
}
/**
* @test
*/
@ -105,7 +99,6 @@ class GroupControllerTest extends FeatureTestCase
]);
}
/**
* @test
*/
@ -115,11 +108,10 @@ class GroupControllerTest extends FeatureTestCase
->json('GET', '/api/v1/groups/1000')
->assertNotFound()
->assertJsonStructure([
'message'
'message',
]);
}
/**
* @test
*/
@ -138,7 +130,6 @@ class GroupControllerTest extends FeatureTestCase
]);
}
/**
* @test
*/
@ -150,11 +141,10 @@ class GroupControllerTest extends FeatureTestCase
])
->assertNotFound()
->assertJsonStructure([
'message'
'message',
]);
}
/**
* @test
*/
@ -169,7 +159,6 @@ class GroupControllerTest extends FeatureTestCase
->assertStatus(422);
}
/**
* @test
*/
@ -190,7 +179,6 @@ class GroupControllerTest extends FeatureTestCase
]);
}
/**
* @test
*/
@ -204,11 +192,10 @@ class GroupControllerTest extends FeatureTestCase
])
->assertNotFound()
->assertJsonStructure([
'message'
'message',
]);
}
/**
* @test
*/
@ -224,7 +211,6 @@ class GroupControllerTest extends FeatureTestCase
->assertStatus(422);
}
/**
* @test
*/
@ -252,12 +238,11 @@ class GroupControllerTest extends FeatureTestCase
'digits',
'algorithm',
'period',
'counter'
]
'counter',
],
]);
}
/**
* @test
*/
@ -286,12 +271,11 @@ class GroupControllerTest extends FeatureTestCase
'digits',
'algorithm',
'period',
'counter'
]
'counter',
],
]);
}
/**
* @test
*/
@ -301,11 +285,10 @@ class GroupControllerTest extends FeatureTestCase
->json('GET', '/api/v1/groups/1000/twofaccounts')
->assertNotFound()
->assertJsonStructure([
'message'
'message',
]);
}
/**
* test Group deletion via API
*
@ -320,7 +303,6 @@ class GroupControllerTest extends FeatureTestCase
->assertNoContent();
}
/**
* test Group deletion via API
*
@ -332,7 +314,7 @@ class GroupControllerTest extends FeatureTestCase
->json('DELETE', '/api/v1/groups/1000')
->assertNotFound()
->assertJsonStructure([
'message'
'message',
]);
}
}

@ -2,21 +2,17 @@
namespace Tests\Api\v1\Controllers;
use Illuminate\Http\UploadedFile;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Http\UploadedFile;
use Tests\FeatureTestCase;
use App\Models\TwoFAccount;
/**
* @covers \App\Api\v1\Controllers\IconController
*/
class IconControllerTest extends FeatureTestCase
{
use WithoutMiddleware;
/**
* @test
*/
@ -29,11 +25,10 @@ class IconControllerTest extends FeatureTestCase
])
->assertCreated()
->assertJsonStructure([
'filename'
'filename',
]);
}
/**
* @test
*/
@ -45,7 +40,6 @@ class IconControllerTest extends FeatureTestCase
->assertStatus(422);
}
/**
* @test
*/
@ -55,7 +49,6 @@ class IconControllerTest extends FeatureTestCase
->assertNoContent(204);
}
/**
* @test
*/
@ -63,7 +56,5 @@ class IconControllerTest extends FeatureTestCase
{
$response = $this->json('DELETE', '/api/v1/icons/null')
->assertNoContent(204);
}
}

@ -2,35 +2,31 @@
namespace Tests\Api\v1\Controllers;
use App\Models\User;
use Tests\FeatureTestCase;
use App\Models\TwoFAccount;
use App\Models\User;
use Tests\Classes\LocalFile;
use Tests\FeatureTestCase;
/**
* @covers \App\Api\v1\Controllers\QrCodeController
*/
class QrCodeControllerTest extends FeatureTestCase
{
/**
* @var \App\Models\User
*/
protected $user;
/**
* @test
*/
public function setUp(): void
public function setUp() : void
{
parent::setUp();
$this->user = User::factory()->create();
}
/**
* @test
*/
@ -57,7 +53,6 @@ class QrCodeControllerTest extends FeatureTestCase
$this->assertStringStartsWith('data:image/png;base64', $response->getData()->qrcode);
}
/**
* @test
*/
@ -67,11 +62,10 @@ class QrCodeControllerTest extends FeatureTestCase
->json('GET', '/api/v1/twofaccounts/1000/qrcode')
->assertNotFound()
->assertJsonStructure([
'message'
'message',
]);
}
/**
* @test
*/
@ -83,7 +77,7 @@ class QrCodeControllerTest extends FeatureTestCase
->actingAs($this->user, 'api-guard')
->json('POST', '/api/v1/qrcode/decode', [
'qrcode' => $file,
'inputFormat' => 'fileUpload'
'inputFormat' => 'fileUpload',
])
->assertOk()
->assertExactJson([
@ -91,7 +85,6 @@ class QrCodeControllerTest extends FeatureTestCase
]);
}
/**
* @test
*/
@ -104,7 +97,6 @@ class QrCodeControllerTest extends FeatureTestCase
->assertStatus(422);
}
/**
* @test
*/
@ -116,7 +108,7 @@ class QrCodeControllerTest extends FeatureTestCase
->actingAs($this->user, 'api-guard')
->json('POST', '/api/v1/qrcode/decode', [
'qrcode' => $file,
'inputFormat' => 'fileUpload'
'inputFormat' => 'fileUpload',
])
->assertStatus(400)
->assertJsonStructure([

@ -2,10 +2,9 @@
namespace Tests\Api\v1\Controllers;
use App\Facades\Settings;
use App\Models\User;
use Tests\FeatureTestCase;
use App\Facades\Settings;
/**
* @covers \App\Api\v1\Controllers\SettingController
@ -19,26 +18,31 @@ class SettingControllerTest extends FeatureTestCase
private const SETTING_JSON_STRUCTURE = [
'key',
'value'
'value',
];
private const TWOFAUTH_NATIVE_SETTING = 'showTokenAsDot';
private const TWOFAUTH_NATIVE_SETTING_DEFAULT_VALUE = false;
private const TWOFAUTH_NATIVE_SETTING_CHANGED_VALUE = true;
private const USER_DEFINED_SETTING = 'mySetting';
private const USER_DEFINED_SETTING_VALUE = 'mySetting';
private const USER_DEFINED_SETTING_CHANGED_VALUE = 'mySetting';
/**
* @test
*/
public function setUp(): void
public function setUp() : void
{
parent::setUp();
$this->user = User::factory()->create();
}
/**
* @test
*/
@ -48,11 +52,10 @@ class SettingControllerTest extends FeatureTestCase
->json('GET', '/api/v1/settings')
->assertOk()
->assertJsonStructure([
'*' => self::SETTING_JSON_STRUCTURE
'*' => self::SETTING_JSON_STRUCTURE,
]);
}
/**
* @test
*/
@ -67,7 +70,6 @@ class SettingControllerTest extends FeatureTestCase
]);
}
/**
* @test
*/
@ -84,7 +86,6 @@ class SettingControllerTest extends FeatureTestCase
]);
}
/**
* @test
*/
@ -101,7 +102,6 @@ class SettingControllerTest extends FeatureTestCase
]);
}
/**
* @test
*/
@ -112,7 +112,6 @@ class SettingControllerTest extends FeatureTestCase
->assertNotFound();
}
/**
* @test
*/
@ -130,7 +129,6 @@ class SettingControllerTest extends FeatureTestCase
]);
}
/**
* @test
*/
@ -144,7 +142,6 @@ class SettingControllerTest extends FeatureTestCase
->assertStatus(422);
}
/**
* @test
*/
@ -160,7 +157,6 @@ class SettingControllerTest extends FeatureTestCase
->assertStatus(422);
}
/**
* @test
*/
@ -177,7 +173,6 @@ class SettingControllerTest extends FeatureTestCase
]);
}
/**
* @test
*/
@ -196,7 +191,6 @@ class SettingControllerTest extends FeatureTestCase
]);
}
/**
* @test
*/
@ -213,7 +207,6 @@ class SettingControllerTest extends FeatureTestCase
]);
}
/**
* @test
*/
@ -226,7 +219,6 @@ class SettingControllerTest extends FeatureTestCase
->assertNoContent();
}
/**
* @test
*/
@ -241,7 +233,6 @@ class SettingControllerTest extends FeatureTestCase
]);
}
/**
* @test
*/
@ -251,6 +242,4 @@ class SettingControllerTest extends FeatureTestCase
->json('DELETE', '/api/v1/settings/' . self::USER_DEFINED_SETTING)
->assertNotFound();
}
}

@ -2,16 +2,15 @@
namespace Tests\Api\v1\Controllers;
use App\Models\User;
use App\Models\Group;
use App\Facades\Settings;
use Tests\FeatureTestCase;
use Tests\Classes\OtpTestData;
use App\Models\Group;
use App\Models\TwoFAccount;
use App\Models\User;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Tests\Classes\LocalFile;
use Tests\Classes\OtpTestData;
use Tests\FeatureTestCase;
/**
* @covers \App\Api\v1\Controllers\TwoFAccountController
@ -30,8 +29,6 @@ class TwoFAccountControllerTest extends FeatureTestCase
*/
protected $group;
private const VALID_RESOURCE_STRUCTURE_WITHOUT_SECRET = [
'id',
'group_id',
@ -42,8 +39,9 @@ class TwoFAccountControllerTest extends FeatureTestCase
'digits',
'algorithm',
'period',
'counter'
'counter',
];
private const VALID_RESOURCE_STRUCTURE_WITH_SECRET = [
'id',
'group_id',
@ -55,19 +53,22 @@ class TwoFAccountControllerTest extends FeatureTestCase
'digits',
'algorithm',
'period',
'counter'
'counter',
];
private const VALID_OTP_RESOURCE_STRUCTURE_FOR_TOTP = [
'generated_at',
'otp_type',
'password',
'period',
];
private const VALID_OTP_RESOURCE_STRUCTURE_FOR_HOTP = [
'otp_type',
'password',
'counter',
];
private const JSON_FRAGMENTS_FOR_CUSTOM_TOTP = [
'service' => OtpTestData::SERVICE,
'account' => OtpTestData::ACCOUNT,
@ -78,6 +79,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
'period' => OtpTestData::PERIOD_CUSTOM,
'counter' => null,
];
private const JSON_FRAGMENTS_FOR_DEFAULT_TOTP = [
'service' => null,
'account' => OtpTestData::ACCOUNT,
@ -88,6 +90,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
'period' => OtpTestData::PERIOD_DEFAULT,
'counter' => null,
];
private const JSON_FRAGMENTS_FOR_CUSTOM_HOTP = [
'service' => OtpTestData::SERVICE,
'account' => OtpTestData::ACCOUNT,
@ -98,6 +101,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
'period' => null,
'counter' => OtpTestData::COUNTER_CUSTOM,
];
private const JSON_FRAGMENTS_FOR_DEFAULT_HOTP = [
'service' => null,
'account' => OtpTestData::ACCOUNT,
@ -108,17 +112,17 @@ class TwoFAccountControllerTest extends FeatureTestCase
'period' => null,
'counter' => OtpTestData::COUNTER_DEFAULT,
];
private const ARRAY_OF_INVALID_PARAMETERS = [
'account' => null,
'otp_type' => 'totp',
'secret' => OtpTestData::SECRET,
];
/**
* @test
*/
public function setUp(): void
public function setUp() : void
{
parent::setUp();
@ -126,7 +130,6 @@ class TwoFAccountControllerTest extends FeatureTestCase
$this->group = Group::factory()->create();
}
/**
* @test
*
@ -137,15 +140,14 @@ class TwoFAccountControllerTest extends FeatureTestCase
TwoFAccount::factory()->count(3)->create();
$response = $this->actingAs($this->user, 'api-guard')
->json('GET', '/api/v1/twofaccounts'.$urlParameter)
->json('GET', '/api/v1/twofaccounts' . $urlParameter)
->assertOk()
->assertJsonCount(3, $key = null)
->assertJsonStructure([
'*' => $expected
'*' => $expected,
]);
}
/**
* Provide data for index tests
*/
@ -154,16 +156,15 @@ class TwoFAccountControllerTest extends FeatureTestCase
return [
'VALID_RESOURCE_STRUCTURE_WITHOUT_SECRET' => [
'',
self::VALID_RESOURCE_STRUCTURE_WITHOUT_SECRET
self::VALID_RESOURCE_STRUCTURE_WITHOUT_SECRET,
],
'VALID_RESOURCE_STRUCTURE_WITH_SECRET' => [
'?withSecret=1',
self::VALID_RESOURCE_STRUCTURE_WITH_SECRET
self::VALID_RESOURCE_STRUCTURE_WITH_SECRET,
],
];
}
/**
* @test
*/
@ -177,7 +178,6 @@ class TwoFAccountControllerTest extends FeatureTestCase
->assertJsonStructure(self::VALID_RESOURCE_STRUCTURE_WITH_SECRET);
}
/**
* @test
*/
@ -191,7 +191,6 @@ class TwoFAccountControllerTest extends FeatureTestCase
->assertJsonStructure(self::VALID_RESOURCE_STRUCTURE_WITHOUT_SECRET);
}
/**
* @test
*/
@ -217,7 +216,6 @@ class TwoFAccountControllerTest extends FeatureTestCase
// ]);
// }
/**
* @test
*/
@ -227,11 +225,10 @@ class TwoFAccountControllerTest extends FeatureTestCase
->json('GET', '/api/v1/twofaccounts/1000')
->assertNotFound()
->assertJsonStructure([
'message'
'message',
]);
}
/**
* @dataProvider accountCreationProvider
* @test
@ -248,7 +245,6 @@ class TwoFAccountControllerTest extends FeatureTestCase
->assertJsonFragment($expected);
}
/**
* @dataProvider accountCreationProvider
* @test
@ -265,7 +261,6 @@ class TwoFAccountControllerTest extends FeatureTestCase
->assertJsonFragment($expected);
}
/**
* Provide data for TwoFAccount store tests
*/
@ -276,46 +271,45 @@ class TwoFAccountControllerTest extends FeatureTestCase
[
'uri' => OtpTestData::TOTP_FULL_CUSTOM_URI,
],
self::JSON_FRAGMENTS_FOR_CUSTOM_TOTP
self::JSON_FRAGMENTS_FOR_CUSTOM_TOTP,
],
'TOTP_SHORT_URI' => [
[
'uri' => OtpTestData::TOTP_SHORT_URI,
],
self::JSON_FRAGMENTS_FOR_DEFAULT_TOTP
self::JSON_FRAGMENTS_FOR_DEFAULT_TOTP,
],
'ARRAY_OF_FULL_VALID_PARAMETERS_FOR_CUSTOM_TOTP' => [
OtpTestData::ARRAY_OF_FULL_VALID_PARAMETERS_FOR_CUSTOM_TOTP,
self::JSON_FRAGMENTS_FOR_CUSTOM_TOTP
self::JSON_FRAGMENTS_FOR_CUSTOM_TOTP,
],
'ARRAY_OF_MINIMUM_VALID_PARAMETERS_FOR_TOTP' => [
OtpTestData::ARRAY_OF_MINIMUM_VALID_PARAMETERS_FOR_TOTP,
self::JSON_FRAGMENTS_FOR_DEFAULT_TOTP
self::JSON_FRAGMENTS_FOR_DEFAULT_TOTP,
],
'HOTP_FULL_CUSTOM_URI' => [
[
'uri' => OtpTestData::HOTP_FULL_CUSTOM_URI,
],
self::JSON_FRAGMENTS_FOR_CUSTOM_HOTP
self::JSON_FRAGMENTS_FOR_CUSTOM_HOTP,
],
'HOTP_SHORT_URI' => [
[
'uri' => OtpTestData::HOTP_SHORT_URI,
],
self::JSON_FRAGMENTS_FOR_DEFAULT_HOTP
self::JSON_FRAGMENTS_FOR_DEFAULT_HOTP,
],
'ARRAY_OF_FULL_VALID_PARAMETERS_FOR_CUSTOM_HOTP' => [
OtpTestData::ARRAY_OF_FULL_VALID_PARAMETERS_FOR_CUSTOM_HOTP,
self::JSON_FRAGMENTS_FOR_CUSTOM_HOTP
self::JSON_FRAGMENTS_FOR_CUSTOM_HOTP,
],
'ARRAY_OF_MINIMUM_VALID_PARAMETERS_FOR_HOTP' => [
OtpTestData::ARRAY_OF_MINIMUM_VALID_PARAMETERS_FOR_HOTP,
self::JSON_FRAGMENTS_FOR_DEFAULT_HOTP
self::JSON_FRAGMENTS_FOR_DEFAULT_HOTP,
],
];
}
/**
* @test
*/
@ -328,7 +322,6 @@ class TwoFAccountControllerTest extends FeatureTestCase
->assertStatus(422);
}
/**
* @test
*/
@ -342,11 +335,10 @@ class TwoFAccountControllerTest extends FeatureTestCase
'uri' => OtpTestData::TOTP_SHORT_URI,
])
->assertJsonFragment([
'group_id' => $this->group->id
'group_id' => $this->group->id,
]);
}
/**
* @test
*/
@ -362,11 +354,10 @@ class TwoFAccountControllerTest extends FeatureTestCase
'uri' => OtpTestData::TOTP_SHORT_URI,
])
->assertJsonFragment([
'group_id' => $this->group->id
'group_id' => $this->group->id,
]);
}
/**
* @test
*/
@ -380,11 +371,10 @@ class TwoFAccountControllerTest extends FeatureTestCase
'uri' => OtpTestData::TOTP_SHORT_URI,
])
->assertJsonFragment([
'group_id' => null
'group_id' => null,
]);
}
/**
* @test
*/
@ -398,11 +388,10 @@ class TwoFAccountControllerTest extends FeatureTestCase
'uri' => OtpTestData::TOTP_SHORT_URI,
])
->assertJsonFragment([
'group_id' => null
'group_id' => null,
]);
}
/**
* @test
*/
@ -416,7 +405,6 @@ class TwoFAccountControllerTest extends FeatureTestCase
->assertJsonFragment(self::JSON_FRAGMENTS_FOR_CUSTOM_TOTP);
}
/**
* @test
*/
@ -430,7 +418,6 @@ class TwoFAccountControllerTest extends FeatureTestCase
->assertJsonFragment(self::JSON_FRAGMENTS_FOR_CUSTOM_HOTP);
}
/**
* @test
*/
@ -441,7 +428,6 @@ class TwoFAccountControllerTest extends FeatureTestCase
->assertNotFound();
}
/**
* @test
*/
@ -454,7 +440,6 @@ class TwoFAccountControllerTest extends FeatureTestCase
->assertStatus(422);
}
/**
* @test
*/
@ -476,7 +461,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
'digits' => OtpTestData::DIGITS_DEFAULT,
'algorithm' => OtpTestData::ALGORITHM_DEFAULT,
'period' => OtpTestData::PERIOD_DEFAULT,
'counter' => null
'counter' => null,
])
->assertJsonFragment([
'id' => 0,
@ -487,11 +472,10 @@ class TwoFAccountControllerTest extends FeatureTestCase
'digits' => OtpTestData::DIGITS_DEFAULT,
'algorithm' => OtpTestData::ALGORITHM_DEFAULT,
'period' => OtpTestData::PERIOD_DEFAULT,
'counter' => null
'counter' => null,
]);
}
/**
* @test
*/
@ -504,7 +488,6 @@ class TwoFAccountControllerTest extends FeatureTestCase
->assertStatus(422);
}
/**
* @test
*/
@ -534,7 +517,6 @@ class TwoFAccountControllerTest extends FeatureTestCase
]);
}
/**
* @test
*/
@ -546,11 +528,10 @@ class TwoFAccountControllerTest extends FeatureTestCase
])
->assertStatus(400)
->assertJsonStructure([
'message'
'message',
]);
}
/**
* @test
*/
@ -575,7 +556,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
'digits' => OtpTestData::DIGITS_DEFAULT,
'algorithm' => OtpTestData::ALGORITHM_DEFAULT,
'period' => OtpTestData::PERIOD_DEFAULT,
'counter' => null
'counter' => null,
])
->assertJsonFragment([
'id' => 0,
@ -586,7 +567,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
'digits' => OtpTestData::DIGITS_CUSTOM,
'algorithm' => OtpTestData::ALGORITHM_CUSTOM,
'period' => OtpTestData::PERIOD_CUSTOM,
'counter' => null
'counter' => null,
])
->assertJsonFragment([
'id' => 0,
@ -597,7 +578,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
'digits' => OtpTestData::DIGITS_DEFAULT,
'algorithm' => OtpTestData::ALGORITHM_DEFAULT,
'period' => null,
'counter' => OtpTestData::COUNTER_DEFAULT
'counter' => OtpTestData::COUNTER_DEFAULT,
])
->assertJsonFragment([
'id' => 0,
@ -619,11 +600,10 @@ class TwoFAccountControllerTest extends FeatureTestCase
'digits' => OtpTestData::DIGITS_STEAM,
'algorithm' => OtpTestData::ALGORITHM_DEFAULT,
'period' => OtpTestData::PERIOD_DEFAULT,
'counter' => null
'counter' => null,
]);
}
/**
* @test
*
@ -639,7 +619,6 @@ class TwoFAccountControllerTest extends FeatureTestCase
->assertStatus(400);
}
/**
* Provide invalid Aegis JSON files for import tests
*/
@ -647,15 +626,14 @@ class TwoFAccountControllerTest extends FeatureTestCase
{
return [
'validPlainTextFile' => [
LocalFile::fake()->encryptedAegisJsonFile()
LocalFile::fake()->encryptedAegisJsonFile(),
],
'validPlainTextFileWithNewLines' => [
LocalFile::fake()->invalidAegisJsonFile()
LocalFile::fake()->invalidAegisJsonFile(),
],
];
}
/**
* @test
*
@ -680,7 +658,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
'digits' => OtpTestData::DIGITS_CUSTOM,
'algorithm' => OtpTestData::ALGORITHM_CUSTOM,
'period' => OtpTestData::PERIOD_CUSTOM,
'counter' => null
'counter' => null,
])
->assertJsonFragment([
'id' => 0,
@ -691,7 +669,7 @@ class TwoFAccountControllerTest extends FeatureTestCase
'digits' => OtpTestData::DIGITS_CUSTOM,
'algorithm' => OtpTestData::ALGORITHM_CUSTOM,
'period' => null,
'counter' => OtpTestData::COUNTER_CUSTOM
'counter' => OtpTestData::COUNTER_CUSTOM,
])
->assertJsonFragment([
'id' => 0,
@ -702,11 +680,10 @@ class TwoFAccountControllerTest extends FeatureTestCase
'digits' => OtpTestData::DIGITS_STEAM,
'algorithm' => OtpTestData::ALGORITHM_DEFAULT,
'period' => OtpTestData::PERIOD_DEFAULT,
'counter' => null
'counter' => null,
]);
}
/**
* Provide valid Plain Text files for import tests
*/
@ -714,15 +691,14 @@ class TwoFAccountControllerTest extends FeatureTestCase
{
return [
'validPlainTextFile' => [
LocalFile::fake()->validPlainTextFile()
LocalFile::fake()->validPlainTextFile(),
],
'validPlainTextFileWithNewLines' => [
LocalFile::fake()->validPlainTextFileWithNewLines()
LocalFile::fake()->validPlainTextFileWithNewLines(),
],
];
}
/**
* @test
*
@ -730,7 +706,6 @@ class TwoFAccountControllerTest extends FeatureTestCase
*/
public function test_import_invalid_plain_text_file_returns_bad_request($file)
{
$response = $this->withHeaders(['Content-Type' => 'multipart/form-data'])
->actingAs($this->user, 'api-guard')
->json('POST', '/api/v1/twofaccounts/migration', [
@ -739,7 +714,6 @@ class TwoFAccountControllerTest extends FeatureTestCase
->assertStatus(400);
}
/**
* Provide invalid Plain Text files for import tests
*/
@ -747,21 +721,20 @@ class TwoFAccountControllerTest extends FeatureTestCase
{
return [
'validPlainTextFile' => [
LocalFile::fake()->invalidPlainTextFileEmpty()
LocalFile::fake()->invalidPlainTextFileEmpty(),
],
'validPlainTextFileWithNewLines' => [
LocalFile::fake()->invalidPlainTextFileNoUri()
LocalFile::fake()->invalidPlainTextFileNoUri(),
],
'validPlainTextFileWithNewLines' => [
LocalFile::fake()->invalidPlainTextFileWithInvalidUri()
LocalFile::fake()->invalidPlainTextFileWithInvalidUri(),
],
'validPlainTextFileWithNewLines' => [
LocalFile::fake()->invalidPlainTextFileWithInvalidLine()
LocalFile::fake()->invalidPlainTextFileWithInvalidLine(),
],
];
}
/**
* @test
*/
@ -771,14 +744,13 @@ class TwoFAccountControllerTest extends FeatureTestCase
$response = $this->actingAs($this->user, 'api-guard')
->json('POST', '/api/v1/twofaccounts/reorder', [
'orderedIds' => [3,2,1]])
'orderedIds' => [3, 2, 1], ])
->assertStatus(200)
->assertJsonStructure([
'message'
'message',
]);
}
/**
* @test
*/
@ -788,11 +760,10 @@ class TwoFAccountControllerTest extends FeatureTestCase
$response = $this->actingAs($this->user, 'api-guard')
->json('POST', '/api/v1/twofaccounts/reorder', [
'orderedIds' => '3,2,1'])
'orderedIds' => '3,2,1', ])
->assertStatus(422);
}
/**
* @test
*/
@ -806,7 +777,6 @@ class TwoFAccountControllerTest extends FeatureTestCase
->assertJsonFragment(self::JSON_FRAGMENTS_FOR_CUSTOM_TOTP);
}
/**
* @test
*/
@ -819,7 +789,6 @@ class TwoFAccountControllerTest extends FeatureTestCase
->assertStatus(422);
}
/**
* @test
*/
@ -831,11 +800,10 @@ class TwoFAccountControllerTest extends FeatureTestCase
])
->assertOk()
->assertJsonFragment([
'icon' => null
'icon' => null,
]);
}
/**
* @test
*/
@ -863,7 +831,6 @@ class TwoFAccountControllerTest extends FeatureTestCase
]);
}
/**
* @test
*/
@ -881,7 +848,6 @@ class TwoFAccountControllerTest extends FeatureTestCase
]);
}
/**
* @test
*/
@ -897,7 +863,6 @@ class TwoFAccountControllerTest extends FeatureTestCase
]);
}
/**
* @test
*/
@ -925,7 +890,6 @@ class TwoFAccountControllerTest extends FeatureTestCase
]);
}
/**
* @test
*/
@ -943,7 +907,6 @@ class TwoFAccountControllerTest extends FeatureTestCase
]);
}
/**
* @test
*/
@ -959,7 +922,6 @@ class TwoFAccountControllerTest extends FeatureTestCase
]);
}
/**
* @test
*/
@ -977,7 +939,6 @@ class TwoFAccountControllerTest extends FeatureTestCase
]);
}
/**
* @test
*/
@ -1001,7 +962,6 @@ class TwoFAccountControllerTest extends FeatureTestCase
]);
}
/**
* @test
*/
@ -1012,7 +972,6 @@ class TwoFAccountControllerTest extends FeatureTestCase
->assertNotFound();
}
/**
* @test
*/
@ -1025,7 +984,6 @@ class TwoFAccountControllerTest extends FeatureTestCase
->assertStatus(422);
}
/**
* @test
*/
@ -1036,7 +994,6 @@ class TwoFAccountControllerTest extends FeatureTestCase
->assertStatus(422);
}
/**
* @test
*/
@ -1048,11 +1005,10 @@ class TwoFAccountControllerTest extends FeatureTestCase
->json('GET', '/api/v1/twofaccounts/count')
->assertStatus(200)
->assertExactJson([
'count' => 3
'count' => 3,
]);
}
/**
* @test
*/
@ -1069,7 +1025,6 @@ class TwoFAccountControllerTest extends FeatureTestCase
]);
}
/**
* @test
*/
@ -1087,7 +1042,6 @@ class TwoFAccountControllerTest extends FeatureTestCase
]);
}
/**
* @test
*/
@ -1100,7 +1054,6 @@ class TwoFAccountControllerTest extends FeatureTestCase
->assertNoContent();
}
/**
* @test
*/
@ -1113,7 +1066,6 @@ class TwoFAccountControllerTest extends FeatureTestCase
->assertNotFound();
}
/**
* @test
*/
@ -1127,7 +1079,6 @@ class TwoFAccountControllerTest extends FeatureTestCase
->assertNoContent();
}
/**
* @test
*/
@ -1144,5 +1095,4 @@ class TwoFAccountControllerTest extends FeatureTestCase
'reason',
]);
}
}

@ -4,13 +4,12 @@ namespace Tests\Api\v1\Requests;
use App\Api\v1\Requests\GroupAssignRequest;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;
use Tests\TestCase;
class GroupAssignRequestTest extends TestCase
{
use WithoutMiddleware;
/**
@ -46,8 +45,8 @@ class GroupAssignRequestTest extends TestCase
return [
[[
'ids' => [
1, 2, 3
]
1, 2, 3,
],
]],
];
}
@ -70,22 +69,21 @@ class GroupAssignRequestTest extends TestCase
{
return [
[[
'ids' => null // required
'ids' => null, // required
]],
[[
'ids' => '1,2,3' // array
'ids' => '1,2,3', // array
]],
[[
'ids' => [
'a', 'b', 'c' // array of integers
]
'a', 'b', 'c', // array of integers
],
]],
[[
'ids' => [
true, false // array of integers
]
true, false, // array of integers
],
]],
];
}
}

@ -2,21 +2,17 @@
namespace Tests\Api\v1\Requests;
use App\Models\Group;
use App\Api\v1\Requests\GroupStoreRequest;
use App\Models\Group;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;
use Tests\FeatureTestCase;
class GroupStoreRequestTest extends FeatureTestCase
{
use WithoutMiddleware;
/**
*
*/
protected String $uniqueGroupName = 'MyGroup';
/**
@ -51,7 +47,7 @@ class GroupStoreRequestTest extends FeatureTestCase
{
return [
[[
'name' => 'validWord'
'name' => 'validWord',
]],
];
}
@ -80,21 +76,20 @@ class GroupStoreRequestTest extends FeatureTestCase
{
return [
[[
'name' => '' // required
'name' => '', // required
]],
[[
'name' => true // string
'name' => true, // string
]],
[[
'name' => 8 // string
'name' => 8, // string
]],
[[
'name' => 'mmmmmmoooooorrrrrreeeeeeettttttthhhhhhaaaaaaannnnnn32cccccchhhhhaaaaaarrrrrrsssssss' // max:32
'name' => 'mmmmmmoooooorrrrrreeeeeeettttttthhhhhhaaaaaaannnnnn32cccccchhhhhaaaaaarrrrrrsssssss', // max:32
]],
[[
'name' => $this->uniqueGroupName // unique
'name' => $this->uniqueGroupName, // unique
]],
];
}
}

@ -4,14 +4,13 @@ namespace Tests\Api\v1\Requests;
use App\Api\v1\Requests\QrCodeDecodeRequest;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;
use Tests\Classes\LocalFile;
use Tests\TestCase;
class QrCodeDecodeRequestTest extends TestCase
{
use WithoutMiddleware;
/**
@ -48,7 +47,7 @@ class QrCodeDecodeRequestTest extends TestCase
return [
[[
'qrcode' => $file
'qrcode' => $file,
]],
];
}
@ -71,18 +70,17 @@ class QrCodeDecodeRequestTest extends TestCase
{
return [
[[
'qrcode' => null // required
'qrcode' => null, // required
]],
[[
'qrcode' => true // image
'qrcode' => true, // image
]],
[[
'qrcode' => 8 // image
'qrcode' => 8, // image
]],
[[
'qrcode' => 'string' // image
'qrcode' => 'string', // image
]],
];
}
}

@ -3,20 +3,16 @@
namespace Tests\Api\v1\Requests;
use App\Api\v1\Requests\SettingStoreRequest;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Auth;
use Tests\FeatureTestCase;
use App\Facades\Settings;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;
use Tests\FeatureTestCase;
class SettingStoreRequestTest extends FeatureTestCase
{
use WithoutMiddleware;
/**
*
*/
protected String $uniqueKey = 'UniqueKey';
/**
@ -52,15 +48,15 @@ class SettingStoreRequestTest extends FeatureTestCase
return [
[[
'key' => 'MyKey',
'value' => true
'value' => true,
]],
[[
'key' => 'MyKey',
'value' => 'MyValue'
'value' => 'MyValue',
]],
[[
'key' => 'MyKey',
'value' => 10
'value' => 10,
]],
];
}
@ -86,25 +82,24 @@ class SettingStoreRequestTest extends FeatureTestCase
return [
[[
'key' => null, // required
'value' => ''
'value' => '',
]],
[[
'key' => 'my-key', // alpha
'value' => 'MyValue'
'value' => 'MyValue',
]],
[[
'key' => 10, // alpha
'value' => 'MyValue'
'value' => 'MyValue',
]],
[[
'key' => 'mmmmmmoooooorrrrrreeeeeeettttttthhhhhhaaaaaaannnnnn128cccccchhhhhaaaaaarrrrrraaaaaaaccccccttttttttteeeeeeeeerrrrrrrrsssssss', // max:128
'value' => 'MyValue'
'value' => 'MyValue',
]],
[[
'key' => $this->uniqueKey, // unique
'value' => 'MyValue'
'value' => 'MyValue',
]],
];
}
}

@ -4,13 +4,12 @@ namespace Tests\Api\v1\Requests;
use App\Api\v1\Requests\SettingUpdateRequest;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;
use Tests\TestCase;
class SettingUpdateRequestTest extends TestCase
{
use WithoutMiddleware;
/**
@ -45,13 +44,13 @@ class SettingUpdateRequestTest extends TestCase
{
return [
[[
'value' => true
'value' => true,
]],
[[
'value' => 'MyValue'
'value' => 'MyValue',
]],
[[
'value' => 10
'value' => 10,
]],
];
}
@ -74,12 +73,11 @@ class SettingUpdateRequestTest extends TestCase
{
return [
[[
'value' => '' // required
'value' => '', // required
]],
[[
'value' => null // required
'value' => null, // required
]],
];
}
}

@ -4,13 +4,12 @@ namespace Tests\Api\v1\Requests;
use App\Api\v1\Requests\TwoFAccountBatchRequest;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;
use Tests\TestCase;
class TwoFAccountBatchRequestTest extends TestCase
{
use WithoutMiddleware;
/**
@ -45,10 +44,10 @@ class TwoFAccountBatchRequestTest extends TestCase
{
return [
[[
'ids' => '1'
'ids' => '1',
]],
[[
'ids' => '1,2,5'
'ids' => '1,2,5',
]],
];
}
@ -71,42 +70,41 @@ class TwoFAccountBatchRequestTest extends TestCase
{
return [
[[
'ids' => '' // required
'ids' => '', // required
]],
[[
'ids' => null // required
'ids' => null, // required
]],
[[
'ids' => true // string
'ids' => true, // string
]],
[[
'ids' => 10 // string
'ids' => 10, // string
]],
[[
'ids' => 'notaCommaSeparatedList' // regex
'ids' => 'notaCommaSeparatedList', // regex
]],
[[
'ids' => 'a,b' // regex
'ids' => 'a,b', // regex
]],
[[
'ids' => 'a,1' // regex
'ids' => 'a,1', // regex
]],
[[
'ids' => ',1,2' // regex
'ids' => ',1,2', // regex
]],
[[
'ids' => '1,,2' // regex
'ids' => '1,,2', // regex
]],
[[
'ids' => '1,2,' // regex
'ids' => '1,2,', // regex
]],
[[
'ids' => ',1,2,' // regex
'ids' => ',1,2,', // regex
]],
[[
'ids' => '1;2' // regex
'ids' => '1;2', // regex
]],
];
}
}

@ -3,16 +3,14 @@
namespace Tests\Api\v1\Requests;
use App\Api\v1\Requests\TwoFAccountDynamicRequest;
use App\Api\v1\Requests\TwoFAccountUriRequest;
use App\Api\v1\Requests\TwoFAccountStoreRequest;
use App\Api\v1\Requests\TwoFAccountUriRequest;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Auth;
use Tests\TestCase;
class TwoFAccountDynamicRequestTest extends TestCase
{
use WithoutMiddleware;
/**
@ -51,5 +49,4 @@ class TwoFAccountDynamicRequestTest extends TestCase
$this->assertEquals($twofaccountStoreRequest->rules(), $request->rules());
}
}

@ -4,13 +4,12 @@ namespace Tests\Api\v1\Requests;
use App\Api\v1\Requests\TwoFAccountImportRequest;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;
use Tests\TestCase;
class TwoFAccountImportRequestTest extends TestCase
{
use WithoutMiddleware;
/**
@ -45,7 +44,7 @@ class TwoFAccountImportRequestTest extends TestCase
{
return [
[[
'payload' => 'otpauth-migration://offline?data=AEoATACEAEYASAA'
'payload' => 'otpauth-migration://offline?data=AEoATACEAEYASAA',
]],
];
}
@ -68,18 +67,17 @@ class TwoFAccountImportRequestTest extends TestCase
{
return [
[[
'payload' => null // required
'payload' => null, // required
]],
[[
'payload' => '' // required
'payload' => '', // required
]],
[[
'payload' => true // string
'payload' => true, // string
]],
[[
'payload' => 8 // string
]]
'payload' => 8, // string
]],
];
}
}

@ -4,13 +4,12 @@ namespace Tests\Api\v1\Requests;
use App\Api\v1\Requests\TwoFAccountReorderRequest;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;
use Tests\TestCase;
class TwoFAccountReorderRequestTest extends TestCase
{
use WithoutMiddleware;
/**
@ -45,10 +44,10 @@ class TwoFAccountReorderRequestTest extends TestCase
{
return [
[[
'orderedIds' => [1,2,5]
'orderedIds' => [1, 2, 5],
]],
[[
'orderedIds' => [5]
'orderedIds' => [5],
]],
];
}
@ -71,21 +70,20 @@ class TwoFAccountReorderRequestTest extends TestCase
{
return [
[[
'orderedIds' => [] // required
'orderedIds' => [], // required
]],
[[
'orderedIds' => null // required
'orderedIds' => null, // required
]],
[[
'orderedIds' => 0 // array
'orderedIds' => 0, // array
]],
[[
'orderedIds' => 'string' // array
'orderedIds' => 'string', // array
]],
[[
'orderedIds' => true // array
'orderedIds' => true, // array
]],
];
}
}

@ -4,13 +4,12 @@ namespace Tests\Api\v1\Requests;
use App\Api\v1\Requests\TwoFAccountStoreRequest;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;
use Tests\TestCase;
class TwoFAccountStoreRequestTest extends TestCase
{
use WithoutMiddleware;
/**
@ -167,5 +166,4 @@ class TwoFAccountStoreRequestTest extends TestCase
]],
];
}
}

@ -4,13 +4,12 @@ namespace Tests\Api\v1\Requests;
use App\Api\v1\Requests\TwoFAccountUpdateRequest;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;
use Tests\TestCase;
class TwoFAccountUpdateRequestTest extends TestCase
{
use WithoutMiddleware;
/**
@ -218,5 +217,4 @@ class TwoFAccountUpdateRequestTest extends TestCase
]],
];
}
}

@ -4,13 +4,12 @@ namespace Tests\Api\v1\Requests;
use App\Api\v1\Requests\TwoFAccountUriRequest;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;
use Tests\TestCase;
class TwoFAccountUriRequestTest extends TestCase
{
use WithoutMiddleware;
/**
@ -45,14 +44,14 @@ class TwoFAccountUriRequestTest extends TestCase
{
return [
[[
'uri' => 'otpauth://totp/test@test.com?secret=A4GRFHZVRBGY7UIW&issuer=test'
'uri' => 'otpauth://totp/test@test.com?secret=A4GRFHZVRBGY7UIW&issuer=test',
]],
[[
'uri' => 'otpauth://hotp/test@test.com?secret=A4GRFHZVRBGY7UIW&issuer=test'
'uri' => 'otpauth://hotp/test@test.com?secret=A4GRFHZVRBGY7UIW&issuer=test',
]],
[[
'uri' => 'otpauth://totp/test@test.com?secret=A4GRFHZVRBGY7UIW&issuer=test',
'custom_otp' => 'steamtotp'
'custom_otp' => 'steamtotp',
]],
];
}
@ -75,33 +74,32 @@ class TwoFAccountUriRequestTest extends TestCase
{
return [
[[
'uri' => null // required
'uri' => null, // required
]],
[[
'uri' => '' // required
'uri' => '', // required
]],
[[
'uri' => true // string
'uri' => true, // string
]],
[[
'uri' => 8 // string
'uri' => 8, // string
]],
[[
'uri' => 'otpXauth://totp/test@test.com?secret=A4GRFHZVRBGY7UIW&issuer=test' // regex
'uri' => 'otpXauth://totp/test@test.com?secret=A4GRFHZVRBGY7UIW&issuer=test', // regex
]],
[[
'uri' => 'otpauth://totp/test@test.com?secret=A4GRFHZVRBGY7UIW&issuer=test',
'custom_otp' => 'notSteam' // not in
'custom_otp' => 'notSteam', // not in
]],
[[
'uri' => 'otpauth://totp/test@test.com?secret=A4GRFHZVRBGY7UIW&issuer=test',
'custom_otp' => 0 // string
'custom_otp' => 0, // string
]],
[[
'uri' => 'otpauth://totp/test@test.com?secret=A4GRFHZVRBGY7UIW&issuer=test',
'custom_otp' => true // string
'custom_otp' => true, // string
]],
];
}
}

@ -6,7 +6,6 @@ use Symfony\Component\HttpFoundation\File\UploadedFile as SymfonyUploadedFile;
class LocalFile extends SymfonyUploadedFile
{
/**
* Begin creating a new local file fake.
*
@ -16,5 +15,4 @@ class LocalFile extends SymfonyUploadedFile
{
return new LocalFileFactory;
}
}

Some files were not shown because too many files have changed in this diff Show More