package service import ( "context" "crypto/tls" "encoding/json" "fmt" "net" "helmet/app/logger" "helmet/app/handler" "helmet/app/operator" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials" "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" ) type ServiceConfig struct { Handler *handler.Handler Operator *operator.Operator PortNum uint32 Hostname string X509Cert []byte X509Key []byte } type Service struct { gsrv *grpc.Server hand *handler.Handler oper *operator.Operator log *logger.Logger portnum uint32 hostname string username string password string x509Cert []byte x509Key []byte } func NewService(conf *ServiceConfig) *Service { svc := Service{ hand: conf.Handler, oper: conf.Operator, portnum: conf.PortNum, hostname: conf.Hostname, x509Cert: conf.X509Cert, x509Key: conf.X509Key, } svc.log = logger.NewLogger("service") return &svc } func (svc *Service) Run() error { var err error svc.log.Infof("Service run") listenSpec := fmt.Sprintf(":%d", svc.portnum) listener, err := net.Listen("tcp", listenSpec) if err != nil { return err } tlsCert, err := tls.X509KeyPair(svc.x509Cert, svc.x509Key) if err != nil { return err } tlsConfig := tls.Config{ Certificates: []tls.Certificate{tlsCert}, ClientAuth: tls.NoClientCert, InsecureSkipVerify: true, } tlsCredentials := credentials.NewTLS(&tlsConfig) if err != nil { return err } interceptors := []grpc.UnaryServerInterceptor{ svc.authInterceptor, svc.logInterceptor, } gsrvOpts := []grpc.ServerOption{ grpc.Creds(tlsCredentials), grpc.ChainUnaryInterceptor(interceptors...), //grpc.UnaryInterceptor(svc.authInterceptor), } svc.gsrv = grpc.NewServer(gsrvOpts...) svc.hand.Register(svc.gsrv) svc.log.Infof("Service listening at %v", listener.Addr()) err = svc.gsrv.Serve(listener) if err != nil { return err } return err } func (svc *Service) authInterceptor(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) { meta, _ := metadata.FromIncomingContext(ctx) usernameArr := meta["username"] passwordArr := meta["password"] if len(usernameArr) == 0 || len(passwordArr) == 0 { err := status.Errorf(codes.PermissionDenied, "Empty auth data") return nil, err } username := meta["username"][0] password := meta["password"][0] if !svc.oper.ValidateUser(username, password) { err := status.Errorf(codes.PermissionDenied, "Incorrect auth data") return nil, err } return handler(ctx, req) } func (svc *Service) logInterceptor(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) { var err error svc.log.Debugf("Called method: %v", info.FullMethod) reqData, err := json.Marshal(req) if err == nil { svc.log.Debugf("Request: %s", string(reqData)) } return handler(ctx, req) } func (svc *Service) Stop() { svc.log.Infof("Stopping service") svc.gsrv.GracefulStop() }