Module: Railsmith::CrossDomainGuard
- Defined in:
- lib/railsmith/cross_domain_guard.rb
Overview
Detects when a service from one bounded context runs under another domain’s request context (context[:current_domain]). Emits non-blocking cross_domain.warning.railsmith instrumentation by default; optional strict hook runs when strict_mode is enabled.
Class Method Summary collapse
- .allowed_crossing?(allowlist, from_domain, to_domain) ⇒ Boolean
- .allowlisted?(configuration, mismatch) ⇒ Boolean
- .array_pair_matches?(entry, from_domain, to_domain) ⇒ Boolean
- .build_payload(context_domain:, service_domain:, service:, action:, strict_mode:) ⇒ Object
- .domain_mismatch(instance) ⇒ Object
- .emit_if_violation(instance:, action:, configuration: Railsmith.configuration) ⇒ Object
- .hash_pair_matches?(entry, from_domain, to_domain) ⇒ Boolean
- .instrument_payload(base) ⇒ Object
- .pair_matches?(entry, from_domain, to_domain) ⇒ Boolean
- .publish_violation(instance:, action:, configuration:, mismatch:) ⇒ Object
Class Method Details
.allowed_crossing?(allowlist, from_domain, to_domain) ⇒ Boolean
58 59 60 |
# File 'lib/railsmith/cross_domain_guard.rb', line 58 def self.allowed_crossing?(allowlist, from_domain, to_domain) Array(allowlist).any? { |entry| pair_matches?(entry, from_domain, to_domain) } end |
.allowlisted?(configuration, mismatch) ⇒ Boolean
20 21 22 23 24 25 26 |
# File 'lib/railsmith/cross_domain_guard.rb', line 20 def self.allowlisted?(configuration, mismatch) allowed_crossing?( configuration.cross_domain_allowlist, mismatch[:context_domain], mismatch[:service_domain] ) end |
.array_pair_matches?(entry, from_domain, to_domain) ⇒ Boolean
80 81 82 83 84 85 |
# File 'lib/railsmith/cross_domain_guard.rb', line 80 def self.array_pair_matches?(entry, from_domain, to_domain) return false unless entry.size == 2 Context.normalize_current_domain(entry[0]) == from_domain && Context.normalize_current_domain(entry[1]) == to_domain end |
.build_payload(context_domain:, service_domain:, service:, action:, strict_mode:) ⇒ Object
87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/railsmith/cross_domain_guard.rb', line 87 def self.build_payload(context_domain:, service_domain:, service:, action:, strict_mode:) { event: "cross_domain.warning", context_domain: context_domain, service_domain: service_domain, service: service, action: action, strict_mode: strict_mode, blocking: false, occurred_at: Time.now.utc.iso8601(6) } end |
.domain_mismatch(instance) ⇒ Object
49 50 51 52 53 54 55 56 |
# File 'lib/railsmith/cross_domain_guard.rb', line 49 def self.domain_mismatch(instance) context_domain = Context.normalize_current_domain(instance.context[:current_domain]) service_domain = instance.class.domain return nil if context_domain.nil? || service_domain.nil? return nil if context_domain == service_domain { context_domain: context_domain, service_domain: service_domain } end |
.emit_if_violation(instance:, action:, configuration: Railsmith.configuration) ⇒ Object
11 12 13 14 15 16 17 18 |
# File 'lib/railsmith/cross_domain_guard.rb', line 11 def self.emit_if_violation(instance:, action:, configuration: Railsmith.configuration) return unless configuration.warn_on_cross_domain_calls mismatch = domain_mismatch(instance) return if mismatch.nil? || allowlisted?(configuration, mismatch) publish_violation(instance:, action:, configuration:, mismatch:) end |
.hash_pair_matches?(entry, from_domain, to_domain) ⇒ Boolean
73 74 75 76 77 78 |
# File 'lib/railsmith/cross_domain_guard.rb', line 73 def self.hash_pair_matches?(entry, from_domain, to_domain) from_key = entry[:from] || entry["from"] to_key = entry[:to] || entry["to"] Context.normalize_current_domain(from_key) == from_domain && Context.normalize_current_domain(to_key) == to_domain end |
.instrument_payload(base) ⇒ Object
42 43 44 45 46 47 |
# File 'lib/railsmith/cross_domain_guard.rb', line 42 def self.instrument_payload(base) base.merge( log_json_line: CrossDomainWarningFormatter.as_json_line(base), log_kv_line: CrossDomainWarningFormatter.as_key_value_line(base) ) end |
.pair_matches?(entry, from_domain, to_domain) ⇒ Boolean
62 63 64 65 66 67 68 69 70 71 |
# File 'lib/railsmith/cross_domain_guard.rb', line 62 def self.pair_matches?(entry, from_domain, to_domain) case entry when Hash hash_pair_matches?(entry, from_domain, to_domain) when Array array_pair_matches?(entry, from_domain, to_domain) else false end end |
.publish_violation(instance:, action:, configuration:, mismatch:) ⇒ Object
28 29 30 31 32 33 34 35 36 37 38 39 40 |
# File 'lib/railsmith/cross_domain_guard.rb', line 28 def self.publish_violation(instance:, action:, configuration:, mismatch:) base = build_payload( context_domain: mismatch[:context_domain], service_domain: mismatch[:service_domain], service: instance.class.name, action: action, strict_mode: configuration.strict_mode ) payload = instrument_payload(base) Instrumentation.instrument("cross_domain.warning", payload) configuration.on_cross_domain_violation&.call(payload) if configuration.strict_mode end |