Skip to content

Commit

Permalink
feat(Collections): Remove items / delete collection (#46)
Browse files Browse the repository at this point in the history
  • Loading branch information
joseotoro authored Apr 13, 2022
1 parent 0720b96 commit 28e249b
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 1 deletion.
134 changes: 134 additions & 0 deletions cmd/collection.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package cmd
import (
"fmt"
"io"
"net"
"regexp"
"strings"

"github.com/VirusTotal/vt-go"
Expand All @@ -12,6 +14,12 @@ import (
"github.com/spf13/viper"
)

type objectDescriptor struct {
Type string `json:"type"`
Id string `json:"id,omitempty"`
Url string `json:"url,omitempty"`
}

var collectionCmdHelp = `Get information about one or more collections.
This command receives one or more collection IDs and returns information about
Expand Down Expand Up @@ -49,6 +57,8 @@ func NewCollectionCmd() *cobra.Command {
cmd.AddCommand(NewCollectionCreateCmd())
cmd.AddCommand(NewCollectionRenameCmd())
cmd.AddCommand(NewCollectionUpdateCmd())
cmd.AddCommand(NewCollectionDeleteCmd())
cmd.AddCommand(NewCollectionRemoveItemsCmd())

addRelationshipCmds(cmd, "collections", "collection", "[collection]")
addThreadsFlag(cmd.Flags())
Expand Down Expand Up @@ -200,6 +210,82 @@ func NewCollectionUpdateCmd() *cobra.Command {
}
}

var removeCollectionItemsCmdHelp = `Remove items from a collection.
This command receives a collection ID and one of more IoCs
(sha256 hashes, URLs, domains, IP addresses) and removes them from the collection.
If the command receives a single hypen (-) the IoCs will be read from the
standard input.`

var removeCollectionItemsExample = ` vt collection remove [collection id] www.example.com
vt collection remove [collection id] www.example.com 8.8.8.8
cat list_of_iocs | vt collection remove [collection id] -`

// NewCollectionRemoveItemsCmd returns a command for removing items from a collection.
func NewCollectionRemoveItemsCmd() *cobra.Command {
return &cobra.Command{
Use: "remove [collection id] [ioc]...",
Short: "Remove items from a collection.",
Args: cobra.MinimumNArgs(2),
Long: removeCollectionItemsCmdHelp,
Example: removeCollectionItemsExample,

RunE: func(cmd *cobra.Command, args []string) error {
c, err := NewAPIClient()
if err != nil {
return err
}
relationshipDescriptors := descriptorsFromReader(
utils.StringReaderFromCmdArgs(args[1:]))
for relationshipName, descriptors := range relationshipDescriptors {
url := vt.URL("collections/%s/%s", args[0], relationshipName)
response, err := c.DeleteData(url, descriptors)
if err != nil {
return err
}
if response.Error.Code != "" {
return response.Error
}
}
return nil
},
}
}

var deleteCollectionCmdHelp = `Delete a collection.
This command receives a collection ID and deletes it.`

var deleteCollectionExample = ` vt collection delete [collection id]`

// NewCollectionDeleteCmd returns a command for deleting a collection.
func NewCollectionDeleteCmd() *cobra.Command {
return &cobra.Command{
Use: "delete [collection id]",
Short: "Delete a collection.",
Args: cobra.MinimumNArgs(1),
Long: deleteCollectionCmdHelp,
Example: deleteCollectionExample,

RunE: func(cmd *cobra.Command, args []string) error {
c, err := NewAPIClient()
if err != nil {
return err
}
url := vt.URL("collections/%s", args[0])
response, err := c.Delete(url)
if err != nil {
return err
}
if response.Error.Code != "" {
return response.Error
}
return nil
},
}
}

func rawFromReader(reader utils.StringReader) string {
var lines []string
for {
Expand All @@ -211,3 +297,51 @@ func rawFromReader(reader utils.StringReader) string {
}
return strings.Join(lines, " ")
}

func descriptorsFromReader(reader utils.StringReader) map[string][]objectDescriptor {
descriptors := make(map[string][]objectDescriptor)
hashPattern := regexp.MustCompile("[0-9a-fA-F]{32,64}")
urlPattern := regexp.MustCompile("[hH][tTxX]{2}[pP][sS]?://.*")
// At least two domain parts.
domainPattern := regexp.MustCompile(".*[^.]+\\.[^.]+.*")
for {
next, err := reader.ReadString()
if err == io.EOF {
break
}
if match := hashPattern.MatchString(next); match {
files := descriptors["files"]
files = append(files, objectDescriptor{
Type: "file",
Id: next,
})
descriptors["files"] = files
} else if net.ParseIP(next) != nil {
if strings.Contains(next, ".") {
ipAddresses := descriptors["ip_addresses"]
ipAddresses = append(ipAddresses, objectDescriptor{
Type: "ip_address",
Id: next,
})
descriptors["ip_addresses"] = ipAddresses
} else {
// IPv6, skip.
}
} else if urlPattern.MatchString(next) {
urls := descriptors["urls"]
urls = append(urls, objectDescriptor{
Type: "url",
Url: next,
})
descriptors["urls"] = urls
} else if domainPattern.MatchString(next) {
domains := descriptors["domains"]
domains = append(domains, objectDescriptor{
Type: "domain",
Id: next,
})
descriptors["domains"] = domains
}
}
return descriptors
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/VirusTotal/vt-cli
go 1.14

require (
github.com/VirusTotal/vt-go v0.0.0-20211209151516-855a1e790678
github.com/VirusTotal/vt-go v0.0.0-20220413144842-e010bf48aaee
github.com/briandowns/spinner v1.7.0
github.com/cavaliercoder/grab v2.0.0+incompatible
github.com/dustin/go-humanize v1.0.0
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ github.com/VirusTotal/vt-go v0.0.0-20211116094520-07a92e6467b7 h1:1oIDITWcezvHQX
github.com/VirusTotal/vt-go v0.0.0-20211116094520-07a92e6467b7/go.mod h1:u1+HeRyl/gQs67eDgVEWNE7+x+zCyXhdtNVrRJR5YPE=
github.com/VirusTotal/vt-go v0.0.0-20211209151516-855a1e790678 h1:IVvLDz0INo1rn7wG4OQub9MkyNNaBp0sQgU1apho/mk=
github.com/VirusTotal/vt-go v0.0.0-20211209151516-855a1e790678/go.mod h1:u1+HeRyl/gQs67eDgVEWNE7+x+zCyXhdtNVrRJR5YPE=
github.com/VirusTotal/vt-go v0.0.0-20220413141716-fce0077b709b h1:YdiHY6VO3InYpfasvfpF6EolaNqKNv6pmGJfBQCVuL4=
github.com/VirusTotal/vt-go v0.0.0-20220413141716-fce0077b709b/go.mod h1:u1+HeRyl/gQs67eDgVEWNE7+x+zCyXhdtNVrRJR5YPE=
github.com/VirusTotal/vt-go v0.0.0-20220413144842-e010bf48aaee h1:JDhi0dS8y9QLMJZA7ezLyXHxYaMlyzX6MDkq0SSc304=
github.com/VirusTotal/vt-go v0.0.0-20220413144842-e010bf48aaee/go.mod h1:u1+HeRyl/gQs67eDgVEWNE7+x+zCyXhdtNVrRJR5YPE=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
Expand Down

0 comments on commit 28e249b

Please sign in to comment.