Skip to main content

View and control remote terminals from your browser with end-to-end encryption

Project description

View and control remote terminals from your browser with end-to-end encryption

Try It: https://chadsmith.dev/termpair

PyPI version PyPI version

What is TermPair?

TermPair lets developers securely share and control terminals in real time.

Features

✔️ Share unix terminals

✔️ Can type from Terminal or Browser

✔️ Multiple browsers can connect simultaneously

✔️ Read+Write or Read only mode

✔️ Server cannot read terminal data even if it wanted to, since it is encrypted with AES 128 bit encryption

✔️ Secure web environment required (https)

✔️ Optional static-site hosting -- build the web app yourself to ensure the integrity of the web app

Usage

First start the TermPair server with termpair serve, or use the one already running at https://chadsmith.dev/termpair.

The server is used to route encrypted data between terminals and connected browsers — it doesn't actually start sharing any terminals just by running it.

> termpair serve --port 8000

Now that you have the server running, you can share your terminal by running termpair share.

This connects your terminal to the server, and allows browsers to access the terminal through the server.

> termpair share
--------------------------------------------------------------------------------
Connection established with end-to-end encryption 🔒

Shareable link: http://localhost:8000/?terminal_id=d58ff4eed5aa9425e944abe63214382e#g8hSgHnDaBtiWKTeH4I0Ow==

Terminal ID: d58ff4eed5aa9425e944abe63214382e
Secret encryption key: g8hSgHnDaBtiWKTeH4I0Ow==
TermPair Server URL: http://localhost:8000/

Type 'exit' or close terminal to stop sharing.
--------------------------------------------------------------------------------

The URL printed contains a unique terminal ID and encryption key. You can share the URL with whoever you like. Anyone who has it can access your terminal while the termpair share process is running, so be sure you trust the person you are sharing the link with.

The server multicasts terminal output to all browsers that connect to the session.

System Requirements

Python: 3.6+

Operating Systems: Linux, macOS

Installation

You can install using pipx, which installs Python applications in isolated environments (recommended):

> pipx install termpair

or install with pip

> pip install termpair

Note: Make sure the TermPair server you are broadcasting to is running the same major version as the broadcasting terminal (see termpair --version).

Run With Latest Version

You can also use pipx to directly run the latest version without installing:

Serve:

> pipx run termpair serve

Then share:

> pipx run termpair share --open-browser

Note: Make sure the TermPair server you are broadcasting to is running the same major version as the broadcasting terminal (see pipx run termpair --version). You can specify the version with pipx run --spec termpair==$VERSION termpair ....

Security

TermPair uses end-to-end encryption for all terminal input and output, meaning the server never has access to the raw input or output of the terminal, nor does it have access to encryption keys (other than the https connection).

The browser must be running in a secure context. This typically means running with secure http traffic (https) or on localhost.

Static Hosting

As an optional additional security measure, TermPair supports statically serving the JavaScript web app.

In this arrangement, you can build the TermPair web app yourself and host on your computer, or statically host on something like GitHub pages or Vercel. That way you can guarantee the server is not providing a malicious JavaScript web app.

When you open it you then specify the Terminal ID, encryption key, and TermPair server host to connect to.

You can try it out or just see what it looks like with a GitHub page from this project, https://cs01.github.io/termpair/connect/.

If you'd like to build web app yourself, see CONTRIBUTING.md.

Then you can self-serve with

$ cd termpair/termpair/frontend_build
$ python3 -m http.server 7999 --bind 127.0.0.1
# Serves at http://127.0.01:7999

or you can deploy to GitHub pages, Vercel, etc.

How it Works

TermPair consists of three pieces:

  1. server
  2. terminal client
  3. JavaScript web app running in browser client(s)

Server

First, the termpair server is started (termpair serve). The server acts as a router that blindly forwards encrypted data between TermPair terminal clients and connected browsers. The server listens for termpair websocket connections from unix terminal clients, and maintains a mapping to any connected browsers.

Terminal Client

When a user wants to share their terminal, they run termpair share to start the client. The TermPair client registers this session with the server, then forks and starts a psuedo-terminal (pty) with the desired process, usually a shell like bash or zsh. TermPair reads data from the pty's file descriptor as it becomes available, then writes it to ther real terminal's stdout, where it is printed like normal. However, it also encrypts this output and sends it to the server via a websocket.

Encryption

The TermPair client creates three 128 bit AES encryption keys when it starts:

  • The first is used to encrypt the terminal's output to the browsers so the server cannot read it.
  • The second is used by the browser when sending input from the browser to the terminal.
  • The third is a "bootstrap" key used by the browser to decrypt the initial connection response from the broadcasting terminal, which contains the above two keys encrypted with this third key. The browser obtains this bootstrap key via a part of the url that the server does not have access to, or via manual user input.

Web App

The TermPair client provides the user with a unique URL for the duration of the shaing session. That URL points to the TermPair web application that sets up a websocket connection to receive and send the encrypted terminal data. When data is received, it is decrypted and written to a browser-based terminal.

When a users types in the browser's terminal, it is encrypted in the browser with key #2, sent to the server, forwarded from the server to the terminal, then decrypted in the terminal by TermPair. Finally, the TermPair client writes it to the pty's file descriptor, as if it were being typed directly to the terminal.

AES keys #1 and #2 get rotated after either key has sent 2^20 (1048576) messages. The AES initialization vector (IV) values increment monotonically to ensure they are never reused.

Serving with NGINX

Running behind an nginx proxy can be done with the following configuration.

The TermPair server must be started with termpair serve, and the port being run on must be specified in the upstream configuration.

upstream termpair_app {
  # Make sure the port matches the port you are running on
  server 127.0.0.1:8000;
}

server {
    server_name myserver.com;

    # I recommend Certbot if you don't have SSL set up
    listen 443 ssl;
    ssl_certificate fullchain.pem;
    ssl_certificate_key privkey.pem;

    location /termpair/ {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;

        proxy_pass http://termpair_app/;

        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

Running as a systemd service

If you use systemd to manage services, here is an exampe configuration you can use.

This configuration assumes you've installed TermPair to /home/$USER/.local/bin/termpair and saved the file to /etc/systemd/system/termpair.service.

# /etc/systemd/system/termpair.service

# https://www.freedesktop.org/software/systemd/man/systemd.service.html
[Unit]
Description=
After=network.target

[Service]
User=$USER
Group=www-data
WorkingDirectory=/var/www/termpair/
PermissionsStartOnly=true
ExecStart=/home/$USER/.local/bin/termpair -s serve
ExecStop=
Restart=on-failure
RestartSec=1s

[Install]
WantedBy=multi-user.target

After saving, you can use systemctl to start your systemd service:

sudo systemctl daemon-reload
sudo systemctl enable termpair.service
sudo systemctl restart termpair

CLI API

> termpair --help
usage: termpair [-h] [--version] {share,serve} ...

View and control remote terminals from your browser

positional arguments:
  {share,serve}

optional arguments:
  -h, --help     show this help message and exit
  --version

To start the TermPair server:

> termpair serve --help
usage: termpair serve [-h] [--port PORT] [--host HOST] [--certfile CERTFILE]
                      [--keyfile KEYFILE]

Run termpair server to route messages between unix terminals and browsers. Run
this before connecting any clients. It is recommended to encrypt communication
by using SSL/TLS. To generate an SSL certificate and private key, run `openssl
req -newkey rsa:2048 -nodes -keyout host.key -x509 -days 365 -out host.crt`.
To skip questions and use defaults, add the `-batch` flag. You can ignore
warnings about self-signed certificates since you know you just made it. Then
use them, pass the '--certfile' and '--keyfile' arguments.

optional arguments:
  -h, --help            show this help message and exit
  --port PORT, -p PORT  Port to run the server on (default: 8000)
  --host HOST           Host to run the server on (0.0.0.0 exposes publicly)
                        (default: localhost)
  --certfile CERTFILE, -c CERTFILE
                        Path to SSL certificate file (commonly .crt extension)
                        (default: None)
  --keyfile KEYFILE, -k KEYFILE
                        Path to SSL private key .key file (commonly .key
                        extension) (default: None)

To share a terminal using the TermPair client:

> termpair share --help
usage: termpair share [-h] [--cmd CMD] [--port PORT] [--host HOST] [--read-only]
                      [--open-browser]

Share your terminal session with one or more browsers. A termpair server must be
running before using this command.

optional arguments:
  -h, --help            show this help message and exit
  --cmd CMD             The command to run in this TermPair session. Defaults to
                        the SHELL environment variable (default: /bin/bash)
  --port PORT, -p PORT  port server is running on (default: 8000)
  --host HOST           host server is running on (default: http://localhost)
  --read-only, -r       Do not allow browsers to write to the terminal (default:
                        False)
  --open-browser, -b    Open a browser tab to the terminal after you start
                        sharing (default: False)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

termpair-0.3.0.0.tar.gz (602.5 kB view details)

Uploaded Source

Built Distribution

termpair-0.3.0.0-py3-none-any.whl (606.5 kB view details)

Uploaded Python 3

File details

Details for the file termpair-0.3.0.0.tar.gz.

File metadata

  • Download URL: termpair-0.3.0.0.tar.gz
  • Upload date:
  • Size: 602.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.2 importlib_metadata/4.6.3 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.0 CPython/3.8.9

File hashes

Hashes for termpair-0.3.0.0.tar.gz
Algorithm Hash digest
SHA256 a8be46e14ef298c286edd241abc72f87cc2abb64ea794ed908676afdbd0c9caf
MD5 296b632c9ec113b18ea84714bfcdbca4
BLAKE2b-256 3936c8811a03565158d68d18518cd874beaced11a9593152b3b0643cdbfaf07e

See more details on using hashes here.

File details

Details for the file termpair-0.3.0.0-py3-none-any.whl.

File metadata

  • Download URL: termpair-0.3.0.0-py3-none-any.whl
  • Upload date:
  • Size: 606.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.2 importlib_metadata/4.6.3 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.0 CPython/3.8.9

File hashes

Hashes for termpair-0.3.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 aac2323344de1bb44dd51a4e8ee2f830563bd2476c45e3faa6c3295dd5f531a6
MD5 4e0b429e15b57ee88ff4e102694617e4
BLAKE2b-256 f3c44c003d114249ca52fb3d864572be5ed7554a36cca8baa2d5e723cb8190f1

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page