Files
gocommon/apicaller/api_caller_auths.go

215 lines
3.9 KiB
Go

package apicaller
import (
"encoding/json"
"os"
"strings"
"sync"
"sync/atomic"
"unsafe"
)
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 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
}