| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -830,11 +830,15 @@ function check_login($user, $pass, $app_passwd_data = false) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  $stmt->execute(array(':user' => $user));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  foreach ($rows as $row) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // verify password
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (verify_hash($row['password'], $pass)) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      if (get_tfa($user)['name'] != "none") {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      // check for tfa authenticators
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      $authenticators = get_tfa($user);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      if (isset($authenticators['additional']) && is_array($authenticators['additional']) && count($authenticators['additional']) > 0) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        // active tfa authenticators found, set pending user login
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        $_SESSION['pending_mailcow_cc_username'] = $user;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        $_SESSION['pending_mailcow_cc_role'] = "admin";
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        $_SESSION['pending_tfa_method'] = get_tfa($user)['name'];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        $_SESSION['pending_tfa_methods'] = $authenticators['additional'];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        unset($_SESSION['ldelay']);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        $_SESSION['return'][] =  array(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          'type' => 'info',
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -842,8 +846,7 @@ function check_login($user, $pass, $app_passwd_data = false) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          'msg' => 'awaiting_tfa_confirmation'
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        );
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        return "pending";
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      else {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      } else {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        unset($_SESSION['ldelay']);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        // Reactivate TFA if it was set to "deactivate TFA for next login"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        $stmt = $pdo->prepare("UPDATE `tfa` SET `active`='1' WHERE `username` = :user");
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -866,11 +869,14 @@ function check_login($user, $pass, $app_passwd_data = false) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  $stmt->execute(array(':user' => $user));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  foreach ($rows as $row) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // verify password
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (verify_hash($row['password'], $pass) !== false) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      if (get_tfa($user)['name'] != "none") {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      // check for tfa authenticators
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      $authenticators = get_tfa($user);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      if (isset($authenticators['additional']) && is_array($authenticators['additional']) && count($authenticators['additional']) > 0) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        $_SESSION['pending_mailcow_cc_username'] = $user;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        $_SESSION['pending_mailcow_cc_role'] = "domainadmin";
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        $_SESSION['pending_tfa_method'] = get_tfa($user)['name'];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        $_SESSION['pending_tfa_method'] = $authenticators['additional'];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        unset($_SESSION['ldelay']);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        $_SESSION['return'][] =  array(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          'type' => 'info',
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -1142,47 +1148,46 @@ function set_tfa($_data) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  global $yubi;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  global $tfa;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  $_data_log = $_data;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  $access_denied = null;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  !isset($_data_log['confirm_password']) ?: $_data_log['confirm_password'] = '*';
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  $username = $_SESSION['mailcow_cc_username'];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if (!isset($_SESSION['mailcow_cc_role']) || empty($username)) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      $_SESSION['return'][] =  array(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        'type' => 'danger',
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        'log' => array(__FUNCTION__, $_data_log),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        'msg' => 'access_denied'
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      );
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      return false;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  $stmt = $pdo->prepare("SELECT `password` FROM `admin`
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      WHERE `username` = :username");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  $stmt->execute(array(':username' => $username));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  $row = $stmt->fetch(PDO::FETCH_ASSOC);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if (!empty($num_results)) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (!verify_hash($row['password'], $_data["confirm_password"])) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      $_SESSION['return'][] =  array(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        'type' => 'danger',
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        'log' => array(__FUNCTION__, $_data_log),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        'msg' => 'access_denied'
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      );
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      return false;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  $stmt = $pdo->prepare("SELECT `password` FROM `mailbox`
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      WHERE `username` = :username");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  $stmt->execute(array(':username' => $username));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  $row = $stmt->fetch(PDO::FETCH_ASSOC);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if (!empty($num_results)) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (!verify_hash($row['password'], $_data["confirm_password"])) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      $_SESSION['return'][] =  array(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        'type' => 'danger',
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        'log' => array(__FUNCTION__, $_data_log),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        'msg' => 'access_denied'
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      );
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      return false;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  // check for empty user and role
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if (!isset($_SESSION['mailcow_cc_role']) || empty($username)) $access_denied = true;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  // check admin confirm password
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if ($access_denied === null) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    $stmt = $pdo->prepare("SELECT `password` FROM `admin`
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        WHERE `username` = :username");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    $stmt->execute(array(':username' => $username));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    $row = $stmt->fetch(PDO::FETCH_ASSOC);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if ($row) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      if (!verify_hash($row['password'], $_data["confirm_password"])) $access_denied = true;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      else $access_denied = false;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  // check mailbox confirm password
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if ($access_denied === null) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    $stmt = $pdo->prepare("SELECT `password` FROM `mailbox`
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        WHERE `username` = :username");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    $stmt->execute(array(':username' => $username));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    $row = $stmt->fetch(PDO::FETCH_ASSOC);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if ($row) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      if (!verify_hash($row['password'], $_data["confirm_password"])) $access_denied = true;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      else $access_denied = false;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  // set access_denied error
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if ($access_denied){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    $_SESSION['return'][] =  array(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      'type' => 'danger',
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      'log' => array(__FUNCTION__, $_data_log),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      'msg' => 'access_denied'
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    );
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    return false;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  switch ($_data["tfa_method"]) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    case "yubi_otp":
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -1265,9 +1270,6 @@ function set_tfa($_data) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    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(
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -1439,25 +1441,27 @@ function unset_tfa_key($_data) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  global $pdo;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  global $lang;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  $_data_log = $_data;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  $access_denied = null;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  $id = intval($_data['unset_tfa_key']);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  $username = $_SESSION['mailcow_cc_username'];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if (!isset($_SESSION['mailcow_cc_role']) || empty($username)) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    $_SESSION['return'][] =  array(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      'type' => 'danger',
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      'log' => array(__FUNCTION__, $_data_log),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      'msg' => 'access_denied'
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    );
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    return false;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  // check for empty user and role
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if (!isset($_SESSION['mailcow_cc_role']) || empty($username)) $access_denied = true;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  try {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (!is_numeric($id)) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      $_SESSION['return'][] =  array(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (!is_numeric($id)) $access_denied = true;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // set access_denied error
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if ($access_denied){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      $_SESSION['return'][] = array(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        'type' => 'danger',
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        'log' => array(__FUNCTION__, $_data_log),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        'msg' => 'access_denied'
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      );
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      return false;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    } 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // check if it's last key
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    $stmt = $pdo->prepare("SELECT COUNT(*) AS `keys` FROM `tfa`
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      WHERE `username` = :username AND `active` = '1'");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    $stmt->execute(array(':username' => $username));
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -1470,6 +1474,8 @@ function unset_tfa_key($_data) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      );
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      return false;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // delete key
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    $stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `username` = :username AND `id` = :id");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    $stmt->execute(array(':username' => $username, ':id' => $id));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    $_SESSION['return'][] =  array(
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -1487,7 +1493,7 @@ function unset_tfa_key($_data) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    return false;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				function get_tfa($username = null) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				function get_tfa($username = null, $key_id = null) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  global $pdo;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if (isset($_SESSION['mailcow_cc_username'])) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    $username = $_SESSION['mailcow_cc_username'];
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -1495,92 +1501,116 @@ function get_tfa($username = null) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  elseif (empty($username)) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    return false;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  $stmt = $pdo->prepare("SELECT * FROM `tfa`
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      WHERE `username` = :username AND `active` = '1'");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  $stmt->execute(array(':username' => $username));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  $row = $stmt->fetch(PDO::FETCH_ASSOC);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if (isset($row["authmech"])) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    switch ($row["authmech"]) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      case "yubi_otp":
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        $data['name'] = "yubi_otp";
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        $data['pretty'] = "Yubico OTP";
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        $stmt = $pdo->prepare("SELECT `id`, `key_id`, RIGHT(`secret`, 12) AS 'modhex' FROM `tfa` WHERE `authmech` = 'yubi_otp' AND `username` = :username");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        $stmt->execute(array(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          ':username' => $username,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        ));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        while($row = array_shift($rows)) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          $data['additional'][] = $row;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if (!isset($key_id)){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // fetch all tfa methods - just get information about possible authenticators
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    $stmt = $pdo->prepare("SELECT `id`, `key_id`, `authmech` FROM `tfa`
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        WHERE `username` = :username AND `active` = '1'");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    $stmt->execute(array(':username' => $username));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    $results = $stmt->fetchAll(PDO::FETCH_ASSOC);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // no tfa methods found
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (count($results) == 0) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        $data['name'] = 'none';
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        $data['pretty'] = "-";
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        $data['additional'] = array();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        return $data;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    $data['additional'] = $results;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    return $data;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  } else {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // fetch specific authenticator details by key_id
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    $stmt = $pdo->prepare("SELECT * FROM `tfa`
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    WHERE `username` = :username AND `active` = '1'");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    $stmt->execute(array(':username' => $username));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    $row = $stmt->fetch(PDO::FETCH_ASSOC);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (isset($row["authmech"])) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        switch ($row["authmech"]) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          case "yubi_otp":
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            $data['name'] = "yubi_otp";
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            $data['pretty'] = "Yubico OTP";
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            $stmt = $pdo->prepare("SELECT `id`, `key_id`, RIGHT(`secret`, 12) AS 'modhex' FROM `tfa` WHERE `authmech` = 'yubi_otp' 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;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          // u2f - deprecated, should be removed
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          case "u2f":
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            $data['name'] = "u2f";
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            $data['pretty'] = "Fido U2F";
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            $stmt = $pdo->prepare("SELECT `id`, `key_id` FROM `tfa` WHERE `authmech` = 'u2f' 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;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          case "hotp":
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            $data['name'] = "hotp";
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            $data['pretty'] = "HMAC-based OTP";
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            return $data;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          break;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          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");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            $stmt->execute(array(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				              ':username' => $username,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            ));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            while($row = array_shift($rows)) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				              $data['additional'][] = $row;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            return $data;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          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'] = "-";
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            return $data;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          break;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        return $data;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      break;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      // u2f - deprecated, should be removed
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      case "u2f":
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        $data['name'] = "u2f";
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        $data['pretty'] = "Fido U2F";
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        $stmt = $pdo->prepare("SELECT `id`, `key_id` FROM `tfa` WHERE `authmech` = 'u2f' 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;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      case "hotp":
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        $data['name'] = "hotp";
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        $data['pretty'] = "HMAC-based OTP";
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        return $data;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      break;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      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");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        $stmt->execute(array(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          ':username' => $username,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        ));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        while($row = array_shift($rows)) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          $data['additional'][] = $row;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        return $data;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      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:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      else {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        $data['name'] = 'none';
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        $data['pretty'] = "-";
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        return $data;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      break;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  else {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    $data['name'] = 'none';
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    $data['pretty'] = "-";
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    return $data;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				function verify_tfa_login($username, $_data, $WebAuthn) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    global $pdo;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    global $yubi;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    global $u2f;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    global $tfa;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				function verify_tfa_login($username, $_data) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  global $pdo;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  global $yubi;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  global $u2f;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  global $tfa;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  global $WebAuthn;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if ($_data['tfa_method'] != 'u2f'){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    $stmt = $pdo->prepare("SELECT `authmech` FROM `tfa`
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        WHERE `username` = :username AND `active` = '1'");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    $stmt->execute(array(':username' => $username));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        WHERE `username` = :username AND `key_id` = :key_id AND `active` = '1'");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    $stmt->execute(array(':username' => $username, ':key_id' => $_data['key_id']));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    $row = $stmt->fetch(PDO::FETCH_ASSOC);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    switch ($row["authmech"]) {
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -1597,9 +1627,10 @@ function verify_tfa_login($username, $_data, $WebAuthn) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            $stmt = $pdo->prepare("SELECT `id`, `secret` FROM `tfa`
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                WHERE `username` = :username
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                AND `authmech` = 'yubi_otp'
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                AND `key_id` = ':key_id'
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                AND `active`='1'
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                AND `secret` LIKE :modhex");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            $stmt->execute(array(':username' => $username, ':modhex' => '%' . $yubico_modhex_id));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            $stmt->execute(array(':username' => $username, ':modhex' => '%' . $yubico_modhex_id, ':key_id' => $_data['key_id']));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            $row = $stmt->fetch(PDO::FETCH_ASSOC);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            $yubico_auth = explode(':', $row['secret']);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            $yubi = new Auth_Yubico($yubico_auth[0], $yubico_auth[1]);
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -1636,8 +1667,9 @@ function verify_tfa_login($username, $_data, $WebAuthn) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            $stmt = $pdo->prepare("SELECT `id`, `secret` FROM `tfa`
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                WHERE `username` = :username
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                AND `authmech` = 'totp'
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                AND `key_id` = :key_id
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                AND `active`='1'");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            $stmt->execute(array(':username' => $username));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            $stmt->execute(array(':username' => $username, ':key_id' => $_data['key_id']));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            foreach ($rows as $row) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                if ($tfa->verifyCode($row['secret'], $_data['token']) === true) {
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -1666,13 +1698,6 @@ function verify_tfa_login($username, $_data, $WebAuthn) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            return false;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        break;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        // u2f - deprecated, should be removed
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        case "u2f":
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            // delete old keys that used u2f
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            $stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `authmech` = :authmech AND `username` = :username");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            $stmt->execute(array(':authmech' => 'u2f', ':username' => $username));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            return true;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        case "webauthn":
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            $tokenData = json_decode($_data['token']);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            $clientDataJSON = base64_decode($tokenData->clientDataJSON);
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -1681,7 +1706,7 @@ function verify_tfa_login($username, $_data, $WebAuthn) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            $id = base64_decode($tokenData->id);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            $challenge = $_SESSION['challenge'];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            $stmt = $pdo->prepare("SELECT `key_id`, `keyHandle`, `username`, `publicKey` FROM `tfa` WHERE `keyHandle` = :tokenId");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            $stmt = $pdo->prepare("SELECT `id`, `key_id`, `keyHandle`, `username`, `publicKey` FROM `tfa` WHERE `keyHandle` = :tokenId");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            $stmt->execute(array(':tokenId' => $tokenData->id));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            $process_webauthn = $stmt->fetch(PDO::FETCH_ASSOC);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -1738,7 +1763,7 @@ function verify_tfa_login($username, $_data, $WebAuthn) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            $_SESSION["mailcow_cc_username"] = $process_webauthn['username'];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            $_SESSION['tfa_id'] = $process_webauthn['key_id'];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            $_SESSION['tfa_id'] = $process_webauthn['id'];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            $_SESSION['authReq'] = null;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            unset($_SESSION["challenge"]);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            $_SESSION['return'][] =  array(
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -1759,6 +1784,17 @@ function verify_tfa_login($username, $_data, $WebAuthn) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    return false;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  } else {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // delete old keys that used u2f
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    $stmt = $pdo->prepare("SELECT * FROM `tfa` WHERE `authmech` = 'u2f' AND `username` = :username");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    $stmt->execute(array(':username' => $username));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (count($rows) == 0) return false;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    $stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `authmech` = 'u2f' AND `username` = :username");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    $stmt->execute(array(':username' => $username));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    return true;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				function admin_api($access, $action, $data = null) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  global $pdo;
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				 
 |