mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 21:27:42 +00:00
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>
This commit is contained in:
@@ -3,6 +3,7 @@ package user
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
@@ -11,18 +12,18 @@ import (
|
||||
"github.com/zitadel/zitadel/pkg/grpc/user/v2"
|
||||
)
|
||||
|
||||
func (s *Server) SetEmail(ctx context.Context, req *user.SetEmailRequest) (resp *user.SetEmailResponse, err error) {
|
||||
func (s *Server) SetEmail(ctx context.Context, req *connect.Request[user.SetEmailRequest]) (resp *connect.Response[user.SetEmailResponse], err error) {
|
||||
var email *domain.Email
|
||||
|
||||
switch v := req.GetVerification().(type) {
|
||||
switch v := req.Msg.GetVerification().(type) {
|
||||
case *user.SetEmailRequest_SendCode:
|
||||
email, err = s.command.ChangeUserEmailURLTemplate(ctx, req.GetUserId(), req.GetEmail(), s.userCodeAlg, v.SendCode.GetUrlTemplate())
|
||||
email, err = s.command.ChangeUserEmailURLTemplate(ctx, req.Msg.GetUserId(), req.Msg.GetEmail(), s.userCodeAlg, v.SendCode.GetUrlTemplate())
|
||||
case *user.SetEmailRequest_ReturnCode:
|
||||
email, err = s.command.ChangeUserEmailReturnCode(ctx, req.GetUserId(), req.GetEmail(), s.userCodeAlg)
|
||||
email, err = s.command.ChangeUserEmailReturnCode(ctx, req.Msg.GetUserId(), req.Msg.GetEmail(), s.userCodeAlg)
|
||||
case *user.SetEmailRequest_IsVerified:
|
||||
email, err = s.command.ChangeUserEmailVerified(ctx, req.GetUserId(), req.GetEmail())
|
||||
email, err = s.command.ChangeUserEmailVerified(ctx, req.Msg.GetUserId(), req.Msg.GetEmail())
|
||||
case nil:
|
||||
email, err = s.command.ChangeUserEmail(ctx, req.GetUserId(), req.GetEmail(), s.userCodeAlg)
|
||||
email, err = s.command.ChangeUserEmail(ctx, req.Msg.GetUserId(), req.Msg.GetEmail(), s.userCodeAlg)
|
||||
default:
|
||||
err = zerrors.ThrowUnimplementedf(nil, "USERv2-Ahng0", "verification oneOf %T in method SetEmail not implemented", v)
|
||||
}
|
||||
@@ -30,26 +31,26 @@ func (s *Server) SetEmail(ctx context.Context, req *user.SetEmailRequest) (resp
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &user.SetEmailResponse{
|
||||
return connect.NewResponse(&user.SetEmailResponse{
|
||||
Details: &object.Details{
|
||||
Sequence: email.Sequence,
|
||||
ChangeDate: timestamppb.New(email.ChangeDate),
|
||||
ResourceOwner: email.ResourceOwner,
|
||||
},
|
||||
VerificationCode: email.PlainCode,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) ResendEmailCode(ctx context.Context, req *user.ResendEmailCodeRequest) (resp *user.ResendEmailCodeResponse, err error) {
|
||||
func (s *Server) ResendEmailCode(ctx context.Context, req *connect.Request[user.ResendEmailCodeRequest]) (resp *connect.Response[user.ResendEmailCodeResponse], err error) {
|
||||
var email *domain.Email
|
||||
|
||||
switch v := req.GetVerification().(type) {
|
||||
switch v := req.Msg.GetVerification().(type) {
|
||||
case *user.ResendEmailCodeRequest_SendCode:
|
||||
email, err = s.command.ResendUserEmailCodeURLTemplate(ctx, req.GetUserId(), s.userCodeAlg, v.SendCode.GetUrlTemplate())
|
||||
email, err = s.command.ResendUserEmailCodeURLTemplate(ctx, req.Msg.GetUserId(), s.userCodeAlg, v.SendCode.GetUrlTemplate())
|
||||
case *user.ResendEmailCodeRequest_ReturnCode:
|
||||
email, err = s.command.ResendUserEmailReturnCode(ctx, req.GetUserId(), s.userCodeAlg)
|
||||
email, err = s.command.ResendUserEmailReturnCode(ctx, req.Msg.GetUserId(), s.userCodeAlg)
|
||||
case nil:
|
||||
email, err = s.command.ResendUserEmailCode(ctx, req.GetUserId(), s.userCodeAlg)
|
||||
email, err = s.command.ResendUserEmailCode(ctx, req.Msg.GetUserId(), s.userCodeAlg)
|
||||
default:
|
||||
err = zerrors.ThrowUnimplementedf(nil, "USERv2-faj0l0nj5x", "verification oneOf %T in method ResendEmailCode not implemented", v)
|
||||
}
|
||||
@@ -57,26 +58,26 @@ func (s *Server) ResendEmailCode(ctx context.Context, req *user.ResendEmailCodeR
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &user.ResendEmailCodeResponse{
|
||||
return connect.NewResponse(&user.ResendEmailCodeResponse{
|
||||
Details: &object.Details{
|
||||
Sequence: email.Sequence,
|
||||
ChangeDate: timestamppb.New(email.ChangeDate),
|
||||
ResourceOwner: email.ResourceOwner,
|
||||
},
|
||||
VerificationCode: email.PlainCode,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) SendEmailCode(ctx context.Context, req *user.SendEmailCodeRequest) (resp *user.SendEmailCodeResponse, err error) {
|
||||
func (s *Server) SendEmailCode(ctx context.Context, req *connect.Request[user.SendEmailCodeRequest]) (resp *connect.Response[user.SendEmailCodeResponse], err error) {
|
||||
var email *domain.Email
|
||||
|
||||
switch v := req.GetVerification().(type) {
|
||||
switch v := req.Msg.GetVerification().(type) {
|
||||
case *user.SendEmailCodeRequest_SendCode:
|
||||
email, err = s.command.SendUserEmailCodeURLTemplate(ctx, req.GetUserId(), s.userCodeAlg, v.SendCode.GetUrlTemplate())
|
||||
email, err = s.command.SendUserEmailCodeURLTemplate(ctx, req.Msg.GetUserId(), s.userCodeAlg, v.SendCode.GetUrlTemplate())
|
||||
case *user.SendEmailCodeRequest_ReturnCode:
|
||||
email, err = s.command.SendUserEmailReturnCode(ctx, req.GetUserId(), s.userCodeAlg)
|
||||
email, err = s.command.SendUserEmailReturnCode(ctx, req.Msg.GetUserId(), s.userCodeAlg)
|
||||
case nil:
|
||||
email, err = s.command.SendUserEmailCode(ctx, req.GetUserId(), s.userCodeAlg)
|
||||
email, err = s.command.SendUserEmailCode(ctx, req.Msg.GetUserId(), s.userCodeAlg)
|
||||
default:
|
||||
err = zerrors.ThrowUnimplementedf(nil, "USERv2-faj0l0nj5x", "verification oneOf %T in method SendEmailCode not implemented", v)
|
||||
}
|
||||
@@ -84,30 +85,30 @@ func (s *Server) SendEmailCode(ctx context.Context, req *user.SendEmailCodeReque
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &user.SendEmailCodeResponse{
|
||||
return connect.NewResponse(&user.SendEmailCodeResponse{
|
||||
Details: &object.Details{
|
||||
Sequence: email.Sequence,
|
||||
ChangeDate: timestamppb.New(email.ChangeDate),
|
||||
ResourceOwner: email.ResourceOwner,
|
||||
},
|
||||
VerificationCode: email.PlainCode,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) VerifyEmail(ctx context.Context, req *user.VerifyEmailRequest) (*user.VerifyEmailResponse, error) {
|
||||
func (s *Server) VerifyEmail(ctx context.Context, req *connect.Request[user.VerifyEmailRequest]) (*connect.Response[user.VerifyEmailResponse], error) {
|
||||
details, err := s.command.VerifyUserEmail(ctx,
|
||||
req.GetUserId(),
|
||||
req.GetVerificationCode(),
|
||||
req.Msg.GetUserId(),
|
||||
req.Msg.GetVerificationCode(),
|
||||
s.userCodeAlg,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.VerifyEmailResponse{
|
||||
return connect.NewResponse(&user.VerifyEmailResponse{
|
||||
Details: &object.Details{
|
||||
Sequence: details.Sequence,
|
||||
ChangeDate: timestamppb.New(details.EventDate),
|
||||
ResourceOwner: details.ResourceOwner,
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"golang.org/x/text/language"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
@@ -14,7 +15,7 @@ import (
|
||||
"github.com/zitadel/zitadel/pkg/grpc/user/v2"
|
||||
)
|
||||
|
||||
func (s *Server) createUserTypeHuman(ctx context.Context, humanPb *user.CreateUserRequest_Human, orgId string, userName, userId *string) (*user.CreateUserResponse, error) {
|
||||
func (s *Server) createUserTypeHuman(ctx context.Context, humanPb *user.CreateUserRequest_Human, orgId string, userName, userId *string) (*connect.Response[user.CreateUserResponse], error) {
|
||||
addHumanPb := &user.AddHumanUserRequest{
|
||||
Username: userName,
|
||||
UserId: userId,
|
||||
@@ -52,15 +53,15 @@ func (s *Server) createUserTypeHuman(ctx context.Context, humanPb *user.CreateUs
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.CreateUserResponse{
|
||||
return connect.NewResponse(&user.CreateUserResponse{
|
||||
Id: newHuman.ID,
|
||||
CreationDate: timestamppb.New(newHuman.Details.EventDate),
|
||||
EmailCode: newHuman.EmailCode,
|
||||
PhoneCode: newHuman.PhoneCode,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) updateUserTypeHuman(ctx context.Context, humanPb *user.UpdateUserRequest_Human, userId string, userName *string) (*user.UpdateUserResponse, error) {
|
||||
func (s *Server) updateUserTypeHuman(ctx context.Context, humanPb *user.UpdateUserRequest_Human, userId string, userName *string) (*connect.Response[user.UpdateUserResponse], error) {
|
||||
cmd, err := updateHumanUserToCommand(userId, userName, humanPb)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -68,11 +69,11 @@ func (s *Server) updateUserTypeHuman(ctx context.Context, humanPb *user.UpdateUs
|
||||
if err = s.command.ChangeUserHuman(ctx, cmd, s.userCodeAlg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.UpdateUserResponse{
|
||||
return connect.NewResponse(&user.UpdateUserResponse{
|
||||
ChangeDate: timestamppb.New(cmd.Details.EventDate),
|
||||
EmailCode: cmd.EmailCode,
|
||||
PhoneCode: cmd.PhoneCode,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func updateHumanUserToCommand(userId string, userName *string, human *user.UpdateUserRequest_Human) (*command.ChangeHuman, error) {
|
||||
|
@@ -3,6 +3,8 @@ package user
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/object/v2"
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
@@ -11,22 +13,22 @@ import (
|
||||
"github.com/zitadel/zitadel/pkg/grpc/user/v2"
|
||||
)
|
||||
|
||||
func (s *Server) AddIDPLink(ctx context.Context, req *user.AddIDPLinkRequest) (_ *user.AddIDPLinkResponse, err error) {
|
||||
details, err := s.command.AddUserIDPLink(ctx, req.UserId, "", &command.AddLink{
|
||||
IDPID: req.GetIdpLink().GetIdpId(),
|
||||
DisplayName: req.GetIdpLink().GetUserName(),
|
||||
IDPExternalID: req.GetIdpLink().GetUserId(),
|
||||
func (s *Server) AddIDPLink(ctx context.Context, req *connect.Request[user.AddIDPLinkRequest]) (_ *connect.Response[user.AddIDPLinkResponse], err error) {
|
||||
details, err := s.command.AddUserIDPLink(ctx, req.Msg.GetUserId(), "", &command.AddLink{
|
||||
IDPID: req.Msg.GetIdpLink().GetIdpId(),
|
||||
DisplayName: req.Msg.GetIdpLink().GetUserName(),
|
||||
IDPExternalID: req.Msg.GetIdpLink().GetUserId(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.AddIDPLinkResponse{
|
||||
return connect.NewResponse(&user.AddIDPLinkResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) ListIDPLinks(ctx context.Context, req *user.ListIDPLinksRequest) (_ *user.ListIDPLinksResponse, err error) {
|
||||
queries, err := ListLinkedIDPsRequestToQuery(req)
|
||||
func (s *Server) ListIDPLinks(ctx context.Context, req *connect.Request[user.ListIDPLinksRequest]) (_ *connect.Response[user.ListIDPLinksResponse], err error) {
|
||||
queries, err := ListLinkedIDPsRequestToQuery(req.Msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -34,10 +36,10 @@ func (s *Server) ListIDPLinks(ctx context.Context, req *user.ListIDPLinksRequest
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.ListIDPLinksResponse{
|
||||
return connect.NewResponse(&user.ListIDPLinksResponse{
|
||||
Result: IDPLinksToPb(res.Links),
|
||||
Details: object.ToListDetails(res.SearchResponse),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func ListLinkedIDPsRequestToQuery(req *user.ListIDPLinksRequest) (*query.IDPUserLinksSearchQuery, error) {
|
||||
@@ -72,14 +74,14 @@ func IDPLinkToPb(link *query.IDPUserLink) *user.IDPLink {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) RemoveIDPLink(ctx context.Context, req *user.RemoveIDPLinkRequest) (*user.RemoveIDPLinkResponse, error) {
|
||||
objectDetails, err := s.command.RemoveUserIDPLink(ctx, RemoveIDPLinkRequestToDomain(ctx, req))
|
||||
func (s *Server) RemoveIDPLink(ctx context.Context, req *connect.Request[user.RemoveIDPLinkRequest]) (*connect.Response[user.RemoveIDPLinkResponse], error) {
|
||||
objectDetails, err := s.command.RemoveUserIDPLink(ctx, RemoveIDPLinkRequestToDomain(ctx, req.Msg))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.RemoveIDPLinkResponse{
|
||||
return connect.NewResponse(&user.RemoveIDPLinkResponse{
|
||||
Details: object.DomainToDetailsPb(objectDetails),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func RemoveIDPLinkRequestToDomain(ctx context.Context, req *user.RemoveIDPLinkRequest) *domain.UserIDPLink {
|
||||
|
@@ -6,6 +6,7 @@ import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
oidc_pkg "github.com/zitadel/oidc/v3/pkg/oidc"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
@@ -32,18 +33,18 @@ import (
|
||||
"github.com/zitadel/zitadel/pkg/grpc/user/v2"
|
||||
)
|
||||
|
||||
func (s *Server) StartIdentityProviderIntent(ctx context.Context, req *user.StartIdentityProviderIntentRequest) (_ *user.StartIdentityProviderIntentResponse, err error) {
|
||||
switch t := req.GetContent().(type) {
|
||||
func (s *Server) StartIdentityProviderIntent(ctx context.Context, req *connect.Request[user.StartIdentityProviderIntentRequest]) (_ *connect.Response[user.StartIdentityProviderIntentResponse], err error) {
|
||||
switch t := req.Msg.GetContent().(type) {
|
||||
case *user.StartIdentityProviderIntentRequest_Urls:
|
||||
return s.startIDPIntent(ctx, req.GetIdpId(), t.Urls)
|
||||
return s.startIDPIntent(ctx, req.Msg.GetIdpId(), t.Urls)
|
||||
case *user.StartIdentityProviderIntentRequest_Ldap:
|
||||
return s.startLDAPIntent(ctx, req.GetIdpId(), t.Ldap)
|
||||
return s.startLDAPIntent(ctx, req.Msg.GetIdpId(), t.Ldap)
|
||||
default:
|
||||
return nil, zerrors.ThrowUnimplementedf(nil, "USERv2-S2g21", "type oneOf %T in method StartIdentityProviderIntent not implemented", t)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) startIDPIntent(ctx context.Context, idpID string, urls *user.RedirectURLs) (*user.StartIdentityProviderIntentResponse, error) {
|
||||
func (s *Server) startIDPIntent(ctx context.Context, idpID string, urls *user.RedirectURLs) (*connect.Response[user.StartIdentityProviderIntentResponse], error) {
|
||||
state, session, err := s.command.AuthFromProvider(ctx, idpID, s.idpCallback(ctx), s.samlRootURL(ctx, idpID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -58,12 +59,12 @@ func (s *Server) startIDPIntent(ctx context.Context, idpID string, urls *user.Re
|
||||
}
|
||||
switch a := auth.(type) {
|
||||
case *idp.RedirectAuth:
|
||||
return &user.StartIdentityProviderIntentResponse{
|
||||
return connect.NewResponse(&user.StartIdentityProviderIntentResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
NextStep: &user.StartIdentityProviderIntentResponse_AuthUrl{AuthUrl: a.RedirectURL},
|
||||
}, nil
|
||||
}), nil
|
||||
case *idp.FormAuth:
|
||||
return &user.StartIdentityProviderIntentResponse{
|
||||
return connect.NewResponse(&user.StartIdentityProviderIntentResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
NextStep: &user.StartIdentityProviderIntentResponse_FormData{
|
||||
FormData: &user.FormData{
|
||||
@@ -71,12 +72,12 @@ func (s *Server) startIDPIntent(ctx context.Context, idpID string, urls *user.Re
|
||||
Fields: a.Fields,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
return nil, zerrors.ThrowInvalidArgumentf(nil, "USERv2-3g2j3", "type oneOf %T in method StartIdentityProviderIntent not implemented", auth)
|
||||
}
|
||||
|
||||
func (s *Server) startLDAPIntent(ctx context.Context, idpID string, ldapCredentials *user.LDAPCredentials) (*user.StartIdentityProviderIntentResponse, error) {
|
||||
func (s *Server) startLDAPIntent(ctx context.Context, idpID string, ldapCredentials *user.LDAPCredentials) (*connect.Response[user.StartIdentityProviderIntentResponse], error) {
|
||||
intentWriteModel, details, err := s.command.CreateIntent(ctx, "", idpID, "", "", authz.GetInstance(ctx).InstanceID(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -92,7 +93,7 @@ func (s *Server) startLDAPIntent(ctx context.Context, idpID string, ldapCredenti
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.StartIdentityProviderIntentResponse{
|
||||
return connect.NewResponse(&user.StartIdentityProviderIntentResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
NextStep: &user.StartIdentityProviderIntentResponse_IdpIntent{
|
||||
IdpIntent: &user.IDPIntent{
|
||||
@@ -101,7 +102,7 @@ func (s *Server) startLDAPIntent(ctx context.Context, idpID string, ldapCredenti
|
||||
UserId: userID,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) checkLinkedExternalUser(ctx context.Context, idpID, externalUserID string) (string, error) {
|
||||
@@ -150,12 +151,12 @@ func (s *Server) ldapLogin(ctx context.Context, idpID, username, password string
|
||||
return externalUser, userID, session, nil
|
||||
}
|
||||
|
||||
func (s *Server) RetrieveIdentityProviderIntent(ctx context.Context, req *user.RetrieveIdentityProviderIntentRequest) (_ *user.RetrieveIdentityProviderIntentResponse, err error) {
|
||||
intent, err := s.command.GetIntentWriteModel(ctx, req.GetIdpIntentId(), "")
|
||||
func (s *Server) RetrieveIdentityProviderIntent(ctx context.Context, req *connect.Request[user.RetrieveIdentityProviderIntentRequest]) (_ *connect.Response[user.RetrieveIdentityProviderIntentResponse], err error) {
|
||||
intent, err := s.command.GetIntentWriteModel(ctx, req.Msg.GetIdpIntentId(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := s.checkIntentToken(req.GetIdpIntentToken(), intent.AggregateID); err != nil {
|
||||
if err := s.checkIntentToken(req.Msg.GetIdpIntentToken(), intent.AggregateID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if intent.State != domain.IDPIntentStateSucceeded {
|
||||
@@ -203,7 +204,7 @@ func (s *Server) RetrieveIdentityProviderIntent(ctx context.Context, req *user.R
|
||||
}
|
||||
idpIntent.AddHumanUser = idpUserToAddHumanUser(idpUser, idpIntent.IdpInformation.IdpId)
|
||||
}
|
||||
return idpIntent, nil
|
||||
return connect.NewResponse(idpIntent), nil
|
||||
}
|
||||
|
||||
type rawUserMapper struct {
|
||||
|
@@ -3,6 +3,7 @@ package user
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
@@ -11,16 +12,16 @@ import (
|
||||
"github.com/zitadel/zitadel/pkg/grpc/user/v2"
|
||||
)
|
||||
|
||||
func (s *Server) AddKey(ctx context.Context, req *user.AddKeyRequest) (*user.AddKeyResponse, error) {
|
||||
func (s *Server) AddKey(ctx context.Context, req *connect.Request[user.AddKeyRequest]) (*connect.Response[user.AddKeyResponse], error) {
|
||||
newMachineKey := &command.MachineKey{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: req.UserId,
|
||||
AggregateID: req.Msg.GetUserId(),
|
||||
},
|
||||
ExpirationDate: req.GetExpirationDate().AsTime(),
|
||||
ExpirationDate: req.Msg.GetExpirationDate().AsTime(),
|
||||
Type: domain.AuthNKeyTypeJSON,
|
||||
PermissionCheck: s.command.NewPermissionCheckUserWrite(ctx),
|
||||
}
|
||||
newMachineKey.PublicKey = req.PublicKey
|
||||
newMachineKey.PublicKey = req.Msg.GetPublicKey()
|
||||
|
||||
pubkeySupplied := len(newMachineKey.PublicKey) > 0
|
||||
details, err := s.command.AddUserMachineKey(ctx, newMachineKey)
|
||||
@@ -37,26 +38,26 @@ func (s *Server) AddKey(ctx context.Context, req *user.AddKeyRequest) (*user.Add
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return &user.AddKeyResponse{
|
||||
return connect.NewResponse(&user.AddKeyResponse{
|
||||
KeyId: newMachineKey.KeyID,
|
||||
KeyContent: keyDetails,
|
||||
CreationDate: timestamppb.New(details.EventDate),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) RemoveKey(ctx context.Context, req *user.RemoveKeyRequest) (*user.RemoveKeyResponse, error) {
|
||||
func (s *Server) RemoveKey(ctx context.Context, req *connect.Request[user.RemoveKeyRequest]) (*connect.Response[user.RemoveKeyResponse], error) {
|
||||
machineKey := &command.MachineKey{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: req.UserId,
|
||||
AggregateID: req.Msg.GetUserId(),
|
||||
},
|
||||
PermissionCheck: s.command.NewPermissionCheckUserWrite(ctx),
|
||||
KeyID: req.KeyId,
|
||||
KeyID: req.Msg.GetKeyId(),
|
||||
}
|
||||
objectDetails, err := s.command.RemoveUserMachineKey(ctx, machineKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.RemoveKeyResponse{
|
||||
return connect.NewResponse(&user.RemoveKeyResponse{
|
||||
DeletionDate: timestamppb.New(objectDetails.EventDate),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package user
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/filter/v2"
|
||||
@@ -12,13 +13,13 @@ import (
|
||||
"github.com/zitadel/zitadel/pkg/grpc/user/v2"
|
||||
)
|
||||
|
||||
func (s *Server) ListKeys(ctx context.Context, req *user.ListKeysRequest) (*user.ListKeysResponse, error) {
|
||||
offset, limit, asc, err := filter.PaginationPbToQuery(s.systemDefaults, req.Pagination)
|
||||
func (s *Server) ListKeys(ctx context.Context, req *connect.Request[user.ListKeysRequest]) (*connect.Response[user.ListKeysResponse], error) {
|
||||
offset, limit, asc, err := filter.PaginationPbToQuery(s.systemDefaults, req.Msg.GetPagination())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
filters, err := keyFiltersToQueries(req.Filters)
|
||||
filters, err := keyFiltersToQueries(req.Msg.GetFilters())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -27,7 +28,7 @@ func (s *Server) ListKeys(ctx context.Context, req *user.ListKeysRequest) (*user
|
||||
Offset: offset,
|
||||
Limit: limit,
|
||||
Asc: asc,
|
||||
SortingColumn: authnKeyFieldNameToSortingColumn(req.SortingColumn),
|
||||
SortingColumn: authnKeyFieldNameToSortingColumn(req.Msg.SortingColumn),
|
||||
},
|
||||
Queries: filters,
|
||||
}
|
||||
@@ -49,7 +50,7 @@ func (s *Server) ListKeys(ctx context.Context, req *user.ListKeysRequest) (*user
|
||||
ExpirationDate: timestamppb.New(key.Expiration),
|
||||
}
|
||||
}
|
||||
return resp, nil
|
||||
return connect.NewResponse(resp), nil
|
||||
}
|
||||
|
||||
func keyFiltersToQueries(filters []*user.KeysSearchFilter) (_ []query.SearchQuery, err error) {
|
||||
|
@@ -3,6 +3,7 @@ package user
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
@@ -11,7 +12,7 @@ import (
|
||||
"github.com/zitadel/zitadel/pkg/grpc/user/v2"
|
||||
)
|
||||
|
||||
func (s *Server) createUserTypeMachine(ctx context.Context, machinePb *user.CreateUserRequest_Machine, orgId, userName, userId string) (*user.CreateUserResponse, error) {
|
||||
func (s *Server) createUserTypeMachine(ctx context.Context, machinePb *user.CreateUserRequest_Machine, orgId, userName, userId string) (*connect.Response[user.CreateUserResponse], error) {
|
||||
cmd := &command.Machine{
|
||||
Username: userName,
|
||||
Name: machinePb.Name,
|
||||
@@ -32,21 +33,21 @@ func (s *Server) createUserTypeMachine(ctx context.Context, machinePb *user.Crea
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.CreateUserResponse{
|
||||
return connect.NewResponse(&user.CreateUserResponse{
|
||||
Id: cmd.AggregateID,
|
||||
CreationDate: timestamppb.New(details.EventDate),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) updateUserTypeMachine(ctx context.Context, machinePb *user.UpdateUserRequest_Machine, userId string, userName *string) (*user.UpdateUserResponse, error) {
|
||||
func (s *Server) updateUserTypeMachine(ctx context.Context, machinePb *user.UpdateUserRequest_Machine, userId string, userName *string) (*connect.Response[user.UpdateUserResponse], error) {
|
||||
cmd := updateMachineUserToCommand(userId, userName, machinePb)
|
||||
err := s.command.ChangeUserMachine(ctx, cmd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.UpdateUserResponse{
|
||||
return connect.NewResponse(&user.UpdateUserResponse{
|
||||
ChangeDate: timestamppb.New(cmd.Details.EventDate),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func updateMachineUserToCommand(userId string, userName *string, machine *user.UpdateUserRequest_Machine) *command.ChangeMachine {
|
||||
|
@@ -3,39 +3,41 @@ package user
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/object/v2"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/user/v2"
|
||||
)
|
||||
|
||||
func (s *Server) AddOTPSMS(ctx context.Context, req *user.AddOTPSMSRequest) (*user.AddOTPSMSResponse, error) {
|
||||
details, err := s.command.AddHumanOTPSMS(ctx, req.GetUserId(), "")
|
||||
func (s *Server) AddOTPSMS(ctx context.Context, req *connect.Request[user.AddOTPSMSRequest]) (*connect.Response[user.AddOTPSMSResponse], error) {
|
||||
details, err := s.command.AddHumanOTPSMS(ctx, req.Msg.GetUserId(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.AddOTPSMSResponse{Details: object.DomainToDetailsPb(details)}, nil
|
||||
return connect.NewResponse(&user.AddOTPSMSResponse{Details: object.DomainToDetailsPb(details)}), nil
|
||||
}
|
||||
|
||||
func (s *Server) RemoveOTPSMS(ctx context.Context, req *user.RemoveOTPSMSRequest) (*user.RemoveOTPSMSResponse, error) {
|
||||
objectDetails, err := s.command.RemoveHumanOTPSMS(ctx, req.GetUserId(), "")
|
||||
func (s *Server) RemoveOTPSMS(ctx context.Context, req *connect.Request[user.RemoveOTPSMSRequest]) (*connect.Response[user.RemoveOTPSMSResponse], error) {
|
||||
objectDetails, err := s.command.RemoveHumanOTPSMS(ctx, req.Msg.GetUserId(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.RemoveOTPSMSResponse{Details: object.DomainToDetailsPb(objectDetails)}, nil
|
||||
return connect.NewResponse(&user.RemoveOTPSMSResponse{Details: object.DomainToDetailsPb(objectDetails)}), nil
|
||||
}
|
||||
|
||||
func (s *Server) AddOTPEmail(ctx context.Context, req *user.AddOTPEmailRequest) (*user.AddOTPEmailResponse, error) {
|
||||
details, err := s.command.AddHumanOTPEmail(ctx, req.GetUserId(), "")
|
||||
func (s *Server) AddOTPEmail(ctx context.Context, req *connect.Request[user.AddOTPEmailRequest]) (*connect.Response[user.AddOTPEmailResponse], error) {
|
||||
details, err := s.command.AddHumanOTPEmail(ctx, req.Msg.GetUserId(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.AddOTPEmailResponse{Details: object.DomainToDetailsPb(details)}, nil
|
||||
return connect.NewResponse(&user.AddOTPEmailResponse{Details: object.DomainToDetailsPb(details)}), nil
|
||||
|
||||
}
|
||||
|
||||
func (s *Server) RemoveOTPEmail(ctx context.Context, req *user.RemoveOTPEmailRequest) (*user.RemoveOTPEmailResponse, error) {
|
||||
objectDetails, err := s.command.RemoveHumanOTPEmail(ctx, req.GetUserId(), "")
|
||||
func (s *Server) RemoveOTPEmail(ctx context.Context, req *connect.Request[user.RemoveOTPEmailRequest]) (*connect.Response[user.RemoveOTPEmailResponse], error) {
|
||||
objectDetails, err := s.command.RemoveHumanOTPEmail(ctx, req.Msg.GetUserId(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.RemoveOTPEmailResponse{Details: object.DomainToDetailsPb(objectDetails)}, nil
|
||||
return connect.NewResponse(&user.RemoveOTPEmailResponse{Details: object.DomainToDetailsPb(objectDetails)}), nil
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package user
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/object/v2"
|
||||
@@ -13,17 +14,17 @@ import (
|
||||
"github.com/zitadel/zitadel/pkg/grpc/user/v2"
|
||||
)
|
||||
|
||||
func (s *Server) RegisterPasskey(ctx context.Context, req *user.RegisterPasskeyRequest) (resp *user.RegisterPasskeyResponse, err error) {
|
||||
func (s *Server) RegisterPasskey(ctx context.Context, req *connect.Request[user.RegisterPasskeyRequest]) (resp *connect.Response[user.RegisterPasskeyResponse], err error) {
|
||||
var (
|
||||
authenticator = passkeyAuthenticatorToDomain(req.GetAuthenticator())
|
||||
authenticator = passkeyAuthenticatorToDomain(req.Msg.GetAuthenticator())
|
||||
)
|
||||
if code := req.GetCode(); code != nil {
|
||||
if code := req.Msg.GetCode(); code != nil {
|
||||
return passkeyRegistrationDetailsToPb(
|
||||
s.command.RegisterUserPasskeyWithCode(ctx, req.GetUserId(), "", authenticator, code.Id, code.Code, req.GetDomain(), s.userCodeAlg),
|
||||
s.command.RegisterUserPasskeyWithCode(ctx, req.Msg.GetUserId(), "", authenticator, code.Id, code.Code, req.Msg.GetDomain(), s.userCodeAlg),
|
||||
)
|
||||
}
|
||||
return passkeyRegistrationDetailsToPb(
|
||||
s.command.RegisterUserPasskey(ctx, req.GetUserId(), "", req.GetDomain(), authenticator),
|
||||
s.command.RegisterUserPasskey(ctx, req.Msg.GetUserId(), "", req.Msg.GetDomain(), authenticator),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -51,86 +52,86 @@ func webAuthNRegistrationDetailsToPb(details *domain.WebAuthNRegistrationDetails
|
||||
return object.DomainToDetailsPb(details.ObjectDetails), options, nil
|
||||
}
|
||||
|
||||
func passkeyRegistrationDetailsToPb(details *domain.WebAuthNRegistrationDetails, err error) (*user.RegisterPasskeyResponse, error) {
|
||||
func passkeyRegistrationDetailsToPb(details *domain.WebAuthNRegistrationDetails, err error) (*connect.Response[user.RegisterPasskeyResponse], error) {
|
||||
objectDetails, options, err := webAuthNRegistrationDetailsToPb(details, err)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.RegisterPasskeyResponse{
|
||||
return connect.NewResponse(&user.RegisterPasskeyResponse{
|
||||
Details: objectDetails,
|
||||
PasskeyId: details.ID,
|
||||
PublicKeyCredentialCreationOptions: options,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) VerifyPasskeyRegistration(ctx context.Context, req *user.VerifyPasskeyRegistrationRequest) (*user.VerifyPasskeyRegistrationResponse, error) {
|
||||
pkc, err := req.GetPublicKeyCredential().MarshalJSON()
|
||||
func (s *Server) VerifyPasskeyRegistration(ctx context.Context, req *connect.Request[user.VerifyPasskeyRegistrationRequest]) (*connect.Response[user.VerifyPasskeyRegistrationResponse], error) {
|
||||
pkc, err := req.Msg.GetPublicKeyCredential().MarshalJSON()
|
||||
if err != nil {
|
||||
return nil, zerrors.ThrowInternal(err, "USERv2-Pha2o", "Errors.Internal")
|
||||
}
|
||||
objectDetails, err := s.command.HumanHumanPasswordlessSetup(ctx, req.GetUserId(), "", req.GetPasskeyName(), "", pkc)
|
||||
objectDetails, err := s.command.HumanHumanPasswordlessSetup(ctx, req.Msg.GetUserId(), "", req.Msg.GetPasskeyName(), "", pkc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.VerifyPasskeyRegistrationResponse{
|
||||
return connect.NewResponse(&user.VerifyPasskeyRegistrationResponse{
|
||||
Details: object.DomainToDetailsPb(objectDetails),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) CreatePasskeyRegistrationLink(ctx context.Context, req *user.CreatePasskeyRegistrationLinkRequest) (resp *user.CreatePasskeyRegistrationLinkResponse, err error) {
|
||||
switch medium := req.Medium.(type) {
|
||||
func (s *Server) CreatePasskeyRegistrationLink(ctx context.Context, req *connect.Request[user.CreatePasskeyRegistrationLinkRequest]) (resp *connect.Response[user.CreatePasskeyRegistrationLinkResponse], err error) {
|
||||
switch medium := req.Msg.Medium.(type) {
|
||||
case nil:
|
||||
return passkeyDetailsToPb(
|
||||
s.command.AddUserPasskeyCode(ctx, req.GetUserId(), "", s.userCodeAlg),
|
||||
s.command.AddUserPasskeyCode(ctx, req.Msg.GetUserId(), "", s.userCodeAlg),
|
||||
)
|
||||
case *user.CreatePasskeyRegistrationLinkRequest_SendLink:
|
||||
return passkeyDetailsToPb(
|
||||
s.command.AddUserPasskeyCodeURLTemplate(ctx, req.GetUserId(), "", s.userCodeAlg, medium.SendLink.GetUrlTemplate()),
|
||||
s.command.AddUserPasskeyCodeURLTemplate(ctx, req.Msg.GetUserId(), "", s.userCodeAlg, medium.SendLink.GetUrlTemplate()),
|
||||
)
|
||||
case *user.CreatePasskeyRegistrationLinkRequest_ReturnCode:
|
||||
return passkeyCodeDetailsToPb(
|
||||
s.command.AddUserPasskeyCodeReturn(ctx, req.GetUserId(), "", s.userCodeAlg),
|
||||
s.command.AddUserPasskeyCodeReturn(ctx, req.Msg.GetUserId(), "", s.userCodeAlg),
|
||||
)
|
||||
default:
|
||||
return nil, zerrors.ThrowUnimplementedf(nil, "USERv2-gaD8y", "verification oneOf %T in method CreatePasskeyRegistrationLink not implemented", medium)
|
||||
}
|
||||
}
|
||||
|
||||
func passkeyDetailsToPb(details *domain.ObjectDetails, err error) (*user.CreatePasskeyRegistrationLinkResponse, error) {
|
||||
func passkeyDetailsToPb(details *domain.ObjectDetails, err error) (*connect.Response[user.CreatePasskeyRegistrationLinkResponse], error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.CreatePasskeyRegistrationLinkResponse{
|
||||
return connect.NewResponse(&user.CreatePasskeyRegistrationLinkResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func passkeyCodeDetailsToPb(details *domain.PasskeyCodeDetails, err error) (*user.CreatePasskeyRegistrationLinkResponse, error) {
|
||||
func passkeyCodeDetailsToPb(details *domain.PasskeyCodeDetails, err error) (*connect.Response[user.CreatePasskeyRegistrationLinkResponse], error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.CreatePasskeyRegistrationLinkResponse{
|
||||
return connect.NewResponse(&user.CreatePasskeyRegistrationLinkResponse{
|
||||
Details: object.DomainToDetailsPb(details.ObjectDetails),
|
||||
Code: &user.PasskeyRegistrationCode{
|
||||
Id: details.CodeID,
|
||||
Code: details.Code,
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) RemovePasskey(ctx context.Context, req *user.RemovePasskeyRequest) (*user.RemovePasskeyResponse, error) {
|
||||
objectDetails, err := s.command.HumanRemovePasswordless(ctx, req.GetUserId(), req.GetPasskeyId(), "")
|
||||
func (s *Server) RemovePasskey(ctx context.Context, req *connect.Request[user.RemovePasskeyRequest]) (*connect.Response[user.RemovePasskeyResponse], error) {
|
||||
objectDetails, err := s.command.HumanRemovePasswordless(ctx, req.Msg.GetUserId(), req.Msg.GetPasskeyId(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.RemovePasskeyResponse{
|
||||
return connect.NewResponse(&user.RemovePasskeyResponse{
|
||||
Details: object.DomainToDetailsPb(objectDetails),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) ListPasskeys(ctx context.Context, req *user.ListPasskeysRequest) (*user.ListPasskeysResponse, error) {
|
||||
func (s *Server) ListPasskeys(ctx context.Context, req *connect.Request[user.ListPasskeysRequest]) (*connect.Response[user.ListPasskeysResponse], error) {
|
||||
query := new(query.UserAuthMethodSearchQueries)
|
||||
err := query.AppendUserIDQuery(req.UserId)
|
||||
err := query.AppendUserIDQuery(req.Msg.UserId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -146,10 +147,10 @@ func (s *Server) ListPasskeys(ctx context.Context, req *user.ListPasskeysRequest
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.ListPasskeysResponse{
|
||||
return connect.NewResponse(&user.ListPasskeysResponse{
|
||||
Details: object.ToListDetails(authMethods.SearchResponse),
|
||||
Result: authMethodsToPasskeyPb(authMethods),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func authMethodsToPasskeyPb(methods *query.AuthMethods) []*user.Passkey {
|
||||
|
@@ -123,11 +123,11 @@ func Test_passkeyRegistrationDetailsToPb(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := passkeyRegistrationDetailsToPb(tt.args.details, tt.args.err)
|
||||
require.ErrorIs(t, err, tt.wantErr)
|
||||
if !proto.Equal(tt.want, got) {
|
||||
if tt.want != nil && !proto.Equal(tt.want, got.Msg) {
|
||||
t.Errorf("Not equal:\nExpected\n%s\nActual:%s", tt.want, got)
|
||||
}
|
||||
if tt.want != nil {
|
||||
grpc.AllFieldsSet(t, got.ProtoReflect())
|
||||
grpc.AllFieldsSet(t, got.Msg.ProtoReflect())
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -181,7 +181,9 @@ func Test_passkeyDetailsToPb(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := passkeyDetailsToPb(tt.args.details, tt.args.err)
|
||||
require.ErrorIs(t, err, tt.args.err)
|
||||
assert.Equal(t, tt.want, got)
|
||||
if tt.want != nil {
|
||||
assert.Equal(t, tt.want, got.Msg)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -242,9 +244,9 @@ func Test_passkeyCodeDetailsToPb(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := passkeyCodeDetailsToPb(tt.args.details, tt.args.err)
|
||||
require.ErrorIs(t, err, tt.args.err)
|
||||
assert.Equal(t, tt.want, got)
|
||||
if tt.want != nil {
|
||||
grpc.AllFieldsSet(t, got.ProtoReflect())
|
||||
assert.Equal(t, tt.want, got.Msg)
|
||||
grpc.AllFieldsSet(t, got.Msg.ProtoReflect())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@@ -3,23 +3,25 @@ package user
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/object/v2"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/user/v2"
|
||||
)
|
||||
|
||||
func (s *Server) PasswordReset(ctx context.Context, req *user.PasswordResetRequest) (_ *user.PasswordResetResponse, err error) {
|
||||
func (s *Server) PasswordReset(ctx context.Context, req *connect.Request[user.PasswordResetRequest]) (_ *connect.Response[user.PasswordResetResponse], err error) {
|
||||
var details *domain.ObjectDetails
|
||||
var code *string
|
||||
|
||||
switch m := req.GetMedium().(type) {
|
||||
switch m := req.Msg.GetMedium().(type) {
|
||||
case *user.PasswordResetRequest_SendLink:
|
||||
details, code, err = s.command.RequestPasswordResetURLTemplate(ctx, req.GetUserId(), m.SendLink.GetUrlTemplate(), notificationTypeToDomain(m.SendLink.GetNotificationType()))
|
||||
details, code, err = s.command.RequestPasswordResetURLTemplate(ctx, req.Msg.GetUserId(), m.SendLink.GetUrlTemplate(), notificationTypeToDomain(m.SendLink.GetNotificationType()))
|
||||
case *user.PasswordResetRequest_ReturnCode:
|
||||
details, code, err = s.command.RequestPasswordResetReturnCode(ctx, req.GetUserId())
|
||||
details, code, err = s.command.RequestPasswordResetReturnCode(ctx, req.Msg.GetUserId())
|
||||
case nil:
|
||||
details, code, err = s.command.RequestPasswordReset(ctx, req.GetUserId())
|
||||
details, code, err = s.command.RequestPasswordReset(ctx, req.Msg.GetUserId())
|
||||
default:
|
||||
err = zerrors.ThrowUnimplementedf(nil, "USERv2-SDeeg", "verification oneOf %T in method RequestPasswordReset not implemented", m)
|
||||
}
|
||||
@@ -27,10 +29,10 @@ func (s *Server) PasswordReset(ctx context.Context, req *user.PasswordResetReque
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &user.PasswordResetResponse{
|
||||
return connect.NewResponse(&user.PasswordResetResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
VerificationCode: code,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func notificationTypeToDomain(notificationType user.NotificationType) domain.NotificationType {
|
||||
@@ -46,16 +48,16 @@ func notificationTypeToDomain(notificationType user.NotificationType) domain.Not
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) SetPassword(ctx context.Context, req *user.SetPasswordRequest) (_ *user.SetPasswordResponse, err error) {
|
||||
func (s *Server) SetPassword(ctx context.Context, req *connect.Request[user.SetPasswordRequest]) (_ *connect.Response[user.SetPasswordResponse], err error) {
|
||||
var details *domain.ObjectDetails
|
||||
|
||||
switch v := req.GetVerification().(type) {
|
||||
switch v := req.Msg.GetVerification().(type) {
|
||||
case *user.SetPasswordRequest_CurrentPassword:
|
||||
details, err = s.command.ChangePassword(ctx, "", req.GetUserId(), v.CurrentPassword, req.GetNewPassword().GetPassword(), "", req.GetNewPassword().GetChangeRequired())
|
||||
details, err = s.command.ChangePassword(ctx, "", req.Msg.GetUserId(), v.CurrentPassword, req.Msg.GetNewPassword().GetPassword(), "", req.Msg.GetNewPassword().GetChangeRequired())
|
||||
case *user.SetPasswordRequest_VerificationCode:
|
||||
details, err = s.command.SetPasswordWithVerifyCode(ctx, "", req.GetUserId(), v.VerificationCode, req.GetNewPassword().GetPassword(), "", req.GetNewPassword().GetChangeRequired())
|
||||
details, err = s.command.SetPasswordWithVerifyCode(ctx, "", req.Msg.GetUserId(), v.VerificationCode, req.Msg.GetNewPassword().GetPassword(), "", req.Msg.GetNewPassword().GetChangeRequired())
|
||||
case nil:
|
||||
details, err = s.command.SetPassword(ctx, "", req.GetUserId(), req.GetNewPassword().GetPassword(), req.GetNewPassword().GetChangeRequired())
|
||||
details, err = s.command.SetPassword(ctx, "", req.Msg.GetUserId(), req.Msg.GetNewPassword().GetPassword(), req.Msg.GetNewPassword().GetChangeRequired())
|
||||
default:
|
||||
err = zerrors.ThrowUnimplementedf(nil, "USERv2-SFdf2", "verification oneOf %T in method SetPasswordRequest not implemented", v)
|
||||
}
|
||||
@@ -63,7 +65,7 @@ func (s *Server) SetPassword(ctx context.Context, req *user.SetPasswordRequest)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &user.SetPasswordResponse{
|
||||
return connect.NewResponse(&user.SetPasswordResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package user
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"github.com/zitadel/oidc/v3/pkg/oidc"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
@@ -13,13 +14,13 @@ import (
|
||||
"github.com/zitadel/zitadel/pkg/grpc/user/v2"
|
||||
)
|
||||
|
||||
func (s *Server) AddPersonalAccessToken(ctx context.Context, req *user.AddPersonalAccessTokenRequest) (*user.AddPersonalAccessTokenResponse, error) {
|
||||
func (s *Server) AddPersonalAccessToken(ctx context.Context, req *connect.Request[user.AddPersonalAccessTokenRequest]) (*connect.Response[user.AddPersonalAccessTokenResponse], error) {
|
||||
newPat := &command.PersonalAccessToken{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: req.UserId,
|
||||
AggregateID: req.Msg.GetUserId(),
|
||||
},
|
||||
PermissionCheck: s.command.NewPermissionCheckUserWrite(ctx),
|
||||
ExpirationDate: req.ExpirationDate.AsTime(),
|
||||
ExpirationDate: req.Msg.GetExpirationDate().AsTime(),
|
||||
Scopes: []string{
|
||||
oidc.ScopeOpenID,
|
||||
oidc.ScopeProfile,
|
||||
@@ -32,25 +33,25 @@ func (s *Server) AddPersonalAccessToken(ctx context.Context, req *user.AddPerson
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.AddPersonalAccessTokenResponse{
|
||||
return connect.NewResponse(&user.AddPersonalAccessTokenResponse{
|
||||
CreationDate: timestamppb.New(details.EventDate),
|
||||
TokenId: newPat.TokenID,
|
||||
Token: newPat.Token,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) RemovePersonalAccessToken(ctx context.Context, req *user.RemovePersonalAccessTokenRequest) (*user.RemovePersonalAccessTokenResponse, error) {
|
||||
func (s *Server) RemovePersonalAccessToken(ctx context.Context, req *connect.Request[user.RemovePersonalAccessTokenRequest]) (*connect.Response[user.RemovePersonalAccessTokenResponse], error) {
|
||||
objectDetails, err := s.command.RemovePersonalAccessToken(ctx, &command.PersonalAccessToken{
|
||||
TokenID: req.TokenId,
|
||||
TokenID: req.Msg.GetTokenId(),
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: req.UserId,
|
||||
AggregateID: req.Msg.GetUserId(),
|
||||
},
|
||||
PermissionCheck: s.command.NewPermissionCheckUserWrite(ctx),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.RemovePersonalAccessTokenResponse{
|
||||
return connect.NewResponse(&user.RemovePersonalAccessTokenResponse{
|
||||
DeletionDate: timestamppb.New(objectDetails.EventDate),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package user
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/filter/v2"
|
||||
@@ -12,12 +13,12 @@ import (
|
||||
"github.com/zitadel/zitadel/pkg/grpc/user/v2"
|
||||
)
|
||||
|
||||
func (s *Server) ListPersonalAccessTokens(ctx context.Context, req *user.ListPersonalAccessTokensRequest) (*user.ListPersonalAccessTokensResponse, error) {
|
||||
offset, limit, asc, err := filter.PaginationPbToQuery(s.systemDefaults, req.Pagination)
|
||||
func (s *Server) ListPersonalAccessTokens(ctx context.Context, req *connect.Request[user.ListPersonalAccessTokensRequest]) (*connect.Response[user.ListPersonalAccessTokensResponse], error) {
|
||||
offset, limit, asc, err := filter.PaginationPbToQuery(s.systemDefaults, req.Msg.GetPagination())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
filters, err := patFiltersToQueries(req.Filters)
|
||||
filters, err := patFiltersToQueries(req.Msg.GetFilters())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -26,7 +27,7 @@ func (s *Server) ListPersonalAccessTokens(ctx context.Context, req *user.ListPer
|
||||
Offset: offset,
|
||||
Limit: limit,
|
||||
Asc: asc,
|
||||
SortingColumn: authnPersonalAccessTokenFieldNameToSortingColumn(req.SortingColumn),
|
||||
SortingColumn: authnPersonalAccessTokenFieldNameToSortingColumn(req.Msg.SortingColumn),
|
||||
},
|
||||
Queries: filters,
|
||||
}
|
||||
@@ -48,7 +49,7 @@ func (s *Server) ListPersonalAccessTokens(ctx context.Context, req *user.ListPer
|
||||
ExpirationDate: timestamppb.New(pat.Expiration),
|
||||
}
|
||||
}
|
||||
return resp, nil
|
||||
return connect.NewResponse(resp), nil
|
||||
}
|
||||
|
||||
func patFiltersToQueries(filters []*user.PersonalAccessTokensSearchFilter) (_ []query.SearchQuery, err error) {
|
||||
|
@@ -3,6 +3,7 @@ package user
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
@@ -11,18 +12,18 @@ import (
|
||||
"github.com/zitadel/zitadel/pkg/grpc/user/v2"
|
||||
)
|
||||
|
||||
func (s *Server) SetPhone(ctx context.Context, req *user.SetPhoneRequest) (resp *user.SetPhoneResponse, err error) {
|
||||
func (s *Server) SetPhone(ctx context.Context, req *connect.Request[user.SetPhoneRequest]) (resp *connect.Response[user.SetPhoneResponse], err error) {
|
||||
var phone *domain.Phone
|
||||
|
||||
switch v := req.GetVerification().(type) {
|
||||
switch v := req.Msg.GetVerification().(type) {
|
||||
case *user.SetPhoneRequest_SendCode:
|
||||
phone, err = s.command.ChangeUserPhone(ctx, req.GetUserId(), req.GetPhone(), s.userCodeAlg)
|
||||
phone, err = s.command.ChangeUserPhone(ctx, req.Msg.GetUserId(), req.Msg.GetPhone(), s.userCodeAlg)
|
||||
case *user.SetPhoneRequest_ReturnCode:
|
||||
phone, err = s.command.ChangeUserPhoneReturnCode(ctx, req.GetUserId(), req.GetPhone(), s.userCodeAlg)
|
||||
phone, err = s.command.ChangeUserPhoneReturnCode(ctx, req.Msg.GetUserId(), req.Msg.GetPhone(), s.userCodeAlg)
|
||||
case *user.SetPhoneRequest_IsVerified:
|
||||
phone, err = s.command.ChangeUserPhoneVerified(ctx, req.GetUserId(), req.GetPhone())
|
||||
phone, err = s.command.ChangeUserPhoneVerified(ctx, req.Msg.GetUserId(), req.Msg.GetPhone())
|
||||
case nil:
|
||||
phone, err = s.command.ChangeUserPhone(ctx, req.GetUserId(), req.GetPhone(), s.userCodeAlg)
|
||||
phone, err = s.command.ChangeUserPhone(ctx, req.Msg.GetUserId(), req.Msg.GetPhone(), s.userCodeAlg)
|
||||
default:
|
||||
err = zerrors.ThrowUnimplementedf(nil, "USERv2-Ahng0", "verification oneOf %T in method SetPhone not implemented", v)
|
||||
}
|
||||
@@ -30,42 +31,42 @@ func (s *Server) SetPhone(ctx context.Context, req *user.SetPhoneRequest) (resp
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &user.SetPhoneResponse{
|
||||
return connect.NewResponse(&user.SetPhoneResponse{
|
||||
Details: &object.Details{
|
||||
Sequence: phone.Sequence,
|
||||
ChangeDate: timestamppb.New(phone.ChangeDate),
|
||||
ResourceOwner: phone.ResourceOwner,
|
||||
},
|
||||
VerificationCode: phone.PlainCode,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) RemovePhone(ctx context.Context, req *user.RemovePhoneRequest) (resp *user.RemovePhoneResponse, err error) {
|
||||
func (s *Server) RemovePhone(ctx context.Context, req *connect.Request[user.RemovePhoneRequest]) (resp *connect.Response[user.RemovePhoneResponse], err error) {
|
||||
details, err := s.command.RemoveUserPhone(ctx,
|
||||
req.GetUserId(),
|
||||
req.Msg.GetUserId(),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &user.RemovePhoneResponse{
|
||||
return connect.NewResponse(&user.RemovePhoneResponse{
|
||||
Details: &object.Details{
|
||||
Sequence: details.Sequence,
|
||||
ChangeDate: timestamppb.New(details.EventDate),
|
||||
ResourceOwner: details.ResourceOwner,
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) ResendPhoneCode(ctx context.Context, req *user.ResendPhoneCodeRequest) (resp *user.ResendPhoneCodeResponse, err error) {
|
||||
func (s *Server) ResendPhoneCode(ctx context.Context, req *connect.Request[user.ResendPhoneCodeRequest]) (resp *connect.Response[user.ResendPhoneCodeResponse], err error) {
|
||||
var phone *domain.Phone
|
||||
switch v := req.GetVerification().(type) {
|
||||
switch v := req.Msg.GetVerification().(type) {
|
||||
case *user.ResendPhoneCodeRequest_SendCode:
|
||||
phone, err = s.command.ResendUserPhoneCode(ctx, req.GetUserId(), s.userCodeAlg)
|
||||
phone, err = s.command.ResendUserPhoneCode(ctx, req.Msg.GetUserId(), s.userCodeAlg)
|
||||
case *user.ResendPhoneCodeRequest_ReturnCode:
|
||||
phone, err = s.command.ResendUserPhoneCodeReturnCode(ctx, req.GetUserId(), s.userCodeAlg)
|
||||
phone, err = s.command.ResendUserPhoneCodeReturnCode(ctx, req.Msg.GetUserId(), s.userCodeAlg)
|
||||
case nil:
|
||||
phone, err = s.command.ResendUserPhoneCode(ctx, req.GetUserId(), s.userCodeAlg)
|
||||
phone, err = s.command.ResendUserPhoneCode(ctx, req.Msg.GetUserId(), s.userCodeAlg)
|
||||
default:
|
||||
err = zerrors.ThrowUnimplementedf(nil, "USERv2-ResendUserPhoneCode", "verification oneOf %T in method SetPhone not implemented", v)
|
||||
}
|
||||
@@ -73,30 +74,30 @@ func (s *Server) ResendPhoneCode(ctx context.Context, req *user.ResendPhoneCodeR
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &user.ResendPhoneCodeResponse{
|
||||
return connect.NewResponse(&user.ResendPhoneCodeResponse{
|
||||
Details: &object.Details{
|
||||
Sequence: phone.Sequence,
|
||||
ChangeDate: timestamppb.New(phone.ChangeDate),
|
||||
ResourceOwner: phone.ResourceOwner,
|
||||
},
|
||||
VerificationCode: phone.PlainCode,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) VerifyPhone(ctx context.Context, req *user.VerifyPhoneRequest) (*user.VerifyPhoneResponse, error) {
|
||||
func (s *Server) VerifyPhone(ctx context.Context, req *connect.Request[user.VerifyPhoneRequest]) (*connect.Response[user.VerifyPhoneResponse], error) {
|
||||
details, err := s.command.VerifyUserPhone(ctx,
|
||||
req.GetUserId(),
|
||||
req.GetVerificationCode(),
|
||||
req.Msg.GetUserId(),
|
||||
req.Msg.GetVerificationCode(),
|
||||
s.userCodeAlg,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.VerifyPhoneResponse{
|
||||
return connect.NewResponse(&user.VerifyPhoneResponse{
|
||||
Details: &object.Details{
|
||||
Sequence: details.Sequence,
|
||||
ChangeDate: timestamppb.New(details.EventDate),
|
||||
ResourceOwner: details.ResourceOwner,
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
@@ -3,37 +3,38 @@ package user
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/user/v2"
|
||||
)
|
||||
|
||||
func (s *Server) AddSecret(ctx context.Context, req *user.AddSecretRequest) (*user.AddSecretResponse, error) {
|
||||
func (s *Server) AddSecret(ctx context.Context, req *connect.Request[user.AddSecretRequest]) (*connect.Response[user.AddSecretResponse], error) {
|
||||
newSecret := &command.GenerateMachineSecret{
|
||||
PermissionCheck: s.command.NewPermissionCheckUserWrite(ctx),
|
||||
}
|
||||
details, err := s.command.GenerateMachineSecret(ctx, req.UserId, "", newSecret)
|
||||
details, err := s.command.GenerateMachineSecret(ctx, req.Msg.GetUserId(), "", newSecret)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.AddSecretResponse{
|
||||
return connect.NewResponse(&user.AddSecretResponse{
|
||||
CreationDate: timestamppb.New(details.EventDate),
|
||||
ClientSecret: newSecret.ClientSecret,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) RemoveSecret(ctx context.Context, req *user.RemoveSecretRequest) (*user.RemoveSecretResponse, error) {
|
||||
func (s *Server) RemoveSecret(ctx context.Context, req *connect.Request[user.RemoveSecretRequest]) (*connect.Response[user.RemoveSecretResponse], error) {
|
||||
details, err := s.command.RemoveMachineSecret(
|
||||
ctx,
|
||||
req.UserId,
|
||||
req.Msg.GetUserId(),
|
||||
"",
|
||||
s.command.NewPermissionCheckUserWrite(ctx),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.RemoveSecretResponse{
|
||||
return connect.NewResponse(&user.RemoveSecretResponse{
|
||||
DeletionDate: timestamppb.New(details.EventDate),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
@@ -2,8 +2,10 @@ package user
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"connectrpc.com/connect"
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/server"
|
||||
@@ -13,12 +15,12 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/user/v2"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/user/v2/userconnect"
|
||||
)
|
||||
|
||||
var _ user.UserServiceServer = (*Server)(nil)
|
||||
var _ userconnect.UserServiceHandler = (*Server)(nil)
|
||||
|
||||
type Server struct {
|
||||
user.UnimplementedUserServiceServer
|
||||
systemDefaults systemdefaults.SystemDefaults
|
||||
command *command.Commands
|
||||
query *query.Queries
|
||||
@@ -58,8 +60,12 @@ func CreateServer(
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) RegisterServer(grpcServer *grpc.Server) {
|
||||
user.RegisterUserServiceServer(grpcServer, s)
|
||||
func (s *Server) RegisterConnectServer(interceptors ...connect.Interceptor) (string, http.Handler) {
|
||||
return userconnect.NewUserServiceHandler(s, connect.WithInterceptors(interceptors...))
|
||||
}
|
||||
|
||||
func (s *Server) FileDescriptor() protoreflect.FileDescriptor {
|
||||
return user.File_zitadel_user_v2_user_service_proto
|
||||
}
|
||||
|
||||
func (s *Server) AppName() string {
|
||||
|
@@ -3,42 +3,44 @@ package user
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/object/v2"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/user/v2"
|
||||
)
|
||||
|
||||
func (s *Server) RegisterTOTP(ctx context.Context, req *user.RegisterTOTPRequest) (*user.RegisterTOTPResponse, error) {
|
||||
func (s *Server) RegisterTOTP(ctx context.Context, req *connect.Request[user.RegisterTOTPRequest]) (*connect.Response[user.RegisterTOTPResponse], error) {
|
||||
return totpDetailsToPb(
|
||||
s.command.AddUserTOTP(ctx, req.GetUserId(), ""),
|
||||
s.command.AddUserTOTP(ctx, req.Msg.GetUserId(), ""),
|
||||
)
|
||||
}
|
||||
|
||||
func totpDetailsToPb(totp *domain.TOTP, err error) (*user.RegisterTOTPResponse, error) {
|
||||
func totpDetailsToPb(totp *domain.TOTP, err error) (*connect.Response[user.RegisterTOTPResponse], error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.RegisterTOTPResponse{
|
||||
return connect.NewResponse(&user.RegisterTOTPResponse{
|
||||
Details: object.DomainToDetailsPb(totp.ObjectDetails),
|
||||
Uri: totp.URI,
|
||||
Secret: totp.Secret,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) VerifyTOTPRegistration(ctx context.Context, req *user.VerifyTOTPRegistrationRequest) (*user.VerifyTOTPRegistrationResponse, error) {
|
||||
objectDetails, err := s.command.CheckUserTOTP(ctx, req.GetUserId(), req.GetCode(), "")
|
||||
func (s *Server) VerifyTOTPRegistration(ctx context.Context, req *connect.Request[user.VerifyTOTPRegistrationRequest]) (*connect.Response[user.VerifyTOTPRegistrationResponse], error) {
|
||||
objectDetails, err := s.command.CheckUserTOTP(ctx, req.Msg.GetUserId(), req.Msg.GetCode(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.VerifyTOTPRegistrationResponse{
|
||||
return connect.NewResponse(&user.VerifyTOTPRegistrationResponse{
|
||||
Details: object.DomainToDetailsPb(objectDetails),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) RemoveTOTP(ctx context.Context, req *user.RemoveTOTPRequest) (*user.RemoveTOTPResponse, error) {
|
||||
objectDetails, err := s.command.HumanRemoveTOTP(ctx, req.GetUserId(), "")
|
||||
func (s *Server) RemoveTOTP(ctx context.Context, req *connect.Request[user.RemoveTOTPRequest]) (*connect.Response[user.RemoveTOTPResponse], error) {
|
||||
objectDetails, err := s.command.HumanRemoveTOTP(ctx, req.Msg.GetUserId(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.RemoveTOTPResponse{Details: object.DomainToDetailsPb(objectDetails)}, nil
|
||||
return connect.NewResponse(&user.RemoveTOTPResponse{Details: object.DomainToDetailsPb(objectDetails)}), nil
|
||||
}
|
||||
|
@@ -63,7 +63,7 @@ func Test_totpDetailsToPb(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := totpDetailsToPb(tt.args.otp, tt.args.err)
|
||||
require.ErrorIs(t, err, tt.wantErr)
|
||||
if !proto.Equal(tt.want, got) {
|
||||
if tt.want != nil && !proto.Equal(tt.want, got.Msg) {
|
||||
t.Errorf("RegisterTOTPResponse =\n%v\nwant\n%v", got, tt.want)
|
||||
}
|
||||
})
|
||||
|
@@ -3,50 +3,52 @@ package user
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/object/v2"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/user/v2"
|
||||
)
|
||||
|
||||
func (s *Server) RegisterU2F(ctx context.Context, req *user.RegisterU2FRequest) (*user.RegisterU2FResponse, error) {
|
||||
func (s *Server) RegisterU2F(ctx context.Context, req *connect.Request[user.RegisterU2FRequest]) (*connect.Response[user.RegisterU2FResponse], error) {
|
||||
return u2fRegistrationDetailsToPb(
|
||||
s.command.RegisterUserU2F(ctx, req.GetUserId(), "", req.GetDomain()),
|
||||
s.command.RegisterUserU2F(ctx, req.Msg.GetUserId(), "", req.Msg.GetDomain()),
|
||||
)
|
||||
}
|
||||
|
||||
func u2fRegistrationDetailsToPb(details *domain.WebAuthNRegistrationDetails, err error) (*user.RegisterU2FResponse, error) {
|
||||
func u2fRegistrationDetailsToPb(details *domain.WebAuthNRegistrationDetails, err error) (*connect.Response[user.RegisterU2FResponse], error) {
|
||||
objectDetails, options, err := webAuthNRegistrationDetailsToPb(details, err)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.RegisterU2FResponse{
|
||||
return connect.NewResponse(&user.RegisterU2FResponse{
|
||||
Details: objectDetails,
|
||||
U2FId: details.ID,
|
||||
PublicKeyCredentialCreationOptions: options,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) VerifyU2FRegistration(ctx context.Context, req *user.VerifyU2FRegistrationRequest) (*user.VerifyU2FRegistrationResponse, error) {
|
||||
pkc, err := req.GetPublicKeyCredential().MarshalJSON()
|
||||
func (s *Server) VerifyU2FRegistration(ctx context.Context, req *connect.Request[user.VerifyU2FRegistrationRequest]) (*connect.Response[user.VerifyU2FRegistrationResponse], error) {
|
||||
pkc, err := req.Msg.GetPublicKeyCredential().MarshalJSON()
|
||||
if err != nil {
|
||||
return nil, zerrors.ThrowInternal(err, "USERv2-IeTh4", "Errors.Internal")
|
||||
}
|
||||
objectDetails, err := s.command.HumanVerifyU2FSetup(ctx, req.GetUserId(), "", req.GetTokenName(), "", pkc)
|
||||
objectDetails, err := s.command.HumanVerifyU2FSetup(ctx, req.Msg.GetUserId(), "", req.Msg.GetTokenName(), "", pkc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.VerifyU2FRegistrationResponse{
|
||||
return connect.NewResponse(&user.VerifyU2FRegistrationResponse{
|
||||
Details: object.DomainToDetailsPb(objectDetails),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) RemoveU2F(ctx context.Context, req *user.RemoveU2FRequest) (*user.RemoveU2FResponse, error) {
|
||||
objectDetails, err := s.command.HumanRemoveU2F(ctx, req.GetUserId(), req.GetU2FId(), "")
|
||||
func (s *Server) RemoveU2F(ctx context.Context, req *connect.Request[user.RemoveU2FRequest]) (*connect.Response[user.RemoveU2FResponse], error) {
|
||||
objectDetails, err := s.command.HumanRemoveU2F(ctx, req.Msg.GetUserId(), req.Msg.GetU2FId(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.RemoveU2FResponse{
|
||||
return connect.NewResponse(&user.RemoveU2FResponse{
|
||||
Details: object.DomainToDetailsPb(objectDetails),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
@@ -92,11 +92,11 @@ func Test_u2fRegistrationDetailsToPb(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := u2fRegistrationDetailsToPb(tt.args.details, tt.args.err)
|
||||
require.ErrorIs(t, err, tt.wantErr)
|
||||
if !proto.Equal(tt.want, got) {
|
||||
if tt.want != nil && !proto.Equal(tt.want, got.Msg) {
|
||||
t.Errorf("Not equal:\nExpected\n%s\nActual:%s", tt.want, got)
|
||||
}
|
||||
if tt.want != nil {
|
||||
grpc.AllFieldsSet(t, got.ProtoReflect())
|
||||
grpc.AllFieldsSet(t, got.Msg.ProtoReflect())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
@@ -15,8 +16,8 @@ import (
|
||||
"github.com/zitadel/zitadel/pkg/grpc/user/v2"
|
||||
)
|
||||
|
||||
func (s *Server) AddHumanUser(ctx context.Context, req *user.AddHumanUserRequest) (_ *user.AddHumanUserResponse, err error) {
|
||||
human, err := AddUserRequestToAddHuman(req)
|
||||
func (s *Server) AddHumanUser(ctx context.Context, req *connect.Request[user.AddHumanUserRequest]) (_ *connect.Response[user.AddHumanUserResponse], err error) {
|
||||
human, err := AddUserRequestToAddHuman(req.Msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -24,12 +25,12 @@ func (s *Server) AddHumanUser(ctx context.Context, req *user.AddHumanUserRequest
|
||||
if err = s.command.AddUserHuman(ctx, orgID, human, false, s.userCodeAlg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.AddHumanUserResponse{
|
||||
return connect.NewResponse(&user.AddHumanUserResponse{
|
||||
UserId: human.ID,
|
||||
Details: object.DomainToDetailsPb(human.Details),
|
||||
EmailCode: human.EmailCode,
|
||||
PhoneCode: human.PhoneCode,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func AddUserRequestToAddHuman(req *user.AddHumanUserRequest) (*command.AddHuman, error) {
|
||||
@@ -117,8 +118,8 @@ func genderToDomain(gender user.Gender) domain.Gender {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) UpdateHumanUser(ctx context.Context, req *user.UpdateHumanUserRequest) (_ *user.UpdateHumanUserResponse, err error) {
|
||||
human, err := updateHumanUserRequestToChangeHuman(req)
|
||||
func (s *Server) UpdateHumanUser(ctx context.Context, req *connect.Request[user.UpdateHumanUserRequest]) (_ *connect.Response[user.UpdateHumanUserResponse], err error) {
|
||||
human, err := updateHumanUserRequestToChangeHuman(req.Msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -126,51 +127,51 @@ func (s *Server) UpdateHumanUser(ctx context.Context, req *user.UpdateHumanUserR
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.UpdateHumanUserResponse{
|
||||
return connect.NewResponse(&user.UpdateHumanUserResponse{
|
||||
Details: object.DomainToDetailsPb(human.Details),
|
||||
EmailCode: human.EmailCode,
|
||||
PhoneCode: human.PhoneCode,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) LockUser(ctx context.Context, req *user.LockUserRequest) (_ *user.LockUserResponse, err error) {
|
||||
details, err := s.command.LockUserV2(ctx, req.UserId)
|
||||
func (s *Server) LockUser(ctx context.Context, req *connect.Request[user.LockUserRequest]) (_ *connect.Response[user.LockUserResponse], err error) {
|
||||
details, err := s.command.LockUserV2(ctx, req.Msg.GetUserId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.LockUserResponse{
|
||||
return connect.NewResponse(&user.LockUserResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) UnlockUser(ctx context.Context, req *user.UnlockUserRequest) (_ *user.UnlockUserResponse, err error) {
|
||||
details, err := s.command.UnlockUserV2(ctx, req.UserId)
|
||||
func (s *Server) UnlockUser(ctx context.Context, req *connect.Request[user.UnlockUserRequest]) (_ *connect.Response[user.UnlockUserResponse], err error) {
|
||||
details, err := s.command.UnlockUserV2(ctx, req.Msg.GetUserId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.UnlockUserResponse{
|
||||
return connect.NewResponse(&user.UnlockUserResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) DeactivateUser(ctx context.Context, req *user.DeactivateUserRequest) (_ *user.DeactivateUserResponse, err error) {
|
||||
details, err := s.command.DeactivateUserV2(ctx, req.UserId)
|
||||
func (s *Server) DeactivateUser(ctx context.Context, req *connect.Request[user.DeactivateUserRequest]) (_ *connect.Response[user.DeactivateUserResponse], err error) {
|
||||
details, err := s.command.DeactivateUserV2(ctx, req.Msg.GetUserId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.DeactivateUserResponse{
|
||||
return connect.NewResponse(&user.DeactivateUserResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) ReactivateUser(ctx context.Context, req *user.ReactivateUserRequest) (_ *user.ReactivateUserResponse, err error) {
|
||||
details, err := s.command.ReactivateUserV2(ctx, req.UserId)
|
||||
func (s *Server) ReactivateUser(ctx context.Context, req *connect.Request[user.ReactivateUserRequest]) (_ *connect.Response[user.ReactivateUserResponse], err error) {
|
||||
details, err := s.command.ReactivateUserV2(ctx, req.Msg.GetUserId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.ReactivateUserResponse{
|
||||
return connect.NewResponse(&user.ReactivateUserResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func ifNotNilPtr[v, p any](value *v, conv func(v) p) *p {
|
||||
@@ -182,18 +183,18 @@ func ifNotNilPtr[v, p any](value *v, conv func(v) p) *p {
|
||||
return &pVal
|
||||
}
|
||||
|
||||
func (s *Server) DeleteUser(ctx context.Context, req *user.DeleteUserRequest) (_ *user.DeleteUserResponse, err error) {
|
||||
memberships, grants, err := s.removeUserDependencies(ctx, req.GetUserId())
|
||||
func (s *Server) DeleteUser(ctx context.Context, req *connect.Request[user.DeleteUserRequest]) (_ *connect.Response[user.DeleteUserResponse], err error) {
|
||||
memberships, grants, err := s.removeUserDependencies(ctx, req.Msg.GetUserId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
details, err := s.command.RemoveUserV2(ctx, req.UserId, "", memberships, grants...)
|
||||
details, err := s.command.RemoveUserV2(ctx, req.Msg.GetUserId(), "", memberships, grants...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.DeleteUserResponse{
|
||||
return connect.NewResponse(&user.DeleteUserResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) removeUserDependencies(ctx context.Context, userID string) ([]*command.CascadingMembership, []string, error) {
|
||||
@@ -268,35 +269,35 @@ func userGrantsToIDs(userGrants []*query.UserGrant) []string {
|
||||
return converted
|
||||
}
|
||||
|
||||
func (s *Server) ListAuthenticationMethodTypes(ctx context.Context, req *user.ListAuthenticationMethodTypesRequest) (*user.ListAuthenticationMethodTypesResponse, error) {
|
||||
authMethods, err := s.query.ListUserAuthMethodTypes(ctx, req.GetUserId(), true, req.GetDomainQuery().GetIncludeWithoutDomain(), req.GetDomainQuery().GetDomain())
|
||||
func (s *Server) ListAuthenticationMethodTypes(ctx context.Context, req *connect.Request[user.ListAuthenticationMethodTypesRequest]) (*connect.Response[user.ListAuthenticationMethodTypesResponse], error) {
|
||||
authMethods, err := s.query.ListUserAuthMethodTypes(ctx, req.Msg.GetUserId(), true, req.Msg.GetDomainQuery().GetIncludeWithoutDomain(), req.Msg.GetDomainQuery().GetDomain())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.ListAuthenticationMethodTypesResponse{
|
||||
return connect.NewResponse(&user.ListAuthenticationMethodTypesResponse{
|
||||
Details: object.ToListDetails(authMethods.SearchResponse),
|
||||
AuthMethodTypes: authMethodTypesToPb(authMethods.AuthMethodTypes),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) ListAuthenticationFactors(ctx context.Context, req *user.ListAuthenticationFactorsRequest) (*user.ListAuthenticationFactorsResponse, error) {
|
||||
func (s *Server) ListAuthenticationFactors(ctx context.Context, req *connect.Request[user.ListAuthenticationFactorsRequest]) (*connect.Response[user.ListAuthenticationFactorsResponse], error) {
|
||||
query := new(query.UserAuthMethodSearchQueries)
|
||||
|
||||
if err := query.AppendUserIDQuery(req.UserId); err != nil {
|
||||
if err := query.AppendUserIDQuery(req.Msg.GetUserId()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
authMethodsType := []domain.UserAuthMethodType{domain.UserAuthMethodTypeU2F, domain.UserAuthMethodTypeTOTP, domain.UserAuthMethodTypeOTPSMS, domain.UserAuthMethodTypeOTPEmail}
|
||||
if len(req.GetAuthFactors()) > 0 {
|
||||
authMethodsType = object.AuthFactorsToPb(req.GetAuthFactors())
|
||||
if len(req.Msg.GetAuthFactors()) > 0 {
|
||||
authMethodsType = object.AuthFactorsToPb(req.Msg.GetAuthFactors())
|
||||
}
|
||||
if err := query.AppendAuthMethodsQuery(authMethodsType...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
states := []domain.MFAState{domain.MFAStateReady}
|
||||
if len(req.GetStates()) > 0 {
|
||||
states = object.AuthFactorStatesToPb(req.GetStates())
|
||||
if len(req.Msg.GetStates()) > 0 {
|
||||
states = object.AuthFactorStatesToPb(req.Msg.GetStates())
|
||||
}
|
||||
if err := query.AppendStatesQuery(states...); err != nil {
|
||||
return nil, err
|
||||
@@ -307,9 +308,9 @@ func (s *Server) ListAuthenticationFactors(ctx context.Context, req *user.ListAu
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &user.ListAuthenticationFactorsResponse{
|
||||
return connect.NewResponse(&user.ListAuthenticationFactorsResponse{
|
||||
Result: object.AuthMethodsToPb(authMethods),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func authMethodTypesToPb(methodTypes []domain.UserAuthMethodType) []user.AuthenticationMethodType {
|
||||
@@ -343,8 +344,8 @@ func authMethodTypeToPb(methodType domain.UserAuthMethodType) user.Authenticatio
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) CreateInviteCode(ctx context.Context, req *user.CreateInviteCodeRequest) (*user.CreateInviteCodeResponse, error) {
|
||||
invite, err := createInviteCodeRequestToCommand(req)
|
||||
func (s *Server) CreateInviteCode(ctx context.Context, req *connect.Request[user.CreateInviteCodeRequest]) (*connect.Response[user.CreateInviteCodeResponse], error) {
|
||||
invite, err := createInviteCodeRequestToCommand(req.Msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -352,30 +353,30 @@ func (s *Server) CreateInviteCode(ctx context.Context, req *user.CreateInviteCod
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.CreateInviteCodeResponse{
|
||||
return connect.NewResponse(&user.CreateInviteCodeResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
InviteCode: code,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) ResendInviteCode(ctx context.Context, req *user.ResendInviteCodeRequest) (*user.ResendInviteCodeResponse, error) {
|
||||
details, err := s.command.ResendInviteCode(ctx, req.GetUserId(), "", "")
|
||||
func (s *Server) ResendInviteCode(ctx context.Context, req *connect.Request[user.ResendInviteCodeRequest]) (*connect.Response[user.ResendInviteCodeResponse], error) {
|
||||
details, err := s.command.ResendInviteCode(ctx, req.Msg.GetUserId(), "", "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.ResendInviteCodeResponse{
|
||||
return connect.NewResponse(&user.ResendInviteCodeResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) VerifyInviteCode(ctx context.Context, req *user.VerifyInviteCodeRequest) (*user.VerifyInviteCodeResponse, error) {
|
||||
details, err := s.command.VerifyInviteCode(ctx, req.GetUserId(), req.GetVerificationCode())
|
||||
func (s *Server) VerifyInviteCode(ctx context.Context, req *connect.Request[user.VerifyInviteCodeRequest]) (*connect.Response[user.VerifyInviteCodeResponse], error) {
|
||||
details, err := s.command.VerifyInviteCode(ctx, req.Msg.GetUserId(), req.Msg.GetVerificationCode())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.VerifyInviteCodeResponse{
|
||||
return connect.NewResponse(&user.VerifyInviteCodeResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func createInviteCodeRequestToCommand(req *user.CreateInviteCodeRequest) (*command.CreateUserInvite, error) {
|
||||
@@ -394,33 +395,33 @@ func createInviteCodeRequestToCommand(req *user.CreateInviteCodeRequest) (*comma
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) HumanMFAInitSkipped(ctx context.Context, req *user.HumanMFAInitSkippedRequest) (_ *user.HumanMFAInitSkippedResponse, err error) {
|
||||
details, err := s.command.HumanMFAInitSkippedV2(ctx, req.UserId)
|
||||
func (s *Server) HumanMFAInitSkipped(ctx context.Context, req *connect.Request[user.HumanMFAInitSkippedRequest]) (_ *connect.Response[user.HumanMFAInitSkippedResponse], err error) {
|
||||
details, err := s.command.HumanMFAInitSkippedV2(ctx, req.Msg.GetUserId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.HumanMFAInitSkippedResponse{
|
||||
return connect.NewResponse(&user.HumanMFAInitSkippedResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) CreateUser(ctx context.Context, req *user.CreateUserRequest) (*user.CreateUserResponse, error) {
|
||||
switch userType := req.GetUserType().(type) {
|
||||
func (s *Server) CreateUser(ctx context.Context, req *connect.Request[user.CreateUserRequest]) (*connect.Response[user.CreateUserResponse], error) {
|
||||
switch userType := req.Msg.GetUserType().(type) {
|
||||
case *user.CreateUserRequest_Human_:
|
||||
return s.createUserTypeHuman(ctx, userType.Human, req.OrganizationId, req.Username, req.UserId)
|
||||
return s.createUserTypeHuman(ctx, userType.Human, req.Msg.GetOrganizationId(), req.Msg.Username, req.Msg.UserId)
|
||||
case *user.CreateUserRequest_Machine_:
|
||||
return s.createUserTypeMachine(ctx, userType.Machine, req.OrganizationId, req.GetUsername(), req.GetUserId())
|
||||
return s.createUserTypeMachine(ctx, userType.Machine, req.Msg.GetOrganizationId(), req.Msg.GetUsername(), req.Msg.GetUserId())
|
||||
default:
|
||||
return nil, zerrors.ThrowInternal(nil, "", "user type is not implemented")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) UpdateUser(ctx context.Context, req *user.UpdateUserRequest) (*user.UpdateUserResponse, error) {
|
||||
switch userType := req.GetUserType().(type) {
|
||||
func (s *Server) UpdateUser(ctx context.Context, req *connect.Request[user.UpdateUserRequest]) (*connect.Response[user.UpdateUserResponse], error) {
|
||||
switch userType := req.Msg.GetUserType().(type) {
|
||||
case *user.UpdateUserRequest_Human_:
|
||||
return s.updateUserTypeHuman(ctx, userType.Human, req.UserId, req.Username)
|
||||
return s.updateUserTypeHuman(ctx, userType.Human, req.Msg.GetUserId(), req.Msg.Username)
|
||||
case *user.UpdateUserRequest_Machine_:
|
||||
return s.updateUserTypeMachine(ctx, userType.Machine, req.UserId, req.Username)
|
||||
return s.updateUserTypeMachine(ctx, userType.Machine, req.Msg.GetUserId(), req.Msg.Username)
|
||||
default:
|
||||
return nil, zerrors.ThrowUnimplemented(nil, "", "user type is not implemented")
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package user
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"github.com/muhlemmer/gu"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
@@ -13,12 +14,12 @@ import (
|
||||
"github.com/zitadel/zitadel/pkg/grpc/user/v2"
|
||||
)
|
||||
|
||||
func (s *Server) GetUserByID(ctx context.Context, req *user.GetUserByIDRequest) (_ *user.GetUserByIDResponse, err error) {
|
||||
resp, err := s.query.GetUserByIDWithPermission(ctx, true, req.GetUserId(), s.checkPermission)
|
||||
func (s *Server) GetUserByID(ctx context.Context, req *connect.Request[user.GetUserByIDRequest]) (_ *connect.Response[user.GetUserByIDResponse], err error) {
|
||||
resp, err := s.query.GetUserByIDWithPermission(ctx, true, req.Msg.GetUserId(), s.checkPermission)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.GetUserByIDResponse{
|
||||
return connect.NewResponse(&user.GetUserByIDResponse{
|
||||
Details: object.DomainToDetailsPb(&domain.ObjectDetails{
|
||||
Sequence: resp.Sequence,
|
||||
CreationDate: resp.CreationDate,
|
||||
@@ -26,11 +27,11 @@ func (s *Server) GetUserByID(ctx context.Context, req *user.GetUserByIDRequest)
|
||||
ResourceOwner: resp.ResourceOwner,
|
||||
}),
|
||||
User: userToPb(resp, s.assetAPIPrefix(ctx)),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) ListUsers(ctx context.Context, req *user.ListUsersRequest) (*user.ListUsersResponse, error) {
|
||||
queries, err := listUsersRequestToModel(req)
|
||||
func (s *Server) ListUsers(ctx context.Context, req *connect.Request[user.ListUsersRequest]) (*connect.Response[user.ListUsersResponse], error) {
|
||||
queries, err := listUsersRequestToModel(req.Msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -38,10 +39,10 @@ func (s *Server) ListUsers(ctx context.Context, req *user.ListUsersRequest) (*us
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.ListUsersResponse{
|
||||
return connect.NewResponse(&user.ListUsersResponse{
|
||||
Result: UsersToPb(res.Users, s.assetAPIPrefix(ctx)),
|
||||
Details: object.ToListDetails(res.SearchResponse),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func UsersToPb(users []*query.User, assetPrefix string) []*user.User {
|
||||
|
@@ -3,6 +3,7 @@ package user
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
@@ -11,18 +12,18 @@ import (
|
||||
user "github.com/zitadel/zitadel/pkg/grpc/user/v2beta"
|
||||
)
|
||||
|
||||
func (s *Server) SetEmail(ctx context.Context, req *user.SetEmailRequest) (resp *user.SetEmailResponse, err error) {
|
||||
func (s *Server) SetEmail(ctx context.Context, req *connect.Request[user.SetEmailRequest]) (resp *connect.Response[user.SetEmailResponse], err error) {
|
||||
var email *domain.Email
|
||||
|
||||
switch v := req.GetVerification().(type) {
|
||||
switch v := req.Msg.GetVerification().(type) {
|
||||
case *user.SetEmailRequest_SendCode:
|
||||
email, err = s.command.ChangeUserEmailURLTemplate(ctx, req.GetUserId(), req.GetEmail(), s.userCodeAlg, v.SendCode.GetUrlTemplate())
|
||||
email, err = s.command.ChangeUserEmailURLTemplate(ctx, req.Msg.GetUserId(), req.Msg.GetEmail(), s.userCodeAlg, v.SendCode.GetUrlTemplate())
|
||||
case *user.SetEmailRequest_ReturnCode:
|
||||
email, err = s.command.ChangeUserEmailReturnCode(ctx, req.GetUserId(), req.GetEmail(), s.userCodeAlg)
|
||||
email, err = s.command.ChangeUserEmailReturnCode(ctx, req.Msg.GetUserId(), req.Msg.GetEmail(), s.userCodeAlg)
|
||||
case *user.SetEmailRequest_IsVerified:
|
||||
email, err = s.command.ChangeUserEmailVerified(ctx, req.GetUserId(), req.GetEmail())
|
||||
email, err = s.command.ChangeUserEmailVerified(ctx, req.Msg.GetUserId(), req.Msg.GetEmail())
|
||||
case nil:
|
||||
email, err = s.command.ChangeUserEmail(ctx, req.GetUserId(), req.GetEmail(), s.userCodeAlg)
|
||||
email, err = s.command.ChangeUserEmail(ctx, req.Msg.GetUserId(), req.Msg.GetEmail(), s.userCodeAlg)
|
||||
default:
|
||||
err = zerrors.ThrowUnimplementedf(nil, "USERv2-Ahng0", "verification oneOf %T in method SetEmail not implemented", v)
|
||||
}
|
||||
@@ -30,26 +31,26 @@ func (s *Server) SetEmail(ctx context.Context, req *user.SetEmailRequest) (resp
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &user.SetEmailResponse{
|
||||
return connect.NewResponse(&user.SetEmailResponse{
|
||||
Details: &object.Details{
|
||||
Sequence: email.Sequence,
|
||||
ChangeDate: timestamppb.New(email.ChangeDate),
|
||||
ResourceOwner: email.ResourceOwner,
|
||||
},
|
||||
VerificationCode: email.PlainCode,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) ResendEmailCode(ctx context.Context, req *user.ResendEmailCodeRequest) (resp *user.ResendEmailCodeResponse, err error) {
|
||||
func (s *Server) ResendEmailCode(ctx context.Context, req *connect.Request[user.ResendEmailCodeRequest]) (resp *connect.Response[user.ResendEmailCodeResponse], err error) {
|
||||
var email *domain.Email
|
||||
|
||||
switch v := req.GetVerification().(type) {
|
||||
switch v := req.Msg.GetVerification().(type) {
|
||||
case *user.ResendEmailCodeRequest_SendCode:
|
||||
email, err = s.command.ResendUserEmailCodeURLTemplate(ctx, req.GetUserId(), s.userCodeAlg, v.SendCode.GetUrlTemplate())
|
||||
email, err = s.command.ResendUserEmailCodeURLTemplate(ctx, req.Msg.GetUserId(), s.userCodeAlg, v.SendCode.GetUrlTemplate())
|
||||
case *user.ResendEmailCodeRequest_ReturnCode:
|
||||
email, err = s.command.ResendUserEmailReturnCode(ctx, req.GetUserId(), s.userCodeAlg)
|
||||
email, err = s.command.ResendUserEmailReturnCode(ctx, req.Msg.GetUserId(), s.userCodeAlg)
|
||||
case nil:
|
||||
email, err = s.command.ResendUserEmailCode(ctx, req.GetUserId(), s.userCodeAlg)
|
||||
email, err = s.command.ResendUserEmailCode(ctx, req.Msg.GetUserId(), s.userCodeAlg)
|
||||
default:
|
||||
err = zerrors.ThrowUnimplementedf(nil, "USERv2-faj0l0nj5x", "verification oneOf %T in method ResendEmailCode not implemented", v)
|
||||
}
|
||||
@@ -57,30 +58,30 @@ func (s *Server) ResendEmailCode(ctx context.Context, req *user.ResendEmailCodeR
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &user.ResendEmailCodeResponse{
|
||||
return connect.NewResponse(&user.ResendEmailCodeResponse{
|
||||
Details: &object.Details{
|
||||
Sequence: email.Sequence,
|
||||
ChangeDate: timestamppb.New(email.ChangeDate),
|
||||
ResourceOwner: email.ResourceOwner,
|
||||
},
|
||||
VerificationCode: email.PlainCode,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) VerifyEmail(ctx context.Context, req *user.VerifyEmailRequest) (*user.VerifyEmailResponse, error) {
|
||||
func (s *Server) VerifyEmail(ctx context.Context, req *connect.Request[user.VerifyEmailRequest]) (*connect.Response[user.VerifyEmailResponse], error) {
|
||||
details, err := s.command.VerifyUserEmail(ctx,
|
||||
req.GetUserId(),
|
||||
req.GetVerificationCode(),
|
||||
req.Msg.GetUserId(),
|
||||
req.Msg.GetVerificationCode(),
|
||||
s.userCodeAlg,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.VerifyEmailResponse{
|
||||
return connect.NewResponse(&user.VerifyEmailResponse{
|
||||
Details: &object.Details{
|
||||
Sequence: details.Sequence,
|
||||
ChangeDate: timestamppb.New(details.EventDate),
|
||||
ResourceOwner: details.ResourceOwner,
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
@@ -3,40 +3,42 @@ package user
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
|
||||
object "github.com/zitadel/zitadel/internal/api/grpc/object/v2beta"
|
||||
user "github.com/zitadel/zitadel/pkg/grpc/user/v2beta"
|
||||
)
|
||||
|
||||
func (s *Server) AddOTPSMS(ctx context.Context, req *user.AddOTPSMSRequest) (*user.AddOTPSMSResponse, error) {
|
||||
details, err := s.command.AddHumanOTPSMS(ctx, req.GetUserId(), "")
|
||||
func (s *Server) AddOTPSMS(ctx context.Context, req *connect.Request[user.AddOTPSMSRequest]) (*connect.Response[user.AddOTPSMSResponse], error) {
|
||||
details, err := s.command.AddHumanOTPSMS(ctx, req.Msg.GetUserId(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.AddOTPSMSResponse{Details: object.DomainToDetailsPb(details)}, nil
|
||||
return connect.NewResponse(&user.AddOTPSMSResponse{Details: object.DomainToDetailsPb(details)}), nil
|
||||
|
||||
}
|
||||
|
||||
func (s *Server) RemoveOTPSMS(ctx context.Context, req *user.RemoveOTPSMSRequest) (*user.RemoveOTPSMSResponse, error) {
|
||||
objectDetails, err := s.command.RemoveHumanOTPSMS(ctx, req.GetUserId(), "")
|
||||
func (s *Server) RemoveOTPSMS(ctx context.Context, req *connect.Request[user.RemoveOTPSMSRequest]) (*connect.Response[user.RemoveOTPSMSResponse], error) {
|
||||
objectDetails, err := s.command.RemoveHumanOTPSMS(ctx, req.Msg.GetUserId(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.RemoveOTPSMSResponse{Details: object.DomainToDetailsPb(objectDetails)}, nil
|
||||
return connect.NewResponse(&user.RemoveOTPSMSResponse{Details: object.DomainToDetailsPb(objectDetails)}), nil
|
||||
}
|
||||
|
||||
func (s *Server) AddOTPEmail(ctx context.Context, req *user.AddOTPEmailRequest) (*user.AddOTPEmailResponse, error) {
|
||||
details, err := s.command.AddHumanOTPEmail(ctx, req.GetUserId(), "")
|
||||
func (s *Server) AddOTPEmail(ctx context.Context, req *connect.Request[user.AddOTPEmailRequest]) (*connect.Response[user.AddOTPEmailResponse], error) {
|
||||
details, err := s.command.AddHumanOTPEmail(ctx, req.Msg.GetUserId(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.AddOTPEmailResponse{Details: object.DomainToDetailsPb(details)}, nil
|
||||
return connect.NewResponse(&user.AddOTPEmailResponse{Details: object.DomainToDetailsPb(details)}), nil
|
||||
|
||||
}
|
||||
|
||||
func (s *Server) RemoveOTPEmail(ctx context.Context, req *user.RemoveOTPEmailRequest) (*user.RemoveOTPEmailResponse, error) {
|
||||
objectDetails, err := s.command.RemoveHumanOTPEmail(ctx, req.GetUserId(), "")
|
||||
func (s *Server) RemoveOTPEmail(ctx context.Context, req *connect.Request[user.RemoveOTPEmailRequest]) (*connect.Response[user.RemoveOTPEmailResponse], error) {
|
||||
objectDetails, err := s.command.RemoveHumanOTPEmail(ctx, req.Msg.GetUserId(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.RemoveOTPEmailResponse{Details: object.DomainToDetailsPb(objectDetails)}, nil
|
||||
return connect.NewResponse(&user.RemoveOTPEmailResponse{Details: object.DomainToDetailsPb(objectDetails)}), nil
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package user
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
|
||||
object "github.com/zitadel/zitadel/internal/api/grpc/object/v2beta"
|
||||
@@ -12,17 +13,17 @@ import (
|
||||
user "github.com/zitadel/zitadel/pkg/grpc/user/v2beta"
|
||||
)
|
||||
|
||||
func (s *Server) RegisterPasskey(ctx context.Context, req *user.RegisterPasskeyRequest) (resp *user.RegisterPasskeyResponse, err error) {
|
||||
func (s *Server) RegisterPasskey(ctx context.Context, req *connect.Request[user.RegisterPasskeyRequest]) (resp *connect.Response[user.RegisterPasskeyResponse], err error) {
|
||||
var (
|
||||
authenticator = passkeyAuthenticatorToDomain(req.GetAuthenticator())
|
||||
authenticator = passkeyAuthenticatorToDomain(req.Msg.GetAuthenticator())
|
||||
)
|
||||
if code := req.GetCode(); code != nil {
|
||||
if code := req.Msg.GetCode(); code != nil {
|
||||
return passkeyRegistrationDetailsToPb(
|
||||
s.command.RegisterUserPasskeyWithCode(ctx, req.GetUserId(), "", authenticator, code.Id, code.Code, req.GetDomain(), s.userCodeAlg),
|
||||
s.command.RegisterUserPasskeyWithCode(ctx, req.Msg.GetUserId(), "", authenticator, code.Id, code.Code, req.Msg.GetDomain(), s.userCodeAlg),
|
||||
)
|
||||
}
|
||||
return passkeyRegistrationDetailsToPb(
|
||||
s.command.RegisterUserPasskey(ctx, req.GetUserId(), "", req.GetDomain(), authenticator),
|
||||
s.command.RegisterUserPasskey(ctx, req.Msg.GetUserId(), "", req.Msg.GetDomain(), authenticator),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -50,69 +51,69 @@ func webAuthNRegistrationDetailsToPb(details *domain.WebAuthNRegistrationDetails
|
||||
return object.DomainToDetailsPb(details.ObjectDetails), options, nil
|
||||
}
|
||||
|
||||
func passkeyRegistrationDetailsToPb(details *domain.WebAuthNRegistrationDetails, err error) (*user.RegisterPasskeyResponse, error) {
|
||||
func passkeyRegistrationDetailsToPb(details *domain.WebAuthNRegistrationDetails, err error) (*connect.Response[user.RegisterPasskeyResponse], error) {
|
||||
objectDetails, options, err := webAuthNRegistrationDetailsToPb(details, err)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.RegisterPasskeyResponse{
|
||||
return connect.NewResponse(&user.RegisterPasskeyResponse{
|
||||
Details: objectDetails,
|
||||
PasskeyId: details.ID,
|
||||
PublicKeyCredentialCreationOptions: options,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) VerifyPasskeyRegistration(ctx context.Context, req *user.VerifyPasskeyRegistrationRequest) (*user.VerifyPasskeyRegistrationResponse, error) {
|
||||
pkc, err := req.GetPublicKeyCredential().MarshalJSON()
|
||||
func (s *Server) VerifyPasskeyRegistration(ctx context.Context, req *connect.Request[user.VerifyPasskeyRegistrationRequest]) (*connect.Response[user.VerifyPasskeyRegistrationResponse], error) {
|
||||
pkc, err := req.Msg.GetPublicKeyCredential().MarshalJSON()
|
||||
if err != nil {
|
||||
return nil, zerrors.ThrowInternal(err, "USERv2-Pha2o", "Errors.Internal")
|
||||
}
|
||||
objectDetails, err := s.command.HumanHumanPasswordlessSetup(ctx, req.GetUserId(), "", req.GetPasskeyName(), "", pkc)
|
||||
objectDetails, err := s.command.HumanHumanPasswordlessSetup(ctx, req.Msg.GetUserId(), "", req.Msg.GetPasskeyName(), "", pkc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.VerifyPasskeyRegistrationResponse{
|
||||
return connect.NewResponse(&user.VerifyPasskeyRegistrationResponse{
|
||||
Details: object.DomainToDetailsPb(objectDetails),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) CreatePasskeyRegistrationLink(ctx context.Context, req *user.CreatePasskeyRegistrationLinkRequest) (resp *user.CreatePasskeyRegistrationLinkResponse, err error) {
|
||||
switch medium := req.Medium.(type) {
|
||||
func (s *Server) CreatePasskeyRegistrationLink(ctx context.Context, req *connect.Request[user.CreatePasskeyRegistrationLinkRequest]) (resp *connect.Response[user.CreatePasskeyRegistrationLinkResponse], err error) {
|
||||
switch medium := req.Msg.Medium.(type) {
|
||||
case nil:
|
||||
return passkeyDetailsToPb(
|
||||
s.command.AddUserPasskeyCode(ctx, req.GetUserId(), "", s.userCodeAlg),
|
||||
s.command.AddUserPasskeyCode(ctx, req.Msg.GetUserId(), "", s.userCodeAlg),
|
||||
)
|
||||
case *user.CreatePasskeyRegistrationLinkRequest_SendLink:
|
||||
return passkeyDetailsToPb(
|
||||
s.command.AddUserPasskeyCodeURLTemplate(ctx, req.GetUserId(), "", s.userCodeAlg, medium.SendLink.GetUrlTemplate()),
|
||||
s.command.AddUserPasskeyCodeURLTemplate(ctx, req.Msg.GetUserId(), "", s.userCodeAlg, medium.SendLink.GetUrlTemplate()),
|
||||
)
|
||||
case *user.CreatePasskeyRegistrationLinkRequest_ReturnCode:
|
||||
return passkeyCodeDetailsToPb(
|
||||
s.command.AddUserPasskeyCodeReturn(ctx, req.GetUserId(), "", s.userCodeAlg),
|
||||
s.command.AddUserPasskeyCodeReturn(ctx, req.Msg.GetUserId(), "", s.userCodeAlg),
|
||||
)
|
||||
default:
|
||||
return nil, zerrors.ThrowUnimplementedf(nil, "USERv2-gaD8y", "verification oneOf %T in method CreatePasskeyRegistrationLink not implemented", medium)
|
||||
}
|
||||
}
|
||||
|
||||
func passkeyDetailsToPb(details *domain.ObjectDetails, err error) (*user.CreatePasskeyRegistrationLinkResponse, error) {
|
||||
func passkeyDetailsToPb(details *domain.ObjectDetails, err error) (*connect.Response[user.CreatePasskeyRegistrationLinkResponse], error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.CreatePasskeyRegistrationLinkResponse{
|
||||
return connect.NewResponse(&user.CreatePasskeyRegistrationLinkResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func passkeyCodeDetailsToPb(details *domain.PasskeyCodeDetails, err error) (*user.CreatePasskeyRegistrationLinkResponse, error) {
|
||||
func passkeyCodeDetailsToPb(details *domain.PasskeyCodeDetails, err error) (*connect.Response[user.CreatePasskeyRegistrationLinkResponse], error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.CreatePasskeyRegistrationLinkResponse{
|
||||
return connect.NewResponse(&user.CreatePasskeyRegistrationLinkResponse{
|
||||
Details: object.DomainToDetailsPb(details.ObjectDetails),
|
||||
Code: &user.PasskeyRegistrationCode{
|
||||
Id: details.CodeID,
|
||||
Code: details.Code,
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
@@ -123,11 +123,11 @@ func Test_passkeyRegistrationDetailsToPb(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := passkeyRegistrationDetailsToPb(tt.args.details, tt.args.err)
|
||||
require.ErrorIs(t, err, tt.wantErr)
|
||||
if !proto.Equal(tt.want, got) {
|
||||
if tt.want != nil && !proto.Equal(tt.want, got.Msg) {
|
||||
t.Errorf("Not equal:\nExpected\n%s\nActual:%s", tt.want, got)
|
||||
}
|
||||
if tt.want != nil {
|
||||
grpc.AllFieldsSet(t, got.ProtoReflect())
|
||||
grpc.AllFieldsSet(t, got.Msg.ProtoReflect())
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -181,7 +181,9 @@ func Test_passkeyDetailsToPb(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := passkeyDetailsToPb(tt.args.details, tt.args.err)
|
||||
require.ErrorIs(t, err, tt.args.err)
|
||||
assert.Equal(t, tt.want, got)
|
||||
if tt.want != nil {
|
||||
assert.Equal(t, tt.want, got.Msg)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -242,9 +244,9 @@ func Test_passkeyCodeDetailsToPb(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := passkeyCodeDetailsToPb(tt.args.details, tt.args.err)
|
||||
require.ErrorIs(t, err, tt.args.err)
|
||||
assert.Equal(t, tt.want, got)
|
||||
if tt.want != nil {
|
||||
grpc.AllFieldsSet(t, got.ProtoReflect())
|
||||
assert.Equal(t, tt.want, got.Msg)
|
||||
grpc.AllFieldsSet(t, got.Msg.ProtoReflect())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@@ -3,23 +3,25 @@ package user
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
|
||||
object "github.com/zitadel/zitadel/internal/api/grpc/object/v2beta"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
user "github.com/zitadel/zitadel/pkg/grpc/user/v2beta"
|
||||
)
|
||||
|
||||
func (s *Server) PasswordReset(ctx context.Context, req *user.PasswordResetRequest) (_ *user.PasswordResetResponse, err error) {
|
||||
func (s *Server) PasswordReset(ctx context.Context, req *connect.Request[user.PasswordResetRequest]) (_ *connect.Response[user.PasswordResetResponse], err error) {
|
||||
var details *domain.ObjectDetails
|
||||
var code *string
|
||||
|
||||
switch m := req.GetMedium().(type) {
|
||||
switch m := req.Msg.GetMedium().(type) {
|
||||
case *user.PasswordResetRequest_SendLink:
|
||||
details, code, err = s.command.RequestPasswordResetURLTemplate(ctx, req.GetUserId(), m.SendLink.GetUrlTemplate(), notificationTypeToDomain(m.SendLink.GetNotificationType()))
|
||||
details, code, err = s.command.RequestPasswordResetURLTemplate(ctx, req.Msg.GetUserId(), m.SendLink.GetUrlTemplate(), notificationTypeToDomain(m.SendLink.GetNotificationType()))
|
||||
case *user.PasswordResetRequest_ReturnCode:
|
||||
details, code, err = s.command.RequestPasswordResetReturnCode(ctx, req.GetUserId())
|
||||
details, code, err = s.command.RequestPasswordResetReturnCode(ctx, req.Msg.GetUserId())
|
||||
case nil:
|
||||
details, code, err = s.command.RequestPasswordReset(ctx, req.GetUserId())
|
||||
details, code, err = s.command.RequestPasswordReset(ctx, req.Msg.GetUserId())
|
||||
default:
|
||||
err = zerrors.ThrowUnimplementedf(nil, "USERv2-SDeeg", "verification oneOf %T in method RequestPasswordReset not implemented", m)
|
||||
}
|
||||
@@ -27,10 +29,10 @@ func (s *Server) PasswordReset(ctx context.Context, req *user.PasswordResetReque
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &user.PasswordResetResponse{
|
||||
return connect.NewResponse(&user.PasswordResetResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
VerificationCode: code,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func notificationTypeToDomain(notificationType user.NotificationType) domain.NotificationType {
|
||||
@@ -46,16 +48,16 @@ func notificationTypeToDomain(notificationType user.NotificationType) domain.Not
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) SetPassword(ctx context.Context, req *user.SetPasswordRequest) (_ *user.SetPasswordResponse, err error) {
|
||||
func (s *Server) SetPassword(ctx context.Context, req *connect.Request[user.SetPasswordRequest]) (_ *connect.Response[user.SetPasswordResponse], err error) {
|
||||
var details *domain.ObjectDetails
|
||||
|
||||
switch v := req.GetVerification().(type) {
|
||||
switch v := req.Msg.GetVerification().(type) {
|
||||
case *user.SetPasswordRequest_CurrentPassword:
|
||||
details, err = s.command.ChangePassword(ctx, "", req.GetUserId(), v.CurrentPassword, req.GetNewPassword().GetPassword(), "", req.GetNewPassword().GetChangeRequired())
|
||||
details, err = s.command.ChangePassword(ctx, "", req.Msg.GetUserId(), v.CurrentPassword, req.Msg.GetNewPassword().GetPassword(), "", req.Msg.GetNewPassword().GetChangeRequired())
|
||||
case *user.SetPasswordRequest_VerificationCode:
|
||||
details, err = s.command.SetPasswordWithVerifyCode(ctx, "", req.GetUserId(), v.VerificationCode, req.GetNewPassword().GetPassword(), "", req.GetNewPassword().GetChangeRequired())
|
||||
details, err = s.command.SetPasswordWithVerifyCode(ctx, "", req.Msg.GetUserId(), v.VerificationCode, req.Msg.GetNewPassword().GetPassword(), "", req.Msg.GetNewPassword().GetChangeRequired())
|
||||
case nil:
|
||||
details, err = s.command.SetPassword(ctx, "", req.GetUserId(), req.GetNewPassword().GetPassword(), req.GetNewPassword().GetChangeRequired())
|
||||
details, err = s.command.SetPassword(ctx, "", req.Msg.GetUserId(), req.Msg.GetNewPassword().GetPassword(), req.Msg.GetNewPassword().GetChangeRequired())
|
||||
default:
|
||||
err = zerrors.ThrowUnimplementedf(nil, "USERv2-SFdf2", "verification oneOf %T in method SetPasswordRequest not implemented", v)
|
||||
}
|
||||
@@ -63,7 +65,7 @@ func (s *Server) SetPassword(ctx context.Context, req *user.SetPasswordRequest)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &user.SetPasswordResponse{
|
||||
return connect.NewResponse(&user.SetPasswordResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package user
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
@@ -11,18 +12,18 @@ import (
|
||||
user "github.com/zitadel/zitadel/pkg/grpc/user/v2beta"
|
||||
)
|
||||
|
||||
func (s *Server) SetPhone(ctx context.Context, req *user.SetPhoneRequest) (resp *user.SetPhoneResponse, err error) {
|
||||
func (s *Server) SetPhone(ctx context.Context, req *connect.Request[user.SetPhoneRequest]) (resp *connect.Response[user.SetPhoneResponse], err error) {
|
||||
var phone *domain.Phone
|
||||
|
||||
switch v := req.GetVerification().(type) {
|
||||
switch v := req.Msg.GetVerification().(type) {
|
||||
case *user.SetPhoneRequest_SendCode:
|
||||
phone, err = s.command.ChangeUserPhone(ctx, req.GetUserId(), req.GetPhone(), s.userCodeAlg)
|
||||
phone, err = s.command.ChangeUserPhone(ctx, req.Msg.GetUserId(), req.Msg.GetPhone(), s.userCodeAlg)
|
||||
case *user.SetPhoneRequest_ReturnCode:
|
||||
phone, err = s.command.ChangeUserPhoneReturnCode(ctx, req.GetUserId(), req.GetPhone(), s.userCodeAlg)
|
||||
phone, err = s.command.ChangeUserPhoneReturnCode(ctx, req.Msg.GetUserId(), req.Msg.GetPhone(), s.userCodeAlg)
|
||||
case *user.SetPhoneRequest_IsVerified:
|
||||
phone, err = s.command.ChangeUserPhoneVerified(ctx, req.GetUserId(), req.GetPhone())
|
||||
phone, err = s.command.ChangeUserPhoneVerified(ctx, req.Msg.GetUserId(), req.Msg.GetPhone())
|
||||
case nil:
|
||||
phone, err = s.command.ChangeUserPhone(ctx, req.GetUserId(), req.GetPhone(), s.userCodeAlg)
|
||||
phone, err = s.command.ChangeUserPhone(ctx, req.Msg.GetUserId(), req.Msg.GetPhone(), s.userCodeAlg)
|
||||
default:
|
||||
err = zerrors.ThrowUnimplementedf(nil, "USERv2-Ahng0", "verification oneOf %T in method SetPhone not implemented", v)
|
||||
}
|
||||
@@ -30,42 +31,42 @@ func (s *Server) SetPhone(ctx context.Context, req *user.SetPhoneRequest) (resp
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &user.SetPhoneResponse{
|
||||
return connect.NewResponse(&user.SetPhoneResponse{
|
||||
Details: &object.Details{
|
||||
Sequence: phone.Sequence,
|
||||
ChangeDate: timestamppb.New(phone.ChangeDate),
|
||||
ResourceOwner: phone.ResourceOwner,
|
||||
},
|
||||
VerificationCode: phone.PlainCode,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) RemovePhone(ctx context.Context, req *user.RemovePhoneRequest) (resp *user.RemovePhoneResponse, err error) {
|
||||
func (s *Server) RemovePhone(ctx context.Context, req *connect.Request[user.RemovePhoneRequest]) (resp *connect.Response[user.RemovePhoneResponse], err error) {
|
||||
details, err := s.command.RemoveUserPhone(ctx,
|
||||
req.GetUserId(),
|
||||
req.Msg.GetUserId(),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &user.RemovePhoneResponse{
|
||||
return connect.NewResponse(&user.RemovePhoneResponse{
|
||||
Details: &object.Details{
|
||||
Sequence: details.Sequence,
|
||||
ChangeDate: timestamppb.New(details.EventDate),
|
||||
ResourceOwner: details.ResourceOwner,
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) ResendPhoneCode(ctx context.Context, req *user.ResendPhoneCodeRequest) (resp *user.ResendPhoneCodeResponse, err error) {
|
||||
func (s *Server) ResendPhoneCode(ctx context.Context, req *connect.Request[user.ResendPhoneCodeRequest]) (resp *connect.Response[user.ResendPhoneCodeResponse], err error) {
|
||||
var phone *domain.Phone
|
||||
switch v := req.GetVerification().(type) {
|
||||
switch v := req.Msg.GetVerification().(type) {
|
||||
case *user.ResendPhoneCodeRequest_SendCode:
|
||||
phone, err = s.command.ResendUserPhoneCode(ctx, req.GetUserId(), s.userCodeAlg)
|
||||
phone, err = s.command.ResendUserPhoneCode(ctx, req.Msg.GetUserId(), s.userCodeAlg)
|
||||
case *user.ResendPhoneCodeRequest_ReturnCode:
|
||||
phone, err = s.command.ResendUserPhoneCodeReturnCode(ctx, req.GetUserId(), s.userCodeAlg)
|
||||
phone, err = s.command.ResendUserPhoneCodeReturnCode(ctx, req.Msg.GetUserId(), s.userCodeAlg)
|
||||
case nil:
|
||||
phone, err = s.command.ResendUserPhoneCode(ctx, req.GetUserId(), s.userCodeAlg)
|
||||
phone, err = s.command.ResendUserPhoneCode(ctx, req.Msg.GetUserId(), s.userCodeAlg)
|
||||
default:
|
||||
err = zerrors.ThrowUnimplementedf(nil, "USERv2-ResendUserPhoneCode", "verification oneOf %T in method SetPhone not implemented", v)
|
||||
}
|
||||
@@ -73,30 +74,30 @@ func (s *Server) ResendPhoneCode(ctx context.Context, req *user.ResendPhoneCodeR
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &user.ResendPhoneCodeResponse{
|
||||
return connect.NewResponse(&user.ResendPhoneCodeResponse{
|
||||
Details: &object.Details{
|
||||
Sequence: phone.Sequence,
|
||||
ChangeDate: timestamppb.New(phone.ChangeDate),
|
||||
ResourceOwner: phone.ResourceOwner,
|
||||
},
|
||||
VerificationCode: phone.PlainCode,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) VerifyPhone(ctx context.Context, req *user.VerifyPhoneRequest) (*user.VerifyPhoneResponse, error) {
|
||||
func (s *Server) VerifyPhone(ctx context.Context, req *connect.Request[user.VerifyPhoneRequest]) (*connect.Response[user.VerifyPhoneResponse], error) {
|
||||
details, err := s.command.VerifyUserPhone(ctx,
|
||||
req.GetUserId(),
|
||||
req.GetVerificationCode(),
|
||||
req.Msg.GetUserId(),
|
||||
req.Msg.GetVerificationCode(),
|
||||
s.userCodeAlg,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.VerifyPhoneResponse{
|
||||
return connect.NewResponse(&user.VerifyPhoneResponse{
|
||||
Details: &object.Details{
|
||||
Sequence: details.Sequence,
|
||||
ChangeDate: timestamppb.New(details.EventDate),
|
||||
ResourceOwner: details.ResourceOwner,
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package user
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"github.com/muhlemmer/gu"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
@@ -13,23 +14,23 @@ import (
|
||||
user "github.com/zitadel/zitadel/pkg/grpc/user/v2beta"
|
||||
)
|
||||
|
||||
func (s *Server) GetUserByID(ctx context.Context, req *user.GetUserByIDRequest) (_ *user.GetUserByIDResponse, err error) {
|
||||
resp, err := s.query.GetUserByIDWithPermission(ctx, true, req.GetUserId(), s.checkPermission)
|
||||
func (s *Server) GetUserByID(ctx context.Context, req *connect.Request[user.GetUserByIDRequest]) (_ *connect.Response[user.GetUserByIDResponse], err error) {
|
||||
resp, err := s.query.GetUserByIDWithPermission(ctx, true, req.Msg.GetUserId(), s.checkPermission)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.GetUserByIDResponse{
|
||||
return connect.NewResponse(&user.GetUserByIDResponse{
|
||||
Details: object.DomainToDetailsPb(&domain.ObjectDetails{
|
||||
Sequence: resp.Sequence,
|
||||
EventDate: resp.ChangeDate,
|
||||
ResourceOwner: resp.ResourceOwner,
|
||||
}),
|
||||
User: userToPb(resp, s.assetAPIPrefix(ctx)),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) ListUsers(ctx context.Context, req *user.ListUsersRequest) (*user.ListUsersResponse, error) {
|
||||
queries, err := listUsersRequestToModel(req)
|
||||
func (s *Server) ListUsers(ctx context.Context, req *connect.Request[user.ListUsersRequest]) (*connect.Response[user.ListUsersResponse], error) {
|
||||
queries, err := listUsersRequestToModel(req.Msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -37,10 +38,10 @@ func (s *Server) ListUsers(ctx context.Context, req *user.ListUsersRequest) (*us
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.ListUsersResponse{
|
||||
return connect.NewResponse(&user.ListUsersResponse{
|
||||
Result: UsersToPb(res.Users, s.assetAPIPrefix(ctx)),
|
||||
Details: object.ToListDetails(res.SearchResponse),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func UsersToPb(users []*query.User, assetPrefix string) []*user.User {
|
||||
|
@@ -2,8 +2,10 @@ package user
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"connectrpc.com/connect"
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/server"
|
||||
@@ -12,12 +14,12 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
user "github.com/zitadel/zitadel/pkg/grpc/user/v2beta"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/user/v2beta/userconnect"
|
||||
)
|
||||
|
||||
var _ user.UserServiceServer = (*Server)(nil)
|
||||
var _ userconnect.UserServiceHandler = (*Server)(nil)
|
||||
|
||||
type Server struct {
|
||||
user.UnimplementedUserServiceServer
|
||||
command *command.Commands
|
||||
query *query.Queries
|
||||
userCodeAlg crypto.EncryptionAlgorithm
|
||||
@@ -54,8 +56,12 @@ func CreateServer(
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) RegisterServer(grpcServer *grpc.Server) {
|
||||
user.RegisterUserServiceServer(grpcServer, s)
|
||||
func (s *Server) RegisterConnectServer(interceptors ...connect.Interceptor) (string, http.Handler) {
|
||||
return userconnect.NewUserServiceHandler(s, connect.WithInterceptors(interceptors...))
|
||||
}
|
||||
|
||||
func (s *Server) FileDescriptor() protoreflect.FileDescriptor {
|
||||
return user.File_zitadel_user_v2beta_user_service_proto
|
||||
}
|
||||
|
||||
func (s *Server) AppName() string {
|
||||
|
@@ -3,42 +3,44 @@ package user
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
|
||||
object "github.com/zitadel/zitadel/internal/api/grpc/object/v2beta"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
user "github.com/zitadel/zitadel/pkg/grpc/user/v2beta"
|
||||
)
|
||||
|
||||
func (s *Server) RegisterTOTP(ctx context.Context, req *user.RegisterTOTPRequest) (*user.RegisterTOTPResponse, error) {
|
||||
func (s *Server) RegisterTOTP(ctx context.Context, req *connect.Request[user.RegisterTOTPRequest]) (*connect.Response[user.RegisterTOTPResponse], error) {
|
||||
return totpDetailsToPb(
|
||||
s.command.AddUserTOTP(ctx, req.GetUserId(), ""),
|
||||
s.command.AddUserTOTP(ctx, req.Msg.GetUserId(), ""),
|
||||
)
|
||||
}
|
||||
|
||||
func totpDetailsToPb(totp *domain.TOTP, err error) (*user.RegisterTOTPResponse, error) {
|
||||
func totpDetailsToPb(totp *domain.TOTP, err error) (*connect.Response[user.RegisterTOTPResponse], error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.RegisterTOTPResponse{
|
||||
return connect.NewResponse(&user.RegisterTOTPResponse{
|
||||
Details: object.DomainToDetailsPb(totp.ObjectDetails),
|
||||
Uri: totp.URI,
|
||||
Secret: totp.Secret,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) VerifyTOTPRegistration(ctx context.Context, req *user.VerifyTOTPRegistrationRequest) (*user.VerifyTOTPRegistrationResponse, error) {
|
||||
objectDetails, err := s.command.CheckUserTOTP(ctx, req.GetUserId(), req.GetCode(), "")
|
||||
func (s *Server) VerifyTOTPRegistration(ctx context.Context, req *connect.Request[user.VerifyTOTPRegistrationRequest]) (*connect.Response[user.VerifyTOTPRegistrationResponse], error) {
|
||||
objectDetails, err := s.command.CheckUserTOTP(ctx, req.Msg.GetUserId(), req.Msg.GetCode(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.VerifyTOTPRegistrationResponse{
|
||||
return connect.NewResponse(&user.VerifyTOTPRegistrationResponse{
|
||||
Details: object.DomainToDetailsPb(objectDetails),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) RemoveTOTP(ctx context.Context, req *user.RemoveTOTPRequest) (*user.RemoveTOTPResponse, error) {
|
||||
objectDetails, err := s.command.HumanRemoveTOTP(ctx, req.GetUserId(), "")
|
||||
func (s *Server) RemoveTOTP(ctx context.Context, req *connect.Request[user.RemoveTOTPRequest]) (*connect.Response[user.RemoveTOTPResponse], error) {
|
||||
objectDetails, err := s.command.HumanRemoveTOTP(ctx, req.Msg.GetUserId(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.RemoveTOTPResponse{Details: object.DomainToDetailsPb(objectDetails)}, nil
|
||||
return connect.NewResponse(&user.RemoveTOTPResponse{Details: object.DomainToDetailsPb(objectDetails)}), nil
|
||||
}
|
||||
|
@@ -63,7 +63,7 @@ func Test_totpDetailsToPb(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := totpDetailsToPb(tt.args.otp, tt.args.err)
|
||||
require.ErrorIs(t, err, tt.wantErr)
|
||||
if !proto.Equal(tt.want, got) {
|
||||
if tt.want != nil && !proto.Equal(tt.want, got.Msg) {
|
||||
t.Errorf("RegisterTOTPResponse =\n%v\nwant\n%v", got, tt.want)
|
||||
}
|
||||
})
|
||||
|
@@ -3,40 +3,42 @@ package user
|
||||
import (
|
||||
"context"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
|
||||
object "github.com/zitadel/zitadel/internal/api/grpc/object/v2beta"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
user "github.com/zitadel/zitadel/pkg/grpc/user/v2beta"
|
||||
)
|
||||
|
||||
func (s *Server) RegisterU2F(ctx context.Context, req *user.RegisterU2FRequest) (*user.RegisterU2FResponse, error) {
|
||||
func (s *Server) RegisterU2F(ctx context.Context, req *connect.Request[user.RegisterU2FRequest]) (*connect.Response[user.RegisterU2FResponse], error) {
|
||||
return u2fRegistrationDetailsToPb(
|
||||
s.command.RegisterUserU2F(ctx, req.GetUserId(), "", req.GetDomain()),
|
||||
s.command.RegisterUserU2F(ctx, req.Msg.GetUserId(), "", req.Msg.GetDomain()),
|
||||
)
|
||||
}
|
||||
|
||||
func u2fRegistrationDetailsToPb(details *domain.WebAuthNRegistrationDetails, err error) (*user.RegisterU2FResponse, error) {
|
||||
func u2fRegistrationDetailsToPb(details *domain.WebAuthNRegistrationDetails, err error) (*connect.Response[user.RegisterU2FResponse], error) {
|
||||
objectDetails, options, err := webAuthNRegistrationDetailsToPb(details, err)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.RegisterU2FResponse{
|
||||
return connect.NewResponse(&user.RegisterU2FResponse{
|
||||
Details: objectDetails,
|
||||
U2FId: details.ID,
|
||||
PublicKeyCredentialCreationOptions: options,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) VerifyU2FRegistration(ctx context.Context, req *user.VerifyU2FRegistrationRequest) (*user.VerifyU2FRegistrationResponse, error) {
|
||||
pkc, err := req.GetPublicKeyCredential().MarshalJSON()
|
||||
func (s *Server) VerifyU2FRegistration(ctx context.Context, req *connect.Request[user.VerifyU2FRegistrationRequest]) (*connect.Response[user.VerifyU2FRegistrationResponse], error) {
|
||||
pkc, err := req.Msg.GetPublicKeyCredential().MarshalJSON()
|
||||
if err != nil {
|
||||
return nil, zerrors.ThrowInternal(err, "USERv2-IeTh4", "Errors.Internal")
|
||||
}
|
||||
objectDetails, err := s.command.HumanVerifyU2FSetup(ctx, req.GetUserId(), "", req.GetTokenName(), "", pkc)
|
||||
objectDetails, err := s.command.HumanVerifyU2FSetup(ctx, req.Msg.GetUserId(), "", req.Msg.GetTokenName(), "", pkc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.VerifyU2FRegistrationResponse{
|
||||
return connect.NewResponse(&user.VerifyU2FRegistrationResponse{
|
||||
Details: object.DomainToDetailsPb(objectDetails),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
@@ -92,11 +92,11 @@ func Test_u2fRegistrationDetailsToPb(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := u2fRegistrationDetailsToPb(tt.args.details, tt.args.err)
|
||||
require.ErrorIs(t, err, tt.wantErr)
|
||||
if !proto.Equal(tt.want, got) {
|
||||
if tt.want != nil && !proto.Equal(tt.want, got.Msg) {
|
||||
t.Errorf("Not equal:\nExpected\n%s\nActual:%s", tt.want, got)
|
||||
}
|
||||
if tt.want != nil {
|
||||
grpc.AllFieldsSet(t, got.ProtoReflect())
|
||||
grpc.AllFieldsSet(t, got.Msg.ProtoReflect())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@@ -6,6 +6,7 @@ import (
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"golang.org/x/text/language"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
@@ -23,8 +24,8 @@ import (
|
||||
user "github.com/zitadel/zitadel/pkg/grpc/user/v2beta"
|
||||
)
|
||||
|
||||
func (s *Server) AddHumanUser(ctx context.Context, req *user.AddHumanUserRequest) (_ *user.AddHumanUserResponse, err error) {
|
||||
human, err := AddUserRequestToAddHuman(req)
|
||||
func (s *Server) AddHumanUser(ctx context.Context, req *connect.Request[user.AddHumanUserRequest]) (_ *connect.Response[user.AddHumanUserResponse], err error) {
|
||||
human, err := AddUserRequestToAddHuman(req.Msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -32,12 +33,12 @@ func (s *Server) AddHumanUser(ctx context.Context, req *user.AddHumanUserRequest
|
||||
if err = s.command.AddUserHuman(ctx, orgID, human, false, s.userCodeAlg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.AddHumanUserResponse{
|
||||
return connect.NewResponse(&user.AddHumanUserResponse{
|
||||
UserId: human.ID,
|
||||
Details: object.DomainToDetailsPb(human.Details),
|
||||
EmailCode: human.EmailCode,
|
||||
PhoneCode: human.PhoneCode,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func AddUserRequestToAddHuman(req *user.AddHumanUserRequest) (*command.AddHuman, error) {
|
||||
@@ -115,8 +116,8 @@ func genderToDomain(gender user.Gender) domain.Gender {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) UpdateHumanUser(ctx context.Context, req *user.UpdateHumanUserRequest) (_ *user.UpdateHumanUserResponse, err error) {
|
||||
human, err := UpdateUserRequestToChangeHuman(req)
|
||||
func (s *Server) UpdateHumanUser(ctx context.Context, req *connect.Request[user.UpdateHumanUserRequest]) (_ *connect.Response[user.UpdateHumanUserResponse], err error) {
|
||||
human, err := UpdateUserRequestToChangeHuman(req.Msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -124,51 +125,51 @@ func (s *Server) UpdateHumanUser(ctx context.Context, req *user.UpdateHumanUserR
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.UpdateHumanUserResponse{
|
||||
return connect.NewResponse(&user.UpdateHumanUserResponse{
|
||||
Details: object.DomainToDetailsPb(human.Details),
|
||||
EmailCode: human.EmailCode,
|
||||
PhoneCode: human.PhoneCode,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) LockUser(ctx context.Context, req *user.LockUserRequest) (_ *user.LockUserResponse, err error) {
|
||||
details, err := s.command.LockUserV2(ctx, req.UserId)
|
||||
func (s *Server) LockUser(ctx context.Context, req *connect.Request[user.LockUserRequest]) (_ *connect.Response[user.LockUserResponse], err error) {
|
||||
details, err := s.command.LockUserV2(ctx, req.Msg.GetUserId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.LockUserResponse{
|
||||
return connect.NewResponse(&user.LockUserResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) UnlockUser(ctx context.Context, req *user.UnlockUserRequest) (_ *user.UnlockUserResponse, err error) {
|
||||
details, err := s.command.UnlockUserV2(ctx, req.UserId)
|
||||
func (s *Server) UnlockUser(ctx context.Context, req *connect.Request[user.UnlockUserRequest]) (_ *connect.Response[user.UnlockUserResponse], err error) {
|
||||
details, err := s.command.UnlockUserV2(ctx, req.Msg.GetUserId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.UnlockUserResponse{
|
||||
return connect.NewResponse(&user.UnlockUserResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) DeactivateUser(ctx context.Context, req *user.DeactivateUserRequest) (_ *user.DeactivateUserResponse, err error) {
|
||||
details, err := s.command.DeactivateUserV2(ctx, req.UserId)
|
||||
func (s *Server) DeactivateUser(ctx context.Context, req *connect.Request[user.DeactivateUserRequest]) (_ *connect.Response[user.DeactivateUserResponse], err error) {
|
||||
details, err := s.command.DeactivateUserV2(ctx, req.Msg.GetUserId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.DeactivateUserResponse{
|
||||
return connect.NewResponse(&user.DeactivateUserResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) ReactivateUser(ctx context.Context, req *user.ReactivateUserRequest) (_ *user.ReactivateUserResponse, err error) {
|
||||
details, err := s.command.ReactivateUserV2(ctx, req.UserId)
|
||||
func (s *Server) ReactivateUser(ctx context.Context, req *connect.Request[user.ReactivateUserRequest]) (_ *connect.Response[user.ReactivateUserResponse], err error) {
|
||||
details, err := s.command.ReactivateUserV2(ctx, req.Msg.GetUserId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.ReactivateUserResponse{
|
||||
return connect.NewResponse(&user.ReactivateUserResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func ifNotNilPtr[v, p any](value *v, conv func(v) p) *p {
|
||||
@@ -260,32 +261,32 @@ func SetHumanPasswordToPassword(password *user.SetPassword) *command.Password {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) AddIDPLink(ctx context.Context, req *user.AddIDPLinkRequest) (_ *user.AddIDPLinkResponse, err error) {
|
||||
details, err := s.command.AddUserIDPLink(ctx, req.UserId, "", &command.AddLink{
|
||||
IDPID: req.GetIdpLink().GetIdpId(),
|
||||
DisplayName: req.GetIdpLink().GetUserName(),
|
||||
IDPExternalID: req.GetIdpLink().GetUserId(),
|
||||
func (s *Server) AddIDPLink(ctx context.Context, req *connect.Request[user.AddIDPLinkRequest]) (_ *connect.Response[user.AddIDPLinkResponse], err error) {
|
||||
details, err := s.command.AddUserIDPLink(ctx, req.Msg.GetUserId(), "", &command.AddLink{
|
||||
IDPID: req.Msg.GetIdpLink().GetIdpId(),
|
||||
DisplayName: req.Msg.GetIdpLink().GetUserName(),
|
||||
IDPExternalID: req.Msg.GetIdpLink().GetUserId(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.AddIDPLinkResponse{
|
||||
return connect.NewResponse(&user.AddIDPLinkResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) DeleteUser(ctx context.Context, req *user.DeleteUserRequest) (_ *user.DeleteUserResponse, err error) {
|
||||
memberships, grants, err := s.removeUserDependencies(ctx, req.GetUserId())
|
||||
func (s *Server) DeleteUser(ctx context.Context, req *connect.Request[user.DeleteUserRequest]) (_ *connect.Response[user.DeleteUserResponse], err error) {
|
||||
memberships, grants, err := s.removeUserDependencies(ctx, req.Msg.GetUserId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
details, err := s.command.RemoveUserV2(ctx, req.UserId, "", memberships, grants...)
|
||||
details, err := s.command.RemoveUserV2(ctx, req.Msg.GetUserId(), "", memberships, grants...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.DeleteUserResponse{
|
||||
return connect.NewResponse(&user.DeleteUserResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) removeUserDependencies(ctx context.Context, userID string) ([]*command.CascadingMembership, []string, error) {
|
||||
@@ -360,18 +361,18 @@ func userGrantsToIDs(userGrants []*query.UserGrant) []string {
|
||||
return converted
|
||||
}
|
||||
|
||||
func (s *Server) StartIdentityProviderIntent(ctx context.Context, req *user.StartIdentityProviderIntentRequest) (_ *user.StartIdentityProviderIntentResponse, err error) {
|
||||
switch t := req.GetContent().(type) {
|
||||
func (s *Server) StartIdentityProviderIntent(ctx context.Context, req *connect.Request[user.StartIdentityProviderIntentRequest]) (_ *connect.Response[user.StartIdentityProviderIntentResponse], err error) {
|
||||
switch t := req.Msg.GetContent().(type) {
|
||||
case *user.StartIdentityProviderIntentRequest_Urls:
|
||||
return s.startIDPIntent(ctx, req.GetIdpId(), t.Urls)
|
||||
return s.startIDPIntent(ctx, req.Msg.GetIdpId(), t.Urls)
|
||||
case *user.StartIdentityProviderIntentRequest_Ldap:
|
||||
return s.startLDAPIntent(ctx, req.GetIdpId(), t.Ldap)
|
||||
return s.startLDAPIntent(ctx, req.Msg.GetIdpId(), t.Ldap)
|
||||
default:
|
||||
return nil, zerrors.ThrowUnimplementedf(nil, "USERv2-S2g21", "type oneOf %T in method StartIdentityProviderIntent not implemented", t)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) startIDPIntent(ctx context.Context, idpID string, urls *user.RedirectURLs) (*user.StartIdentityProviderIntentResponse, error) {
|
||||
func (s *Server) startIDPIntent(ctx context.Context, idpID string, urls *user.RedirectURLs) (*connect.Response[user.StartIdentityProviderIntentResponse], error) {
|
||||
state, session, err := s.command.AuthFromProvider(ctx, idpID, s.idpCallback(ctx), s.samlRootURL(ctx, idpID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -386,12 +387,12 @@ func (s *Server) startIDPIntent(ctx context.Context, idpID string, urls *user.Re
|
||||
}
|
||||
switch a := auth.(type) {
|
||||
case *idp.RedirectAuth:
|
||||
return &user.StartIdentityProviderIntentResponse{
|
||||
return connect.NewResponse(&user.StartIdentityProviderIntentResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
NextStep: &user.StartIdentityProviderIntentResponse_AuthUrl{AuthUrl: a.RedirectURL},
|
||||
}, nil
|
||||
}), nil
|
||||
case *idp.FormAuth:
|
||||
return &user.StartIdentityProviderIntentResponse{
|
||||
return connect.NewResponse(&user.StartIdentityProviderIntentResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
NextStep: &user.StartIdentityProviderIntentResponse_FormData{
|
||||
FormData: &user.FormData{
|
||||
@@ -399,12 +400,12 @@ func (s *Server) startIDPIntent(ctx context.Context, idpID string, urls *user.Re
|
||||
Fields: a.Fields,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
return nil, zerrors.ThrowInvalidArgumentf(nil, "USERv2-3g2j3", "type oneOf %T in method StartIdentityProviderIntent not implemented", auth)
|
||||
}
|
||||
|
||||
func (s *Server) startLDAPIntent(ctx context.Context, idpID string, ldapCredentials *user.LDAPCredentials) (*user.StartIdentityProviderIntentResponse, error) {
|
||||
func (s *Server) startLDAPIntent(ctx context.Context, idpID string, ldapCredentials *user.LDAPCredentials) (*connect.Response[user.StartIdentityProviderIntentResponse], error) {
|
||||
intentWriteModel, details, err := s.command.CreateIntent(ctx, "", idpID, "", "", authz.GetInstance(ctx).InstanceID(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -420,7 +421,7 @@ func (s *Server) startLDAPIntent(ctx context.Context, idpID string, ldapCredenti
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.StartIdentityProviderIntentResponse{
|
||||
return connect.NewResponse(&user.StartIdentityProviderIntentResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
NextStep: &user.StartIdentityProviderIntentResponse_IdpIntent{
|
||||
IdpIntent: &user.IDPIntent{
|
||||
@@ -429,7 +430,7 @@ func (s *Server) startLDAPIntent(ctx context.Context, idpID string, ldapCredenti
|
||||
UserId: userID,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Server) checkLinkedExternalUser(ctx context.Context, idpID, externalUserID string) (string, error) {
|
||||
@@ -483,12 +484,12 @@ func (s *Server) ldapLogin(ctx context.Context, idpID, username, password string
|
||||
return externalUser, userID, session, nil
|
||||
}
|
||||
|
||||
func (s *Server) RetrieveIdentityProviderIntent(ctx context.Context, req *user.RetrieveIdentityProviderIntentRequest) (_ *user.RetrieveIdentityProviderIntentResponse, err error) {
|
||||
intent, err := s.command.GetIntentWriteModel(ctx, req.GetIdpIntentId(), "")
|
||||
func (s *Server) RetrieveIdentityProviderIntent(ctx context.Context, req *connect.Request[user.RetrieveIdentityProviderIntentRequest]) (_ *connect.Response[user.RetrieveIdentityProviderIntentResponse], err error) {
|
||||
intent, err := s.command.GetIntentWriteModel(ctx, req.Msg.GetIdpIntentId(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := s.checkIntentToken(req.GetIdpIntentToken(), intent.AggregateID); err != nil {
|
||||
if err := s.checkIntentToken(req.Msg.GetIdpIntentToken(), intent.AggregateID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if intent.State != domain.IDPIntentStateSucceeded {
|
||||
@@ -500,7 +501,7 @@ func (s *Server) RetrieveIdentityProviderIntent(ctx context.Context, req *user.R
|
||||
return idpIntentToIDPIntentPb(intent, s.idpAlg)
|
||||
}
|
||||
|
||||
func idpIntentToIDPIntentPb(intent *command.IDPIntentWriteModel, alg crypto.EncryptionAlgorithm) (_ *user.RetrieveIdentityProviderIntentResponse, err error) {
|
||||
func idpIntentToIDPIntentPb(intent *command.IDPIntentWriteModel, alg crypto.EncryptionAlgorithm) (_ *connect.Response[user.RetrieveIdentityProviderIntentResponse], err error) {
|
||||
rawInformation := new(structpb.Struct)
|
||||
err = rawInformation.UnmarshalJSON(intent.IDPUser)
|
||||
if err != nil {
|
||||
@@ -539,7 +540,7 @@ func idpIntentToIDPIntentPb(intent *command.IDPIntentWriteModel, alg crypto.Encr
|
||||
information.IdpInformation.Access = IDPSAMLResponseToPb(assertion)
|
||||
}
|
||||
|
||||
return information, nil
|
||||
return connect.NewResponse(information), nil
|
||||
}
|
||||
|
||||
func idpOAuthTokensToPb(idpIDToken string, idpAccessToken *crypto.CryptoValue, alg crypto.EncryptionAlgorithm) (_ *user.IDPInformation_Oauth, err error) {
|
||||
@@ -602,15 +603,15 @@ func (s *Server) checkIntentToken(token string, intentID string) error {
|
||||
return crypto.CheckToken(s.idpAlg, token, intentID)
|
||||
}
|
||||
|
||||
func (s *Server) ListAuthenticationMethodTypes(ctx context.Context, req *user.ListAuthenticationMethodTypesRequest) (*user.ListAuthenticationMethodTypesResponse, error) {
|
||||
authMethods, err := s.query.ListUserAuthMethodTypes(ctx, req.GetUserId(), true, false, "")
|
||||
func (s *Server) ListAuthenticationMethodTypes(ctx context.Context, req *connect.Request[user.ListAuthenticationMethodTypesRequest]) (*connect.Response[user.ListAuthenticationMethodTypesResponse], error) {
|
||||
authMethods, err := s.query.ListUserAuthMethodTypes(ctx, req.Msg.GetUserId(), true, false, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.ListAuthenticationMethodTypesResponse{
|
||||
return connect.NewResponse(&user.ListAuthenticationMethodTypesResponse{
|
||||
Details: object.ToListDetails(authMethods.SearchResponse),
|
||||
AuthMethodTypes: authMethodTypesToPb(authMethods.AuthMethodTypes),
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
func authMethodTypesToPb(methodTypes []domain.UserAuthMethodType) []user.AuthenticationMethodType {
|
||||
|
@@ -322,7 +322,9 @@ func Test_idpIntentToIDPIntentPb(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := idpIntentToIDPIntentPb(tt.args.intent, tt.args.alg)
|
||||
require.ErrorIs(t, err, tt.res.err)
|
||||
grpc.AllFieldsEqual(t, tt.res.resp.ProtoReflect(), got.ProtoReflect(), grpc.CustomMappers)
|
||||
if tt.res.resp != nil {
|
||||
grpc.AllFieldsEqual(t, tt.res.resp.ProtoReflect(), got.Msg.ProtoReflect(), grpc.CustomMappers)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user