From 26df05374cded0c46c3ed99b9adbf1b553290ce4 Mon Sep 17 00:00:00 2001 From: 7rans Date: Wed, 27 Oct 2010 14:04:26 -0400 Subject: [PATCH 1/3] provide customizable sanitization --- lib/gollum.rb | 45 +---------- lib/gollum/markup.rb | 6 +- lib/gollum/sanitization.rb | 150 +++++++++++++++++++++++++++++++++++++ lib/gollum/wiki.rb | 44 ++++++++--- 4 files changed, 190 insertions(+), 55 deletions(-) create mode 100644 lib/gollum/sanitization.rb diff --git a/lib/gollum.rb b/lib/gollum.rb index 36bcab92..bc5f5829 100644 --- a/lib/gollum.rb +++ b/lib/gollum.rb @@ -18,54 +18,13 @@ require 'gollum/page' require 'gollum/file' require 'gollum/markup' require 'gollum/albino' +require 'gollum/sanitization' module Gollum VERSION = '1.0.1' - SANITIZATION_OPTIONS = { - :elements => [ - 'a', 'abbr', 'acronym', 'address', 'area', 'b', 'big', - 'blockquote', 'br', 'button', 'caption', 'center', 'cite', - 'code', 'col', 'colgroup', 'dd', 'del', 'dfn', 'dir', - 'div', 'dl', 'dt', 'em', 'fieldset', 'font', 'form', 'h1', - 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'img', 'input', - 'ins', 'kbd', 'label', 'legend', 'li', 'map', 'menu', - 'ol', 'optgroup', 'option', 'p', 'pre', 'q', 's', 'samp', - 'select', 'small', 'span', 'strike', 'strong', 'sub', - 'sup', 'table', 'tbody', 'td', 'textarea', 'tfoot', 'th', - 'thead', 'tr', 'tt', 'u', 'ul', 'var' - ], - :attributes => { - :all => ['abbr', 'accept', 'accept-charset', - 'accesskey', 'action', 'align', 'alt', 'axis', - 'border', 'cellpadding', 'cellspacing', 'char', - 'charoff', 'charset', 'checked', 'cite', - 'class', 'clear', 'cols', 'colspan', 'color', - 'compact', 'coords', 'datetime', 'dir', - 'disabled', 'enctype', 'for', 'frame', - 'headers', 'height', 'href', 'hreflang', - 'hspace', 'id', 'ismap', 'label', 'lang', - 'longdesc', 'maxlength', 'media', 'method', - 'multiple', 'name', 'nohref', 'noshade', - 'nowrap', 'prompt', 'readonly', 'rel', 'rev', - 'rows', 'rowspan', 'rules', 'scope', - 'selected', 'shape', 'size', 'span', 'src', - 'start', 'summary', 'tabindex', 'target', - 'title', 'type', 'usemap', 'valign', 'value', - 'vspace', 'width'] - }, - :protocols => { - 'a' => {'href' => ['http', 'https', 'mailto', :relative]}, - 'img' => {'href' => ['http', 'https', :relative]} - } - } - HISTORY_SANITIZATION_OPTIONS = SANITIZATION_OPTIONS.merge( - :add_attributes => { - 'a' => {'rel' => 'nofollow'} - } - ) - class Error < StandardError; end + class DuplicatePageError < Error attr_accessor :dir attr_accessor :existing_path diff --git a/lib/gollum/markup.rb b/lib/gollum/markup.rb index 2a78bbbf..40ee86fa 100644 --- a/lib/gollum/markup.rb +++ b/lib/gollum/markup.rb @@ -27,9 +27,9 @@ module Gollum # # Returns the formatted String content. def render(no_follow = false) - sanitize_options = no_follow ? - HISTORY_SANITIZATION_OPTIONS : - SANITIZATION_OPTIONS + sanitize_options = ( + no_follow ? @wiki.history_sanitization : @wiki.sanitization + ).to_h data = extract_tex(@data) data = extract_code(data) data = extract_tags(data) diff --git a/lib/gollum/sanitization.rb b/lib/gollum/sanitization.rb new file mode 100644 index 00000000..65cdcc8c --- /dev/null +++ b/lib/gollum/sanitization.rb @@ -0,0 +1,150 @@ +module Gollum + + # Encapsulate sanitization options. + # + # This class does not yet support all options of Sanitize library. + # See http://github.com/rgrove/sanitize/. + class Sanitization + + # + ELEMENTS = [ + 'a', 'abbr', 'acronym', 'address', 'area', 'b', 'big', + 'blockquote', 'br', 'button', 'caption', 'center', 'cite', + 'code', 'col', 'colgroup', 'dd', 'del', 'dfn', 'dir', + 'div', 'dl', 'dt', 'em', 'fieldset', 'font', 'form', 'h1', + 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'img', 'input', + 'ins', 'kbd', 'label', 'legend', 'li', 'map', 'menu', + 'ol', 'optgroup', 'option', 'p', 'pre', 'q', 's', 'samp', + 'select', 'small', 'span', 'strike', 'strong', 'sub', + 'sup', 'table', 'tbody', 'td', 'textarea', 'tfoot', 'th', + 'thead', 'tr', 'tt', 'u', 'ul', 'var' + ] + + # + ATTRIBUTES = { + :all => [ + 'abbr', 'accept', 'accept-charset', + 'accesskey', 'action', 'align', 'alt', 'axis', + 'border', 'cellpadding', 'cellspacing', 'char', + 'charoff', 'charset', 'checked', 'cite', + 'class', 'clear', 'cols', 'colspan', 'color', + 'compact', 'coords', 'datetime', 'dir', + 'disabled', 'enctype', 'for', 'frame', + 'headers', 'height', 'href', 'hreflang', + 'hspace', 'id', 'ismap', 'label', 'lang', + 'longdesc', 'maxlength', 'media', 'method', + 'multiple', 'name', 'nohref', 'noshade', + 'nowrap', 'prompt', 'readonly', 'rel', 'rev', + 'rows', 'rowspan', 'rules', 'scope', + 'selected', 'shape', 'size', 'span', 'src', + 'start', 'summary', 'tabindex', 'target', + 'title', 'type', 'usemap', 'valign', 'value', + 'vspace', 'width' + ] + } + + # + PROTOCOLS = { + 'a' => {'href' => ['http', 'https', 'mailto', :relative]}, + 'img' => {'href' => ['http', 'https', :relative]} + } + + # + ADD_ATTRIBUTES = { + 'a' => {'rel' => 'nofollow'} + } + + # Additional options specifically for histories. + HISTORY_OPTIONS = { + :add_attributes => { + 'a' => {'rel' => 'nofollow'} + } + } + + # + def initialize(*settings) + if settings.empty? + @elements = ELEMENTS + @attributes = ATTRIBUTES + @protocols = PROTOCOLS + @add_attributes = {} + @allow_comments = false + else + @elements = [] + @attributes = {} + @protocols = {} + @add_attributes = {} + @allow_comments = false + settings.each{ |s| merge!(s) } + end + end + + def elements + @elements + end + + def attributes + @attributes + end + + def protocols + @protocols + end + + def add_attributes + @add_attributes + end + + def allow_comments + !!@allow_comments + end + + # + def to_h + { :elements => elements, + :attributes => attributes, + :protocols => protocols, + :add_attributes => add_attributes, + :allow_comments => allow_comments + } + end + + # + def merge(settings) + self.class.new(self, settings) + end + + # + def merge!(settings) + case settings + when Sanitization + other_elements = settings.elements + other_attributes = settings.attributes + other_protocols = settings.protocols + other_add_attributes = settings.add_attributes + else + other_elements = settings[:elements] || [] + other_attributes = settings[:attributes] || {} + other_protocols = settings[:protocols] || {} + other_add_attributes = settings[:add_attributes] || {} + end + + elements.concat(other_elements) + other_attributes.each do |k,v| + attributes[k] ||= [] + attributes[k].concat(v) + end + other_protocols.each do |k,v| + protocols[k] ||= {} + protocols[k].merge!(v) + end + other_add_attributes.each do |k,v| + add_attributes[k] ||= {} + add_attributes[k].merge!(v) + end + end + + end + +end + diff --git a/lib/gollum/wiki.rb b/lib/gollum/wiki.rb index 30fade8a..f74cfd89 100644 --- a/lib/gollum/wiki.rb +++ b/lib/gollum/wiki.rb @@ -15,6 +15,12 @@ module Gollum # Sets the default email for commits. attr_accessor :default_committer_email + # + attr_writer :sanitization_options + + # + attr_writer :history_sanitization_options + # Gets the page class used by all instances of this Wiki. # Default: Gollum::Page. def page_class @@ -36,6 +42,12 @@ module Gollum ::Gollum::File end end + + # + def sanitization + @sanitization ||= Sanitization.new + end + end self.default_committer_name = 'Anonymous' @@ -51,21 +63,35 @@ module Gollum # repo - The String path to the Git repository that holds the Gollum # site. # options - Optional Hash: - # :base_path - String base path for all Wiki links. - # Default: "/" - # :page_class - The page Class. Default: Gollum::Page - # :file_class - The file Class. Default: Gollum::File + # :base_path - String base path for all Wiki links. + # Default: "/" + # :page_class - The page Class. Default: Gollum::Page + # :file_class - The file Class. Default: Gollum::File + # :sanitization - An instance of Santitization. # # Returns a fresh Gollum::Repo. def initialize(path, options = {}) - @path = path - @repo = Grit::Repo.new(path) - @base_path = options[:base_path] || "/" - @page_class = options[:page_class] || self.class.page_class - @file_class = options[:file_class] || self.class.file_class + @path = path + @repo = Grit::Repo.new(path) + @base_path = options[:base_path] || "/" + @page_class = options[:page_class] || self.class.page_class + @file_class = options[:file_class] || self.class.file_class + @sanitization = options[:sanitization] || self.class.sanitization + clear_cache end + # Public: Instance of Sanitization class. + attr :sanitization + + # Public: Return a new sanitization instance combining #sanitiazation + # and additional history sanitization options. + # + # Returns a Sanitization instance. + def history_sanitization + @history_sanitiazation ||= sanitization.merge(Sanitization::HISTORY_OPTIONS) + end + # Public: check whether the wiki's git repo exists on the filesystem. # # Returns true if the repo exists, and false if it does not. From 3e8d2773be2308c8e4362e9fbb2349f7be15ca8d Mon Sep 17 00:00:00 2001 From: 7rans Date: Wed, 27 Oct 2010 14:17:24 -0400 Subject: [PATCH 2/3] allow deactivation of sanitization --- lib/gollum/markup.rb | 4 ++-- lib/gollum/wiki.rb | 20 +++++++++++++------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/lib/gollum/markup.rb b/lib/gollum/markup.rb index 40ee86fa..b79e7a19 100644 --- a/lib/gollum/markup.rb +++ b/lib/gollum/markup.rb @@ -29,7 +29,7 @@ module Gollum def render(no_follow = false) sanitize_options = ( no_follow ? @wiki.history_sanitization : @wiki.sanitization - ).to_h + ) data = extract_tex(@data) data = extract_code(data) data = extract_tags(data) @@ -43,7 +43,7 @@ module Gollum end data = process_tags(data) data = process_code(data) - data = Sanitize.clean(data, sanitize_options) + data = Sanitize.clean(data, sanitize_options.to_h) if sanitize_options data = process_tex(data) data.gsub!(/

<\/p>/, '') data diff --git a/lib/gollum/wiki.rb b/lib/gollum/wiki.rb index f74cfd89..82de0a89 100644 --- a/lib/gollum/wiki.rb +++ b/lib/gollum/wiki.rb @@ -15,11 +15,9 @@ module Gollum # Sets the default email for commits. attr_accessor :default_committer_email - # - attr_writer :sanitization_options - - # - attr_writer :history_sanitization_options + # Sets sanitization options. Set to false to deactivate + # sanitization altogether. + attr_writer :sanitization # Gets the page class used by all instances of this Wiki. # Default: Gollum::Page. @@ -45,7 +43,8 @@ module Gollum # def sanitization - @sanitization ||= Sanitization.new + return @sanitization unless @sanitization.nil? + @sanitization = Sanitization.new end end @@ -89,7 +88,14 @@ module Gollum # # Returns a Sanitization instance. def history_sanitization - @history_sanitiazation ||= sanitization.merge(Sanitization::HISTORY_OPTIONS) + return @history_sanitiazation unless @history_sanitiazation.nil? + @history_sanitiazation = ( + if sanitization + sanitization.merge(Sanitization::HISTORY_OPTIONS) + else + false + end + ) end # Public: check whether the wiki's git repo exists on the filesystem. From ac1d1c47e2ef5b66d5638170a9cd815dcf947e0f Mon Sep 17 00:00:00 2001 From: 7rans Date: Wed, 27 Oct 2010 14:20:33 -0400 Subject: [PATCH 3/3] fix misspelling of sanitization --- lib/gollum/wiki.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/gollum/wiki.rb b/lib/gollum/wiki.rb index 82de0a89..fb1bec04 100644 --- a/lib/gollum/wiki.rb +++ b/lib/gollum/wiki.rb @@ -88,8 +88,8 @@ module Gollum # # Returns a Sanitization instance. def history_sanitization - return @history_sanitiazation unless @history_sanitiazation.nil? - @history_sanitiazation = ( + return @history_sanitization unless @history_sanitization.nil? + @history_sanitization = ( if sanitization sanitization.merge(Sanitization::HISTORY_OPTIONS) else