Skip to content

Commit

Permalink
Merge pull request #214 from Spomky-Labs/11.2.x-merge-up-into-11.3.x_…
Browse files Browse the repository at this point in the history
…xhiMGKTI

Merge release 11.2.1 into 11.3.x
  • Loading branch information
Spomky authored Apr 15, 2024
2 parents 3380f38 + 2f13de8 commit 37243ac
Show file tree
Hide file tree
Showing 13 changed files with 214 additions and 137 deletions.
35 changes: 35 additions & 0 deletions .github/workflows/infection.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# yaml-language-server: $schema=https://json.schemastore.org/github-workflow

name: "Infection"

on:
push:
branches:
- "*.x"

jobs:
mutation_testing:
name: "5️⃣ Mutation Testing"
runs-on: "ubuntu-latest"
steps:
- name: "Set up PHP"
uses: "shivammathur/setup-php@v2"
with:
php-version: "8.1"
extensions: "mbstring"
coverage: "xdebug"

- name: "Checkout code"
uses: "actions/checkout@v3"

- name: "Fetch Git base reference"
run: "git fetch --depth=1 origin ${GITHUB_BASE_REF}"

- name: "Install dependencies"
uses: "ramsey/composer-install@v2"
with:
dependency-versions: "highest"
composer-options: "--optimize-autoloader"

- name: "Execute Infection"
run: "make ci-mu"
10 changes: 2 additions & 8 deletions .github/workflows/integrate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ jobs:
- "ubuntu-latest"
php-version:
- "8.1"
- "8.2"
- "8.3"
dependencies:
- "lowest"
- "highest"
Expand All @@ -80,14 +82,6 @@ jobs:
- name: "Execute tests (PHP)"
run: "make ci-cc"

# - name: Send coverage to Coveralls
# if: "matrix.php-version == '8.1' && matrix.dependencies == 'highest'"
# env:
# COVERALLS_REPO_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
# run: |
# wget "https://github.com/php-coveralls/php-coveralls/releases/download/v2.5.2/php-coveralls.phar"
# php ./php-coveralls.phar -v

static_analysis:
name: "3️⃣ Static Analysis"
needs:
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ TOTP / HOTP library in PHP
==========================

![Build Status](https://github.com/spomky-labs/otphp/workflows/Integrate/badge.svg)
![Build Status](https://github.com/spomky-labs/otphp/workflows/Infection/badge.svg)

[![Latest Stable Version](https://poser.pugx.org/spomky-labs/otphp/v/stable.png)](https://packagist.org/packages/spomky-labs/otphp)
[![Total Downloads](https://poser.pugx.org/spomky-labs/otphp/downloads.png)](https://packagist.org/packages/spomky-labs/otphp)
Expand Down
7 changes: 4 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,16 @@
},
"require-dev": {
"ekino/phpstan-banned-code": "^1.0",
"infection/infection": "^0.27",
"infection/infection": "^0.26|^0.27|^0.28",
"php-parallel-lint/php-parallel-lint": "^1.3",
"phpstan/phpstan": "^1.0",
"phpstan/phpstan-deprecation-rules": "^1.0",
"phpstan/phpstan-phpunit": "^1.0",
"phpstan/phpstan-strict-rules": "^1.0",
"phpunit/phpunit": "^10.1",
"phpunit/phpunit": "^9.5.26|^10.0|^11.0",
"qossmic/deptrac-shim": "^1.0",
"rector/rector": "^0.18",
"rector/rector": "1.0",
"symfony/phpunit-bridge": "^6.1|^7.0",
"symplify/easy-coding-standard": "^12.0"
},
"autoload": {
Expand Down
15 changes: 4 additions & 11 deletions ecs.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,7 @@
use Symplify\EasyCodingStandard\Config\ECSConfig;
use Symplify\EasyCodingStandard\ValueObject\Set\SetList;

$header = '';

return static function (ECSConfig $config) use ($header): void {
return static function (ECSConfig $config): void {
$config->import(SetList::PSR_12);
$config->import(SetList::CLEAN_CODE);
$config->import(SetList::DOCTRINE_ANNOTATIONS);
Expand Down Expand Up @@ -74,7 +72,7 @@
'strict' => true,
]);
$config->ruleWithConfiguration(HeaderCommentFixer::class, [
'header' => $header,
'header' => '',
]);
$config->ruleWithConfiguration(AlignMultilineCommentFixer::class, [
'comment_type' => 'all_multiline',
Expand All @@ -89,11 +87,6 @@
]);

$config->parallel();
$config->paths([
__DIR__.'/src',
__DIR__.'/tests',
]);
$config->skip([
PhpUnitTestClassRequiresCoversFixer::class
]);
$config->paths([__DIR__]);
$config->skip([__DIR__ . '/vendor', PhpUnitTestClassRequiresCoversFixer::class]);
};
10 changes: 0 additions & 10 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,3 @@ parameters:
message: "#^Parameter \\#1 \\$dateTime of method OTPHP\\\\Test\\\\ClockMock\\:\\:setDateTime\\(\\) expects DateTimeImmutable\\|null, DateTimeImmutable\\|false given\\.$#"
count: 5
path: tests/TOTPTest.php

-
message: "#^Parameter \\#1 \\$otp of method OTPHP\\\\TOTP\\:\\:verify\\(\\) expects non\\-empty\\-string, string given\\.$#"
count: 2
path: tests/TOTPTest.php

-
message: "#^Parameter \\#3 \\$leeway of method OTPHP\\\\TOTP\\:\\:verify\\(\\) expects int\\<0, max\\>\\|null, int given\\.$#"
count: 2
path: tests/TOTPTest.php
4 changes: 2 additions & 2 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.1/phpunit.xsd"
bootstrap="vendor/autoload.php"
colors="true"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
>
<testsuites>
<testsuite name="OTP Test Suite">
<directory>./tests</directory>
</testsuite>
</testsuites>
<coverage/>
<source>
<include>
<directory>./src</directory>
Expand Down
33 changes: 9 additions & 24 deletions rector.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,23 @@
declare(strict_types=1);

use Rector\Config\RectorConfig;
use Rector\Core\ValueObject\PhpVersion;
use Rector\Doctrine\Set\DoctrineSetList;
use Rector\Php74\Rector\Property\TypedPropertyRector;
use Rector\PHPUnit\CodeQuality\Rector\Class_\PreferPHPUnitThisCallRector;
use Rector\PHPUnit\Set\PHPUnitLevelSetList;
use Rector\PHPUnit\Set\PHPUnitSetList;
use Rector\Set\ValueObject\LevelSetList;
use Rector\Set\ValueObject\SetList;
use Rector\Symfony\Set\SymfonyLevelSetList;
use Rector\Symfony\Set\SymfonySetList;
use Rector\ValueObject\PhpVersion;

return static function (RectorConfig $config): void {
$config->sets([
SetList::DEAD_CODE,
LevelSetList::UP_TO_PHP_81,
SymfonyLevelSetList::UP_TO_SYMFONY_54,
SymfonySetList::SYMFONY_CODE_QUALITY,
SymfonySetList::SYMFONY_CONSTRUCTOR_INJECTION,
DoctrineSetList::DOCTRINE_CODE_QUALITY,
DoctrineSetList::ANNOTATIONS_TO_ATTRIBUTES,
PHPUnitLevelSetList::UP_TO_PHPUNIT_100,
PHPUnitSetList::PHPUNIT_CODE_QUALITY,
PHPUnitSetList::ANNOTATIONS_TO_ATTRIBUTES,
]);
$config->import(SetList::DEAD_CODE);
$config->import(LevelSetList::UP_TO_PHP_81);
$config->import(SymfonySetList::SYMFONY_CODE_QUALITY);
$config->import(PHPUnitSetList::PHPUNIT_100);
$config->import(PHPUnitSetList::ANNOTATIONS_TO_ATTRIBUTES);
$config->import(PHPUnitSetList::PHPUNIT_CODE_QUALITY);
$config->parallel();
$config->paths([
__DIR__ . '/src',
__DIR__ . '/tests',
]);
$config->skip([
PreferPHPUnitThisCallRector::class,
]);
$config->paths([__DIR__ . '/src', __DIR__ . '/tests']);
$config->skip([PreferPHPUnitThisCallRector::class]);
$config->phpVersion(PhpVersion::PHP_81);
$config->parallel();
$config->importNames();
Expand Down
6 changes: 6 additions & 0 deletions src/HOTP.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ public static function generate(): self
return self::createFromSecret(self::generateSecret());
}

/**
* @return 0|positive-int
*/
public function getCounter(): int
{
$value = $this->getParameter('counter');
Expand All @@ -63,6 +66,8 @@ public function getProvisioningUri(): string

/**
* If the counter is not provided, the OTP is verified at the actual counter.
*
* @param null|0|positive-int $counter
*/
public function verify(string $otp, null|int $counter = null, null|int $window = null): bool
{
Expand Down Expand Up @@ -112,6 +117,7 @@ private function getWindow(null|int $window): int

/**
* @param non-empty-string $otp
* @param 0|positive-int $counter
* @param null|0|positive-int $window
*/
private function verifyOtpWithWindow(string $otp, int $counter, null|int $window): bool
Expand Down
7 changes: 6 additions & 1 deletion src/OTP.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ public function getQrCodeUri(string $uri, string $placeholder): string
return str_replace($placeholder, $provisioning_uri, $uri);
}

/**
* @param 0|positive-int $input
*/
public function at(int $input): string
{
return $this->generateOTP($input);
Expand All @@ -51,6 +54,8 @@ final protected static function generateSecret(): string
/**
* The OTP at the specified input.
*
* @param 0|positive-int $input
*
* @return non-empty-string
*/
protected function generateOTP(int $input): string
Expand Down Expand Up @@ -98,7 +103,7 @@ protected function generateURI(string $type, array $options): string
$this->hasColon($label) === false || throw new InvalidArgumentException('Label must not contain a colon.');
$options = [...$options, ...$this->getParameters()];
$this->filterOptions($options);
$params = str_replace(['+', '%7E'], ['%20', '~'], http_build_query($options));
$params = str_replace(['+', '%7E'], ['%20', '~'], http_build_query($options, arg_separator: '&'));

return sprintf(
'otpauth://%s/%s?%s',
Expand Down
4 changes: 4 additions & 0 deletions src/OTPInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ public function setDigits(int $digits): void;
public function setDigest(string $digest): void;

/**
* Generate the OTP at the specified input.
*
* @param 0|positive-int $input
*
* @return non-empty-string Return the OTP at the specified timestamp
*/
public function at(int $input): string;
Expand Down
25 changes: 23 additions & 2 deletions src/TOTP.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,19 +90,31 @@ public function expiresIn(): int
return $period - ($this->clock->now()->getTimestamp() % $this->getPeriod());
}

/**
* The OTP at the specified input.
*
* @param 0|positive-int $input
*/
public function at(int $input): string
{
return $this->generateOTP($this->timecode($input));
}

public function now(): string
{
return $this->at($this->clock->now()->getTimestamp());
$timestamp = $this->clock->now()
->getTimestamp();
assert($timestamp >= 0, 'The timestamp must return a positive integer.');

return $this->at($timestamp);
}

/**
* If no timestamp is provided, the OTP is verified at the actual timestamp. When used, the leeway parameter will
* allow time drift. The passed value is in seconds.
*
* @param 0|positive-int $timestamp
* @param null|0|positive-int $leeway
*/
public function verify(string $otp, null|int $timestamp = null, null|int $leeway = null): bool
{
Expand All @@ -118,8 +130,12 @@ public function verify(string $otp, null|int $timestamp = null, null|int $leeway
$leeway < $this->getPeriod() || throw new InvalidArgumentException(
'The leeway must be lower than the TOTP period'
);
$timestampMinusLeeway = $timestamp - $leeway;
$timestampMinusLeeway >= 0 || throw new InvalidArgumentException(
'The timestamp must be greater than or equal to the leeway.'
);

return $this->compareOTP($this->at($timestamp - $leeway), $otp)
return $this->compareOTP($this->at($timestampMinusLeeway), $otp)
|| $this->compareOTP($this->at($timestamp), $otp)
|| $this->compareOTP($this->at($timestamp + $leeway), $otp);
}
Expand Down Expand Up @@ -184,6 +200,11 @@ protected function filterOptions(array &$options): void
ksort($options);
}

/**
* @param 0|positive-int $timestamp
*
* @return 0|positive-int
*/
private function timecode(int $timestamp): int
{
$timecode = (int) floor(($timestamp - $this->getEpoch()) / $this->getPeriod());
Expand Down
Loading

0 comments on commit 37243ac

Please sign in to comment.