#!/bin/bash # Porkbun API docs # https://porkbun.com/api/json/v3/documentation # SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) # Environment file with API_KEY and SECRET_KEY ENV_FILE="$SCRIPT_DIR/.env" VERSION="0.4.0" # Porkbun API base url BASE_URL=https://api.porkbun.com/api/json/v3 # Porkbun ipv4 API base url BASE_URL_IPV4=https://api-ipv4.porkbun.com/api/json/v3 # Parameter values PARAM_HELP="--help" PARAM_HELP_SHORT="-h" PARAM_DOMAIN="--domain" PARAM_DOMAIN_SHORT="-d" PARAM_NAME="--name" PARAM_NAME_SHORT="-n" PARAM_TYPE="--type" PARAM_TYPE_SHORT="-t" PARAM_CONTENT="--content" PARAM_CONTENT_SHORT="-c" PARAM_TTL="--ttl" PARAM_TTL_SHORT="-l" PARAM_PRIORITY="--priority" PARAM_PRIORITY_SHORT="-p" PARAM_ID="--id" PARAM_ID_SHORT="-i" PARAM_START="--start" PARAM_START_SHORT="-s" ################################################### # # # HELPERS # # # ################################################### # region: helpers function load_env { if [[ ! -f "$ENV_FILE" ]]; then echo "Missing configuration file, starting configuration phase" echo read -p "Porkbun API key: " API_KEY read -sp "Porkbun Secret key: " SECRET_KEY echo echo echo "Checking valid keys" PING_STATUS=$(ping | jq -r .status) echo echo $PING_STATUS if [[ "$PING_STATUS" != "SUCCESS" ]]; then echo "API keys are not valid" exit 1 fi echo "Keys are valid, saving credentials in $ENV_FILE" create_env_file $API_KEY $SECRET_KEY echo echo "Credentials saved!" echo echo "The script is ready for use" exit 0 fi source "$ENV_FILE" check_env } function create_env_file { cat > "$ENV_FILE" << EOL # Porkbun API key API_KEY=$1 # Porkbun SECRET API key SECRET_KEY=$2 EOL chmod 600 $ENV_FILE } function check_env { if [[ -z $API_KEY ]]; then echo "Missing API_KEY" exit 1 fi if [[ -z $SECRET_KEY ]]; then echo "Missing SECRET_KEY" exit 1 fi } function base_json_payload { echo " \"secretapikey\": \"$SECRET_KEY\", \"apikey\": \"$API_KEY\" " } function request { URL=$1 PAYLOAD=$2 DATA="{$(base_json_payload)" if [[ ! -z $PAYLOAD ]]; then DATA="$DATA, $PAYLOAD" fi DATA="$DATA}" echo $( curl -s \ --request POST \ --url "$URL" \ --header 'Content-Type: application/json' \ --data "$DATA" ) } function handle_show_help_on_error { COMMAND=$1 COMMAND_HELP="${COMMAND}_help" shift SHOW_HELP=0 for ARG in $@; do case $ARG in $PARAM_HELP_SHORT|$PARAM_HELP) SHOW_HELP=1 ;; esac done if [[ $SHOW_HELP -ne 0 ]]; then eval $COMMAND_HELP exit 0 fi OUTPUT=$($COMMAND $@) if [[ $? -ne 0 ]]; then if [[ ! -z $OUTPUT ]]; then echo $OUTPUT echo fi eval $COMMAND_HELP exit 1 fi echo $OUTPUT | jq . } # endregion ################################################### # # # GENERAL # # # ################################################### # region: general HANDLE_PING="ping" function ping { echo $(request "$BASE_URL/ping") } HANDLE_PING_IPV4="ping-ipv4" function ping_ipv4 { echo $(request "$BASE_URL_IPV4/ping") } # endregion ################################################### # # # DOMAIN # # # ################################################### # region: domain HANDLE_DOMAIN="domain" function handle_domain { case $1 in $PARAM_HELP_SHORT|$PARAM_HELP) handle_domain_help ;; $DOMAIN_LIST_ALL) shift handle_show_help_on_error handle_domain_list_all $@ ;; *) handle_domain_help exit 1 ;; esac } function handle_domain_help { echo "Usage: $0 $HANDLE_DOMAIN " echo echo "Commands:" echo " $DOMAIN_LIST_ALL List all domain names in account" } DOMAIN_LIST_ALL="list" function handle_domain_list_all { while [[ $# -gt 0 ]]; do case $1 in $PARAM_START_SHORT|$PARAM_START) START="$2" shift shift ;; -*|--*) echo "Unknown option $1" exit 1 ;; *) shift ;; esac done PAYLOAD="" if [[ ! -z $START ]]; then PAYLOAD=" \"start\": \"$START\" " fi echo $(request "$BASE_URL/domain/listAll" "$PAYLOAD") } function handle_domain_list_all_help { echo "Usage: $0 $HANDLE_DOMAIN $DOMAIN_LIST_ALL [OPTIONS]" echo echo "Options:" echo " $PARAM_START_SHORT, $PARAM_START (optional)" echo " An index to start at when retrieving the domains, defaults to 0. To get all domains increment by 1000 until you receive an empty array." } # endregion ################################################### # # # DNS # # # ################################################### # region: dns HANDLE_DNS="dns" function handle_dns { case $1 in $PARAM_HELP_SHORT|$PARAM_HELP) handle_dns_help ;; $HANDLE_DNS_EDIT) shift handle_dns_edit $@ ;; $DNS_CREATE_RECORD) shift handle_show_help_on_error dns_create_record $@ ;; $HANDLE_DNS_DELETE) shift handle_dns_delete $@ ;; $HANDLE_DNS_LIST) shift handle_dns_list $@ ;; *) handle_dns_help exit 1 ;; esac } function handle_dns_help { echo "Usage: $0 $HANDLE_DNS " echo echo "Commands:" echo " $DNS_CREATE_RECORD Create a DNS record" echo " $HANDLE_DNS_EDIT Edit DNS record(s)" echo " $HANDLE_DNS_DELETE Delete a DNS record" echo " $HANDLE_DNS_LIST List DNS record(s)" } HANDLE_DNS_EDIT="edit" function handle_dns_edit { case $1 in $PARAM_HELP_SHORT|$PARAM_HELP) handle_dns_edit_help ;; $DNS_EDIT_RECORD) shift handle_show_help_on_error dns_edit_record $@ ;; $DNS_EDIT_RECORDS) shift handle_show_help_on_error dns_edit_records $@ ;; *) handle_dns_edit_help exit 1 ;; esac } function handle_dns_edit_help { echo "Usage: $0 $HANDLE_DNS $HANDLE_DNS_EDIT " echo echo "Commands:" echo " $DNS_EDIT_RECORD Edit a DNS record by Domain and ID" echo " $DNS_EDIT_RECORDS Edit DNS records by Domain, Subdomain, and Type" } DNS_EDIT_RECORD="record" function dns_edit_record { while [[ $# -gt 0 ]]; do case $1 in $PARAM_DOMAIN_SHORT|$PARAM_DOMAIN) DOMAIN="$2" shift shift ;; $PARAM_ID_SHORT|$PARAM_ID) ID="$2" shift shift ;; $PARAM_NAME_SHORT|$PARAM_NAME) NAME="$2" shift shift ;; $PARAM_TYPE_SHORT|$PARAM_TYPE) TYPE="$2" shift shift ;; $PARAM_CONTENT_SHORT|$PARAM_CONTENT) CONTENT="$2" shift shift ;; $PARAM_TTL_SHORT|$PARAM_TTL) TTL="$2" shift shift ;; $PARAM_PRIORITY_SHORT|$PARAM_PRIORITY) PRIORITY="$2" shift shift ;; -*|--*) echo "Unknown option $1" exit 1 ;; *) shift ;; esac done if [[ -z $DOMAIN || -z $ID || -z $TYPE || -z $CONTENT ]]; then echo "Missing domain, id, type, or content parameters" exit 1 fi PAYLOAD=" \"type\": \"$TYPE\", \"content\": \"$CONTENT\" " if [[ ! -z $NAME ]]; then PAYLOAD=" $PAYLOAD, \"name\": \"$NAME\" " fi if [[ ! -z $TTL ]]; then PAYLOAD=" $PAYLOAD, \"ttl\": \"$TTL\" " fi if [[ ! -z $PRIORITY ]]; then PAYLOAD=" $PAYLOAD, \"prio\": \"$PRIORITY\" " fi echo $(request "$BASE_URL/dns/edit/$DOMAIN/$ID" "$PAYLOAD") } function dns_edit_record_help { echo "Usage: $0 $HANDLE_DNS $HANDLE_DNS_EDIT $DNS_EDIT_RECORD [OPTIONS]" echo echo "Options:" echo " $PARAM_DOMAIN_SHORT, $PARAM_DOMAIN" echo " The domain for the record being created." echo " $PARAM_ID_SHORT, $PARAM_ID" echo " The ID of the record." echo " $PARAM_NAME_SHORT, $PARAM_NAME (optional)" echo " The subdomain for the record being created, not including the domain itself. Leave blank to create a record on the root domain. Use * to create a wildcard record." echo " $PARAM_TYPE_SHORT, $PARAM_TYPE" echo " The type of record being created. Valid types are: A, MX, CNAME, ALIAS, TXT, NS, AAAA, SRV, TLSA, CAA" echo " $PARAM_CONTENT_SHORT, $PARAM_CONTENT" echo " The answer content for the record. Please see the DNS management popup from the domain management console for proper formatting of each record type." echo " $PARAM_TTL_SHORT, $PARAM_TTL (optional)" echo " The time to live in seconds for the record. The minimum and the default is 600 seconds." echo " $PARAM_PRIORITY_SHORT, $PARAM_PRIORITY (optional)" echo " The priority of the record for those that support it." } DNS_EDIT_RECORDS="records" function dns_edit_records { while [[ $# -gt 0 ]]; do case $1 in $PARAM_DOMAIN_SHORT|$PARAM_DOMAIN) DOMAIN="$2" shift shift ;; $PARAM_TYPE_SHORT|$PARAM_TYPE) TYPE="$2" shift shift ;; $PARAM_NAME_SHORT|$PARAM_NAME) NAME="$2" shift shift ;; $PARAM_CONTENT_SHORT|$PARAM_CONTENT) CONTENT="$2" shift shift ;; $PARAM_TTL_SHORT|$PARAM_TTL) TTL="$2" shift shift ;; $PARAM_PRIORITY_SHORT|$PARAM_PRIORITY) PRIORITY="$2" shift shift ;; -*|--*) echo "Unknown option $1" exit 1 ;; *) shift ;; esac done if [[ -z $DOMAIN || -z $TYPE || -z $CONTENT ]]; then echo "Missing domain, type, or content parameters" exit 1 fi URL="$BASE_URL/dns/editByNameType/$DOMAIN/$TYPE" PAYLOAD=" \"content\": \"$CONTENT\" " if [[ ! -z $NAME ]]; then URL="$URL/$NAME" fi if [[ ! -z $TTL ]]; then PAYLOAD=" $PAYLOAD, \"ttl\": \"$TTL\" " fi if [[ ! -z $PRIORITY ]]; then PAYLOAD=" $PAYLOAD, \"prio\": \"$PRIORITY\" " fi echo $(request "$URL" "$PAYLOAD") } function dns_edit_records_help { echo "Usage: $0 $HANDLE_DNS $HANDLE_DNS_EDIT $DNS_EDIT_RECORDS [OPTIONS]" echo echo "Options:" echo " $PARAM_DOMAIN_SHORT, $PARAM_DOMAIN" echo " The domain for the record being created." echo " $PARAM_TYPE_SHORT, $PARAM_TYPE" echo " The type of record being created. Valid types are: A, MX, CNAME, ALIAS, TXT, NS, AAAA, SRV, TLSA, CAA" echo " $PARAM_NAME_SHORT, $PARAM_NAME (optional)" echo " The subdomain for the record being created, not including the domain itself. Leave blank to create a record on the root domain. Use * to create a wildcard record." echo " $PARAM_CONTENT_SHORT, $PARAM_CONTENT" echo " The answer content for the record. Please see the DNS management popup from the domain management console for proper formatting of each record type." echo " $PARAM_TTL_SHORT, $PARAM_TTL (optional)" echo " The time to live in seconds for the record. The minimum and the default is 600 seconds." echo " $PARAM_PRIORITY_SHORT, $PARAM_PRIORITY (optional)" echo " The priority of the record for those that support it." } DNS_CREATE_RECORD="create" function dns_create_record { while [[ $# -gt 0 ]]; do case $1 in $PARAM_DOMAIN_SHORT|$PARAM_DOMAIN) DOMAIN="$2" shift shift ;; $PARAM_NAME_SHORT|$PARAM_NAME) NAME="$2" shift shift ;; $PARAM_TYPE_SHORT|$PARAM_TYPE) TYPE="$2" shift shift ;; $PARAM_CONTENT_SHORT|$PARAM_CONTENT) CONTENT="$2" shift shift ;; $PARAM_TTL_SHORT|$PARAM_TTL) TTL="$2" shift shift ;; $PARAM_PRIORITY_SHORT|$PARAM_PRIORITY) PRIORITY="$2" shift shift ;; -*|--*) echo "Unknown option $1" exit 1 ;; *) shift ;; esac done if [[ -z $DOMAIN || -z $TYPE || -z $CONTENT ]]; then echo "Missing domain, type, or content parameters" exit 1 fi PAYLOAD=" \"type\": \"$TYPE\", \"content\": \"$CONTENT\" " if [[ ! -z $NAME ]]; then PAYLOAD=" $PAYLOAD, \"name\": \"$NAME\" " fi if [[ ! -z $TTL ]]; then PAYLOAD=" $PAYLOAD, \"ttl\": \"$TTL\" " fi if [[ ! -z $PRIORITY ]]; then PAYLOAD=" $PAYLOAD, \"prio\": \"$PRIORITY\" " fi echo $(request "$BASE_URL/dns/create/$DOMAIN" "$PAYLOAD") } function dns_create_record_help { echo "Usage: $0 $HANDLE_DNS $DNS_CREATE_RECORD [OPTIONS]" echo echo "Options:" echo " $PARAM_DOMAIN_SHORT, $PARAM_DOMAIN" echo " The domain for the record being created." echo " $PARAM_NAME_SHORT, $PARAM_NAME (optional)" echo " The subdomain for the record being created, not including the domain itself. Leave blank to create a record on the root domain. Use * to create a wildcard record." echo " $PARAM_TYPE_SHORT, $PARAM_TYPE" echo " The type of record being created. Valid types are: A, MX, CNAME, ALIAS, TXT, NS, AAAA, SRV, TLSA, CAA" echo " $PARAM_CONTENT_SHORT, $PARAM_CONTENT" echo " The answer content for the record. Please see the DNS management popup from the domain management console for proper formatting of each record type." echo " $PARAM_TTL_SHORT, $PARAM_TTL (optional)" echo " The time to live in seconds for the record. The minimum and the default is 600 seconds." echo " $PARAM_PRIORITY_SHORT, $PARAM_PRIORITY (optional)" echo " The priority of the record for those that support it." } HANDLE_DNS_DELETE="delete" function handle_dns_delete { case $1 in $PARAM_HELP_SHORT|$PARAM_HELP) handle_dns_delete_help ;; $DNS_DELETE_RECORD) shift handle_show_help_on_error dns_delete_record $@ ;; $DNS_DELETE_RECORDS) shift handle_show_help_on_error dns_delete_records $@ ;; *) handle_dns_delete_help exit 1 ;; esac } function handle_dns_delete_help { echo "Usage: $0 $HANDLE_DNS $HANDLE_DNS_DELETE " echo echo "Commands:" echo " $DNS_DELETE_RECORD Delete a DNS record by Domain and ID" echo " $DNS_DELETE_RECORDS Delete DNS records by Domain, Subdomain, and Type" } DNS_DELETE_RECORD="record" function dns_delete_record { while [[ $# -gt 0 ]]; do case $1 in $PARAM_DOMAIN_SHORT|$PARAM_DOMAIN) DOMAIN="$2" shift shift ;; $PARAM_ID_SHORT|$PARAM_ID) ID="$2" shift shift ;; -*|--*) echo "Unknown option $1" exit 1 shift shift ;; *) shift ;; esac done if [[ -z $DOMAIN || -z $ID ]]; then echo "Missing domain or record id parameters" exit 1 fi echo $(request "$BASE_URL/dns/delete/$DOMAIN/$ID") } function dns_delete_record_help { echo "Usage: $0 $HANDLE_DNS $DNS_DELETE_RECORD [OPTIONS]" echo echo "Options:" echo " $PARAM_DOMAIN_SHORT, $PARAM_DOMAIN" echo " The domain of the record being deleted." echo " $PARAM_ID_SHORT, $PARAM_ID" echo " The record id being deleted." } DNS_DELETE_RECORDS="records" function dns_delete_records { while [[ $# -gt 0 ]]; do case $1 in $PARAM_DOMAIN_SHORT|$PARAM_DOMAIN) DOMAIN="$2" shift shift ;; $PARAM_TYPE_SHORT|$PARAM_TYPE) TYPE="$2" shift shift ;; $PARAM_NAME_SHORT|$PARAM_NAME) NAME="$2" shift shift ;; -*|--*) echo "Unknown option $1" exit 1 ;; *) shift ;; esac done if [[ -z $DOMAIN || -z $TYPE ]]; then echo "Missing domain or type parameters" exit 1 fi URL="$BASE_URL/dns/deleteByNameType/$DOMAIN/$TYPE" PAYLOAD="" if [[ ! -z $NAME ]]; then URL="$URL/$NAME" fi echo $(request "$URL" "$PAYLOAD") } function dns_delete_records_help { echo "Usage: $0 $HANDLE_DNS $HANDLE_DNS_EDIT $DNS_EDIT_RECORDS [OPTIONS]" echo echo "Options:" echo " $PARAM_DOMAIN_SHORT, $PARAM_DOMAIN" echo " The domain of the record being deleted." echo " $PARAM_TYPE_SHORT, $PARAM_TYPE" echo " The type of record being deleted. Valid types are: A, MX, CNAME, ALIAS, TXT, NS, AAAA, SRV, TLSA, CAA" echo " $PARAM_NAME_SHORT, $PARAM_NAME (optional)" echo " The subdomain of the record being deleted." } HANDLE_DNS_LIST="list" function handle_dns_list { case $1 in $PARAM_HELP_SHORT|$PARAM_HELP) handle_dns_list_help ;; $DNS_LIST_RECORD) shift handle_show_help_on_error dns_list_record $@ ;; $DNS_LIST_RECORDS) shift handle_show_help_on_error dns_list_records $@ ;; *) handle_dns_list_help exit 1 ;; esac } function handle_dns_list_help { echo "Usage: $0 $HANDLE_DNS $HANDLE_DNS_LIST " echo echo "Commands:" echo " $DNS_LIST_RECORD List a DNS record by Domain and ID" echo " $DNS_LIST_RECORDS List DNS records by Domain, Subdomain, and Type" } DNS_LIST_RECORD="record" function dns_list_record { while [[ $# -gt 0 ]]; do case $1 in $PARAM_DOMAIN_SHORT|$PARAM_DOMAIN) DOMAIN="$2" shift shift ;; $PARAM_ID_SHORT|$PARAM_ID) ID="$2" shift shift ;; -*|--*) echo "Unknown option $1" exit 1 shift shift ;; *) shift ;; esac done if [[ -z $DOMAIN ]]; then echo "Missing domain parameter" exit 1 fi URL="$BASE_URL/dns/retrieve/$DOMAIN" PAYLOAD="" if [[ ! -z $ID ]]; then URL="$URL/$ID" fi echo $(request "$URL" "$PAYLOAD") } function dns_list_record_help { echo "Usage: $0 $HANDLE_DNS $HANDLE_DNS_LIST $DNS_LIST_RECORD [OPTIONS]" echo echo "Options:" echo " $PARAM_DOMAIN_SHORT, $PARAM_DOMAIN" echo " The domain to list records from." echo " $PARAM_ID_SHORT, $PARAM_ID (optional)" echo " The ID of the record." } DNS_LIST_RECORDS="records" function dns_list_records { while [[ $# -gt 0 ]]; do case $1 in $PARAM_DOMAIN_SHORT|$PARAM_DOMAIN) DOMAIN="$2" shift shift ;; $PARAM_TYPE_SHORT|$PARAM_TYPE) TYPE="$2" shift shift ;; $PARAM_NAME_SHORT|$PARAM_NAME) NAME="$2" shift shift ;; -*|--*) echo "Unknown option $1" exit 1 ;; *) shift ;; esac done if [[ -z $DOMAIN || -z $TYPE ]]; then echo "Missing domain or type parameters" exit 1 fi URL="$BASE_URL/dns/retrieveByNameType/$DOMAIN/$TYPE" PAYLOAD="" if [[ ! -z $NAME ]]; then URL="$URL/$NAME" fi echo $(request "$URL" "$PAYLOAD") } function dns_list_records_help { echo "Usage: $0 $HANDLE_DNS $HANDLE_DNS_LIST $DNS_LIST_RECORDS [OPTIONS]" echo echo "Options:" echo " $PARAM_DOMAIN_SHORT, $PARAM_DOMAIN" echo " The domain of the records being listed." echo " $PARAM_TYPE_SHORT, $PARAM_TYPE" echo " The type of record being listed. Valid types are: A, MX, CNAME, ALIAS, TXT, NS, AAAA, SRV, TLSA, CAA" echo " $PARAM_NAME_SHORT, $PARAM_NAME (optional)" echo " The subdomain of the record being listed, not including the domain itself." } # endregion ################################################### # # # MAIN # # # ################################################### # region: main function handle { case $1 in $PARAM_HELP_SHORT|$PARAM_HELP) handle_help ;; $HANDLE_PING) handle_show_help_on_error ping ;; $HANDLE_PING_IPV4) handle_show_help_on_error ping_ipv4 ;; $HANDLE_DOMAIN) shift handle_domain $@ ;; $HANDLE_DNS) shift handle_dns $@ ;; *) handle_help exit 1 ;; esac } function handle_help { echo "Usage: $0 [ARGUMENTS]" echo echo "Commands:" echo " $HANDLE_PING Test communication with the API, also returns the IP address." echo " $HANDLE_PING_IPV4 Test communication with the API, also returns the IP address in IPv4 format." echo " $HANDLE_DOMAIN Manage account Domains" echo " $HANDLE_DNS Manage DNS records" echo echo "Arguments:" echo " $PARAM_HELP_SHORT, $PARAM_HELP" echo " Show command help." echo echo "Version: v$VERSION" } load_env if [[ $? -ne 0 ]]; then exit 1 fi handle $@ # endregion