mirror of
https://github.com/bitechdev/ResolveSpec.git
synced 2026-04-09 17:36:23 +00:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f10bb0827e | ||
|
|
22a4ab345a |
@@ -168,16 +168,17 @@ func SanitizeWhereClause(where string, tableName string, options ...*RequestOpti
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Build a set of allowed table prefixes (main table + preloaded relations)
|
// Build a set of allowed table prefixes (main table + preloaded relations)
|
||||||
|
// Keys are stored lowercase for case-insensitive matching
|
||||||
allowedPrefixes := make(map[string]bool)
|
allowedPrefixes := make(map[string]bool)
|
||||||
if tableName != "" {
|
if tableName != "" {
|
||||||
allowedPrefixes[tableName] = true
|
allowedPrefixes[strings.ToLower(tableName)] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add preload relation names as allowed prefixes
|
// Add preload relation names as allowed prefixes
|
||||||
if len(options) > 0 && options[0] != nil {
|
if len(options) > 0 && options[0] != nil {
|
||||||
for pi := range options[0].Preload {
|
for pi := range options[0].Preload {
|
||||||
if options[0].Preload[pi].Relation != "" {
|
if options[0].Preload[pi].Relation != "" {
|
||||||
allowedPrefixes[options[0].Preload[pi].Relation] = true
|
allowedPrefixes[strings.ToLower(options[0].Preload[pi].Relation)] = true
|
||||||
logger.Debug("Added preload relation '%s' as allowed table prefix", options[0].Preload[pi].Relation)
|
logger.Debug("Added preload relation '%s' as allowed table prefix", options[0].Preload[pi].Relation)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -185,7 +186,7 @@ func SanitizeWhereClause(where string, tableName string, options ...*RequestOpti
|
|||||||
// Add join aliases as allowed prefixes
|
// Add join aliases as allowed prefixes
|
||||||
for _, alias := range options[0].JoinAliases {
|
for _, alias := range options[0].JoinAliases {
|
||||||
if alias != "" {
|
if alias != "" {
|
||||||
allowedPrefixes[alias] = true
|
allowedPrefixes[strings.ToLower(alias)] = true
|
||||||
logger.Debug("Added join alias '%s' as allowed table prefix", alias)
|
logger.Debug("Added join alias '%s' as allowed table prefix", alias)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -217,8 +218,8 @@ func SanitizeWhereClause(where string, tableName string, options ...*RequestOpti
|
|||||||
currentPrefix, columnName := extractTableAndColumn(condToCheck)
|
currentPrefix, columnName := extractTableAndColumn(condToCheck)
|
||||||
|
|
||||||
if currentPrefix != "" && columnName != "" {
|
if currentPrefix != "" && columnName != "" {
|
||||||
// Check if the prefix is allowed (main table or preload relation)
|
// Check if the prefix is allowed (main table or preload relation) - case-insensitive
|
||||||
if !allowedPrefixes[currentPrefix] {
|
if !allowedPrefixes[strings.ToLower(currentPrefix)] {
|
||||||
// Prefix is not in the allowed list - only fix if it's a valid column in the main table
|
// Prefix is not in the allowed list - only fix if it's a valid column in the main table
|
||||||
if validColumns == nil || isValidColumn(columnName, validColumns) {
|
if validColumns == nil || isValidColumn(columnName, validColumns) {
|
||||||
// Replace the incorrect prefix with the correct main table name
|
// Replace the incorrect prefix with the correct main table name
|
||||||
|
|||||||
@@ -456,6 +456,125 @@ func GetUserMeta(ctx context.Context) (map[string]any, bool) {
|
|||||||
return meta, ok
|
return meta, ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SessionCookieOptions configures the session cookie set by SetSessionCookie.
|
||||||
|
// All fields are optional; sensible secure defaults are applied when omitted.
|
||||||
|
type SessionCookieOptions struct {
|
||||||
|
// Name is the cookie name. Defaults to "session_token".
|
||||||
|
Name string
|
||||||
|
// Path is the cookie path. Defaults to "/".
|
||||||
|
Path string
|
||||||
|
// Domain restricts the cookie to a specific domain. Empty means current host.
|
||||||
|
Domain string
|
||||||
|
// Secure sets the Secure flag. Defaults to true.
|
||||||
|
// Set to false only in local development over HTTP.
|
||||||
|
Secure *bool
|
||||||
|
// SameSite sets the SameSite policy. Defaults to http.SameSiteLaxMode.
|
||||||
|
SameSite http.SameSite
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o SessionCookieOptions) name() string {
|
||||||
|
if o.Name != "" {
|
||||||
|
return o.Name
|
||||||
|
}
|
||||||
|
return "session_token"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o SessionCookieOptions) path() string {
|
||||||
|
if o.Path != "" {
|
||||||
|
return o.Path
|
||||||
|
}
|
||||||
|
return "/"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o SessionCookieOptions) secure() bool {
|
||||||
|
if o.Secure != nil {
|
||||||
|
return *o.Secure
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o SessionCookieOptions) sameSite() http.SameSite {
|
||||||
|
if o.SameSite != 0 {
|
||||||
|
return o.SameSite
|
||||||
|
}
|
||||||
|
return http.SameSiteLaxMode
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetSessionCookie writes the session_token cookie to the response after a successful login.
|
||||||
|
// Call this immediately after a successful Authenticator.Login() call.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// resp, err := auth.Login(r.Context(), req)
|
||||||
|
// if err != nil { ... }
|
||||||
|
// security.SetSessionCookie(w, resp)
|
||||||
|
// json.NewEncoder(w).Encode(resp)
|
||||||
|
func SetSessionCookie(w http.ResponseWriter, loginResp *LoginResponse, opts ...SessionCookieOptions) {
|
||||||
|
var o SessionCookieOptions
|
||||||
|
if len(opts) > 0 {
|
||||||
|
o = opts[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
maxAge := 0
|
||||||
|
if loginResp.ExpiresIn > 0 {
|
||||||
|
maxAge = int(loginResp.ExpiresIn)
|
||||||
|
}
|
||||||
|
|
||||||
|
http.SetCookie(w, &http.Cookie{
|
||||||
|
Name: o.name(),
|
||||||
|
Value: loginResp.Token,
|
||||||
|
Path: o.path(),
|
||||||
|
Domain: o.Domain,
|
||||||
|
MaxAge: maxAge,
|
||||||
|
HttpOnly: true,
|
||||||
|
Secure: o.secure(),
|
||||||
|
SameSite: o.sameSite(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSessionCookie returns the session token value from the request cookie, or empty string if not present.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// token := security.GetSessionCookie(r)
|
||||||
|
func GetSessionCookie(r *http.Request, opts ...SessionCookieOptions) string {
|
||||||
|
var o SessionCookieOptions
|
||||||
|
if len(opts) > 0 {
|
||||||
|
o = opts[0]
|
||||||
|
}
|
||||||
|
cookie, err := r.Cookie(o.name())
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return cookie.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClearSessionCookie expires the session_token cookie, effectively logging the user out on the browser side.
|
||||||
|
// Call this after a successful Authenticator.Logout() call.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// err := auth.Logout(r.Context(), req)
|
||||||
|
// if err != nil { ... }
|
||||||
|
// security.ClearSessionCookie(w)
|
||||||
|
func ClearSessionCookie(w http.ResponseWriter, opts ...SessionCookieOptions) {
|
||||||
|
var o SessionCookieOptions
|
||||||
|
if len(opts) > 0 {
|
||||||
|
o = opts[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
http.SetCookie(w, &http.Cookie{
|
||||||
|
Name: o.name(),
|
||||||
|
Value: "",
|
||||||
|
Path: o.path(),
|
||||||
|
Domain: o.Domain,
|
||||||
|
MaxAge: -1,
|
||||||
|
HttpOnly: true,
|
||||||
|
Secure: o.secure(),
|
||||||
|
SameSite: o.sameSite(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// GetModelRulesFromContext extracts ModelRules stored by NewModelAuthMiddleware
|
// GetModelRulesFromContext extracts ModelRules stored by NewModelAuthMiddleware
|
||||||
func GetModelRulesFromContext(ctx context.Context) (modelregistry.ModelRules, bool) {
|
func GetModelRulesFromContext(ctx context.Context) (modelregistry.ModelRules, bool) {
|
||||||
rules, ok := ctx.Value(ModelRulesKey).(modelregistry.ModelRules)
|
rules, ok := ctx.Value(ModelRulesKey).(modelregistry.ModelRules)
|
||||||
|
|||||||
@@ -222,9 +222,8 @@ func (a *DatabaseAuthenticator) Authenticate(r *http.Request) (*UserContext, err
|
|||||||
|
|
||||||
if sessionToken == "" {
|
if sessionToken == "" {
|
||||||
// Try cookie
|
// Try cookie
|
||||||
cookie, err := r.Cookie("session_token")
|
if token := GetSessionCookie(r); token != "" {
|
||||||
if err == nil {
|
tokens = []string{token}
|
||||||
tokens = []string{cookie.Value}
|
|
||||||
reference = "cookie"
|
reference = "cookie"
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user