Changeset View
Changeset View
Standalone View
Standalone View
web/account/siwe-login-form.react.js
// @flow | // @flow | ||||
import '@rainbow-me/rainbowkit/styles.css'; | import '@rainbow-me/rainbowkit/styles.css'; | ||||
import olm from '@matrix-org/olm'; | |||||
import invariant from 'invariant'; | import invariant from 'invariant'; | ||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import { useAccount, useSigner } from 'wagmi'; | import { useAccount, useSigner } from 'wagmi'; | ||||
import { | import { | ||||
getSIWENonce, | getSIWENonce, | ||||
getSIWENonceActionTypes, | getSIWENonceActionTypes, | ||||
siweAuth, | siweAuth, | ||||
siweAuthActionTypes, | siweAuthActionTypes, | ||||
} from 'lib/actions/siwe-actions.js'; | } from 'lib/actions/siwe-actions.js'; | ||||
import ConnectedWalletInfo from 'lib/components/connected-wallet-info.react.js'; | import ConnectedWalletInfo from 'lib/components/connected-wallet-info.react.js'; | ||||
import SWMansionIcon from 'lib/components/SWMansionIcon.react.js'; | import SWMansionIcon from 'lib/components/SWMansionIcon.react.js'; | ||||
import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js'; | import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js'; | ||||
import type { LogInStartingPayload } from 'lib/types/account-types.js'; | import type { LogInStartingPayload } from 'lib/types/account-types.js'; | ||||
import type { | import type { | ||||
OLMIdentityKeys, | OLMIdentityKeys, | ||||
PickledOLMAccount, | |||||
SignedIdentityKeysBlob, | SignedIdentityKeysBlob, | ||||
} from 'lib/types/crypto-types.js'; | } from 'lib/types/crypto-types.js'; | ||||
import { | import { | ||||
useDispatchActionPromise, | useDispatchActionPromise, | ||||
useServerCall, | useServerCall, | ||||
} from 'lib/utils/action-utils.js'; | } from 'lib/utils/action-utils.js'; | ||||
import { | import { | ||||
createSIWEMessage, | createSIWEMessage, | ||||
getSIWEStatementForPublicKey, | getSIWEStatementForPublicKey, | ||||
siweMessageSigningExplanationStatements, | siweMessageSigningExplanationStatements, | ||||
} from 'lib/utils/siwe-utils.js'; | } from 'lib/utils/siwe-utils.js'; | ||||
import HeaderSeparator from './header-separator.react.js'; | import HeaderSeparator from './header-separator.react.js'; | ||||
import css from './siwe.css'; | import css from './siwe.css'; | ||||
import Button from '../components/button.react.js'; | import Button from '../components/button.react.js'; | ||||
import OrBreak from '../components/or-break.react.js'; | import OrBreak from '../components/or-break.react.js'; | ||||
import LoadingIndicator from '../loading-indicator.react.js'; | import LoadingIndicator from '../loading-indicator.react.js'; | ||||
import { useSelector } from '../redux/redux-utils.js'; | import { useSelector } from '../redux/redux-utils.js'; | ||||
import { webLogInExtraInfoSelector } from '../selectors/account-selectors.js'; | import { webLogInExtraInfoSelector } from '../selectors/account-selectors.js'; | ||||
import { signedIdentityKeysBlobSelector } from '../selectors/socket-selectors.js'; | |||||
type SIWELoginFormProps = { | type SIWELoginFormProps = { | ||||
+cancelSIWEAuthFlow: () => void, | +cancelSIWEAuthFlow: () => void, | ||||
}; | }; | ||||
const getSIWENonceLoadingStatusSelector = createLoadingStatusSelector( | const getSIWENonceLoadingStatusSelector = createLoadingStatusSelector( | ||||
getSIWENonceActionTypes, | getSIWENonceActionTypes, | ||||
); | ); | ||||
Show All 24 Lines | dispatchActionPromise( | ||||
setSIWENonce(response); | setSIWENonce(response); | ||||
})(), | })(), | ||||
); | ); | ||||
}, [dispatchActionPromise, getSIWENonceCall, siweNonceShouldBeFetched]); | }, [dispatchActionPromise, getSIWENonceCall, siweNonceShouldBeFetched]); | ||||
const primaryIdentityPublicKeys: ?OLMIdentityKeys = useSelector( | const primaryIdentityPublicKeys: ?OLMIdentityKeys = useSelector( | ||||
state => state.cryptoStore.primaryIdentityKeys, | state => state.cryptoStore.primaryIdentityKeys, | ||||
); | ); | ||||
const notificationIdentityPublicKeys: ?OLMIdentityKeys = useSelector( | |||||
state => state.cryptoStore.notificationIdentityKeys, | const signedIdentityKeysBlob: ?SignedIdentityKeysBlob = useSelector( | ||||
); | signedIdentityKeysBlobSelector, | ||||
const primaryAccount: ?PickledOLMAccount = useSelector( | |||||
state => state.cryptoStore.primaryAccount, | |||||
); | ); | ||||
const callSIWEAuthEndpoint = React.useCallback( | const callSIWEAuthEndpoint = React.useCallback( | ||||
( | (message: string, signature: string, extraInfo) => { | ||||
message: string, | invariant( | ||||
signature: string, | signedIdentityKeysBlob, | ||||
extraInfo, | 'signedIdentityKeysBlob must be set in attemptSIWEAuth', | ||||
signedIdentityKeysBlob: SignedIdentityKeysBlob, | ); | ||||
) => | return siweAuthCall({ | ||||
siweAuthCall({ | |||||
message, | message, | ||||
signature, | signature, | ||||
signedIdentityKeysBlob, | signedIdentityKeysBlob, | ||||
...extraInfo, | ...extraInfo, | ||||
}), | }); | ||||
[siweAuthCall], | }, | ||||
[signedIdentityKeysBlob, siweAuthCall], | |||||
); | ); | ||||
const attemptSIWEAuth = React.useCallback( | const attemptSIWEAuth = React.useCallback( | ||||
(message: string, signature: string) => { | (message: string, signature: string) => { | ||||
invariant( | |||||
primaryIdentityPublicKeys, | |||||
'primaryIdentityPublicKeys must be set in attemptSIWEAuth', | |||||
); | |||||
invariant( | |||||
notificationIdentityPublicKeys, | |||||
'notificationIdentityPublicKeys must be set in attemptSIWEAuth', | |||||
); | |||||
invariant(primaryAccount, 'primaryAccount must be set in logInAction'); | |||||
const primaryOLMAccount = new olm.Account(); | |||||
primaryOLMAccount.unpickle( | |||||
primaryAccount.picklingKey, | |||||
primaryAccount.pickledAccount, | |||||
); | |||||
const payloadToBeSigned = JSON.stringify({ | |||||
primaryIdentityPublicKeys, | |||||
notificationIdentityPublicKeys, | |||||
}); | |||||
const signedIdentityKeysBlob: SignedIdentityKeysBlob = { | |||||
payload: payloadToBeSigned, | |||||
signature: primaryOLMAccount.sign(payloadToBeSigned), | |||||
}; | |||||
const extraInfo = logInExtraInfo(); | const extraInfo = logInExtraInfo(); | ||||
dispatchActionPromise( | dispatchActionPromise( | ||||
siweAuthActionTypes, | siweAuthActionTypes, | ||||
callSIWEAuthEndpoint( | callSIWEAuthEndpoint(message, signature, extraInfo), | ||||
message, | |||||
signature, | |||||
extraInfo, | |||||
signedIdentityKeysBlob, | |||||
), | |||||
undefined, | undefined, | ||||
({ calendarQuery: extraInfo.calendarQuery }: LogInStartingPayload), | ({ calendarQuery: extraInfo.calendarQuery }: LogInStartingPayload), | ||||
); | ); | ||||
}, | }, | ||||
[ | [callSIWEAuthEndpoint, dispatchActionPromise, logInExtraInfo], | ||||
callSIWEAuthEndpoint, | |||||
dispatchActionPromise, | |||||
logInExtraInfo, | |||||
notificationIdentityPublicKeys, | |||||
primaryAccount, | |||||
primaryIdentityPublicKeys, | |||||
], | |||||
); | ); | ||||
const onSignInButtonClick = React.useCallback(async () => { | const onSignInButtonClick = React.useCallback(async () => { | ||||
invariant(signer, 'signer must be present during SIWE attempt'); | invariant(signer, 'signer must be present during SIWE attempt'); | ||||
invariant(siweNonce, 'nonce must be present during SIWE attempt'); | invariant(siweNonce, 'nonce must be present during SIWE attempt'); | ||||
invariant( | invariant( | ||||
primaryIdentityPublicKeys, | primaryIdentityPublicKeys, | ||||
'primaryIdentityPublicKeys must be present during SIWE attempt', | 'primaryIdentityPublicKeys must be present during SIWE attempt', | ||||
Show All 13 Lines | const backButtonColor = React.useMemo( | ||||
[], | [], | ||||
); | ); | ||||
const signInButtonColor = React.useMemo( | const signInButtonColor = React.useMemo( | ||||
() => ({ backgroundColor: '#6A20E3' }), | () => ({ backgroundColor: '#6A20E3' }), | ||||
[], | [], | ||||
); | ); | ||||
if (!siweNonce || !primaryIdentityPublicKeys) { | if (!siweNonce || !primaryIdentityPublicKeys || !signedIdentityKeysBlob) { | ||||
return ( | return ( | ||||
<div className={css.loadingIndicator}> | <div className={css.loadingIndicator}> | ||||
<LoadingIndicator status="loading" size="large" /> | <LoadingIndicator status="loading" size="large" /> | ||||
</div> | </div> | ||||
); | ); | ||||
} | } | ||||
return ( | return ( | ||||
Show All 38 Lines |