oauth: add twitter
This commit is contained in:
parent
d367ac8391
commit
c07f3e8b9f
9
api/Gopkg.lock
generated
9
api/Gopkg.lock
generated
@ -25,6 +25,14 @@
|
||||
revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:d03d0fae6a7a80e89c540787a69ab6e0d3b773fdb3303c0b3d96a15490c6ef32"
|
||||
name = "github.com/gomodule/oauth1"
|
||||
packages = ["oauth"]
|
||||
pruneopts = "UT"
|
||||
revision = "9a59ed3b0a84f454c260f2f8f82918223fc5630f"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c79fb010be38a59d657c48c6ba1d003a8aa651fa56b579d959d74573b7dff8e1"
|
||||
name = "github.com/gorilla/context"
|
||||
@ -153,6 +161,7 @@
|
||||
analyzer-version = 1
|
||||
input-imports = [
|
||||
"github.com/adtac/go-akismet/akismet",
|
||||
"github.com/gomodule/oauth1/oauth",
|
||||
"github.com/gorilla/handlers",
|
||||
"github.com/gorilla/mux",
|
||||
"github.com/lib/pq",
|
||||
|
@ -50,6 +50,9 @@ func configParse() error {
|
||||
|
||||
"GITHUB_KEY": "",
|
||||
"GITHUB_SECRET": "",
|
||||
|
||||
"TWITTER_KEY": "",
|
||||
"TWITTER_SECRET": "",
|
||||
}
|
||||
|
||||
for key, value := range defaults {
|
||||
|
@ -15,5 +15,9 @@ func oauthConfigure() error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := twitterOauthConfigure(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
51
api/oauth_twitter.go
Normal file
51
api/oauth_twitter.go
Normal file
@ -0,0 +1,51 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gomodule/oauth1/oauth"
|
||||
"os"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type twitterOauthState struct {
|
||||
CommenterToken string
|
||||
Cred *oauth.Credentials
|
||||
}
|
||||
|
||||
var twitterClient *oauth.Client
|
||||
var twitterCredMapLock sync.RWMutex
|
||||
var twitterCredMap map[string]twitterOauthState
|
||||
|
||||
func twitterOauthConfigure() error {
|
||||
twitterClient = nil
|
||||
if os.Getenv("TWITTER_KEY") == "" && os.Getenv("TWITTER_SECRET") == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
if os.Getenv("TWITTER_KEY") == "" {
|
||||
logger.Errorf("COMMENTO_TWITTER_KEY not configured, but COMMENTO_TWITTER_SECRET is set")
|
||||
return errorOauthMisconfigured
|
||||
}
|
||||
|
||||
if os.Getenv("TWITTER_SECRET") == "" {
|
||||
logger.Errorf("COMMENTO_TWITTER_SECRET not configured, but COMMENTO_TWITTER_KEY is set")
|
||||
return errorOauthMisconfigured
|
||||
}
|
||||
|
||||
logger.Infof("loading twitter OAuth config")
|
||||
|
||||
twitterClient = &oauth.Client{
|
||||
TemporaryCredentialRequestURI: "https://api.twitter.com/oauth/request_token",
|
||||
ResourceOwnerAuthorizationURI: "https://api.twitter.com/oauth/authenticate",
|
||||
TokenRequestURI: "https://api.twitter.com/oauth/access_token",
|
||||
Credentials: oauth.Credentials{
|
||||
Token: os.Getenv("TWITTER_KEY"),
|
||||
Secret: os.Getenv("TWITTER_SECRET"),
|
||||
},
|
||||
}
|
||||
|
||||
configuredOauths = append(configuredOauths, "twitter")
|
||||
|
||||
twitterCredMap = make(map[string]twitterOauthState, 1e3)
|
||||
|
||||
return nil
|
||||
}
|
92
api/oauth_twitter_callback.go
Normal file
92
api/oauth_twitter_callback.go
Normal file
@ -0,0 +1,92 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
func twitterCallbackHandler(w http.ResponseWriter, r *http.Request) {
|
||||
token := r.FormValue("oauth_token")
|
||||
verifier := r.FormValue("oauth_verifier")
|
||||
|
||||
twitterCredMapLock.RLock()
|
||||
s, ok := twitterCredMap[token]
|
||||
twitterCredMapLock.RUnlock()
|
||||
|
||||
commenterToken := s.CommenterToken
|
||||
|
||||
if !ok {
|
||||
fmt.Fprintf(w, "no such token/verifier combination found")
|
||||
return
|
||||
}
|
||||
|
||||
_, err := commenterGetByCommenterToken(commenterToken)
|
||||
if err != nil && err != errorNoSuchToken {
|
||||
fmt.Fprintf(w, "Error: %s\n", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
x, _, err := twitterClient.RequestToken(nil, s.Cred, verifier)
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "Error: %s\n", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
twitterCredMapLock.Lock()
|
||||
delete(twitterCredMap, token)
|
||||
twitterCredMapLock.Unlock()
|
||||
|
||||
resp, err := twitterClient.Get(nil, x, "https://api.twitter.com/1.1/account/verify_credentials.json", url.Values{"include_email": {"true"}})
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "Error getting email: %s\n", err.Error())
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
msg, _ := ioutil.ReadAll(resp.Body)
|
||||
fmt.Fprintf(w, "Error: status %d: %s\n", resp.StatusCode, msg)
|
||||
return
|
||||
}
|
||||
|
||||
var res map[string]interface{}
|
||||
if err = json.NewDecoder(resp.Body).Decode(&res); err != nil {
|
||||
fmt.Fprintf(w, "Error: %s\n", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
name := res["name"].(string)
|
||||
handle := res["screen_name"].(string)
|
||||
link := "https://twitter.com/" + handle
|
||||
photo := "https://twitter.com/" + handle + "/profile_image"
|
||||
email := res["email"].(string)
|
||||
|
||||
c, err := commenterGetByEmail("twitter", email)
|
||||
if err != nil && err != errorNoSuchCommenter {
|
||||
fmt.Fprintf(w, "Error: %s", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
var commenterHex string
|
||||
|
||||
// TODO: in case of returning users, update the information we have on record?
|
||||
if err == errorNoSuchCommenter {
|
||||
commenterHex, err = commenterNew(email, name, link, photo, "twitter", "")
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "Error: %s", err.Error())
|
||||
return
|
||||
}
|
||||
} else {
|
||||
commenterHex = c.CommenterHex
|
||||
}
|
||||
|
||||
if err := commenterSessionUpdate(commenterToken, commenterHex); err != nil {
|
||||
fmt.Fprintf(w, "Error: %s", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, "<html><script>window.parent.close()</script></html>")
|
||||
}
|
39
api/oauth_twitter_redirect.go
Normal file
39
api/oauth_twitter_redirect.go
Normal file
@ -0,0 +1,39 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
)
|
||||
|
||||
func twitterRedirectHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if twitterClient == nil {
|
||||
logger.Errorf("twitter oauth access attempt without configuration")
|
||||
fmt.Fprintf(w, "error: this website has not configured twitter OAuth")
|
||||
return
|
||||
}
|
||||
|
||||
commenterToken := r.FormValue("commenterToken")
|
||||
|
||||
_, err := commenterGetByCommenterToken(commenterToken)
|
||||
if err != nil && err != errorNoSuchToken {
|
||||
fmt.Fprintf(w, "error: %s\n", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
cred, err := twitterClient.RequestTemporaryCredentials(nil, os.Getenv("ORIGIN")+"/api/oauth/twitter/callback", nil)
|
||||
if err != nil {
|
||||
logger.Errorf("cannot get temporary twitter credentials: %v", err)
|
||||
fmt.Fprintf(w, "error: %v", errorInternal.Error())
|
||||
return
|
||||
}
|
||||
|
||||
twitterCredMapLock.Lock()
|
||||
twitterCredMap[cred.Token] = twitterOauthState{
|
||||
CommenterToken: commenterToken,
|
||||
Cred: cred,
|
||||
}
|
||||
twitterCredMapLock.Unlock()
|
||||
|
||||
http.Redirect(w, r, twitterClient.AuthorizationURL(cred, nil), http.StatusFound)
|
||||
}
|
@ -38,6 +38,9 @@ func apiRouterInit(router *mux.Router) error {
|
||||
router.HandleFunc("/api/oauth/github/redirect", githubRedirectHandler).Methods("GET")
|
||||
router.HandleFunc("/api/oauth/github/callback", githubCallbackHandler).Methods("GET")
|
||||
|
||||
router.HandleFunc("/api/oauth/twitter/redirect", twitterRedirectHandler).Methods("GET")
|
||||
router.HandleFunc("/api/oauth/twitter/callback", twitterCallbackHandler).Methods("GET")
|
||||
|
||||
router.HandleFunc("/api/comment/new", commentNewHandler).Methods("POST")
|
||||
router.HandleFunc("/api/comment/list", commentListHandler).Methods("POST")
|
||||
router.HandleFunc("/api/comment/count", commentCountHandler).Methods("POST")
|
||||
|
@ -262,6 +262,8 @@
|
||||
attrSet(avatar, "src", commenter.photo + "?sz=50");
|
||||
} else if (commenter.provider === "github") {
|
||||
attrSet(avatar, "src", commenter.photo + "&s=50");
|
||||
} else if (commenter.provider === "twitter") {
|
||||
attrSet(avatar, "src", commenter.photo + "?size=normal");
|
||||
} else {
|
||||
attrSet(avatar, "src", commenter.photo);
|
||||
}
|
||||
@ -745,6 +747,8 @@
|
||||
attrSet(avatar, "src", commenter.photo + "?sz=50");
|
||||
} else if (commenter.provider === "github") {
|
||||
attrSet(avatar, "src", commenter.photo + "&s=50");
|
||||
} else if (commenter.provider === "twitter") {
|
||||
attrSet(avatar, "src", commenter.photo + "?size=normal");
|
||||
} else {
|
||||
attrSet(avatar, "src", commenter.photo);
|
||||
}
|
||||
|
@ -25,5 +25,12 @@
|
||||
font-size: 13px;
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
.commento-twitter-button {
|
||||
background: #00aced;
|
||||
text-transform: uppercase;
|
||||
font-size: 13px;
|
||||
width: 70px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user