diff --git a/docker-compose.yml b/docker-compose.yml index 98bff6f..d6ee74e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,3 +9,4 @@ services: - .:/app environment: - CHIBISAFE_BASEPATH= + - MAX_UPLOAD_SIZE= diff --git a/main.go b/main.go index 1c3d97b..3a228ba 100644 --- a/main.go +++ b/main.go @@ -6,6 +6,7 @@ import ( "log" "net/http" "os" + "strconv" "github.com/minoplhy/chibisafe_netstorage_middleman/src/handler" ) @@ -13,6 +14,13 @@ import ( 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 + } // 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) @@ -23,7 +31,7 @@ func uploadHandler(w http.ResponseWriter, r *http.Request) { log.SetOutput(log_file) if r.Method != "POST" { - http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) + http.Error(w, handler.ErrorResponseBuild(http.StatusMethodNotAllowed, "Method not allowed"), http.StatusMethodNotAllowed) log.Printf("[%s] : Method not allowed", r.RemoteAddr) return } @@ -31,24 +39,30 @@ func uploadHandler(w http.ResponseWriter, r *http.Request) { // Check for x-api-key header API_Key := r.Header.Get("x-api-key") if API_Key == "" { - http.Error(w, "X-api-key is empty!", http.StatusBadRequest) + http.Error(w, handler.ErrorResponseBuild(http.StatusBadRequest, "X-api-key is empty!"), http.StatusBadRequest) log.Printf("[%s] : X-api-key is empty!", r.RemoteAddr) return } - // Set a limit on the request body size - maxUploadSize := 10 * 1024 * 1024 // 10 MB + // Validate x-api-key + if !handler.Check_API_Key(Chibisafe_basepath, API_Key) { + http.Error(w, handler.ErrorResponseBuild(http.StatusUnauthorized, "Failure to validate X-API-Key"), http.StatusUnauthorized) + log.Printf("[%s] : Failue to validate X-API-Key", r.RemoteAddr) + return + } + r.Body = http.MaxBytesReader(w, r.Body, int64(maxUploadSize)) // ParseMultipartForm parses a request body as multipart/form-data err = r.ParseMultipartForm(int64(maxUploadSize)) if err != nil { if err.Error() == "http: request body too large" { - http.Error(w, "File too large.", http.StatusRequestEntityTooLarge) - log.Printf("[%s] : Request Body is too large!", r.RemoteAddr) + http.Error(w, handler.ErrorResponseBuild(http.StatusRequestEntityTooLarge, "Request Body is too large!"), http.StatusRequestEntityTooLarge) + log.Printf("[ERROR] [%s] : Request Body is too large!", r.RemoteAddr) return } - http.Error(w, err.Error(), http.StatusInternalServerError) + http.Error(w, handler.ErrorResponseBuild(http.StatusInternalServerError, "Something went wrong!"), http.StatusInternalServerError) + log.Printf("[ERROR] [%s] : %s", r.RemoteAddr, err) return } @@ -58,8 +72,8 @@ func uploadHandler(w http.ResponseWriter, r *http.Request) { // of the file input on the frontend file, fileHeader, err := r.FormFile("file") if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - log.Printf("[%s] : %s", r.RemoteAddr, err) + http.Error(w, handler.ErrorResponseBuild(http.StatusInternalServerError, "Something went wrong!"), http.StatusInternalServerError) + log.Printf("[ERROR] [%s] : %s", r.RemoteAddr, err) return } defer file.Close() @@ -78,23 +92,24 @@ func uploadHandler(w http.ResponseWriter, r *http.Request) { chibisafe_post, err := handler.UploadPost(Chibisafe_basepath, PostData, API_Key) if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - log.Printf("[%s] [%s] : %s", r.RemoteAddr, tempfilepath, err) + http.Error(w, handler.ErrorResponseBuild(http.StatusBadRequest, "Something went wrong!"), http.StatusBadRequest) + log.Printf("[ERROR] [%s] [%s] : %s", r.RemoteAddr, tempfilepath, err) return } var chibisafe_Response_Metadata handler.UploadResponseMeta err = json.Unmarshal(chibisafe_post, &chibisafe_Response_Metadata) if err != nil { - log.Print(err) + http.Error(w, handler.ErrorResponseBuild(http.StatusInternalServerError, "Something went wrong!"), http.StatusInternalServerError) + log.Printf("[ERROR] %s", err) return } log.Printf("[%s] [%s] [%s] : Successfully obtained PUT keys", r.RemoteAddr, chibisafe_Response_Metadata.Identifier, tempfilepath) _, err = handler.NetworkStoragePut(chibisafe_Response_Metadata.URL, PostData.ContentType, tempfilepath) if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - log.Printf("[%s] [%s] [%s] : %s", r.RemoteAddr, chibisafe_Response_Metadata.Identifier, tempfilepath, err) + http.Error(w, handler.ErrorResponseBuild(http.StatusInternalServerError, "Something went wrong!"), http.StatusInternalServerError) + log.Printf("[ERROR] [%s] [%s] [%s] : %s", r.RemoteAddr, chibisafe_Response_Metadata.Identifier, tempfilepath, err) return } log.Printf("[%s] [%s] [%s] : Successfully PUT file to Network Storage", r.RemoteAddr, chibisafe_Response_Metadata.Identifier, tempfilepath) @@ -107,22 +122,23 @@ func uploadHandler(w http.ResponseWriter, r *http.Request) { PostProcess, err := handler.UploadProcessPost(Chibisafe_basepath, PostData.ContentType, chibisafe_Response_Metadata.Identifier, API_Key, PostProcessData) if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - log.Printf("[%s] [%s] [%s] : %s", r.RemoteAddr, chibisafe_Response_Metadata.Identifier, tempfilepath, err) + http.Error(w, handler.ErrorResponseBuild(http.StatusInternalServerError, "Something went wrong!"), http.StatusInternalServerError) + log.Printf("[ERROR] [%s] [%s] [%s] : %s", r.RemoteAddr, chibisafe_Response_Metadata.Identifier, tempfilepath, err) return } var PostProcessResponse handler.UploadProcessResponseMeta err = json.Unmarshal(PostProcess, &PostProcessResponse) if err != nil { - log.Print(err) + http.Error(w, handler.ErrorResponseBuild(http.StatusInternalServerError, "Something went wrong!"), http.StatusInternalServerError) + log.Printf("[ERROR] %s", err) return } log.Printf("[%s] [%s] [%s] : Successfully Processed Response with UUID: %s", r.RemoteAddr, PostProcessResponse.Name, tempfilepath, PostProcessResponse.UUID) err = handler.DeleteFile(tempfilepath) if err != nil { - log.Printf("[%s] [%s] [%s] : %s", r.RemoteAddr, chibisafe_Response_Metadata.Identifier, tempfilepath, err) + log.Printf("[ERROR] [%s] [%s] [%s] : %s", r.RemoteAddr, chibisafe_Response_Metadata.Identifier, tempfilepath, err) return } log.Printf("[%s] [%s] : Successfully Deleted Temporary file from local disk", r.RemoteAddr, tempfilepath) @@ -132,10 +148,17 @@ func uploadHandler(w http.ResponseWriter, r *http.Request) { func main() { Chibisafe_basepath := os.Getenv("CHIBISAFE_BASEPATH") + Max_Upload_Size := os.Getenv("MAX_UPLOAD_SIZE") if Chibisafe_basepath == "" { log.Fatal("CHIBISAFE_BASEPATH environment is not set!") } + if Max_Upload_Size != "" { + _, err := strconv.Atoi(Max_Upload_Size) + if err != nil { + log.Fatal("MAX_UPLOAD_SIZE environment is invaild!") + } + } mux := http.NewServeMux() mux.HandleFunc("/api/v1/upload", uploadHandler) diff --git a/src/handler/chibisafe.go b/src/handler/chibisafe.go index b205302..fc3360e 100644 --- a/src/handler/chibisafe.go +++ b/src/handler/chibisafe.go @@ -8,6 +8,25 @@ import ( "os" ) +func Check_API_Key(Basepath string, accessKey string) bool { + URL := Basepath + "/api/user/me" + headers := map[string]string{ + "X-Api-Key": accessKey, + } + GETStruct := URLRequest{ + URL: URL, + Header: headers, + Method: "GET", + } + resp, err := HTTPNoData(GETStruct) + if err != nil { + return false + } + defer resp.Body.Close() + + return resp.StatusCode == http.StatusOK +} + func UploadPost(BasePath string, PostData UploadPostMeta, accessKey string) ([]byte, error) { URL := BasePath + "/api/upload" // Convert PostData to JSON diff --git a/src/handler/httpdo.go b/src/handler/httpdo.go index 04ad5d5..656ec76 100644 --- a/src/handler/httpdo.go +++ b/src/handler/httpdo.go @@ -51,6 +51,24 @@ func HTTPOSFile(RequestStruct URLRequest, RequestData *os.File) (*http.Response, return resp, nil } +// HTTP With no Data sent +func HTTPNoData(RequestStruct URLRequest) (*http.Response, error) { + req, err := http.NewRequest(RequestStruct.Method, RequestStruct.URL, nil) + if err != nil { + return nil, err + } + + for key, value := range RequestStruct.Header { + req.Header.Set(key, value) + } + + resp, err := HTTPClientDo(req) + if err != nil { + return nil, err + } + return resp, nil +} + func HTTPClientDo(Request *http.Request) (*http.Response, error) { client := &http.Client{} response, err := client.Do(Request) diff --git a/src/handler/struct.go b/src/handler/struct.go index 826de80..56d93b4 100644 --- a/src/handler/struct.go +++ b/src/handler/struct.go @@ -31,3 +31,8 @@ type URLRequest struct { ContentLength *int Header map[string]string } + +type ErrorResponse struct { + StatusCode int64 + Message string +} diff --git a/src/handler/templates.go b/src/handler/templates.go new file mode 100644 index 0000000..b3a99d8 --- /dev/null +++ b/src/handler/templates.go @@ -0,0 +1,12 @@ +package handler + +import "encoding/json" + +func ErrorResponseBuild(StatusCode int64, Message string) string { + ErrorResponse := ErrorResponse{ + StatusCode: StatusCode, + Message: Message, + } + Response, _ := json.Marshal(ErrorResponse) + return string(Response) +}