Просмотр исходного кода

Update composer dependencies (#2628)

* Update composer dependencies

* Update 2FA dependencies
Jaap Marcus 3 лет назад
Родитель
Сommit
2ccf56c4af
27 измененных файлов с 1089 добавлено и 387 удалено
  1. 195 194
      install/deb/filemanager/filegator/composer.lock
  2. 159 0
      web/inc/2fa/Providers/Qr/BaconQrCodeProvider.php
  3. 9 3
      web/inc/2fa/Providers/Qr/BaseHTTPQRCodeProvider.php
  4. 84 0
      web/inc/2fa/Providers/Qr/EndroidQrCodeProvider.php
  5. 55 0
      web/inc/2fa/Providers/Qr/EndroidQrCodeWithLogoProvider.php
  6. 67 0
      web/inc/2fa/Providers/Qr/GoogleChartsQrCodeProvider.php
  7. 0 39
      web/inc/2fa/Providers/Qr/GoogleQRCodeProvider.php
  8. 24 0
      web/inc/2fa/Providers/Qr/HandlesDataUri.php
  9. 16 1
      web/inc/2fa/Providers/Qr/IQRCodeProvider.php
  10. 60 0
      web/inc/2fa/Providers/Qr/ImageChartsQRCodeProvider.php
  11. 3 1
      web/inc/2fa/Providers/Qr/QRException.php
  12. 59 22
      web/inc/2fa/Providers/Qr/QRServerProvider.php
  13. 40 18
      web/inc/2fa/Providers/Qr/QRicketProvider.php
  14. 12 4
      web/inc/2fa/Providers/Rng/CSRNGProvider.php
  15. 25 10
      web/inc/2fa/Providers/Rng/HashRNGProvider.php
  16. 10 1
      web/inc/2fa/Providers/Rng/IRNGProvider.php
  17. 23 9
      web/inc/2fa/Providers/Rng/MCryptRNGProvider.php
  18. 26 11
      web/inc/2fa/Providers/Rng/OpenSSLRNGProvider.php
  19. 3 1
      web/inc/2fa/Providers/Rng/RNGException.php
  20. 30 13
      web/inc/2fa/Providers/Time/HttpTimeProvider.php
  21. 4 1
      web/inc/2fa/Providers/Time/ITimeProvider.php
  22. 5 3
      web/inc/2fa/Providers/Time/LocalMachineTimeProvider.php
  23. 30 12
      web/inc/2fa/Providers/Time/NTPTimeProvider.php
  24. 3 1
      web/inc/2fa/Providers/Time/TimeException.php
  25. 145 41
      web/inc/2fa/TwoFactorAuth.php
  26. 1 1
      web/inc/2fa/TwoFactorAuthException.php
  27. 1 1
      web/inc/composer.lock

Разница между файлами не показана из-за своего большого размера
+ 195 - 194
install/deb/filemanager/filegator/composer.lock


+ 159 - 0
web/inc/2fa/Providers/Qr/BaconQrCodeProvider.php

@@ -0,0 +1,159 @@
+<?php
+
+namespace RobThree\Auth\Providers\Qr;
+
+use BaconQrCode\Writer;
+use BaconQrCode\Renderer\ImageRenderer;
+use BaconQrCode\Renderer\RendererStyle\RendererStyle;
+use BaconQrCode\Renderer\RendererStyle\Fill;
+use BaconQrCode\Renderer\Color\Rgb;
+use BaconQrCode\Renderer\RendererStyle\EyeFill;
+
+use BaconQrCode\Renderer\Image\EpsImageBackEnd;
+use BaconQrCode\Renderer\Image\ImageBackEndInterface;
+use BaconQrCode\Renderer\Image\ImagickImageBackEnd;
+use BaconQrCode\Renderer\Image\SvgImageBackEnd;
+
+class BaconQrCodeProvider implements IQRCodeProvider
+{
+    private $borderWidth = 4; // default from Bacon QR Code
+    private $backgroundColour;
+    private $foregroundColour;
+    private $format;
+
+    /**
+     * Ensure we using the latest Bacon QR Code and specify default options
+     *
+     * @param int $borderWidth space around the QR code, 4 is the default from Bacon QR Code
+     * @param string $backgroundColour hex reference for the background colour
+     * @param string $foregroundColour hex reference for the foreground colour
+     * @param string $format the desired output, png or svg
+     */
+    public function __construct($borderWidth = 4, $backgroundColour = '#ffffff', $foregroundColour = '#000000', $format = 'png')
+    {
+        if (! class_exists(ImagickImageBackEnd::class)) {
+            throw new \RuntimeException('Make sure you are using version 2 of Bacon QR Code');
+        }
+
+        $this->borderWidth = $borderWidth;
+        $this->backgroundColour = $this->handleColour($backgroundColour);
+        $this->foregroundColour = $this->handleColour($foregroundColour);
+        $this->format = strtolower($format);
+    }
+
+    /**
+     * Standard functions from IQRCodeProvider
+     */
+
+    public function getMimeType()
+    {
+        switch ($this->format) {
+            case 'png':
+                return 'image/png';
+            case 'gif':
+                return 'image/gif';
+            case 'jpg':
+            case 'jpeg':
+                return 'image/jpeg';
+            case 'svg':
+                return 'image/svg+xml';
+            case 'eps':
+                return 'application/postscript';
+        }
+
+        throw new \RuntimeException(sprintf('Unknown MIME-type: %s', $this->format));
+    }
+
+    public function getQRCodeImage($qrText, $size)
+    {
+        switch ($this->format) {
+            case 'svg':
+                $backend = new SvgImageBackEnd;
+                break;
+            case 'eps':
+                $backend = new EpsImageBackEnd;
+                break;
+            default:
+                $backend = new ImagickImageBackEnd($this->format);
+        }
+
+        $output = $this->getQRCodeByBackend($qrText, $size, $backend);
+
+        if ($this->format == 'svg') {
+            $svg = explode("\n", $output);
+            return $svg[1];
+        }
+
+        return $output;
+    }
+
+    /**
+     * Abstract QR code generation function
+     * providing colour changing support
+     */
+    private function getQRCodeByBackend($qrText, $size, ImageBackEndInterface $backend)
+    {
+        $rendererStyleArgs = array($size, $this->borderWidth);
+
+        if (is_array($this->foregroundColour) && is_array($this->backgroundColour)) {
+            $rendererStyleArgs = array_merge($rendererStyleArgs, array(
+                null,
+                null,
+                Fill::withForegroundColor(
+                    new Rgb(...$this->backgroundColour),
+                    new Rgb(...$this->foregroundColour),
+                    new EyeFill(null, null),
+                    new EyeFill(null, null),
+                    new EyeFill(null, null)
+                )
+            ));
+        }
+
+        $writer = new Writer(new ImageRenderer(
+            new RendererStyle(...$rendererStyleArgs),
+            $backend
+        ));
+
+        return $writer->writeString($qrText);
+    }
+
+    /**
+     * Ensure colour is an array of three values but also
+     * accept a string and assume its a 3 or 6 character hex
+     */
+    private function handleColour($colour)
+    {
+        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($input, strlen($input) / 3);
+
+                // cope with three character hex reference
+                if (strlen($input) == 3) {
+                    array_walk($split, function (&$character) {
+                        $character = str_repeat($character, 2);
+                    });
+                }
+
+                // convert hex to rgb
+                return array_map('hexdec', $split);
+            };
+
+            return $hexToRGB($colour);
+        }
+
+        if (is_array($colour) && count($colour) == 3) {
+            return $colour;
+        }
+
+        throw new \RuntimeException('Invalid colour value');
+    }
+}

+ 9 - 3
web/inc/2fa/Providers/Qr/BaseHTTPQRCodeProvider.php

@@ -4,12 +4,18 @@ namespace RobThree\Auth\Providers\Qr;
 
 abstract class BaseHTTPQRCodeProvider implements IQRCodeProvider
 {
+    /** @var bool */
     protected $verifyssl;
 
+    /**
+     * @param string $url
+     *
+     * @return string|bool
+     */
     protected function getContent($url)
     {
         $curlhandle = curl_init();
-        
+
         curl_setopt_array($curlhandle, array(
             CURLOPT_URL => $url,
             CURLOPT_RETURNTRANSFER => true,
@@ -20,8 +26,8 @@ abstract class BaseHTTPQRCodeProvider implements IQRCodeProvider
             CURLOPT_USERAGENT => 'TwoFactorAuth'
         ));
         $data = curl_exec($curlhandle);
-        
+
         curl_close($curlhandle);
         return $data;
     }
-}
+}

+ 84 - 0
web/inc/2fa/Providers/Qr/EndroidQrCodeProvider.php

@@ -0,0 +1,84 @@
+<?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
+{
+    public $bgcolor;
+    public $color;
+    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;
+        $this->errorcorrectionlevel = $this->handleErrorCorrectionLevel($errorcorrectionlevel);
+    }
+
+    public function getMimeType()
+    {
+        return 'image/png';
+    }
+
+    public function getQRCodeImage($qrtext, $size)
+    {
+        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)
+    {
+        $qrCode = new QrCode($qrtext);
+        $qrCode->setSize($size);
+
+        $qrCode->setErrorCorrectionLevel($this->errorcorrectionlevel);
+        $qrCode->setMargin($this->margin);
+        $qrCode->setBackgroundColor($this->bgcolor);
+        $qrCode->setForegroundColor($this->color);
+
+        return $qrCode;
+    }
+
+    private function handleColor($color)
+    {
+        $split = str_split($color, 2);
+        $r = hexdec($split[0]);
+        $g = hexdec($split[1]);
+        $b = hexdec($split[2]);
+
+        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 $this->endroid4 ? new ErrorCorrectionLevelLow() : ErrorCorrectionLevel::LOW();
+            case 'M':
+                return $this->endroid4 ? new ErrorCorrectionLevelMedium() : ErrorCorrectionLevel::MEDIUM();
+            case 'Q':
+                return $this->endroid4 ? new ErrorCorrectionLevelQuartile() : ErrorCorrectionLevel::QUARTILE();
+            case 'H':
+            default:
+                return $this->endroid4 ? new ErrorCorrectionLevelHigh() : ErrorCorrectionLevel::HIGH();
+        }
+    }
+}

+ 55 - 0
web/inc/2fa/Providers/Qr/EndroidQrCodeWithLogoProvider.php

@@ -0,0 +1,55 @@
+<?php
+namespace RobThree\Auth\Providers\Qr;
+
+use Endroid\QrCode\Logo\Logo;
+use Endroid\QrCode\Writer\PngWriter;
+
+class EndroidQrCodeWithLogoProvider extends EndroidQrCodeProvider
+{
+    protected $logoPath;
+    protected $logoSize;
+
+    /**
+     * Adds an image to the middle of the QR Code.
+     * @param string $path Path to an image file
+     * @param array|int $size Just the width, or [width, height]
+     */
+    public function setLogo($path, $size = null)
+    {
+        $this->logoPath = $path;
+        $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->endroid4 && $this->logoPath) {
+            $qrCode->setLogoPath($this->logoPath);
+            if ($this->logoSize) {
+                $qrCode->setLogoSize($this->logoSize[0], isset($this->logoSize[1]) ? $this->logoSize[1] : null);
+            }
+        }
+
+        return $qrCode;
+    }
+}

+ 67 - 0
web/inc/2fa/Providers/Qr/GoogleChartsQrCodeProvider.php

@@ -0,0 +1,67 @@
+<?php
+
+namespace RobThree\Auth\Providers\Qr;
+
+// https://developers.google.com/chart/infographics/docs/qr_codes
+class GoogleChartsQrCodeProvider extends BaseHTTPQRCodeProvider
+{
+    /** @var string */
+    public $errorcorrectionlevel;
+
+    /** @var int */
+    public $margin;
+
+    /** @var string */
+    public $encoding;
+
+    /**
+     * @param bool $verifyssl
+     * @param string $errorcorrectionlevel
+     * @param int $margin
+     * @param string $encoding
+     */
+    public function __construct($verifyssl = false, $errorcorrectionlevel = 'L', $margin = 4, $encoding = 'UTF-8')
+    {
+        if (!is_bool($verifyssl)) { 
+            throw new QRException('VerifySSL must be bool'); 
+        }
+
+        $this->verifyssl = $verifyssl;
+
+        $this->errorcorrectionlevel = $errorcorrectionlevel;
+        $this->margin = $margin;
+        $this->encoding = $encoding;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getMimeType()
+    {
+        return 'image/png';
+    }
+    
+    /**
+     * {@inheritdoc}
+     */
+    public function getQRCodeImage($qrtext, $size)
+    {
+        return $this->getContent($this->getUrl($qrtext, $size));   
+    }
+
+    /**
+     * @param string $qrtext the value to encode in the QR code
+     * @param int|string $size the desired size of the QR code
+     *
+     * @return string file contents of the QR code
+     */
+    public function getUrl($qrtext, $size)
+    {
+        return 'https://chart.googleapis.com/chart'
+            . '?chs=' . $size . 'x' . $size
+            . '&chld=' . urlencode(strtoupper($this->errorcorrectionlevel) . '|' . $this->margin)
+            . '&cht=' . 'qr'
+            . '&choe=' . $this->encoding
+            . '&chl=' . rawurlencode($qrtext);
+    }
+}

+ 0 - 39
web/inc/2fa/Providers/Qr/GoogleQRCodeProvider.php

@@ -1,39 +0,0 @@
-<?php
-
-namespace RobThree\Auth\Providers\Qr;
-
-// https://developers.google.com/chart/infographics/docs/qr_codes
-class GoogleQRCodeProvider extends BaseHTTPQRCodeProvider 
-{
-    public $errorcorrectionlevel;
-    public $margin;
-
-    function __construct($verifyssl = false, $errorcorrectionlevel = 'L', $margin = 1) 
-    {
-        if (!is_bool($verifyssl))
-            throw new \QRException('VerifySSL must be bool');
-
-        $this->verifyssl = $verifyssl;
-        
-        $this->errorcorrectionlevel = $errorcorrectionlevel;
-        $this->margin = $margin;
-    }
-    
-    public function getMimeType() 
-    {
-        return 'image/png';
-    }
-    
-    public function getQRCodeImage($qrtext, $size) 
-    {
-        return $this->getContent($this->getUrl($qrtext, $size));
-    }
-    
-    public function getUrl($qrtext, $size) 
-    {
-        return 'https://chart.googleapis.com/chart?cht=qr'
-            . '&chs=' . $size . 'x' . $size
-            . '&chld=' . $this->errorcorrectionlevel . '|' . $this->margin
-            . '&chl=' . rawurlencode($qrtext);
-    }
-}

+ 24 - 0
web/inc/2fa/Providers/Qr/HandlesDataUri.php

@@ -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;
+    }
+}

+ 16 - 1
web/inc/2fa/Providers/Qr/IQRCodeProvider.php

@@ -4,6 +4,21 @@ namespace RobThree\Auth\Providers\Qr;
 
 interface IQRCodeProvider
 {
+    /**
+     * Generate and return the QR code to embed in a web page
+     *
+     * @param string $qrtext the value to encode in the QR code
+     * @param int $size the desired size of the QR code
+     *
+     * @return string file contents of the QR code
+     */
     public function getQRCodeImage($qrtext, $size);
+
+    /**
+     * Returns the appropriate mime type for the QR code
+     * that will be generated
+     *
+     * @return string
+     */
     public function getMimeType();
-}
+}

+ 60 - 0
web/inc/2fa/Providers/Qr/ImageChartsQRCodeProvider.php

@@ -0,0 +1,60 @@
+<?php
+
+namespace RobThree\Auth\Providers\Qr;
+
+// https://image-charts.com
+class ImageChartsQRCodeProvider extends BaseHTTPQRCodeProvider
+{
+    /** @var string */
+    public $errorcorrectionlevel;
+
+    /** @var int */
+    public $margin;
+
+    /**
+     * @param bool $verifyssl
+     * @param string $errorcorrectionlevel
+     * @param int $margin
+     */
+    public function __construct($verifyssl = false, $errorcorrectionlevel = 'L', $margin = 1)
+    {
+        if (!is_bool($verifyssl)) {
+            throw new QRException('VerifySSL must be bool');
+        }
+
+        $this->verifyssl = $verifyssl;
+
+        $this->errorcorrectionlevel = $errorcorrectionlevel;
+        $this->margin = $margin;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getMimeType()
+    {
+        return 'image/png';
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getQRCodeImage($qrtext, $size)
+    {
+        return $this->getContent($this->getUrl($qrtext, $size));
+    }
+
+    /**
+     * @param string $qrtext the value to encode in the QR code
+     * @param int $size the desired size of the QR code
+     *
+     * @return string file contents of the QR code
+     */
+    public function getUrl($qrtext, $size)
+    {
+        return 'https://image-charts.com/chart?cht=qr'
+            . '&chs=' . ceil($size / 2) . 'x' . ceil($size / 2)
+            . '&chld=' . $this->errorcorrectionlevel . '|' . $this->margin
+            . '&chl=' . rawurlencode($qrtext);
+    }
+}

+ 3 - 1
web/inc/2fa/Providers/Qr/QRException.php

@@ -1,5 +1,7 @@
 <?php
 
+namespace RobThree\Auth\Providers\Qr;
+
 use RobThree\Auth\TwoFactorAuthException;
 
-class QRException extends TwoFactorAuthException {}
+class QRException extends TwoFactorAuthException {}

+ 59 - 22
web/inc/2fa/Providers/Qr/QRServerProvider.php

@@ -3,22 +3,43 @@
 namespace RobThree\Auth\Providers\Qr;
 
 // http://goqr.me/api/doc/create-qr-code/
-class QRServerProvider extends BaseHTTPQRCodeProvider 
+class QRServerProvider extends BaseHTTPQRCodeProvider
 {
+    /** @var string */
     public $errorcorrectionlevel;
+
+    /** @var int */
     public $margin;
+
+    /** @var int */
     public $qzone;
+
+    /** @var string */
     public $bgcolor;
+
+    /** @var string */
     public $color;
+
+    /** @var string */
     public $format;
 
-    function __construct($verifyssl = false, $errorcorrectionlevel = 'L', $margin = 4, $qzone = 1, $bgcolor = 'ffffff', $color = '000000', $format = 'png') 
+    /**
+     * @param bool $verifyssl
+     * @param string $errorcorrectionlevel
+     * @param int $margin
+     * @param int $qzone
+     * @param string $bgcolor
+     * @param string $color
+     * @param string $format
+     */
+    public function __construct($verifyssl = false, $errorcorrectionlevel = 'L', $margin = 4, $qzone = 1, $bgcolor = 'ffffff', $color = '000000', $format = 'png')
     {
-        if (!is_bool($verifyssl))
+        if (!is_bool($verifyssl)) {
             throw new QRException('VerifySSL must be bool');
+        }
 
         $this->verifyssl = $verifyssl;
-        
+
         $this->errorcorrectionlevel = $errorcorrectionlevel;
         $this->margin = $margin;
         $this->qzone = $qzone;
@@ -26,37 +47,53 @@ class QRServerProvider extends BaseHTTPQRCodeProvider
         $this->color = $color;
         $this->format = $format;
     }
-    
-    public function getMimeType() 
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getMimeType()
     {
-        switch (strtolower($this->format))
-        {
-        	case 'png':
+        switch (strtolower($this->format)) {
+            case 'png':
                 return 'image/png';
-        	case 'gif':
+            case 'gif':
                 return 'image/gif';
-        	case 'jpg':
-        	case 'jpeg':
+            case 'jpg':
+            case 'jpeg':
                 return 'image/jpeg';
-        	case 'svg':
+            case 'svg':
                 return 'image/svg+xml';
-        	case 'eps':
+            case 'eps':
                 return 'application/postscript';
         }
-        throw new \QRException(sprintf('Unknown MIME-type: %s', $this->format));
+        throw new QRException(sprintf('Unknown MIME-type: %s', $this->format));
     }
-    
-    public function getQRCodeImage($qrtext, $size) 
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getQRCodeImage($qrtext, $size)
     {
         return $this->getContent($this->getUrl($qrtext, $size));
     }
-    
-    private function decodeColor($value) 
+
+    /**
+     * @param string $value
+     *
+     * @return string
+     */
+    private function decodeColor($value)
     {
         return vsprintf('%d-%d-%d', sscanf($value, "%02x%02x%02x"));
     }
-    
-    public function getUrl($qrtext, $size) 
+
+    /**
+     * @param string $qrtext the value to encode in the QR code
+     * @param int|string $size the desired size of the QR code
+     *
+     * @return string file contents of the QR code
+     */
+    public function getUrl($qrtext, $size)
     {
         return 'https://api.qrserver.com/v1/create-qr-code/'
             . '?size=' . $size . 'x' . $size
@@ -68,4 +105,4 @@ class QRServerProvider extends BaseHTTPQRCodeProvider
             . '&format=' . strtolower($this->format)
             . '&data=' . rawurlencode($qrtext);
     }
-}
+}

+ 40 - 18
web/inc/2fa/Providers/Qr/QRicketProvider.php

@@ -3,45 +3,67 @@
 namespace RobThree\Auth\Providers\Qr;
 
 // http://qrickit.com/qrickit_apps/qrickit_api.php
-class QRicketProvider extends BaseHTTPQRCodeProvider 
+class QRicketProvider extends BaseHTTPQRCodeProvider
 {
+    /** @var string */
     public $errorcorrectionlevel;
-    public $margin;
-    public $qzone;
+
+    /** @var string */
     public $bgcolor;
+
+    /** @var string */
     public $color;
+
+    /** @var string */
     public $format;
 
-    function __construct($errorcorrectionlevel = 'L', $bgcolor = 'ffffff', $color = '000000', $format = 'p') 
+    /**
+     * @param string $errorcorrectionlevel
+     * @param string $bgcolor
+     * @param string $color
+     * @param string $format
+     */
+    public function __construct($errorcorrectionlevel = 'L', $bgcolor = 'ffffff', $color = '000000', $format = 'p')
     {
         $this->verifyssl = false;
-        
+
         $this->errorcorrectionlevel = $errorcorrectionlevel;
         $this->bgcolor = $bgcolor;
         $this->color = $color;
         $this->format = $format;
     }
-    
-    public function getMimeType() 
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getMimeType()
     {
-        switch (strtolower($this->format))
-        {
-        	case 'p':
+        switch (strtolower($this->format)) {
+            case 'p':
                 return 'image/png';
-        	case 'g':
+            case 'g':
                 return 'image/gif';
-        	case 'j':
+            case 'j':
                 return 'image/jpeg';
         }
-        throw new \QRException(sprintf('Unknown MIME-type: %s', $this->format));
+        throw new QRException(sprintf('Unknown MIME-type: %s', $this->format));
     }
-    
-    public function getQRCodeImage($qrtext, $size) 
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getQRCodeImage($qrtext, $size)
     {
         return $this->getContent($this->getUrl($qrtext, $size));
     }
-    
-    public function getUrl($qrtext, $size) 
+
+    /**
+     * @param string $qrtext the value to encode in the QR code
+     * @param int|string $size the desired size of the QR code
+     *
+     * @return string file contents of the QR code
+     */
+    public function getUrl($qrtext, $size)
     {
         return 'http://qrickit.com/api/qr'
             . '?qrsize=' . $size
@@ -51,4 +73,4 @@ class QRicketProvider extends BaseHTTPQRCodeProvider
             . '&t=' . strtolower($this->format)
             . '&d=' . rawurlencode($qrtext);
     }
-}
+}

+ 12 - 4
web/inc/2fa/Providers/Rng/CSRNGProvider.php

@@ -4,11 +4,19 @@ namespace RobThree\Auth\Providers\Rng;
 
 class CSRNGProvider implements IRNGProvider
 {
-    public function getRandomBytes($bytecount) {
+    /**
+     * {@inheritdoc}
+     */
+    public function getRandomBytes($bytecount)
+    {
         return random_bytes($bytecount);    // PHP7+
     }
-    
-    public function isCryptographicallySecure() {
+
+    /**
+     * {@inheritdoc}
+     */
+    public function isCryptographicallySecure()
+    {
         return true;
     }
-}
+}

+ 25 - 10
web/inc/2fa/Providers/Rng/HashRNGProvider.php

@@ -1,28 +1,43 @@
 <?php
+
 namespace RobThree\Auth\Providers\Rng;
 
 class HashRNGProvider implements IRNGProvider
 {
+    /** @var string */
     private $algorithm;
-    
-    function __construct($algorithm = 'sha256' ) {
+
+    /**
+     * @param string $algorithm
+     */
+    public function __construct($algorithm = 'sha256')
+    {
         $algos = array_values(hash_algos());
-        if (!in_array($algorithm, $algos, true))
-            throw new \RNGException('Unsupported algorithm specified');
+        if (!in_array($algorithm, $algos, true)) {
+            throw new RNGException('Unsupported algorithm specified');
+        }
         $this->algorithm = $algorithm;
     }
-    
-    public function getRandomBytes($bytecount) {
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getRandomBytes($bytecount)
+    {
         $result = '';
         $hash = mt_rand();
         for ($i = 0; $i < $bytecount; $i++) {
-            $hash = hash($this->algorithm, $hash.mt_rand(), true);
-            $result .= $hash[mt_rand(0, strlen($hash)-1)];
+            $hash = hash($this->algorithm, $hash . mt_rand(), true);
+            $result .= $hash[mt_rand(0, strlen($hash) - 1)];
         }
         return $result;
     }
-    
-    public function isCryptographicallySecure() {
+
+    /**
+     * {@inheritdoc}
+     */
+    public function isCryptographicallySecure()
+    {
         return false;
     }
 }

+ 10 - 1
web/inc/2fa/Providers/Rng/IRNGProvider.php

@@ -4,6 +4,15 @@ namespace RobThree\Auth\Providers\Rng;
 
 interface IRNGProvider
 {
+    /**
+     * @param int $bytecount the number of bytes of randomness to return
+     *
+     * @return string the random bytes
+     */
     public function getRandomBytes($bytecount);
+
+    /**
+     * @return bool whether this provider is cryptographically secure
+     */
     public function isCryptographicallySecure();
-}
+}

+ 23 - 9
web/inc/2fa/Providers/Rng/MCryptRNGProvider.php

@@ -4,20 +4,34 @@ namespace RobThree\Auth\Providers\Rng;
 
 class MCryptRNGProvider implements IRNGProvider
 {
+    /** @var int */
     private $source;
-    
-    function __construct($source = MCRYPT_DEV_URANDOM) {
+
+    /**
+     * @param int $source
+     */
+    public function __construct($source = MCRYPT_DEV_URANDOM)
+    {
         $this->source = $source;
     }
-    
-    public function getRandomBytes($bytecount) {
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getRandomBytes($bytecount)
+    {
         $result = @mcrypt_create_iv($bytecount, $this->source);
-        if ($result === false)
-            throw new \RNGException('mcrypt_create_iv returned an invalid value');
+        if ($result === false) {
+            throw new RNGException('mcrypt_create_iv returned an invalid value');
+        }
         return $result;
     }
-    
-    public function isCryptographicallySecure() {
+
+    /**
+     * {@inheritdoc}
+     */
+    public function isCryptographicallySecure()
+    {
         return true;
     }
-}
+}

+ 26 - 11
web/inc/2fa/Providers/Rng/OpenSSLRNGProvider.php

@@ -4,22 +4,37 @@ namespace RobThree\Auth\Providers\Rng;
 
 class OpenSSLRNGProvider implements IRNGProvider
 {
+    /** @var bool */
     private $requirestrong;
-    
-    function __construct($requirestrong = true) {
+
+    /**
+     * @param bool $requirestrong
+     */
+    public function __construct($requirestrong = true)
+    {
         $this->requirestrong = $requirestrong;
     }
-    
-    public function getRandomBytes($bytecount) {
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getRandomBytes($bytecount)
+    {
         $result = openssl_random_pseudo_bytes($bytecount, $crypto_strong);
-        if ($this->requirestrong && ($crypto_strong === false))
-            throw new \RNGException('openssl_random_pseudo_bytes returned non-cryptographically strong value');
-        if ($result === false)
-            throw new \RNGException('openssl_random_pseudo_bytes returned an invalid value');
+        if ($this->requirestrong && ($crypto_strong === false)) {
+            throw new RNGException('openssl_random_pseudo_bytes returned non-cryptographically strong value');
+        }
+        if ($result === false) {
+            throw new RNGException('openssl_random_pseudo_bytes returned an invalid value');
+        }
         return $result;
     }
-    
-    public function isCryptographicallySecure() {
+
+    /**
+     * {@inheritdoc}
+     */
+    public function isCryptographicallySecure()
+    {
         return $this->requirestrong;
     }
-}
+}

+ 3 - 1
web/inc/2fa/Providers/Rng/RNGException.php

@@ -1,5 +1,7 @@
 <?php
 
+namespace RobThree\Auth\Providers\Rng;
+
 use RobThree\Auth\TwoFactorAuthException;
 
-class RNGException extends TwoFactorAuthException {}
+class RNGException extends TwoFactorAuthException {}

+ 30 - 13
web/inc/2fa/Providers/Time/HttpTimeProvider.php

@@ -2,22 +2,33 @@
 
 namespace RobThree\Auth\Providers\Time;
 
+use DateTime;
+
 /**
  * Takes the time from any webserver by doing a HEAD request on the specified URL and extracting the 'Date:' header
  */
 class HttpTimeProvider implements ITimeProvider
 {
+    /** @var string */
     public $url;
-    public $options;
+
+    /** @var string */
     public $expectedtimeformat;
 
-    function __construct($url = 'https://google.com', $expectedtimeformat = 'D, d M Y H:i:s O+', array $options = null)
+    /** @var array */
+    public $options;
+
+    /**
+     * @param string $url
+     * @param string $expectedtimeformat
+     * @param array $options
+     */
+    public function __construct($url = 'https://google.com', $expectedtimeformat = 'D, d M Y H:i:s O+', array $options = null)
     {
         $this->url = $url;
         $this->expectedtimeformat = $expectedtimeformat;
-        $this->options = $options;
-        if ($this->options === null) {
-            $this->options = array(
+        if ($options === null) {
+            $options = array(
                 'http' => array(
                     'method' => 'HEAD',
                     'follow_location' => false,
@@ -32,9 +43,14 @@ class HttpTimeProvider implements ITimeProvider
                 )
             );
         }
+        $this->options = $options;
     }
 
-    public function getTime() {
+    /**
+     * {@inheritdoc}
+     */
+    public function getTime()
+    {
         try {
             $context  = stream_context_create($this->options);
             $fd = fopen($this->url, 'rb', false, $context);
@@ -42,13 +58,14 @@ class HttpTimeProvider implements ITimeProvider
             fclose($fd);
 
             foreach ($headers['wrapper_data'] as $h) {
-                if (strcasecmp(substr($h, 0, 5), 'Date:') === 0)
-                    return \DateTime::createFromFormat($this->expectedtimeformat, trim(substr($h,5)))->getTimestamp();
+                if (strcasecmp(substr($h, 0, 5), 'Date:') === 0) {
+                    return DateTime::createFromFormat($this->expectedtimeformat, trim(substr($h, 5)))->getTimestamp();
+                }
             }
-            throw new \TimeException(sprintf('Unable to retrieve time from %s (Invalid or no "Date:" header found)', $this->url));
-        }
-        catch (Exception $ex) {
-            throw new \TimeException(sprintf('Unable to retrieve time from %s (%s)', $this->url, $ex->getMessage()));
+            throw new \Exception('Invalid or no "Date:" header found');
+        } catch (\Exception $ex) {
+            throw new TimeException(sprintf('Unable to retrieve time from %s (%s)', $this->url, $ex->getMessage()));
         }
+
     }
-}
+}

+ 4 - 1
web/inc/2fa/Providers/Time/ITimeProvider.php

@@ -4,5 +4,8 @@ namespace RobThree\Auth\Providers\Time;
 
 interface ITimeProvider
 {
+    /**
+     * @return int the current timestamp according to this provider
+     */
     public function getTime();
-}
+}

+ 5 - 3
web/inc/2fa/Providers/Time/LocalMachineTimeProvider.php

@@ -2,8 +2,10 @@
 
 namespace RobThree\Auth\Providers\Time;
 
-class LocalMachineTimeProvider implements ITimeProvider {
-    public function getTime() {
+class LocalMachineTimeProvider implements ITimeProvider
+{
+    public function getTime()
+    {
         return time();
     }
-}
+}

+ 30 - 12
web/inc/2fa/Providers/Time/NTPTimeProvider.php

@@ -7,27 +7,44 @@ namespace RobThree\Auth\Providers\Time;
  */
 class NTPTimeProvider implements ITimeProvider
 {
+    /** @var string */
     public $host;
+
+    /** @var int */
     public $port;
+
+    /** @var int */
     public $timeout;
 
-    function __construct($host = 'pool.ntp.org', $port = 123, $timeout = 1)
+    /**
+     * @param string $host
+     * @param int $port
+     * @param int $timeout
+     */
+    public function __construct($host = 'time.google.com', $port = 123, $timeout = 1)
     {
         $this->host = $host;
 
-        if (!is_int($port) || $port <= 0 || $port > 65535)
-            throw new \TimeException('Port must be 0 < port < 65535');
+        if (!is_int($port) || $port <= 0 || $port > 65535) {
+            throw new TimeException('Port must be 0 < port < 65535');
+        }
         $this->port = $port;
 
-        if (!is_int($timeout) || $timeout < 0)
-            throw new \TimeException('Timeout must be >= 0');
+        if (!is_int($timeout) || $timeout < 0) {
+            throw new TimeException('Timeout must be >= 0');
+        }
         $this->timeout = $timeout;
     }
 
-    public function getTime() {
+    /**
+     * {@inheritdoc}
+     */
+    public function getTime()
+    {
         try {
             /* Create a socket and connect to NTP server */
             $sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
+            socket_set_option($sock, SOL_SOCKET, SO_RCVTIMEO, ['sec' => $this->timeout, 'usec' => 0]);
             socket_connect($sock, $this->host, $this->port);
 
             /* Send request */
@@ -35,18 +52,19 @@ class NTPTimeProvider implements ITimeProvider
             socket_send($sock, $msg, strlen($msg), 0);
 
             /* Receive response and close socket */
-            socket_recv($sock, $recv, 48, MSG_WAITALL);
+            if (socket_recv($sock, $recv, 48, MSG_WAITALL) === false) {
+                throw new \Exception(socket_strerror(socket_last_error($sock)));
+            }
             socket_close($sock);
 
             /* Interpret response */
             $data = unpack('N12', $recv);
-            $timestamp = sprintf('%u', $data[9]);
+            $timestamp = (int) sprintf('%u', $data[9]);
 
             /* NTP is number of seconds since 0000 UT on 1 January 1900 Unix time is seconds since 0000 UT on 1 January 1970 */
             return $timestamp - 2208988800;
-        }
-        catch (Exception $ex) {
-            throw new \TimeException(sprintf('Unable to retrieve time from %s (%s)', $this->host, $ex->getMessage()));
+        } catch (\Exception $ex) {
+            throw new TimeException(sprintf('Unable to retrieve time from %s (%s)', $this->host, $ex->getMessage()));
         }
     }
-}
+}

+ 3 - 1
web/inc/2fa/Providers/Time/TimeException.php

@@ -1,5 +1,7 @@
 <?php
 
+namespace RobThree\Auth\Providers\Time;
+
 use RobThree\Auth\TwoFactorAuthException;
 
-class TimeException extends TwoFactorAuthException {}
+class TimeException extends TwoFactorAuthException {}

+ 145 - 41
web/inc/2fa/TwoFactorAuth.php

@@ -1,40 +1,82 @@
 <?php
+
 namespace RobThree\Auth;
 
 use RobThree\Auth\Providers\Qr\IQRCodeProvider;
+use RobThree\Auth\Providers\Qr\QRServerProvider;
+use RobThree\Auth\Providers\Rng\CSRNGProvider;
+use RobThree\Auth\Providers\Rng\HashRNGProvider;
 use RobThree\Auth\Providers\Rng\IRNGProvider;
+use RobThree\Auth\Providers\Rng\MCryptRNGProvider;
+use RobThree\Auth\Providers\Rng\OpenSSLRNGProvider;
+use RobThree\Auth\Providers\Time\HttpTimeProvider;
 use RobThree\Auth\Providers\Time\ITimeProvider;
+use RobThree\Auth\Providers\Time\LocalMachineTimeProvider;
+use RobThree\Auth\Providers\Time\NTPTimeProvider;
 
 // Based on / inspired by: https://github.com/PHPGangsta/GoogleAuthenticator
 // Algorithms, digits, period etc. explained: https://github.com/google/google-authenticator/wiki/Key-Uri-Format
 class TwoFactorAuth
 {
+    /** @var string */
     private $algorithm;
+
+    /** @var int */
     private $period;
+
+    /** @var int */
     private $digits;
+
+    /** @var string */
     private $issuer;
+
+    /** @var ?IQRCodeProvider */
     private $qrcodeprovider = null;
+
+    /** @var ?IRNGProvider */
     private $rngprovider = null;
+
+    /** @var ?ITimeProvider */
     private $timeprovider = null;
+
+    /** @var string */
     private static $_base32dict = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=';
+
+    /** @var array */
     private static $_base32;
+
+    /** @var array */
     private static $_base32lookup = array();
+
+    /** @var array */
     private static $_supportedalgos = array('sha1', 'sha256', 'sha512', 'md5');
 
-    function __construct($issuer = null, $digits = 6, $period = 30, $algorithm = 'sha1', IQRCodeProvider $qrcodeprovider = null, IRNGProvider $rngprovider = null, ITimeProvider $timeprovider = null)
+    /**
+     * @param ?string $issuer
+     * @param int $digits
+     * @param int $period
+     * @param string $algorithm
+     * @param ?IQRCodeProvider $qrcodeprovider
+     * @param ?IRNGProvider $rngprovider
+     * @param ?ITimeProvider $timeprovider
+     */
+    public function __construct($issuer = null, $digits = 6, $period = 30, $algorithm = 'sha1', IQRCodeProvider $qrcodeprovider = null, IRNGProvider $rngprovider = null, ITimeProvider $timeprovider = null)
     {
         $this->issuer = $issuer;
-        if (!is_int($digits) || $digits <= 0)
+        if (!is_int($digits) || $digits <= 0) {
             throw new TwoFactorAuthException('Digits must be int > 0');
+        }
         $this->digits = $digits;
 
-        if (!is_int($period) || $period <= 0)
+        if (!is_int($period) || $period <= 0) {
             throw new TwoFactorAuthException('Period must be int > 0');
+        }
         $this->period = $period;
 
         $algorithm = strtolower(trim($algorithm));
-        if (!in_array($algorithm, self::$_supportedalgos))
+        if (!in_array($algorithm, self::$_supportedalgos)) {
             throw new TwoFactorAuthException('Unsupported algorithm: ' . $algorithm);
+        }
         $this->algorithm = $algorithm;
         $this->qrcodeprovider = $qrcodeprovider;
         $this->rngprovider = $rngprovider;
@@ -46,22 +88,34 @@ class TwoFactorAuth
 
     /**
      * Create a new secret
+     *
+     * @param int $bits
+     * @param bool $requirecryptosecure
+     *
+     * @return string
      */
     public function createSecret($bits = 80, $requirecryptosecure = true)
     {
         $secret = '';
-        $bytes = ceil($bits / 5);   //We use 5 bits of each byte (since we have a 32-character 'alphabet' / BASE32)
-        $rngprovider = $this->getRngprovider();
-        if ($requirecryptosecure && !$rngprovider->isCryptographicallySecure())
+        $bytes = (int) ceil($bits / 5);   //We use 5 bits of each byte (since we have a 32-character 'alphabet' / BASE32)
+        $rngprovider = $this->getRngProvider();
+        if ($requirecryptosecure && !$rngprovider->isCryptographicallySecure()) {
             throw new TwoFactorAuthException('RNG provider is not cryptographically secure');
+        }
         $rnd = $rngprovider->getRandomBytes($bytes);
-        for ($i = 0; $i < $bytes; $i++)
+        for ($i = 0; $i < $bytes; $i++) {
             $secret .= self::$_base32[ord($rnd[$i]) & 31];  //Mask out left 3 bits for 0-31 values
+        }
         return $secret;
     }
 
     /**
      * Calculate the code with given secret and point in time
+     *
+     * @param string $secret
+     * @param ?int $time
+     *
+     * @return string
      */
     public function getCode($secret, $time = null)
     {
@@ -73,15 +127,23 @@ class TwoFactorAuth
         $value = unpack('N', $hashpart);                                                   // Unpack binary value
         $value = $value[1] & 0x7FFFFFFF;                                                   // Drop MSB, keep only 31 bits
 
-        return str_pad($value % pow(10, $this->digits), $this->digits, '0', STR_PAD_LEFT);
+        return str_pad((string) ($value % pow(10, $this->digits)), $this->digits, '0', STR_PAD_LEFT);
     }
 
     /**
      * Check if the code is correct. This will accept codes starting from ($discrepancy * $period) sec ago to ($discrepancy * period) sec from now
+     *
+     * @param string $secret
+     * @param string $code
+     * @param int $discrepancy
+     * @param ?int $time
+     * @param int $timeslice
+     *
+     * @return bool
      */
     public function verifyCode($secret, $code, $discrepancy = 1, $time = null, &$timeslice = 0)
     {
-        $timetamp = $this->getTime($time);
+        $timestamp = $this->getTime($time);
 
         $timeslice = 0;
 
@@ -90,7 +152,7 @@ class TwoFactorAuth
         // of the match. Each iteration we either set the timeslice variable to the timeslice of the match
         // or set the value to itself.  This is an effort to maintain constant execution time for the code.
         for ($i = -$discrepancy; $i <= $discrepancy; $i++) {
-            $ts = $timetamp + ($i * $this->period);
+            $ts = $timestamp + ($i * $this->period);
             $slice = $this->getTimeSlice($ts);
             $timeslice = $this->codeEquals($this->getCode($secret, $ts), $code) ? $slice : $timeslice;
         }
@@ -100,17 +162,24 @@ class TwoFactorAuth
 
     /**
      * Timing-attack safe comparison of 2 codes (see http://blog.ircmaxell.com/2014/11/its-all-about-time.html)
+     *
+     * @param string $safe
+     * @param string $user
+     *
+     * @return bool
      */
-    private function codeEquals($safe, $user) {
+    private function codeEquals($safe, $user)
+    {
         if (function_exists('hash_equals')) {
             return hash_equals($safe, $user);
         }
         // In general, it's not possible to prevent length leaks. So it's OK to leak the length. The important part is that
         // we don't leak information about the difference of the two strings.
-        if (strlen($safe)===strlen($user)) {
+        if (strlen($safe) === strlen($user)) {
             $result = 0;
-            for ($i = 0; $i < strlen($safe); $i++)
+            for ($i = 0; $i < strlen($safe); $i++) {
                 $result |= (ord($safe[$i]) ^ ord($user[$i]));
+            }
             return $result === 0;
         }
         return false;
@@ -118,11 +187,18 @@ class TwoFactorAuth
 
     /**
      * Get data-uri of QRCode
+     *
+     * @param string $label
+     * @param string $secret
+     * @param mixed $size
+     *
+     * @return string
      */
     public function getQRCodeImageAsDataUri($label, $secret, $size = 200)
     {
-        if (!is_int($size) || $size <= 0)
+        if (!is_int($size) || $size <= 0) {
             throw new TwoFactorAuthException('Size must be int > 0');
+        }
 
         $qrcodeprovider = $this->getQrCodeProvider();
         return 'data:'
@@ -133,37 +209,52 @@ class TwoFactorAuth
 
     /**
      * Compare default timeprovider with specified timeproviders and ensure the time is within the specified number of seconds (leniency)
+     * @param ?array $timeproviders
+     * @param int $leniency
+     *
+     * @return void
      */
     public function ensureCorrectTime(array $timeproviders = null, $leniency = 5)
     {
-        if ($timeproviders != null && !is_array($timeproviders))
-            throw new TwoFactorAuthException('No timeproviders specified');
-
-        if ($timeproviders == null)
+        if ($timeproviders === null) {
             $timeproviders = array(
-                new Providers\Time\NTPTimeProvider(),
-                new Providers\Time\HttpTimeProvider()
+                new NTPTimeProvider(),
+                new HttpTimeProvider()
             );
+        }
 
         // Get default time provider
         $timeprovider = $this->getTimeProvider();
 
         // Iterate specified time providers
         foreach ($timeproviders as $t) {
-            if (!($t instanceof ITimeProvider))
+            if (!($t instanceof ITimeProvider)) {
                 throw new TwoFactorAuthException('Object does not implement ITimeProvider');
+            }
 
             // Get time from default time provider and compare to specific time provider and throw if time difference is more than specified number of seconds leniency
-            if (abs($timeprovider->getTime() - $t->getTime()) > $leniency)
+            if (abs($timeprovider->getTime() - $t->getTime()) > $leniency) {
                 throw new TwoFactorAuthException(sprintf('Time for timeprovider is off by more than %d seconds when compared to %s', $leniency, get_class($t)));
+            }
         }
     }
 
-    private function getTime($time)
+    /**
+     * @param ?int $time
+     *
+     * @return int
+     */
+    private function getTime($time = null)
     {
         return ($time === null) ? $this->getTimeProvider()->getTime() : $time;
     }
 
+    /**
+     * @param int $time
+     * @param int $offset
+     *
+     * @return int
+     */
     private function getTimeSlice($time = null, $offset = 0)
     {
         return (int)floor($time / $this->period) + ($offset * $this->period);
@@ -171,36 +262,49 @@ class TwoFactorAuth
 
     /**
      * Builds a string to be encoded in a QR code
+     *
+     * @param string $label
+     * @param string $secret
+     *
+     * @return string
      */
     public function getQRText($label, $secret)
     {
         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);
     }
 
+    /**
+     * @param string $value
+     * @return string
+     */
     private function base32Decode($value)
     {
-        if (strlen($value)==0) return '';
+        if (strlen($value) == 0) {
+            return '';
+        }
 
-        if (preg_match('/[^'.preg_quote(self::$_base32dict).']/', $value) !== 0)
+        if (preg_match('/[^' . preg_quote(self::$_base32dict) . ']/', $value) !== 0) {
             throw new TwoFactorAuthException('Invalid base32 string');
+        }
 
         $buffer = '';
-        foreach (str_split($value) as $char)
-        {
-            if ($char !== '=')
-                $buffer .= str_pad(decbin(self::$_base32lookup[$char]), 5, 0, STR_PAD_LEFT);
+        foreach (str_split($value) as $char) {
+            if ($char !== '=') {
+                $buffer .= str_pad(decbin(self::$_base32lookup[$char]), 5, '0', STR_PAD_LEFT);
+            }
         }
         $length = strlen($buffer);
         $blocks = trim(chunk_split(substr($buffer, 0, $length - ($length % 8)), 8, ' '));
 
         $output = '';
-        foreach (explode(' ', $blocks) as $block)
-            $output .= chr(bindec(str_pad($block, 8, 0, STR_PAD_RIGHT)));
+        foreach (explode(' ', $blocks) as $block) {
+            $output .= chr(bindec(str_pad($block, 8, '0', STR_PAD_RIGHT)));
+        }
         return $output;
     }
 
@@ -212,7 +316,7 @@ class TwoFactorAuth
     {
         // Set default QR Code provider if none was specified
         if (null === $this->qrcodeprovider) {
-            return $this->qrcodeprovider = new Providers\Qr\GoogleQRCodeProvider();
+            return $this->qrcodeprovider = new QRServerProvider();
         }
         return $this->qrcodeprovider;
     }
@@ -221,22 +325,22 @@ class TwoFactorAuth
      * @return IRNGProvider
      * @throws TwoFactorAuthException
      */
-    public function getRngprovider()
+    public function getRngProvider()
     {
         if (null !== $this->rngprovider) {
             return $this->rngprovider;
         }
         if (function_exists('random_bytes')) {
-            return $this->rngprovider = new Providers\Rng\CSRNGProvider();
+            return $this->rngprovider = new CSRNGProvider();
         }
         if (function_exists('mcrypt_create_iv')) {
-            return $this->rngprovider = new Providers\Rng\MCryptRNGProvider();
+            return $this->rngprovider = new MCryptRNGProvider();
         }
         if (function_exists('openssl_random_pseudo_bytes')) {
-            return $this->rngprovider = new Providers\Rng\OpenSSLRNGProvider();
+            return $this->rngprovider = new OpenSSLRNGProvider();
         }
         if (function_exists('hash')) {
-            return $this->rngprovider = new Providers\Rng\HashRNGProvider();
+            return $this->rngprovider = new HashRNGProvider();
         }
         throw new TwoFactorAuthException('Unable to find a suited RNGProvider');
     }
@@ -249,8 +353,8 @@ class TwoFactorAuth
     {
         // Set default time provider if none was specified
         if (null === $this->timeprovider) {
-            return $this->timeprovider = new Providers\Time\LocalMachineTimeProvider();
+            return $this->timeprovider = new LocalMachineTimeProvider();
         }
         return $this->timeprovider;
     }
-}
+}

+ 1 - 1
web/inc/2fa/TwoFactorAuthException.php

@@ -4,4 +4,4 @@ namespace RobThree\Auth;
 
 use Exception;
 
-class TwoFactorAuthException extends \Exception {}
+class TwoFactorAuthException extends Exception {}

+ 1 - 1
web/inc/composer.lock

@@ -93,5 +93,5 @@
     "prefer-lowest": false,
     "platform": [],
     "platform-dev": [],
-    "plugin-api-version": "2.2.0"
+    "plugin-api-version": "2.1.0"
 }

Некоторые файлы не были показаны из-за большого количества измененных файлов