sahat/satellizer

View on GitHub
examples/server/go/oauth.go

Summary

Maintainability
C
1 day
Test Coverage
package main

import (
    "encoding/json"
    "errors"
    "io"
    "io/ioutil"
    "log"
    "net/http"
    "strings"

    "github.com/mrjones/oauth"
    "gopkg.in/mgo.v2"
    "gopkg.in/mgo.v2/bson"
)

func LoginWithTwitter(w http.ResponseWriter, r *http.Request) {

    c := oauth.NewConsumer(
        config.TWITTER_KEY,
        config.TWITTER_SECRET,
        oauth.ServiceProvider{
            RequestTokenUrl:   "https://api.twitter.com/oauth/request_token",
            AuthorizeTokenUrl: "https://api.twitter.com/oauth/authenticate",
            AccessTokenUrl:    "https://api.twitter.com/oauth/access_token",
        })

    profileUrl := "https://api.twitter.com/1.1/users/show.json"

    decoder := json.NewDecoder(r.Body)
    var requestPayload struct {
        OAuthToken    string `json:"oauth_token"`
        OAuthVerifier string `json:"oauth_verifier"`
    }
    err := decoder.Decode(&requestPayload)
    if err != nil && err != io.EOF {
        log.Println(err)
        return
    }

    // Part 1/2: Initial request from Satellizer.
    if requestPayload.OAuthToken == "" || requestPayload.OAuthVerifier == "" {

        // Step 1. Obtain request token for the authorization popup.
        requestToken, _, err := c.GetRequestTokenAndUrl(config.TWITTER_CALLBACK)
        if err != nil {
            log.Println(err)
            return
        }

        // Step 2. Redirect to the authorization screen.
        ServeJSON(w, r, &Response{
            "oauth_token":              requestToken.Token,
            "oauth_token_secret":       requestToken.Secret,
            "oauth_callback_confirmed": "true",
        }, 200)
    } else {
        // Part 2/2: Second request after Authorize app is clicked.
        requestToken := &oauth.RequestToken{requestPayload.OAuthToken, config.TWITTER_SECRET}

        // Step 3. Exchange oauth token and oauth verifier for access token.
        accessToken, err := c.AuthorizeToken(requestToken, requestPayload.OAuthVerifier)
        if err != nil {
            log.Println(err)
            return
        }

        // Step 4. Retrieve profile information about the current user.
        response, err := c.Get(
            profileUrl,
            map[string]string{"screen_name": accessToken.AdditionalData["screen_name"]},
            accessToken)

        if err != nil {
            log.Fatal(err)
        }
        defer response.Body.Close()

        bits, err := ioutil.ReadAll(response.Body)

        var profileData map[string]interface{}
        err = json.Unmarshal(bits, &profileData)

        db := GetDB(w, r)

        if IsTokenSet(r) {
            // Step 5a. Link user accounts.
            existingUser, errM := FindUserByProvider(db, "twitter", accessToken.AdditionalData["user_id"])
            if existingUser != nil {
                ServeJSON(w, r, &Response{
                    "message": "There is already a Twitter account that belongs to you",
                }, 409)
                return
            }

            if errM != nil && errM.Reason != mgo.ErrNotFound {
                HandleModelError(w, r, errM)
                return
            }

            tokenData := GetToken(w, r)
            user, errM := FindUserById(db, bson.ObjectIdHex(tokenData.ID))
            if user == nil {
                ServeJSON(w, r, &Response{
                    "message": "User not found",
                }, 400)
                return
            }

            if errM != nil && errM.Reason != mgo.ErrNotFound {
                HandleModelError(w, r, errM)
                return
            }

            user.Twitter = accessToken.AdditionalData["user_id"]
            if user.DisplayName == "" {
                user.DisplayName = accessToken.AdditionalData["screen_name"]
            }
            if user.Picture == "" {
                user.Picture = strings.Replace(profileData["profile_image_url"].(string), "_normal", "", 1)
            }

            err = user.Save(db)
            if err != nil {
                ISR(w, r, errors.New("Couldn't save user profile informations"))
            }

            SetToken(w, r, user)

        } else {
            // Step 5b. Create a new user account or return an existing one.
            existingUser, errM := FindUserByProvider(db, "twitter", accessToken.AdditionalData["user_id"])
            if existingUser != nil {
                SetToken(w, r, existingUser)
                return
            }
            if errM != nil && errM.Reason != mgo.ErrNotFound {
                HandleModelError(w, r, errM)
                return
            }

            user := NewUser()
            user.Email = accessToken.AdditionalData["user_id"] + "-satellizer@twitter.com"
            user.Twitter = accessToken.AdditionalData["user_id"]
            user.DisplayName = accessToken.AdditionalData["screen_name"]
            user.Picture = strings.Replace(profileData["profile_image_url"].(string), "_normal", "", 1)
            err = user.Save(db)
            if err != nil {
                ISR(w, r, err)
                return
            }

            SetToken(w, r, user)
        }

    }
}