letter_thief 0.1.0 → 0.2.0

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: f34879896479445bff76a77165e6f7db08a18880e14df630b76c747f76fc64af
4
- data.tar.gz: 6db1a3fde6c19127cb57a939b48e98cbf4183eab230ede479909279edd687923
3
+ metadata.gz: 967473d3c9121f2d1d82d1d477284f251b0b19666f2511cdde5a1123b58255c2
4
+ data.tar.gz: 174d09ccdf13d992281e8533e565646069f494f36fd49b221dd7c1e665b9e1a0
5
5
  SHA512:
6
- metadata.gz: 5c772c8efb3b683164e883057ed94bea7497643f1aeb32e39f76a8430e25bea178c69a4d79a8178d93c277cca7e7be055b01892ef726649af33952ed79ea1edb
7
- data.tar.gz: 05dfe63a3bfbe3ff7bad33e0ec8e5ca3e46728315cd8ceebabde3d59609b37c69876a991e390f4f9109ec5e3406b178f654aab16dff90f2d6b77b4eb41e9cf25
6
+ metadata.gz: 6233fbd351a7e103122aa373593bd2acab90a4143dc8fb32c31ef71642255bf2a7a796363ea4fe32daca5d0c4c2adb1677fc6a589f39da36bf90b84420838de2
7
+ data.tar.gz: ccf721f2572308ad7e592bc9afeb1c5b902fd27d30f55e97aa414068610891ead8fe1d56516a68bbadc70499674187dc482447d41ad9f813adcecfe79a5b847e
data/README.md CHANGED
@@ -48,6 +48,15 @@ bin/rails db:migrate
48
48
 
49
49
  This will create the necessary tables.
50
50
 
51
+ Mount the engine in your routes, protecting it.
52
+ The code below might be different depending on how you authenticate your users.
53
+
54
+ ```ruby
55
+ authenticate :user, ->(user) { sys_manager&.administrator? } do
56
+ mount LetterThief::Engine => "/letter_thief"
57
+ end
58
+ ```
59
+
51
60
  If you want to stop sending emails, you can use it also as delivery method:
52
61
 
53
62
  ```ruby
@@ -101,6 +110,8 @@ development:
101
110
 
102
111
  ## Development
103
112
 
113
+ Clone the project and install dependencies with `bundle install`.
114
+
104
115
  You can run the tests with `bin/test`. By default they run on sqlite. To run them on postgres or mysql, specify the
105
116
  TARGET_DB.
106
117
 
@@ -110,6 +121,9 @@ TARGET_DB=postgres bin/test #postgres
110
121
  TARGET_DB=mysql bin/test #mysql
111
122
  ```
112
123
 
124
+ You can also sping up a dummy app with `bin/rails server` and work there.
125
+
126
+
113
127
  ## Contributing
114
128
 
115
129
  Bug reports and pull requests are welcome on GitHub at https://github.com/coorasse/letter_thief.
@@ -120,3 +134,7 @@ Try to be a decent human being while interacting with other people.
120
134
 
121
135
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
122
136
 
137
+ ## Credits
138
+
139
+ * [letter_opener](https://github.com/ryanb/letter_opener) is simpler and does not persist emails. This might be indeed
140
+ be better for your use case. It's also the gem that inspired me to create this one.
@@ -4,6 +4,10 @@ module LetterThief
4
4
  class EmailMessagesController < ApplicationController
5
5
  layout "letter_thief/application"
6
6
 
7
+ content_security_policy do |policy|
8
+ policy.style_src :self, :https, :unsafe_inline
9
+ end
10
+
7
11
  PAGE_SIZE = 20
8
12
 
9
13
  def index
@@ -2,7 +2,10 @@ module LetterThief
2
2
  class EmailMessage < ApplicationRecord
3
3
  self.table_name = "letter_thief_email_messages"
4
4
 
5
+ connects_to(**LetterThief.connects_to) if LetterThief.connects_to
6
+
5
7
  has_many_attached :attachments
8
+ has_one_attached :raw_email
6
9
 
7
10
  unless ActiveRecord::Base.connection.adapter_name.downcase.include?("postgresql")
8
11
  serialize :to, coder: JSON, type: Array
@@ -1,7 +1,7 @@
1
1
  <!DOCTYPE html>
2
2
  <html style="height:100%">
3
3
  <head>
4
- <title>Letter thief</title>
4
+ <title><%= yield :title %></title>
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
6
6
  <%= csrf_meta_tags %>
7
7
  <%= csp_meta_tag %>
@@ -1,5 +1,9 @@
1
- <h1>📬 Intercepted Emails</h1>
1
+ <% content_for :title, "Letter Thief" %>
2
2
 
3
+ <h1>📬 Intercepted Emails (Outbox)</h1>
4
+ <p>
5
+ Currently occupying <%= number_to_human_size(LetterThief.used_activestorage_space)%>
6
+ </p>
3
7
  <form method="get" style="margin-bottom: 1rem;">
4
8
  <fieldset class="grid">
5
9
  <label>
@@ -42,6 +46,7 @@
42
46
  <th>To</th>
43
47
  <th>Subject</th>
44
48
  <th>Time</th>
49
+ <th>Size</th>
45
50
  </tr>
46
51
  </thead>
47
52
  <tbody>
@@ -50,11 +55,12 @@
50
55
  <td><%= email.from&.join(", ") %></td>
51
56
  <td><%= email.to&.join(", ") %></td>
52
57
  <td>
53
- <a href="<%= letter_thief.email_message_path(email) %>">
58
+ <a href="<%= email_message_path(email) %>">
54
59
  <%= email.subject.presence || "(no subject)" %>
55
60
  </a>
56
61
  </td>
57
62
  <td><%= email.intercepted_at.strftime("%Y-%m-%d %H:%M") %></td>
63
+ <td><%= number_to_human_size(email.raw_email.byte_size) %></td>
58
64
  </tr>
59
65
  <% end %>
60
66
  </tbody>
@@ -64,7 +70,7 @@
64
70
  <ul style="display: flex; gap: 1rem; list-style: none; padding-left: 0;">
65
71
  <% if @search.page > 1 %>
66
72
  <li>
67
- <%= link_to "← Previous", letter_thief.email_messages_path(
73
+ <%= link_to "← Previous", email_messages_path(
68
74
  query: @search.query,
69
75
  start_time: @search.start_time,
70
76
  end_time: @search.end_time,
@@ -77,7 +83,7 @@
77
83
 
78
84
  <% if @search.has_next_page %>
79
85
  <li>
80
- <%= link_to "Next →", letter_thief.email_messages_path(
86
+ <%= link_to "Next →", email_messages_path(
81
87
  query: @search.query,
82
88
  start_time: @search.start_time,
83
89
  end_time: @search.end_time,
@@ -1,4 +1,6 @@
1
- <p><a href="<%= letter_thief.email_messages_path %>">&larr; Back to Inbox 📬</a></p>
1
+ <% content_for :title, "Message ##{@email.id}" %>
2
+
3
+ <p><a href="<%= email_messages_path %>">&larr; Back to Outbox 📬</a></p>
2
4
 
3
5
  <section id="message_headers">
4
6
  <dl>
@@ -41,6 +43,9 @@
41
43
  </dd>
42
44
  <% end %>
43
45
  </dl>
46
+ <% if @email.raw_email.attached? %>
47
+ <%= link_to "Download", main_app.rails_blob_path(@email.raw_email, disposition: "attachment") %>
48
+ <% end %>
44
49
  </section>
45
50
 
46
51
  <hr>
data/config/routes.rb CHANGED
@@ -1,3 +1,4 @@
1
1
  LetterThief::Engine.routes.draw do
2
2
  resources :email_messages, only: [:index, :show]
3
+ root "email_messages#index"
3
4
  end
@@ -21,7 +21,6 @@ class CreateLetterThiefEmailMessages < ActiveRecord::Migration<%= migration_vers
21
21
  t.text :body_text
22
22
  t.text :body_html
23
23
  t.text :headers
24
- t.text :raw_message
25
24
  t.string :content_type
26
25
  t.datetime :intercepted_at
27
26
 
@@ -1,6 +1,7 @@
1
1
  module LetterThief
2
2
  class Interceptor
3
3
  def self.delivering_email(mail)
4
+ string_io = StringIO.new(mail.to_s)
4
5
  email = EmailMessage.create!(
5
6
  to: mail.to,
6
7
  from: mail.from,
@@ -11,7 +12,6 @@ module LetterThief
11
12
  body_text: mail.text_part&.decoded || mail.body.decoded,
12
13
  body_html: mail.html_part&.decoded,
13
14
  headers: mail.header.to_s,
14
- raw_message: mail.to_s,
15
15
  content_type: mail.content_type,
16
16
  intercepted_at: Time.current
17
17
  )
@@ -25,6 +25,12 @@ module LetterThief
25
25
  ar_attachment.blob.metadata["cid"] = attachment.cid
26
26
  ar_attachment.blob.save!
27
27
  end
28
+
29
+ email.raw_email.attach(
30
+ io: string_io,
31
+ filename: "message-#{email.id}.eml",
32
+ content_type: "message/rfc822"
33
+ )
28
34
  rescue => e
29
35
  Rails.logger.error("[LetterThief] Failed to store intercepted email: #{e.message}")
30
36
  end
@@ -1,3 +1,3 @@
1
1
  module LetterThief
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/letter_thief.rb CHANGED
@@ -2,5 +2,13 @@ require "letter_thief/version"
2
2
  require "letter_thief/engine"
3
3
 
4
4
  module LetterThief
5
- # Your code goes here...
5
+ mattr_accessor :connects_to
6
+
7
+ def self.used_activestorage_space
8
+ ActiveStorage::Blob
9
+ .joins(:attachments)
10
+ .where(active_storage_attachments: {
11
+ record_type: "LetterThief::EmailMessage"
12
+ }).sum(:byte_size)
13
+ end
6
14
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: letter_thief
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alessandro Rodi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-03-25 00:00:00.000000000 Z
11
+ date: 2025-04-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails