Serein
Rust로 만든 가볍고 성능 좋은 Discord 전용 네이티브 클라이언트
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기NodeX web app: decentralized, peer-to-peer chat in the browser (Next.js, libp2p)
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
A decentralized, peer-to-peer chat app that runs in your browser.
Your identity lives on your device, not on a server.
The backend runs on Render's free plan, so after a quiet spell the first visit can take about a minute while it wakes up; the app connects by itself once it does. To try chat, open the app in a normal and a private window, create two identities, and search for one from the other by its handle.README 전문 보기 ↗| Live | Address |
|---|---|
| App (Vercel) | https://node-x-frontend-red.vercel.app |
| Email verifier (Render) | https://nodex-verifier.onrender.com |
| P2P node (Render) | /dns4/nodex-node.onrender.com/tcp/443/wss/p2p/12D3KooWPXJbYpESjgy7rxyTgS6szXv373DHJBjidVRbzgSRAfr3 |
The backend runs on Render's free plan, so after a quiet spell the first visit can take about a minute while it wakes up; the app connects by itself once it does. To try chat, open the app in a normal and a private window, create two identities, and search for one from the other by its handle.
This repository is the NodeX web app (Next.js). It needs two small services from the NodeX-backend repository: a P2P node that browsers join the network through, and an email verifier used once at sign-up.
NodeX is a messaging app built on a simple principle: no central server owns your account.
Rahul#7K3M9X.| Feature | Details | |
|---|---|---|
| ✅ | Email verification | A 6-digit code sent to your email during sign-up |
| ✅ | Cryptographic identity | Ed25519 key pair and libp2p Peer ID, generated on your device |
| ✅ | Handle | DisplayName#TAG, e.g. Rahul#7K3M9X, case-insensitive. It's your only username. |
| ✅ | 12-word recovery phrase | BIP39; restores the exact same identity on any device |
| ✅ | Passwordless local login | Email + handle + recovery phrase, checked on your device |
| ✅ | Secure key storage | Private key encrypted with a non-exportable browser key |
| ✅ | Find people by handle (P2P) | Signed records in a libp2p DHT, verified on your device |
| ✅ | Real-time P2P chat | Browser to browser over WebRTC, end-to-end encrypted |
| ✅ | Ticks and read receipts | 🕓 waiting · ✓ delivered · ✓✓ read; unread counts |
| ✅ | Offline queue | Messages to an offline friend wait on your device and go out when they're back |
| ✅ | Disappearing messages | Deleted from both devices 48 hours after being read |
| ✅ | Photos, videos, documents | Photos compressed on device; files up to 50 MB with progress, cancel and resume |
| ✅ | Emoji picker | Built in; emoji-only messages shown large |
| ✅ | Reply, forward, edit, delete | Quote replies, forward to another chat, edit your messages, delete for me / for everyone |
| ✅ | Typing indicator and last seen | "typing…" and "last seen today at 11:05", from your own device's connections |
| ✅ | Profile photo (P2P) | Shared device to device; visible to everyone or "My contacts only" |
| ✅ |
Everything below runs in your browser:
12-word recovery phrase ──BIP39──► Ed25519 private key ──► Peer ID (12D3KooW…)
email + Peer ID ──PBKDF2 (200k)──► email commitment
display name + Peer ID + commitment ──PBKDF2 (600k)──► 6-character tag
handle = DisplayName # TAG → Rahul#7K3M9X
0-9 A-Z without I L O U); I/L are read as 1 and O as 0.You (browser) ──publish signed record──► NodeX DHT ◄──lookup "rahul#7k3m9x"── Someone else (browser)
key = /nodex/<lowercase handle>, value = { handle, peer_id, email_commitment, seq, sig }), and republishes it every 6 hours while the app is open.Search is by exact handle (a DHT can't do partial search) and sends no HTTP requests.
Asha's browser ──WebRTC (direct, encrypted)──► Bob's browser
│ │
└──── handshake only, via a NodeX node ───┘
| Protocol | Used for |
|---|---|
/nodex/chat/1.0.0 | Messages, photos (60 KB chunks), acks, read receipts, typing, edits, deletions |
/nodex/file/1.0.0 | Videos and documents: the receiver pulls the bytes, with resume and SHA-256 check |
/nodex/profile/1.0.0 | Profile photos: fetch and live updates |
Both people need the app open at the same time for a message to move. There's no server to hold messages for offline users.
| Data | Where it lives | Sent to a server? |
|---|---|---|
| 12-word recovery phrase | Only with you (written down) | ❌ Never |
| Private key | Your device, encrypted with a non-exportable device key | ❌ Never |
| Not stored; the verifier sees it only to send the code | Only during sign-up | |
| Handle record | The P2P network's DHT, so others can find you | Public by design |
| Contacts, messages, block list | Your device | ❌ Never |
| Profile photo | Your device, and devices of people allowed to see it | ❌ Never |
The email commitment in your public handle record is a slow, salted hash of your email, needed so anyone can check your handle belongs to your key. Someone who already suspects your exact email could test that guess, so treat your handle as linked to your email.
git clone https://github.com/noobdivya/NodeX-frontend.git
cd NodeX-frontend
cp .env.example .env.local # paste the P2P node address into it
npm install
npm run dev
Open http://localhost:3000 and create your identity. The home screen shows Online · discoverable on the NodeX network once your handle is published. To try chat, create a second identity in a private/InPrivate window and look it up by its handle.
.env.local)| Variable | Default | Description |
|---|---|---|
NEXT_PUBLIC_API_URL | http://localhost:8080 | Address of the email verifier |
NEXT_PUBLIC_BOOTSTRAP_PEERS | – | P2P node address(es) to join the network through, as printed by the node (comma-separated) |
NEXT_PUBLIC_STUN_SERVERS | – | Optional STUN servers (e.g. stun:stun.l.google.com:19302) so browsers on different networks can connect directly. STUN never sees messages. |
NEXT_PUBLIC_BOOTSTRAP_PEERS value from its logs.NEXT_PUBLIC_BOOTSTRAP_PEERS = the node's /dns4/…/tcp/443/wss/p2p/… addressNEXT_PUBLIC_API_URL = the verifier's address, e.g. https://nodex-verifier.onrender.comCORS_ORIGINS to your Vercel address.Every page is static, so the app is served from Vercel's CDN; all networking happens in the browser.
app/ Pages: /, /register, /login, /home
components/
├── register/ Email → code → name → phrase → identity
├── login/ Log in / recover
└── home/ Chat list, chat screen, search, profile, menu
lib/
├── identity.ts Keys, recovery phrase, handle derivation
├── handle.ts Handle parsing, case-insensitive comparison
├── keystore.ts Encrypted identity vault (IndexedDB)
├── contacts.ts Local contacts, last seen, block flag
├── messages.ts Local message storage (IndexedDB)
├── profile.ts Profile photos and photo privacy
├── image.ts Photo crop, resize and compression
├── notifications.ts Background notifications
├── api.ts Email verifier calls
└── p2p/
├── node.ts Browser libp2p node: join, publish, look up, WebRTC
├── record.ts Create/validate handle records (mirrors the node's record.go)
├── chat.ts Chat protocol: messages, acks, receipts, edits, deletes, typing
├── file-transfer.ts Video/document transfer with resume
├── profile-share.ts Profile photo sharing
└── blocklist.ts Blocked people, enforced on this device
| Layer | Technology |
|---|---|
| App | Next.js 16, React 19, TypeScript |
| Cryptography | @libp2p/crypto, @libp2p/peer-id, @scure/bip39, Web Crypto (PBKDF2, AES-GCM, SHA-256) |
| P2P | libp2p, @libp2p/kad-dht, @libp2p/websockets, @libp2p/webrtc, @libp2p/circuit-relay-v2, Noise, Yamux |
| Storage | IndexedDB |
End-to-end tests run in real browsers (Playwright, two or three users at once) against a local P2P node. They cover sign-up, recovery and case-insensitive login; P2P search including a forged record being rejected; real-time chat over a confirmed direct WebRTC connection; offline delivery; read receipts and disappearing messages; photos, videos and documents arriving byte-for-byte identical (including cancel and resume); reply, forward, edit and delete; last seen, typing, notifications, blocking and photo privacy; and that none of this makes HTTP requests to any server.
npx tsc --noEmit # type-check
npm run build # production build
Issues and pull requests are welcome. Please open an issue first to discuss larger changes.
No license has been chosen yet. Until one is added, all rights are reserved by the author.
| Notifications |
| While NodeX is open in the background; unread count in the tab title |
| ✅ | Block a user | Your device refuses their connections and requests; they aren't told |