Fix order autoupdate and chat (#1047)

* Fix Order autoupdate and chat

* Remove console.log
This commit is contained in:
KoalaSat 2024-01-06 12:33:57 +00:00 committed by GitHub
parent 399671d709
commit 94af0b2afd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 110 additions and 82 deletions

View File

@ -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);

View File

@ -69,7 +69,7 @@ const RobotProfile = ({
const handleChangeSlot = (e: SelectChangeEvent<number | 'loading'>): void => {
garage.currentSlot = e.target.value;
setInputToken(garage.getSlot()?.getRobot()?.token ?? '');
setInputToken(garage.getSlot()?.token ?? '');
setLoading(true);
};

View File

@ -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,

View File

@ -87,8 +87,8 @@ const RobotInfo: React.FC<Props> = ({ 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 ?? '');

View File

@ -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<Props> = ({
orderId,
order,
status,
userNick,
takerNick,
@ -46,7 +49,9 @@ const EncryptedSocketChat: React.FC<Props> = ({
}: Props): JSX.Element => {
const { t } = useTranslation();
const theme = useTheme();
const { origin, hostUrl, settings } = useContext<UseAppStoreType>(AppContext);
const { garage, robotUpdatedAt } = useContext<UseGarageStoreType>(GarageContext);
const { federation } = useContext<UseFederationStoreType>(FederationContext);
const [audio] = useState(() => new Audio(`${audioPath}/chat-open.mp3`));
const [connected, setConnected] = useState<boolean>(false);
@ -98,13 +103,20 @@ const EncryptedSocketChat: React.FC<Props> = ({
}, [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<Props> = ({
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<Props> = ({
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<Props> = ({
};
const onButtonClicked = (e: React.FormEvent<HTMLFormElement>): 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<Props> = ({
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<Props> = ({
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<Props> = ({
</Grid>
<Grid item>
<ChatBottom
orderId={orderId}
orderId={order.id}
audit={audit}
setAudit={setAudit}
createJsonFile={createJsonFile}

View File

@ -19,9 +19,10 @@ import {
FederationContext,
} from '../../../../contexts/FederationContext';
import { type UseGarageStoreType, GarageContext } from '../../../../contexts/GarageContext';
import { Order } from '../../../../models';
interface Props {
orderId: number;
order: Order;
userNick: string;
takerNick: string;
chatOffset: number;
@ -38,7 +39,7 @@ const audioPath =
: 'file:///android_asset/Web.bundle/assets/sounds';
const EncryptedTurtleChat: React.FC<Props> = ({
orderId,
order,
userNick,
takerNick,
chatOffset,
@ -94,7 +95,7 @@ const EncryptedTurtleChat: React.FC<Props> = ({
.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<Props> = ({
};
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<Props> = ({
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<Props> = ({
};
const onButtonClicked = (e: React.FormEvent<HTMLFormElement>): 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<Props> = ({
`/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<Props> = ({
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<Props> = ({
`/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<Props> = ({
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<Props> = ({
<Grid item>
<ChatBottom
orderId={orderId}
orderId={order.id}
audit={audit}
setAudit={setAudit}
createJsonFile={createJsonFile}

View File

@ -1,10 +1,10 @@
import React, { useState } from 'react';
import { type Robot } from '../../../models';
import { Order, type Robot } from '../../../models';
import EncryptedSocketChat from './EncryptedSocketChat';
import EncryptedTurtleChat from './EncryptedTurtleChat';
interface Props {
orderId: number;
order: Order;
status: number;
takerNick: string;
makerNick: string;
@ -33,7 +33,7 @@ export interface ServerMessage {
}
const EncryptedChat: React.FC<Props> = ({
orderId,
order,
takerNick,
userNick,
chatOffset,
@ -48,7 +48,7 @@ const EncryptedChat: React.FC<Props> = ({
<EncryptedTurtleChat
messages={messages}
setMessages={setMessages}
orderId={orderId}
order={order}
takerNick={takerNick}
userNick={userNick}
chatOffset={chatOffset}
@ -61,7 +61,7 @@ const EncryptedChat: React.FC<Props> = ({
status={status}
messages={messages}
setMessages={setMessages}
orderId={orderId}
order={order}
takerNick={takerNick}
userNick={userNick}
baseUrl={baseUrl}

View File

@ -132,7 +132,7 @@ export const ChatPrompt = ({
<EncryptedChat
status={order.status}
chatOffset={order.chat_last_index}
orderId={order.id}
order={order}
takerNick={order.taker_nick}
makerNick={order.maker_nick}
userNick={order.ur_nick}

View File

@ -269,11 +269,12 @@ const TradeBox = ({ baseUrl, onStartAgain }: TradeBoxProps): JSX.Element => {
};
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 });

View File

@ -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]);

View File

@ -291,17 +291,14 @@ export class Coordinator {
};
fecthRobot = async (garage: Garage, token: string): Promise<Robot | null> => {
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<Order | null> => {
fetchOrder = async (orderId: number, robot: Robot, token: string): Promise<Order | null> => {
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<null> => {
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,
});

View File

@ -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();
}

View File

@ -10,13 +10,13 @@ interface AuthHeaders {
}
class Robot {
constructor(garageRobot?: Robot) {
if (garageRobot != null) {
this.token = garageRobot?.token ?? undefined;
constructor(attributes?: Record<any, any>) {
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 ?? '';

View File

@ -48,7 +48,8 @@ class Slot {
};
upsertRobot = (shortAlias: string, attributes: Record<any, any>): 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);