From 441ea2e64b0c446802c7bb0e367eb2a82a117aa2 Mon Sep 17 00:00:00 2001 From: Konstantin Demin Date: Fri, 8 Nov 2024 12:10:06 +0300 Subject: [PATCH] j2cfg: provide almost sane escape filter --- angie/autoconf.dist/core-worker-env.conf.j2 | 2 +- angie/autoconf.dist/http-alt-svc.conf.j2 | 3 +-- .../http-request-headers-basic.conf.j2 | 2 +- angie/conf.dist/fastcgi/cache-bypass.conf.j2 | 5 ++--- angie/conf.dist/grpc/ssl.conf.j2 | 3 +-- angie/conf.dist/http-ssl.conf.j2 | 6 ++--- .../conf.dist/proxy-http/cache-bypass.conf.j2 | 5 ++--- angie/conf.dist/proxy/ssl.conf.j2 | 3 +-- angie/conf.dist/scgi/cache-bypass.conf.j2 | 5 ++--- angie/conf.dist/ssl/cmd.conf.j2 | 3 +-- angie/conf.dist/uwsgi/cache-bypass.conf.j2 | 5 ++--- angie/conf.dist/uwsgi/ssl.conf.j2 | 3 +-- angie/snip.dist/fastcgi-request-headers.j2 | 5 ++--- angie/snip.dist/grpc-request-headers.j2 | 5 ++--- angie/snip.dist/http-response-headers.j2 | 3 +-- angie/snip.dist/proxy-request-headers.j2 | 5 ++--- angie/snip.dist/scgi-request-headers.j2 | 5 ++--- angie/snip.dist/uwsgi-request-headers.j2 | 5 ++--- j2cfg/j2cfg/functions.py | 22 +++++++++++++++++++ 19 files changed, 50 insertions(+), 45 deletions(-) diff --git a/angie/autoconf.dist/core-worker-env.conf.j2 b/angie/autoconf.dist/core-worker-env.conf.j2 index 61a6ce1..3367dab 100644 --- a/angie/autoconf.dist/core-worker-env.conf.j2 +++ b/angie/autoconf.dist/core-worker-env.conf.j2 @@ -26,6 +26,6 @@ env {{ k }}; ## {%- for k in c_vars_override %} {#- {%- set v = c_env[k] %} #} -## env {{ k }}={{ c_env[k].__repr__() }}; +## env {{ k }}={{ c_env[k] | ngx_esc }}; {%- endfor %} {%- endif %} \ No newline at end of file diff --git a/angie/autoconf.dist/http-alt-svc.conf.j2 b/angie/autoconf.dist/http-alt-svc.conf.j2 index f764b23..42fb313 100644 --- a/angie/autoconf.dist/http-alt-svc.conf.j2 +++ b/angie/autoconf.dist/http-alt-svc.conf.j2 @@ -7,6 +7,5 @@ {%- set proto = proto | re_sub('^v3$', 'h3=":443"; ma=3600') -%} {#- main part -#} {%- if proto %} -{#- TODO: precise quotation #} -add_header Alt-Svc {{ (proto | join(', ')).__repr__() }}; +add_header Alt-Svc {{ (proto | join(', ')) | ngx_esc }}; {%- endif %} \ No newline at end of file diff --git a/angie/autoconf.dist/http-request-headers-basic.conf.j2 b/angie/autoconf.dist/http-request-headers-basic.conf.j2 index 65a5166..2c20f8d 100644 --- a/angie/autoconf.dist/http-request-headers-basic.conf.j2 +++ b/angie/autoconf.dist/http-request-headers-basic.conf.j2 @@ -11,7 +11,7 @@ map $http_user_agent default $http_user_agent; {%- if env.NGX_HTTP_FAKE_UA %} ## merely fake - "" {{ env.NGX_HTTP_FAKE_UA.__repr__() }}; + "" {{ env.NGX_HTTP_FAKE_UA | ngx_esc }}; {%- else %} "" "Angie/$angie_version"; {%- endif %} diff --git a/angie/conf.dist/fastcgi/cache-bypass.conf.j2 b/angie/conf.dist/fastcgi/cache-bypass.conf.j2 index cb5095c..dbf6b85 100644 --- a/angie/conf.dist/fastcgi/cache-bypass.conf.j2 +++ b/angie/conf.dist/fastcgi/cache-bypass.conf.j2 @@ -1,15 +1,14 @@ -{#- TODO: precise quotation -#} {%- set cache_bypass = j2cfg.cache_bypass or [] -%} {%- if cache_bypass -%} ## disable (response) cache under following conditions fastcgi_cache_bypass {%- for v in cache_bypass %} - {{ v.__repr__() }} + {{ v | ngx_esc }} {%- endfor %} ; fastcgi_no_cache {%- for v in cache_bypass %} - {{ v.__repr__() }} + {{ v | ngx_esc }} {%- endfor %} ; {%- endif -%} \ No newline at end of file diff --git a/angie/conf.dist/grpc/ssl.conf.j2 b/angie/conf.dist/grpc/ssl.conf.j2 index b7ee94c..cc0a9aa 100644 --- a/angie/conf.dist/grpc/ssl.conf.j2 +++ b/angie/conf.dist/grpc/ssl.conf.j2 @@ -1,6 +1,5 @@ {%- for k, v in j2cfg.tls.conf_cmd.items() %} -{#- TODO: precise quotation #} -grpc_ssl_conf_command {{ k }} {{ v.__repr__() }}; +grpc_ssl_conf_command {{ k }} {{ v | ngx_esc }}; {%- endfor %} grpc_ssl_trusted_certificate {{ env.NGX_SSL_CERT_FILE }}; diff --git a/angie/conf.dist/http-ssl.conf.j2 b/angie/conf.dist/http-ssl.conf.j2 index 6157286..d86cfde 100644 --- a/angie/conf.dist/http-ssl.conf.j2 +++ b/angie/conf.dist/http-ssl.conf.j2 @@ -15,12 +15,10 @@ ssl_stapling_verify on; ssl_stapling_verify off; {%- endif %} {%- if j2cfg.tls.stapling.file %} -{#- TODO: precise quotation #} -ssl_stapling_file {{ j2cfg.tls.stapling.file.__repr__() }}; +ssl_stapling_file {{ j2cfg.tls.stapling.file | ngx_esc }}; {%- endif %} {%- if j2cfg.tls.stapling.responder %} -{#- TODO: precise quotation #} -ssl_stapling_responder {{ j2cfg.tls.stapling.responder.__repr__() }}; +ssl_stapling_responder {{ j2cfg.tls.stapling.responder | ngx_esc }}; {%- endif %} {%- else %} ssl_stapling off; diff --git a/angie/conf.dist/proxy-http/cache-bypass.conf.j2 b/angie/conf.dist/proxy-http/cache-bypass.conf.j2 index fb6357c..69d1110 100644 --- a/angie/conf.dist/proxy-http/cache-bypass.conf.j2 +++ b/angie/conf.dist/proxy-http/cache-bypass.conf.j2 @@ -1,15 +1,14 @@ -{#- TODO: precise quotation -#} {%- set cache_bypass = j2cfg.cache_bypass or [] -%} {%- if cache_bypass -%} ## disable (response) cache under following conditions proxy_cache_bypass {%- for v in cache_bypass %} - {{ v.__repr__() }} + {{ v | ngx_esc }} {%- endfor %} ; proxy_no_cache {%- for v in cache_bypass %} - {{ v.__repr__() }} + {{ v | ngx_esc }} {%- endfor %} ; {%- endif -%} \ No newline at end of file diff --git a/angie/conf.dist/proxy/ssl.conf.j2 b/angie/conf.dist/proxy/ssl.conf.j2 index 0deaaef..3d583b3 100644 --- a/angie/conf.dist/proxy/ssl.conf.j2 +++ b/angie/conf.dist/proxy/ssl.conf.j2 @@ -1,6 +1,5 @@ {%- for k, v in j2cfg.tls.conf_cmd.items() %} -{#- TODO: precise quotation #} -proxy_ssl_conf_command {{ k }} {{ v.__repr__() }}; +proxy_ssl_conf_command {{ k }} {{ v | ngx_esc }}; {%- endfor %} proxy_ssl_trusted_certificate {{ env.NGX_SSL_CERT_FILE }}; diff --git a/angie/conf.dist/scgi/cache-bypass.conf.j2 b/angie/conf.dist/scgi/cache-bypass.conf.j2 index b08bae2..8d7d52b 100644 --- a/angie/conf.dist/scgi/cache-bypass.conf.j2 +++ b/angie/conf.dist/scgi/cache-bypass.conf.j2 @@ -1,15 +1,14 @@ -{#- TODO: precise quotation -#} {%- set cache_bypass = j2cfg.cache_bypass or [] -%} {%- if cache_bypass -%} ## disable (response) cache under following conditions scgi_cache_bypass {%- for v in cache_bypass %} - {{ v.__repr__() }} + {{ v | ngx_esc }} {%- endfor %} ; scgi_no_cache {%- for v in cache_bypass %} - {{ v.__repr__() }} + {{ v | ngx_esc }} {%- endfor %} ; {%- endif -%} \ No newline at end of file diff --git a/angie/conf.dist/ssl/cmd.conf.j2 b/angie/conf.dist/ssl/cmd.conf.j2 index 2b17c6e..f484e2a 100644 --- a/angie/conf.dist/ssl/cmd.conf.j2 +++ b/angie/conf.dist/ssl/cmd.conf.j2 @@ -1,4 +1,3 @@ {%- for k, v in j2cfg.tls.conf_cmd.items() %} -{#- TODO: precise quotation #} -ssl_conf_command {{ k }} {{ v.__repr__() }}; +ssl_conf_command {{ k }} {{ v | ngx_esc }}; {%- endfor %} \ No newline at end of file diff --git a/angie/conf.dist/uwsgi/cache-bypass.conf.j2 b/angie/conf.dist/uwsgi/cache-bypass.conf.j2 index 4571bb0..09a35f7 100644 --- a/angie/conf.dist/uwsgi/cache-bypass.conf.j2 +++ b/angie/conf.dist/uwsgi/cache-bypass.conf.j2 @@ -1,15 +1,14 @@ -{#- TODO: precise quotation -#} {%- set cache_bypass = j2cfg.cache_bypass or [] -%} {%- if cache_bypass -%} ## disable (response) cache under following conditions uwsgi_cache_bypass {%- for v in cache_bypass %} - {{ v.__repr__() }} + {{ v | ngx_esc }} {%- endfor %} ; uwsgi_no_cache {%- for v in cache_bypass %} - {{ v.__repr__() }} + {{ v | ngx_esc }} {%- endfor %} ; {%- endif -%} \ No newline at end of file diff --git a/angie/conf.dist/uwsgi/ssl.conf.j2 b/angie/conf.dist/uwsgi/ssl.conf.j2 index 5aa4cc7..58be3c4 100644 --- a/angie/conf.dist/uwsgi/ssl.conf.j2 +++ b/angie/conf.dist/uwsgi/ssl.conf.j2 @@ -1,6 +1,5 @@ {%- for k, v in j2cfg.tls.conf_cmd.items() %} -{#- TODO: precise quotation #} -uwsgi_ssl_conf_command {{ k }} {{ v.__repr__() }}; +uwsgi_ssl_conf_command {{ k }} {{ v | ngx_esc }}; {%- endfor %} uwsgi_ssl_trusted_certificate {{ env.NGX_SSL_CERT_FILE }}; diff --git a/angie/snip.dist/fastcgi-request-headers.j2 b/angie/snip.dist/fastcgi-request-headers.j2 index 594e11d..73b81f9 100644 --- a/angie/snip.dist/fastcgi-request-headers.j2 +++ b/angie/snip.dist/fastcgi-request-headers.j2 @@ -1,7 +1,6 @@ ## sourced by conf.d/fastcgi/headers.conf -## hide/remove request headers +## set/remove request headers {%- set req_hdr_dict = j2cfg.request_headers or {} -%} {%- for h, v in req_hdr_dict.items() %} -{#- TODO: precise quotation #} -fastcgi_param {{ h | as_cgi_header }} {{ v.__repr__() }}; +fastcgi_param {{ h | as_cgi_header }} {{ v | ngx_esc }}; {%- endfor %} \ No newline at end of file diff --git a/angie/snip.dist/grpc-request-headers.j2 b/angie/snip.dist/grpc-request-headers.j2 index 4be0b17..5161818 100644 --- a/angie/snip.dist/grpc-request-headers.j2 +++ b/angie/snip.dist/grpc-request-headers.j2 @@ -1,7 +1,6 @@ ## sourced by conf.d/grpc/headers.conf -## hide/remove request headers +## set/remove request headers {%- set req_hdr_dict = j2cfg.request_headers or {} -%} {%- for h, v in req_hdr_dict.items() %} -{#- TODO: precise quotation #} -grpc_set_header {{ h }} {{ v.__repr__() }}; +grpc_set_header {{ h }} {{ v | ngx_esc }}; {%- endfor %} \ No newline at end of file diff --git a/angie/snip.dist/http-response-headers.j2 b/angie/snip.dist/http-response-headers.j2 index 9b578a8..32662a0 100644 --- a/angie/snip.dist/http-response-headers.j2 +++ b/angie/snip.dist/http-response-headers.j2 @@ -2,6 +2,5 @@ ## add response headers {%- set resp_hdr_dict = j2cfg.response_headers or {} -%} {%- for h, v in resp_hdr_dict.items() %} -{#- TODO: precise quotation #} -add_header {{ h }} {{ v.__repr__() }}; +add_header {{ h }} {{ v | ngx_esc }}; {%- endfor %} \ No newline at end of file diff --git a/angie/snip.dist/proxy-request-headers.j2 b/angie/snip.dist/proxy-request-headers.j2 index b86adc3..28080bf 100644 --- a/angie/snip.dist/proxy-request-headers.j2 +++ b/angie/snip.dist/proxy-request-headers.j2 @@ -1,7 +1,6 @@ ## sourced by conf.d/proxy-http/headers.conf -## hide/remove request headers +## set/remove request headers {%- set req_hdr_dict = j2cfg.request_headers or {} -%} {%- for h, v in req_hdr_dict.items() %} -{#- TODO: precise quotation #} -proxy_set_header {{ h }} {{ v.__repr__() }}; +proxy_set_header {{ h }} {{ v | ngx_esc }}; {%- endfor %} \ No newline at end of file diff --git a/angie/snip.dist/scgi-request-headers.j2 b/angie/snip.dist/scgi-request-headers.j2 index f6bebbd..1ea6704 100644 --- a/angie/snip.dist/scgi-request-headers.j2 +++ b/angie/snip.dist/scgi-request-headers.j2 @@ -1,7 +1,6 @@ ## sourced by conf.d/scgi/headers.conf -## hide/remove request headers +## set/remove request headers {%- set req_hdr_dict = j2cfg.request_headers or {} -%} {%- for h, v in req_hdr_dict.items() %} -{#- TODO: precise quotation #} -scgi_param {{ h | as_cgi_header }} {{ v.__repr__() }}; +scgi_param {{ h | as_cgi_header }} {{ v | ngx_esc }}; {%- endfor %} \ No newline at end of file diff --git a/angie/snip.dist/uwsgi-request-headers.j2 b/angie/snip.dist/uwsgi-request-headers.j2 index b045da3..7e45c1b 100644 --- a/angie/snip.dist/uwsgi-request-headers.j2 +++ b/angie/snip.dist/uwsgi-request-headers.j2 @@ -1,7 +1,6 @@ ## sourced by conf.d/uwsgi/headers.conf -## hide/remove request headers +## set/remove request headers {%- set req_hdr_dict = j2cfg.request_headers or {} -%} {%- for h, v in req_hdr_dict.items() %} -{#- TODO: precise quotation #} -uwsgi_param {{ h | as_cgi_header }} {{ v.__repr__() }}; +uwsgi_param {{ h | as_cgi_header }} {{ v | ngx_esc }}; {%- endfor %} \ No newline at end of file diff --git a/j2cfg/j2cfg/functions.py b/j2cfg/j2cfg/functions.py index 7645c74..480d791 100644 --- a/j2cfg/j2cfg/functions.py +++ b/j2cfg/j2cfg/functions.py @@ -240,6 +240,27 @@ def sh_like_file_to_list(j2env, file_in: str) -> list: )) +def ngx_esc(x): + if isinstance(x, str): + if x == "": + return "''" + if re.search(r'(?:\s|[;{}()\[\]\\\'"])', x): + return repr(x) + return x + if is_sequence(x): + return uniq([ + ngx_esc(v) + for v in x + ]) + if is_mapping(x): + return dict_remap_keys( + x, ngx_esc + ) + if x is None: + return None + return ngx_esc(str(x)) + + def merge_dict_recurse(d1, d2: dict) -> dict: x = {} | d1 @@ -290,6 +311,7 @@ J2CFG_FILTERS = [ is_sequence, list_diff, list_intersect, + ngx_esc, re_fullmatch, re_fullmatch_negate, re_match,