mirror of
https://github.com/onsonr/sonr.git
synced 2025-03-10 13:07:09 +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"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gorilla/sessions"
|
"github.com/gorilla/sessions"
|
||||||
@ -45,16 +46,28 @@ func SessionMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func defaultSession(id string, s *sessions.Session) *session {
|
func buildSession(c echo.Context, id string) *Session {
|
||||||
return &session{
|
return &Session{
|
||||||
session: s,
|
ID: id,
|
||||||
id: id,
|
Origin: getOrigin(c.Request().Header.Get("Host")),
|
||||||
origin: "",
|
UserAgent: c.Request().Header.Get("Sec-Ch-Ua"),
|
||||||
address: "",
|
Platform: c.Request().Header.Get("Sec-Ch-Ua-Platform"),
|
||||||
chainID: "",
|
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) {
|
func getSessionID(ctx context.Context) (string, error) {
|
||||||
sessionID, ok := ctx.Value(ctxKeySessionID{}).(string)
|
sessionID, ok := ctx.Value(ctxKeySessionID{}).(string)
|
||||||
if !ok || sessionID == "" {
|
if !ok || sessionID == "" {
|
||||||
|
@ -25,27 +25,3 @@ func GetAuthState(c echo.Context) AuthState {
|
|||||||
s := AuthState(c.Request().Header.Get("Authorization"))
|
s := AuthState(c.Request().Header.Get("Authorization"))
|
||||||
return s
|
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
|
package ctx
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/go-webauthn/webauthn/protocol"
|
"github.com/go-webauthn/webauthn/protocol"
|
||||||
"github.com/gorilla/sessions"
|
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
type WebBytes = protocol.URLEncodedBase64
|
type WebBytes = protocol.URLEncodedBase64
|
||||||
|
|
||||||
type Session interface {
|
type Session struct {
|
||||||
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 {
|
|
||||||
// Defaults
|
// Defaults
|
||||||
session *sessions.Session
|
ID string // Generated ksuid http cookie; 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
|
||||||
origin string // Webauthn mapping to Relaying Party ID; Initialized on first request
|
UserAgent string
|
||||||
|
Platform string
|
||||||
|
|
||||||
// Initialization
|
// Initialization
|
||||||
address string // Webauthn mapping to User ID; 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
|
ChainID string // Macaroon mapping to location; Supplied by DWN frontend
|
||||||
|
|
||||||
|
Subject string // Webauthn mapping to User Displayable Name; Supplied by DWN frontend
|
||||||
|
|
||||||
// Authentication
|
// Authentication
|
||||||
challenge WebBytes // Webauthn mapping to Challenge; Per session based on origin
|
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 {
|
func (s *Session) GetChallenge(subject string) (WebBytes, error) {
|
||||||
return s.id
|
// 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 {
|
if s.challenge == nil {
|
||||||
return nil, nil
|
chl, err := protocol.CreateChallenge()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
s.challenge = chl
|
||||||
}
|
}
|
||||||
return s.challenge, nil
|
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 {
|
if s.challenge == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if s.challenge.String() != challenge.String() {
|
if s.challenge.String() != challenge.String() {
|
||||||
return fmt.Errorf("invalid challenge")
|
return fmt.Errorf("invalid challenge")
|
||||||
}
|
}
|
||||||
s.subject = subject
|
s.Subject = subject
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *session) SaveHTTP(c echo.Context) error {
|
func GetSession(c echo.Context) *Session {
|
||||||
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 {
|
|
||||||
id, _ := getSessionID(c.Request().Context())
|
id, _ := getSessionID(c.Request().Context())
|
||||||
sess, _ := store.Get(c.Request(), id)
|
return buildSession(c, id)
|
||||||
if sess.IsNew {
|
}
|
||||||
s := defaultSession(id, sess)
|
|
||||||
s.SaveHTTP(c)
|
func SetAddress(c echo.Context, address string) *Session {
|
||||||
return s
|
// Write address to X-Sonr-Address header
|
||||||
}
|
c.Response().Header().Set("X-Sonr-Address", address)
|
||||||
s, _ := readSessionFromStore(c, id)
|
return buildSession(c, "")
|
||||||
return s
|
|
||||||
}
|
}
|
||||||
|
@ -5,13 +5,9 @@ import (
|
|||||||
"github.com/go-webauthn/webauthn/protocol/webauthncose"
|
"github.com/go-webauthn/webauthn/protocol/webauthncose"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewCredentialCreationOptions(subject, address string) (*protocol.PublicKeyCredentialCreationOptions, error) {
|
func NewCredentialCreationOptions(subject, address string, challenge protocol.URLEncodedBase64) *protocol.PublicKeyCredentialCreationOptions {
|
||||||
chl, err := protocol.CreateChallenge()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &protocol.PublicKeyCredentialCreationOptions{
|
return &protocol.PublicKeyCredentialCreationOptions{
|
||||||
Challenge: chl,
|
Challenge: challenge,
|
||||||
User: protocol.UserEntity{
|
User: protocol.UserEntity{
|
||||||
DisplayName: subject,
|
DisplayName: subject,
|
||||||
ID: address,
|
ID: address,
|
||||||
@ -19,7 +15,7 @@ func NewCredentialCreationOptions(subject, address string) (*protocol.PublicKeyC
|
|||||||
Attestation: defaultAttestation(),
|
Attestation: defaultAttestation(),
|
||||||
AuthenticatorSelection: defaultAuthenticatorSelection(),
|
AuthenticatorSelection: defaultAuthenticatorSelection(),
|
||||||
Parameters: defaultCredentialParameters(),
|
Parameters: defaultCredentialParameters(),
|
||||||
}, nil
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildUserEntity(userID string) protocol.UserEntity {
|
func buildUserEntity(userID string) protocol.UserEntity {
|
||||||
|
@ -10,9 +10,9 @@ import (
|
|||||||
|
|
||||||
func Route(c echo.Context) error {
|
func Route(c echo.Context) error {
|
||||||
s := ctx.GetSession(c)
|
s := ctx.GetSession(c)
|
||||||
log.Printf("Session ID: %s", s.ID())
|
log.Printf("Session ID: %s", s.ID)
|
||||||
log.Printf("Session Origin: %s", s.Origin())
|
log.Printf("Session Origin: %s", s.Origin)
|
||||||
log.Printf("Session Address: %s", s.Address())
|
log.Printf("Session Address: %s", s.Address)
|
||||||
log.Printf("Session ChainID: %s", s.ChainID())
|
log.Printf("Session ChainID: %s", s.ChainID)
|
||||||
return ctx.RenderTempl(c, View())
|
return ctx.RenderTempl(c, View())
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,9 @@ package handlers
|
|||||||
import (
|
import (
|
||||||
"github.com/go-webauthn/webauthn/protocol"
|
"github.com/go-webauthn/webauthn/protocol"
|
||||||
"github.com/labstack/echo/v4"
|
"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 {
|
func RegisterSubjectCheck(e echo.Context) error {
|
||||||
credentialID := e.FormValue("credentialID")
|
subject := e.FormValue("subject")
|
||||||
return e.JSON(200, credentialID)
|
return e.JSON(200, subject)
|
||||||
}
|
}
|
||||||
|
|
||||||
func RegisterSubjectStart(e echo.Context) error {
|
func RegisterSubjectStart(e echo.Context) error {
|
||||||
opts := &protocol.PublicKeyCredentialCreationOptions{
|
// Get subject and address
|
||||||
RelyingParty: protocol.RelyingPartyEntity{
|
subject := e.FormValue("subject")
|
||||||
CredentialEntity: protocol.CredentialEntity{
|
address := e.FormValue("address")
|
||||||
Name: "Sonr",
|
|
||||||
},
|
// Set address in session
|
||||||
ID: "https://sonr.io",
|
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 {
|
func RegisterSubjectFinish(e echo.Context) error {
|
||||||
@ -65,5 +73,5 @@ func RegisterSubjectFinish(e echo.Context) error {
|
|||||||
//
|
//
|
||||||
// // Create the Credential
|
// // Create the Credential
|
||||||
// // credential := orm.NewCredential(parsedData, e.Request().Host, "")
|
// // 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