فعال

نِکونیموس

نِکونیموس یک ربات تلگرام فارسی‌محور و متن‌باز برای لینک شخصی، پیام و پاسخ ناشناس، کنترل‌های حریم خصوصی و پیشنهاد گفت‌وگوی اختیاری است؛ با معماری تیکت‌های مستقل روی Cloudflare.

به‌روزرسانی ۷ دقیقه مطالعه
نِکونیموس

نِکونیموس یک ربات پیام ناشناس فارسی‌محور است؛ برای ساخت لینک شخصی، دریافت پیام، پاسخ ناشناس و شروع گفت‌وگو بدون نمایش هویت دو طرف در جریان عادی محصول.

اما مسئله‌ی اصلی پروژه فقط مخفی‌کردن نام کاربران از یکدیگر نبود. سؤال مهم‌تر این بود که خود سیستم برای رساندن یک پیام، واقعاً چه مقدار داده باید نگه دارد.

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

نسخه‌ی اول نِکونیموس یک محصول Telegram-only است. صفحه‌ی وب مسیر معرفی و مستندات را فراهم می‌کند، اما خود بات سطح اصلی استفاده از محصول باقی می‌ماند.

مسیرها:

چرا وجود دارد

یک ربات پیام ناشناس در ظاهر کار کوچکی انجام می‌دهد:

یک نفر پیام می‌فرستد
→ بات آن را پیدا می‌کند
→ پیام به صاحب لینک می‌رسد

اما پیاده‌سازی ساده‌ی همین جریان معمولاً خیلی زود به یک دیتابیس قابل جست‌وجو از کاربران، پیام‌ها و رابطه‌هایشان تبدیل می‌شود:

sender_id
recipient_id
message_body
conversation_id
created_at

حتی اگر متن پیام رمزنگاری شود، چنین مدلی هنوز می‌تواند نشان دهد چه کسی با چه کسی در ارتباط بوده، چند بار پیام فرستاده و هر ارتباط چقدر ادامه پیدا کرده است.

نِکونیموس از این سؤال ساخته شد:

آیا می‌شود یک بات پیام ناشناس فقط پیام را برساند، بدون اینکه برای انجام همین کار به صاحب یک آرشیو منسجم از زندگی خصوصی کاربران تبدیل شود؟

هدف پروژه ساخت «امن‌ترین پیام‌رسان ناشناس» یا وعده‌ی حذف همه‌ی ردپاها نبود. هدف محدودتر و عملی‌تر بود: کم‌کردن داده‌ی ذخیره‌شده، شکستن رابطه‌های مستقیم میان storageها و توضیح صادقانه‌ی مرزهایی که هنوز وجود دارند.

چه چیزی را بررسی می‌کند

نِکونیموس چند مسئله‌ی فنی و محصولی را کنار هم بررسی می‌کند.

پیام ناشناس بدون transcript دائمی

هر پیام یک capability مستقل، lookup کور، payload رمزنگاری‌شده و route محدود خودش را دارد. پاسخ نیز ادامه‌ی یک conversation row دائمی نیست؛ یک تیکت تازه است.

صندوق به‌عنوان صف تحویل

صندوق نِکو آرشیو تاریخچه نیست. unreadها فقط تا زمان تحویل نگه‌داری می‌شوند. بعد از ارسال موفق پیام به Telegram، payload پاک و unread pointer حذف می‌شود.

کنترل سوءاستفاده با داده‌ی کمتر

بلاک، گزارش و sanction باید کار کنند، اما نباید برای این کار یک social graph خوانا ساخته شود. نِکو از tagهای کور و stateهای محدود برای block و abuse tracking استفاده می‌کند.

پیشنهاد گفت‌وگو بدون ادعای سازگاری

کاربر می‌تواند با یک ارزیابی ۲۵سؤالی، پروفایل محدودی از سبک گفت‌وگو و انتظار فعلی خودش بسازد. نمایش در پیشنهادها خاموش است تا زمانی که خود کاربر آن را فعال کند.

در flow فعلی Telegram، پیشرفت ارزیابی، وضعیت نمایش، خلاصه‌ی پروفایل و آمادگی پیشنهادها در یک hub دیده می‌شوند. پیشرفت قابل ذخیره و ادامه‌دادن است. شروع ارزیابی دوباره نمایش را خاموش می‌کند و دکمه‌ی دیدن پیشنهادها نیز تا ساخت هر دو vector و تأیید index آماده نمی‌شود.

Vectorize فقط گزینه‌های اولیه را پیدا می‌کند. رتبه‌بندی نهایی در TypeScript، قطعی و قابل تست است. سیستم درصد سازگاری، تشخیص شخصیت یا تصمیم خودکار درباره‌ی آدم‌ها ارائه نمی‌کند.

حریم خصوصی با مرزهای روشن

نِکو E2EE یا zero-knowledge نیست. Telegram و Worker هنگام پردازش، plaintext پیام را می‌بینند. رمزنگاری در این پروژه برای کم‌کردن plaintext ذخیره‌شده و ارزش یک storage dump استفاده می‌شود، نه برای پنهان‌کردن واقعیت پردازش.

چطور کار می‌کند

جریان اصلی پیام ساده باقی مانده است:

لینک شخصی
→ نوشتن پیام
→ ساخت تیکت مستقل
→ ذخیره‌ی route و payload رمزنگاری‌شده
→ unread موقت در UserState
→ اعلان به گیرنده
→ تحویل از صندوق
→ پاک‌شدن payload
→ باقی‌ماندن actionهای محدود تا انقضا

معماری روی یک Cloudflare Worker اجرا می‌شود و هر ابزار مسئولیت مشخصی دارد:

Telegram Bot API


Cloudflare Worker + grammY

        ├── D1
        │   حساب‌ها، لینک‌های عمومی و آمار تجمیعی

        ├── Durable Objects
        │   state کاربر، تیکت‌ها، safety، پروفایل‌ها،
        │   درخواست‌های گفت‌وگو و Telegram Outbox

        ├── KV
        │   cache و routing به‌صورت best-effort

        ├── Queues
        │   تحویل inbox، اعلان، آمار و profile indexing

        ├── Vectorize
        │   retrieval محدود گزینه‌های گفت‌وگو

        └── Web Crypto
            HMAC، HKDF و AES-GCM

ساختار سورس عمومی نیز همین مرزها را با folderهای کم‌عمق مستقیم زیر src/ نشان می‌دهد: identity/، ticketing/، profile/، suggestions/ و بخش‌های دیگر runtime. typeهای مشترک و clientهای Durable Object هم در types/ و storage/ به‌شکل flat قابل پیدا کردن‌اند. cleanup روز ۱۶ ژوئیه‌ی ۲۰۲۶ مسیر خواندن کد و importها را تغییر داد، نه مدل runtime را.

D1 منبع ساختارهای relational است، اما متن پیام ناشناس و graph مستقیم فرستنده و گیرنده را نگه نمی‌دارد.

Durable Objectها stateهایی را مدیریت می‌کنند که به ترتیب، lease، transaction یا coordination محلی نیاز دارند. KV فقط cache است و اگر در دسترس نباشد، مسیر اصلی باید از D1 ادامه پیدا کند.

Queueها کارهای retryپذیر را از مسیر اصلی کاربر جدا می‌کنند. چون تحویل Queue ممکن است تکرار شود، operationهای حساس مثل ارسال Telegram، تحویل ticket و پذیرش درخواست گفت‌وگو idempotent طراحی شده‌اند.

هر تیکت یک capability سی‌ودوبایتی دارد. یک بخش برای ساخت lookup کور و بخش دیگر برای مشتق‌کردن کلیدهای مستقل route، payload و metadata استفاده می‌شود. capability خام در TicketVault ذخیره نمی‌شود و actionهای آن علاوه بر capability به حساب فعلی گیرنده هم متصل‌اند.

این ویژگی باعث می‌شود hard reset فقط لینک عمومی را تغییر ندهد؛ با ساخت internal account تازه، callbackهای تیکت‌های قبلی نیز اعتبار خودشان را از دست می‌دهند.

چه چیزی یاد گرفتم

مهم‌ترین درس پروژه این بود که حریم خصوصی فقط یک مسئله‌ی رمزنگاری نیست.

ممکن است متن پیام‌ها با الگوریتم درستی رمزنگاری شوند، اما storage model همچنان رابطه‌ی میان کاربران را به‌شکل واضح نگه دارد. در مقابل، ممکن است معماری داده‌ی کمتری بسازد، اما retry اشتباه یا cleanup تهاجمی باعث گم‌شدن پیام شود.

پس privacy، correctness و reliability در این پروژه از هم جدا نیستند.

چند اصل در جریان ساخت نِکو برایم روشن‌تر شد:

  • چیزی که ذخیره نمی‌شود، بعداً نیاز به محافظت یا پاک‌کردن ندارد؛
  • رمزنگاری متن بدون فکرکردن به route و metadata کافی نیست؛
  • Queue را نباید exactly-once فرض کرد؛
  • failure موقت نباید باعث حذف destructive داده‌ی سالم شود؛
  • reset واقعی باید identity عملیاتی قبلی را بشکند؛
  • پیشنهاد گفت‌وگو باید consent-first باشد و از ادعاهای روان‌شناختی دور بماند؛
  • open-source بودن تضمین امنیت نیست، اما امکان بررسی و نقد را باز می‌کند؛
  • مستندات حریم خصوصی باید دقیقاً همان چیزی را بگویند که کد انجام می‌دهد.

نِکو برای من فقط تمرین ساخت یک Telegram bot نبود. تمرینی بود برای اینکه یک مسئله‌ی کوچک محصولی را تا storage contract، threat model، failure semantics، تجربه‌ی کاربری و انتشار عمومی دنبال کنم.

وضعیت فعلی

نسخه‌ی اول نِکونیموس تست شده و برای انتشار عمومی آماده است.

خط پشتیبانی‌شده‌ی master اکنون شامل این بخش‌هاست:

  • لینک شخصی پیام ناشناس؛
  • ارسال متن و رسانه‌های پشتیبانی‌شده؛
  • تیکت‌های مستقل و مهروموم‌شده؛
  • صندوق تحویل محدود؛
  • اعلان با شمارنده‌ی زنده؛
  • پاسخ ناشناس؛
  • نام خصوصی؛
  • بلاک و رفع بلاک؛
  • گزارش کور و sanction خودکار؛
  • توقف و ادامه‌ی دریافت پیام؛
  • hard account reset؛
  • پروفایل سبک گفت‌وگو؛
  • hub یکپارچه‌ی پروفایل و پیشنهادها با پیشرفت ذخیره‌شده و gate آمادگی؛
  • پیشنهاد گفت‌وگوی اختیاری؛
  • درخواست گفت‌وگو با پذیرش دوطرفه؛
  • Telegram Outbox با pacing و idempotency؛
  • آمار تجمیعی بدون اسکن vaultهای کاربران؛
  • testها و auditهای مخصوص storage boundary، retry، reset و logging.

نِکونیموس همچنان یک hosted relay است و به Telegram، Cloudflare و operator پروژه اعتماد دارد. این محدودیت در README، Threat Model، آزمایشگاه فنی و متن‌های داخل بات به‌صورت یکسان بیان شده است.

قدم‌های بعدی

  • انتشار نسخه‌ی اول و ثبت release عمومی؛
  • همگام نگه‌داشتن صفحه‌ی پروژه، مقاله، آزمایشگاه، README و متن‌های Telegram با master؛
  • بررسی رفتار واقعی inbox، Queue و Outbox بعد از ورود کاربران؛
  • جمع‌کردن بازخورد درباره‌ی زبان گربه‌ای، کنترل‌های حریم خصوصی و پیشنهاد گفت‌وگو؛
  • ارزیابی abuse patternها پیش از اضافه‌کردن ابزار moderation سنگین‌تر؛
  • مستندکردن provenance و روش‌های بهتر برای نزدیک‌کردن کد عمومی به نسخه‌ی deployشده؛
  • بازکردن scope نسخه‌ی بعد فقط بر اساس استفاده‌ی واقعی و feedback، نه اضافه‌کردن feature پیش از انتشار.

نسخه‌ی اول نِکو قرار نیست پایان این مسئله باشد. فعلاً یک پاسخ کوچک، قابل اجرا و قابل بررسی است به این سؤال:

یک سیستم پیام ناشناس چطور می‌تواند وظیفه‌اش را انجام دهد، بدون اینکه بیشتر از نیازش درباره‌ی آدم‌ها و حرف‌هایشان بداند؟

اشتراک‌گذاری

ادامه مطالعه