mirror of
https://github.com/ENSL/ensl.org.git
synced 2024-12-27 04:51:14 +00:00
Add scrypt
This commit is contained in:
parent
b0c9697109
commit
3a4aa11d84
11 changed files with 141 additions and 49 deletions
|
@ -6,7 +6,7 @@ RAILS_ENV=development
|
||||||
APP_SECRET=fe837ea72667ec3d8ecb94cfba1a1bba
|
APP_SECRET=fe837ea72667ec3d8ecb94cfba1a1bba
|
||||||
|
|
||||||
DEPLOY_PATH=/var/www
|
DEPLOY_PATH=/var/www
|
||||||
FILES_PATH=/var/www/files
|
FILES_PATH=/var/www/public/files
|
||||||
|
|
||||||
PUMA_WORKERS=0
|
PUMA_WORKERS=0
|
||||||
PUMA_MIN_THREADS=1
|
PUMA_MIN_THREADS=1
|
||||||
|
|
|
@ -8,6 +8,11 @@ RAILS_ENV=production
|
||||||
# App secret for cookie encryption
|
# App secret for cookie encryption
|
||||||
APP_SECRET=randomstringhere
|
APP_SECRET=randomstringhere
|
||||||
|
|
||||||
|
# Use
|
||||||
|
# SCrypt::Engine.calibrate!(max_mem: 16 * 1024 * 1024)
|
||||||
|
# SCrypt::Engine.generate_salt
|
||||||
|
SCRYPT_SALT_OPTS=
|
||||||
|
|
||||||
# Since this is inside Docker container, it doesn't really matter
|
# Since this is inside Docker container, it doesn't really matter
|
||||||
DEPLOY_PATH=/var/www
|
DEPLOY_PATH=/var/www
|
||||||
|
|
||||||
|
|
1
Gemfile
1
Gemfile
|
@ -21,6 +21,7 @@ gem 'unicorn'
|
||||||
|
|
||||||
# Model plugins
|
# Model plugins
|
||||||
gem 'unread'
|
gem 'unread'
|
||||||
|
gem 'scrypt'
|
||||||
# gem 'impressionist'
|
# gem 'impressionist'
|
||||||
# gem 'ratyrate'
|
# gem 'ratyrate'
|
||||||
# gem "acts_as_rateable", :git => "git://github.com/anton-zaytsev/acts_as_rateable.git"
|
# gem "acts_as_rateable", :git => "git://github.com/anton-zaytsev/acts_as_rateable.git"
|
||||||
|
|
|
@ -200,6 +200,9 @@ GEM
|
||||||
faraday (0.17.3)
|
faraday (0.17.3)
|
||||||
multipart-post (>= 1.2, < 3)
|
multipart-post (>= 1.2, < 3)
|
||||||
ffi (1.12.2)
|
ffi (1.12.2)
|
||||||
|
ffi-compiler (1.0.1)
|
||||||
|
ffi (>= 1.0.0)
|
||||||
|
rake
|
||||||
font-awesome-sass (4.1.0)
|
font-awesome-sass (4.1.0)
|
||||||
sass (~> 3.2)
|
sass (~> 3.2)
|
||||||
geckodriver-helper (0.24.0)
|
geckodriver-helper (0.24.0)
|
||||||
|
@ -393,6 +396,8 @@ GEM
|
||||||
sprockets (>= 2.8, < 4.0)
|
sprockets (>= 2.8, < 4.0)
|
||||||
sprockets-rails (>= 2.0, < 4.0)
|
sprockets-rails (>= 2.0, < 4.0)
|
||||||
tilt (>= 1.1, < 3)
|
tilt (>= 1.1, < 3)
|
||||||
|
scrypt (3.0.7)
|
||||||
|
ffi-compiler (>= 1.0, < 2.0)
|
||||||
selenium-webdriver (3.142.7)
|
selenium-webdriver (3.142.7)
|
||||||
childprocess (>= 0.5, < 4.0)
|
childprocess (>= 0.5, < 4.0)
|
||||||
rubyzip (>= 1.2.2)
|
rubyzip (>= 1.2.2)
|
||||||
|
@ -511,6 +516,7 @@ DEPENDENCIES
|
||||||
rubocop
|
rubocop
|
||||||
sanitize
|
sanitize
|
||||||
sass-rails (~> 5.0.3)
|
sass-rails (~> 5.0.3)
|
||||||
|
scrypt
|
||||||
selenium-webdriver
|
selenium-webdriver
|
||||||
signet (= 0.11.0)
|
signet (= 0.11.0)
|
||||||
simplecov
|
simplecov
|
||||||
|
|
|
@ -90,16 +90,19 @@ class UsersController < ApplicationController
|
||||||
|
|
||||||
# FIXME: maybe move to session controller
|
# FIXME: maybe move to session controller
|
||||||
def login
|
def login
|
||||||
if params[:login] && (u = User.authenticate(params[:login]))
|
if params[:login]
|
||||||
|
if (u = User.authenticate(params[:login]))
|
||||||
if u.banned? Ban::TYPE_SITE
|
if u.banned? Ban::TYPE_SITE
|
||||||
flash[:notice] = t(:accounts_locked)
|
flash[:notice] = t(:accounts_locked)
|
||||||
else
|
else
|
||||||
flash[:notice] = t(:login_successful)
|
flash[:notice] = "%s (%s)" % [t(:login_successful), u.password_hash_s]
|
||||||
|
flash[:notice] << " \n%s" % I18n.t(:password_md5_scrypt) if u.password_hash_changed?
|
||||||
save_session u
|
save_session u
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
flash[:error] = t(:login_unsuccessful)
|
flash[:error] = t(:login_unsuccessful)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
# FIXME: check return on rails 6
|
# FIXME: check return on rails 6
|
||||||
if session[:return_to]
|
if session[:return_to]
|
||||||
return_to
|
return_to
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
# lastname :string(255)
|
# lastname :string(255)
|
||||||
# lastvisit :datetime
|
# lastvisit :datetime
|
||||||
# password :string(255)
|
# password :string(255)
|
||||||
|
# password_hash :integer default(0)
|
||||||
# public_email :boolean default(FALSE), not null
|
# public_email :boolean default(FALSE), not null
|
||||||
# steamid :string(255)
|
# steamid :string(255)
|
||||||
# time_zone :string(255)
|
# time_zone :string(255)
|
||||||
|
@ -27,6 +28,7 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
require 'digest/md5'
|
require 'digest/md5'
|
||||||
|
require "scrypt"
|
||||||
|
|
||||||
class SteamIdValidator < ActiveModel::Validator
|
class SteamIdValidator < ActiveModel::Validator
|
||||||
def validate(record)
|
def validate(record)
|
||||||
|
@ -43,10 +45,15 @@ class User < ActiveRecord::Base
|
||||||
|
|
||||||
VERIFICATION_TIME = 604800
|
VERIFICATION_TIME = 604800
|
||||||
|
|
||||||
|
PASSWORD_SCRYPT = 0
|
||||||
|
PASSWORD_MD5 = 1
|
||||||
|
PASSWORD_MD5_SCRYPT = 2
|
||||||
|
|
||||||
#attr_protected :id, :created_at, :updated_at, :lastvisit, :lastip, :password, :version
|
#attr_protected :id, :created_at, :updated_at, :lastvisit, :lastip, :password, :version
|
||||||
attr_accessor :raw_password
|
attr_accessor :raw_password, :password_updated
|
||||||
|
|
||||||
attribute :lastvisit, :datetime, default: Time.now.utc
|
attribute :lastvisit, :datetime, default: Time.now.utc
|
||||||
|
attribute :password_hash, :integer, default: PASSWORD_SCRYPT
|
||||||
|
|
||||||
belongs_to :team, :optional => true
|
belongs_to :team, :optional => true
|
||||||
has_one :profile, :dependent => :destroy
|
has_one :profile, :dependent => :destroy
|
||||||
|
@ -121,8 +128,8 @@ class User < ActiveRecord::Base
|
||||||
validates_uniqueness_of :username, :email, :steamid
|
validates_uniqueness_of :username, :email, :steamid
|
||||||
validates_length_of :firstname, :in => 1..15, :allow_blank => true
|
validates_length_of :firstname, :in => 1..15, :allow_blank => true
|
||||||
validates_length_of :lastname, :in => 1..25, :allow_blank => true
|
validates_length_of :lastname, :in => 1..25, :allow_blank => true
|
||||||
validates_length_of :username, :in => 2..20
|
validates_length_of :username, :in => 1..30
|
||||||
validates_format_of :username, :with => /\A[A-Za-z0-9_\-\+]{2,20}\Z/
|
validates_format_of :username, :with => /\A[A-Za-z0-9_\-\+]{1,30}\Z/
|
||||||
validates_presence_of :raw_password, :on => :create
|
validates_presence_of :raw_password, :on => :create
|
||||||
validates_length_of :email, :maximum => 50
|
validates_length_of :email, :maximum => 50
|
||||||
validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i
|
validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i
|
||||||
|
@ -131,6 +138,7 @@ class User < ActiveRecord::Base
|
||||||
# validates_format_of :steamid, :with => /\A(STEAM_)?[0-5]:[01]:\d+\Z/
|
# validates_format_of :steamid, :with => /\A(STEAM_)?[0-5]:[01]:\d+\Z/
|
||||||
validates_length_of :time_zone, :maximum => 100, :allow_blank => true, :allow_nil => true
|
validates_length_of :time_zone, :maximum => 100, :allow_blank => true, :allow_nil => true
|
||||||
validates_inclusion_of [:public_email], :in => [true, false], :allow_nil => true
|
validates_inclusion_of [:public_email], :in => [true, false], :allow_nil => true
|
||||||
|
# validates_inclusion_of :password_hash, in: => [User::PASSWORD_SCRYPT, User::PASSWORD_MD5, User::PASSWORD_MD5_SCRYPT]
|
||||||
validate :validate_team
|
validate :validate_team
|
||||||
|
|
||||||
before_create :init_variables
|
before_create :init_variables
|
||||||
|
@ -152,12 +160,25 @@ class User < ActiveRecord::Base
|
||||||
non_versioned_columns << 'birthdate'
|
non_versioned_columns << 'birthdate'
|
||||||
non_versioned_columns << 'time_zone'
|
non_versioned_columns << 'time_zone'
|
||||||
non_versioned_columns << 'public_email'
|
non_versioned_columns << 'public_email'
|
||||||
|
non_versioned_columns << 'password_hash'
|
||||||
non_versioned_columns << 'created_at'
|
non_versioned_columns << 'created_at'
|
||||||
|
|
||||||
def to_s
|
def to_s
|
||||||
username
|
username
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def password_hash_s
|
||||||
|
case self.password_hash
|
||||||
|
when User::PASSWORD_MD5
|
||||||
|
"MD5"
|
||||||
|
when User::PASSWORD_SCRYPT
|
||||||
|
"Scrypt"
|
||||||
|
when User::PASSWORD_MD5_SCRYPT
|
||||||
|
"Scrypt+MD5"
|
||||||
|
else
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def email_s
|
def email_s
|
||||||
email.gsub /@/, " (at) "
|
email.gsub /@/, " (at) "
|
||||||
end
|
end
|
||||||
|
@ -307,9 +328,17 @@ class User < ActiveRecord::Base
|
||||||
self.time_zone = "Amsterdam"
|
self.time_zone = "Amsterdam"
|
||||||
end
|
end
|
||||||
|
|
||||||
# Password should store password and password_hash shoulds store
|
# NOTE: function does not call save
|
||||||
|
# Maybe it should return to not waste save?
|
||||||
def update_password
|
def update_password
|
||||||
self.password = Digest::MD5.hexdigest(raw_password) if raw_password and raw_password.length > 0
|
if raw_password and raw_password.length > 0
|
||||||
|
self.password = SCrypt::Password.create(raw_password)
|
||||||
|
self.password_hash = User::PASSWORD_SCRYPT
|
||||||
|
elsif password_hash == User::PASSWORD_MD5
|
||||||
|
# Scrypt(Md5(passsword))
|
||||||
|
self.password = SCrypt::Password.create(password)
|
||||||
|
self.password_hash = User::PASSWORD_MD5_SCRYPT
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_new_password
|
def send_new_password
|
||||||
|
@ -339,7 +368,31 @@ class User < ActiveRecord::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.authenticate(login)
|
def self.authenticate(login)
|
||||||
where("LOWER(username) = LOWER(?)", login[:username]).where(password: Digest::MD5.hexdigest(login[:password])).first
|
if (user = where("LOWER(username) = LOWER(?)", login[:username]).first)
|
||||||
|
case user.password_hash
|
||||||
|
when User::PASSWORD_SCRYPT
|
||||||
|
pass = SCrypt::Password.new(user.password)
|
||||||
|
return user if pass == login[:password]
|
||||||
|
when User::PASSWORD_MD5_SCRYPT
|
||||||
|
pass = SCrypt::Password.new(user.password)
|
||||||
|
# Match to Scrypt(Md5(password))
|
||||||
|
if pass == Digest::MD5.hexdigest(login[:password])
|
||||||
|
user.raw_password = login[:password]
|
||||||
|
user.update_password
|
||||||
|
user.save!
|
||||||
|
return user
|
||||||
|
end
|
||||||
|
# when User::PASSWORD_MD5
|
||||||
|
else
|
||||||
|
if user.password == Digest::MD5.hexdigest(login[:password])
|
||||||
|
user.raw_password = login[:password]
|
||||||
|
user.update_password
|
||||||
|
user.save!
|
||||||
|
return user
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.get id
|
def self.get id
|
||||||
|
|
|
@ -84,6 +84,7 @@ en:
|
||||||
login_out: "Logged out."
|
login_out: "Logged out."
|
||||||
login_status: "Logged in as"
|
login_status: "Logged in as"
|
||||||
passwords_sent: "Password has been sent."
|
passwords_sent: "Password has been sent."
|
||||||
|
password_md5_scrypt: "Password has been upgraded to higher security level (MD5->SCRYPT)."
|
||||||
incorrect_information: "Incorrect Information."
|
incorrect_information: "Incorrect Information."
|
||||||
weeks_create: "Week was successfully created."
|
weeks_create: "Week was successfully created."
|
||||||
weeks_update: "Week was successfully updated."
|
weeks_update: "Week was successfully updated."
|
||||||
|
|
7
db/migrate/20200401031046_add_password_hash_to_users.rb
Normal file
7
db/migrate/20200401031046_add_password_hash_to_users.rb
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
class AddPasswordHashToUsers < ActiveRecord::Migration[6.0]
|
||||||
|
def change
|
||||||
|
change_table :users do |u|
|
||||||
|
u.integer :password_hash, default: User::PASSWORD_MD5
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
14
db/migrate/20200401031518_update_passwords_to_scrypt.rb
Normal file
14
db/migrate/20200401031518_update_passwords_to_scrypt.rb
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
class UpdatePasswordsToScrypt < ActiveRecord::Migration[6.0]
|
||||||
|
require 'scrypt'
|
||||||
|
require 'user'
|
||||||
|
|
||||||
|
def up
|
||||||
|
SCrypt::Engine.calibrate!(max_time: 0.03)
|
||||||
|
ActiveRecord::Base.transaction do
|
||||||
|
User.all.order(:id).each do |user|
|
||||||
|
user.update_password
|
||||||
|
user.save!
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -10,7 +10,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 2020_03_31_020637) do
|
ActiveRecord::Schema.define(version: 2020_04_01_031046) do
|
||||||
|
|
||||||
create_table "article_versions", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
|
create_table "article_versions", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
|
||||||
t.integer "article_id"
|
t.integer "article_id"
|
||||||
|
@ -805,6 +805,7 @@ ActiveRecord::Schema.define(version: 2020_03_31_020637) do
|
||||||
t.string "time_zone"
|
t.string "time_zone"
|
||||||
t.integer "version"
|
t.integer "version"
|
||||||
t.boolean "public_email", default: false, null: false
|
t.boolean "public_email", default: false, null: false
|
||||||
|
t.integer "password_hash", default: 1
|
||||||
t.index ["lastvisit"], name: "index_users_on_lastvisit"
|
t.index ["lastvisit"], name: "index_users_on_lastvisit"
|
||||||
t.index ["team_id"], name: "index_users_on_team_id"
|
t.index ["team_id"], name: "index_users_on_team_id"
|
||||||
end
|
end
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
# lastname :string(255)
|
# lastname :string(255)
|
||||||
# lastvisit :datetime
|
# lastvisit :datetime
|
||||||
# password :string(255)
|
# password :string(255)
|
||||||
|
# password_hash :integer default(0)
|
||||||
# public_email :boolean default(FALSE), not null
|
# public_email :boolean default(FALSE), not null
|
||||||
# steamid :string(255)
|
# steamid :string(255)
|
||||||
# time_zone :string(255)
|
# time_zone :string(255)
|
||||||
|
|
Loading…
Reference in a new issue