diff --git a/sentry.rb b/sentry.rb index 04ec982..d0c288d 100644 --- a/sentry.rb +++ b/sentry.rb @@ -3,6 +3,7 @@ require 'xmpp4r' require 'net/smtp' require 'json' require 'uri' +require 'openssl' norxondor_gorgonax = URI::MailTo::EMAIL_REGEXP @@ -17,11 +18,18 @@ SMTP_TLS = CONFIG["tls"] SMTP_STARTTLS = CONFIG["starttls"] SMTP_AUTH = CONFIG["auth"].to_sym JABBER_SERVER = CONFIG["jabber-server"] +JABBER_HOST = CONFIG['jabber-host'] +JABBER_PORT = CONFIG['jabber-port'] HTTP_SERVER_ROOT = CONFIG['http-server-root'] +RATELIMIT = CONFIG['ratelimit'] +HTTP_PORT = CONFIG['http-port'] Pending = {} Pending_by_username = {} +Recent = {} + +# Get root path to redirect to def myroot(req) if req.ssl? then return "https://#{HTTP_SERVER_ROOT}" @@ -30,9 +38,7 @@ def myroot(req) end end -def register(username,password) - cl = Jabber::Client.new(Jabber::JID.new( - +# Send email with given SMTP config def sendmail(code,email) smtp = Net::SMTP.new(SMTP_SERVER, SMTP_PORT) msg_headers = '' @@ -47,7 +53,9 @@ def sendmail(code,email) puts(smtp.send_message msg, SMTP_USER, [email]) end -server = Hyde::Server.new Port: 8001 do +# Main API server +server = Hyde::Server.new Port: HTTP_PORT do + # Serve static shit path "register" do preprocess do |ctx| puts "#{ctx.request.remote_ip} is registering" @@ -57,51 +65,78 @@ server = Hyde::Server.new Port: 8001 do index ['index.html'] serve "*.html" end + # API itself path "api" do + # First step post 'register' do |ctx| + # Where to redirect to server_uri = myroot ctx.request - # Add pending user + # Pending user info and validation key key = (1..32).map { |x| "0123456789ABCDEF"[(rand()*15).round] }.join user = ctx.request.query['user'] password = ctx.request.query['password'] email = ctx.request.query['email'] + # Expiration is 2 hours from now expires_on = Time.now+60*60*2 + # Match query parameters against given rules unless user.match /^[\w_-]+$/ and email.match norxondor_gorgonax and password.match /^.{8,}$/ then redirect server_uri+"/register/error.html" end + # Bounce if user is already pending registration if Pending_by_username[user] then redirect server_uri+"/register/error.html" end + # Bounce if email is recent + email_digest = OpenSSL::Digest.digest("sha256",email) + if Recent[email_digest] then + if Time.now < (Recent[email_digest]+RATELIMIT) then + redirect server_uri+"/register/ratelimit.html" + end + end + # Lock registration for pending user Pending_by_username[user] = Pending[key] = { "user" => user, "password" => password, "expires_on" => expires_on } + # Record recent emails that tried registering + Recent[email_digest] = Time.now begin + # Send email to validate sendmail(key,email) redirect server_uri+"/register/validate.html" rescue Exception => e + # Couldn't send email - delete pending account info + Pending_by_username.delete (Pending.delete key)["user"] redirect server_uri+"/register/error.html" end end + # Second step post 'validate' do |ctx| + # Where to redirect to server_uri = myroot ctx.request + # Validation key key = ctx.request.query['key'] + # If validation key matches a user if Pending.has_key? key then - if Pending[key].expires_on < Time.now then - puts "#{Pending.delete key} expired" + # ... and if it's not expired + if Pending[key]["expires_on"] < Time.now then + # key has expired + puts "#{ctx.request.remote_ip} expired" redirect server_uri+"/register/error.html" end + # register the user cl = Jabber::Client.new(Jabber::JID.new(Pending[key]["user"]+"@"+JABBER_SERVER)) - cl.connect + cl.connect JABBER_HOST, JABBER_PORT cl.register(Pending[key]["password"]) cl.close - puts "#{Pending[key]} successfully verified" + puts "#{ctx.request.remote_ip} successfully verified" redirect server_uri+"/register/success.html" else - puts "#{Pending[key]} failed to verify" + # key is invalid + puts "#{ctx.request.remote_ip} failed to verify" redirect server_uri+"/register/error.html" end end diff --git a/static/ratelimit.html b/static/ratelimit.html new file mode 100644 index 0000000..8a5849f --- /dev/null +++ b/static/ratelimit.html @@ -0,0 +1,12 @@ + + +
+You have been ratelimited!
+ + +