DEV: Rename secure_media to secure_uploads (#18376)

This commit renames all secure_media related settings to secure_uploads_* along with the associated functionality.

This is being done because "media" does not really cover it, we aren't just doing this for images and videos etc. but for all uploads in the site.

Additionally, in future we want to secure more types of uploads, and enable a kind of "mixed mode" where some uploads are secure and some are not, so keeping media in the name is just confusing.

This also keeps compatibility with the `secure-media-uploads` path, and changes new
secure URLs to be `secure-uploads`.

Deprecated settings:

* secure_media -> secure_uploads
* secure_media_allow_embed_images_in_emails -> secure_uploads_allow_embed_images_in_emails
* secure_media_max_email_embed_image_size_kb -> secure_uploads_max_email_embed_image_size_kb
This commit is contained in:
Martin Brennan 2022-09-29 09:24:33 +10:00 committed by GitHub
parent 70b96ac4e7
commit 8ebd5edd1e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
67 changed files with 442 additions and 361 deletions

View File

@ -21,8 +21,8 @@ export function nativeLazyLoading(api) {
// Support for smallUpload should be maintained until Post::BAKED_VERSION is bumped higher than 2 // Support for smallUpload should be maintained until Post::BAKED_VERSION is bumped higher than 2
const { smallUpload, dominantColor } = img.dataset; const { smallUpload, dominantColor } = img.dataset;
if (siteSettings.secure_media && smallUpload) { if (siteSettings.secure_uploads && smallUpload) {
// Secure media requests go through the app. In topics with many images, // Secure uploads requests go through the app. In topics with many images,
// this makes it very easy to hit rate limiters. Skipping the low-res // this makes it very easy to hit rate limiters. Skipping the low-res
// placeholders reduces the chance of this problem occuring. // placeholders reduces the chance of this problem occuring.
return; return;

View File

@ -19,6 +19,7 @@ const SERVER_SIDE_ONLY = [
/^\/assets\//, /^\/assets\//,
/^\/uploads\//, /^\/uploads\//,
/^\/secure-media-uploads\//, /^\/secure-media-uploads\//,
/^\/secure-uploads\//,
/^\/stylesheets\//, /^\/stylesheets\//,
/^\/site_customizations\//, /^\/site_customizations\//,
/^\/raw\//, /^\/raw\//,

View File

@ -97,7 +97,7 @@ const ORIGINAL_SETTINGS = {
enable_personal_messages: true, enable_personal_messages: true,
personal_message_enabled_groups: "11", // TL1 group personal_message_enabled_groups: "11", // TL1 group
unicode_usernames: false, unicode_usernames: false,
secure_media: false, secure_uploads: false,
external_emoji_url: "", external_emoji_url: "",
remove_muted_tags_from_latest: "always", remove_muted_tags_from_latest: "always",
enable_group_directory: true, enable_group_directory: true,

View File

@ -997,12 +997,12 @@ eviltrout</p>
); );
}); });
test("attachment - mapped url - secure media disabled", function (assert) { test("attachment - mapped url - secure uploads disabled", function (assert) {
function lookupUploadUrls() { function lookupUploadUrls() {
let cache = {}; let cache = {};
cache["upload://o8iobpLcW3WSFvVH7YQmyGlKmGM.pdf"] = { cache["upload://o8iobpLcW3WSFvVH7YQmyGlKmGM.pdf"] = {
short_url: "upload://o8iobpLcW3WSFvVH7YQmyGlKmGM.pdf", short_url: "upload://o8iobpLcW3WSFvVH7YQmyGlKmGM.pdf",
url: "/secure-media-uploads/original/3X/c/b/o8iobpLcW3WSFvVH7YQmyGlKmGM.pdf", url: "/secure-uploads/original/3X/c/b/o8iobpLcW3WSFvVH7YQmyGlKmGM.pdf",
short_path: "/uploads/short-url/blah", short_path: "/uploads/short-url/blah",
}; };
return cache; return cache;
@ -1010,20 +1010,20 @@ eviltrout</p>
assert.cookedOptions( assert.cookedOptions(
"[test.pdf|attachment](upload://o8iobpLcW3WSFvVH7YQmyGlKmGM.pdf)", "[test.pdf|attachment](upload://o8iobpLcW3WSFvVH7YQmyGlKmGM.pdf)",
{ {
siteSettings: { secure_media: false }, siteSettings: { secure_uploads: false },
lookupUploadUrls, lookupUploadUrls,
}, },
`<p><a class="attachment" href="/uploads/short-url/blah">test.pdf</a></p>`, `<p><a class="attachment" href="/uploads/short-url/blah">test.pdf</a></p>`,
"It returns the correct attachment link HTML when the URL is mapped without secure media" "It returns the correct attachment link HTML when the URL is mapped without secure uploads"
); );
}); });
test("attachment - mapped url - secure media enabled", function (assert) { test("attachment - mapped url - secure uploads enabled", function (assert) {
function lookupUploadUrls() { function lookupUploadUrls() {
let cache = {}; let cache = {};
cache["upload://o8iobpLcW3WSFvVH7YQmyGlKmGM.pdf"] = { cache["upload://o8iobpLcW3WSFvVH7YQmyGlKmGM.pdf"] = {
short_url: "upload://o8iobpLcW3WSFvVH7YQmyGlKmGM.pdf", short_url: "upload://o8iobpLcW3WSFvVH7YQmyGlKmGM.pdf",
url: "/secure-media-uploads/original/3X/c/b/o8iobpLcW3WSFvVH7YQmyGlKmGM.pdf", url: "/secure-uploads/original/3X/c/b/o8iobpLcW3WSFvVH7YQmyGlKmGM.pdf",
short_path: "/uploads/short-url/blah", short_path: "/uploads/short-url/blah",
}; };
return cache; return cache;
@ -1031,11 +1031,11 @@ eviltrout</p>
assert.cookedOptions( assert.cookedOptions(
"[test.pdf|attachment](upload://o8iobpLcW3WSFvVH7YQmyGlKmGM.pdf)", "[test.pdf|attachment](upload://o8iobpLcW3WSFvVH7YQmyGlKmGM.pdf)",
{ {
siteSettings: { secure_media: true }, siteSettings: { secure_uploads: true },
lookupUploadUrls, lookupUploadUrls,
}, },
`<p><a class="attachment" href="/secure-media-uploads/original/3X/c/b/o8iobpLcW3WSFvVH7YQmyGlKmGM.pdf">test.pdf</a></p>`, `<p><a class="attachment" href="/secure-uploads/original/3X/c/b/o8iobpLcW3WSFvVH7YQmyGlKmGM.pdf">test.pdf</a></p>`,
"It returns the correct attachment link HTML when the URL is mapped with secure media" "It returns the correct attachment link HTML when the URL is mapped with secure uploads"
); );
}); });
@ -1052,12 +1052,12 @@ eviltrout</p>
); );
}); });
test("video - mapped url - secure media enabled", function (assert) { test("video - mapped url - secure uploads enabled", function (assert) {
function lookupUploadUrls() { function lookupUploadUrls() {
let cache = {}; let cache = {};
cache["upload://eyPnj7UzkU0AkGkx2dx8G4YM1Jx.mp4"] = { cache["upload://eyPnj7UzkU0AkGkx2dx8G4YM1Jx.mp4"] = {
short_url: "upload://eyPnj7UzkU0AkGkx2dx8G4YM1Jx.mp4", short_url: "upload://eyPnj7UzkU0AkGkx2dx8G4YM1Jx.mp4",
url: "/secure-media-uploads/original/3X/c/b/test.mp4", url: "/secure-uploads/original/3X/c/b/test.mp4",
short_path: "/uploads/short-url/blah", short_path: "/uploads/short-url/blah",
}; };
return cache; return cache;
@ -1065,16 +1065,16 @@ eviltrout</p>
assert.cookedOptions( assert.cookedOptions(
"![baby shark|video](upload://eyPnj7UzkU0AkGkx2dx8G4YM1Jx.mp4)", "![baby shark|video](upload://eyPnj7UzkU0AkGkx2dx8G4YM1Jx.mp4)",
{ {
siteSettings: { secure_media: true }, siteSettings: { secure_uploads: true },
lookupUploadUrls, lookupUploadUrls,
}, },
`<p><div class="video-container"> `<p><div class="video-container">
<video width="100%" height="100%" preload="metadata" controls> <video width="100%" height="100%" preload="metadata" controls>
<source src="/secure-media-uploads/original/3X/c/b/test.mp4"> <source src="/secure-uploads/original/3X/c/b/test.mp4">
<a href="/secure-media-uploads/original/3X/c/b/test.mp4">/secure-media-uploads/original/3X/c/b/test.mp4</a> <a href="/secure-uploads/original/3X/c/b/test.mp4">/secure-uploads/original/3X/c/b/test.mp4</a>
</video> </video>
</div></p>`, </div></p>`,
"It returns the correct video HTML when the URL is mapped with secure media, removing data-orig-src" "It returns the correct video HTML when the URL is mapped with secure uploads, removing data-orig-src"
); );
}); });
@ -1089,12 +1089,12 @@ eviltrout</p>
); );
}); });
test("audio - mapped url - secure media enabled", function (assert) { test("audio - mapped url - secure uploads enabled", function (assert) {
function lookupUploadUrls() { function lookupUploadUrls() {
let cache = {}; let cache = {};
cache["upload://eyPnj7UzkU0AkGkx2dx8G4YM1Jx.mp3"] = { cache["upload://eyPnj7UzkU0AkGkx2dx8G4YM1Jx.mp3"] = {
short_url: "upload://eyPnj7UzkU0AkGkx2dx8G4YM1Jx.mp3", short_url: "upload://eyPnj7UzkU0AkGkx2dx8G4YM1Jx.mp3",
url: "/secure-media-uploads/original/3X/c/b/test.mp3", url: "/secure-uploads/original/3X/c/b/test.mp3",
short_path: "/uploads/short-url/blah", short_path: "/uploads/short-url/blah",
}; };
return cache; return cache;
@ -1102,14 +1102,14 @@ eviltrout</p>
assert.cookedOptions( assert.cookedOptions(
"![baby shark|audio](upload://eyPnj7UzkU0AkGkx2dx8G4YM1Jx.mp3)", "![baby shark|audio](upload://eyPnj7UzkU0AkGkx2dx8G4YM1Jx.mp3)",
{ {
siteSettings: { secure_media: true }, siteSettings: { secure_uploads: true },
lookupUploadUrls, lookupUploadUrls,
}, },
`<p><audio preload="metadata" controls> `<p><audio preload="metadata" controls>
<source src="/secure-media-uploads/original/3X/c/b/test.mp3"> <source src="/secure-uploads/original/3X/c/b/test.mp3">
<a href="/secure-media-uploads/original/3X/c/b/test.mp3">/secure-media-uploads/original/3X/c/b/test.mp3</a> <a href="/secure-uploads/original/3X/c/b/test.mp3">/secure-uploads/original/3X/c/b/test.mp3</a>
</audio></p>`, </audio></p>`,
"It returns the correct audio HTML when the URL is mapped with secure media, removing data-orig-src" "It returns the correct audio HTML when the URL is mapped with secure uploads, removing data-orig-src"
); );
}); });

View File

@ -96,7 +96,7 @@ module("Unit | Utility | pretty-text/upload-short-url", function (hooks) {
lookup = lookupCachedUploadUrl("upload://a.jpeg"); lookup = lookupCachedUploadUrl("upload://a.jpeg");
assert.deepEqual(lookup, {}); assert.deepEqual(lookup, {});
await resolveAllShortUrls(ajax, { secure_media: false }, fixture()); await resolveAllShortUrls(ajax, { secure_uploads: false }, fixture());
await settled(); await settled();
lookup = lookupCachedUploadUrl("upload://a.jpeg"); lookup = lookupCachedUploadUrl("upload://a.jpeg");
@ -143,7 +143,7 @@ module("Unit | Utility | pretty-text/upload-short-url", function (hooks) {
test("resolveAllShortUrls - href + src replaced correctly", async function (assert) { test("resolveAllShortUrls - href + src replaced correctly", async function (assert) {
stubUrls(); stubUrls();
await resolveAllShortUrls(ajax, { secure_media: false }, fixture()); await resolveAllShortUrls(ajax, { secure_uploads: false }, fixture());
await settled(); await settled();
let image1 = fixture().querySelector("img"); let image1 = fixture().querySelector("img");
@ -167,7 +167,7 @@ module("Unit | Utility | pretty-text/upload-short-url", function (hooks) {
test("resolveAllShortUrls - url with full origin replaced correctly", async function (assert) { test("resolveAllShortUrls - url with full origin replaced correctly", async function (assert) {
stubUrls(); stubUrls();
await resolveAllShortUrls(ajax, { secure_media: false }, fixture()); await resolveAllShortUrls(ajax, { secure_uploads: false }, fixture());
await settled(); await settled();
let video = fixture().querySelectorAll("video")[1]; let video = fixture().querySelectorAll("video")[1];
@ -177,25 +177,25 @@ module("Unit | Utility | pretty-text/upload-short-url", function (hooks) {
); );
}); });
test("resolveAllShortUrls - when secure media is enabled use the attachment full URL", async function (assert) { test("resolveAllShortUrls - when secure uploads is enabled use the attachment full URL", async function (assert) {
stubUrls( stubUrls(
null, null,
[ [
{ {
short_url: "upload://c.pdf", short_url: "upload://c.pdf",
url: "/secure-media-uploads/default/original/3X/c/b/3.pdf", url: "/secure-uploads/default/original/3X/c/b/3.pdf",
short_path: "/uploads/short-url/c.pdf", short_path: "/uploads/short-url/c.pdf",
}, },
], ],
null null
); );
await resolveAllShortUrls(ajax, { secure_media: true }, fixture()); await resolveAllShortUrls(ajax, { secure_uploads: true }, fixture());
await settled(); await settled();
let link = fixture().querySelector("a"); let link = fixture().querySelector("a");
assert.strictEqual( assert.strictEqual(
link.getAttribute("href"), link.getAttribute("href"),
"/secure-media-uploads/default/original/3X/c/b/3.pdf" "/secure-uploads/default/original/3X/c/b/3.pdf"
); );
}); });

View File

@ -143,14 +143,12 @@ module("Unit | Utility | url", function () {
); );
}); });
test("routeTo redirects secure media URLS because they are server side only", async function (assert) { test("routeTo redirects secure uploads URLS because they are server side only", async function (assert) {
sinon.stub(DiscourseURL, "redirectTo"); sinon.stub(DiscourseURL, "redirectTo");
sinon.stub(DiscourseURL, "handleURL"); sinon.stub(DiscourseURL, "handleURL");
DiscourseURL.routeTo("/secure-media-uploads/original/1X/test.pdf"); DiscourseURL.routeTo("/secure-uploads/original/1X/test.pdf");
assert.ok( assert.ok(
DiscourseURL.redirectTo.calledWith( DiscourseURL.redirectTo.calledWith("/secure-uploads/original/1X/test.pdf")
"/secure-media-uploads/original/1X/test.pdf"
)
); );
}); });

View File

@ -525,7 +525,7 @@ export function setup(opts, siteSettings, state) {
getOptions.f = () => opts.discourse; getOptions.f = () => opts.discourse;
opts.discourse.limitedSiteSettings = { opts.discourse.limitedSiteSettings = {
secureMedia: siteSettings.secure_media, secureUploads: siteSettings.secure_uploads,
enableDiffhtmlPreview: siteSettings.enable_diffhtml_preview, enableDiffhtmlPreview: siteSettings.enable_diffhtml_preview,
traditionalMarkdownLinebreaks: siteSettings.traditional_markdown_linebreaks, traditionalMarkdownLinebreaks: siteSettings.traditional_markdown_linebreaks,
enableMarkdownLinkify: siteSettings.enable_markdown_linkify, enableMarkdownLinkify: siteSettings.enable_markdown_linkify,

View File

@ -112,11 +112,12 @@ function getAttributeBasedUrl(dataAttribute, cachedUpload, siteSettings) {
return cachedUpload.url; return cachedUpload.url;
} }
// attachments should use the full /secure-media-uploads/ URL // attachments should use the full /secure-media-uploads/ or
// in this case for permission checks // /secure-uploads/ URL in this case for permission checks
if ( if (
siteSettings.secure_media && siteSettings.secure_uploads &&
cachedUpload.url.includes("secure-media-uploads") (cachedUpload.url.includes("secure-media-uploads") ||
cachedUpload.url.includes("secure-uploads"))
) { ) {
return cachedUpload.url; return cachedUpload.url;
} }

View File

@ -136,11 +136,12 @@ function rule(state) {
} }
} else if (token.tag === "a") { } else if (token.tag === "a") {
if (mapped) { if (mapped) {
// when secure media is enabled we want the full /secure-media-uploads/ // when secure uploads is enabled we want the full /secure-media-uploads or /secure-uploads
// url to take advantage of access control security // url to take advantage of access control security
if ( if (
state.md.options.discourse.limitedSiteSettings.secureMedia && state.md.options.discourse.limitedSiteSettings.secureUploads &&
mapped.url.includes("secure-media-uploads") (mapped.url.includes("secure-media-uploads") ||
mapped.url.includes("secure-uploads"))
) { ) {
token.attrs[srcIndex][1] = mapped.url; token.attrs[srcIndex][1] = mapped.url;
} else { } else {

View File

@ -28,7 +28,7 @@ workbox.routing.registerRoute(
plugins: [ plugins: [
new workbox.cacheableResponse.Plugin({ new workbox.cacheableResponse.Plugin({
statuses: [200] // opaque responses will return status code '0' statuses: [200] // opaque responses will return status code '0'
}), // for s3 secure media signed urls }), // for s3 secure uploads signed urls
new workbox.expiration.Plugin({ new workbox.expiration.Plugin({
maxAgeSeconds: 7* 24 * 60 * 60, // 7 days maxAgeSeconds: 7* 24 * 60 * 60, // 7 days
maxEntries: 250, maxEntries: 250,

View File

@ -94,7 +94,7 @@ private
end end
def ensure_publish_enabled def ensure_publish_enabled
if !SiteSetting.enable_page_publishing? || SiteSetting.secure_media if !SiteSetting.enable_page_publishing? || SiteSetting.secure_uploads
raise Discourse::NotFound raise Discourse::NotFound
end end
end end

View File

@ -5,13 +5,13 @@ require "mini_mime"
class UploadsController < ApplicationController class UploadsController < ApplicationController
include ExternalUploadHelpers include ExternalUploadHelpers
requires_login except: [:show, :show_short, :show_secure] requires_login except: [:show, :show_short, :_show_secure_deprecated, :show_secure]
skip_before_action :preload_json, :check_xhr, :redirect_to_login_if_required, only: [:show, :show_short, :show_secure] skip_before_action :preload_json, :check_xhr, :redirect_to_login_if_required, only: [:show, :show_short, :_show_secure_deprecated, :show_secure]
protect_from_forgery except: :show protect_from_forgery except: :show
before_action :is_asset_path, :apply_cdn_headers, only: [:show, :show_short, :show_secure] before_action :is_asset_path, :apply_cdn_headers, only: [:show, :show_short, :_show_secure_deprecated, :show_secure]
before_action :external_store_check, only: [:show_secure] before_action :external_store_check, only: [:_show_secure_deprecated, :show_secure]
SECURE_REDIRECT_GRACE_SECONDS = 5 SECURE_REDIRECT_GRACE_SECONDS = 5
@ -111,7 +111,7 @@ class UploadsController < ApplicationController
sha1 = Upload.sha1_from_base62_encoded(params[:base62]) sha1 = Upload.sha1_from_base62_encoded(params[:base62])
if upload = Upload.find_by(sha1: sha1) if upload = Upload.find_by(sha1: sha1)
if upload.secure? && SiteSetting.secure_media? if upload.secure? && SiteSetting.secure_uploads?
return handle_secure_upload_request(upload) return handle_secure_upload_request(upload)
end end
@ -125,6 +125,13 @@ class UploadsController < ApplicationController
end end
end end
# Kept to avoid rebaking old posts with /show-secure-uploads/ in their
# contents, this will ensure the uploads in these posts continue to
# work in future.
def _show_secure_deprecated
show_secure
end
def show_secure def show_secure
# do not serve uploads requested via XHR to prevent XSS # do not serve uploads requested via XHR to prevent XSS
return xhr_not_allowed if request.xhr? return xhr_not_allowed if request.xhr?
@ -139,9 +146,9 @@ class UploadsController < ApplicationController
return render_404 if upload.blank? return render_404 if upload.blank?
return render_404 if SiteSetting.prevent_anons_from_downloading_files && current_user.nil? return render_404 if SiteSetting.prevent_anons_from_downloading_files && current_user.nil?
return handle_secure_upload_request(upload, path_with_ext) if SiteSetting.secure_media? return handle_secure_upload_request(upload, path_with_ext) if SiteSetting.secure_uploads?
# we don't want to 404 here if secure media gets disabled # we don't want to 404 here if secure uploads gets disabled
# because all posts with secure uploads will show broken media # because all posts with secure uploads will show broken media
# until rebaked, which could take some time # until rebaked, which could take some time
# #

View File

@ -67,6 +67,10 @@ module EmailHelper
border-color: #454545 !important; border-color: #454545 !important;
} }
[data-stripped-secure-upload] {
border-color: #454545 !important;
}
[dm='text-color'] { [dm='text-color'] {
color: #dddddd; color: #dddddd;
} }

View File

@ -108,9 +108,9 @@ module Jobs
class UploadCreateError < StandardError; end class UploadCreateError < StandardError; end
def attempt_download(src, user_id) def attempt_download(src, user_id)
# secure-media-uploads endpoint prevents anonymous downloads, so we # secure-uploads endpoint prevents anonymous downloads, so we
# need the presigned S3 URL here # need the presigned S3 URL here
src = Upload.signed_url_from_secure_media_url(src) if Upload.secure_media_url?(src) src = Upload.signed_url_from_secure_uploads_url(src) if Upload.secure_uploads_url?(src)
hotlinked = download(src) hotlinked = download(src)
raise ImageBrokenError if !hotlinked raise ImageBrokenError if !hotlinked
@ -147,7 +147,7 @@ module Jobs
].compact.map { |s| normalize_src(s) } ].compact.map { |s| normalize_src(s) }
if Discourse.store.has_been_uploaded?(src) || normalize_src(src).start_with?(*local_bases) || src =~ /\A\/[^\/]/i if Discourse.store.has_been_uploaded?(src) || normalize_src(src).start_with?(*local_bases) || src =~ /\A\/[^\/]/i
return false if !(src =~ /\/uploads\// || Upload.secure_media_url?(src)) return false if !(src =~ /\/uploads\// || Upload.secure_uploads_url?(src))
# Someone could hotlink a file from a different site on the same CDN, # Someone could hotlink a file from a different site on the same CDN,
# so check whether we have it in this database # so check whether we have it in this database

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
module Jobs module Jobs
# Sometimes we need to update a _lot_ of ACLs on S3 (such as when secure media # Sometimes we need to update a _lot_ of ACLs on S3 (such as when secure uploads
# is enabled), and since it takes ~1s per upload to update the ACL, this is # is enabled), and since it takes ~1s per upload to update the ACL, this is
# best spread out over many jobs instead of having to do the whole thing serially. # best spread out over many jobs instead of having to do the whole thing serially.
class SyncAclsForUploads < ::Jobs::Base class SyncAclsForUploads < ::Jobs::Base

View File

@ -309,7 +309,7 @@ class Post < ActiveRecord::Base
options[:user_id] = post_user.id if post_user options[:user_id] = post_user.id if post_user
options[:omit_nofollow] = true if omit_nofollow? options[:omit_nofollow] = true if omit_nofollow?
if self.with_secure_media? if self.with_secure_uploads?
each_upload_url do |url| each_upload_url do |url|
uri = URI.parse(url) uri = URI.parse(url)
if FileHelper.is_supported_media?(File.basename(uri.path)) if FileHelper.is_supported_media?(File.basename(uri.path))
@ -517,8 +517,8 @@ class Post < ActiveRecord::Base
ReviewableFlaggedPost.pending.find_by(target: self) ReviewableFlaggedPost.pending.find_by(target: self)
end end
def with_secure_media? def with_secure_uploads?
return false if !SiteSetting.secure_media? return false if !SiteSetting.secure_uploads?
SiteSetting.login_required? || \ SiteSetting.login_required? || \
(topic.present? && (topic.private_message? || topic.category&.read_restricted)) (topic.present? && (topic.private_message? || topic.category&.read_restricted))
end end
@ -971,7 +971,7 @@ class Post < ActiveRecord::Base
UploadReference.where(target: self).delete_all UploadReference.where(target: self).delete_all
UploadReference.insert_all(upload_references) if upload_references.size > 0 UploadReference.insert_all(upload_references) if upload_references.size > 0
if SiteSetting.secure_media? if SiteSetting.secure_uploads?
Upload.where( Upload.where(
id: upload_ids, access_control_post_id: nil id: upload_ids, access_control_post_id: nil
).where( ).where(
@ -1033,7 +1033,7 @@ class Post < ActiveRecord::Base
next if Rails.configuration.multisite && src.exclude?(current_db) next if Rails.configuration.multisite && src.exclude?(current_db)
src = "#{SiteSetting.force_https ? "https" : "http"}:#{src}" if src.start_with?("//") src = "#{SiteSetting.force_https ? "https" : "http"}:#{src}" if src.start_with?("//")
next unless Discourse.store.has_been_uploaded?(src) || Upload.secure_media_url?(src) || (include_local_upload && src =~ /\A\/[^\/]/i) next unless Discourse.store.has_been_uploaded?(src) || Upload.secure_uploads_url?(src) || (include_local_upload && src =~ /\A\/[^\/]/i)
path = begin path = begin
URI(UrlHelper.unencode(GlobalSetting.cdn_url ? src.sub(GlobalSetting.cdn_url, "") : src))&.path URI(UrlHelper.unencode(GlobalSetting.cdn_url ? src.sub(GlobalSetting.cdn_url, "") : src))&.path

View File

@ -186,7 +186,7 @@ class Upload < ActiveRecord::Base
"upload://#{short_url_basename}" "upload://#{short_url_basename}"
end end
def uploaded_before_secure_media_enabled? def uploaded_before_secure_uploads_enabled?
original_sha1.blank? original_sha1.blank?
end end
@ -204,14 +204,14 @@ class Upload < ActiveRecord::Base
end end
def self.consider_for_reuse(upload, post) def self.consider_for_reuse(upload, post)
return upload if !SiteSetting.secure_media? || upload.blank? || post.blank? return upload if !SiteSetting.secure_uploads? || upload.blank? || post.blank?
return nil if !upload.matching_access_control_post?(post) || upload.uploaded_before_secure_media_enabled? return nil if !upload.matching_access_control_post?(post) || upload.uploaded_before_secure_uploads_enabled?
upload upload
end end
def self.secure_media_url?(url) def self.secure_uploads_url?(url)
# we do not want to exclude topic links that for whatever reason # we do not want to exclude topic links that for whatever reason
# have secure-media-uploads in the URL e.g. /t/secure-media-uploads-are-cool/223452 # have secure-uploads in the URL e.g. /t/secure-uploads-are-cool/223452
route = UrlHelper.rails_route_from_url(url) route = UrlHelper.rails_route_from_url(url)
return false if route.blank? return false if route.blank?
route[:action] == "show_secure" && route[:controller] == "uploads" && FileHelper.is_supported_media?(url) route[:action] == "show_secure" && route[:controller] == "uploads" && FileHelper.is_supported_media?(url)
@ -219,14 +219,14 @@ class Upload < ActiveRecord::Base
false false
end end
def self.signed_url_from_secure_media_url(url) def self.signed_url_from_secure_uploads_url(url)
route = UrlHelper.rails_route_from_url(url) route = UrlHelper.rails_route_from_url(url)
url = Rails.application.routes.url_for(route.merge(only_path: true)) url = Rails.application.routes.url_for(route.merge(only_path: true))
secure_upload_s3_path = url[url.index(route[:path])..-1] secure_upload_s3_path = url[url.index(route[:path])..-1]
Discourse.store.signed_url_for_path(secure_upload_s3_path) Discourse.store.signed_url_for_path(secure_upload_s3_path)
end end
def self.secure_media_url_from_upload_url(url) def self.secure_uploads_url_from_upload_url(url)
return url if !url.include?(SiteSetting.Upload.absolute_base_url) return url if !url.include?(SiteSetting.Upload.absolute_base_url)
uri = URI.parse(url) uri = URI.parse(url)
Rails.application.routes.url_for( Rails.application.routes.url_for(

View File

@ -290,7 +290,7 @@ class TopicViewSerializer < ApplicationSerializer
SiteSetting.enable_page_publishing? && SiteSetting.enable_page_publishing? &&
scope.is_staff? && scope.is_staff? &&
object.published_page.present? && object.published_page.present? &&
!SiteSetting.secure_media !SiteSetting.secure_uploads
end end
def thumbnails def thumbnails

View File

@ -17,6 +17,6 @@ class UploadSerializer < ApplicationSerializer
:dominant_color :dominant_color
def url def url
object.for_site_setting ? object.url : UrlHelper.cook_url(object.url, secure: SiteSetting.secure_media? && object.secure) object.for_site_setting ? object.url : UrlHelper.cook_url(object.url, secure: SiteSetting.secure_uploads? && object.secure)
end end
end end

View File

@ -45,6 +45,7 @@ if defined?(Rack::MiniProfiler) && defined?(Rack::MiniProfiler::Config)
/^\/site_customizations/, /^\/site_customizations/,
/^\/uploads/, /^\/uploads/,
/^\/secure-media-uploads/, /^\/secure-media-uploads/,
/^\/secure-uploads/,
/^\/javascripts\//, /^\/javascripts\//,
/^\/images\//, /^\/images\//,
/^\/stylesheets\//, /^\/stylesheets\//,

View File

@ -139,7 +139,7 @@ en:
unsubscribe_not_allowed: "Happens when unsubscribing via email is not allowed for this user." unsubscribe_not_allowed: "Happens when unsubscribing via email is not allowed for this user."
email_not_allowed: "Happens when the email address is not on the allowlist or is on the blocklist." email_not_allowed: "Happens when the email address is not on the allowlist or is on the blocklist."
unrecognized_error: "Unrecognized Error" unrecognized_error: "Unrecognized Error"
secure_media_placeholder: "Redacted: This site has secure media enabled, visit the topic or click View Media to see the attached media." secure_uploads_placeholder: "Redacted: This site has secure uploads enabled, visit the topic or click View Media to see the attached uploads."
view_redacted_media: "View Media" view_redacted_media: "View Media"
errors: &errors errors: &errors
@ -210,7 +210,7 @@ en:
page_publishing_requirements: "Page publishing cannot be enabled if secure media is enabled." page_publishing_requirements: "Page publishing cannot be enabled if secure media is enabled."
s3_backup_requires_s3_settings: "You cannot use S3 as backup location unless you've provided the '%{setting_name}'." s3_backup_requires_s3_settings: "You cannot use S3 as backup location unless you've provided the '%{setting_name}'."
s3_bucket_reused: "You cannot use the same bucket for 's3_upload_bucket' and 's3_backup_bucket'. Choose a different bucket or use a different path for each bucket." s3_bucket_reused: "You cannot use the same bucket for 's3_upload_bucket' and 's3_backup_bucket'. Choose a different bucket or use a different path for each bucket."
secure_media_requirements: "S3 uploads must be enabled before enabling secure media." secure_uploads_requirements: "S3 uploads must be enabled before enabling secure uploads."
share_quote_facebook_requirements: "You must set a Facebook app id to enable quote sharing for Facebook." share_quote_facebook_requirements: "You must set a Facebook app id to enable quote sharing for Facebook."
second_factor_cannot_enforce_with_socials: "You cannot enforce 2FA with social logins enabled. You must first disable login via: %{auth_provider_names}" second_factor_cannot_enforce_with_socials: "You cannot enforce 2FA with social logins enabled. You must first disable login via: %{auth_provider_names}"
second_factor_cannot_be_enforced_with_disabled_local_login: "You cannot enforce 2FA if local logins are disabled." second_factor_cannot_be_enforced_with_disabled_local_login: "You cannot enforce 2FA if local logins are disabled."
@ -2219,9 +2219,12 @@ en:
bootstrap_mode_min_users: "Minimum number of users required to disable bootstrap mode (set to 0 to disable)" bootstrap_mode_min_users: "Minimum number of users required to disable bootstrap mode (set to 0 to disable)"
prevent_anons_from_downloading_files: "Prevent anonymous users from downloading attachments." prevent_anons_from_downloading_files: "Prevent anonymous users from downloading attachments."
secure_media: 'Limits access to ALL uploads (images, video, audio, text, pdfs, zips, and others). If “login required” is enabled, only logged-in users can access uploads. Otherwise, access will be limited only for media uploads in private messages and private categories. WARNING: This setting is complex and requires deep administrative understanding. See <a target="_blank" href="https://meta.discourse.org/t/secure-media-uploads/140017">the secure media topic on Meta</a> for details.' secure_media: 'DEPRECATED: Use the secure_uploads setting instead, will be removed in Discourse 3.0.'
secure_media_allow_embed_images_in_emails: "Allows embedding secure images that would normally be redacted in emails, if their size is smaller than the 'secure media max email embed image size kb' setting." secure_uploads: 'Limits access to ALL uploads (images, video, audio, text, pdfs, zips, and others). If "login required” is enabled, only logged-in users can access uploads. Otherwise, access will be limited only for media uploads in private messages and private categories. WARNING: This setting is complex and requires deep administrative understanding. See <a target="_blank" href="https://meta.discourse.org/t/-/140017">the secure uploads topic on Meta</a> for details.'
secure_media_max_email_embed_image_size_kb: "The size cutoff for secure images that will be embedded in emails if the 'secure media allow embed in emails' setting is enabled. Without that setting enabled, this setting has no effect." secure_media_allow_embed_images_in_emails: "DEPRECATED: Use secure_uploads_allow_embed_images_in_emails, will remove in Discourse 3.0."
secure_uploads_allow_embed_images_in_emails: "Allows embedding secure images that would normally be redacted in emails, if their size is smaller than the 'secure uploads max email embed image size kb' setting."
secure_media_max_email_embed_image_size_kb: "DEPRECATED: Use secure_uploads_max_email_embed_image_size_kb, will be removed in Discourse 3.0."
secure_uploads_max_email_embed_image_size_kb: "The size cutoff for secure images that will be embedded in emails if the 'secure uploads allow embed in emails' setting is enabled. Without that setting enabled, this setting has no effect."
slug_generation_method: "Choose a slug generation method. 'encoded' will generate percent encoding string. 'none' will disable slug at all." slug_generation_method: "Choose a slug generation method. 'encoded' will generate percent encoding string. 'none' will disable slug at all."
enable_emoji: "Enable emoji" enable_emoji: "Enable emoji"

View File

@ -110,7 +110,7 @@ server {
break; break;
} }
location ~ ^/secure-media-uploads/ { location ~ ^/(secure-media-uploads/|secure-uploads)/ {
proxy_set_header Host $http_host; proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Request-Start "t=${msec}"; proxy_set_header X-Request-Start "t=${msec}";

View File

@ -583,7 +583,12 @@ Discourse::Application.routes.draw do
end end
# used to download attachments (old route) # used to download attachments (old route)
get "uploads/:site/:id/:sha" => "uploads#show", constraints: { site: /\w+/, id: /\d+/, sha: /\h{16}/, format: /.*/ } get "uploads/:site/:id/:sha" => "uploads#show", constraints: { site: /\w+/, id: /\d+/, sha: /\h{16}/, format: /.*/ }
get "secure-media-uploads/*path(.:extension)" => "uploads#show_secure", constraints: { extension: /[a-z0-9\._]+/i }
# NOTE: secure-media-uploads is the old form, all new URLs generated for
# secure uploads will be secure-uploads, this is left in for backwards
# compat without needing to rebake all posts for each site.
get "secure-media-uploads/*path(.:extension)" => "uploads#_show_secure_deprecated", constraints: { extension: /[a-z0-9\._]+/i }
get "secure-uploads/*path(.:extension)" => "uploads#show_secure", constraints: { extension: /[a-z0-9\._]+/i }
get "posts" => "posts#latest", id: "latest_posts", constraints: { format: /(json|rss)/ } get "posts" => "posts#latest", id: "latest_posts", constraints: { format: /(json|rss)/ }
get "private-posts" => "posts#latest", id: "private_posts", constraints: { format: /(json|rss)/ } get "private-posts" => "posts#latest", id: "private_posts", constraints: { format: /(json|rss)/ }

View File

@ -1365,12 +1365,24 @@ files:
secure_media: secure_media:
default: false default: false
client: true client: true
hidden: true
secure_media_allow_embed_images_in_emails: secure_media_allow_embed_images_in_emails:
default: true default: true
hidden: true
secure_media_max_email_embed_image_size_kb: secure_media_max_email_embed_image_size_kb:
default: 1024 default: 1024
min: 1 min: 1
max: 10240 max: 10240
hidden: true
secure_uploads:
default: false
client: true
secure_uploads_allow_embed_images_in_emails:
default: true
secure_uploads_max_email_embed_image_size_kb:
default: 1024
min: 1
max: 10240
enable_s3_uploads: enable_s3_uploads:
default: false default: false
client: true client: true

View File

@ -0,0 +1,36 @@
# frozen_string_literal: true
class SetSecureUploadsSettingsBasedOnSecureMediaEquivalent < ActiveRecord::Migration[7.0]
def up
secure_media_enabled = DB.query_single("SELECT value FROM site_settings WHERE name = 'secure_media'")
if secure_media_enabled.present? && secure_media_enabled[0] == "t"
execute <<~SQL
INSERT INTO site_settings(name, data_type, value, created_at, updated_at)
VALUES ('secure_uploads', 5, 't', now(), now())
SQL
end
secure_media_allow_embed_images_in_emails = DB.query_single("SELECT value FROM site_settings WHERE name = 'secure_media_allow_embed_images_in_emails'")
if secure_media_allow_embed_images_in_emails.present? && secure_media_allow_embed_images_in_emails[0] == "t"
execute <<~SQL
INSERT INTO site_settings(name, data_type, value, created_at, updated_at)
VALUES ('secure_uploads_allow_embed_images_in_emails', 5, 't', now(), now())
SQL
end
secure_media_max_email_embed_image_size_kb = DB.query_single("SELECT value FROM site_settings WHERE name = 'secure_media_max_email_embed_image_size_kb'")
if secure_media_max_email_embed_image_size_kb.present?
execute <<~SQL
INSERT INTO site_settings(name, data_type, value, created_at, updated_at)
VALUES ('secure_uploads_max_email_embed_image_size_kb', 3, '#{secure_uploads_max_email_embed_image_size_kb[0]}', now(), now())
SQL
end
end
def down
raise ActiveRecord::IrreversibleMigration
end
end

View File

@ -22,7 +22,7 @@ class CookedPostProcessor
@cooking_options = post.cooking_options || opts[:cooking_options] || {} @cooking_options = post.cooking_options || opts[:cooking_options] || {}
@cooking_options[:topic_id] = post.topic_id @cooking_options[:topic_id] = post.topic_id
@cooking_options = @cooking_options.symbolize_keys @cooking_options = @cooking_options.symbolize_keys
@with_secure_media = @post.with_secure_media? @with_secure_uploads = @post.with_secure_uploads?
@category_id = @post&.topic&.category_id @category_id = @post&.topic&.category_id
cooked = post.cook(post.raw, @cooking_options) cooked = post.cook(post.raw, @cooking_options)
@ -225,14 +225,14 @@ class CookedPostProcessor
resized_h = (h * ratio).to_i resized_h = (h * ratio).to_i
if !cropped && upload.width && resized_w > upload.width if !cropped && upload.width && resized_w > upload.width
cooked_url = UrlHelper.cook_url(upload.url, secure: @post.with_secure_media?) cooked_url = UrlHelper.cook_url(upload.url, secure: @post.with_secure_uploads?)
srcset << ", #{cooked_url} #{ratio.to_s.sub(/\.0$/, "")}x" srcset << ", #{cooked_url} #{ratio.to_s.sub(/\.0$/, "")}x"
elsif t = upload.thumbnail(resized_w, resized_h) elsif t = upload.thumbnail(resized_w, resized_h)
cooked_url = UrlHelper.cook_url(t.url, secure: @post.with_secure_media?) cooked_url = UrlHelper.cook_url(t.url, secure: @post.with_secure_uploads?)
srcset << ", #{cooked_url} #{ratio.to_s.sub(/\.0$/, "")}x" srcset << ", #{cooked_url} #{ratio.to_s.sub(/\.0$/, "")}x"
end end
img["srcset"] = "#{UrlHelper.cook_url(img["src"], secure: @post.with_secure_media?)}#{srcset}" if srcset.present? img["srcset"] = "#{UrlHelper.cook_url(img["src"], secure: @post.with_secure_uploads?)}#{srcset}" if srcset.present?
end end
else else
img["src"] = upload.url img["src"] = upload.url
@ -250,7 +250,7 @@ class CookedPostProcessor
lightbox.add_child(img) lightbox.add_child(img)
# then, the link to our larger image # then, the link to our larger image
src = UrlHelper.cook_url(img["src"], secure: @post.with_secure_media?) src = UrlHelper.cook_url(img["src"], secure: @post.with_secure_uploads?)
a = create_link_node("lightbox", src) a = create_link_node("lightbox", src)
img.add_next_sibling(a) img.add_next_sibling(a)
@ -323,7 +323,7 @@ class CookedPostProcessor
@doc.css("img[#{selector}]").each do |img| @doc.css("img[#{selector}]").each do |img|
custom_emoji = img["class"]&.include?("emoji-custom") && Emoji.custom?(img["title"]) custom_emoji = img["class"]&.include?("emoji-custom") && Emoji.custom?(img["title"])
img[selector] = UrlHelper.cook_url( img[selector] = UrlHelper.cook_url(
img[selector].to_s, secure: @post.with_secure_media? && !custom_emoji img[selector].to_s, secure: @post.with_secure_uploads? && !custom_emoji
) )
end end
end end
@ -384,7 +384,7 @@ class CookedPostProcessor
still_an_image = false still_an_image = false
elsif info&.downloaded? && upload = info&.upload elsif info&.downloaded? && upload = info&.upload
img["src"] = UrlHelper.cook_url(upload.url, secure: @with_secure_media) img["src"] = UrlHelper.cook_url(upload.url, secure: @with_secure_uploads)
img.delete(PrettyText::BLOCKED_HOTLINKED_SRC_ATTR) img.delete(PrettyText::BLOCKED_HOTLINKED_SRC_ATTR)
end end

View File

@ -175,10 +175,10 @@ module CookedProcessorMixin
# FastImage fails when there's no scheme # FastImage fails when there's no scheme
absolute_url = SiteSetting.scheme + ":" + absolute_url if absolute_url.start_with?("//") absolute_url = SiteSetting.scheme + ":" + absolute_url if absolute_url.start_with?("//")
# we can't direct FastImage to our secure-media-uploads url because it bounces # we can't direct FastImage to our secure-uploads url because it bounces
# anonymous requests with a 404 error # anonymous requests with a 404 error
if url && Upload.secure_media_url?(url) if url && Upload.secure_uploads_url?(url)
absolute_url = Upload.signed_url_from_secure_media_url(absolute_url) absolute_url = Upload.signed_url_from_secure_uploads_url(absolute_url)
end end
return unless is_valid_image_url?(absolute_url) return unless is_valid_image_url?(absolute_url)

View File

@ -242,7 +242,7 @@ module Email
# Embeds any of the secure images that have been attached inline, # Embeds any of the secure images that have been attached inline,
# removing the redaction notice. # removing the redaction notice.
if SiteSetting.secure_media_allow_embed_images_in_emails if SiteSetting.secure_uploads_allow_embed_images_in_emails
style.inline_secure_images(@message.attachments, @message_attachments_index) style.inline_secure_images(@message.attachments, @message_attachments_index)
end end
@ -357,8 +357,8 @@ module Email
end end
def should_attach_image?(upload, optimized_1X = nil) def should_attach_image?(upload, optimized_1X = nil)
return if !SiteSetting.secure_media_allow_embed_images_in_emails || !upload.secure? return if !SiteSetting.secure_uploads_allow_embed_images_in_emails || !upload.secure?
return if (optimized_1X&.filesize || upload.filesize) > SiteSetting.secure_media_max_email_embed_image_size_kb.kilobytes return if (optimized_1X&.filesize || upload.filesize) > SiteSetting.secure_uploads_max_email_embed_image_size_kb.kilobytes
true true
end end

View File

@ -257,10 +257,10 @@ module Email
end end
def inline_secure_images(attachments, attachments_index) def inline_secure_images(attachments, attachments_index)
stripped_media = @fragment.css('[data-stripped-secure-media]') stripped_media = @fragment.css('[data-stripped-secure-media], [data-stripped-secure-upload]')
upload_shas = {} upload_shas = {}
stripped_media.each do |div| stripped_media.each do |div|
url = div['data-stripped-secure-media'] url = div['data-stripped-secure-media'] || div['data-stripped-secure-upload']
filename = File.basename(url) filename = File.basename(url)
filename_bare = filename.gsub(File.extname(filename), "") filename_bare = filename.gsub(File.extname(filename), "")
sha1 = filename_bare.partition('_').first sha1 = filename_bare.partition('_').first
@ -269,7 +269,9 @@ module Email
uploads = Upload.select(:original_filename, :sha1).where(sha1: upload_shas.values) uploads = Upload.select(:original_filename, :sha1).where(sha1: upload_shas.values)
stripped_media.each do |div| stripped_media.each do |div|
upload = uploads.find { |upl| upl.sha1 == upload_shas[div['data-stripped-secure-media']] } upload = uploads.find do |upl|
upl.sha1 == (upload_shas[div['data-stripped-secure-media']] || upload_shas[div['data-stripped-secure-upload']])
end
next if !upload next if !upload
if attachments[attachments_index[upload.sha1]] if attachments[attachments_index[upload.sha1]]
@ -294,7 +296,7 @@ module Email
def to_html def to_html
# needs to be before class + id strip because we need to style redacted # needs to be before class + id strip because we need to style redacted
# media and also not double-redact already redacted from lower levels # media and also not double-redact already redacted from lower levels
replace_secure_media_urls if SiteSetting.secure_media? replace_secure_uploads_urls if SiteSetting.secure_uploads?
strip_classes_and_ids strip_classes_and_ids
replace_relative_urls replace_relative_urls
@ -369,13 +371,13 @@ module Email
end end
end end
def replace_secure_media_urls def replace_secure_uploads_urls
# strip again, this can be done at a lower level like in the user # strip again, this can be done at a lower level like in the user
# notification template but that may not catch everything # notification template but that may not catch everything
PrettyText.strip_secure_media(@fragment) PrettyText.strip_secure_uploads(@fragment)
style('div.secure-media-notice', 'border: 5px solid #e9e9e9; padding: 5px; display: inline-block;') style('div.secure-upload-notice', 'border: 5px solid #e9e9e9; padding: 5px; display: inline-block;')
style('div.secure-media-notice a', "color: #{SiteSetting.email_link_color}") style('div.secure-upload-notice a', "color: #{SiteSetting.email_link_color}")
end end
def correct_first_body_margin def correct_first_body_margin

View File

@ -543,7 +543,7 @@ class Guardian
def can_publish_page?(topic) def can_publish_page?(topic)
return false if !SiteSetting.enable_page_publishing? return false if !SiteSetting.enable_page_publishing?
return false if SiteSetting.secure_media? return false if SiteSetting.secure_uploads?
return false if topic.blank? return false if topic.blank?
return false if topic.private_message? return false if topic.private_message?
return false unless can_see_topic?(topic) return false unless can_see_topic?(topic)

View File

@ -398,7 +398,7 @@ class PostCreator
end end
def update_uploads_secure_status def update_uploads_secure_status
@post.update_uploads_secure_status(source: "post creator") if SiteSetting.secure_media? @post.update_uploads_secure_status(source: "post creator") if SiteSetting.secure_uploads?
end end
def delete_owned_bookmarks def delete_owned_bookmarks

View File

@ -488,14 +488,14 @@ module PrettyText
end end
end end
def self.strip_secure_media(doc) def self.strip_secure_uploads(doc)
# images inside a lightbox or other link # images inside a lightbox or other link
doc.css('a[href]').each do |a| doc.css('a[href]').each do |a|
next if !Upload.secure_media_url?(a['href']) next if !Upload.secure_uploads_url?(a['href'])
non_image_media = %w(video audio).include?(a&.parent&.name) non_image_media = %w(video audio).include?(a&.parent&.name)
target = non_image_media ? a.parent : a target = non_image_media ? a.parent : a
next if target.to_s.include?('stripped-secure-view-media') next if target.to_s.include?('stripped-secure-view-media') || target.to_s.include?('stripped-secure-view-upload')
next if a.css('img[src]').empty? && !non_image_media next if a.css('img[src]').empty? && !non_image_media
@ -509,12 +509,12 @@ module PrettyText
else else
url = img['src'] url = img['src']
end end
a.add_next_sibling secure_media_placeholder(doc, url, width: img['width'], height: img['height']) a.add_next_sibling secure_uploads_placeholder(doc, url, width: img['width'], height: img['height'])
a.remove a.remove
else else
width = non_image_media ? nil : a.at_css('img').attr('width') width = non_image_media ? nil : a.at_css('img').attr('width')
height = non_image_media ? nil : a.at_css('img').attr('height') height = non_image_media ? nil : a.at_css('img').attr('height')
target.add_next_sibling secure_media_placeholder(doc, a['href'], width: width, height: height) target.add_next_sibling secure_uploads_placeholder(doc, a['href'], width: width, height: height)
target.remove target.remove
end end
end end
@ -551,20 +551,20 @@ module PrettyText
height = 16 height = 16
end end
if Upload.secure_media_url?(url) if Upload.secure_uploads_url?(url)
img.add_next_sibling secure_media_placeholder(doc, url, onebox_type: onebox_type, width: width, height: height) img.add_next_sibling secure_uploads_placeholder(doc, url, onebox_type: onebox_type, width: width, height: height)
img.remove img.remove
end end
end end
end end
def self.secure_media_placeholder(doc, url, onebox_type: false, width: nil, height: nil) def self.secure_uploads_placeholder(doc, url, onebox_type: false, width: nil, height: nil)
data_width = width ? "data-width=#{width}" : '' data_width = width ? "data-width=#{width}" : ''
data_height = height ? "data-height=#{height}" : '' data_height = height ? "data-height=#{height}" : ''
data_onebox_type = onebox_type ? "data-onebox-type='#{onebox_type}'" : '' data_onebox_type = onebox_type ? "data-onebox-type='#{onebox_type}'" : ''
<<~HTML <<~HTML
<div class="secure-media-notice" data-stripped-secure-media="#{url}" #{data_onebox_type} #{data_width} #{data_height}> <div class="secure-upload-notice" data-stripped-secure-upload="#{url}" #{data_onebox_type} #{data_width} #{data_height}>
#{I18n.t('emails.secure_media_placeholder')} <a class='stripped-secure-view-media' href="#{url}">#{I18n.t("emails.view_redacted_media")}</a>. #{I18n.t('emails.secure_uploads_placeholder')} <a class='stripped-secure-view-upload' href="#{url}">#{I18n.t("emails.view_redacted_media")}</a>.
</div> </div>
HTML HTML
end end
@ -572,7 +572,7 @@ module PrettyText
def self.format_for_email(html, post = nil) def self.format_for_email(html, post = nil)
doc = Nokogiri::HTML5.fragment(html) doc = Nokogiri::HTML5.fragment(html)
DiscourseEvent.trigger(:reduce_cooked, doc, post) DiscourseEvent.trigger(:reduce_cooked, doc, post)
strip_secure_media(doc) if post&.with_secure_media? strip_secure_uploads(doc) if post&.with_secure_uploads?
strip_image_wrapping(doc) strip_image_wrapping(doc)
convert_vimeo_iframes(doc) convert_vimeo_iframes(doc)
make_all_links_absolute(doc) make_all_links_absolute(doc)

View File

@ -70,11 +70,11 @@ module PrettyText
sha1, url, extension, original_filename, secure = row sha1, url, extension, original_filename, secure = row
if short_urls = reverse_map[sha1] if short_urls = reverse_map[sha1]
secure_media = SiteSetting.secure_media? && secure secure_uploads = SiteSetting.secure_uploads? && secure
short_urls.each do |short_url| short_urls.each do |short_url|
result[short_url] = { result[short_url] = {
url: secure_media ? Upload.secure_media_url_from_upload_url(url) : Discourse.store.cdn_url(url), url: secure_uploads ? Upload.secure_uploads_url_from_upload_url(url) : Discourse.store.cdn_url(url),
short_path: Upload.short_path(sha1: sha1, extension: extension), short_path: Upload.short_path(sha1: sha1, extension: extension),
base62_sha1: Upload.base62_sha1(sha1) base62_sha1: Upload.base62_sha1(sha1)
} }

View File

@ -9,6 +9,9 @@ module SiteSettings::DeprecatedSettings
['default_categories_regular', 'default_categories_normal', true, '3.0'], ['default_categories_regular', 'default_categories_normal', true, '3.0'],
['min_trust_to_send_messages', 'personal_message_enabled_groups', false, '3.0'], ['min_trust_to_send_messages', 'personal_message_enabled_groups', false, '3.0'],
['enable_personal_messages', 'personal_message_enabled_groups', false, '3.0'], ['enable_personal_messages', 'personal_message_enabled_groups', false, '3.0'],
['secure_media', 'secure_uploads', true, '3.0'],
['secure_media_allow_embed_images_in_emails', 'secure_uploads_allow_embed_images_in_emails', true, '3.0'],
['secure_media_max_email_embed_image_size_kb', 'secure_uploads_max_email_embed_image_size_kb', true, '3.0'],
] ]
def setup_deprecated_methods def setup_deprecated_methods

View File

@ -162,12 +162,12 @@ module SiteSettings::Validations
validate_error :s3_upload_bucket_is_required if SiteSetting.s3_upload_bucket.blank? validate_error :s3_upload_bucket_is_required if SiteSetting.s3_upload_bucket.blank?
end end
def validate_secure_media(new_val) def validate_secure_uploads(new_val)
validate_error :secure_media_requirements if new_val == "t" && !SiteSetting.Upload.enable_s3_uploads validate_error :secure_uploads_requirements if new_val == "t" && !SiteSetting.Upload.enable_s3_uploads
end end
def validate_enable_page_publishing(new_val) def validate_enable_page_publishing(new_val)
validate_error :page_publishing_requirements if new_val == "t" && SiteSetting.secure_media? validate_error :page_publishing_requirements if new_val == "t" && SiteSetting.secure_uploads?
end end
def validate_share_quote_buttons(new_val) def validate_share_quote_buttons(new_val)

View File

@ -518,16 +518,16 @@ task "uploads:sync_s3_acls" => :environment do
end end
end end
task "uploads:disable_secure_media" => :environment do task "uploads:disable_secure_uploads" => :environment do
RailsMultisite::ConnectionManagement.each_connection do |db| RailsMultisite::ConnectionManagement.each_connection do |db|
unless Discourse.store.external? unless Discourse.store.external?
puts "This task only works for external storage." puts "This task only works for external storage."
exit 1 exit 1
end end
puts "Disabling secure media and resetting uploads to not secure in #{db}...", "" puts "Disabling secure upload and resetting uploads to not secure in #{db}...", ""
SiteSetting.secure_media = false SiteSetting.secure_uploads = false
secure_uploads = Upload.joins(:upload_references).where(upload_references: { target_type: 'Post' }).where(secure: true) secure_uploads = Upload.joins(:upload_references).where(upload_references: { target_type: 'Post' }).where(secure: true)
secure_upload_count = secure_uploads.count secure_upload_count = secure_uploads.count
@ -537,7 +537,7 @@ task "uploads:disable_secure_media" => :environment do
secure_uploads.update_all( secure_uploads.update_all(
secure: false, secure: false,
security_last_changed_at: Time.zone.now, security_last_changed_at: Time.zone.now,
security_last_changed_reason: "marked as not secure by disable_secure_media task" security_last_changed_reason: "marked as not secure by disable_secure_uploads task"
) )
post_ids_to_rebake = DB.query_single( post_ids_to_rebake = DB.query_single(
@ -550,11 +550,11 @@ task "uploads:disable_secure_media" => :environment do
puts "", "Rebaking and uploading complete!", "" puts "", "Rebaking and uploading complete!", ""
end end
puts "", "Secure media is now disabled!", "" puts "", "Secure uploads are now disabled!", ""
end end
## ##
# Run this task whenever the secure_media or login_required # Run this task whenever the secure_uploads or login_required
# settings are changed for a Discourse instance to update # settings are changed for a Discourse instance to update
# the upload secure flag and S3 upload ACLs. Any uploads that # the upload secure flag and S3 upload ACLs. Any uploads that
# have their secure status changed will have all associated posts # have their secure status changed will have all associated posts
@ -569,12 +569,12 @@ task "uploads:secure_upload_analyse_and_update" => :environment do
puts "Analyzing security for uploads in #{db}...", "" puts "Analyzing security for uploads in #{db}...", ""
all_upload_ids_changed, post_ids_to_rebake = nil all_upload_ids_changed, post_ids_to_rebake = nil
Upload.transaction do Upload.transaction do
# If secure media is enabled we need to first set the access control post of # If secure upload is enabled we need to first set the access control post of
# all post uploads (even uploads that are linked to multiple posts). If the # all post uploads (even uploads that are linked to multiple posts). If the
# upload is not set to secure media then this has no other effect on the upload, # upload is not set to secure upload then this has no other effect on the upload,
# but we _must_ know what the access control post is because the with_secure_media? # but we _must_ know what the access control post is because the with_secure_uploads?
# method is on the post, and this knows about the category security & PM status # method is on the post, and this knows about the category security & PM status
if SiteSetting.secure_media? if SiteSetting.secure_uploads?
update_uploads_access_control_post update_uploads_access_control_post
end end

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
## ##
# There are certain conditions with secure media when the security of # There are certain conditions with secure uploads when the security of
# uploads will need to change depending on the context they reside in. # uploads will need to change depending on the context they reside in.
# #
# For example on these conditions: # For example on these conditions:
@ -38,16 +38,16 @@ class TopicUploadSecurityManager
end end
end end
return if !SiteSetting.secure_media return if !SiteSetting.secure_uploads
# we only want to do this if secure media is enabled. if # we only want to do this if secure uploads is enabled. if
# the setting is turned on after a site has been running # the setting is turned on after a site has been running
# already, we want to make sure that any post moves after # already, we want to make sure that any post moves after
# this are handled and upload secure statuses and ACLs # this are handled and upload secure statuses and ACLs
# are updated appropriately, as well as setting the access control # are updated appropriately, as well as setting the access control
# post for secure uploads missing it. # post for secure uploads missing it.
# #
# examples (all after secure media is enabled): # examples (all after secure uploads is enabled):
# #
# -> a public topic is moved to a private category after # -> a public topic is moved to a private category after
# -> a PM is converted to a public topic # -> a PM is converted to a public topic

View File

@ -94,15 +94,15 @@ class UploadCreator
if !external_upload_too_big if !external_upload_too_big
sha1 = Upload.generate_digest(@file) sha1 = Upload.generate_digest(@file)
end end
if SiteSetting.secure_media || external_upload_too_big if SiteSetting.secure_uploads || external_upload_too_big
unique_hash = generate_fake_sha1_hash unique_hash = generate_fake_sha1_hash
end end
# we do not check for duplicate uploads if secure media is # we do not check for duplicate uploads if secure uploads is
# enabled because we use a unique access hash to differentiate # enabled because we use a unique access hash to differentiate
# between uploads instead of the sha1, and to get around various # between uploads instead of the sha1, and to get around various
# access/permission issues for uploads # access/permission issues for uploads
if !SiteSetting.secure_media && !external_upload_too_big if !SiteSetting.secure_uploads && !external_upload_too_big
# do we already have that upload? # do we already have that upload?
@upload = Upload.find_by(sha1: sha1) @upload = Upload.find_by(sha1: sha1)
@ -140,8 +140,8 @@ class UploadCreator
@upload.user_id = user_id @upload.user_id = user_id
@upload.original_filename = fixed_original_filename || @filename @upload.original_filename = fixed_original_filename || @filename
@upload.filesize = filesize @upload.filesize = filesize
@upload.sha1 = (SiteSetting.secure_media? || external_upload_too_big) ? unique_hash : sha1 @upload.sha1 = (SiteSetting.secure_uploads? || external_upload_too_big) ? unique_hash : sha1
@upload.original_sha1 = SiteSetting.secure_media? ? sha1 : nil @upload.original_sha1 = SiteSetting.secure_uploads? ? sha1 : nil
@upload.url = "" @upload.url = ""
@upload.origin = @opts[:origin][0...1000] if @opts[:origin] @upload.origin = @opts[:origin][0...1000] if @opts[:origin]
@upload.extension = image_type || File.extname(@filename)[1..10] @upload.extension = image_type || File.extname(@filename)[1..10]
@ -173,7 +173,7 @@ class UploadCreator
add_metadata! add_metadata!
if SiteSetting.secure_media if SiteSetting.secure_uploads
secure, reason = UploadSecurity.new(@upload, @opts.merge(creating: true)).should_be_secure_with_reason secure, reason = UploadSecurity.new(@upload, @opts.merge(creating: true)).should_be_secure_with_reason
attrs = @upload.secure_params(secure, reason, "upload creator") attrs = @upload.secure_params(secure, reason, "upload creator")
@upload.assign_attributes(attrs) @upload.assign_attributes(attrs)

View File

@ -66,8 +66,8 @@ class UploadSecurity
[false, "no checks satisfied"] [false, "no checks satisfied"]
end end
def secure_media_disabled_check def secure_uploads_disabled_check
!SiteSetting.secure_media? !SiteSetting.secure_uploads?
end end
def insecure_creation_for_modifiers_check def insecure_creation_for_modifiers_check
@ -96,14 +96,14 @@ class UploadSecurity
# whether the upload should remain secure or not after posting depends on its context, # whether the upload should remain secure or not after posting depends on its context,
# which is based on the post it is linked to via access_control_post_id. # which is based on the post it is linked to via access_control_post_id.
# if that post is with_secure_media? then the upload should also be secure. # if that post is with_secure_uploads? then the upload should also be secure.
# this may change to false if the upload was set to secure on upload e.g. in # this may change to false if the upload was set to secure on upload e.g. in
# a post composer then it turned out that the post itself was not in a secure context # a post composer then it turned out that the post itself was not in a secure context
# #
# a post is with secure media if it is a private message or in a read restricted # a post is with secure uploads if it is a private message or in a read restricted
# category # category
def access_control_post_has_secure_media_check def access_control_post_has_secure_uploads_check
access_control_post&.with_secure_media? access_control_post&.with_secure_uploads?
end end
def uploading_in_composer_check def uploading_in_composer_check
@ -127,7 +127,7 @@ class UploadSecurity
def insecure_context_checks def insecure_context_checks
{ {
secure_media_disabled: "secure media is disabled", secure_uploads_disabled: "secure uploads is disabled",
insecure_creation_for_modifiers: "one or more creation for_modifiers was satisfied", insecure_creation_for_modifiers: "one or more creation for_modifiers was satisfied",
public_type: "upload is public type", public_type: "upload is public type",
custom_emoji: "upload is used for custom emoji", custom_emoji: "upload is used for custom emoji",
@ -138,7 +138,7 @@ class UploadSecurity
def secure_context_checks def secure_context_checks
{ {
login_required: "login is required", login_required: "login is required",
access_control_post_has_secure_media: "access control post dictates security", access_control_post_has_secure_uploads: "access control post dictates security",
secure_creation_for_modifiers: "one or more creation for_modifiers was satisfied", secure_creation_for_modifiers: "one or more creation for_modifiers was satisfied",
uploading_in_composer: "uploading via the composer", uploading_in_composer: "uploading via the composer",
already_secure: "upload is already secure" already_secure: "upload is already secure"
@ -149,7 +149,7 @@ class UploadSecurity
# of whether an upload should be secure or not, and thus should be returned # of whether an upload should be secure or not, and thus should be returned
# immediately if there is an access control post # immediately if there is an access control post
def priority_check?(check) def priority_check?(check)
check == :access_control_post_has_secure_media && access_control_post check == :access_control_post_has_secure_uploads && access_control_post
end end
def perform_check(check) def perform_check(check)

View File

@ -57,7 +57,7 @@ class UrlHelper
end end
def self.secure_proxy_without_cdn(url) def self.secure_proxy_without_cdn(url)
self.absolute(Upload.secure_media_url_from_upload_url(url), nil) self.absolute(Upload.secure_uploads_url_from_upload_url(url), nil)
end end
def self.escape_uri(uri) def self.escape_uri(uri)
@ -105,14 +105,14 @@ class UrlHelper
end end
def self.cook_url(url, secure: false, local: nil) def self.cook_url(url, secure: false, local: nil)
is_secure = SiteSetting.secure_media && secure is_secure = SiteSetting.secure_uploads && secure
local = is_local(url) if local.nil? local = is_local(url) if local.nil?
return url if !local return url if !local
url = is_secure ? secure_proxy_without_cdn(url) : absolute_without_cdn(url) url = is_secure ? secure_proxy_without_cdn(url) : absolute_without_cdn(url)
# we always want secure media to come from # we always want secure uploads to come from
# Discourse.base_url_no_prefix/secure-media-uploads # Discourse.base_url_no_prefix/secure-uploads
# to avoid asset_host mixups # to avoid asset_host mixups
return schemaless(url) if is_secure return schemaless(url) if is_secure

View File

@ -222,14 +222,14 @@ RSpec.describe Jobs::PullHotlinkedImages do
expect(post.raw).to eq(raw) expect(post.raw).to eq(raw)
end end
context "when secure media enabled for an upload that has already been downloaded and exists" do context "when secure uploads enabled for an upload that has already been downloaded and exists" do
it "doesnt redownload the secure upload" do it "doesnt redownload the secure upload" do
setup_s3 setup_s3
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
upload = Fabricate(:secure_upload_s3, secure: true) upload = Fabricate(:secure_upload_s3, secure: true)
stub_s3(upload) stub_s3(upload)
url = Upload.secure_media_url_from_upload_url(upload.url) url = Upload.secure_uploads_url_from_upload_url(upload.url)
url = Discourse.base_url + url url = Discourse.base_url + url
post = Fabricate(:post, raw: "<img src='#{url}'>") post = Fabricate(:post, raw: "<img src='#{url}'>")
upload.update(access_control_post: post) upload.update(access_control_post: post)
@ -240,12 +240,12 @@ RSpec.describe Jobs::PullHotlinkedImages do
context "when the upload original_sha1 is missing" do context "when the upload original_sha1 is missing" do
it "redownloads the upload" do it "redownloads the upload" do
setup_s3 setup_s3
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
upload = Fabricate(:upload_s3, secure: true) upload = Fabricate(:upload_s3, secure: true)
stub_s3(upload) stub_s3(upload)
Upload.stubs(:signed_url_from_secure_media_url).returns(upload.url) Upload.stubs(:signed_url_from_secure_uploads_url).returns(upload.url)
url = Upload.secure_media_url_from_upload_url(upload.url) url = Upload.secure_uploads_url_from_upload_url(upload.url)
url = Discourse.base_url + url url = Discourse.base_url + url
post = Fabricate(:post, raw: "<img src='#{url}'>") post = Fabricate(:post, raw: "<img src='#{url}'>")
upload.update(access_control_post: post) upload.update(access_control_post: post)
@ -261,12 +261,12 @@ RSpec.describe Jobs::PullHotlinkedImages do
context "when the upload access_control_post is different to the current post" do context "when the upload access_control_post is different to the current post" do
it "redownloads the upload" do it "redownloads the upload" do
setup_s3 setup_s3
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
upload = Fabricate(:secure_upload_s3, secure: true) upload = Fabricate(:secure_upload_s3, secure: true)
stub_s3(upload) stub_s3(upload)
Upload.stubs(:signed_url_from_secure_media_url).returns(upload.url) Upload.stubs(:signed_url_from_secure_uploads_url).returns(upload.url)
url = Upload.secure_media_url_from_upload_url(upload.url) url = Upload.secure_uploads_url_from_upload_url(upload.url)
url = Discourse.base_url + url url = Discourse.base_url + url
post = Fabricate(:post, raw: "<img src='#{url}'>") post = Fabricate(:post, raw: "<img src='#{url}'>")
upload.update(access_control_post: Fabricate(:post)) upload.update(access_control_post: Fabricate(:post))
@ -466,14 +466,14 @@ RSpec.describe Jobs::PullHotlinkedImages do
expect(subject.should_download_image?(Fabricate(:upload).url)).to eq(false) expect(subject.should_download_image?(Fabricate(:upload).url)).to eq(false)
end end
context "when secure media enabled" do context "when secure uploads enabled" do
it 'should return false for secure-media-upload url' do it 'should return false for secure-upload url' do
setup_s3 setup_s3
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
upload = Fabricate(:upload_s3, secure: true) upload = Fabricate(:upload_s3, secure: true)
stub_s3(upload) stub_s3(upload)
url = Upload.secure_media_url_from_upload_url(upload.url) url = Upload.secure_uploads_url_from_upload_url(upload.url)
expect(subject.should_download_image?(url)).to eq(false) expect(subject.should_download_image?(url)).to eq(false)
end end
end end

View File

@ -14,7 +14,7 @@ RSpec.describe Jobs::UpdatePostUploadsSecureStatus do
before do before do
setup_s3 setup_s3
stub_s3_store stub_s3_store
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
end end
context "when login_required" do context "when login_required" do

View File

@ -485,7 +485,7 @@ RSpec.describe CookedPostProcessor do
stub_upload(upload) stub_upload(upload)
SiteSetting.login_required = true SiteSetting.login_required = true
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
end end
let(:optimized_size) { "600x500" } let(:optimized_size) { "600x500" }
@ -496,7 +496,7 @@ RSpec.describe CookedPostProcessor do
let(:cooked_html) do let(:cooked_html) do
<<~HTML <<~HTML
<p><div class="lightbox-wrapper"><a class="lightbox" href="//test.localhost/secure-media-uploads/original/1X/#{upload.sha1}.png" data-download-href="//test.localhost/uploads/short-url/#{upload.base62_sha1}.unknown?dl=1" title="large.png"><img src="" alt="large.png" data-base62-sha1="#{upload.base62_sha1}" width="600" height="500"><div class="meta"> <p><div class="lightbox-wrapper"><a class="lightbox" href="//test.localhost/secure-uploads/original/1X/#{upload.sha1}.png" data-download-href="//test.localhost/uploads/short-url/#{upload.base62_sha1}.unknown?dl=1" title="large.png"><img src="" alt="large.png" data-base62-sha1="#{upload.base62_sha1}" width="600" height="500"><div class="meta">
<svg class="fa d-icon d-icon-far-image svg-icon" aria-hidden="true"><use href="#far-image"></use></svg><span class="filename">large.png</span><span class="informations">1750×2000 1.21 KB</span><svg class="fa d-icon d-icon-discourse-expand svg-icon" aria-hidden="true"><use href="#discourse-expand"></use></svg> <svg class="fa d-icon d-icon-far-image svg-icon" aria-hidden="true"><use href="#far-image"></use></svg><span class="filename">large.png</span><span class="informations">1750×2000 1.21 KB</span><svg class="fa d-icon d-icon-discourse-expand svg-icon" aria-hidden="true"><use href="#discourse-expand"></use></svg>
</div></a></div></p> </div></a></div></p>
HTML HTML
@ -1074,13 +1074,13 @@ RSpec.describe CookedPostProcessor do
Oneboxer.unstub(:onebox) Oneboxer.unstub(:onebox)
end end
context "when the post is with_secure_media and the upload is secure and secure media is enabled" do context "when the post is with_secure_uploads and the upload is secure and secure uploads is enabled" do
before do before do
setup_s3 setup_s3
upload.update(secure: true) upload.update(secure: true)
SiteSetting.login_required = true SiteSetting.login_required = true
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
end end
it "does not use the direct URL, uses the cooked URL instead (because of the private ACL preventing w/h fetch)" do it "does not use the direct URL, uses the cooked URL instead (because of the private ACL preventing w/h fetch)" do
@ -1091,7 +1091,7 @@ RSpec.describe CookedPostProcessor do
PostHotlinkedMedia.create!(url: "//image.com/avatar.png", post: post, status: 'downloaded', upload: upload) PostHotlinkedMedia.create!(url: "//image.com/avatar.png", post: post, status: 'downloaded', upload: upload)
cooked_url = "https://localhost/secure-media-uploads/test.png" cooked_url = "https://localhost/secure-uploads/test.png"
UrlHelper.expects(:cook_url).with(upload.url, secure: true).returns(cooked_url) UrlHelper.expects(:cook_url).with(upload.url, secure: true).returns(cooked_url)
cpp = CookedPostProcessor.new(post, invalidate_oneboxes: true) cpp = CookedPostProcessor.new(post, invalidate_oneboxes: true)
@ -1417,8 +1417,8 @@ RSpec.describe CookedPostProcessor do
HTML HTML
end end
it "doesn't use CDN for secure media" do it "doesn't use CDN for secure uploads" do
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
stored_path = Discourse.store.get_path_for_upload(upload) stored_path = Discourse.store.get_path_for_upload(upload)
upload.update_column(:url, "#{SiteSetting.Upload.absolute_base_url}/#{stored_path}") upload.update_column(:url, "#{SiteSetting.Upload.absolute_base_url}/#{stored_path}")
@ -1431,11 +1431,11 @@ RSpec.describe CookedPostProcessor do
expect(cpp.html).to match_html <<~HTML expect(cpp.html).to match_html <<~HTML
<p>This post has a local emoji <img src="https://local.cdn.com/images/emoji/twitter/+1.png?v=#{Emoji::EMOJI_VERSION}" title=":+1:" class="emoji" alt=":+1:" loading="lazy" width="20" height="20"> and an external upload</p> <p>This post has a local emoji <img src="https://local.cdn.com/images/emoji/twitter/+1.png?v=#{Emoji::EMOJI_VERSION}" title=":+1:" class="emoji" alt=":+1:" loading="lazy" width="20" height="20"> and an external upload</p>
<p><img src="/secure-media-uploads/#{stored_path}" alt="smallest.png" data-base62-sha1="#{upload.base62_sha1}" width="10" height="20"></p> <p><img src="/secure-uploads/#{stored_path}" alt="smallest.png" data-base62-sha1="#{upload.base62_sha1}" width="10" height="20"></p>
HTML HTML
end end
it "doesn't use the secure media URL for custom emoji" do it "doesn't use the secure uploads URL for custom emoji" do
CustomEmoji.create!(name: 'trout', upload: upload) CustomEmoji.create!(name: 'trout', upload: upload)
Emoji.clear_cache Emoji.clear_cache
Emoji.load_custom Emoji.load_custom
@ -1484,9 +1484,9 @@ RSpec.describe CookedPostProcessor do
HTML HTML
end end
it "oneboxes video using secure url when secure_media is enabled" do it "oneboxes video using secure url when secure_uploads is enabled" do
SiteSetting.login_required = true SiteSetting.login_required = true
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
video_upload.update_column(:secure, true) video_upload.update_column(:secure, true)
the_post = Fabricate(:post, raw: "This post has an S3 video onebox:\n#{video_upload.url}") the_post = Fabricate(:post, raw: "This post has an S3 video onebox:\n#{video_upload.url}")
@ -1494,7 +1494,7 @@ RSpec.describe CookedPostProcessor do
cpp = CookedPostProcessor.new(the_post) cpp = CookedPostProcessor.new(the_post)
cpp.post_process_oneboxes cpp.post_process_oneboxes
secure_url = video_upload.url.sub(SiteSetting.s3_cdn_url, "#{Discourse.base_url}/secure-media-uploads") secure_url = video_upload.url.sub(SiteSetting.s3_cdn_url, "#{Discourse.base_url}/secure-uploads")
expect(cpp.html).to match_html <<~HTML expect(cpp.html).to match_html <<~HTML
<p>This post has an S3 video onebox:</p><div class="onebox video-onebox"> <p>This post has an S3 video onebox:</p><div class="onebox video-onebox">
@ -1506,9 +1506,9 @@ RSpec.describe CookedPostProcessor do
HTML HTML
end end
it "oneboxes only audio/video and not images when secure_media is enabled" do it "oneboxes only audio/video and not images when secure_uploads is enabled" do
SiteSetting.login_required = true SiteSetting.login_required = true
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
video_upload.update_column(:secure, true) video_upload.update_column(:secure, true)
@ -1541,8 +1541,8 @@ RSpec.describe CookedPostProcessor do
cpp = CookedPostProcessor.new(the_post) cpp = CookedPostProcessor.new(the_post)
cpp.post_process_oneboxes cpp.post_process_oneboxes
secure_video_url = video_upload.url.sub(SiteSetting.s3_cdn_url, "#{Discourse.base_url}/secure-media-uploads") secure_video_url = video_upload.url.sub(SiteSetting.s3_cdn_url, "#{Discourse.base_url}/secure-uploads")
secure_audio_url = audio_upload.url.sub(SiteSetting.s3_cdn_url, "#{Discourse.base_url}/secure-media-uploads") secure_audio_url = audio_upload.url.sub(SiteSetting.s3_cdn_url, "#{Discourse.base_url}/secure-uploads")
expect(cpp.html).to match_html <<~HTML expect(cpp.html).to match_html <<~HTML
<p>This post has a video upload.</p> <p>This post has a video upload.</p>

View File

@ -4,7 +4,7 @@ require 'email/sender'
RSpec.describe Email::Sender do RSpec.describe Email::Sender do
before do before do
SiteSetting.secure_media_allow_embed_images_in_emails = false SiteSetting.secure_uploads_allow_embed_images_in_emails = false
end end
fab!(:post) { Fabricate(:post) } fab!(:post) { Fabricate(:post) }
let(:mock_smtp_transaction_response) { "250 Ok: queued as 2l3Md07BObzB8kRyHZeoN0baSUAhzc7A-NviRioOr80=@mailhog.example" } let(:mock_smtp_transaction_response) { "250 Ok: queued as 2l3Md07BObzB8kRyHZeoN0baSUAhzc7A-NviRioOr80=@mailhog.example" }
@ -535,15 +535,15 @@ RSpec.describe Email::Sender do
.to contain_exactly(*[small_pdf, large_pdf, csv_file].map(&:original_filename)) .to contain_exactly(*[small_pdf, large_pdf, csv_file].map(&:original_filename))
end end
context "when secure media enabled" do context "when secure uploads enabled" do
before do before do
setup_s3 setup_s3
store = stub_s3_store store = stub_s3_store
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
SiteSetting.login_required = true SiteSetting.login_required = true
SiteSetting.email_total_attachment_size_limit_kb = 14_000 SiteSetting.email_total_attachment_size_limit_kb = 14_000
SiteSetting.secure_media_max_email_embed_image_size_kb = 5_000 SiteSetting.secure_uploads_max_email_embed_image_size_kb = 5_000
Jobs.run_immediately! Jobs.run_immediately!
Jobs::PullHotlinkedImages.any_instance.expects(:execute) Jobs::PullHotlinkedImages.any_instance.expects(:execute)
@ -566,7 +566,7 @@ RSpec.describe Email::Sender do
context "when embedding secure images in email is allowed" do context "when embedding secure images in email is allowed" do
before do before do
SiteSetting.secure_media_allow_embed_images_in_emails = true SiteSetting.secure_uploads_allow_embed_images_in_emails = true
end end
it "can inline images with duplicate names" do it "can inline images with duplicate names" do
@ -590,7 +590,7 @@ RSpec.describe Email::Sender do
end end
it "does not embed images that are too big" do it "does not embed images that are too big" do
SiteSetting.secure_media_max_email_embed_image_size_kb = 1 SiteSetting.secure_uploads_max_email_embed_image_size_kb = 1
Email::Sender.new(message, :valid_type).send Email::Sender.new(message, :valid_type).send
expect(message.attachments.length).to eq(3) expect(message.attachments.length).to eq(3)
end end

View File

@ -208,32 +208,32 @@ RSpec.describe Email::Styles do
end end
end end
describe "replace_secure_media_urls" do describe "replace_secure_uploads_urls" do
before do before do
setup_s3 setup_s3
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
end end
let(:attachments) { { 'testimage.png' => stub(url: 'email/test.png') } } let(:attachments) { { 'testimage.png' => stub(url: 'email/test.png') } }
it "replaces secure media within a link with a placeholder" do it "replaces secure uploads within a link with a placeholder" do
frag = html_fragment("<a href=\"#{Discourse.base_url}\/secure-media-uploads/original/1X/testimage.png\"><img src=\"/secure-media-uploads/original/1X/testimage.png\"></a>") frag = html_fragment("<a href=\"#{Discourse.base_url}\/secure-uploads/original/1X/testimage.png\"><img src=\"/secure-uploads/original/1X/testimage.png\"></a>")
expect(frag.at('img')).not_to be_present expect(frag.at('img')).not_to be_present
expect(frag.to_s).to include("Redacted") expect(frag.to_s).to include("Redacted")
end end
it "replaces secure images with a placeholder" do it "replaces secure images with a placeholder" do
frag = html_fragment("<img src=\"/secure-media-uploads/original/1X/testimage.png\">") frag = html_fragment("<img src=\"/secure-uploads/original/1X/testimage.png\">")
expect(frag.at('img')).not_to be_present expect(frag.at('img')).not_to be_present
expect(frag.to_s).to include("Redacted") expect(frag.to_s).to include("Redacted")
end end
it "does not replace topic links with secure-media-uploads in the name" do it "does not replace topic links with secure-uploads in the name" do
frag = html_fragment("<a href=\"#{Discourse.base_url}\/t/secure-media-uploads/235723\">Visit Topic</a>") frag = html_fragment("<a href=\"#{Discourse.base_url}\/t/secure-uploads/235723\">Visit Topic</a>")
expect(frag.to_s).not_to include("Redacted") expect(frag.to_s).not_to include("Redacted")
end end
it "works in lightboxes with missing srcset attribute" do it "works in lightboxes with missing srcset attribute" do
frag = html_fragment("<a href=\"#{Discourse.base_url}\/secure-media-uploads/original/1X/testimage.png\" class=\"lightbox\"><img src=\"/secure-media-uploads/original/1X/testimage.png\"></a>") frag = html_fragment("<a href=\"#{Discourse.base_url}\/secure-uploads/original/1X/testimage.png\" class=\"lightbox\"><img src=\"/secure-uploads/original/1X/testimage.png\"></a>")
expect(frag.at('img')).not_to be_present expect(frag.at('img')).not_to be_present
expect(frag.to_s).to include("Redacted") expect(frag.to_s).to include("Redacted")
end end
@ -241,8 +241,8 @@ RSpec.describe Email::Styles do
it "works in lightboxes with srcset attribute set" do it "works in lightboxes with srcset attribute set" do
frag = html_fragment( frag = html_fragment(
<<~HTML <<~HTML
<a href="#{Discourse.base_url}/secure-media-uploads/original/1X/testimage.png" class="lightbox"> <a href="#{Discourse.base_url}/secure-uploads/original/1X/testimage.png" class="lightbox">
<img src="/secure-media-uploads/original/1X/testimage.png" srcset="/secure-media-uploads/optimized/1X/testimage.png, /secure-media-uploads/original/1X/testimage.png 1.5x" /> <img src="/secure-uploads/original/1X/testimage.png" srcset="/secure-uploads/optimized/1X/testimage.png, /secure-uploads/original/1X/testimage.png 1.5x" />
</a> </a>
HTML HTML
) )
@ -252,7 +252,7 @@ RSpec.describe Email::Styles do
end end
it "skips links with no images as children" do it "skips links with no images as children" do
frag = html_fragment("<a href=\"#{Discourse.base_url}\/secure-media-uploads/original/1X/testimage.png\"><span>Clearly not an image</span></a>") frag = html_fragment("<a href=\"#{Discourse.base_url}\/secure-uploads/original/1X/testimage.png\"><span>Clearly not an image</span></a>")
expect(frag.to_s).to include("not an image") expect(frag.to_s).to include("not an image")
end end
@ -261,16 +261,16 @@ RSpec.describe Email::Styles do
describe "inline_secure_images" do describe "inline_secure_images" do
before do before do
setup_s3 setup_s3
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
end end
fab!(:upload) { Fabricate(:upload, original_filename: 'testimage.png', secure: true, sha1: '123456') } fab!(:upload) { Fabricate(:upload, original_filename: 'testimage.png', secure: true, sha1: '123456') }
let(:attachments) { [stub(url: 'cid:email/test.png')] } let(:attachments) { [stub(url: 'cid:email/test.png')] }
let(:attachments_index) { { upload.sha1 => 0 } } let(:attachments_index) { { upload.sha1 => 0 } }
let(:html) { "<a href=\"#{Discourse.base_url}\/secure-media-uploads/original/1X/123456.png\"><img src=\"/secure-media-uploads/original/1X/123456.png\" width=\"20\" height=\"30\"></a>" } let(:html) { "<a href=\"#{Discourse.base_url}\/secure-uploads/original/1X/123456.png\"><img src=\"/secure-uploads/original/1X/123456.png\" width=\"20\" height=\"30\"></a>" }
def strip_and_inline def strip_and_inline
# strip out the secure media # strip out the secure uploads
styler = Email::Styles.new(html) styler = Email::Styles.new(html)
styler.format_basic styler.format_basic
styler.format_html styler.format_html
@ -285,7 +285,7 @@ RSpec.describe Email::Styles do
it "inlines attachments where stripped-secure-media data attr is present" do it "inlines attachments where stripped-secure-media data attr is present" do
strip_and_inline strip_and_inline
expect(@frag.to_s).to include("cid:email/test.png") expect(@frag.to_s).to include("cid:email/test.png")
expect(@frag.css('[data-stripped-secure-media]')).not_to be_present expect(@frag.css('[data-stripped-secure-upload]')).not_to be_present
expect(@frag.children.attr('style').value).to eq("width: 20px; height: 30px;") expect(@frag.children.attr('style').value).to eq("width: 20px; height: 30px;")
end end
@ -294,17 +294,17 @@ RSpec.describe Email::Styles do
strip_and_inline strip_and_inline
expect(@frag.to_s).not_to include("cid:email/test.png") expect(@frag.to_s).not_to include("cid:email/test.png")
expect(@frag.css('[data-stripped-secure-media]')).to be_present expect(@frag.css('[data-stripped-secure-upload]')).to be_present
end end
context "when an optimized image is used instead of the original" do context "when an optimized image is used instead of the original" do
let(:html) { "<a href=\"#{Discourse.base_url}\/secure-media-uploads/optimized/2X/1/123456_2_20x30.png\"><img src=\"/secure-media-uploads/optimized/2X/1/123456_2_20x30.png\" width=\"20\" height=\"30\"></a>" } let(:html) { "<a href=\"#{Discourse.base_url}\/secure-uploads/optimized/2X/1/123456_2_20x30.png\"><img src=\"/secure-uploads/optimized/2X/1/123456_2_20x30.png\" width=\"20\" height=\"30\"></a>" }
it "inlines attachments where the stripped-secure-media data attr is present" do it "inlines attachments where the stripped-secure-media data attr is present" do
optimized = Fabricate(:optimized_image, upload: upload, width: 20, height: 30) optimized = Fabricate(:optimized_image, upload: upload, width: 20, height: 30)
strip_and_inline strip_and_inline
expect(@frag.to_s).to include("cid:email/test.png") expect(@frag.to_s).to include("cid:email/test.png")
expect(@frag.css('[data-stripped-secure-media]')).not_to be_present expect(@frag.css('[data-stripped-secure-upload]')).not_to be_present
expect(@frag.children.attr('style').value).to eq("width: 20px; height: 30px;") expect(@frag.children.attr('style').value).to eq("width: 20px; height: 30px;")
end end
end end
@ -321,11 +321,11 @@ RSpec.describe Email::Styles do
<<~HTML <<~HTML
<aside class="onebox allowlistedgeneric"> <aside class="onebox allowlistedgeneric">
<header class="source"> <header class="source">
<img src="#{Discourse.base_url}/secure-media-uploads/original/1X/#{siteicon.sha1}.ico" class="site-icon" width="64" height="64"> <img src="#{Discourse.base_url}/secure-uploads/original/1X/#{siteicon.sha1}.ico" class="site-icon" width="64" height="64">
<a href="https://test.com/article" target="_blank" rel="noopener" title="02:33PM - 24 October 2020">Test</a> <a href="https://test.com/article" target="_blank" rel="noopener" title="02:33PM - 24 October 2020">Test</a>
</header> </header>
<article class="onebox-body"> <article class="onebox-body">
<div class="aspect-image" style="--aspect-ratio:20/30;"><img src="#{Discourse.base_url}/secure-media-uploads/optimized/2X/1/123456_2_20x30.png" class="thumbnail d-lazyload" width="20" height="30" srcset="#{Discourse.base_url}/secure-media-uploads/optimized/2X/1/123456_2_20x30.png"></div> <div class="aspect-image" style="--aspect-ratio:20/30;"><img src="#{Discourse.base_url}/secure-uploads/optimized/2X/1/123456_2_20x30.png" class="thumbnail d-lazyload" width="20" height="30" srcset="#{Discourse.base_url}/secure-uploads/optimized/2X/1/123456_2_20x30.png"></div>
<h3><a href="https://test.com/article" target="_blank" rel="noopener">Test</a></h3> <h3><a href="https://test.com/article" target="_blank" rel="noopener">Test</a></h3>
@ -344,7 +344,7 @@ RSpec.describe Email::Styles do
strip_and_inline strip_and_inline
expect(@frag.to_s).to include("cid:email/test.png") expect(@frag.to_s).to include("cid:email/test.png")
expect(@frag.to_s).to include("cid:email/test2.ico") expect(@frag.to_s).to include("cid:email/test2.ico")
expect(@frag.css('[data-stripped-secure-media]')).not_to be_present expect(@frag.css('[data-stripped-secure-upload]')).not_to be_present
expect(@frag.css('[data-embedded-secure-image]')[0].attr('style')).to eq('width: 16px; height: 16px;') expect(@frag.css('[data-embedded-secure-image]')[0].attr('style')).to eq('width: 16px; height: 16px;')
expect(@frag.css('[data-embedded-secure-image]')[1].attr('style')).to eq('width: 60px; max-height: 80%; max-width: 20%; height: auto; float: left; margin-right: 10px;') expect(@frag.css('[data-embedded-secure-image]')[1].attr('style')).to eq('width: 60px; max-height: 80%; max-width: 20%; height: auto; float: left; margin-right: 10px;')
end end
@ -354,11 +354,11 @@ RSpec.describe Email::Styles do
<<~HTML <<~HTML
<aside class="onebox allowlistedgeneric"> <aside class="onebox allowlistedgeneric">
<header class="source"> <header class="source">
<img src="#{Discourse.base_url}/secure-media-uploads/original/1X/#{siteicon.sha1}.ico" class="site-icon" width="64" height="64"> <img src="#{Discourse.base_url}/secure-uploads/original/1X/#{siteicon.sha1}.ico" class="site-icon" width="64" height="64">
<a href="https://test.com/article" target="_blank" rel="noopener" title="02:33PM - 24 October 2020">Test</a> <a href="https://test.com/article" target="_blank" rel="noopener" title="02:33PM - 24 October 2020">Test</a>
</header> </header>
<article class="onebox-body"> <article class="onebox-body">
<img src="#{Discourse.base_url}/secure-media-uploads/original/1X/123456.png" class="thumbnail onebox-avatar" width="20" height="30"> <img src="#{Discourse.base_url}/secure-uploads/original/1X/123456.png" class="thumbnail onebox-avatar" width="20" height="30">
<h3><a href="https://test.com/article" target="_blank" rel="noopener">Test</a></h3> <h3><a href="https://test.com/article" target="_blank" rel="noopener">Test</a></h3>
@ -376,7 +376,7 @@ RSpec.describe Email::Styles do
strip_and_inline strip_and_inline
expect(@frag.to_s).to include("cid:email/test.png") expect(@frag.to_s).to include("cid:email/test.png")
expect(@frag.to_s).to include("cid:email/test2.ico") expect(@frag.to_s).to include("cid:email/test2.ico")
expect(@frag.css('[data-stripped-secure-media]')).not_to be_present expect(@frag.css('[data-stripped-secure-upload]')).not_to be_present
expect(@frag.css('[data-embedded-secure-image]')[1].attr('style')).to eq('width: 60px; max-height: 80%; max-width: 20%; height: auto; float: left; margin-right: 10px;') expect(@frag.css('[data-embedded-secure-image]')[1].attr('style')).to eq('width: 60px; max-height: 80%; max-width: 20%; height: auto; float: left; margin-right: 10px;')
end end
end end
@ -405,7 +405,7 @@ RSpec.describe Email::Styles do
</div> </div>
<div class="user"> <div class="user">
<a href="https://github.com/udan11" target="_blank" rel="noopener"> <a href="https://github.com/udan11" target="_blank" rel="noopener">
<img alt="udan11" src="#{Discourse.base_url}/secure-media-uploads/original/1X/123456.png" class="onebox-avatar-inline" width="20" height="20"> <img alt="udan11" src="#{Discourse.base_url}/secure-uploads/original/1X/123456.png" class="onebox-avatar-inline" width="20" height="20">
udan11 udan11
</a> </a>
</div> </div>
@ -428,7 +428,7 @@ RSpec.describe Email::Styles do
it "keeps the special onebox styles" do it "keeps the special onebox styles" do
strip_and_inline strip_and_inline
expect(@frag.to_s).to include("cid:email/test.png") expect(@frag.to_s).to include("cid:email/test.png")
expect(@frag.css('[data-stripped-secure-media]')).not_to be_present expect(@frag.css('[data-stripped-secure-upload]')).not_to be_present
expect(@frag.css('[data-embedded-secure-image]')[0].attr('style')).to eq('width: 20px; height: 20px; float: none; vertical-align: middle; max-height: 80%; max-width: 20%; height: auto; float: left; margin-right: 10px;') expect(@frag.css('[data-embedded-secure-image]')[0].attr('style')).to eq('width: 20px; height: 20px; float: none; vertical-align: middle; max-height: 80%; max-width: 20%; height: auto; float: left; margin-right: 10px;')
end end
end end

View File

@ -173,9 +173,9 @@ RSpec.describe FileStore::BaseStore do
expect(file.class).to eq(File) expect(file.class).to eq(File)
end end
it "should return the file when secure media are enabled" do it "should return the file when secure uploads are enabled" do
SiteSetting.login_required = true SiteSetting.login_required = true
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
stub_request(:head, "https://s3-upload-bucket.s3.#{SiteSetting.s3_region}.amazonaws.com/") stub_request(:head, "https://s3-upload-bucket.s3.#{SiteSetting.s3_region}.amazonaws.com/")
signed_url = Discourse.store.signed_url_for_path(upload_s3.url) signed_url = Discourse.store.signed_url_for_path(upload_s3.url)

View File

@ -3864,10 +3864,10 @@ RSpec.describe Guardian do
expect(Guardian.new(admin).can_publish_page?(post.topic)).to eq(false) expect(Guardian.new(admin).can_publish_page?(post.topic)).to eq(false)
end end
context "when secure_media is also enabled" do context "when secure_uploads is also enabled" do
before do before do
setup_s3 setup_s3
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
end end
it "is false for everyone" do it "is false for everyone" do

View File

@ -1839,7 +1839,7 @@ RSpec.describe PostCreator do
end end
end end
describe "secure media uploads" do describe "secure uploads uploads" do
fab!(:image_upload) { Fabricate(:upload, secure: true) } fab!(:image_upload) { Fabricate(:upload, secure: true) }
fab!(:user2) { Fabricate(:user) } fab!(:user2) { Fabricate(:user) }
fab!(:public_topic) { Fabricate(:topic) } fab!(:public_topic) { Fabricate(:topic) }
@ -1847,7 +1847,7 @@ RSpec.describe PostCreator do
before do before do
setup_s3 setup_s3
SiteSetting.authorized_extensions = "png|jpg|gif|mp4" SiteSetting.authorized_extensions = "png|jpg|gif|mp4"
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
stub_upload(image_upload) stub_upload(image_upload)
end end

View File

@ -1242,13 +1242,13 @@ RSpec.describe PostRevisor do
expect(post.reload.upload_references.pluck(:upload_id)).to contain_exactly(image2.id, image3.id, image4.id) expect(post.reload.upload_references.pluck(:upload_id)).to contain_exactly(image2.id, image3.id, image4.id)
end end
context "with secure media uploads" do context "with secure uploads uploads" do
let!(:image5) { Fabricate(:secure_upload) } let!(:image5) { Fabricate(:secure_upload) }
before do before do
Jobs.run_immediately! Jobs.run_immediately!
setup_s3 setup_s3
SiteSetting.authorized_extensions = "png|jpg|gif|mp4" SiteSetting.authorized_extensions = "png|jpg|gif|mp4"
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
stub_upload(image5) stub_upload(image5)
end end

View File

@ -1125,19 +1125,19 @@ RSpec.describe PrettyText do
end end
end end
describe "#strip_secure_media" do describe "#strip_secure_uploads" do
before do before do
setup_s3 setup_s3
SiteSetting.s3_cdn_url = "https://s3.cdn.com" SiteSetting.s3_cdn_url = "https://s3.cdn.com"
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
SiteSetting.login_required = true SiteSetting.login_required = true
end end
it "replaces secure video content" do it "replaces secure video content" do
html = <<~HTML html = <<~HTML
<video width="100%" height="100%" controls=""> <video width="100%" height="100%" controls="">
<source src="#{base_url}/secure-media-uploads/original/1X/some-video.mp4"> <source src="#{base_url}/secure-uploads/original/1X/some-video.mp4">
<a href="#{base_url}/secure-media-uploads/original/1X/some-video.mp4">Video label</a> <a href="#{base_url}/secure-uploads/original/1X/some-video.mp4">Video label</a>
</source> </source>
</video> </video>
HTML HTML
@ -1145,58 +1145,58 @@ RSpec.describe PrettyText do
md = PrettyText.format_for_email(html, post) md = PrettyText.format_for_email(html, post)
expect(md).not_to include('<video') expect(md).not_to include('<video')
expect(md.to_s).to match(I18n.t("emails.secure_media_placeholder")) expect(md.to_s).to match(I18n.t("emails.secure_uploads_placeholder"))
expect(md.to_s).not_to match(SiteSetting.Upload.s3_cdn_url) expect(md.to_s).not_to match(SiteSetting.Upload.s3_cdn_url)
end end
it "replaces secure audio content" do it "replaces secure audio content" do
html = <<~HTML html = <<~HTML
<audio controls> <audio controls>
<source src="#{base_url}/secure-media-uploads/original/1X/some-audio.mp3"> <source src="#{base_url}/secure-uploads/original/1X/some-audio.mp3">
<a href="#{base_url}/secure-media-uploads/original/1X/some-audio.mp3">Audio label</a> <a href="#{base_url}/secure-uploads/original/1X/some-audio.mp3">Audio label</a>
</source> </source>
</audio> </audio>
HTML HTML
md = PrettyText.format_for_email(html, post) md = PrettyText.format_for_email(html, post)
expect(md).not_to include('<video') expect(md).not_to include('<audio')
expect(md.to_s).to match(I18n.t("emails.secure_media_placeholder")) expect(md.to_s).to match(I18n.t("emails.secure_uploads_placeholder"))
expect(md.to_s).not_to match(SiteSetting.Upload.s3_cdn_url) expect(md.to_s).not_to match(SiteSetting.Upload.s3_cdn_url)
end end
it "replaces secure media within a link with a placeholder, keeping the url in an attribute" do it "replaces secure uploads within a link with a placeholder, keeping the url in an attribute" do
url = "#{Discourse.base_url}\/secure-media-uploads/original/1X/testimage.png" url = "#{Discourse.base_url}\/secure-uploads/original/1X/testimage.png"
html = <<~HTML html = <<~HTML
<a href=\"#{url}\"><img src=\"/secure-media-uploads/original/1X/testimage.png\"></a> <a href=\"#{url}\"><img src=\"/secure-uploads/original/1X/testimage.png\"></a>
HTML HTML
md = PrettyText.format_for_email(html, post) md = PrettyText.format_for_email(html, post)
expect(md).not_to include('<img') expect(md).not_to include('<img')
expect(md).to include("Redacted") expect(md).to include("Redacted")
expect(md).to include("data-stripped-secure-media=\"#{url}\"") expect(md).to include("data-stripped-secure-upload=\"#{url}\"")
end end
it "does not create nested redactions from double processing because of the view media link" do it "does not create nested redactions from double processing because of the view media link" do
url = "#{Discourse.base_url}\/secure-media-uploads/original/1X/testimage.png" url = "#{Discourse.base_url}\/secure-uploads/original/1X/testimage.png"
html = <<~HTML html = <<~HTML
<a href=\"#{url}\"><img src=\"/secure-media-uploads/original/1X/testimage.png\"></a> <a href=\"#{url}\"><img src=\"/secure-uploads/original/1X/testimage.png\"></a>
HTML HTML
md = PrettyText.format_for_email(html, post) md = PrettyText.format_for_email(html, post)
md = PrettyText.format_for_email(md, post) md = PrettyText.format_for_email(md, post)
expect(md.scan(/stripped-secure-view-media/).length).to eq(1) expect(md.scan(/stripped-secure-view-upload/).length).to eq(1)
expect(md.scan(/Redacted/).length).to eq(1) expect(md.scan(/Redacted/).length).to eq(1)
end end
it "replaces secure images with a placeholder, keeping the url in an attribute" do it "replaces secure images with a placeholder, keeping the url in an attribute" do
url = "/secure-media-uploads/original/1X/testimage.png" url = "/secure-uploads/original/1X/testimage.png"
html = <<~HTML html = <<~HTML
<img src=\"#{url}\" width=\"20\" height=\"20\"> <img src=\"#{url}\" width=\"20\" height=\"20\">
HTML HTML
md = PrettyText.format_for_email(html, post) md = PrettyText.format_for_email(html, post)
expect(md).not_to include('<img') expect(md).not_to include('<img')
expect(md).to include("Redacted") expect(md).to include("Redacted")
expect(md).to include("data-stripped-secure-media=\"#{url}\"") expect(md).to include("data-stripped-secure-upload=\"#{url}\"")
expect(md).to include("data-width=\"20\"") expect(md).to include("data-width=\"20\"")
expect(md).to include("data-height=\"20\"") expect(md).to include("data-height=\"20\"")
end end

View File

@ -210,10 +210,10 @@ RSpec.describe SiteSettings::Validations do
expect { subject.validate_enable_page_publishing("t") }.not_to raise_error expect { subject.validate_enable_page_publishing("t") }.not_to raise_error
end end
context "if secure media is enabled" do context "if secure uploads is enabled" do
let(:error_message) { I18n.t("errors.site_settings.page_publishing_requirements") } let(:error_message) { I18n.t("errors.site_settings.page_publishing_requirements") }
before do before do
enable_secure_media enable_secure_uploads
end end
it "is not ok" do it "is not ok" do
@ -223,8 +223,8 @@ RSpec.describe SiteSettings::Validations do
end end
end end
describe "#validate_secure_media" do describe "#validate_secure_uploads" do
let(:error_message) { I18n.t("errors.site_settings.secure_media_requirements") } let(:error_message) { I18n.t("errors.site_settings.secure_uploads_requirements") }
context "when the new value is true" do context "when the new value is true" do
context 'if site setting for enable_s3_uploads is enabled' do context 'if site setting for enable_s3_uploads is enabled' do
@ -233,7 +233,7 @@ RSpec.describe SiteSettings::Validations do
end end
it "should be ok" do it "should be ok" do
expect { subject.validate_secure_media("t") }.not_to raise_error expect { subject.validate_secure_uploads("t") }.not_to raise_error
end end
end end
@ -243,7 +243,7 @@ RSpec.describe SiteSettings::Validations do
end end
it "is not ok" do it "is not ok" do
expect { subject.validate_secure_media("t") }.to raise_error(Discourse::InvalidParameters, error_message) expect { subject.validate_secure_uploads("t") }.to raise_error(Discourse::InvalidParameters, error_message)
end end
context "if global s3 setting is enabled" do context "if global s3 setting is enabled" do
@ -252,7 +252,7 @@ RSpec.describe SiteSettings::Validations do
end end
it "should be ok" do it "should be ok" do
expect { subject.validate_secure_media("t") }.not_to raise_error expect { subject.validate_secure_uploads("t") }.not_to raise_error
end end
end end
end end

View File

@ -27,10 +27,10 @@ RSpec.describe TopicUploadSecurityManager do
context "when the topic category is read restricted" do context "when the topic category is read restricted" do
let(:category) { Fabricate(:private_category, group: group) } let(:category) { Fabricate(:private_category, group: group) }
context "when secure media is enabled" do context "when secure uploads is enabled" do
before do before do
setup_s3 setup_s3
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
[upload, upload2, upload3].each { |upl| stub_upload(upl) } [upload, upload2, upload3].each { |upl| stub_upload(upl) }
end end
@ -49,7 +49,7 @@ RSpec.describe TopicUploadSecurityManager do
end end
end end
context "when secure media is disabled" do context "when secure uploads is disabled" do
it "changes the upload secure statuses to false and updates ACLs and rebakes" do it "changes the upload secure statuses to false and updates ACLs and rebakes" do
expect_upload_status_to_change_and_rebake expect_upload_status_to_change_and_rebake
end end
@ -59,10 +59,10 @@ RSpec.describe TopicUploadSecurityManager do
context "when the topic is a private message" do context "when the topic is a private message" do
let(:topic) { Fabricate(:private_message_topic, category: category, user: user) } let(:topic) { Fabricate(:private_message_topic, category: category, user: user) }
context "when secure media is enabled" do context "when secure uploads is enabled" do
before do before do
setup_s3 setup_s3
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
[upload, upload2, upload3].each { |upl| stub_upload(upl) } [upload, upload2, upload3].each { |upl| stub_upload(upl) }
end end
@ -81,7 +81,7 @@ RSpec.describe TopicUploadSecurityManager do
end end
end end
context "when secure media is disabled" do context "when secure uploads is disabled" do
it "changes the upload secure statuses to false and updates ACLs and rebakes" do it "changes the upload secure statuses to false and updates ACLs and rebakes" do
expect_upload_status_to_change_and_rebake expect_upload_status_to_change_and_rebake
end end
@ -89,10 +89,10 @@ RSpec.describe TopicUploadSecurityManager do
end end
context "when the topic is public" do context "when the topic is public" do
context "when secure media is enabled" do context "when secure uploads is enabled" do
before do before do
setup_s3 setup_s3
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
[upload, upload2, upload3].each { |upl| stub_upload(upl) } [upload, upload2, upload3].each { |upl| stub_upload(upl) }
end end
@ -125,7 +125,7 @@ RSpec.describe TopicUploadSecurityManager do
before do before do
setup_s3 setup_s3
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
[upload, upload2, upload3].each { |upl| stub_upload(upl) } [upload, upload2, upload3].each { |upl| stub_upload(upl) }
end end
@ -142,9 +142,9 @@ RSpec.describe TopicUploadSecurityManager do
expect(upload3.reload.access_control_post).to eq(post4) expect(upload3.reload.access_control_post).to eq(post4)
end end
context "when secure media is not enabled" do context "when secure uploads is not enabled" do
before do before do
SiteSetting.secure_media = false SiteSetting.secure_uploads = false
end end
it "does not change the upload secure status and does not set the access control post" do it "does not change the upload secure status and does not set the access control post" do

View File

@ -305,7 +305,7 @@ RSpec.describe UploadCreator do
setup_s3 setup_s3
stub_s3_store stub_s3_store
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
SiteSetting.authorized_extensions = 'pdf|svg|jpg' SiteSetting.authorized_extensions = 'pdf|svg|jpg'
end end
@ -357,7 +357,7 @@ RSpec.describe UploadCreator do
it 'should return signed URL for secure attachments in S3' do it 'should return signed URL for secure attachments in S3' do
SiteSetting.authorized_extensions = 'pdf' SiteSetting.authorized_extensions = 'pdf'
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
upload = UploadCreator.new(pdf_file, pdf_filename, opts).create_for(user.id) upload = UploadCreator.new(pdf_file, pdf_filename, opts).create_for(user.id)
stored_upload = Upload.last stored_upload = Upload.last
@ -399,12 +399,12 @@ RSpec.describe UploadCreator do
end end
end end
context "when SiteSetting.secure_media is enabled" do context "when SiteSetting.secure_uploads is enabled" do
before do before do
setup_s3 setup_s3
stub_s3_store stub_s3_store
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
end end
it "does not return the existing upload, as duplicate uploads are allowed" do it "does not return the existing upload, as duplicate uploads are allowed" do
@ -413,18 +413,18 @@ RSpec.describe UploadCreator do
end end
end end
context "with secure media functionality" do context "with secure uploads functionality" do
let(:filename) { "logo.jpg" } let(:filename) { "logo.jpg" }
let(:file) { file_from_fixtures(filename) } let(:file) { file_from_fixtures(filename) }
let(:opts) { {} } let(:opts) { {} }
let(:result) { UploadCreator.new(file, filename, opts).create_for(user.id) } let(:result) { UploadCreator.new(file, filename, opts).create_for(user.id) }
context "when SiteSetting.secure_media enabled" do context "when SiteSetting.secure_uploads enabled" do
before do before do
setup_s3 setup_s3
stub_s3_store stub_s3_store
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
end end
it "sets an original_sha1 on the upload created because the sha1 column is securerandom in this case" do it "sets an original_sha1 on the upload created because the sha1 column is securerandom in this case" do

View File

@ -161,7 +161,7 @@ RSpec.describe UploadRecovery do
end end
it 'does not create a duplicate upload when secure uploads are enabled' do it 'does not create a duplicate upload when secure uploads are enabled' do
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
upload.verification_status = Upload.verification_statuses[:invalid_etag] upload.verification_status = Upload.verification_statuses[:invalid_etag]
upload.save! upload.save!

View File

@ -8,10 +8,10 @@ RSpec.describe UploadSecurity do
let(:opts) { { type: type, creating: true } } let(:opts) { { type: type, creating: true } }
subject { described_class.new(upload, opts) } subject { described_class.new(upload, opts) }
context "when secure media is enabled" do context "when secure uploads is enabled" do
before do before do
setup_s3 setup_s3
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
end end
context "when login_required (everything should be secure except public context items)" do context "when login_required (everything should be secure except public context items)" do
@ -126,7 +126,7 @@ RSpec.describe UploadSecurity do
end end
end end
context "when the access control post has_secure_media?" do context "when the access control post has_secure_uploads?" do
before do before do
upload.update(access_control_post_id: post_in_secure_context.id) upload.update(access_control_post_id: post_in_secure_context.id)
end end
@ -138,7 +138,7 @@ RSpec.describe UploadSecurity do
before do before do
post_in_secure_context.trash! post_in_secure_context.trash!
end end
it "still determines whether the post has secure media; returns true" do it "still determines whether the post has secure uploads; returns true" do
expect(subject.should_be_secure?).to eq(true) expect(subject.should_be_secure?).to eq(true)
end end
end end
@ -180,7 +180,7 @@ RSpec.describe UploadSecurity do
upload.update(original_filename: 'test.pdf') upload.update(original_filename: 'test.pdf')
end end
context "when the access control post has_secure_media?" do context "when the access control post has_secure_uploads?" do
before do before do
upload.update(access_control_post: post_in_secure_context) upload.update(access_control_post: post_in_secure_context)
end end
@ -191,9 +191,9 @@ RSpec.describe UploadSecurity do
end end
end end
context "when secure media is disabled" do context "when secure uploads is disabled" do
before do before do
SiteSetting.secure_media = false SiteSetting.secure_uploads = false
end end
it "returns false" do it "returns false" do
expect(subject.should_be_secure?).to eq(false) expect(subject.should_be_secure?).to eq(false)

View File

@ -197,7 +197,7 @@ RSpec.describe UrlHelper do
FileStore::S3Store.any_instance.stubs(:has_been_uploaded?).returns(true) FileStore::S3Store.any_instance.stubs(:has_been_uploaded?).returns(true)
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
end end
def cooked def cooked
@ -209,12 +209,12 @@ RSpec.describe UrlHelper do
it "returns the secure_proxy_without_cdn url, with no asset host URL change" do it "returns the secure_proxy_without_cdn url, with no asset host URL change" do
expect(cooked).to eq( expect(cooked).to eq(
"//test.localhost/secure-media-uploads/dev/original/3X/2/e/2e6f2ef81b6910ea592cd6d21ee897cd51cf72e4.jpeg" "//test.localhost/secure-uploads/dev/original/3X/2/e/2e6f2ef81b6910ea592cd6d21ee897cd51cf72e4.jpeg"
) )
end end
context "when secure_media setting is disabled" do context "when secure_uploads setting is disabled" do
before { SiteSetting.secure_media = false } before { SiteSetting.secure_uploads = false }
it "returns the local_cdn_url" do it "returns the local_cdn_url" do
expect(cooked).to eq( expect(cooked).to eq(

View File

@ -344,7 +344,7 @@ RSpec.describe OptimizedImage do
end end
context "when the thumbnail is properly generated" do context "when the thumbnail is properly generated" do
context "with secure media disabled" do context "with secure uploads disabled" do
let(:s3_upload) { Fabricate(:upload_s3) } let(:s3_upload) { Fabricate(:upload_s3) }
let(:optimized_path) { %r{/optimized/\d+X.*/#{s3_upload.sha1}_2_100x200\.png} } let(:optimized_path) { %r{/optimized/\d+X.*/#{s3_upload.sha1}_2_100x200\.png} }

View File

@ -149,25 +149,25 @@ RSpec.describe Post do
end end
end end
describe "with_secure_media?" do describe "with_secure_uploads?" do
let(:topic) { Fabricate(:topic) } let(:topic) { Fabricate(:topic) }
let!(:post) { Fabricate(:post, topic: topic) } let!(:post) { Fabricate(:post, topic: topic) }
it "returns false if secure media is not enabled" do it "returns false if secure uploads is not enabled" do
expect(post.with_secure_media?).to eq(false) expect(post.with_secure_uploads?).to eq(false)
end end
context "when secure media is enabled" do context "when secure uploads is enabled" do
before do before do
setup_s3 setup_s3
SiteSetting.authorized_extensions = "pdf|png|jpg|csv" SiteSetting.authorized_extensions = "pdf|png|jpg|csv"
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
end end
context "if login_required" do context "if login_required" do
before { SiteSetting.login_required = true } before { SiteSetting.login_required = true }
it "returns true" do it "returns true" do
expect(post.with_secure_media?).to eq(true) expect(post.with_secure_uploads?).to eq(true)
end end
end end
@ -178,7 +178,7 @@ RSpec.describe Post do
end end
it "returns true" do it "returns true" do
expect(post.with_secure_media?).to eq(true) expect(post.with_secure_uploads?).to eq(true)
end end
end end
@ -186,7 +186,7 @@ RSpec.describe Post do
let(:topic) { Fabricate(:private_message_topic) } let(:topic) { Fabricate(:private_message_topic) }
it "returns true" do it "returns true" do
expect(post.with_secure_media?).to eq(true) expect(post.with_secure_uploads?).to eq(true)
end end
end end
end end
@ -1476,11 +1476,11 @@ RSpec.describe Post do
expect(post.reload.upload_references.pluck(:id)).to_not contain_exactly(post_uploads_ids) expect(post.reload.upload_references.pluck(:id)).to_not contain_exactly(post_uploads_ids)
end end
context "when secure media is enabled" do context "when secure uploads is enabled" do
before do before do
setup_s3 setup_s3
SiteSetting.authorized_extensions = "pdf|png|jpg|csv" SiteSetting.authorized_extensions = "pdf|png|jpg|csv"
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
end end
it "sets the access_control_post_id on uploads in the post that don't already have the value set" do it "sets the access_control_post_id on uploads in the post that don't already have the value set" do
@ -1523,7 +1523,7 @@ RSpec.describe Post do
setup_s3 setup_s3
SiteSetting.authorized_extensions = "pdf|png|jpg|csv" SiteSetting.authorized_extensions = "pdf|png|jpg|csv"
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
attachment_upload.update!(original_filename: "hello.csv") attachment_upload.update!(original_filename: "hello.csv")
@ -1531,8 +1531,8 @@ RSpec.describe Post do
stub_upload(image_upload) stub_upload(image_upload)
end end
it "marks image and attachment uploads as secure in PMs when secure_media is ON" do it "marks image and attachment uploads as secure in PMs when secure_uploads is ON" do
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
post = Fabricate(:post, raw: raw, user: user, topic: Fabricate(:private_message_topic, user: user)) post = Fabricate(:post, raw: raw, user: user, topic: Fabricate(:private_message_topic, user: user))
post.link_post_uploads post.link_post_uploads
post.update_uploads_secure_status(source: "test") post.update_uploads_secure_status(source: "test")
@ -1543,8 +1543,8 @@ RSpec.describe Post do
) )
end end
it "marks image uploads as not secure in PMs when when secure_media is ON" do it "marks image uploads as not secure in PMs when when secure_uploads is ON" do
SiteSetting.secure_media = false SiteSetting.secure_uploads = false
post = Fabricate(:post, raw: raw, user: user, topic: Fabricate(:private_message_topic, user: user)) post = Fabricate(:post, raw: raw, user: user, topic: Fabricate(:private_message_topic, user: user))
post.link_post_uploads post.link_post_uploads
post.update_uploads_secure_status(source: "test") post.update_uploads_secure_status(source: "test")
@ -1556,7 +1556,7 @@ RSpec.describe Post do
end end
it "marks attachments as secure when relevant setting is enabled" do it "marks attachments as secure when relevant setting is enabled" do
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
private_category = Fabricate(:private_category, group: Fabricate(:group)) private_category = Fabricate(:private_category, group: Fabricate(:group))
post = Fabricate(:post, raw: raw, user: user, topic: Fabricate(:topic, user: user, category: private_category)) post = Fabricate(:post, raw: raw, user: user, topic: Fabricate(:topic, user: user, category: private_category))
post.link_post_uploads post.link_post_uploads
@ -1697,7 +1697,7 @@ RSpec.describe Post do
it "correctly identifies secure uploads" do it "correctly identifies secure uploads" do
setup_s3 setup_s3
SiteSetting.authorized_extensions = "pdf|png|jpg|csv" SiteSetting.authorized_extensions = "pdf|png|jpg|csv"
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
upload1 = Fabricate(:upload_s3, secure: true) upload1 = Fabricate(:upload_s3, secure: true)
upload2 = Fabricate(:upload_s3, secure: true) upload2 = Fabricate(:upload_s3, secure: true)

View File

@ -399,9 +399,9 @@ RSpec.describe Upload do
let(:upload) { Fabricate(:upload, original_filename: "small.pdf", extension: "pdf", secure: true) } let(:upload) { Fabricate(:upload, original_filename: "small.pdf", extension: "pdf", secure: true) }
it 'marks a local attachment as secure if secure media enabled' do it 'marks a local attachment as secure if secure uploads enabled' do
upload.update!(secure: false, access_control_post: Fabricate(:private_message_post)) upload.update!(secure: false, access_control_post: Fabricate(:private_message_post))
enable_secure_media enable_secure_uploads
expect { upload.update_secure_status } expect { upload.update_secure_status }
.to change { upload.secure } .to change { upload.secure }
@ -409,7 +409,7 @@ RSpec.describe Upload do
expect(upload.secure).to eq(true) expect(upload.secure).to eq(true)
end end
it 'marks a local attachment as not secure if secure media enabled' do it 'marks a local attachment as not secure if secure uploads enabled' do
expect { upload.update_secure_status } expect { upload.update_secure_status }
.to change { upload.secure } .to change { upload.secure }
@ -428,9 +428,9 @@ RSpec.describe Upload do
expect(upload.secure).to eq(false) expect(upload.secure).to eq(false)
end end
context "with secure media enabled" do context "with secure uploads enabled" do
before do before do
enable_secure_media enable_secure_uploads
end end
it "does not mark an image upload as not secure when there is no access control post id, to avoid unintentional exposure" do it "does not mark an image upload as not secure when there is no access control post id, to avoid unintentional exposure" do
@ -543,9 +543,9 @@ RSpec.describe Upload do
end end
end end
def enable_secure_media def enable_secure_uploads
setup_s3 setup_s3
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
stub_upload(upload) stub_upload(upload)
end end
@ -568,54 +568,54 @@ RSpec.describe Upload do
end end
end end
describe ".secure_media_url_from_upload_url" do describe ".secure_uploads_url_from_upload_url" do
before do before do
# must be done so signed_url_for_path exists # must be done so signed_url_for_path exists
enable_secure_media enable_secure_uploads
end end
it "gets the secure media url from an S3 upload url" do it "gets the secure uploads url from an S3 upload url" do
upload = Fabricate(:upload_s3, secure: true) upload = Fabricate(:upload_s3, secure: true)
url = upload.url url = upload.url
secure_url = Upload.secure_media_url_from_upload_url(url) secure_url = Upload.secure_uploads_url_from_upload_url(url)
expect(secure_url).not_to include(SiteSetting.Upload.absolute_base_url) expect(secure_url).not_to include(SiteSetting.Upload.absolute_base_url)
end end
end end
describe ".secure_media_url?" do describe ".secure_uploads_url?" do
it "works for a secure media url with or without schema + host" do it "works for a secure uploads url with or without schema + host" do
url = "//localhost:3000/secure-media-uploads/original/2X/f/f62055931bb702c7fd8f552fb901f977e0289a18.png" url = "//localhost:3000/secure-uploads/original/2X/f/f62055931bb702c7fd8f552fb901f977e0289a18.png"
expect(Upload.secure_media_url?(url)).to eq(true) expect(Upload.secure_uploads_url?(url)).to eq(true)
url = "/secure-media-uploads/original/2X/f/f62055931bb702c7fd8f552fb901f977e0289a18.png" url = "/secure-uploads/original/2X/f/f62055931bb702c7fd8f552fb901f977e0289a18.png"
expect(Upload.secure_media_url?(url)).to eq(true) expect(Upload.secure_uploads_url?(url)).to eq(true)
url = "http://localhost:3000/secure-media-uploads/original/2X/f/f62055931bb702c7fd8f552fb901f977e0289a18.png" url = "http://localhost:3000/secure-uploads/original/2X/f/f62055931bb702c7fd8f552fb901f977e0289a18.png"
expect(Upload.secure_media_url?(url)).to eq(true) expect(Upload.secure_uploads_url?(url)).to eq(true)
end end
it "does not get false positives on a topic url" do it "does not get false positives on a topic url" do
url = "/t/secure-media-uploads-are-cool/42839" url = "/t/secure-uploads-are-cool/42839"
expect(Upload.secure_media_url?(url)).to eq(false) expect(Upload.secure_uploads_url?(url)).to eq(false)
end end
it "returns true only for secure media URL for actual media (images/video/audio)" do it "returns true only for secure uploads URL for actual media (images/video/audio)" do
url = "/secure-media-uploads/original/2X/f/f62055931bb702c7fd8f552fb901f977e0289a18.mp4" url = "/secure-uploads/original/2X/f/f62055931bb702c7fd8f552fb901f977e0289a18.mp4"
expect(Upload.secure_media_url?(url)).to eq(true) expect(Upload.secure_uploads_url?(url)).to eq(true)
url = "/secure-media-uploads/original/2X/f/f62055931bb702c7fd8f552fb901f977e0289a18.png" url = "/secure-uploads/original/2X/f/f62055931bb702c7fd8f552fb901f977e0289a18.png"
expect(Upload.secure_media_url?(url)).to eq(true) expect(Upload.secure_uploads_url?(url)).to eq(true)
url = "/secure-media-uploads/original/2X/f/f62055931bb702c7fd8f552fb901f977e0289a18.mp3" url = "/secure-uploads/original/2X/f/f62055931bb702c7fd8f552fb901f977e0289a18.mp3"
expect(Upload.secure_media_url?(url)).to eq(true) expect(Upload.secure_uploads_url?(url)).to eq(true)
url = "/secure-media-uploads/original/2X/f/f62055931bb702c7fd8f552fb901f977e0289a18.pdf" url = "/secure-uploads/original/2X/f/f62055931bb702c7fd8f552fb901f977e0289a18.pdf"
expect(Upload.secure_media_url?(url)).to eq(false) expect(Upload.secure_uploads_url?(url)).to eq(false)
end end
it "does not work for regular upload urls" do it "does not work for regular upload urls" do
url = "/uploads/default/test_0/original/1X/e1864389d8252958586c76d747b069e9f68827e3.png" url = "/uploads/default/test_0/original/1X/e1864389d8252958586c76d747b069e9f68827e3.png"
expect(Upload.secure_media_url?(url)).to eq(false) expect(Upload.secure_uploads_url?(url)).to eq(false)
end end
it "does not raise for invalid URLs" do it "does not raise for invalid URLs" do
url = "http://URL:%20https://google.com" url = "http://URL:%20https://google.com"
expect(Upload.secure_media_url?(url)).to eq(false) expect(Upload.secure_uploads_url?(url)).to eq(false)
end end
end end

View File

@ -172,7 +172,7 @@ RSpec.describe 'Multisite s3 uploads', type: :multisite do
end end
end end
describe 'secure uploads' do describe 'secure uploadss' do
let(:store) { FileStore::S3Store.new } let(:store) { FileStore::S3Store.new }
let(:client) { Aws::S3::Client.new(stub_responses: true) } let(:client) { Aws::S3::Client.new(stub_responses: true) }
let(:resource) { Aws::S3::Resource.new(client: client) } let(:resource) { Aws::S3::Resource.new(client: client) }
@ -209,10 +209,10 @@ RSpec.describe 'Multisite s3 uploads', type: :multisite do
end end
end end
describe "when secure media are enabled" do describe "when secure uploads are enabled" do
before do before do
SiteSetting.login_required = true SiteSetting.login_required = true
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
s3_helper.stubs(:s3_client).returns(client) s3_helper.stubs(:s3_client).returns(client)
Discourse.stubs(:store).returns(store) Discourse.stubs(:store).returns(store)
end end

View File

@ -100,10 +100,10 @@ RSpec.describe PublishedPagesController do
published_page.topic.tags = [Fabricate(:tag, name: "recipes")] published_page.topic.tags = [Fabricate(:tag, name: "recipes")]
end end
context "when secure media is enabled" do context "when secure uploads is enabled" do
before do before do
setup_s3 setup_s3
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
end end
it "returns 404" do it "returns 404" do

View File

@ -6,7 +6,7 @@ RSpec.describe UploadsController, type: [:multisite, :request] do
before do before do
setup_s3 setup_s3
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
upload.update(secure: true) upload.update(secure: true)
end end

View File

@ -399,9 +399,9 @@ RSpec.describe UploadsController do
expect(response).to redirect_to(upload.url) expect(response).to redirect_to(upload.url)
end end
context "when upload is secure and secure media enabled" do context "when upload is secure and secure uploads enabled" do
before do before do
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
upload.update(secure: true) upload.update(secure: true)
end end
@ -448,8 +448,8 @@ RSpec.describe UploadsController do
describe "local store" do describe "local store" do
fab!(:image_upload) { upload_file("smallest.png") } fab!(:image_upload) { upload_file("smallest.png") }
it "does not return secure media when using local store" do it "does not return secure uploads when using local store" do
secure_url = image_upload.url.sub("/uploads", "/secure-media-uploads") secure_url = image_upload.url.sub("/uploads", "/secure-uploads")
get secure_url get secure_url
expect(response.status).to eq(404) expect(response.status).to eq(404)
@ -458,12 +458,12 @@ RSpec.describe UploadsController do
describe "s3 store" do describe "s3 store" do
let(:upload) { Fabricate(:upload_s3) } let(:upload) { Fabricate(:upload_s3) }
let(:secure_url) { upload.url.sub(SiteSetting.Upload.absolute_base_url, "/secure-media-uploads") } let(:secure_url) { upload.url.sub(SiteSetting.Upload.absolute_base_url, "/secure-uploads") }
before do before do
setup_s3 setup_s3
SiteSetting.authorized_extensions = "*" SiteSetting.authorized_extensions = "*"
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
end end
it "should return 404 for anonymous requests requests" do it "should return 404 for anonymous requests requests" do
@ -479,7 +479,7 @@ RSpec.describe UploadsController do
expect(response.redirect_url).to match("Amz-Expires") expect(response.redirect_url).to match("Amz-Expires")
end end
it "should return secure media URL when looking up urls" do it "should return secure uploads URL when looking up urls" do
upload.update_column(:secure, true) upload.update_column(:secure, true)
sign_in(user) sign_in(user)
@ -487,7 +487,7 @@ RSpec.describe UploadsController do
expect(response.status).to eq(200) expect(response.status).to eq(200)
result = response.parsed_body result = response.parsed_body
expect(result[0]["url"]).to match("secure-media-uploads") expect(result[0]["url"]).to match("secure-uploads")
end end
context "when the upload cannot be found from the URL" do context "when the upload cannot be found from the URL" do
@ -571,9 +571,9 @@ RSpec.describe UploadsController do
end end
end end
context "when secure media is disabled" do context "when secure uploads is disabled" do
before do before do
SiteSetting.secure_media = false SiteSetting.secure_uploads = false
end end
context "if the upload is secure false, meaning the ACL is probably public" do context "if the upload is secure false, meaning the ACL is probably public" do
@ -582,7 +582,7 @@ RSpec.describe UploadsController do
end end
it "should redirect to the regular show route" do it "should redirect to the regular show route" do
secure_url = upload.url.sub(SiteSetting.Upload.absolute_base_url, "/secure-media-uploads") secure_url = upload.url.sub(SiteSetting.Upload.absolute_base_url, "/secure-uploads")
sign_in(user) sign_in(user)
get secure_url get secure_url
@ -597,7 +597,7 @@ RSpec.describe UploadsController do
end end
it "should redirect to the presigned URL still otherwise we will get a 403" do it "should redirect to the presigned URL still otherwise we will get a 403" do
secure_url = upload.url.sub(SiteSetting.Upload.absolute_base_url, "/secure-media-uploads") secure_url = upload.url.sub(SiteSetting.Upload.absolute_base_url, "/secure-uploads")
sign_in(user) sign_in(user)
get secure_url get secure_url
@ -622,23 +622,23 @@ RSpec.describe UploadsController do
expect(result[0]["short_path"]).to eq(upload.short_path) expect(result[0]["short_path"]).to eq(upload.short_path)
end end
describe 'secure media' do describe 'secure uploads' do
let(:upload) { Fabricate(:upload_s3, secure: true) } let(:upload) { Fabricate(:upload_s3, secure: true) }
before do before do
setup_s3 setup_s3
SiteSetting.authorized_extensions = "pdf|png" SiteSetting.authorized_extensions = "pdf|png"
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
end end
it 'returns secure url for a secure media upload' do it 'returns secure url for a secure uploads upload' do
sign_in(user) sign_in(user)
post "/uploads/lookup-urls.json", params: { short_urls: [upload.short_url] } post "/uploads/lookup-urls.json", params: { short_urls: [upload.short_url] }
expect(response.status).to eq(200) expect(response.status).to eq(200)
result = response.parsed_body result = response.parsed_body
expect(result[0]["url"]).to match("/secure-media-uploads") expect(result[0]["url"]).to match("/secure-uploads")
expect(result[0]["short_path"]).to eq(upload.short_path) expect(result[0]["short_path"]).to eq(upload.short_path)
end end
@ -650,7 +650,7 @@ RSpec.describe UploadsController do
expect(response.status).to eq(200) expect(response.status).to eq(200)
result = response.parsed_body result = response.parsed_body
expect(result[0]["url"]).to match("/secure-media-uploads") expect(result[0]["url"]).to match("/secure-uploads")
expect(result[0]["short_path"]).to eq(upload.short_path) expect(result[0]["short_path"]).to eq(upload.short_path)
end end
end end

View File

@ -487,10 +487,10 @@ RSpec.describe TopicViewSerializer do
expect(json[:published_page][:slug]).to eq(published_page.slug) expect(json[:published_page][:slug]).to eq(published_page.slug)
end end
context "when secure media is enabled" do context "when secure uploads is enabled" do
before do before do
setup_s3 setup_s3
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
end end
it "doesn't return the published page" do it "doesn't return the published page" do

View File

@ -18,17 +18,17 @@ RSpec.describe UploadSerializer do
context "when the upload is secure" do context "when the upload is secure" do
fab!(:upload) { Fabricate(:secure_upload) } fab!(:upload) { Fabricate(:secure_upload) }
context "when secure media is disabled" do context "when secure uploads is disabled" do
it "just returns the normal URL, otherwise S3 errors are encountered" do it "just returns the normal URL, otherwise S3 errors are encountered" do
UrlHelper.expects(:cook_url).with(upload.url, secure: false) UrlHelper.expects(:cook_url).with(upload.url, secure: false)
subject.to_json subject.to_json
end end
end end
context "when secure media is enabled" do context "when secure uploads is enabled" do
before do before do
setup_s3 setup_s3
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
end end
it "returns the cooked URL based on the upload URL" do it "returns the cooked URL based on the upload URL" do

View File

@ -13,9 +13,16 @@ module UploadsHelpers
stub_request(:head, "https://#{SiteSetting.s3_upload_bucket}.s3.#{SiteSetting.s3_region}.amazonaws.com/") stub_request(:head, "https://#{SiteSetting.s3_upload_bucket}.s3.#{SiteSetting.s3_region}.amazonaws.com/")
end end
# TODO (martin) Remove this alias once discourse-chat plugin has been
# updated to use secure_uploads instead.
def enable_secure_media def enable_secure_media
enable_secure_uploads
DiscourseEvent.trigger(:site_setting_changed, :secure_media, false, true)
end
def enable_secure_uploads
setup_s3 setup_s3
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
end end
def stub_upload(upload) def stub_upload(upload)

View File

@ -52,9 +52,9 @@ RSpec.describe "tasks/uploads" do
uploads.each { |upload| stub_upload(upload) } uploads.each { |upload| stub_upload(upload) }
end end
context "when secure media is enabled" do context "when secure upload is enabled" do
before do before do
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
end end
it "sets an access_control_post for each post upload, using the first linked post in the case of multiple links" do it "sets an access_control_post for each post upload, using the first linked post in the case of multiple links" do
@ -155,10 +155,10 @@ RSpec.describe "tasks/uploads" do
end end
end end
describe "uploads:disable_secure_media" do describe "uploads:disable_secure_uploads" do
def invoke_task def invoke_task
capture_stdout do capture_stdout do
Rake::Task['uploads:disable_secure_media'].invoke Rake::Task['uploads:disable_secure_uploads'].invoke
end end
end end
@ -166,7 +166,7 @@ RSpec.describe "tasks/uploads" do
setup_s3 setup_s3
uploads.each { |upload| stub_upload(upload) } uploads.each { |upload| stub_upload(upload) }
SiteSetting.secure_media = true SiteSetting.secure_uploads = true
UploadReference.create(target: post1, upload: upload1) UploadReference.create(target: post1, upload: upload1)
UploadReference.create(target: post1, upload: upload2) UploadReference.create(target: post1, upload: upload2)
UploadReference.create(target: post2, upload: upload3) UploadReference.create(target: post2, upload: upload3)
@ -186,9 +186,9 @@ RSpec.describe "tasks/uploads" do
let(:upload4) { Fabricate(:upload_s3, secure: true, access_control_post: post2) } let(:upload4) { Fabricate(:upload_s3, secure: true, access_control_post: post2) }
let(:upload5) { Fabricate(:upload_s3, secure: false) } let(:upload5) { Fabricate(:upload_s3, secure: false) }
it "disables the secure media setting" do it "disables the secure upload setting" do
invoke_task invoke_task
expect(SiteSetting.secure_media).to eq(false) expect(SiteSetting.secure_uploads).to eq(false)
end end
it "updates all secure uploads to secure: false" do it "updates all secure uploads to secure: false" do