125 lines
2.8 KiB
Go
125 lines
2.8 KiB
Go
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
|
|
}
|