mbuzz 0.7.2 → 0.7.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0d8514076473bbc4fa543510e84789f8cb91ccc99e916b3cef4f4928aaf6baf5
4
- data.tar.gz: 159074f0dbac29eb6b721bab4288ce976e4e4361ba503caffc36f37e79cf315e
3
+ metadata.gz: 717fff0f77150fb5f0a2ddcd60e59aaccaacdddbe41acd88ec7b953b568ec448
4
+ data.tar.gz: caedfee3a6e6ced3dcfadcfcce5b80a9f13679b73710f0933b6c2d8573c2accb
5
5
  SHA512:
6
- metadata.gz: 3d515f639e577a68d9daa8afe13de92dec0a5556cfad2e335ea482f7db0240ff996dd1fb6bbf3388e7f632cb8300e439028091cf1c551627c9be1c22e73ca666
7
- data.tar.gz: 9fbe4999f2ce0855d83847d61b4684f30217c01c9074df4cced51e4083167cf3ca24e0e5223f2e57fd859aab6d88f60a68a0adc3074bd0a7f4356c0f9d3e5116
6
+ metadata.gz: ce5da1805916ac523dc3d9a40e8b3126ee8f7b1d95cc3fe042d6e800e796e38227f117edd9acb72e1ec4e357cd83d378fe87b3f87eb063c2857f267ae2508c56
7
+ data.tar.gz: 190f2ddbf15dbc17cde637ee4f8ed4d00a8b06d47f0d16fce9b54e96e67e7e8191359f57cc3a5e218c9028ccac072e14e0035a1c1cc0f5c9a4e95b3c14b73c41
data/CHANGELOG.md CHANGED
@@ -5,6 +5,26 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.7.3] - 2026-02-02
9
+
10
+ ### Breaking Changes
11
+
12
+ - **Session cookie removed** — `_mbuzz_sid` cookie is no longer set or read. Sessions are fully server-side.
13
+ - **`SESSION_COOKIE_NAME` and `SESSION_COOKIE_MAX_AGE` constants removed** from `Mbuzz` module.
14
+
15
+ ### Added
16
+
17
+ - **Navigation-aware session creation** — middleware now gates `POST /sessions` on real page navigations using browser-enforced `Sec-Fetch-*` headers (whitelist), with a framework-specific blacklist fallback for older browsers and bots.
18
+ - Turbo Frame, htmx, Unpoly, and XHR sub-requests no longer create spurious sessions.
19
+ - Prefetches and iframe loads are correctly filtered out.
20
+ - New public methods on `Mbuzz::Middleware::Tracking`: `should_create_session?`, `sec_fetch_headers?`, `page_navigation?`, `framework_sub_request?`
21
+
22
+ ### Migration Guide
23
+
24
+ 1. Remove any code that reads or depends on the `_mbuzz_sid` cookie.
25
+ 2. Remove references to `Mbuzz::SESSION_COOKIE_NAME` or `Mbuzz::SESSION_COOKIE_MAX_AGE`.
26
+ 3. Visitor cookie (`_mbuzz_vid`) is unaffected — still set on every request.
27
+
8
28
  ## [0.7.0] - 2026-01-09
9
29
 
10
30
  ### Breaking Changes
@@ -23,12 +23,11 @@ module Mbuzz
23
23
 
24
24
  store_in_current_attributes(context, request)
25
25
 
26
- create_session_async(context, request) if context[:new_session]
26
+ create_session_async(context, request) if should_create_session?(env)
27
27
 
28
28
  RequestContext.with_context(request: request) do
29
29
  status, headers, body = @app.call(env)
30
30
  set_visitor_cookie(headers, context, request)
31
- set_session_cookie(headers, context, request)
32
31
  [status, headers, body]
33
32
  ensure
34
33
  reset_current_attributes
@@ -51,25 +50,46 @@ module Mbuzz
51
50
  Mbuzz.config.all_skip_extensions.any? { |ext| path.end_with?(ext) }
52
51
  end
53
52
 
53
+ # Navigation detection — only create sessions for real page navigations.
54
+ # Sec-Fetch-* headers (browser-enforced, unforgeable) are the primary signal;
55
+ # framework-specific blacklist covers old browsers and bots.
56
+
57
+ def should_create_session?(env)
58
+ return page_navigation?(env) if sec_fetch_headers?(env)
59
+
60
+ !framework_sub_request?(env)
61
+ end
62
+
63
+ def sec_fetch_headers?(env)
64
+ !env["HTTP_SEC_FETCH_MODE"].nil?
65
+ end
66
+
67
+ def page_navigation?(env)
68
+ env["HTTP_SEC_FETCH_MODE"] == "navigate" &&
69
+ env["HTTP_SEC_FETCH_DEST"] == "document" &&
70
+ env["HTTP_SEC_PURPOSE"].nil?
71
+ end
72
+
73
+ def framework_sub_request?(env)
74
+ !env["HTTP_TURBO_FRAME"].nil? ||
75
+ !env["HTTP_HX_REQUEST"].nil? ||
76
+ !env["HTTP_X_UP_VERSION"].nil? ||
77
+ env["HTTP_X_REQUESTED_WITH"] == "XMLHttpRequest"
78
+ end
79
+
54
80
  private
55
81
 
56
- # Build all request-specific context as a frozen hash
57
- # This ensures thread-safety by using local variables only
58
- # IMPORTANT: All values needed by async session creation must be captured here,
59
- # NOT accessed from the request object in the background thread (see #create_session)
82
+ # Build all request-specific context as a frozen hash.
83
+ # Thread-safety: all values needed by async session creation are captured here,
84
+ # NOT accessed from the request object in the background thread.
60
85
  def build_request_context(request)
61
- existing_session_id = session_id_from_cookie(request)
62
- new_session = existing_session_id.nil?
63
86
  ip = extract_ip(request)
64
87
  user_agent = request.user_agent.to_s
65
88
 
66
89
  {
67
90
  visitor_id: resolve_visitor_id(request),
68
- session_id: existing_session_id || generate_session_id,
91
+ session_id: SecureRandom.uuid,
69
92
  user_id: user_id_from_session(request),
70
- new_session: new_session,
71
- # Session creation data - captured here for thread-safety
72
- # Background thread must NOT read from request object
73
93
  url: request.url,
74
94
  referrer: request.referer,
75
95
  ip: ip,
@@ -86,14 +106,6 @@ module Mbuzz
86
106
  request.cookies[VISITOR_COOKIE_NAME]
87
107
  end
88
108
 
89
- def session_id_from_cookie(request)
90
- request.cookies[SESSION_COOKIE_NAME]
91
- end
92
-
93
- def generate_session_id
94
- SecureRandom.uuid
95
- end
96
-
97
109
  def user_id_from_session(request)
98
110
  request.session[SESSION_USER_ID_KEY] if request.session
99
111
  end
@@ -126,7 +138,7 @@ module Mbuzz
126
138
  Rails.logger.error("[Mbuzz] #{message}")
127
139
  end
128
140
 
129
- # Cookie setting - visitor and session cookies
141
+ # Cookie setting - visitor identity only (sessions are server-side)
130
142
 
131
143
  def set_visitor_cookie(headers, context, request)
132
144
  Rack::Utils.set_cookie_header!(
@@ -136,14 +148,6 @@ module Mbuzz
136
148
  )
137
149
  end
138
150
 
139
- def set_session_cookie(headers, context, request)
140
- Rack::Utils.set_cookie_header!(
141
- headers,
142
- SESSION_COOKIE_NAME,
143
- session_cookie_options(context, request)
144
- )
145
- end
146
-
147
151
  def visitor_cookie_options(context, request)
148
152
  base_cookie_options(request).merge(
149
153
  value: context[:visitor_id],
@@ -151,13 +155,6 @@ module Mbuzz
151
155
  )
152
156
  end
153
157
 
154
- def session_cookie_options(context, request)
155
- base_cookie_options(request).merge(
156
- value: context[:session_id],
157
- max_age: SESSION_COOKIE_MAX_AGE
158
- )
159
- end
160
-
161
158
  def base_cookie_options(request)
162
159
  options = {
163
160
  path: VISITOR_COOKIE_PATH,
data/lib/mbuzz/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mbuzz
4
- VERSION = "0.7.2"
4
+ VERSION = "0.7.3"
5
5
  end
data/lib/mbuzz.rb CHANGED
@@ -27,9 +27,6 @@ module Mbuzz
27
27
  VISITOR_COOKIE_PATH = "/"
28
28
  VISITOR_COOKIE_SAME_SITE = "Lax"
29
29
 
30
- SESSION_COOKIE_NAME = "_mbuzz_sid"
31
- SESSION_COOKIE_MAX_AGE = 30 * 60 # 30 minutes
32
-
33
30
  SESSION_USER_ID_KEY = "user_id"
34
31
  ENV_USER_ID_KEY = "mbuzz.user_id"
35
32
  ENV_VISITOR_ID_KEY = "mbuzz.visitor_id"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mbuzz
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.2
4
+ version: 0.7.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - mbuzz team