NiceDayZc/OkLine

GitHub: NiceDayZc/OkLine

一个非官方的 LINE Chrome 消息 API Python 客户端,通过完整复现官方扩展协议与签名机制,解决从 Python 自动化操作 LINE 账户的问题。

Stars: 1 | Forks: 0

# OkLine — LINE Chrome messaging API 的 Python 客户端 / SDK [![CI](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/5c0c81ae94011811.svg)](https://github.com/NiceDayZc/OkLine/actions/workflows/ci.yml) [![Python](https://img.shields.io/badge/python-3.9%2B-blue.svg)](https://www.python.org/) [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE) [![Tests](https://img.shields.io/badge/tests-392%20passing-brightgreen.svg)](tests/) [![Endpoints](https://img.shields.io/badge/endpoints-77-blue.svg)](docs/ENDPOINTS.md) [![PRs welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](docs/contributing.md) **OkLine** 是一个非官方的高级 **LINE Python 客户端 / SDK**,它 完整复现了官方 **LINE Chrome 扩展程序** (`CHROMEOS` 3.7.2) 的**每一个** endpoint。你可以用它**从 Python 中发送和接收 LINE 消息**, 通过**二维码或电子邮件**登录,并自动化操作你自己的账户——逐字节完美复现真实 协议(包括网关、headers、payloads、通过 LINE 真实的 `ltsm.wasm` 实现的强制性 `X-Hmac` 签名、登录加密、SSE 事件流以及 OBS 媒体),并**记录每一次响应**,方便你直接复制粘贴。 `import okline` · `from okline import OkLine` **核心亮点** - ✅ 全部 77 个 Thrift endpoint,支持类型提示;也支持通用化调用其中的任何一个。 - ✅ 自动处理强制性的 `X-Hmac` 签名(运行真实的 WASM)。 - ✅ 支持电子邮件 (RSA) **及** 二维码登录 —— 二维码会在你的终端中以 ASCII 形式渲染。 - ✅ **完整的响应记录** —— 可以复制每一个 endpoint 的响应。 - ✅ 提供一个 CLI (`python -m okline …`) 以便从 shell 中调用任何 endpoint。 ## ⚠️ 法律 / 免责声明 本项目仅用于**互操作性、研究及操作你自己的账户**。使用 它必须遵守 LINE 的服务条款。请勿用于发送垃圾信息、抓取 他人数据或任何滥用行为。你需要对自己的使用方式负责。 ## 安装 ``` pip install -r requirements.txt # requests + cryptography # 可选: pip install qrcode # 用于渲染 QR 登录码 ``` 需要 Python 3.9+。**Node.js 18+ 也必须配置在你的 PATH 中** —— 因为计算 强制性的 `X-Hmac` 请求签名(见下文)需要用到它。 ## ⭐ X-Hmac 请求签名(必需) 网关会拒绝任何缺少有效 **`X-Hmac`** header 的请求 (`REQUEST_INVALID_HMAC`,错误码 10005)。该签名由 LINE 的 安全 WASM 模块 (`ltsm.wasm`) 生成,因此本库内置了真实的模块,并 通过一个微型的持久化 **Node.js bridge** 运行它,像扩展程序一样为每个请求进行签名: ``` X-Hmac = base64( Hmac( deriveKey( SHA256("3.7.2"), SHA256(accessToken) ) ) .digest(path + body) ) ``` 只要 `node` 在你的 PATH 中,它就能“直接运行”——该 bridge 会在 第一次请求时延迟启动,并会被后续重复使用。配置: ``` from okline import OkLine, LineConfig api = OkLine(config=LineConfig( node_path="node", # or an absolute path; env LINE_NODE also works enable_hmac=True, # set False only for offline/mocked tests )) ``` 内置的 `ltsm.wasm` + token 是特定于此扩展版本的 (`chrome-extension://ophjlpahpchlmihnnnihgmmeilfjmjjc`, v3.7.2)。如果你替换了 不同版本的构建产物,请使用 `LineConfig(ltsm_origin=...)` 或环境变量 `LTSM_ORIGIN` 覆盖 origin。 ## 协议工作原理 | 层级 | 详情 | |-------|--------| | **网关** | `https://line-chrome-gw.line-apps.com` | | **RPC 形式** | `POST /api/talk/thrift///` | | **Body** | 一个由位置 Thrift 参数组成的 JSON **数组**;结构体参数是带有**命名** (camelCase) 字段的普通 JSON 对象 | | **Auth header** | `X-Line-Access: ` | | **App header** | `X-Line-Application: CHROMEOS\t3.7.2\tChrome_OS\t` | | **Version header** | `X-Line-Chrome-Version: 3.7.2` | | **Signature** | 每个请求都带有 `X-Hmac: ` (由 `ltsm.wasm` 计算,见上文) | | **Locale** | `X-LAL: en_US` + `Accept-Language: en-US` | | **接收** | SSE `GET /api/operation/receive` (+ 长轮询 `/api/talk/long-polling/LF1`,`/JQ`) | | **Token 刷新** | `POST /api/auth/tokenRefresh` `{refreshToken}` | | **媒体** | OBS `obs.line-apps.com` + 网关 `/api/obs/*` | 示例 —— `sendMessage(reqSeq, Message)` 变为: ``` POST /api/talk/thrift/Talk/TalkService/sendMessage X-Line-Access: X-Line-Application: CHROMEOS 3.7.2 Chrome_OS content-type: application/json [1, {"to":"u...","toType":0,"text":"hi","contentType":0,"contentMetadata":{},"sessionId":0}] ``` 包含所有 77 个 endpoint 及其参数字段和示例 payload 的完整生成列表位于 **[`docs/ENDPOINTS.md`](docs/ENDPOINTS.md)**。 ## 快速开始 ``` from okline import OkLine, enums # A) 复用现有的 access token (例如: 从运行中的 extension 中捕获的) api = OkLine(access_token="...", refresh_token="...") print(api.get_profile()) api.send_text("u0123456789abcdef0123456789abcdef", "hello from python") # B) 使用 e-mail + password 登录 (RSA flow, 与 extension 完全一致) api = OkLine() res = api.auth.email_login("me@example.com", "secret", with_e2ee=False) if res.success: api.send_text("u....", "hi!") # C) 使用手机扫描 QR code 登录 api = OkLine() api.auth.qr_login(on_qr=print, on_pin=lambda pin: print("PIN:", pin)) ``` ## 身份验证 共有三种高度还原的流程,均位于 `api.auth` 下(参见 [`auth.py`](okline/auth.py)): ### 电子邮件 + 密码 (RSA) ``` res = api.auth.email_login(email, password, with_e2ee=True) # 内部: getRSAKeyInfo -> RSA/PKCS1v1.5 encrypt # chr(len(sessionKey))+sessionKey+chr(len(email))+email+chr(len(pw))+pw # -> loginV2(LoginRequest{identifier=keynm, password=, ...}) ``` ### 二维码(辅助设备登录) ``` from okline.qrterm import print_qr api.auth.qr_login(on_qr=lambda url: print_qr(url), # renders an ASCII QR in the terminal on_pin=lambda pin: print("PIN:", pin)) # createSession -> createQrCode -> curveKeyGenerate (在 WASM 中) # -> 显示 QR (callbackUrl + ?secret=&e2eeVersion=1) # -> checkQrCodeVerified (long-poll) -> verifyCertificate / PIN flow # -> qrCodeLoginV2 (签发 token) -> 尽力而为的 E2EE keychain unwrap ``` `?secret=…&e2eeVersion=1` 是**强制必需的** —— 如果缺少它,LINE App 在 扫码后会立即显示“发生错误”。本库会在真实的 `ltsm.wasm` 内部生成 Curve25519 密钥(通过与 `X-Hmac` 相同的 Node bridge),并自动将其追加到后面,因此你只需渲染 `on_qr` 提供给你的 URL 即可。 ### Token 刷新(自动) 如果你提供了 `refresh_token`,当遇到 `401` 错误时会自动触发 `POST /api/auth/tokenRefresh`,并重试该请求。 ## 发送消息 ``` api.send_text(to, "plain text") api.reply_text(to, "a reply", related_message_id="140000...") api.send_sticker(to, package_id="11537", sticker_id="52002734") api.send_location(to, 35.6586, 139.7454, title="Tokyo Tower") api.send_contact(to, contact_mid="u....") api.send_flex(to, "alt text", {"type": "bubble", ...}) # 底层: 自行构建任何 Message from okline import Message api.send_message(Message.text(to, "hi", content_metadata={"AGENT_NAME": "bot"})) # reactions, unsend, read receipts api.react("140000...", enums.PredefinedReactionType.LOVE) api.cancel_reaction("140000...") api.unsend_message("140000...") api.send_chat_checked(chat_mid, last_message_id="140000...") # mark read ``` `to` 可以是用户 (`u…`)、房间 (`r…`) 或群组/聊天 (`c…`) 的 mid —— 消息 构建器会自动检测 `toType`。 ## 接收消息 ``` for op in api.ops.iter_operations(): # SSE stream, auto-reconnect if op.type == enums.OpType.RECEIVE_MESSAGE and op.message: print(op.message["from"], op.message.get("text")) ``` 或者通过 `api.ops.stream()` 获取原始的 SSE 事件(`ping`、`fullSync` 等)。 ## 记录 —— 复制每个 endpoint 的响应 记录功能**默认开启**。每个请求/响应都会被完整捕获 (包括方法、URL、所有 headers、body、状态码、耗时),并保存为一个 `Exchange`: ``` api = OkLine(access_token="...") # record=True, redact=True by default api.get_profile() api.send_text("u...", "hi") print(api.last.pretty()) # the most recent call, as an HTTP transcript print(api.dump()) # every call this session api.history # list[Exchange] api.recorder.find("Talk.TalkService.getProfile") # filter by endpoint # 导出 api.save_log("session.txt") # plain transcript api.save_log("session.har", fmt="har") # open in browser devtools api.save_log("session.json", fmt="json") # secrets (token / X-Hmac / passwords) 默认会被遮蔽 — 通过以下方式显示: print(api.last.pretty(redact=False)) api = OkLine(access_token="...", redact=False) # 对每次 call 实时 react: @api.on_exchange def _(ex): print(ex.seq, ex.endpoint, ex.status, f"{ex.duration_ms:.0f}ms") ``` 使用 `OkLine(record=False)` 可禁用此功能。设置 `LINE_DEBUG=1` 还会将原始的 body 输出到 stderr 中。 ## CLI 直接从 shell 调用任何 endpoint 并复制其响应: ``` python -m okline endpoints # list every endpoint key (optionally grep) python -m okline version # call 任何 endpoint (参数 = 作为 JSON array 的 positional thrift args) python -m okline call Talk.TalkService.getProfile "[2]" --token "$TOKEN" python -m okline call Talk.TalkService.sendMessage \ '[0,{"to":"u...","text":"hi","contentType":0,"contentMetadata":{}}]' --token "$TOKEN" python -m okline call LoginQrCode.SecondaryQrCodeLoginService.createSession "[{}]" --no-auth --raw # 通过扫描终端 QR 登录, 然后保存 tokens python -m okline qr-login --save tokens.json python -m okline profile --token "$TOKEN" --raw # --raw prints the full transcript ``` `--raw` 会打印完整的 HTTP 记录;`--show-secrets` 会显示未被掩盖的 token。Token 来源于 `--token`/`--refresh` 或 `LINE_ACCESS_TOKEN`/`LINE_REFRESH_TOKEN`。 ## 完整方法映射表 每个 endpoint 都在 `OkLine` 上有一个带类型提示的方法(并且可以通过 `api.call("Namespace.Service.method", *args)` 进行通用调用)。 | 领域 | 方法 | |------|---------| | **Auth** | `auth.email_login`, `auth.qr_login`, `auth.refresh_access_token`, `login_v2`, `logout_v2`, `confirm_e2ee_login`, `get_rsa_key_info`, `get_encrypted_identity_v3`, `acquire_encrypted_access_token` | | **Messaging** | `send_message`/`send_text`/`send_sticker`/`send_location`/`send_contact`/`send_flex`/`reply_text`, `unsend_message`, `send_postback`, `react`, `cancel_reaction`, `send_chat_checked`, `send_chat_removed`, `set_chat_hidden_status`, `get_recent_messages`, `get_previous_messages`, `get_messages_by_ids`, `get_message_boxes`, `get_message_boxes_by_ids`, `get_message_read_range`, `determine_media_message_flow`, `get_last_op_revision` | | **Contacts** | `get_all_contact_ids`, `get_contacts`, `find_contact_by_userid`, `find_contacts_by_phone`, `find_and_add_contacts_by_mid`, `block_contact`, `unblock_contact`, `get_blocked_contact_ids`, `update_contact_setting`, `set_favorite`, `hide_contact`, `get_favorite_mids`, `get_recommendation_ids`, `get_blocked_recommendation_ids`, `block_recommendation`, `add_friend_by_mid`, `get_target_profile_notice`, `get_buddy_detail` | | **Chats / Groups / Rooms** | `create_chat`/`create_group`, `update_chat`, `rename_chat`, `set_chat_favorite`, `invite_into_chat`, `kick_from_chat`, `cancel_chat_invitation`, `leave_chat`, `accept_chat_invitation`, `reject_chat_invitation`, `get_all_chat_mids`, `get_chats`, `invite_into_room`, `leave_room`, `get_rooms` | | **Profile / Settings** | `get_profile`, `update_profile_attributes`, `set_display_name`, `set_status_message`, `get_settings`, `get_settings_attributes2`, `update_settings_attributes2`, `get_configurations`, `get_server_time`, `report_abuse` | | **E2EE keys** | `get_e2ee_public_key`, `negotiate_e2ee_public_key`, `get_e2ee_public_keys_ex`, `get_last_e2ee_public_keys`, `register_e2ee_group_key`, `get_e2ee_group_shared_key`, `get_last_e2ee_group_shared_key` | | **Channel / Shop / OBS** | `issue_channel_token`, `get_owned_product_summaries`, `iter_owned_products`, `preview_customized_image_text`, `set_customized_image_text`, `obs.upload_profile_image`, `obs.upload_object`, `obs.download_object`, `obs.copy_for_message` | ## 包结构 ``` okline/ client.py OkLine facade (transport + auth + ops + obs + recorder + services) transport.py HTTP engine: headers, X-Hmac, JSON encode/decode, errors, recording hmac_signer.py LtsmBridge — manages the Node bridge (X-Hmac + Curve25519/E2EE) ltsm/ ltsm.wasm + ltsmSandbox.js + ltsm_bridge.js (LINE's real module) auth.py email / QR / token-refresh login flows crypto.py RSA/PKCS1v1.5 login credential encryption operations.py SSE + long-poll operation receiver obs.py object storage (media) upload/download recorder.py Exchange + Recorder (capture/redact/pretty/HAR/JSON) qrterm.py render a QR as ASCII/Unicode in the terminal enums.py all enums (OpType, ContentType, ErrorCode, ...) — extracted verbatim models.py Message builders (text/sticker/location/contact/flex) endpoints.py complete endpoint registry (all 77 paths) exceptions.py OkLine error hierarchy services/ one typed method per endpoint, grouped by area __main__.py the `python -m okline` CLI selftest.py live read-only self-test of every endpoint docs/ full documentation (see below) example.py runnable examples tests/ 392 offline tests (conftest fixtures + per-module files) ``` ## 📚 文档 | 页面 | 内容 | |------|---------------| | [入门指南](docs/getting-started.md) | 安装、你的第一次调用、`OkLine` 对象 | | [身份验证](docs/authentication.md) | token 复用、电子邮件 (RSA)、二维码登录、刷新、登出 | | [发送消息](docs/messaging.md) | 文本、贴图、位置、联系人、flex、回应 | | [接收事件](docs/receiving-events.md) | SSE 流、一个回声机器人 | | [记录](docs/recording.md) | 捕获、粘贴、脱敏并导出每一次响应 | | [CLI](docs/cli.md) | `python -m okline` —— 调用任何 endpoint,`selftest`,`qr-login` | | [架构](docs/architecture.md) | 协议、`X-Hmac`、模块映射 | | [故障排除](docs/troubleshooting.md) | 常见错误与修复 (FAQ) | | [贡献指南](docs/contributing.md) | 开发设置、测试、添加 endpoint | | [Endpoint 参考](docs/ENDPOINTS.md) | 包含参数字段的每一个 endpoint | ## 测试 ``` python -m pytest -q # 392 offline tests, no network/Node needed ``` ## 关于保真度的说明 - 枚举值、endpoint 路径、header 字符串以及 RSA 登录格式均**逐字** 提取自扩展程序包。 - 每个方法的参数*顺序*与网络传输格式保持一致(已通过调用点验证)。 - E2EE(Letter Sealing)密钥的 **endpoint** 已实现;执行实际的 Curve25519 ECDH + AES 消息加密由调用者自行完成(密钥结构体将 以原始形式返回)。非 E2EE 消息传递可直接开箱即用。 - 当你不传入 `reqSeq` 时,它将自动生成(单调递增)。 ## 发布至 GitHub 创建仓库后,请设置一个富含关键字的**描述**和**主题**(这是 影响 GitHub 搜索结果的两个最重要因素),并替换徽章和 `pyproject.toml` URL 中的 `NiceDayZc`: ``` gh repo create OkLine --public --source . --remote origin --push \ --description "Unofficial Python client/SDK for the LINE Chrome messaging API — send/receive LINE messages, QR & e-mail login, X-Hmac signing, full response recording." # Topics (GitHub 最多允许 20 个) — 它们影响可发现性: gh repo edit --add-topic line,line-api,line-bot,line-messaging-api,line-chrome \ --add-topic python,python-line,line-sdk,line-client,unofficial \ --add-topic messaging,chatbot,automation,reverse-engineering,chrome-extension ``` 推荐的**主题**:`line` · `line-api` · `line-bot` · `line-messaging-api` · `line-chrome` · `python` · `python-line` · `line-sdk` · `line-client` · `unofficial` · `messaging` · `chatbot` · `automation` · `reverse-engineering` · `chrome-extension`。 ## 免责声明 OkLine 是一个**非官方、独立**的项目,**不隶属于 LINE Corporation,也未获得其认可或赞助**。“LINE”是其 各自所有者的商标。请仅在遵守 LINE [服务条款](https://terms.line.me/line_terms) 的前提下使用**你自己的账户**。你需对 你的使用方式负责。有关凭证的处理,请参阅 [SECURITY.md](SECURITY.md)。 ## 许可证 [MIT](LICENSE) © OkLine 贡献者。
标签:MITM代理, Python, 即时通讯, 无后门, 网络调试, 自动化, 逆向工具