pwned 1.2.1 → 2.0.0
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/.travis.yml +15 -9
- data/CHANGELOG.md +44 -17
- data/README.md +117 -7
- data/bin/pwned +52 -0
- data/docs/NotPwnedValidator.html +23 -17
- data/docs/Pwned.html +30 -22
- data/docs/Pwned/Error.html +3 -3
- data/docs/Pwned/Password.html +60 -49
- data/docs/Pwned/TimeoutError.html +3 -3
- data/docs/PwnedValidator.html +3 -3
- data/docs/_index.html +4 -4
- data/docs/css/style.css +4 -7
- data/docs/file.README.html +147 -17
- data/docs/frames.html +1 -1
- data/docs/index.html +147 -17
- data/docs/js/app.js +55 -0
- data/docs/top-level-namespace.html +3 -3
- data/lib/pwned.rb +6 -6
- data/lib/pwned/password.rb +44 -11
- data/lib/pwned/version.rb +1 -1
- data/pwned.gemspec +10 -1
- metadata +20 -7
data/docs/frames.html
CHANGED
data/docs/index.html
CHANGED
@@ -6,7 +6,7 @@
|
|
6
6
|
<title>
|
7
7
|
File: README
|
8
8
|
|
9
|
-
— Documentation by YARD 0.9.
|
9
|
+
— Documentation by YARD 0.9.20
|
10
10
|
|
11
11
|
</title>
|
12
12
|
|
@@ -74,6 +74,33 @@ src="https://inch-ci.org/github/philnash/pwned.svg?branch=master"></a></p>
|
|
74
74
|
<p><a href="https://philnash.github.io/pwned/">API docs</a> | <a
|
75
75
|
href="https://github.com/philnash/pwned">GitHub repo</a></p>
|
76
76
|
|
77
|
+
<h2 id="label-Table+of+Contents">Table of Contents</h2>
|
78
|
+
<ul><li>
|
79
|
+
<p><a href="#about">About</a></p>
|
80
|
+
</li><li>
|
81
|
+
<p><a href="#installation">Installation</a></p>
|
82
|
+
</li><li>
|
83
|
+
<p><a href="#usage">Usage</a></p>
|
84
|
+
</li><li>
|
85
|
+
<p><a href="#plain-ruby">Plain Ruby</a></p>
|
86
|
+
</li><li>
|
87
|
+
<p><a href="#activerecord-validator">Rails (ActiveRecord)</a></p>
|
88
|
+
</li><li>
|
89
|
+
<p><a href="#devise">Devise</a></p>
|
90
|
+
</li><li>
|
91
|
+
<p><a href="#command-line">Command line</a></p>
|
92
|
+
</li><li>
|
93
|
+
<p><a href="#how-pwned-is-pi">How Pwned is Pi?</a></p>
|
94
|
+
</li><li>
|
95
|
+
<p><a href="#development">Development</a></p>
|
96
|
+
</li><li>
|
97
|
+
<p><a href="#contributing">Contributing</a></p>
|
98
|
+
</li><li>
|
99
|
+
<p><a href="#license">License</a></p>
|
100
|
+
</li><li>
|
101
|
+
<p><a href="#code-of-conduct">Code of Conduct</a></p>
|
102
|
+
</li></ul>
|
103
|
+
|
77
104
|
<h2 id="label-About">About</h2>
|
78
105
|
|
79
106
|
<p>Troy Hunt's <a
|
@@ -93,6 +120,11 @@ API, please check <a
|
|
93
120
|
href="https://haveibeenpwned.com/API/v2#AcceptableUse">the acceptable uses
|
94
121
|
and license of the API</a>.</p>
|
95
122
|
|
123
|
+
<p>Here is a blog post I wrote on <a
|
124
|
+
href="https://www.twilio.com/blog/2018/03/better-passwords-in-ruby-applications-pwned-passwords-api.html">how
|
125
|
+
to use this gem in your Ruby applications to make your users’ passwords
|
126
|
+
better</a>.</p>
|
127
|
+
|
96
128
|
<h2 id="label-Installation">Installation</h2>
|
97
129
|
|
98
130
|
<p>Add this line to your application's Gemfile:</p>
|
@@ -112,6 +144,17 @@ and license of the API</a>.</p>
|
|
112
144
|
|
113
145
|
<h2 id="label-Usage">Usage</h2>
|
114
146
|
|
147
|
+
<p>There are a few ways you can use this gem:</p>
|
148
|
+
<ol><li>
|
149
|
+
<p><a href="#plain-ruby">Plain Ruby</a></p>
|
150
|
+
</li><li>
|
151
|
+
<p><a href="#activerecord-validator">Rails</a></p>
|
152
|
+
</li><li>
|
153
|
+
<p><a href="#devise">Rails and Devise</a></p>
|
154
|
+
</li></ol>
|
155
|
+
|
156
|
+
<h3 id="label-Plain+Ruby">Plain Ruby</h3>
|
157
|
+
|
115
158
|
<p>To test a password against the API, instantiate a
|
116
159
|
<code>Pwned::Password</code> object and then ask if it is
|
117
160
|
<code>pwned?</code>.</p>
|
@@ -154,12 +197,14 @@ been pwned, or how many times it was pwned:</p>
|
|
154
197
|
|
155
198
|
<h4 id="label-Advanced">Advanced</h4>
|
156
199
|
|
157
|
-
<p>You can set
|
158
|
-
making the request to the API.
|
159
|
-
|
160
|
-
|
200
|
+
<p>You can set http request options to be used with
|
201
|
+
<code>Net::HTTP.start</code> when making the request to the API. These
|
202
|
+
options are documented in the <a
|
203
|
+
href="http://ruby-doc.org/stdlib-2.6.3/libdoc/net/http/rdoc/Net/HTTP.html#method-c-start">Net::HTTP.start
|
204
|
+
documentation</a>. The <code>:headers</code> option defines defines HTTP
|
205
|
+
headers. These headers must be string keys.</p>
|
161
206
|
|
162
|
-
<pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_password'>password</span> <span class='op'>=</span> <span class='const'><span class='object_link'><a href="Pwned.html" title="Pwned (module)">Pwned</a></span></span><span class='op'>::</span><span class='const'><span class='object_link'><a href="Pwned/Password.html" title="Pwned::Password (class)">Password</a></span></span><span class='period'>.</span><span class='id identifier rubyid_new'><span class='object_link'><a href="Pwned/Password.html#initialize-instance_method" title="Pwned::Password#initialize (method)">new</a></span></span><span class='lparen'>(</span><span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>password</span><span class='tstring_end'>"</span></span><span class='comma'>,</span> <span class='lbrace'>{</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>User-Agent</span><span class='tstring_end'>'</span></span> <span class='op'>=></span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>Super fun new user agent</span><span class='tstring_end'>'</span></span> <span class='rbrace'>}</span><span class='rparen'>)</span>
|
207
|
+
<pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_password'>password</span> <span class='op'>=</span> <span class='const'><span class='object_link'><a href="Pwned.html" title="Pwned (module)">Pwned</a></span></span><span class='op'>::</span><span class='const'><span class='object_link'><a href="Pwned/Password.html" title="Pwned::Password (class)">Password</a></span></span><span class='period'>.</span><span class='id identifier rubyid_new'><span class='object_link'><a href="Pwned/Password.html#initialize-instance_method" title="Pwned::Password#initialize (method)">new</a></span></span><span class='lparen'>(</span><span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>password</span><span class='tstring_end'>"</span></span><span class='comma'>,</span> <span class='label'>headers:</span> <span class='lbrace'>{</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>User-Agent</span><span class='tstring_end'>'</span></span> <span class='op'>=></span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>Super fun new user agent</span><span class='tstring_end'>'</span></span> <span class='rbrace'>}</span><span class='comma'>,</span> <span class='label'>read_timeout:</span> <span class='int'>10</span><span class='rparen'>)</span>
|
163
208
|
</code></pre>
|
164
209
|
|
165
210
|
<h3 id="label-ActiveRecord+Validator">ActiveRecord Validator</h3>
|
@@ -198,7 +243,7 @@ whether the <code>pwned_count</code> is greater than the threshold.</p>
|
|
198
243
|
<span class='kw'>end</span>
|
199
244
|
</code></pre>
|
200
245
|
|
201
|
-
<h4 id="label-Network+
|
246
|
+
<h4 id="label-Network+Error+Handling">Network Error Handling</h4>
|
202
247
|
|
203
248
|
<p>By default the record will be treated as valid when we cannot reach the <a
|
204
249
|
href="https://haveibeenpwned.com/">haveibeenpwned.com</a> servers. This can
|
@@ -233,19 +278,104 @@ be changed with the <code>:on_error</code> validator parameter:</p>
|
|
233
278
|
|
234
279
|
<p>You can configure network requests made from the validator using
|
235
280
|
<code>:request_options</code> (see <a
|
236
|
-
href="http://ruby-doc.org/stdlib-2.
|
237
|
-
for the list of available options
|
238
|
-
|
281
|
+
href="http://ruby-doc.org/stdlib-2.6.3/libdoc/net/http/rdoc/Net/HTTP.html#method-c-start">Net::HTTP.start</a>
|
282
|
+
for the list of available options). In addition to these options, HTTP
|
283
|
+
headers can be specified with the <code>:headers</code> key, e.g.
|
284
|
+
<code>"User-Agent"</code>):</p>
|
239
285
|
|
240
286
|
<pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_validates'>validates</span> <span class='symbol'>:password</span><span class='comma'>,</span> <span class='label'>not_pwned:</span> <span class='lbrace'>{</span>
|
241
|
-
<span class='label'>request_options:</span> <span class='lbrace'>{</span> <span class='label'>read_timeout:</span> <span class='int'>5</span><span class='comma'>,</span> <span class='label'>open_timeout:</span> <span class='int'>1</span><span class='comma'>,</span> <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>User-Agent</span><span class='tstring_end'>"</span></span> <span class='op'>=></span> <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>Super fun user agent</span><span class='tstring_end'>"</span></span> <span class='rbrace'>}</span>
|
287
|
+
<span class='label'>request_options:</span> <span class='lbrace'>{</span> <span class='label'>read_timeout:</span> <span class='int'>5</span><span class='comma'>,</span> <span class='label'>open_timeout:</span> <span class='int'>1</span><span class='comma'>,</span> <span class='label'>headers:</span> <span class='lbrace'>{</span> <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>User-Agent</span><span class='tstring_end'>"</span></span> <span class='op'>=></span> <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>Super fun user agent</span><span class='tstring_end'>"</span></span> <span class='rbrace'>}</span> <span class='rbrace'>}</span>
|
242
288
|
<span class='rbrace'>}</span>
|
243
289
|
</code></pre>
|
244
290
|
|
245
|
-
<
|
246
|
-
|
247
|
-
<p>
|
248
|
-
|
291
|
+
<h3 id="label-Devise">Devise</h3>
|
292
|
+
|
293
|
+
<p>If you are using Devise I recommend you use the <a
|
294
|
+
href="https://github.com/michaelbanfield/devise-pwned_password">devise-pwned_password
|
295
|
+
extension</a> which is now powered by this gem.</p>
|
296
|
+
|
297
|
+
<h3 id="label-Command+line">Command line</h3>
|
298
|
+
|
299
|
+
<p>The gem provides a command line utility for checking passwords. You can
|
300
|
+
call it from your terminal application like this:</p>
|
301
|
+
|
302
|
+
<pre class="code ruby"><code class="ruby">$ pwned password
|
303
|
+
Pwned!
|
304
|
+
The password has been found in public breaches 3645804 times.
|
305
|
+
</code></pre>
|
306
|
+
|
307
|
+
<p>If you don't want the password you are checking to be visible, call:</p>
|
308
|
+
|
309
|
+
<pre class="code ruby"><code class="ruby">$ pwned --secret
|
310
|
+
</code></pre>
|
311
|
+
|
312
|
+
<p>You will be prompted for the password, but it won't be displayed.</p>
|
313
|
+
|
314
|
+
<h2 id="label-How+Pwned+is+Pi-3F">How Pwned is Pi?</h2>
|
315
|
+
|
316
|
+
<p><a href="https://github.com/daz">@daz</a> <a
|
317
|
+
href="https://twitter.com/dazonic/status/1074647842046660609">shared</a> a
|
318
|
+
fantastic example of using this gem to show how many times the digits of Pi
|
319
|
+
have been used as passwords and leaked.</p>
|
320
|
+
|
321
|
+
<pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_require'>require</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>pwned</span><span class='tstring_end'>'</span></span>
|
322
|
+
|
323
|
+
<span class='const'>PI</span> <span class='op'>=</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111</span><span class='tstring_end'>'</span></span>
|
324
|
+
|
325
|
+
<span class='kw'>for</span> <span class='id identifier rubyid_n'>n</span> <span class='kw'>in</span> <span class='int'>1</span><span class='op'>..</span><span class='int'>40</span>
|
326
|
+
<span class='id identifier rubyid_password'>password</span> <span class='op'>=</span> <span class='const'><span class='object_link'><a href="Pwned.html" title="Pwned (module)">Pwned</a></span></span><span class='op'>::</span><span class='const'><span class='object_link'><a href="Pwned/Password.html" title="Pwned::Password (class)">Password</a></span></span><span class='period'>.</span><span class='id identifier rubyid_new'><span class='object_link'><a href="Pwned/Password.html#initialize-instance_method" title="Pwned::Password#initialize (method)">new</a></span></span> <span class='const'>PI</span><span class='lbracket'>[</span><span class='int'>0</span><span class='op'>..</span><span class='lparen'>(</span><span class='id identifier rubyid_n'>n</span> <span class='op'>+</span> <span class='int'>1</span><span class='rparen'>)</span><span class='rbracket'>]</span>
|
327
|
+
<span class='id identifier rubyid_str'>str</span> <span class='op'>=</span> <span class='lbracket'>[</span> <span class='id identifier rubyid_n'>n</span><span class='period'>.</span><span class='id identifier rubyid_to_s'>to_s</span><span class='period'>.</span><span class='id identifier rubyid_rjust'>rjust</span><span class='lparen'>(</span><span class='int'>2</span><span class='rparen'>)</span> <span class='rbracket'>]</span>
|
328
|
+
<span class='id identifier rubyid_str'>str</span> <span class='op'><<</span> <span class='lparen'>(</span><span class='id identifier rubyid_password'>password</span><span class='period'>.</span><span class='id identifier rubyid_pwned?'>pwned?</span> <span class='op'>?</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>😡</span><span class='tstring_end'>'</span></span> <span class='op'>:</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>😃</span><span class='tstring_end'>'</span></span><span class='rparen'>)</span>
|
329
|
+
<span class='id identifier rubyid_str'>str</span> <span class='op'><<</span> <span class='id identifier rubyid_password'>password</span><span class='period'>.</span><span class='id identifier rubyid_pwned_count'>pwned_count</span><span class='period'>.</span><span class='id identifier rubyid_to_s'>to_s</span><span class='period'>.</span><span class='id identifier rubyid_rjust'>rjust</span><span class='lparen'>(</span><span class='int'>4</span><span class='rparen'>)</span>
|
330
|
+
<span class='id identifier rubyid_str'>str</span> <span class='op'><<</span> <span class='id identifier rubyid_password'>password</span><span class='period'>.</span><span class='id identifier rubyid_password'>password</span>
|
331
|
+
|
332
|
+
<span class='id identifier rubyid_puts'>puts</span> <span class='id identifier rubyid_str'>str</span><span class='period'>.</span><span class='id identifier rubyid_join'>join</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'> </span><span class='tstring_end'>'</span></span>
|
333
|
+
<span class='kw'>end</span>
|
334
|
+
</code></pre>
|
335
|
+
|
336
|
+
<p>The results may, or may not, surprise you.</p>
|
337
|
+
|
338
|
+
<pre class="code ruby"><code class="ruby">1 😡 16 3.1
|
339
|
+
2 😡 238 3.14
|
340
|
+
3 😡 34 3.141
|
341
|
+
4 😡 1345 3.1415
|
342
|
+
5 😡 2552 3.14159
|
343
|
+
6 😡 791 3.141592
|
344
|
+
7 😡 9582 3.1415926
|
345
|
+
8 😡 1591 3.14159265
|
346
|
+
9 😡 637 3.141592653
|
347
|
+
10 😡 873 3.1415926535
|
348
|
+
11 😡 137 3.14159265358
|
349
|
+
12 😡 103 3.141592653589
|
350
|
+
13 😡 65 3.1415926535897
|
351
|
+
14 😡 201 3.14159265358979
|
352
|
+
15 😡 41 3.141592653589793
|
353
|
+
16 😡 57 3.1415926535897932
|
354
|
+
17 😡 28 3.14159265358979323
|
355
|
+
18 😡 29 3.141592653589793238
|
356
|
+
19 😡 1 3.1415926535897932384
|
357
|
+
20 😡 7 3.14159265358979323846
|
358
|
+
21 😡 5 3.141592653589793238462
|
359
|
+
22 😡 2 3.1415926535897932384626
|
360
|
+
23 😡 2 3.14159265358979323846264
|
361
|
+
24 😃 0 3.141592653589793238462643
|
362
|
+
25 😡 3 3.1415926535897932384626433
|
363
|
+
26 😃 0 3.14159265358979323846264338
|
364
|
+
27 😃 0 3.141592653589793238462643383
|
365
|
+
28 😃 0 3.1415926535897932384626433832
|
366
|
+
29 😃 0 3.14159265358979323846264338327
|
367
|
+
30 😃 0 3.141592653589793238462643383279
|
368
|
+
31 😃 0 3.1415926535897932384626433832795
|
369
|
+
32 😃 0 3.14159265358979323846264338327950
|
370
|
+
33 😃 0 3.141592653589793238462643383279502
|
371
|
+
34 😃 0 3.1415926535897932384626433832795028
|
372
|
+
35 😃 0 3.14159265358979323846264338327950288
|
373
|
+
36 😃 0 3.141592653589793238462643383279502884
|
374
|
+
37 😃 0 3.1415926535897932384626433832795028841
|
375
|
+
38 😃 0 3.14159265358979323846264338327950288419
|
376
|
+
39 😃 0 3.141592653589793238462643383279502884197
|
377
|
+
40 😃 0 3.1415926535897932384626433832795028841971
|
378
|
+
</code></pre>
|
249
379
|
|
250
380
|
<h2 id="label-Development">Development</h2>
|
251
381
|
|
@@ -284,9 +414,9 @@ of conduct</a>.</p>
|
|
284
414
|
</div></div>
|
285
415
|
|
286
416
|
<div id="footer">
|
287
|
-
Generated on
|
417
|
+
Generated on Tue Oct 1 21:19:36 2019 by
|
288
418
|
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
289
|
-
0.9.
|
419
|
+
0.9.20 (ruby-2.5.5).
|
290
420
|
</div>
|
291
421
|
|
292
422
|
</div>
|
data/docs/js/app.js
CHANGED
@@ -120,6 +120,49 @@ function summaryToggle() {
|
|
120
120
|
} else { localStorage.summaryCollapsed = "expand"; }
|
121
121
|
}
|
122
122
|
|
123
|
+
function constantSummaryToggle() {
|
124
|
+
$('.constants_summary_toggle').click(function(e) {
|
125
|
+
e.preventDefault();
|
126
|
+
localStorage.summaryCollapsed = $(this).text();
|
127
|
+
$('.constants_summary_toggle').each(function() {
|
128
|
+
$(this).text($(this).text() == "collapse" ? "expand" : "collapse");
|
129
|
+
var next = $(this).parent().parent().nextAll('dl.constants').first();
|
130
|
+
if (next.hasClass('compact')) {
|
131
|
+
next.toggle();
|
132
|
+
next.nextAll('dl.constants').first().toggle();
|
133
|
+
}
|
134
|
+
else if (next.hasClass('constants')) {
|
135
|
+
var list = $('<dl class="constants compact" />');
|
136
|
+
list.html(next.html());
|
137
|
+
list.find('dt').each(function() {
|
138
|
+
$(this).addClass('summary_signature');
|
139
|
+
$(this).text( $(this).text().split('=')[0]);
|
140
|
+
if ($(this).has(".deprecated").length) {
|
141
|
+
$(this).addClass('deprecated');
|
142
|
+
};
|
143
|
+
});
|
144
|
+
// Add the value of the constant as "Tooltip" to the summary object
|
145
|
+
list.find('pre.code').each(function() {
|
146
|
+
console.log($(this).parent());
|
147
|
+
var dt_element = $(this).parent().prev();
|
148
|
+
var tooltip = $(this).text();
|
149
|
+
if (dt_element.hasClass("deprecated")) {
|
150
|
+
tooltip = 'Deprecated. ' + tooltip;
|
151
|
+
};
|
152
|
+
dt_element.attr('title', tooltip);
|
153
|
+
});
|
154
|
+
list.find('.docstring, .tags, dd').remove();
|
155
|
+
next.before(list);
|
156
|
+
next.toggle();
|
157
|
+
}
|
158
|
+
});
|
159
|
+
return false;
|
160
|
+
});
|
161
|
+
if (localStorage.summaryCollapsed == "collapse") {
|
162
|
+
$('.constants_summary_toggle').first().click();
|
163
|
+
} else { localStorage.summaryCollapsed = "expand"; }
|
164
|
+
}
|
165
|
+
|
123
166
|
function generateTOC() {
|
124
167
|
if ($('#filecontents').length === 0) return;
|
125
168
|
var _toc = $('<ol class="top"></ol>');
|
@@ -232,6 +275,16 @@ function mainFocus() {
|
|
232
275
|
setTimeout(function() { $('#main').focus(); }, 10);
|
233
276
|
}
|
234
277
|
|
278
|
+
function navigationChange() {
|
279
|
+
// This works around the broken anchor navigation with the YARD template.
|
280
|
+
window.onpopstate = function() {
|
281
|
+
var hash = window.location.hash;
|
282
|
+
if (hash !== '' && $(hash)[0]) {
|
283
|
+
$(hash)[0].scrollIntoView();
|
284
|
+
}
|
285
|
+
};
|
286
|
+
}
|
287
|
+
|
235
288
|
$(document).ready(function() {
|
236
289
|
navResizer();
|
237
290
|
navExpander();
|
@@ -241,8 +294,10 @@ $(document).ready(function() {
|
|
241
294
|
searchFrameButtons();
|
242
295
|
linkSummaries();
|
243
296
|
summaryToggle();
|
297
|
+
constantSummaryToggle();
|
244
298
|
generateTOC();
|
245
299
|
mainFocus();
|
300
|
+
navigationChange();
|
246
301
|
});
|
247
302
|
|
248
303
|
})();
|
@@ -6,7 +6,7 @@
|
|
6
6
|
<title>
|
7
7
|
Top Level Namespace
|
8
8
|
|
9
|
-
— Documentation by YARD 0.9.
|
9
|
+
— Documentation by YARD 0.9.20
|
10
10
|
|
11
11
|
</title>
|
12
12
|
|
@@ -102,9 +102,9 @@
|
|
102
102
|
</div>
|
103
103
|
|
104
104
|
<div id="footer">
|
105
|
-
Generated on
|
105
|
+
Generated on Tue Oct 1 21:19:37 2019 by
|
106
106
|
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
107
|
-
0.9.
|
107
|
+
0.9.20 (ruby-2.5.5).
|
108
108
|
</div>
|
109
109
|
|
110
110
|
</div>
|
data/lib/pwned.rb
CHANGED
@@ -29,10 +29,10 @@ module Pwned
|
|
29
29
|
# Pwned.pwned?("pwned::password") #=> false
|
30
30
|
#
|
31
31
|
# @param password [String] The password you want to check against the API.
|
32
|
-
# @param [Hash] request_options Options that can be passed to +
|
32
|
+
# @param [Hash] request_options Options that can be passed to +Net::HTTP.start+ when
|
33
33
|
# calling the API
|
34
|
-
# @option request_options [
|
35
|
-
#
|
34
|
+
# @option request_options [Symbol] :headers ({ "User-Agent" => '"Ruby Pwned::Password #{Pwned::VERSION}" })
|
35
|
+
# HTTP headers to include in the request
|
36
36
|
# @return [Boolean] Whether the password appears in the data breaches or not.
|
37
37
|
# @since 1.1.0
|
38
38
|
def self.pwned?(password, request_options={})
|
@@ -47,10 +47,10 @@ module Pwned
|
|
47
47
|
# Pwned.pwned_count("pwned::password") #=> 0
|
48
48
|
#
|
49
49
|
# @param password [String] The password you want to check against the API.
|
50
|
-
# @param [Hash] request_options Options that can be passed to +
|
50
|
+
# @param [Hash] request_options Options that can be passed to +Net::HTTP.start+ when
|
51
51
|
# calling the API
|
52
|
-
# @option request_options [
|
53
|
-
#
|
52
|
+
# @option request_options [Symbol] :headers ({ "User-Agent" => '"Ruby Pwned::Password #{Pwned::VERSION}" })
|
53
|
+
# HTTP headers to include in the request
|
54
54
|
# @return [Integer] The number of times the password has appeared in the data
|
55
55
|
# breaches.
|
56
56
|
# @since 1.1.0
|
data/lib/pwned/password.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "digest"
|
4
|
-
require
|
4
|
+
require 'net/http'
|
5
5
|
|
6
6
|
module Pwned
|
7
7
|
##
|
@@ -23,10 +23,10 @@ module Pwned
|
|
23
23
|
SHA1_LENGTH = 40
|
24
24
|
|
25
25
|
##
|
26
|
-
# The default request
|
26
|
+
# The default request headers that are used to make HTTP requests to the
|
27
27
|
# API. A user agent is provided as requested in the documentation.
|
28
28
|
# @see https://haveibeenpwned.com/API/v2#UserAgent
|
29
|
-
|
29
|
+
DEFAULT_REQUEST_HEADERS = {
|
30
30
|
"User-Agent" => "Ruby Pwned::Password #{Pwned::VERSION}"
|
31
31
|
}.freeze
|
32
32
|
|
@@ -40,21 +40,23 @@ module Pwned
|
|
40
40
|
#
|
41
41
|
# @example A simple password with the default request options
|
42
42
|
# password = Pwned::Password.new("password")
|
43
|
-
# @example Setting the user agent and the read timeout of the
|
44
|
-
# password = Pwned::Password.new("password", "User-Agent" => "My user agent", :
|
43
|
+
# @example Setting the user agent and the read timeout of the request
|
44
|
+
# password = Pwned::Password.new("password", headers: { "User-Agent" => "My user agent" }, read_timout: 10)
|
45
45
|
#
|
46
46
|
# @param password [String] The password you want to check against the API.
|
47
|
-
# @param [Hash] request_options Options that can be passed to +
|
47
|
+
# @param [Hash] request_options Options that can be passed to +Net::HTTP.start+ when
|
48
48
|
# calling the API
|
49
|
-
# @option request_options [
|
50
|
-
#
|
49
|
+
# @option request_options [Symbol] :headers ({ "User-Agent" => '"Ruby Pwned::Password #{Pwned::VERSION}" })
|
50
|
+
# HTTP headers to include in the request
|
51
51
|
# @return [Boolean] Whether the password appears in the data breaches or not.
|
52
52
|
# @raise [TypeError] if the password is not a string.
|
53
53
|
# @since 1.1.0
|
54
54
|
def initialize(password, request_options={})
|
55
55
|
raise TypeError, "password must be of type String" unless password.is_a? String
|
56
56
|
@password = password
|
57
|
-
@request_options =
|
57
|
+
@request_options = Hash(request_options).dup
|
58
|
+
@request_headers = Hash(request_options.delete(:headers))
|
59
|
+
@request_headers = DEFAULT_REQUEST_HEADERS.merge(@request_headers)
|
58
60
|
end
|
59
61
|
|
60
62
|
##
|
@@ -93,6 +95,8 @@ module Pwned
|
|
93
95
|
|
94
96
|
private
|
95
97
|
|
98
|
+
attr_reader :request_options, :request_headers
|
99
|
+
|
96
100
|
def fetch_pwned_count
|
97
101
|
for_each_response_line do |line|
|
98
102
|
next unless line.start_with?(hashed_password_suffix)
|
@@ -106,8 +110,9 @@ module Pwned
|
|
106
110
|
|
107
111
|
def for_each_response_line(&block)
|
108
112
|
begin
|
109
|
-
|
110
|
-
|
113
|
+
with_http_response "#{API_URL}#{hashed_password_prefix}" do |response|
|
114
|
+
response.value # raise if request was unsuccessful
|
115
|
+
stream_response_lines(response, &block)
|
111
116
|
end
|
112
117
|
rescue Timeout::Error => e
|
113
118
|
raise Pwned::TimeoutError, e.message
|
@@ -123,5 +128,33 @@ module Pwned
|
|
123
128
|
def hashed_password_suffix
|
124
129
|
hashed_password[HASH_PREFIX_LENGTH..-1]
|
125
130
|
end
|
131
|
+
|
132
|
+
# Make a HTTP GET request given the url and headers.
|
133
|
+
# Yields a `Net::HTTPResponse`.
|
134
|
+
def with_http_response(url, &block)
|
135
|
+
uri = URI(url)
|
136
|
+
|
137
|
+
request = Net::HTTP::Get.new(uri)
|
138
|
+
request.initialize_http_header(request_headers)
|
139
|
+
request_options[:use_ssl] = true
|
140
|
+
|
141
|
+
Net::HTTP.start(uri.host, uri.port, request_options) do |http|
|
142
|
+
http.request(request, &block)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
# Stream a Net::HTTPResponse by line, handling lines that cross chunks.
|
147
|
+
def stream_response_lines(response, &block)
|
148
|
+
last_line = ''
|
149
|
+
|
150
|
+
response.read_body do |chunk|
|
151
|
+
chunk_lines = (last_line + chunk).lines
|
152
|
+
# This could end with half a line, so save it for next time
|
153
|
+
last_line = chunk_lines.pop
|
154
|
+
chunk_lines.each(&block)
|
155
|
+
end
|
156
|
+
yield last_line
|
157
|
+
end
|
158
|
+
|
126
159
|
end
|
127
160
|
end
|