Skip to content

Instantly share code, notes, and snippets.

@nicolas-brousse
Last active April 7, 2018 13:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nicolas-brousse/ef872cc237ad969ac83e161e170af362 to your computer and use it in GitHub Desktop.
Save nicolas-brousse/ef872cc237ad969ac83e161e170af362 to your computer and use it in GitHub Desktop.

Usage

$ ruby fake_smtp_server
require "net/smtp"

smtp = Net::SMTP.new("localhost", 3555)
# smtp.enable_starttls_auto
smtp.read_timeout = 15
smtp.open_timeout = 15
smtp.set_debug_output $stderr
smtp.start("localhost", "usernam", "pass", :plain) { status = smtp.helo("localhost") }
#!/usr/bin/env ruby
require 'socket'
require 'openssl'
class FakeSmtpServer
def initialize(port)
@port = port
@socket = TCPServer.new(@port)
@client = nil
@ssl_client = nil
end
def start
return unless @client.nil?
puts "fake_smtp_server: Waiting for one connection to port #{@port} ..."
@client = @socket.accept
send "220 dummy-smtp.example.com SMTP"
cmd = receive
while cmd !~ /^QUIT\r/
if cmd =~ /^HELO(.*)\r/
send "250-Welcome to a dummy smtp server"
send "250-STARTTLS"
send "250-AUTH PLAIN LOGIN"
send "250 Ok"
elsif cmd =~ /^AUTH(.*)\r/
send "235 2.7.0 Authentication successful"
elsif cmd =~ /^STARTTLS\r/
send "220 Ready to start TLS"
@socket, @ssl_client = tlsconnect(@socket)
else
send "502 I am so dumb I only understand HELO, AUTH, STARTTLS and QUIT"
end
cmd = receive
end
send "221 Bye Bye"
close
end
private
def client
@ssl_client || @client
end
def close
@client.close unless @client.nil?
@ssl_client.close unless @ssl_client.nil?
end
def send(line)
client.puts line
puts "-> #{line}"
end
def receive
line = client.gets
puts "<- #{line}"
line
end
def ssl_socket(socket, context)
OpenSSL::SSL::SSLServer.new(socket, context)
end
def ssl_context
@_ssl_context ||= begin
key, cert = generate_certificate
c = OpenSSL::SSL::SSLContext.new
c.key = key
c.cert = cert
c
end
end
def tlsconnect(s)
s = ssl_socket(s, ssl_context)
puts "=> TLS connection started"
client = s.accept
puts "=> TLS connection accepted"
[s, client]
end
def generate_certificate
key = OpenSSL::PKey::RSA.new(2048)
name = OpenSSL::X509::Name.parse('CN=nobody/DC=example')
cert = OpenSSL::X509::Certificate.new
cert.version = 2
cert.serial = 0
cert.not_before = Time.now
cert.not_after = Time.now + 3600
cert.public_key = key.public_key
cert.subject = name
extension_factory = OpenSSL::X509::ExtensionFactory.new nil, cert
cert.add_extension extension_factory.create_extension('basicConstraints', 'CA:FALSE', true)
cert.add_extension extension_factory.create_extension('keyUsage', 'keyEncipherment,dataEncipherment,digitalSignature')
cert.add_extension extension_factory.create_extension('subjectKeyIdentifier', 'hash')
cert.issuer = name
cert.sign key, OpenSSL::Digest::SHA256.new
[key, cert]
end
end
FakeSmtpServer.new(3555).start
puts "fake_smtp_server: Exiting now the conversation has finished."
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment