Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Paydisini Integration #309

Merged
merged 24 commits into from
Sep 14, 2024
Merged

Added Paydisini Integration #309

merged 24 commits into from
Sep 14, 2024

Conversation

yasirarism
Copy link
Owner

@yasirarism yasirarism commented Sep 14, 2024

About This:
PAYDISINI_KEY = api key paydisini
PAYDISINI_CHANNEL_ID = paydisini channel id, default 11

Daftar dulu disini https://paydisini.co.id/Buat-Transaksi/ dan minta whitelist IP VPS agar bisa dipake, maybe soon this feature will be applied to some feature if user abuse my bot

Summary by Sourcery

Integrate Paydisini payment system into the application, allowing users to make payments and receive payment status updates. Add a new FastAPI-based web server to handle payment callbacks and provide system status information. Enhance the application with new environment variables for Paydisini configuration and introduce a WSGI server task.

New Features:

  • Integrate Paydisini payment system, allowing users to initiate payments through a new command and handle payment callbacks.
  • Introduce a new web server using FastAPI to handle payment callbacks and provide status information.

Enhancements:

  • Add environment variables for Paydisini integration, including PAYDISINI_KEY and PAYDISINI_CHANNEL_ID.
  • Implement a new asynchronous task to run a WSGI server using Uvicorn.

Copy link
Contributor

sourcery-ai bot commented Sep 14, 2024

Reviewer's Guide by Sourcery

This pull request integrates the Paydisini payment system into the MissKaty bot. It adds a new payment command, implements a callback endpoint for payment processing, and sets up a web server to handle API requests. The changes also include new environment variables for Paydisini configuration and modifications to the bot's initialization process.

File-Level Changes

Change Details Files
Implemented Paydisini payment integration
  • Added new 'payment' command to generate payment requests
  • Created QR code and payment guide for users
  • Implemented payment status tracking and database updates
  • Added Paydisini API key and channel ID to environment variables
misskaty/plugins/dev.py
misskaty/vars.py
Set up web server for API endpoints
  • Created FastAPI application for handling web requests
  • Implemented callback endpoint for payment processing
  • Added status endpoint for bot and system information
  • Integrated web server initialization with bot startup
web/webserver.py
misskaty/__main__.py
misskaty/__init__.py
Added database support for payment tracking
  • Created new collection 'autopay' in the database
  • Implemented functions for payment data management
  • Added support for updating and retrieving payment information
database/payment_db.py

Tips
  • Trigger a new Sourcery review by commenting @sourcery-ai review on the pull request.
  • Continue your discussion with Sourcery by replying directly to review comments.
  • You can change your review settings at any time by accessing your dashboard:
    • Enable or disable the Sourcery-generated pull request summary or reviewer's guide;
    • Change the review language;
  • You can always contact us if you have any questions or feedback.

@yasirarism yasirarism merged commit 3f6cd58 into master Sep 14, 2024
3 checks passed
@yasirarism yasirarism deleted the paydisini branch September 14, 2024 06:03
Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey @yasirarism - I've reviewed your changes - here's some feedback:

Overall Comments:

  • Consider improving error handling and providing more informative error messages, especially in the payment function. This will aid in debugging and improve user experience.
  • The payment integration logic is tightly coupled with the API calls. Consider separating the business logic from the API interaction for better maintainability and testability.
  • Add comprehensive unit and integration tests for the new payment feature to ensure reliability and catch potential issues early.
Here's what I looked at during the review
  • 🟡 General issues: 1 issue found
  • 🟡 Security: 3 issues found
  • 🟢 Testing: all looks good
  • 🟡 Complexity: 1 issue found
  • 🟢 Documentation: all looks good

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment to tell me if it was helpful.

async def payment(client: Client, message: Message):
api_url = 'https://api.paydisini.co.id/v1/'
api_key = PAYDISINI_KEY
unique_id = f"VIP-{secrets.token_hex(5)}"
Copy link
Contributor

Choose a reason for hiding this comment

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

🚨 suggestion (security): Consider using a longer token for the unique ID

While using secrets.token_hex() is good for security, a 5-byte token might not provide sufficient uniqueness for a payment ID. Consider using a longer token, such as secrets.token_hex(16), to reduce the risk of collisions.

Suggested change
unique_id = f"VIP-{secrets.token_hex(5)}"
unique_id = f"VIP-{secrets.token_hex(16)}"

# if id_ in user_data and user_data[id_].get("is_auth"):
# return await message.reply("Already Authorized!")
rget = await fetch.post(api_url, data=params)
if rget.status_code != 200:
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: Enhance error handling and logging

The current error handling is quite basic. Consider implementing more robust error handling and logging. For example, log the specific error message and status code, and provide more informative error messages to the user based on different error scenarios.

    if rget.status_code != 200:
        error_message = f"API Error: Status code {rget.status_code}"
        logging.error(f"{error_message}. Response: {rget.text}")
        user_message = "An error occurred while processing your request. Please try again later."
        return await message.reply(user_message)

LOGGER = getLogger(__name__)
getLogger("fastapi").setLevel(ERROR)

@api.post("/callback")
Copy link
Contributor

Choose a reason for hiding this comment

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

🚨 suggestion (security): Enhance security measures for payment callback

While you're verifying the IP and signature, consider adding additional security measures such as rate limiting, HTTPS enforcement, and possibly a webhook secret. Also, ensure that all sensitive data is properly sanitized before use.

@api.post("/callback", dependencies=[Depends(RateLimiter(times=10, seconds=60))])
@requires_https
async def autopay(request: Request, signature: str = Header(None)):
    if not verify_signature(signature, request):
        raise HTTPException(status_code=403, detail="Invalid signature")

exists = await autopay.find_one({"_id": uniqueCode})
return exists

async def autopay_update(self, msg_id: Optional[int] = "", note: Optional[str] = "", user_id: Optional[int] = "", amount: Optional[int] = "", status: Optional[str] = "", uniqueCode: Optional[str] = "", createdAt: Optional[str] = ""):
Copy link
Contributor

Choose a reason for hiding this comment

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

🚨 suggestion (security): Improve type hints and parameter handling

The type hints for integer fields (msg_id, user_id, amount) default to empty strings, which is inconsistent. Consider using None as the default value for these Optional fields. Also, validate and sanitize these inputs before using them in database operations to prevent potential injection attacks.

async def autopay_update(
    self,
    uniqueCode: str,
    msg_id: Optional[int] = None,
    note: Optional[str] = None,
    user_id: Optional[int] = None,
    amount: Optional[int] = None,
    status: Optional[str] = None,
    createdAt: Optional[str] = None
):
    data = {k: v for k, v in locals().items() if k != 'self' and v is not None}
    await autopay.update_one({"_id": uniqueCode}, {"$set": data}, upsert=True)

@@ -179,6 +184,45 @@
else:
await msg.edit_msg("Unsupported parameter")

@app.on_message(filters.command(["payment"], COMMAND_HANDLER))
Copy link
Contributor

Choose a reason for hiding this comment

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

issue (complexity): Consider refactoring the 'payment' function into smaller, focused helper functions.

The payment function introduces significant complexity by handling multiple responsibilities within a single function. To improve readability and maintainability, consider breaking it down into smaller, focused helper functions. Here's a suggested refactoring:

  1. API Call: Extract the API interaction into a separate function.
async def create_payment(api_url, api_key, unique_id, service_id, amount, valid_time):
    params = {
        'key': api_key,
        'request': 'new',
        'unique_code': unique_id,
        'service': service_id,
        'amount': amount,
        'note': 'MissKaty Support by YS Dev',
        'valid_time': valid_time,
        'type_fee': '1',
        'payment_guide': True,
        'signature': hashlib.md5((api_key + unique_id + service_id + amount + valid_time + 'NewTransaction').encode()).hexdigest(),
        'return_url': f'https://t.me/{client.me.username}?start'
    }
    return await fetch.post(api_url, data=params)
  1. QR Code Generation: Isolate the QR code generation logic.
def generate_qr_code(data):
    return f"https://api.qrserver.com/v1/create-qr-code/?size=300x300&data={quote(data)}"
  1. Database Update: Separate the database update logic.
async def update_payment_db(msg_id, note, user_id, amount, status, unique_code, created_at):
    await autopay_update(msg_id, note, user_id, amount, status, unique_code, created_at)

By organizing the code in this way, the main payment function will be more concise and focused, improving both readability and maintainability.

Comment on lines +11 to +12
exists = await autopay.find_one({"_id": uniqueCode})
return exists
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion (code-quality): Inline variable that is immediately returned (inline-immediately-returned-variable)

Suggested change
exists = await autopay.find_one({"_id": uniqueCode})
return exists
return await autopay.find_one({"_id": uniqueCode})

valid_time = str(5*60)
service_id = PAYDISINI_CHANNEL_ID

params = {
Copy link
Contributor

Choose a reason for hiding this comment

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

issue (code-quality): Replace f-string with no interpolated values with string (remove-redundant-fstring)

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