laconic-wallet/components/SignRequest.tsx
Adwait Gharpure 7db0edce75
Allow incoming signature requests from intents (#32)
* Add url scheme and linking

* Pass account to sign request page

* Provide functionality for accepting or rejecting requests

* Load account state before handling url

* Refactor code

* Make intent work when app is cleared from recents

* Fix bug to populate data from intents

* Fix bug to update data on subsequent requests

* Pass correct network to sign messages from cosmos account

* Fix bug to populate data for incoming intent

* Allow spaces in url

* Bad signature page

* Review changes

* Change page heading

* Use correct regex

* Clean up code

* Use https in url

* Set state properly

---------

Co-authored-by: Adw8 <adwait@deepstacksoft.com>
2024-02-28 19:37:26 +05:30

130 lines
3.4 KiB
TypeScript

import React, { useEffect, useState } from 'react';
import { Alert, View } from 'react-native';
import { ActivityIndicator, Button, Text } from 'react-native-paper';
import { useNavigation } from '@react-navigation/native';
import {
NativeStackNavigationProp,
NativeStackScreenProps,
} from '@react-navigation/native-stack';
import { Account, StackParamsList } from '../types';
import AccountDetails from './AccountDetails';
import styles from '../styles/stylesheet';
import { signMessage } from '../utils/sign-message';
import { retrieveSingleAccount } from '../utils/accounts';
type SignRequestProps = NativeStackScreenProps<StackParamsList, 'SignRequest'>;
const SignRequest = ({ route }: SignRequestProps) => {
const [account, setAccount] = useState<Account>();
const [message, setMessage] = useState<string>('');
const [network, setNetwork] = useState<string>('');
const [loaded, setLoaded] = useState(false);
const navigation =
useNavigation<NativeStackNavigationProp<StackParamsList>>();
const retrieveData = async (
requestNetwork: string,
requestAddress: string,
requestMessage: string,
) => {
const requestAccount = await retrieveSingleAccount(
requestNetwork,
requestAddress,
);
if (!requestAccount) {
navigation.navigate('InvalidPath');
}
if (requestAccount && requestAccount !== account) {
setAccount(requestAccount);
}
if (requestMessage && requestMessage !== message) {
setMessage(decodeURIComponent(requestMessage));
}
if (requestNetwork && requestNetwork !== network) {
setNetwork(requestNetwork);
}
};
const sanitizePath = (path: string) => {
const regex = /^\/sign\/(eth|cosmos)\/(.+)\/(.+)$/;
const match = path.match(regex);
if (match) {
const [network, address, message] = match;
return {
network,
address,
message,
};
} else {
navigation.navigate('InvalidPath');
}
return null;
};
useEffect(() => {
setLoaded(true);
if (route.path) {
const sanitizedRoute = sanitizePath(route.path);
sanitizedRoute &&
route.params &&
retrieveData(
route.params?.network,
route.params?.address,
route.params?.message,
);
}
setLoaded(false);
}, [route]);
const signMessageHandler = async () => {
if (!account) {
throw new Error('Account is not valid');
}
if (message) {
const signedMessage = await signMessage({
message,
network,
accountId: account.counterId,
});
Alert.alert('Signature', signedMessage);
navigation.navigate('Laconic');
}
};
const rejectRequestHandler = async () => {
navigation.navigate('Laconic');
};
return (
<>
{!loaded ? (
<View style={styles.appContainer}>
<AccountDetails account={account} />
<View style={styles.requestMessage}>
<Text variant="bodyLarge">{message}</Text>
</View>
<View style={styles.buttonContainer}>
<Button
mode="contained"
onPress={rejectRequestHandler}
buttonColor="#B82B0D">
No
</Button>
<Button mode="contained" onPress={signMessageHandler}>
Yes
</Button>
</View>
</View>
) : (
<ActivityIndicator />
)}
</>
);
};
export default SignRequest;