Refactor tradebox states as switch, fix websocket first connect, show PGP erros.

This commit is contained in:
Reckless_Satoshi
2023-04-20 08:19:47 -07:00
parent 28ef253020
commit 7665a2bb22
3 changed files with 335 additions and 309 deletions

View File

@ -1,6 +1,6 @@
import React, { useEffect, useLayoutEffect, useState } from 'react'; import React, { useEffect, useLayoutEffect, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Button, Tooltip, TextField, Grid, Paper } from '@mui/material'; import { Button, Tooltip, TextField, Grid, Paper, Typography } from '@mui/material';
import { encryptMessage, decryptMessage } from '../../../../pgp'; import { encryptMessage, decryptMessage } from '../../../../pgp';
import { AuditPGPDialog } from '../../../Dialogs'; import { AuditPGPDialog } from '../../../Dialogs';
import { websocketClient, WebsocketConnection } from '../../../../services/Websocket'; import { websocketClient, WebsocketConnection } from '../../../../services/Websocket';
@ -46,10 +46,7 @@ const EncryptedSocketChat: React.FC<Props> = ({
const audio = new Audio(`/static/assets/sounds/chat-open.mp3`); const audio = new Audio(`/static/assets/sounds/chat-open.mp3`);
const [connected, setConnected] = useState<boolean>(false); const [connected, setConnected] = useState<boolean>(false);
const [peerConnected, setPeerConnected] = useState<boolean>(false); const [peerConnected, setPeerConnected] = useState<boolean>(false);
const [ownPubKey] = useState<string>(robot.pubKey);
const [ownEncPrivKey] = useState<string>(robot.encPrivKey);
const [peerPubKey, setPeerPubKey] = useState<string>(); const [peerPubKey, setPeerPubKey] = useState<string>();
const [token] = useState<string>(robot.token);
const [serverMessages, setServerMessages] = useState<ServerMessage[]>([]); const [serverMessages, setServerMessages] = useState<ServerMessage[]>([]);
const [value, setValue] = useState<string>(''); const [value, setValue] = useState<string>('');
const [connection, setConnection] = useState<WebsocketConnection>(); const [connection, setConnection] = useState<WebsocketConnection>();
@ -58,12 +55,13 @@ const EncryptedSocketChat: React.FC<Props> = ({
const [lastSent, setLastSent] = useState<string>('---BLANK---'); const [lastSent, setLastSent] = useState<string>('---BLANK---');
const [messageCount, setMessageCount] = useState<number>(0); const [messageCount, setMessageCount] = useState<number>(0);
const [receivedIndexes, setReceivedIndexes] = useState<number[]>([]); const [receivedIndexes, setReceivedIndexes] = useState<number[]>([]);
const [error, setError] = useState<string>('');
useEffect(() => { useEffect(() => {
if (!connected) { if (!connected && robot.avatarLoaded) {
connectWebsocket(); connectWebsocket();
} }
}, [connected]); }, [connected, robot]);
// Make sure to not keep reconnecting once status is not Chat // Make sure to not keep reconnecting once status is not Chat
useEffect(() => { useEffect(() => {
@ -99,7 +97,7 @@ const EncryptedSocketChat: React.FC<Props> = ({
setConnected(true); setConnected(true);
connection.send({ connection.send({
message: ownPubKey, message: robot.pubKey,
nick: userNick, nick: userNick,
}); });
@ -112,10 +110,10 @@ const EncryptedSocketChat: React.FC<Props> = ({
const createJsonFile: () => object = () => { const createJsonFile: () => object = () => {
return { return {
credentials: { credentials: {
own_public_key: ownPubKey, own_public_key: robot.pubKey,
peer_public_key: peerPubKey, peer_public_key: peerPubKey,
encrypted_private_key: ownEncPrivKey, encrypted_private_key: robot.encPrivKey,
passphrase: token, passphrase: robot.token,
}, },
messages, messages,
}; };
@ -131,7 +129,7 @@ const EncryptedSocketChat: React.FC<Props> = ({
if ( if (
connection != null && connection != null &&
dataFromServer.message.substring(0, 36) == `-----BEGIN PGP PUBLIC KEY BLOCK-----` && dataFromServer.message.substring(0, 36) == `-----BEGIN PGP PUBLIC KEY BLOCK-----` &&
dataFromServer.message != ownPubKey dataFromServer.message != robot.pubKey
) { ) {
setPeerPubKey(dataFromServer.message); setPeerPubKey(dataFromServer.message);
connection.send({ connection.send({
@ -143,9 +141,9 @@ const EncryptedSocketChat: React.FC<Props> = ({
else if (dataFromServer.message.substring(0, 27) == `-----BEGIN PGP MESSAGE-----`) { else if (dataFromServer.message.substring(0, 27) == `-----BEGIN PGP MESSAGE-----`) {
decryptMessage( decryptMessage(
dataFromServer.message.split('\\').join('\n'), dataFromServer.message.split('\\').join('\n'),
dataFromServer.user_nick == userNick ? ownPubKey : peerPubKey, dataFromServer.user_nick == userNick ? robot.pubKey : peerPubKey,
ownEncPrivKey, robot.encPrivKey,
token, robot.token,
).then((decryptedData) => { ).then((decryptedData) => {
setWaitingEcho(waitingEcho ? decryptedData.decryptedMessage !== lastSent : false); setWaitingEcho(waitingEcho ? decryptedData.decryptedMessage !== lastSent : false);
setLastSent(decryptedData.decryptedMessage === lastSent ? '----BLANK----' : lastSent); setLastSent(decryptedData.decryptedMessage === lastSent ? '----BLANK----' : lastSent);
@ -197,9 +195,9 @@ const EncryptedSocketChat: React.FC<Props> = ({
}; };
const onButtonClicked = (e: any) => { const onButtonClicked = (e: any) => {
if (token && value.includes(token)) { if (robot.token && value.includes(robot.token)) {
alert( alert(
`Aye! You just sent your own robot token to your peer in chat, that's a catastrophic idea! So bad your message was blocked.`, `Aye! You just sent your own robot robot.token to your peer in chat, that's a catastrophic idea! So bad your message was blocked.`,
); );
setValue(''); setValue('');
} }
@ -217,16 +215,16 @@ const EncryptedSocketChat: React.FC<Props> = ({
setValue(''); setValue('');
setWaitingEcho(true); setWaitingEcho(true);
setLastSent(value); setLastSent(value);
encryptMessage(value, ownPubKey, peerPubKey, ownEncPrivKey, token).then( encryptMessage(value, robot.pubKey, peerPubKey, robot.encPrivKey, robot.token)
(encryptedMessage) => { .then((encryptedMessage) => {
if (connection != null) { if (connection != null) {
connection.send({ connection.send({
message: encryptedMessage.toString().split('\n').join('\\'), message: encryptedMessage.toString().split('\n').join('\\'),
nick: userNick, nick: userNick,
}); });
} }
}, })
); .catch((error) => setError(error.toString()));
} }
e.preventDefault(); e.preventDefault();
}; };
@ -244,10 +242,10 @@ const EncryptedSocketChat: React.FC<Props> = ({
onClose={() => setAudit(false)} onClose={() => setAudit(false)}
orderId={Number(orderId)} orderId={Number(orderId)}
messages={messages} messages={messages}
own_pub_key={ownPubKey || ''} own_pub_key={robot.pubKey || ''}
own_enc_priv_key={ownEncPrivKey || ''} own_enc_priv_key={robot.encPrivKey || ''}
peer_pub_key={peerPubKey || 'Not received yet'} peer_pub_key={peerPubKey || 'Not received yet'}
passphrase={token || ''} passphrase={robot.token || ''}
onClickBack={() => setAudit(false)} onClickBack={() => setAudit(false)}
/> />
<Grid item> <Grid item>
@ -343,6 +341,9 @@ const EncryptedSocketChat: React.FC<Props> = ({
</Button> </Button>
</Grid> </Grid>
</Grid> </Grid>
<Typography color='error' variant='caption'>
{error}
</Typography>
</form> </form>
</Grid> </Grid>
<Grid item> <Grid item>

View File

@ -1,6 +1,6 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Button, TextField, Grid, Paper } from '@mui/material'; import { Button, TextField, Grid, Paper, Typography } from '@mui/material';
import { encryptMessage, decryptMessage } from '../../../../pgp'; import { encryptMessage, decryptMessage } from '../../../../pgp';
import { AuditPGPDialog } from '../../../Dialogs'; import { AuditPGPDialog } from '../../../Dialogs';
import { Robot } from '../../../../models'; import { Robot } from '../../../../models';
@ -45,10 +45,7 @@ const EncryptedTurtleChat: React.FC<Props> = ({
const audio = new Audio(`/static/assets/sounds/chat-open.mp3`); const audio = new Audio(`/static/assets/sounds/chat-open.mp3`);
const [peerConnected, setPeerConnected] = useState<boolean>(false); const [peerConnected, setPeerConnected] = useState<boolean>(false);
const [ownPubKey] = useState<string>(robot.pubKey || '');
const [ownEncPrivKey] = useState<string>(robot.encPrivKey || '');
const [peerPubKey, setPeerPubKey] = useState<string>(); const [peerPubKey, setPeerPubKey] = useState<string>();
const [token] = useState<string>(robot.token || '');
const [value, setValue] = useState<string>(''); const [value, setValue] = useState<string>('');
const [audit, setAudit] = useState<boolean>(false); const [audit, setAudit] = useState<boolean>(false);
const [waitingEcho, setWaitingEcho] = useState<boolean>(false); const [waitingEcho, setWaitingEcho] = useState<boolean>(false);
@ -56,6 +53,7 @@ const EncryptedTurtleChat: React.FC<Props> = ({
const [messageCount, setMessageCount] = useState<number>(0); const [messageCount, setMessageCount] = useState<number>(0);
const [serverMessages, setServerMessages] = useState<ServerMessage[]>([]); const [serverMessages, setServerMessages] = useState<ServerMessage[]>([]);
const [lastIndex, setLastIndex] = useState<number>(0); const [lastIndex, setLastIndex] = useState<number>(0);
const [error, setError] = useState<string>('');
useEffect(() => { useEffect(() => {
if (messages.length > messageCount) { if (messages.length > messageCount) {
@ -91,10 +89,10 @@ const EncryptedTurtleChat: React.FC<Props> = ({
const createJsonFile: () => object = () => { const createJsonFile: () => object = () => {
return { return {
credentials: { credentials: {
own_public_key: ownPubKey, own_public_key: robot.pubKey,
peer_public_key: peerPubKey, peer_public_key: peerPubKey,
encrypted_private_key: ownEncPrivKey, encrypted_private_key: robot.encPrivKey,
passphrase: token, passphrase: robot.token,
}, },
messages, messages,
}; };
@ -106,9 +104,9 @@ const EncryptedTurtleChat: React.FC<Props> = ({
if (dataFromServer.message.substring(0, 27) == `-----BEGIN PGP MESSAGE-----`) { if (dataFromServer.message.substring(0, 27) == `-----BEGIN PGP MESSAGE-----`) {
decryptMessage( decryptMessage(
dataFromServer.message.split('\\').join('\n'), dataFromServer.message.split('\\').join('\n'),
dataFromServer.nick == userNick ? ownPubKey : peerPubKey, dataFromServer.nick == userNick ? robot.pubKey : peerPubKey,
ownEncPrivKey, robot.encPrivKey,
token, robot.token,
).then((decryptedData) => { ).then((decryptedData) => {
setLastSent(decryptedData.decryptedMessage === lastSent ? '----BLANK----' : lastSent); setLastSent(decryptedData.decryptedMessage === lastSent ? '----BLANK----' : lastSent);
setLastIndex(lastIndex < dataFromServer.index ? dataFromServer.index : lastIndex); setLastIndex(lastIndex < dataFromServer.index ? dataFromServer.index : lastIndex);
@ -160,9 +158,9 @@ const EncryptedTurtleChat: React.FC<Props> = ({
}; };
const onButtonClicked = (e: any) => { const onButtonClicked = (e: any) => {
if (token && value.includes(token)) { if (robot.token && value.includes(robot.token)) {
alert( alert(
`Aye! You just sent your own robot token to your peer in chat, that's a catastrophic idea! So bad your message was blocked.`, `Aye! You just sent your own robot robot.token to your peer in chat, that's a catastrophic idea! So bad your message was blocked.`,
); );
setValue(''); setValue('');
} }
@ -191,8 +189,8 @@ const EncryptedTurtleChat: React.FC<Props> = ({
else if (value != '') { else if (value != '') {
setWaitingEcho(true); setWaitingEcho(true);
setLastSent(value); setLastSent(value);
encryptMessage(value, ownPubKey, peerPubKey, ownEncPrivKey, token).then( encryptMessage(value, robot.pubKey, peerPubKey, robot.encPrivKey, robot.token)
(encryptedMessage) => { .then((encryptedMessage) => {
apiClient apiClient
.post(baseUrl, `/api/chat/`, { .post(baseUrl, `/api/chat/`, {
PGP_message: encryptedMessage.toString().split('\n').join('\\'), PGP_message: encryptedMessage.toString().split('\n').join('\\'),
@ -211,8 +209,8 @@ const EncryptedTurtleChat: React.FC<Props> = ({
setWaitingEcho(false); setWaitingEcho(false);
setValue(''); setValue('');
}); });
}, })
); .catch((error) => setError(error.toString()));
} }
e.preventDefault(); e.preventDefault();
}; };
@ -230,10 +228,10 @@ const EncryptedTurtleChat: React.FC<Props> = ({
onClose={() => setAudit(false)} onClose={() => setAudit(false)}
orderId={Number(orderId)} orderId={Number(orderId)}
messages={messages} messages={messages}
own_pub_key={ownPubKey || ''} own_pub_key={robot.pubKey || ''}
own_enc_priv_key={ownEncPrivKey || ''} own_enc_priv_key={robot.encPrivKey || ''}
peer_pub_key={peerPubKey || 'Not received yet'} peer_pub_key={peerPubKey || 'Not received yet'}
passphrase={token || ''} passphrase={robot.token || ''}
onClickBack={() => setAudit(false)} onClickBack={() => setAudit(false)}
/> />
@ -323,6 +321,9 @@ const EncryptedTurtleChat: React.FC<Props> = ({
</Button> </Button>
</Grid> </Grid>
</Grid> </Grid>
<Typography color='error' variant='caption'>
{error}
</Typography>
</form> </form>
</Grid> </Grid>

View File

@ -49,6 +49,7 @@ import { Order, Robot, Settings } from '../../models';
import { EncryptedChatMessage } from './EncryptedChat'; import { EncryptedChatMessage } from './EncryptedChat';
import CollabCancelAlert from './CollabCancelAlert'; import CollabCancelAlert from './CollabCancelAlert';
import { Bolt } from '@mui/icons-material'; import { Bolt } from '@mui/icons-material';
import es from 'date-fns/esm/locale/es/index.js';
interface loadingButtonsProps { interface loadingButtonsProps {
cancel: boolean; cancel: boolean;
@ -304,8 +305,9 @@ const TradeBox = ({
let prompt = () => <span>Wops!</span>; let prompt = () => <span>Wops!</span>;
let bondStatus: 'hide' | 'locked' | 'unlocked' | 'settled' = 'hide'; let bondStatus: 'hide' | 'locked' | 'unlocked' | 'settled' = 'hide';
switch (status) {
// 0: 'Waiting for maker bond' // 0: 'Waiting for maker bond'
if (status == 0) { case 0:
if (isMaker) { if (isMaker) {
title = 'Lock {{amountSats}} Sats to PUBLISH order'; title = 'Lock {{amountSats}} Sats to PUBLISH order';
titleVariables = { amountSats: pn(order.bond_satoshis) }; titleVariables = { amountSats: pn(order.bond_satoshis) };
@ -314,9 +316,9 @@ const TradeBox = ({
}; };
bondStatus = 'hide'; bondStatus = 'hide';
} }
break;
// 1: 'Public' // 1: 'Public'
} else if (status == 1) { case 1:
if (isMaker) { if (isMaker) {
title = 'Your order is public'; title = 'Your order is public';
prompt = () => { prompt = () => {
@ -330,9 +332,9 @@ const TradeBox = ({
}; };
bondStatus = 'locked'; bondStatus = 'locked';
} }
break;
// 2: 'Paused' // 2: 'Paused'
} else if (status == 2) { case 2:
if (isMaker) { if (isMaker) {
title = 'Your order is paused'; title = 'Your order is paused';
prompt = () => { prompt = () => {
@ -345,9 +347,10 @@ const TradeBox = ({
}; };
bondStatus = 'locked'; bondStatus = 'locked';
} }
break;
// 3: 'Waiting for taker bond' // 3: 'Waiting for taker bond'
} else if (status == 3) { case 3:
if (isMaker) { if (isMaker) {
title = 'A taker has been found!'; title = 'A taker has been found!';
prompt = () => { prompt = () => {
@ -362,9 +365,10 @@ const TradeBox = ({
}; };
bondStatus = 'hide'; bondStatus = 'hide';
} }
break;
// 5: 'Expired' // 5: 'Expired'
} else if (status == 5) { case 5:
title = 'The order has expired'; title = 'The order has expired';
prompt = () => { prompt = () => {
return ( return (
@ -381,7 +385,7 @@ const TradeBox = ({
bondStatus = 'hide'; // To do: show bond status according to expiry message. bondStatus = 'hide'; // To do: show bond status according to expiry message.
// 6: 'Waiting for trade collateral and buyer invoice' // 6: 'Waiting for trade collateral and buyer invoice'
} else if (status == 6) { case 6:
bondStatus = 'locked'; bondStatus = 'locked';
if (isBuyer) { if (isBuyer) {
title = 'Submit payout info'; title = 'Submit payout info';
@ -410,9 +414,10 @@ const TradeBox = ({
return <LockInvoicePrompt order={order} concept={'escrow'} />; return <LockInvoicePrompt order={order} concept={'escrow'} />;
}; };
} }
break;
// 7: 'Waiting only for seller trade collateral' // 7: 'Waiting only for seller trade collateral'
} else if (status == 7) { case 7:
bondStatus = 'locked'; bondStatus = 'locked';
if (isBuyer) { if (isBuyer) {
title = 'Your info looks good!'; title = 'Your info looks good!';
@ -427,9 +432,10 @@ const TradeBox = ({
return <LockInvoicePrompt order={order} concept={'escrow'} />; return <LockInvoicePrompt order={order} concept={'escrow'} />;
}; };
} }
break;
// 8: 'Waiting only for buyer invoice' // 8: 'Waiting only for buyer invoice'
} else if (status == 8) { case 8:
bondStatus = 'locked'; bondStatus = 'locked';
if (isBuyer) { if (isBuyer) {
title = 'Submit payout info'; title = 'Submit payout info';
@ -456,10 +462,12 @@ const TradeBox = ({
return <PayoutWaitPrompt />; return <PayoutWaitPrompt />;
}; };
} }
break;
// 9: 'Sending fiat - In chatroom' // 9: 'Sending fiat - In chatroom'
// 10: 'Fiat sent - In chatroom' // 10: 'Fiat sent - In chatroom'
} else if (status == 9 || status == 10) { case 9:
case 10:
title = isBuyer ? 'Chat with the seller' : 'Chat with the buyer'; title = isBuyer ? 'Chat with the seller' : 'Chat with the buyer';
prompt = function () { prompt = function () {
return ( return (
@ -479,9 +487,10 @@ const TradeBox = ({
); );
}; };
bondStatus = 'locked'; bondStatus = 'locked';
break;
// 11: 'In dispute' // 11: 'In dispute'
} else if (status == 11) { case 11:
bondStatus = 'settled'; bondStatus = 'settled';
if (order.statement_submitted) { if (order.statement_submitted) {
title = 'We have received your statement'; title = 'We have received your statement';
@ -501,10 +510,13 @@ const TradeBox = ({
); );
}; };
} }
break;
// 12: 'Collaboratively cancelled' // 12: 'Collaboratively cancelled'
} else if (status == 12) { case 12:
break;
// 13: 'Sending satoshis to buyer' // 13: 'Sending satoshis to buyer'
} else if (status == 13) { case 13:
if (isBuyer) { if (isBuyer) {
bondStatus = 'unlocked'; bondStatus = 'unlocked';
title = 'Attempting Lightning Payment'; title = 'Attempting Lightning Payment';
@ -533,9 +545,10 @@ const TradeBox = ({
); );
}; };
} }
break;
// 14: 'Sucessful trade' // 14: 'Sucessful trade'
} else if (status == 14) { case 14:
title = 'Trade finished!'; title = 'Trade finished!';
titleColor = 'success'; titleColor = 'success';
titleIcon = function () { titleIcon = function () {
@ -556,8 +569,10 @@ const TradeBox = ({
/> />
); );
}; };
break;
// 15: 'Failed lightning network routing' // 15: 'Failed lightning network routing'
} else if (status == 15) { case 15:
if (isBuyer) { if (isBuyer) {
bondStatus = 'unlocked'; bondStatus = 'unlocked';
title = 'Lightning Routing Failed'; title = 'Lightning Routing Failed';
@ -595,29 +610,38 @@ const TradeBox = ({
); );
}; };
} }
break;
// 16: 'Wait for dispute resolution' // 16: 'Wait for dispute resolution'
} else if (status == 16) { case 16:
bondStatus = 'settled'; bondStatus = 'settled';
title = 'We have the statements'; title = 'We have the statements';
prompt = function () { prompt = function () {
return <DisputeWaitResolutionPrompt />; return <DisputeWaitResolutionPrompt />;
}; };
break;
// 17: 'Maker lost dispute' // 17: 'Maker lost dispute'
// 18: 'Taker lost dispute' // 18: 'Taker lost dispute'
} else if ((status == 17 && isMaker) || (status == 18 && !isMaker)) { case 17:
case 18:
if ((status === 17 && isMaker) || (status === 18 && !isMaker)) {
title = 'You have lost the dispute'; title = 'You have lost the dispute';
prompt = function () { prompt = function () {
return <DisputeLoserPrompt />; return <DisputeLoserPrompt />;
}; };
bondStatus = 'settled'; bondStatus = 'settled';
} else if ((status == 17 && !isMaker) || (status == 18 && isMaker)) { } else if ((status === 17 && !isMaker) || (status === 18 && isMaker)) {
title = 'You have won the dispute'; title = 'You have won the dispute';
prompt = function () { prompt = function () {
return <DisputeWinnerPrompt />; return <DisputeWinnerPrompt />;
}; };
} }
break;
default:
break;
}
return { title, titleVariables, titleColor, prompt, bondStatus, titleIcon }; return { title, titleVariables, titleColor, prompt, bondStatus, titleIcon };
}; };