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

feat: Add origin throttling modal #29656

Open
wants to merge 20 commits into
base: main
Choose a base branch
from

Conversation

OGPoyraz
Copy link
Member

@OGPoyraz OGPoyraz commented Jan 13, 2025

Description

This PR brings origin throttling modal functionality which is done in the mobile MetaMask/metamask-mobile#10082

The PR also needs an ApprovalController to be updated in order to subscribe the accepted and rejected approvals to handle user rejected approvals.

Core PR: MetaMask/core#5127

Open in GitHub Codespaces

Related issues

Fixes: https://github.com/MetaMask/MetaMask-planning/issues/3344
First mobile task: https://github.com/MetaMask/MetaMask-planning/issues/1822

Manual testing steps

  1. Go to test-dapp
  2. Trigger 2x sign/transaction and reject
  3. See modal appear on the third rejection
  4. Click "cancel" to ignore this modal and behaviour
  5. Trigger 2x sign/transaction and reject
  6. See modal appear on the third rejection
  7. Click "Temporarily block this site" and "Got It"
  8. Try sign/transaction - they will be blocked without error since they are considered & marked as "spam" by user
  9. Wait 1 minute to trigger or reset the situation

Screenshots/Recordings

origin.throttling.modal.mov

Before

After

Pre-merge author checklist

Pre-merge reviewer checklist

  • I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed).
  • I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots.

@OGPoyraz OGPoyraz requested a review from a team as a code owner January 13, 2025 12:09
@metamaskbot metamaskbot added the team-confirmations Push issues to confirmations team label Jan 13, 2025
}

export default function createOriginThrottlingMiddleware({
appStateController,
Copy link
Member

Choose a reason for hiding this comment

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

Can we try and encapsulate as much logic as possible inside this middleware for the sake of maintainability and testing?

As this is constructed from the MetamaskController, can we define callbacks for anything we need such as:

  • onApprovalAccept
  • onApprovalReject
  • updateThrottledOrigins
  • getThrottledOrigins

Copy link
Member Author

Choose a reason for hiding this comment

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

Done

return;
}

next();
Copy link
Member

Choose a reason for hiding this comment

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

What do we gain by subscribing to the approval controller events if we already have the means to check all the request responses via a callback provided to next similar to what we do in app/scripts/lib/createRPCMethodTrackingMiddleware.js?

Could we just check the result error and update the throttled state via our callbacks?

It would reduce coupling between this middleware and the controllers and further modularise all this throttling functionality?

Copy link
Member Author

Choose a reason for hiding this comment

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

Removed approval controller events, fixed all in middleware

export function validateOriginThrottling({
req,
end,
appStateController,
Copy link
Member

Choose a reason for hiding this comment

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

Is it worth a more specific callback to avoid coupling to the controller directly?

Copy link
Member Author

Choose a reason for hiding this comment

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

Done

'Request blocked due to spam filter.',
);

export function validateOriginThrottling({
Copy link
Member

Choose a reason for hiding this comment

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

Is this function necessary if it's only used internally and encapsulates a call to a single function? Would it add readability to the main middleware to move it inline?

Copy link
Member Author

Choose a reason for hiding this comment

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

Done

Copy link
Member

Choose a reason for hiding this comment

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

If we're able to encapsulate all the logic in the middleware, should these constants be moved there if there's no other usages of them?

Copy link
Member Author

Choose a reason for hiding this comment

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

These constants still be shared between UI and background. Not all of them(BLOCKABLE_METHODS used in background only) but is it make sense to have them together under shared?


return (
<PageFooter className="confirm-footer_page-footer">
<OriginThrottleModal
isOpen={showOriginThrottleModal}
onConfirmationCancel={onFooterCancel}
Copy link
Member

Choose a reason for hiding this comment

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

Rather than relying on forceCancel, could we instead just use onCancel here or a wrapper to avoid duplicating the location property?

Copy link
Member Author

Choose a reason for hiding this comment

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

I am not sure if I follow, can you elaborate on this?

<ModalFooter
paddingTop={4}
onSubmit={() => {
// Order of operations is important here to ensure the origin is reset after the confirmation is cancelled
Copy link
Member

Choose a reason for hiding this comment

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

❤️

Copy link
Member

Choose a reason for hiding this comment

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

Minor, is it worth storybooks for this component?

Copy link
Member Author

Choose a reason for hiding this comment

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

Done

return {
origin,
resetOrigin,
willNextRejectionReachThreshold:
Copy link
Member

Choose a reason for hiding this comment

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

Minor, could this be defined above in a variable to avoid the inline logic?

Copy link
Member Author

Choose a reason for hiding this comment

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

Done

return {
origin,
resetOrigin,
willNextRejectionReachThreshold:
Copy link
Member

Choose a reason for hiding this comment

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

Should we call this something like shouldThrottleOrigin to be explicit and also include some extra context for the external usages?

Copy link
Member Author

Choose a reason for hiding this comment

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

Done

return callback();
}

if ('error' in res && res.error && isUserRejectedError(res.error)) {
Copy link
Member Author

@OGPoyraz OGPoyraz Jan 17, 2025

Choose a reason for hiding this comment

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

in operator here is to satisfy type check on response

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
team-confirmations Push issues to confirmations team
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants