initial echo project website (rust + axum + askama)

This commit is contained in:
Jean Chevronnet 2026-08-30 18:21:49 +00:00
commit 899040a319
No known key found for this signature in database
GPG key ID: 439666D63A9477E4
11 changed files with 1480 additions and 0 deletions

40
templates/base.html Normal file
View file

@ -0,0 +1,40 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% block title %}echoIRCd{% endblock %}</title>
<meta name="description" content="echoIRCd — a modern IRC network built from scratch in Rust: TLS 1.3, full IRCv3, SASL, and native services.">
<meta property="og:title" content="echoIRCd">
<meta property="og:description" content="A modern IRC network, built from scratch in Rust.">
<meta property="og:type" content="website">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="stylesheet" href="/static/style.css">
</head>
<body>
<header class="nav">
<a class="brand" href="/">echo<span class="dot">IRCd</span></a>
<nav class="navlinks">
<a href="/"{% if active == "home" %} class="on"{% endif %}>Home</a>
<a href="/features"{% if active == "features" %} class="on"{% endif %}>Features</a>
<a href="/connect"{% if active == "connect" %} class="on"{% endif %}>Connect</a>
<a href="https://git.devtronic.pro/echo/echoIRCd" class="ext">Source&nbsp;&#8599;</a>
</nav>
</header>
<main>
{% block content %}{% endblock %}
</main>
<footer class="foot">
<div class="foot-in">
<div>echoIRCd — native Rust IRC daemon &amp; services · <span class="mono">#![forbid(unsafe_code)]</span></div>
<div class="foot-links">
<a href="https://git.devtronic.pro/echo/echoIRCd">echoIRCd</a>
<a href="https://git.devtronic.pro/echo/echo">services</a>
<a href="https://git.devtronic.pro/echo/website">website</a>
</div>
</div>
</footer>
</body>
</html>

58
templates/connect.html Normal file
View file

@ -0,0 +1,58 @@
{% extends "base.html" %}
{% block title %}Connect — echoIRCd{% endblock %}
{% block content %}
<section class="page-head">
<h1>Connect</h1>
<p class="lede">Point any IRC client at the network — or open it in your browser.</p>
</section>
<section class="wrap">
<table class="detail">
<tr><th>Server</th><td class="mono">irc.echoircd.org</td></tr>
<tr><th>TLS (recommended)</th><td class="mono">6697</td></tr>
<tr><th>Plaintext</th><td class="mono">6667</td></tr>
<tr><th>Network</th><td class="mono">echoiRCd</td></tr>
</table>
<div class="webchat">
<span>Prefer the browser?</span>
<a class="btn" href="https://orbit.devtronic.pro">Open the web client &#8599;</a>
</div>
<h2 class="section-title">Client quick-start</h2>
<div class="block">
<p>Most clients accept a one-line server string. The leading <span class="mono">+</span> on the
port means TLS.</p>
<pre class="code">/server irc.echoircd.org +6697
/join #echoircd</pre>
<table class="detail">
<tr><th>HexChat</th><td class="mono">Network list → Add → irc.echoircd.org/+6697 → tick "Use SSL"</td></tr>
<tr><th>WeeChat</th><td class="mono">/server add echo irc.echoircd.org/6697 -tls</td></tr>
<tr><th>irssi</th><td class="mono">/connect -tls irc.echoircd.org 6697</td></tr>
<tr><th>mIRC</th><td class="mono">/server irc.echoircd.org +6697</td></tr>
</table>
</div>
<h2 class="section-title">Register your nick</h2>
<div class="block">
<p>Registering lets you keep your nickname, found channels, and log in with SASL.</p>
<pre class="code">/msg NickServ REGISTER &lt;password&gt; &lt;email&gt;
/msg NickServ IDENTIFY &lt;password&gt;</pre>
</div>
<h2 class="section-title">Log in with a key (ECDSA)</h2>
<div class="block">
<p>Instead of a password you can authenticate with a NIST&nbsp;P-256 key. The server sends a
challenge, your client signs it, and the signature is checked against the key on your
account — nothing secret crosses the wire.</p>
<pre class="code"># generate a key and read its public half
ecdsatool keygen ~/.ecdsa.pem
ecdsatool pubkey ~/.ecdsa.pem
# store it on your account, then use ECDSA-NIST256P-CHALLENGE for SASL
/msg NickServ SET PUBKEY &lt;printed-public-key&gt;</pre>
<p class="hint">Point your client's SASL settings at the same key file and pick the
<span class="mono">ECDSA-NIST256P-CHALLENGE</span> mechanism.</p>
</div>
</section>
{% endblock %}

85
templates/features.html Normal file
View file

@ -0,0 +1,85 @@
{% extends "base.html" %}
{% block title %}Features — echoIRCd{% endblock %}
{% block content %}
<section class="page-head">
<h1>Features</h1>
<p class="lede">Everything below is original, native Rust — the InspIRCd protocol and API are a
reference for wire compatibility, never a source of code.</p>
</section>
<section class="wrap prose">
<div class="block">
<h2>The daemon</h2>
<ul>
<li><strong>Safe by construction</strong><span class="mono">#![forbid(unsafe_code)]</span> across the whole tree, enforced in CI.</li>
<li><strong>Reactor core</strong> — a single core thread with a mio/epoll reactor pool; zero-copy broadcast lines and parallel large-channel fan-out.</li>
<li><strong>Full mode set</strong> — every standard channel and user mode, host cloaking, and custom prefixes.</li>
<li><strong>Operators</strong> — an InspIRCd-style privilege model: command grants, named privileges, and a usermode/chanmode allow-list per oper type.</li>
<li><strong>Edge</strong> — connection classes, per-class flood / fakelag, RFC&nbsp;1413 ident, and PROXY protocol v1/v2 (with TLS TLVs).</li>
<li><strong>Observability</strong> — a metrics endpoint, structured JSON logging, and native syslog.</li>
</ul>
</div>
<div class="block">
<h2>Transport &amp; TLS</h2>
<ul>
<li><strong>6697</strong> direct TLS, <strong>7799</strong> WebSocket-over-TLS (wss), <strong>6667</strong> plaintext.</li>
<li>Two interchangeable backends — <strong>OpenSSL</strong> and <strong>rustls</strong> — both serving TLS&nbsp;1.3.</li>
<li>With OpenSSL&nbsp;3.5 the handshake negotiates post-quantum <span class="mono">X25519MLKEM768</span> key exchange.</li>
<li>Per-host <strong>SNI</strong> certificates, reloaded live on rehash.</li>
</ul>
</div>
<div class="block">
<h2>IRCv3</h2>
<p>Capabilities advertised to clients:</p>
<div class="chips">
<span>server-time</span><span>message-tags</span><span>account-tag</span><span>account-notify</span>
<span>extended-join</span><span>chghost</span><span>multi-prefix</span><span>away-notify</span>
<span>invite-notify</span><span>setname</span><span>echo-message</span><span>userhost-in-names</span>
<span>batch</span><span>labeled-response</span><span>standard-replies</span><span>extended-monitor</span>
<span>draft/chathistory</span><span>draft/event-playback</span><span>draft/message-redaction</span>
<span>draft/multiline</span><span>draft/metadata-2</span><span>draft/read-marker</span>
<span>draft/webpush</span><span>draft/account-registration</span><span>sts</span>
</div>
</div>
<div class="block">
<h2>SASL</h2>
<ul>
<li><strong>PLAIN</strong> — classic username/password.</li>
<li><strong>EXTERNAL</strong> — authenticate by TLS client-certificate fingerprint.</li>
<li><strong>SCRAM-SHA-256</strong> — challenge/response, no password on the wire.</li>
<li><strong>ECDSA-NIST256P-CHALLENGE</strong> — sign a server challenge with a NIST&nbsp;P-256 key; the private key never leaves your client.</li>
</ul>
</div>
<div class="block">
<h2>Services</h2>
<ul>
<li><strong>NickServ</strong> — registration, grouped nicks, certificates, public keys, vhosts, profile metadata.</li>
<li><strong>ChanServ</strong> — founder/access, auto-op, akick, topic and mode locks.</li>
<li><strong>OperServ / MemoServ / more</strong> — network administration, offline messaging, and games.</li>
<li><strong>Event-sourced</strong> — every change is an appended event, replayed to rebuild state.</li>
<li><strong>SASL over S2S</strong> — the daemon relays mechanisms mechanism-agnostically; the services layer holds the credentials.</li>
</ul>
</div>
<div class="block">
<h2>Security</h2>
<ul>
<li>A native anti-abuse engine in the core — not a bolt-on module.</li>
<li>Connection-flood and nick-flood detection, mass-join screening.</li>
<li>Behavioral and content heuristics with computed-pattern mining.</li>
<li>A DEFCON state machine and policy, plus DNSBL / MX-blacklist screening via a native async resolver.</li>
</ul>
</div>
</section>
<section class="connect-strip">
<div class="cs-in">
<div><h2>Ready?</h2><p>See how to connect and register.</p></div>
<a class="btn primary" href="/connect">Connect &amp; register</a>
</div>
</section>
{% endblock %}

93
templates/index.html Normal file
View file

@ -0,0 +1,93 @@
{% extends "base.html" %}
{% block title %}echoIRCd — a modern IRC network in Rust{% endblock %}
{% block content %}
<section class="hero">
<div class="badge-row">
<span class="badge">100% safe Rust</span>
<span class="badge">TLS 1.3 · post-quantum</span>
<span class="badge">Full IRCv3</span>
<span class="badge">SASL</span>
</div>
<h1>A modern IRC network,<br>built from scratch in <span class="accent">Rust</span>.</h1>
<p class="lede">echoIRCd is an original IRC daemon and services suite — no forks, no C, no
<span class="mono">unsafe</span>. Full IRCv3, modern TLS, server-to-server linking, and a
complete services stack with accounts, channels, and SASL.</p>
<div class="cta">
<a class="btn primary" href="/connect">Connect now</a>
<a class="btn" href="/features">Explore features</a>
</div>
<div class="connectline mono">/server irc.echoircd.org +6697</div>
</section>
<section class="split">
<div class="card">
<h3>echoIRCd <span class="tag">the daemon</span></h3>
<p>A single-threaded core with an epoll reactor pool and a module-per-file architecture.
The full channel and user mode set, host cloaking, connection classes, PROXY protocol,
ident, and an InspIRCd-style operator privilege system.</p>
</div>
<div class="card">
<h3>echo <span class="tag">the services</span></h3>
<p>NickServ, ChanServ, OperServ, MemoServ and more, linked over a standard server-to-server
protocol. Account registration, vhosts, grouped nicks, memos and SASL — all backed by an
event-sourced store.</p>
</div>
</section>
<section class="wrap">
<h2 class="section-title">What's inside</h2>
<div class="grid">
<div class="feat">
<div class="ico">&#128274;</div>
<h4>Modern TLS</h4>
<p>Direct TLS on 6697 and WebSocket (wss) on 7799. OpenSSL <em>and</em> rustls backends,
TLS&nbsp;1.3 with post-quantum X25519MLKEM768, and per-host SNI certificates.</p>
</div>
<div class="feat">
<div class="ico">&#9889;</div>
<h4>Full IRCv3</h4>
<p>server-time, message-tags, account-tag, extended-join, batch, labeled-response,
chathistory, multiline, setname, standard-replies, metadata and more.</p>
</div>
<div class="feat">
<div class="ico">&#128273;</div>
<h4>SASL</h4>
<p>PLAIN, EXTERNAL (certificate fingerprint), SCRAM-SHA-256, and
ECDSA-NIST256P-CHALLENGE — sign a challenge with your key, no password on the wire.</p>
</div>
<div class="feat">
<div class="ico">&#129302;</div>
<h4>Services</h4>
<p>Accounts, channels, vhosts, memos and games over a standard S2S link, with SASL relayed
mechanism-agnostically to the services layer.</p>
</div>
<div class="feat">
<div class="ico">&#128737;</div>
<h4>Anti-abuse</h4>
<p>A native security subsystem: connection and nick-flood detection, behavioral and content
heuristics, DEFCON states, and DNSBL / MX screening.</p>
</div>
<div class="feat">
<div class="ico">&#127760;</div>
<h4>Localized</h4>
<p>Server-wide locale catalogs translate numerics and service replies at a single chokepoint.
English stays zero-cost; switch locales on rehash.</p>
</div>
</div>
</section>
<section class="connect-strip">
<div class="cs-in">
<div>
<h2>Jump in.</h2>
<p>Point any IRC client at the network and say hello.</p>
</div>
<table class="mini">
<tr><td>Server</td><td class="mono">irc.echoircd.org</td></tr>
<tr><td>TLS</td><td class="mono">6697</td></tr>
<tr><td>WebSocket</td><td class="mono">7799 (wss)</td></tr>
<tr><td>Network</td><td class="mono">echoiRCd</td></tr>
</table>
</div>
</section>
{% endblock %}