Skip to content

Commit

Permalink
Add pdsadmin script (#38)
Browse files Browse the repository at this point in the history
* add pdsadmin helper script

---------

Co-authored-by: Devin Ivy <[email protected]>
  • Loading branch information
Jacob2161 and devinivy authored Feb 21, 2024
1 parent 2307208 commit 78da261
Show file tree
Hide file tree
Showing 6 changed files with 334 additions and 0 deletions.
31 changes: 31 additions & 0 deletions pdsadmin.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/bin/bash
set -o errexit
set -o nounset
set -o pipefail

#PDSADMIN_BASE_URL="https://raw.githubusercontent.com/bluesky-social/pds/main/pdsadmin"
PDSADMIN_BASE_URL="https://raw.githubusercontent.com/bluesky-social/pds/jake/add-pdsadmin/pdsadmin"

# Command to run.
COMMAND="${1:-help}"
shift || true

# Ensure the user is root, since it's required for most commands.
if [[ "${EUID}" -ne 0 ]]; then
echo "ERROR: This script must be run as root"
exit 1
fi

# Download the script, if it exists.
SCRIPT_URL="${PDSADMIN_BASE_URL}/${COMMAND}.sh"
SCRIPT_FILE="$(mktemp /tmp/pdsadmin.${COMMAND}.XXXXXX)"

if ! curl --fail --silent --show-error --location --output "${SCRIPT_FILE}" "${SCRIPT_URL}"; then
echo "ERROR: ${COMMAND} not found"
exit 2
fi

chmod +x "${SCRIPT_FILE}"
if "${SCRIPT_FILE}" "$@"; then
rm --force "${SCRIPT_FILE}"
fi
169 changes: 169 additions & 0 deletions pdsadmin/account.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
#!/bin/bash
set -o errexit
set -o nounset
set -o pipefail

PDS_ENV_FILE="/pds/pds.env"
source "${PDS_ENV_FILE}"

curl_cmd() {
curl --fail --silent --show-error "$@"
}

curl_cmd_post() {
curl --fail --silent --show-error --request POST --header "Content-Type: application/json" "$@"
}

curl_cmd_post_nofail() {
curl --silent --show-error --request POST --header "Content-Type: application/json" "$@"
}

SUBCOMMAND="${1:-}"

if [[ "${SUBCOMMAND}" == "list" ]]; then
DIDS=$(curl_cmd \
"https://${PDS_HOSTNAME}/xrpc/com.atproto.sync.listRepos?limit=100" | jq --raw-output '.repos[].did'
)
OUTPUT='[{"handle":"Handle","email":"Email","did":"DID"}'
for did in $DIDS; do
ITEM=$(curl_cmd \
--user "admin:${PDS_ADMIN_PASSWORD}" \
"https://${PDS_HOSTNAME}/xrpc/com.atproto.admin.getAccountInfo?did=$did"
)
OUTPUT="${OUTPUT},${ITEM}"
done
OUTPUT="${OUTPUT}]"
echo $OUTPUT | jq --raw-output '.[] | [.handle, .email, .did] | @tsv' | column -t
elif [[ "${SUBCOMMAND}" == "create" ]]; then
EMAIL="${2:-}"
HANDLE="${3:-}"

if [[ "${EMAIL}" == "" || "${HANDLE}" == "" ]]; then
echo "ERROR: missing EMAIL and/or HANDLE parameters." >/dev/stderr
echo "Usage: $0 ${SUBCOMMAND} <EMAIL> <HANDLE>" >/dev/stderr
exit 1
fi

PASSWORD=$(openssl rand -base64 30 | tr -d "=+/" | cut -c1-24)
INVITE_CODE=$(curl_cmd_post \
--user "admin:${PDS_ADMIN_PASSWORD}" \
--data '{"useCount": 1}' \
https://${PDS_HOSTNAME}/xrpc/com.atproto.server.createInviteCode | jq --raw-output '.code'
)
RESULT=$(curl_cmd_post_nofail \
--data "{\"email\":\"${EMAIL}\", \"handle\":\"${HANDLE}\", \"password\":\"${PASSWORD}\", \"inviteCode\":\"${INVITE_CODE}\"}" \
https://${PDS_HOSTNAME}/xrpc/com.atproto.server.createAccount
)

DID=$(echo $RESULT | jq --raw-output '.did')
if [[ "${DID}" != did:* ]]; then
ERR=$(echo $RESULT | jq --raw-output '.message')
echo "ERROR: ${ERR}" >/dev/stderr
echo "Usage: $0 ${SUBCOMMAND} <EMAIL> <HANDLE>" >/dev/stderr
exit 1
fi

echo "Account created for ${HANDLE}.\nYour password is below, which we'll only show you once.\n"
echo "DID: ${DID}"
echo "Password: ${PASSWORD}"
elif [[ "${SUBCOMMAND}" == "delete" ]]; then
DID="${2:-}"

if [[ "${DID}" == "" ]]; then
echo "ERROR: missing DID parameter." >/dev/stderr
echo "Usage: $0 ${SUBCOMMAND} <DID>" >/dev/stderr
exit 1
fi

if [[ "${DID}" != did:* ]]; then
echo "ERROR: DID parameter must start with \"did:\"." >/dev/stderr
echo "Usage: $0 ${SUBCOMMAND} <DID>" >/dev/stderr
exit 1
fi

echo "This action is permanent."
read -r -p "Are you sure you'd like to delete ${DID}? [y/N] " response
if [[ ! "$response" =~ ^([yY][eE][sS]|[yY])$ ]]; then
exit 0
fi

curl_cmd_post \
--user "admin:${PDS_ADMIN_PASSWORD}" \
--data "{\"did\": \"${DID}\"}" \
https://${PDS_HOSTNAME}/xrpc/com.atproto.admin.deleteAccount >/dev/null

echo "${DID} deleted"
elif [[ "${SUBCOMMAND}" == "takedown" ]]; then
DID="${2:-}"
TAKEDOWN_REF="$(date +%s)"

if [[ "${DID}" == "" ]]; then
echo "ERROR: missing DID parameter." >/dev/stderr
echo "Usage: $0 ${SUBCOMMAND} <DID>" >/dev/stderr
exit 1
fi

if [[ "${DID}" != did:* ]]; then
echo "ERROR: DID parameter must start with \"did:\"." >/dev/stderr
echo "Usage: $0 ${SUBCOMMAND} <DID>" >/dev/stderr
exit 1
fi

PAYLOAD=$(cat <<EOF
{
"subject": {
"\$type": "com.atproto.admin.defs#repoRef",
"did": "${DID}"
},
"takedown": {
"applied": true,
"ref": "${TAKEDOWN_REF}"
}
}
EOF
)

curl_cmd_post \
--user "admin:${PDS_ADMIN_PASSWORD}" \
--data "${PAYLOAD}" \
https://${PDS_HOSTNAME}/xrpc/com.atproto.admin.updateSubjectStatus >/dev/null

echo "${DID} taken down"
elif [[ "${SUBCOMMAND}" == "untakedown" ]]; then
DID="${2:-}"

if [[ "${DID}" == "" ]]; then
echo "ERROR: missing DID parameter." >/dev/stderr
echo "Usage: $0 ${SUBCOMMAND} <DID>" >/dev/stderr
exit 1
fi

if [[ "${DID}" != did:* ]]; then
echo "ERROR: DID parameter must start with \"did:\"." >/dev/stderr
echo "Usage: $0 ${SUBCOMMAND} <DID>" >/dev/stderr
exit 1
fi

PAYLOAD=$(cat <<EOF
{
"subject": {
"\$type": "com.atproto.admin.defs#repoRef",
"did": "${DID}"
},
"takedown": {
"applied": false
}
}
EOF
)

curl_cmd_post \
--user "admin:${PDS_ADMIN_PASSWORD}" \
--data "${PAYLOAD}" \
https://${PDS_HOSTNAME}/xrpc/com.atproto.admin.updateSubjectStatus >/dev/null

echo "${DID} untaken down"
else
echo "Unknown subcommand "$0 ${SUBCOMMAND}"." >/dev/stderr
exit 1
fi
18 changes: 18 additions & 0 deletions pdsadmin/create-invite-code.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/bin/bash
set -o errexit
set -o nounset
set -o pipefail

PDS_ENV_FILE="/pds/pds.env"

source "${PDS_ENV_FILE}"

curl \
--fail \
--silent \
--show-error \
--request POST \
--user "admin:${PDS_ADMIN_PASSWORD}" \
--header "Content-Type: application/json" \
--data '{"useCount": 1}' \
https://${PDS_HOSTNAME}/xrpc/com.atproto.server.createInviteCode | jq --raw-output '.code'
42 changes: 42 additions & 0 deletions pdsadmin/help.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#!/bin/bash
set -o errexit
set -o nounset
set -o pipefail

# This script is used to display help information for the pdsadmin command.
cat <<HELP
pdsadmin help
--
update
Update to the latest PDS version.
e.g. pdsadmin update
account
list
List accounts
e.g. pdsadmin account list
create <EMAIL> <HANDLE>
Create a new account
e.g. pdsadmin account create [email protected] alice.example.com
delete <DID>
Delete an account specified by DID.
e.g. pdsadmin account takedown did:plc:xyz123abc456
takedown <DID>
Takedown an account specified by DID.
e.g. pdsadmin account takedown did:plc:xyz123abc456
untakedown <DID>
Remove a takedown an account specified by DID.
e.g. pdsadmin account takedown did:plc:xyz123abc456
request-crawl [<RELAY HOST>]
Request a crawl from a relay host.
e.g. pdsadmin request-crawl bsky.network
create-invite-code
Create a new invite code.
e.g. pdsadmin create-invite-code
help
Display this help information.
HELP
33 changes: 33 additions & 0 deletions pdsadmin/request-crawl.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/bin/bash
set -o errexit
set -o nounset
set -o pipefail

PDS_ENV_FILE="/pds/pds.env"
source "${PDS_ENV_FILE}"

RELAY_HOSTS="${1:-}"
if [[ "${RELAY_HOSTS}" == "" ]]; then
RELAY_HOSTS="${PDS_CRAWLERS}"
fi

if [[ "${RELAY_HOSTS}" == "" ]]; then
echo "ERROR: missing RELAY HOST parameter." >/dev/stderr
echo "Usage: $0 <RELAY HOST>[,<RELAY HOST>,...]" >/dev/stderr
exit 1
fi

for host in ${RELAY_HOSTS//,/ }; do
echo "Requesting crawl from ${host}"
curl \
--fail \
--silent \
--show-error \
--request POST \
--user "admin:${PDS_ADMIN_PASSWORD}" \
--header "Content-Type: application/json" \
--data "{\"hostname\": \"${PDS_HOSTNAME}\"}" \
https://${host}/xrpc/com.atproto.sync.requestCrawl >/dev/null
done

echo "done"
41 changes: 41 additions & 0 deletions pdsadmin/update.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/bin/bash
set -o errexit
set -o nounset
set -o pipefail

PDS_DATADIR="/pds"
COMPOSE_FILE="${PDS_DATADIR}/compose.yaml"
COMPOSE_URL="https://raw.githubusercontent.com/bluesky-social/pds/main/compose.yaml"

# TODO: allow the user to specify a version to update to.
TARGET_VERSION="${1:-}"

COMPOSE_TEMP_FILE="${COMPOSE_FILE}.tmp"

echo "* Downloading PDS compose file"
curl \
--silent \
--show-error \
--fail \
--output "${COMPOSE_TEMP_FILE}" \
"${COMPOSE_URL}"

if cmp -s "${COMPOSE_FILE}" "${COMPOSE_TEMP_FILE}"; then
echo "PDS is already up to date"
rm "${COMPOSE_TEMP_FILE}"
exit 0
fi

echo "* Updating PDS"
mv "${COMPOSE_TEMP_FILE}" "${COMPOSE_FILE}"

echo "* Restarting PDS"
systemctl restart pds

cat <<MESSAGE
PDS has been updated
---------------------
Check systemd logs: journalctl --unit pds
Check container logs: docker logs pds
MESSAGE

0 comments on commit 78da261

Please sign in to comment.