# 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

Standalone Cargo install:

```
cargo install tsafe-nativehost
```

Some release channels bundle `tsafe-nativehost` for browser/native-host
workflows. A plain `cargo install tsafe-cli` installs the compiled CLI only; it
does not install this companion binary unless that channel says so explicitly.
The meta-crate path builds the bundled suite:

```
cargo install tsafe
```

## 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:

| Command        | Description                                              |
|----------------|----------------------------------------------------------|
| `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.
