From 6da018f5367cfc2dc190f025e4ce2ee79c0e6e4d Mon Sep 17 00:00:00 2001
From: StevenDufresne
Date: Mon, 15 Jul 2024 15:32:11 +0900
Subject: [PATCH 01/49] Try a setup wizard.
---
settings/src/components/first-time.js | 113 ++++++++++++++++++
settings/src/components/first-time.scss | 18 +++
settings/src/components/screen-link.js | 1 -
settings/src/components/screen-navigation.js | 15 ++-
settings/src/components/settings.js | 43 +++++++
settings/src/components/setup-progress-bar.js | 8 +-
settings/src/components/totp.js | 4 +-
settings/src/script.js | 37 +-----
settings/src/style.scss | 1 +
9 files changed, 199 insertions(+), 41 deletions(-)
create mode 100644 settings/src/components/first-time.js
create mode 100644 settings/src/components/first-time.scss
create mode 100644 settings/src/components/settings.js
diff --git a/settings/src/components/first-time.js b/settings/src/components/first-time.js
new file mode 100644
index 00000000..5c23b818
--- /dev/null
+++ b/settings/src/components/first-time.js
@@ -0,0 +1,113 @@
+/**
+ * WordPress dependencies
+ */
+import { useContext, useState } from "@wordpress/element";
+import { Button, Flex } from "@wordpress/components";
+
+/**
+ * Internal dependencies
+ */
+import ScreenNavigation from "./screen-navigation";
+import TOTP from "./totp";
+import WebAuthn from "./webauthn/webauthn";
+import BackupCodes from "./backup-codes";
+import SetupProgressBar from "./setup-progress-bar";
+import { GlobalContext } from "../script";
+
+function DefaultView({ onSelect }) {
+ const [selectedOption, setSelectedOption] = useState("webauthn");
+
+ const handleOptionChange = (e) => {
+ setSelectedOption(e.target.value);
+ };
+
+ const handleButtonClick = () => {
+ if (selectedOption === "") {
+ return;
+ }
+
+ onSelect(selectedOption);
+ };
+
+ return (
+ <>
+
+ As of September 10, 2024, all plugin committers will be required to have
+ Two-Factor Authentication enabled.
+
+
+
+
+ Configure
+
+
+ Skip for now
+
+
+ >
+ );
+}
+
+/**
+ * Render the correct component based on the URL.
+ *
+ */
+export default function InitialSetup() {
+ const { navigateToScreen, screen } = useContext(GlobalContext);
+
+ // The index is the URL slug and the value is the React component.
+ const components = {
+ totp: ,
+ "backup-codes": ,
+ webauthn: ,
+ home: (
+ {
+ navigateToScreen( val);
+ } }
+ />
+ ),
+ };
+
+ const titles = {
+ 'home': 'Secure your account',
+ }
+
+
+ const currentScreenComponent = (
+
+
+ {components[screen]}
+ )
+
+ return (
+
+
+ {currentScreenComponent}
+
+
+ );
+}
diff --git a/settings/src/components/first-time.scss b/settings/src/components/first-time.scss
new file mode 100644
index 00000000..9a362ccd
--- /dev/null
+++ b/settings/src/components/first-time.scss
@@ -0,0 +1,18 @@
+.wporg-2fa__first-time {
+ display: flex;
+ justify-content: center;
+ position: fixed;
+ background: #fff;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ z-index: 1000;
+ padding-top: 100px;
+
+ .wporg-2fa__first-time__inner {
+ height: 50vh;
+ width: 60vw;
+ max-width: 800px;
+ }
+}
\ No newline at end of file
diff --git a/settings/src/components/screen-link.js b/settings/src/components/screen-link.js
index 2519c3db..415b2710 100644
--- a/settings/src/components/screen-link.js
+++ b/settings/src/components/screen-link.js
@@ -31,7 +31,6 @@ export default function ScreenLink( { screen, anchorText, buttonStyle = false, a
// implicitly verifying them, or at least needs to be treated that way. This should be removed once
// `two-factor/#507` is fixed, though.
setBackupCodesVerified( true );
-
navigateToScreen( screen );
},
[ navigateToScreen ]
diff --git a/settings/src/components/screen-navigation.js b/settings/src/components/screen-navigation.js
index ea8a5278..ef9f7932 100644
--- a/settings/src/components/screen-navigation.js
+++ b/settings/src/components/screen-navigation.js
@@ -13,12 +13,13 @@ import ScreenLink from './screen-link';
* @param props
* @param props.children
* @param props.screen
+ * @param props.title
*/
-const ScreenNavigation = ( { screen, children } ) => (
+const ScreenNavigation = ( { screen, children, title = '' } ) => (
@@ -29,10 +30,12 @@ const ScreenNavigation = ( { screen, children } ) => (
/>
- { screen
- .replace( '-', ' ' )
- .replace( 'totp', 'Two-Factor Authentication' )
- .replace( 'webauthn', 'Two-Factor Security Key' ) }
+ { title.length
+ ? title
+ : screen
+ .replace( '-', ' ' )
+ .replace( 'totp', 'Two-Factor Authentication' )
+ .replace( 'webauthn', 'Two-Factor Security Key' ) }
{ children }
diff --git a/settings/src/components/settings.js b/settings/src/components/settings.js
new file mode 100644
index 00000000..7cc3e08a
--- /dev/null
+++ b/settings/src/components/settings.js
@@ -0,0 +1,43 @@
+/**
+ * WordPress dependencies
+ */
+import { useContext } from '@wordpress/element';
+
+/**
+ * Internal dependencies
+ */
+import ScreenNavigation from './screen-navigation';
+import AccountStatus from './account-status';
+import Password from './password';
+import EmailAddress from './email-address';
+import TOTP from './totp';
+import WebAuthn from './webauthn/webauthn';
+import BackupCodes from './backup-codes';
+
+import { GlobalContext } from '../script';
+
+/**
+ * Render the correct component based on the URL.
+ */
+export default function Settings() {
+ const { screen } = useContext( GlobalContext );
+
+ // The index is the URL slug and the value is the React component.
+ const components = {
+ home: ,
+ email: ,
+ password: ,
+ totp: ,
+ 'backup-codes': ,
+ webauthn: ,
+ };
+
+ const currentScreenComponent =
+ 'home' === screen ? (
+ components[ screen ]
+ ) : (
+ { components[ screen ] }
+ );
+
+ return <>{ currentScreenComponent }>;
+}
diff --git a/settings/src/components/setup-progress-bar.js b/settings/src/components/setup-progress-bar.js
index 963d188f..2d8346b0 100644
--- a/settings/src/components/setup-progress-bar.js
+++ b/settings/src/components/setup-progress-bar.js
@@ -1,12 +1,18 @@
/**
* WordPress dependencies
*/
-import { Icon, lock, reusableBlock } from '@wordpress/icons';
+import { Icon, lock, edit, reusableBlock } from '@wordpress/icons';
export default function SetupProgressBar( { step } ) {
return (
+
+
+
+ Select type
+
+
diff --git a/settings/src/components/totp.js b/settings/src/components/totp.js
index 1f74bc6c..0f2d8953 100644
--- a/settings/src/components/totp.js
+++ b/settings/src/components/totp.js
@@ -12,6 +12,7 @@ import { RawHTML, useCallback, useContext, useEffect, useRef, useState } from '@
import ScreenLink from './screen-link';
import AutoTabbingInput from './auto-tabbing-input';
import { refreshRecord } from '../utilities/common';
+import SetupProgressBar from './setup-progress-bar';
import { GlobalContext } from '../script';
import Success from './success';
@@ -28,7 +29,7 @@ export default function TOTP() {
if ( ! backupCodesEnabled ) {
navigateToScreen( 'backup-codes' );
} else {
- navigateToScreen( 'account-status' );
+ navigateToScreen( 'home' );
}
}, [ backupCodesEnabled, navigateToScreen ] );
@@ -79,7 +80,6 @@ function Setup( { setSuccess } ) {
} );
setSecretKey( response.secret_key );
- setQrCodeUrl( response.qr_code_url );
};
fetchSetupData();
diff --git a/settings/src/script.js b/settings/src/script.js
index 62456ae6..694daa20 100644
--- a/settings/src/script.js
+++ b/settings/src/script.js
@@ -15,15 +15,10 @@ import { Spinner } from '@wordpress/components';
* Internal dependencies
*/
import { useUser } from './hooks/useUser';
-import ScreenNavigation from './components/screen-navigation';
-import AccountStatus from './components/account-status';
-import Password from './components/password';
-import EmailAddress from './components/email-address';
-import TOTP from './components/totp';
-import WebAuthn from './components/webauthn/webauthn';
-import BackupCodes from './components/backup-codes';
import GlobalNotice from './components/global-notice';
import RevalidateModal from './components/revalidate-modal';
+//import Settings from './components/settings';
+import FirstTime from './components/first-time';
export const GlobalContext = createContext( null );
@@ -65,25 +60,11 @@ function Main( { userId } ) {
let currentUrl = new URL( document.location.href );
const initialScreen = currentUrl.searchParams.get( 'screen' );
- const [ screen, setScreen ] = useState( initialScreen );
-
- // The index is the URL slug and the value is the React component.
- const components = {
- 'account-status': ,
- email: ,
- password: ,
- totp: ,
- 'backup-codes': ,
- webauthn: ,
- };
+ const [ screen, setScreen ] = useState( initialScreen === null ? 'home' : initialScreen );
// The screens where a recent two factor challenge is required.
const twoFactorRequiredScreens = [ 'webauthn', 'totp', 'backup-codes' ];
- if ( ! components[ screen ] ) {
- setScreen( 'account-status' );
- }
-
// Listen for back/forward button clicks.
useEffect( () => {
window.addEventListener( 'popstate', handlePopState );
@@ -130,7 +111,6 @@ function Main( { userId } ) {
currentUrl = new URL( document.location.href );
currentUrl.searchParams.set( 'screen', nextScreen );
window.history.pushState( {}, '', currentUrl );
-
setError( '' );
setGlobalNotice( '' );
setScreen( nextScreen );
@@ -142,13 +122,6 @@ function Main( { userId } ) {
return ;
}
- const currentScreenComponent =
- 'account-status' === screen ? (
- components[ screen ]
- ) : (
- { components[ screen ] }
- );
-
const isRevalidationExpired =
twoFactorRequiredScreens.includes( screen ) &&
hasPrimaryProvider &&
@@ -166,10 +139,12 @@ function Main( { userId } ) {
error,
backupCodesVerified,
setBackupCodesVerified,
+ setScreen,
+ screen,
} }
>
- { currentScreenComponent }
+
{ shouldRevalidate && }
);
diff --git a/settings/src/style.scss b/settings/src/style.scss
index d9320531..2baeca41 100644
--- a/settings/src/style.scss
+++ b/settings/src/style.scss
@@ -138,3 +138,4 @@ $alert-blue: #72aee6;
@import "components/auto-tabbing-input";
@import "components/revalidate-modal";
@import "components/success";
+@import "components/first-time";
From 64d38efa547e883aabe5aea66b6542b71fb7972a Mon Sep 17 00:00:00 2001
From: StevenDufresne
Date: Tue, 16 Jul 2024 15:46:08 +0900
Subject: [PATCH 02/49] More changes.
---
settings/src/components/backup-codes.js | 11 +-
settings/src/components/first-time.js | 179 +++++++++++++-----
settings/src/components/first-time.scss | 65 ++++++-
settings/src/components/screen-navigation.js | 25 +--
settings/src/components/settings.js | 14 +-
settings/src/components/setup-progress-bar.js | 68 ++++---
.../src/components/setup-progress-bar.scss | 60 +++---
settings/src/components/totp.js | 10 +-
8 files changed, 298 insertions(+), 134 deletions(-)
diff --git a/settings/src/components/backup-codes.js b/settings/src/components/backup-codes.js
index b9be260b..23da6a01 100644
--- a/settings/src/components/backup-codes.js
+++ b/settings/src/components/backup-codes.js
@@ -19,7 +19,7 @@ import DownloadButton from './download-button';
/**
* Setup and manage backup codes.
*/
-export default function BackupCodes() {
+export default function BackupCodes( { onSuccess = () => {} } ) {
const {
user: { backupCodesEnabled, hasPrimaryProvider, backupCodesRemaining },
backupCodesVerified,
@@ -47,7 +47,7 @@ export default function BackupCodes() {
regenerating ||
! backupCodesVerified
) {
- return ;
+ return ;
}
return ;
@@ -59,7 +59,7 @@ export default function BackupCodes() {
* @param props
* @param props.setRegenerating
*/
-function Setup( { setRegenerating } ) {
+function Setup( { setRegenerating, onSuccess } ) {
const {
setGlobalNotice,
user: { userRecord },
@@ -150,7 +150,10 @@ function Setup( { setRegenerating } ) {
{
+ setHasPrinted( ! hasPrinted );
+ onSuccess();
+ } }
disabled={ error }
/>
>
diff --git a/settings/src/components/first-time.js b/settings/src/components/first-time.js
index 5c23b818..2ce6c101 100644
--- a/settings/src/components/first-time.js
+++ b/settings/src/components/first-time.js
@@ -1,71 +1,92 @@
/**
* WordPress dependencies
*/
-import { useContext, useState } from "@wordpress/element";
-import { Button, Flex } from "@wordpress/components";
+import { useCallback, useContext, useState } from '@wordpress/element';
+import { Button, Flex } from '@wordpress/components';
+import { lock, edit, reusableBlock } from '@wordpress/icons';
/**
* Internal dependencies
*/
-import ScreenNavigation from "./screen-navigation";
-import TOTP from "./totp";
-import WebAuthn from "./webauthn/webauthn";
-import BackupCodes from "./backup-codes";
-import SetupProgressBar from "./setup-progress-bar";
-import { GlobalContext } from "../script";
+import ScreenNavigation from './screen-navigation';
+import TOTP from './totp';
+import WebAuthn from './webauthn/webauthn';
+import BackupCodes from './backup-codes';
+import SetupProgressBar from './setup-progress-bar';
+import { GlobalContext } from '../script';
-function DefaultView({ onSelect }) {
- const [selectedOption, setSelectedOption] = useState("webauthn");
+const WordPressLogo = () => (
+
+
+
+
+
+);
- const handleOptionChange = (e) => {
- setSelectedOption(e.target.value);
+function DefaultView( { onSelect } ) {
+ const [ selectedOption, setSelectedOption ] = useState( 'totp' );
+
+ const handleOptionChange = ( event ) => {
+ setSelectedOption( event.target.value );
};
const handleButtonClick = () => {
- if (selectedOption === "") {
+ if ( selectedOption === '' ) {
return;
}
- onSelect(selectedOption);
+ onSelect( selectedOption );
};
return (
<>
- As of September 10, 2024, all plugin committers will be required to have
- Two-Factor Authentication enabled.
+ As of September 10, 2024 , all plugin committers will be required to have Two-Factor
+ Authentication enabled.
-
-
-
+
+
Configure
-
- Skip for now
-
>
);
@@ -76,38 +97,92 @@ function DefaultView({ onSelect }) {
*
*/
export default function InitialSetup() {
- const { navigateToScreen, screen } = useContext(GlobalContext);
+ const { navigateToScreen, screen } = useContext( GlobalContext );
+ const [ steps, setSteps ] = useState( [
+ {
+ id: 'home',
+ title: 'Select Method',
+ icon: edit,
+ },
+ {
+ id: 'totp',
+ title: 'Configure',
+ icon: lock,
+ },
+ {
+ id: 'backup-codes',
+ title: 'Backup Codes',
+ icon: reusableBlock,
+ },
+ ] );
// The index is the URL slug and the value is the React component.
const components = {
- totp: ,
- "backup-codes": ,
+ totp: (
+ {
+ navigateToScreen( 'backup-codes' );
+ } }
+ />
+ ),
+ 'backup-codes': (
+ {
+ navigateToScreen( 'congratulations' );
+ } }
+ />
+ ),
webauthn: ,
home: (
{
- navigateToScreen( val);
+ onSelect={ ( val ) => {
+ navigateToScreen( val );
+
+ /* This updates the second item in the steps array to be the right id */
+ setSteps( ( prevSteps ) => {
+ const updatedSteps = [ ...prevSteps ];
+
+ updatedSteps[ 1 ] = {
+ ...updatedSteps[ 1 ],
+ id: val,
+ };
+
+ return updatedSteps;
+ } );
} }
/>
),
+ congratulations: (
+
+
Two-Factor Authentication is now enabled.
+
+ You can now
+
+ page.
+
+
+ ),
};
- const titles = {
- 'home': 'Secure your account',
- }
-
+ const currentStepIndex = useCallback( () => {
+ return steps.findIndex( ( step ) => step.id === screen );
+ }, [ screen, steps ] )();
const currentScreenComponent = (
-
-
- {components[screen]}
- )
+
+
+ { components[ screen ] }
+
+ );
return (
-
- {currentScreenComponent}
-
+
+
{ currentScreenComponent }
);
}
diff --git a/settings/src/components/first-time.scss b/settings/src/components/first-time.scss
index 9a362ccd..c3c30a04 100644
--- a/settings/src/components/first-time.scss
+++ b/settings/src/components/first-time.scss
@@ -1,6 +1,7 @@
.wporg-2fa__first-time {
display: flex;
- justify-content: center;
+ flex-direction: column;
+ align-items: center;
position: fixed;
background: #fff;
top: 0;
@@ -8,11 +9,65 @@
width: 100%;
height: 100%;
z-index: 1000;
- padding-top: 100px;
+ padding-top: 80px;
.wporg-2fa__first-time__inner {
+ margin-top: 20px;
height: 50vh;
- width: 60vw;
- max-width: 800px;
+ width: 90vw;
+ max-width: 700px;
}
-}
\ No newline at end of file
+
+ .wporg-2fa__first-time-default {
+ padding: 16px 0 0;
+ display: flex;
+ flex-direction: column;
+ gap: 24px;
+ }
+
+ .wporg-2fa__first-time-default-item {
+ margin: 6px;
+ position: relative;
+ display: flex;
+ gap: 10px;
+ align-items: flex-start;
+
+ span {
+ font-weight: 600;
+ z-index: 1;
+ }
+
+ input {
+ position: relative;
+ z-index: 1;
+ margin-top: 4px;
+ margin-left: 4px;
+ }
+
+ input:checked + div::before {
+ position: absolute;
+ content: '';
+ border: 1px solid var(--wp--preset--color--charcoal-3, #40464d);
+ border-radius: 4px;
+ height: 140%;
+ width: 102%;
+ left: -1%;
+ top: -20%;
+ z-index: 0;
+ }
+
+ > div {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+
+ p {
+ color: var(--wp--preset--color--charcoal-4, #656a71);
+ margin: 0;
+ z-index: 1;
+ }
+ }
+ }
+
+}
+
diff --git a/settings/src/components/screen-navigation.js b/settings/src/components/screen-navigation.js
index ef9f7932..2fc32d88 100644
--- a/settings/src/components/screen-navigation.js
+++ b/settings/src/components/screen-navigation.js
@@ -15,19 +15,22 @@ import ScreenLink from './screen-link';
* @param props.screen
* @param props.title
*/
-const ScreenNavigation = ( { screen, children, title = '' } ) => (
+// eslint-disable-next-line no-unused-vars
+const ScreenNavigation = ( { screen, children, title = '', canNavigate = true } ) => (
-
-
- Back
- >
- }
- />
+ { canNavigate && (
+
+
+ Back
+ >
+ }
+ />
+ ) }
{ title.length
diff --git a/settings/src/components/settings.js b/settings/src/components/settings.js
index 7cc3e08a..bcb156de 100644
--- a/settings/src/components/settings.js
+++ b/settings/src/components/settings.js
@@ -20,14 +20,24 @@ import { GlobalContext } from '../script';
* Render the correct component based on the URL.
*/
export default function Settings() {
- const { screen } = useContext( GlobalContext );
+ const { backupCodesEnabled, navigateToScreen, screen } = useContext( GlobalContext );
// The index is the URL slug and the value is the React component.
const components = {
home: ,
email: ,
password: ,
- totp: ,
+ totp: (
+ {
+ if ( ! backupCodesEnabled ) {
+ navigateToScreen( 'backup-codes' );
+ } else {
+ navigateToScreen( 'home' );
+ }
+ } }
+ />
+ ),
'backup-codes': ,
webauthn: ,
};
diff --git a/settings/src/components/setup-progress-bar.js b/settings/src/components/setup-progress-bar.js
index 2d8346b0..b6fca99c 100644
--- a/settings/src/components/setup-progress-bar.js
+++ b/settings/src/components/setup-progress-bar.js
@@ -1,43 +1,49 @@
/**
* WordPress dependencies
*/
-import { Icon, lock, edit, reusableBlock } from '@wordpress/icons';
+import { useCallback } from '@wordpress/element';
+import { Icon, check } from '@wordpress/icons';
-export default function SetupProgressBar( { step } ) {
- return (
-
-
-
-
-
- Select type
-
-
-
-
-
- Scan QR Code
-
+export default function SetupProgressBar( { currentStep, steps } ) {
+ const currentIndex = steps.findIndex( ( step ) => step.id === currentStep );
+ const getCompletionPercentage = useCallback(
+ () => ( ( currentIndex + 1 ) / steps.length ) * 100,
+ [ currentIndex, steps.length ]
+ );
-
-
-
- Backup Codes
-
-
+ const getStepClass = ( index ) => {
+ if ( index === currentIndex ) {
+ return 'is-enabled';
+ }
-
-
+ if ( currentIndex > index ) {
+ return 'is-complete';
+ }
-
+ return 'is-disabled';
+ };
-
+ return (
+
+
+ { steps.map( ( step, index ) => (
+
+ index ? check : step.icon }
+ />
+ { step.title }
+
+ ) ) }
+
+
);
}
diff --git a/settings/src/components/setup-progress-bar.scss b/settings/src/components/setup-progress-bar.scss
index b8146f30..543db4bc 100644
--- a/settings/src/components/setup-progress-bar.scss
+++ b/settings/src/components/setup-progress-bar.scss
@@ -1,7 +1,7 @@
.wporg-2fa__progress-bar,
#bbpress-forums .wporg-2fa__progress-bar,
#bbpress-forums.bbpress-wrapper .wporg-2fa__progress-bar {
- --color-enabled: #0475c4;
+ --color-enabled: #1e1e1e;
--color-disabled: #{$gray-400};
--color-disabled-text: #{$gray-700}; // Darker than `color-disabled` to meet a11y contrast standards.
@@ -10,12 +10,20 @@
.wporg-2fa__setup-steps {
position: relative;
+ margin-bottom: 40px;
z-index: 2; /* On top of the separators. */
display: flex;
justify-content: space-evenly; /* Align the steps up with the separators. */
li {
text-align: center;
+ width: 125px;
+
+ .wporg-2fa__setup-label {
+ display: block;
+ margin-top: 8px;
+ font-size: 12px;
+ }
}
svg {
@@ -26,7 +34,6 @@
}
li.is-enabled {
- font-weight: bold;
color: var(--color-enabled);
svg {
@@ -45,29 +52,38 @@
fill: var(--color-disabled);
}
}
- }
-
- .wporg-2fa__setup-step-separators {
- display: flex;
- justify-content: space-between; /* Align the separators up with the steps. */
- position: absolute;
- top: 27px;
- z-index: 1; /* Under the steps. */
- width: 100%;
-
- li {
- height: 3px;
- flex-basis: 33%;
- flex-grow: 1;
- flex-shrink: 1;
- &.is-enabled {
- background-color: var(--color-enabled);
- }
+ li.is-complete {
+ color: var(--color-disabled-text);
- &.is-disabled {
- background-color: var(--color-disabled);
+ svg {
+ background-color: var(--wp--preset--color--blueberry-1, #3858e9);
+ border-color: var(--wp--preset--color--blueberry-1, #3858e9);
+ fill: white;
}
}
}
}
+
+.wporg-2fa__progress-bar {
+ margin: 0;
+}
+
+.wporg-2fa__progress-bar .wporg-2fa__setup-step-separator::before {
+ content: '';
+ position: absolute;
+ height: 2px;
+ width: var(--wporg-separator-width, 0%);
+ background: var(--wp--preset--color--blueberry-1, #3858e9);
+ z-index: 1;
+}
+
+.wporg-2fa__progress-bar .wporg-2fa__setup-step-separator {
+ position: absolute;
+ height: 2px;
+ width: 100%;
+ top: 25px;
+ z-index: 0;
+ background: var(--color-disabled);
+ z-index: 0;
+}
\ No newline at end of file
diff --git a/settings/src/components/totp.js b/settings/src/components/totp.js
index 0f2d8953..f7d29a61 100644
--- a/settings/src/components/totp.js
+++ b/settings/src/components/totp.js
@@ -12,11 +12,10 @@ import { RawHTML, useCallback, useContext, useEffect, useRef, useState } from '@
import ScreenLink from './screen-link';
import AutoTabbingInput from './auto-tabbing-input';
import { refreshRecord } from '../utilities/common';
-import SetupProgressBar from './setup-progress-bar';
import { GlobalContext } from '../script';
import Success from './success';
-export default function TOTP() {
+export default function TOTP( { onSuccess } ) {
const {
user: { backupCodesEnabled, totpEnabled },
navigateToScreen,
@@ -26,11 +25,7 @@ export default function TOTP() {
const afterTimeout = useCallback( () => {
setSuccess( false );
- if ( ! backupCodesEnabled ) {
- navigateToScreen( 'backup-codes' );
- } else {
- navigateToScreen( 'home' );
- }
+ onSuccess();
}, [ backupCodesEnabled, navigateToScreen ] );
if ( success ) {
@@ -80,6 +75,7 @@ function Setup( { setSuccess } ) {
} );
setSecretKey( response.secret_key );
+ setQrCodeUrl( response.qr_code_url );
};
fetchSetupData();
From a3fc16e97e9d6135fe439790e80303ddc33c7870 Mon Sep 17 00:00:00 2001
From: StevenDufresne
Date: Wed, 17 Jul 2024 15:40:31 +0900
Subject: [PATCH 03/49] More changes
---
settings/src/components/backup-codes.js | 10 +-
.../src/components/first-time/first-time.js | 147 +++++++++++++++
.../{ => first-time}/first-time.scss | 38 +++-
settings/src/components/first-time/home.js | 62 +++++++
.../{ => first-time}/setup-progress-bar.js | 19 +-
.../{ => first-time}/setup-progress-bar.scss | 14 +-
.../wordpress-logo.js} | 174 +-----------------
settings/src/components/webauthn/webauthn.js | 6 +-
settings/src/script.js | 2 +-
settings/src/style.scss | 4 +-
10 files changed, 269 insertions(+), 207 deletions(-)
create mode 100644 settings/src/components/first-time/first-time.js
rename settings/src/components/{ => first-time}/first-time.scss (69%)
create mode 100644 settings/src/components/first-time/home.js
rename settings/src/components/{ => first-time}/setup-progress-bar.js (61%)
rename settings/src/components/{ => first-time}/setup-progress-bar.scss (86%)
rename settings/src/components/{first-time.js => first-time/wordpress-logo.js} (54%)
diff --git a/settings/src/components/backup-codes.js b/settings/src/components/backup-codes.js
index 23da6a01..86bf2979 100644
--- a/settings/src/components/backup-codes.js
+++ b/settings/src/components/backup-codes.js
@@ -18,6 +18,9 @@ import DownloadButton from './download-button';
/**
* Setup and manage backup codes.
+ *
+ * @param props
+ * @param props.onSuccess
*/
export default function BackupCodes( { onSuccess = () => {} } ) {
const {
@@ -58,6 +61,7 @@ export default function BackupCodes( { onSuccess = () => {} } ) {
*
* @param props
* @param props.setRegenerating
+ * @param props.onSuccess
*/
function Setup( { setRegenerating, onSuccess } ) {
const {
@@ -111,6 +115,7 @@ function Setup( { setRegenerating, onSuccess } ) {
await refreshRecord( userRecord ); // This has the intended side-effect of redirecting to the Manage screen.
setGlobalNotice( 'Backup codes have been enabled.' );
setRegenerating( false );
+ onSuccess();
} );
return (
@@ -150,10 +155,7 @@ function Setup( { setRegenerating, onSuccess } ) {
{
- setHasPrinted( ! hasPrinted );
- onSuccess();
- } }
+ onChange={ setHasPrinted }
disabled={ error }
/>
>
diff --git a/settings/src/components/first-time/first-time.js b/settings/src/components/first-time/first-time.js
new file mode 100644
index 00000000..17605841
--- /dev/null
+++ b/settings/src/components/first-time/first-time.js
@@ -0,0 +1,147 @@
+/**
+ * WordPress dependencies
+ */
+import { useEffect, useContext } from '@wordpress/element';
+import { Button } from '@wordpress/components';
+import { lock, edit, reusableBlock } from '@wordpress/icons';
+
+/**
+ * Internal dependencies
+ */
+import ScreenNavigation from '../screen-navigation';
+import TOTP from '../totp';
+import WebAuthn from '../webauthn/webauthn';
+import BackupCodes from '../backup-codes';
+import SetupProgressBar from './setup-progress-bar';
+import Home from './home';
+import WordPressLogo from './wordpress-logo';
+import { GlobalContext } from '../../script';
+
+/**
+ * Render the correct component based on the URL.
+ *
+ */
+export default function FirstTime() {
+ const { navigateToScreen, screen } = useContext( GlobalContext );
+ const steps = [
+ {
+ title: 'Choose an authentication method',
+ label: 'Select',
+ icon: edit,
+ },
+ {
+ title: 'Set up your authentication method',
+ label: 'Configure',
+ icon: lock,
+ },
+ {
+ title: 'Print Backup Codes',
+ label: 'Print',
+ icon: reusableBlock,
+ },
+ ];
+
+ // The index is the URL slug and the value is the React component.
+ const screens = {
+ home: {
+ stepIndex: 0,
+ component: (
+ {
+ navigateToScreen( val );
+ } }
+ />
+ ),
+ },
+ totp: {
+ stepIndex: 1,
+ component: (
+ {
+ navigateToScreen( 'backup-codes' );
+ } }
+ />
+ ),
+ },
+ webauthn: {
+ stepIndex: 1,
+ component: (
+ {
+ navigateToScreen( 'backup-codes' );
+ } }
+ />
+ ),
+ },
+ 'backup-codes': {
+ stepIndex: 2,
+ component: (
+ {
+ navigateToScreen( 'congratulations' );
+ } }
+ />
+ ),
+ },
+ congratulations: {
+ stepIndex: 3,
+ component: (
+
+
Two-factor authentication setup is now complete! 🎉
+
+ To ensure the highest level of security for your account, please remember to
+ keep your authentication methods up to date. We recommend configuring
+ multiple authentication methods to guarantee you always have access to your
+ account.
+
+
+ Continue
+
+
+ ),
+ },
+ };
+
+ // Lock the scroll when the modal is open.
+ useEffect( () => {
+ document.querySelector( 'html' ).style.overflow = 'hidden';
+
+ return () => {
+ document.querySelector( 'html' ).style.overflow = 'initial';
+ };
+ }, [] );
+
+ const currentStepIndex = screens[ screen ].stepIndex;
+ let currentScreenComponent = null;
+
+ if ( 'congratulations' === screen ) {
+ currentScreenComponent = (
+
+ { screens[ screen ].component }
+
+ );
+ } else {
+ currentScreenComponent = (
+
+
+ { screens[ screen ].component }
+
+ );
+ }
+
+ return (
+
+
+
+
+ { currentScreenComponent }
+
+
+
+
+ );
+}
diff --git a/settings/src/components/first-time.scss b/settings/src/components/first-time/first-time.scss
similarity index 69%
rename from settings/src/components/first-time.scss
rename to settings/src/components/first-time/first-time.scss
index c3c30a04..26e6f728 100644
--- a/settings/src/components/first-time.scss
+++ b/settings/src/components/first-time/first-time.scss
@@ -1,7 +1,4 @@
.wporg-2fa__first-time {
- display: flex;
- flex-direction: column;
- align-items: center;
position: fixed;
background: #fff;
top: 0;
@@ -9,13 +6,36 @@
width: 100%;
height: 100%;
z-index: 1000;
- padding-top: 80px;
+
.wporg-2fa__first-time__inner {
+ padding: 80px 0;
margin-top: 20px;
- height: 50vh;
- width: 90vw;
- max-width: 700px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ width: 100%;
+ height: 100%;
+ overflow: scroll;
+ }
+
+ .wporg-2fa__first-time__inner-content {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+
+ @media (min-width: 600px) {
+ width: 600px;
+ }
+
+ > svg {
+ margin-bottom: 16px;
+ }
+
+ // Preven cards from shrinking.
+ .components-card {
+ width: 100%;
+ }
}
.wporg-2fa__first-time-default {
@@ -68,6 +88,8 @@
}
}
}
-
}
+.wporg-2fa__congratulations h3 {
+ margin-bottom: 14px;
+}
diff --git a/settings/src/components/first-time/home.js b/settings/src/components/first-time/home.js
new file mode 100644
index 00000000..6d99ecff
--- /dev/null
+++ b/settings/src/components/first-time/home.js
@@ -0,0 +1,62 @@
+/**
+ * WordPress dependencies
+ */
+import { useState } from '@wordpress/element';
+import { Button, Flex } from '@wordpress/components';
+
+export default function Select( { onSelect } ) {
+ const [ selectedOption, setSelectedOption ] = useState( 'totp' );
+
+ const handleOptionChange = ( event ) => {
+ setSelectedOption( event.target.value );
+ };
+
+ const handleButtonClick = () => {
+ if ( selectedOption === '' ) {
+ return;
+ }
+
+ onSelect( selectedOption );
+ };
+
+ return (
+ <>
+ Select a method to configure two-factor authentication for your account.
+
+
+
+
+
Setup One Time Password
+
Use an application to get two-factor authentication codes.
+
+
+
+
+
+
Setup Security Key
+
Use biometrics, digital cryptography, or hardware keys.
+
+
+
+
+
+ Configure two-factor
+
+
+ >
+ );
+}
diff --git a/settings/src/components/setup-progress-bar.js b/settings/src/components/first-time/setup-progress-bar.js
similarity index 61%
rename from settings/src/components/setup-progress-bar.js
rename to settings/src/components/first-time/setup-progress-bar.js
index b6fca99c..4d7652be 100644
--- a/settings/src/components/setup-progress-bar.js
+++ b/settings/src/components/first-time/setup-progress-bar.js
@@ -4,19 +4,18 @@
import { useCallback } from '@wordpress/element';
import { Icon, check } from '@wordpress/icons';
-export default function SetupProgressBar( { currentStep, steps } ) {
- const currentIndex = steps.findIndex( ( step ) => step.id === currentStep );
+export default function SetupProgressBar( { currentStepIndex, steps } ) {
const getCompletionPercentage = useCallback(
- () => ( ( currentIndex + 1 ) / steps.length ) * 100,
- [ currentIndex, steps.length ]
+ () => ( currentStepIndex / ( steps.length - 1 ) ) * 100,
+ [ currentStepIndex, steps.length ]
);
const getStepClass = ( index ) => {
- if ( index === currentIndex ) {
+ if ( index === currentStepIndex ) {
return 'is-enabled';
}
- if ( currentIndex > index ) {
+ if ( currentStepIndex > index ) {
return 'is-complete';
}
@@ -29,11 +28,11 @@ export default function SetupProgressBar( { currentStep, steps } ) {
{ steps.map( ( step, index ) => (
index ? check : step.icon }
+ width="16px"
+ height="16px"
+ icon={ currentStepIndex > index ? check : step.icon }
/>
- { step.title }
+ { step.label }
) ) }
diff --git a/settings/src/components/setup-progress-bar.scss b/settings/src/components/first-time/setup-progress-bar.scss
similarity index 86%
rename from settings/src/components/setup-progress-bar.scss
rename to settings/src/components/first-time/setup-progress-bar.scss
index 543db4bc..fcf4eed8 100644
--- a/settings/src/components/setup-progress-bar.scss
+++ b/settings/src/components/first-time/setup-progress-bar.scss
@@ -6,29 +6,26 @@
--color-disabled-text: #{$gray-700}; // Darker than `color-disabled` to meet a11y contrast standards.
position: relative;
- margin: 0 -24px; /* Separators need to stretch to edges of container. */
.wporg-2fa__setup-steps {
position: relative;
- margin-bottom: 40px;
+ margin-bottom: 32px;
z-index: 2; /* On top of the separators. */
display: flex;
- justify-content: space-evenly; /* Align the steps up with the separators. */
+ justify-content: space-between;
li {
text-align: center;
- width: 125px;
.wporg-2fa__setup-label {
display: block;
- margin-top: 8px;
font-size: 12px;
}
}
svg {
box-sizing: content-box;
- padding: 15px;
+ padding: 8px;
border: 1px solid;
border-radius: 30px;
}
@@ -80,9 +77,10 @@
.wporg-2fa__progress-bar .wporg-2fa__setup-step-separator {
position: absolute;
+ width: 96%;
height: 2px;
- width: 100%;
- top: 25px;
+ margin-left: 2%;
+ top: 16px;
z-index: 0;
background: var(--color-disabled);
z-index: 0;
diff --git a/settings/src/components/first-time.js b/settings/src/components/first-time/wordpress-logo.js
similarity index 54%
rename from settings/src/components/first-time.js
rename to settings/src/components/first-time/wordpress-logo.js
index 2ce6c101..aec32250 100644
--- a/settings/src/components/first-time.js
+++ b/settings/src/components/first-time/wordpress-logo.js
@@ -1,21 +1,4 @@
-/**
- * WordPress dependencies
- */
-import { useCallback, useContext, useState } from '@wordpress/element';
-import { Button, Flex } from '@wordpress/components';
-import { lock, edit, reusableBlock } from '@wordpress/icons';
-
-/**
- * Internal dependencies
- */
-import ScreenNavigation from './screen-navigation';
-import TOTP from './totp';
-import WebAuthn from './webauthn/webauthn';
-import BackupCodes from './backup-codes';
-import SetupProgressBar from './setup-progress-bar';
-import { GlobalContext } from '../script';
-
-const WordPressLogo = () => (
+export default () => (
(
>
);
-
-function DefaultView( { onSelect } ) {
- const [ selectedOption, setSelectedOption ] = useState( 'totp' );
-
- const handleOptionChange = ( event ) => {
- setSelectedOption( event.target.value );
- };
-
- const handleButtonClick = () => {
- if ( selectedOption === '' ) {
- return;
- }
-
- onSelect( selectedOption );
- };
-
- return (
- <>
-
- As of September 10, 2024 , all plugin committers will be required to have Two-Factor
- Authentication enabled.
-
-
-
-
-
-
Setup One Time Password
-
Use an application to get two-factor authentication codes.
-
-
-
-
-
-
Setup Security Key
-
Use biometrics, digital cryptography, or hardware keys.
-
-
-
-
-
- Configure
-
-
- >
- );
-}
-
-/**
- * Render the correct component based on the URL.
- *
- */
-export default function InitialSetup() {
- const { navigateToScreen, screen } = useContext( GlobalContext );
- const [ steps, setSteps ] = useState( [
- {
- id: 'home',
- title: 'Select Method',
- icon: edit,
- },
- {
- id: 'totp',
- title: 'Configure',
- icon: lock,
- },
- {
- id: 'backup-codes',
- title: 'Backup Codes',
- icon: reusableBlock,
- },
- ] );
-
- // The index is the URL slug and the value is the React component.
- const components = {
- totp: (
-
{
- navigateToScreen( 'backup-codes' );
- } }
- />
- ),
- 'backup-codes': (
- {
- navigateToScreen( 'congratulations' );
- } }
- />
- ),
- webauthn: ,
- home: (
- {
- navigateToScreen( val );
-
- /* This updates the second item in the steps array to be the right id */
- setSteps( ( prevSteps ) => {
- const updatedSteps = [ ...prevSteps ];
-
- updatedSteps[ 1 ] = {
- ...updatedSteps[ 1 ],
- id: val,
- };
-
- return updatedSteps;
- } );
- } }
- />
- ),
- congratulations: (
-
-
Two-Factor Authentication is now enabled.
-
- You can now
-
- page.
-
-
- ),
- };
-
- const currentStepIndex = useCallback( () => {
- return steps.findIndex( ( step ) => step.id === screen );
- }, [ screen, steps ] )();
-
- const currentScreenComponent = (
-
-
- { components[ screen ] }
-
- );
-
- return (
-
-
-
{ currentScreenComponent }
-
- );
-}
diff --git a/settings/src/components/webauthn/webauthn.js b/settings/src/components/webauthn/webauthn.js
index 43fac9ae..d6f6f276 100644
--- a/settings/src/components/webauthn/webauthn.js
+++ b/settings/src/components/webauthn/webauthn.js
@@ -16,8 +16,11 @@ import RegisterKey from './register-key';
/**
* Render the WebAuthn setting.
+ *
+ * @param {Object} props
+ * @param {Function} props.onKeyAdd
*/
-export default function WebAuthn() {
+export default function WebAuthn( { onKeyAdd = () => {} } ) {
const {
user: { userRecord, webAuthnEnabled },
setGlobalNotice,
@@ -96,6 +99,7 @@ export default function WebAuthn() {
}
updateFlow( 'manage' );
+ onKeyAdd();
}, [ webAuthnEnabled, toggleProvider, updateFlow ] );
if ( 'register' === flow ) {
diff --git a/settings/src/script.js b/settings/src/script.js
index 694daa20..fd933276 100644
--- a/settings/src/script.js
+++ b/settings/src/script.js
@@ -18,7 +18,7 @@ import { useUser } from './hooks/useUser';
import GlobalNotice from './components/global-notice';
import RevalidateModal from './components/revalidate-modal';
//import Settings from './components/settings';
-import FirstTime from './components/first-time';
+import FirstTime from './components/first-time/first-time';
export const GlobalContext = createContext( null );
diff --git a/settings/src/style.scss b/settings/src/style.scss
index 2baeca41..5dad1b15 100644
--- a/settings/src/style.scss
+++ b/settings/src/style.scss
@@ -131,11 +131,11 @@ $alert-blue: #72aee6;
@import "components/webauthn/webauthn";
@import "components/totp";
@import "components/backup-codes";
-@import "components/setup-progress-bar";
@import "components/global-notice";
@import "components/screen-link";
@import "components/screen-navigation";
@import "components/auto-tabbing-input";
@import "components/revalidate-modal";
@import "components/success";
-@import "components/first-time";
+@import "components/first-time/first-time";
+@import "components/first-time/setup-progress-bar";
From 53131c5904a3debc3b0b3dc615a6447e4a4d530b Mon Sep 17 00:00:00 2001
From: StevenDufresne
Date: Wed, 17 Jul 2024 16:00:29 +0900
Subject: [PATCH 04/49] Fix the linter.
---
settings/src/components/first-time/first-time.js | 1 -
settings/src/components/first-time/first-time.scss | 5 ++++-
settings/src/components/first-time/home.js | 5 +++--
settings/src/components/screen-navigation.js | 1 +
settings/src/components/totp.js | 5 ++---
settings/src/components/webauthn/webauthn.js | 2 +-
settings/src/script.js | 9 +++++++--
7 files changed, 18 insertions(+), 10 deletions(-)
diff --git a/settings/src/components/first-time/first-time.js b/settings/src/components/first-time/first-time.js
index 17605841..8d8ba04d 100644
--- a/settings/src/components/first-time/first-time.js
+++ b/settings/src/components/first-time/first-time.js
@@ -139,7 +139,6 @@ export default function FirstTime() {
{ currentScreenComponent }
-
diff --git a/settings/src/components/first-time/first-time.scss b/settings/src/components/first-time/first-time.scss
index 26e6f728..e5efd855 100644
--- a/settings/src/components/first-time/first-time.scss
+++ b/settings/src/components/first-time/first-time.scss
@@ -7,7 +7,6 @@
height: 100%;
z-index: 1000;
-
.wporg-2fa__first-time__inner {
padding: 80px 0;
margin-top: 20px;
@@ -36,6 +35,10 @@
.components-card {
width: 100%;
}
+
+ .components-card__body {
+ padding: 32px;
+ }
}
.wporg-2fa__first-time-default {
diff --git a/settings/src/components/first-time/home.js b/settings/src/components/first-time/home.js
index 6d99ecff..d7f9d95c 100644
--- a/settings/src/components/first-time/home.js
+++ b/settings/src/components/first-time/home.js
@@ -1,3 +1,4 @@
+/* eslint-disable jsx-a11y/label-has-associated-control */
/**
* WordPress dependencies
*/
@@ -23,7 +24,7 @@ export default function Select( { onSelect } ) {
<>
Select a method to configure two-factor authentication for your account.
-
+
Use an application to get two-factor authentication codes.
-
+
(
diff --git a/settings/src/components/totp.js b/settings/src/components/totp.js
index f7d29a61..cee144ab 100644
--- a/settings/src/components/totp.js
+++ b/settings/src/components/totp.js
@@ -17,8 +17,7 @@ import Success from './success';
export default function TOTP( { onSuccess } ) {
const {
- user: { backupCodesEnabled, totpEnabled },
- navigateToScreen,
+ user: { totpEnabled },
} = useContext( GlobalContext );
const [ success, setSuccess ] = useState( false );
@@ -26,7 +25,7 @@ export default function TOTP( { onSuccess } ) {
setSuccess( false );
onSuccess();
- }, [ backupCodesEnabled, navigateToScreen ] );
+ }, [ onSuccess ] );
if ( success ) {
return (
diff --git a/settings/src/components/webauthn/webauthn.js b/settings/src/components/webauthn/webauthn.js
index d6f6f276..cd74fd4f 100644
--- a/settings/src/components/webauthn/webauthn.js
+++ b/settings/src/components/webauthn/webauthn.js
@@ -100,7 +100,7 @@ export default function WebAuthn( { onKeyAdd = () => {} } ) {
updateFlow( 'manage' );
onKeyAdd();
- }, [ webAuthnEnabled, toggleProvider, updateFlow ] );
+ }, [ webAuthnEnabled, toggleProvider, updateFlow, onKeyAdd ] );
if ( 'register' === flow ) {
return (
diff --git a/settings/src/script.js b/settings/src/script.js
index fd933276..5d15a4c3 100644
--- a/settings/src/script.js
+++ b/settings/src/script.js
@@ -17,7 +17,7 @@ import { Spinner } from '@wordpress/components';
import { useUser } from './hooks/useUser';
import GlobalNotice from './components/global-notice';
import RevalidateModal from './components/revalidate-modal';
-//import Settings from './components/settings';
+import Settings from './components/settings';
import FirstTime from './components/first-time/first-time';
export const GlobalContext = createContext( null );
@@ -144,7 +144,12 @@ function Main( { userId } ) {
} }
>
-
+
+ { new URLSearchParams( window.location.search ).get( 'first-time' ) ? (
+
+ ) : (
+
+ ) }
{ shouldRevalidate && }
);
From 7b4c74905fdcdde0e2d7c2428ce03e29a0a1efd1 Mon Sep 17 00:00:00 2001
From: StevenDufresne
Date: Wed, 17 Jul 2024 16:05:24 +0900
Subject: [PATCH 05/49] Clean up
---
settings/src/components/first-time/setup-progress-bar.scss | 7 +++----
settings/src/components/screen-link.js | 1 +
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/settings/src/components/first-time/setup-progress-bar.scss b/settings/src/components/first-time/setup-progress-bar.scss
index fcf4eed8..7228ccaf 100644
--- a/settings/src/components/first-time/setup-progress-bar.scss
+++ b/settings/src/components/first-time/setup-progress-bar.scss
@@ -77,11 +77,10 @@
.wporg-2fa__progress-bar .wporg-2fa__setup-step-separator {
position: absolute;
+ margin-left: 2%;
+ background: var(--color-disabled);
width: 96%;
height: 2px;
- margin-left: 2%;
- top: 16px;
- z-index: 0;
- background: var(--color-disabled);
+ top: 16px;
z-index: 0;
}
\ No newline at end of file
diff --git a/settings/src/components/screen-link.js b/settings/src/components/screen-link.js
index 415b2710..2519c3db 100644
--- a/settings/src/components/screen-link.js
+++ b/settings/src/components/screen-link.js
@@ -31,6 +31,7 @@ export default function ScreenLink( { screen, anchorText, buttonStyle = false, a
// implicitly verifying them, or at least needs to be treated that way. This should be removed once
// `two-factor/#507` is fixed, though.
setBackupCodesVerified( true );
+
navigateToScreen( screen );
},
[ navigateToScreen ]
From 7aaecf89a0955e979bb502857b17c590a45e0be9 Mon Sep 17 00:00:00 2001
From: StevenDufresne
Date: Thu, 18 Jul 2024 15:52:59 +0900
Subject: [PATCH 06/49] Update account-status to be 'home'.
---
settings/src/components/backup-codes.js | 5 +----
settings/src/components/first-time/home.js | 2 +-
settings/src/components/revalidate-modal.js | 2 +-
3 files changed, 3 insertions(+), 6 deletions(-)
diff --git a/settings/src/components/backup-codes.js b/settings/src/components/backup-codes.js
index 86bf2979..2b170cb7 100644
--- a/settings/src/components/backup-codes.js
+++ b/settings/src/components/backup-codes.js
@@ -35,10 +35,7 @@ export default function BackupCodes( { onSuccess = () => {} } ) {
Please
-
+
before enabling backup codes.
);
diff --git a/settings/src/components/first-time/home.js b/settings/src/components/first-time/home.js
index d7f9d95c..fc77e1f3 100644
--- a/settings/src/components/first-time/home.js
+++ b/settings/src/components/first-time/home.js
@@ -55,7 +55,7 @@ export default function Select( { onSelect } ) {
- Configure two-factor
+ Configure Two-Factor
>
diff --git a/settings/src/components/revalidate-modal.js b/settings/src/components/revalidate-modal.js
index 0962e09e..195a2e2b 100644
--- a/settings/src/components/revalidate-modal.js
+++ b/settings/src/components/revalidate-modal.js
@@ -13,7 +13,7 @@ export default function RevalidateModal() {
const goBack = useCallback(
( event ) => {
event.preventDefault();
- navigateToScreen( 'account-status' );
+ navigateToScreen( 'home' );
},
[ navigateToScreen ]
);
From 98335e823ae3f074592959b6838f90735c2e9af9 Mon Sep 17 00:00:00 2001
From: StevenDufresne
Date: Thu, 18 Jul 2024 15:53:50 +0900
Subject: [PATCH 07/49] Add back empty line.
---
settings/src/script.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/settings/src/script.js b/settings/src/script.js
index 5d15a4c3..788c645d 100644
--- a/settings/src/script.js
+++ b/settings/src/script.js
@@ -111,6 +111,7 @@ function Main( { userId } ) {
currentUrl = new URL( document.location.href );
currentUrl.searchParams.set( 'screen', nextScreen );
window.history.pushState( {}, '', currentUrl );
+
setError( '' );
setGlobalNotice( '' );
setScreen( nextScreen );
From e347ab34fa95b887566cce8080df41645e1be68a Mon Sep 17 00:00:00 2001
From: StevenDufresne
Date: Thu, 8 Aug 2024 16:03:18 +0900
Subject: [PATCH 08/49] Update copy.
---
settings/src/components/first-time/first-time.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/settings/src/components/first-time/first-time.js b/settings/src/components/first-time/first-time.js
index 8d8ba04d..062f00e2 100644
--- a/settings/src/components/first-time/first-time.js
+++ b/settings/src/components/first-time/first-time.js
@@ -90,7 +90,7 @@ export default function FirstTime() {
Two-factor authentication setup is now complete! 🎉
To ensure the highest level of security for your account, please remember to
- keep your authentication methods up to date. We recommend configuring
+ keep your authentication methods up-to-date. We recommend configuring
multiple authentication methods to guarantee you always have access to your
account.
From 3673f39800081558d8406025b79f6bfd98144815 Mon Sep 17 00:00:00 2001
From: StevenDufresne
Date: Thu, 8 Aug 2024 16:20:30 +0900
Subject: [PATCH 09/49] Add redirect logic.
---
.../src/components/first-time/first-time.js | 32 ++++++++++++++++++-
1 file changed, 31 insertions(+), 1 deletion(-)
diff --git a/settings/src/components/first-time/first-time.js b/settings/src/components/first-time/first-time.js
index 062f00e2..f8573d49 100644
--- a/settings/src/components/first-time/first-time.js
+++ b/settings/src/components/first-time/first-time.js
@@ -17,6 +17,20 @@ import Home from './home';
import WordPressLogo from './wordpress-logo';
import { GlobalContext } from '../../script';
+/**
+ * Check if the URL is valid. Make sure it stays on wordpress.org.
+ * @param url
+ * @return {boolean} Whether it's a valid URL.
+ */
+const isValidUrl = ( url ) => {
+ try {
+ const { hostname } = new URL( url );
+ return hostname.endsWith( 'wordpress.org' );
+ } catch ( exception ) {
+ return false;
+ }
+};
+
/**
* Render the correct component based on the URL.
*
@@ -95,7 +109,23 @@ export default function FirstTime() {
account.
- Continue
+ {
+ const redirectTo = new URLSearchParams(
+ window.location.search
+ ).get( 'redirect_to' );
+
+ if ( redirectTo && isValidUrl( redirectTo ) ) {
+ window.location.href = redirectTo;
+ } else {
+ window.location.href =
+ '//profiles.wordpress.org/me/profile/edit/group/1';
+ }
+ } }
+ isPrimary
+ >
+ Continue
+
),
From 16ab35f6b9e3b05d82889666ae7f928ef5172149 Mon Sep 17 00:00:00 2001
From: StevenDufresne
Date: Fri, 9 Aug 2024 10:52:27 +0900
Subject: [PATCH 10/49] Fix spacing.
---
settings/src/components/first-time/first-time.scss | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/settings/src/components/first-time/first-time.scss b/settings/src/components/first-time/first-time.scss
index e5efd855..2c8439eb 100644
--- a/settings/src/components/first-time/first-time.scss
+++ b/settings/src/components/first-time/first-time.scss
@@ -8,8 +8,7 @@
z-index: 1000;
.wporg-2fa__first-time__inner {
- padding: 80px 0;
- margin-top: 20px;
+ box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: center;
@@ -19,6 +18,7 @@
}
.wporg-2fa__first-time__inner-content {
+ padding: 6vh 16px;
display: flex;
flex-direction: column;
align-items: center;
From a4152b5a1fbae0803bba2237e8f53147c83d6062 Mon Sep 17 00:00:00 2001
From: StevenDufresne
Date: Fri, 9 Aug 2024 11:18:13 +0900
Subject: [PATCH 11/49] Improve css.
---
settings/src/components/backup-codes.scss | 6 ++++++
settings/src/components/first-time/first-time.scss | 6 +++---
2 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/settings/src/components/backup-codes.scss b/settings/src/components/backup-codes.scss
index 4d2e47a3..a9f6b158 100644
--- a/settings/src/components/backup-codes.scss
+++ b/settings/src/components/backup-codes.scss
@@ -13,6 +13,12 @@
margin: 0;
}
+ @media (max-width: 600px) {
+ ol {
+ column-count: 1;
+ }
+ }
+
li::marker {
/* todo: a11y issues w/ contrast here? mockup calls for this to be lighter than the backup code
-- presumably so that users don't mistakenly think it's part of the code --
diff --git a/settings/src/components/first-time/first-time.scss b/settings/src/components/first-time/first-time.scss
index 2c8439eb..c85be52e 100644
--- a/settings/src/components/first-time/first-time.scss
+++ b/settings/src/components/first-time/first-time.scss
@@ -42,18 +42,18 @@
}
.wporg-2fa__first-time-default {
- padding: 16px 0 0;
display: flex;
flex-direction: column;
gap: 24px;
}
.wporg-2fa__first-time-default-item {
- margin: 6px;
+ margin: 6px !important;
position: relative;
display: flex;
gap: 10px;
align-items: flex-start;
+ cursor: pointer;
span {
font-weight: 600;
@@ -64,7 +64,7 @@
position: relative;
z-index: 1;
margin-top: 4px;
- margin-left: 4px;
+ margin-left: 6px;
}
input:checked + div::before {
From 0db3f198f02173f5b59672652a902db9d75ef692 Mon Sep 17 00:00:00 2001
From: StevenDufresne
Date: Fri, 9 Aug 2024 11:18:26 +0900
Subject: [PATCH 12/49] Font show if they have a primary.
---
settings/src/script.js | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/settings/src/script.js b/settings/src/script.js
index 788c645d..c53b84d8 100644
--- a/settings/src/script.js
+++ b/settings/src/script.js
@@ -54,6 +54,7 @@ function Main( { userId } ) {
userRecord: { record, edit, hasEdits, hasResolved },
hasPrimaryProvider,
} = user;
+
const [ globalNotice, setGlobalNotice ] = useState( '' );
const [ error, setError ] = useState( '' );
const [ backupCodesVerified, setBackupCodesVerified ] = useState( true );
@@ -146,7 +147,8 @@ function Main( { userId } ) {
>
- { new URLSearchParams( window.location.search ).get( 'first-time' ) ? (
+ { ! hasPrimaryProvider &&
+ new URLSearchParams( window.location.search ).get( 'first-time' ) ? (
) : (
From 7d8b9e10241f07f761d89ca19d3144870fb25e5d Mon Sep 17 00:00:00 2001
From: StevenDufresne
Date: Fri, 9 Aug 2024 11:26:54 +0900
Subject: [PATCH 13/49] We can't check via the component because it reloads.
---
settings/src/script.js | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/settings/src/script.js b/settings/src/script.js
index c53b84d8..393b07b2 100644
--- a/settings/src/script.js
+++ b/settings/src/script.js
@@ -147,8 +147,7 @@ function Main( { userId } ) {
>
- { ! hasPrimaryProvider &&
- new URLSearchParams( window.location.search ).get( 'first-time' ) ? (
+ { new URLSearchParams( window.location.search ).get( 'first-time' ) ? (
) : (
From 70aa9c44d8bc7db74953a80491bf1b330162d00d Mon Sep 17 00:00:00 2001
From: StevenDufresne
Date: Fri, 9 Aug 2024 11:45:50 +0900
Subject: [PATCH 14/49] Remove eslint disable line.
---
settings/src/components/screen-navigation.js | 1 -
1 file changed, 1 deletion(-)
diff --git a/settings/src/components/screen-navigation.js b/settings/src/components/screen-navigation.js
index 1ed88af0..a21967c5 100644
--- a/settings/src/components/screen-navigation.js
+++ b/settings/src/components/screen-navigation.js
@@ -16,7 +16,6 @@ import ScreenLink from './screen-link';
* @param props.title
* @param props.canNavigate
*/
-// eslint-disable-next-line no-unused-vars
const ScreenNavigation = ( { screen, children, title = '', canNavigate = true } ) => (
From 213d2d4abcab8e136074c6da4f5ead1a194c6071 Mon Sep 17 00:00:00 2001
From: StevenDufresne
Date: Fri, 9 Aug 2024 11:47:37 +0900
Subject: [PATCH 15/49] Remove empty line.
---
settings/src/script.js | 1 -
1 file changed, 1 deletion(-)
diff --git a/settings/src/script.js b/settings/src/script.js
index 393b07b2..788c645d 100644
--- a/settings/src/script.js
+++ b/settings/src/script.js
@@ -54,7 +54,6 @@ function Main( { userId } ) {
userRecord: { record, edit, hasEdits, hasResolved },
hasPrimaryProvider,
} = user;
-
const [ globalNotice, setGlobalNotice ] = useState( '' );
const [ error, setError ] = useState( '' );
const [ backupCodesVerified, setBackupCodesVerified ] = useState( true );
From 8c1e2ead3ce4509c44b390ea24de0307ea044238 Mon Sep 17 00:00:00 2001
From: StevenDufresne
Date: Mon, 12 Aug 2024 07:41:05 +0900
Subject: [PATCH 16/49] Clean up formatting.
---
.wp-env.override.json | 14 ++++++++++++++
settings/src/components/first-time/first-time.js | 2 +-
settings/src/script.js | 2 +-
3 files changed, 16 insertions(+), 2 deletions(-)
create mode 100644 .wp-env.override.json
diff --git a/.wp-env.override.json b/.wp-env.override.json
new file mode 100644
index 00000000..44117726
--- /dev/null
+++ b/.wp-env.override.json
@@ -0,0 +1,14 @@
+{
+ "plugins": [
+ "https://downloads.wordpress.org/plugin/gutenberg.latest-stable.zip",
+ "https://downloads.wordpress.org/plugin/bbpress.latest-stable.zip",
+ "../two-factor",
+ "../wp-two-factor-provider-webauthn",
+ "."
+ ],
+ "mappings": {
+ "wp-content/themes/wporg-support": "WordPress/wordpress.org/wordpress.org/public_html/wp-content/themes/pub/wporg-support/",
+ "wp-content/mu-plugins/pub/": "WordPress/wporg-mu-plugins#build",
+ "wp-content/mu-plugins/mu-plugin.php": "./.wp-env/mu-plugin.php"
+ }
+}
diff --git a/settings/src/components/first-time/first-time.js b/settings/src/components/first-time/first-time.js
index f8573d49..a6cc7dda 100644
--- a/settings/src/components/first-time/first-time.js
+++ b/settings/src/components/first-time/first-time.js
@@ -19,6 +19,7 @@ import { GlobalContext } from '../../script';
/**
* Check if the URL is valid. Make sure it stays on wordpress.org.
+ *
* @param url
* @return {boolean} Whether it's a valid URL.
*/
@@ -33,7 +34,6 @@ const isValidUrl = ( url ) => {
/**
* Render the correct component based on the URL.
- *
*/
export default function FirstTime() {
const { navigateToScreen, screen } = useContext( GlobalContext );
diff --git a/settings/src/script.js b/settings/src/script.js
index 788c645d..fc2da6e9 100644
--- a/settings/src/script.js
+++ b/settings/src/script.js
@@ -129,7 +129,7 @@ function Main( { userId } ) {
record[ '2fa_revalidation' ]?.expires_at <= new Date().getTime() / 1000;
const shouldRevalidate = 'revalidation_required' === error.code || isRevalidationExpired;
-
+debugger;
return (
Date: Mon, 12 Aug 2024 07:43:33 +0900
Subject: [PATCH 17/49] Revert "Clean up formatting."
This reverts commit 0b635733a6ce174b421369e3eccdcbe015ddd5b0.
---
.wp-env.override.json | 14 --------------
settings/src/components/first-time/first-time.js | 2 +-
settings/src/script.js | 2 +-
3 files changed, 2 insertions(+), 16 deletions(-)
delete mode 100644 .wp-env.override.json
diff --git a/.wp-env.override.json b/.wp-env.override.json
deleted file mode 100644
index 44117726..00000000
--- a/.wp-env.override.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "plugins": [
- "https://downloads.wordpress.org/plugin/gutenberg.latest-stable.zip",
- "https://downloads.wordpress.org/plugin/bbpress.latest-stable.zip",
- "../two-factor",
- "../wp-two-factor-provider-webauthn",
- "."
- ],
- "mappings": {
- "wp-content/themes/wporg-support": "WordPress/wordpress.org/wordpress.org/public_html/wp-content/themes/pub/wporg-support/",
- "wp-content/mu-plugins/pub/": "WordPress/wporg-mu-plugins#build",
- "wp-content/mu-plugins/mu-plugin.php": "./.wp-env/mu-plugin.php"
- }
-}
diff --git a/settings/src/components/first-time/first-time.js b/settings/src/components/first-time/first-time.js
index a6cc7dda..f8573d49 100644
--- a/settings/src/components/first-time/first-time.js
+++ b/settings/src/components/first-time/first-time.js
@@ -19,7 +19,6 @@ import { GlobalContext } from '../../script';
/**
* Check if the URL is valid. Make sure it stays on wordpress.org.
- *
* @param url
* @return {boolean} Whether it's a valid URL.
*/
@@ -34,6 +33,7 @@ const isValidUrl = ( url ) => {
/**
* Render the correct component based on the URL.
+ *
*/
export default function FirstTime() {
const { navigateToScreen, screen } = useContext( GlobalContext );
diff --git a/settings/src/script.js b/settings/src/script.js
index fc2da6e9..788c645d 100644
--- a/settings/src/script.js
+++ b/settings/src/script.js
@@ -129,7 +129,7 @@ function Main( { userId } ) {
record[ '2fa_revalidation' ]?.expires_at <= new Date().getTime() / 1000;
const shouldRevalidate = 'revalidation_required' === error.code || isRevalidationExpired;
-debugger;
+
return (
Date: Mon, 12 Aug 2024 07:44:10 +0900
Subject: [PATCH 18/49] clean up formatting.
---
settings/src/components/first-time/first-time.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/settings/src/components/first-time/first-time.js b/settings/src/components/first-time/first-time.js
index f8573d49..a6cc7dda 100644
--- a/settings/src/components/first-time/first-time.js
+++ b/settings/src/components/first-time/first-time.js
@@ -19,6 +19,7 @@ import { GlobalContext } from '../../script';
/**
* Check if the URL is valid. Make sure it stays on wordpress.org.
+ *
* @param url
* @return {boolean} Whether it's a valid URL.
*/
@@ -33,7 +34,6 @@ const isValidUrl = ( url ) => {
/**
* Render the correct component based on the URL.
- *
*/
export default function FirstTime() {
const { navigateToScreen, screen } = useContext( GlobalContext );
From a494064b00d74101597044dfe3e84e4441dd085f Mon Sep 17 00:00:00 2001
From: StevenDufresne
Date: Mon, 12 Aug 2024 09:50:10 +0900
Subject: [PATCH 19/49] Lowercase setup radial.
---
settings/src/components/first-time/home.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/settings/src/components/first-time/home.js b/settings/src/components/first-time/home.js
index fc77e1f3..ea7337f0 100644
--- a/settings/src/components/first-time/home.js
+++ b/settings/src/components/first-time/home.js
@@ -34,7 +34,7 @@ export default function Select( { onSelect } ) {
onChange={ handleOptionChange }
/>
-
Setup One Time Password
+
Setup one time password
Use an application to get two-factor authentication codes.
@@ -48,7 +48,7 @@ export default function Select( { onSelect } ) {
onChange={ handleOptionChange }
/>
-
Setup Security Key
+
Setup security key
Use biometrics, digital cryptography, or hardware keys.
From 919094f9484dfee1392dc2f81c3da7825e192cdc Mon Sep 17 00:00:00 2001
From: StevenDufresne
Date: Mon, 12 Aug 2024 10:15:10 +0900
Subject: [PATCH 20/49] Trap the keyboard focus within the window.
---
.../src/components/first-time/first-time.js | 42 +++++++++++++++++--
1 file changed, 39 insertions(+), 3 deletions(-)
diff --git a/settings/src/components/first-time/first-time.js b/settings/src/components/first-time/first-time.js
index a6cc7dda..d06b1f99 100644
--- a/settings/src/components/first-time/first-time.js
+++ b/settings/src/components/first-time/first-time.js
@@ -1,7 +1,7 @@
/**
* WordPress dependencies
*/
-import { useEffect, useContext } from '@wordpress/element';
+import { useEffect, useContext, useRef } from '@wordpress/element';
import { Button } from '@wordpress/components';
import { lock, edit, reusableBlock } from '@wordpress/icons';
@@ -36,6 +36,7 @@ const isValidUrl = ( url ) => {
* Render the correct component based on the URL.
*/
export default function FirstTime() {
+ const modalRef = useRef( null );
const { navigateToScreen, screen } = useContext( GlobalContext );
const steps = [
{
@@ -134,12 +135,47 @@ export default function FirstTime() {
// Lock the scroll when the modal is open.
useEffect( () => {
+ const modal = modalRef.current;
+ const focusableElements = modal.querySelectorAll(
+ 'a, button, input, textarea, select, [tabindex]:not([tabindex="-1"])'
+ );
+ const firstFocusableElement = focusableElements[ 0 ];
+ const lastFocusableElement = focusableElements[ focusableElements.length - 1 ];
+
+ const trapFocus = ( event ) => {
+ const isTabPressed = event.key === 'Tab' || event.keyCode === 9;
+ if ( ! isTabPressed ) {
+ return;
+ }
+
+ if ( event.shiftKey ) {
+ // eslint-disable-next-line @wordpress/no-global-active-element
+ if ( document.activeElement === firstFocusableElement ) {
+ lastFocusableElement.focus();
+ event.preventDefault();
+ }
+ return;
+ }
+
+ // eslint-disable-next-line @wordpress/no-global-active-element
+ if ( document.activeElement === lastFocusableElement ) {
+ firstFocusableElement.focus();
+ event.preventDefault();
+ }
+ };
+
+ modal.addEventListener( 'keydown', trapFocus );
+
document.querySelector( 'html' ).style.overflow = 'hidden';
+ // Focus the first focusable element in the modal when it opens
+ firstFocusableElement.focus();
+
return () => {
+ modal.removeEventListener( 'keydown', trapFocus );
document.querySelector( 'html' ).style.overflow = 'initial';
};
- }, [] );
+ }, [ screen ] );
const currentStepIndex = screens[ screen ].stepIndex;
let currentScreenComponent = null;
@@ -164,7 +200,7 @@ export default function FirstTime() {
}
return (
-
+
From 21213a951e6f2794a088f31d8bd939b0c9eed5d2 Mon Sep 17 00:00:00 2001
From: StevenDufresne
Date: Mon, 12 Aug 2024 10:57:34 +0900
Subject: [PATCH 21/49] Update the padding-top for the wizard.
---
settings/src/components/first-time/first-time.scss | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/settings/src/components/first-time/first-time.scss b/settings/src/components/first-time/first-time.scss
index c85be52e..ee429c2b 100644
--- a/settings/src/components/first-time/first-time.scss
+++ b/settings/src/components/first-time/first-time.scss
@@ -18,7 +18,7 @@
}
.wporg-2fa__first-time__inner-content {
- padding: 6vh 16px;
+ padding: 8vh 16px;
display: flex;
flex-direction: column;
align-items: center;
From 6d9b0b6a4127dde1563e9c546c22fb67357bbdc7 Mon Sep 17 00:00:00 2001
From: StevenDufresne
Date: Mon, 12 Aug 2024 11:10:42 +0900
Subject: [PATCH 22/49] Update the component name.
---
settings/src/components/first-time/home.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/settings/src/components/first-time/home.js b/settings/src/components/first-time/home.js
index ea7337f0..608c2a5d 100644
--- a/settings/src/components/first-time/home.js
+++ b/settings/src/components/first-time/home.js
@@ -5,7 +5,7 @@
import { useState } from '@wordpress/element';
import { Button, Flex } from '@wordpress/components';
-export default function Select( { onSelect } ) {
+export default function Home( { onSelect } ) {
const [ selectedOption, setSelectedOption ] = useState( 'totp' );
const handleOptionChange = ( event ) => {
From f6e32879ed1782ed23fa420a048cdb388823a3a5 Mon Sep 17 00:00:00 2001
From: Steven Dufresne
Date: Mon, 12 Aug 2024 11:43:18 +0900
Subject: [PATCH 23/49] Update settings/src/components/first-time/first-time.js
Co-authored-by: Adam Wood <1017872+adamwoodnz@users.noreply.github.com>
---
settings/src/components/first-time/first-time.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/settings/src/components/first-time/first-time.js b/settings/src/components/first-time/first-time.js
index d06b1f99..05f3ab61 100644
--- a/settings/src/components/first-time/first-time.js
+++ b/settings/src/components/first-time/first-time.js
@@ -133,7 +133,7 @@ export default function FirstTime() {
},
};
- // Lock the scroll when the modal is open.
+ // Lock the scroll when the modal is open, and trap tab navigation.
useEffect( () => {
const modal = modalRef.current;
const focusableElements = modal.querySelectorAll(
From 6a5aaaa916b4ed1e23ff39be0a522643720f8d75 Mon Sep 17 00:00:00 2001
From: StevenDufresne
Date: Mon, 12 Aug 2024 13:03:32 +0900
Subject: [PATCH 24/49] Prefer keys as the first option.
---
settings/src/components/first-time/home.js | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/settings/src/components/first-time/home.js b/settings/src/components/first-time/home.js
index 608c2a5d..85b63ea1 100644
--- a/settings/src/components/first-time/home.js
+++ b/settings/src/components/first-time/home.js
@@ -27,29 +27,29 @@ export default function Home( { onSelect } ) {
-
Setup one time password
-
Use an application to get two-factor authentication codes.
+
Setup security key
+
Use biometrics, digital cryptography, or hardware keys.
-
Setup security key
-
Use biometrics, digital cryptography, or hardware keys.
+
Setup one time password
+
Use an application to get two-factor authentication codes.
From e8ab11ef9035f059a16944f8d9b0e7e17b4eeec1 Mon Sep 17 00:00:00 2001
From: StevenDufresne
Date: Mon, 12 Aug 2024 13:27:37 +0900
Subject: [PATCH 25/49] Move progress indicator about window.
---
settings/src/components/first-time/first-time.scss | 4 +++-
.../src/components/first-time/setup-progress-bar.scss | 10 ++++++----
2 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/settings/src/components/first-time/first-time.scss b/settings/src/components/first-time/first-time.scss
index ee429c2b..9b7bdb6a 100644
--- a/settings/src/components/first-time/first-time.scss
+++ b/settings/src/components/first-time/first-time.scss
@@ -28,7 +28,8 @@
}
> svg {
- margin-bottom: 16px;
+ margin-bottom: 32px;
+ width: 250px;
}
// Preven cards from shrinking.
@@ -38,6 +39,7 @@
.components-card__body {
padding: 32px;
+ padding-top: 16px;
}
}
diff --git a/settings/src/components/first-time/setup-progress-bar.scss b/settings/src/components/first-time/setup-progress-bar.scss
index 7228ccaf..03d6f8a4 100644
--- a/settings/src/components/first-time/setup-progress-bar.scss
+++ b/settings/src/components/first-time/setup-progress-bar.scss
@@ -1,7 +1,7 @@
.wporg-2fa__progress-bar,
#bbpress-forums .wporg-2fa__progress-bar,
#bbpress-forums.bbpress-wrapper .wporg-2fa__progress-bar {
- --color-enabled: #1e1e1e;
+ --color-enabled: var(--wp--preset--color--blueberry-1, #3858e9);
--color-disabled: #{$gray-400};
--color-disabled-text: #{$gray-700}; // Darker than `color-disabled` to meet a11y contrast standards.
@@ -31,7 +31,7 @@
}
li.is-enabled {
- color: var(--color-enabled);
+ color: var(--wp--preset--color--charcoal-1 #1e1e1e);
svg {
background-color: var(--color-enabled);
@@ -54,8 +54,8 @@
color: var(--color-disabled-text);
svg {
- background-color: var(--wp--preset--color--blueberry-1, #3858e9);
- border-color: var(--wp--preset--color--blueberry-1, #3858e9);
+ background-color: var(--color-enabled);
+ border-color: var(--color-enabled);
fill: white;
}
}
@@ -64,6 +64,8 @@
.wporg-2fa__progress-bar {
margin: 0;
+ width: 100%;
+ max-width: 350px;
}
.wporg-2fa__progress-bar .wporg-2fa__setup-step-separator::before {
From f4cd78bdeec1da3bc46ac4bb8f6505272c8c2df0 Mon Sep 17 00:00:00 2001
From: StevenDufresne
Date: Mon, 12 Aug 2024 13:27:55 +0900
Subject: [PATCH 26/49] Default to 2fa view.
---
settings/src/components/first-time/first-time.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/settings/src/components/first-time/first-time.js b/settings/src/components/first-time/first-time.js
index 05f3ab61..f069dd05 100644
--- a/settings/src/components/first-time/first-time.js
+++ b/settings/src/components/first-time/first-time.js
@@ -120,7 +120,7 @@ export default function FirstTime() {
window.location.href = redirectTo;
} else {
window.location.href =
- '//profiles.wordpress.org/me/profile/edit/group/1';
+ '//profiles.wordpress.org/me/profile/edit/group/3';
}
} }
isPrimary
From ea309fdf7440b57237502c7f911ed23368721d24 Mon Sep 17 00:00:00 2001
From: StevenDufresne
Date: Mon, 12 Aug 2024 13:47:10 +0900
Subject: [PATCH 27/49] move the progress component.
---
settings/src/components/first-time/first-time.js | 16 +++++++++-------
1 file changed, 9 insertions(+), 7 deletions(-)
diff --git a/settings/src/components/first-time/first-time.js b/settings/src/components/first-time/first-time.js
index f069dd05..d139e8f9 100644
--- a/settings/src/components/first-time/first-time.js
+++ b/settings/src/components/first-time/first-time.js
@@ -188,14 +188,16 @@ export default function FirstTime() {
);
} else {
currentScreenComponent = (
-
+ <>
- { screens[ screen ].component }
-
+
+ { screens[ screen ].component }
+
+ >
);
}
From 5268407026ec1b4f008ae2bfa6e0228a1f2e3c56 Mon Sep 17 00:00:00 2001
From: StevenDufresne
Date: Mon, 12 Aug 2024 13:47:55 +0900
Subject: [PATCH 28/49] Update selected radial to be webauthn.
---
settings/src/components/first-time/home.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/settings/src/components/first-time/home.js b/settings/src/components/first-time/home.js
index 85b63ea1..c9fc9467 100644
--- a/settings/src/components/first-time/home.js
+++ b/settings/src/components/first-time/home.js
@@ -6,7 +6,7 @@ import { useState } from '@wordpress/element';
import { Button, Flex } from '@wordpress/components';
export default function Home( { onSelect } ) {
- const [ selectedOption, setSelectedOption ] = useState( 'totp' );
+ const [ selectedOption, setSelectedOption ] = useState( 'webauthn' );
const handleOptionChange = ( event ) => {
setSelectedOption( event.target.value );
From 4354dbe414636c2809d4070136bca46cadc8e8e3 Mon Sep 17 00:00:00 2001
From: StevenDufresne
Date: Mon, 12 Aug 2024 13:52:41 +0900
Subject: [PATCH 29/49] Fix react error with map key.
---
settings/src/components/first-time/setup-progress-bar.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/settings/src/components/first-time/setup-progress-bar.js b/settings/src/components/first-time/setup-progress-bar.js
index 4d7652be..b7020eda 100644
--- a/settings/src/components/first-time/setup-progress-bar.js
+++ b/settings/src/components/first-time/setup-progress-bar.js
@@ -26,7 +26,7 @@ export default function SetupProgressBar( { currentStepIndex, steps } ) {
{ steps.map( ( step, index ) => (
-
+
Date: Mon, 12 Aug 2024 14:06:31 +0900
Subject: [PATCH 30/49] Update radio list styles.
---
.../src/components/first-time/first-time.scss | 17 +++--------------
1 file changed, 3 insertions(+), 14 deletions(-)
diff --git a/settings/src/components/first-time/first-time.scss b/settings/src/components/first-time/first-time.scss
index 9b7bdb6a..30961526 100644
--- a/settings/src/components/first-time/first-time.scss
+++ b/settings/src/components/first-time/first-time.scss
@@ -46,11 +46,12 @@
.wporg-2fa__first-time-default {
display: flex;
flex-direction: column;
- gap: 24px;
+ gap: 18px;
+ padding-top: 8px;
}
.wporg-2fa__first-time-default-item {
- margin: 6px !important;
+ margin: 0;
position: relative;
display: flex;
gap: 10px;
@@ -69,18 +70,6 @@
margin-left: 6px;
}
- input:checked + div::before {
- position: absolute;
- content: '';
- border: 1px solid var(--wp--preset--color--charcoal-3, #40464d);
- border-radius: 4px;
- height: 140%;
- width: 102%;
- left: -1%;
- top: -20%;
- z-index: 0;
- }
-
> div {
display: flex;
flex-direction: column;
From 23bf7b4ddbe43d20248b0169d97c5d3dc5806be2 Mon Sep 17 00:00:00 2001
From: StevenDufresne
Date: Tue, 13 Aug 2024 11:19:50 +0900
Subject: [PATCH 31/49] Update progress bar and titles.
---
.../src/components/first-time/first-time.js | 26 ++++----------
settings/src/components/first-time/home.js | 4 +--
.../first-time/setup-progress-bar.js | 18 ++++------
.../first-time/setup-progress-bar.scss | 36 ++++++++++---------
4 files changed, 34 insertions(+), 50 deletions(-)
diff --git a/settings/src/components/first-time/first-time.js b/settings/src/components/first-time/first-time.js
index d139e8f9..9a0a7675 100644
--- a/settings/src/components/first-time/first-time.js
+++ b/settings/src/components/first-time/first-time.js
@@ -3,7 +3,6 @@
*/
import { useEffect, useContext, useRef } from '@wordpress/element';
import { Button } from '@wordpress/components';
-import { lock, edit, reusableBlock } from '@wordpress/icons';
/**
* Internal dependencies
@@ -38,28 +37,12 @@ const isValidUrl = ( url ) => {
export default function FirstTime() {
const modalRef = useRef( null );
const { navigateToScreen, screen } = useContext( GlobalContext );
- const steps = [
- {
- title: 'Choose an authentication method',
- label: 'Select',
- icon: edit,
- },
- {
- title: 'Set up your authentication method',
- label: 'Configure',
- icon: lock,
- },
- {
- title: 'Print Backup Codes',
- label: 'Print',
- icon: reusableBlock,
- },
- ];
// The index is the URL slug and the value is the React component.
const screens = {
home: {
stepIndex: 0,
+ title: 'Set up two-factor authentication',
component: (
{
@@ -70,6 +53,7 @@ export default function FirstTime() {
},
totp: {
stepIndex: 1,
+ title: 'Set up one-time password',
component: (
{
@@ -80,6 +64,7 @@ export default function FirstTime() {
},
webauthn: {
stepIndex: 1,
+ title: 'Set up security key',
component: (
{
@@ -90,6 +75,7 @@ export default function FirstTime() {
},
'backup-codes': {
stepIndex: 2,
+ title: 'Print backup codes',
component: (
{
@@ -189,10 +175,10 @@ export default function FirstTime() {
} else {
currentScreenComponent = (
<>
-
+
{ screens[ screen ].component }
diff --git a/settings/src/components/first-time/home.js b/settings/src/components/first-time/home.js
index c9fc9467..dbdc41af 100644
--- a/settings/src/components/first-time/home.js
+++ b/settings/src/components/first-time/home.js
@@ -34,7 +34,7 @@ export default function Home( { onSelect } ) {
onChange={ handleOptionChange }
/>
-
Setup security key
+
Set up security key
Use biometrics, digital cryptography, or hardware keys.
@@ -48,7 +48,7 @@ export default function Home( { onSelect } ) {
onChange={ handleOptionChange }
/>
-
Setup one time password
+
Set up one time password
Use an application to get two-factor authentication codes.
diff --git a/settings/src/components/first-time/setup-progress-bar.js b/settings/src/components/first-time/setup-progress-bar.js
index b7020eda..f8dae8ba 100644
--- a/settings/src/components/first-time/setup-progress-bar.js
+++ b/settings/src/components/first-time/setup-progress-bar.js
@@ -2,12 +2,11 @@
* WordPress dependencies
*/
import { useCallback } from '@wordpress/element';
-import { Icon, check } from '@wordpress/icons';
-export default function SetupProgressBar( { currentStepIndex, steps } ) {
+export default function SetupProgressBar( { currentStepIndex, stepCount } ) {
const getCompletionPercentage = useCallback(
- () => ( currentStepIndex / ( steps.length - 1 ) ) * 100,
- [ currentStepIndex, steps.length ]
+ () => ( currentStepIndex / ( stepCount - 1 ) ) * 100,
+ [ currentStepIndex, stepCount ]
);
const getStepClass = ( index ) => {
@@ -25,14 +24,9 @@ export default function SetupProgressBar( { currentStepIndex, steps } ) {
return (
- { steps.map( ( step, index ) => (
-
- index ? check : step.icon }
- />
- { step.label }
+ { Array.from( { length: stepCount } ).map( ( step, index ) => (
+
+ { index + 1 }
) ) }
diff --git a/settings/src/components/first-time/setup-progress-bar.scss b/settings/src/components/first-time/setup-progress-bar.scss
index 03d6f8a4..4f52013d 100644
--- a/settings/src/components/first-time/setup-progress-bar.scss
+++ b/settings/src/components/first-time/setup-progress-bar.scss
@@ -14,6 +14,18 @@
display: flex;
justify-content: space-between;
+ .wporg-2fa__setup-count {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background-color: white;
+ width: 32px;
+ height: 32px;
+ border-radius: 32px;
+ color: var(--color-disabled-text);
+ border: 1.5px solid var(--color-disabled);
+ }
+
li {
text-align: center;
@@ -23,40 +35,32 @@
}
}
- svg {
- box-sizing: content-box;
- padding: 8px;
- border: 1px solid;
- border-radius: 30px;
- }
-
li.is-enabled {
color: var(--wp--preset--color--charcoal-1 #1e1e1e);
- svg {
+ .wporg-2fa__setup-count {
background-color: var(--color-enabled);
border-color: var(--color-enabled);
- fill: $white;
+ color: white;
}
}
li.is-disabled {
color: var(--color-disabled-text);
- svg {
+ .wporg-2fa__setup-count {
background-color: white;
border-color: var(--color-disabled);
- fill: var(--color-disabled);
}
}
li.is-complete {
color: var(--color-disabled-text);
- svg {
+ .wporg-2fa__setup-count {
background-color: var(--color-enabled);
border-color: var(--color-enabled);
- fill: white;
+ color: white;
}
}
}
@@ -65,13 +69,13 @@
.wporg-2fa__progress-bar {
margin: 0;
width: 100%;
- max-width: 350px;
+ max-width: 300px;
}
.wporg-2fa__progress-bar .wporg-2fa__setup-step-separator::before {
content: '';
position: absolute;
- height: 2px;
+ height: 1.5px;
width: var(--wporg-separator-width, 0%);
background: var(--wp--preset--color--blueberry-1, #3858e9);
z-index: 1;
@@ -82,7 +86,7 @@
margin-left: 2%;
background: var(--color-disabled);
width: 96%;
- height: 2px;
+ height: 1.5px;
top: 16px;
z-index: 0;
}
\ No newline at end of file
From 9d5b2a584c1e1a1257183917c5c06d0a08e7e9cd Mon Sep 17 00:00:00 2001
From: StevenDufresne
Date: Tue, 13 Aug 2024 12:16:31 +0900
Subject: [PATCH 32/49] Move congratulations to its own component.
---
.../components/first-time/congratulations.js | 50 +++++++++++++++++++
.../src/components/first-time/first-time.js | 47 +----------------
settings/src/components/first-time/home.js | 2 +-
3 files changed, 53 insertions(+), 46 deletions(-)
create mode 100644 settings/src/components/first-time/congratulations.js
diff --git a/settings/src/components/first-time/congratulations.js b/settings/src/components/first-time/congratulations.js
new file mode 100644
index 00000000..4a4e6c9b
--- /dev/null
+++ b/settings/src/components/first-time/congratulations.js
@@ -0,0 +1,50 @@
+/**
+ * WordPress dependencies
+ */
+import { Button } from '@wordpress/components';
+
+/**
+ * Check if the URL is valid. Make sure it stays on wordpress.org.
+ *
+ * @param url
+ * @return {boolean} Whether it's a valid URL.
+ */
+const isValidUrl = ( url ) => {
+ try {
+ const { hostname } = new URL( url );
+ return hostname.endsWith( 'wordpress.org' );
+ } catch ( exception ) {
+ return false;
+ }
+};
+
+export default function Congratulations() {
+ return (
+ <>
+
+ To ensure the highest level of security for your account, please remember to keep
+ your authentication methods up-to-date. We recommend configuring multiple
+ authentication methods to guarantee you always have access to your account.
+
+
+ {
+ const redirectTo = new URLSearchParams( window.location.search ).get(
+ 'redirect_to'
+ );
+
+ if ( redirectTo && isValidUrl( redirectTo ) ) {
+ window.location.href = redirectTo;
+ } else {
+ window.location.href =
+ '//profiles.wordpress.org/me/profile/edit/group/3';
+ }
+ } }
+ isPrimary
+ >
+ Continue
+
+
+ >
+ );
+}
diff --git a/settings/src/components/first-time/first-time.js b/settings/src/components/first-time/first-time.js
index 9a0a7675..a0d6e2ac 100644
--- a/settings/src/components/first-time/first-time.js
+++ b/settings/src/components/first-time/first-time.js
@@ -13,24 +13,10 @@ import WebAuthn from '../webauthn/webauthn';
import BackupCodes from '../backup-codes';
import SetupProgressBar from './setup-progress-bar';
import Home from './home';
+import Congratulations from './congratulations';
import WordPressLogo from './wordpress-logo';
import { GlobalContext } from '../../script';
-/**
- * Check if the URL is valid. Make sure it stays on wordpress.org.
- *
- * @param url
- * @return {boolean} Whether it's a valid URL.
- */
-const isValidUrl = ( url ) => {
- try {
- const { hostname } = new URL( url );
- return hostname.endsWith( 'wordpress.org' );
- } catch ( exception ) {
- return false;
- }
-};
-
/**
* Render the correct component based on the URL.
*/
@@ -86,36 +72,7 @@ export default function FirstTime() {
},
congratulations: {
stepIndex: 3,
- component: (
-
-
Two-factor authentication setup is now complete! 🎉
-
- To ensure the highest level of security for your account, please remember to
- keep your authentication methods up-to-date. We recommend configuring
- multiple authentication methods to guarantee you always have access to your
- account.
-
-
- {
- const redirectTo = new URLSearchParams(
- window.location.search
- ).get( 'redirect_to' );
-
- if ( redirectTo && isValidUrl( redirectTo ) ) {
- window.location.href = redirectTo;
- } else {
- window.location.href =
- '//profiles.wordpress.org/me/profile/edit/group/3';
- }
- } }
- isPrimary
- >
- Continue
-
-
-
- ),
+ component: ,
},
};
diff --git a/settings/src/components/first-time/home.js b/settings/src/components/first-time/home.js
index dbdc41af..d962ccd8 100644
--- a/settings/src/components/first-time/home.js
+++ b/settings/src/components/first-time/home.js
@@ -55,7 +55,7 @@ export default function Home( { onSelect } ) {
- Configure Two-Factor
+ Configure
>
From 8fe507f1bf895101bf1dc8560688cc23fb4ec11c Mon Sep 17 00:00:00 2001
From: StevenDufresne
Date: Tue, 13 Aug 2024 12:17:37 +0900
Subject: [PATCH 33/49] Remove unsued button.
---
settings/src/components/first-time/first-time.js | 1 -
1 file changed, 1 deletion(-)
diff --git a/settings/src/components/first-time/first-time.js b/settings/src/components/first-time/first-time.js
index a0d6e2ac..c970aaee 100644
--- a/settings/src/components/first-time/first-time.js
+++ b/settings/src/components/first-time/first-time.js
@@ -2,7 +2,6 @@
* WordPress dependencies
*/
import { useEffect, useContext, useRef } from '@wordpress/element';
-import { Button } from '@wordpress/components';
/**
* Internal dependencies
From 8feef5d3d0cb2cefb18d92ea9aeca2f8bbf4f218 Mon Sep 17 00:00:00 2001
From: StevenDufresne
Date: Tue, 13 Aug 2024 16:11:19 +0900
Subject: [PATCH 34/49] Prepare for an inline view.
---
.../src/components/first-time/first-time.js | 53 ++-----------------
.../src/components/first-time/first-time.scss | 14 ++---
.../first-time/setup-progress-bar.js | 11 ++--
.../first-time/setup-progress-bar.scss | 4 +-
.../components/first-time/wordpress-logo.js | 16 ------
5 files changed, 17 insertions(+), 81 deletions(-)
delete mode 100644 settings/src/components/first-time/wordpress-logo.js
diff --git a/settings/src/components/first-time/first-time.js b/settings/src/components/first-time/first-time.js
index c970aaee..d2f3b5a7 100644
--- a/settings/src/components/first-time/first-time.js
+++ b/settings/src/components/first-time/first-time.js
@@ -1,7 +1,7 @@
/**
* WordPress dependencies
*/
-import { useEffect, useContext, useRef } from '@wordpress/element';
+import { useContext, useRef } from '@wordpress/element';
/**
* Internal dependencies
@@ -13,7 +13,6 @@ import BackupCodes from '../backup-codes';
import SetupProgressBar from './setup-progress-bar';
import Home from './home';
import Congratulations from './congratulations';
-import WordPressLogo from './wordpress-logo';
import { GlobalContext } from '../../script';
/**
@@ -75,50 +74,6 @@ export default function FirstTime() {
},
};
- // Lock the scroll when the modal is open, and trap tab navigation.
- useEffect( () => {
- const modal = modalRef.current;
- const focusableElements = modal.querySelectorAll(
- 'a, button, input, textarea, select, [tabindex]:not([tabindex="-1"])'
- );
- const firstFocusableElement = focusableElements[ 0 ];
- const lastFocusableElement = focusableElements[ focusableElements.length - 1 ];
-
- const trapFocus = ( event ) => {
- const isTabPressed = event.key === 'Tab' || event.keyCode === 9;
- if ( ! isTabPressed ) {
- return;
- }
-
- if ( event.shiftKey ) {
- // eslint-disable-next-line @wordpress/no-global-active-element
- if ( document.activeElement === firstFocusableElement ) {
- lastFocusableElement.focus();
- event.preventDefault();
- }
- return;
- }
-
- // eslint-disable-next-line @wordpress/no-global-active-element
- if ( document.activeElement === lastFocusableElement ) {
- firstFocusableElement.focus();
- event.preventDefault();
- }
- };
-
- modal.addEventListener( 'keydown', trapFocus );
-
- document.querySelector( 'html' ).style.overflow = 'hidden';
-
- // Focus the first focusable element in the modal when it opens
- firstFocusableElement.focus();
-
- return () => {
- modal.removeEventListener( 'keydown', trapFocus );
- document.querySelector( 'html' ).style.overflow = 'initial';
- };
- }, [ screen ] );
-
const currentStepIndex = screens[ screen ].stepIndex;
let currentScreenComponent = null;
@@ -131,7 +86,10 @@ export default function FirstTime() {
} else {
currentScreenComponent = (
<>
-
+
-
{ currentScreenComponent }
diff --git a/settings/src/components/first-time/first-time.scss b/settings/src/components/first-time/first-time.scss
index 30961526..03b47229 100644
--- a/settings/src/components/first-time/first-time.scss
+++ b/settings/src/components/first-time/first-time.scss
@@ -1,24 +1,16 @@
.wporg-2fa__first-time {
- position: fixed;
- background: #fff;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- z-index: 1000;
+ padding: 0 16px;
+ min-height: 600px;
.wporg-2fa__first-time__inner {
box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: center;
- width: 100%;
- height: 100%;
- overflow: scroll;
}
.wporg-2fa__first-time__inner-content {
- padding: 8vh 16px;
+ padding: 0 0 100px;
display: flex;
flex-direction: column;
align-items: center;
diff --git a/settings/src/components/first-time/setup-progress-bar.js b/settings/src/components/first-time/setup-progress-bar.js
index f8dae8ba..54133d9a 100644
--- a/settings/src/components/first-time/setup-progress-bar.js
+++ b/settings/src/components/first-time/setup-progress-bar.js
@@ -3,10 +3,10 @@
*/
import { useCallback } from '@wordpress/element';
-export default function SetupProgressBar( { currentStepIndex, stepCount } ) {
+export default function SetupProgressBar( { currentStepIndex, steps } ) {
const getCompletionPercentage = useCallback(
- () => ( currentStepIndex / ( stepCount - 1 ) ) * 100,
- [ currentStepIndex, stepCount ]
+ () => ( currentStepIndex / ( steps.length - 1 ) ) * 100,
+ [ currentStepIndex, steps ]
);
const getStepClass = ( index ) => {
@@ -24,9 +24,10 @@ export default function SetupProgressBar( { currentStepIndex, stepCount } ) {
return (
- { Array.from( { length: stepCount } ).map( ( step, index ) => (
-
+ { steps.map( ( step, index ) => (
+
{ index + 1 }
+ { step }
) ) }
diff --git a/settings/src/components/first-time/setup-progress-bar.scss b/settings/src/components/first-time/setup-progress-bar.scss
index 4f52013d..e18c6057 100644
--- a/settings/src/components/first-time/setup-progress-bar.scss
+++ b/settings/src/components/first-time/setup-progress-bar.scss
@@ -27,7 +27,9 @@
}
li {
- text-align: center;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
.wporg-2fa__setup-label {
display: block;
diff --git a/settings/src/components/first-time/wordpress-logo.js b/settings/src/components/first-time/wordpress-logo.js
deleted file mode 100644
index aec32250..00000000
--- a/settings/src/components/first-time/wordpress-logo.js
+++ /dev/null
@@ -1,16 +0,0 @@
-export default () => (
-
-
-
-
-
-);
From 7aec1156adab01e585d6dfd5c459524a40b51e81 Mon Sep 17 00:00:00 2001
From: StevenDufresne
Date: Wed, 14 Aug 2024 11:25:57 +0900
Subject: [PATCH 35/49] Update the inline experience.
---
.../components/first-time/congratulations.js | 49 ++++++++++++++++++-
.../src/components/first-time/first-time.js | 9 ++--
.../src/components/first-time/first-time.scss | 18 +++----
settings/src/components/settings.js | 2 +-
settings/src/style.scss | 5 +-
wporg-two-factor.php | 4 +-
6 files changed, 62 insertions(+), 25 deletions(-)
diff --git a/settings/src/components/first-time/congratulations.js b/settings/src/components/first-time/congratulations.js
index 4a4e6c9b..80150515 100644
--- a/settings/src/components/first-time/congratulations.js
+++ b/settings/src/components/first-time/congratulations.js
@@ -2,6 +2,12 @@
* WordPress dependencies
*/
import { Button } from '@wordpress/components';
+import { useContext } from '@wordpress/element';
+
+/**
+ * Internal dependencies
+ */
+import { GlobalContext } from '../../script';
/**
* Check if the URL is valid. Make sure it stays on wordpress.org.
@@ -19,13 +25,51 @@ const isValidUrl = ( url ) => {
};
export default function Congratulations() {
+ const {
+ user: { webAuthnEnabled, totpEnabled },
+ } = useContext( GlobalContext );
+
+ const getAuthenticationMethod = () => {
+ if ( webAuthnEnabled && totpEnabled ) {
+ return null;
+ }
+
+ return (
+
+ );
+ };
+
return (
<>
To ensure the highest level of security for your account, please remember to keep
- your authentication methods up-to-date. We recommend configuring multiple
- authentication methods to guarantee you always have access to your account.
+ your authentication methods up-to-date, and consult{ ' ' }
+
+ our documentation
+ { ' ' }
+ if you need help or have any questions.
+
+
+ We recommend configuring multiple authentication methods to guarantee you always
+ have access to your account.
+
+ { getAuthenticationMethod() }
+
{
@@ -44,6 +88,7 @@ export default function Congratulations() {
>
Continue
+ View security settings
>
);
diff --git a/settings/src/components/first-time/first-time.js b/settings/src/components/first-time/first-time.js
index d2f3b5a7..c7bee69e 100644
--- a/settings/src/components/first-time/first-time.js
+++ b/settings/src/components/first-time/first-time.js
@@ -19,7 +19,6 @@ import { GlobalContext } from '../../script';
* Render the correct component based on the URL.
*/
export default function FirstTime() {
- const modalRef = useRef( null );
const { navigateToScreen, screen } = useContext( GlobalContext );
// The index is the URL slug and the value is the React component.
@@ -102,11 +101,9 @@ export default function FirstTime() {
}
return (
-
-
-
- { currentScreenComponent }
-
+
+
+ { currentScreenComponent }
);
diff --git a/settings/src/components/first-time/first-time.scss b/settings/src/components/first-time/first-time.scss
index 03b47229..4556b174 100644
--- a/settings/src/components/first-time/first-time.scss
+++ b/settings/src/components/first-time/first-time.scss
@@ -1,13 +1,8 @@
.wporg-2fa__first-time {
padding: 0 16px;
min-height: 600px;
-
- .wporg-2fa__first-time__inner {
- box-sizing: border-box;
- display: flex;
- flex-direction: column;
- align-items: center;
- }
+ display: flex;
+ justify-content: center;
.wporg-2fa__first-time__inner-content {
padding: 0 0 100px;
@@ -19,11 +14,6 @@
width: 600px;
}
- > svg {
- margin-bottom: 32px;
- width: 250px;
- }
-
// Preven cards from shrinking.
.components-card {
width: 100%;
@@ -35,6 +25,10 @@
}
}
+ .wporg-2fa__first-time__inner-content.congratulations {
+ justify-content: center;
+ }
+
.wporg-2fa__first-time-default {
display: flex;
flex-direction: column;
diff --git a/settings/src/components/settings.js b/settings/src/components/settings.js
index bcb156de..b2714e51 100644
--- a/settings/src/components/settings.js
+++ b/settings/src/components/settings.js
@@ -49,5 +49,5 @@ export default function Settings() {
{ components[ screen ] }
);
- return <>{ currentScreenComponent }>;
+ return currentScreenComponent;
}
diff --git a/settings/src/style.scss b/settings/src/style.scss
index 5dad1b15..985d2bb1 100644
--- a/settings/src/style.scss
+++ b/settings/src/style.scss
@@ -20,13 +20,14 @@ $alert-blue: #72aee6;
.wp-block-wporg-two-factor-settings {
position: relative;
font-size: 13px;
+ min-height: 600px;
> div.initial-load {
display: flex;
justify-content: center;
align-items: center;
- height: 400px;
- box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 0px 1px;
+ min-height: 400px;
+ // box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 0px 1px;
}
h3,
diff --git a/wporg-two-factor.php b/wporg-two-factor.php
index 2cb6fa0e..7060857c 100644
--- a/wporg-two-factor.php
+++ b/wporg-two-factor.php
@@ -207,7 +207,7 @@ function remove_capabilities_until_2fa_enabled( array $allcaps, array $caps, arr
}
add_action( 'admin_notices', __NAMESPACE__ . '\render_2fa_admin_notice' );
- add_filter( 'wporg_global_header_alert_markup', __NAMESPACE__ . '\get_enable_2fa_notice' );
+ //add_filter( 'wporg_global_header_alert_markup', __NAMESPACE__ . '\get_enable_2fa_notice' );
}
return $allcaps;
@@ -370,7 +370,7 @@ function block_webauthn_settings_page() {
* @codeCoverageIgnore
*/
function get_edit_account_url() : string {
- return 'https://profiles.wordpress.org/' . ( wp_get_current_user()->user_nicename ?? 'me' ) . '/profile/edit/group/3';
+ return 'https://profiles.wordpress.org/' . ( wp_get_current_user()->user_nicename ?? 'me' ) . '/profile/security?first-time=1';
}
/**
From ffb5d737f3db8b9cdb049bbcd27312c215d1bbef Mon Sep 17 00:00:00 2001
From: StevenDufresne
Date: Fri, 16 Aug 2024 11:30:33 +0900
Subject: [PATCH 36/49] Copy update.
---
settings/src/components/first-time/congratulations.js | 7 +++----
settings/src/components/first-time/first-time.js | 6 +++---
settings/src/components/first-time/home.js | 2 +-
.../src/components/first-time/setup-progress-bar.js | 10 +++++++++-
.../src/components/first-time/setup-progress-bar.scss | 4 +---
5 files changed, 17 insertions(+), 12 deletions(-)
diff --git a/settings/src/components/first-time/congratulations.js b/settings/src/components/first-time/congratulations.js
index 80150515..89fface3 100644
--- a/settings/src/components/first-time/congratulations.js
+++ b/settings/src/components/first-time/congratulations.js
@@ -45,7 +45,7 @@ export default function Congratulations() {
{ webAuthnEnabled && (
- Set up one time password
+ Set up an authenticator app
) }
@@ -64,8 +64,8 @@ export default function Congratulations() {
if you need help or have any questions.
- We recommend configuring multiple authentication methods to guarantee you always
- have access to your account.
+ We recommend configuring multiple authentication methods and generating backup codes
+ to guarantee you always have access to your account.
{ getAuthenticationMethod() }
@@ -88,7 +88,6 @@ export default function Congratulations() {
>
Continue
- View security settings
>
);
diff --git a/settings/src/components/first-time/first-time.js b/settings/src/components/first-time/first-time.js
index c7bee69e..59ee133b 100644
--- a/settings/src/components/first-time/first-time.js
+++ b/settings/src/components/first-time/first-time.js
@@ -36,7 +36,7 @@ export default function FirstTime() {
},
totp: {
stepIndex: 1,
- title: 'Set up one-time password',
+ title: 'Set up an authenticator app',
component: (
{
@@ -58,7 +58,7 @@ export default function FirstTime() {
},
'backup-codes': {
stepIndex: 2,
- title: 'Print backup codes',
+ title: 'Generate backup codes',
component: (
{
@@ -87,7 +87,7 @@ export default function FirstTime() {
<>
-
Set up one time password
+
Set up an authenticator app
Use an application to get two-factor authentication codes.
diff --git a/settings/src/components/first-time/setup-progress-bar.js b/settings/src/components/first-time/setup-progress-bar.js
index 54133d9a..698f6860 100644
--- a/settings/src/components/first-time/setup-progress-bar.js
+++ b/settings/src/components/first-time/setup-progress-bar.js
@@ -21,11 +21,17 @@ export default function SetupProgressBar( { currentStepIndex, steps } ) {
return 'is-disabled';
};
+ const flexWidth = 100 / steps.length;
+
return (
{ steps.map( ( step, index ) => (
-
+
{ index + 1 }
{ step }
@@ -35,6 +41,8 @@ export default function SetupProgressBar( { currentStepIndex, steps } ) {
diff --git a/settings/src/components/first-time/setup-progress-bar.scss b/settings/src/components/first-time/setup-progress-bar.scss
index e18c6057..d5f6e222 100644
--- a/settings/src/components/first-time/setup-progress-bar.scss
+++ b/settings/src/components/first-time/setup-progress-bar.scss
@@ -71,7 +71,7 @@
.wporg-2fa__progress-bar {
margin: 0;
width: 100%;
- max-width: 300px;
+ max-width: 350px;
}
.wporg-2fa__progress-bar .wporg-2fa__setup-step-separator::before {
@@ -85,9 +85,7 @@
.wporg-2fa__progress-bar .wporg-2fa__setup-step-separator {
position: absolute;
- margin-left: 2%;
background: var(--color-disabled);
- width: 96%;
height: 1.5px;
top: 16px;
z-index: 0;
From e10c09bfe8fd274716fc6354da85470ecd113542 Mon Sep 17 00:00:00 2001
From: StevenDufresne
Date: Fri, 16 Aug 2024 12:17:04 +0900
Subject: [PATCH 37/49] Add onboarding property to trigger the onboarding api.
---
settings/settings.php | 8 +++++++-
settings/src/block.json | 4 ++++
settings/src/render.php | 2 +-
settings/src/script.js | 9 +++------
wporg-two-factor.php | 2 +-
5 files changed, 16 insertions(+), 9 deletions(-)
diff --git a/settings/settings.php b/settings/settings.php
index 0bee6210..3dd8eec0 100644
--- a/settings/settings.php
+++ b/settings/settings.php
@@ -57,7 +57,13 @@ function render_custom_ui() : void {
return;
}
- $json_attrs = json_encode( [ 'userId' => $user_id ] );
+ $block_attributes = [ 'userId' => $user_id ];
+
+ if ( true ) {
+ $block_attributes['onboarding'] = true;
+ }
+
+ $json_attrs = json_encode( $block_attributes );
$preload_paths = [
'/wp/v2/users/' . $user_id . '?context=edit',
diff --git a/settings/src/block.json b/settings/src/block.json
index e008fd9b..5415d3ad 100644
--- a/settings/src/block.json
+++ b/settings/src/block.json
@@ -13,6 +13,10 @@
"attributes": {
"userId": {
"type": "integer"
+ },
+ "onboarding": {
+ "type": "boolean",
+ "default": false
}
},
"textdomain": "wporg",
diff --git a/settings/src/render.php b/settings/src/render.php
index c512b56b..38012928 100644
--- a/settings/src/render.php
+++ b/settings/src/render.php
@@ -1,4 +1,4 @@
- data-user-id="attributes['userId'] ); ?>">
+
data-user-id="attributes['userId'] ); ?>" data-onboarding="attributes['onboarding'] ); ?>">
Loading ...
diff --git a/settings/src/script.js b/settings/src/script.js
index 788c645d..7230df6f 100644
--- a/settings/src/script.js
+++ b/settings/src/script.js
@@ -47,8 +47,9 @@ function renderSettings() {
*
* @param props
* @param props.userId
+ * @param props.onboarding
*/
-function Main( { userId } ) {
+function Main( { userId, onboarding } ) {
const user = useUser( userId );
const {
userRecord: { record, edit, hasEdits, hasResolved },
@@ -146,11 +147,7 @@ function Main( { userId } ) {
>
- { new URLSearchParams( window.location.search ).get( 'first-time' ) ? (
-
- ) : (
-
- ) }
+ { onboarding ?
:
}
{ shouldRevalidate &&
}
);
diff --git a/wporg-two-factor.php b/wporg-two-factor.php
index 7060857c..3056e3ba 100644
--- a/wporg-two-factor.php
+++ b/wporg-two-factor.php
@@ -207,7 +207,7 @@ function remove_capabilities_until_2fa_enabled( array $allcaps, array $caps, arr
}
add_action( 'admin_notices', __NAMESPACE__ . '\render_2fa_admin_notice' );
- //add_filter( 'wporg_global_header_alert_markup', __NAMESPACE__ . '\get_enable_2fa_notice' );
+ add_filter( 'wporg_global_header_alert_markup', __NAMESPACE__ . '\get_enable_2fa_notice' );
}
return $allcaps;
From aab006373910556470444da1b8c8dace1f1d905d Mon Sep 17 00:00:00 2001
From: StevenDufresne
Date: Fri, 16 Aug 2024 13:59:50 +0900
Subject: [PATCH 38/49] Add onboarding state.
---
settings/settings.php | 19 ++++++++++++++++++-
settings/src/render.php | 6 +++++-
settings/src/script.js | 5 ++++-
settings/src/style.scss | 7 +++++--
4 files changed, 32 insertions(+), 5 deletions(-)
diff --git a/settings/settings.php b/settings/settings.php
index 3dd8eec0..d53f20dc 100644
--- a/settings/settings.php
+++ b/settings/settings.php
@@ -11,6 +11,7 @@
add_action( 'init', __NAMESPACE__ . '\register_block' );
add_action( 'enqueue_block_assets', __NAMESPACE__ . '\maybe_dequeue_stylesheet', 40 );
add_action( 'wp_head', __NAMESPACE__ . '\maybe_add_custom_print_css' );
+add_action( 'template_redirect', __NAMESPACE__ . '\onboarding_template_page' );
/**
* Registers the block
@@ -50,6 +51,8 @@ function replace_core_ui_with_custom() : void {
* @codeCoverageIgnore
*/
function render_custom_ui() : void {
+ global $wp;
+
$user_id = function_exists( 'bbp_get_displayed_user_id' ) ? bbp_get_displayed_user_id() : bp_displayed_user_id();
if ( ! current_user_can( 'edit_user', $user_id ) ) {
@@ -59,7 +62,7 @@ function render_custom_ui() : void {
$block_attributes = [ 'userId' => $user_id ];
- if ( true ) {
+ if ( 1 === preg_match( '#profile/security#', $wp->request ) ) {
$block_attributes['onboarding'] = true;
}
@@ -198,3 +201,17 @@ function maybe_add_custom_print_css() {
request ) ) {
+ status_header( 200 );
+ locate_template( array( "members/single/security.php" ), true );
+ die;
+ }
+}
diff --git a/settings/src/render.php b/settings/src/render.php
index 38012928..b15d1e2c 100644
--- a/settings/src/render.php
+++ b/settings/src/render.php
@@ -1,4 +1,8 @@
- data-user-id="attributes['userId'] ); ?>" data-onboarding="attributes['onboarding'] ); ?>">
+
+ data-user-id="attributes['userId'] ); ?>"
+ data-onboarding="attributes['onboarding'] ? 'true' : 'false' ); ?>"
+ >
Loading ...
diff --git a/settings/src/script.js b/settings/src/script.js
index 7230df6f..beeaf075 100644
--- a/settings/src/script.js
+++ b/settings/src/script.js
@@ -37,7 +37,10 @@ function renderSettings() {
root.render(
-
+
);
}
diff --git a/settings/src/style.scss b/settings/src/style.scss
index 985d2bb1..40a4b445 100644
--- a/settings/src/style.scss
+++ b/settings/src/style.scss
@@ -20,14 +20,17 @@ $alert-blue: #72aee6;
.wp-block-wporg-two-factor-settings {
position: relative;
font-size: 13px;
- min-height: 600px;
> div.initial-load {
display: flex;
justify-content: center;
align-items: center;
min-height: 400px;
- // box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 0px 1px;
+ box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 0px 1px;
+ }
+
+ &[data-onboarding="true"] > div.initial-load {
+ box-shadow: none;
}
h3,
From ef1fe2fcbc5fef02978c238ad85377163069f04d Mon Sep 17 00:00:00 2001
From: StevenDufresne
Date: Fri, 16 Aug 2024 15:04:38 +0900
Subject: [PATCH 39/49] Update how we deal with profile/security
---
settings/settings.php | 39 ++++++++++++++++++++++++---------
tests/test-wporg-two-factor.php | 2 +-
wporg-two-factor.php | 2 +-
3 files changed, 31 insertions(+), 12 deletions(-)
diff --git a/settings/settings.php b/settings/settings.php
index d53f20dc..fbc8bab0 100644
--- a/settings/settings.php
+++ b/settings/settings.php
@@ -7,6 +7,9 @@
require __DIR__ . '/rest-api.php';
+const SETTINGS_PAGE_PATH = '/profile/edit/group/3';
+const ONBOARDING_PAGE_PATH = '/profile/security';
+
add_action( 'plugins_loaded', __NAMESPACE__ . '\replace_core_ui_with_custom' ); // Must run after Two Factor plugin loaded.
add_action( 'init', __NAMESPACE__ . '\register_block' );
add_action( 'enqueue_block_assets', __NAMESPACE__ . '\maybe_dequeue_stylesheet', 40 );
@@ -45,14 +48,34 @@ function replace_core_ui_with_custom() : void {
add_action( 'login_footer', __NAMESPACE__ . '\login_footer_revalidate_customizations' );
}
+/**
+ * Return true if the current page is the onboarding page.
+ *
+ * @return bool
+ */
+function is_onboarding_page() {
+ global $wp;
+
+ return 1 === preg_match( '#' . ONBOARDING_PAGE_PATH . '#', $wp->request );
+}
+
+/**
+ * Return true if we load the 2fa component on this path.
+ *
+ * @return bool
+ */
+function page_has_2fa_component() {
+ global $wp;
+
+ return is_onboarding_page() || 1 === preg_match( '#' . SETTINGS_PAGE_PATH . '#', $wp->request );
+}
+
/**
* Render our custom 2FA interface.
*
* @codeCoverageIgnore
*/
function render_custom_ui() : void {
- global $wp;
-
$user_id = function_exists( 'bbp_get_displayed_user_id' ) ? bbp_get_displayed_user_id() : bp_displayed_user_id();
if ( ! current_user_can( 'edit_user', $user_id ) ) {
@@ -62,7 +85,7 @@ function render_custom_ui() : void {
$block_attributes = [ 'userId' => $user_id ];
- if ( 1 === preg_match( '#profile/security#', $wp->request ) ) {
+ if ( is_onboarding_page() ) {
$block_attributes['onboarding'] = true;
}
@@ -169,10 +192,9 @@ function login_footer_revalidate_customizations() {
* @todo this may not be necessary once https://github.com/WordPress/gutenberg/issues/54491 is resolved.
*/
function maybe_dequeue_stylesheet() {
- global $wp;
// Match the URL since page/blog IDs etc aren't consistent across environments.
- if ( 1 === preg_match( '#/profile/edit/group/3#', $wp->request ) ) {
+ if ( page_has_2fa_component() ) {
return;
}
@@ -183,10 +205,9 @@ function maybe_dequeue_stylesheet() {
* Add custom CSS for print styles.
*/
function maybe_add_custom_print_css() {
- global $wp;
// Check if the current URL matches the specific condition
- if ( 1 === preg_match( '#/profile/edit/group/3#', $wp->request ) ) {
+ if ( page_has_2fa_component() ) {
?>