option = new LoginDongleOption(); add_action('profile_personal_options', array($this, 'handleGET')); //owner view //add_action('personal_options_update', array($this, 'handlePOST')); //" add_action('edit_user_profile', array($this, 'handleGET')); //admin view add_action('profile_update', array($this, 'handlePOST')); //" } /** * Returns the default settings for the user option. * * @return struct */ protected function defaultSettings() { $hash = strtoupper(md5(time())); $result = array( 'challenge' => substr($hash, 0, 5), 'response' => substr($hash, -3, 3), ); return $result; } /** * Returns the code for the bookmarklet, based on the given challenge. * * @param struct $data * @return string */ protected function bookmarklet( $data ) { $challenge = $data['challenge']; if ('' == $challenge) { return; } $fieldName = LoginDonglePlugin::challengeFieldName($challenge); $blog_url = preg_replace('@^(https|http)://@', '', site_url()); //the following JS is semi-minified, just remove double spaces and new lines to fully minify it $result = <<< END_source (function($){ var form$=$('form[action*="://BLOG_URL/wp-login.php"]'); if(!form$.length) return alert('No form targeting the login at BLOG_URL.'); var challenge='CHALLENGE'; var response=$.trim(prompt(challenge,'')); $('') .appendTo(form$) .attr('name','FIELD_NAME') .attr('value',response); $('#wp-submit') .click() })(jQuery); END_source; $result = str_replace(' ', '', $result); $result = preg_replace("@\r?\n@", '', $result); $result = preg_replace('@\bBLOG_URL\b@', addslashes($blog_url), $result); $result = preg_replace('@\bCHALLENGE\b@', addslashes($challenge), $result); $result = preg_replace('@\bFIELD_NAME\b@', addslashes($fieldName), $result); return $result; } /** * Echoes the html for the user settings page. * * This method is a handler bound to the profile_personal_options and edit_user_profile action. * * @param WP_User $user */ public function handleGET($user) { $username = $user->user_login; $data = $this->option->get($username); if (! is_array($data)) { //$data = $this->defaultSettings(); $data = array( 'challenge' => '', 'response' => '', ); } if (! empty($data['challenge'])) { $code = $this->bookmarklet($data); $dongle_pc = 'javascript:' . htmlspecialchars(rawurlencode($code), ENT_COMPAT); //safest $dongle_sp = 'javascript:' . htmlspecialchars($code, ENT_COMPAT); } ?>
Login Dongle makes the login for your personal use only, by means of a conventional challenge >> response mechanism.
The challenge and its expected response resemble passwords, but are fundamentally different. This data is supposed to have enough complexity to deter the casual user of your PC, if any. So feel free to use simple pairs, but such that only you can easily associate the response to the challenge, while others will have a harder time. E.G. color >> ful. (For your security, please do not use this example literally!).
| Challenge |
1 to chars. Leave this empty to be able to log in without a login dongle. |
|---|---|
| Response |
1 to chars. |
| Encoded Bookmarklet (PC) |
Send on next update |
Show
|
| Raw Bookmarklet (SmartPhone) |
Send on next update |
Show
|
After saving any changes, you should drag and drop into your bookmarks this login dongle bookmarklet.
To be able to log into your blog using a different browser or a different system in the future,
check the Send on next update option above and click the Update button at the
bottom. You'll soon receive the bookmarklet code by email. Please note that
you yourself won't be able to log into your blog without your most current login dongle, unless
you disable this plugin right from the file system, as described in the
FAQ.