Class: Noise::Pattern

Inherits:
Object
  • Object
show all
Defined in:
lib/noise/pattern.rb

Constant Summary collapse

NAME_REGEX =
/\A([A-Z1]+)([^A-Z]*)\z/

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(modifiers) ⇒ Pattern

Returns a new instance of Pattern.



125
126
127
128
129
130
131
# File 'lib/noise/pattern.rb', line 125

def initialize(modifiers)
  @pre_messages = [[], []]
  @tokens = []
  @name = ''
  @psk_count = 0
  @modifiers = modifiers
end

Instance Attribute Details

#fallbackObject (readonly)

Returns the value of attribute fallback.



103
104
105
# File 'lib/noise/pattern.rb', line 103

def fallback
  @fallback
end

#modifiersObject (readonly)

Returns the value of attribute modifiers.



103
104
105
# File 'lib/noise/pattern.rb', line 103

def modifiers
  @modifiers
end

#nameObject (readonly)

Returns the value of attribute name.



103
104
105
# File 'lib/noise/pattern.rb', line 103

def name
  @name
end

#psk_countObject (readonly)

Returns the value of attribute psk_count.



103
104
105
# File 'lib/noise/pattern.rb', line 103

def psk_count
  @psk_count
end

#tokensObject (readonly)

Returns the value of attribute tokens.



103
104
105
# File 'lib/noise/pattern.rb', line 103

def tokens
  @tokens
end

Class Method Details

.create(name) ⇒ Object



107
108
109
110
111
112
113
# File 'lib/noise/pattern.rb', line 107

def self.create(name)
  matched = NAME_REGEX.match(name)
  raise Noise::Exceptions::ProtocolNameError, "Malformed pattern name: #{name}" unless matched

  modifiers = matched[2].split('+').map { |s| Modifier.parse(s) }
  pattern_class(matched[1]).new(modifiers)
end

Instance Method Details

#apply_pattern_modifiersObject



137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/noise/pattern.rb', line 137

def apply_pattern_modifiers
  @modifiers.each do |modifier|
    case modifier
    when Modifier::Psk
      index = modifier.index
      # psk0 prepends to the first message, pskN appends to the Nth one.
      raise Noise::Exceptions::PSKValueError if index > @tokens.size

      if index.zero?
        @tokens[0].insert(0, Token::PSK)
      else
        @tokens[index - 1] << Token::PSK
      end
      @psk_count += 1
    when Modifier::Fallback
      @fallback = true
    end
  end
end

#initiator_pre_messagesObject



176
177
178
# File 'lib/noise/pattern.rb', line 176

def initiator_pre_messages
  (@pre_messages[0] || []).dup
end

#initiator_static?Boolean

A party needs a static keypair when its static public key is either pre-shared with the peer or transmitted during the handshake. Deriving this from the pattern itself keeps deferred patterns (whose names carry a '1', e.g. X1K) working, unlike inspecting single characters of the name.

Returns:

  • (Boolean)


187
188
189
# File 'lib/noise/pattern.rb', line 187

def initiator_static?
  initiator_static_pre_shared? || sends_static?(0)
end

#initiator_static_pre_shared?Boolean

Returns:

  • (Boolean)


195
196
197
# File 'lib/noise/pattern.rb', line 195

def initiator_static_pre_shared?
  initiator_pre_messages.include?(Token::S)
end

#one_way?Boolean

Returns:

  • (Boolean)


208
209
210
# File 'lib/noise/pattern.rb', line 208

def one_way?
  false
end

#psk?Boolean

Returns:

  • (Boolean)


133
134
135
# File 'lib/noise/pattern.rb', line 133

def psk?
  modifiers.any? { |m| m.is_a? Modifier::Psk }
end

#required_keypairs(initiator) ⇒ Object

initiator [Boolean]



158
159
160
# File 'lib/noise/pattern.rb', line 158

def required_keypairs(initiator)
  initiator ? required_keypairs_of_initiator : required_keypairs_of_responder
end

#required_keypairs_of_initiatorObject



162
163
164
165
166
167
# File 'lib/noise/pattern.rb', line 162

def required_keypairs_of_initiator
  required = []
  required << :s if initiator_static?
  required << :rs if responder_static_pre_shared?
  required
end

#required_keypairs_of_responderObject



169
170
171
172
173
174
# File 'lib/noise/pattern.rb', line 169

def required_keypairs_of_responder
  required = []
  required << :rs if initiator_static_pre_shared?
  required << :s if responder_static?
  required
end

#responder_pre_messagesObject



180
181
182
# File 'lib/noise/pattern.rb', line 180

def responder_pre_messages
  (@pre_messages[1] || []).dup
end

#responder_static?Boolean

Returns:

  • (Boolean)


191
192
193
# File 'lib/noise/pattern.rb', line 191

def responder_static?
  responder_static_pre_shared? || sends_static?(1)
end

#responder_static_pre_shared?Boolean

Returns:

  • (Boolean)


199
200
201
# File 'lib/noise/pattern.rb', line 199

def responder_static_pre_shared?
  responder_pre_messages.include?(Token::S)
end

#sends_static?(offset) ⇒ Boolean

The initiator writes the messages at even indexes, the responder the ones at odd indexes.

Returns:

  • (Boolean)


204
205
206
# File 'lib/noise/pattern.rb', line 204

def sends_static?(offset)
  offset.step(@tokens.size - 1, 2).any? { |i| @tokens[i].include?(Token::S) }
end