From 71242ac40055097ebcca547576644b2e5304858e Mon Sep 17 00:00:00 2001 From: TEC Date: Wed, 16 Feb 2022 23:59:43 +0800 Subject: [PATCH] Escape input when creating html --- lib/Surveys.jl | 72 ++++++++++++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 32 deletions(-) diff --git a/lib/Surveys.jl b/lib/Surveys.jl index c390037..600e24a 100644 --- a/lib/Surveys.jl +++ b/lib/Surveys.jl @@ -344,11 +344,11 @@ isvalid(r::Response, s::Survey) = # General htmlrenderer # --------------------- -htmlcontent(::FormField, value) = "" -htmlelement(::FormField) = "?" -htmlattrs(::FormField, value) = [] -htmlvoidelem(::FormField) = false -htmlpostprocess(::FormField, ::Symbol) = identity +html_content(::FormField, value) = "" +html_element(::FormField) = "?" +html_attrs(::FormField, value) = [] +html_voidelem(::FormField) = false +html_postprocess(::FormField, ::Symbol) = identity elem(e::AbstractString, content::AbstractString="", attrs::Pair{Symbol,<:Any}...) = Html.normal_element(content, e, [], attrs...) @@ -357,20 +357,28 @@ elem(e::AbstractString, attrs::Pair{Symbol,<:Any}...) = elem(e, "", attrs...) velem(e::AbstractString, attrs::Pair{Symbol,<:Any}...) = Html.void_element(e, [], Vector{Pair{Symbol,Any}}(collect(attrs))) +const html_escape_characters = + Dict('"' => """, + '&' => "&", + '<' => "<", + '>' => ">") +html_escape(s::String) = replace(s, r"\"|&|<|>" => c -> html_escape_characters[c[1]]) +html_escape(::Missing) = "" + function htmlrender(field::FormField, value::Any, id, mandatory, invalid) - element = htmlelement(field) - attrs = vcat(htmlattrs(field, value), + element = html_element(field) + attrs = vcat(html_attrs(field, value), [:id => string("qn-", id), :name => id, Symbol("aria-invalid") => invalid, :required => mandatory && !isa(field, Checkbox)]) - if htmlvoidelem(field) + if html_voidelem(field) velem(element, attrs...) else - content = htmlcontent(field, value) + content = html_content(field, value) elem(element, if ismissing(content) "" else string(content) end, attrs...) - end |> htmlpostprocess(field, id) + end |> html_postprocess(field, id) end # --------------------- @@ -388,28 +396,28 @@ struct FormInput{T} <: FormField{T} end end -htmlelement(::FormInput) = "input" -htmlvoidelem(::FormInput) = true -htmlattrs(::FormInput, value) = - [:value => if ismissing(value) false else string(value) end] +html_element(::FormInput) = "input" +html_voidelem(::FormInput) = true +html_attrs(::FormInput, value) = + [:value => if ismissing(value) false else html_escape(string(value)) end] # interpret(::FormInput{Bool}, value::AbstractString) = value == "yes" -htmlattrs(::FormInput{Bool}, value::Union{Bool, Missing}) = +html_attrs(::FormInput{Bool}, value::Union{Bool, Missing}) = [:type => "checkbox", :value => "yes", :checked => !ismissing(value) && value === true] -htmlpostprocess(::FormInput{Bool}, id::Symbol) = +html_postprocess(::FormInput{Bool}, id::Symbol) = s -> string(input(type="hidden", name=id, value="no"), s) # -function htmlattrs(::FormInput{T}, value) where {T <: Union{Date, Number, Integer, String}} +function html_attrs(::FormInput{T}, value) where {T <: Union{Date, Number, Integer, String}} type = Dict(Date => "date", Number => "number", Integer => "number", String => "text")[T] [:type => type, - :value => if ismissing(value) false else string(value) end] + :value => if ismissing(value) false else html_escape(string(value)) end] end const Checkbox = FormInput{Bool} @@ -426,8 +434,8 @@ struct TextArea <: FormField{String} end default_validators(::TextArea) = Function[wordlimit(500), charlimit(2500)] -htmlelement(::TextArea) = "textarea" -htmlcontent(::TextArea, value) = value +html_element(::TextArea) = "textarea" +html_content(::TextArea, value) = html_escape(value) #