Add grass touching bans (which dont work yet), grass touching submit page which if used, increments the grass touching count and last grass touching, make it so only one error shows up if it fails and multiple errors cant.

This commit is contained in:
csd4ni3l
2025-08-14 11:50:11 +02:00
parent 3c1fc21c1c
commit fdb30a7f86
5 changed files with 241 additions and 17 deletions

60
main.py
View File

@@ -6,7 +6,7 @@ from PIL import Image
from jina import get_grass_touching_similarity from jina import get_grass_touching_similarity
from ocr_check import generate_challenge, check_text_similarity from ocr_check import generate_challenge, check_text_similarity
import os, flask_login, uuid, base64, sqlite3, bcrypt, secrets, hashlib, time import os, flask_login, uuid, base64, sqlite3, bcrypt, secrets, hashlib, time, threading
if os.path.exists(".env"): if os.path.exists(".env"):
load_dotenv(".env") load_dotenv(".env")
@@ -52,6 +52,20 @@ def close_connection(exception):
if db is not None: if db is not None:
db.close() db.close()
def check_grass_touching_bans():
while True:
cur = get_db().cursor()
cur.execute("SELECT username, last_grass_touch_time FROM Users")
for user in cur.fetchall():
if time.time() - user[1] >= (24 * 3600):
cur.execute("UPDATE users SET banned = ? WHERE username = ?", (True, user[0]))
cur.close()
time.sleep(60)
threading.Thread(target=check_grass_touching_bans, daemon=True).start()
class User(flask_login.UserMixin): class User(flask_login.UserMixin):
pass pass
@@ -61,6 +75,39 @@ def user_loader(user_id):
user.id = user_id user.id = user_id
return user return user
@login_manager.unauthorized_handler
def unauthorized_handler():
return redirect(url_for("login"))
def resize_image_file(path, max_side=256, fmt="JPEG"):
img = Image.open(path)
scale = max_side / max(img.size)
if scale < 1:
img = img.resize((int(img.width * scale), int(img.height * scale)), Image.LANCZOS)
img.save(path, format=fmt)
@app.route("/submit_grass_touching", methods=["POST"])
@flask_login.login_required
def submit_grass_touching():
username = flask_login.current_user.id
if not challenges.get(username):
return Response("Start and finish a challenge before submitting the grass touching.", 401)
if not challenges[username]["completed"]:
return Response("Finish a challenge before submitting the grass touching.", 401)
cur = get_db().cursor()
cur.execute("UPDATE Users grass_touching_count = grass_touching_count + 1 WHERE username = ?", (username,))
cur.execute("UPDATE Users last_grass_touch_time = ? WHERE username = ?", (time.time(), username))
get_db().commit()
cur.close()
return redirect("/")
@app.route("/generate_challenge", methods=["POST"]) @app.route("/generate_challenge", methods=["POST"])
def generate_challenge_route(): def generate_challenge_route():
username = request.json["username"] username = request.json["username"]
@@ -70,13 +117,6 @@ def generate_challenge_route():
return challenges[username]["text"] return challenges[username]["text"]
def resize_image_file(path, max_side=256, fmt="JPEG"):
img = Image.open(path)
scale = max_side / max(img.size)
if scale < 1:
img = img.resize((int(img.width * scale), int(img.height * scale)), Image.LANCZOS)
img.save(path, format=fmt)
@app.route("/submit_challenge", methods=["POST"]) @app.route("/submit_challenge", methods=["POST"])
def submit_challenge(): def submit_challenge():
try: try:
@@ -228,8 +268,4 @@ def logout():
flask_login.logout_user() flask_login.logout_user()
return redirect(url_for("/")) return redirect(url_for("/"))
@login_manager.unauthorized_handler
def unauthorized_handler():
return redirect(url_for("login"))
app.run(port=os.environ.get("PORT"), host=os.environ.get("HOST", "0.0.0.0")) app.run(port=os.environ.get("PORT"), host=os.environ.get("HOST", "0.0.0.0"))

View File

@@ -29,6 +29,9 @@
<a class="nav-link" href="/login">Login</a> <a class="nav-link" href="/login">Login</a>
</li> </li>
{% else %} {% else %}
<li class="nav-item">
<a class="nav-link" href="/submit_grass_touching">Submit Grass Touching</a>
</li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="/logout">Logout</a> <a class="nav-link" href="/logout">Logout</a>
</li> </li>

View File

@@ -29,6 +29,9 @@
<a class="nav-link" href="/login">Login</a> <a class="nav-link" href="/login">Login</a>
</li> </li>
{% else %} {% else %}
<li class="nav-item">
<a class="nav-link" href="/submit_grass_touching">Submit Grass Touching</a>
</li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="/logout">Logout</a> <a class="nav-link" href="/logout">Logout</a>
</li> </li>

View File

@@ -50,10 +50,12 @@
<label class="form-label" for="file_input">Grass touching proof</label> <label class="form-label" for="file_input">Grass touching proof</label>
<div id="challengehelp">To complete this challenge, you need to submit a picture of you touching grass next to a paper containing the following text: Loading...</div> <div id="challengehelp">To complete this challenge, you need to submit a picture of you touching grass next to a paper containing the following text: Loading...</div>
<input accept="image/png, image/jpeg" name="file" type="file" class="form-control" id="file_input"> <input accept="image/png, image/jpeg" name="file" type="file" class="form-control" id="file_input">
<div hidden id="error-label" class="text-danger"></div>
</div> </div>
<small id="proofhelp" class="form-text text-muted">Dont worry! We wont tell your friends.</small> <small id="proofhelp" class="form-text text-muted">Dont worry! We wont tell your friends.</small>
</div> </div>
<button id="submit" type="button" class="btn btn-primary mx-auto d-block" style="width: 100%; margin-top: 4%;">Submit</button> <button id="submit" type="button" class="btn btn-primary mx-auto d-block" style="width: 100%; margin-top: 4%;">Submit</button>
</form> </form>
</div> </div>
@@ -64,6 +66,8 @@ function upload_success(image_url) {
document.getElementById("submit").disabled = false; document.getElementById("submit").disabled = false;
document.getElementById("submit").innerHTML = "Submit" document.getElementById("submit").innerHTML = "Submit"
document.getElementById("submit").type = "submit" document.getElementById("submit").type = "submit"
document.getElementById("error-label").textContent = ""
document.getElementById("error-label").hidden = true;
document.getElementById("grass-touching-form").innerHTML += `<img class="preview-img" src="${image_url}">`; document.getElementById("grass-touching-form").innerHTML += `<img class="preview-img" src="${image_url}">`;
} }
@@ -76,15 +80,15 @@ function upload_error(error_message) {
document.getElementById("submit").innerHTML = "Submit" document.getElementById("submit").innerHTML = "Submit"
document.getElementById("submit").disabled = false; document.getElementById("submit").disabled = false;
document.getElementById("grass-touching-form").innerHTML += `<div class="text-danger">${error_message}</div>`; document.getElementById("error-label").textContent = error_message;
document.getElementById("error-label").hidden = false;
} }
function upload_file(file_type, file_content) { function upload_file(file_type, file_content) {
username_input = document.getElementById("usernameinput").value username_input = document.getElementById("usernameinput")
fetch('{{ url_for("submit_challenge") }}', { fetch('{{ url_for("submit_challenge") }}', {
method: "POST", method: "POST",
body: JSON.stringify({image_data: file_content, image_type: file_type, username: username_input}), body: JSON.stringify({image_data: file_content, image_type: file_type, username: username_input.value}),
headers: { headers: {
"Content-type": "application/json" "Content-type": "application/json"
} }
@@ -131,7 +135,8 @@ function read_file () {
file_type = "png"; file_type = "png";
} }
else { else {
document.getElementById("grass-touching-form").textContent += `<div class="text-danger">Only JPEG and PNG is supported.</div>`; document.getElementById("error-label").textContent = "Only JPEG and PNG is supported."
document.getElementById("error-label").hidden = false;
return; return;
} }

View File

@@ -0,0 +1,177 @@
{% extends "base.jinja2" %}
{% block title %}Grass Touching Register{% endblock %}
{% block body %}
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container-fluid d-flex justify-content-center">
<a class="navbar-brand" href="/">Grass Touching Captcha</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link" href="/">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/info">Information</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/leaderboard">Leaderboard</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/submit_grass_touching">Submit Grass Touching</a>
</li>
</ul>
</div>
</div>
</nav>
<div class="d-flex justify-content-center align-items-center" style="height: 75vh;">
<div class="bg-white rounded rounded-5 border border-5 border-white p-4">
<form action="/grass_touching_submit" method="post">
<h2>Grass touching submit</h2>
<div class="form-group" style="margin-top: 4%;">
<div hidden id="grass-touching-form" class="mb-3">
<label class="form-label" for="file_input">Grass touching proof</label>
<div id="challengehelp">To complete this challenge, you need to submit a picture of you touching grass next to a paper containing the following text: Loading...</div>
<input accept="image/png, image/jpeg" name="file" type="file" class="form-control" id="file_input">
<div hidden id="error-label" class="text-danger"></div>
</div>
<small id="proofhelp" class="form-text text-muted">Dont worry! We wont tell your friends.</small>
</div>
<button id="submit" type="button" class="btn btn-primary mx-auto d-block" style="width: 100%; margin-top: 4%;">Submit</button>
</form>
</div>
</div>
<script type="text/javascript">
function upload_success(image_url) {
document.getElementById("submit").disabled = false;
document.getElementById("submit").innerHTML = "Submit"
document.getElementById("submit").type = "submit"
document.getElementById("error-label").textContent = "";
document.getElementById("error-label").hidden = true;
document.getElementById("grass-touching-form").innerHTML += `<img class="preview-img" src="${image_url}">`;
}
function upload_error(error_message) {
console.error(error_message)
file_input = document.getElementById("file_input");
file_input.value = ''
document.getElementById("submit").innerHTML = "Submit"
document.getElementById("submit").disabled = false;
document.getElementById("error-label").textContent = error_message;
document.getElementById("error-label").hidden = false;
}
function upload_file(file_type, file_content) {
username_input = document.getElementById("usernameinput")
fetch('{{ url_for("submit_challenge") }}', {
method: "POST",
body: JSON.stringify({image_data: file_content, image_type: file_type, username: username_input.value}),
headers: {
"Content-type": "application/json"
}
}
).then(response => {
if (response.status == 401 || response.status == 400) {
response.text().then(text => {
if (text) {
upload_error(text);
}
}
)
return;
}
return response.text();
})
.then(image_url => {
if (image_url) {
upload_success(image_url);
}
})
.catch((error) => {
console.error("Error:", error);
});
}
function read_file () {
file_input = document.getElementById("file_input");
var filereader = new FileReader();
filereader.onload = function () {
document.getElementById("submit").innerHTML = '<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span><span class="visually-hidden">Loading...</span>';
document.getElementById("submit").disabled = true;
const file = file_input.files[0];
let file_type;
if (file.type.match("image/jpeg")) {
file_type = "jpeg";
}
else if (file.type.match("image/png")) {
file_type = "png";
}
else {
document.getElementById("error-label").textContent = "Only JPEG and PNG is supported."
document.getElementById("error-label").hidden = false;
return;
}
upload_file(file_type, filereader.result);
};
filereader.readAsDataURL(file_input.files[0]);
}
function get_challenge() {
username_input = document.getElementById("usernameinput")
fetch('{{ url_for("generate_challenge_route") }}', {
method: "POST",
body: JSON.stringify({username: username_input.value}),
headers: {
"Content-type": "application/json"
}
}).then(response => {
response.text().then(challenge_text => {
if (challenge_text) {
document.getElementById("challengehelp").innerHTML = `To complete this challenge, you need to submit a picture of you touching grass next to a paper containing the following text: ${challenge_text}`
}
})
})
}
function submit () {
username_input = document.getElementById("usernameinput")
grass_touching_form = document.getElementById("grass-touching-form")
if (grass_touching_form.hidden) {
if (username_input.value) {
grass_touching_form.hidden = false;
get_challenge();
}
}
else {
read_file();
}
}
submit_button = document.getElementById("submit")
submit_button.addEventListener("click", submit)
</script>
{% endblock %}