Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ require (
github.com/google/go-github/v33 v33.0.0
github.com/jasonlvhit/gocron v0.0.1
github.com/mattn/go-runewidth v0.0.21
github.com/moby/moby v28.5.2+incompatible
github.com/natefinch/lumberjack/v3 v3.0.0-alpha
github.com/peterbourgon/diskv/v3 v3.0.1
github.com/pkg/errors v0.9.1
Expand Down
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,6 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.21 h1:jJKAZiQH+2mIinzCJIaIG9Be1+0NR+5sz/lYEEjdM8w=
github.com/mattn/go-runewidth v0.0.21/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
github.com/moby/moby v28.5.2+incompatible h1:hIn6qcenb3JY1E3STwqEbBvJ8bha+u1LpqjX4CBvNCk=
github.com/moby/moby v28.5.2+incompatible/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc=
github.com/natefinch/lumberjack/v3 v3.0.0-alpha h1:HZ2AJF20D1lo9S0F/rpgkFbPGam5dgR3X0KUtZA5mlY=
github.com/natefinch/lumberjack/v3 v3.0.0-alpha/go.mod h1:rPTlHhMjhrvPAhqKh0FC57E0pXZoanrXgMDj4yv5wcM=
github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
Expand Down
4 changes: 2 additions & 2 deletions src/boost/boost_reactions.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ import (
"strings"
"time"

"github.com/mkmccarty/TokenTimeBoostBot/src/bottools"
"github.com/mkmccarty/TokenTimeBoostBot/src/ei"
"github.com/mkmccarty/TokenTimeBoostBot/src/farmerstate"
"github.com/mkmccarty/TokenTimeBoostBot/src/track"

"github.com/bwmarrin/discordgo"
"github.com/moby/moby/pkg/namesgenerator"
)

// ReactionAdd is called when a reaction is added to a message
Expand Down Expand Up @@ -180,7 +180,7 @@ func ReactionAdd(s *discordgo.Session, r *discordgo.MessageReaction) string {
case "🐿️":
if creatorOfContract(s, contract, r.UserID) {
for i := len(contract.Order); i < contract.CoopSize; i++ {
_, err := AddFarmerToContract(s, contract, r.GuildID, r.ChannelID, namesgenerator.GetRandomName(0), contract.BoostOrder, true)
_, err := AddFarmerToContract(s, contract, r.GuildID, r.ChannelID, bottools.GetRandomName(0), contract.BoostOrder, true)
if err != nil {
Comment on lines 181 to 184
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 🐿️ autofill loop increments i regardless of whether AddFarmerToContract actually added a new booster. With random-name IDs, collisions can cause AddFarmerToContract to no-op (existing booster) and the loop will finish with fewer than contract.CoopSize members. Generate IDs guaranteed-unique for the contract (e.g., retry until contract.Boosters[cand]==nil, or append a short random suffix/xid).

Copilot uses AI. Check for mistakes.
log.Println(err)
}
Expand Down
5 changes: 2 additions & 3 deletions src/boost/contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import (
"github.com/mkmccarty/TokenTimeBoostBot/src/ei"

"github.com/bwmarrin/discordgo"
"github.com/moby/moby/pkg/namesgenerator"
)

// GetSlashContractCommand returns the slash command for creating a contract
Expand Down Expand Up @@ -456,7 +455,7 @@ func CreateContract(s *discordgo.Session, contractID string, coopID string, play

// Try a number of random docker-style names first
for attempt := 0; attempt < 64; attempt++ {
cand := namesgenerator.GetRandomName(0)
cand := bottools.GetRandomName(0)
if Contracts[cand] == nil {
ContractHash = cand
break
Expand All @@ -465,7 +464,7 @@ func CreateContract(s *discordgo.Session, contractID string, coopID string, play

// Fallback: append a short random suffix to guarantee uniqueness
if ContractHash == "" {
base := namesgenerator.GetRandomName(0)
base := bottools.GetRandomName(0)
for {
suffix := strconv.FormatUint(rand.Uint64(), 36)
if len(suffix) > 6 {
Expand Down
10 changes: 5 additions & 5 deletions src/boost/roles.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import (
"sync"

"github.com/bwmarrin/discordgo"
"github.com/mkmccarty/TokenTimeBoostBot/src/bottools"
"github.com/mkmccarty/TokenTimeBoostBot/src/config"
"github.com/mkmccarty/TokenTimeBoostBot/src/ei"
"github.com/moby/moby/pkg/namesgenerator"
"google.golang.org/genai"
)

Expand Down Expand Up @@ -115,7 +115,7 @@ func getContractRoleName(contractID string) string {

if len(unusedRoleNames) == 0 {
// All names are taken; fall back to a generated team name
teamName = namesgenerator.GetRandomName(0)
teamName = bottools.GetRandomName(0)
prefix = "Team "
} else {
lastChance := false
Expand Down Expand Up @@ -151,7 +151,7 @@ func getContractRoleName(contractID string) string {
}
}
if teamName == "" {
teamName = namesgenerator.GetRandomName(0)
teamName = bottools.GetRandomName(0)
}
}

Expand Down Expand Up @@ -204,7 +204,7 @@ func getContractRole(s *discordgo.Session, guildID string, contract *Contract) e

if len(unusedRoleNames) == 0 {
// All names are taken; fall back to a generated team name
teamName = namesgenerator.GetRandomName(0)
teamName = bottools.GetRandomName(0)
prefix = "Team "
} else {
lastChance := false
Expand Down Expand Up @@ -240,7 +240,7 @@ func getContractRole(s *discordgo.Session, guildID string, contract *Contract) e
}
}
if teamName == "" {
teamName = namesgenerator.GetRandomName(0)
teamName = bottools.GetRandomName(0)
}
}

Expand Down
23 changes: 23 additions & 0 deletions src/bottools/random_name.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package bottools

import (
"fmt"
"math/rand/v2"
)

var randomNameLeft = []string{
"brisk", "calm", "clever", "cosmic", "crisp", "daring", "gentle", "lucky", "mellow", "nimble",
"quiet", "rapid", "savvy", "steady", "swift", "vivid", "witty", "bold", "bright", "chill",
}

var randomNameRight = []string{
"acorn", "anchor", "aster", "beacon", "bison", "comet", "drifter", "falcon", "harbor", "meadow",
"nebula", "otter", "ranger", "rocket", "sailor", "sprout", "thunder", "valley", "voyager", "zephyr",
}
Comment on lines +8 to +16
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The adjective/noun lists yield only 400 possible combinations, which makes collisions fairly likely in flows that assume uniqueness (e.g., placeholder farmers added via reactions, random token tracker names). Consider expanding the wordlists and/or adding a short random suffix inside GetRandomName to reduce collision probability.

Copilot uses AI. Check for mistakes.

// GetRandomName returns a docker-style random name.
func GetRandomName(_ int) string {
left := randomNameLeft[rand.IntN(len(randomNameLeft))]
right := randomNameRight[rand.IntN(len(randomNameRight))]
Comment on lines +19 to +21
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GetRandomName currently ignores its input parameter (it’s named _ int). Since this is an exported helper, either remove the parameter and update call sites, or document that it’s kept only for compatibility; ideally, use it (e.g., as a deterministic seed) so callers/tests can reproduce names when needed.

Suggested change
func GetRandomName(_ int) string {
left := randomNameLeft[rand.IntN(len(randomNameLeft))]
right := randomNameRight[rand.IntN(len(randomNameRight))]
// If seed is non-zero, the returned name is deterministic for that seed.
// If seed is zero, a non-deterministic package-level generator is used.
func GetRandomName(seed int) string {
if seed == 0 {
left := randomNameLeft[rand.IntN(len(randomNameLeft))]
right := randomNameRight[rand.IntN(len(randomNameRight))]
return fmt.Sprintf("%s_%s", left, right)
}
r := rand.New(rand.NewPCG(uint64(seed), uint64(seed)^0x9e3779b97f4a7c15))
left := randomNameLeft[r.IntN(len(randomNameLeft))]
right := randomNameRight[r.IntN(len(randomNameRight))]

Copilot uses AI. Check for mistakes.
return fmt.Sprintf("%s_%s", left, right)
}
Comment on lines +18 to +23
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This introduces a new random-name generator that is now used in several user-visible/code-path identifiers. Since the repo runs go test -race ./... in CI and src/bottools already has tests, please add unit coverage for GetRandomName (at least: format invariants, non-empty output, and—if a seed parameter is supported—deterministic output for a fixed seed) to prevent accidental regressions.

Copilot uses AI. Check for mistakes.
4 changes: 1 addition & 3 deletions src/track/track_slashcmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"github.com/mkmccarty/TokenTimeBoostBot/src/bottools"
"github.com/mkmccarty/TokenTimeBoostBot/src/ei"
"github.com/mkmccarty/TokenTimeBoostBot/src/farmerstate"
"github.com/moby/moby/pkg/namesgenerator"
"github.com/rs/xid"
"github.com/xhit/go-str2duration/v2"
)
Expand Down Expand Up @@ -158,8 +157,7 @@ func HandleTokenCommand(s *discordgo.Session, i *discordgo.InteractionCreate, co
if opt, ok := optionMap["coop-id"]; ok {
trackingName = strings.TrimSpace(opt.StringValue())
} else if trackingName == "" {

trackingName = fmt.Sprintln(namesgenerator.GetRandomName(0))
trackingName = bottools.GetRandomName(0)
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When coop-id is omitted and trackingName falls back to a random value, there’s no check that the generated name is unused for this user. If it collides with an existing tracker name, tokenTracking will delete the prior tracker message and reset its data. Consider generating until unused (check Tokens[userID].Coop) or adding a short unique suffix (e.g., xid) to avoid accidental overwrites.

Suggested change
trackingName = bottools.GetRandomName(0)
trackingName = fmt.Sprintf("%s-%s", bottools.GetRandomName(0), xid.New().String()[:6])

Copilot uses AI. Check for mistakes.

}
if opt, ok := optionMap["linked"]; ok {
Expand Down
Loading