Skip to content

fix: Windows BridgeのXTEA暗号文バイトリバースに対応#61

Merged
9c5s merged 4 commits intomainfrom
fix/win-bridge-xtea-byte-reversal
Apr 3, 2026
Merged

fix: Windows BridgeのXTEA暗号文バイトリバースに対応#61
9c5s merged 4 commits intomainfrom
fix/win-bridge-xtea-byte-reversal

Conversation

@9c5s
Copy link
Copy Markdown
Owner

@9c5s 9c5s commented Apr 3, 2026

Summary

  • Windows BridgeはTCNASDP認証のXTEA暗号文 (auth[4:12]) を8バイトリバースして読み取ることが判明
  • Bridge OSをpingのTTL値から自動検出し、Windows判定時に暗号文を事前リバースして送信する
  • Mac/Win両Bridge、ローカル/リモートの4パターン全てで動作確認済み

背景

Win Bridge環境でCUE/BeatGrid/BigWaveFormが配信されない問題を調査した結果、2つの根本原因を特定した:

  1. XTEA暗号文のバイトオーダー差異: Win BridgeはXTEA暗号文をバイトリバース (UInt64 BE変換) してからDecipherに渡す。Mac Bridgeではリバースは発生しない
  2. ライセンスマスク値の検証: v1=0xFFFFFFFF (全ビットON) はWin Bridgeで "open" 扱いとなりCUE/BeatGrid/BigWaveFormが配信されない。正規のShowKontrolライセンスマスク値が必要

本PRは原因1 (バイトリバース) を修正する。原因2はユーザーが.envで適切な暗号文を設定することで対処する。

変更内容

src/tcnet.ts

  • detectBridgeIsWindows(): Bridge OSの自動検出メソッド (async)
    • ローカル (Bridge IP = クライアントIP): os.platform() で判定
    • リモート: execFile("ping", ...) でTTL取得、TTL > 64 → Windows
    • 結果をインスタンス変数にキャッシュ (セッション中1回のみ検出)
    • IPアドレスバリデーション付き (コマンドインジェクション防止)
  • sendAuthSequence(): Windows判定時に ciphertext.reverse() を適用
  • resetAuthSession(): キャッシュクリア (再接続時に再検出)

tests/bridge-os-detection.test.ts (新規, 13テスト)

  • ローカル/リモート判定、TTL境界値、ping失敗フォールバック、キャッシュ動作、プラットフォーム別ping引数

tests/auth.test.ts (+3テスト)

  • Windows Bridge時のバイトリバース送信、non-Windows時のそのまま送信、キャッシュクリア

Test plan

  • npx vitest run 全204ユニットテストパス
  • Win Bridge + Winローカル: 全7データタイプ受信 (CUE 55, BigWaveForm 25, BeatGrid 2)
  • Mac Bridge + Macローカル: 全7データタイプ受信 (CUE 756, BigWaveForm 455, BeatGrid 44)
  • TCNetClient統合テスト: 非逆順暗号文 → 自動検出 → リバース → 全データ受信 PASS

Windows BridgeはTCNASDP認証のXTEA暗号文(auth[4:12])をバイトリバースして
読み取る。pingのTTL値からBridge OSを自動検出し、Windows判定時に暗号文を
事前リバースして送信することで、Mac/Win両Bridgeに対応する。

- detectBridgeIsWindows: ローカルはos.platform()、リモートはping TTLで判定
- sendAuthSequence: Windows Bridge時にciphertext.reverse()を適用
- execFileベースの非同期実装でイベントループブロッキングを回避
- IPアドレスバリデーション追加でコマンドインジェクション防止
- server未設定時のキャッシュ回避で再検出を保証
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 3, 2026

🦋 Changeset detected

Latest commit: 0b7f96c

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@9c5s/node-tcnet Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 3, 2026

Summary by CodeRabbit

  • 新機能

    • リモートブリッジがWindowsかどうかを自動検出するようになりました。
    • 検出結果に応じて認証送信データのバイト順を動的に調整します。
  • バグ修正

    • Windowsブリッジでの認証データのバイト順不整合を修正しました。
  • テスト

    • ブリッジOS検出と認証シーケンスの挙動を網羅する追加テストを導入しました。
  • 雑務

    • リリース用の変更履歴エントリを追加しました。

Walkthrough

TCNetClientがブリッジOSを検出し、認証送信時にXTEA暗号文をOS判定で条件付きバイト反転するようになりました。判定結果はbridgeIsWindowsにキャッシュされ、resetAuthSession()でクリアされます。

Changes

Cohort / File(s) Summary
Bridge OS検出と認証修正
src/tcnet.ts
`bridgeIsWindows: boolean
認証テスト拡張
tests/auth.test.ts
テスト用アクセス/ミューテータを追加し、sendAuthSequenceにおけるXTEAバイト反転挙動とresetAuthSession()でのキャッシュクリアを検証するテストを追加。
Bridge OS検出テスト新規
tests/bridge-os-detection.test.ts
detectBridgeIsWindows()を露出したテストクライアントを使い、ローカル/リモート判定、TTL境界、ping失敗/TTL欠落時の挙動、キャッシュ動作、サーバ未設定や無効IPの扱い、プラットフォーム別ping引数を網羅するテスト群を追加(os.platform()execFileをモック)。
リリース記録
.changeset/blue-emus-doubt.md
Windowsブリッジ向けのXTEAバイト順修正を示すパッチ変更のChangesetを追加。

Sequence Diagram(s)

sequenceDiagram
  participant Client as TCNetClient
  participant OS as Local OS / execFile
  participant Bridge as Remote Bridge (server)

  Client->>Client: detectBridgeIsWindows()
  alt server IP equals local adapter IP
    Client->>OS: os.platform()
    OS-->>Client: platform (win32 / other)
  else remote server
    Client->>OS: execFile("ping", args..., {timeout:3000})
    OS-->>Client: stdout (may contain TTL) / error
    Client->>Client: parse TTL -> ttl > 64 ?
  end
  Client-->>Client: set bridgeIsWindows cache (true/false/null)
  Client->>Client: sendAuthSequence()
  alt bridgeIsWindows == true
    Client->>Client: reverse XTEA ciphertext bytes
  else
    Client->>Client: use ciphertext as-is
  end
  Client->>Bridge: send auth payload
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • PR #50: 既存の認証フロー/sendAuthSequence周りを扱うPRで、本件のBridge OS検出とXTEAバイト順修正に直接関連。
  • PR #2: src/tcnet.tsのサーバ/ブロードキャスト管理に関わる変更を含み、本PRのサーバ変更時のキャッシュクリア処理と関連。
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed タイトルはWindows BridgeのXTEA暗号文バイトリバースへの対応という主要な変更内容を正確かつ簡潔に反映している。
Description check ✅ Passed 説明はWindows Bridgeの暗号文バイトリバース対応、Bridge OS自動検出機能、実装内容、テスト内容を詳細に記載しており、変更内容と十分に関連している。
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/win-bridge-xtea-byte-reversal

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a mechanism to detect if the target Bridge is running on Windows by analyzing the TTL value from a ping command. This detection is necessary because the Windows Bridge implementation requires XTEA ciphertext to be byte-reversed before transmission. The changes include the detectBridgeIsWindows method in TCNetClient, logic to reverse the ciphertext in the authentication sequence, and extensive new tests to verify the detection logic and its impact on the payload. I have no feedback to provide as there are no review comments.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/tcnet.ts`:
- Around line 939-947: After awaiting this.detectBridgeIsWindows(), re-check
that the auth state didn't change (same guards used after the 50ms wait
elsewhere): wait the short 50ms (or reuse the existing wait function), then
verify this.sessionToken is still valid/non-null, this.broadcastSocket and
this.server are still present and not changed; if any are invalid, abort sending
(return early) to avoid calling
generateAuthPayload/createAppDataPacket/sendPacket with stale/null sessionToken
or socket. Implement this check immediately after the await
this.detectBridgeIsWindows() call so the subsequent calls to
generateAuthPayload, createAppDataPacket and sendPacket are only executed when
state is confirmed stable.
- Around line 849-856: The code currently assigns this.bridgeIsWindows = false
when TTL is not found or ping throws, which caches an uncertain non-Windows
result; instead, remove the assignments to the instance field in those ambiguous
branches and only return/use a local false for this probe (e.g., use a local
variable like isWindowsProbe = false or simply return false from the detection
method), leaving this.bridgeIsWindows unchanged until you have a definitive
positive detection; keep the debug logs as-is but ensure only the
definitive-true branch sets this.bridgeIsWindows = true (or a definitive-false
branch sets it when you have conclusive evidence).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2d7a9adb-ea38-4ef7-b6fe-faec6b336cf9

📥 Commits

Reviewing files that changed from the base of the PR and between 669d58d and ef4c450.

📒 Files selected for processing (3)
  • src/tcnet.ts
  • tests/auth.test.ts
  • tests/bridge-os-detection.test.ts
📜 Review details
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2026-03-21T05:30:31.035Z
Learnt from: 9c5s
Repo: 9c5s/node-tcnet PR: 2
File: src/tcnet.ts:249-255
Timestamp: 2026-03-21T05:30:31.035Z
Learning: In `src/network.ts` of the `node-tcnet` repository: `TCNetDataPacket.read()` (class defined at line 321, read() at line 330) converts the wire-format 1-based layer to 0-based by doing `this.layer = this.buffer.readUInt8(25) - 1`. In contrast, `TCNetRequestPacket.read()` (class defined at line 225, read() at line 231) does NOT subtract 1: `this.layer = this.buffer.readUInt8(25)`. Therefore, `dataPacket.layer` from a received `TCNetDataPacket` is already 0-based and correctly matches the 0-based key stored in `requestData()`. Flagging a missing `-1` in `TCNetDataPacket.read()` is a false positive.

Applied to files:

  • src/tcnet.ts
📚 Learning: 2026-03-24T19:15:40.455Z
Learnt from: 9c5s
Repo: 9c5s/node-tcnet PR: 41
File: src/utils.ts:94-94
Timestamp: 2026-03-24T19:15:40.455Z
Learning: In the `node-tcnet` repository (`src/utils.ts`), the project targets ES2022 + NodeNext and does not need to support Node.js 18.0.0. The temporary numeric `family` field (4/6) in `os.networkInterfaces()` introduced in Node.js 18.0.0 and fixed in 18.1.0 does not need to be handled. Suggesting numeric `family` handling for defensive programming is unnecessary for this project.

Applied to files:

  • src/tcnet.ts
🔇 Additional comments (2)
tests/auth.test.ts (1)

463-474: この回帰テスト追加は良いです。

bridgeIsWindows キャッシュのセット/クリアと auth[4:12] の送信順を直接固定できていて、今回のバイトリバース修正の退行を防げています。

Also applies to: 719-805

tests/bridge-os-detection.test.ts (1)

1-229: 検出ロジックのテスト構成は堅いです。

os.platform()execFile() を切り離した上で、ローカル/リモート、TTL境界、失敗フォールバック、キャッシュ、OS別引数まで押さえられており、この分岐追加をかなり安全にできています。

- ping失敗/TTL未検出時にbridgeIsWindowsをキャッシュしない (次回再検出を許可)
- detectBridgeIsWindows() await後に状態再確認ガードを追加
- patch changeset追加
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/tcnet.ts`:
- Around line 822-826: The code sets this.bridgeIsWindows = false when bridgeIp
fails the /^\d{1,3}(\.\d{1,3}){3}$/ check, which caches a determination for
invalid inputs; instead, treat an invalid IP as "undetermined" and do not cache
the result—remove the assignment to bridgeIsWindows in the IP-format check
inside the function that validates/pings the bridge (the block that references
bridgeIp and this.bridgeIsWindows) so the function returns false for this call
but leaves this.bridgeIsWindows unchanged.

In `@tests/bridge-os-detection.test.ts`:
- Around line 192-198: Add an assertion that the detection result was cached as
false: after calling BridgeOsTestClient.callDetectBridgeIsWindows(), verify the
client's cached state (e.g., BridgeOsTestClient.bridgeIsWindows or a getter like
getCachedBridgeIsWindows()) is false; if no public accessor exists, add a small
test-only accessor on BridgeOsTestClient to read the cached value and assert it
equals false so the test verifies both return value and caching behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 547b0574-c6cb-41e5-83aa-d551273c3d38

📥 Commits

Reviewing files that changed from the base of the PR and between ef4c450 and c60273b.

📒 Files selected for processing (3)
  • .changeset/blue-emus-doubt.md
  • src/tcnet.ts
  • tests/bridge-os-detection.test.ts
📜 Review details
🧰 Additional context used
🧠 Learnings (5)
📚 Learning: 2026-03-24T19:15:40.455Z
Learnt from: 9c5s
Repo: 9c5s/node-tcnet PR: 41
File: src/utils.ts:94-94
Timestamp: 2026-03-24T19:15:40.455Z
Learning: In the `node-tcnet` repository (`src/utils.ts`), the project targets ES2022 + NodeNext and does not need to support Node.js 18.0.0. The temporary numeric `family` field (4/6) in `os.networkInterfaces()` introduced in Node.js 18.0.0 and fixed in 18.1.0 does not need to be handled. Suggesting numeric `family` handling for defensive programming is unnecessary for this project.

Applied to files:

  • .changeset/blue-emus-doubt.md
  • src/tcnet.ts
  • tests/bridge-os-detection.test.ts
📚 Learning: 2026-03-21T05:30:31.035Z
Learnt from: 9c5s
Repo: 9c5s/node-tcnet PR: 2
File: src/tcnet.ts:249-255
Timestamp: 2026-03-21T05:30:31.035Z
Learning: In `src/network.ts` of the `node-tcnet` repository: `TCNetDataPacket.read()` (class defined at line 321, read() at line 330) converts the wire-format 1-based layer to 0-based by doing `this.layer = this.buffer.readUInt8(25) - 1`. In contrast, `TCNetRequestPacket.read()` (class defined at line 225, read() at line 231) does NOT subtract 1: `this.layer = this.buffer.readUInt8(25)`. Therefore, `dataPacket.layer` from a received `TCNetDataPacket` is already 0-based and correctly matches the 0-based key stored in `requestData()`. Flagging a missing `-1` in `TCNetDataPacket.read()` is a false positive.

Applied to files:

  • src/tcnet.ts
📚 Learning: 2026-03-27T08:24:18.571Z
Learnt from: 9c5s
Repo: 9c5s/node-tcnet PR: 50
File: src/network.ts:1010-1024
Timestamp: 2026-03-27T08:24:18.571Z
Learning: In the `node-tcnet` repository (`src/network.ts`), `Buffer.allocUnsafe()` is never used — only `Buffer.alloc()` is used throughout the codebase. Reserved fields in packet `write()` methods do not need explicit zero-initialization because `Buffer.alloc()` always zero-initializes. Suggesting defensive zero-writes for reserved packet offsets is unnecessary (YAGNI) for this codebase.

Applied to files:

  • src/tcnet.ts
📚 Learning: 2026-03-21T05:02:27.762Z
Learnt from: 9c5s
Repo: 9c5s/node-tcnet PR: 2
File: src/tcnet.ts:397-400
Timestamp: 2026-03-21T05:02:27.762Z
Learning: In the `node-tcnet` repository (`src/network.ts`, `src/tcnet.ts`), `TCNetDataPacket.write()` has no callers. `TCNetDataPacket` objects are only ever deserialized on receive paths (`read()`), never serialized and sent. The only outbound packet carrying a layer field is `TCNetRequestPacket`, constructed inside `requestData()` in `src/tcnet.ts`. Suggesting to move layer conversion logic into `TCNetDataPacket.write()` is inappropriate because that method is dead code.

Applied to files:

  • src/tcnet.ts
📚 Learning: 2026-03-21T11:31:23.742Z
Learnt from: 9c5s
Repo: 9c5s/node-tcnet PR: 8
File: README.MD:31-33
Timestamp: 2026-03-21T11:31:23.742Z
Learning: In `src/network.ts` of the `node-tcnet` repository: `TCNetDataPacketMetadata` (line 389) has an `info` property (not `data`). `data` property belongs to the sibling class `TCNetDataPacketMetrics` (line 352). Flagging `meta.info` in README/docs examples as wrong and suggesting `meta.data` is a false positive.

Applied to files:

  • src/tcnet.ts
🔇 Additional comments (10)
src/tcnet.ts (5)

3-4: LGTM!

必要なNode.js標準モジュールのインポートが追加されています。execFileexecよりも安全で、シェルインジェクションのリスクがありません。


96-96: LGTM!

null初期値により「未検出」と「非Windows検出済み」を区別できる適切な設計です。


844-853: LGTM!

TTL判定ロジックは同一LAN環境において正確です。ttl > 64の閾値は、Windows (TTL=128)とmacOS/Linux (TTL=64)のデフォルト値の中間点として適切です。

ping失敗時およびTTL未検出時にキャッシュしない修正が適用されており、一時的なネットワーク問題で誤判定が固定されるリスクが解消されています。


894-903: LGTM!

resetAuthSession()bridgeIsWindowsをクリアすることで、再接続時にOS再検出が行われます。これはBridgeの変更やネットワーク構成の変更に対応するための適切な設計です。


941-956: LGTM!

Windows Bridge検出時のXTEA暗号文バイトリバース処理が正しく実装されています。

  • Buffer.from(ct, "hex")で毎回新しいバッファを生成しているため、reverse()のin-place変更は安全です
  • detectBridgeIsWindows()await後に状態ガードが追加されており、非同期処理中の状態変更に対応しています
tests/bridge-os-detection.test.ts (4)

1-22: LGTM!

モックのセットアップが適切に構成されています。vi.mockでモジュール全体をモックしつつ元の実装を保持し、テスト対象のplatformexecFileのみをスタブ化しています。isolateXteaEnv()で環境変数を分離しているのも良いプラクティスです。


26-91: LGTM!

テストヘルパークラスと関数が適切に設計されています。BridgeOsTestClientはプライベートメソッドへのアクセスを提供し、mockExecFileSuccess/mockExecFileErrorexecFileのコールバックパターンを正しくシミュレートしています。


145-163: LGTM!

ping失敗時およびTTL未検出時のテストケースが、キャッシュされないこと(getBridgeIsWindows() === null)を明示的に検証しています。これにより、一時的なネットワーク問題後の再検出が正しく動作することが保証されます。


200-230: LGTM!

プラットフォーム別のping引数テストが網羅的です。Windows(-n 1 -w 1000)とmacOS/Linux(-c 1 -W 1)の両方の引数形式を検証し、タイムアウトオプションも確認しています。

.changeset/blue-emus-doubt.md (1)

1-5: LGTM!

Changesetエントリが適切に作成されています。バグ修正に対するpatchバージョンの指定と、変更内容を正確に説明する日本語の説明文が含まれています。

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
src/tcnet.ts (1)

935-956: ⚠️ Potential issue | 🟠 Major

await 後は非nullではなく同一セッションを確認してください。

この await の間に再接続やアダプタ切替が完了すると、旧 Bridge 向けに作った clientIp / OS 判定結果を、新しい sessionTokenbroadcastSocket で送れてしまいます。今のガードは「値があるか」しか見ていないので、await 前の状態を保持して一致確認し、不一致ならこの古い task だけ中断する必要があります。

🛠️ 修正案
-        const clientIp = this.getClientIp();
-        if (!clientIp) {
+        const clientIp = this.getClientIp();
+        const sessionToken = this.sessionToken;
+        const broadcastSocket = this.broadcastSocket;
+        const serverAddress = this.server.address;
+        const serverPort = this.server.port;
+        const broadcastAddress = this.config.broadcastAddress;
+        if (!clientIp || sessionToken === null) {
             this.resetAuthSession();
             return;
         }

         const ciphertext = Buffer.from(ct, "hex");
         // Windows BridgeはXTEA暗号文をバイトリバースして読み取るため、事前にリバースして送信する
         // 初回呼び出し時のみpingが発生し最大3秒かかる (AUTH_RESPONSE_TIMEOUT=5秒内に収まる想定)
         if (await this.detectBridgeIsWindows()) {
             ciphertext.reverse();
         }

-        // detectBridgeIsWindowsのawait中に状態が変わった場合のガード
-        if (!this.server || !this.broadcastSocket || this.sessionToken === null) {
-            this.resetAuthSession();
+        if (
+            !this.server ||
+            this.broadcastSocket !== broadcastSocket ||
+            this.sessionToken !== sessionToken ||
+            this.server.address !== serverAddress ||
+            this.server.port !== serverPort ||
+            this.config.broadcastAddress !== broadcastAddress ||
+            this.getClientIp() !== clientIp
+        ) {
             return;
         }

-        const payload = generateAuthPayload(this.sessionToken, clientIp, ciphertext);
-        const auth = this.createAppDataPacket(2, this.sessionToken, payload);
-        await this.sendPacket(auth, this.broadcastSocket, TCNET_BROADCAST_PORT, this.config.broadcastAddress);
+        const payload = generateAuthPayload(sessionToken, clientIp, ciphertext);
+        const auth = this.createAppDataPacket(2, sessionToken, payload);
+        await this.sendPacket(auth, broadcastSocket, TCNET_BROADCAST_PORT, broadcastAddress);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/tcnet.ts` around lines 935 - 956, Before awaiting
detectBridgeIsWindows(), capture the current session identity (e.g., store
this.sessionToken and this.broadcastSocket into local variables like
preSessionToken and preBroadcastSocket) and after the await verify those stored
values still match this.sessionToken and this.broadcastSocket; if they differ,
abort this task (call resetAuthSession() or return) so you don't send the
clientIp/OS result using a new session. Apply this check around the await in the
flow that uses getClientIp(), detectBridgeIsWindows(), generateAuthPayload(),
createAppDataPacket(), and sendPacket() with TCNET_BROADCAST_PORT and
this.config.broadcastAddress to ensure the same session is used end-to-end.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/tcnet.ts`:
- Line 96: The field bridgeIsWindows is being cached globally and can return
stale results when this.server (and thus the remote IP) changes; update the
implementation that reads/returns bridgeIsWindows to key the cache by the
current bridge endpoint (use this.server.address()/this.server.address().address
or host:port string) or reset the cached value whenever this.server changes so
the platform decision is based on the current server.address; apply the same
per-endpoint cache or reset logic to the other affected locations (the other
checks around the bridge/platform detection referenced in the review) and ensure
all uses consult the current this.server.address before returning a cached
boolean.

---

Duplicate comments:
In `@src/tcnet.ts`:
- Around line 935-956: Before awaiting detectBridgeIsWindows(), capture the
current session identity (e.g., store this.sessionToken and this.broadcastSocket
into local variables like preSessionToken and preBroadcastSocket) and after the
await verify those stored values still match this.sessionToken and
this.broadcastSocket; if they differ, abort this task (call resetAuthSession()
or return) so you don't send the clientIp/OS result using a new session. Apply
this check around the await in the flow that uses getClientIp(),
detectBridgeIsWindows(), generateAuthPayload(), createAppDataPacket(), and
sendPacket() with TCNET_BROADCAST_PORT and this.config.broadcastAddress to
ensure the same session is used end-to-end.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: dd1bd057-4c11-45ee-8d80-b8fa23110ba0

📥 Commits

Reviewing files that changed from the base of the PR and between c60273b and dc71413.

📒 Files selected for processing (2)
  • src/tcnet.ts
  • tests/bridge-os-detection.test.ts
📜 Review details
🧰 Additional context used
🧠 Learnings (5)
📚 Learning: 2026-03-24T19:15:40.455Z
Learnt from: 9c5s
Repo: 9c5s/node-tcnet PR: 41
File: src/utils.ts:94-94
Timestamp: 2026-03-24T19:15:40.455Z
Learning: In the `node-tcnet` repository (`src/utils.ts`), the project targets ES2022 + NodeNext and does not need to support Node.js 18.0.0. The temporary numeric `family` field (4/6) in `os.networkInterfaces()` introduced in Node.js 18.0.0 and fixed in 18.1.0 does not need to be handled. Suggesting numeric `family` handling for defensive programming is unnecessary for this project.

Applied to files:

  • src/tcnet.ts
  • tests/bridge-os-detection.test.ts
📚 Learning: 2026-03-21T05:30:31.035Z
Learnt from: 9c5s
Repo: 9c5s/node-tcnet PR: 2
File: src/tcnet.ts:249-255
Timestamp: 2026-03-21T05:30:31.035Z
Learning: In `src/network.ts` of the `node-tcnet` repository: `TCNetDataPacket.read()` (class defined at line 321, read() at line 330) converts the wire-format 1-based layer to 0-based by doing `this.layer = this.buffer.readUInt8(25) - 1`. In contrast, `TCNetRequestPacket.read()` (class defined at line 225, read() at line 231) does NOT subtract 1: `this.layer = this.buffer.readUInt8(25)`. Therefore, `dataPacket.layer` from a received `TCNetDataPacket` is already 0-based and correctly matches the 0-based key stored in `requestData()`. Flagging a missing `-1` in `TCNetDataPacket.read()` is a false positive.

Applied to files:

  • src/tcnet.ts
  • tests/bridge-os-detection.test.ts
📚 Learning: 2026-03-27T08:24:18.571Z
Learnt from: 9c5s
Repo: 9c5s/node-tcnet PR: 50
File: src/network.ts:1010-1024
Timestamp: 2026-03-27T08:24:18.571Z
Learning: In the `node-tcnet` repository (`src/network.ts`), `Buffer.allocUnsafe()` is never used — only `Buffer.alloc()` is used throughout the codebase. Reserved fields in packet `write()` methods do not need explicit zero-initialization because `Buffer.alloc()` always zero-initializes. Suggesting defensive zero-writes for reserved packet offsets is unnecessary (YAGNI) for this codebase.

Applied to files:

  • src/tcnet.ts
📚 Learning: 2026-03-21T11:31:23.742Z
Learnt from: 9c5s
Repo: 9c5s/node-tcnet PR: 8
File: README.MD:31-33
Timestamp: 2026-03-21T11:31:23.742Z
Learning: In `src/network.ts` of the `node-tcnet` repository: `TCNetDataPacketMetadata` (line 389) has an `info` property (not `data`). `data` property belongs to the sibling class `TCNetDataPacketMetrics` (line 352). Flagging `meta.info` in README/docs examples as wrong and suggesting `meta.data` is a false positive.

Applied to files:

  • src/tcnet.ts
📚 Learning: 2026-03-21T05:02:27.762Z
Learnt from: 9c5s
Repo: 9c5s/node-tcnet PR: 2
File: src/tcnet.ts:397-400
Timestamp: 2026-03-21T05:02:27.762Z
Learning: In the `node-tcnet` repository (`src/network.ts`, `src/tcnet.ts`), `TCNetDataPacket.write()` has no callers. `TCNetDataPacket` objects are only ever deserialized on receive paths (`read()`), never serialized and sent. The only outbound packet carrying a layer field is `TCNetRequestPacket`, constructed inside `requestData()` in `src/tcnet.ts`. Suggesting to move layer conversion logic into `TCNetDataPacket.write()` is inappropriate because that method is dead code.

Applied to files:

  • src/tcnet.ts
🔇 Additional comments (1)
tests/bridge-os-detection.test.ts (1)

93-232: テスト観点は十分です。

ローカル/リモート、TTL境界、失敗時の非キャッシュ、プラットフォーム別引数まで押さえていて、この変更の回帰をかなり防げています。

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/tcnet.ts`:
- Around line 825-829: The current IPv4 format check using
/^\d{1,3}(\.\d{1,3}){3}$/ on bridgeIp only enforces dot-decimal shape and allows
invalid octets like 999; update the validation in the pre-execFile guard around
bridgeIp to enforce each octet is 0–255—either replace the regex with one that
encodes 0-255 ranges or split bridgeIp by '.' and parseInt each octet and return
false if any octet <0 or >255; keep the behavior that invalid IPs are not cached
and ensure the same variable name bridgeIp is used in the new check.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 83630b40-a432-4ec6-9847-783b6cf6a525

📥 Commits

Reviewing files that changed from the base of the PR and between dc71413 and 0b7f96c.

📒 Files selected for processing (1)
  • src/tcnet.ts
📜 Review details
🧰 Additional context used
🧠 Learnings (5)
📚 Learning: 2026-03-24T19:15:40.455Z
Learnt from: 9c5s
Repo: 9c5s/node-tcnet PR: 41
File: src/utils.ts:94-94
Timestamp: 2026-03-24T19:15:40.455Z
Learning: In the `node-tcnet` repository (`src/utils.ts`), the project targets ES2022 + NodeNext and does not need to support Node.js 18.0.0. The temporary numeric `family` field (4/6) in `os.networkInterfaces()` introduced in Node.js 18.0.0 and fixed in 18.1.0 does not need to be handled. Suggesting numeric `family` handling for defensive programming is unnecessary for this project.

Applied to files:

  • src/tcnet.ts
📚 Learning: 2026-03-21T05:30:31.035Z
Learnt from: 9c5s
Repo: 9c5s/node-tcnet PR: 2
File: src/tcnet.ts:249-255
Timestamp: 2026-03-21T05:30:31.035Z
Learning: In `src/network.ts` of the `node-tcnet` repository: `TCNetDataPacket.read()` (class defined at line 321, read() at line 330) converts the wire-format 1-based layer to 0-based by doing `this.layer = this.buffer.readUInt8(25) - 1`. In contrast, `TCNetRequestPacket.read()` (class defined at line 225, read() at line 231) does NOT subtract 1: `this.layer = this.buffer.readUInt8(25)`. Therefore, `dataPacket.layer` from a received `TCNetDataPacket` is already 0-based and correctly matches the 0-based key stored in `requestData()`. Flagging a missing `-1` in `TCNetDataPacket.read()` is a false positive.

Applied to files:

  • src/tcnet.ts
📚 Learning: 2026-03-27T08:24:18.571Z
Learnt from: 9c5s
Repo: 9c5s/node-tcnet PR: 50
File: src/network.ts:1010-1024
Timestamp: 2026-03-27T08:24:18.571Z
Learning: In the `node-tcnet` repository (`src/network.ts`), `Buffer.allocUnsafe()` is never used — only `Buffer.alloc()` is used throughout the codebase. Reserved fields in packet `write()` methods do not need explicit zero-initialization because `Buffer.alloc()` always zero-initializes. Suggesting defensive zero-writes for reserved packet offsets is unnecessary (YAGNI) for this codebase.

Applied to files:

  • src/tcnet.ts
📚 Learning: 2026-03-21T05:02:27.762Z
Learnt from: 9c5s
Repo: 9c5s/node-tcnet PR: 2
File: src/tcnet.ts:397-400
Timestamp: 2026-03-21T05:02:27.762Z
Learning: In the `node-tcnet` repository (`src/network.ts`, `src/tcnet.ts`), `TCNetDataPacket.write()` has no callers. `TCNetDataPacket` objects are only ever deserialized on receive paths (`read()`), never serialized and sent. The only outbound packet carrying a layer field is `TCNetRequestPacket`, constructed inside `requestData()` in `src/tcnet.ts`. Suggesting to move layer conversion logic into `TCNetDataPacket.write()` is inappropriate because that method is dead code.

Applied to files:

  • src/tcnet.ts
📚 Learning: 2026-03-21T11:31:23.742Z
Learnt from: 9c5s
Repo: 9c5s/node-tcnet PR: 8
File: README.MD:31-33
Timestamp: 2026-03-21T11:31:23.742Z
Learning: In `src/network.ts` of the `node-tcnet` repository: `TCNetDataPacketMetadata` (line 389) has an `info` property (not `data`). `data` property belongs to the sibling class `TCNetDataPacketMetrics` (line 352). Flagging `meta.info` in README/docs examples as wrong and suggesting `meta.data` is a false positive.

Applied to files:

  • src/tcnet.ts
🔇 Additional comments (6)
src/tcnet.ts (6)

3-4: OS判定に必要な依存追加は妥当です。

execFile/platform の追加で、ローカル判定とリモート判定の両方を実装する前提が揃っています。


96-96: Bridge OS判定キャッシュの導入は適切です。

boolean | null で未判定状態を表現できており、セッション内再利用の意図が明確です。


476-478: Master IP変更時のキャッシュ無効化は正しいです。

接続先アドレス変更時に bridgeIsWindows をクリアしており、誤ったOS判定の使い回しを防げています。


816-865: detectBridgeIsWindows() の判定・キャッシュ方針は良いです。

「確定時のみキャッシュ、判定不能時は非キャッシュ」の挙動が保たれており、再試行可能性と誤固定回避のバランスが取れています。


901-901: 認証セッションリセット時のOS判定キャッシュクリアは適切です。

再接続・再認証時に再検出されるため、セッション境界の整合性が保てています。


945-956: 暗号文リバース適用とawait後ガードの組み合わせは適切です。

Windows向け変換を適用しつつ、await中の状態変化を sessionToken/socket/server で再検証できており、誤送信リスクを抑えられています。

@9c5s 9c5s merged commit b6748a6 into main Apr 3, 2026
2 checks passed
@9c5s 9c5s deleted the fix/win-bridge-xtea-byte-reversal branch April 3, 2026 17:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant