macaw_framework 1.2.5 → 1.2.6

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: fd7f1b0bfc6306d0d86f2228f3a51cf955cad0db12031920cf9f0f131d664f6d
4
- data.tar.gz: 92ea7a2854218fb31726c37bc6cbe99399159cdb0cc08a3c72ce62e4b27e72c2
3
+ metadata.gz: 2353cd5ffe4a264a2eacab71fc2de65c5c4a6b2cd925666529e36b8bdde0ada6
4
+ data.tar.gz: 4855cf3e106380f6c6718058001cd6cbd888a6c0f1927f833da3bc97cf648785
5
5
  SHA512:
6
- metadata.gz: 1a06342e79d24109aa1b47058e7a973009e9e19a0a898f95c653a13dd3558b5576be34b628f5fbf488aa0b019f35ed6f941fd1b3808c7894bac9dd1b9d9c85e5
7
- data.tar.gz: cfff2868edfd0314006a36cdeb21d1f69ed6388b2c9a5181cec7f67c1c101818f6feb58e865d3672c84b55c3d71372a3850e9dd6b0ee6f3f948baec5af2a726c
6
+ metadata.gz: 85f5262044b8b3029ad507d501655f72ccd022630b34fc72a5606fe993d223a7e83b245b2ee858adbedf1723717d2d050e1276badf2a353d89612d2c544253a4
7
+ data.tar.gz: 31b67715e3f2b2c792262d53f6488ae0b8df38c2c1f700fd5590b45927f49dc47fa8c84db884d2ec560b0e981582091b3f38a0f8af06bbddb26efd26f33e2e58
data/CHANGELOG.md CHANGED
@@ -132,3 +132,7 @@
132
132
  ## [1.2.5]
133
133
 
134
134
  - Improvements to cache usability
135
+
136
+ ## [1.2.6]
137
+
138
+ - Improving session strategy and fixing vulnerabilities on it.
data/README.md CHANGED
@@ -113,6 +113,15 @@ end
113
113
 
114
114
  ### Session management: Handle user sessions with server-side in-memory storage
115
115
 
116
+ Session will only be enabled if it's configurations exists in the `application.json` file.
117
+ The session mechanism works by recovering the Session ID from a client sent header. The default
118
+ header is `X-Session-ID`, but it can be changed in the `application.json` file.
119
+
120
+ This header will be sent back to the user on every response if Session is enabled. Also, the
121
+ session ID will be automatically generated and sent to a client if this client does not provide
122
+ a session id in the HTTP request. In the case of the client sending an ID of an expired session
123
+ the framework will return a new session with a new ID.
124
+
116
125
  ```ruby
117
126
  m.get('/login') do |context|
118
127
  # Authenticate user
@@ -129,8 +138,6 @@ m.get('/dashboard') do |context|
129
138
  end
130
139
  ```
131
140
 
132
- **Caution: This feature is vulnerable to IP spoofing and may disrupt sessions on devices sharing the same network (e.g., Wi-Fi).**
133
-
134
141
  ### Configuration: Customize various aspects of the framework through the application.json configuration file, such as rate limiting, SSL support, and Prometheus integration
135
142
 
136
143
  ```json
@@ -155,6 +162,10 @@ end
155
162
  "key_type": "EC",
156
163
  "cert_file_name": "path/to/cert/file/file.crt",
157
164
  "key_file_name": "path/to/cert/key/file.key"
165
+ },
166
+ "session": {
167
+ "secure_header": "X-Session-ID",
168
+ "invalidation_time": 3600
158
169
  }
159
170
  }
160
171
  }
@@ -8,6 +8,7 @@ require_relative "../../utils/supported_ssl_versions"
8
8
  require_relative "../../aspects/prometheus_aspect"
9
9
  require_relative "../../aspects/logging_aspect"
10
10
  require_relative "../../aspects/cache_aspect"
11
+ require "securerandom"
11
12
 
12
13
  ##
13
14
  # Base module for Server classes. It contains
@@ -21,14 +22,14 @@ module ServerBase
21
22
 
22
23
  private
23
24
 
24
- def call_endpoint(name, client_data, client_ip)
25
+ def call_endpoint(name, client_data, session_id, _client_ip)
25
26
  @macaw.send(
26
27
  name.to_sym,
27
28
  {
28
29
  headers: client_data[:headers],
29
30
  body: client_data[:body],
30
31
  params: client_data[:params],
31
- client: @session[client_ip][0]
32
+ client: @session[session_id][0]
32
33
  }
33
34
  )
34
35
  end
@@ -42,12 +43,14 @@ module ServerBase
42
43
  raise EndpointNotMappedError unless @macaw.respond_to?(method_name)
43
44
  raise TooManyRequestsError unless @rate_limit.nil? || @rate_limit.allow?(client.peeraddr[3])
44
45
 
45
- declare_client_session(client)
46
46
  client_data = get_client_data(body, headers, parameters)
47
+ session_id = declare_client_session(client_data[:headers], @macaw.secure_header) if @macaw.session
47
48
 
48
49
  @macaw_log&.info("Running #{path.gsub("\n", "").gsub("\r", "")}")
49
50
  message, status, response_headers = call_endpoint(@prometheus_middleware, @macaw_log, @cache,
50
- method_name, client_data, client.peeraddr[3])
51
+ method_name, client_data, session_id, client.peeraddr[3])
52
+ response_headers ||= {}
53
+ response_headers[@macaw.secure_header] = session_id if @macaw.session
51
54
  status ||= 200
52
55
  message ||= nil
53
56
  response_headers ||= nil
@@ -69,9 +72,11 @@ module ServerBase
69
72
  end
70
73
  end
71
74
 
72
- def declare_client_session(client)
73
- @session[client.peeraddr[3]] ||= [{}, Time.now]
74
- @session[client.peeraddr[3]] = [{}, Time.now] if @session[client.peeraddr[3]][0].nil?
75
+ def declare_client_session(headers, secure_header_name)
76
+ session_id = headers[secure_header_name] || SecureRandom.uuid
77
+ session_id = SecureRandom.uuid if @session[session_id].nil?
78
+ @session[session_id] ||= [{}, Time.now]
79
+ session_id
75
80
  end
76
81
 
77
82
  def set_rate_limiting
@@ -110,7 +115,7 @@ module ServerBase
110
115
  end
111
116
 
112
117
  def set_session
113
- @session = {}
118
+ @session ||= {}
114
119
  inv = if @macaw.config&.dig("macaw", "session", "invalidation_time")
115
120
  MemoryInvalidationMiddleware.new(@macaw.config["macaw"]["session"]["invalidation_time"])
116
121
  else
@@ -122,7 +127,7 @@ module ServerBase
122
127
  def set_features
123
128
  @is_shutting_down = false
124
129
  set_rate_limiting
125
- set_session
130
+ set_session if @macaw.session
126
131
  set_ssl
127
132
  end
128
133
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MacawFramework
4
- VERSION = "1.2.5"
4
+ VERSION = "1.2.6"
5
5
  end
@@ -19,7 +19,7 @@ module MacawFramework
19
19
  # Class responsible for creating endpoints and
20
20
  # starting the web server.
21
21
  class Macaw
22
- attr_reader :routes, :macaw_log, :config, :jobs, :cached_methods
22
+ attr_reader :routes, :macaw_log, :config, :jobs, :cached_methods, :secure_header, :session
23
23
  attr_accessor :port, :bind, :threads
24
24
 
25
25
  ##
@@ -28,23 +28,7 @@ module MacawFramework
28
28
  # @param {ThreadServer} server
29
29
  # @param {String?} dir
30
30
  def initialize(custom_log: Logger.new($stdout), server: ThreadServer, dir: nil)
31
- begin
32
- @routes = []
33
- @cached_methods = {}
34
- @macaw_log ||= custom_log
35
- @config = JSON.parse(File.read("application.json"))
36
- @port = @config["macaw"]["port"] || 8080
37
- @bind = @config["macaw"]["bind"] || "localhost"
38
- @threads = @config["macaw"]["threads"] || 200
39
- unless @config["macaw"]["cache"].nil?
40
- @cache = MemoryInvalidationMiddleware.new(@config["macaw"]["cache"]["cache_invalidation"].to_i || 3_600)
41
- end
42
- @prometheus = Prometheus::Client::Registry.new if @config["macaw"]["prometheus"]
43
- @prometheus_middleware = PrometheusMiddleware.new if @config["macaw"]["prometheus"]
44
- @prometheus_middleware.configure_prometheus(@prometheus, @config, self) if @config["macaw"]["prometheus"]
45
- rescue StandardError => e
46
- @macaw_log&.warn(e.message)
47
- end
31
+ apply_options(custom_log)
48
32
  create_endpoint_public_files(dir)
49
33
  @port ||= 8080
50
34
  @bind ||= "localhost"
@@ -193,6 +177,29 @@ module MacawFramework
193
177
 
194
178
  private
195
179
 
180
+ def apply_options(custom_log)
181
+ @routes = []
182
+ @cached_methods = {}
183
+ @macaw_log ||= custom_log
184
+ @config = JSON.parse(File.read("application.json"))
185
+ @port = @config["macaw"]["port"] || 8080
186
+ @bind = @config["macaw"]["bind"] || "localhost"
187
+ @session = false
188
+ unless @config["macaw"]["session"].nil?
189
+ @session = true
190
+ @secure_header = @config["macaw"]["session"]["secure_header"] || "X-Session-ID"
191
+ end
192
+ @threads = @config["macaw"]["threads"] || 200
193
+ unless @config["macaw"]["cache"].nil?
194
+ @cache = MemoryInvalidationMiddleware.new(@config["macaw"]["cache"]["cache_invalidation"].to_i || 3_600)
195
+ end
196
+ @prometheus = Prometheus::Client::Registry.new if @config["macaw"]["prometheus"]
197
+ @prometheus_middleware = PrometheusMiddleware.new if @config["macaw"]["prometheus"]
198
+ @prometheus_middleware.configure_prometheus(@prometheus, @config, self) if @config["macaw"]["prometheus"]
199
+ rescue StandardError => e
200
+ @macaw_log&.warn(e.message)
201
+ end
202
+
196
203
  def server_loop(server)
197
204
  server.run
198
205
  end
@@ -10,8 +10,11 @@ module MacawFramework
10
10
 
11
11
  @prometheus: untyped
12
12
  @prometheus_middleware: untyped
13
+ @secure_header: String
13
14
  @server: untyped
14
15
 
16
+ @server_class: untyped
17
+ @session: bool
15
18
  @threads: Integer
16
19
 
17
20
  attr_accessor bind: String
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: macaw_framework
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.5
4
+ version: 1.2.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aria Diniz
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-04-14 00:00:00.000000000 Z
11
+ date: 2024-04-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: prometheus-client