Skip to content

Commit 31d1693

Browse files
committed
Parsing of flags, refactoring, better output
1 parent d2aeaf5 commit 31d1693

File tree

3 files changed

+190
-70
lines changed

3 files changed

+190
-70
lines changed

cmd/cli-uploader/Main.go

Lines changed: 21 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,46 @@
11
package main
22

33
import (
4+
"encoding/json"
45
"fmt"
56
"github.com/forceu/gokapi/cmd/cli-uploader/cliapi"
67
"github.com/forceu/gokapi/cmd/cli-uploader/cliconfig"
8+
"github.com/forceu/gokapi/cmd/cli-uploader/cliflags"
79
"os"
810
)
911

10-
const (
11-
paramLogin = "login"
12-
paramLogout = "logout"
13-
)
14-
1512
func main() {
16-
17-
if len(os.Args) < 2 {
18-
fmt.Println("Valid options are:")
19-
fmt.Println(" gokapi-cli login")
20-
fmt.Println(" gokapi-cli logout")
21-
fmt.Println(" gokapi-cli upload [file to upload]")
22-
os.Exit(1)
23-
}
24-
switch os.Args[1] {
25-
case "login":
13+
mode := cliflags.Parse()
14+
switch mode {
15+
case cliflags.ModeLogin:
2616
cliconfig.CreateLogin()
27-
case "logout":
17+
case cliflags.ModeLogout:
2818
doLogout()
29-
case "upload":
19+
case cliflags.ModeUpload:
3020
processUpload()
31-
default:
32-
printUsage()
21+
case cliflags.ModeInvalid:
22+
os.Exit(3)
3323
}
3424
}
3525

3626
func processUpload() {
3727
cliconfig.Load()
38-
if len(os.Args) < 3 {
39-
fmt.Println("ERROR: Missing parameter file to upload")
40-
printUsage()
41-
os.Exit(1)
42-
}
43-
file, err := os.OpenFile(os.Args[2], os.O_RDONLY, 0664)
44-
if err != nil {
45-
fmt.Println("ERROR: Could not open file to upload")
46-
fmt.Println(err)
47-
os.Exit(2)
48-
}
49-
result, err := cliapi.UploadFile(file)
28+
uploadParam := cliflags.GetUploadParameters()
29+
30+
result, err := cliapi.UploadFile(uploadParam)
5031
if err != nil {
5132
fmt.Println("ERROR: Could not upload file")
5233
fmt.Println(err)
53-
os.Exit(3)
34+
os.Exit(1)
35+
}
36+
if uploadParam.JsonOutput {
37+
jsonStr, _ := json.Marshal(result)
38+
fmt.Println(string(jsonStr))
39+
} else {
40+
fmt.Println("File uploaded successfully")
41+
fmt.Println("File ID: " + result.Id)
42+
fmt.Println("File Download URL: " + result.UrlDownload)
5443
}
55-
fmt.Println(result)
56-
}
57-
58-
func printUsage() {
59-
fmt.Println("Valid options are:")
60-
fmt.Println(" gokapi-cli login")
61-
fmt.Println(" gokapi-cli logout")
62-
fmt.Println(" gokapi-cli upload")
63-
os.Exit(1)
6444
}
6545

6646
func doLogout() {

cmd/cli-uploader/cliapi/cliapi.go

Lines changed: 59 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"encoding/json"
77
"errors"
88
"fmt"
9+
"github.com/forceu/gokapi/cmd/cli-uploader/cliflags"
910
"github.com/forceu/gokapi/internal/encryption"
1011
"github.com/forceu/gokapi/internal/encryption/end2end"
1112
"github.com/forceu/gokapi/internal/helper"
@@ -106,68 +107,83 @@ func getUrl(url string, headers []header) (string, error) {
106107
return string(body), nil
107108
}
108109

109-
func UploadFile(f *os.File) (string, error) {
110+
func UploadFile(uploadParams cliflags.UploadConfig) (models.FileApiOutput, error) {
111+
file, err := os.OpenFile(uploadParams.File, os.O_RDONLY, 0664)
112+
if err != nil {
113+
fmt.Println("ERROR: Could not open file to upload")
114+
fmt.Println(err)
115+
os.Exit(4)
116+
}
110117
maxSize, chunkSize, isE2e, err := GetConfig()
111-
// TODO check for 401
112118
if err != nil {
113-
return "", err
119+
return models.FileApiOutput{}, err
114120
}
115-
if len(e2eKey) == 0 {
121+
// TODO check for 401
122+
123+
if len(e2eKey) == 0 || !isE2e || uploadParams.DisableE2e {
116124
isE2e = false
117125
}
118-
fi, err := f.Stat()
126+
fileStat, err := file.Stat()
119127
if err != nil {
120-
return "", err
128+
return models.FileApiOutput{}, err
121129
}
122-
sizeBytes := fi.Size()
123-
realSize := fi.Size()
130+
sizeBytes := fileStat.Size()
131+
realSize := fileStat.Size()
124132
if isE2e {
125133
sizeBytes = encryption.CalculateEncryptedFilesize(sizeBytes)
126134
}
127135
if sizeBytes > int64(maxSize)*megaByte {
128-
return "", EFileTooBig
136+
return models.FileApiOutput{}, EFileTooBig
129137
}
130138
uuid := helper.GenerateRandomString(30)
131139

132140
if isE2e {
133141
cipher, err := encryption.GetRandomCipher()
134142
if err != nil {
135-
return "", err
143+
return models.FileApiOutput{}, err
136144
}
137-
stream, err := encryption.GetEncryptReader(cipher, f)
145+
stream, err := encryption.GetEncryptReader(cipher, file)
138146
if err != nil {
139-
return "", err
147+
return models.FileApiOutput{}, err
140148
}
141149
for i := int64(0); i < sizeBytes; i = i + (int64(chunkSize) * megaByte) {
142150
err = uploadChunk(stream, uuid, i, int64(chunkSize)*megaByte, sizeBytes)
143151
if err != nil {
144-
return "", err
152+
return models.FileApiOutput{}, err
145153
}
146154
}
147-
file, err := completeChunk(uuid, "Encrypted File", sizeBytes, realSize, true)
155+
metaData, err := completeChunk(uuid, "Encrypted File", sizeBytes, realSize, true, uploadParams)
148156
if err != nil {
149-
return "", err
157+
return models.FileApiOutput{}, err
150158
}
151-
err = addE2EFileInfo(models.E2EFile{
159+
160+
e2eFile := models.E2EFile{
152161
Uuid: uuid,
153-
Id: file.Id,
154-
Filename: getFileName(f),
162+
Id: metaData.Id,
163+
Filename: getFileName(file),
155164
Cipher: cipher,
156-
})
157-
return file.Id, err
165+
}
166+
err = addE2EFileInfo(e2eFile)
167+
if err != nil {
168+
return models.FileApiOutput{}, err
169+
}
170+
hashContent, err := getHashContent(e2eFile)
171+
metaData.UrlDownload = metaData.UrlDownload + "#" + hashContent
172+
metaData.Name = getFileName(file)
173+
return metaData, err
158174
}
159175

160176
for i := int64(0); i < sizeBytes; i = i + (int64(chunkSize) * megaByte) {
161-
err = uploadChunk(f, uuid, i, int64(chunkSize)*megaByte, sizeBytes)
177+
err = uploadChunk(file, uuid, i, int64(chunkSize)*megaByte, sizeBytes)
162178
if err != nil {
163-
return "", err
179+
return models.FileApiOutput{}, err
164180
}
165181
}
166-
file, err := completeChunk(uuid, nameToBase64(f), sizeBytes, realSize, false)
182+
metaData, err := completeChunk(uuid, nameToBase64(file), sizeBytes, realSize, false, uploadParams)
167183
if err != nil {
168-
return "", err
184+
return models.FileApiOutput{}, err
169185
}
170-
return file.Id, nil
186+
return metaData, nil
171187
}
172188

173189
func nameToBase64(f *os.File) string {
@@ -237,24 +253,28 @@ func uploadChunk(f io.Reader, uuid string, offset, chunkSize, filesize int64) er
237253
return nil
238254
}
239255

240-
func completeChunk(uid, filename string, filesize, realsize int64, useE2e bool) (models.File, error) {
256+
func completeChunk(uid, filename string, filesize, realsize int64, useE2e bool, uploadParams cliflags.UploadConfig) (models.FileApiOutput, error) {
241257
type expectedFormat struct {
242-
FileInfo models.File `json:"FileInfo"`
258+
FileInfo models.FileApiOutput `json:"FileInfo"`
243259
}
244260
result, err := getUrl(gokapiUrl+"/chunk/complete", []header{
245261
{"uuid", uid},
246262
{"filename", filename},
247263
{"filesize", strconv.FormatInt(filesize, 10)},
248264
{"realsize", strconv.FormatInt(realsize, 10)},
249265
{"isE2E", strconv.FormatBool(useE2e)},
266+
{"allowedDownloads", strconv.Itoa(uploadParams.ExpiryDownloads)},
267+
{"expiryDays", strconv.Itoa(uploadParams.ExpiryDays)},
268+
{"password", uploadParams.Password},
269+
{"contenttype", "application/octet-stream"}, // TODO
250270
})
251271
if err != nil {
252-
return models.File{}, err
272+
return models.FileApiOutput{}, err
253273
}
254274
var parsedResult expectedFormat
255275
err = json.Unmarshal([]byte(result), &parsedResult)
256276
if err != nil {
257-
return models.File{}, err
277+
return models.FileApiOutput{}, err
258278
}
259279
return parsedResult.FileInfo, nil
260280
}
@@ -321,5 +341,15 @@ func setE2eInfo(input models.E2EInfoEncrypted) error {
321341
}
322342
_ = resp.Body.Close()
323343
return nil
344+
}
324345

346+
func getHashContent(input models.E2EFile) (string, error) {
347+
output, err := json.Marshal(models.E2EHashContent{
348+
Filename: input.Filename,
349+
Cipher: base64.StdEncoding.EncodeToString(input.Cipher),
350+
})
351+
if err != nil {
352+
return "", err
353+
}
354+
return base64.StdEncoding.EncodeToString(output), nil
325355
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
package cliflags
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"strconv"
7+
)
8+
9+
const (
10+
ModeLogin = iota
11+
ModeLogout
12+
ModeUpload
13+
ModeInvalid
14+
)
15+
16+
type UploadConfig struct {
17+
File string
18+
JsonOutput bool
19+
DisableE2e bool
20+
ExpiryDays int
21+
ExpiryDownloads int
22+
Password string
23+
}
24+
25+
func Parse() int {
26+
if len(os.Args) < 2 {
27+
printUsage()
28+
return ModeInvalid
29+
}
30+
switch os.Args[1] {
31+
case "login":
32+
return ModeLogin
33+
case "logout":
34+
return ModeLogout
35+
case "upload":
36+
return ModeUpload
37+
default:
38+
printUsage()
39+
return ModeInvalid
40+
}
41+
}
42+
43+
func GetUploadParameters() UploadConfig {
44+
result := UploadConfig{}
45+
for i := 2; i < len(os.Args); i++ {
46+
switch os.Args[i] {
47+
case "--json":
48+
result.JsonOutput = true
49+
case "--disable-e2e":
50+
result.DisableE2e = true
51+
case "--file":
52+
result.File = getParameter(&i)
53+
case "--expiry-days":
54+
result.ExpiryDays = requireInt(getParameter(&i))
55+
case "--expiry-downloads":
56+
result.ExpiryDownloads = requireInt(getParameter(&i))
57+
case "--password":
58+
result.Password = getParameter(&i)
59+
}
60+
}
61+
if result.File == "" {
62+
fmt.Println("ERROR: Missing parameter --file")
63+
os.Exit(2)
64+
}
65+
if result.ExpiryDownloads < 0 {
66+
result.ExpiryDownloads = 0
67+
}
68+
if result.ExpiryDays < 0 {
69+
result.ExpiryDays = 0
70+
}
71+
return result
72+
}
73+
74+
func getParameter(position *int) string {
75+
newPosition := *position + 1
76+
position = &newPosition
77+
if newPosition >= len(os.Args) {
78+
printUsage()
79+
os.Exit(3)
80+
}
81+
return os.Args[newPosition]
82+
}
83+
84+
func requireInt(input string) int {
85+
result, err := strconv.Atoi(input)
86+
if err != nil {
87+
fmt.Println("ERROR: " + input + " is not a valid integer")
88+
os.Exit(2)
89+
}
90+
return result
91+
}
92+
93+
func printUsage() {
94+
fmt.Println("Gokapi CLI")
95+
fmt.Println()
96+
fmt.Println("Valid options are:")
97+
fmt.Println(" gokapi-cli login")
98+
fmt.Println(" gokapi-cli logout")
99+
fmt.Println(" gokapi-cli upload --file /file/to/upload [--json] [--disable-e2e]\n" +
100+
" [--expiry-days INT] [--expiry-downloads INT]\n" +
101+
" [--password STRING] ")
102+
fmt.Println()
103+
fmt.Println("gokapi-cli upload:")
104+
fmt.Println("--json Outputs the result as JSON only")
105+
fmt.Println("--disable-e2e Disables end-to-end encryption")
106+
fmt.Println("--expiry-days Sets the expiry date of the file in days, otherwise unlimited")
107+
fmt.Println("--expiry-downloads Sets the allowed downloads, otherwise unlimited")
108+
fmt.Println("--password Sets a password")
109+
os.Exit(3)
110+
}

0 commit comments

Comments
 (0)