package command import ( "context" "encoding/json" "github.com/zitadel/zitadel/internal/domain" caos_errs "github.com/zitadel/zitadel/internal/errors" ) type humanPasskeys struct { human *domain.Human tokens []*domain.WebAuthNToken } func (s *SessionCommands) getHumanPasskeys(ctx context.Context) (*humanPasskeys, error) { humanWritemodel, err := s.gethumanWriteModel(ctx) if err != nil { return nil, err } tokenReadModel, err := s.getHumanPasswordlessTokenReadModel(ctx) if err != nil { return nil, err } return &humanPasskeys{ human: writeModelToHuman(humanWritemodel), tokens: readModelToPasswordlessTokens(tokenReadModel), }, nil } func (s *SessionCommands) getHumanPasswordlessTokenReadModel(ctx context.Context) (*HumanPasswordlessTokensReadModel, error) { tokenReadModel := NewHumanPasswordlessTokensReadModel(s.sessionWriteModel.UserID, s.sessionWriteModel.ResourceOwner) err := s.eventstore.FilterToQueryReducer(ctx, tokenReadModel) if err != nil { return nil, err } return tokenReadModel, nil } func (c *Commands) CreatePasskeyChallenge(userVerification domain.UserVerificationRequirement, dst json.Unmarshaler) SessionCommand { return func(ctx context.Context, cmd *SessionCommands) error { humanPasskeys, err := cmd.getHumanPasskeys(ctx) if err != nil { return err } webAuthNLogin, err := c.webauthnConfig.BeginLogin(ctx, humanPasskeys.human, userVerification, humanPasskeys.tokens...) if err != nil { return err } if err = json.Unmarshal(webAuthNLogin.CredentialAssertionData, dst); err != nil { return caos_errs.ThrowInternal(err, "COMMAND-Yah6A", "Errors.Internal") } cmd.sessionWriteModel.PasskeyChallenged(ctx, webAuthNLogin.Challenge, webAuthNLogin.AllowedCredentialIDs, webAuthNLogin.UserVerification) return nil } } func (c *Commands) CheckPasskey(credentialAssertionData json.Marshaler) SessionCommand { return func(ctx context.Context, cmd *SessionCommands) error { credentialAssertionData, err := json.Marshal(credentialAssertionData) if err != nil { return caos_errs.ThrowInvalidArgument(err, "COMMAND-ohG2o", "todo") } humanPasskeys, err := cmd.getHumanPasskeys(ctx) if err != nil { return err } webAuthN, err := cmd.sessionWriteModel.PasskeyChallenge.WebAuthNLogin(humanPasskeys.human, credentialAssertionData) if err != nil { return err } keyID, signCount, err := c.webauthnConfig.FinishLogin(ctx, humanPasskeys.human, webAuthN, credentialAssertionData, humanPasskeys.tokens...) if err != nil && keyID == nil { return err } _, token := domain.GetTokenByKeyID(humanPasskeys.tokens, keyID) if token == nil { return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-Aej7i", "Errors.User.WebAuthN.NotFound") } cmd.sessionWriteModel.PasskeyChecked(ctx, cmd.now(), token.WebAuthNTokenID, signCount) return nil } }