348 lines
12 KiB
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"})
|
|
}
|