zxcvbn-ruby 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. data/.gitignore +18 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +3 -0
  4. data/LICENSE +22 -0
  5. data/README.md +23 -0
  6. data/Rakefile +18 -0
  7. data/data/adjacency_graphs.json +9 -0
  8. data/data/frequency_lists.yaml +85094 -0
  9. data/lib/zxcvbn.rb +37 -0
  10. data/lib/zxcvbn/crack_time.rb +51 -0
  11. data/lib/zxcvbn/dictionary_ranker.rb +23 -0
  12. data/lib/zxcvbn/entropy.rb +151 -0
  13. data/lib/zxcvbn/match.rb +13 -0
  14. data/lib/zxcvbn/matchers/date.rb +134 -0
  15. data/lib/zxcvbn/matchers/dictionary.rb +34 -0
  16. data/lib/zxcvbn/matchers/digits.rb +18 -0
  17. data/lib/zxcvbn/matchers/l33t.rb +127 -0
  18. data/lib/zxcvbn/matchers/new_l33t.rb +120 -0
  19. data/lib/zxcvbn/matchers/regex_helpers.rb +21 -0
  20. data/lib/zxcvbn/matchers/repeat.rb +32 -0
  21. data/lib/zxcvbn/matchers/sequences.rb +64 -0
  22. data/lib/zxcvbn/matchers/spatial.rb +79 -0
  23. data/lib/zxcvbn/matchers/year.rb +18 -0
  24. data/lib/zxcvbn/math.rb +63 -0
  25. data/lib/zxcvbn/omnimatch.rb +49 -0
  26. data/lib/zxcvbn/password_strength.rb +21 -0
  27. data/lib/zxcvbn/score.rb +15 -0
  28. data/lib/zxcvbn/scorer.rb +84 -0
  29. data/lib/zxcvbn/version.rb +3 -0
  30. data/spec/matchers/date_spec.rb +109 -0
  31. data/spec/matchers/dictionary_spec.rb +14 -0
  32. data/spec/matchers/digits_spec.rb +15 -0
  33. data/spec/matchers/l33t_spec.rb +85 -0
  34. data/spec/matchers/repeat_spec.rb +18 -0
  35. data/spec/matchers/sequences_spec.rb +16 -0
  36. data/spec/matchers/spatial_spec.rb +20 -0
  37. data/spec/matchers/year_spec.rb +15 -0
  38. data/spec/omnimatch_spec.rb +24 -0
  39. data/spec/scorer_spec.rb +5 -0
  40. data/spec/scoring/crack_time_spec.rb +106 -0
  41. data/spec/scoring/entropy_spec.rb +213 -0
  42. data/spec/scoring/math_spec.rb +131 -0
  43. data/spec/spec_helper.rb +54 -0
  44. data/spec/support/js_helpers.rb +35 -0
  45. data/spec/support/js_source/adjacency_graphs.js +8 -0
  46. data/spec/support/js_source/compiled.js +1188 -0
  47. data/spec/support/js_source/frequency_lists.js +10 -0
  48. data/spec/support/js_source/init.coffee +63 -0
  49. data/spec/support/js_source/init.js +95 -0
  50. data/spec/support/js_source/matching.coffee +444 -0
  51. data/spec/support/js_source/matching.js +685 -0
  52. data/spec/support/js_source/scoring.coffee +270 -0
  53. data/spec/support/js_source/scoring.js +390 -0
  54. data/spec/support/matcher.rb +35 -0
  55. data/spec/zxcvbn_spec.rb +49 -0
  56. data/zxcvbn-ruby.gemspec +20 -0
  57. metadata +167 -0
@@ -0,0 +1,685 @@
1
+ // Generated by CoffeeScript 1.3.3
2
+ var SEQUENCES, build_dict_matcher, build_ranked_dict, check_date, date_match, date_rx_year_prefix, date_rx_year_suffix, date_sep_match, date_without_sep_match, dictionary_match, digits_match, digits_rx, empty, enumerate_l33t_subs, extend, findall, l33t_match, l33t_table, omnimatch, relevent_l33t_subtable, repeat, repeat_match, sequence_match, spatial_match, spatial_match_helper, translate, year_match, year_rx;
3
+
4
+ empty = function(obj) {
5
+ var k;
6
+ return ((function() {
7
+ var _results;
8
+ _results = [];
9
+ for (k in obj) {
10
+ _results.push(k);
11
+ }
12
+ return _results;
13
+ })()).length === 0;
14
+ };
15
+
16
+ extend = function(lst, lst2) {
17
+ return lst.push.apply(lst, lst2);
18
+ };
19
+
20
+ translate = function(string, chr_map) {
21
+ var chr;
22
+ return ((function() {
23
+ var _i, _len, _ref, _results;
24
+ _ref = string.split('');
25
+ _results = [];
26
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
27
+ chr = _ref[_i];
28
+ _results.push(chr_map[chr] || chr);
29
+ }
30
+ return _results;
31
+ })()).join('');
32
+ };
33
+
34
+ omnimatch = function(password) {
35
+ var matcher, matches, _i, _len;
36
+ matches = [];
37
+ for (_i = 0, _len = MATCHERS.length; _i < _len; _i++) {
38
+ matcher = MATCHERS[_i];
39
+ extend(matches, matcher(password));
40
+ }
41
+ return matches.sort(function(match1, match2) {
42
+ return (match1.i - match2.i) || (match1.j - match2.j);
43
+ });
44
+ };
45
+
46
+ dictionary_match = function(password, ranked_dict) {
47
+ var i, j, len, password_lower, rank, result, word, _i, _j;
48
+ result = [];
49
+ len = password.length;
50
+ password_lower = password.toLowerCase();
51
+ for (i = _i = 0; 0 <= len ? _i < len : _i > len; i = 0 <= len ? ++_i : --_i) {
52
+ for (j = _j = i; i <= len ? _j < len : _j > len; j = i <= len ? ++_j : --_j) {
53
+ if (password_lower.slice(i, j + 1 || 9e9) in ranked_dict) {
54
+ word = password_lower.slice(i, j + 1 || 9e9);
55
+ rank = ranked_dict[word];
56
+ result.push({
57
+ pattern: 'dictionary',
58
+ i: i,
59
+ j: j,
60
+ token: password.slice(i, j + 1 || 9e9),
61
+ matched_word: word,
62
+ rank: rank
63
+ });
64
+ }
65
+ }
66
+ }
67
+ return result;
68
+ };
69
+
70
+ build_ranked_dict = function(unranked_list) {
71
+ var i, result, word, _i, _len;
72
+ result = {};
73
+ i = 1;
74
+ for (_i = 0, _len = unranked_list.length; _i < _len; _i++) {
75
+ word = unranked_list[_i];
76
+ result[word] = i;
77
+ i += 1;
78
+ }
79
+ return result;
80
+ };
81
+
82
+ build_dict_matcher = function(dict_name, ranked_dict) {
83
+ return function(password) {
84
+ var match, matches, _i, _len;
85
+ matches = dictionary_match(password, ranked_dict);
86
+ for (_i = 0, _len = matches.length; _i < _len; _i++) {
87
+ match = matches[_i];
88
+ match.dictionary_name = dict_name;
89
+ }
90
+ return matches;
91
+ };
92
+ };
93
+
94
+ l33t_table = {
95
+ a: ['4', '@'],
96
+ b: ['8'],
97
+ c: ['(', '{', '[', '<'],
98
+ e: ['3'],
99
+ g: ['6', '9'],
100
+ i: ['1', '!', '|'],
101
+ l: ['1', '|', '7'],
102
+ o: ['0'],
103
+ s: ['$', '5'],
104
+ t: ['+', '7'],
105
+ x: ['%'],
106
+ z: ['2']
107
+ };
108
+
109
+ relevent_l33t_subtable = function(password) {
110
+ var chr, filtered, letter, password_chars, relevent_subs, sub, subs, _i, _len, _ref;
111
+ password_chars = {};
112
+ _ref = password.split('');
113
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
114
+ chr = _ref[_i];
115
+ password_chars[chr] = true;
116
+ }
117
+ filtered = {};
118
+ for (letter in l33t_table) {
119
+ subs = l33t_table[letter];
120
+ relevent_subs = (function() {
121
+ var _j, _len1, _results;
122
+ _results = [];
123
+ for (_j = 0, _len1 = subs.length; _j < _len1; _j++) {
124
+ sub = subs[_j];
125
+ if (sub in password_chars) {
126
+ _results.push(sub);
127
+ }
128
+ }
129
+ return _results;
130
+ })();
131
+ if (relevent_subs.length > 0) {
132
+ filtered[letter] = relevent_subs;
133
+ }
134
+ }
135
+ return filtered;
136
+ };
137
+
138
+ enumerate_l33t_subs = function(table) {
139
+ var chr, dedup, helper, k, keys, l33t_chr, sub, sub_dict, sub_dicts, subs, _i, _j, _len, _len1, _ref;
140
+ keys = (function() {
141
+ var _results;
142
+ _results = [];
143
+ for (k in table) {
144
+ _results.push(k);
145
+ }
146
+ return _results;
147
+ })();
148
+ subs = [[]];
149
+ dedup = function(subs) {
150
+ var assoc, deduped, label, members, sub, v, _i, _len;
151
+ deduped = [];
152
+ members = {};
153
+ for (_i = 0, _len = subs.length; _i < _len; _i++) {
154
+ sub = subs[_i];
155
+ assoc = (function() {
156
+ var _j, _len1, _results;
157
+ _results = [];
158
+ for (v = _j = 0, _len1 = sub.length; _j < _len1; v = ++_j) {
159
+ k = sub[v];
160
+ _results.push([k, v]);
161
+ }
162
+ return _results;
163
+ })();
164
+ assoc.sort();
165
+ label = ((function() {
166
+ var _j, _len1, _results;
167
+ _results = [];
168
+ for (v = _j = 0, _len1 = assoc.length; _j < _len1; v = ++_j) {
169
+ k = assoc[v];
170
+ _results.push(k + ',' + v);
171
+ }
172
+ return _results;
173
+ })()).join('-');
174
+ if (!(label in members)) {
175
+ members[label] = true;
176
+ deduped.push(sub);
177
+ }
178
+ }
179
+ return deduped;
180
+ };
181
+ helper = function(keys) {
182
+ var dup_l33t_index, first_key, i, l33t_chr, next_subs, rest_keys, sub, sub_alternative, sub_extension, _i, _j, _k, _len, _len1, _ref, _ref1;
183
+ if (!keys.length) {
184
+ return;
185
+ }
186
+ first_key = keys[0];
187
+ rest_keys = keys.slice(1);
188
+ next_subs = [];
189
+ _ref = table[first_key];
190
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
191
+ l33t_chr = _ref[_i];
192
+ for (_j = 0, _len1 = subs.length; _j < _len1; _j++) {
193
+ sub = subs[_j];
194
+ dup_l33t_index = -1;
195
+ for (i = _k = 0, _ref1 = sub.length; 0 <= _ref1 ? _k < _ref1 : _k > _ref1; i = 0 <= _ref1 ? ++_k : --_k) {
196
+ if (sub[i][0] === l33t_chr) {
197
+ dup_l33t_index = i;
198
+ break;
199
+ }
200
+ }
201
+ if (dup_l33t_index === -1) {
202
+ sub_extension = sub.concat([[l33t_chr, first_key]]);
203
+ next_subs.push(sub_extension);
204
+ } else {
205
+ sub_alternative = sub.slice(0);
206
+ sub_alternative.splice(dup_l33t_index, 1);
207
+ sub_alternative.push([l33t_chr, first_key]);
208
+ next_subs.push(sub);
209
+ next_subs.push(sub_alternative);
210
+ }
211
+ }
212
+ }
213
+ subs = dedup(next_subs);
214
+ return helper(rest_keys);
215
+ };
216
+ helper(keys);
217
+ sub_dicts = [];
218
+ for (_i = 0, _len = subs.length; _i < _len; _i++) {
219
+ sub = subs[_i];
220
+ sub_dict = {};
221
+ for (_j = 0, _len1 = sub.length; _j < _len1; _j++) {
222
+ _ref = sub[_j], l33t_chr = _ref[0], chr = _ref[1];
223
+ sub_dict[l33t_chr] = chr;
224
+ }
225
+ sub_dicts.push(sub_dict);
226
+ }
227
+ return sub_dicts;
228
+ };
229
+
230
+ l33t_match = function(password) {
231
+ var chr, k, match, match_sub, matcher, matches, sub, subbed_chr, subbed_password, token, v, _i, _j, _k, _len, _len1, _len2, _ref, _ref1;
232
+ matches = [];
233
+ _ref = enumerate_l33t_subs(relevent_l33t_subtable(password));
234
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
235
+ sub = _ref[_i];
236
+ if (empty(sub)) {
237
+ break;
238
+ }
239
+ for (_j = 0, _len1 = DICTIONARY_MATCHERS.length; _j < _len1; _j++) {
240
+ matcher = DICTIONARY_MATCHERS[_j];
241
+ subbed_password = translate(password, sub);
242
+ _ref1 = matcher(subbed_password);
243
+ for (_k = 0, _len2 = _ref1.length; _k < _len2; _k++) {
244
+ match = _ref1[_k];
245
+ token = password.slice(match.i, match.j + 1 || 9e9);
246
+ if (token.toLowerCase() === match.matched_word) {
247
+ continue;
248
+ }
249
+ match_sub = {};
250
+ for (subbed_chr in sub) {
251
+ chr = sub[subbed_chr];
252
+ if (token.indexOf(subbed_chr) !== -1) {
253
+ match_sub[subbed_chr] = chr;
254
+ }
255
+ }
256
+ match.l33t = true;
257
+ match.token = token;
258
+ match.sub = match_sub;
259
+ match.sub_display = ((function() {
260
+ var _results;
261
+ _results = [];
262
+ for (k in match_sub) {
263
+ v = match_sub[k];
264
+ _results.push("" + k + " -> " + v);
265
+ }
266
+ return _results;
267
+ })()).join(', ');
268
+ matches.push(match);
269
+ }
270
+ }
271
+ }
272
+ return matches;
273
+ };
274
+
275
+ spatial_match = function(password) {
276
+ var graph, graph_name, matches;
277
+ matches = [];
278
+ for (graph_name in GRAPHS) {
279
+ graph = GRAPHS[graph_name];
280
+ extend(matches, spatial_match_helper(password, graph, graph_name));
281
+ }
282
+ return matches;
283
+ };
284
+
285
+ spatial_match_helper = function(password, graph, graph_name) {
286
+ var adj, adjacents, cur_char, cur_direction, found, found_direction, i, j, last_direction, prev_char, result, shifted_count, turns, _i, _len;
287
+ result = [];
288
+ i = 0;
289
+ while (i < password.length - 1) {
290
+ j = i + 1;
291
+ last_direction = null;
292
+ turns = 0;
293
+ shifted_count = 0;
294
+ while (true) {
295
+ prev_char = password.charAt(j - 1);
296
+ found = false;
297
+ found_direction = -1;
298
+ cur_direction = -1;
299
+ adjacents = graph[prev_char] || [];
300
+ if (j < password.length) {
301
+ cur_char = password.charAt(j);
302
+ for (_i = 0, _len = adjacents.length; _i < _len; _i++) {
303
+ adj = adjacents[_i];
304
+ cur_direction += 1;
305
+ if (adj && adj.indexOf(cur_char) !== -1) {
306
+ found = true;
307
+ found_direction = cur_direction;
308
+ if (adj.indexOf(cur_char) === 1) {
309
+ shifted_count += 1;
310
+ }
311
+ if (last_direction !== found_direction) {
312
+ turns += 1;
313
+ last_direction = found_direction;
314
+ }
315
+ break;
316
+ }
317
+ }
318
+ }
319
+ if (found) {
320
+ j += 1;
321
+ } else {
322
+ if (j - i > 2) {
323
+ result.push({
324
+ pattern: 'spatial',
325
+ i: i,
326
+ j: j - 1,
327
+ token: password.slice(i, j),
328
+ graph: graph_name,
329
+ turns: turns,
330
+ shifted_count: shifted_count
331
+ });
332
+ }
333
+ i = j;
334
+ break;
335
+ }
336
+ }
337
+ }
338
+ return result;
339
+ };
340
+
341
+ repeat_match = function(password) {
342
+ var cur_char, i, j, prev_char, result, _ref;
343
+ result = [];
344
+ i = 0;
345
+ while (i < password.length) {
346
+ j = i + 1;
347
+ while (true) {
348
+ _ref = password.slice(j - 1, j + 1 || 9e9), prev_char = _ref[0], cur_char = _ref[1];
349
+ if (password.charAt(j - 1) === password.charAt(j)) {
350
+ j += 1;
351
+ } else {
352
+ if (j - i > 2) {
353
+ result.push({
354
+ pattern: 'repeat',
355
+ i: i,
356
+ j: j - 1,
357
+ token: password.slice(i, j),
358
+ repeated_char: password.charAt(i)
359
+ });
360
+ }
361
+ break;
362
+ }
363
+ }
364
+ i = j;
365
+ }
366
+ return result;
367
+ };
368
+
369
+ SEQUENCES = {
370
+ lower: 'abcdefghijklmnopqrstuvwxyz',
371
+ upper: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
372
+ digits: '01234567890'
373
+ };
374
+
375
+ sequence_match = function(password) {
376
+ var chr, cur_char, cur_n, direction, i, i_n, j, j_n, prev_char, prev_n, result, seq, seq_candidate, seq_candidate_name, seq_direction, seq_name, _ref, _ref1, _ref2;
377
+ result = [];
378
+ i = 0;
379
+ while (i < password.length) {
380
+ j = i + 1;
381
+ seq = null;
382
+ seq_name = null;
383
+ seq_direction = null;
384
+ for (seq_candidate_name in SEQUENCES) {
385
+ seq_candidate = SEQUENCES[seq_candidate_name];
386
+ _ref = (function() {
387
+ var _i, _len, _ref, _results;
388
+ _ref = [password.charAt(i), password.charAt(j)];
389
+ _results = [];
390
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
391
+ chr = _ref[_i];
392
+ _results.push(seq_candidate.indexOf(chr));
393
+ }
394
+ return _results;
395
+ })(), i_n = _ref[0], j_n = _ref[1];
396
+ if (i_n > -1 && j_n > -1) {
397
+ direction = j_n - i_n;
398
+ if (direction === 1 || direction === (-1)) {
399
+ seq = seq_candidate;
400
+ seq_name = seq_candidate_name;
401
+ seq_direction = direction;
402
+ break;
403
+ }
404
+ }
405
+ }
406
+ if (seq) {
407
+ while (true) {
408
+ _ref1 = password.slice(j - 1, j + 1 || 9e9), prev_char = _ref1[0], cur_char = _ref1[1];
409
+ _ref2 = (function() {
410
+ var _i, _len, _ref2, _results;
411
+ _ref2 = [prev_char, cur_char];
412
+ _results = [];
413
+ for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
414
+ chr = _ref2[_i];
415
+ _results.push(seq_candidate.indexOf(chr));
416
+ }
417
+ return _results;
418
+ })(), prev_n = _ref2[0], cur_n = _ref2[1];
419
+ if (!!cur_n && (cur_n - prev_n === seq_direction)) {
420
+ j += 1;
421
+ } else {
422
+ if (j - i > 2) {
423
+ result.push({
424
+ pattern: 'sequence',
425
+ i: i,
426
+ j: j - 1,
427
+ token: password.slice(i, j),
428
+ sequence_name: seq_name,
429
+ sequence_space: seq.length,
430
+ ascending: seq_direction === 1
431
+ });
432
+ }
433
+ break;
434
+ }
435
+ }
436
+ }
437
+ i = j;
438
+ }
439
+ return result;
440
+ };
441
+
442
+ repeat = function(chr, n) {
443
+ var i;
444
+ return ((function() {
445
+ var _i, _results;
446
+ _results = [];
447
+ for (i = _i = 1; 1 <= n ? _i <= n : _i >= n; i = 1 <= n ? ++_i : --_i) {
448
+ _results.push(chr);
449
+ }
450
+ return _results;
451
+ })()).join('');
452
+ };
453
+
454
+ findall = function(password, rx) {
455
+ var match, matches;
456
+ matches = [];
457
+ while (true) {
458
+ match = password.match(rx);
459
+ if (!match) {
460
+ break;
461
+ }
462
+ match.i = match.index;
463
+ match.j = match.index + match[0].length - 1;
464
+ matches.push(match);
465
+ password = password.replace(match[0], repeat(' ', match[0].length));
466
+ }
467
+ return matches;
468
+ };
469
+
470
+ digits_rx = /\d{3,}/;
471
+
472
+ digits_match = function(password) {
473
+ var i, j, match, _i, _len, _ref, _ref1, _results;
474
+ _ref = findall(password, digits_rx);
475
+ _results = [];
476
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
477
+ match = _ref[_i];
478
+ _ref1 = [match.i, match.j], i = _ref1[0], j = _ref1[1];
479
+ _results.push({
480
+ pattern: 'digits',
481
+ i: i,
482
+ j: j,
483
+ token: password.slice(i, j + 1 || 9e9)
484
+ });
485
+ }
486
+ return _results;
487
+ };
488
+
489
+ year_rx = /19\d\d|200\d|201\d/;
490
+
491
+ year_match = function(password) {
492
+ var i, j, match, _i, _len, _ref, _ref1, _results;
493
+ _ref = findall(password, year_rx);
494
+ _results = [];
495
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
496
+ match = _ref[_i];
497
+ _ref1 = [match.i, match.j], i = _ref1[0], j = _ref1[1];
498
+ _results.push({
499
+ pattern: 'year',
500
+ i: i,
501
+ j: j,
502
+ token: password.slice(i, j + 1 || 9e9)
503
+ });
504
+ }
505
+ return _results;
506
+ };
507
+
508
+ date_match = function(password) {
509
+ return date_without_sep_match(password).concat(date_sep_match(password));
510
+ };
511
+
512
+ date_without_sep_match = function(password) {
513
+ var candidate, candidates_round_1, candidates_round_2, date_matches, day, digit_match, end, i, j, month, token, valid, year, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2, _ref3;
514
+ date_matches = [];
515
+ _ref = findall(password, /\d{4,8}/);
516
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
517
+ digit_match = _ref[_i];
518
+ _ref1 = [digit_match.i, digit_match.j], i = _ref1[0], j = _ref1[1];
519
+ token = password.slice(i, j + 1 || 9e9);
520
+ end = token.length;
521
+ candidates_round_1 = [];
522
+ if (token.length <= 6) {
523
+ candidates_round_1.push({
524
+ daymonth: token.slice(2),
525
+ year: token.slice(0, 2),
526
+ i: i,
527
+ j: j
528
+ });
529
+ candidates_round_1.push({
530
+ daymonth: token.slice(0, end - 2),
531
+ year: token.slice(end - 2),
532
+ i: i,
533
+ j: j
534
+ });
535
+ }
536
+ if (token.length >= 6) {
537
+ candidates_round_1.push({
538
+ daymonth: token.slice(4),
539
+ year: token.slice(0, 4),
540
+ i: i,
541
+ j: j
542
+ });
543
+ candidates_round_1.push({
544
+ daymonth: token.slice(0, end - 4),
545
+ year: token.slice(end - 4),
546
+ i: i,
547
+ j: j
548
+ });
549
+ }
550
+ candidates_round_2 = [];
551
+ for (_j = 0, _len1 = candidates_round_1.length; _j < _len1; _j++) {
552
+ candidate = candidates_round_1[_j];
553
+ switch (candidate.daymonth.length) {
554
+ case 2:
555
+ candidates_round_2.push({
556
+ day: candidate.daymonth[0],
557
+ month: candidate.daymonth[1],
558
+ year: candidate.year,
559
+ i: candidate.i,
560
+ j: candidate.j
561
+ });
562
+ break;
563
+ case 3:
564
+ candidates_round_2.push({
565
+ day: candidate.daymonth.slice(0, 2),
566
+ month: candidate.daymonth[2],
567
+ year: candidate.year,
568
+ i: candidate.i,
569
+ j: candidate.j
570
+ });
571
+ candidates_round_2.push({
572
+ day: candidate.daymonth[0],
573
+ month: candidate.daymonth.slice(1, 3),
574
+ year: candidate.year,
575
+ i: candidate.i,
576
+ j: candidate.j
577
+ });
578
+ break;
579
+ case 4:
580
+ candidates_round_2.push({
581
+ day: candidate.daymonth.slice(0, 2),
582
+ month: candidate.daymonth.slice(2, 4),
583
+ year: candidate.year,
584
+ i: candidate.i,
585
+ j: candidate.j
586
+ });
587
+ }
588
+ }
589
+ for (_k = 0, _len2 = candidates_round_2.length; _k < _len2; _k++) {
590
+ candidate = candidates_round_2[_k];
591
+ day = parseInt(candidate.day);
592
+ month = parseInt(candidate.month);
593
+ year = parseInt(candidate.year);
594
+ _ref2 = check_date(day, month, year), valid = _ref2[0], (_ref3 = _ref2[1], day = _ref3[0], month = _ref3[1], year = _ref3[2]);
595
+ if (!valid) {
596
+ continue;
597
+ }
598
+ date_matches.push({
599
+ pattern: 'date',
600
+ i: candidate.i,
601
+ j: candidate.j,
602
+ token: password.slice(i, j + 1 || 9e9),
603
+ separator: '',
604
+ day: day,
605
+ month: month,
606
+ year: year
607
+ });
608
+ }
609
+ }
610
+ return date_matches;
611
+ };
612
+
613
+ date_rx_year_suffix = /(\d{1,2})(\s|-|\/|\\|_|\.)(\d{1,2})\2(19\d{2}|200\d|201\d|\d{2})/;
614
+
615
+ date_rx_year_prefix = /(19\d{2}|200\d|201\d|\d{2})(\s|-|\/|\\|_|\.)(\d{1,2})\2(\d{1,2})/;
616
+
617
+ date_sep_match = function(password) {
618
+ var day, k, match, matches, month, valid, year, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2, _ref3, _ref4, _ref5, _results;
619
+ matches = [];
620
+ _ref = findall(password, date_rx_year_suffix);
621
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
622
+ match = _ref[_i];
623
+ _ref1 = (function() {
624
+ var _j, _len1, _ref1, _results;
625
+ _ref1 = [1, 3, 4];
626
+ _results = [];
627
+ for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
628
+ k = _ref1[_j];
629
+ _results.push(parseInt(match[k]));
630
+ }
631
+ return _results;
632
+ })(), match.day = _ref1[0], match.month = _ref1[1], match.year = _ref1[2];
633
+ match.sep = match[2];
634
+ matches.push(match);
635
+ }
636
+ _ref2 = findall(password, date_rx_year_prefix);
637
+ for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) {
638
+ match = _ref2[_j];
639
+ _ref3 = (function() {
640
+ var _k, _len2, _ref3, _results;
641
+ _ref3 = [4, 3, 1];
642
+ _results = [];
643
+ for (_k = 0, _len2 = _ref3.length; _k < _len2; _k++) {
644
+ k = _ref3[_k];
645
+ _results.push(parseInt(match[k]));
646
+ }
647
+ return _results;
648
+ })(), match.day = _ref3[0], match.month = _ref3[1], match.year = _ref3[2];
649
+ match.sep = match[2];
650
+ matches.push(match);
651
+ }
652
+ _results = [];
653
+ for (_k = 0, _len2 = matches.length; _k < _len2; _k++) {
654
+ match = matches[_k];
655
+ _ref4 = check_date(match.day, match.month, match.year), valid = _ref4[0], (_ref5 = _ref4[1], day = _ref5[0], month = _ref5[1], year = _ref5[2]);
656
+ if (!valid) {
657
+ continue;
658
+ }
659
+ _results.push({
660
+ pattern: 'date',
661
+ i: match.i,
662
+ j: match.j,
663
+ token: password.slice(match.i, match.j + 1 || 9e9),
664
+ separator: match.sep,
665
+ day: day,
666
+ month: month,
667
+ year: year
668
+ });
669
+ }
670
+ return _results;
671
+ };
672
+
673
+ check_date = function(day, month, year) {
674
+ var _ref;
675
+ if ((12 <= month && month <= 31) && day <= 12) {
676
+ _ref = [month, day], day = _ref[0], month = _ref[1];
677
+ }
678
+ if (day > 31 || month > 12) {
679
+ return [false, []];
680
+ }
681
+ if (!((1900 <= year && year <= 2019))) {
682
+ return [false, []];
683
+ }
684
+ return [true, [day, month, year]];
685
+ };