beautify locosocket...

This commit is contained in:
NetRiceCake
2025-12-06 21:09:14 +09:00
parent 8e737a688c
commit cdbfeff1f4
7 changed files with 73 additions and 57 deletions

View File

@@ -4,7 +4,7 @@ import com.github.netricecake.kakao.structs.ChatRoom;
import com.github.netricecake.kakao.structs.Member;
import com.github.netricecake.kakao.structs.Message;
import com.github.netricecake.loco.LocoPacket;
import com.github.netricecake.loco.LocoSocektHandler;
import com.github.netricecake.loco.LocoSocketHandler;
import com.github.netricecake.loco.packet.inbound.member.*;
import com.github.netricecake.loco.packet.inbound.message.MessageIn;
import com.github.netricecake.loco.packet.inbound.room.ChatInfoIn;
@@ -18,7 +18,7 @@ import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import lombok.Getter;
public class LocoSocketHandlerImpl extends LocoSocektHandler {
public class LocoSocketHandlerImpl extends LocoSocketHandler {
@Getter
private TalkClient client;

View File

@@ -3,7 +3,7 @@ package com.github.netricecake.kakao;
import com.github.netricecake.kakao.exception.*;
import com.github.netricecake.kakao.structs.ChatRoom;
import com.github.netricecake.loco.LocoPacket;
import com.github.netricecake.loco.LocoSocektHandler;
import com.github.netricecake.loco.LocoSocketHandler;
import com.github.netricecake.loco.LocoSocket;
import com.github.netricecake.loco.packet.inbound.login.CheckInIn;
import com.github.netricecake.loco.packet.inbound.login.GetConfIn;
@@ -90,7 +90,7 @@ public class TalkClient {
bookingData = KakaoApi.getBookingData(loginData.userId);
if (bookingData == null || bookingData.getStatus() != 0) throw new BookingFailedException();
LocoSocket checkInSocket = new LocoSocket(bookingData.getAddr(), bookingData.getPort(), new LocoSocektHandler() {
LocoSocket checkInSocket = new LocoSocket(bookingData.getAddr(), bookingData.getPort(), new LocoSocketHandler() {
@Override
public void onError(Exception e) {
e.printStackTrace();
@@ -181,7 +181,7 @@ public class TalkClient {
if (si.getStatus() != 0) return false;
final CompletableFuture<Integer> future = new CompletableFuture<>();
postSocket = new LocoSocket(si.getVhost(), si.getPort(), new LocoSocektHandler() {
postSocket = new LocoSocket(si.getVhost(), si.getPort(), new LocoSocketHandler() {
@Override
public void onPacket(LocoPacket packet) {
JsonObject jsonObject = BsonUtil.bsonToJsonObject(packet.getBody());

View File

@@ -21,11 +21,12 @@ import java.util.concurrent.*;
public class LocoSocket {
@Getter
private String ip;
private final String ip;
@Getter
private int port;
private final int port;
private CryptoManager cryptoManager;
@Getter
private final CryptoManager cryptoManager = new CryptoManager();;
private Channel channel;
private EventLoopGroup eventLoopGroup;
@@ -33,28 +34,24 @@ public class LocoSocket {
@Getter
private boolean alive = false;
@Getter
private Map<Integer, Future<LocoPacket>> waitList = new HashMap<>();
private final LocoSocketHandler locoSocektHandler;
@Getter
private LocoSocektHandler locoSocektHandler;
private final ExecutorService handlerPool;
@Getter
private ExecutorService handlerPool;
private final Map<Integer, Future<LocoPacket>> waitList = new HashMap<>();
private int packetIdCounter = 1000;
public LocoSocket(String ip, int port, LocoSocektHandler locoSocektHandler, ExecutorService handlerPool) {
public LocoSocket(String ip, int port, LocoSocketHandler locoSocektHandler, ExecutorService handlerPool) {
this.ip = ip;
this.port = port;
this.locoSocektHandler = locoSocektHandler;
this.handlerPool = handlerPool;
cryptoManager = new CryptoManager();
}
public void connect() throws IOException {
if (alive) throw new IOException("Already connected");
try {
byte[] handshakePacket = cryptoManager.generateHandshakeMessage();
eventLoopGroup = new MultiThreadIoEventLoopGroup(1, NioIoHandler.newFactory());
Bootstrap bootstrap = new Bootstrap();
bootstrap.remoteAddress(new InetSocketAddress(ip, port))
@@ -70,21 +67,17 @@ public class LocoSocket {
});
channel = bootstrap.connect().sync().channel();
alive = true;
channel.writeAndFlush(handshakePacket).sync();
channel.writeAndFlush(cryptoManager.generateHandshakeMessage()).sync();
channel.pipeline().addLast(new SecureLayerCodec(cryptoManager));
channel.pipeline().addLast(new LocoCodec(this));
handlerPool.execute(() -> {
locoSocektHandler.onConnect();
});
channel.pipeline().addLast(new LocoCodec(locoSocektHandler, handlerPool, waitList));
handlerPool.execute(locoSocektHandler::onConnect);
new Thread() {
@Override
public void run() {
try {
channel.closeFuture().sync();
eventLoopGroup.shutdownGracefully();
handlerPool.execute(() -> {
locoSocektHandler.onDisconnect();
});
handlerPool.execute(locoSocektHandler::onDisconnect);
alive = false;
} catch (Exception e) {
handlerPool.execute(() -> {
@@ -119,7 +112,9 @@ public class LocoSocket {
waitList.put(packetId, future);
channel.writeAndFlush(packet);
try {
return future.get();
LocoPacket result = future.get(5, TimeUnit.SECONDS);
waitList.remove(packetId);
return result;
} catch (Exception e) {
handlerPool.execute(() -> {
locoSocektHandler.onError(e);
@@ -135,6 +130,7 @@ public class LocoSocket {
});
eventLoopGroup.shutdownGracefully();
channel.close();
handlerPool.execute(locoSocektHandler::onDisconnect);
alive = false;
}

View File

@@ -0,0 +1,13 @@
package com.github.netricecake.loco;
public class LocoSocketHandler {
public void onPacket(LocoPacket packet) {}
public void onConnect() {}
public void onDisconnect() {}
public void onError(Exception e) {}
}

View File

@@ -1,24 +1,33 @@
package com.github.netricecake.loco.codec;
import com.github.netricecake.loco.LocoPacket;
import com.github.netricecake.loco.LocoSocket;
import com.github.netricecake.loco.LocoSocketHandler;
import com.github.netricecake.loco.util.BsonUtil;
import com.github.netricecake.loco.util.ByteUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageCodec;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
public class LocoCodec extends MessageToMessageCodec<byte[], LocoPacket> {
private LocoPacket currentLocoPacket = null;
private byte[] buffer = new byte[0];
private final LocoSocket locoSocket;
private final Map<Integer, Future<LocoPacket>> waitList;
public LocoCodec(LocoSocket locoSocekt) {
this.locoSocket = locoSocekt;
private final LocoSocketHandler locoSocektHandler;
private final ExecutorService handlerPool;
public LocoCodec(LocoSocketHandler locoSocektHandler, ExecutorService handlerPool, Map<Integer, Future<LocoPacket>> waitList) {
this.locoSocektHandler = locoSocektHandler;
this.handlerPool = handlerPool;
this.waitList = waitList;
}
@Override
@@ -59,17 +68,16 @@ public class LocoCodec extends MessageToMessageCodec<byte[], LocoPacket> {
}
if (currentLocoPacket.getBodyLength() > buffer.length) break;
byte[] body = ByteUtil.sliceBytes(buffer, 0, currentLocoPacket.getBodyLength());
System.out.println(currentLocoPacket.getMethod());
System.out.println(BsonUtil.bsonToJson(body));
//System.out.println(currentLocoPacket.getMethod());
//System.out.println(BsonUtil.bsonToJson(body));
buffer = ByteUtil.sliceBytes(buffer, currentLocoPacket.getBodyLength(), buffer.length - currentLocoPacket.getBodyLength());
currentLocoPacket.setBody(body);
if (locoSocket.getWaitList().containsKey(currentLocoPacket.getPacketId())) {
((CompletableFuture<LocoPacket>) locoSocket.getWaitList().get(currentLocoPacket.getPacketId())).complete(currentLocoPacket);
locoSocket.getWaitList().remove(currentLocoPacket.getPacketId());
if (waitList.containsKey(currentLocoPacket.getPacketId())) {
((CompletableFuture<LocoPacket>) waitList.get(currentLocoPacket.getPacketId())).complete(currentLocoPacket);
} else {
final LocoPacket p = currentLocoPacket;
locoSocket.getHandlerPool().execute(() -> {
locoSocket.getLocoSocektHandler().onPacket(p);
handlerPool.execute(() -> {
locoSocektHandler.onPacket(p);
});
}
currentLocoPacket = null;

View File

@@ -1,10 +1,12 @@
package com.github.netricecake.loco.crypto;
import com.github.netricecake.loco.util.ByteUtil;
import lombok.Getter;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.security.KeyFactory;
import java.security.PublicKey;
@@ -13,18 +15,23 @@ import java.security.spec.X509EncodedKeySpec;
public class CryptoManager {
public final static int HANDSHAKE_BODY_SIZE = 256; // ENCRYPTED KEY
public final static int HANDSHAKE_BODY_SIZE = 256;
// Key share(RSA ES) spec
public final static String RSA_ALGORITHM = "RSA/ECB/OAEPWithSHA-1AndMGF1Padding";
public final static int RSA_LOCO_HEADER = 16;
public final static byte[] RSA_PUBLIC_KEY_BYTES = ByteUtil.hexStringToByteArray("30820120300D06092A864886F70D01010105000382010D00308201080282010100A3B076E8C445851F19A670C231AAC6DB42EFD09717D06048A5CC56906CD1AB27B9DF37FFD5017E7C13A1405B5D1C3E4879A6A499D3C618A72472B0B50CA5EF1EF6EEA70369D9413FE662D8E2B479A9F72142EE70CEE6C2AD12045D52B25C4A204A28968E37F0BA6A49EE3EC9F2AC7A65184160F22F62C43A4067CD8D2A6F13D9B8298AB002763D236C9D1879D7FCE5B8FA910882B21E15247E0D0A24791308E51983614402E9FA03057C57E9E178B1CC39FE67288EFC461945CBCAA11D1FCC123E750B861F0D447EBE3C115F411A42DC95DDB21DA42774A5BCB1DDF7FA5F10628010C74F36F31C40EFCFE289FD81BABA44A6556A6C301210414B6023C3F46371020103");
// AES spec
public final static String AES_ALGORITHM = "AES/GCM/NoPadding";
public final static int AES_KEY_SIZE = 128;
public final static int AES_NONCE_SIZE = 12;
public final static int AES_LOCO_HEADER = 3;
@Getter
private Key aesKey;
// nonce(iv) generator
private final SecureRandom generator = new SecureRandom();
public CryptoManager() {
@@ -32,13 +39,11 @@ public class CryptoManager {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(AES_KEY_SIZE);
aesKey = keyGenerator.generateKey();
} catch (Exception e) {
e.printStackTrace();
}
} catch (Exception e) {}
}
public CryptoManager(Key aesKey) {
this.aesKey = aesKey;
public CryptoManager(byte[] key) {
this.aesKey = new SecretKeySpec(key, "AES");
}
public byte[] generateHandshakeMessage() {
@@ -49,24 +54,19 @@ public class CryptoManager {
byte[] encryptedKey = cipher.doFinal(aesKey.getEncoded());
byte[] length = ByteUtil.intToByteArrayLE(HANDSHAKE_BODY_SIZE);
return ByteUtil.concatBytes(length, ByteUtil.intToByteArrayLE(RSA_LOCO_HEADER), ByteUtil.intToByteArrayLE(AES_LOCO_HEADER), encryptedKey);
} catch (Exception e) {
e.printStackTrace();
}
} catch (Exception e) {}
return new byte[0];
}
// 바디 사이즈가 131067가 최대인거 같은데 잘 모르겠음
public byte[] encryptMessage(byte[] message) {
try {
byte[] nonce = new byte[AES_NONCE_SIZE];
byte[] nonce = new byte[AES_NONCE_SIZE];
generator.nextBytes(nonce);
Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, aesKey, new GCMParameterSpec(AES_KEY_SIZE, nonce));
byte[] encryptedBody = cipher.doFinal(message);
return ByteUtil.concatBytes(nonce, encryptedBody);
} catch (Exception e) {
e.printStackTrace();
}
return ByteUtil.concatBytes(nonce, cipher.doFinal(message));
} catch (Exception e) {}
return new byte[0];
}
@@ -76,9 +76,7 @@ public class CryptoManager {
Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, aesKey, new GCMParameterSpec(AES_KEY_SIZE, nonce));
return cipher.doFinal(ByteUtil.sliceBytes(message, AES_NONCE_SIZE, message.length - nonce.length));
} catch (Exception e) {
e.printStackTrace();
}
} catch (Exception e) {}
return new byte[0];
}

View File

@@ -4,6 +4,7 @@ import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.bson.BsonBinaryReader;
import org.bson.BsonDocument;
import org.bson.RawBsonDocument;
import org.bson.codecs.BsonDocumentCodec;
import org.bson.codecs.DecoderContext;
@@ -16,7 +17,7 @@ public class BsonUtil {
private final static Gson gson = new Gson();
public static byte[] jsonToBson(String json) {
var rawBson = RawBsonDocument.parse(json);
RawBsonDocument rawBson = RawBsonDocument.parse(json);
ByteBuffer buffer = rawBson.getByteBuffer().asNIO();
byte[] exactBytes = new byte[buffer.remaining()];
buffer.get(exactBytes);
@@ -28,7 +29,7 @@ public class BsonUtil {
}
public static String bsonToJson(byte[] bson) {
var doc = bsonDocumentCodec.decode(
BsonDocument doc = bsonDocumentCodec.decode(
new BsonBinaryReader(ByteBuffer.wrap(bson)),
DecoderContext.builder().build()
);