login-control 0.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 576dfb778fef6f08e892aee929fb44b15ac51de82b8bca41a6d5b7fa5291cf1e
4
+ data.tar.gz: 15f8547991b86ae2f90b212cfc639ad67e8fd2556acd5851b7fc2b9894d6a337
5
+ SHA512:
6
+ metadata.gz: 5668048e7774db39f276303cc32d9bf6e1538a3300c4118bea7c520eb32ee263203c9afb7b8a60a9ba48a76be4cdcf430029015ddd1ee334d587d1c52dcd7bd1
7
+ data.tar.gz: 480d115794fb3726822b090718eb5dd941aed63db411bb1931290944307cd8db0f6742db01c1ebac8a748d312372e05f474cbb2a29f19c08b0845d41d66b6f33
data/README.md ADDED
@@ -0,0 +1,64 @@
1
+ ## Description
2
+
3
+ The Attempt here is to give more flexibility on multiple signup barriers, like captacha or 2fa. Based on the requests it gives you a decisive criteria of the barriers a user have to take for sign in. It stores a permanent cookie and a table for tracking requests for specific routes you track within a controller method.
4
+
5
+ its built for systems on higher security requirements, for users which have sign-in multiple times on same login.
6
+
7
+ ## Features
8
+
9
+ The `RequestControlViewHelper.captcha_tag?` delivers true if captcha is necessary and showed on a login form.
10
+
11
+ This decision is based on the status of failed login attempts, which is stored in rails-session-cookie.
12
+
13
+ For a user that had never a successfully login, `captcha_tag?` is always true. After first successful login, `captcha_tag?` is true if `attempts` are less than configured (default: 10) and `last_attempt` is older than `config.x.login_control.retry_after_seconds`
14
+
15
+ On localhost captcha is never required.
16
+
17
+ ## Installation
18
+
19
+ `gem 'request-control'
20
+
21
+ run
22
+ ```
23
+ $ bundle
24
+ $ rails g model login_control session_id:string login_name:string scope:string sign_in_success:integer attempts:integer last_attempt:datetime validate_captcha:boolean
25
+ $ rails db:migrate
26
+ ```
27
+
28
+ Login Form
29
+
30
+ `include RequestControlViewHelper`
31
+
32
+ ```
33
+ - if captcha_tag?
34
+ = hcaptcha xxx
35
+ ```
36
+
37
+ Controller example for subclassed devise controller
38
+
39
+ ```
40
+ class SessionsController < Devise::SessionsController
41
+
42
+ include RequestControlModule
43
+
44
+ def create
45
+ notice_request_attempt
46
+ if (captcha_validation? ? verify_hcaptcha(secret_key: ...) : true) && credentials-matched
47
+ super
48
+ notice_successful_request
49
+ else
50
+ redirect_to login_path, alert: 'captcha failed'
51
+ end
52
+ end
53
+ end
54
+ ```
55
+
56
+ ## Configs
57
+
58
+ `config.x.login_control.attempts_allowed` integer, default: 10
59
+
60
+ `config.x.login_control.retry_after_seconds` integer, default: 30 (seconds) # => if, after a failed login, within status `:known`, within `attempts_allowed`, within `retry_after_seconds` `RequestControlViewHelper.captcha_tag?` returns true
61
+
62
+ `config.x.login_control.debug` boolean, default: false only for production
63
+
64
+
@@ -0,0 +1,56 @@
1
+ module LoginControlModule
2
+
3
+ # check if captcha is to validate (does not store a cookie)
4
+ def captcha_validation?(scope: :global, login_name: nil)
5
+ rec = rc_record(scope, login_name)
6
+ rec ? rec.validate_captcha : true
7
+ end
8
+
9
+ # stores cookie, count-up sign_in_success, set attempts count to 1
10
+
11
+ def notice_successful_request(scope: :global, login_name: nil)
12
+ rec = find_or_build_rc_record(scope, login_name)
13
+ rec.sign_in_success = rec.sign_in_success.to_i + 1
14
+ rec.attempts = 1
15
+ rec.save!
16
+ logger.info "REQUEST-CONTROL => #{rec.sign_in_success}. successful request noticed" if debug_request_control
17
+ end
18
+
19
+ # stores cookie, counts up attempts
20
+
21
+ def notice_request_attempt(scope: :global, login_name: nil)
22
+ rec = find_or_build_rc_record(scope, login_name)
23
+ rec.attempts = rec.attempts.to_i + 1
24
+ rec.save!
25
+ logger.info "REQUEST-CONTROL => #{rec.attempts}. failed request noticed" if debug_request_control
26
+ end
27
+
28
+ private
29
+
30
+ # read or store encrypted permanent cookie «login_control»
31
+
32
+ def find_or_build_rc_record(scope, login_name)
33
+ id = cookies.encrypted.permanent[:login_control]
34
+ if id.present?
35
+ rc_record(scope, login_name, id: id)
36
+ else
37
+ id = SecureRandom.hex(20)
38
+ cookies.encrypted.permanent[:login_control] = id
39
+ LoginControl.new(session_id: id, scope: scope, login_name: login_name)
40
+ end
41
+ end
42
+
43
+ # read cookie «login_control»
44
+ def rc_record(scope, login_name, id: cookies.encrypted.permanent[:login_control])
45
+ if id
46
+ LoginControl.find_by(session_id: id, scope: scope, login_name: login_name)
47
+ else
48
+ nil
49
+ end
50
+ end
51
+
52
+ def debug_request_control
53
+ Rails.configuration.x.login_control.debug || !Rails.env.production?
54
+ end
55
+
56
+ end
@@ -0,0 +1,45 @@
1
+ module LoginControlViewHelper
2
+
3
+ # true if captcha tag is showed on a login form
4
+ # the result is saved in rails-session-cookie and later picked up by LoginControlModule.captcha_validation?
5
+
6
+ def captcha_tag?(scope: :global, login_name: nil)
7
+ debug = (Rails.configuration.x.login_control.debug || !Rails.env.production?)
8
+ rc_id = cookies.encrypted.permanent[:login_control]
9
+ if request.host == 'localhost'
10
+ logger.info 'REQUEST-CONTROL => no captcha because of localhost' if debug
11
+ false
12
+ elsif !rc_id.present?
13
+ logger.info 'REQUEST-CONTROL => captcha because no cookie stored yet' if debug
14
+ true
15
+ else
16
+ logger.info 'REQUEST-CONTROL => cookie found ...' if debug
17
+ rec = LoginControl.find_by(session_id: rc_id, scope: scope, login_name: login_name)
18
+ if !rec
19
+ logger.info 'REQUEST-CONTROL => captcha required because no record found(!)' if debug
20
+ true
21
+ else
22
+ logger.info 'REQUEST-CONTROL => record found ...' if debug
23
+ captcha_requested = true
24
+
25
+ attempts_allowed = (Rails.configuration.x.login_control.attempts_allowed || 10)
26
+ retry_after_seconds = (Rails.configuration.x.login_control.retry_after_seconds || 30)
27
+ logger.info "REQUEST-CONTROL => #{rec.attempts.to_i}. attempt (config.x.attempts_allowed: #{attempts_allowed})" if debug
28
+
29
+ if rec.attempts.to_i <= attempts_allowed
30
+ secs = Time.now - rec.updated_at
31
+ captcha_requested = retry_after_seconds.to_f >= secs
32
+ logger.info "REQUEST-CONTROL => captcha #{captcha_requested ? '' : 'NOT '}requested: config.x.retry_after_seconds(#{retry_after_seconds}) >= secs(#{secs})" if debug
33
+ end
34
+
35
+ rec.update!(validate_captcha: captcha_requested)
36
+ captcha_requested
37
+ end
38
+ end
39
+ end
40
+
41
+ # Text for ask a user for storing a cookie
42
+
43
+ REQUEST_CONTROL_COOKIE_TXT = "On first login attempt this service stores a permanent cookie. It tracks login attempts. Only aim is securing and, on the other hand, simplifying access."
44
+
45
+ end
metadata ADDED
@@ -0,0 +1,46 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: login-control
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Christian Sedlmair
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-01-07 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Based on Login Attempts check if captcha is necessary. It stores a permanent
14
+ cookie and uses a table for tracking login requests.
15
+ email: christian@sedlmair.ch
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - README.md
21
+ - lib/login_control_module.rb
22
+ - lib/login_control_view_helper.rb
23
+ homepage: https://rubygems.org/gems/request-control
24
+ licenses:
25
+ - MIT
26
+ metadata: {}
27
+ post_install_message:
28
+ rdoc_options: []
29
+ require_paths:
30
+ - lib
31
+ required_ruby_version: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - ">="
34
+ - !ruby/object:Gem::Version
35
+ version: '0'
36
+ required_rubygems_version: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ requirements: []
42
+ rubygems_version: 3.3.17
43
+ signing_key:
44
+ specification_version: 4
45
+ summary: Lib for simplifying and securing login.
46
+ test_files: []