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

Bulk ASN #159

Merged
merged 11 commits into from
Aug 18, 2023
134 changes: 54 additions & 80 deletions ipinfo/cmd_asn.go
Original file line number Diff line number Diff line change
@@ -1,113 +1,87 @@
package main

import (
"errors"
"fmt"
"net/http"
"github.com/ipinfo/cli/lib"
"github.com/spf13/pflag"
"os"

"github.com/fatih/color"
"github.com/ipinfo/cli/lib/complete"
"github.com/ipinfo/cli/lib/complete/predict"
"github.com/ipinfo/go/v2/ipinfo"
"github.com/spf13/pflag"
)

var completionsASN = &complete.Command{
Sub: map[string]*complete.Command{
"bulk": completionsASNBulk,
},
Flags: map[string]complete.Predictor{
"-t": predict.Nothing,
"--token": predict.Nothing,
"--nocache": predict.Nothing,
"-h": predict.Nothing,
"--help": predict.Nothing,
"-f": predict.Set(asnFields),
"--field": predict.Set(asnFields),
"--nocolor": predict.Nothing,
"-p": predict.Nothing,
"--pretty": predict.Nothing,
"-j": predict.Nothing,
"--json": predict.Nothing,
"-c": predict.Nothing,
"--csv": predict.Nothing,
"-h": predict.Nothing,
"--help": predict.Nothing,
},
}

func printHelpASN(asn string) {
func printHelpASN() {

fmt.Printf(
`Usage: %s %s [<opts>]
`Usage: %s asn <cmd> [<opts>]

Commands:
bulk lookup ASNs in bulk

Options:
General:
--token <tok>, -t <tok>
use <tok> as API token.
--nocache
do not use the cache.
--help, -h
show help.

Outputs:
--field <field>, -f <field>
lookup only specific fields in the output.
field names correspond to JSON keys, e.g. 'registry' or 'allocated'.
multiple field names must be separated by commas.
--nocolor
disable colored output.

Formats:
--json, -j
output JSON format. (default)
--yaml, -y
output YAML format.
`, progBase, asn)
`, progBase)
}

func cmdASN(asn string) error {
var fTok string
var fField []string
var fJSON bool
var fYAML bool

pflag.StringVarP(&fTok, "token", "t", "", "the token to use.")
pflag.BoolVar(&fNoCache, "nocache", false, "disable the cache.")
pflag.BoolVarP(&fHelp, "help", "h", false, "show help.")
pflag.StringSliceVarP(&fField, "field", "f", nil, "specific field to lookup.")
pflag.BoolVarP(&fJSON, "json", "j", true, "output JSON format. (default)")
pflag.BoolVarP(&fYAML, "yaml", "y", false, "output YAML format.")
pflag.BoolVar(&fNoColor, "nocolor", false, "disable color output.")
pflag.Parse()

if fNoColor {
color.NoColor = true
// cmdASN is the handler for the "asn" command.
func cmdASN() error {
var err error
cmd := ""
if len(os.Args) > 2 {
cmd = os.Args[2]
}

if fHelp {
printHelpASN(asn)
return nil
}
switch {
case cmd == "bulk":
err = cmdASNBulk()
default:
UmanShahzad marked this conversation as resolved.
Show resolved Hide resolved
// check whether the standard input (stdin) is being piped
// or redirected from another source or whether it's being read from the terminal (interactive mode).
stat, _ := os.Stdin.Stat()
if (stat.Mode() & os.ModeCharDevice) != 0 {
printHelpASN()
return nil
}

ii = prepareIpinfoClient(fTok)
f := lib.CmdASNBulkFlags{}
f.Init()
pflag.Parse()

// require token for ASN API.
if ii.Token == "" {
return errors.New("ASN lookups require a token; login via `ipinfo init`.")
}
ii = prepareIpinfoClient(f.Token)
data, err := lib.CmdASNBulk(f, ii, lib.ReadStringsFromStdin(), printHelpASNBulk)
if err != nil {
return err
}
if (data) == nil {
return nil
}

data, err := ii.GetASNDetails(asn)
if err != nil {
iiErr, ok := err.(*ipinfo.ErrorResponse)
if ok && (iiErr.Response.StatusCode == http.StatusUnauthorized) {
return errors.New("Token does not have access to ASN API")
if len(f.Field) > 0 {
return outputFieldBatchASNDetails(data, f.Field, false, false)
}
return err
}

if len(fField) > 0 {
d := make(ipinfo.BatchASNDetails, 1)
d[data.ASN] = data
return outputFieldBatchASNDetails(d, fField, false, false)
if f.Yaml {
return outputYAML(data)
}

return outputJSON(data)
}
if fYAML {
return outputYAML(data)

if err != nil {
fmt.Fprintf(os.Stderr, "err: %v\n", err)
}

return outputJSON(data)
return nil
}
90 changes: 90 additions & 0 deletions ipinfo/cmd_asn_bulk.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package main

import (
"fmt"
"github.com/ipinfo/cli/lib"
"github.com/ipinfo/cli/lib/complete"
"github.com/ipinfo/cli/lib/complete/predict"
"github.com/spf13/pflag"
)

var completionsASNBulk = &complete.Command{
Flags: map[string]complete.Predictor{
"-t": predict.Nothing,
"--token": predict.Nothing,
"--nocache": predict.Nothing,
"-h": predict.Nothing,
"--help": predict.Nothing,
"-f": predict.Set(asnFields),
"--field": predict.Set(asnFields),
"-j": predict.Nothing,
"--json": predict.Nothing,
},
}

// printHelpASNBulk prints the help message for the asn bulk command.
func printHelpASNBulk() {
fmt.Printf(
`Usage: %s asn bulk [<opts>] <ASNs | filepath>

Description:
Accepts ASNs and file paths.

Examples:
# Lookup all ASNs in multiple files.
$ %[1]s asn bulk /path/to/asnlist1.txt /path/to/asnlist2.txt

# Lookup multiple ASNs.
$ %[1]s asn bulk AS123 AS456 AS789

# Lookup ASNs from multiple sources simultaneously.
$ %[1]s asn bulk AS123 AS456 AS789 asns.txt

Options:
General:
--token <tok>, -t <tok>
use <tok> as API token.
--nocache
do not use the cache.
--help, -h
show help.

Outputs:
--field <field>, -f <field>
lookup only specific fields in the output.
field names correspond to JSON keys, e.g. 'name' or 'registry'.
multiple field names must be separated by commas.

Formats:
--json, -j
output JSON format. (default)
--yaml, -y
output YAML format.
`, progBase)
}

// cmdASNBulk is the asn bulk command.
func cmdASNBulk() error {
f := lib.CmdASNBulkFlags{}
f.Init()
pflag.Parse()

ii = prepareIpinfoClient(f.Token)
data, err := lib.CmdASNBulk(f, ii, pflag.Args()[2:], printHelpASNBulk)
if err != nil {
return err
}
if (data) == nil {
return nil
}

if len(f.Field) > 0 {
return outputFieldBatchASNDetails(data, f.Field, false, false)
}

if f.Yaml {
return outputYAML(data)
}

return outputJSON(data)
}
111 changes: 111 additions & 0 deletions ipinfo/cmd_asn_single.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package main

import (
"errors"
"fmt"
"net/http"

"github.com/fatih/color"
"github.com/ipinfo/cli/lib/complete"
"github.com/ipinfo/cli/lib/complete/predict"
"github.com/ipinfo/go/v2/ipinfo"
"github.com/spf13/pflag"
)

var completionsASNSingle = &complete.Command{
Flags: map[string]complete.Predictor{
"-t": predict.Nothing,
"--token": predict.Nothing,
"--nocache": predict.Nothing,
"-h": predict.Nothing,
"--help": predict.Nothing,
"-f": predict.Set(asnFields),
"--field": predict.Set(asnFields),
"--nocolor": predict.Nothing,
"-p": predict.Nothing,
"--pretty": predict.Nothing,
"-j": predict.Nothing,
"--json": predict.Nothing,
},
}

func printHelpASNSingle(asn string) {
fmt.Printf(
`Usage: %s %s [<opts>]

Options:
General:
--token <tok>, -t <tok>
use <tok> as API token.
--nocache
do not use the cache.
--help, -h
show help.

Outputs:
--field <field>, -f <field>
lookup only specific fields in the output.
field names correspond to JSON keys, e.g. 'registry' or 'allocated'.
multiple field names must be separated by commas.
--nocolor
disable colored output.

Formats:
--json, -j
output JSON format. (default)
--yaml, -y
output YAML format.
`, progBase, asn)
}

func cmdASNSingle(asn string) error {
var fTok string
var fField []string
var fJSON bool
var fYAML bool

pflag.StringVarP(&fTok, "token", "t", "", "the token to use.")
pflag.BoolVar(&fNoCache, "nocache", false, "disable the cache.")
pflag.BoolVarP(&fHelp, "help", "h", false, "show help.")
pflag.StringSliceVarP(&fField, "field", "f", nil, "specific field to lookup.")
pflag.BoolVarP(&fJSON, "json", "j", true, "output JSON format. (default)")
pflag.BoolVarP(&fYAML, "yaml", "y", false, "output YAML format.")
pflag.BoolVar(&fNoColor, "nocolor", false, "disable color output.")
pflag.Parse()

if fNoColor {
color.NoColor = true
}

if fHelp {
printHelpASNSingle(asn)
return nil
}

ii = prepareIpinfoClient(fTok)

// require token for ASN API.
if ii.Token == "" {
return errors.New("ASN lookups require a token; login via `ipinfo init`.")
}

data, err := ii.GetASNDetails(asn)
if err != nil {
iiErr, ok := err.(*ipinfo.ErrorResponse)
if ok && (iiErr.Response.StatusCode == http.StatusUnauthorized) {
return errors.New("Token does not have access to ASN API")
}
return err
}

if len(fField) > 0 {
d := make(ipinfo.BatchASNDetails, 1)
d[data.ASN] = data
return outputFieldBatchASNDetails(d, fField, false, false)
}
if fYAML {
return outputYAML(data)
}

return outputJSON(data)
}
1 change: 1 addition & 0 deletions ipinfo/cmd_default.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Commands:
<asn> look up details for an ASN, e.g. AS123 or as123.
myip get details for your IP.
bulk get details for multiple IPs in bulk.
asn tools related to ASNs.
summarize get summarized data for a group of IPs.
map open a URL to a map showing the locations of a group of IPs.
prips print IP list from CIDR or range.
Expand Down
2 changes: 1 addition & 1 deletion ipinfo/cmd_init.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ func cmdInit() error {
}

// save token to file.
gConfig.Token = tok
gConfig.Token = newtoken
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this intentional?

if err := SaveConfig(gConfig); err != nil {
return err
}
Expand Down
Loading