package api import ( "context" "errors" "strings" grpc_auth "github.com/grpc-ecosystem/go-grpc-middleware/auth" "github.com/hhhapz/codequest/models" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) const ( UserKey = "ctxuser" TokenKey = "ctxtoken" ) func AuthInterceptor(authFunc grpc_auth.AuthFunc) grpc.UnaryServerInterceptor { return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { var newCtx context.Context var err error if overrideSrv, ok := info.Server.(grpc_auth.ServiceAuthFuncOverride); ok { method := strings.LastIndex(info.FullMethod, "/") newCtx, err = overrideSrv.AuthFuncOverride(ctx, info.FullMethod[method+1:]) } else { newCtx, err = authFunc(ctx) } if err != nil { return nil, err } return handler(newCtx, req) } } func (as AuthService) defaultAuthFunc(ctx context.Context) (context.Context, error) { return BearerAuth(ctx, as.userStore) } func BearerAuth(ctx context.Context, us UserStore) (context.Context, error) { token, err := grpc_auth.AuthFromMD(ctx, "Bearer") if err != nil { return nil, err } u, err := us.UserByToken(ctx, token) if err != nil { if errors.As(err, &models.UserError{}) { return nil, status.Error(codes.Unauthenticated, err.Error()) } return nil, status.Errorf(codes.Internal, "could not authenticate your request") } ctx = context.WithValue(ctx, UserKey, u) ctx = context.WithValue(ctx, TokenKey, token) return ctx, nil } func AdminOnly(ctx context.Context) (context.Context, error) { u := UserCtx(ctx) if u == nil { return nil, status.Errorf(codes.Unauthenticated, "user not found") } if !u.Admin { return nil, status.Errorf(codes.PermissionDenied, "access denied: user is not admin") } return ctx, nil } func UserCtx(ctx context.Context) *models.User { u, _ := ctx.Value(UserKey).(*models.User) return u } func TokenCtx(ctx context.Context) string { t, _ := ctx.Value(TokenKey).(string) return t }