From 84012ca2fdfeeaae51c3e540ba3f183fc658e5df Mon Sep 17 00:00:00 2001 From: Toby Zerner Date: Mon, 7 Sep 2015 08:37:33 +0930 Subject: [PATCH] Preliminary implementation of master API keys Part of #205 --- ...015_02_24_000000_create_api_keys_table.php | 38 +++++++++++++ src/Api/ApiKey.php | 57 +++++++++++++++++++ src/Api/Middleware/LoginWithHeader.php | 24 ++++++-- 3 files changed, 113 insertions(+), 6 deletions(-) create mode 100644 migrations/2015_02_24_000000_create_api_keys_table.php create mode 100644 src/Api/ApiKey.php diff --git a/migrations/2015_02_24_000000_create_api_keys_table.php b/migrations/2015_02_24_000000_create_api_keys_table.php new file mode 100644 index 000000000..0ea0c6a8f --- /dev/null +++ b/migrations/2015_02_24_000000_create_api_keys_table.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Flarum\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; + +class CreateApiKeysTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + $this->schema->create('api_keys', function (Blueprint $table) { + $table->string('id', 100)->primary(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + $this->schema->drop('api_keys'); + } +} diff --git a/src/Api/ApiKey.php b/src/Api/ApiKey.php new file mode 100644 index 000000000..eee9552b1 --- /dev/null +++ b/src/Api/ApiKey.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Flarum\Api; + +use Flarum\Core\Model; +use DateTime; + +/** + * @todo document database columns with @property + */ +class ApiKey extends Model +{ + /** + * {@inheritdoc} + */ + protected $table = 'api_keys'; + + /** + * Use a custom primary key for this model. + * + * @var bool + */ + public $incrementing = false; + + /** + * Generate an API key. + * + * @return static + */ + public static function generate() + { + $key = new static; + + $key->id = str_random(40); + + return $key; + } + + /** + * Get the given key only if it is valid. + * + * @param string $key + * @return static|null + */ + public static function valid($key) + { + return static::where('id', $key)->first(); + } +} diff --git a/src/Api/Middleware/LoginWithHeader.php b/src/Api/Middleware/LoginWithHeader.php index 7eb890b0a..1a66456af 100644 --- a/src/Api/Middleware/LoginWithHeader.php +++ b/src/Api/Middleware/LoginWithHeader.php @@ -11,6 +11,8 @@ namespace Flarum\Api\Middleware; use Flarum\Api\AccessToken; +use Flarum\Api\ApiKey; +use Flarum\Core\Users\User; use Illuminate\Contracts\Container\Container; use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; @@ -42,13 +44,23 @@ class LoginWithHeader implements MiddlewareInterface public function __invoke(Request $request, Response $response, callable $out = null) { $header = $request->getHeaderLine('authorization'); - if (starts_with($header, $this->prefix) && - ($token = substr($header, strlen($this->prefix))) && - ($accessToken = AccessToken::valid($token)) - ) { - $this->app->instance('flarum.actor', $user = $accessToken->user); - $user->updateLastSeen()->save(); + $parts = explode(';', $header); + + if (isset($parts[0]) && starts_with($parts[0], $this->prefix)) { + $token = substr($parts[0], strlen($this->prefix)); + + if ($accessToken = AccessToken::valid($token)) { + $this->app->instance('flarum.actor', $user = $accessToken->user); + + $user->updateLastSeen()->save(); + } elseif (isset($parts[1]) && ($apiKey = ApiKey::valid($token))) { + $userParts = explode('=', trim($parts[1])); + + if (isset($userParts[0]) && $userParts[0] === 'userId') { + $this->app->instance('flarum.actor', $user = User::find($userParts[1])); + } + } } return $out ? $out($request, $response) : $response;