mirror of
https://github.com/onsonr/sonr.git
synced 2025-03-10 04:57:08 +00:00
feat: add User-Agent and Platform to session
This commit is contained in:
parent
58aa71997d
commit
104df074e9
@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/sessions"
|
||||
@ -45,16 +46,28 @@ func SessionMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
}
|
||||
}
|
||||
|
||||
func defaultSession(id string, s *sessions.Session) *session {
|
||||
return &session{
|
||||
session: s,
|
||||
id: id,
|
||||
origin: "",
|
||||
address: "",
|
||||
chainID: "",
|
||||
func buildSession(c echo.Context, id string) *Session {
|
||||
return &Session{
|
||||
ID: id,
|
||||
Origin: getOrigin(c.Request().Header.Get("Host")),
|
||||
UserAgent: c.Request().Header.Get("Sec-Ch-Ua"),
|
||||
Platform: c.Request().Header.Get("Sec-Ch-Ua-Platform"),
|
||||
Address: c.Request().Header.Get("X-Sonr-Address"),
|
||||
ChainID: "",
|
||||
}
|
||||
}
|
||||
|
||||
func getOrigin(o string) string {
|
||||
if o == "" {
|
||||
return ""
|
||||
}
|
||||
u, err := url.Parse(o)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return u.Hostname()
|
||||
}
|
||||
|
||||
func getSessionID(ctx context.Context) (string, error) {
|
||||
sessionID, ok := ctx.Value(ctxKeySessionID{}).(string)
|
||||
if !ok || sessionID == "" {
|
||||
|
@ -25,27 +25,3 @@ func GetAuthState(c echo.Context) AuthState {
|
||||
s := AuthState(c.Request().Header.Get("Authorization"))
|
||||
return s
|
||||
}
|
||||
|
||||
func readSessionFromStore(c echo.Context, id string) (*session, error) {
|
||||
sess, err := store.Get(c.Request(), id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewSessionFromValues(sess.Values), nil
|
||||
}
|
||||
|
||||
func writeSessionToStore(
|
||||
c echo.Context,
|
||||
id string,
|
||||
) error {
|
||||
sess, err := store.Get(c.Request(), id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s := defaultSession(id, sess)
|
||||
err = s.SaveHTTP(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -1,120 +1,70 @@
|
||||
package ctx
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/go-webauthn/webauthn/protocol"
|
||||
"github.com/gorilla/sessions"
|
||||
"github.com/labstack/echo/v4"
|
||||
)
|
||||
|
||||
type WebBytes = protocol.URLEncodedBase64
|
||||
|
||||
type Session interface {
|
||||
ID() string
|
||||
Origin() string
|
||||
|
||||
Address() string
|
||||
ChainID() string
|
||||
|
||||
GetChallenge(subject string) (WebBytes, error)
|
||||
ValidateChallenge(challenge WebBytes, subject string) error
|
||||
|
||||
SaveHTTP(c echo.Context) error
|
||||
}
|
||||
|
||||
func NewSessionFromValues(vals map[interface{}]interface{}) *session {
|
||||
s := &session{
|
||||
id: vals["id"].(string),
|
||||
origin: vals["origin"].(string),
|
||||
address: vals["address"].(string),
|
||||
chainID: vals["chainID"].(string),
|
||||
challenge: vals["challenge"].(WebBytes),
|
||||
subject: vals["subject"].(string),
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
type session struct {
|
||||
type Session struct {
|
||||
// Defaults
|
||||
session *sessions.Session
|
||||
id string // Generated ksuid http cookie; Initialized on first request
|
||||
origin string // Webauthn mapping to Relaying Party ID; Initialized on first request
|
||||
ID string // Generated ksuid http cookie; Initialized on first request
|
||||
Origin string // Webauthn mapping to Relaying Party ID; Initialized on first request
|
||||
UserAgent string
|
||||
Platform string
|
||||
|
||||
// Initialization
|
||||
address string // Webauthn mapping to User ID; Supplied by DWN frontend
|
||||
chainID string // Macaroon mapping to location; Supplied by DWN frontend
|
||||
Address string // Webauthn mapping to User ID; Supplied by DWN frontend
|
||||
ChainID string // Macaroon mapping to location; Supplied by DWN frontend
|
||||
|
||||
Subject string // Webauthn mapping to User Displayable Name; Supplied by DWN frontend
|
||||
|
||||
// Authentication
|
||||
challenge WebBytes // Webauthn mapping to Challenge; Per session based on origin
|
||||
subject string // Webauthn mapping to User Displayable Name; Supplied by DWN frontend
|
||||
}
|
||||
|
||||
func (s *session) ID() string {
|
||||
return s.id
|
||||
}
|
||||
func (s *Session) GetChallenge(subject string) (WebBytes, error) {
|
||||
// Check if challenge is already set and subject matches
|
||||
if s.Subject != "" && s.Subject != subject {
|
||||
return nil, errors.New("challenge already set, and subject does not match")
|
||||
} else if s.Subject == "" {
|
||||
s.Subject = subject
|
||||
} else {
|
||||
return s.challenge, nil
|
||||
}
|
||||
|
||||
func (s *session) Origin() string {
|
||||
return s.origin
|
||||
}
|
||||
|
||||
func (s *session) Address() string {
|
||||
return s.address
|
||||
}
|
||||
|
||||
func (s *session) ChainID() string {
|
||||
return s.chainID
|
||||
}
|
||||
|
||||
func (s *session) GetChallenge(subject string) (WebBytes, error) {
|
||||
if s.challenge == nil {
|
||||
return nil, nil
|
||||
chl, err := protocol.CreateChallenge()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.challenge = chl
|
||||
}
|
||||
return s.challenge, nil
|
||||
}
|
||||
|
||||
func (s *session) ValidateChallenge(challenge WebBytes, subject string) error {
|
||||
func (s *Session) ValidateChallenge(challenge WebBytes, subject string) error {
|
||||
if s.challenge == nil {
|
||||
return nil
|
||||
}
|
||||
if s.challenge.String() != challenge.String() {
|
||||
return fmt.Errorf("invalid challenge")
|
||||
}
|
||||
s.subject = subject
|
||||
s.Subject = subject
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *session) SaveHTTP(c echo.Context) error {
|
||||
sess, err := store.Get(c.Request(), s.id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sess.Values = s.Values()
|
||||
err = sess.Save(c.Request(), c.Response().Writer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *session) Values() map[interface{}]interface{} {
|
||||
vals := make(map[interface{}]interface{})
|
||||
vals["id"] = s.id
|
||||
vals["address"] = s.address
|
||||
vals["chainID"] = s.chainID
|
||||
vals["challenge"] = s.challenge
|
||||
vals["subject"] = s.subject
|
||||
return vals
|
||||
}
|
||||
|
||||
func GetSession(c echo.Context) Session {
|
||||
func GetSession(c echo.Context) *Session {
|
||||
id, _ := getSessionID(c.Request().Context())
|
||||
sess, _ := store.Get(c.Request(), id)
|
||||
if sess.IsNew {
|
||||
s := defaultSession(id, sess)
|
||||
s.SaveHTTP(c)
|
||||
return s
|
||||
}
|
||||
s, _ := readSessionFromStore(c, id)
|
||||
return s
|
||||
return buildSession(c, id)
|
||||
}
|
||||
|
||||
func SetAddress(c echo.Context, address string) *Session {
|
||||
// Write address to X-Sonr-Address header
|
||||
c.Response().Header().Set("X-Sonr-Address", address)
|
||||
return buildSession(c, "")
|
||||
}
|
||||
|
@ -5,13 +5,9 @@ import (
|
||||
"github.com/go-webauthn/webauthn/protocol/webauthncose"
|
||||
)
|
||||
|
||||
func NewCredentialCreationOptions(subject, address string) (*protocol.PublicKeyCredentialCreationOptions, error) {
|
||||
chl, err := protocol.CreateChallenge()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
func NewCredentialCreationOptions(subject, address string, challenge protocol.URLEncodedBase64) *protocol.PublicKeyCredentialCreationOptions {
|
||||
return &protocol.PublicKeyCredentialCreationOptions{
|
||||
Challenge: chl,
|
||||
Challenge: challenge,
|
||||
User: protocol.UserEntity{
|
||||
DisplayName: subject,
|
||||
ID: address,
|
||||
@ -19,7 +15,7 @@ func NewCredentialCreationOptions(subject, address string) (*protocol.PublicKeyC
|
||||
Attestation: defaultAttestation(),
|
||||
AuthenticatorSelection: defaultAuthenticatorSelection(),
|
||||
Parameters: defaultCredentialParameters(),
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func buildUserEntity(userID string) protocol.UserEntity {
|
||||
|
@ -10,9 +10,9 @@ import (
|
||||
|
||||
func Route(c echo.Context) error {
|
||||
s := ctx.GetSession(c)
|
||||
log.Printf("Session ID: %s", s.ID())
|
||||
log.Printf("Session Origin: %s", s.Origin())
|
||||
log.Printf("Session Address: %s", s.Address())
|
||||
log.Printf("Session ChainID: %s", s.ChainID())
|
||||
log.Printf("Session ID: %s", s.ID)
|
||||
log.Printf("Session Origin: %s", s.Origin)
|
||||
log.Printf("Session Address: %s", s.Address)
|
||||
log.Printf("Session ChainID: %s", s.ChainID)
|
||||
return ctx.RenderTempl(c, View())
|
||||
}
|
||||
|
@ -3,6 +3,9 @@ package handlers
|
||||
import (
|
||||
"github.com/go-webauthn/webauthn/protocol"
|
||||
"github.com/labstack/echo/v4"
|
||||
|
||||
"github.com/onsonr/sonr/internal/ctx"
|
||||
"github.com/onsonr/sonr/internal/orm"
|
||||
)
|
||||
|
||||
// ╭───────────────────────────────────────────────────────────╮
|
||||
@ -34,20 +37,25 @@ func LoginSubjectFinish(e echo.Context) error {
|
||||
// ╰───────────────────────────────────────────────────────────╯
|
||||
|
||||
func RegisterSubjectCheck(e echo.Context) error {
|
||||
credentialID := e.FormValue("credentialID")
|
||||
return e.JSON(200, credentialID)
|
||||
subject := e.FormValue("subject")
|
||||
return e.JSON(200, subject)
|
||||
}
|
||||
|
||||
func RegisterSubjectStart(e echo.Context) error {
|
||||
opts := &protocol.PublicKeyCredentialCreationOptions{
|
||||
RelyingParty: protocol.RelyingPartyEntity{
|
||||
CredentialEntity: protocol.CredentialEntity{
|
||||
Name: "Sonr",
|
||||
},
|
||||
ID: "https://sonr.io",
|
||||
},
|
||||
// Get subject and address
|
||||
subject := e.FormValue("subject")
|
||||
address := e.FormValue("address")
|
||||
|
||||
// Set address in session
|
||||
s := ctx.GetSession(e)
|
||||
s = ctx.SetAddress(e, address)
|
||||
|
||||
// Get challenge
|
||||
chal, err := s.GetChallenge(subject)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return e.JSON(200, opts)
|
||||
return e.JSON(201, orm.NewCredentialCreationOptions(subject, address, chal))
|
||||
}
|
||||
|
||||
func RegisterSubjectFinish(e echo.Context) error {
|
||||
@ -65,5 +73,5 @@ func RegisterSubjectFinish(e echo.Context) error {
|
||||
//
|
||||
// // Create the Credential
|
||||
// // credential := orm.NewCredential(parsedData, e.Request().Host, "")
|
||||
return e.JSON(200, ccr)
|
||||
return e.JSON(201, ccr)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user