servcvgen/handlers_mng_users.go

348 lines
12 KiB
Go

package main
import (
"bytes"
b64 "encoding/base64"
"encoding/json"
"fmt"
"net/http"
"strings"
"github.com/gin-gonic/gin"
utils "github.com/jesusperez/datautils"
"gopkg.in/yaml.v2"
)
func send_invitation_handle(c *gin.Context, rtenv *RouteEnv) {
role := rtenv.Cfg.AdminRole
user,res := user_has_role(nil,c,rtenv,role)
if !res {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Authentication failed"})
return
}
var sendData PostInvitation
err := c.BindJSON(&sendData)
if err != nil {
fmt.Printf("err: %+v\n", err)
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save info"})
return
}
if len(sendData.Data.Email) == 0 {
c.JSON(http.StatusNotAcceptable, gin.H{"error": "no data found"})
return
}
accept_langs := strings.Split(c.Request.Header.Get("Accept-Language"),";")
langs := strings.Split(accept_langs[0], ",")
tplPath := fmt.Sprintf("%s/%s_%s",rtenv.Cfg.TplsMailPath,langs[0],rtenv.Cfg.TplsMail["newuser"].Path)
if ! utils.ExistsPath(tplPath) {
tplPath = fmt.Sprintf("%s/%s",rtenv.Cfg.TplsMailPath,rtenv.Cfg.TplsMail["newuser"].Path)
if ! utils.ExistsPath(tplPath) {
c.JSON(http.StatusNotAcceptable, gin.H{"error": "no template found"})
return
}
}
target := rtenv.Cfg.MailFrom
bodyData := sendData
if len(sendData.Data.Expire) > 0 {
bodyData.Data.Expire = fmt.Sprintf("Expire: %s",sendData.Data.Expire)
}
request := Mail{
Sender: target,
To: []string{sendData.Data.Email},
Cc: []string{},
Bcc: []string{},
Subject: fmt.Sprintf("Invitation "),
Body: bytes.Buffer{},
}
err = email(rtenv.Cfg, "text", tplPath, "", "", request,bodyData)
if err == nil {
fmt.Printf("Invitation send from (%s): %s\n",user.UserName, target)
logRoute(c,rtenv,"send_inivitation",fmt.Sprintf("get %s: %s",user.UserName,target), fmt.Sprintf("get %s: %s",user.UserName,target))
c.JSON(http.StatusOK, sendData)
} else {
fmt.Printf("Error send invitation from (%s) %s: %v\n", user.UserName, target, err)
logRoute(c,rtenv,"send_invitation",fmt.Sprintf("get %s: read error %v ",user.UserName,err), fmt.Sprintf("get %s: %s",user.UserName,target))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to send invitation"})
}
}
func get_invitation_handle(c *gin.Context, rtenv *RouteEnv) {
id := c.Params.ByName(rtenv.Cfg.Routes["invitation"].Param)
usrsInvitations,err := getUsersInvitations(rtenv.Cfg.InvitationsPath,true)
if err != nil {
logRoute(c,rtenv,"users",fmt.Sprintf("get /invitation error %v",err),fmt.Sprintf("get invitation %s",id))
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("Failed to get invitation %s",id)})
return
}
if val, ok := usrsInvitations[id]; ok {
invitation, valid, needSync := checkUserInvitation(id, usrsInvitations[id], 1)
if (needSync) {
allInvitations, err := loadUsersInvitations(rtenv.Cfg.InvitationsPath)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("Failed to validate invitation %s",id)})
return
}
allInvitations[id]=invitation
strdata, yamlerr := yaml.Marshal(allInvitations)
if yamlerr != nil {
fmt.Printf("Error parse invitations yaml %s: %v",rtenv.Cfg.InvitationsPath,yamlerr)
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("Failed to sync invitations %s",id)})
return
}
if res := utils.WriteData(string(strdata),rtenv.Cfg.InvitationsPath) ; res != nil {
logRoute(c,rtenv,"post_users",fmt.Sprintf("Error write invitations: %s",id), fmt.Sprintf("error: %+v",res))
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("Failed to sync invitation %s",id)})
return
}
}
if !valid {
logRoute(c,rtenv,"users",fmt.Sprintf("get /invitation error %v",err),fmt.Sprintf("get invitation not valid %s",id))
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("Failed to validate invitation %s",id)})
return
}
tkn := ""
if rtenv.Cfg.UseAuthz {
data := &User{
UserName: val.Email,
UUID: id,
Data: "Invitation",
FirstName: "",
LastName: "",
}
tkn,err = makeTokenString(rtenv,data)
if err != nil {
fmt.Printf("tkn err: %+v\n", err)
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to auth"})
return
}
}
logRoute(c,rtenv,"users",fmt.Sprintf("get /invitation %s",id),fmt.Sprintf("get invitation %s (%s) %s",val.Email,val.Role,val.Data))
data := NewUserData{ Email: val.Email, Role: val.Role, Data: val.Data }
strdata,err := json.Marshal(data)
if err == nil {
c.JSON(http.StatusOK, gin.H{"data": b64.StdEncoding.EncodeToString(strdata),"auth": tkn})
return
} else {
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("Failed to confirm invitation %s",id)})
return
}
} else {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invitation not found"})
}
}
func get_users_handle(c *gin.Context, rtenv *RouteEnv) {
idusr := rtenv.AuthMiddleware.IdentityHandler(c)
user, okusr := idusr.(*User)
if !okusr || len(user.UserName) == 0 {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Authentication failed"})
return
}
role := rtenv.Cfg.AdminRole
if _,res := user_has_role(user,c,rtenv,role); !res {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Authentication failed"})
return
}
usersData := &UsersData {
UsersData: "",
ModelsData: "",
Invitations: "",
AuthzModel: "",
AuthzPolicy: "",
}
if utils.ExistsPath(rtenv.Cfg.UsersPath) {
data,err := loadPath(rtenv.Cfg.UsersPath)
if err != nil {
logRoute(c,rtenv,"config",fmt.Sprintf("get /users error %v",err),fmt.Sprintf("get userspath %s (%s)",user.UserName,role))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to load users data"})
return
}
usersData.UsersData = b64.StdEncoding.EncodeToString(data)
}
if utils.ExistsPath(rtenv.Cfg.UsersModelsPath) {
data,err := loadPath(rtenv.Cfg.UsersModelsPath)
if err != nil {
logRoute(c,rtenv,"config",fmt.Sprintf("get /users error %v",err),fmt.Sprintf("get usersmodels %s (%s)",user.UserName,role))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to load users models"})
return
}
usersData.ModelsData = b64.StdEncoding.EncodeToString(data)
}
if utils.ExistsPath(rtenv.Cfg.InvitationsPath) {
data,err := loadPath(rtenv.Cfg.InvitationsPath)
if err != nil {
logRoute(c,rtenv,"config",fmt.Sprintf("get /users error %v",err),fmt.Sprintf("get invitations %s (%s)",user.UserName,role))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to load users invitations"})
return
}
usersData.Invitations = b64.StdEncoding.EncodeToString(data)
}
if rtenv.Cfg.UseAuthz {
if utils.ExistsPath(rtenv.Cfg.AuthzModel) {
data,err := loadPath(rtenv.Cfg.AuthzModel)
if err != nil {
logRoute(c,rtenv,"config",fmt.Sprintf("get /users error %v",err),fmt.Sprintf("get authzmodels %s (%s)",user.UserName,role))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to load authz models"})
return
}
usersData.AuthzModel = b64.StdEncoding.EncodeToString(data)
}
if utils.ExistsPath(rtenv.Cfg.AuthzPolicy) {
data,err := loadPath(rtenv.Cfg.AuthzPolicy)
if err != nil {
logRoute(c,rtenv,"config",fmt.Sprintf("get /users error %v",err),fmt.Sprintf("get authzpolizy %s (%s)",user.UserName,role))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to load authz policy"})
return
}
usersData.AuthzPolicy = b64.StdEncoding.EncodeToString(data)
}
}
logRoute(c,rtenv,"config","get /users",fmt.Sprintf("get users %s (%s)",user.UserName,role))
c.JSON(http.StatusOK, gin.H{"data": usersData})
}
func save_users_data(saveInfo SaveDataInfo,c *gin.Context,rtenv *RouteEnv) bool {
path := fmt.Sprintf("%s%s",saveInfo.Prfx, saveInfo.Path)
data,err := b64.StdEncoding.DecodeString(saveInfo.Data)
if err != nil {
fmt.Printf("Error save %s: %v",path,err)
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("Failed to save %s",saveInfo.Title)})
return false
}
var accounts map[string]Account
err = yaml.Unmarshal([]byte(data), &accounts)
if err != nil {
fmt.Printf("Error parse yaml %s: %v",path,err)
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("Failed to save %s",saveInfo.Title)})
return false
}
prfx := rtenv.Cfg.PasswdEnc
var allUsers = map[string]Account{}
for key, item := range accounts {
if strings.HasPrefix(item.Passwd,"enc:") {
txtPasswd := strings.Replace(item.Passwd,prfx,"",-1)
passwd,err := encrypt(txtPasswd, string(CRYPTKEY))
if err == nil {
item.Passwd = passwd
allUsers[key] = item
}
} else {
allUsers[key] = item
}
}
strdata, yamlerr := yaml.Marshal(allUsers)
if yamlerr != nil {
fmt.Printf("Error parse yaml %s: %v",path,yamlerr)
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("Failed to save %s",saveInfo.Title)})
return false
}
if res := utils.WriteData(string(strdata),path) ; res != nil {
logRoute(c,rtenv,"post_users",fmt.Sprintf("Error post %s: %s",saveInfo.Title,saveInfo.Id), fmt.Sprintf("error: %+v",res))
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("Failed to save %s",saveInfo.Title)})
return false
}
return true
}
func save_file_data(saveInfo SaveDataInfo,c *gin.Context,rtenv *RouteEnv) bool {
path := fmt.Sprintf("%s%s",saveInfo.Prfx, saveInfo.Path)
data,err := b64.StdEncoding.DecodeString(saveInfo.Data)
if err != nil {
fmt.Printf("Error save %s: %v",path,err)
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("Failed to save %s",saveInfo.Title)})
return false
}
if res := utils.WriteData(string(data),path) ; res != nil {
logRoute(c,rtenv,"post_users",fmt.Sprintf("Error post %s: %s",saveInfo.Title,saveInfo.Id), fmt.Sprintf("error: %+v",res))
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("Failed to save %s",saveInfo.Title)})
return false
}
return true
}
func post_users_handle(c *gin.Context, rtenv *RouteEnv) {
var postdata UsersDataPost
role := rtenv.Cfg.AdminRole
err := c.BindJSON(&postdata)
if err != nil {
fmt.Printf("err: %+v\n", err)
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save users"})
return
}
if len(postdata.Id) == 0 {
c.JSON(http.StatusNotAcceptable, gin.H{"info": "error users"})
return
}
hasRole,_ := rtenv.Enforcer.HasRoleForUser(postdata.Id,role)
// fmt.Printf("post users: %s (%s) %+v\n",postdata.Id, role, hasRole)
if !hasRole {
logRoute(c,rtenv,"post_users",fmt.Sprintf("post %s: has no role",postdata.Id), fmt.Sprintf("post %s",postdata.Id))
c.JSON(http.StatusUnauthorized, gin.H{"error": "Authentication failed"})
return
}
savedList := ""
if len(postdata.Data.UsersData) > 0 {
saveInfo := SaveDataInfo{
Title: "users",
Data: postdata.Data.UsersData,
Id: postdata.Id,
Path: rtenv.Cfg.UsersPath,
Prfx: "new_",
}
if !save_users_data(saveInfo,c,rtenv) {
return
}
savedList = "usersData"
}
if len(postdata.Data.ModelsData) > 0 {
saveInfo := SaveDataInfo{
Title: "users models",
Data: postdata.Data.ModelsData,
Id: postdata.Id,
Path: rtenv.Cfg.UsersModelsPath,
Prfx: "new_",
}
if !save_file_data(saveInfo,c,rtenv) {
return
}
savedList = fmt.Sprintf("%s,modelsData",savedList)
}
if len(postdata.Data.Invitations) > 0 {
saveInfo := SaveDataInfo{
Title: "users invitations",
Data: postdata.Data.Invitations,
Id: postdata.Id,
Path: rtenv.Cfg.InvitationsPath,
Prfx: "new_",
}
if !save_file_data(saveInfo,c,rtenv) {
return
}
savedList = fmt.Sprintf("%s,invitations",savedList)
}
if rtenv.Cfg.UseAuthz {
if len(postdata.Data.AuthzModel) > 0 {
saveInfo := SaveDataInfo{
Title: "users authz models",
Data: postdata.Data.AuthzModel,
Id: postdata.Id,
Path: rtenv.Cfg.AuthzModel,
Prfx: "new_",
}
if !save_file_data(saveInfo,c,rtenv) {
return
}
savedList = fmt.Sprintf("%s,authzModels",savedList)
}
if len(postdata.Data.AuthzPolicy) > 0 {
saveInfo := SaveDataInfo{
Title: "users authz policy",
Data: postdata.Data.AuthzPolicy,
Id: postdata.Id,
Path: rtenv.Cfg.AuthzPolicy,
Prfx: "new_",
}
if !save_file_data(saveInfo,c,rtenv) {
return
}
savedList = fmt.Sprintf("%s,authzPolicy",savedList)
}
}
logRoute(c,rtenv,"post_users",fmt.Sprintf("post %s: users",postdata.Id), fmt.Sprintf("post %s: %s",postdata.Id,savedList))
c.JSON(http.StatusOK, gin.H{"status": "ok"})
}