Skip to content

Commit

Permalink
Update csv.rb
Browse files Browse the repository at this point in the history
  • Loading branch information
joeldrapper committed Feb 20, 2024
1 parent ad3cd94 commit 962184f
Showing 1 changed file with 38 additions and 14 deletions.
52 changes: 38 additions & 14 deletions lib/phlex/csv.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ def call(buffer = +"", view_context: nil)
view_template(*args, **kwargs)

if @_first && render_headers?
buffer << @_headers.map! { |value| escape(value) }.join(",") << "\n"
buffer << @_headers.join(",") << "\n"
end

buffer << @_current_row.map! { |value| escape(value) }.join(",") << "\n"
buffer << @_current_row.join(",") << "\n"
@_current_column_index = 0
@_current_row.clear
end
Expand All @@ -48,12 +48,12 @@ def content_type

def column(header = nil, value)
if @_first
@_headers << header
@_headers << escape(header)
elsif header != @_headers[@_current_column_index]
raise "Inconsistent header."
end

@_current_row << value
@_current_row << escape(value)
@_current_column_index += 1
end

Expand All @@ -73,6 +73,14 @@ def render_headers?
true
end

def trim_space?
true
end

def escape_formulas?
true
end

def helpers
@_view_context
end
Expand All @@ -82,16 +90,32 @@ def render(renderable)
end

def escape(value)
value = value.to_s.dup
value.strip!

if value.start_with?("=") || value.start_with?("+") || value.start_with?("-") || value.start_with?("@")
# Prefix a tab to prevent Excel and Google Docs from interpreting the value as a formula
%("\t#{value.gsub('"', '""')}")
elsif value.include?('"') || value.include?(",") || value.include?("\n")
%("#{value.gsub('"', '""')}")
else
value
if trim_space?
value = value.to_s.strip

first_char = value[0]

if first_char == "=" || first_char == "+" || first_char == "-" || first_char == "@"
# Prefix a single quote to prevent Excel, Google Docs, etc. from interpreting the value as a formula
# See https://owasp.org/www-community/attacks/CSV_Injection
%("'#{value.gsub('"', '""')}")
elsif value.include?('"') || value.include?(",") || value.include?("\n")
%("#{value.gsub('"', '""')}")
else
value
end
else # In the case of non-trimmed values, we need to escape some extra characters
first_char = value[0]

if first_char == "=" || first_char == "+" || first_char == "-" || first_char == "@" || first_char == "\t" || first_char == "\n"
# Prefix a single quote to prevent Excel, Google Docs, etc. from interpreting the value as a formula
# See https://owasp.org/www-community/attacks/CSV_Injection
%("'#{value.gsub('"', '""')}")
elsif first_char == " " || value.include?('"') || value.include?(",") || value.include?("\n")
%("#{value.gsub('"', '""')}")
else
value
end
end
end
end

0 comments on commit 962184f

Please sign in to comment.