Skip to content

BOt SHop - #63

Open
CyberTAck-afks wants to merge 1 commit into
aeither:mainfrom
CyberTAck-afks:patch-1
Open

CyberTAck-afks wants to merge 1 commit into
aeither:mainfrom
CyberTAck-afks:patch-1

Conversation

@CyberTAck-afks

@CyberTAck-afks CyberTAck-afks commented Aug 5, 2026 •

Copy link
Copy Markdown

Summary by CodeRabbit

  • New Features
    • Added a Telegram bot for managing ST VPN services.
    • Users can browse products, submit payment receipts, access subscriptions, and receive configuration details.
    • Added membership verification for required channels.
    • Added administrator tools for managing purchases, inventory, subscriptions, and bot settings.
    • Added persistent data storage for user and service information.

@coderabbitai

coderabbitai Bot commented Aug 5, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The Railway deployment configuration was replaced by a Python Telegram bot. The bot persists JSON data and supports channel checks, menus, purchases, receipt approval, inventory, subscriptions, administrator management, and configuration delivery.

Changes

ST VPN Telegram Bot

Layer / File(s) Summary
Bot persistence and interaction workflows
railway.toml
The file now contains the Telegram bot implementation. It manages persistent data, forced channel membership, user purchases, payment receipts, product inventory, subscriptions, administrators, menus, callbacks, and configuration delivery. The previous Railway startCommand configuration was removed.

Estimated code review effort: 5 (Critical) | ~90+ minutes

Sequence Diagram(s)

sequenceDiagram
  participant TelegramUser
  participant handle_all_messages
  participant handle_receipt_photo
  participant callback_handler
  participant JSONDatabase
  TelegramUser->>handle_all_messages: Send payment receipt photo
  handle_all_messages->>handle_receipt_photo: Process receipt
  handle_receipt_photo->>JSONDatabase: Save receipt and purchase data
  callback_handler->>JSONDatabase: Load purchase and subscription data
  callback_handler->>JSONDatabase: Save approved payment and subscription
  callback_handler->>TelegramUser: Deliver configuration with expiration date
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title identifies the main change as a bot shop implementation and is concise and related to the changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Warning

⚠️ This pull request has been flagged as potential spam (vandalism) by CodeRabbit slop detection and should be reviewed carefully.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@railway.toml`:
- Around line 188-191: Add a reject_ branch in callback_handler matching the
callback_data generated by the “رد پرداخت” button. In this branch, answer the
callback query, notify the buyer that payment was refused, and update the
administrator message caption to reflect the rejection.
- Around line 1-9: Restore railway.toml as valid TOML, including the previous
startCommand = "uv run python main.py" configuration. Move the Python bot
implementation beginning with the telebot imports and bot initialization into
the Python entry module launched by the Dockerfile, such as main.py, and ensure
the deployment continues to start that module.
- Around line 7-9: Remove the hardcoded TOKEN value, revoke the exposed Telegram
token via BotFather, and update the bot initialization to read TOKEN from an
environment variable. Confirm the token is absent from the working tree and
repository history using the provided search pattern, without adding another
secret fallback.
- Around line 583-595: The approval read-modify-write flow around the
`delivered_config` and `save_db` calls is not thread-safe, and `save_db` must
not overwrite the database directly. Add a shared `threading.Lock` and guard all
database read-modify-write sections, including the approval path, then update
`save_db` to write JSON to a temporary file and atomically replace the database
with `os.replace`.
- Around line 193-205: Update the admin_msg construction to escape
message.from_user.first_name for the selected Markdown parse mode before
embedding it in the Telegram link, and replace the silent exception handling in
the administrator send loop with exception logging. Preserve successful delivery
and ensure failures remain visible while the buyer notification flow continues
as intended.
- Around line 118-125: Remove the pasted Telegram advertisement text from the
markup.add argument list and restore the indentation of the following
KeyboardButton call. Repair the copy/paste damage throughout the file by
reindenting the statements at db["card_holder"] = parts[1], the line around 370,
elif text == "📊 حساب کاربری":, and if prod_key in db["products"]: to their
enclosing blocks; remove the duplicated lines identified around 201, 282, 328,
542, 544, and 562 while preserving the intended surrounding logic.
- Around line 540-542: Update the callback-handler branches for buy_ data and
the matching product lookups around the referenced branches to use the existing
safe .get access pattern, including the lookup near the current prod_key
assignment and those at the other reported locations. Handle a missing product
consistently with the established behavior near line 581 so unknown or deleted
tariffs do not raise KeyError or leave the user without a response.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 36d20438-6d6a-4f7f-9192-d21cf50e8c7b

📥 Commits

Reviewing files that changed from the base of the PR and between 5cfd740 and 2e4e96c.

📒 Files selected for processing (1)
  • railway.toml

Comment thread railway.toml
Comment on lines +1 to +9
import telebot
from telebot import types
import json
import os
from datetime import datetime, timedelta

# توکن اختصاصی ربات شما
TOKEN = '8857262027:AAGUB9VgDiTZhoKCBLNSmnXY9c-yxCN9_Qw'
bot = telebot.TeleBot(TOKEN)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🔴 Critical | 🏗️ Heavy lift

Python source was committed into railway.toml. This breaks the deployment configuration.

railway.toml must be valid TOML. This file now contains Python code, so Railway cannot parse it, and the previous startCommand = "uv run python main.py" is gone. Move this bot code into a Python module (for example main.py, which Dockerfile already launches) and restore the TOML configuration.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@railway.toml` around lines 1 - 9, Restore railway.toml as valid TOML,
including the previous startCommand = "uv run python main.py" configuration.
Move the Python bot implementation beginning with the telebot imports and bot
initialization into the Python entry module launched by the Dockerfile, such as
main.py, and ensure the deployment continues to start that module.

Comment thread railway.toml
Comment on lines +7 to +9
# توکن اختصاصی ربات شما
TOKEN = '8857262027:AAGUB9VgDiTZhoKCBLNSmnXY9c-yxCN9_Qw'
bot = telebot.TeleBot(TOKEN)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🔴 Critical | ⚡ Quick win

Sensitive Data Exposure (CWE-798): Use of Hard-coded Credentials

Reachability: External

Remove the hardcoded bot token and revoke it now.

Line 8 commits a live Telegram bot token to the repository. Anyone who reads this pull request can control the bot, read user messages, and send messages to all users. Revoke this token with @BotFather immediately, then load it from an environment variable.

🔒 Proposed fix
-# توکن اختصاصی ربات شما
-TOKEN = '8857262027:AAGUB9VgDiTZhoKCBLNSmnXY9c-yxCN9_Qw'
+TOKEN = os.environ["BOT_TOKEN"]
 bot = telebot.TeleBot(TOKEN)

Confirm the token is not still present elsewhere in the repository or in its history:

#!/bin/bash
# Description: Find committed Telegram bot tokens.
rg -nP '\b\d{8,12}:[A-Za-z0-9_-]{35}\b' || echo "no token pattern in working tree"
git log --oneline -20
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@railway.toml` around lines 7 - 9, Remove the hardcoded TOKEN value, revoke
the exposed Telegram token via BotFather, and update the bot initialization to
read TOKEN from an environment variable. Confirm the token is absent from the
working tree and repository history using the provided search pattern, without
adding another secret fallback.

Comment thread railway.toml
Comment on lines +118 to +125
Telegram
ST VPN ⚡️ | اینترنت بدون مرز
​🚀 ST VPN | تجربه سرعت و امنیت واقعی
🌐 مخصوص یوتیوب، اینستاگرام، وب‌گردی و گیمینگ
🔒 سرورهای اختصاصی با پینگ پایین
🛡 ضمانت کامل و پشتیبانی تا آخرین...
VIEW CHANNEL
types.KeyboardButton("📦 مشاهده موجودی انبار"),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

The pasted channel advertisement makes the file invalid Python.

Lines 118 through 124 contain Telegram channel promotional text inside the markup.add(...) call. Line 125 also loses its indentation. Delete the advertisement text and restore the argument list.

The same copy/paste damage appears at other places: line 295 (db["card_holder"] = parts[1]), line 370, line 444 (elif text == "📊 حساب کاربری":), and line 517 (if prod_key in db["products"]:) all start at column 0 and break their enclosing blocks. Several lines are also duplicated (201, 282, 328, 542, 544, 562). Fix all of them before merge.

🐛 Proposed fix for lines 117-125
         types.KeyboardButton("➕ افزودن کانفیگ به انبار"),
-Telegram
-ST VPN ⚡️ | اینترنت بدون مرز
-​🚀 ST VPN | تجربه سرعت و امنیت واقعی
-🌐 مخصوص یوتیوب، اینستاگرام، وب‌گردی و گیمینگ
-🔒 سرورهای اختصاصی با پینگ پایین
-🛡 ضمانت کامل و پشتیبانی تا آخرین...
-VIEW CHANNEL
-types.KeyboardButton("📦 مشاهده موجودی انبار"),
+        types.KeyboardButton("📦 مشاهده موجودی انبار"),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Telegram
ST VPN ⚡️ | اینترنت بدون مرز
​🚀 ST VPN | تجربه سرعت و امنیت واقعی
🌐 مخصوص یوتیوب، اینستاگرام، وب‌گردی و گیمینگ
🔒 سرورهای اختصاصی با پینگ پایین
🛡 ضمانت کامل و پشتیبانی تا آخرین...
VIEW CHANNEL
types.KeyboardButton("📦 مشاهده موجودی انبار"),
types.KeyboardButton("➕ افزودن کانفیگ به انبار"),
types.KeyboardButton("📦 مشاهده موجودی انبار"),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@railway.toml` around lines 118 - 125, Remove the pasted Telegram
advertisement text from the markup.add argument list and restore the indentation
of the following KeyboardButton call. Repair the copy/paste damage throughout
the file by reindenting the statements at db["card_holder"] = parts[1], the line
around 370, elif text == "📊 حساب کاربری":, and if prod_key in db["products"]:
to their enclosing blocks; remove the duplicated lines identified around 201,
282, 328, 542, 544, and 562 while preserving the intended surrounding logic.

Comment thread railway.toml
Comment on lines +188 to +191
markup.add(
types.InlineKeyboardButton("✅ تایید و تحویل سرویس", callback_data=f"approve_{user_id}_{prod_key}"),
types.InlineKeyboardButton("❌ رد پرداخت", callback_data=f"reject_{user_id}")
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

The reject_ callback has no handler.

Line 190 creates a button with callback_data=f"reject_{user_id}", but callback_handler contains no reject_ branch. The administrator gets no response, the callback query stays unanswered, and the buyer is never told the payment was refused. Add a reject_ branch that answers the query, notifies the buyer, and updates the caption.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@railway.toml` around lines 188 - 191, Add a reject_ branch in
callback_handler matching the callback_data generated by the “رد پرداخت” button.
In this branch, answer the callback query, notify the buyer that payment was
refused, and update the administrator message caption to reflect the rejection.

Comment thread railway.toml
Comment on lines +193 to +205
admin_msg = (
f"📥 فیش واریزی جدید دریافت شد!\n\n"
f"👤 خریدار: [{message.from_user.first_name}](tg://user?id={user_id})\n"
f"🆔 شناسه کاربری: {user_id}\n"
f"📦 سرویس درخواستی: {prod['name']}\n"
f"💰 مبلغ: {prod['price']}"
)

for adm in db.get("admins", [db["admin_id"]]):
try:
bot.send_photo(adm, photo_id, caption=admin_msg, reply_markup=markup, parse_mode="Markdown")
except Exception:
pass

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

An unescaped first_name can silently stop receipt delivery to administrators.

Line 195 places message.from_user.first_name inside a Markdown link and line 203 sends it with parse_mode="Markdown". A name that contains _, *, [, or ] makes Telegram reject the request with a 400 error. The bare except: pass at lines 204 and 205 hides the failure, and line 207 still tells the buyer the receipt was sent. No administrator ever sees the payment.

Escape the name, or use parse_mode="MarkdownV2" with proper escaping, and log the exception instead of discarding it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@railway.toml` around lines 193 - 205, Update the admin_msg construction to
escape message.from_user.first_name for the selected Markdown parse mode before
embedding it in the Telegram link, and replace the silent exception handling in
the administrator send loop with exception logging. Preserve successful delivery
and ensure failures remain visible while the buyer notification flow continues
as intended.

Comment thread railway.toml
Comment on lines +540 to +542
elif data.startswith("buy_"):
prod_key = data.split("_")[-1]
prod = db["products"][prod_key]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Unvalidated prod_key raises KeyError in the callback handler.

prod_key comes from call.data. If an administrator deleted the tariff after the keyboard was sent, or the client sends unknown data, db["products"][prod_key] raises KeyError. The user then sees no response. The same pattern exists at lines 502, 510, and 562. Line 581 already uses .get; use the same approach here.

🐛 Proposed fix
     elif data.startswith("buy_"):
         prod_key = data.split("_")[-1]
-        prod = db["products"][prod_key]
+        prod = db["products"].get(prod_key)
+        if not prod:
+            bot.answer_callback_query(call.id, "❌ این تعرفه دیگر موجود نیست.", show_alert=True)
+            return
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
elif data.startswith("buy_"):
prod_key = data.split("_")[-1]
prod = db["products"][prod_key]
elif data.startswith("buy_"):
prod_key = data.split("_")[-1]
prod = db["products"].get(prod_key)
if not prod:
bot.answer_callback_query(call.id, "❌ این تعرفه دیگر موجود نیست.", show_alert=True)
return
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@railway.toml` around lines 540 - 542, Update the callback-handler branches
for buy_ data and the matching product lookups around the referenced branches to
use the existing safe .get access pattern, including the lookup near the current
prod_key assignment and those at the other reported locations. Handle a missing
product consistently with the established behavior near line 581 so unknown or
deleted tariffs do not raise KeyError or leave the user without a response.

Comment thread railway.toml
Comment on lines +583 to +595
if not prod or len(prod["configs"]) == 0:
bot.answer_callback_query(call.id, "❌ انبار خالی است! کانفیگ موجود نیست.", show_alert=True)
return

delivered_config = prod["configs"].pop(0)
expire_time = datetime.now() + timedelta(days=prod["days"])

db["user_services"][str(target_user_id)] = {
"plan": prod["name"],
"expire_date": expire_time.strftime("%Y-%m-%d %H:%M:%S"),
"config": delivered_config
}
save_db(db)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

The approval path is not atomic and save_db can truncate the database.

pyTelegramBotAPI dispatches updates in worker threads by default. Two concurrent approve_ callbacks can both pass the stock check at line 583 and both pop a config, and the last save_db wins. save_db also opens the file with 'w', so a crash during the write leaves a truncated bot_database.json with no backup.

Guard all read-modify-write sections with a threading.Lock, and write the JSON to a temporary file, then use os.replace for an atomic swap.

#!/bin/bash
# Description: Confirm the polling mode and whether any locking exists.
rg -n 'infinity_polling|polling\(|num_threads|threaded|threading' || echo "no polling/threading setup found"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@railway.toml` around lines 583 - 595, The approval read-modify-write flow
around the `delivered_config` and `save_db` calls is not thread-safe, and
`save_db` must not overwrite the database directly. Add a shared
`threading.Lock` and guard all database read-modify-write sections, including
the approval path, then update `save_db` to write JSON to a temporary file and
atomically replace the database with `os.replace`.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant