diff --git a/app/Console/Commands/ActivateApiKey.php b/app/Console/Commands/ActivateApiKey.php new file mode 100644 index 0000000..eb35525 --- /dev/null +++ b/app/Console/Commands/ActivateApiKey.php @@ -0,0 +1,63 @@ +argument('name'); + $error = $this->validateName($name); + if ($error) { + $this->error($error); + return; + } + $key = ApiKey::where('name', $name)->first(); + if ($key->active) { + $this->info('Key "' . $name . '" is already active'); + return; + } + $key->active = 1; + $key->save(); + $this->info('Activated key: ' . $name); + } + /** + * Validate name + * + * @param string $name + * @return string + */ + protected function validateName($name) + { + if (!ApiKey::isValidName($name)) { + return self::MESSAGE_ERROR_INVALID_NAME; + } + if (!ApiKey::nameExists($name)) { + return self::MESSAGE_ERROR_NAME_DOES_NOT_EXIST; + } + return null; + } +} diff --git a/app/Console/Commands/DeactivateApiKey.php b/app/Console/Commands/DeactivateApiKey.php new file mode 100644 index 0000000..4302809 --- /dev/null +++ b/app/Console/Commands/DeactivateApiKey.php @@ -0,0 +1,63 @@ +argument('name'); + $error = $this->validateName($name); + if ($error) { + $this->error($error); + return; + } + $key = ApiKey::where('name', $name)->first(); + if (!$key->active) { + $this->info('Key "' . $name . '" is already deactivated'); + return; + } + $key->active = 0; + $key->save(); + $this->info('Deactivated key: ' . $name); + } + /** + * Validate name + * + * @param string $name + * @return string + */ + protected function validateName($name) + { + if (!ApiKey::isValidName($name)) { + return self::MESSAGE_ERROR_INVALID_NAME; + } + if (!ApiKey::nameExists($name)) { + return self::MESSAGE_ERROR_NAME_DOES_NOT_EXIST; + } + return null; + } +} diff --git a/app/Console/Commands/DeleteApiKey.php b/app/Console/Commands/DeleteApiKey.php new file mode 100644 index 0000000..9f1056f --- /dev/null +++ b/app/Console/Commands/DeleteApiKey.php @@ -0,0 +1,62 @@ +argument('name'); + $error = $this->validateName($name); + if ($error) { + $this->error($error); + return; + } + $confirmMessage = 'Are you sure you want to delete API key \'' . $name . '\'?'; + if (!$this->confirm($confirmMessage)) { + return; + } + $key = ApiKey::where('name', $name)->first(); + $key->delete(); + $this->info('Deleted key: ' . $name); + } + /** + * Validate name + * + * @param string $name + * @return string + */ + protected function validateName($name) + { + if (!ApiKey::isValidName($name)) { + return self::MESSAGE_ERROR_INVALID_NAME; + } + if (!ApiKey::nameExists($name)) { + return self::MESSAGE_ERROR_NAME_DOES_NOT_EXIST; + } + return null; + } +} diff --git a/app/Console/Commands/GenerateApiKey.php b/app/Console/Commands/GenerateApiKey.php new file mode 100644 index 0000000..af1adac --- /dev/null +++ b/app/Console/Commands/GenerateApiKey.php @@ -0,0 +1,62 @@ +argument('name'); + $error = $this->validateName($name); + if ($error) { + $this->error($error); + return; + } + $apiKey = new ApiKey; + $apiKey->name = $name; + $apiKey->key = ApiKey::generate(); + $apiKey->save(); + $this->info('API key created'); + $this->info('Name: ' . $apiKey->name); + $this->info('Key: ' . $apiKey->key); + } + /** + * Validate name + * + * @param string $name + * @return string + */ + protected function validateName($name) + { + if (!ApiKey::isValidName($name)) { + return self::MESSAGE_ERROR_INVALID_NAME_FORMAT; + } + if (ApiKey::nameExists($name)) { + return self::MESSAGE_ERROR_NAME_ALREADY_USED; + } + return null; + } +} diff --git a/app/Console/Commands/ListApiKeys.php b/app/Console/Commands/ListApiKeys.php new file mode 100644 index 0000000..3124f2f --- /dev/null +++ b/app/Console/Commands/ListApiKeys.php @@ -0,0 +1,49 @@ +option('deleted') + ? ApiKey::withTrashed()->orderBy('name')->get() + : ApiKey::orderBy('name')->get(); + if ($keys->count() === 0) { + $this->info('There are no API keys'); + return; + } + $headers = ['Name', 'ID', 'Status', 'Status Date', 'Key']; + $rows = $keys->map(function ($key) { + $status = $key->active ? 'active' : 'deactivated'; + $status = $key->trashed() ? 'deleted' : $status; + $statusDate = $key->deleted_at ?: $key->updated_at; + return [ + $key->name, + $key->id, + $status, + $statusDate, + $key->key + ]; + }); + $this->table($headers, $rows); + } +} diff --git a/app/Http/Controllers/NewHostController.php b/app/Http/Controllers/NewHostController.php new file mode 100644 index 0000000..995c80f --- /dev/null +++ b/app/Http/Controllers/NewHostController.php @@ -0,0 +1,10 @@ +header(self::AUTH_HEADER); + $apiKey = ApiKey::getByKey($header); + if ($apiKey instanceof ApiKey) { + $this->logAccessEvent($request, $apiKey); + return $next($request); + } + return response([ + 'errors' => [[ + 'message' => 'Unauthorized' + ]] + ], 401); + } + /** + * Log an API key access event + * + * @param Request $request + * @param ApiKey $apiKey + */ + protected function logAccessEvent(Request $request, ApiKey $apiKey) + { + $event = new ApiKeyAccessEvent; + $event->api_key_id = $apiKey->id; + $event->ip_address = $request->ip(); + $event->url = $request->fullUrl(); + $event->save(); + } +} diff --git a/app/Models/ApiKey.php b/app/Models/ApiKey.php new file mode 100644 index 0000000..403db3b --- /dev/null +++ b/app/Models/ApiKey.php @@ -0,0 +1,140 @@ +hasMany(ApiKeyAccessEvent::class, 'api_key_id'); + } + /** + * Get the related ApiKeyAdminEvents records + * + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function adminEvents() + { + return $this->hasMany(ApiKeyAdminEvent::class, 'api_key_id'); + } + /** + * Bootstrapping event handlers + */ + public static function boot() + { + parent::boot(); + static::created(function (ApiKey $apiKey) { + self::logApiKeyAdminEvent($apiKey, self::EVENT_NAME_CREATED); + }); + static::updated(function ($apiKey) { + $changed = $apiKey->getDirty(); + if (isset($changed) && $changed['active'] === 1) { + self::logApiKeyAdminEvent($apiKey, self::EVENT_NAME_ACTIVATED); + } + if (isset($changed) && $changed['active'] === 0) { + self::logApiKeyAdminEvent($apiKey, self::EVENT_NAME_DEACTIVATED); + } + }); + static::deleted(function ($apiKey) { + self::logApiKeyAdminEvent($apiKey, self::EVENT_NAME_DELETED); + }); + } + /** + * Generate a secure unique API key + * + * @return string + */ + public static function generate() + { + do { + $key = str_random(64); + } while (self::keyExists($key)); + return $key; + } + /** + * Get ApiKey record by key value + * + * @param string $key + * @return bool + */ + public static function getByKey($key) + { + return self::where([ + 'key' => $key, + 'active' => 1 + ])->first(); + } + /** + * Check if key is valid + * + * @param string $key + * @return bool + */ + public static function isValidKey($key) + { + return self::getByKey($key) instanceof self; + } + /** + * Check if name is valid format + * + * @param string $name + * @return bool + */ + public static function isValidName($name) + { + return (bool) preg_match(self::$nameRegex, $name); + } + /** + * Check if a key already exists + * + * Includes soft deleted records + * + * @param string $key + * @return bool + */ + public static function keyExists($key) + { + return self::where('key', $key)->withTrashed()->first() instanceof self; + } + /** + * Check if a name already exists + * + * Does not include soft deleted records + * + * @param string $name + * @return bool + */ + public static function nameExists($name) + { + return self::where('name', $name)->first() instanceof self; + } + /** + * Log an API key admin event + * + * @param ApiKey $apiKey + * @param string $eventName + */ + protected static function logApiKeyAdminEvent(ApiKey $apiKey, $eventName) + { + $event = new ApiKeyAdminEvent; + $event->api_key_id = $apiKey->id; + $event->ip_address = request()->ip(); + $event->event = $eventName; + $event->save(); + } +} diff --git a/app/Models/ApiKeyAccessEvent.php b/app/Models/ApiKeyAccessEvent.php new file mode 100644 index 0000000..b96b604 --- /dev/null +++ b/app/Models/ApiKeyAccessEvent.php @@ -0,0 +1,20 @@ +belongsTo(ApiKey::class, 'api_key_id'); + } +} diff --git a/app/Models/ApiKeyAdminEvent.php b/app/Models/ApiKeyAdminEvent.php new file mode 100644 index 0000000..d5fc22f --- /dev/null +++ b/app/Models/ApiKeyAdminEvent.php @@ -0,0 +1,20 @@ +belongsTo(ApiKey::class, 'api_key_id'); + } +} diff --git a/app/Providers/ApiKeyServiceProvider.php b/app/Providers/ApiKeyServiceProvider.php new file mode 100644 index 0000000..bfb260e --- /dev/null +++ b/app/Providers/ApiKeyServiceProvider.php @@ -0,0 +1,67 @@ +registerMiddleware($router); + $this->registerMigrations(__DIR__ . '/../../database/migrations'); + } + /** + * Register the application services. + * + * @return void + */ + public function register() + { + $this->commands([ + ActivateApiKey::class, + DeactivateApiKey::class, + DeleteApiKey::class, + GenerateApiKey::class, + ListApiKeys::class, + ]); + } + /** + * Register middleware + * + * Support added for different Laravel versions + * + * @param Router $router + */ + protected function registerMiddleware(Router $router) + { + $versionComparison = version_compare(app()->version(), '5.4.0'); + if ($versionComparison >= 0) { + $router->aliasMiddleware('auth.apikey', AuthorizeApiKey::class); + } else { + $router->middleware('auth.apikey', AuthorizeApiKey::class); + } + } + /** + * Register migrations + */ + protected function registerMigrations($migrationsDirectory) + { + $this->publishes([ + $migrationsDirectory => database_path('migrations') + ], 'migrations'); + } +} diff --git a/composer.json b/composer.json index 288180d..a526b3b 100644 --- a/composer.json +++ b/composer.json @@ -10,10 +10,13 @@ "require": { "php": "^7.2", "fideloper/proxy": "^4.0", + "guzzlehttp/guzzle": "^6.4", "laravel/framework": "^6.2", + "laravel/slack-notification-channel": "^2.0", "laravel/tinker": "^1.0" }, "require-dev": { + "barryvdh/laravel-debugbar": "^3.2", "facade/ignition": "^1.4", "fzaninotto/faker": "^1.4", "mockery/mockery": "^1.0", diff --git a/composer.lock b/composer.lock index 29e60f4..9163c96 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "fa503b104f700e4337a4bf209a56bc8a", + "content-hash": "3f94ec0487b1e60ceb87a55dbd092f32", "packages": [ { "name": "dnoegel/php-xdg-base-dir", @@ -380,6 +380,194 @@ ], "time": "2019-09-03T16:45:42+00:00" }, + { + "name": "guzzlehttp/guzzle", + "version": "6.4.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "0895c932405407fd3a7368b6910c09a24d26db11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/0895c932405407fd3a7368b6910c09a24d26db11", + "reference": "0895c932405407fd3a7368b6910c09a24d26db11", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^1.0", + "guzzlehttp/psr7": "^1.6.1", + "php": ">=5.5" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", + "psr/log": "^1.1" + }, + "suggest": { + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.3-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "time": "2019-10-23T15:58:00+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "v1.3.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646", + "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646", + "shasum": "" + }, + "require": { + "php": ">=5.5.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "time": "2016-12-20T10:07:11+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "1.6.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "239400de7a173fe9901b9ac7c06497751f00727a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/239400de7a173fe9901b9ac7c06497751f00727a", + "reference": "239400de7a173fe9901b9ac7c06497751f00727a", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "psr/http-message": "~1.0", + "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "ext-zlib": "*", + "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.8" + }, + "suggest": { + "zendframework/zend-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.6-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Schultze", + "homepage": "https://github.com/Tobion" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "time": "2019-07-01T23:21:34+00:00" + }, { "name": "jakub-onderka/php-console-color", "version": "v0.2", @@ -614,6 +802,63 @@ ], "time": "2019-10-29T14:30:39+00:00" }, + { + "name": "laravel/slack-notification-channel", + "version": "v2.0.2", + "source": { + "type": "git", + "url": "https://github.com/laravel/slack-notification-channel.git", + "reference": "ecc90a70791195d6f5e20b2732a5eb1eb9619d10" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/slack-notification-channel/zipball/ecc90a70791195d6f5e20b2732a5eb1eb9619d10", + "reference": "ecc90a70791195d6f5e20b2732a5eb1eb9619d10", + "shasum": "" + }, + "require": { + "guzzlehttp/guzzle": "^6.0", + "illuminate/notifications": "~5.8.0|^6.0|^7.0", + "php": "^7.1.3" + }, + "require-dev": { + "mockery/mockery": "^1.0", + "phpunit/phpunit": "^7.0|^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + }, + "laravel": { + "providers": [ + "Illuminate\\Notifications\\SlackChannelServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Illuminate\\Notifications\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Slack Notification Channel for laravel.", + "keywords": [ + "laravel", + "notifications", + "slack" + ], + "time": "2019-08-27T14:40:26+00:00" + }, { "name": "laravel/tinker", "version": "v1.0.10", @@ -1166,6 +1411,56 @@ ], "time": "2017-02-14T16:28:37+00:00" }, + { + "name": "psr/http-message", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "time": "2016-08-06T14:39:51+00:00" + }, { "name": "psr/log", "version": "1.1.1", @@ -1335,6 +1630,46 @@ ], "time": "2018-10-13T15:16:03+00:00" }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "time": "2019-03-08T08:55:37+00:00" + }, { "name": "ramsey/uuid", "version": "3.8.0", @@ -2897,6 +3232,74 @@ } ], "packages-dev": [ + { + "name": "barryvdh/laravel-debugbar", + "version": "v3.2.8", + "source": { + "type": "git", + "url": "https://github.com/barryvdh/laravel-debugbar.git", + "reference": "18208d64897ab732f6c04a19b319fe8f1d57a9c0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/18208d64897ab732f6c04a19b319fe8f1d57a9c0", + "reference": "18208d64897ab732f6c04a19b319fe8f1d57a9c0", + "shasum": "" + }, + "require": { + "illuminate/routing": "^5.5|^6", + "illuminate/session": "^5.5|^6", + "illuminate/support": "^5.5|^6", + "maximebf/debugbar": "~1.15.0", + "php": ">=7.0", + "symfony/debug": "^3|^4", + "symfony/finder": "^3|^4" + }, + "require-dev": { + "laravel/framework": "5.5.x" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + }, + "laravel": { + "providers": [ + "Barryvdh\\Debugbar\\ServiceProvider" + ], + "aliases": { + "Debugbar": "Barryvdh\\Debugbar\\Facade" + } + } + }, + "autoload": { + "psr-4": { + "Barryvdh\\Debugbar\\": "src/" + }, + "files": [ + "src/helpers.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Barry vd. Heuvel", + "email": "barryvdh@gmail.com" + } + ], + "description": "PHP Debugbar integration for Laravel", + "keywords": [ + "debug", + "debugbar", + "laravel", + "profiler", + "webprofiler" + ], + "time": "2019-08-29T07:01:03+00:00" + }, { "name": "doctrine/instantiator", "version": "1.2.0", @@ -3281,6 +3684,67 @@ ], "time": "2016-01-20T08:20:44+00:00" }, + { + "name": "maximebf/debugbar", + "version": "v1.15.1", + "source": { + "type": "git", + "url": "https://github.com/maximebf/php-debugbar.git", + "reference": "6c4277f6117e4864966c9cb58fb835cee8c74a1e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/6c4277f6117e4864966c9cb58fb835cee8c74a1e", + "reference": "6c4277f6117e4864966c9cb58fb835cee8c74a1e", + "shasum": "" + }, + "require": { + "php": ">=5.6", + "psr/log": "^1.0", + "symfony/var-dumper": "^2.6|^3|^4" + }, + "require-dev": { + "phpunit/phpunit": "^5" + }, + "suggest": { + "kriswallsmith/assetic": "The best way to manage assets", + "monolog/monolog": "Log using Monolog", + "predis/predis": "Redis storage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.15-dev" + } + }, + "autoload": { + "psr-4": { + "DebugBar\\": "src/DebugBar/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Maxime Bouroumeau-Fuseau", + "email": "maxime.bouroumeau@gmail.com", + "homepage": "http://maximebf.com" + }, + { + "name": "Barry vd. Heuvel", + "email": "barryvdh@gmail.com" + } + ], + "description": "Debug bar in the browser for php application", + "homepage": "https://github.com/maximebf/php-debugbar", + "keywords": [ + "debug", + "debugbar" + ], + "time": "2019-09-24T14:55:42+00:00" + }, { "name": "mockery/mockery", "version": "1.2.4", diff --git a/database/migrations/2018_09_14_132853_create_api_keys_table.php b/database/migrations/2018_09_14_132853_create_api_keys_table.php new file mode 100644 index 0000000..47dbea3 --- /dev/null +++ b/database/migrations/2018_09_14_132853_create_api_keys_table.php @@ -0,0 +1,36 @@ +increments('id'); + $table->string('name'); + $table->string('key', 64); + $table->boolean('active')->default(1); + $table->timestamps(); + $table->softDeletes(); + $table->index('name'); + $table->index('key'); + }); + } + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('api_keys'); + } +} diff --git a/database/migrations/2018_09_14_132854_create_api_key_access_events_table.php b/database/migrations/2018_09_14_132854_create_api_key_access_events_table.php new file mode 100644 index 0000000..0d3861d --- /dev/null +++ b/database/migrations/2018_09_14_132854_create_api_key_access_events_table.php @@ -0,0 +1,35 @@ +increments('id'); + $table->unsignedInteger('api_key_id'); + $table->ipAddress('ip_address'); + $table->text('url'); + $table->timestamps(); + $table->index('ip_address'); + $table->foreign('api_key_id')->references('id')->on('api_keys'); + }); + } + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('api_key_access_events'); + } +} diff --git a/database/migrations/2018_09_14_132855_create_api_key_admin_events_table.php b/database/migrations/2018_09_14_132855_create_api_key_admin_events_table.php new file mode 100644 index 0000000..7713197 --- /dev/null +++ b/database/migrations/2018_09_14_132855_create_api_key_admin_events_table.php @@ -0,0 +1,36 @@ +increments('id'); + $table->unsignedInteger('api_key_id'); + $table->ipAddress('ip_address'); + $table->string('event'); + $table->timestamps(); + $table->index('ip_address'); + $table->index('event'); + $table->foreign('api_key_id')->references('id')->on('api_keys'); + }); + } + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('api_key_admin_events'); + } +}