Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: validate hashes #98

Merged
merged 2 commits into from
Aug 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
}
})
}
}
Loading