Skip to content

Commit

Permalink
✨ v5
Browse files Browse the repository at this point in the history
  • Loading branch information
codemasher committed Jul 8, 2023
1 parent 0556c5c commit 1b7ddb3
Show file tree
Hide file tree
Showing 21 changed files with 101 additions and 116 deletions.
6 changes: 0 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,6 @@ jobs:
fail-fast: true
matrix:
php-version:
- "7.4"
- "8.0"
- "8.1"
- "8.2"
- "8.3"

Expand Down Expand Up @@ -63,9 +60,6 @@ jobs:
- ubuntu-latest
- windows-latest
php-version:
- "7.4"
- "8.0"
- "8.1"
- "8.2"
- "8.3"

Expand Down
3 changes: 1 addition & 2 deletions .phan/config.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
// that functions removed in php 7.0 exist.
// (See `backward_compatibility_checks` for additional options)
'target_php_version' => null,
'minimum_target_php_version' => '7.4',
'minimum_target_php_version' => '8.2',

// A list of directories that should be parsed for class and
// method information. After excluding the directories
Expand Down Expand Up @@ -53,6 +53,5 @@
],
'suppress_issue_types' => [
'PhanAccessMethodInternal',
'PhanDeprecatedFunction',
],
];
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ A generator for counter based ([RFC 4226](https://tools.ietf.org/html/rfc4226))

# Documentation
## Requirements
- PHP 7.4+
- PHP 8.2+
- [`ext-curl`](https://www.php.net/manual/book.curl) for Battle.net and Steam Guard server time synchronization
- [`ext-gmp`](https://www.php.net/manual/book.gmp) for Battle.net authenticator secret retrieval (RSA encryption)
- [`ext-sodium`](https://www.php.net/manual/book.sodium) for constant time implementations of base64 encode/decode and hex2bin/bin2hex
Expand All @@ -29,11 +29,11 @@ A generator for counter based ([RFC 4226](https://tools.ietf.org/html/rfc4226))

via terminal: `composer require chillerlan/php-authenticator`

*composer.json* (note: replace `dev-main` with a [version constraint](https://getcomposer.org/doc/articles/versions.md#writing-version-constraints), e.g. `^4.1` - see [releases](https://github.com/chillerlan/php-authenticator/releases) for valid versions)
*composer.json* (note: replace `dev-main` with a [version constraint](https://getcomposer.org/doc/articles/versions.md#writing-version-constraints), e.g. `^5.0` - see [releases](https://github.com/chillerlan/php-authenticator/releases) for valid versions)
```json
{
"require": {
"php": "^7.4 || ^8.0",
"php": "^8.2",
"chillerlan/php-authenticator": "dev-main"
}
}
Expand Down
10 changes: 5 additions & 5 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "chillerlan/php-authenticator",
"description": "A generator for counter- and time based 2-factor authentication codes (Google Authenticator). PHP 7.4+",
"description": "A generator for counter- and time based 2-factor authentication codes (Google Authenticator). PHP 8.2+",
"homepage": "https://github.com/chillerlan/php-authenticator",
"license": "MIT",
"type": "library",
Expand All @@ -21,8 +21,8 @@
"minimum-stability": "stable",
"prefer-stable": true,
"require": {
"php": "^7.4 || ^8.0",
"chillerlan/php-settings-container": "^2.1.4 || ^3.0",
"php": "^8.2",
"chillerlan/php-settings-container": "^3.0",
"paragonie/constant_time_encoding": "^2.6"
},
"require-dev": {
Expand All @@ -32,7 +32,7 @@
"ext-sodium": "*",
"phan/phan": "^5.4",
"phpmd/phpmd": "^2.13",
"phpunit/phpunit": "^9.6",
"phpunit/phpunit": "^10.2",
"squizlabs/php_codesniffer": "^3.7"
},
"suggest": {
Expand All @@ -50,7 +50,7 @@
},
"scripts": {
"phpunit": "@php vendor/bin/phpunit",
"phan": "@php vendor/bin/phan"
"phan": "@php vendor/bin/phan --allow-polyfill-parser"
},
"config": {
"lock": false,
Expand Down
20 changes: 13 additions & 7 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -1,23 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.5/phpunit.xsd"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.2/phpunit.xsd"
bootstrap="vendor/autoload.php"
cacheResultFile=".build/phpunit.result.cache"
colors="true"
verbose="true"
beStrictAboutOutputDuringTests="true"
>
<testsuites>
<testsuite name="php-authenticator test suite">
<directory suffix=".php">./tests</directory>
<directory suffix=".php">./tests/</directory>
<exclude>tests/Authenticators/AuthenticatorInterfaceTestAbstract.php</exclude>
</testsuite>
</testsuites>
<coverage processUncoveredFiles="true">
<include>
<directory suffix=".php">./src</directory>
</include>
<coverage>
<report>
<clover outputFile=".build/coverage/clover.xml"/>
<xml outputDirectory=".build/coverage/coverage-xml"/>
</report>
</coverage>
<logging>
<junit outputFile=".build/logs/junit.xml"/>
</logging>
<source>
<include>
<directory>./src</directory>
</include>
</source>
</phpunit>
19 changes: 9 additions & 10 deletions src/Authenticator.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use chillerlan\Authenticator\Authenticators\AuthenticatorInterface;
use chillerlan\Settings\SettingsContainerInterface;
use InvalidArgumentException;
use SensitiveParameter;
use function http_build_query;
use function rawurlencode;
use function sprintf;
Expand All @@ -30,15 +31,14 @@
*/
class Authenticator{

/** @var \chillerlan\Settings\SettingsContainerInterface|\chillerlan\Authenticator\AuthenticatorOptions */
protected SettingsContainerInterface $options;
protected AuthenticatorInterface $authenticator;
protected string $mode = AuthenticatorInterface::TOTP;
protected SettingsContainerInterface|AuthenticatorOptions $options;
protected AuthenticatorInterface $authenticator;
protected string $mode = AuthenticatorInterface::TOTP;

/**
* Authenticator constructor
*/
public function __construct(SettingsContainerInterface $options = null, string $secret = null){
public function __construct(SettingsContainerInterface|AuthenticatorOptions $options = null, string $secret = null){
// phpcs:ignore
$this->setOptions($options ?? new AuthenticatorOptions);

Expand All @@ -54,14 +54,13 @@ public function __construct(SettingsContainerInterface $options = null, string $
* Please note that this will reset the secret phrase stored with the authenticator instance
* if a different mode than the current is given.
*/
public function setOptions(SettingsContainerInterface $options):self{
public function setOptions(SettingsContainerInterface|AuthenticatorOptions $options):self{
$this->options = $options;

// invoke a new authenticator interface if necessary
if(!isset($this->authenticator) || $this->options->mode !== $this->mode){
$class = AuthenticatorInterface::MODES[$this->options->mode];
$this->mode = $this->options->mode;
$this->authenticator = new $class;
$this->authenticator = new (AuthenticatorInterface::MODES[$this->options->mode])($this->options);
}

$this->authenticator->setOptions($this->options);
Expand All @@ -74,7 +73,7 @@ public function setOptions(SettingsContainerInterface $options):self{
*
* @codeCoverageIgnore
*/
public function setSecret(string $encodedSecret):self{
public function setSecret(#[SensitiveParameter] string $encodedSecret):self{
$this->authenticator->setSecret($encodedSecret);

return $this;
Expand Down Expand Up @@ -120,7 +119,7 @@ public function code(int $data = null):string{
*
* @codeCoverageIgnore
*/
public function verify(string $otp, int $data = null):bool{
public function verify(#[SensitiveParameter] string $otp, int $data = null):bool{
return $this->authenticator->verify($otp, $data);
}

Expand Down
14 changes: 7 additions & 7 deletions src/Authenticators/AuthenticatorAbstract.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use chillerlan\Settings\SettingsContainerInterface;
use InvalidArgumentException;
use RuntimeException;
use SensitiveParameter;
use function random_bytes;
use function time;
use function trim;
Expand All @@ -26,16 +27,15 @@ abstract class AuthenticatorAbstract implements AuthenticatorInterface{

protected const userAgent = 'chillerlanAuthenticator/5.0 +https://github.com/chillerlan/php-authenticator';

/** @var \chillerlan\Settings\SettingsContainerInterface|\chillerlan\Authenticator\AuthenticatorOptions */
protected SettingsContainerInterface $options;
protected ?string $secret = null;
protected int $serverTime = 0;
protected int $lastRequestTime = 0;
protected SettingsContainerInterface|AuthenticatorOptions $options;
protected ?string $secret = null;
protected int $serverTime = 0;
protected int $lastRequestTime = 0;

/**
* AuthenticatorInterface constructor
*/
public function __construct(SettingsContainerInterface $options = null){
public function __construct(SettingsContainerInterface|AuthenticatorOptions $options = null){
// phpcs:ignore
$this->setOptions($options ?? new AuthenticatorOptions);
}
Expand All @@ -52,7 +52,7 @@ public function setOptions(SettingsContainerInterface $options):AuthenticatorInt
/**
* @inheritDoc
*/
public function setSecret(string $encodedSecret):AuthenticatorInterface{
public function setSecret(#[SensitiveParameter] string $encodedSecret):AuthenticatorInterface{
$this->secret = Base32::decode($this->checkEncodedSecret($encodedSecret));

return $this;
Expand Down
9 changes: 5 additions & 4 deletions src/Authenticators/AuthenticatorInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
namespace chillerlan\Authenticator\Authenticators;

use chillerlan\Settings\SettingsContainerInterface;
use SensitiveParameter;

/**
*
Expand Down Expand Up @@ -49,7 +50,7 @@ public function setOptions(SettingsContainerInterface $options):AuthenticatorInt
*
* @throws \RuntimeException
*/
public function setSecret(string $encodedSecret):AuthenticatorInterface;
public function setSecret(#[SensitiveParameter] string $encodedSecret):AuthenticatorInterface;

/**
* Returns an encoded representation of the current secret phrase
Expand Down Expand Up @@ -89,14 +90,14 @@ public function getHMAC(int $counter):string;
*
* @internal
*/
public function getCode(string $hmac):int;
public function getCode(#[SensitiveParameter] string $hmac):int;

/**
* Formats the final output OTP from the given intermediate $code
*
* @internal
*/
public function getOTP(int $code):string;
public function getOTP(#[SensitiveParameter] int $code):string;

/**
* Creates a new OTP code with the given secret
Expand All @@ -114,6 +115,6 @@ public function code(int $data = null):string;
* - a UNIX timestamp (TOTP)
* - a counter value (HOTP)
*/
public function verify(string $otp, int $data = null):bool;
public function verify(#[SensitiveParameter] string $otp, int $data = null):bool;

}
21 changes: 13 additions & 8 deletions src/Authenticators/BattleNet.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use chillerlan\Authenticator\Common\Hex;
use InvalidArgumentException;
use RuntimeException;
use SensitiveParameter;
use function array_reverse;
use function array_unshift;
use function curl_close;
Expand Down Expand Up @@ -155,7 +156,7 @@ public function getHMAC(int $counter):string{
/**
* @inheritDoc
*/
public function getOTP(int $code):string{
public function getOTP(#[SensitiveParameter] int $code):string{
$code %= 100000000;

// length is fixed to 8 for Battle.net
Expand All @@ -182,7 +183,11 @@ public function getServerTime():int{
* Retrieves the secret from Battle.net using the given serial and restore code.
* If the public key for the serial is given (from a previous retrieval), it saves a server request.
*/
public function restoreSecret(string $serial, string $restore_code, string $public_key = null):array{
public function restoreSecret(
#[SensitiveParameter] string $serial,
#[SensitiveParameter] string $restore_code,
#[SensitiveParameter] string $public_key = null
):array{
$serial = $this->cleanSerial($serial);
$region = $this->getRegion($serial);

Expand Down Expand Up @@ -257,7 +262,7 @@ private function getRegion(string $serial):string{
*
* @throws \InvalidArgumentException
*/
private function cleanSerial(string $serial):string{
private function cleanSerial(#[SensitiveParameter] string $serial):string{
$serial = str_replace('-', '', strtoupper(trim($serial)));

if(!preg_match('/^[CNEUSKR]{2}\d{12}$/', $serial)){
Expand All @@ -270,7 +275,7 @@ private function cleanSerial(string $serial):string{
/**
*
*/
private function formatSerial(string $serial):string{
private function formatSerial(#[SensitiveParameter] string $serial):string{
$serial = $this->cleanSerial($serial);
// split the numeric part into 3x 4 numbers
$blocks = str_split(substr($serial, 2), 4);
Expand Down Expand Up @@ -318,7 +323,7 @@ private function request(string $endpoint, string $region, string $data = null):
* Convert restore code char to byte but with appropriate mapping to exclude I,L,O and S.
* e.g. A=10 but J=18 not 19 (as I is missing)
*/
private function convertRestoreCodeToByte(string $restore_code):string{
private function convertRestoreCodeToByte(#[SensitiveParameter] string $restore_code):string{
$chars = unpack('C*', $restore_code);

foreach($chars as &$c){
Expand Down Expand Up @@ -354,7 +359,7 @@ private function convertRestoreCodeToByte(string $restore_code):string{
/**
* Convert restore code byte to char but with appropriate mapping to exclude I,L,O and S.
*/
private function convertRestoreCodeToChar(string $data):string{
private function convertRestoreCodeToChar(#[SensitiveParameter] string $data):string{
$chars = unpack('C*', $data);

foreach($chars as &$c){
Expand Down Expand Up @@ -390,7 +395,7 @@ private function convertRestoreCodeToChar(string $data):string{
/**
*
*/
private function encrypt(string $data):string{
private function encrypt(#[SensitiveParameter] string $data):string{
$num = gmp_powm(gmp_import($data), self::rsa_exp_base10, self::rsa_mod_base10); // gmp_init(self::rsa_mod_base16, 16)
$zero = gmp_init('0', 10);
$ret = [];
Expand All @@ -406,7 +411,7 @@ private function encrypt(string $data):string{
/**
* @throws \RuntimeException
*/
private function decrypt(string $data, string $key):string{
private function decrypt(#[SensitiveParameter] string $data, #[SensitiveParameter] string $key):string{

if(strlen($data) !== strlen($key)){
throw new RuntimeException('The decryption key size and data size doesn\'t match');
Expand Down
7 changes: 4 additions & 3 deletions src/Authenticators/HOTP.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
namespace chillerlan\Authenticator\Authenticators;

use RuntimeException;
use SensitiveParameter;
use function hash_equals;
use function hash_hmac;
use function pack;
Expand Down Expand Up @@ -51,7 +52,7 @@ public function getHMAC(int $counter):string{
/**
* @inheritDoc
*/
public function getCode(string $hmac):int{
public function getCode(#[SensitiveParameter] string $hmac):int{
$data = unpack('C*', $hmac);
$b = ($data[strlen($hmac)] & 0xF);
// phpcs:ignore
Expand All @@ -61,7 +62,7 @@ public function getCode(string $hmac):int{
/**
* @inheritDoc
*/
public function getOTP(int $code):string{
public function getOTP(#[SensitiveParameter] int $code):string{
$code %= (10 ** $this->options->digits);

return str_pad((string)$code, $this->options->digits, '0', STR_PAD_LEFT);
Expand All @@ -79,7 +80,7 @@ public function code(int $data = null):string{
/**
* @inheritDoc
*/
public function verify(string $otp, int $data = null):bool{
public function verify(#[SensitiveParameter] string $otp, int $data = null):bool{
return hash_equals($this->code($data), $otp);
}

Expand Down
Loading

0 comments on commit 1b7ddb3

Please sign in to comment.