tina4ruby 3.11.13 → 3.11.15
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 +4 -4
- data/CHANGELOG.md +80 -80
- data/LICENSE.txt +21 -21
- data/README.md +137 -137
- data/exe/tina4ruby +5 -5
- data/lib/tina4/ai.rb +696 -696
- data/lib/tina4/api.rb +189 -189
- data/lib/tina4/auth.rb +305 -305
- data/lib/tina4/auto_crud.rb +244 -244
- data/lib/tina4/cache.rb +154 -154
- data/lib/tina4/cli.rb +1449 -1449
- data/lib/tina4/constants.rb +46 -46
- data/lib/tina4/container.rb +74 -74
- data/lib/tina4/cors.rb +74 -74
- data/lib/tina4/crud.rb +692 -692
- data/lib/tina4/database/sqlite3_adapter.rb +165 -165
- data/lib/tina4/database.rb +625 -625
- data/lib/tina4/database_result.rb +208 -208
- data/lib/tina4/debug.rb +8 -8
- data/lib/tina4/dev.rb +14 -14
- data/lib/tina4/dev_admin.rb +935 -935
- data/lib/tina4/dev_mailbox.rb +191 -191
- data/lib/tina4/drivers/firebird_driver.rb +124 -110
- data/lib/tina4/drivers/mongodb_driver.rb +561 -561
- data/lib/tina4/drivers/mssql_driver.rb +112 -112
- data/lib/tina4/drivers/mysql_driver.rb +90 -90
- data/lib/tina4/drivers/odbc_driver.rb +191 -191
- data/lib/tina4/drivers/postgres_driver.rb +116 -106
- data/lib/tina4/drivers/sqlite_driver.rb +122 -122
- data/lib/tina4/env.rb +95 -95
- data/lib/tina4/error_overlay.rb +252 -252
- data/lib/tina4/events.rb +109 -109
- data/lib/tina4/field_types.rb +154 -154
- data/lib/tina4/frond.rb +2025 -2025
- data/lib/tina4/gallery/auth/meta.json +1 -1
- data/lib/tina4/gallery/auth/src/routes/api/gallery_auth.rb +114 -114
- data/lib/tina4/gallery/database/meta.json +1 -1
- data/lib/tina4/gallery/database/src/routes/api/gallery_db.rb +43 -43
- data/lib/tina4/gallery/error-overlay/meta.json +1 -1
- data/lib/tina4/gallery/error-overlay/src/routes/api/gallery_crash.rb +17 -17
- data/lib/tina4/gallery/orm/meta.json +1 -1
- data/lib/tina4/gallery/orm/src/routes/api/gallery_products.rb +16 -16
- data/lib/tina4/gallery/queue/meta.json +1 -1
- data/lib/tina4/gallery/queue/src/routes/api/gallery_queue.rb +325 -325
- data/lib/tina4/gallery/rest-api/meta.json +1 -1
- data/lib/tina4/gallery/rest-api/src/routes/api/gallery_hello.rb +14 -14
- data/lib/tina4/gallery/templates/meta.json +1 -1
- data/lib/tina4/gallery/templates/src/routes/gallery_page.rb +12 -12
- data/lib/tina4/gallery/templates/src/templates/gallery_page.twig +257 -257
- data/lib/tina4/graphql.rb +966 -966
- data/lib/tina4/health.rb +39 -39
- data/lib/tina4/html_element.rb +170 -170
- data/lib/tina4/job.rb +80 -80
- data/lib/tina4/localization.rb +168 -168
- data/lib/tina4/log.rb +203 -203
- data/lib/tina4/mcp.rb +696 -696
- data/lib/tina4/messenger.rb +587 -587
- data/lib/tina4/metrics.rb +793 -793
- data/lib/tina4/middleware.rb +445 -445
- data/lib/tina4/migration.rb +451 -451
- data/lib/tina4/orm.rb +790 -790
- data/lib/tina4/public/css/tina4.css +2463 -2463
- data/lib/tina4/public/css/tina4.min.css +1 -1
- data/lib/tina4/public/images/logo.svg +5 -5
- data/lib/tina4/public/js/frond.min.js +2 -2
- data/lib/tina4/public/js/tina4-dev-admin.js +565 -565
- data/lib/tina4/public/js/tina4-dev-admin.min.js +480 -480
- data/lib/tina4/public/js/tina4.min.js +92 -92
- data/lib/tina4/public/js/tina4js.min.js +48 -48
- data/lib/tina4/public/swagger/index.html +90 -90
- data/lib/tina4/public/swagger/oauth2-redirect.html +63 -63
- data/lib/tina4/query_builder.rb +380 -380
- data/lib/tina4/queue.rb +366 -366
- data/lib/tina4/queue_backends/kafka_backend.rb +80 -80
- data/lib/tina4/queue_backends/lite_backend.rb +298 -298
- data/lib/tina4/queue_backends/mongo_backend.rb +126 -126
- data/lib/tina4/queue_backends/rabbitmq_backend.rb +73 -73
- data/lib/tina4/rack_app.rb +817 -817
- data/lib/tina4/rate_limiter.rb +130 -130
- data/lib/tina4/request.rb +268 -255
- data/lib/tina4/response.rb +346 -346
- data/lib/tina4/response_cache.rb +551 -551
- data/lib/tina4/router.rb +406 -406
- data/lib/tina4/scss/tina4css/_alerts.scss +34 -34
- data/lib/tina4/scss/tina4css/_badges.scss +22 -22
- data/lib/tina4/scss/tina4css/_buttons.scss +69 -69
- data/lib/tina4/scss/tina4css/_cards.scss +49 -49
- data/lib/tina4/scss/tina4css/_forms.scss +156 -156
- data/lib/tina4/scss/tina4css/_grid.scss +81 -81
- data/lib/tina4/scss/tina4css/_modals.scss +84 -84
- data/lib/tina4/scss/tina4css/_nav.scss +149 -149
- data/lib/tina4/scss/tina4css/_reset.scss +94 -94
- data/lib/tina4/scss/tina4css/_tables.scss +54 -54
- data/lib/tina4/scss/tina4css/_typography.scss +55 -55
- data/lib/tina4/scss/tina4css/_utilities.scss +197 -197
- data/lib/tina4/scss/tina4css/_variables.scss +117 -117
- data/lib/tina4/scss/tina4css/base.scss +1 -1
- data/lib/tina4/scss/tina4css/colors.scss +48 -48
- data/lib/tina4/scss/tina4css/tina4.scss +17 -17
- data/lib/tina4/scss_compiler.rb +178 -178
- data/lib/tina4/seeder.rb +567 -567
- data/lib/tina4/service_runner.rb +303 -303
- data/lib/tina4/session.rb +297 -297
- data/lib/tina4/session_handlers/database_handler.rb +72 -72
- data/lib/tina4/session_handlers/file_handler.rb +67 -67
- data/lib/tina4/session_handlers/mongo_handler.rb +49 -49
- data/lib/tina4/session_handlers/redis_handler.rb +43 -43
- data/lib/tina4/session_handlers/valkey_handler.rb +43 -43
- data/lib/tina4/shutdown.rb +84 -84
- data/lib/tina4/sql_translation.rb +158 -158
- data/lib/tina4/swagger.rb +124 -124
- data/lib/tina4/template.rb +894 -894
- data/lib/tina4/templates/base.twig +26 -26
- data/lib/tina4/templates/errors/302.twig +14 -14
- data/lib/tina4/templates/errors/401.twig +9 -9
- data/lib/tina4/templates/errors/403.twig +29 -29
- data/lib/tina4/templates/errors/404.twig +29 -29
- data/lib/tina4/templates/errors/500.twig +38 -38
- data/lib/tina4/templates/errors/502.twig +9 -9
- data/lib/tina4/templates/errors/503.twig +12 -12
- data/lib/tina4/templates/errors/base.twig +37 -37
- data/lib/tina4/test_client.rb +159 -159
- data/lib/tina4/testing.rb +340 -340
- data/lib/tina4/validator.rb +174 -174
- data/lib/tina4/version.rb +1 -1
- data/lib/tina4/webserver.rb +312 -312
- data/lib/tina4/websocket.rb +343 -343
- data/lib/tina4/websocket_backplane.rb +190 -190
- data/lib/tina4/wsdl.rb +564 -564
- data/lib/tina4.rb +458 -458
- data/lib/tina4ruby.rb +4 -4
- metadata +3 -3
data/lib/tina4/constants.rb
CHANGED
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
# Tina4 Constants — HTTP status codes and content types.
|
|
2
|
-
#
|
|
3
|
-
# Standard constants for use in route handlers across all Tina4 frameworks.
|
|
4
|
-
#
|
|
5
|
-
# Tina4.get "/api/users" do |request, response|
|
|
6
|
-
# response.call(users, Tina4::HTTP_OK)
|
|
7
|
-
# end
|
|
8
|
-
|
|
9
|
-
module Tina4
|
|
10
|
-
# ── HTTP Status Codes ──
|
|
11
|
-
|
|
12
|
-
HTTP_OK = 200
|
|
13
|
-
HTTP_CREATED = 201
|
|
14
|
-
HTTP_ACCEPTED = 202
|
|
15
|
-
HTTP_NO_CONTENT = 204
|
|
16
|
-
|
|
17
|
-
HTTP_MOVED = 301
|
|
18
|
-
HTTP_REDIRECT = 302
|
|
19
|
-
HTTP_NOT_MODIFIED = 304
|
|
20
|
-
|
|
21
|
-
HTTP_BAD_REQUEST = 400
|
|
22
|
-
HTTP_UNAUTHORIZED = 401
|
|
23
|
-
HTTP_FORBIDDEN = 403
|
|
24
|
-
HTTP_NOT_FOUND = 404
|
|
25
|
-
HTTP_METHOD_NOT_ALLOWED = 405
|
|
26
|
-
HTTP_CONFLICT = 409
|
|
27
|
-
HTTP_GONE = 410
|
|
28
|
-
HTTP_UNPROCESSABLE = 422
|
|
29
|
-
HTTP_TOO_MANY = 429
|
|
30
|
-
|
|
31
|
-
HTTP_SERVER_ERROR = 500
|
|
32
|
-
HTTP_BAD_GATEWAY = 502
|
|
33
|
-
HTTP_UNAVAILABLE = 503
|
|
34
|
-
|
|
35
|
-
# ── Content Types ──
|
|
36
|
-
|
|
37
|
-
APPLICATION_JSON = "application/json"
|
|
38
|
-
APPLICATION_XML = "application/xml"
|
|
39
|
-
APPLICATION_FORM = "application/x-www-form-urlencoded"
|
|
40
|
-
APPLICATION_OCTET = "application/octet-stream"
|
|
41
|
-
|
|
42
|
-
TEXT_HTML = "text/html; charset=utf-8"
|
|
43
|
-
TEXT_PLAIN = "text/plain; charset=utf-8"
|
|
44
|
-
TEXT_CSV = "text/csv"
|
|
45
|
-
TEXT_XML = "text/xml"
|
|
46
|
-
end
|
|
1
|
+
# Tina4 Constants — HTTP status codes and content types.
|
|
2
|
+
#
|
|
3
|
+
# Standard constants for use in route handlers across all Tina4 frameworks.
|
|
4
|
+
#
|
|
5
|
+
# Tina4.get "/api/users" do |request, response|
|
|
6
|
+
# response.call(users, Tina4::HTTP_OK)
|
|
7
|
+
# end
|
|
8
|
+
|
|
9
|
+
module Tina4
|
|
10
|
+
# ── HTTP Status Codes ──
|
|
11
|
+
|
|
12
|
+
HTTP_OK = 200
|
|
13
|
+
HTTP_CREATED = 201
|
|
14
|
+
HTTP_ACCEPTED = 202
|
|
15
|
+
HTTP_NO_CONTENT = 204
|
|
16
|
+
|
|
17
|
+
HTTP_MOVED = 301
|
|
18
|
+
HTTP_REDIRECT = 302
|
|
19
|
+
HTTP_NOT_MODIFIED = 304
|
|
20
|
+
|
|
21
|
+
HTTP_BAD_REQUEST = 400
|
|
22
|
+
HTTP_UNAUTHORIZED = 401
|
|
23
|
+
HTTP_FORBIDDEN = 403
|
|
24
|
+
HTTP_NOT_FOUND = 404
|
|
25
|
+
HTTP_METHOD_NOT_ALLOWED = 405
|
|
26
|
+
HTTP_CONFLICT = 409
|
|
27
|
+
HTTP_GONE = 410
|
|
28
|
+
HTTP_UNPROCESSABLE = 422
|
|
29
|
+
HTTP_TOO_MANY = 429
|
|
30
|
+
|
|
31
|
+
HTTP_SERVER_ERROR = 500
|
|
32
|
+
HTTP_BAD_GATEWAY = 502
|
|
33
|
+
HTTP_UNAVAILABLE = 503
|
|
34
|
+
|
|
35
|
+
# ── Content Types ──
|
|
36
|
+
|
|
37
|
+
APPLICATION_JSON = "application/json"
|
|
38
|
+
APPLICATION_XML = "application/xml"
|
|
39
|
+
APPLICATION_FORM = "application/x-www-form-urlencoded"
|
|
40
|
+
APPLICATION_OCTET = "application/octet-stream"
|
|
41
|
+
|
|
42
|
+
TEXT_HTML = "text/html; charset=utf-8"
|
|
43
|
+
TEXT_PLAIN = "text/plain; charset=utf-8"
|
|
44
|
+
TEXT_CSV = "text/csv"
|
|
45
|
+
TEXT_XML = "text/xml"
|
|
46
|
+
end
|
data/lib/tina4/container.rb
CHANGED
|
@@ -1,74 +1,74 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Tina4
|
|
4
|
-
# Lightweight dependency injection container.
|
|
5
|
-
#
|
|
6
|
-
# Tina4::Container.register(:mailer) { MailService.new } # transient — new instance each get
|
|
7
|
-
# Tina4::Container.singleton(:db) { Database.new(ENV["DB_URL"]) } # singleton — memoised
|
|
8
|
-
# Tina4::Container.register(:cache, RedisCacheInstance) # concrete instance (always same)
|
|
9
|
-
# Tina4::Container.get(:db) # => Database instance
|
|
10
|
-
#
|
|
11
|
-
module Container
|
|
12
|
-
class << self
|
|
13
|
-
def registry
|
|
14
|
-
@registry ||= {}
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
# Register a service by name.
|
|
18
|
-
# Pass a concrete instance directly, or a block for transient instantiation.
|
|
19
|
-
# Blocks are called on every get() — use singleton() for memoised factories.
|
|
20
|
-
def register(name, instance = nil, &factory)
|
|
21
|
-
raise ArgumentError, "provide an instance or a block, not both" if instance && factory
|
|
22
|
-
raise ArgumentError, "provide an instance or a block" unless instance || factory
|
|
23
|
-
|
|
24
|
-
registry[name.to_sym] = if factory
|
|
25
|
-
{ factory: factory, singleton: false, instance: nil }
|
|
26
|
-
else
|
|
27
|
-
{ factory: nil, singleton: false, instance: instance }
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
# Register a singleton factory by name.
|
|
32
|
-
# The block is called once on first resolve() and the result is memoised.
|
|
33
|
-
def singleton(name, &factory)
|
|
34
|
-
raise ArgumentError, "singleton requires a block" unless factory
|
|
35
|
-
|
|
36
|
-
registry[name.to_sym] = { factory: factory, singleton: true, instance: nil }
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
# Resolve a service by name.
|
|
40
|
-
# Singletons and concrete instances return the same object each time.
|
|
41
|
-
# Transient factories (register with block) return a new object each time.
|
|
42
|
-
def get(name)
|
|
43
|
-
entry = registry[name.to_sym]
|
|
44
|
-
raise KeyError, "service not registered: #{name}" unless entry
|
|
45
|
-
|
|
46
|
-
# Concrete instance (register with value)
|
|
47
|
-
return entry[:instance] if entry[:instance] && entry[:factory].nil?
|
|
48
|
-
|
|
49
|
-
if entry[:factory]
|
|
50
|
-
if entry[:singleton]
|
|
51
|
-
# Singleton — call once, memoize
|
|
52
|
-
entry[:instance] ||= entry[:factory].call
|
|
53
|
-
entry[:instance]
|
|
54
|
-
else
|
|
55
|
-
# Transient — call every time
|
|
56
|
-
entry[:factory].call
|
|
57
|
-
end
|
|
58
|
-
else
|
|
59
|
-
entry[:instance]
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
# Check if a service is registered.
|
|
64
|
-
def has(name)
|
|
65
|
-
registry.key?(name.to_sym)
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
# Remove all registrations (useful in tests).
|
|
69
|
-
def reset
|
|
70
|
-
@registry = {}
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
end
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Tina4
|
|
4
|
+
# Lightweight dependency injection container.
|
|
5
|
+
#
|
|
6
|
+
# Tina4::Container.register(:mailer) { MailService.new } # transient — new instance each get
|
|
7
|
+
# Tina4::Container.singleton(:db) { Database.new(ENV["DB_URL"]) } # singleton — memoised
|
|
8
|
+
# Tina4::Container.register(:cache, RedisCacheInstance) # concrete instance (always same)
|
|
9
|
+
# Tina4::Container.get(:db) # => Database instance
|
|
10
|
+
#
|
|
11
|
+
module Container
|
|
12
|
+
class << self
|
|
13
|
+
def registry
|
|
14
|
+
@registry ||= {}
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Register a service by name.
|
|
18
|
+
# Pass a concrete instance directly, or a block for transient instantiation.
|
|
19
|
+
# Blocks are called on every get() — use singleton() for memoised factories.
|
|
20
|
+
def register(name, instance = nil, &factory)
|
|
21
|
+
raise ArgumentError, "provide an instance or a block, not both" if instance && factory
|
|
22
|
+
raise ArgumentError, "provide an instance or a block" unless instance || factory
|
|
23
|
+
|
|
24
|
+
registry[name.to_sym] = if factory
|
|
25
|
+
{ factory: factory, singleton: false, instance: nil }
|
|
26
|
+
else
|
|
27
|
+
{ factory: nil, singleton: false, instance: instance }
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Register a singleton factory by name.
|
|
32
|
+
# The block is called once on first resolve() and the result is memoised.
|
|
33
|
+
def singleton(name, &factory)
|
|
34
|
+
raise ArgumentError, "singleton requires a block" unless factory
|
|
35
|
+
|
|
36
|
+
registry[name.to_sym] = { factory: factory, singleton: true, instance: nil }
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Resolve a service by name.
|
|
40
|
+
# Singletons and concrete instances return the same object each time.
|
|
41
|
+
# Transient factories (register with block) return a new object each time.
|
|
42
|
+
def get(name)
|
|
43
|
+
entry = registry[name.to_sym]
|
|
44
|
+
raise KeyError, "service not registered: #{name}" unless entry
|
|
45
|
+
|
|
46
|
+
# Concrete instance (register with value)
|
|
47
|
+
return entry[:instance] if entry[:instance] && entry[:factory].nil?
|
|
48
|
+
|
|
49
|
+
if entry[:factory]
|
|
50
|
+
if entry[:singleton]
|
|
51
|
+
# Singleton — call once, memoize
|
|
52
|
+
entry[:instance] ||= entry[:factory].call
|
|
53
|
+
entry[:instance]
|
|
54
|
+
else
|
|
55
|
+
# Transient — call every time
|
|
56
|
+
entry[:factory].call
|
|
57
|
+
end
|
|
58
|
+
else
|
|
59
|
+
entry[:instance]
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Check if a service is registered.
|
|
64
|
+
def has(name)
|
|
65
|
+
registry.key?(name.to_sym)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Remove all registrations (useful in tests).
|
|
69
|
+
def reset
|
|
70
|
+
@registry = {}
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
data/lib/tina4/cors.rb
CHANGED
|
@@ -1,74 +1,74 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Tina4
|
|
4
|
-
module CorsMiddleware
|
|
5
|
-
class << self
|
|
6
|
-
def config
|
|
7
|
-
@config ||= load_config
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def reset!
|
|
11
|
-
@config = nil
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
# Handle OPTIONS preflight request, returns a Rack response array
|
|
15
|
-
def preflight_response(env = {})
|
|
16
|
-
origin = resolve_origin(env)
|
|
17
|
-
[
|
|
18
|
-
204,
|
|
19
|
-
{
|
|
20
|
-
"access-control-allow-origin" => origin,
|
|
21
|
-
"access-control-allow-methods" => config[:methods],
|
|
22
|
-
"access-control-allow-headers" => config[:headers],
|
|
23
|
-
"access-control-max-age" => config[:max_age],
|
|
24
|
-
"access-control-allow-credentials" => config[:credentials]
|
|
25
|
-
},
|
|
26
|
-
[""]
|
|
27
|
-
]
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
# Apply CORS headers to a response headers hash
|
|
31
|
-
def apply_headers(response_headers, env = {})
|
|
32
|
-
origin = resolve_origin(env)
|
|
33
|
-
response_headers["access-control-allow-origin"] = origin
|
|
34
|
-
response_headers["access-control-allow-methods"] = config[:methods]
|
|
35
|
-
response_headers["access-control-allow-headers"] = config[:headers]
|
|
36
|
-
response_headers["access-control-max-age"] = config[:max_age]
|
|
37
|
-
response_headers["access-control-allow-credentials"] = config[:credentials] if config[:credentials] == "true"
|
|
38
|
-
response_headers
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
# Check if a given origin is allowed
|
|
42
|
-
def origin_allowed?(origin)
|
|
43
|
-
return true if config[:origins] == "*"
|
|
44
|
-
|
|
45
|
-
allowed = config[:origins].split(",").map(&:strip)
|
|
46
|
-
allowed.include?(origin)
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
private
|
|
50
|
-
|
|
51
|
-
def load_config
|
|
52
|
-
{
|
|
53
|
-
origins: ENV["TINA4_CORS_ORIGINS"] || "*",
|
|
54
|
-
methods: ENV["TINA4_CORS_METHODS"] || "GET, POST, PUT, PATCH, DELETE, OPTIONS",
|
|
55
|
-
headers: ENV["TINA4_CORS_HEADERS"] || "Content-Type,Authorization,X-Request-ID",
|
|
56
|
-
max_age: ENV["TINA4_CORS_MAX_AGE"] || "86400",
|
|
57
|
-
credentials: ENV["TINA4_CORS_CREDENTIALS"] || "false"
|
|
58
|
-
}.freeze
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
def resolve_origin(env)
|
|
62
|
-
request_origin = env["HTTP_ORIGIN"] || env["HTTP_REFERER"]
|
|
63
|
-
|
|
64
|
-
if config[:origins] == "*"
|
|
65
|
-
"*"
|
|
66
|
-
elsif request_origin && origin_allowed?(request_origin.chomp("/"))
|
|
67
|
-
request_origin.chomp("/")
|
|
68
|
-
else
|
|
69
|
-
""
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
end
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Tina4
|
|
4
|
+
module CorsMiddleware
|
|
5
|
+
class << self
|
|
6
|
+
def config
|
|
7
|
+
@config ||= load_config
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def reset!
|
|
11
|
+
@config = nil
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Handle OPTIONS preflight request, returns a Rack response array
|
|
15
|
+
def preflight_response(env = {})
|
|
16
|
+
origin = resolve_origin(env)
|
|
17
|
+
[
|
|
18
|
+
204,
|
|
19
|
+
{
|
|
20
|
+
"access-control-allow-origin" => origin,
|
|
21
|
+
"access-control-allow-methods" => config[:methods],
|
|
22
|
+
"access-control-allow-headers" => config[:headers],
|
|
23
|
+
"access-control-max-age" => config[:max_age],
|
|
24
|
+
"access-control-allow-credentials" => config[:credentials]
|
|
25
|
+
},
|
|
26
|
+
[""]
|
|
27
|
+
]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Apply CORS headers to a response headers hash
|
|
31
|
+
def apply_headers(response_headers, env = {})
|
|
32
|
+
origin = resolve_origin(env)
|
|
33
|
+
response_headers["access-control-allow-origin"] = origin
|
|
34
|
+
response_headers["access-control-allow-methods"] = config[:methods]
|
|
35
|
+
response_headers["access-control-allow-headers"] = config[:headers]
|
|
36
|
+
response_headers["access-control-max-age"] = config[:max_age]
|
|
37
|
+
response_headers["access-control-allow-credentials"] = config[:credentials] if config[:credentials] == "true"
|
|
38
|
+
response_headers
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Check if a given origin is allowed
|
|
42
|
+
def origin_allowed?(origin)
|
|
43
|
+
return true if config[:origins] == "*"
|
|
44
|
+
|
|
45
|
+
allowed = config[:origins].split(",").map(&:strip)
|
|
46
|
+
allowed.include?(origin)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
def load_config
|
|
52
|
+
{
|
|
53
|
+
origins: ENV["TINA4_CORS_ORIGINS"] || "*",
|
|
54
|
+
methods: ENV["TINA4_CORS_METHODS"] || "GET, POST, PUT, PATCH, DELETE, OPTIONS",
|
|
55
|
+
headers: ENV["TINA4_CORS_HEADERS"] || "Content-Type,Authorization,X-Request-ID",
|
|
56
|
+
max_age: ENV["TINA4_CORS_MAX_AGE"] || "86400",
|
|
57
|
+
credentials: ENV["TINA4_CORS_CREDENTIALS"] || "false"
|
|
58
|
+
}.freeze
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def resolve_origin(env)
|
|
62
|
+
request_origin = env["HTTP_ORIGIN"] || env["HTTP_REFERER"]
|
|
63
|
+
|
|
64
|
+
if config[:origins] == "*"
|
|
65
|
+
"*"
|
|
66
|
+
elsif request_origin && origin_allowed?(request_origin.chomp("/"))
|
|
67
|
+
request_origin.chomp("/")
|
|
68
|
+
else
|
|
69
|
+
""
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|