Skip to content

Commit

Permalink
feat: user metadata middleware
Browse files Browse the repository at this point in the history
  • Loading branch information
pieceowater committed Jan 8, 2025
1 parent 6d21a9f commit 285c59d
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 2 deletions.
11 changes: 9 additions & 2 deletions cmd/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"app/internal/core/cfg"
"app/internal/core/middleware"
"app/internal/pkg"
gossiper "github.com/pieceowater-dev/lotof.lib.gossiper/v2"
"google.golang.org/grpc"
Expand All @@ -10,7 +11,7 @@ import (
)

func init() {
// EXAMPLE, todo: make global CURRENT SCHEMA pass + switching, then store and manage schemas in HUB
// EXAMPLE, todo: make schema switching, then store and manage schemas in HUB
encryptedTenants := []gossiper.EncryptedTenant{
{
Namespace: "someSchema",
Expand Down Expand Up @@ -43,7 +44,13 @@ func main() {
appCfg := cfg.Inst()
appRouter := pkg.NewRouter()

grpcServer := grpc.NewServer()
grpcServer := grpc.NewServer(
grpc.UnaryInterceptor(
middleware.GrpcMiddleware(
middleware.NewMetadataMiddleware(),
).MiddlewareMethod(),
),
)
reflection.Register(grpcServer)

serverManager := gossiper.NewServerManager()
Expand Down
7 changes: 7 additions & 0 deletions internal/core/middleware/middleware.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package middleware

import "google.golang.org/grpc"

type GrpcMiddleware interface {
MiddlewareMethod() grpc.UnaryServerInterceptor
}
70 changes: 70 additions & 0 deletions internal/core/middleware/userdata.middleware.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package middleware

import (
"context"
"fmt"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
"log"
)

type contextKey string

type UserMetadata struct {
UserID string
Namespace string
}

func GetUserMetadata(ctx context.Context) (*UserMetadata, bool) {
userMetadata, ok := ctx.Value(contextKey("userMetadata")).(*UserMetadata)
return userMetadata, ok
}

type GrpcMetadata struct {
contextUserMetadataKey contextKey
}

func NewMetadataMiddleware() *GrpcMetadata {
return &GrpcMetadata{
contextUserMetadataKey: "userMetadata",
}
}

func (md *GrpcMetadata) MiddlewareMethod() grpc.UnaryServerInterceptor {
return func(
ctx context.Context,
req any,
info *grpc.UnaryServerInfo,
handler grpc.UnaryHandler,
) (any, error) {
userMetadata, err := md.getUserMetadataFromContext(ctx)
if err != nil {
log.Printf("Failed to extract metadata: %v", err)
return nil, status.Errorf(codes.Unauthenticated, "missing metadata")
}
ctx = md.withUserMetadata(ctx, userMetadata)
return handler(ctx, req)
}
}

func (md *GrpcMetadata) getUserMetadataFromContext(ctx context.Context) (*UserMetadata, error) {
incoming, ok := metadata.FromIncomingContext(ctx)
if !ok {
return nil, fmt.Errorf("no metadata found in context")
}
userIDs := incoming.Get("userid")
namespaces := incoming.Get("namespace")
if len(userIDs) == 0 || len(namespaces) == 0 {
return nil, fmt.Errorf("missing metadata keys: userid or namespace")
}
return &UserMetadata{
UserID: userIDs[0],
Namespace: namespaces[0],
}, nil
}

func (md *GrpcMetadata) withUserMetadata(ctx context.Context, userMetadata *UserMetadata) context.Context {
return context.WithValue(ctx, md.contextUserMetadataKey, userMetadata)
}

0 comments on commit 285c59d

Please sign in to comment.