Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions psalm-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6312,9 +6312,6 @@
<code><![CDATA[$status !== []]]></code>
<code><![CDATA[$status !== null && $status !== []]]></code>
</RedundantCondition>
<UnusedClass>
<code><![CDATA[UploadProgress]]></code>
</UnusedClass>
</file>
<file src="src/Plugins/Import/Upload/UploadSession.php">
<MixedArgument>
Expand Down
4 changes: 2 additions & 2 deletions resources/templates/preferences/two_factor/main.twig
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
</div>
<div class="card-body">
{% if enabled %}
{% if num_backends == 0 %}
{% if not has_backends %}
<p>{{ t('Two-factor authentication is not available, please install optional dependencies to enable authentication backends.') }}</p>
<p>{{ t('Following composer packages are missing:') }}</p>
<ul>
Expand Down Expand Up @@ -69,7 +69,7 @@
</div>
</div>
</div>
{% elseif num_backends > 0 %}
{% elseif has_backends %}
<div class="row">
<div class="col">
<div class="card mt-4">
Expand Down
2 changes: 1 addition & 1 deletion src/Controllers/Database/ImportController.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public function __invoke(ServerRequest $request): Response
return $this->response->redirectToRoute('/', ['reload' => true, 'message' => __('No databases selected.')]);
}

[$uploadId] = Ajax::uploadProgressSetup();
$uploadId = Ajax::uploadProgressSetup();

ImportSettings::$importType = 'database';
$importList = Plugins::getImport();
Expand Down
2 changes: 1 addition & 1 deletion src/Controllers/Preferences/TwoFactorController.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public function __invoke(ServerRequest $request): Response
$backend = $twoFactor->getBackend();
$this->response->render('preferences/two_factor/main', [
'enabled' => $twoFactor->isWritable(),
'num_backends' => count($twoFactor->getAvailable()),
'has_backends' => count($twoFactor->getAvailable()) > 1,
'backend_id' => $backend::$id,
'backend_name' => $backend::getName(),
'backend_description' => $backend::getDescription(),
Expand Down
2 changes: 1 addition & 1 deletion src/Controllers/Server/ImportController.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public function __invoke(ServerRequest $request): Response
$this->dbi->selectDb('mysql');
}

[$uploadId] = Ajax::uploadProgressSetup();
$uploadId = Ajax::uploadProgressSetup();

ImportSettings::$importType = 'server';
$importList = Plugins::getImport();
Expand Down
2 changes: 1 addition & 1 deletion src/Controllers/Table/ImportController.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public function __invoke(ServerRequest $request): Response
UrlParams::$params['goto'] = Url::getFromRoute('/table/import');
UrlParams::$params['back'] = Url::getFromRoute('/table/import');

[$uploadId] = Ajax::uploadProgressSetup();
$uploadId = Ajax::uploadProgressSetup();

ImportSettings::$importType = 'table';
$importList = Plugins::getImport();
Expand Down
25 changes: 10 additions & 15 deletions src/Import/Ajax.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@
namespace PhpMyAdmin\Import;

use PhpMyAdmin\Core;
use PhpMyAdmin\Plugins\Import\Upload\UploadNoplugin;
use PhpMyAdmin\Plugins\Import\Upload\UploadProgress;

use function defined;
use function function_exists;
use function header;
use function ini_get;
use function json_encode;
use function sprintf;
use function ucwords;
use function uniqid;

/**
Expand All @@ -23,12 +24,7 @@ final class Ajax
/** For differentiating array in $_SESSION variable */
public const SESSION_KEY = '__upload_status';

/**
* Sets up some variables for upload progress
*
* @return array{string, string[]}
*/
public static function uploadProgressSetup(): array
public static function uploadProgressSetup(): string
{
/**
* sets default plugin for handling the import process
Expand All @@ -45,23 +41,22 @@ public static function uploadProgressSetup(): array
*/
$plugins = [
// in PHP 5.4 session-based upload progress was problematic, see closed bug 3964
//"session",
'progress',
'noplugin',
// [UploadSession::class, 'sessionCheck'],
[UploadProgress::class, 'progressCheck'],
[UploadNoplugin::class, 'nopluginCheck'],
];

// select available plugin
foreach ($plugins as $plugin) {
$check = $plugin . 'Check';
[$class, $method] = $plugin;

if (self::$check()) {
$uploadClass = 'PhpMyAdmin\Plugins\Import\Upload\Upload' . ucwords($plugin);
$_SESSION[self::SESSION_KEY]['handler'] = $uploadClass;
if (self::$method()) {
$_SESSION[self::SESSION_KEY]['handler'] = $class;
break;
}
}

return [$uploadId, $plugins];
return $uploadId;
}

/**
Expand Down
21 changes: 12 additions & 9 deletions src/Plugins/AuthenticationPluginFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@

use PhpMyAdmin\Config;
use PhpMyAdmin\Exceptions\AuthenticationPluginException;
use PhpMyAdmin\Plugins\Auth\AuthenticationConfig;
use PhpMyAdmin\Plugins\Auth\AuthenticationCookie;
use PhpMyAdmin\Plugins\Auth\AuthenticationHttp;
use PhpMyAdmin\Plugins\Auth\AuthenticationSignon;
use PhpMyAdmin\ResponseRenderer;

use function __;
use function class_exists;
use function is_subclass_of;
use function strtolower;
use function ucfirst;

class AuthenticationPluginFactory
{
Expand All @@ -30,12 +30,15 @@ public function create(): AuthenticationPlugin
}

$authType = Config::getInstance()->selectedServer['auth_type'];
$class = 'PhpMyAdmin\\Plugins\\Auth\\Authentication' . ucfirst(strtolower($authType));
if (! class_exists($class) || ! is_subclass_of($class, AuthenticationPlugin::class)) {
throw new AuthenticationPluginException(
$class = match ($authType) {
'config' => AuthenticationConfig::class,
'cookie' => AuthenticationCookie::class,
'http' => AuthenticationHttp::class,
'signon' => AuthenticationSignon::class,
default => throw new AuthenticationPluginException(
__('Invalid authentication method set in configuration:') . ' ' . $authType,
);
}
),
};

$this->plugin = new $class($this->responseRenderer);

Expand Down
49 changes: 15 additions & 34 deletions src/TwoFactor.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,17 @@
use PhpMyAdmin\Plugins\TwoFactor\Application;
use PhpMyAdmin\Plugins\TwoFactor\Invalid;
use PhpMyAdmin\Plugins\TwoFactor\Key;
use PhpMyAdmin\Plugins\TwoFactor\Simple;
use PhpMyAdmin\Plugins\TwoFactor\WebAuthn;
use PhpMyAdmin\Plugins\TwoFactorPlugin;
use PragmaRX\Google2FAQRCode\Google2FA;
use XMLWriter;

use function array_merge;
use function class_exists;
use function extension_loaded;
use function in_array;
use function is_array;
use function is_bool;
use function is_string;
use function ucfirst;

/**
* Two factor authentication wrapper class
Expand All @@ -45,9 +44,6 @@ class TwoFactor

private TwoFactorPlugin $backend;

/** @var string[] */
private array $available;

private UserPreferences $userPreferences;

/**
Expand All @@ -67,7 +63,6 @@ public function __construct(public string $user)
$config,
new Clock(),
);
$this->available = $this->getAvailableBackends();
$this->config = $this->readConfig();
$this->writable = $this->config['type'] === 'db';
$this->backend = $this->getBackendForCurrentUser();
Expand Down Expand Up @@ -109,42 +104,38 @@ public function getBackend(): TwoFactorPlugin
return $this->backend;
}

/** @return string[] */
/** @return array<string, class-string<TwoFactorPlugin>> */
public function getAvailable(): array
{
return $this->available;
return $this->getAvailableBackends();
}

public function showSubmit(): bool
{
return $this->backend::$showSubmit;
}

/**
* Returns list of available backends
*
* @return string[]
*/
public function getAvailableBackends(): array
/** @return array<string, class-string<TwoFactorPlugin>> */
private function getAvailableBackends(): array
{
$result = [];
$result = ['' => TwoFactorPlugin::class];
$config = Config::getInstance();
if ($config->config->debug->simple2fa) {
$result[] = 'simple';
$result['simple'] = Simple::class;
}

if (
class_exists(Google2FA::class)
&& class_exists(ImageRenderer::class)
&& (class_exists(XMLWriter::class) || extension_loaded('imagick'))
) {
$result[] = 'application';
$result['application'] = Application::class;
}

$result[] = 'WebAuthn';
$result['WebAuthn'] = WebAuthn::class;

if (class_exists(U2FServer::class)) {
$result[] = 'key';
$result['key'] = Key::class;
}

return $result;
Expand Down Expand Up @@ -182,15 +173,7 @@ public function getMissingDeps(): array
*/
public function getBackendClass(string $name): string
{
$result = TwoFactorPlugin::class;
if (in_array($name, $this->available, true)) {
/** @psalm-var class-string<TwoFactorPlugin> $result */
$result = 'PhpMyAdmin\\Plugins\\TwoFactor\\' . ucfirst($name);
} elseif ($name !== '') {
$result = Invalid::class;
}

return $result;
return $this->getAvailableBackends()[$name] ?? Invalid::class;
}

/**
Expand Down Expand Up @@ -268,11 +251,11 @@ public function configure(ServerRequest $request, string $name): bool
$cls = $this->getBackendClass($name);
$this->backend = new $cls($this);
} else {
if (! in_array($name, $this->available, true)) {
$cls = $this->getBackendClass($name);
if ($cls === Invalid::class) {
return false;
}

$cls = $this->getBackendClass($name);
$this->backend = new $cls($this);
if (! $this->backend->configure($request)) {
return false;
Expand All @@ -294,10 +277,8 @@ public function configure(ServerRequest $request, string $name): bool
*/
public function getAllBackends(): array
{
$all = array_merge([''], $this->available);
$backends = [];
foreach ($all as $name) {
$cls = $this->getBackendClass($name);
foreach ($this->getAvailableBackends() as $cls) {
$backends[] = ['id' => $cls::$id, 'name' => $cls::getName(), 'description' => $cls::getDescription()];
}

Expand Down
6 changes: 3 additions & 3 deletions tests/unit/Plugins/AuthenticationPluginFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ public function testValidPlugins(string $type, string $class): void
public static function providerForTestValidPlugins(): iterable
{
yield 'config plugin' => ['config', AuthenticationConfig::class];
yield 'cookie plugin' => ['Cookie', AuthenticationCookie::class];
yield 'http plugin' => ['HTTP', AuthenticationHttp::class];
yield 'sign on plugin' => ['signOn', AuthenticationSignon::class];
yield 'cookie plugin' => ['cookie', AuthenticationCookie::class];
yield 'http plugin' => ['http', AuthenticationHttp::class];
yield 'sign on plugin' => ['signon', AuthenticationSignon::class];
}

public function testInvalidPlugin(): void
Expand Down
10 changes: 5 additions & 5 deletions tests/unit/TwoFactorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
use Psr\Http\Message\ServerRequestInterface;
use ReflectionProperty;

use function array_key_exists;
use function count;
use function in_array;
use function json_encode;
use function str_replace;

Expand Down Expand Up @@ -266,7 +266,7 @@ public function testApplication(): void
$request = new ServerRequest(self::createStub(ServerRequestInterface::class));

$object = $this->getTwoFactorAndLoadConfig('user', null);
if (! in_array('application', $object->getAvailable(), true)) {
if (! array_key_exists('application', $object->getAvailable())) {
self::markTestSkipped('google2fa not available');
}

Expand Down Expand Up @@ -320,7 +320,7 @@ public function testKey(): void
$request = new ServerRequest(self::createStub(ServerRequestInterface::class));

$object = $this->getTwoFactorAndLoadConfig('user', null);
if (! in_array('key', $object->getAvailable(), true)) {
if (! array_key_exists('key', $object->getAvailable())) {
self::markTestSkipped('u2f-php-server not available');
}

Expand Down Expand Up @@ -386,7 +386,7 @@ public function testKeyAuthentication(): void
$request = new ServerRequest(self::createStub(ServerRequestInterface::class));

$object = $this->getTwoFactorAndLoadConfig('user', null);
if (! in_array('key', $object->getAvailable(), true)) {
if (! array_key_exists('key', $object->getAvailable())) {
self::markTestSkipped('u2f-php-server not available');
}

Expand Down Expand Up @@ -509,7 +509,7 @@ public function testBackends(): void
$object = $this->getTwoFactorAndLoadConfig('user', null);
$backends = $object->getAllBackends();
self::assertCount(
count($object->getAvailable()) + 1,
count($object->getAvailable()),
$backends,
);
$config->config->debug->simple2fa = false;
Expand Down
Loading