discourse/spec/integration/secure_uploads_spec.rb
Martin Brennan 4d2a95ffe6
FIX: Query UploadReference in UploadSecurity for existing uploads (#19917)
This fixes a longstanding issue for sites with the
secure_uploads setting enabled. What would happen is a scenario
like this, since we did not check all places an upload could be
linked to whenever we used UploadSecurity to check whether an
upload should be secure:

* Upload is created and used for site setting, set to secure: false
  since site setting uploads should not be secure. Let's say favicon
* Favicon for the site is used inside a post in a private category,
  e.g. via a Onebox
* We changed the secure status for the upload to true, since it's been
  used in a private category and we don't check if it's originator
  was a public place
* The site favicon breaks :'(

This was a source of constant consternation. Now, when an upload is _not_
being created, and we are checking if an existing upload should be
secure, we now check to see what the first record in the UploadReference
table is for that upload. If it's something public like a site setting,
then we will never change the upload to `secure`.
2023-01-20 10:24:52 +10:00

125 lines
3.9 KiB
Ruby

# frozen_string_literal: true
describe "Secure uploads" do
fab!(:user) { Fabricate(:user) }
fab!(:group) { Fabricate(:group) }
fab!(:secure_category) { Fabricate(:private_category, group: group) }
before do
Jobs.run_immediately!
# this is done so the after_save callbacks for site settings to make
# UploadReference records works
@original_provider = SiteSetting.provider
SiteSetting.provider = SiteSettings::DbProvider.new(SiteSetting)
setup_s3
stub_s3_store
SiteSetting.secure_uploads = true
group.add(user)
user.reload
end
after { SiteSetting.provider = @original_provider }
def create_upload
filename = "logo.png"
file = file_from_fixtures(filename)
UploadCreator.new(file, filename).create_for(user.id)
end
def stub_presign_upload_get(upload)
# this is necessary because by default any upload inside a secure post is considered "secure"
# for the purposes of fetching hotlinked images until proven otherwise, and this is easier
# than trying to stub the presigned URL for s3 in a different way
stub_request(:get, "https:#{upload.url}").to_return(
status: 200,
body: file_from_fixtures("logo.png"),
)
Upload.stubs(:signed_url_from_secure_uploads_url).returns("https:#{upload.url}")
end
it "does not convert an upload to secure when it was first used in a site setting then in a post" do
upload = create_upload
SiteSetting.favicon = upload
expect(upload.reload.upload_references.count).to eq(1)
create_post(
title: "Secure upload post",
raw: "This is a new post <img src=\"#{upload.url}\" />",
category: secure_category,
user: user,
)
upload.reload
expect(upload.upload_references.count).to eq(2)
expect(upload.secure).to eq(false)
end
it "does not convert an upload to insecure when it was first used in a secure post then a site setting" do
upload = create_upload
create_post(
title: "Secure upload post",
raw: "This is a new post <img src=\"#{upload.url}\" />",
category: secure_category,
user: user,
)
expect(upload.reload.upload_references.count).to eq(1)
SiteSetting.favicon = upload
upload.reload
expect(upload.upload_references.count).to eq(2)
expect(upload.secure).to eq(true)
end
it "does not convert an upload to secure when it was first used in a public post then in a secure post" do
upload = create_upload
post =
create_post(
title: "Public upload post",
raw: "This is a new post <img src=\"#{upload.url}\" />",
user: user,
)
upload.reload
expect(upload.upload_references.count).to eq(1)
expect(upload.secure).to eq(false)
expect(upload.access_control_post).to eq(post)
stub_presign_upload_get(upload)
create_post(
title: "Secure upload post",
raw: "This is a new post <img src=\"#{upload.url}\" />",
category: secure_category,
user: user,
)
upload.reload
expect(upload.upload_references.count).to eq(2)
expect(upload.secure).to eq(false)
expect(upload.access_control_post).to eq(post)
end
it "does not convert an upload to insecure when it was first used in a secure post then in a public post" do
upload = create_upload
stub_presign_upload_get(upload)
post =
create_post(
title: "Secure upload post",
raw: "This is a new post <img src=\"#{upload.url}\" />",
category: secure_category,
user: user,
)
upload.reload
expect(upload.upload_references.count).to eq(1)
expect(upload.secure).to eq(true)
expect(upload.access_control_post).to eq(post)
create_post(
title: "Public upload post",
raw: "This is a new post <img src=\"#{upload.url}\" />",
user: user,
)
upload.reload
expect(upload.upload_references.count).to eq(2)
expect(upload.secure).to eq(true)
expect(upload.access_control_post).to eq(post)
end
end