mirror of
https://github.com/RobThree/TwoFactorAuth.git
synced 2026-08-24 10:46:35 +00:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 65681de5a3 | |||
| dc681e1ced | |||
| 5f2611cde2 | |||
| 5d36d4feb0 | |||
| cb45226800 | |||
| 2d1ec8d265 | |||
| ae4da10ff1 | |||
| 66e1e030ba | |||
| e76f31e93b | |||
| 4203749bd2 | |||
| 4f1543f782 | |||
| 8a220fe37b | |||
| 8a5cb24967 | |||
| dc9f168746 | |||
| 0096cce02d | |||
| 042f347666 |
@@ -0,0 +1,30 @@
|
||||
name: Test Bacon QR Code Provider
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
php-version: ['5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1']
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-version }}
|
||||
tools: composer
|
||||
coverage: xdebug
|
||||
ini-values: error_reporting=E_ALL
|
||||
|
||||
- uses: ramsey/composer-install@v1
|
||||
|
||||
- run: composer require bacon/bacon-qr-code
|
||||
|
||||
- run: composer lint
|
||||
- run: composer test testsDependency/BaconQRCodeTest.php
|
||||
@@ -0,0 +1,46 @@
|
||||
name: Test Endroid QR Code Provider
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
php-version: ['8.0', '8.1']
|
||||
endroid-version: ["^4"]
|
||||
include:
|
||||
- php-version: 5.6
|
||||
# earliest supported version
|
||||
endroid-version: 2.2.1
|
||||
- php-version: 7.0
|
||||
endroid-version: 2.5.1
|
||||
- php-version: 7.1
|
||||
# this version is 7.1+
|
||||
endroid-version: 3.0.0
|
||||
- php-version: 7.2
|
||||
# all later versions are 7.3+
|
||||
endroid-version: 3.5.9
|
||||
- php-version: 7.3
|
||||
endroid-version: 3.9.7
|
||||
- php-version: 7.4
|
||||
endroid-version: 4.0.0
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-version }}
|
||||
tools: composer
|
||||
coverage: xdebug
|
||||
ini-values: error_reporting=E_ALL
|
||||
|
||||
- uses: ramsey/composer-install@v1
|
||||
|
||||
- run: composer require endroid/qrcode:${{ matrix.endroid-version }}
|
||||
|
||||
- run: composer test testsDependency/EndroidQRCodeTest.php
|
||||
@@ -10,7 +10,7 @@ jobs:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
php-version: ['5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0']
|
||||
php-version: ['5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1']
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
@@ -20,6 +20,7 @@ jobs:
|
||||
php-version: ${{ matrix.php-version }}
|
||||
tools: composer
|
||||
coverage: xdebug
|
||||
ini-values: error_reporting=E_ALL
|
||||
|
||||
- uses: ramsey/composer-install@v1
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2015 Rob Janssen
|
||||
Copyright (c) 2014-2021 Rob Janssen and contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "robthree/twofactorauth",
|
||||
"description": "Two Factor Authentication",
|
||||
"version": "1.8.1",
|
||||
"version": "1.8.2",
|
||||
"type": "library",
|
||||
"keywords": [ "Authentication", "Two Factor Authentication", "Multi Factor Authentication", "TFA", "MFA", "PHP", "Authenticator", "Authy" ],
|
||||
"homepage": "https://github.com/RobThree/TwoFactorAuth",
|
||||
|
||||
@@ -125,12 +125,19 @@ class BaconQrCodeProvider implements IQRCodeProvider
|
||||
{
|
||||
if (is_string($colour) && $colour[0] == '#') {
|
||||
$hexToRGB = function ($input) {
|
||||
// ensure input no longer has a # for more predictable division
|
||||
// PHP 8.1 does not like implicitly casting a float to an int
|
||||
$input = trim($input, '#');
|
||||
|
||||
if (strlen($input) != 3 && strlen($input) != 6) {
|
||||
throw new \RuntimeException('Colour should be a 3 or 6 character value after the #');
|
||||
}
|
||||
|
||||
// split the array into three chunks
|
||||
$split = str_split(trim($input, '#'), strlen($input) / 3);
|
||||
$split = str_split($input, strlen($input) / 3);
|
||||
|
||||
// cope with three character hex reference
|
||||
// three characters plus a # = 4
|
||||
if (strlen($input) == 4) {
|
||||
if (strlen($input) == 3) {
|
||||
array_walk($split, function (&$character) {
|
||||
$character = str_repeat($character, 2);
|
||||
});
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
<?php
|
||||
namespace RobThree\Auth\Providers\Qr;
|
||||
|
||||
use Endroid\QrCode\Color\Color;
|
||||
use Endroid\QrCode\ErrorCorrectionLevel;
|
||||
use Endroid\QrCode\ErrorCorrectionLevel\ErrorCorrectionLevelHigh;
|
||||
use Endroid\QrCode\ErrorCorrectionLevel\ErrorCorrectionLevelLow;
|
||||
use Endroid\QrCode\ErrorCorrectionLevel\ErrorCorrectionLevelMedium;
|
||||
use Endroid\QrCode\ErrorCorrectionLevel\ErrorCorrectionLevelQuartile;
|
||||
use Endroid\QrCode\QrCode;
|
||||
use Endroid\QrCode\Writer\PngWriter;
|
||||
|
||||
class EndroidQrCodeProvider implements IQRCodeProvider
|
||||
{
|
||||
@@ -11,8 +17,12 @@ class EndroidQrCodeProvider implements IQRCodeProvider
|
||||
public $margin;
|
||||
public $errorcorrectionlevel;
|
||||
|
||||
protected $endroid4 = false;
|
||||
|
||||
public function __construct($bgcolor = 'ffffff', $color = '000000', $margin = 0, $errorcorrectionlevel = 'H')
|
||||
{
|
||||
$this->endroid4 = method_exists(QrCode::class, 'create');
|
||||
|
||||
$this->bgcolor = $this->handleColor($bgcolor);
|
||||
$this->color = $this->handleColor($color);
|
||||
$this->margin = $margin;
|
||||
@@ -26,7 +36,12 @@ class EndroidQrCodeProvider implements IQRCodeProvider
|
||||
|
||||
public function getQRCodeImage($qrtext, $size)
|
||||
{
|
||||
return $this->qrCodeInstance($qrtext, $size)->writeString();
|
||||
if (!$this->endroid4) {
|
||||
return $this->qrCodeInstance($qrtext, $size)->writeString();
|
||||
}
|
||||
|
||||
$writer = new PngWriter();
|
||||
return $writer->write($this->qrCodeInstance($qrtext, $size))->getString();
|
||||
}
|
||||
|
||||
protected function qrCodeInstance($qrtext, $size)
|
||||
@@ -49,22 +64,21 @@ class EndroidQrCodeProvider implements IQRCodeProvider
|
||||
$g = hexdec($split[1]);
|
||||
$b = hexdec($split[2]);
|
||||
|
||||
return ['r' => $r, 'g' => $g, 'b' => $b, 'a' => 0];
|
||||
return $this->endroid4 ? new Color($r, $g, $b, 0) : ['r' => $r, 'g' => $g, 'b' => $b, 'a' => 0];
|
||||
}
|
||||
|
||||
private function handleErrorCorrectionLevel($level)
|
||||
{
|
||||
switch ($level) {
|
||||
case 'L':
|
||||
return ErrorCorrectionLevel::LOW();
|
||||
return $this->endroid4 ? new ErrorCorrectionLevelLow() : ErrorCorrectionLevel::LOW();
|
||||
case 'M':
|
||||
return ErrorCorrectionLevel::MEDIUM();
|
||||
return $this->endroid4 ? new ErrorCorrectionLevelMedium() : ErrorCorrectionLevel::MEDIUM();
|
||||
case 'Q':
|
||||
return ErrorCorrectionLevel::QUARTILE();
|
||||
return $this->endroid4 ? new ErrorCorrectionLevelQuartile() : ErrorCorrectionLevel::QUARTILE();
|
||||
case 'H':
|
||||
return ErrorCorrectionLevel::HIGH();
|
||||
default:
|
||||
return ErrorCorrectionLevel::HIGH();
|
||||
return $this->endroid4 ? new ErrorCorrectionLevelHigh() : ErrorCorrectionLevel::HIGH();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
namespace RobThree\Auth\Providers\Qr;
|
||||
|
||||
use Endroid\QrCode\ErrorCorrectionLevel;
|
||||
use Endroid\QrCode\QrCode;
|
||||
use Endroid\QrCode\Logo\Logo;
|
||||
use Endroid\QrCode\Writer\PngWriter;
|
||||
|
||||
class EndroidQrCodeWithLogoProvider extends EndroidQrCodeProvider
|
||||
{
|
||||
@@ -20,13 +20,33 @@ class EndroidQrCodeWithLogoProvider extends EndroidQrCodeProvider
|
||||
$this->logoSize = (array)$size;
|
||||
}
|
||||
|
||||
public function getQRCodeImage($qrtext, $size)
|
||||
{
|
||||
if (!$this->endroid4) {
|
||||
return $this->qrCodeInstance($qrtext, $size)->writeString();
|
||||
}
|
||||
|
||||
$logo = null;
|
||||
if ($this->logoPath) {
|
||||
$logo = Logo::create($this->logoPath);
|
||||
if ($this->logoSize) {
|
||||
$logo->setResizeToWidth($this->logoSize[0]);
|
||||
if (isset($this->logoSize[1])) {
|
||||
$logo->setResizeToHeight($this->logoSize[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
$writer = new PngWriter();
|
||||
return $writer->write($this->qrCodeInstance($qrtext, $size), $logo)->getString();
|
||||
}
|
||||
|
||||
protected function qrCodeInstance($qrtext, $size) {
|
||||
$qrCode = parent::qrCodeInstance($qrtext, $size);
|
||||
|
||||
if ($this->logoPath) {
|
||||
if (!$this->endroid4 && $this->logoPath) {
|
||||
$qrCode->setLogoPath($this->logoPath);
|
||||
if ($this->logoSize) {
|
||||
$qrCode->setLogoSize($this->logoSize[0], $this->logoSize[1]);
|
||||
$qrCode->setLogoSize($this->logoSize[0], isset($this->logoSize[1]) ? $this->logoSize[1] : null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace RobThree\Auth\Providers\Qr;
|
||||
|
||||
trait HandlesDataUri
|
||||
{
|
||||
/**
|
||||
* @param string $datauri
|
||||
*
|
||||
* @return null|array
|
||||
*/
|
||||
private function DecodeDataUri($datauri)
|
||||
{
|
||||
if (preg_match('/data:(?P<mimetype>[\w\.\-\+\/]+);(?P<encoding>\w+),(?P<data>.*)/', $datauri, $m) === 1) {
|
||||
return array(
|
||||
'mimetype' => $m['mimetype'],
|
||||
'encoding' => $m['encoding'],
|
||||
'data' => base64_decode($m['data'])
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -272,7 +272,7 @@ class TwoFactorAuth
|
||||
{
|
||||
return 'otpauth://totp/' . rawurlencode($label)
|
||||
. '?secret=' . rawurlencode($secret)
|
||||
. '&issuer=' . rawurlencode($this->issuer)
|
||||
. '&issuer=' . rawurlencode((string)$this->issuer)
|
||||
. '&period=' . intval($this->period)
|
||||
. '&algorithm=' . rawurlencode(strtoupper($this->algorithm))
|
||||
. '&digits=' . intval($this->digits);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
<phpunit backupGlobals="false"
|
||||
backupStaticAttributes="false"
|
||||
colors="true"
|
||||
convertDeprecationsToExceptions="true"
|
||||
convertErrorsToExceptions="true"
|
||||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
|
||||
@@ -5,26 +5,11 @@ namespace Tests\Providers\Qr;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use RobThree\Auth\TwoFactorAuth;
|
||||
use RobThree\Auth\TwoFactorAuthException;
|
||||
use RobThree\Auth\Providers\Qr\HandlesDataUri;
|
||||
|
||||
class IQRCodeProviderTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @param string $datauri
|
||||
*
|
||||
* @return null|array
|
||||
*/
|
||||
private function DecodeDataUri($datauri)
|
||||
{
|
||||
if (preg_match('/data:(?P<mimetype>[\w\.\-\/]+);(?P<encoding>\w+),(?P<data>.*)/', $datauri, $m) === 1) {
|
||||
return array(
|
||||
'mimetype' => $m['mimetype'],
|
||||
'encoding' => $m['encoding'],
|
||||
'data' => base64_decode($m['data'])
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
use HandlesDataUri;
|
||||
|
||||
/**
|
||||
* @return void
|
||||
@@ -40,6 +25,25 @@ class IQRCodeProviderTest extends TestCase
|
||||
$this->assertEquals('otpauth://totp/Test%26Label?secret=VMR466AB62ZBOKHE&issuer=Test%26Issuer&period=30&algorithm=SHA1&digits=6@200', $data['data']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testTotpUriIsCorrectNoIssuer()
|
||||
{
|
||||
$qr = new TestQrProvider();
|
||||
|
||||
/**
|
||||
* The library specifies the issuer is null by default however in PHP 8.1
|
||||
* there is a deprecation warning for passing null as a string argument to rawurlencode
|
||||
*/
|
||||
|
||||
$tfa = new TwoFactorAuth(null, 6, 30, 'sha1', $qr);
|
||||
$data = $this->DecodeDataUri($tfa->getQRCodeImageAsDataUri('Test&Label', 'VMR466AB62ZBOKHE'));
|
||||
$this->assertEquals('test/test', $data['mimetype']);
|
||||
$this->assertEquals('base64', $data['encoding']);
|
||||
$this->assertEquals('otpauth://totp/Test%26Label?secret=VMR466AB62ZBOKHE&issuer=&period=30&algorithm=SHA1&digits=6@200', $data['data']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace TestsDependency;
|
||||
|
||||
use BaconQrCode\Renderer\Image\ImagickImageBackEnd;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use RobThree\Auth\Providers\Qr\BaconQrCodeProvider;
|
||||
use RobThree\Auth\TwoFactorAuth;
|
||||
use RobThree\Auth\Providers\Qr\HandlesDataUri;
|
||||
|
||||
class BaconQRCodeTest extends TestCase
|
||||
{
|
||||
use HandlesDataUri;
|
||||
|
||||
public function testDependency()
|
||||
{
|
||||
// php < 7.1 will install an older Bacon QR Code
|
||||
if (! class_exists(ImagickImageBackEnd::class)) {
|
||||
$this->expectException(\RuntimeException::class);
|
||||
|
||||
$qr = new BaconQrCodeProvider(1, '#000', '#FFF', 'svg');
|
||||
} else {
|
||||
$qr = new BaconQrCodeProvider(1, '#000', '#FFF', 'svg');
|
||||
|
||||
$tfa = new TwoFactorAuth('Test&Issuer', 6, 30, 'sha1', $qr);
|
||||
|
||||
$data = $this->DecodeDataUri($tfa->getQRCodeImageAsDataUri('Test&Label', 'VMR466AB62ZBOKHE'));
|
||||
$this->assertEquals('image/svg+xml', $data['mimetype']);
|
||||
}
|
||||
}
|
||||
|
||||
public function testBadTextColour()
|
||||
{
|
||||
$this->expectException(\RuntimeException::class);
|
||||
|
||||
new BaconQrCodeProvider(1, 'not-a-colour', '#FFF');
|
||||
}
|
||||
|
||||
public function testBadBackgroundColour()
|
||||
{
|
||||
$this->expectException(\RuntimeException::class);
|
||||
|
||||
new BaconQrCodeProvider(1, '#000', 'not-a-colour');
|
||||
}
|
||||
|
||||
public function testBadTextColourHexRef()
|
||||
{
|
||||
$this->expectException(\RuntimeException::class);
|
||||
|
||||
new BaconQrCodeProvider(1, '#AAAA', '#FFF');
|
||||
}
|
||||
|
||||
public function testBadBackgroundColourHexRef()
|
||||
{
|
||||
$this->expectException(\RuntimeException::class);
|
||||
|
||||
new BaconQrCodeProvider(1, '#000', '#AAAA');
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace TestsDependency;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use RobThree\Auth\TwoFactorAuth;
|
||||
use RobThree\Auth\Providers\Qr\EndroidQrCodeProvider;
|
||||
use RobThree\Auth\Providers\Qr\HandlesDataUri;
|
||||
|
||||
class EndroidQRCodeTest extends TestCase
|
||||
{
|
||||
use HandlesDataUri;
|
||||
|
||||
public function testDependency()
|
||||
{
|
||||
$qr = new EndroidQrCodeProvider();
|
||||
$tfa = new TwoFactorAuth('Test&Issuer', 6, 30, 'sha1', $qr);
|
||||
$data = $this->DecodeDataUri($tfa->getQRCodeImageAsDataUri('Test&Label', 'VMR466AB62ZBOKHE'));
|
||||
$this->assertEquals('image/png', $data['mimetype']);
|
||||
$this->assertEquals('base64', $data['encoding']);
|
||||
$this->assertNotEmpty($data['data']);
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user