Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add "Require 2FA" in Ghost Admin settings #22386

Merged
merged 9 commits into from
Mar 10, 2025
Merged

Add "Require 2FA" in Ghost Admin settings #22386

merged 9 commits into from
Mar 10, 2025

Conversation

sam-lord
Copy link
Contributor

@sam-lord sam-lord commented Mar 5, 2025

ref ENG-2072

This adds the setting to make signing out also remove the verified flag. This effectively ensures that 2FA is required on every login, not just once per device.

@sam-lord sam-lord requested a review from aileen March 5, 2025 12:47
Copy link
Contributor

coderabbitai bot commented Mar 5, 2025

Walkthrough

This pull request introduces a new configuration setting, require_email_mfa, for managing email-based multi-factor authentication. The setting is added with a default value of false in the JSON configuration file and included in the default settings schema under a new "security" section. Corresponding updates have been made in React components to conditionally render a toggle for email 2FA, allowing administrators to manage this setting. On the server side, the new key is incorporated into editable settings, key-to-group mappings, and type mappings. Additionally, a migration script registers the new setting, and adjustments in session management logic ensure that the verified status is reset when this configuration is active. Test cases have been expanded to cover the revised session handling and settings integrity checks, and query parameters have been updated to include the new security group.

Suggested reviewers

  • aileen

Warning

There were issues while running some tools. Please review the errors and either fix the tool’s configuration or disable the tool if it’s a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ghost/admin/app/services/settings.js

Oops! Something went wrong! :(

ESLint: 8.44.0

Error: Failed to load parser '@babel/eslint-parser' declared in 'ghost/admin/.eslintrc.js': Cannot find module '@babel/eslint-parser'
Require stack:

  • /ghost/admin/.eslintrc.js
    at Module._resolveFilename (node:internal/modules/cjs/loader:1248:15)
    at Function.resolve (node:internal/modules/helpers:145:19)
    at Object.resolve (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2346:46)
    at ConfigArrayFactory._loadParser (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3325:39)
    at ConfigArrayFactory._normalizeObjectConfigDataBody (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3099:43)
    at _normalizeObjectConfigDataBody.next ()
    at ConfigArrayFactory._normalizeObjectConfigData (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3040:20)
    at _normalizeObjectConfigData.next ()
    at ConfigArrayFactory.loadInDirectory (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2886:28)
    at CascadingConfigArrayFactory._loadConfigInAncestors (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3871:46)
apps/admin-x-framework/src/api/settings.ts

Oops! Something went wrong! :(

ESLint: 8.44.0

ESLint couldn't find the plugin "eslint-plugin-react-hooks".

(The package "eslint-plugin-react-hooks" was not found when loaded as a Node module from the directory "/apps/admin-x-framework".)

It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:

npm install eslint-plugin-react-hooks@latest --save-dev

The plugin "eslint-plugin-react-hooks" was referenced from the config file in "apps/admin-x-framework/.eslintrc.cjs".

If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team.

apps/admin-x-settings/src/components/settings/general/Users.tsx

Oops! Something went wrong! :(

ESLint: 8.44.0

ESLint couldn't find the plugin "eslint-plugin-react-hooks".

(The package "eslint-plugin-react-hooks" was not found when loaded as a Node module from the directory "/apps/admin-x-settings".)

It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:

npm install eslint-plugin-react-hooks@latest --save-dev

The plugin "eslint-plugin-react-hooks" was referenced from the config file in "apps/admin-x-settings/.eslintrc.cjs".

If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4cd01d2 and 0df224f.

📒 Files selected for processing (13)
  • apps/admin-x-framework/src/api/settings.ts (1 hunks)
  • apps/admin-x-framework/src/test/responses/settings.json (1 hunks)
  • apps/admin-x-settings/src/components/settings/general/Users.tsx (3 hunks)
  • ghost/admin/app/services/settings.js (1 hunks)
  • ghost/core/core/server/api/endpoints/utils/serializers/input/settings.js (1 hunks)
  • ghost/core/core/server/api/endpoints/utils/serializers/input/utils/settings-key-group-mapper.js (1 hunks)
  • ghost/core/core/server/api/endpoints/utils/serializers/input/utils/settings-key-type-mapper.js (1 hunks)
  • ghost/core/core/server/data/migrations/versions/5.112/2025-03-10-10-01-01-add-require-mfa-setting.js (1 hunks)
  • ghost/core/core/server/data/schema/default-settings/default-settings.json (1 hunks)
  • ghost/core/test/unit/server/data/exporter/index.test.js (1 hunks)
  • ghost/core/test/unit/server/data/schema/integrity.test.js (1 hunks)
  • ghost/session-service/lib/session-service.js (1 hunks)
  • ghost/session-service/test/SessionService.test.js (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (10)
  • ghost/session-service/lib/session-service.js
  • ghost/core/core/server/api/endpoints/utils/serializers/input/utils/settings-key-group-mapper.js
  • ghost/core/test/unit/server/data/exporter/index.test.js
  • ghost/core/core/server/api/endpoints/utils/serializers/input/utils/settings-key-type-mapper.js
  • apps/admin-x-framework/src/test/responses/settings.json
  • ghost/core/core/server/api/endpoints/utils/serializers/input/settings.js
  • ghost/core/test/unit/server/data/schema/integrity.test.js
  • ghost/admin/app/services/settings.js
  • apps/admin-x-framework/src/api/settings.ts
  • ghost/core/core/server/data/schema/default-settings/default-settings.json
⏰ Context from checks skipped due to timeout of 90000ms (15)
  • GitHub Check: Browser tests
  • GitHub Check: Ghost-CLI tests
  • GitHub Check: Unit tests (Node 22.13.1)
  • GitHub Check: Unit tests (Node 20.11.1)
  • GitHub Check: Database tests (Node 20.11.1, sqlite3)
  • GitHub Check: Unit tests (Node 18.12.1)
  • GitHub Check: Regression tests (Node 20.11.1, sqlite3)
  • GitHub Check: Database tests (Node 22.13.1, mysql8)
  • GitHub Check: Regression tests (Node 20.11.1, mysql8)
  • GitHub Check: Database tests (Node 20.11.1, mysql8)
  • GitHub Check: Database tests (Node 18.12.1, mysql8)
  • GitHub Check: Admin-X Settings tests
  • GitHub Check: Lint
  • GitHub Check: i18n
  • GitHub Check: Admin tests - Chrome
🔇 Additional comments (10)
ghost/core/core/server/data/migrations/versions/5.112/2025-03-10-10-01-01-add-require-mfa-setting.js (1)

1-8: Migration looks good for adding the new MFA setting

The migration script correctly adds the new require_email_mfa setting with appropriate type and group configuration. The setting is properly initialized to false by default and categorized under the 'security' group.

ghost/session-service/test/SessionService.test.js (5)

17-21: LGTM: Settings cache mock correctly implements the new MFA setting

The mock properly returns false for the require_email_mfa setting key, matching the expected default behavior in the first test case.


32-33: Good - Settings cache is properly injected to SessionService

The getSettingsCache function is correctly passed to the SessionService constructor.


166-170: LGTM: Consistent implementation of settings cache mock

The mock implementation for the "Can verify a user session" test case is consistent with the first test case.


181-182: Settings cache properly injected

The getSettingsCache function is correctly passed to the SessionService constructor in this test case.


582-643: Comprehensive test case for the new MFA behavior

This test case thoroughly validates that when require_email_mfa is enabled:

  1. The verified flag is correctly set to undefined when removing a user from the session
  2. When creating a new session, the verified flag starts as undefined

This ensures that users must re-verify with 2FA on each login when this setting is enabled, which aligns with the PR objective of requiring 2FA for every login attempt rather than just once per device.

apps/admin-x-settings/src/components/settings/general/Users.tsx (4)

6-7: LGTM: Required components imported

The necessary UI components are properly imported from the design system.


10-11: Good - Settings API hooks imported

The required hooks for accessing and modifying settings are correctly imported.


278-283: Well-implemented settings access for the 2FA feature

The code correctly:

  1. Retrieves the current settings
  2. Extracts and parses the require_email_mfa and labs settings
  3. Sets up the mutation function for updating settings
  4. Prepares error handling

This provides all the necessary data and functions for managing the 2FA toggle.


301-327: Well-designed UI for the 2FA security toggle

The implementation:

  1. Conditionally renders the section only when the labs feature flag is enabled
  2. Uses proper semantic structure with clear headings and descriptions
  3. Correctly binds the toggle state to the setting value
  4. Implements proper error handling for settings updates
  5. Uses appropriate styling and layout

The UI is user-friendly and properly integrated with the rest of the component.

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@sam-lord sam-lord requested a review from vershwal March 5, 2025 12:48
@github-actions github-actions bot added the migration [pull request] Includes migration for review label Mar 5, 2025
Copy link
Contributor

github-actions bot commented Mar 5, 2025

It looks like this PR contains a migration 👀
Here's the checklist for reviewing migrations:

General requirements

  • ⚠️ Tested on the staging database servers
  • Satisfies idempotency requirement (both up() and down())
  • Does not reference models
  • Filename is in the correct format (and correctly ordered)
  • Targets the next minor version
  • All code paths have appropriate log messages
  • Uses the correct utils
  • Contains a minimal changeset
  • Does not mix DDL/DML operations
  • Tested in MySQL and SQLite

Schema changes

  • Both schema change and related migration have been implemented
  • For index changes: has been performance tested for large tables
  • For new tables/columns: fields use the appropriate predefined field lengths
  • For new tables/columns: field names follow the appropriate conventions
  • Does not drop a non-alpha table outside of a major version

Data changes

  • Mass updates/inserts are batched appropriately
  • Does not loop over large tables/datasets
  • Defends against missing or invalid data
  • For settings updates: follows the appropriate guidelines

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
apps/admin-x-settings/src/components/settings/general/Users.tsx (2)

301-323: Consider adding a loading state during settings update

The toggle implementation for requiring email 2FA is functional, but lacks visual feedback during the settings update process. This could lead to confusion if there's server latency.

Consider adding a loading state to provide better user feedback:

 {labs.staff2fa && (
     <>
         <Separator />
         <Toggle
             checked={require2fa}
+            disabled={isUpdating}
             direction='rtl'
             gap='gap-0'
             label='Require email two-factor authentication on every login'
             labelClasses='w-full'
             onChange={async () => {
                 const newValue = !require2fa;
+                let isUpdating = true;
                 try {
                     await editSettings([{
                         key: 'require_email_mfa',
                         value: newValue
                     }]);
                 } catch (error) {
                     handleError(error);
+                } finally {
+                    isUpdating = false;
                 }
             }}
         />
+        {isUpdating && <span className="ml-2 text-sm text-grey">Updating...</span>}
     </>
 )}

310-320: Consider adding a confirmation dialog for this security setting change

Toggling this setting affects security for all users and forces them to verify on every login. Without a confirmation, an admin might toggle this accidentally without understanding the consequences.

Consider adding a confirmation dialog before applying the change:

 onChange={async () => {
     const newValue = !require2fa;
+    // For enabling MFA, show a confirmation
+    if (newValue && !window.confirm('This will require all staff to verify their login with email 2FA every time they sign in. Are you sure you want to proceed?')) {
+        return;
+    }
     try {
         await editSettings([{
             key: 'require_email_mfa',
             value: newValue
         }]);
     } catch (error) {
         handleError(error);
     }
 }}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 991c9ec and 2c8f79c.

📒 Files selected for processing (10)
  • apps/admin-x-framework/src/test/responses/settings.json (1 hunks)
  • apps/admin-x-settings/src/components/settings/general/Users.tsx (3 hunks)
  • ghost/core/core/server/api/endpoints/utils/serializers/input/settings.js (1 hunks)
  • ghost/core/core/server/api/endpoints/utils/serializers/input/utils/settings-key-group-mapper.js (1 hunks)
  • ghost/core/core/server/api/endpoints/utils/serializers/input/utils/settings-key-type-mapper.js (1 hunks)
  • ghost/core/core/server/data/migrations/versions/5.111/2025-03-03-15-05-38-add-require-mfa-setting.js (1 hunks)
  • ghost/core/core/server/data/schema/default-settings/default-settings.json (1 hunks)
  • ghost/core/core/shared/settings-cache/public.js (1 hunks)
  • ghost/session-service/lib/session-service.js (1 hunks)
  • ghost/session-service/test/SessionService.test.js (5 hunks)
🔇 Additional comments (18)
ghost/core/core/shared/settings-cache/public.js (1)

51-51: Clean Addition of the require_email_mfa Setting

The new setting is correctly added to the list of public settings, making it accessible to the frontend components that will need to display or modify this configuration.

ghost/session-service/lib/session-service.js (1)

311-316: Well-Implemented MFA Session State Management

The code correctly checks the require_email_mfa setting and removes the verified status when a user signs out, ensuring that 2FA will be required on the next login when this setting is enabled. This implementation aligns perfectly with the PR objective of requiring 2FA for every login attempt rather than just once per device.

ghost/core/core/server/data/migrations/versions/5.111/2025-03-03-15-05-38-add-require-mfa-setting.js (1)

1-8: Clean and Proper Migration Implementation

The migration file correctly uses the utility function addSetting to add the new require_email_mfa setting with appropriate metadata:

  • The default value is set to 'false', making it an opt-in feature
  • The type is properly set as 'boolean'
  • The setting is correctly categorized under the 'security' group

This follows the established patterns for adding new settings in the Ghost platform.

apps/admin-x-framework/src/test/responses/settings.json (1)

338-342: Test Settings Properly Updated

The new setting has been correctly added to the test responses, ensuring that tests will have access to the require_email_mfa configuration with its default value of false. This keeps the test environment in sync with the production settings.

ghost/core/core/server/api/endpoints/utils/serializers/input/utils/settings-key-type-mapper.js (1)

57-58: Mapping added correctly for the new 2FA setting.

The require_email_mfa setting is correctly mapped to the 'boolean' type, which aligns with its implementation in the default settings schema.

ghost/core/core/server/api/endpoints/utils/serializers/input/utils/settings-key-group-mapper.js (1)

50-51: Appropriate security categorization for the 2FA setting.

The require_email_mfa setting is appropriately mapped to the 'security' group, which correctly categorizes this authentication-related configuration.

ghost/core/core/server/data/schema/default-settings/default-settings.json (1)

599-603: New security section with 2FA setting properly defined.

The new security section with the require_email_mfa setting is properly defined with the appropriate default value (false) and type (boolean). This implementation aligns with the PR objective to make 2FA configurable at the admin level.

One thing to note is that this setting will default to not requiring 2FA on every login (which is a reasonable default for backward compatibility), but admins can enable it through the settings UI.

ghost/core/core/server/api/endpoints/utils/serializers/input/settings.js (2)

78-79: Added setting to editable settings list.

The require_email_mfa setting is correctly added to the EDITABLE_SETTINGS array, making it configurable through the API.

This change connects the new setting to the rest of the system by making it editable via the Ghost Admin interface, fulfilling the PR objective.


1-130:

✅ Verification successful

Verify session management and sign-out behavior with the new 2FA setting.

Based on the PR description, this setting should ensure that the verified flag is removed upon signing out when the setting is enabled. While the setting itself is correctly implemented here, we should verify that the session service has been updated to check this setting during logout operations.


🏁 Script executed:

#!/bin/bash
# Description: Check if the session service handles the require_email_mfa setting during sign-out

# Look for code that handles the require_email_mfa setting in the session service
echo "Checking for session service handling of require_email_mfa..."
rg -A 5 -B 5 "require_email_mfa" --glob "ghost/session-service/**"

# Look for sign-out or logout related functionality that might be affected
echo "Checking for modified sign-out behavior..."
rg -A 5 -B 5 "signOut|logout|sign-out|log-out" --glob "ghost/session-service/**"

Length of output: 4569


Session Management 2FA Behavior Confirmed

After verifying the session service code:

  • In ghost/session-service/lib/session-service.js, the logout function checks the require_email_mfa setting using getSettingsCache('require_email_mfa') and correctly resets the session.verified flag when the setting is enabled.
  • The test files in ghost/session-service/test/SessionService.test.js cover both cases (when MFA is enabled and disabled), ensuring the expected behavior during sign-out.

No further changes are required.

apps/admin-x-settings/src/components/settings/general/Users.tsx (4)

6-6: Good addition of necessary UI components

Adding Separator and Toggle components from the design system is appropriate for creating the new 2FA setting UI.


10-10: Well-structured import of settings API methods

Importing getSettingValue and useEditSettings from the framework API provides a clean approach to interact with the settings functionality.


278-283: Good implementation of settings access and state management

The code correctly retrieves the current state of the require_email_mfa setting and parses the labs configuration to check for feature availability. This follows the recommended pattern for settings management in Ghost.


308-308:

❓ Verification inconclusive

Verify the label text with stakeholders

The label "Require email two-factor authentication on every login" is clear, but should be verified with stakeholders to ensure it matches the intended user experience and product terminology.


🌐 Web query:

Ghost email-based MFA terminology

Error during web search


Action Required: Verify MFA Terminology Label with Stakeholders

The label

label='Require email two-factor authentication on every login'

appears clear from a wording perspective. However, since our attempt to automatically verify "Ghost email-based MFA terminology" returned an error, please ensure that this label aligns with the intended product terminology by directly confirming with stakeholders.

ghost/session-service/test/SessionService.test.js (5)

17-21: Well-structured mock for the settings cache

The getSettingsCache spy correctly mocks the behavior of returning the require_email_mfa setting value.


166-170: Consistent approach to mocking settings values

The implementation maintains consistency with the first test in how the settings cache mock is structured.


582-643: Good test case for the new behavior with require_email_mfa enabled

This test case properly validates the new functionality: when the require_email_mfa setting is enabled, the verified flag should be removed upon signing out. This ensures that 2FA is required for every login attempt, not just the first one per device.

The test structure follows the same pattern as existing tests, making it easy to understand and maintain.


592-598: Consistent mock implementation for getSettingsCache

Good implementation of the settings cache mock that returns true for the 'require_email_mfa' key and 'site-title' for other keys. This matches how other tests in the file handle similar scenarios.


636-638: Critical verification for the core functionality

These assertions are the key test for the new functionality: when require_email_mfa is enabled, removing a user from a session should also clear the verified flag. This differs from the existing behavior where the verified flag was maintained.

The test correctly verifies that both user_id and verified are undefined after removeUserForSession is called.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
apps/admin-x-settings/src/components/settings/general/Users.tsx (3)

278-282: Consider making JSON parsing more robust.

The code correctly retrieves and manages global settings, but there's a potential edge case when parsing the labs JSON string.

- const labs = JSON.parse(getSettingValue<string>(settings, 'labs') || '{}');
+ const labsValue = getSettingValue<string>(settings, 'labs') || '{}';
+ const labs = JSON.parse(labsValue);

This change separates the retrieval and parsing steps, making the code more readable and avoiding potential issues if getSettingValue returned null instead of an empty string.


301-327: Consider adding loading state and success feedback to the toggle.

The implementation of the 2FA security settings section is clean and well-structured, with proper conditional rendering based on the feature flag. However, there are a few user experience improvements that could be made.

The toggle doesn't show a loading state while the setting is being updated, which could lead to users clicking multiple times if there's any delay. Additionally, there's no success feedback when the setting is updated successfully.

Here's a suggested improvement:

+ const [isUpdating, setIsUpdating] = useState(false);

<Toggle
    checked={require2fa}
    direction='rtl'
    gap='gap-0'
+   disabled={isUpdating}
    onChange={async () => {
        const newValue = !require2fa;
        try {
+           setIsUpdating(true);
            await editSettings([{
                key: 'require_email_mfa',
                value: newValue
            }]);
+           showToast({
+               title: newValue ? 'Email 2FA requirement enabled' : 'Email 2FA requirement disabled',
+               type: 'success'
+           });
        } catch (error) {
            handleError(error);
        } finally {
+           setIsUpdating(false);
        }
    }}
/>

This change adds:

  1. A loading state to prevent multiple clicks
  2. A success toast to provide feedback when the setting is updated

305-308: Enhance accessibility with detailed explanations.

The UI text is clear but could benefit from additional context about what email 2FA means for administrators.

Consider expanding the description to provide more context:

<div className='flex flex-col'>
    <span className='text-[1.5rem] font-semibold tracking-tight'>Security settings</span>
-   <span>Enable email 2FA for all staff logins</span>
+   <span>Enable email 2FA for all staff logins. When enabled, staff members will need to verify their login via email every time they sign in, even on previously verified devices.</span>
</div>

This helps users understand the implications of enabling this setting.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2c8f79c and d03180d.

📒 Files selected for processing (1)
  • apps/admin-x-settings/src/components/settings/general/Users.tsx (3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Setup
🔇 Additional comments (1)
apps/admin-x-settings/src/components/settings/general/Users.tsx (1)

6-6: Good addition of necessary imports.

The imports for UI components (Separator, Toggle) and settings management hooks (getSettingValue, useEditSettings) are properly added to support the new 2FA functionality.

Also applies to: 10-10

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
apps/admin-x-settings/src/components/settings/general/Users.tsx (1)

301-327: Well-implemented conditional 2FA toggle UI

The 2FA toggle UI is properly implemented with:

  • Conditional rendering based on the labs.staff2fa flag
  • Clear labeling and description for the feature
  • Proper toggle state management and error handling
  • Asynchronous update of the setting when the toggle is changed

Consider using a more consistent naming convention - the setting is called 'require_email_mfa' but the variable is 'require2fa'. While functionally correct, consistent naming would improve maintainability.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d03180d and 0286bec.

📒 Files selected for processing (11)
  • apps/admin-x-framework/src/api/settings.ts (1 hunks)
  • apps/admin-x-framework/src/test/responses/settings.json (1 hunks)
  • apps/admin-x-settings/src/components/settings/general/Users.tsx (3 hunks)
  • ghost/admin/app/services/settings.js (1 hunks)
  • ghost/core/core/server/api/endpoints/utils/serializers/input/settings.js (1 hunks)
  • ghost/core/core/server/api/endpoints/utils/serializers/input/utils/settings-key-group-mapper.js (1 hunks)
  • ghost/core/core/server/api/endpoints/utils/serializers/input/utils/settings-key-type-mapper.js (1 hunks)
  • ghost/core/core/server/data/migrations/versions/5.111/2025-03-03-15-05-38-add-require-mfa-setting.js (1 hunks)
  • ghost/core/core/server/data/schema/default-settings/default-settings.json (1 hunks)
  • ghost/session-service/lib/session-service.js (1 hunks)
  • ghost/session-service/test/SessionService.test.js (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (7)
  • apps/admin-x-framework/src/test/responses/settings.json
  • ghost/core/core/server/api/endpoints/utils/serializers/input/utils/settings-key-type-mapper.js
  • ghost/core/core/server/api/endpoints/utils/serializers/input/settings.js
  • ghost/core/core/server/data/schema/default-settings/default-settings.json
  • ghost/session-service/lib/session-service.js
  • ghost/core/core/server/api/endpoints/utils/serializers/input/utils/settings-key-group-mapper.js
  • ghost/core/core/server/data/migrations/versions/5.111/2025-03-03-15-05-38-add-require-mfa-setting.js
🔇 Additional comments (7)
apps/admin-x-framework/src/api/settings.ts (1)

34-34: Good addition of 'security' group to settings query

Adding the 'security' group to the defaultSearchParams ensures that security-related settings, particularly the new 'require_email_mfa' setting, are loaded when browsing settings.

ghost/admin/app/services/settings.js (1)

58-58: Good addition of 'security' group to queryRecord

Including the 'security' group in the settings query ensures the Ember admin application can load and modify security-related settings, particularly the new require_email_mfa setting.

apps/admin-x-settings/src/components/settings/general/Users.tsx (2)

6-6: Appropriate UI component imports for 2FA toggle

The addition of Separator and Toggle components from the design system, along with the necessary settings API functions, provides the UI elements needed for the 2FA requirement feature.

Also applies to: 10-10


278-282: Properly retrieves and prepares settings for 2FA toggle

Good implementation that retrieves the global settings, extracts the 'require_email_mfa' setting with a default value of false, and sets up the editSettings mutation for updating the setting.

ghost/session-service/test/SessionService.test.js (3)

17-21: Good test setup for settings cache

The implementation of the getSettingsCache spy function properly mocks the settings retrieval for testing purposes, returning false for the 'require_email_mfa' setting.

Also applies to: 32-32


166-170: Consistent settings spy setup across tests

Good consistency in implementing the getSettingsCache spy function across multiple test cases, ensuring proper test isolation.

Also applies to: 181-181


582-643: Comprehensive test for verified session removal with 2FA enabled

This test case properly verifies that when the 'require_email_mfa' setting is enabled:

  1. A session can be created for a user
  2. The session can be verified, setting the 'verified' flag to true
  3. When the user is removed from the session, both the user_id and verified properties are cleared
  4. When the session is recreated, the verified property remains undefined

This ensures that 2FA is required for every login attempt when the setting is enabled, not just once per device.

@Ghost-Slimer
Copy link

Deployed to staging with ID: 3268

How does this work?

1 similar comment
@Ghost-Slimer
Copy link

Deployed to staging with ID: 3268

How does this work?

@Ghost-Slimer
Copy link

Deployed to staging with ID: 3268

How does this work?

@sam-lord sam-lord merged commit 8ffe64e into main Mar 10, 2025
26 checks passed
@sam-lord sam-lord deleted the 2fa-setting branch March 10, 2025 10:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
browser-tests deploy-to-staging migration [pull request] Includes migration for review
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants