devise-suspicious_login 0.1.1
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/.gitignore +10 -0
- data/Gemfile +2 -0
- data/README.md +111 -0
- data/Rakefile +36 -0
- data/app/views/devise/mailer/suspicious_login_instructions.html.erb +7 -0
- data/bin/test +7 -0
- data/config/locales/en.yml +10 -0
- data/devise-suspicious_login.gemspec +26 -0
- data/lib/generators/active_record/suspicious_login_generator.rb +97 -0
- data/lib/generators/active_record/templates/migration.rb +11 -0
- data/lib/generators/active_record/templates/migration_existing.rb +13 -0
- data/lib/generators/suspicious_login/install_generator.rb +23 -0
- data/lib/generators/suspicious_login/orm_helpers.rb +56 -0
- data/lib/generators/templates/suspicious_login.rb +26 -0
- data/lib/suspicious_login.rb +38 -0
- data/lib/suspicious_login/controllers/helpers.rb +6 -0
- data/lib/suspicious_login/hooks/suspicious_login.rb +8 -0
- data/lib/suspicious_login/mailer.rb +11 -0
- data/lib/suspicious_login/model.rb +79 -0
- data/lib/suspicious_login/patches.rb +12 -0
- data/lib/suspicious_login/rails.rb +9 -0
- data/lib/suspicious_login/schema.rb +19 -0
- data/lib/suspicious_login/strategies/token.rb +54 -0
- data/lib/suspicious_login/version.rb +3 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/controllers/application_controller.rb +3 -0
- data/test/dummy/app/controllers/home_controller.rb +5 -0
- data/test/dummy/app/mailers/application_mailer.rb +4 -0
- data/test/dummy/app/models/application_record.rb +3 -0
- data/test/dummy/app/models/user.rb +9 -0
- data/test/dummy/app/views/home/index.html +0 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/bin/setup +38 -0
- data/test/dummy/bin/update +29 -0
- data/test/dummy/bin/yarn +11 -0
- data/test/dummy/config.ru +5 -0
- data/test/dummy/config/application.rb +17 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/database.yml +21 -0
- data/test/dummy/config/environment.rb +2 -0
- data/test/dummy/config/environments/test.rb +19 -0
- data/test/dummy/config/initializers/devise.rb +13 -0
- data/test/dummy/config/locales/devise.en.yml +12 -0
- data/test/dummy/config/routes.rb +5 -0
- data/test/dummy/config/secrets.yml +5 -0
- data/test/dummy/config/spring.rb +6 -0
- data/test/dummy/db/migrate/20180910092425_create_tables.rb +16 -0
- data/test/dummy/db/migrate/20180910094718_add_login_token_columns.rb +8 -0
- data/test/dummy/db/migrate/20180910104707_add_trackable_columns.rb +11 -0
- data/test/dummy/db/migrate/20180919081730_add_recoverable_columns.rb +8 -0
- data/test/dummy/db/schema.rb +38 -0
- data/test/dummy/log/.keep +0 -0
- data/test/factories.rb +47 -0
- data/test/generators/active_record_generator_test.rb +40 -0
- data/test/generators/install_generator_test.rb +15 -0
- data/test/support/helpers.rb +16 -0
- data/test/suspicious_acceptance_test.rb +269 -0
- data/test/suspicious_login_test.rb +38 -0
- data/test/test_helper.rb +37 -0
- metadata +245 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 0222b12b1368c6bd070e59a5e8f5a85711cc16f9fe9f2565a9ae8f10c7172055
|
|
4
|
+
data.tar.gz: b216d35f79d6d79f85cd01cfeba1ae2e13ddb61e6b35acf3edc8b826d9f7036d
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 4fbaf798720e48198aade72a7a21be195bdec0776e878d0424fb1ff342f3986d4fe6492e537cbdeffa0bbbcbdae49661660bfaa7ef92c09388d6de09448da16d
|
|
7
|
+
data.tar.gz: 6f3ff5333a4ca4dfc6f2b85747bdb6345a1659445078c6e2aa8ce60a7d98c9f3d84155cfef1b023becedf4f5023f8988450850cc02c8519f253df334e3171eb4
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# devise-suspicious_login
|
|
2
|
+
|
|
3
|
+
A devise extension that helps protect again suspicious logins.
|
|
4
|
+
|
|
5
|
+
## Getting started
|
|
6
|
+
|
|
7
|
+
```ruby
|
|
8
|
+
gem 'devise-suspicious_login
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Run `bundle` command to install.
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Quick Installation
|
|
15
|
+
|
|
16
|
+
Quick Installation should work on most default rails apps.
|
|
17
|
+
|
|
18
|
+
Run the install generator:
|
|
19
|
+
|
|
20
|
+
`rails generate suspicious_login:install`
|
|
21
|
+
|
|
22
|
+
to install the relevant config files `config/initializers/suspicious_login.rb` with default settings.
|
|
23
|
+
|
|
24
|
+
Next run the ActiveRecord generator for each model you want to enable suspicious_login detection for.
|
|
25
|
+
|
|
26
|
+
`rails generate active_record:suspicious_login User`
|
|
27
|
+
|
|
28
|
+
will update and configure the User model automatically. This will also automatically create a database migration that adds the necessary fields to the User model.
|
|
29
|
+
|
|
30
|
+
Run this migration wih
|
|
31
|
+
|
|
32
|
+
`rails db:migrate`
|
|
33
|
+
|
|
34
|
+
By default only dormant users (3 months without a login by default setting) are considered suspicious. Suspicious check for dormant users can be turned of by setting:
|
|
35
|
+
|
|
36
|
+
```ruby
|
|
37
|
+
config.dormant_sign_in after = nil
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
To add a custom suspicious check for a model simply define a method `suspicious_login_attempt?(request)` eg:
|
|
41
|
+
|
|
42
|
+
```ruby
|
|
43
|
+
# request parameter contains the contents of the rails request
|
|
44
|
+
def suspicious_login_attempt?(request)
|
|
45
|
+
if request.ip.botnet? return true
|
|
46
|
+
false
|
|
47
|
+
end
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
### Manual Installation
|
|
52
|
+
|
|
53
|
+
Once installed you need to add `login_token` and `login_token_sent_at` fields to any resources (eg User) that will use need this feature. Below shows how to add this to the `User` model.
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
```ruby
|
|
57
|
+
# For a new migration for the users table, define a migration as follows:
|
|
58
|
+
create_table :users do |t|
|
|
59
|
+
t.login_token
|
|
60
|
+
end
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
```ruby
|
|
64
|
+
# If the table already exists, define a migration and add the following:
|
|
65
|
+
change_table :users do |t|
|
|
66
|
+
t.string login_token
|
|
67
|
+
t.datetime :login_token_sent_at
|
|
68
|
+
end
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Add the `:suspicious_login` module to the resource.
|
|
72
|
+
This extension requires the resource to have the native devise modules `:trackable` and `:recoverable` attached to it eg:
|
|
73
|
+
|
|
74
|
+
```ruby
|
|
75
|
+
class User < ApplicationRecord
|
|
76
|
+
devise :database_authenticatable, :recoverable, :registerable, :authenticatable, :trackable, :suspicious_login
|
|
77
|
+
end
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Configuration
|
|
81
|
+
|
|
82
|
+
```ruby
|
|
83
|
+
Devise.setup do |config|
|
|
84
|
+
# Period of time to expire token after login_tokens
|
|
85
|
+
# config.expire_login_token_after = 10.minutes
|
|
86
|
+
|
|
87
|
+
# Period of time to wait before resending another email for a suspicious login
|
|
88
|
+
# config.resend_login_token_after = 1.minute
|
|
89
|
+
|
|
90
|
+
# Period of time after which a user is considered to be dormant and a login treated as suspicious
|
|
91
|
+
# dormant_sign_in_after = 3.months
|
|
92
|
+
|
|
93
|
+
# Column to store login token for resource
|
|
94
|
+
# config.token_field_name = :login_token
|
|
95
|
+
|
|
96
|
+
# Column to store login token create time for resource
|
|
97
|
+
# config.token_created_at_field_name = :login_token_sent_at
|
|
98
|
+
|
|
99
|
+
# Clear token on login (allows tokens to be one time use only)
|
|
100
|
+
# config.clear_token_on_login = true
|
|
101
|
+
end
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Be sure to set all of your devise login failure messages to be the same otherwise an attack will know if the login credentials are correct depending on the failure message returned!
|
|
105
|
+
|
|
106
|
+
See (test/dummy/config/locales/devise.en.yml)
|
|
107
|
+
|
|
108
|
+
## Requirements
|
|
109
|
+
|
|
110
|
+
* Devise (https://github.com/plataformatec/devise)
|
|
111
|
+
* Rails 5.1 onwards (http://github.com/rails/rails)
|
data/Rakefile
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
begin
|
|
4
|
+
require "bundler/setup"
|
|
5
|
+
require "bundler/gem_tasks"
|
|
6
|
+
rescue LoadError
|
|
7
|
+
puts "You must `gem install bundler` and `bundle install` to run rake tasks"
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
require "rdoc/task"
|
|
11
|
+
|
|
12
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
|
13
|
+
rdoc.rdoc_dir = "rdoc"
|
|
14
|
+
rdoc.title = "Devise::SuspiciousLogin"
|
|
15
|
+
rdoc.options << "--line-numbers"
|
|
16
|
+
rdoc.rdoc_files.include("README.md")
|
|
17
|
+
rdoc.rdoc_files.include("lib/**/*.rb")
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
require "bundler/gem_tasks"
|
|
26
|
+
|
|
27
|
+
require "rake/testtask"
|
|
28
|
+
|
|
29
|
+
Rake::TestTask.new(:test) do |t|
|
|
30
|
+
t.libs << "test"
|
|
31
|
+
t.pattern = "test/**/*_test.rb"
|
|
32
|
+
t.verbose = false
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
task default: :test
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<h2><%= "Hi #{@resource.email}" %></h2>
|
|
2
|
+
<p>We noticed a new login to your account</p>
|
|
3
|
+
<h4>If this was you:</h4>
|
|
4
|
+
<p>Click the login link below to config and log in</p>
|
|
5
|
+
<p><%= link_to("Log in", root_url(login_token: @token, email: @resource.email)) %></p>
|
|
6
|
+
<h4>If this wasn't you:</h4>
|
|
7
|
+
<p>Your account may have been compromised and you should <%= link_to("reset your password now.", edit_user_password_url(@resource, reset_password_token: @reset_password_token)) %></p>
|
data/bin/test
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
en:
|
|
2
|
+
devise:
|
|
3
|
+
installer:
|
|
4
|
+
missing_modules:
|
|
5
|
+
one: "The following devise module is missing from your model and has been automatically added -> :%{missing_modules}.\n\n"
|
|
6
|
+
other: "The following devise modules are missing from your model and have been automatically added -> :%{missing_modules}.\n\n"
|
|
7
|
+
missing_model: "Model %{name} does not exist."
|
|
8
|
+
devise_missing: "Devise not found on %{name}"
|
|
9
|
+
failure:
|
|
10
|
+
suspicious_login: "Your email or password are invalid, OR we need to verify your sign in. If you have received an email from us, please follow the instructions to complete your sign in."
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
$LOAD_PATH.push File.expand_path('../lib', __FILE__)
|
|
2
|
+
|
|
3
|
+
# Maintain your gem's version:
|
|
4
|
+
require "suspicious_login/version"
|
|
5
|
+
|
|
6
|
+
# Describe your gem and declare its dependencies:
|
|
7
|
+
Gem::Specification.new do |s|
|
|
8
|
+
s.name = "devise-suspicious_login"
|
|
9
|
+
s.version = SuspiciousLogin::VERSION.dup
|
|
10
|
+
s.platform = Gem::Platform::RUBY
|
|
11
|
+
s.authors = ["ceres629"]
|
|
12
|
+
s.email = ["ceres629@gmail.com"]
|
|
13
|
+
s.summary = "Devise extension that check for suspicious logins"
|
|
14
|
+
s.summary = "Devise extension that check for suspicious logins"
|
|
15
|
+
s.files = `git ls-files`.split("\n")
|
|
16
|
+
s.test_files = `git ls-files -- test/*`.split("\n")
|
|
17
|
+
s.require_paths = ['lib']
|
|
18
|
+
|
|
19
|
+
s.add_runtime_dependency "devise", ">= 4"
|
|
20
|
+
s.add_development_dependency "colorize"
|
|
21
|
+
s.add_development_dependency 'rails', '>= 5.0', '< 6.0'
|
|
22
|
+
s.add_development_dependency 'minitest'
|
|
23
|
+
s.add_development_dependency "rake"
|
|
24
|
+
s.add_development_dependency "sqlite3"
|
|
25
|
+
s.add_development_dependency "factory_bot_rails"
|
|
26
|
+
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
require 'generators/active_record/devise_generator'
|
|
2
|
+
require 'generators/suspicious_login/orm_helpers'
|
|
3
|
+
|
|
4
|
+
module ActiveRecord
|
|
5
|
+
module Generators
|
|
6
|
+
class SuspiciousLoginGenerator < ActiveRecord::Generators::Base
|
|
7
|
+
argument :attributes, type: :array, default: [], banner: "field:type field:type"
|
|
8
|
+
include SuspiciousLogin::Generators::OrmHelpers
|
|
9
|
+
source_root File.expand_path("../templates", __FILE__)
|
|
10
|
+
|
|
11
|
+
@required_devise_modules = [:trackable, :recoverable]
|
|
12
|
+
|
|
13
|
+
def generate_model
|
|
14
|
+
class_path = namespaced? ? class_name.to_s.split("::") : [class_name]
|
|
15
|
+
|
|
16
|
+
if behavior == :invoke && !model_exists?
|
|
17
|
+
if Rails.env.test?
|
|
18
|
+
invoke "active_record:model", [name], migration: false
|
|
19
|
+
else
|
|
20
|
+
raise(SuspiciousLogin::MissingModelError, I18n.t('devise.installer.missing_model', name: class_path.last))
|
|
21
|
+
end
|
|
22
|
+
elsif behavior == :revoke
|
|
23
|
+
return
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def copy_devise_migration
|
|
28
|
+
if (behavior == :invoke && model_exists?) || (behavior == :revoke && migration_exists?(table_name))
|
|
29
|
+
migration_template "migration_existing.rb", "#{migration_path}/add_devise_suspicious_login_to_#{table_name}.rb", migration_version: migration_version
|
|
30
|
+
else
|
|
31
|
+
migration_template "migration.rb", "#{migration_path}/devise_create_#{table_name}.rb", migration_version: migration_version
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def add_warden_strategy
|
|
36
|
+
template('../../templates/suspicious_login.rb', 'config/initializers/suspicious_login.rb') unless File.exist?(File.join(destination_root, 'config/initializers/suspicious_login.rb'))
|
|
37
|
+
|
|
38
|
+
content = File.read(File.join(destination_root, 'config/initializers/suspicious_login.rb'))
|
|
39
|
+
|
|
40
|
+
if content.include?("config.warden do |manager|\n")
|
|
41
|
+
inject_into_file 'config/initializers/suspicious_login.rb', :after => "config.warden do |manager|\n" do
|
|
42
|
+
" manager.default_strategies(:scope => :#{name.downcase.to_sym}).unshift :suspicious_login_token\n"
|
|
43
|
+
end
|
|
44
|
+
else
|
|
45
|
+
inject_into_file 'config/initializers/suspicious_login.rb', :after => "Devise.setup do |config|" do
|
|
46
|
+
""" config.warden do |manager|
|
|
47
|
+
manager.default_strategies(:scope => :#{name.downcase.to_sym}).unshift :suspicious_login_token
|
|
48
|
+
end
|
|
49
|
+
"""
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def migration_data
|
|
55
|
+
<<RUBY
|
|
56
|
+
t.string #{Devise.token_field_name}
|
|
57
|
+
t.datetime #{Devise.token_created_at_field_name}
|
|
58
|
+
RUBY
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def inject_devise_content
|
|
62
|
+
devise_modules_re = /devise((\s*)(:\S*))+/
|
|
63
|
+
suspicious_login_re = /devise(?:(?:\s*)(?::\S*))+(,\s*:suspicious_login)/
|
|
64
|
+
content = File.read(File.join(destination_root, model_path))
|
|
65
|
+
|
|
66
|
+
if model_exists?
|
|
67
|
+
class_path = namespaced? ? class_name.to_s.split("::") : [class_name]
|
|
68
|
+
|
|
69
|
+
if behavior == :invoke
|
|
70
|
+
devise_content = devise_modules_re.match(content)&.[](0)
|
|
71
|
+
devise_missing_modules = missing_modules(devise_content)
|
|
72
|
+
if devise_content && devise_missing_modules
|
|
73
|
+
updated_devise_content = devise_missing_modules.reduce(devise_content) { |acc, mod| "#{acc}, :#{mod.to_s}" }
|
|
74
|
+
puts I18n.t('devise.installer.missing_modules', missing_modules: devise_missing_modules.join(', '), count: devise_missing_modules.length) if devise_missing_modules.any? && gsub_file(model_path, devise_modules_re, updated_devise_content) > 0
|
|
75
|
+
puts "\n"
|
|
76
|
+
else
|
|
77
|
+
raise(SuspiciousLogin::DeviseMissingFromModel, I18n.t('devise.installer.devise_missing', name: class_path.last)) if !Rails.env.test?
|
|
78
|
+
end
|
|
79
|
+
elsif behavior == :revoke
|
|
80
|
+
chop_content = suspicious_login_re.match(content)&.[](1)
|
|
81
|
+
force_gsub_file(model_path, chop_content, "") if chop_content
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def rails5?
|
|
87
|
+
Rails.version.start_with? '5'
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def migration_version
|
|
91
|
+
if rails5?
|
|
92
|
+
"[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
class DeviseCreate<%= table_name.camelize %> < ActiveRecord::Migration<%= migration_version %>
|
|
2
|
+
def change
|
|
3
|
+
create_table :<%= table_name %><%= primary_key_type %> do |t|
|
|
4
|
+
<%= migration_data -%>
|
|
5
|
+
|
|
6
|
+
<% attributes.each do |attribute| -%>
|
|
7
|
+
t.<%= attribute.type %> :<%= attribute.name %>
|
|
8
|
+
<% end -%>
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
class AddDeviseSuspiciousLoginTo<%= table_name.camelize %> < ActiveRecord::Migration<%= migration_version %>
|
|
2
|
+
def self.up
|
|
3
|
+
change_table :<%= table_name %> do |t|
|
|
4
|
+
<%= migration_data -%>
|
|
5
|
+
end
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def self.down
|
|
9
|
+
# By default, we don't want to make any assumption about how to roll back a migration when your
|
|
10
|
+
# model already existed. Please edit below which fields you would like to remove in this migration.
|
|
11
|
+
raise ActiveRecord::IrreversibleMigration
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module SuspiciousLogin
|
|
2
|
+
module Generators
|
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
|
4
|
+
|
|
5
|
+
source_root File.expand_path("../../templates", __FILE__)
|
|
6
|
+
desc "Add SuspiciousLogin config variables and files to rails project"
|
|
7
|
+
def create_initializer
|
|
8
|
+
template('suspicious_login.rb', 'config/initializers/suspicious_login.rb')
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def copy_locale
|
|
12
|
+
copy_file "../../../config/locales/en.yml", "config/locales/suspicious_login.en.yml"
|
|
13
|
+
puts "\n*** IMPORTANT: Be sure to set all devise authentication failure messages to be the same as 'devise.failure.suspicious_login' ***".red
|
|
14
|
+
puts "See https://github.com/ceres629/devise-suspicious_login/blob/master/test/dummy/config/locales/devise.en.yml for an example devise.en.yml.".yellow
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def prepend_application_file
|
|
18
|
+
create_file "config/application.rb", "module Rails\n class Application < Rails::Application\n end\nend" if Rails.env.test?
|
|
19
|
+
application "require 'suspicious_login'"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
module SuspiciousLogin
|
|
2
|
+
module Generators
|
|
3
|
+
module OrmHelpers
|
|
4
|
+
def force_gsub_file(path, flag, *args, &block)
|
|
5
|
+
config = args.last.is_a?(Hash) ? args.pop : {}
|
|
6
|
+
|
|
7
|
+
path = File.expand_path(path, destination_root)
|
|
8
|
+
say_status :gsub, relative_to_original_destination_root(path), config.fetch(:verbose, true)
|
|
9
|
+
|
|
10
|
+
unless options[:pretend]
|
|
11
|
+
content = File.binread(path)
|
|
12
|
+
content.gsub!(flag, *args, &block)
|
|
13
|
+
File.open(path, "wb") { |file| file.write(content) }
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def required_devise_modules
|
|
18
|
+
[:trackable, :recoverable, :suspicious_login]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def missing_modules(devise_content)
|
|
22
|
+
missing_modules = []
|
|
23
|
+
required_devise_modules.each { |mod| missing_modules << mod unless devise_content&.include?(mod.to_s)}
|
|
24
|
+
missing_modules
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def devise_module_exists?(devise_content, module_name)
|
|
28
|
+
devise_content.include?(module_name)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def append_devise_module(devise_content, module_name)
|
|
32
|
+
(devise_content.blank? || devise_content.include?(module_name.to_s)) ? devise_content : devise_content + ", :#{module_name.to_s}"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def model_exists?
|
|
36
|
+
File.exist?(File.join(destination_root, model_path))
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def migration_exists?(table_name)
|
|
40
|
+
Dir.glob("#{File.join(destination_root, migration_path)}/[0-9]*_*.rb").grep(/\d+_add_devise_suspicious_login_to_#{table_name}.rb$/).first
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def migration_path
|
|
44
|
+
if Rails.version >= '5.0.3'
|
|
45
|
+
db_migrate_path
|
|
46
|
+
else
|
|
47
|
+
@migration_path ||= File.join("db", "migrate")
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def model_path
|
|
52
|
+
@model_path ||= File.join("app", "models", "#{file_path}.rb")
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
Devise.setup do |config|
|
|
2
|
+
# ==> SuspiciousLogin Extension
|
|
3
|
+
|
|
4
|
+
# Configure suspicious extension for devise
|
|
5
|
+
|
|
6
|
+
# Period of time after which tokens expire
|
|
7
|
+
# config.expire_login_token_after = 10.minutes
|
|
8
|
+
|
|
9
|
+
# Minimum period of time before another token can be resent
|
|
10
|
+
# config.resend_login_token_after = 1.minute
|
|
11
|
+
|
|
12
|
+
# Period of time after which a user is considered to be dormant
|
|
13
|
+
# config.dormant_sign_in_after = 3.months
|
|
14
|
+
|
|
15
|
+
# Resource field that will be used to store the login_token
|
|
16
|
+
# config.token_field_name = :login_token
|
|
17
|
+
|
|
18
|
+
# Resource field that will be used to store the token_created_at time
|
|
19
|
+
# config.token_created_at_field_name = :login_token_sent_at
|
|
20
|
+
|
|
21
|
+
# Clear login_token after user login (true means each token can only be used once)
|
|
22
|
+
# config.clear_token_on_login = true
|
|
23
|
+
|
|
24
|
+
config.warden do |manager|
|
|
25
|
+
end
|
|
26
|
+
end
|