(w http.ResponseWriter, r *http.Request)
| 459 | } |
| 460 | |
| 461 | func (a *API) challengeWebAuthnFactor(w http.ResponseWriter, r *http.Request) error { |
| 462 | ctx := r.Context() |
| 463 | db := a.db.WithContext(ctx) |
| 464 | config := a.config |
| 465 | |
| 466 | user := getUser(ctx) |
| 467 | factor := getFactor(ctx) |
| 468 | ipAddress := utilities.GetIPAddress(r) |
| 469 | |
| 470 | params := &ChallengeFactorParams{} |
| 471 | if err := retrieveRequestParams(r, params); err != nil { |
| 472 | return err |
| 473 | } |
| 474 | webAuthn, err := a.getWebAuthnMFA() |
| 475 | if err != nil { |
| 476 | return err |
| 477 | } |
| 478 | var response *ChallengeFactorResponse |
| 479 | var ws *models.WebAuthnSessionData |
| 480 | var challenge *models.Challenge |
| 481 | if factor.IsUnverified() { |
| 482 | // Get existing WebAuthn credentials to exclude duplicates |
| 483 | excludeList := []wbnprotocol.CredentialDescriptor{} |
| 484 | existingCredentials := user.WebAuthnCredentials() |
| 485 | for _, cred := range existingCredentials { |
| 486 | excludeList = append(excludeList, wbnprotocol.CredentialDescriptor{ |
| 487 | Type: wbnprotocol.PublicKeyCredentialType, |
| 488 | CredentialID: cred.ID, |
| 489 | Transport: []wbnprotocol.AuthenticatorTransport{"usb", "nfc"}, |
| 490 | }) |
| 491 | } |
| 492 | |
| 493 | options, session, err := webAuthn.BeginRegistration(user, webauthn.WithExclusions(excludeList)) |
| 494 | if err != nil { |
| 495 | return apierrors.NewInternalServerError("Failed to generate WebAuthn registration data").WithInternalError(err) |
| 496 | } |
| 497 | ws = &models.WebAuthnSessionData{ |
| 498 | SessionData: session, |
| 499 | } |
| 500 | challenge = ws.ToChallenge(factor.ID, ipAddress) |
| 501 | |
| 502 | response = &ChallengeFactorResponse{ |
| 503 | Type: factor.FactorType, |
| 504 | ID: challenge.ID, |
| 505 | WebAuthn: &WebAuthnChallengeData{ |
| 506 | Type: "create", |
| 507 | CredentialOptions: options, |
| 508 | }, |
| 509 | } |
| 510 | |
| 511 | } else if factor.IsVerified() { |
| 512 | options, session, err := webAuthn.BeginLogin(user) |
| 513 | if err != nil { |
| 514 | return err |
| 515 | } |
| 516 | ws = &models.WebAuthnSessionData{ |
| 517 | SessionData: session, |
| 518 | } |
no test coverage detected