mirror of
https://github.com/Theodor-Springmann-Stiftung/musenalm.git
synced 2025-10-29 09:15:33 +00:00
user login & middleware complete
This commit is contained in:
@@ -503,6 +503,7 @@ const (
|
||||
ITEMS_IDENTIFIER_FIELD = "identifier"
|
||||
|
||||
SESSIONS_TOKEN_FIELD = "token"
|
||||
SESSIONS_CSRF_FIELD = "csrf"
|
||||
SESSIONS_USER_FIELD = "user"
|
||||
SESSIONS_IP_FIELD = "ip"
|
||||
SESSIONS_USER_AGENT_FIELD = "agent"
|
||||
@@ -512,8 +513,11 @@ const (
|
||||
SESSIONS_PERSIST_FIELD = "persist"
|
||||
|
||||
USERS_TABLE = "users"
|
||||
USERS_EMAIL_FIELD = "email"
|
||||
USERS_SETTINGS_FIELD = "settings"
|
||||
USERS_NAME_FIELD = "name"
|
||||
USERS_ROLE_FIELD = "role"
|
||||
USERS_AVATAR_FIELD = "avatar"
|
||||
|
||||
SESSION_COOKIE_NAME = "sid"
|
||||
)
|
||||
|
||||
78
dbmodels/session_generation.go
Normal file
78
dbmodels/session_generation.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package dbmodels
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
"github.com/pocketbase/pocketbase/tools/types" // For types.NewDateTimeFromTime
|
||||
)
|
||||
|
||||
const (
|
||||
secureTokenByteLength = 64
|
||||
)
|
||||
|
||||
func generateSecureRandomToken(length int) (string, error) {
|
||||
if length <= 0 {
|
||||
length = secureTokenByteLength
|
||||
}
|
||||
randomBytes := make([]byte, length)
|
||||
_, err := rand.Read(randomBytes)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to generate random bytes for token: %w", err)
|
||||
}
|
||||
|
||||
return base64.URLEncoding.EncodeToString(randomBytes), nil
|
||||
}
|
||||
|
||||
func CreateSessionToken(
|
||||
app core.App,
|
||||
userID string,
|
||||
ipAddress string,
|
||||
userAgent string,
|
||||
isPersistent bool,
|
||||
sessionDuration time.Duration,
|
||||
) (*Session, error) {
|
||||
|
||||
collection, err := app.FindCollectionByNameOrId(SESSIONS_TABLE)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find '%s' collection: %w", SESSIONS_TABLE, err)
|
||||
}
|
||||
|
||||
sessionTokenClear, err := generateSecureRandomToken(secureTokenByteLength)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to generate session token: %w", err)
|
||||
}
|
||||
|
||||
csrfTokenClear, err := generateSecureRandomToken(secureTokenByteLength)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to generate CSRF token: %w", err)
|
||||
}
|
||||
|
||||
record := core.NewRecord(collection)
|
||||
session := NewSession(record)
|
||||
|
||||
// Set required fields with hashed tokens
|
||||
session.SetToken(sessionTokenClear)
|
||||
session.SetCSRF(csrfTokenClear)
|
||||
session.SetUser(userID)
|
||||
|
||||
date := types.NowDateTime()
|
||||
expires := date.Add(sessionDuration)
|
||||
session.SetExpires(expires)
|
||||
|
||||
session.SetPersist(isPersistent)
|
||||
session.SetLastAccess(types.NowDateTime())
|
||||
session.SetUserAgent(userAgent)
|
||||
session.SetIP(ipAddress)
|
||||
|
||||
if errSave := app.Save(session); errSave != nil {
|
||||
app.Logger().Error("Failed to save session token record", "error", errSave, "userID", userID)
|
||||
return nil, fmt.Errorf("failed to save session token record: %w", errSave)
|
||||
}
|
||||
|
||||
app.Logger().Info("Successfully created session token entry", "recordId", record.Id, "userID", userID)
|
||||
return session, nil
|
||||
}
|
||||
@@ -5,6 +5,24 @@ import (
|
||||
"github.com/pocketbase/pocketbase/tools/types"
|
||||
)
|
||||
|
||||
type FixedSession struct {
|
||||
ID string `json:"id"`
|
||||
Token string `json:"token"`
|
||||
User string `json:"user"`
|
||||
Created string `json:"created"`
|
||||
Updated string `json:"updated"`
|
||||
Expires types.DateTime `json:"expires"`
|
||||
IP string `json:"ip"`
|
||||
UserAgent string `json:"user_agent"`
|
||||
LastAccess types.DateTime `json:"last_access"`
|
||||
Persist bool `json:"persist"`
|
||||
CSRF string `json:"csrf"`
|
||||
}
|
||||
|
||||
func (s *FixedSession) IsExpired() bool {
|
||||
return s.Expires.IsZero() || s.Expires.Before(types.NowDateTime())
|
||||
}
|
||||
|
||||
var _ core.RecordProxy = (*Place)(nil)
|
||||
|
||||
type Session struct {
|
||||
@@ -18,7 +36,7 @@ func NewSession(record *core.Record) *Session {
|
||||
}
|
||||
|
||||
func (u *Session) TableName() string {
|
||||
return USERS_TABLE
|
||||
return SESSIONS_TABLE
|
||||
}
|
||||
|
||||
func (u *Session) Token() string {
|
||||
@@ -84,3 +102,31 @@ func (u *Session) Persist() bool {
|
||||
func (u *Session) SetPersist(persist bool) {
|
||||
u.Set(SESSIONS_PERSIST_FIELD, persist)
|
||||
}
|
||||
|
||||
func (u *Session) CSRF() string {
|
||||
return u.GetString(SESSIONS_CSRF_FIELD)
|
||||
}
|
||||
|
||||
func (u *Session) SetCSRF(csrf string) {
|
||||
u.Set(SESSIONS_CSRF_FIELD, csrf)
|
||||
}
|
||||
|
||||
func (u *Session) IsExpired() bool {
|
||||
return u.Expires().IsZero() || u.Expires().Before(types.NowDateTime())
|
||||
}
|
||||
|
||||
func (u *Session) Fixed() FixedSession {
|
||||
return FixedSession{
|
||||
ID: u.Id,
|
||||
Token: u.Token(),
|
||||
User: u.User(),
|
||||
Created: u.Created(),
|
||||
Updated: u.Updated(),
|
||||
Expires: u.Expires(),
|
||||
IP: u.IP(),
|
||||
UserAgent: u.UserAgent(),
|
||||
LastAccess: u.LastAccess(),
|
||||
Persist: u.Persist(),
|
||||
CSRF: u.CSRF(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,18 @@ import (
|
||||
"github.com/pocketbase/pocketbase/tools/types"
|
||||
)
|
||||
|
||||
type FixedUser struct {
|
||||
Id string `json:"id"`
|
||||
Email string `json:"email"`
|
||||
Created types.DateTime `json:"created"`
|
||||
Updated types.DateTime `json:"updated"`
|
||||
Name string `json:"name"`
|
||||
Role string `json:"role"`
|
||||
Avatar string `json:"avatar"`
|
||||
Verified bool `json:"verified"`
|
||||
Settings string `json:"settings"`
|
||||
}
|
||||
|
||||
var _ core.RecordProxy = (*Place)(nil)
|
||||
|
||||
type User struct {
|
||||
@@ -22,7 +34,7 @@ func (u *User) TableName() string {
|
||||
return USERS_TABLE
|
||||
}
|
||||
|
||||
// INFO: Email is already set on the core.Record
|
||||
// INFO: Email, password functions are already set on the core.Record
|
||||
// TODO: We need to create a settings struct as soon as we have settings
|
||||
func (u *User) Name() string {
|
||||
return u.GetString(USERS_NAME_FIELD)
|
||||
@@ -59,3 +71,16 @@ func (u *User) Avatar() string {
|
||||
func (u *User) SetAvatar(avatar *filesystem.File) {
|
||||
u.Set(USERS_AVATAR_FIELD, avatar)
|
||||
}
|
||||
|
||||
func (u *User) Fixed() FixedUser {
|
||||
return FixedUser{
|
||||
Id: u.Id,
|
||||
Email: u.Email(),
|
||||
Created: u.Created(),
|
||||
Updated: u.Updated(),
|
||||
Name: u.Name(),
|
||||
Role: u.Role(),
|
||||
Avatar: u.Avatar(),
|
||||
Verified: u.Verified(),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user