mail2cb 0.0.6 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- 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
|