diff --git a/data/web/inc/functions.inc.php b/data/web/inc/functions.inc.php
index 7ac0af58..b222e13d 100644
--- a/data/web/inc/functions.inc.php
+++ b/data/web/inc/functions.inc.php
@@ -1142,7 +1142,7 @@ function set_tfa($_data) {
global $yubi;
global $u2f;
global $tfa;
- $_data_log = $_data;
+ $_data_log = $_data["tfa_method"];
!isset($_data_log['confirm_password']) ?: $_data_log['confirm_password'] = '*';
$username = $_SESSION['mailcow_cc_username'];
if (!isset($_SESSION['mailcow_cc_role']) || empty($username)) {
@@ -1183,6 +1183,8 @@ function set_tfa($_data) {
return false;
}
}
+
+
switch ($_data["tfa_method"]) {
case "yubi_otp":
$key_id = (!isset($_data["key_id"])) ? 'unidentified' : $_data["key_id"];
@@ -1240,14 +1242,18 @@ function set_tfa($_data) {
'msg' => array('object_modified', htmlspecialchars($username))
);
break;
+ // u2f - deprecated, should be removed
case "u2f":
$key_id = (!isset($_data["key_id"])) ? 'unidentified' : $_data["key_id"];
try {
$reg = $u2f->doRegister(json_decode($_SESSION['regReq']), json_decode($_data['token']));
+
$stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `username` = :username AND `authmech` != 'u2f'");
$stmt->execute(array(':username' => $username));
+
$stmt = $pdo->prepare("INSERT INTO `tfa` (`username`, `key_id`, `authmech`, `keyHandle`, `publicKey`, `certificate`, `counter`, `active`) VALUES (?, ?, 'u2f', ?, ?, ?, ?, '1')");
$stmt->execute(array($username, $key_id, $reg->keyHandle, $reg->publicKey, $reg->certificate, $reg->counter));
+
$_SESSION['return'][] = array(
'type' => 'success',
'log' => array(__FUNCTION__, $_data_log),
@@ -1286,6 +1292,29 @@ function set_tfa($_data) {
);
}
break;
+ case "webauthn":
+ $key_id = (!isset($_data["key_id"])) ? 'unidentified' : $_data["key_id"];
+
+ $stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `username` = :username AND `authmech` != 'webauthn'");
+ $stmt->execute(array(':username' => $username));
+
+ $stmt = $pdo->prepare("INSERT INTO `tfa` (`username`, `key_id`, `authmech`, `keyHandle`, `publicKey`, `certificate`, `counter`, `active`)
+ VALUES (?, ?, 'webauthn', ?, ?, ?, ?, '1')");
+ $stmt->execute(array(
+ $username,
+ $key_id,
+ base64_encode($_data['registration']->credentialId),
+ $_data['registration']->credentialPublicKey,
+ $_data['registration']->certificate,
+ 0
+ ));
+
+ $_SESSION['return'][] = array(
+ 'type' => 'success',
+ 'log' => array(__FUNCTION__, $_data_log),
+ 'msg' => array('object_modified', $username)
+ );
+ break;
case "none":
$stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `username` = :username");
$stmt->execute(array(':username' => $username));
@@ -1516,6 +1545,7 @@ function get_tfa($username = null) {
}
return $data;
break;
+ // u2f - deprecated, should be removed
case "u2f":
$data['name'] = "u2f";
$data['pretty'] = "Fido U2F";
@@ -1534,7 +1564,7 @@ function get_tfa($username = null) {
$data['pretty'] = "HMAC-based OTP";
return $data;
break;
- case "totp":
+ case "totp":
$data['name'] = "totp";
$data['pretty'] = "Time-based OTP";
$stmt = $pdo->prepare("SELECT `id`, `key_id`, `secret` FROM `tfa` WHERE `authmech` = 'totp' AND `username` = :username");
@@ -1546,7 +1576,20 @@ function get_tfa($username = null) {
$data['additional'][] = $row;
}
return $data;
- break;
+ break;
+ case "webauthn":
+ $data['name'] = "webauthn";
+ $data['pretty'] = "WebAuthn";
+ $stmt = $pdo->prepare("SELECT `id`, `key_id` FROM `tfa` WHERE `authmech` = 'webauthn' AND `username` = :username");
+ $stmt->execute(array(
+ ':username' => $username,
+ ));
+ $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
+ while($row = array_shift($rows)) {
+ $data['additional'][] = $row;
+ }
+ return $data;
+ break;
default:
$data['name'] = 'none';
$data['pretty'] = "-";
@@ -1560,140 +1603,261 @@ function get_tfa($username = null) {
return $data;
}
}
-function verify_tfa_login($username, $token) {
- global $pdo;
- global $yubi;
- global $u2f;
- global $tfa;
- $stmt = $pdo->prepare("SELECT `authmech` FROM `tfa`
- WHERE `username` = :username AND `active` = '1'");
- $stmt->execute(array(':username' => $username));
- $row = $stmt->fetch(PDO::FETCH_ASSOC);
+function verify_tfa_login($username, $_data, $WebAuthn) {
+ global $pdo;
+ global $yubi;
+ global $u2f;
+ global $tfa;
+ $stmt = $pdo->prepare("SELECT `authmech` FROM `tfa`
+ WHERE `username` = :username AND `active` = '1'");
+ $stmt->execute(array(':username' => $username));
+ $row = $stmt->fetch(PDO::FETCH_ASSOC);
- switch ($row["authmech"]) {
- case "yubi_otp":
- if (!ctype_alnum($token) || strlen($token) != 44) {
- $_SESSION['return'][] = array(
- 'type' => 'danger',
- 'log' => array(__FUNCTION__, $username, '*'),
- 'msg' => array('yotp_verification_failed', 'token length error')
- );
- return false;
- }
- $yubico_modhex_id = substr($token, 0, 12);
- $stmt = $pdo->prepare("SELECT `id`, `secret` FROM `tfa`
- WHERE `username` = :username
- AND `authmech` = 'yubi_otp'
- AND `active`='1'
- AND `secret` LIKE :modhex");
- $stmt->execute(array(':username' => $username, ':modhex' => '%' . $yubico_modhex_id));
- $row = $stmt->fetch(PDO::FETCH_ASSOC);
- $yubico_auth = explode(':', $row['secret']);
- $yubi = new Auth_Yubico($yubico_auth[0], $yubico_auth[1]);
- $yauth = $yubi->verify($token);
- if (PEAR::isError($yauth)) {
- $_SESSION['return'][] = array(
- 'type' => 'danger',
- 'log' => array(__FUNCTION__, $username, '*'),
- 'msg' => array('yotp_verification_failed', $yauth->getMessage())
- );
- return false;
- }
- else {
- $_SESSION['tfa_id'] = $row['id'];
- $_SESSION['return'][] = array(
- 'type' => 'success',
- 'log' => array(__FUNCTION__, $username, '*'),
- 'msg' => 'verified_yotp_login'
- );
- return true;
- }
- $_SESSION['return'][] = array(
- 'type' => 'danger',
- 'log' => array(__FUNCTION__, $username, '*'),
- 'msg' => array('yotp_verification_failed', 'unknown')
- );
- return false;
- break;
- case "u2f":
- try {
- $reg = $u2f->doAuthenticate(json_decode($_SESSION['authReq']), get_u2f_registrations($username), json_decode($token));
- $stmt = $pdo->prepare("SELECT `id` FROM `tfa` WHERE `keyHandle` = ?");
- $stmt->execute(array($reg->keyHandle));
- $row_key_id = $stmt->fetch(PDO::FETCH_ASSOC);
- $_SESSION['tfa_id'] = $row_key_id['id'];
- $_SESSION['authReq'] = null;
- $_SESSION['return'][] = array(
- 'type' => 'success',
- 'log' => array(__FUNCTION__, $username, '*'),
- 'msg' => 'verified_u2f_login'
- );
- return true;
- }
- catch (Exception $e) {
- $_SESSION['return'][] = array(
- 'type' => 'danger',
- 'log' => array(__FUNCTION__, $username, '*'),
- 'msg' => array('u2f_verification_failed', $e->getMessage())
- );
- $_SESSION['regReq'] = null;
- return false;
- }
- $_SESSION['return'][] = array(
- 'type' => 'danger',
- 'log' => array(__FUNCTION__, $username, '*'),
- 'msg' => array('u2f_verification_failed', 'unknown')
- );
- return false;
- break;
- case "hotp":
- return false;
- break;
- case "totp":
- try {
- $stmt = $pdo->prepare("SELECT `id`, `secret` FROM `tfa`
- WHERE `username` = :username
- AND `authmech` = 'totp'
- AND `active`='1'");
- $stmt->execute(array(':username' => $username));
- $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
- foreach ($rows as $row) {
- if ($tfa->verifyCode($row['secret'], $_POST['token']) === true) {
- $_SESSION['tfa_id'] = $row['id'];
- $_SESSION['return'][] = array(
- 'type' => 'success',
+ switch ($row["authmech"]) {
+ case "yubi_otp":
+ if (!ctype_alnum($_data['token']) || strlen($_data['token']) != 44) {
+ $_SESSION['return'][] = array(
+ 'type' => 'danger',
+ 'log' => array(__FUNCTION__, $username, '*'),
+ 'msg' => array('yotp_verification_failed', 'token length error')
+ );
+ return false;
+ }
+ $yubico_modhex_id = substr($_data['token'], 0, 12);
+ $stmt = $pdo->prepare("SELECT `id`, `secret` FROM `tfa`
+ WHERE `username` = :username
+ AND `authmech` = 'yubi_otp'
+ AND `active`='1'
+ AND `secret` LIKE :modhex");
+ $stmt->execute(array(':username' => $username, ':modhex' => '%' . $yubico_modhex_id));
+ $row = $stmt->fetch(PDO::FETCH_ASSOC);
+ $yubico_auth = explode(':', $row['secret']);
+ $yubi = new Auth_Yubico($yubico_auth[0], $yubico_auth[1]);
+ $yauth = $yubi->verify($_data['token']);
+ if (PEAR::isError($yauth)) {
+ $_SESSION['return'][] = array(
+ 'type' => 'danger',
+ 'log' => array(__FUNCTION__, $username, '*'),
+ 'msg' => array('yotp_verification_failed', $yauth->getMessage())
+ );
+ return false;
+ }
+ else {
+ $_SESSION['tfa_id'] = $row['id'];
+ $_SESSION['return'][] = array(
+ 'type' => 'success',
+ 'log' => array(__FUNCTION__, $username, '*'),
+ 'msg' => 'verified_yotp_login'
+ );
+ return true;
+ }
+ $_SESSION['return'][] = array(
+ 'type' => 'danger',
+ 'log' => array(__FUNCTION__, $username, '*'),
+ 'msg' => array('yotp_verification_failed', 'unknown')
+ );
+ return false;
+ break;
+ case "hotp":
+ return false;
+ break;
+ case "totp":
+ try {
+ $stmt = $pdo->prepare("SELECT `id`, `secret` FROM `tfa`
+ WHERE `username` = :username
+ AND `authmech` = 'totp'
+ AND `active`='1'");
+ $stmt->execute(array(':username' => $username));
+ $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
+ foreach ($rows as $row) {
+ if ($tfa->verifyCode($row['secret'], $_data['token']) === true) {
+ $_SESSION['tfa_id'] = $row['id'];
+ $_SESSION['return'][] = array(
+ 'type' => 'success',
+ 'log' => array(__FUNCTION__, $username, '*'),
+ 'msg' => 'verified_totp_login'
+ );
+ return true;
+ }
+ }
+ $_SESSION['return'][] = array(
+ 'type' => 'danger',
+ 'log' => array(__FUNCTION__, $username, '*'),
+ 'msg' => 'totp_verification_failed'
+ );
+ return false;
+ }
+ catch (PDOException $e) {
+ $_SESSION['return'][] = array(
+ 'type' => 'danger',
+ 'log' => array(__FUNCTION__, $username, '*'),
+ 'msg' => array('mysql_error', $e)
+ );
+ return false;
+ }
+ break;
+ // u2f - deprecated, should be removed
+ case "u2f":
+ $tokenData = json_decode($_data['token']);
+ $clientDataJSON = base64_decode($tokenData->clientDataJSON);
+ $authenticatorData = base64_decode($tokenData->authenticatorData);
+ $signature = base64_decode($tokenData->signature);
+ $id = base64_decode($tokenData->id);
+ $challenge = $_SESSION['challenge'];
+
+ $stmt = $pdo->prepare("SELECT `key_id`, `keyHandle`, `username`, `publicKey` FROM `tfa` WHERE `keyHandle` = :tokenId");
+ $stmt->execute(array(':tokenId' => $tokenData->id));
+ $process_webauthn = $stmt->fetch(PDO::FETCH_ASSOC);
+
+ if (empty($process_webauthn) || empty($process_webauthn['publicKey']) || empty($process_webauthn['username'])) return false;
+
+ if ($process_webauthn['publicKey'] === false) {
+ $_SESSION['return'][] = array(
+ 'type' => 'danger',
+ 'log' => array(__FUNCTION__, $username, '*'),
+ 'msg' => array('webauthn_verification_failed', 'publicKey not found')
+ );
+ return false;
+ }
+ try {
+ $WebAuthn->processGet($clientDataJSON, $authenticatorData, $signature, $process_webauthn['publicKey'], $challenge, null, $GLOBALS['WEBAUTHN_UV_FLAG_LOGIN'], $GLOBALS['WEBAUTHN_USER_PRESENT_FLAG']);
+ }
+ catch (Throwable $ex) {
+ $_SESSION['return'][] = array(
+ 'type' => 'danger',
+ 'log' => array(__FUNCTION__, $username, '*'),
+ 'msg' => array('webauthn_verification_failed', $ex->getMessage())
+ );
+ return false;
+ }
+
+
+ $stmt = $pdo->prepare("SELECT `superadmin` FROM `admin` WHERE `username` = :username");
+ $stmt->execute(array(':username' => $process_webauthn['username']));
+ $obj_props = $stmt->fetch(PDO::FETCH_ASSOC);
+ if ($obj_props['superadmin'] === 1) {
+ $_SESSION["mailcow_cc_role"] = "admin";
+ }
+ elseif ($obj_props['superadmin'] === 0) {
+ $_SESSION["mailcow_cc_role"] = "domainadmin";
+ }
+ else {
+ $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `username` = :username");
+ $stmt->execute(array(':username' => $process_webauthn['username']));
+ $row = $stmt->fetch(PDO::FETCH_ASSOC);
+ if ($row['username'] == $process_webauthn['username']) {
+ $_SESSION["mailcow_cc_role"] = "user";
+ }
+ }
+
+
+ if ($process_webauthn['username'] != $_SESSION['pending_mailcow_cc_username']){
+ $_SESSION['return'][] = array(
+ 'type' => 'danger',
+ 'log' => array(__FUNCTION__, $username, '*'),
+ 'msg' => array('webauthn_verification_failed', 'user who requests does not match with sql entry')
+ );
+ return false;
+ }
+
+
+ $_SESSION["mailcow_cc_username"] = $process_webauthn['username'];
+ $_SESSION['tfa_id'] = $process_webauthn['key_id'];
+ $_SESSION['authReq'] = null;
+ unset($_SESSION["challenge"]);
+ $_SESSION['return'][] = array(
+ 'type' => 'success',
+ 'log' => array("webauthn_login"),
+ 'msg' => array('logged_in_as', $process_webauthn['username'])
+ );
+ return true;
+ break;
+ case "webauthn":
+ $tokenData = json_decode($_data['token']);
+ $clientDataJSON = base64_decode($tokenData->clientDataJSON);
+ $authenticatorData = base64_decode($tokenData->authenticatorData);
+ $signature = base64_decode($tokenData->signature);
+ $id = base64_decode($tokenData->id);
+ $challenge = $_SESSION['challenge'];
+
+ $stmt = $pdo->prepare("SELECT `key_id`, `keyHandle`, `username`, `publicKey` FROM `tfa` WHERE `keyHandle` = :tokenId");
+ $stmt->execute(array(':tokenId' => $tokenData->id));
+ $process_webauthn = $stmt->fetch(PDO::FETCH_ASSOC);
+
+ if (empty($process_webauthn) || empty($process_webauthn['publicKey']) || empty($process_webauthn['username'])) return false;
+
+ if ($process_webauthn['publicKey'] === false) {
+ $_SESSION['return'][] = array(
+ 'type' => 'danger',
+ 'log' => array(__FUNCTION__, $username, '*'),
+ 'msg' => array('webauthn_verification_failed', 'publicKey not found')
+ );
+ return false;
+ }
+ try {
+ $WebAuthn->processGet($clientDataJSON, $authenticatorData, $signature, $process_webauthn['publicKey'], $challenge, null, $GLOBALS['WEBAUTHN_UV_FLAG_LOGIN'], $GLOBALS['WEBAUTHN_USER_PRESENT_FLAG']);
+ }
+ catch (Throwable $ex) {
+ $_SESSION['return'][] = array(
+ 'type' => 'danger',
+ 'log' => array(__FUNCTION__, $username, '*'),
+ 'msg' => array('webauthn_verification_failed', $ex->getMessage())
+ );
+ return false;
+ }
+
+
+ $stmt = $pdo->prepare("SELECT `superadmin` FROM `admin` WHERE `username` = :username");
+ $stmt->execute(array(':username' => $process_webauthn['username']));
+ $obj_props = $stmt->fetch(PDO::FETCH_ASSOC);
+ if ($obj_props['superadmin'] === 1) {
+ $_SESSION["mailcow_cc_role"] = "admin";
+ }
+ elseif ($obj_props['superadmin'] === 0) {
+ $_SESSION["mailcow_cc_role"] = "domainadmin";
+ }
+ else {
+ $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `username` = :username");
+ $stmt->execute(array(':username' => $process_webauthn['username']));
+ $row = $stmt->fetch(PDO::FETCH_ASSOC);
+ if ($row['username'] == $process_webauthn['username']) {
+ $_SESSION["mailcow_cc_role"] = "user";
+ }
+ }
+
+
+ if ($process_webauthn['username'] != $_SESSION['pending_mailcow_cc_username']){
+ $_SESSION['return'][] = array(
+ 'type' => 'danger',
+ 'log' => array(__FUNCTION__, $username, '*'),
+ 'msg' => array('webauthn_verification_failed', 'user who requests does not match with sql entry')
+ );
+ return false;
+ }
+
+
+ $_SESSION["mailcow_cc_username"] = $process_webauthn['username'];
+ $_SESSION['tfa_id'] = $process_webauthn['key_id'];
+ $_SESSION['authReq'] = null;
+ unset($_SESSION["challenge"]);
+ $_SESSION['return'][] = array(
+ 'type' => 'success',
+ 'log' => array("webauthn_login"),
+ 'msg' => array('logged_in_as', $process_webauthn['username'])
+ );
+ return true;
+ break;
+ default:
+ $_SESSION['return'][] = array(
+ 'type' => 'danger',
'log' => array(__FUNCTION__, $username, '*'),
- 'msg' => 'verified_totp_login'
- );
- return true;
- }
- }
- $_SESSION['return'][] = array(
- 'type' => 'danger',
- 'log' => array(__FUNCTION__, $username, '*'),
- 'msg' => 'totp_verification_failed'
- );
- return false;
+ 'msg' => 'unknown_tfa_method'
+ );
+ return false;
+ break;
}
- catch (PDOException $e) {
- $_SESSION['return'][] = array(
- 'type' => 'danger',
- 'log' => array(__FUNCTION__, $username, '*'),
- 'msg' => array('mysql_error', $e)
- );
- return false;
- }
- break;
- default:
- $_SESSION['return'][] = array(
- 'type' => 'danger',
- 'log' => array(__FUNCTION__, $username, '*'),
- 'msg' => 'unknown_tfa_method'
- );
+
return false;
- break;
- }
- return false;
}
function admin_api($access, $action, $data = null) {
global $pdo;
@@ -1955,6 +2119,7 @@ function rspamd_ui($action, $data = null) {
break;
}
}
+// u2f - deprecated, should be removed
function get_u2f_registrations($username) {
global $pdo;
$sel = $pdo->prepare("SELECT * FROM `tfa` WHERE `authmech` = 'u2f' AND `username` = ? AND `active` = '1'");
diff --git a/data/web/inc/init_db.inc.php b/data/web/inc/init_db.inc.php
index 60a8ead2..a79c6237 100644
--- a/data/web/inc/init_db.inc.php
+++ b/data/web/inc/init_db.inc.php
@@ -696,7 +696,7 @@ function init_db_schema() {
"id" => "INT NOT NULL AUTO_INCREMENT",
"key_id" => "VARCHAR(255) NOT NULL",
"username" => "VARCHAR(255) NOT NULL",
- "authmech" => "ENUM('yubi_otp', 'u2f', 'hotp', 'totp')",
+ "authmech" => "ENUM('yubi_otp', 'u2f', 'hotp', 'totp', 'webauthn')",
"secret" => "VARCHAR(255) DEFAULT NULL",
"keyHandle" => "VARCHAR(255) DEFAULT NULL",
"publicKey" => "VARCHAR(255) DEFAULT NULL",
diff --git a/data/web/inc/lib/WebAuthn/Attestation/AttestationObject.php b/data/web/inc/lib/WebAuthn/Attestation/AttestationObject.php
index aeb4e201..115d7878 100644
--- a/data/web/inc/lib/WebAuthn/Attestation/AttestationObject.php
+++ b/data/web/inc/lib/WebAuthn/Attestation/AttestationObject.php
@@ -1,9 +1,9 @@
_authenticatorData = new AuthenticatorData($enc['authData']->getBinaryString());
+ $this->_attestationFormatName = $enc['fmt'];
// Format ok?
- if (!in_array($enc['fmt'], $allowedFormats)) {
- throw new WebAuthnException('invalid atttestation format: ' . $enc['fmt'], WebAuthnException::INVALID_DATA);
+ if (!in_array($this->_attestationFormatName, $allowedFormats)) {
+ throw new WebAuthnException('invalid atttestation format: ' . $this->_attestationFormatName, WebAuthnException::INVALID_DATA);
}
- switch ($enc['fmt']) {
+
+ switch ($this->_attestationFormatName) {
case 'android-key': $this->_attestationFormat = new Format\AndroidKey($enc, $this->_authenticatorData); break;
case 'android-safetynet': $this->_attestationFormat = new Format\AndroidSafetyNet($enc, $this->_authenticatorData); break;
case 'apple': $this->_attestationFormat = new Format\Apple($enc, $this->_authenticatorData); break;
@@ -47,6 +50,14 @@ class AttestationObject {
}
}
+ /**
+ * returns the attestation format name
+ * @return string
+ */
+ public function getAttestationFormatName() {
+ return $this->_attestationFormatName;
+ }
+
/**
* returns the attestation public key in PEM format
* @return AuthenticatorData
@@ -72,16 +83,19 @@ class AttestationObject {
$issuer = '';
if ($pem) {
$certInfo = \openssl_x509_parse($pem);
- if (\is_array($certInfo) && \is_array($certInfo['issuer'])) {
- if ($certInfo['issuer']['CN']) {
- $issuer .= \trim($certInfo['issuer']['CN']);
+ if (\is_array($certInfo) && \array_key_exists('issuer', $certInfo) && \is_array($certInfo['issuer'])) {
+
+ $cn = $certInfo['issuer']['CN'] ?? '';
+ $o = $certInfo['issuer']['O'] ?? '';
+ $ou = $certInfo['issuer']['OU'] ?? '';
+
+ if ($cn) {
+ $issuer .= $cn;
}
- if ($certInfo['issuer']['O'] || $certInfo['issuer']['OU']) {
- if ($issuer) {
- $issuer .= ' (' . \trim($certInfo['issuer']['O'] . ' ' . $certInfo['issuer']['OU']) . ')';
- } else {
- $issuer .= \trim($certInfo['issuer']['O'] . ' ' . $certInfo['issuer']['OU']);
- }
+ if ($issuer && ($o || $ou)) {
+ $issuer .= ' (' . trim($o . ' ' . $ou) . ')';
+ } else {
+ $issuer .= trim($o . ' ' . $ou);
}
}
}
@@ -98,16 +112,19 @@ class AttestationObject {
$subject = '';
if ($pem) {
$certInfo = \openssl_x509_parse($pem);
- if (\is_array($certInfo) && \is_array($certInfo['subject'])) {
- if ($certInfo['subject']['CN']) {
- $subject .= \trim($certInfo['subject']['CN']);
+ if (\is_array($certInfo) && \array_key_exists('subject', $certInfo) && \is_array($certInfo['subject'])) {
+
+ $cn = $certInfo['subject']['CN'] ?? '';
+ $o = $certInfo['subject']['O'] ?? '';
+ $ou = $certInfo['subject']['OU'] ?? '';
+
+ if ($cn) {
+ $subject .= $cn;
}
- if ($certInfo['subject']['O'] || $certInfo['subject']['OU']) {
- if ($subject) {
- $subject .= ' (' . \trim($certInfo['subject']['O'] . ' ' . $certInfo['subject']['OU']) . ')';
- } else {
- $subject .= \trim($certInfo['subject']['O'] . ' ' . $certInfo['subject']['OU']);
- }
+ if ($subject && ($o || $ou)) {
+ $subject .= ' (' . trim($o . ' ' . $ou) . ')';
+ } else {
+ $subject .= trim($o . ' ' . $ou);
}
}
}
diff --git a/data/web/inc/lib/WebAuthn/Attestation/AuthenticatorData.php b/data/web/inc/lib/WebAuthn/Attestation/AuthenticatorData.php
index 374d9ab4..1e1212ea 100644
--- a/data/web/inc/lib/WebAuthn/Attestation/AuthenticatorData.php
+++ b/data/web/inc/lib/WebAuthn/Attestation/AuthenticatorData.php
@@ -1,9 +1,9 @@
_attestationObject = $AttestionObject;
$this->_authenticatorData = $authenticatorData;
}
@@ -26,7 +27,7 @@ abstract class FormatBase {
*/
public function __destruct() {
// delete X.509 chain certificate file after use
- if (\is_file($this->_x5c_tempFile)) {
+ if ($this->_x5c_tempFile && \is_file($this->_x5c_tempFile)) {
\unlink($this->_x5c_tempFile);
}
}
@@ -36,7 +37,7 @@ abstract class FormatBase {
* @return string|null
*/
public function getCertificateChain() {
- if (\is_file($this->_x5c_tempFile)) {
+ if ($this->_x5c_tempFile && \is_file($this->_x5c_tempFile)) {
return \file_get_contents($this->_x5c_tempFile);
}
return null;
diff --git a/data/web/inc/lib/WebAuthn/Attestation/Format/None.php b/data/web/inc/lib/WebAuthn/Attestation/Format/None.php
index 1664c559..ba95e40f 100644
--- a/data/web/inc/lib/WebAuthn/Attestation/Format/None.php
+++ b/data/web/inc/lib/WebAuthn/Attestation/Format/None.php
@@ -1,13 +1,14 @@
PHP 7.0
@@ -97,6 +97,14 @@ class ByteBuffer implements \JsonSerializable, \Serializable {
return \ord(\substr($this->_data, $offset, 1));
}
+ public function getJson($jsonFlags=0) {
+ $data = \json_decode($this->getBinaryString(), null, 512, $jsonFlags);
+ if (\json_last_error() !== JSON_ERROR_NONE) {
+ throw new WebAuthnException(\json_last_error_msg(), WebAuthnException::BYTEBUFFER);
+ }
+ return $data;
+ }
+
public function getLength() {
return $this->_length;
}
@@ -203,7 +211,7 @@ class ByteBuffer implements \JsonSerializable, \Serializable {
/**
* jsonSerialize interface
* return binary data in RFC 1342-Like serialized string
- * @return \stdClass
+ * @return string
*/
public function jsonSerialize() {
if (ByteBuffer::$useBase64UrlEncoding) {
@@ -231,6 +239,36 @@ class ByteBuffer implements \JsonSerializable, \Serializable {
$this->_length = \strlen($this->_data);
}
+ /**
+ * (PHP 8 deprecates Serializable-Interface)
+ * @return array
+ */
+ public function __serialize() {
+ return [
+ 'data' => \serialize($this->_data)
+ ];
+ }
+
+ /**
+ * object to string
+ * @return string
+ */
+ public function __toString() {
+ return $this->getHex();
+ }
+
+ /**
+ * (PHP 8 deprecates Serializable-Interface)
+ * @param array $data
+ * @return void
+ */
+ public function __unserialize($data) {
+ if ($data && isset($data['data'])) {
+ $this->_data = \unserialize($data['data']);
+ $this->_length = \strlen($this->_data);
+ }
+ }
+
// -----------------------
// PROTECTED STATIC
// -----------------------
diff --git a/data/web/inc/lib/WebAuthn/CBOR/CborDecoder.php b/data/web/inc/lib/WebAuthn/CBOR/CborDecoder.php
index 45626eb1..e6b5427d 100644
--- a/data/web/inc/lib/WebAuthn/CBOR/CborDecoder.php
+++ b/data/web/inc/lib/WebAuthn/CBOR/CborDecoder.php
@@ -1,9 +1,9 @@
_caFiles)) {
$this->_caFiles = array();
}
+ if ($certFileExtensions === null) {
+ $certFileExtensions = array('pem', 'crt', 'cer', 'der');
+ }
$path = \rtrim(\trim($path), '\\/');
if (\is_dir($path)) {
foreach (\scandir($path) as $ca) {
- if (\is_file($path . '/' . $ca)) {
- $this->addRootCertificates($path . '/' . $ca);
+ if (\is_file($path . DIRECTORY_SEPARATOR . $ca) && \in_array(\strtolower(\pathinfo($ca, PATHINFO_EXTENSION)), $certFileExtensions)) {
+ $this->addRootCertificates($path . DIRECTORY_SEPARATOR . $ca);
}
}
} else if (\is_file($path) && !\in_array(\realpath($path), $this->_caFiles)) {
@@ -273,10 +277,11 @@ class WebAuthn {
* @param string|ByteBuffer $challenge binary used challange
* @param bool $requireUserVerification true, if the device must verify user (e.g. by biometric data or pin)
* @param bool $requireUserPresent false, if the device must NOT check user presence (e.g. by pressing a button)
+ * @param bool $failIfRootMismatch false, if there should be no error thrown if root certificate doesn't match
* @return \stdClass
* @throws WebAuthnException
*/
- public function processCreate($clientDataJSON, $attestationObject, $challenge, $requireUserVerification=false, $requireUserPresent=true) {
+ public function processCreate($clientDataJSON, $attestationObject, $challenge, $requireUserVerification=false, $requireUserPresent=true, $failIfRootMismatch=true) {
$clientDataHash = \hash('sha256', $clientDataJSON, true);
$clientData = \json_decode($clientDataJSON);
$challenge = $challenge instanceof ByteBuffer ? $challenge : new ByteBuffer($challenge);
@@ -318,18 +323,21 @@ class WebAuthn {
}
// 15. If validation is successful, obtain a list of acceptable trust anchors
- if (is_array($this->_caFiles) && !$attestationObject->validateRootCertificate($this->_caFiles)) {
+ $rootValid = is_array($this->_caFiles) ? $attestationObject->validateRootCertificate($this->_caFiles) : null;
+ if ($failIfRootMismatch && is_array($this->_caFiles) && !$rootValid) {
throw new WebAuthnException('invalid root certificate', WebAuthnException::CERTIFICATE_NOT_TRUSTED);
}
// 10. Verify that the User Present bit of the flags in authData is set.
- if ($requireUserPresent && !$attestationObject->getAuthenticatorData()->getUserPresent()) {
+ $userPresent = $attestationObject->getAuthenticatorData()->getUserPresent();
+ if ($requireUserPresent && !$userPresent) {
throw new WebAuthnException('user not present during authentication', WebAuthnException::USER_PRESENT);
}
// 11. If user verification is required for this registration, verify that the User Verified bit of the flags in authData is set.
- if ($requireUserVerification && !$attestationObject->getAuthenticatorData()->getUserVerified()) {
- throw new WebAuthnException('user not verificated during authentication', WebAuthnException::USER_VERIFICATED);
+ $userVerified = $attestationObject->getAuthenticatorData()->getUserVerified();
+ if ($requireUserVerification && !$userVerified) {
+ throw new WebAuthnException('user not verified during authentication', WebAuthnException::USER_VERIFICATED);
}
$signCount = $attestationObject->getAuthenticatorData()->getSignCount();
@@ -340,6 +348,7 @@ class WebAuthn {
// prepare data to store for future logins
$data = new \stdClass();
$data->rpId = $this->_rpId;
+ $data->attestationFormat = $attestationObject->getAttestationFormatName();
$data->credentialId = $attestationObject->getAuthenticatorData()->getCredentialId();
$data->credentialPublicKey = $attestationObject->getAuthenticatorData()->getPublicKeyPem();
$data->certificateChain = $attestationObject->getCertificateChain();
@@ -348,6 +357,9 @@ class WebAuthn {
$data->certificateSubject = $attestationObject->getCertificateSubject();
$data->signatureCounter = $this->_signatureCounter;
$data->AAGUID = $attestationObject->getAuthenticatorData()->getAAGUID();
+ $data->rootValid = $rootValid;
+ $data->userPresent = $userPresent;
+ $data->userVerified = $userVerified;
return $data;
}
@@ -453,6 +465,92 @@ class WebAuthn {
return true;
}
+ /**
+ * Downloads root certificates from FIDO Alliance Metadata Service (MDS) to a specific folder
+ * https://fidoalliance.org/metadata/
+ * @param string $certFolder Folder path to save the certificates in PEM format.
+ * @param bool $deleteCerts=true
+ * @return int number of cetificates
+ * @throws WebAuthnException
+ */
+ public function queryFidoMetaDataService($certFolder, $deleteCerts=true) {
+ $url = 'https://mds.fidoalliance.org/';
+ $raw = null;
+ if (\function_exists('curl_init')) {
+ $ch = \curl_init($url);
+ \curl_setopt($ch, CURLOPT_HEADER, false);
+ \curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ \curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
+ \curl_setopt($ch, CURLOPT_USERAGENT, 'github.com/lbuchs/WebAuthn - A simple PHP WebAuthn server library');
+ $raw = \curl_exec($ch);
+ \curl_close($ch);
+ } else {
+ $raw = \file_get_contents($url);
+ }
+
+ $certFolder = \rtrim(\realpath($certFolder), '\\/');
+ if (!is_dir($certFolder)) {
+ throw new WebAuthnException('Invalid folder path for query FIDO Alliance Metadata Service');
+ }
+
+ if (!\is_string($raw)) {
+ throw new WebAuthnException('Unable to query FIDO Alliance Metadata Service');
+ }
+
+ $jwt = \explode('.', $raw);
+ if (\count($jwt) !== 3) {
+ throw new WebAuthnException('Invalid JWT from FIDO Alliance Metadata Service');
+ }
+
+ if ($deleteCerts) {
+ foreach (\scandir($certFolder) as $ca) {
+ if (\substr($ca, -4) === '.pem') {
+ if (\unlink($certFolder . DIRECTORY_SEPARATOR . $ca) === false) {
+ throw new WebAuthnException('Cannot delete certs in folder for FIDO Alliance Metadata Service');
+ }
+ }
+ }
+ }
+
+ list($header, $payload, $hash) = $jwt;
+ $payload = Binary\ByteBuffer::fromBase64Url($payload)->getJson();
+
+ $count = 0;
+ if (\is_object($payload) && \property_exists($payload, 'entries') && \is_array($payload->entries)) {
+ foreach ($payload->entries as $entry) {
+ if (\is_object($entry) && \property_exists($entry, 'metadataStatement') && \is_object($entry->metadataStatement)) {
+ $description = $entry->metadataStatement->description ?? null;
+ $attestationRootCertificates = $entry->metadataStatement->attestationRootCertificates ?? null;
+
+ if ($description && $attestationRootCertificates) {
+
+ // create filename
+ $certFilename = \preg_replace('/[^a-z0-9]/i', '_', $description);
+ $certFilename = \trim(\preg_replace('/\_{2,}/i', '_', $certFilename),'_') . '.pem';
+ $certFilename = \strtolower($certFilename);
+
+ // add certificate
+ $certContent = $description . "\n";
+ $certContent .= \str_repeat('-', \mb_strlen($description)) . "\n";
+
+ foreach ($attestationRootCertificates as $attestationRootCertificate) {
+ $count++;
+ $certContent .= "\n-----BEGIN CERTIFICATE-----\n";
+ $certContent .= \chunk_split(\trim($attestationRootCertificate), 64, "\n");
+ $certContent .= "-----END CERTIFICATE-----\n";
+ }
+
+ if (\file_put_contents($certFolder . DIRECTORY_SEPARATOR . $certFilename, $certContent) === false) {
+ throw new WebAuthnException('unable to save certificate from FIDO Alliance Metadata Service');
+ }
+ }
+ }
+ }
+ }
+
+ return $count;
+ }
+
// -----------------------------------------------
// PRIVATE
// -----------------------------------------------
diff --git a/data/web/inc/lib/WebAuthn/WebAuthnException.php b/data/web/inc/lib/WebAuthn/WebAuthnException.php
index 823f7d80..e399bd3b 100644
--- a/data/web/inc/lib/WebAuthn/WebAuthnException.php
+++ b/data/web/inc/lib/WebAuthn/WebAuthnException.php
@@ -1,5 +1,5 @@
addRootCertificates($_SERVER['DOCUMENT_ROOT'] . '/inc/lib/WebAuthn/rootCertificates/solo.pem');
-$WebAuthn->addRootCertificates($_SERVER['DOCUMENT_ROOT'] . '/inc/lib/WebAuthn/rootCertificates/apple.pem');
-$WebAuthn->addRootCertificates($_SERVER['DOCUMENT_ROOT'] . '/inc/lib/WebAuthn/rootCertificates/nitro.pem');
-$WebAuthn->addRootCertificates($_SERVER['DOCUMENT_ROOT'] . '/inc/lib/WebAuthn/rootCertificates/yubico.pem');
-$WebAuthn->addRootCertificates($_SERVER['DOCUMENT_ROOT'] . '/inc/lib/WebAuthn/rootCertificates/hypersecu.pem');
-$WebAuthn->addRootCertificates($_SERVER['DOCUMENT_ROOT'] . '/inc/lib/WebAuthn/rootCertificates/globalSign.pem');
-$WebAuthn->addRootCertificates($_SERVER['DOCUMENT_ROOT'] . '/inc/lib/WebAuthn/rootCertificates/googleHardware.pem');
-$WebAuthn->addRootCertificates($_SERVER['DOCUMENT_ROOT'] . '/inc/lib/WebAuthn/rootCertificates/microsoftTpmCollection.pem');
-$WebAuthn->addRootCertificates($_SERVER['DOCUMENT_ROOT'] . '/inc/lib/WebAuthn/rootCertificates/huawei.pem');
-$WebAuthn->addRootCertificates($_SERVER['DOCUMENT_ROOT'] . '/inc/lib/WebAuthn/rootCertificates/trustkey.pem');
-$WebAuthn->addRootCertificates($_SERVER['DOCUMENT_ROOT'] . '/inc/lib/WebAuthn/rootCertificates/bsi.pem');
+$WebAuthn = new lbuchs\WebAuthn\WebAuthn('WebAuthn Library', $_SERVER['HTTP_HOST'], $formats);
+// only include root ca's when dev mode is false, to support testing with chromiums virutal authenticator
+if (!$DEV_MODE){
+ $WebAuthn->addRootCertificates($_SERVER['DOCUMENT_ROOT'] . '/inc/lib/WebAuthn/rootCertificates/solo.pem');
+ $WebAuthn->addRootCertificates($_SERVER['DOCUMENT_ROOT'] . '/inc/lib/WebAuthn/rootCertificates/apple.pem');
+ $WebAuthn->addRootCertificates($_SERVER['DOCUMENT_ROOT'] . '/inc/lib/WebAuthn/rootCertificates/nitro.pem');
+ $WebAuthn->addRootCertificates($_SERVER['DOCUMENT_ROOT'] . '/inc/lib/WebAuthn/rootCertificates/yubico.pem');
+ $WebAuthn->addRootCertificates($_SERVER['DOCUMENT_ROOT'] . '/inc/lib/WebAuthn/rootCertificates/hypersecu.pem');
+ $WebAuthn->addRootCertificates($_SERVER['DOCUMENT_ROOT'] . '/inc/lib/WebAuthn/rootCertificates/globalSign.pem');
+ $WebAuthn->addRootCertificates($_SERVER['DOCUMENT_ROOT'] . '/inc/lib/WebAuthn/rootCertificates/googleHardware.pem');
+ $WebAuthn->addRootCertificates($_SERVER['DOCUMENT_ROOT'] . '/inc/lib/WebAuthn/rootCertificates/microsoftTpmCollection.pem');
+ $WebAuthn->addRootCertificates($_SERVER['DOCUMENT_ROOT'] . '/inc/lib/WebAuthn/rootCertificates/huawei.pem');
+ $WebAuthn->addRootCertificates($_SERVER['DOCUMENT_ROOT'] . '/inc/lib/WebAuthn/rootCertificates/trustkey.pem');
+ $WebAuthn->addRootCertificates($_SERVER['DOCUMENT_ROOT'] . '/inc/lib/WebAuthn/rootCertificates/bsi.pem');
+}
// Redis
$redis = new Redis();
diff --git a/data/web/inc/triggers.inc.php b/data/web/inc/triggers.inc.php
index a2342dfc..cb3a3771 100644
--- a/data/web/inc/triggers.inc.php
+++ b/data/web/inc/triggers.inc.php
@@ -1,15 +1,28 @@
array(
diff --git a/data/web/json_api.php b/data/web/json_api.php
index 595bd8f9..e04fe549 100644
--- a/data/web/json_api.php
+++ b/data/web/json_api.php
@@ -117,12 +117,12 @@ if (isset($_GET['query'])) {
echo isset($_SESSION['return']) ? json_encode($_SESSION['return']) : $generic_success;
}
}
- if (!isset($_POST['attr']) && $category != "fido2-registration") {
+ if (!isset($_POST['attr']) && $category != "fido2-registration" && $category != "webauthn-tfa-registration") {
echo $request_incomplete;
exit;
}
else {
- if ($category != "fido2-registration") {
+ if ($category != "fido2-registration" && $category != "webauthn-tfa-registration") {
$attr = (array)json_decode($_POST['attr'], true);
}
unset($attr['csrf_token']);
@@ -170,6 +170,48 @@ if (isset($_GET['query'])) {
exit;
}
break;
+ case "webauthn-tfa-registration":
+ if (isset($_SESSION["mailcow_cc_role"])) {
+ // parse post data
+ $post = trim(file_get_contents('php://input'));
+ if ($post) $post = json_decode($post);
+
+ // decode base64 strings
+ $clientDataJSON = base64_decode($post->clientDataJSON);
+ $attestationObject = base64_decode($post->attestationObject);
+
+ // process registration data from authenticator
+ try {
+ // processCreate($clientDataJSON, $attestationObject, $challenge, $requireUserVerification=false, $requireUserPresent=true, $failIfRootMismatch=true)
+ $data = $WebAuthn->processCreate($clientDataJSON, $attestationObject, $_SESSION['challenge'], false, true);
+ }
+ catch (Throwable $ex) {
+ // err
+ $return = new stdClass();
+ $return->success = false;
+ $return->msg = $ex->getMessage();
+ echo json_encode($return);
+ exit;
+ }
+
+ // safe authenticator in mysql `tfa` table
+ $_data['tfa_method'] = $post->tfa_method;
+ $_data['key_id'] = $post->key_id;
+ $_data['registration'] = $data;
+ set_tfa($_data);
+
+ // send response
+ $return = new stdClass();
+ $return->success = true;
+ echo json_encode($return);
+ exit;
+ }
+ else {
+ // err - request incomplete
+ echo $request_incomplete;
+ exit;
+ }
+ break;
case "time_limited_alias":
process_add_return(mailbox('add', 'time_limited_alias', $attr));
break;
@@ -350,6 +392,7 @@ if (isset($_GET['query'])) {
exit();
}
switch ($category) {
+ // u2f - deprecated, should be removed
case "u2f-registration":
header('Content-Type: application/javascript');
if (isset($_SESSION["mailcow_cc_role"]) && $_SESSION["mailcow_cc_username"] == $object) {
@@ -366,21 +409,6 @@ if (isset($_GET['query'])) {
return;
}
break;
- // fido2-registration via GET
- case "fido2-registration":
- header('Content-Type: application/json');
- if (isset($_SESSION["mailcow_cc_role"])) {
- // Exclude existing CredentialIds, if any
- $excludeCredentialIds = fido2(array("action" => "get_user_cids"));
- $createArgs = $WebAuthn->getCreateArgs($_SESSION["mailcow_cc_username"], $_SESSION["mailcow_cc_username"], $_SESSION["mailcow_cc_username"], 30, true, $GLOBALS['FIDO2_UV_FLAG_REGISTER'], $excludeCredentialIds);
- print(json_encode($createArgs));
- $_SESSION['challenge'] = $WebAuthn->getChallenge();
- return;
- }
- else {
- return;
- }
- break;
case "u2f-authentication":
header('Content-Type: application/javascript');
if (isset($_SESSION['pending_mailcow_cc_username']) && $_SESSION['pending_mailcow_cc_username'] == $object) {
@@ -403,6 +431,21 @@ if (isset($_GET['query'])) {
return;
}
break;
+ // fido2
+ case "fido2-registration":
+ header('Content-Type: application/json');
+ if (isset($_SESSION["mailcow_cc_role"])) {
+ // Exclude existing CredentialIds, if any
+ $excludeCredentialIds = fido2(array("action" => "get_user_cids"));
+ $createArgs = $WebAuthn->getCreateArgs($_SESSION["mailcow_cc_username"], $_SESSION["mailcow_cc_username"], $_SESSION["mailcow_cc_username"], 30, true, $GLOBALS['FIDO2_UV_FLAG_REGISTER'], $excludeCredentialIds);
+ print(json_encode($createArgs));
+ $_SESSION['challenge'] = $WebAuthn->getChallenge();
+ return;
+ }
+ else {
+ return;
+ }
+ break;
case "fido2-get-args":
header('Content-Type: application/json');
// Login without username, no ids!
@@ -416,6 +459,36 @@ if (isset($_GET['query'])) {
$_SESSION['challenge'] = $WebAuthn->getChallenge();
return;
break;
+ // webauthn two factor authentication
+ case "webauthn-tfa-registration":
+ if (isset($_SESSION["mailcow_cc_role"])) {
+ $excludeCredentialIds = null;
+
+ $createArgs = $WebAuthn->getCreateArgs($_SESSION["mailcow_cc_username"], $_SESSION["mailcow_cc_username"], $_SESSION["mailcow_cc_username"], 30, false, $GLOBALS['WEBAUTHN_UV_FLAG_REGISTER'], true);
+
+ print(json_encode($createArgs));
+ $_SESSION['challenge'] = $WebAuthn->getChallenge();
+ return;
+
+ }
+ else {
+ return;
+ }
+ break;
+ case "webauthn-tfa-get-args":
+ $stmt = $pdo->prepare("SELECT `keyHandle` FROM `tfa` WHERE username = :username");
+ $stmt->execute(array(':username' => $_SESSION['pending_mailcow_cc_username']));
+ $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
+ while($row = array_shift($rows)) {
+ $cids[] = base64_decode($row['keyHandle']);
+ }
+
+ $getArgs = $WebAuthn->getGetArgs($cids, 30, true, true, true, true, $GLOBALS['WEBAUTHN_UV_FLAG_LOGIN']);
+ $getArgs->publicKey->extensions = array('appid' => "https://".$getArgs->publicKey->rpId);
+ print(json_encode($getArgs));
+ $_SESSION['challenge'] = $WebAuthn->getChallenge();
+ return;
+ break;
}
if (isset($_SESSION['mailcow_cc_role'])) {
switch ($category) {
diff --git a/data/web/lang/lang.ca.json b/data/web/lang/lang.ca.json
index d75c83b1..88bbcef1 100644
--- a/data/web/lang/lang.ca.json
+++ b/data/web/lang/lang.ca.json
@@ -443,9 +443,9 @@
"set_tfa": "Definir el mètode d'autenticació de dos factors",
"tfa": "Autenticació de dos factors",
"totp": "OTP basat en temps (Google Authenticator etc.)",
- "u2f": "Autenticació U2F",
- "waiting_usb_auth": "Esperant el dispositiu USB...
Apreta el botó del teu dispositiu USB U2F ara.",
- "waiting_usb_register": "Esperant el dispositiu USB...
Posa el teu password i confirma el registre del teu U2F apretant el botó del teu dispositiiu USB U2F.",
+ "webauthn": "Autenticació WebAuthn",
+ "waiting_usb_auth": "Esperant el dispositiu USB...
Apreta el botó del teu dispositiu USB WebAuthn ara.",
+ "waiting_usb_register": "Esperant el dispositiu USB...
Posa el teu password i confirma el registre del teu WebAuthn apretant el botó del teu dispositiiu USB WebAuthn.",
"yubi_otp": "Autenticació OTP de Yubico"
},
"user": {
diff --git a/data/web/lang/lang.cs.json b/data/web/lang/lang.cs.json
index 5d82a007..5021dec4 100644
--- a/data/web/lang/lang.cs.json
+++ b/data/web/lang/lang.cs.json
@@ -454,7 +454,7 @@
"tls_policy_map_parameter_invalid": "Parametr pravidel TLS je neplatný",
"totp_verification_failed": "TOTP ověření selhalo",
"transport_dest_exists": "Transportní cíl \"%s\" již existuje",
- "u2f_verification_failed": "U2F ověření selhalo: %s",
+ "webauthn": "WebAuthn ověření selhalo: %s",
"unknown": "Došlo k neznámé chybě",
"unknown_tfa_method": "Neznámá 2FA metoda",
"unlimited_quota_acl": "Neomeznou kvótu nepovoluje seznam oprávnění ACL",
@@ -972,7 +972,7 @@
"upload_success": "Soubor úspěšně nahrán",
"verified_fido2_login": "Ověřené FIDO2 přihlášení",
"verified_totp_login": "TOTP přihlášení ověřeno",
- "verified_u2f_login": "U2F přihlášení ověřeno",
+ "webauthn": "WebAuthn přihlášení ověřeno",
"verified_yotp_login": "Yubico OTP přihlášení ověřeno"
},
"tfa": {
@@ -983,7 +983,7 @@
"disable_tfa": "Zakázat 2FA do příštího úspěšného přihlášení",
"enter_qr_code": "Kód TOTP, pokud zařízení neumí číst QR kódy",
"error_code": "Kód chyby",
- "init_u2f": "Probíhá inicializace, čekejte...",
+ "init_webauthn": "Probíhá inicializace, čekejte...",
"key_id": "Identifikátor YubiKey",
"key_id_totp": "Identifikátor klíče",
"none": "Deaktivovat",
@@ -991,13 +991,13 @@
"scan_qr_code": "Prosím načtěte následující kód svou aplikací na ověření nebo zadejte kód ručně.",
"select": "Prosím vyberte...",
"set_tfa": "Nastavení způsobu dvoufaktorového ověření",
- "start_u2f_validation": "Zahájit inicializaci",
+ "start_webauthn_validation": "Zahájit inicializaci",
"tfa": "Dvoufaktorové ověření (TFA)",
"tfa_token_invalid": "Neplatný TFA token",
"totp": "Časově založené OTP (Google Authenticator, Authy apod.)",
- "u2f": "U2F ověření",
- "waiting_usb_auth": "Čeká se na USB zařízení...
Prosím stiskněte tlačítko na svém U2F USB zařízení.",
- "waiting_usb_register": "Čeká se na USB zařízení...
Prosím zadejte své heslo výše a potvrďte U2F registraci stiskem tlačítka na svém U2F USB zařízení.",
+ "webauthn": "WebAuthn ověření",
+ "waiting_usb_auth": "Čeká se na USB zařízení...
Prosím stiskněte tlačítko na svém WebAuthn USB zařízení.",
+ "waiting_usb_register": "Čeká se na USB zařízení...
Prosím zadejte své heslo výše a potvrďte WebAuthn registraci stiskem tlačítka na svém WebAuthn USB zařízení.",
"yubi_otp": "Yubico OTP ověření"
},
"user": {
diff --git a/data/web/lang/lang.da.json b/data/web/lang/lang.da.json
index 7c23e323..fc03ec5c 100644
--- a/data/web/lang/lang.da.json
+++ b/data/web/lang/lang.da.json
@@ -426,7 +426,7 @@
"tls_policy_map_parameter_invalid": "Politikparameter er ugyldig",
"totp_verification_failed": "Bekræftelse af TOTP mislykkedes",
"transport_dest_exists": "Transport destination \"%s\" eksisterer",
- "u2f_verification_failed": "U2F-bekræftelse mislykkedes: %s",
+ "webauthn_verification_failed": "WebAuthn-bekræftelse mislykkedes: %s",
"fido2_verification_failed": "Bekræftelse af FIDO2 mislykkedes: %s",
"unknown": "Der opstod en ukendt fejl",
"unknown_tfa_method": "Ukendt TFA-metode",
@@ -881,7 +881,7 @@
"ui_texts": "Gemte ændringer til UI-tekster",
"upload_success": "Filen blev uploadet",
"verified_totp_login": "Bekræftet TOTP-login",
- "verified_u2f_login": "Bekræftet U2F-login",
+ "verified_webauthn_login": "Bekræftet WebAuthn-login",
"verified_fido2_login": "Bekræftet FIDO2-login",
"verified_yotp_login": "Bekræftet Yubico OTP-login"
},
@@ -893,7 +893,7 @@
"disable_tfa": "Deaktiver TFA indtil næste vellykkede login",
"enter_qr_code": "Din TOTP kode hvis din enhed ikke kan scanne QR-koder",
"error_code": "Fejl kode",
- "init_u2f": "Initialiserer, vent venligst...",
+ "init_webauthn": "Initialiserer, vent venligst...",
"key_id": "En identifikator til din YubiKey",
"key_id_totp": "En identifikator for din nøgle",
"none": "Deaktivere",
@@ -901,11 +901,11 @@
"scan_qr_code": "Scan venligst følgende kode med din godkendelsesapp, eller indtast koden manuelt.",
"select": "Vælg venligst",
"set_tfa": "Set 2-faktor godkendelses metoden",
- "start_u2f_validation": "Start validering",
+ "start_webauthn_validation": "Start validering",
"tfa": "2-faktor godkendelse",
"tfa_token_invalid": "TFA nøgle ugyldig",
"totp": "Tids-baseret OTP (Google Authenticator, Authy, etc.)",
- "u2f": "U2F godkendelse",
+ "webauthn": "WebAuthn godkendelse",
"waiting_usb_auth": "Venter på USB-enhed...
Tryk let på knappen på din USB-enhed nu.",
"waiting_usb_register": "Venter på USB-enhed...
Indtast din adgangskode ovenfor, og bekræft din registrering ved at trykke på knappen på din USB-enhed.",
"yubi_otp": "Yubico OTP godkendelse"
diff --git a/data/web/lang/lang.de.json b/data/web/lang/lang.de.json
index c94eb31b..6f928c0b 100644
--- a/data/web/lang/lang.de.json
+++ b/data/web/lang/lang.de.json
@@ -455,7 +455,7 @@
"tls_policy_map_parameter_invalid": "Parameter ist ungültig",
"totp_verification_failed": "TOTP-Verifizierung fehlgeschlagen",
"transport_dest_exists": "Transport-Maps-Ziel \"%s\" existiert bereits",
- "u2f_verification_failed": "U2F-Verifizierung fehlgeschlagen: %s",
+ "webauthn_verification_failed": "WebAuthn-Verifizierung fehlgeschlagen: %s",
"unknown": "Ein unbekannter Fehler trat auf",
"unknown_tfa_method": "Unbekannte TFA-Methode",
"unlimited_quota_acl": "Unendliche Quota untersagt durch ACL",
@@ -971,7 +971,7 @@
"upload_success": "Datei wurde erfolgreich hochgeladen",
"verified_fido2_login": "FIDO2-Anmeldung verifiziert",
"verified_totp_login": "TOTP-Anmeldung verifiziert",
- "verified_u2f_login": "U2F-Anmeldung verifiziert",
+ "verified_webauthn_login": "WebAuthn-Anmeldung verifiziert",
"verified_yotp_login": "Yubico-OTP-Anmeldung verifiziert"
},
"tfa": {
@@ -982,7 +982,7 @@
"disable_tfa": "Deaktiviere 2FA bis zur nächsten erfolgreichen Anmeldung",
"enter_qr_code": "Falls Sie den angezeigten QR-Code nicht scannen können, verwenden Sie bitte nachstehenden Sicherheitsschlüssel",
"error_code": "Fehlercode",
- "init_u2f": "Initialisiere, bitte warten...",
+ "init_webauthn": "Initialisiere, bitte warten...",
"key_id": "Ein Namen für diesen YubiKey",
"key_id_totp": "Ein eindeutiger Name",
"none": "Deaktiviert",
@@ -990,11 +990,11 @@
"scan_qr_code": "Bitte scannen Sie jetzt den angezeigten QR-Code:",
"select": "Bitte auswählen",
"set_tfa": "Konfiguriere Zwei-Faktor-Authentifizierungsmethode",
- "start_u2f_validation": "Starte Validierung",
+ "start_webauthn_validation": "Starte Validierung",
"tfa": "Zwei-Faktor-Authentifizierung",
"tfa_token_invalid": "TFA-Token ungültig!",
"totp": "Time-based-OTP (Google Authenticator etc.)",
- "u2f": "U2F-Authentifizierung",
+ "webauthn": "WebAuthn-Authentifizierung",
"waiting_usb_auth": "Warte auf USB-Gerät...
Bitte jetzt den vorgesehenen Taster des USB-Gerätes berühren.",
"waiting_usb_register": "Warte auf USB-Gerät...
Bitte zuerst das obere Passwortfeld ausfüllen und erst dann den vorgesehenen Taster des USB-Gerätes berühren.",
"yubi_otp": "Yubico OTP-Authentifizierung"
diff --git a/data/web/lang/lang.en.json b/data/web/lang/lang.en.json
index aae79c70..4c26ee0c 100644
--- a/data/web/lang/lang.en.json
+++ b/data/web/lang/lang.en.json
@@ -455,7 +455,7 @@
"tls_policy_map_parameter_invalid": "Policy parameter is invalid",
"totp_verification_failed": "TOTP verification failed",
"transport_dest_exists": "Transport destination \"%s\" exists",
- "u2f_verification_failed": "U2F verification failed: %s",
+ "webauthn_verification_failed": "WebAuthn verification failed: %s",
"unknown": "An unknown error occurred",
"unknown_tfa_method": "Unknown TFA method",
"unlimited_quota_acl": "Unlimited quota prohibited by ACL",
@@ -978,7 +978,7 @@
"upload_success": "File uploaded successfully",
"verified_fido2_login": "Verified FIDO2 login",
"verified_totp_login": "Verified TOTP login",
- "verified_u2f_login": "Verified U2F login",
+ "verified_webauthn_login": "Verified WebAuthn login",
"verified_yotp_login": "Verified Yubico OTP login"
},
"tfa": {
@@ -989,7 +989,7 @@
"disable_tfa": "Disable TFA until next successful login",
"enter_qr_code": "Your TOTP code if your device cannot scan QR codes",
"error_code": "Error code",
- "init_u2f": "Initializing, please wait...",
+ "init_webauthn": "Initializing, please wait...",
"key_id": "An identifier for your YubiKey",
"key_id_totp": "An identifier for your key",
"none": "Deactivate",
@@ -997,11 +997,11 @@
"scan_qr_code": "Please scan the following code with your authenticator app or enter the code manually.",
"select": "Please select",
"set_tfa": "Set two-factor authentication method",
- "start_u2f_validation": "Start validation",
+ "start_webauthn_validation": "Start validation",
"tfa": "Two-factor authentication",
"tfa_token_invalid": "TFA token invalid",
"totp": "Time-based OTP (Google Authenticator, Authy, etc.)",
- "u2f": "U2F authentication",
+ "webauthn": "WebAuthn authentication",
"waiting_usb_auth": "Waiting for USB device...
Please tap the button on your USB device now.",
"waiting_usb_register": "Waiting for USB device...
Please enter your password above and confirm your registration by tapping the button on your USB device.",
"yubi_otp": "Yubico OTP authentication"
diff --git a/data/web/lang/lang.es.json b/data/web/lang/lang.es.json
index 1e269650..87be8b4d 100644
--- a/data/web/lang/lang.es.json
+++ b/data/web/lang/lang.es.json
@@ -323,7 +323,7 @@
"tls_policy_map_parameter_invalid": "El parámetro de póliza no es válido.",
"totp_verification_failed": "Verificación TOTP fallida",
"transport_dest_exists": "Destino de la regla de transporte ya existe",
- "u2f_verification_failed": "Verificación U2F fallida: %s",
+ "webauthn_verification_failed": "Verificación WebAuthn fallida: %s",
"unknown": "Se produjo un error desconocido",
"unknown_tfa_method": "Método TFA desconocido",
"unlimited_quota_acl": "Cuota ilimitada restringida por controles administrativos",
@@ -649,7 +649,7 @@
"tls_policy_map_entry_deleted": "Regla de póliza de TLS con ID %s ha sido elimindada",
"tls_policy_map_entry_saved": "Regla de póliza de TLS \"%s\" ha sido guardada",
"verified_totp_login": "Inicio de sesión TOTP verificado",
- "verified_u2f_login": "Inicio de sesión U2F verificado",
+ "verified_webauthn_login": "Inicio de sesión WebAuthn verificado",
"verified_yotp_login": "Inicio de sesión Yubico OTP verificado"
},
"tfa": {
@@ -667,9 +667,9 @@
"set_tfa": "Establecer el método de autenticación de dos factores",
"tfa": "Autenticación de dos factores",
"totp": "OTP basado en tiempo (Google Authenticator, Authy, etc.)",
- "u2f": "Autenticación U2F",
- "waiting_usb_auth": "Esperando al dispositivo USB...
Toque el botón en su dispositivo USB U2F ahora.",
- "waiting_usb_register": "Esperando al dispositivo USB....
Ingrese su contraseña arriba y confirme su registro U2F tocando el botón en su dispositivo USB U2F.",
+ "webauthn": "Autenticación WebAuthn",
+ "waiting_usb_auth": "Esperando al dispositivo USB...
Toque el botón en su dispositivo USB WebAuthn ahora.",
+ "waiting_usb_register": "Esperando al dispositivo USB....
Ingrese su contraseña arriba y confirme su registro WebAuthn tocando el botón en su dispositivo USB WebAuthn.",
"yubi_otp": "Yubico OTP"
},
"user": {
diff --git a/data/web/lang/lang.fi.json b/data/web/lang/lang.fi.json
index 950d3a62..66e279e2 100644
--- a/data/web/lang/lang.fi.json
+++ b/data/web/lang/lang.fi.json
@@ -370,7 +370,7 @@
"tls_policy_map_parameter_invalid": "Käytäntö parametri ei kelpaa",
"totp_verification_failed": "TOTP-vahvistus epäonnistui",
"transport_dest_exists": "Kuljetuksen määränpää \"%s\" olemassa",
- "u2f_verification_failed": "U2F vahvistaminen epäonnistui: %s",
+ "webauthn_verification_failed": "WebAuthn vahvistaminen epäonnistui: %s",
"unknown": "Ilmeni tuntematon virhe",
"unknown_tfa_method": "Tuntematon TFA-menetelmä",
"unlimited_quota_acl": "Rajoittamaton kiintiö kielletty ACL",
@@ -754,7 +754,7 @@
"ui_texts": "Tallennettu käyttöliittymätekstien muutokset",
"upload_success": "Tiedosto ladattu onnistuneesti",
"verified_totp_login": "Vahvistettu TOTP-kirjautuminen",
- "verified_u2f_login": "Vahvistettu U2F kirjautuminen",
+ "verified_webauthn_login": "Vahvistettu WebAuthn kirjautuminen",
"verified_yotp_login": "Vahvistettu Yubico OTP kirjautuminen"
},
"tfa": {
@@ -765,7 +765,7 @@
"disable_tfa": "Poista TFA käytöstä seuraavaan onnistuneen kirjautumisen jälkeen",
"enter_qr_code": "TOTP-koodisi, jos laitteesi ei pysty tarkistamaan QR-koodeja",
"error_code": "Virhekoodi",
- "init_u2f": "Alustetaan, odota...",
+ "init_webauthn": "Alustetaan, odota...",
"key_id": "Tunniste YubiKey",
"key_id_totp": "Avaimen tunnus",
"none": "Poista",
@@ -773,12 +773,12 @@
"scan_qr_code": "Tarkista seuraava koodi Authenticator-sovelluksella tai Syötä koodi manuaalisesti.",
"select": "Valitse",
"set_tfa": "Määritä kaksiosainen todennus menetelmä",
- "start_u2f_validation": "Aloita oikeellisuus tarkistus",
+ "start_webauthn_validation": "Aloita oikeellisuus tarkistus",
"tfa": "Kaksiosainen todennus",
"totp": "Aikapohjainen OTP (Google Authenticator, Authy jne.)",
- "u2f": "U2F todennus",
- "waiting_usb_auth": "Odotetaan USB-laitetta...
Napauta painiketta U2F USB-laitteessa nyt",
- "waiting_usb_register": "Odotetaan USB-laitetta...
Anna salasanasi yltä ja vahvista U2F-rekisteröinti napauttamalla painiketta U2F USB-laitteessa.",
+ "webauthn": "WebAuthn todennus",
+ "waiting_usb_auth": "Odotetaan USB-laitetta...
Napauta painiketta WebAuthn USB-laitteessa nyt",
+ "waiting_usb_register": "Odotetaan USB-laitetta...
Anna salasanasi yltä ja vahvista WebAuthn-rekisteröinti napauttamalla painiketta WebAuthn USB-laitteessa.",
"yubi_otp": "Yubico OTP-todennus"
},
"user": {
diff --git a/data/web/lang/lang.fr.json b/data/web/lang/lang.fr.json
index e0750c5e..1b5c4233 100644
--- a/data/web/lang/lang.fr.json
+++ b/data/web/lang/lang.fr.json
@@ -430,7 +430,7 @@
"tls_policy_map_parameter_invalid": "Le paramètre Policy est invalide",
"totp_verification_failed": "Echec de la vérification TOTP",
"transport_dest_exists": "La destination de transport \"%s\" existe",
- "u2f_verification_failed": "Echec de la vérification U2F: %s",
+ "webauthn_verification_failed": "Echec de la vérification WebAuthn: %s",
"fido2_verification_failed": "La vérification FIDO2 a échoué: %s",
"unknown": "Une erreur inconnue est survenue",
"unknown_tfa_method": "Methode TFA inconnue",
@@ -895,7 +895,7 @@
"ui_texts": "Enregistrement des modifications apportées aux textes de l’interface utilisateur",
"upload_success": "Fichier téléchargé avec succès",
"verified_totp_login": "Authentification TOTP vérifiée",
- "verified_u2f_login": "Authentification U2F vérifiée",
+ "verified_webauthn_login": "Authentification WebAuthn vérifiée",
"verified_fido2_login": "Authentification FIDO2 vérifiée",
"verified_yotp_login": "Authentification Yubico OTP vérifiée"
},
@@ -907,7 +907,7 @@
"disable_tfa": "Désactiver TFA jusqu’à la prochaine ouverture de session réussie",
"enter_qr_code": "Votre code TOTP si votre appareil ne peut pas scanner les codes QR",
"error_code": "Code d'erreur",
- "init_u2f": "Initialisation, veuillez patienter...",
+ "init_webauthn": "Initialisation, veuillez patienter...",
"key_id": "Un identifiant pour votre Yubikey",
"key_id_totp": "Un identifiant pour votre clé",
"none": "Désactiver",
@@ -915,13 +915,13 @@
"scan_qr_code": "Veuillez scanner le code suivant avec votre application d’authentification ou entrer le code manuellement.",
"select": "Veuillez sélectionner",
"set_tfa": "Définir une méthode d’authentification à deux facteurs",
- "start_u2f_validation": "Début de la validation",
+ "start_webauthn_validation": "Début de la validation",
"tfa": "Authentification à deux facteurs",
"tfa_token_invalid": "Token TFA invalide",
"totp": "OTP (One Time Password = Mot de passe à usage unique : Google Authenticator, Authy, etc.)",
- "u2f": "Authentification U2F",
- "waiting_usb_auth": "En attente d’un périphérique USB...
S’il vous plaît appuyez maintenant sur le bouton de votre périphérique USB U2F.",
- "waiting_usb_register": "En attente d’un périphérique USB...
Veuillez entrer votre mot de passe ci-dessus et confirmer votre inscription U2F en appuyant sur le bouton de votre périphérique USB U2F.",
+ "webauthn": "Authentification WebAuthn",
+ "waiting_usb_auth": "En attente d’un périphérique USB...
S’il vous plaît appuyez maintenant sur le bouton de votre périphérique USB WebAuthn.",
+ "waiting_usb_register": "En attente d’un périphérique USB...
Veuillez entrer votre mot de passe ci-dessus et confirmer votre inscription WebAuthn en appuyant sur le bouton de votre périphérique USB WebAuthn.",
"yubi_otp": "Authentification OTP Yubico"
},
"fido2": {
diff --git a/data/web/lang/lang.it.json b/data/web/lang/lang.it.json
index 496c0d71..70786eea 100644
--- a/data/web/lang/lang.it.json
+++ b/data/web/lang/lang.it.json
@@ -449,7 +449,7 @@
"tls_policy_map_parameter_invalid": "Policy parameter is invalid",
"totp_verification_failed": "TOTP verification failed",
"transport_dest_exists": "Transport destination \"%s\" exists",
- "u2f_verification_failed": "U2F verification failed: %s",
+ "webauthn_verification_failed": "WebAuthn verification failed: %s",
"unknown": "An unknown error occurred",
"unknown_tfa_method": "Unknown TFA method",
"unlimited_quota_acl": "Unlimited quota prohibited by ACL",
@@ -947,7 +947,7 @@
"upload_success": "File caricato con successo",
"verified_fido2_login": "Verified FIDO2 login",
"verified_totp_login": "Verified TOTP login",
- "verified_u2f_login": "Verified U2F login",
+ "verified_webauthn_login": "Verified WebAuthn login",
"verified_yotp_login": "Verified Yubico OTP login"
},
"tfa": {
@@ -958,7 +958,7 @@
"disable_tfa": "Disabilita TFA fino al prossimo accesso",
"enter_qr_code": "Il codice TOTP se il tuo dispositivo non è in grado di acquisire i codici QR",
"error_code": "Codice di errore",
- "init_u2f": "Inizializzazione, attendere prego...",
+ "init_webauthn": "Inizializzazione, attendere prego...",
"key_id": "Identificatore per il tuo YubiKey",
"key_id_totp": "Identificatore per la tua chiave",
"none": "Disattivato",
@@ -966,12 +966,12 @@
"scan_qr_code": "Esegui la scansione del seguente codice con l'applicazione di autenticazione o inserisci manualmente il codice.",
"select": "Seleziona",
"set_tfa": "Imposta il metodo di autenticazione a due fattori",
- "start_u2f_validation": "Avvia convalida",
+ "start_webauthn_validation": "Avvia convalida",
"tfa": "Autenticazione a due fattori",
"totp": "Time-based OTP (Google Authenticator etc.)",
- "u2f": "Autenticazione U2F",
- "waiting_usb_auth": "In attesa del device USB...
Tocca ora il pulsante sul dispositivo U2F USB.",
- "waiting_usb_register": "In attesa del device USB...
Inserisci la tua password qui sopra e conferma la tua registrazione U2F toccando il pulsante del dispositivo U2F USB.",
+ "webauthn": "Autenticazione WebAuthn",
+ "waiting_usb_auth": "In attesa del device USB...
Tocca ora il pulsante sul dispositivo WebAuthn USB.",
+ "waiting_usb_register": "In attesa del device USB...
Inserisci la tua password qui sopra e conferma la tua registrazione WebAuthn toccando il pulsante del dispositivo WebAuthn USB.",
"yubi_otp": "Autenticazione Yubico OTP",
"tfa_token_invalid": "Token TFA non valido"
},
diff --git a/data/web/lang/lang.ko.json b/data/web/lang/lang.ko.json
index e4ceb1c7..3dd1f446 100644
--- a/data/web/lang/lang.ko.json
+++ b/data/web/lang/lang.ko.json
@@ -417,7 +417,7 @@
"tls_policy_map_parameter_invalid": "유효하지 않은 정책 매개변수",
"totp_verification_failed": "TOTP 확인 실패",
"transport_dest_exists": "전송 목적지 \"%s\"가 존재합니다.",
- "u2f_verification_failed": "U2F 검증 실패: %s",
+ "webauthn_verification_failed": "WebAuthn 검증 실패: %s",
"unknown": "알 수 없는 오류 발생",
"unknown_tfa_method": "알 수 없는 TFA 방식",
"unlimited_quota_acl": "ACL에 따라 할당량을 무제한으로 둘 수 없습니다.",
@@ -852,7 +852,7 @@
"ui_texts": "Saved changes to UI texts",
"upload_success": "File uploaded successfully",
"verified_totp_login": "Verified TOTP login",
- "verified_u2f_login": "Verified U2F login",
+ "verified_webauthn_login": "Verified WebAuthn login",
"verified_yotp_login": "Verified Yubico OTP login"
},
"tfa": {
@@ -863,7 +863,7 @@
"disable_tfa": "Disable TFA until next successful login",
"enter_qr_code": "Your TOTP code if your device cannot scan QR codes",
"error_code": "Error code",
- "init_u2f": "Initializing, please wait...",
+ "init_webauthn": "Initializing, please wait...",
"key_id": "An identifier for your YubiKey",
"key_id_totp": "An identifier for your key",
"none": "Deactivate",
@@ -871,12 +871,12 @@
"scan_qr_code": "Please scan the following code with your authenticator app or enter the code manually.",
"select": "Please select",
"set_tfa": "Set two-factor authentication method",
- "start_u2f_validation": "Start validation",
+ "start_webauthn_validation": "Start validation",
"tfa": "Two-factor authentication",
"totp": "Time-based OTP (Google Authenticator, Authy, etc.)",
- "u2f": "U2F authentication",
- "waiting_usb_auth": "Waiting for USB device...
Please tap the button on your U2F USB device now.",
- "waiting_usb_register": "Waiting for USB device...
Please enter your password above and confirm your U2F registration by tapping the button on your U2F USB device.",
+ "webauthn": "WebAuthn authentication",
+ "waiting_usb_auth": "Waiting for USB device...
Please tap the button on your WebAuthn USB device now.",
+ "waiting_usb_register": "Waiting for USB device...
Please enter your password above and confirm your WebAuthn registration by tapping the button on your WebAuthn USB device.",
"yubi_otp": "Yubico OTP authentication"
},
"user": {
diff --git a/data/web/lang/lang.lv.json b/data/web/lang/lang.lv.json
index d4af59c6..ef6f85fb 100644
--- a/data/web/lang/lang.lv.json
+++ b/data/web/lang/lang.lv.json
@@ -450,9 +450,9 @@
"set_tfa": "Uzstādīt difi faktoru autentifik;acijas metodi",
"tfa": "Divu faktoru autentifikācija",
"totp": "Uz laiku bāzēta vienreizēja parole (Google Autentifikātors utt.)",
- "u2f": "U2F autentifikācija",
- "waiting_usb_auth": "Gaida USB ierīci...
Lūdzu, tagad nospiežiet pogu uz Jūsu U2F USB ierīces.",
- "waiting_usb_register": "Gaida USB ierīci...
Lūdzu augšā ievadiet Jūsu paroli un apstipriniet U2F reģistrāciju nospiežot pogu uz Jūsu U2F USB ierīces.",
+ "webauthn": "WebAuthn autentifikācija",
+ "waiting_usb_auth": "Gaida USB ierīci...
Lūdzu, tagad nospiežiet pogu uz Jūsu WebAuthn USB ierīces.",
+ "waiting_usb_register": "Gaida USB ierīci...
Lūdzu augšā ievadiet Jūsu paroli un apstipriniet WebAuthn reģistrāciju nospiežot pogu uz Jūsu WebAuthn USB ierīces.",
"yubi_otp": "Yubico OTP autentifikators"
},
"user": {
diff --git a/data/web/lang/lang.nl.json b/data/web/lang/lang.nl.json
index 0c548d00..4628aacf 100644
--- a/data/web/lang/lang.nl.json
+++ b/data/web/lang/lang.nl.json
@@ -428,7 +428,7 @@
"tls_policy_map_parameter_invalid": "Beleidsparameter is ongeldig",
"totp_verification_failed": "TOTP-verificatie mislukt",
"transport_dest_exists": "Transportbestemming \"%s\" bestaat reeds",
- "u2f_verification_failed": "U2F-verificatie mislukt: %s",
+ "webauthn_verification_failed": "WebAuthn-verificatie mislukt: %s",
"fido2_verification_failed": "FIDO2-verificatie mislukt: %s",
"unknown": "Er is een onbekende fout opgetreden",
"unknown_tfa_method": "Onbekende tweefactorauthenticatiemethode",
@@ -891,7 +891,7 @@
"ui_texts": "Wijzigingen aan labels en teksten zijn opgeslagen",
"upload_success": "Bestand succesvol geupload",
"verified_totp_login": "TOTP succesvol geverifieerd",
- "verified_u2f_login": "U2F succesvol geverifieerd",
+ "verified_webauthn_login": "WebAuthn succesvol geverifieerd",
"verified_fido2_login": "FIDO2 succesvol geverifieerd",
"verified_yotp_login": "Yubico OTP succesvol geverifieerd"
},
@@ -903,7 +903,7 @@
"disable_tfa": "Pauzeer tweefactorauthenticatie tot de eerstvolgende succesvolle login",
"enter_qr_code": "Voer deze code in als je apparaat geen QR-codes kan scannen:",
"error_code": "Errorcode",
- "init_u2f": "Even geduld aub...",
+ "init_webauthn": "Even geduld aub...",
"key_id": "Geef deze YubiKey een naam",
"key_id_totp": "Geef deze key een naam",
"none": "Deactiveer",
@@ -911,13 +911,13 @@
"scan_qr_code": "Scan de volgende QR-code met je authenticatie-app:",
"select": "Selecteer...",
"set_tfa": "Kies methode voor tweefactorauthenticatie",
- "start_u2f_validation": "Start validatie",
+ "start_webauthn_validation": "Start validatie",
"tfa": "Tweefactorauthenticatie",
"tfa_token_invalid": "Tweefactorauthenticatietoken is ongeldig",
"totp": "TOTP (Step Two, Authy, etc.)",
- "u2f": "U2F",
- "waiting_usb_auth": "In afwachting van USB-apparaat...
Druk nu op de knop van je U2F-apparaat.",
- "waiting_usb_register": "In afwachting van USB-apparaat...
Voer je wachtwoord hierboven in en bevestig de registratie van het U2F-apparaat door op de knop van het apparaat te drukken.",
+ "webauthn": "WebAuthn",
+ "waiting_usb_auth": "In afwachting van USB-apparaat...
Druk nu op de knop van je WebAuthn-apparaat.",
+ "waiting_usb_register": "In afwachting van USB-apparaat...
Voer je wachtwoord hierboven in en bevestig de registratie van het WebAuthn-apparaat door op de knop van het apparaat te drukken.",
"yubi_otp": "Yubico OTP"
},
"fido2": {
diff --git a/data/web/lang/lang.pl.json b/data/web/lang/lang.pl.json
index ea8fb6f2..4bfde1d7 100644
--- a/data/web/lang/lang.pl.json
+++ b/data/web/lang/lang.pl.json
@@ -329,9 +329,9 @@
"set_tfa": "Ustaw metodę uwierzytelniania dwuetapowego",
"tfa": "Uwierzytelnianie dwuetapowe",
"totp": "Time-based OTP (Google Authenticator itd.)",
- "u2f": "Uwierzytelnianie U2F",
- "waiting_usb_auth": "Czekam na urządzenie USB...
Wciśnij teraz przycisk na urządzeniu U2F USB.",
- "waiting_usb_register": " Czekam na urządzenie USB...
Wprowadź swoje hasło powyżej i potwierdź rejestrację U2F przez naciśnięcie przycisku na urządzeniu U2F USB.",
+ "webauthn": "Uwierzytelnianie WebAuthn",
+ "waiting_usb_auth": "Czekam na urządzenie USB...
Wciśnij teraz przycisk na urządzeniu WebAuthn USB.",
+ "waiting_usb_register": " Czekam na urządzenie USB...
Wprowadź swoje hasło powyżej i potwierdź rejestrację WebAuthn przez naciśnięcie przycisku na urządzeniu WebAuthn USB.",
"yubi_otp": "Uwierzytelnianie Yubico OTP"
},
"user": {
diff --git a/data/web/lang/lang.ro.json b/data/web/lang/lang.ro.json
index 20ba0e7e..07d615cf 100644
--- a/data/web/lang/lang.ro.json
+++ b/data/web/lang/lang.ro.json
@@ -448,7 +448,7 @@
"tls_policy_map_parameter_invalid": "Parametrul politicii este invalid",
"totp_verification_failed": "Verificarea TOTP a eșuat",
"transport_dest_exists": "Destinația transportului \"%s\" există",
- "u2f_verification_failed": "Verificarea U2F a eșuat: %s",
+ "webauthn_verification_failed": "Verificarea WebAuthn a eșuat: %s",
"fido2_verification_failed": "Verificarea FIDO2 a eșuat: %s",
"unknown": "A apărut o eroare necunoscută",
"unknown_tfa_method": "Metodă TFA necunoscută",
@@ -928,7 +928,7 @@
"ui_texts": "Modificări salvate în textele UI",
"upload_success": "Fișier încărcat cu succes",
"verified_totp_login": "Autentificarea TOTP verificată",
- "verified_u2f_login": "Autentificarea U2F verificată",
+ "verified_webauthn_login": "Autentificarea WebAuthn verificată",
"verified_fido2_login": "Conectare FIDO2 verificată",
"verified_yotp_login": "Autentificarea Yubico OTP verificată"
},
@@ -940,7 +940,7 @@
"disable_tfa": "Dezactivează TFA până la următoarea conectare reușită",
"enter_qr_code": "Codul tău TOTP dacă dispozitivul tău nu poate scana codurile QR",
"error_code": "Cod de eroare",
- "init_u2f": "Inițializare, vă rugăm așteptați...",
+ "init_webauthn": "Inițializare, vă rugăm așteptați...",
"key_id": "Un identificator pentru YubiKey",
"key_id_totp": "Un identificator pentru cheia ta",
"none": "Dezactivează",
@@ -948,13 +948,13 @@
"scan_qr_code": "Scanează codul următor cu aplicația ta de autentificare sau introdu manual codul.",
"select": "Te rog selectează",
"set_tfa": "Setează metoda de autentificare cu doi factori",
- "start_u2f_validation": "Începi validarea",
+ "start_webauthn_validation": "Începi validarea",
"tfa": "Autentificare cu doi factori",
"tfa_token_invalid": "Jeton TFA invalid",
"totp": "OTP pe bază de timp (Google Authenticator etc.)",
- "u2f": "Autentificare U2F",
- "waiting_usb_auth": "În așteptarea dispozitivului USB...
Apasă acum butonul de pe dispozitivul tău USB U2F.",
- "waiting_usb_register": "În așteptarea dispozitivului USB...
Introdu parola ta mai sus și confirmă înregistrarea ta U2F atingând butonul de pe dispozitivul tău USB U2F.",
+ "webauthn": "Autentificare WebAuthn",
+ "waiting_usb_auth": "În așteptarea dispozitivului USB...
Apasă acum butonul de pe dispozitivul tău USB WebAuthn.",
+ "waiting_usb_register": "În așteptarea dispozitivului USB...
Introdu parola ta mai sus și confirmă înregistrarea ta WebAuthn atingând butonul de pe dispozitivul tău USB WebAuthn.",
"yubi_otp": "Autentificare Yubico OTP"
},
"fido2": {
diff --git a/data/web/lang/lang.ru.json b/data/web/lang/lang.ru.json
index 9310e276..0628fe2d 100644
--- a/data/web/lang/lang.ru.json
+++ b/data/web/lang/lang.ru.json
@@ -454,7 +454,7 @@
"tls_policy_map_parameter_invalid": "Недопустимое значение параметра политики",
"totp_verification_failed": "Ошибка валидации TOTP",
"transport_dest_exists": "Назначение для отправки \"%s\" уже существует",
- "u2f_verification_failed": "Ошибка валидации U2F: %s",
+ "webauthn_verification_failed": "Ошибка валидации WebAuthn: %s",
"unknown": "Произошла неизвестная ошибка",
"unknown_tfa_method": "Неизвестный метод TFA",
"unlimited_quota_acl": "Неограниченная квота запрещена политикой доступа",
@@ -973,7 +973,7 @@
"upload_success": "Файл загружен успешно",
"verified_fido2_login": "Авторизация FIDO2 пройдена",
"verified_totp_login": "Авторизация TOTP пройдена",
- "verified_u2f_login": "Авторизация U2F пройдена",
+ "verified_webauthn_login": "Авторизация WebAuthn пройдена",
"verified_yotp_login": "Авторизация Yubico OTP пройдена"
},
"tfa": {
@@ -984,7 +984,7 @@
"disable_tfa": "Отключить TFA до следующего успешного входа",
"enter_qr_code": "Ваш код TOTP, если устройство не может отсканировать QR-код",
"error_code": "Код ошибки",
- "init_u2f": "Инициализация, пожалуйста, подождите...",
+ "init_webauthn": "Инициализация, пожалуйста, подождите...",
"key_id": "Идентификатор YubiKey ключа",
"key_id_totp": "Идентификатор TOTP ключа",
"none": "Отключить",
@@ -992,11 +992,11 @@
"scan_qr_code": "Пожалуйста, отсканируйте QR-код с помощью приложения или введите его вручную.",
"select": "Пожалуйста, выберите",
"set_tfa": "Задать метод двухфакторной проверки",
- "start_u2f_validation": "Начать проверку",
+ "start_webauthn_validation": "Начать проверку",
"tfa": "Двухфакторная проверка подлинности",
"tfa_token_invalid": "Неправильный TFA токен",
"totp": "OTP (Authy, Google Authenticator и др.)",
- "u2f": "U2F аутентификация",
+ "webauthn": "WebAuthn аутентификация",
"waiting_usb_auth": "Ожидание устройства USB...
Пожалуйста, нажмите кнопку на USB устройстве сейчас.",
"waiting_usb_register": "Ожидание устройства USB...
Пожалуйста, введите пароль выше и подтвердите регистрацию, нажав кнопку на USB устройстве.",
"yubi_otp": "Yubico OTP аутентификация"
diff --git a/data/web/lang/lang.sk.json b/data/web/lang/lang.sk.json
index b3518908..49002c56 100644
--- a/data/web/lang/lang.sk.json
+++ b/data/web/lang/lang.sk.json
@@ -454,7 +454,7 @@
"tls_policy_map_parameter_invalid": "Podmienkový parameter mapy TLS pravidiel je neplatný",
"totp_verification_failed": "TOTP overenie zlyhalo",
"transport_dest_exists": "Transportný cieľ \"%s\" už existuje",
- "u2f_verification_failed": "U2F overenie zlyhalo: %s",
+ "webauthn_verification_failed": "WebAuthn overenie zlyhalo: %s",
"unknown": "Nastala neznáma chyba",
"unknown_tfa_method": "Neznáma TFA metóda",
"unlimited_quota_acl": "Neobmedzené kvóta je zakázaná cez ACL",
@@ -973,7 +973,7 @@
"upload_success": "Súbor úspešne nahratý",
"verified_fido2_login": "Overené FIDO2 prihlásenie",
"verified_totp_login": "Overené TOTP prihlásenie",
- "verified_u2f_login": "Overené U2F prihlásenie",
+ "verified_webauthn_login": "Overené WebAuthn prihlásenie",
"verified_yotp_login": "Overené Yubico OTP prihlásenie"
},
"tfa": {
@@ -984,7 +984,7 @@
"disable_tfa": "Vypnúť TFA do ďalšieho úspešného prihlásenia",
"enter_qr_code": "Zadajte váš TOTP kód, ak vaše zariadenie nedokáže skenovať QR kódy",
"error_code": "Chyba kódu",
- "init_u2f": "Inicializácia, prosím čakajte...",
+ "init_webauthn": "Inicializácia, prosím čakajte...",
"key_id": "Identifikátor pre váš YubiKey",
"key_id_totp": "Identifikátor pre váš kľúč",
"none": "Deaktivovať",
@@ -992,11 +992,11 @@
"scan_qr_code": "Prosím oskenujte nasledovný kód pomocou vašej autentizačnej aplikácie alebo zadajte kód manuálne.",
"select": "Prosím vyberte",
"set_tfa": "Nastaviť dvojúrovňovú autentifikačnú metódu",
- "start_u2f_validation": "Spustiť validáciu",
+ "start_webauthn_validation": "Spustiť validáciu",
"tfa": "Dvojúrovňová autentifikácia (TFA)",
"tfa_token_invalid": "Neplatný TFA token",
"totp": "Časovo-založený OTP (Google Authenticator, Authy, atď.)",
- "u2f": "U2F autentifikácia",
+ "webauthn": "WebAuthn autentifikácia",
"waiting_usb_auth": "Čakanie na USB zariadenie...
Prosím stlačte tlačidlo na vašom USB zariadení.",
"waiting_usb_register": "Čakanie na USB zariadenie...
Prosím zadajte vaše heslo a potvrďte registráciu stlačením tlačidla na vašom USB zariadení.",
"yubi_otp": "Yubico OTP autentifikácia"
diff --git a/data/web/lang/lang.sv.json b/data/web/lang/lang.sv.json
index f2b9e8fc..12cf2586 100644
--- a/data/web/lang/lang.sv.json
+++ b/data/web/lang/lang.sv.json
@@ -441,8 +441,8 @@
"tls_policy_map_parameter_invalid": "Policy parameter är ogiltig",
"totp_verification_failed": "TOTP-verifiering misslyckades",
"transport_dest_exists": "Transportdestinationen \"%s\" existerar redan",
- "u2f_verification_failed": "U2F-verifiering misslyckades: %s",
- "fido2_verification_failed": "U2F-verifiering misslyckades: %s",
+ "webauthn_verification_failed": "WebAuthn-verifiering misslyckades: %s",
+ "fido2_verification_failed": "WebAuthn-verifiering misslyckades: %s",
"unknown": "Ett fel har inträffat",
"unknown_tfa_method": "Okänd TFA method",
"unlimited_quota_acl": "På grund av en åtkomstlista tillåts inte en obegränsad kvot",
@@ -911,7 +911,7 @@
"ui_texts": "Ändringarna på texter och rubriker i gränssnittet sparade",
"upload_success": "Filen har laddats upp",
"verified_totp_login": "Verifierad TOTP inloggning",
- "verified_u2f_login": "Verifierad U2F inloggning",
+ "verified_webauthn_login": "Verifierad WebAuthn inloggning",
"verified_fido2_login": "Verifierad FIDO2 inloggning",
"verified_yotp_login": "Verifierad Yubico OTP inloggning"
},
@@ -923,7 +923,7 @@
"disable_tfa": "Inaktivera tvåfaktorsautentisering tills nästa lyckade inloggning",
"enter_qr_code": "Om du inte kan skanna den QR-kod som visas, använd säkerhetsnyckeln som visas nedan",
"error_code": "Felkod",
- "init_u2f": "Initierar, vänta...",
+ "init_webauthn": "Initierar, vänta...",
"key_id": "En identifierare för din YubiKey",
"key_id_totp": "En identifierare för din nyckel",
"none": "Avaktivera",
@@ -931,11 +931,11 @@
"scan_qr_code": "Skanna nu den QR-kod som visas på skärmen.",
"select": "Välj",
"set_tfa": "Metod för tvåfaktorsautentisering",
- "start_u2f_validation": "Startar validering",
+ "start_webauthn_validation": "Startar validering",
"tfa": "Tvåfaktorsautentisering",
"tfa_token_invalid": "TFA nyckeln är ogiltig!",
"totp": "Tidsbaserad OTP (Google Authenticator, Authy, mm)",
- "u2f": "U2F-autentisering",
+ "webauthn": "WebAuthn-autentisering",
"waiting_usb_auth": "Väntar på USB-enhet...
Tryck på knappen på USB-enheten nu.",
"waiting_usb_register": "Väntar på USB-enhet...
Vänligen fyll i det övre lösenordsfältet först och tryck sedan på knappen på USB-enheten.",
"yubi_otp": "Yubico OTP-autentisering"
diff --git a/data/web/lang/lang.zh.json b/data/web/lang/lang.zh.json
index 4d587385..485a4636 100644
--- a/data/web/lang/lang.zh.json
+++ b/data/web/lang/lang.zh.json
@@ -424,7 +424,7 @@
"tls_policy_map_parameter_invalid": "策略参数非法",
"totp_verification_failed": "TOTP认证失败",
"transport_dest_exists": "传输目标 \"%s\" 已存在",
- "u2f_verification_failed": "U2F认证失败: %s",
+ "webauthn_verification_failed": "WebAuthn认证失败: %s",
"unknown": "发生未知错误",
"unknown_tfa_method": "未知TFA方法",
"unlimited_quota_acl": "ACL设置禁止了无限配额",
@@ -875,7 +875,7 @@
"ui_texts": "已保存UI文本更改",
"upload_success": "成功上传文件",
"verified_totp_login": "TOTP登录验证成功",
- "verified_u2f_login": "U2F登录验证成功",
+ "verified_webauthn_login": "WebAuthn登录验证成功",
"verified_yotp_login": "Yubico OTP登录验证成功"
},
"tfa": {
@@ -886,7 +886,7 @@
"disable_tfa": "在下一次成功登录前关闭两步验证",
"enter_qr_code": "如果你的设备不能扫描QR码,输入此TOTP码",
"error_code": "错误码",
- "init_u2f": "初始化中,请等待...",
+ "init_webauthn": "初始化中,请等待...",
"key_id": "你的YubiKey的标识",
"key_id_totp": "你的密钥的标识",
"none": "禁用",
@@ -894,12 +894,12 @@
"scan_qr_code": "请用你认证应用扫描或手动输入此码。",
"select": "请选择",
"set_tfa": "设置两步验证方法",
- "start_u2f_validation": "开始认证",
+ "start_webauthn_validation": "开始认证",
"tfa": "两步验证(2FA)",
"totp": "TOTP认证 (Google Authenticator、Authy等)",
- "u2f": "U2F认证",
- "waiting_usb_auth": "等待USB设备...
现在请触碰你的U2F USB设备上的按钮。",
- "waiting_usb_register": "等待USB设备...
请在上方输入你的密码并请触碰你的U2F USB设备上的按钮以确认注册U2F设备。",
+ "webauthn": "WebAuthn认证",
+ "waiting_usb_auth": "等待USB设备...
现在请触碰你的WebAuthn USB设备上的按钮。",
+ "waiting_usb_register": "等待USB设备...
请在上方输入你的密码并请触碰你的WebAuthn USB设备上的按钮以确认注册WebAuthn设备。",
"yubi_otp": "Yubico OTP认证"
},
"user": {
diff --git a/data/web/templates/admin/tab-config-admins.twig b/data/web/templates/admin/tab-config-admins.twig
index d7c17c8b..cfb69d4d 100644
--- a/data/web/templates/admin/tab-config-admins.twig
+++ b/data/web/templates/admin/tab-config-admins.twig
@@ -40,7 +40,7 @@
' + lang_tfa.init_u2f + '
'); + $('#webauthn_status_auth').html('' + lang_tfa.init_u2f + '
'); $('#ConfirmTFAModal').on('shown.bs.modal', function(){ $(this).find('input[name=token]').focus(); - // If U2F - if(document.getElementById("u2f_auth_data") !== null) { - $.ajax({ - type: "GET", - cache: false, - dataType: 'script', - url: "/api/v1/get/u2f-authentication/{{ pending_mailcow_cc_username|url_encode(true)|default('null') }}", - complete: function(data){ - $('#u2f_status_auth').html(lang_tfa.waiting_usb_auth); - data; - setTimeout(function() { - console.log("Ready to authenticate"); - u2f.sign(appId, challenge, registeredKeys, function(data) { - var form = document.getElementById('u2f_auth_form'); - var auth = document.getElementById('u2f_auth_data'); - console.log("Authenticate callback", data); - auth.value = JSON.stringify(data); - form.submit(); - }); - }, 1000); - } + // If WebAuthn + if(document.getElementById("webauthn_auth_data") !== null) { + // Check Browser support + if (!window.fetch || !navigator.credentials || !navigator.credentials.create) { + window.alert('Browser not supported for WebAuthn.'); + return; + } + + window.fetch("/api/v1/get/webauthn-tfa-get-args", {method:'GET',cache:'no-cache'}).then(response => { + return response.json(); + }).then(json => { + console.log(json); + if (json.success === false) throw new Error(); + + recursiveBase64StrToArrayBuffer(json); + return json; + }).then(getCredentialArgs => { + console.log(getCredentialArgs); + return navigator.credentials.get(getCredentialArgs); + }).then(cred => { + console.log(cred); + return { + id: cred.rawId ? arrayBufferToBase64(cred.rawId) : null, + clientDataJSON: cred.response.clientDataJSON ? arrayBufferToBase64(cred.response.clientDataJSON) : null, + authenticatorData: cred.response.authenticatorData ? arrayBufferToBase64(cred.response.authenticatorData) : null, + signature : cred.response.signature ? arrayBufferToBase64(cred.response.signature) : null + }; + }).then(JSON.stringify).then(function(AuthenticatorAttestationResponse) { + console.log(AuthenticatorAttestationResponse); + + var form = document.getElementById('webauthn_auth_form'); + var auth = document.getElementById('webauthn_auth_data'); + console.log("Authenticate callback", AuthenticatorAttestationResponse); + auth.value = AuthenticatorAttestationResponse; + form.submit(); + }).catch(function(err) { + if (typeof err.message === 'undefined') { + mailcow_alert_box(lang_fido2.fido2_validation_failed, "danger"); + } else { + mailcow_alert_box(lang_fido2.fido2_validation_failed + ":' + lang_tfa.init_u2f + '
'); - $.ajax({ - type: "GET", - cache: false, - dataType: 'script', - url: "/api/v1/get/u2f-registration/{{ mailcow_cc_username|url_encode(true)|default('null') }}", - complete: function(data){ - data; - setTimeout(function() { - console.log("Ready to register"); - $('#u2f_status_reg').html(lang_tfa.waiting_usb_register); - u2f.register(appId, registerRequests, registeredKeys, function(deviceResponse) { - var form = document.getElementById('u2f_reg_form'); - var reg = document.getElementById('u2f_register_data'); - console.log("Register callback: ", data); - if (deviceResponse.errorCode && deviceResponse.errorCode != 0) { - var u2f_return_code = document.getElementById('u2f_return_code'); - u2f_return_code.style.display = u2f_return_code.style.display === 'none' ? '' : null; - if (deviceResponse.errorCode == "4") { - deviceResponse.errorCode = "4 - The presented device is not eligible for this request. For a registration request this may mean that the token is already registered, and for a sign request it may mean that the token does not know the presented key handle"; - } - else if (deviceResponse.errorCode == "5") { - deviceResponse.errorCode = "5 - Timeout reached before request could be satisfied."; - } - u2f_return_code.innerHTML = lang_tfa.error_code + ': ' + deviceResponse.errorCode + ' ' + lang_tfa.reload_retry; - return; + if ($(this).val() == "webauthn") { + // check if Browser is supported + if (!window.fetch || !navigator.credentials || !navigator.credentials.create) { + window.alert('Browser not supported.'); + return; + } + + // show modal + $('#WebAuthnModal').modal('show'); + $("option:selected").prop("selected", false); + + $("#start_webauthn_register").click(() => { + var key_id = document.getElementsByName('key_id')[1].value; + + // fetch WebAuthn CreateArgs + window.fetch("/api/v1/get/webauthn-tfa-registration/{{ mailcow_cc_username|url_encode(true)|default('null') }}", {method:'GET',cache:'no-cache'}).then(response => { + return response.json(); + }).then(json => { + console.log(json); + + if (json.success === false) throw new Error(json.msg); + + recursiveBase64StrToArrayBuffer(json); + + return json; + }).then(createCredentialArgs => { + return navigator.credentials.create(createCredentialArgs); + }).then(cred => { + return { + clientDataJSON: cred.response.clientDataJSON ? arrayBufferToBase64(cred.response.clientDataJSON) : null, + attestationObject: cred.response.attestationObject ? arrayBufferToBase64(cred.response.attestationObject) : null, + key_id: key_id, + tfa_method: "webauthn" + }; + }).then(JSON.stringify).then(AuthenticatorAttestationResponse => { + console.log(AuthenticatorAttestationResponse); + + return window.fetch("/api/v1/add/webauthn-tfa-registration", {method:'POST', body: AuthenticatorAttestationResponse, cache:'no-cache'}); + }).then(response => { + return response.json(); + }).then(json => { + console.log(json); + + if (json.success) { + console.log("success"); + window.location.reload(); + } else { + throw new Error(json.msg); } - reg.value = JSON.stringify(deviceResponse); - form.submit(); - }); - }, 1000); - } + }).catch(function(err) { + console.log(err); + var webauthn_return_code = document.getElementById('webauthn_return_code'); + webauthn_return_code.style.display = webauthn_return_code.style.display === 'none' ? '' : null; + webauthn_return_code.innerHTML = lang_tfa.error_code + ': ' + err + ' ' + lang_tfa.reload_retry; + }); }); - }); } if ($(this).val() == "none") { $('#DisableTFAModal').modal('show'); diff --git a/data/web/templates/modals/footer.twig b/data/web/templates/modals/footer.twig index 8e5cb175..306005a1 100644 --- a/data/web/templates/modals/footer.twig +++ b/data/web/templates/modals/footer.twig @@ -37,15 +37,15 @@