Skip to content
Simple-Irc-ClientPublic

About

📦 React front-end for Simple Irc Client

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

1 watching

Forks

Latest commit

 

History

1,182 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Simple Irc Client core

Build Status OpenSSF Scorecard

A React IRC client that connects to IRC servers directly over WebSocket.

Features

  • Direct WebSocket connection, no backend required
  • Responsive UI (Tailwind CSS, shadcn/ui), light and dark mode
  • Built-in themes (classic, modern, irc) and custom CSS themes; comfortable or compact spacing, 24 or 12-hour time, with or without seconds
  • IRCv3: SASL, STS, chathistory, typing, metadata, MONITOR, read markers, pre-away, standard replies and more
  • Replies, emoji reactions, multiline messages and deleting messages (IRCv3 drafts); replies and multiline messages fall back to plain lines where the server lacks them
  • Spoilers (||text||) and quotes (> text)
  • Bouncers: soju networks picked in the wizard or from the user menu, and the history and read state the bouncer keeps
  • Older history loaded by scrolling up, and a search through the messages of the open windows
  • Highlight words, an ignore list (/ignore), and notification sounds for private messages and mentions
  • Joins, parts, quits and nick changes collapsed into one line, optionally hiding people who said nothing
  • Keyboard shortcuts: a window switcher (Ctrl/⌘+K), message search (Ctrl/⌘+Shift+F) and the list of shortcuts (Ctrl/⌘+/)
  • Auto away after a chosen time, with a message of your own
  • A nick already in use: connects as nick_, takes the nick back once it is free (MONITOR/WATCH), or asks NickServ to free it
  • End-to-end encrypted private messages (SIC-E2EE v1, described below)
  • Through the Simple IRC Client gateway: sessions survive a backgrounded mobile tab (see below)

Resumable Gateway Sessions

Built in gateway mode, the app asks the gateway for a resumable session. When the WebSocket drops (a phone puts the tab in the background), the gateway keeps the IRC connection and buffers what arrives. When the tab is visible again, the app reconnects with the session token and the number of the last line it saw, skips registration, and receives exactly the lines it missed. Channels, nick and negotiated capabilities stay as they were, and other users see no quit or rejoin.

  • If the gateway no longer has the session (it expired or the gateway restarted), the same connection registers from scratch.
  • After a page reload the app cannot resume, so it asks the gateway to end the old session and starts a new one.
  • Disconnecting from the menu, or /quit, sends QUIT so the gateway ends the session right away.
  • Encrypted conversations carry on: the peer never saw the connection end, so the session keys are kept and missed encrypted messages are decrypted from the replay.
  • When some missed lines were dropped from the gateway's buffer, the app says so, refreshes the user lists of open channels and ends encrypted sessions, since a lost QUIT could mean someone else now holds a peer's nick; they are re-offered once presence reports the peer.
  • It works the same on servers without IRCv3: the gateway adds the time it received each line to replayed lines that have no server-time.

The protocol is described in the gateway's README.

End-to-End Encryption (E2EE)

SIC-E2EE v1 encrypts private messages between clients without any server-side support. It uses WebCrypto only, with no third-party crypto library.

Protocol Overview

The protocol uses a Noise-like handshake with Triple Diffie-Hellman (3DH) for authentication and forward secrecy:

  • Key Exchange: ECDH P-256 (chosen for broad WebCrypto compatibility across desktop webviews)
  • Encryption: AES-256-GCM with 12-byte nonces
  • Key Derivation: HKDF-SHA256 with a transcript hash as salt
  • Message Format: CTCP-based, graceful degradation (non-SIC clients see nothing)

Handshake Flow

Alice (Initiator)                          Bob (Responder)
      |                                        |
      |--- SIC-E2EE OFFER 1 <idKey> <ephKey> --->
      |                                        |
      |<---- SIC-E2EE ACCEPT 1 <idKey> <ephKey> ---
      |                                        |
      [Both derive session keys]              [Both derive session keys]
      |                                        |
      |--- SICE <frameId> 1/1 <ciphertext> ---->
      |                                        |

The handshake produces:

  • Three DH operations mixed into IKM: DH(ephA,ephB) + DH(idA,ephB) + DH(ephA,idB)
  • Transcript hash over all four public keys as HKDF salt
  • Separate send/recv keys derived with different info labels (sic-e2ee-v1 i2r / sic-e2ee-v1 r2i)

Security Properties

  • Forward Secrecy: Per handshake, not per message (no ratchet); compromising a long-term identity key does not decrypt past sessions
  • Authentication: Long-term identity keys bind the session to specific peers
  • TOFU Pinning: First-seen identity keys are pinned; changed keys block the session and warn the user
  • Fingerprint Verification: Users can compare 64-bit fingerprints (shown as NATO phonetic alphabet words) out-of-band to detect MITM at first contact
  • No Silent Downgrade: If encryption was previously established with a peer, dropping back to plaintext shows a warning

Identity Management

  • Each IRC network has its own identity key pair
  • Identity keys are non-extractable CryptoKey objects stored in IndexedDB via structured clone
  • Private keys are never exposed as raw bytes to JavaScript, so they cannot be exported or copied out
  • Fingerprints are displayed as 16 NATO phonetic alphabet words, one per hex nibble (e.g., Zero One Two Three Four Five Six Seven Eight Nine Alpha Bravo Charlie Delta Echo Foxtrot) — internationally standard and unambiguous to read aloud

Message Handling

  • Chunking: Large messages split into multiple IRC lines (frame size follows the server's LINELEN, 320 base64 chars by default; max 16 frames)
  • Reassembly: Out-of-order chunks are buffered and reassembled within 120 seconds of the first chunk
  • Message Types: Regular messages (m) and actions/CTCP ACTION (a) are preserved through encryption
  • No Plaintext Leak: Even /me actions are encrypted, not sent as cleartext ACTION

Rate Limiting

  • Inbound OFFER frames throttled to 1 per peer per second
  • RESET replies throttled to 1 per peer per 10 seconds
  • Tracked peers and pending frames are capped, so memory use stays bounded

User Experience

The encryption state is always visible:

  • Lock icon in conversation header shows encryption status
  • Banners appear for handshake prompts, key-mismatch warnings, and errors — an unverified-but-encrypted session is the expected TOFU default and stays quiet, with verification discoverable in the lock popover instead of nagging
  • Color coding:
    • Green lock = Encrypted & verified
    • Yellow lock = Encrypted but unverified
    • Red shield = Key mismatch / security issue
    • Open lock = No encryption (with warning if previously encrypted)

Users can:

  • Start encryption with any peer via the lock button menu
  • Accept or decline incoming encryption requests
  • View and compare fingerprints in the lock popover
  • Mark a peer as verified after out-of-band fingerprint comparison
  • End active encryption sessions

Privacy Features

  • Per-network identities: Prevents correlation of the same user across different IRC networks
  • No history storage: Encrypted messages are not persisted to IndexedDB; only plaintext messages are stored
  • Session binding to nicks: If a peer changes nick, the session is dropped (not automatically transferred)

Wire Format

All E2EE traffic uses CTCP (Client-To-Client Protocol):

Handshake:
  SIC-E2EE OFFER 1 <identityKeyB64> <ephemeralKeyB64>  (PRIVMSG)
  SIC-E2EE ACCEPT 1 <identityKeyB64> <ephemeralKeyB64> (NOTICE)
  SIC-E2EE DECLINE                                    (NOTICE)
  SIC-E2EE RESET                                      (NOTICE)

Encrypted messages:
  SICE <frameId> <index>/<total> <base64Chunk>         (PRIVMSG)

CTCP was chosen because unknown CTCP verbs are silently ignored by other IRC clients, providing graceful degradation.

Getting Started

Installation

pnpm install

Development

Start the development server:

pnpm run dev

The application will be available at http://localhost:5173

Tests

pnpm test          # unit tests
pnpm run test:e2e  # Playwright, against IRC servers in Docker

Every e2e test runs twice: against ergo, an IRCv3 server, and through the gateway against ngircd, a server without IRCv3 (the *-legacy-* projects). The tests serve the app on ports of their own (5273 and 5274), so a running pnpm run dev is left alone. Tests of IRCv3-only features are skipped on ngircd. The gateway runs from source for the *-gateway and *-legacy-* projects; it expects a checkout next to this repository (../gateway, with pnpm install done); set E2E_GATEWAY_DIR to use another location.

Docker

Run using Docker:

docker build -t simple-irc-client .
docker run -p 5173:5173 simple-irc-client

The application will be available at http://localhost:5173

Related Projects

Contributing

If you find a bug or have a feature request, please open an issue on GitHub.

License

This project is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0).

The AGPL-3.0 license ensures that if you modify and deploy this software over a network, you must make the complete source code available to users.

Authors:

About

📦 React front-end for Simple Irc Client

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages