mirror of
https://github.com/RoganDawes/P4wnP1_aloa.git
synced 2025-03-28 18:41:46 +01:00
240 lines
8.3 KiB
Go
240 lines
8.3 KiB
Go
package cli_client
|
|
|
|
import (
|
|
"context"
|
|
"github.com/mame82/P4wnP1_aloa/common"
|
|
"github.com/spf13/cobra"
|
|
"fmt"
|
|
"path/filepath"
|
|
"strings"
|
|
"io"
|
|
"bufio"
|
|
"os"
|
|
"errors"
|
|
"log"
|
|
"strconv"
|
|
pb "github.com/mame82/P4wnP1_aloa/proto"
|
|
)
|
|
|
|
var (
|
|
tmpHidCommands = ""
|
|
tmpRunStored = ""
|
|
tmpHidTimeout = uint32(0) // values < 0 = endless
|
|
)
|
|
|
|
var hidCmd = &cobra.Command{
|
|
Use: "hid",
|
|
Short: "Use keyboard or mouse functionality",
|
|
}
|
|
|
|
var hidRunCmd = &cobra.Command{
|
|
Use: "run",
|
|
Short: "Run a HID Script",
|
|
Long:"Run script provided from standard input, commandline parameter or by path to script file on P4wnP1",
|
|
Run: cobraHidRun,
|
|
}
|
|
|
|
var hidJobCmd = &cobra.Command{
|
|
Use: "job",
|
|
Short: "Run a HID Script as background job",
|
|
Long:"Run a background script provided from standard input, commandline parameter or by path to script file on P4wnP1",
|
|
Run: cobraHidJob,
|
|
}
|
|
|
|
var hidJobCancelCmd = &cobra.Command{
|
|
Use: "cancel",
|
|
Short: "Cancel background job given by its ID",
|
|
Run: cobraHidJobCancel,
|
|
}
|
|
|
|
// Decision on how to run scripts (terms "local"/"remote" from perspective of gRPC server):
|
|
//
|
|
// 1) `P4wnP1_cli HID run` (no host flag, no additional args)
|
|
// Assume that the CLI runs on the same host as the server, read script from STDIN as no parameter is provided
|
|
// --> The script has to be run as remote script (content has to be transferred from CLI to gRPC server)
|
|
// after reading till EOF. Abort on timeout.
|
|
//
|
|
// 2) `P4wnP1_cli HID run --host "some hostname"` (host flag, no additional args)
|
|
// Assume that the CLI runs on a host different from the gRPC server, read script from STDIN as no parameter is provided
|
|
// --> The script has to be run as remote script (content has to be transferred from CLI to gRPC server)
|
|
// after reading till EOF. Abort on timeout.
|
|
//
|
|
// 3) `P4wnP1_cli HID run -c "Some HID script commands"`
|
|
// --> Same as 1) but content is read from `-c` instead of STDIN
|
|
//
|
|
// 4) `P4wnP1_cli HID run --host "some hostname" -c "Some HID script commands"`
|
|
// --> Same as 2) but content is read from `-c` instead of STDIN
|
|
//
|
|
// 5) `P4wnP1_cli HID run /some/path/to/file`
|
|
// Assume that the CLI runs on the same host as the server, assume that the given path refers to a file hosted on the
|
|
// gRPC server
|
|
// --> The script has to be run as local script (content is searched on P4wnP1 device by given path)
|
|
//
|
|
// 6) `P4wnP1_cli HID run --host "some hostname" -r /some/path/to/file`
|
|
// Assume that the CLI runs on a host different from the gRPC server and the given path points to a script on the host
|
|
// which runs the gRPC server (indicated by `-r`).
|
|
// --> The script has to be run as local script (content is searched on P4wnP1 device by given path)
|
|
//
|
|
// 7) `P4wnP1_cli HID run --host "some hostname" /some/path/to/file` (no host flag, no additional args)
|
|
// Assume that the CLI runs on a host different from the gRPC server and the given path points to a script on the host
|
|
// which runs the CLI client.
|
|
// --> The script has to be run as remote script (content has to be transferred from CLI to gRPC server)
|
|
// after reading it from the file.
|
|
//
|
|
// --> if flag `-c` is enabled, all following args are interpreted as script content
|
|
// --> if flag `-c` isn't set and args are present, the first arg is assumed to represent a filepath
|
|
// --> if flag `-c` isn't set and no additional args are provided, it is assumed that the script content has to be read
|
|
// from STDIN
|
|
//
|
|
// --> the two cases, which don't require a script content transfer from gRPC client to server:
|
|
// a) `-c` isn't set && --host == localhost && path is given as arg (example 5)
|
|
// b) `-c` isn't set && path is given with parameter `-r` (example 6)
|
|
//
|
|
// The logic above applies to both, running scripts synchronous with `run` or asynchronous with `job`
|
|
|
|
|
|
func parseHIDRunScriptCmd(cmd *cobra.Command, args []string) (serverScriptPath string, err error) {
|
|
/*
|
|
readFromStdin := false
|
|
localFile := false //if true readFilePath refers to a file on the host of the rpcClient, else to a file on the rpcServer
|
|
readFilePath := ""
|
|
scriptContent :=""
|
|
*/
|
|
|
|
var srcReader io.Reader
|
|
transferNeeded := false
|
|
|
|
|
|
cFlagSet := cmd.Flags().ShorthandLookup("c").Changed
|
|
rFlagSet := cmd.Flags().ShorthandLookup("n").Changed
|
|
|
|
switch {
|
|
case !rFlagSet && !cFlagSet:
|
|
// if `-c` and `-r` aren't set and no additional args are provided, we have to read from STDIN
|
|
if len(args) == 0 {
|
|
//We have to read from STDIN
|
|
srcReader = bufio.NewReader(os.Stdin)
|
|
transferNeeded = true
|
|
} else {
|
|
// we assume the arg is a filePath
|
|
if strings.ToLower(StrRemoteHost) != "localhost" {
|
|
// file not hosted on RPC server, needs to be transferred
|
|
transferNeeded=true
|
|
f,err := os.OpenFile(args[0], os.O_RDONLY, os.ModePerm)
|
|
if err != nil { return "",err }
|
|
defer f.Close()
|
|
srcReader = bufio.NewReader(f)
|
|
} else {
|
|
// assume RPC client is run from same host as RPC server and the script path refers to a local file
|
|
transferNeeded = false
|
|
serverScriptPath = common.PATH_HID_SCRIPTS + "/" + args[0]
|
|
}
|
|
}
|
|
case rFlagSet:
|
|
// the flag represents a script path on the RPC server, no matter where the RPC client is running, so we assume the script is already there
|
|
transferNeeded = false
|
|
serverScriptPath = common.PATH_HID_SCRIPTS + "/" + tmpRunStored
|
|
case cFlagSet:
|
|
// script content is provided by parameter and needs to be transferred
|
|
transferNeeded = true
|
|
srcReader = strings.NewReader(tmpHidCommands)
|
|
case cFlagSet && rFlagSet:
|
|
return "",errors.New("Couldn't use '-c' and '-r' at the same time")
|
|
default:
|
|
return "",errors.New("Invalid flag/parameter combination")
|
|
}
|
|
|
|
/*
|
|
if readFromStdin {
|
|
buf := make([]byte,1024)
|
|
reader := bufio.NewReader(os.Stdin)
|
|
for {
|
|
n,rErr := reader.Read(buf)
|
|
if rErr != nil {
|
|
if rErr == io.EOF { break } else { return rErr }
|
|
}
|
|
chunk := buf[:n]
|
|
scriptContent += string(chunk)
|
|
fmt.Printf("Read %d bytes: %+q\n", n, string(chunk))
|
|
}
|
|
}
|
|
|
|
|
|
fmt.Printf("readFromStdIn: %v path: %v content: %v\n", readFromStdin, readFilePath, scriptContent)
|
|
*/
|
|
|
|
if transferNeeded {
|
|
// create random remote file
|
|
|
|
serverScriptPath, err = ClientCreateTempFile(StrRemoteHost,StrRemotePort,"","HIDscript")
|
|
if err != nil {
|
|
return "",err
|
|
} else {
|
|
fmt.Printf("TempFile created: %s\n", serverScriptPath)
|
|
}
|
|
|
|
filename := filepath.Base(serverScriptPath)
|
|
|
|
//transfer from reader to remote file
|
|
err = ClientUploadFile(StrRemoteHost, StrRemotePort, srcReader, pb.AccessibleFolder_TMP, filename, true)
|
|
if err != nil { return "",errors.New(fmt.Sprintf("Error transfering HIDScript content to P4wnP1 Server: %v", err))}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func cobraHidRun(cmd *cobra.Command, args []string) {
|
|
serverScriptFilePath, err := parseHIDRunScriptCmd(cmd,args)
|
|
if err != nil { log.Fatal(err)}
|
|
|
|
ctx,cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
|
|
res,err := ClientHIDRunScript(StrRemoteHost, StrRemotePort, ctx, serverScriptFilePath, tmpHidTimeout)
|
|
if err != nil { log.Fatal(err) }
|
|
|
|
fmt.Printf("Result:\n%s\n", res.ResultJson)
|
|
return
|
|
}
|
|
|
|
|
|
func cobraHidJob(cmd *cobra.Command, args []string) {
|
|
serverScriptFilePath, err := parseHIDRunScriptCmd(cmd,args)
|
|
if err != nil { log.Fatal(err)}
|
|
|
|
|
|
job,err := ClientHIDRunScriptJob(StrRemoteHost, StrRemotePort, serverScriptFilePath, tmpHidTimeout)
|
|
if err != nil { log.Fatal(err) }
|
|
|
|
fmt.Printf("Job ID: %d\n", job.Id)
|
|
return
|
|
}
|
|
|
|
func cobraHidJobCancel(cmd *cobra.Command, args []string) {
|
|
if len(args) < 1 { log.Fatal("Job ID to cancel has to be given as argument\n")}
|
|
jobID,err := strconv.ParseUint(args[0], 10, 32)
|
|
if err != nil { log.Fatalf("Error parsing job ID '%s' ton integer\n", args[0])}
|
|
|
|
err = ClientHIDCancelScriptJob(StrRemoteHost, StrRemotePort, uint32(jobID))
|
|
if err != nil { log.Fatal(err) }
|
|
|
|
return
|
|
}
|
|
|
|
|
|
|
|
func init() {
|
|
rootCmd.AddCommand(hidCmd)
|
|
hidCmd.AddCommand(hidRunCmd)
|
|
hidCmd.AddCommand(hidJobCmd)
|
|
hidJobCmd.AddCommand(hidJobCancelCmd)
|
|
|
|
hidRunCmd.Flags().StringVarP(&tmpHidCommands, "commands","c", "", "HIDScript commands to run, given as string")
|
|
hidRunCmd.Flags().StringVarP(&tmpRunStored, "name","n", "", "Run a stored HIDScript")
|
|
hidRunCmd.Flags().Uint32VarP(&tmpHidTimeout, "timeout","t", 0, "Interrupt HIDScript after this timeout (seconds)")
|
|
|
|
hidJobCmd.Flags().StringVarP(&tmpHidCommands, "commands","c", "", "HIDScript commands to run, given as string")
|
|
hidJobCmd.Flags().StringVarP(&tmpRunStored, "name","n", "", "Run a stored HIDScript")
|
|
hidJobCmd.Flags().Uint32VarP(&tmpHidTimeout, "timeout","t", 0, "Interrupt HIDScript after this timeout (seconds)")
|
|
}
|