{"id":15034144,"url":"https://github.com/spatiumportae/portal","last_synced_at":"2025-12-14T21:24:42.335Z","repository":{"id":37799418,"uuid":"412444545","full_name":"SpatiumPortae/portal","owner":"SpatiumPortae","description":"Portal is a quick and easy command-line file transfer utility from any computer to another 🌌 ✨","archived":false,"fork":false,"pushed_at":"2024-08-20T14:40:18.000Z","size":16766,"stargazers_count":1633,"open_issues_count":27,"forks_count":46,"subscribers_count":10,"default_branch":"master","last_synced_at":"2025-05-15T07:05:00.840Z","etag":null,"topics":["data-transfer","e2e","file-sharing","filetransfer","go","golang","p2p","pake","peer-to-peer"],"latest_commit_sha":null,"homepage":"https://portal.spatiumportae.com","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SpatiumPortae.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE-OF-CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-10-01T11:44:20.000Z","updated_at":"2025-05-14T17:48:33.000Z","dependencies_parsed_at":"2024-01-05T21:46:04.402Z","dependency_job_id":"24be0ab6-01c8-4556-8a11-758dd6dc9710","html_url":"https://github.com/SpatiumPortae/portal","commit_stats":{"total_commits":460,"total_committers":7,"mean_commits":65.71428571428571,"dds":"0.48913043478260865","last_synced_commit":"e51984e186dc2ea1176f082c0690eeb5719d353d"},"previous_names":["zinokader/portal"],"tags_count":18,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SpatiumPortae%2Fportal","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SpatiumPortae%2Fportal/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SpatiumPortae%2Fportal/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SpatiumPortae%2Fportal/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SpatiumPortae","download_url":"https://codeload.github.com/SpatiumPortae/portal/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254292040,"owners_count":22046426,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["data-transfer","e2e","file-sharing","filetransfer","go","golang","p2p","pake","peer-to-peer"],"created_at":"2024-09-24T20:24:04.441Z","updated_at":"2025-12-14T21:24:41.689Z","avatar_url":"https://github.com/SpatiumPortae.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Portal\n\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"https://user-images.githubusercontent.com/6842167/172497072-e196c2d0-f0f9-4039-83f4-5d7e056e97cf.png\" width=\"375\" height=\"auto\"\u003e\n\u003c/p\u003e\n\u003cp align=\"center\" style=\"font-weight: bold;\"\u003e\na command-line file transfer utility for sending files from any computer to another\n\u003c/p\u003e\n  \n\u003cbr\u003e\n\n\u003cp align=\"center\"\u003e\n      \u003ca href=\"https://github.com/SpatiumPortae/portal/releases\"\u003e\u003cimg src=\"https://img.shields.io/github/v/release/spatiumportae/portal?color=%231777AB\u0026label=version\"\u003e\u003c/a\u003e\n      \u0026nbsp;\n      \u003ca href=\"https://github.com/SpatiumPortae/portal/actions\"\u003e\u003cimg src=\"https://img.shields.io/github/actions/workflow/status/SpatiumPortae/portal/ci.yml?branch=master\u0026color=%231777AB\"\u003e\u003c/a\u003e\n      \u0026nbsp;\n      \u003ca href=\"https://github.com/SpatiumPortae/portal/blob/master/LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/github/license/spatiumportae/portal?color=%231777AB\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n## Installation\n\nOn macOS/Linux, if you are using [Homebrew](https://brew.sh/)\n```bash\nbrew install portal\n```\n\nOn Windows, if you are using [Scoop](https://scoop.sh)\n\n```bash\nscoop install portal\n```\n\nOn Windows, if you are using [WinGet](https://github.com/microsoft/winget-cli)\n```bash\nwinget install SpatiumPortae.portal\n```\n\nOn Arch Linux (AUR)\n```bash\nyay -S portal-bin\n```\n\n\u003c!-- \n// Hidden until the snap build is granted the right filesystem permissions.\nOn the Snap Store\n```bash\nsudo snap install portal\n```\n--\u003e\n\nOn any platform, you can get the [latest release manually](https://github.com/SpatiumPortae/portal/releases/latest), or simply run\n\n```bash\ncurl -sL portal.spatiumportae.com | bash\n```\nor\n```bash\nwget -qO - portal.spatiumportae.com | bash\n```\n\n## How it works\n\n### Sending files and folders\n\nTo send files:\n\n```bash\nportal send \u003cfile1\u003e \u003cfile2\u003e \u003cfolder1\u003e \u003cfolder2\u003e ...\n```\n\nThe application will output a temporary password on the format `1-inertia-elliptical-celestial`.\n\u003cbr\u003e\u003cbr\u003e\nThe sender will communicate this password to the receiver over some secure channel.\n\n### Receiving files and folders\n\nTo receive those files:\n\n```bash\nportal receive 1-intertia-elliptical-celestial\n```\n\nThe two clients will establish a connection through a relay server. The file transfer will then commence with a direct or relayed connection, depending on what's possible.\n\n## What it looks like ✨\n\nThe sender **(top)** sends a folder and three files to the receiver **(bottom)**.\n\u003cbr\u003e\u003cbr\u003e\nIn this case, as you can see in the event log, the transfer is made using **direct transfer**. That means\nthat the files are sent **directly** from one client to the other, _no middlemen involved_. \n\u003cbr\u003e\u003cbr\u003e\nAs it happens, these computers are in the same local network, and `portal` recognizes this.\n\n![demo](./assets/demo.gif)\n\n## Features\n\n`portal` provides:\n\n- End-to-end encryption using [PAKE2](https://en.wikipedia.org/wiki/Password-authenticated_key_agreement)\n- Direct transfer of files if possible (e.g. sender and receiver are in the same local network)\n- Fallback to relay server if sender and receiver cannot connect directly\n- Parallel gzip compression of files for faster and more efficient transfers\n- Hosting your own relay (we'd appreciate it if you plan to send a lot of data!)\n- Configurability and shell completions\n- A shiny UI ⭐✨ to gaze your eyes upon while you wait for your files\n\n### Completions\n\n`portal` provides extensive \u003ckbd\u003eTAB\u003c/kbd\u003e completions for the following shells:\n\n- `bash`\n- `zsh`\n- `fish`\n- `powershell`\n\nTo see installation instructions for your shell and platform, run:\n\n```bash\nportal completion [bash|zsh|fish|powershell] --help\n```\n\n#### Tip!\n\nYou probably didn't _quite_ catch the password Bob was screaming across the room.\n\u003cbr\u003e\nYou can use \u003ckbd\u003eTAB\u003c/kbd\u003e completions to auto-complete passwords on the receiving end.\n\nPress \u003ckbd\u003eTAB\u003c/kbd\u003e when entering parts of your password...\n```bash\nportal receive 42-relative-parsec-s...\n```\n\n...and `portal` will suggest the possible words\n```bash\n$ portal receive 42-relative-parsec-s...\n\n42-relative-parsec-supernova  42-relative-parsec-scatter    42-relative-parsec-solar      42-relative-parsec-spin       42-relative-parsec-static     \n42-relative-parsec-sigma      42-relative-parsec-solid      42-relative-parsec-star       42-relative-parsec-storm      42-relative-parsec-system\n```\n\n__boom__. _supernova_.\n```bash\nportal receive 42-relative-parsec-supernova\n```\n\n### Flags\n\n#### `Receiver`\n\n- `-y/--yes`: overwrite existing files without `[Y/n]` prompts\n\n#### `Relay`\n\n- `-p/--port`: port to host the relay server on\n\n#### `Sender` and `Receiver`\n\n- `-r/--relay`: address of the relay server (`:8080`, `myrelay.io:1234`, ...)\n- `-s/--tui-style`: the style of the tui (`rich` | `raw`)\n\n#### `Sender`, `Receiver` and `Relay`\n\n- `-h/--help`: output help messages for any command\n- `-v/--verbose`: log debug info to file\n\n### Configuration\n\n`portal` places its configuration file in `$HOME/.config/portal/config.yml`.\n\u003cbr\u003e\u003cbr\u003e\nAs evident by the file extension, the config is a simple [YAML](https://yaml.org/) file with descriptive field names.\n\n#### Default configuration\n```yaml\n# The URL of the relay server.\nrelay: portal.spatiumportae.com\n# Log debug output to file.\nverbose: false\n# Prompt for overwriting duplicates when receiving files.\nprompt_overwrite_files: true\n# The port used when serving the relay using \"portal serve\".\nrelay_serve_port: 8080\n# The style of the TUI.\ntui_style: rich\n```\n\n### Hosting your own relay\n\nThe `portal` binary comes with a built-in relay server.\n\u003cbr\u003e\u003cbr\u003e\nSpinning up your own relay is as easy as...\n```bash\nportal serve --port 1337\n```\n\nThe server log output is `JSON`. Super-recommended to run it through [jq](https://github.com/stedolan/jq)!\n```bash\nportal serve --port 1337 2\u003e\u00261 | jq .\n```\n...\n```json\n{\n  \"level\": \"info\",\n  \"ts\": \"2023-02-28T02:57:45.310134+01:00\",\n  \"caller\": \"rendezvous/server.go:77\",\n  \"msg\": \"serving rendezvous server\",\n  \"version\": \"v1.2.1\",\n  \"address\": \":1337\"\n}\n```\n\n### More details about the connection process\n\n\u003cdetails\u003e\n\u003csummary\u003eTechnical details\u003c/summary\u003e\n  \n### Technical details\n\nThe connection between the sender and the server is negotiated using a intermediary server (relay).\n\u003cbr\u003e\u003cbr\u003e\nThe relay server is used to negotiate a secure encrypted channel while never seeing the contents of files nor the temporary password.\n\nThe communication works as follows:\n\n- `sender` connects to `relay`\n- `relay` allocates a numerical ID to the sender and sends it to the `sender`\n- `sender` generates and outputs the password (starting with the ID) to the terminal, hashes the password and sends it to the `relay`\n- `receiver` hashes the password (which has been communicated over some secure channel) and sends it to the `relay`\n- When both the `sender` and the `receiver` have sent the hashed password to the `relay`, the cryptographic exchange starts\n- During the cryptographic exchange, the `relay`, well, relays messages from the `sender` to the `receiver` and vice-versa\n- Once the cryptographic exchange is done, every message sent by the `sender` and `receiver` is encrypted, and the `relay` cannot see their contents\n- The file transfer is about to begin, and can commence in two ways: \n  1. The `sender` and `receiver` are in the same local network or can be reached directly by IP in some other way\n     - In this case, the `sender` and `receiver` will happily send the files to each other directly. The `relay` will close down for this connection.\n  2. The `sender` and `receiver` are not on the same local network, or cannot reach each other directly. The transfer will go through the `relay`, which will continue to relay encrypted messages until the file transfer is completed\n\n\u003c/details\u003e\n\n## Building from source\n\nThe [`Makefile`](Makefile) has everything you need. \n\u003cbr\u003e\u003cbr\u003e\nTo build a binary containing all commands, run:\n```bash\nPORTAL_VERSION=v1.x.x make build\n```\n\nIt's important to include `PORTAL_VERSION`, which is a [semantic version](https://semver.org/) string. This is needed\nin order to validate senders and receivers against the relay, so transfers are disallowed\nwhen on different major versions, for instance.\n\n## Maintainers\n\n- [Arvid Gotthard](https://github.com/mellonnen)\n- [Zino Kader](https://github.com/ZinoKader)\n\n## Acknowledgements\n\na big thank you to [magic-wormhole](https://github.com/magic-wormhole/magic-wormhole) for greatly inspiring the concept of Portal.\n\n[nhooyr/websocket](https://github.com/nhooyr/websocket), [shollz/pake](https://github.com/schollz/pake), [charmbracelet/bubbles](https://github.com/charmbracelet/bubbles), [charmbracelet/bubbletea](https://github.com/charmbracelet/bubbletea), [charmbracelet/lipgloss](https://github.com/charmbracelet/lipgloss), [muesli/reflow](https://github.com/muesli/reflow), [klauspost/pgzip](https://github.com/klauspost/pgzip) and many, many more.\n\n### DigitalOcean \u003c3\n\nA **special thanks** to our sponsors [DigitalOcean](https://m.do.co/c/73a491fda077).\n\u003cbr\u003e\u003cbr\u003e\nThe public relay available for everyone to use is...\n\n[![DigitalOcean Referral Badge](https://web-platforms.sfo2.digitaloceanspaces.com/WWW/Badge%203.svg)](https://www.digitalocean.com/?refcode=73a491fda077\u0026utm_campaign=Referral_Invite\u0026utm_medium=Referral_Program\u0026utm_source=badge)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspatiumportae%2Fportal","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fspatiumportae%2Fportal","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspatiumportae%2Fportal/lists"}