Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Add dynamic TOTP functionality #36

Merged
merged 2 commits into from
Jan 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 41 additions & 2 deletions settings/rest-api.php
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
<?php

namespace WordPressdotorg\Two_Factor;
use Two_Factor_Core, Two_Factor_Backup_Codes;
use Two_Factor_Core, Two_Factor_Totp, Two_Factor_Backup_Codes;
use WP_REST_Server, WP_REST_Request;

defined( 'WPINC' ) || die();

add_action( 'rest_api_init', __NAMESPACE__ . '\register_rest_routes' );
add_action( 'rest_api_init', __NAMESPACE__ . '\register_user_fields' );
add_filter( 'rest_pre_insert_user', __NAMESPACE__ . '\require_email_confirmation', 10, 2 );

/**
* Register/Output some REST-API calls to be pre-loaded.
*
* This prevents the browser having to make the HTTP call before the react UI can be ready.
* This prevents the browser having to make the HTTP call before the React UI can be ready.
* This duplicates block_editor_rest_api_preload() as there is no generic function for performing this preloading.
* WARNING: This will output Javascript immediately if called during the page load if the wp-api-fetch script has already been output.
*
Expand Down Expand Up @@ -64,6 +66,43 @@ function preload_api_requests( array $preload_paths ) : void {
}
}

/**
* Register the rest-api endpoints required for this provider.
*/
function register_rest_routes() : void {
register_rest_route(
'wporg-two-factor/1.0',
'/totp-setup',
array(
'methods' => WP_REST_Server::READABLE,
'callback' => __NAMESPACE__ . '\rest_get_totp_setup',
'permission_callback' => function( $request ) {
return current_user_can( 'edit_user', $request['user_id'] );
},
'args' => array(
'user_id' => array(
'required' => true,
'type' => 'number',
),
),
),
);
}

/**
* Rest API endpoint for supplying data needed to set up TOTP.
*/
function rest_get_totp_setup( WP_REST_Request $request ) : array {
$user_id = absint( $request['user_id'] );
$user = get_user_by( 'id', $user_id );
$key = Two_Factor_Totp::generate_key();

return array(
'secret_key' => $key,
'qr_code_url' => Two_Factor_Totp::generate_qr_code_url( $user, $key ),
);
}

/**
* Register any user meta that needs to be exposed.
*/
Expand Down
8 changes: 8 additions & 0 deletions settings/settings.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php

namespace WordPressdotorg\Two_Factor;
use Two_Factor_Core;

defined( 'WPINC' ) || die();

Expand Down Expand Up @@ -51,6 +52,13 @@ function render_custom_ui() : void {
$preload_paths = [
'/wp/v2/users/' . $user_id . '?context=edit',
];

$enabled_providers = Two_Factor_Core::get_enabled_providers_for_user( $user_id );

if ( ! in_array( 'Two_Factor_Totp', $enabled_providers, true ) ) {
$preload_paths[] = "/wporg-two-factor/1.0/totp-setup?user_id=$user_id"; // todo not working, still see xhr request
}

preload_api_requests( $preload_paths );

echo do_blocks( "<!-- wp:wporg-two-factor/settings $json_attrs /-->" );
Expand Down
2 changes: 1 addition & 1 deletion settings/src/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"textdomain": "wporg",
"editorScript": "file:./index.js",
"editorStyle": "file:./index.css",
"script": [ "file:./script.js", "zxcvbn-async" ],
"script": [ "file:./script.js", "zxcvbn-async", "two-factor-qr-code-generator" ],
"style": [ "file:./style-index.css", "wp-components" ],
"render": "file:./render.php"
}
14 changes: 8 additions & 6 deletions settings/src/components/backup-codes.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/**
* Internal dependencies
*/
import SetupProgressBar from './setup-progress-bar';

//
export default function TOTP( { userRecord } ) {
const enabledProviders = Object.values( userRecord.record[ '2fa_enabled_providers' ] );
Expand All @@ -16,14 +21,11 @@ export default function TOTP( { userRecord } ) {
function Setup() {
return (
<>
<p>
Backup codes let you access your account if your phone is lost, stolen, or if you run it through the washing machine and the bag of rice trick doesn't work.
We ask that you print this list of ten unique, one-time-use backup codes and keep the list in a safe place.
</p>
<SetupProgressBar step="backup-codes" />

<p>
Backup codes let you access your account if your phone is lost or stolen, or even just accidentally run through the washing machine!

Backup codes let you access your account if your primary two-factor authentication method is unavailable, like if your phone is lost or stolen.
We ask that you print this list of ten unique, one-time-use backup codes and keep the list in a safe place.
</p>

<code>
Expand Down
20 changes: 20 additions & 0 deletions settings/src/components/setup-progress-bar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* WordPress dependencies
*/
import { Icon, lock, reusableBlock } from '@wordpress/icons';

export default function SetupProgressBar( { step } ) {
return (
<ul className="wporg-2fa__setup-steps">
<li className={ 'totp' === step ? 'is-enabled' : 'is-disabled' }>
<Icon icon={ lock } />
Verify Codes
</li>

<li className={ 'backup-codes' === step ? 'is-enabled' : 'is-disabled' }>
<Icon icon={ reusableBlock } />
Backup Codes
</li>
</ul>
);
}
11 changes: 11 additions & 0 deletions settings/src/components/setup-progress-bar.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// todo style this closer to the mockup
.wporg-2fa__setup-steps {
.is-enabled {
font-weight: bold;
color: blue; // todo use color var w/ correct color
}

.is-disabled {
color: grey; // todo use color var w/ correct color
}
}
Loading