encrypted-chat.sh

· antonio's pastes · raw

expires: never

 1#!/bin/bash
 2
 3set -eu -o pipefail
 4
 5# Implements an encrypted chat using age and pico pipes
 6# Usage: ./encrypted-chat.sh pubkey <identity> <user> <topic>
 7# Key: The user's key to send the message to, public key string
 8# Topic: The topic of the conversation
 9# Identity: The private key to decrypt the messages, file
10
11MODE="${1?Error: no mode given (pubkey)}"
12IDENTITY="${2?Error: no identity given for decryption}"
13KEY="${3?Error: no key given}"
14TOPIC="${4?Error: no topic given}"
15
16case "${MODE}" in
17    pubkey)
18        if [ ! -f "${IDENTITY}" ]; then
19            echo "Error: Identity file not found"
20            exit 1
21        fi
22
23        IDENTITY_INFO=$(ssh-keygen -lf "${IDENTITY}" | awk '{print $2}')
24        ACCESS_LIST="$(echo "${KEY}" | ssh-keygen -lf - | awk '{print $2}')"
25        AGE_FLAGS=(-r "${KEY}")
26        AGE_DECRYPT_FLAGS=(-i "${IDENTITY}")
27        ;;
28    *)
29        echo "Error: Invalid mode. Use 'pubkey'."
30        exit 1
31        ;;
32esac
33
34# Create random fifo pipes
35TMP_PIPE_IN="/tmp/pipe.${RANDOM}"
36TMP_PIPE_OUT="/tmp/pipe.${RANDOM}"
37mkfifo "${TMP_PIPE_IN}"
38mkfifo "${TMP_PIPE_OUT}"
39
40# Start the network pipe with our access list
41ssh pipe.pico.sh pipe "${TOPIC}" -a "${ACCESS_LIST}" < "${TMP_PIPE_IN}" > "${TMP_PIPE_OUT}" &
42PIPE_PID=$!
43
44# Start the age decryption process
45while read output; do echo "$output" | base64 -d | age -d "${AGE_DECRYPT_FLAGS[@]}" - || true; done < "${TMP_PIPE_OUT}" &
46AGE_PID=$!
47
48# Cleanup function
49function cleanup(){
50    kill "${PIPE_PID}" "${AGE_PID}" > /dev/null 2>&1 || true
51    rm -f "${TMP_PIPE_IN}" "${TMP_PIPE_OUT}"
52    exit 0
53}
54
55trap cleanup SIGINT SIGTERM EXIT
56
57# Read from stdin and encrypt the message. Send it to the pipe.
58while read line; do
59  echo "${IDENTITY_INFO}: ${line}" | age -e "${AGE_FLAGS[@]}" - | base64 -w0
60done > "${TMP_PIPE_IN}"