Documentation
¶
Index ¶
- Constants
- func Hash(id uint64) string
- type Identifier
- type JSONStore
- type Middleware
- type Options
- type Profile
- func (p *Profile) CalcIdentifier(routes *RouteTable) uint64
- func (p *Profile) HasVisited(route string) bool
- func (p *Profile) Identifier() uint64
- func (p *Profile) IsReading() bool
- func (p *Profile) SetStorageSize(size int)
- func (p *Profile) StorageSize() int
- func (p *Profile) Vector() []string
- func (p *Profile) VectorContains(route string) bool
- func (p *Profile) VisitRoute(route string)
- func (p *Profile) VisitedCount() int
- type ProfileStore
- type RouteTable
- func (t *RouteTable) HasRoute(route string) bool
- func (t *RouteTable) Identifier(visited map[string]bool, size int) uint64
- func (t *RouteTable) IndexByRoute(route string) int
- func (t *RouteTable) Len() int
- func (t *RouteTable) NextRoute(route string) string
- func (t *RouteTable) RouteByIndex(i int) string
- func (t *RouteTable) Vector(identifier uint32) []string
- type Store
- type WriteTokenSet
Constants ¶
const DefaultProbeBits = 32
ProbeBits controls how many probe routes are generated per deployment; 2^ProbeBits-1 unique identifiers are possible. 32 is a sane default and matches a native machine word on most platforms.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Identifier ¶
type Identifier struct {
// ID is the raw decoded value. Only meaningful when Identified is true.
ID uint64
// Hash is a short, human-readable rendering of ID.
Hash string
// Identified reports whether the visitor's browser could be fingerprinted
// via the cache probe. False means identification was attempted but the
// browser didn't yield a usable signal (e.g. cache isolation, private
// browsing, or repeated failures past MaxAttempts).
Identified bool
}
Identifier is the result of a successful (or exhausted) identification pass.
func FromContext ¶
func FromContext(ctx context.Context) (Identifier, bool)
FromContext returns the Identifier attached to the request context by the middleware, if any. It is absent for non-GET requests and for requests served before the middleware has finished a probe pass.
type JSONStore ¶
type JSONStore struct {
// contains filtered or unexported fields
}
JSONStore is the default Store: it persists state as a small JSON file.
func NewJSONStore ¶
NewJSONStore opens (or creates) the JSON file at path as a Store.
type Middleware ¶
type Middleware struct {
// contains filtered or unexported fields
}
Middleware identifies visitors via cache probing and exposes the result through FromContext.
func New ¶
func New(opts Options) *Middleware
New builds a Middleware. It reads (or creates) its persistent state immediately, via Options.Store if set, or a JSONStore at Options.StoragePath otherwise.
func (*Middleware) Wrap ¶
func (m *Middleware) Wrap(next http.Handler) http.Handler
Wrap returns an http.Handler that identifies visitors before delegating to next. GET requests without a resolved identifier are sent to the background probe page and, once identification finishes (or gives up), navigated back to the URL they originally requested. Non-GET requests are passed through with no Identifier in context.
type Options ¶
type Options struct {
// MountPrefix is the path prefix under which the middleware serves its
// internal probe routes. Must not collide with routes in the wrapped
// application. Defaults to "/_cachefp".
MountPrefix string
// CookieName is where the resolved identifier is stored once known.
// Defaults to "cfpid".
CookieName string
// CookieMaxAge controls how long an established identifier cookie lasts.
// Defaults to 1 year.
CookieMaxAge time.Duration
// Store holds the small amount of persistent state (the per-deployment
// cache ID and next write index). Defaults to a JSONStore at
// StoragePath; set Store directly to use a different backend (a
// database row, a KV store, etc.) instead of a JSON file.
Store Store
// StoragePath is where the default JSONStore keeps its file. Ignored if
// Store is set. Defaults to "cachefp_data.json".
StoragePath string
// ProbeBits sets the number of probe routes; see DefaultProbeBits.
ProbeBits int
// MaxAttempts caps how many write/read passes are made before giving up
// on a visitor and marking them non-identifiable, to avoid looping
// forever for browsers that don't exhibit the caching behavior this
// technique relies on. Defaults to 2.
MaxAttempts int
// Logf, if set, receives diagnostic log lines. Defaults to log.Printf.
Logf func(format string, args ...any)
}
Options configures a Middleware.
type Profile ¶
type Profile struct {
// contains filtered or unexported fields
}
Profile tracks one visitor across the write (encode) or read (decode) flow.
func (*Profile) CalcIdentifier ¶
func (p *Profile) CalcIdentifier(routes *RouteTable) uint64
CalcIdentifier decodes the identifier from visited routes (read mode) and caches it.
func (*Profile) HasVisited ¶
func (*Profile) Identifier ¶
func (*Profile) SetStorageSize ¶
func (*Profile) StorageSize ¶
func (*Profile) VectorContains ¶
func (*Profile) VisitRoute ¶
func (*Profile) VisitedCount ¶
type ProfileStore ¶
type ProfileStore struct {
// contains filtered or unexported fields
}
ProfileStore is a concurrency-safe registry of in-flight profiles, keyed by uid.
func NewProfileStore ¶
func NewProfileStore() *ProfileStore
func (*ProfileStore) Delete ¶
func (s *ProfileStore) Delete(uid string)
func (*ProfileStore) FromRead ¶
func (s *ProfileStore) FromRead(uid string) *Profile
FromRead creates a profile with no known identifier yet (read mode). Returns nil if uid is already registered.
func (*ProfileStore) FromWrite ¶
func (s *ProfileStore) FromWrite(uid string, identifier uint64, routes *RouteTable) *Profile
FromWrite creates a profile bound to a known identifier (write mode). Returns nil if uid is already registered.
func (*ProfileStore) Get ¶
func (s *ProfileStore) Get(uid string) *Profile
func (*ProfileStore) Has ¶
func (s *ProfileStore) Has(uid string) bool
type RouteTable ¶
type RouteTable struct {
// contains filtered or unexported fields
}
RouteTable is the ordered, fixed set of favicon-cache probe routes for one cache identifier, plus the bit<->route conversions used to encode/decode a visitor's cache profile.
func NewRouteTable ¶
func NewRouteTable(cacheID string, n int) *RouteTable
func (*RouteTable) HasRoute ¶
func (t *RouteTable) HasRoute(route string) bool
func (*RouteTable) Identifier ¶
func (t *RouteTable) Identifier(visited map[string]bool, size int) uint64
Identifier reconstructs the numeric identifier from a set of visited routes, only considering the first `size` routes in the table.
func (*RouteTable) IndexByRoute ¶
func (t *RouteTable) IndexByRoute(route string) int
func (*RouteTable) Len ¶
func (t *RouteTable) Len() int
func (*RouteTable) NextRoute ¶
func (t *RouteTable) NextRoute(route string) string
NextRoute returns the route after `route`, or "" once the table is exhausted.
func (*RouteTable) RouteByIndex ¶
func (t *RouteTable) RouteByIndex(i int) string
func (*RouteTable) Vector ¶
func (t *RouteTable) Vector(identifier uint32) []string
Vector returns the routes whose bit is set in identifier (bit i <-> routes[i]).
type Store ¶
Store persists the middleware's small amount of durable state: the per-deployment cache ID and the next write index. Both must survive process restarts, or previously-cached probe URLs in visitors' browsers stop matching anything the server expects.
Get/Set values are limited to what encoding/json's default decoding produces (so implementations backed by JSON, like JSONStore, round-trip cleanly): strings and float64 for the numeric index. A custom Store may use a real integer type internally as long as GetUint64 converts it.
type WriteTokenSet ¶
type WriteTokenSet struct {
// contains filtered or unexported fields
}
WriteTokenSet is a self-expiring set used to authorize one-shot /write/:mid requests.
func NewWriteTokenSet ¶
func NewWriteTokenSet() *WriteTokenSet
func (*WriteTokenSet) Delete ¶
func (s *WriteTokenSet) Delete(token string)
func (*WriteTokenSet) Generate ¶
func (s *WriteTokenSet) Generate() string
func (*WriteTokenSet) Has ¶
func (s *WriteTokenSet) Has(token string) bool