better 1.9 support

This commit is contained in:
winter 2023-01-08 16:10:27 +09:00
parent 44f2cc50ef
commit 3a01984268
11 changed files with 146 additions and 23 deletions

View File

@ -37,6 +37,17 @@ spam_thres = -3
# allow new accounts to be created
allow_registration = true
[sessions]
# allow sessions to be created (for 1.9, as it
# doesn't send the password for authentication
# in any shape or form, making relying on ip
# addresses the only secure way of accessing
# the server)
allow = true
# how long the session should last for
expiry_time = 604800
[reuploads]
# allow reuploading levels from other servers
allowed = true
@ -240,4 +251,4 @@ allow = true
[songs.sources.generic]
# direct URLs and similar
allow = true
allow = true

View File

@ -0,0 +1,30 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/png" href="/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="/style.css" />
<title>Session Creation</title>
</head>
<body style="max-width: 800px; margin: auto; padding-top: 1em;">
<%= Templates.dir_header %>
<h1>Session Creation</h1>
<%- if disabled -%>
<b>Sessions have been disabled</b><br /> <br />
<%- end -%>
<form action="/tools/create_session" method="post">
Username: <input type="text" id="username" name="username" />
Password: <input type="password" id="password" name="password" />
<input type="submit" value="Submit" <%= disabled ? "disabled" : "" %> />
</form>
<%- if result == false -%>
<div>Could not create session</div><br />
<%- elsif result == true -%>
<div>Session created successfully</div>
<%- end -%>
</body>
</html>

View File

@ -38,6 +38,9 @@
<li>The <a href="https://git.oat.zone/oat/crystal-gauntlet">Git repository</a></li>
<li><a href="/tools/song_upload">Song reuploading</a> and <a href="/tools/song_search">searching</a></li>
<li><a href="/tools/levels">Levels</a> and <a href="/tools/reupload">level reuploading</a></li>
<%- if config_get("sessions.allow").as(Bool | Nil) -%>
<li>The <a href="/tools/create_session">session creation page</a> (for accessing features in 1.9)</li>
<%- end -%>
<li><a href="https://oat.zone/f/geometry_dash_gdpstest.oat.zone.zip"><i>Completely legal</i> executable download</a></li>
</el>
</p>

View File

@ -8,7 +8,10 @@ CrystalGauntlet.endpoints["/uploadGJComment21.php"] = ->(context : HTTP::Server:
user_id, account_id = Accounts.auth(params)
if !(user_id && account_id)
return "-1"
user_id, account_id = Accounts.auth_old(context.request, params)
if !(user_id && account_id)
return "-1"
end
end
comment = params["comment"]?
@ -20,7 +23,12 @@ CrystalGauntlet.endpoints["/uploadGJComment21.php"] = ->(context : HTTP::Server:
end
if comment && !comment.blank?
comment_value = Base64.decode_string(comment)[..100-1]
comment_value = comment
if params.has_key?("gameVersion")
comment_value = Base64.decode_string(comment_value)[..100-1]
else
comment_value = comment_value[..100-1]
end
next_id = IDs.get_next_id("comments")
DATABASE.exec("insert into comments (id, level_id, user_id, comment, percent) values (?, ?, ?, ?, ?)", next_id, level_id, user_id, comment_value, percent)
return "1"
@ -31,6 +39,5 @@ CrystalGauntlet.endpoints["/uploadGJComment21.php"] = ->(context : HTTP::Server:
CrystalGauntlet.endpoints["/uploadGJComment20.php"] = CrystalGauntlet.endpoints["/uploadGJComment21.php"]
CrystalGauntlet.endpoints["/uploadGJComment19.php"] = ->(context : HTTP::Server::Context): String {
"-1"
}
CrystalGauntlet.endpoints["/uploadGJComment19.php"] = CrystalGauntlet.endpoints["/uploadGJComment21.php"]

View File

@ -8,7 +8,10 @@ CrystalGauntlet.endpoints["/deleteGJComment20.php"] = ->(context : HTTP::Server:
user_id, account_id = Accounts.auth(params)
if !(user_id && account_id)
return "-1"
user_id, account_id = Accounts.auth_old(context.request, params)
if !(user_id && account_id)
return "-1"
end
end
comment_user_id, level_user_id = DATABASE.query_one("select comments.user_id, levels.user_id from comments join levels on levels.id = comments.id where comments.id = ?", params["commentID"].to_i, as: {Int32, Int32})
@ -22,6 +25,4 @@ CrystalGauntlet.endpoints["/deleteGJComment20.php"] = ->(context : HTTP::Server:
return "1"
}
CrystalGauntlet.endpoints["/deleteGJComment19.php"] = ->(context : HTTP::Server::Context): String {
"-1"
}
CrystalGauntlet.endpoints["/deleteGJComment19.php"] = CrystalGauntlet.endpoints["/deleteGJComment20.php"]

View File

@ -7,7 +7,10 @@ CrystalGauntlet.endpoints["/deleteGJLevelUser20.php"] = ->(context : HTTP::Serve
user_id, account_id = Accounts.auth(params)
if !(user_id && account_id)
return "-1"
user_id, account_id = Accounts.auth_old(context.request, params)
if !(user_id && account_id)
return "-1"
end
end
level_id = params["levelID"].to_i
@ -19,3 +22,5 @@ CrystalGauntlet.endpoints["/deleteGJLevelUser20.php"] = ->(context : HTTP::Serve
return "1"
}
CrystalGauntlet.endpoints["/deleteGJLevelUser19.php"] = CrystalGauntlet.endpoints["/deleteGJLevelUser20.php"]

View File

@ -87,9 +87,7 @@ CrystalGauntlet.endpoints["/rateGJDemon21.php"] = ->(context : HTTP::Server::Con
CrystalGauntlet.endpoints["/rateGJStars20.php"] = CrystalGauntlet.endpoints["/rateGJStars211.php"]
CrystalGauntlet.endpoints["/rateGJStars.php"] = ->(context : HTTP::Server::Context): String {
"-1"
}
CrystalGauntlet.endpoints["/rateGJStars.php"] = CrystalGauntlet.endpoints["/rateGJStars211.php"]
CrystalGauntlet.endpoints["/rateGJLevel.php"] = ->(context : HTTP::Server::Context): String {
"-1"

View File

@ -9,7 +9,10 @@ CrystalGauntlet.endpoints["/uploadGJLevel21.php"] = ->(context : HTTP::Server::C
# todo: green user fixes? pretty please?
user_id, account_id = Accounts.auth(params)
if !(user_id && account_id)
return "-1"
user_id, account_id = Accounts.auth_old(context.request, params)
if !(user_id && account_id)
return "-1"
end
end
song_id = params["songID"] == "0" ? params["audioTrack"] : params["songID"]
@ -112,7 +115,7 @@ CrystalGauntlet.endpoints["/uploadGJLevel21.php"] = ->(context : HTTP::Server::C
# todo: check seed2?
requested_stars = params["requestedStars"].to_i.clamp(0..10)
requested_stars = (params["requestedStars"]? || "0").to_i.clamp(0..10)
if requested_stars == 0
requested_stars = nil
end
@ -134,7 +137,7 @@ CrystalGauntlet.endpoints["/uploadGJLevel21.php"] = ->(context : HTTP::Server::C
# create new level
next_id = IDs.get_next_id("levels")
DATABASE.exec("insert into levels (id, name, user_id, description, original, game_version, binary_version, password, requested_stars, unlisted, version, extra_data, level_info, editor_time, editor_time_copies, song_id, length, objects, coins, has_ldm, two_player) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", next_id, Clean.clean_special(params["levelName"])[..20-1], user_id, description[..140-1], params["original"].to_i, params["gameVersion"].to_i, params["binaryVersion"].to_i, params["password"] == "0" ? nil : params["password"].to_i, requested_stars, (params["unlisted"]? || "0").to_i == 1, params["levelVersion"].to_i, Clean.clean_special(extraString), Clean.clean_b64(params["levelInfo"]), (params["wt"]? || "0").to_i, (params["wt2"]? || "0").to_i, song_id.to_i, level_length, objects, coins, (params["ldm"]? || "0").to_i == 1, two_player)
DATABASE.exec("insert into levels (id, name, user_id, description, original, game_version, binary_version, password, requested_stars, unlisted, version, extra_data, level_info, editor_time, editor_time_copies, song_id, length, objects, coins, has_ldm, two_player) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", next_id, Clean.clean_special(params["levelName"])[..20-1], user_id, description[..140-1], params["original"].to_i, params["gameVersion"].to_i, (params["binaryVersion"]? || "0").to_i, params["password"] == "0" ? nil : params["password"].to_i, requested_stars, (params["unlisted"]? || "0").to_i == 1, params["levelVersion"].to_i, Clean.clean_special(extraString), Clean.clean_b64(params["levelInfo"]? || ""), (params["wt"]? || "0").to_i, (params["wt2"]? || "0").to_i, song_id.to_i, level_length, objects, coins, (params["ldm"]? || "0").to_i == 1, two_player)
File.write(DATA_FOLDER / "levels" / "#{next_id.to_s}.lvl", Base64.decode(params["levelString"]))
@ -144,6 +147,5 @@ CrystalGauntlet.endpoints["/uploadGJLevel21.php"] = ->(context : HTTP::Server::C
CrystalGauntlet.endpoints["/uploadGJLevel20.php"] = CrystalGauntlet.endpoints["/uploadGJLevel21.php"]
CrystalGauntlet.endpoints["/uploadGJLevel19.php"] = ->(context : HTTP::Server::Context): String {
"-1"
}
CrystalGauntlet.endpoints["/uploadGJLevel19.php"] = CrystalGauntlet.endpoints["/uploadGJLevel21.php"]

View File

@ -44,7 +44,5 @@ CrystalGauntlet.endpoints["/likeGJItem211.php"] = ->(context : HTTP::Server::Con
}
CrystalGauntlet.endpoints["/likeGJItem20.php"] = CrystalGauntlet.endpoints["/likeGJItem211.php"]
CrystalGauntlet.endpoints["/likeGJItem.php"] = CrystalGauntlet.endpoints["/likeGJItem211.php"]
CrystalGauntlet.endpoints["/likeGJItem.php"] = ->(context : HTTP::Server::Context): String {
"-1"
}

View File

@ -26,6 +26,7 @@ module CrystalGauntlet::Accounts
# todo: clean this periodically
AUTH_CACHE = Hash(Tuple(String | Nil, String | Nil, String | Nil), Tuple(Int32, Int32) | Tuple(Nil, Nil)).new
SESSIONS = Hash(Tuple(String | Nil, String | Nil), Tuple(Int32, Int32, Int64)).new
# returns userid, accountid
def auth(params : URI::Params) : (Tuple(Int32, Int32) | Tuple(Nil, Nil))
@ -52,6 +53,51 @@ module CrystalGauntlet::Accounts
return user_id, ext_id.to_i
end
def auth_old(req : HTTP::Request, params : URI::Params) : (Tuple(Int32, Int32) | Tuple(Nil, Nil))
account_id = params["accountID"]
ip = IPs.get_real_ip(req)
if SESSIONS.has_key?({account_id, ip})
LOG.debug {"#{account_id || "???"}: session exists"}
user_id, ext_id, expiry_time = SESSIONS[{account_id, ip}]
if Time.utc.to_unix > expiry_time
LOG.debug {"#{account_id || "???"}: session expired"}
SESSIONS.delete({account_id, ip})
return nil, nil
else
LOG.debug {"#{account_id || "???"}: session valid"}
return user_id, ext_id
end
end
LOG.debug {"#{account_id || "???"}: session does not exist"}
return nil, nil
end
def new_session(req : HTTP::Request, username : String, password : String) : Bool
if !config_get("sessions.allow").as(Bool | Nil)
return false
end
ip = IPs.get_real_ip(req)
result = DATABASE.query_all("select id, password from accounts where username = ?", username, as: {Int32, String})
if result.size > 0
account_id, hash = result[0]
bcrypt = Crypto::Bcrypt::Password.new(hash)
if bcrypt.verify(password)
user_id = Accounts.get_user_id(account_id)
expiry_time = Time.utc.to_unix + (config_get("sessions.expiry_time").as(Int64 | Nil) || 604800)
SESSIONS[{account_id.to_s, ip}] = { user_id, account_id, expiry_time }
return true
else
return false
end
else
return false
end
end
def get_user_id(ext_id : Int32) : Int32
DATABASE.query("select id from users where udid = ? or account_id = ?", ext_id, ext_id) do |rs|
if rs.move_next

View File

@ -0,0 +1,22 @@
require "uri"
require "compress/gzip"
include CrystalGauntlet
CrystalGauntlet.template_endpoints["/tools/create_session"] = ->(context : HTTP::Server::Context) {
disabled = !config_get("sessions.allow").as(Bool | Nil)
result = nil
body = context.request.body
if body && !disabled
begin
params = URI::Params.parse(body.gets_to_end)
result = Accounts.new_session(context.request, params["username"], params["password"])
rescue error
LOG.error {"whar.... #{error}"}
end
end
context.response.content_type = "text/html"
ECR.embed("./public/template/create_session.ecr", context.response)
}