AIButton
根据描述自动生成符合规范的Vision Node AI按钮控件ZIP包。
通过 Chrome 扩展网关集成 LINE 消息功能,支持收发消息、管理联系人与群组。
openclaw skills install @2manslkh/line-api命令、参数、文件名以原文为准
通过 Chrome 扩展网关 JSON API 实现的完整 LINE 消息客户端。
/data/workspace/line-client ([github.com/2manslkh/line-api](https://github.com/2manslkh/line-api))src/chrome_client.py → LineChromeClientsrc/auth/qr_login.py → QRLoginsrc/hmac/signer.js (Node.js,自动在端口 18944 启动)~/.line-client/tokens.json~/.line-client/sqr_certlstm.wasm + lstmSandbox.js(必需,位于仓库根目录)import json
from pathlib import Path
from src.chrome_client import LineChromeClient
tokens = json.loads((Path.home() / ".line-client" / "tokens.json").read_text())
client = LineChromeClient(auth_token=tokens["auth_token"])
# 发送消息
client.send_message("U...", "Hello!")
# 获取个人资料
profile = client.get_profile()令牌有效期约为 7 天。若过期(返回 APIError(10051)),需重新执行二维码登录。
二维码登录需要用户交互:在手机上扫描二维码并输入验证码。
from src.hmac import HmacSigner
from src.auth.qr_login import QRLogin
import qrcode
signer = HmacSigner(mode="server")
login = QRLogin(signer)
result = login.run(
on_qr=lambda url: send_qr_image_to_user(qrcode.make(url)),
on_pin=lambda pin: send_pin_to_user_IMMEDIATELY(pin), # 极其敏感!
on_status=lambda msg: print(msg),
)
# result.auth_token, result.mid, result.refresh_token重要提示: 验证码必须在约 60 秒内送达用户。一旦触发 on_pin,应立即发送。
createSession → 生成会话 IDcreateQrCode → 返回回调 URL(附加 ?secret={curve25519_pubkey}&e2eeVersion=1)checkQrCodeVerified — 轮询直到被扫描(使用 X-Line-Session-ID,不带 origin 头)verifyCertificate** — 即使失败也必须调用(状态转移必需)createPinCode → 生成 6 位数字验证码(若步骤 4 已验证证书则跳过)checkPinCodeVerified — 轮询直到用户输入验证码qrCodeLoginV2 → 返回 JWT 令牌、证书和刷新令牌python scripts/qr_login_server.py /tmp/qr.png向标准输出输出 JSON 事件:{"event": "qr", "path": "...", "url": "..."},{"event": "pin", "pin": "123456"},{"event": "done", "mid": "U..."}。
| 方法 | 参数 | 描述 |
|---|---|---|
get_profile() | — | 获取自己的个人资料(displayName、mid、statusMessage 等) |
get_contact(mid) | mid: str | 获取单个联系人的资料 |
get_contacts(mids) | mids: list[str] | 获取多个联系人资料 |
get_all_contact_ids() | — | 列出所有好友 MID |
find_contact_by_userid(userid) | userid: str | 通过 LINE ID 搜索联系人 |
find_and_add_contact_by_mid(mid) | mid: str | 通过 MID 添加好友 |
find_contacts_by_phone(phones) | phones: list[str] | 通过手机号搜索联系人 |
add_friend_by_mid(mid) | mid: str | 添加好友(使用 RelationService 接口) |
get_blocked_contact_ids() | — | 列出被屏蔽的 MID |
get_blocked_recommendation_ids() | — | 列出被屏蔽的好友推荐 |
block_contact(mid) | mid: str | 屏蔽某个联系人 |
unblock_contact(mid) | mid: str | 取消屏蔽联系人 |
block_recommendation(mid) | mid: str | 屏蔽某条好友推荐 |
update_contact_setting(mid, flag, value) | mid, flag: int, value: str | 更新联系人设置(例如静音) |
get_favorite_mids() | — | 列出收藏的好友 MID |
get_recommendation_ids() | — | 列出好友推荐列表 |
| 方法 | 参数 | 描述 |
|---|---|---|
send_message(to, text, ...) | to: str, text: str, reply_to: str(可选) | 发送文本消息。支持通过 reply_to=message_id 回复 |
unsend_message(message_id) | message_id: str | 取消发送/删除已发送的消息 |
get_recent_messages(chat_id, count=50) | chat_id: str | 获取指定聊天中的最新消息 |
get_previous_messages(chat_id, end_seq, count=50) | chat_id, end_seq: int | 分页获取历史消息(更早的消息) |
get_messages_by_ids(message_ids) | message_ids: list[str] | 获取指定消息 |
get_message_boxes(count=50) | — | 获取聊天列表及最后一条消息(收件箱视图) |
get_message_boxes_by_ids(chat_ids) | chat_ids: list[str] | 获取指定聊天及其最后一条消息 |
get_message_read_range(chat_ids) | chat_ids: list[str] | 获取已读回执信息 |
send_chat_checked(chat_id, last_message_id) | chat_id, last_message_id: str | 标记消息为已读 |
send_chat_removed(chat_id, last_message_id) | chat_id, last_message_id: str | 从收件箱移除聊天 |
send_postback(to, postback_data) | to, postback_data: str | 发送事件回传(用于机器人交互) |
# Skill: Line Client
Version: 0.2.1
Chunk: 2/2
## 方法
| 方法 | 参数 | 描述 |
|------|------|------|
| `get_chats(chat_ids, with_members=True, with_invitees=True)` | chat_ids: list[str] | 获取聊天/群组详情 |
| `get_all_chat_mids()` | — | 列出所有聊天 MID(群组 + 邀请) |
| `create_chat(name, target_mids)` | name: str, target_mids: list[str] | 创建新群组聊天 |
| `accept_chat_invitation(chat_id)` | chat_id: str | 接受群组邀请 |
| `reject_chat_invitation(chat_id)` | chat_id: str | 拒绝群组邀请 |
| `invite_into_chat(chat_id, mids)` | chat_id: str, mids: list[str] | 将用户邀请至群组 |
| `cancel_chat_invitation(chat_id, mids)` | chat_id: str, mids: list[str] | 取消待发送的邀请 |
| `delete_other_from_chat(chat_id, mids)` | chat_id: str, mids: list[str] | 将成员移出群组 |
| `leave_chat(chat_id)` | chat_id: str | 退出群组聊天 |
| `update_chat(chat_id, updates)` | chat_id: str, updates: dict | 更新群组名称/设置 |
| `set_chat_hidden_status(chat_id, hidden)` | chat_id: str, hidden: bool | 归档/取消归档聊天 |
| `get_rooms(room_ids)` | room_ids: list[str] | 获取旧版房间信息 |
| `invite_into_room(room_id, mids)` | room_id: str, mids: list[str] | 邀请用户加入旧版房间 |
| `leave_room(room_id)` | room_id: str | 退出旧版房间 |
## 回复(表情)
| 方法 | 参数 | 描述 |
|------|------|------|
| `react(message_id, reaction_type)` | message_id: str, type: int | 对消息进行回复。类型:2=点赞,3=爱心,4=大笑,5=惊讶,6=难过,7=生气 |
| `cancel_reaction(message_id)` | message_id: str | 移除你的回复 |
## 个人资料与设置
| 方法 | 参数 | 描述 |
|------|------|------|
| `update_profile_attributes(attr, value, meta={})` | attr: int, value: str | 更新个人资料。属性:2=显示名称,16=状态消息,4=头像状态 |
| `update_status_message(message)` | message: str | 快捷方式:更新状态消息 |
| `update_display_name(name)` | name: str | 快捷方式:更新显示名称 |
| `get_settings()` | — | 获取全部账户设置 |
| `get_settings_attributes(attr_bitset)` | attr_bitset: int | 获取特定设置 |
| `update_settings_attributes(attr_bitset, settings)` | attr_bitset: int, settings: dict | 更新设置 |
## 轮询与事件
| 方法 | 参数 | 描述 |
|------|------|------|
| `get_last_op_revision()` | — | 获取最新的操作版本号 |
| `fetch_ops(count=50)` | — | 获取待处理的操作(可能长时间轮询) |
| `poll()` | — | 生成器,实时接收操作数据 |
| `on_message(handler)` | handler: Callable(msg, client) | 启动轮询线程,在收到新消息时调用 handler。操作类型:26=发送消息,27=接收消息 |
| `stop()` | — | 停止轮询线程 |
## 其他服务
| 方法 | 参数 | 描述 |
|------|------|------|
| `get_server_time()` | — | 获取 LINE 服务器时间戳 |
| `get_configurations()` | — | 获取服务器配置 |
| `get_rsa_key_info()` | — | 获取用于认证的 RSA 密钥信息 |
| `issue_channel_token(channel_id)` | channel_id: str | 发行频道令牌(用于 LINE Login / LIFF) |
| `get_buddy_detail(mid)` | mid: str | 获取官方账号信息 |
| `report_abuse(mid, category=0, reason="")` | mid: str | 举报用户 |
| `add_friend_by_mid(mid)` | mid: str | 添加好友(通过 RelationService) |
| `logout()` | — | 退出登录并失效令牌 |
## MID 格式
LINE 使用 MID 来标识实体:
- `U...` 或 `u...` → 用户(toType=0)
- `C...` 或 `c...` → 群组聊天(toType=2)
- `R...` 或 `r...` → 房间(toType=1)
客户端在发送消息时会自动根据 MID 前缀识别 `toType`。
## HMAC 签名
所有 API 请求都需要 `X-Hmac` 头部。WASM 签名器会自动处理:
- 使用版本号 "3.7.1" 和访问令牌,通过专有 KDF(在 lstm.wasm 中实现)推导密钥
- 对 `path + body` 进行签名,结果转为 base64 编码,作为 `X-Hmac` 值
- 服务端模式:约 13ms/次签名(Node.js HTTP 服务器运行于端口 18944,自动启动)
- 子进程模式:约 2s/次签名(备用方案)
## 错误处理from src.chrome_client import APIError
try:
client.send_message(mid, "test")
except APIError as e:
print(e.code, e.api_message)
# 10051 = 会话已过期或无效
# 10052 = 后端 HTTP 错误
# 10102 = 参数无效
## 架构用户的手机(LINE 应用)
↕ (扫描二维码 / 输入 PIN)
LINE 服务器(line-chrome-gw.line-apps.com)
↕ (JSON REST + X-Hmac 签名)
LineChromeClient(本项目)
↕ (通过 Node.js 签名器使用 WASM HMAC)
lstm.wasm + lstmSandbox.js
Chrome 网关内部负责 JSON ↔ Thrift 的转换。我们无需直接处理 Thrift 二进制数据——所有交互均为干净的 JSON 格式。已收录 1 个 Skill