A portable offline file-sharing device built on the AI Thinker ESP32-CAM. Creates its own WiFi network and serves a web-based file manager over SD card storage.
  • C++ 96.1%
  • C 3.9%
Find a file
RGBToaster 461d2727b5
Fix admin login, duplicate definitions, SP upload slot check, and security issues
- Add /admin/login POST handler with session token and 4-hour expiry
- Add /admin/logout GET handler to clear session
- Strip monolithic function duplicates from icons.cpp (broken linker)
- Remove duplicate JS, QR_JS, rmRecursive, and upload state from pages.cpp
- Fix SP upload slot check (was checking stale globals instead of queue pos)
- Add rate limiting (10 attempts/5min, 5min lockout) on login and SP code entry
- Upgrade randToken to use esp_random() HW RNG with [a-z0-9] charset
- Add SameSite=Strict to cookies, session expiry tracking
- Change static const char* to constexpr in config.h
- Remove dead isAdminHost() code, fix duplicate CFG_UPLOAD_SLOTS assignment
2026-06-26 22:58:17 +02:00
src Fix admin login, duplicate definitions, SP upload slot check, and security issues 2026-06-26 22:58:17 +02:00
.gitignore initial push 2026-06-26 03:33:56 +02:00
platformio.ini initial push 2026-06-26 03:33:56 +02:00
README.md rewritten readme 2026-06-26 04:04:06 +02:00

PocketNAS

A portable offline file-sharing device built on the AI Thinker ESP32-CAM. Creates its own WiFi network and serves a web-based file manager over SD card storage.


Hardware

  • AI Thinker ESP32-CAM
  • MicroSD card (FAT32)

(Could not test it on a normal ESP32 since i don't have one.)


Building

Requires PlatformIO.

pio run --target upload

Dependencies (resolved automatically by PlatformIO):

  • ESP32Async/AsyncTCP @ ^3.3.2
  • ESP32Async/ESPAsyncWebServer @ ^3.7.0

Partition scheme: huge_app (3MB code / 1MB SPIFFS) - set in platformio.ini, required due to the size of the embedded HTML/CSS/JS.


First Boot

On first boot (or if the SD card has no config), the device starts in setup mode. Connect to the WiFi network PocketNAS (open, no password) and navigate to http://storage.local or http://192.168.4.1. A three-step wizard will walk you through:

  1. Network name - the SSID the device broadcasts
  2. Sharepoint - enable or disable the guest sharing feature
  3. Passwords and settings - admin password, and either a WiFi password (if sharepoint is disabled) or upload slot count and code lifetime (if enabled)

The device reboots after saving. Config is stored at /.pnas/nas.conf on the SD card.


Interfaces

PocketNAS exposes two separate web interfaces, distinguished by the Host: header. Both run on the same IP (192.168.4.1).

Interface URL Fallback IP Purpose
Admin storage.local 192.168.4.1 Full file manager, protected by admin password
Sharepoint sharepoint.local 192.168.4.2 Guest access, protected by time-limited code

If mDNS isn't resolving (common on some devices), the fallback IPs work identically.


Admin Interface

Log in with the admin password set during setup. From here you can:

  • Browse, upload, download files and folders
  • Create and delete folders
  • Rename files and folders
  • View files inline (images, video, audio, PDF, text) or download anything
  • Manage sharepoints and generate guest access codes
  • View the QR code for easy connection sharing

All per-item actions (rename, delete, sharepoint, download) are behind a menu on each row.


Sharepoint

Sharepoint lets you expose specific files or folders to guests without giving them access to the rest of the SD card.

Setting up a sharepoint

  1. In the admin file manager, open the menu on any file or folder
  2. Click Sharepoint
  3. Choose an access mode:
    • Read Only - guests can browse and download, no uploads
    • Write Only - guests can upload files, but cannot see or download anything (suitable for collecting submissions privately)
    • Read + Write - guests can both upload and download
  4. Go to Sharepoint in the header to generate an access code

Guest access

Guests connect to the same WiFi network and navigate to sharepoint.local (or 192.168.4.2). They enter the 6-digit code and immediately land in the shared folder or file. They see it as their root - no other paths on the SD are visible or accessible.

Codes expire after the configured TTL (default 1 hour). Multiple codes for different paths can be active simultaneously. Codes can be revoked early from the Sharepoint admin page.

Upload slots

To prevent the ESP32 from being overwhelmed when multiple guests upload simultaneously, uploads are queued. The slot count (set during setup, default 3) controls how many uploads can proceed at once. Waiting guests see their position in the queue and are notified when a slot opens.


Configuration

/.pnas/nas.conf on the SD card, key=value format. Lines starting with # are comments. The setup wizard generates this file - you can also edit it by hand.

Key Default Description
ap_ssid PocketNAS WiFi network name
admin_password - Password for storage.local
sp_disabled false Set true to disable all sharepoint features
ap_password - WiFi password, only used when sp_disabled=true
upload_slots 3 Max concurrent uploads (sharepoint only, 110)
code_ttl 3600 Guest code lifetime in seconds

When sp_disabled=true, the WiFi network uses WPA2 with ap_password, the sharepoint interface is completely removed, and the device behaves as a simple private file server.

The /.pnas/ directory is hidden from the browser interface and cannot be browsed, downloaded, or modified through the web UI.


Source layout

src/
├── PocketNAS.ino   hardware init, WiFi, DNS, entry point
├── config.h/.cpp   config file, sharepoint map
├── auth.h/.cpp     admin session, guest codes, upload queue
├── files.h/.cpp    SD operations, upload handler
├── icons.h/.cpp    SVG icon strings
├── assets.h/.cpp   CSS, JS, QR encoder (flash-stored)
├── pages.h/.cpp    HTML page builders
├── routes.h/.cpp   HTTP route registration, request dispatch
└── util.h/.cpp     string, path, and MIME helpers

Known limitations

  • Single WiFi radio - only one network at a time. Sharepoint guests and admin share the same AP; the Host header distinguishes which interface to serve.
  • mDNS reliability varies by OS. Some devices may need the IP fallback.
  • SD card writes are not atomic. If power is lost mid-upload, the partial file will remain on the card.
  • The upload queue is in-memory and resets on reboot. Guests in a queue will need to rejoin after a power cycle.

© 2026 CrystalSky | Code AI Assisted