rage-rb 1.19.0 → 1.19.1

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: 847e3debe188b3b34ffdd6b7306edeca0a053b82c0e5106b3faa37a6e43f20bf
4
- data.tar.gz: 202db65e0a17d27ae94178d93ddfca940a95237450095b06c0fa4e080a6fd09a
3
+ metadata.gz: 80ca2fffb3bfe313c4be9218461d8346872ea1384472e74ed0236ece99288cfa
4
+ data.tar.gz: e516241ce7ffa73973b22e4abffeeb40aa0cba342d3566e3517549de979dddf6
5
5
  SHA512:
6
- metadata.gz: 74610482cca2fd1394e3ffd4bd2cf577ed78a980140e39bf359ece4050bed7497dc1845a472a3c403a6fb0cbd48c1124a1714b8e7c8352b0ed720287177418c9
7
- data.tar.gz: cd7cec704b0019012d1a08aea63b97dd83e0a6ee17155228d9517575e7882482c58b4b227d6663b053cc77a2edc551e34da53d0bf9bc0463e254ca917f9e8af4
6
+ metadata.gz: 5b3ea8087b89085a05946a6efd296d3d0bae2f40184356b41d17a49f62a1ad348a0ee4d0295694e6de845465ea004d9d2fb710e0d04316c132533952d9164fae
7
+ data.tar.gz: 8bf64fcb40ed0beccc1f975bec376ebeeadfe84e815e10e801b69ab8820d1ddbaf8b6c87bb3bcbab04e421376b963ee905bfcf13a44443c5391a3b3fb73e30d7
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.19.1] - 2025-12-26
4
+
5
+ ### Changed
6
+
7
+ - Use app-specific cookie keys for sessions (#189).
8
+
3
9
  ## [1.19.0] - 2025-12-03
4
10
 
5
11
  ### Added
@@ -1,5 +1,33 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ ##
4
+ # `Rage::Cable` provides built-in WebSocket support for Rage apps, similar to Action Cable in Rails. It lets you mount a separate WebSocket application, define channels and connections, subscribe clients to named streams, and broadcast messages in real time.
5
+ #
6
+ # Define a channel:
7
+ # ```ruby
8
+ # class ChatChannel < Rage::Cable::Channel
9
+ # def subscribed
10
+ # stream_from "chat"
11
+ # end
12
+ #
13
+ # def receive(data)
14
+ # puts "Received message: #{data['message']}"
15
+ # end
16
+ # end
17
+ # ```
18
+ #
19
+ # Mount the Cable application:
20
+ # ```ruby
21
+ # Rage.routes.draw do
22
+ # mount Rage::Cable.application, at: "/cable"
23
+ # end
24
+ # ```
25
+ #
26
+ # Broadcast a message to a stream:
27
+ # ```ruby
28
+ # Rage.cable.broadcast("chat", { message: "Hello, world!" })
29
+ # ```
30
+ #
3
31
  module Rage::Cable
4
32
  # Create a new Cable application.
5
33
  #
@@ -203,6 +203,14 @@ class Rage::Configuration
203
203
  end
204
204
  # @!endgroup
205
205
 
206
+ # @!group Session Configuration
207
+ # Allows configuring session settings.
208
+ # @return [Rage::Configuration::Session]
209
+ def session
210
+ @session ||= Session.new
211
+ end
212
+ # @!endgroup
213
+
206
214
  # @private
207
215
  def internal
208
216
  @internal ||= Internal.new
@@ -773,6 +781,17 @@ class Rage::Configuration
773
781
  end
774
782
  end
775
783
 
784
+ class Session
785
+ # @!attribute key
786
+ # Specify the name of the session cookie.
787
+ # @return [String]
788
+ # @example Change the session cookie name
789
+ # Rage.configure do
790
+ # config.session.key = "_myapp_session"
791
+ # end
792
+ attr_accessor :key
793
+ end
794
+
776
795
  # @private
777
796
  class Internal
778
797
  attr_accessor :rails_mode
data/lib/rage/cookies.rb CHANGED
@@ -12,6 +12,92 @@ if !defined?(DomainName)
12
12
  ERR
13
13
  end
14
14
 
15
+ ##
16
+ # Cookies provide a convenient way to store small amounts of data on the client side that persists across requests.
17
+ # They are commonly used for session management, personalization, and tracking user preferences.
18
+ #
19
+ # Rage cookies support both simple string-based cookies and encrypted cookies for sensitive data.
20
+ #
21
+ # To use cookies, add the `domain_name` gem to your `Gemfile`:
22
+ #
23
+ # ```bash
24
+ # bundle add domain_name
25
+ # ```
26
+ #
27
+ # Additionally, if you need to use encrypted cookies, see {Session} for setup steps.
28
+ #
29
+ # ## Usage
30
+ #
31
+ # ### Basic Cookies
32
+ #
33
+ # Read and write simple string values:
34
+ #
35
+ # ```ruby
36
+ # # Set a cookie
37
+ # cookies[:user_name] = "Alice"
38
+ #
39
+ # # Read a cookie
40
+ # cookies[:user_name] # => "Alice"
41
+ #
42
+ # # Delete a cookie
43
+ # cookies.delete(:user_name)
44
+ # ```
45
+ #
46
+ # ### Cookie Options
47
+ #
48
+ # Set cookies with additional options for security and control:
49
+ #
50
+ # ```ruby
51
+ # cookies[:user_id] = {
52
+ # value: "12345",
53
+ # expires: 1.year.from_now,
54
+ # secure: true,
55
+ # httponly: true,
56
+ # same_site: :lax
57
+ # }
58
+ # ```
59
+ #
60
+ # ### Encrypted Cookies
61
+ #
62
+ # Store sensitive data securely with automatic encryption:
63
+ #
64
+ # ```ruby
65
+ # # Set an encrypted cookie
66
+ # cookies.encrypted[:api_token] = "secret-token"
67
+ #
68
+ # # Read an encrypted cookie
69
+ # cookies.encrypted[:api_token] # => "secret-token"
70
+ #
71
+ # ```
72
+ #
73
+ # ### Permanent Cookies
74
+ #
75
+ # Create cookies that expire 20 years from now:
76
+ #
77
+ # ```ruby
78
+ # cookies.permanent[:remember_token] = "token-value"
79
+ #
80
+ # # Can be combined with encrypted
81
+ # cookies.permanent.encrypted[:user_id] = current_user.id
82
+ # ```
83
+ #
84
+ # ### Domain Configuration
85
+ #
86
+ # Control which domains can access your cookies:
87
+ #
88
+ # ```ruby
89
+ # # Specific domain
90
+ # cookies[:cross_domain] = { value: "data", domain: "example.com" }
91
+ #
92
+ # # All subdomains
93
+ # cookies[:shared] = { value: "data", domain: :all }
94
+ #
95
+ # # Multiple allowed domains
96
+ # cookies[:limited] = { value: "data", domain: ["app.example.com", "api.example.com"] }
97
+ # ```
98
+ #
99
+ # @see Session
100
+ #
15
101
  class Rage::Cookies
16
102
  # @private
17
103
  def initialize(env, headers)
@@ -190,10 +276,13 @@ class Rage::Cookies
190
276
  begin
191
277
  box.decrypt(Base64.urlsafe_decode64(value).byteslice(2..))
192
278
  rescue ArgumentError
279
+ Rage.logger.debug("Failed to decode encrypted cookie")
193
280
  nil
194
281
  rescue RbNaCl::CryptoError
282
+ Rage.logger.debug("Failed to decrypt encrypted cookie")
195
283
  i ||= 0
196
284
  if (box = fallback_boxes[i])
285
+ Rage.logger.debug("Trying to decrypt with fallback key ##{i + 1}")
197
286
  i += 1
198
287
  retry
199
288
  end
@@ -209,13 +209,7 @@ class Rage::Logger
209
209
  RUBY
210
210
  elsif @external_logger.is_a?(External::Dynamic)
211
211
  # a callable object is used as a logger
212
- call_method = if @external_logger.wrapped.is_a?(Proc)
213
- @external_logger.wrapped
214
- else
215
- @external_logger.wrapped.method(:call)
216
- end
217
-
218
- parameters = Rage::Internal.build_arguments(call_method, {
212
+ parameters = Rage::Internal.build_arguments(@external_logger.wrapped, {
219
213
  severity: ":#{level_name}",
220
214
  tags: "logger[:tags].freeze",
221
215
  context: "logger[:context].freeze",
data/lib/rage/session.rb CHANGED
@@ -2,9 +2,68 @@
2
2
 
3
3
  require "json"
4
4
 
5
+ ##
6
+ # Sessions securely store data between requests using cookies and are typically one of the most convenient and secure
7
+ # authentication mechanisms for browser-based clients.
8
+ #
9
+ # Rage sessions are encrypted using a secret key. This prevents clients from reading or tampering with session data.
10
+ #
11
+ # ## Setup
12
+ #
13
+ # 1. Add the required gems to your `Gemfile`:
14
+ #
15
+ # ```bash
16
+ # bundle add base64 domain_name rbnacl
17
+ # ```
18
+ #
19
+ # 2. Generate a secret key base (keep this value private and out of version control):
20
+ #
21
+ # ```bash
22
+ # ruby -r securerandom -e 'puts SecureRandom.hex(64)'
23
+ # ```
24
+ #
25
+ # 3. Configure your application to use the generated key, either via configuration:
26
+ #
27
+ # ```ruby
28
+ # Rage.configure do |config|
29
+ # config.secret_key_base = "my-secret-key"
30
+ # end
31
+ # ```
32
+ #
33
+ # or via the `SECRET_KEY_BASE` environment variable:
34
+ #
35
+ # ```bash
36
+ # export SECRET_KEY_BASE="my-secret-key"
37
+ # ```
38
+ #
39
+ # ## System Dependencies
40
+ #
41
+ # Rage sessions use libsodium (via RbNaCl) for encryption. On many Debian-based systems
42
+ # it is installed by default; if not, install it with:
43
+ #
44
+ # - Ubuntu / Debian:
45
+ #
46
+ # ```bash
47
+ # sudo apt install libsodium23
48
+ # ```
49
+ #
50
+ # - Fedora / RHEL / Amazon Linux:
51
+ #
52
+ # ```bash
53
+ # sudo yum install libsodium
54
+ # ```
55
+ #
56
+ # - macOS (using Homebrew):
57
+ #
58
+ # ```bash
59
+ # brew install libsodium
60
+ # ```
61
+ #
5
62
  class Rage::Session
6
63
  # @private
7
- KEY = Rack::RACK_SESSION.to_sym
64
+ def self.key
65
+ @key ||= Rage.config.session.key&.to_sym || :"_#{Rage.root.basename.to_s.gsub(/\W/, "_").downcase}_session"
66
+ end
8
67
 
9
68
  # @private
10
69
  def initialize(cookies)
@@ -92,13 +151,15 @@ class Rage::Session
92
151
  read_session.clear
93
152
  end
94
153
 
95
- @cookies[KEY] = { httponly: true, same_site: :lax, value: read_session.to_json }
154
+ @cookies[self.class.key] = { httponly: true, same_site: :lax, value: read_session.to_json }
96
155
  end
97
156
 
98
157
  def read_session
99
158
  @session ||= begin
100
- JSON.parse(@cookies[KEY] || "{}", symbolize_names: true)
159
+ session_value = @cookies[self.class.key] || @cookies[Rack::RACK_SESSION.to_sym] || "{}"
160
+ JSON.parse(session_value, symbolize_names: true)
101
161
  rescue JSON::ParserError
162
+ Rage.logger.debug("Failed to parse session cookie, resetting session")
102
163
  {}
103
164
  end
104
165
  end
data/lib/rage/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rage
4
- VERSION = "1.19.0"
4
+ VERSION = "1.19.1"
5
5
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rage-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.19.0
4
+ version: 1.19.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Roman Samoilov
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-12-03 00:00:00.000000000 Z
10
+ date: 2025-12-26 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: thor