Public Access
Storage: share the card with a phone's browser (#88)
`w` in the Storage App starts a small HTTP server and shows its address, as a QR code and in letters, with a six-digit code. A browser on the same network that has typed the code can list, download, upload, make folders and delete, under the Storage App's rules. The server runs only while that screen is open. Nothing is encrypted, and the screen says so. Uploads are streamed to the card under a temporary name and renamed when whole. Every access to the card is handed to the storage task, 8 KB at a time, from the server's own task. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include "debug_auth.h"
|
||||
|
||||
// The parts of sharing files with a browser (issue #88) that need no network: what a request
|
||||
// asks for, whether it may, and the answers as JSON. The server itself is src/services/web_share.h.
|
||||
namespace roro::files {
|
||||
|
||||
std::string urlDecode(const std::string& text); // %41 is A; a + stays a +
|
||||
// The value of `key` in a query string ("path=%2Fnotes&replace=1"), decoded. False if it isn't there.
|
||||
bool queryParam(const std::string& query, const std::string& key, std::string& out);
|
||||
// The value of a cookie in a Cookie header ("a=1; s=abc"), or "".
|
||||
std::string cookieValue(const std::string& header, const std::string& name);
|
||||
|
||||
// A path a browser may name: from the card's root, no "..", nothing a file name can't hold.
|
||||
// "" or why not.
|
||||
std::string checkSharePath(const std::string& path);
|
||||
|
||||
std::string jsonString(const std::string& text); // with its quotes
|
||||
|
||||
// A folder's listing as the page wants it: {"path":"/notes","items":[{"n":"a.txt","s":12,"d":0,"t":1791400000}],"more":false}
|
||||
class ShareListing {
|
||||
public:
|
||||
explicit ShareListing(const std::string& path);
|
||||
void add(const std::string& name, uint32_t size, bool folder, int64_t modified);
|
||||
std::string json(bool more);
|
||||
size_t count() const { return count_; }
|
||||
|
||||
private:
|
||||
std::string out_;
|
||||
size_t count_ = 0;
|
||||
};
|
||||
|
||||
// Who may use the page: whoever typed the code the device's screen shows. The code is new each
|
||||
// time sharing starts; five wrong ones in a row close the door for a minute (as the Debug
|
||||
// Console's token does). A browser that got it right is given a token to send back as a cookie.
|
||||
// Nothing here is encrypted on the way: see the issue.
|
||||
class ShareAuth {
|
||||
public:
|
||||
enum class Result { Ok, Wrong, Locked };
|
||||
|
||||
void begin(const uint8_t random[4]); // a new code, and nobody is logged in
|
||||
const std::string& code() const { return code_; } // six digits
|
||||
Result login(const std::string& code, uint32_t nowMs, const uint8_t random[16], std::string& token);
|
||||
bool allowed(const std::string& token) const;
|
||||
|
||||
private:
|
||||
std::string code_, token_;
|
||||
debug::AuthGate gate_;
|
||||
};
|
||||
|
||||
} // namespace roro::files
|
||||
Reference in New Issue
Block a user