من أي شبكة
./scripts/1-node.sh serve --domain node.example.org # or: --tailscaleيعمل casty web على جهازك ويصل إلى هاتف على الشبكة نفسها. أما 1-node.sh serve فيشغّل الصفحة نفسها
على مضيف العقدة، بجانب العقدة، خلف وكيل ينهي HTTPS، فيصل إليها الهاتف من شبكة الهاتف المحمول أيضًا.
إنها شيفرة casty نفسها، مبنية على المضيف داخل حاوية من هذه النسخة، وتقرأ وتكتب عبر العقدة بوصفها
http://snapchain:3381 على شبكة Docker الخاصة بالمضيف.
ما يفعله
Section titled “ما يفعله”- يقرأ مجلد إعدادات casty هنا (
~/.config/casty، أو--config): الملفconfig.jsonمع معرّف fid الخاص بك، وkeys.enc.jsonمع مفتاح التطبيق، ويطلب كلمة مرور مخزن المفاتيح. مع--read-only، لا يغادر هذا الجهاز لا مخزن المفاتيح ولا كلمة المرور، وتقرأ الصفحة ولا تستطيع الكتابة. - ينقل الشيفرة المصدرية للعميل (لا
node_modulesولا الاختبارات ولا ناتج البناء) إلى~/snapchain/casty/srcعلى المضيف مع ملف Dockerfile: node:22-alpine، والاعتماديات من ملف القفل، والبناء نفسه الذي يجريه2-client.sh --from-source. يبني المضيف الصورة؛ وتستغرق المرة الأولى دقيقة أو دقيقتين. - يكتب
~/snapchain/docker-compose.casty.ymlبجانب ملف compose الخاص بالعقدة ويسمّيه فيCOMPOSE_FILEفي~/snapchain/.env، فيشمله كل أمرdocker composeهناك. تشغّل الخدمةcastyالأمرcasty serve --public-host <name>، وتُعاد تشغيلها مع المضيف، وتحفظ رمزها المميز وذاكرتها المؤقتة في~/snapchain/casty/config(مركّب بربط)، وتقرأ كلمة المرور من سر Docker، وهو الملف~/snapchain/casty/passphrase، بالصلاحيات 0600. - يضع وكيلًا في الواجهة:
--domain <name>: تنشر خدمةcaddyالمنفذين 80 و443 وتحصل على الشهادة من Let’s Encrypt بنفسها. يجب أن يشير الاسم إلى المضيف، وأن يكون المنفذان 80 و443 قابلين للوصول من الإنترنت: يفتحهما./scripts/0-provision.sh --httpsعلى جدار حماية Hetzner أو AWS (وإعادة التشغيل تُبقي الخادم)؛ وعلى مضيف خاص بك، افتحهما بنفسك.--tailscale: تُنشرcastyعلى واجهة loopback الخاصة بالمضيف فقط ويقدّمهاtailscale serve --bg 3390بوصفهاhttps://<host>.<tailnet>.ts.netلشبكة tailnet الخاصة بك، بشهادة يوفّرها Tailscale. يجب أن يكون Tailscale مثبتًا ومسجّل الدخول على المضيف، وأن يكون الهاتف على شبكة tailnet. لا يُفتح أي منفذ على الإنترنت.
- ينتظر إلى أن تكتب الخدمة رمز الإقران الخاص بها، ثم يطبع
https://<name>/#token=.... رمز QR لذلك الرابط موجود في سجلات الخدمة:./scripts/1-node.sh logs casty.
شغّل serve مجددًا بعد أي تغيير في casty: ينقل الشيفرة المصدرية مجددًا، ويعيد البناء ويعيد التشغيل.
يوقف ./scripts/1-node.sh down العقدة وcasty معًا؛ وعلى المضيف، يوقف docker compose stop casty (وcaddy،
مع --domain) الصفحة فقط. للإقران من جديد من الصفر، احذف ~/snapchain/casty/config/web-token على
المضيف ونفّذ docker compose restart casty.
ما يضيفه casty serve إلى casty web
Section titled “ما يضيفه casty serve إلى casty web”casty serve هو casty web فوق الفهرس الموصوف أدناه، مع إشعارات الدفع وحدّ للطلبات، ومع
--public-host، اسم الوكيل:
- تحمل الروابط التي يطبعها
https://<public host>، ويُقبل ذلك الاسم قيمةً لـHostفي الطلب، إلى جانب عنوان IP أوlocalhost؛ - يحمل كل رد
Strict-Transport-Security، فالمتصفح الذي رأى الصفحة مرة لا يطلبها أبدًا عبر HTTP عادي؛ - يُحدّ
/api/*بـ 120 طلبًا في الدقيقة لكل عنوان عميل، تُعدّ قبل التحقق من الرمز، مع429وRetry-Afterبعد تجاوز ذلك. خلف الوكيل يكون عنوان العميل هو الأخير فيX-Forwarded-For، أي العنوان الذي ألحقه الوكيل؛ أما العنوان الذي وضعه العميل هناك بنفسه فلا يُحتسب؛ - بدون
--public-host، على حاسوب محمول، يكونcasty serveهوcasty webمع الفهرس والحدّ: الروابط نفسها، بلا HSTS، ويَعدّ الحدّ بحسب عنوان المقبس، إذ إنX-Forwarded-Forبدون وكيل هو ما كتبه العميل أيًّا كان. عند البناء من الشيفرة المصدرية، يحتاجcasty serveإلى Node 22.13 أو أحدث من أجل SQLite الخاص به؛ أما الملف التنفيذي الواحد فيحمل نسخته الخاصة؛ - تأتي كلمة مرور مخزن المفاتيح من
CASTY_PASSPHRASE_FILE، وهو سر Docker، فتبدأ الخدمة دون طرفية.
كل ما عدا ذلك هو الصفحة الموصوفة في في المتصفح وعلى الهاتف: الإقران نفسه بالرمز، والترقيم نفسه المشترك مع الطرفية، والكتابات نفسها عبر العقدة.
التغذية من فهرس
Section titled “التغذية من فهرس”يحفظ casty serve التغذية في index.sqlite في مجلد إعداداته (~/snapchain/casty/config/index.sqlite
على المضيف)، باستخدام SQLite المدمج في Node. عند أول تشغيل يقرأ متابعاتك، وأحدث 100 منشور لك ولكل منهم،
والمنشورات التي تذكرك، والردود على أحدث 25 منشورًا لك، وإعجاباتك وإعادات نشرك. ومن ثم يتابع سجل أحداث
العقدة (/v1/events، كل شريحة، كل 1.5 ثانية): يدخل المنشور من شخص تتابعه، أو ذِكر لك، أو رد عليك؛ ويخرج
المنشور المُزال أو المقتطع؛ والمتابعة التي تجريها تُدخل أحدث منشورات الحساب الجديد وإلغاء المتابعة يُخرج
الحساب؛ وتبقى إعجاباتك وإعادات نشرك محدّثة. عندئذ تأتي تغذية الصفحة وإشاراتها وحالة الإعجاب من الفهرس في
بضع أجزاء من الثانية بدل مئات الطلبات إلى العقدة، والكتابة التي تجريها في الصفحة تقرأ الأحداث فورًا،
فتظهر في القائمة التالية. وبعد اكتمال المرور الأول، تُقرأ أيضًا أسماء متابعاتك وتطبيقاتهم، فلا تطلب أول
تغذية بعد التشغيل شيئًا من العقدة. وإلى أن يكتمل المرور الأول، تقرأ الصفحة من العقدة كما يفعل
casty web. أما الملفات الشخصية وسلاسل المحادثة فتقرأ من العقدة دائمًا.
أثناء القراءة، تسأل الصفحة الفهرس كل نصف دقيقة، وكلما عادت إلى العرض، هل وصلت منشورات أحدث من المنشور في الأعلى. إن كان الأمر كذلك، تقول شارة تحت الشريط “3 new casts”؛ ولا تتحرك القائمة تحتك أبدًا. والنقر يعرضها.
تحتفظ العقدة بنحو ثلاثة أيام من الأحداث؛ والخدمة التي كانت متوقفة لأكثر من يومين تجري المرور الأول مجددًا
عند تشغيلها، وتتابع من هناك. احذف index.sqlite على المضيف وأعد تشغيل casty للبدء من لا شيء.
الذِكر يصل إلى الهاتف
Section titled “الذِكر يصل إلى الهاتف”تحت «you»، يفعّل «notifications» خدمة Web Push لذلك المتصفح: تسجّل الصفحة عامل الخدمة الخاص بها (sw.js)،
وتشترك بالمفتاح الذي أنشأه casty serve عند أول تشغيل (vapid.json في مجلد إعداداته، بالصلاحيات 0600)،
وتسلّم الاشتراك إلى الخدمة، التي تحفظه في cache/push.json. حين تأتي الأحداث بمنشور من شخص آخر يذكرك أو
يرد على أحد منشوراتك، ترسل الخدمة إلى كل متصفح مشترك رسالة واحدة: “new mention from @name” أو “new reply
from @name”، ولا شيء غير ذلك، لا نص المنشور. وهي مشفرة بمفتاح المتصفح نفسه (RFC 8291) وموقّعة بمفتاح
الخدمة (RFC 8292)، فخدمة الدفع الوسيطة، سواء أكانت لـ Apple أم Google أم Mozilla، تنقل نصًا مشفرًا لا
تستطيع قراءته. النقر يفتح «mentions». ويُحذف الاشتراك الذي تبلّغ خدمة الدفع بأنه لم يعد موجودًا.
على iPhone، لا يعمل Web Push إلا لصفحة مضافة إلى الشاشة الرئيسية (iOS 16.4 وما بعده)؛ أما العدد بجانب «mentions» فيعمل في كل مكان، كما من قبل. إيقاف الإشعارات يزيل الاشتراك من المتصفح ومن الخدمة كليهما.
ما يضعه هذا على المضيف
Section titled “ما يضعه هذا على المضيف”مع serve يحمل المضيف، إلى جانب العقدة:
| ما هو | أين | ما يمكنه فعله |
|---|---|---|
| مفتاح التطبيق، مشفرًا | ~/snapchain/casty/config/keys.enc.json، بالصلاحيات 0600 |
لا شيء دون كلمة المرور |
| كلمة مرور مخزن المفاتيح | ~/snapchain/casty/passphrase، بالصلاحيات 0600، تقرأها الحاوية عند التشغيل |
فك تشفير المفتاح: معًا، الكتابة باسمك |
| الرمز للصفحة | ~/snapchain/casty/config/web-token، وفي كل متصفح مقترن |
القراءة والكتابة باسمك، من أي مكان، ما دامت الخدمة تعمل |
| الشهادة ومفتاحها | القرص caddy_data الخاص بـ Caddy، أو قرص Tailscale |
تقديم الصفحة بذلك الاسم |
| فهرس تغذيتك | ~/snapchain/casty/config/index.sqlite |
لا شيء: يحمل منشورات عامة، ومتابعاتك وتفاعلاتك، وهي ما تحمله العقدة أيضًا |
| زوج مفاتيح الدفع | ~/snapchain/casty/config/vapid.json، بالصلاحيات 0600 |
إرسال إشعارات دفع إلى المتصفحات المشتركة؛ والزوج الجديد يُبطل كل اشتراك |
| اشتراكات الدفع | ~/snapchain/casty/config/cache/push.json |
إرسال إشعار دفع إلى تلك المتصفحات، بوصفها نقاط نهاية خدمة الدفع، مع المفاتيح العامة للمتصفحات |
من يملك صلاحيات root على المضيف يملك مفتاح التطبيق، مفكوك التشفير، في ذاكرة الخدمة. هذه هي المقايضة مقابل
صفحة من أي مكان، وهذه أسباب بقائها محدودة: لا يوقّع المفتاح إلا ما تسمح به نطاقاته (المنشورات والتفاعلات
والمتابعات افتراضيًا) وتنتهي صلاحيته إن لم يُستخدم بعد مدة TTL الخاصة به؛ وcasty key revoke <key> مع
عبارة البذرة، من أي جهاز، يلغيه فورًا؛ و--read-only يُبقي المفتاح في المنزل لصفحة تقرأ فقط. لا تذهب عبارة
البذرة إلى أي مكان أبدًا. تسرد صفحة الأمان كل سر.
الخيارات
Section titled “الخيارات”Usage: casty serve [options]
the page over an index of the feed, with push; on the node's host behind HTTPS,which 1-node.sh serve installs
Options: --public-host <domain> the domain the page is reached at through a proxy that ends HTTPS; it goes into the pairing link --listen <host:port> where to serve, for the proxy (default: "0.0.0.0:3390") --new-token pair again; links printed before stop working --read-only do not unlock the app key; the page reads but cannot write --no-allow-fname-server look @names up with your node only; by default names it does not know are looked up on fnames.farcaster.xyz (public, no key) -h, --help display help for command