From c610427d0664e477edad765646ce57aa553aae47 Mon Sep 17 00:00:00 2001 From: ALEXANDER MA COTE Date: Fri, 15 Dec 2023 14:54:48 -0500 Subject: [PATCH 01/12] add unique name selection and opportunistically generate lower complexity names --- tavern/internal/c2/server.go | 41 +++++++++++++++++++++------ tavern/internal/ent/schema/beacon.go | 2 +- tavern/internal/namegen/namegen.go | 42 +++++++++++++++++++--------- tavern/test_data.go | 4 +-- 4 files changed, 65 insertions(+), 24 deletions(-) diff --git a/tavern/internal/c2/server.go b/tavern/internal/c2/server.go index 925282979..c76afe37e 100644 --- a/tavern/internal/c2/server.go +++ b/tavern/internal/c2/server.go @@ -11,6 +11,7 @@ import ( "github.com/kcarretto/realm/tavern/internal/ent/beacon" "github.com/kcarretto/realm/tavern/internal/ent/host" "github.com/kcarretto/realm/tavern/internal/ent/task" + "github.com/kcarretto/realm/tavern/internal/namegen" ) type Server struct { @@ -64,12 +65,36 @@ func (srv *Server) ClaimTasks(ctx context.Context, req *c2pb.ClaimTasksRequest) if err != nil { return nil, fmt.Errorf("failed to upsert host entity: %w", err) } + // 2. check if beacon is new + resolvedbeacons, err := srv.graph.Beacon.Query().Where(beacon.IdentifierEQ(req.Beacon.Identifier)).Exist(ctx) + if err != nil { + return nil, fmt.Errorf("failed to query beacon entity: %w", err) + } + var beaconnameaddr *string = nil + //3. if the beacon is new lets pick a name for it + if !resolvedbeacons { + for i := 0; i < 3; i++ { + beaconname := namegen.GetRandomName(i) + namecollison, err := srv.graph.Beacon.Query().Where(beacon.Name(beaconname)).Exist(ctx) + if err != nil { + return nil, fmt.Errorf("failed to query beacon entity: %w", err) + } + if namecollison { + //detected name collision on new beacon registration, increasing the name complexity and trying again + continue + } + beaconnameaddr = &beaconname + //picked a good name, loop iterations not required + break + } - // 2. Upsert the beacon + } + // 4. Upsert the beacon beaconID, err := srv.graph.Beacon.Create(). SetPrincipal(req.Beacon.Principal). SetIdentifier(req.Beacon.Identifier). SetAgentIdentifier(req.Beacon.Agent.Identifier). + SetNillableName(beaconnameaddr). SetHostID(hostID). SetLastSeenAt(now). SetInterval(req.Beacon.Interval). @@ -80,7 +105,7 @@ func (srv *Server) ClaimTasks(ctx context.Context, req *c2pb.ClaimTasksRequest) return nil, fmt.Errorf("failed to upsert beacon entity: %w", err) } - // 3. Load Tasks + // 5. Load Tasks tasks, err := srv.graph.Task.Query(). Where(task.And( task.HasBeaconWith(beacon.ID(beaconID)), @@ -91,14 +116,14 @@ func (srv *Server) ClaimTasks(ctx context.Context, req *c2pb.ClaimTasksRequest) return nil, fmt.Errorf("failed to query tasks: %w", err) } - // 4. Prepare Transaction for Claiming Tasks + // 6. Prepare Transaction for Claiming Tasks tx, err := srv.graph.Tx(ctx) if err != nil { return nil, fmt.Errorf("failed to initialize transaction: %w", err) } client := tx.Client() - // 5. Rollback transaction if we panic + // 7. Rollback transaction if we panic defer func() { if v := recover(); v != nil { tx.Rollback() @@ -106,7 +131,7 @@ func (srv *Server) ClaimTasks(ctx context.Context, req *c2pb.ClaimTasksRequest) } }() - // 6. Update all ClaimedAt timestamps to claim tasks + // 8. Update all ClaimedAt timestamps to claim tasks // ** Note: If one fails to update, we roll back the transaction and return the error taskIDs := make([]int, 0, len(tasks)) for _, t := range tasks { @@ -119,12 +144,12 @@ func (srv *Server) ClaimTasks(ctx context.Context, req *c2pb.ClaimTasksRequest) taskIDs = append(taskIDs, t.ID) } - // 7. Commit the transaction + // 9. Commit the transaction if err := tx.Commit(); err != nil { return nil, rollback(tx, fmt.Errorf("failed to commit transaction: %w", err)) } - // 8. Load the tasks with our non transactional client (cannot use transaction after commit) + // 10. Load the tasks with our non transactional client (cannot use transaction after commit) resp := c2pb.ClaimTasksResponse{} resp.Tasks = make([]*c2pb.Task, 0, len(taskIDs)) for _, taskID := range taskIDs { @@ -153,7 +178,7 @@ func (srv *Server) ClaimTasks(ctx context.Context, req *c2pb.ClaimTasksRequest) }) } - // 9. Return claimed tasks + // 11. Return claimed tasks return &resp, nil } diff --git a/tavern/internal/ent/schema/beacon.go b/tavern/internal/ent/schema/beacon.go index 9ebc3c7fa..05c868d51 100644 --- a/tavern/internal/ent/schema/beacon.go +++ b/tavern/internal/ent/schema/beacon.go @@ -27,7 +27,7 @@ func (Beacon) Fields() []ent.Field { NotEmpty(). Unique(). Immutable(). - DefaultFunc(namegen.GetRandomName). + DefaultFunc(namegen.GetComplexRandomName). Comment("A human readable identifier for the beacon."), field.String("principal"). Optional(). diff --git a/tavern/internal/namegen/namegen.go b/tavern/internal/namegen/namegen.go index 2d1411aa2..5a41b430c 100644 --- a/tavern/internal/namegen/namegen.go +++ b/tavern/internal/namegen/namegen.go @@ -886,21 +886,34 @@ var ( } ) -// GetRandomName generates a random name from the list of adjectives and surnames in this package -// formatted as "adjective-surname". For example 'focused-turing'. -func GetRandomName() string { +// GetRandomName generates a random name from the list of adjectives. +func GetRandomName(complexityfactor int) string { + var adj1, adj2, noun string + var num int64 + if time.Now().Month() == time.October && time.Now().Day() == 31 { - adj1IndexHalloween := newRandInt(int64(len(adjectives_halloween))) - adj2IndexHalloween := newRandInt(int64(len(adjectives_halloween))) - nounIndex := newRandInt(int64(len(noun_halloween))) - randNum := newRandInt(10000000) - return fmt.Sprintf("%s-%s-%s-%d", adjectives_halloween[adj1IndexHalloween], adjectives_halloween[adj2IndexHalloween], noun_halloween[nounIndex], randNum) + adj1 = adjectives[newRandInt(int64(len(adjectives_halloween)))] + adj2 = adjectives[newRandInt(int64(len(adjectives_halloween)))] + noun = nouns[newRandInt(int64(len(noun_halloween)))] + num = newRandInt(10000000) + } else { + adj1 = adjectives[newRandInt(int64(len(adjectives)))] + adj2 = adjectives[newRandInt(int64(len(adjectives)))] + noun = nouns[newRandInt(int64(len(nouns)))] + num = newRandInt(10000000) + } + + switch complexityfactor { + case 0: + return fmt.Sprintf("%s-%s", adj1, noun) + case 1: + return fmt.Sprintf("%s-%s-%s", adj1, adj2, noun) + case 2: + return fmt.Sprintf("%s-%s-%s-%d", adj1, adj2, noun, num) + default: + return "hacker1337" } - adj1Index := newRandInt(int64(len(adjectives))) - adj2Index := newRandInt(int64(len(adjectives))) - nounIndex := newRandInt(int64(len(nouns))) - randNum := newRandInt(10000000) - return fmt.Sprintf("%s-%s-%s-%d", adjectives[adj1Index], adjectives[adj2Index], nouns[nounIndex], randNum) + } // cryptoRandSecure is not always secure, if it errors we return 1337 % max @@ -912,3 +925,6 @@ func newRandInt(max int64) int64 { } return nBig.Int64() } +func GetComplexRandomName() string { + return GetRandomName(2) +} diff --git a/tavern/test_data.go b/tavern/test_data.go index 72318fdf5..b957475d5 100644 --- a/tavern/test_data.go +++ b/tavern/test_data.go @@ -348,14 +348,14 @@ None func createQuest(ctx context.Context, client *ent.Client, beacons ...*ent.Beacon) { // Mid-Execution testTome := client.Tome.Create(). - SetName(namegen.GetRandomName()). + SetName(namegen.GetRandomName(2)). SetDescription("Print a message for fun!"). SetEldritch(`print(input_params['msg'])`). SetParamDefs(`[{"name":"msg","label":"Message","type":"string","placeholder":"something to print"}]`). SaveX(ctx) q := client.Quest.Create(). - SetName(namegen.GetRandomName()). + SetName(namegen.GetRandomName(2)). SetParameters(`{"msg":"Hello World!"}`). SetTome(testTome). SaveX(ctx) From 172af1b3254ba4f17c17148f508492514873683e Mon Sep 17 00:00:00 2001 From: ALEXANDER MA COTE Date: Fri, 15 Dec 2023 15:31:09 -0500 Subject: [PATCH 02/12] fix tests --- tavern/internal/namegen/namegen_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tavern/internal/namegen/namegen_test.go b/tavern/internal/namegen/namegen_test.go index b8f3756bd..a5f90169f 100644 --- a/tavern/internal/namegen/namegen_test.go +++ b/tavern/internal/namegen/namegen_test.go @@ -10,7 +10,7 @@ import ( func TestGetRandomName(t *testing.T) { t.Run("BasicName", func(t *testing.T) { - name := namegen.GetRandomName() + name := namegen.GetRandomName(1) assert.NotEmpty(t, name) }) @@ -19,7 +19,7 @@ func TestGetRandomName(t *testing.T) { names := make(map[string]bool, 1000000) count := 0 for i := 0; i < 1000000; i++ { - name := namegen.GetRandomName() + name := namegen.GetRandomName(2) exists, ok := names[name] require.False(t, ok, "Name %s already exists - after %d attempts", name, count) assert.False(t, exists) From 1f8ceaa180189e2951233206a0d431132769b43d Mon Sep 17 00:00:00 2001 From: ALEXANDER MA COTE Date: Mon, 18 Dec 2023 15:35:56 -0500 Subject: [PATCH 03/12] batch search for collisions. and add a complexity identifier --- tavern/internal/c2/server.go | 26 +++++++++++------------ tavern/internal/namegen/namegen.go | 34 +++++++++++++++++++++++------- 2 files changed, 39 insertions(+), 21 deletions(-) diff --git a/tavern/internal/c2/server.go b/tavern/internal/c2/server.go index c76afe37e..64a526034 100644 --- a/tavern/internal/c2/server.go +++ b/tavern/internal/c2/server.go @@ -73,22 +73,22 @@ func (srv *Server) ClaimTasks(ctx context.Context, req *c2pb.ClaimTasksRequest) var beaconnameaddr *string = nil //3. if the beacon is new lets pick a name for it if !resolvedbeacons { - for i := 0; i < 3; i++ { - beaconname := namegen.GetRandomName(i) - namecollison, err := srv.graph.Beacon.Query().Where(beacon.Name(beaconname)).Exist(ctx) - if err != nil { - return nil, fmt.Errorf("failed to query beacon entity: %w", err) - } - if namecollison { - //detected name collision on new beacon registration, increasing the name complexity and trying again - continue + candiatenames := []string{} + candiatenames = append(candiatenames, namegen.GetRandomName(namegen.Complexity(namegen.Simple))) + candiatenames = append(candiatenames, namegen.GetRandomName(namegen.Complexity(namegen.Moderate))) + candiatenames = append(candiatenames, namegen.GetRandomName(namegen.Complexity(namegen.Complex))) + collisions, err := srv.graph.Beacon.Query().Where(beacon.NameIn(candiatenames...)).All(ctx) + if err != nil { + return nil, fmt.Errorf("failed to query beacon entity: %w", err) + } + for _, canidate := range candiatenames { + if !namegen.Beaconnameinstring(collisions, canidate) { + beaconnameaddr = &canidate + break } - beaconnameaddr = &beaconname - //picked a good name, loop iterations not required - break } - } + // 4. Upsert the beacon beaconID, err := srv.graph.Beacon.Create(). SetPrincipal(req.Beacon.Principal). diff --git a/tavern/internal/namegen/namegen.go b/tavern/internal/namegen/namegen.go index 5a41b430c..5fc245652 100644 --- a/tavern/internal/namegen/namegen.go +++ b/tavern/internal/namegen/namegen.go @@ -6,6 +6,8 @@ import ( "log" "math/big" "time" + + "github.com/kcarretto/realm/tavern/internal/ent" ) var ( @@ -886,8 +888,16 @@ var ( } ) -// GetRandomName generates a random name from the list of adjectives. -func GetRandomName(complexityfactor int) string { +type Complexity int + +const ( + Simple Complexity = iota // 0 + Moderate // 1 + Complex // 2 +) + +// GetRandomName generates a random name based on the complexity. +func GetRandomName(complexity Complexity) string { var adj1, adj2, noun string var num int64 @@ -903,17 +913,16 @@ func GetRandomName(complexityfactor int) string { num = newRandInt(10000000) } - switch complexityfactor { - case 0: + switch complexity { + case Simple: return fmt.Sprintf("%s-%s", adj1, noun) - case 1: + case Moderate: return fmt.Sprintf("%s-%s-%s", adj1, adj2, noun) - case 2: + case Complex: return fmt.Sprintf("%s-%s-%s-%d", adj1, adj2, noun, num) default: return "hacker1337" } - } // cryptoRandSecure is not always secure, if it errors we return 1337 % max @@ -926,5 +935,14 @@ func newRandInt(max int64) int64 { return nBig.Int64() } func GetComplexRandomName() string { - return GetRandomName(2) + return GetRandomName(Complex) +} + +func Beaconnameinstring(beacons []*ent.Beacon, str string) bool { + for _, v := range beacons { + if v.Name == str { + return true + } + } + return false } From 2d791f4e73ffbe45ea2e55e4c25208b68f1a6c42 Mon Sep 17 00:00:00 2001 From: ALEXANDER MA COTE Date: Mon, 18 Dec 2023 19:20:19 -0500 Subject: [PATCH 04/12] add test for Beaconnameinstring --- tavern/internal/namegen/namegen_test.go | 39 +++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/tavern/internal/namegen/namegen_test.go b/tavern/internal/namegen/namegen_test.go index a5f90169f..82a5b1de8 100644 --- a/tavern/internal/namegen/namegen_test.go +++ b/tavern/internal/namegen/namegen_test.go @@ -3,6 +3,7 @@ package namegen_test import ( "testing" + "github.com/kcarretto/realm/tavern/internal/ent" "github.com/kcarretto/realm/tavern/internal/namegen" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -29,3 +30,41 @@ func TestGetRandomName(t *testing.T) { }) } + +// TestBeaconnameinstring tests the Beaconnameinstring function +func TestBeaconnameinstring(t *testing.T) { + testCases := []struct { + name string + beacons []*ent.Beacon + str string + expected bool + }{ + { + name: "String matches a beacon name", + beacons: []*ent.Beacon{ + {Name: "Alpha"}, + {Name: "Beta"}, + }, + str: "Beta", + expected: true, + }, + { + name: "String does not match any beacon name", + beacons: []*ent.Beacon{ + {Name: "Alpha"}, + {Name: "Beta"}, + }, + str: "Gamma", + expected: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + result := namegen.Beaconnameinstring(tc.beacons, tc.str) + if result != tc.expected { + t.Errorf("Beaconnameinstring(%v, %s) = %v; expected %v", tc.beacons, tc.str, result, tc.expected) + } + }) + } +} From 9a75cde27f876a34b09accf0f79df589c9b3548b Mon Sep 17 00:00:00 2001 From: ALEXANDER MA COTE Date: Mon, 18 Dec 2023 19:23:00 -0500 Subject: [PATCH 05/12] add tests to other random names --- tavern/internal/namegen/namegen_test.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tavern/internal/namegen/namegen_test.go b/tavern/internal/namegen/namegen_test.go index 82a5b1de8..ca3ea2fa5 100644 --- a/tavern/internal/namegen/namegen_test.go +++ b/tavern/internal/namegen/namegen_test.go @@ -11,8 +11,12 @@ import ( func TestGetRandomName(t *testing.T) { t.Run("BasicName", func(t *testing.T) { - name := namegen.GetRandomName(1) - assert.NotEmpty(t, name) + name1 := namegen.GetRandomName(0) + assert.NotEmpty(t, name1) + name2 := namegen.GetRandomName(1) + assert.NotEmpty(t, name2) + name3 := namegen.GetComplexRandomName() + assert.NotEmpty(t, name3) }) t.Run("NoDuplicates", func(t *testing.T) { From c0db2dd6fa59370d80de7bd3e13105e76cb27d1a Mon Sep 17 00:00:00 2001 From: ALEXANDER MA COTE Date: Sun, 31 Dec 2023 10:09:50 -0500 Subject: [PATCH 06/12] add requested changes. --- tavern/internal/c2/server.go | 20 +++++++++++--------- tavern/internal/namegen/namegen.go | 13 +++++++------ tavern/internal/namegen/namegen_test.go | 8 ++++---- 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/tavern/internal/c2/server.go b/tavern/internal/c2/server.go index 64a526034..221290ba7 100644 --- a/tavern/internal/c2/server.go +++ b/tavern/internal/c2/server.go @@ -66,23 +66,25 @@ func (srv *Server) ClaimTasks(ctx context.Context, req *c2pb.ClaimTasksRequest) return nil, fmt.Errorf("failed to upsert host entity: %w", err) } // 2. check if beacon is new - resolvedbeacons, err := srv.graph.Beacon.Query().Where(beacon.IdentifierEQ(req.Beacon.Identifier)).Exist(ctx) + beaconExists, err := srv.graph.Beacon.Query().Where(beacon.IdentifierEQ(req.Beacon.Identifier)).Exist(ctx) if err != nil { return nil, fmt.Errorf("failed to query beacon entity: %w", err) } var beaconnameaddr *string = nil //3. if the beacon is new lets pick a name for it - if !resolvedbeacons { - candiatenames := []string{} - candiatenames = append(candiatenames, namegen.GetRandomName(namegen.Complexity(namegen.Simple))) - candiatenames = append(candiatenames, namegen.GetRandomName(namegen.Complexity(namegen.Moderate))) - candiatenames = append(candiatenames, namegen.GetRandomName(namegen.Complexity(namegen.Complex))) - collisions, err := srv.graph.Beacon.Query().Where(beacon.NameIn(candiatenames...)).All(ctx) + if !beaconExists { + candidateNames := []string{ + namegen.GetRandomName(namegen.Complexity(namegen.Simple)), + namegen.GetRandomName(namegen.Complexity(namegen.Moderate)), + namegen.GetRandomName(namegen.Complexity((namegen.Complex))), + } + + collisions, err := srv.graph.Beacon.Query().Where(beacon.NameIn(candidateNames...)).All(ctx) if err != nil { return nil, fmt.Errorf("failed to query beacon entity: %w", err) } - for _, canidate := range candiatenames { - if !namegen.Beaconnameinstring(collisions, canidate) { + for _, canidate := range candidateNames { + if !namegen.IsCollision(collisions, canidate) { beaconnameaddr = &canidate break } diff --git a/tavern/internal/namegen/namegen.go b/tavern/internal/namegen/namegen.go index 5fc245652..e70288d87 100644 --- a/tavern/internal/namegen/namegen.go +++ b/tavern/internal/namegen/namegen.go @@ -901,10 +901,10 @@ func GetRandomName(complexity Complexity) string { var adj1, adj2, noun string var num int64 - if time.Now().Month() == time.October && time.Now().Day() == 31 { - adj1 = adjectives[newRandInt(int64(len(adjectives_halloween)))] - adj2 = adjectives[newRandInt(int64(len(adjectives_halloween)))] - noun = nouns[newRandInt(int64(len(noun_halloween)))] + if time.Now().Month() == time.October { + adj1 = adjectives_halloween[newRandInt(int64(len(adjectives_halloween)))] + adj2 = adjectives_halloween[newRandInt(int64(len(adjectives_halloween)))] + noun = noun_halloween[newRandInt(int64(len(noun_halloween)))] num = newRandInt(10000000) } else { adj1 = adjectives[newRandInt(int64(len(adjectives)))] @@ -921,7 +921,8 @@ func GetRandomName(complexity Complexity) string { case Complex: return fmt.Sprintf("%s-%s-%s-%d", adj1, adj2, noun, num) default: - return "hacker1337" + //same as complex case + return fmt.Sprintf("%s-%s-%s-%d", adj1, adj2, noun, num) } } @@ -938,7 +939,7 @@ func GetComplexRandomName() string { return GetRandomName(Complex) } -func Beaconnameinstring(beacons []*ent.Beacon, str string) bool { +func IsCollision(beacons []*ent.Beacon, str string) bool { for _, v := range beacons { if v.Name == str { return true diff --git a/tavern/internal/namegen/namegen_test.go b/tavern/internal/namegen/namegen_test.go index ca3ea2fa5..385f731c8 100644 --- a/tavern/internal/namegen/namegen_test.go +++ b/tavern/internal/namegen/namegen_test.go @@ -11,9 +11,9 @@ import ( func TestGetRandomName(t *testing.T) { t.Run("BasicName", func(t *testing.T) { - name1 := namegen.GetRandomName(0) + name1 := namegen.GetRandomName(namegen.Simple) assert.NotEmpty(t, name1) - name2 := namegen.GetRandomName(1) + name2 := namegen.GetRandomName(namegen.Moderate) assert.NotEmpty(t, name2) name3 := namegen.GetComplexRandomName() assert.NotEmpty(t, name3) @@ -24,7 +24,7 @@ func TestGetRandomName(t *testing.T) { names := make(map[string]bool, 1000000) count := 0 for i := 0; i < 1000000; i++ { - name := namegen.GetRandomName(2) + name := namegen.GetRandomName(namegen.Moderate) exists, ok := names[name] require.False(t, ok, "Name %s already exists - after %d attempts", name, count) assert.False(t, exists) @@ -65,7 +65,7 @@ func TestBeaconnameinstring(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - result := namegen.Beaconnameinstring(tc.beacons, tc.str) + result := namegen.IsCollision(tc.beacons, tc.str) if result != tc.expected { t.Errorf("Beaconnameinstring(%v, %s) = %v; expected %v", tc.beacons, tc.str, result, tc.expected) } From af3e5b7327149ae21e9ce538f58f1d9735cb6e8d Mon Sep 17 00:00:00 2001 From: ALEXANDER MA COTE Date: Sun, 31 Dec 2023 12:34:37 -0500 Subject: [PATCH 07/12] make duplicate test use complex names --- tavern/internal/namegen/namegen_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tavern/internal/namegen/namegen_test.go b/tavern/internal/namegen/namegen_test.go index 385f731c8..afca46d7c 100644 --- a/tavern/internal/namegen/namegen_test.go +++ b/tavern/internal/namegen/namegen_test.go @@ -24,7 +24,7 @@ func TestGetRandomName(t *testing.T) { names := make(map[string]bool, 1000000) count := 0 for i := 0; i < 1000000; i++ { - name := namegen.GetRandomName(namegen.Moderate) + name := namegen.GetRandomName(namegen.Complex) exists, ok := names[name] require.False(t, ok, "Name %s already exists - after %d attempts", name, count) assert.False(t, exists) From 46dcd0da941330e4b48f467ce23409d10d4eb734 Mon Sep 17 00:00:00 2001 From: ALEXANDER MA COTE Date: Wed, 10 Jan 2024 18:02:49 -0500 Subject: [PATCH 08/12] impliment one retry per request to generate a name --- tavern/internal/c2/server.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tavern/internal/c2/server.go b/tavern/internal/c2/server.go index 221290ba7..08cf80ce9 100644 --- a/tavern/internal/c2/server.go +++ b/tavern/internal/c2/server.go @@ -83,6 +83,18 @@ func (srv *Server) ClaimTasks(ctx context.Context, req *c2pb.ClaimTasksRequest) if err != nil { return nil, fmt.Errorf("failed to query beacon entity: %w", err) } + if len(collisions) == 3 { + candidateNames := []string{ + namegen.GetRandomName(namegen.Complexity(namegen.Simple)), + namegen.GetRandomName(namegen.Complexity(namegen.Moderate)), + namegen.GetRandomName(namegen.Complexity((namegen.Complex))), + } + + collisions, err = srv.graph.Beacon.Query().Where(beacon.NameIn(candidateNames...)).All(ctx) + if err != nil { + return nil, fmt.Errorf("failed to query beacon entity: %w", err) + } + } for _, canidate := range candidateNames { if !namegen.IsCollision(collisions, canidate) { beaconnameaddr = &canidate From 6c79c656c9d036db34c26ca4836bd89a02c34636 Mon Sep 17 00:00:00 2001 From: ALEXANDER MA COTE Date: Wed, 10 Jan 2024 18:06:12 -0500 Subject: [PATCH 09/12] rename the complexity levels --- tavern/internal/c2/server.go | 12 ++++++------ tavern/internal/namegen/namegen.go | 14 +++++++------- tavern/internal/namegen/namegen_test.go | 6 +++--- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/tavern/internal/c2/server.go b/tavern/internal/c2/server.go index 08cf80ce9..652bbdd3a 100644 --- a/tavern/internal/c2/server.go +++ b/tavern/internal/c2/server.go @@ -74,9 +74,9 @@ func (srv *Server) ClaimTasks(ctx context.Context, req *c2pb.ClaimTasksRequest) //3. if the beacon is new lets pick a name for it if !beaconExists { candidateNames := []string{ - namegen.GetRandomName(namegen.Complexity(namegen.Simple)), - namegen.GetRandomName(namegen.Complexity(namegen.Moderate)), - namegen.GetRandomName(namegen.Complexity((namegen.Complex))), + namegen.GetRandomName(namegen.Complexity(namegen.ComplexitySimple)), + namegen.GetRandomName(namegen.Complexity(namegen.ComplexityModerate)), + namegen.GetRandomName(namegen.Complexity((namegen.ComplexityComplex))), } collisions, err := srv.graph.Beacon.Query().Where(beacon.NameIn(candidateNames...)).All(ctx) @@ -85,9 +85,9 @@ func (srv *Server) ClaimTasks(ctx context.Context, req *c2pb.ClaimTasksRequest) } if len(collisions) == 3 { candidateNames := []string{ - namegen.GetRandomName(namegen.Complexity(namegen.Simple)), - namegen.GetRandomName(namegen.Complexity(namegen.Moderate)), - namegen.GetRandomName(namegen.Complexity((namegen.Complex))), + namegen.GetRandomName(namegen.Complexity(namegen.ComplexitySimple)), + namegen.GetRandomName(namegen.Complexity(namegen.ComplexityModerate)), + namegen.GetRandomName(namegen.Complexity((namegen.ComplexityComplex))), } collisions, err = srv.graph.Beacon.Query().Where(beacon.NameIn(candidateNames...)).All(ctx) diff --git a/tavern/internal/namegen/namegen.go b/tavern/internal/namegen/namegen.go index e70288d87..620ed2376 100644 --- a/tavern/internal/namegen/namegen.go +++ b/tavern/internal/namegen/namegen.go @@ -891,9 +891,9 @@ var ( type Complexity int const ( - Simple Complexity = iota // 0 - Moderate // 1 - Complex // 2 + ComplexitySimple Complexity = iota // 0 + ComplexityModerate // 1 + ComplexityComplex // 2 ) // GetRandomName generates a random name based on the complexity. @@ -914,11 +914,11 @@ func GetRandomName(complexity Complexity) string { } switch complexity { - case Simple: + case ComplexitySimple: return fmt.Sprintf("%s-%s", adj1, noun) - case Moderate: + case ComplexityModerate: return fmt.Sprintf("%s-%s-%s", adj1, adj2, noun) - case Complex: + case ComplexityComplex: return fmt.Sprintf("%s-%s-%s-%d", adj1, adj2, noun, num) default: //same as complex case @@ -936,7 +936,7 @@ func newRandInt(max int64) int64 { return nBig.Int64() } func GetComplexRandomName() string { - return GetRandomName(Complex) + return GetRandomName(ComplexityComplex) } func IsCollision(beacons []*ent.Beacon, str string) bool { diff --git a/tavern/internal/namegen/namegen_test.go b/tavern/internal/namegen/namegen_test.go index afca46d7c..7352aa7c9 100644 --- a/tavern/internal/namegen/namegen_test.go +++ b/tavern/internal/namegen/namegen_test.go @@ -11,9 +11,9 @@ import ( func TestGetRandomName(t *testing.T) { t.Run("BasicName", func(t *testing.T) { - name1 := namegen.GetRandomName(namegen.Simple) + name1 := namegen.GetRandomName(namegen.ComplexitySimple) assert.NotEmpty(t, name1) - name2 := namegen.GetRandomName(namegen.Moderate) + name2 := namegen.GetRandomName(namegen.ComplexityModerate) assert.NotEmpty(t, name2) name3 := namegen.GetComplexRandomName() assert.NotEmpty(t, name3) @@ -24,7 +24,7 @@ func TestGetRandomName(t *testing.T) { names := make(map[string]bool, 1000000) count := 0 for i := 0; i < 1000000; i++ { - name := namegen.GetRandomName(namegen.Complex) + name := namegen.GetRandomName(namegen.ComplexityComplex) exists, ok := names[name] require.False(t, ok, "Name %s already exists - after %d attempts", name, count) assert.False(t, exists) From 2c4c3ff01a3b353a1f2553f642619d7680a9684a Mon Sep 17 00:00:00 2001 From: ALEXANDER MA COTE Date: Thu, 18 Jan 2024 14:23:01 -0500 Subject: [PATCH 10/12] seperate them out into diffrent functions, removing the enum --- tavern/internal/c2/server.go | 12 ++--- tavern/internal/ent/schema/beacon.go | 2 +- tavern/internal/namegen/namegen.go | 62 +++++++++++++------------ tavern/internal/namegen/namegen_test.go | 8 ++-- tavern/test_data.go | 4 +- 5 files changed, 46 insertions(+), 42 deletions(-) diff --git a/tavern/internal/c2/server.go b/tavern/internal/c2/server.go index 652bbdd3a..0ef0918b7 100644 --- a/tavern/internal/c2/server.go +++ b/tavern/internal/c2/server.go @@ -74,9 +74,9 @@ func (srv *Server) ClaimTasks(ctx context.Context, req *c2pb.ClaimTasksRequest) //3. if the beacon is new lets pick a name for it if !beaconExists { candidateNames := []string{ - namegen.GetRandomName(namegen.Complexity(namegen.ComplexitySimple)), - namegen.GetRandomName(namegen.Complexity(namegen.ComplexityModerate)), - namegen.GetRandomName(namegen.Complexity((namegen.ComplexityComplex))), + namegen.GetRandomNameSimple(), + namegen.GetRandomNameModerate(), + namegen.GetRandomNameComplex(), } collisions, err := srv.graph.Beacon.Query().Where(beacon.NameIn(candidateNames...)).All(ctx) @@ -85,9 +85,9 @@ func (srv *Server) ClaimTasks(ctx context.Context, req *c2pb.ClaimTasksRequest) } if len(collisions) == 3 { candidateNames := []string{ - namegen.GetRandomName(namegen.Complexity(namegen.ComplexitySimple)), - namegen.GetRandomName(namegen.Complexity(namegen.ComplexityModerate)), - namegen.GetRandomName(namegen.Complexity((namegen.ComplexityComplex))), + namegen.GetRandomNameSimple(), + namegen.GetRandomNameModerate(), + namegen.GetRandomNameComplex(), } collisions, err = srv.graph.Beacon.Query().Where(beacon.NameIn(candidateNames...)).All(ctx) diff --git a/tavern/internal/ent/schema/beacon.go b/tavern/internal/ent/schema/beacon.go index 05c868d51..6ca0d3e80 100644 --- a/tavern/internal/ent/schema/beacon.go +++ b/tavern/internal/ent/schema/beacon.go @@ -27,7 +27,7 @@ func (Beacon) Fields() []ent.Field { NotEmpty(). Unique(). Immutable(). - DefaultFunc(namegen.GetComplexRandomName). + DefaultFunc(namegen.GetRandomNameComplex). Comment("A human readable identifier for the beacon."), field.String("principal"). Optional(). diff --git a/tavern/internal/namegen/namegen.go b/tavern/internal/namegen/namegen.go index 620ed2376..26fa89aa7 100644 --- a/tavern/internal/namegen/namegen.go +++ b/tavern/internal/namegen/namegen.go @@ -888,42 +888,49 @@ var ( } ) -type Complexity int +// getRandomNameSimple generates a random name with one adjective and one noun. +func GetRandomNameSimple() string { + adj, noun := getRandomAdjNoun() + return fmt.Sprintf("%s-%s", adj, noun) +} -const ( - ComplexitySimple Complexity = iota // 0 - ComplexityModerate // 1 - ComplexityComplex // 2 -) +// getRandomNameModerate generates a random name with two adjectives and one noun. +func GetRandomNameModerate() string { + adj1, adj2, noun := getRandomAdjAdjNoun() + return fmt.Sprintf("%s-%s-%s", adj1, adj2, noun) +} -// GetRandomName generates a random name based on the complexity. -func GetRandomName(complexity Complexity) string { - var adj1, adj2, noun string - var num int64 +// getRandomNameComplex generates a random name with two adjectives, one noun, and a number. +func GetRandomNameComplex() string { + adj1, adj2, noun := getRandomAdjAdjNoun() + num := newRandInt(10000000) + return fmt.Sprintf("%s-%s-%s-%d", adj1, adj2, noun, num) +} + +// Helper function to get a random adjective and noun. +func getRandomAdjNoun() (string, string) { + var adj, noun string if time.Now().Month() == time.October { - adj1 = adjectives_halloween[newRandInt(int64(len(adjectives_halloween)))] - adj2 = adjectives_halloween[newRandInt(int64(len(adjectives_halloween)))] + adj = adjectives_halloween[newRandInt(int64(len(adjectives_halloween)))] noun = noun_halloween[newRandInt(int64(len(noun_halloween)))] - num = newRandInt(10000000) } else { - adj1 = adjectives[newRandInt(int64(len(adjectives)))] - adj2 = adjectives[newRandInt(int64(len(adjectives)))] + adj = adjectives[newRandInt(int64(len(adjectives)))] noun = nouns[newRandInt(int64(len(nouns)))] - num = newRandInt(10000000) } + return adj, noun +} - switch complexity { - case ComplexitySimple: - return fmt.Sprintf("%s-%s", adj1, noun) - case ComplexityModerate: - return fmt.Sprintf("%s-%s-%s", adj1, adj2, noun) - case ComplexityComplex: - return fmt.Sprintf("%s-%s-%s-%d", adj1, adj2, noun, num) - default: - //same as complex case - return fmt.Sprintf("%s-%s-%s-%d", adj1, adj2, noun, num) +// Helper function to get two random adjectives and a noun. +func getRandomAdjAdjNoun() (string, string, string) { + adj1, noun := getRandomAdjNoun() + var adj2 string + if time.Now().Month() == time.October { + adj2 = adjectives_halloween[newRandInt(int64(len(adjectives_halloween)))] + } else { + adj2 = adjectives[newRandInt(int64(len(adjectives)))] } + return adj1, adj2, noun } // cryptoRandSecure is not always secure, if it errors we return 1337 % max @@ -935,9 +942,6 @@ func newRandInt(max int64) int64 { } return nBig.Int64() } -func GetComplexRandomName() string { - return GetRandomName(ComplexityComplex) -} func IsCollision(beacons []*ent.Beacon, str string) bool { for _, v := range beacons { diff --git a/tavern/internal/namegen/namegen_test.go b/tavern/internal/namegen/namegen_test.go index 7352aa7c9..02fb8677f 100644 --- a/tavern/internal/namegen/namegen_test.go +++ b/tavern/internal/namegen/namegen_test.go @@ -11,11 +11,11 @@ import ( func TestGetRandomName(t *testing.T) { t.Run("BasicName", func(t *testing.T) { - name1 := namegen.GetRandomName(namegen.ComplexitySimple) + name1 := namegen.GetRandomNameSimple() assert.NotEmpty(t, name1) - name2 := namegen.GetRandomName(namegen.ComplexityModerate) + name2 := namegen.GetRandomNameModerate() assert.NotEmpty(t, name2) - name3 := namegen.GetComplexRandomName() + name3 := namegen.GetRandomNameComplex() assert.NotEmpty(t, name3) }) @@ -24,7 +24,7 @@ func TestGetRandomName(t *testing.T) { names := make(map[string]bool, 1000000) count := 0 for i := 0; i < 1000000; i++ { - name := namegen.GetRandomName(namegen.ComplexityComplex) + name := namegen.GetRandomNameComplex() exists, ok := names[name] require.False(t, ok, "Name %s already exists - after %d attempts", name, count) assert.False(t, exists) diff --git a/tavern/test_data.go b/tavern/test_data.go index b957475d5..6f9ce2804 100644 --- a/tavern/test_data.go +++ b/tavern/test_data.go @@ -348,14 +348,14 @@ None func createQuest(ctx context.Context, client *ent.Client, beacons ...*ent.Beacon) { // Mid-Execution testTome := client.Tome.Create(). - SetName(namegen.GetRandomName(2)). + SetName(namegen.GetRandomNameComplex()). SetDescription("Print a message for fun!"). SetEldritch(`print(input_params['msg'])`). SetParamDefs(`[{"name":"msg","label":"Message","type":"string","placeholder":"something to print"}]`). SaveX(ctx) q := client.Quest.Create(). - SetName(namegen.GetRandomName(2)). + SetName(namegen.GetRandomNameComplex()). SetParameters(`{"msg":"Hello World!"}`). SetTome(testTome). SaveX(ctx) From 7c0dbf279576280461ff088bfebfd35fde909524 Mon Sep 17 00:00:00 2001 From: ALEXANDER MA COTE Date: Sat, 20 Jan 2024 20:52:17 -0500 Subject: [PATCH 11/12] fix imports --- tavern/internal/namegen/namegen.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tavern/internal/namegen/namegen.go b/tavern/internal/namegen/namegen.go index 26fa89aa7..101f88dd8 100644 --- a/tavern/internal/namegen/namegen.go +++ b/tavern/internal/namegen/namegen.go @@ -7,7 +7,7 @@ import ( "math/big" "time" - "github.com/kcarretto/realm/tavern/internal/ent" + "realm.pub/tavern/internal/ent" ) var ( From 02e73912456040f9ed2299cd245e2319f042b830 Mon Sep 17 00:00:00 2001 From: ALEXANDER MA COTE Date: Sat, 20 Jan 2024 20:56:24 -0500 Subject: [PATCH 12/12] add ent to namegen test --- tavern/internal/namegen/namegen_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/tavern/internal/namegen/namegen_test.go b/tavern/internal/namegen/namegen_test.go index 520dfbe47..8987bba76 100644 --- a/tavern/internal/namegen/namegen_test.go +++ b/tavern/internal/namegen/namegen_test.go @@ -5,6 +5,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "realm.pub/tavern/internal/namegen" + "realm.pub/tavern/internal/ent" ) func TestGetRandomName(t *testing.T) {