diff --git a/TODO.txt b/TODO.txt index c2dcd58..1ff2ddf 100644 --- a/TODO.txt +++ b/TODO.txt @@ -32,7 +32,7 @@ Due: July 1, 2023 making it a separate block, there's less of a chance of the information getting destroyed. It's worth a few extra bytes of memory to make accidents harder, I think. -[ ] Add recipe to td script to upload patches to the Matrix room +[x] Add recipe to td script to upload patches to the Matrix room [ ] Figure out how to write unit tests for array/hashmap/etc [~] Convert documentation to man pages [~] Internal API docs diff --git a/man/man7/telodendria-contributing.7 b/man/man7/telodendria-contributing.7 index 1149181..5e5bba8 100644 --- a/man/man7/telodendria-contributing.7 +++ b/man/man7/telodendria-contributing.7 @@ -1,4 +1,4 @@ -.Dd $Mdocdate: November 6 2022 $ +.Dd $Mdocdate: November 11 2022 $ .Dt TELODENDRIA-CONTRIBUTING 7 .Os Telodendria Project .Sh NAME @@ -161,9 +161,8 @@ consistent with this project or the open source licenses involved. If you agree to the above, fill in the square brackets with an 'x', and then after the headers, but before the checkbox, write a more thorough description of the patch and why it was created. Then, send the resulting patch file to the public -Matrix room, as noted in -.Xr telodendria 7 , -so it can be discussed and reviewed by the community. +Matrix room using +.Xr send-patch 1 . .sp Try to keep your patches on topic\(emmake one patch file per feature or bug fix being implemented. It is okay if your patches depend on previous patches, just diff --git a/tools/bin/send-patch b/tools/bin/send-patch new file mode 100755 index 0000000..0364d88 --- /dev/null +++ b/tools/bin/send-patch @@ -0,0 +1,170 @@ +#!/usr/bin/env sh +# +# send-patch: "The Telodendria Patch Sender" +# +# This is a simple script for posting patch files to +# a single room(generally the Telodendria patch room.) + +. "$(pwd)/tools/lib/common.sh" + +# Path to the patch to send. +PATCHFILE="$1" + +# Tries to decompose the name and the HS from an MXID using +# sed. +UR_NAME="$(echo "$MXID" | sed "s/\@\(.*\)\:\(.*\)/\1/")" +HS_NAME="$(echo "$MXID" | sed "s/\@\(.*\)\:\(.*\)/\2/")" + +# Prompts the user for a password, while disabling echo-ing. +readpwd() { + printf "$1" + stty -echo -ctlecho + read -r "$2"; echo + stty echo ctlecho +} + +# Calls curl, setting the RETURN variable for the actual +# reply from the server and the ERROR_CODE variable for a +# HTTP error code. +curlec() { + RETURN="$(curl -w "\n%{http_code}" "$@" 2> /dev/null)" + ERROR_CODE="$(echo "$RETURN" | tail -n1)" + RETURN="$(echo "$RETURN" | head -n"-1")" +} + +# Prompts user to login and gives out an access token to use +# in the ACCESS_TOKEN variable +matrix_login() { + # Check authentication methods + echo "Checking authentication methods..." + curlec "$HS_BASE/_matrix/client/v3/login" + AUTH_METHODS=$RETURN + if [ $ERROR_CODE -ne 200 ]; then + echo "Homeserver does not support login." + exit 1; + fi; + SUPPORTS_PASSWORD="$(echo "$AUTH_METHODS" | jq -r '.flows[].type' | grep "m.login.password" | wc -l)" + if [ $SUPPORTS_PASSWORD -lt 1 ]; then + echo "Homeserver does not support password authentication." + exit 1; + fi; + # Homeserver does support password authentication, so request + # them one. + if [ -z "$MXPW" ]; then + readpwd "Enter your Matrix password: " MXPW + fi + # Tries to login using the "Telodendria Patch Script" device + # name + JSON="$(jq --null-input \ + --arg username "$UR_NAME" \ + --arg password "$MXPW" \ + --arg idtype "m.id.user" \ + --arg passwordtype "m.login.password" \ + '{ + "identifier": { + "type": $idtype, + "user": $username + }, + "initial_device_display_name": "Telodendria Patch Script", + "type": $passwordtype, + "password": $password + }')" + curlec -X POST $HS_BASE/_matrix/client/v3/login --data "$JSON" + LOGIN=$RETURN + if [ $ERROR_CODE -ne 200 ]; then + echo "Login failed." + exit 1; + fi; + ACCESS_TOKEN="$(echo "$LOGIN" | jq -r .access_token)" +} + +# Logs out of Matrix using the ACFESS_TOKEN environment variable +matrix_logout() { + if [ -z "$ACCESS_TOKEN" ]; then + echo "No access token" + exit 1 + fi + curlec -X POST $HS_BASE/_matrix/client/v3/logout -H "Authorization: Bearer $ACCESS_TOKEN" + LOGOUT=$RETURN + if [ $ERROR_CODE -ne 200 ]; then + echo "Logout failed." + exit 1 + fi; + echo "Logged out." +} + +send_patch() { + if [ -z "$ACCESS_TOKEN" ]; then + matrix_login + DO_LOGOUT=1 + fi + # We are sucessfully logged in as our user, now let's + # try to upload and post our patch + echo "$PATCHFILE" + curlec -X POST "$HS_BASE/_matrix/media/v3/upload" \ + -H "Content-Type: text/x-patch" \ + -H "Authorization: Bearer $ACCESS_TOKEN" \ + -T "$PATCHFILE" + MXCID=$RETURN + if [ $ERROR_CODE -ne 200 ]; then + echo "Upload failed." + matrix_logout + exit 1; + fi; + MXCID="$(echo "$MXCID" | jq -r .content_uri)" + echo "MXC ID: $MXCID" + JSON="$(jq --null-input \ + --arg name "$(basename "$PATCHFILE")" \ + --arg mxc "$MXCID" \ + --arg msgtype "m.file" \ + --argjson size "$(wc -c "$PATCHFILE" | cut -d" " -f1)" \ + '{ + "body": $name, + "filename": $name, + "info": { + "mimetype": "text/x-patch", + "size": $size + }, + "msgtype": $msgtype, + "url": $mxc + }')" + curl \ + -X PUT \ + -H "Authorization: Bearer $ACCESS_TOKEN" \ + "$HS_BASE/_matrix/client/v3/rooms/$PATCHES_ROOM/send/m.room.message/$(date +%s)" \ + --data "$JSON" 2> /dev/null > /dev/null && echo "Patch sent." + + # Log out if we generated an access token + if [ "$DO_LOGOUT" -eq "1" ]; then + matrix_logout + fi +} + +# Check if the patch file is valid. +if [ "$(basename "$PATCHFILE" .patch)" = "$PATCHFILE" ] || [ ! -f "$PATCHFILE" ]; then + echo "Format: $0 file.patch" + exit 1 +fi +echo "Sending file '$PATCHFILE'" +echo "Checking homeserver's real address using .well-known..." +curlec "$HS_NAME/.well-known/matrix/client" +case "$ERROR_CODE" in + "200") + WELL_KNOWN=$RETURN + if [ -z "$WELL_KNOWN" ]; then + echo "well-known test returned 200 but no correct input was given." + exit 1 + fi + # well-known entry is correct, we can now store our base endpoint + HS_BASE="$(printf "$WELL_KNOWN" | jq -r '.["m.homeserver"].base_url')" && send_patch + ;; + * ) + echo "$ERROR_CODE" + + echo "well-known test failed." + printf "Please enter your homeserver base URL: " + read -r HS_BASE; echo + send_patch + ;; +esac + diff --git a/tools/bin/td b/tools/bin/td index 0dccbc5..2e3a90e 100644 --- a/tools/bin/td +++ b/tools/bin/td @@ -32,14 +32,7 @@ : "${PREFIX:=/usr/local}" -# If a .env file exists in the current directory, we load it. -# As Telodendria's build infrastructure relies heavily on -# environment variables, we allow users to specify their -# Telodendria-specific variables in a dedicated .env so they don't -# have to pollute their environment. -if [ -f "$(pwd)/.env" ]; then - . "$(pwd)/.env" -fi +. "$(pwd)/tools/lib/common.sh" if [ "$DEBUG" = "1" ]; then CFLAGS="$CFLAGS -O0 -g" diff --git a/tools/bin/tp b/tools/bin/tp index c6a6590..5f1a593 100755 --- a/tools/bin/tp +++ b/tools/bin/tp @@ -4,17 +4,7 @@ # # This script is used to manage the patch queue. -if [ -f "$(pwd)/.env" ]; then - . "$(pwd)/.env" -fi - -if [ -z "$MXID" ]; then - MXID="@(${USER}:$(hostname)" -fi - -if [ -z "$DISPLAY_NAME" ]; then - DISPLAY_NAME=$(getent passwd "$USER" | cut -d ':' -f 5 | cut -d ',' -f 1) -fi +. "$(pwd)/tools/lib/common.sh" if [ -z "$TELODENDRIA_PUB" ]; then echo "TELODENDRIA_PUB not set." @@ -39,13 +29,13 @@ matrix_send() { --arg format "org.matrix.custom.html" \ --arg msgtype "m.text" \ '{"body":$body,"formatted_body":$formatted_body,"format":$format,"msgtype":$msgtype}' | - $CURL -X PUT -d @- "$HOMESERVER/client/v3/rooms/$ROOM_ID/send/m.room.message/$(date +%s)?access_token=$ACCESS_TOKEN" + $CURL -X PUT -d @- "$HOMESERVER/client/v3/rooms/$PATCHES_ROOM/send/m.room.message/$(date +%s)?access_token=$ACCESS_TOKEN" fi } matrix_get_files() { $CURL "$HOMESERVER/client/v3/sync?access_token=$ACCESS_TOKEN" | - jq ".rooms.join.\"$ROOM_ID\".timeline.events[] | select(.type==\"m.room.message\") | .content | select(.msgtype==\"m.file\") | [.body,.info.size,.url] | @tsv" | + jq ".rooms.join.\"$PATCHES_ROOM\".timeline.events[] | select(.type==\"m.room.message\") | .content | select(.msgtype==\"m.file\") | [.body,.info.size,.url] | @tsv" | cut -d '"' -f 2 | sed 's/\\t/,/g' } diff --git a/tools/lib/common.sh b/tools/lib/common.sh new file mode 100644 index 0000000..95455b5 --- /dev/null +++ b/tools/lib/common.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env sh + +: "${PATCHES_ROOM:=!tyDHfIvAyfImrzOVVt:bancino.net}" + +if [ -f "$(pwd)/.env" ]; then + . "$(pwd)/.env" +fi + +if [ -z "$MXID" ]; then + MXID="@${USER}:$(hostname)" +fi + +if [ -z "$DISPLAY_NAME" ]; then + DISPLAY_NAME=$(getent passwd "$USER" | cut -d ':' -f 5 | cut -d ',' -f 1) +fi +