lots o updates
- moved mcr code to package - added the save, run, and view commands - commands can now be saved - saved commands support placeholders
This commit is contained in:
parent
bef3521770
commit
f943639a88
59
client/mcr.go
Normal file
59
client/mcr.go
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"code.jakeyoungdev.com/jake/mctl/cryptography"
|
||||||
|
"github.com/jake-young-dev/mcr"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
This is a simple wrapper for the MCR client to provide easy use of mcr without having to manually
|
||||||
|
decrypt the password/hit viper each time.
|
||||||
|
*/
|
||||||
|
|
||||||
|
type Client struct {
|
||||||
|
cli *mcr.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
type IClient interface {
|
||||||
|
Close()
|
||||||
|
Command(cmd string) (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// creates a new mcr client using saved credentials and decrypted password
|
||||||
|
func New() (*Client, error) {
|
||||||
|
//grab saved credentials
|
||||||
|
server := viper.Get("server").(string)
|
||||||
|
password := viper.Get("password").(string)
|
||||||
|
port := viper.Get("port").(int)
|
||||||
|
fmt.Printf("Logging into %s on port %d\n", server, port)
|
||||||
|
|
||||||
|
//decrypt password
|
||||||
|
pt, err := cryptography.DecryptPassword([]byte(password))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
//connect to game server
|
||||||
|
cli := mcr.NewClient(server, mcr.WithPort(port))
|
||||||
|
err = cli.Connect(string(pt))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Client{
|
||||||
|
cli: cli,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// closes client connection
|
||||||
|
func (c *Client) Close() error {
|
||||||
|
return c.cli.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// sends command to server, only exists to prevent exposing cli field
|
||||||
|
func (c *Client) Command(cmd string) (string, error) {
|
||||||
|
return c.cli.Command(cmd)
|
||||||
|
}
|
@ -16,14 +16,15 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
server string
|
cfgserver string
|
||||||
port int
|
cfgport int
|
||||||
)
|
)
|
||||||
|
|
||||||
// configCmd represents the config command
|
// configCmd represents the config command
|
||||||
var configCmd = &cobra.Command{
|
var configCmd = &cobra.Command{
|
||||||
Use: "config",
|
Use: "config",
|
||||||
Short: "Create and populate config file",
|
Example: "mctl config -s x.x.x.x -p 61695",
|
||||||
|
Short: "Create and populate config file",
|
||||||
Long: `Creates the .mctl file in the user home directory
|
Long: `Creates the .mctl file in the user home directory
|
||||||
populating it with the server address, rcon password, and
|
populating it with the server address, rcon password, and
|
||||||
rcon port to be pulled when using Login command`,
|
rcon port to be pulled when using Login command`,
|
||||||
@ -33,26 +34,20 @@ var configCmd = &cobra.Command{
|
|||||||
ps, err := term.ReadPassword(int(os.Stdin.Fd()))
|
ps, err := term.ReadPassword(int(os.Stdin.Fd()))
|
||||||
cobra.CheckErr(err)
|
cobra.CheckErr(err)
|
||||||
|
|
||||||
//setup aes encrypter
|
|
||||||
// block, err := aes.NewCipher([]byte(viper.Get("device").(string)))
|
|
||||||
// cobra.CheckErr(err)
|
|
||||||
//generate and apply random nonce
|
//generate and apply random nonce
|
||||||
nonce := make([]byte, 12)
|
nonce := make([]byte, 12)
|
||||||
_, err = io.ReadFull(rand.Reader, nonce)
|
_, err = io.ReadFull(rand.Reader, nonce)
|
||||||
cobra.CheckErr(err)
|
cobra.CheckErr(err)
|
||||||
viper.Set("nonce", string(nonce))
|
viper.Set("nonce", string(nonce))
|
||||||
// aesg, err := cipher.NewGCM(block)
|
|
||||||
// cobra.CheckErr(err)
|
|
||||||
|
|
||||||
// //encrypt rcon password
|
//encrypt password
|
||||||
// ciphert := aesg.Seal(nil, nonce, ps, nil)
|
|
||||||
ciphert, err := cryptography.EncryptPassword(ps)
|
ciphert, err := cryptography.EncryptPassword(ps)
|
||||||
cobra.CheckErr(err)
|
cobra.CheckErr(err)
|
||||||
|
|
||||||
//update config file with new values
|
//update config file with new values
|
||||||
viper.Set("server", server)
|
viper.Set("server", cfgserver)
|
||||||
viper.Set("password", string(ciphert))
|
viper.Set("password", string(ciphert))
|
||||||
viper.Set("port", port)
|
viper.Set("port", cfgport)
|
||||||
viper.WriteConfig()
|
viper.WriteConfig()
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
fmt.Println("Config file updated!")
|
fmt.Println("Config file updated!")
|
||||||
@ -61,13 +56,14 @@ var configCmd = &cobra.Command{
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
initConfig()
|
initConfig()
|
||||||
configCmd.Flags().StringVarP(&server, "server", "s", "", "server address")
|
configCmd.Flags().StringVarP(&cfgserver, "server", "s", "", "server address")
|
||||||
configCmd.MarkFlagRequired("server")
|
configCmd.MarkFlagRequired("server")
|
||||||
configCmd.Flags().IntVarP(&port, "port", "p", 0, "server rcon port")
|
configCmd.Flags().IntVarP(&cfgport, "port", "p", 0, "server rcon port")
|
||||||
configCmd.MarkFlagRequired("port")
|
configCmd.MarkFlagRequired("port")
|
||||||
rootCmd.AddCommand(configCmd)
|
rootCmd.AddCommand(configCmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// init config sets viper config and checks for config file, creating it if it doesn't exist
|
||||||
func initConfig() {
|
func initConfig() {
|
||||||
home, err := os.UserHomeDir()
|
home, err := os.UserHomeDir()
|
||||||
cobra.CheckErr(err)
|
cobra.CheckErr(err)
|
||||||
@ -75,15 +71,14 @@ func initConfig() {
|
|||||||
viper.AddConfigPath(home)
|
viper.AddConfigPath(home)
|
||||||
viper.SetConfigType("yaml")
|
viper.SetConfigType("yaml")
|
||||||
viper.SetConfigName(".mctl")
|
viper.SetConfigName(".mctl")
|
||||||
|
|
||||||
viper.AutomaticEnv()
|
viper.AutomaticEnv()
|
||||||
viper.ReadInConfig()
|
viper.ReadInConfig()
|
||||||
|
|
||||||
if err := viper.ReadInConfig(); err != nil {
|
if err := viper.ReadInConfig(); err != nil {
|
||||||
//file does not exist, create it
|
//file does not exist, create it
|
||||||
viper.Set("server", server)
|
viper.Set("server", cfgserver)
|
||||||
viper.Set("password", "")
|
viper.Set("password", "")
|
||||||
viper.Set("port", port)
|
viper.Set("port", cfgport)
|
||||||
viper.Set("nonce", "")
|
viper.Set("nonce", "")
|
||||||
|
|
||||||
//generate psuedo-random key
|
//generate psuedo-random key
|
||||||
|
34
cmd/login.go
34
cmd/login.go
@ -8,43 +8,22 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"code.jakeyoungdev.com/jake/mctl/cryptography"
|
"code.jakeyoungdev.com/jake/mctl/client"
|
||||||
"github.com/jake-young-dev/mcr"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
// loginCmd represents the login command
|
// loginCmd represents the login command
|
||||||
var loginCmd = &cobra.Command{
|
var loginCmd = &cobra.Command{
|
||||||
Use: "login",
|
Use: "login",
|
||||||
Short: "Login to server and send commands",
|
Example: "mctl login",
|
||||||
|
Short: "Login to server and send commands",
|
||||||
Long: `Login to server using saved config and enter command loop
|
Long: `Login to server using saved config and enter command loop
|
||||||
sending commands to server and printing the response.`,
|
sending commands to server and printing the response.`,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
//grab saved credentials
|
//grab saved credentials
|
||||||
server := viper.Get("server")
|
server := viper.Get("server").(string)
|
||||||
password := viper.Get("password")
|
cli, err := client.New()
|
||||||
port := viper.Get("port")
|
|
||||||
fmt.Printf("Logging into %s on port %d\n", server, port)
|
|
||||||
|
|
||||||
//setup decrypter
|
|
||||||
// nonce := viper.Get("nonce")
|
|
||||||
// block, err := aes.NewCipher([]byte(viper.Get("device").(string)))
|
|
||||||
// cobra.CheckErr(err)
|
|
||||||
// aesg, err := cipher.NewGCM(block)
|
|
||||||
// cobra.CheckErr(err)
|
|
||||||
|
|
||||||
// //decrypt password
|
|
||||||
pwd := []byte(password.(string))
|
|
||||||
// nn := []byte(nonce.(string))
|
|
||||||
// pt, err := aesg.Open(nil, nn, pwd, nil)
|
|
||||||
// cobra.CheckErr(err)
|
|
||||||
pt, err := cryptography.DecryptPassword(pwd)
|
|
||||||
cobra.CheckErr(err)
|
|
||||||
|
|
||||||
//connect to game server
|
|
||||||
cli := mcr.NewClient(server.(string), mcr.WithPort(port.(int)))
|
|
||||||
err = cli.Connect(string(pt))
|
|
||||||
cobra.CheckErr(err)
|
cobra.CheckErr(err)
|
||||||
defer cli.Close()
|
defer cli.Close()
|
||||||
|
|
||||||
@ -62,6 +41,7 @@ var loginCmd = &cobra.Command{
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//mctl exits command terminal
|
||||||
if runningCmd == "mctl" {
|
if runningCmd == "mctl" {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
66
cmd/run.go
66
cmd/run.go
@ -1,50 +1,64 @@
|
|||||||
/*
|
/*
|
||||||
Copyright © 2025 NAME HERE <EMAIL ADDRESS>
|
Copyright © 2025 Jake jake.young.dev@gmail.com
|
||||||
*/
|
*/
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"code.jakeyoungdev.com/jake/mctl/client"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
// runCmd represents the run command
|
// runCmd represents the run command
|
||||||
var runCmd = &cobra.Command{
|
var runCmd = &cobra.Command{
|
||||||
Use: "run",
|
Use: "run <name> args...",
|
||||||
Short: "A brief description of your command",
|
Example: "mctl run savedcmd 63 jake",
|
||||||
Long: `A longer description that spans multiple lines and likely contains examples
|
Short: "Runs a previously saved command with supplied arguments on remote server",
|
||||||
and usage of using your command. For example:
|
Long: `Loads a saved command, injects the supplied arguments into the command, and sends the command to the remove server
|
||||||
|
printing the response`,
|
||||||
Cobra is a CLI library for Go that empowers applications.
|
|
||||||
This application is a tool to generate the needed files
|
|
||||||
to quickly create a Cobra application.`,
|
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
// fmt.Println(viper.Get(runname))
|
//grab saved command
|
||||||
// server := viper.Get("server")
|
cmdName := viper.Get(fmt.Sprintf("customCmd-%s", args[0])).(string)
|
||||||
// r := viper.Get(args[0])
|
//convert arguments to interface
|
||||||
// cli, err := mcr.NewClient()
|
var nargs []any
|
||||||
|
for _, a := range args[1:] {
|
||||||
|
nargs = append(nargs, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
//inject arguments
|
||||||
|
fixed := fmt.Sprintf(cmdName, nargs...)
|
||||||
|
fmt.Printf("Running saved command %s\n", fixed)
|
||||||
|
|
||||||
|
//create client and send command
|
||||||
|
cli, err := client.New()
|
||||||
|
cobra.CheckErr(err)
|
||||||
|
defer cli.Close()
|
||||||
|
|
||||||
|
res, err := cli.Command(fixed)
|
||||||
|
cobra.CheckErr(err)
|
||||||
|
|
||||||
|
fmt.Println(res)
|
||||||
},
|
},
|
||||||
PreRunE: func(cmd *cobra.Command, args []string) error {
|
PreRunE: func(cmd *cobra.Command, args []string) error {
|
||||||
if len(args) == 0 {
|
//ensure we have a command name
|
||||||
|
al := len(args)
|
||||||
|
if al == 0 {
|
||||||
return errors.New("name argument is required")
|
return errors.New("name argument is required")
|
||||||
}
|
}
|
||||||
|
cmdCheck := viper.Get(fmt.Sprintf("customCmd-%s", args[0]))
|
||||||
|
count := strings.Count(cmdCheck.(string), "%s")
|
||||||
|
//make sure enough arguments are sent to fill command placeholders
|
||||||
|
if al < count+1 {
|
||||||
|
return fmt.Errorf("not enough arguments to populate command. Supplied: %d, Needed: %d", al-1, count)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
rootCmd.AddCommand(runCmd)
|
rootCmd.AddCommand(runCmd)
|
||||||
// runCmd.Flags().StringVar(&runname, "name", "", "")
|
|
||||||
// runCmd.MarkFlagRequired("name")
|
|
||||||
|
|
||||||
// Here you will define your flags and configuration settings.
|
|
||||||
|
|
||||||
// Cobra supports Persistent Flags which will work for this command
|
|
||||||
// and all subcommands, e.g.:
|
|
||||||
// runCmd.PersistentFlags().String("foo", "", "A help for foo")
|
|
||||||
|
|
||||||
// Cobra supports local flags which will only run when this command
|
|
||||||
// is called directly, e.g.:
|
|
||||||
// runCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
|
|
||||||
}
|
}
|
||||||
|
51
cmd/save.go
51
cmd/save.go
@ -1,10 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
Copyright © 2025 NAME HERE <EMAIL ADDRESS>
|
Copyright © 2025 Jake jake.young.dev@gmail.com
|
||||||
*/
|
*/
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
@ -12,56 +13,36 @@ import (
|
|||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
|
||||||
name string
|
|
||||||
// cmd string
|
|
||||||
)
|
|
||||||
|
|
||||||
// saveCmd represents the save command
|
// saveCmd represents the save command
|
||||||
var saveCmd = &cobra.Command{
|
var saveCmd = &cobra.Command{
|
||||||
Use: "save",
|
Use: "save <name>",
|
||||||
Short: "A brief description of your command",
|
Example: "mctl save newcmd",
|
||||||
Long: `A longer description that spans multiple lines and likely contains examples
|
Short: "Saves a server command under an alias for quick execution",
|
||||||
and usage of using your command. For example:
|
Long: `Saves supplied command using alias <name> to allow the command to be executed using the run command. The %s placeholder can be
|
||||||
|
used as a wildcard to be injected when running the command`,
|
||||||
Cobra is a CLI library for Go that empowers applications.
|
|
||||||
This application is a tool to generate the needed files
|
|
||||||
to quickly create a Cobra application.`,
|
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
// fmt.Println("save called")
|
fmt.Printf("Use %s as a wildcard in your command\n", "%s") //this is ugly, have to use printf to stop issues with compiler
|
||||||
// viper.Set("testcmd", "im doin stuff and testing a command idea ' idk")
|
|
||||||
// viper.WriteConfig()
|
|
||||||
// fmt.Println(viper.Get("testcmd"))
|
|
||||||
// fmt.Println(name)
|
|
||||||
// fmt.Println(cmd)
|
|
||||||
fmt.Printf("Command: ")
|
fmt.Printf("Command: ")
|
||||||
sc := bufio.NewScanner(os.Stdin)
|
sc := bufio.NewScanner(os.Stdin)
|
||||||
if sc.Scan() {
|
if sc.Scan() {
|
||||||
txt := sc.Text()
|
txt := sc.Text()
|
||||||
if txt != "" {
|
if txt != "" {
|
||||||
viper.Set(name, txt)
|
viper.Set(fmt.Sprintf("customCmd-%s", args[0]), txt)
|
||||||
viper.WriteConfig()
|
viper.WriteConfig()
|
||||||
fmt.Println("\nSaved!")
|
fmt.Println("\nSaved!")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
PreRunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
if len(args) == 0 {
|
||||||
|
return errors.New("name argument is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
rootCmd.AddCommand(saveCmd)
|
rootCmd.AddCommand(saveCmd)
|
||||||
|
|
||||||
// Here you will define your flags and configuration settings.
|
|
||||||
|
|
||||||
// Cobra supports Persistent Flags which will work for this command
|
|
||||||
// and all subcommands, e.g.:
|
|
||||||
// saveCmd.PersistentFlags().String("foo", "", "A help for foo")
|
|
||||||
|
|
||||||
// Cobra supports local flags which will only run when this command
|
|
||||||
// is called directly, e.g.:
|
|
||||||
// saveCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
|
|
||||||
saveCmd.Flags().StringVar(&name, "name", "", "")
|
|
||||||
saveCmd.MarkFlagRequired("name")
|
|
||||||
// saveCmd.Flags().StringVar(&cmd, "command", "", "")
|
|
||||||
// saveCmd.MarkFlagRequired("command")
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright © 2025 NAME HERE <EMAIL ADDRESS>
|
Copyright © 2025 Jake jake.young.dev@gmail.com
|
||||||
*/
|
*/
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user