2023-12-08 16:30:55 +02:00
|
|
|
package gerrors
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
|
feat: exchange gRPC server implementation to connectRPC (#10145)
# Which Problems Are Solved
The current maintained gRPC server in combination with a REST (grpc)
gateway is getting harder and harder to maintain. Additionally, there
have been and still are issues with supporting / displaying `oneOf`s
correctly.
We therefore decided to exchange the server implementation to
connectRPC, which apart from supporting connect as protocol, also also
"standard" gRCP clients as well as HTTP/1.1 / rest like clients, e.g.
curl directly call the server without any additional gateway.
# How the Problems Are Solved
- All v2 services are moved to connectRPC implementation. (v1 services
are still served as pure grpc servers)
- All gRPC server interceptors were migrated / copied to a corresponding
connectRPC interceptor.
- API.ListGrpcServices and API. ListGrpcMethods were changed to include
the connect services and endpoints.
- gRPC server reflection was changed to a `StaticReflector` using the
`ListGrpcServices` list.
- The `grpc.Server` interfaces was split into different combinations to
be able to handle the different cases (grpc server and prefixed gateway,
connect server with grpc gateway, connect server only, ...)
- Docs of services serving connectRPC only with no additional gateway
(instance, webkey, project, app, org v2 beta) are changed to expose that
- since the plugin is not yet available on buf, we download it using
`postinstall` hook of the docs
# Additional Changes
- WebKey service is added as v2 service (in addition to the current
v2beta)
# Additional Context
closes #9483
---------
Co-authored-by: Elio Bischof <elio@zitadel.com>
2025-07-04 10:06:20 -04:00
|
|
|
"connectrpc.com/connect"
|
2024-04-23 10:35:25 +02:00
|
|
|
"github.com/jackc/pgx/v5/pgconn"
|
2023-12-08 16:30:55 +02:00
|
|
|
"github.com/zitadel/logging"
|
|
|
|
"google.golang.org/grpc/codes"
|
|
|
|
"google.golang.org/grpc/status"
|
feat: exchange gRPC server implementation to connectRPC (#10145)
# Which Problems Are Solved
The current maintained gRPC server in combination with a REST (grpc)
gateway is getting harder and harder to maintain. Additionally, there
have been and still are issues with supporting / displaying `oneOf`s
correctly.
We therefore decided to exchange the server implementation to
connectRPC, which apart from supporting connect as protocol, also also
"standard" gRCP clients as well as HTTP/1.1 / rest like clients, e.g.
curl directly call the server without any additional gateway.
# How the Problems Are Solved
- All v2 services are moved to connectRPC implementation. (v1 services
are still served as pure grpc servers)
- All gRPC server interceptors were migrated / copied to a corresponding
connectRPC interceptor.
- API.ListGrpcServices and API. ListGrpcMethods were changed to include
the connect services and endpoints.
- gRPC server reflection was changed to a `StaticReflector` using the
`ListGrpcServices` list.
- The `grpc.Server` interfaces was split into different combinations to
be able to handle the different cases (grpc server and prefixed gateway,
connect server with grpc gateway, connect server only, ...)
- Docs of services serving connectRPC only with no additional gateway
(instance, webkey, project, app, org v2 beta) are changed to expose that
- since the plugin is not yet available on buf, we download it using
`postinstall` hook of the docs
# Additional Changes
- WebKey service is added as v2 service (in addition to the current
v2beta)
# Additional Context
closes #9483
---------
Co-authored-by: Elio Bischof <elio@zitadel.com>
2025-07-04 10:06:20 -04:00
|
|
|
"google.golang.org/protobuf/proto"
|
2025-01-29 10:29:00 +00:00
|
|
|
"google.golang.org/protobuf/protoadapt"
|
2023-12-08 16:30:55 +02:00
|
|
|
|
2025-01-29 10:29:00 +00:00
|
|
|
commandErrors "github.com/zitadel/zitadel/internal/command/errors"
|
2023-12-08 16:30:55 +02:00
|
|
|
"github.com/zitadel/zitadel/internal/zerrors"
|
|
|
|
"github.com/zitadel/zitadel/pkg/grpc/message"
|
|
|
|
)
|
|
|
|
|
|
|
|
func ZITADELToGRPCError(err error) error {
|
|
|
|
if err == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
code, key, id, ok := ExtractZITADELError(err)
|
|
|
|
if !ok {
|
|
|
|
return status.Convert(err).Err()
|
|
|
|
}
|
|
|
|
msg := key
|
|
|
|
msg += " (" + id + ")"
|
|
|
|
|
2025-01-29 10:29:00 +00:00
|
|
|
errorInfo := getErrorInfo(id, key, err)
|
|
|
|
|
|
|
|
s, err := status.New(code, msg).WithDetails(errorInfo)
|
2023-12-08 16:30:55 +02:00
|
|
|
if err != nil {
|
|
|
|
logging.WithError(err).WithField("logID", "GRPC-gIeRw").Debug("unable to add detail")
|
|
|
|
return status.New(code, msg).Err()
|
|
|
|
}
|
|
|
|
|
|
|
|
return s.Err()
|
|
|
|
}
|
|
|
|
|
feat: exchange gRPC server implementation to connectRPC (#10145)
# Which Problems Are Solved
The current maintained gRPC server in combination with a REST (grpc)
gateway is getting harder and harder to maintain. Additionally, there
have been and still are issues with supporting / displaying `oneOf`s
correctly.
We therefore decided to exchange the server implementation to
connectRPC, which apart from supporting connect as protocol, also also
"standard" gRCP clients as well as HTTP/1.1 / rest like clients, e.g.
curl directly call the server without any additional gateway.
# How the Problems Are Solved
- All v2 services are moved to connectRPC implementation. (v1 services
are still served as pure grpc servers)
- All gRPC server interceptors were migrated / copied to a corresponding
connectRPC interceptor.
- API.ListGrpcServices and API. ListGrpcMethods were changed to include
the connect services and endpoints.
- gRPC server reflection was changed to a `StaticReflector` using the
`ListGrpcServices` list.
- The `grpc.Server` interfaces was split into different combinations to
be able to handle the different cases (grpc server and prefixed gateway,
connect server with grpc gateway, connect server only, ...)
- Docs of services serving connectRPC only with no additional gateway
(instance, webkey, project, app, org v2 beta) are changed to expose that
- since the plugin is not yet available on buf, we download it using
`postinstall` hook of the docs
# Additional Changes
- WebKey service is added as v2 service (in addition to the current
v2beta)
# Additional Context
closes #9483
---------
Co-authored-by: Elio Bischof <elio@zitadel.com>
2025-07-04 10:06:20 -04:00
|
|
|
func ZITADELToConnectError(err error) error {
|
|
|
|
if err == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
connectError := new(connect.Error)
|
|
|
|
if errors.As(err, &connectError) {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
code, key, id, ok := ExtractZITADELError(err)
|
|
|
|
if !ok {
|
|
|
|
return status.Convert(err).Err()
|
|
|
|
}
|
|
|
|
msg := key
|
|
|
|
msg += " (" + id + ")"
|
|
|
|
|
|
|
|
errorInfo := getErrorInfo(id, key, err)
|
|
|
|
|
|
|
|
cErr := connect.NewError(connect.Code(code), errors.New(msg))
|
|
|
|
if detail, detailErr := connect.NewErrorDetail(errorInfo.(proto.Message)); detailErr == nil {
|
|
|
|
cErr.AddDetail(detail)
|
|
|
|
}
|
|
|
|
return cErr
|
|
|
|
}
|
|
|
|
|
2023-12-08 16:30:55 +02:00
|
|
|
func ExtractZITADELError(err error) (c codes.Code, msg, id string, ok bool) {
|
|
|
|
if err == nil {
|
|
|
|
return codes.OK, "", "", false
|
|
|
|
}
|
2024-04-23 10:35:25 +02:00
|
|
|
connErr := new(pgconn.ConnectError)
|
|
|
|
if ok := errors.As(err, &connErr); ok {
|
|
|
|
return codes.Internal, "db connection error", "", true
|
|
|
|
}
|
2023-12-08 16:30:55 +02:00
|
|
|
zitadelErr := new(zerrors.ZitadelError)
|
|
|
|
if ok := errors.As(err, &zitadelErr); !ok {
|
|
|
|
return codes.Unknown, err.Error(), "", false
|
|
|
|
}
|
|
|
|
switch {
|
|
|
|
case zerrors.IsErrorAlreadyExists(err):
|
|
|
|
return codes.AlreadyExists, zitadelErr.GetMessage(), zitadelErr.GetID(), true
|
|
|
|
case zerrors.IsDeadlineExceeded(err):
|
|
|
|
return codes.DeadlineExceeded, zitadelErr.GetMessage(), zitadelErr.GetID(), true
|
|
|
|
case zerrors.IsInternal(err):
|
|
|
|
return codes.Internal, zitadelErr.GetMessage(), zitadelErr.GetID(), true
|
|
|
|
case zerrors.IsErrorInvalidArgument(err):
|
|
|
|
return codes.InvalidArgument, zitadelErr.GetMessage(), zitadelErr.GetID(), true
|
|
|
|
case zerrors.IsNotFound(err):
|
|
|
|
return codes.NotFound, zitadelErr.GetMessage(), zitadelErr.GetID(), true
|
|
|
|
case zerrors.IsPermissionDenied(err):
|
|
|
|
return codes.PermissionDenied, zitadelErr.GetMessage(), zitadelErr.GetID(), true
|
|
|
|
case zerrors.IsPreconditionFailed(err):
|
|
|
|
return codes.FailedPrecondition, zitadelErr.GetMessage(), zitadelErr.GetID(), true
|
|
|
|
case zerrors.IsUnauthenticated(err):
|
|
|
|
return codes.Unauthenticated, zitadelErr.GetMessage(), zitadelErr.GetID(), true
|
|
|
|
case zerrors.IsUnavailable(err):
|
|
|
|
return codes.Unavailable, zitadelErr.GetMessage(), zitadelErr.GetID(), true
|
|
|
|
case zerrors.IsUnimplemented(err):
|
|
|
|
return codes.Unimplemented, zitadelErr.GetMessage(), zitadelErr.GetID(), true
|
|
|
|
case zerrors.IsResourceExhausted(err):
|
|
|
|
return codes.ResourceExhausted, zitadelErr.GetMessage(), zitadelErr.GetID(), true
|
|
|
|
default:
|
|
|
|
return codes.Unknown, err.Error(), "", false
|
|
|
|
}
|
|
|
|
}
|
2025-01-29 10:29:00 +00:00
|
|
|
|
|
|
|
func getErrorInfo(id, key string, err error) protoadapt.MessageV1 {
|
|
|
|
var errorInfo protoadapt.MessageV1
|
|
|
|
|
|
|
|
var wpe *commandErrors.WrongPasswordError
|
|
|
|
if err != nil && errors.As(err, &wpe) {
|
|
|
|
errorInfo = &message.CredentialsCheckError{Id: id, Message: key, FailedAttempts: wpe.FailedAttempts}
|
|
|
|
} else {
|
|
|
|
errorInfo = &message.ErrorDetail{Id: id, Message: key}
|
|
|
|
}
|
|
|
|
|
|
|
|
return errorInfo
|
|
|
|
}
|