diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..26ba2b5 --- /dev/null +++ b/LICENSE @@ -0,0 +1,18 @@ +Copyright 2021 Louis Abel + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/modules/paste/.rpaste.go.swp b/modules/paste/.rpaste.go.swp new file mode 100644 index 0000000..12dc7a1 Binary files /dev/null and b/modules/paste/.rpaste.go.swp differ diff --git a/modules/paste/method.go b/modules/paste/method.go index 7b5ffe7..fe4f596 100644 --- a/modules/paste/method.go +++ b/modules/paste/method.go @@ -42,16 +42,27 @@ func runPaste(ctx *cli.Context) error { } else if !stdMethod && PasteData == "" { argList := os.Args lastArg := argList[len(argList)-1] - fileBytes, err := ioutil.ReadFile(lastArg) - if err != nil { - panic(err) + if lastArg != os.Args[0] { + fileBytes, err := ioutil.ReadFile(lastArg) + if err != nil { + panic(err) + } + PasteData = string(fileBytes) } - PasteData = string(fileBytes) + } + + // Final check to see if there's paste data + if PasteData == "" { + cli.ShowAppHelp(ctx) + os.Exit(0) } // Check that PasteData is text, and not binary + // fmt.Println("You cannot upload binary data.") - fmt.Println(PasteData) + //fmt.Println(PasteData) + + Rpaste(ctx.String("life"), ctx.String("type"), PasteData) return nil } diff --git a/modules/paste/rpaste.go b/modules/paste/rpaste.go index fcb0b57..8b08dd5 100644 --- a/modules/paste/rpaste.go +++ b/modules/paste/rpaste.go @@ -1,6 +1,15 @@ // support for rpaste (bpaste) package paste +import ( + "bytes" + "encoding/json" + "fmt" + "net/http" + "os" + "strings" +) + var ( rpasteTimeMap = map[string]string{ "1hour": "1hour", @@ -8,3 +17,45 @@ var ( "1week": "1week", } ) + +func Rpaste(life string, lexer string, fileContent string) error { + payload := map[string]interface{}{ + "expiry": life, + "files": []map[string]string{ + { + "name": "paste", + "lexer": lexer, + "content": PasteData, + }, + }, + } + + payloadJson, err := json.Marshal(payload) + if err != nil { + fmt.Println("Could not marshal json") + os.Exit(1) + } + + fmt.Println("Uploading...") + resp, err := http.Post("https://rpa.st/api/v1/paste", "application/json", bytes.NewBuffer(payloadJson)) + if err != nil { + fmt.Println("Could not contact rpaste endpoint") + os.Exit(1) + } + + if resp.StatusCode == 200 { + var response map[string]interface{} + json.NewDecoder(resp.Body).Decode(&response) + url := fmt.Sprintf("%s", response["link"]) + ss := strings.Split(url, "/") + slug := ss[len(ss)-1] + + fmt.Printf("Paste URL: %s\n", response["link"]) + fmt.Printf("Raw URL: https://rpa.st/raw/%s\n", slug) + fmt.Printf("Removal URL: %s\n", response["removal"]) + } else { + fmt.Printf("ERROR: %d\n", resp.StatusCode) + } + + return nil +} diff --git a/modules/setting/usage.go b/modules/setting/usage.go index 667f92b..e10ba02 100644 --- a/modules/setting/usage.go +++ b/modules/setting/usage.go @@ -12,6 +12,7 @@ var ( HelpTemplate = "\033[01;32m{{.Name}}\033[0m: {{.Usage}}\n\n" + "Usage: {{.Name}} [options] [filepath]\n" + " command | {{.Name}} [options]\n\n" + + "This command can take a file or standard in as input\n\n" + "Options:\n" + "{{range .VisibleFlags}}{{.}}\n" + "{{end}}" diff --git a/modules/utility/file.go b/modules/utility/file.go index ef08338..bebd0ea 100644 --- a/modules/utility/file.go +++ b/modules/utility/file.go @@ -5,10 +5,11 @@ package utility import ( _ "errors" + "io/ioutil" "os" _ "path" _ "path/filepath" - _ "strings" + "strings" ) // Check if this is a file @@ -35,4 +36,13 @@ func IsExist(path string) (bool, error) { return false, err } +// Reads one-line text files (like for /sys or /proc) - Strips carriage returns +func Slurp(path string) string { + data, err := ioutil.ReadFile(path) + if err != nil { + return "" + } + return strings.TrimSpace(string(data)) +} + // todo: add string checking, we can't paste binary diff --git a/modules/utility/pipes.go b/modules/utility/pipes.go index 6ad9a84..e1b1ab5 100644 --- a/modules/utility/pipes.go +++ b/modules/utility/pipes.go @@ -13,10 +13,10 @@ func ExecutePipe(outbuffer *bytes.Buffer, stack ...*exec.Cmd) (err error) { i := 0 for ; i < len(stack)-1; i++ { - stdin_pipe, stdoutpipe := io.Pipe() + stdinpipe, stdoutpipe := io.Pipe() stack[i].Stdout = stdoutpipe stack[i].Stderr = &errbuffer - stack[i+1].Stdin = stdin_pipe + stack[i+1].Stdin = stdinpipe pipestack[i] = stdoutpipe } diff --git a/modules/utility/system.go b/modules/utility/system.go new file mode 100644 index 0000000..c5398ae --- /dev/null +++ b/modules/utility/system.go @@ -0,0 +1,50 @@ +package utility + +import ( + "bufio" + "os" + "regexp" + "strings" +) + +// Not all of these are going to be used, but just in case. This is more of a +// reference just for me. I want to be able to support more than just EL for +// example and send to the "right" paste bins or some generic one. +var ( + regexPrettyName = regexp.MustCompile(`^PRETTY_NAME=(.*)$`) + regexID = regexp.MustCompile(`^ID=(.*)$`) + regexVersionID = regexp.MustCompile(`^VERSION_ID=(.*)$`) + regexRockyName = regexp.MustCompile(`^Rocky( Linux)? release`) + regexOtherEL = regexp.MustCompile(`^(CentOS|Fedora|Red Hat Enterprise|AlmaLinux|Scientific)( Linux)? release`) + regexRedHatName = regexp.MustCompile(`^(Rocky|CentOS|Fedora|Red Hat Enterprise|AlmaLinux|Scientific)( Linux)? release`) + + VendorName string + SystemVersion string + SystemPrettyName string +) + +func SetPasteOnOS() string { + file, err := os.Open("/etc/os-release") + if err != nil { + return "" + } + defer file.Close() + scanner := bufio.NewScanner(file) + for scanner.Scan() { + if m := regexID.FindStringSubmatch(scanner.Text()); m != nil { + VendorName = strings.Trim(m[1], `"`) + } + } + + // default is set to rpaste elsewhere + switch VendorName { + case "rocky": + return "rpaste" + //setting.PasteBinService = "rpaste" + case "redhat", "fedora", "centos", "almalinux", "scientific": + return "fpaste" + //setting.PasteBinService = "fpaste" + } + + return "rpaste" +} diff --git a/rpaste.go b/rpaste.go index f1e3185..3b97525 100644 --- a/rpaste.go +++ b/rpaste.go @@ -21,6 +21,7 @@ var ( DefaultConf = "/etc/rpaste/rpaste.conf" DefaultLexer = "text" DefaultLifeTime = "1hour" + // This will end up being dynamic in the future DefaultPasteBin = "rpaste" DefaultSysInfo = false ShortOption = true @@ -40,7 +41,7 @@ func init() { func main() { app := &cli.App{ Name: AppName, - Usage: "Paste utility originally made for the Rocky paste service", + Usage: "A paste utility originally made for the Rocky paste service", Version: Version, // short options should be on UseShortOptionHandling: ShortOption, @@ -55,7 +56,8 @@ func main() { UsageText: `Paste utility used primarily for the Rocky Linux pastebin service. It can collect system information and forward it to a pastebin or simply send regular text files. This utility is primarily used for asking for -assistance in the Rocky Linux support venue.`, +assistance in the Rocky Linux community support venue. It can also be used on +other systems like Fedora and other Enterprise Linux distributions.`, // list all commands below Commands: []*cli.Command{ paste.PasteMethod, @@ -88,12 +90,6 @@ assistance in the Rocky Linux support venue.`, Usage: "Collects general system information (disables stdin and file input)", Required: false, }, - // &cli.StringFlag{ - // Name: "pastebin", - // Aliases: []string{"p"}, - // Value: setting.PasteBinService, - // Usage: "Decides what pastebin to use", - // }, } // append the default flags to both the main and paste method @@ -101,7 +97,7 @@ assistance in the Rocky Linux support venue.`, app.Flags = append(app.Flags, defaultFlags...) // Actions - //app.Before = establishConfExistence + //app.Before = utility.SetPasteOnOS app.Action = paste.PasteMethod.Action // Verify reader is set