کانکشنیجات (Connectionijat) جزو مهمی از برگزاری ایونت‌های کشوری مانند المپیک‌فناوری پردیس هستند که اختلالات یا شنود در آن‌ها می‌تواند منجر به تبدیل شدن به یک فاجعه واقعی خواهد شد...

آقای لطفی (Mr.Lotfi) اسکواد لید کانتست کوئرا که همواره پس از برگزاری مسابقات و هکاتون‌ها توسط کوئرا، نظرسنجی‌های مفصلی را برای سنجیدن و بهبود هر چه بیشتر تمام جنبه‌های رویداد برگزار شده از شرکت‌کنندگان انجام می‌دهد، پس از دریافت نتایج نظرسنجی مسابقات برنامه‌نویسی و هوش‌مصنوعی سری اول #المپیک‌فناوری پردیس، به یک مشکل اساسی که کاربران زیادی به آن پرداخته بودند پی می‌برد، مشکلات کانکشنیجات!

کاربران در نظرسنجی‌ها به نبود زیرساختی مطمئن و سریع برای برقراری کانکشنیجات بین خودشان و طراحان و دست‌اندرکاران سری رویداد‌های المپیک‌فناوری پردیس معترض بودند! از آنجایی که آقای لطفی مثل همیشه مشتاق جلب بیشتر رضایت شرکت‌کنندگان است، به پیمانوش (Peymanoosh) در تیم فنی کوئرا، ماموریت جدیدی داده تا برنامه‌ای برای برقراری ارتباطات بهتر میان شرکت‌کنندگان و برگزار‌کنندگان سری جدید #المپیک‌فناوری پردیس با عنوان "فناوری کانکشنیجات" توسعه دهد.

تصویر سوال دوم

فناوری کانکشنیجات که بر اساس ارسال بسته‌های داده (Data Packet) طوری طراحی شده است که برای جلوگیری از شنود ارتباطات بین طراحان و برگزار‌کنندگان توسط شرکت‌کنندگان عادی، بسته‌های طعمه (Bait) ایجاد کند که اطلاعات واقعی ندارند، از دو بخش ارسال‌کننده پیام (Transmitter) و دریافت‌کننده پیام (Receiver) تشکیل شده است. همچنین علی رغم دانش فنی فراوان پیامنوش، به دلیل وسعت بسیار زیاد پارک فناوری پردیس، بسته‌ها ممکن است با ترتیب نامشخص (Jitter) به مقصد برسند.

پروژه‌ی اولیه

برای دانلود پروژه‌ی اولیه روی این لینک کلیک کنید.

ساختار فایل‌ها

fanavari-connectionijat/
├── tests/
├   ├── __init__.py
├   └── test_sample.py
├── base.py
├── packet.py
├── receiver.py
└── transmitter.py

جزئیات پروژه

تیم فنی کوئرا و به ویژه پیمانوش این روز‌ها به دلیل المپیک‌فناوری، لود زیادی را تحمل می‌کنند؛ از این رو پیمانوش تنها بعضی بخش‌های فناوری کانکشنیجات را توسعه‌ داده و پیاده‌سازی باقی قسمت‌های آن را بر عهده شما قرار داده است تا شما نیز در توسعه بخشی از زیرساخت ارتباطاتی المپیک‌فناوری سهیم باشید. شما در این سوال قرار است بخش‌های زیر از فناوری کانکشنیجات را طراحی کنید:

  1. یک دیتاکلاس (Data Class) برای مدل‌سازی بسته‌ها پیاده‌سازی کنید.
  2. کلاسی تحت عنوان فرستنده پیاده‌سازی کنید تا پیام‌ها را با فرمت بسته‌های مدل‌سازی شده ارسال کند؛ همچنین متدی برای اضافه کردن بسته‌‌های تقلبی اضافه کنید تا در مرحله‌ی تست پیمانوش از آن استفاده شود.
  3. کلاسی تحت عنوان گیرنده پیاده‌سازی کنید تا با دریافت پیام، بسته‌های طعمه را فیلتر کند و با مرتب‌سازی بسته‌های واقعی بر اساس شماره توالی، محتوای پیام اولیه را بازسازی نمایید.

پیاده‌سازی فایل base.py

این فایل شامل کلاس پایه‌ای به نام Base است که یک تابع کمکی مهم برای انجام عملیات هش (Hash) در اختیار سایر کلاس‌ها (Transmitter و Receiver) قرار می‌دهد.

محتوای این فایل از قبل به شکل زیر پیاده‌سازی شده است و در فایل پروژه اولیه قرار گرفته است:

import hashlib

class Base:
    def _hash_function(self, data: str, key: str) -> str:
        return hashlib.sha256((data + key).encode()).hexdigest()

پیاده‌سازی فایل packet.py

در این فایل باید دیتاکلاس Packet را پیاده‌سازی کنید. هر بسته‌ی داده‌ای که بین فرستنده و گیرنده در فناوری کانکشنیجات منتقل می‌شود، با این ساختار مدل‌سازی شده است که فیلد‌های آن به شکل زیر می‌باشد:

نام فیلد نوع داده توضیح
sequence_number int مشخص‌کننده‌ی جایگاه بسته در پیام اصلی (برای مرتب‌سازی)
data str محتوای واقعی بسته (یک بخش از پیام اصلی یا طعمه)
hashed_data str هش تولید شده از data با استفاده از کلید عمومی و تابع موجود در کلاس Base
  • توجه کنید که شما باید فیلد‌های جدول بالا را دقیقا با نام و نوع گفته شده پیاده‌سازی کنید، در غیر این صورت در سیستم داوری نمره‌ای به شما تعلق نخواهد گرفت.

  • همچنین توجه داشته باشید که شما مجازید تا هر تعداد فیلد‌ دلخواه دیگری را نیز برای پیاده‌سازی ادامه برنامه، در این کلاس معرفی کنید.

پیاده‌سازی متد is_valid

def is_valid(self, hash_func: Callable, key: str) -> bool:
    pass
  • خروجی این متد از نوع بولین‌ خواهد بود؛ در صورت برابر بودن مقدار hashed_data بسته‌ی موردنظر با مقدار خروجی تابع hash_func خروجی برابر با True و در غیر این‌صورت برابر با False خواهد بود.

نکته: تابعی که در پارامتر hash_func به متد موردنظر پاس داده‌ می‌شود، دارای دو ورودی از نوع رشته خواهد بود که ورودی اول رشته data بسته‌ی موردنظر و ورودی دوم key می‌باشد که کلیدی است که با آن data هش شده است.

نمونه‌ای از این تابع:

def example_hash_func(data: str, key: str) -> str:
    return f"hashed_{key}"
  • توجه داشته باشید که عملکرد هش کردن این تابع در تست‌های سوال متغیر خواهد بود و همیشه عملیات هش کردن به شکل بالا انجام نخواهد شد. این مورد صرفا یک نمونه برای درک بهتر سوال است.

پیاده‌سازی فایل transmitter.py

در این فایل باید کلاس Transmitter را پیاده‌سازی کنید. این کلاس پیام ورودی را به تکه‌های کوچک تقسیم می‌کند، برای هر تکه یک بسته‌ی واقعی با هش معتبر می‌سازد، سپس به تعداد مشخصی بسته‌ی طعمه اضافه می‌کند، ترتیب همه‌ی بسته‌ها را به‌هم می‌زند و آن‌ها را به گیرنده ارسال می‌کند. این کلاس از Base ارث‌بری می‌کند و برای ساخت هش از متد کمکی داخل این کلاس استفاده می‌کند.

پیاده‌سازی سازنده‌ی کلاس

در متد سازنده‌ی کلاس Transmitter، کلید مشترک که برای تولید هش بسته‌های واقعی استفاده می‌شود به عنوان ورودی دریافت شده و در متغیر داخلی self._key ذخیره می‌گردد. علاوه بر این، هنگام ایجاد شیء می‌توان پارامترهای دیگری نیز مشخص کرد. پارامتر self.bait_count تعداد بسته‌های طعمه‌ای را تعیین می‌کند که در ادامه ساخته خواهند شد، همچنین پارامتر self.chunk_size اندازه‌ی هر برش از پیام را مشخص می‌کند تا پیام اصلی در فرآیند تکه‌تکه‌سازی به قطعات مناسب تقسیم شود. این مقادیر علاوه بر کلید ورودی، امکان مدیریت دقیق‌تر و انعطاف‌پذیری بیشتر در پردازش و اعتبارسنجی داده‌ها را فراهم می‌آورند.

def __init__(key: str, bait_count: int = 2, chunk_size: int = 3):
    pass

پیاده‌سازی متد _add_bait_packets

این متد به تعداد bait_count بسته‌‌های طعمه می‌سازد و آن‌ها را به لیست packets ارسال شده اضافه می‌کند. توجه داشته باشید که محتوای بسته‌های طعمه اهمیتی ندارد.

def _add_bait_packets(self, packets: list) -> None:
    return None

پیاده‌سازی متد _prepare_packets

این متد ابتدا پیام را به تکه‌هایی با طول chunk_size تقسیم می‌کند (تکه‌ی آخر ممکن است از این مقدار کمتر باشد): سپس برای هر تکه، هش معتبر را با توابع موجود تولید می‌کند و یک نمونه از دیتاکلاس Packet با داده‌های فعلی ایجاد می‌کند که شماره‌ی هر بسته نیز به صورت متوالی با شروع از عدد 1 شماره‌گذاری می‌شود.

سپس با استفاده از متد _add_bait_packets، طعمه‌ها را به لیست بسته‌ها اضافه می‌کند و در پایان لیست نهایی را بُر می‌زند (Shuffle) و آن را برمی‌گرداند (return می‌کند).

def _prepare_packets(self, message: str) -> list[Packet]:
    pass

پیاده‌سازی متد transmit

این متد باید پیام موردنظر را به گیرنده‌ی مربوطه ارسال می‌کند؛ برای این‌کار ابتدا با متد _prepare_packets(message) بسته‌ها ساخته شود و سپس آن‌ها را به متد receive گیرنده ارسال کند؛ درنهایت همان بسته‌ها را به عنوان خروجی متد برگردانده شود.

def transmit(self, message: str, receiver: Receiver) -> list[Packet]:
    pass

پیاده‌سازی فایل receiver.py

در این فایل، شما باید کلاسی به نام Receiver پیاده‌سازی کنید که بتواند بسته‌های دریافتی از فرستنده را بررسی کرده؛ بسته‌های تقلبی (Bait) را شناسایی و فیلتر کند و در نهایت پیام اصلی را بازسازی کند. این کلاس دارای سه متد زیر است که باید هر یک را به صورت خواسته شده پیاده‌سازی کنید.

پیاده‌سازی سازنده‌ی کلاس

این متد هنگام ساخته شدن شیء از کلاس Receiver فراخوانی می‌شود و کلید عمومی (رشته‌ی pub_key) را به عنوان ورودی دریافت می‌کند و در پارامتر self._key قرار می‌دهد. از این کلید جلوتر در اعتبارسنجی هش‌ها استفاده خواهد شد. توجه داشته باشید که شما می‌توانید متغیرهای کمکی دیگری نیز در متد ایجاد کنید.

def __init__(self, key: str):
    pass

پیاده‌سازی متد receive

این متد، یک لیست از بسته‌ها (packets) که هر عضو آن از نوع Packet است را دریافت می‌کند. باید مشخص شود که هر بسته معتبر است یا خیر و در صورت معتبر بودن، در یک لیست دیگر ذخیره شود. برای بررسی معتبر بودن هر بسته با استفاده از متدis_valid بسته‌ی موردنظر استفاده شود. فقط بسته‌هایی که فیلد hased_data آن‌ها با مقدار هش data با استفاده از کلید برابر است را ذخیره کند و بسته‌های نامعتبر نادیده گرفته شوند.

def receive(self, packets: list[Packet]) -> None:
    pass

پیاده‌سازی متد get_message

این متد، پس از با فراخوانی متد قبلی (دریافت تمام بسته‌ها و حذف بسته‌های طعمه) باید با مرتب‌سازی لیست بسته‌ها، رشته‌ی حاوی پیام اصلی را بازسازی کند. در صورتی که دو بسته‌ی معتبر با شماره‌ی توالی برابر وجود داشته‌ باشند باید به ترتیب ورودی در پیام خروجی نمایش داده‌ شوند.

def get_message(self) -> str:
    pass

مثال‌ها

نمونه‌ی مثال ۱

from transmitter import Transmitter
from receiver import Receiver

transmitter = Transmitter(key="k", bait_count=2, chunk_size=3)
receiver = Receiver("k")
packets = transmitter.transmit("hello world", receiver)
print(packets)
# ["hel", "low", "orl", "d"]
message = receiver.get_message()
print(message)
# hello world
  • در این مثال، پیام به تکه‌های ["hel", "low", "orl", "d"] تقسیم می‌شود و سپس سه بسته‌ی طعمه به لیست بسته‌ها افزوده و کل لیست درهم‌ریزی می‌شود. سپس با استفاده از متد transmit به گیرنده‌ی مربوطه ارسال می‌شود؛ در نهایت با فراخوانی متد get_message در گیرنده‌ی موردنظر، پیام اولیه (hello world) چاپ می‌شود.

نمونه‌ی مثال ۲

from transmitter import Transmitter
from receiver import Receiver

transmitter = Transmitter(key="s3cr3t", bait_count=3, chunk_size=4)
receiver = Receiver("s3cr3t")
packets = transmitter.transmit("abcdefghijk", receiver)
# ["abcd", "efgh", "ijk"]
message = receiver.get_message()
# abcdefghijk
  • در این مثال، پیام به تکه‌های ["abcd", "efgh", "ijk"] تقسیم می‌شود، سپس سه بسته‌ی طعمه به لیست بسته‌ها افزوده و کل لیست درهم‌ریزی می‌شود. سپس با استفاده از متد transmit به گیرنده‌ی مربوطه ارسال می‌گردد؛ در نهایت با فراخوانی متد get_message در گیرنده، پیام اولیه (abcdefghijk) بازسازی و چاپ می‌شود.

آن‌چه باید آپلود کنید

  • توجه: پس از اعمال تغییرات، کل پروژه را Zip کرده و آپلود کنید. همانند پروژه اولیه در فایل زیپ شده نباید کد در پوشه‌ی دیگری قرار بگیرد در غیر این صورت سیستم داوری فایل را شناسایی نکرده و نمره‌ای دریافت نخواهید کرد.

  • توجه: تنها فایل‌هایی که در ساختار پروژه مشخص شده‌اند، در سیستم داوری مورد پذیرش قرار خواهد گرفت و سایر تغییرات در سایر فایل‌ها بی‌تاثیر خواهند بود.

ارسال پاسخ برای این سؤال
فایلی انتخاب نشده است.