-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
224 lines (194 loc) · 7.21 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"strconv"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"github.com/minoplhy/chibisafe-netproxy/src/handler"
)
func uploadHandler(w http.ResponseWriter, r *http.Request) {
// Check is already done in main()
Chibisafe_basepath := os.Getenv("CHIBISAFE_BASEPATH")
// Max Upload Size
// if Enviroment is failed, will fallback to 10MB
GetMaxUploadSize := os.Getenv("MAX_UPLOAD_SIZE")
maxUploadSize, err := strconv.Atoi(GetMaxUploadSize)
if err != nil {
maxUploadSize = 10 * 1024 * 1024 // 10 MB
}
if r.Method != "POST" {
handler.ErrorResponseBuild(w, http.StatusMethodNotAllowed, "Method not allowed")
handler.ErrorLogBuilder([]string{r.RemoteAddr}, "Method not allowed")
return
}
// Check for x-api-key header
API_Key := r.Header.Get("x-api-key")
if API_Key == "" {
handler.ErrorResponseBuild(w, http.StatusBadRequest, "X-api-key is empty!")
handler.ErrorLogBuilder([]string{r.RemoteAddr}, "X-api-key is empty!")
return
}
// Validate x-api-key
if !handler.Check_API_Key(Chibisafe_basepath, API_Key) {
handler.ErrorResponseBuild(w, http.StatusUnauthorized, "Failure to validate X-API-Key")
handler.ErrorLogBuilder([]string{r.RemoteAddr}, "Failure to validate X-API-Key")
return
}
// Set Max Body read size
r.Body = http.MaxBytesReader(w, r.Body, int64(maxUploadSize))
// truncated for brevity
// The argument to FormFile must match the name attribute
// of the file input on the frontend
file, fileHeader, err := r.FormFile("file")
if err != nil {
switch err.Error() {
case "http: request body too large":
handler.ErrorResponseBuild(w, http.StatusRequestEntityTooLarge, "Request Body is too large!")
handler.ErrorLogBuilder([]string{r.RemoteAddr}, "Request Body is too large!")
default:
handler.ErrorResponseBuild(w, http.StatusInternalServerError, "Something went wrong!")
handler.ErrorLogBuilder([]string{r.RemoteAddr}, err.Error())
}
return
}
defer file.Close()
handler.InfoLogBuilder([]string{r.RemoteAddr}, "Received a successful POST")
tempfilepath := handler.GetTempFilename(fileHeader.Filename)
handler.InfoLogBuilder([]string{r.RemoteAddr, tempfilepath}, "Successfully obtained temporary Filename")
// Save Temporary file
handler.SaveFile(tempfilepath, file)
PostData := handler.UploadPostMeta{
ContentType: fileHeader.Header.Get("Content-Type"),
Name: fileHeader.Filename,
FileSize: fileHeader.Size,
}
UploadHeaders := map[string]string{
"X-Api-Key": API_Key,
"Content-Type": "application/json",
}
// Check if client sent X-Real-IP Header
if r.Header.Get("X-Real-IP") != "" && handler.IsInternalIP(r.RemoteAddr) {
UploadHeaders["X-Real-IP"] = r.Header.Get("X-Real-IP")
}
// POST to chibisafe's /api/upload
chibisafe_post, err := handler.UploadPost(Chibisafe_basepath, UploadHeaders, PostData)
if err != nil {
switch err.Error() {
default:
handler.ErrorResponseBuild(w, http.StatusBadRequest, "Something went wrong!")
handler.ErrorLogBuilder([]string{r.RemoteAddr, tempfilepath}, err.Error())
}
return
}
var chibisafe_Response_Metadata handler.UploadResponseMeta
err = json.Unmarshal(chibisafe_post, &chibisafe_Response_Metadata)
if err != nil {
switch err.Error() {
default:
handler.ErrorResponseBuild(w, http.StatusInternalServerError, "Something went wrong!")
handler.ErrorLogBuilder([]string{}, err.Error())
}
return
}
handler.InfoLogBuilder([]string{r.RemoteAddr, chibisafe_Response_Metadata.Identifier, tempfilepath}, "Successfully obtained PUT keys")
// PUT File to Network Storage
_, err = handler.NetworkStoragePut(chibisafe_Response_Metadata.URL, PostData.ContentType, tempfilepath)
if err != nil {
switch err.Error() {
default:
handler.ErrorResponseBuild(w, http.StatusInternalServerError, "Something went wrong!")
handler.ErrorLogBuilder([]string{r.RemoteAddr, chibisafe_Response_Metadata.Identifier, tempfilepath}, err.Error())
}
return
}
handler.InfoLogBuilder([]string{r.RemoteAddr, chibisafe_Response_Metadata.Identifier, tempfilepath}, "Successfully PUT file to Network Storage")
// Build Struct for PostProcess Json
//
// Name -> original Filename
// ContentType -> original Content-Type
// Identifier -> File Identifier ID
PostProcessData := handler.UploadProcessMeta{
Name: fileHeader.Filename,
ContentType: fileHeader.Header.Get("Content-Type"),
Identifier: chibisafe_Response_Metadata.Identifier,
}
ProcessHeaders := map[string]string{
"X-Api-Key": API_Key,
"Content-Type": "application/json",
}
// Check if client sent X-Real-IP Header
if r.Header.Get("X-Real-IP") != "" && handler.IsInternalIP(r.RemoteAddr) {
ProcessHeaders["X-Real-IP"] = r.Header.Get("X-Real-IP")
}
// POST to chibisafe's /api/upload/process
PostProcess, err := handler.UploadProcessPost(Chibisafe_basepath, ProcessHeaders, PostProcessData)
if err != nil {
switch err.Error() {
default:
handler.ErrorResponseBuild(w, http.StatusInternalServerError, "Something went wrong!")
handler.ErrorLogBuilder([]string{r.RemoteAddr, chibisafe_Response_Metadata.Identifier, tempfilepath}, err.Error())
}
return
}
var PostProcessResponse handler.UploadProcessResponseMeta
err = json.Unmarshal(PostProcess, &PostProcessResponse)
if err != nil {
switch err.Error() {
default:
handler.ErrorResponseBuild(w, http.StatusInternalServerError, "Something went wrong!")
handler.ErrorLogBuilder([]string{}, err.Error())
}
return
}
handler.InfoLogBuilder([]string{r.RemoteAddr, PostProcessResponse.Name, tempfilepath}, fmt.Sprintf("Successfully Processed Response with UUID: %s", PostProcessResponse.UUID))
// Delete Temporary file
err = handler.DeleteFile(tempfilepath)
if err != nil {
switch err.Error() {
default:
handler.ErrorLogBuilder([]string{r.RemoteAddr, chibisafe_Response_Metadata.Identifier, tempfilepath}, err.Error())
}
return
}
handler.InfoLogBuilder([]string{r.RemoteAddr, tempfilepath}, "Successfully Deleted Temporary file from local disk")
// Response JSON to client
JsonResponse, _ := json.Marshal(PostProcessResponse)
handler.ResponseBuild(w, "application/json", JsonResponse)
}
func main() {
// Open or create a file for appending logs
log_file, err := os.OpenFile("activity.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
log.Fatal().Msg(err.Error())
}
defer log_file.Close()
// Setup Logging Policy
// Multi level writer on logfile and console
//
// Format : Console -> Human Readable
// File -> Json
logger := zerolog.New(zerolog.MultiLevelWriter(log_file, os.Stdout)).With().Timestamp().Logger()
logger = logger.Output(io.MultiWriter(zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: "15:04:05"}, log_file))
// Set as Global logger :)
log.Logger = logger
Chibisafe_basepath := os.Getenv("CHIBISAFE_BASEPATH")
Max_Upload_Size := os.Getenv("MAX_UPLOAD_SIZE")
if Chibisafe_basepath == "" {
log.Fatal().Msg("CHIBISAFE_BASEPATH environment is not set!")
}
if Max_Upload_Size != "" {
_, err := strconv.Atoi(Max_Upload_Size)
if err != nil {
log.Fatal().Msg("MAX_UPLOAD_SIZE environment is invaild!")
}
}
mux := http.NewServeMux()
mux.HandleFunc("/api/v1/upload", uploadHandler)
if err := http.ListenAndServe(":4040", mux); err != nil {
log.Fatal().Msg(err.Error())
}
}