Refactor slightly the indieauth code
This commit is contained in:
parent
4f57905bcc
commit
fe8f871e3a
5 changed files with 70 additions and 59 deletions
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use IndieAuth\Client;
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Services\TokenService;
|
use App\Services\TokenService;
|
||||||
use App\Services\IndieAuthService;
|
use App\Services\IndieAuthService;
|
||||||
|
@ -14,11 +13,6 @@ class IndieAuthController extends Controller
|
||||||
*/
|
*/
|
||||||
protected $indieAuthService;
|
protected $indieAuthService;
|
||||||
|
|
||||||
/**
|
|
||||||
* The IndieAuth Client implementation.
|
|
||||||
*/
|
|
||||||
protected $client;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Token handling service.
|
* The Token handling service.
|
||||||
*/
|
*/
|
||||||
|
@ -28,16 +22,14 @@ class IndieAuthController extends Controller
|
||||||
* Inject the dependencies.
|
* Inject the dependencies.
|
||||||
*
|
*
|
||||||
* @param \App\Services\IndieAuthService $indieAuthService
|
* @param \App\Services\IndieAuthService $indieAuthService
|
||||||
* @param \IndieAuth\Client $client
|
* @param \App\Services\TokenService $tokenService
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
IndieAuthService $indieAuthService = null,
|
IndieAuthService $indieAuthService = null,
|
||||||
Client $client = null,
|
|
||||||
TokenService $tokenService = null
|
TokenService $tokenService = null
|
||||||
) {
|
) {
|
||||||
$this->indieAuthService = $indieAuthService ?? new IndieAuthService();
|
$this->indieAuthService = $indieAuthService ?? new IndieAuthService();
|
||||||
$this->client = $client ?? new Client();
|
|
||||||
$this->tokenService = $tokenService ?? new TokenService();
|
$this->tokenService = $tokenService ?? new TokenService();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,21 +45,19 @@ class IndieAuthController extends Controller
|
||||||
public function start(Request $request)
|
public function start(Request $request)
|
||||||
{
|
{
|
||||||
$authorizationEndpoint = $this->indieAuthService->getAuthorizationEndpoint(
|
$authorizationEndpoint = $this->indieAuthService->getAuthorizationEndpoint(
|
||||||
$request->input('me'),
|
$request->input('me')
|
||||||
$this->client
|
|
||||||
);
|
);
|
||||||
if ($authorizationEndpoint) {
|
if ($authorizationEndpoint !== null) {
|
||||||
$authorizationURL = $this->indieAuthService->buildAuthorizationURL(
|
$authorizationURL = $this->indieAuthService->buildAuthorizationURL(
|
||||||
$authorizationEndpoint,
|
$authorizationEndpoint,
|
||||||
$request->input('me'),
|
$request->input('me')
|
||||||
$this->client
|
|
||||||
);
|
);
|
||||||
if ($authorizationURL) {
|
if ($authorizationURL) {
|
||||||
return redirect($authorizationURL);
|
return redirect($authorizationURL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect(route('micropub-client'))->withErrors('Unable to determine authorisation endpoint', 'indieauth');
|
return redirect(route('micropub-client'))->with('error', 'Unable to determine authorisation endpoint');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -80,14 +70,17 @@ class IndieAuthController extends Controller
|
||||||
public function callback(Request $request)
|
public function callback(Request $request)
|
||||||
{
|
{
|
||||||
if ($request->session()->get('state') != $request->input('state')) {
|
if ($request->session()->get('state') != $request->input('state')) {
|
||||||
return redirect(route('micropub-client'))->withErrors(
|
return redirect(route('micropub-client'))->with(
|
||||||
'Invalid <code>state</code> value returned from indieauth server',
|
'error',
|
||||||
'indieauth'
|
'Invalid <code>state</code> value returned from indieauth server'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
$tokenEndpoint = $this->indieAuthService->getTokenEndpoint($request->input('me'), $this->client);
|
$tokenEndpoint = $this->indieAuthService->getTokenEndpoint($request->input('me'));
|
||||||
if ($tokenEndpoint === false) {
|
if ($tokenEndpoint === false) {
|
||||||
return redirect(route('micropub-client'))->withErrors('Unable to determine token endpoint', 'indieauth');
|
return redirect(route('micropub-client'))->with(
|
||||||
|
'error',
|
||||||
|
'Unable to determine token endpoint'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
$data = [
|
$data = [
|
||||||
'endpoint' => $tokenEndpoint,
|
'endpoint' => $tokenEndpoint,
|
||||||
|
@ -97,7 +90,7 @@ class IndieAuthController extends Controller
|
||||||
'client_id' => route('micropub-client'),
|
'client_id' => route('micropub-client'),
|
||||||
'state' => $request->input('state'),
|
'state' => $request->input('state'),
|
||||||
];
|
];
|
||||||
$token = $this->indieAuthService->getAccessToken($data, $this->client);
|
$token = $this->indieAuthService->getAccessToken($data);
|
||||||
|
|
||||||
if (array_key_exists('access_token', $token)) {
|
if (array_key_exists('access_token', $token)) {
|
||||||
$request->session()->put('me', $token['me']);
|
$request->session()->put('me', $token['me']);
|
||||||
|
@ -106,7 +99,10 @@ class IndieAuthController extends Controller
|
||||||
return redirect(route('micropub-client'));
|
return redirect(route('micropub-client'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect(route('micropub-client'))->withErrors('Unable to get a token from the endpoint', 'indieauth');
|
return redirect(route('micropub-client'))->with(
|
||||||
|
'error',
|
||||||
|
'Unable to get a token from the endpoint'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -136,7 +132,7 @@ class IndieAuthController extends Controller
|
||||||
'client_id' => $request->input('client_id'),
|
'client_id' => $request->input('client_id'),
|
||||||
'state' => $request->input('state'),
|
'state' => $request->input('state'),
|
||||||
];
|
];
|
||||||
$auth = $this->indieAuthService->verifyIndieAuthCode($authData, $this->client);
|
$auth = $this->indieAuthService->verifyIndieAuthCode($authData);
|
||||||
if (array_key_exists('me', $auth)) {
|
if (array_key_exists('me', $auth)) {
|
||||||
$scope = $auth['scope'] ?? '';
|
$scope = $auth['scope'] ?? '';
|
||||||
$tokenData = [
|
$tokenData = [
|
||||||
|
|
|
@ -1,20 +1,34 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Services;
|
namespace App\Services;
|
||||||
|
|
||||||
|
use IndieAuth\Client;
|
||||||
|
|
||||||
class IndieAuthService
|
class IndieAuthService
|
||||||
{
|
{
|
||||||
|
protected $client;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->client = new Client();
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Given a domain, determing the assocaited authorization endpoint,
|
* Given a domain, determing the assocaited authorization endpoint,
|
||||||
* if one exists.
|
* if one exists.
|
||||||
*
|
*
|
||||||
* @param string The domain
|
* @param string The domain
|
||||||
* @param \IndieAuth\Client $client
|
|
||||||
* @return string|null
|
* @return string|null
|
||||||
*/
|
*/
|
||||||
public function getAuthorizationEndpoint($domain, $client)
|
public function getAuthorizationEndpoint(string $domain): ?string
|
||||||
{
|
{
|
||||||
return $client->discoverAuthorizationEndpoint($client->normalizeMeURL($domain));
|
$endpoint = $this->client->discoverAuthorizationEndpoint($this->client->normalizeMeURL($domain));
|
||||||
|
if ($endpoint === false) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $endpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -22,20 +36,18 @@ class IndieAuthService
|
||||||
*
|
*
|
||||||
* @param string $authEndpoint
|
* @param string $authEndpoint
|
||||||
* @param string $domain
|
* @param string $domain
|
||||||
* @param \IndieAuth\Client $client
|
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function buildAuthorizationURL($authEndpoint, $domain, $client)
|
public function buildAuthorizationURL(string $authEndpoint, string $domain): string
|
||||||
{
|
{
|
||||||
$domain = $client->normalizeMeURL($domain);
|
|
||||||
$state = bin2hex(openssl_random_pseudo_bytes(16));
|
$state = bin2hex(openssl_random_pseudo_bytes(16));
|
||||||
session(['state' => $state]);
|
session(['state' => $state]);
|
||||||
$redirectURL = route('indieauth-callback');
|
$redirectURL = route('indieauth-callback');
|
||||||
$clientId = route('micropub-client');
|
$clientId = route('micropub-client');
|
||||||
$scope = 'post';
|
$scope = 'post';
|
||||||
$authorizationURL = $client->buildAuthorizationURL(
|
$authorizationURL = $this->client->buildAuthorizationURL(
|
||||||
$authEndpoint,
|
$authEndpoint,
|
||||||
$domain,
|
$this->client->normalizeMeURL($domain),
|
||||||
$redirectURL,
|
$redirectURL,
|
||||||
$clientId,
|
$clientId,
|
||||||
$state,
|
$state,
|
||||||
|
@ -49,24 +61,22 @@ class IndieAuthService
|
||||||
* Discover the token endpoint for a given domain.
|
* Discover the token endpoint for a given domain.
|
||||||
*
|
*
|
||||||
* @param string The domain
|
* @param string The domain
|
||||||
* @param \IndieAuth\Client $client
|
|
||||||
* @return string|null
|
* @return string|null
|
||||||
*/
|
*/
|
||||||
public function getTokenEndpoint($domain, $client)
|
public function getTokenEndpoint(string $domain): ?string
|
||||||
{
|
{
|
||||||
return $client->discoverTokenEndpoint($domain);
|
return $this->client->discoverTokenEndpoint($this->client->normalizeMeURL($domain));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve a token from the token endpoint.
|
* Retrieve a token from the token endpoint.
|
||||||
*
|
*
|
||||||
* @param array The relavent data
|
* @param array The relavent data
|
||||||
* @param \IndieAuth\Client $client
|
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getAccessToken(array $data, $client)
|
public function getAccessToken(array $data): array
|
||||||
{
|
{
|
||||||
return $client->getAccessToken(
|
return $this->client->getAccessToken(
|
||||||
$data['endpoint'],
|
$data['endpoint'],
|
||||||
$data['code'],
|
$data['code'],
|
||||||
$data['me'],
|
$data['me'],
|
||||||
|
@ -81,14 +91,13 @@ class IndieAuthService
|
||||||
* valid.
|
* valid.
|
||||||
*
|
*
|
||||||
* @param array The data.
|
* @param array The data.
|
||||||
* @param \IndieAuth\Client $client
|
|
||||||
* @return array|null
|
* @return array|null
|
||||||
*/
|
*/
|
||||||
public function verifyIndieAuthCode(array $data, $client)
|
public function verifyIndieAuthCode(array $data): ?array
|
||||||
{
|
{
|
||||||
$authEndpoint = $client->discoverAuthorizationEndpoint($data['me']);
|
$authEndpoint = $this->client->discoverAuthorizationEndpoint($data['me']);
|
||||||
if ($authEndpoint) {
|
if ($authEndpoint) {
|
||||||
return $client->verifyIndieAuthCode(
|
return $this->client->verifyIndieAuthCode(
|
||||||
$authEndpoint,
|
$authEndpoint,
|
||||||
$data['code'],
|
$data['code'],
|
||||||
$data['me'],
|
$data['me'],
|
||||||
|
@ -103,11 +112,10 @@ class IndieAuthService
|
||||||
* Determine the micropub endpoint.
|
* Determine the micropub endpoint.
|
||||||
*
|
*
|
||||||
* @param string $domain
|
* @param string $domain
|
||||||
* @param \IndieAuth\Client $client
|
* @return string|null The endpoint
|
||||||
* @return string The endpoint
|
|
||||||
*/
|
*/
|
||||||
public function discoverMicropubEndpoint($domain, $client)
|
public function discoverMicropubEndpoint(string $domain): ?string
|
||||||
{
|
{
|
||||||
return $client->discoverMicropubEndpoint($client->normalizeMeURL($domain));
|
return $this->client->discoverMicropubEndpoint($this->client->normalizeMeURL($domain));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,7 +109,7 @@ Route::group(['domain' => config('url.longurl')], function () {
|
||||||
Route::get('notes/tagged/{tag}', 'NotesController@tagged');
|
Route::get('notes/tagged/{tag}', 'NotesController@tagged');
|
||||||
|
|
||||||
//indieauth
|
//indieauth
|
||||||
Route::any('indieauth/start', 'IndieAuthController@start')->name('indieauth-start');
|
Route::post('indieauth/start', 'IndieAuthController@start')->name('indieauth-start');
|
||||||
Route::get('indieauth/callback', 'IndieAuthController@callback')->name('indieauth-callback');
|
Route::get('indieauth/callback', 'IndieAuthController@callback')->name('indieauth-callback');
|
||||||
Route::get('logout', 'IndieAuthController@logout')->name('indieauth-logout');
|
Route::get('logout', 'IndieAuthController@logout')->name('indieauth-logout');
|
||||||
Route::post('api/token', 'IndieAuthController@tokenEndpoint'); //hmmm?
|
Route::post('api/token', 'IndieAuthController@tokenEndpoint'); //hmmm?
|
||||||
|
|
|
@ -15,8 +15,8 @@ class IndieAuthControllerTest extends TestCase
|
||||||
*/
|
*/
|
||||||
public function test_indieauthcontroller_begin_auth_flow_redirects_back_to_client_on_error()
|
public function test_indieauthcontroller_begin_auth_flow_redirects_back_to_client_on_error()
|
||||||
{
|
{
|
||||||
$response = $this->call('GET', '/indieauth/start', ['me' => 'http://example.org']);
|
$response = $this->call('POST', '/indieauth/start', ['me' => 'http://example.org']);
|
||||||
$this->assertSame(config('app.url') . '/micropub/create', $response->headers->get('Location'));
|
$this->assertSame(route('micropub-client'), $response->headers->get('Location'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -26,7 +26,7 @@ class IndieAuthControllerTest extends TestCase
|
||||||
*/
|
*/
|
||||||
public function test_indieauthcontroller_begin_auth_redirects_to_endpoint()
|
public function test_indieauthcontroller_begin_auth_redirects_to_endpoint()
|
||||||
{
|
{
|
||||||
$response = $this->call('GET', '/indieauth/start', ['me' => config('app.url')]);
|
$response = $this->call('POST', '/indieauth/start', ['me' => config('app.url')]);
|
||||||
$this->assertSame(
|
$this->assertSame(
|
||||||
'https://indieauth.com/auth?me=',
|
'https://indieauth.com/auth?me=',
|
||||||
substr($response->headers->get('Location'), 0, 30)
|
substr($response->headers->get('Location'), 0, 30)
|
||||||
|
@ -46,6 +46,6 @@ class IndieAuthControllerTest extends TestCase
|
||||||
'indieauth/callback',
|
'indieauth/callback',
|
||||||
['me', config('app.url'), 'state' => 'request-session']
|
['me', config('app.url'), 'state' => 'request-session']
|
||||||
);
|
);
|
||||||
$response->assertSessionHasErrors();
|
$response->assertSessionHas(['error' => 'Invalid <code>state</code> value returned from indieauth server']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,11 +16,22 @@ class IndieAuthServiceTest extends TestCase
|
||||||
public function test_indieauthservice_getauthorizationendpoint_method()
|
public function test_indieauthservice_getauthorizationendpoint_method()
|
||||||
{
|
{
|
||||||
$service = new \App\Services\IndieAuthService();
|
$service = new \App\Services\IndieAuthService();
|
||||||
$client = new \IndieAuth\Client();
|
$result = $service->getAuthorizationEndpoint(config('app.url'));
|
||||||
$result = $service->getAuthorizationEndpoint(config('app.url'), $client);
|
|
||||||
$this->assertEquals('https://indieauth.com/auth', $result);
|
$this->assertEquals('https://indieauth.com/auth', $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the getAuthorizationEndpoint method returns null on failure.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function test_indieauthservice_getauthorizationendpoint_method_returns_null_on_failure()
|
||||||
|
{
|
||||||
|
$service = new \App\Services\IndieAuthService();
|
||||||
|
$result = $service->getAuthorizationEndpoint('http://example.org');
|
||||||
|
$this->assertEquals(null, $result);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that the Service build the correct redirect URL.
|
* Test that the Service build the correct redirect URL.
|
||||||
*
|
*
|
||||||
|
@ -29,11 +40,9 @@ class IndieAuthServiceTest extends TestCase
|
||||||
public function test_indieauthservice_builds_correct_redirect_url()
|
public function test_indieauthservice_builds_correct_redirect_url()
|
||||||
{
|
{
|
||||||
$service = new \App\Services\IndieAuthService();
|
$service = new \App\Services\IndieAuthService();
|
||||||
$client = new \IndieAuth\Client();
|
|
||||||
$result = $service->buildAuthorizationURL(
|
$result = $service->buildAuthorizationURL(
|
||||||
'https://indieauth.com/auth',
|
'https://indieauth.com/auth',
|
||||||
config('app.url'),
|
config('app.url')
|
||||||
$client
|
|
||||||
);
|
);
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
'https://indieauth.com/auth?me=',
|
'https://indieauth.com/auth?me=',
|
||||||
|
@ -49,8 +58,7 @@ class IndieAuthServiceTest extends TestCase
|
||||||
public function test_indieauthservice_gettokenendpoint_method()
|
public function test_indieauthservice_gettokenendpoint_method()
|
||||||
{
|
{
|
||||||
$service = new \App\Services\IndieAuthService();
|
$service = new \App\Services\IndieAuthService();
|
||||||
$client = new \IndieAuth\Client();
|
$result = $service->getTokenEndpoint(config('app.url'));
|
||||||
$result = $service->getTokenEndpoint(config('app.url'), $client);
|
|
||||||
$this->assertEquals(config('app.url') . '/api/token', $result);
|
$this->assertEquals(config('app.url') . '/api/token', $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,8 +70,7 @@ class IndieAuthServiceTest extends TestCase
|
||||||
public function test_indieauthservice_discovermicropubendpoint_method()
|
public function test_indieauthservice_discovermicropubendpoint_method()
|
||||||
{
|
{
|
||||||
$service = new \App\Services\IndieAuthService();
|
$service = new \App\Services\IndieAuthService();
|
||||||
$client = new \IndieAuth\Client();
|
$result = $service->discoverMicropubEndpoint(config('app.url'));
|
||||||
$result = $service->discoverMicropubEndpoint(config('app.url'), $client);
|
|
||||||
$this->assertEquals(config('app.url') . '/api/post', $result);
|
$this->assertEquals(config('app.url') . '/api/post', $result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue