more stuff

This commit is contained in:
Yessiest 2023-05-07 20:05:41 +04:00
parent 98847ffc51
commit d580c2cba1
2 changed files with 57 additions and 10 deletions

View File

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

12
static/ratelimit.html Normal file
View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<title> Registration form </title>
</head>
<body>
<h1> Oops! </h1>
<hr />
<p> You have been ratelimited! </p>
</body>
</html>