mirror of
https://github.com/vrana/adminer.git
synced 2025-08-29 17:19:52 +02:00
AdminerLoginOtp: Autocomplete hints for OTP input field, code refactoring
Tanks to SGCBB (https://github.com/vrana/adminer/pull/488)
This commit is contained in:
@@ -1,54 +1,79 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/** Require One-Time Password at login
|
/** Require One-Time Password at login
|
||||||
* @link https://www.adminer.org/plugins/otp/
|
* @link https://www.adminer.org/plugins/otp/
|
||||||
* @author Jakub Vrana, https://www.vrana.cz/
|
* @author Jakub Vrana, https://www.vrana.cz/
|
||||||
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
|
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
|
||||||
* @license https://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, version 2 (one or other)
|
* @license https://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, version 2 (one or other)
|
||||||
*/
|
*/
|
||||||
class AdminerLoginOtp {
|
class AdminerLoginOtp
|
||||||
/** @access protected */
|
{
|
||||||
var $secret;
|
/** @var string */
|
||||||
|
private $secret;
|
||||||
/**
|
|
||||||
* @param string decoded secret, e.g. base32_decode("SECRET")
|
/**
|
||||||
*/
|
* @param string $secret Decoded secret, e.g. base64_decode("ENCODED_SECRET").
|
||||||
function __construct($secret) {
|
*/
|
||||||
|
public function __construct($secret) {
|
||||||
$this->secret = $secret;
|
$this->secret = $secret;
|
||||||
if ($_POST["auth"]) {
|
|
||||||
$_SESSION["otp"] = (string) $_POST["auth"]["otp"];
|
if (isset($_POST["auth"])) {
|
||||||
}
|
$_SESSION["otp"] = (string)$_POST["auth"]["otp"];
|
||||||
}
|
|
||||||
|
|
||||||
function loginFormField($name, $heading, $value) {
|
|
||||||
if ($name == 'password') {
|
|
||||||
return $heading . $value
|
|
||||||
. "<tr><th><acronym title='One Time Password' lang='en'>OTP</acronym>"
|
|
||||||
. "<td><input type='number' name='auth[otp]' value='" . h($_SESSION["otp"]) . "' size='6' autocomplete='off'>\n"
|
|
||||||
;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function login($login, $password) {
|
/**
|
||||||
if (isset($_SESSION["otp"])) {
|
* @param string $name
|
||||||
$timeSlot = floor(time() / 30);
|
* @param string $heading
|
||||||
foreach (array(0, -1, 1) as $skew) {
|
* @param string $value
|
||||||
if ($_SESSION["otp"] == $this->getOtp($timeSlot + $skew)) {
|
*
|
||||||
restart_session();
|
* @return string|null
|
||||||
unset($_SESSION["otp"]);
|
*/
|
||||||
stop_session();
|
public function loginFormField($name, $heading, $value) {
|
||||||
return;
|
if ($name != "password") return null;
|
||||||
}
|
|
||||||
}
|
return $heading . $value .
|
||||||
return 'Invalid OTP.';
|
"<tr><th><abbr title='" . lang('One Time Password') . "' lang='en'>OTP</abbr></th>" .
|
||||||
}
|
"<td><input type='text' name='auth[otp]' value='" . h($_SESSION["otp"]) . "' " .
|
||||||
|
"size='6' autocomplete='one-time-code' inputmode='numeric' maxlength='6' pattern='\d{6}'/></td>" .
|
||||||
|
"</tr>\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
function getOtp($timeSlot) {
|
/**
|
||||||
$data = str_pad(pack('N', $timeSlot), 8, "\0", STR_PAD_LEFT);
|
* @param string $login
|
||||||
$hash = hash_hmac('sha1', $data, $this->secret, true);
|
* @param string $password
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function login($login, $password) {
|
||||||
|
if (!isset($_SESSION["otp"])) return null;
|
||||||
|
|
||||||
|
$timeSlot = floor(time() / 30);
|
||||||
|
|
||||||
|
foreach (array(0, -1, 1) as $skew) {
|
||||||
|
if ($_SESSION["otp"] == $this->getOtp($timeSlot + $skew)) {
|
||||||
|
restart_session();
|
||||||
|
unset($_SESSION["otp"]);
|
||||||
|
stop_session();
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return lang('Invalid OTP code.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $timeSlot
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
private function getOtp($timeSlot) {
|
||||||
|
$data = str_pad(pack("N", $timeSlot), 8, "\0", STR_PAD_LEFT);
|
||||||
|
$hash = hash_hmac("sha1", $data, $this->secret, true);
|
||||||
$offset = ord(substr($hash, -1)) & 0xF;
|
$offset = ord(substr($hash, -1)) & 0xF;
|
||||||
$unpacked = unpack('N', substr($hash, $offset, 4));
|
$unpacked = unpack("N", substr($hash, $offset, 4));
|
||||||
|
|
||||||
return ($unpacked[1] & 0x7FFFFFFF) % 1e6;
|
return ($unpacked[1] & 0x7FFFFFFF) % 1e6;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user