diff --git a/composer.json b/composer.json index d957407..63dfb2b 100644 --- a/composer.json +++ b/composer.json @@ -4,7 +4,7 @@ "mf2/mf2": "^0.4.3", "indieweb/mention-client": "~1.1", "indieweb/representative-h-card": "0.1.*", - "indieauth/client": "0.2.*", + "indieauth/client": "^1.0", "firebase/php-jwt": "~3.0", "league/route": "~1.2", "league/plates": "~3.1", diff --git a/composer.lock b/composer.lock index b4310a3..355be3c 100644 --- a/composer.lock +++ b/composer.lock @@ -1,51 +1,11 @@ { "_readme": [ "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "d36cff93d0bbe63f248f5c5ad541f2c9", + "content-hash": "2e3a9f1ddef93aa21e064fcee6c98176", "packages": [ - { - "name": "barnabywalters/mf-cleaner", - "version": "v0.1.4", - "source": { - "type": "git", - "url": "https://github.com/barnabywalters/php-mf-cleaner.git", - "reference": "ef6a16628db6e8aee2b4f8bb8093d18c24b74cd4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/barnabywalters/php-mf-cleaner/zipball/ef6a16628db6e8aee2b4f8bb8093d18c24b74cd4", - "reference": "ef6a16628db6e8aee2b4f8bb8093d18c24b74cd4", - "shasum": "" - }, - "require-dev": { - "php": ">=5.3", - "phpunit/phpunit": "*" - }, - "suggest": { - "mf2/mf2": "To parse microformats2 structures from (X)HTML" - }, - "type": "library", - "autoload": { - "files": [ - "src/BarnabyWalters/Mf2/Functions.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Barnaby Walters", - "email": "barnaby@waterpigs.co.uk" - } - ], - "description": "Cleans up microformats2 array structures", - "time": "2014-10-06T23:11:15+00:00" - }, { "name": "camspiers/json-pretty", "version": "1.0.2", @@ -400,24 +360,27 @@ }, { "name": "indieauth/client", - "version": "0.2.2", + "version": "1.0.1", "source": { "type": "git", "url": "https://github.com/indieweb/indieauth-client-php.git", - "reference": "225ece31ddafaee3348eabdc915422c457498a84" + "reference": "d551eeb268100b87ebc7a05ae796a858550e700a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/indieweb/indieauth-client-php/zipball/225ece31ddafaee3348eabdc915422c457498a84", - "reference": "225ece31ddafaee3348eabdc915422c457498a84", + "url": "https://api.github.com/repos/indieweb/indieauth-client-php/zipball/d551eeb268100b87ebc7a05ae796a858550e700a", + "reference": "d551eeb268100b87ebc7a05ae796a858550e700a", "shasum": "" }, "require": { - "barnabywalters/mf-cleaner": "0.*", - "indieweb/link-rel-parser": "0.1.*", - "mf2/mf2": "~0.3", + "indieweb/representative-h-card": "^0.1.2", + "mf2/mf2": ">=0.3.2", + "p3k/http": ">=0.1.6", "php": ">5.3.0" }, + "require-dev": { + "phpunit/phpunit": "4.8.*" + }, "type": "library", "autoload": { "psr-0": { @@ -426,16 +389,16 @@ }, "notification-url": "https://packagist.org/downloads/", "license": [ - "Apache 2.0" + "Apache-2.0" ], "authors": [ { "name": "Aaron Parecki", - "homepage": "http://aaronparecki.com" + "homepage": "https://aaronparecki.com" } ], "description": "IndieAuth Client Library", - "time": "2017-07-01T15:43:45+00:00" + "time": "2020-11-26T19:41:45+00:00" }, { "name": "indieweb/link-rel-parser", @@ -1385,12 +1348,12 @@ "version": "v1.0.3", "source": { "type": "git", - "url": "https://github.com/nrk/predis.git", + "url": "https://github.com/predis/predis.git", "reference": "84060b9034d756b4d79641667d7f9efe1aeb8e04" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nrk/predis/zipball/84060b9034d756b4d79641667d7f9efe1aeb8e04", + "url": "https://api.github.com/repos/predis/predis/zipball/84060b9034d756b4d79641667d7f9efe1aeb8e04", "reference": "84060b9034d756b4d79641667d7f9efe1aeb8e04", "shasum": "" }, @@ -1740,10 +1703,51 @@ "xml", "zf" ], + "abandoned": "laminas/laminas-xml", "time": "2018-04-30T15:11:04+00:00" } ], "packages-dev": [ + { + "name": "barnabywalters/mf-cleaner", + "version": "v0.1.4", + "source": { + "type": "git", + "url": "https://github.com/barnabywalters/php-mf-cleaner.git", + "reference": "ef6a16628db6e8aee2b4f8bb8093d18c24b74cd4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/barnabywalters/php-mf-cleaner/zipball/ef6a16628db6e8aee2b4f8bb8093d18c24b74cd4", + "reference": "ef6a16628db6e8aee2b4f8bb8093d18c24b74cd4", + "shasum": "" + }, + "require-dev": { + "php": ">=5.3", + "phpunit/phpunit": "*" + }, + "suggest": { + "mf2/mf2": "To parse microformats2 structures from (X)HTML" + }, + "type": "library", + "autoload": { + "files": [ + "src/BarnabyWalters/Mf2/Functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Barnaby Walters", + "email": "barnaby@waterpigs.co.uk" + } + ], + "description": "Cleans up microformats2 array structures", + "time": "2014-10-06T23:11:15+00:00" + }, { "name": "doctrine/instantiator", "version": "1.0.5", @@ -2190,6 +2194,7 @@ "keywords": [ "tokenizer" ], + "abandoned": true, "time": "2015-09-15T10:49:45+00:00" }, { @@ -2321,6 +2326,7 @@ "mock", "xunit" ], + "abandoned": true, "time": "2016-03-24T05:58:25+00:00" }, { @@ -2893,5 +2899,6 @@ "platform": { "php": ">=5.5" }, - "platform-dev": [] + "platform-dev": [], + "plugin-api-version": "1.1.0" } diff --git a/controllers/Auth.php b/controllers/Auth.php index f520756..7d21257 100644 --- a/controllers/Auth.php +++ b/controllers/Auth.php @@ -41,14 +41,29 @@ class Auth { return $response; } + // Check if the user's URL defines an authorization endpoint + $authorizationEndpoint = IndieAuth\Client::discoverAuthorizationEndpoint($me); + if(!$authorizationEndpoint) { + $authorizationEndpoint = Config::$defaultAuthorizationEndpoint; + } + + $codeVerifier = IndieAuth\Client::generatePKCECodeVerifier(); $state = JWT::encode([ + 'az' => $authorizationEndpoint, 'me' => $me, + 'code_verifier' => $codeVerifier, 'return_to' => $request->get('return_to'), 'time' => time(), 'exp' => time()+300 // verified by the JWT library ], Config::$secretKey); - $authorizationURL = IndieAuth\Client::buildAuthorizationURL(Config::$defaultAuthorizationEndpoint, $me, self::_buildRedirectURI(), Config::$clientID, $state); + $authorizationURL = IndieAuth\Client::buildAuthorizationURL($authorizationEndpoint, [ + 'me' => $me, + 'redirect_uri' => self::_buildRedirectURI(), + 'client_id' => Config::$clientID, + 'state' => $state, + 'code_verifier' => $codeVerifier, + ]); $response->setStatusCode(302); $response->headers->set('Location', $authorizationURL); @@ -87,26 +102,46 @@ class Auth { return $response; } - $authorizationEndpoint = Config::$defaultAuthorizationEndpoint; + $authorizationEndpoint = $state->az; // Verify the code with the auth server - $token = IndieAuth\Client::verifyIndieAuthCode($authorizationEndpoint, $request->get('code'), $state->me, self::_buildRedirectURI(), Config::$clientID, true); - - if(!array_key_exists('auth', $token) || !array_key_exists('me', $token['auth'])) { - // The auth server didn't return a "me" URL + $data = IndieAuth\Client::exchangeAuthorizationCode($state->az, [ + 'code' => $request->get('code'), + 'redirect_uri' => self::_buildRedirectURI(), + 'client_id' => Config::$clientID, + 'code_verifier' => $state->code_verifier, + ]); + + if(!isset($data['response']['me'])) { + // The authorization server didn't return a "me" URL $response->setContent(view('login', [ 'title' => 'Sign In to Telegraph', 'error' => 'Invalid Auth Server Response', - 'error_description' => 'The authorization server ('.$authorizationEndpoint.') did not return a valid response:
HTTP '.$token['response_code']."\n\n".htmlspecialchars($token['response']).'
' + 'error_description' => 'The authorization server ('.$authorizationEndpoint.') did not return a valid response:
HTTP '.$data['response_code']."\n\n".htmlspecialchars(json_encode($data)).'
' ])); return $response; } + // Verify the authorization endpoint matches + if($data['response']['me'] != $state->me) { + $newAuthorizationEndpoint = IndieAuth\Client::discoverAuthorizationEndpoint($data['response']['me']); + if($newAuthorizationEndpoint != $authorizationEndpoint) { + $response->setContent(view('login', [ + 'title' => 'Sign In to Telegraph', + 'error' => 'Invalid Authorization Endpoint', + 'error_description' => 'The authorization endpoint for the returned profile URL ('.$data['response']['me'].') did not match the authorization endpoint used to begin the login.' + ])); + return $response; + } + } + + $me = $data['response']['me']; + // Create or load the user - $user = ORM::for_table('users')->where('url', $token['auth']['me'])->find_one(); + $user = ORM::for_table('users')->where('url', $me)->find_one(); if(!$user) { $user = ORM::for_table('users')->create(); - $user->url = $token['auth']['me']; + $user->url = $me; $user->created_at = date('Y-m-d H:i:s'); $user->last_login = date('Y-m-d H:i:s'); $user->save(); @@ -114,7 +149,7 @@ class Auth { // Create a site for them with the default role $site = ORM::for_table('sites')->create(); $site->name = 'My Website'; - $site->url = $token['auth']['me']; + $site->url = $me; $site->created_by = $user->id; $site->created_at = date('Y-m-d H:i:s'); $site->save();