Skip to content

Commit

Permalink
Update client information discovery
Browse files Browse the repository at this point in the history
  • Loading branch information
gRegorLove committed Jul 6, 2024
1 parent 2cfb79f commit ebd19be
Show file tree
Hide file tree
Showing 2 changed files with 142 additions and 3 deletions.
9 changes: 7 additions & 2 deletions ProcessIndieAuth.module.php
Original file line number Diff line number Diff line change
Expand Up @@ -926,9 +926,9 @@ public function authorizationEndpoint(): void

$request['client_id'] = Server::canonizeUrl($request['client_id']);
$request['redirect_uri'] = Server::canonizeUrl($request['redirect_uri']);
$client = $this->getClientInfo($request['client_id']);
$client = Server::getClientInfo($request['client_id']);

if (!Server::isRedirectUriAllowed($request['redirect_uri'], $request['client_id'], $client['redirect_uri'])) {
if (!Server::isRedirectUriAllowed($request['redirect_uri'], $request['client_id'], $client['redirect_uris'])) {
$this->httpResponse('mismatched redirect_uri');
}

Expand Down Expand Up @@ -2038,6 +2038,11 @@ private function httpResponse($response, int $http_status = 400, array $headers
exit;
}

/**
* DEPRECATED
*
* @see Client::getInfo()
*/
private function getClientInfo(string $url): array
{
$info = array_fill_keys([
Expand Down
136 changes: 135 additions & 1 deletion src/IndieAuth/Server.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,81 @@

namespace IndieAuth;

final class Server
use IndieAuth\Libs\{
Barnabywalters\Mf2 as Mf2Helper,
Mf2
};
use ProcessWire\WireHttp;

final class Server
{
/**
* Get client information
* First check if the client_id itself is the info (JSON)
* Fallback to checking for h-app or h-x-app
*
* @see https://github.com/indieweb/indieauth/issues/133
*/
public static function getClientInfo(string $client_id): array
{
$headers = static::fetchHead($client_id, ['content-type']);

$is_json = false;
if ($headers) {
if (static::hasContentType('application/json', $headers['content-type'])) {
$is_json = true;
}
}

$content = static::fetchBody($client_id);

if ($is_json) {
$json = json_decode($content, true);
if ($json) {
return [
'name' => $json['client_name'] ?? '',
'url' => $json['client_uri'] ?? '',
'logo' => $json['logo_uri'] ?? '',
'redirect_uris' => $json['redirect_uris'] ?? [],
];
}
}

$info = array_fill_keys([
'name',
'url',
'logo',
], '');

$info['name'] = parse_url($client_id, PHP_URL_HOST);
$info['url'] = $client_id;
$info['redirect_uris'] = [];

$mf2 = Mf2\parse($content, $client_id);
$info['redirect_uris'] = $mf2['rels']['redirect_uri'] ?? [];

$apps = Mf2Helper\findMicroformatsByType($mf2, 'h-app');
if (!$apps) {
$apps = Mf2Helper\findMicroformatsByType($mf2, 'h-x-app');
}

if (!$apps) {
return $info;
}

$app = reset($apps);

if (Mf2Helper\hasProp($app, 'name')) {
$info['name'] = Mf2Helper\getPlaintext($app, 'name');
}

if (Mf2Helper\hasProp($app, 'logo')) {
$info['logo'] = Mf2Helper\getPlaintext($app, 'logo');
}

return $info;
}

/**
* @see https://indieauth.spec.indieweb.org/#client-identifier
*/
Expand Down Expand Up @@ -169,5 +242,66 @@ public static function base64UrlEncode(string $input): string
{
return rtrim(strtr(base64_encode($input), '+/', '-_'), '=');
}

/**
* Perform a HEAD request and return an array of headers
* If $requested_headers is provided, only return those headers.
* For example, `$requested_headers = ['link']` will return
* only the Link: headers
*/
private static function fetchHead(
string $url,
array $requested_headers = []
): ?array {
$http = new WireHttp();

$response = $http->status($url);
if (!$response) {
return null;
}

$http_headers = $http->getResponseHeaderValues('', true);

if ($requested_headers) {
$http_headers = array_intersect_key(
$http_headers,
array_fill_keys($requested_headers, [])
);

if (!$http_headers) {
return null;
}
}

return $http_headers;
}

/**
* Fetch the content of a URL
*/
private static function fetchBody(string $url): string
{
$http = new WireHttp();
$content = $http->get($url);

if (!$content) {
return '';
}

return $content;
}

private static function hasContentType(
string $expected,
array $content_types
) {
foreach ($content_types as $content_type) {
if (stripos($content_type, $expected) !== false) {
return true;
}
}

return false;
}
}

0 comments on commit ebd19be

Please sign in to comment.