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 기반 비공식 카카오톡 클라이언트 (태블릿 서브 디바이스 로그인) -![test](./test.png) +현재 오픈 채팅방에서만 작동합니다. + +절대 본계정으로 돌려보지마세요. + +## Example + +![ex](./ex.png) + +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