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: 33a24728b4d0e4bd0f038f228419b1be59ed1f37
4
- data.tar.gz: 48256086d719c039ebe89b0015b3eb5ef0c7e2d6
3
+ metadata.gz: 9034d6a6d49339f92023d27ef40b8633a2332ded
4
+ data.tar.gz: 1e429adc52ffb2aff28985d9a1636aec657b686a
5
5
  SHA512:
6
- metadata.gz: e59fdefbc4f327c4cc93bb84532b67e57af8c59bb78270d3c9ec805bdd8319cb19b4a8241506c84daa04413abc5387c0e1ce2de78ee4a986f10fce1b889d1718
7
- data.tar.gz: a9731a85f5d23f3c4ba0d67b6928719daa72623d51ae79fee1bd88c895bd638e18247c570e9ff2fcdffc601bb2bc15a985b8f80cb42c91250e921a20b3ff79b5
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 requests
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)
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Devise
4
4
  module PwnedPassword
5
- VERSION = "0.1.3"
5
+ VERSION = "0.1.4"
6
6
  end
7
7
  end
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.3
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-06 00:00:00.000000000 Z
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