diff --git a/Gemfile b/Gemfile index f250144a..99ab1cbe 100644 --- a/Gemfile +++ b/Gemfile @@ -24,6 +24,7 @@ gem 'sass', require: nil gem 'dav4rack' gem 'filesize' gem 'thread' +gem 'scrypt' platform :mri do gem 'magic' # sudo apt-get install file, For OSX: brew install libmagic diff --git a/Gemfile.lock b/Gemfile.lock index 436ef6bd..f6d17b97 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -54,7 +54,10 @@ GEM i18n (~> 0.5) faraday (0.9.0) multipart-post (>= 1.2, < 3) - ffi (1.9.3) + ffi (1.9.6) + ffi-compiler (0.1.3) + ffi (>= 1.0.0) + rake filesize (0.0.3) google-api-client (0.7.1) addressable (>= 2.3.2) @@ -133,7 +136,7 @@ GEM rack (~> 1.1) unicorn (~> 4.8) raindrops (0.13.0) - rake (10.2.1) + rake (10.3.2) redis (3.0.7) redis-namespace (1.4.1) redis (~> 3.0.4) @@ -146,6 +149,9 @@ GEM sass (3.3.8) screencap (0.1.1) phantomjs + scrypt (2.0.0) + ffi-compiler (>= 0.0.2) + rake sequel (4.8.0) sequel_pg (1.6.9) pg (>= 0.8.0) @@ -242,6 +248,7 @@ DEPENDENCIES ruby-debug sass screencap + scrypt sequel (= 4.8.0) sequel_pg shotgun diff --git a/Rakefile b/Rakefile index fb4371b1..e5042035 100644 --- a/Rakefile +++ b/Rakefile @@ -188,6 +188,15 @@ task :prime_site_updated_at => [:environment] do end end +desc 'hash_ips' +task :hash_ips => [:environment] do + Site.select(:id,:ip).order(:id).all.each do |s| + next if s.ip.nil? || s.ip.match(/#{$config['ip_hash_salt']}/) + s.ip = s.ip + s.save_changes validate: false + end +end + =begin desc 'Update screenshots' task :update_screenshots => [:environment] do diff --git a/app.rb b/app.rb index 49f40b7d..338c0dcd 100644 --- a/app.rb +++ b/app.rb @@ -1216,8 +1216,7 @@ post '/admin/banip' do flash[:error] = 'IP is blank, cannot continue' redirect '/admin' end - - sites = Site.filter(ip: site.ip, is_banned: false).all + sites = Site.filter(ip: Site.hash_ip(site.ip), is_banned: false).all sites.each {|s| s.ban!} flash[:error] = "#{sites.length} sites have been banned." redirect '/admin' @@ -1495,7 +1494,7 @@ post '/site/:username/report' do |username| redirect request.referer if current_site.id == site.id report.reporting_site_id = current_site.id else - report.ip = request.ip + report.ip = Site.hash_ip request.ip end report.save @@ -1533,8 +1532,8 @@ def dashboard_if_signed_in end def require_login_ajax - halt 'You are banned.' if Site.banned_ip?(request.ip) halt 'You are not logged in!' unless signed_in? + halt 'You are banned.' if current_site.is_banned? || parent_site.is_banned? end def csrf_safe? @@ -1546,8 +1545,11 @@ def csrf_token end def require_login - require_unbanned_ip redirect '/' unless signed_in? + if current_site.is_banned || parent_site.is_banned + session[:id] = nil + redirect '/' + end end def signed_in? diff --git a/config.yml.template b/config.yml.template index 1aba4e99..afb13194 100644 --- a/config.yml.template +++ b/config.yml.template @@ -8,6 +8,7 @@ development: sidekiq_pass: ENTER PASS HERE stripe_publishable_key: fillout stripe_api_key: fillout + ip_hash_salt: "400$8$1$fc21863da5d531c1" test: database: 'postgres://neocities@127.0.0.1/neocities_test' database_pool: 1 @@ -18,3 +19,4 @@ test: sidekiq_pass: ENTER PASS HERE stripe_publishable_key: fillout stripe_api_key: fillout + ip_hash_salt: "400$8$1$fc21863da5d531c1" \ No newline at end of file diff --git a/environment.rb b/environment.rb index 4095bccc..edc67d5c 100644 --- a/environment.rb +++ b/environment.rb @@ -26,6 +26,8 @@ else end # :nocov: +raise 'hash_ip_salt is required' unless $config['ip_hash_salt'] + DB = Sequel.connect $config['database'], sslmode: 'disable', max_connections: $config['database_pool'] DB.extension :pagination diff --git a/models/site.rb b/models/site.rb index 21db0433..3c9e1dd9 100644 --- a/models/site.rb +++ b/models/site.rb @@ -202,20 +202,29 @@ class Site < Sequel::Model end def ip_create_limit?(ip) - Site.where('created_at > ?', Date.today.to_time).where(ip: ip).count > IP_CREATE_LIMIT || - Site.where(ip: ip).count > TOTAL_IP_CREATE_LIMIT + hashed_ip = hash_ip ip + Site.where('created_at > ?', Date.today.to_time).where(ip: hashed_ip).count > IP_CREATE_LIMIT || + Site.where(ip: hashed_ip).count > TOTAL_IP_CREATE_LIMIT + end + + def hash_ip(ip) + SCrypt::Engine.hash_secret ip, $config['ip_hash_salt'] + end + + def banned_ip?(ip) + return true if Site.where(is_banned: true). + where(ip: hash_ip(ip)). + where(['updated_at > ?', Time.now-BANNED_TIME]). + first + + return true if BlockedIp[ip] + + false end end - def self.banned_ip?(ip) - return true if Site.where(is_banned: true). - where(ip: ip). - where(['updated_at > ?', Time.now-BANNED_TIME]). - first - - return true if BlockedIp[ip] - - false + def ip=(ip) + super self.class.hash_ip(ip) end def is_following?(site) @@ -296,12 +305,24 @@ class Site < Sequel::Model FileUtils.mkdir_p files_path %w{index not_found}.each do |name| - File.write files_path("#{name}.html"), render_template("#{name}.erb") + tmpfile = Tempfile.new "newinstall-#{name}" + tmpfile.write render_template("#{name}.erb") + tmpfile.close + + store_file "#{name}.html", tmpfile, new_install: true purge_cache "/#{name}.html" ScreenshotWorker.perform_async values[:username], "#{name}.html" end - FileUtils.cp template_file_path('cat.png'), files_path('cat.png') + tmpfile = Tempfile.new 'style.css' + tmpfile.close + FileUtils.cp template_file_path('style.css'), tmpfile.path + store_file 'style.css', tmpfile, new_install: true + + tmpfile = Tempfile.new 'cat.png' + tmpfile.close + FileUtils.cp template_file_path('cat.png'), tmpfile.path + store_file 'cat.png', tmpfile, new_install: true end def get_file(path) @@ -451,7 +472,7 @@ class Site < Sequel::Model PurgeCacheWorker.perform_async payload end - def store_file(path, uploaded) + def store_file(path, uploaded, opts={}) relative_path = scrubbed_path path path = files_path path @@ -486,7 +507,8 @@ class Site < Sequel::Model end pathname = Pathname(path) - if pathname.basename.to_s == 'index.html' + + if pathname.basename.to_s == 'index.html' && opts[:new_install] != true begin new_title = Nokogiri::HTML(File.read(uploaded.path)).css('title').first.text rescue NoMethodError => e @@ -533,7 +555,7 @@ class Site < Sequel::Model ThumbnailWorker.perform_async values[:username], relative_path end - SiteChange.record self, relative_path + SiteChange.record self, relative_path unless opts[:new_install] true end diff --git a/tests/acceptance/signup_tests.rb b/tests/acceptance/signup_tests.rb index f29eddc6..3ab21c5d 100644 --- a/tests/acceptance/signup_tests.rb +++ b/tests/acceptance/signup_tests.rb @@ -38,10 +38,18 @@ describe 'signup' do fill_in_valid click_signup_button site_created?.must_equal true + assert_equal( true, File.exist?(File.join(Site::SITE_FILES_ROOT, @site[:username], 'index.html')) ) + + site = Site[username: @site[:username]] + site.site_files.length.must_equal 4 + site.site_changed.must_equal false + site.site_updated_at.must_equal nil + + site.ip.must_equal Site.hash_ip('127.0.0.1') end it 'fails to create for existing site' do diff --git a/tests/site_file_tests.rb b/tests/site_file_tests.rb index 76e0a2ed..62ed59ca 100644 --- a/tests/site_file_tests.rb +++ b/tests/site_file_tests.rb @@ -72,8 +72,8 @@ describe 'site_files' do upload 'files[]' => Rack::Test::UploadedFile.new('./tests/files/img/test.jpg', 'image/jpeg') last_response.body.must_match /successfully uploaded/i @site.reload.changed_count.must_equal 2 - @site.site_files.count.must_equal 1 - digest.wont_equal @site.reload.site_files.first.sha1_hash + @site.site_files.select {|f| f.path == 'test.jpg'}.length.must_equal 1 + digest.wont_equal @site.site_files_dataset.where(path: 'test.jpg').first.sha1_hash end it 'works with directory path' do diff --git a/views/templates/index.erb b/views/templates/index.erb index 22b9b466..3b57c2d1 100644 --- a/views/templates/index.erb +++ b/views/templates/index.erb @@ -3,18 +3,10 @@
Here's how you can make bold and italic text.
Here's how you can add an image:
-Here's how to make a list:
diff --git a/views/templates/not_found.erb b/views/templates/not_found.erb index dc6a06c8..2ed111e2 100644 --- a/views/templates/not_found.erb +++ b/views/templates/not_found.erb @@ -3,11 +3,7 @@