lib/knj/facebook_connect.rb in knjrbfw-0.0.8 vs lib/knj/facebook_connect.rb in knjrbfw-0.0.9

- old
+ new

@@ -1,37 +1,114 @@ class Knj::Facebook_connect + attr_reader :args + def initialize(args) + require "#{$knjpath}http" + require "#{$knjpath}http2" + @args = args raise "No app-ID given." if !@args[:app_id] raise "No app-secret given." if !@args[:app_secret] end - def login(args) - hash = {} - Knj::Php.parse_str(args[:token], hash) - hash = Knj::Php.ksort(hash) + def base64_urldecode(str) + return Base64.decode64("#{str.tr("-_", "+/")}=") + end + + def get(http, url) + resp = http.get(url) - payload = "" - hash.each do |key, val| - next if key == "sig" - payload += "#{key}=#{val}" + if resp.body.length > 0 + begin + jdata = JSON.parse(resp.body) + + error_type = RuntimeError + if jdata["error"] and jdata["error"]["message"] == "Code was invalid or expired. The session is invalid because the user logged out." + error_type = Knj::Errors::InvalidData + end + + raise error_type, "#{jdata["error"]["type"]}: #{jdata["error"]["message"]}" if jdata["error"] + rescue JSON::ParserError + #ignore + end end - raise "Invalid payload or signature." if Digest::MD5.hexdigest("#{payload}#{@args[:app_secret]}") != hash["sig"] + return {:json => jdata, :resp => resp, :headers => resp.headers, :body => resp.body} + end + + def validate_cookie(cookie) + data = cookie.split(".", 2) + enc_sig, payload = data[0], data[1] - http = Knj::Http.new( - "host" => "graph.facebook.com", - "ssl" => true + sig = self.base64_urldecode(enc_sig).unpack("H*").first + data = self.base64_urldecode(payload) + data = JSON.parse(data) + + raise "Unknown algorithm: '#{data["algorithm"]}'." if data["algorithm"] != "HMAC-SHA256" + exp_sig = OpenSSL::HMAC.hexdigest("sha256", @args[:app_secret], payload) + + raise "Bad signed JSON signature." if sig != exp_sig + + return data + end + + def token_from_cookie(http, cookie = nil) + if @token + return @token + end + + raise "No token set and no cookie given." if !@args[:cookie] + + data = self.validate_cookie(@args[:cookie]) + resp = self.get(http, "oauth/access_token?client_id=#{Knj::Web.urlenc(@args[:app_id])}&client_secret=#{Knj::Web.urlenc(@args[:app_secret])}&redirect_uri=&code=#{Knj::Web.urlenc(data["code"])}") + + match = resp[:body].match(/access_token=(.+)&expires=(\d+)/) + raise "No access token was given." if !match + atoken = match[1] + @token = atoken + @expires = match[2] + + return atoken + end + + def login(args = {}) + http = Knj::Http2.new( + :host => "graph.facebook.com", + :ssl => true ) - data = http.get("/me?access_token=#{hash["access_token"]}") - data = {:access_token => JSON.parse(data["data"])} + atoken = self.token_from_cookie(http, @args[:cookie]) + + url = "me?access_token=#{Knj::Web.urlenc(atoken)}" + resp = self.get(http, url) + data = {"user" => resp[:json]} + if args[:profile_picture] - pic_data = http.get("/#{data[:access_token]["id"]}/picture?type=large") - pic_obj = Magick::Image.from_blob(pic_data["data"].to_s)[0] - data[:pic] = pic_obj + pic_data = self.get(http, "#{data["user"]["id"]}/picture?type=large") + pic_obj = Magick::Image.from_blob(pic_data[:body].to_s)[0] + data["pic"] = pic_obj end return data + end + + def wall_post(args) + http = Knj::Http2.new( + :host => "graph.facebook.com", + :ssl => true + ) + + atoken = self.token_from_cookie(http) + post_data = {} + + args_keys = [:link, :object_attachment, :picture, :caption, :name, :description, :message, :media] + args_keys.each do |key| + if args.key?(key) and args[key] + post_data[key] = args[key] + end + end + + res = http.post("/me/feed?access_token=#{atoken}", post_data) + raise res.body.to_s.strip if res.code.to_s != "200" end end \ No newline at end of file