Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added better logo file validation #8934

Merged
merged 1 commit into from
Oct 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion app/controllers/ops_controller/settings/upload.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def upload_favicon

def upload_logos(file, field, text, type)
if field && field[:logo] && field[:logo].respond_to?(:read)
if field[:logo].original_filename.split(".").last.downcase != type
unless valid_file?(field[:logo], type)
add_flash(_("%{image} must be a .%{type} file") % {:image => text, :type => type}, :error)
else
File.open(file, "wb") { |f| f.write(field[:logo].read) }
Expand Down Expand Up @@ -115,4 +115,28 @@ def logo_dir
Dir.mkdir(dir) unless dir.exist?
dir.to_s
end

def valid_file?(file, type)
ext = file.original_filename.split(".").last.downcase
return false unless ext == type

case type
when "ico"
valid_magic_number = "\x00\x00\x01\x00".force_encoding("ASCII-8BIT")
when "png"
valid_magic_number = "\x89PNG\r\n\x1A\n".force_encoding("ASCII-8BIT")
else
return false
end

magic_number = File.open(file.tempfile.path, 'rb') do |f|
begin
f.readpartial(valid_magic_number.size)
rescue EOFError
return false
end
end

magic_number == valid_magic_number
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This is a test file.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
92 changes: 92 additions & 0 deletions spec/controllers/ops_controller/settings/upload_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,98 @@
stub_user(:features => :all)
end

describe '#upload_png' do
before do
allow(controller).to receive(:load_edit).and_return(true)
allow(controller).to receive(:redirect_to)
controller.instance_variable_set(:@sb, :active_tab => 'settings_custom_logos', :selected_server_id => 123)
end

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

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

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

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

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

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

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

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

file = 'app/assets/images/favicon.ico'
controller.params = {:brand => {:logo => ActionDispatch::Http::UploadedFile.new(:tempfile => File.open(file), :filename => 'favicon.ico', :type => 'image/png')}}
controller.send(:upload_login_brand)
expect(controller.instance_variable_get(:@flash_array)).to include(:message => 'Custom brand must be a .png file', :level => :error)
end
end

describe '#upload_ico' do
before do
allow(controller).to receive(:load_edit).and_return(true)
allow(controller).to receive(:redirect_to)
controller.instance_variable_set(:@sb, :active_tab => 'settings_custom_logos', :selected_server_id => 123)
end

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

it 'adds error flash message to @flash_array regarding updating custom favicon with a non .ico file' do
file = File.join(__dir__, '/data/test.txt.ico')
controller.params = {:favicon => {:logo => ActionDispatch::Http::UploadedFile.new(:tempfile => File.open(file), :filename => 'test.txt.ico', :type => 'image/png')}}
controller.send(:upload_favicon)
expect(controller.instance_variable_get(:@flash_array)).to include(:message => 'Custom favicon must be a .ico file', :level => :error)

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

describe '#upload_csv' do
let(:file) { StringIO.new("name,category,entry\nevm1,Environment,Test") }

Expand Down