diff --git a/app/components/DeviceVerify/DeviceVerify.tsx b/app/components/DeviceVerify/DeviceVerify.tsx index 5ba702f..71c541d 100644 --- a/app/components/DeviceVerify/DeviceVerify.tsx +++ b/app/components/DeviceVerify/DeviceVerify.tsx @@ -1,6 +1,8 @@ import { useRosettaColors } from "@/app/hooks/useRosettaColors"; +import { useDeviceResolve } from "@/app/providers/DeviceProvider/useDeviceResolve"; import { DeviceEntry } from "@/app/providers/ProtocolProvider/protocol/packets/packet.device.list"; import { Box, Button, Divider, Flex, Text } from "@mantine/core"; +import { modals } from "@mantine/modals"; export interface DeviceVerifyProps { device: DeviceEntry; @@ -8,6 +10,24 @@ export interface DeviceVerifyProps { export function DeviceVerify(props: DeviceVerifyProps) { const colors = useRosettaColors(); + const { accept, decline } = useDeviceResolve(); + + const acceptConfirmModal = () => { + modals.openConfirmModal({ + title: 'Accept new device', + children: ( + + Are you sure you want to accept this device? This will allow it to access your account. + + ), + centered: true, + labels: { confirm: 'Accept', cancel: 'Cancel' }, + cancelProps: { color: 'gray', style: { + outline: 'none' + } }, + onConfirm: () => accept(props.device.deviceId), + }); + } return ( @@ -17,8 +37,8 @@ export function DeviceVerify(props: DeviceVerifyProps) { New login from {props.device.deviceName} ({props.device.deviceOs}) - - + + diff --git a/app/hooks/useDeviceMessage.ts b/app/hooks/useDeviceMessage.ts index 4289d11..3db8360 100644 --- a/app/hooks/useDeviceMessage.ts +++ b/app/hooks/useDeviceMessage.ts @@ -6,22 +6,22 @@ import { dotCenterIfNeeded } from "../utils/utils"; const messageTemplate = ` **Attempt to login from a new device** -We detected a login to your account from **{os}** a new device **by seed phrase**. If this was you, you can safely ignore this message. +We detected a login to your account from **{ip}** a new device **by seed phrase**. If this was you, you can safely ignore this message. -**OS:** {os} +**Arch:** {os} **IP:** {ip} **Device:** {device} -**ID:** {deviceId}` +**ID:** {deviceId}`; export function useDeviceMessage() { const send = useSendSystemMessage("safe"); usePacket(0x09, (packet: PacketDeviceNew) => { send(messageTemplate - .replace("{ip}", packet.getIpAddress()) - .replace("{device}", packet.getDevice().deviceName) - .replace("{os}", packet.getDevice().deviceOs) - .replace("{deviceId}", dotCenterIfNeeded(packet.getDevice().deviceId, 12, 4)) + .replaceAll("{ip}", packet.getIpAddress()) + .replaceAll("{device}", packet.getDevice().deviceName) + .replaceAll("{os}", packet.getDevice().deviceOs) + .replaceAll("{deviceId}", dotCenterIfNeeded(packet.getDevice().deviceId, 12, 4)) ); }, []); } \ No newline at end of file diff --git a/app/providers/DeviceProvider/useDeviceResolve.ts b/app/providers/DeviceProvider/useDeviceResolve.ts new file mode 100644 index 0000000..70e430f --- /dev/null +++ b/app/providers/DeviceProvider/useDeviceResolve.ts @@ -0,0 +1,28 @@ +import { PacketDeviceResolve, Solution } from "../ProtocolProvider/protocol/packets/packet.device.resolve"; +import { useSender } from "../ProtocolProvider/useSender" + +/** + * Хук для отклонения или принятия устройств + */ +export function useDeviceResolve() { + const send = useSender(); + + const accept = (deviceId: string) => { + const packet = new PacketDeviceResolve(); + packet.setDeviceId(deviceId); + packet.setSolution(Solution.ACCEPT); + send(packet); + } + + const decline = (deviceId: string) => { + const packet = new PacketDeviceResolve(); + packet.setDeviceId(deviceId); + packet.setSolution(Solution.DECLINE); + send(packet); + } + + return { + accept, + decline + } +} \ No newline at end of file diff --git a/app/providers/ProtocolProvider/protocol/packets/packet.device.resolve.ts b/app/providers/ProtocolProvider/protocol/packets/packet.device.resolve.ts new file mode 100644 index 0000000..265bce7 --- /dev/null +++ b/app/providers/ProtocolProvider/protocol/packets/packet.device.resolve.ts @@ -0,0 +1,54 @@ +import Packet from "../packet"; +import Stream from "../stream"; + +/** + * Решение по устройству при верификации + * Отклонить или принять + */ +export enum Solution { + DECLINE, + ACCEPT +} + +/** + * Отправляется клиентом при решении по устройству + */ +export class PacketDeviceResolve extends Packet { + + private deviceId: string = ""; + private solution: Solution = Solution.DECLINE; + + public getPacketId(): number { + return 0x18; + } + + public _receive(stream: Stream): void { + this.deviceId = stream.readString(); + this.solution = stream.readInt8(); + } + + public _send(): Promise | Stream { + const stream = new Stream(); + stream.writeInt16(this.getPacketId()); + stream.writeString(this.deviceId); + stream.writeInt8(this.solution); + return stream; + } + + public getDeviceId(): string { + return this.deviceId; + } + + public getSolution(): Solution { + return this.solution; + } + + public setDeviceId(deviceId: string): void { + this.deviceId = deviceId; + } + + public setSolution(solution: Solution): void { + this.solution = solution; + } + +} \ No newline at end of file diff --git a/app/providers/ProtocolProvider/protocol/protocol.ts b/app/providers/ProtocolProvider/protocol/protocol.ts index 5ae939a..a6ea06a 100644 --- a/app/providers/ProtocolProvider/protocol/protocol.ts +++ b/app/providers/ProtocolProvider/protocol/protocol.ts @@ -26,6 +26,7 @@ import { PacketGroupLeave } from "./packets/packet.group.leave"; import { PacketGroupBan } from "./packets/packet.group.ban"; import { PacketDeviceNew } from "./packets/packet.device.new"; import { PacketDeviceList } from "./packets/packet.device.list"; +import { PacketDeviceResolve } from "./packets/packet.device.resolve"; export default class Protocol extends EventEmitter { private serverAddress: string; @@ -122,6 +123,7 @@ export default class Protocol extends EventEmitter { this._supportedPackets.set(0x15, new PacketGroupLeave()); this._supportedPackets.set(0x16, new PacketGroupBan()); this._supportedPackets.set(0x17, new PacketDeviceList()); + this._supportedPackets.set(0x18, new PacketDeviceResolve()); } private _findWaiters(packetId: number): ((packet: Packet) => void)[] { @@ -133,6 +135,11 @@ export default class Protocol extends EventEmitter { public connect() { this.socket = new WebSocket(this.serverAddress); + /** + * Сбрасываем флаг ручного закрытия соединения + * при подключении + */ + this.isManuallyClosed = false; this.socket.addEventListener('open', () => { //this.reconnectTryings = 0; diff --git a/app/views/DeviceConfirm/DeviceConfirm.tsx b/app/views/DeviceConfirm/DeviceConfirm.tsx index d184089..e17a113 100644 --- a/app/views/DeviceConfirm/DeviceConfirm.tsx +++ b/app/views/DeviceConfirm/DeviceConfirm.tsx @@ -8,6 +8,8 @@ import { useNavigate } from "react-router-dom"; import animationData from './inbox.json' import { AnimatedButton } from "@/app/components/AnimatedButton/AnimatedButton"; import { useLogout } from "@/app/providers/AccountProvider/useLogout"; +import { usePacket } from "@/app/providers/ProtocolProvider/usePacket"; +import { PacketDeviceResolve, Solution } from "@/app/providers/ProtocolProvider/protocol/packets/packet.device.resolve"; export function DeviceConfirm() { const protocolState = useProtocolState(); @@ -19,6 +21,15 @@ export function DeviceConfirm() { navigate('/main'); } }, [protocolState]); + + usePacket(0x18, (packet : PacketDeviceResolve) => { + /** + * Если решение отклонено, то выходим из аккаунта + */ + if(packet.getSolution() == Solution.DECLINE){ + logout(); + } + }, []); return (