1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
|
<?php
/** Require One-Time Password at login
* @link https://www.adminer.org/plugins/otp/
* @author Jakub Vrana, https://www.vrana.cz/
* @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)
*/
class AdminerLoginOtp extends Adminer\Plugin {
protected $secret;
/**
* @param string $secret decoded secret, e.g. base64_decode("SECRET")
*/
function __construct(string $secret) {
$this->secret = $secret;
if ($_POST["auth"]) {
$_SESSION["otp"] = (string) $_POST["auth"]["otp"];
}
}
function loginFormField($name, $heading, $value) {
if ($name == 'password') {
return $heading . $value . "\n"
. "<tr><th><abbr title='" . $this->lang('One Time Password') . "'>OTP</abbr>"
. "<td><input type='number' name='auth[otp]' value='" . Adminer\h($_SESSION["otp"]) . "' size='6' autocomplete='one-time-code' inputmode='numeric' maxlength='6' pattern='\d{6}'>\n"
;
}
}
function login($login, $password) {
if (isset($_SESSION["otp"])) {
$timeSlot = floor(time() / 30);
foreach (array(0, -1, 1) as $skew) {
if ($_SESSION["otp"] == $this->getOtp($timeSlot + $skew)) {
Adminer\restart_session();
unset($_SESSION["otp"]);
Adminer\stop_session();
return;
}
}
return $this->lang('Invalid OTP.');
}
}
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;
$unpacked = unpack('N', substr($hash, $offset, 4));
return ($unpacked[1] & 0x7FFFFFFF) % 1e6;
}
function screenshot() {
return "https://www.adminer.org/static/login-otp.png";
}
protected $translations = array(
'cs' => array(
'' => 'Při přihlášení požaduje jednorázové heslo',
'One Time Password' => 'Jednorázové heslo',
'Invalid OTP.' => 'Neplatné jednorázové heslo.',
),
'de' => array(
'' => 'Bei der Anmeldung ist ein Einmalpasswort (Zwei-Faktor-Authentifizierung) erforderlich',
'One Time Password' => 'Einmal-Passwort',
'Invalid OTP.' => 'Ungültiger OTP.',
),
'pl' => array(
'' => 'Wymagaj jednorazowego hasła przy logowaniu',
),
'ro' => array(
'' => 'Cereți o parolă unică la autentificare',
),
'ja' => array(
'' => 'ログイン時にワンタイムパスワード (二要素認証) が必要',
),
);
}
|