## Author: Fatih Aziz ## This section of code was written by Fatih Aziz and is provided under the MIT License. #!/bin/bash echo "Generating SSH key for GitHub CICD" if [ ! -f ~/.ssh/cicd_ecdsa ]; then ssh-keygen -t ed25519 -C "dev.fortis77@gmail.com" -f ~/.ssh/cicd_ecdsa -q -N "" else echo "SSH key already exists, skipping..." fi echo "Adding cicd_ecdsa to authorized_keys" if ! grep -q "dev.fortis77@gmail.com" ~/.ssh/authorized_keys; then echo "" >> ~/.ssh/authorized_keys # adds a newline to authorized_keys file cat ~/.ssh/cicd_ecdsa.pub >> ~/.ssh/authorized_keys else echo "cicd_ecdsa already exists in authorized_keys, skipping..." fi echo "Setting up key to ssh config" if [ ! -f ~/.ssh/config ]; then touch ~/.ssh/config fi # only add if not contains Host github if ! grep -q "Host github-dev.fortis77@gmail.com" ~/.ssh/config; then echo " Host github.com HostName github.com PubkeyAuthentication yes PubkeyAcceptedKeyTypes=+ssh-rsa AddKeysToAgent yes PreferredAuthentications publickey IdentityFile ~/.ssh/cicd_ecdsa Host github-dev.fortis77@gmail.com HostName github.com PubkeyAuthentication yes PubkeyAcceptedKeyTypes=+ssh-rsa AddKeysToAgent yes PreferredAuthentications publickey IdentityFile ~/.ssh/cicd_ecdsa " >>~/.ssh/config else echo "Host github already exists, skipping..." fi echo "change file permissions" chmod 400 ~/.ssh/cicd_ecdsa chmod 400 ~/.ssh/cicd_ecdsa.pub echo "Copy this to github key to SSH_KEY:" cat ~/.ssh/cicd_ecdsa echo "Copy this to github key to SSH DEPLOY KEY:" cat ~/.ssh/cicd_ecdsa.pub echo "This server ip:" curl -sL https://ifconfig.me echo "" # commence auto adding ENV_FILENAME=".env" # default filename # Parse command-line arguments while getopts f: flag; do case "${flag}" in f) ENV_FILENAME=${OPTARG} # Set filename if '-f' flag is found ;; esac done # LOAD .ENV if [ -f "${ENV_FILENAME}" ]; then { set -o allexport source <(cat ./$ENV_FILENAME | tr -d '[:blank:]') echo "NODE_ENV=$NODE_ENV" set +o allexport } || { echo "Failed to load ${ENV_FILENAME}, check the end of line." exit 1 } fi # Parse command-line arguments while getopts o:r: flag; do case "${flag}" in f) ENV_FILENAME=${OPTARG} # Set filename if '-f' flag is found ;; o) OWNER=${OPTARG} ;; r) REPO=${OPTARG} ;; esac done function auto_add() { OWNER=$1 REPO=$2 TOKEN=$GH_TOKEN # check dependencies, # it need python, pip, and nacl if ! command -v python &>/dev/null; then # then install it, based on linux os, is it fedora, ubuntu, debian, or arch, or alpine if command -v dnf &>/dev/null; then sudo dnf install python3 python3-pip -y elif command -v apt &>/dev/null; then sudo apt install python3 python3-pip -y elif command -v pacman &>/dev/null; then sudo pacman -S python python-pip elif command -v apk &>/dev/null; then sudo apk add python3 fi fi pip install pynacl # if in the future default ssh port is not secure, change it! SSH_PORT="22" if [ -z "$MY_HOST_IP" ]; then MY_HOST_IP=$(curl -sL https://ifconfig.me) fi if [ -z "$MY_HOST_USERNAME" ]; then MY_HOST_USERNAME="ec2-user" fi if [ -z "$MY_HOST_KEY" ]; then MY_HOST_KEY=$(cat ~/.ssh/cicd_ecdsa) fi if [ -z "${HOST_IP_VARNAME}" ]; then echo "HOST_IP_VARNAME is required!" exit 1 fi if [ -z "${HOST_USERNAME_VARNAME}" ]; then echo "HOST_USERNAME_VARNAME is required!" exit 1 fi if [ -z "${HOST_KEY_VARNAME}" ]; then echo "HOST_KEY_VARNAME is required!" exit 1 fi declare ${HOST_IP_VARNAME}=$MY_HOST_IP declare ${HOST_USERNAME_VARNAME}=$MY_HOST_USERNAME declare ${HOST_KEY_VARNAME}="$MY_HOST_KEY" # declare all required keys to array, then loop it to check if its empty or not declare -a required_keys=( "OWNER" "REPO" "TOKEN" "SSH_PORT" "TELEGRAM_CHAT_ID" "TELEGRAM_BOT_TOKEN" "${HOST_IP_VARNAME}" "${HOST_USERNAME_VARNAME}" "${HOST_KEY_VARNAME}" ) for key in "${required_keys[@]}"; do if [ -z "${!key}" ]; then echo "$key is required!" exit 1 fi done # FUNCTION DECLARATIONS function update_gh_secret() { local TOKEN=$1 local OWNER=$2 local REPO=$3 local KEY_NAME=$4 local MY_SECRET=$5 read KEY_ID SECRET_KEY <<< $(get_public_key $OWNER $REPO $TOKEN) # echo "::DEBUG:: going to encrypt: $MY_SECRET" # echo "::DEBUG:: with publicKey: $SECRET_KEY" local PAYLOAD=$(encrypt_message "$MY_SECRET" $SECRET_KEY) local JSON_PAYLOAD="{\"encrypted_value\":\"${PAYLOAD}\",\"key_id\":\"${KEY_ID}\"}" RESPONSE=$(curl -s -L \ -X PUT \ -H "Accept: application/vnd.github+json" \ -H "Authorization: Bearer $TOKEN" \ -H "X-GitHub-Api-Version: 2022-11-28" \ https://api.github.com/repos/$OWNER/$REPO/actions/secrets/$KEY_NAME \ -d $JSON_PAYLOAD \ -w "\n%{http_code}") # gh api \ # --method PUT \ # -H "Accept: application/vnd.github+json" \ # -H "X-GitHub-Api-Version: 2022-11-28" \ # /repos/$OWNER/$REPO/actions/secrets/$KEY_NAME \ # -f encrypted_value=''$PAYLOAD'' \ # -f key_id=''$KEY_ID'' HTTP_STATUS=$(echo "$RESPONSE" | tail -n1) # Extract the body without the status code BODY=$(echo "$RESPONSE" | head -n-1 ) if [ $HTTP_STATUS -ge 200 ] && [ $HTTP_STATUS -lt 300 ]; then echo "Request was successful [$HTTP_STATUS]" echo "Request: $JSON_PAYLOAD" echo "Response: $BODY" else echo "Request failed with status $HTTP_STATUS" echo "Request: $JSON_PAYLOAD" echo "Error: $BODY" exit 1 # uncomment this if you want to stop the script fi } function update_gh_variable() { local TOKEN=$1 local OWNER=$2 local REPO=$3 local KEY_NAME=$4 local PAYLOAD=$5 RESPONSE=$(curl -s -L \ -X POST \ -H "Accept: application/vnd.github+json" \ -H "Authorization: Bearer $TOKEN" \ -H "X-GitHub-Api-Version: 2022-11-28" \ https://api.github.com/repos/$OWNER/$REPO/actions/variables \ -d '{"name":"'$KEY_NAME'","value":"'$PAYLOAD'"}' \ -w "\n%{http_code}") HTTP_STATUS=$(echo "$RESPONSE" | tail -n1) # Extract the body without the status code BODY=$(echo "$RESPONSE" | head -n-1 ) if [ $HTTP_STATUS -ge 200 ] && [ $HTTP_STATUS -lt 300 ]; then echo "Request was successful [$HTTP_STATUS]" echo "Request: $PAYLOAD" echo "Response: $BODY" else echo "Request failed with status $HTTP_STATUS" echo "Request: $PAYLOAD" echo "Error: $BODY" # exit 1 # uncomment this if you want to stop the script fi } function encrypt_message() { local message="$1" local publicKey="$2" # local encrypted=$(node encrypt_sodium.js "$SECRET_KEY" "$MY_SECRET") # local encrypted=$(python encrypt_sodium.py "$SECRET_KEY" "$MY_SECRET") # local encrypted=$(echo -n "$message" | base64) # text to be encrypted text=$message # encrypt by running github_cicd_encrypt.py encrypted=$(python3 github_cicd_encrypt.py.sh "$publicKey" "$text") echo "$encrypted" } function get_public_key() { local OWNER=$1 local REPO=$2 local TOKEN=$3 RESPONSE=$(curl -s -L \ -H "Accept: application/vnd.github+json" \ -H "Authorization: Bearer $TOKEN" \ -H "X-GitHub-Api-Version: 2022-11-28" \ https://api.github.com/repos/$OWNER/$REPO/actions/secrets/public-key) KEY_ID=$(echo $RESPONSE | jq -r '.key_id') SECRET_KEY=$(echo $RESPONSE | jq -r '.key') echo "$KEY_ID $SECRET_KEY" } # END OF FUNCTIONS DECLARATION # SETUP DEPLOY SERVER # PORT update_gh_secret $TOKEN $OWNER $REPO 'SSH_PORT' "$SSH_PORT" # HOST update_gh_secret $TOKEN $OWNER $REPO $HOST_IP_VARNAME "$MY_HOST_IP" update_gh_secret $TOKEN $OWNER $REPO $HOST_USERNAME_VARNAME "$MY_HOST_USERNAME" update_gh_secret $TOKEN $OWNER $REPO $HOST_KEY_VARNAME "$MY_HOST_KEY" # TELEGRAM NOTIF update_gh_secret $TOKEN $OWNER $REPO "TELEGRAM_CHAT_ID" "$TELEGRAM_CHAT_ID" update_gh_secret $TOKEN $OWNER $REPO "TELEGRAM_BOT_TOKEN" "$TELEGRAM_BOT_TOKEN" } auto_add $OWNER $REPO