From 94af0b2afd92c793c104e6f8bb3790b3c308dcc1 Mon Sep 17 00:00:00 2001 From: KoalaSat Date: Sat, 6 Jan 2024 12:33:57 +0000 Subject: [PATCH] Fix order autoupdate and chat (#1047) * Fix Order autoupdate and chat * Remove console.log --- frontend/src/basic/OrderPage/index.tsx | 2 +- frontend/src/basic/RobotPage/RobotProfile.tsx | 2 +- .../src/components/MakerForm/MakerForm.tsx | 9 ++++- frontend/src/components/RobotInfo/index.tsx | 4 +- .../EncryptedSocketChat/index.tsx | 40 +++++++++++++------ .../EncryptedTurtleChat/index.tsx | 27 +++++++------ .../TradeBox/EncryptedChat/index.tsx | 10 ++--- .../src/components/TradeBox/Prompts/Chat.tsx | 2 +- frontend/src/components/TradeBox/index.tsx | 18 +++++---- frontend/src/contexts/FederationContext.ts | 20 ++++++---- frontend/src/models/Coordinator.model.ts | 33 ++++++++------- frontend/src/models/Garage.model.ts | 6 +-- frontend/src/models/Robot.model.ts | 16 ++++---- frontend/src/models/Slot.model.ts | 3 +- 14 files changed, 110 insertions(+), 82 deletions(-) diff --git a/frontend/src/basic/OrderPage/index.tsx b/frontend/src/basic/OrderPage/index.tsx index 4a48124f..a5db3c8c 100644 --- a/frontend/src/basic/OrderPage/index.tsx +++ b/frontend/src/basic/OrderPage/index.tsx @@ -67,7 +67,7 @@ const OrderPage = (): JSX.Element => { if (robot != null && slot?.token != null) { void federation.fetchRobot(garage, slot.token); coordinator - .fetchOrder(currentOrderId, robot) + .fetchOrder(currentOrderId, robot, slot.token) .then((order) => { if (order?.bad_request !== undefined) { setBadOrder(order.bad_request); diff --git a/frontend/src/basic/RobotPage/RobotProfile.tsx b/frontend/src/basic/RobotPage/RobotProfile.tsx index 94c7171a..4e5d274d 100644 --- a/frontend/src/basic/RobotPage/RobotProfile.tsx +++ b/frontend/src/basic/RobotPage/RobotProfile.tsx @@ -69,7 +69,7 @@ const RobotProfile = ({ const handleChangeSlot = (e: SelectChangeEvent): void => { garage.currentSlot = e.target.value; - setInputToken(garage.getSlot()?.getRobot()?.token ?? ''); + setInputToken(garage.getSlot()?.token ?? ''); setLoading(true); }; diff --git a/frontend/src/components/MakerForm/MakerForm.tsx b/frontend/src/components/MakerForm/MakerForm.tsx index 8844508d..3dcfaef0 100644 --- a/frontend/src/components/MakerForm/MakerForm.tsx +++ b/frontend/src/components/MakerForm/MakerForm.tsx @@ -98,6 +98,13 @@ const MakerForm = ({ useEffect(() => { setCurrencyCode(currencyDict[fav.currency === 0 ? 1 : fav.currency]); + }, [coordinatorUpdatedAt]); + + useEffect(() => { + updateCoordinatorInfo(); + }, [maker.coordinator]); + + const updateCoordinatorInfo = () => { if (maker.coordinator != null) { const newLimits = federation.getCoordinator(maker.coordinator).limits; if (Object.keys(newLimits).length !== 0) { @@ -107,7 +114,7 @@ const MakerForm = ({ setLimits(newLimits); } } - }, [coordinatorUpdatedAt]); + }; const updateAmountLimits = function ( limitList: LimitList, diff --git a/frontend/src/components/RobotInfo/index.tsx b/frontend/src/components/RobotInfo/index.tsx index e01ad85c..d9f7fc75 100644 --- a/frontend/src/components/RobotInfo/index.tsx +++ b/frontend/src/components/RobotInfo/index.tsx @@ -87,8 +87,8 @@ const RobotInfo: React.FC = ({ coordinator, onClose }: Props) => { const slot = garage.getSlot(); const robot = slot?.getRobot(coordinator.shortAlias); - if (robot != null && slot?.token != null && robot.encPrivKey != null && robot.token != null) { - void signCleartextMessage(rewardInvoice, robot.encPrivKey, robot.token).then( + if (robot != null && slot?.token != null && robot.encPrivKey != null) { + void signCleartextMessage(rewardInvoice, robot.encPrivKey, slot?.token).then( (signedInvoice) => { void coordinator.fetchReward(signedInvoice, garage, slot?.token).then((data) => { setBadInvoice(data.bad_invoice ?? ''); diff --git a/frontend/src/components/TradeBox/EncryptedChat/EncryptedSocketChat/index.tsx b/frontend/src/components/TradeBox/EncryptedChat/EncryptedSocketChat/index.tsx index 9d3d76bc..06a823f1 100644 --- a/frontend/src/components/TradeBox/EncryptedChat/EncryptedSocketChat/index.tsx +++ b/frontend/src/components/TradeBox/EncryptedChat/EncryptedSocketChat/index.tsx @@ -15,6 +15,9 @@ import ChatHeader from '../ChatHeader'; import { type EncryptedChatMessage, type ServerMessage } from '..'; import ChatBottom from '../ChatBottom'; import { sha256 } from 'js-sha256'; +import { Order } from '../../../../models'; +import { UseFederationStoreType, FederationContext } from '../../../../contexts/FederationContext'; +import { UseAppStoreType, AppContext } from '../../../../contexts/AppContext'; const audioPath = window.NativeRobosats === undefined @@ -22,7 +25,7 @@ const audioPath = : 'file:///android_asset/Web.bundle/assets/sounds'; interface Props { - orderId: number; + order: Order; status: number; userNick: string; takerNick: string; @@ -34,7 +37,7 @@ interface Props { } const EncryptedSocketChat: React.FC = ({ - orderId, + order, status, userNick, takerNick, @@ -46,7 +49,9 @@ const EncryptedSocketChat: React.FC = ({ }: Props): JSX.Element => { const { t } = useTranslation(); const theme = useTheme(); + const { origin, hostUrl, settings } = useContext(AppContext); const { garage, robotUpdatedAt } = useContext(GarageContext); + const { federation } = useContext(FederationContext); const [audio] = useState(() => new Audio(`${audioPath}/chat-open.mp3`)); const [connected, setConnected] = useState(false); @@ -98,13 +103,20 @@ const EncryptedSocketChat: React.FC = ({ }, [serverMessages]); const connectWebsocket = (): void => { - const robot = garage.getSlot()?.getRobot(); + const slot = garage.getSlot(); + const robot = slot?.getRobot(); - if (!robot) return; + if (!slot?.token) return; + + const { url, basePath } = federation + .getCoordinator(order.shortAlias) + .getEndpoint(settings.network, origin, settings.selfhostedClient, hostUrl); websocketClient .open( - `ws://${window.location.host}/ws/chat/${orderId}/?token_sha256_hex=${sha256(robot?.token)}`, + `${url.replace(/^https?:\/\//, 'ws://') + basePath}/ws/chat/${ + order.id + }/?token_sha256_hex=${sha256(slot?.token)}`, ) .then((connection) => { setConnection(connection); @@ -144,7 +156,8 @@ const EncryptedSocketChat: React.FC = ({ const onMessage: (message: any) => void = (message) => { const dataFromServer = JSON.parse(message.data); - const robot = garage.getSlot()?.getRobot(); + const slot = garage.getSlot(); + const robot = slot?.getRobot(); if (dataFromServer != null && !receivedIndexes.includes(dataFromServer.index)) { setReceivedIndexes((prev) => [...prev, dataFromServer.index]); setPeerConnected(dataFromServer.peer_connected); @@ -166,7 +179,7 @@ const EncryptedSocketChat: React.FC = ({ dataFromServer.message.split('\\').join('\n'), dataFromServer.user_nick === userNick ? robot.pubKey : peerPubKey, robot.encPrivKey, - robot.token, + slot.token, ).then((decryptedData) => { setWaitingEcho(waitingEcho ? decryptedData.decryptedMessage !== lastSent : false); setLastSent(decryptedData.decryptedMessage === lastSent ? '----BLANK----' : lastSent); @@ -214,8 +227,9 @@ const EncryptedSocketChat: React.FC = ({ }; const onButtonClicked = (e: React.FormEvent): void => { - const robot = garage.getSlot()?.getRobot(); - if (robot?.token !== undefined && value.includes(robot.token)) { + const slot = garage.getSlot(); + const robot = slot?.getRobot(); + if (slot?.token !== undefined && value.includes(slot.token)) { alert( `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.`, ); @@ -235,7 +249,7 @@ const EncryptedSocketChat: React.FC = ({ setValue(''); setWaitingEcho(true); setLastSent(value); - encryptMessage(value, robot.pubKey, peerPubKey, robot.encPrivKey, robot.token) + encryptMessage(value, robot.pubKey, peerPubKey, robot.encPrivKey, slot.token) .then((encryptedMessage) => { if (connection != null) { connection.send({ @@ -264,12 +278,12 @@ const EncryptedSocketChat: React.FC = ({ onClose={() => { setAudit(false); }} - orderId={Number(orderId)} + orderId={Number(order.id)} messages={messages} ownPubKey={garage.getSlot()?.getRobot()?.pubKey ?? ''} ownEncPrivKey={garage.getSlot()?.getRobot()?.encPrivKey ?? ''} peerPubKey={peerPubKey ?? 'Not received yet'} - passphrase={garage.getSlot()?.getRobot()?.token ?? ''} + passphrase={garage.getSlot()?.token ?? ''} onClickBack={() => { setAudit(false); }} @@ -381,7 +395,7 @@ const EncryptedSocketChat: React.FC = ({ = ({ - orderId, + order, userNick, takerNick, chatOffset, @@ -94,7 +95,7 @@ const EncryptedTurtleChat: React.FC = ({ .getCoordinator(shortAlias) .getEndpoint(settings.network, origin, settings.selfhostedClient, hostUrl); apiClient - .get(url + basePath, `/api/chat/?order_id=${orderId}&offset=${lastIndex}`, { + .get(url + basePath, `/api/chat/?order_id=${order.id}&offset=${lastIndex}`, { tokenSHA256: garage.getSlot()?.getRobot()?.tokenSHA256 ?? '', }) .then((results: any) => { @@ -122,7 +123,8 @@ const EncryptedTurtleChat: React.FC = ({ }; const onMessage = (dataFromServer: ServerMessage): void => { - const robot = garage.getSlot(); + const slot = garage.getSlot(); + const robot = slot?.getRobot(); if (robot && dataFromServer != null) { // If we receive an encrypted message if (dataFromServer.message.substring(0, 27) === `-----BEGIN PGP MESSAGE-----`) { @@ -130,7 +132,7 @@ const EncryptedTurtleChat: React.FC = ({ dataFromServer.message.split('\\').join('\n'), dataFromServer.nick === userNick ? robot.pubKey : peerPubKey, robot.encPrivKey, - robot.token, + slot.token, ).then((decryptedData) => { setLastSent(decryptedData.decryptedMessage === lastSent ? '----BLANK----' : lastSent); setLastIndex(lastIndex < dataFromServer.index ? dataFromServer.index : lastIndex); @@ -178,11 +180,12 @@ const EncryptedTurtleChat: React.FC = ({ }; const onButtonClicked = (e: React.FormEvent): void => { - const robot = garage.getSlot()?.getRobot(); + const slot = garage.getSlot(); + const robot = slot?.getRobot(); if (!robot) return; - if (robot?.token && value.includes(robot.token)) { + if (slot?.token && value.includes(slot.token)) { alert( `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.`, ); @@ -199,7 +202,7 @@ const EncryptedTurtleChat: React.FC = ({ `/api/chat/`, { PGP_message: value, - order_id: orderId, + order_id: order.id, offset: lastIndex, }, { tokenSHA256: robot?.tokenSHA256 ?? '' }, @@ -221,7 +224,7 @@ const EncryptedTurtleChat: React.FC = ({ else if (value !== '' && Boolean(robot?.pubKey)) { setWaitingEcho(true); setLastSent(value); - encryptMessage(value, robot?.pubKey, peerPubKey ?? '', robot?.encPrivKey, robot?.token) + encryptMessage(value, robot?.pubKey, peerPubKey ?? '', robot?.encPrivKey, slot?.token) .then((encryptedMessage) => { const { url, basePath } = federation .getCoordinator(garage.getSlot()?.activeShortAlias ?? '') @@ -232,7 +235,7 @@ const EncryptedTurtleChat: React.FC = ({ `/api/chat/`, { PGP_message: String(encryptedMessage).split('\n').join('\\'), - order_id: orderId, + order_id: order.id, offset: lastIndex, }, { tokenSHA256: robot?.tokenSHA256 }, @@ -270,7 +273,7 @@ const EncryptedTurtleChat: React.FC = ({ onClose={() => { setAudit(false); }} - orderId={Number(orderId)} + orderId={Number(order.id)} messages={messages} ownPubKey={garage.getSlot()?.getRobot()?.pubKey ?? ''} ownEncPrivKey={garage.getSlot()?.getRobot()?.encPrivKey ?? ''} @@ -382,7 +385,7 @@ const EncryptedTurtleChat: React.FC = ({ = ({ - orderId, + order, takerNick, userNick, chatOffset, @@ -48,7 +48,7 @@ const EncryptedChat: React.FC = ({ = ({ status={status} messages={messages} setMessages={setMessages} - orderId={orderId} + order={order} takerNick={takerNick} userNick={userNick} baseUrl={baseUrl} diff --git a/frontend/src/components/TradeBox/Prompts/Chat.tsx b/frontend/src/components/TradeBox/Prompts/Chat.tsx index 1b2ba30e..0a8c90f7 100644 --- a/frontend/src/components/TradeBox/Prompts/Chat.tsx +++ b/frontend/src/components/TradeBox/Prompts/Chat.tsx @@ -132,7 +132,7 @@ export const ChatPrompt = ({ { }; const updateInvoice = function (invoice: string): void { - const robot = garage.getSlot()?.getRobot(); + const slot = garage.getSlot(); + const robot = slot?.getRobot(); - if (robot?.encPrivKey != null && robot?.token != null) { + if (robot?.encPrivKey != null && slot?.token != null) { setLoadingButtons({ ...noLoadingButtons, submitInvoice: true }); - void signCleartextMessage(invoice, robot.encPrivKey, robot.token).then((signedInvoice) => { + void signCleartextMessage(invoice, robot.encPrivKey, slot.token).then((signedInvoice) => { submitAction({ action: 'update_invoice', invoice: signedInvoice, @@ -284,11 +285,12 @@ const TradeBox = ({ baseUrl, onStartAgain }: TradeBoxProps): JSX.Element => { }; const updateAddress = function (): void { - const robot = garage.getSlot()?.getRobot(); + const slot = garage.getSlot(); + const robot = slot?.getRobot(); - if (robot?.encPrivKey != null && robot?.token != null) { + if (robot?.encPrivKey != null && slot?.token != null) { setLoadingButtons({ ...noLoadingButtons, submitAddress: true }); - void signCleartextMessage(onchain.address, robot.encPrivKey, robot.token).then( + void signCleartextMessage(onchain.address, robot.encPrivKey, slot.token).then( (signedAddress) => { submitAction({ action: 'update_address', @@ -306,10 +308,10 @@ const TradeBox = ({ baseUrl, onStartAgain }: TradeBoxProps): JSX.Element => { }; const submitStatement = function (): void { - const robot = garage.getSlot()?.getRobot(); + const slot = garage.getSlot(); let statement = dispute.statement; if (dispute.attachLogs) { - const payload = { statement, messages, token: robot?.token }; + const payload = { statement, messages, token: slot?.token }; statement = JSON.stringify(payload, null, 2); } setLoadingButtons({ ...noLoadingButtons, submitStatement: true }); diff --git a/frontend/src/contexts/FederationContext.ts b/frontend/src/contexts/FederationContext.ts index 4a5ff4f0..12a95831 100644 --- a/frontend/src/contexts/FederationContext.ts +++ b/frontend/src/contexts/FederationContext.ts @@ -119,14 +119,18 @@ export const useFederationStore = (): UseFederationStoreType => { } }; - const fetchCurrentOrder = (): void => { - const activeSlot = garage.getSlot(); - const robot = activeSlot?.getRobot(activeSlot?.activeShortAlias ?? ''); - if (robot?.activeOrderId && activeSlot?.activeShortAlias) { - const coordinator = federation.getCoordinator(activeSlot?.activeShortAlias ?? ''); + const fetchCurrentOrder: () => void = () => { + const slot = garage?.getSlot(); + const robot = slot?.getRobot(); + console.log('slot?.token', slot?.token); + console.log('slot?.activeShortAlias', slot?.activeShortAlias); + console.log('robot?.activeOrderId', robot?.activeOrderId); + if (slot?.token && slot?.activeShortAlias && robot?.activeOrderId) { + const coordinator = federation.getCoordinator(slot.activeShortAlias); coordinator - ?.fetchOrder(robot.activeOrderId, robot) + ?.fetchOrder(robot.activeOrderId, robot, slot.token) .then((order) => { + console.log('order', order); onOrderReceived(order as Order); }) .finally(() => { @@ -156,8 +160,8 @@ export const useFederationStore = (): UseFederationStoreType => { if (robot && garage.currentSlot) { if (open.profile && Boolean(slot?.hashId) && slot?.token) { void federation.fetchRobot(garage, slot?.token); // refresh/update existing robot - } else if (robot.token && robot.encPrivKey && robot.pubKey) { - void federation.fetchRobot(garage, robot.token); // create new robot with existing token and keys (on network and coordinator change) + } else if (slot?.token && robot.encPrivKey && robot.pubKey) { + void federation.fetchRobot(garage, slot.token); // create new robot with existing token and keys (on network and coordinator change) } } }, [open.profile, hostUrl, robotUpdatedAt]); diff --git a/frontend/src/models/Coordinator.model.ts b/frontend/src/models/Coordinator.model.ts index 95a4ece0..a1a7db98 100644 --- a/frontend/src/models/Coordinator.model.ts +++ b/frontend/src/models/Coordinator.model.ts @@ -291,17 +291,14 @@ export class Coordinator { }; fecthRobot = async (garage: Garage, token: string): Promise => { - if (!this.enabled) return null; + if (!this.enabled || !token) return null; const robot = garage?.getSlot(token)?.getRobot() ?? null; + const authHeaders = robot?.getAuthHeaders(); - if (robot?.token !== token) return null; + if (!authHeaders) return null; - const authHeaders = robot.getAuthHeaders(); - - if (authHeaders === null) return null; - - const { hasEnoughEntropy, bitsEntropy, shannonEntropy } = validateTokenEntropy(robot.token); + const { hasEnoughEntropy, bitsEntropy, shannonEntropy } = validateTokenEntropy(token); if (!hasEnoughEntropy) return null; @@ -339,17 +336,17 @@ export class Coordinator { return garage.getSlot(this.shortAlias)?.getRobot() ?? null; }; - fetchOrder = async (orderId: number, robot: Robot): Promise => { + fetchOrder = async (orderId: number, robot: Robot, token: string): Promise => { if (!this.enabled) return null; - if (!(robot.token != null)) return null; + if (!token) return null; const authHeaders = robot.getAuthHeaders(); - - if (authHeaders === null) return null; + if (!authHeaders) return null; return await apiClient .get(this.url, `${this.basePath}/api/order/?order_id=${orderId}`, authHeaders) .then((data) => { + console.log('data', data); const order: Order = { ...defaultOrder, ...data, @@ -373,9 +370,10 @@ export class Coordinator { }> => { if (!this.enabled) return null; - const robot = garage.getSlot(index)?.getRobot(); + const slot = garage.getSlot(index); + const robot = slot?.getRobot(); - if (!(robot?.token != null) || !(robot.encPrivKey != null)) return null; + if (!slot?.token || !robot?.encPrivKey) return null; const data = await apiClient.post( this.url, @@ -385,7 +383,7 @@ export class Coordinator { }, { tokenSHA256: robot.tokenSHA256 }, ); - garage.upsertRobot(robot?.token, this.shortAlias, { + garage.upsertRobot(slot?.token, this.shortAlias, { earnedRewards: data?.successful_withdrawal === true ? 0 : robot.earnedRewards, }); @@ -395,9 +393,10 @@ export class Coordinator { fetchStealth = async (wantsStealth: boolean, garage: Garage, index: string): Promise => { if (!this.enabled) return null; - const robot = garage?.getSlot(index)?.getRobot(); + const slot = garage.getSlot(index); + const robot = slot?.getRobot(); - if (!(robot?.token != null) || !(robot.encPrivKey != null)) return null; + if (!(slot?.token != null) || !(robot?.encPrivKey != null)) return null; await apiClient.post( this.url, @@ -406,7 +405,7 @@ export class Coordinator { { tokenSHA256: robot.tokenSHA256 }, ); - garage.upsertRobot(robot?.token, this.shortAlias, { + garage.upsertRobot(slot?.token, this.shortAlias, { stealthInvoices: wantsStealth, }); diff --git a/frontend/src/models/Garage.model.ts b/frontend/src/models/Garage.model.ts index af5c9299..14f5b339 100644 --- a/frontend/src/models/Garage.model.ts +++ b/frontend/src/models/Garage.model.ts @@ -120,12 +120,12 @@ class Garage { let slot = this.getSlot(token); - if (slot === null && attributes.token != null) { - slot = this.createSlot(attributes.token); + if (slot === null && token) { + slot = this.createSlot(token); } if (slot != null) { - slot.upsertRobot(shortAlias, attributes); + slot.upsertRobot(shortAlias, { token, ...attributes }); this.triggerHook('onRobotUpdate'); this.save(); } diff --git a/frontend/src/models/Robot.model.ts b/frontend/src/models/Robot.model.ts index ad88af99..ed741f95 100644 --- a/frontend/src/models/Robot.model.ts +++ b/frontend/src/models/Robot.model.ts @@ -10,13 +10,13 @@ interface AuthHeaders { } class Robot { - constructor(garageRobot?: Robot) { - if (garageRobot != null) { - this.token = garageRobot?.token ?? undefined; + constructor(attributes?: Record) { + if (attributes != null) { + this.token = attributes?.token ?? undefined; this.tokenSHA256 = - garageRobot?.tokenSHA256 ?? (this.token != null ? hexToBase91(sha256(this.token)) : ''); - this.pubKey = garageRobot?.pubKey ?? undefined; - this.encPrivKey = garageRobot?.encPrivKey ?? undefined; + attributes?.tokenSHA256 ?? (this.token != null ? hexToBase91(sha256(this.token)) : ''); + this.pubKey = attributes?.pubKey ?? undefined; + this.encPrivKey = attributes?.encPrivKey ?? undefined; } } @@ -43,9 +43,7 @@ class Robot { }; getAuthHeaders = (): AuthHeaders | null => { - if (this.token === undefined) return null; - - const tokenSHA256 = hexToBase91(sha256(this.token)); + const tokenSHA256 = this.tokenSHA256 ?? ''; const encPrivKey = this.encPrivKey ?? ''; const pubKey = this.pubKey ?? ''; diff --git a/frontend/src/models/Slot.model.ts b/frontend/src/models/Slot.model.ts index ea38dcce..76eff4e9 100644 --- a/frontend/src/models/Slot.model.ts +++ b/frontend/src/models/Slot.model.ts @@ -48,7 +48,8 @@ class Slot { }; upsertRobot = (shortAlias: string, attributes: Record): Robot | null => { - if (this.robots[shortAlias] === undefined) this.robots[shortAlias] = new Robot(); + if (this.robots[shortAlias] === undefined) + this.robots[shortAlias] = new Robot(attributes ?? {}); this.robots[shortAlias].update(attributes);