zyphr 0.1.50 → 0.1.51
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 +4 -4
- data/docs/PasswordPolicy.md +3 -1
- data/docs/PasswordStrength.md +6 -2
- data/lib/zyphr/models/password_policy.rb +31 -4
- data/lib/zyphr/models/password_strength.rb +66 -3
- data/spec/models/password_policy_spec.rb +6 -0
- data/spec/models/password_strength_spec.rb +12 -0
- data/zyphr.gemspec +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f7ec40b14a9b8a2ce14cff88cdb6d2e4cdebd6b1c324a65a8f8c4f1b551f1688
|
|
4
|
+
data.tar.gz: dd884a0621a0a3243a6b1ffa98e6acc8821f1b4efaaf841f12df6307fba729cb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 799f68978d7a8ea632126b16f2addb82b7e16f41e75c23f12abe809c5465ac74a7046276d371720f90472b4f0228353a3ccb9d48fbbf50ed443da2f9cf565a52
|
|
7
|
+
data.tar.gz: c17b1bdd2725d25d2c117ca6460e306ab1fe2cf96fddbcb43624f52f9dffa4546abd24ef2f13c66eb9c699e21ece24ef7e92f3d52f714ae712380fb09dcc21f6
|
data/docs/PasswordPolicy.md
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
| **require_numbers** | **Boolean** | Whether at least one number (0-9) is required. | |
|
|
12
12
|
| **require_special** | **Boolean** | Whether at least one special character is required. | |
|
|
13
13
|
| **disallow_common** | **Boolean** | Whether commonly used passwords are rejected. | |
|
|
14
|
+
| **disallow_breached** | **Boolean** | Whether passwords found in the HaveIBeenPwned breach corpus are rejected at registration/reset. Checked via k-anonymity (only a 5-char SHA-1 prefix leaves our infrastructure) and fail-open: if the breach source is unavailable the password is allowed. Default false (advisory only — the breach signal is returned but does not gate acceptance unless enabled). | |
|
|
14
15
|
|
|
15
16
|
## Example
|
|
16
17
|
|
|
@@ -24,7 +25,8 @@ instance = Zyphr::PasswordPolicy.new(
|
|
|
24
25
|
require_lowercase: null,
|
|
25
26
|
require_numbers: null,
|
|
26
27
|
require_special: null,
|
|
27
|
-
disallow_common: null
|
|
28
|
+
disallow_common: null,
|
|
29
|
+
disallow_breached: null
|
|
28
30
|
)
|
|
29
31
|
```
|
|
30
32
|
|
data/docs/PasswordStrength.md
CHANGED
|
@@ -4,8 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
| Name | Type | Description | Notes |
|
|
6
6
|
| ---- | ---- | ----------- | ----- |
|
|
7
|
-
| **valid** | **Boolean** | Whether the password would be accepted by the server's enforcement path. A password that is valid here is accepted by registration. | |
|
|
8
|
-
| **
|
|
7
|
+
| **valid** | **Boolean** | Whether the password would be accepted by the server's enforcement path. A password that is valid here is accepted by registration. When the application enables `disallow_breached`, a breached password is `valid: false` here AND rejected by register/reset (no drift). | |
|
|
8
|
+
| **breached** | **Boolean** | Whether the password appears in the HaveIBeenPwned breach corpus. This is a distinct signal from `valid` and is always returned regardless of the app's `disallow_breached` setting. Fail-open: if the breach source is unavailable this is `false`. | |
|
|
9
|
+
| **breach_count** | **Integer** | HIBP occurrence count for the password (0 if not breached or if the breach lookup failed/was unavailable). | |
|
|
10
|
+
| **score** | **Integer** | Strength score, 0-100. A pure composition measure — independent of the breach signal. | |
|
|
9
11
|
| **label** | **String** | Strength label derived from the score. | |
|
|
10
12
|
| **feedback** | **Array<String>** | Actionable feedback — policy errors plus strength-improvement suggestions. | |
|
|
11
13
|
|
|
@@ -16,6 +18,8 @@ require 'zyphr'
|
|
|
16
18
|
|
|
17
19
|
instance = Zyphr::PasswordStrength.new(
|
|
18
20
|
valid: null,
|
|
21
|
+
breached: null,
|
|
22
|
+
breach_count: null,
|
|
19
23
|
score: null,
|
|
20
24
|
label: null,
|
|
21
25
|
feedback: null
|
|
@@ -37,6 +37,9 @@ module Zyphr
|
|
|
37
37
|
# Whether commonly used passwords are rejected.
|
|
38
38
|
attr_accessor :disallow_common
|
|
39
39
|
|
|
40
|
+
# Whether passwords found in the HaveIBeenPwned breach corpus are rejected at registration/reset. Checked via k-anonymity (only a 5-char SHA-1 prefix leaves our infrastructure) and fail-open: if the breach source is unavailable the password is allowed. Default false (advisory only — the breach signal is returned but does not gate acceptance unless enabled).
|
|
41
|
+
attr_accessor :disallow_breached
|
|
42
|
+
|
|
40
43
|
# Attribute mapping from ruby-style variable name to JSON key.
|
|
41
44
|
def self.attribute_map
|
|
42
45
|
{
|
|
@@ -46,7 +49,8 @@ module Zyphr
|
|
|
46
49
|
:'require_lowercase' => :'require_lowercase',
|
|
47
50
|
:'require_numbers' => :'require_numbers',
|
|
48
51
|
:'require_special' => :'require_special',
|
|
49
|
-
:'disallow_common' => :'disallow_common'
|
|
52
|
+
:'disallow_common' => :'disallow_common',
|
|
53
|
+
:'disallow_breached' => :'disallow_breached'
|
|
50
54
|
}
|
|
51
55
|
end
|
|
52
56
|
|
|
@@ -69,7 +73,8 @@ module Zyphr
|
|
|
69
73
|
:'require_lowercase' => :'Boolean',
|
|
70
74
|
:'require_numbers' => :'Boolean',
|
|
71
75
|
:'require_special' => :'Boolean',
|
|
72
|
-
:'disallow_common' => :'Boolean'
|
|
76
|
+
:'disallow_common' => :'Boolean',
|
|
77
|
+
:'disallow_breached' => :'Boolean'
|
|
73
78
|
}
|
|
74
79
|
end
|
|
75
80
|
|
|
@@ -136,6 +141,12 @@ module Zyphr
|
|
|
136
141
|
else
|
|
137
142
|
self.disallow_common = nil
|
|
138
143
|
end
|
|
144
|
+
|
|
145
|
+
if attributes.key?(:'disallow_breached')
|
|
146
|
+
self.disallow_breached = attributes[:'disallow_breached']
|
|
147
|
+
else
|
|
148
|
+
self.disallow_breached = nil
|
|
149
|
+
end
|
|
139
150
|
end
|
|
140
151
|
|
|
141
152
|
# Show invalid properties with the reasons. Usually used together with valid?
|
|
@@ -171,6 +182,10 @@ module Zyphr
|
|
|
171
182
|
invalid_properties.push('invalid value for "disallow_common", disallow_common cannot be nil.')
|
|
172
183
|
end
|
|
173
184
|
|
|
185
|
+
if @disallow_breached.nil?
|
|
186
|
+
invalid_properties.push('invalid value for "disallow_breached", disallow_breached cannot be nil.')
|
|
187
|
+
end
|
|
188
|
+
|
|
174
189
|
invalid_properties
|
|
175
190
|
end
|
|
176
191
|
|
|
@@ -185,6 +200,7 @@ module Zyphr
|
|
|
185
200
|
return false if @require_numbers.nil?
|
|
186
201
|
return false if @require_special.nil?
|
|
187
202
|
return false if @disallow_common.nil?
|
|
203
|
+
return false if @disallow_breached.nil?
|
|
188
204
|
true
|
|
189
205
|
end
|
|
190
206
|
|
|
@@ -258,6 +274,16 @@ module Zyphr
|
|
|
258
274
|
@disallow_common = disallow_common
|
|
259
275
|
end
|
|
260
276
|
|
|
277
|
+
# Custom attribute writer method with validation
|
|
278
|
+
# @param [Object] disallow_breached Value to be assigned
|
|
279
|
+
def disallow_breached=(disallow_breached)
|
|
280
|
+
if disallow_breached.nil?
|
|
281
|
+
fail ArgumentError, 'disallow_breached cannot be nil'
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
@disallow_breached = disallow_breached
|
|
285
|
+
end
|
|
286
|
+
|
|
261
287
|
# Checks equality by comparing each attribute.
|
|
262
288
|
# @param [Object] Object to be compared
|
|
263
289
|
def ==(o)
|
|
@@ -269,7 +295,8 @@ module Zyphr
|
|
|
269
295
|
require_lowercase == o.require_lowercase &&
|
|
270
296
|
require_numbers == o.require_numbers &&
|
|
271
297
|
require_special == o.require_special &&
|
|
272
|
-
disallow_common == o.disallow_common
|
|
298
|
+
disallow_common == o.disallow_common &&
|
|
299
|
+
disallow_breached == o.disallow_breached
|
|
273
300
|
end
|
|
274
301
|
|
|
275
302
|
# @see the `==` method
|
|
@@ -281,7 +308,7 @@ module Zyphr
|
|
|
281
308
|
# Calculates hash code according to all attributes.
|
|
282
309
|
# @return [Integer] Hash code
|
|
283
310
|
def hash
|
|
284
|
-
[min_length, max_length, require_uppercase, require_lowercase, require_numbers, require_special, disallow_common].hash
|
|
311
|
+
[min_length, max_length, require_uppercase, require_lowercase, require_numbers, require_special, disallow_common, disallow_breached].hash
|
|
285
312
|
end
|
|
286
313
|
|
|
287
314
|
# Builds the object from hash
|
|
@@ -15,10 +15,16 @@ require 'time'
|
|
|
15
15
|
|
|
16
16
|
module Zyphr
|
|
17
17
|
class PasswordStrength
|
|
18
|
-
# Whether the password would be accepted by the server's enforcement path. A password that is valid here is accepted by registration.
|
|
18
|
+
# Whether the password would be accepted by the server's enforcement path. A password that is valid here is accepted by registration. When the application enables `disallow_breached`, a breached password is `valid: false` here AND rejected by register/reset (no drift).
|
|
19
19
|
attr_accessor :valid
|
|
20
20
|
|
|
21
|
-
#
|
|
21
|
+
# Whether the password appears in the HaveIBeenPwned breach corpus. This is a distinct signal from `valid` and is always returned regardless of the app's `disallow_breached` setting. Fail-open: if the breach source is unavailable this is `false`.
|
|
22
|
+
attr_accessor :breached
|
|
23
|
+
|
|
24
|
+
# HIBP occurrence count for the password (0 if not breached or if the breach lookup failed/was unavailable).
|
|
25
|
+
attr_accessor :breach_count
|
|
26
|
+
|
|
27
|
+
# Strength score, 0-100. A pure composition measure — independent of the breach signal.
|
|
22
28
|
attr_accessor :score
|
|
23
29
|
|
|
24
30
|
# Strength label derived from the score.
|
|
@@ -53,6 +59,8 @@ module Zyphr
|
|
|
53
59
|
def self.attribute_map
|
|
54
60
|
{
|
|
55
61
|
:'valid' => :'valid',
|
|
62
|
+
:'breached' => :'breached',
|
|
63
|
+
:'breach_count' => :'breach_count',
|
|
56
64
|
:'score' => :'score',
|
|
57
65
|
:'label' => :'label',
|
|
58
66
|
:'feedback' => :'feedback'
|
|
@@ -73,6 +81,8 @@ module Zyphr
|
|
|
73
81
|
def self.openapi_types
|
|
74
82
|
{
|
|
75
83
|
:'valid' => :'Boolean',
|
|
84
|
+
:'breached' => :'Boolean',
|
|
85
|
+
:'breach_count' => :'Integer',
|
|
76
86
|
:'score' => :'Integer',
|
|
77
87
|
:'label' => :'String',
|
|
78
88
|
:'feedback' => :'Array<String>'
|
|
@@ -107,6 +117,18 @@ module Zyphr
|
|
|
107
117
|
self.valid = nil
|
|
108
118
|
end
|
|
109
119
|
|
|
120
|
+
if attributes.key?(:'breached')
|
|
121
|
+
self.breached = attributes[:'breached']
|
|
122
|
+
else
|
|
123
|
+
self.breached = nil
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
if attributes.key?(:'breach_count')
|
|
127
|
+
self.breach_count = attributes[:'breach_count']
|
|
128
|
+
else
|
|
129
|
+
self.breach_count = nil
|
|
130
|
+
end
|
|
131
|
+
|
|
110
132
|
if attributes.key?(:'score')
|
|
111
133
|
self.score = attributes[:'score']
|
|
112
134
|
else
|
|
@@ -137,6 +159,18 @@ module Zyphr
|
|
|
137
159
|
invalid_properties.push('invalid value for "valid", valid cannot be nil.')
|
|
138
160
|
end
|
|
139
161
|
|
|
162
|
+
if @breached.nil?
|
|
163
|
+
invalid_properties.push('invalid value for "breached", breached cannot be nil.')
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
if @breach_count.nil?
|
|
167
|
+
invalid_properties.push('invalid value for "breach_count", breach_count cannot be nil.')
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
if @breach_count < 0
|
|
171
|
+
invalid_properties.push('invalid value for "breach_count", must be greater than or equal to 0.')
|
|
172
|
+
end
|
|
173
|
+
|
|
140
174
|
if @score.nil?
|
|
141
175
|
invalid_properties.push('invalid value for "score", score cannot be nil.')
|
|
142
176
|
end
|
|
@@ -165,6 +199,9 @@ module Zyphr
|
|
|
165
199
|
def valid?
|
|
166
200
|
warn '[DEPRECATED] the `valid?` method is obsolete'
|
|
167
201
|
return false if @valid.nil?
|
|
202
|
+
return false if @breached.nil?
|
|
203
|
+
return false if @breach_count.nil?
|
|
204
|
+
return false if @breach_count < 0
|
|
168
205
|
return false if @score.nil?
|
|
169
206
|
return false if @score > 100
|
|
170
207
|
return false if @score < 0
|
|
@@ -185,6 +222,30 @@ module Zyphr
|
|
|
185
222
|
@valid = valid
|
|
186
223
|
end
|
|
187
224
|
|
|
225
|
+
# Custom attribute writer method with validation
|
|
226
|
+
# @param [Object] breached Value to be assigned
|
|
227
|
+
def breached=(breached)
|
|
228
|
+
if breached.nil?
|
|
229
|
+
fail ArgumentError, 'breached cannot be nil'
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
@breached = breached
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
# Custom attribute writer method with validation
|
|
236
|
+
# @param [Object] breach_count Value to be assigned
|
|
237
|
+
def breach_count=(breach_count)
|
|
238
|
+
if breach_count.nil?
|
|
239
|
+
fail ArgumentError, 'breach_count cannot be nil'
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
if breach_count < 0
|
|
243
|
+
fail ArgumentError, 'invalid value for "breach_count", must be greater than or equal to 0.'
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
@breach_count = breach_count
|
|
247
|
+
end
|
|
248
|
+
|
|
188
249
|
# Custom attribute writer method with validation
|
|
189
250
|
# @param [Object] score Value to be assigned
|
|
190
251
|
def score=(score)
|
|
@@ -229,6 +290,8 @@ module Zyphr
|
|
|
229
290
|
return true if self.equal?(o)
|
|
230
291
|
self.class == o.class &&
|
|
231
292
|
valid == o.valid &&
|
|
293
|
+
breached == o.breached &&
|
|
294
|
+
breach_count == o.breach_count &&
|
|
232
295
|
score == o.score &&
|
|
233
296
|
label == o.label &&
|
|
234
297
|
feedback == o.feedback
|
|
@@ -243,7 +306,7 @@ module Zyphr
|
|
|
243
306
|
# Calculates hash code according to all attributes.
|
|
244
307
|
# @return [Integer] Hash code
|
|
245
308
|
def hash
|
|
246
|
-
[valid, score, label, feedback].hash
|
|
309
|
+
[valid, breached, breach_count, score, label, feedback].hash
|
|
247
310
|
end
|
|
248
311
|
|
|
249
312
|
# Builds the object from hash
|
|
@@ -33,6 +33,18 @@ describe Zyphr::PasswordStrength do
|
|
|
33
33
|
end
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
+
describe 'test attribute "breached"' do
|
|
37
|
+
it 'should work' do
|
|
38
|
+
# assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
describe 'test attribute "breach_count"' do
|
|
43
|
+
it 'should work' do
|
|
44
|
+
# assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
36
48
|
describe 'test attribute "score"' do
|
|
37
49
|
it 'should work' do
|
|
38
50
|
# assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
|
data/zyphr.gemspec
CHANGED