minbox 0.1.1 → 0.1.2
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/.gitignore +1 -0
- data/.ruby-version +1 -0
- data/Gemfile.lock +1 -1
- data/lib/minbox/cli.rb +6 -3
- data/lib/minbox/client.rb +19 -9
- data/lib/minbox/server.rb +55 -3
- data/lib/minbox/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7aa7df98b9f03f4db8a1971c248579b5f033fef52ff74479c5bababac5ef416f
|
4
|
+
data.tar.gz: 30507d43a907f6a4eb730930b88e11b56b99bfdd0f45b63500271efcee3d8a90
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ea55e3fd8bd032f1666bdbcf7a6892456502379cbabeac6de95a3572e66a8386f25e2f3ef6027b04ae806710b1359d46b7d149d14af836aa627a3f4e18777865
|
7
|
+
data.tar.gz: 0c2ad2a2d4803945869874e5bbd2cd1e6aed03944cdf1a18b774d173569c2a61481a7e0b1a21c385f4e4343346c5ea7f213331314a95e021694ec002a7d41ae3
|
data/.gitignore
CHANGED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.6.1
|
data/Gemfile.lock
CHANGED
data/lib/minbox/cli.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
-
require 'thor'
|
2
1
|
require 'mail'
|
2
|
+
require 'net/smtp'
|
3
|
+
require 'openssl'
|
4
|
+
require 'thor'
|
3
5
|
|
4
6
|
require 'minbox'
|
5
7
|
|
@@ -16,18 +18,19 @@ module Minbox
|
|
16
18
|
subject 'test message'
|
17
19
|
body "#{Time.now} This is a test message."
|
18
20
|
end
|
19
|
-
require 'net/smtp'
|
20
21
|
Net::SMTP.start(host, port) do |smtp|
|
22
|
+
smtp.debug_output= Minbox.logger
|
21
23
|
smtp.send_message(mail.to_s, 'me+1@example.org', 'them+1@example.com')
|
22
24
|
smtp.send_message(mail.to_s, 'me+2@example.org', 'them+2@example.com')
|
23
25
|
end
|
24
26
|
end
|
25
27
|
|
26
28
|
method_option :output, type: :array, default: ['stdout']
|
29
|
+
method_option :tls, type: :boolean, default: false
|
27
30
|
desc 'server <HOST> <PORT>', 'SMTP server'
|
28
31
|
def server(host = 'localhost', port = '25')
|
29
32
|
publisher = Publisher.from(options[:output])
|
30
|
-
Server.new(host, port).listen! do |mail|
|
33
|
+
Server.new(host, port, options[:tls]).listen! do |mail|
|
31
34
|
publisher.publish(mail)
|
32
35
|
end
|
33
36
|
end
|
data/lib/minbox/client.rb
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
module Minbox
|
2
2
|
class Client
|
3
|
-
attr_reader :
|
3
|
+
attr_reader :server, :socket, :logger
|
4
4
|
|
5
|
-
def initialize(
|
6
|
-
@
|
5
|
+
def initialize(server, socket, logger)
|
6
|
+
@server = server
|
7
7
|
@logger = logger
|
8
8
|
@socket = socket
|
9
9
|
end
|
10
10
|
|
11
11
|
def handle(&block)
|
12
|
-
write "220"
|
12
|
+
write "220 #{server.host} ESMTP"
|
13
13
|
while connected? && (line = read)
|
14
14
|
case line
|
15
15
|
when /^EHLO/i then ehlo(line)
|
@@ -28,6 +28,10 @@ module Minbox
|
|
28
28
|
write '502 Invalid/unsupported command'
|
29
29
|
end
|
30
30
|
end
|
31
|
+
close
|
32
|
+
rescue Errno::ECONNRESET, Errno::EPIPE => error
|
33
|
+
logger.error(error)
|
34
|
+
close
|
31
35
|
end
|
32
36
|
|
33
37
|
private
|
@@ -46,7 +50,7 @@ module Minbox
|
|
46
50
|
line = read
|
47
51
|
end
|
48
52
|
write "250 OK"
|
49
|
-
block.call(Mail.new(body.join))
|
53
|
+
block.call(Mail.new(body.join)) unless body.empty?
|
50
54
|
end
|
51
55
|
|
52
56
|
def rcpt_to(line)
|
@@ -59,19 +63,25 @@ module Minbox
|
|
59
63
|
|
60
64
|
def ehlo(line)
|
61
65
|
_ehlo, _client_domain = line.split(" ")
|
62
|
-
write "250-#{host}"
|
63
|
-
|
66
|
+
write "250-#{server.host} offers a warm hug of welcome"
|
67
|
+
write "250-8BITMIME"
|
64
68
|
write "250-ENHANCEDSTATUSCODES"
|
69
|
+
#write "250-STARTTLS"# if server.tls?
|
70
|
+
#write "250 AUTH PLAIN LOGIN"
|
65
71
|
write "250 OK"
|
66
72
|
end
|
67
73
|
|
68
74
|
def helo(line)
|
69
75
|
_ehlo, _client_domain = line.split(" ")
|
70
|
-
write "250 #{host}"
|
76
|
+
write "250 #{server.host}"
|
71
77
|
end
|
72
78
|
|
73
79
|
def start_tls
|
74
|
-
write "
|
80
|
+
write "220 Ready to start TLS"
|
81
|
+
|
82
|
+
socket = OpenSSL::SSL::SSLSocket.new(@socket, server.ssl_context)
|
83
|
+
socket.sync_close = true
|
84
|
+
@socket = socket.accept
|
75
85
|
end
|
76
86
|
|
77
87
|
def reset
|
data/lib/minbox/server.rb
CHANGED
@@ -1,16 +1,23 @@
|
|
1
1
|
module Minbox
|
2
2
|
class Server
|
3
|
-
attr_reader :host, :port, :logger
|
3
|
+
attr_reader :host, :port, :logger, :key
|
4
4
|
|
5
|
-
def initialize(host = 'localhost', port = 25, logger = Minbox.logger)
|
5
|
+
def initialize(host = 'localhost', port = 25, tls = false, logger = Minbox.logger)
|
6
6
|
@host = host
|
7
7
|
@port = port
|
8
8
|
@logger = logger
|
9
|
+
@tls = tls
|
10
|
+
@key = OpenSSL::PKey::RSA.new(2048)
|
11
|
+
end
|
12
|
+
|
13
|
+
def tls?
|
14
|
+
@tls
|
9
15
|
end
|
10
16
|
|
11
17
|
def listen!(&block)
|
12
18
|
logger.debug("Starting server on port #{port}...")
|
13
19
|
@server = TCPServer.new(port.to_i)
|
20
|
+
@server = upgrade(@server) if tls?
|
14
21
|
logger.debug("Server started!")
|
15
22
|
|
16
23
|
loop do
|
@@ -22,11 +29,56 @@ module Minbox
|
|
22
29
|
|
23
30
|
def handle(socket, &block)
|
24
31
|
logger.debug("client connected: #{socket.inspect}")
|
25
|
-
Client.new(
|
32
|
+
Client.new(self, socket, logger).handle(&block)
|
26
33
|
end
|
27
34
|
|
28
35
|
def shutdown!
|
29
36
|
@server&.close
|
30
37
|
end
|
38
|
+
|
39
|
+
def ssl_context
|
40
|
+
@ssl_context ||=
|
41
|
+
begin
|
42
|
+
ssl_context = OpenSSL::SSL::SSLContext.new
|
43
|
+
ssl_context.cert = certificate_for(key)
|
44
|
+
ssl_context.key = key
|
45
|
+
ssl_context.ssl_version = :TLSv1_2
|
46
|
+
ssl_context
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def upgrade(tcp_server)
|
53
|
+
server = OpenSSL::SSL::SSLServer.new(tcp_server, ssl_context)
|
54
|
+
server.start_immediately = true
|
55
|
+
server
|
56
|
+
end
|
57
|
+
|
58
|
+
def certificate_for(private_key)
|
59
|
+
certificate = OpenSSL::X509::Certificate.new
|
60
|
+
subject = '/C=CA/ST=AB/L=Calgary/O=minbox/OU=development/CN=minbox'
|
61
|
+
certificate.subject = certificate.issuer = OpenSSL::X509::Name.parse(subject)
|
62
|
+
certificate.not_before = Time.now
|
63
|
+
certificate.not_after = certificate.not_before + 30 * 24 * 60 * 60 # 30 days
|
64
|
+
certificate.public_key = private_key.public_key
|
65
|
+
certificate.serial = 1
|
66
|
+
certificate.version = 2
|
67
|
+
apply_ski_extension_to(certificate)
|
68
|
+
certificate.sign(private_key, OpenSSL::Digest::SHA256.new)
|
69
|
+
certificate
|
70
|
+
end
|
71
|
+
|
72
|
+
def apply_ski_extension_to(certificate)
|
73
|
+
extensions = OpenSSL::X509::ExtensionFactory.new
|
74
|
+
extensions.subject_certificate = certificate
|
75
|
+
extensions.issuer_certificate = certificate
|
76
|
+
certificate.add_extension(
|
77
|
+
extensions.create_extension('subjectKeyIdentifier', 'hash', false)
|
78
|
+
)
|
79
|
+
certificate.add_extension(
|
80
|
+
extensions.create_extension('keyUsage', 'keyEncipherment,digitalSignature', true)
|
81
|
+
)
|
82
|
+
end
|
31
83
|
end
|
32
84
|
end
|
data/lib/minbox/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: minbox
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- mo khan
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-03-
|
11
|
+
date: 2019-03-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: mail
|
@@ -118,6 +118,7 @@ extra_rdoc_files: []
|
|
118
118
|
files:
|
119
119
|
- ".gitignore"
|
120
120
|
- ".rspec"
|
121
|
+
- ".ruby-version"
|
121
122
|
- ".travis.yml"
|
122
123
|
- Dockerfile
|
123
124
|
- Gemfile
|