diff --git a/app/components/DeviceVerify/DeviceVerify.tsx b/app/components/DeviceVerify/DeviceVerify.tsx
new file mode 100644
index 0000000..6b965f6
--- /dev/null
+++ b/app/components/DeviceVerify/DeviceVerify.tsx
@@ -0,0 +1,16 @@
+import { DeviceEntry } from "@/app/providers/ProtocolProvider/protocol/packets/packet.device.list";
+import { Flex, Text } from "@mantine/core";
+
+export interface DeviceVerifyProps {
+ device: DeviceEntry;
+}
+
+export function DeviceVerify(props: DeviceVerifyProps) {
+ return (
+
+
+ New login from {props.device.deviceName}
+
+
+ );
+}
\ No newline at end of file
diff --git a/app/components/DialogsPanel/DialogsPanel.tsx b/app/components/DialogsPanel/DialogsPanel.tsx
index 86e782e..f4bde5e 100644
--- a/app/components/DialogsPanel/DialogsPanel.tsx
+++ b/app/components/DialogsPanel/DialogsPanel.tsx
@@ -8,6 +8,8 @@ import { useNavigate } from 'react-router-dom';
import { DialogsList } from '../DialogsList/DialogsList';
import { DialogsPanelHeader } from '../DialogsPanelHeader/DialogsPanelHeader';
import { useDialogsList } from '@/app/providers/DialogListProvider/useDialogsList';
+import { useVerifyRequest } from '@/app/providers/DeviceProvider/useVerifyRequest';
+import { DeviceVerify } from '../DeviceVerify/DeviceVerify';
export function DialogsPanel() {
const [dialogsMode, setDialogsMode] = useState<'all' | 'requests'>('all');
@@ -15,6 +17,7 @@ export function DialogsPanel() {
const {dialogs} = useDialogsList();
const colors = useRosettaColors();
const navigate = useNavigate();
+ const device = useVerifyRequest();
useEffect(() => {
((async () => {
@@ -51,6 +54,9 @@ export function DialogsPanel() {
>
+ {device && (
+
+ )}
{requestsCount > 0 && }
diff --git a/app/providers/DeviceProvider/DeviceProvider.tsx b/app/providers/DeviceProvider/DeviceProvider.tsx
index dca79c5..60b6866 100644
--- a/app/providers/DeviceProvider/DeviceProvider.tsx
+++ b/app/providers/DeviceProvider/DeviceProvider.tsx
@@ -1,76 +1,31 @@
-import { decodeWithPassword, encodeWithPassword } from "@/app/crypto/crypto";
-import { useFileStorage } from "@/app/hooks/useFileStorage";
-import { generateRandomKey } from "@/app/utils/utils";
-import { createContext, useEffect, useState } from "react";
+import { createContext, useState } from "react";
+import { DeviceEntry, PacketDeviceList } from "../ProtocolProvider/protocol/packets/packet.device.list";
+import { usePacket } from "../ProtocolProvider/usePacket";
interface DeviceProviderContextValue {
- deviceId: string;
+ devices: DeviceEntry[];
}
-export const DeviceProviderContext = createContext(null);
+export const DeviceProviderContext = createContext(null);
interface DeviceProviderProps {
children?: React.ReactNode;
}
export function DeviceProvider(props: DeviceProviderProps) {
- const [deviceId, setDeviceId] = useState("");
- const {writeFile, readFile} = useFileStorage();
+ /**
+ * Подключенные устройства
+ */
+ const [devices, setDevices] = useState([]);
- useEffect(() => {
- fetchDeviceId();
+ usePacket(0x17, (packet : PacketDeviceList) => {
+ console.info("Device list update", packet.getDevices());
+ setDevices(packet.getDevices());
}, []);
- const fetchDeviceId = async () => {
- const device = await readFile("device");
- if(device){
- const decoded = await decodeDevice(Buffer.from(device).toString('utf-8'));
- if(decoded){
- setDeviceId(decoded);
- return;
- }
- }
- await createDeviceId();
- }
-
- const createDeviceId = async () => {
- const newDevice = generateRandomKey(128);
- const encoded = await encodeDevice(newDevice);
- await writeFile("device", encoded);
- setDeviceId(newDevice);
- }
-
- const decodeDevice = async (data: string) => {
- const hwid = window.deviceId;
- const platform = window.deviceName;
- const salt = "rosetta-device-salt";
-
- try {
- const decoded = await decodeWithPassword(hwid + platform + salt, data);
- return decoded;
- } catch (e) {
- console.error("Failed to decode device data:", e);
- return null;
- }
- }
-
- const encodeDevice = async (data: string) => {
- const hwid = window.deviceId;
- const platform = window.deviceName;
- const salt = "rosetta-device-salt";
-
- try {
- const encoded = await encodeWithPassword(hwid + platform + salt, data);
- return encoded;
- } catch (e) {
- console.error("Failed to encode device data:", e);
- return null;
- }
- }
-
return (
{props.children}
diff --git a/app/providers/DeviceProvider/useDevices.ts b/app/providers/DeviceProvider/useDevices.ts
new file mode 100644
index 0000000..8f1f6e0
--- /dev/null
+++ b/app/providers/DeviceProvider/useDevices.ts
@@ -0,0 +1,13 @@
+import { useContext } from "react";
+import { DeviceProviderContext } from "./DeviceProvider";
+import { DeviceEntry } from "../ProtocolProvider/protocol/packets/packet.device.list";
+
+export function useDevices() : DeviceEntry[] {
+ const context = useContext(DeviceProviderContext);
+
+ if(!context) {
+ throw new Error("useDevices must be used within a DeviceProvider");
+ }
+
+ return context.devices;
+}
\ No newline at end of file
diff --git a/app/providers/DeviceProvider/useVerifyRequest.ts b/app/providers/DeviceProvider/useVerifyRequest.ts
new file mode 100644
index 0000000..c76f228
--- /dev/null
+++ b/app/providers/DeviceProvider/useVerifyRequest.ts
@@ -0,0 +1,23 @@
+import { useContext } from "react";
+import { DeviceEntry, DeviceVerifyState } from "../ProtocolProvider/protocol/packets/packet.device.list";
+import { DeviceProviderContext } from "./DeviceProvider";
+
+/**
+ * Получает устройство ожидающее подтверждения, если оно есть
+ * @returns возвращает устройство которое сейчас ждет одобрения
+ * от других устройств
+ */
+export function useVerifyRequest() : DeviceEntry | null {
+ const context = useContext(DeviceProviderContext);
+ if(!context) {
+ throw new Error("useVerifyRequest must be used within a DeviceProvider");
+ }
+
+ const pending = context.devices.find(device => device.deviceVerify === DeviceVerifyState.NOT_VERIFIED);
+
+ if(!pending) {
+ return null;
+ }
+
+ return pending;
+}
\ No newline at end of file
diff --git a/app/providers/ProtocolProvider/protocol/protocol.ts b/app/providers/ProtocolProvider/protocol/protocol.ts
index 0b983c5..7fcc486 100644
--- a/app/providers/ProtocolProvider/protocol/protocol.ts
+++ b/app/providers/ProtocolProvider/protocol/protocol.ts
@@ -24,6 +24,8 @@ import { PacketGroupInviteInfo } from "./packets/packet.group.invite.info";
import { PacketGroupJoin } from "./packets/packet.group.join";
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";
export default class Protocol extends EventEmitter {
private serverAddress: string;
@@ -105,7 +107,7 @@ export default class Protocol extends EventEmitter {
this._supportedPackets.set(0x06, new PacketMessage());
this._supportedPackets.set(0x07, new PacketRead());
this._supportedPackets.set(0x08, new PacketDelivery());
- //TODO: 0x09
+ this._supportedPackets.set(0x09, new PacketDeviceNew());
this._supportedPackets.set(0x0A, new PacketRequestUpdate());
this._supportedPackets.set(0x0B, new PacketTyping());
this._supportedPackets.set(0x0C, new PacketAvatar());
@@ -119,6 +121,7 @@ export default class Protocol extends EventEmitter {
this._supportedPackets.set(0x14, new PacketGroupJoin());
this._supportedPackets.set(0x15, new PacketGroupLeave());
this._supportedPackets.set(0x16, new PacketGroupBan());
+ this._supportedPackets.set(0x17, new PacketDeviceList());
}
private _findWaiters(packetId: number): ((packet: Packet) => void)[] {