Co-authored-by: Danny Kim <temeddix@gmail.com> Co-committed-by: Danny Kim <temeddix@gmail.com>
4.0 KiB
Memona signature plugin
Opens a WebDAV server as a folder inside Memona and signs every Markdown file
saved to it with an ENS name, writing signer and signature into the file's
frontmatter so anyone can check who wrote it against the name's current ENSv2
records. Signing comes from the
md-ens-signature library.
The plugin is a WASI component: it speaks no sockets of its own and makes every
request through the host's HTTP interface, under the connection's permissions.
It registers one provider, signature, for the signed-webdav scheme.
Connecting
| Field | Meaning |
|---|---|
| Server address | The folder's address, for example https://dav.example.com/files/ |
| Username | Optional account name for HTTP basic authentication |
| Password | Optional password, stored as a secret |
| Signer name | The ENS name that signs, for example laptop.alice.eth |
| Signing key | The private key of the address the name resolves to, stored as a secret |
| Sepolia RPC address | The endpoint used to check signers against ENS, by default https://ethereum-sepolia-rpc.publicnode.com |
Listing, reading, writing, creating directories, renaming and deleting behave
as in the WebDAV plugin: reads and writes stream in pieces of at most 1 MiB,
conditional writes use If-Match and If-None-Match, change polling is not
supported, a rename never replaces an existing target, and a folder with
contents is refused rather than removed whole.
Signing
Saving a .md file holds it whole, up to 96 KiB, and writes it once finished,
with signer and signature set in its frontmatter; every other file streams
straight through. The signature is EIP-191 personal_sign over the signer name
and the body's SHA-256, made with the configured key; other frontmatter and the
body stay byte for byte. A key that is not 32 bytes of hex refuses the
connection, and a .md file that is not UTF-8 refuses the save.
Verifying
Reading a .md file of up to 40 KiB checks its signature against ENSv2 on
Sepolia through the RPC address and adds an ens-verification line to the
frontmatter Memona receives, which Memona shows as a badge; a larger one up to
1 MiB is marked as not checked. Both limits keep hashing and key recovery
inside the instruction budget Memona gives each call. The line never
reaches the server: a save drops it before signing, and one stored on the
server is replaced. Verdicts are reused for 30 seconds per signed body.
Building
rustup target add wasm32-wasip2
cargo build --locked --release --target wasm32-wasip2
cargo test --locked --lib
The component lands at
target/wasm32-wasip2/release/memona_plugin_signature.wasm.
wit/filesystem.wit is a copy of the canonical Memona filesystem contract, and
src/sdk.rs generates the guest bindings from it, so this repository builds
without a Memona checkout. Refresh the copy from plugin_system/sdk/wit in the
Memona repository when the contract
moves, and keep apiVersion in manifest.json in step.
Packaging for the plugin store
A .memona-plugin package is a ZIP archive with the files at its root, never
inside a directory:
cargo build --locked --release --target wasm32-wasip2
cp target/wasm32-wasip2/release/memona_plugin_signature.wasm plugin.wasm
zip memona-plugin-signature.memona-plugin \
manifest.json plugin.wasm README.md LICENSE
manifest.json and plugin.wasm are required; README.md becomes the guide on
the plugin's public page and LICENSE is shown beside it.
Attribution
The WebDAV code in src/lib.rs, src/dav.rs and src/sdk.rs is copied from
the MIT-licensed
Memona WebDAV plugin
at commit 3d69750. That crate keeps its provider, reader and writer private
and exports the component's entry points itself, so it cannot be wrapped as a
dependency without forking it; the copy stays as close to the original as the
signing hook allows, so fixes there carry over with a plain diff.