aprhodite/README.md

28 KiB
Raw Permalink Blame History

💋 SexyChat (Aphrodite)

A real-time encrypted chat platform with an AI companion, role-based moderation, and a glassmorphism UI. Built with Flask-SocketIO, AES-GCM encryption, and a local Ollama-powered AI named Violet.


Table of Contents


Features

Core Chat

  • Public Lobby — Real-time ephemeral group chat. Messages are never persisted; they live only in connected clients' browsers.
  • Private Messaging — AES-GCM-256 encrypted PMs with persistent history (up to 500 messages per conversation).
  • Guest Mode — Join and chat anonymously without an account.
  • Registration & Login — Bcrypt password hashing, JWT token auth (7-day expiry), automatic session restore on page refresh.
  • Rate Limiting — 6 messages per 5-second window per session.

Violet AI Companion

  • Local Ollama inference (sadiq-bd/llama3.2-3b-uncensored:latest by default).
  • Transit-encrypted messages — decrypted server-side only for inference, never stored in plaintext.
  • Per-user conversation memory (last 20 turns), persisted across sessions. /reset command to clear.
  • Free trial (configurable, default: 3 messages), then paywall — admins can grant unlimited access.
  • Real-time typing indicator while Violet is generating a response.
  • Friendly signup prompt for unregistered guests who try to PM Violet.

Moderation & Roles

  • 4-tier role hierarchy: root (👑) > admin (⚔️) > mod (🛡️) > user
  • Kick, ban (username + IP), kickban, mute/unmute, verify/unverify.
  • Persistent bans and mutes survive server restarts (stored in DB, loaded on startup).
  • Admin panel with three tabs: Users, Bans, Mutes.
  • Privilege escalation prevention — you can't modify users at or above your own power level.

User Features

  • Persistent ignore list (stealth blocking — ignored users receive no indication).
  • Context menu (right-click a username) for PM, ignore, and mod actions.
  • Settings panel with four tabs: Account, Chat, Violet, Premium.
  • Password change from settings (requires current password).
  • Unread PM indicators on conversation tabs.

UI/UX

  • Glassmorphism dark theme with CSS custom property theming.
  • 10 color themes (dark, light, neon, cyberpunk, and more).
  • Responsive mobile layout with collapsible sidebar.
  • Auto-expanding message textarea.
  • Enter-to-send toggle (configurable).
  • Google Fonts (Inter + Outfit).

Architecture

┌─────────────┐    WebSocket / HTTP    ┌──────────────────────────────┐
│   Browser    │ ◄────────────────────► │  Gunicorn + Eventlet         │
│  (chat.js    │                        │  Flask-SocketIO              │
│   crypto.js) │                        │                              │
└─────────────┘                        │  ┌────────────────────────┐  │
                                       │  │ REST Blueprint          │  │
                                       │  │ (routes.py)             │  │
                                       │  └────────────────────────┘  │
                                       │                              │
                                       │  ┌────────────────────────┐  │
                                       │  │ AI Worker (greenlet)    │  │
                                       │  │ Serialized Ollama queue │  │
                                       │  └───────────┬────────────┘  │
                                       └──────────────┼───────────────┘
                                                      │
                                       ┌──────────────▼───────────────┐
                                       │  Ollama (localhost:11434)     │
                                       │  LLaMA 3.2 3B Uncensored     │
                                       └──────────────────────────────┘
                                                      │
                                       ┌──────────────▼───────────────┐
                                       │  SQLite (instance/sexchat.db)│
                                       │  Users, Messages, Bans,      │
                                       │  Mutes, VioletHistory         │
                                       └──────────────────────────────┘

Key Design Decisions

  • Single-process, single-worker — Eventlet async mode with one Gunicorn worker. All in-memory state (connected users, rooms, rate limits) lives in-process.
  • AI inference queue — A dedicated eventlet greenlet serialises Ollama requests one at a time, broadcasting violet_typing indicators while busy. Runs within Flask app context for DB access.
  • Lobby is ephemeral — No lobby messages are ever written to the database.
  • PMs are encrypted at rest — The server stores only AES-GCM ciphertext and nonces for registered-user PMs.
  • Shared config moduleconfig.py centralises all constants, config loading, AES-GCM helpers, and JWT helpers so app.py and routes.py share a single source of truth.

Tech Stack

Layer Technology
Web server Gunicorn 21.x with eventlet worker
Framework Flask 3.x + Flask-SocketIO 5.x
Concurrency Eventlet (monkey-patched greenlets)
Database SQLite (default) or PostgreSQL via DATABASE_URL
ORM SQLAlchemy 3.x + Flask-Migrate 4.x (Alembic)
AI Ollama HTTP API (local inference)
Auth JWT (PyJWT 2.x) + bcrypt 4.x
Encryption AES-GCM-256 (server: cryptography 42.x, client: Web Crypto API)
Frontend Vanilla JS, Socket.IO 4 client, custom CSS
Scaling Optional Redis message queue for multi-worker deployments

Project Structure

aprhodite/
├── app.py              # Flask-SocketIO app: socket events, AI worker, admin panel, moderation
├── config.py           # Shared config loader, constants, AES-GCM helpers, JWT helpers, Violet prompt
├── database.py         # SQLAlchemy + Flask-Migrate init, Violet bot user seeding
├── models.py           # ORM models: User, Message, Ban, Mute, UserIgnore, VioletHistory
├── routes.py           # REST API blueprint: auth, PM history, AI message, payment webhook
├── start.py            # Process manager: start / stop / restart / status / debug
├── gunicorn.conf.py    # Gunicorn configuration (workers, bind, worker class)
├── config.json         # Runtime secrets & overrides (gitignored)
├── requirements.txt    # Python dependencies
├── index.html          # Single-page app: join screen, chat, settings modal, admin panel modal
├── static/
│   ├── chat.js         # Frontend logic: socket events, PMs, settings, admin panel, themes
│   ├── crypto.js       # Client-side AES-GCM encryption (PBKDF2 key derivation, SubtleCrypto)
│   ├── style.css       # All styles: glassmorphism, 10 themes, admin panel, responsive layout
│   └── socket.io.min.js# Socket.IO v4 client library
└── instance/
    └── sexchat.db      # SQLite database (auto-created on first run)

Setup & Installation

Prerequisites

  • Python 3.11+
  • Ollama (required for Violet AI)

Install

git clone https://git.computertech.dev/lord3nd3r/aprhodite.git
cd aprhodite

python -m venv venv
source venv/bin/activate
pip install -r requirements.txt

Pull the AI Model

ollama pull sadiq-bd/llama3.2-3b-uncensored:latest

Create config.json

{
  "SECRET_KEY": "your-random-secret-key",
  "JWT_SECRET": "your-random-jwt-secret",
  "ADMIN_PASSWORD": "a-strong-moderator-password",
  "AI_FREE_LIMIT": 3,
  "HOST": "0.0.0.0",
  "PORT": 5000
}

Tip: Generate secrets with python -c "import uuid; print(uuid.uuid4().hex)".

Database

On first run, database.py calls db.create_all() and seeds the Violet bot user automatically. No manual migration is needed for a fresh install.

For schema changes after the initial setup:

flask db migrate -m "description of changes"
flask db upgrade

Configuration

Configuration is resolved with the following precedence: Environment Variable → config.json → Default Value.

All config loading is centralised in config.py.

Key Default Description
SECRET_KEY Random UUID hex Flask session secret
JWT_SECRET Random UUID hex JWT HMAC signing key
ADMIN_PASSWORD "admin1234" Shared mod password for guest elevation
DATABASE_URL "sqlite:///sexchat.db" SQLAlchemy database URI
PAYMENT_SECRET "change-me-payment-secret" Payment webhook validation secret
CORS_ORIGINS None Socket.IO CORS allowlist
HOST "0.0.0.0" Server bind address
PORT 5000 Server bind port
OLLAMA_URL "http://localhost:11434" Ollama API endpoint
VIOLET_MODEL "sadiq-bd/llama3.2-3b-uncensored:latest" Ollama model tag for Violet
AI_FREE_LIMIT 3 Free Violet messages before paywall
SOCKETIO_MESSAGE_QUEUE / REDIS_URL None Redis URL for multi-worker Socket.IO

Hardcoded Constants (in config.py)

Constant Value Description
MAX_MSG_LEN 500 chars Maximum message length
MAX_HISTORY 500 messages PM history cap per conversation pair
JWT_EXPIRY_DAYS 7 days JWT token lifespan
AI_BOT_NAME "Violet" AI bot display name
PBKDF2_ITERATIONS 100,000 Client-side key derivation iterations (crypto.js)
Rate limit 6 msgs / 5 sec Per-session lobby rate limit (app.py)
MAX_HISTORY_PER_USER 20 turns Violet conversation memory depth (app.py)

Running the Server

Debug Mode (foreground, full logging)

python start.py debug

Daemon Mode

python start.py start     # Start in background (PID written to .pid file)
python start.py stop      # Graceful shutdown
python start.py restart   # Stop + start
python start.py status    # Check if running

Direct Gunicorn

gunicorn --worker-class eventlet -w 1 --bind 0.0.0.0:5000 start:application

The server will be available at http://localhost:5000.


Database Models

Six models defined in models.py. All timestamps use datetime.now(timezone.utc).

users

Column Type Description
id Integer, PK Auto-increment
username String(20), unique, indexed Alphanumeric + - + _
password_hash String(128) Bcrypt hash
email String(255), unique, nullable Optional email
role String(10), default "user" root, admin, mod, or user
has_ai_access Boolean, default False Unlimited Violet access flag
ai_messages_used Integer, default 0 Free trial counter
is_verified Boolean, default False Manual verification status
created_at DateTime UTC timestamp

messages (Encrypted PM History)

Column Type Description
id Integer, PK
sender_id FK → users.id
recipient_id FK → users.id
encrypted_content Text Base64-encoded AES-GCM ciphertext
nonce String(64) Base64-encoded 12-byte IV
timestamp DateTime Indexed with sender/recipient for query performance

bans

Column Type Description
id Integer, PK
username String(20), indexed Banned username (lowercase)
ip String(45), nullable, indexed Banned IP address
reason String(255), nullable Ban reason
created_at DateTime

mutes

Column Type Description
id Integer, PK
username String(20), unique, indexed Muted username
created_at DateTime

user_ignores

Column Type Description
id Integer, PK
ignorer_id FK → users.id User doing the ignoring
ignored_id FK → users.id User being ignored
created_at DateTime

Unique composite index on (ignorer_id, ignored_id).

violet_history

Column Type Description
id Integer, PK
user_id FK → users.id Owning user
role String(10) "user" or "assistant"
text Text Plaintext conversation turn
timestamp DateTime

Socket Events Reference

Connection & Auth

Direction Event Data Description
C→S join { mode, username, password?, email?, mod_password? } Authenticate and enter lobby. mode: guest, login, register, or restore.
S→C joined { username, is_admin, role, is_registered, has_ai_access, ai_messages_used, email?, token?, ignored_list? } Auth success — includes JWT token for session restore.
S→C error { msg } Error message.
S→C kicked { msg } User was kicked/banned.

Lobby Chat

Direction Event Data Description
C→S message { text } Send lobby message (rate-limited).
S→C message { username, text, is_admin, is_registered, ts } Broadcast lobby message.
S→C system { msg, ts } System notification (joins, parts, mod actions).
S→C nicklist { users: [{ username, is_admin, is_registered, is_verified, role }] } Full online user list (includes Violet bot).

Private Messaging

Direction Event Data Description
C→S pm_open { target } Initiate PM with target user.
C→S pm_accept { room } Accept an incoming PM invitation (validated against pending invites).
C→S pm_message { room, text? } or { room, ciphertext, nonce, transit_key? } Send PM — plaintext (guests) or encrypted (registered). Include transit_key for Violet.
S→C pm_invite { from, room, room_key } Incoming PM invitation with server-derived room key.
S→C pm_ready { with, room, room_key } PM room opened — sent to the initiator.
S→C pm_message { from, text?, ciphertext?, nonce?, room, ts } Receive a PM.

Violet AI

Direction Event Data Description
C→S pm_message (to Violet room) { room, ciphertext, nonce, transit_key } Encrypted message routed to Violet via AI worker.
C→S violet_reset (none) Clear your conversation memory with Violet.
S→C violet_typing { busy, room? } AI processing indicator (shown while Ollama generates).
S→C ai_response { error: "ai_limit_reached", room } Free trial exhausted.
S→C ai_unlock { has_ai_access, msg? } Premium access granted or revoked (pushed live).

Moderation

Direction Event Data Description
C→S mod_kick { target } Kick user (mod+).
C→S mod_ban { target } Ban username + IP (mod+).
C→S mod_kickban { target } Kick + ban simultaneously (mod+).
C→S mod_mute { target } Toggle mute on user (mod+).
C→S mod_verify { target } Toggle verification on user (mod+).

User Actions

Direction Event Data Description
C→S user_ignore { target } Ignore a user (registered only).
C→S user_unignore { target } Unignore a user.
C→S change_password { old_password, new_password } Change password (6-char minimum).
S→C ignore_status { target, ignored } Ignore list update confirmation.
S→C password_changed { success, msg? } Password change result.
S→C role_updated { role } Live notification when your role is changed by an admin.

Admin Panel

Direction Event Data Description
C→S admin_get_users (none) Request full user list (mod+).
C→S admin_get_bans (none) Request ban list (mod+).
C→S admin_get_mutes (none) Request mute list (mod+).
C→S admin_set_role { user_id, role } Change a user's role (admin+ only, can't set ≥ own role).
C→S admin_verify_user { user_id } Toggle verification (mod+).
C→S admin_toggle_ai { user_id } Toggle unlimited AI access (admin+). Notifies user in real-time.
C→S admin_unban { ban_id } Remove a ban (mod+).
C→S admin_unmute { mute_id } Remove a mute (mod+).
S→C admin_users { users: [{ id, username, role, is_verified, has_ai_access, email, created_at, online }] } User list with online status.
S→C admin_bans { bans: [{ id, username, ip?, reason?, created_at }] } Ban list.
S→C admin_mutes { mutes: [{ id, username, created_at }] } Mute list.
S→C admin_action_ok { msg } Action success toast (panel auto-refreshes).

REST API Endpoints

All endpoints are under the /api prefix.

POST /api/auth/register

Create a new account.

// Request
{ "username": "alice", "password": "hunter2", "email": "alice@example.com" }

// Response 201
{
  "token": "eyJ...",
  "user": { "id": 3, "username": "alice", "has_ai_access": false, "ai_messages_used": 0 }
}

POST /api/auth/login

Authenticate and receive a JWT.

// Request
{ "username": "alice", "password": "hunter2" }

// Response 200
{ "token": "eyJ...", "user": { "id": 3, "username": "alice", ... } }

GET /api/pm/history?with={username}

Fetch encrypted PM history with another user. Requires Authorization: Bearer <jwt>.

// Response 200
{
  "room_key": "base64...",
  "messages": [
    { "from_me": true, "ciphertext": "...", "nonce": "...", "ts": "2025-04-12T..." },
    { "from_me": false, "ciphertext": "...", "nonce": "...", "ts": "2025-04-12T..." }
  ]
}

POST /api/ai/message

Send an encrypted message to Violet via REST (alternative to the socket path).

// Request (Authorization: Bearer <jwt>)
{ "ciphertext": "...", "nonce": "...", "transit_key": "..." }

// Response 200
{ "ciphertext": "...", "nonce": "...", "ai_messages_used": 2, "has_ai_access": false }

POST /api/payment/success

Payment webhook (server-to-server). Validates secret with constant-time HMAC comparison.

// Request
{ "secret": "PAYMENT_SECRET", "user_id": 3 }

// Response 200
{ "status": "ok", "has_ai_access": true }

Role System & Admin Panel

Hierarchy

Role Power Level Badge Capabilities
root 3 👑 Everything. Can promote to admin. Cannot be demoted.
admin 2 ⚔️ Set roles (mod/user), toggle AI access, all mod actions.
mod 1 🛡️ Kick, ban, mute, verify, view admin panel.
user 0 Standard chat, PMs, Violet AI (free trial).

Rules:

  • You cannot modify a user whose power level is ≥ your own.
  • You cannot assign a role whose power level is ≥ your own.
  • The first registered human user should be set to root in the database.
  • Legacy: Guests can enter the shared mod password at login to gain temporary mod session access.

Admin Panel

Accessible via the shield icon (🛡️) in the header (visible to mod and above). Three tabs:

Tab Features
Users Searchable user list. Change roles (dropdown), toggle verification (checkmark), grant/revoke AI access (brain icon). Shows online status.
Bans All active bans with username, IP, and date. One-click unban button.
Mutes All active mutes. One-click unmute button.

All actions trigger a system message in the lobby, auto-refresh the panel, and (where applicable) push live updates to the affected user's session.


Encryption & Security

PM Encryption (AES-GCM-256)

1. Server generates a deterministic room key: HMAC-SHA256(JWT_SECRET, room_name)
2. Room key is delivered to both clients via pm_invite / pm_ready events
3. Client encrypts each message with AES-GCM-256 using the room key + random 12-byte nonce
4. Server stores only base64(ciphertext) + base64(nonce) — never sees plaintext
5. Recipient decrypts client-side with the same room key

Violet AI Transit Encryption

1. Client generates a random AES-256 transit key
2. Client encrypts message with transit key → sends { ciphertext, nonce, transit_key }
3. Server decrypts with transit key → sends plaintext to Ollama for inference
4. Server encrypts Violet's response with the same transit key → delivers to client
5. Transit key is ephemeral — used only in memory, never stored

Security Measures

Category Implementation
Password hashing Bcrypt with adaptive cost factor
Authentication JWT tokens (HMAC-SHA256), 7-day expiry
Session restore JWT stored in localStorage, validated on reconnect
Input validation Regex-enforced usernames ([a-zA-Z0-9_-], 120 chars), message length limits, SQLAlchemy parameterized queries
Rate limiting 6 messages per 5-second window per session
RBAC @_require_role() decorator with power-level hierarchy checks
Webhook auth Constant-time HMAC comparison for payment secret
Ban persistence Username + IP stored in DB bans table, loaded into memory on startup
Mute persistence Stored in DB mutes table, loaded on startup
PM invite validation Server-side pending invite mapping — pm_accept only works for legitimately invited rooms

Theme System

10 themes available in Settings → Chat → Theme. Each theme is a set of CSS custom properties applied via the data-theme attribute on the document root.

Theme Style Palette
Midnight Purple Dark Deep purple + neon magenta (default)
Crimson Noir Dark Black + crimson red
Ocean Deep Dark Navy + cyan / teal
Ember Dark Dark brown + orange / amber
Neon Green Dark Black + bright lime
Cyberpunk Dark Purple + electric yellow
Rose Gold Dark Dark rose + blush pink
Arctic Light Cool blue-white + indigo accents
Daylight Light White + pink / purple accents
Midnight Blue Dark Deep navy + blue glow

Theme preference is saved to localStorage (sc_theme) and applied immediately on page load — no flash of default theme.


Settings Panel

Accessed via the gear icon (⚙️) in the header. Four tabs:

Account

  • View your username and email.
  • Change password (requires current password, 6-character minimum for the new one).

Chat

  • Theme — 10-option grid with gradient color swatches.
  • Font Size — 1220px slider.
  • Timestamp Format — 12-hour / 24-hour toggle.
  • Enter to Send — On/Off. When off, Enter inserts a newline and Shift+Enter sends.
  • Notification Sounds — On/Off.

Violet

  • AI access status display (Unlimited ✓ or X remaining free messages).
  • Messages used counter.
  • Reset conversation memory button.

Premium

  • Feature showcase (Unlimited Violet, Encrypted PMs, Priority Access, Custom Themes).
  • Pricing display ($10/month).
  • Coming soon placeholder.

All preferences are persisted in localStorage with the sc_ prefix (e.g., sc_theme, sc_fontSize, sc_enterSend).


Violet AI Companion

Violet is an AI chat companion powered by a local Ollama model. She's configured as a "flirtatious and sophisticated nightclub hostess at an exclusive, dimly-lit members-only club" via her system prompt in config.py.

How It Works

  1. User clicks Violet in the nicklist → PM room opens automatically (no invite needed for the bot).
  2. User's message is transit-encrypted (AES-GCM) and queued to a single-threaded inference greenlet.
  3. The AI worker decrypts the message, builds a prompt from the last 20 conversation turns (violet_history table), and calls Ollama's /api/generate endpoint.
  4. The response is transit-encrypted with the same key and delivered as a PM back to the user.
  5. Both the user's message and Violet's reply are saved to violet_history for context continuity across sessions.

Commands

Command Description
/reset Clear Violet's memory of your conversation (deletes all violet_history rows for your user).

Guest Behavior

Unregistered guests who PM Violet receive a friendly plaintext reply:

"Hey hun 💜 You'll need to register an account before we can chat privately. Go back to the join screen and sign up — I'll be waiting for you! 😘"

Free Trial & Paywall

Users get AI_FREE_LIMIT (default: 3) free messages. After that, a paywall modal is shown. Admins can grant unlimited access via the admin panel's "Grant AI" button — the user is notified in real-time via ai_unlock.

Fallback

If Ollama is unreachable or returns an error, Violet sends a graceful fallback message instead of crashing.


Premium / Paywall

When a user exhausts their free Violet messages, a paywall modal appears with pricing and feature highlights. Premium access (has_ai_access = True) can be granted two ways:

  1. Admin Panel — Any admin+ can click the brain icon (🧠) on a user in the Users tab to toggle unlimited AI access. The user receives a real-time notification.
  2. Payment WebhookPOST /api/payment/success with the payment secret and user ID. Validated with constant-time comparison.

Premium unlocks unlimited Violet messages. The ai_unlock event is pushed to the user's active socket session immediately.

Note: The payment flow is currently a stub. For production, replace the secret-comparison logic with a proper payment provider webhook (e.g., Stripe's stripe.Webhook.construct_event()).


Dependencies

From requirements.txt:

Package Version Purpose
flask ≥3.0 Web framework
flask-socketio ≥5.3 WebSocket support
eventlet ≥0.35 Async concurrency
gunicorn ≥21.0 Production WSGI server
flask-sqlalchemy ≥3.1 ORM
flask-migrate ≥4.0 Database migrations (Alembic)
psycopg2-binary ≥2.9 PostgreSQL driver (optional)
bcrypt ≥4.0 Password hashing
PyJWT ≥2.8 JWT auth tokens
cryptography ≥42.0 Server-side AES-GCM
redis ≥5.0 Socket.IO multi-worker adapter (optional)
requests ≥2.31 Ollama HTTP client

License

Private project. All rights reserved.


Credits

Built by End3rgit.computertech.dev/lord3nd3r/aprhodite