diff --git a/Gemfile b/Gemfile index 2b9b7b6..13c0e1a 100644 --- a/Gemfile +++ b/Gemfile @@ -13,16 +13,18 @@ gem 'dotenv-rails' # DB gem 'mysql2' gem 'dalli' +gem 'connection_pool' # Needed for MT # Web server gem 'faraday' gem 'puma' -gem 'unicorn' +# gem 'unicorn' # Model plugins gem 'unread' gem 'scrypt' -# gem 'impressionist' +gem 'active_flag' +# gem 'impressionist # gem 'ratyrate' # gem "acts_as_rateable", :git => "git://github.com/anton-zaytsev/acts_as_rateable.git" @@ -30,6 +32,13 @@ gem 'scrypt' gem 'google-api-client', '~> 0.10.3' gem 'steam-condenser', github: 'koraktor/steam-condenser-ruby' +# Auth +gem 'omniauth' +gem 'omniauth-steam' +gem 'omniauth-rails_csrf_protection' +# FIXME +# gem 'rails_csrf_protection' + # View and model helper gems gem 'time_difference' gem 'public_suffix' @@ -133,6 +142,7 @@ group :development, :test do gem 'pry-byebug' gem 'spring' gem "rails_best_practices" + gem 'awesome_print' # For n+1 uqeries # gem 'bullet' end diff --git a/Gemfile.lock b/Gemfile.lock index 763ce45..8f23815 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -87,6 +87,8 @@ GEM erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.1, >= 1.2.0) + active_flag (1.5.0) + activerecord (>= 5) active_link_to (1.0.5) actionpack addressable @@ -119,6 +121,7 @@ GEM archive-zip (0.12.0) io-like (~> 0.3.0) ast (2.4.0) + awesome_print (1.8.0) bbcoder (1.1.1) better_errors (2.6.0) coderay (>= 1.0.0) @@ -163,6 +166,7 @@ GEM execjs coffee-script-source (1.12.2) concurrent-ruby (1.1.6) + connection_pool (2.2.2) countries (3.0.1) i18n_data (~> 0.10.0) sixarm_ruby_unaccent (~> 1.1) @@ -228,6 +232,7 @@ GEM haml (5.1.2) temple (>= 0.8.0) tilt + hashie (4.1.0) httpclient (2.8.3) hurley (0.2) i18n (0.9.5) @@ -253,7 +258,6 @@ GEM thor (>= 0.14, < 2.0) json (2.3.0) jwt (2.2.1) - kgio (2.11.3) loofah (2.4.0) crass (~> 1.0.2) nokogiri (>= 1.5.9) @@ -284,6 +288,18 @@ GEM mini_portile2 (~> 2.4.0) nokogumbo (2.0.2) nokogiri (~> 1.8, >= 1.8.4) + omniauth (1.9.1) + hashie (>= 3.4.6) + rack (>= 1.6.2, < 3) + omniauth-openid (1.0.1) + omniauth (~> 1.0) + rack-openid (~> 1.3.1) + omniauth-rails_csrf_protection (0.1.2) + actionpack (>= 4.2) + omniauth (>= 1.3.1) + omniauth-steam (1.0.6) + multi_json + omniauth-openid os (1.0.1) parallel (1.19.1) parser (2.7.0.5) @@ -306,6 +322,9 @@ GEM puma (4.3.3) nio4r (~> 2.0) rack (2.2.2) + rack-openid (1.3.1) + rack (>= 1.1.0) + ruby-openid (>= 2.1.8) rack-test (1.1.0) rack (>= 1.0, < 3) rails (6.0.2.2) @@ -349,7 +368,6 @@ GEM rake (>= 0.8.7) thor (>= 0.20.3, < 2.0) rainbow (3.0.0) - raindrops (0.19.1) rake (13.0.1) rb-fsevent (0.10.3) rb-inotify (0.10.1) @@ -377,6 +395,7 @@ GEM rexml ruby-progressbar (~> 1.7) unicode-display_width (>= 1.4.0, < 1.7) + ruby-openid (2.9.2) ruby-progressbar (1.10.1) ruby-vips (2.0.17) ffi (~> 1.9) @@ -440,9 +459,6 @@ GEM execjs (>= 0.3.0, < 3) unicode-display_width (1.6.1) unicode_utils (1.4.0) - unicorn (5.5.4) - kgio (~> 2.6) - raindrops (~> 0.7) unread (0.11.0) activerecord (>= 3) web-console (4.0.1) @@ -462,9 +478,11 @@ PLATFORMS ruby DEPENDENCIES + active_flag active_link_to active_record_union annotate + awesome_print bbcoder better_errors binding_of_caller @@ -474,6 +492,7 @@ DEPENDENCIES carrierwave codeclimate-test-reporter coffee-rails + connection_pool country_select dalli database_cleaner-active_record @@ -494,6 +513,9 @@ DEPENDENCIES neat (~> 1.6.0) newrelic_rpm nokogiri + omniauth + omniauth-rails_csrf_protection + omniauth-steam phantomjs poltergeist pry-byebug @@ -527,7 +549,6 @@ DEPENDENCIES timecop tinymce-rails uglifier - unicorn unread web-console will_paginate diff --git a/app/assets/stylesheets/themes/default/layout/_header.scss b/app/assets/stylesheets/themes/default/layout/_header.scss index 5634579..07352cf 100644 --- a/app/assets/stylesheets/themes/default/layout/_header.scss +++ b/app/assets/stylesheets/themes/default/layout/_header.scss @@ -2,12 +2,13 @@ Banner */ + header .banner { height: 180px; #authentication { - @include span-columns(5 of 12); - @include shift(7); + @include span-columns(6 of 12); + @include shift(6); padding: 30px 0; padding-top: 50px; color: white; @@ -52,8 +53,14 @@ header .banner { .fields { @include span-columns(12); + img { + padding-top: 4px; + padding-right: 5px; + @include span-columns(2 of 12); + } + input { - @include span-columns(6); + @include span-columns(5 of 12); margin-bottom: 10px; } } @@ -73,10 +80,6 @@ header .banner { } } - .password-reset { - float: right; - } - .links { float: right; position: relative; @@ -116,15 +119,23 @@ header .banner { } .buttons { - @include span-columns(12); + @include span-columns(12 of 12); font-family: $header-font-family; text-align: right; text-transform: uppercase; font-size: 12px; - .login, + .login { + @include span-columns(5 of 12); + @include shift(1.7); + } + .register { - @include span-columns(6); + @include span-columns(5 of 12); + + .password-reset { + float: right; + } } .login input { diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 48a189a..9ecb8c9 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -7,7 +7,9 @@ class ApplicationController < ActionController::Base before_action :update_user before_action :set_controller_and_action_names - protect_from_forgery + # Omniauth has its own CSRF + protect_from_forgery :except => [:callback] + respond_to :html, :js def cuser @@ -24,6 +26,18 @@ class ApplicationController < ActionController::Base redirect_to addr end + def return_back + if session[:return_to] + return_to + elsif request.env["HTTP_REFERER"] + redirect_to request.env["HTTP_REFERER"] + else + redirect_to "/" + end + rescue + redirect_to "/" + end + def redirect_to_back if request.env["HTTP_REFERER"] redirect_to request.env["HTTP_REFERER"] diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index cf89d4c..7b26c3b 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -60,9 +60,6 @@ class UsersController < ApplicationController raise AccessError unless @user.can_create? cuser if @user.valid? and @user.save - @user.profile = Profile.new - @user.profile.user = @user - @user.profile.save! redirect_to action: :show, id: @user.id save_session @user else @@ -88,28 +85,26 @@ class UsersController < ApplicationController redirect_to users_url end + def callback + @user = User.focfah(auth_hash, request.ip) + login_user(@user) + if @user.created_at > (Time.zone.now - 1.week.ago) + render :edit + else + return_back + end + end + # FIXME: maybe move to session controller def login if params[:login] if (u = User.authenticate(params[:login])) - if u.banned? Ban::TYPE_SITE - flash[:notice] = t(:accounts_locked) - else - flash[:notice] = "%s (%s)" % [t(:login_successful), u.password_hash_s] - # FIXME: this doesn't work because model is saved before - flash[:notice] << " \n%s" % I18n.t(:password_md5_scrypt) if u.password_hash_changed? - save_session u - end + login_user(u) else flash[:error] = t(:login_unsuccessful) end end - # FIXME: check return on rails 6 - if session[:return_to] - return_to - else - redirect_to_back - end + return_back end def logout @@ -134,10 +129,25 @@ class UsersController < ApplicationController @user = User.find(params[:id]) end + def login_user(user) + if user.banned? Ban::TYPE_SITE + flash[:error] = t(:accounts_locked) + else + flash[:notice] = "%s (%s)" % [t(:login_successful), user.password_hash_s] + # FIXME: this doesn't work because model is saved before + flash[:notice] << " \n%s" % I18n.t(:password_md5_scrypt) if user.password_hash_changed? + save_session user + end + end + def save_session user session[:user] = user.id user.lastip = request.ip user.lastvisit = Time.now.utc - user.save + user.save! + end + + def auth_hash + request.env['omniauth.auth'] end end diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb index 968046d..9aa7c7b 100644 --- a/app/helpers/users_helper.rb +++ b/app/helpers/users_helper.rb @@ -18,4 +18,9 @@ module UsersHelper # link_to_remote text, options, html_options end + + def steamid_tool + df = DataFile.where("name LIKE '%SteamID Finder%'").first + df ? data_file_url(df) : "/" + end end diff --git a/app/models/user.rb b/app/models/user.rb index d9d8cb4..1733346 100755 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -28,7 +28,9 @@ # require 'digest/md5' +require 'steamid' require "scrypt" +require 'securerandom' class SteamIdValidator < ActiveModel::Validator def validate(record) @@ -50,11 +52,10 @@ class User < ActiveRecord::Base PASSWORD_MD5_SCRYPT = 2 #attr_protected :id, :created_at, :updated_at, :lastvisit, :lastip, :password, :version - attr_accessor :raw_password, :password_updated + attr_accessor :raw_password, :password_updated, :password_force, :fullname attribute :lastvisit, :datetime, default: Time.now.utc attribute :password_hash, :integer, default: PASSWORD_SCRYPT - attr_accessor :password_force belongs_to :team, :optional => true has_one :profile, :dependent => :destroy @@ -142,7 +143,9 @@ class User < ActiveRecord::Base # validates_inclusion_of :password_hash, in: => [User::PASSWORD_SCRYPT, User::PASSWORD_MD5, User::PASSWORD_MD5_SCRYPT] validate :validate_team + before_validation :set_name before_create :init_variables + after_create :create_profile before_save :correct_steamid_universe accepts_nested_attributes_for :profile @@ -168,6 +171,17 @@ class User < ActiveRecord::Base username end + def set_name + return unless fullname + if fullname.include?(" ") + # TODO: check this + self.firstname = fullname.match(/(?:^|(?:\.\s))(\w+)/)[1] + self.surname = fullname.match(/\s(\w+)$/)[1] + else + self.firstname = fullname + end + end + def password_hash_s case self.password_hash when User::PASSWORD_MD5 @@ -327,6 +341,14 @@ class User < ActiveRecord::Base def init_variables self.public_email = false self.time_zone = "Amsterdam" + self.raw_password = SecureRandom.base64(32) unless raw_password and new_record? + self.profile = profile.build unless profile&.present? + end + + def create_profile + if profile + profile.save + end end # NOTE: function does not call save @@ -363,6 +385,18 @@ class User < ActiveRecord::Base true end + def fix_attributes + if errors[:username] + i = 2 + loop do + new_username = "%s%d" % [username, i] + i+=1 + break if User.find_by_username(new_username).count == 0 or i > 50 + end + self.username = new_username + end + end + def can_update? cuser cuser and (self == cuser or cuser.admin?) end @@ -410,8 +444,8 @@ class User < ActiveRecord::Base return nil end - def self.get id - id ? find(id) : "" + def self.get(id) + id ? User.find(id) : "" end def self.historic steamid @@ -442,4 +476,26 @@ class User < ActiveRecord::Base allowed << :username if cuser&.admin? || operation == 'create' params.require(:user).permit(*allowed) end -end + + def self.focfah(auth_hash, lastip) + return nil unless auth_hash&.include?(:provider) + byebug + case auth_hash[:provider] + when 'steam' + return nil unless auth_hash&.include?(:uid) + steamid = SteamID::from_steamID64(auth_hash[:uid]) + user = User.where("LOWER(steamid) = LOWER(?)", steamid).first + unless user + user = User.new(username: auth_hash[:info][:nickname], lastip: lastip, fullname: auth_hash[:info][:name], steamid: steamid) + user.fix_attributes + # TODO: user make valid by force + # user.profile.country + # get profile picture, :image + # This really shouldn't fail. + user.save! + end + return user + end + return nil + end +end \ No newline at end of file diff --git a/app/views/users/new.html.erb b/app/views/users/new.html.erb index 5725834..8aac041 100644 --- a/app/views/users/new.html.erb +++ b/app/views/users/new.html.erb @@ -1,31 +1,49 @@