#!/bin/zsh
## Bits shamelessly borrowed from Graham Pugh - https://gist.github.com/grahampugh/836547859c18fefe1dba6ba8c093accc
## Then reversed to only pull down files which either do not exist in the DP or whose md5 doesn't match
##
## This script relies on a Jamf API role/client and a local identity file of the following format:
## {"client_name":"test_for_screenshot","client_id":"a7682e67-a276-448b-83af-9c83be5e02f4","client_secret":"ubPrXqRRyc0jRLFOY9iJYGpCjHiJc1M-tRLlCFb9aWZhtqf7iC9UpQG_dO1ZkvNF","grant_type":"client_credentials"}
##
## This is most easily obtained by creating an api client, enabling it and copying the data from the popup, then pasting it into a file
##
##

usage() {
    echo "Usage: sync_jcds_local_dp.zsh --id /path/to/identity_file --jss your.jamf.server --localpath /path/to/dp/share --log /path/to/log/file"
    echo "(don't include https:// but do include the port if needed)"
}

logStatement(){
    # Function to log informational output for review
    echo "$(date) - $1" >> "$logFile"
}

## Borrowed from https://gist.github.com/lucasad/6474224
urlencode() {
    setopt localoptions extendedglob
    input=( ${(s::)1} )
    print ${(j::)input/(#b)([^A-Za-z0-9_.\!~*\'\(\)-])/%${(l:2::0:)$(([##16]#match))}}
}

getToken() {
    client_id=$(plutil -extract client_id raw "$identity_file")
    client_secret=$(plutil -extract client_secret raw "$identity_file")
    cred_type=$(plutil -extract grant_type raw "$identity_file")

    token=$(curl --silent --location --request POST "${jss_url}/api/oauth/token" \
        --header "Content-Type: application/x-www-form-urlencoded" \
        --data-urlencode "client_id=${client_id}" \
        --data-urlencode "grant_type=${cred_type}" \
        --data-urlencode "client_secret=${client_secret}" \
        | plutil -extract access_token raw -)
        # echo "$token"
}

getPackageList(){
    # list all the packages
    echo "Getting a list of packages from JCDS"
    logStatement "Getting a list of packages from JCDS"
    getToken
    http_response=$(
        curl --request GET \
            --silent \
            --header "authorization: Bearer $token" \
            --header 'Accept: application/json' \
            "$jss_url/api/v1/jcds/files" \
            --write-out "%{http_code}" \
            --output "$output_file_list"
    )
    logStatement "Package List response code:  $http_response"
    # echo "HTTP response: $http_response"
}

syncPackages(){
    if [[ $http_response -eq 200 ]]; then
        # convert the list to a plist so we can actually work with it in bash
        plutil -convert xml1 "$output_file_list"

        # count the number of items in the list
        pkg_count=$(grep -c fileName "$output_file_list")

        # loop through each item in the JSON response
        jcds_pkg=""
        jcds_pkg_md5=""  # assign empty value to avoid errors
        local_pkg=""
        local_pkg_md5=""
        echo "Looping through $pkg_count files"

        for ((i=1; i<=pkg_count; i++)); do
            jcds_pkg=$(/usr/libexec/PlistBuddy -c "Print :$i:fileName" "$output_file_list")
            jcds_pkg_md5=$(/usr/libexec/PlistBuddy -c "Print :$i:md5" "$output_file_list")
            local_pkg="${rsync_path}/${jcds_pkg}"
            if [ -f "${local_pkg}" ]; then
                local_pkg_md5=$(md5 -q "${local_pkg}")
            fi

            if [[ "$local_pkg_md5" == "$jcds_pkg_md5" ]]; then
                echo "$jcds_pkg is the same"
                logStatement "$jcds_pkg is the same"
            else
                getToken
                # urlencode package names for paces
                download_pkg=$(urlencode "$jcds_pkg")

                # retrieve the download URL from the API endpoint
                get_download_url=$(curl --request GET \
                    --silent \
                    --location \
                    --header "authorization: Bearer $token" \
                    --header 'Accept: application/json' \
                    "$jss_url/api/v1/jcds/files/${download_pkg}" )
                download_url=$(echo "$get_download_url" | plutil -extract uri raw -)
                # Get the file, please
                echo "Downloading $jcds_pkg ..."
                logStatement "Downloading $jcds_pkg ..."
                curl "${download_url}" -o "${rsync_path}/${jcds_pkg}"
            fi
        done
    fi

}


while test $# -gt 0 ; do
    case "$1" in
        -i|--id)
            shift
            identity_file="$1"
            ;;
        --localpath)
            shift
            rsync_path="$1"
            ;;
        --log)
            shift
            logFile="$1"
            ;;
        --jss)
            shift
            jss="$1"
            ;;
        *)
            usage
            exit
            ;;
    esac
    shift
done

if [[ ! "$identity_file" || ! "$rsync_path" ]]; then
    usage
    exit
fi

jss_url="https://${jss}"
output_file_list="/tmp/jcds.txt"

getPackageList

syncPackages