package core import ( "bytes" "encoding/json" "errors" "io" "net/http" "net/url" "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" ) type GamepotTemplate struct { RedirectBaseUrl string State string } type Gamepot_LoginValidationResponse struct { Message string `json:"message"` Status int `json:"status"` } func (mg *Maingate) platform_gamepot_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") withSDK := r.URL.Query().Get("withSDK") //fmt.Println("existid =>", existid) if existid != "" { //기존 계정이 있는 경우에는 그 계정 부터 조회한다. info, err := mg.getUserTokenWithCheck(AuthPlatformGamepot, existid, browserinfo) if err == nil { if info.token != "" { params := url.Values{} params.Add("id", existid) params.Add("authtype", AuthPlatformGamepot) if withSDK == "1" { w.Write([]byte("?" + params.Encode())) } else { http.Redirect(w, r, "actionsquare://login?"+params.Encode(), http.StatusSeeOther) } return } } } sessionkey := mg.GeneratePlatformLoginNonceKey() nonce := mg.GeneratePlatformLoginNonceKey() mg.mongoClient.Delete(CollectionPlatformLoginToken, bson.M{ "platform": AuthPlatformGamepot, "key": sessionkey, }) _, _, err = mg.mongoClient.Update(CollectionPlatformLoginToken, bson.M{ "_id": primitive.NewObjectID(), }, bson.M{ "$setOnInsert": bson.M{ "platform": AuthPlatformGamepot, "key": sessionkey, "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) if withSDK == "1" { params := url.Values{} params.Add("nonce", nonce) w.Write([]byte("?" + params.Encode())) } else { var templateVar GamepotTemplate templateVar.RedirectBaseUrl = mg.RedirectBaseUrl templateVar.State = nonce mg.webTemplate[AuthPlatformGamepot].Execute(w, templateVar) } } func (mg *Maingate) platform_gamepot_authorize(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() 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 } r.ParseForm() code := r.Form.Get("code") state := r.Form.Get("state") gamepotmemberId := r.Form.Get("id") gamepotnickname := r.Form.Get("nickname") gamepotprovider := r.Form.Get("provider") gamepotproviderId := r.Form.Get("providerId") // gamepotverify := r.Form.Get("verify") // gamepotagree := r.Form.Get("agree") bSuccess, Result := mg.platform_gamepot_authorize_raw(w, brinfo, code, state, cookie.Value, gamepotmemberId, gamepotnickname, gamepotprovider, gamepotproviderId) if bSuccess { http.Redirect(w, r, "actionsquare://login?"+Result, http.StatusSeeOther) } else { http.Redirect(w, r, "actionsquare://error", http.StatusSeeOther) } } type GamePotSDKAuthInfo struct { Code string `json:"code"` State string `json:"state"` MemberId string `json:"id"` Nickname string `json:"nickname"` Provider string `json:"provider"` ProviderId string `json:"providerId"` // Verify string `json:"verify"` // Agree string `json:"agree"` } func (mg *Maingate) platform_gamepot_authorize_sdk(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() 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 } var authinfo GamePotSDKAuthInfo err = json.NewDecoder(r.Body).Decode(&authinfo) if err != nil { logger.Println("authinfo decoding fail:", err) w.WriteHeader(http.StatusBadRequest) return } bSuccess, Result := mg.platform_gamepot_authorize_raw(w, brinfo, authinfo.Code, authinfo.State, cookie.Value, authinfo.MemberId, authinfo.Nickname, authinfo.Provider, authinfo.ProviderId) if bSuccess { w.Write([]byte("?" + Result)) //http.Redirect(w, r, "actionsquare://login?"+Result, http.StatusSeeOther) } else { http.Redirect(w, r, "actionsquare://error", http.StatusSeeOther) } } func (mg *Maingate) platform_gamepot_authorize_raw(w http.ResponseWriter, brinfo, code, state, cookieSessionKey, gamepotmemberId, gamepotnickname, gamepotprovider, gamepotproviderId string) (bool, string) { found, err := mg.mongoClient.FindOne(CollectionPlatformLoginToken, bson.M{ "platform": AuthPlatformGamepot, "key": cookieSessionKey, }) if err != nil { logger.Println("LoginFlowContext_SessionKey find key :", err) w.WriteHeader(http.StatusBadRequest) return false, "" } if found == nil { logger.Println("LoginFlowContext_SessionKey not found") w.WriteHeader(http.StatusBadRequest) return false, "" } if cookieSessionKey != found["key"] { logger.Println("LoginFlowContext_SessionKey key not match") logger.Println(cookieSessionKey) logger.Println(found["key"]) w.WriteHeader(http.StatusBadRequest) return false, "" } if state != found["nonce"] { logger.Println("LoginFlowContext_SessionKey nonce not match") logger.Println(state) logger.Println(found["nonce"]) w.WriteHeader(http.StatusBadRequest) return false, "" } if brinfo != found["brinfo"] { //-- 로그인 시작점과 인증점의 브라우저 혹은 접속지 정보가 다르다? logger.Println("LoginFlowContext_SessionKey brinfo not match ") logger.Println(brinfo) logger.Println(found["brinfo"]) w.WriteHeader(http.StatusBadRequest) return false, "" } //================= params := url.Values{} params.Add("projectId", mg.GamepotProjectId) params.Add("memberId", gamepotmemberId) params.Add("token", code) var respLoginCheck Gamepot_LoginValidationResponse content := params.Encode() resp, _ := http.Post(mg.GamepotLoginCheckAPIURL, "application/json", bytes.NewBuffer([]byte(content))) if resp != nil { body, _ := io.ReadAll(resp.Body) json.Unmarshal(body, &respLoginCheck) } else { logger.Println("gamepot logincheck fail.") w.WriteHeader(http.StatusBadRequest) return false, "" } // fmt.Println("==============================") // fmt.Println("respLoginCheck.Status:", respLoginCheck.Status) // fmt.Println("respLoginCheck.Message:", respLoginCheck.Message) // fmt.Println("==============================") if respLoginCheck.Status != 0 { logger.Errorf("gamepot login fail:", respLoginCheck.Message) w.WriteHeader(http.StatusBadRequest) return false, "" } acceestoken_expire_time := time.Date(2999, 1, int(time.January), 0, 0, 0, 0, time.UTC).Unix() if gamepotmemberId != "" && gamepotprovider != "" && gamepotproviderId != "" { var info usertokeninfo info.platform = AuthPlatformGamepot info.userid = gamepotmemberId //== memberid 제외하고는 모두 client로 부터 온 값이기 때문에 유효성이 확인된 값이 아니다. 하지만, 참조용으로 사용은 한다. // 정확한 정보는 gamepotid를 gamepot dashboard에서 조회해서 확인 할 수 밖에 없다. info.token = gamepotprovider + "-" + gamepotproviderId info.brinfo = brinfo info.accesstoken = "" info.accesstoken_expire_time = acceestoken_expire_time mg.setUserToken(info) mg.mongoClient.Delete(CollectionGamepotUserInfo, bson.M{ "gamepotuserid": info.userid, }) _, _, err := mg.mongoClient.Update(CollectionGamepotUserInfo, bson.M{ "_id": primitive.NewObjectID(), }, bson.M{ "$setOnInsert": bson.M{ "gamepotuserid": gamepotmemberId, "gamepotnickname": gamepotnickname, "gamepotprovider": gamepotprovider, "gamepotproviderId": gamepotproviderId, // "gamepotverify": gamepotverify, // "gamepotagree": gamepotagree, "updatetime": time.Now(), }, }, options.Update().SetUpsert(true)) if err != nil { logger.Error(err) } params := url.Values{} params.Add("id", gamepotmemberId) params.Add("authtype", AuthPlatformGamepot) return true, params.Encode() } return false, "" } func (mg *Maingate) platform_gamepot_getuserinfo(info usertokeninfo) (bool, string, string) { found, err := mg.mongoClient.FindOne(CollectionGamepotUserInfo, bson.M{ "gamepotuserid": info.userid, }) if err != nil { logger.Error(err) return false, "", "" } if found == nil { logger.Error(errors.New("gamepot info not found: " + info.userid)) return false, "", "" } gamepotprovider := found["gamepotprovider"].(string) gamepotproviderId := found["gamepotproviderId"].(string) if gamepotprovider+"-"+gamepotproviderId != info.token { logger.Println("gamepot info not match..") //-- token은 플랫폼종류+플랫폼ID로 구성했는데... 검증할 방법이 없어서 client로 부터 온값을 쓴다. 그래도 유저가 조작하지 않는 이상 일치해야 된다. logger.Println(info.token) logger.Println(gamepotprovider + "-" + gamepotproviderId) return false, "", "" } tempEmail := info.userid + "@gamepot" //-- 게임팟은 email을 안줘서 일단 gamepotid기준으로 임시값을 할당한다. return true, info.userid, tempEmail }