Enha: use of sql sessions
This commit is contained in:
		| @@ -5,6 +5,7 @@ | |||||||
| 		{{template "linklogin" .LinkLogin}} | 		{{template "linklogin" .LinkLogin}} | ||||||
| 	{{ else if eq .State.RoomID "" }} | 	{{ else if eq .State.RoomID "" }} | ||||||
| 		<div id="hello-user"> | 		<div id="hello-user"> | ||||||
|  | 	<p>data: {{.}} {{.State}} {{.Room}}</p> | ||||||
| 			<p>Hello {{.State.Username}}</p> | 			<p>Hello {{.State.Username}}</p> | ||||||
| 		</div> | 		</div> | ||||||
| 		<div id="create-room" class="create-room-div"> | 		<div id="create-room" class="create-room-div"> | ||||||
|   | |||||||
							
								
								
									
										
											BIN
										
									
								
								gralias.db
									
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								gralias.db
									
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							| @@ -130,10 +130,10 @@ func notifyBotIfNeeded(room *models.Room) { | |||||||
| func getFullInfoByCtx(ctx context.Context) (*models.FullInfo, error) { | func getFullInfoByCtx(ctx context.Context) (*models.FullInfo, error) { | ||||||
| 	resp := &models.FullInfo{} | 	resp := &models.FullInfo{} | ||||||
| 	// state, err := getStateByCtx(ctx) | 	// state, err := getStateByCtx(ctx) | ||||||
| 	// if err != nil { |  | ||||||
| 	// 	return nil, err |  | ||||||
| 	// } |  | ||||||
| 	state, err := getPlayerByCtx(ctx) | 	state, err := getPlayerByCtx(ctx) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
| 	resp.State = state | 	resp.State = state | ||||||
| 	if state.RoomID == "" { | 	if state.RoomID == "" { | ||||||
| 		return resp, nil | 		return resp, nil | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| package handlers | package handlers | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|  | 	"context" | ||||||
| 	"crypto/hmac" | 	"crypto/hmac" | ||||||
| 	"crypto/sha256" | 	"crypto/sha256" | ||||||
| 	"encoding/base64" | 	"encoding/base64" | ||||||
| @@ -12,6 +13,7 @@ import ( | |||||||
| 	"html/template" | 	"html/template" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"strings" | 	"strings" | ||||||
|  | 	"time" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func abortWithError(w http.ResponseWriter, msg string) { | func abortWithError(w http.ResponseWriter, msg string) { | ||||||
| @@ -144,9 +146,10 @@ func makeCookie(username string, remote string) (*http.Cookie, error) { | |||||||
| 	// expiresAt := time.Now().Add(time.Duration(cfg.SessionLifetime) * time.Second) | 	// expiresAt := time.Now().Add(time.Duration(cfg.SessionLifetime) * time.Second) | ||||||
| 	// Set the token in the session map, along with the session information | 	// Set the token in the session map, along with the session information | ||||||
| 	session := &models.Session{ | 	session := &models.Session{ | ||||||
| 		Username:    username, | 		Username:  username, | ||||||
| 		CookieToken: sessionToken, | 		TokenKey:  sessionToken, | ||||||
| 		Lifetime:    uint32(cfg.SessionLifetime / 60), | 		UpdatedAt: time.Now(), | ||||||
|  | 		Lifetime:  uint32(cfg.SessionLifetime / 60), | ||||||
| 	} | 	} | ||||||
| 	cookieName := "session_token" | 	cookieName := "session_token" | ||||||
| 	// hmac to protect cookies | 	// hmac to protect cookies | ||||||
| @@ -173,6 +176,9 @@ func makeCookie(username string, remote string) (*http.Cookie, error) { | |||||||
| 		log.Info("changing cookie domain", "domain", cookie.Domain) | 		log.Info("changing cookie domain", "domain", cookie.Domain) | ||||||
| 	} | 	} | ||||||
| 	// set ctx? | 	// set ctx? | ||||||
|  | 	if err := repo.SessionCreate(context.Background(), session); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
| 	// set user in session | 	// set user in session | ||||||
| 	if err := cacheSetSession(sessionToken, session); err != nil { | 	if err := cacheSetSession(sessionToken, session); err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
|   | |||||||
| @@ -48,7 +48,10 @@ func HandleHome(w http.ResponseWriter, r *http.Request) { | |||||||
| 		abortWithError(w, err.Error()) | 		abortWithError(w, err.Error()) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	fi, _ := getFullInfoByCtx(r.Context()) | 	fi, err := getFullInfoByCtx(r.Context()) | ||||||
|  | 	if err != nil { | ||||||
|  | 		log.Error("failed to fetch fi", "error", err) | ||||||
|  | 	} | ||||||
| 	if fi != nil && fi.Room != nil && fi.State != nil { | 	if fi != nil && fi.Room != nil && fi.State != nil { | ||||||
| 		fi.Room.UpdateCounter() | 		fi.Room.UpdateCounter() | ||||||
| 		if fi.State.Role == "mime" { | 		if fi.State.Role == "mime" { | ||||||
|   | |||||||
| @@ -61,12 +61,12 @@ func GetSession(next http.Handler) http.Handler { | |||||||
| 			next.ServeHTTP(w, r) | 			next.ServeHTTP(w, r) | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| 		userSession, err := cacheGetSession(sessionToken) | 		userSession, err := repo.SessionByToken(r.Context(), sessionToken) | ||||||
|  | 		// userSession, err := cacheGetSession(sessionToken) | ||||||
| 		// log.Debug("userSession from cache", "us", userSession) | 		// log.Debug("userSession from cache", "us", userSession) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			// msg := "auth failed; session does not exists" | 			msg := "auth failed; session does not exists" | ||||||
| 			// err = errors.New(msg) | 			log.Debug(msg, "error", err, "key", sessionToken) | ||||||
| 			// log.Debug(msg, "error", err) |  | ||||||
| 			next.ServeHTTP(w, r) | 			next.ServeHTTP(w, r) | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
|   | |||||||
| @@ -72,7 +72,7 @@ CREATE TABLE sessions( | |||||||
|     id INTEGER PRIMARY KEY AUTOINCREMENT, |     id INTEGER PRIMARY KEY AUTOINCREMENT, | ||||||
|     updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, |     updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||||||
|     lifetime INTEGER NOT NULL DEFAULT 3600, |     lifetime INTEGER NOT NULL DEFAULT 3600, | ||||||
|     cookie_token TEXT NOT NULL DEFAULT '', -- encoded value |     token_key TEXT NOT NULL DEFAULT '' UNIQUE, -- encoded value | ||||||
|     username TEXT NOT NULL, |     username TEXT NOT NULL, | ||||||
|     FOREIGN KEY (username) REFERENCES players(username) |     FOREIGN KEY (username) REFERENCES players(username) | ||||||
| ); | ); | ||||||
|   | |||||||
| @@ -6,19 +6,19 @@ import ( | |||||||
|  |  | ||||||
| // each session contains the username of the user and the time at which it expires | // each session contains the username of the user and the time at which it expires | ||||||
| type Session struct { | type Session struct { | ||||||
| 	ID uint32 | 	ID uint32 `db:"id"` | ||||||
| 	// CurrentRoom string | 	// CurrentRoom string | ||||||
| 	// Expiry      time.Time | 	// Expiry      time.Time | ||||||
| 	UpdatedAt   time.Time | 	UpdatedAt time.Time `db:"updated_at"` | ||||||
| 	Lifetime    uint32 // minutes | 	Lifetime  uint32    `db:"lifetime"` // minutes | ||||||
| 	CookieToken string | 	TokenKey  string    `db:"token_key"` | ||||||
| 	Username    string // username is playerid | 	Username  string    `db:"username"` // username is playerid | ||||||
| } | } | ||||||
|  |  | ||||||
| // we'll use this method later to determine if the session has expired | // we'll use this method later to determine if the session has expired | ||||||
| func (s Session) IsExpired() bool { | func (s Session) IsExpired() bool { | ||||||
| 	return time.Now().After(s.UpdatedAt.Add(time.Minute * time.Duration(s.Lifetime))) | 	// return time.Now().After(s.UpdatedAt.Add(time.Minute * time.Duration(s.Lifetime))) | ||||||
| 	// return s.Expiry.Before(time.Now()) | 	return false | ||||||
| } | } | ||||||
|  |  | ||||||
| // func ListUsernames(ss map[string]*Session) []string { | // func ListUsernames(ss map[string]*Session) []string { | ||||||
|   | |||||||
| @@ -19,7 +19,7 @@ func (p *RepoProvider) SessionByToken(ctx context.Context, token string) (*model | |||||||
| 	db := getDB(ctx, p.DB) | 	db := getDB(ctx, p.DB) | ||||||
| 	session := &models.Session{} | 	session := &models.Session{} | ||||||
| 	// The lifetime in the DB is in seconds, but in the model it is in minutes. | 	// The lifetime in the DB is in seconds, but in the model it is in minutes. | ||||||
| 	err := sqlx.GetContext(ctx, db, session, `SELECT id, updated_at, lifetime / 60 as lifetime, cookie_token, username FROM sessions WHERE cookie_token = ?`, token) | 	err := sqlx.GetContext(ctx, db, session, `SELECT id, updated_at, lifetime / 60 as lifetime, token_key, username FROM sessions WHERE token_key = ? LIMIT 1;`, token) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| @@ -29,21 +29,21 @@ func (p *RepoProvider) SessionByToken(ctx context.Context, token string) (*model | |||||||
| func (p *RepoProvider) SessionCreate(ctx context.Context, session *models.Session) error { | func (p *RepoProvider) SessionCreate(ctx context.Context, session *models.Session) error { | ||||||
| 	db := getDB(ctx, p.DB) | 	db := getDB(ctx, p.DB) | ||||||
| 	// The lifetime in the model is in minutes, but in the DB it is in seconds. | 	// The lifetime in the model is in minutes, but in the DB it is in seconds. | ||||||
| 	_, err := db.ExecContext(ctx, `INSERT INTO sessions (updated_at, lifetime, cookie_token, username) VALUES (?, ?, ?, ?)`, | 	_, err := db.ExecContext(ctx, `INSERT INTO sessions (updated_at, lifetime, token_key, username) VALUES (?, ?, ?, ?) ON CONFLICT (token_key) DO UPDATE SET updated_at=CURRENT_TIMESTAMP, lifetime=excluded.lifetime;`, | ||||||
| 		time.Now(), session.Lifetime*60, session.CookieToken, session.Username) | 		time.Now(), session.Lifetime*60, session.TokenKey, session.Username) | ||||||
| 	return err | 	return err | ||||||
| } | } | ||||||
|  |  | ||||||
| func (p *RepoProvider) SessionUpdate(ctx context.Context, session *models.Session) error { | func (p *RepoProvider) SessionUpdate(ctx context.Context, session *models.Session) error { | ||||||
| 	db := getDB(ctx, p.DB) | 	db := getDB(ctx, p.DB) | ||||||
| 	// The lifetime in the model is in minutes, but in the DB it is in seconds. | 	// The lifetime in the model is in minutes, but in the DB it is in seconds. | ||||||
| 	_, err := db.ExecContext(ctx, `UPDATE sessions SET updated_at = ?, lifetime = ? WHERE cookie_token = ?`, | 	_, err := db.ExecContext(ctx, `UPDATE sessions SET updated_at = ?, lifetime = ? WHERE token_key = ?`, | ||||||
| 		time.Now(), session.Lifetime*60, session.CookieToken) | 		time.Now(), session.Lifetime*60, session.TokenKey) | ||||||
| 	return err | 	return err | ||||||
| } | } | ||||||
|  |  | ||||||
| func (p *RepoProvider) SessionDelete(ctx context.Context, token string) error { | func (p *RepoProvider) SessionDelete(ctx context.Context, token string) error { | ||||||
| 	db := getDB(ctx, p.DB) | 	db := getDB(ctx, p.DB) | ||||||
| 	_, err := db.ExecContext(ctx, `DELETE FROM sessions WHERE cookie_token = ?`, token) | 	_, err := db.ExecContext(ctx, `DELETE FROM sessions WHERE token_key = ?`, token) | ||||||
| 	return err | 	return err | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								todos.md
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								todos.md
									
									
									
									
									
								
							| @@ -30,6 +30,7 @@ | |||||||
| - clear indication that model (llm) is thinking / answered; | - clear indication that model (llm) is thinking / answered; | ||||||
| - possibly turn markings into parts of names of users (first three letters?); | - possibly turn markings into parts of names of users (first three letters?); | ||||||
| - at game creation list languages and support them at backend; | - at game creation list languages and support them at backend; | ||||||
|  | - sql ping goroutine with reconnect on fail; | ||||||
|  |  | ||||||
| #### sse points | #### sse points | ||||||
| - clue sse update; | - clue sse update; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Grail Finder
					Grail Finder