fix: make Lastfm work with Sanctum

This commit is contained in:
Phan An 2020-09-06 23:11:48 +02:00
parent e356e72814
commit d5e2d3ec79
6 changed files with 43 additions and 17 deletions

View file

@ -10,6 +10,7 @@ use App\Services\TokenManager;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Response;
/**
* @group Last.fm integration
@ -22,7 +23,7 @@ class LastfmController extends Controller
/** @var User */
private $currentUser;
public function __construct(LastfmService $lastfmService, TokenManager $tokenManager, Authenticatable $currentUser)
public function __construct(LastfmService $lastfmService, TokenManager $tokenManager, ?Authenticatable $currentUser)
{
$this->lastfmService = $lastfmService;
$this->tokenManager = $tokenManager;
@ -45,7 +46,11 @@ class LastfmController extends Controller
*/
public function connect()
{
abort_unless($this->lastfmService->enabled(), 401, 'Koel is not configured to use with Last.fm yet.');
abort_unless(
$this->lastfmService->enabled(),
Response::HTTP_NOT_IMPLEMENTED,
'Koel is not configured to use with Last.fm yet.'
);
$callbackUrl = urlencode(sprintf(
'%s?api_token=%s',
@ -63,9 +68,11 @@ class LastfmController extends Controller
*/
public function callback(LastfmCallbackRequest $request)
{
$sessionKey = $this->lastfmService->getSessionKey($request->token);
$this->currentUser = $this->tokenManager->getUserFromPlainTextToken($request->api_token);
abort_unless((bool) $this->currentUser, Response::HTTP_UNAUTHORIZED);
abort_unless($sessionKey, 500, 'Invalid token key.');
$sessionKey = $this->lastfmService->getSessionKey($request->token);
abort_unless($sessionKey, Response::HTTP_INTERNAL_SERVER_ERROR, 'Invalid token key.');
$this->currentUser->savePreference('lastfm_session_key', $sessionKey);

View file

@ -3,7 +3,8 @@
namespace App\Http\Requests\API;
/**
* @property string $token
* @property string $token Lastfm's access token
* @property string $api_token Koel's current user's token
*/
class LastfmCallbackRequest extends Request
{
@ -11,6 +12,7 @@ class LastfmCallbackRequest extends Request
{
return [
'token' => 'required',
'api_token' => 'required',
];
}
}

View file

@ -4,6 +4,7 @@ namespace App\Services;
use App\Models\User;
use Laravel\Sanctum\NewAccessToken;
use Laravel\Sanctum\PersonalAccessToken;
class TokenManager
{
@ -16,4 +17,11 @@ class TokenManager
{
$user->tokens()->delete();
}
public function getUserFromPlainTextToken(string $plainTextToken): ?User
{
$token = PersonalAccessToken::findToken($plainTextToken);
return $token ? $token->tokenable : null;
}
}

View file

@ -57,9 +57,7 @@ Route::group(['namespace' => 'API'], function () {
Route::put('me', 'ProfileController@update');
// Last.fm-related routes
Route::get('lastfm/connect', 'LastfmController@connect');
Route::post('lastfm/session-key', 'LastfmController@setSessionKey');
Route::get('lastfm/callback', 'LastfmController@callback')->name('lastfm.callback');
Route::delete('lastfm/disconnect', 'LastfmController@disconnect')->name('lastfm.disconnect');
// YouTube-related routes

View file

@ -14,3 +14,9 @@ Route::get('/♫', function () {
Route::get('/remote', function () {
return view('remote');
});
Route::get('/lastfm/connect', 'API\LastfmController@connect')
->name('lastfm.connect');
Route::get('/lastfm/callback', 'API\LastfmController@callback')
->name('lastfm.callback');

View file

@ -9,7 +9,6 @@ use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Response;
use Illuminate\Contracts\Cache\Repository as Cache;
use Illuminate\Log\Logger;
use Laravel\Sanctum\NewAccessToken;
use Mockery;
class LastfmTest extends TestCase
@ -27,12 +26,12 @@ class LastfmTest extends TestCase
public function testSetSessionKey(): void
{
/** @var User $user */
$user = factory(User::class)->create();
$this->postAsUser('api/lastfm/session-key', ['key' => 'foo'], $user)
->assertOk();
$user = User::find($user->id);
self::assertEquals('foo', $user->lastfm_session_key);
self::assertEquals('foo', $user->refresh()->lastfm_session_key);
}
public function testConnectToLastfm(): void
@ -41,27 +40,33 @@ class LastfmTest extends TestCase
$user = factory(User::class)->create();
$token = $user->createToken('Koel')->plainTextToken;
$this->getAsUser('api/lastfm/connect?api_token='.$token, $user)
$this->get('lastfm/connect?api_token='.$token)
->assertRedirect(
'https://www.last.fm/api/auth/?api_key=foo&cb=http%3A%2F%2Flocalhost%2Fapi%2Flastfm%2Fcallback%3Fapi_token%3D'
'https://www.last.fm/api/auth/?api_key=foo&cb=http%3A%2F%2Flocalhost%2Flastfm%2Fcallback%3Fapi_token%3D'
.urlencode($token)
);
}
public function testRetrieveAndStoreSessionKey(): void
{
/** @var User $user */
$user = factory(User::class)->create();
$lastfm = static::mockIocDependency(LastfmService::class);
$lastfm->shouldReceive('getSessionKey')
->once()
->with('foo')
->andReturn('bar');
/** @var User $user */
$user = factory(User::class)->create();
$this->getAsUser('api/lastfm/callback?token=foo', $user);
$user->refresh();
$tokenManager = static::mockIocDependency(TokenManager::class);
$tokenManager->shouldReceive('getUserFromPlainTextToken')
->once()
->with('my-token')
->andReturn($user);
self::assertEquals('bar', $user->lastfm_session_key);
$this->get('lastfm/callback?token=foo&api_token=my-token');
self::assertEquals('bar', $user->refresh()->lastfm_session_key);
}
public function testDisconnectUser(): void