glib-web 5.0.5 → 5.0.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:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2e9d0b6eb1a02d147f08a0166a4d67075ebbf903af3601e78ab592c5f9a11808
|
|
4
|
+
data.tar.gz: ee0d8980dfa1158fa65126b8d29dad29e2b788f1b51e4fb062a2de306a1d789a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 21960f43365ee50457f2ad2856d5bf5e6cf6c1a5014332006e9fe43e7f2e6cec9633a35cb5678a34388310d88e69222ab4641d1267125e87e01d822d00fb7e4f
|
|
7
|
+
data.tar.gz: cf920f5f56177c092fc2bd84bacf4b096d1b41ae4364b47bcfe3beba1b58bb8afa76883a33210a9f9ad709085c7dc33644933128cddbe93b4ff2251e6f2367b5
|
|
@@ -38,7 +38,16 @@ module Glib::Analytics
|
|
|
38
38
|
referrer_url = request.headers['referer'] # Notice that the HTTP header uses one "r"
|
|
39
39
|
if group.nil? && action.nil? && !referrer_url.nil?
|
|
40
40
|
current_host = request.host
|
|
41
|
-
|
|
41
|
+
# The Referer header is attacker-controlled and may not be a valid URI
|
|
42
|
+
# (scanners send junk like "() { ignored; }; cat /etc/passwd"). Treat an
|
|
43
|
+
# unparseable referer as "no referer" rather than letting URI::InvalidURIError
|
|
44
|
+
# bubble up mid-render, where the 500 rescue then double-renders.
|
|
45
|
+
referrer_host =
|
|
46
|
+
begin
|
|
47
|
+
URI.parse(referrer_url).host
|
|
48
|
+
rescue URI::InvalidURIError
|
|
49
|
+
nil
|
|
50
|
+
end
|
|
42
51
|
|
|
43
52
|
# Replace the subdomain portion with regex so it will only match the non-subdomain part.
|
|
44
53
|
# This will allow cross-subdomain referral, but it will not work if the host is a bare domain,
|
|
@@ -249,6 +249,13 @@ module Glib::Json::Libs
|
|
|
249
249
|
Rollbar.error(exception, use_exception_level_filters: true)
|
|
250
250
|
end
|
|
251
251
|
|
|
252
|
+
# The exception may have been raised AFTER a response was already rendered
|
|
253
|
+
# (e.g. from an after_action injection). Rendering the error page on top of that
|
|
254
|
+
# would raise AbstractController::DoubleRenderError, which masks the genuine
|
|
255
|
+
# exception reported above. The real cause is already logged, so leave the
|
|
256
|
+
# already-rendered response in place rather than double-rendering.
|
|
257
|
+
return if performed?
|
|
258
|
+
|
|
252
259
|
render file: Rails.root.join('public', '500.html'), status: :internal_server_error
|
|
253
260
|
else
|
|
254
261
|
raise exception
|
|
@@ -261,6 +268,12 @@ module Glib::Json::Libs
|
|
|
261
268
|
def glib_json_handle_404(exception, preview_mode)
|
|
262
269
|
if json_ui_activated?
|
|
263
270
|
if Rails.env.production? || preview_mode
|
|
271
|
+
# As with glib_json_handle_500: if a response was already rendered (e.g. an
|
|
272
|
+
# after_action raised RecordNotFound), rendering the 404 page on top would raise
|
|
273
|
+
# AbstractController::DoubleRenderError and mask the real exception. Keep the
|
|
274
|
+
# already-rendered response instead of double-rendering.
|
|
275
|
+
return if performed?
|
|
276
|
+
|
|
264
277
|
render file: Rails.root.join('public', '404.html'), status: :not_found
|
|
265
278
|
else
|
|
266
279
|
raise exception
|
data/lib/glib/mailer_tester.rb
CHANGED
|
@@ -8,11 +8,7 @@ module Glib
|
|
|
8
8
|
|
|
9
9
|
module ClassMethods
|
|
10
10
|
def generate_preview_tests
|
|
11
|
-
|
|
12
|
-
paths = Dir.glob(project_root + 'test/mailers/previews/*')
|
|
13
|
-
paths.each do |file|
|
|
14
|
-
require file
|
|
15
|
-
end
|
|
11
|
+
Glib::MailerTester.load_preview_files
|
|
16
12
|
|
|
17
13
|
ActionMailer::Preview.subclasses.each do |preview_class|
|
|
18
14
|
preview = preview_class.new
|
|
@@ -45,6 +41,95 @@ module Glib
|
|
|
45
41
|
end
|
|
46
42
|
end
|
|
47
43
|
end
|
|
44
|
+
|
|
45
|
+
# Opt-in companion to `generate_preview_tests`. That method only snapshot-tests
|
|
46
|
+
# the previews that EXIST; this asserts every mailer ACTION has a matching
|
|
47
|
+
# preview, so a new mailer/action can't silently ship with no preview.
|
|
48
|
+
#
|
|
49
|
+
# `except:` allowlists "Mailer#action" strings that intentionally have no
|
|
50
|
+
# preview — document the reason at the call site.
|
|
51
|
+
def assert_all_mailer_actions_have_previews(except: [])
|
|
52
|
+
test 'every mailer action has a preview' do
|
|
53
|
+
missing = Glib::MailerTester.missing_previews(except: except)
|
|
54
|
+
assert missing.empty?, Glib::MailerTester.missing_previews_message(missing)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# --- Preview coverage (companion to generate_preview_tests) ---------------
|
|
60
|
+
|
|
61
|
+
# Loads every preview file (idempotent — `require` no-ops if already loaded).
|
|
62
|
+
def self.load_preview_files
|
|
63
|
+
Dir.glob(Rails.root + 'test/mailers/previews/*').each { |file| require file }
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Sorted Array<String> of "Mailer#action" entries that have no preview.
|
|
67
|
+
def self.missing_previews(except: [])
|
|
68
|
+
load_preview_files
|
|
69
|
+
compute_missing_previews(
|
|
70
|
+
mailer_actions: reflect_mailer_actions,
|
|
71
|
+
previewed_actions: ->(mailer) { reflect_preview_methods(mailer) },
|
|
72
|
+
except: except
|
|
73
|
+
)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Pure (no Rails reflection) so it is unit-testable.
|
|
77
|
+
# mailer_actions: { "FooMailer" => ["welcome", "goodbye"] }
|
|
78
|
+
# previewed_actions: ->(mailer_name) { ["welcome"] }
|
|
79
|
+
# except: ["FooMailer#goodbye"]
|
|
80
|
+
def self.compute_missing_previews(mailer_actions:, previewed_actions:, except: [])
|
|
81
|
+
excluded = except.map(&:to_s).to_set
|
|
82
|
+
mailer_actions.flat_map do |mailer, actions|
|
|
83
|
+
previewed = Array(previewed_actions.call(mailer)).map(&:to_s).to_set
|
|
84
|
+
actions.map(&:to_s)
|
|
85
|
+
.reject { |action| previewed.include?(action) }
|
|
86
|
+
.map { |action| "#{mailer}##{action}" }
|
|
87
|
+
end.reject { |id| excluded.include?(id) }.sort
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def self.missing_previews_message(missing)
|
|
91
|
+
<<~MSG
|
|
92
|
+
Every mailer action must have a preview so `generate_preview_tests` snapshot-tests it.
|
|
93
|
+
These actions have none:
|
|
94
|
+
|
|
95
|
+
#{missing.join("\n ")}
|
|
96
|
+
|
|
97
|
+
Add a method named after the action to the matching `<Mailer>Preview` class under
|
|
98
|
+
test/mailers/previews/, returning `<Mailer>.<action>(...)`. If an action genuinely
|
|
99
|
+
cannot be previewed, allowlist it with a reason:
|
|
100
|
+
|
|
101
|
+
assert_all_mailer_actions_have_previews(except: ['FooMailer#some_action']) # why
|
|
102
|
+
MSG
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Reflection glue (needs a loaded Rails app). Scopes to app mailers under
|
|
106
|
+
# `ApplicationMailer` so third-party mailers (Devise, etc.) are not flagged.
|
|
107
|
+
def self.reflect_mailer_actions
|
|
108
|
+
load_mailer_files
|
|
109
|
+
base = '::ApplicationMailer'.safe_constantize || ActionMailer::Base
|
|
110
|
+
base.descendants.each_with_object({}) do |mailer, acc|
|
|
111
|
+
actions = mailer.action_methods.to_a
|
|
112
|
+
acc[mailer.name] = actions unless actions.empty?
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Loads only `app/mailers` (so every mailer subclass is defined) rather than
|
|
117
|
+
# eager-loading the whole app — faster, and avoids unrelated load failures.
|
|
118
|
+
def self.load_mailer_files
|
|
119
|
+
dir = Rails.root.join('app/mailers')
|
|
120
|
+
return unless dir.exist?
|
|
121
|
+
|
|
122
|
+
loader = Rails.respond_to?(:autoloaders) ? Rails.autoloaders.main : nil
|
|
123
|
+
if loader.respond_to?(:eager_load_dir)
|
|
124
|
+
loader.eager_load_dir(dir.to_s)
|
|
125
|
+
else
|
|
126
|
+
Rails.application.eager_load!
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def self.reflect_preview_methods(mailer_name)
|
|
131
|
+
preview = "#{mailer_name}Preview".safe_constantize
|
|
132
|
+
preview ? preview.instance_methods(false).map(&:to_s) : []
|
|
48
133
|
end
|
|
49
134
|
|
|
50
135
|
def log_root_dir
|