From 20daf733711bcddee513f2225ef3946d4b3fb107 Mon Sep 17 00:00:00 2001 From: Brendan Le Glaunec Date: Sun, 18 Feb 2018 19:18:05 +0100 Subject: [PATCH] Migrate cameradar server to cameradar-app repo --- Gopkg.lock | 23 ++-- server/actor/server.go | 7 - server/actor/server/mock.go | 17 --- server/actor/server/webSocket.go | 69 ---------- server/adaptor/jsonrpc2/jsonrpc2.go | 48 ------- server/adaptor/websocket.go | 8 -- server/adaptor/websocket/factoryMock.go | 33 ----- server/adaptor/websocket/gorilla.go | 107 --------------- server/adaptor/websocket/gorillaFactory.go | 120 ----------------- server/adaptor/websocket/mock.go | 62 --------- server/adaptor/websocketFactory.go | 9 -- server/main.go | 50 ------- server/service/handler.go | 137 ------------------- server/service/service.go | 146 --------------------- 14 files changed, 9 insertions(+), 827 deletions(-) delete mode 100644 server/actor/server.go delete mode 100644 server/actor/server/mock.go delete mode 100644 server/actor/server/webSocket.go delete mode 100644 server/adaptor/jsonrpc2/jsonrpc2.go delete mode 100644 server/adaptor/websocket.go delete mode 100644 server/adaptor/websocket/factoryMock.go delete mode 100644 server/adaptor/websocket/gorilla.go delete mode 100644 server/adaptor/websocket/gorillaFactory.go delete mode 100644 server/adaptor/websocket/mock.go delete mode 100644 server/adaptor/websocketFactory.go delete mode 100644 server/main.go delete mode 100644 server/service/handler.go delete mode 100644 server/service/service.go diff --git a/Gopkg.lock b/Gopkg.lock index 4e3f11d..d95b041 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -1,4 +1,11 @@ -# This fils is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + branch = "master" + name = "github.com/Ullaakut/cameradar" + packages = ["."] + revision = "7711e34b5c437adc438ab1bbb4b5c633177a4799" [[projects]] branch = "master" @@ -48,12 +55,6 @@ revision = "b32fa301c9fe55953584134cb6853a13c87ec0a1" version = "v0.16.0" -[[projects]] - name = "github.com/gorilla/websocket" - packages = ["."] - revision = "ea4d1f681babbce9545c9c5f3d5194a789c89f5b" - version = "v1.2.0" - [[projects]] branch = "master" name = "github.com/hashicorp/hcl" @@ -204,12 +205,6 @@ revision = "48a433ba4bcadc5be9aa16d4bdcb383d3f57a741" version = "v9.9.3" -[[projects]] - name = "gopkg.in/tylerb/graceful.v1" - packages = ["."] - revision = "4654dfbb6ad53cb5e27f37d99b02e16c1872fbbb" - version = "v1.2.15" - [[projects]] branch = "v2" name = "gopkg.in/yaml.v2" @@ -219,6 +214,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "b24f286ed09dfd5eb04e811c87c97622e76a8b906bac611119f4bfa2b300b537" + inputs-digest = "8edbf6b1ec61fc8dae79000a7ccfea2523471e840756e5879421fca896a0d0cb" solver-name = "gps-cdcl" solver-version = 1 diff --git a/server/actor/server.go b/server/actor/server.go deleted file mode 100644 index 143c222..0000000 --- a/server/actor/server.go +++ /dev/null @@ -1,7 +0,0 @@ -package actor - -// Server is a generic interface for creating a bidirectional -// communication server through websocket. -type Server interface { - Run() -} diff --git a/server/actor/server/mock.go b/server/actor/server/mock.go deleted file mode 100644 index b346313..0000000 --- a/server/actor/server/mock.go +++ /dev/null @@ -1,17 +0,0 @@ -package server - -import ( - "net/http" - - "github.com/stretchr/testify/mock" -) - -// Mock mocks a pubsub actor -type Mock struct { - mock.Mock -} - -// Accept mock -func (m *Mock) Accept(w http.ResponseWriter, req *http.Request) { - m.Called(w, req) -} diff --git a/server/actor/server/webSocket.go b/server/actor/server/webSocket.go deleted file mode 100644 index dbe3a6d..0000000 --- a/server/actor/server/webSocket.go +++ /dev/null @@ -1,69 +0,0 @@ -package server - -import ( - "fmt" - "net/http" - - "github.com/Ullaakut/cameradar/server/adaptor" -) - -// WebSocket manages server communication using a websocket adaptor -type WebSocket struct { - wsf adaptor.WebSocketFactory - - client adaptor.WebSocket - - fromClient chan<- string - toClient <-chan string - disconnect chan interface{} -} - -// New creates a Server actor that uses a WebSocketFactory -func New( - wsf adaptor.WebSocketFactory, - fromClient chan string, - toClient chan string, -) *WebSocket { - wsServer := &WebSocket{ - wsf: wsf, - - fromClient: fromClient, - toClient: toClient, - } - return wsServer -} - -// Accept a new incoming connection and create a websocket using the factory -func (ws *WebSocket) Accept(w http.ResponseWriter, req *http.Request) { - client, err := ws.wsf.NewIncomingWebSocket(w, req) - if err != nil { - fmt.Printf("cannot accept incoming connection: %v\n", err) - return - } - - go ws.readClient(client) -} - -func (ws *WebSocket) readClient(client adaptor.WebSocket) { - for { - select { - case message, ok := <-client.Read(): - if !ok { - // connection channel closed, disconnect client (in the main routine) - ws.disconnect <- struct{}{} - println("client disconnected") - return - } - - // expect text message - msg, ok := message.(string) - if !ok { - fmt.Printf("invalid non-text message: %v\n", message) - return - } - ws.fromClient <- msg - case msg := <-ws.toClient: - client.Write() <- msg - } - } -} diff --git a/server/adaptor/jsonrpc2/jsonrpc2.go b/server/adaptor/jsonrpc2/jsonrpc2.go deleted file mode 100644 index e5097dc..0000000 --- a/server/adaptor/jsonrpc2/jsonrpc2.go +++ /dev/null @@ -1,48 +0,0 @@ -package jsonrpc2 - -import "github.com/Ullaakut/cameradar" - -// http://www.jsonrpc.org/specification -const ( - ParseError = -32700 // Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text. - InvalidRequest = -32600 // The JSON sent is not a valid Request object. - MethodNotFound = -32601 // The method does not exist / is not available. - InvalidParams = -32602 // Invalid method parameter(s). - InternalError = -32603 // Internal JSON-RPC error. -) - -const ( - // ParseErrorMessage is the message associated with the ParseError error - ParseErrorMessage = "Parse error" - // InvalidRequestMessage is the message associated with the InvalidRequest error - InvalidRequestMessage = "Invalid Request" - // MethodNotFoundMessage is the message associated with the MethodNotFound error - MethodNotFoundMessage = "Method not found" - // InvalidParamsMessage is the message associated with the InvalidParams error - InvalidParamsMessage = "Invalid params" - // InternalErrorMessage is the message associated with the InternalError error - InternalErrorMessage = "Internal error" -) - -// Request represents a JSONRPC request -type Request struct { - JSONRPC string `json:"jsonrpc" validate:"eq=2.0"` - Method string `json:"method" validate:"required"` - Params cmrdr.Options `json:"params" validate:"required"` - ID string `json:"id"` -} - -// Response represents a JSONRPC response -type Response struct { - JSONRPC string `json:"jsonrpc" validate:"eq=2.0"` - Result []cmrdr.Stream `json:"result"` - Error Error `json:"error"` - ID string `json:"id"` -} - -// Error represents a JSONRPC response's error -type Error struct { - Code int `json:"code"` - Message string `json:"message"` - Data string `json:"data"` -} diff --git a/server/adaptor/websocket.go b/server/adaptor/websocket.go deleted file mode 100644 index 1c3227e..0000000 --- a/server/adaptor/websocket.go +++ /dev/null @@ -1,8 +0,0 @@ -package adaptor - -// WebSocket is an interface that represents an authenticated websocket connection -type WebSocket interface { - AccessToken() string - Read() <-chan interface{} - Write() chan<- interface{} -} diff --git a/server/adaptor/websocket/factoryMock.go b/server/adaptor/websocket/factoryMock.go deleted file mode 100644 index 40841e6..0000000 --- a/server/adaptor/websocket/factoryMock.go +++ /dev/null @@ -1,33 +0,0 @@ -package websocket - -import ( - "net/http" - - "github.com/Ullaakut/cameradar/server/adaptor" - - "github.com/stretchr/testify/mock" -) - -// FactoryMock mocks a websocket factory -type FactoryMock struct { - mock.Mock -} - -// NewIncomingWebSocket mocks the creation of a websocket adaptor -func (m *FactoryMock) NewIncomingWebSocket( - w http.ResponseWriter, - req *http.Request, -) (adaptor.WebSocket, error) { - args := m.Called(w, req) - return args.Get(0).(adaptor.WebSocket), args.Error(1) -} - -// NewWebSocket mocks the creation of a websocket adaptor -func (m *FactoryMock) NewWebSocket(url string) (adaptor.WebSocket, error) { - args := m.Called(url) - ws := args.Get(0) - if ws != nil { - return ws.(adaptor.WebSocket), args.Error(1) - } - return nil, args.Error(1) -} diff --git a/server/adaptor/websocket/gorilla.go b/server/adaptor/websocket/gorilla.go deleted file mode 100644 index 1c99680..0000000 --- a/server/adaptor/websocket/gorilla.go +++ /dev/null @@ -1,107 +0,0 @@ -package websocket - -import ( - "fmt" - "time" - - gorilla "github.com/gorilla/websocket" -) - -// Gorilla implements WebSocket interface using Gorilla library -type Gorilla struct { - conn *gorilla.Conn - accessToken string - - input chan interface{} - output chan interface{} -} - -// AccessToken returns the user authentication token -func (g *Gorilla) AccessToken() string { - return g.accessToken -} - -// Write return a chan to retrieve websocket inputs -func (g *Gorilla) Read() <-chan interface{} { - return g.input -} - -// Write returns a chan to write on websocket -func (g *Gorilla) Write() chan<- interface{} { - return g.output -} - -func (g *Gorilla) read(readLimit int64, pongWait time.Duration) { - defer (func() { - g.conn.Close() - close(g.input) - })() - - // setup read to timeout if no pong is received after `pongWait` - g.conn.SetReadDeadline(time.Now().Add(pongWait)) - g.conn.SetPongHandler(func(string) error { - g.conn.SetReadDeadline(time.Now().Add(pongWait)) - return nil - }) - - g.conn.SetReadLimit(readLimit) - for { - messageType, message, err := g.conn.ReadMessage() - if err != nil { - if _, ok := err.(*gorilla.CloseError); ok { - fmt.Printf("ws connection closed from %v (%v)\n", g.conn.RemoteAddr(), err) - } else { - // most of the time, a read error is not an error (connection closed, ...) - fmt.Printf("ws read error: %v\n", err) - } - break - } - - switch messageType { - case gorilla.TextMessage: - g.input <- string(message) - case gorilla.BinaryMessage: - g.input <- message - default: - fmt.Printf("received invalid message type: %v\n", messageType) - } - - } -} - -func (g *Gorilla) pingAndWrite(pingInterval time.Duration) { - defer g.conn.Close() - - pinger := time.NewTicker(pingInterval) - - for { - select { - case <-pinger.C: - if err := g.conn.WriteMessage(gorilla.PingMessage, []byte{}); err != nil { - fmt.Printf("ping write error: %v\n", err) - return - } - case message, ok := <-g.output: - if !ok { - // chan closed, stop write routine - return - } - - var err error - - switch msg := message.(type) { - case []byte: - err = g.conn.WriteMessage(gorilla.BinaryMessage, msg) - case string: - err = g.conn.WriteMessage(gorilla.TextMessage, []byte(msg)) - default: - err = fmt.Errorf("invalid message type: %T", msg) - } - - if err != nil { - fmt.Printf("write error: %v\n", err) - return - } - } - } -} diff --git a/server/adaptor/websocket/gorillaFactory.go b/server/adaptor/websocket/gorillaFactory.go deleted file mode 100644 index f6dbe83..0000000 --- a/server/adaptor/websocket/gorillaFactory.go +++ /dev/null @@ -1,120 +0,0 @@ -package websocket - -import ( - "fmt" - "net/http" - "time" - - "github.com/Ullaakut/cameradar/server/adaptor" - - gorilla "github.com/gorilla/websocket" - "github.com/pkg/errors" -) - -// GorillaFactory is a websocket Factory using Gorilla websocket client -type GorillaFactory struct { - readLimit int64 - pingInterval time.Duration - pongWait time.Duration - writeChanBufferSize uint - upgrader gorilla.Upgrader -} - -// NewGorillaFactory instantiates and returns a Gorilla Factory -func NewGorillaFactory(options ...func(*GorillaFactory)) *GorillaFactory { - gf := &GorillaFactory{ - // readLimit: default to 1MB - readLimit: 1024 * 1024, - pingInterval: 5 * time.Second, - pongWait: 10 * time.Second, - - // allow about 1 frame per grid cell to be buffered (grids contain about ~16 cameras) - // NOTE: this should be about the same size as the number of subcriptions the client has - writeChanBufferSize: 20, - - // default upgrader: don't check requests origin - upgrader: gorilla.Upgrader{ - CheckOrigin: func(r *http.Request) bool { return true }, - }, - } - // apply the options to the struct - for _, option := range options { - option(gf) - } - return gf -} - -// NewIncomingWebSocket instantiates a Gorilla websocket from an http incoming connection -func (gf *GorillaFactory) NewIncomingWebSocket(w http.ResponseWriter, req *http.Request) (adaptor.WebSocket, error) { - fmt.Printf("new ws connection from %v\n", req.RemoteAddr) - - // create WS connection - conn, err := gf.upgrader.Upgrade(w, req, nil) - if err != nil { - return nil, errors.Wrap(err, "cannot upgrade ws connection") - } - - g := &Gorilla{ - conn: conn, - accessToken: req.Header.Get("Sec-WebSocket-Protocol"), - - input: make(chan interface{}), - output: make(chan interface{}, gf.writeChanBufferSize), - } - - go g.pingAndWrite(gf.pingInterval) - go g.read(gf.readLimit, gf.pongWait) - - return g, nil -} - -// NewWebSocket attempts to connect to a ws server using Gorilla library -func (gf *GorillaFactory) NewWebSocket(url string) (adaptor.WebSocket, error) { - fmt.Printf("opening new ws connection to %v\n", url) - - // create WS connection - conn, _, err := gorilla.DefaultDialer.Dial(url, nil) - if err != nil { - return nil, errors.Wrap(err, "cannot open ws connection") - } - - g := &Gorilla{ - conn: conn, - - input: make(chan interface{}), - output: make(chan interface{}, gf.writeChanBufferSize), - } - - go g.pingAndWrite(gf.pingInterval) - go g.read(gf.readLimit, gf.pongWait) - - return g, nil -} - -// SetReadLimit sets the maximum size read from an incoming message -func SetReadLimit(limit int64) func(gf *GorillaFactory) { - return func(gf *GorillaFactory) { - gf.readLimit = limit - } -} - -// SetPingInterval sets the interval between pings -func SetPingInterval(interval time.Duration) func(gf *GorillaFactory) { - return func(gf *GorillaFactory) { - gf.pingInterval = interval - } -} - -// SetPongWait sets the time before read should timeout if no pong is received -func SetPongWait(pongWait time.Duration) func(gf *GorillaFactory) { - return func(gf *GorillaFactory) { - gf.pongWait = pongWait - } -} - -// SetWriteChanBufferSize sets the buffer size of the write channel -func SetWriteChanBufferSize(size uint) func(gf *GorillaFactory) { - return func(gf *GorillaFactory) { - gf.writeChanBufferSize = size - } -} diff --git a/server/adaptor/websocket/mock.go b/server/adaptor/websocket/mock.go deleted file mode 100644 index cc69123..0000000 --- a/server/adaptor/websocket/mock.go +++ /dev/null @@ -1,62 +0,0 @@ -package websocket - -import ( - "github.com/stretchr/testify/mock" -) - -// Mock mocks a websocket adaptor -type Mock struct { - mock.Mock - - Token string - ReadChan chan interface{} - WriteChan chan interface{} -} - -// NewMock create a new websocket adaptor mock, with helper read/write -// chans already created -func NewMock(accessToken string, writeChanBuffer uint) *Mock { - return &Mock{ - Token: accessToken, - ReadChan: make(chan interface{}), - WriteChan: make(chan interface{}, writeChanBuffer), - } -} - -// AccessToken mocks token getter -func (m *Mock) AccessToken() string { - args := m.Called() - return args.String(0) -} - -// OnAccessToken is a helper method to setup an "AccessToken()" handler -// with the mock accessToken -func (m *Mock) OnAccessToken() *mock.Call { - return m.On("AccessToken").Return(m.Token) -} - -// Read mocks read channel getter -func (m *Mock) Read() <-chan interface{} { - args := m.Called() - return args.Get(0).(<-chan interface{}) -} - -// OnRead is a helper method to setup a "Read()" handler -// with the mock readChan -func (m *Mock) OnRead() *mock.Call { - var readOnlyChan <-chan interface{} = m.ReadChan - return m.On("Read").Return(readOnlyChan) -} - -// Write mocks write channel getter -func (m *Mock) Write() chan<- interface{} { - args := m.Called() - return args.Get(0).(chan<- interface{}) -} - -// OnWrite is a helper method to setup a "Write()" handler -// with the mock writeChan -func (m *Mock) OnWrite() *mock.Call { - var writeOnlyChan chan<- interface{} = m.WriteChan - return m.On("Write").Return(writeOnlyChan) -} diff --git a/server/adaptor/websocketFactory.go b/server/adaptor/websocketFactory.go deleted file mode 100644 index a3ccb85..0000000 --- a/server/adaptor/websocketFactory.go +++ /dev/null @@ -1,9 +0,0 @@ -package adaptor - -import "net/http" - -// WebSocketFactory is an interface for creating generic websocket connections -type WebSocketFactory interface { - NewIncomingWebSocket(w http.ResponseWriter, req *http.Request) (WebSocket, error) - NewWebSocket(url string) (WebSocket, error) -} diff --git a/server/main.go b/server/main.go deleted file mode 100644 index 4fa9c4a..0000000 --- a/server/main.go +++ /dev/null @@ -1,50 +0,0 @@ -package main - -import ( - "fmt" - "net/http" - "os" - - "github.com/Ullaakut/cameradar/server/actor/server" - "github.com/Ullaakut/cameradar/server/adaptor/websocket" - "github.com/Ullaakut/cameradar/server/service" - graceful "gopkg.in/tylerb/graceful.v1" -) - -func main() { - webSocketFactory := websocket.NewGorillaFactory() - fromClient := make(chan string) - toClient := make(chan string) - - server := server.New(webSocketFactory, fromClient, toClient) - - _, err := service.New( - "/Users/ullaakut/Work/go/src/github.com/Ullaakut/cameradar/dictionaries/routes", - "/Users/ullaakut/Work/go/src/github.com/Ullaakut/cameradar/dictionaries/credentials.json", - fromClient, - toClient, - ) - if err != nil { - fmt.Printf("could not start service: %v", err) - os.Exit(1) - } - - // create and setup the http server - serverMux := http.NewServeMux() - serverMux.HandleFunc("/", server.Accept) - - httpServer := &graceful.Server{ - NoSignalHandling: true, - Server: &http.Server{ - Addr: fmt.Sprintf("%v:%v", "0.0.0.0", 7000), - Handler: serverMux, - }, - } - - fmt.Printf("cameradar server listening on %v\n", httpServer.Addr) - err = httpServer.ListenAndServe() - if err != nil { - fmt.Printf("could not start server: %v\n", err) - os.Exit(1) - } -} diff --git a/server/service/handler.go b/server/service/handler.go deleted file mode 100644 index 0b4cab7..0000000 --- a/server/service/handler.go +++ /dev/null @@ -1,137 +0,0 @@ -package service - -import ( - "encoding/json" - "fmt" - - "github.com/Ullaakut/cameradar" - "github.com/Ullaakut/cameradar/server/adaptor/jsonrpc2" - v "gopkg.in/go-playground/validator.v9" -) - -func (c *Cameradar) handleRequest(message string) { - var ret []cmrdr.Stream - var JSONRPCErr jsonrpc2.Error - - var request jsonrpc2.Request - err := json.Unmarshal([]byte(message), &request) - if err != nil { - JSONRPCErr = jsonrpc2.Error{ - Code: jsonrpc2.ParseError, - Message: jsonrpc2.ParseErrorMessage, - Data: err.Error(), - } - c.respondToClient(ret, "", JSONRPCErr) - return - } - - validate := v.New() - err = validate.Struct(request) - if err != nil { - JSONRPCErr = jsonrpc2.Error{ - Code: jsonrpc2.InvalidRequest, - Message: jsonrpc2.InvalidRequestMessage, - Data: err.Error(), - } - c.respondToClient(ret, request.ID, JSONRPCErr) - return - } - - c.SetOptions(request.Params) - - switch request.Method { - case "discover": - ret, err = c.Discover() - case "attack_credentials": - ret, err = c.AttackCredentials() - case "attack_route": - ret, err = c.AttackRoute() - case "discover_and_attack": - c.discoverAndAttack(request.ID) - return - default: - JSONRPCErr = jsonrpc2.Error{ - Code: jsonrpc2.MethodNotFound, - Message: jsonrpc2.MethodNotFoundMessage, - Data: "method" + request.Method + "not found", - } - } - if err != nil { - JSONRPCErr = jsonrpc2.Error{ - Code: jsonrpc2.InternalError, - Message: jsonrpc2.InternalErrorMessage, - Data: err.Error(), - } - } - - c.respondToClient(ret, request.ID, JSONRPCErr) -} - -func (c *Cameradar) discoverAndAttack(ID string) { - var JSONRPCErr jsonrpc2.Error - - streams, err := c.Discover() - if err != nil { - c.respondToClient(streams, ID, jsonrpc2.Error{ - Code: jsonrpc2.InternalError, - Message: jsonrpc2.InternalErrorMessage, - Data: err.Error(), - }) - return - } - c.respondToClient(streams, ID, JSONRPCErr) - - streams, err = c.AttackRoute() - if err != nil { - c.respondToClient(streams, ID, jsonrpc2.Error{ - Code: jsonrpc2.InternalError, - Message: jsonrpc2.InternalErrorMessage, - Data: err.Error(), - }) - return - } - c.respondToClient(streams, ID, JSONRPCErr) - - streams, err = c.AttackCredentials() - if err != nil { - c.respondToClient(streams, ID, jsonrpc2.Error{ - Code: jsonrpc2.InternalError, - Message: jsonrpc2.InternalErrorMessage, - Data: err.Error(), - }) - return - } - c.respondToClient(streams, ID, JSONRPCErr) - - for _, stream := range streams { - if stream.RouteFound == false { - streams, err = c.AttackCredentials() - if err != nil { - c.respondToClient(streams, ID, jsonrpc2.Error{ - Code: jsonrpc2.InternalError, - Message: jsonrpc2.InternalErrorMessage, - Data: err.Error(), - }) - return - } - c.respondToClient(streams, ID, JSONRPCErr) - return - } - } -} - -func (c *Cameradar) respondToClient(result []cmrdr.Stream, ID string, JSONRPCErr jsonrpc2.Error) { - r := jsonrpc2.Response{ - JSONRPC: "2.0", - Result: result, - Error: JSONRPCErr, - ID: ID, - } - - response, err := json.Marshal(r) - if err != nil { - c.toClient <- "{\"jsonrpc\": \"2.0\",\"result\":null,\"error\":{\"code\":" + fmt.Sprint(jsonrpc2.InternalError) + ",\"" + jsonrpc2.InternalErrorMessage + "\",\"data\":\"could not marshal response\"},\"id\":\"" + ID + "\"}" - } - - c.toClient <- string(response) -} diff --git a/server/service/service.go b/server/service/service.go deleted file mode 100644 index fe083e1..0000000 --- a/server/service/service.go +++ /dev/null @@ -1,146 +0,0 @@ -package service - -import ( - "fmt" - "time" - - "github.com/Ullaakut/cameradar" - "github.com/pkg/errors" -) - -// Cameradar is the service in charge of communicating with the GUI -type Cameradar struct { - Streams []cmrdr.Stream - - options *cmrdr.Options - - toClient chan<- string - fromClient <-chan string -} - -// New instanciates a new Cameradar service -func New(routesFilePath, credentialsFilePath string, fromClient <-chan string, toClient chan<- string) (*Cameradar, error) { - routes, err := cmrdr.LoadRoutes(routesFilePath) - if err != nil { - return nil, errors.Wrap(err, "can't load routes dictionary") - } - - credentials, err := cmrdr.LoadCredentials(credentialsFilePath) - if err != nil { - return nil, errors.Wrap(err, "can't load credentials dictionary") - } - - cameradar := &Cameradar{ - Streams: nil, - options: &cmrdr.Options{ - Ports: "554,8554", - Routes: routes, - Credentials: credentials, - OutputFile: "/tmp/cameradar_nmap_result.xml", - Speed: 4, - Timeout: 2000, - }, - - fromClient: fromClient, - toClient: toClient, - } - - go cameradar.Run() - return cameradar, nil -} - -// Run launches the service that will automatically call the service methods -// using the instructions received over websocket -func (c *Cameradar) Run() { - for { - msg := <-c.fromClient - go c.handleRequest(msg) - } -} - -// Discover launches a Cameradar scan using the service's options -func (c *Cameradar) Discover() ([]cmrdr.Stream, error) { - streams, err := cmrdr.Discover(c.options.Target, c.options.Ports, c.options.OutputFile, c.options.Speed, true) - if err != nil { - return streams, errors.Wrap(err, "could not discover streams") - } - c.Streams = streams - return streams, nil -} - -// AttackRoute launches a Cameradar route attack using the service's options -func (c *Cameradar) AttackRoute() ([]cmrdr.Stream, error) { - streams, err := cmrdr.AttackRoute(c.Streams, c.options.Routes, c.options.Timeout, true) - if err != nil { - return streams, errors.Wrap(err, "could not discover streams") - } - c.Streams = streams - return streams, nil -} - -// AttackCredentials launches a Cameradar credential attack using the service's options -func (c *Cameradar) AttackCredentials() ([]cmrdr.Stream, error) { - streams, err := cmrdr.AttackCredentials(c.Streams, c.options.Credentials, c.options.Timeout, true) - if err != nil { - return streams, errors.Wrap(err, "could not discover streams") - } - c.Streams = streams - return streams, nil -} - -// SetOptions sets all options using an option structure -func (c *Cameradar) SetOptions(options cmrdr.Options) { - c.options.Target = options.Target - - if len(options.Ports) > 0 { - c.options.Ports = options.Ports - } - - if len(options.OutputFile) > 0 { - c.options.OutputFile = options.OutputFile - } - - // TODO: Add custom dictionary support through ws - - c.SetSpeed(options.Speed) - - c.SetTimeout(options.Timeout) -} - -// SetNmapOutputFile sets the OutputFile option -func (c *Cameradar) SetNmapOutputFile(path string) { - c.options.OutputFile = path -} - -// SetRoutes overwrites the routes dictionary with new values -func (c *Cameradar) SetRoutes(routes string) { - c.options.Routes = cmrdr.ParseRoutesFromString(routes) -} - -// SetCredentials overwrites the routes dictionary with new values -func (c *Cameradar) SetCredentials(credentials string) error { - newCredentials, err := cmrdr.ParseCredentialsFromString(credentials) - if err != nil { - return errors.Wrap(err, "could not decode credentials") - } - c.options.Credentials = newCredentials - return nil -} - -// SetSpeed sets the Speed option -func (c *Cameradar) SetSpeed(speed int) error { - if speed < cmrdr.PARANOIAC || speed > cmrdr.INSANE { - return fmt.Errorf("invalid speed value '%d'. should be between '%d' and '%d'", speed, cmrdr.PARANOIAC, cmrdr.INSANE) - } - c.options.Speed = speed - return nil -} - -// SetTimeout sets the Timeout option -func (c *Cameradar) SetTimeout(timeout time.Duration) error { - if timeout < 0 { - return fmt.Errorf("invalid timeout value '%d'. should be superior to 0", timeout) - } - c.options.Timeout = time.Millisecond * time.Duration(timeout) - return nil -}