Signature
Open a WebDAV server as a folder, and sign the Markdown saved to it with an ENS name.
- Version
- 0.1.1
- Plugin-API
- 0.1.0
- Downloads
- 3
- Likes
- 0
In Memona installieren
Öffne zum Installieren die Plugins in Memona und suche unter Durchsuchen.
Anleitung
# 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](https://github.com/capsulizers/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 | Key | Meaning | | --- | --- | --- | | Server address | `url` | The folder's address, for example `https://dav.example.com/files/` | | Username | `username` | Optional account name for HTTP basic authentication | | Password | `password` | Optional password, stored as a secret | | Signer name | `ensName` | Optional. The ENS name that signs, for example `laptop.alice.eth` | | Signing key | `privateKey` | Optional. The private key of the address that owns the name, stored as a secret | | Sepolia RPC address | `rpcUrl` | The endpoint used to check signers against ENS, by default `https://ethereum-sepolia-rpc.publicnode.com` | | Trusted parent name | `trustedParent` | Optional. Only signers that are this name or one of its subnames count, for example `team.eth` | Give the signer name and signing key together, or leave both empty for a verify-only folder: reads still show a verdict, and a Markdown save is stored unsigned, byte for byte except the verdict line, so a signature the file already carries stays and an edit then reads as Tampered. Giving only one of the two refuses the connection. The connection's allowed hosts must include the RPC address's host as well as the server's, or every check reads as Sepolia unreachable. 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 checks its signature against ENSv2 on Sepolia and adds an `ens-verification` line to the frontmatter Memona receives, which Memona shows as a badge. The owner of the signer name comes from the Universal Resolver's `findOwner`, so a name its parent revoked stops counting at once. | Badge | Meaning | | --- | --- | | `Verified: bob.team.eth` | The name's current owner signed this exact body | | `Tampered: signed as bob.team.eth` | The body changed after signing, or another key signed it | | `Unauthorized: bob.team.eth is not registered` | The signature holds, but no one owns the name now: it was revoked or never granted | | `Unauthorized: bob.team.eth is not a member of team.eth` | The signer is outside the trusted parent name | | `Unsigned` | The file has no `signer` and `signature` | | `Not checked: Sepolia unreachable` | The RPC address did not answer, so nothing was decided | | `Not checked: file too large` | The file is over 96 KiB, too large to hash within one call | | Verified | Tampered | | --- | --- | |  |  | | Unauthorized | Unsigned | | --- | --- | |  |  | The line never reaches the server: a save drops it before signing, and one stored on the server is replaced, so a file cannot claim its own verdict. Verdicts are reused for 30 seconds per signed body, a failed lookup included, so an editor rereading a file does not flood the RPC. Stat, list and saves keep reporting the stored size and the server's etag, so `If-Match` works as before. Memona gives each call into a plugin a fixed instruction budget, which is where the size limits come from: checking hashes the body and recovers a key, so it covers files up to 96 KiB, the same as signing; a file up to 1 MiB is marked not checked, and a larger one streams through without a badge. ## Building ```sh 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](https://git.capsulizers.com/lead/memona) 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: ```sh 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](https://git.capsulizers.com/commons/memona-plugin-webdav) 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.