]> 91.132.146.200 Git - selfpaste.git/commitdiff
selfpase go client ready
authorBanana <johannes.kessler@bechtle.com>
Wed, 16 Mar 2022 13:34:45 +0000 (14:34 +0100)
committerBanana <johannes.kessler@bechtle.com>
Wed, 16 Mar 2022 13:34:45 +0000 (14:34 +0100)
client/c-client-linux/selfpaste.c
client/go-client/README
client/go-client/go.mod
client/go-client/go.sum
client/go-client/selfpaste.go

index 25a1059bf05d9e8bde6ca074125258070d4a660e..244564f36916334512e2678d4326a1729fdbc306 100644 (file)
@@ -5,7 +5,7 @@
  * COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
  * along with this program.  If not, see http://www.sun.com/cddl/cddl.html
  *
- * 2019 - 2020 https://://www.bananas-playground.net/projekt/selfpaste
+ * 2019 - 2022 https://://www.bananas-playground.net/projekt/selfpaste
  */
 
 /**
@@ -40,14 +40,13 @@ static char args_doc[] = "file";
 /* The options we understand. */
 static struct argp_option options[] = {
     {"verbose",'v', 0, 0, "Produce verbose output" },
-    {"quiet", 'q', 0, 0, "Don't produce any output" },
     {"create-config-file", 'c', 0, 0, "Create default config file" },
     { 0 }
 };
 
 struct cmdArguments {
     char *args[1];
-    int quiet, verbose, create_config_file;
+    int verbose, create_config_file;
 };
 
 /* Parse a single option. */
@@ -56,9 +55,6 @@ parse_opt (int key, char *arg, struct argp_state *state) {
     struct cmdArguments *arguments = state->input;
 
     switch (key) {
-        case 'q':
-            arguments->quiet = 1;
-        break;
         case 'v':
             arguments->verbose = 1;
         break;
@@ -173,7 +169,7 @@ int uploadCall(struct configOptions cfgo, struct cmdArguments arguments) {
     curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);
     /* some servers don't like requests that are made without a user-agent */
     /* field, so we provide one */
-    curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "selfpaseCurlAgent/1.0");
+    curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "selfpasteAgent/1.0");
 
     /* add the POST data */
     /* https://curl.haxx.se/libcurl/c/postit2.html */
@@ -241,7 +237,6 @@ int main(int argc, char *argv[]) {
      * command line argument parsing and default values
      */
     struct cmdArguments arguments;
-    arguments.quiet = 0;
     arguments.verbose = 0;
     arguments.create_config_file = 0;
 
@@ -250,11 +245,9 @@ int main(int argc, char *argv[]) {
     if(arguments.verbose) {
         printf ("File = %s\n"
             "Verbose = %s\n"
-            "Quiet = %s\n"
             "Create config file = %s\n",
             arguments.args[0],
             arguments.verbose ? "yes" : "no",
-            arguments.quiet ? "yes" : "no",
             arguments.create_config_file ? "yes" : "no"
         );
     }
index 6e356bed8b1cddd08f53a2433525acb9108b146a..65ad9fcc8771958b7ecbaddb7c8c120b0b0a56b1 100644 (file)
@@ -6,3 +6,4 @@ This is a very simple, with limited experience written, go program.
 Use at own risk and feel free to improve.
 
 Howto build:
+Nothing special, just go build -o selfpase
\ No newline at end of file
index b7aa2920ed44c57cd00391cbcc82d97d0436b857..31eec34a387f99709342af154f9163c012f396cd 100644 (file)
@@ -1,3 +1,5 @@
 module selfpaste/go-client
 
 go 1.17
+
+require gopkg.in/yaml.v2 v2.4.0 // indirect
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..75346616b19bda7882ecbba954fe5bc1e5577468 100644 (file)
@@ -0,0 +1,3 @@
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
index 46b69f21e8c152a1e0940c09fbe703d5469aada2..910b75321ed40de9b7c02f5d2c9169cfb0d3a399 100644 (file)
@@ -6,6 +6,13 @@ import (
        "log"
        "math/rand"
        "os"
+       "flag"
+       "gopkg.in/yaml.v2"
+       "net/http"
+       "io/ioutil"
+       "bytes"
+       "mime/multipart"
+       "encoding/json"
 )
 
 // This program is free software: you can redistribute it and/or modify
@@ -16,15 +23,73 @@ import (
 
 // 2019 - 2022 https://://www.bananas-playground.net/projekt/selfpaste
 
+/**
+ * !WARNING!
+ * This is a very simple, with limited experience written, go program.
+ * Use at own risk and feel free to improve
+ */
+
 const website = "https://www.bananas-playground.net/projekt/selfpaste"
 const version = "1.0"
 // used for non-existing default config
 const letters = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-_"
 
+// command line parameters
+var optsVerbose bool
+var optsCreateConfig bool
+var optsDebug bool
+
+// config
+var cfg Config
+// config file struct
+type Config struct {
+       Endpoint struct {
+               Host string `yaml:"host"`
+               Secret string `yaml:"secret"`
+    } `yaml:"endpoint"`
+}
+
+// response json struct
+type Response struct {
+       Message string `json:"message"`
+       Status int `json:"status"`
+}
+
+/**
+ * Main
+ */
 func main() {
+
+       // parse commandline parameters
+       flag.BoolVar(&optsVerbose, "verbose", false, "Produce verbose output")
+       flag.BoolVar(&optsCreateConfig, "create-config-file", false, "Create default config file")
+       flag.BoolVar(&optsDebug, "debug", false, "Print debug infos")
+       flag.Parse()    
+       if optsDebug {
+               fmt.Println("verbose:", optsVerbose)
+               fmt.Println("create-config-file:", optsCreateConfig)
+               fmt.Println("debug:", optsDebug)
+       }
+
+       // load the config and populate Config
        loadConfig()
+
+       // get the paylout
+       payload := getInput()
+       if optsDebug { log.Println(payload) }
+
+       // do the upload and get the response
+       responseString := uploadCall(payload)
+       response := Response{}
+    json.Unmarshal([]byte(responseString), &response)
+
+    // print the result and link to the pasty
+    fmt.Printf("Status: %d\n", response.Status)
+    fmt.Printf("Message: %s\n", response.Message)
 }
 
+
+
 /**
  * Check and display error with additional message
  */
@@ -34,6 +99,17 @@ func errorCheck(e error, msg string) {
        }
 }
 
+/**
+ * just a random string
+ */
+func randStringBytes(n int) string {
+       b := make([]byte, n)
+       for i := range b {
+               b[i] = letters[rand.Intn(len(letters))]
+       }
+       return string(b)
+}
+
 /**
  * load or even create a default config
  * $HOME/.selfpaste.yaml
@@ -41,37 +117,135 @@ func errorCheck(e error, msg string) {
 func loadConfig() {
        homeDir, err := os.UserHomeDir()
        errorCheck(err, "No $HOME directory available?")
-       log.Printf("Your $HOME: %s \n", homeDir)
+       if optsVerbose { log.Printf("Your $HOME: %s \n", homeDir) }
 
        var configFile = homeDir + "/.selfpaste.yaml"
 
        if _, err := os.Stat(configFile); errors.Is(err, os.ErrNotExist) {
-               log.Printf("Config file not found. Creating default: %s \n", configFile)
+               log.Printf("Config file not found: %s \n", configFile)
+
+               if optsCreateConfig {
+                       log.Printf("Creating new default config file: %s \n", configFile)
+
+                       newConfig, err := os.Create(configFile)
+                       errorCheck(err, "Can not create config file!")
+                       defer newConfig.Close()
+
 
-               newConfig, err := os.Create(configFile)
-               errorCheck(err, "Can not create config file!")
-               defer newConfig.Close()
+                       _, err = fmt.Fprintf(newConfig, "# selfpaste go client config file.\n")
+                       errorCheck(err, "Can not write to new config file")
+                       fmt.Fprintf(newConfig, "# See %s for more details.\n", website)
+                       fmt.Fprintf(newConfig, "# Version: %s\n", version)
+                       fmt.Fprintf(newConfig, "endpoint:\n")
+                       fmt.Fprintf(newConfig, "  host: http://your-seflpaste-endpoi.nt\n")
+                       fmt.Fprintf(newConfig, "  secret: %s\n", randStringBytes(50))
 
+                       log.Fatalf("New default config file created: - %s - Edit and launch again!",configFile)
+               }
+       }
+
+       existingConfigFile, err := os.Open(configFile)
+       errorCheck(err, "Can not open config file")
+       defer existingConfigFile.Close()
+       if optsVerbose { log.Printf("Reading config file: %s \n", configFile) }
 
-               _, err = fmt.Fprintf(newConfig, "# selfpaste go client config file.\n")
-               errorCheck(err, "Can not write to new config file")
-               fmt.Fprintf(newConfig, "# See %s for more details.\n", website)
-               fmt.Fprintf(newConfig, "# Version: %s\n", version)
-               fmt.Fprintf(newConfig, "endpoint:\n")
-               fmt.Fprintf(newConfig, "  host: http://your-seflpaste-endpoi.nt\n")
-               fmt.Fprintf(newConfig, "  secret: %s\n", randStringBytes(50))
+       var decoder = yaml.NewDecoder(existingConfigFile)
+       err = decoder.Decode(&cfg)
+       errorCheck(err, "Can not decode config file")
+
+       if cfg.Endpoint.Host == "" || cfg.Endpoint.Secret == "" {
+               log.Fatal("Empty config?")
+       }
 
-               log.Fatalf("New default config file created: - %s - Edit and launch again!",configFile)
+       if optsDebug {
+               log.Println(cfg.Endpoint.Host)
+               log.Println(cfg.Endpoint.Secret)
        }
 }
 
 /**
- * just a random string
+ * Do a http POST call to the defined endpoint
+ * and upload the payload
+ * Return response body as string
  */
-func randStringBytes(n int) string {
-       b := make([]byte, n)
-       for i := range b {
-               b[i] = letters[rand.Intn(len(letters))]
+func uploadCall(payload string) string {
+
+       if optsVerbose { log.Println("Starting to upload data") }
+       if optsDebug { log.Println(payload) }
+       if len(payload) == 0 {
+               log.Fatal("Nothing provided to upload")
        }
-       return string(b)
+
+       // Buffer to store our request body as bytes
+       var requestBody bytes.Buffer
+
+       // Create a multipart writer
+       multiPartWriter := multipart.NewWriter(&requestBody)
+
+       // file field
+       fileWriter, err := multiPartWriter.CreateFormFile("pasty", "pastyfile")
+       errorCheck(err, "Can not create form file field")
+       fileWriter.Write([]byte(payload))
+
+       dlField, err := multiPartWriter.CreateFormField("dl")
+       errorCheck(err, "Can not create form dl field")
+       dlField.Write([]byte(cfg.Endpoint.Secret))
+
+       multiPartWriter.Close()
+
+       req, err := http.NewRequest(http.MethodPost, cfg.Endpoint.Host, &requestBody)
+       errorCheck(err, "Can not create http request")
+       // We need to set the content type from the writer, it includes necessary boundary as well
+       req.Header.Set("Content-Type", multiPartWriter.FormDataContentType())
+       req.Header.Set("User-Agent", "selfpasteAgent/1.0");
+
+       // Do the request
+       client := &http.Client{}
+       response, err := client.Do(req)
+       errorCheck(err, "POST request failed")
+
+       responseBody, err := ioutil.ReadAll(response.Body)
+       errorCheck(err, "Can not read response body")
+
+       if optsVerbose { log.Println("Request done") }
+       if optsDebug {
+               log.Printf("Response status code: %d\n",response.StatusCode)
+               log.Printf("Response headers: %#v\n", response.Header)
+               log.Println(string(responseBody)) 
+        }
+
+        return string(responseBody)
 }
+
+/**
+ * check if file is provided as commandline argument
+ * or piped into
+ * return the read data as string
+ */
+func getInput() string {
+       if optsVerbose { log.Println("Getting input") }
+
+       var inputString string
+
+       if filename := flag.Arg(0); filename != "" {
+               if optsVerbose { log.Println("Read from file argument") }
+
+               bytes, err := os.ReadFile(filename)
+               errorCheck(err, "Error opening file")
+               inputString = string(bytes)
+       } else {
+               stat, _ := os.Stdin.Stat()
+               if (stat.Mode() & os.ModeCharDevice) == 0 {
+                       if optsVerbose { log.Println("data is being piped") }
+
+                       bytes, _ := ioutil.ReadAll(os.Stdin)
+                       inputString = string(bytes)
+               }
+       }
+
+       if len(inputString) == 0 {
+               log.Fatal("Nothing provided to upload")
+       }
+
+       return inputString
+}
\ No newline at end of file