devise-pwned_password 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
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