Some running real world usecases.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

182 lines
6.2 KiB

#!/bin/sh
#
# Demo the 'Like' activity using server-to-server protocol.
#
# https://socialhub.activitypub.rocks/t/help-needed-http-signatures/2458
#
# https://www.w3.org/TR/activitypub/#server-to-server-interactions
# https://blog.joinmastodon.org/2018/06/how-to-implement-a-basic-activitypub-server/#http-signatures
# adjust to match the $(dirname $0)
readonly baseurl="https://demo.mro.name/activitypub"
# some posts to like (object URL and owner actor):
#readonly object="https://digitalcourage.video/w/s3o5rzHfzFvXt4pUU9FMSg"
#readonly to="https://digitalcourage.video/accounts/digitalcourage.de"
#readonly object="https://digitalcourage.video/w/uFUuCoZ1MUJmia3QeN7u1h"
#readonly to="https://digitalcourage.video/accounts/digitalcourage.de"
#readonly object="https://digitalcourage.social/@mro/108206209517296437"
#readonly to="https://digitalcourage.social/users/mro"
#readonly object="https://pleroma.tilde.zone/notice/AIt4fotwER1doEg81I"
#readonly to="https://pleroma.tilde.zone/users/mro"
# readonly object="https://framatube.org/w/r15ZA9rna5UDNjKKZTbFwd"
# readonly to="https://tube.tchncs.de/accounts/diogo"
readonly object="https://tube.network.europa.eu/w/aTx3DYwH1km2gTEn9gKpah"
readonly to="https://tube.network.europa.eu/accounts/edps"
#readonly object="https://pixelfed.social/p/dk/279335294023634944"
#readonly to="https://pixelfed.social/users/dk"
# readonly object="https://gnusocial.net/notice/11921862"
# readonly to="https://gnusocial.net/index.php/user/1"
#readonly object="https://soc.schuerz.at/display/4edd2508-2562-911b-fa02-42c297830067"
#readonly to="https://soc.schuerz.at/profile/jakob"
# readonly object="https://lemmy.ml/post/171775"
# readonly to="https://lemmy.ml/u/nutomic"
cd "$(dirname "${0}")" || exit 1
[ "Linux" = "$(uname -s)" ] || { echo "at the time I run on Linux only" && exit 1; }
base64 --version >/dev/null || { echo "please install $ sudo apt-get install coreutils" && exit 1; }
curl --version >/dev/null || { echo "please install $ sudo apt-get install curl" && exit 1; }
dbus-uuidgen --version >/dev/null || { echo "please install $ sudo apt-get install dbus" && exit 1; }
jq --version >/dev/null || { echo "please install $ sudo apt-get install jq" && exit 1; }
openssl version >/dev/null || { echo "please install $ sudo apt-get install openssl" && exit 1; }
readonly agent="https://codeberg.org/mro/activitypub"
#############################################
echo "-> ensure current dir and baseurl match"
#############################################
readonly token="$(dbus-uuidgen)"
echo "${token}" > token
[ "$(curl --silent --location --user-agent "${agent}" "${baseurl}/token")" = "${token}" ] || {
cat 1>&2 <<EOF
!!! Error
put the current directory into a webserver.
Adjust '\$baseurl' above to match URL and filesystem.
!!!
EOF
exit 2
}
readonly actor="alice"
mkdir -p "u/${actor}/"
#############################################
echo "-> create RSA keys in case"
#############################################
[ -r "u/${actor}/id_rsa.priv.pem" ] || {
echo "-> generate private key"
openssl genrsa \
-out "u/${actor}/id_rsa.priv.pem" \
2048
chmod 400 "u/${actor}/id_rsa.priv.pem"
}
[ -r "u/${actor}/id_rsa.pub.pem" ] || {
openssl rsa \
-in "u/${actor}/id_rsa.priv.pem" \
-outform PEM \
-pubout \
-out "u/${actor}/id_rsa.pub.pem"
}
#############################################
echo "-> create actor profile"
#############################################
id="$baseurl/u/${actor}/"
pub_pem="$(jq -sR . < "u/${actor}/id_rsa.pub.pem")"
export id pub_pem
for f in \
"u/${actor}"/*.tpl
do
dst="$(dirname "${f}")/$(basename "${f}" .tpl)"
echo "-> create ${dst}"
envsubst \
< "${f}" \
> "${dst}"
done
#############################################
echo "-> create the activity"
#############################################
data="$(cat <<EOF
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Like",
"id": "${id}just-any-new-created-id#foo-bar",
"to": [ "${to}" ],
"actor": "${id}",
"object": "${object}",
"cc": [ "https://www.w3.org/ns/activitystreams#Public" ]
}
EOF
)"
#############################################
echo "-> create digest and signature"
#############################################
# HTTP signature according https://tools.ietf.org/id/draft-cavage-http-signatures-12.html#rfc.appendix.C
# https://www.ietf.org/archive/id/draft-ietf-httpbis-message-signatures-10.html#name-creating-a-signature
# Digest http://tools.ietf.org/html/rfc3230#section-4.3.2
#
# https://docs.joinmastodon.org/spec/security/#http
# https://w3id.org/security#publicKey
# https://w3id.org/security/v1
readonly dgst="SHA-256=$(printf "%s" "${data}" \
| openssl dgst -sha256 -binary \
| base64 -w 0)"
to_inbox="$(curl -H 'accept: application/activity+json' -A "${agent}" "$to" \
| jq -r .inbox)"
readonly to_host="$(printf "%s" "$to_inbox" | cut -d / -f 3)"
readonly now="$(LC_ALL=C date -u +'%a, %d %b %Y %T GMT')"
printf "%s: %s\n%s: %s\n%s: %s\n%s: %s" \
"(request-target)" "post /$(printf "%s" "$to_inbox" | cut -d / -f 4-)" \
"host" "${to_host}" \
"date" "${now}" \
"digest" "${dgst}" \
> "/tmp/ap-headers.txt"
# https://stackoverflow.com/a/49710414/349514
readonly sig="$(openssl dgst -sha256 -sign "u/${actor}/id_rsa.priv.pem" -binary "/tmp/ap-headers.txt" \
| base64 -w 0)"
readonly
sig_head="keyId=\"${id}#main-key\",algorithm=\"rsa-sha256\",headers=\"(request-target) host date digest\",signature=\"${sig}\""
#############################################
echo "-> preflight check: verify using the key from the HTTPS reachable profile"
#############################################
curl \
--location \
--silent \
--url "${id}" \
--user-agent "${agent}" \
| jq -r .publicKey.publicKeyPem \
> "/tmp/ap-pub.pem"
printf "%s" "${sig}" \
| base64 --decode \
> "/tmp/ap-sig.bin"
openssl dgst \
-sha256 \
-verify "/tmp/ap-pub.pem" \
-signature "/tmp/ap-sig.bin" \
"/tmp/ap-headers.txt"
#############################################
echo "-> POST the activity to $to_inbox"
#############################################
curl \
--data-binary "${data}" \
--header "host: ${to_host}" \
--header "date: ${now}" \
--header "digest: ${dgst}" \
--header "content-type: application/activity+json" \
--header "signature: ${sig_head}" \
--url "${to_inbox}" \
--trace "${0}.trace" \
--user-agent "${agent}"