#!/bin/bash set -eu -o pipefail # Implements an encrypted chat using age and pico pipes # Usage: ./encrypted-chat.sh pubkey # Key: The user's key to send the message to, public key string # Topic: The topic of the conversation # Identity: The private key to decrypt the messages, file MODE="${1?Error: no mode given (pubkey)}" IDENTITY="${2?Error: no identity given for decryption}" KEY="${3?Error: no key given}" TOPIC="${4?Error: no topic given}" case "${MODE}" in pubkey) if [ ! -f "${IDENTITY}" ]; then echo "Error: Identity file not found" exit 1 fi IDENTITY_INFO=$(ssh-keygen -lf "${IDENTITY}" | awk '{print $2}') ACCESS_LIST="$(echo "${KEY}" | ssh-keygen -lf - | awk '{print $2}')" AGE_FLAGS=(-r "${KEY}") AGE_DECRYPT_FLAGS=(-i "${IDENTITY}") ;; *) echo "Error: Invalid mode. Use 'pubkey'." exit 1 ;; esac # Create random fifo pipes TMP_PIPE_IN="/tmp/pipe.${RANDOM}" TMP_PIPE_OUT="/tmp/pipe.${RANDOM}" mkfifo "${TMP_PIPE_IN}" mkfifo "${TMP_PIPE_OUT}" # Start the network pipe with our access list ssh pipe.pico.sh pipe "${TOPIC}" -a "${ACCESS_LIST}" < "${TMP_PIPE_IN}" > "${TMP_PIPE_OUT}" & PIPE_PID=$! # Start the age decryption process while read output; do echo "$output" | base64 -d | age -d "${AGE_DECRYPT_FLAGS[@]}" - || true; done < "${TMP_PIPE_OUT}" & AGE_PID=$! # Cleanup function function cleanup(){ kill "${PIPE_PID}" "${AGE_PID}" > /dev/null 2>&1 || true rm -f "${TMP_PIPE_IN}" "${TMP_PIPE_OUT}" exit 0 } trap cleanup SIGINT SIGTERM EXIT # Read from stdin and encrypt the message. Send it to the pipe. while read line; do echo "${IDENTITY_INFO}: ${line}" | age -e "${AGE_FLAGS[@]}" - | base64 -w0 done > "${TMP_PIPE_IN}"