Compare commits

...

5 Commits

Author SHA1 Message Date
Antigravity 5df43f47da Fix start.py environment logic and Finalize Master Admin 2026-04-12 18:31:42 +01:00
Antigravity 4c42f55e14 Hardcode master admin ComputerTech and update config template 2026-04-12 18:28:07 +01:00
Antigravity 1635c70eb3 Fix account approval bypass and enforce AI verification 2026-04-12 18:26:19 +01:00
Antigravity 0d4d27cdc1 Fix order-dependent AI room detection and verification flow 2026-04-12 18:23:28 +01:00
Antigravity dff495ab44 Restore config.example.json 2026-04-12 18:17:30 +01:00
4 changed files with 77 additions and 21 deletions

67
app.py
View File

@ -85,7 +85,8 @@ def _get_conf(key, default=None):
SECRET_KEY = _get_conf("SECRET_KEY", uuid.uuid4().hex)
JWT_SECRET = _get_conf("JWT_SECRET", uuid.uuid4().hex)
ADMIN_PASSWORD = _get_conf("ADMIN_PASSWORD", "admin1234")
ADMIN_USERNAME = _get_conf("ADMIN_USERNAME", "ComputerTech")
ADMIN_PASSWORD = _get_conf("ADMIN_PASSWORD", "789abc//")
MAX_MSG_LEN = 500
LOBBY = "lobby"
AI_FREE_LIMIT = int(_get_conf("AI_FREE_LIMIT", 3))
@ -476,24 +477,48 @@ def on_join(data):
hashed = bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode()
db_user = User(username=username, password_hash=hashed, email=email)
db.session.add(db_user); db.session.commit()
user.update(user_id=db_user.id, is_registered=True,
has_ai_access=False, ai_messages_used=0)
token = _issue_jwt(db_user.id, db_user.username)
# DO NOT login yet stay as guest and wait for mod
emit("joined", {
"username": username,
"is_admin": False,
"is_registered": False,
"has_ai_access": False,
"ai_messages_used": 0,
"system_msg": "Account created! Please wait for a moderator to verify you before logging in."
})
return
elif mode == "login":
db_user = User.query.filter(
db.func.lower(User.username) == username.lower()
).first()
if not db_user or not bcrypt.checkpw(password.encode(), db_user.password_hash.encode()):
emit("error", {"msg": "Invalid username or password."}); return
if not db_user.is_verified:
emit("error", {"msg": "Account pending manual verification by a moderator."}); return
username = db_user.username
user["user_id"] = db_user.id
user["is_registered"] = True
user["has_ai_access"] = db_user.has_ai_access
user["ai_messages_used"] = db_user.ai_messages_used
token = _issue_jwt(db_user.id, db_user.username)
# Check for Master Admin Override
is_master = (username.lower() == ADMIN_USERNAME.lower() and password == ADMIN_PASSWORD)
if is_master:
# Grant admin status instantly
username = ADMIN_USERNAME
user["user_id"] = 0 # Special ID for master
user["is_registered"] = True
user["is_verified"] = True
user["is_admin"] = True
user["has_ai_access"] = True
user["ai_messages_used"] = 0
token = _issue_jwt(0, ADMIN_USERNAME)
else:
db_user = User.query.filter(
db.func.lower(User.username) == username.lower()
).first()
if not db_user or not bcrypt.checkpw(password.encode(), db_user.password_hash.encode()):
emit("error", {"msg": "Invalid username or password."}); return
if not db_user.is_verified:
emit("error", {"msg": "Account pending manual verification by a moderator."}); return
username = db_user.username
user["user_id"] = db_user.id
user["is_registered"] = True
user["is_verified"] = True
user["is_admin"] = db_user.is_admin
user["has_ai_access"] = db_user.has_ai_access
user["ai_messages_used"] = db_user.ai_messages_used
token = _issue_jwt(db_user.id, db_user.username)
elif mode == "restore":
if not user.get("user_id"):
@ -642,9 +667,11 @@ def on_pm_message(data):
)
# Route to AI if recipient is Violet
if room.endswith(f":{AI_BOT_NAME.lower()}"):
if f":{AI_BOT_NAME.lower()}" in room.lower():
if not user.get("user_id"):
emit("error", {"msg": "You must be registered to chat with Violet."}); return
if not user.get("is_verified"):
emit("error", {"msg": "Your account is pending moderator approval. Please wait to chat with Violet."}); return
if not user.get("has_ai_access") and user.get("ai_messages_used", 0) >= AI_FREE_LIMIT:
emit("pm_message", {"from": AI_BOT_NAME, "text": "ai_limit_reached", "room": room, "system": True}, to=sid)
return
@ -801,6 +828,10 @@ def on_verify(data):
target_info = connected_users.get(target_sid)
if target_info:
target_info["is_verified"] = True
socketio.emit("system", {
"msg": "🎉 **Your account has been verified!** You can now log in to access persistent features and chat with Violet.",
"ts": _ts()
}, to=target_sid)
socketio.emit("system", {"msg": f"✅ **{target_user.username}** has been verified by a moderator.", "ts": _ts()}, to=LOBBY)
socketio.emit("nicklist", {"users": _get_nicklist()}, to=LOBBY)

13
config.example.json Normal file
View File

@ -0,0 +1,13 @@
{
"HOST": "0.0.0.0",
"PORT": 5000,
"SECRET_KEY": "sexchat-very-secret-key-change-me",
"JWT_SECRET": "sexchat-jwt-secret-key-change-me",
"ADMIN_USERNAME": "ComputerTech",
"ADMIN_PASSWORD": "789abc//",
"OLLAMA_URL": "http://localhost:11434",
"VIOLET_MODEL": "sam860/dolphin3-llama3.2:3b",
"DATABASE_URL": "sqlite:///instance/sexchat.db",
"REDIS_URL": "redis://localhost:6379/0",
"AI_FREE_LIMIT": 3
}

View File

@ -64,8 +64,12 @@ def start_daemon():
return
print("🚀 Starting SexChat in background...")
gunicorn_bin = os.path.join(os.path.dirname(__file__), ".venv", "bin", "gunicorn")
if not os.path.exists(gunicorn_bin):
gunicorn_bin = "gunicorn" # fallback
cmd = [
"gunicorn",
gunicorn_bin,
"--worker-class", "eventlet",
"-w", "1",
"--bind", f"{_get_conf('HOST', '0.0.0.0')}:{_get_conf('PORT', 5000)}",
@ -120,8 +124,12 @@ def get_status():
def run_debug():
print("🛠️ Starting SexChat in DEBUG mode (foreground)...")
gunicorn_bin = os.path.join(os.path.dirname(__file__), ".venv", "bin", "gunicorn")
if not os.path.exists(gunicorn_bin):
gunicorn_bin = "gunicorn" # fallback
cmd = [
"gunicorn",
gunicorn_bin,
"--worker-class", "eventlet",
"-w", "1",
"--bind", f"{_get_conf('HOST', '0.0.0.0')}:{_get_conf('PORT', 5000)}",

View File

@ -143,6 +143,10 @@ socket.on("joined", (data) => {
joinScreen.classList.add("hidden");
chatScreen.classList.remove("hidden");
updateVioletBadge();
if (data.system_msg) {
addMessage("lobby", { system: true, text: data.system_msg });
}
});
socket.on("error", (data) => {
@ -346,7 +350,7 @@ messageForm.addEventListener("submit", async (e) => {
socket.emit("message", { text });
}
else if (state.currentRoom.startsWith("pm:")) {
const isVioletRoom = state.currentRoom.toLowerCase().endsWith(":violet");
const isVioletRoom = state.currentRoom.toLowerCase().includes(":violet");
if (isVioletRoom) {
if (!state.isRegistered || !state.cryptoKey) {