113 lines
2.8 KiB
Bash
113 lines
2.8 KiB
Bash
|
#!/bin/sh
|
||
|
|
||
|
# MM Shell bot
|
||
|
# By 0xDEADCADE
|
||
|
|
||
|
# Config
|
||
|
MM="${HOME}/go/bin/mm"
|
||
|
MMDIR="mm"
|
||
|
CMDDIR="bin"
|
||
|
HOMESERVER="https://matrix.example.org"
|
||
|
USERNAME="user"
|
||
|
MMCONF="${PWD}/mm.yml"
|
||
|
PREFIX="\\"
|
||
|
TIMEOUT=60
|
||
|
# Ensure access to ADMIN env var to subprocesses
|
||
|
export ADMIN="@deadcade:deadca.de"
|
||
|
|
||
|
# Create mm directory
|
||
|
mkdir -p "${MMDIR}"
|
||
|
# Ensure real paths instead of relative
|
||
|
MMDIR=$(readlink -nf "${MMDIR}")
|
||
|
CMDDIR=$(readlink -nf "${CMDDIR}")
|
||
|
|
||
|
# Generate mm config
|
||
|
if [ ! -f "${MMCONF}" ]; then
|
||
|
# No config was found, create a new one
|
||
|
PASSWORD=$(pass "${HOMESERVER}/${USERNAME}")
|
||
|
echo "server: ${HOMESERVER}
|
||
|
username: ${USERNAME}
|
||
|
password: ${PASSWORD}
|
||
|
certificate: ''
|
||
|
directory: ${MMDIR}
|
||
|
login:
|
||
|
userid: ''
|
||
|
deviceid: ''
|
||
|
accesstoken: ''
|
||
|
" > "${MMCONF}"
|
||
|
unset PASSWORD
|
||
|
fi
|
||
|
|
||
|
# Start mm
|
||
|
cd "${MMDIR}" || exit
|
||
|
$MM -c "${MMCONF}" 2>> "${MMDIR}/log" 1>> "${MMDIR}/out" &
|
||
|
MMPID="${!}"
|
||
|
|
||
|
# Ensure mm is started
|
||
|
sleep 3
|
||
|
|
||
|
# Remove password from file (otherwise password would be stored in plaintext)
|
||
|
grep -vF "password" "${MMCONF}" > /tmp/mm.yml
|
||
|
cp /tmp/mm.yml "${MMCONF}"
|
||
|
rm /tmp/mm.yml
|
||
|
|
||
|
# Get some variables from created config
|
||
|
HOMESERVER=$(echo "${HOMESERVER}" | cut -d "/" -f 3)
|
||
|
USERID=$(grep "userid" "${MMCONF}" | awk '{ print $2 }' | cut -d "'" -f 2)
|
||
|
|
||
|
# Ensure log in was successful
|
||
|
cd "${MMDIR}/${HOMESERVER}/${USERID}" || exit
|
||
|
|
||
|
# Separate function to execute the command, for async support
|
||
|
execute() {
|
||
|
CMD=$1
|
||
|
# Grab args without command
|
||
|
ARGS=$(printf '%s' "$MESSAGE" | tail -c"+$((${#PREFIX} + ${#CMD} + 2))")
|
||
|
# Execute command, keeping every Matrix command argument as a shell command argument
|
||
|
# shellcheck disable=SC2086
|
||
|
OUT=$(timeout "$((TIMEOUT + 5))" timeout -s INT "${TIMEOUT}" "${CMDDIR}/${CMD}" ${ARGS} 2>&1)
|
||
|
if [ "$OUT" != "" ]; then
|
||
|
# Send back output
|
||
|
printf '%s' "${OUT}" > "${INFILE}"
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
# Process a message
|
||
|
message() {
|
||
|
while read -r MSG; do
|
||
|
cd "${MMDIR}/${HOMESERVER}/${USERID}" || exit
|
||
|
# Give detail about message to subprocess
|
||
|
FILE="!"$(echo "${MSG}" | cut -d "!" -f 2)
|
||
|
MESSAGE=$(cat "${FILE}")
|
||
|
ROOMID=$(echo "${FILE}" | cut -d "/" -f 1)
|
||
|
SENDER=$(echo "${FILE}" | cut -d "/" -f 2)
|
||
|
INFILE="${MMDIR}/${HOMESERVER}/${USERID}/${ROOMID}/in"
|
||
|
export FILE MESSAGE ROOMID SENDER INFILE
|
||
|
# If this message is a command
|
||
|
case "${MESSAGE}" in
|
||
|
"${PREFIX}"*)
|
||
|
cd "${CMDDIR}" || exit
|
||
|
for CMD in *; do
|
||
|
# Check if the command is valid, either with args or exact
|
||
|
if [ "${MESSAGE}" = "${PREFIX}${CMD}" ]; then
|
||
|
execute "${CMD}" &
|
||
|
fi
|
||
|
case "${MESSAGE}" in
|
||
|
"${PREFIX}${CMD} "*)
|
||
|
execute "${CMD}" &
|
||
|
;;
|
||
|
esac
|
||
|
done
|
||
|
esac
|
||
|
done
|
||
|
}
|
||
|
|
||
|
# Ensure ctrl+c continues the script
|
||
|
trap true INT
|
||
|
|
||
|
# Give new messages to message function
|
||
|
tail -n0 -f "${MMDIR}/out" | message
|
||
|
|
||
|
# Kill the mm instance after ctrl+c
|
||
|
kill "${MMPID}"
|