diff --git a/app/Contracts/Repository/ApiKeyRepositoryInterface.php b/app/Contracts/Repository/ApiKeyRepositoryInterface.php new file mode 100644 index 000000000..bfd44e921 --- /dev/null +++ b/app/Contracts/Repository/ApiKeyRepositoryInterface.php @@ -0,0 +1,30 @@ +. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +namespace Pterodactyl\Contracts\Repository; + +interface ApiKeyRepositoryInterface extends RepositoryInterface +{ + // +} diff --git a/app/Contracts/Repository/ApiPermissionRepositoryInterface.php b/app/Contracts/Repository/ApiPermissionRepositoryInterface.php new file mode 100644 index 000000000..f0556b453 --- /dev/null +++ b/app/Contracts/Repository/ApiPermissionRepositoryInterface.php @@ -0,0 +1,30 @@ +. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +namespace Pterodactyl\Contracts\Repository; + +interface ApiPermissionRepositoryInterface extends RepositoryInterface +{ + // +} diff --git a/app/Contracts/Repository/Attributes/SearchableInterface.php b/app/Contracts/Repository/Attributes/SearchableInterface.php index 37d9316ee..60ca52b97 100644 --- a/app/Contracts/Repository/Attributes/SearchableInterface.php +++ b/app/Contracts/Repository/Attributes/SearchableInterface.php @@ -26,5 +26,11 @@ namespace Pterodactyl\Contracts\Repository\Attributes; interface SearchableInterface { + /** + * Filter results by search term. + * + * @param string $term + * @return $this + */ public function search($term); } diff --git a/app/Contracts/Repository/DatabaseHostInterface.php b/app/Contracts/Repository/DatabaseHostInterface.php index e1fcee8bd..2fd26b167 100644 --- a/app/Contracts/Repository/DatabaseHostInterface.php +++ b/app/Contracts/Repository/DatabaseHostInterface.php @@ -26,5 +26,14 @@ namespace Pterodactyl\Contracts\Repository; interface DatabaseHostInterface extends RepositoryInterface { + /** + * Delete a database host from the DB if there are no databases using it. + * + * @param int $id + * @return bool|null + * + * @throws \Pterodactyl\Exceptions\DisplayException + * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException + */ public function deleteIfNoDatabases($id); } diff --git a/app/Contracts/Repository/LocationRepositoryInterface.php b/app/Contracts/Repository/LocationRepositoryInterface.php index 81a75ff80..9a52e2988 100644 --- a/app/Contracts/Repository/LocationRepositoryInterface.php +++ b/app/Contracts/Repository/LocationRepositoryInterface.php @@ -28,5 +28,14 @@ use Pterodactyl\Contracts\Repository\Attributes\SearchableInterface; interface LocationRepositoryInterface extends RepositoryInterface, SearchableInterface { + /** + * Delete a location only if there are no nodes attached to it. + * + * @param $id + * @return bool|mixed|null + * + * @throws \Pterodactyl\Exceptions\DisplayException + * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException + */ public function deleteIfNoNodes($id); } diff --git a/app/Contracts/Repository/RepositoryInterface.php b/app/Contracts/Repository/RepositoryInterface.php index 5eba06b19..470dc3ebb 100644 --- a/app/Contracts/Repository/RepositoryInterface.php +++ b/app/Contracts/Repository/RepositoryInterface.php @@ -26,25 +26,108 @@ namespace Pterodactyl\Contracts\Repository; interface RepositoryInterface { + /** + * Return an identifier or Model object to be used by the repository. + * + * @return string|\Closure|object + */ public function model(); + /** + * Return the model being used for this repository instance. + * + * @return mixed + */ public function getModel(); + /** + * Returns an instance of a query builder. + * + * @return mixed + */ public function getBuilder(); + /** + * Returns the colummns to be selected or returned by the query. + * + * @return mixed + */ public function getColumns(); + /** + * An array of columns to filter the response by. + * + * @param array $columns + * @return $this + */ public function withColumns($columns = ['*']); - public function create($fields); + /** + * Disable returning a fresh model when data is inserted or updated. + * + * @return $this + */ + public function withoutFresh(); + /** + * Create a new model instance and persist it to the database. + * + * @param array $fields + * @param bool $validate + * @return mixed + * + * @throws \Pterodactyl\Exceptions\Model\DataValidationException + */ + public function create(array $fields, $validate = true); + + /** + * Delete a given record from the database. + * + * @param int $id + * @return bool|null + */ public function delete($id); + /** + * Find a model that has the specific ID passed. + * + * @param int $id + * @return mixed + * + * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException + */ public function find($id); - public function findWhere($fields); + /** + * Find a model matching an array of where clauses. + * + * @param array $fields + * @return mixed + * + * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException + */ + public function findWhere(array $fields); - public function update($id, $fields); + /** + * Update a given ID with the passed array of fields. + * + * @param int $id + * @param array $fields + * @param bool $validate + * @param bool $force + * @return mixed + * + * @throws \Pterodactyl\Exceptions\Model\DataValidationException + * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException + */ + public function update($id, array $fields, $validate = true, $force = false); - public function massUpdate($fields); + /** + * Update multiple records matching the passed clauses. + * + * @param array $where + * @param array $fields + * @return mixed + */ + public function massUpdate(array $where, array $fields); } diff --git a/app/Contracts/Repository/UserRepositoryInterface.php b/app/Contracts/Repository/UserRepositoryInterface.php index cf61251ef..d6a02c925 100644 --- a/app/Contracts/Repository/UserRepositoryInterface.php +++ b/app/Contracts/Repository/UserRepositoryInterface.php @@ -28,7 +28,20 @@ use Pterodactyl\Contracts\Repository\Attributes\SearchableInterface; interface UserRepositoryInterface extends RepositoryInterface, SearchableInterface { + /** + * Return all users with counts of servers and subusers of servers. + * + * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator + */ public function getAllUsersWithCounts(); + /** + * Delete a user if they have no servers attached to their account. + * + * @param int $id + * @return bool + * + * @throws \Pterodactyl\Exceptions\DisplayException + */ public function deleteIfNoServers($id); } diff --git a/app/Models/APIPermission.php b/app/Models/APIPermission.php index 9361d31b2..626185fc0 100644 --- a/app/Models/APIPermission.php +++ b/app/Models/APIPermission.php @@ -36,7 +36,7 @@ class APIPermission extends Model implements ValidableContract /** * List of permissions available for the API. */ - const PERMISSIONS = [ + const CONST_PERMISSIONS = [ // Items within this block are available to non-adminitrative users. '_user' => [ 'server' => [ diff --git a/app/Providers/RepositoryServiceProvider.php b/app/Providers/RepositoryServiceProvider.php index 739b91328..9d0f59b35 100644 --- a/app/Providers/RepositoryServiceProvider.php +++ b/app/Providers/RepositoryServiceProvider.php @@ -25,8 +25,12 @@ namespace Pterodactyl\Providers; use Illuminate\Support\ServiceProvider; +use Pterodactyl\Contracts\Repository\ApiKeyRepositoryInterface; +use Pterodactyl\Contracts\Repository\ApiPermissionRepositoryInterface; use Pterodactyl\Contracts\Repository\DatabaseHostInterface; use Pterodactyl\Contracts\Repository\LocationRepositoryInterface; +use Pterodactyl\Repositories\Eloquent\ApiKeyRepository; +use Pterodactyl\Repositories\Eloquent\ApiPermissionRepository; use Pterodactyl\Repositories\Eloquent\DatabaseHostRepository; use Pterodactyl\Repositories\Eloquent\LocationRepository; use Pterodactyl\Repositories\Eloquent\UserRepository; @@ -39,6 +43,8 @@ class RepositoryServiceProvider extends ServiceProvider */ public function register() { + $this->app->bind(ApiKeyRepositoryInterface::class, ApiKeyRepository::class); + $this->app->bind(ApiPermissionRepositoryInterface::class, ApiPermissionRepository::class); $this->app->bind(DatabaseHostInterface::class, DatabaseHostRepository::class); $this->app->bind(LocationRepositoryInterface::class, LocationRepository::class); $this->app->bind(UserRepositoryInterface::class, UserRepository::class); diff --git a/app/Repositories/Eloquent/ApiKeyRepository.php b/app/Repositories/Eloquent/ApiKeyRepository.php new file mode 100644 index 000000000..c82088f28 --- /dev/null +++ b/app/Repositories/Eloquent/ApiKeyRepository.php @@ -0,0 +1,39 @@ +. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +namespace Pterodactyl\Repositories\Eloquent; + +use Pterodactyl\Models\APIKey; +use Pterodactyl\Contracts\Repository\ApiKeyRepositoryInterface; + +class ApiKeyRepository extends EloquentRepository implements ApiKeyRepositoryInterface +{ + /** + * {@inheritdoc} + */ + public function model() + { + return APIKey::class; + } +} diff --git a/app/Repositories/Eloquent/ApiPermissionRepository.php b/app/Repositories/Eloquent/ApiPermissionRepository.php new file mode 100644 index 000000000..5c87e8131 --- /dev/null +++ b/app/Repositories/Eloquent/ApiPermissionRepository.php @@ -0,0 +1,39 @@ +. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +namespace Pterodactyl\Repositories\Eloquent; + +use Pterodactyl\Models\APIPermission; +use Pterodactyl\Contracts\Repository\ApiPermissionRepositoryInterface; + +class ApiPermissionRepository extends EloquentRepository implements ApiPermissionRepositoryInterface +{ + /** + * {@inheritdoc} + */ + public function model() + { + return APIPermission::class; + } +} diff --git a/app/Repositories/Eloquent/DatabaseHostRepository.php b/app/Repositories/Eloquent/DatabaseHostRepository.php index 921bc7b08..76c572123 100644 --- a/app/Repositories/Eloquent/DatabaseHostRepository.php +++ b/app/Repositories/Eloquent/DatabaseHostRepository.php @@ -32,9 +32,7 @@ use Pterodactyl\Models\DatabaseHost; class DatabaseHostRepository extends EloquentRepository implements DatabaseHostInterface { /** - * Setup the model to be used. - * - * @return string + * {@inheritdoc} */ public function model() { @@ -42,13 +40,7 @@ class DatabaseHostRepository extends EloquentRepository implements DatabaseHostI } /** - * Delete a database host from the DB if there are no databases using it. - * - * @param int $id - * @return bool|null - * - * @throws \Pterodactyl\Exceptions\DisplayException - * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException + * {@inheritdoc} */ public function deleteIfNoDatabases($id) { diff --git a/app/Repositories/Eloquent/EloquentRepository.php b/app/Repositories/Eloquent/EloquentRepository.php index 614d80396..2da2eccd3 100644 --- a/app/Repositories/Eloquent/EloquentRepository.php +++ b/app/Repositories/Eloquent/EloquentRepository.php @@ -24,14 +24,15 @@ namespace Pterodactyl\Repositories\Eloquent; -use Pterodactyl\Exceptions\Model\DataValidationException; -use Pterodactyl\Exceptions\Repository\RecordNotFoundException; use Pterodactyl\Repository\Repository; use Pterodactyl\Contracts\Repository\RepositoryInterface; +use Pterodactyl\Exceptions\Model\DataValidationException; +use Pterodactyl\Exceptions\Repository\RecordNotFoundException; abstract class EloquentRepository extends Repository implements RepositoryInterface { /** + * {@inheritdoc} * @return \Illuminate\Database\Eloquent\Builder */ public function getBuilder() @@ -40,14 +41,11 @@ abstract class EloquentRepository extends Repository implements RepositoryInterf } /** - * Create a new model instance and persist it to the database. - * @param array $fields - * @param bool $validate - * @param bool $force - * @return bool|\Illuminate\Database\Eloquent\Model - * @throws \Pterodactyl\Exceptions\Model\DataValidationException + * {@inheritdoc} + * @param bool $force + * @return \Illuminate\Database\Eloquent\Model|bool */ - public function create($fields, $validate = true, $force = false) + public function create(array $fields, $validate = true, $force = false) { $instance = $this->getBuilder()->newModelInstance(); @@ -69,12 +67,8 @@ abstract class EloquentRepository extends Repository implements RepositoryInterf } /** - * Return a record from the database for a given ID. - * - * @param int $id + * {@inheritdoc} * @return \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Model - * - * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException */ public function find($id) { @@ -87,17 +81,16 @@ abstract class EloquentRepository extends Repository implements RepositoryInterf return $instance; } - public function findWhere($fields) + /** + * {@inheritdoc} + */ + public function findWhere(array $fields) { // TODO: Implement findWhere() method. } /** - * Delete a record from the DB given an ID. - * - * @param int $id - * @param bool $destroy - * @return bool|null + * {@inheritdoc} */ public function delete($id, $destroy = false) { @@ -109,16 +102,9 @@ abstract class EloquentRepository extends Repository implements RepositoryInterf } /** - * @param int $id - * @param array $fields - * @param bool $validate - * @param bool $force - * @return mixed - * - * @throws \Pterodactyl\Exceptions\Model\DataValidationException - * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException + * {@inheritdoc} */ - public function update($id, $fields, $validate = true, $force = false) + public function update($id, array $fields, $validate = true, $force = false) { $instance = $this->getBuilder()->where('id', $id)->first(); @@ -143,7 +129,10 @@ abstract class EloquentRepository extends Repository implements RepositoryInterf return ($this->withFresh) ? $instance->fresh($this->getColumns()) : $saved; } - public function massUpdate($fields) + /** + * {@inheritdoc} + */ + public function massUpdate(array $where, array $fields) { // TODO: Implement massUpdate() method. } diff --git a/app/Repositories/Eloquent/LocationRepository.php b/app/Repositories/Eloquent/LocationRepository.php index fffbe61b0..43e2e15d6 100644 --- a/app/Repositories/Eloquent/LocationRepository.php +++ b/app/Repositories/Eloquent/LocationRepository.php @@ -37,9 +37,7 @@ class LocationRepository extends EloquentRepository implements LocationRepositor protected $searchTerm; /** - * Setup model. - * - * @return string + * {@inheritdoc} */ public function model() { @@ -47,10 +45,7 @@ class LocationRepository extends EloquentRepository implements LocationRepositor } /** - * Setup the model for search abilities. - * - * @param $term - * @return $this + * {@inheritdoc} */ public function search($term) { @@ -65,13 +60,7 @@ class LocationRepository extends EloquentRepository implements LocationRepositor } /** - * Delete a location only if there are no nodes attached to it. - * - * @param $id - * @return bool|mixed|null - * - * @throws \Pterodactyl\Exceptions\DisplayException - * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException + * {@inheritdoc} */ public function deleteIfNoNodes($id) { diff --git a/app/Repositories/Eloquent/UserRepository.php b/app/Repositories/Eloquent/UserRepository.php index 96b85ffdf..00776bb70 100644 --- a/app/Repositories/Eloquent/UserRepository.php +++ b/app/Repositories/Eloquent/UserRepository.php @@ -56,11 +56,17 @@ class UserRepository extends EloquentRepository implements UserRepositoryInterfa $this->config = $config; } + /** + * {@inheritdoc} + */ public function model() { return User::class; } + /** + * {@inheritdoc} + */ public function search($term) { if (empty($term)) { @@ -73,6 +79,9 @@ class UserRepository extends EloquentRepository implements UserRepositoryInterfa return $clone; } + /** + * {@inheritdoc} + */ public function getAllUsersWithCounts() { $users = $this->getBuilder()->withCount('servers', 'subuserOf'); @@ -87,12 +96,7 @@ class UserRepository extends EloquentRepository implements UserRepositoryInterfa } /** - * Delete a user if they have no servers attached to their account. - * - * @param int $id - * @return bool - * - * @throws \Pterodactyl\Exceptions\DisplayException + * {@inheritdoc} */ public function deleteIfNoServers($id) { diff --git a/app/Services/ApiKeyService.php b/app/Services/ApiKeyService.php index 91e703ea1..d4a3c6e2f 100644 --- a/app/Services/ApiKeyService.php +++ b/app/Services/ApiKeyService.php @@ -24,48 +24,52 @@ namespace Pterodactyl\Services; -use Pterodactyl\Models\APIKey; -use Illuminate\Database\Connection; +use Illuminate\Database\ConnectionInterface; use Illuminate\Contracts\Encryption\Encrypter; -use Pterodactyl\Exceptions\Model\DataValidationException; +use Pterodactyl\Contracts\Repository\ApiKeyRepositoryInterface; class ApiKeyService { const PUB_CRYPTO_BYTES = 8; const PRIV_CRYPTO_BYTES = 32; + /** + * @var \Illuminate\Database\ConnectionInterface + */ + protected $database; + /** * @var \Illuminate\Contracts\Encryption\Encrypter */ protected $encrypter; - /** - * @var \Pterodactyl\Models\APIKey - */ - protected $model; - /** * @var \Pterodactyl\Services\ApiPermissionService */ protected $permissionService; + /** + * @var \Pterodactyl\Contracts\Repository\ApiKeyRepositoryInterface + */ + protected $repository; + /** * ApiKeyService constructor. * - * @param \Pterodactyl\Models\APIKey $model - * @param \Illuminate\Database\Connection $database - * @param \Illuminate\Contracts\Encryption\Encrypter $encrypter - * @param \Pterodactyl\Services\ApiPermissionService $permissionService + * @param \Pterodactyl\Contracts\Repository\ApiKeyRepositoryInterface $repository + * @param \Illuminate\Database\ConnectionInterface $database + * @param \Illuminate\Contracts\Encryption\Encrypter $encrypter + * @param \Pterodactyl\Services\ApiPermissionService $permissionService */ public function __construct( - APIKey $model, - Connection $database, + ApiKeyRepositoryInterface $repository, + ConnectionInterface $database, Encrypter $encrypter, ApiPermissionService $permissionService ) { + $this->repository = $repository; $this->database = $database; $this->encrypter = $encrypter; - $this->model = $model; $this->permissionService = $permissionService; } @@ -88,16 +92,12 @@ class ApiKeyService // Start a Transaction $this->database->beginTransaction(); - $instance = $this->model->newInstance($data); - $instance->public = $publicKey; - $instance->secret = $this->encrypter->encrypt($secretKey); + $data = array_merge($data, [ + 'public' => $publicKey, + 'secret' => $this->encrypter->encrypt($secretKey), + ]); - if (! $instance->save()) { - $this->database->rollBack(); - throw new DataValidationException($instance->getValidator()); - } - - $key = $instance->fresh(); + $instance = $this->repository->create($data, true, true); $nodes = $this->permissionService->getPermissions(); foreach ($permissions as $permission) { @@ -111,7 +111,7 @@ class ApiKeyService continue; } - $this->permissionService->create($key->id, sprintf('user.%s', $permission)); + $this->permissionService->create($instance->id, sprintf('user.%s', $permission)); } foreach ($administrative as $permission) { @@ -125,7 +125,7 @@ class ApiKeyService continue; } - $this->permissionService->create($key->id, $permission); + $this->permissionService->create($instance->id, $permission); } $this->database->commit(); @@ -136,18 +136,11 @@ class ApiKeyService /** * Delete the API key and associated permissions from the database. * - * @param int|\Pterodactyl\Models\APIKey $key + * @param int $id * @return bool|null - * - * @throws \Exception - * @throws \Illuminate\Database\Eloquent\ModelNotFoundException */ - public function revoke($key) + public function revoke($id) { - if (! $key instanceof APIKey) { - $key = $this->model->findOrFail($key); - } - - return $key->delete(); + return $this->repository->delete($id); } } diff --git a/app/Services/ApiPermissionService.php b/app/Services/ApiPermissionService.php index 20a722bf3..40ca4a1c9 100644 --- a/app/Services/ApiPermissionService.php +++ b/app/Services/ApiPermissionService.php @@ -24,24 +24,23 @@ namespace Pterodactyl\Services; -use Pterodactyl\Models\APIPermission; -use Pterodactyl\Exceptions\Model\DataValidationException; +use Pterodactyl\Contracts\Repository\ApiPermissionRepositoryInterface; class ApiPermissionService { /** - * @var \Pterodactyl\Models\APIPermission + * @var \Pterodactyl\Contracts\Repository\ApiPermissionRepositoryInterface */ - protected $model; + protected $repository; /** * ApiPermissionService constructor. * - * @param \Pterodactyl\Models\APIPermission $model + * @param \Pterodactyl\Contracts\Repository\ApiPermissionRepositoryInterface $repository */ - public function __construct(APIPermission $model) + public function __construct(ApiPermissionRepositoryInterface $repository) { - $this->model = $model; + $this->repository = $repository; } /** @@ -55,16 +54,11 @@ class ApiPermissionService */ public function create($key, $permission) { - $instance = $this->model->newInstance([ + // @todo handle an array of permissions to do a mass assignment? + return $this->repository->withoutFresh()->create([ 'key_id' => $key, 'permission' => $permission, ]); - - if (! $instance->save()) { - throw new DataValidationException($instance->getValidator()); - } - - return true; } /** @@ -74,6 +68,6 @@ class ApiPermissionService */ public function getPermissions() { - return APIPermission::PERMISSIONS; + return $this->repository->getModel()::CONST_PERMISSIONS; } } diff --git a/composer.json b/composer.json index f025b24c9..bd8f49da6 100644 --- a/composer.json +++ b/composer.json @@ -44,6 +44,7 @@ "friendsofphp/php-cs-fixer": "1.*", "fzaninotto/faker": "~1.4", "mockery/mockery": "0.9.*", + "php-mock/php-mock-phpunit": "^1.1", "phpunit/phpunit": "~5.7", "sllh/php-cs-fixer-styleci-bridge": "^2.1" }, diff --git a/composer.lock b/composer.lock index d263f6eee..a6afca005 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "d3edf73b6618705ee34a76fa0319f0de", + "content-hash": "f1afab5cf73088c6034bfb2b13631600", "packages": [ { "name": "aws/aws-sdk-php", @@ -803,16 +803,16 @@ }, { "name": "erusev/parsedown", - "version": "1.6.2", + "version": "1.6.3", "source": { "type": "git", "url": "https://github.com/erusev/parsedown.git", - "reference": "1bf24f7334fe16c88bf9d467863309ceaf285b01" + "reference": "728952b90a333b5c6f77f06ea9422b94b585878d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/erusev/parsedown/zipball/1bf24f7334fe16c88bf9d467863309ceaf285b01", - "reference": "1bf24f7334fe16c88bf9d467863309ceaf285b01", + "url": "https://api.github.com/repos/erusev/parsedown/zipball/728952b90a333b5c6f77f06ea9422b94b585878d", + "reference": "728952b90a333b5c6f77f06ea9422b94b585878d", "shasum": "" }, "require": { @@ -841,7 +841,7 @@ "markdown", "parser" ], - "time": "2017-03-29T16:04:15+00:00" + "time": "2017-05-14T14:47:48+00:00" }, { "name": "fideloper/proxy", @@ -1989,16 +1989,16 @@ }, { "name": "nikic/php-parser", - "version": "v3.0.5", + "version": "v3.0.6", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "2b9e2f71b722f7c53918ab0c25f7646c2013f17d" + "reference": "0808939f81c1347a3c8a82a5925385a08074b0f1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/2b9e2f71b722f7c53918ab0c25f7646c2013f17d", - "reference": "2b9e2f71b722f7c53918ab0c25f7646c2013f17d", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/0808939f81c1347a3c8a82a5925385a08074b0f1", + "reference": "0808939f81c1347a3c8a82a5925385a08074b0f1", "shasum": "" }, "require": { @@ -2036,7 +2036,7 @@ "parser", "php" ], - "time": "2017-03-05T18:23:57+00:00" + "time": "2017-06-28T20:53:48+00:00" }, { "name": "paragonie/random_compat", @@ -2346,16 +2346,16 @@ }, { "name": "psy/psysh", - "version": "v0.8.8", + "version": "v0.8.9", "source": { "type": "git", "url": "https://github.com/bobthecow/psysh.git", - "reference": "fe65c30cbc55c71e61ba3a38b5a581149be31b8e" + "reference": "58a31cc4404c8f632d8c557bc72056af2d3a83db" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bobthecow/psysh/zipball/fe65c30cbc55c71e61ba3a38b5a581149be31b8e", - "reference": "fe65c30cbc55c71e61ba3a38b5a581149be31b8e", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/58a31cc4404c8f632d8c557bc72056af2d3a83db", + "reference": "58a31cc4404c8f632d8c557bc72056af2d3a83db", "shasum": "" }, "require": { @@ -2415,7 +2415,7 @@ "interactive", "shell" ], - "time": "2017-06-24T06:16:19+00:00" + "time": "2017-07-06T14:53:52+00:00" }, { "name": "ramsey/uuid", @@ -2653,16 +2653,16 @@ }, { "name": "spatie/fractalistic", - "version": "2.2.0", + "version": "2.3.0", "source": { "type": "git", "url": "https://github.com/spatie/fractalistic.git", - "reference": "8f00c666a8b8dfb06f79286f97255e6ab1c89639" + "reference": "79a48d949bc053a1c60c934f727f5901bf35fa74" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/fractalistic/zipball/8f00c666a8b8dfb06f79286f97255e6ab1c89639", - "reference": "8f00c666a8b8dfb06f79286f97255e6ab1c89639", + "url": "https://api.github.com/repos/spatie/fractalistic/zipball/79a48d949bc053a1c60c934f727f5901bf35fa74", + "reference": "79a48d949bc053a1c60c934f727f5901bf35fa74", "shasum": "" }, "require": { @@ -2700,7 +2700,7 @@ "spatie", "transform" ], - "time": "2017-05-29T14:16:20+00:00" + "time": "2017-07-03T08:20:31+00:00" }, { "name": "spatie/laravel-fractal", @@ -2816,16 +2816,16 @@ }, { "name": "symfony/console", - "version": "v3.3.2", + "version": "v3.3.4", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "70d2a29b2911cbdc91a7e268046c395278238b2e" + "reference": "a97e45d98c59510f085fa05225a1acb74dfe0546" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/70d2a29b2911cbdc91a7e268046c395278238b2e", - "reference": "70d2a29b2911cbdc91a7e268046c395278238b2e", + "url": "https://api.github.com/repos/symfony/console/zipball/a97e45d98c59510f085fa05225a1acb74dfe0546", + "reference": "a97e45d98c59510f085fa05225a1acb74dfe0546", "shasum": "" }, "require": { @@ -2881,11 +2881,11 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2017-06-02T19:24:58+00:00" + "time": "2017-07-03T13:19:36+00:00" }, { "name": "symfony/css-selector", - "version": "v3.3.2", + "version": "v3.3.4", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", @@ -2938,16 +2938,16 @@ }, { "name": "symfony/debug", - "version": "v3.3.2", + "version": "v3.3.4", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", - "reference": "e9c50482841ef696e8fa1470d950a79c8921f45d" + "reference": "63b85a968486d95ff9542228dc2e4247f16f9743" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/e9c50482841ef696e8fa1470d950a79c8921f45d", - "reference": "e9c50482841ef696e8fa1470d950a79c8921f45d", + "url": "https://api.github.com/repos/symfony/debug/zipball/63b85a968486d95ff9542228dc2e4247f16f9743", + "reference": "63b85a968486d95ff9542228dc2e4247f16f9743", "shasum": "" }, "require": { @@ -2990,20 +2990,20 @@ ], "description": "Symfony Debug Component", "homepage": "https://symfony.com", - "time": "2017-06-01T21:01:25+00:00" + "time": "2017-07-05T13:02:37+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v3.3.2", + "version": "v3.3.4", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "4054a102470665451108f9b59305c79176ef98f0" + "reference": "67535f1e3fd662bdc68d7ba317c93eecd973617e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/4054a102470665451108f9b59305c79176ef98f0", - "reference": "4054a102470665451108f9b59305c79176ef98f0", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/67535f1e3fd662bdc68d7ba317c93eecd973617e", + "reference": "67535f1e3fd662bdc68d7ba317c93eecd973617e", "shasum": "" }, "require": { @@ -3053,11 +3053,11 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2017-06-04T18:15:29+00:00" + "time": "2017-06-09T14:53:08+00:00" }, { "name": "symfony/finder", - "version": "v3.3.2", + "version": "v3.3.4", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", @@ -3106,16 +3106,16 @@ }, { "name": "symfony/http-foundation", - "version": "v3.3.2", + "version": "v3.3.4", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "80eb5a1f968448b77da9e8b2c0827f6e8d767846" + "reference": "f347a5f561b03db95ed666959db42bbbf429b7e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/80eb5a1f968448b77da9e8b2c0827f6e8d767846", - "reference": "80eb5a1f968448b77da9e8b2c0827f6e8d767846", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/f347a5f561b03db95ed666959db42bbbf429b7e5", + "reference": "f347a5f561b03db95ed666959db42bbbf429b7e5", "shasum": "" }, "require": { @@ -3155,20 +3155,20 @@ ], "description": "Symfony HttpFoundation Component", "homepage": "https://symfony.com", - "time": "2017-06-05T13:06:51+00:00" + "time": "2017-06-24T09:29:48+00:00" }, { "name": "symfony/http-kernel", - "version": "v3.3.2", + "version": "v3.3.4", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "be8280f7fa8e95b86514f1e1be997668a53b2888" + "reference": "33f87c957122cfbd9d90de48698ee074b71106ea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/be8280f7fa8e95b86514f1e1be997668a53b2888", - "reference": "be8280f7fa8e95b86514f1e1be997668a53b2888", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/33f87c957122cfbd9d90de48698ee074b71106ea", + "reference": "33f87c957122cfbd9d90de48698ee074b71106ea", "shasum": "" }, "require": { @@ -3241,7 +3241,7 @@ ], "description": "Symfony HttpKernel Component", "homepage": "https://symfony.com", - "time": "2017-06-06T03:59:58+00:00" + "time": "2017-07-05T13:28:15+00:00" }, { "name": "symfony/polyfill-mbstring", @@ -3412,16 +3412,16 @@ }, { "name": "symfony/process", - "version": "v3.3.2", + "version": "v3.3.4", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "8e30690c67aafb6c7992d6d8eb0d707807dd3eaf" + "reference": "5ab8949b682b1bf9d4511a228b5e045c96758c30" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/8e30690c67aafb6c7992d6d8eb0d707807dd3eaf", - "reference": "8e30690c67aafb6c7992d6d8eb0d707807dd3eaf", + "url": "https://api.github.com/repos/symfony/process/zipball/5ab8949b682b1bf9d4511a228b5e045c96758c30", + "reference": "5ab8949b682b1bf9d4511a228b5e045c96758c30", "shasum": "" }, "require": { @@ -3457,20 +3457,20 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2017-05-22T12:32:03+00:00" + "time": "2017-07-03T08:12:02+00:00" }, { "name": "symfony/routing", - "version": "v3.3.2", + "version": "v3.3.4", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "39804eeafea5cca851946e1eed122eb94459fdb4" + "reference": "dc70bbd0ca7b19259f63cdacc8af370bc32a4728" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/39804eeafea5cca851946e1eed122eb94459fdb4", - "reference": "39804eeafea5cca851946e1eed122eb94459fdb4", + "url": "https://api.github.com/repos/symfony/routing/zipball/dc70bbd0ca7b19259f63cdacc8af370bc32a4728", + "reference": "dc70bbd0ca7b19259f63cdacc8af370bc32a4728", "shasum": "" }, "require": { @@ -3535,20 +3535,20 @@ "uri", "url" ], - "time": "2017-06-02T09:51:43+00:00" + "time": "2017-06-24T09:29:48+00:00" }, { "name": "symfony/translation", - "version": "v3.3.2", + "version": "v3.3.4", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "dc3b2a0c6cfff60327ba1c043a82092735397543" + "reference": "35dd5fb003c90e8bd4d8cabdf94bf9c96d06fdc3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/dc3b2a0c6cfff60327ba1c043a82092735397543", - "reference": "dc3b2a0c6cfff60327ba1c043a82092735397543", + "url": "https://api.github.com/repos/symfony/translation/zipball/35dd5fb003c90e8bd4d8cabdf94bf9c96d06fdc3", + "reference": "35dd5fb003c90e8bd4d8cabdf94bf9c96d06fdc3", "shasum": "" }, "require": { @@ -3600,20 +3600,20 @@ ], "description": "Symfony Translation Component", "homepage": "https://symfony.com", - "time": "2017-05-22T07:42:36+00:00" + "time": "2017-06-24T16:45:30+00:00" }, { "name": "symfony/var-dumper", - "version": "v3.3.2", + "version": "v3.3.4", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "347c4247a3e40018810b476fcd5dec36d46d08dc" + "reference": "9ee920bba1d2ce877496dcafca7cbffff4dbe08a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/347c4247a3e40018810b476fcd5dec36d46d08dc", - "reference": "347c4247a3e40018810b476fcd5dec36d46d08dc", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/9ee920bba1d2ce877496dcafca7cbffff4dbe08a", + "reference": "9ee920bba1d2ce877496dcafca7cbffff4dbe08a", "shasum": "" }, "require": { @@ -3668,7 +3668,7 @@ "debug", "dump" ], - "time": "2017-06-02T09:10:29+00:00" + "time": "2017-07-05T13:02:37+00:00" }, { "name": "tijsverkoyen/css-to-inline-styles", @@ -4362,6 +4362,175 @@ ], "time": "2017-04-12T18:52:22+00:00" }, + { + "name": "php-mock/php-mock", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-mock/php-mock.git", + "reference": "bfa2d17d64dbf129073a7ba2051a96ce52749570" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-mock/php-mock/zipball/bfa2d17d64dbf129073a7ba2051a96ce52749570", + "reference": "bfa2d17d64dbf129073a7ba2051a96ce52749570", + "shasum": "" + }, + "require": { + "php": ">=5.5", + "phpunit/php-text-template": "^1" + }, + "replace": { + "malkusch/php-mock": "*" + }, + "require-dev": { + "phpunit/phpunit": "^4|^5" + }, + "suggest": { + "php-mock/php-mock-mockery": "Allows using PHPMockery for Mockery integration", + "php-mock/php-mock-phpunit": "Allows integration into PHPUnit testcase with the trait PHPMock." + }, + "type": "library", + "autoload": { + "psr-4": { + "phpmock\\": [ + "classes/", + "tests/unit/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "WTFPL" + ], + "authors": [ + { + "name": "Markus Malkusch", + "email": "markus@malkusch.de", + "homepage": "http://markus.malkusch.de", + "role": "Developer" + } + ], + "description": "PHP-Mock can mock built-in PHP functions (e.g. time()). PHP-Mock relies on PHP's namespace fallback policy. No further extension is needed.", + "homepage": "https://github.com/php-mock/php-mock", + "keywords": [ + "BDD", + "TDD", + "function", + "mock", + "stub", + "test", + "test double" + ], + "time": "2015-11-11T22:37:09+00:00" + }, + { + "name": "php-mock/php-mock-integration", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-mock/php-mock-integration.git", + "reference": "e83fb65dd20cd3cf250d554cbd4682b96b684f4b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-mock/php-mock-integration/zipball/e83fb65dd20cd3cf250d554cbd4682b96b684f4b", + "reference": "e83fb65dd20cd3cf250d554cbd4682b96b684f4b", + "shasum": "" + }, + "require": { + "php": ">=5.5", + "php-mock/php-mock": "^1", + "phpunit/php-text-template": "^1" + }, + "require-dev": { + "phpunit/phpunit": "^4|^5" + }, + "type": "library", + "autoload": { + "psr-4": { + "phpmock\\integration\\": "classes/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "WTFPL" + ], + "authors": [ + { + "name": "Markus Malkusch", + "email": "markus@malkusch.de", + "homepage": "http://markus.malkusch.de", + "role": "Developer" + } + ], + "description": "Integration package for PHP-Mock", + "homepage": "https://github.com/php-mock/php-mock-integration", + "keywords": [ + "BDD", + "TDD", + "function", + "mock", + "stub", + "test", + "test double" + ], + "time": "2015-10-26T21:21:42+00:00" + }, + { + "name": "php-mock/php-mock-phpunit", + "version": "1.1.2", + "source": { + "type": "git", + "url": "https://github.com/php-mock/php-mock-phpunit.git", + "reference": "359e3038c016cee4c8f8db6387bcab3fcdebada0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-mock/php-mock-phpunit/zipball/359e3038c016cee4c8f8db6387bcab3fcdebada0", + "reference": "359e3038c016cee4c8f8db6387bcab3fcdebada0", + "shasum": "" + }, + "require": { + "php": ">=5.5", + "php-mock/php-mock-integration": "^1", + "phpunit/phpunit": "^4.0.0 || ^5.0.0" + }, + "conflict": { + "phpunit/phpunit-mock-objects": "3.2.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "phpmock\\phpunit\\": "classes/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "WTFPL" + ], + "authors": [ + { + "name": "Markus Malkusch", + "email": "markus@malkusch.de", + "homepage": "http://markus.malkusch.de", + "role": "Developer" + } + ], + "description": "Mock built-in PHP functions (e.g. time()) with PHPUnit. This package relies on PHP's namespace fallback policy. No further extension is needed.", + "homepage": "https://github.com/php-mock/php-mock-phpunit", + "keywords": [ + "BDD", + "TDD", + "function", + "mock", + "phpunit", + "stub", + "test", + "test double" + ], + "time": "2016-06-15T23:36:13+00:00" + }, { "name": "phpdocumentor/reflection-common", "version": "1.0", @@ -4904,16 +5073,16 @@ }, { "name": "phpunit/phpunit-mock-objects", - "version": "3.4.3", + "version": "3.4.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "3ab72b65b39b491e0c011e2e09bb2206c2aa8e24" + "reference": "a23b761686d50a560cc56233b9ecf49597cc9118" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/3ab72b65b39b491e0c011e2e09bb2206c2aa8e24", - "reference": "3ab72b65b39b491e0c011e2e09bb2206c2aa8e24", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/a23b761686d50a560cc56233b9ecf49597cc9118", + "reference": "a23b761686d50a560cc56233b9ecf49597cc9118", "shasum": "" }, "require": { @@ -4959,7 +5128,7 @@ "mock", "xunit" ], - "time": "2016-12-08T20:27:08+00:00" + "time": "2017-06-30T09:13:00+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", @@ -5586,7 +5755,7 @@ }, { "name": "symfony/class-loader", - "version": "v3.3.2", + "version": "v3.3.4", "source": { "type": "git", "url": "https://github.com/symfony/class-loader.git", @@ -5642,16 +5811,16 @@ }, { "name": "symfony/config", - "version": "v3.3.2", + "version": "v3.3.4", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "35716d4904e0506a7a5a9bcf23f854aeb5719bca" + "reference": "a094618deb9a3fe1c3cf500a796e167d0495a274" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/35716d4904e0506a7a5a9bcf23f854aeb5719bca", - "reference": "35716d4904e0506a7a5a9bcf23f854aeb5719bca", + "url": "https://api.github.com/repos/symfony/config/zipball/a094618deb9a3fe1c3cf500a796e167d0495a274", + "reference": "a094618deb9a3fe1c3cf500a796e167d0495a274", "shasum": "" }, "require": { @@ -5659,10 +5828,12 @@ "symfony/filesystem": "~2.8|~3.0" }, "conflict": { - "symfony/dependency-injection": "<3.3" + "symfony/dependency-injection": "<3.3", + "symfony/finder": "<3.3" }, "require-dev": { "symfony/dependency-injection": "~3.3", + "symfony/finder": "~3.3", "symfony/yaml": "~3.0" }, "suggest": { @@ -5698,20 +5869,20 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2017-06-02T18:07:20+00:00" + "time": "2017-06-16T12:40:34+00:00" }, { "name": "symfony/filesystem", - "version": "v3.3.2", + "version": "v3.3.4", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "c709670bf64721202ddbe4162846f250735842c0" + "reference": "311fa718389efbd8b627c272b9324a62437018cc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/c709670bf64721202ddbe4162846f250735842c0", - "reference": "c709670bf64721202ddbe4162846f250735842c0", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/311fa718389efbd8b627c272b9324a62437018cc", + "reference": "311fa718389efbd8b627c272b9324a62437018cc", "shasum": "" }, "require": { @@ -5747,11 +5918,11 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2017-05-28T14:08:56+00:00" + "time": "2017-06-24T09:29:48+00:00" }, { "name": "symfony/stopwatch", - "version": "v3.3.2", + "version": "v3.3.4", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", @@ -5800,16 +5971,16 @@ }, { "name": "symfony/yaml", - "version": "v3.3.2", + "version": "v3.3.4", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "9752a30000a8ca9f4b34b5227d15d0101b96b063" + "reference": "1f93a8d19b8241617f5074a123e282575b821df8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/9752a30000a8ca9f4b34b5227d15d0101b96b063", - "reference": "9752a30000a8ca9f4b34b5227d15d0101b96b063", + "url": "https://api.github.com/repos/symfony/yaml/zipball/1f93a8d19b8241617f5074a123e282575b821df8", + "reference": "1f93a8d19b8241617f5074a123e282575b821df8", "shasum": "" }, "require": { @@ -5851,7 +6022,7 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2017-06-02T22:05:06+00:00" + "time": "2017-06-15T12:58:50+00:00" }, { "name": "webmozart/assert", diff --git a/tests/Unit/Services/ApiKeyServiceTest.php b/tests/Unit/Services/ApiKeyServiceTest.php new file mode 100644 index 000000000..e48ead4ca --- /dev/null +++ b/tests/Unit/Services/ApiKeyServiceTest.php @@ -0,0 +1,127 @@ +. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +namespace Tests\Unit\Services; + +use Illuminate\Contracts\Encryption\Encrypter; +use Illuminate\Database\ConnectionInterface; +use Mockery as m; +use phpmock\phpunit\PHPMock; +use Pterodactyl\Contracts\Repository\ApiKeyRepositoryInterface; +use Pterodactyl\Services\ApiKeyService; +use Pterodactyl\Services\ApiPermissionService; +use Tests\TestCase; + +class ApiKeyServiceTest extends TestCase +{ + use PHPMock; + + /** + * @var \Illuminate\Database\ConnectionInterface + */ + protected $database; + + /** + * @var \Illuminate\Contracts\Encryption\Encrypter + */ + protected $encrypter; + + /** + * @var \Pterodactyl\Services\ApiPermissionService + */ + protected $permissions; + + /** + * @var \Pterodactyl\Contracts\Repository\ApiKeyRepositoryInterface + */ + protected $repository; + + /** + * @var \Pterodactyl\Services\ApiKeyService + */ + protected $service; + + public function setUp() + { + parent::setUp(); + + $this->database = m::mock(ConnectionInterface::class); + $this->encrypter = m::mock(Encrypter::class); + $this->permissions = m::mock(ApiPermissionService::class); + $this->repository = m::mock(ApiKeyRepositoryInterface::class); + + $this->service = new ApiKeyService( + $this->repository, $this->database, $this->encrypter, $this->permissions + ); + } + + /** + * Test that the service is able to create a keypair and assign the correct permissions. + */ + public function test_create_function() + { + $this->getFunctionMock('\\Pterodactyl\\Services', 'random_bytes') + ->expects($this->exactly(2)) + ->willReturnCallback(function ($bytes) { + return hex2bin(str_pad('', $bytes * 2, '0')); + }); + + $this->database->shouldReceive('beginTransaction')->withNoArgs()->once()->andReturnNull(); + $this->encrypter->shouldReceive('encrypt')->with(str_pad('', 64, '0')) + ->once()->andReturn('encrypted-secret'); + + $this->repository->shouldReceive('create')->with([ + 'test-data' => 'test', + 'public' => str_pad('', 16, '0'), + 'secret' => 'encrypted-secret', + ], true, true)->once()->andReturn((object) ['id' => 1]); + + $this->permissions->shouldReceive('getPermissions')->withNoArgs()->once()->andReturn([ + '_user' => ['server' => ['list']], + 'server' => ['create'], + ]); + + $this->permissions->shouldReceive('create')->with(1, 'user.server-list')->once()->andReturnNull(); + $this->permissions->shouldReceive('create')->with(1, 'server-create')->once()->andReturnNull(); + + $this->database->shouldReceive('commit')->withNoArgs()->once()->andReturnNull(); + + $response = $this->service->create( + ['test-data' => 'test'], ['invalid-node', 'server-list'], ['invalid-node', 'server-create'] + ); + + $this->assertNotEmpty($response); + $this->assertEquals(str_pad('', 64, '0'), $response); + } + + /** + * Test that an API key can be revoked. + */ + public function test_revoke_function() + { + $this->repository->shouldReceive('delete')->with(1)->once()->andReturn(true); + + $this->assertTrue($this->service->revoke(1)); + } +} diff --git a/tests/Unit/Services/ApiPermissionServiceTest.php b/tests/Unit/Services/ApiPermissionServiceTest.php new file mode 100644 index 000000000..8e730623c --- /dev/null +++ b/tests/Unit/Services/ApiPermissionServiceTest.php @@ -0,0 +1,77 @@ +. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +namespace Tests\Unit\Services; + +use Mockery as m; +use Pterodactyl\Contracts\Repository\ApiPermissionRepositoryInterface; +use Pterodactyl\Models\APIPermission; +use Pterodactyl\Services\ApiPermissionService; +use Tests\TestCase; + +class ApiPermissionServiceTest extends TestCase +{ + /** + * @var \Pterodactyl\Contracts\Repository\ApiPermissionRepositoryInterface + */ + protected $repository; + + /** + * @var \Pterodactyl\Services\ApiPermissionService + */ + protected $service; + + /** + * Setup tests. + */ + public function setUp() + { + parent::setUp(); + + $this->repository = m::mock(ApiPermissionRepositoryInterface::class); + $this->service = new ApiPermissionService($this->repository); + } + + /** + * Test that a new API permission can be assigned to a key. + */ + public function test_create_function() + { + $this->repository->shouldReceive('withoutFresh')->withNoArgs()->once()->andReturnSelf() + ->shouldReceive('create')->with(['key_id' => 1, 'permission' => 'test-permission']) + ->once()->andReturn(true); + + $this->assertTrue($this->service->create(1, 'test-permission')); + } + + /** + * Test that function returns an array of all the permissions available as defined on the model. + */ + public function test_get_permissions_function() + { + $this->repository->shouldReceive('getModel')->withNoArgs()->once()->andReturn(new APIPermission()); + + $this->assertEquals(APIPermission::CONST_PERMISSIONS, $this->service->getPermissions()); + } +}