<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های ;...z@nko!#</title>
        <link>https://virgool.io/feed/@zankoAn</link>
        <description>یه بک اند دولوپر پایتون، علاقمه مند به DevOps  و دیپ شدن در مباحث مرتبط  &quot;-)

https://mastodon.social/@zankoAN</description>
        <language>fa</language>
        <pubDate>2026-06-17 00:37:23</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/196572/avatar/e8rT9n.jpeg?height=120&amp;width=120</url>
            <title>;...z@nko!#</title>
            <link>https://virgool.io/@zankoAn</link>
        </image>

                    <item>
                <title>🧤 آسیب پذیری 0.0.0.0 Day مشکل من با 0.0.0.0 ؟ 🧤</title>
                <link>https://virgool.io/@zankoAn/day-0-0-0-0-rzro84tqtdrr</link>
                <description>0.0.0.0امروز داشتم کدم رو مینوشتم و چون داخل لوکال هاست بود و فعلا برای پروداکشن نبود، داخل فرانت اند ست کردم که ادرس API من باشه 0.0.0.0:8000 و خب بک اند هم روی لوکال در حال اجرا بود... اما شب داشتم تست میکردم، دیدم کلا مروگر ارور ERR_EMPTY_RESPONSE میده بهم و منطقی نیست و برای همین یکم سرچ کردم... و رسیدم به آسیب پذیری 0.0.0.0 Day  ( که البته ربطی به مشکل من هم نداشت و مشکل از افزونه proxy switcher بود ولی خب این هم موضع جالبی بود و خواستم راجبش بنویسم).قبل از اینکه بریم سراغ این اسیب پذیری بهتر راجب PNA و CORS سرچ کنید‌( تو پست قبلی راجب CORS حرف زدیم و میتونید اونجا رو هم ببینید)0.0.0.0 Dayاین آسیب پذیری مربوط میشه به خود مروگر ها و شرکت Oligo Security چند ماه پیش گزارشش رو  داده،  به هکر اجازه میده که روی مروگر های روز مره(مثل فایرفاکس، کروم،‌ سافاری) بتونه از طریق یه وبسایت پابلیک با دور زدن PNA و CORS به سرویس های لوکال سمت کلاینت درخواست بفرسته و حتی بتونه دست رسی بگیره و... البته آسیب پذیری شامل ویندوز نمیشه چون دیفالت 0.0.0.0 ip رو بلاک میکنه و فقط برای لینوکس و مک هستش (‌ آسیب پذیری قرار تو ورژن های جدید مروگر ها به زودی فیکس بشه.)ماجرا از اینجا شروع میشه که اگه یه هکر بیاد و یه وبسایت مخرب( فیشینگ *) رو بیاره بالا و شما برید داخل اون وبسایت، هکر میتونه از طریق مرورگر و جاوااسکریپت یه درخواست بفرسته به یه پورت روی ip 0.0.0.0  ( که اشاره میکنه به همه ip های موجود داخل اون شبکه) و حالا اگه یه سرویسی روی اون پورت در حال اجرا باشه ریکوست رو میتونه دریافت بکنه و درخواست رو هم انجام بده.برای جلوگیری از همچین اتفاقی داخل مروگر ها قابلیت CORS و Private Network Access (PNA) رو داریم که نمیزاره یه سایت پابلیک بیاد ریکوست fetch بفرسته به شبکه داخلی ما و دیتا بگیره یا دست رسی پیدا بکنه و...PNA &amp; CORSتوی این آسیب پذیری درواقع هکر با fetch میاد یه ریکوئست http میفرسته با  mode: no-cors و اینشکلی دیگه درخواست Preflight برای CORS ارسال نمیشه و مستقیم ریکوست از سمت وبسایت میره سمت سرویسی که رو سیستم در حال اجرا هستش ( تو مود non-cors ریسپانس سرور رو نمیتونیم ببینیم داخل مروگر ) و اینشکلی هکر میتونه مثلا اسکن بکنه پورت های ما رو و اگه بفهمه مروبط به سرویس خاص هستش و... شاید بتونه یه مشکل امنیتی ازش پیدا بکنه و مثل چیزی که تو مقاله بود دست رسی RCE (Remote Code   Execution) بگیره و... که البته سخته..!!علاوه بر CORS گفتیم PNA هم وجود داره، الان اگه اینجا ریکوست بفرستیم به localhost یا 127.0.0.1 و یه سری ip دیگه( تصویر پایین) این PNA جلوش رو میگیره و نمیزاره درخواست بره، اما داخل لیستی که PNA ازش جلوگیری میکنه ایپی 0.0.0.0 نیست و برای همین ترکیبش با mode: non-cors  میتونه این باگ امنیتی رو بوجود بیاره .Non-public IP address blocks البته کم کم فیکس میشه این مشکل و سخت هم هستش که همچین تارگتی پیدا کرد ولی در کل مشکلی هست که وجود داره، همونطور که داخل مقاله میگه بهتر به لوکال هاست اعتماد نکنیم چون لوکال !مرسی که تا اینجا خوندید، چاکس ❤️جزئیات کامل همراه با مثال و... اینجا قرار گرفته که میتونید بخونید:https://www.oligo.security/blog/0-0-0-0-day-exploiting-localhost-apis-from-the-browserاینجا هم یه سری نکته برای دولوپر ها گذاشتن که میتونیم داخل لوکال اپلیکیشن مون انجام بدیم تا از این نوع حمله ها جلوگیری کنیم:https://www.oligo.security/blog/0-0-0-0-day-exploiting-localhost-apis-from-the-browser#how-can-i-protect-local-applications-from-0000-day</description>
                <category>;...z@nko!#</category>
                <author>;...z@nko!#</author>
                <pubDate>Thu, 19 Dec 2024 05:54:49 +0330</pubDate>
            </item>
                    <item>
                <title>🎗 برسی CORS Policy سمت سرور و بک اند ❄️</title>
                <link>https://virgool.io/@zankoAn/cors-policy-atdilsqcmzq3</link>
                <description>CORS🪽 سلام به همگی!  به اون افرادی که لذت میبرن از شکافتن لایه های ابسترکت و عمیق شدن 🦔تو این مقاله میخوایم راجب  CORS Policy حرف بزنیم و ببینیم کلا چی هستش، چرا از نظر امنیتی مهمه و اگر با ارور های مربوط به CORS Policy بخورد کردیم چطوری دیباگ کنیم.  جنبه های مختلفش رو برسی مکنیم تا درک خیلی بهتری ازش پیدا بکنیم. این مقاله شامل موضوعات زیر میشه:توضیح کوتاهی راجب SOP.برسی اینکه CORS چی هستش و موارد بیسیک.از نظر امنیتی چرا CORS اهمیت داره و برسی flow کلی.برسی هدر هایی مربوط به CORS.نگاهی به CORS داخل جنگو و نحوه دیباگ کردن ارور های مربوط بهش.SOP(Same-origin policy)قبل از CORS بیاید یکم راجب SOP حرف بزنیم، SOP یه مکانیزم امنیتی هستش برای جلوگیری از یه سری اتک مثل CSRF که به صورت دیفالت داخل مروگر ها اعمال شده، وقتی ما سایت x رو باز میکنیم داخل این سایت میتونیم به همین origin فعلی درخواست بفرستیم و مکانیزم SOP مشکلی با این عملکرد نداره، ولی اگر بیایم از origin X درخواست بفرستیم به origin Y اینجا هستش که SOP به ما گیر میده و ارور های مربوط به CORS Policy میده، و اجازه نمیده درخواست مون ارسال بشه و به دیتای origin دیگه دسترسی داشته باشیم.فرض کنید یه هکر بیاد یه سیات مخرب ایجاد بکنه و یه کد js داخل سایت باشه که وقتی کاربر سایت رو باز میکنه این کد js اجرا بشه، حالا اگر کاربر داخل سایت y  لایگن باشه اینجا وقتی سایت هکر رو باز میکنه درخواست از سمت اون به سایت y فرستاده میشه(بر فرض اینکه هکر سایت y رو میدونه...) و ریسپانس درخواست برگشت داده میشه به هکر و اون میتونه به دیتا دسترسی داشته باشه که این امن نیست، برای همین  SOP بوجود اومد تا دسترسی رو محدود بکنه(تو قسمت مربوط به security بیشتر برسی میکنیم).originنکته: وقتی میگیم origin منظور مون مبدا درخواست هستش، خود origin شامل 3 بخش میشه که داخل تصویر بالا میتونید مشاهد کنید.CORS(Cross-Origin Resource Sharing) Mechanism?بالاتر گفتیم SOP چی هستش و چه کاری انجام میده، ولی بعضی وقتا نیاز هستش که به بعضی از origin ها دسترسی بدیم، مثلا سمت فرانت اند درخواست با یه origin دیگه به backend ارسال میشه، یا اگر از  OAuth اتنتیکیشن استفاده کرده باشیم گوگل و... نیاز دارن که یه سری تعاملات با origin ما داشته باشن و سرویس های دیگه...، اینجا هستش که CORS وارد ماجرا میشه و همونطور که از اسمش پیداست یعنی اشتراک گذاشتن دیتای یه origin با origin های دیگه، این هم یه مکانیزم دیگه هستش که بر اساس هدر های http تشخیص میده که یه origin اجازه ارسال درخواست به origin ما رو داره یا نه، مثل SOP دیفالت داخل مروگر ها هستش و اعمال میشه،‌ وقتی از یه origin دیگه درخواست میفرستید اول یه درخواست prefight رو میفرسته تا ببینه origin دیگه اجازه تعامل باهاش رو میده یا نه و بعد اگر داخل header ها تایید کرده بود ادامه درخواست ها رو میفرسته و...نکته: داخل مرورگر وقتی از origin X درخواست رو برای origin Y  میفرستیم اول یه ریکوئست از نوع  OPTION ارسال میشه که بهش میگن &quot;Preflight request&quot;، این درخواست میره تا بدونه بک اند پالیسی خاصی برای هدر های CORS تایین کرده یا نه، مثلا بک اند شاید یه سری اجازه ها رو داده باشه(در قسمت هدر ها بیشتر میگیم) و اگر بک اند اجازه ای نداده باشه و... اینجا مروگر میاد به کاربر CORS Policy ERR میده.Understanding CORS Securityفرض کنید یه سری کاربر داخل سایت ما(shop.com) لاگین کردن و دربک اند براشون سشن ایجاد شده( درواقع authenticate شدن)، این وسط یه هکر هم وجود داره که یه وبسایت فیک بالا اورده، مثلا test.com و داخل سایتش یه کد js وجود داره که وقتی صفحه وبسایت باز میشه این js ران میشه، داخل عکس میتونید flow کلی رو ببینید:flowداخل تصویر بالا همونطور که میبینید تو استپ 1 و 2 یوزر اول سایت test.com رو باز کرده بعد کد js ران شده و درخواست رو فرستاده به shop.com و چون origin متفاوت هستش میاد اول درخواست prefight میفرسته تا ببینه سرور بهش اجازه ارسال درخواست اصلی رو میده یا نه، تو استپ 3 بک اند اگر درست کانفیگ نشده باشه و.. به همه اجازه میده،  اینجا اگر اجازه بده میره مرحله 4 و درغیر اینصورت ریکوئست ارور CORS Policy میگیره.تو استپ 4 میاد درخواست اصلی اجرا میشه که میتونه درخواست به سمت هر endpointی باشه و... اینجا هکر میتونه پارامتر credintial=True رو هم داخل درخواست تو js قرار بده که اینشکلی از قابلیت ارسال اتوماتیک داده های مربوط به اعتبار سنجی از سمت مرورگر  استفاده میشه:  کاربر داخل سایت shop.com لاگین هستش پس هنوز سشنس داخل لوکال استوریج وجود داره و اینجا هستش که از قابلیت دیفالت مروگر استفاده میشه و زمان درخواست از اینجا سشن رو برمیداره مرورگر و با درخواست میفرسته سمت بک اند، درواقع مثل این میمونه که کاربر درخواست رو فرستاده باشه نه هکر.تو استپ 5 بک اند میاد برای کاربر یه response برمیگردونه که این باز برمیگرده به هکر و اون میتونه به دیتا دسترسی داشته باشه همچنین داخل این ریسپانس تو headers یه set-cookie هستش که مربوط به کاربر و هکر میتونه بهش دسترسی پیدا کنه و با همین به سشن کاربر لاگین کنه و...CORS Headersهمونطور که گفتیم بر اساس هدر هایی که از سمت بک اند درجواب ریکوئست prefight میاد مشخص میشه چه دسترسی های رو داده به origin دیگه،  ما یه سری Header میتونیم ست بکنیم سمت بک اند که درجواب درخواست prefight ارسال میشه:Base: Access-Control-Allow-Origin: &lt;origin&gt; | *  Ex: Access-Control-Allow-Origin: https://google.com, https://virgool.ioداخل این هدر مشخص میکنیم که کدوم origin ها اجازه دسترسی رو دارن، میتونیم از * استفاده کنیم که یعنی همه origin ها و این اصلا پیشنهاد نمیشه(بعضی جاها از regex هم پشتیبانی میکنن یا مینویسین که اون هم پیشنهاد نمیشه مگر اینکه مطمن باشید که چی مینویسید)، بهتر که origin های مورد نیاز رو فقط اضافه کنید..Base: Access-Control-Expose-Headers: &lt;header-name&gt;[, &lt;header-name&gt;]*   Ex: Access-Control-Expose-Headers: x,y,zاین هدر مشخص میکنه که کلاینت(مروگر) به چه هدر هایی دسترسی داشته باشه، به صورت پیشفرض وقتی از یه origin دیگه ریسپانس میاد فقط به هدر هایی مثل Cache-Control، Content-Language  و Content-Type دسترسی داره کلاینت. اگر ما بخوایم هدر هایی دیگه ای رو هم دسترسی داشته باشه مثل مورد x,y,z تعریف میکنیم..Base: Access-Control-Max-Age: &lt;delta-seconds&gt;   Ex: Access-Control-Max-Age: 30داخل این هدر میتونیم مشخص بکنیم که تا چه مدت مروگر درخواست prefight رو با هر ریکوئست نفرسته، یعنی اولین بار میفرسته و درخواست های بعدی دیگه نمیفرسته تا اون n ثانیه تموم بشه بعدش یه درخواست prefight دیگه میفرسته..Base: Access-Control-Allow-Credentials: true | false Ex: Access-Control-Allow-Credentials: trueاین هدر اجازه میده که اطلاعات اعتبار سنجی همراه با درخواست از سمت کلاینت ارسال بشه، میتونه سشن کاربر و کوکی باشه یا اطلاعات مربوط به سرتیفیکیشن ها و...Base: Access-Control-Allow-Methods:  * | post, put, get, patch, delete Ex: Access-Control-Allow-Methods: getاینجا متود هایی که اجازه دارن رو تایین میکنیم مثلا الان گفتیم درخواست get رو فقط از allow origin ها قبول کن و هر متود دیگه ای که بیاد ارور CORS Policy میگیره..Base: Access-Control-Allow-Headers: &lt;header-name&gt;[, &lt;header-name&gt;]*  Ex: Access-Control-Allow-Headers: custom_headerبالاتر یه Access-Control-Expose-Headers داشتیم اونجا یه سری هدر ست میکردیم که کلاینت دسترسی داشته باشه بهش از داخل response، ولی اینجا یه سری هدر مشخص میکنیم که کلاینت بتونه بفرسته، یعنی غیر اگر غیر از هدر های که ما گفتیم رو بفرسته کلاینت بهش ارور CORS بده ( اگر هدر کاستومی داشته باشیم باید اینجا اضافه کنیم در غیر اینصورت پیشفرض Deny میشه)‌.نکته : هدر های access-control-request-private-network و access-control-allow-private-networ قبلا برای دست رسی دادن به شبکه پرایویت وجود داشتن که  در ورژن جدید مروگر ها غیر فعال شدن، مگر اینکه خودتون فعال کنید.Django CORS &amp; DEBUGداخل جنگو میتونیم همه موارد گفته شده رو با پکیج django-cors-headers هندل بکنیم  که خیلی ساده و راحت هستش، کافیه مواردی که داخل لینک بالا گفته رو انجام بدیم تا اعمال بشه. داخل فریمورک های دیگه هم باید ماژول هایی برای این وجود داشته باشه و اگر هم وجود نداشت کافیه داخل هدر ریسپانس برای درخواست prefight اون موارد مورد نیاز رو قرار بدید تا اوکی بشه.برای دیباگ کردن ارور های مربوط به CORS اگر تب مربوط به network مروگر رو چک بکنید اونجا میتونید وضعیت درخواست رو ببینید و اگر ارور دریافت کرده باشید و faield شده باشه میتونید برید داخل تب console اونجا با جزئیات کامل تری ارور هستش، مثلا ممکنه ارور داده باشه که این origin داخل allow origin ها نیستش یا دست رسی لازم برای فلان هدر و متود ها داده نشده از سمت بک اند و... در کل برای حل ارور ها اگر هدر هایی که بالاتر توضیح دادیم رو استفاده کنید میتونید خیلی راحت دیباگ کنید.همچنین اگر زمانی اومدید با پکیج django-cors-headers هدر ها و موارد مورد نیاز تون رو ست کردید ولی همچنان مشکل داشت میتونید ریسپانس اون ریکوئست OPTION که فرستاده میشه رو برسی کنید ببینید واقعا سرور داره اون هدر ها و مواردی که ست کردید رو برمیگردونه یا نه؟ و میتونید وبسرور رو هم چک کنید (اگر مثلا از nginx یا apache و.. استفاده میکنید).خب دوستان امید وارم توضیحات کافی و خوبی رو داده باشم و دید بهتری از CORS Policy پیدا کرده باشید و اگر به ارور های مربوط بهش برخورد کردید بتونید راحت دیباگ کنید و مناسب ترین تصمیم رو بگیرید.مرسی که تا اینجا خوندید، اگر داخل پست مشکلی وجود داشت یا چیزی به اشتباه گفت شده بود و یا می تونست بهتر باشه خوشحال میشم کامنت بزارید، چاکس ❤️Links :https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#the_http_response_headershttps://portswigger.net/web-security/corshttps://owasp.org/www-community/attacks/CORS_OriginHeaderScrutinyhttps://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.htmlhttps://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy</description>
                <category>;...z@nko!#</category>
                <author>;...z@nko!#</author>
                <pubDate>Sat, 30 Dec 2023 20:17:40 +0330</pubDate>
            </item>
                    <item>
                <title>رهایی از مرزها: پیشرفت شبکه‌های اجتماعی غیرمتمرکز و برسی پروتکل ActivityPub</title>
                <link>https://virgool.io/@zankoAn/activitypub-lo20egjbacpa</link>
                <description>APپیش گفتارخیلی از شبکه های اجتماعی فدرال و اوپن سورس مثل Plume, Peertube, Mastodon PixelFed, Lemmy, Funkwhale و... دارن از پروتکل ActivityPub استفاده میکنن و برای همین این پروتکل برای من جذاب بود و یه مدت سرچ کردم راجبش و... در نهایت خواستم چیز هایی که یاد گرفتم و تجربه کردم رو اینجا به اشتراک بزارم تا برای افرادی که میخوان آشنا بشن باهش منبع خوبی باشه، البته پروتکل های دیگه ای هم غیر از AP هستن مثل: Farcaster, Nostr و... در کل همیشه یه سری مشکلات و چالش ها برای این پروتکل ها هستش که با حمایت جامعه در طی زمان بهتر و بهتر میشن(اینکه کدوم پروتکل، پلتفرم و سرور رو برای استفاده انتخاب کنیم بستگی داره به اینکه چه چیزی برامون اهمیت بیشتری داره).در ادامه یه نگاهی به پروتکل های خوبه گذشته میندازیم و بعد میریم سراغ جزئیات پروتکل اکتیویتی پاب.اصطلاح فدریشن(Federation) : در واقع نمایانگر یه شبکه هستش که داخلش سرور ها به توافق رسیدن که از یه پروتکل استاندارد(مثل ActivityPub) برای تعامل با همدیگه بدونه نیاز به سرور مرکزی استفاده کنن.به پلتفرم های مختلفی که از این پروتکل استاندارد و مشترک استفاده میکنن میگن federated (فدرال)‌ مثل Mastodon ،Pleroma، Plume و...اصطلاح فدیور(Fediverse)‌ : این از ترکیب federated و universe بوجود اومده، در واقع اشاره میکنه به گروهی از این پلتفرم های فدرال که میتونن با هم دیگه تعامل داشته باشن. مثلا ماستودون میتونه روی n تا سرور ران باشه و این سرور ها به عنوان instance در شبکه فعالیت بکنن، حالا ممکنه plume هم n تا سرور داشته باشه و هر دو چون فدرال هستن میتونن با همدیگه تعامل داشته باشن، به این شبکه بزرگ که از ترکیب این پلتفرم های فدرال شکل گرفته میگن فدیور.نکته : ممکنه بعضی جاها به جای واژه سرور از pod، node، relay و یا instance هم استفاده بشه که همشون مفهمون همون سرور رو دارن ولی داخل پلتفرم و پروتکل های مختلف ممکنه اسم های متفاوتی داشته باشه.تفاوت شبکه های اجتماعی متمرکز و غیر متمرکزDecentralized / Centralizeشبکه های اجتماعی متمرکز(Centralize):در این نوع از شبکه های اجتماعی همه کاربرا وصل میشن به یک یا چند سرور و دیتای خصوصی شون داخل سرور های اون شرکت ذخیره میشه: مثل توتیتر، یوتیوب، فیسبوک و... این دیتای خصوصی میتونه به شرکت های دیگه فروخته بشه و یا برای هدف های دیگه استفاده بشه و کاربر کنترلی روی جریان نداره، همه کاربر ها باید از قوانینی که اون شبکه اجتماعی تعیین کرده پیروی بکنن و باز هم کاری از دسته کاربر نمیاد(مثل محدودیت های توییتر که زیاد تر شد و..)، دولت میتونه به شکل ساده تری سانسور بکنه، اکانت کاربر رو ببنده، روی دیتا و فعالیت های کاربر نظارت داشته باشه و... همچنین کاربر ها برای اینکه بتونن با بقیه تعامل داشته باشن، پست هاشون رو بنویسن و یا از پست های جدید بقیه باخبر بشن و... باید از برنامه یا وب سایتی که برای اون شبکه اجتماعی هستش استفاده بکنن و نمیتونن مثلا داخل توییتر نوتیفای بگیر که فلان کاربر تو یوتیوب فیلم جدید اپلود کرد یا لایو داره یا برن کامنت بزارن براش و از این موارد، شرکت هایی اصلی میتونن هر تبلیغاتی رو که میخوان به کاربر ها نشون بدن و این هم آزار دهنده هستش.در کل سانسور، نقض حریم خصوصی، محدودیت ها، تبلیغات و... میتونه هر لحظه ای اتفاق بیفته تو این شبکه ها و کاربر رو چیزی کنترل نداره و همچنین اگر سرور های اصلی مشکلی براشون پیدا بشه کل شبکه down میشه و یا اگر سروری هک بشه اطلاعت همه کاربر ها در دسترس قرار میگیره .شبکه های اجتماعی فدرال(Decentralized) :تو این نوع از شبکه‌های اجتماعی کاربر ها میتونن به سرور های متعددی وصل بشن و محدود به سرور های یه شرکت/شخص خاص نمیشن و میتونن تصمیم بگیرن که دیتاشون روی کدوم سرور ذخیره بشه و هروقت خواستن هم میتونن اطلاعات شون رو از یک سرور به سرور دیگه انتقال بدن و یا حتی سرور خودشون رو بیارن بالا و به عنوان یه instance به شبکه اضافه بشن، هر سرور هم قوانین و موضوع خودش رو میتونه داشته باشه و افرادی که با این موافقن داخلش رجستر میکنن. برای مثال تعداد زیادی instance در mastodon وجود داره و کاربر میتونه داخل هرکدوم از این instance ها که دوست داره عضو بشه و با کاربر های اون instance تعامل داشته باشه و یا اگر خواست میتونه از قسمت تایم لاین با یوزر سرور های دیگه هم در تعامل باشه... و حتی کاربر میتونه با پلتفرم های دیگه هم در تعامل باشه(به شرطی که داخل فدیور باشه (بالاتر گفتیم)) .البته این شبکه های اجتماعی که تو مثال گفتیم هنوز میتونن به شکل کاملی غیر متمرکز نباشن، چون هر سرور یه صاحب داره و اون هستش که اطلاعات ما رو ذخیره میکنه(اگه سرور خودمون نباشه) و زمانی که بخوایم از یه سرور اطلاعات مون رو انتقال بدیم به سرور دیگه ادمین سرور فعلی میتونه این کار رو انجام نده، چون کاربر هاش دارن میرن!! و حتی ممکنه زمان انتقال، دیتا کامل انتقال داده نشه و... که این موضوع داخل پروتکل هایی مثل Nostr بهتر هستش چون کاربر به یه سری relay وصل میشه و بعد یه پست میزاره و این برای همه relay ها ارسال میشه(تو همشون ذخیره میشه) و کل یوزر هایی که وصلن به اون relay ها میتونن پیام رو ببین و...(کاربر ها با پرایویت کی خودشون و الگوریتم Schnorr امضا(sign)‌ میکنن پیام رو و بعد به relay ارسال میشه، اینجوری کسی نمیتونه محتوا رو تغیر بده چون امضا با public key ما چک میشه و اگر تغیر کرده باشه مشخص میشه).A History Lessonقبلا برای ایجاد یه شبکه اجتماعی غیر متمرکز از پروتکل های دیگه ای مثل XMPP یا OStatus یا Diasora و... استفاده میشد ولی خب هرکدوم یک سری مزایا و معایبی داشتن که میخوایم یه نگاهی بهشون بندازیم.اگر علاقه ای به این قسمت ندارید میتونید برید قسمت بعدی.#: XMPP(Extensible Messaging and Presence Protocol)این پروتکل برای ارتباط ریل تایم مثل چت های انلاین به شکل client-to-server ایجاد شد و دیتا در قالب XML ارسال و دریافت میشه. همچنین به کاربر اجازه میده وضعیت خودش رو در شبکه اعالم بکنه(Presence)، مثلا اعلام بکنه انلاین یا افلاین هستش و یا اطلاعات دیگه ای رو ارسال بکنه. این پروتکل برای شبکه های اجتماعی کوچیک و ساده و یا برای ارتباط بین دستگاه های IoT و ارسال پیام فوری خوب بود، مثلا تو IoT میشه برای اعلام وضعیت حسگر های یه دستگاه یا آلارم ها ازش استفاده کرد(Presence). بعضی جا ها هنوز استفاده میشه ولی برای یه شبکه اجتماعی که واقعا کار بکنه یه سری مشکلات داشت: برای ریل تایم بودنش میتونست از websocket استفاده بکنه به جای سوکت tcp،‌ قابلیت های یه شبکه اجتماعی مثل فالو کردن،‌ تایم لاین، ادیت کردن پروفایل، داشتن سطح های مختلف پرایوسی و... رو نداشت، نمیتونست بفهمه که کدوم کاربر برای کدوم سرور هستش و چطوری باید پیداش بکنه و...البته همه این مشکلات رو میشه با نوشتن Extension های مختلف حل کرد(XMPP پروتکل XEP رو برای نوشتن اکستنشن هاش ارئه که با فرمت استانداردش باعث اینجاد همکاری بین پیاده سازی های مختلف و کلاینت های مختلف میشه) ولی خب در مقایسه با پروتکل های جدید تر که به صورت پیشفرض خودشون موراد مورد نیاز یه شبکه اجتماعی رو هندل کردن کم کم این پروتکل کم رنگ تر شد و... همچنین تو سطح بالا تر منیج کردن چندین میلیون یوزر با این پروتکل سخت بود.#: OStatusاین پروتکل بوجود اومد تا شبکه های اجتماعی غیر متمرکز ایجاد بشن و بتونن با هم دیگه در قالب استاندارد تری تعامل و همکاری داشته باشن( برای ایجاد شبکه هایی مثل توییتر و..). از این پروتکل در پلتفرم هایی مثل Mastodon, GNU Social, Pleroma استفاده میشد که البته الان از بین این موارد فقط در GNU Social استفاده میشه، این پروتکل خودش از چندین پروتکل دیگه مثل :‌ ActivityStream 1.0, Salmon, Atom, WebSub, Webfinger, Portable Contacts استفاده میکنه تا بتونه سازگار تر باشه با سایر سرویس های وب و بتونه یه حالت استاندارد تری رو داشته باشه.این پروتکل به ما اجازه میده که بتونیم یک سری تغیرات رو ایجاد بکنیم و مورادی که نیاز داریم رو اضافه بکنیم تا در کل دستمون باز تر باشه، بعضی جاها نیاز بود که اون instance یه سری ویژگی ها رو خودش اضافه بکنه مثلا:فلیتر کردن محتوا : هر instance باید بتونه قوانین خودش رو داشته باشه مثلا بتونه بگه که اگر کلمات توهین آمیز وجود داشت فیلتر بشن و در کل بر روی محتوا بتونه عملیات فیلتر کردن رو انجام بده.پرایوسی دقیق تر :‌ مثلا پست من فقط برای یه گروه یا افراد خاص ارسال بشه یا فقط افرادی که معیار های گفته شده من رو دارن بتونن پست و... رو ببینن.ردیابی دقیق تر فعالیت ها و علایق کاربر:‌ این موارد بیشتر برای سیستم های توصیه گر استفاده میشن که این پروتکل ویژگیی رو برای پیاده سازی این قابلیت ارائه نمیده.ناهماهنگی بین instance ها :‌ چند مورد بالا و بقیه قابلیت هایی که وجود ندارن رو باید ایجاد کرد و خب ممکنه یه instance یه قابلیتی رو ایجاد بکنه ولی بقیه instance ها از این عمل خبر نداشته باشن و باعث تداخل میشه بین instance ها، مثل زمانی که mastodon یه فیلد برای پرایویت کردن پست اضافه کرد ولی اینستنس های دیگه از این فیلد خبر نداشتن و خب اونجا پست پرایویت نبود و پابلیک می شد...#: Diasporaاین پروتکل و وب اپلیکیشنش که همین اسم رو داره با این هدف ایجاد شد که بتونه پراویسی و مدیریت دیتای خوبی رو به کاربر هاش بده، کاربر ها میتونن پروایسی رو تا سطح های خیلی خوبی تعیین بکنن، مثلا چه افراد یا گروه هایی بتونن یه پست رو بیینن و یا چه قسمت هایی از پروفایل رو بتونن همه ببینن و... همچنین به کاربر اجازه میده که کل دیتاش که داخل pod(سرور) هستش رو export بکنه تا خیلی راحت بتونه بره داخل یه pod دیگه عضو بشه و کوچ بکنه، همچنین کاربر ها میتونن شخص دیگه ای رو بلاک بکنن یا پست های یه کاربر دیگه رو ignore بکنن تا براشون نمایش داده نشه. برخلاف OStatus که از پروتکل های مختلف استفاده میکرد اینجا Diaspora(دیاسپورا)‌ پروتکل خودش رو داره و خیلی از چیز ها داخل core خودش هندل شده.ActivityPub (AP)اکتیویتی پاب یه پروتکل هستش که یه سری قوانین و قرارداد ها رو تعیین میکنه تا همه بتونن به شکل استانداردی با همدیگه صحبت بکنن، AP بعداً توسط w3c تایید شد و به یه پروتکل استاندارد و قوی برای شبکه های اجتماعی فدرال تبدیل شد. داخل AP دیپندنسی ها نسب به OStatus و... خیلی کمتر شد‌ و دیگه نیازی به پروتکل هایی مثل Salmon, WebSub, Atom و... نیست چون اکتیویتی پاب به شکل built-in کاری که این پروتکل ها انجام میدادن رو انجام میده و با داکیومنت خوبی هم که ارئه میده کار رو برای دولوپر ها خیلی راحت تر کرد(نسبت به قبل).اکتیویتی پاب رو میشه به دو شکل Client To Server و Server To Server استفاده کرد که بیشتر همون حالت سرور به سرور هستش و یوزر ها به api اون وب اپلیکیشن وصل میشن و تعامل دارن.نکته: ممکنه وقتی راجب این پروتکل سرچ میکنیم به inbox و outbox برخورد کرده باشیم، inbox میشه endpoint که ما داخل backend با همین اسم مینویسم و از این به بعد بقیه سرور ها درخواست های POST شون رو به اینجا میفرستن مثلا : ایجاد یک پیام - فالو کردن - لایک و... outbox هم مثل قبلی هستش ولی برای درخواست های GET یعنی سرور های دیگه درخواست میدن مثلا برای دریافت پست های فلان یوزر یا تعداد لایک های فلان یوزر و...برای کار کردن با پروتکل AP و ساختن وب اپلیکیشن خودمون باید این 4 تا پروتکل پایین رو درک کنیم:ActivityStreams 2.0Activity VocabularyJson-LDWebFingerActivityStreams 2.0:اکتیویتی استریم از Activity Vocabulary و JSON-LD تشکیل شده و هدف اصلیش سریالایز کردن دیتا هستش(در ادامه وقتی این دو مورد رو توضیح دادیم این هم قابل لمس تر میشه). اکتیویتی استریم تو ورژن 1 از فرمت xml برای سریالایز کردن دیتا استفاده میکرد و همچنین تایپ و پراپرتی های کمتری رو هم پشتیبانی میکرد. تو ورژن 2 توسط w3c تأیید و به یه پروتکل استاندارد تبدیل شد، تو این ورژن تغیر های زیادی بوجود اومد، مثلا استفاده از Json-LD برای سریالایز کردن دیتا و یا اضافه شدن تایپ و پراپرتی های بیشتر برای پوشش دادن متا دیتا های مربوط به یه اکشن(همین Vocabulary).Activity Vocabulary:این پروتکل یه سری Type و Property رو برای Activity Stream تعریف میکنه، در حالت واقعی ما میایم با استفاده از این تایپ و پراپرتی ها متا دیتای مربوط به یه activity رو تعریف میکنیم و بعد در قالب Json-LD برای یه instance دیگه ارسالش میکنیم، فعلا باید یه درک اولیه از تایپ ها داشته باشیم و بدونیم به چه شکل هستن در ادامه قابل لمس تر میشه قضیه... ‌:(خود Type ها به دو دسته بندی کلی تقسیم میشن :Core TypesExtended Typesمورد اول خودش شامل یه سری تایپ بیسیک میشه مثل:‌Object, Link, Activity، IntransitiveActivity, Collection, CollectionPage, OrderCollection, OrderCollectionPageدر کل 8 تایپ بیسیک داریم و همه این ها به عنوان تایپ های بیس برای Extended ها عمل میکنن، هرکدوم از این تایپ ها یه سری پراپرتی دارن، مثلا تو extended type ها Follow رو داریم که خود این از Activity ارث بری میکنه و خود Activity از Object، یعنی میتونیم از پراپرتی های اکتیوتی و ابجکت استفاده کنیم موقع استفاده از Follow(در حالت واقعی وقتی کسی رو فالو میکنیم میتونید این پراپرتی ها رو ست بکنیم داخل درخواست) .Extended Typesاین دسته شامل 3 نوع تایپ مختلف میشه :تایپ Actor : این تایپ میتونه نمایانگر کاربر(ربات) - گروه - اپلیکیشن - سرویس - شرکت و یا سازمان باشه، این بیسش همون تایپ Object داخل Core Type هستش.تایپ Activity :‌ اینجا میتونیم چندین نوع اکتیویتی داشته باشیم مثل لایک - فالو - کامنت - انفالو - ساختن پست - ریپلی و.... همه این موارد شامل این دسته بندی میشن و بیس این هم میشه همون Activity داخل Core Type.تایپ Object یا تایپ لینک : خود Object میتونه شامل: Note, Document, Video, Voice و ... باشه یعنی این تایپ ها رو شامل میشه‌(‌Note درواقع برای تکست های کوتاه هستش مثل تویت)‌ و Link type هم برای منشن هستش مثلا زمانی که کسی رو داخل یه پست منشن میکنیم ، اینجا همونطور که از اسمش پیداست داخل Core Type بیسش همون Object.Properties:علاوه بر تایپ ها یه سری property خیلی خوب داریم که تعدادشون هم زیاده، زمانی که ما یه Activity رو ایجاد میکنیم میتونیم از این پراپرتی ها داخلش استفاده بکنیم تا متا دیتای اون activity مون کامل بشه، اینجا 3 تا پراپرتی جالب رو مثال میزنیم:پراپرتی to, cc, bcc, bto :‌ این پراپرتی ها برای هدف گذاری کاربر ها استفاده میشن، هر اکتیویتی(فالو، منشن، لایک و..)میتونه هم یوزر درجه اول داشته باشه هم درجه دوم، مثلا کاربر a یه پیام میفرسته به b، اینجا این دو نفر مستقیم داخل اون activity شرکت کردن و برای همین میشن Primary audience و یوزر x که b رو دنبال میکنه میشه Secondary audience که حالا زمان ارسال این اکتیوتی میتونیم یوزر b رو داخل این فیلد cc مشخص کنیم). جزئیات بیشتر...پراپرتی icon: میتونیم از این پراپرتی برای تعریف کردن یه عکس کوچیک استفاده کنیم مثل عکس پروفایل.پراپرتی next, prev:‌ برای pagination(صفحه بندی) استفاده میشه مثلا از تایپ Collection استفاده کردیم و یه لیست از پست ها رو نشون دادیم(لیست میشه همون پراپرتی items ) و حالا میتونیم از این prev, next برای دیدن پست های قبلی و بعدی استفاده کنیم .Json-LD(Link Data)جیسان لینک دیتا مثل همون JSON هستش با این تفاوت که داخلش میتونیم دیتا ها رو لینک بکنیم مثلا داخل یه صفحه html ما میتونیم یه لینک بسازیم و وقتی کاربری روی اون کلیک کرد میره به صفحه مربوطه،‌ داخل json-LD هم ما میتونیم برای کلید هامون یه ولیو تعیین بکنیم و این ولیو میتونه لینک باشه همچنین به ما قابلیت های دیگه ای رو هم میده.خود Json-LD یه سری keywords داره که برای تعریف بعضی قسمت ها ازش استفاده میشه مثلا برای تعیین کردن type@ یا id@ یا context@ و...(همشون با @ شروع میشن)، بعضی از این keywords ها داخل پراپرتی های Activity Vocabulary وجود دارن و از اون ها استفاده میکنیم(بعضی از کی ها هم وجود ندارن چون ربطی به هدف شبکه اجتماعی ندرن) این مورادی که وجود دارن همه map شدن یعنی نیازی به اون @ اولشون نیست.ما از این پراپرتی ها خیلی جاها استفاده میکنیم مثلا برای هر ابجکت تایپی که داخل Vocabulary داشتیم یه context هم باید ست بکنیم زمان سریالایز کردن.این context، تایپ و پراپرتی هایی که در ادامه مینویسم رو مشخص میکنه یعنی اگر سرور یا فرد دیگه ای بیاد این json ما رو ببینه از روی این context میتونه بفهمه که این keywords هامون چه معنی میدن و value شون قرار چه چیزی باشه، درواقع schema دیتای ما رو مشخص میکنه مثلا:{
    &amp;quot@context&amp;quot: &amp;quothttps://www.w3.org/ns/activitystreams&amp;quot,
    &amp;quottype&amp;quot: &amp;quotLike&amp;quot,
    &amp;quotid&amp;quot: &amp;quothttp://example.com/activity/1&amp;quot,
    &amp;quotactor&amp;quot: &amp;quothttp://example.com/users/harold_finch&amp;quot,
    &amp;quotobject&amp;quot: &amp;quothttp://example.com/notes/1&amp;quot,
    &amp;quotpublished&amp;quot: &amp;quot2023-08-10T17:30:06Z&amp;quot
}اینجا ما یه activity با تایپ Like تعریف کردیم که مشخص میکنه یوزر harold اومده پست 1 رو لایک کرده(اینجا پست و یوزر داخل یه سرور هستن) .چند تا نکته وجود داره،‌ اولین قسمت برای این activity اومدیم تعیین کردیم که contextش چیه و رفرنس دادیم به داکیومنتAcitvity Stream تا کاربر یا سرور مقصد متوجه بشه.مورد بعدی اومدیم id رو ست کردیم، این هم یه keyword(پراپرتی) دیگه هستش که داخل json-ld تعریف شده و میاد شناسه یکتا برای این activity رو مشخص میکنه، اینجا مقدارش میشه url خود instance + یه عدد رندم که داخل دیتابیس ذخیره میشه و بعد ارسال(تایپ این فیلد میتونید URN یا URL باشه).WebFingerاین پروتکل جالبی هستش که قبل تر هم استفاده میشد، هدف این پروتکل این هستش که بتونیم باهاش اطلاعات یه URI رو بدست بیاریم که URI میتونه URL باشه یا URN که در اکثر حالت ها ما با URL سرو کار داریم.داخل شبکه های مثل Mastodon, GnuSocial, Diaspora و.. از این پروتکل استفاده میشه تا اطلاعات یوزر رو به دست بیاریم، داخل این شبکه های اجتماعی چون غیرمتمرکز هستن ممکنه مثلا داخل سرور x یه یوزنیم وجود داشته باشه و داخل سرور y هم همین یوزرنیم وجود داشته باشه‌، درواقعی چون سرور ها جدا هستن ممکنه این موارد تکراری پیش بیاد برای همین میان از domain مربوط به اون instance استفاده میکنن داخل username کاربر یعنی یوزنیم کاربر میشه:@username@domainبیاید یه مثلا عملی تر بزنیم که بهتر درک بشه، مثلا داخل ماستودون شما در سرور mastodon.social اکانت ساختید و الان میخواید یوزر harold_finch که داخل سرور pinkorange.red هست رو فالو بکنید یا پست هاش رو لایک بکنید یا منشن کنید و... اینجا قبل از اینکه درخواست فالو فرستاده بشه میاد یه درخواست میده به endpoint مربوط به webfinger تا اطلاعات یوزر harold_finch رو به دست بیار از اون سرور دوم.همونطور که گفتیم یوزنیم کاربر از دامین و یوزنیم ایجاد شده و همه وب اپلیکیشن ها در سمت بک اند یه endpoint ایجاد میکنن برای webfinger :‌https://domain/.well-known/webfingerو اینجا وقتی یه instance نیاز داره اطلاعات یه یوزر رو بگیره و یوز داخل سرور خودش نیست میاد این endpoint درخواست میده:https://pinkorange.red/.well-known/webfinger?resource=acct:harold_finch@pinkorange.redو داخل خروجی این هم یه سری دیتا برگشت داده میشه که اینجا یه نمونه هستش و داخل سیستم خودتون هم میتونید همین درخواست رو بزنید و ببینید.نکته : instance ها همیشه دیتا رو cache میکن و مثلا اگر اطلاعات یوزر داخل دیتابیس مربوط به کشش وجود داشته باشه میاد از همون استفاده میکنه...In Summary...تا الان یه سری اصطلاح یاد گرفتیم و راجب اینکه شبکه های متمرکز و غیر متمرکز چی هستن و چه تفاوت هایی به هم دارن تا حدودی صحبت کردیم و بعد رفتیم سراغ پروتکل های محبوبی که قبلا برای شبکه های اجتماعی استفاده میشد و بعد رفتیم سراغ ActivityPub و یه دید کلی راجبشون پیدا کردیم، پروتکل های جالب دیگه ای هم هستن که بعد از AP بوجود اومدن و دارن رشد میکنن و همیشه یه سری مشکلات رو حل میکنن و یه سری مشکلات جدید رو بوجود میارن و یه سری از ادم ها هم دنبالشون میکنن و میره جلو... ولی فعلا AP محبوب تر بوده و داخل پلتفرم های مختلفی مورد استفاده قرار گرفته و جامعه بیشتری دارن ازش استفاده میکنن(ن ب شکل مستقیم) و فعلا اوکیه..الان انتظار میره که یه درک کلی نسبت به موارد گفته شده داشته باشیم و کانسپت کلی ماجرا تو ذهن مون شکل گرفته باشه، بعد از این میشه رفت سراغ داکیومنت AP و مطالعش کرد تا مورادی که اینجا گفته نشده رو خوند، مثل جزئیات نحوه ارتباط سرور ها با هم، sharedInbox، Security، احراز هویت و... تا بعدش بتونیم وبسایت خودمون رو بیاریم بالا و یا تو پروژه های اوپن سورس مشارکت کنیم و یا حتی اصلا برای کنجنکاوی یه سری موراد رو تست بکنیم و...داخل این مقاله جا نمیشد که مثال های واقعی بزنیم و داخل کد مرحله به مرحله بریم جلوو به instance های دیگه درخواست بدیم و تعامل داشته باشیم و... برای همین شاید داخل یه مقاله دیگه با پایتون و فریم ورک های سمت بک اندش یه چیزایی نوشتیم...! (البته یه سری لینک مفید و خوب اخر صفحه گذاشتم که این موراد رو پوشش میده)میتونید از لینک زیر هم استفاده کنید، یه حساب کاربری ماستودون برای 1 روز بهتون میده و درواقع یه instance ماستودون هستش مثل بقیه فقط یه قابلیت های بیشتری داره مثلا وقتی کسی رو فالو میکنید میتونید درخواست هایی که از سمت این سرور ارسال میشه و ریسپانس ها رو ببینید یا خودتون درخواست بزنید به یه url خاص و ریسپانسی که یه سرور دیگه بهتون میده رو ببینید و... در کل کار کردن باهش خوبه و درک خیلی بهتری پیدا میکنید از پروتکل Activitypub و...https://activitypub.academy/auth/sign_upمرسی که تا اینجا خوندید و همراهی کردید، امید وارم که مفید بوده باشه و چیز جدید بهتون اضافه شده باشه و... اگر داخل پست مشکلی وجود داشت یا چیزی به اشتباه گفت شده بود و یا می تونست بهتر باشه خوشحال میشم کامنت بزارید، چاکس ❤️Links :Sebastian Jambor: Part-1 - Part-2 - Part-3 new..Tiny-Subversions: https://tinysubversions.com/notes/reading-activitypub/Pleroma: https://blog.soykaf.com/post/pleroma-encyclical-activity-pub/Dennis Schubert | Diaspora: Part-1 - Part-2Libre Lounge(podcast): Part-1 - Part-2 - Part-3Christine Lemmer: https://gitlab.com/spritely/ocappub/blob/master/README.orghttps://flak.tedunangst.com/post/what-happens-when-you-honkhttps://flak.tedunangst.com/post/the-activity-person-examinedhttps://flak.tedunangst.com/post/activity-noteshttps://flak.tedunangst.com/post/AP-networkinghttps://www.hughrundle.net/how-to-implement-remote-following-for-your-activitypub-project/</description>
                <category>;...z@nko!#</category>
                <author>;...z@nko!#</author>
                <pubDate>Tue, 15 Aug 2023 15:42:04 +0330</pubDate>
            </item>
                    <item>
                <title>پروسه Validation و Deserialization در DRF</title>
                <link>https://virgool.io/@zankoAn/drf-validation-qtowd2okibsf</link>
                <description>responseامروز داشتم یه endpoint مینوشتم و قرار بود مثلا یه رکورد x ایجاد بشه که فیلد productش فارنکی بود، وقتی برای سریالایزر از ModelSerializer استفاده کرده باشیم و تو مدل یه فیلد فارنکی هم داشته باشیم DRF براش یه فیلد دیفالت رو در نظر میگیره و اگر زمان POST کردن دیتا ایدی رو اشتباه بدیم، این ارور بالا رو تو response برمیگردونه. اینجا یه مشکلی برام پیش اومد چون نمیتونستم با فیلد ولیدیتور یا get-object تو ویو و... بیام فرمت error رو بهتر بکنم و اون چیزی که میخوام رو تو response برگردونم برای همین یکم سرچ کردم و کد هاش رو دیدم و... در نهایت خواستم تجربم رو اینجا به اشتراک بزارم.# ModelSerializerداخل DRF میتونیم دیتا رو Serialize یا Deserialize بکنیم که این پروسه اتوماتیک هستش و وقتی دیکشنری میدیم به serializer میفهمه و deserialize میکنه و وقتی ابجکت پایتونی میدیم بهش میاد سریالایزش میکنه، مثلا وقتی ریکوئست POST رو ارسال میکنیم میاد deserialize میکنه:serializer(ممکنه از جنریک ویو ،ویو ست و... استفاده کنیم که و این قسمت رو نبینیم.)اینجا اگر MySerializer از ModelSerizlier و یا HyperlinkedModelSerializer ارث بری کرده باشه یه سری ویژگی رو دریافت میکنه، که اینجا ما با ویژگی فیلد های ریلیشنال کار داریم که باعث میشد اون ارور تو  Response برای من نمایش داده باشه و با مواردی که گفتم نتونم هندلش بکنم.وقتی از ModelSerializer استفاده میکنیم اگر داخل مدل مون یه فیلد فارنکی داشته باشیم، اینجا داخل مدل سریلایزر به صورت دیفالت میاد از فیلد PrimaryKeyRelatedField استفاده میکنه که برای OnToOne یا ForeignKey ریلیشن استفاده میشه و این خودش یه class هستش که شامل یه سری متود میشه، متودی که ما باهاش کار داریم to_internal_value هستش اما قبل از اینکه بریم راجب این حرف بزنیم باید یه مورد دیگه رو هم بگیم.# Method: is_valid - Processزمانی که کاربر ریکوئست POST رو ارسال میکنه، دیتاش به شکل دیکشنری(json) هستش و باید این دیکشنری تبدیل بشه به ابجکت پایتونی و اینجا ما درواقع با صدا زدن متود is_valid اون اینستنسی که بالاتر ساختیم این پروسه رو انجام میدیم، وقتی این متود صدا زده میشه درواقع flow زیر شکل میگیره:validation and deserialization processاینجا اولین بار اون مواردی که داخل متود to_internal_value هست چک میشه (البته اولین متود نیست در ادامه میگیم).بعد از این میاد validators ها رو چک میکنه: این ولیدیتور ها رو زمان  ایجاد فیلد تو کانستراکتور میدیم بهش، همون پارامتر validators  که میتونه مثلا MaxLengthValidator ،UniqueValidator ProhibitNullCharactersValidator و... باشه)فیلدولیدیتور ها هم شامل متود هایی میشن که داخل سریالایزر تعریف میکنیم مثل validate_age, validate_email و...ابجکت ولیدیشن یا cross-validation هم شامل مواردی میشه که ما نیاز داریم چند مورد رو با هم ولیدیت بکنیم مثلا بگیم اگر کاربر پرمیوم بود و پروداکت  x  از کتگوری y رو میخواست بیا براش یه تخفیف بده...(این مورد 3-4 شبیه clean وclean_field داخل form ها هستن).# Method: is_valid - Process Detailsبالاتر یه توضیح کلی دادیم و اما بریم داخل جزئیات :‌در مرحله اول داخل is_valid با متود validate_empty_values چک میشه و اگر فیلد های که داریم مقدارشون خالی باشه(استرینگ &quot;&quot; یا Null یا...) و همچنین required نباشن میگه برای این فیلد نیازی به ولیدیشن نیست.اما اگر validate_empty_values ما False باشه یعنی فیلد empty نداشته باشیم میاد متود to_internal_value ابجکت فعلی رو ران میکنه، اینجا ابجکت فعلی میشه همون فیلد هامون که تو پروسه Deserialization ایجاد شده،  یعنی مثلا PrimaryKeyRelatedField یا CharField و هر چیزی که داخلی مدل سریالیزر تعریف کردیم.نکته: این فیلد هایی که داخل سریلایزر تعریف میکنیم همشون متود to_internal_value رو دیفالت دارن چون از کلس Field ارث بری میکنن.اگر داخل سریلایزر مون یه فیلد فارنکی داشته باشیم،  همونطور که بالاتر گفتم میشه PrimaryKeyRelatedField و اینجا زمانی که متود to_internal_value صدا زده میشه این فیلد یه عمکلرد متفاوتی رو داره و میاد این کوئری رو میزنه:queryاین data میشه همون ایدی فیلد فارنکی که تو ریکوئست POST میفرستیم و خود فیلد هم در زمان Deserialization یه کوئری ست تایین میشه براش(دیفالت yyy.objects.all()i) و الان اینجا وقتی get میکنه اگر ایدی وجود نداشت باشه میاد تو excpetion و اون ارور رو با فرمت عکس اول  برمیگردونه!.# Overwrite to_internal_valueمیتونیم بیایم داخل متود post یا initial یا handle_exception این رو هندل بکنیم ولی من متود to_internal_value رو overwrite کردم چون نمی یه سری سریالایزر داشتم که از سریالایز فعلی ارث بری کرده بودن و به نظرم اینجا بهتر بود براش(اگه نظر شما چیز دیگه ای کامنت بزارید ). البته متود post میتونه بهتر باشه چون در این مثال overhead کمتری داره و نیازی به deserialize کردن نیست و همون اول میتونیم کوئری بزنیم و چک کنیم این مورد رو.to_internal_value method
اگر به نظرتون به شکل دیگه ای میشد بهتر نوشت یا هر چیز دیگه ای میتونید کامنت بزارید، مرسی که وقت گذاشتید❤️!</description>
                <category>;...z@nko!#</category>
                <author>;...z@nko!#</author>
                <pubDate>Sun, 30 Apr 2023 15:19:25 +0330</pubDate>
            </item>
                    <item>
                <title>نوشتن یه ربات تلگرام با Pyromod در Pyrogram</title>
                <link>https://virgool.io/@zankoAn/pyrogram-plus-pyromod-fctenppctqcx</link>
                <description>Pyromod + pyrogramخب سلام دوستان امید وارم حال دلتون خوب باشه یا اگه نیست بهتر بشه +)وقتی میخواید شروع کنید به کار کردن با ربات های تلگرامی با پایروگرام یکم  اذیت میشید که چطوری دیتا رو از کاربر بگیرید و چطوری جوابش رو بدید، در واقع  step گذاری کنیدو... امروز میخوایم  از  Pyromod برای هندل کردن ای مورد استفاده کنیم، در کل چیز زیادی نداره Pyromod و یه سری مانکی پچ هستش و زیاد هم سخت نیست، بریم جلو یادش بگیریم :)نکته: وقتی دارید از Pyromod استفاده میکنید باید از نسخه async پایروگرام استفاده کنید(هرچند ورژن 2 async هستش)نکته: در این آموزش موارد بیسیک و پایه ای رو توضیح نمیدم مثلا فیلتر چیه، هندلر چیه و... این موارد داخل آموزش های قبلی به صورت کامل توضیح داده شده!نکته :‌ تو این آموزش چند تا از متود های خوب لایبرری pyromod  رو نگاه میکنیم و... ولی همش رو نمیگیم برای هیمن میتونید سورس کدش رو ببینید و خیلی درک بهتری پیدا بکنید ازش ... https://github.com/usernein/pyromod/tree/master/pyromod خب اولین کار نصب لایبرری ها هستش:pip install pyromod
pip install pyrogram بعد از اینکه نصب شدن یه فایل باز میکنیم و کدمون رو داخلش مینویسیم، چون قرار نیست ربات پیچیده ای باشه و پلاگین و... داشته باشه داخل یه فایل مینویسیم...Step1-initializefrom pyrogram import Client, filters, enums
from pyromod.helpers import ikb, kb, array_chunk
from pyromod import listen

api_id = your_api_id
api_hash = &amp;quotyour_api_hash&amp;quot

bot = Client(
    name=&amp;quotmy_bot&amp;quot,
    api_id=api_id,
    api_hash=api_hash,
    bot_token=&amp;quotyour_token&amp;quot, 
    proxy=dict(scheme=&amp;quotsocks5&amp;quot, hostname=&amp;quotyour_ip&amp;quot, port=your_port))اول اومدیم مواردی که نیاز داشتیم رو import کردیم، بعد  یه اینستنس از کلاس کلاینت ایجاد کردیم به اسم bot.اینجا از pyromod اون listen رو هم ایمپورت کردیم که مانکی پچ اعمال بشه و یه سری متود رو به ما بده مثل ask و clear_listener, cancel_listener و... در غیر اینصورت به ما ارور میده چون مانکی پچ pyromod اعمال نشده، پس این رو یادتون نره که import کنید.Step2-First Handlerbase_msg = &amp;quotلطفا یکی از دکمه های زیر را انتخاب نمایید ??&amp;quot
ask_phone_msg = &amp;quot? شماره تلفن خورد را ارسال نمایید&amp;quot
timeout_err_msg = &amp;quot❌ کاربر گرامی، زمان پاسخگویی شما به اتمام رسیده است&amp;quot
keys = [[&amp;quot? راهنمایی&amp;quot, &amp;quot? افزودن اکانت&amp;quot]

keyboard = kb(keys, resize_keyboard=True)

@bot.on_message(filters.private &amp; filters.command(&amp;quotstart&amp;quot))
async def start_bot(client, message):
    chat_id = message.chat.id
    await client.send_chat_action(chat_id=chat_id, action=enums.ChatAction.TYPING)
    await message.reply(text=base_msg, reply_markup=keyboard)خب در کد بالا اومدیم یه سری پیام که قرار به کاربر نشون بدیم رو اول کدمون قرار دادیم و داخل متغیر های مربوطه ریختیم(میتونید یه فایل json بسازید داخل اون پیام های ربات رو بزارید به نظرم اینجوری تمیز تره)، اینجا یه متغیر به اسم keyboard ایجاد کریدم که مقدارش دوتا دکمه افزودن اکانت و راهنمایی هستش، بعد یه هندلر نوشتیم و داخلش اومدیم یه send_action فرستادیم + یه پیام که به کاربر بگه یکی از دکمه ها رو انتخاب کن. داخل ربات api ما دو نوع دکمه داریم یکیش ReplayKeyboardMarkup  هستش و اون یکی InlineKeyboardButton، اولی دکمه عادی و دومی دکمه شیشه ای هستش،  لایبرری pyromod به ما این قابلیت رو میده که یکم ساده تر دکمه هامون رو بسازیم، برای دکمه های عادی از  kb و برای دکمه های شیشه ای از ikb استفاده میکنیم که بالا تر ایمپورتشون کردیم.در pyromod برای اینکه کیبورد های عادی بسازیم کافیه  یه لیست بدیم به متود kb دقیقا مثل همونی که بالاتر نوشتیم، حالا داخل این لیست ما میتونیم  شکل نمایش دکمه هامون رو مشخص کنیم مثلا دکمه ها در یک row قرار بگیرن یا در n تا row جدا قرار بگیرن و اینکه چند دکمه در هر row قرار بگیره(column)، مثلا تو چیزی که بالا نوشتیم بهش گفتیم دکمه ها داخل 2 تا row جدا قرار نمایش داده بشه(هر لیست تو در تو به عنوان یک row در نظر گرفته میشه و item های هر لیست هم به عنوان بگیم column های اون row نمایش داده میشن).الان دکمه های که نوشتیم  اینشکلی هستن:reply keyboard markupحالا اگه بخوایم این دوتا دکمه داخل یه row قرار بگیرن میایم اینشکلی مینویسیم:keyboard = kb([ 
      [&amp;quot? راهنمایی&amp;quot , &amp;quot? افزودن اکانت&amp;quot]],
      resize_keyboard=True)reply keyboard markupStep3-Second Handlerاینجا یه موردی هستش که باید بگم، قبلا step رو دستی مینوشتیم و میرفتیم جلو و هندلر های مختلفی مینوشتیم و داخل هرکدوم میومدیم مثلا فیلتر های تسکت میزاشتیم و با gorup جدا میکردیم،  ولی اینجا دیگه نیازی به این کار نیست میتونیم داخل همین فانکشن بریم جلو و کدمون رو ادامه بدیم...@bot.on_message(filters.private &amp; filters.command(prefixes=&amp;quot&amp;quot, commands=keys[1]))
async def get_account(client, message):
    chat_id = message.chat.id
    try:
        phone_number = await client.ask(
            chat_id=chat_id, 
            text=ask_phone_msg,
            reply_markup=keyboard,
            timeout=10)
        print(phone_number.text)
    except listen.ListenerTimeout:
        await message.reply(text=timeout_err_msg, reply_markup=keyboard)
bot.run()خب تو کد بالا اومدیم یه هندلر دیگه اضافه کردیم، مثلا اگه الان قرار ربات دریافت اکانت بنویسیم اینجا میتوینم داخل همین فانکشن کل عملیات رو خیلی راحت بنویسیم(قبلا هم میتونستیم با شرط گذاشتن و... پیش ببریم قضیه رو  ولی الان با pyarmod خیلی راحت تر هستش) البته برای اینکه کدمون تمیز تر باشه میتونیم برای هر دکمه که داخل رباتمون هست یه هندلر  جدا بنویسیم.الان ما میخوایم به کاربر بگیم که شمارش رو بفرسته و بعد چیزی که میفرسته رو دریفات کنیم و مثلا اگه تو 30 ثانیه هر چند دقیقه که ما میگیم نفرستاده بگه وقتش تموم شده.در کد بالا از متود ask  لایبرری pyromod استفاده کردیم این یکی از اون مانکی پچ هایی هستش که pyromod اضافه کرده، اینجا دقیقا مثل متود send_message میتونیم پارامتر هایی که میخوایم رو بهش بدیدم همچنین میتونیم دوتا پارامتر اضافه filter و  timeout رو هم ست بکنیم براش(اپشنال هستش اجباری نیست) این timeout تعیین میکنه که چقدر متود ask منتظر ورودی کاربر باشه،  مهم ترین نکته این هستش که وقتی پیام فرستاده میشه ما  چیزی که کاربر در جوابش میفرسته رو میتونیم داخل phone_number ذخیره کنیم بعد از اینکه کاربر یه چیزی بفرسته این عمل ask خود به خود کنسل میشه و دیگه هرچیزی که کاربر بفرسته برای این ask ذخیره نمیشه.اینجا داخل اکسپشن هم هندل کردیم که اگر تو تایم تایین شده جواب نداد به کاربر بگه دوباره دکمه رو بزنه(این اکسپشن برای ورژن جدید pyromod هستش و تو ورژن های قبل تر باید از اکسپشن asyncio.exceptions.TimeoutError استفاده کنیم).Step3-4-Method array_chunk/Paginationیه مورد هستش که اینجا خواستم اضافه بکنم اون هم متود array_chunk هستش که قبلا ایمپورتش کرده بودیم، اگه تعداد دکمه هامون زیاد باشه میتونیم از این متود برای ساختن راحت تره این column هامون استفاده بکنیم، با این متود میتونیم بگیم column هامون چند تا چندتا باشه مثلا :k=[(&amp;quotTest 1&amp;quot, &amp;quottest_1&amp;quot), (&amp;quotTest 2&amp;quot, &amp;quottest_2&amp;quot), (&amp;quotTest 3&amp;quot, &amp;quottest_3&amp;quot), (&amp;quotTest 4&amp;quot, &amp;quottest_4&amp;quot)]])الان ما همچین چیزی داریم اگه بیایم از این متود استفاده کنیم میتوینم بگیم بهش برامون هر row که میشه بساز (یعنی تعداد row داینامیک میشه) ولی داخل هر کدوم فقط n تا کالمنی که ما میگیم رو  قرار بده:b= array_chunk(k, 2)
keyboard = ikb(b)الان برای ما دوتا row میسازه و داخل هرکدوم 2 تا column قرار میده که خیلی ساده تر میکنه کار ما رو،  برای کیبورد عادی هم میتونید استفاده کنید.همچنین یه متود Pagination هم داره این لایبرری pyromod که میتونید برای ساختن پیجینیشن دکمه ها ازش استفاده کنیم، برای زمانی خوبه که تعداد دکمه ها زیاد باشه و نخوایم در یک پیام نشونشون بدیم.Step4-KeyboardButtonبرای نوشتن دکمه های شیشه دو مورد هستش که اول باید توضیح بدم. مورد اول : در دکمه های شیشه ای ما باید 2 مورد رو حتما ست بکنیم یکش text هستش همون متنی که روی دکمه نمایش داده میشه و دومین مورد هم callback_data یا url هستش(یکی از این دو مورد اخر حتما باید ست بشه).مورد دوم : وقتی روی دکمه عادی کلیک میکنید یه تکست میفرسته داخل چت و در کل ما از اپدیت عادی؛ درواقع تو هندلر message میتوینم اون رو دریافت کنیم ولی برای دکمه های شیشه ای فرق میکنه و وقی کلیک میشه رو دکمه یه دیتایی رو برمیگیردونه دقیقا همون callback_data که ست میکنیم، و ما برای دریافت اون و تشخیص اینکه رو کدوم دکمه کلیک شده باید بیایم از هندلر on_callback_query استفاده بکینم.@bot.on_message(filters.private &amp; filters.command(&amp;quotstart&amp;quot))
async def start_bot(client, message):
    keyboard = ikb([[
            (&amp;quot? راهنمایی&amp;quot, &amp;quothelp&amp;quot),
            (&amp;quot? افزودن اکانت&amp;quot, &amp;quotadd_account&amp;quot)]])

    await message.reply(text=base_msg, reply_markup=keyboard)

bot.run()خب این همون کدی هستش که قبلا با کیبورد عادی نوشتیم و الان با کیبورد شیشه ای، اینجا هم مثل قبل هر لیست تو در تو یک row هستش و هر row میتونه شامل یه سری column باشه.هر دکمه رو داخل یه تاپل قرار میدیم که شامل تکست و callback_data یا url میشه. چیزی که الان نوشتیم خروجیش اینشکلی میشه:Inline Keyboard Button  الان اگه رو یکی از این دکمه ها کلیک بشه یه اپدیتی میفرسته و همونطور که قبلا گفتیم داخل هندلر callback_qurey باید بگیریمش.@bot.on_callback_query()
def get_callback(client, query):
    chat_id = query.message.chat.id

    if query.data == &amp;quotadd_account&amp;quot:
        phone_number = await client.ask(chat_id=chat_id, text=ask_phone_msg)
        print(phone_number.text)الان رو هر دکمه ای که کلیک بشه اپدیتش میاد اینجا و ما باید یه جوری تشخیص بدیم که اپدیت برای کدوم دکمست برای همین میایم از اون callback_data که قبلا ست کرده بویدم استفاده میکنیم، اینجا به جای message مینویسیم query که منطقی تر باشه هرچند هر چیزی که بخوایم میتونیم بنویسیم... و پیشنهاد میکنم این query رو پرینت بکنید و چیزی که داخلش هست رو ببینید که درک بهتری از اپدیتش داشته باشید و...تو کد بالا اومدیم شرط گذاشتیم اگر dataش برابر  add_acount  بود به کاربر بگه شمارش رو وارد کنه اینجا باز هم اومدیم خیلی ساده از متود ask برای گرفتن شماره کاربر استفاده کردیم.یه مورد دیگه هستش، وقتی الان کاربر رو دکمه کلیک میکنه درسته که بهش میگه شمارش رو بفرسته ولی اگه دقت کنید روی دکمه یه ساعت سفید رنگ میاد که این به این دلیل هستش که داخل callbacK_query ما باید بیایم یه answer_callback_query رو بفرستیم یا مثلا دکمه رو پاک کنیم یا دکمه رو چینج بکنیم مثلا یه سری دکمه دیگه نمایش بدیم ولی اینجا چون ما ask کریدم و در واقع send_message میشه برای همین اون علامت باقی میمونه، اگه بخوایم بعد از اینکه جواب میدیم پاک بشه میتونیم از متود answer استفاده کنیم (یه شورت کات هستش به جای اسم بالا که یکم طولانیه)به این شکل مینویسیم :await query.answer(&amp;quot&amp;quot)البته اینشکلی هیچ اتفاقی نمیفته(در واقع میفته ولی کاربر چیزی نمیبینه صرفا اون علامت ساعت میره)اگه بخوایم میتونیم از این برای نمایش یه سری متن هم استفاده بکنیم مثلا زمانی که کاربر روی یه دکمه کلیک میکنه ولی دکمه برای اون کاربر نیستش مثلا فقط ادمین حق داره از اون استفاده بکنه تو این شرایط میتونیم این رو بزاریم و وقتی کاربر کلیک میکنه بهش اخطار بده و... کافیه داخل اون استرینگ متنی که میخوایم رو بنویسیم.answer callback query همونطور که میبینید بالای صفحه نمایش داده میشه و اون ساعت هم روی دکمه شیشه ای دیگه نمیمونه. داخل کد های بالا ما مینوشتیم client.ask شما میتونید روی ابجکت user و chat هم از متود ask استفاده کنید. همچنین وقتی ask میکنید منتظر میمونه تا اپدیت جدید دریافت بشه و همینجوری منظتر میمونه، مگر اینکه پروسس کدمون kill بشه(البته اگه timeout ست نکرده باشیم براش) برای هیمن میتونیم از متود cancel_listener استفاده کنیم و فقط یه پارامتر chat_id باید بدیم بهش البته میتونیم رو ابجکت مثلا  User و Chat  هم صداش بزنیم مثلا :bot.cancel_listener(chat_id)  # OR
message.chat.cancel_listener()  # OR
message.from_user.cancel_listener()البته این عمل یه اکسپشنی رو هم برمیگردونه، یه مانکی پچ دیگه هم برای این Exception ایجاد شده که میتونید زمانی که ask میکنید اون ask رو داخل یه try قرار بدید و ارور رو هندل کنیدexcept pyrogram.errors.ListenerCanceled:درواقع این متود cancel_listener میاد future که پشت صحنه ایجاد شده رو پاک میکنه. نکته: وقتی میگید app.ask اینجا دیگه منتظره که یه پیامی بیاد و اون رو دریفات بکنه، تو این حالت خط بعدش اجرا نمیشه و تو این حالت ها نمیتونید کنسل بکنید چون این هر اپدیت مسیجی که بیاد رو دریافت میکنه، اگر مثلا اپدیت هایی غیر از مسیج داشته باشیم مثلا اینلاین کوئری یا کالبک دکمه شیشه ای و.. میتونیم از این کنسل استفاده کنیم، بیشتر مواقع هم همون تایم اوت ست کردن جواب میده...میتونید به یه شکل دیگه هم منطق کنسل کردن رو پیاده کنید، مثلا یه حالت دارید که میگید به کاربر ورودی رو بده و یه دکمه عادی  به اسم کنسل هم نشون دادید بهش، داخل کد میتونید شرط بزارید مثلاuser_input = await app.ask(.......)
if user_input in cancel_key:
    do something...به این شکل میتونید چک کنید اگر اینپوت کلید کنسل بود یه کاری رو انجام بده.... اینجوری هم میشه! غیر از این حالت ها تایم اوت جواب میده.خب دوستان آموزش تا همینجا بود امید وارم براتون مفید بوده باشه، پیشنهاد میکنیم لینک های مربوطه که براتون گذاشتم رو یه نگاهی بندازید، اونجا کامل تر هستش چون داخل یه مقاله نمیشه همه چیز رو گفت و  خسته کننده و طولانی میشه و بهتر که همیشه یه نگاهی به داکیومنت بندازیم...مثل همیشه میتونید لایک کنید کامنت بزارید و اگه دوست داشتید با بقیه هم شیر بکنید، اگه مشکلی، حرفی چیزی هم بود میتونید کامنت بزارید ❤️</description>
                <category>;...z@nko!#</category>
                <author>;...z@nko!#</author>
                <pubDate>Wed, 11 May 2022 15:35:49 +0430</pubDate>
            </item>
                    <item>
                <title>اضافه کردن قابلیت اپلود عکس و فیلم  به ادیتور TinyMCE در Django</title>
                <link>https://virgool.io/@zankoAn/upload-local-image-video-in-django-tinymce-hdho1jjimula</link>
                <description>جاده فرعی :))خب سلام دوستان، تو این قسمت میخوایم به ادیتور TinyMCE یه اپشن اضافه کنیم که بتونیم عکس ها رو با استفاده از file browser دیفالت سیستم اپلود کنیم چون در حالت دیفالت همچین اپشنی نیست و مجبوریم url رو دستی بدیم بهش یا بریم از پکیج های دیگه کمک بگیریم مثلا بیایم از پکیج filebrowser استفاده کنیم  که باز خود این باز دیپندنسی داره به grappelli (django-grappelli) که اون هم تمپلیت پنل ادمین جنگو رو تغیر میده و خب این برای من زیاد جالب نبود که این همه دیپندنسی نصب کنم صرفا برای یه اپلود عکس؟؟! زیاد بود واقعا برای همین بیاید بدونه نصب کردن این دیپندنسی ها مشکل رو حل کنیم ...- اضافه کردن قسمت اپلود به ادیتور TinyMCEمرحله اول میایم یه فایل داخل  دایرکتوری static مون ایجاد میکنیم :ساختار دایرکتوری مون فرض کنیم اینشکلیه. 
├── core
│   ├── urls.py
│   ├── settings.py
│   └── ...
├── post
│   ├── admin.py
│   ├── models.py
│   └── ...
└── static
    └── js
        └── uploader.js
خب الان ما  یه دایرکتوری به اسم static داریم که فایل های static مون داخلش قرار میگین(اطلاعات بیشتر راجب static فایل ها...)،  اینجا ما میایم یه دایرکتوری برای فایل های js مون ایجاد میکنیم و داخل دایرکتوری یه فایل به اسم  uploader.js  یا هر اسم دیگه که میخواید ایجاد میکنیم، بعد داخل این فایل میایم کد زیر رو قرار میدیم:- Uploader.jstinymce.init({
      selector: &amp;quottextarea#id_body&amp;quot,      
      height: &amp;quot700&amp;quot,
      width: &amp;quot1300&amp;quot,
      plugins: &amp;quotinsertdatetime media image preview&amp;quot,
      toolbar: &amp;quotundo redo |  bold italic | alignleft alignright aligncenter alignjustify | image media | preview&amp;quot,
      image_title: true,
      image_caption: true,
      automatic_uploads: true,
      image_advtab: true,
      file_picker_types: &amp;quotimage media&amp;quot,

      file_picker_callback: function (cb, value, meta) {
        var input = document.createElement(&amp;quotinput&amp;quot);
        input.setAttribute(&amp;quottype&amp;quot, &amp;quotfile&amp;quot);
        if (meta.filetype == &amp;quotimage&amp;quot) {
            input.setAttribute(&amp;quotaccept&amp;quot, &amp;quotimage/*&amp;quot);}
        if (meta.filetype == &amp;quotmedia&amp;quot) {
        input.setAttribute(&amp;quotaccept&amp;quot, &amp;quotvideo/*&amp;quot);}

        input. = function () {     
            var file = this.files[0];
            var reader = new FileReader();
            reader. = function () {
                var id = &amp;quotblobid&amp;quot + (new Date()).getTime();
                var blobCache =  tinymce.activeEditor.editorUpload.blobCache;
                var base64 = reader.result.split(&amp;quot,&amp;quot)[1];
                var blobInfo = blobCache.create(id, file, base64);
                blobCache.add(blobInfo);
               cb(blobInfo.blobUri(), { title: file.name });
             };
             reader.readAsDataURL(file);
         };
         input.click();
      },
      content_style: &amp;quotbody { font-family:Helvetica,Arial,sans-serif; font-size:14px }&amp;quot
  });این چند خط کد برای اپلود کرد فیلم و عکس کافیه و چیز دیگه ای نیاز نیست ولی خب این رو در نظر داشته باشید کانفیگ هایی که داخل settings برای TinyMCE ست کردیم(البته اگه ست کردید!) دیگه الان با این تغیر اینجا بدرد نمیخوره و اعمال نمیشه پس اگر اپشنی چیزی میخواید نمایش داده بشه  اینجا اعمال کنید مثلا چیز های بیشتری داخل toolbar میتونید قرار بدید(کلی اپشن دیگه داره که داخل داکیومنتش میتونید بخونید...)برای کانفیگ قسمت مربوط به image دوتا لینک زیر رو میتونید بخونید: https://www.tiny.cloud/docs/configure/file-image-upload/#automatic_uploads  https://www.tiny.cloud/docs/plugins/opensource/image/#options - Edit Admin Panelمهم ترین قسمت ماجرا این هستش که چطوری داخل ادمین پنل بتونیم گذینه اپلود رو اضافه کنیم(این رو هم بگم هرجا نیاز داشتید به اپلود از همین کدی که نوشتیم میتونید استفاده کنید و...)، برای این کار ما باید فایل زیر رو پیدا و ادیت کنیم :/django/contrib/admin/templates/admin/change_form.html ته این فایل قبل از خط {% endblock %} باید بیایم و این خط زیر رو بهش اضافه کنیم  که فایل js مون لود بشه :&lt;script src=&amp;quot{% static &#039;js/uploader.js&#039; %}&amp;quot&gt;&lt;\/script&gt;نکته:  این خط بالا تگ script وقتی میبستمش &lt;script/&gt; داخل ویرگول نمایشش نمیداد برای همین \ زدم که اوکی بشه این \ رو پاک کنید....change_form.htmlخب الان کار ما تموم شده بعد از ادیت و ذخیره فایل کافیه یک بار reload بشه قسمت مربوط به ادیتور مون و بعدش میتونیم مثل تصویر زیر گذینه جدیدی که بهش اضافه شده رو ببینیم و عکس و فیلم هامون رو اپلود کنیم:new optionupload imageخب امید وارم مفید بوده باشه براتون، مثل همیشه میتونید لایک کنید کامنت بزارید و اگر دوست داشتید با بقیه هم شیر بکنید و... اگه مشکلی، حرفی چیزی هم بود میتونید کامنت بزارید ❤️</description>
                <category>;...z@nko!#</category>
                <author>;...z@nko!#</author>
                <pubDate>Fri, 24 Dec 2021 02:40:30 +0330</pubDate>
            </item>
                    <item>
                <title>لاگین کردن در اینستاگرام با پایتون و لایبرری AioHttp</title>
                <link>https://virgool.io/@zankoAn/login-instagram-vjttpyzppviy</link>
                <description>instagramخب سلام دوستان امروز خواستم تو این مقاله نحوه لاگین کردن تو سایت اینستاگرام با پایتون و لایبرری aiohttp رو برسی کنیم و ببینیم به چه شکل هستش، برای اینکه تو سایت اینستا گرام لاگین کنیم یا لایک، فالو و... رو انجام بدیم  در پایتون میتونیم یا از لایبرری های که نوشته شدن استفاده کنیم  یا بیایم خودمون اون متود هایی که نیاز داریم رو بنویسیم که ما هم میخوایم همین کار رو انجام بدیم،  بعضی از لایبرری ها هستن که با requests نوشته شدن  و بعضی هم با لایبرری selenium و.. که میتونید ازشون استفاده کنید  ولی امروز ما میخوایم با لایبرری aiohttp بنویسیم .در آخر این post لینک گیت هاب قرار گرفته که میتونید کد هایی نوشته شده رو دریافت کنید. Step-1: Requirements خب در مرحله اول نیاز هستش که خود پایتون رو بلد باشید،  و یه درکی از http header ها داشته باشید، مورد بعدی  بهتر هستش که داخل گوگل یک سرچی راجب اینکه خود request چی هستش متود هاش چی هست و چجوری کار میکنه و این دسته از موارد بکنید تا یه درکی ازش پیدا بکنید  و همچنین اگر کار با لایبرری asyncio و aiohttp هم بلد باشید خیلی بهتون کمک میکنه پیشنهاد میکنم اگه ازشون استفاده نکردید  یه سری به داکیومنتشون بزنید یا 1 2 مورد فیلم یا مقالت موجود رو ببینید و بخونید که مشکلی نداشته باشید..نکته: برای ماژول asyncio در پایتون مقاله زیر خوب هستش  و در کل خوندش خالی از لطف نیست!(در ادامه برای درک کد هایی که مینویسیم بهتون خیلی کمک میکنه) https://virgool.io/@vahid_fathi/%D9%BE%D8%A7%DB%8C%D8%AA%D9%88%D9%86-%D9%88-coroutine%D8%B4-d4ve9jvzhobp Step-2: Toolsبرای اینکه که ما بفهمیم وقتی ریکوئستی فرستاده میشه دقیقا چه اتفاقی میفته و البته بر این اساس کدمون رو  بنویسیم میتونیم از خود مرورگر، مرورگر هایی با قابلیت های بیشتر و یا افزونه ها و برنامه های دیگه استفاده کنیم،اینجا 3 مورد رو مینویسم که بیشتر استفاده میشه و در ادامه مثال هایی هم میزنیم ازشون:Developer tools Burp SuitePost Manاولین مورد که قسمت نتورک developer tools مروگرتون هستش و در دامه با این قسمت بیشتر آشنا میشیم. دومین مورد هم یه برنامه مولتی پلتفرم و قدرتمند هستش که اینجا بدردمون میخوره و همچنین برای پنتست رو وب اپلیکیشن ها هم استفاده میشه و.. برای این مقاله ما میتونیم ازش برای دریافت، فرستادن و تغیر ریکوئست ها و بقیه موارد استفاده کنیم.اخرین مورد هم میتونید در برنامش یا در add onsش یا در بستر وب ازش استفاده کنید  .Step-3: Start Projectاز اون مواردی که بالا گفتیم اول میخوایم با Developer tools مروگر کار کنیم چون ساده تر هستش و برای استفاده کردنش لازم نیست کاری بکنید.خب اولین کاری که باید انجام بدیم این هستش که بریم  سایت اینستا و قسمت لاگین و بعدش Developer tools مروگر رو باز کنیم، بعد از این میتونیم تمام ریکوست هایی که در این tab فعلی ما به سمت اینستا میره رو ببینیم و همین درخواست ها رو با لایبرری aiohttp هم بفرستیم، در واقع تو مرورگر شما میاید درخواست هایی که میره رو اسنیف و برسی میکنید تا ببینید چه هدر هایی ست شده براشون و درخواست ها به کجا رفتن و...  بعد میاید اون ها رو با این کتابخونه یا کتابخونه های دیگه  مینویسید.خب بریم اون مواردی که بالا گفتیم رو انجام بدیم ببینم چی میشه اول باید بریم سایت اینستا گرام و بعد قسمت Developer tools رو باز میکنیم بعد میریم قسمت Network و بعد اونجا ما میتونیم درخواست ها و ریسپانس ها رو ببینیم و ازشون استفاده کنیم  :requestsوقتی میرید قسمت network مروگر(تصویر بالا) میبینید یه درخواست هایی فرستاده شده و برای هر درخواست شما میتونید ریسپانس و هدر request ها رو ببینید.(کافیه رو این درخواست هایی که فرستاده شده کلیک بکنید) ولی ما الان با این درخواست هایی که تا الان رفته کاری نداریم، چون میخوایم درخواست لاگین کردن رو ببینیم نه این موارد رو  برای همین میتونید اون دکمه clear رو بزنید که ریکوست هایی که تا الان رفته رو پاک کنه و تمیز بشه یا اینکه اون دکمه قرمز رنگ سمت چپ رو بزنید بعد رفرش بکنید اینشکلی تا زمانی که فعالش نکنید درخواست ها رو براتون رکورد نمیکنه.clearحالا ما برای اینکه درخواست لاگین کردن رو ببینیم  نیاز داریم  که یوزرنیم  و پسورد رو تو اون فیلد های مربوط قرار بدیم و بعد دکمه login رو بزنیم و بعد از اون باید requestی که فرستاده میشه رو تو همین قسمت network مرورگر ببینیم(دقت کنید که دکمه قرمز رنگی که بالا گفتم قرمز باشه که رکورد کنه ریکوست ها رو)send_user_passخب من اول قسمت dev tools رو جابجا کردم  و اون دکمه clear رو زدم که تمیز بشه و بهتر بتونیم ببینیمش، الان اینجا همونطور که مشاهده میکنید یه سری request فرستاده شده، الان ما اینجا درخواست های که تایپشون xhr هست رو میتوینم ببینیم ( xhr یا XmlHttpRequest یه ابجکت هستش که برای تعامل با سرور استفاده میشه، دیتا رو میتونید بگیرید از سرور بدونه اینکه صفحه رو رفرش کنید و اینکه میتونه به صورت synchronously و asynchronously این کار رو انجام بده؛ برای مثال زمانی که فالو میکنید، تو سرچ بار چیزی مینویسید یا لایک میکنیدو... درخواست های xhr هستن که فرستاده میشن و از سرور اون دیتا رو میگیرن و بهتون نشون میدن)Step-4: Header - POST(User/Pass)خب بیاید درخواست های مربوط Login رو باز کنیم تا بتونیم هدر هاشون رو ببینیم(برای اینکه بدونید کدوم درخواست مربوط به Login کردن هستش اول میتونید متود درخواست رو چک کنید و بعد تایپ درخواست، مثلا همونxhr)header خب وقتی میرید قسمت Header شامل چند قسمت میشه خودش Generalاین قسمت یه info کلی میده بهمون که کلیک بکنید روش میتونید ببینیدش .Response Headerاینجا هدر response اون درخواستی که فرستادیم رو میتونیم  مشاهد کنیم.Request Headerهدر اون  requestی که فرستادیم رو میتونیم اینجا مشاهده کنیم.قسمت اخر هم ممکن متغیر باشه مثلا الان ما یوز پسورد فرستادیم تو اینجا Form Data رو میتونید ببینید که داخلش دیتای هستش که فرستادیم .post user/pass headerخب در تصویر بالا شما هدر requestی که برای لاگین کردن فرستادیم رو میبینید که شامل خیلی چیزا میشه میتونید راجب http headers سرچ کنید و بفهمید چه مواردی داخل هدر قرار میگیره و.. اما قسمت پایین که با رنگ صورتی هایلایت شده اون قسمت دیتایی هستش که فرستادیم اونجا user و password ما قرار داره البته پسوردش یکم پیچیده میشه چون میتونید authentication version ست کنید که 0 برای تکست خالی هستش(همون عدد بین :‌ :‌ که اینجا 9 هستش) و میتونید صرفا پسورد رو بنویسید و تکست خالی رو میفرسته  و خب امنیتش هم پایین چون میشه اسنیفش کرد... در ادامه باز بیشتر میگیم.. و البته درکل پسورد شامل time - version - password و قسمت ثابتی که اولش هست میشه.الان تو تصویر بالا ما یک درخواست فرستادیم به /accounts/login/ajax/ و متودی که استفاده شده هم post هستش. یک سری از موارد داخل این  header ست شده ولی ما اون ها رو نداریم و به صورت داینامیک هستن یعنی مثلا از درخواست های قبلی یه مقادری بدست میاد و بعد تو هدر این درخواست ست میشه و بعد فرستاده میشه به سمت سایت مثلا وقتی از متود post استفاده میکنیم یه هدری ست میشه روی درخواست هدر csrf-token  ولی ما اینجا مقدارش رو نداریم این متغیر هستش هربار که درخواست بفرستیم سمت سایت نباید مقدار ثابت بدیم بهش و باید متغیر بدیم بهش این موارد معمولا از درخواست هایی که قبل تر فرستاده شده حالا چه در header چه در html اون پیج بدست میاد .cookie-csrf_tokenدر تصویر بالا اومدیم صفحه رو رفرش کردیم میبنید که درخواست اول متود GET فرستاده شده به ادرس /accounts/login/ و در اینجا اگر هدر Responseی که برمیگرده رو دقت کنید میبینید که داره Cookie رو ست میکنه (اگر خواستید راجب ست کردن کوکی بدونید اینجا رو میتونید بخونید..)و همونجا هم داخل هدر csrf_token روهستش (قسمت سبز رنگ ) و خب ما به این csrf_token رو برای لاگین کردن نیاز داریم  و البته از جا های دیگه ای هم میشه بدستش اورد که در ادامه میگیم .Step-5: Config Fileبالاتر دیدیم که ریکوئست یه هدر هایی داره که باید ست کنیم تا درخواست ما معتبر باشه و ریسپانس درستی رو دریافت کنیم چون اگر هدر درست نباشه ممکنه جواب های مختلفی دریافت کنیم پس برای همین اون هدر هایی که در عکس بالا دیدیم رو داخل یک فایل به اسم config.py مینویسم البته الزامی نیست که همه اون هدر ها رو ست کنیم میتونید اون مواردی که نیاز دارید رو ست کنید(راجب شون میتونید سرچ کنید  و.. یا تست کنید) class Config:
    def __init__(self):
        self.user_agent = &amp;quotMozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.106 Safari/537.36&amp;quot

    def shared_data(self) -&gt; tuple:
        url = &amp;quothttps://www.instagram.com/data/shared_data/&amp;quot
        headers = {
            &amp;quotuser-agent&amp;quot:self.user_agent,
        }
        return url, headers

    def login(self, rollout_hash: str, csrf: str, username: str, password: str, version: int = 0, time: int = 0) -&gt; tuple:
        url = &amp;quothttps://www.instagram.com/accounts/login/ajax/&amp;quot
        headers = {
            &amp;quotaccept-encoding&amp;quot:&amp;quotgzip, deflate&amp;quot,
            &amp;quotaccept-language&amp;quot:&amp;quoten-US,en;q=0.9&amp;quot,
            &amp;quotuser-agent&amp;quot:self.user_agent,
            &amp;quotorigin&amp;quot:&amp;quothttps://www.instagram.com&amp;quot,
            &amp;quotreferer&amp;quot:&amp;quothttps://www.instagram.com/accounts/login/&amp;quot,            
            &amp;quotsec-fetch-site&amp;quot:&amp;quotsame-origin&amp;quot,
            &amp;quotsec-fetch-mode&amp;quot:&amp;quotcors&amp;quot,
            &amp;quotx-instagram-ajax&amp;quot: rollout_hash,
            &amp;quotX-CSRFToken&amp;quot:csrf,
            &amp;quotx-requested-with&amp;quot:&amp;quotXMLHttpRequest&amp;quot,
        }
        data = {
            &amp;quotusername&amp;quot:username, 
            &amp;quotenc_password&amp;quot:f&amp;quot#PWD_INSTAGRAM_BROWSER:{version}:{time}:{password}&amp;quot,
            &amp;quotqueryParams&amp;quot:{}, 
            &amp;quotstopDeletionNonce&amp;quot:&amp;quot&amp;quot, 
            &amp;quotoptIntoOneTap&amp;quot:&amp;quotfalse&amp;quot,
            &amp;quottrustedDeviceRecords&amp;quot:{}
        }
        return url, headers, data    
خب الان هدر های مورد نیازمون رو داخل فایل config.py نوشتیم و اینجا دوتا فانکشن نوشتیم  یکی برای لاگین کردن و اون یکی هم برای گرفتن یک سری داده که بدردمون میخوره از جمله csrf-token و x-instagram-ajax و خیلی چیزای دیگه، که اگر نیاز بود میتونیم ازشون استفاده کنیم،   اون user-agent هم چون هر هدری که ما بنویسیم ثابت هستش پس داخلی init تعریفش کردیم (در هدر بالا میتونید هرکدوم که ست شده رو سرچ کنید و متوجه میشید که برای چه کاری هستن ولی مینیموم هدری که  برای لاگین کردن نیاز هست شامل user-agent و csrf-token میشه؛ یعنی این 2 تا هدر وجود داشته باشه کفایت میکنه و میتونید پروسه لاگین رو انجام بدید درضمن الان ما 2 تا هدر رو اینجا متغیر گذاشتیم(x-instagram-ajax و csrf) چون مقدارشون ثابت نیست و از shared_data بدستشون میاریم.)Step-6: Login Userimport aiohttp
import asyncio
from datetime import datetime
from config import Config      # ==&gt; local config fileخب  اول میایم لایبرری های مورد نیاز مون رو ایمپورت میکنیم( اون لایبرری datetime رو هم برای قسمتی هستش که باید time رو ست کنیم داخل دیتایی که میفرستیم برای لاگین همراه با پسورد) و فایل کانفیگ مون رو هم ایمپورت کردیم.async def login_user(session, username: str = None, password: str = None) -&gt; bool:
    url, headers = Config().shared_data()
    async with session.get(url=url, headers=headers) as resp:
        data = await resp.json()
        csrf_token = data.get(&amp;quotconfig&amp;quot).get(&amp;quotcsrf_token&amp;quot)
        rollout_hash = data.get(&amp;quotrollout_has&amp;quot)در ادامه یک coroutine ساختیم به اسم  login_user و 3تا ارگمان میگیره اولیش session هستش در واقع ابجکت ClientSession مون هستش  و همچنین ارگمان های یوزرنیم و پسورد. در خط بعد اون url که برای shared_data ست کردیم رو گرفتیم و الان دو متغیر  url , headers مقدار دهی شدن(داخل کانفیگ فایل ما url , headers رو  به شکل تاپل ریترن کردیم)  و خب در ادامه میایم یه context manager ایجاد میکنیم و یک request با متود GET به اون url  و با اون header  که گرفتیم میفرستیم .(اگر با Context manager مشکل دارید یا نمیدونید... میتونید این لینک رو بیبنید)داخل بلوک context manger که ساختیم میایم ریسپانس درخواستمون رو دریافت میکنیم، میتونیم تکستش رو بگیریم یا اگر json باشه jsonش رو بگیریم که خیلی بهتر هستش و خب ما هم همین کار رو انجام میدیم و json میریزیم داخل متغیر data و بعد اومدیم ازمتود get استفاده کردریم و از اون دیتامون csrf_token رو گرفتیم در قدم بعدی اومدیم به همین شکل مقدار  x-instagram-ajax v که نیاز داشتیم رو هم گرفتیم(بالاتر داخل کانفیگ فایل این دو مقدار رو به بعنوان پارامتر های تابعمون تعریف کرده بودیم).الان باید هدر مورد نیاز برای لاگین کردن رو بگیریم یا بهتر بگم بسازیم :url, headers, data = Config().login(rollout_hash ,csrf_token, username, password, 0, int(datetime.now().timestamp()))اول متود login رو صدا زدیم و بهش اون مقادیر مورد نیاز رو دادیم، 2 تا ارگمان اول برای قسمت header هستن و 2 ارگمان بعدی هم یوزر پسورد ما هستش و 2 ارگمان اخر هم  authentication version و timestamp مون هستش که ست کردیم براش.اینجا لازمه که یه مورد رو بگم همونطور که بالا تر هم گفتیم  authentication version میتونید ورژن دیگه ای رو قرار بدید و پسورد تون رو به صورت تکست خالی نفرستید و با استفاده از الگوریتم های رمز نگاری بیاید encrypt کنید پسورد تون رو و بعد بفرستید؛ در اینجا اگر بخواید همیچن کاری رو انجام بدید قبلا کدش نوشته شده مثلا میتونید از کدی که در لینک زیر قرار داره استفاده کنید برای جنریت کردن پسورد encrypt شدهhttps://gist.github.com/lorenzodifuccia/c857afa47ede66db852e6a25c0a1a027والبته میتونید بیشتر هم سرچ کنید راجبش و.. در اینجا چون ما برامون مهم نیست که حالا پسورد مون تکست فرستاده بشه یا encrypt بشه پس همون ورژن 0 میزاریم که تکست خالی باشه و راحت لاگین بشیم،  ولی اگه خواستید میتونید encryptش هم بکنید و اما اون shared_link رو هم برای همین اوردم و داخل کانفیگ ازش  استفاده کریدم چون اینجا اگه بخواید پسورد تون رو encrypt بکنید نیاز دارید به یک key_id و یک public_key که این دو مورد داخل همین shared_link هستش و به شکل jsonهم بهمون میده و خیلی مناسب تر هستش وگرنه میتونید html سایت اینستا رو هم نگاه بکنید اونجا هم هستش که میتونید با لایبرری bs4 اسکرپ کنید اون قسمت رو ولی خب وقتی اینجا به شکل json میتونیم بدستش بیاریم دیگه چه کاریه! و البته csrf_token رو هم خیلی ساده از همینجا گرفتیم(اون رو هم باز میتونستید یه ریکوست بفرستید به سایت اینستا و از ریسپانس هدر اون ریکوست و از قسمت کوکی بدستش بیارید..)در ادامه کار میایم با هدرها و دیتایی که داریم درخواستمون برای لاگین کردن رو میفرستیم:async with session.post(url=url, headers=headers, data=data) as r:
    data = await r.json()
    print(data)
    if data.get(&amp;quotauthenticated&amp;quot) == True:
        return True
    else:
        return False   خب میایم یه context manger منیجر دیگه مثل قبل ایجاد میکنیم و درخواست مون رو به اون url برای لاگین کردن میفرستیم ولی این بار از متود POST استفاده میکنیم چون میخوایم یوزنیم و پسورد رو هم بفرستیم(دیتامون)  بعد میایم response این درخواستی که فرستادیم رو پرینت میکنیم اگر یوزرنیم و پسورد تون درست باشه  لاگین میشید و باید همچین چیزی رو براتون پرینت بکنه(این پرینت رو گذاشتیم صرفا برای اینکه یه نگاهی به ریسپانس بندازیم):{&#039;user&#039;: True, &#039;userId&#039;: &#039;46059443573&#039;, &#039;authenticated&#039;: True, &#039;oneTapPrompt&#039;: True, &#039;status&#039;: &#039;ok&#039;}                                                                        والبته اگر لاگین تون موفقیت امیز نباشه همچین response رو دریافت خواهید کرد:{&#039;user&#039;: False, &#039;authenticated&#039;: False, &#039;status&#039;: &#039;ok&#039;} خب ما هم شرط گذاشتیم اگر اینجا authenticated برابر True بود یعنی با موفقیت لایگن کردیم و همه چی اوکی هستش و همونطور که قرار گذاشته بودیم True رو return میکنیم در غیر اینصورت هم False. (بهتر هستش که این قسمت  رو داخل یه try قرار بدید که except های احتمالی رو هم هندل کنید براش و...)و اما یک قسمت دیگه از کد باقی میمونه الان ما فقط یک Coroutine نوشتیم و باید اجراش کنیم  برای اجرا کردنش هم به این شکل عمل میکنیم async  def main():
    async with aiohttp.ClientSession() as session:
        login_task =  asyncio.create_task(login_user(session, &amp;quotUsername&amp;quot, &amp;quotPassword&amp;quot))
        response = await login_task
        if response:
            print(&amp;quot\nYou have successfully logged in&amp;quot)
        else:
            print(&amp;quot\nWrong username or password&amp;quot)

asyncio.run(main())خب قسمت اخر کدمون هم تابع main هستش(coroutine) که داخلش اومدیم یک تسک ایجاد کردیم و ارگمان های تابع لاگین یوزر مون رو هم بهش دادیم اولین ارگمان ابجکت Client session هستش و بعد یوزنیم و پسورد. خط بعد اومدیم با await اون تسک مون رو اجرا کردیم و چیزی که return میشه رو هم داخل response ریختیم و بعد یه پیامی رو هم پرنیت کردیم که بگیم لاگین شد یا نشد.Postmanهمونطور که قبلا گفتم میتونید این پروسه رو هم با اون بزار هایی که قبلا معرفی کردم  تست کنید و انجام بدید  اونا هم میتونن در بعضی مواقع  خیلی مفید باشن... مثلا در تصویر زیر ما درخواست POST رو فرستادیم  و اولین درخواست با موفقیت لاگین کردیم و هدر هم همونطور که مشخص کردم فقط csrf-token و user-agent باشه کفایت میکنه میتویند لاگین بشید و در تصویر بعدی هم پسورد اشتباه دادیم و لایگن انجام نشد و response متفاوتی رو دریافت کردیم. یه نکته اگر از postman استفاده کردید بعد از اینکه لاگین کردید اگر خواستید باز هم تست کنید یادتون نره کوکی هاش رو پاک کنید، اون گوشه سمت راست زیر دکمه send گذینش هست چون وقتی شما کوکی ها رو پاک نکنید اکانت لاگین هستش و url ی که برای لایگن کردن هستش رو دیگه پیدا نمیکنه.(اگه دوباره send کنید) authentication success authentication failed اما الان شما لاگین کردید و در واقع اون قسمت که درخواست post رو فرستادیم اونجا از هدر اون responseمون میتونیم cookie رو بگیریم و اون رو داخل یک فایل یا دیتابیس ذخیره کنیم از این به بعد کافیه داخل فایل کانفیگ و داخل هدر هایی که  میخوایم اون کوکی رو قرار بدیم  و دیگه هرکاری انجام بدیم با اون اکانت انجام دادیم میتویند لایک کنید فالو کنید، لیست فالور هاتون رو بگیرید، پیام بدید و هرکار دیگه ای که میخواید.پیشنهاد میکنم سورس های که  داخل GitHub قرار گرفتن رو بخونید برسیش کنید باهاشون کار کنید تا بیشتر دستتون بیاد حالا شاید بعدا هم تو یه پست دیگه  یه سری مثلا زدیم برای کار هایی مثل لایک ، فالو ، سرچ کردن، اپلود و..و خب این قسمت همینجا تموم شد امید وارم مفید بوده باشه و اینکه اره سعی کنید خوشحال باشید، امید داشته باشید- - و به زندگیتون ادامه بدید، مرسی که تا اینجا خوندید ❤️اگر نظری انتقادی پیشنهادی چیزی داشتید میتونید کامنت بزارید ✍️کد هایی که نوشتیم رو هم در لینک زیر میتونید مشاهد و دانلود کنید:‌ https://github.com/zankoAn/instagram-blog-project </description>
                <category>;...z@nko!#</category>
                <author>;...z@nko!#</author>
                <pubDate>Sun, 08 Aug 2021 20:45:07 +0430</pubDate>
            </item>
                    <item>
                <title>نوشتن ربات CLI تلگرام با زبان PYTHON و با لایبرری pyrogram قسمت اخر</title>
                <link>https://virgool.io/@zankoAn/pyrogram-ep4-ysnjgmoakuka</link>
                <description>pyrogram-bot-ep4خب سلام دوستان .  در این قسمت میخوایم رباتمون رو کامل کنیم،  یه قسمت برای فرستادن پیام ها به کاربران و همچنین ذخیره کردن id کاربر داخل دیتابیس و یه قسمت برای فوروارد کردن پیام به کاربران و یه قسمت هم برای جوین دادن ربات داخل لینک یا لینک هایی که ادمین میفرسته(لینک گروه)   رو به ربات اضافه کنیم .در اخر این پست لینک گیت هاب هستش میتونید برید کد هایی که نوشتیم رو ببینید و...ما تقریبا همیشه میام یه ربات api واسط میسازیم و با اون ربات میایم ربات های کلاینتمون رو کنترل میکنیم و عملی که میخوایم رو انجام میدیم چون یک سری قابلیت ها دارن که کار کردن با ربات رو ساده تر میکنه و خیلی بهتر هستش مثلا برای رباتی که نوشتیم زمانی که جمله های ربات زیاد بشه ما باید یه پیجینیشنی داشته باشیم که  مثلا تو هر صفحه 10 تا پیام نشون بده بقیش تو صفحه های بعدی نشون بده مثلا دکمه next و back داشته باشه کاربر بزنه روشون و عقب و جلو کنه داخل پیام ها و همچین مواردی.. شاید بعدا یه اموزش گذاشتیم برای وصل کردن این دوتا بهم و کار کردن باهاشون...User Sectionخب برای این قسمت ما میایم یه فایل جدید به اسم user_section یا هر اسمی که میخواید داخل دایرکتوری plugins ایجاد میکنیم و کد هایی که قرار مروبط به تعامل ربات با کاربر باشه رو اینجا مینویسیم .خب در کد بالا اومدیم مثل همیشه هندلر مون رو اول تعریف کردیم اما این دفعه اومدیم 2 تا یوزر ادمین و SpamBot رو  not کردیم و group رو هم 3 قرار دادیم چون 2 تا از قبل تعریف شده .در کد بالا ما هرکسی که پیام بده ربات این تابع اجرا میشه ولی ما نمیخوایم برای ادمین و اسپم بات(اسپم بات به این دلیل که وقتی ما کامند start رو تو قسمت status میفرستیم  اون یه جوابی میده،  زمانی که جواب میده در واقع پیام فرستاده و وارد این تابع میشه) این قسمت اجرا بشه برای همین not کردیم این دو یوزر رو.خب بریم ببینیم چی نوشتیم:قسمت  اول مثل همیشه چت ایدی رو ذخیره کردیم بعد شرط گذاشتیم ببینیم اصلا پیامی داخل دیتابیس هست یا نیست و بعد اگر پیامی بود مثل قسمت قبلی جمله ها رو از دیتابیس گرفتیم و داخل متغیر data ذخیره کردیم در ادامه یه حلقه زدیم رو data  و درون حلقه برای هر پیام یه چت اکشن فرستادیم بعد جمله رو فرستادیم و برای هر جمله هم 3 ثانیه اسلیپ دادیم یعنی پیام اول میره 3 ثانیه صبر میکنه جمله بعدی...اینجا ما داخل دیتابیس اومده بودیم قسمت اول جمله یه عددی رو مشخص کرده بودیم و ازش برای حذف کردن جمله ها استفاده کردیم ولی اینجا برای کاربر نباید اون رو بفرستیم برای همین میایم اون قسمت اولش رو نادیده میگیریم به این شکل:message.split(&quot;:&quot;, 1)[1]الان اینجا درون حلقه هربار یکی از جمله ها رو میگیره و ما میایم 1 بار اسپلیتش میکنیم با : و بعد الان وقتی جدا میشه همچین دیتایی خواهیم داشت[&quot;1&quot;, &quot;test-0&quot;]خب اینجا قسمت اول میشه عدد مربوط به هرجمله که نباید برای کاربر ارسال بشه پس میایم ایندکس دوم لیستمون رو میفرستیم برای کاربر.اگر هم پیامی داخل دیتابیس نبود میایم برای کاربر یه سلام میفرستیم..اما دو خط اخر میایم داخل دیتابیس ایدی کاربر رو ذخیره میکنیم : current_user = await c.get_me()
r.sadd(f&amp;quotusers:{current_user.id}&amp;quot, m.from_user.id)اینجا ما از یه متود جدید به اسم get_me استفاده کردیم،  این متود میاد اطلاعات این اکانتی که الان باهاش به تلگرام وصل شدیم رو بهمون میده( در واقع تایپ User رو بهمون برمیگردونه ) و بعد ما اومدیم به دیتابیس ایدی این یوزری که پیام فرستاده به ربات رو داخل دیتابیس ذخیره کردیم اینجا ما کلید رو برابر users:{current_user.id}قرار دادیم ، میتونستید کلا این قسمت current_user رو بردارید ننویسید به این شکل: r.sadd(&amp;quotusers&amp;quot, m.from_user.id)ولی من current_user رو هم ایجاد کردم برای اینکه مثلا اگر چند اکانت استفاده کردید تعداد یوزر های هر اکانت جدا باشه.نکته:  تو کدی که نوشتیم هربار که کاربر پیام بده به ربات این تابع اجرا میشه و پیام ها برای کاربر ارسال میشن که این زیاد جالب نیست برای همین میتونید یک مقداری رو داخل دیتابیس بعد از فرستادن پیام  ذخیره کنید  و قبل از اینکه پیامی رو بفرستید به کاربر بیاید  مقدارش روچک کنید اگر نبود بعد  بیاید پیام رو بفرستید به کاربر(اینجوری اگه از قبل پیام داده باشه بهش دیگه نمیده) حالت های دیگه ای رو هم میتونید خودتون بنویسید...Show infoShow infoخب ما چون در بالا اومدیم یوزر ها رو داخل دیتابیس ذخیره کردیم اینجا میایم فایل info_section مون رو هم تغیر میدیم و به این شکل تعداد یوزر های  موجود رو میگیریم.اینجا از متود scard ردیس استفاده کردیم، این متود میاد تعداد ولیو هایی که برای اون کلیدمون داخل set ذخیره کرده بودیم رو برمیگردونه؛ دقت کنید که این متود برای set هستش بالاتر که sadd کردیم داخل یک set اون یوزر ایدی ها رو ذخیره میکنه .Forward Msg / step1forward_msg خب الان میخوایم یه پیامی رو به یه تعداد خاصی از کاربر های ربات یا همه کاربر ها ارسال کنیم اینجا گفتیم برای اینکه به یه تعداد خاص از کاربر ارسال کنید یه عدد رو بفرستید و اگر میخواید به همه کاربر ها ارسال کنید * رو بفرستید.تو کد بالا اومدیم مثل همیشه هندلر مون رو تعریف کردیم و کامند forward رو هم فیلتر کردیم بعد اومدیم پیامی که میخوایم فرستاده بشه رو نوشتیم و در ادامه یه چت اکشن و بعدش پیام رو فرستادیم در اخر هم داخل دیتابیس مثل همیشه که میخوایم input بگیریم step رو مشخص کردیم مثلا اینجا offset کلید forward msg رو برابر 0 و valueش رو هم برابر 1 قرار دادیم  برای step اول که گرفتن تعداد کاربر هستش.و اومدیم offset استپ بعدی رو 1 قرار دادیم و مقدارش رو گذاشتیم 0 ،  این step برای گرفتن پیامی هستش که میخوایم فوروارد کنیم اگر اینجا مقداری براش تایین نکنیم و تو مراحل بعدی وسطش کاربر بیاد کامند forward رو بفرسته اون رو به عنوان پیام ممکنه ارسال بکنه چون اونجا مثلا step چیز دیگه ای بود پس بهتر چنین جا هایی شما step رو 0 بکنید داخل این مرحله اولیه که به اشتباه وارد اون هندلر هایی که نوشتید نشه.نکته: اینجا درسته که کلید یکی هستش یعنی هردو forward:msg هست ولی تو متود setbit میتونید تعداد زیادی offset داشته باشید اینجا برای استپ اول افست رو 0  قرار دادیم و برای استپ بعدی افست رو 1 دادیمForward Msg / step2اینجا میخوایم تعدادی که کاربر میفرسته رو بگیریم و یه ولیدیتی انجام بدیم و همچنین step رو هم تغیر بدیمforward msg step2  خب مثل قبل هندلر مون رو نوشتیم و group رو 4 گذاشتیم چون قبلا 3 تا group تعریف کردیم.در ادامه یه شرط نوشتیم که اگر مقدار forward:msg برابر 1 بود و همچنین msg هم وجود داشت؛  در اینجا ممکن کاربر فایل یا اهنگ و.. بفرسته که اینها text نداشته باشه در اینصورت ارور میگیریم چون and بعدی گفتیم اگر  با / شروع نشده بود بیا وارد شرط بشو پس برای همین اینجا  and msg رو هم مینویسیم.بعد داخل شرط اول یه try نوشتیم چون ما گفتیم به کاربر بیا یه عدد بفرست یا * ولی اگه کاربر چیز دیگه ای فرستاد چی؟ باید این رو هم هندل کنیم خب ما اومدیم گتفیم اگر مسیج برابر بود با * یا تونستی اون مسیج رو تبدیل کنی به int برو داخل شرط  اگر هم نتونستی int بکنی یعنی پیام کاربر متنی یا چیز دیگه ای بوده و الان بهمون ValueError ارور میده که داخل except گفتیم اگر ValueError بود بیا به کاربر بگو فرمت درست رو ارسال بکنه .بعد از اینکه وارد شرط شدیم اومدیم یه چت اکشن فرستادیم و بعدش یه پیام فرستادیم به کاربر که بیاد پیامی که میخواد ارسال بشه رو بفرسته در ادامه اومدیم یه مقادیری رو داخل دیتابیس ست کردیم اینجا اولین مقدار تعداد یوزر هایی هستش که کاربر میخواد بهشون پیام بفرسته، در خط بعدی اومدیم ایدی این پیامی که الان فرستادیم به ادمین رو هم ذخیره کردیم (در ادامه بهش نیاز داریم) و 2 خط بعدی هم step رو مشخص کردیم اول step قبلیمون رو 0 کردیم که وارد اینجا نشه و بعد استپ جدیدی رو 1 کردیم برای گرفتن پیامی که میخواد ارسال بکنه.Forward Msg / step3الان ما تعداد کاربرانی که پیام قرار براشون ارسال بشه رو داریم فقط کافیه پیامی که قرار ارسال بشه رو از ادمین بگیریم  و  ارسال کنیم برای اینکار میایم یه هندلر دیگه مینویسیم مثل قبلی که نوشتیم:forward msg step3خب در اینجا دقیقا مثل قبل هندلر مون رو تعریف کردیم فقط group رو یکی زیاد کردیم  و بعد یک شرط نوشتیم که اگر  step مون اونی بود که تو مرحله قبل نوشتیم بیا برو داخل شرط: بعد داخل شرط میایم ایدی پیامی که قبلا ذخیره کردیم رو از دیتابیس میگیریم بعد یه شرط میزاریم که اگر ایدی این پیامی که الان فرستاده شده برابر بود با اون ایدیی که تو مرحله قبل داخل دیتابیس ذخیره کردیم بیا برو داخل شرط :نکته :‌ تو مرحله قبل اگر ایدی پیامی که فرستادیم رو ذخیره نمیکردیم و الان هم چک نمیکردیم یه مشکل بوجود میومد زمانی که پیام رو میفرستیم این هندلر هایی که نوشتیم group شون فرق میکه پس  اون پیامی که میاد رو دریافت میکنن اینجا ما میایم شرط میزاریم و مراحل رو جدا میکنیم ولی  اینجا وقتی میگه به کاربر عدد یا * رو بفرست اگه کاربر مثلا یه عدد بفرسته بعدش میاد وارد forward_msg_S2 میشه و اونجا step تغیر میکنه و وقتی وارد هندلر دیگه میشه (هردو هندلر پیام رو گرفتن اول اونی که اولویتش پایین تره زود تر اجرا میشه بعد اونی که اولویتش بیشتر، الان اینجا forward_msg_S2 اولویتش کمتر بود پس اون اول گرفت و step رو هم تغیر داد والان وقتی وارد forward_msg_S3  میشه اونجا شرط ما که دیتابیس چک میکنیم درست هستش و اونجا خود به خود اون چیزی که قرار بود عدد ما باشه میشه پیام ما و همون برای کاربر ارسال میشه برای حل این مشکل میتونید یا به اینشکلی که نوشتیم مسیج ایدی رو هم چک بکنید یا اینکه بیاید group رو تغیر بدید یعنی مثلا برای forward_msg_S3 بیاید groupرو بزارید 4 و برای forward_msg_S2 بزارید 5 اینجوری اول این اجرا میشه شرط درست نیست بیخیال میشه میره اون یکی رو چک میکنه شرط درست هستش و ادامه ماجرا...تو شرط میایم یه counter تعریف میکنیم برای اینکه تو مرحله قبل اگر کاربر * نداده بود برای تعداد ارسال پیام و عدد داده بود اینجا بشماریم و وقتی به اون تعداد رسید دیگه پیام نفرستیم .بعدش میایم مثل قبل از متود get_me استفاده میکنیم و ایدی اکانت رو میگریم و یک حلقه میزنیم رو دیتابیس و یوزر id ها رو میگیریم بعدش داخل حلقه یه چت اکشن ارسال میکینم و بعد از متود forward_messages  استفاده میکینم این متود فوروارد میکنه پیام رو چون ببینید❌ پیامی که ادمین ست میکنه برای راسال ممکنه کپشن داشته باشه عکس باشه یا فیلم یا هرچیز دیگه ای برای همین ما ساخته بیایم خودمون دونه دونه جدا کنیم داخل دیتابیس ذخیره کنیم بعد اینجا باز بهم وصلشون کنیم بعد تازه بیایم ارسال بکنیم میبینید که کار  اشتباهی هستش❌ پس مایم id اون پیامی که ادمین فرستاده رو میگیریم و فورواردش میکنیم اگر نمیخواید وقتی که به کاربر ارسال میشه بنویسه فوروارد شده این پیام از طرف x میتونید از متود copy_messages استفاده کنید.بعد نوشتیم که اگر تعدادی که ادمین مشخص کرده تو مرحله قبل * نبود و همچنین کانتر ما برابر اون شده بود بیا اینجا break کن دیگه پیام نفرست اینجوری به اون تعداد که ادمین گفته پیام میفرستیم(پیشنهاد میکنم اینجا یه اسلیپ چند ثانیه ای اعمال کنید چون اگر تعداد زیاد باشه و شما پشت سر هم زیاد پیام ارسال کنید به ارور flood wait برمیخورید که در ادامه باز بیشتر میگیم راجب این ارور )خب بیایم یکم بیشتر راجب متود  forward_messages بگیم چون چیزی راجب ارگمان هاش و.. نگفتیم:forward_messagesو اما متود فورواردی که استفاده کردیم پارامتر هاش به چه شکل هست:chat_id (int | str)chat_id (int | str)message_ids (int | List of int)disable_notification(bool )schedule_date(int)پارامتر اول  ایدی فردی هستش که میخوایم فوروارد بشه براش ( مقصد ) پارامتر دوم چت ایدی مبدا هستش در اینجا ما اومدیم همین چتی که با ربات داشتیم رو دادیم بهش چون میخواستیم یپامی که اینجا هست رو برای کاربر فوروارد کنیم . پارامتر بعدی id اون پیامی هستش که قرار فوروارد بشه که میتونه لیستی از پیام ها یا فقط یک پیام باشه.پارامتر بعدی هم میتونید ست کنید که نوتیفای بره یا نره  و پارمتر اخر هم یه Unix time رو میتونید ست کنید که اون زمان پیام فوروارد بشه.قبلا پارامتر های دیگه ای رو میگرفت متود فوروارد مثلا  as_copy ولی تو اپدیت های جدید مثلا متود   copy_message رو اضافه کردن که بهتون اجازه میده خیلی چیزا رو روی پیام ست کنید .Screenshotforward-msg-tmJoin Msgاینجا میخوایم یه پیامی از کاربر بگیریم که بعد از اینکه وارد گروه شد اون رو ارسال بکنه:Join msgدر کد بالا اول از همه اومدیم errors رو هم ایمپورت کردیم برای هندل کردن ارور ها که در ادامه بهش میرسیم...مثل قبل هندلر مون رو نوشتیم یه چت اکش ارسال کردیم و step مون رو هم مشخص کردیم ولی اینجا چت اکشن برای اینکه هربار اون تایم رو ننویسیم اومیدم یه تابع اینشکلی اینجاد کردیم هرجا نیاز شد صداش میزنیم(درواقع یه کوروتین نوشتیم که هرموقع نیاز شد یه تسک ایجاد میکنیم و await میکنم تسکمون رو (قسمت قبل یه لینک راجب کوروتین گذاشته بودم حتما ببینید))‌Get-Join-Msg  خب باز مثل قبل هندلر مون رو نوشتیم و بعد group رو هم برابر 6 قرار دادیم چون قبلا 5 تا استفاده کردیم و بعد ما شرط گذاشتیم که ببینم  در step درستی هستیم یا نه و همچنین msg تکست وجود داره و همچنین با / شروع نشده باشه اگه این شرایط برقرار بود بیاد یه چت اکشنی بفرسته وهمچنین اون پیام رو داخل دیتابیس ذخیره بکنه و به کاربر بگه ذخیره شد اخرش هم داخل دیتابیس stepرو 0 میکنیم.Join Chat / step1Get-Linkخب در کد بالا ما میخوایم لینک گروه رو از کاربر بگیریم اینجا میایم مثل قبل هندلر مون رو مینویسیم و بعد یه چت اکشن ارسال میکنیم و همچنین یه پیامی میفرستیم که بیاد لینک گروه رو بفرسته در اخر هم step  رو برابر 1 قرار میدیم.join Chat / step2Join-Chat خب باز هم هندلر مون رو نوشتیم و یکی به group اضافه کردیم و بعد چک کردیم ببینیم step درست هستش یا نه و همچنینی msg.text وجود داره یا نه  و با / شروع نشده باشه.در ادامه یه چت اکشن نوشتیم و بعد یه try گذاشتیم که ارور ها رو هندل کنیم اگه یادتون باشه تو این فایل ما اول اومدیم errors روهم ایمپورت کردیم ما اینجا ازش برای هندل کردن ارور های احتمالی استفاده میکنیم.اول چک میکنیم ببینم لینکی که کاربر فرستاده برای گروه پابلیک هست یا پرایویت گروه های پرایویت داخل لینکشون joinchat هستش برای همین چک میکنیم اگر داخل لینک کاربر بود پس پرایویت چت هستش و مستقیم با متود join_chat وارد اون گروه میشیم .متود join_chat پارامتر های زیادی رو نمیگیره فقط لینک گروه یا چنل رو میگیره و یا ایدی عددی اون گروه یا چنل رو .اگه دقت کنید من اومدم چیزی که متود join_chat برمیگردونه رو ریختم داخل متغیر resp این رو در ادامه باهاش کارداریم ، چیزی هم که برمیگردونه خود Chat هستش که در این لینک میتونید ببینید که Chat دقیقا چه پارامتر هایی داره و همینا رو هم برمیگردونه.در ادامه اومدیم یه پیام فرستادیم برای ادمین که با موفقیت وارد گروه شدیم و بعدش هم یک شرط گذاشتیم که اگر ولیویی برای join_msg داخل دیتابیس وجود داشت بیاد یه چت اکشن بفرسته و اون پیام رو هم به اون گروه بفرسته. دقت کنید بالاتر زدیم پیام رو بفرست به chat_id که متغیری هستش که بالا تر تعریفش کردیم و مقدارش میشه چت ایدی همین جایی که با ادمین تعامل داره ربات ولی اینجا اومدیم از اون resp استفاده کردیم چون میخوایم چت اکشن رو در اون گروه ارسال کنیم نه در pv به همین دلیل بود که مقدار return شده  join_chat رو ریختیم داخل resp.Error Handlingjoin-chat-exceptخب کدی که بالا نوشتیم ممکنه ارور هایی رو دریافت کنه این ارور ها رو ما باید هندل کنیم برای هندل کردن اررو ها شما از لایبری پایروگرام همونطور که اول این فایل نوشتیم میاید errors رو هم ایمپورت میکنید و بعد داخل except ها میاید میگید اگه اون ارور بود بیاد فلان رفتار رو انجام بده مثلا اینجا ما اولی except که نوشتیم برای هندل کردن ارور این بوده که کاربر قبلا داخل گروه بوده یا اینکه لینک اشتباه فرستاده، لینک اصلا وجود نداره و .... مواردی که بیشتر بهش میخورید و در ذهنم بود رو هندل کردم که به ادمین بگیم دقیقا چه اتفاقی افتاده مثلا ارور اخری میگیم که اونقدر تایم باید صبر کنه تا اینکه بتونه وارد اون گروه بشه ربات چون محدود شده و اگر اروری رو هم در اینجا ننوشتم و بهش برخوردید باز میتونید به همین شکل هندل کنید .البته ارور اخر که یه تایمی رو باید صبر کنه معمولا میایم از اسلیپ ماژول asyncio استفاده میکنیم برای اینکه به اون مدت گفته شده sleep بدیم بهش.در اخر   اومدیم داخل دیتابیس Step مون رو هم 0 کردیم همه چی اوکی باشه.Screenshottest_join_chat_0خب همونطور که میبیند اوکی بود و پیام رو هم ارسال کرد داخل اون گروه مشکلی نبود اما برای اون ارور هایی که هندل کردیم هم خروجیمون اینشکلی میشه:test_join_chat_1خب ارور هایی هم که هندل کردیم همچین شکلی خواهند داشت باز اگه به ارور دیگه برخورد کردید میتونید خیلی راحت هندل کنید و برید جلو ...نکته: تا اینجای کار ما Step هایی که هندل کردیم درست کار میکنن ولی یه مشکلی هست زمانی که مثلا بزنید join_chat/ بهتون میگه لینک رو بفرستید اینجا مثلا یکی بیاد به جای لینک بزنه join_msg/ ازش میخواد که پیام رو بفرسته وخب اگر بفرسته باز میاد اون رو ذخیره میکنه و همچنین ارور میده که لینک معتبر نیست اگر خواستید این موارد رو هم هندل کنید میتونید یا بیاید اینجا تو هر مرحله تمامی step ها رو setbit کنید یعنی هر قسمت فقط step مربوط به خودش 1 بشه و بقیه رو  0  بکنید  ولی اینجوری یکم طولانی میشه اگه دارید از ردیس استفاده میکنید میتونید از متود hset استفاده کنید به این شکل که یه کلید میزارید مثلا Bot:Steps بعد در هر قسمت کل استپ ها رو میدید بهش مثلا r.hset(&amp;quotBot:Steps&amp;quot, mapping={&amp;quotjoin:chat:link&amp;quot:0, &amp;quotjoin:chat:msg&amp;quot:1})اینشکلی میتونید چندین step رو همزمان تایین کنید و اون مشکل که گفتم پیش نماید چون بقیه step ها 0 شدن و زمانی که چک میشن دیگه اجرا نمیشن(شاید بعدا تو گیت هاب Step رو اینشکلی اضافه کنم براش). https://redis.io/commands/hset و اینکه میتونید این اپشن ها رو باز زیاد تر کنید بهتر کنید و یا هر چیزی که به ذهنتون میرسه مثلا این پیامی که میدیم برای ارسال رو بتونیم نمایش و تغیرش بدیم... تا همینجا برای این رباتمون کافیه و دیگه اپشنی بهش اضافه نمیکنیم احتمالا... شاید بعدا یه ربات دیگه هم نوشتیم فعلا مطمن نیستم میتونید نظر بدید که ربات های api بنوسیم یا client یا هرچیز دیگه ای ...و مرسی که خوندید و با من همراه بودید تو این ماجرا امید وارم راضی بوده باشید و خوشحال و خندون به زندگیتون ادامه بدید، چاکس همگی ❤️اگر نظری انتقادی پیشنهادی چیزی داشتید میتونید کامنت بزارید ✍️کد هایی که نوشتیم رو هم در لینک زیر میتونید مشاهد کنید :‌ https://github.com/zankoAn/Pyrogram-Bolg-Project قسمت اول اموزش رباتقسمت دوم اموزش رباتقسمت سوم اموزش ربات</description>
                <category>;...z@nko!#</category>
                <author>;...z@nko!#</author>
                <pubDate>Fri, 26 Mar 2021 19:26:53 +0430</pubDate>
            </item>
                    <item>
                <title>نوشتن ربات CLI تلگرام با زبان PYTHON و با لایبرری pyrogram قسمت سوم</title>
                <link>https://virgool.io/@zankoAn/pyrogram-client-bot-ep3-yaj73eg5mmdr</link>
                <description>pyrogram  خب سلام دوستان در ادمه ماجرا رسیدیم به قسمت دیلیت کردن پیام هایی که ذخیره کرده بودیم و تو این قسمت میخوایم اپشن del_msg , status و  info رو به ربات اضافه کنیم و از یه سری متود جدید هم استفاده میکنم...در اخر این پست لینک گیت هاب هستش میتونید برید کد هایی که نوشتیم رو ببینید و...Delete_Messageاولین اپشنی که میخوایم اضافه کنیم دیلیت کردن جمله ها از دیتابیس هستش .del msgمثل همیشه یه هندلر تعریف کردیم و پرایویت چت و یوزر ادمین رو فیلتر کردیم  +  کامند del_msg  و بعد اومدیم چت اکشن فرستادیم برای کاربر و مثل قبل چک کردیم اگر کلید Messages داخل دیتابیسمون بود بیاد به کاربر بگه شماره جملش رو بفرسته تا حذف بشه و یا * رو بفرسته که همه پیام های موجود رو پاک کنیم،    اگر هم نبود کلا Messages وجود نداشت داخل دیتابیس بیاد بگه  جمله ای وجود نداره .اینجا ما نمیتونیم حذف بکنیم پیام رو از دیتابیس چرا؟ چونکه باید ورودی بگیریم از کاربر پس میایم مثل add msg که قبلا نوشتیم اینجا هم step بندی میکنیم  الان اگر ما جمله ای داخل دیتابیسمون وجود داشت میایم step این del:msg  رو برابر 1 قرار میدیم الان کافیه یه هندلر دیگه تعریف کنیم که بیاد پیام کاربر رو بگیره و از دیتابیس حذف بکنه.اینجا از کاربر خواستیم که عدد مربوط به اون جملش رو بفرسته چونکه سخته کاربر بیاد کل متن رو بنویسه یا کپی کنه... اگه یادتون باشه تو اموزش قبلی ما اومدیم به هر جمله داخل دیتابیس یه شماره دادیم الان جمله هامون اینشکلی ذخیره شده بودن messagesهر جمله یک عدد قبلش هست که ما از همین عدد برای حذف کردنش از دیتابیس استفاده میکنیم.خروجی:del msg tmGet Message iddel-msg خب یه هندلر تعریف کردیم مثل قبل فقط اینجا چون نمیخواستیم با هندلر قبلیمون که برای گرفتن جمله ها بود قاتی بشه(درواقع نادیده گرفته بشه) اومدیم group رو گذاشتیم 2.اول مثل قبل چک کردیم که اگر del:msg  برابر 1 بود و همچنین پیام کاربر با / شروع نشده بود بیا داخل شرط ، داخل شرط متغیر چت ایدی رو تعریف کردیم و همچنین یه اکشن تایپینگ هم ارسال کردیم بعد اومدیم یه شرط گذاشتیم که اگر پیام برابر بود با  *  کلا هرچی پیام هست رو از دیتابیس پاک کنه (‌r.delete در ردیس میاد اون کلید رو از دیتابیس پاک میکنه و هرچی ولیو داشته باشه هم پاک میشه)  و اگر پیام کاربر * نبود پس یک عدد هستش که اول میایم با استفاده از متود sscan داخل دیتابیس سرچ میکینم؛ این متود یه ارگمان match میگیره که باهاش میتونیم طبق یک الگو اون ولیو رو پیدا کنیم مثلا اینجا ما گفتیم اولش اون عدد کاربر باشه :  بعدش هرچی بود بود اینجوری پیام دقیق رو میگیره از دیتابیس و نمایش میده.  اینجا میتونید برسی هم بکنید که ببینید چیزی که کاربر میده اول عدد بوده یا علکی پیام فرستاده.(البته مشکلی بوجود نمیاد اگر علکی هم داده باشه چون متود sscan چیزی رو برنمیگردونه پس میره داخل else و به کاربر میگه جمله وجود نداره) برای اینکار چون msg استرینگ هستش msg میتونید داخل یک try  و except این عمل رو انجام بدید مثلا int(msg)‌ اگر ValueError داد پس عدد نبوده!....خروجی :delete messageCheck Statusخب قسمت بعدی که باید به ربات اضافه کنیم برای status گرفتن هستش فایل قبلی که برای ادمین پنل بود زیاد شده بود برای همین یه فایل به اسم info_section ساختیم و قسمت مربوط به گرفتن status ربات رو اینجا قرار میدم.ابتدا چیز هایی که نیاز داریم رو import میکنیم:importsخب مثل قبل Client, filters و از پلاگین ها هم r , admin رو ایمپورت کردیم اما اینجا 2 تا مورد جدید هستن لایبرری asyncio رو هم ایمپورت کردیم البته اینجا زیاد کاری باهاش نداریم فقط از متود sleepش میخوای استفاده کنیم و اما اون raw که بالا ایمپورت کردیم مربوط به raw متود ها داخل پایرو گرام هستش این مثال رو خواستم با اون بزنم که با این raw متود ها هم اشنا بشید در ادامه بیشتر میگیم...خب الان بریم قسمت گرفتن وضعیت اکانت رو بنویسیم:«get statusخب در کد بالا اول اومدیم هندلر مون رو مثل قبل تعریف کردیم و فیلتر هامون رو هم قرار دادیم در ادامه اومدیم چت ایدی رو هم داخل متغیر chat_id ذخیره کردیم چون در ادامه بهش نیاز داریم  و بعد از raw متود StartBot استفاده کردیم برای استارت کردن SpamBot ، از این ربات برای چک کردن وضعیت اکانتتون میتونید استفاده کنید اگر محدودیتی چیزی داشته باشه اکانت بهمون میگه.اما یکم بیشتر راجب raw متود ها حرف بزنیم بعدا به کد برمیگردیم.زمانی که در پایروگرام بخواید با api تلگرام در سطح پایین( low-level) تری کار کنید میتونید از raw متود ها استفاده کنید در بعضی از موارد ممکن پیش بیاد که نیاز شما با متود های سطح بالا(high-level)  برطرف نشه و یا اصلا بخواید برای داشتن سرعت بهتر از raw متود ها استفاده کنید... کار کردن باهاشون یکم ممکنه گنگ باشه اول کار  ولی یه مدت باهاشون کار کنید دستتون میاد ... ( همه متود هایی که در سطح بالا داریم ازشون استفاده میکنیم با همین raw متود ها نوشته شدن  پس برای همین هم پرفرمنس بهتری رو خواهید داشت با استفاده از این متود ها ولی یکم ممکنه کدتون شلوغ بشه و یکم پیچیده بشه...)برای اینکه از این متود ها استفاده کنید باید اول ایمپورتشون کنید:from pyrogram import Client, filters, raw در تصویر get-status اومدیم از raw متود StartBot استفاده کردیم این متود  4 پارامتر رو به عنوان ورودی میگیره که شامل این 4 مورد میشه:bot(InputUser)peer(InputPeer)random_id(int)star_paramپارامتر اول رباتی که میخواید باهاش کار کنید رو مشخص میکنید ولی مثل قبل نمیتونید بگید ربات x چون دارید low-level کار میکنید و باید چیزی که تغریف شده براش رو بدید بهش که اینجا گفته ورودیش فقط InputUser باید باشه که اگه داکیومنتش رو بخونید میگه inputUser شامل id و access_hash میشه که اینجا باید ست کنید براش ولی  پایروگرام برای اینکه یه مقدار کار شما رو راحت تر کنه یه متود گذاشته به اسم resolve_peer که دقیقا این id و access_hash رو بهتون برمیگردونه فقط کافی یوزر نیم یا چت ایدی یا شماره تلفن رو بهش بدید تا بهتون چیزی که میخواید رو بده:inputUser = client.resolve_peer(&amp;quotSpamBot&amp;quot)اگر  الان inputUser رو پرینت کنید میبینید که در خروجی id و access_hash قرار داره(البته این رو هم بگم اگر میخواید خودتون دستی باز این access_hash , id رو بدید بهش باید از type ها و تایپ InputPeerUser استفاده کنید و اون رو بسازید).خب پارامتر دوم هم جایی هستش که میخواید به ربات پیام بدید و اون کانورسیشن رو شروع کنید که  میتونه گروه باشه یا اینکه پیوی خود ربات باشه اون هم باید حتما بهش InputPeer بدید که باز هم با همین resolve_peer مثل قبلی میتونید انجامش بدید ( اگه اسم گروه بدید بهش میره ربات رو اونجا استارت میکنه اگه داخل گروه نباشه ربات رو add  میکنه تو گروه  و اگر دست رسی add کردن نداشته باشه ربات، میاد ارور میده بهتون که دست رسی نداره)پارامتر سوم هم یه عدد رندم هستش برای اینکه پیام قاتی نشه چون low-level کار میکنیم و اگه مثلا یه عد ثابت بدیم دفعه بعدی پیام رو به ربات ارسال نمیکنه چون قبلا کرده برای همین باز یه متود داریم به این شکل :client.rnd_id()با استفاده از این متود میتونید id های یونیکی رو بسازید و استفاده کنید دیگه پیام ها id یکسانی نمیگیرن و مشکلی پیش نمیاد به درستی کار خواهد کرد.و اما پارامتر اخر :  خب این پارامتر دستوری هستش که میخوایم ربات انجام بده مثلا میخوایم کامند help/ رو بفرستیم بهش یا start/ یا هر چیزی که اون ربات به عنوان ورودی قبول میکنه از شما. در این مثال ما  start رو فرستادیم.خب یکم ممکنه پیچیده باشه ولی گفتم که یه دیدی داشته باشید به raw متود ها چون خیلی جاها میتونید استفاده کنید و نتیجه بهینه تری رو بدست بیارید....بعد از اینکه raw فانکشن مون رو ساختیم  باید بیایم  با استفاده از متود invoke(ورژن های قبلی send)  ارسالش کنیم به تلگرام( فقط برای raw متود ها از این متود استفاده میشه):از ورژن 2.0 اسم این متود به invoke تغیر پیدا کرد.client.invoke(........)خود این  متود invoke چند پارامتر رو به عنوان ورودی میگیره :data(RawFunction)retries(int)timeout(float)sleep_threshold(float)اولین پارامتر همین raw فانکشن مون هستش که ساختیم دومین پارامتر هم تعداد تلاش هایی مجدد هستش یعنی چی؟ خب مثلا ما میخوایم اگر دفعه اول به هر دلیلی ارسال نشد ریسپانسی(جوابی) دریافت نکردیم بیاد دوباره ارسال کنه یه عدد رو به عنوان ورودی میدیم بهش،  پارامتر سوم هم از اسمش معلومه !! یه زمانی رو صبر میکنه اگر جوابی دریافت نکرد تایم اوت میده و پارامتر اخر هم برای این هستش که مثلا بگیم n ثانیه صبر کن بعد ارسال کند.خب موارد لازم رو گفتیم الان برمیگردیم به کدمون . الان اومدیم پیام start رو فرستادیم به ربات و این پیامی که فرستادیم یه ریسپانسی برمیگردونه که داخلش id این پیامی که الان ارسال شده هستش و ما این رو نیاز داریم یکم دیگه میگم چرا...حالا ما این پیامی که فرستادیم به ربات SpamBot یه جوابی هم باید داشته باشه!! پس باید بیایم اون جوابی که SpamBot بهمون میده رو بگیریم تا بفهمیم اکانت محدودیتی داره یا نه...  برای اینکار 2 تا راه دارید اول اینکه بیاید یه هندلر مثل قبل  بسازید و فیلتر کنید مثلا یوزر SpamBot  رو و پیامی که میده رو دریافت کنید راه دوم هم این هستش که از متود get_messages استفاده کنیم و بیایم دقیقا اون پیامی که ربات داده رو بگیریم الان ما میام از همین مورد دوم استفاده میکینم.Get Statusخب ببینید اینجا اول اومدیم یه چت اکشن ارسال کردیم مثل قبل و بعد اومدیم 1 ثانیه اسلیپ دادیم این اسلیپ برای این هستش که وقتی شما پیام رو میدید و ربات بهتون پیامی رو میده یکم طول میکشه این 1 ثانیه برای همین هستش که صبر کنه  تا ربات جواب رو بده بعد بیایم get_messages بکنیم و اون پیامی که ربات فرستاده رو بگیریم.در ادمه یه متغیر به اسم  spambot_msg ساختیم که در واقع اومدیم id مسیجی که فرستادیم به اسپم بات رو + 1 کردیم درواقع ایدی پیامی هستش که قرار اسپم بات برامون بفرسته(داخل تلگرام هر پیامی که میفرستید یه ایدی عددی داره که هربار یکی بهش اضافه میشه حالا چه داخل کانال چه داخل گروه چه پرایویت چت چه پیوی ربات...)‌ و بعد اومدیم از متود get_messages استفاده کردیم برای اینکه پیام رو از اون چت بگیریم در اینجا ما دو ارگمان chat_id و message_ids رو دادیم بهش میتونید لیست مسیج ایدی بدید بهش  ولی اینجا ما فقط میخوایم اون پیامی که ربات فرستاده رو بگیریم برای همین همون اون spambot_msg که ساختیم رو میدیم بهش در انتها پیامی که spambot فرستاده رو ما میفرستیم به کاربر(میتونید اینجا از متود فوروارد هم استفاده بکنید مستقیم اون پیام رو از پیوی اسپم بات فوروارد کنید یا از متود copy_message استفاده کنید که در قسمت اخر میگیم...) .خروجی ربات:Status-1در تصویر بالا همونطور که میبینید بهم گفته که اکانت برای همیشه لیمیت هستش و در تصویر زیر برای یک اکانت دیگه تست کردیم و میگه که محدودیتی نداره..Status-2خب به همین شکل میتونید لیستی از اکانت ها رو چک کنید(کار کردن با مولتی اکانت رو هم شاید یه قسمت توضیح دادیم!!) و...Show infoاپشن بعدی یه قسمت مینویسیم که به ادمین یه اطلاعاتی راجب ربات نشون بدیم :Show Infoاطلاعتی که در بالا میخوایم به ادمین نمایش بدیم شامل گروه های ربات و تعداد کاربران ربات هستش + ایدی ادمین ربات.در کد بالا اومدیم مثل همیشه هندلر مون رو نوشتیم و  کامند info رو فیلتر کردیم و بعد متغیر chat_id رو ایجاد کردیم و همچنین دو متغیر groups و private_chats  و مقدارشون رو 0 دادیم .برای اینکه بفهمیم اکانت مون داخل چند تا گروه عضو هستش یا چنتا پیوی داره... میایم از متود iter_dialogs استفاده میکنیم این متود لیست تمام چت هایی که داریم رو بر میگردونه گروه، پیوی، چنل، ربات...(همه این ها دیالوگ هستن) ولی ما اینجا میخوایم فقط گروه و پراویت چت ها رو داشت باشیم برای همین میایم میگیم تایپ این چت ها برابر سوپرگروه یا گروه عادی بود به اون متغیر groups ما  1 دونه اضافه کن و همچنین اگر تایپش پرایویت چت بود به اون متغیر private_chats ما 1 دونه اضافه کن.async for dialog in c.iter_dialogs():
    if dialog.chat.type in [&amp;quotsupergroup&amp;quot, &amp;quotgroup&amp;quot]:
        groups += 1
    if dialog.chat.type == &amp;quotprivate&amp;quot:
        private_chats += 1میتونید این dialog رو هم برای خودتون پرینت کنید قبل از نوشتن شرط و... ک ببینید چه چیزی رو  به شما برمیگردونه ( مثل اپدیت ک پرینت میکردیم) .در ادامه اومدیم پیاممون رو نوشتیم اول تعداد گروه ها  بعد تعداد کاربران و در اخر یوزر ادمین رو هم mention کردیم .برای mention کردن یک یوزر شما یا میتونید از html style یا markdown style استفاده کنید در این لینک  میتونید توضیحات کامل و مثال هاش رو ببینید .خروجی این قسمت :info-output  در اینجا میتونید بهش اپشن های دیگه یا رو هم  اضافه کنید  مثلا کاربران امروز رو بهتون بده یعنی امار امروزش جدا باشه از بقیه روز ها و مواردی مثل این....یه مورد دیگه هم هستش اونم اینه که ما اینجا فقط پیوی های اون اکانتمون رو ست کردیم برای تعداد کاربران ولی این میتونه درست نباشه برای اینکه دقیق تر باشیم در قسمت بعدی میایم اون پیام هایی که ذخیره کردیم رو به کاربرانی که میان پیوی ربات میفرستیم و همونجا هم داخل دیتابیس اطلاعات اون یوزر ها رو ذخیره میکنیم و بعد اینجا تعداد رو از دیتابیس میگیرم و  اینجوری بهتر هستش و امار پیوی های دقیق تری رو خواهیم داشت.خب تا همینجا برای این قسمت کافی هستش در قسمت بعدی اپشن های دیگه رو هم بهش اضافه میکنیم .اگر نظری انتقادی پیشنهادی چیزی داشتید میتونید کامنت بزارید✍️کد هایی که نوشتیم رو هم در لینک زیر میتونید مشاهد کنید :‌ https://github.com/zankoAn/Pyrogram-Bolg-Project قسمت اول اموزش رباتقسمت دوم اموزش رباتقسمت چهارم اموزش ربات&amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;br/&amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;</description>
                <category>;...z@nko!#</category>
                <author>;...z@nko!#</author>
                <pubDate>Fri, 12 Mar 2021 17:53:39 +0330</pubDate>
            </item>
                    <item>
                <title>نوشتن ربات CLI تلگرام با زبان PYTHON و با لایبرری pyrogram قسمت دوم</title>
                <link>https://virgool.io/@zankoAn/pyrogram-client-bot-ep-2-ohgfjqgffvim</link>
                <description>pyrogramاخرین اپدیت : Pyrogram version &gt;= 2.0خب  دوستان تو قسمت اول یک سری پیشنیاز ها و یه info کلی راجب پایروگرام رو گرفتیم، در این قسمت و قسمت های بعد میخوایم ربات اصلیمون که تو قسمت اول بهش اشاره کردیم رو بنویسیم.تو این چند قسمت از دیتابیس redis استفاده میکنیم،  شما میتونید از دیتابیس های دیگه هم استفاده کنید یا داخل فایل بنویسید یا متغیر تعریف کنید و...) ولی در کل بهتر الان دیتابیس رو   یاد بگیرید چون بعدا هم باز به دیتابیس نیاز پیدا میکنید . نکته: کد هایی که مینویسیم رو هم میتونید از گیت هاب بردارید لینکش رو آخر هر قسمت گذاشتم.نکته: تو  این قسمت  از async هم استفاده میکنیم و در ادامه هم  باز استفاده خواهیم کرد پیشنهاد میکنم یاد بگیرید و یه درکی ازش پیدا کنید.Step-1: Send messagemessageخب در کد بالا ما اومدیم فقط پرایویت چت(پی وی) رو فیلتر کردیم یعنی هر اپدیتی از سمت پیوی بیاد این ربات اون رو دریافت میکنه. در ادامه داخل فانکشن اومدیم پیام سلام رو به کاربر ارسال کردیم.نکته:  در کد بالا اومدیم هندلر مون رو asynchronous کردیم با گذاشتن async قبل def و بعدا متود هایی که صدا میزنیم رو هم await میکنیم و اینکه پایروگرام به صورت پیش فرض خودش به صورت concurrent هستش.تو کد بالا ما از دوتا متود جدید استفاده کردیم به اسم reply و send_message، تو پایروگرام برای اینکه یه پیام text رو به کاربر بفرستیم از این دوتا متود میتونیم استفاده کنیم، هرکدوم از این متود ها یه سری پارامتر میگیرن که میتونیم بدیم بهشون مثلا اینجا متود reply یکی از مهم ترین پارامتر هاش اون هم متنی هستش که قرار به کاربر بفرستیم، دقت کنید این متود رو ما باید روی خود ابجکت message صدا بزنیم یعنی client.reply_message بهمون ارور میده چون متود این ابجکت نیستش پس باید روی ابجکت message صداش بزنیم.مورد بعدی  متود send_message هستش، این متود پارامتر های زیادی رو میگیره ولی مهم ترینش chat_id و text هستش اولین مورد chat_idهستش، هر اکانت، چنل، گروه و ربات تلگرامی یه ایدی عددی منحصر به فرد داره که ما میتونیم از این ایدی عددی برای تعامل با اون کاربر استفاده کنیم، اینجا ما با chat_id یا username میتونیم مشخص میکنیم که به چه کسی پیام ارسال بشه و بعد متنی که قرار ارسال بشه رو هم مشخص کردیم، یه سری پارامتر دیگه هم میگیره این متود که اون ها اختیاری هستن میتونید ست بکنید یا ست نکنید.پارامتر های دیگه متود send_message و reply رو میتونید توی این لینک ها ببینید.نکته: با استفاده از id عددی فقط به افرادی که قبلا باهاشون تعامل داشتید میتونید پیام ارسال کنید. مثلا تو یه گروه با هم باشن، هم دیگه رو دیده باشن یا قبلا بهم دیگه پیام داده باشن و.. اینا میشه تعامل داشتن با اون id، اگر این تعامل وجود نداشته باشه بهتون ارور  PEER_ID_INVALID  رو میده یعنی شما با کاربر قبلا تعاملی نداشتید این نکته مهمی هستش که بهش برخورد میکنید.Step-2 : Admin Panel یه قسمت میخوایم بزاریم برای ربات که بتونیم یه سری جمله رو اضافه و حذف بکنیم و همچنین جمله های موجود رو نمایش بدیم،  وقتی کسی بهش پیام داد بیاد از این جمله های ست شده براشون بفرسته ، برای اینکار از دیتابیس Redis استفاده میکنم شما میتونید از دیتابیس های دیگه هم استفاده کنید یا داخل فایل بنویسیدو...     Step-2-1: Smart Pluginsقبل از قسمت ادمین پنل میخوام راجب اسمارت پلاگین براتون بگم چون قرار ازش استفاده کنیم.پایروگرام این قابلیت رو به شما میده که هندلر  هاتون رو داخل فایل های مختلف قرار بدید مثلا اینجا ما میایم قسمت مربوط به ادمین رو داخل یه فایل جدا میزاریم که کد تمیز تر باشه و توسعش هم راحت تر باشه.  برای اینکه از اسمارت پلاگین استفاده کنید میتونید داخل فایل اصلی به این شکل بنویسید(یه فایل به اسم main.py ایجاد کنید و با یکی از دو روش زیر پلاگین رو بهش معرفی کنید): smart_pluginخب بعدش شما باید یک دایرکتوری به اسم plugins ایجاد کنید کنار فایل اصلیتون و داخل این دایرکتوری پلاگین هاتون رو قرار میدید ( دیگه نیازی ندارید که تو کد اصلی چیزی رو ایمپورت کنید و...)اگر خواستید بیشتر بخونید راجبش و.. میتونید اینجا رو ببینید.خب در مرحله بعدی میایم دیتابیس رو وصل میکنیم به ربات و کم کم میریم جلو برای اینکا میتونید یه فایل __init__.pyداخل فولدر plugins ایجاد کنید و داخل این فایل مثلا ایدی ادمین و اینستنسی که از کلاس دیتابیستون میسازید رو قرار بدید:__init__.py الان در کد بالا اومدیم ردیس رو ایمپورت کردیم و بعد بهش کانکت شدیم(رو سیستم تون سرویس redis server رو باید start کرده باشید که اینجا بتونید بهش کانکت بشید دیفالت پورتش 6379 هستش البته اگه تغیر نداده باشید، برای قسمت host هم الان رو سیستم لوکال هستش برای همین میتونید بنویسید localhost و مقدار db هم شماره دیتابیس هستش ، داخل ردیس اسم نمیزارید برای دیتابیس تون و از شماره استفاده میکنید از 0 تا 15 میتونید عدد بدید که دیفالت 0 هستش البته کانفیگش رو میشه تغیر داد داد و تعداد بیشتری ایجاد کرد) یه اینستنس از کلاس redis.StrictRedis  به اسم query  ساختیم که از این به بعد به وصیله اون کوری میزنیم و دیتا هامون رو میگیریم و...و همچنین ایدی ادمین رو هم قرار دادیم الان کافیه هر جا که نیاز داشتیم query  و admin رو ایمپورت کنیم .Step-3 : Help Messagefrom pyrogram import Client, filters
from pyrogram.enums.ChatAction import TYPING
from plugins import query, admin

@Client.on_message(filters.private &amp; filters.user(admin) &amp; filters.command(&amp;quothelp&amp;quot))
async def help_message(client, message):
    chat_id = message.chat.id
    help_message = &amp;quot&amp;quot&amp;quot⚡️ **اپشن های موجود** ⚡️ 
       \n☔️ اضافه کردن پیام به ربات با کامند     /add_msg
        \n☔️ حذف کردن پیام از ربات با کامند       /del_msg
        \n☔️ نمایش جمسملات موجود با کامند       /show_msg
         \n☔️ نمایش وضعیت ربات     /info
         \n☔️ چک کردن وضعیت ربات با کامند      /status
         \n☔️ فوروارد کردن پیام       /forward
         \b☔️ جوین شدن داخل گروه مورد نظر     /join_chat
         \n☔️ ست کردن پیام بعد از جوین شدن ربات در گروه       /join_msg
         \n.
    &amp;quot&amp;quot&amp;quot
    await client.send_chat_action(chat_id=chat_id, action=TYPING)
    await message.reply(text=help_message)خب بیاید ببینم در کد بالا دقیقا چیکار کردیم ..اول اومدیم یه فایل به اسم admin_pannel.py تو دایرکتوری پلاگین مون ایجاد کردیم و  اولین هندلر مون رو برای پنل ادمین  نوشتیم  .@Client.on_message(filters.private &amp; filters.user(admin) &amp; filters.command(&amp;quothelp&amp;quot))
def help_message(client, message):خب در کد بالا اومدیم از چند تا فیلتر استفاده کردیم اگه بخواید از چند تا فیلتر تو هندلر تون استفاده کنید میتونید از علامت &amp;  برای and  وعلامت  | (پایپ) برای or  استفاده کنید و اگر بخواید فیلتری رو not کنید یعنی بگید اگر این فیلتر نبود بیا یه کاری رو انجام بده  باید از علامت ~ به همراه &amp; یا پایپ ( | )  استفاده کنید(اگه وسط دوتا فیلتر استفاده میکنید در غیر اینصورت همون ~ کافیه).در مثال بالا گفتیم اگر   فیلتر private  و فیلتر user  و فیلتر command  برقرار بود یعنی شرط هایی که تایین کردیم اوکی بود  بیا داخل فانکشن  help_message  و با استفاده از متود send_message اون  help_message ما رو به کاربر بفرست.در اینجا قبل از فرستادن پیام اومدیم از متود send_chat_action استفاده کردیم، حتما دیدید که وقتی کسی پیامی  مینویسه اون بالا تلگرام میزنه is typing... خب این همون chat action هستش و ما الان چت اکشن تایپینگ رو ارسال میکنیم به کاربر(برای مشخص شدن اینکه که چه نوع اکشی فرستاد بشه  اومدیم دومین خط import کریدمش). لیست بقیه چت اکشن ها رو اینجا بببینید.نکته:  در کد بالا برای  help_message اومدیم جلوی اموجی ☔️ یه n\ قرار دادیم اگر این n\ رو بیاید انتهای جمله قرار بدید باعث میشه اون Tab  هایی که داخل کد زدید هم در تلگرام ارسال بشن برای همین ما اومدیم اول خط نوشتیم(برای پیام های چند خطی به این شکل عمل کنید). نکته: زمانی که از اسمارت پلاگین استفاده میکنید نیازی به ساختن دوباره اینستنس Client داخل پلاگین ها نیست و همون اینستنس اولیه که داخل main.py ساختیم کافیه و در اینجا فقط ایمپورت میکنیم.در نهایت این چیزی که تا الان نوشتیم همچین خروجیی رو داره:admin panel tmStep-5 : Add Message@Client.on_message(filters.private &amp; filters.user(admin) &amp; filters.command(&amp;quotadd_msg&amp;quot))
async def add_msg(client, message):
    chat_id = message.chat.id
    messages = &amp;quot&amp;quot&amp;quot⚡️ **اضافه کردن پیام** ⚡️
        \nلطفا جمله یا جملات خود را ارسال کنید و در انتها کامند زیر را ارسال کنید:
        \n/save
    &amp;quot&amp;quot&amp;quot
    await client.send_chat_action(chat_id=chat_id, action=TYPING)
    await message.reply(text=messages)

    query.setbit(&amp;quotadd:msg&amp;quot, 0, 1)خب در کد بالا اومدیم تابع مربوط به اضافه کردن جمله به ربات رو ایجاد کردیم مثل قبل فیلتر ها رو نوشتیم و پیامی رو هم برای کاربر ارسال کردیم  الان به کاربر گفتیم جملش رو بفرسته و در اخر save/ رو بفرسته چون میخوایم اگر چند تا پیام جدا هم فرستاد  ذخیره کنیم.ولی ما اینجا چیزی رو ذخیره نمیکنیم داخل دیتابیس! پس چجوری باید ورودی بگیریم از کاربر..؟؟بزارید یکم بیشتر توضیح بدم ، ببینید زمانی که میخواید از کاربر چیزی بگیرید و بعدش ذخیرش کنید یا...  نیاز دارید که یه هندلر داشته باشید که پیام ها رو بگیر الان این  هندلر بالا فقط به کامند add_msg جواب میده و جمله هایی که کاربر میفرسته رو تو اینجا نمیتونیم بگیریم  برای همین میایم یه هندلر دیگه مینویسیم که تکست ها رو بگیره و دیگه کامندی رو فیلتر نمیکینم اینجوری تکست ها رو میگیره ولی یه مشکلی دیگه هست، این هندلری که مینویسیم برای گرفتن تکست  هر پیامی که بیاد رو میگیره خود کامند هم تکست هستش پس اون رو هم میگیره و اون رو هم اضافه میکنه به دیتابیس(در ادامه اضافه کردن رو میگیم)‌ الان قاتی میشه برای همین نیاز داریم که Step بزاریم مثلا اینجا اخرین خط استپ add:msg رو گذاشتم 1 (داخل دیتابیس برای کلید add:msg مقدار 1 رو ست کردیم) بعدا تو هندلر تکستی که مینویسیم برای گرفتن جمله ها میایم چک میکنیم ببینم stepما چی هستش اگر add:msg برابر 1 اون زمان یعنی، پیام کاربر جمله هایی بوده که قرار اضافه بشه و اضافه میکنیم .اگه بخواید اینجا فقط برای کاربری که الان پیام داده step گذاری کنید در واقع وقتی چند کاربر استفاده میکنن از ربات، ربات قاتی نکنه بینشون اینجا باید بیام و چت ایدی رو هم ذخیره بکنیم همراه با step یعنی :   query.setbit(f&amp;quotadd:msg:{chat_id}&amp;quot, 0, 1)الان با استفاده از فرمت استرینگ این چت ایدی رو هم دادیم بهش و فقط برای این یوزر استپ add:msg برابر 1 میشه در نتیجه موقع چک کردن هم برای همون یوزر چک میکنیم به این شکل میتونید یوزر هاتون رو جدا کنید یعنی قاتی نکنه ربات. این نکته مهم بود که بعدا بهش برمیخورید.نکته : برای step گذاری میتونید از دیتابیس یا متغیر گلوبال یا لایبرری pyromod استفاده کنید.در زیر یه آموزش برای کار کردن با لایبرری pyromod قرار دادم که میتونید ببینید: https://vrgl.ir/OwEiB خروجی چیزی که نوشتیم:Add msg tm  Step-6 : Get User Inputخب برای دریافت ورودی به یه هندلر دیگه نیازی داریم که داخلش پیام رو ذخیره کنیم:@Client.on_message(filters.private &amp; filters.user(admin), group=1)
async def get_input(client, message):
    msg = message.text

    if query.getbit(&amp;quotadd:msg&amp;quot, 0) == 1 and msg and not msg.startswith(&amp;quot/&amp;quot):
        msg_counter = query.incr(&amp;quotNew:Msg&amp;quot)
        query.sadd(&amp;quotMessages&amp;quot, f&amp;quot{msg_counter}:{msg}&amp;quot)

    elif msg == &amp;quot/save&amp;quot:
        chat_id = message.chat.id
        await client.send_chat_action(chat_id=chat_id, action=TYPING)
        await message.reply(text=&amp;quot&amp;quot&amp;quot⚡️ **اضافه کردن پیام** ⚡️
            \n✅ جمله های شما با موفقیت ذخیره شد
            \n.&amp;quot&amp;quot&amp;quot)

        query.setbit(&amp;quotadd:msg&amp;quot, 0, 0)خب در کد بالا اومدیم مثل قبل هندلر مون رو تعریف کردیم و بعد داخل تابع اومدیم چک کردیم ببینیم اون مقدار add:msg برابر 1 هستش یا نه اگر 1 بود و همچنین با / شروع نشده بود پیام کاربر(درواقع اگه  کامند نبود) بیا وارد شرط ما بشه.نکته: دقت کنید اینجا چون اون کامند ها معنی کامند رو نمیدن یعنی همه چی تکست هستش اگه شرط نزاریم و چک نکنیم که با / شروع شده یا نه اگه کامند باشه متن کاربر اون رو هم به عنوان جمله اضافه میکنه به دیتابیس پس برای همین مثلا اینجا اون شرط رو علاوه بر چک کردن مقدا add:msg نوشتیم.در اینجا اول اومدیم گفتیم اگر شرطمون برقرار بود بیا یه msg_counter ایجاد کنه برای اینکار ما اومدیم از متود incr ردیس استفاده کریدم، این متود به این شکل هستش که هر زمان صداش بزنید یه شمارنده براتون اضافه میکنه مثلا الان صداش زدیم مقدار New:Msg داخل دیتابیس 1 میشه، دفعه بعدی میشه 2 دفعه بعد 3 و الا اخر... خب ما از این new:msg  زمانی که میخوای پیام رو حذف کنیم استفاده میکنیم، بعد اومدیم گفتیم بیا این پیامی که کاربر میفرسته رو به دیتابیس اضافه کن این کانتر رو هم بزار اول اون پیام کاربر الان دیتا اینشکلی ذخیره شده داخل دیتابیس:DBشما میتونید داخل ipython یا شل پایتون و... اینکشلی به دیتابیس ردیس متصل بشید و query بزنید و باهاش کار کنید(البته دیتابیس های دیگه رو هم میتونید!)خب میتونید ببینید که جمله های ما اینشکلی به دیتابیس اضافه شدن، اون msg_counter  که تعریف کردیم رو هم دارن که بعدا استفاده میکنیم.نکته: داخل ردیس میتونید با استفاده از متود sadd  اون مقادیر رو برای اون کلیدی که میگید داخل یک set  ذخیره کنید که الان اینجا کلیدمون Messages هستش و پیام کاربر رو ذخیره میکنیم داخلش این متود اینجا مفید هستش چون دیگه خیالمون راحت میشه که جمله تکراری وارد دیتابیس نمیشه وگرنه میتونستید از متود های rpush یا lpush هم استفاده کنید..اگر راجب متود sadd خواستید بیشتر بدونید متونید اینجا رو نگاه کنید.در ادامه یه شرط نوشتیم که  اگر پیام برابر بود با save/ بیاد اون مقدار add:msg داخل دیتابیس رو برابر 0 بکنه و درواقع اون step رو قفل میکنه و دیگه شرط اول برقرار نمیشه، قبلا گفتیم شاید کاربر خواست چند تا پیام بفرسته اینجا هرچند تا بفرسته ذخیره میشه تهش save/ رو فرستاد دیگه ذخیره نمیشه، تهش یه پیامم به کاربر دادیم که جمله هاش ذخیره شد.داخل ترمینال هم همونطور که میبینید پرینتی که انجام دادیم اعمال شده و دقیقا اون پیام های test-0 تا 3 رو به دیتابیس اضافه کرده.Step-6-2: Group@Client.on_message(filters.private &amp; filters.user(admin), group=1)اگر دقت کنید در کد بالا  همچین هندلری نوشتیم اینجا ما یه مقدار جدید داریم و اون هم group هستش ،      در پایروگرام اگه مثلا شما  چند تا هندلر مثل هم داشته باشید موقع اجرا بقیه هندلر ها نادیده گرفته میشن و فقط هندلر اول اجرا میشه مثلا اینجا ما درسته فعلا هندلر مشابه نداریم ولی در اینده خواهیم داشت چون چندین بار میایم از کاربر ورودی میگیرم و هندلر ها هم یک فیلتر یکسانی رو دارن و مشابه هم هستن پس برای همین group رو مشخص میکنیم  این group یه مقداری رو میگیره که اولویت اون هندلر رو مشخص میکنه هرچی عددش پایین تر باشه اولویت اجرا شدنش بیشتر یعنی اول اون اجرا میشه هرچی عدد بالاتر باشه یعنی اولویت کمتری داره .نکته: در اینجا شما میتونید به جای ذخیره پیام id پیام رو ذخیره کنید اینجوری در زمان ارسال این جمله ها میتونید عکس با کپشن یا فیلم یا اهنگ و... رو بفرستید چون شما id اون پیام رو ذخیره کردید نه متنش رو پس زمان ارسال هم میتونید بهش بگید که بیا این message  رو ارسال کن.خروجی چیزی که نوشتیم تا الان:pyrogram-input-messageStep-7 : Show Messages@Client.on_message(filters.private &amp; filters.user(admin) &amp; filters.command(&amp;quotshow_msg&amp;quot))
async def show_msg(client, message):
    chat_id = message.chat.id
    await client.send_chat_action(chat_id=chat_id, action=TYPING)

    if query.exists(&amp;quotMessages&amp;quot):
        messages = &amp;quot⚡️ **نمایش جمله ها** ⚡️\n&amp;quot
        data = sorted(query.smembers(&amp;quotMessages&amp;quot), key=lambda x: x.split(&amp;quot:&amp;quot)[0])
        for item in data:
            item = item.split(&amp;quot:&amp;quot, 1)
            separator = &amp;quot➖&amp;quot * 12
            messages += f&amp;quot`{item[0]}`:{item[1]}\n{separator}\n&amp;quot
        await message.reply(text=messages)
    else:
        await message.reply(text=&amp;quot❌جمله ای یافت نشد❌&amp;quot)خب در کد بالا ما مثل قبل یه هندلر نوشتیم و فیلتر کردیم کامند show_msg رو، بعد اومدیم یه چت اکشن تایپینگ فرستادیم و در ادامه چک کردیم اگر اون کلید messages داخل دیتابیس وجود داشت بیاد اون مسیج/مسیج ها رو به کاربر نشون بده در غیر این صورت بیاد بهش بگه جمله ای یافت نشد.برای اینکه پیامی که به کاربر میفرستیم هم یکم تمیز تر باشه این قسمت for رو اضافه نوشتیم:اول اومدیم یه متغیر تعریف کردیم که در اخر همه جمله های داخل دیتابیس رو با هم بفرستیم و بعد اومدیم از متود smembers ردیس برای گرفتن تمام ولیو های اون کلیدمون استفاده کردیم ولی اینجا مقادیری که بهمون میده چون داخل set هستش ترتیب خاصی ندارن و نمایششون به اون شکل یکم زشت هست پس میایم با متود sorted مرتبشون میکنیم .اینجا داخل sorted کلید رو برابر اون عدد مربوط به هر پیام قرار دادیم تا با توجه به اون عدد ها سورت رو انجام بده و بعد حلقه زدیم روش،   در ادامه داخل حلقه اومدیم هر پیام رو با : برای گرفتن اون عدد اسپلیت کردیم و بعد برای اینکه قشنگ تر بشه هر پیام رو با 12 تا ➖ جدا کردیم در ادامه اومدیم اینا رو به متغیر مون که بالا تعریف کردیم اضافه کریم. اینجا از backtick برای مونو اسپیس کردن اون تکست استفاده کردیم راجب تکست فرمتینگ میتونید این لینک رو مطالعه کنید.در نهایت همچین خروجیمون اینشکلیه:show-msg نکته: در هندلر بالاتر اومدیم group رو مشخص کردیم اگر این کار رو انجام نمیدادیم  اصلا به این هندلری که الان نوشتیم نمیرسید و اجرا نمیشد چون show_msg هم باز تکست هستش اونجا این رو میگرفت و دیگه وارد هندلر دوم نمیشد تو همون هندلر بالاتر میموند مگر اینکه این هندلر رو بالاتر از اون هندلر قبل بنویسید اینجوری اول این اجرا میشد بعد اون هندلر به این شکل هم میشد ولی ست کردن group بهتر هستش.خب تا اینجا به نظرم برای این قسمت کافی هستش در قسمت بعدی ادامه این کد ها رو میریم جلو و اپشن های دیگه رو هم بهش اضافه میکنیم یه جا هایی رو ادیت میکنیم چون یه مشکلاتی هنوز هست که در قسمت بعدی بهش می پردازیم .اگر نظری انتقادی پیشنهادی چیزی داشتید میتونید کامنت بزارید✍️میتویند سورس کدی که نوشتیم رو هم در این لینک مشاهد کنید :‌ https://github.com/zankoAn/Pyrogram-Bolg-Project قسمت سوم: https://vrgl.ir/ZMRBE </description>
                <category>;...z@nko!#</category>
                <author>;...z@nko!#</author>
                <pubDate>Thu, 04 Mar 2021 18:27:08 +0330</pubDate>
            </item>
                    <item>
                <title>نوشتن ربات CLI تلگرام با زبان PYTHON و با لایبرری pyrogram</title>
                <link>https://virgool.io/@zankoAn/pyrogram-client-bot-rr2yvak3gvqx</link>
                <description>program-Ep1اخرین اپدیت : Pyrogram version &gt;= 2.0 خب سلام دوستان.قرار یه اموزش پروژه محور ربات client(یوزر بات، ربات cli ....)‌ رو با هم باشیم اول کار تو این قسمت راجب یه سری مفاهیم پایه ای حرفه میزنیم و یه info کلی میدیم و در قسمت های بعد میایم ربات مون رو کم کم مینویسیم و کاملش میکنیم، تو این سری قرار نیست بیایم تمام متود های موجود و.. رو توضیح بدیم صرفا مواردی که مربوط به پروژه هستن رو توضیح میدیم و میریم جلو.در اخر هر پست لینک گیت هاب پروژه قرار داده شده که میتونید برید و کد هایی که نوشتیم رو ببینید.در کل میخوایم یک ربات بنویسیم که این قابلیت ها رو داشته باشه :نمایش، حذف و اضافه کردن جمله به ربات.فوروارد کردن پیام به یوزر های ربات.جوین دادن داخل لینک های پرایویت و پابلیک و ارسال پیام...چک کردن وضعیت ریپورتی,... اکانت یا اکانت ها.گرفتن اطلاعات اکانت.نحوه استفاده کردن از هندلر ها،  raw متود ها ، step گذاری، متود های عادی و هندل کردن ارور های احتمالی و .. رو در این دوره با هم یاد میگیریم.نکته: داکیومنت این لایبرری خیلی ساده و مناسب هستش میتونید مواردی که نیاز دارید رو داخل داکیومنت سرچ کنید و بخونیدش، توضیحات کامله و مثال های واضحی هم قرار داده شده . https://docs.pyrogram.org/ نکته: در قسمت های بعدی برای قسمت step گذاری و... از دیتابیس استفاده میشه ولی میتویند از لایبرری pyromod هم استفاده بکنید، که تو لینک زیر آموزش استفادش رو گذاشتم. https://vrgl.ir/OwEiB Step-1: Api-id &amp;&amp; Api-hashاولین کاری که برای ساخت ربات client یا api در پروتکل mtproto باید انجام بدیم گرفتن api-id و  api-hash  هستش(میتونید از یک  api-id و api-hash برای هرچند تا اکانت که نیاز دارید استفاده کنید ولی اگر با اکانت زیاد کار میکنید پیشنهاد نمیشه چون ممکنه تلگرام تشخصی بده و...) خب چنتا راه دارید برای گرفتنش:میتونید برید از این ربات دریافت کنید .میتونید از  این کانال  بردارید.یا اینکه از سایت خود تلگرام  به شکل زیر دریافت کنید : اول وارد سایت telegram  میشید، بعد شماره تلفن تون رو وارد میکنید next رو میزنید و کدی برای شما راسال میشه رو وارد میکنید و sing in رو میزنید، در مرحله بعد  یه فرم میاره برای شما که باید کاملش کنید، بعد از کامل کردنش( همینجوری پرش کنید هم زیاد مهم نیست) در آخر به شما یه api_id و یه api_hash میده(اگه از سایت تلگرام میگیرید، این روزا درست نمیده و Error میده، پس کشور تون رو تغیر بدید تا بلکه بتونید بگیرید ازش!) .api-id and api-hashخب چرا ما  از api-id و api-hash استفاده بکنیم!! اصلا برای چی هستن؟؟  خب باید بگم ما  داریم با لایبرری پایروگرام کار میکنیم که با استفاده از پروتکل Mtproto به تلگرام وصل میشه و  در این پروتکل ما باید از api-id و api-hash استفاده کنیم و بدونه این نمیتونیم وصل بشیم  به سرورای تلگرام.به صورت کلی برای تایید هویت application خودمون باید از api-id و api-hash استفاده کنیمHTTP --------   HTTP/MTProto  --------MTProto[You] &lt;------------&gt; [Bot API] &lt;--------------&gt; [Telegram] MTProto --------------------------------MTProto[Pyrogram] &lt;-------------------------------------&gt; [Telegram]Step-2: Installationخب بریم مواردی که نیاز داریم رو نصب کنیم:pip install pyrogram
pip install tgcryptoاگه از لینوکس استفاده میکنید pip3 رو بزنید که برای پایتون 3 نصب بشه (البته اگه اپدیت باشید دیفالت پایتون 3 هستش و همون pip خالی اوکیه) این tgcrypto که بالاتر نصب کردیم برای این هستش که کارایی و سرعت pyrogram بیشتر بشه، البته اختیاری هستش اگه ست نکنید از PyAES استفاده میکنه که کند تر هستش به نسبت... اگه خواستید در مورد tgcrypto  بیشتر بدونید به این لینک مراجعه کنید.اگه رو ویندوز هستید ممکن مشکلاتی برای شما پیش بیاد چون این tgcrypto یه سری دیپندنسی داره که باید از قبل نصب شده باشه  مثلا رو ویندوز باید Visual C++ 2015 Build Toolsنصب باشه   و رو لینوکس یه کامپایلر برای c مثل gcc و همچنین python-dev باید نصب باشه که در لینوکس به صورت پیش فرض اوکیه ، اگر هم نبود!!  خب  با پیکج منیجرتون نصبش کنید :) خب دیگه پیش نیاز ها رو نصب کردیم و الان وقت کد زدن هستش... ( یه فیلتر شکن یا پروکسی socks5 هم نیاز دارید اگه تلگرام فیلتر یا تحریم هستش تو کشور شما)نکته:  اگر نتونستید وصل بشید و ارور Unable to connect due to network issues: timed outرو دریافت کردید این مربوط به فیلتر شکن(یا نتورک شما ) شما هستش که نتونسته کانکت بشه به تلگرام،  بعضی فیلتر شکن ها ممکنه کار نکنن، علیرغم اینکه شما میتونید به تلگرام رو سیستم تون وصل بشید و اوکی هستش شاید اینجا این ارور بالا رو بگیرید ونتونید وصل بشید پس اگر همچین اروری گرفتید میتونید فیلتر شکن دیگه ای رو تست کنید.Step-3: Client Paramsfrom pyrogram import Client
bot = Client(.....)در کد بالا Client رو ایمپورت کردیم، هر رباتی که بنویسید نیاز دارید که Client رو ایمپورت کنید برای اینکه به تلگرام وصل بشید و قسمت تعامل شما با تلگرام رو هندل کنه( مثل این هستش که تلگرام رو باز کرده باشید ) خب الان یه اینستنس از کلاس Client ساختیم به اسم bot و خب الان ما به جای .... باید چی بزاریم؟؟کلاس کلاینت پارامتر های مختلفی رو میگیره، مهم ترین هاش که حالا بیشتر استفاده میکنیم رو میگم بقیش رو هم میتونید از داکیومنتش ببینید...* name(str)خب اولین مورد که مهم هستش اسم سشن تون هست سشن چیه؟ خب وقتی شما به تلگرام وصل میشید یه فایل سشن در سیستم شما ایجاد میشه که دفعات بعدی خواستید کانکت بشید دیگه از شما رمز و پسورد نخواد البته اطلاعات بیشتری از اکانتتون هم داخلش ذخیره میشه برای همین دفعات بعدی نیازی نیست لاگین کنید... اگه نمیخواید سشن روی هارد شما ذخیره بشه، میتونید داخل مموری هم این سشن رو ایجاد کنید ولی بعد از دیزکانکت شدن شما یعنی وقتی پروسس مربوط به اسکریپتتون kill یا break بشه دیگه اون سشن از مموری پاک میشه و بهش دست رسی ندارید، البته میتونید قبل از اینکه break یا kill بشه از دستور bot.export_session_string()استفاده کنید و سشن استرینگ فعلی رو بدست بیارید بعدا دیگه نیاز نیست هربار اکسپورت کنید همین چیزی  که بهتون میده رو بعدا میتونید ست کنید و ازش استفاده کنید یه همچین چیزی باید بهتون نشون بدهBAB-zAc9wtZY1SFBY5S-6AiSMyeJ6aLbIQT7JNpf9QOQwQ0W8GP0Fse..............پس شد دو حالت یا داخل فایل ذخیره میشه که باید سشن نیم یه رشته استرینگ به عنوان اسم فایل بدیم بهش مثلا x یا y(بیشتر میایم اسم سشن رو برابر شماره تلفنی که وارد کردیم قرار میدیم که دیتکتش راحت تر باشه) یا اینکه بیایم اینجوری داخل مموری ذخیرش کنیم که باید بیایم از پارامتر in_memory استفاده کنیم .( این حالت دوم که داخل مموری ذخیره میشه رو هم بهش میگن سشن استرینگ)* in_memory(bool)برای اینکه از سشن استرینگ استفاده بکنیم باید این پارامتر رو هم قرار بدیم اگر true باشه از سشن استرینگ استفاده میکنه دیفالت False هستش.* session_string(str)برای اینکه از سشن استرینگ استفاده بکنیم باید سشن استرینگ مون رو با این پارامتر بدیم بهش البته name رو هم باید یه یچزی بزاریم(خالی هم باشه اوکیه)! * api_id(int) , api_hash(str)مورد بعدی هم که بالاتر توضیح دادیم باید این دو مورد رو هم ست کنید ، در ورژن v2.0 پایروگرام برای سشن هایی که از قبل ایجاد شدن لازم نیست ست بشه و بدونه این دو مورد هم کار میکنه.* proxy(dict)    --&gt;   dict(scheme=&quot;socks5&quot;, hostname=”127.0.0.0.1&quot;, port=9050, username=&quot;user&quot;, password=&quot;pass&quot;)خب پایروگرام بهتون اجازه میده که از پروکسی socks5 و httpو socks4 به شکل بالا استفاده کنید.( tor برای این مورد خیلی خوبه:)) ) اگر پروکسیی که دارید  username و پسورد نداره مثل tor اون قسمت رو ننویسید همون hostaname و port و scheme رو مشخص کنید کافیه.* bot_token(str) این مورد برای زمانی هستش که شما نمیخواید ربات client بنوییسد و صرفا میخواید ربات api بنویسید کافیه توکن رباتی که با بات فادر ساختید رو ست کنید .force_sms(bool)درمواردی که میخواید حتما تلگرام به شما code رو sms کنه با این اپشن میگید حتما sms کنه براتون.workers(int) با استفاده از این اپشن میتونید تعداد ترد های همزمانی که میخواید رو ست کنید، برای هندل کردن اپدیت هاتون که به صورت پیشفرض مقدارmin(32, os.cpu_count() + 4) در نظر گرفته شده که اگه نیاز داشتید میتونید تغیرش بدید.no_updates(bool)این مورد بعضی جاها خیلی بدرد میخوره مثلا مثلا شما یه اکانت دارید که 5000 تا کانال و گروه.. عضو هستش و شما میخواید الان از همه اونا لفت بدید اگه این رو ست نکنید خب کل اپدیت های 5000 گروه رو دریافت میکنه و واقعا حجم زیادی داره ، هندل نمیشه و مشکلتون زیاد میشه ولی اگه ست کنید این رو دیگه اپدیتی دریافت نمیشه و خیلی راحت و سریع میتونید کاری که میخواید رو انجام بدید (البته که اپدیت رو نمیتونید بگیرید ولی بقی مواردی که نیازی به اپدیت ندارن و حجم اپدیت شما خیلی زیاد هستش این اپشن خیلی مفید هستش)( یه نکته دیگه اینکه اپدیت رو درسته نمیتونید بگیرید ولی get_history,... رو میتونید بگیرید که بعدا مثال هایی خواهیم زد)Step-4 : Simple Botfrom pyrogram import Client, filters

bot = Client(
    name=&amp;quotnew-client-bot&amp;quot,
    apit_id=your_api_id,
    api_hash=&amp;quotyour_api_hash&amp;quot)

@bot.on_message(filters.command(&amp;quotstart&amp;quot))
async def test_bot(client, message):
    print(message)

bot.run()اول ما متود filters و Client رو ایمپورت کردیم، متود کلاینت برای کانکت شدن به تلگرام و.. استفاده میکنیم و از متود فیلتر برای فیلتر گذاشتن روی اپدیت ها استفاده میکینم ؛  همه اتفاق هایی که داخل اکانت رخ میده  اپدیت هستش مثلا وقتی که شما وارد تلگرام میشید یه سری پیام ممکن برای شما بیاد حالا از گروه ها یا pv و کانال ها... همه این پیام ها اپدیت هستن یا یه فرد پیامی رو تو گروه pin میکنه یا جوین میده و... حالا میتونه تکست باشه یا فیلم باشه عکس،اهنگ،وویس و... همه این ها رو ما میتونیم داخل اپدیت دریافت کنیم. خب الان فک کنم واضع تر شده باشه که update دقیقا چی هستش .ما میتونیم  از filters استفاده کنیم تا برای یک سری اپدیت خاص یه عملی رو انجام بده مثلا میگیم اگر کامند بود بیا  به کاربر پیام &quot;سلام&quot; بده ( کامند با / ( اسلش) شروع میشه) یا بیا  پیام خوش‌آمدگویی رو به بده و یا یه info راجب ربات به کاربر بده و...( فیلتر ها رو ما میتونیم به شکل های مختلفی بنویسیم ) میتونید با  زدن tab بقیه فیلتر ها رو هم ببینید داخل ادیتورتون(مثلا vsc)@bot.on_message(filters.در اینجا tab بزنید بهتون نشون میده(البته اگه ادیتورتون autocomplete برای پایتون داشته باشه) بعد داخل داکیومنت پایرو هم میتونید فیلتر مورد نظر رو سرچ کنید و اطلاعات بیشتری راجبش بدست بیارید(حتی میتونید از regex استفاده بکنید و قدرت مانور بیشتری داشته باشید و...)اینجا اگه دقت کنید نوشتیم on_message به این میگن هندلر، ما هندلر های مختلفی رو داریم اینجا هندلر مون روی message هستش میتونه روی چیز های مختلفی باشه مثلا on_chat_join_request که وقتی کاربری تازه میخواد وارد گروه بشه و... در ادامه بیشتر میگیم..ما میتونیم به 2 شکل هندل رو تعریف کنیم یا بیایم از متود add_handler استفاده کنیم یا اینکه از دیکوریتور  استفاده کنیم . @bot.on_message(filters.command(&#039;start&#039;))
async def test_bot(client, message):در مثال بالا اومدیم یه دیکوریتور تعریف کردیم برای هندل کردن اپدیت هایی که میاد و با on_message نوع هندلر مون رو مشخص کردیم on پایه ثابت هستش و روی یه چیزی قرار میگیره در اینجا روی message ها هستش میتویند لیست  دیکوریتور ها رو اینجا ببینید، اینجا ما یه فانکشن پایتونی زیر decorators نوشتیم که async هستش راجب async تو پایتون هم میتونید سرچ بکنید و یه آشنایی باهاش داشته باشید(در اینده بیشتر میگیم...). بعد با استفاده از filter اومدیم گفتیم فقط کامند start/ رو بگیر داخل اپدیت ها(اینجا اگه خواستید چند تا کامند رو ست کنید براش میتونید به شکل لیست تعریف کنید (اون / رو هم میتونید تغیر بدید با استفاده از ارگمان prefixes ) ) و اگر کاربری الان start/ رو بفرسته به ربات در جواب ربات چیزی که درون تابع test_bot تعریف کردیم رو انجام میده اگه چیز دیگه ای رو هم بفرسته ربات کاری انجام نمیده. خود تابع test_bot هم 2 پارامتر client و message رو دریافت میکنه اولیش کلاینت و دومی هم اپدیت.print(message)در ادامش ما اومدیم اپدیتی که دریافت کردیم رو چاپ کردیم این اپدیت رو شما اگر کد رو اجرا کردید به دقت برسیش بکنید چون بیشتر مواردی که نیاز دارید در خود این اپدیت هستش و بیشتر کار ما هم با همین اپدیت ها هستش.. فرمتش به شکل json هست اگر اشنا نیستید با این فرمت سرچ کنید تو گوگل و یکم باهاش کار کنید چون در ادامه راه بهش نیاز پیدا میکنید.تا اینجا ربات کار خاصی رو انجام نمیده یعنی اجرا نشده و به تلگرام کانکت نشده، برای اینکه کانکت بشه و دیگه رباتمون ران باشه میایم از متود run استفاده میکنیم bot.run()اینجا ما اون ابجکت bot که ساختیم رو run میکنیم و بعد از اینکه فایل پایتون مون رو اجرا بکنیم سعی میکنه با توجه به پارامتر هایی که براش ست کردیم(تو خط 2وم) به سرور تلگرام وصل بشه و بعد اگه start/ رو بفرستیم به ربات برامون اون اپدیت رو پرینت میکنه. جدا از حالت بالا میتونید از متود های connect, start, idle هم استفاده کنید.connect میاد به سرور تلگرام وصل میشه و یه مقدار true یا false رو هم برمیگردونه(فقط اپدیت رو یادتون بمونه که نمیتونیم بگیریم چون کانکت میشه و بعد دیزکانکت).startمثل قبلی هستش با این تفاوت که  مراحل لاگین کردن رو هم انجام میده بالاتر توضیح دادیم راجب سشن و این متود اگر سشن برای اولین بار ایجاد شده باشه مراحل گرفتن شماره، تایید کد و... رو انجام میده درضمن این متود مثل قبل بولین بر نمیگردونه و خود کلاینت رو استارت شدش رو برمیگردونه که میتونید ازش استفاده کنید(در ادامه ملموس تر میشه این قضیه)idleاین متود هم برای زنده نگه داشتن اون کلاینت استفاده میشه در مورارد قبل اگر اجرا کنید اون مواردی که ست کرده باشید رو انجام میده و تموم میشه میاد بیرون exit میکنه میاد بیرون دیگه منتظره نمیمونه که ایا اپدیت جدیدی قرار بیاد یا نه و...  با استفاده از این متود ما میتونیم اپدیت های جدیدی که میاد رو هم دریافت کنیم اگر از این متود استفاده کنیم باید قبلش کلاینت رو  start  کرده باشیم و بعد idle  و در انتهای کد کلاینت رو stop کرده باشیم.runاین متود شما همه متود های  start, idle, stop رو انجام دادید در واقع کار رو اسون تر میکنه برای ما فقط تنها مشکلش و نقطه تمایزش با موارد قبل این هستش که این متود به ما اجازه نمیده چندین کلاینت ایجاد کنیم و فقط 1 کلاینت رو میتونیم اجرا کنیم اگه بیشتر باشه کلا block میکنه و اجرا نمیشه.stopزمانی که نیاز دارید ربات رو متوقف کنید از این متود میتونید استفاده کنید یه پارامتر رو میگیره به اسم block و زمانی بدرد میخوره که شما داخل یه هندلر بخواید ربات رو stop کنید اگه این ارگمانش رو ست نکنید به شکل کامل stop نمیشه و یه جورایی کدی که اجرا کردید کرش میکنه و بسته نمیشه مگر اینکه پروسسش رو kill کنید( درضمن این متود stop پروسس رو kill نمیکنه و فقط ربات رو stop میکنه و دیگه ربات کاری انجام نمیده) و حتی ممکن دیتابیس sqlite که پایرو استفاده میکنه lock شه(اگه کدی که استاپ شده رو suspend کنید).خب بیایم کد بالا رو اجرا کنیم  بیبنم چه اتفاقی میفتهstart-botخب همونطور که میبینید پیام اول که به ربات دادم  start خالی بود یعنی یه تکست بود، در این حالت ربات بهش جواب نمیده ولی پیام دوم کامند start بود و ما این رو فیلتر کرده بودیم برای همین اون print ما انجام شد و update رو برامون چاپ کرد، همونطور که بالا تر گفتم فرمت اپدیت json هستش و باید کار کردن با این فورمت رو بلد باشید سخت نیست مثل دیکشنریه، مثلا اینجا میتونیم username, id زمان ارسال پیام نوع پیام و کلی چیز دیگه رو از اپدیت بگیریم  و  با توجه به نیازمون یه کارهایی رو انجام بدیم..کد هایی که نوشتیم رو هم در لینک زیر میتونید مشاهد کنید :‌ https://github.com/zankoAn/Pyrogram-Bolg-Project قسمت دوم اموزش ربات : https://vrgl.ir/6ZMwA اگر نظری انتقادی پیشنهادی چیزی داشتید میتونید کامنت بزارید✍️</description>
                <category>;...z@nko!#</category>
                <author>;...z@nko!#</author>
                <pubDate>Thu, 25 Feb 2021 17:20:35 +0330</pubDate>
            </item>
                    <item>
                <title>آموزش فایروال قدرت مند IPTABLES :) قسمت سوم</title>
                <link>https://virgool.io/@zankoAn/iptables-p3-inqpkuavdkre</link>
                <description>iptablesخب تا اینجا با iptables  و کامند هاش اشنا شدید. الان وقتشه بریم سراغ پارامتر هاش رو در اخر هم مثال های عملی و کاربردی رو با هم برسی میکنیم.نکته :  برای هر پارامتر یا کامند تو سینتکسشون یه [ ... ]  گذاشتم به این معنی هستش که میتونید بجاش یک الا چند کامند بزارید.[ PARAMETERS ]-g, --gotoاین پارامتر بر خلاف jump که پردازش در همون chain انجام میشد، میاد پردازش رو میفرسته به chain که ما مشخص میکنیم.Syntax :
    iptables  [ ... ] -g [ Chain ]
Example :
    iptables -A  INPUT  -p icmp  -g my_chainنکته  : زنجیره ای که مشخص میکنید باید توسط کاربر ایجاد شده باشد درغیر این صورت با ارور مواجه میشوید.-p, --protocol [!] protocolاز این پارامتر میتوان برای ست کردن نوع پروتکل استفاده کرد .( هم میتونید عدد مربوت به اون پروتکل رو قرار بدید هم اسمش رو ) میتونید فایل  etc/protocols/ رو هم مشاهد کنید خالی از لطف نیست.Syntax :
    iptables [ ... ] -p [ protocol ] [ ... ]
Example :
    iptables  -A  INPUT -p  icmp  -j  REJECT
    iptables  -A  INPUT ! -p  icmp  -j  REJECTنکته :‌ اگر از علمات ( ! ) قبل از  اسم پروتکل استفاده کنید باعث معکوس شدن اون چیزی که تعین کردید میشود . اگر بر روی 0 ست شود به معنای تمام پروتکل های موجود میباشد.-s, --source [!]از این پارامتر برای مشخص کردن مبدا استفاده میشود. میتوان خود ip یا که هاست نیم رو قرار داد ولی پیشنهاد نمیشه Hostname بزارید بهتر که از ip استفاده کنید. میتوان سابنت مسک را به دو شکل برای ip مشخص کرد (192.168.1.1/24  و یا 192.168.1.1/255.255.255.0). و مثل قبل علامت ( ! ) باعث not شدن اون شرط میشه یعنی معکوس میشه. مثلا وقتی مشخص میکنید اون ip باشه اگه ! بزارید یعنی اون ip نباشه.Syntax :
    iptables [ ... ] -s  [ address[/mask] ] [ ... ]
Example :
    iptables   -A INPUT  -p icmp -s 192.168.1.1  -j  DROP
    iptables   -A INPUT  -p icmp -s 192.168.1.1/24  -j  DROP
    iptables   -A INPUT  -p icmp -s 192.168.1.1/255.255.255.0   -j  DROP
    iptables   -A INPUT  -p icmp  -s hostname  -j DROP-d, --destination [!]این پارامتر دقیقا مثل source هستش با این تفاوت که اون برای مبدا بود این برای مقصد هستش .-i, --in-interface [!]میتونید با استفاده از این پارامتر اینترفیس تون رو مشخص کنید. میتونید از + در ادرس دهی استفاده کنید مثل رجکس ،  در اینجا +enp کارت شبکه ای  که اولش با enp شروع شده باشه رو ست میکنه. مثل قبل علامت ! باعث معکوس شدن این جریان میشه.Syntax :
    iptables [ ... ] [ interface ] [ ... ]
Example :
    iptables -A INPUT -i enpX  -p icmp  -j ACCEPT
    iptables -A INPUT -i enp2+  -p icmp  -j ACCEPT
    iptables -A INPUT  ! -i lo  -p icmp  -j ACCEPTنکته : از این پارامتر فقط در chain های  INPUT, FORWARD, PREROUTING استفاده میشود.-o, --out-interface [!]پارامتر out-interface هم دقیقا مثل پارامتر in-interface هستش با این تفاوت که شبکه خارجی رو مشخص میکنه(پکت هایی که از این کارت شبکه خارج میشن)‌ .نکته : از این پارامتر فقط در chain های  OUTPUT, FORWARD, POSTROUTING استفاده میشود.[!] -f, --fragmentاین پارامتر به این معنی هستش که اون rules فقط به پکت های که به 2 یا چند فریم تقسیم شدن اشاره داره .و علامت ! هم مثل همیشه معکوس میکنه این جریان رو. ( بیشتر این فلگ رو میزارن برای اینکه تارگت drop شه و..) .وقتی پکتی وارد شبکه ما میشه اگه  MTU اون پکت بیشتر از MTU شبکه ما باشه در مورد این پکت (link_0, link_1)fragmentation اتفاق میفته و اون پکت به فریم های کوچیک تری تقسیم میشه تا به سایز MTU ما بخوره  و این عملیات تو ip-v4 هست وفرستند و گیرنده میتونن فرگمنتیشن رو انجام بدن ولی در ip-v6 اینجوری نیستش و سمت فرستند فرگمنتیشن انجام میشه . وقتی پکتی ارسال میشه روی پروتکل tcp ip-v4 یه فلگ به اسم DF که مخفف Don&#x27;t Fragment هستش میتونه ست بشه ، اگه ست شده باشه روتر اون پکت رو  به فریم های کوچیک تری تبدیل نمیکنه در عوض یه روتر که MTU کوچیک تری داره میتونه پیام icmp رو به فرستنده  بفرسته و بهش بگه که  MTU رو کاهش بده البته میتونیم از پروتکل های دیگه ای هم استفاده کنیم ولی icmp بهینه تره (تو پکت های بزرگ..) اگه ست نشه این فلگ روتر های میانی میتونن به فریم های کوچیک تری تبدیل کنن دیتا رو...  تو حملات حتی ممکن از این فرگمنتیشن استفاده کنن تا ips .. فایروال و ..رو دور بزنن و پکت های زیادی رو به سمت شما ارسال کنن و همچنین باعث میشه منابع بیشتری از سیستم استفاده شه و...Syntax : 
    iptables [ ... ] -f [ ... ]
Example :
    iptables -A INPUT -f  -j DROP-m, --match matchاز این پارامتر برای ست کردن ماژول استفاده میشود ، میتوانید از ماژول های (tcp, udp, udplite, icmp, esp, ah, sct) استفاده کنید یا all بزنید برای همه پروتکل های موجود و همچنین میتونید فایل زیر رو مشاهد کنیدcat /proc/net/ip_tables_matches
Syntax :
    iptables  [ ... ] -m [ module ] [ ... ]
Example :
    iptables -A OUTPUT -m ttl --ttl 60 -j ACCEPT-c, --set-countersاین پارا متر برای تنظیم کردن شمارنده  پکت و بایت هستش ؛ میتونید براش ست کنید که مثلا پکت های جدید که با اون قانون مچ شدن رو از 400 بشماره یا هر عدد دیگه ای!Syntax :
    iptables [ ... ] -c  [ packet counter ] [ bytes counter ]  [ ... ]
Example :
    iptables  -A  INPUT -c  10 400 -i enp2+ -j ACCEPT
    iptables  -A  INPUT -c 10   -i enp2+  -j  ACCEPT-4, --ipv4برای ست کردن ipv4.-6, --ipv6برای ست کردن ipv6.Syntax :
    iptables [ ... ]  [ -4 | -6 ] [ ... ]  
Example:
    iptables -A INPUT  -4  -j ACCEPT
    iptables -A INPUT  -6  -j ACCEPT[ OTHER OPTIONS ]-v , --verboseتو بیشتر دستورات در لینوکس v- برای پر سر وصدا بودن خروجی هستش (اطلاعات بیشتری رو درخورجی چاپ میکنه).Syntax :
    iptables   -L  -v [ ... ]
Example :
    iptables  -L -v
    iptables  -L -t  nat -v-w, --waitاگر فرآیند دیگری در حال تغییر قوانین iptables باشد در زمانی که یک برنامه دیگر سعی میکند قوانین iptables را اضافه کند با  locking error مواجه میشود این فلگ ( w- ) باعث میشود که iptables به جای برگرداندن ارور منتظر قفل xtables بماند،  از این اپشن برای جلوگیری از اجرا های همزمان استفاده میشود، میتوان یک مقداری رو بهش اختصاص داد (بر حسب ثانیه )  که این مقدار رو صبر میکنه تا به مشکل نخوره.Syntax :
   iptables -w [ seconds ] [ .. ]
Examole : 
    iptables -w 100  -A FORWARD  -j ACCEPT-W, --wait-interval microsecondsفاصله برای هرتکرار. وقتی برنامه حساسی اجرا میشود نباید مدت زمان طولانیی رو برای قفل xtables صبر کنیم.دیفالت 1 ثانیه هستش میتونی عدد دلخواه مون رو قرار بدیم ( بر حسب میکرو ثانیه).نکته: این اپشن فقط با اپشن بالا یعنی w- کار میکند.باید اول اون w- باشه بعدش میتونید از این اپشن هم استفاده کنید .-n, --numericاز این اپشن برای نمایش ادرس های ip به شکل نامریک استفاده میشه دیگه هاست نیم رو نمینویسه بجاش ip رو مینویسه  .Syntax :
    iptables  -L  -n [ ... ]
Example :
    iptables  -L  INPUT -t nat  -n -v-x, --exactاز این اپشن برای نمایش دقیق سایز پکت استفاده میشه دیگه رندش نمیکنه مثلا بنویسه 100M و...Syntax :  
    iptables  -L   - v  -x  [ ... ]
Example :
    iptables  -L  OUTPUT -t nat  -v  -x  -nمثال های عملیخب این قسمت رو چون در اینجا به اندازه کافی نوشتیم و اگه مثال ها رو هم همینجا بنویسیم خیلی زیاد میشه تو یه پست دیگه منتشر کردم که میتونید در  این لینک مشاهد کنید.</description>
                <category>;...z@nko!#</category>
                <author>;...z@nko!#</author>
                <pubDate>Fri, 28 Aug 2020 20:38:26 +0430</pubDate>
            </item>
                    <item>
                <title>مثال های عملی و کاربردی iptables</title>
                <link>https://virgool.io/@zankoAn/iptables-rules-examples-cihjovhaemjc</link>
                <description>iptablesخب سلام دوستان عزیز امید وارم تا اینجا مفاهیم گفته شده رو  یاد گرفته باشید  تو این قسمت قرار  یه سری مثال کاربردی بزنیم . خب شروع کنیم!!مثال اول: باز و بسته کردن پورت icmp  هستش Drop Icmpiptables -A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT
iptables -A INPUT -p icmp -m icmp --icmp-type 8 -j DROP

iptables -P INPUT DROP
iptables -A INPUT -p icmp -m icmp --icmp-type 8  -s 192.168.1.2,192.168.1.2 -j ACCEPTاولین قانون  پورت  icmp رو باز کردیم برای تایپ 8 که echo requests هستش تایپ های دیگه رو هم میتونید ست کنید یه تب بزند بعد از icmp-type-- بهتون تایپ ها  رو نشون میده. در  قانون بعدی  icmp رو این دفعه بستیم میتونستید از تارگت  REJECT هم استفاده کنید که یه  پیغامی رو به کاربر نشون بده به شکل زیر iptables -A INPUT -p icmp -m icmp --icmp-type 8 -j REJECT --reject-with -icmp-port-unreachableبعد از  reject-with-- یه تب بزنید پیام های دیگه ای که میتونید ست کنید رو بهتون نمایش میده.قانون سوم و چهارم که اضافه کردیم در واقع در اینجا میخواستم بگم که میتونید برای یه سری  ip پورت icmp رو باز بزارید  allow باشه  و بقیه رو  deny کنیدو برای اینکار  شما  دوتا راه  دارید یا اینکه اول بیاید پالیسی دیفالت زنجیره INPUT  داخل جدول filter رو DROP کنید بعد ip هایی که میخواید allow باشن رو  ACCEPT  کنید ( همین کاری که  تو قانون 3 و 4 انجام دادیم ) یا اینکه  بیاید یه زنجیره جدید درست کنید و یه قانون جدید اضافه کنید که پکت های زنجیره  INPUT رو بفرسته تو زنجیره جدید که ساختید با  j- تارگت زنجیره INPUT  رو میزارید روی اون زنجیره ای که ساختید. به این شکل وقتی پکتی وارد زنجیره INPUT میشه اول میره تو اون زنجیره ای که ما ساختیم و با قوانین موجود در اون برسی میشه بعد قانون بعدی تو زنجیره INPUT  اعمال میشه  . از اونجایی که نمیشه پالیسی روی زنجیره هایی که کاربر میسازه گذاشت باید بگیم پکت هایی که میاد تو زنجیره ای که ساختیم رو DROP کن بعد میایم میگیم هر پکت icmp که اومد تو زنجیره INPUT  و مبداشون اون ip  هایی که ما گفتیم بود allow کن (تارگتشون رو روی accept قرار میدیم مثل قانون دوم) به همین سادگی. نکته :  اگه ننویسید  t filter- هم مشکلی پیش نمیاد دیفالت اگه چیزی ننویسید جدول فیلتر استفاده میشه .نکته :  اگه خواستید تو iptables از یه لیست ip یا port استفاده کنید با ( , ) میتونید از هم جداشون کنید. البته برای مولتی پورت باید از ماژول multiport استفاده کنید، برای مولتی ip نیازی نیست.نکته : زنجیره ای که کاربر میسازه هیچ  کاری انجام نمیده  یعنی کلا نمیدونه رو پکت های ورودی قوانین که داخلش هست رو اعمال کنه یا پکت های خروجی برای اینکار باید یه قانون اضافه کنیم داخل زنجیره ای که لازم داریم  و تارگتش رو بزاریم روی  زنجیره ای که ساختیم اینجوری قوانین داخل زنجیره کاربر اعمال میشه.مثال دوم: ssh فورواردینگ.در این مثلا اگه کسی به سیستم ما ssh بزنه ما میتونیم ریدایرکتش کنیم به یه سیستم دیگه که ssh روش  در حال اجرا هست و این اجازه رو به ما میده(یعنی قانون و... نداره که مانع کار ما بشه)‌ اینجا مثلا میتونید رو سیستم اصلی و ماشین مجازیتون تست کنید.iptables -t nat -A PREROUTING -i enp2s0 -p tcp --dport 22 -j DNAT --to 192.168.1.5:22
iptables -A FORWARD -p   tcp --dst 192.168.1.5 --dport 22  -j ACCEPT                 
iptables -t nat -A POSTROUTING -j MASQUERADE   اولین قانون :در این مثال  گفته شد iptables به زنجیره PREROUTING تو  جدول nat یه قانون رو اضافه کن و با i- مخشص کردیم که فقط پکت هایی که از اون کارت شبکه رو پروتکل tcp و از پورت 22 به بیرون میرن رو لازم داریم و با j-  تارگتش رو ست کردیم روی DNAT که برای تغیر مقصد اون پکت ها هستش و با  to-- گفتیم اون پکت هایی که با این قوانین مچ هستن رو مقصدشون رو تغیر بده به  فلان ip  .دومین قانون : در قانون دوم میگیم iptables به زنجیره forward تو جدول filter یه قانون اضافه کن که هرموقع پکتی خواست فوروارد بشه از یه مبدا به  مقصد دیگه ای  و  رو پروتکل tcp بودش و مقصدش اون ip   که  که ما گفتیم بودش و پورت 22 بود قبولش کن accept کن.سومین قانون : قانون سوم هم اگه شما از ip پرایوت استفاده میکنید و ip پابلیک ندارید باید از MASQUERADE استفاده کنید در غیر اینصورت لازم نیست قانون اخر رو استفاده کنید.نکته : ما میخواستیم ssh فورواردینگ انجام بدیم برای اینکار لازم بود که مقصد اون پکت رو دست کاری کنیم و بفرستیمش اون جایی که میخوایم برای همین از جدول  NAT و Filter استفاده کردیم .مثال  سوم : بایپس کردن لاگین نرم افزار packettracerخب اگه تا الان از پکت تریسر استفاده کرده باشید میدونید که بعد از نصبش باید لاگین کنید تا اکتیو شه وبتونید ازش استفاده کنید  راه های زیادی برای اینکار وجود داره ولی با  iptables  هم میشه برای همین گفتم تو مثال ها بیارمش که ببینید چجوری و اینکه از iptables  هم استفاده کرده باشیم.iptables -A OUTPUT -j DROP

iptables -A OUTPUT --dst 46.140.72.219  -j DROP

iptables -A OUTPUT --dst www.cisco.com -j DROPخب به  2 روش بالا میتونید استفاده کنید  اصل قضیه اینه که شما باید پکتی که از سمت پکت تریسر میره رو DROP کنید تو این مثال حالت اول گفتیم همه پکت هایی که از کارت شبکه ما به بیرون میره رو  DROP کن و تو این حالت خیلی راحت و سریع باز میشه  و مشکلی نداره ولی شاید کسی نخواد کل پکت هایی که به بیرون از کارت شبکش میرن رو DROP کنه ، برای همین میتونید از کامند دوم در زمانی که  vpn روشن هستش و سیستم تونل شده  یا  فقط پکت تریسر تونل... شده استفاده کنید و از کامند سوم هم زمانی که vpn روشن نیست و سیستم تونل نشده میتونید استفاده کنید . وقتی این قانون رو بنویسید و پکت تریسر رو اجرا کنید بین 1 الی 2 دیقه واردش میشه و مشکلی نداره.در قانون 2 و 3 گفتیم هر پکتی به اون 2 تا مقصد رفت رو DROP کن ولی ما اون دوتا مقصد رو از کجا اوردیم خب خیلی ساده میتونید با اسنیف کردن شبکتون بدستش بیارید مثلا ابزار tcpdump رو میتونید استفاده کنید یا حالا برنامه های دیگه ( Wireshark, Xplico ,NetworkMiner و ...)تو عکس زیر میتونید یه نمای کلی رو ببینید.packettracerمثال چهارم: لاگ گرفتن با  iptables iptables -A  OUTPUT --dst 4.2.2.4 -p icmp -m icmp --icmp-type 8  -m limit --limit 3/min --limit-burst 2  -j LOG --log-level info --log-prefix &amp;quot ICMP LOG IPTABLES: &amp;quotخب در اینجا گفتیم iptables هر پکت icmp که تایپش echo requests هستش و داره از کارت شبکه ما به سمت 4.2.2.4 میره رو لاگ کن  تو لول info و prefix ش رو هم بزار  ICMP LOG IPTABLES . در اینجا از ماژول limit استفاده کردیم میگه تو هر دقیقه 1 بار لاگ بنداز و با burst تعداد پکت های اولیه رو مشخص کردیم یعنی اولین لیمیتی که اعمال میشه 2 تا هستش و بعد از اون هر دقیقه 1 بار لاگ میندازه .میتونید برای لیمیت از  روز، ساعت، دقیقه و ثانیه استفاده کنید .تو عکس زیر میتونید مشاهده کنید که به چه شکلی اجرا میشه (  تو قسمت اول راجب لاگینگ صحبت کردیم لول ها و..... اگه یادتون نمونده این لینک رو میتونید ببینید )‌.logمثال پنجم:  دراپ کردن پکت های INVALIDiptables -A INPUT -m conntrack --ctstate INVALID -j DROPمیتونید به این شکل پکت های invalid رو دراپ کنید  ولی یه مشکلی هست اگه تعداد این پکت ها زیاد بشه سرور فشار زیادی رو متحمل میشه برای همین ما میتونیم یه کار بهتری رو انجام بدیم!! بجای اینکه از زنجیره  input استفاده کنیم بیایم از PREROUTING استفاده  کنیم چون قبل از  input هستش و اولین جا هستش برای برسی پکت های ورودی خب درسته که اینجوری بهتر ولی یادتونه که جدول فیلتر همچین زنجیره ای رو نداره برای همین باید از جدول mangle استفاده کنیم چون بیشتر زنجیره ها رو شامل میشه و بهتر.iptables -t mangle -A PREROUTING -m conntrack --ctstate INVALID -j DROPمثال ششم: جلوگیری از traceroute کردن شبکهtracerouteخب برای اینکار اول باید بدونید که traceroute به چه صورت هستش تا بعد بتونید جلوش رو بگیرید. سیستم عامل های مختلف و ابزار های مختلف  عملکرده متفاوتی رو پیاده سازی میکنن برای traceroute کردن در ویندوز شما traceroute کنید بر روی پروتکل icmp با پکت های echo-requests میاد traceroute رو انجام میده ولی رو لینوکس مثلا رو پروتکل udp و رو پورت های 33434...33534 این عمل رو انجام میده برای همین متناسب با اون سیستم عامل میتونید جلوش رو بگیرید مثلا در لینوکس میتونید با دوتا قانون زیر جلوش رو بگیرید .iptables -t raw -A PREROUTING -p udp --dport 33434:33534 -j DROP
iptables -t raw -A PREROUTING  -p icmp --icmp-type 8 -j DROPقانون اول گفتیم هرپکتی بر روی پروتکل  udp خواست وارد شبکه ما بشه اگر تو رنج پورت 33434 تا 33534 بود بیا دارپش کن و این کافیه اما اگر بر روی پروتکل  tcp و با پکت های icmp سعی کنه traceroute رو انجام بده باز هم میتونه این کار رو انجام بده برای همین میایم در قانون دوم تایپ 8 icmp رو دراپ میکنیم که دیگه به پکتی با همچین مشخصه ای اجازه ورود داده نشه. مثال هفتم: لود بالانسینگ ترافیک ورودی وبLoad balancing iptables -t nat -A PREROUTING  -p tcp --dport 443 -m state --state NEW -m statistic --mode nth
--every 3 --packet 0 -j DNAT --to-destination 192.168.1.101:443

iptables -t nat -A PREROUTING -p tcp --dport 443 -m state --state NEW -m statistic --mode nth
--every 3 --packet 1 -j DNAT --to-destination 192.168.1.102:443

iptables -t nat -A PREROUTING  -p tcp --dport 443 -m state --state NEW -m statistic --mode nth --every 3 --packet 2 -j DNAT --to-destination 192.168.1.103:443
خب در مثال بالا ما اومدیم لود بالانسینگ رو بین 3 تا سرور انجام دادیم به شکلی که سرور اصلی  پکت هایی که مقصدشون پورت 443 هستش رو  توسط تارگت DNAT ریداریکت کردیم به مقصد سرور اول  و دوم و سوم.در اینجا برای لود بالانسینگ از ماژولstatistic استفاده کردیم که این ماژول 2 تا mode داره یکیش random و اون یکی هم nth اینجا ما از nth استفاده کردیم که از الگوریتم Round Robin استفاده میکنه. به این شکل که برای سرور اولی با every 3-- مشخص کریدم که هر 3 پکت یک بار از پکت 0 (packet  0--) به بعد بفرسته برای سرور اولی و برای سرور دومی هم به همین شکل هر 3 پکت 1 بار از پکت دوم به بعدبفرسته برای سرور 2 و هر 3 پکت یک بار از پکت سوم به بعد رو بفرسته برای سرور 3وم.فک کنم متوجه شده باشید دیگه ! با every-- استپ هاش رو مشخص میکنیم که هر چند پکت این عمل رو انجام بده و با packet--  هم مشخص کردیم که از پکت چندم شروع کنه به فرستادن اینجوری بالانسینگ ایجاد میشه و به درستی بین سرور ها فشار بوجود اومده تقسیم میشه.تو این قسمت سعی کردم که مثال ها تا حد ممکن کاربردی باشه و اینکه از ماژول های مختلف استفاده بشه  که ببینید به چه شکل استفاده میشن و البته که ماژول های بیشتری هم هستن که با توجه به نیازتون میتونید ازشون استفاده کنید(با سرچ کردن تو گوگل میتونید خیلی راحت برای نیازتون پیداشون کنید) این ماژول هایی که استفاده کریدم صرفا برای تیتر بالاشون که نوشتیم نیستن و میتونید هرجا که نیاز شد با ترکیب کردنشون قانون های بهتری رو بنویسید .قسمت دوم اموزش رو میتونید اینجا مشاهد کنید.</description>
                <category>;...z@nko!#</category>
                <author>;...z@nko!#</author>
                <pubDate>Fri, 28 Aug 2020 20:00:15 +0430</pubDate>
            </item>
                    <item>
                <title>آموزش فایروال قدرت مند IPTABLES :) قسمت دوم</title>
                <link>https://virgool.io/@zankoAn/iptables-p2-ipiwdppslyzr</link>
                <description>IPTABLESخب تا الان با خود iptables  و نحوه کارکردش آشنا شدید(..,tables, chain, rules, target)تو  این اموزش میخوایم راجب  کامند های iptables  صحبت کنیم... فایروال  iptables یه سری کامند داره که میتونید برای نوشتن قوانین مورد نظر از  اونها استفاده کنید، برای هر کامند هم یه مثال به همراه سینتکسش نوشته شده .نکته : وقتی دارید با iptables  کار میکنید باید با دست رسی root کامند ها رو اجرا کنید. (sudo)-L, --listاز  این کامند  برای نشون دادن تمام قوانین موجود در  همه زنجیرها یا فقط  زنجیره داده شده یا فقط قانون مشخص شده در یک زنجیره استفاده میشود( لیست  قوانین رو نشون میده از کل به جز نوشتم ).Syntax :
    iptables -L [ chain ] [ rule-number ] [ table ]
Example :
    iptables -L
    iptables  -L  -t  nat
    iptables  -L  INPUT  -t  nat 
    iptables  -L  INPUT  10  -t  nat-T, --tableاز  این کامند برای انتخاب کردن جدول مورد نظر استفاده میشود. ( البته به  تنهایی استفاده  نمیشه معمولا برای نمایش قانون های موجود در جدول و یا  نوشتن یه قانون جدید و... استفاده میشه )Syntax :
    iptables  [ ... ] -t [ table ] [ ... ]
Example :
    iptables  -L  -t nat-j, --jumpاین هدف پکت رو مشخص میکنه ،  اگه پکت با قانون نوشته شده مطابقت داشت اون هدف اعمال میشه.   میتونید از این تارگت ها استفاد کنیدACCEPT        ( پذیرفتن پکت های  مچ شده با قانون نوشته شده )DROP            ( رد کردن پکت های مچ شده با قانون نوشته شده )LOG ‌              ( برای لاگ گرفتن استفاده میشود )REDIRECT( برای ریدایرکت کردن  پکت مورد نظر استفاده میشه  مثلا میتونیم بگیم  همه  پکت هایی .که از فلان جا میاد رو بفرست فلان جا!!  تو مثال ها  باهاش کار  میکنیم ‌)REJECT         (  REJECT  )RETURN        ( RETURN )QUEUE          ‌( QUEUE )MARK           ( MARK )SNATآدرس  ip پکت رو تغیر میده . همچنین میتونه پورت منبع رو هم تو هدر tcp/udp تغیر  بده. کاربرد اصلیش ترجمه ip/port پرایویت به ip/port پابلیک هستش برای پکت  هایی که از شبکه ما خارج میشن. تو جدول nat  و در زنجیره  POSTROUTING  استفاده میشود.MASQUERADEدقیقا  مثل SNAT هستش  با این تفاوت که سیستم بصورت خودکار  دنبال ip پابلیک برای  ترجمه می گرده.  MASQUERADE بار  و عملیات اضافی به سیستم تحمیل می کنه،  هر چند امتیاز بزرگی نسبت به SNAT  داره و اون هم اینه که با هر بار تغییر  ip پابلیک، تغییری در عملکرد سیستم به  وجود نمیاد.(بعضی از سرویس دهند ها  از طریق DHCP ،PPPoE و … اینترنت رو در اختیار شما قرار میدن که با هربار  خاموش روشن کردن نت  ip  پابلیک تون عوض میشه پس برای همین میتونید از  MASQUERADE استفاده کنید .... ). مثلا داخل یه شبکه هستید و یکی از سیستم ها نت داره ولی بقیه ندارن، میتونید داخل اون سیستمی که نت داره بگید اگر پکتی از سمت فلانی اومد، بفرستش به بیرون به جایی که میخواد بره فقط بگو که من هستم یعنی ایپی مبدا پکت رو بکن ایپی من، اینشکلی  دوتا سیستم دارن از طریق یه نتورک درخواستشون رو به بیرون میفرستن.DNAT            ( برای ترجمه آدرس مقصد بسته استفاده می شود )TOS              ( TOS )ECNبرای حذف کردن  بیت های ECN در هدر ipv4 استفاده میشود و فقط ارگمان ecn-tcp-remove--  رو قبول میکنه.DSCP      ( DSCP )اصولاً  DSCP راهی است برای تمایز سرویس های مختلف به دسته های جداگانه و بر این  اساس ، از طریق روترها به آنها اولویت متفاوتی می دهد.TCPMSSاز  این تارگت میتوان برای تغیر مقدار  MSS ( Maximum Segment Size ) پکت های  tcp syn استفاده کرد. مقدار  MSS برای کنترل حداکثر اندازه بسته ها هستش (  تو شرایط عادی به معنای MTU  منهای 40 بایت است)ULOG     ( در فضای کاربر برای گرفتن لاگ پکت ها استفاده میشود )Syntax :
    iptables  [ ... ] -j  [ Target ]
Example :
    iptables  -A INPUT  -p icmp  -j  DROPنکته  :‌ اگر از این پارامتر و همینطور  پارامتر g- استفاده نشود هیچ تاثیری بر  روی پکت دریافتی نخواهد داشت.فقط شمارنده اون قانون زیاد میشه همین.-A, --appendبرای اضافه کردن یک قانون به انتهای زنجیره قوانین موجود .Syntax : 
    iptables -A [ chain ] [ rule ]
Example :
    iptables -A INPUT -j DROP-C, --checkقبل از اضافه کردن یه قانون جدید میتونید با این کامند چک کنید که قانون از قبل وجود داره یا نه .Syntax:
    iptables -C [ chain ] [ rule ]
Example:
    iptables  -C INPUT  -j DROPبعد  از اجرا اگه خروجیی نداد پس وجود داره اگه خروجی داد تو خروجی میگه که  وجود نداره میتونید با دستور زیر هم چک کنید .( exit status  دستور قبل رو  میده )‌echo $?در صورت وجود 0 برمیگردونه در غیر اینصورت 1.--line-numbersبرای  نمایش عدد(شمارنده*) مربوط به هر قانون استفاده میشود( اگه قانونی وجود  نداشته باشه داخل خروجی تو اولین قسمت یه  num مینویسه  ولی اگه قانونی  وجود داشته باشه بجای اون num شماره مربوط به اون قانون رو مینویسه )‌Syntax :  
    iptables  -L  --line-numbers
Example :
    iptables  -L  --line-numbers 
    iptables  -L  OUTPUT -t nat  --line-numbers-D, --deleteاز این کامند میتونید برای حذف کردن قوانین موجود در chain  مورد نظر استفاده کنید.syntax:
      iptables -D  [ Chain ]  [ rule-number ]
example:
     iptables -D INPUT  1-I, --insertبرای اضافه کردن یه قانون به یه زنجیره با یه موقعیت مشخص هستش. مثلا میتونیم بگیم یه قانون به زنجیره input  اضافه کن و تو لیست قانون ها بزارش اولین قانون.  3 مقدار  رو میگیره اولی اسم زنجیره دومی اون شماره ای که میخواید تولیست قرار بگیره  مثلا اولین قانون باشه یا هرچیز دیگه ای... و خود قانونی که میخواید  بزارید.Syntax:
    iptables -I [ chain ]  [ rule-number ]  [rule]
Example: 
    iptables -I INPUT  1 -j DROP-R, --replaceبرای  جایگزین کردن یه قانون در  زنجیره  استفاده میشود .Sytax :
    iptables -R [ chain ] [ rule-number ] [ rule ]
Example:
   iptables -R INPUT  1  -j  ACCEPT-S, --list-rulesاز  این کامند میشه برای نمایش قانون های موجود داخل یه زنجیره استفاده کرد هم  میتونید لیست قانون های موجود رو مشاهد کنید هم میتونید فقط یه قانون خاص  رو مشاهد کنید .Sytax :
    iptables  [ table ] -S  [ chain ] [rulenum]
Example:
    iptables -S                              
    iptables -t nat -S                     
    iptables -t nat -S INPUT          
    iptables  -t nat -S INPUT 4-F, --flushاز این کامند برای حذف کردن تمام قوانین موجود در [ زنجیره ای از جدول یا جدول ] مورد نظر استفاده میشود.Syntax : 
    iptables -F [ chain ]  [ table] 
Example :
    iptables -F
    iptables -F -t nat 
    iptables -F INPUT 
    iptables -F INPUT -t nat-N, --new-chainاین کامند برای ایجاد یک chain جدید توسط کاربر هستش. قابلیتش اینه که مثلا شما یه قانون دارید داخل جدول  filter  که میاد داخل زنجیره  input و  پکت های یه ip رو drop میکنه خب  حالا ممکن این  قانون تو زنجیره input شماره 200 باشه حالا میاد دونه دونه   200 تارو چک میکنه بعد که رسید به این قانون اعمالش میکنه، مشکل اینه که  زمان بیشتری میبره  شما میتونید با این کامند یه  زنجیره جدید بسازید که  مثلا بیاد روی پکت های یه ip قوانین رو اعمال کنه اینجوری دیگه نمیره اون  200 تا رو چک کنه مستقیم میره تو زنجیره مربوطه و اون قانون ها رو اعمال  میکنه.Syntax :
     iptables -N [ name-chain ] -t [ table ] 
Example :
   iptables  -N  new_chain -t filter-X, --delete-chainاین کامند برای حذف chain به وجود اماده توسط کاربر هستش.Syntax :
    iptables  -X [ chain ]  -t [ table ]
Example :
   iptables -X test
   iptables -X test -t nat-P, --policyاز  این کامند میتونیم برای ست کردن یه پالیسی روی یه chain خاص استفاده  کنیم.میتونیم از تارگت های DROP, ACCEPT استفاده کنیم ( اگه یادتون باشه تو  قسمت قبل اون اخرها گفتیم که یه تارگت دیفالت داره هر زنجیره اینجا  میتونیم ست کنیم که اون دیفالت چی باشه ).Syntax :
    iptables -P [ Chain ] [ Target ]
Example :
   iptables -P INPUT ACCEPTنکته :  بر روی Chain هایی که کاربر ایجاد کرده نمیتوان پالیسی تعریف کرد.-Z, --zeroاین  کامند برای صفر کردن شمارنده پکت ها و بایت های دریافتی همه زنجیرها یا  فقط زنجیره داده شده یا فقط قانون مشخص شده در یک زنجیره استفاده میشود.همچنین  میتونید از کامند زیر برای دقیق تر نشون دادن اتفاقی که داره میفته  استفاده کنید ( v- رو تو قسمت بعد توضیح میدیم (برای نشون دادن اطلاعت  بیشتر هستش( verbose) ))iptables -Z  OUTPUT  10  -t nat -L -v --line-number-E, --rename-chainاگه بخوایم اسم chain  خودمون رو تغیر بدیم از این کامند استفاده میکنیم.Syntax :
    iptables  -E   [ old-chain ] [ new-chain ]
Example :
    iptables -E  test  my_chainنکته : فقط chain هایی که توسط کاربر ایجاد شده اند قابلیت تغیر اسم را دارند.قسمت سوم: https://virgool.io/@zankoAn/iptables-p3-inqpkuavdkre </description>
                <category>;...z@nko!#</category>
                <author>;...z@nko!#</author>
                <pubDate>Tue, 02 Jun 2020 23:42:26 +0430</pubDate>
            </item>
                    <item>
                <title>آموزش فایروال قدرت مند IPTABLES :)  قسمت اول</title>
                <link>https://virgool.io/@zankoAn/iptables-zk9weh2k6rfk</link>
                <description>iptablesLast Update: 2022-06-10 - 00:51در  این آموزش میخوایم با  فایروال قدرتمند Iptables آشنا بشیم و با این فایروال بیایم قانون ها و پالیسی های مختلفی که میخوایم رو پیاده سازی کنیم. این آموزش شامل 3 قسمت میشه: 1 - تو قسمت اول راجب خود iptables و netfilters حرف میزنیم و بعد به ساختار کلی iptables نگاه میندازیم یه سری مفاهیم پایه ای رو یاد میگیریم و میریم جلو.2 - در قسمت دوم با پارامتر  های iptables  اشنا میشم، ساختار کلیشون رو برسی میکینم و...  که میتونید ازشون  برای نوشتن قانون ها حذف، ادیت و ... استفاده کنید.3 - در قسمت آخر یا بهتر بگیم یکی مونده به اخر  میام کامند های iptables رو نگاه  و برسی میکنم و  با هم میریم جلو.4 - در قسمت اخر هم میایم یه سری مثال عملی میزنیم که بیشتر سعی میشه ترکیبی از چیز هایی باشه که یاد گرفتیم تا قابل لمس تر بشه کل ماجرا.نکته: ممکنه در طول این چند قسمت از یه چیز هایی اسم ببریم و توضیح زیادی راجبش ندیم به 2 دلیل، اول اینکه بعضیاش رو خود من هم دانش کافی ندارم ازشون و نمیتونم توضیح کاملی ارئه بدم و  دلیل  دوم این هستش که خود این موارد یه مقاله جدا میخواد یعنی از موضوع این مقاله خارج میشه و بیشتر سمت شبکه هستش و میتونه خیلی عمیق تر بشه و.... برای همین اگه چیزی رو متوجه نشدید پیشنهاد  میکنم گوگل کنید.معرفی iptables و نحوه ارتباطش با netfilterدر ابتدا تو کرنل 1.1 لینوکس ابزار ipfilter وجود داشت که برای فیلتر کردن و اعمال قوانین از ابزار ipfwadm استفاده میکرد؛ تو کرنل 2.2 به بعد ابزاری به اسم IPChains معرفی شد و در کرنل 2.4 به بعد هم iptables اومد که تا الان هم استفاده میشه این فایروال توسط تیم netfilter  ساخته شده. خود iptables  برای ipv4 کار میکنه از ipv6 هم پشتیبانی میکنه  و یه نسخه ip6tables  هم داره برای ipv4 هم میشه ازش استفاده کرد.!فایروال  iptables  یه فایروال عالی برای سیستم های لینوکسی هستش که خیلی خوب  میتونه پکت ها رو هندل کنه وقابلیت های خیلی زیادی رو به ما میده. خود  Netfilter شامل 5 تا hook هستش که برنامه میتونه با اونا کار بکنه، هر  پکتی که وارد فرایند پردازش میشه با یکی از این hook ها در  kernel  تطبیق  داده میشود و کل میشه، بسته به نوع هر پکت یه hook بهش اختصاص داده میشه:قلاب(hook) های نت فیلترNF_IP_PRE_ROUTINGNF_IP_LOCAL_INNF_IP_FORWARDNF_IP_LOCAL_OUTNF_IP_POST_ROUTINGدر اصل iptables یه نرم افزار userspace هستش که با netfilter کار میکنه، خود Netfilter با کرنل در ارتباط هستش و وقتی  پکتی وارد شبکه ما میشه  با استفاده از hook های netfilter  اون پکت با  قوانینی که داخل iptables نوشته شده  تطبیق داده میشه و باتوجه به قوانین با اون پکت برخود میشه ( مثلا اگه گفته باشه  Drop کن  دراپ میکنه یا هرچیز دیگه ای که براش ست شده باشه در ادامه بیشتر میگیم .)فایروال iptables چجوری کار میکنه؟همون طور که گفتیم iptables یه پکیج تو سطح کاربر هستش و راحت کاربر میتونه باهاش قانون هایی رو که میخواد بنویسه و خیلی قابل کاستومایز هستش؛ همچین دستمون باز تره، میتونیم از firewalld هم استفاده کنیم که user friendly تر هستش ولی امروز ما میخوایم با iptables کار کنیم.فایروال iptables پکت های ما رو بر اساس موارد زیر فیلتر میکنه(در ادامه هرکدوم رو توضیح میدیم! فعلا به ترتیب میریم جلو...):جدول ها (Tables):‌  شامل مجموعه ای از chain ها هستش مثلا یه تیبل داریم برای ورودی برای خروحی برای منگل و... که هرکدوم شامل یه سری چین ها میشن و اولویت دارن نسبت به همدیگه.زنجیره (Chains):  شامل مجموعه  ای از قانون ها میشه، وقتی یک پکت رو دریافت میکنیم iptables جدولی که به اون پکت مربوط میشه رو پیدا میکنه و اون chain مربوطه رو  اجرا میکنه. به صورت کلی chain ها تعیین میکنن که چه زمانی  قوانین ارزیابی بشن مثلا پکت میاد تو سیستم اول میره یه table بعد چینی که اولویتش بیشتر مثل PREROUTING اون یه کار هایی باهاش میکنه بعد میره سراغ چین ها یا تیبل های دیگه.قوانین (Rules):  قوانین مشخص میکنن که با پکت دریافتی چه رفتاری انجام بشه مثلا میگیم اگر پکت از ip فلان اومده بود یه بلایی سرش بیاد یا نیاد و...هدف (Targets):   اینجا  میایم اون بلا که قرار سر پکت بیاد رو مشخص میکنیم مثلا پکت اومده یه چین هایی رو رد کرده حالا تصمیم گرفتیم روتینگ رو انجام بدیم یعنی مثلا داخل جدول nat اومدیم تو  PREROUTING تصمیم گرفتیم که برای ما نیست اینجا مثلا میایم دست به دستش میکنیم برسه مقصدش و یا dropمیکنم و حالت های دیگه.در iptables یه سری  Table مشخص وجود داره که هرکدوم از اون Table ها  یه سری Chain داخلشون هست که تو شکل پایین میتونیم خیلی بهتر ببینیم این موضوع رو:Tablesخب بر اساس شکل بالا ما میایم مواردی رو اینجا توضیح میدیم و مواردی رو هم در آینده...Table = Filter  &lt;--- Chains = [ OUTPUT, INPUT, FORWARD  ]وظیفه  جدول Filter  پالیسی(سیاست) گذاشتن  و دادن مجوز برای ورود و خروج پکت ها به سیستم  هستش(فیلترشون میکنه‌:))،  این جدول خودش شامل سه تا چین INPUT برای ترافیک ورودی به سیستم، OUTPUT برای ترافیک خروجی سیستم و FORWARD برای ترافیک فوروارد  شده از سیستم هستش که بعدا بیشتر درکش میکنیم.Table = Nat  &lt;--- Chains = [ OUTPUT, PREROUTING, POSTROUTING  ]از جدول Nat برای قانون گذاری و دادن مجوز برای عملایت  مسیر یابی استفاده میشه و قوانین مربوط به تغییر آدرس IP و یا پورت در جدول   nat قرار میگیره،  این جدول شامل سه تا چین PREROUTING برای شبکه مقصد در ترافیک ورودی به  سیستم، POSTROUTING  برای شبکه مبدا در ترافیک خروجی از سیستم و OUTPUT  هستش.Table = Mangle &lt;---  Chains = [ INPUT, OUTPUT, FORWARD, PREROUTING, POSTROUTING ]از  جدول Mangle میتونیم برای عملیات بررسی بسته ها قبل از ورود به table های  بالا استفاده کنیم  و تغیراتی رو روی  header  پکت های  IP  اعمال کنیم، در واقع این چین های تیبل فیلتر و نت رو شامل میشه، این  جدول  سه هدف عمده را دنبال میکنه:[ TOS,  TTL,  Mark]نوع سرویس (ToS / Type of Service)از  طریق منگل میتونیم فیلد TOS ) Type of Service) هدر بسته رو تغییر بدیم،  این تنظیم تو روتر ها، فایروال ها و… تاثیر زیادی نداره مگه اینکه تو پالیسی های مربوط به مسیریابی، پینگ، QOS و… استفاده بشه. زمان زندگی (TTL / Time To Live)از  طریق منگل میتونیم فیلد TTL ) Time To Live ) رو در هدر بسته تغیر بدیم،  فیلد TTL برای این منظور هستش که اگه یه سری پکت همینجوری موندن بعد از یه تایمی به جایی نرسیدن از بین برن، اگه از TTL استفاده نمی شد یه سری while true اتفاق می افتاد که اگه بیشتر میشدن باعث downشدن شبکه ما میشد.TTLmarkجدول  منگل این قابلیت رو داره که از طریق اون بسته ها رو mark کنیم(نشونه گذاری کنیم)، از  این مارک ها میتونیم در پینگ، مسیریابی و... استفاده  کنیم. هد از این مارک این هستش که قسمت های مختلف شبکه با این مثل یه پیام با هم دیگه تو تعامل باشن، این میتونه یه عددصحیح 32 بیتی باشه که به پکت توی شبکه وصل میشه و این علامت گذاری فقط تو جدول منگل معتبر هستش و بخش های مختلف استک شبکه میتونن این علامت(mark) رو بخونن و رفتارشون با پکت رو  بر اساس مقدار mark تغییر بدن یا دوباره بنویسنش مثل  tc و...برای استفاده از این قابلیت  باید از اپشن  set-mark-- استفاده کنیم.برای درک بهتر این موضوع میتونید به اینجا مراجعه کنید.Table = Raw &lt;--- Chains = [ PREROUTING, OUTPUT ]از جدول  RAW برای معاف کردن پکت ها از connection tracking استفاده میشه، یه بخش از استک شبکه لینوکس  conntrack  هستش  که به طور کلی یه بخش از زیر سیستم  فایروال هستش( کلیه سیستم عامل ها connection tracking رو داخل فایروال  خودشون اجرا میکنن که شامل  6 ستون (protocol (TCP or UDP), source IP, source port, destination IP, destination port , connection state ) هستش و داخل لینوکس به این ساب سیستم conntrack میگیم و به صورت پیش فرض هم فعال هستش).این  جدول  به نحوی عمل می کنه که قبل از ورود پکت ها به  Connection Tracking و… ( طبق عکس tables  ها که بالا تر مشاهد کردید‌)‌ اون ها رو میتونه فیلتر  کنه و این کار باعث میشه که فشار روی سیستم خیلی کمتر بشه(cpu,  ram ,...).برای استفاده ازش باید وقتی قانونی رو مینویسیم از تارگت NOTRACK  استفاده کنیم.Table = Security &lt;--- Chains = [ OUTPUT, INPUT, FORWARD ]این جدول برای قوانین شبکه، کنترل دسترسی اجباری(MAC) مثل مواردی که توسط تارگت های SECMARK و CONNSECMARK  فعال میشن قابل استفاده هستش، MAC توسط ماژول های امنیتی لینوکس مثل  SELinux اجرا میشه، خود جدول security  بعد از  جدول فیلتر هستش و به همین دلیل  اجازه میده تا قوانین دسترسی(DAC) در جدول فیلتر قبل از قوانین MAC اعمال  بشه، راجب  SELinux , MAC , DAC میتونید تو گوگل سرچ کنید و...هدف یا TARGETهدف یا همون target مشخص میکنه که سرنوشت یه پکت با توجه به rule نوشته شده چی بشه(  مثلا میگیم اگه یه پکت از فلان ip اومد  چه بلایی سرش بیاد) پایین  تر لیست بلاهایی که میتونید سر پکت بیارید رو نوشتم:نکته  : هر Chain به صورت دیفالت یک Target داره البته این دیفالت برای chain  هایی هستش که به صورت دیفالت وجود دارن و اون هایی که کاربر ایجاد کرده رو  شامل نمیشه . تارگت دیفالت هم accept یا drop هستش(ایجاد چین حذف اضافه و .. رو هم تو قسمت های بعدی میگیم).[  ACCEPT  ]در این حالت میگیم این پکت اگه این rule شده ما باهاش مطابقت داشت بیا  قبولش کن این پکت اوکیه  از نظر ما.[  DROP  ]میتوینم بگیم این پکت حق خروج نداره از شبکه یا حق ورود به شبکه ما رو نداره، اگه پکتی به سمت ما بیاد و دراپ بشه؛ به فرستنده پکت هیچ ارور نمیاشی نمیده( مثلا میتونن پینگ یه ip رو DROP  کنن و وقتی که پینگ بگیرید هیچی بهتون نده، ولی اگه مثلا  بجای  drop کردن Reject میکردن اون زمان به شما ارور میداد مثلا  Port Unreachable برمیگردوند.)[  QUEUE  ]نکته: این قابلیت از کرنل 3.1 به بالا پشتیبانی میشه .به وصیله  nfnetlink_queue پکت رو به فضای کاربر (userspace) منتقل میکنه، میتونه تو برنامه های فیلتر شکن و پروکسی ... استفاده بشه.وقتی یه پکت با rules نوشته شده مطابقت داره کرنل اون پکت رو در لیست chain قرار میده و بعد یه پیام              nfnetlink رو قالب دهی میکنه و اطلاعات(packet data , packet id and metadata)  رو از  طریق سوکت به نرم افزار متصل به queue ارسال میکنه و نرم افزار میتونه پکت  رو بخونه یا تغیر بده و...برای مثال وقتی شما یه  vpn دارید رو سیستم تون و در حال اجرا هستش اگه دستور زیر رو بزنیدsudo iptables -A OUTPUT -p icmp --icmp-type 8 -j QUEUEمیاد  انتقالش میده به نرم افزار های سطح کاربر که الان فیلتر شکن شما میشه همین  نرم افزار سطح کاربر و خب الان ما پکت  های icmp که مربوط به  پینگ هست رو  داخل  صف( queue) قرار دادیم الان اگه پینگ بگیرید پینگتون اوکی هست حالا  بیاید یبار فیلتر شکن رو  خاموش کنید و این دستور رو بزنید بعدش پینگ  بگیرید ،  متوجه میشید که نمیتونید پینگ بگیرید.  وقتی که تو فضای کاربر  نرم افزاری وجود نداشته باشه اون چیزی که براش ست کردید که اینجا icmp هستش  دراپ میشه و برای همین پینگ ندارید.[  RETURN  ]اگه پکتی  با این تارگت  ست شده باشه وقتی بهش برسه فایروال چک کردن  اون  پکت رو متوقف میکنه وکلا اون چین رو متوقف میکنه، اگه این  Chain که  پکت الان توش هست و... ساب chain باشه، یعنی تو یه chain دیگه  مثلا jump شده  باشه بهش؛ الان این  retrn میشه و به اون chainی که ازش جامپ کرده اینجا و از اون  chain ادامه کار رو میره...ـ(اگه برنامه نویسی کرده باشید فکر کنید یه یه فانکشن داخل یه فانکشن دیگه داریم که اون داخلیه الان return میشه و ادامه کار از فانکشن اصلی پیش میره)  ولی اگه ساب chain نباشه و خودش chain اصلی  بوده باشه یکی از هدف های دیفالت که یا  accept یا drop هست روش ست میشه براش.[  Reject  ]فایروال  پکت دریافتی را رد (reject) میکنه یعنی پیامی حاوی اطلاعات دقیق تر  یا  خطا رو ارسال میکنه، مثل همون مثال بالا که راجب پینگ بودش.[  LOG  ]این  Chain بسته های ورودی رو لاگ میکنه میتونید از این اپشن برای لاگینگ  iptables استفاده کنید میتونید بگید بهش که در چه لولی لاگ بگیره  از جمله :alertcritdebugemergerrinfonoticeمیتونید اپشن log-prefix-- رو هم براش ست کنید که با توجه به یه پیشوند خاص لاگ کنه  براتون برای وقتی که میخواید لاگ رو بخونید واضح تر میشه...میتونید اپشن log-tcp-options--  رو هم ست کنید که یه سری از اپشن های هدر tcp رو تو لاگ مینویسه برای دیباگینگ میتونه مفید باشه.یه  اپشن log-ip-options-- رو هم داره که میتونید ست کنید مثل tcp بالا ولی این  فقط رو هدر بسته ip کار میکنه... یه  log-tcp-sequence  هم داره که این  چنتایی که توضیح دادم بهترن حالا این log-tcp-sequence  میتونه به ضرر ادم  هم باشه... همون بالایی ها رو استفاده کنید بنظرم اوکی باشه!!فایروال  iptables  به صورت دیفالت  لاگ خودش رو داخل   syslog  یا   var/log/kern.log/ میریزه میتونید از اینجا برسی کنید . همچنین میتونید از  syslog-ng  استفاده کنید( اگه نداریدش باید نصبش کنید.) اپشن های بیشتری  بهتون میده میتونید لاگ های iptables  رو بفرستید تو یه فایل جدا برای این  کار باید فایل زیر رو باز کنید/etc/syslog-ng/syslog-ng.confبعد چند خط زیر  رو بهش اضافه کنید .destination iptables { file&#40;&amp;quot/var/log/iptables.log&amp;quot&#41;; };
filter f_iptables { match(&amp;quotIPT=&amp;quot); };
log { source(src); filter(f_iptables); destination(iptables); };از این به بعد میتونید تو فایل var/log/iptables.log/  لاگ ها رو مشاهد کنید . البته  باید تو  قسمت log-prefix-- برای هر زمانی که میخواید لاگ کنید IPT رو  قرار بدید برای اینکه لاگ بره تو این فایل.قسمت دوم : https://virgool.io/@zankoAn/iptables-p2-ipiwdppslyzr </description>
                <category>;...z@nko!#</category>
                <author>;...z@nko!#</author>
                <pubDate>Sat, 23 May 2020 20:15:35 +0430</pubDate>
            </item>
            </channel>
</rss>