From 56d5cdb411613841b3bb99ed755dc3d956d36237 Mon Sep 17 00:00:00 2001 From: Eko Junaidi Salam Date: Tue, 10 May 2022 00:46:20 +0700 Subject: [PATCH] Initial Code --- .gitattributes | 6 +++++ .gitignore | 5 ++++ LICENSE | 21 ++++++++++++++++ README.md | 2 ++ composer.json | 23 +++++++++++++++++ src/HOTP.php | 66 +++++++++++++++++++++++++++++++++++++++++++++++++ src/TOTP.php | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 190 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 composer.json create mode 100644 src/HOTP.php create mode 100644 src/TOTP.php diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..44d5cff --- /dev/null +++ b/.gitattributes @@ -0,0 +1,6 @@ +.gitattributes export-ignore +.gitignore export-ignore +.gitreview export-ignore +.travis.yml export-ignore +phpunit.xml export-ignore +tests/ export-ignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d792118 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +composer.lock +vendor/ +build/ +.phpunit.result.cache +.phpunit.cache diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..202fb58 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Eko Junaidi Salam + +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. diff --git a/README.md b/README.md new file mode 100644 index 0000000..9238073 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# ejsotp +TOTP dan HOTP Library with backup codes, compatible with google authenticator diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..ccbdf0b --- /dev/null +++ b/composer.json @@ -0,0 +1,23 @@ +{ + "name": "ekojs/otp", + "description": "TOTP dan HOTP Library with backup codes, compatible with google authenticator", + "type": "library", + "license": "MIT", + "autoload": { + "psr-4": { + "Ekojs\\Otp\\": "src/" + } + }, + "authors": [ + { + "name": "Eko Junaidi Salam", + "email": "eko.junaidi.salam@gmail.com" + } + ], + "minimum-stability": "stable", + "require": { + "spomky-labs/otphp": "^10.0", + "endroid/qr-code": "^4.4", + "furqansiddiqui/bip39-mnemonic-php": "^0.1.4" + } +} diff --git a/src/HOTP.php b/src/HOTP.php new file mode 100644 index 0000000..f55c692 --- /dev/null +++ b/src/HOTP.php @@ -0,0 +1,66 @@ + + */ + +namespace Ekojs\Otp; + +use OTPHP\HOTP as LabHOTP; +use \FurqanSiddiqui\BIP39\BIP39; +use \FurqanSiddiqui\BIP39\Wordlist; +use Endroid\QrCode\QrCode; +use Endroid\QrCode\Writer\PngWriter; +use Endroid\QrCode\Logo\Logo; +use Endroid\QrCode\Label\Label; +use Endroid\QrCode\Color\Color; + +class HOTP { + public static $instance; + public $otp; + protected $writer; + protected $bip39; + public $parameters = []; + + public function __construct(?array $params=null) { + $this->parameters = $params; + $this->otp = LabHOTP::create($params["secret"] ?? null, $params["counter"] ?? 0, $params["digest"] ?? 'sha1', $params["digits"] ?? 6); + $this->writer = new PngWriter(); + $this->bip39 = new BIP39(); + self::$instance = $this; + } + + public static function getInstance(?array $params=null) { + if (self::$instance === null) { + self::$instance = new self($params); + } + return self::$instance; + } + + public function getParams(): array { + return $this->parameters; + } + + public function generateQr(?string $logo=null, bool $setLabel=false, int $size=200) { + $label = null; + $qrCode = QrCode::create($this->otp->getProvisioningUri()); + $qrCode->setSize($size); + + if(!empty($logo)) $logo = Logo::create($logo)->setResizeToWidth(50); + if(!empty($this->otp->getLabel()) && $setLabel) $label = Label::create($this->otp->getLabel())->setTextColor(new Color(0, 0, 255)); + + return $this->writer->write($qrCode, $logo, $label); + } + + public function generateBackupCodes(string $entropy, ?WordList $wordList=null) { + $wordList = $wordList ?? WordList::English(); + return $this->bip39->wordlist($wordList)->useEntropy(hash("md5",$entropy))->mnemonic(); + } + + public function reverseMnemonic($words) { + return $this->bip39::Words($words); + } +} + \ No newline at end of file diff --git a/src/TOTP.php b/src/TOTP.php new file mode 100644 index 0000000..594b364 --- /dev/null +++ b/src/TOTP.php @@ -0,0 +1,67 @@ + + */ + +namespace Ekojs\Otp; + +use OTPHP\TOTP as LabTOTP; +use \FurqanSiddiqui\BIP39\BIP39; +use \FurqanSiddiqui\BIP39\Wordlist; +use Endroid\QrCode\QrCode; +use Endroid\QrCode\Writer\PngWriter; +use Endroid\QrCode\Logo\Logo; +use Endroid\QrCode\Label\Label; +use Endroid\QrCode\Color\Color; + +class TOTP { + public static $instance; + private $mode; + public $otp; + protected $writer; + protected $bip39; + public $parameters = []; + + public function __construct(?array $params=null) { + $this->parameters = $params; + $this->otp = LabTOTP::create($params["secret"] ?? null, $params["period"] ?? 30, $params["digest"] ?? 'sha1', $params["digits"] ?? 6, $params["epoch"] ?? 0); + $this->writer = new PngWriter(); + $this->bip39 = new BIP39(); + self::$instance = $this; + } + + public static function getInstance(?array $params=null) { + if (self::$instance === null) { + self::$instance = new self($params); + } + return self::$instance; + } + + public function getParams(): array { + return $this->parameters; + } + + public function generateQr(?string $logo=null, bool $setLabel=false, int $size=200) { + $label = null; + $qrCode = QrCode::create($this->otp->getProvisioningUri()); + $qrCode->setSize($size); + + if(!empty($logo)) $logo = Logo::create($logo)->setResizeToWidth(50); + if(!empty($this->otp->getLabel()) && $setLabel) $label = Label::create($this->otp->getLabel())->setTextColor(new Color(0, 0, 255)); + + return $this->writer->write($qrCode, $logo, $label); + } + + public function generateBackupCodes(string $entropy, ?WordList $wordList=null) { + $wordList = $wordList ?? WordList::English(); + return $this->bip39->wordlist($wordList)->useEntropy(hash("md5",$entropy))->mnemonic(); + } + + public function reverseMnemonic($words) { + return $this->bip39::Words($words); + } +} + \ No newline at end of file