Class: Mailscope::BodyRenderer
- Inherits:
-
Object
- Object
- Mailscope::BodyRenderer
- Defined in:
- lib/mailscope/body_renderer.rb
Overview
Builds the document that goes inside the preview iframe.
The body is never rewritten with blind gsubs the way letter_opener_web did it. Inline (cid:) images become data: URIs so the frame can stay in a fully sandboxed opaque origin, and everything else is controlled with a Content-Security-Policy response header rather than by editing the markup.
Constant Summary collapse
- MAX_INLINE_BYTES =
2 * 1024 * 1024
- REMOTE_ASSET =
/\b(?:src|background)\s*=\s*["']?\s*https?:/i- REMOTE_CSS_ASSET =
/url\(\s*["']?\s*https?:/i- URL_IN_TEXT =
%r{\bhttps?://[^\s<>"')\]]+}
Instance Attribute Summary collapse
-
#block_remote ⇒ Object
readonly
Returns the value of attribute block_remote.
-
#message ⇒ Object
readonly
Returns the value of attribute message.
-
#part ⇒ Object
readonly
Returns the value of attribute part.
-
#theme ⇒ Object
readonly
Returns the value of attribute theme.
Instance Method Summary collapse
-
#blocked_resources ⇒ Object
How many remote assets the current policy is holding back.
- #content_security_policy ⇒ Object
- #dark? ⇒ Boolean
- #document ⇒ Object
- #empty? ⇒ Boolean
-
#initialize(message, part: nil, block_remote: true, theme: 'light') ⇒ BodyRenderer
constructor
A new instance of BodyRenderer.
Constructor Details
#initialize(message, part: nil, block_remote: true, theme: 'light') ⇒ BodyRenderer
Returns a new instance of BodyRenderer.
21 22 23 24 25 26 |
# File 'lib/mailscope/body_renderer.rb', line 21 def initialize(, part: nil, block_remote: true, theme: 'light') @message = @part = %w[html text].include?(part.to_s) ? part.to_s : .default_part @block_remote = block_remote @theme = theme.to_s == 'dark' ? 'dark' : 'light' end |
Instance Attribute Details
#block_remote ⇒ Object (readonly)
Returns the value of attribute block_remote.
19 20 21 |
# File 'lib/mailscope/body_renderer.rb', line 19 def block_remote @block_remote end |
#message ⇒ Object (readonly)
Returns the value of attribute message.
19 20 21 |
# File 'lib/mailscope/body_renderer.rb', line 19 def @message end |
#part ⇒ Object (readonly)
Returns the value of attribute part.
19 20 21 |
# File 'lib/mailscope/body_renderer.rb', line 19 def part @part end |
#theme ⇒ Object (readonly)
Returns the value of attribute theme.
19 20 21 |
# File 'lib/mailscope/body_renderer.rb', line 19 def theme @theme end |
Instance Method Details
#blocked_resources ⇒ Object
How many remote assets the current policy is holding back. Surfaced in the UI so "why is this email blank?" answers itself.
63 64 65 66 67 |
# File 'lib/mailscope/body_renderer.rb', line 63 def blocked_resources return 0 unless block_remote @blocked_resources ||= raw_body.to_s.scan(REMOTE_ASSET).size + raw_body.to_s.scan(REMOTE_CSS_ASSET).size end |
#content_security_policy ⇒ Object
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/mailscope/body_renderer.rb', line 45 def content_security_policy directives = [ "default-src 'none'", "style-src 'unsafe-inline' data:", 'font-src data:', "frame-src 'none'", "object-src 'none'", "script-src 'none'", "form-action 'none'", "base-uri 'none'" ] directives << (block_remote ? 'img-src data:' : 'img-src data: https: http:') directives << (block_remote ? "media-src 'none'" : 'media-src data: https: http:') directives.join('; ') end |
#dark? ⇒ Boolean
28 |
# File 'lib/mailscope/body_renderer.rb', line 28 def dark? = theme == 'dark' |
#document ⇒ Object
30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/mailscope/body_renderer.rb', line 30 def document <<~HTML <!doctype html> <html lang="pt-BR"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <base target="_blank"> <style>#{frame_styles}</style> </head> <body class="mailscope-frame mailscope-frame--#{part} mailscope-frame--#{theme}">#{body}</body> </html> HTML end |
#empty? ⇒ Boolean
69 |
# File 'lib/mailscope/body_renderer.rb', line 69 def empty? = raw_body.to_s.strip.empty? |