Skip to content

fix(VSDK-909): use platform-default TLS validation for signaling WebSocket - #153

Open
mobile-sdk-afk[bot] wants to merge 3 commits into
mainfrom
afk/vsdk-909-remove-tls-bypass
Open

mobile-sdk-afk[bot] wants to merge 3 commits into
mainfrom
afk/vsdk-909-remove-tls-bypass

Conversation

@mobile-sdk-afk

@mobile-sdk-afk mobile-sdk-afk Bot commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Removes the react-native-websocket-self-signed transport from the signaling connection and restores platform-default TLS certificate and hostname validation (VSDK-909).

The previous transport unconditionally accepted any certificate for any host — an empty checkServerTrusted plus an always-true hostname verifier on Android, and an unevaluated .useCredential trust answer on iOS — allowing a network-positioned attacker to intercept the signaling WebSocket and capture login credentials. Both documented gateways (wss://rtc.telnyx.com, wss://rtcdev.telnyx.com) serve publicly-signed certificates, so no deployment needs the bypass.

What changed

  • package/lib/signaling-socket.ts (new) — SignalingSocket interface + createSignalingSocket(url) adapter over the React Native built-in WebSocket. Constructed with the URL only — no custom trust options — so TLS validation follows platform defaults. Same listener/dedup/fresh-instance-per-reconnect semantics the Connection class expects.
  • package/lib/connection.ts — swaps WebSocketSelfSigned.getInstance(wsUrl) for createSignalingSocket(wsUrl); connect/close/reconnect/teardown logic untouched. A handshake failure (untrusted certificate) now rejects connect() instead of ever treating the connection as established.
  • package/package.json — dependency react-native-websocket-self-signed removed; version bumped 1.1.0 → 1.1.1 per the acceptance criteria.
  • package/CHANGELOG.md — ### Security entry under Unreleased (final release-note wording should stay coordinated with the SEC-1045 disclosure timing).
  • Root manifest + lockfile — demo app's direct react-native-websocket-self-signed declaration removed, lockfile regenerated (direct declaration purge; see risk notes for the transitive remainder).
  • Tests — teardown/freshness connection mocks re-pointed at the new adapter; new __tests__/signaling-socket.test.ts pins the security contract (URL-only constructor — any second constructor argument fails the test — and handshake failures rejecting connect()) plus lifecycle/reconnect behavior; version-pinned fixtures updated 1.1.0 → 1.1.1.

Validation (run from this branch)

package/:

$ npx jest
Test Suites: 25 passed, 25 total
Tests:       280 passed, 280 total

Baseline on main at branch creation: 24 suites / 270 tests → the +1 suite / +10 tests is the new signaling-socket.test.ts; all 270 pre-existing tests still pass.

react-voice-commons-sdk/:

$ npm run build   → OK (tsc emit clean)
$ npm test
Test Suites: 16 passed, 16 total
Tests:       158 passed, 158 total
$ npm run lint    → 0 errors, 246 warnings (pre-existing warning baseline, unchanged)

Repo root:

$ npm run security:check
83 vulnerabilities (19 moderate, 62 high, 2 critical)

Pre-existing on main (same count) — unchanged by this PR; npm audit --audit-level=high still exits non-zero due to the known demo-app dependency tree.

$ npm run quality:check
[warn] react-voice-commons-sdk/README.md
[warn] README.md
[warn] Code style issues found in 2 files.

Pre-existing on main — both files untouched by this PR. All files included in this diff pass prettier (npx prettier --check "package/**/*.ts" → All matched files use Prettier code style!).

Risk notes

  • Behavior change (intended): self-signed certificates for the signaling gateway are no longer accepted. Apps that relied on this for private-gateway testing must add their own trusted-CA or token-auth story; the SDK now ships only platform-default-validated TLS.
  • Demo app residue: the demo app consumes @telnyx/react-native-voice-sdk ^0.3.0 from the npm registry, so react-native-websocket-self-signed remains in its lockfile as a transitive dependency of the published 0.3.x tarball. It disappears from the demo once the demo app bumps to a patched release (1.1.1 of this package) — release-time follow-up, coordinated with the version bump above.
  • Runtime surface preserved: the Connection socket API (onOpen/onError/onClose/onMessage/connect/send/close/removeOn*Listener) is unchanged for client.ts; connection-level integration paths (login → telnyx.socket.open → attach) are covered by the existing suites, but a device smoke test (login + call on both gateways) is still recommended at review since the transport swap sits beneath runtime behavior.

Linear

VSDK-909 — link posted on the ticket in the same handoff.

Review-fix cycle (2026-10-21)

Addresses P1 review thread oPr0VwHkEu73mA6NW1kwDQ ("Avoid requiring globalThis on supported React Native versions").

  • Fix (e070e01): connect() no longer evaluates a bare globalThis identifier. A typeof-guarded getGlobalObject() helper resolves the runtime's global object, falling back to React Native's universally available global on older JavaScriptCore/Hermes runtimes (within the react-native >=0.60.0 peer range) where globalThis does not exist. Previously the unguarded evaluation threw a synchronous ReferenceError before connect() could return its promise, so Connection could never open signaling at all. Security contract unchanged: URL-only WebSocket construction, platform-default TLS certificate + hostname validation, untrusted-cert handshake failures still reject connect().
  • Tests (+2, 282 total): resolver identity pin + a source-shape guard asserting the bare globalThis evaluation cannot return and the typeof globalThis / typeof global guarded fallbacks stay in place.
  • Validation at e070e01: package/ npx jest: 25 suites / 282 tests passed (baseline 280); react-voice-commons-sdk/ npm run build OK, npm test 16 suites / 158 tests passed, npm run lint 0 errors / 246 pre-existing warnings; root npm run quality:check fails only on the 2 pre-existing unformatted READMEs (unchanged from main); root npm run security:check reports 83 vulnerabilities (same total count as main, unchanged). Changed files prettier-clean.

…ocket

Remove the react-native-websocket-self-signed transport, which unconditionally
accepted any certificate for any host on the signaling connection (empty
checkServerTrusted plus an always-true hostnameVerifier on Android; an
unevaluated useCredential trust answer on iOS). Signaling now goes through
the React Native built-in WebSocket via a new lib/signaling-socket.ts
adapter, so TLS certificate and hostname validation follow platform
defaults for both the production and development gateways.

- Drop the dependency from package/package.json (version 1.1.0 -> 1.1.1)
  and from the demo app manifest; regenerate the root lockfile accordingly
- Add a package/CHANGELOG.md Security entry under Unreleased
- Re-point the two connection test mocks at the new adapter and add a
  signaling-socket test suite pinning the URL-only constructor contract
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-21T14:58:37.725744Z fa96813 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fa968134cf

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread package/lib/signaling-socket.ts Outdated
Comment on lines +99 to +100
const WebSocketImpl = (globalThis as unknown as Record<string, unknown>)
.WebSocket;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Avoid requiring globalThis on supported React Native versions

On older JavaScriptCore or Hermes runtimes covered by the package's react-native >=0.60.0 peer range, globalThis may not exist. Evaluating this identifier then throws a synchronous ReferenceError before connect() can return its promise, so Connection cannot open signaling at all. Read the WebSocket constructor from React Native's universally available global object or the ambient WebSocket, or raise the minimum supported runtime.

Useful? React with 👍 / 👎.

Telnyx AFK Bot added 2 commits October 21, 2026 17:35
Address the P1 review thread on PR #153 (oPr0VwHkEu73mA6NW1kwDQ): the WebSocket constructor lookup evaluated a bare `globalThis` identifier, which throws a synchronous ReferenceError on older JavaScriptCore/Hermes runtimes within the react-native >=0.60.0 peer range - before connect() could return a rejected promise, so Connection could never open signaling. Resolve the global object through a typeof-guarded helper with React Native's universal `global` fallback, and pin the contract with two new tests (resolver identity + source-shape guard).
…ls-bypass

# Conflicts:
#	package-lock.json

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

0 participants