Compare commits

..

75 Commits

Author SHA1 Message Date
e37a974d9c [이민권] 계정 삭제
- 계정 삭제 시, Firebase 정보 삭제
2024-01-12 12:31:21 +09:00
470591cb44 [이민권] 계정 삭제
- 계정 삭제 취소 기능 추가
2024-01-11 19:11:43 +09:00
38114769b3 [이민권] 계정 삭제
- 계정 삭제 취소 기능 추가
2024-01-11 12:54:48 +09:00
b05473a1c6 [이민권] 계정 삭제
- 계정 삭제 취소 기능 추가
2024-01-10 18:40:38 +09:00
0fff694e8a [이민권] 계정 삭제
- 계정 삭제 취소 기능 추가
2024-01-10 18:10:18 +09:00
d8713298c4 [이민권] 계정 삭제
- 계정 삭제 취소 기능 추가
2024-01-10 17:35:00 +09:00
763b0fc4bd [이민권] 계정 삭제
- 계정 삭제 취소 기능 추가
2024-01-10 17:28:24 +09:00
d8e18d7ffc [이민권] 서비스 준비
- 계정 삭제 시, TTL 적용
2024-01-09 19:56:57 +09:00
381f1edb80 [이민우] 정보가 아니라 주소갑이 나와서 수정 (대리 커밋) 2023-12-08 17:08:14 +09:00
a8e448b8ca 로그 정리 2023-10-30 17:25:39 +09:00
9b0e3a5d5b 모듈 정리 2023-10-30 17:25:31 +09:00
5757a81cb8 fba, template 폴더를 package 에 추가 2023-10-24 14:05:42 +09:00
c4b8e630dc [이민권] 에러 수정 2023-10-23 15:17:07 +09:00
43b0242652 Firebase-Google Analaytics Desktop 버전 연동을 위해서 JavaScript SDK( JS-SDk ) 관련 코드 추가 2023-10-23 15:08:48 +09:00
893744a1ab Revert "모듈 업데이트"
This reverts commit 192cc569b4.
2023-10-12 12:04:49 +09:00
192cc569b4 모듈 업데이트 2023-10-12 12:04:31 +09:00
56e6608537 화이트리스트 추가,삭제 반영 안되는 문제 수정 2023-10-05 11:08:09 +09:00
0053033e32 현재 block된 정보를 조회 2023-09-25 12:29:41 +09:00
d1ff6a56fc gocommon 업데이트 반영 2023-09-21 13:18:41 +09:00
114461c51d 화이트리스트 추가 안되는 문제 수정 2023-09-12 17:07:16 +09:00
117a3e5d90 [이민우] 캐릭터 생성 제한 구현 (대신 커밋) 2023-09-08 18:24:17 +09:00
fafc463f2a [이민우] 캐릭터 생성 제한 구현 (대신 커밋) 2023-09-06 19:34:47 +09:00
e2bec481f0 [이민우] 캐릭터 생성 제한 구현 (대신 커밋) 2023-09-06 17:11:47 +09:00
89e7d35b5a [이민권] 오타 수정 2023-09-06 11:35:21 +09:00
fe662c5355 [이민우] 캐릭터 생성 제한 구현 (대신 커밋) 2023-09-06 11:23:06 +09:00
6767a37704 version split 수정 2023-09-05 17:14:56 +09:00
2ea035a43b version split 수정 2023-09-04 11:15:23 +09:00
2a1ad499ed [이민우] 캐릭터 생성 제한 구현 (대신 커밋) 2023-08-31 17:19:18 +09:00
5cc6ddc8f1 [이민우] 캐릭터 생성 제한 구현 (대신 커밋) 2023-08-31 11:55:31 +09:00
0e070221f8 Merge branch 'master' into kd-live 2023-08-29 18:41:22 +09:00
d2e06961b9 [이민권] guest 계정에 link 걸면 guest link는 제거하도록 수정 2023-08-24 16:45:01 +09:00
28092fcf17 [이민권] 게스트 계정 링크 시 삭제 기능 추가 2023-08-24 15:39:11 +09:00
c43c10982c [이민권] link 수정 2023-08-23 19:03:28 +09:00
02c4f9e3d1 [이민권] link, unlink 이슈 수정 2023-08-23 18:53:24 +09:00
1db22730aa [이민권] linkinfo 이슈 수정 2023-08-23 18:46:23 +09:00
869fa48d74 Revert "[이민권] 임시 로그 삽입"
This reverts commit 7470f8e001.
2023-08-22 18:32:37 +09:00
7470f8e001 [이민권] 임시 로그 삽입 2023-08-22 18:27:04 +09:00
fc70a9482c [이민권] getProviderInfo 실패시 리턴하지 않는 부분 수정 2023-08-22 18:22:31 +09:00
9ccd97564a [이민권] Unlink 수정 2023-08-22 15:38:51 +09:00
4958cb0b93 [이민권] linkinfo 로그 수정 2023-08-21 19:18:27 +09:00
9c14480be7 [이민권] 게스트 상태에서 링크하는 경우 수정 2023-08-18 17:06:21 +09:00
daf3e3f027 version split 디폴트 이름 변경 2023-08-18 13:56:51 +09:00
2de82b9d2a [이민권] 계정 정보 받아오는 함수 수정 2023-08-17 19:13:01 +09:00
00c2d6e205 [이민권] 언더바 빼먹은거 수정 2023-08-17 18:31:41 +09:00
87d922c558 [이민권] 크래쉬 수정 2023-08-17 18:21:01 +09:00
0be7adefe3 [이민권] api 수정
- unlink시 link collection에 doc 남겨지는 이슈 수정
- linkinfo api가 단순 link 갯수가 아니라 어떤 platform에 연동 하였는지 반환하도록 수정
- 계정 삭제 api인 delacc api 추가
2023-08-17 14:23:00 +09:00
3a9f81f1cb divisionsSerialized가 잘못 덮어씌어진 문제 수정 2023-08-17 12:36:04 +09:00
a97b9f0983 Merge branch 'master' into kd-live 2023-08-16 21:44:47 +09:00
9edea29983 Merge branch 'master' into kd-live 2023-08-09 17:39:30 +09:00
8e908982a8 Merge branch 'master' into kd-live 2023-08-09 17:24:40 +09:00
6b68d918ba 모듈 업데이트 2023-08-01 14:18:38 +09:00
3216e2620a Merge branch 'master' into kd-live 2023-07-10 18:12:57 +09:00
f66904d428 Merge branch 'master' into kd-live 2023-07-07 15:33:18 +09:00
8d70777269 안쓰는 로그 제거 2023-06-30 18:04:25 +09:00
15ead6b0bc Merge branch 'master' into kd-live 2023-06-30 18:01:43 +09:00
97636ce31d Merge branch 'master' into kd-live 2023-06-29 21:32:19 +09:00
2b4becdb61 Merge branch 'master' into kd-live 2023-06-29 21:22:19 +09:00
429bbd1e7a Merge branch 'master' into kd-live 2023-06-29 16:09:40 +09:00
1c397da77a Merge branch 'master' into kd-live 2023-06-28 16:45:34 +09:00
5502c4d744 Merge commit 'cb08ecb53a4d472919f24baaf4e8069412c2870c' into kd-live 2023-06-28 16:18:48 +09:00
cb793092e9 Merge branch 'master' into kd-live 2023-06-28 15:28:11 +09:00
13f6492e5f Merge branch 'master' into kd-live 2023-06-28 15:17:21 +09:00
f739eb3a8b Merge branch 'master' into kd-live 2023-06-27 19:13:19 +09:00
c95d7747cd Merge branch 'master' into kd-live 2023-06-27 19:04:01 +09:00
841dad4992 Merge branch 'master' into kd-live 2023-06-27 18:51:12 +09:00
ff7d56152e Merge branch 'master' into kd-live 2023-06-26 17:34:42 +09:00
2acca6dbe8 Merge branch 'master' into kd-live 2023-06-23 17:58:56 +09:00
484db90037 로그 추가 2023-06-23 17:35:25 +09:00
b06eb86578 되돌림을 되돌림 2023-06-23 17:21:36 +09:00
9704decb7a 되돌림 2023-06-23 17:05:19 +09:00
767d6bf002 Merge branch 'master' into kd-live 2023-06-23 16:53:16 +09:00
1f7421dd2e Merge branch 'master' into kd-live 2023-06-23 16:43:32 +09:00
53701d61f8 Merge branch 'master' into kd-live 2023-06-23 16:27:35 +09:00
6d02eb092c 로그 추가 2023-06-23 16:27:31 +09:00
7bee78a875 live용 설정 추가 2023-06-22 20:20:50 +09:00
12 changed files with 709 additions and 258 deletions

View File

@ -1,9 +1,7 @@
{ {
"maingate_mongodb_url": "mongodb://...", "maingate_mongodb_url": "mongodb://...",
"session_storage": "",
"session_ttl" : 3600,
"autologin_ttl": 604800, "autologin_ttl": 604800,
"acc_del_ttl": 7776000,
"maximum_num_link_account": 10, "maximum_num_link_account": 10,
"redirect_base_url": "", "redirect_base_url": "",
"google_client_id" : "", "google_client_id" : "",

View File

@ -199,8 +199,6 @@ func (caller apiCaller) blockAPI(w http.ResponseWriter, r *http.Request) error {
if err != nil { if err != nil {
return err return err
} }
mg.sessionProvider.Delete(accid)
} else if r.Method == "DELETE" { } else if r.Method == "DELETE" {
id := r.URL.Query().Get("id") id := r.URL.Query().Get("id")
@ -223,6 +221,8 @@ func (caller apiCaller) blockAPI(w http.ResponseWriter, r *http.Request) error {
if err != nil { if err != nil {
return err return err
} }
mg.mongoClient.Delete(CollectionAuth, bson.M{"_id": idobj})
} }
return nil return nil
} }
@ -239,7 +239,7 @@ func (caller apiCaller) whitelistAPI(w http.ResponseWriter, r *http.Request) err
return err return err
} }
member.ExpiredAt = 0 member.ExpiredAt = 0
member.Id = primitive.NilObjectID
_, _, err := mg.mongoClient.Update(CollectionWhitelist, bson.M{ _, _, err := mg.mongoClient.Update(CollectionWhitelist, bson.M{
"_id": primitive.NewObjectID(), "_id": primitive.NewObjectID(),
}, bson.M{ }, bson.M{
@ -403,6 +403,40 @@ func (caller apiCaller) configAPI(w http.ResponseWriter, r *http.Request) error
return nil return nil
} }
func (caller apiCaller) lockcreatecharAPI(w http.ResponseWriter, r *http.Request) error {
mg, err := caller.mg.mongoClient.FindAll(CollectionService, bson.M{})
if err != nil {
return err
}
haschr, _ := gocommon.ReadStringFormValue(r.Form, "haschr")
locked := make(map[string]any)
if haschr == "true" {
locked["lock"] = false
} else {
curregion, _ := gocommon.ReadStringFormValue(r.Form, "region")
for _, regioninfo := range mg {
region := regioninfo["divisions"].(primitive.M)
for idx, rl := range region {
if idx == curregion {
if rl.(primitive.M)["lockcreatechar"].(bool) {
locked["lock"] = true
} else {
locked["lock"] = false
}
}
}
}
}
create, _ := json.Marshal(locked)
w.Write(create)
return nil
}
type apiCaller struct { type apiCaller struct {
userinfo map[string]any userinfo map[string]any
globalAdmins map[string]bool globalAdmins map[string]bool
@ -509,6 +543,8 @@ func (mg *Maingate) api(w http.ResponseWriter, r *http.Request) {
err = caller.blockAPI(w, r) err = caller.blockAPI(w, r)
} else if strings.HasSuffix(r.URL.Path, "/coupon") { } else if strings.HasSuffix(r.URL.Path, "/coupon") {
err = caller.couponAPI(w, r) err = caller.couponAPI(w, r)
} else if strings.HasSuffix(r.URL.Path, "/lockcreatechar") {
err = caller.lockcreatecharAPI(w, r)
} }
if err != nil { if err != nil {

View File

@ -44,17 +44,17 @@ func makeCouponKey(roundnum uint32, uid []byte) string {
return fmt.Sprintf("%s-%s-%s-%s", hex.EncodeToString(final[0:2]), hex.EncodeToString(final[2:4]), hex.EncodeToString(final[4:6]), hex.EncodeToString(final[6:8])) return fmt.Sprintf("%s-%s-%s-%s", hex.EncodeToString(final[0:2]), hex.EncodeToString(final[2:4]), hex.EncodeToString(final[4:6]), hex.EncodeToString(final[6:8]))
} }
var r = rand.New(rand.NewSource(time.Now().UnixNano()))
func makeCouponCodes(name string, count int) (string, map[string]string) { func makeCouponCodes(name string, count int) (string, map[string]string) {
checkunique := make(map[string]bool) checkunique := make(map[string]bool)
keys := make(map[string]string) keys := make(map[string]string)
uid := make([]byte, 4) uid := make([]byte, 4)
roundHash, roundnum := coupon.MakeCouponRoundHash(name) roundHash, roundnum := coupon.MakeCouponRoundHash(name)
seed := time.Now().UnixNano()
for len(keys) < count { for len(keys) < count {
r.Read(uid) rand.Seed(seed)
rand.Read(uid)
code := makeCouponKey(roundnum, uid) code := makeCouponKey(roundnum, uid)
@ -62,6 +62,7 @@ func makeCouponCodes(name string, count int) (string, map[string]string) {
checkunique[code] = true checkunique[code] = true
keys[hex.EncodeToString(uid)] = code keys[hex.EncodeToString(uid)] = code
} }
seed = int64(binary.BigEndian.Uint32(uid))
} }
return roundHash, keys return roundHash, keys
} }

View File

@ -21,7 +21,7 @@ func TestMakeLocalUniqueId(t *testing.T) {
fmt.Println(start.Time().Format(time.RFC3339)) fmt.Println(start.Time().Format(time.RFC3339))
fmt.Println(end.Time().Format(time.RFC3339)) fmt.Println(end.Time().Format(time.RFC3339))
mongoClient, err := gocommon.NewMongoClient(context.Background(), "mongodb://121.134.91.160:27018/?replicaSet=rs0&retrywrites=true") mongoClient, err := gocommon.NewMongoClient(context.Background(), "mongodb://121.134.91.160:27018/mountain-maingate?replicaSet=rs0&retrywrites=true", "maingate")
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }

View File

@ -9,9 +9,11 @@ import (
"fmt" "fmt"
"io" "io"
"math/big" "math/big"
"math/rand"
"net" "net"
"net/http" "net/http"
"os" "os"
"runtime/debug"
"strings" "strings"
"sync/atomic" "sync/atomic"
"text/template" "text/template"
@ -21,7 +23,6 @@ import (
"repositories.action2quare.com/ayo/gocommon" "repositories.action2quare.com/ayo/gocommon"
"repositories.action2quare.com/ayo/gocommon/flagx" "repositories.action2quare.com/ayo/gocommon/flagx"
"repositories.action2quare.com/ayo/gocommon/logger" "repositories.action2quare.com/ayo/gocommon/logger"
"repositories.action2quare.com/ayo/gocommon/session"
"github.com/golang-jwt/jwt" "github.com/golang-jwt/jwt"
"go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson"
@ -39,6 +40,7 @@ var noauth = flagx.Bool("noauth", false, "")
var ( var (
CollectionLink = gocommon.CollectionName("link") CollectionLink = gocommon.CollectionName("link")
CollectionAuth = gocommon.CollectionName("auth")
CollectionWhitelist = gocommon.CollectionName("whitelist") CollectionWhitelist = gocommon.CollectionName("whitelist")
CollectionService = gocommon.CollectionName("service") CollectionService = gocommon.CollectionName("service")
CollectionAccount = gocommon.CollectionName("account") CollectionAccount = gocommon.CollectionName("account")
@ -72,10 +74,57 @@ func SessionTTL() time.Duration {
return sessionTTL return sessionTTL
} }
type mongoAuthCell struct {
src *gocommon.Authinfo
}
func (ac *mongoAuthCell) ToAuthinfo() *gocommon.Authinfo {
if ac.src == nil {
logger.Error("mongoAuthCell ToAuthinfo failed. ac.src is nil")
}
return ac.src
}
func (ac *mongoAuthCell) ToBytes() []byte {
bt, _ := json.Marshal(ac.src)
return bt
}
func makeAuthCollection(mongoClient gocommon.MongoClient, sessionTTL time.Duration) *gocommon.AuthCollection {
authcoll := gocommon.MakeAuthCollection(sessionTTL)
authcoll.SessionRemoved = func(sk string) {
skid, _ := primitive.ObjectIDFromHex(sk)
mongoClient.Delete(CollectionAuth, bson.M{
"sk": skid,
})
}
authcoll.QuerySession = func(sk string, token string) gocommon.AuthinfoCell {
skid, _ := primitive.ObjectIDFromHex(sk)
var outcell mongoAuthCell
err := mongoClient.FindOneAs(CollectionAuth, bson.M{
"sk": skid,
}, &outcell.src, options.FindOne().SetHint("skonly"))
if err != nil {
logger.Error("QuerySession failed :", err)
return nil
}
if outcell.src == nil {
return nil
}
return &outcell
}
return authcoll
}
type maingateConfig struct { type maingateConfig struct {
session.SessionConfig `json:",inline"`
Mongo string `json:"maingate_mongodb_url"` Mongo string `json:"maingate_mongodb_url"`
SessionTTL int64 `json:"maingate_session_ttl"`
Autologin_ttl int64 `json:"autologin_ttl"` Autologin_ttl int64 `json:"autologin_ttl"`
AccDelTTL int64 `json:"acc_del_ttl"`
MaximumNumLinkAccount int64 `json:"maximum_num_link_account"` MaximumNumLinkAccount int64 `json:"maximum_num_link_account"`
RedirectBaseUrl string `json:"redirect_base_url"` RedirectBaseUrl string `json:"redirect_base_url"`
GoogleClientId string `json:"google_client_id"` GoogleClientId string `json:"google_client_id"`
@ -131,7 +180,7 @@ type Maingate struct {
mongoClient gocommon.MongoClient mongoClient gocommon.MongoClient
sessionProvider session.Provider auths *gocommon.AuthCollection
//services servicelist //services servicelist
serviceptr unsafe.Pointer serviceptr unsafe.Pointer
admins unsafe.Pointer admins unsafe.Pointer
@ -158,10 +207,6 @@ func New(ctx context.Context) (*Maingate, error) {
admins.parse() admins.parse()
} }
if len(config.SessionStorage) == 0 {
return nil, errors.New("maingate_session_storage is missing")
}
if config.SessionTTL == 0 { if config.SessionTTL == 0 {
config.SessionTTL = 3600 config.SessionTTL = 3600
} }
@ -256,96 +301,110 @@ func (mg *Maingate) discoverOpenIdConfiguration(name string, url string) error {
} }
func makeErrorWithStack(err error) error {
return fmt.Errorf("%s\n%s", err.Error(), string(debug.Stack()))
}
func (mg *Maingate) prepare(context context.Context) (err error) { func (mg *Maingate) prepare(context context.Context) (err error) {
if err := mg.discoverOpenIdConfiguration(AuthPlatformMicrosoft, "https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration"); err != nil { if err := mg.discoverOpenIdConfiguration(AuthPlatformMicrosoft, "https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration"); err != nil {
return logger.ErrorWithCallStack(err) return makeErrorWithStack(err)
} }
if err := mg.discoverOpenIdConfiguration("google", "https://accounts.google.com/.well-known/openid-configuration"); err != nil { if err := mg.discoverOpenIdConfiguration("google", "https://accounts.google.com/.well-known/openid-configuration"); err != nil {
return logger.ErrorWithCallStack(err) return makeErrorWithStack(err)
} }
// redis에서 env를 가져온 후에 // redis에서 env를 가져온 후에
mg.mongoClient, err = gocommon.NewMongoClient(context, mg.Mongo) mg.mongoClient, err = gocommon.NewMongoClient(context, mg.Mongo, "maingate")
if err != nil { if err != nil {
return logger.ErrorWithCallStack(err) return makeErrorWithStack(err)
} }
if err = mg.mongoClient.MakeUniqueIndices(CollectionCouponUse, map[string]bson.D{ if err = mg.mongoClient.MakeUniqueIndices(CollectionCouponUse, map[string]bson.D{
"idrounds": {{Key: "_id", Value: 1}, {Key: "rounds", Value: 1}}, "idrounds": {{Key: "_id", Value: 1}, {Key: "rounds", Value: 1}},
}); err != nil { }); err != nil {
return logger.ErrorWithCallStack(err) return err
}
if err = mg.mongoClient.MakeUniqueIndices(CollectionAuth, map[string]bson.D{
"skonly": {{Key: "sk", Value: 1}},
}); err != nil {
return makeErrorWithStack(err)
} }
if err = mg.mongoClient.MakeUniqueIndices(CollectionLink, map[string]bson.D{ if err = mg.mongoClient.MakeUniqueIndices(CollectionLink, map[string]bson.D{
"platformuid": {{Key: "platform", Value: 1}, {Key: "uid", Value: 1}}, "platformuid": {{Key: "platform", Value: 1}, {Key: "uid", Value: 1}},
}); err != nil { }); err != nil {
return logger.ErrorWithCallStack(err) return makeErrorWithStack(err)
} }
if err = mg.mongoClient.MakeUniqueIndices(CollectionLink, map[string]bson.D{ if err = mg.mongoClient.MakeUniqueIndices(CollectionLink, map[string]bson.D{
"emailplatform": {{Key: "email", Value: 1}, {Key: "platform", Value: 1}}, "emailplatform": {{Key: "email", Value: 1}, {Key: "platform", Value: 1}},
}); err != nil { }); err != nil {
return logger.ErrorWithCallStack(err) return makeErrorWithStack(err)
} }
if err = mg.mongoClient.MakeIndices(CollectionAccount, map[string]bson.D{ if err = mg.mongoClient.MakeIndices(CollectionAccount, map[string]bson.D{
"accid": {{Key: "accid", Value: 1}}, "accid": {{Key: "accid", Value: 1}},
}); err != nil { }); err != nil {
return logger.ErrorWithCallStack(err) return makeErrorWithStack(err)
} }
if err = mg.mongoClient.MakeUniqueIndices(CollectionFile, map[string]bson.D{ if err = mg.mongoClient.MakeUniqueIndices(CollectionFile, map[string]bson.D{
"keyonly": {{Key: "key", Value: 1}}, "keyonly": {{Key: "key", Value: 1}},
}); err != nil { }); err != nil {
return logger.ErrorWithCallStack(err) return makeErrorWithStack(err)
}
if err = mg.mongoClient.MakeExpireIndex(CollectionAccount, int32(mg.AccDelTTL)); err != nil {
return makeErrorWithStack(err)
}
if err = mg.mongoClient.MakeExpireIndex(CollectionLink, int32(mg.AccDelTTL)); err != nil {
return makeErrorWithStack(err)
} }
// Delete대신 _ts로 expire시킴. pipeline에 삭제 알려주기 위함 // Delete대신 _ts로 expire시킴. pipeline에 삭제 알려주기 위함
if err = mg.mongoClient.MakeExpireIndex(CollectionWhitelist, 10); err != nil { if err = mg.mongoClient.MakeExpireIndex(CollectionWhitelist, 10); err != nil {
return logger.ErrorWithCallStack(err) return makeErrorWithStack(err)
} }
if *devflag { if err = mg.mongoClient.MakeExpireIndex(CollectionAuth, int32(mg.SessionTTL+300)); err != nil {
// 에러 체크하지 말것 return makeErrorWithStack(err)
mg.mongoClient.DropIndex(CollectionBlock, "codeaccid")
} }
if err = mg.mongoClient.MakeExpireIndex(CollectionBlock, int32(3)); err != nil { if err = mg.mongoClient.MakeExpireIndex(CollectionBlock, int32(3)); err != nil {
return logger.ErrorWithCallStack(err) return makeErrorWithStack(err)
} }
if err = mg.mongoClient.MakeUniqueIndices(CollectionPlatformLoginToken, map[string]bson.D{ if err = mg.mongoClient.MakeUniqueIndices(CollectionPlatformLoginToken, map[string]bson.D{
"platformauthtoken": {{Key: "platform", Value: 1}, {Key: "key", Value: 1}}, "platformauthtoken": {{Key: "platform", Value: 1}, {Key: "key", Value: 1}},
}); err != nil { }); err != nil {
return logger.ErrorWithCallStack(err) return makeErrorWithStack(err)
} }
if err = mg.mongoClient.MakeExpireIndex(CollectionPlatformLoginToken, int32(mg.SessionTTL+300)); err != nil { if err = mg.mongoClient.MakeExpireIndex(CollectionPlatformLoginToken, int32(mg.SessionTTL+300)); err != nil {
return logger.ErrorWithCallStack(err) return makeErrorWithStack(err)
} }
if err = mg.mongoClient.MakeUniqueIndices(CollectionUserToken, map[string]bson.D{ if err = mg.mongoClient.MakeUniqueIndices(CollectionUserToken, map[string]bson.D{
"platformusertoken": {{Key: "platform", Value: 1}, {Key: "userid", Value: 1}}, "platformusertoken": {{Key: "platform", Value: 1}, {Key: "userid", Value: 1}},
}); err != nil { }); err != nil {
return logger.ErrorWithCallStack(err) return makeErrorWithStack(err)
} }
if err = mg.mongoClient.MakeUniqueIndices(CollectionGamepotUserInfo, map[string]bson.D{ if err = mg.mongoClient.MakeUniqueIndices(CollectionGamepotUserInfo, map[string]bson.D{
"gamepotuserid": {{Key: "gamepotuserid", Value: 1}}, "gamepotuserid": {{Key: "gamepotuserid", Value: 1}},
}); err != nil { }); err != nil {
return logger.ErrorWithCallStack(err) return makeErrorWithStack(err)
} }
if err = mg.mongoClient.MakeUniqueIndices(CollectionFirebaseUserInfo, map[string]bson.D{ if err = mg.mongoClient.MakeUniqueIndices(CollectionFirebaseUserInfo, map[string]bson.D{
"firebaseuserid": {{Key: "firebaseuserid", Value: 1}}, "firebaseuserid": {{Key: "firebaseuserid", Value: 1}},
}); err != nil { }); err != nil {
return logger.ErrorWithCallStack(err) return makeErrorWithStack(err)
} }
mg.sessionProvider, err = session.NewProviderWithConfig(context, mg.SessionConfig) mg.auths = makeAuthCollection(mg.mongoClient, time.Duration(mg.SessionTTL*int64(time.Second)))
if err != nil {
return logger.ErrorWithCallStack(err)
}
var preall []struct { var preall []struct {
Link string `bson:"link"` Link string `bson:"link"`
@ -354,7 +413,7 @@ func (mg *Maingate) prepare(context context.Context) (err error) {
if err = mg.mongoClient.FindAllAs(CollectionFile, nil, &preall, options.Find().SetProjection(bson.M{ if err = mg.mongoClient.FindAllAs(CollectionFile, nil, &preall, options.Find().SetProjection(bson.M{
"link": 1, "link": 1,
})); err != nil { })); err != nil {
return logger.ErrorWithCallStack(err) return makeErrorWithStack(err)
} }
for _, pre := range preall { for _, pre := range preall {
@ -369,26 +428,27 @@ func (mg *Maingate) prepare(context context.Context) (err error) {
"_id": pre.Id, "_id": pre.Id,
}, &fulldoc) }, &fulldoc)
if err != nil { if err != nil {
return logger.ErrorWithCallStack(err) return makeErrorWithStack(err)
} }
err = fulldoc.Save() err = fulldoc.Save()
if err != nil { if err != nil {
return logger.ErrorWithCallStack(err) return makeErrorWithStack(err)
} }
} }
var whites []*whitelistmember var whites []*whitelistmember
if err := mg.mongoClient.AllAs(CollectionWhitelist, &whites, options.Find().SetReturnKey(false)); err != nil { if err := mg.mongoClient.AllAs(CollectionWhitelist, &whites, options.Find().SetReturnKey(false)); err != nil {
return logger.ErrorWithCallStack(err) return makeErrorWithStack(err)
} }
mg.wl.init(whites) mg.wl.init(whites)
var blocks []*blockinfo var blocks []*blockinfo
if err := mg.mongoClient.AllAs(CollectionBlock, &blocks); err != nil { if err := mg.mongoClient.AllAs(CollectionBlock, &blocks); err != nil {
return logger.ErrorWithCallStack(err) return makeErrorWithStack(err)
} }
mg.bl.init(blocks) mg.bl.init(blocks)
go watchAuthCollection(context, mg.auths, mg.mongoClient)
go mg.wl.watchCollection(context, CollectionWhitelist, mg.mongoClient) go mg.wl.watchCollection(context, CollectionWhitelist, mg.mongoClient)
go mg.bl.watchCollection(context, CollectionBlock, mg.mongoClient) go mg.bl.watchCollection(context, CollectionBlock, mg.mongoClient)
@ -398,7 +458,7 @@ func (mg *Maingate) prepare(context context.Context) (err error) {
func (mg *Maingate) RegisterHandlers(ctx context.Context, serveMux *http.ServeMux, prefix string) error { func (mg *Maingate) RegisterHandlers(ctx context.Context, serveMux *http.ServeMux, prefix string) error {
var allServices []*serviceDescription var allServices []*serviceDescription
if err := mg.mongoClient.AllAs(CollectionService, &allServices, options.Find().SetReturnKey(false)); err != nil { if err := mg.mongoClient.AllAs(CollectionService, &allServices, options.Find().SetReturnKey(false)); err != nil {
return logger.ErrorWithCallStack(err) return err
} }
if len(allServices) > 0 { if len(allServices) > 0 {
@ -417,7 +477,7 @@ func (mg *Maingate) RegisterHandlers(ctx context.Context, serveMux *http.ServeMu
host, _ := os.Hostname() host, _ := os.Hostname()
addrs, err := net.InterfaceAddrs() addrs, err := net.InterfaceAddrs()
if err != nil { if err != nil {
return logger.ErrorWithCallStack(err) return err
} }
ipaddr := "127.0.0.1" ipaddr := "127.0.0.1"
for _, addr := range addrs { for _, addr := range addrs {
@ -431,8 +491,9 @@ func (mg *Maingate) RegisterHandlers(ctx context.Context, serveMux *http.ServeMu
empty.Divisions = map[string]*Division{ empty.Divisions = map[string]*Division{
host: { host: {
DivisionForUser: DivisionForUser{ DivisionForUser: DivisionForUser{
Priority: 0, Priority: 0,
State: DivisionState_FullOpen, State: DivisionState_FullOpen,
LockCreateChar: false,
}, },
Url: fmt.Sprintf("http://%s/warehouse", ipaddr), Url: fmt.Sprintf("http://%s/warehouse", ipaddr),
@ -449,7 +510,7 @@ func (mg *Maingate) RegisterHandlers(ctx context.Context, serveMux *http.ServeMu
}, options.Update().SetUpsert(true)) }, options.Update().SetUpsert(true))
if err != nil { if err != nil {
return logger.ErrorWithCallStack(err) return err
} }
} }
@ -458,11 +519,12 @@ func (mg *Maingate) RegisterHandlers(ctx context.Context, serveMux *http.ServeMu
mg.service().serveHTTP(w, r) mg.service().serveHTTP(w, r)
}) })
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "api/"), mg.api) serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "api/"), mg.api)
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "query/"), mg.query)
configraw, _ := json.Marshal(mg.maingateConfig) configraw, _ := json.Marshal(mg.maingateConfig)
var convertedConfig map[string]any var convertedConfig map[string]any
if err := json.Unmarshal(configraw, &convertedConfig); err != nil { if err := json.Unmarshal(configraw, &convertedConfig); err != nil {
return logger.ErrorWithCallStack(err) return err
} }
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "config"), func(w http.ResponseWriter, r *http.Request) { serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "config"), func(w http.ResponseWriter, r *http.Request) {
@ -495,7 +557,7 @@ func (mg *Maingate) RegisterHandlers(ctx context.Context, serveMux *http.ServeMu
if err := os.MkdirAll("static", os.ModePerm); err != nil { if err := os.MkdirAll("static", os.ModePerm); err != nil {
// 일반 엔드유저한테 오픈할 static 페이지 // 일반 엔드유저한테 오픈할 static 페이지
return logger.ErrorWithCallStack(err) return err
} }
cfsx := http.FileServer(http.Dir("console")) cfsx := http.FileServer(http.Dir("console"))
@ -546,11 +608,59 @@ func (mg *Maingate) RegisterHandlers(ctx context.Context, serveMux *http.ServeMu
return nil return nil
} }
func (mg *Maingate) query(w http.ResponseWriter, r *http.Request) {
defer func() {
s := recover()
if s != nil {
logger.Error(s)
}
}()
defer func() {
io.Copy(io.Discard, r.Body)
r.Body.Close()
}()
queryvals := r.URL.Query()
sk := queryvals.Get("sk")
if len(sk) == 0 {
w.WriteHeader(http.StatusUnauthorized)
return
}
info := mg.auths.Find(sk)
if info == nil {
logger.Println("session key is not valid :", sk)
w.WriteHeader(http.StatusUnauthorized)
return
}
if !*devflag {
apitoken := r.Header.Get("MG-X-API-TOKEN")
if len(apitoken) == 0 {
logger.Println("MG-X-API-TOKEN is missing")
w.WriteHeader(http.StatusBadRequest)
return
}
apitokenObj, _ := primitive.ObjectIDFromHex(apitoken)
if !mg.service().isValidToken(apitokenObj) {
logger.Println("MG-X-API-TOKEN is invalid :", apitoken)
w.WriteHeader(http.StatusBadRequest)
return
}
}
bt, _ := json.Marshal(info)
w.Write(bt)
}
func (mg *Maingate) GeneratePlatformLoginNonceKey() string { func (mg *Maingate) GeneratePlatformLoginNonceKey() string {
const allowed = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" const allowed = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
b := make([]byte, 52) b := make([]byte, 52)
for i := range b { for i := range b {
b[i] = allowed[r.Intn(len(allowed))] b[i] = allowed[rand.Intn(len(allowed))]
} }
return string(b) return string(b)
} }
@ -564,7 +674,7 @@ func (mg *Maingate) GetUserBrowserInfo(r *http.Request) (string, error) {
cookie, err := r.Cookie("ActionSquareSessionExtraInfo") cookie, err := r.Cookie("ActionSquareSessionExtraInfo")
if err != nil { if err != nil {
return "", logger.ErrorWithCallStack(err) return "", err
} }
//requestinfo := fmt.Sprintf("%s_%s", cookie.Value, host) //-- RemoteAddr체크는 로드밸런서 IP 찍히는 문제 때문에 제외한다. //requestinfo := fmt.Sprintf("%s_%s", cookie.Value, host) //-- RemoteAddr체크는 로드밸런서 IP 찍히는 문제 때문에 제외한다.
@ -586,7 +696,7 @@ func (mg *Maingate) setUserToken(info usertokeninfo) error {
"accesstoken_expire_time": info.accesstoken_expire_time, "accesstoken_expire_time": info.accesstoken_expire_time,
}, },
}, options.Update().SetUpsert(true)) }, options.Update().SetUpsert(true))
return logger.ErrorWithCallStack(err) return err
} }
func (mg *Maingate) getUserTokenWithCheck(platform string, userid string, brinfo string) (usertokeninfo, error) { func (mg *Maingate) getUserTokenWithCheck(platform string, userid string, brinfo string) (usertokeninfo, error) {
@ -700,13 +810,18 @@ func (mg *Maingate) getProviderInfo(platform string, uid string) (string, string
if provider == "" || providerid == "" { if provider == "" || providerid == "" {
return "", "", errors.New("getProviderInfo - firebase info not found: " + provider + " / " + providerid) return "", "", errors.New("getProviderInfo - firebase info not found: " + provider + " / " + providerid)
} }
case "":
//guest auth
providerid = uid
if providerid == "" {
return "", "", errors.New("getProviderInfo - guest provider id not found: " + provider + " / " + providerid)
}
default: default:
provider = platform provider = platform
providerid = uid providerid = uid
} if provider == "" || providerid == "" {
return "", "", errors.New("getProviderInfo - provider info not found: " + provider + " / " + providerid)
if provider == "" || providerid == "" { }
return "", "", errors.New("getProviderInfo - provider info not found: " + provider + " / " + providerid)
} }
return provider, providerid, nil return provider, providerid, nil

View File

@ -95,7 +95,7 @@ func (p *memberContainerPtr[K, T]) contains(key K, out *T) bool {
return false return false
} }
if out != nil { if out != nil {
out = &found *out = found
} }
return true return true
} }

View File

@ -1,7 +1,6 @@
package core package core
import ( import (
"context"
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"errors" "errors"
@ -14,7 +13,6 @@ import (
"repositories.action2quare.com/ayo/gocommon" "repositories.action2quare.com/ayo/gocommon"
"repositories.action2quare.com/ayo/gocommon/logger" "repositories.action2quare.com/ayo/gocommon/logger"
"repositories.action2quare.com/ayo/gocommon/session"
"go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/bson/primitive"
@ -36,7 +34,7 @@ type blockinfoWithStringId struct {
} }
type whitelistmember struct { type whitelistmember struct {
Id primitive.ObjectID `bson:"_id" json:"_id"` Id primitive.ObjectID `bson:"_id,omitempty" json:"_id,omitempty"`
Email string `bson:"email" json:"email"` Email string `bson:"email" json:"email"`
Platform string `bson:"platform" json:"platform"` Platform string `bson:"platform" json:"platform"`
Desc string `bson:"desc" json:"desc"` Desc string `bson:"desc" json:"desc"`
@ -90,9 +88,10 @@ type Maintenance struct {
} }
type DivisionForUser struct { type DivisionForUser struct {
Priority int `bson:"priority" json:"priority"` Priority int `bson:"priority" json:"priority"`
State DivisionStateName `bson:"state" json:"state"` State DivisionStateName `bson:"state" json:"state"`
Maintenance *Maintenance `bson:"maintenance,omitempty" json:"maintenance,omitempty"` LockCreateChar bool `bson:"lockcreatechar" json:"lockcreatechar"`
Maintenance *Maintenance `bson:"maintenance,omitempty" json:"maintenance,omitempty"`
} }
type Division struct { type Division struct {
@ -112,11 +111,11 @@ type serviceDescription struct {
MaximumNumLinkAccount int64 MaximumNumLinkAccount int64
VersionSplits map[string]string `bson:"version_splits" json:"version_splits"` VersionSplits map[string]string `bson:"version_splits" json:"version_splits"`
sessionProvider session.Provider auths *gocommon.AuthCollection
wl *memberContainerPtr[string, *whitelistmember] wl *memberContainerPtr[string, *whitelistmember]
bl *memberContainerPtr[primitive.ObjectID, *blockinfo] bl *memberContainerPtr[primitive.ObjectID, *blockinfo]
mongoClient gocommon.MongoClient mongoClient gocommon.MongoClient
sessionTTL time.Duration sessionTTL time.Duration
serviceCodeBytes []byte serviceCodeBytes []byte
getUserBrowserInfo func(r *http.Request) (string, error) getUserBrowserInfo func(r *http.Request) (string, error)
@ -163,7 +162,6 @@ func (sh *serviceDescription) readProfile(authtype string, id string, binfo stri
if err != nil { if err != nil {
return "", err return "", err
} }
if len(userinfo.token) == 0 { if len(userinfo.token) == 0 {
return "", errors.New("refreshtoken token not found") return "", errors.New("refreshtoken token not found")
} }
@ -255,7 +253,7 @@ func (sh *serviceDescription) prepare(mg *Maingate) error {
sh.MaximumNumLinkAccount = mg.maingateConfig.MaximumNumLinkAccount sh.MaximumNumLinkAccount = mg.maingateConfig.MaximumNumLinkAccount
sh.mongoClient = mg.mongoClient sh.mongoClient = mg.mongoClient
sh.sessionProvider = mg.sessionProvider sh.auths = mg.auths
sh.sessionTTL = time.Duration(mg.SessionTTL * int64(time.Second)) sh.sessionTTL = time.Duration(mg.SessionTTL * int64(time.Second))
sh.serviceCodeBytes, _ = hex.DecodeString(sh.ServiceCode) sh.serviceCodeBytes, _ = hex.DecodeString(sh.ServiceCode)
sh.getUserBrowserInfo = mg.GetUserBrowserInfo sh.getUserBrowserInfo = mg.GetUserBrowserInfo
@ -294,10 +292,11 @@ func (sh *serviceDescription) link(w http.ResponseWriter, r *http.Request) {
newType := queryvals.Get("ntype") newType := queryvals.Get("ntype")
newId := queryvals.Get("nid") newId := queryvals.Get("nid")
oldAuth, err := sh.sessionProvider.Query(sk) oldAuth := sh.auths.Find(sk)
if err != nil { if oldAuth == nil {
logger.Println("sessionProvider.Query return err :", err) // 잘못된 세션
w.WriteHeader(http.StatusInternalServerError) logger.Println("link failed. session key is not valid :", sk)
w.WriteHeader(http.StatusBadRequest)
return return
} }
@ -312,13 +311,6 @@ func (sh *serviceDescription) link(w http.ResponseWriter, r *http.Request) {
// fmt.Println(oldAuth.Uid) // fmt.Println(oldAuth.Uid)
// fmt.Println("=================") // fmt.Println("=================")
//if oldAuth.Token != oldToken || oldAuth.Uid != oldId || oldAuth.Platform != oldType {
if oldAuth.Uid != oldId || oldAuth.Platform != oldType {
logger.Println("link failed. session key is not correct :", oldAuth, queryvals)
w.WriteHeader(http.StatusBadRequest)
return
}
bfinfo, err := sh.getUserBrowserInfo(r) bfinfo, err := sh.getUserBrowserInfo(r)
if err != nil { if err != nil {
logger.Error("getUserBrowserInfo failed :", err) logger.Error("getUserBrowserInfo failed :", err)
@ -326,16 +318,35 @@ func (sh *serviceDescription) link(w http.ResponseWriter, r *http.Request) {
return return
} }
_, err = sh.readProfile(oldType, oldId, bfinfo) guestlink := (len(oldType) == 0)
if !guestlink {
_, err = sh.readProfile(oldType, oldId, bfinfo)
if err != nil {
logger.Println("readProfile(old) failed :", err)
w.WriteHeader(http.StatusBadRequest)
return
}
} else {
logger.Println("from guest acc to real acc link : ", oldId, bfinfo, newType, newId, bfinfo)
}
oldType, oldId, err = sh.getProviderInfo(oldType, oldId)
if err != nil { if err != nil {
logger.Error("readProfile(old) failed :", err) logger.Println("getProviderInfo failed :", err)
w.WriteHeader(http.StatusBadRequest)
return
}
//if oldAuth.Token != oldToken || oldAuth.Uid != oldId || oldAuth.Platform != oldType {
if oldAuth.Uid != oldId || oldAuth.Platform != oldType {
logger.Println("link failed. session key is not correct :", *oldAuth, queryvals)
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
return return
} }
email, err := sh.readProfile(newType, newId, bfinfo) email, err := sh.readProfile(newType, newId, bfinfo)
if err != nil { if err != nil {
logger.Error("readProfile(new) failed :", err) logger.Println("readProfile(new) failed :", err)
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
return return
} }
@ -348,8 +359,9 @@ func (sh *serviceDescription) link(w http.ResponseWriter, r *http.Request) {
newType, newId, err = sh.getProviderInfo(newType, newId) newType, newId, err = sh.getProviderInfo(newType, newId)
if err != nil { if err != nil {
logger.Error("getProviderInfo failed :", err) logger.Println("getProviderInfo failed :", err)
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
return
} }
createtime := primitive.NewDateTimeFromTime(time.Now().UTC()) createtime := primitive.NewDateTimeFromTime(time.Now().UTC())
@ -372,13 +384,13 @@ func (sh *serviceDescription) link(w http.ResponseWriter, r *http.Request) {
"_id": link["_id"].(primitive.ObjectID), "_id": link["_id"].(primitive.ObjectID),
}, bson.M{ }, bson.M{
"$setOnInsert": bson.M{ "$setOnInsert": bson.M{
"accid": oldAuth.Account, "accid": oldAuth.Accid,
"create": createtime, "create": createtime,
}, },
}, options.Update().SetUpsert(true)) }, options.Update().SetUpsert(true))
if err != nil { if err != nil {
logger.Error("link failed. Update ServiceName err :", err) logger.Error("link failed. Update ServiceName err :", err)
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusInternalServerError)
return return
} }
@ -390,6 +402,20 @@ func (sh *serviceDescription) link(w http.ResponseWriter, r *http.Request) {
return return
} }
if guestlink {
//기존 게스트 링크 삭제
link, err = sh.mongoClient.FindOneAndDelete(CollectionLink, bson.M{
"platform": oldType,
"uid": oldId,
}, options.FindOneAndDelete().SetProjection(bson.M{"_id": 1}))
if err == nil {
sh.mongoClient.Delete(CollectionAccount, bson.M{
"_id": link["_id"].(primitive.ObjectID),
})
}
}
logger.Println("link success :", r.URL.Query()) logger.Println("link success :", r.URL.Query())
} }
@ -411,11 +437,13 @@ func (sh *serviceDescription) unlink(w http.ResponseWriter, r *http.Request) {
sType := queryvals.Get("stype") sType := queryvals.Get("stype")
sId := queryvals.Get("sid") sId := queryvals.Get("sid")
sk := queryvals.Get("sk") sk := queryvals.Get("sk")
targetType := queryvals.Get("ttype")
authInfo, err := sh.sessionProvider.Query(sk) authInfo := sh.auths.Find(sk)
if err != nil { if authInfo == nil {
logger.Println("sessionProvider.Query return err :", err) // 잘못된 세션
w.WriteHeader(http.StatusInternalServerError) logger.Println("linkinfo failed. session key is not valid :", sk)
w.WriteHeader(http.StatusBadRequest)
return return
} }
@ -427,55 +455,60 @@ func (sh *serviceDescription) unlink(w http.ResponseWriter, r *http.Request) {
// fmt.Println(authInfo.Uid) // fmt.Println(authInfo.Uid)
// fmt.Println("=================") // fmt.Println("=================")
if authInfo.Uid != sId || authInfo.Platform != sType { sType, sId, err := sh.getProviderInfo(sType, sId)
logger.Println("unlink failed. session key is not correct :", authInfo, queryvals) if err != nil {
logger.Println("getProviderInfo failed :", err)
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
return return
} }
numRecord, err := sh.mongoClient.Collection(CollectionAccount).CountDocuments(context.Background(), bson.M{ if authInfo.Uid != sId || authInfo.Platform != sType {
"accid": authInfo.Account, logger.Println("unlink failed. session key is not correct :", *authInfo, queryvals)
}, options.Count().SetLimit(2)) w.WriteHeader(http.StatusBadRequest)
return
}
accDocs, err := sh.mongoClient.FindAll(CollectionAccount, bson.M{
"accid": authInfo.Accid,
}, options.Find().SetProjection(bson.M{
"_id": 1,
}))
if err != nil { if err != nil {
logger.Error("unlink failed, fail to count accounts :", err) logger.Error("unlink failed, fail to count accounts :", err)
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusInternalServerError)
} }
if numRecord <= 1 { if len(accDocs) <= 1 {
logger.Println("unlink failed. At least one link must be maintained. :", r.URL.Query()) logger.Println("unlink failed. At least one link must be maintained. :", r.URL.Query())
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
return return
} }
sType, sId, err = sh.getProviderInfo(sType, sId) var ids primitive.A
if err != nil { for _, accDoc := range accDocs {
logger.Error("getProviderInfo failed :", err) ids = append(ids, accDoc["_id"].(primitive.ObjectID))
w.WriteHeader(http.StatusBadRequest)
} }
link, err := sh.mongoClient.FindOne(CollectionLink, bson.M{ link, err := sh.mongoClient.FindOneAndDelete(CollectionLink, bson.M{
"platform": sType, "platform": targetType,
"uid": sId, "_id": bson.M{"$in": ids},
}, options.FindOne().SetProjection(bson.M{"_id": 1})) }, options.FindOneAndDelete().SetProjection(bson.M{"_id": 1}))
if err != nil { if err != nil {
logger.Error("link failed. FindOneAndUpdate link err:", err) logger.Error("unlink failed. FindOneAndDelete link err:", err)
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
return return
} }
newid, err := sh.mongoClient.FindOneAndDelete(CollectionAccount, bson.M{ preid, err := sh.mongoClient.FindOneAndDelete(CollectionAccount, bson.M{
"_id": link["_id"].(primitive.ObjectID), "_id": link["_id"].(primitive.ObjectID),
}, options.FindOneAndDelete().SetProjection(bson.M{"_id": 1})) }, options.FindOneAndDelete().SetProjection(bson.M{"_id": 1}))
if err != nil { if err != nil {
logger.Error("unlink failed. Delete ServiceName err :", err) logger.Error("unlink failed. Delete ServiceName err :", err)
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusInternalServerError)
return return
} }
if preid == nil {
// newid가 있어야 한다. 그래야 기존 서비스 계정이 없는 상태이다.
if newid == nil {
// 이미 계정이 있네?
logger.Println("unlink failed. service account not found:", r.URL.Query()) logger.Println("unlink failed. service account not found:", r.URL.Query())
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
return return
@ -503,10 +536,11 @@ func (sh *serviceDescription) linkinfo(w http.ResponseWriter, r *http.Request) {
sId := queryvals.Get("sid") sId := queryvals.Get("sid")
sk := queryvals.Get("sk") sk := queryvals.Get("sk")
authInfo, err := sh.sessionProvider.Query(sk) authInfo := sh.auths.Find(sk)
if err != nil { if authInfo == nil {
logger.Println("sessionProvider.Query return err :", err) // 잘못된 세션
w.WriteHeader(http.StatusInternalServerError) logger.Println("linkinfo failed. session key is not valid :", sk)
w.WriteHeader(http.StatusBadRequest)
return return
} }
@ -518,26 +552,62 @@ func (sh *serviceDescription) linkinfo(w http.ResponseWriter, r *http.Request) {
// fmt.Println(authInfo.Uid) // fmt.Println(authInfo.Uid)
// fmt.Println("=================") // fmt.Println("=================")
sType, sId, err := sh.getProviderInfo(sType, sId)
if err != nil {
logger.Println("getProviderInfo failed :", err)
w.WriteHeader(http.StatusBadRequest)
return
}
//if oldAuth.Token != oldToken || oldAuth.Uid != oldId || oldAuth.Platform != oldType { //if oldAuth.Token != oldToken || oldAuth.Uid != oldId || oldAuth.Platform != oldType {
if authInfo.Uid != sId || authInfo.Platform != sType { if authInfo.Uid != sId || authInfo.Platform != sType {
logger.Println("linkinfo failed. session key is not correct :", authInfo, queryvals) logger.Println("linkinfo failed. session key is not correct :", *authInfo, queryvals)
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
return return
} }
numRecord, err := sh.mongoClient.Collection(CollectionAccount).CountDocuments(context.Background(), bson.M{ platformName := "platform"
"accid": authInfo.Account, accDocs, err := sh.mongoClient.FindAll(CollectionAccount, bson.M{
}, options.Count().SetLimit(sh.MaximumNumLinkAccount)) "accid": authInfo.Accid,
}, options.Find().SetLimit(sh.MaximumNumLinkAccount).SetProjection(bson.M{
"_id": 1,
}))
if err != nil { if err != nil {
logger.Error("linkinfo failed. CountDocuments err :", err) logger.Error("linkinfo failed. CountDocuments err :", err)
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusInternalServerError)
return return
} }
logger.Println("linkinfo :", numRecord) var ids primitive.A
w.Write([]byte(fmt.Sprintf(`{"num_linked_account":"%d"}`, numRecord))) for _, accDoc := range accDocs {
ids = append(ids, accDoc["_id"].(primitive.ObjectID))
}
links, err := sh.mongoClient.FindAll(CollectionLink, bson.M{
"_id": bson.M{"$in": ids},
}, options.Find().SetLimit(sh.MaximumNumLinkAccount).SetProjection(bson.M{
platformName: 1,
}))
if err != nil {
logger.Error("linkinfo failed. FindAll returns err :", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
var linkstrs []string
for _, link := range links {
linkstrs = append(linkstrs, link[platformName].(string))
}
linkbytes, err := json.Marshal(linkstrs)
if err != nil {
logger.Error("linkinfo failed. json marshal fail :", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
logger.Println("linkinfo :", linkstrs)
w.Write(linkbytes)
} }
func (sh *serviceDescription) authorize(w http.ResponseWriter, r *http.Request) { func (sh *serviceDescription) authorize(w http.ResponseWriter, r *http.Request) {
@ -556,26 +626,8 @@ func (sh *serviceDescription) authorize(w http.ResponseWriter, r *http.Request)
queryvals := r.URL.Query() queryvals := r.URL.Query()
authtype := queryvals.Get("type") authtype := queryvals.Get("type")
uid := queryvals.Get("id") uid := queryvals.Get("id")
if sk := queryvals.Get("sk"); len(sk) > 0 { //accesstoken := queryvals.Get("token") //-- 이거 이제 받지마라
success, err := sh.sessionProvider.Touch(sk) session := queryvals.Get("sk")
if err != nil {
logger.Error("authorize failed. sessionProvider.Touch err:", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
// !success일 때 빈 body를 보내면 클라이언트는 로그아웃 된다.
if success {
json.NewEncoder(w).Encode(map[string]any{
"sk": sk,
"expirein": sh.sessionTTL.Seconds(),
})
} else {
logger.Println("sh.sessionProvider.Touch failed :", sk)
}
return
}
var email string var email string
if !*noauth { if !*noauth {
@ -583,114 +635,173 @@ func (sh *serviceDescription) authorize(w http.ResponseWriter, r *http.Request)
//email, err := sh.readProfile(authtype, uid, accesstoken) //email, err := sh.readProfile(authtype, uid, accesstoken)
bfinfo, err := sh.getUserBrowserInfo(r) bfinfo, err := sh.getUserBrowserInfo(r)
if err != nil { if err != nil {
logger.Error("getUserBrowserInfo failed :", err) logger.Println("getUserBrowserInfo failed :", err)
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
return return
} }
email, err = sh.readProfile(authtype, uid, bfinfo) email, err = sh.readProfile(authtype, uid, bfinfo)
if err != nil { if err != nil {
logger.Error("readProfile failed :", err) logger.Println("readProfile failed :", err)
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
return return
} }
newType, newId, err := sh.getProviderInfo(authtype, uid) newType, newId, err := sh.getProviderInfo(authtype, uid)
if err != nil { if err != nil {
logger.Error("getProviderInfo failed :", err) logger.Println("getProviderInfo failed :", err)
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
return return
} }
if authtype != newType || uid != newId { if authtype != newType || uid != newId {
logger.Printf("auth success ( redirect ) : %s->%s, %s->%s, %s, %s", authtype, newType, uid, newId, email, session)
authtype = newType authtype = newType
uid = newId uid = newId
} }
} else if *devflag {
email = fmt.Sprintf("%s@guest.flag", uid)
} else { } else {
// authtype이 없으면 입장 불가 email = fmt.Sprintf("%s@guest.flag", uid)
logger.Error("authorize failed. 'type' query parameter is missing")
w.WriteHeader(http.StatusBadRequest)
return
} }
} else { } else {
email = fmt.Sprintf("%s@noauth.flag", uid) email = fmt.Sprintf("%s@noauth.flag", uid)
} }
// platform + id -> account id //if len(session) == 0 && len(email) > 0 {
createtime := primitive.NewDateTimeFromTime(time.Now().UTC()) if len(session) == 0 {
link, err := sh.mongoClient.FindOneAndUpdate(CollectionLink, bson.M{ // platform + id -> account id
"platform": authtype, createtime := primitive.NewDateTimeFromTime(time.Now().UTC())
"uid": uid, link, err := sh.mongoClient.FindOneAndUpdate(CollectionLink, bson.M{
}, bson.M{ "platform": authtype,
"$setOnInsert": bson.M{ "uid": uid,
"create": createtime, }, bson.M{
"email": email, "$setOnInsert": bson.M{
}, "create": createtime,
}, options.FindOneAndUpdate().SetReturnDocument(options.After).SetUpsert(true).SetProjection(bson.M{"_id": 1})) "email": email,
if err != nil { },
logger.Error("authorize failed :", err) }, options.FindOneAndUpdate().SetReturnDocument(options.After).SetUpsert(true).SetProjection(bson.M{
w.WriteHeader(http.StatusInternalServerError) "_id": 1,
return "_ts": 1,
} }))
if err != nil {
logger.Error("authorize failed :", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
linkid := link["_id"].(primitive.ObjectID)
newaccid := primitive.NewObjectID()
for i := 0; i < len(sh.serviceCodeBytes); i++ {
newaccid[i] ^= sh.serviceCodeBytes[i]
}
account, err := sh.mongoClient.FindOneAndUpdate(CollectionAccount, bson.M{
"_id": linkid,
}, bson.M{
"$setOnInsert": bson.M{
"accid": newaccid,
"create": createtime,
},
}, options.FindOneAndUpdate().SetReturnDocument(options.After).SetUpsert(true).SetProjection(bson.M{"accid": 1, "create": 1}))
if err != nil {
logger.Error("authorize failed. Update sh.ServiceName err:", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
linkid := link["_id"].(primitive.ObjectID) accid := account["accid"].(primitive.ObjectID)
newaccid := primitive.NewObjectID() oldcreate := account["create"].(primitive.DateTime)
for i := 0; i < len(sh.serviceCodeBytes); i++ { newaccount := oldcreate == createtime
newaccid[i] ^= sh.serviceCodeBytes[i]
}
account, err := sh.mongoClient.FindOneAndUpdate(CollectionAccount, bson.M{
"_id": linkid,
}, bson.M{
"$setOnInsert": bson.M{
"accid": newaccid,
"create": createtime,
},
}, options.FindOneAndUpdate().SetReturnDocument(options.After).SetUpsert(true).SetProjection(bson.M{"accid": 1, "create": 1}))
if err != nil {
logger.Error("authorize failed. Update sh.ServiceName err:", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
accid := account["accid"].(primitive.ObjectID) var bi *blockinfo
oldcreate := account["create"].(primitive.DateTime) if sh.bl.contains(accid, &bi) {
newaccount := oldcreate == createtime // 블럭된 계정. 블락 정보를 알려준다.
w.Header().Add("MG-ACCOUNTBLOCK-START", strconv.FormatInt(bi.Start.Time().Unix(), 10))
w.Header().Add("MG-ACCOUNTBLOCK-END", strconv.FormatInt(bi.End.Time().Unix(), 10))
w.Header().Add("MG-ACCOUNTBLOCK-REASON", bi.Reason)
w.WriteHeader(http.StatusUnauthorized)
return
}
var bi *blockinfo newsession := primitive.NewObjectID()
if sh.bl.contains(accid, &bi) { expired := primitive.NewDateTimeFromTime(time.Now().UTC().Add(sh.sessionTTL))
// 블럭된 계정. 블락 정보를 알려준다. newauth := gocommon.Authinfo{
w.Header().Add("MG-ACCOUNTBLOCK-START", strconv.FormatInt(bi.Start.Time().Unix(), 10)) Accid: accid,
w.Header().Add("MG-ACCOUNTBLOCK-END", strconv.FormatInt(bi.End.Time().Unix(), 10)) ServiceCode: sh.ServiceCode,
w.Header().Add("MG-ACCOUNTBLOCK-REASON", bi.Reason) Platform: authtype,
w.WriteHeader(http.StatusUnauthorized) Uid: uid,
return Email: email,
} Sk: newsession,
Expired: expired,
//RefreshToken: queryvals.Get("rt"),
}
sk, err := sh.sessionProvider.New(&session.Authorization{ _, _, err = sh.mongoClient.UpsertOne(CollectionAuth, bson.M{"_id": newauth.Accid}, &newauth)
Account: accid, if err != nil {
Platform: authtype, logger.Error("authorize failed :", err)
Uid: uid, w.WriteHeader(http.StatusInternalServerError)
Email: email, return
}) }
if err != nil {
logger.Error("authorize failed. sessionProvider.New err:", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
output := map[string]any{ logger.Println("session created :", accid, authtype, uid, email, newsession)
"sk": sk,
"expirein": sh.sessionTTL.Seconds(),
"newAccount": newaccount,
"accid": accid.Hex(),
}
if *noauth {
output["noauth"] = true
}
json.NewEncoder(w).Encode(output) output := map[string]any{
"sk": newsession.Hex(),
"expirein": sh.sessionTTL.Seconds(),
"newAccount": newaccount,
"accid": newauth.Accid.Hex(),
}
if *noauth {
output["noauth"] = true
}
if link["_ts"] != nil {
delts := link["_ts"].(primitive.DateTime)
if !delts.Time().IsZero() {
// 삭제된 계정. 삭제 되었다고 알려주자
w.Header().Add("MG-ACCOUNT-DELETED", "TRUE")
}
}
bt, _ := json.Marshal(output)
w.Write(bt)
} else if len(session) > 0 {
sessionobj, _ := primitive.ObjectIDFromHex(session)
if !sessionobj.IsZero() {
updated, _, err := sh.mongoClient.Update(CollectionAuth,
bson.M{
"sk": sessionobj,
},
bson.M{
"$currentDate": bson.M{
"_ts": bson.M{"$type": "date"},
},
}, options.Update().SetUpsert(false))
if err != nil {
logger.Error("update auth collection failed :", err)
return
}
if !updated {
// 세션이 없네?
logger.Println("authorize failed. session not exists in database :", session)
w.WriteHeader(http.StatusUnauthorized)
return
}
output := map[string]any{
"sk": session,
"expirein": sh.sessionTTL.Seconds(),
}
logger.Println("session updated :", authtype, uid, session)
bt, _ := json.Marshal(output)
w.Write(bt)
} else {
logger.Println("authorize failed. sk is not valid hex :", session)
w.WriteHeader(http.StatusBadRequest)
return
}
} else {
logger.Println("authorize failed. id empty :", queryvals)
}
} }
func (sh *serviceDescription) findVersionSplit(version string) []byte { func (sh *serviceDescription) findVersionSplit(version string) []byte {
@ -706,6 +817,101 @@ func (sh *serviceDescription) findVersionSplit(version string) []byte {
return sh.divisionsSplits["default"] return sh.divisionsSplits["default"]
} }
func (sh *serviceDescription) delacc(w http.ResponseWriter, r *http.Request) {
defer func() {
s := recover()
if s != nil {
logger.Error(s)
}
}()
if r.Method != "GET" {
w.WriteHeader(http.StatusBadRequest)
return
}
queryvals := r.URL.Query()
sType := queryvals.Get("stype")
sId := queryvals.Get("sid")
sk := queryvals.Get("sk")
cancel := queryvals.Has("cancel")
authInfo := sh.auths.Find(sk)
if authInfo == nil {
// 잘못된 세션
logger.Println("delacc failed. session key is not valid :", sk)
w.WriteHeader(http.StatusBadRequest)
return
}
if authInfo.Uid != sId || authInfo.Platform != sType {
logger.Println("delacc failed. session key is not correct :", *authInfo, queryvals)
w.WriteHeader(http.StatusBadRequest)
return
}
linkidMap, err := sh.mongoClient.FindAll(CollectionAccount, bson.M{
"accid": authInfo.Accid,
}, options.Find().SetProjection(bson.M{
"_id": 1,
}))
if err != nil {
logger.Error("delacc failed. FindAll account err :", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
var linkidAry primitive.A
for _, linkid := range linkidMap {
linkidAry = append(linkidAry, linkid["_id"].(primitive.ObjectID))
}
delfilter := primitive.M{"_id": bson.M{"$in": linkidAry}}
var delop primitive.M
if !cancel {
curtime := primitive.NewDateTimeFromTime(time.Now().UTC())
delop = primitive.M{
"$set": primitive.M{"_ts": curtime},
}
if sType == AuthPlatformFirebaseAuth {
sh.mongoClient.Delete(CollectionFirebaseUserInfo, bson.M{
"firebaseuserid": sId,
})
}
} else {
delfilter["platform"] = sType
targetLinkId, err := sh.mongoClient.FindAll(CollectionLink, delfilter, options.Find().SetProjection(bson.M{
"_id": 1,
}))
if len(targetLinkId) != 1 {
logger.Error("delacc failed. FindAll link err :", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
delfilter = primitive.M{"_id": targetLinkId[0]["_id"].(primitive.ObjectID)}
delop = primitive.M{
"$unset": primitive.M{"_ts": true},
}
}
updated, _, err := sh.mongoClient.Update(CollectionAccount, delfilter, delop, options.Update().SetUpsert(false))
if !updated || err != nil {
logger.Error("delacc failed. Update CollectionAccount timestamp err :", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
updated, _, err = sh.mongoClient.Update(CollectionLink, delfilter, delop, options.Update().SetUpsert(false))
if !updated || err != nil {
logger.Error("delacc failed. Update CollectionLink timestamp err :", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
logger.Println("delacc success :", linkidMap)
}
func (sh *serviceDescription) serveHTTP(w http.ResponseWriter, r *http.Request) { func (sh *serviceDescription) serveHTTP(w http.ResponseWriter, r *http.Request) {
defer func() { defer func() {
s := recover() s := recover()
@ -727,6 +933,8 @@ func (sh *serviceDescription) serveHTTP(w http.ResponseWriter, r *http.Request)
sh.unlink(w, r) sh.unlink(w, r)
} else if strings.HasSuffix(r.URL.Path, "/linkinfo") { } else if strings.HasSuffix(r.URL.Path, "/linkinfo") {
sh.linkinfo(w, r) sh.linkinfo(w, r)
} else if strings.HasSuffix(r.URL.Path, "/delacc") {
sh.delacc(w, r)
} else if strings.HasSuffix(r.URL.Path, "/divs") { } else if strings.HasSuffix(r.URL.Path, "/divs") {
// TODO : 세션키와 authtoken을 헤더로 받아서 accid 조회 // TODO : 세션키와 authtoken을 헤더로 받아서 accid 조회
queryvals := r.URL.Query() queryvals := r.URL.Query()
@ -741,14 +949,7 @@ func (sh *serviceDescription) serveHTTP(w http.ResponseWriter, r *http.Request)
// TODO : 각 서버에 있는 자산? 캐릭터 정보를 보여줘야 하나. 뭘 보여줄지는 프로젝트에 문의 // TODO : 각 서버에 있는 자산? 캐릭터 정보를 보여줘야 하나. 뭘 보여줄지는 프로젝트에 문의
// 일단 서버 종류만 내려보내자 // 일단 서버 종류만 내려보내자
// 세션키가 있는지 확인 // 세션키가 있는지 확인
authInfo, err := sh.sessionProvider.Query(sk) if _, ok := sh.auths.IsValid(sk, ""); !ok {
if err != nil {
logger.Println("sessionProvider.Query return err :", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
if authInfo.Account.IsZero() {
logger.Println("sessionkey is not valid :", sk) logger.Println("sessionkey is not valid :", sk)
w.WriteHeader(http.StatusUnauthorized) w.WriteHeader(http.StatusUnauthorized)
return return
@ -769,14 +970,7 @@ func (sh *serviceDescription) serveHTTP(w http.ResponseWriter, r *http.Request)
// TODO : 각 서버에 있는 자산? 캐릭터 정보를 보여줘야 하나. 뭘 보여줄지는 프로젝트에 문의 // TODO : 각 서버에 있는 자산? 캐릭터 정보를 보여줘야 하나. 뭘 보여줄지는 프로젝트에 문의
// 일단 서버 종류만 내려보내자 // 일단 서버 종류만 내려보내자
// 세션키가 있는지 확인 // 세션키가 있는지 확인
authInfo, err := sh.sessionProvider.Query(sk) if _, ok := sh.auths.IsValid(sk, ""); !ok {
if err != nil {
logger.Println("sessionProvider.Query return err :", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
if authInfo.Account.IsZero() {
logger.Println("sessionkey is not valid :", sk) logger.Println("sessionkey is not valid :", sk)
w.WriteHeader(http.StatusUnauthorized) w.WriteHeader(http.StatusUnauthorized)
return return
@ -792,14 +986,13 @@ func (sh *serviceDescription) serveHTTP(w http.ResponseWriter, r *http.Request)
case DivisionState_RestrictedOpen: case DivisionState_RestrictedOpen:
// 점검중이면 whitelist만 입장 가능 // 점검중이면 whitelist만 입장 가능
authInfo, err := sh.sessionProvider.Query(sk) cell := sh.auths.QuerySession(sk, "")
if err != nil { if cell == nil {
logger.Println("sessionProvider.Query return err :", err) logger.Println("sessionkey is not valid :", sk)
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusBadRequest)
return return
} }
wm := &whitelistmember{Email: cell.ToAuthinfo().Email, Platform: cell.ToAuthinfo().Platform}
wm := &whitelistmember{Email: authInfo.Email, Platform: authInfo.Platform}
if sh.wl.contains(wm.Key(), nil) { if sh.wl.contains(wm.Key(), nil) {
// qa 권한이면 입장 가능 // qa 권한이면 입장 가능
w.Write([]byte(fmt.Sprintf(`{"service":"%s"}`, div.Url))) w.Write([]byte(fmt.Sprintf(`{"service":"%s"}`, div.Url)))

View File

@ -10,6 +10,7 @@ import (
"time" "time"
"unsafe" "unsafe"
"repositories.action2quare.com/ayo/gocommon"
"repositories.action2quare.com/ayo/gocommon/logger" "repositories.action2quare.com/ayo/gocommon/logger"
"go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson"
@ -18,6 +19,14 @@ import (
"go.mongodb.org/mongo-driver/mongo/options" "go.mongodb.org/mongo-driver/mongo/options"
) )
type authPipelineDocument struct {
OperationType string `bson:"operationType"`
DocumentKey struct {
Id primitive.ObjectID `bson:"_id"`
} `bson:"documentKey"`
Authinfo *gocommon.Authinfo `bson:"fullDocument"`
}
type servicePipelineDocument struct { type servicePipelineDocument struct {
OperationType string `bson:"operationType"` OperationType string `bson:"operationType"`
DocumentKey struct { DocumentKey struct {
@ -213,3 +222,87 @@ func (mg *Maingate) watchServiceCollection(parentctx context.Context, serveMux *
} }
} }
} }
func watchAuthCollection(parentctx context.Context, ac *gocommon.AuthCollection, mongoClient gocommon.MongoClient) {
defer func() {
s := recover()
if s != nil {
logger.Error(s)
}
}()
matchStage := bson.D{
{
Key: "$match", Value: bson.D{
{Key: "operationType", Value: bson.D{
{Key: "$in", Value: bson.A{
"delete",
"insert",
"update",
}},
}},
},
}}
projectStage := bson.D{
{
Key: "$project", Value: bson.D{
{Key: "documentKey", Value: 1},
{Key: "operationType", Value: 1},
{Key: "fullDocument", Value: 1},
},
},
}
var stream *mongo.ChangeStream
var err error
var ctx context.Context
for {
if stream == nil {
stream, err = mongoClient.Watch(CollectionAuth, mongo.Pipeline{matchStage, projectStage})
if err != nil {
logger.Error("watchAuthCollection watch failed :", err)
time.Sleep(time.Minute)
continue
}
ctx = context.TODO()
}
changed := stream.TryNext(ctx)
if ctx.Err() != nil {
logger.Error("watchAuthCollection stream.TryNext failed. process should be restarted! :", ctx.Err().Error())
break
}
if changed {
var data authPipelineDocument
if err := stream.Decode(&data); err == nil {
ot := data.OperationType
switch ot {
case "insert":
ac.AddRaw(&mongoAuthCell{src: data.Authinfo})
case "update":
ac.AddRaw(&mongoAuthCell{src: data.Authinfo})
case "delete":
ac.RemoveByAccId(data.DocumentKey.Id)
}
} else {
logger.Error("watchAuthCollection stream.Decode failed :", err)
}
} else if stream.Err() != nil || stream.ID() == 0 {
select {
case <-ctx.Done():
logger.Println("watchAuthCollection is done")
stream.Close(ctx)
return
case <-time.After(time.Second):
logger.Error("watchAuthCollection stream error :", stream.Err())
stream.Close(ctx)
stream = nil
}
} else {
time.Sleep(time.Second)
}
}
}

6
go.mod
View File

@ -1,13 +1,13 @@
module repositories.action2quare.com/ayo/maingate module repositories.action2quare.com/ayo/maingate
go 1.19 go 1.18
require ( require (
firebase.google.com/go v3.13.0+incompatible firebase.google.com/go v3.13.0+incompatible
github.com/golang-jwt/jwt v3.2.2+incompatible github.com/golang-jwt/jwt v3.2.2+incompatible
go.mongodb.org/mongo-driver v1.11.7 go.mongodb.org/mongo-driver v1.11.7
google.golang.org/api v0.128.0 google.golang.org/api v0.128.0
repositories.action2quare.com/ayo/gocommon v0.0.0-20231128132952-e5a5240f96d8 repositories.action2quare.com/ayo/gocommon v0.0.0-20230912075917-f9a146321cdb
) )
require ( require (
@ -53,3 +53,5 @@ require (
google.golang.org/grpc v1.56.0 // indirect google.golang.org/grpc v1.56.0 // indirect
google.golang.org/protobuf v1.30.0 // indirect google.golang.org/protobuf v1.30.0 // indirect
) )
replace repositories.action2quare.com/ayo/maingate => ./

4
go.sum
View File

@ -268,5 +268,5 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
repositories.action2quare.com/ayo/gocommon v0.0.0-20231128132952-e5a5240f96d8 h1:GbvfiscAV/gquGzC9bJ3RTNtezLcdfGOv+9JmAZYQVc= repositories.action2quare.com/ayo/gocommon v0.0.0-20230912075917-f9a146321cdb h1:Rdf6uhBIWunRLZ2LIT1hSovYXxZoOzx9mdSK5bjWpos=
repositories.action2quare.com/ayo/gocommon v0.0.0-20231128132952-e5a5240f96d8/go.mod h1:XvklTTSvQX5uviivGBcZo8eIL+mV94W2e4uBBXcT5JY= repositories.action2quare.com/ayo/gocommon v0.0.0-20230912075917-f9a146321cdb/go.mod h1:rn6NA28Mej+qgLNx/Bu2wsdGyIycmacqlNP6gUXX2a0=

15
main.go
View File

@ -2,7 +2,9 @@ package main
import ( import (
"context" "context"
"math/rand"
"net/http" "net/http"
"time"
"repositories.action2quare.com/ayo/gocommon" "repositories.action2quare.com/ayo/gocommon"
"repositories.action2quare.com/ayo/gocommon/flagx" "repositories.action2quare.com/ayo/gocommon/flagx"
@ -19,29 +21,26 @@ func main() {
flagx.Parse() flagx.Parse()
logger.Println("build revision =", revision) logger.Println("build revision =", revision)
rand.Seed(time.Now().UnixNano())
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
defer cancel()
mg, err := core.New(ctx) mg, err := core.New(ctx)
if err != nil { if err != nil {
logger.Error("core.New failed :", err) logger.Error("core.New failed :", err)
return panic(err)
} }
defer mg.Destructor()
serveMux := http.NewServeMux() serveMux := http.NewServeMux()
if err := mg.RegisterHandlers(ctx, serveMux, *prefix); err != nil { if err := mg.RegisterHandlers(ctx, serveMux, *prefix); err != nil {
logger.Error("RegisterHandlers failed :", err) logger.Error("RegisterHandlers failed :", err)
return panic(err)
} }
server := gocommon.NewHTTPServer(serveMux) server := gocommon.NewHTTPServer(serveMux)
logger.Println("maingate is started") logger.Println("maingate is started")
if err := server.Start(); err != nil { if err := server.Start(); err != nil {
logger.Error("maingate is stopped with error :", err) logger.Error("maingate is stopped with error :", err)
} }
cancel()
logger.Println("maingate is terminated") mg.Destructor()
} }

14
make_maingate_package.ps1 Normal file
View File

@ -0,0 +1,14 @@
# $ErrorActionPreference = 'SilentlyContinue'
$CurBranch = git branch --show-current
Remove-Item maingate.zip -Force -Recurse -ErrorAction SilentlyContinue
$Env:GOOS="linux"
$Env:GOARCH="amd64"
go build -ldflags="-s -w" .
Compress-Archive -Path maingate -Update -DestinationPath maingate.zip
Compress-Archive -Path *-firebase-*.json -Update -DestinationPath maingate.zip
Compress-Archive -Path fba -Update -DestinationPath maingate.zip
Compress-Archive -Path template -Update -DestinationPath maingate.zip