مقدمه
این کتاب شامل منابعی برای افراد مختلف جهت یادگیری اموزش استفاده یا توسعه نوستر میباشد.
در بخش نوستر به زبان ساده کوشش میکنیم تا نوستر را به سادگی برای کاربران تازه اموزش دهیم.
در بخش 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 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
اشاره کند کلاینت نباید ان را جایگزین کند یا چیز ویژه ای نمایش دهد و متن را به حالت اصلی نشان دهد.
نیپ شماره 9
درخواست پاک کردن رویداد
پیش نویس
دلبخواهی
یک رویداد ویژه با شماره گونه ۵ به معنای درخواست پاک کردن یک رویداد است. که فهرستی از یک یا چند تگ e و/یا a دارد که ارجاع داده میشود به رویدادی که مالک ان میخواهد پاک شود. درخواست پاک کردن باید یک تگ k را شامل شود که شماره گونه هر رویدادی است که درخواست میشود که پاک شود.
بخش محتوا رویداد ممکن است با یک یادداشت راجع به دلیل این درخواست پر شود.
برای نمونه:
{
"kind": 5,
"pubkey": <32-bytes hex-encoded public key of the event creator>,
"tags": [
["e", "dcd59..464a2"],
["e", "968c5..ad7a4"],
["a", "<kind>:<pubkey>:<d-identifier>"],
["k", "1"],
["k", "30023"]
],
"content": "these posts were published by accident",
// other fields...
}
رله ها باید از نشر و نگهداری هر رویداد پاک شده که مالک ان کلید عمومی درخواست کننده است خودداری کنند. کلاینت ها باید رویداد را پنهان کنند یا وضعیت ان را بصورت پاک شده نشان دهند.
رله هااز انجایی که ممکن است کلاینت ها رویداد های پاک شده را داشته باشند به نشر درخواست پاک شدن ادامه دهند. همچنین کلاینت ها باید درخواست را به رله هایی که رویداد پاک کردن را ممکن است نداشته باشند بفرستند.
وقتی از یک تگ a استفاده میشود رله باید تمام نگارش های رویداد جایگزین پذیر را تا زمان created_at رویداد پاک کنند.
استفاده کلاینت ها
کلاینت ها ممکن است بخواهند که رویدادهایی را که توسط رویدادهای درخواست پاک کردن معتبری به آنها ارجاع داده شده است را به طور کامل پنهان کنند. این شامل یادداشتهای متنی، پیامهای مستقیم یا دیگر انواع رویدادهایی است که هنوز تعریف نشدهاند.
از طرف دیگر ممکن است رویداد را همراه با نماد یا نشانه ای نشان دهند که نویسنده آن رویداد را پاک کرده است. بخش محتوا ممکن است برای جایگزینی محتوای خود رویدادهای پاک شده نیز استفاده شود هرچند یک رابط کاربری باید به وضوح نشان دهد که این دلیل درخواست پاک کردن است، نه محتوای رویداد.
کلاینت باید قبل از پنهان کردن یا پاک هر رویدادی تا یید کند که هر رویداد کلید عمومی که در تگ e درخواست پاک کردن ارجاع شده است، با کلید عمومی درخواست پاک کردن یکی است. رله ها به طور کلی نمی توانند این اعتبار سنجی را انجام دهند و نباید معتبر حساب شوند.
کلاینت ها رویداد درخواست پاک کردن را به هر شکلی که انتخاب کنند میتوانند نمایش دهند، برای نمونه اصلا نشان ندهند یا با یک اطلاعیه برجسته ان را نمایش دهند.
کلاینت ها ممکن است بخواهند به کاربر اطلاع دهند که درخواست پاک کردن پاک شدن رویداد را ضمانت نمیکند چرا که پاک کردن یک رویداد از تمام رله ها و کلاینت ها ممکن نیست.
استفاده رله ها
رله ها ممکن است تایید کنند که یک رویداد درخواست پاک کردن فقط به رویدادهایی اشاره میکند که همان کلید عمومی خود درخواست پاک کردن را دارند، اما این مورد اجباری نیست زیرا رله ها ممکن است از همه رویدادهای اشاره شده باخبر نباشد.
درخواست پاک کردن یک رویداد درخواست پاک کردن
انتشار یک رویداد برای پاک کردن یک درخواست پاک کردن بی تاثیر است. رله ها و کلاینت ها مجبور به پشتیبانی ویژگی لغو درخواست پاک کردن نیستند.
نیپ شماره 10
راجع به تگ های p و e در رویداد های متنی (گونه ۱)
پیش نویس
دلبخواهی
چکیده
این نیپ توضیح میدهد که چگونه از تگ های e و p در رویداد های متنی استفاده شود. بخصوص رویداد هایی که درپاسخ به رویداد های متنی دیگری ارسال شده اند. این به کلاینت ها کمک میکند تا پاسخ ها را در رشته ای درختی با رویداد اصلی به عنوان ریشه درخت قرار دهد.
تگ e موقعیتی (منسوخ شده)
این رویه در استفاده است اما باید به عنوان منسوخ شده در نظر گرفته شود.
["e",
به طوری که:
: شناسه رویداد ارجاع داده شده است. : ادرس رله پیشنهادی برای رویداد ارجاع داده شده. کلاینت های زیادی این را دلبخواهی در نظر میگیرند.
موقعیت تگ e در رویداد معنا های متفاوتی دارد:
-
بدون تگ e: این رویداد یک پاسخ نیست و به رویدادی ارجاعی ندارد.
-
یک تگ e: ["e",
]: ایدی رویدادی که این رویداد پاسخ به ان است. -
دو تگ e ["e",
], ["e", ]: : شناسه رویدادی که در ریشه زنجیره پاسخ ها قرار دارد. : شناسه رویدادی که این رویداد به ان اشاره میکند. -
چند تگ e ["e",
] ["e", ], ..., ["e", ]: ممکن است هر تعداد شناسه وجود داشته باشد که میتواند در زنجیره پاسخ ها باشند یا نباشند که از این رویداد استناد میکنند. root-id و reply-id همچون موارد قبل اند.
این روند منسوخ شده چرا که وقتی یک رویداد به رویداد دیگری ارجاع میدهد اما یک پاسخ نیست ابهاماتی پیچیده یا حتی غیرقابل حل ایجاد میکند.
تگ e علامت گزاری شده (ترجیحی)
["e",
به طوری که:
*
-
: ادرس رله پیشنهادی برای رویداد ارجاع داده شده. کلاینت باید یک ادرس معتبر قرار دهد. کلاینت ممکن است این فیلد را یک رشته خالی قرار دهد. -
: دلبخواهی است و اگر وجود داشته باشد یکی از موارد reply یا root یا mention است. -
: دلبخواهی است و باید شناسه مالک رویداد ارجاع شده باشد.
مواردی که با "reply" نشانه گذاری شده اند نشان دهنده شناسه رویدادی است که به آن پاسخ داده شده است. موارد نشانه گذاری شده با "root" شناسه رویداد ریشه رویدادی است که به ان پاسخ داده شده است. برای پاسخ های سطح بالا (رویداد هایی که مستقیما به ریشه اشاره میکنند.) تنها نشانه root باید استفاده شود. مواردی که با "mention" نشانه گذاری شده اند نشان دهنده شناسه یک رویداد نقل قول شده یا بازنشر شده اند.
یک پاسخ مستقیم به رویداد ریشه باید تنها یک تگ e با نشانه گذاری root داشته باشد.
این روند ترجیح داده شده است زیرا اجازه میدهد رویداد به رویداد های دیگر اشاره کند بدون اینکه با
یا اشتباه گرفته شوند.
تگ p
یک فهرست است کلید های عمومی افرادی که در ریک رشته پاسخ درگیر هستند در رویداد های متنی.
زمانی که به یک رویداد پاسخ داده میشود تگ های p پاسخ برابر با تمام تگ های p خود رویداد و کلید عمومی ان رویداد است.
برای نمونه: یک رویداد متنی با مالکیت a1 با تگ های p: [p1, p2, p3] سپس تگ های p پاسخ به این رویداد باید به صورت [a1, p1, p2, p3] بدون اهمیت ترتیب باشد.