login-control 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +64 -0
- data/lib/login_control_module.rb +56 -0
- data/lib/login_control_view_helper.rb +45 -0
- metadata +46 -0
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: []
|