- Read x-engpad-username/x-engpad-password from gRPC metadata (matching what the Android client sends) - Allow TLS 1.2 on gRPC port — Android's BoringSSL/OkHttp transport does not negotiate TLS 1.3 without Conscrypt Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
47 lines
1.3 KiB
Go
47 lines
1.3 KiB
Go
package grpcserver
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
|
|
"git.wntrmute.dev/kyle/eng-pad-server/internal/auth"
|
|
"google.golang.org/grpc"
|
|
"google.golang.org/grpc/codes"
|
|
"google.golang.org/grpc/metadata"
|
|
"google.golang.org/grpc/status"
|
|
)
|
|
|
|
type contextKey string
|
|
|
|
const userIDKey contextKey = "user_id"
|
|
|
|
// UserIDFromContext extracts the authenticated user ID from the context.
|
|
func UserIDFromContext(ctx context.Context) (int64, bool) {
|
|
id, ok := ctx.Value(userIDKey).(int64)
|
|
return id, ok
|
|
}
|
|
|
|
// AuthInterceptor verifies username/password from gRPC metadata.
|
|
func AuthInterceptor(database *sql.DB) grpc.UnaryServerInterceptor {
|
|
return func(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {
|
|
md, ok := metadata.FromIncomingContext(ctx)
|
|
if !ok {
|
|
return nil, status.Error(codes.Unauthenticated, "missing metadata")
|
|
}
|
|
|
|
usernames := md.Get("x-engpad-username")
|
|
passwords := md.Get("x-engpad-password")
|
|
if len(usernames) == 0 || len(passwords) == 0 {
|
|
return nil, status.Error(codes.Unauthenticated, "missing credentials")
|
|
}
|
|
|
|
userID, err := auth.AuthenticateUser(database, usernames[0], passwords[0])
|
|
if err != nil {
|
|
return nil, status.Error(codes.Unauthenticated, "invalid credentials")
|
|
}
|
|
|
|
ctx = context.WithValue(ctx, userIDKey, userID)
|
|
return handler(ctx, req)
|
|
}
|
|
}
|