Permalink
Browse files

basic contextual autoescape wrapper for eruby + jruby

  • Loading branch information...
1 parent 6b1f371 commit 146da8866b896abf7e8231007e757187cf8a8efc @igrigorik committed Oct 22, 2011
View
0 .rspec
No changes.
View
@@ -1 +1,11 @@
require 'bundler/gem_tasks'
+require 'rspec/core/rake_task'
+
+task :default => [:spec]
+task :test => [:spec]
+
+desc "run spec tests"
+RSpec::Core::RakeTask.new('spec') do |t|
+ t.pattern = 'spec/**_spec.rb'
+end
+
View
@@ -7,11 +7,14 @@ Gem::Specification.new do |s|
s.version = Contextual::VERSION
s.authors = ["Ilya Grigorik"]
s.email = ["ilya@igvita.com"]
- s.homepage = ""
- s.summary = %q{TODO: Write a gem summary}
- s.description = %q{TODO: Write a gem description}
+ s.homepage = "https://github.com/igrigorik/contextual"
+ s.summary = "Runtime contextual autoescaper"
+ s.description = s.summary
s.rubyforge_project = "contextual"
+ s.platform = "java"
+
+ s.add_development_dependency "rspec"
s.files = `git ls-files`.split("\n")
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
View
Binary file not shown.
View
Binary file not shown.
View
@@ -1,5 +1,3 @@
require "contextual/version"
+require "contextual/contextual"
-module Contextual
- # Your code goes here...
-end
@@ -0,0 +1,82 @@
+require "java"
+require "ext/guava"
+require "ext/autoesc"
+
+java_import com.google.autoesc.HTMLEscapingWriter
+
+require "rubygems"
+require "erubis"
+
+module Erubis
+ module ContextualEscapeEnhancer
+
+ def self.desc # :nodoc:
+ "switch '<%= %>' to escaped and '<%== %>' to unescaped"
+ end
+
+ def add_expr(src, code, indicator)
+ case indicator
+ when '='
+ @escape ? add_expr_literal(src, code) : add_expr_escaped(src, code)
+ when '=='
+ @escape ? add_expr_escaped(src, code) : add_expr_literal(src, code)
+ when '==='
+ add_expr_debug(src, code)
+ end
+ end
+
+ def add_text(src, text)
+ src << " #{@bufvar}.writeSafe '" << text << "';" unless text.empty?
+ end
+
+ def add_stmt(src, code)
+ src << code
+ src << ';' unless code[-1] == ?\n
+ end
+
+ def add_expr_literal(src, code)
+ src << " #{@bufvar}.writeSafe(" << code << ').to_s;'
+ end
+
+ def add_expr_escaped(src, code)
+ src << " #{@bufvar}.write((" << code << ').to_s);'
+ end
+ end
+
+ class ContextualBuffer
+ def initialize
+ @writer = java.io.StringWriter.new
+ @buf = HTMLEscapingWriter.new(@writer)
+ end
+
+ def writeSafe(code)
+ @buf.writeSafe(code)
+ end
+
+ def write(code)
+ @buf.write(code)
+ end
+
+ def to_s
+ @writer.to_s
+ end
+
+ def close
+ @writer.close
+ end
+ end
+
+ class ContextualEruby < Eruby
+ include ContextualEscapeEnhancer
+
+ def add_preamble(src)
+ src << "#{@bufvar} = Erubis::ContextualBuffer.new; "
+ end
+
+ def add_postamble(src)
+ src << "\n" unless src[-1] == ?\n
+ src << "#{@bufvar}.close\n"
+ src << "#{@bufvar}.to_s\n"
+ end
+ end
+end
View
@@ -0,0 +1,35 @@
+require "contextual"
+
+describe Contextual do
+
+ it "should escape unsafe content" do
+ t = Erubis::ContextualEruby.new(" \
+ <% elements.each do |e| %> \
+ <%= e %> \
+ <% end %> \
+ ")
+
+ elements = ['<script>', '&bar', 'style="test"']
+ res = t.result(binding())
+
+ res.should match('&lt;script&gt;')
+ res.should match('&amp;bar')
+ res.should match('style=&#34;test&#34;')
+ end
+
+ it "should preserve safe content" do
+ t = Erubis::ContextualEruby.new("<ul><%= '<script>' %></ul>")
+ t.result.should match('<ul>&lt;script&gt;</ul>')
+ end
+
+ it "should allow explicit safe content" do
+ t = Erubis::ContextualEruby.new("<ul><%== '<script>' %></ul>")
+ t.result.should match('<ul><script></ul>')
+ end
+
+ it "should skip comments" do
+ t = Erubis::ContextualEruby.new("<%# some comment %>")
+ t.result.should be_empty
+ end
+
+end

0 comments on commit 146da88

Please sign in to comment.