flag를 내재화함
This commit is contained in:
205
core/api.go
205
core/api.go
@ -7,13 +7,11 @@ import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
@ -22,6 +20,7 @@ import (
|
||||
|
||||
common "repositories.action2quare.com/ayo/gocommon"
|
||||
"repositories.action2quare.com/ayo/gocommon/logger"
|
||||
"repositories.action2quare.com/ayo/maingate/flag"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
@ -76,79 +75,8 @@ func (fd *fileDocumentDesc) save() error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (caller apiCaller) isGlobalAdmin() bool {
|
||||
if *noauth {
|
||||
return true
|
||||
}
|
||||
|
||||
email, ok := caller.userinfo["email"]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
if _, ok := caller.globalAdmins[email.(string)]; ok {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (caller apiCaller) writeAccessableServices(w http.ResponseWriter) {
|
||||
services, editable := caller.getAccessableServices()
|
||||
for _, r := range editable {
|
||||
w.Header().Add("MG-X-SERVICE-EDITABLE", r)
|
||||
}
|
||||
|
||||
w.Write([]byte("{"))
|
||||
start := true
|
||||
for _, v := range services {
|
||||
if !start {
|
||||
w.Write([]byte(","))
|
||||
}
|
||||
w.Write([]byte(fmt.Sprintf(`"%s":`, v.ServiceName)))
|
||||
serptr := atomic.LoadPointer(&v.serviceSummarySerialized)
|
||||
w.Write(*(*[]byte)(serptr))
|
||||
start = false
|
||||
}
|
||||
w.Write([]byte("}"))
|
||||
}
|
||||
|
||||
func (caller apiCaller) getAccessableServices() ([]*serviceDescription, []string) {
|
||||
allservices := caller.mg.services.all()
|
||||
|
||||
admin := caller.isGlobalAdmin()
|
||||
var email string
|
||||
if !*noauth {
|
||||
v, ok := caller.userinfo["email"]
|
||||
if !ok {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
email = v.(string)
|
||||
_, admin = caller.globalAdmins[email]
|
||||
}
|
||||
|
||||
var output []*serviceDescription
|
||||
var editable []string
|
||||
for _, desc := range allservices {
|
||||
if admin {
|
||||
output = append(output, desc)
|
||||
editable = append(editable, desc.ServiceName)
|
||||
} else if caller.isAdminOrValidToken(email) {
|
||||
output = append(output, desc)
|
||||
editable = append(editable, desc.ServiceName)
|
||||
}
|
||||
}
|
||||
|
||||
sort.Slice(output, func(i, j int) bool {
|
||||
return output[i].ServiceName < output[j].ServiceName
|
||||
})
|
||||
|
||||
return output, editable
|
||||
}
|
||||
|
||||
func (caller apiCaller) isAdmin(service any) bool {
|
||||
if *noauth {
|
||||
func (caller apiCaller) isAdmin() bool {
|
||||
if *flag.Noauth {
|
||||
return true
|
||||
}
|
||||
|
||||
@ -163,66 +91,49 @@ func (caller apiCaller) isAdmin(service any) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
svcdesc := caller.mg.services.get(service)
|
||||
if svcdesc == nil {
|
||||
logger.Println("isVaidUser failed. service is missing :", service)
|
||||
return false
|
||||
}
|
||||
|
||||
return svcdesc.isAdmin(email)
|
||||
return caller.mg.service().isAdmin(email)
|
||||
}
|
||||
|
||||
func (caller apiCaller) isAdminOrValidToken(service any) bool {
|
||||
if caller.isAdmin(service) {
|
||||
func (caller apiCaller) isAdminOrValidToken() bool {
|
||||
if caller.isAdmin() {
|
||||
return true
|
||||
}
|
||||
|
||||
sh := caller.mg.services.get(service)
|
||||
if sh == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return sh.isValidToken(caller.apiToken)
|
||||
return caller.mg.service().isValidToken(caller.apiToken)
|
||||
}
|
||||
|
||||
func (caller apiCaller) filesAPI(w http.ResponseWriter, r *http.Request) error {
|
||||
if r.Method == "GET" {
|
||||
servicename := r.FormValue("service")
|
||||
if !caller.isAdminOrValidToken(servicename) {
|
||||
if !caller.isAdminOrValidToken() {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
return nil
|
||||
}
|
||||
|
||||
var files []fileDocumentDesc
|
||||
err := caller.mg.mongoClient.FindAllAs(CollectionFile, bson.M{
|
||||
"service": servicename,
|
||||
}, &files, options.Find().SetProjection(bson.M{
|
||||
allfiles, err := caller.mg.mongoClient.All(CollectionFile, options.Find().SetProjection(bson.M{
|
||||
"contents": 0,
|
||||
}))
|
||||
}).SetReturnKey(false))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(files) > 0 {
|
||||
if len(allfiles) > 0 {
|
||||
enc := json.NewEncoder(w)
|
||||
return enc.Encode(files)
|
||||
return enc.Encode(allfiles)
|
||||
}
|
||||
} else if r.Method == "DELETE" {
|
||||
servicename := r.FormValue("service")
|
||||
key := r.FormValue("key")
|
||||
if len(servicename) == 0 || len(key) == 0 {
|
||||
if len(key) == 0 {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return nil
|
||||
}
|
||||
|
||||
if !caller.isAdminOrValidToken(servicename) {
|
||||
if !caller.isAdminOrValidToken() {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err := caller.mg.mongoClient.Delete(CollectionFile, bson.M{
|
||||
"service": servicename,
|
||||
"key": key,
|
||||
"key": key,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
@ -302,7 +213,7 @@ func (caller apiCaller) whitelistAPI(w http.ResponseWriter, r *http.Request) err
|
||||
if r.Method == "GET" {
|
||||
service := queryvals.Get("service")
|
||||
if len(service) > 0 {
|
||||
if !caller.isAdminOrValidToken(service) {
|
||||
if !caller.isAdminOrValidToken() {
|
||||
logger.Println("whitelistAPI failed. not vaild user :", r.Method, caller.userinfo)
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
return nil
|
||||
@ -335,7 +246,7 @@ func (caller apiCaller) whitelistAPI(w http.ResponseWriter, r *http.Request) err
|
||||
return err
|
||||
}
|
||||
|
||||
if !caller.isAdminOrValidToken(member.Service) {
|
||||
if !caller.isAdminOrValidToken() {
|
||||
logger.Println("whitelistAPI failed. not vaild user :", r.Method, caller.userinfo)
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
return nil
|
||||
@ -378,22 +289,21 @@ func (caller apiCaller) whitelistAPI(w http.ResponseWriter, r *http.Request) err
|
||||
|
||||
func (caller apiCaller) serviceAPI(w http.ResponseWriter, r *http.Request) error {
|
||||
mg := caller.mg
|
||||
queryvals := r.URL.Query()
|
||||
if r.Method == "GET" {
|
||||
name := queryvals.Get("name")
|
||||
if len(name) > 0 {
|
||||
if !caller.isAdminOrValidToken(name) {
|
||||
logger.Println("serviceAPI failed. not vaild user :", r.Method, caller.userinfo)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return nil
|
||||
if mg.service().Id.IsZero() {
|
||||
newService := serviceDescription{
|
||||
ServiceDescriptionSummary: ServiceDescriptionSummary{
|
||||
Id: primitive.NewObjectID(),
|
||||
},
|
||||
}
|
||||
|
||||
w.Header().Add("MG-X-SERVICE-EDITABLE", name)
|
||||
serptr := atomic.LoadPointer(&mg.services.get(name).serviceSerialized)
|
||||
w.Write(*(*[]byte)(serptr))
|
||||
} else {
|
||||
caller.writeAccessableServices(w)
|
||||
if err := newService.prepare(caller.mg); err != nil {
|
||||
return err
|
||||
}
|
||||
atomic.StorePointer(&mg.serviceptr, unsafe.Pointer(&newService))
|
||||
}
|
||||
|
||||
serptr := atomic.LoadPointer(&mg.service().serviceSerialized)
|
||||
w.Write(*(*[]byte)(serptr))
|
||||
} else if r.Method == "POST" {
|
||||
body, _ := io.ReadAll(r.Body)
|
||||
var service serviceDescription
|
||||
@ -401,31 +311,7 @@ func (caller apiCaller) serviceAPI(w http.ResponseWriter, r *http.Request) error
|
||||
return err
|
||||
}
|
||||
|
||||
if service.Id.IsZero() {
|
||||
if caller.isGlobalAdmin() {
|
||||
service.Id = primitive.NewObjectID()
|
||||
} else {
|
||||
logger.Println("serviceAPI failed. not vaild user :", r.Method, caller.userinfo)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return nil
|
||||
}
|
||||
} else if !caller.isAdminOrValidToken(service.Id) {
|
||||
logger.Println("serviceAPI failed. not vaild user :", r.Method, caller.userinfo)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(service.ServerApiTokens) == 0 {
|
||||
service.ServerApiTokens = []primitive.ObjectID{
|
||||
primitive.NewObjectID(),
|
||||
}
|
||||
}
|
||||
|
||||
filter := bson.M{"_id": service.Id}
|
||||
if len(service.ServiceCode) == 0 {
|
||||
service.ServiceCode = hex.EncodeToString(service.Id[6:])
|
||||
}
|
||||
|
||||
success, _, err := mg.mongoClient.Update(CollectionService, filter, bson.M{
|
||||
"$set": &service,
|
||||
}, options.Update().SetUpsert(true))
|
||||
@ -445,28 +331,10 @@ func (caller apiCaller) serviceAPI(w http.ResponseWriter, r *http.Request) error
|
||||
|
||||
func (caller apiCaller) maintenanceAPI(w http.ResponseWriter, r *http.Request) error {
|
||||
mg := caller.mg
|
||||
queryvals := r.URL.Query()
|
||||
if r.Method == "GET" {
|
||||
name := queryvals.Get("name")
|
||||
if len(name) > 0 {
|
||||
if !caller.isAdminOrValidToken(name) {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
return nil
|
||||
}
|
||||
w.Header().Add("MG-X-SERVICE-EDITABLE", name)
|
||||
serptr := atomic.LoadPointer(&mg.services.get(name).divisionsSerialized)
|
||||
w.Write(*(*[]byte)(serptr))
|
||||
} else {
|
||||
caller.writeAccessableServices(w)
|
||||
}
|
||||
serptr := atomic.LoadPointer(&mg.service().divisionsSerialized)
|
||||
w.Write(*(*[]byte)(serptr))
|
||||
} else if r.Method == "POST" {
|
||||
servicename := queryvals.Get("name")
|
||||
if !caller.isAdminOrValidToken(servicename) {
|
||||
logger.Println("maintenanceAPI failed. not vaild user :", r.Method, caller.userinfo)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return nil
|
||||
}
|
||||
|
||||
var divs map[string]*Division
|
||||
dec := json.NewDecoder(r.Body)
|
||||
if err := dec.Decode(&divs); err != nil {
|
||||
@ -475,7 +343,7 @@ func (caller apiCaller) maintenanceAPI(w http.ResponseWriter, r *http.Request) e
|
||||
}
|
||||
|
||||
_, _, err := mg.mongoClient.Update(CollectionService, bson.M{
|
||||
"service": servicename,
|
||||
"_Id": mg.service().Id,
|
||||
}, bson.M{
|
||||
"$set": bson.M{"divisions": divs},
|
||||
}, options.Update().SetUpsert(false))
|
||||
@ -498,7 +366,7 @@ func (caller apiCaller) accountAPI(w http.ResponseWriter, r *http.Request) error
|
||||
return nil
|
||||
}
|
||||
|
||||
if !caller.isAdminOrValidToken(service) {
|
||||
if !caller.isAdminOrValidToken() {
|
||||
logger.Println("accountAPI failed. not vaild user :", r.Method, caller.userinfo)
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
return nil
|
||||
@ -615,15 +483,14 @@ func (caller apiCaller) configAPI(w http.ResponseWriter, r *http.Request) error
|
||||
return errApiTokenMissing
|
||||
}
|
||||
|
||||
if _, exists := mg.apiTokenToService.get(apitoken); !exists {
|
||||
apitokenObj, _ := primitive.ObjectIDFromHex(apitoken)
|
||||
if !mg.service().isValidToken(apitokenObj) {
|
||||
return fmt.Errorf("mg-x-api-token is not valid : %s", apitoken)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var noauth = flag.Bool("noauth", false, "")
|
||||
|
||||
type apiCaller struct {
|
||||
userinfo map[string]any
|
||||
globalAdmins map[string]bool
|
||||
@ -646,7 +513,7 @@ func (mg *Maingate) api(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
var userinfo map[string]any
|
||||
|
||||
if !*noauth {
|
||||
if !*flag.Noauth {
|
||||
authheader := r.Header.Get("Authorization")
|
||||
if len(authheader) == 0 {
|
||||
logger.Println("Authorization header is not valid :", authheader)
|
||||
|
||||
Reference in New Issue
Block a user