forked from lavina/lavina
Compare commits
5 Commits
377d9c32d2
...
87d73af811
Author | SHA1 | Date |
---|---|---|
JustTestingV | 87d73af811 | |
Nikita Vilunov | 298245f3f5 | |
Nikita Vilunov | 3de7a131f0 | |
Nikita Vilunov | c662b64f11 | |
JustTestingV | 53f218c58f |
|
@ -0,0 +1,6 @@
|
||||||
|
*
|
||||||
|
!/src/
|
||||||
|
!/migrations/
|
||||||
|
!Cargo.lock
|
||||||
|
!Cargo.toml
|
||||||
|
!rust-toolchain
|
|
@ -1,2 +1,3 @@
|
||||||
/target
|
/target
|
||||||
/db.sqlite
|
/db.sqlite
|
||||||
|
.idea/
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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 }
|
||||||
|
|
|
@ -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"]
|
|
@ -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,
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -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() }
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue