maingate 이전
This commit is contained in:
417
core/platformtwitter.go
Normal file
417
core/platformtwitter.go
Normal file
@ -0,0 +1,417 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/sha1"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"repositories.action2quare.com/ayo/go-ayo/logger"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
func (mg *Maingate) platform_twitter_get_login_url(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
browserinfo, err := mg.GetUserBrowserInfo(r)
|
||||
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
logger.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
existid := r.URL.Query().Get("existid")
|
||||
//fmt.Println("existid =>", existid)
|
||||
if existid != "" {
|
||||
// 기존 계정이 있는 경우에는 그 계정 부터 조회한다.
|
||||
info, err := mg.getUserTokenWithCheck(AuthPlatformTwitter, existid, browserinfo)
|
||||
if err == nil {
|
||||
if info.token != "" {
|
||||
params := url.Values{}
|
||||
params.Add("id", existid)
|
||||
params.Add("authtype", AuthPlatformTwitter)
|
||||
http.Redirect(w, r, "actionsquare://login?"+params.Encode(), http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sessionkey := mg.GeneratePlatformLoginNonceKey()
|
||||
nonce := mg.GeneratePlatformLoginNonceKey()
|
||||
|
||||
auth_token, auth_secret := parse_TwitterOAuthToken(mg.CallTwitterAPI_WithAPPKey("https://api.twitter.com/oauth/request_token", "POST", nonce))
|
||||
|
||||
if auth_token == "" || auth_secret == "" {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
} else {
|
||||
|
||||
mg.mongoClient.Delete(CollectionPlatformLoginToken, bson.M{
|
||||
"platform": AuthPlatformTwitter,
|
||||
"key": sessionkey,
|
||||
})
|
||||
|
||||
_, _, err := mg.mongoClient.Update(CollectionPlatformLoginToken, bson.M{
|
||||
"_id": primitive.NewObjectID(),
|
||||
}, bson.M{
|
||||
"$setOnInsert": bson.M{
|
||||
"platform": AuthPlatformTwitter,
|
||||
"key": sessionkey,
|
||||
"token": auth_token,
|
||||
"secret": auth_secret,
|
||||
"nonce": nonce,
|
||||
"brinfo": browserinfo,
|
||||
},
|
||||
}, options.Update().SetUpsert(true))
|
||||
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
logger.Error(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// set cookie for storing token
|
||||
cookie := http.Cookie{
|
||||
Name: "LoginFlowContext_SessionKey",
|
||||
Value: sessionkey,
|
||||
Expires: time.Now().Add(1 * time.Hour),
|
||||
//SameSite: http.SameSiteStrictMode,
|
||||
SameSite: http.SameSiteLaxMode,
|
||||
// HttpOnly: false,
|
||||
Secure: true,
|
||||
Path: "/",
|
||||
}
|
||||
http.SetCookie(w, &cookie)
|
||||
|
||||
params := url.Values{}
|
||||
params.Add("oauth_token", auth_token)
|
||||
http.Redirect(w, r, "https://api.twitter.com/oauth/authorize?"+params.Encode(), http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func (mg *Maingate) platform_twitter_authorize(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// defer r.Body.Close()
|
||||
// body, _ := io.ReadAll(r.Body)
|
||||
// bodyString := string(body)
|
||||
|
||||
// oauth_token := r.URL.Query().Get("oauth_token")
|
||||
// oauth_verifier := r.URL.Query().Get("oauth_verifier")
|
||||
// fmt.Println("bodyString")
|
||||
// fmt.Println(bodyString)
|
||||
// fmt.Println("=======================")
|
||||
// fmt.Println("Req: %s %s", r.URL.Host, r.URL.Path)
|
||||
// fmt.Println(oauth_token, oauth_verifier)
|
||||
// fmt.Println("=======================")
|
||||
|
||||
// set cookie for storing token
|
||||
cookie := http.Cookie{
|
||||
Name: "LoginFlowContext_code",
|
||||
Value: r.URL.Query().Encode(),
|
||||
Expires: time.Now().Add(1 * time.Minute),
|
||||
SameSite: http.SameSiteLaxMode,
|
||||
Secure: true,
|
||||
Path: "/",
|
||||
}
|
||||
http.SetCookie(w, &cookie)
|
||||
|
||||
http.Redirect(w, r, mg.RedirectBaseUrl+"/authorize_result/"+AuthPlatformTwitter, http.StatusSeeOther) //-- 바로 받으니까 쿠키 안와서 한번 더 Redirect 시킨다.
|
||||
}
|
||||
|
||||
func (mg *Maingate) platform_twitter_authorize_result(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
brinfo, err := mg.GetUserBrowserInfo(r)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
logger.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
cookie, err := r.Cookie("LoginFlowContext_SessionKey")
|
||||
if err != nil {
|
||||
logger.Println("Session not found", err)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
cookiecode, err := r.Cookie("LoginFlowContext_code")
|
||||
if err != nil {
|
||||
logger.Println("code not found", err)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
code := cookiecode.Value
|
||||
found, err := mg.mongoClient.FindOne(CollectionPlatformLoginToken, bson.M{
|
||||
"key": cookie.Value,
|
||||
"platform": AuthPlatformTwitter,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
logger.Println("LoginFlowContext_SessionKey find key :", err)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if found == nil {
|
||||
logger.Println("LoginFlowContext_SessionKey not found")
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if cookie.Value != found["key"] {
|
||||
logger.Println("LoginFlowContext_SessionKey key not match")
|
||||
logger.Println(cookie.Value)
|
||||
logger.Println(found["key"])
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if brinfo != found["brinfo"] { //-- 로그인 시작점과 인증점의 브라우저 혹은 접속지 정보가 다르다?
|
||||
logger.Println("LoginFlowContext_SessionKey brinfo not match ")
|
||||
logger.Println(brinfo)
|
||||
logger.Println(found["brinfo"])
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
urlvalue, err := url.ParseQuery(code)
|
||||
if err != nil {
|
||||
logger.Println("Token parse error")
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
//===
|
||||
|
||||
oauth_token := urlvalue.Get("oauth_token")
|
||||
oauth_verifier := urlvalue.Get("oauth_verifier")
|
||||
if oauth_token == "" || oauth_verifier == "" {
|
||||
w.WriteHeader(400)
|
||||
return
|
||||
}
|
||||
|
||||
userid, token, secret := getTwitterAccessToken("https://api.twitter.com/oauth/access_token?oauth_token=" + oauth_token + "&oauth_verifier=" + oauth_verifier)
|
||||
|
||||
if userid != "" && token != "" && secret != "" {
|
||||
|
||||
var info usertokeninfo
|
||||
info.platform = AuthPlatformTwitter
|
||||
info.userid = userid
|
||||
info.token = token
|
||||
info.secret = secret
|
||||
info.brinfo = brinfo
|
||||
|
||||
mg.setUserToken(info)
|
||||
params := url.Values{}
|
||||
params.Add("id", userid)
|
||||
params.Add("authtype", AuthPlatformTwitter)
|
||||
http.Redirect(w, r, "actionsquare://login?"+params.Encode(), http.StatusSeeOther)
|
||||
} else {
|
||||
http.Redirect(w, r, "actionsquare://error", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (mg *Maingate) platform_twitter_getuserinfo(token, secret string) (bool, string, string) {
|
||||
|
||||
result := mg.CallTwitterAPI("https://api.twitter.com/2/users/me", "GET", token, secret, mg.GeneratePlatformLoginNonceKey())
|
||||
|
||||
var TwitterUserInfo struct {
|
||||
Data struct {
|
||||
Id string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Username string `json:"username"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
err := json.Unmarshal([]byte(result), &TwitterUserInfo)
|
||||
if err != nil {
|
||||
logger.Error("twitter userinfo api unmarshal fail :", result)
|
||||
return false, "", ""
|
||||
}
|
||||
|
||||
// fmt.Println("=====================")
|
||||
// fmt.Println(result)
|
||||
// fmt.Println(TwitterUserInfo.Data.Id)
|
||||
// fmt.Println(TwitterUserInfo.Data.Name)
|
||||
// fmt.Println(TwitterUserInfo.Data.Username)
|
||||
// fmt.Println("=====================")
|
||||
|
||||
return true, TwitterUserInfo.Data.Id, ""
|
||||
}
|
||||
|
||||
func (mg *Maingate) CallTwitterAPI_WithAPPKey(requesturl, method, nonce string) string {
|
||||
return mg.CallTwitterAPI(requesturl, method, mg.TwitterOAuthKey, mg.TwitterOAuthSecret, nonce)
|
||||
}
|
||||
|
||||
func (mg *Maingate) CallTwitterAPI(requesturl, method, oauth_token, oauth_secret, nonce string) string {
|
||||
vals := url.Values{}
|
||||
|
||||
if method == "GET" {
|
||||
splited := strings.Split(requesturl, "?")
|
||||
if len(splited) > 1 {
|
||||
parameter := splited[1]
|
||||
args := strings.Split(parameter, "&")
|
||||
for _, arg := range args {
|
||||
tempsplited := strings.Split(arg, "=")
|
||||
if len(tempsplited) == 2 {
|
||||
vals.Add(tempsplited[0], tempsplited[1])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//vals.Add("oauth_callback", "actionclient://callback")
|
||||
//vals.Add("oauth_callback", "http://127.0.0.1:7770/auth")
|
||||
|
||||
vals.Add("oauth_callback", mg.RedirectBaseUrl+"/authorize/"+AuthPlatformTwitter)
|
||||
vals.Add("oauth_consumer_key", mg.TwitterCustomerKey)
|
||||
vals.Add("oauth_token", oauth_token)
|
||||
vals.Add("oauth_signature_method", "HMAC-SHA1")
|
||||
vals.Add("oauth_timestamp", strconv.Itoa(int(time.Now().Unix())))
|
||||
vals.Add("oauth_nonce", nonce)
|
||||
vals.Add("oauth_version", "1.0")
|
||||
|
||||
parameterString := strings.Replace(vals.Encode(), "+", "%20", -1)
|
||||
signatureBase := strings.ToUpper(method) + "&" + url.QueryEscape(strings.Split(requesturl, "?")[0]) + "&" + url.QueryEscape(parameterString)
|
||||
signingKey := url.QueryEscape(mg.TwitterCustomerSecret) + "&" + url.QueryEscape(oauth_secret)
|
||||
signature := calculateTwitterSignature(signatureBase, signingKey)
|
||||
|
||||
headerString := "OAuth oauth_callback=\"" + url.QueryEscape(vals.Get("oauth_callback")) + "\", oauth_consumer_key=\"" + url.QueryEscape(vals.Get("oauth_consumer_key")) + "\", oauth_nonce=\"" + url.QueryEscape(vals.Get("oauth_nonce")) +
|
||||
"\", oauth_signature=\"" + url.QueryEscape(signature) + "\", oauth_signature_method=\"" + url.QueryEscape(vals.Get("oauth_signature_method")) +
|
||||
"\", oauth_timestamp=\"" + url.QueryEscape(vals.Get("oauth_timestamp")) + "\", oauth_token=\"" + url.QueryEscape(vals.Get("oauth_token")) +
|
||||
"\", oauth_version=\"" + url.QueryEscape(vals.Get("oauth_version")) + "\""
|
||||
|
||||
client := &http.Client{}
|
||||
|
||||
req, err := http.NewRequest(method, requesturl, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||
req.Header.Add("Content-Length", "0")
|
||||
req.Header.Add("Accept-Encoding", "application/json")
|
||||
req.Header.Add("Host", "api.twitter.com")
|
||||
req.Header.Add("Accept", "*/*")
|
||||
req.Header.Add("Authorization", headerString)
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
strBody := ""
|
||||
respBody, err := io.ReadAll(resp.Body)
|
||||
if err == nil {
|
||||
strBody = string(respBody)
|
||||
}
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
logger.Error("Error: ", resp.StatusCode, err, strBody)
|
||||
return "error"
|
||||
}
|
||||
|
||||
return strBody
|
||||
}
|
||||
|
||||
func getTwitterAccessToken(requesturl string) (string, string, string) {
|
||||
|
||||
client := &http.Client{}
|
||||
|
||||
req, err := http.NewRequest("POST", requesturl, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||
req.Header.Add("Content-Length", "0")
|
||||
req.Header.Add("Accept-Encoding", "application/json")
|
||||
req.Header.Add("Host", "api.twitter.com")
|
||||
req.Header.Add("Accept", "*/*")
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
return "", "", ""
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
strBody := ""
|
||||
respBody, err := io.ReadAll(resp.Body)
|
||||
if err == nil {
|
||||
strBody = string(respBody)
|
||||
}
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
logger.Error("Error: ", resp.StatusCode, err, strBody)
|
||||
return "", "", ""
|
||||
}
|
||||
|
||||
params := strings.Split(strBody, "&")
|
||||
oauth_token := ""
|
||||
oauth_secret := ""
|
||||
user_id := ""
|
||||
//screen_name := ""
|
||||
for _, param := range params {
|
||||
parsedStr := strings.Split(param, "=")
|
||||
if len(parsedStr) == 2 {
|
||||
if parsedStr[0] == "oauth_token" {
|
||||
oauth_token = parsedStr[1]
|
||||
}
|
||||
if parsedStr[0] == "oauth_token_secret" {
|
||||
oauth_secret = parsedStr[1]
|
||||
}
|
||||
if parsedStr[0] == "user_id" {
|
||||
user_id = parsedStr[1]
|
||||
}
|
||||
// if parsedStr[0] == "screen_name" {
|
||||
// screen_name = parsedStr[1]
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
// ret := ""
|
||||
|
||||
// if oauth_token != "" && oauth_secret != "" && user_id != "" && screen_name != "" {
|
||||
// ret = "{ \"AuthToken\": \"" + oauth_token + "\", \"UserId\": \"" + user_id + "\", \"Screen_name\": \"" + screen_name + "\" }"
|
||||
// }
|
||||
// return ret, user_id, oauth_token, oauth_secret
|
||||
return user_id, oauth_token, oauth_secret
|
||||
}
|
||||
|
||||
func calculateTwitterSignature(base, key string) string {
|
||||
hash := hmac.New(sha1.New, []byte(key))
|
||||
hash.Write([]byte(base))
|
||||
signature := hash.Sum(nil)
|
||||
return base64.StdEncoding.EncodeToString(signature)
|
||||
}
|
||||
|
||||
func parse_TwitterOAuthToken(strBody string) (string, string) {
|
||||
params := strings.Split(strBody, "&")
|
||||
oauth_token := ""
|
||||
oauth_secret := ""
|
||||
for _, param := range params {
|
||||
parsedStr := strings.Split(param, "=")
|
||||
|
||||
if len(parsedStr) == 2 {
|
||||
if parsedStr[0] == "oauth_token" {
|
||||
oauth_token = parsedStr[1]
|
||||
}
|
||||
if parsedStr[0] == "oauth_token_secret" {
|
||||
oauth_secret = parsedStr[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return oauth_token, oauth_secret
|
||||
}
|
||||
Reference in New Issue
Block a user