Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RBAC and player-to-player messaging #12

Merged
merged 10 commits into from
Dec 10, 2023
1 change: 1 addition & 0 deletions cmd/monarch/monarch.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ func main() {
config.ClientConfig.Name = "console"
db.Initialize()

commands.ConsoleInitCTX()
if err := console.Run(commands.ServerConsoleCommands, true); err != nil {
log.Fatal(err)
}
Expand Down
53 changes: 26 additions & 27 deletions pkg/commands/co-op.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,18 @@ import (
"encoding/hex"
"encoding/json"
"fmt"
"github.com/pygrum/monarch/pkg/protobuf/rpcpb"
"github.com/pygrum/monarch/pkg/types"
"os"
"time"

"github.com/google/uuid"
"github.com/pygrum/monarch/pkg/config"
"github.com/pygrum/monarch/pkg/console"
"github.com/pygrum/monarch/pkg/consts"
"github.com/pygrum/monarch/pkg/crypto"
"github.com/pygrum/monarch/pkg/db"
"github.com/pygrum/monarch/pkg/protobuf/clientpb"
"github.com/pygrum/monarch/pkg/protobuf/rpcpb"
"github.com/pygrum/monarch/pkg/teamserver"
"github.com/pygrum/monarch/pkg/teamserver/roles"
"github.com/pygrum/monarch/pkg/types"
"os"
)

func coopCmd(stop bool) {
Expand All @@ -33,39 +35,30 @@ func coopCmd(stop bool) {
}

func playersCmd(names []string) {
var players []db.Player
if len(names) > 0 {
if err := db.Where("username IN ?", names).Find(&players).Error; err != nil {
cLogger.Error("query failed: %v", err)
return
}
} else {
if err := db.Find(&players); err != nil {
cLogger.Error("query failed: %v", err)
}
players, err := console.Rpc.Players(ctx, &clientpb.PlayerRequest{Names: names})
if err != nil {
cLogger.Error("%v", err)
return
}
header := "USERNAME\tACCOUNT CREATION DATE\t"
header := "USERNAME\tROLE\tACCOUNT CREATION DATE\t"
_, _ = fmt.Fprintln(w, header)
for _, player := range players {
if player.Username == "console" {
for _, player := range players.Players {
if player.Username == consts.UserConsole {
continue
}
line := fmt.Sprintf("%s\t%s\t",
line := fmt.Sprintf("%s\t%s\t%s\t",
player.Username,
player.CreatedAt.Format(time.RFC850),
player.Role,
player.Registered,
)
_, _ = fmt.Fprintln(w, line)
}
_ = w.Flush()
}

func playersNewCmd(name, lhost string) {
if len(name) == 0 {
cLogger.Error("you must specify the player name")
return
}
if len(lhost) == 0 {
cLogger.Error("you must specify the server host")
func playersNewCmd(name, lhost, role string) {
if !roles.ValidRole(role) {
cLogger.Error("'%s' is not a valid role", role)
return
}
// don't save certificate deliberately, we don't need to and could be an issue if
Expand Down Expand Up @@ -100,6 +93,7 @@ func playersNewCmd(name, lhost string) {
Username: name,
ClientCA: b64Cert,
Challenge: challenge,
Role: roles.Role(role),
Secret: hex.EncodeToString(secret),
}
bytes, err := json.Marshal(clientConfig)
Expand All @@ -115,10 +109,15 @@ func playersNewCmd(name, lhost string) {
cLogger.Error("failed to create configuration file: %v", err)
return
}
cLogger.Info("account '%s' created with role '%s'", name, role)
cLogger.Success("saved player config to ./" + name + "-monarch-client.config")
}

func playersKickCmd(name string) {
if name == consts.UserConsole {
cLogger.Warn("you cannot kick yourself")
return
}
player := &db.Player{}
if err := db.FindOneConditional("username = ?", name, &player); err != nil {
cLogger.Error("query failed: %v", err)
Expand Down
78 changes: 57 additions & 21 deletions pkg/commands/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ import (
"github.com/pygrum/monarch/pkg/completion"
"github.com/pygrum/monarch/pkg/config"
"github.com/pygrum/monarch/pkg/crypto"
"github.com/pygrum/monarch/pkg/teamserver/roles"
"github.com/rsteube/carapace"
"github.com/sirupsen/logrus"
"google.golang.org/grpc/metadata"
"strconv"
"strings"

"github.com/pygrum/monarch/pkg/console"
"github.com/pygrum/monarch/pkg/log"
Expand All @@ -19,8 +21,9 @@ import (
)

var (
ctx = context.Background()
cLogger log.Logger
ctx = context.Background()
cLogger log.Logger
cmdPlayers *cobra.Command
)

func init() {
Expand All @@ -40,6 +43,14 @@ func InitCTX() {
ctx = metadata.NewOutgoingContext(ctx, md)
}

func ConsoleInitCTX() {
m := make(map[string]string)
m["player"] = config.ClientConfig.UUID
m["role"] = string(roles.RoleAdmin)
md := metadata.New(m)
ctx = metadata.NewOutgoingContext(ctx, md)
}

func ServerConsoleCommands() *cobra.Command {
root := ConsoleCommands()
var stop bool
Expand All @@ -52,26 +63,26 @@ func ServerConsoleCommands() *cobra.Command {
}
cmdCoop.Flags().BoolVarP(&stop, "stop", "s", false, "turn off co-op mode")

cmdPlayers := &cobra.Command{
Use: "players",
Short: "list players that have been registered on the server",
Run: func(cmd *cobra.Command, args []string) {
playersCmd(args)
},
}
carapace.Gen(cmdPlayers).PositionalCompletion(completion.Players())

var name, lhost string
var name, lhost, role string
cmdPlayersNew := &cobra.Command{
Use: "new",
Short: "generate a configuration file for a new player",
Run: func(cmd *cobra.Command, args []string) {
playersNewCmd(name, lhost)
playersNewCmd(name, lhost, role)
},
}
cmdPlayersNew.Flags().StringVarP(&name, "username", "u", "", "username of the new player")
cmdPlayersNew.Flags().StringVarP(&lhost, "lhost", "l", "",
"the hostname the player authenticates to this server using")
cmdPlayersNew.Flags().StringVarP(&role, "role", "r", "player",
"the player role (see autocomplete options)")
carapace.Gen(cmdPlayersNew).FlagCompletion(carapace.ActionMap{
"role": carapace.ActionValues(roles.All().String()...),
})

_ = cmdPlayersNew.MarkFlagRequired("username")
_ = cmdPlayersNew.MarkFlagRequired("lhost")

cmdPlayersKick := &cobra.Command{
Use: "kick [flags] NAME",
Short: "kick a player from the server",
Expand All @@ -80,10 +91,10 @@ func ServerConsoleCommands() *cobra.Command {
playersKickCmd(args[0])
},
}
carapace.Gen(cmdPlayersKick).PositionalCompletion(completion.Players())
carapace.Gen(cmdPlayersKick).PositionalCompletion(completion.Players(ctx))

cmdPlayers.AddCommand(cmdPlayersNew, cmdPlayersKick)
root.AddCommand(cmdCoop, cmdPlayers)
root.AddCommand(cmdCoop)
return root
}

Expand Down Expand Up @@ -117,7 +128,7 @@ func ConsoleCommands() *cobra.Command {
buildersCmd(args)
},
}
carapace.Gen(cmdBuilders).PositionalCompletion(completion.Builders(ctx))
carapace.Gen(cmdBuilders).PositionalAnyCompletion(completion.Builders(ctx))

cmdAgents := &cobra.Command{
Use: "agents [flags] AGENTS...",
Expand All @@ -126,7 +137,7 @@ func ConsoleCommands() *cobra.Command {
agentsCmd(args)
},
}
carapace.Gen(cmdAgents).PositionalCompletion(completion.Agents(ctx))
carapace.Gen(cmdAgents).PositionalAnyCompletion(completion.Agents(ctx))

cmdAgentsRm := &cobra.Command{
Use: "rm [flags] AGENTS...",
Expand All @@ -136,7 +147,7 @@ func ConsoleCommands() *cobra.Command {
cmdRm(args)
},
}
carapace.Gen(cmdAgentsRm).PositionalCompletion(completion.Agents(ctx))
carapace.Gen(cmdAgentsRm).PositionalAnyCompletion(completion.Agents(ctx))
cmdAgents.AddCommand(cmdAgentsRm)

cmdSessions := &cobra.Command{
Expand All @@ -146,7 +157,7 @@ func ConsoleCommands() *cobra.Command {
sessionsCmd(args)
},
}
carapace.Gen(cmdSessions).PositionalCompletion(completion.Sessions(ctx))
carapace.Gen(cmdSessions).PositionalAnyCompletion(completion.Sessions(ctx))

cmdUse := &cobra.Command{
Use: "use [id]",
Expand Down Expand Up @@ -222,7 +233,7 @@ func ConsoleCommands() *cobra.Command {
uninstallCmd(args, purge)
},
}
carapace.Gen(cmdUninstall).PositionalCompletion(completion.Builders(ctx))
carapace.Gen(cmdUninstall).PositionalAnyCompletion(completion.Builders(ctx))

cmdUninstall.Flags().BoolVarP(&purge, "delete-data", "p", false, "delete the source"+
" folder that was saved to disk when installed")
Expand Down Expand Up @@ -267,8 +278,33 @@ func ConsoleCommands() *cobra.Command {
fmt.Print("\033[H\033[2J")
},
}
cmdPlayers = &cobra.Command{
Use: "players [USERNAMES...]",
Short: "list registered players",
Run: func(cmd *cobra.Command, args []string) {
playersCmd(args)
},
}
carapace.Gen(cmdPlayers).PositionalCompletion(completion.Players(ctx))

var to string
var all bool
cmdSend := &cobra.Command{
Use: "send",
Short: "send a message to another online player",
Run: func(cmd *cobra.Command, args []string) {
sendCmd(to, strings.Join(args, " "), all)
},
}
cmdSend.Flags().StringVarP(&to, "to", "t", "", "player to message")
cmdSend.Flags().BoolVarP(&all, "all", "a", false, "message all players")

carapace.Gen(cmdSend).FlagCompletion(carapace.ActionMap{
"to": completion.Players(ctx),
})

root.AddCommand(cmdSessions, cmdUse, cmdHttp, cmdHttps, cmdAgents, cmdBuilders, cmdBuild, cmdInstall, cmdUninstall,
cmdStage, cmdUnstage, cmdVersion, cmdClear, cmdExit)
cmdStage, cmdUnstage, cmdVersion, cmdClear, cmdPlayers, cmdSend, cmdExit)
root.CompletionOptions.HiddenDefaultCmd = true
return root
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/commands/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ func installCmd(repoUrl, branch string, useCreds bool) {
for {
notif, err := stream.Recv()
if err == io.EOF {
break
return
}
if err != nil {
cLogger.Error("install failed: %v", err)
break
return
}
log.NumericalLevel(cLogger, uint16(notif.LogLevel), notif.Msg)
}
Expand Down
3 changes: 2 additions & 1 deletion pkg/commands/install_local.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ func localCmd(path string) {
break
}
if err != nil {
cLogger.Error("failed to receive notification: %v", err)
cLogger.Error("install failed: %v", err)
return
}
log.NumericalLevel(cLogger, uint16(notif.LogLevel), notif.Msg)
}
Expand Down
20 changes: 20 additions & 0 deletions pkg/commands/send.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package commands

import (
"github.com/pygrum/monarch/pkg/console"
"github.com/pygrum/monarch/pkg/protobuf/rpcpb"
)

func sendCmd(to, msg string, all bool) {
if len(to) == 0 {
if !all {
cLogger.Error("player not specified with -to, please specify a player name or --all")
return
}
}
if _, err := console.Rpc.SendMessage(ctx, &rpcpb.Message{To: to, Msg: msg}); err != nil {
cLogger.Error("%v", err)
return
}
cLogger.Info("sent")
}
9 changes: 4 additions & 5 deletions pkg/completion/completion.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package completion
import (
"context"
"github.com/pygrum/monarch/pkg/console"
"github.com/pygrum/monarch/pkg/db"
"github.com/pygrum/monarch/pkg/protobuf/clientpb"
"github.com/rsteube/carapace"
"strconv"
Expand Down Expand Up @@ -58,12 +57,12 @@ func Options(options []string) carapace.Action {
return carapace.ActionCallback(c)
}

func Players() carapace.Action {
func Players(mctx context.Context) carapace.Action {
c := func(ctx carapace.Context) carapace.Action {
var results []string
var players []db.Player
if err := db.Find(&players); err == nil {
for _, p := range players {
players, err := console.Rpc.Players(mctx, &clientpb.PlayerRequest{Names: make([]string, 0)})
if err == nil {
for _, p := range players.Players {
results = append(results, p.Username)
}
}
Expand Down
Loading
Loading