Skip to content

Commit f890e1a

Browse files
authored
Merge pull request #9299 from kbrock/file_upload_type
Ensure uploaded images are image files
2 parents ef89acf + 6463af5 commit f890e1a

File tree

12 files changed

+75
-74
lines changed

12 files changed

+75
-74
lines changed

app/controllers/catalog_controller.rb

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ class CatalogController < ApplicationController
33
include Mixins::ServiceDialogCreationMixin
44
include Mixins::BreadcrumbsMixin
55
include Mixins::AutomationMixin
6+
include Mixins::ImageValidationMixin
67

78
before_action :check_privileges
89
before_action :get_session_data
@@ -533,31 +534,28 @@ def st_upload_image
533534

534535
err = false
535536
identify_catalog(params[:id])
537+
image_file = params.dig(:upload, :image)
536538
if params[:pressed]
537539
@record.picture = nil
538540
@record.save
539541
msg = _("Custom Image successfully removed")
540-
elsif params[:upload] && params[:upload][:image] &&
541-
params[:upload][:image].respond_to?(:read)
542-
ext = params[:upload][:image].original_filename.split(".").last.downcase
543-
if !%w[png jpg].include?(ext)
544-
msg = _("Custom Image must be a .png or .jpg file")
545-
err = true
546-
else
547-
picture = {:content => params[:upload][:image].read,
548-
:extension => ext}
549-
if @record.picture.nil?
550-
@record.picture = Picture.new(picture)
551-
else
552-
@record.picture.update(picture)
553-
end
554-
@record.save
555-
msg = _("Custom Image file \"%{name}\" successfully uploaded") %
556-
{:name => params[:upload][:image].original_filename}
557-
end
558-
else
542+
elsif !image_file&.respond_to?(:read)
559543
msg = _("Use the Choose file button to locate a .png or .jpg image file")
560544
err = true
545+
elsif !valid_image_file?(image_file)
546+
msg = _("Custom Image must be a .png or .jpg file")
547+
err = true
548+
else
549+
ext = image_file.original_filename.split(".").last.downcase
550+
picture = {:content => image_file.read, :extension => ext}
551+
if @record.picture.nil?
552+
@record.picture = Picture.new(picture)
553+
else
554+
@record.picture.update(picture)
555+
end
556+
@record.save
557+
msg = _("Custom Image file \"%{name}\" successfully uploaded") %
558+
{:name => image_file.original_filename}
561559
end
562560
params[:id] = x_build_node_id(@record) # Get the tree node id
563561
add_flash(msg, err == true ? :error : nil)
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
module Mixins
2+
module ImageValidationMixin
3+
private
4+
5+
# @param file request parameter for a file
6+
# @param ext if present, the only extension supported (default: nil / accept all extensions)
7+
def valid_image_file?(file, type = nil)
8+
ext = file.original_filename.split(".").last.downcase
9+
return false if type && !Array.wrap(type).include?(ext)
10+
11+
valid_magic_number =
12+
case ext
13+
when "ico"
14+
"\x00\x00\x01\x00".force_encoding("ASCII-8BIT")
15+
when "png"
16+
"\x89PNG\r\n\x1A\n".force_encoding("ASCII-8BIT")
17+
when "jpg"
18+
"\xff\xd8\xff".force_encoding("ASCII-8BIT")
19+
else
20+
return false
21+
end
22+
23+
magic_number = File.open(file.tempfile.path, 'rb') do |f|
24+
f.readpartial(valid_magic_number.size)
25+
end
26+
27+
magic_number == valid_magic_number
28+
rescue EOFError
29+
return false
30+
end
31+
end
32+
end

app/controllers/ops_controller/settings/upload.rb

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
module OpsController::Settings::Upload
22
extend ActiveSupport::Concern
3+
include Mixins::ImageValidationMixin
34

45
def upload_logo
56
assert_privileges("ops_settings")
@@ -31,7 +32,7 @@ def upload_favicon
3132

3233
def upload_logos(file, field, text, type)
3334
if field && field[:logo] && field[:logo].respond_to?(:read)
34-
unless valid_file?(field[:logo], type)
35+
unless valid_image_file?(field[:logo], type)
3536
add_flash(_("%{image} must be a .%{type} file") % {:image => text, :type => type}, :error)
3637
else
3738
File.open(file, "wb") { |f| f.write(field[:logo].read) }
@@ -115,28 +116,4 @@ def logo_dir
115116
Dir.mkdir(dir) unless dir.exist?
116117
dir.to_s
117118
end
118-
119-
def valid_file?(file, type)
120-
ext = file.original_filename.split(".").last.downcase
121-
return false unless ext == type
122-
123-
case type
124-
when "ico"
125-
valid_magic_number = "\x00\x00\x01\x00".force_encoding("ASCII-8BIT")
126-
when "png"
127-
valid_magic_number = "\x89PNG\r\n\x1A\n".force_encoding("ASCII-8BIT")
128-
else
129-
return false
130-
end
131-
132-
magic_number = File.open(file.tempfile.path, 'rb') do |f|
133-
begin
134-
f.readpartial(valid_magic_number.size)
135-
rescue EOFError
136-
return false
137-
end
138-
end
139-
140-
magic_number == valid_magic_number
141-
end
142119
end

spec/controllers/catalog_controller_spec.rb

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -353,13 +353,19 @@
353353
end
354354

355355
it "uploads a selected png file " do
356-
file = fixture_file_upload('files/upload_image.png', 'image/png')
356+
file = fixture_file_upload('spec/fixtures/image.png', 'image/png')
357357
post :st_upload_image, :params => { :format => :js, :id => @st.id, :upload => {:image => file}, :active_tree => :sandt_tree, :commit => 'Upload' }
358-
expect(assigns(:flash_array).first[:message]).to include('Custom Image file "upload_image.png" successfully uploaded')
358+
expect(assigns(:flash_array).first[:message]).to include('Custom Image file "image.png" successfully uploaded')
359+
end
360+
361+
it "uploads a selected jpg file " do
362+
file = fixture_file_upload('spec/fixtures/image.jpg', 'image/jpeg')
363+
post :st_upload_image, :params => { :format => :js, :id => @st.id, :upload => {:image => file}, :active_tree => :sandt_tree, :commit => 'Upload' }
364+
expect(assigns(:flash_array).first[:message]).to include('Custom Image file "image.jpg" successfully uploaded')
359365
end
360366

361367
it "displays an error when the selected file is not a png file or .jpg " do
362-
file = fixture_file_upload('files/upload_image.txt', 'image/png')
368+
file = fixture_file_upload('spec/fixtures/test.txt.png', 'image/png')
363369
post :st_upload_image, :params => { :format => :js, :id => @st.id, :upload => {:image => file}, :commit => 'Upload' }
364370
expect(assigns(:flash_array).first[:message]).to include("Custom Image must be a .png or .jpg file")
365371
end

spec/controllers/ops_controller/settings/upload_spec.rb

Lines changed: 15 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -11,58 +11,49 @@
1111
end
1212

1313
it 'adds success flash message to @flash_array regarding updating custom logo image with a .png file' do
14-
file = 'app/assets/images/layout/login-screen-logo.png'
15-
controller.params = {:upload => {:logo => ActionDispatch::Http::UploadedFile.new(:tempfile => File.open(file), :filename => 'login-screen-logo.png', :type => 'image/png')}}
14+
controller.params = {:upload => {:logo => fixture_file_upload('spec/fixtures/image.png', 'image/png')}}
1615
controller.send(:upload_logo)
17-
expect(controller.instance_variable_get(:@flash_array)).to include(:message => 'Custom logo image "login-screen-logo.png" uploaded', :level => :success)
16+
expect(controller.instance_variable_get(:@flash_array)).to include(:message => 'Custom logo image "image.png" uploaded', :level => :success)
1817
end
1918

2019
it 'adds error flash message to @flash_array regarding updating custom logo image with a non-png file' do
21-
file = File.join(__dir__, '/data/test.txt.png')
22-
controller.params = {:upload => {:logo => ActionDispatch::Http::UploadedFile.new(:tempfile => File.open(file), :filename => 'test.txt.png', :type => 'image/png')}}
20+
controller.params = {:upload => {:logo => fixture_file_upload('spec/fixtures/test.txt.png', 'image/png')}}
2321
controller.send(:upload_logo)
2422
expect(controller.instance_variable_get(:@flash_array)).to include(:message => 'Custom logo image must be a .png file', :level => :error)
2523

26-
file = 'app/assets/images/favicon.ico'
27-
controller.params = {:upload => {:logo => ActionDispatch::Http::UploadedFile.new(:tempfile => File.open(file), :filename => 'favicon.ico', :type => 'image/png')}}
24+
controller.params = {:upload => {:logo => fixture_file_upload('spec/fixtures/favicon.ico', 'image/png')}}
2825
controller.send(:upload_logo)
2926
expect(controller.instance_variable_get(:@flash_array)).to include(:message => 'Custom logo image must be a .png file', :level => :error)
3027
end
3128

3229
it 'adds success flash message to @flash_array regarding updating custom login and about screen background image with a .png file' do
33-
file = 'app/assets/images/layout/login-screen-logo.png'
34-
controller.params = {:login => {:logo => ActionDispatch::Http::UploadedFile.new(:tempfile => File.open(file), :filename => 'login-screen-logo.png', :type => 'image/png')}}
30+
controller.params = {:login => {:logo => fixture_file_upload('spec/fixtures/image.png', 'image/png')}}
3531
controller.send(:upload_login_logo)
36-
expect(controller.instance_variable_get(:@flash_array)).to include(:message => 'Custom login image "login-screen-logo.png" uploaded', :level => :success)
32+
expect(controller.instance_variable_get(:@flash_array)).to include(:message => 'Custom login image "image.png" uploaded', :level => :success)
3733
end
3834

3935
it 'adds error flash message to @flash_array regarding updating custom login and about screen background image with a non .png file' do
40-
file = File.join(__dir__, '/data/test.txt.png')
41-
controller.params = {:login => {:logo => ActionDispatch::Http::UploadedFile.new(:tempfile => File.open(file), :filename => 'test.txt.png', :type => 'image/png')}}
36+
controller.params = {:login => {:logo => fixture_file_upload('spec/fixtures/test.txt.png', 'image/png')}}
4237
controller.send(:upload_login_logo)
4338
expect(controller.instance_variable_get(:@flash_array)).to include(:message => 'Custom login image must be a .png file', :level => :error)
4439

45-
file = 'app/assets/images/favicon.ico'
46-
controller.params = {:login => {:logo => ActionDispatch::Http::UploadedFile.new(:tempfile => File.open(file), :filename => 'favicon.ico', :type => 'image/png')}}
40+
controller.params = {:login => {:logo => fixture_file_upload('spec/fixtures/favicon.ico', 'image/png')}}
4741
controller.send(:upload_login_logo)
4842
expect(controller.instance_variable_get(:@flash_array)).to include(:message => 'Custom login image must be a .png file', :level => :error)
4943
end
5044

5145
it 'adds success flash message to @flash_array regarding updating custom brand image with a .png file' do
52-
file = 'app/assets/images/layout/login-screen-logo.png'
53-
controller.params = {:brand => {:logo => ActionDispatch::Http::UploadedFile.new(:tempfile => File.open(file), :filename => 'login-screen-logo.png', :type => 'image/png')}}
46+
controller.params = {:brand => {:logo => fixture_file_upload('spec/fixtures/image.png', 'image/png')}}
5447
controller.send(:upload_login_brand)
55-
expect(controller.instance_variable_get(:@flash_array)).to include(:message => 'Custom brand "login-screen-logo.png" uploaded', :level => :success)
48+
expect(controller.instance_variable_get(:@flash_array)).to include(:message => 'Custom brand "image.png" uploaded', :level => :success)
5649
end
5750

5851
it 'adds error flash message to @flash_array regarding updating custom brand image with a non .png file' do
59-
file = File.join(__dir__, '/data/test.txt.png')
60-
controller.params = {:brand => {:logo => ActionDispatch::Http::UploadedFile.new(:tempfile => File.open(file), :filename => 'test.txt.png', :type => 'image/png')}}
52+
controller.params = {:brand => {:logo => fixture_file_upload('spec/fixtures/test.txt.png', 'image/png')}}
6153
controller.send(:upload_login_brand)
6254
expect(controller.instance_variable_get(:@flash_array)).to include(:message => 'Custom brand must be a .png file', :level => :error)
6355

64-
file = 'app/assets/images/favicon.ico'
65-
controller.params = {:brand => {:logo => ActionDispatch::Http::UploadedFile.new(:tempfile => File.open(file), :filename => 'favicon.ico', :type => 'image/png')}}
56+
controller.params = {:brand => {:logo => fixture_file_upload('spec/fixtures/favicon.ico', 'image/png')}}
6657
controller.send(:upload_login_brand)
6758
expect(controller.instance_variable_get(:@flash_array)).to include(:message => 'Custom brand must be a .png file', :level => :error)
6859
end
@@ -76,20 +67,17 @@
7667
end
7768

7869
it 'adds success flash message to @flash_array regarding updating custom favicon with an .ico file' do
79-
file = 'app/assets/images/favicon.ico'
80-
controller.params = {:favicon => {:logo => ActionDispatch::Http::UploadedFile.new(:tempfile => File.open(file), :filename => 'favicon.ico', :type => 'image/vnd.microsoft.icon')}}
70+
controller.params = {:favicon => {:logo => fixture_file_upload('spec/fixtures/favicon.ico', 'image/vnd.microsoft.icon')}}
8171
controller.send(:upload_favicon)
8272
expect(controller.instance_variable_get(:@flash_array)).to include(:message => 'Custom favicon "favicon.ico" uploaded', :level => :success)
8373
end
8474

8575
it 'adds error flash message to @flash_array regarding updating custom favicon with a non .ico file' do
86-
file = File.join(__dir__, '/data/test.txt.ico')
87-
controller.params = {:favicon => {:logo => ActionDispatch::Http::UploadedFile.new(:tempfile => File.open(file), :filename => 'test.txt.ico', :type => 'image/png')}}
76+
controller.params = {:favicon => {:logo => fixture_file_upload('spec/fixtures/test.txt.ico', 'image/vnd.microsoft.icon')}}
8877
controller.send(:upload_favicon)
8978
expect(controller.instance_variable_get(:@flash_array)).to include(:message => 'Custom favicon must be a .ico file', :level => :error)
9079

91-
file = 'app/assets/images/layout/login-screen-logo.png'
92-
controller.params = {:favicon => {:logo => ActionDispatch::Http::UploadedFile.new(:tempfile => File.open(file), :filename => 'test.ico', :type => 'image/vnd.microsoft.icon')}}
80+
controller.params = {:favicon => {:logo => fixture_file_upload('spec/fixtures/favicon.png.ico', 'image/vnd.microsoft.icon')}}
9381
controller.send(:upload_favicon)
9482
expect(controller.instance_variable_get(:@flash_array)).to include(:message => 'Custom favicon must be a .ico file', :level => :error)
9583
end

spec/fixtures/favicon.ico

24.3 KB
Binary file not shown.

spec/fixtures/favicon.png.ico

17.4 KB
Binary file not shown.

spec/fixtures/image.jpg

4.45 KB
Loading

spec/fixtures/image.png

17.4 KB
Loading

spec/fixtures/test.txt

Whitespace-only changes.

0 commit comments

Comments
 (0)