This commit is contained in:
2023-09-19 11:06:20 +02:00
parent da86ee374a
commit 4a6326a5ab
13 changed files with 775 additions and 1251 deletions

View File

@@ -2,14 +2,31 @@ package grpcserver
import (
"context"
"encoding/base64"
"encoding/json"
grpcproto "git.coopgo.io/coopgo-apps/silvermobi/servers/grpcapi/proto"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
"strings"
"time"
)
func (s SilvermobiGRPCService) SetPhoneNumber(ctx context.Context, req *grpcproto.SetPhoneNumberRequest) (res *grpcproto.SetPhoneNumberResponse, err error) {
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return nil, status.Errorf(codes.Unauthenticated, "Missing metadata")
}
authHeader, ok := md["authorization"]
if !ok || len(authHeader) == 0 {
return nil, status.Errorf(codes.Unauthenticated, "Missing authorization header")
}
tokenString := strings.TrimPrefix(authHeader[0], "Bearer ")
id := ExtractIdFromToken(tokenString)
if err = s.Handler.UpdatePhoneNumber(
context.Background(),
req.Email,
id,
req.PhoneNumber,
); err != nil {
return nil, err
@@ -19,10 +36,20 @@ func (s SilvermobiGRPCService) SetPhoneNumber(ctx context.Context, req *grpcprot
}
func (s SilvermobiGRPCService) VerifyPhoneNumber(ctx context.Context, req *grpcproto.VerifyPhoneNumberRequest) (res *grpcproto.VerifyPhoneNumberResponse, err error) {
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return nil, status.Errorf(codes.Unauthenticated, "Missing metadata")
}
authHeader, ok := md["authorization"]
if !ok || len(authHeader) == 0 {
return nil, status.Errorf(codes.Unauthenticated, "Missing authorization header")
}
tokenString := strings.TrimPrefix(authHeader[0], "Bearer ")
id := ExtractIdFromToken(tokenString)
if err = s.Handler.VerifyPhoneNumber(
context.Background(),
req.Email,
id,
req.PhoneNumber,
req.VerificationCode,
); err != nil {
@@ -33,23 +60,126 @@ func (s SilvermobiGRPCService) VerifyPhoneNumber(ctx context.Context, req *grpcp
}
func (s SilvermobiGRPCService) SetBirthDate(ctx context.Context, req *grpcproto.BirthDateRequest) (res *grpcproto.BirthDateResponse, err error) {
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return nil, status.Errorf(codes.Unauthenticated, "Missing metadata")
}
authHeader, ok := md["authorization"]
if !ok || len(authHeader) == 0 {
return nil, status.Errorf(codes.Unauthenticated, "Missing authorization header")
}
tokenString := strings.TrimPrefix(authHeader[0], "Bearer ")
id := ExtractIdFromToken(tokenString)
birthdate := time.Unix(req.Birthdate.Seconds, int64(req.Birthdate.Nanos)).UTC()
birthdateString := birthdate.Format("2006-01-02T15:04:05Z")
if err = s.Handler.UpdateBirthDate(ctx, req.Email, birthdateString); err != nil {
if err = s.Handler.UpdateBirthDate(ctx, id, birthdateString); err != nil {
return nil, err
}
return &grpcproto.BirthDateResponse{
Ok: true,
}, nil
}
func (s SilvermobiGRPCService) SetAccountType(ctx context.Context, req *grpcproto.AccountTypeRequest) (res *grpcproto.AccountTypeResponse, err error) {
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return nil, status.Errorf(codes.Unauthenticated, "Missing metadata")
}
authHeader, ok := md["authorization"]
if !ok || len(authHeader) == 0 {
return nil, status.Errorf(codes.Unauthenticated, "Missing authorization header")
}
tokenString := strings.TrimPrefix(authHeader[0], "Bearer ")
id := ExtractIdFromToken(tokenString)
if req.GetType() != grpcproto.AccountTypeRequest_PASSENGER && req.GetType() != grpcproto.AccountTypeRequest_DRIVER {
return nil, status.Errorf(codes.InvalidArgument, "Type should be PASSENGER or DRIVER")
}
if err = s.Handler.SetAccountType(ctx, id, req.GetType().String()); err != nil {
return nil, err
}
return &grpcproto.AccountTypeResponse{
Ok: true,
}, nil
}
func (s SilvermobiGRPCService) GetAccountType(ctx context.Context, req *grpcproto.AccountTypeRequest) (res *grpcproto.AccountTypeResponse, err error) {
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return nil, status.Errorf(codes.Unauthenticated, "Missing metadata")
}
authHeader, ok := md["authorization"]
if !ok || len(authHeader) == 0 {
return nil, status.Errorf(codes.Unauthenticated, "Missing authorization header")
}
tokenString := strings.TrimPrefix(authHeader[0], "Bearer ")
id := ExtractIdFromToken(tokenString)
if req.Request == nil || !*req.Request {
return nil, status.Errorf(codes.InvalidArgument, "request arg should be true")
}
account_type, err := s.Handler.GetAccountType(ctx, id)
if err != nil {
return nil, err
}
var responseType grpcproto.AccountTypeResponse_AccountType
switch account_type {
case "PASSENGER":
responseType = grpcproto.AccountTypeResponse_PASSENGER
case "DRIVER":
responseType = grpcproto.AccountTypeResponse_DRIVER
default:
return nil, status.Errorf(codes.InvalidArgument, "Invalid account type")
}
response := &grpcproto.AccountTypeResponse{
Type: &responseType,
}
return response, nil
}
func (s SilvermobiGRPCService) GetValidation(ctx context.Context, req *grpcproto.ValidationRequest) (res *grpcproto.ValidationResponse, err error) {
phone_validation, birth_validation, err := s.Handler.CheckValidation(ctx, req.Email)
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return nil, status.Errorf(codes.Unauthenticated, "Missing metadata")
}
authHeader, ok := md["authorization"]
if !ok || len(authHeader) == 0 {
return nil, status.Errorf(codes.Unauthenticated, "Missing authorization header")
}
tokenString := strings.TrimPrefix(authHeader[0], "Bearer ")
id := ExtractIdFromToken(tokenString)
phone_validation, birth_validation, type_validation, err := s.Handler.CheckValidation(ctx, id)
if err != nil {
return nil, err
}
return &grpcproto.ValidationResponse{
Phone: phone_validation,
Birthdate: birth_validation,
Type: type_validation,
}, nil
}
func ExtractIdFromToken(tokenString string) string {
parts := strings.Split(tokenString, ".")
if len(parts) != 3 {
return ""
}
payloadBytes, err := base64.RawStdEncoding.DecodeString(parts[1])
if err != nil {
return ""
}
var payloadMap map[string]interface{}
if err := json.Unmarshal(payloadBytes, &payloadMap); err != nil {
return ""
}
id, ok := payloadMap["sub"].(string)
if !ok {
return ""
}
return id
}

View File

@@ -2,9 +2,6 @@ package grpcserver
import (
"context"
"net"
"strings"
"git.coopgo.io/coopgo-apps/silvermobi/handler"
grpcproto "git.coopgo.io/coopgo-apps/silvermobi/servers/grpcapi/proto"
"github.com/golang-jwt/jwt/v4"
@@ -14,6 +11,9 @@ import (
"github.com/rs/zerolog/log"
"github.com/spf13/viper"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"net"
)
type contextKey string
@@ -22,53 +22,25 @@ var (
contextKeyUser = contextKey("user")
)
type SilvermobiGRPCService struct {
Config *viper.Viper
Handler *handler.SilvermobiHandler
grpcproto.UnimplementedSilvermobiGRPCServer
}
func NewSilvermobiGRPCService(cfg *viper.Viper, handler *handler.SilvermobiHandler) SilvermobiGRPCService {
return SilvermobiGRPCService{
Config: cfg,
Handler: handler,
}
}
func Run(done chan error, cfg *viper.Viper, handler *handler.SilvermobiHandler) {
var (
address = "127.0.0.1:" + cfg.GetString("services.external.grpc.port")
jwt_secret = cfg.GetString("identification.local.jwt_secret")
)
log.Info().Msg("GRPC server on " + address)
server := grpc.NewServer(
grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(
grpc_ctxtags.StreamServerInterceptor(),
StreamAuthServerInterceptor(GRPCAuthFunc(jwt_secret)),
)),
grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(
grpc_ctxtags.UnaryServerInterceptor(),
UnaryAuthServerInterceptor(GRPCAuthFunc(jwt_secret)),
)),
)
grpcproto.RegisterSilvermobiGRPCServer(server, NewSilvermobiGRPCService(cfg, handler))
l, err := net.Listen("tcp", address)
if err != nil {
log.Fatal().Err(err)
func NoAuth(method string) bool {
noAuthMethods := []string{
"/SilvermobiGRPC/ForgetAccount",
"/SilvermobiGRPC/UpdatePassword",
"/SilvermobiGRPC/AuthRegister",
"/SilvermobiGRPC/AuthLogin",
}
if err := server.Serve(l); err != nil {
log.Error().Err(err).Msg("gRPC service ended")
done <- err
for _, m := range noAuthMethods {
if method == m {
return true
}
}
return false
}
func UnaryAuthServerInterceptor(authFunc grpc_auth.AuthFunc) grpc.UnaryServerInterceptor {
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
print(info.FullMethod)
if NoAuth(info.FullMethod) {
return handler(ctx, req)
}
@@ -81,7 +53,6 @@ func UnaryAuthServerInterceptor(authFunc grpc_auth.AuthFunc) grpc.UnaryServerInt
return handler(newCtx, req)
}
}
func StreamAuthServerInterceptor(authFunc grpc_auth.AuthFunc) grpc.StreamServerInterceptor {
return func(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
if NoAuth(info.FullMethod) {
@@ -101,25 +72,65 @@ func StreamAuthServerInterceptor(authFunc grpc_auth.AuthFunc) grpc.StreamServerI
}
}
type SilvermobiGRPCService struct {
Config *viper.Viper
Handler *handler.SilvermobiHandler
grpcproto.UnimplementedSilvermobiGRPCServer
}
func NewSilvermobiGRPCService(cfg *viper.Viper, handler *handler.SilvermobiHandler) SilvermobiGRPCService {
return SilvermobiGRPCService{
Config: cfg,
Handler: handler,
}
}
func Run(done chan error, cfg *viper.Viper, handler *handler.SilvermobiHandler) {
var (
address = "0.0.0.0:" + cfg.GetString("services.external.grpc.port")
jwt_secret = cfg.GetString("identification.local.jwt_secret")
)
log.Info().Msg("GRPC server on " + address)
server := grpc.NewServer(
grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(
grpc_ctxtags.StreamServerInterceptor(),
StreamAuthServerInterceptor(GRPCAuthFunc(jwt_secret)),
)),
grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(
grpc_ctxtags.UnaryServerInterceptor(),
UnaryAuthServerInterceptor(GRPCAuthFunc(jwt_secret)),
)),
)
service := NewSilvermobiGRPCService(cfg, handler)
grpcproto.RegisterSilvermobiGRPCServer(server, service)
l, err := net.Listen("tcp", address)
if err != nil {
log.Fatal().Err(err)
}
if err := server.Serve(l); err != nil {
log.Error().Err(err).Msg("gRPC service ended")
done <- err
}
}
func GRPCAuthFunc(jwtKey string) grpc_auth.AuthFunc {
return func(ctx context.Context) (context.Context, error) {
tokenString, err := grpc_auth.AuthFromMD(ctx, "bearer")
if err != nil {
log.Error().Err(err)
return nil, err
}
claims := jwt.MapClaims{}
jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
return []byte(jwtKey), nil
})
if err != nil || !token.Valid {
return nil, status.Errorf(codes.Unauthenticated, "Invalid or expired token")
}
ctx = context.WithValue(ctx, contextKeyUser, claims["sub"].(string))
return ctx, nil
}
}
func NoAuth(method string) bool {
return strings.Contains(method, "Auth")
}