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

Port scan flags to the serve command #1157

Merged
merged 7 commits into from
Nov 5, 2022
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
4 changes: 2 additions & 2 deletions cmd/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ func init() {

// Register flags
cmd.PersistentFlags().StringVarP(&opts.Number, "number", "n", "", "The phone number to scan (E164 or international format)")
cmd.PersistentFlags().StringArrayVarP(&opts.DisabledScanners, "disable", "D", []string{}, "A list of scanners to skip for this scan.")
cmd.PersistentFlags().StringSliceVar(&opts.PluginPaths, "plugin", []string{}, "Extra scanner plugin to use for the scan")
cmd.PersistentFlags().StringArrayVarP(&opts.DisabledScanners, "disable", "D", []string{}, "Scanner to skip for this scan")
cmd.PersistentFlags().StringArrayVar(&opts.PluginPaths, "plugin", []string{}, "Extra scanner plugin to use for the scan")
cmd.PersistentFlags().StringSliceVar(&opts.EnvFiles, "env-file", []string{}, "Env files to parse environment variables from (looks for .env by default)")
// scanCmd.PersistentFlags().StringVarP(&input, "input", "i", "", "Text file containing a list of phone numbers to scan (one per line)")
// scanCmd.PersistentFlags().StringVarP(&output, "output", "o", "", "Output to save scan results")
Expand Down
84 changes: 59 additions & 25 deletions cmd/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,44 +3,78 @@ package cmd
import (
"fmt"
"github.com/gin-gonic/gin"
"github.com/joho/godotenv"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/sundowndev/phoneinfoga/v2/build"
"github.com/sundowndev/phoneinfoga/v2/lib/filter"
"github.com/sundowndev/phoneinfoga/v2/lib/remote"
"github.com/sundowndev/phoneinfoga/v2/web"
"github.com/sundowndev/phoneinfoga/v2/web/v2/api/handlers"
"log"
"net/http"
"os"
)

var httpPort int
var disableClient bool
type ServeCmdOptions struct {
HttpPort int
DisableClient bool
DisabledScanners []string
PluginPaths []string
EnvFiles []string
}

func init() {
// Register command
rootCmd.AddCommand(serveCmd)
opts := &ServeCmdOptions{}
cmd := NewServeCmd(opts)
rootCmd.AddCommand(cmd)

// Register flags
serveCmd.PersistentFlags().IntVarP(&httpPort, "port", "p", 5000, "HTTP port")
serveCmd.PersistentFlags().BoolVar(&disableClient, "no-client", false, "Disable web client (REST API only)")
cmd.PersistentFlags().IntVarP(&opts.HttpPort, "port", "p", 5000, "HTTP port")
cmd.PersistentFlags().BoolVar(&opts.DisableClient, "no-client", false, "Disable web client (REST API only)")
cmd.PersistentFlags().StringArrayVarP(&opts.DisabledScanners, "disable", "D", []string{}, "Scanner to skip for the scans")
cmd.PersistentFlags().StringArrayVar(&opts.PluginPaths, "plugin", []string{}, "Extra scanner plugin to use for the scans")
cmd.PersistentFlags().StringSliceVar(&opts.EnvFiles, "env-file", []string{}, "Env files to parse environment variables from (looks for .env by default)")
}

var serveCmd = &cobra.Command{
Use: "serve",
Short: "Serve web client",
Run: func(cmd *cobra.Command, args []string) {
if build.IsRelease() && os.Getenv("GIN_MODE") == "" {
gin.SetMode(gin.ReleaseMode)
}

srv, err := web.NewServer(disableClient)
if err != nil {
log.Fatal(err)
}

addr := fmt.Sprintf(":%d", httpPort)

fmt.Printf("Listening on %s\n", addr)
if err := srv.ListenAndServe(addr); err != nil && err != http.ErrServerClosed {
log.Fatalf("listen: %s\n", err)
}
},
func NewServeCmd(opts *ServeCmdOptions) *cobra.Command {
return &cobra.Command{
Use: "serve",
Short: "Serve web client",
PreRun: func(cmd *cobra.Command, args []string) {
err := godotenv.Load(opts.EnvFiles...)
if err != nil {
logrus.WithField("error", err).Debug("Error loading .env file")
}

for _, p := range opts.PluginPaths {
err := remote.OpenPlugin(p)
if err != nil {
exitWithError(err)
}
}

// Initialize remote library
f := filter.NewEngine()
f.AddRule(opts.DisabledScanners...)
handlers.Init(f)
},
Run: func(cmd *cobra.Command, args []string) {
if build.IsRelease() && os.Getenv("GIN_MODE") == "" {
gin.SetMode(gin.ReleaseMode)
}

srv, err := web.NewServer(opts.DisableClient)
if err != nil {
log.Fatal(err)
}

addr := fmt.Sprintf(":%d", opts.HttpPort)
fmt.Printf("Listening on %s\n", addr)
if err := srv.ListenAndServe(addr); err != nil && err != http.ErrServerClosed {
log.Fatalf("listen: %s\n", err)
}
},
}
}
4 changes: 1 addition & 3 deletions docs/getting-started/scanners.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,7 @@ $ phoneinfoga scan -n +4176418xxxx --plugin ./custom_scanner.so
```

!!! info
Plugins are written with the [Go programming language](https://golang.org/).

For now, plugins are only supported through the CLI. To get started, [see this example plugin](https://github.com/sundowndev/phoneinfoga/tree/master/examples/plugin).
Plugins are written with the [Go programming language](https://golang.org/). To get started, [see this example plugin](https://github.com/sundowndev/phoneinfoga/tree/master/examples/plugin).

## Local

Expand Down
9 changes: 4 additions & 5 deletions lib/remote/remote.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ func (r *Library) LoadPlugins() {
}

func (r *Library) AddScanner(s Scanner) {
if r.filter.Match(s.Name()) {
logrus.WithField("scanner", s.Name()).Debug("Scanner was ignored by filter")
return
}
r.scanners = append(r.scanners, s)
}

Expand All @@ -55,11 +59,6 @@ func (r *Library) Scan(n *number.Number) (map[string]interface{}, map[string]err
var wg sync.WaitGroup

for _, s := range r.scanners {
if r.filter.Match(s.Name()) {
logrus.WithField("scanner", s.Name()).Debug("Scanner was ignored by filter")
continue
}

wg.Add(1)
go func(s Scanner) {
defer wg.Done()
Expand Down
20 changes: 20 additions & 0 deletions lib/remote/remote_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,10 @@ func TestRemoteLibrary_PanicDryRun(t *testing.T) {

func TestRemoteLibrary_GetAllScanners(t *testing.T) {
fakeScanner := &mocks.Scanner{}
fakeScanner.On("Name").Return("fake")

fakeScanner2 := &mocks.Scanner{}
fakeScanner2.On("Name").Return("fake2")

lib := NewLibrary(filter.NewEngine())

Expand All @@ -146,3 +149,20 @@ func TestRemoteLibrary_GetAllScanners(t *testing.T) {

assert.Equal(t, []Scanner{fakeScanner, fakeScanner2}, lib.GetAllScanners())
}

func TestRemoteLibrary_AddIgnoredScanner(t *testing.T) {
fakeScanner := &mocks.Scanner{}
fakeScanner.On("Name").Return("fake")

fakeScanner2 := &mocks.Scanner{}
fakeScanner2.On("Name").Return("fake2")

f := filter.NewEngine()
f.AddRule("fake2")
lib := NewLibrary(f)

lib.AddScanner(fakeScanner)
lib.AddScanner(fakeScanner2)

assert.Equal(t, []Scanner{fakeScanner}, lib.GetAllScanners())
}
4 changes: 2 additions & 2 deletions web/v2/api/handlers/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import (
var once sync.Once
var RemoteLibrary *remote.Library

func init() {
func Init(filterEngine filter.Filter) {
once.Do(func() {
RemoteLibrary = remote.NewLibrary(filter.NewEngine())
RemoteLibrary = remote.NewLibrary(filterEngine)
remote.InitScanners(RemoteLibrary)
logrus.Debug("Scanners and plugins initialized")
})
Expand Down
14 changes: 14 additions & 0 deletions web/v2/api/handlers/init_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package handlers_test

import (
"github.com/stretchr/testify/assert"
"github.com/sundowndev/phoneinfoga/v2/lib/filter"
"github.com/sundowndev/phoneinfoga/v2/web/v2/api/handlers"
"testing"
)

func TestInit(t *testing.T) {
handlers.Init(filter.NewEngine())
assert.NotNil(t, handlers.RemoteLibrary)
assert.Greater(t, len(handlers.RemoteLibrary.GetAllScanners()), 0)
}
12 changes: 8 additions & 4 deletions web/v2/api/handlers/scanners_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ func TestGetAllScanners(t *testing.T) {
for _, tt := range testcases {
t.Run(tt.Name, func(t *testing.T) {
fakeScanner := &mocks.Scanner{}
handlers.RemoteLibrary = remote.NewLibrary(filter.NewEngine())
handlers.RemoteLibrary.AddScanner(fakeScanner)
fakeScanner.On("Name").Return("fakeScanner")
fakeScanner.On("Description").Return("fakeScanner description")
handlers.RemoteLibrary = remote.NewLibrary(filter.NewEngine())
handlers.RemoteLibrary.AddScanner(fakeScanner)

r := server.NewServer()

Expand Down Expand Up @@ -124,7 +124,9 @@ func TestDryRunScanner(t *testing.T) {
Code: 400,
Body: api.ErrorResponse{Error: "Invalid phone number: please provide an integer without any special chars"},
},
Mocks: func(s *mocks.Scanner) {},
Mocks: func(s *mocks.Scanner) {
s.On("Name").Return("fakeScanner")
},
},
{
Name: "test scanner not found",
Expand Down Expand Up @@ -240,7 +242,9 @@ func TestRunScanner(t *testing.T) {
Code: 400,
Body: api.ErrorResponse{Error: "Invalid phone number: please provide an integer without any special chars"},
},
Mocks: func(s *mocks.Scanner) {},
Mocks: func(s *mocks.Scanner) {
s.On("Name").Return("fakeScanner")
},
},
{
Name: "test scanner not found",
Expand Down