api key usage

main
alex 2023-07-04 23:19:46 +02:00
parent 0d545ebc86
commit 679f6a16a1
10 changed files with 341 additions and 48 deletions

View File

@ -895,3 +895,39 @@ func StartUnlockLockedGroupTaskStepsTicker() {
}
}
}
func StartGroupTask(userId string, groupTask structs.GroupTasks) {
groupTask.Id = uuid.New().String()
groupTask.CreatorUserId = userId
groupTask.CurrentTasksStep = 1
groupTask.Status = utils.GroupTasksStatusRunning
groupTask.StartedAt = time.Now()
database.DB.Create(&groupTask)
socketclients.BroadcastMessage(structs.SendSocketMessage{
Cmd: utils.SentCmdNewGroupTaskStarted,
Body: groupTask,
})
go RunGroupTask(RunGroupTaskArgs{
CreatorUserId: userId,
StartType: RunGroupTaskStartTypeNormal,
GroupTaskId: groupTask.Id,
Category: groupTask.Category,
GroupId: groupTask.GroupId,
Step: 1,
TaskStepId: "",
GlobalInputs: groupTask.GlobalInputs,
})
logger.AddGroupTasksLog(structs.LogMessage{
Id: 0,
Type: utils.LogTypeInfo,
Messages: []structs.LogData{
{Type: "userId", Value: userId},
{Type: "groupTaskId", Value: groupTask.Id},
{Type: "groupTaskName", Value: groupTask.GroupName},
},
})
}

View File

@ -1,8 +1,10 @@
package structs
import "encoding/json"
type ApiGroupTaskRequest struct {
Category string
GroupId string
Description string
GlobalInputs map[string]string
GlobalInputs json.RawMessage
}

View File

@ -18,8 +18,10 @@ const (
LenHeaderXAuthorization = 36
lenHeaderXAuthorization = "36"
LenUserId = 36
LenHeaderXApiKey = 36
HeaderXAuthorization = "X-Authorization"
HeaderXApiKey = "X-Api-Key"
MaxAvatarSize = 5 * 1024 * 1024 // 5 MB
@ -62,6 +64,8 @@ const (
SentCmdAllUsersUserDeactivation = 28
SentCmdGroupTasksCategoryGroupChanges = 29
SentCmdNewUserApiKeyCreated = 30
SentCmdDeletedUserApiKey = 31
SentCmdNewApiKeyUsageCount = 32
)
// commands received from web clients
@ -105,6 +109,13 @@ var (
"SessionId": "required,len=" + lenHeaderXAuthorization,
"ScannerName": "required,min=" + minScannerName + ",max=" + maxScannerName,
}
groupTaskRules = map[string]string{
"Category": "required",
"GroupId": "required",
"Description": "required",
"GlobalInputs": "required",
}
)
const (
@ -128,6 +139,8 @@ const (
PermissionAdminAreaDeleteRole = _adminAreaRoles + "delete_role"
PermissionAdminAreaMoveRoleUpDown = _adminAreaRoles + "move_role_up_down"
PermissionAdminAreaLogs = _adminArea + "logs"
PermissionUserProfileApiKeys = "user_profile.api_keys"
)
var SystemPermissions = []string{
@ -143,6 +156,7 @@ var SystemPermissions = []string{
PermissionAdminAreaDeleteRole,
PermissionAdminAreaMoveRoleUpDown,
PermissionAdminAreaLogs,
PermissionUserProfileApiKeys,
}
var DynamicGroupTasksPermissions = []string{

View File

@ -14,6 +14,10 @@ func GetXAuhorizationHeader(c *fiber.Ctx) string {
return c.GetReqHeaders()[HeaderXAuthorization]
}
func GetXApiKeyHeader(c *fiber.Ctx) string {
return c.GetReqHeaders()[HeaderXApiKey]
}
func MarshalJson(v any) string {
json, err := json.Marshal(v)

View File

@ -34,4 +34,7 @@ func ValidatorInit() {
structs.UserLoginRequest{},
structs.UserSignOutSessionRequest{},
structs.ScannerRequest{})
Validate.RegisterStructValidationMapRules(groupTaskRules,
structs.ApiGroupTaskRequest{})
}

View File

@ -1,20 +1,120 @@
package grouptask
import (
"encoding/json"
"janex/admin-dashboard-backend/modules/cache"
"janex/admin-dashboard-backend/modules/grouptasks"
"janex/admin-dashboard-backend/modules/structs"
"janex/admin-dashboard-backend/modules/utils"
"janex/admin-dashboard-backend/socketclients"
"github.com/gofiber/fiber/v2"
"github.com/rs/zerolog/log"
)
type b struct {
}
func StartGroupTask(c *fiber.Ctx) error {
var body b
var body structs.ApiGroupTaskRequest
if err := c.BodyParser(&body); err != nil {
log.Error().Msg("Failed to parse body, err: " + err.Error())
return c.Status(fiber.StatusBadRequest).JSON(err)
}
if errValidation := utils.ValidateStruct(body); errValidation != nil {
log.Error().Msgf("Failed to validate body, err: %v", errValidation)
return c.Status(fiber.StatusBadRequest).JSON(errValidation)
}
userId := c.Locals("userId").(string)
if !socketclients.HasPermission(userId, utils.PermissionUserProfileApiKeys) || !socketclients.HasXYPermission(userId, utils.PermissionGroupTasksOverviewXYNewTask, body.Category) {
return c.SendStatus(fiber.StatusUnauthorized)
}
categoryGroup := cache.GetCategoryGroupByCategory(body.Category)
if categoryGroup.Category == "" {
return c.Status(fiber.StatusBadRequest).JSONP(fiber.Map{"err": "Category not found"})
}
group := getGroupFromCategoryGroup(categoryGroup, body.GroupId)
if group.Category == "" {
return c.Status(fiber.StatusBadRequest).JSONP(fiber.Map{"err": "GroupId not found"})
}
var bodyGlobalInputs []map[string]string
err := json.Unmarshal(body.GlobalInputs, &bodyGlobalInputs)
if err != nil {
log.Error().Msgf("Failed to unmarshal body global inputs: %v", err)
return c.SendStatus(fiber.StatusBadRequest)
}
if len(group.Tasks) == 0 || !globalInputsComplete(bodyGlobalInputs, group.GlobalInputs) {
return c.SendStatus(fiber.StatusUnprocessableEntity)
}
grouptasks.StartGroupTask(userId, structs.GroupTasks{
Category: body.Category,
GroupId: body.GroupId,
GroupName: group.Name,
Description: body.Description,
NumberOfSteps: uint8(len(group.Tasks)),
GlobalInputs: convertJsonGlobalInputToStruct(bodyGlobalInputs, group.GlobalInputs),
})
return c.SendStatus(fiber.StatusOK)
}
func getGroupFromCategoryGroup(categoryGroup structs.CategoryGroup, groupId string) structs.Group {
for _, group := range categoryGroup.Groups {
if group.Id == groupId {
return group
}
}
return structs.Group{}
}
func globalInputsComplete(bodyGlobalInputs []map[string]string, groupGlobalInputs []structs.GlobalInputs) bool {
for _, gGlobalInput := range groupGlobalInputs {
if !isInList(gGlobalInput.ParameterName, bodyGlobalInputs) {
return false
}
}
return true
}
func isInList(gParameterName string, bodyInputs []map[string]string) bool {
for _, bInput := range bodyInputs {
if bInput[gParameterName] != "" {
return true
}
}
return false
}
type GlobalInputs struct {
ParameterName string `json:"parameterName"`
Value string `json:"value"`
}
func convertJsonGlobalInputToStruct(bodyGlobalInputs []map[string]string, groupGlobalInputs []structs.GlobalInputs) string {
var globalInputs []GlobalInputs
for _, gGlobalInput := range groupGlobalInputs {
for _, bInput := range bodyGlobalInputs {
if bInput[gGlobalInput.ParameterName] != "" {
globalInputs = append(globalInputs, GlobalInputs{
ParameterName: gGlobalInput.ParameterName,
Value: bInput[gGlobalInput.ParameterName],
})
}
}
}
return utils.MarshalJson(globalInputs)
}

View File

@ -3,14 +3,18 @@ package router
import (
"janex/admin-dashboard-backend/modules/config"
"janex/admin-dashboard-backend/modules/database"
"janex/admin-dashboard-backend/modules/logger"
"janex/admin-dashboard-backend/modules/structs"
"janex/admin-dashboard-backend/modules/utils"
"janex/admin-dashboard-backend/routers/router/api/v1/grouptask"
"janex/admin-dashboard-backend/routers/router/api/v1/jxscanner"
log "janex/admin-dashboard-backend/routers/router/api/v1/logger"
"janex/admin-dashboard-backend/routers/router/api/v1/user"
"janex/admin-dashboard-backend/socketclients"
"time"
"github.com/gofiber/fiber/v2"
"gorm.io/gorm"
)
func SetupRoutes(app *fiber.App) {
@ -31,11 +35,59 @@ func SetupRoutes(app *fiber.App) {
l.Get("/", userSessionValidation, log.GetSystemLog)
g := v1.Group("/grouptasks")
g.Post("/", grouptask.StartGroupTask)
g.Post("/start", userApikeyTokenValidation, grouptask.StartGroupTask)
app.Static("/", config.Cfg.FolderPaths.PublicStatic)
}
func userApikeyTokenValidation(c *fiber.Ctx) error {
xApikey := utils.GetXApiKeyHeader(c)
if len(xApikey) != utils.LenHeaderXApiKey {
return fiber.ErrUnauthorized
}
var apiKey structs.UserApiKey
database.DB.Select("id, user_id, token, usage_count").First(&apiKey, "token = ?", xApikey)
if apiKey.Token != xApikey {
return fiber.ErrUnauthorized
}
lastUsed := time.Now()
database.DB.Model(&structs.UserApiKey{}).Where("id = ?", apiKey.Id).Updates(map[string]interface{}{
"usage_count": gorm.Expr("usage_count + ?", 1),
"last_used": lastUsed,
})
c.Locals("userId", apiKey.UserId)
socketclients.SendMessageToUser(apiKey.UserId, "", structs.SendSocketMessage{
Cmd: utils.SentCmdNewApiKeyUsageCount,
Body: struct {
Id string
UsageCount uint
LastUsed time.Time
}{
Id: apiKey.Id,
UsageCount: (apiKey.UsageCount + 1),
LastUsed: lastUsed,
},
})
logger.AddSystemLog(structs.LogMessage{
Id: 25,
Type: utils.LogTypeInfo,
Messages: []structs.LogData{
{Type: "userId", Value: apiKey.UserId},
},
})
return c.Next()
}
func userSessionValidation(c *fiber.Ctx) error {
xAuthorization := utils.GetXAuhorizationHeader(c)
@ -47,7 +99,7 @@ func userSessionValidation(c *fiber.Ctx) error {
database.DB.First(&userSession, "id = ?", xAuthorization)
if len(userSession.Id) != utils.LenHeaderXAuthorization {
if userSession.Id != xAuthorization {
return fiber.ErrUnauthorized
}
@ -67,7 +119,7 @@ func scannerSessionValidation(c *fiber.Ctx) error {
database.DB.First(&scanner, "session = ?", xAuthorization)
if len(scanner.Session) != utils.LenHeaderXAuthorization {
if scanner.Session != xAuthorization {
return fiber.ErrUnauthorized
}

View File

@ -962,4 +962,29 @@ func CreateNewUserApiKey(userId string, apiName string) {
Cmd: utils.SentCmdNewUserApiKeyCreated,
Body: newApiKey,
})
logger.AddSystemLog(structs.LogMessage{
Id: 23,
Type: utils.LogTypeInfo,
Messages: []structs.LogData{
{Type: "userId", Value: userId},
},
})
}
func DeleteUserApiKey(userId string, apiKey string) {
database.DB.Where("id = ?", apiKey).Where("user_id = ?", userId).Delete(&structs.UserApiKey{})
SendMessageToUser(userId, "", structs.SendSocketMessage{
Cmd: utils.SentCmdDeletedUserApiKey,
Body: apiKey,
})
logger.AddSystemLog(structs.LogMessage{
Id: 24,
Type: utils.LogTypeInfo,
Messages: []structs.LogData{
{Type: "userId", Value: userId},
},
})
}

View File

@ -118,50 +118,63 @@ func RunHub() {
globalInputsJsonString := utils.MarshalJson(receivedMessage.Body["globalInputs"])
groupTaskId := uuid.New().String()
grouptasks.StartGroupTask(data.Conn.Locals("userId").(string),
structs.GroupTasks{
Category: category,
GroupId: groupId,
GroupName: receivedMessage.Body["groupName"].(string),
Description: receivedMessage.Body["description"].(string),
NumberOfSteps: uint8(receivedMessage.Body["numberOfSteps"].(float64)),
GlobalInputs: globalInputsJsonString,
RememberId: receivedMessage.Body["rememberId"].(string),
})
groupTasks := &structs.GroupTasks{
Id: groupTaskId,
CreatorUserId: data.Conn.Locals("userId").(string),
Category: category,
GroupId: groupId,
GroupName: receivedMessage.Body["groupName"].(string),
Description: receivedMessage.Body["description"].(string),
CurrentTasksStep: 1,
NumberOfSteps: uint8(receivedMessage.Body["numberOfSteps"].(float64)),
Status: utils.GroupTasksStatusRunning,
GlobalInputs: globalInputsJsonString,
StartedAt: time.Now(),
RememberId: receivedMessage.Body["rememberId"].(string),
}
//groupTaskId := uuid.New().String()
database.DB.Create(groupTasks)
/*
groupTasks := structs.GroupTasks{
Id: groupTaskId,
CreatorUserId: data.Conn.Locals("userId").(string),
Category: category,
GroupId: groupId,
GroupName: receivedMessage.Body["groupName"].(string),
Description: receivedMessage.Body["description"].(string),
CurrentTasksStep: 1,
NumberOfSteps: uint8(receivedMessage.Body["numberOfSteps"].(float64)),
Status: utils.GroupTasksStatusRunning,
GlobalInputs: globalInputsJsonString,
StartedAt: time.Now(),
RememberId: receivedMessage.Body["rememberId"].(string),
}
socketclients.BroadcastMessage(structs.SendSocketMessage{
Cmd: utils.SentCmdNewGroupTaskStarted,
Body: groupTasks,
})
database.DB.Create(&groupTasks)
go grouptasks.RunGroupTask(grouptasks.RunGroupTaskArgs{
CreatorUserId: data.Conn.Locals("userId").(string),
StartType: grouptasks.RunGroupTaskStartTypeNormal,
GroupTaskId: groupTaskId,
Category: category,
GroupId: groupId,
Step: 1,
TaskStepId: "",
GlobalInputs: globalInputsJsonString,
})
socketclients.BroadcastMessage(structs.SendSocketMessage{
Cmd: utils.SentCmdNewGroupTaskStarted,
Body: groupTasks,
})
go grouptasks.RunGroupTask(grouptasks.RunGroupTaskArgs{
CreatorUserId: data.Conn.Locals("userId").(string),
StartType: grouptasks.RunGroupTaskStartTypeNormal,
GroupTaskId: groupTaskId,
Category: category,
GroupId: groupId,
Step: 1,
TaskStepId: "",
GlobalInputs: globalInputsJsonString,
})
logger.AddGroupTasksLog(structs.LogMessage{
Id: 0,
Type: utils.LogTypeInfo,
Messages: []structs.LogData{
{Type: "userId", Value: data.Conn.Locals("userId").(string)},
{Type: "groupTaskId", Value: groupTaskId},
{Type: "groupTaskName", Value: groupTasks.GroupName},
},
}) */
logger.AddGroupTasksLog(structs.LogMessage{
Id: 0,
Type: utils.LogTypeInfo,
Messages: []structs.LogData{
{Type: "userId", Value: data.Conn.Locals("userId").(string)},
{Type: "groupTaskId", Value: groupTaskId},
{Type: "groupTaskName", Value: groupTasks.GroupName},
},
})
break
case utils.ReceivedCmdTaskFailedTryAgainRunTaskStep:
groupTaskArgs := grouptasks.RunGroupTaskArgs{
@ -371,13 +384,18 @@ func RunHub() {
grouptasks.LookingForCategoryGroupChanges(data.Conn.Locals("userId").(string))
break
case utils.ReceivedCmdHandleUserActionTaskStep:
if !socketclients.HasXYPermission(data.Conn.Locals("userId").(string), utils.PermissionGroupTasksOverviewXYReloadGroupConfig, receivedMessage.Body["category"].(string)) {
socketclients.SendErrorMessageNoPermissions(data.Conn.Locals("sessionId").(string))
break
}
grouptasks.HandleUserActionTaskStep(data.Conn.Locals("userId").(string), receivedMessage.Body)
break
case utils.ReceivedCmdCreateNewUserApiKey:
socketclients.CreateNewUserApiKey(data.Conn.Locals("userId").(string), receivedMessage.Body["Name"].(string))
break
case utils.ReceivedCmdDeleteUserApiKey:
socketclients.DeleteUserApiKey(data.Conn.Locals("userId").(string), receivedMessage.Body["Id"].(string))
break
default:

View File

@ -297,5 +297,44 @@
"message": "%userId% hat eine seiner Sitzungen ausgeloggt"
}
]
},
{
"id": 23,
"languages": [
{
"lang": "en",
"message": "%userId% has created an API key"
},
{
"lang": "de",
"message": "%userId% hat einen API-Schlüssel erstellt"
}
]
},
{
"id": 24,
"languages": [
{
"lang": "en",
"message": "%userId% has deleted one of its api keys"
},
{
"lang": "de",
"message": "%userId% hat einen seiner Api-Schlüssel gelöscht"
}
]
},
{
"id": 25,
"languages": [
{
"lang": "en",
"message": "%userId% has used one of its api keys"
},
{
"lang": "de",
"message": "%userId% hat einen seiner Api-Schlüssel verwendet"
}
]
}
]