Three connected pieces, so downloads stop being write-only.
1. A folder the user can actually find. ios-patch.sh now sets UIFileSharingEnabled
and LSSupportsOpeningDocumentsInPlace, and downloads go to the app's Documents
folder in typed subfolders. iOS shows it as:
Files -> On My iPhone -> Biz Connect -> Images | Videos | Files
Previously everything was written to CACHE (private, and iOS purges it whenever
it likes) and pushed straight at the share sheet, so nothing was ever really
"kept" by the app.
2. Manage storage (Settings -> Storage). Lists what this device has downloaded,
grouped by type with per-group and total sizes; each row can be shared to the OS
sheet (this is where "Save to Photos" now lives) or deleted. Plus Delete all.
Deleting removes ONLY the local copy — the attachment stays on the server, so
anything deleted can be downloaded again from the chat.
3. A downloaded video never downloads twice. Images and files have their own
download link, but a video's tile IS the player, so it had no control at all and
re-streamed on every play. It now carries a download button; once saved, the
button becomes a tick and the tile plays from the local file — no network.
The index is treated as a cache of the filesystem, never as truth, because the user
can delete these from the Files app behind our back: every listing re-stats and
forgets what is gone, the library is reconciled at startup, and a local file that
has vanished by play time falls straight back to streaming instead of showing a
broken player.
Unit-checked the path allocator: collisions between different attachments with the
same filename resolve to "name (2)", re-downloading the SAME attachment reuses its
path, and path traversal / illegal characters are neutralised.
Note: the folder and the save location need a new iOS build to take effect. The web
side degrades cleanly — none of this UI appears outside the native app.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Remote Access Platform — Alpha
A self-hostable remote support platform for IT teams: technicians log in to a web
console, see their team's machines, and start a screen-share + remote-control
session to any online machine after the end user grants consent. Built to the
spec in PRD-remote-access-platform.md.
This alpha implements the PRD's P0 requirements: authenticated console, MFA, RBAC, machine enrollment, per-session consent, WebRTC screen streaming + remote input, and an immutable audit log.
remote-access-app/
├── server/ Backend: HTTP API + WebSocket signaling + SQLite
│ ├── server.js Auth, MFA, machines, audit API + signaling broker
│ ├── auth.js scrypt passwords, TOTP MFA, tokens (no external auth deps)
│ ├── db.js Schema via Node's built-in node:sqlite
│ ├── public/ Web console (index.html) + remote viewer (viewer.html)
│ └── test/e2e.js 26-check end-to-end test of the whole backend flow
└── agent/ Native host agent (Electron)
├── main.js Consent window, screen source, OS input injection
├── input/inject.js Mouse/keyboard injection via nut-js (Win32 SendInput)
└── renderer/ Agent UI + WebRTC screen capture
Quick start
1. Server (any OS, Node 22.5+)
cd server
npm install # only dependency is `ws`
npm start # serves http://localhost:8090
Open http://localhost:8090, click Register team, then set up MFA
(add the shown secret to Google Authenticator / Authy / 1Password and enter a code).
Log in, and enroll a machine — you'll get an AGENT_ENROLL_TOKEN.
2. Agent (on the Windows/macOS PC to be controlled)
cd agent
npm install # installs Electron + nut-js (input injection)
set SERVER_URL=http://<server-ip>:8090 # Windows
set AGENT_ENROLL_TOKEN=<token from console>
npm start
The agent window comes online; the machine shows green in the console. Click Connect in the console — the agent shows a consent prompt. On Allow, the technician sees the live screen and can control it. A red banner stays on the host screen for the whole session, and every step is written to the audit log.
Set a machine to unattended at enrollment to skip the consent prompt (for servers / headless machines), per the PRD's unattended-access policy.
What's tested (in this sandbox)
cd server && npm test # 26/26 checks pass
cd agent && npm run test:input # 5/5 input-mapping checks pass
The e2e test drives the real backend: register → enable MFA → login (password + TOTP) → enroll machine → agent connects → technician requests session → consent → SDP/ICE relay → session end → audit verification → consent-denial path.
What requires real hardware (not testable in a headless sandbox)
- OS input injection runs through
nut-js(Win32SendInputon Windows,CGEventon macOS). Without it installed,inject.jsdegrades to a safe logging no-op so the agent still runs. Verify on a real desktop. - Screen capture uses Electron's
desktopCapturer/getDisplayMedia.
Architecture notes
- Media is peer-to-peer. The server only brokers signaling (SDP/ICE) and consent; screen frames and input never pass through it. Channels are DTLS-encrypted by WebRTC.
- NAT traversal uses a public STUN server. ~10–15% of connections behind symmetric NATs will need a TURN relay (coturn) — the next infra item.
- Auth uses scrypt password hashing and RFC-6238 TOTP, implemented on Node's
built-in
crypto— nobcrypt/jsonwebtoken/speakeasydependencies. - Storage is
node:sqlite(built into Node 22.5+), so the backend has a single runtime dependency (ws).
Gaps before production (from PRD §5)
- TURN relay for non-P2P connections (coturn).
- macOS/Linux agents + code-signed installers; packaged Windows binary.
- File transfer, clipboard sync, multi-monitor (PRD P1).
- SSO, session recording, SOC 2 (PRD P1/T8).
- Harden signaling: rate limiting, per-session authz checks, CSRF on cookie API.