Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ Gate 依 [PLAN.md](PLAN.md) 逐關驗收,不跳關;Gate 0 遠端需存在四

E2EE 文字發送:linejs 3.4.2 被要求 E2EE 時的自動重試只把 `text` 加密,`MENTION` 等 metadata 只留在明文。`decryptE2EEMessage` 會把解密內容的其他欄位併回 metadata,由此推斷 LINE App 從加密內容讀取標記(尚未以真實帳號實測)。因此 adapter 以 `e2ee: false` 先送明文,被拒才自行用 `encryptE2EEMessage(to, { ...metadata, text })` 加密後送出(明文 metadata 照舊保留);不得改回交給 linejs 重試。

E2EE 群組金鑰(issue #2):linejs 3.5.0 在 LINE 回 `NOT_FOUND`(成員變動後新世代尚未發到本裝置)時,會以 `tryRegisterE2EEGroupKey` 自行註冊群組金鑰,連解密路徑也會觸發;這可能與官方 App 建立的世代並存,使該群之後全面無法解密。adapter 於 `activate` 將其改為一律失敗(傳送失敗、訊息顯示佔位),不得恢復自行註冊。linejs 即時事件在解密失敗時會靜默丟棄訊息,adapter 包裝 `decryptE2EEMessage`,失敗時回傳原密文並標記為無法解密,讓即時訊息同樣 fail-closed 顯示佔位。

LINE operation 與連線注意事項:linejs 未記載多數 operation 的參數排列,`SEND_CHAT_CHECKED`(手機已讀)只取 `param1` 且須為伺服器已知聊天室;群組/個人資料/聊天室成員變動不解析參數,只觸發節流的頻道清單重新整理(3 秒合併、最多每 30 秒一次),不得改成依參數猜測內容。頻道清單的最後一則訊息(`Channel.lastMessage`)是預覽,不登記媒體來源,不能藉此下載。WS 心跳:伺服器以協定層 Ping 每 30 秒檢查、兩輪無回應即關閉;網頁 `ping` 需 10 秒內收到 `pong`,回到前景立即探測。斷線記錄(網頁主控台、服務日誌 `WS_CLOSED`)只可含時間、close code、截短的 reason 與前後景狀態,不得含標頭、cookie 或 Token。

PWA 注意事項:`web/public/sw.js` 只可快取公開靜態檔(`/`、`/assets/*`、`/icons/*`、manifest、favicon);`/media/*`、`/ws` 與非 GET 請求絕不經手,避免私人內容在登出後殘留於 Cache Storage。新增靜態副檔名須同步 `src/http/server.ts` 的 mime 表。未讀數以 LINE 的 `unreadCount` 為準(talk `getMessageBoxes`、社群 `getSquareChatStatus`,盡力而為),連線時的訊息快照(`messages` 影格)不計未讀。
Expand Down
2 changes: 2 additions & 0 deletions PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,8 @@

> v1.19(2026-10 小語裁示:聊天室一次性管理員權杖,協定版本仍為 2):新增 `chat:admin-token:get { requestId, chatId }` → `chat:admin-token { requestId, chatId, token, createdAt }`。網頁從聊天室標頭「搜尋」旁的「管理員權杖」取得;小語另裁示權杖資訊必須經 `/api/ws` 告知連入的外掛:連線、登入完成、頻道清單更新與每次成功兌換後,主動推送 `api.chats` 內已知聊天室的 `chat:admin-token { chatId, token, createdAt }`(無 `requestId`),外掛也可主動查詢。每個聊天室以 32-byte 安全亂數產生 `chatadm_` 權杖,只存記憶體,登出/換帳號/重啟/聊天室移除即失效(外掛收 `chat:admin-token:changed { chatId }` 或非 `ready` 的 `auth:state`)。機器人限定 `chat:admin-token:consume { requestId, chatId, token }`:格式不合回 `INVALID_REQUEST`,錯誤或已用回 `CHAT_ADMIN_TOKEN_INVALID`;成功時同步替換為不同的新權杖、回 `chat:admin-token:consumed { requestId, chatId }`(不含新值),再把新權杖推送給所有外掛,網頁收不含祕密的 `chat:admin-token:changed` 後重新取得。成功由機器人自行決定授權,不改 LINE 管理員、不授予 API/mention 權限;因 API 可讀明文,不能證明曾使用 WEB 或具 LINE 管理員身分。

> issue #2 修正(2026-10):adapter 禁止 linejs 在 LINE 未發下群組金鑰時自行註冊(`tryRegisterE2EEGroupKey`),避免與官方 App 的新世代並存;代價是成員剛變動、LINE 尚未發下新金鑰時傳送失敗、訊息顯示佔位,待官方 App 建立新金鑰後恢復。即時訊息解密失敗不再被 linejs 靜默丟棄,改為「無法解密」佔位。驗證:以真實 linejs E2EE 程式碼與隔離 LINE 回應(群組金鑰 `NOT_FOUND`)確認傳送、歷史與即時路徑皆不註冊金鑰(修正前發出 2 次註冊流程,即時訊息被丟棄)。根因為推論:issue 回報的同世代雙金鑰與自行註冊吻合,但未以真實帳號重現 LINE 伺服器端行為;既有已損壞的世代無法由本修正修復,需由新成員加入觸發換代。

> 本次驗證:typecheck、build 與 262 項測試通過;已以隔離 LINE 回應、實際 HTTP/WS Token 認證及正式 adapter 驗證 capability 握手、完整分頁、`ownMemberId`、未發言管理員的 MENTION metadata、跨連線拒絕與重新查詢撤銷。回歸測試另涵蓋聊天室/網頁隔離、空名單、失敗、限流、回應順序顛倒、斷線、登出/換帳號。尚未以真實 LINE 帳號或 NekoGuard 程序完成聯測,不宣稱通過 Gate。

> 詐騙分析加速(協定版本仍為 2):同一登入期間,網頁與 API 在完成既有資格/聊天室權限/限流驗證後,以 UTF-16 完整文字的 SHA-256 合併同內容的進行中請求,並重用成功結果(完成起有效 5 分鐘,命中不延長);記憶體 LRU 最多 256 筆含進行中請求,不另存原文、不落盤。失敗不快取,登出/換帳號/關閉服務清除;等待期間文字變更、收回或移出訊息快取回 `INVALID_REQUEST`,舊帳號請求不得回填新快取。模型、完整文字、Noul/Choice 題目、回應格式及每分鐘限額不變,不新增自動分析或付費預熱;分析錯誤只記固定代碼。首次分析仍受真實上游及網路延遲限制。
Expand Down
1 change: 1 addition & 0 deletions README.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ Open `http://127.0.0.1:3789`. If `session.json` can be reused, you enter the cha
- **Scam probability check** (requires `jev.token`; see [Configuration](#configuration)): right-click (or long-press) a **text message from someone else** and choose 「詐騙機率分析」 (Scam probability check). A dialog shows the scam probability and a reading (> 80% very likely a scam, ≤ 20% unlikely, anything between is uncertain, check carefully). Above 20% it also lists the closest scam kind with its confidence (fake investment/stock-tip groups, impersonating an agency/bank/customer service, phishing links, online shopping/"cancel installments", impersonating friends or family to borrow money, romance, jobs/renting out accounts, prizes, loans, other). The option is not offered for your own messages, taken-back, undecryptable, system or non-text messages, and the menu item is absent when no key is set. Every check sends that one text to TypeSafe and is billed; the result is only a model estimate.
- **Desktop notifications**: clicking 「通知」 (Notifications) at the top right asks the browser for permission and turns them on (the button switches to the accent color; the choice is kept in the browser's localStorage; click again to turn off). Only new messages from others are notified, and only while the page is not in the foreground; each chat shows at most one notification, replaced by its newest message; clicking it returns to the page with that chat open, and it closes once the chat is read. The notification content (sender and message preview) appears in the operating system's notification center. A secure context is required (`127.0.0.1`/`localhost` or HTTPS); on other http addresses the button is hidden.
- **Drafts**: when you switch chats, unsent text (including @ mentions and the reply target) stays with its chat and comes back when you return. Drafts live only in page memory and are cleared by reloading or logging out. A staged picture or video is not kept.
- **End-to-end encrypted group keys**: this service never creates a group key of its own; it only uses keys LINE hands out. Right after a group's membership changes, before LINE has issued the new key, sending fails (the draft is kept) and received messages, live ones included, show as undecryptable; it recovers once a member speaks from an official app and LINE issues the new key. A key created here could coexist with the official apps' key and leave the whole group undecryptable afterwards ([#2](https://github.com/JS-PACKAGE/LINE.js/issues/2)).
- **Message search and retention**: searches currently retained messages, newest first. Counts and matches are complete, but only visible rows plus overscan have DOM. Arrow keys, Home/End and Enter/Space navigate results. The frontend retains at most 500 messages per chat and 10,000 overall, evicting least-recently-used non-current chats when needed; the UI shows limits, retained counts and evictions. A contiguous history window moves upward so older messages remain reachable. 「最新訊息」 (Latest), or leaving a historical window and reopening the chat, fetches the latest page. Reply jumps and mention candidates cover retained messages only. Search neither fetches history nor sends read receipts; ordinary chats acknowledge only while the page is visible, at the bottom of the latest window with the newest message visible.
- **History retry and reaction updates**: the first failed history load offers a retry button. Reaction updates replace only the reaction chips without recreating images, videos, or voice messages.
- **Logout cleanup**: clears search, chat contents, profile information, the image viewer, dialogs, and the account's desktop notifications, while preserving notification preferences.
Expand Down
1 change: 1 addition & 0 deletions README.ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ npm start
- **詐欺確率分析**(`jev.token` の設定が必要。[設定](#設定)を参照):**相手から届いたテキストメッセージ**を右クリック(タッチ操作では長押し)して「詐騙機率分析」(詐欺確率分析)を選ぶと、ダイアログに詐欺確率と判定(> 80% は詐欺の疑いが高い、≤ 20% は詐欺らしくない、その間は判断できないため要確認)を表示します。確率が 20% を超える場合は、最も近い手口と信頼度(偽投資/株推奨グループ、機関・銀行・カスタマーサービスのなりすまし、フィッシングリンク、ネット通販・分割払い解除、親族・友人を装った借金、恋愛詐欺、求人・アルバイト/口座貸し、当選・景品、ローン・代行、その他)も表示します。自分のメッセージ、送信取消済み、復号できない、システム、テキスト以外のメッセージには表示せず、キー未設定時はメニュー項目自体がありません。分析のたびにそのテキストが TypeSafe に送られ課金されます。結果はモデルの推定にすぎません。
- **デスクトップ通知**:右上の「通知」をクリックすると、ブラウザーに通知の許可を求めて有効にします(ボタンが強調色になります。設定はブラウザーの localStorage に保存され、もう一度クリックすると無効)。ページが前面にないときだけ、ほかの人からの新着メッセージを通知します。各チャットの通知は最大 1 件で、新しいメッセージに置き換わります。通知をクリックするとページに戻ってそのチャットを開き、既読になると通知は閉じます。通知の内容(送信者とメッセージの抜粋)は OS の通知センターに表示されます。安全なコンテキスト(`127.0.0.1`/`localhost` または HTTPS)が必要で、それ以外の http アドレスではボタンを表示しません。
- **下書き**:チャットを切り替えると、未送信のテキスト(@ メンションと返信先を含む)は元のチャットに残り、戻ると復元されます。ページのメモリにのみ保持し、再読み込みやログアウトで消去します。選択済みの画像/動画は保持しません。
- **エンドツーエンド暗号化グループの鍵**:本サービスはグループ鍵を自分で作成せず、LINE が配布した鍵だけを使います。メンバー変更直後で LINE がまだ新しい鍵を配布していない間は、送信は失敗し(下書きは保持)、受信メッセージ(リアルタイムを含む)は「復号できません」と表示されます。メンバーが公式アプリで発言し、LINE が新しい鍵を発行すると回復します。本サービスが作った鍵が公式アプリの鍵と並存し、以後グループ全体が復号できなくなるのを防ぐためです([#2](https://github.com/JS-PACKAGE/LINE.js/issues/2))。
- **メッセージ検索と保持**:現在保持しているメッセージを新しい順に検索します。一致件数と結果は省略せず、表示範囲と前後の余裕分だけ DOM を作成します。矢印キー、Home/End、Enter/スペースで移動できます。フロントエンドはチャットごとに最大 500 件、全体で最大 10,000 件を保持し、全体上限では現在のチャット以外の古い利用順にキャッシュを削除します。上限・保持数・削除数を画面に明示します。履歴は連続した窓を過去へ移動するため、さらに古い内容も読み込めます。「最新訊息」(最新)を押すか、履歴の窓を離れてチャットを開き直すと最新ページを取得します。引用への移動とメンション候補は保持範囲のみです。検索自体は履歴取得や既読送信を行いません。通常のチャットでは、ページが表示中で最新の窓の最下部にあり、最新メッセージが見えている場合だけ既読を送ります。
- **履歴の再試行とリアクション更新**:最初の履歴取得が失敗すると再試行ボタンを表示します。リアクション更新はチップのみを置き換え、画像、動画、音声を作り直しません。
- **ログアウト時の消去**:検索、チャット内容、プロフィール、画像ビューアー、ダイアログ、そのアカウントのデスクトップ通知を消去します。通知の設定は保持します。
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ npm start
- **詐騙機率分析**(需設定 `jev.token`,見[設定](#設定)):對**別人傳來的文字訊息**按右鍵(觸控長按)選「詐騙機率分析」,結果以對話框顯示:詐騙機率與判讀(> 80% 高度疑似詐騙、≤ 20% 不太像詐騙,其間為無法確定、請小心查證);機率超過 20% 時另列最接近的手法與信心(假投資/飆股群、假冒機關/銀行/客服、釣魚連結、網購/解除分期付款、冒充親友借錢、感情詐騙、求職打工/租借帳戶、中獎贈品、貸款代辦、其他)。自己的訊息、已收回、無法解密、系統訊息與非文字訊息不提供此選項;未設定金鑰時選單不出現。每次分析都會把那一則文字送到 TypeSafe 並計費,結果只是模型估計。
- **桌面通知**:右上「通知」按一下會向瀏覽器要求通知權限並開啟(按鈕轉為強調色;設定存在瀏覽器的 localStorage,再按一次關閉)。只在頁面不在前景時通知他人傳來的新訊息;每個聊天室最多一則通知,新訊息會取代舊的;點通知回到頁面並開啟該聊天室,讀過後通知自動收起。通知內容(寄件者與訊息摘要)會出現在作業系統的通知中心。需要安全環境(`127.0.0.1`/`localhost` 或 HTTPS),其他 http 位址不顯示此按鈕。
- **草稿**:切換聊天室時,未送出的文字(含 @ 提及與回覆對象)保留在原聊天室,回來時還原;只存頁面記憶體,重新整理或登出即清除。已選取的圖片/影片不保留。
- **端對端加密群組的金鑰**:本服務不自行建立群組金鑰,只使用 LINE 發下的金鑰。群組成員剛變動、LINE 還沒發下新金鑰時,此時傳送會失敗(草稿保留),收到的訊息(含即時訊息)顯示「無法解密」;成員用官方 App 發言、LINE 建立新金鑰後即恢復。這是為了避免本服務建立的金鑰與官方 App 的金鑰並存,導致整個群組之後都無法解密([#2](https://github.com/JS-PACKAGE/LINE.js/issues/2))。
- **訊息搜尋與保留**:只搜尋目前保留的訊息,依時間由新到舊排列;完整計數與結果不截斷,但僅建立可見範圍及前後緩衝列的 DOM。支援方向鍵、Home/End 與 Enter/空白鍵跳轉。前端每聊天室最多 500 則、全部最多 10,000 則,超過總量時淘汰非目前聊天室的較久未使用快取;畫面明示上限、目前筆數與移出筆數。歷史以連續窗口向上移動,仍可繼續載入更舊訊息;按「最新訊息」或離開歷史窗口後重進聊天室會重新取得最新頁。引用跳轉與提及候選僅涵蓋保留範圍。搜尋不額外載入歷史或回報已讀;一般聊天只在最新窗口、頁面可見且置底看到最新訊息時回報已讀。
- **歷史重試與回應更新**:初次載入歷史失敗時可按重試;回應更新只替換回應膠囊,不重建圖片、影片或語音。
- **登出清理**:清除搜尋、聊天內容、個人資料、圖片檢視器、對話框與該帳號的桌面通知,保留通知偏好設定。
Expand Down
Loading
Loading