Many changes
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,7 +1,9 @@
|
|||||||
target/
|
target/
|
||||||
!.mvn/wrapper/maven-wrapper.jar
|
!.mvn/wrapper/maven-wrapper.jar
|
||||||
|
.mvn
|
||||||
!**/src/main/**/target/
|
!**/src/main/**/target/
|
||||||
!**/src/test/**/target/
|
!**/src/test/**/target/
|
||||||
|
.kotlin
|
||||||
|
|
||||||
### IntelliJ IDEA ###
|
### IntelliJ IDEA ###
|
||||||
.idea/modules.xml
|
.idea/modules.xml
|
||||||
|
|||||||
6
.idea/vcs.xml
generated
6
.idea/vcs.xml
generated
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
67
README.md
67
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 폴더 안에 저장됩니다. 서버 연결이 안되면 삭제하고 시도하세요.
|
||||||
|
|
||||||
|
<U>**device uuid 무조건 바꾸시오.**</U>
|
||||||
|
|||||||
@@ -1,56 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
<groupId>com.github.netricecake</groupId>
|
|
||||||
<artifactId>loco-wrapper</artifactId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-shade-plugin</artifactId>
|
|
||||||
<version>3.4.1</version>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<phase>package</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>shade</goal>
|
|
||||||
</goals>
|
|
||||||
<configuration>
|
|
||||||
<transformers>
|
|
||||||
<transformer>
|
|
||||||
<mainClass>com.github.netricecake.Main</mainClass>
|
|
||||||
</transformer>
|
|
||||||
</transformers>
|
|
||||||
<filters>
|
|
||||||
<filter>
|
|
||||||
<artifact>*:*</artifact>
|
|
||||||
<excludes>
|
|
||||||
<exclude>META-INF/*.SF</exclude>
|
|
||||||
<exclude>META-INF/*.DSA</exclude>
|
|
||||||
<exclude>META-INF/*.RSA</exclude>
|
|
||||||
</excludes>
|
|
||||||
</filter>
|
|
||||||
</filters>
|
|
||||||
</configuration>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
<dependencyManagement>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.squareup.okhttp3</groupId>
|
|
||||||
<artifactId>okhttp-bom</artifactId>
|
|
||||||
<version>5.2.0</version>
|
|
||||||
<type>pom</type>
|
|
||||||
<scope>import</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</dependencyManagement>
|
|
||||||
<properties>
|
|
||||||
<maven.compiler.target>21</maven.compiler.target>
|
|
||||||
<maven.compiler.source>21</maven.compiler.source>
|
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
|
||||||
</properties>
|
|
||||||
</project>
|
|
||||||
1
pom.xml
1
pom.xml
@@ -80,6 +80,7 @@
|
|||||||
<groupId>org.projectlombok</groupId>
|
<groupId>org.projectlombok</groupId>
|
||||||
<artifactId>lombok</artifactId>
|
<artifactId>lombok</artifactId>
|
||||||
<version>1.18.42</version>
|
<version>1.18.42</version>
|
||||||
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.mongodb</groupId>
|
<groupId>org.mongodb</groupId>
|
||||||
|
|||||||
@@ -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<String, Integer> 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,22 +1,65 @@
|
|||||||
package com.github.netricecake;
|
package com.github.netricecake;
|
||||||
|
|
||||||
import com.github.netricecake.util.ByteUtil;
|
import com.github.netricecake.kakao.TalkClient;
|
||||||
|
import com.github.netricecake.kakao.TalkHandler;
|
||||||
import java.security.SecureRandom;
|
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 코드를 <b>실행</b>하려면 <shortcut actionId="Run"/>을(를) 누르거나
|
||||||
|
// 에디터 여백에 있는 <icon src="AllIcons.Actions.Execute"/> 아이콘을 클릭하세요.
|
||||||
public class Main {
|
public class Main {
|
||||||
|
|
||||||
static String EMAIL = "";
|
static String email = "invalid@example.com";
|
||||||
static String PASSWORD = "";
|
static String password = "example";
|
||||||
static String DEVICE_NAME = "SM-X930"; // 갤럭시 탭 s11 울트라
|
static String deviceName = "SM-X930"; // 갤럭시 탭 s11 울트라, 지원되는 태블릿 모델명 넣으세요
|
||||||
|
static String deviceUuid = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"; // 64자 랜덤 hex-string
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
byte[] uuid = new byte[32];
|
TalkClient client = new TalkClient(email, password, deviceName, deviceUuid, new TalkHandler() {
|
||||||
new SecureRandom().nextBytes(uuid);
|
@Override
|
||||||
String deviceUuid = ByteUtil.byteArrayToHexString(uuid);
|
public void onMessage(Message msg) {
|
||||||
KakaoTalkClient client = new KakaoTalkClient();
|
if (msg.getType() != 1) return; // 1이 그냥 채팅, 그냥 채팅만 받기
|
||||||
client.login(EMAIL, PASSWORD, DEVICE_NAME, deviceUuid);
|
if (msg.getMessage().equals("!send")) {
|
||||||
client.test();
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package com.github.netricecake;
|
package com.github.netricecake.kakao;
|
||||||
|
|
||||||
import com.github.netricecake.message.request.GetConfRequest;
|
import com.github.netricecake.loco.packet.inbound.GetConfIn;
|
||||||
import com.github.netricecake.message.response.GetConfResponse;
|
import com.github.netricecake.loco.packet.outbound.GetConfOut;
|
||||||
import com.github.netricecake.util.ByteUtil;
|
import com.github.netricecake.loco.util.ByteUtil;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
@@ -10,11 +10,9 @@ import okhttp3.*;
|
|||||||
|
|
||||||
import javax.net.ssl.SSLSocket;
|
import javax.net.ssl.SSLSocket;
|
||||||
import javax.net.ssl.SSLSocketFactory;
|
import javax.net.ssl.SSLSocketFactory;
|
||||||
import javax.security.auth.login.AccountException;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.security.InvalidParameterException;
|
import java.security.InvalidParameterException;
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
@@ -22,6 +20,17 @@ import java.util.Map;
|
|||||||
|
|
||||||
public class KakaoApi {
|
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 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 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";
|
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 String BOOKING_URL = "booking-loco.kakao.com";
|
||||||
public final static int BOOKING_PORT = 443;
|
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_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);
|
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) {
|
if (status == 0) {
|
||||||
|
|
||||||
LoginData data = new LoginData();
|
LoginData data = new LoginData();
|
||||||
data.userId = jsonObject.get("userId").getAsInt();
|
data.userId = jsonObject.get("userId").getAsLong();
|
||||||
data.countryIso = jsonObject.get("countryIso").getAsString();
|
data.countryIso = jsonObject.get("countryIso").getAsString();
|
||||||
data.countryCode = jsonObject.get("countryCode").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.accessToken = jsonObject.get("access_token").getAsString();
|
||||||
data.refreshToken = jsonObject.get("refresh_token").getAsString();
|
data.refreshToken = jsonObject.get("refresh_token").getAsString();
|
||||||
data.tokenType = jsonObject.get("token_type").getAsString();
|
data.tokenType = jsonObject.get("token_type").getAsString();
|
||||||
@@ -133,11 +137,11 @@ public class KakaoApi {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GetConfResponse getBookingData(String MCCMNC, int userId) {
|
public static GetConfIn getBookingData(long userId) {
|
||||||
byte[] id = ByteUtil.intToByteArrayLE(1000);
|
byte[] id = ByteUtil.intToByteArrayLE(1000);
|
||||||
byte[] method = new byte[11];
|
byte[] method = new byte[11];
|
||||||
System.arraycopy("GETCONF".getBytes(), 0, method, 0, 7);
|
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);
|
byte[] m = ByteUtil.concatBytes(id, new byte[2], method, new byte[1], ByteUtil.intToByteArrayLE(b.length), b);
|
||||||
try {
|
try {
|
||||||
SSLSocketFactory socketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
|
SSLSocketFactory socketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
|
||||||
@@ -154,7 +158,7 @@ public class KakaoApi {
|
|||||||
reader.read(res);
|
reader.read(res);
|
||||||
|
|
||||||
int len = ByteUtil.byteArrayToIntLE(ByteUtil.sliceBytes(res, 18, 4));
|
int len = ByteUtil.byteArrayToIntLE(ByteUtil.sliceBytes(res, 18, 4));
|
||||||
GetConfResponse r = new GetConfResponse();
|
GetConfIn r = new GetConfIn();
|
||||||
r.fromBson(ByteUtil.sliceBytes(res, 22, len));
|
r.fromBson(ByteUtil.sliceBytes(res, 22, len));
|
||||||
|
|
||||||
socket.close();
|
socket.close();
|
||||||
@@ -201,10 +205,10 @@ public class KakaoApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class LoginData {
|
public static class LoginData {
|
||||||
public int userId;
|
public long userId;
|
||||||
public String countryIso;
|
public String countryIso;
|
||||||
public String countryCode;
|
public String countryCode;
|
||||||
public int accountId;
|
public long accountId;
|
||||||
public String accessToken;
|
public String accessToken;
|
||||||
public String refreshToken;
|
public String refreshToken;
|
||||||
public String tokenType;
|
public String tokenType;
|
||||||
@@ -213,6 +217,40 @@ public class KakaoApi {
|
|||||||
public String mainDeviceAgentName;
|
public String mainDeviceAgentName;
|
||||||
public String mainDeviceAppVersion;
|
public String mainDeviceAppVersion;
|
||||||
public String recipe;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -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";
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
222
src/main/java/com/github/netricecake/kakao/TalkClient.java
Normal file
222
src/main/java/com/github/netricecake/kakao/TalkClient.java
Normal file
@@ -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<Long, ChatRoom> 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<String, Integer> 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, "{}");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
27
src/main/java/com/github/netricecake/kakao/TalkHandler.java
Normal file
27
src/main/java/com/github/netricecake/kakao/TalkHandler.java
Normal file
@@ -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) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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<Long, Member> members = new HashMap<>();
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,27 +1,22 @@
|
|||||||
package com.github.netricecake.network;
|
package com.github.netricecake.loco;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
public class LocoPacket {
|
public class LocoPacket {
|
||||||
|
|
||||||
@Getter
|
private int packetId;
|
||||||
private final int packetId;
|
|
||||||
|
|
||||||
@Getter
|
private short statusCode;
|
||||||
private final short statusCode;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
private String method;
|
private String method;
|
||||||
|
|
||||||
@Getter
|
private byte bodyType;
|
||||||
private final byte bodyType;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
private int bodyLength;
|
private int bodyLength;
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
private byte[] body;
|
private byte[] body;
|
||||||
|
|
||||||
public LocoPacket(int packetId, short statusCode, String method, byte bodyType, int bodyLength, 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);
|
this(packetId, (short) 0, method, (byte) 0, body.length, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LocoPacket(String method, byte[] body) {
|
||||||
|
this(-1, method, body);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.github.netricecake.loco;
|
||||||
|
|
||||||
|
public interface LocoSocektHandler {
|
||||||
|
|
||||||
|
void onPacket(LocoPacket packet);
|
||||||
|
|
||||||
|
void onConnect();
|
||||||
|
|
||||||
|
void onDisconnect();
|
||||||
|
|
||||||
|
void onError(Exception e);
|
||||||
|
|
||||||
|
}
|
||||||
139
src/main/java/com/github/netricecake/loco/LocoSocket.java
Normal file
139
src/main/java/com/github/netricecake/loco/LocoSocket.java
Normal file
@@ -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<Integer, Future<LocoPacket>> 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<SocketChannel>() {
|
||||||
|
@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<LocoPacket> 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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.loco.LocoPacket;
|
||||||
import com.github.netricecake.util.ByteUtil;
|
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.channel.ChannelHandlerContext;
|
||||||
import io.netty.handler.codec.MessageToMessageCodec;
|
import io.netty.handler.codec.MessageToMessageCodec;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.BlockingQueue;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
public class LocoCodec extends MessageToMessageCodec<byte[], LocoPacket> {
|
public class LocoCodec extends MessageToMessageCodec<byte[], LocoPacket> {
|
||||||
|
|
||||||
private LocoPacket currentLocoPacket = null;
|
private LocoPacket currentLocoPacket = null;
|
||||||
private byte[] buffer = new byte[0];
|
private byte[] buffer = new byte[0];
|
||||||
|
|
||||||
private BlockingQueue<LocoPacket> locoPacketQueue;
|
private final LocoSocket locoSocket;
|
||||||
|
|
||||||
public LocoCodec(BlockingQueue<LocoPacket> locoPacketHandler) {
|
public LocoCodec(LocoSocket locoSocekt) {
|
||||||
this.locoPacketQueue = locoPacketHandler;
|
this.locoSocket = locoSocekt;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -55,7 +57,15 @@ public class LocoCodec extends MessageToMessageCodec<byte[], LocoPacket> {
|
|||||||
byte[] body = ByteUtil.sliceBytes(buffer, 0, currentLocoPacket.getBodyLength());
|
byte[] body = ByteUtil.sliceBytes(buffer, 0, currentLocoPacket.getBodyLength());
|
||||||
buffer = ByteUtil.sliceBytes(buffer, currentLocoPacket.getBodyLength(), buffer.length - currentLocoPacket.getBodyLength());
|
buffer = ByteUtil.sliceBytes(buffer, currentLocoPacket.getBodyLength(), buffer.length - currentLocoPacket.getBodyLength());
|
||||||
currentLocoPacket.setBody(body);
|
currentLocoPacket.setBody(body);
|
||||||
locoPacketQueue.put(currentLocoPacket);
|
if (locoSocket.getWaitList().containsKey(currentLocoPacket.getPacketId())) {
|
||||||
|
((CompletableFuture<LocoPacket>) 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;
|
currentLocoPacket = null;
|
||||||
} while (buffer.length > 0);
|
} while (buffer.length > 0);
|
||||||
|
|
||||||
@@ -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.loco.crypto.CryptoManager;
|
||||||
import com.github.netricecake.util.ByteUtil;
|
import com.github.netricecake.loco.util.ByteUtil;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.handler.codec.MessageToMessageCodec;
|
import io.netty.handler.codec.MessageToMessageCodec;
|
||||||
|
|
||||||
@@ -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.Cipher;
|
||||||
import javax.crypto.KeyGenerator;
|
import javax.crypto.KeyGenerator;
|
||||||
import javax.crypto.spec.GCMParameterSpec;
|
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;
|
import java.security.spec.X509EncodedKeySpec;
|
||||||
|
|
||||||
public class CryptoManager {
|
public class CryptoManager {
|
||||||
@@ -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) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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 = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
package com.github.netricecake.loco.packet.inbound;
|
||||||
|
|
||||||
|
public class PingIn {
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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.loco.util.BsonUtil;
|
||||||
import com.github.netricecake.util.BsonUtil;
|
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
public class GetConfRequest implements LocoRequest {
|
public class GetConfOut {
|
||||||
|
|
||||||
private String MCCMNC;
|
private String MCCMNC;
|
||||||
|
|
||||||
private String os;
|
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.MCCMNC = MCCMNC;
|
||||||
this.os = os;
|
this.os = os;
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getMethod() {
|
|
||||||
return "GETCONF";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte[] toBson() {
|
public byte[] toBson() {
|
||||||
JsonObject jsonObject = new JsonObject();
|
JsonObject jsonObject = new JsonObject();
|
||||||
jsonObject.addProperty("MCCMNC", MCCMNC);
|
jsonObject.addProperty("MCCMNC", MCCMNC);
|
||||||
@@ -31,4 +24,5 @@ public class GetConfRequest implements LocoRequest {
|
|||||||
jsonObject.addProperty("userId", userId);
|
jsonObject.addProperty("userId", userId);
|
||||||
return BsonUtil.jsonObjectToBson(jsonObject);
|
return BsonUtil.jsonObjectToBson(jsonObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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 }");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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("{}");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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.loco.util.BsonUtil;
|
||||||
import com.github.netricecake.util.BsonUtil;
|
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
public class WriteRequest implements LocoRequest {
|
public class WriteOut {
|
||||||
|
|
||||||
private long chatId;
|
private long chatId;
|
||||||
private long msgId; // 이거 뭐임???
|
private long msgId = new SecureRandom().nextLong();
|
||||||
private String message;
|
private String message;
|
||||||
private int type = 1;
|
private int type = 1;
|
||||||
private boolean noSeen = false;
|
private boolean noSeen = false;
|
||||||
private String extra = "{}";
|
private String extra = "{}";
|
||||||
private int scope = 1;
|
private int scope = 1;
|
||||||
|
|
||||||
public WriteRequest() {
|
|
||||||
msgId = (long) Math.ceil(Math.random() * 99999999);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getMethod() {
|
|
||||||
return "WRITE";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte[] toBson() {
|
public byte[] toBson() {
|
||||||
JsonObject jsonObject = new JsonObject();
|
JsonObject jsonObject = new JsonObject();
|
||||||
jsonObject.addProperty("chatId", chatId);
|
jsonObject.addProperty("chatId", chatId);
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.github.netricecake.util;
|
package com.github.netricecake.loco.util;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.github.netricecake.util;
|
package com.github.netricecake.loco.util;
|
||||||
|
|
||||||
public class ByteUtil {
|
public class ByteUtil {
|
||||||
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
package com.github.netricecake.message;
|
|
||||||
|
|
||||||
public interface LocoRequest {
|
|
||||||
|
|
||||||
String getMethod();
|
|
||||||
|
|
||||||
byte[] toBson();
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
package com.github.netricecake.message;
|
|
||||||
|
|
||||||
public interface LocoResponse {
|
|
||||||
|
|
||||||
String getMethod();
|
|
||||||
|
|
||||||
void fromBson(byte[] bson);
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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 }");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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("{}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
package com.github.netricecake.network;
|
|
||||||
|
|
||||||
@FunctionalInterface
|
|
||||||
public interface LocoPacketHandler {
|
|
||||||
void onPacket(LocoPacket packet);
|
|
||||||
}
|
|
||||||
@@ -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<LocoPacket> 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<SocketChannel>() {
|
|
||||||
@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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
Manifest-Version: 1.0
|
|
||||||
Main-Class: com.github.netricecake.Main
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user