Files
Danny Kim 90a54034f7
CI / checks (push) Successful in 53s
FTP connections preserve passwords and filenames, with CI checking every change (#1)
Co-authored-by: Danny Kim <temeddix@gmail.com>
Co-committed-by: Danny Kim <temeddix@gmail.com>
2026-09-30 13:10:40 +00:00

76 lines
2.8 KiB
Markdown

# Memona FTP plugin
Opens an FTP or FTPS server as a folder in [Memona](https://memona.app), so
files on it are browsed, read, written and renamed like local ones, and agents
work in them.
The plugin is a WebAssembly component built against the Memona filesystem
contract, `memona:filesystem@0.1.0`. It uses only the host's sockets; it has no
ambient filesystem, environment or network access of its own.
This package requires a Memona version that supports plugin manifest schema 2.
## What it registers
One provider, `ftp`, for the `ftp` and `ftps` schemes. A connection is
configured with a server name, an optional port, a TLS toggle for FTPS, and an
optional username and password. An empty username signs in anonymously.
With the compatible schema 2 Memona version required by this package, public,
LAN, VPN, link-local and localhost addresses work directly from the server
name; that API has no separate connection network grant.
The TLS toggle currently starts TLS on the control connection only. Protected
data connections and explicit `AUTH TLS` negotiation are not implemented, so
the plugin does not yet provide a complete FTPS connection.
Listing and stat need a server that answers `MLSD` and `MLST`, the
machine-readable listing commands. A server without them reports the folder as
unsupported rather than guessing at the older, human-formatted listing or
changing its working directory to find out. FTP carries no version token,
so a conditional write is reported as unsupported rather than simulated.
## Passive mode and the port range
Transfers are passive: the plugin asks the server for a data port with `EPSV`
and connects out to it; `PASV` fallback is not implemented. The server picks a fresh port for every
transfer and announces it only as the transfer begins, so the range that has to
be reachable is wide.
The package declares socket ports 21 and 1024-65535, which Memona applies
automatically to each connection. The control port and passive data ports
must be within these ranges.
## Build
```sh
rustup target add wasm32-wasip2
cargo build --locked --release --target wasm32-wasip2
```
The component lands at
`target/wasm32-wasip2/release/memona_plugin_ftp.wasm`.
`sdk/` is a vendored copy of the Memona plugin SDK, the WIT contract plus its
generated Rust bindings, so this repository builds without the Memona repository
present.
## Package for the plugin store
Copy the component to `plugin.wasm` and ZIP it at the archive root together
with `manifest.json`, `README.md` and `LICENSE`:
```sh
cp target/wasm32-wasip2/release/memona_plugin_ftp.wasm plugin.wasm
zip memona-plugin-ftp.memona-plugin \
manifest.json plugin.wasm README.md LICENSE
```
The archive must have no wrapping directory. Memona validates the package and
its digest, and checks the component's imports against the supported WIT API,
before activation.
## License
MIT. See [LICENSE](LICENSE).