From b671262aa282b80e741e839b138a7dd3d40918e0 Mon Sep 17 00:00:00 2001 From: RoyceDa Date: Tue, 10 Feb 2026 00:51:40 +0200 Subject: [PATCH] =?UTF-8?q?=D0=9E=D0=B1=D1=80=D0=B0=D0=B1=D0=BE=D1=82?= =?UTF-8?q?=D0=BA=D0=B0=20=D0=BF=D0=B0=D0=BA=D0=B5=D1=82=D0=B0=20=D0=BF?= =?UTF-8?q?=D0=B5=D1=87=D0=B0=D1=82=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/rosetta/im/Boot.java | 4 + .../im/executors/Executor11Typeing.java | 73 +++++++++++++++++++ .../im/executors/Executor6Message.java | 3 +- .../rosetta/im/packet/Packet11Typeing.java | 29 ++++++++ .../im/packet/base/PacketBaseDialog.java | 8 ++ .../service/dispatch/MessageDispatcher.java | 28 ++++++- 6 files changed, 143 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/rosetta/im/executors/Executor11Typeing.java create mode 100644 src/main/java/com/rosetta/im/packet/Packet11Typeing.java diff --git a/src/main/java/com/rosetta/im/Boot.java b/src/main/java/com/rosetta/im/Boot.java index 57255b0..79b03dc 100644 --- a/src/main/java/com/rosetta/im/Boot.java +++ b/src/main/java/com/rosetta/im/Boot.java @@ -4,6 +4,7 @@ import com.rosetta.im.client.ClientManager; import com.rosetta.im.client.OnlineManager; import com.rosetta.im.event.EventManager; import com.rosetta.im.executors.Executor0Handshake; +import com.rosetta.im.executors.Executor11Typeing; import com.rosetta.im.executors.Executor1UserInfo; import com.rosetta.im.executors.Executor24DeviceResolve; import com.rosetta.im.executors.Executor3Search; @@ -19,6 +20,7 @@ import com.rosetta.im.logger.Logger; import com.rosetta.im.logger.enums.Color; import com.rosetta.im.logger.enums.LogLevel; import com.rosetta.im.packet.Packet0Handshake; +import com.rosetta.im.packet.Packet11Typeing; import com.rosetta.im.packet.Packet1UserInfo; import com.rosetta.im.packet.Packet23DeviceList; import com.rosetta.im.packet.Packet24DeviceResolve; @@ -129,6 +131,7 @@ public class Boot { this.packetManager.registerPacket(7, Packet7Read.class); this.packetManager.registerPacket(8, Packet8Delivery.class); this.packetManager.registerPacket(9, Packet9DeviceNew.class); + this.packetManager.registerPacket(11, Packet11Typeing.class); this.packetManager.registerPacket(23, Packet23DeviceList.class); this.packetManager.registerPacket(24, Packet24DeviceResolve.class); @@ -141,6 +144,7 @@ public class Boot { this.packetManager.registerExecutor(4, new Executor4OnlineState(this.onlineManager, this.clientManager)); this.packetManager.registerExecutor(6, new Executor6Message(this.clientManager, this.packetManager)); this.packetManager.registerExecutor(7, new Executor7Read(this.clientManager, this.packetManager)); + this.packetManager.registerExecutor(11, new Executor11Typeing(this.clientManager, this.packetManager)); this.packetManager.registerExecutor(24, new Executor24DeviceResolve(this.clientManager, this.eventManager)); } diff --git a/src/main/java/com/rosetta/im/executors/Executor11Typeing.java b/src/main/java/com/rosetta/im/executors/Executor11Typeing.java new file mode 100644 index 0000000..d54e874 --- /dev/null +++ b/src/main/java/com/rosetta/im/executors/Executor11Typeing.java @@ -0,0 +1,73 @@ +package com.rosetta.im.executors; + +import com.rosetta.im.Failures; +import com.rosetta.im.client.ClientManager; +import com.rosetta.im.client.tags.ECIAuthentificate; +import com.rosetta.im.packet.Packet11Typeing; +import com.rosetta.im.service.dispatch.MessageDispatcher; + +import io.orprotocol.ProtocolException; +import io.orprotocol.client.Client; +import io.orprotocol.packet.PacketExecutor; +import io.orprotocol.packet.PacketManager; + +public class Executor11Typeing extends PacketExecutor { + + private final MessageDispatcher messageDispatcher; + + public Executor11Typeing(ClientManager clientManager, PacketManager packetManager) { + this.messageDispatcher = new MessageDispatcher(clientManager, packetManager); + } + + @Override + public void onPacketReceived(Packet11Typeing packet, Client client) throws Exception, ProtocolException { + ECIAuthentificate eciAuthentificate = client.getTag(ECIAuthentificate.class); + String fromPublicKey = packet.getFromPublicKey(); + String toPublicKey = packet.getToPublicKey(); + + if(eciAuthentificate == null || !eciAuthentificate.hasAuthorized()){ + /** + * Если пользователь не авторизован он не может отправлять пакет печати + */ + client.disconnect(Failures.HANDSHAKE_NOT_COMPLETED); + return; + } + + if(!eciAuthentificate.getPublicKey().equals(fromPublicKey)){ + /** + * Если клиент пытается отправить сообщение от отправителя, + * которым он не является + */ + client.disconnect(Failures.DATA_MISSMATCH); + return; + } + + if(fromPublicKey.equals(toPublicKey)){ + /** + * Отправка пакета печати самому себе, не кикаем пользователя, так как это ни на что не + * влияет, просто ничего не делаем + */ + return; + } + + /** + * Удаляем приватный ключ чтобы не показать его оппоненту + */ + packet.setPrivateKey(""); + + if(toPublicKey.startsWith("#group:")){ + /** + * Пакет печати отправляется в группу, отправляем всем участникам + */ + this.messageDispatcher.sendGroup(packet, client, eciAuthentificate); + }else{ + /** + * Пакет печати отправляется обычному оппоненту (пользователь), + * отправляем его, при этом выключаем буфферизацию, потому что пакет печати действителен + * только "здесь и сейчас", его не нужно видеть офлайн пользователям + */ + this.messageDispatcher.sendPeer(packet, client, false); + } + } + +} diff --git a/src/main/java/com/rosetta/im/executors/Executor6Message.java b/src/main/java/com/rosetta/im/executors/Executor6Message.java index a3fb14f..003bd71 100644 --- a/src/main/java/com/rosetta/im/executors/Executor6Message.java +++ b/src/main/java/com/rosetta/im/executors/Executor6Message.java @@ -95,7 +95,8 @@ public class Executor6Message extends PacketExecutor { return; } /** - * Обновляем системную метку времени в соотвествии с сервером, так как у клиентов могут быть например неправильно настроены часы + * Обновляем системную метку времени в соотвествии с сервером, + * так как у клиентов могут быть например неправильно настроены часы * или разные часовые пояса */ packet.setTimestamp(System.currentTimeMillis()); diff --git a/src/main/java/com/rosetta/im/packet/Packet11Typeing.java b/src/main/java/com/rosetta/im/packet/Packet11Typeing.java new file mode 100644 index 0000000..a9530d0 --- /dev/null +++ b/src/main/java/com/rosetta/im/packet/Packet11Typeing.java @@ -0,0 +1,29 @@ +package com.rosetta.im.packet; + +import com.rosetta.im.packet.base.PacketBaseDialog; + +import io.orprotocol.Stream; + +/** + * Пакет отвечающий за индикацию печати в диалогах + */ +public class Packet11Typeing extends PacketBaseDialog { + + @Override + public void read(Stream stream) { + this.privateKey = stream.readString(); + this.fromPublicKey = stream.readString(); + this.toPublicKey = stream.readString(); + } + + @Override + public Stream write() { + Stream stream = new Stream(); + stream.writeInt16(this.packetId); + stream.writeString(this.privateKey); + stream.writeString(this.fromPublicKey); + stream.writeString(this.toPublicKey); + return stream; + } + +} diff --git a/src/main/java/com/rosetta/im/packet/base/PacketBaseDialog.java b/src/main/java/com/rosetta/im/packet/base/PacketBaseDialog.java index 119b501..b1f8dcf 100644 --- a/src/main/java/com/rosetta/im/packet/base/PacketBaseDialog.java +++ b/src/main/java/com/rosetta/im/packet/base/PacketBaseDialog.java @@ -5,6 +5,14 @@ import io.orprotocol.packet.Packet; /** * Базовый пакет для диалогов между пользователями + * + * ВОПРОС: Почему мы должны отправлять fromPublicKey с клиента, если сервер + * может получить fromPublicKey из хэндшейка? + * ОТВЕТ: Клиенты (оппоненты) должны понимать, от кого им приходит например пакет сообщения + * или печати с сервера (from), чтобы производить с отправителем какие-либо действия (например показать + * имя печатающего или отрендерить аватарку отправтеля сообщения), если бы поле fromPublicKey заполнял + * сервер - это бы выглядело не логично. Это не влияет на безопасность, так как каждый Exectuor + * верифицирует поле fromPublicKey сравнивая его с публичным ключом фактического отправителя. */ public class PacketBaseDialog extends Packet { diff --git a/src/main/java/com/rosetta/im/service/dispatch/MessageDispatcher.java b/src/main/java/com/rosetta/im/service/dispatch/MessageDispatcher.java index 092702a..429462e 100644 --- a/src/main/java/com/rosetta/im/service/dispatch/MessageDispatcher.java +++ b/src/main/java/com/rosetta/im/service/dispatch/MessageDispatcher.java @@ -75,15 +75,41 @@ public class MessageDispatcher { /** * Отправляет личное сообщение получателю * @param packet пакет с личным сообщением + * @param client клиент отправляющий пакет + * @param bufferizationNeed флаг указывающий на то, что сообщение нужно буфферизировать, + * чтобы доставить пользователям если они не онлайн, если указать false то этот пакет получит + * только пользователь который были в сети */ - public void sendPeer(PacketBaseDialog packet, Client client) throws ProtocolException { + public void sendPeer(PacketBaseDialog packet, Client client, boolean bufferizationNeed) throws ProtocolException { String fromPublicKey = packet.getFromPublicKey(); String toPublicKey = packet.getToPublicKey(); this.clientManager.sendPacketToAuthorizedPK(toPublicKey, packet); + + if(!bufferizationNeed){ + /** + * Указан флаг, что буферизация не нужна, сообщения с этим флагом не будут доставлены если + * оппонент оффлайн + */ + return; + } /** * Сохраняем сообщение в буфер на случай если получатель офлайн, или нам нужна будет синхронизация сообщений для получателя */ this.bufferService.pushPacketToBuffer(fromPublicKey, toPublicKey, packet); } + /** + * Отправляет личное сообщение получателю с буферизацией + * @param packet пакет сообщения + * @param client клиент отправляющий пакет + * @throws ProtocolException + */ + public void sendPeer(PacketBaseDialog packet, Client client) throws ProtocolException { + /** + * По умолчанию буферизация включена, чтобы не терять сообщения + */ + this.sendPeer(packet, client, true); + } + + }