summaryrefslogtreecommitdiffstats
path: root/Godeps/_workspace/src/github.com/huandu/facebook/app.go
diff options
context:
space:
mode:
Diffstat (limited to 'Godeps/_workspace/src/github.com/huandu/facebook/app.go')
-rw-r--r--Godeps/_workspace/src/github.com/huandu/facebook/app.go255
1 files changed, 255 insertions, 0 deletions
diff --git a/Godeps/_workspace/src/github.com/huandu/facebook/app.go b/Godeps/_workspace/src/github.com/huandu/facebook/app.go
new file mode 100644
index 000000000..d8787aa87
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/huandu/facebook/app.go
@@ -0,0 +1,255 @@
+// A facebook graph api client in go.
+// https://github.com/huandu/facebook/
+//
+// Copyright 2012 - 2015, Huan Du
+// Licensed under the MIT license
+// https://github.com/huandu/facebook/blob/master/LICENSE
+
+package facebook
+
+import (
+ "bytes"
+ "crypto/hmac"
+ "crypto/sha256"
+ "encoding/json"
+ "fmt"
+ "strings"
+)
+
+// Creates a new App and sets app id and secret.
+func New(appId, appSecret string) *App {
+ return &App{
+ AppId: appId,
+ AppSecret: appSecret,
+ }
+}
+
+// Gets application access token, useful for gathering public information about users and applications.
+func (app *App) AppAccessToken() string {
+ return app.AppId + "|" + app.AppSecret
+}
+
+// Parses signed request.
+func (app *App) ParseSignedRequest(signedRequest string) (res Result, err error) {
+ strs := strings.SplitN(signedRequest, ".", 2)
+
+ if len(strs) != 2 {
+ err = fmt.Errorf("invalid signed request format.")
+ return
+ }
+
+ sig, e1 := decodeBase64URLEncodingString(strs[0])
+
+ if e1 != nil {
+ err = fmt.Errorf("cannot decode signed request sig. error is %v.", e1)
+ return
+ }
+
+ payload, e2 := decodeBase64URLEncodingString(strs[1])
+
+ if e2 != nil {
+ err = fmt.Errorf("cannot decode signed request payload. error is %v.", e2)
+ return
+ }
+
+ err = json.Unmarshal(payload, &res)
+
+ if err != nil {
+ err = fmt.Errorf("signed request payload is not a valid json string. error is %v.", err)
+ return
+ }
+
+ var hashMethod string
+ err = res.DecodeField("algorithm", &hashMethod)
+
+ if err != nil {
+ err = fmt.Errorf("signed request payload doesn't contains a valid 'algorithm' field.")
+ return
+ }
+
+ hashMethod = strings.ToUpper(hashMethod)
+
+ if hashMethod != "HMAC-SHA256" {
+ err = fmt.Errorf("signed request payload uses an unknown HMAC method. expect 'HMAC-SHA256'. actual '%v'.", hashMethod)
+ return
+ }
+
+ hash := hmac.New(sha256.New, []byte(app.AppSecret))
+ hash.Write([]byte(strs[1])) // note: here uses the payload base64 string, not decoded bytes
+ expectedSig := hash.Sum(nil)
+
+ if bytes.Compare(sig, expectedSig) != 0 {
+ err = fmt.Errorf("bad signed request signiture.")
+ return
+ }
+
+ return
+}
+
+// ParseCode redeems code for a valid access token.
+// It's a shorthand call to ParseCodeInfo(code, "").
+//
+// In facebook PHP SDK, there is a CSRF state to avoid attack.
+// That state is not checked in this library.
+// Caller is responsible to store and check state if possible.
+func (app *App) ParseCode(code string) (token string, err error) {
+ token, _, _, err = app.ParseCodeInfo(code, "")
+ return
+}
+
+// ParseCodeInfo redeems code for access token and returns extra information.
+// The machineId is optional.
+//
+// See https://developers.facebook.com/docs/facebook-login/access-tokens#extending
+func (app *App) ParseCodeInfo(code, machineId string) (token string, expires int, newMachineId string, err error) {
+ if code == "" {
+ err = fmt.Errorf("code is empty")
+ return
+ }
+
+ var res Result
+ res, err = defaultSession.sendOauthRequest("/oauth/access_token", Params{
+ "client_id": app.AppId,
+ "redirect_uri": app.RedirectUri,
+ "code": code,
+ })
+
+ if err != nil {
+ err = fmt.Errorf("cannot parse facebook response. error is %v.", err)
+ return
+ }
+
+ err = res.DecodeField("access_token", &token)
+
+ if err != nil {
+ return
+ }
+
+ err = res.DecodeField("expires_in", &expires)
+
+ if err != nil {
+ return
+ }
+
+ if _, ok := res["machine_id"]; ok {
+ err = res.DecodeField("machine_id", &newMachineId)
+ }
+
+ return
+}
+
+// Exchange a short lived access token to a long lived access token.
+// Return new access token and its expires time.
+func (app *App) ExchangeToken(accessToken string) (token string, expires int, err error) {
+ if accessToken == "" {
+ err = fmt.Errorf("short lived accessToken is empty")
+ return
+ }
+
+ var res Result
+ res, err = defaultSession.sendOauthRequest("/oauth/access_token", Params{
+ "grant_type": "fb_exchange_token",
+ "client_id": app.AppId,
+ "client_secret": app.AppSecret,
+ "fb_exchange_token": accessToken,
+ })
+
+ if err != nil {
+ err = fmt.Errorf("cannot parse facebook response. error is %v.", err)
+ return
+ }
+
+ err = res.DecodeField("access_token", &token)
+
+ if err != nil {
+ return
+ }
+
+ err = res.DecodeField("expires_in", &expires)
+ return
+}
+
+// Get code from a long lived access token.
+// Return the code retrieved from facebook.
+func (app *App) GetCode(accessToken string) (code string, err error) {
+ if accessToken == "" {
+ err = fmt.Errorf("long lived accessToken is empty")
+ return
+ }
+
+ var res Result
+ res, err = defaultSession.sendOauthRequest("/oauth/client_code", Params{
+ "client_id": app.AppId,
+ "client_secret": app.AppSecret,
+ "redirect_uri": app.RedirectUri,
+ "access_token": accessToken,
+ })
+
+ if err != nil {
+ err = fmt.Errorf("cannot get code from facebook. error is %v.", err)
+ return
+ }
+
+ err = res.DecodeField("code", &code)
+ return
+}
+
+// Creates a session based on current App setting.
+func (app *App) Session(accessToken string) *Session {
+ return &Session{
+ accessToken: accessToken,
+ app: app,
+ enableAppsecretProof: app.EnableAppsecretProof,
+ }
+}
+
+// Creates a session from a signed request.
+// If signed request contains a code, it will automatically use this code
+// to exchange a valid access token.
+func (app *App) SessionFromSignedRequest(signedRequest string) (session *Session, err error) {
+ var res Result
+
+ res, err = app.ParseSignedRequest(signedRequest)
+
+ if err != nil {
+ return
+ }
+
+ var id, token string
+
+ res.DecodeField("user_id", &id) // it's ok without user id.
+ err = res.DecodeField("oauth_token", &token)
+
+ if err == nil {
+ session = &Session{
+ accessToken: token,
+ app: app,
+ id: id,
+ enableAppsecretProof: app.EnableAppsecretProof,
+ }
+ return
+ }
+
+ // cannot get "oauth_token"? try to get "code".
+ err = res.DecodeField("code", &token)
+
+ if err != nil {
+ // no code? no way to continue.
+ err = fmt.Errorf("cannot find 'oauth_token' and 'code'. no way to continue.")
+ return
+ }
+
+ token, err = app.ParseCode(token)
+
+ if err != nil {
+ return
+ }
+
+ session = &Session{
+ accessToken: token,
+ app: app,
+ id: id,
+ enableAppsecretProof: app.EnableAppsecretProof,
+ }
+ return
+}