diff --git a/lib/types/siwe-types.js b/lib/types/siwe-types.js --- a/lib/types/siwe-types.js +++ b/lib/types/siwe-types.js @@ -128,7 +128,7 @@ +address: string, +message: string, +signature: string, - +nonceTimestamp: number, + +nonceTimestamp: ?number, }; export type IdentityWalletRegisterInput = { diff --git a/native/account/fullscreen-siwe-panel.react.js b/native/account/fullscreen-siwe-panel.react.js --- a/native/account/fullscreen-siwe-panel.react.js +++ b/native/account/fullscreen-siwe-panel.react.js @@ -28,6 +28,8 @@ } from '../utils/alert-messages.js'; import Alert from '../utils/alert.js'; +const siweSignatureRequestData = { messageType: SIWEMessageTypes.MSG_AUTH }; + type Props = { +goBackToPrompt: () => mixed, +closing: boolean, @@ -216,7 +218,7 @@ onClosed={ifBeforeSuccessGoBackToPrompt} onClosing={ifBeforeSuccessGoBackToPrompt} onSuccessfulWalletSignature={onSuccess} - siweMessageType={SIWEMessageTypes.MSG_AUTH} + siweSignatureRequestData={siweSignatureRequestData} setLoading={setLoading} /> diff --git a/native/account/registration/connect-ethereum.react.js b/native/account/registration/connect-ethereum.react.js --- a/native/account/registration/connect-ethereum.react.js +++ b/native/account/registration/connect-ethereum.react.js @@ -43,6 +43,10 @@ exactSearchUserActionTypes, ); +const siweSignatureRequestData = { + messageType: SIWEMessageTypes.MSG_AUTH, +}; + export type ConnectEthereumParams = { +userSelections: { +coolOrNerdMode?: ?CoolOrNerdMode, @@ -196,7 +200,7 @@ onClosed={onPanelClosed} closing={panelState === 'closing'} onSuccessfulWalletSignature={onSuccessfulWalletSignature} - siweMessageType={SIWEMessageTypes.MSG_AUTH} + siweSignatureRequestData={siweSignatureRequestData} setLoading={siwePanelSetLoading} keyserverCallParamOverride={serverCallParamOverride} /> @@ -204,8 +208,14 @@ } const { ethereumAccount } = cachedSelections; + invariant( + !ethereumAccount || ethereumAccount.nonceTimestamp, + 'nonceTimestamp must be set after connecting to Ethereum account', + ); const nonceExpired = - ethereumAccount && siweNonceExpired(ethereumAccount.nonceTimestamp); + ethereumAccount && + ethereumAccount.nonceTimestamp && + siweNonceExpired(ethereumAccount.nonceTimestamp); const alreadyHasConnected = !!ethereumAccount && !nonceExpired; React.useEffect(() => { if (nonceExpired) { diff --git a/native/account/registration/connect-farcaster.react.js b/native/account/registration/connect-farcaster.react.js --- a/native/account/registration/connect-farcaster.react.js +++ b/native/account/registration/connect-farcaster.react.js @@ -63,9 +63,14 @@ const goToNextStep = React.useCallback( (fid?: ?string) => { setWebViewState('closed'); - + invariant( + !ethereumAccount || ethereumAccount.nonceTimestamp, + 'nonceTimestamp must be set after connecting to Ethereum account', + ); const nonceExpired = - ethereumAccount && siweNonceExpired(ethereumAccount.nonceTimestamp); + ethereumAccount && + ethereumAccount.nonceTimestamp && + siweNonceExpired(ethereumAccount.nonceTimestamp); if (nonceExpired) { setCachedSelections(oldUserSelections => ({ ...oldUserSelections, diff --git a/native/account/registration/siwe-backup-message-creation.react.js b/native/account/registration/siwe-backup-message-creation.react.js --- a/native/account/registration/siwe-backup-message-creation.react.js +++ b/native/account/registration/siwe-backup-message-creation.react.js @@ -27,6 +27,10 @@ import { useSIWEPanelState } from '../siwe-hooks.js'; import SIWEPanel from '../siwe-panel.react.js'; +const siweBackupSignatureRequestData = { + messageType: SIWEMessageTypes.MSG_BACKUP, +}; + type CreateSIWEBackupMessageBaseProps = { +onSuccessfulWalletSignature: (result: SIWEResult) => void, +onExistingWalletSignature?: () => void, @@ -58,7 +62,7 @@ onClosed={onPanelClosed} closing={panelState === 'closing'} onSuccessfulWalletSignature={onSuccessfulWalletSignature} - siweMessageType={SIWEMessageTypes.MSG_BACKUP} + siweSignatureRequestData={siweBackupSignatureRequestData} setLoading={siwePanelSetLoading} /> ); diff --git a/native/account/siwe-panel.react.js b/native/account/siwe-panel.react.js --- a/native/account/siwe-panel.react.js +++ b/native/account/siwe-panel.react.js @@ -1,7 +1,6 @@ // @flow import BottomSheet from '@gorhom/bottom-sheet'; -import invariant from 'invariant'; import * as React from 'react'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import WebView from 'react-native-webview'; @@ -21,11 +20,12 @@ import type { SIWEWebViewMessage, SIWEResult, - SIWEMessageType, + SIWESignatureRequestData, } from 'lib/types/siwe-types.js'; import { getContentSigningKey } from 'lib/utils/crypto-utils.js'; import { useDispatchActionPromise } from 'lib/utils/redux-promise-utils.js'; import { usingCommServicesAccessToken } from 'lib/utils/services-utils.js'; +import { getPublicKeyFromSIWEStatement } from 'lib/utils/siwe-utils.js'; import { useKeyboardHeight } from '../keyboard/keyboard-hooks.js'; import { useSelector } from '../redux/redux-utils.js'; @@ -47,16 +47,15 @@ legacySiweAuthActionTypes, ); -type NonceInfo = { - +nonce: string, - +nonceTimestamp: number, -}; +type NonceInfo = + | { +nonceType: 'local', +nonce: string, +issuedAt: string } + | { +nonceType: 'remote', +nonce: string, +nonceTimestamp: number }; type Props = { +onClosed: () => mixed, +onClosing: () => mixed, +onSuccessfulWalletSignature: SIWEResult => mixed, - +siweMessageType: SIWEMessageType, + +siweSignatureRequestData: SIWESignatureRequestData, +closing: boolean, +setLoading: boolean => mixed, +keyserverCallParamOverride?: Partial, @@ -77,7 +76,8 @@ ); const { onClosing } = props; - const { siweMessageType } = props; + const { messageType, siweNonce, siweStatement, siweIssuedAt } = + props.siweSignatureRequestData; const legacySiweAuthCallLoading = useSelector( state => legacySiweAuthLoadingStatusSelector(state) === 'loading', @@ -92,13 +92,29 @@ const nonceNotNeededRef = React.useRef(false); React.useEffect(() => { + if (siweNonce && siweStatement && siweIssuedAt) { + setNonceInfo({ + nonce: siweNonce, + issuedAt: siweIssuedAt, + nonceType: 'local', + }); + const siwePrimaryIdentityPublicKey = + getPublicKeyFromSIWEStatement(siweStatement); + setPrimaryIdentityPublicKey(siwePrimaryIdentityPublicKey); + nonceNotNeededRef.current = true; + return; + } if (nonceNotNeededRef.current) { return; } const generateNonce = async (nonceFunction: () => Promise) => { try { const response = await nonceFunction(); - setNonceInfo({ nonce: response, nonceTimestamp: Date.now() }); + setNonceInfo({ + nonce: response, + nonceTimestamp: Date.now(), + nonceType: 'remote', + }); } catch (e) { Alert.alert( unknownErrorAlertDetails.title, @@ -139,6 +155,9 @@ getSIWENonceCall, identityGenerateNonce, onClosing, + siweNonce, + siweStatement, + siweIssuedAt, ]); const [isLoading, setLoading] = React.useState(true); @@ -183,7 +202,6 @@ if (address && signature) { nonceNotNeededRef.current = true; closeBottomSheet?.(); - invariant(nonceTimestamp, 'nonceTimestamp should be set'); await onSuccessfulWalletSignature({ address, message, @@ -220,16 +238,18 @@ }, [closing, closeBottomSheet]); const nonce = nonceInfo?.nonce; + const issuedAt = nonceInfo?.issuedAt; const source = React.useMemo( () => ({ uri: commSIWE, headers: { 'siwe-nonce': nonce, 'siwe-primary-identity-public-key': primaryIdentityPublicKey, - 'siwe-message-type': siweMessageType, + 'siwe-message-type': messageType, + 'siwe-message-issued-at': issuedAt, }, }), - [nonce, primaryIdentityPublicKey, siweMessageType], + [nonce, primaryIdentityPublicKey, messageType, issuedAt], ); const onWebViewLoaded = React.useCallback(() => {