apicaller package 추가
This commit is contained in:
220
apicaller/api_caller_auths.go
Normal file
220
apicaller/api_caller_auths.go
Normal file
@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user