Files
hanko/backend/flow_api/flow/shared/hook_persist_webauthn_credential.go
2025-09-25 19:15:20 +02:00

81 lines
2.0 KiB
Go

package shared
import (
"encoding/json"
"fmt"
"github.com/gofrs/uuid"
auditlog "github.com/teamhanko/hanko/backend/v2/audit_log"
"github.com/teamhanko/hanko/backend/v2/flowpilot"
"github.com/teamhanko/hanko/backend/v2/persistence/models"
)
type WebauthnCredentialSave struct {
Action
}
func (h WebauthnCredentialSave) Execute(c flowpilot.HookExecutionContext) error {
deps := h.GetDeps(c)
if !c.Stash().Get(StashPathUserID).Exists() {
return nil
}
userId, err := uuid.FromString(c.Stash().Get(StashPathUserID).String())
if err != nil {
return fmt.Errorf("failed to parse stashed user_id into a uuid: %w", err)
}
if !c.Stash().Get(StashPathWebauthnCredentials).Exists() {
return nil
}
auditLogDetails := []auditlog.DetailOption{
auditlog.Detail("flow_id", c.GetFlowID()),
}
auditLogType := models.AuditLogPasskeyCreated
for _, webauthnCredential := range c.Stash().Get(StashPathWebauthnCredentials).Array() {
var credentialModel models.WebauthnCredential
err = json.Unmarshal([]byte(webauthnCredential.String()), &credentialModel)
if err != nil {
return fmt.Errorf("failed to unmarshal stashed webauthn_credential: %w", err)
}
err = deps.Persister.GetWebauthnCredentialPersisterWithConnection(deps.Tx).Create(credentialModel)
if err != nil {
return err
}
if userModel, ok := c.Get("session_user").(*models.User); ok {
userModel.WebauthnCredentials = append(userModel.WebauthnCredentials, credentialModel)
}
if credentialModel.MFAOnly {
auditLogType = models.AuditLogSecurityKeyCreated
auditLogDetails = append(auditLogDetails, auditlog.Detail("security_key", credentialModel.ID))
} else {
auditLogDetails = append(auditLogDetails, auditlog.Detail("passkey", credentialModel.ID))
}
}
err = c.Stash().Delete(StashPathWebauthnCredentials)
if err != nil {
return err
}
err = deps.AuditLogger.CreateWithConnection(
deps.Tx,
deps.HttpContext,
auditLogType,
&models.User{ID: userId},
nil,
auditLogDetails...)
if err != nil {
return fmt.Errorf("could not create audit log: %w", err)
}
return nil
}