RocketChat / RocketChat/Rocket.Chat.ReactNative

Android: add User-Agent interceptor to shared OkHttp client

Open
#7,342 2 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

type: feature
Dominant language
TypeScript
Stars
2.4k
Forks
1.5k
Avg merge
1d 18h
Merged PRs (30d)
90

Description

Context

Follow-up to #7330 / #7339 (avatar fetch in push notifications was missing the RC Mobile User-Agent on Android).

That PR fixed the avatar surface specifically, in the NotificationHelper.avatarLoadModel helper. The broader problem is that other native HTTP call sites on Android can still leak the default Dalvik UA, because they go through the shared OkHttp client without explicit headers.

What's affected

Confirmed sites still missing the RC Mobile UA:

  • android/app/src/main/java/chat/rocket/reactnative/voip/MediaCallsAnswerRequest.kt — VoIP accept/decline REST call (/api/v1/media-calls.answer). Sets x-user-id / x-auth-token, no User-Agent.
  • android/app/src/main/java/chat/rocket/reactnative/networking/ExpoImageClient.java — Expo Image (in-app image loads) uses SSLPinningTurboModule.getSharedOkHttpClient(), which has no UA configured.

Already correctly set today:

  • LoadNotification.java (push.get)
  • ReplyBroadcast.java (chat.sendMessage)
  • NotificationHelper.fetchAvatarBitmap (via the #7339 fix)

Proposed fix

Add a User-Agent interceptor to SSLPinningTurboModule.getSharedOkHttpClient() so every native HTTP call inherits the RC Mobile; android <ver>; v<x> (<n>) UA by default — only the sites that need to override it would have to opt out. Mirrors what iOS already does (URLSession + Bundle.userAgent is applied at every call site, but the centralised analogue on Android is the shared OkHttp client).

Sketch:

OkHttpClient.Builder builder = new OkHttpClient.Builder()
    .addInterceptor(chain -> {
        Request original = chain.request();
        if (original.header("User-Agent") != null) {
            return chain.proceed(original); // respect explicit override
        }
        return chain.proceed(
            original.newBuilder()
                .header("User-Agent", NotificationHelper.getUserAgent())
                .build()
        );
    });

(Helper move: getUserAgent probably wants to live somewhere more general than NotificationHelper once it's used app-wide.)

Test plan

  • Verify with a debug build against a Rocket.Chat workspace that logs UA: VoIP accept/decline, Expo Image loads (avatars in RoomView, file previews) all report RC Mobile; android ....
  • Unit test on the interceptor: explicit User-Agent is preserved; default is injected when none provided.

Out of scope

  • iOS — already correct.
  • JS-side fetches — already use the wrapper in app/lib/methods/helpers/fetch.ts.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with android/app/src/main/java/chat/rocket/reactnative/networking/ExpoImageClient.java and the shared client returned by SSLPinningTurboModule.getSharedOkHttpClient(), then compare the existing UA handling in LoadNotification.java, ReplyBroadcast.java, and NotificationHelper. Add centralized default-UA behavior while preserving explicit User-Agent headers, and verify the interceptor with unit tests plus the listed VoIP and Expo Image flows.

Written by the indexing model from the issue text.

Assessment

Tech stack
android, java, kotlin, react-native
Domain
mobile, networking, testing
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
64/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.