Skip to content

4m1rali/PingPuff

Repository files navigation

PingPuff - R.I.P in 17 April 2026 💔

Internal documentation — for collaborators and the development team only. Do not distribute or publish this document publicly.


Table of Contents


Overview

PingPuff is a Windows desktop VPN client built with Electron + React. It provides a one-click interface for connecting through a DPI-bypass proxy chain:

Your Device → NexNull (SNI Spoofing) → ISP/DPI (bypassed) → Target Server
                                ↑
                          Xray (SOCKS/HTTP proxy)

The app handles the full lifecycle automatically:

  • Downloads and extracts the core binaries on first run
  • Writes all config files
  • Starts the SNI bypass process (nexnull.exe)
  • Starts the Xray proxy core (xray.exe)
  • Sets the Windows system SOCKS proxy to 127.0.0.1:10808
  • Clears the proxy and kills all processes on disconnect or close

Architecture

┌─────────────────────────────────────────────────────────┐
│                    Electron Main Process                 │
│                    (electron/main.js)                    │
│                                                          │
│  ┌─────────────┐   ┌──────────────┐   ┌──────────────┐  │
│  │  Admin Check│   │ Download/    │   │ Process Mgmt │  │
│  │  (net sess) │   │ Extract Core │   │ SNI + Xray   │  │
│  └─────────────┘   └──────────────┘   └──────────────┘  │
│                                                          │
│  ┌─────────────────────────────────────────────────────┐ │
│  │              IPC Bridge (preload.js)                │ │
│  └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
                          │ contextBridge
┌─────────────────────────────────────────────────────────┐
│                  Renderer Process (React)                │
│                                                          │
│  App.jsx → SetupScreen (splash) → Dashboard (main UI)   │
│                                                          │
│  VpnContext ──── connect() / disconnect()                │
│  NetworkGraph ── animated SVG diagram                    │
│  TitleBar ────── logo + info button + window controls    │
└─────────────────────────────────────────────────────────┘

How It Works

First Launch

  1. Admin checknet session detects elevation. If not admin, PowerShell relaunches with Start-Process -Verb RunAs (UAC prompt).
  2. SetupScreen renders immediately — shows logo + progress bar.
  3. Directory check — creates ~/Documents/PingPuff/ if missing.
  4. Download — fetches https://my.uupload.ir/dl/1L06V910 as core.zip. Contains:
    • xray.exe at root
    • sni/nexnull.exe in the sni/ subfolder
  5. Extract — PowerShell Expand-Archive into PingPuff/. Uses recursive findFile() to locate binaries regardless of zip structure.
  6. Config write — writes config.json (Xray) and sni/config.json (NexNull) fresh every launch.
  7. Start NexNull — spawns nexnull.exe, sends \n to stdin to bypass the interactive startup prompt.
  8. Start Xray — spawns xray.exe run -c config.json, buffers all output to detect success vs failure.
  9. Set proxy — writes socks=127.0.0.1:10808 to Windows registry + notifies WinINet.
  10. Dashboard fades in.

Connect / Disconnect

  • Connect — kills any stale processes by PID + taskkill /F /IM, rewrites configs, restarts NexNull → Xray → sets proxy.
  • Disconnecttaskkill /F by PID and by name, clears registry proxy, notifies WinINet.
  • Window close — same as disconnect, then app.quit().

SNI Bypass (NexNull)

NexNull intercepts the TCP handshake at kernel level using WinDivert. It injects a fake TLS ClientHello with SNI = hcaptcha.com (a whitelisted domain). The DPI system sees the allowed domain and permits the connection. The real server ignores the out-of-window packet. Full bidirectional relay then starts.

Config: LISTEN_PORT=40443, CONNECT_IP=104.19.229.21:443, FAKE_SNI=hcaptcha.com

Xray Core

Xray runs a local SOCKS5 proxy on 127.0.0.1:10808 and HTTP proxy on 127.0.0.1:10809. It routes traffic through the NexNull tunnel using Trojan protocol over WebSocket/TLS.

Protocol: Trojan → WS → TLS
Server:   127.0.0.1:40443 (NexNull)
SNI:      www.gossipglove.com
Path:     /assignment
Password: humanity

Tech Stack

Layer Technology
Desktop shell Electron 33
Frontend React 18 + Vite 6
Styling TailwindCSS 3 + inline styles
Package manager pnpm
VPN core Xray-core (Trojan/WS/TLS)
DPI bypass NexNull / SNI-Spoofing (WinDivert)
Proxy setting Windows Registry + WinINet
Build/package electron-builder 25

Project Structure

PingPuff/
│
├── electron/
│   ├── main.js          # Main process — admin check, download, process mgmt, IPC
│   └── preload.js       # Context bridge — exposes electronAPI to renderer
│
├── src/
│   ├── App.jsx          # Root — shows SetupScreen then Dashboard
│   ├── main.jsx         # React entry point
│   ├── index.css        # Global styles + keyframe animations
│   │
│   ├── components/
│   │   ├── TitleBar.jsx      # Draggable title bar, logo, info button, window controls
│   │   ├── Dashboard.jsx     # Main view — graph + magnet connect button
│   │   ├── NetworkGraph.jsx  # Animated SVG network diagram (5-node SNI flow)
│   │   ├── SetupScreen.jsx   # Splash screen with progress bar during setup
│   │   ├── ServerPicker.jsx  # Server selection modal
│   │   └── AboutModal.jsx    # About / credits modal (Persian)
│   │
│   └── context/
│       └── VpnContext.jsx    # Global VPN state — connect/disconnect, stats, ping
│
├── resources/
│   └── sni/                  # (legacy) bundled SNI resources — now downloaded
│
├── public/
│   ├── logo.png              # App logo (shown in title bar + setup screen)
│   └── icon.ico              # Windows app icon (generated from logo.png)
│
├── index.html
├── vite.config.js
├── tailwind.config.js
├── postcss.config.js
└── package.json

Component Reference

electron/main.js

The entire backend. Key functions:

Function Purpose
isAdmin() Checks net session for elevation
relaunchAsAdmin() PowerShell Start-Process -Verb RunAs
downloadFile(url, dest, onProgress) HTTPS download with redirect follow + progress callback
extractZip(zipPath, destDir) PowerShell Expand-Archive
findFile(dir, name) Recursive file search (handles any zip structure)
writeSNIConfig() Writes sni/config.json
startSNI() Spawns nexnull.exe, sends \n to stdin, 4s timeout
startXray() Spawns xray.exe run -c config.json, buffers output, 5s timeout
setSystemProxy() Registry write + WinINet notify
clearSystemProxy() Registry clear + WinINet notify
cleanup() taskkill /F by PID + by name, clears proxy
runSetup(win) Full 8-step setup flow, sends IPC progress events
dbg(tag, ...args) Timestamped console debug logger
dbgErr(tag, ...args) Timestamped console error logger

electron/preload.js

Exposes window.electronAPI to the renderer:

window.electronAPI = {
  minimize()              // window-minimize IPC
  maximize()              // window-maximize IPC
  close()                 // window-close IPC
  platform                // process.platform string
  onSetupStatus(cb)       // setup:status event → { step, msg, progress }
  onSetupDone(cb)         // setup:done event
  onSetupError(cb)        // setup:error event → { msg }
  vpnConnect()            // invoke vpn:connect → { ok, error? }
  vpnDisconnect()         // invoke vpn:disconnect → { ok }
  removeAllListeners(ch)  // cleanup IPC listeners
}

src/context/VpnContext.jsx

Global state provider. Exposes:

{
  connected, connecting,
  connect(),       // calls electronAPI.vpnConnect() or simulates in dev
  disconnect(),    // calls electronAPI.vpnDisconnect()
  selectedServer, setSelectedServer,
  pingHistory,     // last 24 ping values (ms)
  bytesDown, bytesUp, sessionTime,
  fmtTime(s), fmtBytes(b),
  killSwitch, setKillSwitch,
}

src/components/NetworkGraph.jsx

SVG-based animated network diagram showing the actual NexNull/SNI-Spoofing flow:

[You] ──── [NexNull :40443] ──── [WinDivert] ──── [DPI] ──── [Target]
                                      │                           ↑
                                      └── fake SNI arc ───────────┘
                                          (amber, hcaptcha.com)
  • Green edges — main data path with animated lime packets when connected
  • Amber arc — fake SNI bypass path from WinDivert over DPI to Target
  • Neon glow — breathing multi-layer glow on Target node when connected
  • Connecting animation — white→green linear fill on each edge, staggered delays
  • DPI badge — shows BYPASSED ✓ / BLOCKING state

src/components/SetupScreen.jsx

Full-screen splash shown during the 8-step setup. Receives setup:status IPC events and renders:

  • Breathing logo with drop-shadow glow
  • Step message text
  • Smooth progress bar with shimmer
  • Step indicator dots (active dot expands)
  • Error state (red) with message

src/components/Dashboard.jsx

Main UI after setup. Contains:

  • NetworkGraph filling the upper area
  • MagnetButton — the connect/disconnect pill button with rAF-driven cursor-tracking magnet effect
  • Random Persian connect labels from FUNNY_LABELS[]
  • ServerPicker modal (triggered by "change server" link — currently UI-only)

src/components/TitleBar.jsx

Custom frameless title bar:

  • logo.png + "PingPuff" name
  • info button → opens AboutModal
  • Minimize and Close × buttons
  • WebkitAppRegion: drag for window dragging

Backend Flow

app launch
    │
    ├─ isAdmin? ──No──→ relaunchAsAdmin() → UAC → restart
    │
    ├─ createWindow()
    │
    ├─ ready-to-show → show() → runSetup()
    │
    └─ runSetup()
         │
         ├─ [1] mkdir ~/Documents/PingPuff
         │
         ├─ [2] xray.exe && nexnull.exe exist?
         │        No → downloadFile(DOWNLOAD_URL, core.zip)
         │
         ├─ [3] extractZip(core.zip, PingPuff/)
         │        findFile(xray.exe) → move to root if needed
         │        findFile(nexnull.exe) → move to sni/ if needed
         │
         ├─ [4] writeFile(config.json)  ← Xray Trojan/WS/TLS config
         │
         ├─ [5] writeSNIConfig()  ← NexNull config
         │
         ├─ [6] startSNI()
         │        spawn nexnull.exe
         │        stdin.write('\n')  ← bypass Press Enter prompt
         │        wait 4s or "NexNull" in stdout
         │
         ├─ [7] startXray()
         │        spawn xray.exe run -c config.json
         │        buffer stdout, detect "started" vs "failed"
         │        5s timeout fallback
         │
         ├─ [8] setSystemProxy()
         │        reg add ProxyEnable=1
         │        reg add ProxyServer=socks=127.0.0.1:10808
         │        InternetSetOption notify
         │
         └─ send setup:done → renderer fades in Dashboard

IPC API

Main → Renderer events

Event Payload When
setup:status { step, msg, progress } Each setup step
setup:done Setup complete
setup:error { msg } Fatal setup error

Renderer → Main (invoke)

Channel Returns Action
vpn:connect { ok, error? } Kill stale procs, restart SNI+Xray, set proxy
vpn:disconnect { ok } Kill all procs, clear proxy

Renderer → Main (send)

Channel Action
window-minimize win.minimize()
window-maximize win.maximize() / unmaximize()
window-close cleanup() + win.close()

Network Diagram

  CLIENT (You)
      │
      │  SOCKS5 127.0.0.1:10808
      ▼
  ┌─────────────────────────────────────────────────────────────┐
  │  Xray Core  (xray.exe)                                      │
  │  Inbound:  SOCKS 127.0.0.1:10808 + HTTP 127.0.0.1:10809    │
  │  Outbound: Trojan → WS → TLS → 127.0.0.1:40443             │
  └─────────────────────────────────────────────────────────────┘
      │
      │  Trojan/WS/TLS  127.0.0.1:40443
      ▼
  ┌─────────────────────────────────────────────────────────────┐
  │  NexNull (nexnull.exe)  — SNI Spoofing Proxy                │
  │  Listen:  0.0.0.0:40443                                     │
  │  Target:  104.19.229.21:443                                 │
  │  Fake SNI: hcaptcha.com  (WinDivert kernel injection)       │
  └─────────────────────────────────────────────────────────────┘
      │
      │  TCP  104.19.229.21:443
      ▼
  ┌─────────────────────────────────────────────────────────────┐
  │  ISP / DPI                                                  │
  │  Sees: TLS ClientHello with SNI = hcaptcha.com  → ALLOW ✓  │
  └─────────────────────────────────────────────────────────────┘
      │
      ▼
  Target Server (104.19.229.21)
  Real TLS handshake with www.gossipglove.com

Config Files

~/Documents/PingPuff/config.json (Xray)

{
  "log": { "loglevel": "warning" },
  "inbounds": [
    { "port": 10808, "listen": "127.0.0.1", "protocol": "socks", "settings": { "udp": true } },
    { "port": 10809, "listen": "127.0.0.1", "protocol": "http" }
  ],
  "outbounds": [{
    "protocol": "trojan",
    "settings": {
      "servers": [{ "address": "127.0.0.1", "port": 40443, "password": "humanity" }]
    },
    "streamSettings": {
      "network": "ws",
      "security": "tls",
      "tlsSettings": { "serverName": "www.gossipglove.com", "allowInsecure": true },
      "wsSettings": { "path": "/assignment", "headers": { "Host": "www.gossipglove.com" } }
    }
  }]
}

~/Documents/PingPuff/sni/config.json (NexNull)

{
  "LISTEN_HOST": "0.0.0.0",
  "LISTEN_PORT": 40443,
  "CONNECT_IP": "104.19.229.21",
  "CONNECT_PORT": 443,
  "FAKE_SNI": "hcaptcha.com",
  "BROWSER_PROFILE": "random",
  "TTL_SPOOF": true,
  "LOG_LEVEL": "WARNING"
}

Development Setup

Prerequisites

  • Windows 10/11 (64-bit) — must run as Administrator
  • Node.js 22+
  • pnpm 10+
  • Python 3.11+ (for NexNull source, not needed if using compiled exe)

Install

pnpm install

Run in dev mode

pnpm run dev

This starts:

  1. Vite dev server on http://localhost:5173
  2. Electron pointing at the Vite server
  3. DevTools opens automatically (detached window)

Note: The full backend setup flow (download, extract, start processes) runs on every launch including dev mode. Make sure you're running as Administrator.

Dev tips

  • All backend logs are timestamped and tagged: [HH:MM:SS.mmm] [TAG] message
  • Tags: PATHS, ADMIN, DOWNLOAD, EXTRACT, SNI, XRAY, PROXY, SETUP, IPC, VPN, CLEANUP
  • If xray.exe and nexnull.exe already exist in ~/Documents/PingPuff/, the download step is skipped
  • To force re-download: delete ~/Documents/PingPuff/xray.exe or sni/nexnull.exe
  • To test UI without backend: the VpnContext falls back to a 2.8s simulated connect if electronAPI is not available

Build & Package

MSI installer (Windows x64)

pnpm run build:msi

Output: dist-electron/PingPuff-1.0.0.msi

Requires WiX Toolset v3 (electron-builder downloads it automatically to its cache on first build).

Standard build

pnpm run build

Build config highlights (package.json)

"win": {
  "icon": "public/icon.ico",
  "requestedExecutionLevel": "requireAdministrator",
  "target": [{ "target": "msi", "arch": ["x64"] }]
},
"msi": {
  "oneClick": false,
  "perMachine": true,
  "createDesktopShortcut": true,
  "createStartMenuShortcut": true
}

perMachine: true installs to C:\Program Files\PingPuff and requires admin — consistent with the app's runtime requirement.


Known Issues & Notes

Issue Status Notes
reg delete ProxyServer fails if key doesn't exist Fixed Wrapped in inner try/catch
NexNull EOFError on startup Fixed stdin.write('\n') bypasses the interactive prompt
Xray resolves on version banner before failure line Fixed Output buffered, failure checked before success
Reconnect after disconnect didn't restart processes Fixed vpn:connect now kills stale procs by PID + taskkill /F /IM
WiX 7 installed but electron-builder needs WiX 3 Pending electron-builder auto-downloads WiX 3 to its cache on first MSI build
ServerPicker server list is UI-only By design Servers are hardcoded; real server discovery not implemented yet
Ping/stats in Dashboard are simulated By design Real metrics from Xray not yet wired

Team

Name Role
4m1rali Backend & Frontend Developer
Matin SenPai Backend Developer
TheRitalin Network Engineer

PingPuff — یه تلاش کوچیک برای یه نفس راحت‌تر

About

One-click Windows VPN client that bypasses DPI using Xray-core, SNI spoofing, and a secure proxy chain.

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors