M README.md => README.md +2 -6
@@ 26,16 26,13 @@ have their own `README.md`.
## Features
-- RFC [1459][r1] and [2812][r2] compliance (almost! see [#1][i1])
-- IRCv3 support
-- IRC over WebSockets
+- IRCv3 server
- Configurable via a file that can be reloaded at runtime
-- SASL support with SQLite and PostgreSQL
- kawaii messages
[Supported extensions][ext]: `account-notify`, `away-notify`, `batch`,
`cap-notify`, `echo-message`, `extended-join`, `invite-notify`,
-`labeled-response`, `message-ids`, `message-tags`, `multi-prefix`, `sasl`,
+`labeled-response`, `message-ids`, `message-tags`, `multi-prefix`,
`server-time`, `setname`, `userhost-in-names`
ellidri doesn't support any server-to-server (S2S) protocol. As such, it is
@@ 46,7 43,6 @@ casemapping.
[r1]: https://tools.ietf.org/html/rfc1459
[r2]: https://tools.ietf.org/html/rfc2812
-[i1]: https://todo.sr.ht/~taiite/ellidri/1
[ext]: https://ircv3.net/irc/
M doc/config_full.yaml => doc/config_full.yaml +0 -65
@@ 11,22 11,6 @@
# For an example configuration file, see `config_example.yaml`.
-# Whether ellidri can be started in an unsafe state.
-#
-# If you are using ellidri for a server on production, you want to set this to
-# false and solve any problem that may arise when starting ellidri. If you
-# configure ellidri in an unsafe manner, it will display an error message and
-# quit. If you want to start ellidri anyway, set this to true; then ellidri
-# will display a warning and continue.
-#
-# Unsafe configurations are configurations that fulfill any of the following:
-# - has a plain-text or WebSocket binding on a public IP,
-# - has a TLS binding with a self-signed certificate on a public IP,
-#
-# The definition of configuration unsafety may change over time.
-unsafe: false
-
-
# Domain of the IRC server
#
# It is sent through most replies to clients as a prefix, and should be the same
@@ 106,57 90,8 @@ opers:
password: My password can't be this cute!
-# Database URL
-#
-# Specify the URL to the database ellidri should use for SASL. If unset,
-# ellidri will disable SASL. While ellidri tries its best at all times to serve
-# its users, it cannot reload the database once started. Please bear with it!
-#
-# The format of the setting is <driver>://<url>
-#
-# Supported drivers:
-# - mysql
-# - postgres (aliases: psql, postgresql)
-# - sqlite
-#
-# For sqlite, the url is the path to the file. In-memory databases are not supported.
-#
-# For postgres, the url must follow the key-value format specified at:
-# <https://docs.rs/postgres/0.17.0/postgres/config/struct.Config.html>
-#
-# Simple SQLite example:
-#database:
-# driver: sqlite
-# url: sqlite:///var/lib/ellidri/ellidri.db
-#
-# More complex example with PostgreSQL:
-database:
- # The URL to the PostgreSQL instance. See here for more details:
- # <https://docs.rs/postgres/0.17.0/postgres/config/struct.Config.html>
- url: postgres://host=/run/postgresql,localhost database=ellidri
-
- # The values below are optional and their default are shown.
-
- # Disabled by default, this is the number of *milliseconds* ellidri should
- # wait before closing an inactive connection. You'll want to set this if
- # you are billed on usage of the database.
- idle_timeout:
-
- # ellidri will not make more connections to the database than this.
- max_pool_size: 10
-
- # ellidri will make at least this number of connections to the database.
- min_pool_size: 0
-
- # If a connection to a database cannot be established within this number of
- # *milliseconds*, then ellidri will stop trying to connect and write an
- # error message.
- connect_timeout: 10000
-
-
# Misc settings
-
# Number of worker threads
#
# Worker threads handle incoming connections and messages. When set to 0,
M doc/setup-guide.md => doc/setup-guide.md +0 -6
@@ 8,7 8,6 @@ a working installation of ellidri. Namely,
3. Create a user on your system
4. Generate or localize your certificates
5. Write ellidri's configuration file
-6. Enable SASL with SQLite
This guide assume the following locations:
@@ 74,8 73,3 @@ After any change you make to the configuration file, you can apply them with
`systemctl reload ellidri`.
[config]: https://git.sr.ht/~taiite/ellidri/tree/master/doc/config_example.yaml
-
-
-## 6. Enable SASL with SQLite
-
-TODO
M src/client.rs => src/client.rs +11 -81
@@ 70,9 70,7 @@ impl ConnectionState {
match self {
ConnectionState::ConnectionEstablished => match request {
CapLs { .. } | CapReq { .. } => Ok(ConnectionState::CapGiven),
- Authenticate { .. } | CapEnd | CapList { .. } | Pass { .. } | Ping { .. } => {
- Ok(self)
- }
+ CapEnd | CapList { .. } | Pass { .. } | Ping { .. } => Ok(self),
Nick { .. } => Ok(ConnectionState::NickGiven),
User { .. } => Ok(ConnectionState::UserGiven),
Quit { .. } => Ok(ConnectionState::Quit),
@@ 80,33 78,23 @@ impl ConnectionState {
},
ConnectionState::NickGiven => match request {
CapLs { .. } | CapReq { .. } => Ok(ConnectionState::CapGiven),
- Authenticate { .. }
- | CapEnd
- | CapList { .. }
- | Nick { .. }
- | Pass { .. }
- | Ping { .. } => Ok(self),
+ CapEnd | CapList { .. } | Nick { .. } | Pass { .. } | Ping { .. } => Ok(self),
User { .. } => Ok(ConnectionState::Registered),
Quit { .. } => Ok(ConnectionState::Quit),
_ => Err(()),
},
ConnectionState::UserGiven => match request {
CapLs { .. } | CapReq { .. } => Ok(ConnectionState::CapGiven),
- Authenticate { .. } | CapEnd | CapList { .. } | Pass { .. } | Ping { .. } => {
- Ok(self)
- }
+ CapEnd | CapList { .. } | Pass { .. } | Ping { .. } => Ok(self),
Nick { .. } => Ok(ConnectionState::Registered),
Quit { .. } => Ok(ConnectionState::Quit),
_ => Err(()),
},
ConnectionState::CapGiven => match request {
CapEnd => Ok(ConnectionState::ConnectionEstablished),
- Authenticate { .. }
- | CapList { .. }
- | CapLs { .. }
- | CapReq { .. }
- | Pass { .. }
- | Ping { .. } => Ok(self),
+ CapList { .. } | CapLs { .. } | CapReq { .. } | Pass { .. } | Ping { .. } => {
+ Ok(self)
+ }
Nick { .. } => Ok(ConnectionState::CapNickGiven),
User { .. } => Ok(ConnectionState::CapUserGiven),
Quit { .. } => Ok(ConnectionState::Quit),
@@ 114,8 102,7 @@ impl ConnectionState {
},
ConnectionState::CapNickGiven => match request {
CapEnd => Ok(ConnectionState::NickGiven),
- Authenticate { .. }
- | CapList { .. }
+ CapList { .. }
| CapLs { .. }
| CapReq { .. }
| Nick { .. }
@@ 127,20 114,16 @@ impl ConnectionState {
},
ConnectionState::CapUserGiven => match request {
CapEnd => Ok(ConnectionState::UserGiven),
- Authenticate { .. }
- | CapList { .. }
- | CapLs { .. }
- | CapReq { .. }
- | Pass { .. }
- | Ping { .. } => Ok(self),
+ CapList { .. } | CapLs { .. } | CapReq { .. } | Pass { .. } | Ping { .. } => {
+ Ok(self)
+ }
Nick { .. } => Ok(ConnectionState::CapNegotiation),
Quit { .. } => Ok(ConnectionState::Quit),
_ => Err(()),
},
ConnectionState::CapNegotiation => match request {
CapEnd => Ok(ConnectionState::Registered),
- Authenticate { .. }
- | CapList { .. }
+ CapList { .. }
| CapLs { .. }
| CapReq { .. }
| Nick { .. }
@@ 163,9 146,6 @@ impl ConnectionState {
}
}
-pub const AUTHENTICATE_CHUNK_LEN: usize = 400;
-pub const AUTHENTICATE_WHOLE_LEN: usize = 1024;
-
const FULL_NAME_LENGTH: usize = 64;
/// Client data.
@@ 182,10 162,6 @@ pub struct Client {
pub cap_enabled: data::Capabilities,
state: ConnectionState,
- auth_buffer: String,
- auth_buffer_complete: bool,
- auth_id: Option<usize>,
-
nick: String,
user: String,
real: String,
@@ 224,9 200,6 @@ impl Client {
cap_version: data::cap::Version::V300,
cap_enabled: data::Capabilities::default(),
state: ConnectionState::default(),
- auth_buffer: String::new(),
- auth_buffer_complete: false,
- auth_id: None,
nick: String::from("*"),
user: String::new(),
real: String::new(),
@@ 282,45 255,6 @@ impl Client {
self.state == ConnectionState::Registered
}
- pub fn auth_id(&self) -> Option<usize> {
- self.auth_id
- }
-
- pub fn auth_set_id(&mut self, auth_id: usize) {
- self.auth_id = Some(auth_id);
- }
-
- pub fn auth_buffer_push(&mut self, buf: &str) -> Result<bool, ()> {
- if self.auth_buffer_complete {
- self.auth_buffer_complete = false;
- self.auth_buffer.clear();
- }
- if AUTHENTICATE_CHUNK_LEN < buf.len()
- || AUTHENTICATE_WHOLE_LEN < self.auth_buffer.len() + buf.len()
- {
- return Err(());
- }
- if buf != "+" {
- self.auth_buffer.push_str(buf);
- }
- self.auth_buffer_complete = buf.len() < AUTHENTICATE_CHUNK_LEN;
- Ok(self.auth_buffer_complete)
- }
-
- pub fn auth_buffer_decode(&self) -> Result<Vec<u8>, base64::DecodeError> {
- if !self.auth_buffer_complete {
- return Err(base64::DecodeError::InvalidLength);
- }
- base64::decode(&self.auth_buffer)
- }
-
- /// Free authentication-related buffers and reset authentication state.
- pub fn auth_reset(&mut self) {
- self.auth_buffer = String::new();
- self.auth_buffer_complete = false;
- self.auth_id = None;
- }
-
pub fn full_name(&self) -> &str {
&self.full_name
}
@@ 376,10 310,6 @@ impl Client {
self.account.as_ref().map(|s| s.as_ref())
}
- pub fn log_in(&mut self, account: String) {
- self.account = Some(account);
- }
-
pub fn signon_time(&self) -> u64 {
self.signon_time
}
M src/config.rs => src/config.rs +0 -46
@@ 125,9 125,6 @@ pub struct State {
/// The whole configuration.
#[derive(Deserialize, Serialize)]
pub struct Config {
- #[serde(rename = "unsafe", default)]
- pub is_unsafe: bool,
-
#[serde(default = "bindings")]
pub bindings: Vec<Binding>,
@@ 185,50 182,7 @@ fn login_timeout() -> u64 {
60_000
}
-fn db_max_size() -> u32 {
- 10
-}
-fn db_min_size() -> u32 {
- 0
-}
-fn db_connect_timeout() -> u64 {
- 10_000
-}
-
-impl State {
- pub fn sample() -> Self {
- Self {
- domain: domain(),
- default_chan_mode: default_chan_mode(),
- motd_file: motd_file(),
- password: String::new(),
- opers: Vec::new(),
- org_name: org(),
- org_location: org(),
- org_mail: org(),
- awaylen: awaylen(),
- channellen: channellen(),
- keylen: keylen(),
- kicklen: kicklen(),
- namelen: namelen(),
- nicklen: nicklen(),
- topiclen: topiclen(),
- userlen: userlen(),
- login_timeout: login_timeout(),
- }
- }
-}
-
impl Config {
- pub fn sample() -> Self {
- Self {
- is_unsafe: false,
- bindings: bindings(),
- workers: 0,
- state: State::sample(),
- }
- }
-
/// Reads the configuration file at the given path.
pub fn from_file(path: impl AsRef<path::Path>) -> Result<Self> {
let contents = fs::read_to_string(path)?;
D src/data/auth.rs => src/data/auth.rs +0 -43
@@ 1,43 0,0 @@
-/// Provider errors, used by the `Provider` trait.
-#[derive(Debug)]
-pub enum Error {
- /// Challenge response is not valid base64.
- BadBase64,
-
- /// Challenge response does not follow the mechanism's format.
- BadFormat,
-
- /// Challenge response is well-formed, but incorrect.
- InvalidCredentials,
-
- /// The provider cannot perform the authentication.
- ProviderUnavailable,
-
- /// Chosen mechanism is unsupported by the provider.
- UnsupportedMechanism,
-}
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-pub enum Mechanism {
- Plain,
- External,
-}
-
-#[derive(Clone, Copy, Debug)]
-pub enum Payload<'a> {
- Abort,
- Mechanism(Mechanism),
- Chunk(&'a str),
-}
-
-impl<'a> From<&'a str> for Payload<'a> {
- fn from(val: &'a str) -> Self {
- match val {
- "*" => Self::Abort,
- "+" => Self::Chunk(""),
- "PLAIN" => Self::Mechanism(Mechanism::Plain),
- "EXTERNAL" => Self::Mechanism(Mechanism::External),
- val => Self::Chunk(val),
- }
- }
-}
M src/data/cap.rs => src/data/cap.rs +0 -4
@@ 150,10 150,6 @@ caps! {
}
impl Capabilities {
- pub fn has_labeled_response(&self) -> bool {
- self.batch && self.labeled_response
- }
-
pub fn has_message_tags(&self) -> bool {
self.message_tags || self.server_time
}
M src/data/mod.rs => src/data/mod.rs +0 -1
@@ 1,7 1,6 @@
pub use self::cap::Capabilities;
pub use self::req::Request;
pub use self::strings::{ChannelName, HostName, JoinList, Key, List, Mask, Nickname};
-pub mod auth;
pub mod cap;
pub mod modes;
pub mod req;
M src/data/req.rs => src/data/req.rs +1 -6
@@ 135,7 135,6 @@ pub enum Request<'a> {
TopicSet(TopicSet<'a>),
// Client session related requests.
- Authenticate(auth::Payload<'a>),
CapLs(cap::Version),
CapList,
CapReq(cap::Diff),
@@ 242,10 241,7 @@ impl<'a> Request<'a> {
}
}
- Command::Authenticate => {
- let payload = auth::Payload::from(msg.params[0]);
- Self::Authenticate(payload)
- }
+ Command::Authenticate => return Err(Error::UnknownCommand("AUTHENTICATE")),
Command::Cap => match msg.params[0] {
"LS" => {
let version = cap::Version::from(msg.params[1]);
@@ 427,7 423,6 @@ impl<'a> Request<'a> {
Self::TopicSet(_) => 7,
// Client session related requests.
- Self::Authenticate(_) => 16,
Self::CapLs(_) => 1,
Self::CapList => 1,
Self::CapReq(_) => 1,
M src/data/strings.rs => src/data/strings.rs +0 -10
@@ 52,10 52,6 @@ impl Mask<'_> {
self.0
}
- pub fn u(&self) -> &UniCase<str> {
- u(self.0)
- }
-
pub fn is_channel(&self) -> bool {
let first = self.0.chars().next().unwrap();
is_namespace(first)
@@ 152,12 148,6 @@ impl<'a> TryFrom<&'a str> for Key<'a> {
#[derive(Clone, Copy, Debug)]
pub struct HostName<'a>(&'a str);
-impl HostName<'_> {
- pub fn get(&self) -> &str {
- self.0
- }
-}
-
impl<'a> TryFrom<&'a str> for HostName<'a> {
type Error = ();
M src/lines.rs => src/lines.rs +0 -16
@@ 164,22 164,6 @@ macro_rules! lines_welcome {
};
}
-//
-// SASL
-//
-
-pub const SASL_ABORTED: &str = "ABORT BAKA";
-
-pub const SASL_ALREADY: &str = "I can't authenticate you again senpai!";
-
-pub const SASL_FAILED: &str = "it's not like I wanted to do my best for you, but it didn't worked";
-
-pub const SASL_MECHS: &str = "please use these to authenticate!";
-
-pub const SASL_SUCCESSFUL: &str = "sugoi~~! looks like it worked!";
-
-pub const SASL_TOO_LONG: &str = "senpai, it's too big!";
-
#[macro_export]
macro_rules! lines_logged_in {
( $user:expr ) => {
M src/state/mod.rs => src/state/mod.rs +0 -1
@@ 389,7 389,6 @@ impl StateInner {
Request::TopicSet(args) => self.cmd_topic_set(ctx, args),
// Client session related requests.
- Request::Authenticate(args) => self.cmd_authenticate(ctx, args),
Request::CapLs(args) => self.cmd_cap_ls(ctx, args),
Request::CapList => self.cmd_cap_list(ctx),
Request::CapReq(args) => self.cmd_cap_req(ctx, args),
M src/state/v3.rs => src/state/v3.rs +0 -11
@@ 50,17 50,6 @@ impl super::StateInner {
}
}
-/// Handlers for commands related to SASL specifications.
-impl super::StateInner {
- pub fn cmd_authenticate(
- &mut self,
- _ctx: CommandContext<'_>,
- _payload: data::auth::Payload<'_>,
- ) -> Result {
- todo!()
- }
-}
-
/// Handlers for commands related to the setname specification.
impl super::StateInner {
pub fn cmd_setname(&mut self, ctx: CommandContext<'_>, realname: &str) -> Result {