forked from lavina/lavina
1
0
Fork 0

Compare commits

...

5 Commits

Author SHA1 Message Date
JustTestingV 87d73af811 [irc] used nonempty prefixed nicks in 353 reply (#9)
Reviewed-on: lavina/lavina#9
Co-authored-by: JustTestingV <JustTestingV@gmail.com>
Co-committed-by: JustTestingV <JustTestingV@gmail.com>
2023-09-15 16:33:25 +00:00
Nikita Vilunov 298245f3f5 bump version 2023-09-15 17:12:12 +02:00
Nikita Vilunov 3de7a131f0 add dockerfile 2023-09-15 17:11:29 +02:00
Nikita Vilunov c662b64f11 disable tls support in sqlx, remove webpki-roots 2023-09-14 18:55:03 +02:00
JustTestingV 53f218c58f [irc] send 502 if not sender tries to change mode for other users (#4)
Reviewed-on: lavina/lavina#4
Co-authored-by: JustTestingV <JustTestingV@gmail.com>
Co-committed-by: JustTestingV <JustTestingV@gmail.com>
2023-09-06 18:43:07 +00:00
13 changed files with 111 additions and 47 deletions

6
.dockerignore Normal file
View File

@ -0,0 +1,6 @@
*
!/src/
!/migrations/
!Cargo.lock
!Cargo.toml
!rust-toolchain

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
/target /target
/db.sqlite /db.sqlite
.idea/

35
Cargo.lock generated
View File

@ -750,7 +750,7 @@ dependencies = [
[[package]] [[package]]
name = "lavina" name = "lavina"
version = "0.1.0" version = "0.0.1-dev"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"assert_matches", "assert_matches",
@ -761,6 +761,7 @@ dependencies = [
"hyper 1.0.0-rc.3", "hyper 1.0.0-rc.3",
"lazy_static", "lazy_static",
"nom", "nom",
"nonempty",
"prometheus", "prometheus",
"quick-xml", "quick-xml",
"regex", "regex",
@ -887,6 +888,12 @@ dependencies = [
"minimal-lexical", "minimal-lexical",
] ]
[[package]]
name = "nonempty"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aeaf4ad7403de93e699c191202f017118df734d3850b01e13a3a8b2e6953d3c9"
[[package]] [[package]]
name = "nu-ansi-term" name = "nu-ansi-term"
version = "0.46.0" version = "0.46.0"
@ -1603,19 +1610,14 @@ dependencies = [
"once_cell", "once_cell",
"paste", "paste",
"percent-encoding", "percent-encoding",
"rustls",
"rustls-pemfile",
"serde", "serde",
"serde_json", "serde_json",
"sha2", "sha2",
"smallvec", "smallvec",
"sqlformat", "sqlformat",
"thiserror", "thiserror",
"tokio",
"tokio-stream",
"tracing", "tracing",
"url", "url",
"webpki-roots",
] ]
[[package]] [[package]]
@ -1652,7 +1654,6 @@ dependencies = [
"sqlx-sqlite", "sqlx-sqlite",
"syn 1.0.109", "syn 1.0.109",
"tempfile", "tempfile",
"tokio",
"url", "url",
] ]
@ -1895,17 +1896,6 @@ dependencies = [
"tokio", "tokio",
] ]
[[package]]
name = "tokio-stream"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842"
dependencies = [
"futures-core",
"pin-project-lite",
"tokio",
]
[[package]] [[package]]
name = "tokio-util" name = "tokio-util"
version = "0.7.8" version = "0.7.8"
@ -2208,15 +2198,6 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
[[package]]
name = "webpki-roots"
version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b291546d5d9d1eab74f069c77749f2cb8504a12caa20f0f2de93ddbf6f411888"
dependencies = [
"rustls-webpki",
]
[[package]] [[package]]
name = "whoami" name = "whoami"
version = "1.4.1" version = "1.4.1"

View File

@ -1,6 +1,6 @@
[package] [package]
name = "lavina" name = "lavina"
version = "0.1.0" version = "0.0.1-dev"
edition = "2021" edition = "2021"
publish = false publish = false
@ -19,12 +19,13 @@ prometheus = { version = "0.13.3", default-features = false }
regex = "1.7.1" regex = "1.7.1"
lazy_static = "1.4.0" lazy_static = "1.4.0"
nom = "7.1.3" nom = "7.1.3"
nonempty = "0.8.1"
tokio-rustls = "0.24.1" tokio-rustls = "0.24.1"
rustls-pemfile = "1.0.2" rustls-pemfile = "1.0.2"
quick-xml = { version = "0.30.0", features = ["async-tokio"] } quick-xml = { version = "0.30.0", features = ["async-tokio"] }
derive_more = "0.99.17" derive_more = "0.99.17"
uuid = { version = "1.3.0", features = ["v4"] } uuid = { version = "1.3.0", features = ["v4"] }
sqlx = { version = "0.7.0-alpha.2", features = ["sqlite", "runtime-tokio-rustls", "migrate"] } sqlx = { version = "0.7.0-alpha.2", features = ["sqlite", "migrate"] }
[dev-dependencies] [dev-dependencies]
assert_matches = "1.5.0" assert_matches = "1.5.0"

View File

@ -17,14 +17,18 @@ allow = [
"MIT", "MIT",
"Apache-2.0", "Apache-2.0",
"ISC", "ISC",
"MPL-2.0",
"BSD-3-Clause", "BSD-3-Clause",
] ]
exceptions = [ exceptions = [
{ allow = ["Unicode-DFS-2016"], name = "unicode-ident" }, { allow = ["Unicode-DFS-2016"], name = "unicode-ident" },
{ allow = ["OpenSSL"], name = "ring" }, { allow = ["OpenSSL"], name = "ring" },
] ]
deny = ["GPL-2.0", "GPL-3.0", "AGPL-3.0"] deny = [
"GPL-2.0",
"GPL-3.0",
"AGPL-3.0",
"MPL-2.0" # it is used by webpki-roots; we do not hardcode root certs in the binary
]
copyleft = "deny" copyleft = "deny"
confidence-threshold = 0.93 confidence-threshold = 0.93
private = { ignore = true } private = { ignore = true }

11
dist/alpine3.18.Dockerfile vendored Normal file
View File

@ -0,0 +1,11 @@
FROM rust:1.72.0-alpine3.18@sha256:2f5592c561cef195c9fa4462633a674458dc375fc0ba4b80e7efe4c3c8e68403 as bld
RUN apk add --no-cache musl-dev
COPY . .
RUN cargo build --release
FROM alpine:3.18@sha256:7144f7bab3d4c2648d7e59409f15ec52a18006a128c733fcff20d3a4a54ba44a
COPY --from=bld target/release/lavina /usr/bin/lavina
VOLUME ["/etc/lavina/", "/var/lib/lavina/"]
ENTRYPOINT ["lavina"]

View File

@ -302,7 +302,7 @@ impl Player {
player_id, player_id,
connections: AnonTable::new(), connections: AnonTable::new(),
my_rooms: HashMap::new(), my_rooms: HashMap::new(),
banned_from: HashSet::from([RoomId::from("empty").unwrap()]), banned_from: HashSet::from([RoomId::from("Empty").unwrap()]),
rx, rx,
handle, handle,
rooms, rooms,

View File

@ -32,7 +32,10 @@ struct ServerConfig {
} }
fn load_config() -> Result<ServerConfig> { fn load_config() -> Result<ServerConfig> {
let raw_config = Figment::new().merge(Toml::file("config.toml")); // TODO get config path as a cmd line arg
let raw_config = Figment::new()
.merge(Toml::file("config.toml"))
.merge(Toml::file("/etc/lavina/config.toml"));
let config: ServerConfig = raw_config.extract()?; let config: ServerConfig = raw_config.extract()?;
Ok(config) Ok(config)
} }

View File

@ -2,6 +2,8 @@ use std::collections::HashMap;
use std::net::SocketAddr; use std::net::SocketAddr;
use futures_util::future::join_all; use futures_util::future::join_all;
use nonempty::nonempty;
use nonempty::NonEmpty;
use prometheus::{IntCounter, IntGauge, Registry as MetricsRegistry}; use prometheus::{IntCounter, IntGauge, Registry as MetricsRegistry};
use serde::Deserialize; use serde::Deserialize;
use tokio::io::{AsyncBufReadExt, AsyncWrite, AsyncWriteExt, BufReader, BufWriter}; use tokio::io::{AsyncBufReadExt, AsyncWrite, AsyncWriteExt, BufReader, BufWriter};
@ -16,6 +18,7 @@ use crate::prelude::*;
use crate::protos::irc::client::{client_message, ClientMessage}; use crate::protos::irc::client::{client_message, ClientMessage};
use crate::protos::irc::server::{AwayStatus, ServerMessage, ServerMessageBody}; use crate::protos::irc::server::{AwayStatus, ServerMessage, ServerMessageBody};
use crate::protos::irc::{Chan, Recipient}; use crate::protos::irc::{Chan, Recipient};
use crate::protos::irc::user::PrefixedNick;
use crate::util::Terminator; use crate::util::Terminator;
#[cfg(test)] #[cfg(test)]
@ -528,7 +531,17 @@ async fn handle_incoming_message(
.await?; .await?;
writer.flush().await?; writer.flush().await?;
} else { } else {
// TODO send 502 (not 401) if the user is not the sender ServerMessage {
tags: vec![],
sender: Some(config.server_name.clone()),
body: ServerMessageBody::N502UsersDontMatch {
client: user.nickname.clone(),
message: "Cant change mode for other users".into(),
},
}
.write_async(writer)
.await?;
writer.flush().await?;
} }
} }
Recipient::Chan(_) => { Recipient::Chan(_) => {
@ -656,22 +669,16 @@ async fn produce_on_join_cmd_messages(
} }
.write_async(writer) .write_async(writer)
.await?; .await?;
let mut members: String = if let Some(head) = room_info.members.first() { let prefixed_members: Vec<PrefixedNick> = room_info.members.iter().map(|member| PrefixedNick::from_player_id(member.clone())).collect();
head.as_inner().clone() let non_empty_members: NonEmpty<PrefixedNick> = NonEmpty::from_vec(prefixed_members).unwrap_or(nonempty![PrefixedNick::from_str(user.nickname.clone())]);
} else {
user.nickname.clone()
}.as_ref().into();
for i in &room_info.members[1..] {
members.push(' ');
members.push_str(i.as_inner());
}
ServerMessage { ServerMessage {
tags: vec![], tags: vec![],
sender: Some(config.server_name.clone()), sender: Some(config.server_name.clone()),
body: ServerMessageBody::N353NamesReply { body: ServerMessageBody::N353NamesReply {
client: user.nickname.clone(), client: user.nickname.clone(),
chan: chan.clone(), chan: chan.clone(),
members: members.into(), members: non_empty_members.into(),
}, },
} }
.write_async(writer) .write_async(writer)

View File

@ -1,6 +1,7 @@
//! Client-to-Server IRC protocol. //! Client-to-Server IRC protocol.
pub mod client; pub mod client;
pub mod server; pub mod server;
pub mod user;
use std::io::Result; use std::io::Result;
use crate::prelude::Str; use crate::prelude::Str;

View File

@ -1,7 +1,9 @@
use nonempty::NonEmpty;
use tokio::io::AsyncWrite; use tokio::io::AsyncWrite;
use tokio::io::AsyncWriteExt; use tokio::io::AsyncWriteExt;
use super::*; use super::*;
use crate::protos::irc::user::PrefixedNick;
/// Server-to-client message. /// Server-to-client message.
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
@ -121,7 +123,7 @@ pub enum ServerMessageBody {
N353NamesReply { N353NamesReply {
client: Str, client: Str,
chan: Chan, chan: Chan,
members: Str, // TODO make this a non-empty list with prefixes members: NonEmpty<PrefixedNick>,
}, },
N366NamesReplyEnd { N366NamesReplyEnd {
client: Str, client: Str,
@ -132,6 +134,10 @@ pub enum ServerMessageBody {
chan: Chan, chan: Chan,
message: Str, message: Str,
}, },
N502UsersDontMatch {
client: Str,
message: Str,
},
} }
impl ServerMessageBody { impl ServerMessageBody {
@ -280,7 +286,11 @@ impl ServerMessageBody {
writer.write_all(b" = ").await?; writer.write_all(b" = ").await?;
chan.write_async(writer).await?; chan.write_async(writer).await?;
writer.write_all(b" :").await?; writer.write_all(b" :").await?;
writer.write_all(members.as_bytes()).await?; for member in members {
writer.write_all(member.prefix.to_string().as_bytes()).await?;
writer.write_all(member.nick.as_bytes()).await?;
writer.write_all(b" ").await?;
}
} }
ServerMessageBody::N366NamesReplyEnd { client, chan } => { ServerMessageBody::N366NamesReplyEnd { client, chan } => {
writer.write_all(b"366 ").await?; writer.write_all(b"366 ").await?;
@ -301,6 +311,13 @@ impl ServerMessageBody {
writer.write_all(b" :").await?; writer.write_all(b" :").await?;
writer.write_all(message.as_bytes()).await?; writer.write_all(message.as_bytes()).await?;
} }
ServerMessageBody::N502UsersDontMatch { client, message } => {
writer.write_all(b"502 ").await?;
writer.write_all(client.as_bytes()).await?;
writer.write_all(b" ").await?;
writer.write_all(b" :").await?;
writer.write_all(message.as_bytes()).await?;
}
} }
Ok(()) Ok(())
} }

32
src/protos/irc/user.rs Normal file
View File

@ -0,0 +1,32 @@
use super::*;
use std::fmt;
use crate::core::player::PlayerId;
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Prefix {
Empty,
}
impl fmt::Display for Prefix {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Prefix::Empty => write!(f, ""),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PrefixedNick {
pub prefix: Prefix,
pub nick: Str,
}
impl PrefixedNick {
pub fn from_str(nick: Str) -> PrefixedNick {
PrefixedNick { prefix: Prefix::Empty, nick }
}
pub fn from_player_id(id: PlayerId) -> PrefixedNick {
PrefixedNick { prefix: Prefix::Empty, nick: id.into_inner() }
}
}

View File

@ -21,7 +21,7 @@ impl<V> AnonTable<V> {
pub fn insert(&mut self, value: V) -> Key { pub fn insert(&mut self, value: V) -> Key {
let id = self.next; let id = self.next;
self.next += 1; self.next += 1;
self.inner.insert(id, value); // should be always empty self.inner.insert(id, value); // should be always Empty
Key(id) Key(id)
} }