devise-pwned_password 0.1.3 → 0.1.4
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
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9034d6a6d49339f92023d27ef40b8633a2332ded
|
4
|
+
data.tar.gz: 1e429adc52ffb2aff28985d9a1636aec657b686a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 75aede6ba1404dc2065db2d404467071d1d00397da09ad141f760edb8d74617e750d8707e287ab2ebf088bb85cc1038acb36c7b6099c5dc73bc8372ebb66b067
|
7
|
+
data.tar.gz: 0ca55ec7326ed19bde60f5bc4d5cc55ffaf09b68a65a7162372078641668f743134b1267940e5ecfe5a5263cbb3b39078f93a3a0b9fa912b4fee6dca8bceb4fc
|
data/README.md
CHANGED
@@ -33,6 +33,22 @@ en:
|
|
33
33
|
pwned_password: "has previously appeared in a data breach and should never be used. If you've ever used it anywhere before, change it immediately!"
|
34
34
|
```
|
35
35
|
|
36
|
+
You can optionally warn existing users when they sign in if they are using a password from the PwnedPasswords dataset. The default message is:
|
37
|
+
|
38
|
+
```
|
39
|
+
Your password has previously appeared in a data breach and should never be used. We strongly recommend you change your password.
|
40
|
+
```
|
41
|
+
|
42
|
+
You can customize this message by modifying the `devise` YAML file.
|
43
|
+
|
44
|
+
```yml
|
45
|
+
# config/locales/devise.en.yml
|
46
|
+
en:
|
47
|
+
devise:
|
48
|
+
sessions:
|
49
|
+
warn_pwned: "Your password has previously appeared in a data breach and should never be used. We strongly recommend you change your password everywhere you have used it."
|
50
|
+
```
|
51
|
+
|
36
52
|
By default passwords are rejected if they appear at all in the data set.
|
37
53
|
Optionally, you can add the following snippet to `config/initializers/devise.rb`
|
38
54
|
if you want the error message to be displayed only when the password is present
|
@@ -66,6 +82,26 @@ And then execute:
|
|
66
82
|
$ bundle install
|
67
83
|
```
|
68
84
|
|
85
|
+
Optionally, if you also want to warn existing users when they sign in, override `after_sign_in_path_for`
|
86
|
+
```ruby
|
87
|
+
def after_sign_in_path_for(resource)
|
88
|
+
set_flash_message! :alert, :warn_pwned if resource.respond_to?(:pwned?) && resource.pwned?
|
89
|
+
super
|
90
|
+
end
|
91
|
+
```
|
92
|
+
|
93
|
+
This should generally be added in ```app/controllers/application_controller.rb``` for a rails app. For an Active Admin application the following monkey patch is needed.
|
94
|
+
|
95
|
+
```ruby
|
96
|
+
# config/initializers/active_admin_devise_sessions_controller.rb
|
97
|
+
class ActiveAdmin::Devise::SessionsController
|
98
|
+
def after_sign_in_path_for(resource)
|
99
|
+
set_flash_message! :alert, :warn_pwned if resource.respond_to?(:pwned?) && resource.pwned?
|
100
|
+
super
|
101
|
+
end
|
102
|
+
end
|
103
|
+
```
|
104
|
+
|
69
105
|
|
70
106
|
## Considerations
|
71
107
|
|
@@ -90,7 +126,7 @@ To contribute
|
|
90
126
|
* Fork the repository
|
91
127
|
* Make your changes
|
92
128
|
* Run bin/test to make sure the unit tests still run
|
93
|
-
* Send a pull
|
129
|
+
* Send a pull request
|
94
130
|
|
95
131
|
## License
|
96
132
|
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
@@ -0,0 +1,6 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Warden::Manager.after_set_user except: :fetch do |user, auth, opts|
|
4
|
+
password = auth.request.params.fetch(opts[:scope], {}).fetch(:password, nil)
|
5
|
+
password && auth.authenticated?(opts[:scope]) && user.respond_to?(:password_pwned?) && user.password_pwned?(password)
|
6
|
+
end
|
@@ -1,4 +1,7 @@
|
|
1
1
|
en:
|
2
|
+
devise:
|
3
|
+
sessions:
|
4
|
+
warn_pwned: "Your password has previously appeared in a data breach and should never be used. We strongly recommend you change your password."
|
2
5
|
errors:
|
3
6
|
messages:
|
4
7
|
pwned_password: "has previously appeared in a data breach and should never be used. Please choose something harder to guess."
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "net/http"
|
4
|
+
require "devise/pwned_password/hooks/pwned_password"
|
4
5
|
|
5
6
|
module Devise
|
6
7
|
module Models
|
@@ -22,6 +23,36 @@ module Devise
|
|
22
23
|
Devise::Models.config(self, :pwned_password_read_timeout)
|
23
24
|
end
|
24
25
|
|
26
|
+
def pwned?
|
27
|
+
@pwned ||= false
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns true if password is present in the PwnedPasswords dataset
|
31
|
+
# Implement retry behaviour described here https://haveibeenpwned.com/API/v2#RateLimiting
|
32
|
+
def password_pwned?(password)
|
33
|
+
@pwned = false
|
34
|
+
hash = Digest::SHA1.hexdigest(password.to_s).upcase
|
35
|
+
prefix, suffix = hash.slice!(0..4), hash
|
36
|
+
|
37
|
+
userAgent = "devise_pwned_password"
|
38
|
+
|
39
|
+
uri = URI.parse("https://api.pwnedpasswords.com/range/#{prefix}")
|
40
|
+
|
41
|
+
begin
|
42
|
+
Net::HTTP.start(uri.host, uri.port, use_ssl: true, open_timeout: self.class.pwned_password_open_timeout, read_timeout: self.class.pwned_password_read_timeout) do |http|
|
43
|
+
request = Net::HTTP::Get.new(uri.request_uri, "User-Agent" => userAgent)
|
44
|
+
response = http.request request
|
45
|
+
return false unless response.is_a?(Net::HTTPSuccess)
|
46
|
+
@pwned = usage_count(response.read_body, suffix) >= self.class.min_password_matches
|
47
|
+
return @pwned
|
48
|
+
end
|
49
|
+
rescue StandardError
|
50
|
+
return false
|
51
|
+
end
|
52
|
+
|
53
|
+
false
|
54
|
+
end
|
55
|
+
|
25
56
|
private
|
26
57
|
|
27
58
|
def usage_count(response, suffix)
|
@@ -35,30 +66,6 @@ module Devise
|
|
35
66
|
count
|
36
67
|
end
|
37
68
|
|
38
|
-
# Returns true if password is present in the PwnedPasswords dataset
|
39
|
-
# Implement retry behaviour described here https://haveibeenpwned.com/API/v2#RateLimiting
|
40
|
-
def password_pwned?(password)
|
41
|
-
hash = Digest::SHA1.hexdigest(password).upcase
|
42
|
-
prefix, suffix = hash.slice!(0..4), hash
|
43
|
-
|
44
|
-
userAgent = "devise_pwned_password"
|
45
|
-
|
46
|
-
uri = URI.parse("https://api.pwnedpasswords.com/range/#{prefix}")
|
47
|
-
|
48
|
-
begin
|
49
|
-
Net::HTTP.start(uri.host, uri.port, use_ssl: true, open_timeout: self.class.pwned_password_open_timeout, read_timeout: self.class.pwned_password_read_timeout) do |http|
|
50
|
-
request = Net::HTTP::Get.new(uri.request_uri, "User-Agent" => userAgent)
|
51
|
-
response = http.request request
|
52
|
-
return false unless response.is_a?(Net::HTTPSuccess)
|
53
|
-
return usage_count(response.read_body, suffix) >= self.class.min_password_matches
|
54
|
-
end
|
55
|
-
rescue StandardError
|
56
|
-
return false
|
57
|
-
end
|
58
|
-
|
59
|
-
false
|
60
|
-
end
|
61
|
-
|
62
69
|
def not_pwned_password
|
63
70
|
# This deliberately fails silently on 500's etc. Most apps wont want to tie the ability to sign up customers to the availability of a third party API
|
64
71
|
if password_pwned?(password)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: devise-pwned_password
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Banfield
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-03-
|
11
|
+
date: 2018-03-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -78,6 +78,7 @@ files:
|
|
78
78
|
- README.md
|
79
79
|
- Rakefile
|
80
80
|
- lib/devise/pwned_password.rb
|
81
|
+
- lib/devise/pwned_password/hooks/pwned_password.rb
|
81
82
|
- lib/devise/pwned_password/locales/en.yml
|
82
83
|
- lib/devise/pwned_password/model.rb
|
83
84
|
- lib/devise/pwned_password/version.rb
|