diff --git a/README.md b/README.md index 0afd933..c01076c 100644 --- a/README.md +++ b/README.md @@ -1,61 +1,60 @@ # Gothwad Remote Desktop (`remotedesktop.gothwadtech.com`) -**100% Zero-Database, Zero-Worker Cloudflare Pages Portal — Main Windows 11 OS Control + Headless Isolated Hyper-V Background VM, Secured by Gothwad Accounts (`@gothwadtech.com`) & WebRTC P2P!** +**Simple, fast browser-based Remote Desktop for phone and desktop — powered by Gothwad Accounts (`@gothwadtech.com`), Zero-D1 Cloudflare Pages, and WebRTC P2P.** -Yeh repository (`GothwadTech/remotedesktop`) bilkul **`GothwadTech/meet`** ki tarah **Zero-D1 / Zero-Backend** architecture par bani hai — Cloudflare par **koi D1 database nahi banana, koi Worker deploy nahi karna, koi secret set nahi karna!** Bas repo ko Cloudflare Pages se connect karo aur `remotedesktop.gothwadtech.com` live! +Modeled on Google Chrome Remote Desktop (`remotedesktop.google.com`), `GothwadTech/remotedesk` lets you connect to your **Windows 11 Main Desktop** in one tap from any mobile phone or desktop browser, with an optional secondary **Isolated Hyper-V Background VM** mode when you want a separate workspace without disturbing the physical screen. --- -## ⚠️ Important Consent & Transparency Rules - -1. **Explicit Owner Permission Mandatory:** Kisi bhi Windows PC par one-time setup sirf unki **clear permission aur जानकारी** se karein (Agent pairing bina explicit consent confirm kiye reject ho jaati hai). -2. **Dual-Mode Transparency:** - - **🖥️ Mode 1 (Main Windows 11 Host OS):** Jab aap main OS connect karte ho, toh bilkul *Chrome Remote Desktop* ki tarah host screen par `"Your desktop is shared with username@gothwadtech.com [Stop Sharing]"` banner dikhta hai. - - **📦 Mode 2 (Background Hyper-V VM):** Jab dost apna kaam kar raha ho, toh aap isolated Hyper-V VM me connect hote ho — dost ki screen, mouse, ya personal files bilkul disturb nahi hoti! -3. **Laptop Battery Safety:** Kabhi bhi **"On Battery"** sleep disable mat karna taaki bag me band laptop overheat na ho. +## Key Features + +- **Simple Chrome Remote Desktop UI (Phone & Desktop):** + - Clean three-section layout: **Remote Access**, **Remote Support**, and **Set up via PowerShell** (desktop left navigation rail + mobile bottom navigation bar). + - Exact ecosystem theme palette: **`#212121`** in Dark mode and **`#ffffff`** in Light mode with instant theme switching. + - **Universal Gothwad Account Menu** (`https://accounts.gothwadtech.com/widget/account-menu.js`) with multi-account (`u/0..5`) switching and `+n` avatar badge. +- **Mobile-Ready Full-Screen Viewer:** + - Collapsible floating top toolbar handle so 100% of your phone screen stays unobstructed. + - Dedicated mobile **Keyboard** button (triggers Android/iOS virtual keyboard) and **Direct Touch / Trackpad** cursor toggle. +- **Main Desktop First, Background VM Optional:** + - Primary click connects straight to your Windows 11 Main Desktop (with a visible Chrome Remote Desktop-style `"Your desktop is shared [Stop Sharing]"` banner on the host). + - Optional secondary **Hyper-V Background VM** (`Max 4 GB RAM`, `60% CPU`, Wi-Fi `Default Switch` NAT) accessible from the device overflow menu or viewer toggle. +- **100% Zero-D1 / Zero-Backend Cloudflare Pages:** + - Uses `.gothwadtech.com` SSO cookies via `https://api.gothwadtech.com/api/auth/me` directly from the browser. + - Deterministic WebRTC P2P discovery (`grd--slot-1..6`) via `PeerJS` + STUN/TURN. + - Constant-time `HMAC-SHA256(pin, nonce:viewer:mode)` challenge-response PIN verification on the Windows host (raw PIN never crosses the network). --- -## 🧠 Bina Cloudflare D1 Database ke Kaise Kaam Karta Hai? (Zero-D1 Magic!) +## Safety & Owner Consent -1. **Direct Gothwad Accounts SSO (`api.gothwadtech.com`):** - - `GothwadTech/accounts` pehle se har `*.gothwadtech.com` subdomain ke liye CORS + `.gothwadtech.com` `HttpOnly` multi-account cookies (`u/0..5`) allow karta hai! - - Isliye `remotedesktop.gothwadtech.com` seedha browser se `https://api.gothwadtech.com/api/auth/me` call karke aapka `@gothwadtech.com` user verify kar leta hai — kisi alag Worker ya D1 ki zaroorat hi nahi! -2. **Deterministic WebRTC P2P Slots (`PeerJS` + STUN/TURN, `GothwadTech/meet` Stack):** - - Jab aapka Windows PC start hota hai, `GothwadRemoteAgent.exe` aapke Gothwad username ke deterministic P2P slot (`grd--slot-1`..`6`) par online aa jaata hai. - - Jab aap duniya me kahin se bhi `remotedesktop.gothwadtech.com` kholte ho, browser aapke slots ko P2P probe karke turant **Online**, **RAM/CPU**, aur **Hyper-V VM State** dikha deta hai! -3. **Zero-Knowledge HMAC-SHA256 PIN + Host-Local ACL (`agent-config.json`):** - - Aapka **6-digit PIN** aur allowed `@gothwadtech.com` users (`vm_only` vs `host_and_vm`) seedha Windows Host ke `C:\ProgramData\GothwadRemote\agent-config.json` me rehte hain. - - Connect karte waqt raw PIN kabhi network par nahi jaata — fresh `nonce` ke saath `HMAC-SHA256(pin, nonce + ":" + viewer + ":" + mode)` verify hota hai (5 galat tries par 5-min lockout!). +1. **Explicit Owner Consent Required:** One-time setup on any Windows PC must only be run with the explicit permission of the computer's owner (`--confirm-owner-consent`). +2. **Visible Screen-Sharing Notice:** Connecting to the Main Windows Desktop displays an always-on-top `"Your desktop is shared ... [Stop Sharing]"` banner on the host monitor. +3. **Battery Protection:** Never disable **"On Battery"** sleep so a laptop closed inside a backpack cannot overheat. --- -## ✨ Website ke Andar Built-in Windows Setup Wizard (`/setup`) +## Documentation Index -Bilkul `remotedesktop.google.com/headless` ki tarah `https://remotedesktop.gothwadtech.com` par top bar me **`Windows Setup & Commands`** tab hai jahan user ko saare steps aur copy-paste PowerShell commands website ke andar hi mil jaate hain: -- **Mode Picker:** `Main OS + Background VM`, `Main OS Only` (2-min setup), ya `Background VM Only`. -- **Interactive Hyper-V VM Builder:** RAM, Disk, Linux/Windows ISO badalte hi live PowerShell command banti hai. -- **1-Line Gothwad P2P Installer Command** + Direct `.EXE` / `.ZIP` GitHub Release download buttons. -- **Safe Charger Power Command** (`standby-timeout-ac 0`, battery sleep protected). +- [`docs/01-architecture.md`](docs/01-architecture.md) — Zero-D1 WebRTC P2P & Wi-Fi NAT architecture +- [`docs/02-host-setup-windows11.md`](docs/02-host-setup-windows11.md) — Windows 11 host setup & safe power rules +- [`docs/03-option-a-crd-vm.md`](docs/03-option-a-crd-vm.md) — Optional Background VM with Chrome Remote Desktop +- [`docs/04-option-b-kasm-cloudflare.md`](docs/04-option-b-kasm-cloudflare.md) — Optional Background VM with KasmVNC & Cloudflare Tunnel +- [`docs/05-option-c-guacamole-rdp.md`](docs/05-option-c-guacamole-rdp.md) — Optional Background VM with Tailscale & RDP +- [`docs/06-troubleshooting-faq.md`](docs/06-troubleshooting-faq.md) — Wi-Fi reconnects, PIN lockouts, and troubleshooting +- [`docs/07-gothwad-ecosystem-setup.md`](docs/07-gothwad-ecosystem-setup.md) — 60-second Cloudflare Pages deployment guide --- -## 🚀 60-Second Cloudflare Pages Deployment (Zero D1, Zero Secrets!) - -1. **Cloudflare Dashboard -> Workers & Pages -> Create -> Pages -> Connect to Git (`GothwadTech/remotedesktop`)** -2. **Build command:** `npm run build` -3. **Build output directory:** `dist` -4. **Custom domain:** `remotedesktop.gothwadtech.com` -5. **Done!** 🎉 +## Local Development ---- +```bash +npm install +npm test +npm run dev +``` -## 📚 Documentation Index (`docs/`) +Build static bundle for Cloudflare Pages (`dist/`): -1. **[`docs/07-gothwad-ecosystem-setup.md`](docs/07-gothwad-ecosystem-setup.md)** — ⭐ **START HERE:** Zero-D1 Architecture, Cloudflare Pages 1-Step Deploy & GitHub Actions EXE Release Guide. -2. **[`docs/01-architecture.md`](docs/01-architecture.md)** — Hyper-V Type-1 Service, `Default Switch` Wi-Fi NAT & CGNAT Bypass Deep Dive. -3. **[`docs/02-host-setup-windows11.md`](docs/02-host-setup-windows11.md)** — Windows 11 Pro (16GB/512GB) Safe RAM/CPU Limits & Auto-Boot VM Guide. -4. **[`docs/03-option-a-crd-vm.md`](docs/03-option-a-crd-vm.md)** — Alternative A: Chrome Remote Desktop Inside Guest VM. -5. **[`docs/04-option-b-kasm-cloudflare.md`](docs/04-option-b-kasm-cloudflare.md)** — Alternative B: KasmVNC (`Webtop`) + Cloudflare Tunnel. -6. **[`docs/05-option-c-guacamole-rdp.md`](docs/05-option-c-guacamole-rdp.md)** — Alternative C: DWService / Apache Guacamole HTML5 Windows RDP. -7. **[`docs/06-troubleshooting-faq.md`](docs/06-troubleshooting-faq.md)** — 1080p Resolution Fix, Wi-Fi Drop Watchdog, Gaming Pause/Resume Shortcut & SSD Compacting. +```bash +npm run build +``` diff --git a/docs/01-architecture.md b/docs/01-architecture.md index ffa4f41..e6f540c 100644 --- a/docs/01-architecture.md +++ b/docs/01-architecture.md @@ -1,65 +1,39 @@ -# 01 — System Architecture & How It Works +# 01 — Architecture: Zero-D1 WebRTC P2P & Optional Hyper-V VM -Yeh document explain karta hai ki **1 km (ya kisi bhi distance) door rakhe Wi-Fi laptop** par bina router chhede aur bina host desktop disturb kiye browser-based VM kaise kaam karta hai. +This document explains how **Gothwad Remote Desktop (`remotedesktop.gothwadtech.com`)** connects to a remote Windows 11 laptop over Wi-Fi or mobile hotspot without router port forwarding, without a Cloudflare D1 database, and with optional background VM isolation. --- -## 1. Windows 11 Pro ka Sabse Bada Plus Point: Native Hyper-V +## 1. Primary Mode vs Secondary Background VM Mode -Aapke dost ke laptop me **Windows 11 Pro** hai — yeh sabse bada advantage hai kyunki isme **Microsoft Hyper-V** pehle se built-in aata hai (free, official Microsoft feature). - -### VirtualBox / VMware Workstation vs Hyper-V: -| Feature | VirtualBox / VMware Player | **Microsoft Hyper-V (Win 11 Pro)** | -| :--- | :--- | :--- | -| **Type** | Type-2 (App ki tarah chalta hai) | **Type-1 Bare-Metal Hypervisor** | -| **Auto-Start on Boot** | Mushkil (User login aur taskbar window chahiye) | **Native Windows Service (`vmms`) — Boot hote hi start!** | -| **Headless Mode** | Aksar taskbar me icon/window aati hai | **100% Headless Service (Zero UI windows on desktop)** | -| **Dynamic Memory** | Fixed RAM block kar leta hai | **Dynamic RAM (Jitni zaroorat utni hi RAM use karega)** | -| **Auto Save on Shutdown**| VM crash ho sakta hai agar PC band ho | **Graceful State Save — Wahin se resume hoga!** | +1. **Primary Mode — Main Windows 11 Desktop (`host_os`):** + - Works just like Google Chrome Remote Desktop. + - Streams the Windows 11 desktop over WebRTC DataChannels and forwards mouse, trackpad, keyboard, and clipboard input. + - Displays a visible `"Your desktop is shared with @gothwadtech.com [Stop Sharing]"` banner on the host monitor whenever a session is active. +2. **Secondary Optional Mode — Isolated Hyper-V Background VM (`hyperv_vm`):** + - Windows 11 Pro includes Microsoft's Type-1 **Hyper-V** hypervisor (`vmms` service). + - If enabled, an isolated Linux or Windows guest VM runs headlessly in the background (capped at **4 GB dynamic RAM** and **60% CPU**) so remote work never disturbs the person using the physical laptop. --- -## 2. Wi-Fi + CGNAT Problem aur Uska Solution +## 2. Solving Wi-Fi & CGNAT Without Router Access -Jab dost ka laptop ghar ke Wi-Fi ya mobile hotspot se connect hota hai, toh 2 challenges aate hain: -1. **CGNAT / Dynamic IP:** India me JioFiber, Airtel, aur mobile networks par aapko public IP nahi milti, isliye router me **Port Forwarding kaam nahi karti**. -2. **Wi-Fi Bridging Issue:** Laptop ke Wi-Fi card par Hyper-V ka "External Switch" (Bridge) banane se dost ka Wi-Fi bar-bar disconnect ho sakta hai. +Residential fiber and mobile hotspots place laptops behind **CGNAT** (no public IPv4 address for port forwarding). In addition, bridging a laptop Wi-Fi adapter directly in Hyper-V frequently drops wireless connections. -### Solution: `Default Switch` (WinNAT) + Outbound Tunnel Inside VM -1. **Hyper-V `Default Switch`:** Windows 11 Hyper-V me ek built-in virtual switch hota hai jiska naam hai **`Default Switch`**. Dost chahe Ghar ka Wi-Fi lagaye, Hostel Wi-Fi lagaye, ya Phone Hotspot — Windows automatic apne internet ko NAT ke through VM ke andar bhej deta hai! -2. **Outbound Connection:** VM ke andar chalne wala agent (`chromoting` / `cloudflared` / `tailscaled`) andar se bahar (`Outbound Port 443 HTTPS/WebRTC`) connect karta hai. Isliye: - - Router login ki zaroorat **NAHI** hai. - - Static IP ki zaroorat **NAHI** hai. - - Host Windows Firewall me inbound ports kholne ki zaroorat **NAHI** hai. +Our architecture solves both problems cleanly: +1. **Outbound WebRTC + TURN Relay:** The Windows host agent (`gothwad_agent.py`) opens an outbound WebSocket to PeerJS signaling and establishes peer-to-peer WebRTC connections via Google STUN and OpenRelay TURN over port `443` — zero router configuration or inbound firewall rules required. +2. **Hyper-V `Default Switch` (NAT):** For the optional Background VM, Hyper-V's built-in `Default Switch` automatically NATs traffic over whichever Wi-Fi network or phone hotspot the Windows host joins. --- -## 3. Boot-to-Browser Lifecycle (Jab Dost Laptop On Karega Toh Kya Hoga?) +## 3. Boot-to-Browser Lifecycle ```text -[00:00 sec] Dost ne Laptop ka Power Button dabaya - | -[00:12 sec] Windows 11 Pro Boot hua -> Dost apna kaam shuru kar sakta hai - | (30-second Auto-Start Delay rakha hai taaki boot time pe SSD slow na ho) - | -[00:42 sec] Hyper-V Service (`vmms`) background me Guest VM ko Resume/Boot karti hai - | (Dost ke desktop par koi window nahi aati) - | -[00:55 sec] Dost ka Laptop Wi-Fi se connect hota hai -> `Default Switch` VM ko internet deta hai - | -[01:05 sec] Guest VM ke andar ka Tunnel Service (CRD / Cloudflared / Tailscale) - | auto-start hota hai aur Cloud Relay se jud jaata hai - | -[01:10 sec] AAP APNE GHAR PE BROWSER KHOLTE HO -> VM "ONLINE" DIKHTA HAI -> CLICK & USE! +[00:00s] Windows 11 laptop powers on +[00:15s] Scheduled Task starts GothwadRemoteAgent.exe in the background +[00:20s] Host connects to Wi-Fi and registers on P2P slot grd--slot-1 +[00:30s] (Optional) Hyper-V service resumes RemoteWorkVM after a 30s SSD-friendly delay +[00:35s] Open remotedesktop.gothwadtech.com on phone or desktop -> Click Connect -> Enter 6-digit PIN ``` -Aur jab dost apna laptop **Shut Down** karega: -- Hyper-V automatically VM ki current state (khule huye apps ke saath!) disk par **Save** kar dega (`AutomaticStopAction = Save`). -- Agli baar laptop on hone par VM wahin se wapas chalu ho jayega! - ---- - -## 4. Security & Isolation Guarantee - -- **Host -> Guest Isolation:** Aap VM ke andar kuch bhi install karo, browser chalao, code compile karo — woh sab ek single `.vhdx` virtual hard disk file ke andar band rehta hai. Dost ke `C:\Users\...` personal folders VM ko bilkul accessible nahi hote (jab tak koi manually share na kare). -- **Encrypted Traffic:** Browser se VM tak sara display/keyboard stream **TLS 1.3 / WebRTC DTLS-SRTP** encrypted hota hai. +When the Windows laptop shuts down cleanly, Hyper-V automatically saves any running VM state (`AutomaticStopAction = Save`) and resumes it on the next boot. diff --git a/docs/02-host-setup-windows11.md b/docs/02-host-setup-windows11.md index eb8a13c..8dd30c1 100644 --- a/docs/02-host-setup-windows11.md +++ b/docs/02-host-setup-windows11.md @@ -1,102 +1,47 @@ -# 02 — Host PC Setup (Dost ke Windows 11 Pro Laptop Par One-Time Setup) +# 02 — Windows 11 Host Setup & Safe Power Configuration -> **Consent Reminder:** Yeh one-time setup apne dost ke saamne aur unki permission se hi karein. Isme total ~15–20 minute lagenge. +Run all setup steps on the target Windows 11 computer **only with the explicit consent of the computer's owner**. --- -## Step 1: Check Virtualization Status +## 1. Quick Host Setup (Main Desktop Access) -1. Dost ke laptop par `Ctrl + Shift + Esc` daba kar **Task Manager** kholein. -2. **Performance** tab -> **CPU** par click karein. -3. Neeche right side me check karein: **`Virtualization: Enabled`** likha hona chahiye (Windows 11 laptops me yeh 99% pehle se On hota hai). - ---- - -## Step 2: Enable Hyper-V on Windows 11 Pro - -1. Start Menu par right-click karein -> **Terminal (Admin)** ya **PowerShell (Run as Administrator)** kholein. -2. Yeh command paste karke Enter dabayein: +Open **PowerShell as Administrator** on the Windows 11 PC (or copy the generated command from **Set up via PowerShell** inside `https://remotedesktop.gothwadtech.com`): ```powershell -Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All +irm https://raw.githubusercontent.com/GothwadTech/remotedesk/main/scripts/install-gothwad-agent.ps1 -OutFile $env:TEMP\install-gothwad-agent.ps1 +powershell -ExecutionPolicy Bypass -File $env:TEMP\install-gothwad-agent.ps1 -GothwadUser "your-username" -Slot 1 -DeviceName "Home-Windows-PC" ``` -3. Jab pooche `Do you want to restart the computer now? (Y/N)`, toh **`Y`** daba kar laptop ek baar restart kar lein. - ---- - -## Step 3: Download Guest OS ISO - -Faisla karein ki aapko VM ke andar kaunsa OS chahiye: -- **Recommended (Fast & Light):** **Ubuntu 24.04 LTS Desktop** ya **Linux Mint XFCE** (~2.5 GB RAM me makkhan chalta hai). -- **Windows Inside VM:** **Windows 10 Pro / IoT LTSC** ya **Windows 11 Pro** (~4 GB RAM chahiye hoga). - -ISO file download karke ek clean folder me rakh lein, jaise `C:\HyperV\ISO\`. +During installation: +1. Confirm explicit PC owner consent (`YES`). +2. Choose a **6 to 12 digit numeric PIN** (stored locally in `C:\ProgramData\GothwadRemote\agent-config.json` and verified via HMAC-SHA256 challenge-response). +3. The script registers the `GothwadRemoteAgent` startup scheduled task so the computer comes online automatically whenever Windows boots. --- -## Step 4: Create Resource-Capped Auto-Start VM (Script ya GUI) +## 2. Safe Laptop Power & Lid Rules (16 GB RAM / 512 GB SSD) -### Method 1: Automated PowerShell Script (Recommended — Zero Mistake) -Is repo me diya gaya [`scripts/host-setup-hyperv.ps1`](../scripts/host-setup-hyperv.ps1) Admin PowerShell me run karein: +Keep the laptop awake **only while plugged into AC power**, and keep normal sleep active **on battery** so the laptop never overheats inside a closed bag: ```powershell -# Agar Guest OS Ubuntu/Linux hai: -.\scripts\host-setup-hyperv.ps1 -VMName "RemoteWorkVM" -GuestType "Linux" -IsoPath "C:\HyperV\ISO\ubuntu-24.04-desktop-amd64.iso" +# Stay awake when plugged into AC wall power +powercfg /change standby-timeout-ac 0 +powercfg /change hibernate-timeout-ac 0 -# Agar Guest OS Windows 10/11 hai: -.\scripts\host-setup-hyperv.ps1 -VMName "RemoteWorkVM" -GuestType "Windows" -IsoPath "C:\HyperV\ISO\Win11.iso" +# Sleep after 15 minutes when running on battery (thermal safety) +powercfg /change standby-timeout-dc 15 ``` -### Method 2: Manual Setup via Hyper-V Manager (GUI) -Agar aap manually banana chahte hain: -1. Start Menu se **Hyper-V Manager** kholein -> Right side me **New -> Virtual Machine** click karein. -2. **Name:** `RemoteWorkVM` | Location: `C:\HyperV\VMs\` -3. **Generation:** **Generation 2** select karein. -4. **Assign Memory:** `3072 MB` (Linux ke liye) ya `4096 MB` (Windows ke liye) aur **"Use Dynamic Memory"** pe tick lagayein. -5. **Configure Networking:** Connection dropdown me **`Default Switch`** select karein *(Yeh bahut zaroori hai Wi-Fi NAT ke liye!)*. -6. **Connect Virtual Hard Disk:** Size `50 GB` rakhein (yeh Dynamically Expanding hota hai, shuru me sirf 8–12 GB space lega). -7. **Installation Options:** Apni downloaded `.iso` file select karein aur **Finish** click karein. - -#### ⚠️ Important VM Settings (Finish ke baad VM par Right-Click -> Settings me jayein): -1. **Security (Bahut Zaroori!):** - - Agar **Ubuntu / Linux** install kar rahe ho: **Secure Boot** template ko badal kar **`Microsoft UEFI Certificate Authority`** kar dein (warna Linux boot nahi hoga!). - - Agar **Windows 11** install kar rahe ho: `Enable Trusted Platform Module (TPM)` par tick laga dein. -2. **Memory:** Minimum RAM `1536 MB`, Maximum RAM **`4096 MB`** set karein (taaki dost ke 16GB me se 12GB hamesha free rahe). -3. **Processor:** `2` Virtual Processors dein aur `+` expand karke **Virtual machine limit (percentage)** ko **`60`** kar dein (isse laptop fan kabhi shor nahi karega). -4. **Automatic Start Action (Management tab ke neeche):** - - Select karein: **`Always start this virtual machine automatically`** - - **Startup delay:** `30` seconds daalein (taaki dost ka Windows pehle bina lag ke start ho jaye). -5. **Automatic Stop Action:** - - Select karein: **`Save the virtual machine state`** (Laptop band hone par VM wahin freeze hokar save ho jayega, kuch data loss nahi hoga). - --- -## Step 5: Pehli Baar OS Install Karein +## 3. Optional Secondary Setup: Isolated Hyper-V Background VM -1. Hyper-V Manager me `RemoteWorkVM` par double-click karke **Start** dabayein. -2. Normal tarike se Ubuntu ya Windows install complete karein. -3. OS install hone ke baad Hyper-V Settings -> DVD Drive me se `.iso` hata dein ("None" select karein). -4. Ab **Hyper-V Manager ki window band kar dein!** VM background me chalta rahega — Hyper-V window khuli rakhne ki kabhi zaroorat nahi hoti. +If you also want an isolated background VM (capped at 4 GB RAM and 60% host CPU): ---- - -## Step 6: Laptop Power & Sleep Settings (Dost ki Permission Se) - -Laptop ki ek natural limitation hoti hai: agar laptop **Sleep** mode me chala gaya, toh Wi-Fi aur Hyper-V dono pause ho jayenge. - -**Safe Configuration (`Settings -> System -> Power & battery -> Screen and sleep`):** -- **When plugged in (Charger laga ho tab):** - - *Turn off my screen after:* `5 or 10 minutes` (Dost ki screen normal band ho sakti hai, VM chalta rahega). - - *Put my device to sleep after:* **`Never`** (Ya `2 hours` — jaisa dost comfortable ho). -- **On battery power (⚠️ SAFETY RULE):** - - Battery par sleep ko **`15 or 30 minutes`** hi rehne dein! **Kabhi bhi Battery par Sleep "Never" mat karna**, kyunki agar dost ne laptop bag me rakh diya toh andar garmi se laptop overheat ho jayega! - ---- - -## Next Step: Browser Access Setup Karein! +```powershell +irm https://raw.githubusercontent.com/GothwadTech/remotedesk/main/scripts/host-setup-hyperv.ps1 -OutFile $env:TEMP\host-setup-hyperv.ps1 +powershell -ExecutionPolicy Bypass -File $env:TEMP\host-setup-hyperv.ps1 -VMName "RemoteWorkVM" -GuestType "Linux" -IsoPath "C:\HyperV\ISO\ubuntu-24.04.iso" +``` -Ab aapka background VM ready hai. Ab inme se koi ek guide follow karke VM ke andar Browser Remote Access lagayein: -- 👉 **[Option A: Chrome Remote Desktop Inside VM (Sabse Simple)](03-option-a-crd-vm.md)** -- 👉 **[Option B: KasmVNC + Cloudflare Tunnel (Custom URL + Ultra Fast)](04-option-b-kasm-cloudflare.md)** -- 👉 **[Option C: Apache Guacamole + Tailscale Funnel (HTML5 RDP)](05-option-c-guacamole-rdp.md)** +If Hyper-V was not previously enabled on Windows 11 Pro, the script enables `Microsoft-Hyper-V-All` and asks for one reboot before creating the virtual machine. diff --git a/docs/03-option-a-crd-vm.md b/docs/03-option-a-crd-vm.md index 4512d12..c89bb71 100644 --- a/docs/03-option-a-crd-vm.md +++ b/docs/03-option-a-crd-vm.md @@ -1,81 +1,34 @@ -# 03 — Option A: Hyper-V VM + Chrome Remote Desktop (Inside Guest VM) +# 03 — Optional Guest VM Setup A: Chrome Remote Desktop Inside Ubuntu VM -> ⭐ **Sabse Aasaan Zero-Config Method:** Koi domain kharidne ki zaroorat nahi, koi router port forward nahi, koi IP yaad rakhne ki zaroorat nahi! - -Aapne bilkul sahi pakda tha ki *Chrome Remote Desktop* agar dost ke main Windows par daalo toh woh dost ka system control karta hai. Lekin jab aap **Hyper-V Guest VM ke andar** apna Google account login karke Chrome Remote Desktop set karte ho (aur dost ke main Windows par kuch nahi daalte), toh `https://remoting.google.com/access` kholne par aapko **sirf apne isolated VM ka access** milta hai! +If you provisioned the optional Hyper-V Background VM (`RemoteWorkVM`), one lightweight way to stream the guest Linux desktop with audio and adaptive WebRTC quality is installing headless Chrome Remote Desktop inside the Ubuntu 24.04 VM. --- -## Case 1: Agar VM ke Andar **Windows 10 / 11** Hai - -### Step 1: Basic Session Mode Use Karein (One-Time Tip) -Jab aap pehli baar Hyper-V Manager se VM kholte ho: -1. Agar "Connect to RemoteWorkVM" resolution popup aaye, toh usse **Close (X)** kar dein taaki VM **Basic Session** me khule (View menu me *Enhanced Session* untick hona chahiye). - - *Kyun?* Enhanced Session asal me RDP hota hai; Basic Session virtual monitor (`Microsoft Hyper-V Video`) use karta hai jiske saath Chrome Remote Desktop makkhan ki tarah kaam karta hai. - -### Step 2: VM ke Andar Chrome Remote Desktop Install Karein -1. **VM ke andar** Edge kholkar **Google Chrome** download aur install karein. -2. Chrome me **APNI Google ID** (dost ki nahi!) login karein. -3. VM ke Chrome me yeh URL kholein: - ```text - https://remoting.google.com/access - ``` -4. **"Set up remote access"** ke neeche Download button dabayein -> `.msi` installer run karein. -5. Wapas browser me VM ka naam rakhein (jaise `My-Cloud-VM`) -> **Next** -> ek strong **6+ digit PIN** set karein. - -### Step 3: Verify Auto-Start Service Inside VM -VM ke andar `Win + R` dabayein -> `services.msc` likhein aur check karein: -- **`Chrome Remote Desktop Service`** -> Status: `Running` | Startup Type: **`Automatic`**. -- Iska fayda: Agar VM kabhi pura restart bhi ho jaye aur Windows Lock Screen par ruka ho, tab bhi yeh service boot hote hi chalu ho jaati hai! Aap browser se connect karke Lock Screen unlock kar sakte ho. - -### Step 4: Done! Window Band Kar Dein -1. Dost ke laptop par Hyper-V VM ki window (`vmconnect`) band kar dein (Shut down mat karna, bas `X` daba kar window close kar dein — VM background me chalta rahega!). -2. Ab apne phone ya apne ghar ke PC ke kisi bhi browser me jayein: - 👉 **`https://remoting.google.com/access`** -3. Apni Google ID se login karein -> `My-Cloud-VM` **Online** dikhega -> Click karein -> PIN daalein -> Full Windows VM aapke browser me! 🎉 - ---- - -## Case 2: Agar VM ke Andar **Ubuntu 24.04 LTS (Linux)** Hai *(Fastest & Lightest!)* - -Linux VM sirf **2GB–3GB RAM** me super fast chalta hai. Ubuntu me default GNOME Wayland ki jagah lightweight **XFCE Desktop** ke saath Chrome Remote Desktop lagana sabse reliable tarika hai: +## 1. Install XFCE & Chrome Remote Desktop Inside the Ubuntu VM -### Step 1: VM ke Terminal me XFCE + Chrome Remote Desktop Install Karein -Ubuntu VM kholkar Terminal me yeh commands copy-paste karein: +Run inside the Ubuntu 24.04 guest terminal: ```bash -sudo apt update && sudo apt upgrade -y - -# Lightweight XFCE desktop aur browser install karein -sudo apt install -y xfce4 xfce4-goodies dbus-x11 wget curl - -# Google Chrome + Chrome Remote Desktop package download & install karein -wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb -sudo apt install -y ./google-chrome-stable_current_amd64.deb +sudo apt-get update && sudo apt-get upgrade -y +sudo apt-get install -y xfce4 xfce4-goodies dbus-x11 curl wget wget https://dl.google.com/linux/direct/chrome-remote-desktop_current_amd64.deb -sudo apt install -y ./chrome-remote-desktop_current_amd64.deb +sudo apt-get install -y ./chrome-remote-desktop_current_amd64.deb +rm -f chrome-remote-desktop_current_amd64.deb -# CRD ko XFCE session use karne ke liye set karein echo "exec /etc/X11/Xsession /usr/bin/xfce4-session" > ~/.chrome-remote-desktop-session +sudo usermod -a -G chrome-remote-desktop "$USER" ``` -### Step 2: Headless Auth Command se Link Karein -1. **Apne khud ke laptop/PC** (ya VM ke Chrome) me apni Google ID se yeh page kholein: - 👉 **`https://remoting.google.com/headless`** -2. **Begin** -> **Next** -> **Authorize** par click karein. -3. **"Debian Linux"** wala command copy karein (woh kuch aisa dikhega: `DISPLAY= /opt/google/chrome-remote-desktop/start-host --code="4/0A..." ...`). -4. Woh command **Ubuntu VM ke terminal** me paste karke Enter dabayein aur apna **6-digit PIN** set karein. - -### Step 3: Auto-Start at Boot Enable Karein -```bash -sudo systemctl enable chrome-remote-desktop@$USER.service -sudo loginctl enable-linger $USER -``` +--- -Ab Hyper-V window band kar dein! Jab bhi dost laptop on karega aur Wi-Fi judega, 1 minute ke andar `https://remoting.google.com/access` par aapka Linux Desktop **Online** aa jayega! +## 2. Register Headless Access & Watchdog ---- +1. Generate a Debian headless registration command and execute it inside the Ubuntu VM terminal. +2. Install the Wi-Fi reconnection watchdog (`scripts/guest-watchdog.sh`) via cron so tunnel services automatically recover after host Wi-Fi changes: -## 💡 Bonus: Wi-Fi Drop Auto-Recovery Lagayein -Kabhi-kabhi agar dost ka Wi-Fi 10 minute band hokar wapas aata hai, toh instant reconnect ke liye [`scripts/guest-watchdog.sh`](../scripts/guest-watchdog.sh) ko VM ke andar enable kar lein (Guide [`docs/06-troubleshooting-faq.md`](06-troubleshooting-faq.md) me diya hai). +```bash +sudo cp scripts/guest-watchdog.sh /usr/local/bin/guest-watchdog.sh +sudo chmod +x /usr/local/bin/guest-watchdog.sh +(crontab -l 2>/dev/null; echo "*/2 * * * * /usr/local/bin/guest-watchdog.sh >> /var/log/guest-watchdog.log 2>&1") | crontab - +``` diff --git a/docs/04-option-b-kasm-cloudflare.md b/docs/04-option-b-kasm-cloudflare.md index 8325ec5..84c91c4 100644 --- a/docs/04-option-b-kasm-cloudflare.md +++ b/docs/04-option-b-kasm-cloudflare.md @@ -1,115 +1,28 @@ -# 04 — Option B: Custom Website URL (`https://vm.yourdomain.com`) via KasmVNC + Cloudflare Tunnel +# 04 — Optional Guest VM Setup B: KasmVNC Webtop + Cloudflare Tunnel -> 🔥 **Sabse "Tagda" Pro Developer Setup:** Apni khud ki website (`https://vm.yourdomain.com`) kholo -> Email OTP daalo -> Seedha Browser Tab ke andar High-Speed Desktop (Audio + Clipboard + File Transfer ke saath) chalao! - -Yeh setup **Ubuntu Server 24.04 LTS** Guest VM use karta hai jo sirf **~1.5 GB se 2.5 GB RAM** leta hai — dost ke laptop ko bilkul pata bhi nahi chalega ki koi heavy workload chal raha hai (zero lag!). - ---- - -## Architecture Kaise Kaam Karta Hai? - -```text -Aapka Browser (https://vm.yourdomain.com) - | - v -[ Cloudflare Access Zero Trust ] <-- Sirf AAPKE Email par OTP aayega (100% Free) - | - v (Outbound Encrypted Cloudflare Tunnel — No Port Forwarding!) -[ Hyper-V Ubuntu Server VM ] - | - +--> Docker (`restart: always`) - └── LinuxServer Webtop (KasmVNC Desktop on localhost:3000) -``` - -### Prerequisites: -1. Dost ke Windows 11 Pro par [`docs/02-host-setup-windows11.md`](02-host-setup-windows11.md) follow karke **Ubuntu Server 24.04 LTS** ka VM bana lein (`3GB` Dynamic RAM kaafi hai). -2. Ek sasta domain (jaise `.xyz`, `.tech`, `.in` — ₹99–₹499/year) jo **Cloudflare Free Account** se connected ho. *(Agar domain nahi hai toh Option A ya Option C ka free Tailscale URL use karein).* +If you want your optional Hyper-V Background VM (`RemoteWorkVM`) to expose an embeddable HTTPS desktop stream URL (`streamUrl` inside `agent-config.json`), you can run **LinuxServer Webtop (KasmVNC)** behind a **Cloudflare Zero Trust Tunnel**. --- -## Step 1: Ubuntu VM ke Andar Webtop (KasmVNC) Setup Karein +## 1. Automated Installation Inside the Ubuntu 24.04 Guest VM -Aap hamara automated script [`scripts/guest-linux-kasm-cloudflare.sh`](../scripts/guest-linux-kasm-cloudflare.sh) chala sakte hain, ya neeche diye steps manually run karein: +Run `scripts/guest-linux-kasm-cloudflare.sh` inside the Ubuntu guest VM: ```bash -# 1. Docker & Docker Compose install karein -curl -fsSL https://get.docker.com | sudo sh -sudo usermod -aG docker $USER -newgrp docker - -# 2. Webtop folder banayein -mkdir -p ~/webtop && cd ~/webtop -``` - -Ab `~/webtop/docker-compose.yml` banayein (`nano docker-compose.yml`): - -```yaml -services: - webtop: - image: lscr.io/linuxserver/webtop:ubuntu-xfce - container_name: remote-webtop - security_opt: - - seccomp:unconfined - environment: - - PUID=1000 - - PGID=1000 - - TZ=Asia/Kolkata - - CUSTOM_USER=admin - - PASSWORD=ChangeThisStrongPassword123! - - SUBFOLDER=/ - - TITLE=My Remote Cloud PC - volumes: - - ./data:/config - ports: - - "127.0.0.1:3000:3000" # Sirf localhost par bind hai (bahar se bina tunnel koi access nahi kar sakta) - shm_size: "1gb" # Zaroori: Iske bina container ke andar Chrome crash hota hai! - restart: always # VM start hote hi automatic chalu hoga +export WEBTOP_USER="admin" +export WEBTOP_PASS="ChooseStrongPassword123!" +export CF_TUNNEL_TOKEN="your-cloudflare-tunnel-token" +bash scripts/guest-linux-kasm-cloudflare.sh ``` -Container start karein: -```bash -docker compose up -d -``` - ---- - -## Step 2: Cloudflare Zero Trust Tunnel Connect Karein (Free) - -1. Apne browser me **[Cloudflare Zero Trust Dashboard](https://one.dash.cloudflare.com/)** kholein. -2. Left menu me **Networks -> Tunnels** -> **Create a tunnel** -> **Cloudflared** select karein. -3. Tunnel ka naam rakhein: `friend-laptop-vm` -> **Save tunnel**. -4. **Debian (64-bit)** select karein — wahan aapko ek `curl ... && sudo cloudflared service install ` command milega. -5. Woh command **Ubuntu VM ke terminal** me paste karke run kar dein! - - `cloudflared` ek Linux system service ban jayega jo har reboot par **automatically start** hoga! - -### Public Hostname Set Karein: -Cloudflare Tunnel ke **Public Hostname** tab me: -- **Subdomain:** `vm` -- **Domain:** `yourdomain.com` -- **Service Type:** `HTTP` -- **URL:** `localhost:3000` -- **Save hostname** par click karein! - ---- - -## Step 3: Security Lock Lagayein (Cloudflare Access OTP — MUST DO!) - -Kabhi bhi remote desktop ko sirf password ke bharose public internet par mat chhodna. Cloudflare Access free me **Google Login / Email OTP wall** laga deta hai: - -1. Cloudflare Zero Trust Dashboard -> **Access -> Applications** -> **Add an application** -> **Self-hosted**. -2. **Application name:** `My VM` | **Subdomain:** `vm` | **Domain:** `yourdomain.com`. -3. **Policy Name:** `Only Me` | **Action:** `Allow`. -4. **Configure rules -> Include:** Selector me **`Emails`** chunein aur **sirf apna personal Gmail address** daalein! -5. Save kar dein! +What this script configures: +1. Installs Docker Engine and enables automatic startup (`systemctl enable --now docker`). +2. Launches `lscr.io/linuxserver/webtop:ubuntu-xfce` bound only to `127.0.0.1:3000` with `restart: always`. +3. Installs `cloudflared` as a systemd service so your tunnel reconnects automatically on boot. --- -## 🚀 Kaise Use Karein? +## 2. Protect with Cloudflare Zero Trust Access -1. Dost ke laptop par Hyper-V window close kar dein. -2. Jab bhi dost laptop on karega aur Wi-Fi se connect hoga: - - Hyper-V Ubuntu VM ko background me start karega. - - Docker `remote-webtop` start karega aur `cloudflared` tunnel jod dega. -3. Aap 1 km door apne ghar pe laptop/tablet me browser kholkar **`https://vm.yourdomain.com`** type karoge: - - Cloudflare aapse Email maangega -> Gmail pe OTP aayega -> OTP daalte hi **Pura Ubuntu XFCE Desktop aapke browser tab me khul jayega!** - - Left side me chhota arrow tab hota hai jisse aap **Clipboard Sync, Audio Enable, Fullscreen, aur File Upload/Download** kar sakte ho. +1. In Cloudflare Zero Trust -> **Networks -> Tunnels**, point a subdomain (for example `vm-box.gothwadtech.com`) to `http://localhost:3000`. +2. In **Access -> Applications**, add an Access policy restricting that hostname to your `@gothwadtech.com` email address so unauthenticated visitors never reach the container login screen. diff --git a/docs/05-option-c-guacamole-rdp.md b/docs/05-option-c-guacamole-rdp.md index 400e02d..4e4f657 100644 --- a/docs/05-option-c-guacamole-rdp.md +++ b/docs/05-option-c-guacamole-rdp.md @@ -1,83 +1,21 @@ -# 05 — Option C: Full Windows VM in Browser (RDP / Self-Hosted Gateway Alternatives) +# 05 — Optional Guest VM Setup C: Windows Guest RDP + Apache Guacamole / Tailscale -Agar aapko **Guest VM ke andar Windows 10/11 Pro** hi chalana hai aur aap Google ke Chrome Remote Desktop (Option A) ke alawa **pure Browser URL** alternatives dekh rahe hain, toh yeh 2 tarike sabse best aur lightweight hain: +If your optional Hyper-V Background VM runs **Windows 11 Pro Guest** rather than Linux, you can stream it in any browser using Windows RDP paired with Apache Guacamole or Tailscale. --- -## Method C1: DWService Inside Windows VM (Zero Domain, Ultra-Light ~20MB RAM) +## 1. Enable Remote Desktop Inside the Windows Guest VM -**[DWService](https://www.dwservice.net/)** ek lightweight open-source agent hai jo seedha browser ke andar **Screen Control + File Explorer (Upload/Download) + Command Prompt** teeno de deta hai: +Run inside the Windows 11 Guest VM (not required on the host OS): -1. [`docs/02-host-setup-windows11.md`](02-host-setup-windows11.md) ke hisaab se Hyper-V me **Windows 10/11 Guest VM** banayein. -2. Apne browser me `https://www.dwservice.net` par free account banayein (**2FA / Two-Factor Auth** zaroor on karein) aur **Agents -> New Agent** click karke **Install Code** lein. -3. **Windows Guest VM ke andar** `dwagent.exe` download karke **Install** select karein aur apna Install Code daal dein. -4. `DWAgent` Windows Service ki tarah install ho jaata hai (boot hote hi Lock Screen se pehle chalu ho jaata hai aur sirf ~20MB RAM leta hai!). -5. Ab kahin se bhi browser me `dwservice.net` login karein -> **Screen** click karein -> Pura Windows VM browser me control karein! - ---- - -## Method C2: Apache Guacamole + Tailscale HTTPS (100% Private Self-Hosted HTML5 RDP) - -Agar aap kisi third-party remote screen relay ki jagah **apna khud ka HTML5 RDP Gateway** chalana chahte hain (bina domain kharide!), toh **Apache Guacamole + Tailscale** best combination hai. - -### Architecture: -- **Guest VM 1 (`WinVM` — 3.5GB RAM):** Windows 10/11 Pro jisme built-in **Remote Desktop (RDP Port 3389)** enabled hai. -- **Guest VM 2 (`GatewayVM` — 512MB RAM Alpine/Ubuntu Server):** Isme **Apache Guacamole** (Docker) aur **Tailscale** chalta hai. Dono VMs Hyper-V ke same `Default Switch` par hone ki wajah se aapas me fast local network par baat karte hain! - -### Setup Steps (`GatewayVM` Ubuntu/Debian Mini Server par): - -#### 1. Windows Guest VM (`WinVM`) me RDP Enable Karein: -Windows Guest VM ke andar PowerShell (Admin) kholkar run karein: ```powershell -# Windows VM ke andar RDP enable karein -Set-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server' -name "fDenyTSConnections" -value 0 +Set-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server' -Name "fDenyTSConnections" -Value 0 Enable-NetFirewallRule -DisplayGroup "Remote Desktop" - -# VM ka internal hostname check karein (jaise WinVM.mshome.net) -hostname ``` -#### 2. `GatewayVM` me Docker + Guacamole Chalu Karein: -```bash -curl -fsSL https://get.docker.com | sudo sh -sudo usermod -aG docker $USER && newgrp docker - -mkdir -p ~/guac && cd ~/guac -cat << 'EOF' > docker-compose.yml -services: - guacamole: - image: abesnier/guacamole:latest - container_name: guacamole - ports: - - "127.0.0.1:8080:8080" - volumes: - - ./config:/config - restart: always -EOF - -docker compose up -d -``` - -#### 3. Tailscale HTTPS URL Enable Karein (Free `https://...ts.net` URL, Zero Public Exposure!): -```bash -# Tailscale install karein -curl -fsSL https://tailscale.com/install.sh | sh -sudo tailscale up - -# Port 8080 ko private HTTPS URL par background me serve karein -sudo tailscale serve --bg 8080 -``` +--- -Tailscale aapko ek private URL dega jaise: -👉 `https://gatewayvm.tail12345.ts.net/` +## 2. Connect Without Port Forwarding -#### 4. Guacamole Configure Karein: -1. Apne laptop/phone par **Tailscale** on rakhein aur browser me `https://gatewayvm.tail12345.ts.net/` kholein. -2. Default login (`guacadmin` / `guacadmin`) se ghuste hi **sabse pehle Settings -> Users me jaakar `guacadmin` ka password strong password se badlein aur TOTP 2FA on karein!** -3. **Settings -> Connections -> New Connection:** - - **Protocol:** `RDP` - - **Hostname:** `WinVM.mshome.net` *(Hyper-V `Default Switch` automatic `.mshome.net` local DNS deta hai — IP change hone ka darr bhi khatam!)* - - **Port:** `3389` - - **Username / Password:** Apne Windows VM ka username aur password - - **Security mode:** `NLA` + Tick `Ignore server certificate` -4. Save karein! Ab jab bhi aap browser me apna `https://gatewayvm.tail12345.ts.net` kholenge, click karte hi **Full-Screen 60FPS Windows RDP seedha Chrome/Edge ke andar khulega!** +1. Install **Tailscale** inside the guest VM (`winget install tailscale.tailscale`) and enable unattended mode so it connects before user login. +2. Optionally run **Apache Guacamole** (HTML5 RDP gateway) in Docker to access the Windows VM directly inside your browser over HTTPS without installing an RDP client on your phone or laptop. diff --git a/docs/06-troubleshooting-faq.md b/docs/06-troubleshooting-faq.md index ab5098c..c7362ae 100644 --- a/docs/06-troubleshooting-faq.md +++ b/docs/06-troubleshooting-faq.md @@ -1,74 +1,41 @@ -# 06 — Real-World Troubleshooting, Auto-Recovery & Best Practices +# 06 — Troubleshooting & Frequently Asked Questions -Jab server ek dost ka daily-use Wi-Fi laptop ho, toh real life me kuch practical situations aati hain. Un sabka ready-made solution yahan hai: +Common diagnostics for **Gothwad Remote Desktop (`remotedesktop.gothwadtech.com`)**. --- -## 1. Screen Resolution Fix (`1024x768` se `1920x1080` Full HD Kaise Karein?) +## 1. Computer Shows Offline After Boot -Kabhi-kabhi headless Hyper-V VM me default resolution `1024x768` lock dikhta hai. Isse 1080p Full HD karne ke liye **Dost ke Windows 11 Host PowerShell (Admin)** me ek baar yeh command chala dein: - -```powershell -Set-VMVideo -VMName "RemoteWorkVM" -HorizontalResolution 1920 -VerticalResolution 1080 -ResolutionType Single -``` -*(KasmVNC / Option B aur Chrome Remote Desktop Resize-to-Fit me browser window ke hisaab se resolution apne aap dynamic adjust ho jaata hai!)* - ---- - -## 2. Wi-Fi Disconnect / Hotspot Switch Auto-Recovery - -Agar dost ka router light jaane ki wajah se 10 minute band rahe aur phir wapas on ho, toh 99% time `cloudflared`, `tailscaled`, aur `chrome-remote-desktop` khud reconnect kar lete hain. - -Lekin **100% Bulletproof Guarantee** ke liye Ubuntu Guest VM ke andar hamara watchdog script lagayein: - -```bash -chmod +x scripts/guest-watchdog.sh -sudo cp scripts/guest-watchdog.sh /usr/local/bin/vm-watchdog.sh - -# Har 2 minute me internet + tunnel health check karne ke liye cron job lagayein: -(crontab -l 2>/dev/null; echo "*/2 * * * * /usr/local/bin/vm-watchdog.sh >> /var/log/vm-watchdog.log 2>&1") | crontab - -``` +- Verify the Windows PC has an active Wi-Fi or hotspot internet connection. +- On the Windows PC, check that the scheduled task is running: + ```powershell + Get-ScheduledTask -TaskName "GothwadRemoteAgent" | Select-Object TaskName, State + Start-ScheduledTask -TaskName "GothwadRemoteAgent" + ``` +- Confirm `C:\ProgramData\GothwadRemote\agent-config.json` contains your exact Gothwad username (`ownerUsername`) and slot (`1..6`). --- -## 3. Dost Heavy Gaming Kare Toh Kya? (Give Friend a Pause/Resume Button!) +## 2. Incorrect PIN or 5-Minute Lockout -Dost ke paas 16GB RAM hai. Normal coding, YouTube, MS Office, Chrome me `4GB` VM se unhe **zero farq** padega. Lekin agar dost kabhi heavy AAA game khele aur unhe poora CPU/RAM chahiye ho, toh unke Desktop par 2 chhote shortcuts bana kar de dein (isse dost ka bharosa bhi rahega aur unhe kabhi dikkat nahi aayegi): - -- **Pause VM (Instant Freeze, Frees CPU):** - ```powershell - powershell -Command "Start-Process powershell -Verb runAs -ArgumentList 'Suspend-VM -Name RemoteWorkVM'" - ``` -- **Resume VM:** - ```powershell - powershell -Command "Start-Process powershell -Verb runAs -ArgumentList 'Resume-VM -Name RemoteWorkVM'" - ``` +- After **5 consecutive failed PIN attempts**, `gothwad_agent.py` enforces an automatic **5-minute lockout** to prevent brute-force guessing. +- Wait 5 minutes or update the PIN locally on the Windows PC by re-running `--pair` with owner confirmation. --- -## 4. Laptop Lid Close (Screen Band Karne Par Kya Hoga?) +## 3. Mobile Keyboard or Cursor Control -Default Windows 11 laptop me jab koi **Lid band (screen fold)** karta hai, toh laptop **Sleep** me chala jaata hai aur Wi-Fi band ho jaata hai. -- **Safe Rule:** Agar dost table par charger laga kar lid band karke rakhte hain, toh sirf **`Plugged in -> Closing the lid -> Do nothing`** set kar sakte hain (Control Panel -> Power Options -> Choose what closing the lid does). -- **⚠️ Kabhi Mat Karna:** **`On battery -> Closing the lid`** ko hamesha **`Sleep`** par hi rakhein! Warna bag ke andar laptop garm hokar kharab ho sakta hai. +- Tap the **Keyboard** icon in the floating top viewer bar to open the Android or iOS on-screen keyboard. +- Tap the **Touch / Trackpad** icon to switch between direct tap-to-click mode and laptop-style relative trackpad cursor dragging. --- -## 5. 512GB SSD Space Bachane ka Tarika +## 4. Removing Gothwad Remote Desktop Completely -Hyper-V ka **Dynamically Expanding `.vhdx`** jab VM ke andar files banti hain toh badhta hai, par files delete karne par apne-aap chhota nahi hota. Mahine me ek baar (jab VM shutdown ho) aap space wapas shrink kar sakte ho: +To remove the host service and configuration cleanly from a Windows PC at any time: ```powershell -# Host Admin PowerShell me (VM band hone par): -Optimize-VHD -Path "C:\HyperV\VMs\RemoteWorkVM\Virtual Hard Disks\RemoteWorkVM.vhdx" -Mode Full +Unregister-ScheduledTask -TaskName "GothwadRemoteAgent" -Confirm:$false +Stop-Process -Name "GothwadRemoteAgent*" -Force -ErrorAction SilentlyContinue +Remove-Item -Recurse -Force "C:\Program Files\GothwadRemote", "C:\ProgramData\GothwadRemote" ``` - ---- - -## 6. Security Checklist ✅ - -- [ ] Dost ki explicit permission li gayi hai. -- [ ] Guest VM ke andar strong password laga hai. -- [ ] Browser gateway par **2FA / OTP** on hai (Google Account 2FA for CRD / Cloudflare Access Email OTP / Tailscale Auth). -- [ ] Host PC par koi bhi inbound router port open **nahi** kiya gaya hai. -- [ ] VM ki Maximum RAM `4096 MB` aur CPU limit `60%` par capped hai. diff --git a/docs/07-gothwad-ecosystem-setup.md b/docs/07-gothwad-ecosystem-setup.md index 190eda4..314fff8 100644 --- a/docs/07-gothwad-ecosystem-setup.md +++ b/docs/07-gothwad-ecosystem-setup.md @@ -1,43 +1,36 @@ # 07 — Zero-D1 Cloudflare Pages Deployment (`remotedesktop.gothwadtech.com`) -Yeh guide explain karta hai ki **bina koi alag Cloudflare D1 database ya Worker banaye** (bilkul `GothwadTech/meet` ki tarah!) **`https://remotedesktop.gothwadtech.com`** sirf **60 seconds me Cloudflare Pages** par kaise live hoga! +`GothwadTech/remotedesk` deploys as a pure static **Cloudflare Pages** application — no Cloudflare D1 database, no Worker backend, and no runtime secrets required. --- -## 1. Hume Alag D1 Database Kyun Nahi Chahiye? +## 1. Zero-D1 Architecture Summary -Pehle traditional remote tools device list aur signaling ke liye SQL database use karte the, jisme `wrangler d1 create`, UUIDs, aur secrets maintain karne ka jhanjhat rehta tha. Is project me humne **Zero-D1 P2P Architecture** lagaya hai: - -| Kaam | Zero-D1 Solution (Koi Database Nahi!) | +| Capability | Implementation | | :--- | :--- | -| **Gothwad Login & Multi-Account (`u/0..5`)** | Browser seedha `https://api.gothwadtech.com/api/auth/me` (`credentials: 'include'`) call karta hai! `GothwadTech/accounts` pehle se har `*.gothwadtech.com` subdomain ko allow karta hai. | -| **Auto-Finding Your Windows PCs** | Har PC aapke Gothwad username ke deterministic WebRTC slot (`grd--slot-1`..`6`) par listen karta hai. Login hote hi browser slots ko P2P probe karke Online PCs dikha deta hai! | -| **PIN & Sharing Permissions (`vm_only` / `host_and_vm`)** | Aapka 6-digit PIN aur allowed `@gothwadtech.com` users seedha Windows Host ke `C:\ProgramData\GothwadRemote\agent-config.json` me rehte hain — aur `HMAC-SHA256(pin, nonce:viewer:mode)` challenge-response se verify hote hain (raw PIN kabhi network par nahi jaata!). | -| **60 FPS Screen + Mouse/Keyboard Stream** | `PeerJS` + Google STUN + OpenRelay TURN (`GothwadTech/meet` wala proven CGNAT-bypass WebRTC stack) se seedha Browser ↔ Windows PC ke beech encrypted DTLS tunnel banta hai! | +| **Gothwad SSO & Multi-Account (`u/0..5`)** | Direct browser calls to `https://api.gothwadtech.com/api/auth/me` (`credentials: 'include'`) plus the shared Universal Account Menu widget (`https://accounts.gothwadtech.com/widget/account-menu.js`). | +| **Automatic Device Discovery** | Each paired Windows host listens on deterministic WebRTC slot `grd--slot-1..6`. On sign-in, the web app probes your slots over PeerJS and displays online computers immediately. | +| **PIN & Access Control (`host_and_vm` / `vm_only`)** | Stored locally on the Windows host in `C:\ProgramData\GothwadRemote\agent-config.json` and verified with constant-time `HMAC-SHA256(pin, nonce:viewer:mode)`. | +| **Screen & Input Transport** | End-to-end DTLS-encrypted WebRTC DataChannels (`PeerJS` + Google STUN + OpenRelay TURN over port 443). | --- -## 2. Cloudflare Pages Deployment (Sirf 1 Minute — Zero CLI, Zero Secrets!) +## 2. Deploy to Cloudflare Pages in 60 Seconds -1. **Cloudflare Dashboard** kholein -> **Workers & Pages** -> **Create** -> **Pages** tab -> **Connect to Git**. -2. Apni repo **`GothwadTech/remotedesktop`** select karein. -3. Build settings bharein: +1. Open **Cloudflare Dashboard -> Workers & Pages -> Create -> Pages -> Connect to Git**. +2. Select repository **`GothwadTech/remotedesk`**. +3. Configure build settings: - **Framework preset:** `Vite` - **Build command:** `npm run build` - **Build output directory:** `dist` -4. **Save and Deploy** click karein! -5. Deploy hone ke baad Pages project ke **Custom domains** tab me jaakar **`remotedesktop.gothwadtech.com`** add kar dein. - -**Bas khatam!** Koi `wrangler.toml`, koi D1 database, koi Worker route, ya koi secret key dalne ki zaroorat nahi hai! - -*(Optional: Agar kabhi future me non-`.gothwadtech.com` domain ya mobile app se OAuth consent screen chahiye ho, tabhi sirf `accounts` D1 ke `ecosystem_apps` me `gothwad-remotedesktop` add karna hota hai — web `remotedesktop.gothwadtech.com` ke liye uski bhi zaroorat nahi hai kyunki `.gothwadtech.com` cookie SSO direct kaam karta hai!)* +4. Click **Save and Deploy**. +5. Under **Custom domains**, attach **`remotedesktop.gothwadtech.com`**. --- -## 3. GitHub Actions EXE Release (`GothwadTech/remotedesktop`) +## 3. Build Standalone Windows `.exe` Release via GitHub Actions -Dost ya apne Windows PC par Python install na karna pade, iske liye repo me [`.github/workflows/build-windows-agent.yml`](../.github/workflows/build-windows-agent.yml) laga hua hai: +Repository workflow [`.github/workflows/build-windows-agent.yml`](../.github/workflows/build-windows-agent.yml) compiles `agent/gothwad_agent.py` into `GothwadRemoteAgent-win64.exe` on `windows-latest`: -1. GitHub par **Actions -> Build Windows Agent EXE & Publish GitHub Release -> Run workflow** dabayein (ya `git tag v1.0.0 && git push origin v1.0.0` karein). -2. GitHub ka `windows-latest` server apne-aap **`GothwadRemoteAgent-win64.exe`** aur **`GothwadRemoteSetup-win64.zip`** bana kar **Releases** me daal dega! -3. Uske baad user bas **`https://remotedesktop.gothwadtech.com/setup`** kholega -> wahan diye gaye 1-line PowerShell command ko copy-paste karega -> Owner Consent (`YES`) aur **6-digit PIN** set karega -> PC turant dashboard par **Online** aa jayega! +1. Open **GitHub -> Actions -> Build Windows Agent EXE & Publish GitHub Release -> Run workflow** (or push a version tag such as `v1.0.0`). +2. Download `GothwadRemoteAgent-win64.exe` from Releases or run the one-line PowerShell installer inside the **Set up via PowerShell** tab on `https://remotedesktop.gothwadtech.com`. diff --git a/index.html b/index.html index 545ca8c..b3100ee 100644 --- a/index.html +++ b/index.html @@ -2,16 +2,16 @@ - - + + - Gothwad Remote Desktop — remotedesktop.gothwadtech.com + Gothwad Remote Desktop - +
diff --git a/public/manifest.json b/public/manifest.json index 79c1556..8b662cf 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -1,9 +1,9 @@ { "name": "Gothwad Remote Desktop", "short_name": "Remote Desktop", - "description": "Control your Windows Host OS and headless Hyper-V background VMs in any browser via Gothwad Accounts.", + "description": "Access your Windows computers securely from your phone or browser with your Gothwad Account.", "start_url": "/", "display": "standalone", - "background_color": "#020617", - "theme_color": "#4f46e5" + "background_color": "#212121", + "theme_color": "#212121" } diff --git a/scripts/guest-linux-kasm-cloudflare.sh b/scripts/guest-linux-kasm-cloudflare.sh index 86f6a12..a067ad1 100755 --- a/scripts/guest-linux-kasm-cloudflare.sh +++ b/scripts/guest-linux-kasm-cloudflare.sh @@ -18,7 +18,7 @@ if [[ -z "$WEBTOP_PASS" ]]; then read -rsp "Set a strong password for Webtop user '${WEBTOP_USER}': " WEBTOP_PASS echo "" if [[ ${#WEBTOP_PASS} -lt 8 ]]; then - echo "Error: Password kam se kam 8 characters ka hona chahiye." + echo "Error: Password must be at least 8 characters long." exit 1 fi fi @@ -75,10 +75,10 @@ if [[ -n "$CF_TUNNEL_TOKEN" ]]; then sudo systemctl enable --now cloudflared echo "[+] Cloudflared tunnel service active!" else - echo "[4/4] Skipping cloudflared install (CF_TUNNEL_TOKEN pass nahi kiya gaya)." - echo " Cloudflare Dashboard -> Tunnels me jaakar Debian service command run karein," - echo " aur Public Hostname ko 'http://localhost:3000' par point karein." + echo "[4/4] Skipping cloudflared install (CF_TUNNEL_TOKEN was not provided)." + echo " Open Cloudflare Dashboard -> Tunnels, run the Debian service command," + echo " and point the Public Hostname to 'http://localhost:3000'." fi echo "" -echo "✅ Setup Complete! Container 'remote-webtop' har boot par auto-start hoga." +echo "Setup complete. Container 'remote-webtop' will start automatically on every boot." diff --git a/scripts/guest-watchdog.sh b/scripts/guest-watchdog.sh index e93bbe3..757f769 100755 --- a/scripts/guest-watchdog.sh +++ b/scripts/guest-watchdog.sh @@ -11,7 +11,7 @@ TIMESTAMP="$(date '+%Y-%m-%d %H:%M:%S')" # 1. Check if the host Wi-Fi currently has internet access if ! curl -fsS --max-time 8 https://clients3.google.com/generate_204 >/dev/null 2>&1; then - echo "[$TIMESTAMP] Internet abhi offline hai (Host Wi-Fi disconnected). Waiting for next cycle..." + echo "[$TIMESTAMP] Internet is currently offline (Host Wi-Fi disconnected). Waiting for next cycle..." exit 0 fi diff --git a/scripts/host-setup-hyperv.ps1 b/scripts/host-setup-hyperv.ps1 index ccd1291..5d0322c 100644 --- a/scripts/host-setup-hyperv.ps1 +++ b/scripts/host-setup-hyperv.ps1 @@ -51,15 +51,15 @@ if (-not $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Adm # 2. Check if Hyper-V is enabled $hypervFeature = Get-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V if ($hypervFeature.State -ne "Enabled") { - Write-Host "[!] Hyper-V abhi enabled nahi hai. Enabling Microsoft-Hyper-V-All..." -ForegroundColor Yellow + Write-Host "[!] Hyper-V is not enabled yet. Enabling Microsoft-Hyper-V-All..." -ForegroundColor Yellow Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All - Write-Host "[+] Hyper-V enable ho gaya hai! Please laptop ek baar RESTART karein aur yeh script dobara run karein." -ForegroundColor Green + Write-Host "[+] Hyper-V has been enabled. Please restart this Windows PC once and run this script again." -ForegroundColor Green exit 0 } # 3. Validate ISO file path if (-not (Test-Path -Path $IsoPath)) { - Write-Error "ISO file nahi mili: $IsoPath. Please sahi -IsoPath pass karein." + Write-Error "ISO file not found: $IsoPath. Please pass a valid -IsoPath." exit 1 } @@ -69,7 +69,7 @@ $vhdPath = Join-Path $vmPath "$VMName\$VMName.vhdx" New-Item -ItemType Directory -Force -Path $vmPath | Out-Null if (Get-VM -Name $VMName -ErrorAction SilentlyContinue) { - Write-Error "VM '$VMName' pehle se exist karta hai! Dusra -VMName dein ya purana VM check karein." + Write-Error "VM '$VMName' already exists. Specify a different -VMName or check the existing VM." exit 1 } diff --git a/scripts/install-gothwad-agent.ps1 b/scripts/install-gothwad-agent.ps1 index e50900b..a226532 100644 --- a/scripts/install-gothwad-agent.ps1 +++ b/scripts/install-gothwad-agent.ps1 @@ -4,7 +4,7 @@ .DESCRIPTION - Requires explicit confirmation from the PC owner. - - Downloads GothwadRemoteAgent-win64.exe from GothwadTech/remotedesktop GitHub Releases. + - Downloads GothwadRemoteAgent-win64.exe from GothwadTech/remotedesk GitHub Releases. - Links this PC (Main Windows OS + Hyper-V VM) to your @gothwadtech.com P2P slot. - Registers a transparent startup task ('GothwadRemoteAgent') so it reconnects on boot. #> @@ -23,7 +23,7 @@ param( [string]$VMName = "RemoteWorkVM", [Parameter(Mandatory = $false)] - [string]$ReleaseExeUrl = "https://github.com/GothwadTech/remotedesktop/releases/latest/download/GothwadRemoteAgent-win64.exe" + [string]$ReleaseExeUrl = "https://github.com/GothwadTech/remotedesk/releases/latest/download/GothwadRemoteAgent-win64.exe" ) $ErrorActionPreference = "Stop" @@ -51,12 +51,7 @@ New-Item -ItemType Directory -Force -Path $installDir | Out-Null $exePath = Join-Path $installDir "GothwadRemoteAgent.exe" Write-Host "[1/3] Downloading GothwadRemoteAgent from GitHub Releases..." -ForegroundColor Green -try { - Invoke-WebRequest -Uri $ReleaseExeUrl -OutFile $exePath -} catch { - $fallbackUrl = "https://github.com/GothwadTech/vm/releases/latest/download/GothwadRemoteAgent-win64.exe" - Invoke-WebRequest -Uri $fallbackUrl -OutFile $exePath -} +Invoke-WebRequest -Uri $ReleaseExeUrl -OutFile $exePath Write-Host "[2/3] Configuring Zero-D1 P2P Slot $Slot for '$GothwadUser@gothwadtech.com'..." -ForegroundColor Green & $exePath --pair --gothwad-user $GothwadUser --slot $Slot --device-name $DeviceName --vm-name $VMName --pin $pinPlain --confirm-owner-consent diff --git a/src/App.tsx b/src/App.tsx index ab78166..d475cad 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,382 +1,419 @@ import { useCallback, useEffect, useState } from 'react'; -import { - AlertTriangle, - ArrowRight, - Laptop, - LogIn, - Plus, - Server, - ShieldCheck, - Terminal, -} from 'lucide-react'; +import { Download, Monitor, Plus, Share2, Terminal } from 'lucide-react'; import type { ActiveConnection, RemoteDevice, SessionPayload, TargetMode } from './types'; import { AuthRequiredError, resolveGothwadSession } from './lib/gothwadAuth'; -import { startGothwadOAuthPkce } from './lib/oauthPkce'; import { connectP2PDevice, discoverDevicesForUser, removeBookmarkedPeer, triggerVmPowerOnHost, } from './lib/peerRegistry'; -import { Header, type NavTab } from './components/Header'; import { DeviceCard } from './components/DeviceCard'; +import { Header } from './components/Header'; import { PairDeviceModal } from './components/PairDeviceModal'; -import { ShareAccessModal } from './components/ShareAccessModal'; import { PinPromptModal } from './components/PinPromptModal'; +import { RemoteSupportView } from './components/RemoteSupportView'; import { RemoteViewer } from './components/RemoteViewer'; import { SetupWizard } from './components/SetupWizard'; +import { ShareAccessModal } from './components/ShareAccessModal'; -function readInitialAuthuser(): number { - const pathMatch = window.location.pathname.match(/^\/u\/([0-5])(?:\b|\/)/); - if (pathMatch) return Number(pathMatch[1]); - const q = new URLSearchParams(window.location.search).get('authuser'); - const n = Number(q); - return Number.isInteger(n) && n >= 0 && n <= 5 ? n : 0; -} +type NavTab = 'access' | 'support' | 'headless'; -function readInitialTab(): NavTab { - return window.location.pathname.endsWith('/setup') ? 'setup' : 'access'; +const THEME_STORAGE_KEY = 'gothwad_rd_theme'; + +function getInitialTheme(): 'dark' | 'light' { + try { + const saved = localStorage.getItem(THEME_STORAGE_KEY); + if (saved === 'light' || saved === 'dark') return saved; + } catch { + // ignore storage errors + } + if (typeof window !== 'undefined' && window.matchMedia?.('(prefers-color-scheme: light)').matches) { + return 'light'; + } + return 'dark'; } export function App() { - const [authuser, setAuthuser] = useState(readInitialAuthuser); - const [activeTab, setActiveTab] = useState(readInitialTab); + const [theme, setTheme] = useState<'dark' | 'light'>(getInitialTheme); + const [sidebarOpen, setSidebarOpen] = useState(true); + const [activeTab, setActiveTab] = useState('access'); + + const [authuser, setAuthuser] = useState(() => { + const u = new URLSearchParams(window.location.search).get('authuser'); + return u ? Math.max(0, Math.min(5, Number(u) || 0)) : 0; + }); + const [session, setSession] = useState(null); + const [signinRedirectUrl, setSigninRedirectUrl] = useState(null); const [devices, setDevices] = useState([]); const [loading, setLoading] = useState(true); - const [unauthSigninUrl, setUnauthSigninUrl] = useState(null); - const [serviceError, setServiceError] = useState(null); + const [refreshing, setRefreshing] = useState(false); + const [bannerError, setBannerError] = useState(null); + const [busyAction, setBusyAction] = useState(null); - const [showPairModal, setShowPairModal] = useState(false); + const [pairModalState, setPairModalState] = useState<{ + open: boolean; + tab: 'setup' | 'shared'; + }>({ open: false, tab: 'setup' }); const [shareDevice, setShareDevice] = useState(null); - const [pinTarget, setPinTarget] = useState<{ device: RemoteDevice; mode: TargetMode } | null>( - null, - ); - const [pinError, setPinError] = useState(null); + + const [pendingConnect, setPendingConnect] = useState<{ + device: RemoteDevice; + mode: TargetMode; + } | null>(null); const [connecting, setConnecting] = useState(false); - const [lastVerifiedPin, setLastVerifiedPin] = useState(''); + const [connectError, setConnectError] = useState(null); const [activeConnection, setActiveConnection] = useState(null); - const [busyAction, setBusyAction] = useState(null); - const [toast, setToast] = useState(null); - const showToast = (msg: string) => { - setToast(msg); - setTimeout(() => setToast(null), 3500); - }; + useEffect(() => { + document.documentElement.classList.toggle('dark', theme === 'dark'); + try { + localStorage.setItem(THEME_STORAGE_KEY, theme); + } catch { + // ignore + } + }, [theme]); - const handleChangeTab = (tab: NavTab) => { - setActiveTab(tab); - const url = new URL(window.location.href); - url.pathname = tab === 'setup' ? '/setup' : '/'; - window.history.replaceState({}, '', url.toString()); - }; + const loadWorkspace = useCallback(async (slotIndex: number, quiet = false) => { + if (!quiet) setLoading(true); + else setRefreshing(true); + setBannerError(null); - const loadAll = useCallback(async (slotIndex: number) => { - setLoading(true); - setServiceError(null); - setUnauthSigninUrl(null); try { const sess = await resolveGothwadSession(slotIndex); setSession(sess); + setSigninRedirectUrl(null); const list = await discoverDevicesForUser(sess.user.username); setDevices(list); } catch (err) { if (err instanceof AuthRequiredError) { setSession(null); - setUnauthSigninUrl(err.signinUrl); + setSigninRedirectUrl(err.signinUrl); } else { - setServiceError(err instanceof Error ? err.message : 'Service temporarily unavailable'); + setBannerError(err instanceof Error ? err.message : 'Unable to load computers'); } } finally { setLoading(false); + setRefreshing(false); } }, []); useEffect(() => { - void loadAll(authuser); - }, [authuser, loadAll]); + void loadWorkspace(authuser); + }, [authuser, loadWorkspace]); const handleSwitchAccount = (nextIndex: number) => { const url = new URL(window.location.href); url.searchParams.set('authuser', String(nextIndex)); window.history.replaceState({}, '', url.toString()); - setActiveConnection(null); setAuthuser(nextIndex); }; - const handlePinSubmit = async (pin: string) => { - if (!pinTarget || !session) return; + const handleConfirmConnect = async (pin: string) => { + if (!pendingConnect || !session) return; setConnecting(true); - setPinError(null); + setConnectError(null); try { const conn = await connectP2PDevice( - pinTarget.device, - pinTarget.mode, + pendingConnect.device, + pendingConnect.mode, pin, session.user.username, ); - setLastVerifiedPin(pin); - setPinTarget(null); setActiveConnection(conn); + setPendingConnect(null); } catch (err) { - setPinError(err instanceof Error ? err.message : 'Failed to connect'); + setConnectError(err instanceof Error ? err.message : 'Failed to connect'); } finally { setConnecting(false); } }; - const handleHotSwitchMode = async (nextMode: TargetMode) => { - if (!activeConnection || !session || activeConnection.targetMode === nextMode) return; - try { - activeConnection.p2pHandle?.close(); - const conn = await connectP2PDevice( - activeConnection.device, - nextMode, - lastVerifiedPin, - session.user.username, - ); - setActiveConnection(conn); - } catch (err) { - showToast(err instanceof Error ? err.message : 'Cannot switch target mode'); - } - }; - const handleVmPower = async ( device: RemoteDevice, action: 'start_vm' | 'save_vm' | 'restart_vm', ) => { setBusyAction(`${device.id}:${action}`); try { - const vmState = await triggerVmPowerOnHost(device, action); - showToast(`Sent '${action}' to Hyper-V (${device.vmName}) -> ${vmState}`); - await loadAll(authuser); + await triggerVmPowerOnHost(device, action); + await loadWorkspace(authuser, true); } catch (err) { - showToast(err instanceof Error ? err.message : 'Power action failed'); + setBannerError(err instanceof Error ? err.message : 'VM action failed'); } finally { setBusyAction(null); } }; - const handleUnlink = (device: RemoteDevice) => { - if (device.isDemo) { - showToast('Preview Demo PC resets automatically; real P2P slots unlink via Host CLI.'); - return; - } - if (!window.confirm(`Remove '${device.name}' bookmark from this browser?`)) return; + const handleRemoveBookmark = (device: RemoteDevice) => { removeBookmarkedPeer(device.peerId); - void loadAll(authuser); + void loadWorkspace(authuser, true); }; + if (activeConnection) { + return ( + { + setActiveConnection({ + ...activeConnection, + targetMode: nextMode, + hostNoticeActive: nextMode === 'host_os', + }); + }} + onDisconnect={() => { + activeConnection.p2pHandle?.close(); + setActiveConnection(null); + }} + /> + ); + } + + const navItems: { id: NavTab; label: string; shortLabel: string; icon: typeof Monitor }[] = [ + { id: 'access', label: 'Remote Access', shortLabel: 'Access', icon: Monitor }, + { id: 'support', label: 'Remote Support', shortLabel: 'Support', icon: Share2 }, + { id: 'headless', label: 'Set up via PowerShell', shortLabel: 'PowerShell', icon: Terminal }, + ]; + + const ownedDevice = devices.find((d) => d.role === 'owner') || null; + return ( -
+
void loadAll(authuser)} - onOpenPairModal={() => setShowPairModal(true)} + theme={theme} + refreshing={refreshing} + onToggleSidebar={() => setSidebarOpen((v) => !v)} + onToggleTheme={() => setTheme((t) => (t === 'dark' ? 'light' : 'dark'))} + onRefresh={() => void loadWorkspace(authuser, true)} onSwitchAccount={handleSwitchAccount} + onReloadSession={() => void loadWorkspace(authuser, true)} /> -
- {unauthSigninUrl && ( -
-
- + {signinRedirectUrl ? ( +
+
+
+
-

Sign in with Gothwad Account

-

- 100% Zero-Database Cloudflare Pages Portal. Uses your{' '} - @gothwadtech.com SSO cookie + WebRTC P2P HMAC-SHA256 PIN verification. +

+ Sign in to Remote Desktop +

+

+ Access your Windows computers securely from your phone or another PC with your Gothwad + Account.

-
- - - Continue with Gothwad SSO (.gothwadtech.com) - - -
-
- )} - - {serviceError && ( -
- -

Temporary Connection Issue

-

{serviceError}

- + Sign in with Gothwad +
- )} - - {session && !serviceError && activeTab === 'setup' && ( - { - handleChangeTab('access'); - void loadAll(authuser); - }} - /> - )} - - {session && !serviceError && activeTab === 'access' && ( - <> -
-
- -
-
- Option 1: Main Windows 11 OS Control -
-

- Chrome Remote Desktop jaisa full system access. Host screen par transparent - sharing banner aur Stop button rehta hai. -

-
+
+ ) : ( +
+ {/* Desktop Chrome Remote Desktop left navigation rail */} + + + {/* Main content area */} +
+ {bannerError && ( +
+ {bannerError}
-
- -
-
- Option 2: Headless Hyper-V Background VM + )} + + {activeTab === 'access' && ( +
+ {/* Card 1: Remote devices */} +
+
+

+ Remote devices +

+ +
+ + {loading ? ( +
+
+
+ ) : devices.length === 0 ? ( +
+

+ No remote computers are online +

+

+ Turn on remote access on your Windows computer below, or add a computer + shared with your Gothwad Account. +

+
+ ) : ( +
+ {devices.map((dev) => ( + { + setConnectError(null); + setPendingConnect({ device, mode }); + }} + onVmPower={(device, act) => void handleVmPower(device, act)} + onOpenShare={(device) => setShareDevice(device)} + onRemoveBookmark={handleRemoveBookmark} + /> + ))} +
+ )} +
+ + {/* Card 2: Set up remote access */} +
+
+
+
+ +
+
+

+ Set up remote access +

+

+ Access your Windows 11 computer from your phone or another PC anytime. +

+
+
+ +
-

- Dost apna laptop normal use karta rahe — aap background isolated VM me kaam - karo, dost ki screen/mouse bilkul touch nahi hogi! -

-
+
-
+ )} + + {activeTab === 'support' && ( + setShareDevice(dev)} + onOpenSetup={() => setActiveTab('headless')} + onConnectedBookmark={() => { + setActiveTab('access'); + void loadWorkspace(authuser, true); + }} + /> + )} + + {activeTab === 'headless' && ( + { + setActiveTab('access'); + void loadWorkspace(authuser, true); + }} + /> + )} +
- {devices.length === 0 ? ( -
- -

- No Online Windows PCs Detected Yet -

-

- Open the Windows Setup Wizard for step-by-step PowerShell commands to link your - first PC via WebRTC P2P (Zero D1 Database!). -

+ {/* Mobile fixed bottom navigation bar */} +
- ) : ( -
- {devices.map((dev) => ( - { - setPinError(null); - setPinTarget({ device: d, mode }); - }} - onVmPower={handleVmPower} - onOpenShares={(d) => setShareDevice(d)} - onUnlink={handleUnlink} - /> - ))} -
- )} - -
-
-
- -
-
-

- Set up another Windows computer via PowerShell -

-

- Step-by-step Hyper-V VM builder, Gothwad Account P2P pairing command, aur{' '} - .exe installer seedha yahin se copy karein. -

-
-
- -
- - )} -
- - {showPairModal && session && ( - { - setShowPairModal(false); - handleChangeTab('setup'); - }} - onClose={() => { - setShowPairModal(false); - void loadAll(authuser); - }} - /> - )} - - {shareDevice && ( - setShareDevice(null)} /> + ); + })} + +
)} - {pinTarget && ( - setPinTarget(null)} - /> - )} + setPairModalState((s) => ({ ...s, open: false }))} + onOpenPowerShellSetup={() => setActiveTab('headless')} + onPaired={() => void loadWorkspace(authuser, true)} + /> - {activeConnection && session && ( - { - activeConnection.p2pHandle?.close(); - setActiveConnection(null); - }} - /> - )} + setShareDevice(null)} /> - {toast && ( -
- {toast} -
- )} + + setPendingConnect((prev) => (prev ? { ...prev, mode } : null)) + } + onClose={() => setPendingConnect(null)} + onConfirm={(pin) => void handleConfirmConnect(pin)} + />
); } diff --git a/src/components/AccountMenu.tsx b/src/components/AccountMenu.tsx new file mode 100644 index 0000000..11917db --- /dev/null +++ b/src/components/AccountMenu.tsx @@ -0,0 +1,170 @@ +import { useEffect, useRef } from 'react'; +import type { SessionPayload } from '../types'; +import { + ACCOUNTS_API_ORIGIN, + ACCOUNTS_WEB_ORIGIN, + APP_DOMAIN, + buildGothwadSignInUrl, + ECOSYSTEM_NAME, + manageAccountUrl, + signOutAccountSlotOnServer, + signOutAllOnServer, + switchAccountOnServer, +} from '../lib/gothwadAuth'; +import { + ensureGothwadAccountMenu, + pickAvatarColor, + type WidgetAccountItem, +} from './gothwadAccountMenuFallback'; + +interface AccountMenuProps { + session: SessionPayload | null; + authuser: number; + onSwitchAccount: (index: number) => void; + onReloadSession: () => void; +} + +export function AccountMenu({ + session, + authuser, + onSwitchAccount, + onReloadSession, +}: AccountMenuProps) { + const btnRef = useRef(null); + + useEffect(() => { + if (session) void ensureGothwadAccountMenu(); + }, [session]); + + if (!session) { + return ( + + Sign in + + ); + } + + const extraCount = Math.max(0, session.accounts.length - 1); + const fullName = session.user.name || session.user.username; + const initial = (fullName[0] || session.user.username[0] || 'G').toUpperCase(); + + const handleOpen = async () => { + const widget = await ensureGothwadAccountMenu(); + if (widget.isOpen()) { + widget.close(); + return; + } + + const mappedAccounts: WidgetAccountItem[] = ( + session.accounts.length > 0 + ? session.accounts + : [ + { + index: authuser, + id: session.activeId || 'a', + username: session.user.username, + email: session.user.email, + name: fullName, + avatarUrl: session.user.avatarUrl, + active: true, + }, + ] + ).map((acc) => { + const n = acc.name || acc.username; + const parts = n.split(' '); + return { + id: acc.id, + authuser: acc.index, + username: acc.username, + firstName: parts[0] || acc.username, + lastName: parts.slice(1).join(' '), + name: n, + email: acc.email, + avatarUrl: acc.avatarUrl, + active: acc.active, + }; + }); + + const userParts = fullName.split(' '); + const currentUserItem: WidgetAccountItem = { + id: session.activeId || 'a', + authuser, + username: session.user.username, + firstName: userParts[0] || session.user.username, + lastName: userParts.slice(1).join(' '), + name: fullName, + email: session.user.email, + avatarUrl: session.user.avatarUrl, + active: true, + }; + + widget.open( + { + user: currentUserItem, + accounts: mappedAccounts, + activeId: session.activeId || currentUserItem.id, + authuser, + }, + { + anchorEl: btnRef.current, + appDomain: APP_DOMAIN, + accountsWebOrigin: ACCOUNTS_WEB_ORIGIN, + accountsApiOrigin: ACCOUNTS_API_ORIGIN, + ecosystemName: ECOSYSTEM_NAME, + authuser, + nextUrl: window.location.href, + manageAccountHref: manageAccountUrl(authuser), + onSwitchAccount: async (acc) => { + await switchAccountOnServer(acc.id); + onSwitchAccount(acc.authuser); + }, + onSignOutAccount: async (slotOrAcc) => { + const slotId = typeof slotOrAcc === 'string' ? slotOrAcc : slotOrAcc.id; + if (slotId) { + await signOutAccountSlotOnServer(slotId); + onReloadSession(); + } + }, + onSignOutAll: async () => { + await signOutAllOnServer(); + }, + }, + ); + }; + + return ( + + ); +} diff --git a/src/components/CopyCodeBlock.tsx b/src/components/CopyCodeBlock.tsx index bc60f24..03e1b06 100644 --- a/src/components/CopyCodeBlock.tsx +++ b/src/components/CopyCodeBlock.tsx @@ -1,38 +1,50 @@ import { useState } from 'react'; -import { Check, Copy, Terminal } from 'lucide-react'; +import { Check, Copy } from 'lucide-react'; interface CopyCodeBlockProps { - label: string; - command: string; + title: string; + language?: string; + code: string; } -export function CopyCodeBlock({ label, command }: CopyCodeBlockProps) { +export function CopyCodeBlock({ title, language = 'powershell', code }: CopyCodeBlockProps) { const [copied, setCopied] = useState(false); const handleCopy = async () => { - await navigator.clipboard.writeText(command); + await navigator.clipboard.writeText(code); setCopied(true); setTimeout(() => setCopied(false), 2000); }; return ( -
-
- - - {label} - +
+
+
+ {title} + + {language} + +
-
-        {command}
+      
+        {code}
       
); diff --git a/src/components/DeviceCard.tsx b/src/components/DeviceCard.tsx index d91486d..e183df5 100644 --- a/src/components/DeviceCard.tsx +++ b/src/components/DeviceCard.tsx @@ -1,12 +1,11 @@ +import { useEffect, useRef, useState } from 'react'; import { - Cpu, HardDrive, - Laptop, - Lock, + Monitor, + MoreVertical, + Pause, Play, RotateCcw, - Save, - Server, Share2, Trash2, } from 'lucide-react'; @@ -17,8 +16,8 @@ interface DeviceCardProps { busyAction: string | null; onConnect: (device: RemoteDevice, mode: TargetMode) => void; onVmPower: (device: RemoteDevice, action: 'start_vm' | 'save_vm' | 'restart_vm') => void; - onOpenShares: (device: RemoteDevice) => void; - onUnlink: (device: RemoteDevice) => void; + onOpenShare: (device: RemoteDevice) => void; + onRemoveBookmark?: (device: RemoteDevice) => void; } export function DeviceCard({ @@ -26,212 +25,211 @@ export function DeviceCard({ busyAction, onConnect, onVmPower, - onOpenShares, - onUnlink, + onOpenShare, + onRemoveBookmark, }: DeviceCardProps) { - const ramPct = Math.min( - 100, - Math.round((device.hostRamUsedMb / Math.max(1024, device.hostRamTotalMb)) * 100), - ); - const ramUsedGb = (device.hostRamUsedMb / 1024).toFixed(1); - const ramTotalGb = (device.hostRamTotalMb / 1024).toFixed(0); + const [menuOpen, setMenuOpen] = useState(false); + const menuRef = useRef(null); - return ( -
-
-
-
- -
-
-
-

{device.name}

- - - {device.online ? 'Online via Wi-Fi' : 'Offline'} - - - {device.role === 'owner' - ? `Owner: ${device.ownerUsername}` - : `Shared (${device.accessScope === 'host_and_vm' ? 'Host + VM' : 'VM Only'})`} - -
-

{device.osInfo}

-
-
+ useEffect(() => { + if (!menuOpen) return; + const handleOutside = (e: MouseEvent) => { + if (menuRef.current && !menuRef.current.contains(e.target as Node)) { + setMenuOpen(false); + } + }; + document.addEventListener('mousedown', handleOutside); + return () => document.removeEventListener('mousedown', handleOutside); + }, [menuOpen]); - {device.role === 'owner' && ( -
- - -
- )} -
+ const primaryMode: TargetMode = device.canControlHostOs ? 'host_os' : 'hyperv_vm'; - {/* Host Telemetry Bar */} -
-
- -
-
- Host RAM - - {ramUsedGb} / {ramTotalGb} GB ({ramPct}%) - -
-
-
-
-
-
- -
- -
- Host CPU: - {device.hostCpuPercent}% - (VM cap 60%) -
-
- -
- Hyper-V `{device.vmName}`: + return ( +
+
- {/* Dual-Mode Remote Launch Cards */} -
- {/* Mode 1: Main Windows 11 Host OS */} -
-
-
- - - Mode 1: Main Windows 11 OS - - - Full System +
+
+ + {device.name} + + {device.isDemo && ( + + Demo -
-

- Chrome Remote Desktop jaisa direct Host screen, mouse & files control (Host par - transparent sharing banner dikhega). -

+ )}
- -
- {device.canControlHostOs ? ( - - ) : ( -
- - Restricted to Owner (`vm_only` share) -
+
+ + {device.online ? 'Online' : 'Offline'} + + · + {device.osInfo} + {device.role === 'shared' && ( + <> + · + + Shared by @{device.ownerUsername} + {!device.canControlHostOs ? ' (VM only)' : ''} + + )}
+ - {/* Mode 2: Isolated Background Hyper-V VM */} -
-
-
- - - Mode 2: Background Hyper-V VM - - - Headless Isolated - -
-

- Dost ki screen/mouse bilkul disturb nahi hogi. 100% isolated background VM (`Max 4GB` - RAM, auto-boot). -

-
+
+ {device.canControlHostOs && device.canControlVm && ( + + )} + + + +
+ + + {menuOpen && ( +
+ {device.canControlHostOs && ( + + )} + + {device.canControlVm && ( + + )} + +
-
- - -
+ + + + {device.role === 'owner' && ( + <> +
+ + + )} + + {device.role === 'shared' && !device.isDemo && onRemoveBookmark && ( + <> +
+ + + )}
-
+ )}
diff --git a/src/components/Header.tsx b/src/components/Header.tsx index 0506577..669e3b2 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -1,205 +1,81 @@ -import { useState } from 'react'; -import { - ChevronDown, - ExternalLink, - Monitor, - Plus, - RefreshCw, - ShieldCheck, - Terminal, -} from 'lucide-react'; +import { Menu, Monitor, Moon, RefreshCw, Sun } from 'lucide-react'; import type { SessionPayload } from '../types'; - -export type NavTab = 'access' | 'setup'; +import { AccountMenu } from './AccountMenu'; interface HeaderProps { session: SessionPayload | null; authuser: number; - activeTab: NavTab; - loading: boolean; - onChangeTab: (tab: NavTab) => void; + theme: 'dark' | 'light'; + refreshing: boolean; + onToggleSidebar: () => void; + onToggleTheme: () => void; onRefresh: () => void; - onOpenPairModal: () => void; onSwitchAccount: (index: number) => void; + onReloadSession: () => void; } export function Header({ session, authuser, - activeTab, - loading, - onChangeTab, + theme, + refreshing, + onToggleSidebar, + onToggleTheme, onRefresh, - onOpenPairModal, onSwitchAccount, + onReloadSession, }: HeaderProps) { - const [menuOpen, setMenuOpen] = useState(false); - - const initials = (session?.user.name || session?.user.username || 'G') - .split(/\s+/) - .map((p) => p[0]?.toUpperCase() || '') - .slice(0, 2) - .join(''); - return ( -
-
-
- +
+
+ - {/* Google-Remote-Desktop Style Navigation Tabs */} - {session && ( - - )} +
+
+ +
+ + Remote Desktop +
+
-
- - - - - {session && ( -
- - - {menuOpen && ( -
-
-
- {session.user.name || session.user.username} -
-
{session.user.email}
- {session.source === 'dev' && ( - - Preview / Local Dev Session - - )} -
+
+ - {session.accounts.length > 0 && ( -
-
- Switch Gothwad Account (u/0..5) -
- {session.accounts.map((acc) => ( - - ))} -
- )} + - -
- )} -
- )} +
+
diff --git a/src/components/HeadlessPairStep.tsx b/src/components/HeadlessPairStep.tsx deleted file mode 100644 index aa52f4b..0000000 --- a/src/components/HeadlessPairStep.tsx +++ /dev/null @@ -1,148 +0,0 @@ -import { useState } from 'react'; -import { Download, KeyRound, ShieldAlert } from 'lucide-react'; -import { buildHostPeerId } from '../lib/protocol'; -import { CopyCodeBlock } from './CopyCodeBlock'; - -interface HeadlessPairStepProps { - username: string; - userEmail: string; - vmName: string; - stepNumber: number; -} - -const RELEASE_EXE_URL = - 'https://github.com/GothwadTech/remotedesktop/releases/latest/download/GothwadRemoteAgent-win64.exe'; -const RELEASE_ZIP_URL = - 'https://github.com/GothwadTech/remotedesktop/releases/latest/download/GothwadRemoteSetup-win64.zip'; - -export function HeadlessPairStep({ - username, - userEmail, - vmName, - stepNumber, -}: HeadlessPairStepProps) { - const [slot, setSlot] = useState(1); - const [deviceLabel, setDeviceLabel] = useState('Dost-Win11Pro-Laptop'); - - const peerId = buildHostPeerId(username, slot); - - const oneLinePs = `irm https://raw.githubusercontent.com/GothwadTech/remotedesktop/main/scripts/install-gothwad-agent.ps1 -OutFile setup.ps1; .\\setup.ps1 -GothwadUser "${username}" -Slot ${slot} -DeviceName "${deviceLabel}" -VMName "${vmName}"`; - - const manualExeCmd = `.\\GothwadRemoteAgent-win64.exe --pair --gothwad-user "${username}" --slot ${slot} --device-name "${deviceLabel}" --vm-name "${vmName}" --pin 123456 --confirm-owner-consent`; - - return ( -
-
-
- - {stepNumber} - -

- Link Windows PC to Your Gothwad Account (Zero-Database WebRTC P2P) -

-
- - Peer ID: {peerId} - -
- -

- Koi cloud database ki zaroorat nahi! Windows Agent seedha aapke Gothwad Account ( - {userEmail}) ke P2P slot ({peerId}) par encrypted WebRTC se - connect hota hai aur HMAC-SHA256 6-digit PIN verify karta hai. -

- -
- - - Consent Rule: Yeh command sirf PC owner ki permission se Admin PowerShell - me run karein. Script aapse YES consent aur aapka 6-digit PIN{' '} - set karne ko kahega (PIN sirf us PC par encrypted rehta hai). - -
- -
-
- - setDeviceLabel(e.target.value)} - placeholder="e.g. Dost-Win11Pro-Laptop" - className="mt-1 w-full rounded-lg border border-slate-700 bg-slate-950 px-3 py-2 text-xs text-white focus:border-indigo-500 focus:outline-none" - /> -
- -
- - -
-
- -
-
-
- - Method A (Recommended): 1-Command Auto Download + Install + Startup Service -
-

- Windows par Win + X → Terminal (Admin) kholkar yeh - single command paste karein: -

- -
- -
-
-
-
- Method B: Manual EXE / ZIP Download (GitHub Releases) -
-

- Standalone .exe download karke manually pair karne ke liye: -

-
- -
- -
-
-
- ); -} diff --git a/src/components/PairDeviceModal.tsx b/src/components/PairDeviceModal.tsx index b239f77..d0d9e55 100644 --- a/src/components/PairDeviceModal.tsx +++ b/src/components/PairDeviceModal.tsx @@ -1,131 +1,182 @@ import { useState } from 'react'; -import { ArrowRight, KeyRound, ShieldAlert, Users, X } from 'lucide-react'; +import { Download, Plus, Terminal, X } from 'lucide-react'; import { addBookmarkedPeer } from '../lib/peerRegistry'; -import { CopyCodeBlock } from './CopyCodeBlock'; +import { buildHostPeerId, sanitizeGothwadUsername } from '../lib/protocol'; interface PairDeviceModalProps { - username: string; - onOpenFullGuide: () => void; + open: boolean; + initialTab?: 'setup' | 'shared'; + currentUsername: string; onClose: () => void; + onOpenPowerShellSetup: () => void; + onPaired: () => void; } -export function PairDeviceModal({ username, onOpenFullGuide, onClose }: PairDeviceModalProps) { +const RELEASE_EXE_URL = + 'https://github.com/GothwadTech/remotedesk/releases/latest/download/GothwadRemoteAgent-win64.exe'; + +export function PairDeviceModal({ + open, + initialTab = 'setup', + currentUsername, + onClose, + onOpenPowerShellSetup, + onPaired, +}: PairDeviceModalProps) { + const [tab, setTab] = useState<'setup' | 'shared'>(initialTab); + const [ownerUsername, setOwnerUsername] = useState(''); const [slot, setSlot] = useState(1); - const [friendUsername, setFriendUsername] = useState(''); - const [friendSlot, setFriendSlot] = useState(1); - const [addedPeer, setAddedPeer] = useState(null); - const psCommand = `irm https://raw.githubusercontent.com/GothwadTech/remotedesktop/main/scripts/install-gothwad-agent.ps1 -OutFile setup.ps1; .\\setup.ps1 -GothwadUser "${username}" -Slot ${slot}`; + if (!open) return null; + + const myPeerId = buildHostPeerId(currentUsername, 1); - const handleBookmarkFriend = () => { - if (!friendUsername.trim()) return; - const peerId = addBookmarkedPeer(friendUsername, friendSlot); - setAddedPeer(peerId); - setFriendUsername(''); + const handleBookmark = (e: React.FormEvent) => { + e.preventDefault(); + const clean = sanitizeGothwadUsername(ownerUsername); + if (!clean) return; + addBookmarkedPeer(clean, slot); + setOwnerUsername(''); + onPaired(); + onClose(); }; return ( -
-
-
-
- -

- Add / Connect Windows PC (Zero-D1 P2P) -

+
+
+
+
+

+ {tab === 'setup' ? 'Set up remote access' : 'Add shared computer'} +

+

+ {tab === 'setup' + ? 'Install the lightweight host service on your Windows 11 PC.' + : 'Bookmark a computer that another Gothwad user shared with you.'} +

-
- - - Explicit Owner Consent Required: Kisi bhi PC par setup sirf owner ki - permission ke saath Admin PowerShell me karein. - +
+ +
-
-
-
- - + {tab === 'setup' ? ( +
+
+

+ Download and run the installer on your Windows PC, or use the one-line PowerShell + setup. Once registered under{' '} + + {currentUsername}@gothwadtech.com + {' '} + (Host ID {myPeerId}), it appears here + automatically. +

- -
-
-
- - 2. Ya kisi dost ka Shared PC connect karein: +
+ + + Download Host (.exe) + + +
-

- Agar kisi dusre Gothwad user ne aapko apne PC/VM par allow kiya hai, toh unka username - daalein: -

-
+
+ ) : ( +
+
+ setFriendUsername(e.target.value)} - placeholder="Friend's Gothwad username" - className="flex-1 rounded-lg border border-slate-700 bg-slate-950 px-3 py-1.5 text-xs text-white" + required + placeholder="e.g. alex or alex@gothwadtech.com" + value={ownerUsername} + onChange={(e) => setOwnerUsername(e.target.value)} + className="w-full rounded-xl border border-neutral-300 bg-white px-3.5 py-2 text-sm text-neutral-900 focus:border-[#0494f4] focus:outline-hidden dark:border-neutral-700 dark:bg-[#1b1b1b] dark:text-white" /> +
+ +
+ +
+ +
+
- {addedPeer && ( -

- Added {addedPeer} to discovery list! -

- )} -
-
- -
- -
+ + )}
); diff --git a/src/components/PinPromptModal.tsx b/src/components/PinPromptModal.tsx index 70f0f42..ec08ddf 100644 --- a/src/components/PinPromptModal.tsx +++ b/src/components/PinPromptModal.tsx @@ -1,105 +1,141 @@ -import { useState, type FormEvent } from 'react'; -import { KeyRound, Laptop, Server, X } from 'lucide-react'; +import { useState } from 'react'; +import { HardDrive, Lock, Monitor, X } from 'lucide-react'; import type { RemoteDevice, TargetMode } from '../types'; interface PinPromptModalProps { - device: RemoteDevice; + device: RemoteDevice | null; targetMode: TargetMode; - error: string | null; connecting: boolean; - onSubmit: (pin: string) => void; + error: string | null; + onChangeMode: (mode: TargetMode) => void; onClose: () => void; + onConfirm: (pin: string) => void; } export function PinPromptModal({ device, targetMode, - error, connecting, - onSubmit, + error, + onChangeMode, onClose, + onConfirm, }: PinPromptModalProps) { - const [pin, setPin] = useState(device.id === 'dev_demo_win11' ? '123456' : ''); + const [pin, setPin] = useState(device?.isDemo ? '123456' : ''); + + if (!device) return null; - const handleSubmit = (e: FormEvent) => { - e.preventDefault(); - if (pin.trim()) onSubmit(pin.trim()); - }; + const canSwitchMode = device.canControlHostOs && device.canControlVm; return ( -
-
-
-
- {targetMode === 'host_os' ? ( - - ) : ( - - )} -

- {targetMode === 'host_os' - ? 'Connect to Main Windows 11 OS' - : `Connect to Hyper-V VM (${device.vmName})`} -

+
+
+
+
+
+ +
+
+

+ Enter PIN +

+

{device.name}

+
-

- {targetMode === 'host_os' - ? 'Direct Host OS mode: Host screen par Chrome Remote Desktop jaisa "Shared with your Gothwad Account" banner dikhega.' - : 'Headless Background VM mode: Dost ka desktop/mouse bilkul untouched rahega; aap seedha isolated Hyper-V VM me connect hoge.'} -

+ {canSwitchMode && ( +
+ + +
+ )} -
- - setPin(e.target.value)} - placeholder="••••••" - className="mt-1.5 w-full rounded-lg border border-slate-700 bg-slate-950 px-3 py-2.5 text-center font-mono text-lg tracking-[0.4em] text-white focus:border-indigo-500 focus:outline-none" - /> -
+ { + e.preventDefault(); + onConfirm(pin); + }} + className="mt-4 space-y-4" + > +
+ + setPin(e.target.value)} + placeholder="••••••" + className="w-full rounded-xl border border-neutral-300 bg-white px-4 py-2.5 text-center font-mono text-lg tracking-[0.35em] text-neutral-900 focus:border-[#0494f4] focus:outline-hidden dark:border-neutral-700 dark:bg-[#1b1b1b] dark:text-white" + /> +
- {error &&

{error}

} + {targetMode === 'host_os' && ( +

+ A visible banner will appear on the remote Windows screen while you are connected. +

+ )} -
- - -
- + {error && ( +
+ {error} +
+ )} + +
+ + +
+ +
); } diff --git a/src/components/RemoteSupportView.tsx b/src/components/RemoteSupportView.tsx new file mode 100644 index 0000000..4adc0cc --- /dev/null +++ b/src/components/RemoteSupportView.tsx @@ -0,0 +1,149 @@ +import { useState } from 'react'; +import { ArrowRight, Check, Copy, MonitorUp, Share2 } from 'lucide-react'; +import type { RemoteDevice } from '../types'; +import { addBookmarkedPeer } from '../lib/peerRegistry'; +import { buildHostPeerId, sanitizeGothwadUsername } from '../lib/protocol'; + +interface RemoteSupportViewProps { + currentUsername: string; + ownedDevice: RemoteDevice | null; + onOpenShareModal: (device: RemoteDevice) => void; + onOpenSetup: () => void; + onConnectedBookmark: () => void; +} + +export function RemoteSupportView({ + currentUsername, + ownedDevice, + onOpenShareModal, + onOpenSetup, + onConnectedBookmark, +}: RemoteSupportViewProps) { + const [remoteInput, setRemoteInput] = useState(''); + const [copiedId, setCopiedId] = useState(false); + + const myHostId = buildHostPeerId(currentUsername, 1); + + const handleCopyId = async () => { + await navigator.clipboard.writeText(myHostId); + setCopiedId(true); + setTimeout(() => setCopiedId(false), 2000); + }; + + const handleConnectRemote = (e: React.FormEvent) => { + e.preventDefault(); + const raw = remoteInput.trim().toLowerCase(); + if (!raw) return; + + // Accept either a Peer ID ("grd-alex-slot-2") or a Gothwad username/email ("alex") + const slotMatch = raw.match(/^grd-([a-z0-9-]+)-slot-([1-6])$/); + if (slotMatch) { + addBookmarkedPeer(slotMatch[1], Number(slotMatch[2])); + } else { + const clean = sanitizeGothwadUsername(raw); + if (!clean) return; + addBookmarkedPeer(clean, 1); + } + setRemoteInput(''); + onConnectedBookmark(); + }; + + return ( +
+ {/* Card 1: Share this screen */} +
+
+

+ Share this screen +

+

+ Allow another Gothwad user to view and control your Windows computer or isolated + Background VM. +

+
+ +
+
+ Your Host ID +
+ + {myHostId} + + +
+
+ + {ownedDevice ? ( + + ) : ( + + )} +
+
+ + {/* Card 2: Connect to another computer */} +
+
+

+ Connect to another computer +

+

+ Enter the Host ID or Gothwad username of the computer shared with you. +

+
+ +
+ setRemoteInput(e.target.value)} + placeholder="Host ID or username (e.g. grd-alex-slot-1 or alex)" + className="min-w-0 flex-1 rounded-xl border border-neutral-300 bg-white px-3.5 py-2 text-sm text-neutral-900 focus:border-[#0494f4] focus:outline-hidden dark:border-neutral-700 dark:bg-[#1b1b1b] dark:text-white" + /> + +
+
+
+ ); +} diff --git a/src/components/RemoteViewer.tsx b/src/components/RemoteViewer.tsx index 3ab442b..c187704 100644 --- a/src/components/RemoteViewer.tsx +++ b/src/components/RemoteViewer.tsx @@ -1,260 +1,353 @@ -import { useEffect, useRef, useState, type MouseEvent } from 'react'; +import { useEffect, useRef, useState } from 'react'; import { + ChevronDown, + ChevronUp, Clipboard, Command, - Laptop, + Hand, + HardDrive, + Keyboard, Maximize2, - PhoneOff, - Server, - ShieldCheck, - Wifi, + Minimize2, + Monitor, + MousePointer, + X, } from 'lucide-react'; import type { ActiveConnection, TargetMode } from '../types'; interface RemoteViewerProps { connection: ActiveConnection; - viewerEmail: string; onSwitchMode: (mode: TargetMode) => void; onDisconnect: () => void; } -export function RemoteViewer({ - connection, - viewerEmail, - onSwitchMode, - onDisconnect, -}: RemoteViewerProps) { - const containerRef = useRef(null); - const [liveFrameUrl, setLiveFrameUrl] = useState(null); - const [cursorPos, setCursorPos] = useState({ x: 48, y: 52 }); - const [clipboardText, setClipboardText] = useState(''); - const [showClipboard, setShowClipboard] = useState(false); - const [lastEventLog, setLastEventLog] = useState('Zero-D1 WebRTC P2P DTLS DataChannel ready'); +export function RemoteViewer({ connection, onSwitchMode, onDisconnect }: RemoteViewerProps) { + const containerRef = useRef(null); + const stageRef = useRef(null); + const mobileInputRef = useRef(null); + + const [barOpen, setBarOpen] = useState(true); + const [isFullscreen, setIsFullscreen] = useState(false); + const [touchMode, setTouchMode] = useState<'touch' | 'trackpad'>('touch'); + const [cursor, setCursor] = useState({ x: 50, y: 50 }); + const [liveFrame, setLiveFrame] = useState(null); + const [typedPreview, setTypedPreview] = useState(''); + const [toast, setToast] = useState(null); + + const dragRef = useRef<{ lastX: number; lastY: number } | null>(null); + const isHostOs = connection.targetMode === 'host_os'; + const canSwitch = connection.device.canControlHostOs && connection.device.canControlVm; useEffect(() => { - setLiveFrameUrl(null); - if (!connection.p2pHandle) return; - connection.p2pHandle.onFrame((jpegDataUrl) => { - setLiveFrameUrl(jpegDataUrl); - }); - return () => { - connection.p2pHandle?.close(); - }; + connection.p2pHandle?.onFrame((jpegUrl) => setLiveFrame(jpegUrl)); }, [connection]); - const sendInputPacket = (payload: Record) => { - connection.p2pHandle?.sendInput(payload); + useEffect(() => { + const onFsChange = () => setIsFullscreen(Boolean(document.fullscreenElement)); + document.addEventListener('fullscreenchange', onFsChange); + return () => document.removeEventListener('fullscreenchange', onFsChange); + }, []); + + const flashToast = (msg: string) => { + setToast(msg); + setTimeout(() => setToast(null), 1800); + }; + + const toggleFullscreen = async () => { + if (!document.fullscreenElement && containerRef.current) { + await containerRef.current.requestFullscreen().catch(() => undefined); + } else if (document.fullscreenElement) { + await document.exitFullscreen().catch(() => undefined); + } + }; + + const sendPointer = (type: 'move' | 'click', xPct: number, yPct: number) => { + const clampedX = Math.max(0, Math.min(100, xPct)); + const clampedY = Math.max(0, Math.min(100, yPct)); + setCursor({ x: clampedX, y: clampedY }); + connection.p2pHandle?.sendInput({ + type: 'MOUSE', + action: type, + x: Number((clampedX / 100).toFixed(4)), + y: Number((clampedY / 100).toFixed(4)), + }); }; - const handleCanvasMove = (e: MouseEvent) => { + const handleStageClick = (e: React.MouseEvent) => { + if (touchMode === 'trackpad') { + sendPointer('click', cursor.x, cursor.y); + return; + } const rect = e.currentTarget.getBoundingClientRect(); - const xPct = Math.round(((e.clientX - rect.left) / rect.width) * 100); - const yPct = Math.round(((e.clientY - rect.top) / rect.height) * 100); - setCursorPos({ x: xPct, y: yPct }); - sendInputPacket({ type: 'MOUSE_MOVE', xPct, yPct }); + const xPct = ((e.clientX - rect.left) / rect.width) * 100; + const yPct = ((e.clientY - rect.top) / rect.height) * 100; + sendPointer('click', xPct, yPct); }; - const handleSendCtrlAltDel = () => { - sendInputPacket({ type: 'HOTKEY', combo: 'ctrl+alt+del' }); - setLastEventLog('Sent Ctrl + Alt + Del over WebRTC P2P'); + const handleTouchStart = (e: React.TouchEvent) => { + if (touchMode !== 'trackpad' || e.touches.length !== 1) return; + dragRef.current = { lastX: e.touches[0].clientX, lastY: e.touches[0].clientY }; + }; + + const handleTouchMove = (e: React.TouchEvent) => { + if (touchMode !== 'trackpad' || !dragRef.current || e.touches.length !== 1 || !stageRef.current) + return; + const rect = stageRef.current.getBoundingClientRect(); + const dx = ((e.touches[0].clientX - dragRef.current.lastX) / rect.width) * 125; + const dy = ((e.touches[0].clientY - dragRef.current.lastY) / rect.height) * 125; + dragRef.current = { lastX: e.touches[0].clientX, lastY: e.touches[0].clientY }; + sendPointer('move', cursor.x + dx, cursor.y + dy); }; - const handlePushClipboard = () => { - sendInputPacket({ type: 'CLIPBOARD', text: clipboardText }); - setLastEventLog(`Synced clipboard (${clipboardText.length} chars)`); - setShowClipboard(false); + const handleSendCtrlAltDel = () => { + connection.p2pHandle?.sendInput({ type: 'KEY_COMBO', keys: ['Control', 'Alt', 'Delete'] }); + flashToast('Sent Ctrl + Alt + Del'); }; - const toggleFullscreen = () => { - if (!document.fullscreenElement) { - void containerRef.current?.requestFullscreen(); - } else { - void document.exitFullscreen(); + const handleSyncClipboard = async () => { + try { + const text = await navigator.clipboard.readText(); + if (text) { + connection.p2pHandle?.sendInput({ type: 'CLIPBOARD', text }); + flashToast('Clipboard sent to remote computer'); + } else { + flashToast('Clipboard is empty'); + } + } catch { + flashToast('Clipboard permission denied by browser'); } }; - const isHostMode = connection.targetMode === 'host_os'; + const openMobileKeyboard = () => { + mobileInputRef.current?.focus(); + flashToast('Keyboard active'); + }; + + const handleHiddenKeyDown = (e: React.KeyboardEvent) => { + connection.p2pHandle?.sendInput({ type: 'KEY', key: e.key }); + if (e.key === 'Backspace') { + setTypedPreview((prev) => prev.slice(0, -1)); + } else if (e.key.length === 1) { + setTypedPreview((prev) => (prev + e.key).slice(-48)); + } + }; return (
{ + if (document.activeElement === mobileInputRef.current) return; + connection.p2pHandle?.sendInput({ type: 'KEY', key: e.key }); + }} + className="fixed inset-0 z-50 flex flex-col bg-black text-white select-none focus:outline-hidden" > -
-
- - - {connection.device.name} - - -
+ {/* Hidden input to summon virtual keyboard on Android / iOS */} + { + const val = e.target.value; + if (val) { + connection.p2pHandle?.sendInput({ type: 'TEXT', text: val }); + setTypedPreview((prev) => (prev + val).slice(-48)); + } + }} + onKeyDown={handleHiddenKeyDown} + className="pointer-events-none fixed -top-20 left-0 h-1 w-1 opacity-0" + /> + + {/* Collapsible Chrome Remote Desktop floating top control bar */} +
+ {!barOpen ? ( + + ) : ( +
+
+ + + {connection.device.name} + + + {isHostOs ? 'Main Desktop' : 'Background VM'} + +
+ +
+ + + + + + {canSwitch && ( + + )} + + + + + + + +
-
+ )} -
- - - - -
+ {toast && ( +
+ {toast} +
+ )}
- {showClipboard && ( -
-
Sync Clipboard to Remote
-