macaw_framework 1.2.5 → 1.2.6

Sign up to get free protection for your applications and to get access to all the features.
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