prevent duplicate onStart calls for the same container

This commit is contained in:
its-a-feature
2026-04-23 14:49:30 -05:00
parent 6159d8336a
commit 2024537cd5
4 changed files with 31 additions and 20 deletions
+2 -10
View File
@@ -3,10 +3,12 @@ import { createGlobalStyle} from "styled-components"
export const GlobalStyles = createGlobalStyle`
body {
margin: 0
}
html, body, #root {
height: 100%;
width: 100%;
color-scheme: light dark;
}
@media screen and (max-width: 1100px) {
.hideOnSmallWidth {
@@ -186,16 +188,6 @@ tspan {
.selectedTask {
background-color: ${(props) => props.theme.selectedCallbackColor + "DD"} !important;
}
*::-webkit-scrollbar {
width: 0.4em;
height: 0.4em;
}
*::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.00);
}
*::-webkit-scrollbar-thumb {
background-color: ${(props) => props.theme.palette.secondary.dark};
}
.MythicResizableGrid-headerCellRow {
display: flex;
flex-direction: row;
@@ -6,6 +6,7 @@ import (
"fmt"
"io"
"net/http"
"sync"
"time"
"github.com/its-a-feature/Mythic/authentication/mythicjwt"
@@ -27,6 +28,8 @@ var checkContainerStatusAddConsumingContainerChannel = make(chan databaseStructs
var consumingContainersToCheck = map[string]databaseStructs.ConsumingContainer{}
var checkContainerStatusAddCustomBrowserChannel = make(chan databaseStructs.CustomBrowser)
var customBrowsersToCheck = map[string]databaseStructs.CustomBrowser{}
var containerOnStartLock sync.Mutex
var containerOnStartInFlight = map[string]bool{}
func checkContainerStatusAddPT() {
for {
@@ -123,6 +126,14 @@ type rabbitmqAPIQuery struct {
}
func CreateGraphQLSpectatorAPITokenAndSendOnStartMessage(containerName string) {
containerOnStartLock.Lock()
if containerOnStartInFlight[containerName] {
containerOnStartLock.Unlock()
logging.LogInfo("Skipping duplicate container on start run already in progress", "container", containerName)
return
}
containerOnStartInFlight[containerName] = true
containerOnStartLock.Unlock()
operations := []databaseStructs.Operation{}
err := database.DB.Select(&operations, `SELECT id FROM operation WHERE deleted=false and complete=false`)
if err != nil {
@@ -201,7 +212,7 @@ func CreateGraphQLSpectatorAPITokenAndSendOnStartMessage(containerName string) {
continue
}
onStartMessage.APIToken = plainAPITokenValue
go updateAPITokenAfter5Minutes(apiToken.ID)
go updateAPITokenAfter5Minutes(apiToken.ID, containerName)
err = RabbitMQConnection.SendContainerOnStart(onStartMessage)
if err != nil {
logging.LogError(err, "Failed to send container on start")
@@ -210,12 +221,15 @@ func CreateGraphQLSpectatorAPITokenAndSendOnStartMessage(containerName string) {
time.Sleep(5 * time.Second)
}
}
func updateAPITokenAfter5Minutes(apitoken_id int) {
func updateAPITokenAfter5Minutes(apitokenID int, containerName string) {
<-time.After(5 * time.Minute)
_, err := database.DB.Exec(`UPDATE apitokens SET active=false, deleted=true WHERE id=$1`, apitoken_id)
_, err := database.DB.Exec(`UPDATE apitokens SET active=false, deleted=true WHERE id=$1`, apitokenID)
if err != nil {
logging.LogError(err, "failed to mark apitoken as deleted")
}
containerOnStartLock.Lock()
delete(containerOnStartInFlight, containerName)
containerOnStartLock.Unlock()
}
func checkContainerStatus() {
// get all queues from rabbitmq
@@ -3,6 +3,7 @@ package rabbitmq
import (
"encoding/json"
"fmt"
"github.com/its-a-feature/Mythic/authentication/mythicjwt"
"github.com/its-a-feature/Mythic/database"
databaseStructs "github.com/its-a-feature/Mythic/database/structs"
@@ -138,7 +139,7 @@ func MythicRPCAPITokenCreate(input MythicRPCAPITokenCreateMessage) MythicRPCAPIT
response.APIToken = accessToken
if apiToken.TokenType == mythicjwt.AUTH_METHOD_GRAPHQL_SPECTATOR {
// deactivate the token after 5 min (should be a short-lived use)
go updateAPITokenAfter5Minutes(apiToken.ID)
go updateAPITokenAfter5Minutes(apiToken.ID, response.APIToken)
}
return response
}
+10 -6
View File
@@ -1298,7 +1298,7 @@ type operationMessage struct {
warning bool
}
var operationMessageChannel = make(chan operationMessage, 100)
var operationMessageChannel = make(chan operationMessage, 1000)
func listenForOperationsMessages() {
timer := time.NewTimer(time.Second * 10)
@@ -1341,7 +1341,7 @@ func listenForOperationsMessages() {
if existingMessage.ID == 0 {
err = database.DB.Get(&existingMessage, `
SELECT id, count, "message", source, "level" FROM operationeventlog WHERE
warning=true and source=$1 and operation_id=$2 and resolved=false and deleted=false and "level"=$3
warning=true and resolved=false and deleted=false and source=$1 and operation_id=$2 and "level"=$3
`, sourceString, operation.ID, msg.messageLevel)
if !errors.Is(err, sql.ErrNoRows) && err != nil {
logging.LogError(err, "Failed to query existing event log message")
@@ -1453,8 +1453,8 @@ func listenForOperationsMessages() {
if msg.operationID == 0 {
updateObject.OperationID = operation.ID
}
if _, err := database.DB.NamedExec(`UPDATE operationeventlog SET
resolved=true WHERE warning=true AND resolved=false AND deleted=false AND message=:message AND operation_id=:operation_id`, updateObject); err != nil {
if _, err := database.DB.NamedExec(`UPDATE operationeventlog SET resolved=true
WHERE warning=true AND resolved=false AND deleted=false AND message=:message AND operation_id=:operation_id`, updateObject); err != nil {
logging.LogError(err, "Failed to resolve message")
}
removeUnresolvedError(operation.ID)
@@ -1470,19 +1470,23 @@ func listenForOperationsMessages() {
}
}
func SendAllOperationsMessage(message string, operationID int, source string, messageLevel database.MESSAGE_TYPE, warning bool) {
operationMessageChannel <- operationMessage{
select {
case operationMessageChannel <- operationMessage{
action: "send",
message: message,
source: source,
operationID: operationID,
messageLevel: messageLevel,
warning: warning,
}:
}
}
func ResolveAllOperationsMessage(message string, operationID int) {
operationMessageChannel <- operationMessage{
select {
case operationMessageChannel <- operationMessage{
action: "remove",
operationID: operationID,
message: message,
}:
}
}