์ด ํ๋ก์ ํธ๋ ์นด์นด์คํก ์๋๋ก์ด๋ ์ฑ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ฐ๋ํ์ฌ HTTP ๊ธฐ๋ฐ ์ฑํ ๋ด์ ์์ฑํ ์ ์๋ ํ๊ฒฝ์ ์ ๊ณตํฉ๋๋ค.
ํ๋ก์ ํธ ์ํ: ๋ฒ ํ
- ์๋๋ก์ด๋ ๊ธฐ๊ธฐ: ์ด ์ ํ๋ฆฌ์ผ์ด์ ์ ์นด์นด์คํก์ด ์ค์น๋์ด ์๋ ์๋๋ก์ด๋ ๊ธฐ๊ธฐ์์ ์คํ๋๋๋ก ์ค๊ณ๋์์ต๋๋ค.
- ๋ฃจํธ ๊ถํ: ์นด์นด์คํก ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ผ๋ถ ์์คํ ์๋น์ค์ ์ ๊ทผํ๊ธฐ ์ํ์ฌ ๋ฃจํธ ๊ถํ์ด ํ์ํฉ๋๋ค.
- HTTP ์๋ฒ ๋๋ WebSocket ํด๋ผ์ด์ธํธ: Iris์ ์ํธ ์์ฉํ์ฌ ๋ฉ์์ง๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ์ํ ๋ณ๋์ HTTP ์๋ฒ๋ WebSocket ํด๋ผ์ด์ธํธ๊ฐ ํ์ํฉ๋๋ค.
-
์ต์ Iris๋ฅผ Releases์์ ๋ค์ด๋ก๋ํ์ธ์.
-
ํ์ผ ๋ณต์ฌ: adb๋ฅผ ์ฌ์ฉํ์ฌ Iris apk ํ์ผ์ ์๋๋ก์ด๋ ํ๊ฒฝ์ ๋ณต์ฌํ์ธ์.
adb push Iris.apk /data/local/tmp
-
apk ํ์ผ ์คํ:
iris_control์ ์คํ ๊ฐ๋ฅํ๊ฒ ๋ง๋์ธ์.(์๋์ฐ ์ด์ฉ์๋ skip)
chmod +x iris_control
์คํํ๋ ค๋ฉด iris_control์ ์ฌ์ฉํ์ธ์.(์๋์ฐ ์ด์ฉ์๋ ./iris_control.ps1)
./iris_control start
iris_control์ install/start/status/stop ๋ช ๋ น์ด๋ฅผ ์ ๊ณตํฉ๋๋ค.
-
Config ์ค์ :
http://[ANDROID_IP]:3000/dashboard์ ๋ธ๋ผ์ฐ์ ๋ฅผ ํตํด ์ ์ํ์ฌ, ์ค์ ์ ์งํํฉ๋๋ค.
Iris๋ ๊ธฐ๋ณธ์ ์ผ๋ก HTTP ํ๋กํ ์ฝ์ ํตํด ์ ๋ณด๋ฅผ ์ฃผ๊ณ ๋ฐ์ต๋๋ค.
๋ชจ๋ ์์ฒญ์ ๋ณ๋๋ก ๋ช
์๋์ง ์๋ ํ Content-Type: application/json๊ณผ ํจ๊ป POST ์์ฒญ์ผ๋ก ๋ณด๋ด์ผ ํฉ๋๋ค.
-
/reply: ์นด์นด์คํก ์ฑํ ๋ฐฉ์ ๋ฉ์์ง ๋๋ ์ฌ์ง์ ๋ณด๋ ๋๋ค.์์ฒญ ๋ณธ๋ฌธ (JSON):
{ "type": "text", // ๋๋ "image", "image_multiple" "room": "[CHAT_ROOM_ID]", // ์ฑํ ๋ฐฉ ID (๋ฌธ์์ด) "data": "[MESSAGE_TEXT]" // ํ ์คํธ ๋ฉ์์ง์ ๊ฒฝ์ฐ // ์ด๋ฏธ์ง ๋ฉ์์ง์ ๊ฒฝ์ฐ Base64 ์ธ์ฝ๋ฉ๋ ์ด๋ฏธ์ง ๋ฌธ์์ด // ์ฌ๋ฌ ์ด๋ฏธ์ง ๋ฉ์์ง์ ๊ฒฝ์ฐ Base64 ์ธ์ฝ๋ฉ๋ ์ด๋ฏธ์ง ๋ฌธ์์ด์ ๋ฆฌ์คํธ }์์ (ํ ์คํธ ๋ฉ์์ง):
curl -X POST -H "Content-Type: application/json" -d '{"type": "text", "room": "1234567890", "data": "SendMsgDB์์ ๋ณด๋ธ ๋ฉ์์ง!"}' http://[YOUR_DEVICE_IP]:[bot_http_port]/reply
์์ (์ด๋ฏธ์ง ๋ฉ์์ง):
curl -X POST -H "Content-Type: application/json" -d '{"type": "image", "room": "1234567890", "data": "[BASE64_ENCODED_IMAGE_DATA]"}' http://[YOUR_DEVICE_IP]:[bot_http_port]/reply curl -X POST -H "Content-Type: application/json" -d '{"type": "image_multiple", "room": "1234567890", "data": [BASE64_ENCODED_IMAGE_DATA1,BASE64_ENCODED_IMAGE_DATA2,BASE64_ENCODED_IMAGE_DATA3]}' http://[YOUR_DEVICE_IP]:[bot_http_port]/reply
-
/query: ์นด์นด์คํก ๋ฐ์ดํฐ๋ฒ ์ด์ค์ SQL ์ฟผ๋ฆฌ๋ฅผ ์คํํฉ๋๋ค. ์ด ๋ฉ์๋๋ ์๋ต์์ ์ํธํ๋ ๋ฐ์ดํฐ ํ๋๋ฅผ ์๋์ผ๋ก ๋ณตํธํํฉ๋๋ค.message๋๋attachment๋ฅผuser_id๋ฐenc์ ํจ๊ป ์ฟผ๋ฆฌํ๋ฉด ๋ณตํธํ๋ ๊ฐ์ ๋ฐํํฉ๋๋ค.nickname,profile_image_url,full_profile_image_url๋๋original_profile_image_url์enc์ ํจ๊ป ์ฟผ๋ฆฌํ๋ฉด ๋ณตํธํ๋ ๊ฐ์ ๋ฐํํฉ๋๋ค.์์ฒญ ๋ณธ๋ฌธ (JSON):
// ๋จ์ผ ์์ฒญ { "query": "[SQL_QUERY]", // SQL ์ฟผ๋ฆฌ ๋ฌธ์์ด "bind": ["[BINDING_VALUE_1]", "[BINDING_VALUE_2]", ...] // ์ฟผ๋ฆฌ์ ๋ํ ์ ํ์ ๋ฐ์ธ๋ฉ }
์์ (๋ฐ์ธ๋ฉ์ ์ฌ์ฉํ ๋จ์ผ ์ฟผ๋ฆฌ):
curl -X POST -H "Content-Type: application/json" -d '{"query": "SELECT _id, chat_id, user_id, message FROM chat_logs WHERE user_id = ? ORDER BY _id DESC LIMIT 5", "bind": ["1234567890"]}' http://[YOUR_DEVICE_IP]:[bot_http_port]/query
์์ (๋ฒํฌ ์ฟผ๋ฆฌ):
curl -X POST -H "Content-Type: application/json" -d '{"queries": [{"query": "SELECT _id, chat_id, user_id, message FROM chat_logs ORDER BY _id DESC LIMIT 5", "bind": []}, {"query": "SELECT name FROM db2.friends LIMIT 2", "bind": []}]}' http://[YOUR_DEVICE_IP]:[bot_http_port]/query
์๋ต (JSON):
{ "data": [ // ์ฟผ๋ฆฌ ๊ฒฐ๊ณผ ๋ฐฐ์ด, ๊ฐ ๊ฒฐ๊ณผ๋ ์ด ์ด๋ฆ๊ณผ ๊ฐ์ ๋งต์ ๋๋ค. { "_id": "...", "chat_id": "...", "user_id": "...", "message": "...", // ํด๋ ๋ ๋ฉ์์ง ๋ด์ฉ // ... ๊ธฐํ ์ด ... }, // ... ๋ ๋ง์ ๊ฒฐ๊ณผ ... ] } -
/decrypt: ์นด์นด์คํก ๋ฉ์์ง๋ฅผ ๋ณตํธํํฉ๋๋ค.์์ฒญ ๋ณธ๋ฌธ (JSON):
{ "enc": [ENCRYPTION_TYPE], // ์ํธํ ์ ํ (๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ๊ฐ์ ธ์จ ์ ์) "b64_ciphertext": "[BASE64_ENCODED_CIPHERTEXT]", // Base64 ์ธ์ฝ๋ฉ๋ ์ํธํ๋ ๋ฉ์์ง "user_id": [USER_ID] // ์ฌ์ฉ์ ID (long integer) }์์:
curl -X POST -H "Content-Type: application/json" -d '{"enc": 0, "b64_ciphertext": "[ENCRYPTED_MESSAGE_BASE64]", "user_id": 1234567890}' http://[YOUR_DEVICE_IP]:[bot_http_port]/decrypt
์๋ต (JSON):
{ "plain_text": "[DECRYPTED_MESSAGE_TEXT]" } -
/aot(GET): aot ๊ด๋ จ ํ ํฐ์ ๋ฆฌํดํฉ๋๋ค.์์:
curl -X GET http://[YOUR_DEVICE_IP]:[bot_http_port]/aot
์๋ต (JSON):
{ "success": true, "aot" : { "access_token" : String, "refresh_token" : String, "token_type" : String, "d_id" : String } }
-
/dashboard(GET): Iris ๋ฅผ ์ค์ ํ๊ธฐ ์ํ ์น UI๋ฅผ ์ ๊ณตํฉ๋๋ค. ์น ๋ธ๋ผ์ฐ์ ์์ ์ด URL์ ์ด์ด ์ค์ ์ ์์ ํ์ธ์.์์:
# ์น ๋ธ๋ผ์ฐ์ ์์ ์ฌ์ธ์ http://[YOUR_DEVICE_IP]:[bot_http_port]/dashboard์ด ์๋ํฌ์ธํธ๋ ์น ์๋ฒ ์๋ํฌ์ธํธ, ๋ฐ์ดํฐ๋ฒ ์ด์ค ํด๋ง ์๋, ๋ฉ์์ง ์ ์ก ์๋์ ๊ฐ์ ๊ตฌ์ฑ์ ์ฌ์ฉ์ ์นํ์ ์ธ ์ธํฐํ์ด์ค๋ฅผ ํตํด ๋ณด๊ณ ์ ๋ฐ์ดํธํ ์ ์๋ ์น ํ์ด์ง๋ฅผ ์ ๊ณตํฉ๋๋ค.
-
/config(GET): ํ์ฌ ๊ตฌ์ฑ์ JSON ์๋ต์ผ๋ก ๊ฒ์ํฉ๋๋ค. ํ์ฌ ํ์ฑ ์ค์ ์ ํ์ธํ๋ ๋ฐ ์ ์ฉํฉ๋๋ค.์์:
curl http://[YOUR_DEVICE_IP]:[bot_http_port]/config
์๋ต (JSON):
{ "bot_name": "[YOUR_BOT_NAME]", "bot_http_port": [PORT_FOR_HTTP_SERVER], "web_server_endpoint": "[YOUR_WEB_SERVER_URL_FOR_MESSAGE_FORWARDING], "db_polling_rate": [DATABASE_POLLING_INTERVAL_IN_MILLISECONDS], "message_send_rate": [MESSAGE_SEND_INTERVAL_IN_MILLISECONDS], "bot_id": [YOUR_KAKAO_TALK_USER_ID] } -
/config/endpoint(POST): ๋ฉ์์ง ์ ๋ฌ์ ์ํ ์น ์๋ฒ ์๋ํฌ์ธํธ๋ฅผ ์ ๋ฐ์ดํธํฉ๋๋ค.์์ฒญ ๋ณธ๋ฌธ (JSON):
{ "endpoint": "[YOUR_WEB_SERVER_URL]" }์์:
curl -X POST -H "Content-Type: application/json" -d '{"endpoint": "http://192.168.1.100:5000/new_messages"}' http://[YOUR_DEVICE_IP]:[bot_http_port]/config/endpoint
-
/config/dbrate(POST): ๋ฐ์ดํฐ๋ฒ ์ด์ค ํด๋ง ์๋๋ฅผ ์ ๋ฐ์ดํธํฉ๋๋ค. ์ด ๊ฐ์ ์กฐ์ ํ๋ฉด Iris๊ฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์ ๋ฉ์์ง๋ฅผ ํ์ธํ๋ ๋น๋๊ฐ ๋ณ๊ฒฝ๋ฉ๋๋ค. ๊ฐ์ด ๋ฎ์์๋ก CPU ์ฌ์ฉ๋์ด ์ฆ๊ฐํ์ง๋ง ๋ฉ์์ง ๊ฐ์ง๊ฐ ๋ ์ฆ๊ฐ์ ์ผ ์ ์์ต๋๋ค.์์ฒญ ๋ณธ๋ฌธ (JSON):
{ "rate": [DATABASE_POLLING_INTERVAL_IN_MILLISECONDS] }์์:
curl -X POST -H "Content-Type: application/json" -d '{"rate": 300}' http://[YOUR_DEVICE_IP]:[bot_http_port]/config/dbrate
-
/config/sendrate(POST): ๋ฉ์์ง ์ ์ก ์๋๋ฅผ ์ ๋ฐ์ดํธํฉ๋๋ค. ์ด๋ ์นด์นด์คํก์ผ๋ก ๋ฉ์์ง๋ฅผ ๋ณด๋ด๋ ์ต์ ๊ฐ๊ฒฉ์ ์ ์ดํ์ฌ ์ ์ก ๋น๋๋ฅผ ๊ด๋ฆฌํ๋ ๋ฐ ๋์์ด ๋ฉ๋๋ค.์์ฒญ ๋ณธ๋ฌธ (JSON):
{ "rate": [MESSAGE_SEND_INTERVAL_IN_MILLISECONDS] }์์:
curl -X POST -H "Content-Type: application/json" -d '{"rate": 200}' http://[YOUR_DEVICE_IP]:[bot_http_port]/config/sendrate
-
/config/botport(POST): ๋ด HTTP ์๋ฒ ํฌํธ๋ฅผ ์ ๋ฐ์ดํธํฉ๋๋ค. ์ฐธ๊ณ : ์ด ๋ณ๊ฒฝ ์ฌํญ์ ์ ์ฉํ๋ ค๋ฉด Iris๋ฅผ ์ฌ์์ํด์ผ ํฉ๋๋ค.์์ฒญ ๋ณธ๋ฌธ (JSON):
{ "port": [NEW_PORT_NUMBER] }์์:
curl -X POST -H "Content-Type: application/json" -d '{"port": 3001}' http://[YOUR_DEVICE_IP]:[bot_http_port]/config/botport
/ws: WebSocket ์ฐ๊ฒฐ์ ์์ฑํฉ๋๋ค.
Iris๊ฐ ์นด์นด์คํก ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์ ๋ฉ์์ง๋ฅผ ๊ฐ์งํ๋ฉด /config/endpoint API๋ฅผ ํตํด ๊ตฌ์ฑ๋ web_server_endpoint๋ก POST ์์ฒญ์ ๋ณด๋
๋๋ค.
๋ํ, /ws๋ฅผ ํตํด WebSocket์ด ์ฐ๊ฒฐ๋์ด ์๋ค๋ฉด, WebSocket์ผ๋ก๋ ์๋์ ์ด๋ฒคํธ๋ฅผ ์ ๋ฌํฉ๋๋ค.
{
"msg": "[DECRYPTED_MESSAGE_CONTENT]", // ๋ณตํธํ๋ ๋ฉ์์ง ๋ด์ฉ
"room": "[CHAT_ROOM_NAME]", // ์ฑํ
๋ฐฉ ์ด๋ฆ ๋๋ 1:1 ์ฑํ
์ ๊ฒฝ์ฐ ๋ฐ์ ์ ์ด๋ฆ
"sender": "[SENDER_NAME]", // ๋ฉ์์ง ๋ฐ์ ์ ์ด๋ฆ
"json": { // 'chat_logs' ํ
์ด๋ธ์ ์์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ (JSON ํ์)
"_id": "...",
"chat_id": "...",
"user_id": "...",
"message": "[DECRYPTED_MESSAGE_CONTENT]", // ๋ณตํธํ๋ ๋ฉ์์ง ๋ด์ฉ, "msg" ํ๋์ ๋์ผ
"attachment": "[DECRYPTED_ATTACHMENT_INFO]", // ๋ณตํธํ๋ attachment ๋ด์ฉ
"v": "{\"enc\": 0, ...}", // ์๋ 'v' ์ด ๊ฐ (JSON ํ์)
// ... chat_logs ํ
์ด๋ธ์ ๊ธฐํ ์ด ...
}
}- SendMsg & Initial Concept: Based on the work of
ye-seola/go-kdb. - KakaoTalk Decryption Logic: Decryption methods from
jiru/kakaodecrypt.
This project is provided for educational and research purposes only. The developers are not responsible for any misuse or damage caused by this software. Use it at your own risk and ensure you comply with all applicable laws and terms of service.
This project contains a mix of MIT-licensed and GPL-licensed code.
- Original Code: All files in this repository, unless otherwise noted, are licensed under the MIT License. See
LICENSE-MITfor details. - Third-Party Code: The specific file located at
src/main/java/party/qwer/iris/NotificationPoller.ktis partially derived from an external project and is licensed under the GNU General Public License v3.0. SeeLICENSE-GPLfor details.
Important: Because this project compiles together with GPL v3.0 code, the final compiled application as a whole is subject to the terms of the GPL v3.0.