
Revived the Naked Labs Fitness mirror
Hello everyone ever since Naked Labs/Prism Labs shutdown the cloud late 2023. I've kept an eye on Reddit posts hoping someone would have found a way to get the scanner/app working again. Over the last couple of weeks I figured I'd finally give it a go since we still had the mirror and scale. With some persistence and some help from Claude. I now have the mirror fully working again, 100% offline with measurements and the little 3d model on iOS.
I'm pretty much at feature parity from where the original app/ecosystem was. Little 3D model, side by side comparison with some upgrades with HealthKit integration. I'm proxying all the API/Service calls to a mock cloud running off of a MacBook Pro I use as a media server. I'm working on a blog post series that covers the process. Along with what you'd need to do to fully revive yours if you still have it as well. I also added a calibration cycle since I was getting some odd weight readings to the real app. 5 measurements plus your weight from a working scale and the values are pretty solid. The firmware had no mechanism exposed to recalibrate.
Link to Debug App for side loading: NakedLabs Mirror Debug App
edit: fixed formatting
Debug App Screenshot:
Summary of my findings, plus a debug app you can clone and side load to test your mirror if you still have it:
The mirror is recoverable because:
- It runs Yocto Linux on an Intel mini-PC, not Android.
- The cloud was an orchestration layer + S3-credentials handout — not a compute layer. All CV runs on the mirror (SLAM, multi-camera registration, body-model fitting, body-fat estimator). Scan output gets zipped and uploaded as
capture.zip. - The HTTPS client uses the OS trust store. Inject a self-signed cert + redirect
api.nakedfit.netin/etc/hostsand you control the conversation.
What you need to extract from the mirror:
- Root shell. Local tty1 only (rear USB + Display ports). User
root, empty password. SSH is locked down out of the box; plant your Mac's pubkey at/home/root/.ssh/authorized_keysafter first login. - Cloud-API library:
/usr/lib/libcloud_api_library.so.strings+objdump -dagainst this gives you the 9 endpoints the mirror calls, thenaked-device-hashauth header format, and the exact JSON shapes each handler parses (look forweb::json::value::at(string)call sequences). - Coordinator binary:
/usr/bin/coordinator. State machine, error codes (INT_ERR_CLD_*), subprocess names for the CV pipeline. - Device hash file:
/mnt/bootfs/tpm/key.priv. The mirror's identity. Empty string works against my mock — no enforcement. /etc/ssl/certs/ca-certificates.crt— back this up before injecting your CA.
How I mocked the cloud:
- ~850 lines of stdlib Python on a Mac mini on my LAN. Single-file HTTPS server, no dependencies.
- Self-signed cert with
CN=api.nakedfit.netand SAN entries for*.s3.amazonaws.comandnaked-scans-mock.s3.*.amazonaws.com. - Add
<LAN-host-IP> api.nakedfit.netto mirror's/etc/hosts, append your CA to its/etc/ssl/certs/ca-certificates.crt. - Endpoints to handle:
GET /hardware/me,POST /hardware/me/status,POST /scans/{capture,capture/queue,reconstruction,complete,location,status}. Return JSON shapes match what the disassembly shows the parsers expect —needsOobemust be int not bool,scanCodelives nested insidecapture,preCapturemust be a nested object, etc. - The S3 upload that follows the create-capture call uses credentials you returned in the response. Bucket name + region + scanCode are all yours. Your
/etc/hostscovers the bucket hostname too.
iOS side:
- Debug app (
NakedMirrorDebug) — 16-step BLE/HTTP runbook; behavioral truth against the live mirror. Tells you what each characteristic does and which writes are destructive. Public: github.com/Laszlo-Lazuer/nakedmirror-debug - Real app (
NakedMirror) — production SwiftUI client. Polls/inbox/scanson the mock cloud, unzips, persists to SwiftData, renders the PLY with SceneKit, writes HealthKit per scan. Private — reach out if you have a mirror to recover. - Mock cloud (
nakedfit-server/mock_cloud.py) — the LAN HTTPS server. Private for the same reason.