feat: Enhance captcha handling with submission tracking and user restriction

This commit is contained in:
Slipstream 2025-05-21 11:43:34 -06:00
parent 085d9be740
commit 149a96a90d
Signed by: slipstream
GPG Key ID: 13E498CE010AC6FD

View File

@ -22,20 +22,42 @@ class CaptchaModal(discord.ui.Modal, title="Solve Image Captcha"):
max_length=100
)
self.add_item(self.solution)
self.submitted = asyncio.Event() # Event to track when the modal is submitted
self.timed_out = True # Default to True, set to False when submitted
async def on_submit(self, interaction: discord.Interaction):
# This method will be called when the user submits the modal
# The actual file upload logic will be handled by the calling function
await interaction.response.defer(ephemeral=True) # Defer the response to prevent interaction timeout
self.timed_out = False # Mark as not timed out since it was submitted
self.submitted.set() # Set the event to indicate submission
async def wait(self) -> bool:
"""Wait for the modal to be submitted or time out.
Returns:
bool: True if the modal timed out, False if it was submitted.
"""
try:
# Wait for the modal to be submitted with a timeout
await asyncio.wait_for(self.submitted.wait(), timeout=600) # 10 minute timeout
return self.timed_out
except asyncio.TimeoutError:
return True # Timed out
class CaptchaView(discord.ui.View):
def __init__(self, modal: CaptchaModal):
def __init__(self, modal: CaptchaModal, original_interactor_id: int = None):
super().__init__(timeout=600) # 10 minutes timeout
self.modal = modal
self.original_interactor_id = original_interactor_id
@discord.ui.button(label="Solve Captcha", style=discord.ButtonStyle.primary)
async def solve_button(self, interaction: discord.Interaction, button: discord.ui.Button):
async def solve_button(self, interaction: discord.Interaction, _: discord.ui.Button):
# Only allow the original user to solve the captcha
if self.original_interactor_id and interaction.user.id != self.original_interactor_id:
await interaction.response.send_message("Only the user who initiated the upload can solve this captcha.", ephemeral=True)
return
await interaction.response.send_modal(self.modal)
@ -44,7 +66,7 @@ class UploadCog(commands.Cog, name="Upload"):
def __init__(self, bot: commands.Bot):
self.bot = bot
self.api_base_url = "https://upload.slipstreamm.dev/upload"
self.api_base_url = "https://upload.slipstreamm.dev/upload" # Base URL already includes /upload
self.session = None
self.captcha_cache = {} # Store captcha IDs temporarily
self.headers = {
@ -101,7 +123,13 @@ class UploadCog(commands.Cog, name="Upload"):
if not endpoint.startswith("/"):
endpoint = f"/{endpoint}"
# Fix for duplicate /upload in the path
# If endpoint starts with /api/upload, remove the /upload part as it's already in the base URL
if endpoint.startswith("/api/upload/"):
endpoint = endpoint.replace("/api/upload/", "/api/")
url = f"{self.api_base_url}{endpoint}"
print(f"Making {method} request to: {url}")
try:
if method.upper() == "GET":
@ -156,16 +184,13 @@ class UploadCog(commands.Cog, name="Upload"):
embed.set_image(url="attachment://captcha.png")
embed.set_footer(text="This captcha is valid for 10 minutes. Enter the text from the image.")
# Send the captcha image and instructions
await interaction.followup.send(embed=embed, file=captcha_image_file, ephemeral=True)
# Create the modal instance
modal = CaptchaModal(captcha_id=captcha_id)
# Create a view with a button that sends the modal
view = CaptchaView(modal=modal)
# Create a view with a button that sends the modal, restricted to the original user
view = CaptchaView(modal=modal, original_interactor_id=interaction.user.id)
# Send the captcha image and instructions with the view
# Send the captcha image, instructions, and the view in a single message
await interaction.followup.send(embed=embed, file=captcha_image_file, view=view, ephemeral=True)
# Wait for the modal submission
@ -207,7 +232,11 @@ class UploadCog(commands.Cog, name="Upload"):
)
file_id = upload_data.get("id", "unknown")
# Construct the file URL correctly
# The base URL is https://upload.slipstreamm.dev/upload
# The file URL should be https://upload.slipstreamm.dev/upload/uploads/{file_id}
file_url = f"{self.api_base_url}/uploads/{file_id}"
print(f"File URL: {file_url}")
# Format file size nicely
file_size_bytes = upload_data.get('file_size', 0)