diff --git a/go.mod b/go.mod index 1fdd067..f662b5d 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.16 require ( github.com/btcsuite/btcutil v1.0.2 + github.com/cespare/reflex v0.3.0 // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/olivere/elastic/v7 v7.0.24 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 // indirect diff --git a/go.sum b/go.sum index b99b06c..215e187 100644 --- a/go.sum +++ b/go.sum @@ -13,9 +13,13 @@ github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/reflex v0.3.0 h1:9q8ZXMh+oW4quohPBcLsT56TFl4/DeQsTjZASe4wgoY= +github.com/cespare/reflex v0.3.0/go.mod h1:I+0Pnu2W693i7Hv6ZZG76qHTY0mgUa7uCIfCtikXojE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw= +github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -25,6 +29,7 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -59,9 +64,16 @@ github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfC github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/ogier/pflag v0.0.1 h1:RW6JSWSu/RkSatfcLtogGfFgpim5p7ARQ10ECk5O750= +github.com/ogier/pflag v0.0.1/go.mod h1:zkFki7tvTa0tafRvTBIZTvzYyAu6kQhPZFnshFFPE+g= github.com/olivere/elastic/v7 v7.0.24 h1:9ZcCQP3Pvgese7TaypYiVAL49sCEphyIwkVxtRf8jb8= github.com/olivere/elastic/v7 v7.0.24/go.mod h1:OuWmD2DiuYhddWegBKPWQuelVKBLrW0fa/VUYgxuGTY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= diff --git a/main.go b/main.go index 30dc10c..5624942 100644 --- a/main.go +++ b/main.go @@ -16,11 +16,29 @@ import ( ) const ( - port = ":50051" + defaultPort = "50051" + defaultRPCUser = "rpcuser" + defaultRPCPassword = "rpcpassword" ) -func parseArgs(searchRequest *pb.SearchRequest) { - query:= flag.String("query", "", "query string") +type loginCreds struct { + Username, Password string +} + +func (c *loginCreds) GetRequestMetadata(context.Context, ...string) (map[string]string, error) { + return map[string]string{ + "username": c.Username, + "password": c.Password, + }, nil +} + +func (c *loginCreds) RequireTransportSecurity() bool { + return false +} + + +func parseArgs(searchRequest *pb.SearchRequest) server.Args { + query := flag.String("query", "", "query string") claimType := flag.String("claimType", "", "claim type") id := flag.String("id", "", "_id") author := flag.String("author", "", "author") @@ -28,6 +46,10 @@ func parseArgs(searchRequest *pb.SearchRequest) { channelName := flag.String("channelName", "", "channel name") description := flag.String("description", "", "description") + port := flag.String("rpcport", defaultPort, "port") + user := flag.String("rpcuser", defaultRPCUser, "username") + pass := flag.String("rpcpassword", defaultRPCPassword, "password") + flag.Parse() if *query != "" { @@ -51,16 +73,31 @@ func parseArgs(searchRequest *pb.SearchRequest) { if *description != "" { searchRequest.Description = []string{*description} } + + + return server.Args{Port: ":" + *port, User: *user, Pass: *pass} +} + +func parseServerArgs() server.Args { + port := flag.String("rpcport", defaultPort, "port") + user := flag.String("rpcuser", defaultRPCUser, "username") + pass := flag.String("rpcpassword", defaultRPCPassword, "password") + + flag.Parse() + + return server.Args{Port: ":" + *port, User: *user, Pass: *pass} } func main() { if len(os.Args) == 2 && os.Args[1] == "serve" { - l, err := net.Listen("tcp", port) + args := parseServerArgs() + + l, err := net.Listen("tcp", args.Port) if err != nil { log.Fatalf("failed to listen: %v", err) } - s := grpc.NewServer() + s := server.MakeHubServer(args) pb.RegisterHubServer(s, &server.Server{}) log.Printf("listening on %s\n", l.Addr().String()) @@ -70,7 +107,18 @@ func main() { return } - conn, err := grpc.Dial("localhost"+port, grpc.WithInsecure(), grpc.WithBlock()) + searchRequest := &pb.SearchRequest{} + + args := parseArgs(searchRequest) + + conn, err := grpc.Dial("localhost"+args.Port, + grpc.WithInsecure(), + //grpc.WithBlock(), + grpc.WithPerRPCCredentials(&loginCreds{ + Username: args.User, + Password: args.Pass, + }), + ) if err != nil { log.Fatalf("did not connect: %v", err) } @@ -91,9 +139,6 @@ func main() { ctx, cancel := context.WithTimeout(context.Background(), time.Second) defer cancel() - searchRequest := &pb.SearchRequest{} - - parseArgs(searchRequest) r, err := c.Search(ctx, searchRequest) if err != nil { diff --git a/server/server.go b/server/server.go index 2be839d..1d40d93 100644 --- a/server/server.go +++ b/server/server.go @@ -1,13 +1,32 @@ package server import ( + "context" pb "github.com/lbryio/hub/protobuf/go" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" ) type Server struct { pb.UnimplementedHubServer } +type Args struct { + Port string + User string + Pass string +} + +type AccessDeniedErr struct {} +func (AccessDeniedErr) Error() string { + return "Username or password incorrect." +} + +type EmptyMetadataErr struct {} +func (EmptyMetadataErr) Error() string { + return "No username or password specified." +} + /* 'blockchain.block.get_chunk' 'blockchain.block.get_header' @@ -46,3 +65,48 @@ type Server struct { 'blockchain.address.subscribe' 'blockchain.address.unsubscribe' */ + +func MakeHubServer(args Args) *grpc.Server { + authorize := makeAuthorizeFunc(args.User, args.Pass) + return grpc.NewServer( + grpc.StreamInterceptor(makeStreamInterceptor(authorize)), + grpc.UnaryInterceptor(makeUnaryInterceptor(authorize)), + ) +} + +func makeStreamInterceptor(authorize func(context.Context) error) func(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error { + return func(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error { + if err := authorize(stream.Context()); err != nil { + return err + } + + return handler(srv, stream) + } +} + + +func makeUnaryInterceptor(authorize func(context.Context) error) func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { + return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { + if err := authorize(ctx); err != nil { + return nil, err + } + + return handler(ctx, req) + } +} + +func makeAuthorizeFunc(username string, password string) func(context.Context) error { + + return func(ctx context.Context) error { + if md, ok := metadata.FromIncomingContext(ctx); ok { + if len(md["username"]) > 0 && md["username"][0] == username && + len(md["password"]) > 0 && md["password"][0] == password { + return nil + } + + return AccessDeniedErr{} + } + + return EmptyMetadataErr{} + } +}