파일 업로드 추가 / 화이트리스트에 권한 종류 추가
This commit is contained in:
213
core/service.go
213
core/service.go
@ -7,6 +7,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"path"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
@ -26,16 +27,25 @@ type blockinfo struct {
|
||||
Reason string
|
||||
}
|
||||
|
||||
type whitelistAuthType = string
|
||||
|
||||
const (
|
||||
whitelistAuthType_Default = whitelistAuthType("")
|
||||
whitelistAuthType_QA = whitelistAuthType("qa")
|
||||
)
|
||||
|
||||
type whitelistmember struct {
|
||||
Service string
|
||||
Email string
|
||||
Platform string
|
||||
Desc string
|
||||
Auth []whitelistAuthType
|
||||
Expired primitive.DateTime `bson:"_ts,omitempty" json:"_ts,omitempty"`
|
||||
}
|
||||
|
||||
type whitelist struct {
|
||||
emailptr unsafe.Pointer
|
||||
qaptr unsafe.Pointer
|
||||
working int32
|
||||
}
|
||||
|
||||
@ -50,17 +60,33 @@ type usertokeninfo struct {
|
||||
}
|
||||
|
||||
func (wl *whitelist) init(total []whitelistmember) {
|
||||
next := make(map[string]*whitelistmember)
|
||||
auths := make(map[string]map[string]*whitelistmember)
|
||||
for _, member := range total {
|
||||
next[whitelistKey(member.Email)] = &member
|
||||
}
|
||||
all := auths[""]
|
||||
if all == nil {
|
||||
all = make(map[string]*whitelistmember)
|
||||
auths[""] = all
|
||||
}
|
||||
all[whitelistKey(member.Email)] = &member
|
||||
|
||||
atomic.StorePointer(&wl.emailptr, unsafe.Pointer(&next))
|
||||
atomic.StoreInt32(&wl.working, 1)
|
||||
for _, auth := range member.Auth {
|
||||
spec := auths[auth]
|
||||
if spec == nil {
|
||||
spec = make(map[string]*whitelistmember)
|
||||
auths[auth] = spec
|
||||
}
|
||||
spec[whitelistKey(member.Email)] = &member
|
||||
}
|
||||
}
|
||||
all := auths[whitelistAuthType_Default]
|
||||
atomic.StorePointer(&wl.emailptr, unsafe.Pointer(&all))
|
||||
|
||||
qa := auths[whitelistAuthType_QA]
|
||||
atomic.StorePointer(&wl.qaptr, unsafe.Pointer(&qa))
|
||||
}
|
||||
|
||||
func (wl *whitelist) add(m *whitelistmember) {
|
||||
ptr := atomic.LoadPointer(&wl.emailptr)
|
||||
func addToUnsafePointer(to *unsafe.Pointer, m *whitelistmember) {
|
||||
ptr := atomic.LoadPointer(to)
|
||||
src := (*map[string]*whitelistmember)(ptr)
|
||||
|
||||
next := map[string]*whitelistmember{}
|
||||
@ -68,11 +94,11 @@ func (wl *whitelist) add(m *whitelistmember) {
|
||||
next[k] = v
|
||||
}
|
||||
next[whitelistKey(m.Email)] = m
|
||||
atomic.StorePointer(&wl.emailptr, unsafe.Pointer(&next))
|
||||
atomic.StorePointer(to, unsafe.Pointer(&next))
|
||||
}
|
||||
|
||||
func (wl *whitelist) remove(email string) {
|
||||
ptr := atomic.LoadPointer(&wl.emailptr)
|
||||
func removeFromUnsafePointer(from *unsafe.Pointer, email string) {
|
||||
ptr := atomic.LoadPointer(from)
|
||||
src := (*map[string]*whitelistmember)(ptr)
|
||||
|
||||
next := make(map[string]*whitelistmember)
|
||||
@ -80,7 +106,21 @@ func (wl *whitelist) remove(email string) {
|
||||
next[k] = v
|
||||
}
|
||||
delete(next, whitelistKey(email))
|
||||
atomic.StorePointer(&wl.emailptr, unsafe.Pointer(&next))
|
||||
atomic.StorePointer(from, unsafe.Pointer(&next))
|
||||
}
|
||||
|
||||
func (wl *whitelist) add(m *whitelistmember) {
|
||||
addToUnsafePointer(&wl.emailptr, m)
|
||||
for _, auth := range m.Auth {
|
||||
if auth == whitelistAuthType_QA {
|
||||
addToUnsafePointer(&wl.qaptr, m)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (wl *whitelist) remove(email string) {
|
||||
removeFromUnsafePointer(&wl.emailptr, email)
|
||||
removeFromUnsafePointer(&wl.qaptr, email)
|
||||
}
|
||||
|
||||
func (wl *whitelist) isMember(email string, platform string) bool {
|
||||
@ -97,30 +137,46 @@ func (wl *whitelist) isMember(email string, platform string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (wl *whitelist) hasAuth(email string, platform string, auth whitelistAuthType) bool {
|
||||
if auth == whitelistAuthType_QA {
|
||||
ptr := atomic.LoadPointer(&wl.qaptr)
|
||||
src := *(*map[string]*whitelistmember)(ptr)
|
||||
|
||||
if member, exists := src[whitelistKey(email)]; exists {
|
||||
return member.Platform == platform
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
type divisionStateName string
|
||||
|
||||
const (
|
||||
DivisionState_Closed = string("closed")
|
||||
DivisionState_Maintenance = string("maintenance")
|
||||
DivisionState_RestrictedOpen = string("restricted")
|
||||
DivisionState_FullOpen = string("open")
|
||||
DivisionState_Closed = divisionStateName("closed")
|
||||
DivisionState_Maintenance = divisionStateName("maintenance")
|
||||
DivisionState_RestrictedOpen = divisionStateName("restricted")
|
||||
DivisionState_FullOpen = divisionStateName("open")
|
||||
)
|
||||
|
||||
type maintenance struct {
|
||||
Link string
|
||||
StartTime primitive.Timestamp
|
||||
Notice string `bson:"notice"`
|
||||
StartTimeUTC int64 `bson:"start_unixtime_utc" json:"start_unixtime_utc"`
|
||||
link string
|
||||
}
|
||||
|
||||
type division struct {
|
||||
Url string `bson:"url"`
|
||||
Priority int `bson:"priority"`
|
||||
State string `bson:"state"`
|
||||
Maintenance maintenance `bson:"maintenance"`
|
||||
Url string `bson:"url"`
|
||||
Priority int `bson:"priority"`
|
||||
State divisionStateName `bson:"state"`
|
||||
Maintenance *maintenance `bson:"maintenance"`
|
||||
}
|
||||
|
||||
type serviceDescription struct {
|
||||
// sync.Mutex
|
||||
Id primitive.ObjectID `bson:"_id"`
|
||||
ServiceName string `bson:"service"`
|
||||
Divisions map[string]division `bson:"divisions"`
|
||||
Divisions map[string]*division `bson:"divisions"`
|
||||
ServiceCode string `bson:"code"`
|
||||
UseWhitelist bool `bson:"use_whitelist"`
|
||||
Closed bool `bson:"closed"`
|
||||
@ -175,12 +231,46 @@ func (sh *serviceDescription) readProfile(authtype string, id string, binfo stri
|
||||
}
|
||||
|
||||
func (sh *serviceDescription) prepare(mg *Maingate) error {
|
||||
div := sh.Divisions
|
||||
divs := sh.Divisions
|
||||
if len(sh.ServiceCode) == 0 {
|
||||
sh.ServiceCode = hex.EncodeToString(sh.Id[6:])
|
||||
}
|
||||
|
||||
divmarshaled, _ := json.Marshal(div)
|
||||
var closed []string
|
||||
for dn, div := range divs {
|
||||
if div.State == DivisionState_Closed {
|
||||
closed = append(closed, dn)
|
||||
continue
|
||||
}
|
||||
|
||||
if len(div.State) == 0 {
|
||||
div.State = DivisionState_FullOpen
|
||||
}
|
||||
|
||||
if div.State != DivisionState_FullOpen {
|
||||
if div.Maintenance == nil {
|
||||
div.Maintenance = &maintenance{}
|
||||
}
|
||||
|
||||
if len(div.Maintenance.link) == 0 {
|
||||
if len(div.Maintenance.Notice) == 0 {
|
||||
div.Maintenance.link = "https://www.action2quare.com"
|
||||
} else if strings.HasPrefix(div.Maintenance.Notice, "http") {
|
||||
div.Maintenance.link = div.Maintenance.Notice
|
||||
} else {
|
||||
div.Maintenance.link = path.Join("static", sh.ServiceCode, div.Maintenance.Notice)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
div.Maintenance = nil
|
||||
}
|
||||
}
|
||||
|
||||
for _, dn := range closed {
|
||||
delete(divs, dn)
|
||||
}
|
||||
|
||||
divmarshaled, _ := json.Marshal(divs)
|
||||
devstr := string(divmarshaled)
|
||||
sh.divisionsSerialized = unsafe.Pointer(&devstr)
|
||||
|
||||
@ -200,15 +290,17 @@ func (sh *serviceDescription) prepare(mg *Maingate) error {
|
||||
sh.closed = 0
|
||||
}
|
||||
|
||||
if sh.UseWhitelist {
|
||||
var whites []whitelistmember
|
||||
if err := mg.mongoClient.FindAllAs(CollectionWhitelist, bson.M{
|
||||
"$or": []bson.M{{"service": sh.ServiceName}, {"service": sh.ServiceCode}},
|
||||
}, &whites, options.Find().SetReturnKey(false)); err != nil {
|
||||
return err
|
||||
}
|
||||
var whites []whitelistmember
|
||||
if err := mg.mongoClient.FindAllAs(CollectionWhitelist, bson.M{
|
||||
"$or": []bson.M{{"service": sh.ServiceName}, {"service": sh.ServiceCode}},
|
||||
}, &whites, options.Find().SetReturnKey(false)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sh.wl.init(whites)
|
||||
sh.wl.init(whites)
|
||||
|
||||
if sh.UseWhitelist {
|
||||
sh.wl.working = 1
|
||||
} else {
|
||||
sh.wl.working = 0
|
||||
}
|
||||
@ -517,9 +609,9 @@ func (sh *serviceDescription) authorize(w http.ResponseWriter, r *http.Request)
|
||||
ServiceCode: sh.ServiceCode,
|
||||
Platform: authtype,
|
||||
Uid: uid,
|
||||
//Token: accesstoken,
|
||||
Sk: newsession,
|
||||
Expired: expired,
|
||||
Email: email,
|
||||
Sk: newsession,
|
||||
Expired: expired,
|
||||
//RefreshToken: queryvals.Get("rt"),
|
||||
}
|
||||
|
||||
@ -604,8 +696,6 @@ func (sh *serviceDescription) ServeHTTP(w http.ResponseWriter, r *http.Request)
|
||||
} else {
|
||||
// TODO : 세션키와 authtoken을 헤더로 받아서 accid 조회
|
||||
queryvals := r.URL.Query()
|
||||
//token := queryvals.Get("token")
|
||||
token := "" // 더이상 쓰지 않는다.
|
||||
sk := queryvals.Get("sk")
|
||||
|
||||
//if len(token) == 0 || len(sk) == 0 {
|
||||
@ -617,14 +707,53 @@ func (sh *serviceDescription) ServeHTTP(w http.ResponseWriter, r *http.Request)
|
||||
// TODO : 각 서버에 있는 자산? 캐릭터 정보를 보여줘야 하나. 뭘 보여줄지는 프로젝트에 문의
|
||||
// 일단 서버 종류만 내려보내자
|
||||
// 세션키가 있는지 확인
|
||||
if _, ok := sh.auths.IsValid(sk, token); !ok {
|
||||
logger.Println("sessionkey is not valid :", sk, token)
|
||||
if _, ok := sh.auths.IsValid(sk, ""); !ok {
|
||||
logger.Println("sessionkey is not valid :", sk)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
divstrptr := atomic.LoadPointer(&sh.divisionsSerialized)
|
||||
divstr := *(*string)(divstrptr)
|
||||
w.Write([]byte(divstr))
|
||||
if divname := queryvals.Get("div"); len(divname) > 0 {
|
||||
divname = strings.Trim(divname, `"`)
|
||||
// 점검중인지 아닌지 확인
|
||||
// 점검중이어도 입장이 가능한 인원이 있다.
|
||||
div := sh.Divisions[divname]
|
||||
if div != nil {
|
||||
switch div.State {
|
||||
case DivisionState_FullOpen:
|
||||
w.Write([]byte(fmt.Sprintf(`{"service":"%s"}`, div.Url)))
|
||||
|
||||
case DivisionState_RestrictedOpen:
|
||||
// 점검중인데 일부 권한을 갖고 있는 유저만 들어갈 수 있는 상태
|
||||
cell := sh.auths.QuerySession(sk, "")
|
||||
if cell == nil {
|
||||
logger.Println("sessionkey is not valid :", sk)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if sh.wl.hasAuth(cell.ToAuthinfo().Email, cell.ToAuthinfo().Platform, whitelistAuthType_QA) {
|
||||
// qa 권한이면 입장 가능
|
||||
w.Write([]byte(fmt.Sprintf(`{"service":"%s"}`, div.Url)))
|
||||
} else if div.Maintenance != nil {
|
||||
// 권한이 없으므로 공지
|
||||
w.Write([]byte(fmt.Sprintf(`{"notice":"%s"}`, div.Maintenance.link)))
|
||||
} else {
|
||||
logger.Println("div.Maintenance is nil :", divname)
|
||||
}
|
||||
|
||||
case DivisionState_Maintenance:
|
||||
// 점검중. 아무도 못들어감
|
||||
if div.Maintenance != nil {
|
||||
w.Write([]byte(fmt.Sprintf(`{"notice":"%s"}`, div.Maintenance.link)))
|
||||
} else {
|
||||
logger.Println("div.Maintenance is nil :", divname)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
divstrptr := atomic.LoadPointer(&sh.divisionsSerialized)
|
||||
divstr := *(*string)(divstrptr)
|
||||
w.Write([]byte(divstr))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user