decline & accept devices and protocol connection issues fixed

This commit is contained in:
RoyceDa
2026-01-31 04:55:00 +02:00
parent 22a1fd3a1a
commit a95db0d24b
6 changed files with 129 additions and 9 deletions

View File

@@ -1,6 +1,8 @@
import { useRosettaColors } from "@/app/hooks/useRosettaColors"; 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 { DeviceEntry } from "@/app/providers/ProtocolProvider/protocol/packets/packet.device.list";
import { Box, Button, Divider, Flex, Text } from "@mantine/core"; import { Box, Button, Divider, Flex, Text } from "@mantine/core";
import { modals } from "@mantine/modals";
export interface DeviceVerifyProps { export interface DeviceVerifyProps {
device: DeviceEntry; device: DeviceEntry;
@@ -8,6 +10,24 @@ export interface DeviceVerifyProps {
export function DeviceVerify(props: DeviceVerifyProps) { export function DeviceVerify(props: DeviceVerifyProps) {
const colors = useRosettaColors(); const colors = useRosettaColors();
const { accept, decline } = useDeviceResolve();
const acceptConfirmModal = () => {
modals.openConfirmModal({
title: 'Accept new device',
children: (
<Text size="sm">
Are you sure you want to accept this device? This will allow it to access your account.
</Text>
),
centered: true,
labels: { confirm: 'Accept', cancel: 'Cancel' },
cancelProps: { color: 'gray', style: {
outline: 'none'
} },
onConfirm: () => accept(props.device.deviceId),
});
}
return ( return (
<Box bg={colors.mainColor} h={65}> <Box bg={colors.mainColor} h={65}>
@@ -17,8 +37,8 @@ export function DeviceVerify(props: DeviceVerifyProps) {
New login from {props.device.deviceName} ({props.device.deviceOs}) New login from {props.device.deviceName} ({props.device.deviceOs})
</Text> </Text>
<Flex direction={'row'} mt={'xs'} gap={'md'}> <Flex direction={'row'} mt={'xs'} gap={'md'}>
<Button p={0} h={18} variant={'transparent'} size={'xs'}>Accept</Button> <Button p={0} h={18} onClick={acceptConfirmModal} variant={'transparent'} size={'xs'}>Accept</Button>
<Button p={0} h={18} variant={'transparent'} size={'xs'} color={'red'}>Decline</Button> <Button p={0} h={18} onClick={() => decline(props.device.deviceId)} variant={'transparent'} size={'xs'} color={'red'}>Decline</Button>
</Flex> </Flex>
</Flex> </Flex>
</Box> </Box>

View File

@@ -6,22 +6,22 @@ import { dotCenterIfNeeded } from "../utils/utils";
const messageTemplate = ` const messageTemplate = `
**Attempt to login from a new device** **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} **IP:** {ip}
**Device:** {device} **Device:** {device}
**ID:** {deviceId}` **ID:** {deviceId}`;
export function useDeviceMessage() { export function useDeviceMessage() {
const send = useSendSystemMessage("safe"); const send = useSendSystemMessage("safe");
usePacket(0x09, (packet: PacketDeviceNew) => { usePacket(0x09, (packet: PacketDeviceNew) => {
send(messageTemplate send(messageTemplate
.replace("{ip}", packet.getIpAddress()) .replaceAll("{ip}", packet.getIpAddress())
.replace("{device}", packet.getDevice().deviceName) .replaceAll("{device}", packet.getDevice().deviceName)
.replace("{os}", packet.getDevice().deviceOs) .replaceAll("{os}", packet.getDevice().deviceOs)
.replace("{deviceId}", dotCenterIfNeeded(packet.getDevice().deviceId, 12, 4)) .replaceAll("{deviceId}", dotCenterIfNeeded(packet.getDevice().deviceId, 12, 4))
); );
}, []); }, []);
} }

View File

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

View File

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

View File

@@ -26,6 +26,7 @@ import { PacketGroupLeave } from "./packets/packet.group.leave";
import { PacketGroupBan } from "./packets/packet.group.ban"; import { PacketGroupBan } from "./packets/packet.group.ban";
import { PacketDeviceNew } from "./packets/packet.device.new"; import { PacketDeviceNew } from "./packets/packet.device.new";
import { PacketDeviceList } from "./packets/packet.device.list"; import { PacketDeviceList } from "./packets/packet.device.list";
import { PacketDeviceResolve } from "./packets/packet.device.resolve";
export default class Protocol extends EventEmitter { export default class Protocol extends EventEmitter {
private serverAddress: string; private serverAddress: string;
@@ -122,6 +123,7 @@ export default class Protocol extends EventEmitter {
this._supportedPackets.set(0x15, new PacketGroupLeave()); this._supportedPackets.set(0x15, new PacketGroupLeave());
this._supportedPackets.set(0x16, new PacketGroupBan()); this._supportedPackets.set(0x16, new PacketGroupBan());
this._supportedPackets.set(0x17, new PacketDeviceList()); this._supportedPackets.set(0x17, new PacketDeviceList());
this._supportedPackets.set(0x18, new PacketDeviceResolve());
} }
private _findWaiters(packetId: number): ((packet: Packet) => void)[] { private _findWaiters(packetId: number): ((packet: Packet) => void)[] {
@@ -133,6 +135,11 @@ export default class Protocol extends EventEmitter {
public connect() { public connect() {
this.socket = new WebSocket(this.serverAddress); this.socket = new WebSocket(this.serverAddress);
/**
* Сбрасываем флаг ручного закрытия соединения
* при подключении
*/
this.isManuallyClosed = false;
this.socket.addEventListener('open', () => { this.socket.addEventListener('open', () => {
//this.reconnectTryings = 0; //this.reconnectTryings = 0;

View File

@@ -8,6 +8,8 @@ import { useNavigate } from "react-router-dom";
import animationData from './inbox.json' import animationData from './inbox.json'
import { AnimatedButton } from "@/app/components/AnimatedButton/AnimatedButton"; import { AnimatedButton } from "@/app/components/AnimatedButton/AnimatedButton";
import { useLogout } from "@/app/providers/AccountProvider/useLogout"; 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() { export function DeviceConfirm() {
const protocolState = useProtocolState(); const protocolState = useProtocolState();
@@ -20,6 +22,15 @@ export function DeviceConfirm() {
} }
}, [protocolState]); }, [protocolState]);
usePacket(0x18, (packet : PacketDeviceResolve) => {
/**
* Если решение отклонено, то выходим из аккаунта
*/
if(packet.getSolution() == Solution.DECLINE){
logout();
}
}, []);
return ( return (
<PrivateView> <PrivateView>
<Flex h={500} justify={'space-between'} align={'center'} direction={'column'}> <Flex h={500} justify={'space-between'} align={'center'} direction={'column'}>