Files
rosetta-wss/src/main/java/im/rosetta/executors/Executor0Handshake.java

231 lines
10 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package im.rosetta.executors;
import im.rosetta.Failures;
import im.rosetta.client.ClientManager;
import im.rosetta.client.tags.ECIAuthentificate;
import im.rosetta.client.tags.ECIDevice;
import im.rosetta.database.entity.Device;
import im.rosetta.database.entity.User;
import im.rosetta.database.repository.BufferRepository;
import im.rosetta.database.repository.DeviceRepository;
import im.rosetta.database.repository.UserRepository;
import im.rosetta.event.EventManager;
import im.rosetta.event.events.handshake.HandshakeCompletedEvent;
import im.rosetta.event.events.handshake.HandshakeDeviceConfirmEvent;
import im.rosetta.event.events.handshake.HandshakeFailedEvent;
import im.rosetta.packet.Packet0Handshake;
import im.rosetta.packet.Packet9DeviceNew;
import im.rosetta.packet.runtime.HandshakeStage;
import im.rosetta.service.services.BufferService;
import im.rosetta.service.services.DeviceService;
import io.orprotocol.ProtocolException;
import io.orprotocol.client.Client;
import io.orprotocol.lock.Lock;
import io.orprotocol.packet.PacketExecutor;
import io.orprotocol.packet.PacketManager;
public class Executor0Handshake extends PacketExecutor<Packet0Handshake> {
private final UserRepository userRepository = new UserRepository();
private final DeviceRepository deviceRepository = new DeviceRepository();
private final DeviceService deviceService = new DeviceService(deviceRepository);
private final EventManager eventManager;
private final ClientManager clientManager;
private final BufferRepository bufferRepository = new BufferRepository();
private final BufferService bufferService;
public Executor0Handshake(EventManager eventManager, ClientManager clientManager, PacketManager packetManager) {
this.eventManager = eventManager;
this.clientManager = clientManager;
this.bufferService = new BufferService(bufferRepository, packetManager);
}
@Override
@Lock(lockFor = "publicKey")
public void onPacketReceived(Packet0Handshake handshake, Client client) throws ProtocolException {
String publicKey = handshake.getPublicKey();
String privateKey = handshake.getPrivateKey();
String deviceId = handshake.getDeviceId();
String deviceName = handshake.getDeviceName();
String deviceOs = handshake.getDeviceOs();
int protocolVersion = handshake.getProtocolVersion();
/**
* Получаем информацию об аутентификации клиента
* используя возможности ECI тэгов.
*/
ECIAuthentificate authentificate = client.getTag(ECIAuthentificate.class);
if(authentificate != null && authentificate.hasAuthorized()) {
/**
* Клиент уже авторизован, повторный хэндшейк не допускается
*/
return;
}
/**
* Проверяем корректность версии протокола
*/
if(protocolVersion != 1) {
client.disconnect(Failures.UNSUPPORTED_PROTOCOL);
return;
}
/**
* Создаем минимальную информацию об устройстве клиента
*/
ECIDevice device = new ECIDevice(deviceId, deviceName, deviceOs);
client.addTag(ECIDevice.class, device);
/**
* Проверяем есть ли такой пользователь
*/
User user = userRepository.findByField("publicKey", publicKey);
if(user == null) {
/**
* Пользователь не найден, создаем нового
*/
user = new User();
user.setPrivateKey(privateKey);
user.setPublicKey(publicKey);
user.setUsername("");
user.setTitle(publicKey.substring(0, 7));
/**
* Новый пользователь не верифицирован
*/
user.setVerified(0);
userRepository.save(user);
/**
* Это первое устройство пользователя, сохраняем его
* как верифицированное
*/
Device newDevice = new Device();
newDevice.setDeviceId(deviceId);
newDevice.setDeviceName(deviceName);
newDevice.setDeviceOs(deviceOs);
newDevice.setPublicKey(publicKey);
newDevice.setSyncTime(System.currentTimeMillis());
deviceRepository.save(newDevice);
/**
* Ставим метку аутентификации на клиента
*/
ECIAuthentificate eciTag = new ECIAuthentificate
(publicKey, privateKey, HandshakeStage.COMPLETED);
client.addTag(ECIAuthentificate.class, eciTag);
/**
* Вызываем событие завершения хэндшейка
*/
boolean cancelled = this.eventManager.callEvent(
new HandshakeCompletedEvent(publicKey, privateKey, device, eciTag, client)
);
if(cancelled) {
/**
* Событие было отменено, не даем завершить хэндшейк
*/
client.disconnect(Failures.DATA_MISSMATCH);
return;
}
/**
* Отправляем клиенту подтверждение успешного хэндшейка
*/
handshake.setHandshakeStage(HandshakeStage.COMPLETED);
handshake.setHeartbeatInterval(this.settings.heartbeatInterval);
client.send(handshake);
return;
}
/**
* Пользователь найден, проверяем приватный ключ
*/
if(!user.getPrivateKey().equals(privateKey)){
/**
* Приватный ключ не совпадает, отключаем клиента
*/
eventManager.callEvent(new HandshakeFailedEvent(publicKey, privateKey, device, authentificate, client));
client.disconnect(Failures.AUTHENTIFICATION_ERROR);
return;
}
long userDevicesCount = deviceRepository.countUserDevices(user);
/**
* Проверяем верифицировано ли устройство
*/
if(userDevicesCount > 0 && !deviceService.isDeviceVerifiedByUser(deviceId, user)) {
/**
* Устройство не верифицировано, нужно отправить клиента
* на подтверждение устройства
*/
handshake.setHandshakeStage(HandshakeStage.NEED_DEVICE_VERIFICATION);
handshake.setHeartbeatInterval(this.settings.heartbeatInterval);
/**
* Ставим метку аутентификации на клиента
*/
ECIAuthentificate eciTag = new ECIAuthentificate
(publicKey, privateKey, HandshakeStage.NEED_DEVICE_VERIFICATION);
client.addTag(ECIAuthentificate.class, eciTag);
/**
* Вызываем событие подтверждения устройства
*/
this.eventManager.callEvent(
new HandshakeDeviceConfirmEvent(publicKey, privateKey, device, authentificate, client)
);
/**
* Отправляем клиенту информацию о необходимости
* подтверждения устройства
*/
client.send(handshake);
/**
* Уведомляем все авторизованные устройства пользователя о том, что нужно подтвердить новое устройство
*/
Packet9DeviceNew newDevicePacket = new Packet9DeviceNew();
newDevicePacket.setDeviceId(deviceId);
newDevicePacket.setDeviceName(deviceName);
newDevicePacket.setDeviceOs(deviceOs);
newDevicePacket.setIpAddress(client.getIpAddress());
clientManager.sendPacketToAuthorizedPK(publicKey, newDevicePacket);
/**
* Сбрасываем клиенту все старые подтверждения устройств, чтобы исключить спам запросами
*/
this.bufferService.deletePacketsFromBuffer(publicKey, newDevicePacket, 0);
/**
* Кладем пакет в очередь на все устройства пользователя,
* чтобы если в момент отправки этого пакета какое-то устройство было не онлайн,
* то когда оно зайдет в сеть, то получит этот пакет и сможет отреагировать на него,
* показав пользователю уведомление о том, что нужно подтвердить новое устройство
*/
this.bufferService.pushPacketToBuffer("server", publicKey, newDevicePacket);
return;
}
/**
* Ставим метку аутентификации на клиента
*/
ECIAuthentificate eciTag = new ECIAuthentificate
(publicKey, privateKey, HandshakeStage.COMPLETED);
client.addTag(ECIAuthentificate.class, eciTag);
/**
* Вызываем событие завершения хэндшейка
*/
boolean cancelled = this.eventManager.callEvent(
new HandshakeCompletedEvent(publicKey, privateKey, device, eciTag, client)
);
if(cancelled) {
/**
* Событие было отменено, не даем завершить хэндшейк
*/
client.disconnect(Failures.DATA_MISSMATCH);
return;
}
/**
* Отправляем клиенту подтверждение успешного хэндшейка
*/
handshake.setHandshakeStage(HandshakeStage.COMPLETED);
handshake.setHeartbeatInterval(this.settings.heartbeatInterval);
client.send(handshake);
}
}