lib/faye/authentication.rb in faye-authentication-0.1.0 vs lib/faye/authentication.rb in faye-authentication-0.2.0
- old
+ new
@@ -1,32 +1,34 @@
-require "faye/authentication/version"
+require 'jwt'
+require 'faye/authentication/version'
require 'faye/authentication/extension'
require 'faye/authentication/http_client'
require 'faye/authentication/engine'
module Faye
module Authentication
+ class AuthError < StandardError; end
+ class ExpiredError < AuthError; end
+ class PayloadError < AuthError; end
- def self.sign(message, secret)
- OpenSSL::HMAC.hexdigest('sha1', secret, "#{message['channel']}-#{message['clientId']}")
+ # Return jwt signature, pass hash of payload including channel and client_id
+ def self.sign(payload, secret, options = {})
+ options = {expires_at: Time.now + 12*3600, algorithm: 'HS256'}.merge(options)
+ JWT.encode(payload.merge(exp: options[:expires_at].to_i), secret, options[:algorithm])
end
- def self.valid?(message, secret)
- signature = message.delete('signature')
- return false unless signature
- secure_compare(signature, sign(message, secret))
+ # Return signed payload or raise
+ def self.decode(signature, secret)
+ payload, _ = JWT.decode(signature, secret) rescue raise(AuthError)
+ raise ExpiredError if Time.at(payload['exp'].to_i) < Time.now
+ payload
end
- # constant-time comparison algorithm to prevent timing attacks
- # Copied from ActiveSupport::MessageVerifier
- def self.secure_compare(a, b)
- return false unless a.bytesize == b.bytesize
-
- l = a.unpack "C#{a.bytesize}"
-
- res = 0
- b.each_byte { |byte| res |= byte ^ l.shift }
- res == 0
+ # Return true if signature is valid and correspond to channel and clientId or raise
+ def self.validate(signature, channel, clientId, secret)
+ payload = self.decode(signature, secret)
+ raise PayloadError if channel.to_s.empty? || clientId.to_s.empty?
+ raise PayloadError unless channel == payload['channel'] && clientId == payload['clientId']
+ true
end
-
end
end