Gem cell gem 默认不进行 html escape 问题

heroyct · 2018年10月01日 · 最后由 heroyct 回复于 2018年11月14日 · 139 次阅读

现在的项目使用了cell这个gem
https://github.com/trailblazer/cells

4.0以前

在4.0以前的时候使用的是rails的render,默认会进行html escape

比如下面的代码是没有问题的

@text = '<script>alert("hello")</script>'
<%= @text %>

4.0以后

目前打算升级到4.0

但是4.0以后,cell采用了其他的render方法,默认不进行html escape, 必须像下面这样传递escape过后的值

@text = '<script>alert("hello")</script>'
<%= h @text %>

http://trailblazer.to/gems/cells/cells4.html

Cells per default does not escape HTML. However, you may run into problems when using Rails helpers. Internally, those helpers often blindly escape. This is not Cells’ fault but a design flaw in Rails. Everything related to #capture will cause problems - check this as an example. As you can see, this is Rails swinging the escape hammer. Please don’t blame us for escapes where they shouldn’t be. Rather open an issue on Rails and tell them to make their code better overrideable for us.

但是每个字段自己写代码escape感觉很麻烦,而且万一忘记了,会出现安全问题

问题

目前把需要escape的都加了html_escape方法暂时对应了(估计有漏的地方)

没找到其他的好的方法,有遇到相同的问题的吗?

共收到 4 条回复

建议去掉这个 gem。

@Rei 目前我也是这么想的,因为感觉这个gem不太稳定(突然设计风格就变了)
只是目前所有页面都是cell写的,这改造的活量有点大
所以问问看有没有类似问题的人,借鉴一下经验

暂时把cell的render改成了rails的render

class CellBase < Cell::ViewModel
  attr_accessor :response_body

  include AbstractController::Rendering
  include AbstractController::Helpers
  include ActionView::Layouts

  helper ApplicationHelper
  include ApplicationHelper

  self.view_paths = ['app/cells']

  def self.supports_path?
    true
  end

  def action_name
    caller(5, 1)[0].match(/`(\w+)/)[1]
  end

  # 让view中可以访问cell class里面的方法
  def self.inherited(klass)
    def klass.method_added(name)
      helper_method(name)
    end
  end
end

终于把cell gem删除了

为了尽量少改动代码,扩展render partial来实现了类似的接口

1. 添加一个helper

# app/helpers/cell_helper.rb

module CellHelper
  def cell(cell_name, options = {})
    cell_class = class_from_cell_name(cell_name)
    cell_class.new(self, options)
  end

  private

  def class_from_cell_name(name)
    "#{name}_cell".camelize.constantize
  end
end

2. 添加一个cell的base类

# app/cells/cell_base.rb

class CellBase
  attr_reader :context

  def initialize(context, options = {})
    @context = context
    @options = options
  end

  def call(method_name, options = {})
    send(method_name, options)
  end

  protected

  def render(options = {})
    locals = options.fetch(:locals, {})
    locals = locals.merge(cell: self)
    called_method_name = caller_locations(1, 1)[0].label

    context.render(
      partial: template_file_path(called_method_name, options),
      locals: locals
    )
  end

  def template_file_path(method_name, options)
    file_name = options[:file].present? ? options[:file] : method_name

    folder = self.class.to_s.underscore[0..-6]
    "#{folder}/#{file_name}"
  end
end

3. 让所有的cell类都继承CellBase

class SampleCell < CellBase
end

4. 把xxx.erb文件改成_xxx.html.erb文件(partial file)

heroyct 关闭了讨论 11月14日 17:58
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册