مقدمه

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

در بخش نوستر به زبان ساده کوشش میکنیم تا نوستر را به سادگی برای کاربران تازه اموزش دهیم.

در بخش NIP ها تمامی امکانات پیاده سازی نوستر را به پارسی برگردادنده ایم.

و در بخش نوستر برای توسعه دهندگان توضیحات و مقدماتی بر پیاده سازی رله و کلاینت یا اجرا کد های موجود اراعه کرده ایم.

مقدمه

در این بخش ما نوستر رو به زبان ساده برای افرادی که میخوان اشنایی اولیه با نوستر پیدا کنن و خیلی ساده استفاده از اون رو شروع کنن توضیح میدیم. به مرور توی هر قسمت یک مفهوم جدید معرفی میشه و کار باهاش اموزش داده میشه.

هدف این بخش اینه که سادگی حداکثری داشته باشه.

نوستر به زبان ساده

در این بخش سعی میکنیم کلیات نوستر رو به زبان ساده بیان کنیم و خیلی ساده نحوه شروع به کار با اون رو اموزش بدیم. تلاش میشه تمامی بخش های نوستر به زبان ساده از نظر نوشتار و توضیحات واضح و ساده باشن. اگر توی هر بخش نیاز به راهنمایی یا کمک دارید میتونید از روش های زیر استفاده کنید:

باز کردن ایشو روی مخزن این کتاب و پرسیدن سوال:

https://github.com/persianccbook/nips-persian/issues

توجه کنید که با جستجو مشکل در ایشو ها و یا مروگر ممکنه به پاسخ پرسش خودتون برسید.

نوستر چیست؟

!نکته: توی این بخش ما سعی کردیم کمی با جزییات نوستر رو توضیح بدیم. ممکنه برخی از موارد برای انجام دادن پیچیده و دشوار بنظر بیان اما بدونید که در عمل و حین استفاده ابزار های ساده زیادی توسعه داده شده که همه این کار هارو برای شما به سادگی انجام میدن.

شبکه های اجتماعی فعلی

نوستر یک پروتکل برای ایجاد شبکه های اجتماعی غیرمتمرکز و آزاد هست. زمانی که ما از یک شبکه اجتماعی متمرکز استفاده میکنیم برای نمونه x یک نرم افزار روی دستگاه اندروید خودمون نصب میکنیم و بعد میتونیم شروع به انتشار پست و ارتباط با افراد دیگه کنیم.

در این حالت نرم افزار نصب شده روی دستگاه شما به یک سرور که یک کامپیوتر دیگه در جای دیگه ای از دنیا هست از طریق اینترنت متصل میشه و این دو میتونن با همدیگه از طریق مجموعه ای از قوانین باهم صحبت کنن. که ما بهش میگیم پروتکل. بر اساس این پروتکل نرم افزار روی دستگاه شما از سرور درخواست میکنه که داخل سرور برای شما یک حساب ساخته بشه و یا براتون یک پست رو منتشر کنه. زمانی که دوستتون ادرس شمارو از روی دستگاه خودش به سرور x میده اون سرور پست هایی که شما ازش خواستید منتشر کنه رو به دوستتون نشون میده.

در این حالت شما اجازه ندارید یک نرم افزار مشابه نرم افزار x بنویسید و به اون سرور متصل بشید. نمیتونید یه سرور مثل سرور x بسازید که دوستتون بجای اون سرور مشخص به سرور شما متصل بشه. و تمامی اطلاعات و محتوا خصوصی و عمومی شما برای سرور x و یا صاحبانش شفاف و قابل رویت هست.

همچنین این سرور یه ادرس داره که شما میتونید از طریق اینترنت باهاش صحبت کنید. دسترسی شما به اینترنت از طریق اراعه دهنده اینترنت هست که اون اراعه دهنده با دونستن ادرس x میتونه دسترسی نرم افزار شمارو به اون سرور مسدود کنه یا صحبت های شمارو سانسور کنه.

در نظر بگیرید که به نرم افزاری که شما نصب کردید میگیم کلاینت یا مشتری به زبان خودمون که به نحوی با سرور ارتباط میگیره.

نوستر و تفاوت ها

روند در نوستر کمی متفاوت هست. نوستر یک پروتکل هست. چیزی دقیقا مشابه همون چیزی که نرم افزار x با سرور میتونست صحبت کنه. عده ای شروع به تعریف این مجموعه قوانین کردن و جزییاتش رو بصورت شفاف و عمومی منتشر کردن و هرکسی از جمله خود شما میتونید اونهارو تغییر بدید و یا بهشون اضافه کنید.

حالا ما مجموعه از قوانینی برای سرور ها و کلاینت ها داریم که باهم دیگه سازگاری دارن. یعنی اگر من یه نرم افزار بنویسم که از این قوانین پیروی میکنه و ینفر یه سرور بنویسه و اجرا کنه که با این قوانین سازگار باشه این دو میتونن باهم صحبت کنن و اگر کلاینت دومی هم نوشته بشه باز هم میتونه با اون سرور صحبت کنه.

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

با این حالت حتی خود شما و دوستانتون میتونید یه سرور اجرا کنید که کلاینت های مختلف بهش متصل بشن.

قبل صحبت از مزایای نوستر یک نگاهی به احراز هویت شما بندازیم. وقتی از x استفاده میکنید شما ایمیلتون رو به اون سرور میدید و ثابت میکنید مالک اون هستید که اون ایمیل شامل حجم عظیمی از اطلاعات هست که بعدا باهاش برای شما تبلیغات و محتوای هرزنامه فرستاده میشه. بعد ها شما با یک کلمه عبور مختص x مالکیت اون حساب رو ثابت میکنید و دسترسی به اطلاعاتتون میگیرید.

توی نوستر شما از امضای دیجیتال استفاده میکنید. فرض کنید دوتا عدد خیلی طولانی با یکسری محاسبات ریاضیاتی تولید میشه که یکیش رو بهش میگیم کلید عمومی و یکیش رو بهش میگیم کلید خصوصی. کلید عمومی شما در اصل حکم ایدی x شمارو داره.

وقتی شما یک پست میزارید داخل چندتا سرور نوستر تنها چیزی که از شما وجود داره اون کلید عمومیه و اگر اسمتون یا چیز دیگه ای درکنارش باشه خود شما خواستید قطعا. من که پست شمارو میبنیم با استفاده از فرمول های ریاضیاتی دیگه ای میتونیم مطمن بشم که اون پست رو مالک این کلید عمومی گزاشته نه شخص دیگه ای.

حالا این دو کلید رو ما میتونیم برای رمزنگاری هم استفاده کنیم. اگر شما بخواید پستی بزارید که فقط من ببینم میاید با کلید عمومی من رمزنگاریش میکنید و اونوقت من که کلید خصوصی اون کلید عمومی رو دارم میتونم متنش رو ببینم. یجورایی مثل صندوق پست میمونه. همه میتونن داخلش نامه بزارن و فقط من که مالک صندوق پست هستم میتونم اون رو باز کنم و نامه هارو بخونم.

در این شرایط هیچ واسطی وجود نداره که پیام های مارو ببینه یا بتونه از طرف ما تحت هیچ شرایطی حرف بزنه چون همه چیز با فرمول های ریاضیاتی ای اثبات و رمزنگاری میشه. توی شبکه های اجتماعی کنونی هم رمزنگاری وجود داره اما شما کلید های خودتون رو ندارید و کلید هاتون رو مالک اون شبکه اجتماعی نگه میداره. در اصل پیام های خصوصی شمارو از چشم افرادی غیر از شما کسانی که خواستید و صاحب پلتفرم پنهان خواهد بود. و مورد سوم از اختیار شما خارجه. و اثبات اینکه حرفی رو کسی زده یا نزده با اعتماد به اون پلتفرم که راست میگه مشخص میشه.

اما نوستر صاحبی برای اعتماد نداره. کلید های شما واقعا کلید های شما هستن و پیش خودتون نگهداری میشن.

ما اشاره کردیم که در نوستر چندین سرور و کلاینت مختلف وجود داره که بدون نیاز به اعتماد کردن بهشون (بر اساس داشتن کلید های عمومی خصوصی) وجود دارن و ما به اونا متصل میشیم که هرکدوم ادرس متفاوتی روی اینترنت دارن.

حالا اراعه دهنده اینترنت شما اگر چندین تا از اینارو مسدود کنه شما به چندین به علاوه یکمینش دسترسی خواهید داشت. اگر بیست تا از رله ها شمارو مسدود کنن یا پستی از شمارو منتشر نکنن و ردش کنن یا پاکش کنن شما از طریق بیست و یکمی یا حتی رله شخصی خودتون میتونید پستتون رو منتشر کنید.

توی این شرایط هویت شما همونقدر مشخصه که خودتون میخواید. پیام خصوصی شما خصوصی خواهد موند. حرف شما و ارتباط شما سانسور و فیلتر نخواهد شد. هویت شما به تبلیغ کنندگان و ربات ها فروخته نخواهد شد.

چطوری از نوستر استفاده کنیم؟

اینجا خیلی ساده توضیح میدیم چطوری توی نوستر فعالیت کنیم و ازش استفاده کنیم. شما کافیه یه کلاینت مناسب پیدا کنید و یک کلید خصوصی و عمومی بسازید و به یکسری رله متصل بشید.

تولید کلید های عمومی و خصوصی میتونه با استفاده از اون کلاینت اتفاق بیفته و هیچگونه پیچیدگی نداره. توی این بخش ما یک کلاینت وب معرفی میکنیم اما شما میتونید کلاینت های بیشتری رو از سایت زیر پیدا کنید و اونی که براتون مناسب تر هست رو انتخاب کنید.

https://nostrapps.com

شما میتونید برای با وارد شدن به سایت:

https://iris.to/

یک جفت کلید تولید کنید و به راحتی از این کلاینت استفاده کنید. کلید خصوصی شما یک متنه به هم ریخته هست که پسوند nsec داره رو یک جای امن نگهداری کنید و ترجیحا روی دستگاهی دیجیتالی نگه ندارید.

میتونید به این قسمت برید و کلید خصوصی خودتون رو پیدا کنید:

https://iris.to/settings/keys

همچنین میتونید ۲۴ کلمه منومیک رو نگهدارید که با کلید خصوصی شما برابره اما برای نگهداری روی کاغذ یا به خاطر سپردن ساده تر هست.

این کلید عمومی با گم شدن قابل بازیابی نیست و بشدت مهمه که ازش بصورت امن نگهداری کنید.

همچنین شما یک کلید عمومی با پسوند npub دارید. این حکم ایدی شمارو داره و میتونید خیلی راحت با بقیه به اشتراکتش بزارید تا صفحتون رو پیدا کنن.

میتونید کلید عمومیتون رو به فایل README گیتهاب این کتاب بیفیزایید و کلید عمومی دوستانی که پیشتر این مطلب رو خوندن و کلیدشون رو اونجا به اشتراک گذاشتن رو پیدا کنید و اونار دنبال کنید:

https://github.com/kehiy/persian-nostr-book

ادامه

در ادامه بخش نوستر به زبان ساده مفاهیم کمی پیچیده تر نوستر رو به زبان ساده توضیح میدیم تا بتونید از همه امکانات نوستر استفاده کنید.

برای مثال کلیدتون رو با نرم افزار های امن تر تولید کنید یا اینکه از لایتنینگ و بیتکوین برای پرداخت و دونیت داخل نوستر استفاده کنید و یا ادرس های شخصی سازی شده و کوتاه برای خودتون بزارید و خیلی ساده با دوستاتون به اشتراک بزارید.

برگردان پارسی NIP ها

این بخش یک ترجمه پارسی از مخزن اصلی میباشد:

https://github.com/nostr-protocol/nips

تغییرات مخزن اصلی در این مخزن هم به طور پیوسته اعمال میشود.

نیپ شماره ۱

روشنگری بنیادی روند پروتکل

پیشنویس ‍‍‍‍بایسته(الزامی)

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

رویداد ها و امضا ها

هر کاربر یک جفت کلید دارد. امضا ها کلید های عمومی و رمزگذاری ها بر اساس استاندارد Schnorr signatures standard for the curve secp256k1 انجام میشود.

تنها شی (حالت داده) موجود ‍‍رویداد است که فرمت زیر را دارد:

{
  "id": <32-bytes lowercase hex-encoded sha256 of the serialized event data>, // شناسه
  "pubkey": <32-bytes lowercase hex-encoded public key of the event creator>, // کلید عمومی
  "created_at": <unix timestamp in seconds>, // زمان ساخت شدن رویداد
  "kind": <integer between 0 and 65535>, // نوع

  "tags": [ // برچسب ها
    [<arbitrary string>...],
    // ...
  ],
  "content": <arbitrary string>, // محتوا
  "sig": <64-bytes lowercase hex of the signature of the sha256 hash of the serialized event data, which is the same as the "id" field> // امضا
}

برای محاسبه شناسه رویداد هش sha256 حالت سریالایز شده ان را محاسبه میکنیم.

فرایند سریالایز کردن رویداد ها با استفاده از استاندارد UTF-8 و رشته سریالایز شده جیسان با ساختار زیر اتفاق می افتد:

[
  0,
  <pubkey, as a lowercase hex string>, // کلید عمومی
  <created_at, as a number>, // زمان ساخت بصورت عدد
  <kind, as a number>, // گونه به صورت عدد
  <tags, as an array of arrays of non-null strings>, // برچسب ها له صورت ارایه ای از رشته ها ناتهی
  <content, as a string> // محتوا بصورت رشته
]

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

  • برار رمزگذاری بایذ از UTF-8 استفاده شود.

  • فضا های خالی و خطوط جدید و دگیر فرمت های غیر ضرروی نباید در ساختار جیسان خروجی در نظر گرفته شوند.

  • نشان های زیر در فیلد محتوا (content) باید به شکل زیر نادیده گرفته شوند و دیگر نشان ها باید واژه به واژه در محتوا فراگرفته شوند:

    • برای نشان رفتن به خط بعد (0x0A) باید از \n استفاده شود.

    • برای نشان نقل قول (0x22) باید از \" استفاده شود.

    • برای نشان بک اسلش باید (0x5C) باید از \\ استفاده شود.

    • برای نشان بازگشت carriage (0x0D) باید از \r استفاده شود.

    • برای نشان تب (0x09) باید از \t استفاده شود.

    • برای نشان بک اسپیس باید از (0x08) باید از \b استفاده شود.

    • برای نشان حالت فید (feed) (0x0C) باید از \f استفاده شود.

برچسب ها

هر برچسب ارایه ای از رشته ها با مجموعه ای از قرار داد های مربوط به ان می باشد. به نمونه زیر نگاه کنید:

{
  "tags": [
    ["e", "5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36", "wss://nostr.example.com"],
    ["p", "f7234bd4c1394dda46d09f35bd384dd30cc552ad5541990f98844fb06676e9ca"],
    ["a", "30023:f7234bd4c1394dda46d09f35bd384dd30cc552ad5541990f98844fb06676e9ca:abcd", "wss://nostr.example.com"],
    ["alt", "reply"],
    // ...
  ],
  // ...
}

بخش یکم هر برچسب نام یا کلید برچسب نامیده میشود و بخش دوم مقدار ان. پس ما میتوانیم با خیال راحت بگوییم در نمونه بالا رویداد ما یک برچسب e با مقدار "5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36" و یک برچسب alt با مقدار "reply" دارد.

تمامی بخش ها بعد از دومین نام اصولی ندارند.

این نیپ سه برچسب استاندارد معرفی میکند که در همه رویداد ها با هر گونه ای با معنی یکی استفاده شود:

  • برچسب e برای واگذاری (ارجاع) به رویدادی استفاده میشود: ‍‍["e", <32-bytes lowercase hex of the id of another event>, <recommended relay URL, optional>]

  • برچسب p برای واگذاری به کاربری استفاده میشود: ["p", <32-bytes lowercase hex of a pubkey>, <recommended relay URL, optional>]

  • برچسب a برای واگذاری به یک رویداد (شاید پارامتر شده) قابل جایگزین استفاده میشود:

    • برای رویداد پارامتر شده قابل جایگزین: ["a", <kind integer>:<32-bytes lowercase hex of a pubkey>:<d tag value>, <recommended relay URL, optional>]

    • برای رویداد پارامتر نشده قابل جایگزین: ‍["a", <kind integer>:<32-bytes lowercase hex of a pubkey>:, <recommended relay URL, optional>]

به عنوان یک اصل تمامی بر چسب های تک حرفی با نام های بندواژه (حروف البفا) انگلیسی کوچک و بزرگ توقع میشود کلید ها یا نام ها توسط رله ها فهرست (index) شوند.

به گونه ای که پرس و جو یا دنبال کردن رویداد هایی که به رویداد با شناسه "5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36" واگذاری دارند با استفاده از صافیه (filter) {"#e": ["5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36"]} ممکن باشد.

گونه ها

یک گونه مشخص میکند هر کلاینت چگونه باید معنای هر رویداد و فیلد های ان را تفسیر کند. (برای مثال برچسب در گونه ۱ معنایی داشته باشد و در گونه ۱۰۰۰۲ معنایی کاملا متفاوت داشته باشد."r")

هر نیپ ممکن است معنای مجموعه ای گونه هارا تعریف کند که در جای دیگری تعریف نشده اند. این نیپ گونه های بنیادی ای را تعریف میکند:

  • 0: ‍‍ابرداده(metadata) کاربر: فیلد محتوا با ساختار جیسان رشته شده تنظیم میشود: {name: <username>, about: <string>, picture: <url, string>} کاربری که رویداد را ساخته است را تعریف میکند. فیلد های ابر داده بیشتری میتواند تنظیم شود. رله ها ممکن است رویداد های گونه 0 را حذف کنند اگر رویداد گونه 0 جدیدی برای کلید عمومی یکسانی دریافت کردند.

  • 1: ‍یادداشت متنی: فیلد محتوا با متن خام پر میشود. هر چیزی که کاربر بخواهد بگوید. محتوایی که باید تجزیه شوند (pars) نباید استفاده شود. و کلاینت ها نباید این محتوا را تجزیه کنند.

و همچنین یک اصل برای محدود شماره گونه ها که ازمایش رله هارا اسان تر و پیاده سازی انهارا منعطف تر میکند:

  • یک گونه با شماره ‍n به طوری که: 1000 <= n < 10000 || 4 <= n < 45 || n == 1 || n == 2, رویداد های منظم هستند که انتظار می رود رله همه انهارا نگهداری کند.

  • یک گونه با شماره n به طوری که: 10000 <= n < 20000 || n == 0 || n == 3, رویداد های جایگزین پذیر هستند. یعنی در ازای هر رویداد با این گونه و یک کلید عمومی باید اخرین نسخه ان توسط رله نگهداری شود. نگارش های قدیمی تر ممکن است پاک شوند.

  • یک گونه با شماره n به طوری که 20000 <= n < 30000, رویداد موقت است. یعنی انتظار نمی روند که توسط رله ها ذخیره شوند.

  • یک رویداد با گونه n به طوری که: 30000 <= n < 40000, رویداد جایگزین پذیر پارامتر شده است. یعنی در ازای هر رویداد با این گونه و یک کلید عمومی که یکمین مقدار برچسب d آن هم یکی باشد تنها اخرین رویداد باید توسط رله ذخیره شود. نگارش های قدیمی تر ممکن است پاک شوند.

در مورد گونه جایگزین پذیر دو رویداد با زمان های یکسان رویدادی با با کمترین شناسه (first in lexical order) باید نگهداری شود و دیگری پاک شود.

در زمان پاسخ به پیام REQ برای یک رویداد جایگزین پذیر برای نمونه: ‍{"kinds":[0],"authors":[<hex-key>]} در صورتی که رله چند نسخه از رویداد را داشته باشد باید نسخه اخر را بازگرداند.

اینها تنها اصول هستند. پیاده سازی رله ها میتواند تفاوت داشته باشد.

ارتباط بین رله ها و کلاینت ها

رله ها یک پورت وب سوکت را برای اتصال کلاینت ها آزاد میگزارند. هر کلاینت باید یک اتصال وب سوکت به هر رله برای تمامی اشتراک هایش ایجاد کند. رله ها ممکن است تعداد اتصال های ممکن را برای IP ادرس یا کلاینت خاصی محدود کنند.

از کلاینت به رله: فرستادن رویداد ها و ایجاد اشتراک (subscriptions)

کلاینت ها میتوانند سه نوع پیام ارسال کنند که به صورت یک ارایه جیسان است. این پیام ها به حالت های زیرند:

  • ‍‍["EVENT", <event JSON as defined above>], برای فرستادن رویداد استفاده میشود.
  • ["REQ", <subscription_id>, <filters1>, <filters2>, ...], برای گرفتن یک رویداد و یا ثبت اشتراک برای دریافت رویداد های جدید و بروزرسانی ها استفاده میشود.
  • ["CLOSE", <subscription_id>], برای لغو اشتراک های پیشین استفاده میشود.

‍‍<subscription_id>, مجموعه ای از کاراکتر های دلخواه و غیر خالی و تا حداکثر طول ۶۴ کاراکتر می باشد. که این نشان دهنده یک اشتراک برای دریافت رویداد های جدید در ازاری هر اتصال می باشد.

رله ها این نشانی هارا باید بصورت مستقل برای هر اتصال وب سوکت مدیریت کنند.

این نشانی ها تظمین نشده اند که بصورت همگانی یکتا باشند.

<filtersX> تایین میکند چه رویداد هایی باید در این اشتراک فرستاده شوند. این فیلد میتواند ویژگی های زیر را داشته باشد:

{
  "ids": <a list of event ids>,
  "authors": <a list of lowercase pubkeys, the pubkey of an event must be one of these>,
  "kinds": <a list of a kind numbers>,
  "#<single-letter (a-zA-Z)>": <a list of tag values, for #e — a list of event ids, for #p — a list of pubkeys, etc.>,
  "since": <an integer unix timestamp in seconds. Events must have a created_at >= to this to pass>,
  "until": <an integer unix timestamp in seconds. Events must have a created_at <= to this to pass>,
  "limit": <maximum number of events relays SHOULD return in the initial query>
}

در زمان دریافت یک پیام REQ رله در پایگاه داده داخلی خود رویداد هایی با این ویژگی هارا پیدا میکند و ارسال میکند. سپس این فیلتر را نگهداری میکند و رویداد های اینده مربوط به این فیلتر را میفرستد تا زمانی که اتصال وب سوکت بسته شود.

وقتی یک پیام ‍CLOSE یا یک پیام REQ یا شناسه ای مانند فیلتر پیشین ارسال میشود رله باید فیلتر ذخیره شده را بروزرسانی و بازنویسی کند.

ویژگی هایی که آرایه هستند (مانند شناسه ها گونه ها و نویسنده ها و برچسب ها مانند #e) ارایه های جیسانی با بیش از یک مقدار هستند. حداقل یکی از این مقدار ها باید با یکی از فیلد های رویداد یکی باشد تا رویداد با فیلتر همخوانی داشته باشد. برای ویژگی های اسکالر مانند نویسنده یا شناسه همان ويژگی رویداد باید در فهرست فیلتر موجود باشد. برای ویژگی هایی مانند برچسب #e که هر رویداد میتواند برایش مقادیر متفاوتی داشته باشد رویداد و فیلتر باید حداقل یک مورد یکسان داشته باشند تا شرط بر قرار باشد.

شناسه‌ها نویسندگان فهرست های فیلتر #e و #p باید دارای مقادیر مبنای ۱۶ ۶۴ کاراکتری باشند.

خواص since و until برای محدوده زمانی رویداد های اشتراک استفاده میشوند. اگر فیلتر شامل مقدار since بود تنها رویداد هایی با مقدار created_at برابر و بیشتر از مقدار آن با فیلتر همخوانی خواهند داشت. برای ویژگی ‍‍until مشابه است اما رویداد هایی که ‍created_at کمتر و برابر آن با فیلتر همخوانی دارند.

تمامی شروط فیلتر باید برای یک رویداد همخوانی داشته باشند تا از فیلتر عبور کند. چند شرط در یک فیتلر به عنوان && به حساب میاید.

یک پیام REQ ممکن است چندین فیلتر داشته باشد. در این حالت رویدادی که با هرکدارم از این فیتلر ها همخوانی داشته باشد توسط رله به کلاینت فرستاده میشود. چند فیلتر در یک پیام به عنوان || تفسیر میشود.

مقدار limit تنها برای زمان فرستادن اولیه پیام معتبر است و بعد از آن باید نادیده گرفته شود. زمانی که در یک فیلتر ‍limit: n است توقع میرود n رویداد اخر بر اساس created_at بازگردادنده شود. رویداد های تازه تر باید جلوتر فرستاده شوند. در صورت برابر بودن زمان ساخت رویدادی با کمترین شناسه زودتر فرستاده میشود (first in lexical order). رویداد ها میتواند کمتر از مقدار n باشد اما نمیتواند زیادی بیشتر از آن باشد که کلاینت با مقدار زیاد اطلاعات غرق شود.

از رله به کلاینت: فرستادن رویداد ها و اطلاعیه ها

رله ها میتوانند ۵ نوع پیام بفرستند. که باید بصورت ارایه جیسان باشند بر اساس حالت زیر باشند:

  • ["EVENT", <subscription_id>, <event JSON as defined above>], برای فرستادن رویداد درخواست شده به کلاینت استفاده میشود.
  • ["OK", <event_id>, <true|false>, <message>], برای تایید یا رد شدن رویداد فرستاده شده استفاده میشود.
  • ["EOSE", <subscription_id>], برای اعلام پایان رویداد های ذخیره شده و شروع فرستادن رویداد های تازه در حالت بی درنگ استفاده میشود.
  • ["CLOSED", <subscription_id>, <message>], برای اعلام پایان یک اشتراک در سمت سرور (رله) استفاده میشود.
  • ["NOTICE", <message>], برای فرستادن متن های خطا قابل خواندن توسط انسان و چیز های دیگر به سمت کلاینت استفاده میشود.

این NIP هیچ قانونی برای نحوه رفتار و فرستادن پیام NOTICE تعریف نمیکند.

  • EVENT فقط زمانی باید فرستاده شود که با شناسه اشتراک که در یک پیام REQ که پیشتر تعریف شده فرستاده شده باشد.

  • OK این پیام باید در پاسخ به پیام EVENT فرستاده شود. مقدار سوم باید وجود داشته باشد که اگر رویداد با موفقیت فرستاده شده بود مقدار باید true و در غیر این صورت باید false باشد. مقدار چهارم میتواند در صورت موفقیت ارسال یک رشته خالی باشد یا یک رشته که با یک کلمه قابل خواندن توسط ماشین و یک : و بعد از آن یک متن قابل خواندن توسط انسان باشد. چند نمونه:

    • ["OK", "b1a649ebe8...", true, ""]
    • ["OK", "b1a649ebe8...", true, "pow: difficulty 25>=24"]
    • ["OK", "b1a649ebe8...", true, "duplicate: already have this event"]
    • ["OK", "b1a649ebe8...", false, "blocked: you are banned from posting here"]
    • ["OK", "b1a649ebe8...", false, "blocked: please register your pubkey at https://my-expensive-relay.example.com"]
    • ["OK", "b1a649ebe8...", false, "rate-limited: slow down there chief"]
    • ["OK", "b1a649ebe8...", false, "invalid: event creation date is too far off from the current time"]
    • ["OK", "b1a649ebe8...", false, "pow: difficulty 26 is less than 30"]
    • ["OK", "b1a649ebe8...", false, "error: could not connect to the database"]
  • CLOSED در پاسخ یک پیام REQ فرستاده میشود زمانی که یک رله به آن پاسخ داده یا ان را رد کرده است. همچنین زمانی که رله تصمیم بر از بین بردن اشتراک قبل از قطع اتصال یا دریافت پیام CLOSE توسط یک کلاینت را دارد استفاده میشود. این پیام از طرحی مشابه با پیام OK استفاده میکند که با یک پیشوند قابل خواندن توسط ماشین و ادامه ان بصورت قابل خواندن برای انسان می باشد. چند نمونه:

    • ["CLOSED", "sub1", "duplicate: sub1 already opened"]
    • ["CLOSED", "sub1", "unsupported: filter contains unknown elements"]
    • ["CLOSED", "sub1", "error: could not connect to the database"]
    • ["CLOSED", "sub1", "error: shutting down idle subscription"]
  • مقادیر استاندارد برای پیام های OK و CLOSE: duplicate, pow, blocked, rate-limited, invalid هستند و error برای زمانی که هیچ یک از مقادیر مناسب نیست استفاده میشود.

نیپ شماره ۲

فهرست دنبال شوندگان

پایانی ‍‍دلبخواهی

یک رویداد ویژه با گونه 3 به عنوان لیست دنبال شوندگان تعریف میشود. که دارای برچسب های p است که نشاندهنده افراد دنبال شده یا شناخته شده است.

هر برچسب باید کلید نمایه و ادرس رله ای که رویداد های ان نمایه را میتوان پیدا کرد (درصورت نبود نیاز میتواند خالی باشد.) و یک نام اختصاری (میتواند در صورت نبود نیاز خالی باشد یا اراعه نشود.) داشته باشد. برای مثال:

["p", <32-bytes hex key>, <main relay URL>, <petname>]

فیلد محتوا (.content) استفاده نمی شود.

برای مثال:

{
  "kind": 3,
  "tags": [
    ["p", "91cf9..4e5ca", "wss://alicerelay.com/", "alice"],
    ["p", "14aeb..8dad4", "wss://bobrelay.com/nostr", "bob"],
    ["p", "612ae..e610f", "ws://carolrelay.com/ws", "carol"]
  ],
  "content": "",
  ...other fields
}

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

هر زمان که دنبال شونده ای به فهرست افزوده شد کلاینت باید ان را به پایان ارایه بفزاید (append) پس فهرست به ترتیب زمانی نگهداری میشود.

استفاده ها

پشتبان گیری فهرست دنبالشوندگان

اگر کسی بر این باور باشد که یک رله رویداد های ان را برای زمان مناسبی نگه میدارد میتواند از رویداد گونه ۳ برای پشتبانی گیری فهرست دنبالشونگان خود و بازیابی ان در دستگاه های دیگر خود استفاده کنند.

کشف نمایه و تقویت زمینه

یک کلاینت میتواند از گونه ۳ برای نمایش فهرست دنبال شوندگان استفاده کند. یا افرادی را برای دنبال کردن بر اساس دنباشوندگان افرادی که شخصی دنبال میکند یا مرور میکند پیشنهاد دهد. یا داده هارا در پس زمینه های دیگری نشان دهد.

اشتراک گذاری رله

یک کلاینت ممکن فهرست دنبالشوندگانش را با یک رله خوب برای هر یک از دنبالشوندگان خود منتشر کند. کلاینت های دیگر میتواندد فهرست داخلی رله های خود را برای افزایش مقاومت در برابر سانسور در صورت نیاز بروزرسانی کنند.

طرح نام اختصاری

یک کلاینت میتواند از فهرست دنبالشوندگان افراد دیگر استفاده کند تا یک جدول از نام (http://www.skyhunter.com/marcs/petnames/IntroPetNames.html)[اختصاری] بسازد. این کار نیاز به نام های همگانی قابل خوانده شدن توسط انسان را کاهش میدهد.

یک کاربر یک فهرست دنبالشوندگان درونی دارد:

[
  ["p", "21df6d143fb96c2ec9d63726bf9edc71", "", "erin"]
]

و دو فهرست دنبالشوندگان دریافت میکند یکی از 21df6d143fb96c2ec9d63726bf9edc71 که میگوید:

[
  ["p", "a8bb3d884d5d90b413d9891fe4c4e46d", "", "david"]
]

و یکی از a8bb3d884d5d90b413d9891fe4c4e46d که میگوید:

[
  ["p", "f57f54057d2a7af0efecc8b0b66f5708", "", "frank"]
]

وقتی کاربر 21df6d143fb96c2ec9d63726bf9edc71 را میبنید کلاینت میتواند به جای ان erin را نمایش دهد. وقتی کاربر a8bb3d884d5d90b413d9891fe4c4e46d را میبیند کلاینت میتواند david.erin را نمایش دهد. وقتی کاربر ‍‍f57f54057d2a7af0efecc8b0b66f5708 را میبنید کلاینت میتواند frank.david.erin را نمایش دهد.

نیپ شماره ۳

گواهی OpenTimestamps برای رویداد ها

پیشنویس دلبخواهی

این نیپ یک رویداد با گونه ‍kind:1040 تعریف میکند که یک اثبات OpenTimestamps برای هر رویداد دیگیری دارد:

{
  "kind": 1040
  "tags": [
    ["e", <event-id>, <relay-url>],
    ["alt", "opentimestamps attestation"]
  ],
  "content": <base64-encoded OTS file data>
}
  • مدرک OpenTimestamps باید شناسه رویداد مرجع را به عنوان هش خود ثابت کند.

  • محتوا (content) باید به شکل کامل محتوای یک فایل .ots باشد که حداقل شامل یک گواهی بیت کوین است. این فایل باید شامل یک گواهی بیت کوین باشد (زیرا وجود بیش از یک گواهی معتبر لازم نیست و حجم کمتر بهتر از بیشتر است.) و نباید به گواهی‌ های در انتظار اشاره کند زیرا آنها در این زمینه بی‌ فایده هستند.

روند نمونه بررسی سلامت OpenTimestamps

با استفاده از nak, jq و ots:

~> nak req -i e71c6ea722987debdb60f81f9ea4f604b5ac0664120dd64fb9d23abc4ec7c323 wss://nostr-pub.wellorder.net | jq -r .content | ots verify
> using an esplora server at https://blockstream.info/api
- sequence ending on block 810391 is valid
timestamp validated at block [810391]

اخطار پیشنهاد نشده: به دنبال نیپ شماره هفده منسوخ شده است.

نیپ شماره 4

پیام مستقیم رمزنگاری شده

نهایی پیشنهاد نشده ‍‍دلبخواهی

یک رویداد ویژه با گونه 4 به معنای پیام مستقیم رمزنگاری شده است. انتظار میرود که این رویداد ویژگی های زیر را داشته باشد:

متن باید برابر با رشته‌ای باشد که به صورت base64 رمزنگاری شده و با استفاده از aes-256-cbc رمزگذاری شده است و هر چیزی که یک کاربر می‌خواهد بنویسد را شامل می‌شود. این رمزگذاری با استفاده از یک رمز مشترک انجام می‌گیرد که با ترکیب کلید عمومی گیرنده و کلید خصوصی فرستنده ایجاد شده است. این متن باید به همراه رشته‌ ابتدایی (initialization vector) که به صورت base64 رمزنگاری شده است به عنوان یک پارامتر نام‌گذاری شده با عنوان "iv" اضافه شود. فرمت بدین صورت است: "content": "<encrypted_text>?iv=<initialization_vector>".

برچسب ها ممکن است یک شامل شناسه دریافت کننده پیام باشند (در این صورت رله ها ممکن است به طور طبیعی رویداد را به انها بفرستند.) به شکل: ["p", "<pubkey, as a hex string>"].

برچسب ها ممکن است شامل شناسه پیام قبلی مکالمه یا پیامی که ما صراحتا به ان پاسخ میدهیم (به طوری که ممکن است پیام های سازمان یافته تری رخ دهد.) به صورت ["e", "<event_id>"] باشند.

یادداشت: به طور پیشفرض در پیاده سازی libsecp256k1 ECDH کلید مخفی برابر با هش SHA256 نقطه مشترک (هر دو مختصات X و Y) است. در نوستر فقط مختصات X نقطه مشترک به عنوان کلید مخفی استفاده می‌شود و این مقدار هش نمی‌شود. اگر از کتابخانه libsecp256k1 استفاده می‌کنید، باید یک تابع سفارشی که مختصات X را کپی می‌کند به عنوان آرگومان hashfp در تابع secp256k1_ecdh منتقل کنید. ببینید.

کد منبع نمونه برای تولید چنین رویدادی با جاوااسکریپت:

import crypto from 'crypto'
import * as secp from '@noble/secp256k1'

let sharedPoint = secp.getSharedSecret(ourPrivateKey, '02' + theirPublicKey)
let sharedX = sharedPoint.slice(1, 33)

let iv = crypto.randomFillSync(new Uint8Array(16))
var cipher = crypto.createCipheriv(
  'aes-256-cbc',
  Buffer.from(sharedX),
  iv
)
let encryptedMessage = cipher.update(text, 'utf8', 'base64')
encryptedMessage += cipher.final('base64')
let ivBase64 = Buffer.from(iv.buffer).toString('base64')

let event = {
  pubkey: ourPubKey,
  created_at: Math.floor(Date.now() / 1000),
  kind: 4,
  tags: [['p', theirPublicKey]],
  content: encryptedMessage + '?iv=' + ivBase64
}

اخطار امنیتی

این استاندارد به هیچ وجه به چیزی که به عنوان آخرین پیشرفت‌ ها در ارتباطات رمزگذاری شده بین همتاها در نظر گرفته می‌شود نزدیک نمی‌شود و metadata را در رویدادها نشت می‌کند. بنابراین، نباید برای هیچ چیزی که به واقع نیاز دارید محرمانه بماند استفاده شود و فقط باید با رله‌هایی که از AUTH برای محدود کردن اینکه چه کسی می‌تواند رویدادهای نوع:4 شما را برداشت کند استفاده شود.

اخطار پیاده سازی کلاینت

کلاینت نباید کلید های عمومی را در .content جستجو و جایگذاری کند. اگر مثل یک متن معمولی پردازش شود و @npub... با #[0] و یک برچسب ["p", "..."] جایگذاری شود. برچسب ها به بیرون نشت می شود و کاربران نام برده پیام را در صندوق ورودی خود دریافت میکنند.

نیپ شماره 5

نگاشت کلیدهای Nostr به شناسه های اینترنتی مبتنی بر DNS

نهایی دلبخواهی

در رویداد های گونه ۰ (متادیتا کاربر) یک کلید به نام nip05 (https://datatracker.ietf.org/doc/html/rfc5322#section-3.4.1)[میتواند ادرس شناسه گر اینترنتی] (ادرسی ایمیل مانند) را به عنوان مقدار داشته باشد. هرچند که لینک به مشخصات شناسه گر اینترنتی در بالا وجود دارد اما نیپ ۵ تصور میکند که <local-part> به کاراکتر های a-z0-9-_. حساس است و حساستی به کوچکی و بزرگی کاراکتر ها ندارد.

با دیدن این ادرس کلاینت ادرس را به دو قسمت domain و <local-part> تقسیم میکند و از این مقادیر برای ایجاد یک درخواست GET به https://<domain>/.well-known/nostr.json?name=<local-part> استفاده میکند.

خروجی باید یک شی جیسان با کلید به نام "names" داشته باشد که به کلید های عمومی ای در مبنای ۱۶ اشاره کند. اگر کلید عمومی مربوط به <name> با کلید عمومی کاربری که این شناسه در رویداد متادیتا او قرارداشته برابر باشد کلاینت میتواند نتیجه بگیرد که کلید عمومی با این شناسه هم میتواند شناخته شود.

نمونه

اگر کلاینت رویدادی همچون رویداد زیر دید:

{
  "pubkey": "b0635d6a9851d3aed0cd6c495b282167acf761729078d975fc341b22650b07b9",
  "kind": 0,
  "content": "{\"name\": \"bob\", \"nip05\": \"bob@example.com\"}"
  ...
}

یک درخواست GET به ادرس https://example.com/.well-known/nostr.json?name=bob ایجاد میکند و چنین پاسخی میگیرد:

{
  "names": {
    "bob": "b0635d6a9851d3aed0cd6c495b282167acf761729078d975fc341b22650b07b9"
  }
}

یا به همراه ویژگی رله ها پیشنهاد شده:

{
  "names": {
    "bob": "b0635d6a9851d3aed0cd6c495b282167acf761729078d975fc341b22650b07b9"
  },
  "relays": {
    "b0635d6a9851d3aed0cd6c495b282167acf761729078d975fc341b22650b07b9": [ "wss://relay.example.com", "wss://relay2.example.com" ]
  }
}

اگر کلید عمومی با کلید عمومی داده شده در "names" برابر بود به این معنا است که وابستگی معتبر است و نشانی نیپ ۵ میتواند نمایش داده شود.

ویژگی رله های پیشنهادی میتواند شامل کلید های عمومی به عنوان کلید و ارایه ای از ادرس رله ها به عنوان مقدار باشد. اگر این مقدار وجود داشت میتواند به کلاینت کمک کند تا بفهمد در کدام رله ها میتواند رویداد های مربوط به کلید عمومی داده شده را پیدا کند. وب سرور هایی که .well-known/nostr.json را بصورت پویا اراعه میکنند باید فهرست رله های پیشنهادی را هم در صورت وجود در همان درخواست برگردانند.

پیدا کردن کاربر ها با استفاده از شناسه نیپ ۵

یک کلاینت ممکن است پشتیبانی از یافتن کاربران با استفاده از شناسه گر اینترنتی را پیاده سازی کند. روند همچون پیش است اما برعکس: نخست کلاینت ادرس well-known را میگیرد سپس از خروجی کلید عمومی کاربر را بدست می اورد و کوشش میکند تا رویداد گونه ۰ کاربر را پیدا کند و بررسی کند که ادرس نیپ ۵ با ادرس نیپ ۵ در رویداد گونه ۰ کاربر برابر است یا نه.

یادداشت ها

کلاینت همیشه باید کلید های عمومی را دنبال کند نه ادرس های نیپ ۵ را

برای نمونه بعد از یافتن نشانی bob@bob.com که کلید عمومی abc...def را دارد کاربر بر روی دکمه دنبال کردن در آن پروفایل کلیک میکند. کلاینت باید مرجع اولیه و اصلی abc...def را نگهدارد و نه نشانی bob@bob.com را. اگر بنا به هر دلیلی در اینده ادرس https://bob.com/.well-known/nostr.json?name=bob شروع به بازگرداندن کلید عمومی 1d2...e3fکرد کلاینت نباید در فهرست دنبال شوندگان خود کلید عمومی abc...def را برای برای ان کاربر جایگزین کند. (اما باید از نمایش دادن ادرس bob@bob.com برای ان کاربر دست نگه دارد زیرا این دیگر به یک ویژگی "nip05" نامعتبر تبدیل شده است.)

کلید عمومی باید در مبنای ۱۶ (hex) باشد

کلید ها باید در مبنای ۱۶ (hex) برگردانده شوند. کلید های NIP-19 در فرمت npub برای نمایش در رابط کاربری کلاینت ها به وجود امده اند نه برای استفاده در این نیپ.

پیشنهاد پیاده سازی کاوش/کشف کاربر

یک کلاینت همچنین میتواند از این استفاده کند تا به کاربر اجازه دهند پروفایل کاربران را جستجو کند. اگر یک کلاینت سرچ باکس ای داشت کاربر میتواند "bob@bob.com"را انجا جستجو کند و کلاینت میتواند این را تشخیص دهد و درخواست های لازم برای بدست اوردن کلید عمومی را ایجاد کند و ان را به کاربر پیشنهاد دهد.

نشان دادن دامنه تنها به عنوان نشانی

کلاینت ها ممکن است شناسه _@domain را به عنوان شناسه ریشه در نظر بگیرند. و بخواهند که ان را بصورت <domain> نمایش دهند. برای نمونه اگر bob مالک دامنه bob.com است او شاید نخواهد نشانی به صورت bob@bob.comداشته باشد زیرا بخشی اضافی دارد. بجای این باب میتواند از شناسه "_@bob.com" استفاده کنید و توقع داشته باشد که کلاینت های نوستر از "bob.com" برای نمایش استفاده کنند و برای همه استفاده ها از این استفاده کنند.

دلیل استفاده از ساختار /.well-known/nostr.json?name=<local-part>

با افزودن <local-part> به صورت یک رشته پرس و جو (query string) بجای بخشی از مسیر ادرس پروتکل میتواند بصورت همزمان از سرور هایی که بصورت پویا و برحسب تقاضا JSON تولید میکنند و هم از سرور هایی که بصورت ایستا JSON ای که شامل چند نام میباشد را داشته باشند پشتبانی کند.

اجازه دسترسی از برنامه های جاوا اسکریپت

برنامه های نوستر جاوااسکریپتی ممکن است به دلیل سیاست های(https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)[CORS] مرورگر از دسترسی به مسیر /.well-known/nostr.json در دامنه کاربر محدود شده باشند. زمانی که جاوااسکریپت به دلیل CORS نمیتواند منبعی را بارگیری کند برنامه ان را خطایی مربوط به شبکه میشناسد میگویید منبع وجود ندارد. پس برنامه نمیتواند به کاربر بگویید که خطا به دلیل مشکل CORS است. برنامه های جاوااسکریپتی نوستر که خطا های مربوط به شبکه در گرفتن فایل موجود در مسیر /.well-known/nostr.json بر میخورند میتوانند به کاربر پیشنهاد دهند که سیاست های CORS سرور خود را مورد بررسی قرار دهند. برای نمونه:

$ curl -sI https://example.com/.well-known/nostr.json?name=bob | grep -i ^Access-Control
Access-Control-Allow-Origin: *

کاربر باید مطمن شوند که مسیر /.well-known/nostr.json با HTTP header Access-Control-Allow-Origin: * سرو میشود تا مطمن باشند که برنامه های جاوااسکریپتی که بر روی مرورگر های به روز اجرا میشوند میتوانند ان را اعتبارسنجی کنند.

محدودیت های امنیتی

مسیر /.well-known/nostr.json نباید هیچ گونه تغییر مسیر HTTP ای را برگرداند. صدا زنندگان این ادرس باید هرگونه تغییر مسیر مربوط به /.well-known/nostr.json را نادیده بگیرند.

نیپ شماره 6

اشتقاق کلید از واژگان نمونیک

پیشنویس دلبخواهی

بیپ ۳۹ (https://bips.xyz/39) برای تولید واژگان نمونیک (mnemonic) و مشتق کردن یک دانه باینری از انها استفاده میشود.

بیپ ۳۲ (https://bips.xyz/32) برای مشتق کردن مسیر ‍‍m/44'/1237'/<account>'/0/0 استفاده میشود. (مطابق با ورودی نوستر در سلیپ ۴۴ (https://github.com/satoshilabs/slips/blob/master/slip-0044.md))

یک کلاینت ابتدایی یا ساده میتواند account ای برابر با 0 را برای تولید یک کلید استفاده کند. برای استفاده های حرفه ای تر شما میتوانید account را افزایش دهید برای امکان تولید کلیدهای عملا بی نهایت از مسیر 5 سطحی با استخراج سخت شده.

گونه های دیگر کلاینت ها میتوانند همچنان از گونه های دیگر مسیر اشتقاق برای اهداف دیگر خود استفاده کنند.

بردار های تست (نمونه های تست)

mnemonic: leader monkey parrot ring guide accident before fence cannon height naive bean private key (hex): 7f7ff03d123792d6ac594bfa67bf6d0c0ab55b6b1fdb6249303fe861f1ccba9a nsec: nsec10allq0gjx7fddtzef0ax00mdps9t2kmtrldkyjfs8l5xruwvh2dq0lhhkp public key (hex): 17162c921dc4d2518f9a101db33695df1afb56ab82f5ff3e5da6eec3ca5cd917 npub: npub1zutzeysacnf9rru6zqwmxd54mud0k44tst6l70ja5mhv8jjumytsd2x7nu


mnemonic: what bleak badge arrange retreat wolf trade produce cricket blur garlic valid proud rude strong choose busy staff weather area salt hollow arm fade private key (hex): c15d739894c81a2fcfd3a2df85a0d2c0dbc47a280d092799f144d73d7ae78add nsec: nsec1c9wh8xy5eqdzln7n5t0ctgxjcrdug73gp5yj0x03gntn67h83twssdfhel public key (hex): d41b22899549e1f3d335a31002cfd382174006e166d3e658e3a5eecdb6463573 npub: npub16sdj9zv4f8sl85e45vgq9n7nsgt5qphpvmf7vk8r5hhvmdjxx4es8rq74h

نیپ شماره 7

قابلیت window.nostr برای مرورگر های وب

پیشنویس دلبخواهی

شی window.nostr ممکن است توسط مرورگر وب یا اکستنشن ها در دسترس قرار گیرد و وب اپلیکیشن ها و وبسایت ها ممکن است بعد از بررسی موجود بودن ان از ان استفاده کنند.

این شی (Object) باید متد های زیر را تعریف کند:

async window.nostr.getPublicKey(): string // returns a public key as hex
async window.nostr.signEvent(event: { created_at: number, kind: number, tags: string[][], content: string }): Event // takes an event object, adds `id`, `pubkey` and `sig` and returns it

در کنار دو متد ابتدایی بالا این متد ها بصورت دلبخواهی میتوانند پیاده سازی شوند:

async window.nostr.getRelays(): { [url: string]: {read: boolean, write: boolean} } // returns a basic map of relay urls to relay policies
async window.nostr.nip04.encrypt(pubkey, plaintext): string // returns ciphertext and iv as specified in nip-04 (deprecated)
async window.nostr.nip04.decrypt(pubkey, ciphertext): string // takes ciphertext and iv as specified in nip-04 (deprecated)
async window.nostr.nip44.encrypt(pubkey, plaintext): string // returns ciphertext as specified in nip-44
async window.nostr.nip44.decrypt(pubkey, ciphertext): string // takes ciphertext as specified in nip-44

پیشنهاد برای توسعه دهندگان اکستنشن های مرورگر

برای اطمینان حاصل کردن از اینکه nostr.window برای کلاینت ها در حین بارگیری صفحه در دسترس است توسعه دهنده اکستنشن که اکتنشن هایی برای فایرفاکس و کرومیوم مینویسند باید اسکریپت خود را با مشخص کردن "run_at": "document_end" در ‍‍manifest اکستنشن خود بارگیری کنند.

پیاده سازی ها

ببینید: https://github.com/aljazceru/awesome-nostr#nip-07-browser-extensions

اخطار پیشنهاد نشده: به دنبال نیپ شماره بیست و هفت منسوخ شده است.

نیپ شماره 8

مدیریت اشاره ها (mention)

نهایی پیشنهاد نشده اختیاری`

این مستند روش منشن کردن (اشاره کردن/نام بردن) رویداد ها یا کلید های عمومی دیگر را در فیلد کانتنت هر رویداد یادداشت متنی را برای کلاینت ها استاندارد میکند.

کلاینت هایی که میخواهند منشن را پشتیبانی کنند باید یک جز (component) تکمیل خودکار یا چیزی شبیه به ان را زمانی که کاربر چیز به خصوصی مانند @ را مینویسد و یا دکمه ای برای افزدون یک منشن کلیک میکند نمایش دهد. یا با هر روشی باید به نحوی بدون ابهام بین منشن و متن عادی تفاوتی قاعل شود.

زمانی که منشن شناسایی شد. برای نمونه کلید عمومی ‍‍27866e9d854c78ae625b867eefdfa9580434bc3e675be08d2acb526610d96fbe کلاینت باید کلید عمومی را به برچسب ها بیفزاید. با یک برچسب p. و سپس مرجع متنی درون فیلد محتوا را با نشاشنه #[index] جایگزین کند. جایی که index شماره قرار گرفتن تگ p مد نظر در تگ ها میباشد (شمارش ایندکس ها از صفر).

روند مشابه ای برای منشن کردن رویداد ها هم استفاده میشود.

کلاینتی که یک یادداشت متنی دریافت میکند که محتوای ان شامل #[index] می باشد میتواند محتوا اصلی را در برچسب های p و یا e جستجو کند و با ان جایگزین کند. و انجام هر فرایند دلخواهی همچون نمایش پیش نمایشی از رویداد منشن شده یا افزدودن پیوند به ان نمایه.

جایی که #[index] خارج از تعداد اجزای برچسب ها بود و یا به برچسب هایی غیر از e و یا ‍p اشاره کند کلاینت نباید ان را جایگزین کند یا چیز ویژه ای نمایش دهد و متن را به حالت اصلی نشان دهد.

مقدمه