impress/app/controllers/swf_assets_controller.rb

59 lines
1.8 KiB
Ruby
Raw Normal View History

class SwfAssetsController < ApplicationController
# We're very careful with what content is allowed to load. This is because
# asset movies run arbitrary JS, and, while we generally trust content from
# Neopets.com, let's not be *allowing* movie JS to do whatever it wants! This
# is a good default security stance, even if we don't foresee an attack.
content_security_policy do |policy|
policy.sandbox "allow-scripts"
policy.default_src "none"
policy.img_src -> {
src_list(
helpers.image_url("favicon.png"),
@swf_asset.image_url,
*@swf_asset.canvas_movie_sprite_urls,
# For images, `images.neopets.com` is a generally safe host to load
# from (shouldn't be a vulnerable site or exfiltration vector), and
# doing this can help make this header a *lot* shorter, which helps
# our nginx reverse proxy (and probably some clients) handle it. (For
# example, see asset `667993` for "Engulfed in Flames Effect".)
hosts: ["https://images.neopets.com"],
)
}
policy.script_src -> {
src_list(
helpers.javascript_url("lib/easeljs.min"),
helpers.javascript_url("lib/tweenjs.min"),
helpers.javascript_url("swf_assets/show"),
@swf_asset.canvas_movie_library_url,
)
}
policy.style_src -> {
src_list(
helpers.stylesheet_url("swf_assets/show"),
)
}
end
def show
@swf_asset = SwfAsset.find params[:id]
render layout: nil
end
private
def src_list(*urls, hosts: [])
urls.
# Ignore any `nil`s that might arise
filter(&:present?).
# Remove query strings from URLs (they're invalid in CSPs)
map { |url| url.sub(/\?.*\z/, "") }.
# For the given `hosts`, remove all their specific URLs, and just list
# the host itself.
reject { |url| hosts.any? { |h| url.start_with? h } } + hosts
end
end