Skip to content

Loading…

Signed post #121

Merged
merged 2 commits into from

2 participants

@yssk22

I've added the signed header implementation and the new status code (429) handling.

yssk22 added some commits
@yssk22 yssk22 Added an exception class for 429 status code. 75bfdb7
@yssk22 yssk22 Support the signed header.
Now we can enable the signed header by passing client_ips option
to the Instagram.Client constructor.

   client = Instagram.Client(:access_token => "AT", :client_ips => "1.2.3.4")
   client.like_media(123)  # => call API with X-Insta-Forwarded-For signature.

If you do not set the :client_ips option, X-Insta-Forwarded-For is not sent.
dd6b068
@heatonjb heatonjb merged commit dd6b068 into Instagram:master
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jun 3, 2014
  1. @yssk22
  2. @yssk22

    Support the signed header.

    yssk22 committed
    Now we can enable the signed header by passing client_ips option
    to the Instagram.Client constructor.
    
       client = Instagram.Client(:access_token => "AT", :client_ips => "1.2.3.4")
       client.like_media(123)  # => call API with X-Insta-Forwarded-For signature.
    
    If you do not set the :client_ips option, X-Insta-Forwarded-For is not sent.
This page is out of date. Refresh to see the latest.
View
2 lib/faraday/raise_http_exception.rb
@@ -11,6 +11,8 @@ def call(env)
raise Instagram::BadRequest, error_message_400(response)
when 404
raise Instagram::NotFound, error_message_400(response)
+ when 429
+ raise Instagram::TooManyRequests, error_message_400(response)
when 500
raise Instagram::InternalServerError, error_message_500(response, "Something is technically wrong.")
when 502
View
4 lib/instagram/client/comments.rb
@@ -35,7 +35,7 @@ def media_comments(id, *args)
# @rate_limited true
# @see http://instagram.com/developer/endpoints/comments/#post_media_comments
def create_media_comment(id, text, options={})
- response = post("media/#{id}/comments", options.merge(:text => text))
+ response = post("media/#{id}/comments", options.merge(:text => text), signature=true)
response
end
@@ -54,7 +54,7 @@ def create_media_comment(id, text, options={})
# @rate_limited true
# @see http://instagram.com/developer/endpoints/comments/#delete_media_comments
def delete_media_comment(media_id, comment_id, options={})
- response = delete("media/#{media_id}/comments/#{comment_id}", options)
+ response = delete("media/#{media_id}/comments/#{comment_id}", options, signature=true)
response
end
end
View
2 lib/instagram/client/embedding.rb
@@ -21,7 +21,7 @@ module Embedding
def oembed(*args)
url = args.first
return nil unless url
- get("oembed?url=#{url}", {}, false, true)
+ get("oembed?url=#{url}", {}, false, false, true)
end
end
end
View
4 lib/instagram/client/likes.rb
@@ -34,7 +34,7 @@ def media_likes(id, *args)
# @rate_limited true
# @see http://instagram.com/developer/endpoints/likes/#post_likes
def like_media(id, options={})
- response = post("media/#{id}/likes", options)
+ response = post("media/#{id}/likes", options, signature=true)
response
end
@@ -50,7 +50,7 @@ def like_media(id, options={})
# @rate_limited true
# @see http://instagram.com/developer/endpoints/likes/#delete_likes
def unlike_media(id, options={})
- response = delete("media/#{id}/likes", options)
+ response = delete("media/#{id}/likes", options, signature=true)
response
end
end
View
2 lib/instagram/client/tags.rb
@@ -34,7 +34,7 @@ def tag(tag, *args)
# @rate_limited true
def tag_recent_media(id, *args)
options = args.last.is_a?(Hash) ? args.pop : {}
- response = get("tags/#{id}/media/recent", options, false, false)
+ response = get("tags/#{id}/media/recent", options, false, false, false)
response
end
View
12 lib/instagram/client/users.rb
@@ -213,7 +213,7 @@ def user_relationship(id, options={})
# @rate_limited true
def follow_user(id, options={})
options["action"] = "follow"
- response = post("users/#{id}/relationship", options)
+ response = post("users/#{id}/relationship", options, signature=true)
response
end
@@ -231,7 +231,7 @@ def follow_user(id, options={})
# @rate_limited true
def unfollow_user(id, options={})
options["action"] = "unfollow"
- response = post("users/#{id}/relationship", options)
+ response = post("users/#{id}/relationship", options, signature=true)
response
end
@@ -249,7 +249,7 @@ def unfollow_user(id, options={})
# @rate_limited true
def block_user(id, options={})
options["action"] = "block"
- response = post("users/#{id}/relationship", options)
+ response = post("users/#{id}/relationship", options, signature=true)
response
end
@@ -267,7 +267,7 @@ def block_user(id, options={})
# @rate_limited true
def unblock_user(id, options={})
options["action"] = "unblock"
- response = post("users/#{id}/relationship", options)
+ response = post("users/#{id}/relationship", options, signature=true)
response
end
@@ -285,7 +285,7 @@ def unblock_user(id, options={})
# @rate_limited true
def approve_user(id, options={})
options["action"] = "approve"
- response = post("users/#{id}/relationship", options)
+ response = post("users/#{id}/relationship", options, signature=true)
response
end
@@ -303,7 +303,7 @@ def approve_user(id, options={})
# @rate_limited true
def deny_user(id, options={})
options["action"] = "deny"
- response = post("users/#{id}/relationship", options)
+ response = post("users/#{id}/relationship", options, signature=true)
response
end
end
View
7 lib/instagram/configuration.rb
@@ -10,6 +10,7 @@ module Configuration
:adapter,
:client_id,
:client_secret,
+ :client_ips,
:connection_options,
:scope,
:redirect_uri,
@@ -34,6 +35,9 @@ module Configuration
# By default, don't set an application secret
DEFAULT_CLIENT_SECRET = nil
+ # By default, don't set application IPs
+ DEFAULT_CLIENT_IPS = nil
+
# By default, don't set any connection options
DEFAULT_CONNECTION_OPTIONS = {}
@@ -94,6 +98,7 @@ def reset
self.adapter = DEFAULT_ADAPTER
self.client_id = DEFAULT_CLIENT_ID
self.client_secret = DEFAULT_CLIENT_SECRET
+ self.client_ips = DEFAULT_CLIENT_IPS
self.connection_options = DEFAULT_CONNECTION_OPTIONS
self.scope = DEFAULT_SCOPE
self.redirect_uri = DEFAULT_REDIRECT_URI
@@ -101,7 +106,7 @@ def reset
self.format = DEFAULT_FORMAT
self.proxy = DEFAULT_PROXY
self.user_agent = DEFAULT_USER_AGENT
- self.no_response_wrapper= DEFAULT_NO_RESPONSE_WRAPPER
+ self.no_response_wrapper= DEFAULT_NO_RESPONSE_WRAPPER
end
end
end
View
3 lib/instagram/error.rb
@@ -8,6 +8,9 @@ class BadRequest < Error; end
# Raised when Instagram returns the HTTP status code 404
class NotFound < Error; end
+ # Raised when Instagram returns the HTTP status code 429
+ class TooManyRequests < Error; end
+
# Raised when Instagram returns the HTTP status code 500
class InternalServerError < Error; end
View
2 lib/instagram/oauth.rb
@@ -15,7 +15,7 @@ def get_access_token(code, options={})
options[:grant_type] ||= "authorization_code"
options[:redirect_uri] ||= self.redirect_uri
params = access_token_params.merge(options)
- post("/oauth/access_token/", params.merge(:code => code), raw=false, unformatted=true, no_response_wrapper=true)
+ post("/oauth/access_token/", params.merge(:code => code), signature=false, raw=false, unformatted=true, no_response_wrapper=true)
end
private
View
31 lib/instagram/request.rb
@@ -1,30 +1,33 @@
+require 'openssl'
+require 'base64'
+
module Instagram
# Defines HTTP request methods
module Request
# Perform an HTTP GET request
- def get(path, options={}, raw=false, unformatted=false, no_response_wrapper=no_response_wrapper)
- request(:get, path, options, raw, unformatted, no_response_wrapper)
+ def get(path, options={}, signature=false, raw=false, unformatted=false, no_response_wrapper=no_response_wrapper)
+ request(:get, path, options, signature, raw, unformatted, no_response_wrapper)
end
# Perform an HTTP POST request
- def post(path, options={}, raw=false, unformatted=false, no_response_wrapper=no_response_wrapper)
- request(:post, path, options, raw, unformatted, no_response_wrapper)
+ def post(path, options={}, signature=false, raw=false, unformatted=false, no_response_wrapper=no_response_wrapper)
+ request(:post, path, options, signature, raw, unformatted, no_response_wrapper)
end
# Perform an HTTP PUT request
- def put(path, options={}, raw=false, unformatted=false, no_response_wrapper=no_response_wrapper)
- request(:put, path, options, raw, unformatted, no_response_wrapper)
+ def put(path, options={}, signature=false, raw=false, unformatted=false, no_response_wrapper=no_response_wrapper)
+ request(:put, path, options, signature, raw, unformatted, no_response_wrapper)
end
# Perform an HTTP DELETE request
- def delete(path, options={}, raw=false, unformatted=false, no_response_wrapper=no_response_wrapper)
- request(:delete, path, options, raw, unformatted, no_response_wrapper)
+ def delete(path, options={}, signature=false, raw=false, unformatted=false, no_response_wrapper=no_response_wrapper)
+ request(:delete, path, options, signature, raw, unformatted, no_response_wrapper)
end
private
# Perform an HTTP request
- def request(method, path, options, raw=false, unformatted=false, no_response_wrapper=false)
+ def request(method, path, options, signature=false, raw=false, unformatted=false, no_response_wrapper=false)
response = connection(raw).send(method) do |request|
path = formatted_path(path) unless unformatted
case method
@@ -34,6 +37,9 @@ def request(method, path, options, raw=false, unformatted=false, no_response_wra
request.path = path
request.body = options unless options.empty?
end
+ if signature && client_ips != nil
+ request.headers["X-Insta-Forwarded-For"] = get_insta_fowarded_for(client_ips, client_secret)
+ end
end
return response if raw
return response.body if no_response_wrapper
@@ -43,5 +49,12 @@ def request(method, path, options, raw=false, unformatted=false, no_response_wra
def formatted_path(path)
[path, format].compact.join('.')
end
+
+ def get_insta_fowarded_for(ips, secret)
+ digest = OpenSSL::Digest::Digest.new('sha256')
+ signature = OpenSSL::HMAC.hexdigest(digest, secret, ips)
+ return [ips, signature].join('|')
+ end
+
end
end
View
1 spec/faraday/response_spec.rb
@@ -8,6 +8,7 @@
{
400 => Instagram::BadRequest,
404 => Instagram::NotFound,
+ 429 => Instagram::TooManyRequests,
500 => Instagram::InternalServerError,
503 => Instagram::ServiceUnavailable
}.each do |status, exception|
View
1 spec/instagram/api_spec.rb
@@ -34,6 +34,7 @@
:adapter => :typhoeus,
:client_id => 'CID',
:client_secret => 'CS',
+ :client_ips => '1.2.3.4',
:connection_options => { :ssl => { :verify => true } },
:redirect_uri => 'http://http://localhost:4567/oauth/callback',
:endpoint => 'http://tumblr.com/',
View
2 spec/instagram/client/likes_spec.rb
@@ -5,7 +5,7 @@
context ".new(:format => '#{format}')" do
before do
- @client = Instagram::Client.new(:format => format, :client_id => 'CID', :client_secret => 'CS', :access_token => 'AT')
+ @client = Instagram::Client.new(:format => format, :client_id => 'CID', :client_secret => 'CS', :client_ips => '1.2.3.4', :access_token => 'AT')
end
describe ".media_likes" do
View
56 spec/instagram/request_spec.rb
@@ -0,0 +1,56 @@
+require File.expand_path('../../spec_helper', __FILE__)
+
+describe Instagram::Request do
+ describe "#post" do
+ before do
+ @ips = "1.2.3.4"
+ @secret = "CS"
+ digest = OpenSSL::Digest::Digest.new('sha256')
+ signature = OpenSSL::HMAC.hexdigest(digest, @secret, @ips)
+ @signed_header = [@ips, signature].join('|')
+ end
+
+ context "with signature=true" do
+ it "should set X-Insta-Forwarded-For header" do
+ client = Instagram::Client.new(:client_id => "CID", :client_secret => @secret, :client_ips => @ips, :access_token => "AT")
+ url = client.send(:connection).build_url("/media/123/likes.json").to_s
+ stub_request(:post, url).
+ with(:body => {"access_token"=>"AT"}).
+ to_return(:status => 200, :body => "", :headers => {})
+
+ client.post("/media/123/likes", {}, signature=true)
+ a_request(:post, url).
+ with(:headers => {'X-Insta-Forwarded-For'=> @signed_header}).
+ should have_been_made
+ end
+
+ it "should not set X-Insta-Fowarded-For header if client_ips is not provided" do
+ client = Instagram::Client.new(:client_id => "CID", :client_secret => @secret, :access_token => "AT")
+ url = client.send(:connection).build_url("/media/123/likes.json").to_s
+ stub_request(:post, url).
+ with(:body => {"access_token"=>"AT"}).
+ to_return(:status => 200, :body => "", :headers => {})
+
+ client.post("/media/123/likes", {}, signature=true)
+ a_request(:post, url).
+ with(:headers => {'X-Insta-Forwarded-For'=> @signed_header}).
+ should_not have_been_made
+ end
+ end
+
+ context "with signature=false" do
+ it "should set X-Insta-Forwarded-For header" do
+ client = Instagram::Client.new(:client_id => "CID", :client_secret => @secret, :client_ips => @ips, :access_token => "AT")
+ url = client.send(:connection).build_url("/media/123/likes.json").to_s
+ stub_request(:post, url).
+ with(:body => {"access_token"=>"AT"}).
+ to_return(:status => 200, :body => "", :headers => {})
+
+ client.post("/media/123/likes", {}, signature=false)
+ a_request(:post, url).
+ with(:headers => {'X-Insta-Forwarded-For'=> @signed_header}).
+ should_not have_been_made
+ end
+ end
+ end
+end
Something went wrong with that request. Please try again.