chore: rename project quicnprotochat -> quicproquo (binaries: qpq)

Rename the entire workspace:
- Crate packages: quicnprotochat-{core,proto,server,client,gui,p2p,mobile} -> quicproquo-*
- Binary names: quicnprotochat -> qpq, quicnprotochat-server -> qpq-server,
  quicnprotochat-gui -> qpq-gui
- Default files: *-state.bin -> qpq-state.bin, *-server.toml -> qpq-server.toml,
  *.db -> qpq.db
- Environment variable prefix: QUICNPROTOCHAT_* -> QPQ_*
- App identifier: chat.quicnproto.gui -> chat.quicproquo.gui
- Proto package: quicnprotochat.bench -> quicproquo.bench
- All documentation, Docker, CI, and script references updated

HKDF domain-separation strings and P2P ALPN remain unchanged for
backward compatibility with existing encrypted state and wire protocol.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-01 20:11:51 +01:00
parent 553de3a2b7
commit 853ca4fec0
152 changed files with 4070 additions and 788 deletions

View File

@@ -0,0 +1,78 @@
//! Parse `username@domain` federated addresses.
//!
//! A bare `username` (no `@`) is treated as local.
/// A parsed federated address.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FederatedAddress {
pub username: String,
pub domain: Option<String>,
}
impl FederatedAddress {
/// Parse a `user@domain` string. Bare `user` → domain is `None`.
pub fn parse(input: &str) -> Self {
// Split on the *last* '@' so usernames can contain '@' in theory.
match input.rsplit_once('@') {
Some((user, domain)) if !domain.is_empty() && !user.is_empty() => Self {
username: user.to_string(),
domain: Some(domain.to_string()),
},
_ => Self {
username: input.to_string(),
domain: None,
},
}
}
/// Returns true if this address refers to a local user (no domain or domain matches local).
pub fn is_local(&self, local_domain: &str) -> bool {
match &self.domain {
None => true,
Some(d) => d == local_domain,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn bare_username() {
let addr = FederatedAddress::parse("alice");
assert_eq!(addr.username, "alice");
assert_eq!(addr.domain, None);
assert!(addr.is_local("example.com"));
}
#[test]
fn user_at_domain() {
let addr = FederatedAddress::parse("alice@remote.example.com");
assert_eq!(addr.username, "alice");
assert_eq!(addr.domain, Some("remote.example.com".into()));
assert!(!addr.is_local("local.example.com"));
assert!(addr.is_local("remote.example.com"));
}
#[test]
fn trailing_at_is_bare() {
let addr = FederatedAddress::parse("alice@");
assert_eq!(addr.username, "alice@");
assert_eq!(addr.domain, None);
}
#[test]
fn leading_at_is_bare() {
let addr = FederatedAddress::parse("@domain.com");
assert_eq!(addr.username, "@domain.com");
assert_eq!(addr.domain, None);
}
#[test]
fn multiple_at_uses_last() {
let addr = FederatedAddress::parse("user@org@domain.com");
assert_eq!(addr.username, "user@org");
assert_eq!(addr.domain, Some("domain.com".into()));
}
}