diff --git a/cmd/scan.go b/cmd/scan.go index a37707d5d..3e006dcd5 100644 --- a/cmd/scan.go +++ b/cmd/scan.go @@ -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") diff --git a/cmd/serve.go b/cmd/serve.go index 490bb5fcb..f3679cc7e 100644 --- a/cmd/serve.go +++ b/cmd/serve.go @@ -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) + } + }, + } } diff --git a/docs/getting-started/scanners.md b/docs/getting-started/scanners.md index 431aaa9dd..d7a3829f0 100644 --- a/docs/getting-started/scanners.md +++ b/docs/getting-started/scanners.md @@ -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 diff --git a/lib/remote/remote.go b/lib/remote/remote.go index 9d8d4a44b..40ee543c3 100644 --- a/lib/remote/remote.go +++ b/lib/remote/remote.go @@ -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) } @@ -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() diff --git a/lib/remote/remote_test.go b/lib/remote/remote_test.go index b1135bf0f..3d9dc9cd1 100644 --- a/lib/remote/remote_test.go +++ b/lib/remote/remote_test.go @@ -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()) @@ -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()) +} diff --git a/web/v2/api/handlers/init.go b/web/v2/api/handlers/init.go index ddd6d5877..48b3dbcf2 100644 --- a/web/v2/api/handlers/init.go +++ b/web/v2/api/handlers/init.go @@ -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") }) diff --git a/web/v2/api/handlers/init_test.go b/web/v2/api/handlers/init_test.go new file mode 100644 index 000000000..a6f365ab7 --- /dev/null +++ b/web/v2/api/handlers/init_test.go @@ -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) +} diff --git a/web/v2/api/handlers/scanners_test.go b/web/v2/api/handlers/scanners_test.go index 3c45dbbb9..9cc67c564 100644 --- a/web/v2/api/handlers/scanners_test.go +++ b/web/v2/api/handlers/scanners_test.go @@ -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() @@ -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", @@ -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",