class Omniauth::Protect::Validator

Public Class Methods

new(env, encoded_masked_token) click to toggle source
# File lib/omniauth/protect/validator.rb, line 6
def initialize(env, encoded_masked_token)
  @session = env['rack.session']
  @encoded_masked_token = encoded_masked_token
end

Public Instance Methods

valid_csrf_token?() click to toggle source

This is mostly taken & adapted from Rails' action_controller/metal/request_forgery_protection.rb We copy code from Rails in such a horrible manner because Rails doesn't really expose CSRF protection

# File lib/omniauth/protect/validator.rb, line 13
def valid_csrf_token?
  begin
    masked_token = Base64.urlsafe_decode64(@encoded_masked_token)
  rescue ArgumentError # @encoded_masked_token is invalid Base64
    return false
  end

  token_length = ActionController::RequestForgeryProtection::AUTHENTICITY_TOKEN_LENGTH

  if masked_token.length == token_length * 2
    csrf_token = unmask_token(masked_token, token_length)

    real_token = real_csrf_token(token_length)
    global_token = global_csrf_token(real_token)

    compare_tokens(csrf_token, real_token) || compare_tokens(csrf_token, global_token)
  end
end

Private Instance Methods

compare_tokens(token, other) click to toggle source
# File lib/omniauth/protect/validator.rb, line 34
def compare_tokens(token, other)
  ActiveSupport::SecurityUtils.fixed_length_secure_compare(token, other)
end
global_csrf_token(real_token) click to toggle source
# File lib/omniauth/protect/validator.rb, line 60
def global_csrf_token(real_token)
  OpenSSL::HMAC.digest(
    OpenSSL::Digest::SHA256.new,
    real_token,
    '!real_csrf_token'
  )
end
real_csrf_token(token_length) click to toggle source
# File lib/omniauth/protect/validator.rb, line 55
def real_csrf_token(token_length)
  @session[:_csrf_token] ||= SecureRandom.urlsafe_base64(token_length, padding: false)
  Base64.urlsafe_decode64(@session[:_csrf_token])
end
unmask_token(masked_token, token_length) click to toggle source
# File lib/omniauth/protect/validator.rb, line 38
def unmask_token(masked_token, token_length)
  one_time_pad = masked_token[0...token_length]
  encrypted_csrf_token = masked_token[token_length..-1]
  xor_byte_strings(one_time_pad, encrypted_csrf_token)
end
xor_byte_strings(s1, s2) click to toggle source
# File lib/omniauth/protect/validator.rb, line 44
def xor_byte_strings(s1, s2) # :doc:
  s2 = s2.dup
  size = s1.bytesize
  i = 0
  while i < size
    s2.setbyte(i, s1.getbyte(i) ^ s2.getbyte(i))
    i += 1
  end
  s2
end