Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:5432/matchbot
REDIS_URL=redis://localhost:6379/0
SECRET_KEY=change-me-in-prod
ACCESS_TOKEN_EXPIRE_MINUTES=1440
MATCHMAKING_MIN_TRUST_SCORE=40
TRUST_COOLDOWN_THRESHOLD=40
TRUST_SUSPEND_THRESHOLD=20
TRUST_PENALTY_ON_REPORT=20
TRUST_REGEN_DAYS=3
TRUST_REGEN_AMOUNT=5
BASE_SESSION_MINUTES=15
PREMIUM_SESSION_MINUTES=30
PREMIUM_MATCHMAKING_BOOST=true
RATE_LIMIT_PER_MINUTE=60
14 changes: 14 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
FROM python:3.11-slim

WORKDIR /app

ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

EXPOSE 8000
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
172 changes: 155 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,166 @@
# Decrypt
### [+] Created By HTR-TECH (@***tahmid.rayat***)
### [+] Disclaimer :
***Decrypter is a tool to decrypt Encrypted Bash Scripts into a Readable Format.This Tool is created for Educational Purpose only.I am not responsible for any misuse of this tool.***
# Anonymous Matchmaking Chat Bot (FastAPI)

<img src="https://raw.githubusercontent.com/htr-tech/release-download/master/images/decrypter.png" alt="" border="0" />
Production-oriented anonymous matchmaking backend with JWT auth, Redis queue matchmaking, trust/reporting logic, ad delivery, premium controls, and admin APIs.

### [+] Installation
```apt update```
## 1) Project Structure

```apt install git python2 -y```
```text
.
├── app
│ ├── api
│ │ ├── admin.py
│ │ ├── auth.py
│ │ ├── match.py
│ │ ├── user.py
│ │ └── ws.py
│ ├── core
│ │ ├── config.py
│ │ ├── deps.py
│ │ ├── redis_client.py
│ │ └── security.py
│ ├── db
│ │ ├── base.py
│ │ └── session.py
│ ├── models
│ │ └── models.py
│ ├── schemas
│ │ ├── auth.py
│ │ └── common.py
│ ├── services
│ │ ├── ads.py
│ │ ├── maintenance.py
│ │ ├── matchmaking.py
│ │ └── trust.py
│ ├── websocket
│ │ └── manager.py
│ └── main.py
├── alembic
│ ├── env.py
│ └── versions
│ └── 0001_initial.py
├── scripts
│ └── maintenance.py
├── .env.example
├── Dockerfile
├── docker-compose.yml
├── requirements.txt
└── alembic.ini
```

## 2) Core Features Included

- Daily verification via admin-managed token (`/admin/daily-token`, `/user/verify`)
- User profile fields: gender, preferred gender, trust score, premium, account status
- Matchmaking using Redis waiting queue with trust/gender/block checks
- Anonymous WebSocket chat per room (`/ws/chat/{room_id}?token=JWT`)
- Report flow that stores reports, penalizes trust, blocks pairing
- Ads served after session close for non-premium users
- Premium activation endpoint (`/user/premium/activate`)
- Admin APIs for stats, reports, trust distribution, ad CRUD, blocked pairs
- Rate limiting per IP via Redis
- JWT authentication + admin RBAC

## 3) Database Models

Implemented SQLAlchemy models:
- `Users`
- `ChatRooms`
- `Messages`
- `Reports`
- `BlockedPairs`
- `Ads`
- `DailyVerificationToken`
- `UserVerification`

See: `app/models/models.py`.

## 4) Configuration Reference

```git clone https://github.com/hax0rtahm1d/decrypt```
All key business rules are configurable in `app/core/config.py` (or via env vars):

```cd decrypt```
- **Trust thresholds / penalties / regen**
- `TRUST_COOLDOWN_THRESHOLD`
- `TRUST_SUSPEND_THRESHOLD`
- `TRUST_PENALTY_ON_REPORT`
- `TRUST_REGEN_DAYS`
- `TRUST_REGEN_AMOUNT`
- **Daily token behavior**
- Token value set each day by admin endpoint: `POST /admin/daily-token`
- User verification recorded in `user_verifications` table (`/user/verify`)
- **Ad logic**
- Selection & impression update in `app/services/ads.py`
- Delivery after chat close in `POST /match/rooms/{room_id}/close`
- **Premium benefits**
- `PREMIUM_MATCHMAKING_BOOST` (priority queue)
- `PREMIUM_SESSION_MINUTES` (longer sessions)
- No ads for premium users in room close handler

```python2 dec.py```
## 5) Local Run Instructions

### Or, Use Single Command
### Prerequisites
- Python 3.11+
- PostgreSQL
- Redis

### Setup

```bash
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env
```

### Migrate DB

```bash
alembic upgrade head
```
apt update && apt install git python2 -y && git clone https://github.com/hax0rtahm1d/decrypt && cd decrypt && python2 dec.py

### Start API

```bash
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
```

## [+] Find Me on :
[![Github](https://img.shields.io/badge/Github-HTR--TECH-green?style=for-the-badge&logo=github)](https://github.com/htr-tech)
[![Instagram](https://img.shields.io/badge/IG-%40tahmid.rayat-red?style=for-the-badge&logo=instagram)](https://www.instagram.com/tahmid.rayat)
[![Messenger](https://img.shields.io/badge/Chat-Messenger-blue?style=for-the-badge&logo=messenger)](https://m.me/tahmid.rayat.official)
Health check: `GET /health`

## 6) Docker Deployment Instructions

### Build & Run

```bash
docker compose up --build
```

### Run migrations in API container

```bash
docker compose exec api alembic upgrade head
```

App available at `http://localhost:8000`.

## 7) API Highlights

- `POST /auth/register`
- `POST /auth/login`
- `POST /user/verify`
- `POST /match/find`
- `POST /match/rooms/{room_id}/report`
- `POST /match/rooms/{room_id}/close`
- `GET /admin/stats/users`
- `GET /admin/stats/chats`
- `GET /admin/reports`
- `POST /admin/ads`, `PATCH /admin/ads/{ad_id}`, `DELETE /admin/ads/{ad_id}`
- `POST /admin/daily-token`
- `WS /ws/chat/{room_id}?token=<JWT>`

## 8) Operational Notes

- Schedule `python scripts/maintenance.py` every minute (cron/Celery/worker) to:
- Auto-close expired rooms
- Release completed cooldown/suspension windows
- Apply trust regeneration checks
- Use HTTPS and rotate `SECRET_KEY` in production.
- Add centralized logging, tracing, and audit logs before going live.
35 changes: 35 additions & 0 deletions alembic.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
[alembic]
script_location = alembic
sqlalchemy.url = postgresql+asyncpg://postgres:postgres@db:5432/matchbot

[loggers]
keys = root,sqlalchemy,alembic

[handlers]
keys = console

[formatters]
keys = generic

[logger_root]
level = WARN
handlers = console

[logger_sqlalchemy]
level = WARN
handlers =
qualname = sqlalchemy.engine

[logger_alembic]
level = INFO
handlers =
qualname = alembic

[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic

[formatter_generic]
format = %(levelname)-5.5s [%(name)s] %(message)s
38 changes: 38 additions & 0 deletions alembic/env.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from logging.config import fileConfig

from alembic import context
from sqlalchemy import engine_from_config, pool

from app.db.base import Base
from app.models import models # noqa

config = context.config
if config.config_file_name is not None:
fileConfig(config.config_file_name)

target_metadata = Base.metadata


def run_migrations_offline() -> None:
url = config.get_main_option("sqlalchemy.url")
context.configure(url=url, target_metadata=target_metadata, literal_binds=True)
with context.begin_transaction():
context.run_migrations()


def run_migrations_online() -> None:
connectable = engine_from_config(
config.get_section(config.config_ini_section, {}),
prefix="sqlalchemy.",
poolclass=pool.NullPool,
)
Comment on lines +24 to +28

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Switch Alembic migration runner to async engine

This Alembic environment still uses the synchronous engine_from_config path even though alembic.ini is configured with postgresql+asyncpg. With asyncpg URLs, alembic upgrade head requires the async migration pattern (async_engine_from_config with run_sync), so migrations cannot run successfully with the current setup.

Useful? React with 👍 / 👎.

with connectable.connect() as connection:
context.configure(connection=connection, target_metadata=target_metadata)
with context.begin_transaction():
context.run_migrations()
Comment on lines +23 to +32

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# Check alembic.ini for the database URL configuration
fd 'alembic.ini' --exec cat {}

Repository: huzely/Decrypt

Length of output: 614


🏁 Script executed:

# Also verify the current state of alembic/env.py to confirm it matches the review
fd 'alembic/env.py' -x head -40 {}

Repository: huzely/Decrypt

Length of output: 40


🏁 Script executed:

# Display the full content of alembic/env.py to verify current state
cat -n alembic/env.py | head -50

Repository: huzely/Decrypt

Length of output: 1397


🏁 Script executed:

# Also check imports to confirm the current driver setup
grep -n "engine_from_config\|async_engine_from_config\|import asyncio" alembic/env.py

Repository: huzely/Decrypt

Length of output: 148


run_migrations_online() uses synchronous connection — incompatible with postgresql+asyncpg:// driver.

The alembic.ini configures sqlalchemy.url = postgresql+asyncpg://..., but alembic/env.py uses synchronous operations: engine_from_config() with connectable.connect(). This is incompatible; asyncpg requires async/await patterns and will raise a runtime error when migrations run in online mode.

Update to the async migration pattern using async_engine_from_config, async with connectable.connect(), and connection.run_sync():

Async-compatible online migration
 from logging.config import fileConfig
 
 from alembic import context
-from sqlalchemy import engine_from_config, pool
+from sqlalchemy import pool
+from sqlalchemy.ext.asyncio import async_engine_from_config
+import asyncio
 
 from app.db.base import Base
-from app.models import models  # noqa
+from app.models import models  # noqa: F401
 
 config = context.config
 if config.config_file_name is not None:
     fileConfig(config.config_file_name)
 
 target_metadata = Base.metadata
 
 
 def run_migrations_offline() -> None:
     url = config.get_main_option("sqlalchemy.url")
     context.configure(url=url, target_metadata=target_metadata, literal_binds=True)
     with context.begin_transaction():
         context.run_migrations()
 
 
-def run_migrations_online() -> None:
-    connectable = engine_from_config(
+async def run_async_migrations() -> None:
+    connectable = async_engine_from_config(
         config.get_section(config.config_ini_section, {}),
         prefix="sqlalchemy.",
         poolclass=pool.NullPool,
     )
-    with connectable.connect() as connection:
-        context.configure(connection=connection, target_metadata=target_metadata)
-        with context.begin_transaction():
-            context.run_migrations()
+    async with connectable.connect() as connection:
+        await connection.run_sync(do_run_migrations)
+    await connectable.dispose()
+
+
+def do_run_migrations(connection) -> None:
+    context.configure(connection=connection, target_metadata=target_metadata)
+    with context.begin_transaction():
+        context.run_migrations()
+
+
+def run_migrations_online() -> None:
+    asyncio.run(run_async_migrations())
 
 
 if context.is_offline_mode():
     run_migrations_offline()
 else:
     run_migrations_online()

Also clarify the noqa directive on line 7 to # noqa: F401 (unused import suppression is intentional for model registration).

🤖 Prompt for AI Agents
In `@alembic/env.py` around lines 23 - 32, run_migrations_online currently builds
a synchronous engine with engine_from_config and uses connectable.connect(),
which breaks with the postgresql+asyncpg URL; replace the sync flow in
run_migrations_online with the async pattern: use async_engine_from_config(...)
to create an AsyncEngine, open it with "async with connectable.connect() as
connection", and inside await connection.run_sync(lambda sync_conn:
context.configure(connection=sync_conn, target_metadata=target_metadata))
followed by await connection.run_sync(lambda _: context.run_migrations()) (or
equivalent use of connection.run_sync for
context.begin_transaction()/run_migrations); also update imports to include
async_engine_from_config and change the existing noqa comment to "# noqa: F401"
to clarify intentional unused imports for model registration.



if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()
24 changes: 24 additions & 0 deletions alembic/script.py.mako
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""${message}

Revision ID: ${up_revision}
Revises: ${down_revision | comma,n}
Create Date: ${create_date}

"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = ${repr(up_revision)}
down_revision = ${repr(down_revision)}
branch_labels = ${repr(branch_labels)}
depends_on = ${repr(depends_on)}


def upgrade() -> None:
${upgrades if upgrades else "pass"}


def downgrade() -> None:
${downgrades if downgrades else "pass"}
Loading