mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-12 22:14:37 +00:00
111 lines
3.4 KiB
Go
111 lines
3.4 KiB
Go
package store
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
var (
|
|
ErrBrowserCookieEncryptionRequired = errors.New("browser cookie encryption key required")
|
|
ErrBrowserCookieTenantRequired = errors.New("browser cookie tenant_id required")
|
|
ErrBrowserCookieUserRequired = errors.New("browser cookie user_id required")
|
|
ErrBrowserCookieAgentRequired = errors.New("browser cookie agent_id required")
|
|
ErrBrowserCookieDomainRequired = errors.New("browser cookie domain required")
|
|
ErrBrowserCookieNameRequired = errors.New("browser cookie name required")
|
|
ErrBrowserCookiePathRequired = errors.New("browser cookie path required")
|
|
)
|
|
|
|
// BrowserCookieScope is the tenant/user/agent boundary for synced browser cookies.
|
|
type BrowserCookieScope struct {
|
|
TenantID uuid.UUID
|
|
UserID string
|
|
AgentID string
|
|
}
|
|
|
|
// BrowserCookie stores one selected browser cookie. Value is plaintext only at API
|
|
// and browser-application boundaries; stores encrypt it at rest.
|
|
type BrowserCookie struct {
|
|
ID uuid.UUID `json:"id" db:"id"`
|
|
TenantID uuid.UUID `json:"tenant_id" db:"tenant_id"`
|
|
UserID string `json:"user_id" db:"user_id"`
|
|
AgentID string `json:"agent_id" db:"agent_id"`
|
|
Domain string `json:"domain" db:"domain"`
|
|
Name string `json:"name" db:"name"`
|
|
Path string `json:"path" db:"path"`
|
|
Value string `json:"-" db:"-"`
|
|
Secure bool `json:"secure" db:"secure"`
|
|
HTTPOnly bool `json:"http_only" db:"http_only"`
|
|
SameSite string `json:"same_site,omitempty" db:"same_site"`
|
|
ExpiresAt *time.Time `json:"expires_at,omitempty" db:"expires_at"`
|
|
Source string `json:"source,omitempty" db:"source"`
|
|
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
|
|
}
|
|
|
|
type BrowserCookieFilter struct {
|
|
Domain string
|
|
Name string
|
|
Path string
|
|
}
|
|
|
|
type BrowserCookieStore interface {
|
|
Upsert(ctx context.Context, scope BrowserCookieScope, cookies []BrowserCookie) (int, error)
|
|
List(ctx context.Context, scope BrowserCookieScope, filter BrowserCookieFilter) ([]BrowserCookie, error)
|
|
Delete(ctx context.Context, scope BrowserCookieScope, filter BrowserCookieFilter) (int, error)
|
|
}
|
|
|
|
func BrowserCookieScopeFromContext(ctx context.Context, agentID string) BrowserCookieScope {
|
|
tid := TenantIDFromContext(ctx)
|
|
if tid == uuid.Nil {
|
|
tid = MasterTenantID
|
|
}
|
|
return BrowserCookieScope{
|
|
TenantID: tid,
|
|
UserID: CredentialUserIDFromContext(ctx),
|
|
AgentID: strings.TrimSpace(agentID),
|
|
}
|
|
}
|
|
|
|
func (s BrowserCookieScope) Validate() error {
|
|
switch {
|
|
case s.TenantID == uuid.Nil:
|
|
return ErrBrowserCookieTenantRequired
|
|
case strings.TrimSpace(s.UserID) == "":
|
|
return ErrBrowserCookieUserRequired
|
|
case strings.TrimSpace(s.AgentID) == "":
|
|
return ErrBrowserCookieAgentRequired
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func NormalizeBrowserCookie(c BrowserCookie) BrowserCookie {
|
|
c.Domain = strings.ToLower(strings.TrimSpace(c.Domain))
|
|
c.Name = strings.TrimSpace(c.Name)
|
|
c.Path = strings.TrimSpace(c.Path)
|
|
c.SameSite = strings.TrimSpace(c.SameSite)
|
|
c.Source = strings.TrimSpace(c.Source)
|
|
if c.Path == "" {
|
|
c.Path = "/"
|
|
}
|
|
return c
|
|
}
|
|
|
|
func ValidateBrowserCookie(c BrowserCookie) error {
|
|
c = NormalizeBrowserCookie(c)
|
|
switch {
|
|
case c.Domain == "":
|
|
return ErrBrowserCookieDomainRequired
|
|
case c.Name == "":
|
|
return ErrBrowserCookieNameRequired
|
|
case c.Path == "":
|
|
return ErrBrowserCookiePathRequired
|
|
default:
|
|
return nil
|
|
}
|
|
}
|