From 94ba297c43f5cf432ea7213cd879d4590f2d8cb8 Mon Sep 17 00:00:00 2001 From: Joshua Wehner Date: Wed, 17 May 2023 23:09:47 +0200 Subject: [PATCH] Fix mangled github image embed (#19455) --- app/services/html/image_uri.rb | 43 ++++++++++++++++++++++++++++ app/services/html/parser.rb | 3 +- spec/services/html/image_uri_spec.rb | 36 +++++++++++++++++++++++ 3 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 app/services/html/image_uri.rb create mode 100644 spec/services/html/image_uri_spec.rb diff --git a/app/services/html/image_uri.rb b/app/services/html/image_uri.rb new file mode 100644 index 000000000..91dc64f2a --- /dev/null +++ b/app/services/html/image_uri.rb @@ -0,0 +1,43 @@ +module Html + class ImageUri + GITHUB_CAMO = { + scheme: "https", + host: "camo.githubusercontent.com" + }.freeze + + GITHUB_BADGE = { + scheme: "https", + host: "github.com", + filename: "badge.svg" + }.freeze + + attr_reader :uri, :original_source + + delegate :scheme, :host, :path, to: :uri + + def initialize(src) + @uri = URI(src) + @original_source = src + end + + def allowed? + github_camo_user_content? || github_badge? + end + + def github_badge? + scheme == GITHUB_BADGE[:scheme] && + host == GITHUB_BADGE[:host] && + filename == GITHUB_BADGE[:filename] + end + + def github_camo_user_content? + scheme == GITHUB_CAMO[:scheme] && host == GITHUB_CAMO[:host] + end + + private + + def filename + File.basename path + end + end +end diff --git a/app/services/html/parser.rb b/app/services/html/parser.rb index 5de8a5ac0..5d7d32b39 100644 --- a/app/services/html/parser.rb +++ b/app/services/html/parser.rb @@ -270,8 +270,7 @@ module Html end def allowed_image_host?(src) - # GitHub camo image won't parse but should be safe to host direct - src.start_with?("https://camo.githubusercontent.com") + ImageUri.new(src).allowed? end def user_link_if_exists(mention) diff --git a/spec/services/html/image_uri_spec.rb b/spec/services/html/image_uri_spec.rb new file mode 100644 index 000000000..e9f79a05c --- /dev/null +++ b/spec/services/html/image_uri_spec.rb @@ -0,0 +1,36 @@ +require "rails_helper" + +RSpec.describe Html::ImageUri, type: :service do + let(:camo) { "https://camo.githubusercontent.com/64b9f7c7c5f41ec22113b61235256435cd61779a0554b0595b88b6011f94c60b/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f636f6d6d69742d61637469766974792f772f666f72656d2f666f72656d" } + let(:badge) { "https://github.com/forem/forem/actions/workflows/ci-cd.yml/badge.svg?branch=depfu/update/sterile-1.0.24" } + let(:giphy) { "https://media.giphy.com/media/3ow0TN2M8TH2aAn67F/giphy.gif" } + let(:other) { "https://image.com/image.jpg" } + + it "can detect camo.github hosted image" do + image = described_class.new(camo) + expect(image).to be_github_camo_user_content + + image = described_class.new(badge) + expect(image).not_to be_github_camo_user_content + + image = described_class.new(giphy) + expect(image).not_to be_github_camo_user_content + + image = described_class.new(other) + expect(image).not_to be_github_camo_user_content + end + + it "can detect github hosted badge" do + image = described_class.new(badge) + expect(image).to be_github_badge + + image = described_class.new(camo) + expect(image).not_to be_github_badge + + image = described_class.new(giphy) + expect(image).not_to be_github_badge + + image = described_class.new(other) + expect(image).not_to be_github_badge + end +end