From c6c9b7727b4699f8614b5b521b0db3cee890bfa8 Mon Sep 17 00:00:00 2001 From: mountain Date: Mon, 19 Jun 2023 11:29:10 +0900 Subject: [PATCH] =?UTF-8?q?apicaller=20package=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apicaller/api_caller_auths.go | 220 ++++++++++++++++++++++++++++++++++ 1 file changed, 220 insertions(+) create mode 100644 apicaller/api_caller_auths.go diff --git a/apicaller/api_caller_auths.go b/apicaller/api_caller_auths.go new file mode 100644 index 0000000..7716e97 --- /dev/null +++ b/apicaller/api_caller_auths.go @@ -0,0 +1,220 @@ +package apicaller + +import ( + "encoding/json" + "os" + "strings" + "sync" + "sync/atomic" + "unsafe" + + common "repositories.action2quare.com/ayo/gocommon" +) + +type ApiCaller interface { + HasAuthority(authPath string) bool + GetMyAuthority() []string +} + +type ApiCallerAuths interface { + NewApiCaller(user string) ApiCaller + NewApiCallerByServer() ApiCaller + Update(newusers map[string]*map[string]bool) error + Serialize() []byte +} + +type apiCallerAuths struct { + sync.Mutex + serialized unsafe.Pointer // *[]byte + users map[string]*map[string]bool // email -> authoriries +} + +func (a *apiCallerAuths) Serialize() []byte { + btptr := atomic.LoadPointer(&a.serialized) + return *(*[]byte)(btptr) +} + +func (a *apiCallerAuths) getAuthority(email string) []string { + a.Lock() + defer a.Unlock() + + auths := a.users[email] + if auths == nil { + return nil + } + + var out []string + for k, v := range *auths { + if v { + out = append(out, k) + } + } + return out +} + +func (a *apiCallerAuths) Update(newAuths map[string]*map[string]bool) error { + src := map[string][]string{} + for user, auths := range newAuths { + for cat, has := range *auths { + if has { + arr := append(src[cat], user) + src[cat] = arr + } else if _, ok := src[cat]; !ok { + src[cat] = []string{} + } + } + } + + a.Lock() + defer a.Unlock() + + file, err := os.Create(userAuthsFileName) + if err != nil { + return err + } + defer file.Close() + + enc := json.NewEncoder(file) + err = enc.Encode(src) + if err != nil { + return err + } + + a.users = newAuths + bt, _ := json.Marshal(newAuths) + atomic.StorePointer(&a.serialized, unsafe.Pointer(&bt)) + + return nil +} + +func (a *apiCallerAuths) hasAuthority(email string, authPath string) bool { + a.Lock() + defer a.Unlock() + + auths, ok := a.users[email] + if !ok { + return false + } + + if (*auths)[authPath] { + return true + } + + for k, v := range *auths { + if strings.HasPrefix(k, authPath+"/") { + return v + } + } + + return false +} + +const userAuthsFileName = "userauths.json" + +func NewApiCallerAuths() ApiCallerAuths { + var out apiCallerAuths + f, _ := os.Open(userAuthsFileName) + if f == nil { + emptyAuths := map[string][]string{ + "/admins": {"enter_first_admin_email@action2quare.com"}, + } + newf, _ := os.Create(userAuthsFileName) + if newf != nil { + enc := json.NewEncoder(newf) + enc.Encode(emptyAuths) + newf.Close() + + f, _ = os.Open(userAuthsFileName) + } + } + + if f != nil { + defer f.Close() + + var src map[string][]string + dec := json.NewDecoder(f) + dec.Decode(&src) + + compiled := make(map[string]*map[string]bool) + + // 전체 유저 목록을 먼저 뽑고나서 + for _, users := range src { + for _, user := range users { + if _, ok := compiled[user]; !ok { + compiled[user] = &map[string]bool{} + } + } + } + // 전체 유저한테 모든 카테고리를 설정한다. + for _, auths := range compiled { + for cat := range src { + (*auths)[cat] = false + } + } + // 이제 유저별 권한을 설정 + for category, users := range src { + for _, user := range users { + (*compiled[user])[category] = true + } + } + + out = apiCallerAuths{ + users: compiled, + } + } else { + + out = apiCallerAuths{ + users: map[string]*map[string]bool{}, + } + } + + marshaled, _ := json.Marshal(out.users) + out.serialized = unsafe.Pointer(&marshaled) + + return &out +} + +type apiCaller struct { + userAuths *apiCallerAuths + caller string +} + +func (a *apiCallerAuths) NewApiCaller(user string) ApiCaller { + if len(user) == 0 { + return nil + } + return &apiCaller{ + userAuths: a, + caller: user, + } +} + +func (a *apiCallerAuths) NewApiCallerByServer() ApiCaller { + return &apiCaller{ + userAuths: a, + caller: "", + } +} + +func (ac apiCaller) callByServer() bool { + return len(ac.caller) == 0 +} + +func (ac apiCaller) HasAuthority(authPath string) bool { + if *common.Devflag { + return true + } + + if ac.callByServer() { + return true + } + + return ac.userAuths.hasAuthority(ac.caller, authPath) +} + +func (ac apiCaller) GetMyAuthority() []string { + if !ac.callByServer() { + return ac.userAuths.getAuthority(ac.caller) + } + return nil +}