mail2cb 0.0.6 → 0.0.8
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/.rspec +2 -0
- data/Dockerfile +37 -0
- data/README.md +13 -0
- data/Rakefile +11 -0
- data/bin/mail2cb +25 -6
- data/bin/run +36 -0
- data/lib/mail2cb/{email_body_parser.rb → email_body_cleanser.rb} +1 -1
- data/lib/mail2cb/email_content.rb +44 -0
- data/lib/mail2cb/email_handler.rb +89 -61
- data/lib/mail2cb/email_watcher.rb +78 -14
- data/lib/mail2cb/encryption.rb +44 -25
- data/lib/mail2cb/message_id_handler.rb +63 -0
- data/lib/mail2cb/version.rb +1 -1
- data/lib/mail2cb.rb +4 -1
- data/mail2cb.gemspec +10 -4
- data/samples/bare_bones.txt +5 -0
- data/samples/reply.txt +226 -0
- data/samples/reply_message_id_in_body.txt +416 -0
- data/samples/reply_with_cc.txt +455 -0
- data/spec/hash_key_matcher.rb +22 -0
- data/spec/helpers.rb +14 -0
- data/spec/mail2cb/email_content_spec.rb +27 -0
- data/spec/mail2cb/email_handler_spec.rb +190 -0
- data/spec/mail2cb/email_watcher_spec.rb +61 -0
- data/spec/mail2cb/encryption_spec.rb +47 -0
- data/spec/mail2cb/message_id_handler_spec.rb +35 -0
- data/spec/spec_helper.rb +15 -0
- metadata +109 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 03e52a01d9c2465caaeb3874951ce00a3f0b3647
|
4
|
+
data.tar.gz: e055dcdc4ea7f9b5bd89ef1678549e499fda2cea
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9e5d2e47b37b64fd4e7a31897d7d779cc47bb771ca9bab299dcfad554393e1411077ce0a4414d40ca0b8c81a2690444b8d42099ca067ef0639f3d4f5a3f3d886
|
7
|
+
data.tar.gz: edd382fae7014b10ed07ecdc3b61b094207c37659b3eb1d34d1f4163659f14b492818c66170ae78d5841b6d40090f15b5d5db9509ce43fa8b5dfb63fedd28ed7
|
data/.rspec
ADDED
data/Dockerfile
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# CaseBlocks Mail2cb Daemon
|
2
|
+
#
|
3
|
+
# VERSION 0.0.1
|
4
|
+
|
5
|
+
FROM caseblocks/ruby_node
|
6
|
+
MAINTAINER support@caseblocks.com
|
7
|
+
|
8
|
+
RUN apt-get update -y && apt-get install -y build-essential libmysqlclient-dev vim git-core ca-certificates && mkdir -p /var/www/mail2cb
|
9
|
+
|
10
|
+
RUN gem update bundler
|
11
|
+
|
12
|
+
ADD . /var/www/mail2cb
|
13
|
+
WORKDIR /var/www/mail2cb
|
14
|
+
|
15
|
+
|
16
|
+
RUN /usr/sbin/useradd --create-home --home-dir /usr/local/nonroot --shell /bin/bash nonroot
|
17
|
+
RUN /usr/sbin/adduser nonroot sudo
|
18
|
+
|
19
|
+
RUN groupadd mail2cb
|
20
|
+
RUN usermod -a -G mail2cb nonroot
|
21
|
+
RUN usermod -a -G mail2cb root
|
22
|
+
|
23
|
+
|
24
|
+
RUN chown -R nonroot /usr/local/
|
25
|
+
RUN chown -R nonroot /usr/lib/
|
26
|
+
RUN chown -R nonroot /usr/bin/
|
27
|
+
RUN chgrp -R mail2cb /var/lib/gems
|
28
|
+
RUN chmod -R g+w /var/lib/gems
|
29
|
+
RUN chown -R nonroot /var/www/mail2cb
|
30
|
+
|
31
|
+
USER nonroot
|
32
|
+
|
33
|
+
RUN cd /var/www/mail2cb
|
34
|
+
RUN bundle install
|
35
|
+
|
36
|
+
EXPOSE 8016
|
37
|
+
CMD bin/run
|
data/README.md
CHANGED
@@ -38,6 +38,19 @@ Ensure the following environment variables are set:
|
|
38
38
|
CB_API_ENDPOINT=https://login.caseblocks.com
|
39
39
|
CB_API_TOKEN=...
|
40
40
|
|
41
|
+
MYSQL_HOST
|
42
|
+
MYSQL_PORT
|
43
|
+
MYSQL_DATABASE
|
44
|
+
MYSQL_USERNAME
|
45
|
+
MYSQL_PASSWORD
|
46
|
+
FAYE_HOST
|
47
|
+
FAYE_PORT
|
48
|
+
DEBUG
|
49
|
+
AWS_ACCESS_KEY
|
50
|
+
AWS_SECRET_KEY
|
51
|
+
AWS_MAILROOM_BUCKET
|
52
|
+
CRYPT_API_ENDPOINT
|
53
|
+
|
41
54
|
And run the daemon from the CLI
|
42
55
|
|
43
56
|
mail2cb
|
data/Rakefile
CHANGED
@@ -1,2 +1,13 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
2
|
|
3
|
+
task :console do
|
4
|
+
require 'irb'
|
5
|
+
require 'irb/completion'
|
6
|
+
require 'mail2cb' # You know what to do.
|
7
|
+
ARGV.clear
|
8
|
+
|
9
|
+
@sample_reply = File.read("samples/reply.txt")
|
10
|
+
@sample_reply_with_cc = File.read("samples/reply_with_cc.txt")
|
11
|
+
|
12
|
+
IRB.start
|
13
|
+
end
|
data/bin/mail2cb
CHANGED
@@ -5,12 +5,31 @@ require 'bundler/setup'
|
|
5
5
|
# its dependencies:
|
6
6
|
require 'mail2cb'
|
7
7
|
|
8
|
-
ENV["
|
9
|
-
ENV["MYSQL_HOST"] = "localhost" unless ENV["MYSQL_HOST"]
|
10
|
-
ENV["MYSQL_PORT"] = "3306"
|
11
|
-
ENV["MYSQL_DATABASE"] = "caseblocks_dev"
|
8
|
+
if ENV["MYSQL_PORT_3306_TCP_ADDR"].nil? or ENV["MYSQL_PORT_3306_TCP_PORT"].nil?
|
9
|
+
ENV["MYSQL_HOST"] = "localhost" unless ENV["MYSQL_HOST"]
|
10
|
+
ENV["MYSQL_PORT"] = "3306"
|
11
|
+
ENV["MYSQL_DATABASE"] = "caseblocks_dev" unless ENV["MYSQL_DATABASE"]
|
12
|
+
ENV["MYSQL_USERNAME"] = "root" unless ENV["MYSQL_USERNAME"]
|
13
|
+
ENV["MYSQL_PASSWORD"] = "" unless ENV["MYSQL_PASSWORD"]
|
14
|
+
else
|
15
|
+
ENV["MYSQL_HOST"] = ENV["MYSQL_PORT_3306_TCP_ADDR"]
|
16
|
+
ENV["MYSQL_PORT"] = ENV["MYSQL_PORT_3306_TCP_PORT"]
|
17
|
+
ENV["MYSQL_USERNAME"] = ENV["MYSQL_USER"]
|
18
|
+
end
|
12
19
|
|
13
|
-
ENV["MYSQL_USERNAME"]
|
14
|
-
|
20
|
+
puts "Connecting to MySQL: #{ENV["MYSQL_USERNAME"]}@#{ENV["MYSQL_HOST"]}:#{ENV["MYSQL_PORT"]}/#{ENV["MYSQL_DATABASE"]}"
|
21
|
+
|
22
|
+
if ENV["REDIS_PORT_6379_TCP_ADDR"].nil? or ENV["REDIS_PORT_6379_TCP_PORT"].nil?
|
23
|
+
ENV["REDIS_URL"] = "redis://localhost:6379" unless ENV["REDIS_URL"]
|
24
|
+
else
|
25
|
+
ENV["REDIS_URL"] = "redis://#{ENV["REDIS_PORT_6379_TCP_ADDR"]}:#{ENV["REDIS_PORT_6379_TCP_PORT"]}"
|
26
|
+
end
|
27
|
+
|
28
|
+
puts "Connecting to Redis: #{ENV["REDIS_URL"]}"
|
29
|
+
|
30
|
+
ENV["FAYE_HOST"] = "http://localhost"
|
31
|
+
ENV["FAYE_PORT"] = "9292"
|
32
|
+
|
33
|
+
ENV["DEBUG"] = "false"
|
15
34
|
|
16
35
|
oh = Mail2cb::Handler.new
|
data/bin/run
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler/setup'
|
5
|
+
# Prepares the $LOAD_PATH by adding to it lib directories of the gem and
|
6
|
+
# its dependencies:
|
7
|
+
require 'mail2cb'
|
8
|
+
|
9
|
+
if ENV["MYSQL_PORT_3306_TCP_ADDR"].nil? or ENV["MYSQL_PORT_3306_TCP_PORT"].nil?
|
10
|
+
ENV["MYSQL_HOST"] = "localhost" unless ENV["MYSQL_HOST"]
|
11
|
+
ENV["MYSQL_PORT"] = "3306"
|
12
|
+
ENV["MYSQL_DATABASE"] = "caseblocks_dev" unless ENV["MYSQL_DATABASE"]
|
13
|
+
ENV["MYSQL_USERNAME"] = "root" unless ENV["MYSQL_USERNAME"]
|
14
|
+
ENV["MYSQL_PASSWORD"] = "" unless ENV["MYSQL_PASSWORD"]
|
15
|
+
else
|
16
|
+
ENV["MYSQL_HOST"] = ENV["MYSQL_PORT_3306_TCP_ADDR"]
|
17
|
+
ENV["MYSQL_PORT"] = ENV["MYSQL_PORT_3306_TCP_PORT"]
|
18
|
+
ENV["MYSQL_USERNAME"] = ENV["MYSQL_USER"]
|
19
|
+
end
|
20
|
+
|
21
|
+
puts "Connecting to MySQL: #{ENV["MYSQL_USERNAME"]}@#{ENV["MYSQL_HOST"]}:#{ENV["MYSQL_PORT"]}/#{ENV["MYSQL_DATABASE"]}"
|
22
|
+
|
23
|
+
if ENV["REDIS_PORT_6379_TCP_ADDR"].nil? or ENV["REDIS_PORT_6379_TCP_PORT"].nil?
|
24
|
+
ENV["REDIS_URL"] = "redis://localhost:6379" unless ENV["REDIS_URL"]
|
25
|
+
else
|
26
|
+
ENV["REDIS_URL"] = "redis://#{ENV["REDIS_PORT_6379_TCP_ADDR"]}:#{ENV["REDIS_PORT_6379_TCP_PORT"]}"
|
27
|
+
end
|
28
|
+
|
29
|
+
puts "Connecting to Redis: #{ENV["REDIS_URL"]}"
|
30
|
+
|
31
|
+
ENV["FAYE_HOST"] = "http://localhost"
|
32
|
+
ENV["FAYE_PORT"] = "9292"
|
33
|
+
|
34
|
+
ENV["DEBUG"] = "false"
|
35
|
+
|
36
|
+
oh = Mail2cb::Handler.new
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Mail2cb
|
2
|
+
class EmailContent
|
3
|
+
|
4
|
+
def initialize(email)
|
5
|
+
@email = email
|
6
|
+
|
7
|
+
if @email.multipart?
|
8
|
+
parse_parts(@email.parts)
|
9
|
+
else
|
10
|
+
@text_body = @email.body.decoded.force_encoding("ASCII-8BIT").encode('UTF-8', undef: :replace, replace: '')
|
11
|
+
end
|
12
|
+
@body = @html_body || @text_body
|
13
|
+
end
|
14
|
+
|
15
|
+
def parse_parts(parts)
|
16
|
+
parts.each do |part|
|
17
|
+
content_type = part.content_type.split(";")[0]
|
18
|
+
if content_type == "text/html"
|
19
|
+
@html_body = part.body.decoded.force_encoding("ASCII-8BIT").encode('UTF-8', undef: :replace, replace: '')
|
20
|
+
elsif content_type == "text/plain"
|
21
|
+
@text_body = part.body.decoded.force_encoding("ASCII-8BIT").encode('UTF-8', undef: :replace, replace: '')
|
22
|
+
elsif content_type == "multipart/related"
|
23
|
+
parse_parts(part.parts)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def html
|
29
|
+
@html_body
|
30
|
+
end
|
31
|
+
|
32
|
+
def text
|
33
|
+
@text_body
|
34
|
+
end
|
35
|
+
|
36
|
+
def body
|
37
|
+
@body
|
38
|
+
end
|
39
|
+
def body=(value)
|
40
|
+
@body = value
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
@@ -1,113 +1,141 @@
|
|
1
1
|
require 'fileutils'
|
2
2
|
require 'mail'
|
3
|
-
require_relative "email_body_parser"
|
4
3
|
require 'nokogiri'
|
5
4
|
require 'sanitize'
|
5
|
+
require 'aws/s3'
|
6
|
+
|
7
|
+
include Mail::Utilities
|
6
8
|
|
7
9
|
module Mail2cb
|
8
10
|
class EmailHandler
|
11
|
+
|
12
|
+
TWENTYFOUR_HOURS = 60 * 60 * 24
|
13
|
+
|
9
14
|
def initialize(options)
|
10
15
|
@options = options
|
16
|
+
|
17
|
+
raise "Require :inbound_message to be passed in" unless options.has_key?(:inbound_message)
|
18
|
+
raise "Require :mailbox to be passed in" unless options.has_key?(:mailbox)
|
19
|
+
|
11
20
|
@email = Mail.read_from_string(options[:inbound_message])
|
12
21
|
|
13
|
-
puts "
|
14
|
-
|
15
|
-
|
16
|
-
@email.parts.each do |part|
|
17
|
-
content_type = part.content_type.split(";")[0]
|
18
|
-
if content_type[0..3] == "text"
|
19
|
-
if content_type == "text/html"
|
20
|
-
@html_body = part.body.decoded.force_encoding("ASCII-8BIT").encode('UTF-8', undef: :replace, replace: '')
|
21
|
-
elsif content_type == "text/plain"
|
22
|
-
@text_body = part.body.decoded.force_encoding("ASCII-8BIT").encode('UTF-8', undef: :replace, replace: '')
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
else
|
27
|
-
@text_body = @email.body.decoded.force_encoding("ASCII-8BIT").encode('UTF-8', undef: :replace, replace: '')
|
28
|
-
end
|
22
|
+
puts "Inbound email from #{@email.from.join(", ")}"
|
23
|
+
@content = EmailContent.new(@email)
|
24
|
+
end
|
29
25
|
|
30
|
-
|
26
|
+
def email
|
27
|
+
@email
|
31
28
|
end
|
32
29
|
|
33
30
|
def generate_message_hash
|
34
|
-
|
35
31
|
message_hash = {
|
36
|
-
"from" => @email.
|
37
|
-
"to" => @email.to,
|
32
|
+
"from" => format_recipient(Mail::Address.new(@email[:from].value)),
|
38
33
|
"subject" => @email.subject,
|
39
|
-
"
|
40
|
-
"
|
41
|
-
"
|
34
|
+
"sent_at" => @email.date.rfc3339,
|
35
|
+
"received_at" => DateTime.now.rfc3339,
|
36
|
+
"body" => @content.body,
|
37
|
+
"attachments" => prepare_attachments,
|
42
38
|
"metadata" => fetch_metadata
|
43
39
|
}
|
40
|
+
message_hash["to"] = format_recipients(@email[:to].address_list.addresses) if @email[:to]
|
41
|
+
message_hash["cc"] = format_recipients(@email[:cc].address_list.addresses) if @email[:cc]
|
42
|
+
|
44
43
|
message_hash.delete(:inbound_message)
|
45
44
|
message_hash
|
46
45
|
end
|
47
46
|
|
47
|
+
def format_recipients(recipients)
|
48
|
+
recipients.map{|recipient| format_recipient(recipient)}
|
49
|
+
end
|
50
|
+
def format_recipient(recipient)
|
51
|
+
{:email => recipient.address, :display_name => recipient.display_name, :account_code => @options[:mailbox][:account_code]}
|
52
|
+
end
|
53
|
+
|
48
54
|
def fetch_metadata
|
49
|
-
|
55
|
+
id_parser = MessageIdHandler.new(@email)
|
56
|
+
{
|
50
57
|
"has_bounced" => @email.bounced?,
|
51
58
|
"in_reply_to" => @email.in_reply_to,
|
52
59
|
"message_id" => @email.message_id,
|
53
|
-
"
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
def references
|
58
|
-
@email.header["References"] ? @email.header["References"].field.element.message_ids : []
|
59
|
-
end
|
60
|
-
|
61
|
-
def fetch_fingerprints
|
62
|
-
previous_id = references.last
|
63
|
-
match = /(.*?)\.(.*?)@emergeadapt.com/.match(previous_id)
|
64
|
-
if match
|
65
|
-
if match[2] == "case"
|
66
|
-
{"case_id" => match[1]}
|
67
|
-
else
|
68
|
-
{"message_id" => match[1]}
|
69
|
-
end
|
70
|
-
else
|
71
|
-
{}
|
72
|
-
end
|
60
|
+
"account_code" => @options[:mailbox][:account_code],
|
61
|
+
"references" => id_parser.references
|
62
|
+
}.merge(id_parser.hash)
|
73
63
|
end
|
74
64
|
|
75
65
|
def prepare_attachments
|
76
66
|
attachments = []
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
"
|
86
|
-
|
87
|
-
|
67
|
+
if ENV["AWS_ACCESS_KEY"] && ENV["AWS_SECRET_KEY"] && ENV["AWS_MAILROOM_BUCKET"]
|
68
|
+
AWS::S3::Base.establish_connection!(
|
69
|
+
:access_key_id => ENV["AWS_ACCESS_KEY"],
|
70
|
+
:secret_access_key => ENV["AWS_SECRET_KEY"]
|
71
|
+
)
|
72
|
+
@email.attachments.each do |attachment|
|
73
|
+
filename = attachment.filename
|
74
|
+
bucket_name = ENV["AWS_MAILROOM_BUCKET"]
|
75
|
+
path = ["", "attachments", @options[:mailbox][:account_code], unique_email_code, filename].join("/")
|
76
|
+
AWS::S3::S3Object.store(path, attachment.body.decoded, bucket_name)
|
77
|
+
url = AWS::S3::S3Object.url_for("#{path}", bucket_name, :expires_in => EmailHandler::TWENTYFOUR_HOURS)
|
78
|
+
|
79
|
+
attachments << {
|
80
|
+
"storage_type" => "S3",
|
81
|
+
"filename" => attachment.filename,
|
82
|
+
"filepath" => "/#{bucket_name}#{path}",
|
83
|
+
"url" => url
|
84
|
+
}
|
85
|
+
end
|
86
|
+
else
|
87
|
+
@email.attachments.each do | attachment |
|
88
|
+
filename = attachment.filename
|
89
|
+
random_tag = Random.rand(100000000000)
|
90
|
+
attachment_folder = File.join(["/", "tmp", "caseblocks", "attachments", @options[:mailbox][:account_code], unique_email_code])
|
91
|
+
FileUtils::mkdir_p(attachment_folder)
|
92
|
+
file_path = File.join([attachment_folder, "#{random_tag}.#{filename}"])
|
93
|
+
File.open(file_path, "w+b", 0644) {|f| f.write attachment.body.decoded}
|
94
|
+
attachments << {
|
95
|
+
"storage_type" => "FILE",
|
96
|
+
"filename" => attachment.filename,
|
97
|
+
"filepath" => file_path
|
98
|
+
}
|
99
|
+
end
|
88
100
|
end
|
89
101
|
attachments
|
90
102
|
end
|
91
103
|
|
104
|
+
def unique_email_code
|
105
|
+
md5 = Digest::MD5.new
|
106
|
+
md5.update @email.raw_source
|
107
|
+
|
108
|
+
md5.hexdigest
|
109
|
+
end
|
92
110
|
|
93
111
|
def content_type
|
94
|
-
@
|
112
|
+
@content.html.nil? ? "text/plain" : "text/html"
|
95
113
|
end
|
96
114
|
|
97
115
|
def sanitize!
|
98
|
-
@body = Sanitize.fragment(@body, Sanitize::Config::RELAXED)
|
116
|
+
@content.body = Sanitize.fragment(@content.body, Sanitize::Config::RELAXED)
|
99
117
|
end
|
100
118
|
|
101
119
|
def clean_replies!
|
102
|
-
@body = Mail2cb::
|
120
|
+
@content.body = Mail2cb::EmailBodyCleanser.parse(@content.body, content_type)
|
103
121
|
end
|
104
122
|
|
105
123
|
def queue!
|
106
|
-
|
124
|
+
# puts "___________________________________________________________________________"
|
125
|
+
puts "Queueing on redis #{redis_key(@options)}"
|
126
|
+
ap generate_message_hash
|
127
|
+
# puts "___________________________________________________________________________"
|
128
|
+
$redis.lpush(redis_key(@options), generate_message_hash.to_json)
|
107
129
|
end
|
108
130
|
|
109
131
|
def body
|
110
|
-
@body
|
132
|
+
@content.body
|
111
133
|
end
|
134
|
+
|
135
|
+
private
|
136
|
+
def redis_key(options)
|
137
|
+
"cb:comms:#{options[:mailbox][:account_code]}:inbox"
|
138
|
+
end
|
139
|
+
|
112
140
|
end
|
113
141
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'redis'
|
2
2
|
require 'ap'
|
3
3
|
require 'mysql2'
|
4
|
+
require 'faye'
|
4
5
|
|
5
6
|
module Mail2cb
|
6
7
|
class EmailWatcher
|
@@ -13,8 +14,14 @@ module Mail2cb
|
|
13
14
|
raise "MYSQL_USERNAME environment variable is required" unless ENV["MYSQL_USERNAME"]
|
14
15
|
raise "MYSQL_PASSWORD environment variable is required" unless ENV["MYSQL_PASSWORD"]
|
15
16
|
|
17
|
+
unless ENV["AWS_ACCESS_KEY"] && ENV["AWS_SECRET_KEY"] && ENV["AWS_MAILROOM_BUCKET"]
|
18
|
+
puts "WARNING: Attachments will store to local file system as AWS keys not provided"
|
19
|
+
end
|
20
|
+
|
21
|
+
|
16
22
|
ENV["MYSQL_PASSWORD"] = "" unless ENV["MYSQL_PASSWORD"]
|
17
23
|
ENV["MYSQL_PORT"] = "3306"
|
24
|
+
@debug = ENV["DEBUG"] == "true"
|
18
25
|
|
19
26
|
redis_url = URI.parse(ENV["REDIS_URL"])
|
20
27
|
|
@@ -28,7 +35,7 @@ module Mail2cb
|
|
28
35
|
Thread.new {self.stop}.join
|
29
36
|
}
|
30
37
|
|
31
|
-
@daemon = MailDaemon::Handler.new(:connections => configuration)
|
38
|
+
@daemon = MailDaemon::Handler.new(:connections => configuration, :debug => @debug)
|
32
39
|
end
|
33
40
|
|
34
41
|
def start
|
@@ -46,12 +53,39 @@ module Mail2cb
|
|
46
53
|
def configuration
|
47
54
|
mailboxes = []
|
48
55
|
mysql_client do |mysql|
|
49
|
-
|
56
|
+
sql=<<EOS
|
57
|
+
SELECT case_blocks_email_accounts.id,
|
58
|
+
case_blocks_accounts.id as account_id,
|
59
|
+
case_blocks_accounts.nickname,
|
60
|
+
case_blocks_email_accounts.imap_username,
|
61
|
+
case_blocks_email_accounts.imap_encrypted_password,
|
62
|
+
case_blocks_email_accounts.imap_host,
|
63
|
+
case_blocks_email_accounts.imap_port,
|
64
|
+
case_blocks_email_accounts.imap_ssl,
|
65
|
+
case_blocks_email_accounts.imap_start_tls,
|
66
|
+
case_blocks_email_accounts.imap_folder_name,
|
67
|
+
case_blocks_email_accounts.imap_search_command,
|
68
|
+
case_blocks_email_accounts.imap_messages_processed,
|
69
|
+
case_blocks_email_accounts.imap_last_processed_at,
|
70
|
+
u.authentication_token
|
71
|
+
FROM case_blocks_email_accounts
|
72
|
+
JOIN case_blocks_accounts
|
73
|
+
ON case_blocks_email_accounts.account_id = case_blocks_accounts.id
|
74
|
+
JOIN case_blocks_users u
|
75
|
+
ON u.account_id = case_blocks_accounts.id
|
76
|
+
where imap_enabled=1
|
77
|
+
and u.is_bot=1
|
78
|
+
and u.is_account_admin=1
|
79
|
+
EOS
|
80
|
+
statement = mysql.prepare(sql)
|
50
81
|
result = statement.execute()
|
51
82
|
result.each do |row|
|
52
83
|
ssl_options = row["imap_ssl"]==1 ? {:verify_mode => OpenSSL::SSL::VERIFY_NONE} : false
|
53
|
-
|
54
|
-
|
84
|
+
|
85
|
+
auth_token = row["authentication_token"]
|
86
|
+
decrypted_password = Encryption.new(auth_token).decrypt(row["imap_encrypted_password"])
|
87
|
+
puts "decrypted password: #{decrypted_password}"
|
88
|
+
mailboxes << {:id => row["id"], :account_code => row["nickname"], :account_id => row["account_id"], :username => row["imap_username"], :host => row["imap_host"], :port => row["imap_port"], :password => decrypted_password, :ssl_options => ssl_options, :start_tls => row["imap_start_tls"]==1, :name => row["imap_folder_nam"], :search_command => row["imap_search_command"], :message_count => row["imap_messages_processed"], :last_delivered_at => row["imap_last_processed_at"]}
|
55
89
|
end
|
56
90
|
end
|
57
91
|
mailboxes
|
@@ -62,26 +96,56 @@ module Mail2cb
|
|
62
96
|
end
|
63
97
|
|
64
98
|
def handle_incoming_message(options)
|
99
|
+
update_message_counts(options)
|
65
100
|
@handler = Mail2cb::EmailHandler.new(options)
|
66
101
|
@handler.sanitize!
|
67
102
|
# @handler.clean_replies!
|
103
|
+
@handler.queue!
|
68
104
|
|
69
|
-
hash = @handler.generate_message_hash
|
70
|
-
|
71
|
-
$redis.lpush(redis_key(options), hash)
|
72
105
|
puts "Queued."
|
73
106
|
end
|
74
107
|
|
75
|
-
def
|
76
|
-
|
108
|
+
def update_message_counts(options)
|
109
|
+
begin
|
110
|
+
options[:mailbox][:message_count] = options[:mailbox][:message_count] + 1
|
111
|
+
options[:mailbox][:last_delivered_at] = DateTime.now
|
112
|
+
|
113
|
+
if (ENV["FAYE_HOST"])
|
114
|
+
Thread.new { EventMachine.run } unless EventMachine.reactor_running?
|
115
|
+
Thread.pass until EventMachine.reactor_running?
|
116
|
+
client = Faye::Client.new("#{ENV["FAYE_HOST"]}:#{ENV["FAYE_PORT"]}/faye")
|
117
|
+
client.publish("/case_blocks/account/#{options[:mailbox][:account_id]}/imap_server_new_message/#{options[:mailbox][:id]}", {'message_count' => options[:mailbox][:message_count], 'last_delivered_at' => options[:mailbox][:last_delivered_at]})
|
118
|
+
client.disconnect
|
119
|
+
end
|
120
|
+
mysql_client do |mysql|
|
121
|
+
status_message = options[:status]
|
122
|
+
statement = mysql.prepare("UPDATE case_blocks_email_accounts SET imap_messages_processed='#{options[:mailbox][:message_count]}', imap_last_processed_at='#{options[:mailbox][:last_delivered_at]}' where id=?")
|
123
|
+
statement.execute(options[:mailbox][:id])
|
124
|
+
end
|
125
|
+
rescue => e
|
126
|
+
puts e.message
|
127
|
+
puts e.backtrace.join("\n")
|
128
|
+
end
|
77
129
|
end
|
78
130
|
|
79
131
|
def update_status(options)
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
132
|
+
begin
|
133
|
+
puts "Status Update: #{options[:status]} for #{options[:mailbox][:username]}"
|
134
|
+
if (ENV["FAYE_HOST"])
|
135
|
+
Thread.new { EventMachine.run } unless EventMachine.reactor_running?
|
136
|
+
Thread.pass until EventMachine.reactor_running?
|
137
|
+
client = Faye::Client.new("#{ENV["FAYE_HOST"]}:#{ENV["FAYE_PORT"]}/faye")
|
138
|
+
client.publish("/case_blocks/account/#{options[:mailbox][:account_id]}/imap_server_status_updated/#{options[:mailbox][:id]}", {'status' => options[:status].gsub("_", " ")})
|
139
|
+
client.disconnect
|
140
|
+
end
|
141
|
+
mysql_client do |mysql|
|
142
|
+
status_message = options[:status]
|
143
|
+
statement = mysql.prepare("UPDATE case_blocks_email_accounts SET imap_status='#{options[:status]}', imap_status_message='#{status_message}' where id=?")
|
144
|
+
statement.execute(options[:mailbox][:id])
|
145
|
+
end
|
146
|
+
rescue => e
|
147
|
+
puts e.message
|
148
|
+
puts e.backtrace.join("\n")
|
85
149
|
end
|
86
150
|
end
|
87
151
|
|
data/lib/mail2cb/encryption.rb
CHANGED
@@ -1,37 +1,56 @@
|
|
1
1
|
require 'base64'
|
2
|
+
require 'rest-client'
|
2
3
|
|
3
4
|
module Mail2cb
|
4
5
|
class Encryption
|
5
6
|
|
6
|
-
def initialize()
|
7
|
-
|
8
|
-
|
9
|
-
end
|
10
|
-
|
11
|
-
def encrypt(data)
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
7
|
+
# def initialize()
|
8
|
+
# @key = ENV["CASEBLOCKS_ENCRYPTION_KEY"] || "YLX0IBT+OXaO4mP2bVYqzMPbrrss8eUcX1XtgLxlVH8="
|
9
|
+
# @iv = ENV["CASEBLOCKS_ENCRYPTION_IV"] || "vvSVfoWvZQ3T/DfjsjO/9w=="
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
# def encrypt(data)
|
13
|
+
# unless data.nil?
|
14
|
+
# cipher = OpenSSL::Cipher::AES.new(128, :CBC)
|
15
|
+
# cipher.encrypt
|
16
|
+
# cipher.key = Base64.decode64(@key)
|
17
|
+
# cipher.iv = Base64.decode64(@iv)
|
18
|
+
# encrypted = cipher.update(data) + cipher.final
|
19
|
+
#
|
20
|
+
# # [0..-2] strip off trailing carriage return
|
21
|
+
# Base64.encode64(encrypted)[0..-2]
|
22
|
+
# else
|
23
|
+
# data
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# def decrypt(value)
|
28
|
+
# unless value.nil?
|
29
|
+
# decipher = OpenSSL::Cipher::AES.new(128, :CBC)
|
30
|
+
# decipher.decrypt
|
31
|
+
# decipher.key = Base64.decode64(@key)
|
32
|
+
# decipher.iv = Base64.decode64(@iv)
|
33
|
+
#
|
34
|
+
# encrypted = Base64.decode64(value)
|
35
|
+
# decipher.update(encrypted) + decipher.final
|
36
|
+
# else
|
37
|
+
# value
|
38
|
+
# end
|
39
|
+
# end
|
40
|
+
|
41
|
+
def initialize(auth_token)
|
42
|
+
# @current_user = current_user
|
43
|
+
# config = YAML.load_file(File.join(Rails.root, "config", "secret_keys.yml"))[Rails.env.to_sym]
|
44
|
+
# @key = config[:key]
|
45
|
+
# @iv = config[:iv]
|
46
|
+
@auth_token = auth_token
|
24
47
|
end
|
25
48
|
|
26
49
|
def decrypt(value)
|
27
50
|
unless value.nil?
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
decipher.iv = Base64.decode64(@iv)
|
32
|
-
|
33
|
-
encrypted = Base64.decode64(value)
|
34
|
-
decipher.update(encrypted) + decipher.final
|
51
|
+
url = "#{ENV["CRYPT_API_ENDPOINT"]}/decrypt?auth_token=#{@auth_token}"
|
52
|
+
result = ::RestClient.post url, {base64ciphertext: value}.to_json, :content_type => :json, :accept => :json
|
53
|
+
JSON.parse(result)["plaintext"]
|
35
54
|
else
|
36
55
|
value
|
37
56
|
end
|