feat: implement cross-protocol checksum verification for file transfers

This commit is contained in:
2026-06-09 14:38:46 +01:00
parent 715c4eccb6
commit 93ad8c9321
13 changed files with 171 additions and 14 deletions
+15
View File
@@ -1,7 +1,9 @@
package ftp
import (
"crypto/md5"
"crypto/tls"
"encoding/hex"
"fmt"
"io"
"path/filepath"
@@ -177,3 +179,16 @@ func (e *FTPExplorer) ReadFile(path string) (io.ReadCloser, error) {
func (e *FTPExplorer) WriteFile(path string, r io.Reader, size int64) error {
return e.client.Stor(path, r)
}
func (e *FTPExplorer) Checksum(path string) (string, error) {
r, err := e.ReadFile(path)
if err != nil {
return "", err
}
defer r.Close()
h := md5.New()
if _, err := io.Copy(h, r); err != nil {
return "", err
}
return hex.EncodeToString(h.Sum(nil)), nil
}
+15
View File
@@ -1,6 +1,8 @@
package local
import (
"crypto/md5"
"encoding/hex"
"io"
"os"
"path/filepath"
@@ -82,6 +84,19 @@ func (e *LocalExplorer) Rename(src, dst string) error {
return os.Rename(src, dst)
}
func (e *LocalExplorer) Checksum(path string) (string, error) {
r, err := e.ReadFile(path)
if err != nil {
return "", err
}
defer r.Close()
h := md5.New()
if _, err := io.Copy(h, r); err != nil {
return "", err
}
return hex.EncodeToString(h.Sum(nil)), nil
}
func (e *LocalExplorer) ReadFile(path string) (io.ReadCloser, error) {
return os.Open(path)
}
+15
View File
@@ -3,6 +3,8 @@
package nfs
import (
"crypto/md5"
"encoding/hex"
"fmt"
"io"
"path/filepath"
@@ -125,3 +127,16 @@ func (e *NFSExplorer) WriteFile(path string, r io.Reader, size int64) error {
_, err = io.Copy(f, r)
return err
}
func (e *NFSExplorer) Checksum(path string) (string, error) {
r, err := e.ReadFile(path)
if err != nil {
return "", err
}
defer r.Close()
h := md5.New()
if _, err := io.Copy(h, r); err != nil {
return "", err
}
return hex.EncodeToString(h.Sum(nil)), nil
}
+1
View File
@@ -25,3 +25,4 @@ func (e *NFSExplorer) Delete(path string) error { return nil }
func (e *NFSExplorer) Rename(src, dst string) error { return nil }
func (e *NFSExplorer) ReadFile(path string) (io.ReadCloser, error) { return nil, nil }
func (e *NFSExplorer) WriteFile(path string, r io.Reader, size int64) error { return nil }
func (e *NFSExplorer) Checksum(path string) (string, error) { return "", nil }
+25
View File
@@ -307,3 +307,28 @@ func (e *S3Explorer) WriteFile(path string, r io.Reader, size int64) error {
})
return err
}
func (e *S3Explorer) Checksum(path string) (string, error) {
bucket, subpath, _, err := e.getBucketAndPath(path)
if err != nil {
return "", err
}
if subpath == "" {
return "", fmt.Errorf("cannot calculate checksum of bucket")
}
input := &s3.HeadObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(subpath),
}
head, err := e.client.HeadObject(context.TODO(), input)
if err != nil {
return "", err
}
if head.ETag != nil {
return strings.Trim(*head.ETag, "\""), nil
}
return "", fmt.Errorf("no etag found")
}
+15
View File
@@ -1,6 +1,8 @@
package sftp
import (
"crypto/md5"
"encoding/hex"
"fmt"
"io"
"path/filepath"
@@ -162,3 +164,16 @@ func (e *SFTPExplorer) WriteFile(path string, r io.Reader, size int64) error {
_, err = io.Copy(f, r)
return err
}
func (e *SFTPExplorer) Checksum(path string) (string, error) {
r, err := e.ReadFile(path)
if err != nil {
return "", err
}
defer r.Close()
h := md5.New()
if _, err := io.Copy(h, r); err != nil {
return "", err
}
return hex.EncodeToString(h.Sum(nil)), nil
}
+15
View File
@@ -1,6 +1,8 @@
package smb
import (
"crypto/md5"
"encoding/hex"
"fmt"
"io"
"net"
@@ -243,3 +245,16 @@ func (e *SMBExplorer) WriteFile(path string, r io.Reader, size int64) error {
_, err = io.Copy(f, r)
return err
}
func (e *SMBExplorer) Checksum(path string) (string, error) {
r, err := e.ReadFile(path)
if err != nil {
return "", err
}
defer r.Close()
h := md5.New()
if _, err := io.Copy(h, r); err != nil {
return "", err
}
return hex.EncodeToString(h.Sum(nil)), nil
}
+15
View File
@@ -1,6 +1,8 @@
package webdav
import (
"crypto/md5"
"encoding/hex"
"fmt"
"io"
"strings"
@@ -102,3 +104,16 @@ func (e *WebDAVExplorer) ReadFile(path string) (io.ReadCloser, error) {
func (e *WebDAVExplorer) WriteFile(path string, r io.Reader, size int64) error {
return e.client.WriteStream(path, r, 0644)
}
func (e *WebDAVExplorer) Checksum(path string) (string, error) {
r, err := e.ReadFile(path)
if err != nil {
return "", err
}
defer r.Close()
h := md5.New()
if _, err := io.Copy(h, r); err != nil {
return "", err
}
return hex.EncodeToString(h.Sum(nil)), nil
}