Skip to content

Commit

Permalink
feat: validate hashes (#98)
Browse files Browse the repository at this point in the history
* feat: validate hashes

* chore: update .gitignore
  • Loading branch information
ludviglundgren authored Aug 19, 2024
1 parent 19bd729 commit 09a160a
Show file tree
Hide file tree
Showing 10 changed files with 132 additions and 19 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
.DS_Store
.qbt.toml
dist
bin
bin
testdata
10 changes: 10 additions & 0 deletions cmd/torrent_category.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cmd

import (
"fmt"
"github.com/ludviglundgren/qbittorrent-cli/pkg/utils"
"log"
"os"
"strings"
Expand Down Expand Up @@ -54,6 +55,15 @@ func RunTorrentCategorySet() *cobra.Command {
command.Flags().StringSliceVar(&hashes, "hashes", []string{}, "Torrent hashes, as comma separated list")

command.RunE = func(cmd *cobra.Command, args []string) error {
if len(hashes) == 0 {
log.Println("No hashes supplied!")
}

err := utils.ValidateHash(hashes)
if err != nil {
log.Fatalf("Invalid hashes supplied: %v", err)
}

config.InitConfig()

qbtSettings := qbittorrent.Config{
Expand Down
8 changes: 8 additions & 0 deletions cmd/torrent_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cmd
import (
"encoding/json"
"fmt"
"github.com/ludviglundgren/qbittorrent-cli/pkg/utils"
"log"
"os"
"strings"
Expand Down Expand Up @@ -39,6 +40,13 @@ func RunTorrentList() *cobra.Command {
command.Flags().StringSliceVar(&hashes, "hashes", []string{}, "Filter by hashes. Separated by comma: \"hash1,hash2\".")

command.Run = func(cmd *cobra.Command, args []string) {
if len(hashes) > 0 {
err := utils.ValidateHash(hashes)
if err != nil {
log.Fatalf("Invalid hashes supplied: %v", err)
}
}

config.InitConfig()

qbtSettings := qbittorrent.Config{
Expand Down
10 changes: 9 additions & 1 deletion cmd/torrent_pause.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cmd

import (
"fmt"
"github.com/ludviglundgren/qbittorrent-cli/pkg/utils"
"log"
"os"

Expand Down Expand Up @@ -30,6 +31,13 @@ func RunTorrentPause() *cobra.Command {
command.Flags().BoolVar(&names, "names", false, "Provided arguments will be read as torrent names")

command.Run = func(cmd *cobra.Command, args []string) {
if len(hashes) > 0 {
err := utils.ValidateHash(hashes)
if err != nil {
log.Fatalf("Invalid hashes supplied: %v", err)
}
}

config.InitConfig()

qbtSettings := qbittorrent.Config{
Expand All @@ -54,7 +62,7 @@ func RunTorrentPause() *cobra.Command {
}

if len(hashes) == 0 {
log.Printf("No torrents found to pause with provided search terms")
log.Printf("No torrents found to pause with provided hashes. Use --all to pause all torrents.")
return
}

Expand Down
8 changes: 7 additions & 1 deletion cmd/torrent_recheck.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cmd

import (
"fmt"
"github.com/ludviglundgren/qbittorrent-cli/pkg/utils"
"log"
"os"

Expand Down Expand Up @@ -34,6 +35,11 @@ func RunTorrentRecheck() *cobra.Command {
return
}

err := utils.ValidateHash(hashes)
if err != nil {
log.Fatalf("Invalid hashes supplied: %v", err)
}

config.InitConfig()

qbtSettings := qbittorrent.Config{
Expand All @@ -53,7 +59,7 @@ func RunTorrentRecheck() *cobra.Command {
os.Exit(1)
}

err := batchRequests(hashes, func(start, end int) error {
err = batchRequests(hashes, func(start, end int) error {
return qb.RecheckCtx(ctx, hashes[start:end])
})
if err != nil {
Expand Down
8 changes: 8 additions & 0 deletions cmd/torrent_remove.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cmd

import (
"fmt"
"github.com/ludviglundgren/qbittorrent-cli/pkg/utils"
"log"
"os"

Expand Down Expand Up @@ -40,6 +41,13 @@ func RunTorrentRemove() *cobra.Command {
command.Flags().StringSliceVar(&excludeTags, "exclude-tags", []string{}, "Exclude torrents with provided tags")

command.Run = func(cmd *cobra.Command, args []string) {
if len(hashes) > 0 {
err := utils.ValidateHash(hashes)
if err != nil {
log.Fatalf("Invalid hashes supplied: %v", err)
}
}

config.InitConfig()

qbtSettings := qbittorrent.Config{
Expand Down
8 changes: 8 additions & 0 deletions cmd/torrent_resume.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cmd

import (
"fmt"
"github.com/ludviglundgren/qbittorrent-cli/pkg/utils"
"log"
"os"
"time"
Expand Down Expand Up @@ -29,6 +30,13 @@ func RunTorrentResume() *cobra.Command {
command.Flags().StringSliceVar(&hashes, "hashes", []string{}, "Add hashes as comma separated list")

command.Run = func(cmd *cobra.Command, args []string) {
if len(hashes) > 0 {
err := utils.ValidateHash(hashes)
if err != nil {
log.Fatalf("Invalid hashes supplied: %v", err)
}
}

config.InitConfig()

qbtSettings := qbittorrent.Config{
Expand Down
43 changes: 27 additions & 16 deletions cmd/torrent_tracker.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ func RunTorrentTrackerEdit() *cobra.Command {
command.Flags().StringVar(&oldURL, "old", "", "Old tracker URL to replace")
command.Flags().StringVar(&newURL, "new", "", "New tracker URL")

command.MarkFlagRequired("old")
command.MarkFlagRequired("new")

command.RunE = func(cmd *cobra.Command, args []string) error {
config.InitConfig()

Expand All @@ -64,31 +67,39 @@ func RunTorrentTrackerEdit() *cobra.Command {
os.Exit(1)
}

if dry {
log.Printf("dry-run: successfully updated tracker on torrents\n")
torrents, err := qb.GetTorrentsCtx(ctx, qbittorrent.TorrentFilterOptions{})
if err != nil {
log.Fatalf("could not get torrents err: %q\n", err)
}

return nil
} else {
torrents, err := qb.GetTorrentsCtx(ctx, qbittorrent.TorrentFilterOptions{})
if err != nil {
log.Fatalf("could not get torrents err: %q\n", err)
var torrentsToUpdate []qbittorrent.Torrent

for _, torrent := range torrents {
if strings.Contains(torrent.Tracker, oldURL) {
torrentsToUpdate = append(torrentsToUpdate, torrent)
}
}

matches := 0
if len(torrentsToUpdate) == 0 {
log.Printf("found no torrents with tracker %q\n", oldURL)
return nil
}

for i, torrent := range torrentsToUpdate {
if dry {
log.Printf("dry-run: [%d/%d] updating tracker for torrent %s %q\n", i+1, len(torrentsToUpdate), torrent.Hash, torrent.Name)

for _, torrent := range torrents {
if strings.Contains(torrent.Tracker, oldURL) {
if err := qb.EditTrackerCtx(ctx, torrent.Hash, torrent.Tracker, newURL); err != nil {
log.Fatalf("could not edit tracker for torrent: %s\n", torrent.Hash)
}
} else {
log.Printf("[%d/%d] updating tracker for torrent %s %q\n", i+1, len(torrentsToUpdate), torrent.Hash, torrent.Name)

matches++
if err := qb.EditTrackerCtx(ctx, torrent.Hash, torrent.Tracker, newURL); err != nil {
log.Fatalf("could not edit tracker for torrent: %s\n", torrent.Hash)
}
}

log.Printf("successfully updated tracker for (%d) torrents\n", matches)
}

log.Printf("successfully updated tracker for (%d) torrents\n", len(torrentsToUpdate))

return nil
}

Expand Down
25 changes: 25 additions & 0 deletions pkg/utils/utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package utils

import (
"fmt"
"regexp"
"strings"
)

var hashRegex = regexp.MustCompile("^[a-fA-F0-9]{40}$")

func ValidateHash(hashes []string) error {
var invalid []string

for _, hash := range hashes {
if !hashRegex.MatchString(hash) {
invalid = append(invalid, hash)
}
}

if len(invalid) > 0 {
return fmt.Errorf("invalid hashes: %s", strings.Join(invalid, ","))
}

return nil
}
28 changes: 28 additions & 0 deletions pkg/utils/utils_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package utils

import "testing"

func TestValidateHash(t *testing.T) {
type args struct {
hashes []string
}
tests := []struct {
name string
args args
want bool
wantErr bool
}{
{name: "ok", args: args{hashes: []string{"6957bf5272f5b994132458a557864e3ea747489f"}}, want: true, wantErr: false},
{name: "invalid", args: args{hashes: []string{"6957bf5272f5b994132458a557864e3ea747489"}}, want: false, wantErr: true},
{name: "invalid_2", args: args{hashes: []string{"11111"}}, want: false, wantErr: true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := ValidateHash(tt.args.hashes)
if (err != nil) != tt.wantErr {
t.Errorf("ValidateHash() error = %v, wantErr %v", err, tt.wantErr)
return
}
})
}
}

0 comments on commit 09a160a

Please sign in to comment.