%PDF- %PDF-
| Direktori : /www/varak.net/nextcloud.varak.net/3rdparty/web-auth/webauthn-lib/src/CeremonyStep/ |
| Current File : /www/varak.net/nextcloud.varak.net/3rdparty/web-auth/webauthn-lib/src/CeremonyStep/CheckOrigin.php |
<?php
declare(strict_types=1);
namespace Webauthn\CeremonyStep;
use Webauthn\AuthenticationExtensions\AuthenticationExtensions;
use Webauthn\AuthenticatorAssertionResponse;
use Webauthn\AuthenticatorAttestationResponse;
use Webauthn\Exception\AuthenticatorResponseVerificationException;
use Webauthn\PublicKeyCredentialCreationOptions;
use Webauthn\PublicKeyCredentialRequestOptions;
use Webauthn\PublicKeyCredentialSource;
use function in_array;
use function is_array;
use function is_string;
final class CheckOrigin implements CeremonyStep
{
/**
* @param string[] $securedRelyingPartyId
*/
public function __construct(
private readonly array $securedRelyingPartyId
) {
}
public function process(
PublicKeyCredentialSource $publicKeyCredentialSource,
AuthenticatorAssertionResponse|AuthenticatorAttestationResponse $authenticatorResponse,
PublicKeyCredentialRequestOptions|PublicKeyCredentialCreationOptions $publicKeyCredentialOptions,
?string $userHandle,
string $host
): void {
$authData = $authenticatorResponse instanceof AuthenticatorAssertionResponse ? $authenticatorResponse->authenticatorData : $authenticatorResponse->attestationObject->authData;
$C = $authenticatorResponse->clientDataJSON;
$rpId = $publicKeyCredentialOptions->rpId ?? $publicKeyCredentialOptions->rp->id ?? $host;
$facetId = $this->getFacetId($rpId, $publicKeyCredentialOptions->extensions, $authData->extensions);
$parsedRelyingPartyId = parse_url($C->origin);
is_array($parsedRelyingPartyId) || throw AuthenticatorResponseVerificationException::create(
'Invalid origin'
);
if (! in_array($facetId, $this->securedRelyingPartyId, true)) {
$scheme = $parsedRelyingPartyId['scheme'] ?? '';
$scheme === 'https' || throw AuthenticatorResponseVerificationException::create(
'Invalid scheme. HTTPS required.'
);
}
$clientDataRpId = $parsedRelyingPartyId['host'] ?? '';
$clientDataRpId !== '' || throw AuthenticatorResponseVerificationException::create('Invalid origin rpId.');
$rpIdLength = mb_strlen($facetId);
mb_substr(
'.' . $clientDataRpId,
-($rpIdLength + 1)
) === '.' . $facetId || throw AuthenticatorResponseVerificationException::create('rpId mismatch.');
}
private function getFacetId(
string $rpId,
AuthenticationExtensions $authenticationExtensionsClientInputs,
null|AuthenticationExtensions $authenticationExtensionsClientOutputs
): string {
if ($authenticationExtensionsClientOutputs === null || ! $authenticationExtensionsClientInputs->has(
'appid'
) || ! $authenticationExtensionsClientOutputs->has('appid')) {
return $rpId;
}
$appId = $authenticationExtensionsClientInputs->get('appid')
->value;
$wasUsed = $authenticationExtensionsClientOutputs->get('appid')
->value;
if (! is_string($appId) || $wasUsed !== true) {
return $rpId;
}
return $appId;
}
}