forked from Plemya-x/ALR
		
	feat: add checksum for torrent downloader
This commit is contained in:
		| @@ -11,7 +11,7 @@ | |||||||
|     <g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11"> |     <g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11"> | ||||||
|         <text x="33.5" y="15" fill="#010101" fill-opacity=".3">coverage</text> |         <text x="33.5" y="15" fill="#010101" fill-opacity=".3">coverage</text> | ||||||
|         <text x="33.5" y="14">coverage</text> |         <text x="33.5" y="14">coverage</text> | ||||||
|         <text x="86" y="15" fill="#010101" fill-opacity=".3">20.2%</text> |         <text x="86" y="15" fill="#010101" fill-opacity=".3">20.1%</text> | ||||||
|         <text x="86" y="14">20.2%</text> |         <text x="86" y="14">20.1%</text> | ||||||
|     </g> |     </g> | ||||||
| </svg> | </svg> | ||||||
|   | |||||||
| Before Width: | Height: | Size: 926 B After Width: | Height: | Size: 926 B | 
| @@ -20,11 +20,8 @@ | |||||||
| package dl | package dl | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"bytes" |  | ||||||
| 	"context" | 	"context" | ||||||
| 	"encoding/hex" |  | ||||||
| 	"errors" | 	"errors" | ||||||
| 	"log/slog" |  | ||||||
| 	"net/url" | 	"net/url" | ||||||
| 	"path" | 	"path" | ||||||
| 	"strconv" | 	"strconv" | ||||||
| @@ -127,7 +124,7 @@ func (d *GitDownloader) Download(ctx context.Context, opts Options) (Type, strin | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	err = d.verifyHash(opts) | 	err = VerifyHashFromLocal("", opts) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return 0, "", err | 		return 0, "", err | ||||||
| 	} | 	} | ||||||
| @@ -139,30 +136,6 @@ func (d *GitDownloader) Download(ctx context.Context, opts Options) (Type, strin | |||||||
| 	return TypeDir, name, nil | 	return TypeDir, name, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (GitDownloader) verifyHash(opts Options) error { |  | ||||||
| 	if opts.Hash != nil { |  | ||||||
| 		h, err := opts.NewHash() |  | ||||||
| 		if err != nil { |  | ||||||
| 			return err |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		err = HashDir(opts.Destination, h) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return err |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		sum := h.Sum(nil) |  | ||||||
|  |  | ||||||
| 		slog.Warn("validate checksum", "real", hex.EncodeToString(sum), "expected", hex.EncodeToString(opts.Hash)) |  | ||||||
|  |  | ||||||
| 		if !bytes.Equal(sum, opts.Hash) { |  | ||||||
| 			return ErrChecksumMismatch |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Update uses git to pull the repository and update it | // Update uses git to pull the repository and update it | ||||||
| // to the latest revision. It allows specifying the depth | // to the latest revision. It allows specifying the depth | ||||||
| // and recursion options via query string. It returns | // and recursion options via query string. It returns | ||||||
| @@ -225,7 +198,7 @@ func (d *GitDownloader) Update(opts Options) (bool, error) { | |||||||
| 		return false, err | 		return false, err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	err = d.verifyHash(opts) | 	err = VerifyHashFromLocal("", opts) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return false, err | 		return false, err | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -71,7 +71,17 @@ func (TorrentDownloader) Download(ctx context.Context, opts Options) (Type, stri | |||||||
| 		return 0, "", err | 		return 0, "", err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return determineType(opts.Destination) | 	dlType, name, err := determineType(opts.Destination) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return 0, "", err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	err = VerifyHashFromLocal(name, opts) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return 0, "", err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return dlType, name, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func removeTorrentFiles(path string) error { | func removeTorrentFiles(path string) error { | ||||||
|   | |||||||
| @@ -17,39 +17,79 @@ | |||||||
| package dl | package dl | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"encoding/hex" | ||||||
|  | 	"fmt" | ||||||
| 	"hash" | 	"hash" | ||||||
| 	"io" | 	"io" | ||||||
|  | 	"log/slog" | ||||||
| 	"os" | 	"os" | ||||||
| 	"path/filepath" | 	"path/filepath" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func HashDir(dirPath string, h hash.Hash) error { | // If the checksum does not match, returns ErrChecksumMismatch | ||||||
| 	err := filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error { | func VerifyHashFromLocal(path string, opts Options) error { | ||||||
|  | 	if opts.Hash != nil { | ||||||
|  | 		h, err := opts.NewHash() | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
| 		// Skip .git directory |  | ||||||
| 		if info.IsDir() && info.Name() == ".git" { | 		err = HashLocal(filepath.Join(opts.Destination, path), h) | ||||||
| 			return filepath.SkipDir | 		if err != nil { | ||||||
|  | 			return err | ||||||
| 		} | 		} | ||||||
| 		// Skip directories (only process files) |  | ||||||
| 		if !info.Mode().IsRegular() { | 		sum := h.Sum(nil) | ||||||
|  |  | ||||||
|  | 		slog.Debug("validate checksum", "real", hex.EncodeToString(sum), "expected", hex.EncodeToString(opts.Hash)) | ||||||
|  |  | ||||||
|  | 		if !bytes.Equal(sum, opts.Hash) { | ||||||
|  | 			return ErrChecksumMismatch | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 		// Open file |  | ||||||
|  | func HashLocal(path string, h hash.Hash) error { | ||||||
|  | 	info, err := os.Stat(path) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if info.Mode().IsRegular() { | ||||||
|  | 		// Single file | ||||||
| 		f, err := os.Open(path) | 		f, err := os.Open(path) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
| 		defer f.Close() | 		defer f.Close() | ||||||
| 		// Write file content to hasher | 		_, err = io.Copy(h, f) | ||||||
| 		if _, err := io.Copy(h, f); err != nil { |  | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 		return nil |  | ||||||
| 	}) | 	if info.IsDir() { | ||||||
|  | 		// Walk directory | ||||||
|  | 		return filepath.Walk(path, func(path string, info os.FileInfo, err error) error { | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				return err | 				return err | ||||||
| 			} | 			} | ||||||
|  | 			if info.IsDir() && info.Name() == ".git" { | ||||||
|  | 				return filepath.SkipDir | ||||||
|  | 			} | ||||||
|  | 			if !info.Mode().IsRegular() { | ||||||
| 				return nil | 				return nil | ||||||
| 			} | 			} | ||||||
|  | 			f, err := os.Open(path) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return err | ||||||
|  | 			} | ||||||
|  | 			defer f.Close() | ||||||
|  | 			_, err = io.Copy(h, f) | ||||||
|  | 			return err | ||||||
|  | 		}) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return fmt.Errorf("unsupported file type: %s", path) | ||||||
|  | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user