From 6fdff40f930a028d78c1dbe168f0189eb868cfa1 Mon Sep 17 00:00:00 2001 From: sdomi Date: Wed, 5 Mar 2025 22:23:44 +0100 Subject: [PATCH 1/4] template: clean the uri_list on function exit --- src/template.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/template.sh b/src/template.sh index dd3cb97..8a3950f 100755 --- a/src/template.sh +++ b/src/template.sh @@ -99,6 +99,8 @@ function render() { tr '\n' $'\01' <<< "$template" | sed -E -f "$tmp" | tr $'\01' '\n' rm "$tmp" fi + + [[ "$3" != true ]] && _template_uri_list=() } _template_uri_list=() From 94b65db0e7b0ef4c9d99bc6d7dcc7ab406ad2471 Mon Sep 17 00:00:00 2001 From: sdomi Date: Thu, 6 Mar 2025 00:33:18 +0100 Subject: [PATCH 2/4] template: add datestamp rendering mode --- .resources/primary_config.sh | 2 ++ src/template.sh | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/.resources/primary_config.sh b/.resources/primary_config.sh index 9f0d1d9..bb428dd 100644 --- a/.resources/primary_config.sh +++ b/.resources/primary_config.sh @@ -46,3 +46,5 @@ cfg[cookie_path]="/" cfg[register_should_login]=true cfg[websocket_enable]=false + +cfg[template_date_format]='%Y-%m-%d %H:%M:%S' diff --git a/src/template.sh b/src/template.sh index 8a3950f..bbb76d9 100755 --- a/src/template.sh +++ b/src/template.sh @@ -36,6 +36,16 @@ function render() { elif [[ "$key" == "@"* && "${ref["$key"]}" != '' ]]; then local value="$(tr -d $'\01\02' <<< "${ref["$key"]}" | sed -E 's/\&/�UwU�/g')" echo 's'$'\02''\{\{\'"$key"'\}\}'$'\02'''"$value"''$'\02''g;' >> "$tmp" #' + elif [[ "$key" == "+"* ]]; then # date mode + if [[ ! "${ref["$key"]}" ]]; then + # special case: if the date is empty, + # make the output empty too + echo 's'$'\02''\{\{\'"$key"'\}\}'$'\02\02''g;' >> "$tmp" #' + else + local value + printf -v value "%(${cfg[template_date_format]})T" "${ref["$key"]}" + echo 's'$'\02''\{\{\'"$key"'\}\}'$'\02'''"$value"''$'\02''g;' >> "$tmp" #' + fi elif [[ "$key" == '?'* ]]; then local _key="\\?${key/?/}" From c5c7cda07c370f06ebdc65abf6686f54ddff13c5 Mon Sep 17 00:00:00 2001 From: sdomi Date: Thu, 6 Mar 2025 01:33:04 +0100 Subject: [PATCH 3/4] tests: add template datestamp tests --- tests/02-template.sh | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/tests/02-template.sh b/tests/02-template.sh index 55be91f..a87a9fa 100644 --- a/tests/02-template.sh +++ b/tests/02-template.sh @@ -1,7 +1,7 @@ #!/bin/bash tpl_basic() { - prepare() { + prepare() { source src/misc.sh source src/template.sh } @@ -26,8 +26,37 @@ tpl_basic_newline() { match="value: $(html_encode "$value")" } +tpl_date() { + tst() { + declare -A cfg + cfg[template_date_format]='%Y-%m-%d %H:%M:%S' + + declare -A meow + meow[+asdf]="$value" + + render meow <(echo "value: {{+asdf}}") + } + + value="1337" + match="value: 1970-01-01 01:22:17" +} + +tpl_date_empty() { + value="" + match="value: " +} + +tpl_date_invalid() { + value="gadjkghfdklh" + match="value: 1970-01-01 01:00:00" +} + subtest_list=( tpl_basic tpl_basic_specialchars tpl_basic_newline + + tpl_date + tpl_date_empty + tpl_date_invalid ) From 0673c0f644e0eeefc2d89648528286fdda27977a Mon Sep 17 00:00:00 2001 From: sdomi Date: Thu, 6 Mar 2025 01:34:20 +0100 Subject: [PATCH 4/4] template: migrate from raw hex digits to replacement variables First of a few commits intending to clean up the template engine. Fully moved from $'\01' / $'\02' control chars onto... the same, but in variables. It should be somewhat more readable now. Future work will include removing all of the unnecessary quotes, and a general refactor aiming to remove at least some temporary file writes. --- src/template.sh | 46 ++++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/src/template.sh b/src/template.sh index bbb76d9..9ab870b 100755 --- a/src/template.sh +++ b/src/template.sh @@ -1,13 +1,15 @@ #!/usr/bin/env bash # template.sh - basic templating engine +_tpl_newline=$'\01' +_tpl_ctrl=$'\02' # nightmare fuel # render(array, template_file, recurse) function render() { if [[ "$3" != true ]]; then - local template="$(tr -d $'\01'$'\02' < "$2" | sed 's/\&/�UwU�/g')" + local template="$(tr -d ${_tpl_newline}${_tpl_ctrl} < "$2" | sed 's/\&/�UwU�/g')" else - local template="$(tr -d '$\02' < "$2" | sed -E 's/\\/\\\\/g')" + local template="$(tr -d ${_tpl_ctrl} < "$2" | sed -E 's/\\/\\\\/g')" fi local -n ref=$1 local tmp=$(mktemp) @@ -17,9 +19,9 @@ function render() { for key in ${!ref[@]}; do if [[ "$key" == "_"* ]]; then # iter mode local subtemplate=$(mktemp) - echo "$template" | grep "{{start $key}}" -A99999 | grep "{{end $key}}" -B99999 | tr '\n' $'\01' > "$subtemplate" + echo "$template" | grep "{{start $key}}" -A99999 | grep "{{end $key}}" -B99999 | tr '\n' "${_tpl_newline}" > "$subtemplate" - echo 's'$'\02''\{\{start '"$key"'\}\}.*\{\{end '"$key"'\}\}'$'\02''\{\{'"$key"'\}\}'$'\02'';' >> "$tmp" + echo "s${_tpl_ctrl}\{\{start $key\}\}.*\{\{end $key\}\}${_tpl_ctrl}\{\{$key\}\}${_tpl_ctrl};" >> "$tmp" local -n asdf=${ref["$key"]} local j @@ -29,28 +31,28 @@ function render() { value+="$(render fdsa "$subtemplate" true)" done - value="$(tr -d '$\02' <<< "$value" | sed -E 's'$'\02''\{\{start '"$key"'\}\}'$'\02'$'\02'';s'$'\02''\{\{end '"$key"'\}\}'$'\02'$'\02')" + value="$(tr -d "${_tpl_ctrl}" <<< "$value" | sed -E "s${_tpl_ctrl}"'\{\{start '"$key"'\}\}'"${_tpl_ctrl}${_tpl_ctrl};s${_tpl_ctrl}"'\{\{end '"$key"'\}\}'"${_tpl_ctrl}${_tpl_ctrl}")" - echo 's'$'\02''\{\{'"$key"'\}\}'$'\02'''"$value"''$'\02'';' >> "$tmp" + echo "s${_tpl_ctrl}\{\{$key\}\}${_tpl_ctrl}${value}${_tpl_ctrl};" >> "$tmp" rm "$subtemplate" elif [[ "$key" == "@"* && "${ref["$key"]}" != '' ]]; then - local value="$(tr -d $'\01\02' <<< "${ref["$key"]}" | sed -E 's/\&/�UwU�/g')" - echo 's'$'\02''\{\{\'"$key"'\}\}'$'\02'''"$value"''$'\02''g;' >> "$tmp" #' + local value="$(tr -d "${_tpl_ctrl}${_tpl_newline}" <<< "${ref["$key"]}" | sed -E 's/\&/�UwU�/g')" + echo "s${_tpl_ctrl}"'\{\{\'"$key"'\}\}'"${_tpl_ctrl}${value}${_tpl_ctrl}g;" >> "$tmp" #' elif [[ "$key" == "+"* ]]; then # date mode if [[ ! "${ref["$key"]}" ]]; then # special case: if the date is empty, # make the output empty too - echo 's'$'\02''\{\{\'"$key"'\}\}'$'\02\02''g;' >> "$tmp" #' + echo "s${_tpl_ctrl}\{\{\\$key\}\}${_tpl_ctrl}${_tpl_ctrl}g;" >> "$tmp" #' else local value printf -v value "%(${cfg[template_date_format]})T" "${ref["$key"]}" - echo 's'$'\02''\{\{\'"$key"'\}\}'$'\02'''"$value"''$'\02''g;' >> "$tmp" #' + echo "s${_tpl_ctrl}\{\{\\$key\}\}${_tpl_ctrl}${value}${_tpl_ctrl};" >> "$tmp" #' fi elif [[ "$key" == '?'* ]]; then local _key="\\?${key/?/}" local subtemplate=$(mktemp) - echo 's'$'\02''\{\{start '"$_key"'\}\}((.*)\{\{else '"$_key"'\}\}.*\{\{end '"$_key"'\}\}|(.*)\{\{end '"$_key"'\}\})'$'\02''\2\3'$'\02'';' >> "$subtemplate" + echo "s${_tpl_ctrl}"'\{\{start '"$_key"'\}\}((.*)\{\{else '"$_key"'\}\}.*\{\{end '"$_key"'\}\}|(.*)\{\{end '"$_key"'\}\})'"${_tpl_ctrl}"'\2\3'"${_tpl_ctrl};" >> "$subtemplate" # TODO: check if this is needed? # the code below makes sure to resolve the conditional blocks @@ -63,13 +65,13 @@ function render() { elif [[ "${ref["$key"]}" != "" ]]; then echo "VALUE: ${ref["$key"]}" > /dev/stderr if [[ "$3" != true ]]; then - local value="$(html_encode <<< "${ref["$key"]}" | tr -d $'\02' | sed -E 's/\&/�UwU�/g')" + local value="$(html_encode <<< "${ref["$key"]}" | tr -d "${_tpl_ctrl}" | sed -E 's/\&/�UwU�/g')" else - local value="$(echo -n "${ref["$key"]}" | tr -d $'\01'$'\02' | tr $'\n' $'\01' | sed -E 's/\\\\/�OwO�/g;s/\\//g;s/�OwO�/\\/g' | html_encode | sed -E 's/\&/�UwU�/g')" + local value="$(echo -n "${ref["$key"]}" | tr -d "${_tpl_ctrl}${_tpl_newline}" | tr $'\n' "${_tpl_newline}" | sed -E 's/\\\\/�OwO�/g;s/\\//g;s/�OwO�/\\/g' | html_encode | sed -E 's/\&/�UwU�/g')" fi - echo 's'$'\02''\{\{\.'"$key"'\}\}'$'\02'''"$value"''$'\02''g;' >> "$tmp" + echo "s${_tpl_ctrl}"'\{\{\.'"$key"'\}\}'"${_tpl_ctrl}${value}${_tpl_ctrl}g;" >> "$tmp" else - echo 's'$'\02''\{\{\.'"$key"'\}\}'$'\02'$'\02''g;' >> "$tmp" + echo "s${_tpl_ctrl}"'\{\{\.'"$key"'\}\}'"${_tpl_ctrl}${_tpl_ctrl}g;" >> "$tmp" fi done unset IFS @@ -84,9 +86,9 @@ function render() { # this is possibly not enough to prevent all recursions, but # i see it as a last-ditch measure. so it'll do here. if [[ "$file" == "$2" ]]; then - echo 's'$'\02''\{\{\#'"$key"'\}\}'$'\02''I cowardly refuse to endlessly recurse\!'$'\02''g;' >> "$subtemplate" + echo "s${_tpl_ctrl}\{\{\#$key\}\}${_tpl_ctrl}I cowardly refuse to endlessly recurse\!${_tpl_ctrl}g;" >> "$subtemplate" elif [[ -f "$key" ]]; then - echo 's'$'\02''\{\{\#'"$key"'\}\}'$'\02'"$(tr -d $'\01'$'\02' < "$key" | tr $'\n' $'\01' | sed 's/\&/�UwU�/g')"$'\02''g;' >> "$subtemplate" + echo "s${_tpl_ctrl}\{\{\#$key\}\}${_tpl_ctrl}$(tr -d "${_tpl_ctrl}${_tpl_newline}" < "$key" | tr $'\n' "${_tpl_newline}" | sed 's/\&/�UwU�/g')${_tpl_ctrl};" >> "$subtemplate" _template_find_special_uri "$(cat "$key")" fi done <<< "$(grep -Poh '{{#.*?}}' <<< "$template" | sed 's/{{#//;s/}}$//')" @@ -99,14 +101,14 @@ function render() { _template_gen_special_uri >> "$tmp" if [[ "$3" != true ]]; then # are we recursing? - cat "$tmp" | tr '\n' $'\01' | sed -E 's/'$'\02'';'$'\01''/'$'\02'';/g;s/'$'\02''g;'$'\01''/'$'\02''g;/g' > "${tmp}_" + cat "$tmp" | tr '\n' "${_tpl_newline}" | sed -E $'s/\02;\01/\02;/g;s/\02g;\01/\02g;/g' > "${tmp}_" # i'm sorry what is this sed replace?? echo 's/\{\{start \?([a-zA-Z0-9_-]*[^}])\}\}(.*\{\{else \?\1\}\}(.*)\{\{end \?\1\}\}|.*\{\{end \?\1\}\})/\3/g' >> "${tmp}_" - template="$(tr '\n' $'\01' <<< "$template" | sed -E -f "${tmp}_" | tr $'\01' '\n')" + template="$(tr '\n' ${_tpl_newline} <<< "$template" | sed -E -f "${tmp}_" | tr "${_tpl_newline}" '\n')" sed -E 's/�UwU�/\&/g' <<< "$template" rm "$tmp" "${tmp}_" else - tr '\n' $'\01' <<< "$template" | sed -E -f "$tmp" | tr $'\01' '\n' + tr '\n' "${_tpl_newline}" <<< "$template" | sed -E -f "$tmp" | tr "${_tpl_newline}" '\n' rm "$tmp" fi @@ -139,10 +141,10 @@ _template_gen_special_uri() { # {{-uri-}}, where num is amount of slashed parts to include sort <<< ${_template_uri_list[*]} | uniq | while read num; do uri="$(grep -Poh '^(/.*?){'"$((num+1))"'}' <<< "${r[url_clean]}/")" - echo 's'$'\02''\{\{-uri-'"$num"'\}\}'$'\02'"$uri"$'\02''g;' + echo "s${_tpl_ctrl}"'\{\{-uri-'"$num"'\}\}'"${_tpl_ctrl}${uri}${_tpl_ctrl}g;" done # for replacing plain {{-uri}} without a number - echo 's'$'\02''\{\{-uri\}\}'$'\02'"${r[url_clean]}"$'\02''g;' + echo "s${_tpl_ctrl}"'\{\{-uri\}\}'"${_tpl_ctrl}${r[url_clean]}${_tpl_ctrl}g;" } # render_unsafe(array, template_file)