beautify locosocket...
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user