door_mat 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rspec +2 -0
- data/Gemfile +3 -0
- data/MIT-LICENSE +20 -0
- data/README.md +88 -0
- data/Rakefile +32 -0
- data/app/assets/javascripts/door_mat/application.js +13 -0
- data/app/assets/stylesheets/door_mat/application.css +15 -0
- data/app/assets/stylesheets/scaffold.css +56 -0
- data/app/controllers/door_mat/activities_controller.rb +106 -0
- data/app/controllers/door_mat/application_controller.rb +14 -0
- data/app/controllers/door_mat/change_password_controller.rb +32 -0
- data/app/controllers/door_mat/forgot_passwords_controller.rb +57 -0
- data/app/controllers/door_mat/manage_email_controller.rb +61 -0
- data/app/controllers/door_mat/password_less_session_controller.rb +121 -0
- data/app/controllers/door_mat/reconfirm_password_controller.rb +27 -0
- data/app/controllers/door_mat/sessions_controller.rb +17 -0
- data/app/controllers/door_mat/sign_in_controller.rb +60 -0
- data/app/controllers/door_mat/sign_up_controller.rb +59 -0
- data/app/controllers/door_mat/static_controller.rb +5 -0
- data/app/mailers/door_mat/activity_mailer.rb +18 -0
- data/app/mailers/door_mat/password_less_session_mailer.rb +12 -0
- data/app/models/door_mat/access_token.rb +315 -0
- data/app/models/door_mat/activity.rb +14 -0
- data/app/models/door_mat/activity_confirm_email.rb +45 -0
- data/app/models/door_mat/activity_download_recovery_key.rb +30 -0
- data/app/models/door_mat/activity_reset_password.rb +47 -0
- data/app/models/door_mat/actor.rb +149 -0
- data/app/models/door_mat/change_password.rb +12 -0
- data/app/models/door_mat/email.rb +58 -0
- data/app/models/door_mat/forgot_password.rb +12 -0
- data/app/models/door_mat/membership.rb +42 -0
- data/app/models/door_mat/session.rb +315 -0
- data/app/models/door_mat/sign_in.rb +31 -0
- data/app/models/door_mat/sign_up.rb +17 -0
- data/app/views/door_mat/activity_mailer/confirm_email.html.erb +11 -0
- data/app/views/door_mat/activity_mailer/confirm_email.text.erb +7 -0
- data/app/views/door_mat/activity_mailer/reset_password.html.erb +11 -0
- data/app/views/door_mat/activity_mailer/reset_password.text.erb +7 -0
- data/app/views/door_mat/change_password/new.html.erb +22 -0
- data/app/views/door_mat/forgot_passwords/choose_new_password.html.erb +34 -0
- data/app/views/door_mat/forgot_passwords/new.html.erb +14 -0
- data/app/views/door_mat/helpers/_errors_if_any.html.erb +10 -0
- data/app/views/door_mat/manage_email/new.html.erb +14 -0
- data/app/views/door_mat/password_less_session/access_token.html.erb +16 -0
- data/app/views/door_mat/password_less_session/new.html.erb +34 -0
- data/app/views/door_mat/password_less_session_mailer/send_token.html.erb +11 -0
- data/app/views/door_mat/password_less_session_mailer/send_token.text.erb +7 -0
- data/app/views/door_mat/reconfirm_password/new.html.erb +12 -0
- data/app/views/door_mat/sign_in/new.html.erb +30 -0
- data/app/views/door_mat/sign_up/new.html.erb +24 -0
- data/app/views/door_mat/static/add_email_success.html.erb +5 -0
- data/app/views/door_mat/static/change_password_success.html.erb +2 -0
- data/app/views/door_mat/static/confirm_email_success.html.erb +2 -0
- data/app/views/door_mat/static/email_confirmation_required.html.erb +17 -0
- data/app/views/door_mat/static/forgot_password_verification_mail_sent.html.erb +2 -0
- data/app/views/door_mat/static/reconfirm_password_success.html.erb +4 -0
- data/app/views/door_mat/static/sign_in_success.html.erb +5 -0
- data/app/views/door_mat/static/sign_out_success.html.erb +5 -0
- data/app/views/door_mat/static/sign_up_success.html.erb +4 -0
- data/bin/rails +12 -0
- data/config/locales/en.yml +73 -0
- data/config/routes.rb +48 -0
- data/db/migrate/20140616234935_create_door_mat_actors.rb +23 -0
- data/db/migrate/20140617233357_create_door_mat_sessions.rb +17 -0
- data/db/migrate/20140630043202_create_door_mat_emails.rb +12 -0
- data/db/migrate/20140702045729_create_door_mat_activities.rb +14 -0
- data/db/migrate/20141115183045_create_door_mat_access_tokens.rb +17 -0
- data/db/migrate/20141121191824_create_door_mat_memberships.rb +14 -0
- data/db/migrate/20150910182126_rename_session_guid_column.rb +5 -0
- data/db/migrate/20150918210831_add_access_token_rating_column.rb +5 -0
- data/door_mat.gemspec +37 -0
- data/lib/door_mat.rb +20 -0
- data/lib/door_mat/attr_asymmetric_store.rb +82 -0
- data/lib/door_mat/attr_symmetric_store.rb +82 -0
- data/lib/door_mat/configuration.rb +193 -0
- data/lib/door_mat/controller.rb +117 -0
- data/lib/door_mat/crypto.rb +49 -0
- data/lib/door_mat/crypto/asymmetric_store.rb +77 -0
- data/lib/door_mat/crypto/fast_hash.rb +17 -0
- data/lib/door_mat/crypto/password_hash.rb +39 -0
- data/lib/door_mat/crypto/secure_compare.rb +23 -0
- data/lib/door_mat/crypto/symmetric_store.rb +68 -0
- data/lib/door_mat/engine.rb +23 -0
- data/lib/door_mat/process/actor_password_change.rb +65 -0
- data/lib/door_mat/process/actor_sign_in.rb +38 -0
- data/lib/door_mat/process/actor_sign_up.rb +39 -0
- data/lib/door_mat/process/create_new_anonymous_actor.rb +36 -0
- data/lib/door_mat/process/manage_email.rb +42 -0
- data/lib/door_mat/process/reset_password.rb +50 -0
- data/lib/door_mat/regex.rb +17 -0
- data/lib/door_mat/test_helper.rb +58 -0
- data/lib/door_mat/url_protocol.rb +9 -0
- data/lib/door_mat/version.rb +3 -0
- data/lib/tasks/door_mat_tasks.rake +31 -0
- data/spec/controllers/door_mat/activities_controller_spec.rb +70 -0
- data/spec/controllers/door_mat/forgot_passwords_controller_spec.rb +57 -0
- data/spec/controllers/door_mat/manage_email_spec.rb +181 -0
- data/spec/controllers/door_mat/password_less_session_controller_spec.rb +344 -0
- data/spec/controllers/door_mat/sign_in_controller_spec.rb +211 -0
- data/spec/controllers/door_mat/sign_up_controller_spec.rb +90 -0
- data/spec/factories/door_mat_access_tokens.rb +6 -0
- data/spec/factories/door_mat_activitiess.rb +6 -0
- data/spec/factories/door_mat_actors.rb +23 -0
- data/spec/factories/door_mat_emails.rb +14 -0
- data/spec/factories/door_mat_memberships.rb +6 -0
- data/spec/factories/door_mat_sessions.rb +24 -0
- data/spec/features/password_less_session_spec.rb +165 -0
- data/spec/features/remember_me_spec.rb +672 -0
- data/spec/features/session_spec.rb +336 -0
- data/spec/lib/attr_store_spec.rb +237 -0
- data/spec/lib/crypto_spec.rb +130 -0
- data/spec/lib/process_spec.rb +159 -0
- data/spec/models/door_mat/access_token_spec.rb +134 -0
- data/spec/models/door_mat/activity_spec.rb +38 -0
- data/spec/models/door_mat/actor_spec.rb +56 -0
- data/spec/models/door_mat/email_spec.rb +25 -0
- data/spec/models/door_mat/session_spec.rb +69 -0
- data/spec/spec_helper.rb +223 -0
- data/spec/support/timecop/timecop_helper.rb +52 -0
- data/spec/test_app/README.rdoc +28 -0
- data/spec/test_app/Rakefile +6 -0
- data/spec/test_app/app/assets/javascripts/application.js +13 -0
- data/spec/test_app/app/assets/stylesheets/application.css +15 -0
- data/spec/test_app/app/controllers/account_controller.rb +28 -0
- data/spec/test_app/app/controllers/application_controller.rb +10 -0
- data/spec/test_app/app/controllers/password_less_sample_controller.rb +56 -0
- data/spec/test_app/app/controllers/static_controller.rb +7 -0
- data/spec/test_app/app/helpers/account_helper.rb +2 -0
- data/spec/test_app/app/helpers/application_helper.rb +2 -0
- data/spec/test_app/app/models/game.rb +62 -0
- data/spec/test_app/app/models/shared_data.rb +4 -0
- data/spec/test_app/app/models/shared_key.rb +8 -0
- data/spec/test_app/app/models/user_detail.rb +7 -0
- data/spec/test_app/app/views/account/show.html.erb +133 -0
- data/spec/test_app/app/views/door_mat/static/sign_out_success.html.erb +7 -0
- data/spec/test_app/app/views/layouts/application.html.erb +20 -0
- data/spec/test_app/app/views/password_less_sample/draw_results.html.erb +6 -0
- data/spec/test_app/app/views/password_less_sample/final_result.html.erb +7 -0
- data/spec/test_app/app/views/password_less_sample/play_game.html.erb +5 -0
- data/spec/test_app/app/views/password_less_sample/show_loosing_door.html.erb +10 -0
- data/spec/test_app/app/views/static/index.html.erb +12 -0
- data/spec/test_app/app/views/static/only_confirmed_email_allowed.html.erb +10 -0
- data/spec/test_app/app/views/static/page_that_require_password_reconfirmation.html.erb +16 -0
- data/spec/test_app/app/views/static/session_protected_page.html.erb +32 -0
- data/spec/test_app/bin/bundle +3 -0
- data/spec/test_app/bin/rails +4 -0
- data/spec/test_app/bin/rake +4 -0
- data/spec/test_app/config.ru +4 -0
- data/spec/test_app/config/application.rb +29 -0
- data/spec/test_app/config/boot.rb +5 -0
- data/spec/test_app/config/database.yml +25 -0
- data/spec/test_app/config/environment.rb +19 -0
- data/spec/test_app/config/environments/development.rb +50 -0
- data/spec/test_app/config/environments/production.rb +83 -0
- data/spec/test_app/config/environments/test.rb +48 -0
- data/spec/test_app/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/test_app/config/initializers/cookies_serializer.rb +3 -0
- data/spec/test_app/config/initializers/door_mat.rb +72 -0
- data/spec/test_app/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/test_app/config/initializers/inflections.rb +16 -0
- data/spec/test_app/config/initializers/mime_types.rb +4 -0
- data/spec/test_app/config/initializers/session_store.rb +3 -0
- data/spec/test_app/config/initializers/wrap_parameters.rb +14 -0
- data/spec/test_app/config/locales/en.yml +23 -0
- data/spec/test_app/config/routes.rb +42 -0
- data/spec/test_app/config/secrets.yml +31 -0
- data/spec/test_app/db/migrate/20140717182813_create_user_details.rb +10 -0
- data/spec/test_app/db/migrate/20140908225256_create_shared_data.rb +10 -0
- data/spec/test_app/db/migrate/20140908225604_create_shared_keys.rb +11 -0
- data/spec/test_app/db/migrate/20141121190714_create_games.rb +10 -0
- data/spec/test_app/public/404.html +67 -0
- data/spec/test_app/public/422.html +67 -0
- data/spec/test_app/public/500.html +66 -0
- data/spec/test_app/public/favicon.ico +0 -0
- metadata +552 -0
data/config/routes.rb
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
DoorMat::Engine.routes.draw do
|
|
2
|
+
if DoorMat.configuration.define_door_mat_routes
|
|
3
|
+
|
|
4
|
+
get '/sign_up' => 'sign_up#new', as: 'sign_up'
|
|
5
|
+
post '/sign_up' => 'sign_up#create'
|
|
6
|
+
|
|
7
|
+
get '/sign_in' => 'sign_in#new', as: 'sign_in'
|
|
8
|
+
post '/sign_in' => 'sign_in#create'
|
|
9
|
+
get '/sign_out' => 'sign_in#destroy', as: 'sign_out'
|
|
10
|
+
|
|
11
|
+
post '/terminate_session/:guid' => 'sessions#terminate', as: 'terminate_session'
|
|
12
|
+
get '/reconfirm_password' => 'reconfirm_password#new', as: 'reconfirm_password'
|
|
13
|
+
post '/reconfirm_password' => 'reconfirm_password#create'
|
|
14
|
+
|
|
15
|
+
get '/add_email' => 'manage_email#new', as: 'add_email'
|
|
16
|
+
post '/add_email' => 'manage_email#create'
|
|
17
|
+
post '/delete_email' => 'manage_email#destroy'
|
|
18
|
+
post '/set_primary_email' => 'manage_email#set_primary_email'
|
|
19
|
+
|
|
20
|
+
get '/email_confirmation_required' => 'static#email_confirmation_required', as: 'email_confirmation_required'
|
|
21
|
+
get '/confirm_email/:token/:email' => 'activities#confirm_email', as: 'confirm_email'
|
|
22
|
+
post '/resend_email_confirmation' => 'activities#resend_email_confirmation', as: 'resend_email_confirmation'
|
|
23
|
+
post '/download_recovery_key' => 'activities#download_recovery_key', as: 'download_recovery_key'
|
|
24
|
+
|
|
25
|
+
get '/change_password' => 'change_password#new', as: 'change_password'
|
|
26
|
+
post '/change_password' => 'change_password#create'
|
|
27
|
+
|
|
28
|
+
get '/sign_up_success' => 'static#sign_up_success', as: 'sign_up_success'
|
|
29
|
+
get '/sign_in_success' => 'static#sign_in_success', as: 'sign_in_success'
|
|
30
|
+
get '/add_email_success' => 'static#add_email_success', as: 'add_email_success'
|
|
31
|
+
get '/confirm_email_success' => 'static#confirm_email_success', as: 'confirm_email_success'
|
|
32
|
+
get '/change_password_success' => 'static#change_password_success', as: 'change_password_success'
|
|
33
|
+
get '/reconfirm_password_success' => 'static#reconfirm_password_success', as: 'reconfirm_password_success'
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# skip_before_filter :require_valid_session for these routes
|
|
37
|
+
get '/access_token/:token_for(/:token)' => 'password_less_session#access_token', :as => 'access_token_token_for_token'
|
|
38
|
+
post '/access_token' => 'password_less_session#access_token_post'
|
|
39
|
+
|
|
40
|
+
get '/sign_out_success' => 'static#sign_out_success'
|
|
41
|
+
get '/forgot_password_verification_mail_sent' => 'static#forgot_password_verification_mail_sent'
|
|
42
|
+
|
|
43
|
+
get '/forgot_password' => 'forgot_passwords#new'
|
|
44
|
+
post '/forgot_password' => 'forgot_passwords#create'
|
|
45
|
+
get '/choose_new_password/:token/:email' => 'forgot_passwords#choose_new_password', as: 'choose_new_password'
|
|
46
|
+
post '/reset_password' => 'forgot_passwords#reset_password', as: 'reset_password'
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
class CreateDoorMatActors < ActiveRecord::Migration
|
|
2
|
+
def change
|
|
3
|
+
create_table :door_mat_actors do |t|
|
|
4
|
+
# The salt of the user's password derived key; used for symmetric encryption of data
|
|
5
|
+
t.text :key_salt, :default => '', :null => false
|
|
6
|
+
# The salt of the password
|
|
7
|
+
t.text :password_salt, :default => '', :null => false
|
|
8
|
+
# The resulting hash used for authentication
|
|
9
|
+
t.text :password_hash, :default => '', :null => false
|
|
10
|
+
# A symmetric encryption key used by the system to encrypt data before handing it to the user
|
|
11
|
+
t.text :system_key, :default => '', :null => false
|
|
12
|
+
# The encrypted user key, used to recover data in a password recovery scenario
|
|
13
|
+
t.text :recovery_key, :default => '', :null => false
|
|
14
|
+
|
|
15
|
+
# The key to decrypt the pem pbkey; it is encrypted using the user's password derived key
|
|
16
|
+
t.text :encrypted_pem_key, :default => '', :null => false
|
|
17
|
+
t.text :pem_encrypted_pkey, :default => '', :null => false
|
|
18
|
+
t.text :pem_public_key, :default => '', :null => false
|
|
19
|
+
|
|
20
|
+
t.timestamps :null => false
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
class CreateDoorMatSessions < ActiveRecord::Migration
|
|
2
|
+
def change
|
|
3
|
+
create_table :door_mat_sessions do |t|
|
|
4
|
+
t.belongs_to :actor, index: true
|
|
5
|
+
t.belongs_to :email
|
|
6
|
+
t.string :session_guid, :default => '', :null => false, index: true
|
|
7
|
+
t.text :type, :default => '', :null => false
|
|
8
|
+
t.text :agent, :default => '', :null => false
|
|
9
|
+
t.text :ip, :default => '', :null => false
|
|
10
|
+
t.text :encrypted_symmetric_actor_key, :default => '', :null => false
|
|
11
|
+
t.datetime :password_authenticated_at, :default => Date.new(2014,1,1), :null => false
|
|
12
|
+
t.integer :rating, :default => 0
|
|
13
|
+
|
|
14
|
+
t.timestamps :null => false
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
class CreateDoorMatEmails < ActiveRecord::Migration
|
|
2
|
+
def change
|
|
3
|
+
create_table :door_mat_emails do |t|
|
|
4
|
+
t.belongs_to :actor, index: true
|
|
5
|
+
t.text :address_hash, :default => '', :null => false, index: true
|
|
6
|
+
t.text :address, :default => '', :null => false
|
|
7
|
+
t.integer :status, :default => 0
|
|
8
|
+
|
|
9
|
+
t.timestamps :null => false
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
class CreateDoorMatActivities < ActiveRecord::Migration
|
|
2
|
+
def change
|
|
3
|
+
create_table :door_mat_activities do |t|
|
|
4
|
+
t.belongs_to :actor, index: true
|
|
5
|
+
t.string :type, :default => '', :null => false
|
|
6
|
+
t.integer :notifier_id, :null => false
|
|
7
|
+
t.string :notifier_type, :default => '', :null => false
|
|
8
|
+
t.text :link_hash, :default => '', :null => false
|
|
9
|
+
t.integer :status, :default => 0
|
|
10
|
+
|
|
11
|
+
t.timestamps :null => false
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
class CreateDoorMatAccessTokens < ActiveRecord::Migration
|
|
2
|
+
def change
|
|
3
|
+
create_table :door_mat_access_tokens do |t|
|
|
4
|
+
|
|
5
|
+
t.belongs_to :actor
|
|
6
|
+
t.text :hashed_token, :default => '', :null => false, index: true
|
|
7
|
+
t.text :name, :default => '', :null => false
|
|
8
|
+
t.integer :token_for, :default => 0
|
|
9
|
+
t.integer :status, :default => 0
|
|
10
|
+
t.text :identifier, :default => '', :null => false
|
|
11
|
+
t.text :data, :default => '', :null => false
|
|
12
|
+
t.integer :reference_id, :default => 0, :null => false
|
|
13
|
+
|
|
14
|
+
t.timestamps :null => false
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
class CreateDoorMatMemberships < ActiveRecord::Migration
|
|
2
|
+
def change
|
|
3
|
+
create_table :door_mat_memberships do |t|
|
|
4
|
+
t.belongs_to :member, index: true, class_name: "DoorMat::Actor"
|
|
5
|
+
t.belongs_to :member_of, index: true, class_name: "DoorMat::Actor"
|
|
6
|
+
t.integer :sponsor, :default => 0
|
|
7
|
+
t.integer :owner, :default => 0
|
|
8
|
+
t.integer :permission, :default => 0
|
|
9
|
+
t.text :key, :default => '', :null => false
|
|
10
|
+
|
|
11
|
+
t.timestamps :null => false
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
data/door_mat.gemspec
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
$:.push File.expand_path('../lib', __FILE__)
|
|
2
|
+
|
|
3
|
+
require 'door_mat/version'
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |s|
|
|
6
|
+
s.name = 'door_mat'
|
|
7
|
+
s.version = DoorMat::VERSION
|
|
8
|
+
s.authors = ['Luc Lussier']
|
|
9
|
+
s.email = ['luc.lussier@gmail.com']
|
|
10
|
+
s.homepage = 'https://github.com/datamolecule/door_mat'
|
|
11
|
+
s.summary = 'User authentication and data encryption'
|
|
12
|
+
s.description = 'DoorMat is a Rails Engine that provides a solution for both user authentication and the encryption of user information. It aims to offer safe defaults so you can get going with what your website is really about.'
|
|
13
|
+
s.license = 'MIT'
|
|
14
|
+
|
|
15
|
+
s.files = Dir['{app,bin,config,db,lib}/**/*', 'MIT-LICENSE', 'Rakefile', 'README.md', '.rspec', 'door_mat.gemspec', 'Gemfile']
|
|
16
|
+
s.test_files = Dir['spec/**/*']
|
|
17
|
+
|
|
18
|
+
s.add_dependency 'rails', '~> 4.2'
|
|
19
|
+
s.add_dependency 'bcrypt', '~> 3.1' #https://github.com/codahale/bcrypt-ruby
|
|
20
|
+
s.add_dependency 'request_store', '~> 1.1'
|
|
21
|
+
|
|
22
|
+
s.add_development_dependency 'sprockets', '2.12.4' # to prevent https://github.com/rails/rails/issues/19853
|
|
23
|
+
s.add_development_dependency 'sqlite3'
|
|
24
|
+
s.add_development_dependency 'database_cleaner'
|
|
25
|
+
s.add_development_dependency 'rspec-rails', '~> 3.4.2'
|
|
26
|
+
s.add_development_dependency 'factory_girl_rails', '~> 4.4.1'
|
|
27
|
+
s.add_development_dependency 'email_spec', '~> 2.0'
|
|
28
|
+
s.add_development_dependency 'capybara'
|
|
29
|
+
s.add_development_dependency 'show_me_the_cookies'
|
|
30
|
+
s.add_development_dependency 'poltergeist'
|
|
31
|
+
s.add_development_dependency 'selenium-webdriver'
|
|
32
|
+
s.add_development_dependency 'byebug'
|
|
33
|
+
s.add_development_dependency 'timecop'
|
|
34
|
+
s.add_development_dependency 'better_errors'
|
|
35
|
+
s.add_development_dependency 'binding_of_caller'
|
|
36
|
+
s.add_development_dependency 'simplecov'
|
|
37
|
+
end
|
data/lib/door_mat.rb
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require 'request_store'
|
|
2
|
+
|
|
3
|
+
require 'door_mat/configuration'
|
|
4
|
+
require 'door_mat/engine'
|
|
5
|
+
require 'door_mat/crypto'
|
|
6
|
+
require 'door_mat/attr_symmetric_store'
|
|
7
|
+
require 'door_mat/attr_asymmetric_store'
|
|
8
|
+
require 'door_mat/controller'
|
|
9
|
+
require 'door_mat/url_protocol'
|
|
10
|
+
require 'door_mat/regex'
|
|
11
|
+
|
|
12
|
+
require 'door_mat/process/actor_password_change'
|
|
13
|
+
require 'door_mat/process/actor_sign_in'
|
|
14
|
+
require 'door_mat/process/actor_sign_up'
|
|
15
|
+
require 'door_mat/process/create_new_anonymous_actor'
|
|
16
|
+
require 'door_mat/process/manage_email'
|
|
17
|
+
require 'door_mat/process/reset_password'
|
|
18
|
+
|
|
19
|
+
module DoorMat
|
|
20
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
module DoorMat
|
|
2
|
+
module AttrAsymmetricStore
|
|
3
|
+
class AttrAsymmetricStoreWrapper
|
|
4
|
+
|
|
5
|
+
def initialize(attribute, actor_column)
|
|
6
|
+
@attribute = attribute
|
|
7
|
+
@actor_column = actor_column
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def after_find(record)
|
|
11
|
+
return if DoorMat::Crypto.current_skip_crypto_callback.skip?
|
|
12
|
+
|
|
13
|
+
# leave attribute as-is if blank or the actor is not set
|
|
14
|
+
encrypted_attribute = record.send("#{@attribute}")
|
|
15
|
+
actor = record.send("#{@actor_column}")
|
|
16
|
+
return if encrypted_attribute.blank? || actor.blank?
|
|
17
|
+
|
|
18
|
+
clear_attribute = nil
|
|
19
|
+
|
|
20
|
+
DoorMat::Session.current_session.autoload_sesion_for(actor)
|
|
21
|
+
DoorMat::Session.current_session.with_session_for_actor(actor) do |session|
|
|
22
|
+
clear_attribute = actor.decrypt_shared_key(encrypted_attribute, session)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
if clear_attribute.nil?
|
|
26
|
+
clear_attribute = '[ENCRYPTED SHARED KEY]'
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
record.send("#{@attribute}=", clear_attribute)
|
|
30
|
+
DoorMat.configuration.logger.debug "DEBUG: Decrypt #{@attribute}: #{encrypted_attribute} -> #{clear_attribute}" if Rails.env.development?
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def around_save(record)
|
|
34
|
+
return yield if DoorMat::Crypto.current_skip_crypto_callback.skip?
|
|
35
|
+
|
|
36
|
+
clear_attribute = record.send("#{@attribute}")
|
|
37
|
+
actor = record.send("#{@actor_column}")
|
|
38
|
+
|
|
39
|
+
# leave attribute as-is if blank or the actor is not set
|
|
40
|
+
if clear_attribute.blank? || actor.blank?
|
|
41
|
+
yield
|
|
42
|
+
else
|
|
43
|
+
encrypted_attribute = actor.encrypt_shared_key(clear_attribute)
|
|
44
|
+
|
|
45
|
+
DoorMat.configuration.logger.debug "DEBUG: Encrypt #{@attribute}: #{clear_attribute} -> #{encrypted_attribute}" if Rails.env.development?
|
|
46
|
+
record.send("#{@attribute}=", encrypted_attribute)
|
|
47
|
+
yield
|
|
48
|
+
record.send("#{@attribute}=", clear_attribute)
|
|
49
|
+
DoorMat.configuration.logger.debug "DEBUG: Decrypt #{@attribute}: #{encrypted_attribute} -> #{clear_attribute}" if Rails.env.development?
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def self.included(base)
|
|
56
|
+
base.extend ClassMethods
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
module ClassMethods
|
|
60
|
+
|
|
61
|
+
def attr_asymmetric_store(*args, **options)
|
|
62
|
+
return unless self.table_exists?
|
|
63
|
+
|
|
64
|
+
actor_column = options.fetch(:actor_column, :actor).to_s
|
|
65
|
+
unless self.attribute_names.include? "#{actor_column}_id"
|
|
66
|
+
raise ActiveRecord::ActiveRecordError, "attr_asymmetric_store records must belong to a DoorMat::Actor but could not find the actor column. Pass the actor_column: :actor_column_name option to specify it."
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
args.each do |arg|
|
|
70
|
+
column_type = (self.columns_hash[arg.to_s].cast_type.respond_to?(:type) && self.columns_hash[arg.to_s].cast_type.type) || self.columns_hash[arg.to_s].cast_type.to_s
|
|
71
|
+
if [:text, :string].include? column_type
|
|
72
|
+
after_find DoorMat::AttrAsymmetricStore::AttrAsymmetricStoreWrapper.new(arg.to_s, actor_column)
|
|
73
|
+
around_save DoorMat::AttrAsymmetricStore::AttrAsymmetricStoreWrapper.new(arg.to_s, actor_column)
|
|
74
|
+
else
|
|
75
|
+
raise ActiveRecord::ActiveRecordError, "attr_asymmetric_store only support text and string column types."
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
module DoorMat
|
|
2
|
+
module AttrSymmetricStore
|
|
3
|
+
class AttrSymmetricStoreWrapper
|
|
4
|
+
|
|
5
|
+
def initialize(attribute, actor_column)
|
|
6
|
+
@attribute = attribute
|
|
7
|
+
@actor_column = actor_column
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def after_find(record)
|
|
11
|
+
return if DoorMat::Crypto.current_skip_crypto_callback.skip?
|
|
12
|
+
|
|
13
|
+
encrypted_attribute = record.send("#{@attribute}")
|
|
14
|
+
actor = record.send("#{@actor_column}")
|
|
15
|
+
clear_attribute = nil
|
|
16
|
+
|
|
17
|
+
DoorMat::Session.current_session.autoload_sesion_for(actor)
|
|
18
|
+
DoorMat::Session.current_session.with_session_for_actor(actor) do |session|
|
|
19
|
+
clear_attribute = session.decrypt(encrypted_attribute)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
if clear_attribute.nil?
|
|
23
|
+
clear_attribute = '[ENCRYPTED]'
|
|
24
|
+
record.readonly!
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
record.send("#{@attribute}=", clear_attribute)
|
|
28
|
+
DoorMat.configuration.logger.debug "DEBUG: Decrypt #{@attribute}: #{encrypted_attribute} -> #{clear_attribute}" if Rails.env.development?
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def around_save(record)
|
|
32
|
+
return yield if DoorMat::Crypto.current_skip_crypto_callback.skip?
|
|
33
|
+
|
|
34
|
+
raise ActiveRecord::Rollback, "Record is read-only" if record.readonly?
|
|
35
|
+
|
|
36
|
+
clear_attribute = record.send("#{@attribute}")
|
|
37
|
+
actor = record.send("#{@actor_column}")
|
|
38
|
+
encrypted_attribute = nil
|
|
39
|
+
|
|
40
|
+
DoorMat::Session.current_session.autoload_sesion_for(actor)
|
|
41
|
+
DoorMat::Session.current_session.with_session_for_actor(actor) do |session|
|
|
42
|
+
encrypted_attribute = session.encrypt(clear_attribute)
|
|
43
|
+
end
|
|
44
|
+
raise ActiveRecord::Rollback, "DoorMat::Session is not valid" if encrypted_attribute.nil?
|
|
45
|
+
|
|
46
|
+
DoorMat.configuration.logger.debug "DEBUG: Encrypt #{@attribute}: #{clear_attribute} -> #{encrypted_attribute}" if Rails.env.development?
|
|
47
|
+
record.send("#{@attribute}=", encrypted_attribute)
|
|
48
|
+
yield
|
|
49
|
+
record.send("#{@attribute}=", clear_attribute)
|
|
50
|
+
DoorMat.configuration.logger.debug "DEBUG: Decrypt #{@attribute}: #{encrypted_attribute} -> #{clear_attribute}" if Rails.env.development?
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def self.included(base)
|
|
56
|
+
base.extend ClassMethods
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
module ClassMethods
|
|
60
|
+
|
|
61
|
+
def attr_symmetric_store(*args, **options)
|
|
62
|
+
return unless self.table_exists?
|
|
63
|
+
|
|
64
|
+
actor_column = options.fetch(:actor_column, :actor).to_s
|
|
65
|
+
unless self.attribute_names.include? "#{actor_column}_id"
|
|
66
|
+
raise ActiveRecord::ActiveRecordError, "attr_symmetric_store records must belong to a DoorMat::Actor but could not find the actor column. Pass the actor_column: :actor_column_name option to specify it."
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
args.each do |arg|
|
|
70
|
+
column_type = (self.columns_hash[arg.to_s].cast_type.respond_to?(:type) && self.columns_hash[arg.to_s].cast_type.type) || self.columns_hash[arg.to_s].cast_type.to_s
|
|
71
|
+
if [:text, :string].include? column_type
|
|
72
|
+
after_find DoorMat::AttrSymmetricStore::AttrSymmetricStoreWrapper.new(arg.to_s, actor_column)
|
|
73
|
+
around_save DoorMat::AttrSymmetricStore::AttrSymmetricStoreWrapper.new(arg.to_s, actor_column)
|
|
74
|
+
else
|
|
75
|
+
raise ActiveRecord::ActiveRecordError, "attr_symmetric_store only support text and string column types."
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
module DoorMat
|
|
2
|
+
class Configuration
|
|
3
|
+
|
|
4
|
+
attr_accessor \
|
|
5
|
+
:mailer_from_address,
|
|
6
|
+
:password_reconfirm_delay,
|
|
7
|
+
:public_computer_access_session_timeout,
|
|
8
|
+
:private_computer_access_session_timeout,
|
|
9
|
+
:forgot_password_link_request_delay_minutes,
|
|
10
|
+
:forgot_password_link_expiration_delay_minutes,
|
|
11
|
+
:allow_remember_me_feature,
|
|
12
|
+
:remember_me_require_private_computer_confirmation,
|
|
13
|
+
:remember_me_max_day_count,
|
|
14
|
+
:leak_email_address_at_reconfirm,
|
|
15
|
+
:plausible_deniability_count,
|
|
16
|
+
:max_email_count_per_actor,
|
|
17
|
+
:define_door_mat_routes,
|
|
18
|
+
:allow_redirect_to_requested_url,
|
|
19
|
+
:lockdown_default_redirect_url,
|
|
20
|
+
:sign_up_success_url,
|
|
21
|
+
:sign_in_success_url,
|
|
22
|
+
:add_email_success_url,
|
|
23
|
+
:destroy_email_redirect_url,
|
|
24
|
+
:set_primary_email_redirect_url,
|
|
25
|
+
:resend_email_confirmation_redirect_url,
|
|
26
|
+
:confirm_email_success_url,
|
|
27
|
+
:reconfirm_password_success_url,
|
|
28
|
+
:change_password_success_url,
|
|
29
|
+
:sign_out_success_url,
|
|
30
|
+
:forgot_password_verification_mail_sent_url,
|
|
31
|
+
:allow_sign_up,
|
|
32
|
+
:allow_sign_in_from_sign_up_form,
|
|
33
|
+
:transmit_cookies_only_over_https,
|
|
34
|
+
:crypto_pbkdf2_salt_length,
|
|
35
|
+
:crypto_pbkdf2_password_length,
|
|
36
|
+
:crypto_pbkdf2_iterations,
|
|
37
|
+
:crypto_bcrypt_cost,
|
|
38
|
+
:crypto_secure_compare_default_length,
|
|
39
|
+
:event_hook_before_sign_up,
|
|
40
|
+
:event_hook_after_sign_up,
|
|
41
|
+
:event_hook_after_failed_sign_up,
|
|
42
|
+
:event_hook_before_sign_in,
|
|
43
|
+
:event_hook_after_sign_in,
|
|
44
|
+
:event_hook_after_failed_sign_in,
|
|
45
|
+
:event_hook_before_confirm_email,
|
|
46
|
+
:event_hook_after_confirm_email,
|
|
47
|
+
:event_hook_after_failed_confirm_email,
|
|
48
|
+
:event_hook_before_download_recovery_key,
|
|
49
|
+
:event_hook_after_download_recovery_key,
|
|
50
|
+
:event_hook_after_failed_download_recovery_key,
|
|
51
|
+
:event_hook_before_sign_out,
|
|
52
|
+
:event_hook_after_sign_out,
|
|
53
|
+
:logger,
|
|
54
|
+
:password_less_sessions
|
|
55
|
+
|
|
56
|
+
def initialize
|
|
57
|
+
@mailer_from_address = "noreply@example.com"
|
|
58
|
+
|
|
59
|
+
# Controllers that require_password_reconfirm will only
|
|
60
|
+
# allow the user in without requesting an additional sign-in if the user password
|
|
61
|
+
# was last entered less than password_reconfirm_delay
|
|
62
|
+
# minutes ago.
|
|
63
|
+
# All sections of the site allowing access to or modification
|
|
64
|
+
# of sensitive information or settings should be protected this way.
|
|
65
|
+
# This includes operations resulting in
|
|
66
|
+
# a financial transaction using stored or pre-authorized payment methods.
|
|
67
|
+
@password_reconfirm_delay = 5
|
|
68
|
+
|
|
69
|
+
# A session from a public computer will only last
|
|
70
|
+
# until the browser is closed and will timeout
|
|
71
|
+
# after public_computer_access_session_timeout
|
|
72
|
+
# minutes of inactivity.
|
|
73
|
+
@public_computer_access_session_timeout = 30
|
|
74
|
+
|
|
75
|
+
# A session from a private computer will survive
|
|
76
|
+
# a browser restart but will expire in the
|
|
77
|
+
# browser and timeout on the system
|
|
78
|
+
# after private_computer_access_session_timeout
|
|
79
|
+
# minutes of inactivity.
|
|
80
|
+
@private_computer_access_session_timeout = 60
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
# To prevent email flooding, a new request for a recovery password
|
|
84
|
+
# links will only be sent after the specified delay
|
|
85
|
+
@forgot_password_link_request_delay_minutes = 30
|
|
86
|
+
|
|
87
|
+
# Password recovery links older than this delay become invalid
|
|
88
|
+
@forgot_password_link_expiration_delay_minutes = 30
|
|
89
|
+
|
|
90
|
+
# Does the system allow the remember me feature?
|
|
91
|
+
# High value target systems such as financial sites
|
|
92
|
+
# should not allow the remember me feature.
|
|
93
|
+
# Even when this feature is enabled, sensitive area of the site
|
|
94
|
+
# should require users to re-authenticate using a
|
|
95
|
+
# before_action -> {require_password_reconfirm()}
|
|
96
|
+
# filter
|
|
97
|
+
@allow_remember_me_feature = false
|
|
98
|
+
|
|
99
|
+
# As a safety reminder, the user must confirm that they
|
|
100
|
+
# are not loging in from a public computer before enabling
|
|
101
|
+
# the remember me feature
|
|
102
|
+
@remember_me_require_private_computer_confirmation = true
|
|
103
|
+
|
|
104
|
+
# A session from a private computer for which the
|
|
105
|
+
# cookie will remain for a number of days specified
|
|
106
|
+
# by remember_me_max_day_count and automatically
|
|
107
|
+
# renew the session for that period of time
|
|
108
|
+
@remember_me_max_day_count = 30
|
|
109
|
+
|
|
110
|
+
# Do not pre-populate the email address field
|
|
111
|
+
# in the sign_in form while doing a password reconfirmation
|
|
112
|
+
# as it could be considered to leak the information about which
|
|
113
|
+
# email address was used to login to the system before the reconfirmation request
|
|
114
|
+
@leak_email_address_at_reconfirm = false
|
|
115
|
+
|
|
116
|
+
# How many different accounts a single email address can be associated with on the system
|
|
117
|
+
@plausible_deniability_count = 1
|
|
118
|
+
|
|
119
|
+
# How many different emails can be linked to an actor
|
|
120
|
+
@max_email_count_per_actor = 2
|
|
121
|
+
|
|
122
|
+
# Production systems should eventually redefine their own routes explicitly
|
|
123
|
+
# instead of relying on those provided by the engine
|
|
124
|
+
@define_door_mat_routes = true
|
|
125
|
+
|
|
126
|
+
#
|
|
127
|
+
@allow_redirect_to_requested_url = true
|
|
128
|
+
|
|
129
|
+
# When specifying redirects in
|
|
130
|
+
# config/initializers/door_mat.rb you can use:
|
|
131
|
+
# [ :main_app, :__path__ ] or [:__engine_name_, :__path__] respectively to redirect to an
|
|
132
|
+
# existing path defined in your main application or loaded engine.
|
|
133
|
+
# [:main_app, :root_url] to redirect to the root of your main application.
|
|
134
|
+
# [ :request, :referer ] for an alternative to redirect_to :back.
|
|
135
|
+
@lockdown_default_redirect_url = [ :request, :referer ]
|
|
136
|
+
@sign_up_success_url = [ :sign_up_success_url ]
|
|
137
|
+
@sign_in_success_url = [ :sign_in_success_url ]
|
|
138
|
+
@add_email_success_url = [ :add_email_success_url ]
|
|
139
|
+
@destroy_email_redirect_url = [ :request, :referer ]
|
|
140
|
+
@set_primary_email_redirect_url = [ :request, :referer ]
|
|
141
|
+
@resend_email_confirmation_redirect_url = [ :request, :referer ]
|
|
142
|
+
@confirm_email_success_url = [ :confirm_email_success_url ]
|
|
143
|
+
@reconfirm_password_success_url = [ :reconfirm_password_success_url ]
|
|
144
|
+
@change_password_success_url = [ :change_password_success_url ]
|
|
145
|
+
@sign_out_success_url = [ :sign_out_success_url ]
|
|
146
|
+
@forgot_password_verification_mail_sent_url = [ :forgot_password_verification_mail_sent_url ]
|
|
147
|
+
|
|
148
|
+
@allow_sign_up = true
|
|
149
|
+
@allow_sign_in_from_sign_up_form = false
|
|
150
|
+
|
|
151
|
+
@transmit_cookies_only_over_https = true
|
|
152
|
+
|
|
153
|
+
@crypto_pbkdf2_salt_length = 32
|
|
154
|
+
@crypto_pbkdf2_password_length = 32
|
|
155
|
+
@crypto_pbkdf2_iterations = 10_000
|
|
156
|
+
|
|
157
|
+
@crypto_bcrypt_cost = 12
|
|
158
|
+
|
|
159
|
+
@crypto_secure_compare_default_length = 1024
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
@event_hook_before_sign_up = []
|
|
163
|
+
@event_hook_after_sign_up = []
|
|
164
|
+
@event_hook_after_failed_sign_up = []
|
|
165
|
+
@event_hook_before_sign_in = []
|
|
166
|
+
@event_hook_after_sign_in = []
|
|
167
|
+
@event_hook_after_failed_sign_in = []
|
|
168
|
+
@event_hook_before_confirm_email = []
|
|
169
|
+
@event_hook_after_confirm_email = [] # The confirmed DoorMat::Email is passed as function argument
|
|
170
|
+
@event_hook_after_failed_confirm_email = []
|
|
171
|
+
@event_hook_before_download_recovery_key = []
|
|
172
|
+
@event_hook_after_download_recovery_key = []
|
|
173
|
+
@event_hook_after_failed_download_recovery_key = []
|
|
174
|
+
@event_hook_before_sign_out = []
|
|
175
|
+
@event_hook_after_sign_out = []
|
|
176
|
+
|
|
177
|
+
@logger = Rails.logger
|
|
178
|
+
|
|
179
|
+
# By default, there are no password less sessions defined
|
|
180
|
+
# see test_app/config/initializers/door_mat.rb for sample usage
|
|
181
|
+
@password_less_sessions = {}
|
|
182
|
+
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def self.configuration
|
|
187
|
+
@configuration ||= DoorMat::Configuration.new
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def self.configure
|
|
191
|
+
yield configuration
|
|
192
|
+
end
|
|
193
|
+
end
|