mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 00:27:31 +00:00
feat: user v2alpha email API (#5708)
* chore(proto): update versions
* change protoc plugin
* some cleanups
* define api for setting emails in new api
* implement user.SetEmail
* move SetEmail buisiness logic into command
* resuse newCryptoCode
* command: add ChangeEmail unit tests
Not complete, was not able to mock the generator.
* Revert "resuse newCryptoCode"
This reverts commit c89e90ae35
.
* undo change to crypto code generators
* command: use a generator so we can test properly
* command: reorganise ChangeEmail
improve test coverage
* implement VerifyEmail
including unit tests
* add URL template tests
* proto: change context to object
* remove old auth option
* remove old auth option
* fix linting errors
run gci on modified files
* add permission checks and fix some errors
* comments
* comments
---------
Co-authored-by: Livio Spring <livio.a@gmail.com>
Co-authored-by: Tim Möhlmann <tim+github@zitadel.com>
This commit is contained in:
65
internal/api/grpc/user/v2/email.go
Normal file
65
internal/api/grpc/user/v2/email.go
Normal file
@@ -0,0 +1,65 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
caos_errs "github.com/zitadel/zitadel/internal/errors"
|
||||
object "github.com/zitadel/zitadel/pkg/grpc/object/v2alpha"
|
||||
user "github.com/zitadel/zitadel/pkg/grpc/user/v2alpha"
|
||||
)
|
||||
|
||||
func (s *Server) SetEmail(ctx context.Context, req *user.SetEmailRequest) (resp *user.SetEmailResponse, err error) {
|
||||
resourceOwner := "" // TODO: check if still needed
|
||||
var email *domain.Email
|
||||
|
||||
switch v := req.GetVerification().(type) {
|
||||
case *user.SetEmailRequest_SendCode:
|
||||
email, err = s.command.ChangeUserEmailURLTemplate(ctx, req.GetUserId(), resourceOwner, req.GetEmail(), s.userCodeAlg, v.SendCode.GetUrlTemplate())
|
||||
case *user.SetEmailRequest_ReturnCode:
|
||||
email, err = s.command.ChangeUserEmailReturnCode(ctx, req.GetUserId(), resourceOwner, req.GetEmail(), s.userCodeAlg)
|
||||
case *user.SetEmailRequest_IsVerified:
|
||||
if v.IsVerified {
|
||||
email, err = s.command.ChangeUserEmailVerified(ctx, req.GetUserId(), resourceOwner, req.GetEmail())
|
||||
} else {
|
||||
email, err = s.command.ChangeUserEmail(ctx, req.GetUserId(), resourceOwner, req.GetEmail(), s.userCodeAlg)
|
||||
}
|
||||
case nil:
|
||||
email, err = s.command.ChangeUserEmail(ctx, req.GetUserId(), resourceOwner, req.GetEmail(), s.userCodeAlg)
|
||||
default:
|
||||
err = caos_errs.ThrowUnimplementedf(nil, "USERv2-Ahng0", "verification oneOf %T in method SetEmail not implemented", v)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &user.SetEmailResponse{
|
||||
Details: &object.Details{
|
||||
Sequence: email.Sequence,
|
||||
ChangeDate: timestamppb.New(email.ChangeDate),
|
||||
ResourceOwner: email.ResourceOwner,
|
||||
},
|
||||
VerificationCode: email.PlainCode,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) VerifyEmail(ctx context.Context, req *user.VerifyEmailRequest) (*user.VerifyEmailResponse, error) {
|
||||
details, err := s.command.VerifyUserEmail(ctx,
|
||||
req.GetUserId(),
|
||||
"", // TODO: check if still needed
|
||||
req.GetVerificationCode(),
|
||||
s.userCodeAlg,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.VerifyEmailResponse{
|
||||
Details: &object.Details{
|
||||
Sequence: details.Sequence,
|
||||
ChangeDate: timestamppb.New(details.EventDate),
|
||||
ResourceOwner: details.ResourceOwner,
|
||||
},
|
||||
}, nil
|
||||
}
|
@@ -6,27 +6,27 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/server"
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/user/v2alpha"
|
||||
user "github.com/zitadel/zitadel/pkg/grpc/user/v2alpha"
|
||||
)
|
||||
|
||||
var _ user.UserServiceServer = (*Server)(nil)
|
||||
|
||||
type Server struct {
|
||||
user.UnimplementedUserServiceServer
|
||||
command *command.Commands
|
||||
query *query.Queries
|
||||
command *command.Commands
|
||||
query *query.Queries
|
||||
userCodeAlg crypto.EncryptionAlgorithm
|
||||
}
|
||||
|
||||
type Config struct{}
|
||||
|
||||
func CreateServer(
|
||||
command *command.Commands,
|
||||
query *query.Queries,
|
||||
) *Server {
|
||||
func CreateServer(command *command.Commands, query *query.Queries, userCodeAlg crypto.EncryptionAlgorithm) *Server {
|
||||
return &Server{
|
||||
command: command,
|
||||
query: query,
|
||||
command: command,
|
||||
query: query,
|
||||
userCodeAlg: userCodeAlg,
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,55 +0,0 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/user/v2alpha"
|
||||
)
|
||||
|
||||
func (s *Server) TestGet(ctx context.Context, req *user.TestGetRequest) (*user.TestGetResponse, error) {
|
||||
return &user.TestGetResponse{
|
||||
Ctx: req.Ctx.String(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) TestPost(ctx context.Context, req *user.TestPostRequest) (*user.TestPostResponse, error) {
|
||||
return &user.TestPostResponse{
|
||||
Ctx: req.Ctx.String(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) TestAuth(ctx context.Context, req *user.TestAuthRequest) (*user.TestAuthResponse, error) {
|
||||
reqCtx, err := authDemo(ctx, req.Ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.TestAuthResponse{
|
||||
User: &user.User{Id: authz.GetCtxData(ctx).UserID},
|
||||
Ctx: reqCtx,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func authDemo(ctx context.Context, reqCtx *user.Context) (*user.Context, error) {
|
||||
ro := authz.GetCtxData(ctx).ResourceOwner
|
||||
if reqCtx == nil {
|
||||
return &user.Context{Ctx: &user.Context_OrgId{OrgId: ro}}, nil
|
||||
}
|
||||
switch c := reqCtx.Ctx.(type) {
|
||||
case *user.Context_OrgId:
|
||||
if c.OrgId == ro {
|
||||
return reqCtx, nil
|
||||
}
|
||||
return nil, errors.ThrowPermissionDenied(nil, "USER-dg4g", "Errors.User.NotAllowedOrg")
|
||||
case *user.Context_OrgDomain:
|
||||
if c.OrgDomain == "forbidden.com" {
|
||||
return nil, errors.ThrowPermissionDenied(nil, "USER-SDg4g", "Errors.User.NotAllowedOrg")
|
||||
}
|
||||
return reqCtx, nil
|
||||
case *user.Context_Instance:
|
||||
return reqCtx, nil
|
||||
default:
|
||||
return reqCtx, nil
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user