अपडेट पर वापस जाएँ
New releaseAug 20, 2026

Seal v0.2.3

पीयर-टू-पीयर, एंड-टू-एंड एन्क्रिप्टेड चैट। कोई इनबॉक्स नहीं। रिकवर करने के लिए कोई अकाउंट नहीं। कोई सुन नहीं रहा — हम भी नहीं।

साझा करें
Seal लोगो

Seal

पीयर-टू-पीयर, एंड-टू-एंड एन्क्रिप्टेड चैट।
कोई इनबॉक्स नहीं। पुनर्प्राप्त करने के लिए कोई खाता नहीं। कोई सुन नहीं रहा — हम भी नहीं।

github.com/Emn4tor/Seal

Rust: 1.97+ Tauri: 2.11.5 React: 19.2 प्लेटफ़ॉर्म: macOS, Linux, Windows एन्क्रिप्शन: Olm / Megolm सर्वर-साइड संदेश भंडारण: कोई नहीं

GitHub स्टार्स GitHub फ़ोर्क्स GitHub इश्यूज़ GitHub अंतिम कमिट GitHub रिपोज़िटरी आकार

योगदानकर्ता कुल कमिट

संदेश libp2p के माध्यम से सीधे पीयर के बीच यात्रा करते हैं और आपके डिवाइस से बाहर निकलने से पहले Signal-शैली के Olm/Megolm प्रोटोकॉल (vodozemac के माध्यम से) से एन्क्रिप्ट किए जाते हैं। इसमें शामिल एकमात्र सर्वर एक छोटी निर्देशिका है जो पीयर को एक-दूसरे का वर्तमान पता खोजने में मदद करती है। यह कभी भी संदेश सामग्री नहीं देखता है, और इसे एक ही कमांड में हटाया जा सकता है।

वास्तव में किन चीज़ों से सुरक्षा मिलती है और कैसे, यह देखने के लिए docs/THREAT_MODEL.md और docs/SECURITY.md देखें।

विषय-सूची


स्क्रीनशॉट

पहला रन — एक नाम चुनें; और कुछ सेट करने की ज़रूरत नहीं।

Seal का पहला-रन स्क्रीन: डिस्प्ले-नाम फ़ॉर्म के बगल में एन्क्रिप्शन मॉडल का स्पष्टीकरण, साथ में लॉगिन-पर-लॉन्च टॉगल



बातचीत — ग्रुप रेल, संपर्क सूची, और एक एंड-टू-एंड एन्क्रिप्टेड चैट पैन।

Seal में एक डायरेक्ट-मैसेज वार्तालाप, जिसमें ग्रुप रेल, संपर्क सूची और एंड-टू-एंड एन्क्रिप्टेड चैट पैन दिखाया गया है



सेटिंग्स — माइक संवेदनशीलता, पुश-टू-टॉक, लॉगिन-पर-लॉन्च, नेटवर्क पहुँच।

Seal का सेटिंग्स पैनल: माइक संवेदनशीलता, पुश-टू-टॉक, लॉगिन-पर-लॉन्च और नेटवर्क पहुँच

विशेषताएँ

  • हमेशा एंड-टू-एंड एन्क्रिप्टेड — हर संदेश आपके डिवाइस से बाहर निकलने से पहले Olm (1:1) या Megolm (समूहों) के साथ सील किया जाता है, vodozemac की Double-Ratchet-शैली योजना का उपयोग करते हुए: हर संदेश को अपनी खुद की कुंजी मिलती है।
  • कभी नहीं कोई इनबॉक्स — संदेश एक सीधे पीयर-टू-पीयर कनेक्शन (libp2p: QUIC/TCP + Noise, NAT के लिए रिले और होल-पंचिंग के साथ) पर यात्रा करते हैं। यदि प्राप्तकर्ता ऑफ़लाइन है, तो संदेश स्थानीय रूप से प्रतीक्षा करता है और पुनः प्रयास करता है — यह कभी भी किसी और के इंफ्रास्ट्रक्चर पर कतारबद्ध नहीं होता।
  • एक डायरेक्टरी, डेटाबेस नहीं — इसमें शामिल एकमात्र सर्वर (crates/directory-server) एक उपयोगकर्ता ID को वर्तमान नेटवर्क पते पर मैप करता है और कुछ और नहीं। यह संरचनात्मक रूप से संदेश सामग्री पढ़ने में असमर्थ है: इसका Cargo.toml उन crates पर निर्भर भी नहीं है जो यह जानते हैं।
  • एक डिवाइस, कई खाते — पूरी तरह से अलग पहचान (कुंजियाँ, संपर्क, संदेश) जिनके बीच आप बिना पुनः आरंभ किए स्विच कर सकते हैं।
  • वास्तविक सदस्यता परिवर्तन वाले समूह — प्रति समूह टेक्स्ट और वॉइस चैनल; किसी को हटाने पर समूह की कुंजी घुमा दी जाती है ताकि वे बाद में भेजी गई कोई भी चीज़ न पढ़ सकें।
  • वॉइस, अंतर्निर्मित — सिस्टम-व्यापी शॉर्टकट पर पुश-टू-टॉक (केवल Seal से नहीं, किसी भी ऐप से काम करता है), समायोज्य माइक संवेदनशीलता, और एक वैकल्पिक वॉइस चेंजर।
  • मेटाडेटा के बिना अटैचमेंट — EXIF डेटा (GPS स्थान, कैमरा/डिवाइस जानकारी) भेजे जाने से पहले छवियों से हटा दिया जाता है, डिफ़ॉल्ट रूप से चालू।
  • एक वास्तविक पैनिक बटन — सेटिंग्स → डेटा और गोपनीयता इस डिवाइस पर हर कुंजी, संपर्क और संदेश को तुरंत और अपरिवर्तनीय रूप से हटा देता है, जिसका उन सभी पर शून्य प्रभाव पड़ता है जिनसे आपने बात की है।
  • लॉगिन पर लॉन्च, यदि आप चाहें — डिफ़ॉल्ट रूप से चालू, सेटिंग्स में बस एक टॉगल दूर।
  • एक कोडबेस, तीन प्लेटफ़ॉर्मTauri के माध्यम से macOS, Windows और Linux पर नेटिव विंडोज़।

यह कैसे काम करता है

इस ऐप में दो प्रकार की पहचान हैं, और उन्हें जानबूझकर अलग रखा गया है:

  • आपकी चैट पहचान एक Ed25519/Curve25519 कुंजीयुग्म है जिसे ऐप पहली बार खोलने पर vodozemac द्वारा स्थानीय रूप से उत्पन्न किया जाता है (identity::Identity)। आपका सार्वजनिक "user ID" उस कुंजी का फ़िंगरप्रिंट मात्र है (wire_proto::user_id_from_ed25519)। इसे किसी सर्वर द्वारा जारी या रद्द नहीं किया जा सकता, क्योंकि इसे बनाने में कोई सर्वर शामिल नहीं है।
  • आपकी नेटवर्क पहचान एक अलग libp2p कुंजीयुग्म (PeerId) है, जिसका उपयोग केवल ट्रांसपोर्ट परत के लिए होता है। यह पुनः आरंभ के बीच बदल सकता है, बिना आपकी चैट पहचान को बिल्कुल प्रभावित किए; दोनों केवल एक उपस्थिति रिकॉर्ड से बंधे होते हैं जिस पर आप स्वयं हस्ताक्षर करते हैं।

किसी को खोजना और वास्तव में उनसे बात करना दो अलग-अलग चरण हैं:``` ┌────────────────────────┐ │ directory server │ │ (axum + one SQLite │ │ file: users, │ │ presence, group │ │ rosters. Never │ │ message content.) │ └─────────┬───────────────┘ 1. "where is bob │ 2. "here's my current right now?" │ address" (signed, │ expires in minutes) ┌─────────┴───────────────┐ ▼ ▼ ┌───────┐ 3. direct libp2p ┌───────┐ │ alice │◄──── connection ────►│ bob │ └───────┘ (Noise + Olm/ └───────┘ Megolm encrypted)

1. ऐलिस निर्देशिका में बॉब को उसके यूज़र आईडी से खोजती है। इससे उसकी
   सार्वजनिक कुंजियाँ और उसका अंतिम घोषित नेटवर्क पता मिलता है। निर्देशिका में
   यही सब कुछ होता है: सार्वजनिक कुंजियाँ, प्रदर्शन नाम, समूह
   सदस्यता सूचियाँ, और अल्पकालिक पता घोषणाएँ
   (`crates/directory-server`)।
2. ऐलिस सीधे libp2p पर बॉब को डायल करती है (QUIC या TCP+Noise, relay +
   hole-punching के साथ NATs के पीछे पीयर्स के लिए; `crates/net` देखें)। निर्देशिका
   अब पूरी तरह तस्वीर से बाहर है।
3. वास्तविक संदेश **Olm** से एन्क्रिप्ट किया जाता है 1:1 चैट के लिए, या
   **Megolm** से समूह के लिए (`crates/crypto-session`), एक Double-Ratchet-शैली
   योजना जहाँ हर संदेश को अपनी खुद की कुंजी मिलती है, इससे पहले कि
   उसे libp2p कनेक्शन पर रखा जाए। कोई सर्वर-साइड इनबॉक्स नहीं है: यदि बॉब ऑफ़लाइन है,
   संदेश स्थानीय रूप से प्रतीक्षा करता है और पुनः प्रयास किया जाता है, किसी और के
   इंफ्रास्ट्रक्चर पर संग्रहीत नहीं किया जाता।

उपरोक्त सब कुछ `crates/core` के `AppService` द्वारा संचालित होता है, जो
Tauri ऐप के Rust बैकएंड (`apps/desktop/src-tauri`) द्वारा वास्तव में कॉल
किया जाता है; UI कभी भी सीधे नेटवर्क से बात नहीं करता।

## प्रोजेक्ट लेआउट```
crates/
  wire-proto        shared signed-request types for the directory API
  identity          vodozemac identity, OS-keychain key management
  storage           local encrypted store (contacts, messages, groups)
  net               libp2p transport + directory HTTP client
  crypto-session    Olm (1:1) / Megolm (group) session management
  core              orchestrates the above into `AppService` / `ChatNode`
  directory-server  the one server component (axum + SQLite)
apps/desktop         the Tauri + React app
scripts/             build + backend-deployment scripts (§2, §5)

1. पूर्वापेक्षाएँ

आपको हर प्लेटफ़ॉर्म पर Rust और Node.js की आवश्यकता है, साथ ही एक प्लेटफ़ॉर्म-विशिष्ट टूलचेन की भी, जिसकी Tauri को नेटिव विंडो बनाने के लिए ज़रूरत होती है। storage और directory-server SQLite को स्रोत से बंडल-संकलित भी करते हैं, जिसके लिए एक साधारण C कंपाइलर की आवश्यकता होती है (इस प्रोजेक्ट में कहीं भी OpenSSL या अन्य नेटिव क्रिप्टो लाइब्रेरी की आवश्यकता नहीं है)।

सभी प्लेटफ़ॉर्मों पर सामान्य:

  • Rust (स्थिर चैनल; rustup के माध्यम से इंस्टॉल करें, अपने OS पैकेज मैनेजर से नहीं)
  • Node.js 20+ और npm
macOS```sh xcode-select --install ``` That's it. Xcode Command Line Tools C कंपाइलर और वे फ्रेमवर्क दोनों प्रदान करते हैं जिनकी Tauri के macOS बैकएंड (WKWebView-आधारित) को आवश्यकता होती है।
Linux

C कंपाइलर, pkg-config, और WebKitGTK/AppIndicator डेव पैकेज इंस्टॉल करें, जिनसे Tauri का Linux बैकएंड लिंक होता है।

Debian/Ubuntu:```sh sudo apt update sudo apt install libwebkit2gtk-4.1-dev build-essential curl wget file
libxdo-dev libssl-dev libayatana-appindicator3-dev librsvg2-dev pkg-config

Fedora:```sh
sudo dnf install webkit2gtk4.1-devel openssl-devel curl wget file \
  libappindicator-gtk3-devel librsvg2-devel pkgconf-pkg-config
sudo dnf group install "C Development Tools and Libraries"

वास्तुकला:```sh sudo pacman -S --needed webkit2gtk-4.1 base-devel curl wget file openssl
appmenu-gtk-module libappindicator-gtk3 librsvg pkgconf

(Package names shift between Tauri releases: if a build fails looking for a
missing `.pc` file, check the
[current Tauri Linux prerequisites](https://v2.tauri.app/start/prerequisites/)
for your distro.)

</details>

<details>
<summary><strong>Windows</strong></summary>

1. **Microsoft C++ Build Tools** स्थापित करें (Visual Studio Installer →
   "Desktop development with C++" वर्कलोड), जो Tauri के नेटिव शेल और बंडल किए गए SQLite को संकलित करने दोनों के लिए आवश्यक है।
2. **MSVC** Rust टूलचेन स्थापित करें: `rustup default stable-msvc`.
3. **WebView2**: यह Windows 11 और अधिकांश अद्यतित Windows 10 इंस्टॉलों पर पहले से मौजूद होता है; यदि नहीं है, तो Tauri का बिल्ड आपको Evergreen रनटाइम स्थापित करने के लिए संकेत देगा।

</details>

---

## 2. बिल्ड करना

रिपॉज़िटरी रूट से:```sh
# Rust workspace (backend crates + the directory server)
cargo build --workspace --release

# Frontend + the actual desktop app bundle (installer/.app/.exe)
cd apps/desktop
npm install
npm run tauri build

npm run tauri build रिपॉजिटरी रूट में target/release/bundle/ के अंतर्गत एक प्लेटफ़ॉर्म-नेटिव इंस्टॉलर बनाता है (यह एक Cargo वर्कस्पेस है, इसलिए Tauri ऐप सहित सभी क्रेट्स एक शीर्ष-स्तरीय target/ निर्देशिका साझा करते हैं)। क्रॉस-कंपाइलिंग (जैसे macOS से Windows इंस्टॉलर बनाना) सेट नहीं है: प्रत्येक लक्ष्य प्लेटफ़ॉर्म पर बिल्ड करें, या यदि आप CI-निर्मित रिलीज़ चाहते हैं तो Tauri के GitHub Actions वर्कफ़्लो का उपयोग करें।

या स्क्रिप्ट्स का उपयोग करें

scripts/ में प्रति प्लेटफ़ॉर्म/आउटपुट एक बिल्ड स्क्रिप्ट है, प्रत्येक स्वतंत्र रूप से चलाने योग्य है और प्रत्येक को वास्तव में कार्यशील आर्टिफैक्ट बनाने के लिए सत्यापित किया गया है:

स्क्रिप्टनिर्माण करता है
scripts/build-mac-dmg.shmacOS .dmg इंस्टॉलर
scripts/build-mac-app.shरॉ macOS .app बंडल, कोई इंस्टॉलर नहीं
scripts/build-linux.shLinux .AppImage + .deb
scripts/build-windows.ps1Windows .msi + .exe (NSIS)

प्रत्येक केवल npm run tauri build --bundles <...> को सही फ़्लैग और प्लेटफ़ॉर्म जाँच के साथ रैप करता है; यदि आपको एक अलग बंडल संयोजन चाहिए तो स्वयं रॉ कमांड चलाएँ (apps/desktop से npx tauri build --help)।

scripts/release.sh vX.Y.Z संस्करण को हर उस स्थान पर बढ़ाता है जहाँ इसे रहना आवश्यक है और कमिट को टैग करता है — देखें docs/RELEASING.md। macOS और Linux पर चलता है; कमिट या पुश नहीं करता।

अपना खुद का "Seal" नेटवर्क बेक करना

सर्वर-चयन स्क्रीन (§3) हमेशा तीन विकल्प दिखाती है: Seal (आपका अपना आधिकारिक नेटवर्क), कस्टम सर्वर, और नीचे एक छोटा लोकल टेस्ट सर्वर लिंक। "Seal" तब तक अक्षम (ग्रे किया हुआ, "इस बिल्ड में अभी सेट नहीं है" के साथ) रहता है जब तक आप build समय पर एक URL बेक नहीं करते:```sh SEAL_DEFAULT_DIRECTORY_URL=https://directory.example.com npm run tauri build

एक बार जब आप अपना स्वयं का सर्वर (§5) खड़ा कर लेते हैं और उस पर एक वास्तविक डोमेन इंगित कर लेते हैं, तो इसे सेट करें और पुनर्निर्माण करें: उसके बाद आपके द्वारा वितरित हर प्रति "Seal" को उस URL का उपयोग करके एक वास्तविक, चयन योग्य विकल्प के रूप में दिखाती है, बिना किसी अन्य कोड को छुए। इसे सामान्य/डेव बिल्ड के लिए अनसेट छोड़ दें: इस रेपो द्वारा कोई आधिकारिक सर्वर होस्ट नहीं किया जाता है, इसलिए "Seal" अक्षम रहता है और लोग कस्टम सर्वर या लोकल सर्वर का सहारा लेते हैं, बजाय इसके कि ऐप चुपचाप किसी प्लेसहोल्डर डोमेन की ओर इंगित करे जो वास्तव में कुछ भी नहीं चला रहा है।

---

## 3. डेव मोड में चलाना```sh
cd apps/desktop
npm install
npm run tauri dev

यह Vite डेव सर्वर शुरू करता है, Rust बैकएंड को डीबग मोड में कंपाइल करता है, और फ्रंटएंड पर हॉट-रिलोड के साथ एक नेटिव विंडो खोलता है। पहला बिल्ड पूरे डिपेंडेंसी ट्री को कंपाइल करता है और कुछ मिनट लेता है; उसके बाद के रन तेज़ होते हैं।

सर्वर चुनना (पहला रन)

पहली बार लॉन्च करने पर, Seal पूछता है कि कौन-सा डायरेक्टरी सर्वर उपयोग करना है, इस क्रम में:

  • Seal: आधिकारिक नेटवर्क, यदि इस बिल्ड में वह शामिल है (देखें §2)। जब तक ऐसा न हो, यह अक्षम रहता है; यह रेपो किसी प्लेसहोल्डर डोमेन की ओर इशारा करके नहीं भेजा जाता।
  • Custom server: किसी का भी, जिसमें आपका अपना भी शामिल है (§5)।
  • Local test server: सबसे नीचे एक छोटा, जानबूझकर कम ज़ोर दिया गया लिंक। ऐप का अपना embedded server चालू करता है (127.0.0.1:47100/47101 बाइंड करता है, डेटा आपके OS की ऐप-डेटा डायरेक्टरी में), जो Seal को आज़माने या एक मशीन पर इंस्टेंस टेस्ट करने के लिए ठीक है, वास्तविक डिप्लॉयमेंट नहीं। यदि दूसरा इंस्टेंस पाता है कि वे पोर्ट पहले से लिए हुए हैं, तो वह दूसरा सर्वर शुरू करने के बजाय पहले इंस्टेंस के सर्वर को ही फिर से उपयोग करता है, जिससे एक ही मशीन पर दो इंस्टेंस एक-दूसरे को ढूँढ पाते हैं। यदि "Seal" कॉन्फ़िगर नहीं है और आप कुछ और नहीं चुनते हैं, तो यही स्वतः चुना जाता है।

यह चुनाव सहेजा जाता है (server.json ऐप के अन्य स्थानीय डेटा के पास) और हर बाद के लॉन्च पर चुपचाप पुनः उपयोग किया जाता है; इसे Settings → Directory server से बदलें, जो अगली बार जब आप ऐप शुरू करेंगे तब प्रभावी होगा, न कि चालू कनेक्शन को हॉट-स्वैप करने की कोशिश करके। स्क्रिप्टेड/डेव उपयोग के लिए, एक पर्यावरण चर प्रॉम्प्ट को पूरी तरह से छोड़ देता है:```sh P2P_CHAT_DIRECTORY_URL=https://directory.example.com npm run tauri dev

### स्थानीय रूप से दो इंस्टेंस चलाना (वास्तव में मैसेजिंग का परीक्षण करने के लिए)

प्रत्येक इंस्टेंस को अपनी खुद की पहचान की आवश्यकता होती है। Seal मूल रूप से कई खातों का समर्थन करता है
(इस डिवाइस पर सेटिंग्स → खाते), लेकिन एक मशीन पर दो *अलग
प्रक्रियाओं* के लिए, `P2P_CHAT_PROFILE` तेज़ विकल्प है: यह
स्वतः बनाता है (पहली बार) या स्वतः पुनः शुरू करता है (हर बार बाद में) एक खाता
उस नाम के साथ, बिना किसी इंटरैक्शन के, खाता पिकर को पूरी तरह छोड़ते हुए:```sh
# terminal 1
P2P_CHAT_PROFILE=alice npm run tauri dev

# terminal 2
P2P_CHAT_PROFILE=bob npm run tauri dev

सर्वर चयन (server.json) और खाता सूची (accounts.json) दोनों एक ही मशीन पर प्रोसेसों के बीच साझा होते हैं, प्रति-प्रोफ़ाइल नहीं। आपके द्वारा लॉन्च किया गया पहला इंस्टेंस सर्वर चुनता है, और उसके बाद हर प्रोफ़ाइल (यहाँ bob सहित) उसे चुपचाप पुनः उपयोग करती है। दोनों विंडो एक ही एम्बेडेड डायरेक्टरी सर्वर पर समाप्त होती हैं, इसलिए आप एक-दूसरे को ID द्वारा संपर्क के रूप में जोड़ सकते हैं और उनके बीच संदेश भेज सकते हैं।

Vite का डेव सर्वर Tauri के webview को इंगित करने के लिए एक वास्तविक, निश्चित पोर्ट चाहता है, जिसका सामान्य अर्थ है कि एक समय में केवल एक npm run tauri dev चल सकता है — दूसरा इंस्टेंस पोर्ट 1420 को पहले से लिया हुआ पाएगा और सीधे विफल हो जाएगा। npm run tauri वास्तव में एक छोटा रैपर है (apps/desktop/scripts/tauri.mjs) जो पहले के बाद हर इंस्टेंस के लिए अगला खाली पोर्ट (1421, 1422, …) चुनता है और उसे स्वचालित रूप से जोड़ देता है, इसलिए उपरोक्त दो आदेशों को दो टर्मिनलों में चलाना आसानी से काम करता है; आपको कुछ भी अलग करने की आवश्यकता नहीं है। यह केवल dev के लिए व्यवहार बदलता है — npm run tauri build और बाकी सब कुछ सीधे वास्तविक CLI से होकर गुजरता है।

वास्तविक बिल्ड के विरुद्ध परीक्षण (dev मोड नहीं)```sh

./scripts/run-two-mac-instances.sh # profiles: alice, bob ./scripts/run-two-mac-instances.sh carol dave

Same idea as above, but launches the actual built app (`build-mac-app.sh` /
`build-mac-dmg.sh`'s output, or an installed copy in `/Applications`) twice
with different `P2P_CHAT_PROFILE`s instead of `npm run tauri dev`, closer
to what a real user runs. Prints the PIDs and how to stop both.

### डिबगिंग

- **Rust लॉग्स**: लॉन्च करने से पहले `RUST_LOG` सेट करें, जैसे
  `RUST_LOG=debug npm run tauri dev` (या `RUST_LOG=p2p_core=debug,net=debug`
  इसे सीमित दायरे में रखने के लिए)। लॉग किए गए फ़ील्ड केवल मेटाडेटा तक सीमित हैं (पीयर/ग्रुप/यूज़र
  आईडी, त्रुटि प्रकार); यह देखने के लिए [`docs/SECURITY.md`](https://github.com/emn4tor/seal/blob/HEAD/docs/SECURITY.md) पढ़ें कि
  इसे वर्बोज़ छोड़ना सुरक्षित क्यों है।
- **फ्रंटएंड**: डेव विंडो एक वास्तविक वेबव्यू है; राइट-क्लिक → Inspect Element
  (या डेव टूल्स खोलें) सामान्य ब्राउज़र की तरह काम करता है।
- **बैकएंड क्रेट्स अलगाव में**: प्रत्येक क्रेट का अपना टेस्ट सुइट है जिसे आप
  बिना यूआई को छुए चला सकते हैं और उस पर पुनरावृति कर सकते हैं; §4 देखें।
- **एक स्टैंडअलोन डायरेक्टरी सर्वर**, एम्बेडेड सर्वर के बजाय: §5 देखें।

---

## 4. परीक्षण```sh
# everything
cargo test --workspace

# one crate, e.g. the full backend-to-backend flow a Tauri command would trigger
cargo test -p p2p-core --test app_service

# lint + format check (what CI runs)
cargo fmt --all -- --check
cargo clippy --workspace --all-targets -- -D warnings

# dependency vulnerability scan
cargo install cargo-audit --locked   # once
cargo audit

# frontend type-check + build
cd apps/desktop && npm run build

5. बैकेंड (डायरेक्टरी सर्वर) सेटअप

यह वास्तव में क्या है, इसका सारांश—क्योंकि अधिक कल्पना करना आसान है: एक axum प्रक्रिया, एक SQLite फ़ाइल, तीन प्रकार के रिकॉर्ड (सार्वजनिक कुंजियाँ, अल्पकालिक उपस्थिति घोषणाएँ, समूह रोस्टर), सभी लेखन कॉल करने वाले की अपनी पहचान कुंजी द्वारा हस्ताक्षरित होते हैं। यह कभी भी किसी संदेश के मार्ग में नहीं आता। यह संरचनात्मक रूप से, न केवल नीति के तौर पर, सच क्यों है, यह देखने के लिए docs/THREAT_MODEL.md देखें: directory-server का Cargo.toml उन crates पर भी निर्भर नहीं करता जो संदेश सामग्री पढ़ना जानते हैं।

सबसे तेज़ रास्ता: सेटअप स्क्रिप्ट```sh

sudo ./scripts/setup-backend.sh

इंटरैक्टिव, केवल Linux + systemd (कारण के लिए स्क्रिप्ट का हेडर देखें)। यह पूछता है कि आप किस डिस्ट्रो परिवार पर हैं (Debian/Ubuntu, Fedora/RHEL/Rocky/Alma, Arch/Manjaro, या openSUSE, `/etc/os-release` से अनुमान के साथ पहले से भरा हुआ, इसलिए आमतौर पर एक कुंजी दबाकर पुष्टि हो जाती है) और प्रत्येक परिवार के लिए समर्पित फ़ंक्शन के साथ उस डिस्ट्रो की बिल्ड पूर्वापेक्षाएँ स्थापित करता है, यदि Rust मौजूद नहीं है तो `rustup` के माध्यम से Rust स्थापित करने की पेशकश करता है, रिलीज़ बाइनरी बनाता है, एक समर्पित सिस्टम उपयोगकर्ता बनाता है, एक एडमिन टोकन उत्पन्न करता है, पूछता है कि क्या आप [Caddy](https://caddyserver.com) के माध्यम से स्वचालित HTTPS के साथ एक डोमेन कॉन्फ़िगर करना चाहते हैं (Caddy को स्वयं, प्रति-डिस्ट्रो स्थापित करते हुए, यदि किसी डिस्ट्रो का पैकेज उपलब्ध नहीं है तो Caddy के आधिकारिक स्टैटिक बाइनरी पर वापस जाते हुए), या यदि आप इसे स्वयं प्रबंधित करना चाहते हैं तो केवल लूपबैक/प्लेन-HTTP बाइंड करने के लिए, फिर systemd सेवा लिखता और सक्षम करता है। पुनः चलाना सुरक्षित है।

नीचे दिया गया सब कुछ वही है जो यह वास्तव में कर रहा है, यदि आप इसे हाथ से करना चाहते हैं या इसे चलाने से पहले समझना चाहते हैं।

### macOS: एक त्वरित LAN परीक्षण सर्वर```sh
./scripts/run-mac-test-server.sh

वास्तविक होस्टिंग के लिए नहीं: एक ही नेटवर्क पर दो डिवाइसों पर ऐप का परीक्षण करने के लिए नेटवर्क (जैसे आपका Mac + कोई अन्य मशीन, या एक ही Wi-Fi पर दो लोग) डोमेन, TLS, या systemd सेट किए बिना (जो macOS पर मौजूद नहीं है वैसे भी)। यह रिलीज़ बाइनरी बनाता है, एक एडमिन टोकन उत्पन्न करता है (बाद के रनों पर पुनः उपयोग होता है), सार्वजनिक API को सभी इंटरफेस से बाँधता है, और उपयोग के लिए URL प्रिंट करता है आपके Mac का वास्तविक LAN IP (ipconfig getifaddr के माध्यम से), न कि केवल 127.0.0.1, ताकि अन्य डिवाइस भी उस तक पहुँच सकें। एडमिन पोर्ट केवल लूपबैक पर रहता है। फोरग्राउंड में चलता है; Ctrl-C इसे रोकता है। डेटा यहाँ रहता है: ~/.seal-test-server

त्वरित स्थानीय रन```sh

DIRECTORY_DB_PATH=/var/lib/seal-directory/directory.sqlite3
DIRECTORY_PUBLIC_ADDR=0.0.0.0:8080
DIRECTORY_ADMIN_ADDR=127.0.0.1:8090
DIRECTORY_ADMIN_TOKEN=$(openssl rand -hex 32)
cargo run --release -p directory-server --bin directory-server

| चर | आवश्यक | अर्थ |
|---|---|---|
| `DIRECTORY_DB_PATH` | नहीं (डिफ़ॉल्ट `directory.sqlite3`, cwd) | एकल SQLite फ़ाइल इसी स्थान पर रहती है। पैरेंट डायरेक्टरी का मौजूद होना आवश्यक है। |
| `DIRECTORY_PUBLIC_ADDR` | नहीं (डिफ़ॉल्ट `0.0.0.0:8080`) | वह rendezvous API जिससे ऐप्स बात करते हैं। इसे सार्वजनिक रूप से एक्सपोज़ करना ठीक है। |
| `DIRECTORY_ADMIN_ADDR` | नहीं (डिफ़ॉल्ट `127.0.0.1:8090`) | यह purge एंडपॉइंट है। इसे सार्वजनिक इंटरनेट से दूर रखें; नीचे देखें। |
| `DIRECTORY_ADMIN_TOKEN` | **हाँ** | एडमिन API के लिए Bearer टोकन। इसके बिना प्रोसेस शुरू होने से मना कर देती है। `openssl rand -hex 32` या इसी तरह से जनरेट करें; इसे कहीं और दोबारा उपयोग न करें। |

प्रक्रिया स्टार्टअप पर लॉग करती है कि उसने कौन-से पते बाइंड किए हैं और ज़ोरदार चेतावनी देती है यदि
`DIRECTORY_ADMIN_ADDR` लूपबैक नहीं है।

### ऐप को इसकी ओर इंगित करना

तीन तरीके, उस क्रम में जिसमें आप सामान्यतः इन्हें अपनाते हैं:

1. **पहली बार चलने वाली स्क्रीन**: "Custom server" चुनें और URL दर्ज करें। §3 देखें।
2. **सेटिंग्स → Directory server**: इसे बाद में बदलें; अगले
   पुनरारंभ पर प्रभावी होता है।
3. **`P2P_CHAT_DIRECTORY_URL`**, लॉन्च करने से पहले सेट करें: पूछना
   पूरी तरह छोड़ देता है और जो भी सहेजा गया था उसे ओवरराइड करता है, विकास/स्क्रिप्टेड रन के लिए उपयोगी:   ```sh
   P2P_CHAT_DIRECTORY_URL=https://directory.example.com npm run tauri dev

हर कोई जो एक-दूसरे को खोजना चाहता है, उसे उसी निर्देशिका उदाहरण की ओर इंगित करना होता है; इसी तरह वे पहले स्थान पर एक-दूसरे को ढूँढते हैं।

इसे एक वास्तविक सेवा के रूप में चलाना (systemd)

systemd यूनिट + नोट्स दिखाएँ```ini # /etc/systemd/system/seal-directory.service [Unit] Description=Seal directory server After=network.target

[Service] Type=simple User=seal-directory Group=seal-directory Environment=DIRECTORY_DB_PATH=/var/lib/seal-directory/directory.sqlite3 Environment=DIRECTORY_PUBLIC_ADDR=127.0.0.1:8080 Environment=DIRECTORY_ADMIN_ADDR=127.0.0.1:8090 EnvironmentFile=/etc/seal-directory/admin-token.env ; DIRECTORY_ADMIN_TOKEN=... ExecStart=/usr/local/bin/directory-server Restart=on-failure

Sandboxing: this process needs almost nothing

ProtectSystem=strict ProtectHome=true PrivateTmp=true NoNewPrivileges=true ReadWritePaths=/var/lib/seal-directory

[Install] WantedBy=multi-user.target

नोट्स:

- `DIRECTORY_PUBLIC_ADDR` को जानबूझकर यहाँ **loopback** से बाँधा गया है; TLS (नीचे) के लिए
  सामने एक रिवर्स प्रॉक्सी रखें, न कि axum को इंटरनेट पर सीधे
  उजागर करें।
- पहले `seal-directory` सिस्टम यूज़र/ग्रुप और
  `/var/lib/seal-directory` बनाएँ (`useradd --system --no-create-home
  seal-directory && install -d -o seal-directory -g seal-directory
  /var/lib/seal-directory`), और निर्मित `directory-server` बाइनरी को
  (`target/release/` से) `/usr/local/bin/` पर कॉपी करें।
- एडमिन टोकन को केवल रूट द्वारा पठनीय `EnvironmentFile` में रखें, सीधे
  यूनिट फ़ाइल में नहीं (यूनिट फ़ाइलें प्रायः world-readable होती हैं)।

</details>

### रिवर्स प्रॉक्सी के माध्यम से TLS

<details>
<summary>Caddy / nginx कॉन्फ़िग दिखाएँ</summary>

[Caddy](https://caddyserver.com) आपको स्वचालित HTTPS देता है
न्यूनतम कॉन्फ़िग के साथ:```
# /etc/caddy/Caddyfile
directory.example.com {
    reverse_proxy 127.0.0.1:8080
}

caddy run (या systemctl enable --now caddy) प्रमाणपत्र जारी करने/नवीनीकरण का काम स्वयं संभालता है। यदि आप nginx का उपयोग करना चाहें, तो TLS वहीं समाप्त करें और proxy_pass http://127.0.0.1:8080; लगाएँ, क्योंकि ऐप को प्रॉक्सी के दृष्टिकोण से केवल सादे HTTP की आवश्यकता होती है।

फ़ायरवॉल की दृष्टि से: केवल सार्वजनिक पोर्ट को बाहर से पहुँच योग्य होना चाहिए (ऊपर के उदाहरणों में 8080, जो प्रॉक्सी के माध्यम से 443 द्वारा सामने रहता है)। एडमिन पोर्ट कभी भी बाहर से पहुँच योग्य नहीं होना चाहिए; जब आपको दूर से purge चलाना हो, तो SSH पोर्ट-फ़ॉरवर्डिंग (ssh -L 8090:127.0.0.1:8090 your-server) के माध्यम से उस तक पहुँचें।

इसे purge करना```sh

cargo run --release -p directory-server --bin directory-admin --
--admin-url http://127.0.0.1:8090 --token "$DIRECTORY_ADMIN_TOKEN" purge

यह SQLite फ़ाइल को हटाकर एक खाली स्कीमा फिर से बनाता है: न तो कोई `DELETE` स्टेटमेंट, न ही आंशिक स्थिति। इसे बिना पहले किसी को चेतावनी दिए चलाना सुरक्षित है: इसमें मौजूद हर रिकॉर्ड उस डेटा का कैश है जो प्रत्येक क्लाइंट पहले से स्थानीय रूप से रखता है (उनका अपना पंजीकरण, उपस्थिति, और कोई भी ग्रुप रोस्टर जिसके वे सदस्य हैं), इसलिए क्लाइंट अपने अगले कार्य के कुछ ही पलों में इसे फिर से भर देते हैं। इस डेटाबेस के लिए जानबूझकर कोई बैकअप नीति नहीं है; देखें [`docs/SECURITY.md`](https://github.com/emn4tor/seal/blob/HEAD/docs/SECURITY.md) कि बैकअप रखना पूरे उद्देश्य को क्यों कमजोर कर देगा।

---

## 6. ऐप का उपयोग करना

1. **पहला लॉन्च, पहला सवाल**: किस डायरेक्टरी सर्वर का उपयोग करना है (§3)। डिफ़ॉल्ट वही है जो आपके चलाए जा रहे बिल्ड में अंतर्निहित है (एक स्थानीय परीक्षण सर्वर, जब तक कि जिसने इसे बनाया है उसने कोई आधिकारिक सर्वर कॉन्फ़िगर न किया हो); "Custom server" चुनें जो आपके या किसी विश्वसनीय व्यक्ति द्वारा होस्ट किए गए सर्वर की ओर इशारा करे।
2. **एक प्रदर्शन नाम चुनें।** यह आपके डिवाइस पर एक निजी कुंजी जोड़ी उत्पन्न करता है (याद रखने के लिए कुछ नहीं, और खो जाने पर पुनर्प्राप्ति योग्य कुछ भी नहीं: यह जानबूझकर है) और एन्क्रिप्शन वास्तव में कैसे काम करता है, इसकी एक छोटी इन-ऐप व्याख्या के माध्यम से आपको ले जाता है। इसे सेटिंग्स से कभी भी दोबारा चलाएँ। हर बाद के लॉन्च में बिना किसी संकेत के सीधे वापस चला जाता है; ऐसा प्रति खाते केवल एक बार होता है। इस डिवाइस पर सेटिंग्स → खाते से और खाते (पूरी तरह से अलग पहचान) जोड़ें, और बिना पुनरारंभ किए उनके बीच स्विच करें।
3. **किसी को जोड़ें**: "Direct messages" के बगल में **+** पर क्लिक करें और उनका ID दर्ज करें (जो *उनकी* सेटिंग्स → My Identity में मिलता है)। डिज़ाइन के अनुसार ब्राउज़ करने के लिए कोई डायरेक्टरी नहीं है; आप उसी तरह जुड़ते हैं जैसे आप फ़ोन नंबर साझा करते हैं।
4. **उन्हें संदेश भेजें**: सूची से उनका नाम चुनें और टाइप करें। किसी को भेजा गया पहला संदेश स्वचालित रूप से एक एन्क्रिप्टेड सत्र स्थापित करता है।
5. **एक ग्रुप शुरू करें**: आइकन पट्टी पर **+** पर क्लिक करें, उसे नाम दें, फिर उसी तरह लोगों को ID द्वारा आमंत्रित करें। किसी को हटाने पर ग्रुप की कुंजी बदल दी जाती है ताकि वे उसके बाद भेजी गई कोई भी चीज़ न पढ़ सकें।
6. **सब कुछ हटाएँ**: सेटिंग्स → डेटा और गोपनीयता। यह तुरंत, केवल-स्थानीय और अपरिवर्तनीय है: यह *इस डिवाइस* पर आपकी कुंजियाँ, संपर्क और इतिहास नष्ट कर देता है और आपके द्वारा बात किए गए किसी भी व्यक्ति पर इसका कोई प्रभाव नहीं पड़ता है।

श्रेणियाँ