231 lines
10 KiB
Java
231 lines
10 KiB
Java
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);
|
||
}
|
||
|
||
}
|