mirror of
https://github.com/thomiceli/opengist.git
synced 2024-12-23 13:02:39 +00:00
138 lines
3.6 KiB
Go
138 lines
3.6 KiB
Go
package webauthn
|
|
|
|
import (
|
|
"encoding/json"
|
|
"github.com/go-webauthn/webauthn/protocol"
|
|
"github.com/go-webauthn/webauthn/webauthn"
|
|
"github.com/rs/zerolog/log"
|
|
"github.com/thomiceli/opengist/internal/config"
|
|
"github.com/thomiceli/opengist/internal/db"
|
|
"net/http"
|
|
"net/url"
|
|
)
|
|
|
|
var webAuthn *webauthn.WebAuthn
|
|
|
|
func Init(urlStr string) error {
|
|
var rpid, rporigin string
|
|
var err error
|
|
|
|
if urlStr == "" {
|
|
log.Info().Msg("External URL is not set, passkeys RP ID and Origins will be set to localhost")
|
|
rpid = "localhost"
|
|
rporigin = "http://localhost" + ":" + config.C.HttpPort
|
|
} else {
|
|
urlStruct, err := url.Parse(urlStr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
rpid = urlStruct.Hostname()
|
|
rporigin, err = protocol.FullyQualifiedOrigin(urlStr)
|
|
if err != nil {
|
|
log.Error().Err(err).Msg("Failed to get fully qualified origin from external URL")
|
|
}
|
|
}
|
|
|
|
webAuthn, err = webauthn.New(&webauthn.Config{
|
|
RPDisplayName: "Opengist",
|
|
RPID: rpid,
|
|
RPOrigins: []string{rporigin},
|
|
})
|
|
return err
|
|
}
|
|
|
|
func BeginBinding(dbUser *db.User) (credCreation *protocol.CredentialCreation, jsonSession []byte, err error) {
|
|
waUser := &user{User: dbUser}
|
|
credCreation, session, err := webAuthn.BeginRegistration(waUser, webauthn.WithAuthenticatorSelection(
|
|
protocol.AuthenticatorSelection{
|
|
ResidentKey: protocol.ResidentKeyRequirementRequired,
|
|
UserVerification: protocol.VerificationRequired,
|
|
},
|
|
), webauthn.WithAppIdExcludeExtension("Opengist"), webauthn.WithExclusions(waUser.Exclusions()))
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
jsonSession, _ = json.Marshal(session)
|
|
return
|
|
}
|
|
|
|
func FinishBinding(dbUser *db.User, jsonSession []byte, response *http.Request) (*webauthn.Credential, error) {
|
|
waUser := &user{User: dbUser}
|
|
|
|
var session webauthn.SessionData
|
|
_ = json.Unmarshal(jsonSession, &session)
|
|
|
|
return webAuthn.FinishRegistration(waUser, session, response)
|
|
}
|
|
|
|
func BeginDiscoverableLogin() (credCreation *protocol.CredentialAssertion, jsonSession []byte, err error) {
|
|
credCreation, session, err := webAuthn.BeginDiscoverableLogin(
|
|
webauthn.WithUserVerification(protocol.VerificationPreferred),
|
|
)
|
|
|
|
jsonSession, _ = json.Marshal(session)
|
|
return
|
|
}
|
|
|
|
func FinishDiscoverableLogin(jsonSession []byte, response *http.Request) (uint, error) {
|
|
var session webauthn.SessionData
|
|
_ = json.Unmarshal(jsonSession, &session)
|
|
|
|
parsedResponse, err := protocol.ParseCredentialRequestResponse(response)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
waUser, cred, err := webAuthn.ValidatePasskeyLogin(discoverUser, session, parsedResponse)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
dbCredential, err := db.GetCredentialByID(cred.ID)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if err = dbCredential.UpdateSignCount(); err != nil {
|
|
return 0, err
|
|
}
|
|
if err = dbCredential.UpdateLastUsedAt(); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
return waUser.(*user).User.ID, nil
|
|
}
|
|
|
|
func BeginLogin(dbUser *db.User) (credCreation *protocol.CredentialAssertion, jsonSession []byte, err error) {
|
|
waUser := &user{User: dbUser}
|
|
credCreation, session, err := webAuthn.BeginLogin(waUser)
|
|
|
|
jsonSession, _ = json.Marshal(session)
|
|
return
|
|
}
|
|
|
|
func FinishLogin(dbUser *db.User, jsonSession []byte, response *http.Request) error {
|
|
waUser := &user{User: dbUser}
|
|
|
|
var session webauthn.SessionData
|
|
_ = json.Unmarshal(jsonSession, &session)
|
|
|
|
cred, err := webAuthn.FinishLogin(waUser, session, response)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
dbCredential, err := db.GetCredentialByID(cred.ID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err = dbCredential.UpdateSignCount(); err != nil {
|
|
return err
|
|
}
|
|
if err = dbCredential.UpdateLastUsedAt(); err != nil {
|
|
return err
|
|
}
|
|
|
|
return err
|
|
}
|