Skip to content

Conversation

@harshajain6114
Copy link

@harshajain6114 harshajain6114 commented Nov 19, 2025

Description

Adds support for a new preventIframe modal option that disables opening the QR modal when the SDK is running inside an iframe.
This improves SDK behavior for embedded apps, dashboards, widgets, and hosted integrations.

Changes included:

  • Added preventIframe to ModalOptions type
  • Added iframe detection + conditional modal block in modalUtils.ts
  • Updated README documentation with usage example and explanation

Testing (ignore for documentation update)

  • Tested iframe detection using a local HTML iframe wrapper
  • When preventIframe: true, the modal no longer renders
  • When unset or false, normal modal behavior continues
  • Verified no regression in QR flow, extension flow, or mobile redirects
  • Verified TypeScript builds successfully

Type of change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update

Checklist:


Additional Notes:

This enhancement ensures developers embedding the SDK inside external platforms have better control over modal behavior in restricted iframe environments.


Note

Adds a preventIframe modal option and iframe detection to block the QR modal inside iframes, plus safer modal lifecycle; updates README with usage.

  • SDK / Modal:
    • Add preventIframe to ModalOptions in src/utils/types.ts.
    • In QRCodeModal.show() (src/utils/modalUtils.ts):
      • Always close any existing modal before rendering.
      • Detect iframe context; if preventIframe is true, log, invoke onClose, and skip rendering.
  • Docs:
    • Update README.md with a new preventIframe section and usage example.

Written by Cursor Bugbot for commit 74902a0. This will update automatically on new commits. Configure here.

Summary by CodeRabbit

  • New Features

    • Added an optional preventIframe modal option to stop the QR modal from opening when running inside an iframe.
  • Improvements

    • Modal now reliably closes any existing modal before opening, reorders initialization steps, and includes safer iframe checks.
    • Enhanced error handling and more predictable auto-close behavior.
  • Documentation

    • README updated with an example showing how to use the preventIframe option.

✏️ Tip: You can customize this high-level summary in your review settings.

Added a new option 'preventScreenshot' to ModalOptions to control screenshot prevention behavior.
Added optional preventIframe option to QR modal settings.
@CLAassistant
Copy link

CLAassistant commented Nov 19, 2025

CLA assistant check
All committers have signed the CLA.

@coderabbitai
Copy link

coderabbitai bot commented Nov 19, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds an optional preventIframe boolean to modal options and updates the modal show flow to close any existing modal, check iframe/security when preventIframe is set (log and call onClose then return on detection/error), then proceed to insert DOM, generate QR, register listeners, and start the auto-close timer.

Changes

Cohort / File(s) Summary
Documentation
README.md
Documented new preventIframe option for ReclaimProofRequest.setModalOptions with a TypeScript example showing preventIframe: true.
Modal Type Definitions
src/utils/types.ts
Added optional property preventIframe?: boolean to ModalOptions.
Modal UI Logic
src/utils/modalUtils.ts
Always closes existing modal first; if preventIframe is true, checks for iframe or security error, logs and calls onClose (if provided) then returns early; otherwise inserts modal HTML, generates QR, adds listeners, starts auto-close timer; core flow wrapped in try-catch with logging.

Sequence Diagram(s)

sequenceDiagram
    participant Caller
    participant Modal as QRCodeModal
    participant DOM
    participant QR as QRGenerator

    Caller->>Modal: show(requestUrl)

    Modal->>DOM: Close existing modal (if any)

    alt preventIframe enabled
        Modal->>Modal: Check "in iframe" (may throw SecurityError)
        alt inside iframe or error
            Modal->>Modal: Log info
            Modal->>Caller: invoke onClose (optional)
            Modal-->>Caller: return early
        end
    end

    Modal->>DOM: Insert modal HTML
    Modal->>QR: Generate QR into modal
    QR-->>DOM: Render QR
    Modal->>DOM: Add event listeners
    Modal->>Modal: Start auto-close timer
    Modal-->>Caller: resolve show()
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Pay attention to iframe detection/security error handling in src/utils/modalUtils.ts.
  • Verify try-catch logging doesn't mask actionable errors and that timer lifecycle (start/clear) is correctly managed.
  • Confirm preventIframe?: boolean is backward-compatible and appropriately typed where ModalOptions is consumed.

Possibly related PRs

Suggested reviewers

  • Sajjad21990
  • Karam19
  • Kushal7788

Poem

🐰 I peek where frames might hide the light,
I check the frame and choose what's right—
If trapped within an iframe's seam,
I close my door and skip the gleam,
I hop away with code so bright.

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately summarizes the main changes: adding a preventIframe option to the QR modal and improving modal behavior.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@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: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/utils/types.ts (1)

62-72: ModalOptions is missing preventIframe and exposes unused preventScreenshot

The runtime code (src/utils/modalUtils.ts) and README both rely on a preventIframe modal option, but ModalOptions only declares preventScreenshot?: boolean. Accessing this.options.preventIframe on ModalOptions is a TypeScript error, and integrators copying the README snippet will see a type error.

You should at minimum add preventIframe?: boolean to ModalOptions, and consider whether preventScreenshot should stay (it’s currently unused and not documented here).

For example:

 export type ModalOptions = {
   title?: string;
   description?: string;
   extensionUrl?: string;
   darkTheme?: boolean;
   modalPopupTimer?: number;
   showExtensionInstallButton?: boolean;
   onClose?: () => void;
-   // NEW OPTION
-  preventScreenshot?: boolean;   // when true: add blur + disable copy/screenshot hints
+  // Prevent opening the QR modal when running inside an iframe
+  preventIframe?: boolean;
+
+  // (Optional / future) when true: add blur + disable copy/screenshot hints
+  preventScreenshot?: boolean;
 };
♻️ Duplicate comments (1)
README.md (1)

258-267: Docs use preventIframe that isn’t currently in ModalOptions

This example correctly shows the intended preventIframe usage, but ModalOptions in src/utils/types.ts doesn’t yet declare preventIframe (only preventScreenshot). Until the type is updated, TypeScript consumers will get errors when they copy this snippet.

Once you add preventIframe?: boolean to ModalOptions (see comment in src/utils/types.ts), the README and types will be in sync.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9ed9e6f and 867a9fe.

📒 Files selected for processing (3)
  • README.md (1 hunks)
  • src/utils/modalUtils.ts (2 hunks)
  • src/utils/types.ts (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/utils/modalUtils.ts (1)
src/utils/logger.ts (1)
  • error (46-48)

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

This PR is being reviewed by Cursor Bugbot

Details

Your team is on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle for each member of your team.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

Copy link

@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

♻️ Duplicate comments (1)
src/utils/modalUtils.ts (1)

49-49: Potential duplicate onClose invocation when reopening modal.

Calling this.close() here triggers the onClose callback (lines 88-90) for any existing modal before opening a new one. If show() is called multiple times in succession, onClose will fire for each previous modal removal, which may not match user expectations—they might expect onClose only for user-initiated closes.

Consider one of these approaches:

  1. Add an optional parameter to close() to skip the callback during re-opening:

    close(skipCallback: boolean = false): void {
        // ... timer cleanup ...
        const modal = document.getElementById(this.modalId);
        if (modal) {
            modal.remove();
        }
        if (!skipCallback && this.options.onClose) {
            this.options.onClose();
        }
    }

    Then use this.close(true) at line 49.

  2. Extract DOM-only cleanup into a separate private method and use that instead of this.close().

🧹 Nitpick comments (3)
src/utils/types.ts (1)

70-73: Add inline documentation for preventIframe and remove temporary comment.

The addition of preventIframe resolves the type concern from the previous review. However, there's a documentation inconsistency:

  • preventScreenshot has an inline comment explaining its behavior
  • preventIframe lacks any documentation

For consistency and maintainability, please add an inline comment for preventIframe explaining when/why the modal is blocked, and remove the "// NEW OPTION" scaffolding comment.

-  // NEW OPTION
-  preventScreenshot?: boolean;   // when true: add blur + disable copy/screenshot hints
-  preventIframe?: boolean;
+  preventScreenshot?: boolean;   // when true: add blur + disable copy/screenshot hints
+  preventIframe?: boolean;        // when true: block modal rendering inside iframes
src/utils/modalUtils.ts (2)

30-46: Iframe prevention logic is solid; consider log level adjustment.

The iframe detection correctly handles both the standard check (window.self !== window.top) and cross-origin security errors. The addition of preventIframe to ModalOptions resolves the type concern from the previous review.

However, for better log level semantics, consider using a warning-level method instead of logger.info for these blocking scenarios, since they represent prevented operations rather than normal informational events:

                if (window.self !== window.top) {
-                   logger.info(
+                   logger.warn?.(
                        "Reclaim Modal blocked: preventIframe = true and page is inside an iframe."
-                   );
+                   ) ?? logger.info("Reclaim Modal blocked: preventIframe = true and page is inside an iframe.");
                    if (this.options.onClose) this.options.onClose();
                    return;
                }
            } catch {
-               logger.info(
+               logger.warn?.(
                    "Reclaim Modal blocked: preventIframe = true and iframe check threw a security error."
-               );
+               ) ?? logger.info("Reclaim Modal blocked: preventIframe = true and iframe check threw a security error.");
                if (this.options.onClose) this.options.onClose();
                return;
            }

(Only apply if logger.warn is available in your logger module.)


66-69: Use error-level logging for exceptions.

The try-catch wrapper is good for robustness, but logger.info is not the appropriate log level for error scenarios. If your logger module supports it, use an error-level method:

    } catch (error) {
-       logger.info('Error showing QR code modal:', error);
+       logger.error?.('Error showing QR code modal:', error) ?? logger.info('Error showing QR code modal:', error);
        throw 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 867a9fe and 15e5ffb.

📒 Files selected for processing (2)
  • src/utils/modalUtils.ts (2 hunks)
  • src/utils/types.ts (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Cursor Bugbot

Removed the preventScreenshot option from the types definition.
);
if (this.options.onClose) this.options.onClose();
return;
}
Copy link

Choose a reason for hiding this comment

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

Bug: onClose callback invoked when modal never opened

When preventIframe blocks the modal from opening, the onClose callback is invoked even though the modal was never actually opened. The onClose callback is documented as "Callback when modal is closed" and should only fire when an opened modal is being closed, not when the modal is prevented from opening. This creates semantic inconsistency and will cause false positives for developers tracking modal lifecycle events for analytics, cleanup, or state management purposes.

Fix in Cursor Fix in Web

Copy link
Author

Choose a reason for hiding this comment

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

Fixed the type definition issues and modal cleanup. All checks are passing. Ready for review!

Removed redundant modal close call before creating a new modal.
Copy link

@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

♻️ Duplicate comments (1)
src/utils/modalUtils.ts (1)

32-48: Remove onClose invocations when modal is blocked from opening.

The onClose callback at lines 38 and 45 should not be invoked when the modal is prevented from opening due to iframe detection. The callback is documented as "Callback when modal is closed" and should only fire when an opened modal is being closed, not when the modal is blocked from opening in the first place.

This creates semantic inconsistency and false positives for consumers tracking modal lifecycle events for analytics, cleanup, or state management. Additionally, since this.close() is called at line 29, if a modal was previously open, onClose will have already been invoked—resulting in a double invocation when the iframe check subsequently blocks.

Apply this diff to remove the incorrect onClose calls:

             try {
                 if (window.self !== window.top) {
                     logger.info(
                         "Reclaim Modal blocked: preventIframe = true and page is inside an iframe."
                     );
-                    if (this.options.onClose) this.options.onClose();
                     return;
                 }
             } catch {
                 logger.info(
                     "Reclaim Modal blocked: preventIframe = true and iframe check threw a security error."
                 );
-                if (this.options.onClose) this.options.onClose();
                 return;
             }

If you need to notify consumers when the modal is blocked (as opposed to closed), consider introducing a separate callback like onBlocked in ModalOptions.

🧹 Nitpick comments (1)
src/utils/modalUtils.ts (1)

26-69: Well-structured modal lifecycle flow.

The restructuring of the show() method is solid:

  • Closing any existing modal first (line 29) prevents stale DOM and timer leaks
  • The iframe prevention check (lines 32-48) gates expensive operations before they occur
  • The modal creation sequence (lines 50-63) follows a logical order: create HTML → insert DOM → generate QR → register listeners → start timer
  • The try-catch wrapper provides appropriate error handling

Optional optimization: Consider moving the iframe check before this.close() at line 29. This avoids unnecessarily closing an existing modal when the new one will be blocked anyway:

  async show(requestUrl: string): Promise<void> {
    try {
-       // Always close previous modal FIRST
-       this.close();
-
        // IFRAME CHECK
        if (this.options.preventIframe) {
            try {
                if (window.self !== window.top) {
                    logger.info(
                        "Reclaim Modal blocked: preventIframe = true and page is inside an iframe."
                    );
                    return;
                }
            } catch {
                logger.info(
                    "Reclaim Modal blocked: preventIframe = true and iframe check threw a security error."
                );
                return;
            }
        }
+
+       // Always close previous modal before opening new one
+       this.close();

        // Create modal HTML
        const modalHTML = this.createModalHTML();

This ensures that if the modal is blocked, the existing modal remains open rather than being closed and not replaced.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6af3dc6 and 74902a0.

📒 Files selected for processing (1)
  • src/utils/modalUtils.ts (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Cursor Bugbot

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants