Skip to content
This repository has been archived by the owner on Sep 24, 2019. It is now read-only.

Commit

Permalink
Can now exclude requests by passing an :exclude => proc option.
Browse files Browse the repository at this point in the history
  • Loading branch information
Brian Butz & Kevin Fitzpatrick committed Jun 24, 2011
1 parent 279dde3 commit 8d1e767
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 15 deletions.
10 changes: 9 additions & 1 deletion README.rdoc
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,15 @@ In early 2011 Facebook started to send all iframe application requests as POST.
or

require "rack-facebook-method-fix"
use Rack::Facebook::MethodFix, :secret_id => "c561df165eacdd6e32672c9eaee10318"
use Rack::Facebook::MethodFix, :secret_id => "c561df165eacdd6e32672c9eaee10318"


You can exclude requests from being processed by adding an exclude option:

use Rack::Facebook::MethodFix, :exclude => proc { |env| env['PATH_INFO'].match(/^\/admin/) }

This would make sure that no path in the /admin namespace would change from a POST to a GET regardless of the signed_request param.


== Contributing to Rack::Facebook::MethodFix

Expand Down
34 changes: 21 additions & 13 deletions lib/rack/facebook/method-fix.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,46 +8,54 @@ def initialize(app, settings={})
end

def call(env)
if env["REQUEST_METHOD"] == "POST"
request = Request.new(env)
if @settings[:secret_id] && request.params["signed_request"]
env["REQUEST_METHOD"] = "GET" if signed_request_valid?(@settings[:secret_id], request)
else
env["REQUEST_METHOD"] = "GET" if request.params["signed_request"]
unless env_excluded?(env)
if env["REQUEST_METHOD"] == "POST"
request = Request.new(env)
if @settings[:secret_id] && request.params["signed_request"]
env["REQUEST_METHOD"] = "GET" if signed_request_valid?(@settings[:secret_id], request)
else
env["REQUEST_METHOD"] = "GET" if request.params["signed_request"]
end
end
end
@app.call(env)
end

# Code adapted from https://github.com/nsanta/fbgraph
def signed_request_valid?(secret_id, request)
encoded_signature, payload = request.params["signed_request"].split(".", 2)
signature = ""
valid = true

url_decode_64(encoded_signature).each_byte do |byte|
signature << "%02x" % byte
end

data = JSON.parse(url_decode_64(payload))
if data["algorithm"].to_s.upcase != "HMAC-SHA256"
valid = false
end

expected_signature = OpenSSL::HMAC.hexdigest("sha256", secret_id, payload)
if expected_signature != signature
valid = false
end

valid
end

def url_decode_64(string)
encoded_string = string.gsub("-", "+").gsub("_", "/")
encoded_string += "=" while !(encoded_string.size % 4).zero?
Base64.decode64(encoded_string)
end


protected

def env_excluded?(env)
@settings[:exclude] && @settings[:exclude].call(env)
end

end
end
end
29 changes: 28 additions & 1 deletion spec/rack/facebook/method_fix_spec.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
require File.expand_path('spec_helper', File.join(File.dirname(__FILE__), '../../'))


class MockRackWrapper
def initialize(response)
@response = response
Expand Down Expand Up @@ -41,4 +40,32 @@ def env
end
end
end

context 'when the middleware is passed an exclusion proc' do
before do
simple_response = [200, {"Content-type" => "test/plain", "Content-length" => "5"}, ["foo"]]
@mock_rack_app = MockRackWrapper.new(simple_response)
exclusion_proc = proc { |env| env['PATH_INFO'].match(/^\/admin/) }
facebook_method_fix_app = Rack::Facebook::MethodFix.new(@mock_rack_app, :exclude => exclusion_proc)
@request = Rack::MockRequest.new(facebook_method_fix_app)
end

it "does not change requests that are not from facebook" do
@request.post('/', {})
@mock_rack_app.env["REQUEST_METHOD"].should == "POST"
end

context "requests from facebook " do
let(:params) { {:params => {"signed_request" => 'nothing'}} }
it "changes POSTs to GETs the exclusion proc returns false" do
@request.post('/foo', params)
@mock_rack_app.env["REQUEST_METHOD"].should == "GET"
end

it "does not change POSTs when the exclusion proc returns true" do
@request.post('/admin/foo', params)
@mock_rack_app.env["REQUEST_METHOD"].should == "POST"
end
end
end
end

0 comments on commit 8d1e767

Please sign in to comment.