mirror of
https://github.com/neocities/neocities.git
synced 2025-04-28 11:12:30 +02:00
Scan for embedded viruses/executables in uploaded files
This commit is contained in:
parent
e756724fe7
commit
cc64a57172
4 changed files with 43 additions and 5 deletions
1
Gemfile
1
Gemfile
|
@ -18,6 +18,7 @@ gem 'tilt'
|
||||||
gem 'erubis'
|
gem 'erubis'
|
||||||
gem 'stripe', :git => 'https://github.com/stripe/stripe-ruby'
|
gem 'stripe', :git => 'https://github.com/stripe/stripe-ruby'
|
||||||
gem 'screencap'
|
gem 'screencap'
|
||||||
|
gem 'cocaine'
|
||||||
|
|
||||||
platform :mri do
|
platform :mri do
|
||||||
gem 'magic' # sudo apt-get install file, For OSX: brew install libmagic
|
gem 'magic' # sudo apt-get install file, For OSX: brew install libmagic
|
||||||
|
|
14
Gemfile.lock
14
Gemfile.lock
|
@ -10,6 +10,12 @@ GIT
|
||||||
GEM
|
GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
|
activesupport (4.1.4)
|
||||||
|
i18n (~> 0.6, >= 0.6.9)
|
||||||
|
json (~> 1.7, >= 1.7.7)
|
||||||
|
minitest (~> 5.1)
|
||||||
|
thread_safe (~> 0.1)
|
||||||
|
tzinfo (~> 1.1)
|
||||||
addressable (2.3.6)
|
addressable (2.3.6)
|
||||||
ago (0.1.5)
|
ago (0.1.5)
|
||||||
ansi (1.4.3)
|
ansi (1.4.3)
|
||||||
|
@ -30,7 +36,11 @@ GEM
|
||||||
minitest (>= 2)
|
minitest (>= 2)
|
||||||
celluloid (0.15.2)
|
celluloid (0.15.2)
|
||||||
timers (~> 1.1.0)
|
timers (~> 1.1.0)
|
||||||
|
climate_control (0.0.3)
|
||||||
|
activesupport (>= 3.0)
|
||||||
cliver (0.3.2)
|
cliver (0.3.2)
|
||||||
|
cocaine (0.5.4)
|
||||||
|
climate_control (>= 0.0.3, < 1.0)
|
||||||
coderay (1.1.0)
|
coderay (1.1.0)
|
||||||
columnize (0.3.6)
|
columnize (0.3.6)
|
||||||
connection_pool (2.0.0)
|
connection_pool (2.0.0)
|
||||||
|
@ -168,11 +178,14 @@ GEM
|
||||||
sinatra-xsendfile (0.4.2)
|
sinatra-xsendfile (0.4.2)
|
||||||
sinatra (>= 0.9.1)
|
sinatra (>= 0.9.1)
|
||||||
slop (3.5.0)
|
slop (3.5.0)
|
||||||
|
thread_safe (0.3.4)
|
||||||
tilt (1.4.1)
|
tilt (1.4.1)
|
||||||
timers (1.1.0)
|
timers (1.1.0)
|
||||||
treetop (1.4.15)
|
treetop (1.4.15)
|
||||||
polyglot
|
polyglot
|
||||||
polyglot (>= 0.3.1)
|
polyglot (>= 0.3.1)
|
||||||
|
tzinfo (1.2.2)
|
||||||
|
thread_safe (~> 0.1)
|
||||||
unicorn (4.8.2)
|
unicorn (4.8.2)
|
||||||
kgio (~> 2.6)
|
kgio (~> 2.6)
|
||||||
rack
|
rack
|
||||||
|
@ -193,6 +206,7 @@ DEPENDENCIES
|
||||||
bcrypt
|
bcrypt
|
||||||
capybara
|
capybara
|
||||||
capybara_minitest_spec
|
capybara_minitest_spec
|
||||||
|
cocaine
|
||||||
erubis
|
erubis
|
||||||
fabrication
|
fabrication
|
||||||
faker
|
faker
|
||||||
|
|
4
app.rb
4
app.rb
|
@ -636,7 +636,7 @@ post '/site_files/upload' do
|
||||||
end
|
end
|
||||||
|
|
||||||
if !Site.valid_file_type? file
|
if !Site.valid_file_type? file
|
||||||
file_upload_response "#{file[:filename]}: file type is not allowed on Neocities, upload cancelled."
|
file_upload_response "#{file[:filename]}: file type (or content in file) is not allowed on Neocities, upload cancelled."
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -941,7 +941,7 @@ post '/api/upload' do
|
||||||
|
|
||||||
files.each do |file|
|
files.each do |file|
|
||||||
if !Site.valid_file_type?(file)
|
if !Site.valid_file_type?(file)
|
||||||
api_error 400, 'invalid_file_type', "#{file[:filename]} is not a valid file type, files have not been uploaded"
|
api_error 400, 'invalid_file_type', "#{file[:filename]} is not a valid file type (or contains not allowed content), files have not been uploaded"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -60,6 +60,12 @@ class Site < Sequel::Model
|
||||||
SCREENSHOT_RESOLUTIONS = ['235x141', '105x63', '270x162', '37x37', '146x88', '302x182', '90x63', '82x62', '348x205']
|
SCREENSHOT_RESOLUTIONS = ['235x141', '105x63', '270x162', '37x37', '146x88', '302x182', '90x63', '82x62', '348x205']
|
||||||
THUMBNAIL_RESOLUTIONS = ['105x63', '90x63']
|
THUMBNAIL_RESOLUTIONS = ['105x63', '90x63']
|
||||||
|
|
||||||
|
CLAMAV_THREAT_MATCHES = [
|
||||||
|
/^VBS/,
|
||||||
|
/^PUA.Win32/,
|
||||||
|
/^JS.Popupper/
|
||||||
|
]
|
||||||
|
|
||||||
BANNED_TIME = 2592000 # 30 days in seconds
|
BANNED_TIME = 2592000 # 30 days in seconds
|
||||||
|
|
||||||
TITLE_MAX = 100
|
TITLE_MAX = 100
|
||||||
|
@ -261,9 +267,26 @@ class Site < Sequel::Model
|
||||||
def self.valid_file_type?(uploaded_file)
|
def self.valid_file_type?(uploaded_file)
|
||||||
mime_type = Magic.guess_file_mime_type uploaded_file[:tempfile].path
|
mime_type = Magic.guess_file_mime_type uploaded_file[:tempfile].path
|
||||||
|
|
||||||
return true if (Site::VALID_MIME_TYPES.include?(mime_type) || mime_type =~ /text/) &&
|
return false unless (Site::VALID_MIME_TYPES.include?(mime_type) || mime_type =~ /text/) &&
|
||||||
Site::VALID_EXTENSIONS.include?(File.extname(uploaded_file[:filename]).sub(/^./, '').downcase)
|
Site::VALID_EXTENSIONS.include?(File.extname(uploaded_file[:filename]).sub(/^./, '').downcase)
|
||||||
false
|
|
||||||
|
File.chmod 0640, uploaded_file[:tempfile].path
|
||||||
|
line = Cocaine::CommandLine.new(
|
||||||
|
"clamdscan", "-i --remove=no --no-summary --stdout :path",
|
||||||
|
expected_outcodes: [0, 1]
|
||||||
|
)
|
||||||
|
|
||||||
|
output = line.run path: uploaded_file[:tempfile].path
|
||||||
|
|
||||||
|
return true if output == ''
|
||||||
|
|
||||||
|
threat = output.strip.match(/^.+: (.+) FOUND$/).captures.first
|
||||||
|
|
||||||
|
CLAMAV_THREAT_MATCHES.each do |threat_match|
|
||||||
|
return false if threat.match threat_match
|
||||||
|
end
|
||||||
|
|
||||||
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
def store_file(filename, uploaded)
|
def store_file(filename, uploaded)
|
||||||
|
|
Loading…
Add table
Reference in a new issue