diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml new file mode 100644 index 0000000..326fe1e --- /dev/null +++ b/.github/workflows/php.yml @@ -0,0 +1,89 @@ +name: PHP Tests + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +jobs: + tests: + name: PHP ${{ matrix.php-versions }} - ${{ matrix.db-platforms }} + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + php-versions: ['7.4', '8.0'] + db-platforms: ['MySQLi'] + mysql-versions: ['5.7'] + + services: + mysql: + image: mysql:${{ matrix.mysql-versions }} + env: + MYSQL_ALLOW_EMPTY_PASSWORD: yes + MYSQL_DATABASE: web_service_tests + MYSQL_USER: tests_user + ports: + - 3306:3306 + options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 + + steps: + - uses: actions/checkout@v3 + + - name: Setup PHP, with composer and extensions + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + tools: composer + coverage: xdebug + env: + update: true + + - name: Get composer cache directory + id: composercache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache dependencies + uses: actions/cache@v3 + with: + path: ${{ steps.composercache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install dependencies + run: composer install --ansi --no-interaction + + - name: Compute coverage option + uses: actions/github-script@v6 + id: phpunit-coverage-option + with: + script: 'return "${{ matrix.php-versions }}" == "8.0" ? "" : "--no-coverage"' + result-encoding: string + + - name: Test with PHPUnit + run: script -e -c "vendor/bin/phpunit --color=always --exclude-group=auto-review ${{ steps.phpunit-coverage-option.outputs.result }}" + + - name: Run Coveralls + if: matrix.php-versions == '8.0' + run: | + composer global require --ansi php-coveralls/php-coveralls:^2.4 + php-coveralls --coverage_clover=build/logs/clover.xml -v + env: + COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} + COVERALLS_PARALLEL: true + COVERALLS_FLAG_NAME: PHP ${{ matrix.php-versions }} - ${{ matrix.db-platforms }} + coveralls-finish: + runs-on: ubuntu-latest + needs: [tests] + + steps: + - name: Coveralls Finished + uses: coverallsapp/github-action@master + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + parallel-finished: true diff --git a/README.md b/README.md index ff89fb2..7cdf707 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,13 @@ Rest Server with Doctrine for Codeigniter 4 +[![Build Status](https://github.com/daycry/restserver/workflows/PHP%20Tests/badge.svg)](https://github.com/daycry/restserver/actions?query=workflow%3A%22PHP+Tests%22) +[![Coverage Status](https://coveralls.io/repos/github/daycry/restserver/badge.svg?branch=master)](https://coveralls.io/github/daycry/restserver?branch=master) +[![Downloads](https://poser.pugx.org/daycry/restserver/downloads)](https://packagist.org/packages/daycry/restserver) +[![GitHub release (latest by date)](https://img.shields.io/github/v/release/daycry/restserver)](https://packagist.org/packages/daycry/restserver) +[![GitHub stars](https://img.shields.io/github/stars/daycry/restserver)](https://packagist.org/packages/daycry/restserver) +[![GitHub license](https://img.shields.io/github/license/daycry/restserver)](https://github.com/daycry/restserver/blob/master/LICENSE) + ## Installation via composer Use the package with composer install @@ -28,8 +35,9 @@ $psr4 = [ Run command: - > php spark restserver:publish + > php spark restserver:publish > php spark settings:publish + > php spark jwt:publish This command will copy a config file to your app namespace. Then you can adjust it to your needs. By default file will be present in `app/Config/RestServer.php`. @@ -40,7 +48,7 @@ This command create rest server tables in your database. If you want load and Example Seed you can use this command. - >php spark db:seed Daycry\RestServer\Database\Seeds\ExampleSeeder + > php spark db:seed Daycry\RestServer\Database\Seeds\ExampleSeeder More information about install doctrine: https://github.com/daycry/doctrine diff --git a/composer.json b/composer.json index 0db4bd9..e7b9f15 100644 --- a/composer.json +++ b/composer.json @@ -12,17 +12,17 @@ ], "license": "MIT", "require": { - "php": ">=7.2 || ^8.0", + "php": ">=7.4 || ^8.0", "daycry/encryption": "^2.0", - "lcobucci/jwt": "^4.1", "daycry/settings": "^1.0", - "daycry/class-finder": "^1.0", - "daycry/relations": "^2.0" + "daycry/relations": "^2.0", + "daycry/jwt": "^1.0", + "daycry/class-finder": "^2.0" }, "require-dev": { "phpunit/phpunit": "^9.1", - "codeigniter4/framework": "4.1.2", + "codeigniter4/framework": "^4", "friendsofphp/php-cs-fixer": "3.6.*", "mikey179/vfsstream": "^1.6", "nexusphp/cs-config": "^3.3", diff --git a/phpunit.xml b/phpunit.xml index 66e106d..082b68c 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -52,9 +52,9 @@ - + - + diff --git a/src/Config/JWT.php b/src/Config/JWT.php deleted file mode 100644 index 5a014c1..0000000 --- a/src/Config/JWT.php +++ /dev/null @@ -1,23 +0,0 @@ -decode($username); + $jwtLibrary = new \Daycry\JWT\JWT(); - if (!$claims || !isset($valid_logins[ $claims->get('data') ])) { + try{ + $claims = $jwtLibrary->decode($username); + }catch( \Exception $ex) + { return false; - //throw \Daycry\RestServer\Exceptions\UnauthorizedException::forInvalidCredentials(); + } + + if (!$claims || $claims instanceof \Lcobucci\JWT\Validation\RequiredConstraintsViolated || !isset($valid_logins[ $claims->get('data') ])) { + // @codeCoverageIgnoreStart + return false; + // @codeCoverageIgnoreEnd } return $claims->get('data'); diff --git a/src/Libraries/JWT.php b/src/Libraries/JWT.php deleted file mode 100644 index 3b6dd6e..0000000 --- a/src/Libraries/JWT.php +++ /dev/null @@ -1,131 +0,0 @@ -JWTConfig = $config; - - if ($this->JWTConfig == null) { - $this->JWTConfig = config('JWT'); - } - - $this->configuration = Configuration::forSymmetricSigner( - new Sha256(), - InMemory::base64Encoded($this->JWTConfig->signer) - ); - } - - /** - * Set the attibute to data claim - * Used if data is not an array - */ - public function setParamData(string $data) - { - $this->paramData = $data; - } - - public function setSplitData() - { - $this->split = true; - - return $this; - } - - public function encode($data, $uid = null) - { - $now = new \DateTimeImmutable(); - - $token = $this->configuration->builder(); - - if (is_array($data) || is_object($data)) { - if ($this->split) { - foreach ($data as $key => $value) { - $token->withClaim($key, $value); - } - } else { - $token->withClaim($this->paramData, \json_encode($data)); - } - } else { - $token->withClaim($this->paramData, $data); - } - - // Configures a new claim, called "uid" - if ($uid) { - $token->withClaim('uid', $uid); - } - - // Configures the issuer (iss claim) - $token->issuedBy($this->JWTConfig->issuer) - // Configures the audience (aud claim) - ->permittedFor($this->JWTConfig->audience) - // Configures the id (jti claim) - ->identifiedBy($this->JWTConfig->identifier) - // Configures the time that the token was issue (iat claim) - ->issuedAt($now) - // Configures the time that the token can be used (nbf claim) - ->canOnlyBeUsedAfter($now->modify($this->JWTConfig->canOnlyBeUsedAfter)) - // Configures the expiration time of the token (exp claim) - ->expiresAt($now->modify($this->JWTConfig->expiresAt)) - ->withHeader('type', 'Bearer'); - - // Builds a new token; - $token = $token->getToken($this->configuration->signer(), $this->configuration->signingKey()); - - return $token->toString(); - } - - public function decode($data) - { - $token = $this->configuration->parser()->parse($data); - assert($token instanceof UnencryptedToken); - - $clock = new \Lcobucci\Clock\FrozenClock(new \DateTimeImmutable()); - - $constraints = [ - new \Lcobucci\JWT\Validation\Constraint\StrictValidAt($clock), - new \Lcobucci\JWT\Validation\Constraint\IdentifiedBy($this->JWTConfig->identifier), - new \Lcobucci\JWT\Validation\Constraint\PermittedFor($this->JWTConfig->audience) - ]; - - try { - $this->configuration->validator()->assert($token, ...$constraints); - } catch (RequiredConstraintsViolated $e) { - return null; - } - - return $token->claims(); - } -} diff --git a/src/RestServer.php b/src/RestServer.php index 7a9d487..f5645d2 100644 --- a/src/RestServer.php +++ b/src/RestServer.php @@ -265,7 +265,6 @@ protected function _logRequest($authorized = false) { // Insert the request into the log table $logModel = new \Daycry\RestServer\Models\LogModel(); - //$logModel->setTableName( $this->_restConfig->configRestLogsTable ); $params = $this->args ? ($this->_restConfig->restLogsJsonParams == true ? \json_encode($this->args) : \serialize($this->args)) : null; $params = ($params != null && $this->_restConfig->restEncryptLogParams == true) ? $this->encryption->encrypt($params) : $params; diff --git a/tests/Auth/BasicTest.php b/tests/Auth/BasicTest.php index 9862ffe..6a14967 100644 --- a/tests/Auth/BasicTest.php +++ b/tests/Auth/BasicTest.php @@ -1,6 +1,6 @@ assertStatus(401); $this->assertObjectHasAttribute("error", $content->messages); - $this->AssertSame("Invalid credentials", $content->messages->error); + $this->assertSame("Invalid credentials", $content->messages->error); } public function testBearerErrorNoBearer() @@ -86,7 +86,7 @@ public function testBearerErrorNoBearer() public function testBearerSuccess() { - $jwtLibrary = new \Daycry\RestServer\Libraries\JWT(); + $jwtLibrary = new \Daycry\JWT\JWT(); $bearer = $jwtLibrary->encode('admin'); $this->withHeaders([ @@ -116,9 +116,9 @@ public function testBearerSuccess() public function testBearerWrongError() { - $config = new \Daycry\RestServer\Config\JWT(); + $config = new \Daycry\JWT\Config\JWT(); $config->identifier = '12345'; - $jwtLibrary = new \Daycry\RestServer\Libraries\JWT($config); + $jwtLibrary = new \Daycry\JWT\JWT($config); $jwtLibrary->setParamData('data'); $bearer = $jwtLibrary->encode('admin', 'uid'); @@ -136,12 +136,12 @@ public function testBearerWrongError() $result->assertStatus(401); $this->assertObjectHasAttribute("error", $content->messages); - $this->AssertSame("Invalid credentials", $content->messages->error); + $this->assertSame("Invalid credentials", $content->messages->error); } public function testBearerSetParamSuccess() { - $jwtLibrary = new \Daycry\RestServer\Libraries\JWT(); + $jwtLibrary = new \Daycry\JWT\JWT(); $jwtLibrary->setParamData('data'); $bearer = $jwtLibrary->encode('admin', 'uid'); @@ -172,7 +172,7 @@ public function testBearerSetParamSuccess() public function testBearerSplitDataSuccess() { - $jwtLibrary = new \Daycry\RestServer\Libraries\JWT(); + $jwtLibrary = new \Daycry\JWT\JWT(); $jwtLibrary->setSplitData(true); $data = array('username' => 'admin', 'split' => true); $bearer = $jwtLibrary->encode($data); diff --git a/tests/Auth/DigestTest.php b/tests/Auth/DigestTest.php index b4303ea..7f31750 100644 --- a/tests/Auth/DigestTest.php +++ b/tests/Auth/DigestTest.php @@ -1,6 +1,6 @@ decode($username); if ($claims->get('username') != 'admin') {