# frozen_string_literal: true module Onebox module SanitizeConfig HTTP_PROTOCOLS ||= ["http", "https", :relative].freeze ONEBOX ||= Sanitize::Config.freeze_config( Sanitize::Config.merge( Sanitize::Config::RELAXED, elements: Sanitize::Config::RELAXED[:elements] + %w[audio details embed iframe source video svg path use], attributes: { "a" => Sanitize::Config::RELAXED[:attributes]["a"] + %w[target], "audio" => %w[controls controlslist], "embed" => %w[height src type width], "iframe" => %w[ allowfullscreen frameborder height scrolling src width data-original-href data-unsanitized-src ], "source" => %w[src type], "video" => %w[ controls height loop width autoplay muted poster controlslist playsinline ], "path" => %w[d fill-rule], "svg" => %w[aria-hidden width height viewbox], "div" => [:data], # any data-* attributes, "span" => [:data], # any data-* attributes, "use" => %w[href], }, add_attributes: { "iframe" => { "seamless" => "seamless", "sandbox" => "allow-same-origin allow-scripts allow-forms allow-popups allow-popups-to-escape-sandbox" \ " allow-presentation", }, }, transformers: (Sanitize::Config::RELAXED[:transformers] || []) + [ lambda do |env| next unless env[:node_name] == "a" a_tag = env[:node] a_tag["href"] ||= "#" if a_tag["href"] =~ %r{\A(?:[a-z]+:)?//} a_tag["rel"] = "nofollow ugc noopener" else a_tag.remove_attribute("target") end end, lambda do |env| next unless env[:node_name] == "iframe" iframe = env[:node] allowed_regexes = env[:config][:allowed_iframe_regexes] || [/.*/] allowed = allowed_regexes.any? { |r| iframe["src"] =~ r } if !allowed # add a data attribute with the blocked src. This is not required # but makes it much easier to troubleshoot onebox issues iframe["data-unsanitized-src"] = iframe["src"] iframe.remove_attribute("src") end end, lambda do |env| next if env[:node_name] != "svg" env[:node].traverse do |node| next if node.element? && %w[svg path use].include?(node.name) node.remove end end, ], protocols: { "embed" => { "src" => HTTP_PROTOCOLS, }, "iframe" => { "src" => HTTP_PROTOCOLS, }, "source" => { "src" => HTTP_PROTOCOLS, }, "use" => { "href" => [:relative], }, }, css: { properties: Sanitize::Config::RELAXED[:css][:properties] + %w[--aspect-ratio], }, ), ) DISCOURSE_ONEBOX = Sanitize::Config.freeze_config( Sanitize::Config.merge( ONEBOX, attributes: Sanitize::Config.merge(ONEBOX[:attributes], "aside" => [:data]), ), ) end end