class Facebook::Messenger::Server
This module holds the server that processes incoming messages from the Facebook
Messenger
Platform.
Public Class Methods
# File lib/facebook/messenger/server.rb, line 20 def self.call(env) new.call(env) end
Public Instance Methods
Rack handler for request.
# File lib/facebook/messenger/server.rb, line 25 def call(env) @request = Rack::Request.new(env) @response = Rack::Response.new if @request.get? verify elsif @request.post? receive else @response.status = 405 end @response.finish end
Private Instance Methods
Returns a String describing the bot's configured app secret.
# File lib/facebook/messenger/server.rb, line 125 def app_secret_for(facebook_page_id) Facebook::Messenger.config.provider.app_secret_for(facebook_page_id) end
Returns a String describing the request body.
# File lib/facebook/messenger/server.rb, line 135 def body @body ||= @request.body.read end
Check the integrity of the request. @see developers.facebook.com/docs/messenger-platform/webhook#security
@raise BadRequestError
if the request has been tampered with.
# File lib/facebook/messenger/server.rb, line 74 def check_integrity # If app secret is not found in environment, return. # So for the security purpose always add provision in # configuration provider to return app secret. return unless app_secret_for(parsed_body['entry'][0]['id']) unless signature.start_with?('sha1='.freeze) warn X_HUB_SIGNATURE_MISSING_WARNING raise BadRequestError, 'Error getting integrity signature'.freeze end raise BadRequestError, 'Error checking message integrity'.freeze \ unless valid_signature? end
Generate a HMAC signature for the given content.
# File lib/facebook/messenger/server.rb, line 115 def generate_hmac(content) content_json = JSON.parse(content, symbolize_names: true) facebook_page_id = content_json[:entry][0][:id] OpenSSL::HMAC.hexdigest('sha1'.freeze, app_secret_for(facebook_page_id), content) end
Returns a Hash describing the parsed request body. @raise JSON::ParserError if body hash is not valid.
@return [JSON] Parsed body hash.
# File lib/facebook/messenger/server.rb, line 145 def parsed_body @parsed_body ||= JSON.parse(body) rescue JSON::ParserError raise BadRequestError, 'Error parsing request body format' end
Function handles the webhook events. @raise BadRequestError
if the request is tampered.
# File lib/facebook/messenger/server.rb, line 60 def receive check_integrity trigger(parsed_body) rescue BadRequestError => error respond_with_error(error) end
If received request is tampered, sent 400 code in response.
@param [Object] error Error
object.
# File lib/facebook/messenger/server.rb, line 177 def respond_with_error(error) @response.status = 400 @response.write(error.message) @response.headers['Content-Type'.freeze] = 'text/plain'.freeze end
Returns a String describing the X-Hub-Signature header.
# File lib/facebook/messenger/server.rb, line 91 def signature @request.env['HTTP_X_HUB_SIGNATURE'.freeze].to_s end
Sign the given string.
@return [String] A string describing its signature.
# File lib/facebook/messenger/server.rb, line 110 def signature_for(string) format('sha1=%<string>s'.freeze, string: generate_hmac(string)) end
Function hand over the webhook event to handlers.
@param [Hash] events Parsed body hash in webhook event.
# File lib/facebook/messenger/server.rb, line 156 def trigger(events) # Facebook may batch several items in the 'entry' array during # periods of high load. events['entry'.freeze].each do |entry| # If the application has subscribed to webhooks other than Messenger, # 'messaging' won't be available and it is not relevant to us. next unless entry['messaging'.freeze] # Facebook may batch several items in the 'messaging' array during # periods of high load. entry['messaging'.freeze].each do |messaging| Facebook::Messenger::Bot.receive(messaging) end end end
Verify that the signature given in the X-Hub-Signature header matches that of the body.
@return [Boolean] true if request is valid else false.
# File lib/facebook/messenger/server.rb, line 101 def valid_signature? Rack::Utils.secure_compare(signature, signature_for(body)) end
Checks whether a verify token is valid.
# File lib/facebook/messenger/server.rb, line 130 def valid_verify_token?(token) Facebook::Messenger.config.provider.valid_verify_token?(token) end
Function validates the verification request which is sent by Facebook
to validate the entered endpoint.
@see developers.facebook.com/docs/graph-api/webhooks#callback
# File lib/facebook/messenger/server.rb, line 48 def verify if valid_verify_token?(@request.params['hub.verify_token']) @response.write @request.params['hub.challenge'] else @response.write 'Error; wrong verify token' end end