Skip to content

Latest commit

Β 

History

93 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Lenswire

Lenswire

Local HTTP(S) inspector Β· iOS Packet Tunnel Β· Android VpnService Β· MIT

Website Β· Privacy


Lenswire traffic capture Lenswire request inspector

Lenswire is a native HTTP(S) inspector with a local MITM proxy. Decrypt HTTPS when Lenswire CA is installed and HTTPS decryption is enabled.

  • πŸ” HTTPS decryption with Lenswire CA (Generate CA β†’ Install CA + toggle)
  • πŸ“± Device VPN + local MITM: iOS (Packet Tunnel) and Android (VpnService)
  • 🧭 Domain groups, client tags, and filters (method / status / path)
  • πŸ§ͺ Override rules: request rewrite + response mocks
  • πŸ“‹ Copy as cURL, Share HAR, fail-open bypass with clear reasons
  • 🧰 sandbox/ probe app + sim:trust-ca / android:trust-ca scripts

Primary focus: decrypt and inspect real device traffic via iOS Packet Tunnel / Android VpnService.

Links

Android / Google Play

Preview APK for sideload: GitHub Releases.

npm run version:bump                  # bump semver + build numbers (patch by default)
npm run build:android:preview:local   # APK for sideload (preferred)
npm run release:android:github        # attach APK to GitHub Release
# or one-shot:
npm run release:android:preview       # bump β†’ local preview APK β†’ GitHub Release
npm run build:android:local           # AAB for Play upload (preferred)
npm run build:android:preview         # cloud APK (slower)
npm run build:android                 # cloud AAB (slower)
npm run screenshots:store             # marketing frames 1290Γ—2796
npm run screenshots:play              # Play graphic + Android framed screenshots

Store release checklist

Item Android / Play iOS / App Store
App id / package in config Done (com.lenswire.app) Done (com.lenswire.app + Packet Tunnel extension)
Icon + splash in binary Done Done
Privacy policy URL Done (live) Done (same URL; paste in ASC)
Phone listing screenshots Done (framed-*.png via screenshots:play) Done (01–06.png)
Feature graphic / listing icon Done (play-store/ via screenshots:play) n/a (uses app icon)
Listing copy + compliance docs Done (LISTING, DATA-SAFETY) Todo (docs/app-store/ not started)
EAS production profile / scripts Done (build:android:local, upload keystore on EAS) Todo (no build:ios / submit:ios yet)
Store-signed production binary Done (AAB via local EAS β†’ dist/android/lenswire-production-1.0.0.aab) Todo (.ipa via EAS)
Real Apple Team ID in app.json n/a Todo (appleTeamId is still YOUR_APPLE_TEAM_ID)
Network Extension entitlements n/a Todo (paid Apple Developer + NE capability approved)
Developer account + store console app Todo (Play Console create + first AAB upload) Todo (Apple Developer + App Store Connect)
Automated submit credentials Todo (Google service account for eas submit) Todo (App Store Connect API key)
Internal test track Todo (Play Internal testing) Todo (TestFlight)
Tablet screenshots Optional Todo if supportsTablet stays true
Public production release Todo Todo

Full asset map: docs/STORE-ASSETS.md. Android upload steps: docs/play-store/PLAY-CONSOLE.md.

Requirements

  • Node 22.13+ (see .nvmrc)
  • Mac + Xcode 16+ (iOS)
  • Android Studio / SDK (Android)
  • For iOS device VPN: Apple Developer Program (Network Extension) + physical iPhone
  • For iOS Simulator: free Personal Team is enough (tunnel capture still needs a device)
  • For Android: no paid account required (VpnService)

Run

Shared setup once:

nvm use
npm install

iOS

First time / after native changes (targets/network-packet-tunnel/, vendor/, entitlements, NE):

npm run prebuild:ios   # expo prebuild --clean + link-hev-ios (HevSocks5Tunnel)

Day-to-day:

npm run ios                              # Simulator (UI only β€” no Packet Tunnel)
npx expo run:ios --device                # physical iPhone (full TUN β†’ hev β†’ SOCKS β†’ MITM)
Simulator Device
App UI yes yes
Full capture (VPN) no (IPC failed) yes (paid team + NE + appleTeamId)

On device after install: Certificate β†’ Generate/Install/Trust CA β†’ Start β†’ allow VPN β†’ Safari. Details: modules/lenswire-proxy/ios/README.md.

If you ran plain expo prebuild without the npm script, link hev manually: npm run link:hev-ios.

Android

First time / after native changes (modules/lenswire-proxy/android/, manifest, Gradle):

npm run prebuild:android

Day-to-day:

npm run android          # emulator or device (full TUN β†’ tun2socks β†’ SOCKS β†’ MITM)

After install: Certificate β†’ Generate CA β†’ on rooted AVD for Chrome use npm run android:trust-ca β†’ Start β†’ allow VPN. Details: modules/lenswire-proxy/android/README.md.

iOS: Install CA β†’ view HTTPS

  1. Certificate β†’ Generate CA
  2. Install profile (device) or npm run sim:trust-ca (Simulator)
  3. Settings β†’ General β†’ About β†’ Certificate Trust Settings β†’ enable Lenswire CA
  4. Start β†’ allow VPN (device)
  5. Open Safari / apps without pinning β€” decrypted requests appear with headers and bodies

Toggle HTTPS decryption in Settings. Apps with certificate pinning will fail while decryption is on.

iOS Simulator

Packet Tunnel does not work on Simulator (IPC failed). Full capture requires a physical device (see Run β†’ iOS above).

After Generate CA on Simulator you can still trust it with npm run sim:trust-ca (UI / cert flows only β€” no tunnel capture).

Android full-device mode

npm run android
# Certificate β†’ Generate CA
# Emulator (required for Chrome decrypt): npm run android:trust-ca
# Start β†’ allow VPN β†’ open https://example.com

Sandbox app (User CA + mock probes)

sandbox/ is a separate Expo RN app (com.lenswire.sandbox) that trusts User CAs via networkSecurityConfig. Use it to check decrypt without System CA (after Install CA), and later to verify mocks.

# Lenswire: Generate CA β†’ Install CA β†’ HTTPS decrypt ON
cd sandbox && npm install && npm run prebuild:android && npm run build:apk
adb install -r android/app/build/outputs/apk/release/app-release.apk
# Stop/Start VPN if you previously saw trust?/bypassed CONNECT tunnels, then GET post

See sandbox/README.md. If you only see CONNECT + trust?/bypassed, Stop VPN (clears bypass), Install CA again after Generate.

Android emulator: System CA (required for Chrome)

On Android 7+, Chrome and most apps ignore User CAs. Install CA alone puts the cert under Trusted credentials β†’ User, which causes browser warnings like β€œcertificate is not trusted by your device's operating system” and pages fail to load while HTTPS decryption is ON.

Use a rooted AVD (system image without Google Play):

  1. Certificate β†’ Generate CA
  2. From the project root:
npm run android:trust-ca

On Android 14+ this overlays the Conscrypt APEX trust store (not only /system/etc/security/cacerts). Manual β€œInstall CA” (User store) is not enough for Chrome. Settings β†’ Trusted credentials may not list the CA even when trust works β€” rely on decrypt succeeding.

  1. Force-stop Chrome (script does this), then: Lenswire β†’ HTTPS decryption Enabled β†’ Start β†’ open https://example.com or https://m.vk.ru

Expect decrypted GET/POST rows (not only CONNECT). Google/pinned apps may stay tunnel-only.

Temporary workaround without System CA: Settings β†’ HTTPS decryption OFF β†’ Stop/Start (sites load again; no decrypt).

If Install CA does not open anything, install manually as User CA (not enough for Chrome):

  • Settings β†’ Security β†’ Encryption & credentials β†’ Install a certificate β†’ CA certificate.

To export the generated Android CA file manually:

# Verify cert files inside app sandbox
adb shell run-as com.lenswire.app ls files/certs

# Export DER cert to current host directory
adb exec-out run-as com.lenswire.app cat files/certs/lenswire-ca.cer > lenswire-ca.cer

# Optional: copy to device Downloads
adb push lenswire-ca.cer /sdcard/Download/lenswire-ca.cer

The generated files in app sandbox are:

  • files/certs/lenswire-ca.cer (DER, recommended for install)
  • files/certs/lenswire-ca.pem (PEM)

Notes:

  • Android routes device traffic through TUN (VpnService) β†’ tun2socks β†’ SOCKS bridge β†’ local MITM proxy.
  • iOS (device) uses the same model: Packet Tunnel utun β†’ hev β†’ SOCKS β†’ MITM (no system HTTP proxy). Details: modules/lenswire-proxy/ios/README.md.
  • HTTP capture works without emulator/browser manual proxy setup.
  • HTTPS Path B (TCP/443): SNI-aware MITM (SOCKS peeks ClientHello, proxy uses hostname for leaf cert).
  • Fail-open: recoverable MITM failures fall back to passthrough; handshake-rejected hosts are bypassed for the session.
  • QUIC / HTTP/3 is not decrypted (quicDecrypt: false); browsers typically fall back to TCP HTTPS. SOCKS UDP ASSOCIATE is used for DNS, not for QUIC decrypt.
  • Tunnel-only rows show a reason (no sni, trust?, tls off, …) in the traffic list and request Overview.
  • Pinned apps remain tunnel-only even with System CA. Lenswire cannot bypass pinning β€” on a rooted device unpin separately (Frida / objection / LSPosed), then decrypt again.
  • Trust vs pinning: System CA fixes Chrome/browser trust; Frida-style unpinning is a separate step for apps that pin certificates.
  • No Apple Developer account needed for Android (VpnService). iOS full capture needs a paid team + Network Extension + physical device.
  • After regenerating the iOS native project, use npm run prebuild:ios (runs link:hev-ios) so HevSocks5Tunnel is linked into the Packet Tunnel target.

Device usage (real iOS VPN)

  1. Paid Apple Developer team + physical iPhone
  2. Certificate β†’ Generate CA β†’ Install profile β†’ trust in Settings
  3. Start β†’ allow VPN
  4. Open Safari or any app β€” decrypted HTTPS appears in the list

Architecture

VPN layer (Packet Tunnel on iOS / VpnService on Android) intercepts device traffic and forwards it to a local MITM (LocalProxyServer). HTTPS decryption works only when Lenswire CA is installed and HTTPS decryption is enabled.

iOS device:  apps β†’ PacketTunnel(utun) β†’ hev β†’ SOCKS β†’ LocalProxyServer (MITM) β†’ UI
iOS Sim:     Packet Tunnel unavailable β€” use device for full capture
Android:     VpnService(TUN) β†’ tun2socks β†’ SOCKS bridge β†’ LocalProxyServer(MITM) β†’ UI

Key components:

  • targets/network-packet-tunnel/: iOS Packet Tunnel (VPN interception + hev + SOCKS)
  • modules/lenswire-proxy/: native bridge wiring the tunnel/proxy to the app
  • LocalProxyServer: local MITM proxy (HTTPS decryption + request data to UI)
  • modules/lenswire-proxy/android/README.md: Android capture stack (TUN β†’ SOCKS β†’ MITM)
  • modules/lenswire-proxy/ios/README.md: iOS capture stack (utun β†’ hev β†’ SOCKS β†’ MITM)
  • sandbox/: separate RN probe app (checks User CA trust + mocks)
  • app/: UI and settings (CA trust / HTTPS decryption)

Scripts

Script Purpose
npm run ios / android Build & run
npm run prebuild:ios / prebuild:android Regenerate native projects (iOS also runs link:hev-ios)
npm run link:hev-ios Link HevSocks5Tunnel into Packet Tunnel (after prebuild)
npm run version:bump Bump semver + iOS/Android build numbers
npm run build:android:preview:local Local EAS preview APK
npm run release:android:preview Bump β†’ local preview APK β†’ GitHub Release
npm run release:android:github Upload preview APK to GitHub Release
npm run build:android:local Local EAS production AAB
npm run screenshots:store Colorful marketing frames + website JPG screenshots
npm run screenshots:play Play feature graphic + Android framed screenshots
npm run website:dev / website:deploy Landing page (GitHub Pages)
npm run sim:trust-ca Trust app-generated CA in booted iOS Simulator
npm run android:trust-ca Install Lenswire CA into System store (rooted AVD)

About

Built by Dmitry Shelomanov β€” Senior Frontend / React Native developer.

Socials

About

Local HTTP(S) inspector with VPN MITM on iOS and Android. MIT.

Topics

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages