1 |
|
2 | var DATE_MAX_YEAR, DATE_MIN_YEAR, DATE_SPLITS, GRAPHS, L33T_TABLE, RANKED_DICTIONARIES, REGEXEN, SEQUENCES, adjacency_graphs, build_ranked_dict, frequency_lists, matching, scoring,
|
3 | indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
|
4 |
|
5 | frequency_lists = require('./frequency_lists');
|
6 |
|
7 | adjacency_graphs = require('./adjacency_graphs');
|
8 |
|
9 | scoring = require('./scoring');
|
10 |
|
11 | build_ranked_dict = function(ordered_list) {
|
12 | var i, len1, o, result, word;
|
13 | result = {};
|
14 | i = 1;
|
15 | for (o = 0, len1 = ordered_list.length; o < len1; o++) {
|
16 | word = ordered_list[o];
|
17 | result[word] = i;
|
18 | i += 1;
|
19 | }
|
20 | return result;
|
21 | };
|
22 |
|
23 | RANKED_DICTIONARIES = {
|
24 | passwords: build_ranked_dict(frequency_lists.passwords),
|
25 | english: build_ranked_dict(frequency_lists.english),
|
26 | surnames: build_ranked_dict(frequency_lists.surnames),
|
27 | male_names: build_ranked_dict(frequency_lists.male_names),
|
28 | female_names: build_ranked_dict(frequency_lists.female_names)
|
29 | };
|
30 |
|
31 | GRAPHS = {
|
32 | qwerty: adjacency_graphs.qwerty,
|
33 | dvorak: adjacency_graphs.dvorak,
|
34 | keypad: adjacency_graphs.keypad,
|
35 | mac_keypad: adjacency_graphs.mac_keypad
|
36 | };
|
37 |
|
38 | SEQUENCES = {
|
39 | lower: 'abcdefghijklmnopqrstuvwxyz',
|
40 | upper: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
|
41 | digits: '0123456789'
|
42 | };
|
43 |
|
44 | L33T_TABLE = {
|
45 | a: ['4', '@'],
|
46 | b: ['8'],
|
47 | c: ['(', '{', '[', '<'],
|
48 | e: ['3'],
|
49 | g: ['6', '9'],
|
50 | i: ['1', '!', '|'],
|
51 | l: ['1', '|', '7'],
|
52 | o: ['0'],
|
53 | s: ['$', '5'],
|
54 | t: ['+', '7'],
|
55 | x: ['%'],
|
56 | z: ['2']
|
57 | };
|
58 |
|
59 | REGEXEN = {
|
60 | recent_year: /19\d\d|200\d|201\d/g
|
61 | };
|
62 |
|
63 | DATE_MAX_YEAR = 2050;
|
64 |
|
65 | DATE_MIN_YEAR = 1000;
|
66 |
|
67 | DATE_SPLITS = {
|
68 | 4: [[1, 2], [2, 3]],
|
69 | 5: [[1, 3], [2, 3]],
|
70 | 6: [[1, 2], [2, 4], [4, 5]],
|
71 | 7: [[1, 3], [2, 3], [4, 5], [4, 6]],
|
72 | 8: [[2, 4], [4, 6]]
|
73 | };
|
74 |
|
75 | matching = {
|
76 | empty: function(obj) {
|
77 | var k;
|
78 | return ((function() {
|
79 | var results;
|
80 | results = [];
|
81 | for (k in obj) {
|
82 | results.push(k);
|
83 | }
|
84 | return results;
|
85 | })()).length === 0;
|
86 | },
|
87 | extend: function(lst, lst2) {
|
88 | return lst.push.apply(lst, lst2);
|
89 | },
|
90 | translate: function(string, chr_map) {
|
91 | var chr;
|
92 | return ((function() {
|
93 | var len1, o, ref, results;
|
94 | ref = string.split('');
|
95 | results = [];
|
96 | for (o = 0, len1 = ref.length; o < len1; o++) {
|
97 | chr = ref[o];
|
98 | results.push(chr_map[chr] || chr);
|
99 | }
|
100 | return results;
|
101 | })()).join('');
|
102 | },
|
103 | mod: function(n, m) {
|
104 | return ((n % m) + m) % m;
|
105 | },
|
106 | sorted: function(matches) {
|
107 | return matches.sort(function(m1, m2) {
|
108 | return (m1.i - m2.i) || (m1.j - m2.j);
|
109 | });
|
110 | },
|
111 | omnimatch: function(password) {
|
112 | var len1, matcher, matchers, matches, o;
|
113 | matches = [];
|
114 | matchers = [this.dictionary_match, this.reverse_dictionary_match, this.l33t_match, this.spatial_match, this.repeat_match, this.sequence_match, this.regex_match, this.date_match];
|
115 | for (o = 0, len1 = matchers.length; o < len1; o++) {
|
116 | matcher = matchers[o];
|
117 | this.extend(matches, matcher.call(this, password));
|
118 | }
|
119 | return this.sorted(matches);
|
120 | },
|
121 | dictionary_match: function(password, _ranked_dictionaries) {
|
122 | var dictionary_name, i, j, len, matches, o, p, password_lower, rank, ranked_dict, ref, ref1, ref2, word;
|
123 | if (_ranked_dictionaries == null) {
|
124 | _ranked_dictionaries = RANKED_DICTIONARIES;
|
125 | }
|
126 | matches = [];
|
127 | len = password.length;
|
128 | password_lower = password.toLowerCase();
|
129 | for (dictionary_name in _ranked_dictionaries) {
|
130 | ranked_dict = _ranked_dictionaries[dictionary_name];
|
131 | for (i = o = 0, ref = len; 0 <= ref ? o < ref : o > ref; i = 0 <= ref ? ++o : --o) {
|
132 | for (j = p = ref1 = i, ref2 = len; ref1 <= ref2 ? p < ref2 : p > ref2; j = ref1 <= ref2 ? ++p : --p) {
|
133 | if (password_lower.slice(i, +j + 1 || 9e9) in ranked_dict) {
|
134 | word = password_lower.slice(i, +j + 1 || 9e9);
|
135 | rank = ranked_dict[word];
|
136 | matches.push({
|
137 | pattern: 'dictionary',
|
138 | i: i,
|
139 | j: j,
|
140 | token: password.slice(i, +j + 1 || 9e9),
|
141 | matched_word: word,
|
142 | rank: rank,
|
143 | dictionary_name: dictionary_name,
|
144 | reversed: false,
|
145 | l33t: false
|
146 | });
|
147 | }
|
148 | }
|
149 | }
|
150 | }
|
151 | return this.sorted(matches);
|
152 | },
|
153 | reverse_dictionary_match: function(password, _ranked_dictionaries) {
|
154 | var len1, match, matches, o, ref, reversed_password;
|
155 | if (_ranked_dictionaries == null) {
|
156 | _ranked_dictionaries = RANKED_DICTIONARIES;
|
157 | }
|
158 | reversed_password = password.split('').reverse().join('');
|
159 | matches = this.dictionary_match(reversed_password, _ranked_dictionaries);
|
160 | for (o = 0, len1 = matches.length; o < len1; o++) {
|
161 | match = matches[o];
|
162 | match.token = match.token.split('').reverse().join('');
|
163 | match.reversed = true;
|
164 | ref = [password.length - 1 - match.j, password.length - 1 - match.i], match.i = ref[0], match.j = ref[1];
|
165 | }
|
166 | return this.sorted(matches);
|
167 | },
|
168 | set_user_input_dictionary: function(ordered_list) {
|
169 | return RANKED_DICTIONARIES['user_inputs'] = build_ranked_dict(ordered_list.slice());
|
170 | },
|
171 | relevant_l33t_subtable: function(password, table) {
|
172 | var chr, len1, letter, o, password_chars, ref, relevant_subs, sub, subs, subtable;
|
173 | password_chars = {};
|
174 | ref = password.split('');
|
175 | for (o = 0, len1 = ref.length; o < len1; o++) {
|
176 | chr = ref[o];
|
177 | password_chars[chr] = true;
|
178 | }
|
179 | subtable = {};
|
180 | for (letter in table) {
|
181 | subs = table[letter];
|
182 | relevant_subs = (function() {
|
183 | var len2, p, results;
|
184 | results = [];
|
185 | for (p = 0, len2 = subs.length; p < len2; p++) {
|
186 | sub = subs[p];
|
187 | if (sub in password_chars) {
|
188 | results.push(sub);
|
189 | }
|
190 | }
|
191 | return results;
|
192 | })();
|
193 | if (relevant_subs.length > 0) {
|
194 | subtable[letter] = relevant_subs;
|
195 | }
|
196 | }
|
197 | return subtable;
|
198 | },
|
199 | enumerate_l33t_subs: function(table) {
|
200 | var chr, dedup, helper, k, keys, l33t_chr, len1, len2, o, p, ref, sub, sub_dict, sub_dicts, subs;
|
201 | keys = (function() {
|
202 | var results;
|
203 | results = [];
|
204 | for (k in table) {
|
205 | results.push(k);
|
206 | }
|
207 | return results;
|
208 | })();
|
209 | subs = [[]];
|
210 | dedup = function(subs) {
|
211 | var assoc, deduped, label, len1, members, o, sub, v;
|
212 | deduped = [];
|
213 | members = {};
|
214 | for (o = 0, len1 = subs.length; o < len1; o++) {
|
215 | sub = subs[o];
|
216 | assoc = (function() {
|
217 | var len2, p, results;
|
218 | results = [];
|
219 | for (v = p = 0, len2 = sub.length; p < len2; v = ++p) {
|
220 | k = sub[v];
|
221 | results.push([k, v]);
|
222 | }
|
223 | return results;
|
224 | })();
|
225 | assoc.sort();
|
226 | label = ((function() {
|
227 | var len2, p, results;
|
228 | results = [];
|
229 | for (v = p = 0, len2 = assoc.length; p < len2; v = ++p) {
|
230 | k = assoc[v];
|
231 | results.push(k + ',' + v);
|
232 | }
|
233 | return results;
|
234 | })()).join('-');
|
235 | if (!(label in members)) {
|
236 | members[label] = true;
|
237 | deduped.push(sub);
|
238 | }
|
239 | }
|
240 | return deduped;
|
241 | };
|
242 | helper = function(keys) {
|
243 | var dup_l33t_index, first_key, i, l33t_chr, len1, len2, next_subs, o, p, q, ref, ref1, rest_keys, sub, sub_alternative, sub_extension;
|
244 | if (!keys.length) {
|
245 | return;
|
246 | }
|
247 | first_key = keys[0];
|
248 | rest_keys = keys.slice(1);
|
249 | next_subs = [];
|
250 | ref = table[first_key];
|
251 | for (o = 0, len1 = ref.length; o < len1; o++) {
|
252 | l33t_chr = ref[o];
|
253 | for (p = 0, len2 = subs.length; p < len2; p++) {
|
254 | sub = subs[p];
|
255 | dup_l33t_index = -1;
|
256 | for (i = q = 0, ref1 = sub.length; 0 <= ref1 ? q < ref1 : q > ref1; i = 0 <= ref1 ? ++q : --q) {
|
257 | if (sub[i][0] === l33t_chr) {
|
258 | dup_l33t_index = i;
|
259 | break;
|
260 | }
|
261 | }
|
262 | if (dup_l33t_index === -1) {
|
263 | sub_extension = sub.concat([[l33t_chr, first_key]]);
|
264 | next_subs.push(sub_extension);
|
265 | } else {
|
266 | sub_alternative = sub.slice(0);
|
267 | sub_alternative.splice(dup_l33t_index, 1);
|
268 | sub_alternative.push([l33t_chr, first_key]);
|
269 | next_subs.push(sub);
|
270 | next_subs.push(sub_alternative);
|
271 | }
|
272 | }
|
273 | }
|
274 | subs = dedup(next_subs);
|
275 | return helper(rest_keys);
|
276 | };
|
277 | helper(keys);
|
278 | sub_dicts = [];
|
279 | for (o = 0, len1 = subs.length; o < len1; o++) {
|
280 | sub = subs[o];
|
281 | sub_dict = {};
|
282 | for (p = 0, len2 = sub.length; p < len2; p++) {
|
283 | ref = sub[p], l33t_chr = ref[0], chr = ref[1];
|
284 | sub_dict[l33t_chr] = chr;
|
285 | }
|
286 | sub_dicts.push(sub_dict);
|
287 | }
|
288 | return sub_dicts;
|
289 | },
|
290 | l33t_match: function(password, _ranked_dictionaries, _l33t_table) {
|
291 | var chr, k, len1, len2, match, match_sub, matches, o, p, ref, ref1, sub, subbed_chr, subbed_password, token, v;
|
292 | if (_ranked_dictionaries == null) {
|
293 | _ranked_dictionaries = RANKED_DICTIONARIES;
|
294 | }
|
295 | if (_l33t_table == null) {
|
296 | _l33t_table = L33T_TABLE;
|
297 | }
|
298 | matches = [];
|
299 | ref = this.enumerate_l33t_subs(this.relevant_l33t_subtable(password, _l33t_table));
|
300 | for (o = 0, len1 = ref.length; o < len1; o++) {
|
301 | sub = ref[o];
|
302 | if (this.empty(sub)) {
|
303 | break;
|
304 | }
|
305 | subbed_password = this.translate(password, sub);
|
306 | ref1 = this.dictionary_match(subbed_password, _ranked_dictionaries);
|
307 | for (p = 0, len2 = ref1.length; p < len2; p++) {
|
308 | match = ref1[p];
|
309 | token = password.slice(match.i, +match.j + 1 || 9e9);
|
310 | if (token.toLowerCase() === match.matched_word) {
|
311 | continue;
|
312 | }
|
313 | match_sub = {};
|
314 | for (subbed_chr in sub) {
|
315 | chr = sub[subbed_chr];
|
316 | if (token.indexOf(subbed_chr) !== -1) {
|
317 | match_sub[subbed_chr] = chr;
|
318 | }
|
319 | }
|
320 | match.l33t = true;
|
321 | match.token = token;
|
322 | match.sub = match_sub;
|
323 | match.sub_display = ((function() {
|
324 | var results;
|
325 | results = [];
|
326 | for (k in match_sub) {
|
327 | v = match_sub[k];
|
328 | results.push(k + " -> " + v);
|
329 | }
|
330 | return results;
|
331 | })()).join(', ');
|
332 | matches.push(match);
|
333 | }
|
334 | }
|
335 | return this.sorted(matches.filter(function(match) {
|
336 | return match.token.length > 1;
|
337 | }));
|
338 | },
|
339 | spatial_match: function(password, _graphs) {
|
340 | var graph, graph_name, matches;
|
341 | if (_graphs == null) {
|
342 | _graphs = GRAPHS;
|
343 | }
|
344 | matches = [];
|
345 | for (graph_name in _graphs) {
|
346 | graph = _graphs[graph_name];
|
347 | this.extend(matches, this.spatial_match_helper(password, graph, graph_name));
|
348 | }
|
349 | return this.sorted(matches);
|
350 | },
|
351 | SHIFTED_RX: /[~!@#$%^&*()_+QWERTYUIOP{}|ASDFGHJKL:"ZXCVBNM<>?]/,
|
352 | spatial_match_helper: function(password, graph, graph_name) {
|
353 | var adj, adjacents, cur_char, cur_direction, found, found_direction, i, j, last_direction, len1, matches, o, prev_char, shifted_count, turns;
|
354 | matches = [];
|
355 | i = 0;
|
356 | while (i < password.length - 1) {
|
357 | j = i + 1;
|
358 | last_direction = null;
|
359 | turns = 0;
|
360 | if ((graph_name === 'qwerty' || graph_name === 'dvorak') && this.SHIFTED_RX.exec(password.charAt(i))) {
|
361 | shifted_count = 1;
|
362 | } else {
|
363 | shifted_count = 0;
|
364 | }
|
365 | while (true) {
|
366 | prev_char = password.charAt(j - 1);
|
367 | found = false;
|
368 | found_direction = -1;
|
369 | cur_direction = -1;
|
370 | adjacents = graph[prev_char] || [];
|
371 | if (j < password.length) {
|
372 | cur_char = password.charAt(j);
|
373 | for (o = 0, len1 = adjacents.length; o < len1; o++) {
|
374 | adj = adjacents[o];
|
375 | cur_direction += 1;
|
376 | if (adj && adj.indexOf(cur_char) !== -1) {
|
377 | found = true;
|
378 | found_direction = cur_direction;
|
379 | if (adj.indexOf(cur_char) === 1) {
|
380 | shifted_count += 1;
|
381 | }
|
382 | if (last_direction !== found_direction) {
|
383 | turns += 1;
|
384 | last_direction = found_direction;
|
385 | }
|
386 | break;
|
387 | }
|
388 | }
|
389 | }
|
390 | if (found) {
|
391 | j += 1;
|
392 | } else {
|
393 | if (j - i > 2) {
|
394 | matches.push({
|
395 | pattern: 'spatial',
|
396 | i: i,
|
397 | j: j - 1,
|
398 | token: password.slice(i, j),
|
399 | graph: graph_name,
|
400 | turns: turns,
|
401 | shifted_count: shifted_count
|
402 | });
|
403 | }
|
404 | i = j;
|
405 | break;
|
406 | }
|
407 | }
|
408 | }
|
409 | return matches;
|
410 | },
|
411 | repeat_match: function(password) {
|
412 | var base_analysis, base_guesses, base_matches, base_token, greedy, greedy_match, i, j, lastIndex, lazy, lazy_anchored, lazy_match, match, matches, ref;
|
413 | matches = [];
|
414 | greedy = /(.+)\1+/g;
|
415 | lazy = /(.+?)\1+/g;
|
416 | lazy_anchored = /^(.+?)\1+$/;
|
417 | lastIndex = 0;
|
418 | while (lastIndex < password.length) {
|
419 | greedy.lastIndex = lazy.lastIndex = lastIndex;
|
420 | greedy_match = greedy.exec(password);
|
421 | lazy_match = lazy.exec(password);
|
422 | if (greedy_match == null) {
|
423 | break;
|
424 | }
|
425 | if (greedy_match[0].length > lazy_match[0].length) {
|
426 | match = greedy_match;
|
427 | base_token = lazy_anchored.exec(match[0])[1];
|
428 | } else {
|
429 | match = lazy_match;
|
430 | base_token = match[1];
|
431 | }
|
432 | ref = [match.index, match.index + match[0].length - 1], i = ref[0], j = ref[1];
|
433 | base_analysis = scoring.most_guessable_match_sequence(base_token, this.omnimatch(base_token));
|
434 | base_matches = base_analysis.match_sequence;
|
435 | base_guesses = base_analysis.guesses;
|
436 | matches.push({
|
437 | pattern: 'repeat',
|
438 | i: i,
|
439 | j: j,
|
440 | token: match[0],
|
441 | base_token: base_token,
|
442 | base_guesses: base_guesses,
|
443 | base_matches: base_matches,
|
444 | repeat_count: match[0].length / base_token.length
|
445 | });
|
446 | lastIndex = j + 1;
|
447 | }
|
448 | return matches;
|
449 | },
|
450 | sequence_match: function(password) {
|
451 | var direction, i, j, len1, matches, next_sequence_position, o, ref, ref1, sequence, sequence_name, sequence_position;
|
452 | matches = [];
|
453 | for (sequence_name in SEQUENCES) {
|
454 | sequence = SEQUENCES[sequence_name];
|
455 | ref = [1, -1];
|
456 | for (o = 0, len1 = ref.length; o < len1; o++) {
|
457 | direction = ref[o];
|
458 | i = 0;
|
459 | while (i < password.length) {
|
460 | if (ref1 = password.charAt(i), indexOf.call(sequence, ref1) < 0) {
|
461 | i += 1;
|
462 | continue;
|
463 | }
|
464 | j = i + 1;
|
465 | sequence_position = sequence.indexOf(password.charAt(i));
|
466 | while (j < password.length) {
|
467 | next_sequence_position = this.mod(sequence_position + direction, sequence.length);
|
468 | if (sequence.indexOf(password.charAt(j)) !== next_sequence_position) {
|
469 | break;
|
470 | }
|
471 | j += 1;
|
472 | sequence_position = next_sequence_position;
|
473 | }
|
474 | j -= 1;
|
475 | if (j - i + 1 > 1) {
|
476 | matches.push({
|
477 | pattern: 'sequence',
|
478 | i: i,
|
479 | j: j,
|
480 | token: password.slice(i, +j + 1 || 9e9),
|
481 | sequence_name: sequence_name,
|
482 | sequence_space: sequence.length,
|
483 | ascending: direction === 1
|
484 | });
|
485 | }
|
486 | i = j + 1;
|
487 | }
|
488 | }
|
489 | }
|
490 | return this.sorted(matches);
|
491 | },
|
492 | regex_match: function(password, _regexen) {
|
493 | var matches, name, regex, rx_match, token;
|
494 | if (_regexen == null) {
|
495 | _regexen = REGEXEN;
|
496 | }
|
497 | matches = [];
|
498 | for (name in _regexen) {
|
499 | regex = _regexen[name];
|
500 | regex.lastIndex = 0;
|
501 | while (rx_match = regex.exec(password)) {
|
502 | token = rx_match[0];
|
503 | matches.push({
|
504 | pattern: 'regex',
|
505 | token: token,
|
506 | i: rx_match.index,
|
507 | j: rx_match.index + rx_match[0].length - 1,
|
508 | regex_name: name,
|
509 | regex_match: rx_match
|
510 | });
|
511 | }
|
512 | }
|
513 | return this.sorted(matches);
|
514 | },
|
515 | date_match: function(password) {
|
516 | var best_candidate, candidate, candidates, distance, dmy, i, j, k, l, len1, len2, matches, maybe_date_no_separator, maybe_date_with_separator, metric, min_distance, o, p, q, r, ref, ref1, ref2, ref3, ref4, ref5, ref6, ref7, ref8, ref9, rx_match, s, t, token;
|
517 | matches = [];
|
518 | maybe_date_no_separator = /^\d{4,8}$/;
|
519 | maybe_date_with_separator = /^(\d{1,4})([\s\/\\_.-])(\d{1,2})\2(\d{1,4})$/;
|
520 | for (i = o = 0, ref = password.length - 4; 0 <= ref ? o <= ref : o >= ref; i = 0 <= ref ? ++o : --o) {
|
521 | for (j = p = ref1 = i + 3, ref2 = i + 7; ref1 <= ref2 ? p <= ref2 : p >= ref2; j = ref1 <= ref2 ? ++p : --p) {
|
522 | if (j >= password.length) {
|
523 | break;
|
524 | }
|
525 | token = password.slice(i, +j + 1 || 9e9);
|
526 | if (!maybe_date_no_separator.exec(token)) {
|
527 | continue;
|
528 | }
|
529 | candidates = [];
|
530 | ref3 = DATE_SPLITS[token.length];
|
531 | for (q = 0, len1 = ref3.length; q < len1; q++) {
|
532 | ref4 = ref3[q], k = ref4[0], l = ref4[1];
|
533 | dmy = this.map_ints_to_dmy([parseInt(token.slice(0, k)), parseInt(token.slice(k, l)), parseInt(token.slice(l))]);
|
534 | if (dmy != null) {
|
535 | candidates.push(dmy);
|
536 | }
|
537 | }
|
538 | if (!(candidates.length > 0)) {
|
539 | continue;
|
540 | }
|
541 | best_candidate = candidates[0];
|
542 | metric = function(candidate) {
|
543 | return Math.abs(candidate.year - scoring.REFERENCE_YEAR);
|
544 | };
|
545 | min_distance = metric(candidates[0]);
|
546 | ref5 = candidates.slice(1);
|
547 | for (r = 0, len2 = ref5.length; r < len2; r++) {
|
548 | candidate = ref5[r];
|
549 | distance = metric(candidate);
|
550 | if (distance < min_distance) {
|
551 | ref6 = [candidate, distance], best_candidate = ref6[0], min_distance = ref6[1];
|
552 | }
|
553 | }
|
554 | matches.push({
|
555 | pattern: 'date',
|
556 | token: token,
|
557 | i: i,
|
558 | j: j,
|
559 | separator: '',
|
560 | year: best_candidate.year,
|
561 | month: best_candidate.month,
|
562 | day: best_candidate.day
|
563 | });
|
564 | }
|
565 | }
|
566 | for (i = s = 0, ref7 = password.length - 6; 0 <= ref7 ? s <= ref7 : s >= ref7; i = 0 <= ref7 ? ++s : --s) {
|
567 | for (j = t = ref8 = i + 5, ref9 = i + 9; ref8 <= ref9 ? t <= ref9 : t >= ref9; j = ref8 <= ref9 ? ++t : --t) {
|
568 | if (j >= password.length) {
|
569 | break;
|
570 | }
|
571 | token = password.slice(i, +j + 1 || 9e9);
|
572 | rx_match = maybe_date_with_separator.exec(token);
|
573 | if (rx_match == null) {
|
574 | continue;
|
575 | }
|
576 | dmy = this.map_ints_to_dmy([parseInt(rx_match[1]), parseInt(rx_match[3]), parseInt(rx_match[4])]);
|
577 | if (dmy == null) {
|
578 | continue;
|
579 | }
|
580 | matches.push({
|
581 | pattern: 'date',
|
582 | token: token,
|
583 | i: i,
|
584 | j: j,
|
585 | separator: rx_match[2],
|
586 | year: dmy.year,
|
587 | month: dmy.month,
|
588 | day: dmy.day
|
589 | });
|
590 | }
|
591 | }
|
592 | return this.sorted(matches.filter(function(match) {
|
593 | var is_submatch, len3, other_match, u;
|
594 | is_submatch = false;
|
595 | for (u = 0, len3 = matches.length; u < len3; u++) {
|
596 | other_match = matches[u];
|
597 | if (match === other_match) {
|
598 | continue;
|
599 | }
|
600 | if (other_match.i <= match.i && other_match.j >= match.j) {
|
601 | is_submatch = true;
|
602 | break;
|
603 | }
|
604 | }
|
605 | return !is_submatch;
|
606 | }));
|
607 | },
|
608 | map_ints_to_dmy: function(ints) {
|
609 | var dm, int, len1, len2, len3, o, over_12, over_31, p, possible_year_splits, q, ref, ref1, rest, under_1, y;
|
610 | if (ints[1] > 31 || ints[1] <= 0) {
|
611 | return;
|
612 | }
|
613 | over_12 = 0;
|
614 | over_31 = 0;
|
615 | under_1 = 0;
|
616 | for (o = 0, len1 = ints.length; o < len1; o++) {
|
617 | int = ints[o];
|
618 | if ((99 < int && int < DATE_MIN_YEAR) || int > DATE_MAX_YEAR) {
|
619 | return;
|
620 | }
|
621 | if (int > 31) {
|
622 | over_31 += 1;
|
623 | }
|
624 | if (int > 12) {
|
625 | over_12 += 1;
|
626 | }
|
627 | if (int <= 0) {
|
628 | under_1 += 1;
|
629 | }
|
630 | }
|
631 | if (over_31 >= 2 || over_12 === 3 || under_1 >= 2) {
|
632 | return;
|
633 | }
|
634 | possible_year_splits = [[ints[2], ints.slice(0, 2)], [ints[0], ints.slice(1, 3)]];
|
635 | for (p = 0, len2 = possible_year_splits.length; p < len2; p++) {
|
636 | ref = possible_year_splits[p], y = ref[0], rest = ref[1];
|
637 | if ((DATE_MIN_YEAR <= y && y <= DATE_MAX_YEAR)) {
|
638 | dm = this.map_ints_to_dm(rest);
|
639 | if (dm != null) {
|
640 | return {
|
641 | year: y,
|
642 | month: dm.month,
|
643 | day: dm.day
|
644 | };
|
645 | } else {
|
646 | return;
|
647 | }
|
648 | }
|
649 | }
|
650 | for (q = 0, len3 = possible_year_splits.length; q < len3; q++) {
|
651 | ref1 = possible_year_splits[q], y = ref1[0], rest = ref1[1];
|
652 | dm = this.map_ints_to_dm(rest);
|
653 | if (dm != null) {
|
654 | y = this.two_to_four_digit_year(y);
|
655 | return {
|
656 | year: y,
|
657 | month: dm.month,
|
658 | day: dm.day
|
659 | };
|
660 | }
|
661 | }
|
662 | },
|
663 | map_ints_to_dm: function(ints) {
|
664 | var d, len1, m, o, ref, ref1;
|
665 | ref = [ints, ints.slice().reverse()];
|
666 | for (o = 0, len1 = ref.length; o < len1; o++) {
|
667 | ref1 = ref[o], d = ref1[0], m = ref1[1];
|
668 | if ((1 <= d && d <= 31) && (1 <= m && m <= 12)) {
|
669 | return {
|
670 | day: d,
|
671 | month: m
|
672 | };
|
673 | }
|
674 | }
|
675 | },
|
676 | two_to_four_digit_year: function(year) {
|
677 | if (year > 99) {
|
678 | return year;
|
679 | } else if (year > 50) {
|
680 | return year + scoring.REFERENCE_YEAR - 100;
|
681 | } else {
|
682 | return year + scoring.REFERENCE_YEAR;
|
683 | }
|
684 | }
|
685 | };
|
686 |
|
687 | module.exports = matching;
|
688 |
|
689 |
|