From bb5a1473d1bfa233cc1ba5002f6d12d2c70bf76d Mon Sep 17 00:00:00 2001 From: Lukas Schauer Date: Sat, 4 Jul 2020 21:51:32 +0200 Subject: [PATCH] merged temporary json.sh into dehydrated, fixed authorization "pending" loop --- CHANGELOG | 1 + dehydrated | 206 ++++++++++++++++++++++++++++++++++++++++++++++++++--- json.sh | 190 ------------------------------------------------ 3 files changed, 199 insertions(+), 198 deletions(-) delete mode 100644 json.sh diff --git a/CHANGELOG b/CHANGELOG index 9c4df87..6404f69 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -9,6 +9,7 @@ This file contains a log of major changes in dehydrated - Don't include keyAuthorization in challenge validation (RFC compliance) ## Changed +- Use JSON.sh to parse JSON - Use account URL instead of account ID (RFC compliance) - Dehydrated now has a new home: https://github.com/dehydrated-io/dehydrated diff --git a/dehydrated b/dehydrated index efa6827..7f3a760 100755 --- a/dehydrated +++ b/dehydrated @@ -17,8 +17,6 @@ umask 077 # paranoid umask, we're creating private keys exec 3>&- exec 4>&- -. ./json.sh - VERSION="0.6.6" # Find directory in which this script is stored by traversing all symbolic links @@ -33,6 +31,197 @@ SCRIPTDIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" BASEDIR="${SCRIPTDIR}" ORIGARGS="$@" +#!/bin/sh + +# Generate json.sh path matching string +json_path() { + if [ ! "${1}" = "-p" ]; then + printf '"%s"' "${1}" + else + printf '%s' "${2}" + fi +} + +# Get string value from json dictionary +get_json_string_value() { + local filter + filter="$(printf 's/.*\[%s\]\s*"\([^"]*\)"/\\1/p' "$(json_path "${1:-}" "${2:-}")")" + sed -n "${filter}" +} + +# Get array values from json dictionary +get_json_array_values() { + grep -E '^\['"$(json_path "${1:-}" "${2:-}")"',[0-9]*\]' | sed -e 's/\[[^\]*\]\s*//g' -e 's/^"//' -e 's/"$//' +} + +# Get sub-dictionary from json +get_json_dict_value() { + local filter + echo "$(json_path "${1:-}" "${2:-}")" + filter="$(printf 's/.*\[%s\]\s*\(.*\)/\\1/p' "$(json_path "${1:-}" "${2:-}")")" + sed -n "${filter}" | jsonsh +} + +# Get integer value from json +get_json_int_value() { + local filter + filter="$(printf 's/.*\[%s\]\s*\([^"]*\)/\\1/p' "$(json_path "${1:-}" "${2:-}")")" + sed -n "${filter}" +} + +# JSON.sh JSON-parser +# Modified from https://github.com/dominictarr/JSON.sh +# Original Copyright (c) 2011 Dominic Tarr +# Licensed under The MIT License +jsonsh() { + + throw() { + echo "$*" >&2 + exit 1 + } + + awk_egrep () { + local pattern_string=$1 + + gawk '{ + while ($0) { + start=match($0, pattern); + token=substr($0, start, RLENGTH); + print token; + $0=substr($0, start+RLENGTH); + } + }' pattern="$pattern_string" + } + + tokenize () { + local GREP + local ESCAPE + local CHAR + + if echo "test string" | egrep -ao --color=never "test" >/dev/null 2>&1 + then + GREP='egrep -ao --color=never' + else + GREP='egrep -ao' + fi + + if echo "test string" | egrep -o "test" >/dev/null 2>&1 + then + ESCAPE='(\\[^u[:cntrl:]]|\\u[0-9a-fA-F]{4})' + CHAR='[^[:cntrl:]"\\]' + else + GREP=awk_egrep + ESCAPE='(\\\\[^u[:cntrl:]]|\\u[0-9a-fA-F]{4})' + CHAR='[^[:cntrl:]"\\\\]' + fi + + local STRING="\"$CHAR*($ESCAPE$CHAR*)*\"" + local NUMBER='-?(0|[1-9][0-9]*)([.][0-9]*)?([eE][+-]?[0-9]*)?' + local KEYWORD='null|false|true' + local SPACE='[[:space:]]+' + + # Force zsh to expand $A into multiple words + local is_wordsplit_disabled=$(unsetopt 2>/dev/null | grep -c '^shwordsplit$') + if [ $is_wordsplit_disabled != 0 ]; then setopt shwordsplit; fi + $GREP "$STRING|$NUMBER|$KEYWORD|$SPACE|." | egrep -v "^$SPACE$" + if [ $is_wordsplit_disabled != 0 ]; then unsetopt shwordsplit; fi + } + + parse_array () { + local index=0 + local ary='' + read -r token + case "$token" in + ']') ;; + *) + while : + do + parse_value "$1" "$index" + index=$((index+1)) + ary="$ary""$value" + read -r token + case "$token" in + ']') break ;; + ',') ary="$ary," ;; + *) throw "EXPECTED , or ] GOT ${token:-EOF}" ;; + esac + read -r token + done + ;; + esac + value=$(printf '[%s]' "$ary") || value= + : + } + + parse_object () { + local key + local obj='' + read -r token + case "$token" in + '}') ;; + *) + while : + do + case "$token" in + '"'*'"') key=$token ;; + *) throw "EXPECTED string GOT ${token:-EOF}" ;; + esac + read -r token + case "$token" in + ':') ;; + *) throw "EXPECTED : GOT ${token:-EOF}" ;; + esac + read -r token + parse_value "$1" "$key" + obj="$obj$key:$value" + read -r token + case "$token" in + '}') break ;; + ',') obj="$obj," ;; + *) throw "EXPECTED , or } GOT ${token:-EOF}" ;; + esac + read -r token + done + ;; + esac + value=$(printf '{%s}' "$obj") || value= + : + } + + parse_value () { + local jpath="${1:+$1,}${2:-}" isleaf=0 isempty=0 print=0 + case "$token" in + '{') parse_object "$jpath" ;; + '[') parse_array "$jpath" ;; + # At this point, the only valid single-character tokens are digits. + ''|[!0-9]) throw "EXPECTED value GOT ${token:-EOF}" ;; + *) value=$token + # replace solidus ("\/") in json strings with normalized value: "/" + value=$(echo "$value" | sed 's#\\/#/#g') + isleaf=1 + [ "$value" = '""' ] && isempty=1 + ;; + esac + [ "$value" = '' ] && return + [ -z "$jpath" ] && return # do not print head + + printf "[%s]\t%s\n" "$jpath" "$value" + : + } + + parse () { + read -r token + parse_value + read -r token + case "$token" in + '') ;; + *) throw "EXPECTED EOF GOT $token" ;; + esac + } + + tokenize | parse +} + # Create (identifiable) temporary files _mktemp() { # shellcheck disable=SC2068 @@ -300,8 +489,7 @@ init_system() { fi # Get CA URLs - CA_DIRECTORY_RAW="$(http_request get "${CA}")" - CA_DIRECTORY="$(printf "%s" "${CA_DIRECTORY_RAW}" | jsonsh)" + CA_DIRECTORY="$(http_request get "${CA}" | jsonsh)" # Automatic discovery of API version if [[ "${API}" = "auto" ]]; then @@ -696,7 +884,7 @@ sign_csr() { if [[ "${API}" -eq 2 ]]; then # Receive authorization ($authorization is authz uri) response="$(signed_request "$(echo "${authorization}" | _sed -e 's/\"(.*)".*/\1/')" "" | jsonsh)" - identifier="$(echo "${response}" | get_json_dict_value identifier | get_json_string_value value)" + identifier="$(echo "${response}" | get_json_string_value -p '"identifier","value"')" echo " + Handling authorization for ${identifier}" else # Request new authorization ($authorization is altname) @@ -790,9 +978,9 @@ sign_csr() { while [[ "${reqstatus}" = "pending" ]]; do sleep 1 if [[ "${API}" -eq 2 ]]; then - result="$(signed_request "${challenge_uris[${idx}]}" "")" + result="$(signed_request "${challenge_uris[${idx}]}" "" | jsonsh)" else - result="$(http_request get "${challenge_uris[${idx}]}")" + result="$(http_request get "${challenge_uris[${idx}]}" | jsonsh)" fi reqstatus="$(echo "${result}" | get_json_string_value status)" done @@ -856,7 +1044,7 @@ sign_csr() { _exiterr "Order in status ${status}" ;; esac - result="$(signed_request "${order_location}" "" | clean_json)" + result="$(signed_request "${order_location}" "" | jsonsh)" done certificate="$(echo "${result}" | get_json_string_value certificate)" crt="$(signed_request "${certificate}" "")" @@ -1798,3 +1986,5 @@ if [[ ! "${DEHYDRATED_NOOP:-}" = "NOOP" ]]; then # Run script main "${@:-}" fi + +# vi: expandtab sw=2 ts=2 diff --git a/json.sh b/json.sh deleted file mode 100644 index 84ce9d2..0000000 --- a/json.sh +++ /dev/null @@ -1,190 +0,0 @@ -#!/bin/sh - -# Generate json.sh path matching string -json_path() { - if [ ! "${1}" = "-p" ]; then - printf '"%s"' "${1}" - else - printf '%s' "${2}" - fi -} - -# Get string value from json dictionary -get_json_string_value() { - local filter - filter="$(printf 's/.*\[%s\]\s*"\([^"]*\)"/\\1/p' "$(json_path "${1:-}" "${2:-}")")" - sed -n "${filter}" -} - -# Get array values from json dictionary -get_json_array_values() { - grep -E '^\["'"$1"'",[0-9]*\]' | sed -e 's/\[[^\]*\]\s*//g' -e 's/^"//' -e 's/"$//' -} - -# Get sub-dictionary from json -get_json_dict_value() { - local filter - echo "$(json_path "${1:-}" "${2:-}")" - filter="$(printf 's/.*\[%s\]\s*\(.*\)/\\1/p' "$(json_path "${1:-}" "${2:-}")")" - sed -n "${filter}" | jsonsh -} - -# Get integer value from json -get_json_int_value() { - local filter - filter="$(printf 's/.*\[%s\]\s*\([^"]*\)/\\1/p' "$(json_path "${1:-}" "${2:-}")")" - sed -n "${filter}" -} - -jsonsh() { - # Modified from https://github.com/dominictarr/JSON.sh - # Original Copyright (c) 2011 Dominic Tarr - # Licensed under The MIT License - - throw() { - echo "$*" >&2 - exit 1 - } - - awk_egrep () { - local pattern_string=$1 - - gawk '{ - while ($0) { - start=match($0, pattern); - token=substr($0, start, RLENGTH); - print token; - $0=substr($0, start+RLENGTH); - } - }' pattern="$pattern_string" - } - - tokenize () { - local GREP - local ESCAPE - local CHAR - - if echo "test string" | egrep -ao --color=never "test" >/dev/null 2>&1 - then - GREP='egrep -ao --color=never' - else - GREP='egrep -ao' - fi - - if echo "test string" | egrep -o "test" >/dev/null 2>&1 - then - ESCAPE='(\\[^u[:cntrl:]]|\\u[0-9a-fA-F]{4})' - CHAR='[^[:cntrl:]"\\]' - else - GREP=awk_egrep - ESCAPE='(\\\\[^u[:cntrl:]]|\\u[0-9a-fA-F]{4})' - CHAR='[^[:cntrl:]"\\\\]' - fi - - local STRING="\"$CHAR*($ESCAPE$CHAR*)*\"" - local NUMBER='-?(0|[1-9][0-9]*)([.][0-9]*)?([eE][+-]?[0-9]*)?' - local KEYWORD='null|false|true' - local SPACE='[[:space:]]+' - - # Force zsh to expand $A into multiple words - local is_wordsplit_disabled=$(unsetopt 2>/dev/null | grep -c '^shwordsplit$') - if [ $is_wordsplit_disabled != 0 ]; then setopt shwordsplit; fi - $GREP "$STRING|$NUMBER|$KEYWORD|$SPACE|." | egrep -v "^$SPACE$" - if [ $is_wordsplit_disabled != 0 ]; then unsetopt shwordsplit; fi - } - - parse_array () { - local index=0 - local ary='' - read -r token - case "$token" in - ']') ;; - *) - while : - do - parse_value "$1" "$index" - index=$((index+1)) - ary="$ary""$value" - read -r token - case "$token" in - ']') break ;; - ',') ary="$ary," ;; - *) throw "EXPECTED , or ] GOT ${token:-EOF}" ;; - esac - read -r token - done - ;; - esac - value=$(printf '[%s]' "$ary") || value= - : - } - - parse_object () { - local key - local obj='' - read -r token - case "$token" in - '}') ;; - *) - while : - do - case "$token" in - '"'*'"') key=$token ;; - *) throw "EXPECTED string GOT ${token:-EOF}" ;; - esac - read -r token - case "$token" in - ':') ;; - *) throw "EXPECTED : GOT ${token:-EOF}" ;; - esac - read -r token - parse_value "$1" "$key" - obj="$obj$key:$value" - read -r token - case "$token" in - '}') break ;; - ',') obj="$obj," ;; - *) throw "EXPECTED , or } GOT ${token:-EOF}" ;; - esac - read -r token - done - ;; - esac - value=$(printf '{%s}' "$obj") || value= - : - } - - parse_value () { - local jpath="${1:+$1,}${2:-}" isleaf=0 isempty=0 print=0 - case "$token" in - '{') parse_object "$jpath" ;; - '[') parse_array "$jpath" ;; - # At this point, the only valid single-character tokens are digits. - ''|[!0-9]) throw "EXPECTED value GOT ${token:-EOF}" ;; - *) value=$token - # replace solidus ("\/") in json strings with normalized value: "/" - value=$(echo "$value" | sed 's#\\/#/#g') - isleaf=1 - [ "$value" = '""' ] && isempty=1 - ;; - esac - [ "$value" = '' ] && return - [ -z "$jpath" ] && return # do not print head - - printf "[%s]\t%s\n" "$jpath" "$value" - : - } - - parse () { - read -r token - parse_value - read -r token - case "$token" in - '') ;; - *) throw "EXPECTED EOF GOT $token" ;; - esac - } - - tokenize | parse -} -# vi: expandtab sw=2 ts=2 -- 2.47.2