Low tech collaborative coding
Tags: shell, ssh, tmux, bash
Published: 2020-12-13 09:21:48

Lately I have been using some online/web collaborative coding tools for interviews. Which makes me wonder about how to achieve some sort of screen sharing in the terminal.

The way described here is relatively simple, and isn't particularly obscure or clever.
We will invite the guest to login with ssh, and immediately have them attached to an existing tmux session. Then we effectively have a screen share session in the terminal. Although individual cursors for each user aren't available, we trade in for simplicity. As this requires virtually no setup on the guest and just common tools on the host.

First, we will create a new user, since we don't want/need them to run any command other than attach to our session, they don't need a proper shell at all, their "shell" can just be a script that runs a single command.
```sh
useradd unprivileged --shell=/tmp/connect_to_tmux --expiredate="$(date --date='tomorrow' '+%F')" --home-dir=/tmp
passwd unprivileged
```

Then the "shell" is just a script to attach to the tmux session. We can use the `-r` flag for read-only access, remove it to allow editing. Normally we won't be able to enforce read-only access when sharing tmux session, but since we have control over what command gets run, we could lock the guest in a read-only client.
```sh
cat <<EOF >/tmp/connect_to_tmux
#!/bin/sh
tmux -S /tmp/tmux_session_shared_with_unprivileged attach -r
EOF
chmod +x /tmp/connect_to_tmux
```

Depending on the distribution, you might need to add the new shell to `/etc/shells` for it to be recognized and used as a shell.
```sh
echo '/tmp/connect_to_tmux' >> /etc/shells
```

To prevent unwanted ssh access to other accounts, we can edit `/etc/ssh/sshd_config` to allow only expected users to login. For example, adding/updating `AllowUsers unprivileged` will prevent ssh login any user other than our new user "unprivileged". Don't forget to load/reload the config by starting/restarting the ssh server.

We can establish a TCP tunnel with ngrok to allow the guest accessing our computer with ssh. 
```sh
ngrok tcp 22 # you can specify --region flag according to your location
```

We can start the tmux session with our own account & shell, and we will need to change the access rights of the socket file.
```sh
tmux -S /tmp/tmux_session_shared_with_unprivileged
chmod 766 /tmp/tmux_session_shared_with_unprivileged
```

Or, if we don't want to use our own account, for example, to prevent accidentally showing something in the bash history, we can start the session with the unprivileged user instead. However, we will need to specify a normal shell instead of the `connect_to_tmux` script when starting tmux.
```sh
sudo SHELL=/usr/bin/bash -u unprivileged tmux -S /tmp/tmux_session_shared_with_unprivileged
```

All that is left is to share the login info with your guest.
Oh did I mention there will be no fancy IDE? Time to learn VIM ;)

And after everything, even though the account will expire in a day because we added the `--expiredate` flag when creating the user, we may want to clean it up.
```sh
userdel -r unprivileged
```

----

Reference/Additional Reading
----
Using "custom shell" with ssh
https://askubuntu.com/a/1174843

In addition to enforcing command, you can also disable port forwarding and other stuff ssh comes with.
https://unix.stackexchange.com/a/581814

You can replace `tmux` with `screen`, however there might be security concerns when sharing sessions across users.
https://unix.stackexchange.com/a/578167