Mirror from bluesky-social/pds

Add pdsadmin script (#38)

* add pdsadmin helper script

---------

Co-authored-by: Devin Ivy <devinivy@gmail.com>

authored by

Jake Gold
Devin Ivy
and committed by
GitHub
78da2612 23072087

+334
+31
pdsadmin.sh
··· 1 + #!/bin/bash 2 + set -o errexit 3 + set -o nounset 4 + set -o pipefail 5 + 6 + #PDSADMIN_BASE_URL="https://raw.githubusercontent.com/bluesky-social/pds/main/pdsadmin" 7 + PDSADMIN_BASE_URL="https://raw.githubusercontent.com/bluesky-social/pds/jake/add-pdsadmin/pdsadmin" 8 + 9 + # Command to run. 10 + COMMAND="${1:-help}" 11 + shift || true 12 + 13 + # Ensure the user is root, since it's required for most commands. 14 + if [[ "${EUID}" -ne 0 ]]; then 15 + echo "ERROR: This script must be run as root" 16 + exit 1 17 + fi 18 + 19 + # Download the script, if it exists. 20 + SCRIPT_URL="${PDSADMIN_BASE_URL}/${COMMAND}.sh" 21 + SCRIPT_FILE="$(mktemp /tmp/pdsadmin.${COMMAND}.XXXXXX)" 22 + 23 + if ! curl --fail --silent --show-error --location --output "${SCRIPT_FILE}" "${SCRIPT_URL}"; then 24 + echo "ERROR: ${COMMAND} not found" 25 + exit 2 26 + fi 27 + 28 + chmod +x "${SCRIPT_FILE}" 29 + if "${SCRIPT_FILE}" "$@"; then 30 + rm --force "${SCRIPT_FILE}" 31 + fi
+169
pdsadmin/account.sh
··· 1 + #!/bin/bash 2 + set -o errexit 3 + set -o nounset 4 + set -o pipefail 5 + 6 + PDS_ENV_FILE="/pds/pds.env" 7 + source "${PDS_ENV_FILE}" 8 + 9 + curl_cmd() { 10 + curl --fail --silent --show-error "$@" 11 + } 12 + 13 + curl_cmd_post() { 14 + curl --fail --silent --show-error --request POST --header "Content-Type: application/json" "$@" 15 + } 16 + 17 + curl_cmd_post_nofail() { 18 + curl --silent --show-error --request POST --header "Content-Type: application/json" "$@" 19 + } 20 + 21 + SUBCOMMAND="${1:-}" 22 + 23 + if [[ "${SUBCOMMAND}" == "list" ]]; then 24 + DIDS=$(curl_cmd \ 25 + "https://${PDS_HOSTNAME}/xrpc/com.atproto.sync.listRepos?limit=100" | jq --raw-output '.repos[].did' 26 + ) 27 + OUTPUT='[{"handle":"Handle","email":"Email","did":"DID"}' 28 + for did in $DIDS; do 29 + ITEM=$(curl_cmd \ 30 + --user "admin:${PDS_ADMIN_PASSWORD}" \ 31 + "https://${PDS_HOSTNAME}/xrpc/com.atproto.admin.getAccountInfo?did=$did" 32 + ) 33 + OUTPUT="${OUTPUT},${ITEM}" 34 + done 35 + OUTPUT="${OUTPUT}]" 36 + echo $OUTPUT | jq --raw-output '.[] | [.handle, .email, .did] | @tsv' | column -t 37 + elif [[ "${SUBCOMMAND}" == "create" ]]; then 38 + EMAIL="${2:-}" 39 + HANDLE="${3:-}" 40 + 41 + if [[ "${EMAIL}" == "" || "${HANDLE}" == "" ]]; then 42 + echo "ERROR: missing EMAIL and/or HANDLE parameters." >/dev/stderr 43 + echo "Usage: $0 ${SUBCOMMAND} <EMAIL> <HANDLE>" >/dev/stderr 44 + exit 1 45 + fi 46 + 47 + PASSWORD=$(openssl rand -base64 30 | tr -d "=+/" | cut -c1-24) 48 + INVITE_CODE=$(curl_cmd_post \ 49 + --user "admin:${PDS_ADMIN_PASSWORD}" \ 50 + --data '{"useCount": 1}' \ 51 + https://${PDS_HOSTNAME}/xrpc/com.atproto.server.createInviteCode | jq --raw-output '.code' 52 + ) 53 + RESULT=$(curl_cmd_post_nofail \ 54 + --data "{\"email\":\"${EMAIL}\", \"handle\":\"${HANDLE}\", \"password\":\"${PASSWORD}\", \"inviteCode\":\"${INVITE_CODE}\"}" \ 55 + https://${PDS_HOSTNAME}/xrpc/com.atproto.server.createAccount 56 + ) 57 + 58 + DID=$(echo $RESULT | jq --raw-output '.did') 59 + if [[ "${DID}" != did:* ]]; then 60 + ERR=$(echo $RESULT | jq --raw-output '.message') 61 + echo "ERROR: ${ERR}" >/dev/stderr 62 + echo "Usage: $0 ${SUBCOMMAND} <EMAIL> <HANDLE>" >/dev/stderr 63 + exit 1 64 + fi 65 + 66 + echo "Account created for ${HANDLE}.\nYour password is below, which we'll only show you once.\n" 67 + echo "DID: ${DID}" 68 + echo "Password: ${PASSWORD}" 69 + elif [[ "${SUBCOMMAND}" == "delete" ]]; then 70 + DID="${2:-}" 71 + 72 + if [[ "${DID}" == "" ]]; then 73 + echo "ERROR: missing DID parameter." >/dev/stderr 74 + echo "Usage: $0 ${SUBCOMMAND} <DID>" >/dev/stderr 75 + exit 1 76 + fi 77 + 78 + if [[ "${DID}" != did:* ]]; then 79 + echo "ERROR: DID parameter must start with \"did:\"." >/dev/stderr 80 + echo "Usage: $0 ${SUBCOMMAND} <DID>" >/dev/stderr 81 + exit 1 82 + fi 83 + 84 + echo "This action is permanent." 85 + read -r -p "Are you sure you'd like to delete ${DID}? [y/N] " response 86 + if [[ ! "$response" =~ ^([yY][eE][sS]|[yY])$ ]]; then 87 + exit 0 88 + fi 89 + 90 + curl_cmd_post \ 91 + --user "admin:${PDS_ADMIN_PASSWORD}" \ 92 + --data "{\"did\": \"${DID}\"}" \ 93 + https://${PDS_HOSTNAME}/xrpc/com.atproto.admin.deleteAccount >/dev/null 94 + 95 + echo "${DID} deleted" 96 + elif [[ "${SUBCOMMAND}" == "takedown" ]]; then 97 + DID="${2:-}" 98 + TAKEDOWN_REF="$(date +%s)" 99 + 100 + if [[ "${DID}" == "" ]]; then 101 + echo "ERROR: missing DID parameter." >/dev/stderr 102 + echo "Usage: $0 ${SUBCOMMAND} <DID>" >/dev/stderr 103 + exit 1 104 + fi 105 + 106 + if [[ "${DID}" != did:* ]]; then 107 + echo "ERROR: DID parameter must start with \"did:\"." >/dev/stderr 108 + echo "Usage: $0 ${SUBCOMMAND} <DID>" >/dev/stderr 109 + exit 1 110 + fi 111 + 112 + PAYLOAD=$(cat <<EOF 113 + { 114 + "subject": { 115 + "\$type": "com.atproto.admin.defs#repoRef", 116 + "did": "${DID}" 117 + }, 118 + "takedown": { 119 + "applied": true, 120 + "ref": "${TAKEDOWN_REF}" 121 + } 122 + } 123 + EOF 124 + ) 125 + 126 + curl_cmd_post \ 127 + --user "admin:${PDS_ADMIN_PASSWORD}" \ 128 + --data "${PAYLOAD}" \ 129 + https://${PDS_HOSTNAME}/xrpc/com.atproto.admin.updateSubjectStatus >/dev/null 130 + 131 + echo "${DID} taken down" 132 + elif [[ "${SUBCOMMAND}" == "untakedown" ]]; then 133 + DID="${2:-}" 134 + 135 + if [[ "${DID}" == "" ]]; then 136 + echo "ERROR: missing DID parameter." >/dev/stderr 137 + echo "Usage: $0 ${SUBCOMMAND} <DID>" >/dev/stderr 138 + exit 1 139 + fi 140 + 141 + if [[ "${DID}" != did:* ]]; then 142 + echo "ERROR: DID parameter must start with \"did:\"." >/dev/stderr 143 + echo "Usage: $0 ${SUBCOMMAND} <DID>" >/dev/stderr 144 + exit 1 145 + fi 146 + 147 + PAYLOAD=$(cat <<EOF 148 + { 149 + "subject": { 150 + "\$type": "com.atproto.admin.defs#repoRef", 151 + "did": "${DID}" 152 + }, 153 + "takedown": { 154 + "applied": false 155 + } 156 + } 157 + EOF 158 + ) 159 + 160 + curl_cmd_post \ 161 + --user "admin:${PDS_ADMIN_PASSWORD}" \ 162 + --data "${PAYLOAD}" \ 163 + https://${PDS_HOSTNAME}/xrpc/com.atproto.admin.updateSubjectStatus >/dev/null 164 + 165 + echo "${DID} untaken down" 166 + else 167 + echo "Unknown subcommand "$0 ${SUBCOMMAND}"." >/dev/stderr 168 + exit 1 169 + fi
+18
pdsadmin/create-invite-code.sh
··· 1 + #!/bin/bash 2 + set -o errexit 3 + set -o nounset 4 + set -o pipefail 5 + 6 + PDS_ENV_FILE="/pds/pds.env" 7 + 8 + source "${PDS_ENV_FILE}" 9 + 10 + curl \ 11 + --fail \ 12 + --silent \ 13 + --show-error \ 14 + --request POST \ 15 + --user "admin:${PDS_ADMIN_PASSWORD}" \ 16 + --header "Content-Type: application/json" \ 17 + --data '{"useCount": 1}' \ 18 + https://${PDS_HOSTNAME}/xrpc/com.atproto.server.createInviteCode | jq --raw-output '.code'
+42
pdsadmin/help.sh
··· 1 + #!/bin/bash 2 + set -o errexit 3 + set -o nounset 4 + set -o pipefail 5 + 6 + # This script is used to display help information for the pdsadmin command. 7 + cat <<HELP 8 + pdsadmin help 9 + -- 10 + update 11 + Update to the latest PDS version. 12 + e.g. pdsadmin update 13 + 14 + account 15 + list 16 + List accounts 17 + e.g. pdsadmin account list 18 + create <EMAIL> <HANDLE> 19 + Create a new account 20 + e.g. pdsadmin account create alice@example.com alice.example.com 21 + delete <DID> 22 + Delete an account specified by DID. 23 + e.g. pdsadmin account takedown did:plc:xyz123abc456 24 + takedown <DID> 25 + Takedown an account specified by DID. 26 + e.g. pdsadmin account takedown did:plc:xyz123abc456 27 + untakedown <DID> 28 + Remove a takedown an account specified by DID. 29 + e.g. pdsadmin account takedown did:plc:xyz123abc456 30 + 31 + request-crawl [<RELAY HOST>] 32 + Request a crawl from a relay host. 33 + e.g. pdsadmin request-crawl bsky.network 34 + 35 + create-invite-code 36 + Create a new invite code. 37 + e.g. pdsadmin create-invite-code 38 + 39 + help 40 + Display this help information. 41 + 42 + HELP
+33
pdsadmin/request-crawl.sh
··· 1 + #!/bin/bash 2 + set -o errexit 3 + set -o nounset 4 + set -o pipefail 5 + 6 + PDS_ENV_FILE="/pds/pds.env" 7 + source "${PDS_ENV_FILE}" 8 + 9 + RELAY_HOSTS="${1:-}" 10 + if [[ "${RELAY_HOSTS}" == "" ]]; then 11 + RELAY_HOSTS="${PDS_CRAWLERS}" 12 + fi 13 + 14 + if [[ "${RELAY_HOSTS}" == "" ]]; then 15 + echo "ERROR: missing RELAY HOST parameter." >/dev/stderr 16 + echo "Usage: $0 <RELAY HOST>[,<RELAY HOST>,...]" >/dev/stderr 17 + exit 1 18 + fi 19 + 20 + for host in ${RELAY_HOSTS//,/ }; do 21 + echo "Requesting crawl from ${host}" 22 + curl \ 23 + --fail \ 24 + --silent \ 25 + --show-error \ 26 + --request POST \ 27 + --user "admin:${PDS_ADMIN_PASSWORD}" \ 28 + --header "Content-Type: application/json" \ 29 + --data "{\"hostname\": \"${PDS_HOSTNAME}\"}" \ 30 + https://${host}/xrpc/com.atproto.sync.requestCrawl >/dev/null 31 + done 32 + 33 + echo "done"
+41
pdsadmin/update.sh
··· 1 + #!/bin/bash 2 + set -o errexit 3 + set -o nounset 4 + set -o pipefail 5 + 6 + PDS_DATADIR="/pds" 7 + COMPOSE_FILE="${PDS_DATADIR}/compose.yaml" 8 + COMPOSE_URL="https://raw.githubusercontent.com/bluesky-social/pds/main/compose.yaml" 9 + 10 + # TODO: allow the user to specify a version to update to. 11 + TARGET_VERSION="${1:-}" 12 + 13 + COMPOSE_TEMP_FILE="${COMPOSE_FILE}.tmp" 14 + 15 + echo "* Downloading PDS compose file" 16 + curl \ 17 + --silent \ 18 + --show-error \ 19 + --fail \ 20 + --output "${COMPOSE_TEMP_FILE}" \ 21 + "${COMPOSE_URL}" 22 + 23 + if cmp -s "${COMPOSE_FILE}" "${COMPOSE_TEMP_FILE}"; then 24 + echo "PDS is already up to date" 25 + rm "${COMPOSE_TEMP_FILE}" 26 + exit 0 27 + fi 28 + 29 + echo "* Updating PDS" 30 + mv "${COMPOSE_TEMP_FILE}" "${COMPOSE_FILE}" 31 + 32 + echo "* Restarting PDS" 33 + systemctl restart pds 34 + 35 + cat <<MESSAGE 36 + PDS has been updated 37 + --------------------- 38 + Check systemd logs: journalctl --unit pds 39 + Check container logs: docker logs pds 40 + 41 + MESSAGE