getTraceAsString()); $trace = array_reverse($trace); array_shift($trace); array_pop($trace); $length = count($trace); $result = array(); for($i = 0; $i < $length; $i++){ $result[] = ($i + 1).')'.substr($trace[$i], strpos($trace[$i], ' ')); } return "Traceback:\n ".implode("\n ", $result); } function wwa_cleanup_blog_credentials($user_id, $blog_id){ global $wpdb; $wpdb->delete($wpdb->wwa_credentials, array( 'user_id' => $user_id, 'registered_blog_id' => $blog_id )); } function wwa_cleanup_all_user_credentials($user_id){ global $wpdb; $wpdb->delete($wpdb->wwa_credentials, array('user_id' => $user_id)); delete_user_meta($user_id, 'wwa_user_handle'); delete_user_meta($user_id, 'wwa_webauthn_only'); } function wwa_delete_user($user_id){ $res_id = wwa_generate_random_string(5); $user_data = get_userdata($user_id); if($user_data !== false){ wwa_add_log($res_id, "Deleted user credentials for => \"".$user_data->user_login."\""); } if(is_multisite()){ wwa_cleanup_blog_credentials($user_id, get_current_blog_id()); }else{ wwa_cleanup_all_user_credentials($user_id); } } add_action('delete_user', 'wwa_delete_user'); function wwa_delete_user_multisite($user_id){ $res_id = wwa_generate_random_string(5); $user_data = get_userdata($user_id); if($user_data !== false){ wwa_add_log($res_id, "Deleted all user credentials for => \"".$user_data->user_login."\" (network deletion)"); } wwa_cleanup_all_user_credentials($user_id); } add_action('wpmu_delete_user', 'wwa_delete_user_multisite'); function wwa_remove_user_from_blog($user_id, $blog_id){ $res_id = wwa_generate_random_string(5); $user_data = get_userdata($user_id); if($user_data !== false){ wwa_add_log($res_id, "Deleted user credentials for => \"".$user_data->user_login."\" (removed from blog ".$blog_id.")"); } wwa_cleanup_blog_credentials($user_id, $blog_id); } add_action('remove_user_from_blog', 'wwa_remove_user_from_blog', 10, 2); // Add CSS and JS in login page function wwa_login_js(){ wwa_init_new_options(); $wwa_not_allowed = false; if(!function_exists('mb_substr') || !function_exists('gmp_intval') || !wwa_check_ssl() && (wp_parse_url(site_url(), PHP_URL_HOST) !== 'localhost' && wp_parse_url(site_url(), PHP_URL_HOST) !== '127.0.0.1')){ $wwa_not_allowed = true; } wp_enqueue_script('wwa_login', plugins_url('js/login.js', __FILE__), array(), get_option('wwa_version')['version'], true); $first_choice = wwa_get_option('first_choice'); wp_localize_script('wwa_login', 'wwa_login_php_vars', array( 'ajax_url' => admin_url('admin-ajax.php'), 'admin_url' => admin_url(), 'usernameless' => (wwa_get_option('usernameless_login') === false ? 'false' : wwa_get_option('usernameless_login')), 'remember_me' => (wwa_get_option('remember_me') === false ? 'false' : wwa_get_option('remember_me')), 'email_login' => (wwa_get_option('email_login') === false ? 'false' : wwa_get_option('email_login')), 'allow_authenticator_type' => (wwa_get_option('allow_authenticator_type') === false ? "none" : wwa_get_option('allow_authenticator_type')), 'webauthn_only' => ($first_choice === 'webauthn' && !$wwa_not_allowed) ? 'true' : 'false', 'password_reset' => ((wwa_get_option('password_reset') === false || wwa_get_option('password_reset') === 'off') ? 'false' : 'true'), 'separator' => apply_filters('login_link_separator', ' | '), 'terminology' => (wwa_get_option('terminology') === false ? 'passkey' : wwa_get_option('terminology')), 'i18n_1' => __('Auth', 'wp-webauthn'), 'i18n_2' => wwa_get_option('terminology') === 'webauthn' ? __('Authenticate with WebAuthn', 'wp-webauthn') : __('Authenticate with a passkey', 'wp-webauthn'), 'i18n_3' => __('Hold on...', 'wp-webauthn'), 'i18n_4' => __('Please proceed...', 'wp-webauthn'), 'i18n_5' => __('Authenticating...', 'wp-webauthn'), 'i18n_6' => ' '.__('Authenticated', 'wp-webauthn').'', 'i18n_7' => ' '.__('Auth failed', 'wp-webauthn').'', 'i18n_8' => __('It looks like your browser doesn\'t support WebAuthn, which means you may unable to login.', 'wp-webauthn'), 'i18n_9' => __('Username', 'wp-webauthn'), 'i18n_10' => __('Username or Email Address'), 'i18n_11' => __('Error: The username field is empty.', 'wp-webauthn'), 'i18n_12' => ''.__('Try to enter the username', 'wp-webauthn').'', 'i18n_13' => __('Password'), 'i18n_14' => wwa_get_option('terminology') === 'webauthn' ? 'WebAuthn' : __('Passkey', 'wp-webauthn') )); if($first_choice === 'true' || $first_choice === 'webauthn'){ wp_enqueue_script('wwa_default', plugins_url('js/default_wa.js', __FILE__), array(), get_option('wwa_version')['version'], true); } wp_enqueue_style('wwa_login_css', plugins_url('css/login.css', __FILE__), array(), get_option('wwa_version')['version']); } add_action('login_enqueue_scripts', 'wwa_login_js', 999); // Disable password login function wwa_disable_password($user){ if(!function_exists('mb_substr') || !function_exists('gmp_intval') || !wwa_check_ssl() && (wp_parse_url(site_url(), PHP_URL_HOST) !== 'localhost' && wp_parse_url(site_url(), PHP_URL_HOST) !== '127.0.0.1')){ return $user; } if(wwa_get_option('first_choice') === 'webauthn'){ return new WP_Error('wwa_password_disabled', __('Logging in with password has been disabled by the site manager.', 'wp-webauthn')); } if(is_wp_error($user)){ return $user; } if(get_user_meta($user->ID, 'wwa_webauthn_only', true) === 'true'){ return new WP_Error('wwa_password_disabled_for_account', __('Logging in with password has been disabled for this account.', 'wp-webauthn')); } return $user; } add_filter('wp_authenticate_user', 'wwa_disable_password', 10, 1); function wwa_handle_user_register($user_id){ if(wwa_get_option('password_reset') === 'admin' || wwa_get_option('password_reset') === 'all'){ update_user_option($user_id, 'default_password_nag', false); } if(wwa_get_option('after_user_registration') === 'login'){ wp_set_current_user($user_id); wp_set_auth_cookie($user_id); wp_redirect(admin_url('profile.php?wwa_registered=true#wwa-webauthn-start')); exit; } } add_action('register_new_user', 'wwa_handle_user_register'); // Disable Password Reset URL & Redirect function wwa_disable_lost_password(){ if((wwa_get_option('password_reset') === 'admin' || wwa_get_option('password_reset') === 'all') && isset($_GET['action'])){ if(in_array($_GET['action'], array('lostpassword', 'retrievepassword', 'resetpass', 'rp'))){ wp_redirect(wp_login_url(), 302); exit; } } } function wwa_handle_lost_password_html_link($link){ if(wwa_get_option('password_reset') === 'admin' || wwa_get_option('password_reset') === 'all'){ return ''; } return $link; } function wwa_handle_password(){ if(wwa_get_option('password_reset') === 'admin' || wwa_get_option('password_reset') === 'all'){ if(wwa_get_option('password_reset') === 'admin'){ if(current_user_can('edit_users')){ return true; } } return false; } return true; } if(wwa_get_option('password_reset') === 'admin' || wwa_get_option('password_reset') === 'all'){ add_action('login_init', 'wwa_disable_lost_password'); add_filter('lost_password_html_link', 'wwa_handle_lost_password_html_link'); add_filter('show_password_fields', 'wwa_handle_password'); add_filter('allow_password_reset', 'wwa_handle_password'); } function wwa_no_authenticator_warning(){ if(is_network_admin()){ return; } $user_info = wp_get_current_user(); $first_choice = wwa_get_option('first_choice'); $check_self = true; if($first_choice !== 'webauthn' && get_user_meta($user_info->ID, 'wwa_webauthn_only', true) !== 'true'){ $check_self = false; } if($check_self){ global $wpdb; $count = $wpdb->get_var($wpdb->prepare( "SELECT COUNT(*) FROM {$wpdb->wwa_credentials} WHERE user_id = %d AND registered_blog_id = %d", $user_info->ID, get_current_blog_id() )); if(intval($count) === 0){ ?>

Register', 'wp-webauthn'), $wwa_scope_label, $wwa_cred_label, esc_url(admin_url('profile.php'))), array('a' => array('href' => array())));?>

ID){ $user_id_wp = intval($_GET['user_id']); if($user_id_wp <= 0 || !current_user_can('edit_user', $user_id_wp)){ return; } $other_user = get_user_by('id', $user_id_wp); if($other_user === false){ return; } if($first_choice !== 'webauthn' && get_user_meta($other_user->ID, 'wwa_webauthn_only', true) !== 'true'){ return; } global $wpdb; $count = $wpdb->get_var($wpdb->prepare( "SELECT COUNT(*) FROM {$wpdb->wwa_credentials} WHERE user_id = %d AND registered_blog_id = %d", $other_user->ID, get_current_blog_id() )); if(intval($count) === 0){ ?>

this account haven\'t register any %2$s on the current site yet. This user may unable to login.', 'wp-webauthn'), $wwa_scope_label, $wwa_cred_label), array('strong' => array()));?>

'.__('Settings', 'wp-webauthn').''; } return $links_array; } add_filter('plugin_action_links', 'wwa_settings_link', 10, 2); function wwa_network_settings_link($links_array, $plugin_file_name){ if($plugin_file_name === 'wp-webauthn/wp-webauthn.php'){ $links_array[] = ''.__('Network Settings', 'wp-webauthn').''; } return $links_array; } if(is_multisite()){ add_filter('network_admin_plugin_action_links', 'wwa_network_settings_link', 10, 2); } function wwa_meta_link($links_array, $plugin_file_name){ if($plugin_file_name === 'wp-webauthn/wp-webauthn.php'){ $links_array[] = ''.__('GitHub', 'wp-webauthn').''; $links_array[] = ''.__('Documentation', 'wp-webauthn').''; } return $links_array; } add_filter('plugin_row_meta', 'wwa_meta_link', 10, 2); // Check if we are under HTTPS function wwa_check_ssl(){ if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' && $_SERVER['HTTPS'] !== '') { return true; } if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https' || !empty($_SERVER['HTTP_X_FORWARDED_SSL']) && $_SERVER['HTTP_X_FORWARDED_SSL'] === 'on') { return true; } if (isset($_SERVER['SERVER_PROTOCOL']) && $_SERVER['SERVER_PROTOCOL'] === 'HTTP/3.0') { return true; } if (isset($_SERVER['REQUEST_SCHEME']) && ($_SERVER['REQUEST_SCHEME'] === 'quic' || $_SERVER['REQUEST_SCHEME'] === 'https')) { return true; } return false; } // Check user privileges function wwa_validate_privileges(){ return current_user_can('manage_options'); } // Get Related Origins Request list function wwa_get_ror_list(){ $raw = wwa_get_option('ror_origins'); if($raw === false || $raw === ''){ return array(); } $origins = array(); $lines = explode("\n", $raw); foreach($lines as $line){ $line = trim($line); if($line === ''){ continue; } $parsed = wp_parse_url($line); if(isset($parsed['scheme']) && isset($parsed['host'])){ $origin = $parsed['scheme'] . '://' . $parsed['host']; if(isset($parsed['port'])){ $origin .= ':' . $parsed['port']; } $origins[] = $origin; } } return $origins; } // Get user by username or email function wwa_get_user($username){ if(wwa_get_option('email_login') !== 'true'){ return get_user_by('login', $username); }else{ if(is_email($username)){ return get_user_by('email', $username); } return get_user_by('login', $username); } } // Provide plugin version for other plugins function wwa_loaded_version(){ if(!get_option('wwa_version')){ return '0.0.1'; } return get_option('wwa_version')['version']; } // Register query vars function wwa_query_vars($vars) { $vars[] = 'wwa-well-known-ror'; return $vars; } // Add rewrite rules for .well-known/webauthn function wwa_add_rewrite_rules() { add_rewrite_rule('^\.well-known/webauthn$', 'index.php?wwa-well-known-ror=true', 'top'); } function wwa_apply_rewrite_rules() { wwa_add_rewrite_rules(); flush_rewrite_rules(); } // Handle .well-known/webauthn function wwa_handle_ror($wp) { if (array_key_exists('wwa-well-known-ror', $wp->query_vars)) { header('Content-Type: application/json'); header('Access-Control-Allow-Origin: *'); echo wp_json_encode(array( 'origins'=> wwa_get_ror_list() )); exit; } } // Initialize plugin data for a new site created in a multisite network function wwa_new_site_init($new_site){ $network_active = get_site_option('active_sitewide_plugins'); if(isset($network_active['wp-webauthn/wp-webauthn.php'])){ switch_to_blog($new_site->id); wwa_init_data(); wwa_apply_rewrite_rules(); restore_current_blog(); } } add_action('wp_initialize_site', 'wwa_new_site_init'); add_filter('query_vars', 'wwa_query_vars'); add_action('parse_request', 'wwa_handle_ror', 99); add_action('init', 'wwa_add_rewrite_rules', 1);