@@ -2,25 +2,34 @@ package main
22
33import (
44 "bytes"
5+ "errors"
56 "flag"
67 "fmt"
78 "io"
8- "io/ioutil"
99 "mime/multipart"
1010 "net/http"
1111 "os"
1212 "path/filepath"
1313 "strconv"
14+ "strings"
1415 "time"
1516
17+ "github.com/rodaine/table"
1618 "golang.design/x/clipboard"
1719)
1820
21+ type uploadedFile struct {
22+ fileName string
23+ upUrl string
24+ }
25+
1926func main () {
2027 expires := flag .Int ("expires" , 0 , "set expiration time for the uploaded file in hours" )
2128 secret := flag .Bool ("secret" , false , "enable secret mode" )
29+ dirMode := flag .Bool ("dir" , false , "enable directory mode (non-recursive)" )
30+
2231 flag .Usage = func () {
23- fmt .Fprintf (os .Stderr , "Usage: [-expires <hours>] [-secret] < filePath>\n " )
32+ fmt .Fprintf (os .Stderr , "Usage: [-expires <hours>] [-secret] [-dir] <directory/ filePath>\n " )
2433 flag .PrintDefaults ()
2534 fmt .Print ("\n " )
2635 os .Exit (1 )
@@ -31,21 +40,108 @@ func main() {
3140 if len (args ) < 1 {
3241 flag .Usage ()
3342 }
34- filePath := args [0 ]
3543
44+ // construct list of files to upload
45+ filePaths := []string {}
46+ dir := "./"
47+ if * dirMode {
48+ dir = strings .TrimSuffix (strings .TrimSuffix (args [0 ], "/" ), "\\ " ) // trim trailing slashes
49+
50+ dirEntries , err := os .ReadDir (dir )
51+ if err != nil {
52+ fmt .Println ("Failed to read files in directory:" , err )
53+ os .Exit (1 )
54+ }
55+
56+ for _ , entry := range dirEntries {
57+ if ! entry .IsDir () {
58+ filePaths = append (filePaths , fmt .Sprintf ("%s/%s" , dir , entry .Name ()))
59+ }
60+ }
61+ } else {
62+ for _ , argPath := range args {
63+ filePaths = append (filePaths , argPath )
64+ }
65+ }
66+
67+ // upload files
68+ uploadedFiles := []uploadedFile {}
69+ for _ , filePath := range filePaths {
70+ responseBody , err := uploadFile (filePath , expires , secret )
71+ if err != nil {
72+ fmt .Println (err )
73+ os .Exit (1 )
74+ }
75+
76+ if responseBody != nil {
77+ upUrl := string (responseBody )
78+ upUrl = strings .TrimSuffix (strings .TrimSuffix (upUrl , "\n " ), "\r " )
79+
80+ uploadedFiles = append (uploadedFiles , uploadedFile {
81+ fileName : filepath .Base (filePath ),
82+ upUrl : upUrl ,
83+ })
84+ }
85+ }
86+
87+ if len (uploadedFiles ) == 1 {
88+ // original, single file upload
89+ upUrl := uploadedFiles [0 ].upUrl + "\n "
90+ fmt .Println (string (upUrl ))
91+ clipboard .Write (clipboard .FmtText , []byte (upUrl ))
92+ } else {
93+ // for multiple file upload
94+ printTblOutput (& uploadedFiles )
95+ logFile , err := writeOutputToFile (dir , & uploadedFiles )
96+ if err != nil {
97+ fmt .Println (err )
98+ os .Exit (1 )
99+ }
100+
101+ fmt .Println ("\n Log file saved:" , logFile )
102+ }
103+ }
104+
105+ func printTblOutput (uploadedFiles * []uploadedFile ) {
106+ tbl := table .New ("File" , "| 0x0 Url" )
107+ for _ , upFile := range * uploadedFiles {
108+ tbl .AddRow (upFile .fileName , "| " + upFile .upUrl )
109+ }
110+ tbl .Print ()
111+ }
112+
113+ func writeOutputToFile (dir string , uploadedFiles * []uploadedFile ) (logFile string , err error ) {
114+ logFile = fmt .Sprintf ("%s/%s.%d.log" , dir , "upload" , time .Now ().Unix ())
115+ f , err := os .Create (logFile )
116+ if err != nil {
117+ return "" , errors .New (fmt .Sprintf ("Failed to save output log file: %v" , err ))
118+ }
119+ defer f .Close ()
120+
121+ for _ , upFile := range * uploadedFiles {
122+ _ , err = f .WriteString (fmt .Sprintf ("%s: %s\r \n " , upFile .fileName , upFile .upUrl ))
123+ if err != nil {
124+ return "" , errors .New (fmt .Sprintf ("Failed to write to log file: %v" , err ))
125+ }
126+ }
127+
128+ f .Sync ()
129+
130+ return logFile , nil
131+ }
132+
133+ func uploadFile (filePath string , expires * int , secret * bool ) (responseBody []byte , err error ) {
36134 file , err := os .Open (filePath )
37135 if err != nil {
38- fmt .Println ("Failed to open file:" , err )
39- os .Exit (1 )
136+ return nil , errors .New (fmt .Sprintf ("Failed to open file: %v" , err ))
40137 }
41138 defer file .Close ()
42139
43140 body := & bytes.Buffer {}
44141 writer := multipart .NewWriter (body )
45142 part , err := writer .CreateFormFile ("file" , filepath .Base (filePath ))
46143 if err != nil {
47- fmt .Println ("Failed to create form file:" , err )
48- os .Exit (1 )
144+ return nil , errors .New (fmt .Sprintf ("Failed to create form file: %v" , err ))
49145 }
50146 io .Copy (part , file )
51147
@@ -62,33 +158,26 @@ func main() {
62158
63159 err = writer .Close ()
64160 if err != nil {
65- fmt .Println ("Failed to close multipart writer:" , err )
66- os .Exit (1 )
161+ return nil , errors .New (fmt .Sprintf ("Failed to close multipart writer: %v" , err ))
67162 }
68163
69164 request , err := http .NewRequest ("POST" , "https://0x0.st" , body )
70165 if err != nil {
71- fmt .Println ("Failed to create HTTP request:" , err )
72- os .Exit (1 )
166+ return nil , errors .New (fmt .Sprintf ("Failed to create HTTP request: %v" , err ))
73167 }
74168 request .Header .Set ("Content-Type" , writer .FormDataContentType ())
75169
76170 client := & http.Client {}
77171 response , err := client .Do (request )
78172 if err != nil {
79- fmt .Println ("Failed to send HTTP request:" , err )
80- os .Exit (1 )
173+ return nil , errors .New (fmt .Sprintf ("Failed to send HTTP request: %v" , err ))
81174 }
82175 defer response .Body .Close ()
83176
84- responseBody , err := ioutil .ReadAll (response .Body )
177+ responseBody , err = io .ReadAll (response .Body )
85178 if err != nil {
86- fmt .Println ("Failed to read response body:" , err )
87- os .Exit (1 )
179+ return nil , errors .New (fmt .Sprintf ("Failed to read response body: %v" , err ))
88180 }
89181
90- if responseBody != nil {
91- fmt .Println (string (responseBody ))
92- clipboard .Write (clipboard .FmtText , []byte (string (responseBody )))
93- }
182+ return responseBody , nil
94183}
0 commit comments