diff --git a/.gitignore b/.gitignore index 3da75aa..89f06dd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +system/clearpilot/dev/reverse_ssh +system/clearpilot/dev/id_rsa +system/clearpilot/dev/id_rsa.pub venv/ .venv/ .ci_cache diff --git a/system/clearpilot/dev/GithubSshKeys b/system/clearpilot/dev/GithubSshKeys new file mode 100644 index 0000000..4d49e5f --- /dev/null +++ b/system/clearpilot/dev/GithubSshKeys @@ -0,0 +1,3 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQtHTzkeRlOXDWyK/IvO2RgjSdoq6V81u3YtcyIxBZVX2zCj1xzE9zWcUcVxloe63rB/DBasChODIRBtp1vGnWb/EkLWAuOqS2V5rzhlcSfM103++TI81e04A7HDspWSNUXRh5OD/mUvwtYIH7S4QAkBiCro5lAgSToXNAOR4b4cXgNQecf+RhPc0Nm3K8Is1wEeQajmlC1E22YWBDDV+uoB3Uagl90e58Psbp8PunCdbeY9EfqQsymyloiTeqzKwHnmHnMXSlZluh7A+ifoKgohDsarT1FixAgxT0LSIxxINORhE4P6em/7y3xpgubPhNpbuQSzDlb3op3fwMoFcAEEYKWg+d9OGOrdiWa13aV0g7UNdW/XmmF/BAaBdSOZeomVNnxmftmmJWfu3jtFdwTDRQpZn7nDYC+aZ1R3Q0Xd4lLuqkA/9smUXLZuiBDJXwM5nDyWQR9tESIwlTLcdKAUpj0gQqpcozVehksNksTekZBAg/mYb6DKyYCTY0ti0= +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCm/Vq50kqf94allqGq9luBGjDh2Do/rOCA719CRlDOErCvdY+ZaYNumQZ5AbFfU5KcPZwirJLBvhEoH/G0lEAg9TUaUgH/VvqBBztlpcmA1eplZHzEFLnTDn0oO4Tk46bXwjL0anOZfNaUGhbaO4Th7m+9+o16WUduEabPiyVbnqD6P44CANsvBJNKlyUDBzsdkE9z5gULp06i1+JqqXiGV81HoFWZe5YCFv4j4QUPvfmFhcBHViVrOFs87hS4Eu0gWNxQmQBhh6R1ZbjaBlGdE5GyDZQZwlofjfuO06e0HvCDuIAELSYqlGFCmUhlM/LZ6YkF79/HFrg5sS3gsuY5 +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHbrOZrByUb2Ci21DdJkhWv/4Bz4oghL9joraQYFq4Om diff --git a/system/clearpilot/dev/encrypt.sh b/system/clearpilot/dev/encrypt.sh new file mode 100644 index 0000000..0e31d2d --- /dev/null +++ b/system/clearpilot/dev/encrypt.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +# Encrypt SSH keys if source files exist using the custom encrypt tool +if [ -f /data/openpilot/system/clearpilot/dev/id_rsa.pub ]; then + bash /data/openpilot/system/clearpilot/tools/encrypt /data/openpilot/system/clearpilot/dev/id_rsa.pub /data/openpilot/system/clearpilot/dev/id_rsa.pub.cpt +fi + +if [ -f /data/openpilot/system/clearpilot/dev/id_rsa ]; then + bash /data/openpilot/system/clearpilot/tools/encrypt /data/openpilot/system/clearpilot/dev/id_rsa /data/openpilot/system/clearpilot/dev/id_rsa.cpt +fi + +if [ -f /data/openpilot/system/clearpilot/dev/reverse_ssh ]; then + bash /data/openpilot/system/clearpilot/tools/encrypt /data/openpilot/system/clearpilot/dev/reverse_ssh /data/openpilot/system/clearpilot/dev/reverse_ssh.cpt +fi diff --git a/system/clearpilot/dev/id_rsa.cpt b/system/clearpilot/dev/id_rsa.cpt new file mode 100644 index 0000000..290617a Binary files /dev/null and b/system/clearpilot/dev/id_rsa.cpt differ diff --git a/system/clearpilot/dev/id_rsa.pub.cpt b/system/clearpilot/dev/id_rsa.pub.cpt new file mode 100644 index 0000000..c777f9a Binary files /dev/null and b/system/clearpilot/dev/id_rsa.pub.cpt differ diff --git a/system/clearpilot/dev/provision.sh b/system/clearpilot/dev/provision.sh index ce91fbb..be91775 100644 --- a/system/clearpilot/dev/provision.sh +++ b/system/clearpilot/dev/provision.sh @@ -1,4 +1,49 @@ +!/bin/bash + +# Provision script for BrianBot +# These actions only occur on BrianBot's comma device. + +# 1. Check the string in /data/params/d/DongleId +dongle_id=$(cat /data/params/d/DongleId) +if [[ ! $dongle_id == 90bb71a* ]]; then + echo "Invalid dongle ID." + exit 1 +fi + +echo "BrianBot dongle ID detected." + +# 2. Check if ccrypt is installed, install if not +if ! command -v ccrypt >/dev/null 2>&1; then + echo "Installing ccrypt..." + sudo apt-get update + sudo apt-get install -y ccrypt +fi + +# 3. Decrypt SSH keys if they have not been decrypted yet +if [ ! -f /data/openpilot/system/clearpilot/dev/id_rsa.pub ]; then + echo "Decrypting SSH keys..." + /data/openpilot/system/clearpilot/tools/decrypt /data/openpilot/system/clearpilot/dev/id_rsa.pub.cpt /data/openpilot/system/clearpilot/dev/id_rsa.pub + /data/openpilot/system/clearpilot/tools/decrypt /data/openpilot/system/clearpilot/dev/id_rsa.cpt /data/openpilot/system/clearpilot/dev/id_rsa + /data/openpilot/system/clearpilot/tools/decrypt /data/openpilot/system/clearpilot/dev/reverse_ssh.cpt /data/openpilot/system/clearpilot/dev/reverse_ssh +fi + +# 4. Ensure .ssh directory and keys exist +ssh_dir="/data/ssh/.ssh" +if [[ ! -f "$ssh_dir/id_rsa" || ! -f "$ssh_dir/id_rsa.pub" ]]; then + echo "Setting up SSH directory and keys..." + mkdir -p "$ssh_dir" + cp /data/openpilot/system/clearpilot/dev/id_rsa /data/openpilot/system/clearpilot/dev/id_rsa.pub "$ssh_dir" + chmod 700 "$ssh_dir" + chmod 600 "$ssh_dir/id_rsa" "$ssh_dir/id_rsa.pub" + echo hansonxyz > /data/params/d/GithubUsername + cat /data/openpilot/system/clearpilot/dev/GithubSshKeys > /data/params/d/GithubSshKeys + echo 1 > /data/params/d/SshEnabled + sudo systemctl restart ssh + cd /data/openpilot + git remote remove origin + git remote add origin git@privategit.hanson.xyz:brianhansonxyz/clearpilot.git +fi + +echo "Script execution complete." +exit 0 -cd /data/openpilot -git remote remove origin -git remote add origin git@privategit.hanson.xyz:brianhansonxyz/clearpilot.git diff --git a/system/clearpilot/tools/decrypt b/system/clearpilot/tools/decrypt new file mode 100644 index 0000000..a736b82 --- /dev/null +++ b/system/clearpilot/tools/decrypt @@ -0,0 +1,17 @@ +#!/bin/bash + +# Check for the correct number of arguments +if [ "$#" -ne 2 ]; then + echo "Usage: $0 source destination" + exit 1 +fi + +# Set variables for source and destination +src="$1" +dest="$2" + +# Read DongleId for decryption key +dongle_id=/data/params/d/DongleId + +# Decrypt the file +cat "$src" | ccrypt -d -k "$dongle_id" > "$dest" diff --git a/system/clearpilot/tools/encrypt b/system/clearpilot/tools/encrypt new file mode 100644 index 0000000..9496892 --- /dev/null +++ b/system/clearpilot/tools/encrypt @@ -0,0 +1,17 @@ +#!/bin/bash + +# Check for the correct number of arguments +if [ "$#" -ne 2 ]; then + echo "Usage: $0 source destination" + exit 1 +fi + +# Set variables for source and destination +src="$1" +dest="$2" + +# Read DongleId for encryption key +dongle_id=/data/params/d/DongleId + +# Encrypt the file +cat "$src" | ccrypt -e -k "$dongle_id" > "$dest" diff --git a/system/clearpilot/tools/faketty.py b/system/clearpilot/tools/faketty.py new file mode 100644 index 0000000..51a9a94 --- /dev/null +++ b/system/clearpilot/tools/faketty.py @@ -0,0 +1,81 @@ +#!/usr/bin/env python + +from sys import argv +import os +import signal + +# I've had problems with python's File objects at this low a level, so +# we're going to use integers to specify all files in this script. +stdin = 0 +stdout = 1 +stderr = 2 +# Include this if passing the command and arguments to fish to +# prevent fish from applying any expansions. +#import re +#def fish_escape(args): +# def escape_one(arg): +# return "'" + re.sub(r"('|\\)", r'\\\1', arg) + "'" +# escaped_args = map(escape_one, args) +# return ' '.join(escaped_args) + +if len(argv) < 2: + os.write(stderr, +b"""A tragically beautiful piece of hackery, made to fool programs like ls, +grep, rg, and fd into thinking they're actually connected to a terminal. +Its usage: + +pty command [arg1 arg2 ...] + +Examples: +pty ls --color -R | less -r +git log -p | pty rg | less -r +""") + exit(255) + +# We do not use forkpty here because it would block ^Cs from reaching the +# child process. And we don't need that. +ptm, pts = os.openpty() +pid = os.fork() +if pid == 0: + # The child runs this. + # To get the behaviour we want, we only need to replace the process's + # stdout with pts. Everything else should remain in place, so that things + # like `ps -eF | pty rg python | less -r` will still work as intended. + os.dup2(pts, stdout) + # This is not like a subprocess.call(). It replaces the entire child + # process with argv[1:], meaning execvp will not return! Web search + # "fork exec" for more. + os.execvp(argv[1], argv[1:]) + # Use this if calling fish. + #os.execvp('fish', ['fish', '-c', fish_escape(argv[1:])]) + + +# The parent runs this. + +# If the parent doesn't close the slave end, the script won't be able to +# exit. The next read on ptm after the child process terminates would hang +# forever because pts would technically still be open. +os.close(pts) + +# The whole process group gets SIGINT, including the child, so we don't need +# to react to it. We'll know when to leave, judging by what the child does. +signal.signal(signal.SIGINT, signal.SIG_IGN) + +while True: + try: + chunk = os.read(ptm, 4096) + except OSError: + break + try: + os.write(stdout, chunk) + except BrokenPipeError: + # This happens when the parent is piping output to another process in a + # pipeline, like in `pty ls --color -R | less -r`, and the receiving + # process is terminated before the child has exited. If the receiving + # process is less, this can happen very easily. It happens every time + # the user decides to quit less before it has displayed all output. So, + # we need to stop the child process now. + os.kill(pid, signal.SIGTERM) + break +wait_pid, status = os.waitpid(pid, 0) +exit(status >> 8) diff --git a/system/clearpilot/tools/provision.sh b/system/clearpilot/tools/provision.sh new file mode 100644 index 0000000..826201c --- /dev/null +++ b/system/clearpilot/tools/provision.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +# Provision script for BrianBot +# These actions only occur on BrianBot's comma device. + +# 1. Check the string in /data/params/d/DongleId +dongle_id=$(cat /data/params/d/DongleId) +if [[ ! $dongle_id == 90bb71a* ]]; then + echo "Invalid dongle ID." + exit 1 +fi + +echo "BrianBot dongle ID detected." + +# 2. Check if ccrypt is installed, install if not +if ! command -v ccrypt >/dev/null 2>&1; then + echo "Installing ccrypt..." + sudo apt-get update + sudo apt-get install -y ccrypt +fi + +# 3. Decrypt SSH keys if they have not been decrypted yet +if [ ! -f /data/openpilot/system/clearpilot/dev/id_rsa.pub ]; then + echo "Decrypting SSH keys..." + ccrypt -d -k "$dongle_id" /data/openpilot/system/clearpilot/dev/id_rsa.pub.ccrypt + ccrypt -d -k "$dongle_id" /data/openpilot/system/clearpilot/dev/id_rsa.ccrypt + ccrypt -d -k "$dongle_id" /data/openpilot/system/clearpilot/dev/reverse_ssh.ccrypt +fi + +# 4. Ensure .ssh directory and keys exist +ssh_dir="/home/comma/.ssh" +if [[ ! -f "$ssh_dir/id_rsa" || ! -f "$ssh_dir/id_rsa.pub" ]]; then + echo "Setting up SSH directory and keys..." + mkdir -p "$ssh_dir" + cp /data/openpilot/system/clearpilot/dev/id_rsa /data/openpilot/system/clearpilot/dev/id_rsa.pub "$ssh_dir" + chmod 700 "$ssh_dir" + chmod 600 "$ssh_dir/id_rsa" "$ssh_dir/id_rsa.pub" +fi + +echo "Script execution complete." +exit 0 diff --git a/system/clearpilot/tools/scrun b/system/clearpilot/tools/scrun new file mode 100644 index 0000000..074d598 --- /dev/null +++ b/system/clearpilot/tools/scrun @@ -0,0 +1,37 @@ +#!/bin/bash + +# Usage: +# scrun instancename command + +# - If instancename doesnt exist, starts a screen with instancename and executes the given command. +# - Does not run if the instance is already running. +# - Runs in the same context as a shell (loads environment variables). +# - Logs output into /var/log/scrun/instance/DATE.log, with rotation + +# bash -l -c "$@" + +# Based on https://gist.github.com/camperdave/980040 +echo "defshell -bash" > ~/.screenrc +echo "startup_message off" >> ~/.screenrc +echo "vbell off" >> ~/.screenrc +echo "deflogin on" >> ~/.screenrc +echo "defscrollback 10000" >> ~/.screenrc +echo "defutf8 on" >> ~/.screenrc +echo "defflow off" >> ~/.screenrc +echo "msgwait 20" >> ~/.screenrc +echo "term screen-256color-bce" >> ~/.screenrc + +#SCREENNAME=scrun_$1_ +SCREENNAME=$1 + +screen -wipe 2>/dev/null >/dev/null + +if ! screen -list | grep -q $SCREENNAME; then + cesc="${@:2}" # Everything but first one +# cesc="${cesc@Q}" # Escape it + screen -dmS $SCREENNAME python3 /data/openpilot/system/clearpilot/tools/faketty.py bash -l -c "$cesc" + echo screen -dmS $SCREENNAME python3 /data/openpilot/system/clearpilot/tools/faketty.py bash -l -c "$cesc" +# screen -dmS $1 "$@" +else + echo $SCREENNAME is already running +fi