diff --git a/handlers.go b/handlers.go index d0fc555..3241503 100644 --- a/handlers.go +++ b/handlers.go @@ -1,12 +1,17 @@ package main import ( + "archive/tar" + "compress/gzip" "context" + "crypto/md5" + "encoding/hex" "encoding/json" "fmt" "io" "net/http" "os" + "path/filepath" "strings" "time" @@ -411,3 +416,80 @@ func AuthMiddleware(next http.Handler) http.Handler { next.ServeHTTP(w, r) }) } + +func GetImageArchiveHandler(w http.ResponseWriter, r *http.Request) { + // Create a pipe to write the archive to + pr, pw := io.Pipe() + + // Create an MD5 hash writer + hash := md5.New() + + // Use a MultiWriter to write to both the pipe and the hash + multiWriter := io.MultiWriter(pw, hash) + + // Start a goroutine to create the archive + go func() { + defer pw.Close() + + gzipWriter := gzip.NewWriter(multiWriter) + defer gzipWriter.Close() + + tarWriter := tar.NewWriter(gzipWriter) + defer tarWriter.Close() + + err := filepath.Walk(config.ImageStorageDir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + header, err := tar.FileInfoHeader(info, info.Name()) + if err != nil { + return err + } + + relPath, err := filepath.Rel(config.ImageStorageDir, path) + if err != nil { + return err + } + header.Name = relPath + + if err := tarWriter.WriteHeader(header); err != nil { + return err + } + + if !info.IsDir() { + file, err := os.Open(path) + if err != nil { + return err + } + defer file.Close() + + _, err = io.Copy(tarWriter, file) + if err != nil { + return err + } + } + + return nil + }) + + if err != nil { + pw.CloseWithError(err) + } + }() + + // Set headers + w.Header().Set("Content-Type", "application/gzip") + w.Header().Set("Content-Disposition", "attachment; filename=images.tar.gz") + + // Copy the archive to the response writer + _, err := io.Copy(w, pr) + if err != nil { + http.Error(w, fmt.Sprintf("Error sending archive: %v", err), http.StatusInternalServerError) + return + } + + // Calculate and set the MD5 sum header + md5sum := hex.EncodeToString(hash.Sum(nil)) + w.Header().Set("X-Archive-MD5", md5sum) +} diff --git a/main.go b/main.go index 0866145..db4f744 100644 --- a/main.go +++ b/main.go @@ -88,6 +88,7 @@ func main() { managementRouter.Handle("/user/{id}", http.HandlerFunc(DeleteUserHandler)).Methods("DELETE", "OPTIONS") managementRouter.Handle("/db", http.HandlerFunc(BackupDatabaseHandler)).Methods("GET", "OPTIONS") managementRouter.Handle("/db", http.HandlerFunc(RestoreDatabaseHandler)).Methods("POST", "OPTIONS") + managementRouter.Handle("/imagearchive", http.HandlerFunc(GetImageArchiveHandler)).Methods("GET", "OPTIONS") // Apply CORS middleware c := cors.New(cors.Options{ diff --git a/scripts/ImageArchiveTest.bash b/scripts/ImageArchiveTest.bash new file mode 100644 index 0000000..f4be8d7 --- /dev/null +++ b/scripts/ImageArchiveTest.bash @@ -0,0 +1,73 @@ +#!/bin/bash + +# Set variables +SERVER_URL="http://localhost:8080" # Replace with your server URL +ENDPOINT="/admin/imagearchive" +OUTPUT_FILE="images.tar.gz" +EXTRACT_DIR="extracted_images" +USERNAME=boxuser +PASSWORD=boxuser + +AUTH_TOKEN=$(curl -s -X POST -H "Content-Type: application/json" \ +-d "{\"username\":\"$USERNAME\", \"password\":\"$PASSWORD\"}" \ +"$SERVER_URL/api/v1/login" | jq -r '.token') + +echo $AUTH_TOKEN + +# Function to check if a command exists +command_exists () { + type "$1" &> /dev/null ; +} + +# Check if required commands exist +if ! command_exists curl || ! command_exists md5sum || ! command_exists tar; then + echo "Error: This script requires curl, md5sum, and tar. Please install them and try again." + exit 1 +fi + +# Download the archive +echo "Downloading archive..." +HTTP_RESPONSE=$(curl -s -w "HTTPSTATUS:%{http_code}" -o "$OUTPUT_FILE" \ + -H "Authorization: Bearer $AUTH_TOKEN" \ + "$SERVER_URL/api/v1/login") +HTTP_BODY=$(echo $HTTP_RESPONSE | sed -e 's/HTTPSTATUS\:.*//g') +HTTP_STATUS=$(echo $HTTP_RESPONSE | tr -d '\n' | sed -e 's/.*HTTPSTATUS://') + +if [ $HTTP_STATUS -ne 200 ]; then + echo "Error: HTTP Status $HTTP_STATUS" + echo "Response: $HTTP_BODY" + exit 1 +fi + +# Get MD5 sum from header +HEADER_MD5=$(curl -sI -H "Authorization: Bearer $AUTH_TOKEN" "$SERVER_URL$ENDPOINT" | grep X-Archive-MD5 | cut -d' ' -f2 | tr -d '\r') + +# Calculate MD5 sum of downloaded file +CALCULATED_MD5=$(md5sum "$OUTPUT_FILE" | cut -d' ' -f1) + +echo "MD5 from header: $HEADER_MD5" +echo "Calculated MD5: $CALCULATED_MD5" + +# Compare MD5 sums +if [ "$HEADER_MD5" = "$CALCULATED_MD5" ]; then + echo "MD5 sums match. File integrity verified." +else + echo "MD5 sums do not match. File may be corrupted." + exit 1 +fi + +# Extract the archive +echo "Extracting archive..." +mkdir -p "$EXTRACT_DIR" +tar -xzvf "$OUTPUT_FILE" -C "$EXTRACT_DIR" + +# List contents of extracted directory +echo "Contents of extracted archive:" +find "$EXTRACT_DIR" -type f | sed "s|$EXTRACT_DIR/||" + +# Clean up +echo "Cleaning up..." +rm "$OUTPUT_FILE" +rm -r "$EXTRACT_DIR" + +echo "Test completed successfully." \ No newline at end of file diff --git a/scripts/getusers.bash b/scripts/getusers.bash index 3440108..97bface 100644 --- a/scripts/getusers.bash +++ b/scripts/getusers.bash @@ -1,7 +1,7 @@ #!/bin/bash # API base URL -API_BASE_URL="http://localhost:8080" +API_BASE_URL="http://localhost:8080/api/v1" # Login credentials USERNAME="boxuser" @@ -15,4 +15,4 @@ TOKEN=$(curl -s -X POST -H "Content-Type: application/json" \ curl -X GET \ $API_BASE_URL/admin/user \ -H "Authorization: Bearer $TOKEN" \ - -H "Content-Type: application/json" \ No newline at end of file + -H "Content-Type: application/json" diff --git a/scripts/images.tar.gz b/scripts/images.tar.gz new file mode 100644 index 0000000..834a5f3 --- /dev/null +++ b/scripts/images.tar.gz @@ -0,0 +1 @@ +404 page not found