Skip to content

Share only the evidence usage sharing accepts unless asked for all - #35

Merged
jwrosewell merged 4 commits into
rcfrom
fix/usage-sharing-defaults
Nov 7, 2026
Merged

jwrosewell merged 4 commits into
rcfrom
fix/usage-sharing-defaults

Conversation

@jwrosewell

@jwrosewell jwrosewell commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor

This is the fix for #34, which can close once it reaches main. Session tracking follows .NET, which is the model for usage sharing.

Problem

  1. With no options, which is how the on-premise device detection builder adds it, the usage sharing element sent every piece of evidence to 51Degrees, including every cookie, every form field and every query string parameter. ShareUsageEvidenceKeyFilter switched on sharing everything whenever no cookie and no lists were given.
  2. The filter read this.includeSession and nothing set it, so filterEvidenceKey('cookie.sessionid') gave undefined. The session cookie named by the cookie option was never kept for the tracker, and ShareUsage stored the option as trackingCookie and never read it again.
  3. Node had only cookie, where .NET has two settings. SetTrackSession, false by default (Constants.cs lines 88 to 95), decides whether the session cookie is used to tell sessions apart, and SetAspSessionCookieName only names the cookie and "has no effect if TrackSession is false". The first version of this pull request made naming cookie turn tracking on.

Change

The filter follows the accepted evidence section and the configuration options of the usage sharing specification, and the .NET filter.

  1. ShareUsage takes shareAll, false by default, as the specification's "Share all Evidence" is. Only shareAll: true shares everything.
  2. Otherwise headers are shared unless blocked, cookies and session values only when their names start 51d_, query string and form parameters only when they start 51d_ or are on queryWhitelist, and any other evidence. queryWhitelist: null still shares every parameter.
  3. id.email, id.salt, request-query and request-path are never shared, in any mode, matched without regard to case as the whole key or after a ., as in .NET's EvidenceKeyFilterShareUsage.
  4. A key is split at its first ., so query.valid.email is checked as valid.email.
  5. The header and parameter lists are matched without regard to case.
  6. The filter takes includeSession. ShareUsage builds three filters, as .NET's ShareUsageBase.cs lines 636 to 666 does. The filter for the data sent leaves the session cookie out, and the new ShareUsageTrackerEvidenceKeyFilter leaves out query.session-id and query.sequence, which differ on every request and made every request look new to the tracker. The session id and sequence are added to the parameters kept, as .NET does, because the usage data carries them separately.
  7. ShareUsage takes trackSession, false by default, as .NET's SetTrackSession is. Only when it is true do the pipeline's filter and the tracker's filter include the session cookie named by cookie. A repeat from a new session is then shared again, while a repeat within the same session is not. cookie only names the session cookie, and has no effect unless trackSession is true. The session cookie is not sent unless shareAll is true.
  8. The type declarations under types/ are updated to match. shareUsage.d.ts and shareUsageTrackerEvidenceKeyFilter.d.ts are now exactly what tsc writes from the sources.
  9. The usage sharing example's 51d.json, which the example says lists all the options, now lists trackSession and shareAll with their defaults.

For review

  1. The Cookie header is no longer shared unless shareAll is set. The specification said the default block list "SHOULD include the cookies HTTP header". HTTP has no header called Cookies, and the request header that carries cookies is Cookie (RFC 6265 section 5.4). Evidence.addFromRequest() adds every request header, so header.cookie carries every cookie, and without this the session and sign-in cookies the cookie rule leaves out would still be sent. The 51d_ cookies are still shared, as their own cookie. entries. specifications#89, now merged into rc, put the Cookie header in the specification, and .NET now blocks it too (51degrees-dotnet#81).
  2. cookie keeps its default, which is no name. .NET's default, asp.net_sessionid, is the ASP.NET session cookie, and Java's, JSESSIONID, is the servlet one. Node has no common session cookie name. For example, express-session uses connect.sid unless told otherwise. So no name would be right by default, and trackSession: true needs cookie set to have any effect, as the JSDoc says.
  3. The pipeline keeps the session cookie only when tracking is on. .NET's filter for the evidence the element accepts includes the session cookie whether or not tracking is on (ShareUsageBase.cs lines 646 to 648), though it never sends it and only compares it when tracking is on. Here Evidence.add() keeps it only when tracking is on, so that cookie has no effect at all otherwise. What is sent is the same.
  4. shareAll overrides session tracking, as in .NET. With shareAll: true, every cookie is shared and compared, the session cookie included, whatever trackSession says. .NET's share all filters do the same (ShareUsageBase.cs lines 659 to 666).
  5. trackingCookie is still set from cookie and still never read. It is left in place because it is part of the declared type.
  6. specifications#89, now merged into rc, added the four never-shared keys to the specification. specifications#97 adds the session tracking options.

Tests

  • tests/shareUsageEvidenceKeyFilter.test.js is new. It ports the .NET filter tests and adds the cases the issue lists: query.id.email, header.id.email, cookie.a.b, session.org.example.attribute, query.valid.email, the session cookie, and lists in mixed case.
  • tests/shareUsage.test.js sends through the local receiver and checks what reaches it: the default settings, the never-shared keys, shareAll, a parameter name with a dot, and a repeat that differs only in its session id and sequence.
  • Three tests in tests/shareUsage.test.js cover session tracking. share usage - session cookie turns tracking on and checks the session cookie is kept but not sent. share usage - session cookie without session tracking names the cookie without turning tracking on, and checks that tracking is off by default, the cookie is not kept, and the same evidence from a second session is not sent again. share usage - session tracking turns tracking on and checks that the same evidence is sent again for a new session but not for a repeat in the same session, and that the cookie is never sent.

Checks

  • The filter tests alone, at 9715734, failed on Node 20 and 24 for the reasons above. All 15 new tests failed, among them filterEvidenceKey('cookie.sessionid') giving undefined, the session cookie and email address reaching the receiver, and 2 records where 1 was expected for the repeat. All 14 existing tests passed, and ESLint passed (run 42195395204, first attempt).
  • With the filter fix, at a3b7d5e, all 29 tests passed on both versions and ESLint passed (run 42195395204, second attempt), and the full build passed on all 8 configurations (run 42196176658).
  • The session tracking tests alone, at c281b33, failed on Node 20 and 24. share usage - session cookie without session tracking received 2 records where 1 was expected, because naming the cookie turned tracking on. The other two session tests passed, because they pin what tracking does when it is on, which naming the cookie already did. The other 30 tests, ESLint and the usage sharing example passed (run 42320919381).
  • With session tracking, at 325a510, all 31 tests passed on both versions, ESLint passed, the usage sharing example ran from its configuration with the two new options, and the type declarations matched what tsc writes (run 42321441878).
  • The full build of this pull request, at 325a510, passed on all 8 configurations, Node 22 and 24 on Ubuntu, Ubuntu ARM, macOS and Windows (run 42322024856).

Found, not changed

  • The specification calls the repeat evidence interval a sliding window, reset on every match. Node stores a new time only when it shares a repeat again, and .NET never updates the time once stored. specifications#97 records the difference for a decision.

Release note

Usage sharing now shares only the evidence the specification accepts unless shareAll: true is given, and never shares an email address, its salt, the query string or the path. A new trackSession option, false by default, uses the session cookie named by cookie to tell sessions apart, as .NET's SetTrackSession does.

Usage sharing should share what the specification's accepted evidence
section allows unless the caller asks to share everything: headers other
than Cookie, cookies, session values and query string parameters starting
51D_, the parameters the caller names, and any other evidence. The email
address, the salt for hashed email identifiers, the query string and the
path are never shared. Naming the session cookie keeps it in evidence but
never sends it, and a repeat that differs only in its session id and
sequence is not shared again.

These tests fail on rc, where every key is shared by default and the
session cookie is never kept.
The usage sharing filter shared every piece of evidence whenever no
cookie, parameter list or header list was given, which is how the
on-premise builder adds it, so every cookie, form field and query string
parameter was sent. Sharing everything is now only done when shareAll is
true, which defaults to false, as the specification's share all evidence
option does.

The filter now also
- splits a key at its first dot, so a name containing a dot is matched
  whole,
- never shares id.email, id.salt, request-query or request-path, in any
  mode, as .NET does,
- does not share the Cookie header, which carries every cookie, unless
  all evidence is shared,
- matches the header and parameter lists without regard to case,
- takes includeSession, which it read but nothing set, so the session
  cookie named by the cookie option never reached the tracker.

ShareUsage builds three filters, as .NET does. The pipeline keeps the
named session cookie, the data sent never includes it, and the tracker
leaves out the session id and sequence number, which made every request
look new. The session id and sequence number stay in evidence because the
usage data carries them separately.
.NET keeps two settings apart. SetTrackSession, false by default,
decides whether the session cookie is used to tell sessions apart, and
SetAspSessionCookieName only names the cookie, with no effect unless
tracking is on. Here naming the cookie turned tracking on.

The session cookie test now turns tracking on with trackSession. Two
new tests check that the cookie alone has no effect, and that with
tracking on a repeat is shared again for a new session but not within
the same session.
ShareUsage takes trackSession, false by default, as .NET's
SetTrackSession is. The pipeline's filter and the tracker's filter
include the session cookie named by cookie only when it is true, so
the cookie has no effect otherwise, as .NET's SetAspSessionCookieName
has none. The data sent still leaves the session cookie out unless
shareAll is true.

The type declarations are updated to match, and the declaration for
ShareUsageTrackerEvidenceKeyFilter is now the one tsc writes. The usage
sharing example's configuration, which lists every option, now lists
trackSession and shareAll with their defaults.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant