macaw_framework 1.2.5 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -0
- data/README.md +13 -2
- data/lib/macaw_framework/core/common/server_base.rb +15 -10
- data/lib/macaw_framework/version.rb +1 -1
- data/lib/macaw_framework.rb +25 -18
- data/sig/macaw_framework/macaw.rbs +3 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1488af601dcf17bdfabaad9407c4167ba3cfc9bc3913fc6e51a1905e575c905f
|
4
|
+
data.tar.gz: d2082dadd31530c82ce830b475299c8d4df17b9d600cf4b2e77a9257e3afb045
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e218e790fd300482efcdabb79149819859b5500f4a7e12d511ffecf4d9ca678731045d0defa46cc13893c0fd1367c25104ff10d34ceb73d42ee35ae61c6c32a5
|
7
|
+
data.tar.gz: 151ffbeecb5789abcabfc52af53228ecae894f45717ad8e257bb8ddbd193e1b61ce1458ce107c5c3e300746a37a63f9715d4d87d856ee61a469ed15d3b99c89d
|
data/CHANGELOG.md
CHANGED
@@ -132,3 +132,14 @@
|
|
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.
|
139
|
+
|
140
|
+
## [1.3.0]
|
141
|
+
- Improvements to cache usability
|
142
|
+
- Improving session strategy and fixing vulnerabilities on it
|
143
|
+
- Fixed a bug where errors were being logged with level INFO
|
144
|
+
- Improved error stack trace
|
145
|
+
|
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,
|
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[
|
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
|
@@ -60,7 +63,7 @@ module ServerBase
|
|
60
63
|
client.print "HTTP/1.1 404 Not Found\r\n\r\n"
|
61
64
|
rescue StandardError => e
|
62
65
|
client.print "HTTP/1.1 500 Internal Server Error\r\n\r\n"
|
63
|
-
@macaw_log&.
|
66
|
+
@macaw_log&.error(e.full_message)
|
64
67
|
ensure
|
65
68
|
begin
|
66
69
|
client.close
|
@@ -69,9 +72,11 @@ module ServerBase
|
|
69
72
|
end
|
70
73
|
end
|
71
74
|
|
72
|
-
def declare_client_session(
|
73
|
-
|
74
|
-
|
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
|
data/lib/macaw_framework.rb
CHANGED
@@ -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
|
-
|
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
|
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.
|
4
|
+
version: 1.3.0
|
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
|
11
|
+
date: 2024-05-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: prometheus-client
|