Files
infinsweeper/session.rb
2025-09-03 15:36:28 +01:00

153 lines
5.0 KiB
Ruby

# class Sessions
class Sessions
def initialize(request, response)
@request = request
@response = response
end
def signed_in?
$active_users[self["user"]]
end
def logout
uid = self["user"]
$active_users.delete(uid)
delete("user")
DB["delete from SignedInUsers where code = ?", uid].delete
true
rescue Sequel::Error => e
Logman.log "DB Error: #{e.message}"
false
end
def login(username, pass)
Logman.log "Logging in: #{username} & #{pass} #{ENV_HASH["SALT"]}"
player = Players.authorized?(username, pass)
if player
code = Array.new(24) { ALPHANUM.sample }.join
self["user"] = code
$active_users[code] = username
begin
DB["insert into SignedInUsers (code, player) values (?, ?)", code, username].insert
rescue Sequel::Error => e
Logman.log "DB Error: #{e.message}"
return [500, "Internal server error when signing you in!"]
end
return [200, "Remember to verify your email!"] unless Players.verified?(username)
[200, "Signed in successfully!"]
else
[200, "Couldn't sign you in (Username or password incorrect)!"]
end
end
# TODO: Use .all here
def []=(key, val)
session = @request.cookies["session"]
session = session.nil? ? "{}" : Zlib::Inflate.inflate(Base64.decode64(session))
session = JSON.parse(session)
session[key] = val
Logman.log "Updated: #{key} to #{val}"
compressed = Zlib::Deflate.deflate(JSON.generate(session))
encoded = Base64.encode64(compressed)
@response.set_cookie("session",
value: encoded,
path: "/",
expires: Time.now + 360 * 24 * 60 * 60,
httponly: true,
secure: ENV_HASH["ENV"] == "prod",
samesite: :strict)
uid = session["user"]
DB["UPDATE SignedInUsers SET last_used_at = CURRENT_TIMESTAMP WHERE code = ?", uid].update if uid
rescue JSON::ParserError, Zlib::Error
@response.delete_cookie("session")
rescue Sequel::Error => e
Logman.log "DB Error: #{e.message} when updating last_used_at for #{uid}"
end
def [](key)
session = @request.cookies["session"]
session = session.nil? ? "{}" : Zlib::Inflate.inflate(Base64.decode64(session))
session = JSON.parse(session)
begin
uid = session["user"]
DB["UPDATE SignedInUsers SET last_used_at = CURRENT_TIMESTAMP WHERE code = ?", uid].update if uid
rescue Sequel::Error => e
Logman.log "DB Error: #{e.message} when updating last_used_at for #{uid}"
end
session[key]
rescue JSON::ParserError, Zlib::Error
@response.delete_cookie("session")
""
end
def message=(val)
@response.set_cookie("message",
value: val,
path: "/",
expires: Time.now + 360 * 24 * 60 * 60,
secure: ENV_HASH["ENV"] == "prod",
samesite: :strict)
end
def message
@request.cookies["message"]
end
def csrf_auth?
@request.env["HTTP_X_CSRF_TOKEN"] == self["csrf_token"]
end
def all
session = @request.cookies["session"]
session = session.nil? ? "{}" : Zlib::Inflate.inflate(Base64.decode64(session))
JSON.parse(session)
rescue JSON::ParserError, Zlib::Error
@response.delete_cookie("session")
{}
end
def delete(key)
session = @request.cookies["session"]
session = session.nil? ? "{}" : Zlib::Inflate.inflate(Base64.decode64(session))
session = JSON.parse(session)
session.delete(key)
Logman.log "Deleted: #{key}"
Logman.log session.inspect
compressed = Zlib::Deflate.deflate(JSON.generate(session))
encoded = Base64.encode64(compressed)
@response.set_cookie("session",
value: encoded,
path: "/",
expires: Time.now + 360 * 24 * 60 * 60,
httponly: true,
secure: ENV_HASH["ENV"] == "prod",
samesite: :strict)
rescue JSON::ParserError, Zlib::Error
@response.delete_cookie("session")
end
Thread.new do
loop do
now = Time.now
fifteen_days_ago = now - (60 * 60 * 24 * 15)
six_days_ago = now - (60 * 60 * 24 * 6)
old_sessions = (DB[:SignedInUsers].where { created_at < fifteen_days_ago }.all +
DB[:SignedInUsers].where { last_used_at < six_days_ago }.all).uniq { |s| s[:code] }
old_sessions.each do |session|
begin
DB[:SignedInUsers].where(code: session[:code]).delete
rescue StandardError => e
Logman.log "Thread DB error: #{e.message} on #{session[:code]} for #{session[:player]}"
end
$active_users.delete(session[:code])
puts "Auto-logged out: #{session[:player]} (expired session)"
end
rescue StandardError => e
Logman.log "Thread error: #{e.message}"
ensure
sleep 60 * 60 * 24
Logman.log "Thread sleeping"
end
end
end