diff --git a/app/config/app.php b/app/config/app.php
index bffe61b3..1f294f4f 100644
--- a/app/config/app.php
+++ b/app/config/app.php
@@ -128,9 +128,10 @@ return [
'Roumen\Feed\FeedServiceProvider',
'Thujohn\Rss\RssServiceProvider',
+ 'CachetHQ\Cachet\Providers\AuthServiceProvider',
+ 'CachetHQ\Cachet\Providers\ConsoleServiceProvider',
'CachetHQ\Cachet\Providers\RepositoryServiceProvider',
'CachetHQ\Cachet\Providers\RoutingServiceProvider',
- 'CachetHQ\Cachet\Providers\ConsoleServiceProvider',
],
diff --git a/app/config/packages/dingo/api/config.php b/app/config/packages/dingo/api/config.php
index 440c5aff..5c1e2965 100644
--- a/app/config/packages/dingo/api/config.php
+++ b/app/config/packages/dingo/api/config.php
@@ -76,9 +76,15 @@ return [
*/
'auth' => [
+
'basic' => function ($app) {
return new Dingo\Api\Auth\BasicProvider($app['auth']);
},
+
+ 'api_key' => function ($app) {
+ return new CachetHQ\Cachet\Auth\ApiKeyAuthenticator();
+ },
+
],
/*
diff --git a/app/database/migrations/2015_01_03_120438_AlterTableUsersAddApiKey.php b/app/database/migrations/2015_01_03_120438_AlterTableUsersAddApiKey.php
new file mode 100644
index 00000000..4735512b
--- /dev/null
+++ b/app/database/migrations/2015_01_03_120438_AlterTableUsersAddApiKey.php
@@ -0,0 +1,32 @@
+string('api_key')->after('email');
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::table('users', function (Blueprint $table) {
+ $table->dropColumn();
+ });
+ }
+}
diff --git a/app/routes/dashboard.php b/app/routes/dashboard.php
index 2adb886e..2974c015 100644
--- a/app/routes/dashboard.php
+++ b/app/routes/dashboard.php
@@ -37,6 +37,7 @@ Route::group(['before' => 'auth', 'prefix' => 'dashboard', 'namespace' => 'Cache
// User Settings
Route::get('user', ['as' => 'dashboard.user', 'uses' => 'DashUserController@showUser']);
+ Route::get('/user/{user}/api/regen', 'DashUserController@regenerateApiKey');
Route::post('user', 'DashUserController@postUser');
// Internal API.
diff --git a/app/views/dashboard/user/index.blade.php b/app/views/dashboard/user/index.blade.php
index 87101e5b..80794231 100644
--- a/app/views/dashboard/user/index.blade.php
+++ b/app/views/dashboard/user/index.blade.php
@@ -33,9 +33,16 @@
+
+
+
+
+ Regenerating your API key will revoke all existing applications.
+
+ Regenerate API Key
diff --git a/src/Auth/ApiKeyAuthenticator.php b/src/Auth/ApiKeyAuthenticator.php
new file mode 100644
index 00000000..64cd9711
--- /dev/null
+++ b/src/Auth/ApiKeyAuthenticator.php
@@ -0,0 +1,48 @@
+input('api_key', false);
+
+ if ($api_key === false) {
+ throw new UnauthorizedHttpException(null, 'You did not provide an API key.');
+ }
+
+ try {
+ return User::findByApiKey($api_key);
+ } catch (ModelNotFoundException $e) {
+ throw new UnauthorizedHttpException(null, 'The API key you provided was not correct.');
+ }
+ }
+
+ /**
+ * Get the providers authorization method.
+ *
+ * @return string
+ */
+ public function getAuthorizationMethod()
+ {
+ return 'api_key';
+ }
+}
diff --git a/src/Http/Controllers/DashUserController.php b/src/Http/Controllers/DashUserController.php
index fcdca258..d664e296 100644
--- a/src/Http/Controllers/DashUserController.php
+++ b/src/Http/Controllers/DashUserController.php
@@ -2,6 +2,7 @@
namespace CachetHQ\Cachet\Http\Controllers;
+use CachetHQ\Cachet\Models\User;
use GrahamCampbell\Binput\Facades\Binput;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Auth;
@@ -35,4 +36,17 @@ class DashUserController extends Controller
return Redirect::back()->with('updated', $updated);
}
+
+ /**
+ * Regenerates the users API key.
+ *
+ * @return \Illuminate\View\View
+ */
+ public function regenerateApiKey(User $user)
+ {
+ $user->api_key = User::generateApiKey();
+ $user->save();
+
+ return Redirect::back();
+ }
}
diff --git a/src/Models/User.php b/src/Models/User.php
index c48afad3..2d122f61 100644
--- a/src/Models/User.php
+++ b/src/Models/User.php
@@ -7,6 +7,7 @@ use Illuminate\Auth\Reminders\RemindableTrait;
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\UserTrait;
use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Support\Facades\Hash;
/**
@@ -47,6 +48,20 @@ class User extends Model implements UserInterface, RemindableInterface
*/
protected $guarded = [];
+ /**
+ * Overrides the models boot method.
+ *
+ * @return void
+ */
+ public static function boot()
+ {
+ parent::boot();
+
+ self::creating(function ($user) {
+ $user->api_key = self::generateApiKey();
+ });
+ }
+
/**
* Hash any password being inserted by default.
*
@@ -72,4 +87,35 @@ class User extends Model implements UserInterface, RemindableInterface
{
return sprintf('https://www.gravatar.com/avatar/%s?size=%d', md5($this->email), $size);
}
+
+ /**
+ * Find by api_key, or throw an exception.
+ *
+ * @param string $api_key
+ * @param string[] $columns
+ *
+ * @throws \Illuminate\Database\Eloquent\ModelNotFoundException
+ *
+ * @return \CachetHQ\Cachet\Models\User
+ */
+ public static function findByApiKey($api_key, $columns = ['*'])
+ {
+ $user = static::where('api_key', $api_key)->first($columns);
+
+ if (!$user) {
+ throw new ModelNotFoundException();
+ }
+
+ return $user;
+ }
+
+ /**
+ * Returns an API key.
+ *
+ * @return string
+ */
+ public static function generateApiKey()
+ {
+ return str_random(20);
+ }
}
diff --git a/src/Providers/AuthServiceProvider.php b/src/Providers/AuthServiceProvider.php
new file mode 100644
index 00000000..babf42a0
--- /dev/null
+++ b/src/Providers/AuthServiceProvider.php
@@ -0,0 +1,31 @@
+app->bindShared('CachetHQ\Cachet\Auth\ApiKeyAuthenticator', function () {
+ return new ApiKeyAuthenticator();
+ });
+ }
+}