# tsafe-nativehost
Browser native messaging host for [tsafe](https://crates.io/crates/tsafe-cli).
Implements the Chrome / Edge / Firefox native messaging protocol so the tsafe
browser extension can read secrets from the local vault without exposing them
to web pages.
## Install
Included in the default CLI install:
```
cargo install tsafe-cli
```
Or standalone:
```
cargo install tsafe-nativehost
```
## Registration
After install, register the host with your browser:
```
tsafe browser-native-host register [EXTENSION_ID]
```
This writes the native messaging manifest to the correct location for each
browser:
- **Chrome / Edge (Linux/macOS)** — `~/.config/google-chrome/NativeMessagingHosts/`
- **Firefox (Linux/macOS)** — `~/.mozilla/native-messaging-hosts/`
- **Chrome / Edge (Windows)** — registry key under `HKCU\Software\Google\Chrome\NativeMessagingHosts\`
- **Firefox (Windows)** — `%APPDATA%\Mozilla\NativeMessagingHosts\`
## Protocol
The host speaks the Chrome native messaging wire format: a 4-byte
little-endian length prefix followed by a UTF-8 JSON body, over stdin/stdout.
On Windows, both handles are switched to binary mode at startup to prevent the
C runtime from mangling newline bytes.
Supported JSON commands:
| `unlock` | Open a vault session; returns a `session_token` |
| `lock` | Drop the active session immediately |
| `list_logins` | List secret keys visible to the requesting hostname |
| `get_login` | Fetch a single secret value |
| `save_login` | Write a new or updated secret into the vault |
All commands except `unlock` require a `session_token` obtained from a prior
`unlock` response. Sessions expire after 5 minutes of inactivity; each
successful request resets the idle timer.
## Security model
- **Domain isolation** — each `list_logins`, `get_login`, and `save_login`
request must include a `hostname` field. The hostname is validated against a
browser-profile mapping (`browser-profiles.json`) so the extension can only
read secrets that have been explicitly mapped to the current browser profile.
- **Phishing guard** — if the requesting hostname is not mapped but is one edit
distance away from a registered domain (e.g. `paypa1.com` vs `paypal.com`),
the response is `{"status":"phishing_warning","registered":"paypal.com"}`
rather than a generic error.
- **Hostname fill guard** — structurally invalid hostnames (too many labels,
excessive label length) are rejected before profile lookup.
- **Concurrent requests** — the persistent native messaging port allows the
popup and content script to interleave requests. Each request may carry an
`id` field; the host echoes it back on the response so the extension can
route concurrent replies to the correct awaiter.
- **Audit log** — every `browser-list` and `browser-get` operation is appended
to the profile's audit log.
## License
Same as the tsafe workspace — see the repository root.