Skip to content

Commit ae27f16

Browse files
committed
Merge branch 'QA_5_2'
Signed-off-by: Maurício Meneghini Fauth <mauricio@mfauth.net>
2 parents 513c2ae + 18bdcba commit ae27f16

7 files changed

Lines changed: 301 additions & 11 deletions

File tree

.github/workflows/tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ jobs:
4242
apk add --update --no-cache \
4343
php\$V-cli php\$V-mysqli php\$V-session php\$V-mbstring php\$V-ctype php\$V-sodium \
4444
php\$V-iconv php\$V-xml php\$V-tokenizer php\$V-xmlwriter php\$V-simplexml \
45-
php\$V-dom php\$V-json php\$V-bz2 php\$V-curl php\$V-gd php\$V-zip \
45+
php\$V-dom php\$V-json php\$V-bz2 php\$V-curl php\$V-gd php\$V-zip php\$V-bcmath \
4646
musl-locales musl-locales-lang \
4747
gettext composer git && \
4848
composer config version "$(php -r "define('VERSION_SUFFIX', ''); require_once('src/Version.php'); echo \PhpMyAdmin\Version::VERSION;")" && \

phpstan-baseline.neon

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5467,7 +5467,7 @@ parameters:
54675467

54685468
-
54695469
message: "#^Parameter \\#1 \\$identifier of static method PhpMyAdmin\\\\Util\\:\\:backquote\\(\\) expects string\\|Stringable\\|null, mixed given\\.$#"
5470-
count: 4
5470+
count: 3
54715471
path: src/CreateAddField.php
54725472

54735473
-
@@ -5491,8 +5491,8 @@ parameters:
54915491
path: src/CreateAddField.php
54925492

54935493
-
5494-
message: "#^Parameter \\#1 \\$string of function trim expects string, mixed given\\.$#"
5495-
count: 1
5494+
message: "#^Parameter \\#1 \\$string of function rtrim expects string, mixed given\\.$#"
5495+
count: 2
54965496
path: src/CreateAddField.php
54975497

54985498
-
@@ -15715,3 +15715,38 @@ parameters:
1571515715
count: 1
1571615716
path: tests/unit/WebAuthn/CBORDecoderTest.php
1571715717

15718+
-
15719+
message: "#^Call to static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertArrayHasKey\\(\\) with 'attestation' and array\\{challenge\\: non\\-falsy\\-string, rp\\: array\\{name\\: string, id\\: string\\}, user\\: array\\{id\\: string, name\\: string, displayName\\: string\\}, pubKeyCredParams\\: non\\-empty\\-array\\<int, array\\{alg\\: int, type\\: 'public\\-key'\\}\\>, authenticatorSelection\\: array\\<string, string\\>, timeout\\: int\\<1, max\\>, attestation\\: non\\-empty\\-string\\} will always evaluate to true\\.$#"
15720+
count: 1
15721+
path: tests/unit/WebAuthn/CustomServerTest.php
15722+
15723+
-
15724+
message: "#^Call to static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertArrayHasKey\\(\\) with 'challenge' and array\\{challenge\\: non\\-empty\\-string, rp\\: array\\{name\\: string, id\\: string\\}, user\\: array\\{id\\: string, name\\: string, displayName\\: string\\}, pubKeyCredParams\\: array\\<int, array\\{alg\\: int, type\\: 'public\\-key'\\}\\>, authenticatorSelection\\: array\\<string, string\\>, timeout\\: int\\<1, max\\>, attestation\\: non\\-empty\\-string\\} will always evaluate to true\\.$#"
15725+
count: 1
15726+
path: tests/unit/WebAuthn/CustomServerTest.php
15727+
15728+
-
15729+
message: "#^Call to static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertArrayHasKey\\(\\) with 'pubKeyCredParams' and array\\{challenge\\: non\\-falsy\\-string, rp\\: array\\{name\\: string, id\\: string\\}, user\\: array\\{id\\: string, name\\: string, displayName\\: string\\}, pubKeyCredParams\\: array\\<int, array\\{alg\\: int, type\\: 'public\\-key'\\}\\>, authenticatorSelection\\: array\\<string, string\\>, timeout\\: int\\<1, max\\>, attestation\\: non\\-empty\\-string\\} will always evaluate to true\\.$#"
15730+
count: 1
15731+
path: tests/unit/WebAuthn/CustomServerTest.php
15732+
15733+
-
15734+
message: "#^Call to static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertNull\\(\\) with null will always evaluate to true\\.$#"
15735+
count: 1
15736+
path: tests/unit/WebAuthn/CustomServerTest.php
15737+
15738+
-
15739+
message: "#^Call to static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertArrayHasKey\\(\\) with 'attestation' and array\\{challenge\\: non\\-falsy\\-string, rp\\: array\\{name\\: string, id\\: string\\}, user\\: array\\{id\\: string, name\\: string, displayName\\: string\\}, pubKeyCredParams\\: non\\-empty\\-array\\<int, array\\{alg\\: int, type\\: 'public\\-key'\\}\\>, authenticatorSelection\\: array\\<string, string\\>, timeout\\: int\\<1, max\\>, attestation\\: non\\-empty\\-string\\} will always evaluate to true\\.$#"
15740+
count: 1
15741+
path: tests/unit/WebAuthn/WebauthnLibServerTest.php
15742+
15743+
-
15744+
message: "#^Call to static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertArrayHasKey\\(\\) with 'challenge' and array\\{challenge\\: non\\-empty\\-string, rp\\: array\\{name\\: string, id\\: string\\}, user\\: array\\{id\\: string, name\\: string, displayName\\: string\\}, pubKeyCredParams\\: array\\<int, array\\{alg\\: int, type\\: 'public\\-key'\\}\\>, authenticatorSelection\\: array\\<string, string\\>, timeout\\: int\\<1, max\\>, attestation\\: non\\-empty\\-string\\} will always evaluate to true\\.$#"
15745+
count: 1
15746+
path: tests/unit/WebAuthn/WebauthnLibServerTest.php
15747+
15748+
-
15749+
message: "#^Call to static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertArrayHasKey\\(\\) with 'pubKeyCredParams' and array\\{challenge\\: non\\-falsy\\-string, rp\\: array\\{name\\: string, id\\: string\\}, user\\: array\\{id\\: string, name\\: string, displayName\\: string\\}, pubKeyCredParams\\: array\\<int, array\\{alg\\: int, type\\: 'public\\-key'\\}\\>, authenticatorSelection\\: array\\<string, string\\>, timeout\\: int\\<1, max\\>, attestation\\: non\\-empty\\-string\\} will always evaluate to true\\.$#"
15750+
count: 1
15751+
path: tests/unit/WebAuthn/WebauthnLibServerTest.php
15752+

resources/js/src/modules/indexes.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ function addColumnToIndex (sourceArray, arrayIndex, indexChoice, colIndex): void
193193
columnNames.push($('input[name="field_name[' + this.col_index + ']"]').val());
194194
});
195195

196-
displayName = '[' + columnNames.join(', ') + ']';
196+
displayName = '[' + columnNames.join(', ').trimRight() + ']';
197197
}
198198

199199
$.each(columns, function () {

src/CreateAddField.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use function in_array;
1414
use function json_decode;
1515
use function preg_replace;
16+
use function rtrim;
1617
use function trim;
1718

1819
/**
@@ -64,7 +65,7 @@ private function buildColumnCreationStatement(
6465
}
6566

6667
$definition = $this->getStatementPrefix($isCreateTable) . Table::generateFieldSpec(
67-
trim($_POST['field_name'][$i]),
68+
rtrim($_POST['field_name'][$i]),
6869
$_POST['field_type'][$i],
6970
$_POST['field_length'][$i],
7071
$_POST['field_attribute'][$i],
@@ -153,7 +154,7 @@ private function buildIndexStatement(
153154

154155
$indexFields = [];
155156
foreach ($index['columns'] as $key => $column) {
156-
$indexFields[$key] = Util::backquote($_POST['field_name'][$column['col_index']]);
157+
$indexFields[$key] = Util::backquote(rtrim($_POST['field_name'][$column['col_index']]));
157158
if (! $column['size']) {
158159
continue;
159160
}

src/WebAuthn/CustomServer.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,8 @@ public function parseAndValidateAttestationResponse(
120120
): array {
121121
try {
122122
$attestationCredential = $this->getAttestationCredential($attestationResponse);
123-
} catch (Throwable) {
124-
throw new WebAuthnException('Invalid authenticator response.');
123+
} catch (Throwable $exception) {
124+
throw new WebAuthnException('Invalid authenticator response.', (int) $exception->getCode(), $exception);
125125
}
126126

127127
$creationOptions = json_decode($credentialCreationOptions, true);
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpMyAdmin\Tests\WebAuthn;
6+
7+
use PhpMyAdmin\Http\ServerRequest;
8+
use PhpMyAdmin\WebAuthn\CustomServer;
9+
use PHPUnit\Framework\TestCase;
10+
use Psr\Http\Message\UriInterface;
11+
use Throwable;
12+
13+
use function hex2bin;
14+
15+
/**
16+
* @covers \PhpMyAdmin\WebAuthn\CustomServer
17+
* @covers \PhpMyAdmin\WebAuthn\CBORDecoder
18+
* @covers \PhpMyAdmin\WebAuthn\DataStream
19+
*/
20+
final class CustomServerTest extends TestCase
21+
{
22+
public function testGetCredentialCreationOptions(): void
23+
{
24+
$server = new CustomServer();
25+
$options = $server->getCredentialCreationOptions('user_name', 'user_id', 'test.localhost');
26+
self::assertArrayHasKey('challenge', $options);
27+
self::assertNotEmpty($options['challenge']);
28+
self::assertArrayHasKey('pubKeyCredParams', $options);
29+
self::assertNotEmpty($options['pubKeyCredParams']);
30+
self::assertArrayHasKey('attestation', $options);
31+
self::assertNotEmpty($options['attestation']);
32+
self::assertSame('phpMyAdmin (test.localhost)', $options['rp']['name']);
33+
self::assertSame('test.localhost', $options['rp']['id']);
34+
self::assertSame('user_name', $options['user']['name']);
35+
self::assertSame('user_name', $options['user']['displayName']);
36+
self::assertSame('user_id', $options['user']['id']);
37+
self::assertArrayHasKey('authenticatorAttachment', $options['authenticatorSelection']);
38+
self::assertSame('cross-platform', $options['authenticatorSelection']['authenticatorAttachment']);
39+
}
40+
41+
public function testGetCredentialRequestOptions(): void
42+
{
43+
$server = new CustomServer();
44+
$options = $server->getCredentialRequestOptions(
45+
'user_name',
46+
'userHandle1',
47+
'test.localhost',
48+
[['type' => 'public-key', 'id' => 'cHVibGljS2V5Q3JlZGVudGlhbElkMQ']],
49+
);
50+
self::assertNotEmpty($options['challenge']);
51+
self::assertSame(
52+
[['type' => 'public-key', 'id' => 'cHVibGljS2V5Q3JlZGVudGlhbElkMQ==']],
53+
$options['allowCredentials'],
54+
);
55+
self::assertSame(60000, $options['timeout']);
56+
self::assertSame('none', $options['attestation']);
57+
self::assertSame('discouraged', $options['userVerification']);
58+
}
59+
60+
/** @see https://github.com/web-auth/webauthn-framework/blob/v3.3.12/tests/library/Functional/AssertionTest.php#L46 */
61+
public function testParseAndValidateAssertionResponse(): void
62+
{
63+
$server = new CustomServer();
64+
65+
$uriStub = self::createStub(UriInterface::class);
66+
$uriStub->method('getHost')->willReturn('localhost');
67+
$request = self::createStub(ServerRequest::class);
68+
$request->method('getUri')->willReturn($uriStub);
69+
70+
// phpcs:ignore Generic.Files.LineLength.TooLong
71+
$authenticatorResponse = '{"id":"eHouz_Zi7-BmByHjJ_tx9h4a1WZsK4IzUmgGjkhyOodPGAyUqUp_B9yUkflXY3yHWsNtsrgCXQ3HjAIFUeZB-w","type":"public-key","rawId":"eHouz/Zi7+BmByHjJ/tx9h4a1WZsK4IzUmgGjkhyOodPGAyUqUp/B9yUkflXY3yHWsNtsrgCXQ3HjAIFUeZB+w==","response":{"authenticatorData":"SZYN5YgOjGh0NBcPZHZgW4/krrmihjLHmVzzuoMdl2MBAAAAew==","clientDataJSON":"eyJjaGFsbGVuZ2UiOiJHMEpiTExuZGVmM2EwSXkzUzJzU1FBOHVPNFNPX3plNkZaTUF1UEk2LXhJIiwiY2xpZW50RXh0ZW5zaW9ucyI6e30sImhhc2hBbGdvcml0aG0iOiJTSEEtMjU2Iiwib3JpZ2luIjoiaHR0cHM6Ly9sb2NhbGhvc3Q6ODQ0MyIsInR5cGUiOiJ3ZWJhdXRobi5nZXQifQ==","signature":"MEUCIEY/vcNkbo/LdMTfLa24ZYLlMMVMRd8zXguHBvqud9AJAiEAwCwpZpvcMaqCrwv85w/8RGiZzE+gOM61ffxmgEDeyhM=","userHandle":null}}';
72+
$challenge = 'G0JbLLndef3a0Iy3S2sSQA8uO4SO/ze6FZMAuPI6+xI=';
73+
74+
$allowedCredentials = [
75+
[
76+
'type' => 'public-key',
77+
'id' => 'eHouz_Zi7-BmByHjJ_tx9h4a1WZsK4IzUmgGjkhyOodPGAyUqUp_B9yUkflXY3yHWsNtsrgCXQ3HjAIFUeZB-w',
78+
],
79+
];
80+
81+
$throwable = null;
82+
try {
83+
$server->parseAndValidateAssertionResponse(
84+
$authenticatorResponse,
85+
$allowedCredentials,
86+
$challenge,
87+
$request,
88+
);
89+
} catch (Throwable $throwable) {
90+
throw $throwable;
91+
}
92+
93+
/** @psalm-suppress RedundantCondition */
94+
self::assertNull($throwable);
95+
}
96+
97+
/** @see https://github.com/web-auth/webauthn-framework/blob/v3.3.12/tests/library/Functional/NoneAttestationStatementTest.php#L45 */
98+
public function testParseAndValidateAttestationResponse(): void
99+
{
100+
$uriStub = self::createStub(UriInterface::class);
101+
$uriStub->method('getHost')->willReturn('localhost');
102+
$request = self::createStub(ServerRequest::class);
103+
$request->method('getUri')->willReturn($uriStub);
104+
105+
// phpcs:ignore Generic.Files.LineLength.TooLong
106+
$options = '{"rp":{"name":"My Application"},"pubKeyCredParams":[{"type":"public-key","alg":-7}],"challenge":"9WqgpRIYvGMCUYiFT20o1U7hSD193k11zu4tKP7wRcrE26zs1zc4LHyPinvPGS86wu6bDvpwbt8Xp2bQ3VBRSQ==","attestation":"none","user":{"name":"test@foo.com","id":"MJr5sD0WitVwZM0eoSO6kWhyseT67vc3oQdk\/k1VdZQ=","displayName":"Test PublicKeyCredentialUserEntity"},"authenticatorSelection":{"requireResidentKey":false,"userVerification":"preferred"}}';
107+
// phpcs:ignore Generic.Files.LineLength.TooLong
108+
$response = '{"id":"mMihuIx9LukswxBOMjMHDf6EAONOy7qdWhaQQ7dOtViR2cVB_MNbZxURi2cvgSvKSILb3mISe9lPNG9sYgojuY5iNinYOg6hRVxmm0VssuNG2pm1-RIuTF9DUtEJZEEK","type":"public-key","rawId":"mMihuIx9LukswxBOMjMHDf6EAONOy7qdWhaQQ7dOtViR2cVB/MNbZxURi2cvgSvKSILb3mISe9lPNG9sYgojuY5iNinYOg6hRVxmm0VssuNG2pm1+RIuTF9DUtEJZEEK","response":{"clientDataJSON":"eyJjaGFsbGVuZ2UiOiI5V3FncFJJWXZHTUNVWWlGVDIwbzFVN2hTRDE5M2sxMXp1NHRLUDd3UmNyRTI2enMxemM0TEh5UGludlBHUzg2d3U2YkR2cHdidDhYcDJiUTNWQlJTUSIsImNsaWVudEV4dGVuc2lvbnMiOnt9LCJoYXNoQWxnb3JpdGhtIjoiU0hBLTI1NiIsIm9yaWdpbiI6Imh0dHBzOi8vbG9jYWxob3N0Ojg0NDMiLCJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIn0=","attestationObject":"o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVjkSZYN5YgOjGh0NBcPZHZgW4/krrmihjLHmVzzuoMdl2NBAAAAAAAAAAAAAAAAAAAAAAAAAAAAYJjIobiMfS7pLMMQTjIzBw3+hADjTsu6nVoWkEO3TrVYkdnFQfzDW2cVEYtnL4ErykiC295iEnvZTzRvbGIKI7mOYjYp2DoOoUVcZptFbLLjRtqZtfkSLkxfQ1LRCWRBCqUBAgMmIAEhWCAcPxwKyHADVjTgTsat4R/Jax6PWte50A8ZasMm4w6RxCJYILt0FCiGwC6rBrh3ySNy0yiUjZpNGAhW+aM9YYyYnUTJ"}}';
109+
110+
$server = new CustomServer();
111+
$credential = $server->parseAndValidateAttestationResponse($response, $options, $request);
112+
113+
self::assertSame(
114+
[
115+
// phpcs:ignore Generic.Files.LineLength.TooLong
116+
'publicKeyCredentialId' => 'mMihuIx9LukswxBOMjMHDf6EAONOy7qdWhaQQ7dOtViR2cVB_MNbZxURi2cvgSvKSILb3mISe9lPNG9sYgojuY5iNinYOg6hRVxmm0VssuNG2pm1-RIuTF9DUtEJZEEK',
117+
'type' => 'public-key',
118+
'transports' => [],
119+
'attestationType' => 'none',
120+
'aaguid' => hex2bin('00000000000000000000000000000000'),
121+
// phpcs:ignore Generic.Files.LineLength.TooLong
122+
'credentialPublicKey' => 'pQECAyYgASFYIBw_HArIcANWNOBOxq3hH8lrHo9a17nQDxlqwybjDpHEIlggu3QUKIbALqsGuHfJI3LTKJSNmk0YCFb5oz1hjJidRMk',
123+
'userHandle' => 'MJr5sD0WitVwZM0eoSO6kWhyseT67vc3oQdk_k1VdZQ',
124+
'counter' => 0,
125+
],
126+
$credential,
127+
);
128+
}
129+
}

0 commit comments

Comments
 (0)