zitadel/internal/webauthn/client.go
2023-08-11 15:36:18 +00:00

75 lines
2.3 KiB
Go

package webauthn
import (
"fmt"
"github.com/descope/virtualwebauthn"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/types/known/structpb"
)
type Client struct {
rp virtualwebauthn.RelyingParty
auth virtualwebauthn.Authenticator
authVerifyUser virtualwebauthn.Authenticator
credential virtualwebauthn.Credential
}
func NewClient(name, domain, origin string) *Client {
rp := virtualwebauthn.RelyingParty{
Name: name,
ID: domain,
Origin: origin,
}
return &Client{
rp: rp,
auth: virtualwebauthn.NewAuthenticatorWithOptions(virtualwebauthn.AuthenticatorOptions{
UserNotVerified: true,
}),
authVerifyUser: virtualwebauthn.NewAuthenticator(),
credential: virtualwebauthn.NewCredential(virtualwebauthn.KeyTypeEC2),
}
}
func (c *Client) CreateAttestationResponse(optionsPb *structpb.Struct) (*structpb.Struct, error) {
options, err := protojson.Marshal(optionsPb)
if err != nil {
return nil, fmt.Errorf("webauthn.Client.CreateAttestationResponse: %w", err)
}
parsedAttestationOptions, err := virtualwebauthn.ParseAttestationOptions(string(options))
if err != nil {
return nil, fmt.Errorf("webauthn.Client.CreateAttestationResponse: %w", err)
}
resp := new(structpb.Struct)
err = protojson.Unmarshal([]byte(virtualwebauthn.CreateAttestationResponse(
c.rp, c.auth, c.credential, *parsedAttestationOptions,
)), resp)
if err != nil {
return nil, fmt.Errorf("webauthn.Client.CreateAttestationResponse: %w", err)
}
return resp, nil
}
func (c *Client) CreateAssertionResponse(optionsPb *structpb.Struct, verifyUser bool) (*structpb.Struct, error) {
options, err := protojson.Marshal(optionsPb)
if err != nil {
return nil, fmt.Errorf("webauthn.Client.CreateAssertionResponse: %w", err)
}
parsedAssertionOptions, err := virtualwebauthn.ParseAssertionOptions(string(options))
if err != nil {
return nil, fmt.Errorf("webauthn.Client.CreateAssertionResponse: %w", err)
}
authenticator := c.auth
if verifyUser {
authenticator = c.authVerifyUser
}
resp := new(structpb.Struct)
err = protojson.Unmarshal([]byte(virtualwebauthn.CreateAssertionResponse(
c.rp, authenticator, c.credential, *parsedAssertionOptions,
)), resp)
if err != nil {
return nil, fmt.Errorf("webauthn.Client.CreateAssertionResponse: %w", err)
}
return resp, nil
}