# scottdsnr/ssh-file-transfer architecture

> Architecture diagram of the GitHub repository scottdsnr/ssh-file-transfer, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-09-25). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/scottdsnr/ssh-file-transfer
- Repository: https://github.com/scottdsnr/ssh-file-transfer

## Overview

fsi is a command-line file-transfer tool with two recipient paths: an encrypted CLI-to-CLI exchange and an explicitly unencrypted browser download page. The main workflow generates or accepts a spoken code, pairs peers through a relay (possibly hosted by the sender), authenticates and encrypts the CLI transfer, then verifies received files. The graph also shows direct hosting, optional Cloudflare tunneling, and the browser path. Some receiver and CLI wiring was not sampled; those links use documented package behavior and avoid uncertain internal sequencing.

Main entry points: [`internal/transfer`](https://github.com/scottdsnr/ssh-file-transfer/tree/master/internal/transfer) (Transfer workflow), [`cmd/fsi/main.go`](https://github.com/scottdsnr/ssh-file-transfer/blob/master/cmd/fsi/main.go) (fsi commands), [`cmd/fsi/host.go`](https://github.com/scottdsnr/ssh-file-transfer/blob/master/cmd/fsi/host.go) (Embedded hosting), [`internal/relay/relay.go`](https://github.com/scottdsnr/ssh-file-transfer/blob/master/internal/relay/relay.go) (Peer rendezvous)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_cli["CLI and hosting"]
  node_fsi_cli["fsi commands<br/>[main.go]"]
  node_hosting["Embedded hosting<br/>[host.go]"]
end

subgraph group_transfer["Peer transfer"]
  node_transfer_api["Transfer workflow"]
  node_code_words["Code and room<br/>[words.go]"]
  node_pake["SPAKE2 handshake<br/>[pake.go]"]
  node_encryption["Message encryption<br/>[crypt.go]"]
end

subgraph group_transport["Rendezvous transport"]
  node_framing["Message framing<br/>[comm.go]"]
  node_websocket["WebSocket transport"]
  node_relay["Peer rendezvous<br/>[relay.go]"]
end

subgraph group_browser["Browser downloads"]
  node_web_handler["Download page<br/>[web.go]"]
end

node_sender(("Sender"))
node_recipient(("CLI recipient"))
node_browser_user(("Browser recipient"))
node_cloudflared["cloudflared"]
node_file_sources["Source files"]
node_received_files["Received files"]
node_internet_tunnel["Cloudflare tunnel"]

node_sender -->|"runs send"| node_fsi_cli
node_recipient -->|"runs receive"| node_fsi_cli
node_fsi_cli -->|"generates code"| node_code_words
node_fsi_cli -->|"starts hosting"| node_hosting
node_fsi_cli -->|"starts transfer"| node_transfer_api
node_hosting -->|"starts relay"| node_relay
node_hosting -.->|"starts tunnel"| node_cloudflared
node_cloudflared -.->|"forwards HTTP"| node_relay
node_transfer_api -->|"derives room"| node_code_words
node_transfer_api -->|"dials and exchanges"| node_framing
node_transfer_api -->|"authenticates peers"| node_pake
node_transfer_api -->|"seals frames"| node_encryption
node_transfer_api -->|"reads and hashes"| node_file_sources
node_transfer_api -->|"writes verified files"| node_received_files
node_framing -->|"uses for URL transport"| node_websocket
node_relay -->|"pairs and pipes"| node_framing
node_relay -->|"accepts upgrades"| node_websocket
node_sender -->|"shares download link"| node_browser_user
node_fsi_cli -->|"serves browser path"| node_web_handler
node_web_handler -->|"reads and serves"| node_file_sources
node_browser_user -->|"requests downloads"| node_web_handler
node_hosting -->|"mounts handler"| node_web_handler

click node_fsi_cli "https://github.com/scottdsnr/ssh-file-transfer/blob/master/cmd/fsi/main.go"
click node_hosting "https://github.com/scottdsnr/ssh-file-transfer/blob/master/cmd/fsi/host.go"
click node_transfer_api "https://github.com/scottdsnr/ssh-file-transfer/tree/master/internal/transfer"
click node_code_words "https://github.com/scottdsnr/ssh-file-transfer/blob/master/internal/words/words.go"
click node_pake "https://github.com/scottdsnr/ssh-file-transfer/blob/master/internal/pake/pake.go"
click node_encryption "https://github.com/scottdsnr/ssh-file-transfer/blob/master/internal/crypt/crypt.go"
click node_framing "https://github.com/scottdsnr/ssh-file-transfer/blob/master/internal/comm/comm.go"
click node_websocket "https://github.com/scottdsnr/ssh-file-transfer/tree/master/internal/ws"
click node_relay "https://github.com/scottdsnr/ssh-file-transfer/blob/master/internal/relay/relay.go"
click node_web_handler "https://github.com/scottdsnr/ssh-file-transfer/blob/master/internal/web/web.go"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_fsi_cli,node_hosting,node_browser_user toneBlue
class node_transfer_api,node_code_words,node_pake,node_encryption toneAmber
class node_framing,node_websocket,node_relay toneMint
class node_web_handler toneRose
class node_sender,node_recipient,node_cloudflared,node_file_sources,node_received_files,node_internet_tunnel toneIndigo
```

## Components

### CLI and hosting

- [fsi commands](https://github.com/scottdsnr/ssh-file-transfer/blob/master/cmd/fsi/main.go): `cmd/fsi/main.go`
- [Embedded hosting](https://github.com/scottdsnr/ssh-file-transfer/blob/master/cmd/fsi/host.go): `cmd/fsi/host.go`

### Peer transfer

- [Transfer workflow](https://github.com/scottdsnr/ssh-file-transfer/tree/master/internal/transfer): `internal/transfer`
- [Code and room](https://github.com/scottdsnr/ssh-file-transfer/blob/master/internal/words/words.go): `internal/words/words.go`
- [SPAKE2 handshake](https://github.com/scottdsnr/ssh-file-transfer/blob/master/internal/pake/pake.go): `internal/pake/pake.go`
- [Message encryption](https://github.com/scottdsnr/ssh-file-transfer/blob/master/internal/crypt/crypt.go): `internal/crypt/crypt.go`

### Rendezvous transport

- [Message framing](https://github.com/scottdsnr/ssh-file-transfer/blob/master/internal/comm/comm.go): `internal/comm/comm.go`
- [WebSocket transport](https://github.com/scottdsnr/ssh-file-transfer/tree/master/internal/ws): `internal/ws`
- [Peer rendezvous](https://github.com/scottdsnr/ssh-file-transfer/blob/master/internal/relay/relay.go): `internal/relay/relay.go`

### Browser downloads

- [Download page](https://github.com/scottdsnr/ssh-file-transfer/blob/master/internal/web/web.go): `internal/web/web.go`

### Other components

- **Sender**
- **CLI recipient**
- **Browser recipient**
- **cloudflared**
- **Source files**
- **Received files**
- **Cloudflare tunnel**

## Connections

- Sender → fsi commands: runs send
- CLI recipient → fsi commands: runs receive
- fsi commands → Code and room: generates code
- fsi commands → Embedded hosting: starts hosting
- fsi commands → Transfer workflow: starts transfer
- Embedded hosting → Peer rendezvous: starts relay
- Embedded hosting → cloudflared: starts tunnel
- cloudflared → Peer rendezvous: forwards HTTP
- Transfer workflow → Code and room: derives room
- Transfer workflow → Message framing: dials and exchanges
- Transfer workflow → SPAKE2 handshake: authenticates peers
- Transfer workflow → Message encryption: seals frames
- Transfer workflow → Source files: reads and hashes
- Transfer workflow → Received files: writes verified files
- Message framing → WebSocket transport: uses for URL transport
- Peer rendezvous → Message framing: pairs and pipes
- Peer rendezvous → WebSocket transport: accepts upgrades
- Sender → Browser recipient: shares download link
- fsi commands → Download page: serves browser path
- Download page → Source files: reads and serves
- Browser recipient → Download page: requests downloads
- Embedded hosting → Download page: mounts handler
