-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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 domain binding SIWE redesign alert row #25281
Changes from all commits
04318ca
1fda0b5
68e8b29
979ad8f
661de18
2a9dbeb
35efdfc
2f58e32
fbcf497
f1c0ac7
dfa35a1
5e8fb5b
9ed03d9
78363ec
ca059ab
44bd4e8
8bb125b
c21feb2
f779176
07b8a97
abc8365
7825774
8fcaec9
60a6493
30f7405
a07296d
1f18f72
c195dde
1069915
f8ddcbb
245c5c6
c45f50e
3763396
a467e42
4ecafc7
5ae550d
f87de03
9d22e20
be02ff6
323f1f8
8397115
ea6aeda
bd39c5b
780f5b7
834f68a
3771748
ffda4d1
a98fbcd
e817fec
51df149
c2e8a8c
e78bdd0
95f28be
ec7f458
52502c2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
import { ApprovalType } from '@metamask/controller-utils'; | ||
import { Severity } from '../../../../../helpers/constants/design-system'; | ||
import { renderHookWithProvider } from '../../../../../../test/lib/render-helpers'; | ||
import mockState from '../../../../../../test/data/mock-state.json'; | ||
import useDomainMismatchAlert from './useDomainMismatchAlerts'; | ||
|
||
const MOCK_ORIGIN = 'https://example-dapp.example'; | ||
const MOCK_SUSPICIOUS_DOMAIN = 'http://suspicious.example'; | ||
const MOCK_ADDRESS = '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc'; | ||
|
||
const mockSiwe = { | ||
isSIWEMessage: true, | ||
parsedMessage: { | ||
domain: MOCK_SUSPICIOUS_DOMAIN, | ||
address: MOCK_ADDRESS, | ||
statement: | ||
'Click to sign in and accept the Terms of Service: https://community.metamask.io/tos', | ||
uri: 'http://localhost:8080', | ||
version: '1', | ||
nonce: 'STMt6KQMwwdOXE306', | ||
chainId: 1, | ||
issuedAt: '2023-03-18T21:40:40.823Z', | ||
resources: [ | ||
'ipfs://Qme7ss3ARVgxv6rXqVPiikMJ8u2NLgmgszg13pYrDKEoiu', | ||
'https://example.com/my-web2-claim.json', | ||
], | ||
}, | ||
}; | ||
|
||
const mockCurrentConfirmation = { | ||
id: '1', | ||
status: 'unapproved', | ||
time: new Date().getTime(), | ||
type: ApprovalType.PersonalSign, | ||
msgParams: { | ||
from: MOCK_ADDRESS, | ||
data: '0x6c6f63616c686f73743a383038302077616e747320796f7520746f207369676e20696e207769746820796f757220457468657265756d206163636f756e743a0a3078466232433135303034333433393034653566343038323537386334653865313131303563463765330a0a436c69636b20746f207369676e20696e20616e642061636365707420746865205465726d73206f6620536572766963653a2068747470733a2f2f636f6d6d756e6974792e6d6574616d61736b2e696f2f746f730a0a5552493a20687474703a2f2f6c6f63616c686f73743a383038300a56657273696f6e3a20310a436861696e2049443a20310a4e6f6e63653a2053544d74364b514d7777644f58453330360a4973737565642041743a20323032322d30332d31385432313a34303a34302e3832335a0a5265736f75726365733a0a2d20697066733a2f2f516d653773733341525667787636725871565069696b4d4a3875324e4c676d67737a673133705972444b456f69750a2d2068747470733a2f2f6578616d706c652e636f6d2f6d792d776562322d636c61696d2e6a736f6e', | ||
origin: MOCK_ORIGIN, | ||
siwe: mockSiwe, | ||
}, | ||
}; | ||
|
||
const mockExpectedState = { | ||
...mockState, | ||
metamask: { | ||
...mockState.metamask, | ||
unapprovedPersonalMsgs: { | ||
'1': { ...mockCurrentConfirmation }, | ||
}, | ||
pendingApprovals: { | ||
'1': { | ||
...mockCurrentConfirmation, | ||
// origin: MOCK_ORIGIN, | ||
requestData: {}, | ||
requestState: null, | ||
expectsResult: false, | ||
}, | ||
}, | ||
preferences: { redesignedConfirmationsEnabled: true }, | ||
}, | ||
confirm: { currentConfirmation: mockCurrentConfirmation }, | ||
}; | ||
|
||
describe('useDomainMismatchAlert', () => { | ||
beforeAll(() => { | ||
process.env.ENABLE_CONFIRMATION_REDESIGN = 'true'; | ||
}); | ||
|
||
afterAll(() => { | ||
process.env.ENABLE_CONFIRMATION_REDESIGN = 'false'; | ||
}); | ||
|
||
describe('returns an empty array', () => { | ||
it('when there is no current confirmation', () => { | ||
const { result } = renderHookWithProvider( | ||
() => useDomainMismatchAlert(), | ||
mockState, | ||
); | ||
expect(result.current).toEqual([]); | ||
}); | ||
|
||
it('when the current confirmation is not a SIWE request', () => { | ||
const { result } = renderHookWithProvider( | ||
() => useDomainMismatchAlert(), | ||
{ | ||
...mockExpectedState, | ||
confirm: { | ||
currentConfirmation: { | ||
...mockCurrentConfirmation, | ||
msgParams: { | ||
...mockCurrentConfirmation.msgParams, | ||
siwe: { | ||
isSIWEMessage: false, | ||
parsedMessage: mockSiwe.parsedMessage, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
); | ||
expect(result.current).toEqual([]); | ||
}); | ||
|
||
it('when the SIWE domain matches origin', () => { | ||
const originalDomain = mockSiwe.parsedMessage.domain; | ||
mockSiwe.parsedMessage.domain = MOCK_ORIGIN; | ||
|
||
const { result } = renderHookWithProvider( | ||
() => useDomainMismatchAlert(), | ||
mockExpectedState, | ||
); | ||
expect(result.current).toEqual([]); | ||
|
||
mockSiwe.parsedMessage.domain = originalDomain; | ||
}); | ||
}); | ||
|
||
it('returns an alert when the SIWE domain does not match the origin', () => { | ||
const alertResponseExpected = { | ||
field: 'requestFrom', | ||
key: 'requestFrom', | ||
message: | ||
'The site making the request is not the site you’re signing into. This could be an attempt to steal your login credentials.', | ||
reason: 'Suspicious sign-in request', | ||
severity: Severity.Danger, | ||
}; | ||
const { result } = renderHookWithProvider( | ||
() => useDomainMismatchAlert(), | ||
mockExpectedState, | ||
); | ||
|
||
expect(result.current).toHaveLength(1); | ||
expect(result.current[0]).toStrictEqual(alertResponseExpected); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import { useMemo } from 'react'; | ||
import { useSelector } from 'react-redux'; | ||
import { | ||
isValidSIWEOrigin, | ||
WrappedSIWERequest, | ||
} from '@metamask/controller-utils'; | ||
|
||
import { Alert } from '../../../../../ducks/confirm-alerts/confirm-alerts'; | ||
import { Severity } from '../../../../../helpers/constants/design-system'; | ||
import { useI18nContext } from '../../../../../hooks/useI18nContext'; | ||
import { currentConfirmationSelector } from '../../../../../selectors'; | ||
|
||
import { SignatureRequestType } from '../../../types/confirm'; | ||
import { isSIWESignatureRequest } from '../../../utils'; | ||
|
||
export default function useDomainMismatchAlerts(): Alert[] { | ||
const t = useI18nContext(); | ||
|
||
const currentConfirmation = useSelector( | ||
currentConfirmationSelector, | ||
) as SignatureRequestType; | ||
const { msgParams } = currentConfirmation || {}; | ||
|
||
const isSIWE = isSIWESignatureRequest(currentConfirmation); | ||
const isInvalidSIWEDomain = | ||
isSIWE && !isValidSIWEOrigin(msgParams as WrappedSIWERequest); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It will be useful to include above 3 lines also inside There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I had this originally and then @matthewwalsh0 brought up a good point to reduce the # of observed dependencies |
||
|
||
const alerts = useMemo(() => { | ||
if (!isInvalidSIWEDomain) { | ||
return []; | ||
} | ||
|
||
return [ | ||
{ | ||
field: 'requestFrom', | ||
key: 'requestFrom', | ||
message: t('alertMessageSignInDomainMismatch'), | ||
reason: t('alertReasonSignIn'), | ||
severity: Severity.Danger, | ||
}, | ||
] as Alert[]; | ||
}, [isInvalidSIWEDomain, t]); | ||
|
||
return alerts; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh nice! I can update this in a subsequent alert PR to not need re-reviews