diff --git a/.gitignore b/.gitignore
index af665ab..935d2bb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,9 @@
target/
!.mvn/wrapper/maven-wrapper.jar
+.mvn
!**/src/main/**/target/
!**/src/test/**/target/
+.kotlin
### IntelliJ IDEA ###
.idea/modules.xml
@@ -35,4 +37,4 @@ build/
.vscode/
### Mac OS ###
-.DS_Store
+.DS_Store
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
deleted file mode 100644
index 94a25f7..0000000
--- a/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/README.md b/README.md
index 97f1bc8..135000d 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,66 @@
-# Loco wrapper
+# loco-wrapper
-테스트 해볼거면 본계정 쓰지마세요. 영정먹을 수 있음
+안드로이드 카카오톡 25.9.2 기반 비공식 카카오톡 클라이언트 (태블릿 서브 디바이스 로그인)
-
+현재 오픈 채팅방에서만 작동합니다.
+
+절대 본계정으로 돌려보지마세요.
+
+## Example
+
+
+
+Main.java 파일 참고
+```java
+TalkClient client = new TalkClient(email, password, deviceName, deviceUuid, new TalkHandler() {
+ @Override
+ public void onMessage(Message msg) {
+ if (msg.getType() != 1) return; // 1이 그냥 채팅, 그냥 채팅만 받기
+ if (msg.getMessage().equals("!send")) {
+ getTalkClient().sendMessage(msg.getChatRoom(), "test");
+ }
+ else if (msg.getMessage().equals("!reply")) { // 답장
+ int replyType = 26; // 답장 타입
+ JsonObject extraObject = new JsonObject();
+ extraObject.addProperty("src_logId", msg.getLogId());
+ extraObject.addProperty("src_userId", msg.getAuthor().getId());
+ extraObject.addProperty("src_message", msg.getMessage());
+ extraObject.addProperty("src_type", msg.getType());
+ extraObject.addProperty("src_linkId", msg.getChatRoom().getLinkId());
+ getTalkClient().sendMessage(msg.getChatRoom(), replyType, "reply test", extraObject.toString());
+ }
+ else if (msg.getMessage().equals("!mention")) { // 멘션
+ JsonObject extraObject = new JsonObject();
+ JsonArray mentionArray = new JsonArray();
+ JsonObject mentionObject = new JsonObject();
+ mentionObject.addProperty("user_id", msg.getAuthor().getId());
+ JsonArray pos = new JsonArray();
+ pos.add(1);
+ mentionObject.add("at", pos);
+ mentionObject.addProperty("len", msg.getAuthor().getName().length());
+ mentionArray.add(mentionObject);
+ extraObject.add("mentions", mentionArray);
+ getTalkClient().sendMessage(msg.getChatRoom(), 1, "@" + msg.getAuthor().getName(), extraObject.toString());
+ }
+ }
+
+ @Override
+ public void onNewMember(ChatRoom room, Member member) {
+ getTalkClient().sendMessage(room, member.getName() + "님이 들어왔습니다.");
+ }
+
+ @Override
+ public void onDelMember(ChatRoom room, Member member) {
+ getTalkClient().sendMessage(room, member.getName() + "님이 나갔습니다.");
+ }
+ });
+client.connect();
+```
+
+## Usage
+
+첫 로그인시에 기기등록이 필요합니다. 콘솔창에 방법 나오니 따라하세요.
+
+로그인하면 로그인 정보(토큰 등)가 email_deviceName 폴더 안에 저장됩니다. 서버 연결이 안되면 삭제하고 시도하세요.
+
+**device uuid 무조건 바꾸시오.**
diff --git a/dependency-reduced-pom.xml b/dependency-reduced-pom.xml
deleted file mode 100644
index 16def58..0000000
--- a/dependency-reduced-pom.xml
+++ /dev/null
@@ -1,56 +0,0 @@
-
-
- 4.0.0
- com.github.netricecake
- loco-wrapper
- 1.0-SNAPSHOT
-
-
-
- maven-shade-plugin
- 3.4.1
-
-
- package
-
- shade
-
-
-
-
- com.github.netricecake.Main
-
-
-
-
- *:*
-
- META-INF/*.SF
- META-INF/*.DSA
- META-INF/*.RSA
-
-
-
-
-
-
-
-
-
-
-
-
- com.squareup.okhttp3
- okhttp-bom
- 5.2.0
- pom
- import
-
-
-
-
- 21
- 21
- UTF-8
-
-
diff --git a/ex.png b/ex.png
new file mode 100644
index 0000000..e822ddb
Binary files /dev/null and b/ex.png differ
diff --git a/pom.xml b/pom.xml
index f13d59e..b928e87 100644
--- a/pom.xml
+++ b/pom.xml
@@ -80,6 +80,7 @@
org.projectlombok
lombok
1.18.42
+ provided
org.mongodb
@@ -88,4 +89,4 @@
-
+
\ No newline at end of file
diff --git a/src/main/java/com/github/netricecake/KakaoTalkClient.java b/src/main/java/com/github/netricecake/KakaoTalkClient.java
deleted file mode 100644
index d9d33b1..0000000
--- a/src/main/java/com/github/netricecake/KakaoTalkClient.java
+++ /dev/null
@@ -1,89 +0,0 @@
-package com.github.netricecake;
-
-import com.github.netricecake.kakao.KakaoDefaultValues;
-import com.github.netricecake.message.request.*;
-import com.github.netricecake.message.response.CheckInResponse;
-import com.github.netricecake.message.response.GetConfResponse;
-import com.github.netricecake.message.response.MessageResponse;
-import com.github.netricecake.network.LocoPacket;
-import com.github.netricecake.network.LocoSocket;
-import com.github.netricecake.util.BsonUtil;
-
-import java.io.IOException;
-import java.security.InvalidParameterException;
-import java.util.Map;
-import java.util.concurrent.CompletableFuture;
-
-public class KakaoTalkClient {
-
- private final static String DEFAULT_MCCMNC = KakaoDefaultValues.MCCMNC;
-
- private KakaoApi.LoginData loginData;
- private GetConfResponse bookingData;
- private CheckInResponse checkInData;
-
- LocoSocket socket;
-
- public void login(String email, String password, String deviceName, String deviceUuid) throws Exception, IOException, InvalidParameterException, IllegalStateException {
- try {
- loginData = KakaoApi.loginRequest(email, password, deviceName, deviceUuid);
- } catch (IllegalStateException e) {
- Map.Entry registerInfo = KakaoApi.generatePasscode(email, password, deviceName, deviceUuid);
- System.out.println("디바이스 등록이 필요합니다.");
- System.out.println("카카오톡에서 " + registerInfo.getValue() + "초 안에 코드를 입력해주세요. 코드 : " + registerInfo.getKey());
- boolean registerResult = KakaoApi.registerDevice(email, password, deviceUuid);
- if (!registerResult) throw new IllegalStateException("기기 등록 실패");
- System.out.println("기기 등록 성공");
- loginData = KakaoApi.loginRequest(email, password, deviceName, deviceUuid);
- }
- System.out.println("로그인 성공");
-
- bookingData = KakaoApi.getBookingData(DEFAULT_MCCMNC, loginData.userId);
-
- LocoSocket checkInSocket = new LocoSocket(bookingData.getAddr(), bookingData.getPort());
-
- try {
- CheckInRequest checkInRequest = new CheckInRequest();
- checkInRequest.setUserId(loginData.userId);
- byte[] body = checkInRequest.toBson();
- checkInSocket.connect();
- checkInSocket.write(new LocoPacket(1001, checkInRequest.getMethod(), body));
- checkInData = new CheckInResponse();
- checkInData.fromBson(checkInSocket.read().getBody());
- checkInSocket.close();
- } catch (Exception e) {
- System.out.println("오류 : " + e.getMessage());
- }
-
- socket = new LocoSocket(checkInData.getHost(), checkInData.getPort());
- socket.connect();
- LoginListRequest req = new LoginListRequest();
- req.setDuuid(deviceUuid);
- req.setOauthToken(loginData.accessToken);
- socket.write(new LocoPacket(1002, "LOGINLIST", req.toBson()));
- }
-
- public void test() throws Exception {
- while(true) {
- LocoPacket packet = socket.read();
- if (packet == null) continue;
- if (!packet.getMethod().equals("MSG")) continue;
-
- socket.write(new LocoPacket(packet.getPacketId(), "MSG", new MessageRequest().toBson()));
- MessageResponse res = new MessageResponse();
- res.fromBson(packet.getBody());
- if (res.getType() != 1) return;
- if (res.getMessage().trim().equals("!!test")) {
- WriteRequest req = new WriteRequest();
- req.setChatId(res.getChatId());
- req.setMessage("test!!");
- socket.write(new LocoPacket(1003, "WRITE", req.toBson()));
- LocoPacket t = socket.read();
- System.out.println(BsonUtil.bsonToJson(t.getBody()));
- System.exit(0);
- }
-
- }
- }
-
-}
diff --git a/src/main/java/com/github/netricecake/Main.java b/src/main/java/com/github/netricecake/Main.java
index 63b0821..5d7e8e6 100644
--- a/src/main/java/com/github/netricecake/Main.java
+++ b/src/main/java/com/github/netricecake/Main.java
@@ -1,22 +1,65 @@
package com.github.netricecake;
-import com.github.netricecake.util.ByteUtil;
-
-import java.security.SecureRandom;
+import com.github.netricecake.kakao.TalkClient;
+import com.github.netricecake.kakao.TalkHandler;
+import com.github.netricecake.kakao.structs.ChatRoom;
+import com.github.netricecake.kakao.structs.Member;
+import com.github.netricecake.kakao.structs.Message;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+//TIP 코드를 실행하려면 을(를) 누르거나
+// 에디터 여백에 있는 아이콘을 클릭하세요.
public class Main {
- static String EMAIL = "";
- static String PASSWORD = "";
- static String DEVICE_NAME = "SM-X930"; // 갤럭시 탭 s11 울트라
+ static String email = "invalid@example.com";
+ static String password = "example";
+ static String deviceName = "SM-X930"; // 갤럭시 탭 s11 울트라, 지원되는 태블릿 모델명 넣으세요
+ static String deviceUuid = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"; // 64자 랜덤 hex-string
public static void main(String[] args) throws Exception {
- byte[] uuid = new byte[32];
- new SecureRandom().nextBytes(uuid);
- String deviceUuid = ByteUtil.byteArrayToHexString(uuid);
- KakaoTalkClient client = new KakaoTalkClient();
- client.login(EMAIL, PASSWORD, DEVICE_NAME, deviceUuid);
- client.test();
- }
+ TalkClient client = new TalkClient(email, password, deviceName, deviceUuid, new TalkHandler() {
+ @Override
+ public void onMessage(Message msg) {
+ if (msg.getType() != 1) return; // 1이 그냥 채팅, 그냥 채팅만 받기
+ if (msg.getMessage().equals("!send")) {
+ getTalkClient().sendMessage(msg.getChatRoom(), "test");
+ }
+ else if (msg.getMessage().equals("!reply")) { // 답장
+ int replyType = 26; // 답장 타입
+ JsonObject extraObject = new JsonObject();
+ extraObject.addProperty("src_logId", msg.getLogId());
+ extraObject.addProperty("src_userId", msg.getAuthor().getId());
+ extraObject.addProperty("src_message", msg.getMessage());
+ extraObject.addProperty("src_type", msg.getType());
+ extraObject.addProperty("src_linkId", msg.getChatRoom().getLinkId());
+ getTalkClient().sendMessage(msg.getChatRoom(), replyType, "reply test", extraObject.toString());
+ }
+ else if (msg.getMessage().equals("!mention")) { // 멘션
+ JsonObject extraObject = new JsonObject();
+ JsonArray mentionArray = new JsonArray();
+ JsonObject mentionObject = new JsonObject();
+ mentionObject.addProperty("user_id", msg.getAuthor().getId());
+ JsonArray pos = new JsonArray();
+ pos.add(1);
+ mentionObject.add("at", pos);
+ mentionObject.addProperty("len", msg.getAuthor().getName().length());
+ mentionArray.add(mentionObject);
+ extraObject.add("mentions", mentionArray);
+ getTalkClient().sendMessage(msg.getChatRoom(), 1, "@" + msg.getAuthor().getName(), extraObject.toString());
+ }
+ }
+ @Override
+ public void onNewMember(ChatRoom room, Member member) {
+ getTalkClient().sendMessage(room, member.getName() + "님이 들어왔습니다.");
+ }
+
+ @Override
+ public void onDelMember(ChatRoom room, Member member) {
+ getTalkClient().sendMessage(room, member.getName() + "님이 나갔습니다.");
+ }
+ });
+ client.connect();
+ }
}
diff --git a/src/main/java/com/github/netricecake/KakaoApi.java b/src/main/java/com/github/netricecake/kakao/KakaoApi.java
similarity index 77%
rename from src/main/java/com/github/netricecake/KakaoApi.java
rename to src/main/java/com/github/netricecake/kakao/KakaoApi.java
index f6d088e..bf036f7 100644
--- a/src/main/java/com/github/netricecake/KakaoApi.java
+++ b/src/main/java/com/github/netricecake/kakao/KakaoApi.java
@@ -1,8 +1,8 @@
-package com.github.netricecake;
+package com.github.netricecake.kakao;
-import com.github.netricecake.message.request.GetConfRequest;
-import com.github.netricecake.message.response.GetConfResponse;
-import com.github.netricecake.util.ByteUtil;
+import com.github.netricecake.loco.packet.inbound.GetConfIn;
+import com.github.netricecake.loco.packet.outbound.GetConfOut;
+import com.github.netricecake.loco.util.ByteUtil;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
@@ -10,11 +10,9 @@ import okhttp3.*;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
-import javax.security.auth.login.AccountException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.nio.charset.StandardCharsets;
import java.security.InvalidParameterException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
@@ -22,6 +20,17 @@ import java.util.Map;
public class KakaoApi {
+
+ public final static String AGENT = "android";
+ public final static String VERSION = "25.9.2";
+ public final static String OS_VERSION = "13";
+ public final static String API_LEVEL = "33";
+ public final static String LANGUAGE = "ko";
+
+ public final static String PROTOCOL_VERSION = "1";
+ public final static int NETWORK_TYPE = 0; // 0 : WIFI, 3: Cellular
+ public final static String MCCMNC = "45006"; // 앞자리 세자리(한국) 450 고정, 뒤에 두자리 SKT: 05 KT: 08 LGU+: 06
+
public final static String ALLOW_LIST_URL = "https://katalk.kakao.com/android/account/allowlist.json";
public final static String LOGIN_URL = "https://katalk.kakao.com/android/account/login.json";
public final static String PASSCODE_GENERATE_URL = "https://katalk.kakao.com/android/account/passcodeLogin/generate";
@@ -30,11 +39,6 @@ public class KakaoApi {
public final static String BOOKING_URL = "booking-loco.kakao.com";
public final static int BOOKING_PORT = 443;
- public final static String AGENT = "android";
- public final static String VERSION = "25.9.2";
- public final static String OS_VERSION = "13";
- public final static String API_LEVEL = "33";
- public final static String LANGUAGE = "ko";
public final static String AUTH_USER_AGENT = String.format("KT/%s An/%s %s", VERSION, OS_VERSION, LANGUAGE);
public final static String AUTH_HEADER_AGENT = String.format("%s/%s/%s", AGENT, VERSION, LANGUAGE);
@@ -69,10 +73,10 @@ public class KakaoApi {
if (status == 0) {
LoginData data = new LoginData();
- data.userId = jsonObject.get("userId").getAsInt();
+ data.userId = jsonObject.get("userId").getAsLong();
data.countryIso = jsonObject.get("countryIso").getAsString();
data.countryCode = jsonObject.get("countryCode").getAsString();
- data.accountId = jsonObject.get("accountId").getAsInt();
+ data.accountId = jsonObject.get("accountId").getAsLong();
data.accessToken = jsonObject.get("access_token").getAsString();
data.refreshToken = jsonObject.get("refresh_token").getAsString();
data.tokenType = jsonObject.get("token_type").getAsString();
@@ -133,11 +137,11 @@ public class KakaoApi {
return false;
}
- public static GetConfResponse getBookingData(String MCCMNC, int userId) {
+ public static GetConfIn getBookingData(long userId) {
byte[] id = ByteUtil.intToByteArrayLE(1000);
byte[] method = new byte[11];
System.arraycopy("GETCONF".getBytes(), 0, method, 0, 7);
- byte[] b = new GetConfRequest(MCCMNC, AGENT, userId).toBson();
+ byte[] b = new GetConfOut(MCCMNC, AGENT, userId).toBson();
byte[] m = ByteUtil.concatBytes(id, new byte[2], method, new byte[1], ByteUtil.intToByteArrayLE(b.length), b);
try {
SSLSocketFactory socketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
@@ -154,7 +158,7 @@ public class KakaoApi {
reader.read(res);
int len = ByteUtil.byteArrayToIntLE(ByteUtil.sliceBytes(res, 18, 4));
- GetConfResponse r = new GetConfResponse();
+ GetConfIn r = new GetConfIn();
r.fromBson(ByteUtil.sliceBytes(res, 22, len));
socket.close();
@@ -201,10 +205,10 @@ public class KakaoApi {
}
public static class LoginData {
- public int userId;
+ public long userId;
public String countryIso;
public String countryCode;
- public int accountId;
+ public long accountId;
public String accessToken;
public String refreshToken;
public String tokenType;
@@ -213,6 +217,40 @@ public class KakaoApi {
public String mainDeviceAgentName;
public String mainDeviceAppVersion;
public String recipe;
+
+ public void fromJson(String json) {
+ JsonObject jsonObject = JsonParser.parseString(json).getAsJsonObject();
+ userId = jsonObject.get("userId").getAsLong();
+ countryIso = jsonObject.get("countryIso").getAsString();
+ countryCode = jsonObject.get("countryCode").getAsString();
+ accountId = jsonObject.get("accountId").getAsLong();
+ accessToken = jsonObject.get("access_token").getAsString();
+ refreshToken = jsonObject.get("refresh_token").getAsString();
+ tokenType = jsonObject.get("token_type").getAsString();
+ autoLoginAccountId = jsonObject.get("autoLoginAccountId").getAsString();
+ displayAccountId = jsonObject.get("displayAccountId").getAsString();
+ mainDeviceAgentName = jsonObject.get("mainDeviceAgentName").getAsString();
+ mainDeviceAppVersion = jsonObject.get("mainDeviceAppVersion").getAsString();
+ recipe = jsonObject.get("recipe").getAsString();
+ }
+
+ public String toJson() {
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.addProperty("userId", userId);
+ jsonObject.addProperty("countryIso", countryIso);
+ jsonObject.addProperty("countryCode", countryCode);
+ jsonObject.addProperty("accountId", accountId);
+ jsonObject.addProperty("access_token", accessToken);
+ jsonObject.addProperty("refresh_token", refreshToken);
+ jsonObject.addProperty("token_type", tokenType);
+ jsonObject.addProperty("autoLoginAccountId", autoLoginAccountId);
+ jsonObject.addProperty("displayAccountId", displayAccountId);
+ jsonObject.addProperty("mainDeviceAgentName", mainDeviceAgentName);
+ jsonObject.addProperty("mainDeviceAppVersion", mainDeviceAppVersion);
+ jsonObject.addProperty("recipe", recipe);
+
+ return gson.toJson(jsonObject);
+ }
}
}
diff --git a/src/main/java/com/github/netricecake/kakao/KakaoDefaultValues.java b/src/main/java/com/github/netricecake/kakao/KakaoDefaultValues.java
deleted file mode 100644
index 783d2ea..0000000
--- a/src/main/java/com/github/netricecake/kakao/KakaoDefaultValues.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package com.github.netricecake.kakao;
-
-public class KakaoDefaultValues {
-
- public final static String MCCMNC = "45006";
- public final static int ntype = 0;
- public final static String os = "android";
-
-}
diff --git a/src/main/java/com/github/netricecake/kakao/LocoSocketHandlerImpl.java b/src/main/java/com/github/netricecake/kakao/LocoSocketHandlerImpl.java
new file mode 100644
index 0000000..724758b
--- /dev/null
+++ b/src/main/java/com/github/netricecake/kakao/LocoSocketHandlerImpl.java
@@ -0,0 +1,89 @@
+package com.github.netricecake.kakao;
+
+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.packet.inbound.*;
+import com.github.netricecake.loco.packet.outbound.ChatInfoOut;
+import com.github.netricecake.loco.packet.outbound.InfoLinkOut;
+import com.github.netricecake.loco.packet.outbound.MessageOut;
+import lombok.Getter;
+
+public class LocoSocketHandlerImpl implements LocoSocektHandler {
+
+ @Getter
+ private TalkClient client;
+
+ public LocoSocketHandlerImpl(TalkClient client) {
+ this.client = client;
+ }
+
+ @Override
+ public void onPacket(LocoPacket packet) {
+ if (packet.getMethod().equals("MSG")) {
+ client.getSocket().write(new LocoPacket(packet.getPacketId(), "MSG", new MessageOut().toBson()));
+
+ MessageIn in = new MessageIn();
+ in.fromBson(packet.getBody());
+ checkRoom(in.getChatId());
+
+ ChatRoom room = client.getChatRooms().get(in.getChatId());
+ if (!room.getType().equals("OM")) return;
+ Message msg = new Message(in.getLogId(), room, new Member(in.getAuthorId(), in.getAuthorNickname()), in.getType(), in.getMessage(), in.getAttachment());
+ client.getTalkHandler().onMessage(msg);
+ } else if (packet.getMethod().equals("NEWMEM")) {
+ NewMemIn in = new NewMemIn();
+ in.fromBson(packet.getBody());
+ checkRoom(in.getChatId());
+
+ ChatRoom room = client.getChatRooms().get(in.getChatId());
+ if (!room.getType().equals("OM")) return;
+ client.getTalkHandler().onNewMember(room, new Member(in.getUserId(), in.getNickname()));
+ } else if (packet.getMethod().equals("DELMEM")) {
+ DelMemIn in = new DelMemIn();
+ in.fromBson(packet.getBody());
+ checkRoom(in.getChatId());
+
+ ChatRoom room = client.getChatRooms().get(in.getChatId());
+ if (!room.getType().equals("OM")) return;
+ client.getTalkHandler().onDelMember(room, new Member(in.getUserId(), in.getNickname()));
+ }
+ }
+
+ private void checkRoom(long chatId) {
+ if (!client.getChatRooms().containsKey(chatId)) {
+ ChatInfoOut co = new ChatInfoOut(chatId);
+ ChatInfoIn ci = new ChatInfoIn();
+ ci.fromBson(client.getSocket().writeAndRead(new LocoPacket("CHATINFO", co.toBson())).getBody());
+ ChatRoom room = new ChatRoom();
+ room.setChatId(chatId);
+ room.setType(ci.getType());
+ room.setLinkId(ci.getLinkId());
+ if (ci.getType().equals("OM")) {
+ InfoLinkOut lo = new InfoLinkOut(ci.getLinkId());
+ InfoLinkIn li = new InfoLinkIn();
+ li.fromBson(client.getSocket().writeAndRead(new LocoPacket("INFOLINK", lo.toBson())).getBody());
+ room.setName(li.getName());
+ }
+
+ client.getChatRooms().put(chatId, room);
+ }
+ }
+
+ @Override
+ public void onConnect() {
+
+ }
+
+ @Override
+ public void onDisconnect() {
+
+ }
+
+ @Override
+ public void onError(Exception e) {
+
+ }
+}
diff --git a/src/main/java/com/github/netricecake/kakao/TalkClient.java b/src/main/java/com/github/netricecake/kakao/TalkClient.java
new file mode 100644
index 0000000..d78f530
--- /dev/null
+++ b/src/main/java/com/github/netricecake/kakao/TalkClient.java
@@ -0,0 +1,222 @@
+package com.github.netricecake.kakao;
+
+import com.github.netricecake.kakao.structs.ChatRoom;
+import com.github.netricecake.loco.LocoPacket;
+import com.github.netricecake.loco.LocoSocektHandler;
+import com.github.netricecake.loco.LocoSocket;
+import com.github.netricecake.loco.packet.inbound.CheckInIn;
+import com.github.netricecake.loco.packet.inbound.GetConfIn;
+import com.github.netricecake.loco.packet.inbound.LoginListIn;
+import com.github.netricecake.loco.packet.inbound.WriteIn;
+import com.github.netricecake.loco.packet.outbound.CheckInOut;
+import com.github.netricecake.loco.packet.outbound.LoginListOut;
+import com.github.netricecake.loco.packet.outbound.PingOut;
+import com.github.netricecake.loco.packet.outbound.WriteOut;
+import com.github.netricecake.loco.util.ByteUtil;
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import lombok.Getter;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public class TalkClient {
+
+ private String email;
+ private String password;
+ private String deviceName;
+ private String deviceUuid;
+ private String sessionDir;
+
+ @Getter
+ private Map chatRooms = new HashMap<>();
+
+ @Getter
+ private boolean connected;
+
+ private KakaoApi.LoginData loginData;
+ private GetConfIn bookingData;
+ private CheckInIn checkInData;
+ private LoginListIn loginListData;
+
+ private ExecutorService locoHandlerPool;
+
+ @Getter
+ private TalkHandler talkHandler;
+
+ @Getter
+ private LocoSocket socket;
+
+ public TalkClient(String email, String password, String deviceName, String deviceUuid, TalkHandler talkHandler) {
+ this.email = email;
+ this.password = password;
+ this.deviceName = deviceName;
+ this.deviceUuid = deviceUuid;
+ this.sessionDir = System.getProperty("user.dir") + "/" + email + "_" + deviceName + "/";
+ this.talkHandler = talkHandler;
+ talkHandler.setTalkClient(this);
+
+ new File(sessionDir).mkdir();
+ loginData = readLoginData();
+ }
+
+ public void connect() throws Exception {
+ if (this.connected) throw new Exception("이미 연결되어 있습니다.");
+ if (loginData == null) {
+ System.out.println("로그인 데이터가 없습니다. 새로 로그인을 시도합니다.");
+ try {
+ loginData = KakaoApi.loginRequest(email, password, deviceName, deviceUuid);
+ } catch (IllegalStateException e) {
+ Map.Entry registerInfo = KakaoApi.generatePasscode(email, password, deviceName, deviceUuid);
+ System.out.println("기기 등록이 필요합니다.");
+ System.out.println("카카오톡 앱에서 " + registerInfo.getValue() + "초 안에 코드를 입력해주세요. 코드 : " + registerInfo.getKey());
+ boolean registerResult = KakaoApi.registerDevice(email, password, deviceUuid);
+ if (!registerResult) throw new IllegalStateException("기기등록 실패");
+ System.out.println("기기 등록 성공");
+ loginData = KakaoApi.loginRequest(email, password, deviceName, deviceUuid);
+ }
+ System.out.println("로그인이 완료되었습니다.");
+ writeLoginData();
+ }
+
+ bookingData = KakaoApi.getBookingData(loginData.userId);
+
+ LocoSocket checkInSocket = new LocoSocket(bookingData.getAddr(), bookingData.getPort(), new LocoSocektHandler() {
+ @Override
+ public void onPacket(LocoPacket packet) {
+
+ }
+
+ @Override
+ public void onConnect() {
+
+ }
+
+ @Override
+ public void onDisconnect() {
+
+ }
+
+ @Override
+ public void onError(Exception e) {
+ e.printStackTrace();
+ }
+ }, Executors.newFixedThreadPool(1));
+ CheckInOut checkInRequest = new CheckInOut(loginData.userId);
+ byte[] body = checkInRequest.toBson();
+ checkInSocket.connect();
+ LocoPacket checkinResponse = checkInSocket.writeAndRead(new LocoPacket(1000, checkInRequest.getMethod(), body));
+ checkInData = new CheckInIn();
+ checkInData.fromBson(checkinResponse.getBody());
+ checkInSocket.close();
+
+
+
+ long lastTokenId = 0;
+ long lbk = 0;
+ byte[] rp = ByteUtil.hexStringToByteArray("0000ffff0000");
+
+ try {
+ File loginListDataFile = new File(sessionDir + "loginListData.json");
+ if (loginListDataFile.exists()) {
+ String loginDataJson = Files.readString(Paths.get(loginListDataFile.getAbsolutePath()));
+ JsonObject loginListData = JsonParser.parseString(loginDataJson).getAsJsonObject();
+ lastTokenId = loginListData.getAsJsonPrimitive("lastTokenId").getAsLong();
+ lbk = loginListData.getAsJsonPrimitive("lbk").getAsLong();
+ rp = ByteUtil.hexStringToByteArray("0100ffff0100"); // 이게 도당체 뭐임
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ locoHandlerPool = Executors.newFixedThreadPool(1);
+
+ socket = new LocoSocket(checkInData.getHost(), checkInData.getPort(), new LocoSocketHandlerImpl(this), locoHandlerPool);
+ socket.connect();
+ LoginListOut req = new LoginListOut();
+ req.setDuuid(deviceUuid);
+ req.setOauthToken(loginData.accessToken);
+ req.setLastTokenId(lastTokenId);
+ req.setLbk(lbk);
+ req.setRp(rp);
+ loginListData = new LoginListIn();
+ loginListData.fromBson(socket.writeAndRead(new LocoPacket("LOGINLIST", req.toBson())).getBody());
+ if (loginListData.getStatus() != 0) {
+ System.out.println("카카오톡 서버와 연결을 실패했습니다. 로그인 정보 파일을 삭제 후 다시 시도해보세요.");
+ throw new Exception("카카오톡 서버와 연결을 실패했습니다. 로그인 정보 파일을 삭제 후 다시 시도해보세요.");
+ }
+ System.out.println("연결 성공");
+
+ try {
+ File loginListDataFile = new File(sessionDir + "loginListData.json");
+ if (!loginListDataFile.exists()) loginListDataFile.createNewFile();
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.addProperty("lastTokenId", loginListData.getLastTokenId());
+ jsonObject.addProperty("lbk", loginListData.getLbk());
+ Files.write(Paths.get(loginListDataFile.getAbsolutePath()), new Gson().toJson(jsonObject).getBytes());
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ new Thread(() -> {
+ try {
+ while (socket.isAlive()) {
+ Thread.sleep(10 * 60 * 1000);
+ PingOut pingOut = new PingOut();
+ LocoPacket pingPacket = new LocoPacket("PING", pingOut.toBson());
+ socket.write(pingPacket);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ });
+ }
+
+ private KakaoApi.LoginData readLoginData() {
+ try {
+ File loginDataFile = new File(sessionDir + "loginData.json");
+ if (!loginDataFile.exists()) return null;
+ String loginDataJson = Files.readString(Paths.get(loginDataFile.getAbsolutePath()));
+ KakaoApi.LoginData loginData = new KakaoApi.LoginData();
+ loginData.fromJson(loginDataJson);
+ return loginData;
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ return null;
+ }
+
+ private void writeLoginData() {
+ try {
+ File loginDataFile = new File(sessionDir + "loginData.json");
+ if (!loginDataFile.exists()) loginDataFile.createNewFile();
+ Files.write(Paths.get(loginDataFile.getAbsolutePath()), loginData.toJson().getBytes());
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public boolean sendMessage(ChatRoom room, int type, String message, String extra) {
+ WriteOut wo = new WriteOut();
+ wo.setChatId(room.getChatId());
+ wo.setType(type);
+ wo.setMessage(message);
+ wo.setExtra(extra);
+ WriteIn wi = new WriteIn();
+ wi.fromBson(socket.writeAndRead(new LocoPacket("WRITE", wo.toBson())).getBody());
+ return wi.getStatus() == 0;
+ }
+
+ public boolean sendMessage(ChatRoom room, String message) {
+ return sendMessage(room, 1, message, "{}");
+ }
+
+}
diff --git a/src/main/java/com/github/netricecake/kakao/TalkHandler.java b/src/main/java/com/github/netricecake/kakao/TalkHandler.java
new file mode 100644
index 0000000..3be6ab7
--- /dev/null
+++ b/src/main/java/com/github/netricecake/kakao/TalkHandler.java
@@ -0,0 +1,27 @@
+package com.github.netricecake.kakao;
+
+import com.github.netricecake.kakao.structs.ChatRoom;
+import com.github.netricecake.kakao.structs.Member;
+import com.github.netricecake.kakao.structs.Message;
+import lombok.Getter;
+import lombok.Setter;
+
+public class TalkHandler {
+
+ @Getter
+ @Setter
+ private TalkClient talkClient;
+
+ public void onMessage(Message message) {
+
+ }
+
+ public void onNewMember(ChatRoom chaRoom, Member member) {
+
+ }
+
+ public void onDelMember(ChatRoom chatRoom, Member member) {
+
+ }
+
+}
diff --git a/src/main/java/com/github/netricecake/kakao/structs/ChatRoom.java b/src/main/java/com/github/netricecake/kakao/structs/ChatRoom.java
new file mode 100644
index 0000000..d84f81f
--- /dev/null
+++ b/src/main/java/com/github/netricecake/kakao/structs/ChatRoom.java
@@ -0,0 +1,20 @@
+package com.github.netricecake.kakao.structs;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class ChatRoom {
+
+ private long chatId;
+
+ private String type;
+
+ private String name;
+
+ private long linkId;
+
+ //private Map members = new HashMap<>();
+
+}
diff --git a/src/main/java/com/github/netricecake/kakao/structs/Member.java b/src/main/java/com/github/netricecake/kakao/structs/Member.java
new file mode 100644
index 0000000..42595ca
--- /dev/null
+++ b/src/main/java/com/github/netricecake/kakao/structs/Member.java
@@ -0,0 +1,17 @@
+package com.github.netricecake.kakao.structs;
+
+import lombok.Getter;
+
+@Getter
+public class Member {
+
+ private long id;
+
+ private String name;
+
+ public Member(long id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+
+}
diff --git a/src/main/java/com/github/netricecake/kakao/structs/Message.java b/src/main/java/com/github/netricecake/kakao/structs/Message.java
new file mode 100644
index 0000000..bebff03
--- /dev/null
+++ b/src/main/java/com/github/netricecake/kakao/structs/Message.java
@@ -0,0 +1,29 @@
+package com.github.netricecake.kakao.structs;
+
+import lombok.Getter;
+
+@Getter
+public class Message {
+
+ private long logId;
+
+ private ChatRoom chatRoom;
+
+ private Member author;
+
+ private int type;
+
+ private String message;
+
+ private String attachment;
+
+ public Message(long logId, ChatRoom chatRoom, Member author, int type, String message, String attachment) {
+ this.logId = logId;
+ this.chatRoom = chatRoom;
+ this.author = author;
+ this.type = type;
+ this.message = message;
+ this.attachment = attachment;
+ }
+
+}
diff --git a/src/main/java/com/github/netricecake/network/LocoPacket.java b/src/main/java/com/github/netricecake/loco/LocoPacket.java
similarity index 73%
rename from src/main/java/com/github/netricecake/network/LocoPacket.java
rename to src/main/java/com/github/netricecake/loco/LocoPacket.java
index edbff56..c5bdb27 100644
--- a/src/main/java/com/github/netricecake/network/LocoPacket.java
+++ b/src/main/java/com/github/netricecake/loco/LocoPacket.java
@@ -1,27 +1,22 @@
-package com.github.netricecake.network;
+package com.github.netricecake.loco;
import lombok.Getter;
import lombok.Setter;
+@Getter
+@Setter
public class LocoPacket {
- @Getter
- private final int packetId;
+ private int packetId;
- @Getter
- private final short statusCode;
+ private short statusCode;
- @Getter
private String method;
- @Getter
- private final byte bodyType;
+ private byte bodyType;
- @Getter
private int bodyLength;
- @Getter
- @Setter
private byte[] body;
public LocoPacket(int packetId, short statusCode, String method, byte bodyType, int bodyLength, byte[] body) {
@@ -37,4 +32,8 @@ public class LocoPacket {
this(packetId, (short) 0, method, (byte) 0, body.length, body);
}
+ public LocoPacket(String method, byte[] body) {
+ this(-1, method, body);
+ }
+
}
diff --git a/src/main/java/com/github/netricecake/loco/LocoSocektHandler.java b/src/main/java/com/github/netricecake/loco/LocoSocektHandler.java
new file mode 100644
index 0000000..3d8b94d
--- /dev/null
+++ b/src/main/java/com/github/netricecake/loco/LocoSocektHandler.java
@@ -0,0 +1,13 @@
+package com.github.netricecake.loco;
+
+public interface LocoSocektHandler {
+
+ void onPacket(LocoPacket packet);
+
+ void onConnect();
+
+ void onDisconnect();
+
+ void onError(Exception e);
+
+}
diff --git a/src/main/java/com/github/netricecake/loco/LocoSocket.java b/src/main/java/com/github/netricecake/loco/LocoSocket.java
new file mode 100644
index 0000000..d56058a
--- /dev/null
+++ b/src/main/java/com/github/netricecake/loco/LocoSocket.java
@@ -0,0 +1,139 @@
+package com.github.netricecake.loco;
+
+import com.github.netricecake.loco.crypto.CryptoManager;
+import com.github.netricecake.loco.codec.LocoCodec;
+import com.github.netricecake.loco.codec.SecureLayerCodec;
+import io.netty.bootstrap.Bootstrap;
+import io.netty.channel.*;
+import io.netty.channel.nio.NioIoHandler;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioSocketChannel;
+import io.netty.handler.codec.bytes.ByteArrayDecoder;
+import io.netty.handler.codec.bytes.ByteArrayEncoder;
+import lombok.Getter;
+
+import java.net.InetSocketAddress;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.*;
+
+public class LocoSocket {
+
+ @Getter
+ private String ip;
+ @Getter
+ private int port;
+
+ private CryptoManager cryptoManager;
+
+ private Channel channel;
+ private EventLoopGroup eventLoopGroup;
+
+ @Getter
+ private boolean alive = false;
+
+ @Getter
+ private Map> waitList = new HashMap<>();
+
+ @Getter
+ private LocoSocektHandler locoSocektHandler;
+
+ @Getter
+ private ExecutorService handlerPool;
+
+ private int packetIdCounter = 1000;
+
+ public LocoSocket(String ip, int port, LocoSocektHandler locoSocektHandler, ExecutorService handlerPool) {
+ this.ip = ip;
+ this.port = port;
+ this.locoSocektHandler = locoSocektHandler;
+ this.handlerPool = handlerPool;
+ cryptoManager = new CryptoManager();
+ }
+
+ public void connect() {
+ try {
+ byte[] handshakePacket = cryptoManager.generateHandshakeMessage();
+ eventLoopGroup = new MultiThreadIoEventLoopGroup(1, NioIoHandler.newFactory());
+ Bootstrap bootstrap = new Bootstrap();
+ bootstrap.remoteAddress(new InetSocketAddress(ip, port))
+ .group(eventLoopGroup)
+ .channel(NioSocketChannel.class)
+ .handler(new ChannelInitializer() {
+ @Override
+ protected void initChannel(SocketChannel socketChannel) throws Exception {
+ ChannelPipeline pipeline = socketChannel.pipeline();
+ pipeline.addLast(new ByteArrayEncoder());
+ pipeline.addLast(new ByteArrayDecoder());
+ }
+ });
+ channel = bootstrap.connect().sync().channel();
+ alive = true;
+ channel.writeAndFlush(handshakePacket).sync();
+ channel.pipeline().addLast(new SecureLayerCodec(cryptoManager));
+ channel.pipeline().addLast(new LocoCodec(this));
+ handlerPool.execute(() -> {
+ locoSocektHandler.onConnect();
+ });
+ new Thread() {
+ @Override
+ public void run() {
+ try {
+ channel.closeFuture().sync();
+ eventLoopGroup.shutdownGracefully();
+ handlerPool.execute(() -> {
+ locoSocektHandler.onDisconnect();
+ });
+ alive = false;
+ } catch (Exception e) {
+ handlerPool.execute(() -> {
+ locoSocektHandler.onError(e);
+ });
+ }
+ }
+ }.start();
+ } catch (Exception e) {
+ handlerPool.execute(() -> {
+ locoSocektHandler.onError(e);
+ });
+ }
+ }
+
+ public void write(LocoPacket packet) {
+ if (!alive) return;
+ synchronized (this) {
+ if (packet.getPacketId() == -1) packet.setPacketId(++packetIdCounter);
+ }
+ channel.writeAndFlush(packet);
+ }
+
+ public LocoPacket writeAndRead(LocoPacket packet) {
+ if (!alive) return null;
+ int packetId = packet.getPacketId();
+ synchronized (this) {
+ if (packet.getPacketId() == -1) packetId = ++packetIdCounter;
+ }
+ packet.setPacketId(packetId);
+ Future future = new CompletableFuture<>();
+ waitList.put(packetId, future);
+ channel.writeAndFlush(packet);
+ try {
+ return future.get();
+ } catch (Exception e) {
+ handlerPool.execute(() -> {
+ locoSocektHandler.onError(e);
+ });
+ }
+ return null;
+ }
+
+ public void close() {
+ handlerPool.execute(() -> {
+ locoSocektHandler.onDisconnect();
+ });
+ channel.close();
+ eventLoopGroup.shutdownGracefully();
+ alive = false;
+ }
+
+}
diff --git a/src/main/java/com/github/netricecake/network/codec/LocoCodec.java b/src/main/java/com/github/netricecake/loco/codec/LocoCodec.java
similarity index 72%
rename from src/main/java/com/github/netricecake/network/codec/LocoCodec.java
rename to src/main/java/com/github/netricecake/loco/codec/LocoCodec.java
index 0d5ea71..45734a9 100644
--- a/src/main/java/com/github/netricecake/network/codec/LocoCodec.java
+++ b/src/main/java/com/github/netricecake/loco/codec/LocoCodec.java
@@ -1,22 +1,24 @@
-package com.github.netricecake.network.codec;
+package com.github.netricecake.loco.codec;
-import com.github.netricecake.network.LocoPacket;
-import com.github.netricecake.util.ByteUtil;
+import com.github.netricecake.loco.LocoPacket;
+import com.github.netricecake.loco.LocoSocket;
+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.concurrent.BlockingQueue;
+import java.util.concurrent.CompletableFuture;
public class LocoCodec extends MessageToMessageCodec {
private LocoPacket currentLocoPacket = null;
private byte[] buffer = new byte[0];
- private BlockingQueue locoPacketQueue;
+ private final LocoSocket locoSocket;
- public LocoCodec(BlockingQueue locoPacketHandler) {
- this.locoPacketQueue = locoPacketHandler;
+ public LocoCodec(LocoSocket locoSocekt) {
+ this.locoSocket = locoSocekt;
}
@Override
@@ -55,7 +57,15 @@ public class LocoCodec extends MessageToMessageCodec {
byte[] body = ByteUtil.sliceBytes(buffer, 0, currentLocoPacket.getBodyLength());
buffer = ByteUtil.sliceBytes(buffer, currentLocoPacket.getBodyLength(), buffer.length - currentLocoPacket.getBodyLength());
currentLocoPacket.setBody(body);
- locoPacketQueue.put(currentLocoPacket);
+ if (locoSocket.getWaitList().containsKey(currentLocoPacket.getPacketId())) {
+ ((CompletableFuture) locoSocket.getWaitList().get(currentLocoPacket.getPacketId())).complete(currentLocoPacket);
+ locoSocket.getWaitList().remove(currentLocoPacket.getPacketId());
+ } else {
+ final LocoPacket p = currentLocoPacket;
+ locoSocket.getHandlerPool().execute(() -> {
+ locoSocket.getLocoSocektHandler().onPacket(p);
+ });
+ }
currentLocoPacket = null;
} while (buffer.length > 0);
diff --git a/src/main/java/com/github/netricecake/network/codec/SecureLayerCodec.java b/src/main/java/com/github/netricecake/loco/codec/SecureLayerCodec.java
similarity index 91%
rename from src/main/java/com/github/netricecake/network/codec/SecureLayerCodec.java
rename to src/main/java/com/github/netricecake/loco/codec/SecureLayerCodec.java
index df5a288..0fab3da 100644
--- a/src/main/java/com/github/netricecake/network/codec/SecureLayerCodec.java
+++ b/src/main/java/com/github/netricecake/loco/codec/SecureLayerCodec.java
@@ -1,7 +1,7 @@
-package com.github.netricecake.network.codec;
+package com.github.netricecake.loco.codec;
-import com.github.netricecake.crypto.CryptoManager;
-import com.github.netricecake.util.ByteUtil;
+import com.github.netricecake.loco.crypto.CryptoManager;
+import com.github.netricecake.loco.util.ByteUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageCodec;
diff --git a/src/main/java/com/github/netricecake/crypto/CryptoManager.java b/src/main/java/com/github/netricecake/loco/crypto/CryptoManager.java
similarity index 94%
rename from src/main/java/com/github/netricecake/crypto/CryptoManager.java
rename to src/main/java/com/github/netricecake/loco/crypto/CryptoManager.java
index 0254873..73857bc 100644
--- a/src/main/java/com/github/netricecake/crypto/CryptoManager.java
+++ b/src/main/java/com/github/netricecake/loco/crypto/CryptoManager.java
@@ -1,11 +1,14 @@
-package com.github.netricecake.crypto;
+package com.github.netricecake.loco.crypto;
-import com.github.netricecake.util.ByteUtil;
+import com.github.netricecake.loco.util.ByteUtil;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.GCMParameterSpec;
-import java.security.*;
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.PublicKey;
+import java.security.SecureRandom;
import java.security.spec.X509EncodedKeySpec;
public class CryptoManager {
diff --git a/src/main/java/com/github/netricecake/loco/packet/inbound/ChatInfoIn.java b/src/main/java/com/github/netricecake/loco/packet/inbound/ChatInfoIn.java
new file mode 100644
index 0000000..62ba02c
--- /dev/null
+++ b/src/main/java/com/github/netricecake/loco/packet/inbound/ChatInfoIn.java
@@ -0,0 +1,22 @@
+package com.github.netricecake.loco.packet.inbound;
+
+import com.github.netricecake.loco.util.BsonUtil;
+import com.google.gson.JsonObject;
+import lombok.Getter;
+
+@Getter
+public class ChatInfoIn {
+
+ private String type;
+
+ private long linkId;
+
+ public void fromBson(byte[] bson) {
+ JsonObject jsonObject = BsonUtil.bsonToJsonObject(bson);
+ type = jsonObject.get("chatInfo").getAsJsonObject().get("type").getAsString();
+ try {
+ linkId = jsonObject.get("chatInfo").getAsJsonObject().get("li").getAsLong();
+ } catch (Exception e) {}
+ }
+
+}
diff --git a/src/main/java/com/github/netricecake/loco/packet/inbound/CheckInIn.java b/src/main/java/com/github/netricecake/loco/packet/inbound/CheckInIn.java
new file mode 100644
index 0000000..450dc37
--- /dev/null
+++ b/src/main/java/com/github/netricecake/loco/packet/inbound/CheckInIn.java
@@ -0,0 +1,52 @@
+package com.github.netricecake.loco.packet.inbound;
+
+import com.github.netricecake.loco.util.BsonUtil;
+import com.google.gson.JsonObject;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+public class CheckInIn {
+
+ private int status;
+
+ private String host;
+
+ private String host6;
+
+ private int port;
+
+ private String cshost;
+
+ private String cshost6;
+
+ private int csport;
+
+ private String vsshost;
+
+ private String vsshost6;
+
+ private int vssport;
+
+ private long cacheExpire;
+
+ private String MCCMNC;
+
+ public void fromBson(byte[] bson)
+ {
+ JsonObject json = BsonUtil.bsonToJsonObject(bson);
+ status = json.get("status").getAsInt();
+ host = json.get("host").getAsString();
+ host6 = json.get("host6").getAsString();
+ port = json.get("port").getAsInt();
+ cshost = json.get("cshost").getAsString();
+ cshost6 = json.get("cshost6").getAsString();
+ csport = json.get("csport").getAsInt();
+ vsshost = json.get("vsshost").getAsString();
+ vsshost6 = json.get("vsshost6").getAsString();
+ vssport = json.get("vssport").getAsInt();
+ cacheExpire = json.get("cacheExpire").getAsLong();
+ MCCMNC = json.get("MCCMNC").getAsString();
+ }
+
+}
diff --git a/src/main/java/com/github/netricecake/loco/packet/inbound/DelMemIn.java b/src/main/java/com/github/netricecake/loco/packet/inbound/DelMemIn.java
new file mode 100644
index 0000000..b4f095d
--- /dev/null
+++ b/src/main/java/com/github/netricecake/loco/packet/inbound/DelMemIn.java
@@ -0,0 +1,25 @@
+package com.github.netricecake.loco.packet.inbound;
+
+import com.github.netricecake.loco.util.BsonUtil;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import lombok.Getter;
+
+@Getter
+public class DelMemIn {
+
+ private long chatId;
+
+ private long userId;
+
+ private String nickname;
+
+ public void fromBson(byte[] bson) {
+ JsonObject jsonObject = BsonUtil.bsonToJsonObject(bson).get("chatLog").getAsJsonObject();
+ chatId = jsonObject.get("chatId").getAsLong();
+ userId = jsonObject.get("authorId").getAsLong();
+ JsonObject msgObject = JsonParser.parseString(jsonObject.get("message").getAsString()).getAsJsonObject();
+ nickname = msgObject.get("member").getAsJsonObject().get("nickName").getAsString();
+ }
+
+}
diff --git a/src/main/java/com/github/netricecake/loco/packet/inbound/GetConfIn.java b/src/main/java/com/github/netricecake/loco/packet/inbound/GetConfIn.java
new file mode 100644
index 0000000..ee92d6d
--- /dev/null
+++ b/src/main/java/com/github/netricecake/loco/packet/inbound/GetConfIn.java
@@ -0,0 +1,24 @@
+package com.github.netricecake.loco.packet.inbound;
+
+import com.github.netricecake.loco.util.BsonUtil;
+import com.google.gson.JsonObject;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+public class GetConfIn {
+
+ private int status;
+
+ private String addr;
+
+ private int port;
+
+ public void fromBson(byte[] bson) {
+ JsonObject jsonObject = BsonUtil.bsonToJsonObject(bson);
+ status = jsonObject.get("status").getAsInt();
+ addr = jsonObject.get("ticket").getAsJsonObject().get("lsl").getAsJsonArray().get(0).getAsString();
+ port = jsonObject.get("wifi").getAsJsonObject().get("ports").getAsJsonArray().get(0).getAsInt();
+ }
+
+}
diff --git a/src/main/java/com/github/netricecake/loco/packet/inbound/InfoLinkIn.java b/src/main/java/com/github/netricecake/loco/packet/inbound/InfoLinkIn.java
new file mode 100644
index 0000000..a01a2a3
--- /dev/null
+++ b/src/main/java/com/github/netricecake/loco/packet/inbound/InfoLinkIn.java
@@ -0,0 +1,17 @@
+package com.github.netricecake.loco.packet.inbound;
+
+import com.github.netricecake.loco.util.BsonUtil;
+import com.google.gson.JsonObject;
+import lombok.Getter;
+
+@Getter
+public class InfoLinkIn {
+
+ private String name;
+
+ public void fromBson(byte[] bson) {
+ JsonObject jsonObject = BsonUtil.bsonToJsonObject(bson);
+ name = jsonObject.get("ols").getAsJsonArray().get(0).getAsJsonObject().get("ln").getAsString();
+ }
+
+}
diff --git a/src/main/java/com/github/netricecake/loco/packet/inbound/LoginListIn.java b/src/main/java/com/github/netricecake/loco/packet/inbound/LoginListIn.java
new file mode 100644
index 0000000..0909402
--- /dev/null
+++ b/src/main/java/com/github/netricecake/loco/packet/inbound/LoginListIn.java
@@ -0,0 +1,65 @@
+package com.github.netricecake.loco.packet.inbound;
+
+import com.github.netricecake.loco.util.BsonUtil;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import lombok.Getter;
+
+import java.util.Base64;
+
+@Getter
+public class LoginListIn {
+
+ private int status;
+
+ private long userId;
+
+ private int revision;
+
+ private String revisionInfo;
+
+ private byte[] rp;
+
+ private long minLogId;
+
+ private int sb;
+
+ private JsonArray chatDatas;
+
+ private JsonArray delChatIds;
+
+ private JsonArray kc;
+
+ private int mcmRevision;
+
+ private long lastTokenId;
+
+ private long lastChatId;
+
+ private long ltk;
+
+ private long lbk;
+
+ private boolean eof;
+
+ public void fromBson(byte[] bson) {
+ JsonObject json = BsonUtil.bsonToJsonObject(bson);
+ status = json.get("status").getAsInt();
+ userId = json.get("userId").getAsLong();
+ revision = json.get("revision").getAsInt();
+ revisionInfo = json.get("revisionInfo").getAsString();
+ rp = Base64.getDecoder().decode(json.get("rp").getAsJsonObject().get("$binary").getAsJsonObject().get("base64").getAsString());
+ minLogId = json.get("minLogId").getAsLong();
+ sb = json.get("sb").getAsInt();
+ chatDatas = json.get("chatDatas").getAsJsonArray();
+ delChatIds = json.get("delChatIds").getAsJsonArray();
+ kc = json.get("kc").getAsJsonArray();
+ mcmRevision = json.get("mcmRevision").getAsInt();
+ lastTokenId = json.get("lastTokenId").getAsLong();
+ lastChatId = json.get("lastChatId").getAsLong();
+ ltk = json.get("ltk").getAsLong();
+ lbk = json.get("lbk").getAsLong();
+ eof = json.get("eof").getAsBoolean();
+ }
+
+}
diff --git a/src/main/java/com/github/netricecake/loco/packet/inbound/MessageIn.java b/src/main/java/com/github/netricecake/loco/packet/inbound/MessageIn.java
new file mode 100644
index 0000000..c62a3c4
--- /dev/null
+++ b/src/main/java/com/github/netricecake/loco/packet/inbound/MessageIn.java
@@ -0,0 +1,41 @@
+package com.github.netricecake.loco.packet.inbound;
+
+import com.github.netricecake.loco.util.BsonUtil;
+import com.google.gson.JsonObject;
+import lombok.Getter;
+
+@Getter
+public class MessageIn {
+
+ private long chatId;
+
+ private long logId;
+
+ private long authorId;
+
+ private String authorNickname;
+
+ private int type;
+
+ private String message;
+
+ private String attachment;
+
+ public void fromBson(byte[] bson) {
+ JsonObject jsonObject = BsonUtil.bsonToJsonObject(bson);
+ chatId = jsonObject.get("chatId").getAsLong();
+ logId = jsonObject.get("logId").getAsLong();
+ authorId = jsonObject.get("chatLog").getAsJsonObject().get("authorId").getAsLong();
+ try {
+ authorNickname = jsonObject.get("authorNickname").getAsString(); // 옵챗 아니면 이필드가 없음;;
+ } catch (Exception e) {}
+ type = jsonObject.get("chatLog").getAsJsonObject().get("type").getAsInt();
+ message = jsonObject.get("chatLog").getAsJsonObject().get("message").getAsString();
+ try {
+ attachment = jsonObject.get("chatLog").getAsJsonObject().get("attachment").getAsString();
+ } catch (Exception e) {
+ attachment = "";
+ }
+ }
+
+}
diff --git a/src/main/java/com/github/netricecake/loco/packet/inbound/NewMemIn.java b/src/main/java/com/github/netricecake/loco/packet/inbound/NewMemIn.java
new file mode 100644
index 0000000..15f765c
--- /dev/null
+++ b/src/main/java/com/github/netricecake/loco/packet/inbound/NewMemIn.java
@@ -0,0 +1,25 @@
+package com.github.netricecake.loco.packet.inbound;
+
+import com.github.netricecake.loco.util.BsonUtil;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import lombok.Getter;
+
+@Getter
+public class NewMemIn {
+
+ private long chatId;
+
+ private long userId;
+
+ private String nickname;
+
+ public void fromBson(byte[] bson) {
+ JsonObject jsonObject = BsonUtil.bsonToJsonObject(bson).get("chatLog").getAsJsonObject();
+ chatId = jsonObject.get("chatId").getAsLong();
+ userId = jsonObject.get("authorId").getAsLong();
+ JsonObject msgObject = JsonParser.parseString(jsonObject.get("message").getAsString()).getAsJsonObject();
+ nickname = msgObject.get("members").getAsJsonArray().get(0).getAsJsonObject().get("nickName").getAsString();
+ }
+
+}
diff --git a/src/main/java/com/github/netricecake/loco/packet/inbound/PingIn.java b/src/main/java/com/github/netricecake/loco/packet/inbound/PingIn.java
new file mode 100644
index 0000000..b0af053
--- /dev/null
+++ b/src/main/java/com/github/netricecake/loco/packet/inbound/PingIn.java
@@ -0,0 +1,4 @@
+package com.github.netricecake.loco.packet.inbound;
+
+public class PingIn {
+}
diff --git a/src/main/java/com/github/netricecake/loco/packet/inbound/WriteIn.java b/src/main/java/com/github/netricecake/loco/packet/inbound/WriteIn.java
new file mode 100644
index 0000000..5f9b42b
--- /dev/null
+++ b/src/main/java/com/github/netricecake/loco/packet/inbound/WriteIn.java
@@ -0,0 +1,17 @@
+package com.github.netricecake.loco.packet.inbound;
+
+import com.github.netricecake.loco.util.BsonUtil;
+import com.google.gson.JsonObject;
+import lombok.Getter;
+
+@Getter
+public class WriteIn {
+
+ private int status;
+
+ public void fromBson(byte[] bson) {
+ JsonObject jsonObject = BsonUtil.bsonToJsonObject(bson);
+ status = jsonObject.get("status").getAsInt();
+ }
+
+}
diff --git a/src/main/java/com/github/netricecake/loco/packet/outbound/ChatInfoOut.java b/src/main/java/com/github/netricecake/loco/packet/outbound/ChatInfoOut.java
new file mode 100644
index 0000000..1588512
--- /dev/null
+++ b/src/main/java/com/github/netricecake/loco/packet/outbound/ChatInfoOut.java
@@ -0,0 +1,20 @@
+package com.github.netricecake.loco.packet.outbound;
+
+import com.github.netricecake.loco.util.BsonUtil;
+import com.google.gson.JsonObject;
+
+public class ChatInfoOut {
+
+ private long chatId;
+
+ public ChatInfoOut(long chatId) {
+ this.chatId = chatId;
+ }
+
+ public byte[] toBson() {
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.addProperty("chatId", chatId);
+ return BsonUtil.jsonObjectToBson(jsonObject);
+ }
+
+}
diff --git a/src/main/java/com/github/netricecake/loco/packet/outbound/CheckInOut.java b/src/main/java/com/github/netricecake/loco/packet/outbound/CheckInOut.java
new file mode 100644
index 0000000..2dd7e37
--- /dev/null
+++ b/src/main/java/com/github/netricecake/loco/packet/outbound/CheckInOut.java
@@ -0,0 +1,45 @@
+package com.github.netricecake.loco.packet.outbound;
+
+import com.github.netricecake.kakao.KakaoApi;
+import com.github.netricecake.loco.util.BsonUtil;
+import com.google.gson.JsonObject;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class CheckInOut {
+
+ private long userId;
+
+ private String os = KakaoApi.AGENT;
+
+ private int ntype = KakaoApi.NETWORK_TYPE;
+
+ private String appVer = KakaoApi.VERSION;
+
+ private String lang = KakaoApi.LANGUAGE;
+
+ private String MCCMNC = KakaoApi.MCCMNC;
+
+ public CheckInOut(long userId) {
+ this.userId = userId;
+ }
+
+ public String getMethod() {
+ return "CHECKIN";
+ }
+
+ public byte[] toBson() {
+ JsonObject checkInObject = new JsonObject();
+ checkInObject.addProperty("userId", userId);
+ checkInObject.addProperty("os", os);
+ checkInObject.addProperty("ntype", ntype);
+ checkInObject.addProperty("appVer", appVer);
+ checkInObject.addProperty("lang", lang);
+ checkInObject.addProperty("MCCMNC", MCCMNC);
+
+ return BsonUtil.jsonObjectToBson(checkInObject);
+ }
+
+}
diff --git a/src/main/java/com/github/netricecake/message/request/GetConfRequest.java b/src/main/java/com/github/netricecake/loco/packet/outbound/GetConfOut.java
similarity index 55%
rename from src/main/java/com/github/netricecake/message/request/GetConfRequest.java
rename to src/main/java/com/github/netricecake/loco/packet/outbound/GetConfOut.java
index 713290b..7e4fd01 100644
--- a/src/main/java/com/github/netricecake/message/request/GetConfRequest.java
+++ b/src/main/java/com/github/netricecake/loco/packet/outbound/GetConfOut.java
@@ -1,29 +1,22 @@
-package com.github.netricecake.message.request;
+package com.github.netricecake.loco.packet.outbound;
-import com.github.netricecake.message.LocoRequest;
-import com.github.netricecake.util.BsonUtil;
+import com.github.netricecake.loco.util.BsonUtil;
import com.google.gson.JsonObject;
-public class GetConfRequest implements LocoRequest {
+public class GetConfOut {
private String MCCMNC;
private String os;
- private int userId;
+ private long userId;
- public GetConfRequest(String MCCMNC, String os, int userId) {
+ public GetConfOut(String MCCMNC, String os, long userId) {
this.MCCMNC = MCCMNC;
this.os = os;
this.userId = userId;
}
- @Override
- public String getMethod() {
- return "GETCONF";
- }
-
- @Override
public byte[] toBson() {
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("MCCMNC", MCCMNC);
@@ -31,4 +24,5 @@ public class GetConfRequest implements LocoRequest {
jsonObject.addProperty("userId", userId);
return BsonUtil.jsonObjectToBson(jsonObject);
}
+
}
diff --git a/src/main/java/com/github/netricecake/loco/packet/outbound/InfoLinkOut.java b/src/main/java/com/github/netricecake/loco/packet/outbound/InfoLinkOut.java
new file mode 100644
index 0000000..9406749
--- /dev/null
+++ b/src/main/java/com/github/netricecake/loco/packet/outbound/InfoLinkOut.java
@@ -0,0 +1,23 @@
+package com.github.netricecake.loco.packet.outbound;
+
+import com.github.netricecake.loco.util.BsonUtil;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+
+public class InfoLinkOut {
+
+ private long linkId;
+
+ public InfoLinkOut(long linkId) {
+ this.linkId = linkId;
+ }
+
+ public byte[] toBson() {
+ JsonObject jsonObject = new JsonObject();
+ JsonArray jsonArray = new JsonArray();
+ jsonArray.add(linkId);
+ jsonObject.add("lis", jsonArray);
+ return BsonUtil.jsonObjectToBson(jsonObject);
+ }
+
+}
diff --git a/src/main/java/com/github/netricecake/loco/packet/outbound/LoginListOut.java b/src/main/java/com/github/netricecake/loco/packet/outbound/LoginListOut.java
new file mode 100644
index 0000000..b0b8803
--- /dev/null
+++ b/src/main/java/com/github/netricecake/loco/packet/outbound/LoginListOut.java
@@ -0,0 +1,79 @@
+package com.github.netricecake.loco.packet.outbound;
+
+import com.github.netricecake.kakao.KakaoApi;
+import com.github.netricecake.loco.util.BsonUtil;
+import com.github.netricecake.loco.util.ByteUtil;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Base64;
+
+@Getter
+@Setter
+public class LoginListOut {
+
+ private String appVer = KakaoApi.VERSION;
+
+ private String prtVer = KakaoApi.PROTOCOL_VERSION;
+
+ private String os = KakaoApi.AGENT;
+
+ private String lang = KakaoApi.LANGUAGE;
+
+ private String duuid;
+
+ private int ntype = KakaoApi.NETWORK_TYPE;
+
+ private String MCCMNC = KakaoApi.MCCMNC;
+
+ private int revision = 0;
+
+ private JsonArray chatIds = new JsonArray();
+
+ private JsonArray maxIds = new JsonArray();
+
+ private long lastTokenId = 0;
+
+ private long lbk = 0;
+
+ private byte[] rp; // 이거 뭐임
+
+ private boolean bg = true;
+
+ private String oauthToken;
+
+ public LoginListOut() {
+ rp = ByteUtil.hexStringToByteArray("0000ffff0000");
+ }
+
+ public byte[] toBson() {
+ JsonObject rpObject = new JsonObject();
+ JsonObject binary = new JsonObject();
+ binary.addProperty("base64", new String(Base64.getEncoder().encode(rp)));
+ binary.addProperty("subType", "00");
+ rpObject.add("$binary", binary);
+
+ JsonObject resultObject = new JsonObject();
+ resultObject.addProperty("appVer", appVer);
+ resultObject.addProperty("prtVer", prtVer);
+ resultObject.addProperty("os", os);
+ resultObject.addProperty("lang", lang);
+ resultObject.addProperty("duuid", duuid);
+ resultObject.addProperty("ntype", ntype);
+ resultObject.addProperty("MCCMNC", MCCMNC);
+ resultObject.addProperty("revision", revision);
+ resultObject.add("chatIds", chatIds);
+ resultObject.add("maxIds", maxIds);
+ resultObject.addProperty("lastTokenId", lastTokenId);
+ resultObject.addProperty("lbk", lbk);
+ resultObject.add("rp", rpObject);
+ resultObject.addProperty("bg", bg);
+ resultObject.addProperty("oauthToken", oauthToken);
+
+ return BsonUtil.jsonObjectToBson(resultObject);
+ }
+
+
+}
diff --git a/src/main/java/com/github/netricecake/loco/packet/outbound/MessageOut.java b/src/main/java/com/github/netricecake/loco/packet/outbound/MessageOut.java
new file mode 100644
index 0000000..bbebade
--- /dev/null
+++ b/src/main/java/com/github/netricecake/loco/packet/outbound/MessageOut.java
@@ -0,0 +1,11 @@
+package com.github.netricecake.loco.packet.outbound;
+
+import com.github.netricecake.loco.util.BsonUtil;
+
+public class MessageOut {
+
+ public byte[] toBson() {
+ return BsonUtil.jsonToBson("{ \"notiRead\": false }");
+ }
+
+}
diff --git a/src/main/java/com/github/netricecake/loco/packet/outbound/PingOut.java b/src/main/java/com/github/netricecake/loco/packet/outbound/PingOut.java
new file mode 100644
index 0000000..a5a5b28
--- /dev/null
+++ b/src/main/java/com/github/netricecake/loco/packet/outbound/PingOut.java
@@ -0,0 +1,11 @@
+package com.github.netricecake.loco.packet.outbound;
+
+import com.github.netricecake.loco.util.BsonUtil;
+
+public class PingOut {
+
+ public byte[] toBson() {
+ return BsonUtil.jsonToBson("{}");
+ }
+
+}
diff --git a/src/main/java/com/github/netricecake/message/request/WriteRequest.java b/src/main/java/com/github/netricecake/loco/packet/outbound/WriteOut.java
similarity index 64%
rename from src/main/java/com/github/netricecake/message/request/WriteRequest.java
rename to src/main/java/com/github/netricecake/loco/packet/outbound/WriteOut.java
index 5d9ef27..cbaad6f 100644
--- a/src/main/java/com/github/netricecake/message/request/WriteRequest.java
+++ b/src/main/java/com/github/netricecake/loco/packet/outbound/WriteOut.java
@@ -1,33 +1,24 @@
-package com.github.netricecake.message.request;
+package com.github.netricecake.loco.packet.outbound;
-import com.github.netricecake.message.LocoRequest;
-import com.github.netricecake.util.BsonUtil;
+import com.github.netricecake.loco.util.BsonUtil;
import com.google.gson.JsonObject;
import lombok.Getter;
import lombok.Setter;
+import java.security.SecureRandom;
+
@Getter
@Setter
-public class WriteRequest implements LocoRequest {
+public class WriteOut {
private long chatId;
- private long msgId; // 이거 뭐임???
+ private long msgId = new SecureRandom().nextLong();
private String message;
private int type = 1;
private boolean noSeen = false;
private String extra = "{}";
private int scope = 1;
- public WriteRequest() {
- msgId = (long) Math.ceil(Math.random() * 99999999);
- }
-
- @Override
- public String getMethod() {
- return "WRITE";
- }
-
- @Override
public byte[] toBson() {
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("chatId", chatId);
diff --git a/src/main/java/com/github/netricecake/util/BsonUtil.java b/src/main/java/com/github/netricecake/loco/util/BsonUtil.java
similarity index 96%
rename from src/main/java/com/github/netricecake/util/BsonUtil.java
rename to src/main/java/com/github/netricecake/loco/util/BsonUtil.java
index 4dd064d..75b3a4c 100644
--- a/src/main/java/com/github/netricecake/util/BsonUtil.java
+++ b/src/main/java/com/github/netricecake/loco/util/BsonUtil.java
@@ -1,4 +1,4 @@
-package com.github.netricecake.util;
+package com.github.netricecake.loco.util;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
diff --git a/src/main/java/com/github/netricecake/util/ByteUtil.java b/src/main/java/com/github/netricecake/loco/util/ByteUtil.java
similarity index 97%
rename from src/main/java/com/github/netricecake/util/ByteUtil.java
rename to src/main/java/com/github/netricecake/loco/util/ByteUtil.java
index ae4ea15..0156d35 100644
--- a/src/main/java/com/github/netricecake/util/ByteUtil.java
+++ b/src/main/java/com/github/netricecake/loco/util/ByteUtil.java
@@ -1,4 +1,4 @@
-package com.github.netricecake.util;
+package com.github.netricecake.loco.util;
public class ByteUtil {
diff --git a/src/main/java/com/github/netricecake/message/LocoRequest.java b/src/main/java/com/github/netricecake/message/LocoRequest.java
deleted file mode 100644
index aa715a6..0000000
--- a/src/main/java/com/github/netricecake/message/LocoRequest.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package com.github.netricecake.message;
-
-public interface LocoRequest {
-
- String getMethod();
-
- byte[] toBson();
-
-}
diff --git a/src/main/java/com/github/netricecake/message/LocoResponse.java b/src/main/java/com/github/netricecake/message/LocoResponse.java
deleted file mode 100644
index 1bbdbf0..0000000
--- a/src/main/java/com/github/netricecake/message/LocoResponse.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package com.github.netricecake.message;
-
-public interface LocoResponse {
-
- String getMethod();
-
- void fromBson(byte[] bson);
-
-}
diff --git a/src/main/java/com/github/netricecake/message/request/CheckInRequest.java b/src/main/java/com/github/netricecake/message/request/CheckInRequest.java
deleted file mode 100644
index c1ef6d4..0000000
--- a/src/main/java/com/github/netricecake/message/request/CheckInRequest.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.github.netricecake.message.request;
-
-import com.github.netricecake.KakaoApi;
-import com.github.netricecake.kakao.KakaoDefaultValues;
-import com.github.netricecake.message.LocoRequest;
-import com.github.netricecake.util.BsonUtil;
-import com.google.gson.JsonObject;
-import lombok.Getter;
-import lombok.Setter;
-
-@Getter
-@Setter
-public class CheckInRequest implements LocoRequest {
-
- private int userId;
-
- private String os = KakaoDefaultValues.os;
-
- private int ntype = KakaoDefaultValues.ntype;
-
- private String appVer = KakaoApi.VERSION;
-
- private String lang = KakaoApi.LANGUAGE;
-
- private String MCCMNC = KakaoDefaultValues.MCCMNC;
-
- @Override
- public String getMethod() {
- return "CHECKIN";
- }
-
- @Override
- public byte[] toBson() {
- JsonObject jsonObject = new JsonObject();
- jsonObject.addProperty("userId", userId);
- jsonObject.addProperty("os", os);
- jsonObject.addProperty("ntype", ntype);
- jsonObject.addProperty("appVer", appVer);
- jsonObject.addProperty("lang", lang);
- jsonObject.addProperty("MCCMNC", MCCMNC);
-
- return BsonUtil.jsonObjectToBson(jsonObject);
- }
-}
diff --git a/src/main/java/com/github/netricecake/message/request/LoginListRequest.java b/src/main/java/com/github/netricecake/message/request/LoginListRequest.java
deleted file mode 100644
index b72fa9b..0000000
--- a/src/main/java/com/github/netricecake/message/request/LoginListRequest.java
+++ /dev/null
@@ -1,79 +0,0 @@
-package com.github.netricecake.message.request;
-
-import com.github.netricecake.KakaoApi;
-import com.github.netricecake.message.LocoRequest;
-import com.github.netricecake.util.BsonUtil;
-import com.google.gson.JsonArray;
-import com.google.gson.JsonObject;
-import lombok.Getter;
-import lombok.Setter;
-
-@Getter
-@Setter
-public class LoginListRequest implements LocoRequest {
-
- private String appVer = KakaoApi.VERSION;
-
- private String prtVer = "1";
-
- private String os = KakaoApi.AGENT;
-
- private String lang = "ko";
-
- private String duuid;
-
- private int ntype = 0; // 0 : WIFI, 3: Cellular
-
- private String MCCMNC = "45006"; // 앞자리 세자리(한국) 450 고정, 뒤에 두자리 SKT: 05 KT: 08 LGU+: 06 ex) 45006
-
- private int revision = 0; // TODO 이거뭐임
-
- private JsonArray chatIds = new JsonArray();
-
- private JsonArray maxIds = new JsonArray();
-
- private int lastTokenId = 0;
-
- private int lbk = 0; // TODO 이거 뭐임 2
-
- private JsonObject rp = new JsonObject(); // TODO 이거 뭐임 3
-
- private boolean bg = true; // TODO 이거 뭐임 4
-
- private String oauthToken;
-
- public LoginListRequest() {
- JsonObject jsonObject = new JsonObject();
- jsonObject.addProperty("base64", "AAD//wAA");
- jsonObject.addProperty("subType", "00");
- rp.add("$binary", jsonObject);
- }
-
- @Override
- public String getMethod() {
- return "LOGINLIST";
- }
-
- @Override
- public byte[] toBson() {
- JsonObject jsonObject = new JsonObject();
- jsonObject.addProperty("appVer", appVer);
- jsonObject.addProperty("prtVer", prtVer);
- jsonObject.addProperty("os", os);
- jsonObject.addProperty("lang", lang);
- jsonObject.addProperty("duuid", duuid);
- jsonObject.addProperty("ntype", ntype);
- jsonObject.addProperty("MCCMNC", MCCMNC);
- jsonObject.addProperty("revision", revision);
- jsonObject.add("chatIds", chatIds);
- jsonObject.add("maxIds", maxIds);
- jsonObject.addProperty("lastTokenId", lastTokenId);
- jsonObject.addProperty("lbk", lbk);
- jsonObject.add("rp", rp);
- jsonObject.addProperty("bg", bg);
- jsonObject.addProperty("oauthToken", oauthToken);
-
- return BsonUtil.jsonObjectToBson(jsonObject);
- }
-
-}
diff --git a/src/main/java/com/github/netricecake/message/request/MessageRequest.java b/src/main/java/com/github/netricecake/message/request/MessageRequest.java
deleted file mode 100644
index 756eb92..0000000
--- a/src/main/java/com/github/netricecake/message/request/MessageRequest.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.github.netricecake.message.request;
-
-import com.github.netricecake.message.LocoRequest;
-import com.github.netricecake.util.BsonUtil;
-
-public class MessageRequest implements LocoRequest {
- @Override
- public String getMethod() {
- return "MSG";
- }
-
- @Override
- public byte[] toBson() {
- return BsonUtil.jsonToBson("{ notiRead: false }");
- }
-}
diff --git a/src/main/java/com/github/netricecake/message/request/PingRequest.java b/src/main/java/com/github/netricecake/message/request/PingRequest.java
deleted file mode 100644
index 1fbe9a0..0000000
--- a/src/main/java/com/github/netricecake/message/request/PingRequest.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.github.netricecake.message.request;
-
-import com.github.netricecake.message.LocoRequest;
-import com.github.netricecake.util.BsonUtil;
-
-public class PingRequest implements LocoRequest {
-
-
- @Override
- public String getMethod() {
- return "PING";
- }
-
- @Override
- public byte[] toBson() {
- return BsonUtil.jsonToBson("{}");
- }
-}
diff --git a/src/main/java/com/github/netricecake/message/request/SetStatusRequest.java b/src/main/java/com/github/netricecake/message/request/SetStatusRequest.java
deleted file mode 100644
index 9e78f1b..0000000
--- a/src/main/java/com/github/netricecake/message/request/SetStatusRequest.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.github.netricecake.message.request;
-
-import com.github.netricecake.message.LocoRequest;
-import com.github.netricecake.util.BsonUtil;
-import com.google.gson.JsonObject;
-import lombok.Getter;
-import lombok.Setter;
-
-@Getter
-@Setter
-public class SetStatusRequest implements LocoRequest {
-
- /*
- 카톡 켜고 있는지 안켜고 있는지 알리는 패킷인듯
- */
-
- private int status; // 1 : 본다, 2 : 안본다
-
- public SetStatusRequest(int atatus) {
- this.status = atatus;
- }
-
- @Override
- public String getMethod() {
- return "SETST";
- }
-
- @Override
- public byte[] toBson() {
- JsonObject jsonObject = new JsonObject();
- jsonObject.addProperty("st", status);
- return BsonUtil.jsonObjectToBson(jsonObject);
- }
-}
diff --git a/src/main/java/com/github/netricecake/message/response/CheckInResponse.java b/src/main/java/com/github/netricecake/message/response/CheckInResponse.java
deleted file mode 100644
index eb4a54b..0000000
--- a/src/main/java/com/github/netricecake/message/response/CheckInResponse.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package com.github.netricecake.message.response;
-
-import com.github.netricecake.message.LocoResponse;
-import com.github.netricecake.util.BsonUtil;
-import com.github.netricecake.util.ByteUtil;
-import com.google.gson.JsonObject;
-import lombok.Getter;
-
-@Getter
-public class CheckInResponse implements LocoResponse {
-
- private String host;
-
- private String host6;
-
- private int port;
-
- private String cshost;
-
- private String cshost6;
-
- private int csport;
-
- private String vshost;
-
- private String vshost6;
-
- private int vsport;
-
- private int cacheExpire;
-
- private String MCCMNC;
-
- @Override
- public String getMethod() {
- return "CHECKIN";
- }
-
- @Override
- public void fromBson(byte[] bson) {
- JsonObject jsonObject = BsonUtil.bsonToJsonObject(bson);
- this.host = jsonObject.get("host").getAsString();
- this.host6 = jsonObject.get("host6").getAsString();
- this.port = jsonObject.get("port").getAsInt();
- this.cshost = jsonObject.get("cshost").getAsString();
- this.cshost6 = jsonObject.get("cshost6").getAsString();
- this.csport = jsonObject.get("csport").getAsInt();
- this.vshost = jsonObject.get("vsshost").getAsString();
- this.vshost6 = jsonObject.get("vsshost6").getAsString();
- this.vsport = jsonObject.get("vssport").getAsInt();
- this.cacheExpire = jsonObject.get("cacheExpire").getAsInt();
- this.MCCMNC = jsonObject.get("MCCMNC").getAsString();
- }
-}
diff --git a/src/main/java/com/github/netricecake/message/response/GetConfResponse.java b/src/main/java/com/github/netricecake/message/response/GetConfResponse.java
deleted file mode 100644
index a6d73fb..0000000
--- a/src/main/java/com/github/netricecake/message/response/GetConfResponse.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.github.netricecake.message.response;
-
-import com.github.netricecake.message.LocoResponse;
-import com.github.netricecake.util.BsonUtil;
-import com.google.gson.JsonObject;
-import lombok.Getter;
-
-@Getter
-public class GetConfResponse implements LocoResponse {
-
- private String addr;
-
- private int port;
-
- @Override
- public String getMethod() {
- return "GetConf";
- }
-
- @Override
- public void fromBson(byte[] bson) {
- JsonObject jsonObject = BsonUtil.bsonToJsonObject(bson);
- this.addr = jsonObject.get("ticket").getAsJsonObject().get("lsl").getAsJsonArray().get(0).getAsString();
- this.port = jsonObject.get("wifi").getAsJsonObject().get("ports").getAsJsonArray().get(0).getAsInt();
- }
-}
diff --git a/src/main/java/com/github/netricecake/message/response/LoginListResponse.java b/src/main/java/com/github/netricecake/message/response/LoginListResponse.java
deleted file mode 100644
index 3c5fe78..0000000
--- a/src/main/java/com/github/netricecake/message/response/LoginListResponse.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.github.netricecake.message.response;
-
-import com.github.netricecake.message.LocoResponse;
-import com.github.netricecake.util.BsonUtil;
-import com.google.gson.JsonObject;
-import lombok.Getter;
-
-@Getter
-public class LoginListResponse implements LocoResponse {
-
- private int status;
-
- @Override
- public String getMethod() {
- return "LOGINLIST";
- }
-
- @Override
- public void fromBson(byte[] bson) {
- // 너무 많음;;
- JsonObject jsonObject = BsonUtil.bsonToJsonObject(bson);
- this.status = jsonObject.get("status").getAsInt();
- }
-
-}
diff --git a/src/main/java/com/github/netricecake/message/response/MessageResponse.java b/src/main/java/com/github/netricecake/message/response/MessageResponse.java
deleted file mode 100644
index cb3055f..0000000
--- a/src/main/java/com/github/netricecake/message/response/MessageResponse.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package com.github.netricecake.message.response;
-
-import com.github.netricecake.message.LocoResponse;
-import com.github.netricecake.util.BsonUtil;
-import com.google.gson.JsonObject;
-import lombok.Getter;
-
-@Getter
-public class MessageResponse implements LocoResponse {
-
- private long chatId;
- private long logId;
- private int type;
- private long authorId;
- private String message;
-
- @Override
- public String getMethod() {
- return "MSG";
- }
-
- @Override
- public void fromBson(byte[] bson) {
- JsonObject jsonObject = BsonUtil.bsonToJsonObject(bson);
- chatId = jsonObject.get("chatId").getAsLong();
- logId = jsonObject.get("logId").getAsLong();
- type = jsonObject.get("chatLog").getAsJsonObject().get("type").getAsInt();
- message = jsonObject.get("chatLog").getAsJsonObject().get("message").getAsString();
- }
-}
diff --git a/src/main/java/com/github/netricecake/message/response/PingResponse.java b/src/main/java/com/github/netricecake/message/response/PingResponse.java
deleted file mode 100644
index 9f0e381..0000000
--- a/src/main/java/com/github/netricecake/message/response/PingResponse.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.github.netricecake.message.response;
-
-import com.github.netricecake.message.LocoResponse;
-import com.github.netricecake.util.BsonUtil;
-import com.google.gson.JsonObject;
-import lombok.Getter;
-
-@Getter
-public class PingResponse implements LocoResponse {
-
- private int status;
-
- @Override
- public String getMethod() {
- return "PING";
- }
-
- @Override
- public void fromBson(byte[] bson) {
- JsonObject jsonObject = BsonUtil.bsonToJsonObject(bson);
- this.status = jsonObject.get("status").getAsInt();
- }
-}
diff --git a/src/main/java/com/github/netricecake/message/response/SetStatusResponse.java b/src/main/java/com/github/netricecake/message/response/SetStatusResponse.java
deleted file mode 100644
index e0b9f9e..0000000
--- a/src/main/java/com/github/netricecake/message/response/SetStatusResponse.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.github.netricecake.message.response;
-
-import com.github.netricecake.message.LocoResponse;
-import com.github.netricecake.util.BsonUtil;
-import com.google.gson.JsonObject;
-import lombok.Getter;
-import lombok.Setter;
-
-@Getter
-public class SetStatusResponse implements LocoResponse {
-
- private int status;
-
- @Override
- public String getMethod() {
- return "SETST";
- }
-
- @Override
- public void fromBson(byte[] bson) {
- JsonObject jsonObject = BsonUtil.bsonToJsonObject(bson);
- status = jsonObject.get("status").getAsInt();
- }
-}
diff --git a/src/main/java/com/github/netricecake/network/LocoPacketHandler.java b/src/main/java/com/github/netricecake/network/LocoPacketHandler.java
deleted file mode 100644
index c4b404f..0000000
--- a/src/main/java/com/github/netricecake/network/LocoPacketHandler.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package com.github.netricecake.network;
-
-@FunctionalInterface
-public interface LocoPacketHandler {
- void onPacket(LocoPacket packet);
-}
diff --git a/src/main/java/com/github/netricecake/network/LocoSocket.java b/src/main/java/com/github/netricecake/network/LocoSocket.java
deleted file mode 100644
index d2ab52c..0000000
--- a/src/main/java/com/github/netricecake/network/LocoSocket.java
+++ /dev/null
@@ -1,92 +0,0 @@
-package com.github.netricecake.network;
-
-import com.github.netricecake.crypto.CryptoManager;
-import com.github.netricecake.network.codec.LocoCodec;
-import com.github.netricecake.network.codec.SecureLayerCodec;
-import io.netty.bootstrap.Bootstrap;
-import io.netty.channel.*;
-import io.netty.channel.nio.NioIoHandler;
-import io.netty.channel.socket.SocketChannel;
-import io.netty.channel.socket.nio.NioSocketChannel;
-import io.netty.handler.codec.bytes.ByteArrayDecoder;
-import io.netty.handler.codec.bytes.ByteArrayEncoder;
-import lombok.Getter;
-
-import java.net.InetSocketAddress;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.TimeUnit;
-
-public class LocoSocket {
-
- @Getter
- private String ip;
- @Getter
- private int port;
-
- private CryptoManager cryptoManager;
-
- private Channel channel;
- private EventLoopGroup eventLoopGroup;
-
- @Getter
- private boolean alive = false;
-
- private BlockingQueue locoPacketQueue = new LinkedBlockingQueue<>();
-
- public LocoSocket(String ip, int port) {
- this.ip = ip;
- this.port = port;
- cryptoManager = new CryptoManager();
- }
-
- public void connect() throws Exception {
- byte[] handshakePacket = cryptoManager.generateHandshakeMessage();
- eventLoopGroup = new MultiThreadIoEventLoopGroup(1, NioIoHandler.newFactory());
- Bootstrap bootstrap = new Bootstrap();
- bootstrap.remoteAddress(new InetSocketAddress(ip, port))
- .group(eventLoopGroup)
- .channel(NioSocketChannel.class)
- .handler(new ChannelInitializer() {
- @Override
- protected void initChannel(SocketChannel socketChannel) throws Exception {
- ChannelPipeline pipeline = socketChannel.pipeline();
- pipeline.addLast(new ByteArrayEncoder());
- pipeline.addLast(new ByteArrayDecoder());
- }
- });
- channel = bootstrap.connect().sync().channel();
- alive = true;
- channel.writeAndFlush(handshakePacket).sync();
- channel.pipeline().addLast(new SecureLayerCodec(cryptoManager));
- channel.pipeline().addLast(new LocoCodec(locoPacketQueue));
- new Thread() {
- @Override
- public void run() {
- try {
- channel.closeFuture().sync();
- eventLoopGroup.shutdownGracefully();
- locoPacketQueue.offer(null);
- alive = false;
- } catch (Exception e) {}
- }
- }.start();
- }
-
- public void write(LocoPacket packet) {
- if (!alive) return;
- channel.writeAndFlush(packet);
- }
-
- public LocoPacket read() throws Exception {
- if (!alive) return null;
- return locoPacketQueue.poll(100000, TimeUnit.SECONDS);
- }
-
- public void close() {
- channel.close();
- eventLoopGroup.shutdownGracefully();
- alive = false;
- }
-
-}
diff --git a/src/main/resources/META-INF/MANIFEST.MF b/src/main/resources/META-INF/MANIFEST.MF
deleted file mode 100644
index f7fb8a9..0000000
--- a/src/main/resources/META-INF/MANIFEST.MF
+++ /dev/null
@@ -1,3 +0,0 @@
-Manifest-Version: 1.0
-Main-Class: com.github.netricecake.Main
-
diff --git a/test.png b/test.png
deleted file mode 100644
index bd33f94..0000000
Binary files a/test.png and /dev/null differ