215 lines
3.9 KiB
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
|
|
}
|