diff --git a/flake.nix b/flake.nix index d177f92..bde477a 100644 --- a/flake.nix +++ b/flake.nix @@ -30,15 +30,28 @@ mkdir -p $out cp -r . $out/ ''; - postFixup = '' - substituteInPlace $out/bin/infinsweeper \ - --replace-fail '#!/usr/bin/env ruby' '#!${ruby}/bin/ruby' + }; + + server = pkgs.writeShellApplication { + name = "infinsweeper"; + runtimeInputs = [ ruby ]; + text = '' + set -euo pipefail + data_dir="''${INFINSWEEPER_DATA_DIR:-/var/lib/infinsweeper}" + DB="$data_dir/infinsweeper.db" + mkdir -p "$data_dir" + exec ruby ${app}/main.rb ''; }; in { packages.${system}.default = app; + apps.${system}.default = { + type = "app"; + program = "${server}/bin/infinsweeper"; + }; + devShells.${system}.default = pkgs.mkShell { packages = [ ruby diff --git a/game_logic.rb b/game_logic.rb index 38a277f..5561482 100644 --- a/game_logic.rb +++ b/game_logic.rb @@ -1,5 +1,3 @@ -require "xxhash" - # Game logic main class class GameLogic attr_reader :pos diff --git a/logman.rb b/logman.rb index 453aa80..59d5707 100644 --- a/logman.rb +++ b/logman.rb @@ -2,10 +2,10 @@ module Logman def self.log(log) file, line = caller(1, 1)[0].split(":") - File.write("log/main.log", "[#{Time.now}] {#{file}:#{line}} #{log}\n", mode: "a") if ENV_HASH["ENV"] == "dev" + File.write("log/main.log", "[#{Time.now}] {#{file}:#{line}} #{log}\n", mode: "a") if ENV["ENV"] == "dev" end def self.imp(log) - File.write("log/imp.log", "[#{Time.now}] #{log}\n", mode: "a") if ENV_HASH["ENV"] == "dev" + File.write("log/imp.log", "[#{Time.now}] #{log}\n", mode: "a") if ENV["ENV"] == "dev" end end diff --git a/mailer.rb b/mailer.rb index b8a30c4..a425e3d 100644 --- a/mailer.rb +++ b/mailer.rb @@ -1,7 +1,12 @@ # Mailer module + +# Not to actually be used. proof of concept. + module Mail def send(to, subject, body) - from_email = "infinsweeper@syedm.dev" + raise "Can't send email." + + from_email = "infinsweeper@domain.com" from_name = "InfinSweeper" to = Array(to).map { |addr| { email_address: { address: addr, name: "" } } } @@ -17,7 +22,7 @@ module Mail uri = URI("https://api.zeptomail.com/v1.1/email") req = Net::HTTP::Post.new(uri) - req["Authorization"] = "Zoho-enczapikey #{ENV_HASH["ZOHO_PASS"]}" + req["Authorization"] = "Zoho-enczapikey #{ENV["ZOHO_PASS"]}" req["Content-Type"] = "application/json" req.body = payload.to_json diff --git a/main.rb b/main.rb index 4f2d420..ab7142a 100644 --- a/main.rb +++ b/main.rb @@ -10,17 +10,16 @@ require "zlib" ALPHANUM = [*"0".."9", *"A".."Z", *"a".."z", "-", "_"].freeze env_data = File.exist?(".env") ? File.read(".env") : "" -ENV_HASH = {} env_data.each_line do |line| next unless (match = line.match(/^([A-Z_][A-Z0-9_]*)=(.*)$/)) - ENV_HASH[match[1]] = match[2] + ENV[match[1]] = match[2] end load "logman.rb" -# Logman.log ENV_HASH.inspect +# Logman.log ENV.inspect -db_file = File.expand_path("infinsweeper.db", __dir__) +db_file = ENV.fetch("INFINSWEEPER_DB", File.expand_path("infinsweeper.db", __dir__)) DB = Sequel.connect("sqlite:///#{db_file}", single_threaded: false) DB.run("PRAGMA foreign_keys = ON;") DB.create_table? :Players do diff --git a/players.rb b/players.rb index 3c3e7a3..0697aac 100644 --- a/players.rb +++ b/players.rb @@ -18,15 +18,15 @@ module Players raise ArgumentError, "Password must be at least 8 characters and of valid format." unless pass.match?(/\A[a-zA-Z0-9_.!?@#$%^&*()+=-]+\z/) && pass.length >= 8 - digest = Zlib.crc32(pass, ENV_HASH["SALT"]) - code = ENV_HASH["ENV"] == "prod" ? Array.new(24) { ALPHANUM.sample }.join : "!" + digest = Zlib.crc32(pass, ENV["SALT"]) + code = ENV["ENV"] == "prod" ? Array.new(24) { ALPHANUM.sample }.join : "!" DB[ "insert into Players (username, digest, email, activation_code) values (?, ?, ?, ?)", username, digest, email, code ].insert - send_email(:new, email, username, code) if ENV_HASH["ENV"] == "prod" + send_email(:new, email, username, code) if ENV["ENV"] == "prod" [200, "Successfully signed up!"] rescue ArgumentError => e @@ -53,11 +53,11 @@ module Players true - # send_email(:pass_req, email, code) + send_email(:pass_req, email, code) end - def self.pass_reset(new_pass, code) - digest = XXhash.xxh32(new_pass, ENV_HASH["SALT"]) + def self.pass_reset(pass, code) + digest = Zlib.crc32(pass, ENV["SALT"]) DB["update Players set digest = ?, new_pass_code = ? where new_pass_code = ?", digest, "", code].update != 0 end @@ -78,7 +78,7 @@ module Players end def self.authorized?(username, pass) - digest = Zlib.crc32(pass, ENV_HASH["SALT"]) + digest = Zlib.crc32(pass, ENV["SALT"]) Logman.log "Authorized: #{username} & #{digest}" player = self[username] player && player[:digest].to_i == digest.to_i ? player : false diff --git a/session.rb b/session.rb index 6489c36..81c8a11 100644 --- a/session.rb +++ b/session.rb @@ -21,7 +21,6 @@ class Sessions 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 @@ -40,11 +39,8 @@ class Sessions 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 = all session[key] = val Logman.log "Updated: #{key} to #{val}" compressed = Zlib::Deflate.deflate(JSON.generate(session)) @@ -58,16 +54,12 @@ class Sessions 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) + session = all begin uid = session["user"] DB["UPDATE SignedInUsers SET last_used_at = CURRENT_TIMESTAMP WHERE code = ?", uid].update if uid @@ -75,9 +67,6 @@ class Sessions 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) @@ -85,7 +74,7 @@ class Sessions value: val, path: "/", expires: Time.now + 360 * 24 * 60 * 60, - secure: ENV_HASH["ENV"] == "prod", + secure: ENV["ENV"] == "prod", samesite: :strict) end @@ -107,9 +96,7 @@ class Sessions end def delete(key) - session = @request.cookies["session"] - session = session.nil? ? "{}" : Zlib::Inflate.inflate(Base64.decode64(session)) - session = JSON.parse(session) + session = all session.delete(key) Logman.log "Deleted: #{key}" Logman.log session.inspect @@ -120,7 +107,7 @@ class Sessions path: "/", expires: Time.now + 360 * 24 * 60 * 60, httponly: true, - secure: ENV_HASH["ENV"] == "prod", + secure: ENV["ENV"] == "prod", samesite: :strict) rescue JSON::ParserError, Zlib::Error @response.delete_cookie("session") @@ -140,7 +127,7 @@ class Sessions 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)" + Logman.log "Auto-logged out: #{session[:player]} (expired session)" end rescue StandardError => e Logman.log "Thread error: #{e.message}"