- Voice enhancements, user management, payment method

This commit is contained in:
Ty Clifford
2026-06-08 15:44:15 -04:00
parent 9e3ff61eb7
commit 063b8dc3e8
26 changed files with 2832 additions and 927 deletions
+152 -116
View File
@@ -1,143 +1,179 @@
# CYBERCHAT v2.0
# CyberChat
A self-contained, embed-ready real-time web chat built with **PHP, JavaScript, HTML5, and SQLite**. No external dependencies beyond PHP 8.0+.
CyberChat is a framework-free PHP, SQLite, JavaScript, and HTML5 chat application with configurable paid tiers, Stripe subscriptions, Mailgun email verification, private groups, voice messages, personal archives, an administrator dashboard, and an optional MySQL/MariaDB mirror.
---
## Included Features
## Features
- **Register on the fly** — pick a callsign (username) and passphrase, start chatting instantly
- **Session-locked** — one login per user enforced by IP + cookie; no multi-location sessions
- **Daily chat rooms** — each day starts fresh; yesterday's messages are automatically archived
- **SQLite archives** — stored per `archive/{year}/{month}/{day}.sqlite`; browseable via `archive-viewer.php`
- **Neon cyberpunk UI** — dark by default, light mode toggle per user (saved to localStorage)
- **Embed-ready** — drop into any `<div>` container; auto-adapts to any size
- **Fully configurable** — `config.json` controls all limits, intervals, and theming
- **Voice clips** — record, review, send, and queue WAV/WebM clips one at a time using normal PHP polling
- **No Node.js or WebSockets** — voice uses browser recording, HTTP uploads, and the existing poll loop
---
- Registration without an email address
- Verified email required before premium checkout
- Mailgun email verification and email two-factor login codes
- Stripe Checkout, Billing Portal, webhook synchronization, and cancellation
- Configurable plans, prices, Stripe Price IDs, limits, and feature assignments
- Subscription display switch that hides new sales while preserving billing management for existing customers
- Private groups with plan-based member limits, including the owner
- Premium-configurable recording presence for both sending and viewing
- Premium-configurable automatic voice sending
- Plan-based custom username colors
- Personal text archives retained for at least 30 days
- Plan-based voice archive access and JSON/CSV exports
- Visitor and feature usage statistics
- SQLite by default, with optional automatic MySQL/MariaDB mirroring
- Dark neon interface with a saved light-mode toggle
## Requirements
- PHP 8.0+ with **PDO SQLite** extension enabled
- Any web server (Apache, Nginx, Caddy, PHP built-in)
- Write permissions on `db/`, `archive/`, and `uploads/voice/` directories
- PHP/web-server upload limits at or above `voice.max_upload_bytes`
- PHP 8.1 or newer
- PHP extensions: `pdo_sqlite`, `curl`, and `fileinfo`
- A web server with HTTPS for production
- Write access to `db/`, `archive/`, `uploads/voice/`, and `config.json`
- A modern browser with `MediaRecorder` for voice recording
- Optional: PDO MySQL for the MySQL/MariaDB mirror
---
## Installation
## Quick Start
1. Place the application in the web root.
2. Make the runtime directories and configuration writable by the web-server user.
3. Configure Apache with the included `.htaccess`, or adapt `nginx-example.conf`.
4. Open `admin.php` and sign in with the initial password `changeme123`.
5. Immediately change `admin.password` in the Configuration tab.
6. Open **Plans & Platform** to configure tiers, Mailgun, Stripe, and optional MySQL mirroring.
The SQLite schema and default Free, Plus, and Pro tiers are created automatically on first use.
For a simple shared-hosting deployment:
```bash
# 1. Copy files to your web root (or a subdirectory)
cp -r cyberchat/ /var/www/html/chat/
# 2. Make sure database, archive, and voice storage are writable
chmod 755 /var/www/html/chat/db/
chmod 755 /var/www/html/chat/archive/
chmod 755 /var/www/html/chat/uploads/voice/
# 3. Visit in browser
# http://yourdomain.com/chat/
chmod 0777 db archive uploads/voice
```
The SQLite database is created automatically on first visit.
For a managed server, ownership is preferable:
---
```bash
chown -R www-data:www-data db archive uploads/voice
chmod -R 0770 db archive uploads/voice
```
## Embed in Your Own Page
Replace `www-data` with the PHP-FPM or web-server account. SQLite must be able to create the database plus `-wal` and `-shm` sidecar files. When the application directory itself is restricted, `database.main_db` may be an absolute path to a writable persistent directory.
## Default Tiers
The defaults are starting points and are fully editable in the dashboard.
| Feature | Free | Plus | Pro |
|---|---:|---:|---:|
| Group members, including owner | 2 | 4 | 8 |
| Recording status send/view | No | Yes | Yes |
| Automatic voice send | No | Yes | Yes |
| Custom username color | No | Yes | Yes |
| Text archive | 30 days | 90 days | 365 days |
| Text export | Yes | Yes | Yes |
| Voice archive/export | No | Yes | Yes |
| Email 2FA | No | Yes | Yes |
Each tier can independently configure its price, currency, billing interval, Stripe Price ID, active status, sort order, archive retention, group limit, and every feature entitlement.
## Mailgun
Configure these fields under **Admin > Plans & Platform**:
- API key
- Sending domain
- From address
- API base, normally `https://api.mailgun.net/v3`
- EU API base, when applicable: `https://api.eu.mailgun.net/v3`
The reusable mailer is in `lib/mailer.php`. It sends verification links and codes, limits verification attempts, and sends 2FA codes with a direct link to the authentication screen.
Mailgun API reference: <https://documentation.mailgun.com/docs/mailgun/api-reference/send/mailgun/messages/post-v3--domain-name--messages>
## Stripe
1. Create recurring Stripe Prices for the paid tiers.
2. Enter each `price_...` ID in the matching dashboard plan.
3. Enter the Stripe secret key and webhook signing secret.
4. Add this webhook endpoint:
`https://YOUR-DOMAIN/YOUR-PATH/api/stripe-webhook.php`
5. Subscribe the endpoint to:
- `checkout.session.completed`
- `customer.subscription.created`
- `customer.subscription.updated`
- `customer.subscription.deleted`
- `invoice.paid`
- `invoice.payment_failed`
Checkout is rejected until the account has a verified email. Stripe customer and subscription IDs, status, current period end, cancellation state, and selected plan are synchronized into SQLite.
When `subscriptions.enabled` is off, plans and checkout are hidden from non-subscribers. Existing Stripe customers retain Billing Portal and cancellation access.
Stripe references:
- <https://docs.stripe.com/api/checkout/sessions/create>
- <https://docs.stripe.com/webhooks>
## Archives
The application archives daily messages into:
`archive/{year}/{month}/{day}.sqlite`
The public legacy archive browser now redirects to the authenticated **My Archive** view. Users can only query their own sent messages within their plan retention window. Free users receive text history only; voice history and voice export require the corresponding plan entitlements.
## MySQL/MariaDB Mirror
SQLite remains the required primary database. The optional mirror imports the main database and all archive databases into `sqlite_mirror_rows` using:
- source database path
- source table
- row key
- JSON row data
- synchronization time
Set a PDO MySQL DSN in the dashboard, enable the mirror, and optionally enable automatic import. A manual **Run MySQL Mirror Now** action is also available.
## Embedding
```html
<!-- Fonts -->
<link href="https://fonts.googleapis.com/css2?family=Share+Tech+Mono&family=Rajdhani:wght@400;600;700&family=Orbitron:wght@700;900&display=swap" rel="stylesheet">
<!-- Stylesheet -->
<link rel="stylesheet" href="/chat/assets/css/cyberchat.css">
<!-- Container — set any size -->
<div id="my-chat" style="width:100%; height:600px;"></div>
<!-- Script -->
<script src="/chat/assets/js/cyberchat.js"></script>
<div id="my-chat" style="width:100%;height:600px"></div>
<script>
window.CYBERCHAT_BASE = '/chat';
</script>
<script src="/chat/assets/js/cyberchat-v4.js"></script>
<script>
window.CYBERCHAT_BASE = '/chat'; // path to your cyberchat install
CyberChat.init('#my-chat');
</script>
```
See `embed-example.html` for a live demo.
See `embed-example.html` for a complete example.
---
## Main Files
## Configuration — `config.json`
| Key | Default | Description |
|-----|---------|-------------|
| `chat.max_message_length` | 500 | Max characters per message |
| `chat.max_username_length` | 12 | Max callsign length |
| `chat.poll_interval_ms` | 2000 | How often client polls for new messages (ms) |
| `chat.messages_per_page` | 100 | Messages loaded on initial connect |
| `chat.session_lock_ip` | true | Enforce single login per IP |
| `chat.session_lock_cookie` | true | Enforce single login per cookie |
| `voice.enabled` | true | Enable voice clip controls and uploads |
| `voice.max_duration_seconds` | 60 | Maximum voice clip duration |
| `voice.max_upload_bytes` | 12582912 | Maximum voice upload size |
| `voice.auto_play_default` | true | Queue and play new incoming clips one at a time by default |
| `voice.upload_dir` | "uploads/voice" | Voice recording storage path |
| `security.min_password_length` | 4 | Minimum passphrase length |
| `security.session_timeout_hours` | 24 | Session expiry |
| `security.bcrypt_cost` | 10 | bcrypt work factor for passwords |
| `ui.default_theme` | "dark" | Default theme (`dark` or `light`) |
| `ui.app_title` | "CYBERCHAT" | Title shown in header |
| `ui.app_subtitle` | "v3.0 // SECURE CHANNEL" | Subtitle shown in header |
| `colors.user_palette` | [...] | Array of hex colors assigned randomly to users |
---
## File Structure
```
cyberchat/
├── index.html ← Main chat page
├── embed-example.html ← Embed usage example
├── archive-viewer.php ← Browse archived days
├── bootstrap.php ← DB init, helpers, session auth
├── config.json ← All configuration
├── api/
│ ├── auth.php ← Register / Login / Logout / Check
│ ├── messages.php ← Send / Poll / History
│ └── config.php ← Serves safe config to frontend
├── assets/
│ ├── css/cyberchat.css ← Full cyberpunk stylesheet
│ └── js/cyberchat.js ← Chat client (no framework)
├── db/
│ └── chat.sqlite ← Created automatically; today's messages
├── uploads/
│ └── voice/ ← WAV/WebM voice recordings
└── archive/
└── {year}/{month}/ ← Auto-archived per day as .sqlite files
└── {day}.sqlite
```text
admin.php Administrator dashboard
bootstrap.php Configuration, schema, auth, plans, archives, stats
config.json Runtime settings and service credentials
api/account.php Email, color, and 2FA settings
api/archive.php Private personal archive and export
api/auth.php Registration, login, 2FA, sessions
api/billing.php Stripe checkout, portal, and cancellation
api/groups.php Private group management
api/messages.php Text, voice, polling, and recording presence
api/stripe-webhook.php Stripe event synchronization
assets/js/cyberchat-v4.js Browser application
lib/mailer.php Reusable Mailgun sender
lib/stripe.php Stripe REST client and subscription sync
lib/mysql_mirror.php Optional SQLite-to-MySQL mirror
```
---
## Production Security
## Archive Viewer
Visit `archive-viewer.php` to browse historical chat logs. Select a day from the sidebar to read its messages.
---
## Nginx Config Example
See `nginx-example.conf` for a ready-to-use virtual host config.
---
## Security Notes
- Passwords are hashed with **bcrypt** (configurable cost factor)
- Session tokens are 64-char cryptographically random hex strings
- Session cookies are `HttpOnly`, `SameSite=Strict`, and `Secure` when served over HTTPS
- All user input is escaped on output; no raw HTML accepted
- Single-login enforcement via IP + cookie prevents session sharing
- Change the default administrator password and statistics salt.
- Serve the application only over HTTPS.
- Keep `.htaccess` rules enabled or reproduce all deny rules in the web-server configuration.
- Never expose `config.json`, `db/`, `archive/`, or `lib/`.
- Use separate Stripe test and live webhook secrets.
- Restrict `admin.php` by IP or additional HTTP authentication where practical.
- Back up SQLite databases and voice files together.