From 2c6a314460a32def6be601f9656b96b5c8c65b05 Mon Sep 17 00:00:00 2001 From: Josh Schwartzman Date: Sun, 10 Dec 2023 23:23:21 -0700 Subject: [PATCH] Sign URL uploads if configured (#139) Fix namespace for service Add spec for upload_from_url Fix requiring of SignatureGenerator and location of tests --- lib/uploadcare/client/uploader_client.rb | 15 +-- .../upload_upload_from_url_with_signature.yml | 116 ++++++++++++++++++ .../uploadcare/client/uploader_client_spec.rb | 7 +- spec/uploadcare/entity/uploader_spec.rb | 31 ++++- 4 files changed, 158 insertions(+), 11 deletions(-) create mode 100644 spec/fixtures/vcr_cassettes/upload_upload_from_url_with_signature.yml diff --git a/lib/uploadcare/client/uploader_client.rb b/lib/uploadcare/client/uploader_client.rb index ecc0f25..a5d157c 100644 --- a/lib/uploadcare/client/uploader_client.rb +++ b/lib/uploadcare/client/uploader_client.rb @@ -3,6 +3,7 @@ require_relative 'upload_client' require 'retries' require 'param/upload/upload_params_generator' +require 'param/upload/signature_generator' module Uploadcare module Client @@ -106,13 +107,13 @@ def upload_many_body(arr, options = {}) # Prepare upload_from_url initial request body def upload_from_url_body(url, options = {}) - HTTP::FormData::Multipart.new( - options.merge( - 'pub_key' => Uploadcare.config.public_key, - 'source_url' => url, - 'store' => store_value(options[:store]) - ) - ) + opts = { + 'pub_key' => Uploadcare.config.public_key, + 'source_url' => url, + 'store' => store_value(options[:store]) + } + opts.merge!(Param::Upload::SignatureGenerator.call) if Uploadcare.config.sign_uploads + HTTP::FormData::Multipart.new(options.merge(opts)) end def store_value(store) diff --git a/spec/fixtures/vcr_cassettes/upload_upload_from_url_with_signature.yml b/spec/fixtures/vcr_cassettes/upload_upload_from_url_with_signature.yml new file mode 100644 index 0000000..0e05e64 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/upload_upload_from_url_with_signature.yml @@ -0,0 +1,116 @@ +--- +http_interactions: +- request: + method: post + uri: https://upload.uploadcare.com/from_url/ + body: + encoding: ASCII-8BIT + string: "-----------------------c5f0754b5a5d1bfb797b6944cc4c653cdf2b5c20ab\r\nContent-Disposition: + form-data; name=\"pub_key\"\r\n\r\ndemopublickey\r\n-----------------------c5f0754b5a5d1bfb797b6944cc4c653cdf2b5c20ab\r\nContent-Disposition: + form-data; name=\"source_url\"\r\n\r\nhttps://placekitten.com/2250/2250\r\n-----------------------c5f0754b5a5d1bfb797b6944cc4c653cdf2b5c20ab\r\nContent-Disposition: + form-data; name=\"store\"\r\n\r\nauto\r\n-----------------------c5f0754b5a5d1bfb797b6944cc4c653cdf2b5c20ab\r\nContent-Disposition: + form-data; name=\"signature\"\r\n\r\nf6b1a41383cb2179c57cd1baf967ace8\r\n-----------------------c5f0754b5a5d1bfb797b6944cc4c653cdf2b5c20ab\r\nContent-Disposition: + form-data; name=\"expire\"\r\n\r\n1701130306\r\n-----------------------c5f0754b5a5d1bfb797b6944cc4c653cdf2b5c20ab--\r\n" + headers: + User-Agent: + - UploadcareRuby/4.3.6/demopublickey (Ruby/3.0.5) + Content-Type: + - multipart/form-data; boundary=---------------------c5f0754b5a5d1bfb797b6944cc4c653cdf2b5c20ab + Connection: + - close + Host: + - upload.uploadcare.com + response: + status: + code: 200 + message: OK + headers: + Date: + - Mon, 27 Nov 2023 23:41:47 GMT + Content-Type: + - application/json + Content-Length: + - '63' + Connection: + - close + Server: + - nginx + Vary: + - Accept-Encoding + - Origin + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Methods: + - OPTIONS, GET, POST + Access-Control-Allow-Headers: + - DNT, X-UC-User-Agent, X-PINGOTHER + Access-Control-Max-Age: + - '1' + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - Warning, Retry-After + X-Xss-Protection: + - 1; mode=block + X-Content-Type-Options: + - nosniff + X-Uploadcare-Request-Id: + - ffc67f72-2b8f-46c9-8239-1da1de4c869a + body: + encoding: UTF-8 + string: '{"type":"token","token":"ff450eec-48ad-491c-bfb7-804698c78951"}' + recorded_at: Mon, 27 Nov 2023 23:41:47 GMT +- request: + method: get + uri: https://upload.uploadcare.com/from_url/status/?token=ff450eec-48ad-491c-bfb7-804698c78951 + body: + encoding: ASCII-8BIT + string: '' + headers: + User-Agent: + - UploadcareRuby/4.3.6/demopublickey (Ruby/3.0.5) + Connection: + - close + Host: + - upload.uploadcare.com + response: + status: + code: 200 + message: OK + headers: + Date: + - Mon, 27 Nov 2023 23:41:48 GMT + Content-Type: + - application/json + Content-Length: + - '726' + Connection: + - close + Server: + - nginx + Vary: + - Accept-Encoding + - Origin + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Methods: + - GET, POST, HEAD, OPTIONS + Access-Control-Allow-Headers: + - DNT, X-PINGOTHER, X-UC-User-Agent + Access-Control-Max-Age: + - '1' + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Expose-Headers: + - Warning, Retry-After + X-Xss-Protection: + - 1; mode=block + X-Content-Type-Options: + - nosniff + X-Uploadcare-Request-Id: + - 176cc03a-0df5-4a45-8ff1-b5a394af8b7d + body: + encoding: UTF-8 + string: '{"size":297261,"total":297261,"done":297261,"uuid":"1a4844c6-2463-440a-80a8-219e3d00e22a","file_id":"1a4844c6-2463-440a-80a8-219e3d00e22a","original_filename":"2250","is_image":true,"is_stored":true,"image_info":{"dpi":[96,96],"width":2250,"format":"JPEG","height":2250,"sequence":false,"color_mode":"RGB","orientation":null,"geo_location":null,"datetime_original":null},"video_info":null,"content_info":{"mime":{"mime":"image/jpeg","type":"image","subtype":"jpeg"},"image":{"dpi":[96,96],"width":2250,"format":"JPEG","height":2250,"sequence":false,"color_mode":"RGB","orientation":null,"geo_location":null,"datetime_original":null}},"is_ready":true,"filename":"2250","mime_type":"image/jpeg","metadata":{},"status":"success"}' + recorded_at: Mon, 27 Nov 2023 23:41:48 GMT +recorded_with: VCR 6.2.0 diff --git a/spec/uploadcare/client/uploader_client_spec.rb b/spec/uploadcare/client/uploader_client_spec.rb index 7f2c57e..d4bc797 100644 --- a/spec/uploadcare/client/uploader_client_spec.rb +++ b/spec/uploadcare/client/uploader_client_spec.rb @@ -5,11 +5,12 @@ module Uploadcare module Client RSpec.describe UploaderClient do - subject { UploaderClient.new } - let!(:file) { ::File.open('spec/fixtures/kitten.jpeg') } - let!(:another_file) { ::File.open('spec/fixtures/another_kitten.jpeg') } + subject { described_class.new } describe 'upload' do + let(:file) { ::File.open('spec/fixtures/kitten.jpeg') } + let(:another_file) { ::File.open('spec/fixtures/another_kitten.jpeg') } + it 'uploads a file' do VCR.use_cassette('upload_upload') do response = subject.upload(file, metadata: { subsystem: 'test' }) diff --git a/spec/uploadcare/entity/uploader_spec.rb b/spec/uploadcare/entity/uploader_spec.rb index 395ed14..0dd81d2 100644 --- a/spec/uploadcare/entity/uploader_spec.rb +++ b/spec/uploadcare/entity/uploader_spec.rb @@ -46,11 +46,40 @@ module Entity end describe 'upload_from_url' do + let(:url) { 'https://placekitten.com/2250/2250' } + + before do + allow(HTTP::FormData::Multipart).to receive(:new).and_call_original + end + it 'polls server and returns array of files' do VCR.use_cassette('upload_upload_from_url') do - url = 'https://placekitten.com/2250/2250' upload = subject.upload(url) expect(upload[0]).to be_kind_of(Uploadcare::Entity::File) + expect(HTTP::FormData::Multipart).to have_received(:new).with( + a_hash_including( + 'source_url' => url + ) + ) + end + end + + context 'when signed uploads are enabled' do + before do + allow(Uploadcare.config).to receive(:sign_uploads).and_return(true) + end + + it 'includes signature' do + VCR.use_cassette('upload_upload_from_url_with_signature') do + upload = subject.upload(url) + expect(upload[0]).to be_kind_of(Uploadcare::Entity::File) + expect(HTTP::FormData::Multipart).to have_received(:new).with( + a_hash_including( + signature: instance_of(String), + expire: instance_of(Integer) + ) + ) + end end end end