Class: PossibleKey

Inherits:
Object
  • Object
show all
Includes:
Stats
Defined in:
lib/spellr/key_tuner/possible_key.rb

Overview

rubocop:disable Metrics/ClassLength

Constant Summary collapse

VOWELS =
%i{
  a e i o u
  A E I O U
}.freeze
CONSONANTS =
%i{
  b c d f g h j k l m n p q r s t v w x y z
  B C D F G H J K L M N P Q R S T V W X Y Z
}.freeze
BASE_64 =
VOWELS + CONSONANTS + %i{0 1 2 3 4 5 6 7 8 9 - _ + / =}.freeze
LETTER_COUNT_HASH =
BASE_64.map { |k| [k.to_sym, 0] }.to_h
FEATURE_LETTERS =
%i{+ - _ / A z Z q Q X x}.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Stats

gaussian_probability, max, mean, min, standard_deviation, variance

Constructor Details

#initialize(string, key = nil) ⇒ PossibleKey

Returns a new instance of PossibleKey.



43
44
45
46
# File 'lib/spellr/key_tuner/possible_key.rb', line 43

def initialize(string, key = nil)
  @string = string
  @key = key
end

Instance Attribute Details

#stringObject (readonly)

Returns the value of attribute string.



41
42
43
# File 'lib/spellr/key_tuner/possible_key.rb', line 41

def string
  @string
end

Class Method Details

.keysObject



22
23
24
25
26
27
# File 'lib/spellr/key_tuner/possible_key.rb', line 22

def keys
  @keys ||= begin
    load_from_file('false_positives.txt', false) +
      load_from_file('keys.txt', true)
  end
end

Instance Method Details

#alnum_chunksObject



171
172
173
# File 'lib/spellr/key_tuner/possible_key.rb', line 171

def alnum_chunks
  @alnum_chunks ||= string.scan(/[A-Za-z0-9]+/)
end

#alpha_chunksObject



167
168
169
# File 'lib/spellr/key_tuner/possible_key.rb', line 167

def alpha_chunks
  @alpha_chunks ||= string.scan(/[A-Za-z]+/)
end

#character_setObject

rubocop:disable Metrics/MethodLength



97
98
99
100
101
102
103
104
105
106
# File 'lib/spellr/key_tuner/possible_key.rb', line 97

def character_set # rubocop:disable Metrics/MethodLength
  @character_set ||= case string
  when /^[a-fA-F0-9\-]+$/ then :hex
  when /^[a-z0-9]+$/ then :lower36
  when /^[A-Z0-9]+$/ then :upper36
  when %r{^[A-Za-z0-9\-_+/]+={0,2}$} then :base64
  else
    raise "#{string.inspect} is an unrecognised character set"
  end
end

#character_set_totalObject

rubocop:disable Metrics/MethodLength



108
109
110
111
112
113
114
115
# File 'lib/spellr/key_tuner/possible_key.rb', line 108

def character_set_total # rubocop:disable Metrics/MethodLength
  case character_set
  when :hex then 16
  when :lower36 then 36
  when :upper36 then 36
  when :base64 then 64
  end
end

#classificationObject



84
85
86
87
# File 'lib/spellr/key_tuner/possible_key.rb', line 84

def classification
  key_class = key? ? 'key' : 'not_key'
  "#{key_class}_#{character_set}"
end

#digit_chunksObject



151
152
153
# File 'lib/spellr/key_tuner/possible_key.rb', line 151

def digit_chunks
  @digit_chunks ||= string.scan(/\d+/)
end

#featuresObject

rubocop:disable Metrics/AbcSize, Metrics/MethodLength



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/spellr/key_tuner/possible_key.rb', line 48

def features # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
  {
    **letter_frequency_difference_features,
    equal: letter_count[:'='],
    length: length,
    hex: character_set == :hex ? 1 : 0,
    lower36: character_set == :lower36 ? 1 : 0,
    upper36: character_set == :upper36 ? 1 : 0,
    base64: character_set == :base64 ? 1 : 0,
    mean_title_chunk_size: mean(title_chunks, &:length),
    variance_title_chunk_size: variance(title_chunks, &:length),
    max_title_chunk_size: max(title_chunks, &:length),
    mean_lower_chunk_size: mean(lower_chunks, &:length),
    variance_lower_chunk_size: variance(lower_chunks, &:length),
    mean_upper_chunk_size: mean(upper_chunks, &:length),
    variance_upper_chunk_size: variance(upper_chunks, &:length),
    mean_alpha_chunk_size: mean(alpha_chunks, &:length),
    variance_alpha_chunk_size: variance(alpha_chunks, &:length),
    mean_alnum_chunk_size: mean(alnum_chunks, &:length),
    variance_alnum_chunk_size: variance(alnum_chunks, &:length),
    mean_digit_chunk_size: mean(digit_chunks, &:length),
    variance_digit_chunk_size: variance(digit_chunks, &:length),
    vowel_consonant_ratio: vowel_consonant_ratio,
    alpha_chunks: alpha_chunks.length,
    alnum_chunks: alnum_chunks.length,
    digit_chunks: digit_chunks.length,
    title_chunks: title_chunks.length,
    mean_letter_frequency_difference: mean(letter_frequency_difference.values),
    variance_letter_frequency_difference: max(letter_frequency_difference.values)
  }
end

#ideal_letter_frequencyObject



117
118
119
# File 'lib/spellr/key_tuner/possible_key.rb', line 117

def ideal_letter_frequency
  1.0 / character_set_total * length
end

#key?Boolean

Returns:

  • (Boolean)


80
81
82
# File 'lib/spellr/key_tuner/possible_key.rb', line 80

def key?
  @key
end

#lengthObject



89
90
91
# File 'lib/spellr/key_tuner/possible_key.rb', line 89

def length
  string.length
end

#letter_countObject



121
122
123
124
125
126
127
# File 'lib/spellr/key_tuner/possible_key.rb', line 121

def letter_count
  @letter_count ||= begin
    string.chars.each_with_object(LETTER_COUNT_HASH.dup) do |letter, hash|
      hash[letter.to_sym] += 1
    end
  end
end

#letter_frequencyObject



129
130
131
132
133
134
135
# File 'lib/spellr/key_tuner/possible_key.rb', line 129

def letter_frequency
  @letter_frequency ||= begin
    l = letter_count.dup
    l.each { |k, v| l[k] = v.to_f / string.length }
    l
  end
end

#letter_frequency_differenceObject



137
138
139
140
141
142
143
# File 'lib/spellr/key_tuner/possible_key.rb', line 137

def letter_frequency_difference
  @letter_frequency_difference ||= begin
    l = letter_frequency.dup
    l.each { |k, v| l[k] = (v - ideal_letter_frequency).abs }
    l
  end
end

#letter_frequency_difference_featuresObject



93
94
95
# File 'lib/spellr/key_tuner/possible_key.rb', line 93

def letter_frequency_difference_features
  letter_frequency_difference.slice(*FEATURE_LETTERS)
end

#lower_chunksObject



159
160
161
# File 'lib/spellr/key_tuner/possible_key.rb', line 159

def lower_chunks
  @lower_chunks ||= string.scan(/[a-z]+/)
end

#title_chunksObject



155
156
157
# File 'lib/spellr/key_tuner/possible_key.rb', line 155

def title_chunks
  @title_chunks ||= string.scan(/[A-Z][a-z]+/)
end

#upper_chunksObject



163
164
165
# File 'lib/spellr/key_tuner/possible_key.rb', line 163

def upper_chunks
  @upper_chunks ||= string.scan(/[A-Z]+/)
end

#vowel_consonant_ratioObject



145
146
147
148
149
# File 'lib/spellr/key_tuner/possible_key.rb', line 145

def vowel_consonant_ratio
  vowels = letter_count.fetch_values(*VOWELS).sum
  consonants = letter_count.fetch_values(*CONSONANTS).sum
  vowels / (consonants.nonzero? || 1)
end