package client import ( "bytes" "concord.hectabit.org/Hectabit/burgerbackup/lib/common" "encoding/base64" "encoding/json" "errors" "golang.org/x/crypto/argon2" "io" "log" "mime/multipart" "net/http" "os" "strconv" ) func PerformBackup(fileLocation string, backupKey string, cryptoKey string, remoteURL string) (error, int) { fileContent, err := os.ReadFile(fileLocation) if err != nil { log.Println("[CRITICAL] Unknown in PerformBackup() file read:", err) return err, 0 } fileInfo, err := os.Stat(fileLocation) if err != nil { log.Println("[CRITICAL] Unknown in PerformBackup() file stat:", err) return err, 1 } filename := fileInfo.Name() content := map[string]interface{}{ "filename": filename, "content": base64.StdEncoding.EncodeToString(fileContent), } marshaledContent, err := json.Marshal(content) if err != nil { log.Println("[CRITICAL] Unknown in PerformBackup() content marshal:", err) return err, 2 } cryptoKeyHashed := argon2.IDKey([]byte(cryptoKey), []byte("burgerbackup"), 1, 64*1024, 4, 32) encryptedContent, err := common.EncryptAES(cryptoKeyHashed, marshaledContent) if err != nil { log.Println("[CRITICAL] Unknown in PerformBackup() content encryption", err) return err, 3 } encryptedFile := io.NopCloser(bytes.NewReader(encryptedContent)) err, errCode := SendFileToServer(encryptedFile, backupKey, remoteURL, filename) if err != nil { return err, errCode + 4 } log.Println("[INFO] Backup completed at:") return nil, -1 } func SendFileToServer(file io.Reader, backupKey string, remoteURL string, filename string) (error, int) { sendBody := &bytes.Buffer{} writer := multipart.NewWriter(sendBody) part, err := writer.CreateFormFile("file", filename) if err != nil { return err, 0 } _, err = io.Copy(part, file) if err != nil { return err, 1 } err = writer.Close() if err != nil { return err, 3 } req, err := http.NewRequest("POST", remoteURL, sendBody) if err != nil { return err, 4 } salt, err := common.GenSalt(16) hashedBackupKey, err := common.Hash(backupKey, salt) if err != nil { return err, 5 } req.Header.Set("Authorization", hashedBackupKey) req.Header.Set("Content-Type", writer.FormDataContentType()) req.Header.Set("Content-Length", strconv.Itoa(sendBody.Len())) client := &http.Client{} resp, err := client.Do(req) if err != nil { return err, 6 } defer func(Body io.ReadCloser) { err := Body.Close() if err != nil { log.Println("[ERROR] Error in sendFileToServer() response defer:", err) } }(resp.Body) body, err := io.ReadAll(resp.Body) if err != nil { return err, 7 } var response map[string]interface{} err = json.Unmarshal(body, &response) if err != nil { return err, 8 } if resp.StatusCode != 200 { err, ok := response["goErr"].(string) if !ok { err = "error not sent by server" } return errors.New(err), 9 } return nil, -1 }