<?php
/**
 * Responsible for WP2FA user's TOTP manipulation.
 *
 * @package    wp2fa
 * @subpackage methods
 *
 * @copyright  2026 Melapress
 * @license    https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
 *
 * @see       https://wordpress.org/plugins/wp-2fa/
 *
 * @since 2.6.0
 */

declare(strict_types=1);

namespace WP2FA\Methods;

use WP2FA\WP2FA;
use WP2FA\Admin\User_Profile;
use WP2FA\Utils\Settings_Utils;
use WP2FA\Admin\Settings_Builder;
use WP2FA\Authenticator\Login;
use WP2FA\Authenticator\Open_SSL;
use WP2FA\Admin\Helpers\User_Helper;
use WP2FA\Authenticator\Authentication;
use WP2FA\Admin\Methods\Traits\Providers;
use WP2FA\Admin\Methods\Traits\Validation;
use WP2FA\Admin\Methods\Traits\WhiteLabel;
use WP2FA\Methods\Wizards\TOTP_Wizard_Steps;
use WP2FA\Admin\Methods\Traits\Settings_Trait;
use WP2FA\Admin\SettingsPages\Settings_Page_White_Label;

/**
 * Class for handling totp codes.
 *
 * @since 2.6.0
 *
 * @package WP2FA
 */
if ( ! class_exists( '\WP2FA\Methods\TOTP' ) ) {
	/**
	 * TOTP code class, for handling totp (app) code generation and such.
	 *
	 * @since 2.6.0
	 */
	class TOTP {

		use Providers;
		use Settings_Trait;
		use Validation;
		use WhiteLabel;

		/**
		 * The name of the method.
		 *
		 * @var string
		 *
		 * @since 2.6.0
		 */
		public const METHOD_NAME = 'totp';

		/**
		 * The internal name of the method.
		 *
		 * @var string
		 *
		 * @since 2.5.0
		 */
		public const METHOD_INTERNAL_NAME = self::METHOD_NAME;

		/**
		 * Secret TOTP key meta name.
		 *
		 * @var string
		 *
		 * @since 2.6.0
		 */
		public const TOTP_META_KEY = WP_2FA_PREFIX . 'totp_key';

		/**
		 * The name of the method stored in the policy
		 *
		 * @var string
		 *
		 * @since 2.6.0
		 */
		public const POLICY_SETTINGS_NAME = 'enable_' . self::METHOD_NAME;

		/**
		 * Is the totp method enabled
		 *
		 * @since 1.7
		 *
		 * @var bool
		 */
		private static $enabled = null;

		/**
		 * Totp key assigned to user
		 *
		 * @var string
		 */
		private static $totp_key = '';

		/**
		 * Inits the class and sets the filters.
		 *
		 * @return void
		 *
		 * @since 2.6.0
		 */
		public static function init() {

			self::always_init();

			\add_filter( WP_2FA_PREFIX . 'providers_translated_names', array( __CLASS__, 'provider_name_translated' ) );

			\add_filter( WP_2FA_PREFIX . 'default_settings', array( __CLASS__, 'add_default_settings' ) );

			\add_filter( WP_2FA_PREFIX . 'loop_settings', array( __CLASS__, 'settings_loop' ), 10, 1 );

			\add_filter( WP_2FA_PREFIX . 'no_method_enabled', array( __CLASS__, 'return_default_selection' ), 10, 1 );

			// add the TOTP methods to the list of available methods if enabled.
			\add_filter(
				WP_2FA_PREFIX . 'available_2fa_methods',
				function ( $available_methods, $role ) {
					if ( ! empty( Settings_Utils::get_setting_role( $role, self::POLICY_SETTINGS_NAME ) ) ) {
						array_push( $available_methods, self::METHOD_NAME );
					}

					return $available_methods;
				},
				10,
				2
			);

			\add_filter( WP_2FA_PREFIX . 'white_label_default_settings', array( __CLASS__, 'add_whitelabel_settings' ) );
			\add_action( WP_2FA_PREFIX . 'validate_login_api', array( __CLASS__, 'api_login_validate' ), 10, 3 );

			\add_filter( WP_2FA_PREFIX . 'validate_login_form', array( __CLASS__, 'validate_login_form' ), 10, 3 );

			\add_action( WP_2FA_PREFIX . 'white_label_wizard_options', array( __CLASS__, 'white_label_option_labels' ) );

			TOTP_Wizard_Steps::init();

			\add_filter( WP_2FA_PREFIX . 'providers_settings_labels', array( __CLASS__, 'provider_settings_labels' ) );
		}

		/**
		 * Adds the OOB settings in the white label default settings array
		 *
		 * @param array $labels - array with white label default settings.
		 *
		 * @return array
		 *
		 * @since 3.1.1.2
		 */
		public static function provider_settings_labels( array $labels ): array {
			\ob_start();
			?>
				<div class="form-group settings-row">
					<?php
					Settings_Builder::build_option(
						array(
							'text' => \esc_html__( 'TOTP (one-time code via app) Option label', 'wp-2fa' ),
							'type' => 'settings-label',
						)
					);
					?>
					<div class="settings-control ">
						<?php
						Settings_Builder::build_option(
							array(
								'id'          => 'totp-option-label',
								'type'        => 'text',
								'placeholder' => \esc_html__( 'Provider\'s name', 'wp-2fa' ),
								'class'       => 'form-input',
								'option_name' => 'wp_2fa_white_label[totp-option-label]',
								'default'     => \esc_html( WP2FA::get_wp2fa_white_label_setting( 'totp-option-label', true ) ),
							)
						);
						?>
					</div>
				</div>
				<div class="form-group settings-row">
					<?php
					Settings_Builder::build_option(
						array(
							'text' => \esc_html__( 'TOTP option hint', 'wp-2fa' ),
							'type' => 'settings-label',
						)
					);
					?>
					<div class="settings-control ">
						<?php
						Settings_Builder::build_option(
							array(
								'id'          => 'totp-option-label-hint',
								'type'        => 'editor',
								'placeholder' => \esc_html__( 'Enter custom message', 'wp-2fa' ),
								'option_name' => 'wp_2fa_white_label[totp-option-label-hint]',
								'default'     => WP2FA::get_wp2fa_white_label_setting( 'totp-option-label-hint', true ),
							)
						);
						?>
					</div>
				</div>
				<div class="form-group settings-row">
					<div class="settings-label-group">
						<?php
						Settings_Builder::build_option(
						array(
						'text' => \esc_html(
						\wp_sprintf(
						// translators: Method option label.
						__( '%s help text', 'wp-2fa' ),
						WP2FA::get_wp2fa_white_label_setting( 'totp-option-label', true )
						)
						),
						'type' => 'settings-label',
						)
						);

						Settings_Builder::build_option(
						array(
						'text'  => \wp_sprintf(
						// translators: Method option label.
						\esc_html__( 'This message is shown to users when configuring %s.', 'wp-2fa' ),
						WP2FA::get_wp2fa_white_label_setting( 'totp-option-label', true )
						),
						'class' => 'description-settings-card',
						'id'    => 'general-settings-tab',
						'type'  => 'description',
						)
						);
						?>
					</div>
					<div class="settings-control">
						<?php
						Settings_Builder::build_option(
						array(
						'id'          => 'method_help_totp_intro',
						'type'        => 'editor',
						'placeholder' => \esc_html__( 'Enter custom message', 'wp-2fa' ),
						'option_name' => 'wp_2fa_white_label[method_help_totp_intro]',
						'default'     => WP2FA::get_wp2fa_white_label_setting( 'method_help_totp_intro', true ),
						)
						);
						?>
					</div>
				</div>
				<div class="form-group settings-row">
					<div class="settings-label-group">
						<?php
						Settings_Builder::build_option(
						array(
						'text' => \esc_html(
						\wp_sprintf(
						// translators: Method option label.
						\esc_html__( '%s setup step 1', 'wp-2fa' ),
						WP2FA::get_wp2fa_white_label_setting( 'totp-option-label', true )
						)
						),
						'type' => 'settings-label',
						)
						);

						// Settings_Builder::build_option(
						// array(
						// 'text'  => \wp_sprintf(
						// \esc_html__( 'Step-by-step guidance for the authenticator-app (TOTP) method, e.g. Step 1: open your authenticator app and tap +. Step 2: scan the QR code. Step 3: enter the 6-digit code shown. %1$s', 'wp-2fa' ),
						// \wp_sprintf( '<a href="%s" target="_blank">%s</a>', 'https://melapress.com/support/kb/wp-2fa-customize-user-2fa-experience/?#utm_source=plugin&utm_medium=wp2fa&utm_campaign=guide_customize_2fa_user_experience', \esc_html__( 'Learn more', 'wp-2fa' ) )
						// ),
						// 'class' => 'description-settings-card',
						// 'id'    => 'totp-step-1-desc',
						// 'type'  => 'description',
						// )
						// );
						?>
					</div>
					<div class="settings-control">
						<?php
						Settings_Builder::build_option(
							array(
								'id'          => 'method_help_totp_step_1',
								'type'        => 'text',
								'placeholder' => \esc_html__( 'Enter text', 'wp-2fa' ),
								'class'       => 'form-input',
								'option_name' => 'wp_2fa_white_label[method_help_totp_step_1]',
								'default'     => \esc_html( WP2FA::get_wp2fa_white_label_setting( 'method_help_totp_step_1', true ) ),
							)
						);
						?>
					</div>
				</div>
				<div class="form-group settings-row">
					<?php
					Settings_Builder::build_option(
						array(
							'text' => \esc_html(
								\wp_sprintf(
								// translators: Method option label.
									\esc_html__( '%s setup step 2', 'wp-2fa' ),
									WP2FA::get_wp2fa_white_label_setting( 'totp-option-label', true )
								)
							),
							'type' => 'settings-label',
						)
					);
					?>
					<div class="settings-control ">
						<?php
						Settings_Builder::build_option(
							array(
								'id'          => 'method_help_totp_step_2',
								'type'        => 'text',
								'placeholder' => \esc_html__( 'Enter text', 'wp-2fa' ),
								'class'       => 'form-input',
								'option_name' => 'wp_2fa_white_label[method_help_totp_step_2]',
								'default'     => \esc_html( WP2FA::get_wp2fa_white_label_setting( 'method_help_totp_step_2', true ) ),
							)
						);
						?>
					</div>
				</div>
				<div class="form-group settings-row">
					<?php
					Settings_Builder::build_option(
						array(
							'text' => \esc_html__(
								\wp_sprintf(
								// translators: Method option label.
									\esc_html__( '%s setup step 3', 'wp-2fa' ),
									WP2FA::get_wp2fa_white_label_setting( 'totp-option-label', true )
								)
							),
							'type' => 'settings-label',
						)
					);
					?>
					<div class="settings-control ">
						<?php
						Settings_Builder::build_option(
							array(
								'id'          => 'method_help_totp_step_3',
								'type'        => 'text',
								'placeholder' => \esc_html__( 'Enter text', 'wp-2fa' ),
								'class'       => 'form-input',
								'option_name' => 'wp_2fa_white_label[method_help_totp_step_3]',
								'default'     => \esc_html( WP2FA::get_wp2fa_white_label_setting( 'method_help_totp_step_3', true ) ),
							)
						);
						?>
					</div>
				</div>
				<div class="form-group settings-row">
					<?php
					Settings_Builder::build_option(
						array(
							'text' => \esc_html(
								\wp_sprintf(
								// translators: Method option label.
									__( 'This message is shown when a user presses the info button for the %s method.', 'wp-2fa' ),
									WP2FA::get_wp2fa_white_label_setting( 'totp-option-label', true )
								)
							),
							'type' => 'settings-label',
						)
					);
					?>
					<div class="settings-control ">
						<?php
						Settings_Builder::build_option(
							array(
								'id'          => 'method_help_totp_more_intro',
								'type'        => 'editor',
								'placeholder' => \esc_html__( 'Enter custom message', 'wp-2fa' ),
								'option_name' => 'wp_2fa_white_label[method_help_totp_more_intro]',
								'default'     => WP2FA::get_wp2fa_white_label_setting( 'method_help_totp_more_intro', true ),
							)
						);
						?>
					</div>
				</div>
				<div class="form-group settings-row">
					<div class="settings-label-group">
						<?php
						Settings_Builder::build_option(
						array(
						'text' => \esc_html(
						\wp_sprintf(
						// translators: Method option label.
						\esc_html__( '%s pre-submission text', 'wp-2fa' ),
						WP2FA::get_wp2fa_white_label_setting( 'totp-option-label', true )
						)
						),
						'type' => 'settings-label',
						)
						);

						Settings_Builder::build_option(
						array(
						'text'  => \esc_html(
						\wp_sprintf(
						// translators: Method option label.
						\esc_html__( 'This message is shown to users prior to configuring %s method.', 'wp-2fa' ),
						WP2FA::get_wp2fa_white_label_setting( 'totp-option-label', true )
						)
						),
						'class' => 'description-settings-card',
						'id'    => 'general-settings-tab',
						'type'  => 'description',
						)
						);
						?>
					</div>
					<div class="settings-control">
						<?php
						Settings_Builder::build_option(
						array(
						'id'          => 'method_verification_totp_pre',
						'type'        => 'editor',
						'placeholder' => \esc_html__( 'Enter custom message', 'wp-2fa' ),
						'option_name' => 'wp_2fa_white_label[method_verification_totp_pre]',
						'default'     => WP2FA::get_wp2fa_white_label_setting( 'method_verification_totp_pre', true ),
						)
						);
						?>
					</div>
				</div>


			<?php
			$content = \ob_get_clean();

			$labels[ self::METHOD_NAME ] = array(
				'provider_name' => \esc_html( WP2FA::get_wp2fa_white_label_setting( 'totp-option-label', true ) ),
				'content'       => $content,
			);

			return $labels;
		}

		/**
		 * Returns the translated name of the provider
		 *
		 * @return string
		 *
		 * @since 2.6.0
		 */
		public static function get_translated_name(): string {
			return esc_html__( 'TOTP (one-time code via app)', 'wp-2fa' );
		}

		/**
		 * Validates the token for TOTP.
		 *
		 * @param \WP_User $user - The user.
		 * @param string   $token - The token.
		 *
		 * @return bool
		 */
		protected static function validate_token( \WP_User $user, string $token ): bool {
			return Authentication::is_valid_authcode( self::get_totp_key( $user ), $token, $user );
		}

		/**
		 * Sets the TOTP as a method for the given user
		 *
		 * @param \WP_User $user - The user for which the method has to be set, if null, it uses the current user.
		 * @param string   $totp_key - The totp key for the user to be set.
		 *
		 * @return void
		 *
		 * @throws \LogicException - If the method is called without $totp_key.
		 *
		 * @since 2.6.0
		 */
		public static function set_user_method( $user = null, string $totp_key = '' ) {
			if ( null === $user ) {
				$user = wp_get_current_user();
			}

			if ( '' === \trim( $totp_key ) ) {
				throw new \LogicException( 'TOTP key must not be empty' );
			}

			User_Helper::set_enabled_method_for_user( self::METHOD_NAME, $user );
			self::set_user_totp_key( $totp_key, $user );
			User_Profile::delete_expire_and_enforced_keys( $user->ID );
			User_Helper::set_user_status( $user );
		}

		/**
		 * Retrieves the QR code
		 *
		 * @since 2.6.0
		 *
		 * @return string
		 */
		public static function get_qr_code(): string {

			// Setup site information, used when generating our QR code.
			$site_name = site_url();
			$site_name = trim( str_replace( array( 'http://', 'https://' ), '', (string) $site_name ), '/' );
			/**
			 * Changing the title of the login screen for the TOTP method.
			 *
			 * @param string $title - The default title.
			 * @param \WP_User $user - The WP user.
			 *
			 * @since 2.0.0
			 */
			$totp_title = apply_filters(
				WP_2FA_PREFIX . 'totp_title',
				$site_name . ':' . User_Helper::get_user_object()->user_login,
				User_Helper::get_user_object()
			);

			return Authentication::get_google_qr_code( $totp_title, self::get_totp_key(), $site_name );
		}

		/**
		 * Validates authentication.
		 *
		 * @param \WP_User $user - The WP user, if presented.
		 *
		 * @return bool Whether the user gave a valid code
		 *
		 * @since 2.6.0
		 */
		public static function validate_totp_authentication( ?\WP_User $user = null ): bool {
			if ( ! empty( $_REQUEST['authcode'] ) ) {  //phpcs:ignore
				$valid = Authentication::is_valid_authcode(
					self::get_totp_key( $user ),
					\sanitize_text_field( \wp_unslash( $_REQUEST['authcode'] ) ),
					$user
				);
				if ( $valid ) {
					Authentication::clear_login_attempts( $user );
				} else {
					Authentication::increase_login_attempts( $user );
				}
				return $valid;
			}

			return false;
		}

		/**
		 * Validates the TOTP login form submission.
		 *
		 * @param bool     $authenticated Whether authentication has passed.
		 * @param \WP_User $user          The user being authenticated.
		 * @param string   $provider      The provider name.
		 *
		 * @return bool
		 *
		 * @since 4.0.1
		 */
		public static function validate_login_form( $authenticated, $user, $provider ) {
			if ( self::METHOD_NAME !== $provider ) {
				return $authenticated;
			}

			if ( $authenticated ) {
				return $authenticated;
			}

			if ( true === self::validate_totp_authentication( $user ) ) {
				return true;
			}

			// Validation failed.
			\do_action(
				'wp_login_failed',
				$user->user_login,
				new \WP_Error(
					'authentication_failed',
					__( '<strong>Error</strong>: User can not be authenticated.', 'wp-2fa' )
				)
			);

			Login::delete_login_nonce( $user->ID );
			$login_nonce = Login::create_login_nonce( $user->ID );
			if ( ! $login_nonce ) {
				\wp_die( \esc_html__( 'Failed to create a login nonce.', 'wp-2fa' ) );
			}

			if ( Authentication::check_number_of_attempts( $user ) ) {
				Login::login_html( $user, $login_nonce['key'], \esc_url_raw( \wp_unslash( $_REQUEST['redirect_to'] ) ), \esc_html__( 'ERROR: Invalid verification code.', 'wp-2fa' ), $provider ); // phpcs:ignore
			} else {
				// Reached the maximum number of attempts - clear the attempts and redirect the user to the login page.
				Authentication::clear_login_attempts( $user );
				\wp_safe_redirect( \wp_login_url() );
			}
			exit;
		}

		/**
		 * Add extension settings to the loop array
		 *
		 * @param array $loop_settings - Currently available settings array.
		 *
		 * @return array
		 *
		 * @since 2.6.0
		 */
		public static function settings_loop( array $loop_settings ): array {
			array_push( $loop_settings, self::POLICY_SETTINGS_NAME );

			return $loop_settings;
		}

		/**
		 * Regenerates the TOTP key for the user
		 *
		 * @return void - JSON - object with "key" - stores the new key and "qr" - stores the new QR code.
		 *
		 * @since 2.5.0
		 */
		public static function regenerate_authentication_key() {
			// Grab current user.
			$user = wp_get_current_user();

			check_ajax_referer( 'wp-2fa-backup-codes-generate-json-' . $user->ID );

			$key = Authentication::generate_key();

			$site_name = site_url();
			$site_name = trim( str_replace( array( 'http://', 'https://' ), '', (string) $site_name ), '/' );

			/**
			 * Changing the title of the login screen for the TOTP method.
			 *
			 * @param string $title - The default title.
			 * @param \WP_User $user - The WP user.
			 *
			 * @since 2.0.0
			 */
			$totp_title = apply_filters( WP_2FA_PREFIX . 'totp_title', $site_name . ':' . $user->user_login, $user );
			$new_qr     = Authentication::get_google_qr_code( $totp_title, $key, $site_name );

			\wp_send_json_success(
				array(
					'key' => Authentication::decrypt_key_if_needed( $key ),
					'qr'  => $new_qr,
				)
			);
		}

		/**
		 * User totp key getter
		 *
		 * @param int|\WP_User|null $user - The WP user we should extract the meta data for.
		 *
		 * @return string
		 *
		 * @since 2.6.0
		 */
		public static function get_totp_key( $user = null ): string {
			if ( '' === trim( (string) self::$totp_key ) ) {
				self::$totp_key = self::get_user_totp_key_auth( User_Helper::get_user( $user )->ID );
				if ( empty( self::$totp_key ) ) {
					self::$totp_key = Authentication::generate_key();

					self::set_user_totp_key( self::$totp_key, $user );
				} elseif ( Open_SSL::is_ssl_available() && false === \strpos( self::$totp_key, Open_SSL::SECRET_KEY_PREFIX ) ) {
						self::$totp_key = Open_SSL::SECRET_KEY_PREFIX . Open_SSL::encrypt( self::$totp_key );
						self::set_user_totp_key( self::$totp_key, $user );
				}
			}

			return self::$totp_key;
		}

		/**
		 * Returns the encoded TOTP when we need to show the actual code to the user
		 * If for some reason the code is invalid it recreates it
		 *
		 * @param int|\WP_User|null $user - The WP user we should extract the meta data for.
		 *
		 * @return string
		 *
		 * @since 2.6.0
		 */
		public static function get_totp_decrypted( $user = null ): string {
			$key = self::get_totp_key( $user );
			if ( Open_SSL::is_ssl_available() && false !== \strpos( $key, 'ssl_' ) ) {

				/**
				 * Old key detected - convert.
				 */
				$key = Open_SSL::decrypt_legacy( substr( $key, 4 ) );

				self::remove_user_totp_key( $user );
				self::$totp_key = '';

				$key = self::get_totp_key( $user );
			}

			if ( Open_SSL::is_ssl_available() && false !== \strpos( $key, 'wps_' ) ) {

				/**
				 * Old key detected - convert.
				 */
				$key = Open_SSL::decrypt_wps( substr( $key, 4 ) );

				self::remove_user_totp_key( $user );

				$secret = Open_SSL::encrypt( $key );

				if ( Open_SSL::is_ssl_available() ) {
					$secret = Open_SSL::SECRET_KEY_PREFIX . $secret;
				}

				self::set_user_totp_key( $secret, $user );

				self::$totp_key = $secret;
			}

			if ( Open_SSL::is_ssl_available() && false !== \strpos( $key, Open_SSL::SECRET_KEY_PREFIX ) ) {
				$key = Open_SSL::decrypt( substr( $key, 4 ) );

				/**
				 * If for some reason the key is not valid, that means that we have to clear the stored TOTP for the user, and create new one
				 * That could happen if the global stored secret (plugin level) is deleted.
				 *
				 * Lets check and if that is the case - create new one
				 */
				if ( ! Authentication::validate_base32_string( $key ) ) {
					self::$totp_key = '';
					self::remove_user_totp_key( $user );
					$key = self::get_totp_key( $user );
					$key = Open_SSL::decrypt( substr( $key, 4 ) );
				}
			}

			return $key;
		}

		/**
		 * Deletes the TOTP secret key for a user.
		 *
		 * @param int|\WP_User|null $user - The WP user that must be used.
		 *
		 * @return void
		 */
		public static function remove_user_totp_key( $user = null ) {
			User_Helper::remove_meta( self::TOTP_META_KEY, $user );

			self::$totp_key = '';
		}

		/**
		 * Returns the TOTP secret key for a user.
		 *
		 * @param int|\WP_User|null $user - The WP user that must be used.
		 *
		 * @return string
		 */
		public static function get_user_totp_key( $user = null ) {
			return User_Helper::get_meta( self::TOTP_META_KEY, $user );
		}

		/**
		 * Updates the TOTP secret key for a user.
		 *
		 * @param string            $value - The value of the TOTP key.
		 * @param int|\WP_User|null $user  - The WP user that must be used.
		 *
		 * @return void
		 *
		 * @since 2.2.0
		 */
		public static function set_user_totp_key( string $value, $user = null ) {
			User_Helper::set_meta( self::TOTP_META_KEY, $value, $user );
		}

		/**
		 * Get the TOTP secret key for a user.
		 *
		 * @param  int $user_id User ID.
		 *
		 * @return string
		 *
		 * @since 2.6.0
		 */
		public static function get_user_totp_key_auth( $user_id ) {

			$key = (string) self::get_user_totp_key( $user_id );

			$test = $key;

			if ( Open_SSL::is_ssl_available() && false !== \strpos( $key, 'ssl_' ) ) {

				/**
				 * Old key detected - convert.
				 */
				$key = Open_SSL::decrypt_legacy( substr( $key, 4 ) );

				self::remove_user_totp_key();

				$secret = Open_SSL::encrypt( $key );

				if ( Open_SSL::is_ssl_available() ) {
					$secret = Open_SSL::SECRET_KEY_PREFIX . $secret;
				}

				self::set_user_totp_key( $key, $user_id );

				$test = $key = (string) self::get_user_totp_key( $user_id ); // phpcs:ignore Squiz.PHP.DisallowMultipleAssignments.Found
			}

			// We've tried tried to use WP core functionality, but that doesn't work - lets update.
			if ( Open_SSL::is_ssl_available() && false !== \strpos( $key, 'wps_' ) ) {

				/**
				 * Old key detected - convert.
				 */
				$key = Open_SSL::decrypt_wps( substr( $key, 4 ) );

				self::remove_user_totp_key();

				$secret = Open_SSL::encrypt( $key );

				if ( Open_SSL::is_ssl_available() ) {
					$secret = Open_SSL::SECRET_KEY_PREFIX . $secret;
				}

				self::set_user_totp_key( $key, $user_id );

				$test = $key = (string) self::get_user_totp_key( $user_id );  // phpcs:ignore Squiz.PHP.DisallowMultipleAssignments.Found
			}

			Authentication::decrypt_key_if_needed( $test );

			if ( ! Authentication::is_valid_key( $test ) ) {
				$key = Authentication::generate_key();
				self::set_user_totp_key( $key, $user_id );
				Authentication::clear_decrypted_key();
			}

			return $key;
		}

		/**
		 * Fills up the White Label settings array with the method defaults.
		 *
		 * @param array $default_settings - The array with the collected white label settings.
		 *
		 * @return array
		 *
		 * @since 3.0.0
		 */
		public static function add_whitelabel_settings( array $default_settings ): array {

			\ob_start();
			?>
			<p class="description"><?php \esc_html_e( 'Click on the icon of the app that you are using for a detailed guide on how to set it up.', 'wp-2fa' ); ?></p>
			<table class="apps-wrapper">
				<tr>
				<?php foreach ( Authentication::get_apps() as $app ) { ?>
					<td>
					<a href="https://melapress.com/support/kb/wp-2fa-configuring-2fa-apps/?&utm_source=plugin&utm_medium=wp2fa&utm_campaign=authentication_help#<?php echo $app['hash']; ?>" target="_blank" class="app-logo"><img src="<?php echo \esc_url( WP_2FA_URL . 'dist/images/' . $app['logo'] ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>"></a>
					</td>
				<?php } ?>
				</tr>
			</table>
			<?php
			$mth = \ob_get_clean();

			$default_settings['method_help_totp_intro']       = '<h3>' . __( 'Setting up TOTP (one-time code via app)', 'wp-2fa' ) . '</h3>';
			$default_settings['method_help_totp_step_1']      = __( 'Download and start the application of your choice', 'wp-2fa' );
			$default_settings['method_help_totp_step_2']      = __( 'From within the application scan the QR code provided on the left. Otherwise, enter the following code manually in the application:', 'wp-2fa' );
			$default_settings['method_help_totp_step_3']      = __( 'Click the "I\'m ready" button below when you complete the application setup process to proceed with the wizard.', 'wp-2fa' );
			$default_settings['method_verification_totp_pre'] = '<h3>' . __( 'Almost there…', 'wp-2fa' ) . '</h3><p>' . __( 'Please type in the one-time code from your chosen authentication app to finalize the setup.', 'wp-2fa' ) . '</p>';
			$default_settings['totp_reconfigure_intro']       = '<h3>' . __( '{reconfigure_or_configure_capitalized} the 2FA App', 'wp-2fa' ) . '</h3><p>' . __( 'Click the below button to {reconfigure_or_configure} the current 2FA method. Note that once reset you will have to re-scan the QR code on all devices you want this to work on because the previous codes will stop working.', 'wp-2fa' ) . '</p>';
			$default_settings['totp-option-label']            = __( 'One-time code via 2FA app', 'wp-2fa' );
			$default_settings['method_help_totp_more_intro']  = $mth;
			$default_settings['totp-option-label-hint']       = sprintf(
			/* translators: link to the knowledge base website */
				\esc_html__( 'Refer to the %s for step-by-step instructions on how to set up this method.', 'wp-2fa' ),
				'<a href="https://melapress.com/support/kb/wp-2fa-configuring-2fa-wordpress-user/?utm_source=plugin&utm_medium=wp2fa&utm_campaign=guide_how_to_setup_totp_app_hint" target="_blank">' . \esc_html__( 'setup guide', 'wp-2fa' ) . '</a>'
			);

			return $default_settings;
		}

		/**
		 * Shows the Method option label and hint in the White Label settings.
		 *
		 * @return void
		 *
		 * @since 2.9.0
		 */
		public static function white_label_option_labels() {
			?>
			<strong class="description"><?php esc_html_e( 'TOTP (one-time code via app) Option label', 'wp-2fa' ); ?></strong>
			<br><br>
			<fieldset>
				<input type="text" id="totp-option-label" name="wp_2fa_white_label[totp-option-label]" class="large-text" value="<?php echo \esc_attr( WP2FA::get_wp2fa_white_label_setting( 'totp-option-label', true ) ); ?>">
			</fieldset>
			<br>
			<strong class="description"><?php esc_html_e( 'TOTP option hint', 'wp-2fa' ); ?></strong>
			<br>
			<fieldset>
				<?php
					echo Settings_Page_White_Label::create_standard_editor( 'totp-option-label-hint' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
				?>
			</fieldset>
			<br>
			<?php
		}
	}
}
