Server IP : 213.176.29.180  /  Your IP : 13.58.211.135
Web Server : Apache
System : Linux 213.176.29.180.hostiran.name 4.18.0-553.22.1.el8_10.x86_64 #1 SMP Tue Sep 24 05:16:59 EDT 2024 x86_64
User : webtaragh ( 1001)
PHP Version : 7.4.33
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : ON
Directory (0750) :  /home/webtaragh/public_html/whmcs/assets/../../../public_html/

[  Home  ][  C0mmand  ][  Upload File  ]

Current File : /home/webtaragh/public_html/whmcs/assets/../../../public_html/sonata-project.tar
google-authenticator/sample/tmpl/login.php000064400000000273147361034100014747 0ustar00
<h1>please login</h1>
<p>
<form method="post" action="./">
username: <input name="username"/><br/>
password: <input name="password" type="password"/><br/>
<input type="submit"/>
</form>
google-authenticator/sample/tmpl/show-qr.php000064400000000611147361034100015233 0ustar00<h1>Please scan this </h1>

<p> with <a href="http://www.google.com/support/a/bin/answer.py?hl=en&answer=1037451">the Google Authenticator App</a></p>

<p>
<?php
$link = \Sonata\GoogleAuthenticator\GoogleQrUrl::generate($user->getUsername(), $secret, 'GoogleAuthenticatorExample');
?>

<a  href="<?php echo $link; ?>"><img style="border: 0; padding:10px" src="<?php echo $link; ?>"/></a>
</p>
google-authenticator/sample/tmpl/login-error.php000064400000000122147361034100016067 0ustar00<p>
Wrong username or password or token.
</p>
<p>
<a href="./">try again</a>
</p>
google-authenticator/sample/tmpl/loggedin.php000064400000000304147361034100015422 0ustar00
<p>
Hello <?php echo $user->getUsername(); ?>
</p>
<?php
if (!isset($_GET['showqr'])) {
    ?>

<p>
<a href="?showqr=1">Show QR Code</a>
</p>

<?php
}
?>

<p>
<a href="?logout=1">Logout</a>
</p>
google-authenticator/sample/tmpl/ask-for-otp.php000064400000001053147361034100015776 0ustar00
<h1>please otp</h1>
<p>
<form method="post" action="./">
<?php if ($debug) {
    ?>
    <br/>
    (Set $debug in index.php to false, if you don't want to have the OTP prefilled (for real life application, for example ;))<br/>
<?php
}
?>

otp: <input name="otp"
value="<?php
if ($debug) {
    $g = new GoogleAuthenticator();
    echo $g->getCode($user->getSecret());
}
?>"/><br/>
<input type="checkbox" name="remember" id="remember" /><label for="remember"> Remember verification for this computer for 1 day.</label> <br/>
<input type="submit"/>

</form>
google-authenticator/sample/example.php000064400000001756147361034100014325 0ustar00<?php

declare(strict_types=1);

/*
 * This file is part of the Sonata Project package.
 *
 * (c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

include_once __DIR__.'/../src/FixedBitNotation.php';
include_once __DIR__.'/../src/GoogleAuthenticator.php';
include_once __DIR__.'/../src/GoogleQrUrl.php';

$secret = 'XVQ2UIGO75XRUKJO';
$code = '846474';

$g = new \Sonata\GoogleAuthenticator\GoogleAuthenticator();

echo 'Current Code is: ';
echo $g->getCode($secret);

echo "\n";

echo "Check if $code is valid: ";

if ($g->checkCode($secret, $code)) {
    echo "YES \n";
} else {
    echo "NO \n";
}

$secret = $g->generateSecret();
echo "Get a new Secret: $secret \n";
echo "The QR Code for this secret (to scan with the Google Authenticator App: \n";

echo \Sonata\GoogleAuthenticator\GoogleQrUrl::generate('chregu', $secret, 'GoogleAuthenticatorExample');
echo "\n";
google-authenticator/sample/web/Users.php000064400000007344147361034100014547 0ustar00<?php

declare(strict_types=1);

/*
 * This file is part of the Sonata Project package.
 *
 * (c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

class Users
{
    public function __construct(string $file = '../users.dat')
    {
        $this->userFile = $file;

        $this->users = json_decode(file_get_contents($file), true);
    }

    public function hasSession()
    {
        session_start();
        if (isset($_SESSION['username'])) {
            return $_SESSION['username'];
        }

        return false;
    }

    public function storeData(User $user): void
    {
        $this->users[$user->getUsername()] = $user->getData();
        file_put_contents($this->userFile, json_encode($this->users));
    }

    public function loadUser($name)
    {
        if (isset($this->users[$name])) {
            return new User($name, $this->users[$name]);
        }

        return false;
    }
}

class User
{
    public function __construct($user, $data)
    {
        $this->data = $data;
        $this->user = $user;
    }

    public function auth($pass)
    {
        if ($this->data['password'] === $pass) {
            return true;
        }

        return false;
    }

    public function startSession(): void
    {
        $_SESSION['username'] = $this->user;
    }

    public function doLogin(): void
    {
        session_regenerate_id();
        $_SESSION['loggedin'] = true;
        $_SESSION['ua'] = $_SERVER['HTTP_USER_AGENT'];
    }

    public function doOTP(): void
    {
        $_SESSION['OTP'] = true;
    }

    public function isOTP()
    {
        if (isset($_SESSION['OTP']) && true == $_SESSION['OTP']) {
            return true;
        }

        return false;
    }

    public function isLoggedIn()
    {
        if (isset($_SESSION['loggedin']) && true == $_SESSION['loggedin'] &&
            isset($_SESSION['ua']) && $_SESSION['ua'] == $_SERVER['HTTP_USER_AGENT']
        ) {
            return $_SESSION['username'];
        }

        return false;
    }

    public function getUsername()
    {
        return $this->user;
    }

    public function getSecret()
    {
        if (isset($this->data['secret'])) {
            return $this->data['secret'];
        }

        return false;
    }

    public function generateSecret()
    {
        $g = new \Sonata\GoogleAuthenticator\GoogleAuthenticator();
        $secret = $g->generateSecret();
        $this->data['secret'] = $secret;

        return $secret;
    }

    public function getData()
    {
        return $this->data;
    }

    public function setOTPCookie(): void
    {
        $time = floor(time() / (3600 * 24)); // get day number
        //about using the user agent: It's easy to fake it, but it increases the barrier for stealing and reusing cookies nevertheless
        // and it doesn't do any harm (except that it's invalid after a browser upgrade, but that may be even intented)
        $cookie = $time.':'.hash_hmac('sha1', $this->getUsername().':'.$time.':'.$_SERVER['HTTP_USER_AGENT'], $this->getSecret());
        setcookie('otp', $cookie, time() + (30 * 24 * 3600), null, null, null, true);
    }

    public function hasValidOTPCookie()
    {
        // 0 = tomorrow it is invalid
        $daysUntilInvalid = 0;
        $time = (string) floor((time() / (3600 * 24))); // get day number
        if (isset($_COOKIE['otp'])) {
            list($otpday, $hash) = explode(':', $_COOKIE['otp']);

            if ($otpday >= $time - $daysUntilInvalid && $hash == hash_hmac('sha1', $this->getUsername().':'.$otpday.':'.$_SERVER['HTTP_USER_AGENT'], $this->getSecret())) {
                return true;
            }
        }

        return false;
    }
}
google-authenticator/sample/web/index.php000064400000010424147361034100014546 0ustar00<?php declare(strict_types=1);
ob_start(); //i'm too lazy to check when is sent what ;)
//set session cookie to be read only via http and not by JavaScript
ini_set('session.cookie_httponly', '1');

include_once __DIR__.'/../../src/GoogleAuthenticator.php';
include_once __DIR__.'/../../src/GoogleQrUrl.php';
include_once __DIR__.'/../../src/FixedBitNotation.php';
include_once 'Users.php';

?>
<!DOCTYPE HTML>
<html>
<head>
    <title>Google Authenticator in PHP demo</title>
</head>
<body>
<?php

//set this to false, if you don't want the token prefilled
$debug = true;

$users = new Users();
//check if the user has a session, if not, show the login screen
if ($username = $users->hasSession()) {
    //load the user data from the json storage.
    $user = $users->loadUser($username);
    //if he clicked logout, destroy the session and redirect to the startscreen.
    if (isset($_GET['logout'])) {
        session_destroy();
        header('Location: ./');
    }
    // check if the user is logged in.
    if ($user->isLoggedIn()) {
        include __DIR__.'/../tmpl/loggedin.php';
        //show the QR code if whished so
        if (isset($_GET['showqr'])) {
            $secret = $user->getSecret();
            include __DIR__.'/../tmpl/show-qr.php';
        }
    }
    //if the user is in the OTP phase and submit the OTP.
    else {
        if ($user->isOTP() && isset($_POST['otp'])) {
            $g = new \Google\Authenticator\GoogleAuthenticator();
            // check if the submitted token is the right one and log in
            if ($g->checkCode($user->getSecret(), $_POST['otp'])) {
                // do log-in the user
                $user->doLogin();
                //if the user clicked the "remember the token" checkbox, set the cookie
                if (isset($_POST['remember']) && $_POST['remember']) {
                    $user->setOTPCookie();
                }
                include __DIR__.'/../tmpl/loggedin.php';
            }
            //if the OTP is wrong, destroy the session and tell the user to try again
            else {
                session_destroy();
                include __DIR__.'/../tmpl/login-error.php';
            }
        }
        // if the user is neither logged in nor in the OTP phase, show the login form
        else {
            session_destroy();
            include __DIR__.'/../tmpl/login.php';
        }
    }
    die();
}
    //if the username is set in _POST, then we assume the user filled in the login form.

    if (isset($_POST['username'])) {
        // check if we can load the user (ie. the user exists in our db)
        $user = $users->loadUser($_POST['username']);
        if ($user) {
            //try to authenticate the password and start the session if it's correct.
            if ($user->auth($_POST['password'])) {
                $user->startSession();
                //check if the user has a valid OTP cookie, so we don't have to
                // ask for the current token and can directly log in
                if ($user->hasValidOTPCookie()) {
                    include __DIR__.'/../tmpl/loggedin.php';
                    $user->doLogin();
                }
                // try to get the users' secret from the db,
                //  if he doesn't have one, generate one, store it and show it.
                else {
                    if (!$user->getSecret()) {
                        include __DIR__.'/../tmpl/loggedin.php';

                        $secret = $user->generateSecret();
                        $users->storeData($user);
                        $user->doLogin();
                        include __DIR__.'/../tmpl/show-qr.php';
                    }
                    // if the user neither has a valid OTP cookie nor it's the first login
                    //  ask for the OTP
                    else {
                        $user->doOTP();
                        include __DIR__.'/../tmpl/ask-for-otp.php';
                    }
                }

                die();
            }
        }
        // if we're here, something went wrong, destroy the session and show a login error
        session_destroy();

        include __DIR__.'/../tmpl/login-error.php';
        die();
    }

// if neither a session nor tried to submit the login credentials -> login screen
include __DIR__.'/../tmpl/login.php';

?>
</body>
</html>
google-authenticator/sample/users.dat000064400000000040147361034100013775 0ustar00{"chregu":{"password":"foobar"}}google-authenticator/src/GoogleQrUrl.php000064400000005665147361034100014405 0ustar00<?php

declare(strict_types=1);

/*
 * This file is part of the Sonata Project package.
 *
 * (c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Sonata\GoogleAuthenticator;

/**
 * Responsible for QR image url generation.
 *
 * @see https://developers.google.com/chart/infographics/docs/qr_codes
 * @see https://github.com/google/google-authenticator/wiki/Key-Uri-Format
 *
 * @author Iltar van der Berg <kjarli@gmail.com>
 */
final class GoogleQrUrl
{
    /**
     * Private by design.
     */
    private function __construct()
    {
    }

    /**
     * Generates a URL that is used to show a QR code.
     *
     * Account names may not contain a double colon (:). Valid account name
     * examples:
     *  - "John.Doe@gmail.com"
     *  - "John Doe"
     *  - "John_Doe_976"
     *
     * The Issuer may not contain a double colon (:). The issuer is recommended
     * to pass along. If used, it will also be appended before the accountName.
     *
     * The previous examples with the issuer "Acme inc" would result in label:
     *  - "Acme inc:John.Doe@gmail.com"
     *  - "Acme inc:John Doe"
     *  - "Acme inc:John_Doe_976"
     *
     * The contents of the label, issuer and secret will be encoded to generate
     * a valid URL.
     *
     * @param string      $accountName The account name to show and identify
     * @param string      $secret      The secret is the generated secret unique to that user
     * @param string|null $issuer      Where you log in to
     * @param int         $size        Image size in pixels, 200 will make it 200x200
     *
     * @return string
     */
    public static function generate(string $accountName, string $secret, string $issuer = null, int $size = 200): string
    {
        if ('' === $accountName || false !== strpos($accountName, ':')) {
            throw RuntimeException::InvalidAccountName($accountName);
        }

        if ('' === $secret) {
            throw RuntimeException::InvalidSecret();
        }

        $label = $accountName;
        $otpauthString = 'otpauth://totp/%s?secret=%s';

        if (null !== $issuer) {
            if ('' === $issuer || false !== strpos($issuer, ':')) {
                throw RuntimeException::InvalidIssuer($issuer);
            }

            // use both the issuer parameter and label prefix as recommended by Google for BC reasons
            $label = $issuer.':'.$label;
            $otpauthString .= '&issuer=%s';
        }

        $otpauthString = rawurlencode(sprintf($otpauthString, $label, $secret, $issuer));

        return sprintf(
            'https://chart.googleapis.com/chart?chs=%1$dx%1$d&chld=M|0&cht=qr&chl=%2$s',
            $size,
            $otpauthString
        );
    }
}

// NEXT_MAJOR: Remove class alias
class_alias('Sonata\GoogleAuthenticator\GoogleQrUrl', 'Google\Authenticator\GoogleQrUrl', false);
google-authenticator/src/GoogleAuthenticator.php000064400000012641147361034100016142 0ustar00<?php

declare(strict_types=1);

/*
 * This file is part of the Sonata Project package.
 *
 * (c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Sonata\GoogleAuthenticator;

/**
 * @see https://github.com/google/google-authenticator/wiki/Key-Uri-Format
 */
final class GoogleAuthenticator implements GoogleAuthenticatorInterface
{
    /**
     * @var int
     */
    private $passCodeLength;

    /**
     * @var int
     */
    private $secretLength;

    /**
     * @var int
     */
    private $pinModulo;

    /**
     * @var \DateTimeInterface
     */
    private $now;

    /**
     * @var int
     */
    private $codePeriod = 30;

    /**
     * @param int                     $passCodeLength
     * @param int                     $secretLength
     * @param \DateTimeInterface|null $now
     */
    public function __construct(int $passCodeLength = 6, int $secretLength = 10, \DateTimeInterface $now = null)
    {
        $this->passCodeLength = $passCodeLength;
        $this->secretLength = $secretLength;
        $this->pinModulo = 10 ** $passCodeLength;
        $this->now = $now ?? new \DateTimeImmutable();
    }

    /**
     * @param string $secret
     * @param string $code
     */
    public function checkCode($secret, $code): bool
    {
        /**
         * The result of each comparison is accumulated here instead of using a guard clause
         * (https://refactoring.com/catalog/replaceNestedConditionalWithGuardClauses.html). This is to implement
         * constant time comparison to make side-channel attacks harder. See
         * https://cryptocoding.net/index.php/Coding_rules#Compare_secret_strings_in_constant_time for details.
         * Each comparison uses hash_equals() instead of an operator to implement constant time equality comparison
         * for each code.
         */
        $result = 0;

        // current period
        $result += hash_equals($this->getCode($secret, $this->now), $code);

        // previous period, happens if the user was slow to enter or it just crossed over
        $dateTime = new \DateTimeImmutable('@'.($this->now->getTimestamp() - $this->codePeriod));
        $result += hash_equals($this->getCode($secret, $dateTime), $code);

        // next period, happens if the user is not completely synced and possibly a few seconds ahead
        $dateTime = new \DateTimeImmutable('@'.($this->now->getTimestamp() + $this->codePeriod));
        $result += hash_equals($this->getCode($secret, $dateTime), $code);

        return $result > 0;
    }

    /**
     * NEXT_MAJOR: add the interface typehint to $time and remove deprecation.
     *
     * @param string                                   $secret
     * @param float|string|int|null|\DateTimeInterface $time
     */
    public function getCode($secret, /* \DateTimeInterface */$time = null): string
    {
        if (null === $time) {
            $time = $this->now;
        }

        if ($time instanceof \DateTimeInterface) {
            $timeForCode = floor($time->getTimestamp() / $this->codePeriod);
        } else {
            @trigger_error(
                'Passing anything other than null or a DateTimeInterface to $time is deprecated as of 2.0 '.
                'and will not be possible as of 3.0.',
                E_USER_DEPRECATED
            );
            $timeForCode = $time;
        }

        $base32 = new FixedBitNotation(5, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', true, true);
        $secret = $base32->decode($secret);

        $timeForCode = str_pad(pack('N', $timeForCode), 8, chr(0), STR_PAD_LEFT);

        $hash = hash_hmac('sha1', $timeForCode, $secret, true);
        $offset = ord(substr($hash, -1));
        $offset &= 0xF;

        $truncatedHash = $this->hashToInt($hash, $offset) & 0x7FFFFFFF;

        return str_pad((string) ($truncatedHash % $this->pinModulo), $this->passCodeLength, '0', STR_PAD_LEFT);
    }

    /**
     * NEXT_MAJOR: Remove this method.
     *
     * @param string $user
     * @param string $hostname
     * @param string $secret
     *
     * @deprecated deprecated as of 2.1 and will be removed in 3.0. Use Sonata\GoogleAuthenticator\GoogleQrUrl::generate() instead.
     */
    public function getUrl($user, $hostname, $secret): string
    {
        @trigger_error(sprintf(
            'Using %s() is deprecated as of 2.1 and will be removed in 3.0. '.
            'Use Sonata\GoogleAuthenticator\GoogleQrUrl::generate() instead.',
            __METHOD__
        ), E_USER_DEPRECATED);

        $issuer = func_get_args()[3] ?? null;
        $accountName = sprintf('%s@%s', $user, $hostname);

        // manually concat the issuer to avoid a change in URL
        $url = GoogleQrUrl::generate($accountName, $secret);

        if ($issuer) {
            $url .= '%26issuer%3D'.$issuer;
        }

        return $url;
    }

    public function generateSecret(): string
    {
        return (new FixedBitNotation(5, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', true, true))
            ->encode(random_bytes($this->secretLength));
    }

    /**
     * @param string $bytes
     * @param int    $start
     */
    private function hashToInt(string $bytes, int $start): int
    {
        return unpack('N', substr(substr($bytes, $start), 0, 4))[1];
    }
}

// NEXT_MAJOR: Remove class alias
class_alias('Sonata\GoogleAuthenticator\GoogleAuthenticator', 'Google\Authenticator\GoogleAuthenticator', false);
google-authenticator/src/GoogleAuthenticatorInterface.php000064400000002257147361034100017765 0ustar00<?php

declare(strict_types=1);

/*
 * This file is part of the Sonata Project package.
 *
 * (c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Sonata\GoogleAuthenticator;

interface GoogleAuthenticatorInterface
{
    /**
     * @param string $secret
     * @param string $code
     */
    public function checkCode($secret, $code): bool;

    /**
     * NEXT_MAJOR: add the interface typehint to $time and remove deprecation.
     *
     * @param string                                   $secret
     * @param float|string|int|null|\DateTimeInterface $time
     */
    public function getCode($secret, /* \DateTimeInterface */$time = null): string;

    /**
     * NEXT_MAJOR: Remove this method.
     *
     * @param string $user
     * @param string $hostname
     * @param string $secret
     *
     * @deprecated deprecated as of 2.1 and will be removed in 3.0. Use Sonata\GoogleAuthenticator\GoogleQrUrl::generate() instead.
     */
    public function getUrl($user, $hostname, $secret): string;

    public function generateSecret(): string;
}
google-authenticator/src/RuntimeException.php000064400000002373147361034100015476 0ustar00<?php

declare(strict_types=1);

/*
 * This file is part of the Sonata Project package.
 *
 * (c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Sonata\GoogleAuthenticator;

/**
 * Contains runtime exception templates.
 *
 * @author Iltar van der Berg <kjarli@gmail.com>
 */
final class RuntimeException extends \RuntimeException
{
    public static function InvalidAccountName(string $accountName): self
    {
        return new self(sprintf(
            'The account name may not contain a double colon (:) and may not be an empty string. Given "%s".',
            $accountName
        ));
    }

    public static function InvalidIssuer(string $issuer): self
    {
        return new self(sprintf(
            'The issuer name may not contain a double colon (:) and may not be an empty string. Given "%s".',
            $issuer
        ));
    }

    public static function InvalidSecret(): self
    {
        return new self('The secret name may not be an empty string.');
    }
}

// NEXT_MAJOR: Remove class alias
class_alias('Sonata\GoogleAuthenticator\RuntimeException', 'Google\Authenticator\RuntimeException', false);
google-authenticator/src/FixedBitNotation.php000064400000023340147361034100015403 0ustar00<?php

declare(strict_types=1);

/*
 * This file is part of the Sonata Project package.
 *
 * (c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Sonata\GoogleAuthenticator;

/**
 * FixedBitNotation.
 *
 * The FixedBitNotation class is for binary to text conversion. It
 * can handle many encoding schemes, formally defined or not, that
 * use a fixed number of bits to encode each character.
 *
 * @author Andre DeMarre
 */
final class FixedBitNotation
{
    /**
     * @var string
     */
    private $chars;

    /**
     * @var int
     */
    private $bitsPerCharacter;

    /**
     * @var int
     */
    private $radix;

    /**
     * @var bool
     */
    private $rightPadFinalBits;

    /**
     * @var bool
     */
    private $padFinalGroup;

    /**
     * @var string
     */
    private $padCharacter;

    /**
     * @var string[]
     */
    private $charmap;

    /**
     * @param int    $bitsPerCharacter  Bits to use for each encoded character
     * @param string $chars             Base character alphabet
     * @param bool   $rightPadFinalBits How to encode last character
     * @param bool   $padFinalGroup     Add padding to end of encoded output
     * @param string $padCharacter      Character to use for padding
     */
    public function __construct(int $bitsPerCharacter, string $chars = null, bool $rightPadFinalBits = false, bool $padFinalGroup = false, string $padCharacter = '=')
    {
        // Ensure validity of $chars
        if (!is_string($chars) || ($charLength = strlen($chars)) < 2) {
            $chars =
            '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-,';
            $charLength = 64;
        }

        // Ensure validity of $bitsPerCharacter
        if ($bitsPerCharacter < 1) {
            // $bitsPerCharacter must be at least 1
            $bitsPerCharacter = 1;
            $radix = 2;
        } elseif ($charLength < 1 << $bitsPerCharacter) {
            // Character length of $chars is too small for $bitsPerCharacter
            // Set $bitsPerCharacter to greatest acceptable value
            $bitsPerCharacter = 1;
            $radix = 2;

            while ($charLength >= ($radix <<= 1) && $bitsPerCharacter < 8) {
                ++$bitsPerCharacter;
            }

            $radix >>= 1;
        } elseif ($bitsPerCharacter > 8) {
            // $bitsPerCharacter must not be greater than 8
            $bitsPerCharacter = 8;
            $radix = 256;
        } else {
            $radix = 1 << $bitsPerCharacter;
        }

        $this->chars = $chars;
        $this->bitsPerCharacter = $bitsPerCharacter;
        $this->radix = $radix;
        $this->rightPadFinalBits = $rightPadFinalBits;
        $this->padFinalGroup = $padFinalGroup;
        $this->padCharacter = $padCharacter[0];
    }

    /**
     * Encode a string.
     *
     * @param string $rawString Binary data to encode
     *
     * @return string
     */
    public function encode($rawString): string
    {
        // Unpack string into an array of bytes
        $bytes = unpack('C*', $rawString);
        $byteCount = count($bytes);

        $encodedString = '';
        $byte = array_shift($bytes);
        $bitsRead = 0;

        $chars = $this->chars;
        $bitsPerCharacter = $this->bitsPerCharacter;
        $rightPadFinalBits = $this->rightPadFinalBits;
        $padFinalGroup = $this->padFinalGroup;
        $padCharacter = $this->padCharacter;

        // Generate encoded output;
        // each loop produces one encoded character
        for ($c = 0; $c < $byteCount * 8 / $bitsPerCharacter; ++$c) {
            // Get the bits needed for this encoded character
            if ($bitsRead + $bitsPerCharacter > 8) {
                // Not enough bits remain in this byte for the current
                // character
                // Save the remaining bits before getting the next byte
                $oldBitCount = 8 - $bitsRead;
                $oldBits = $byte ^ ($byte >> $oldBitCount << $oldBitCount);
                $newBitCount = $bitsPerCharacter - $oldBitCount;

                if (!$bytes) {
                    // Last bits; match final character and exit loop
                    if ($rightPadFinalBits) {
                        $oldBits <<= $newBitCount;
                    }
                    $encodedString .= $chars[$oldBits];

                    if ($padFinalGroup) {
                        // Array of the lowest common multiples of
                        // $bitsPerCharacter and 8, divided by 8
                        $lcmMap = [1 => 1, 2 => 1, 3 => 3, 4 => 1, 5 => 5, 6 => 3, 7 => 7, 8 => 1];
                        $bytesPerGroup = $lcmMap[$bitsPerCharacter];
                        $pads = $bytesPerGroup * 8 / $bitsPerCharacter
                        - ceil((strlen($rawString) % $bytesPerGroup)
                        * 8 / $bitsPerCharacter);
                        $encodedString .= str_repeat($padCharacter[0], $pads);
                    }

                    break;
                }

                // Get next byte
                $byte = array_shift($bytes);
                $bitsRead = 0;
            } else {
                $oldBitCount = 0;
                $newBitCount = $bitsPerCharacter;
            }

            // Read only the needed bits from this byte
            $bits = $byte >> 8 - ($bitsRead + $newBitCount);
            $bits ^= $bits >> $newBitCount << $newBitCount;
            $bitsRead += $newBitCount;

            if ($oldBitCount) {
                // Bits come from seperate bytes, add $oldBits to $bits
                $bits = ($oldBits << $newBitCount) | $bits;
            }

            $encodedString .= $chars[$bits];
        }

        return $encodedString;
    }

    /**
     * Decode a string.
     *
     * @param string $encodedString Data to decode
     * @param bool   $caseSensitive
     * @param bool   $strict        Returns null if $encodedString contains
     *                              an undecodable character
     *
     * @return string
     */
    public function decode($encodedString, $caseSensitive = true, $strict = false): string
    {
        if (!$encodedString || !is_string($encodedString)) {
            // Empty string, nothing to decode
            return '';
        }

        $chars = $this->chars;
        $bitsPerCharacter = $this->bitsPerCharacter;
        $radix = $this->radix;
        $rightPadFinalBits = $this->rightPadFinalBits;
        $padCharacter = $this->padCharacter;

        // Get index of encoded characters
        if ($this->charmap) {
            $charmap = $this->charmap;
        } else {
            $charmap = [];

            for ($i = 0; $i < $radix; ++$i) {
                $charmap[$chars[$i]] = $i;
            }

            $this->charmap = $charmap;
        }

        // The last encoded character is $encodedString[$lastNotatedIndex]
        $lastNotatedIndex = strlen($encodedString) - 1;

        // Remove trailing padding characters
        while ($encodedString[$lastNotatedIndex] == $padCharacter[0]) {
            $encodedString = substr($encodedString, 0, $lastNotatedIndex);
            --$lastNotatedIndex;
        }

        $rawString = '';
        $byte = 0;
        $bitsWritten = 0;

        // Convert each encoded character to a series of unencoded bits
        for ($c = 0; $c <= $lastNotatedIndex; ++$c) {
            if (!isset($charmap[$encodedString[$c]]) && !$caseSensitive) {
                // Encoded character was not found; try other case
                if (isset($charmap[$cUpper = strtoupper($encodedString[$c])])) {
                    $charmap[$encodedString[$c]] = $charmap[$cUpper];
                } elseif (isset($charmap[$cLower = strtolower($encodedString[$c])])) {
                    $charmap[$encodedString[$c]] = $charmap[$cLower];
                }
            }

            if (isset($charmap[$encodedString[$c]])) {
                $bitsNeeded = 8 - $bitsWritten;
                $unusedBitCount = $bitsPerCharacter - $bitsNeeded;

                // Get the new bits ready
                if ($bitsNeeded > $bitsPerCharacter) {
                    // New bits aren't enough to complete a byte; shift them
                    // left into position
                    $newBits = $charmap[$encodedString[$c]] << $bitsNeeded
                    - $bitsPerCharacter;
                    $bitsWritten += $bitsPerCharacter;
                } elseif ($c != $lastNotatedIndex || $rightPadFinalBits) {
                    // Zero or more too many bits to complete a byte;
                    // shift right
                    $newBits = $charmap[$encodedString[$c]] >> $unusedBitCount;
                    $bitsWritten = 8; //$bitsWritten += $bitsNeeded;
                } else {
                    // Final bits don't need to be shifted
                    $newBits = $charmap[$encodedString[$c]];
                    $bitsWritten = 8;
                }

                $byte |= $newBits;

                if (8 == $bitsWritten || $c == $lastNotatedIndex) {
                    // Byte is ready to be written
                    $rawString .= pack('C', $byte);

                    if ($c != $lastNotatedIndex) {
                        // Start the next byte
                        $bitsWritten = $unusedBitCount;
                        $byte = ($charmap[$encodedString[$c]]
                        ^ ($newBits << $unusedBitCount)) << 8 - $bitsWritten;
                    }
                }
            } elseif ($strict) {
                // Unable to decode character; abort
                return null;
            }
        }

        return $rawString;
    }
}

// NEXT_MAJOR: Remove class alias
class_alias('Sonata\GoogleAuthenticator\FixedBitNotation', 'Google\Authenticator\FixedBitNotation', false);
google-authenticator/LICENSE000064400000002070147361034100011673 0ustar00The MIT License (MIT)

Copyright (c) 2010 Thomas Rabaix

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.