Don't overwrite photos of other users during import
If a photo with the same filename already exists, generate a new random filename, and re-federate the photo with that filename. This ensures users can't modify their archive to overwrite other users photos.
This commit is contained in:
parent
e9f7bf382e
commit
d3c2407df1
2 changed files with 82 additions and 9 deletions
|
|
@ -47,27 +47,40 @@ class ImportService
|
|||
|
||||
uncompressed_photos_folder = unzip_photos_file(path_to_photos)
|
||||
user.posts.find_in_batches do |posts|
|
||||
import_photos_for_posts(posts, uncompressed_photos_folder)
|
||||
import_photos_for_posts(user, posts, uncompressed_photos_folder)
|
||||
end
|
||||
FileUtils.rmdir(uncompressed_photos_folder)
|
||||
FileUtils.rm_r(uncompressed_photos_folder)
|
||||
end
|
||||
|
||||
def import_photos_for_posts(posts, source_dir)
|
||||
def import_photos_for_posts(user, posts, source_dir)
|
||||
posts.each do |post|
|
||||
post.photos.each do |photo|
|
||||
uploaded_file = "#{source_dir}/#{photo.remote_photo_name}"
|
||||
next unless File.exist?(uploaded_file) && photo.remote_photo_name.present?
|
||||
|
||||
File.open(uploaded_file) do |file|
|
||||
photo.random_string = File.basename(uploaded_file, ".*")
|
||||
photo.unprocessed_image = file
|
||||
photo.save(touch: false)
|
||||
end
|
||||
photo.queue_processing_job
|
||||
# Don't overwrite existing photos if they have the same filename.
|
||||
# Generate a new random filename if a conflict exists and re-federate the photo to update on remote pods.
|
||||
random_string = File.basename(uploaded_file, ".*")
|
||||
conflicting_photo_exists = Photo.where.not(id: photo.id).exists?(random_string: random_string)
|
||||
random_string = SecureRandom.hex(10) if conflicting_photo_exists
|
||||
|
||||
store_and_process_photo(photo, uploaded_file, random_string)
|
||||
|
||||
Diaspora::Federation::Dispatcher.build(user, photo).dispatch if conflicting_photo_exists
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def store_and_process_photo(photo, uploaded_file, random_string)
|
||||
File.open(uploaded_file) do |file|
|
||||
photo.random_string = random_string
|
||||
photo.unprocessed_image.store! file
|
||||
photo.update_remote_path
|
||||
photo.save(touch: false)
|
||||
end
|
||||
photo.queue_processing_job
|
||||
end
|
||||
|
||||
def unzip_photos_file(photo_file_path)
|
||||
folder = create_folder(photo_file_path)
|
||||
Zip::File.open(photo_file_path) do |zip_file|
|
||||
|
|
|
|||
60
spec/integration/import_service_spec.rb
Normal file
60
spec/integration/import_service_spec.rb
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
describe ImportService do
|
||||
context "import photos archive" do
|
||||
let(:user) { FactoryBot.create(:user) }
|
||||
let(:photo) { FactoryBot.create(:status_message_with_photo, author: user.person).photos.first }
|
||||
let(:photo_archive) {
|
||||
user.perform_export_photos!
|
||||
photo_archive = user.exported_photos_file
|
||||
|
||||
# cleanup photo after creating the archive, so it's like it was imported from a remote pod
|
||||
photo.unprocessed_image = nil
|
||||
photo.random_string = nil
|
||||
photo.remote_photo_path = "https://old.example.com/uploads/images/"
|
||||
photo.save
|
||||
|
||||
photo_archive
|
||||
}
|
||||
|
||||
it "imports the photo with the same name" do
|
||||
old_random_string = photo.random_string
|
||||
|
||||
inlined_jobs { ImportService.new.import_by_files(nil, photo_archive.current_path, user.username) }
|
||||
|
||||
imported_photo = photo.reload
|
||||
expect(imported_photo.random_string).to include(old_random_string)
|
||||
expect(imported_photo.unprocessed_image.path).to include(old_random_string)
|
||||
expect(imported_photo.processed_image.path).to include(old_random_string)
|
||||
expect(imported_photo.remote_photo_name).to include(old_random_string)
|
||||
expect(imported_photo.remote_photo_path).to eq("#{AppConfig.pod_uri}uploads/images/")
|
||||
end
|
||||
|
||||
it "imports the photo with a new random name if a conflicting photo already exists" do
|
||||
old_random_string = photo.random_string
|
||||
photo_archive_path = photo_archive.current_path
|
||||
|
||||
sm = FactoryBot.create(:status_message)
|
||||
FactoryBot.create(:photo, author: sm.author, status_message: sm, random_string: old_random_string)
|
||||
|
||||
expect(Diaspora::Federation::Dispatcher).to receive(:build) do |user_param, photo_param|
|
||||
expect(user_param).to eq(user)
|
||||
expect(photo_param.id).to eq(photo.id)
|
||||
|
||||
dispatcher = double
|
||||
expect(dispatcher).to receive(:dispatch)
|
||||
dispatcher
|
||||
end
|
||||
|
||||
inlined_jobs { ImportService.new.import_by_files(nil, photo_archive_path, user.username) }
|
||||
|
||||
imported_photo = photo.reload
|
||||
new_random_string = imported_photo.random_string
|
||||
expect(new_random_string).not_to include(old_random_string)
|
||||
expect(imported_photo.unprocessed_image.path).to include(new_random_string)
|
||||
expect(imported_photo.processed_image.path).to include(new_random_string)
|
||||
expect(imported_photo.remote_photo_name).to include(new_random_string)
|
||||
expect(imported_photo.remote_photo_path).to eq("#{AppConfig.pod_uri}uploads/images/")
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Reference in a new issue