Compare commits

..

No commits in common. "7613055ddefa9de66243d177518f27c7178dd5a4" and "77d175ccd9b976db6271ebe42f774758e9139675" have entirely different histories.

8 changed files with 290 additions and 355 deletions

441
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -180,16 +180,14 @@ async fn handle_registration<'a>(
writer.flush().await?; writer.flush().await?;
} }
CapabilitySubcommand::End => { CapabilitySubcommand::End => {
let Some((ref username, ref realname)) = future_username else { let Some((username, realname)) = future_username else {
todo!(); todo!()
}; };
let Some(nickname) = future_nickname.clone() else { let Some(nickname) = future_nickname.clone() else {
todo!(); todo!()
}; };
let username = username.clone();
let realname = realname.clone();
let candidate_user = RegisteredUser { let candidate_user = RegisteredUser {
nickname: nickname.clone(), nickname,
username, username,
realname, realname,
}; };
@ -199,15 +197,7 @@ async fn handle_registration<'a>(
break Ok(candidate_user); break Ok(candidate_user);
} else { } else {
let Some(candidate_password) = pass else { let Some(candidate_password) = pass else {
sasl_fail_message( todo!();
config.server_name.clone(),
nickname.clone(),
"User credentials was not provided".into(),
)
.write_async(writer)
.await?;
writer.flush().await?;
continue;
}; };
auth_user(storage, &*candidate_user.nickname, &*candidate_password).await?; auth_user(storage, &*candidate_user.nickname, &*candidate_password).await?;
break Ok(candidate_user); break Ok(candidate_user);
@ -219,20 +209,12 @@ async fn handle_registration<'a>(
future_nickname = Some(nickname); future_nickname = Some(nickname);
} else if let Some((username, realname)) = future_username.clone() { } else if let Some((username, realname)) = future_username.clone() {
let candidate_user = RegisteredUser { let candidate_user = RegisteredUser {
nickname: nickname.clone(), nickname,
username, username,
realname, realname,
}; };
let Some(candidate_password) = pass else { let Some(candidate_password) = pass else {
sasl_fail_message( todo!();
config.server_name.clone(),
nickname.clone(),
"User credentials was not provided".into(),
)
.write_async(writer)
.await?;
writer.flush().await?;
continue;
}; };
auth_user(storage, &*candidate_user.nickname, &*candidate_password).await?; auth_user(storage, &*candidate_user.nickname, &*candidate_password).await?;
break Ok(candidate_user); break Ok(candidate_user);
@ -245,20 +227,12 @@ async fn handle_registration<'a>(
future_username = Some((username, realname)); future_username = Some((username, realname));
} else if let Some(nickname) = future_nickname.clone() { } else if let Some(nickname) = future_nickname.clone() {
let candidate_user = RegisteredUser { let candidate_user = RegisteredUser {
nickname: nickname.clone(), nickname,
username, username,
realname, realname,
}; };
let Some(candidate_password) = pass else { let Some(candidate_password) = pass else {
sasl_fail_message( todo!();
config.server_name.clone(),
nickname.clone(),
"User credentials was not provided".into(),
)
.write_async(writer)
.await?;
writer.flush().await?;
continue;
}; };
auth_user(storage, &*candidate_user.nickname, &*candidate_password).await?; auth_user(storage, &*candidate_user.nickname, &*candidate_password).await?;
break Ok(candidate_user); break Ok(candidate_user);
@ -281,59 +255,38 @@ async fn handle_registration<'a>(
.await?; .await?;
writer.flush().await?; writer.flush().await?;
} else { } else {
if let Some(nickname) = future_nickname.clone() { // TODO respond with 904
sasl_fail_message( todo!();
config.server_name.clone(),
nickname.clone(),
"Unsupported mechanism".into(),
)
.write_async(writer)
.await?;
writer.flush().await?;
} else {
break Err(anyhow::Error::msg("Wrong authentication sequence"));
}
} }
} else { } else {
let body = AuthBody::from_str(body.as_bytes())?; let body = AuthBody::from_str(body.as_bytes())?;
if let Err(e) = auth_user(storage, &body.login, &body.password).await { auth_user(storage, &body.login, &body.password).await?;
tracing::warn!("Authentication failed: {:?}", e); let login: Str = body.login.into();
if let Some(nickname) = future_nickname.clone() { validated_user = Some(login.clone());
sasl_fail_message(config.server_name.clone(), nickname.clone(), "Bad credentials".into()) ServerMessage {
.write_async(writer) tags: vec![],
.await?; sender: Some(config.server_name.clone().into()),
writer.flush().await?; body: ServerMessageBody::N900LoggedIn {
} else { nick: login.clone(),
} address: login.clone(),
} else { account: login.clone(),
let login: Str = body.login.into(); message: format!("You are now logged in as {}", login).into(),
validated_user = Some(login.clone()); },
ServerMessage {
tags: vec![],
sender: Some(config.server_name.clone().into()),
body: ServerMessageBody::N900LoggedIn {
nick: login.clone(),
address: login.clone(),
account: login.clone(),
message: format!("You are now logged in as {}", login).into(),
},
}
.write_async(writer)
.await?;
ServerMessage {
tags: vec![],
sender: Some(config.server_name.clone().into()),
body: ServerMessageBody::N903SaslSuccess {
nick: login.clone(),
message: "SASL authentication successful".into(),
},
}
.write_async(writer)
.await?;
writer.flush().await?;
} }
.write_async(writer)
.await?;
ServerMessage {
tags: vec![],
sender: Some(config.server_name.clone().into()),
body: ServerMessageBody::N903SaslSuccess {
nick: login.clone(),
message: "SASL authentication successful".into(),
},
}
.write_async(writer)
.await?;
writer.flush().await?;
} }
// TODO handle abortion of authentication // TODO handle abortion of authentication
} }
_ => {} _ => {}
@ -344,14 +297,6 @@ async fn handle_registration<'a>(
Ok(user) Ok(user)
} }
fn sasl_fail_message(sender: Str, nick: Str, text: Str) -> ServerMessage {
ServerMessage {
tags: vec![],
sender: Some(sender),
body: ServerMessageBody::N904SaslFail { nick, text },
}
}
async fn auth_user(storage: &mut Storage, login: &str, plain_password: &str) -> Result<()> { async fn auth_user(storage: &mut Storage, login: &str, plain_password: &str) -> Result<()> {
let stored_user = storage.retrieve_user_by_name(login).await?; let stored_user = storage.retrieve_user_by_name(login).await?;

View File

@ -218,51 +218,3 @@ async fn scenario_cap_short_negotiation() -> Result<()> {
server.server.terminate().await?; server.server.terminate().await?;
Ok(()) Ok(())
} }
#[tokio::test]
async fn scenario_cap_sasl_fail() -> Result<()> {
let mut server = TestServer::start().await?;
// test scenario
server.storage.create_user("tester").await?;
server.storage.set_password("tester", "password").await?;
let mut stream = TcpStream::connect(server.server.addr).await?;
let mut s = TestScope::new(&mut stream);
s.send("CAP LS 302").await?;
s.send("NICK tester").await?;
s.send("USER UserName 0 * :Real Name").await?;
s.expect(":testserver CAP * LS :sasl=PLAIN").await?;
s.send("CAP REQ :sasl").await?;
s.expect(":testserver CAP tester ACK :sasl").await?;
s.send("AUTHENTICATE SHA256").await?;
s.expect(":testserver 904 tester :Unsupported mechanism").await?;
s.send("AUTHENTICATE PLAIN").await?;
s.expect(":testserver AUTHENTICATE +").await?;
s.send("AUTHENTICATE dGVzdGVyAHRlc3RlcgBwYXNzd29yZDE=").await?;
s.expect(":testserver 904 tester :Bad credentials").await?;
s.send("AUTHENTICATE dGVzdGVyAHRlc3RlcgBwYXNzd29yZA==").await?; // base64-encoded 'tester\x00tester\x00password'
s.expect(":testserver 900 tester tester tester :You are now logged in as tester").await?;
s.expect(":testserver 903 tester :SASL authentication successful").await?;
s.send("CAP END").await?;
s.expect(":testserver 001 tester :Welcome to Kek Server").await?;
s.expect(":testserver 002 tester :Welcome to Kek Server").await?;
s.expect(":testserver 003 tester :Welcome to Kek Server").await?;
s.expect(":testserver 004 tester testserver kek-0.1.alpha.3 r CFILPQbcefgijklmnopqrstvz").await?;
s.expect(":testserver 005 tester CHANTYPES=# :are supported by this server").await?;
s.expect_nothing().await?;
s.send("QUIT :Leaving").await?;
s.expect(":testserver ERROR :Leaving the server").await?;
s.expect_eof().await?;
stream.shutdown().await?;
// wrap up
server.server.terminate().await?;
Ok(())
}

View File

@ -83,7 +83,7 @@ pub async fn launch(
let key = match read_one(&mut SyncBufReader::new(File::open(config.key)?))? { let key = match read_one(&mut SyncBufReader::new(File::open(config.key)?))? {
Some(PemItem::ECKey(k) | PemItem::PKCS8Key(k) | PemItem::RSAKey(k)) => PrivateKey(k), Some(PemItem::ECKey(k) | PemItem::PKCS8Key(k) | PemItem::RSAKey(k)) => PrivateKey(k),
_ => return Err(fail("no keys in file")), _ => panic!("no keys in file"),
}; };
let loaded_config = Arc::new(LoadedConfig { let loaded_config = Arc::new(LoadedConfig {

View File

@ -30,10 +30,6 @@ fn token(input: &str) -> IResult<&str, &str> {
take_while(|i| i != '\n' && i != '\r')(input) take_while(|i| i != '\n' && i != '\r')(input)
} }
fn params(input: &str) -> IResult<&str, &str> {
take_while(|i| i != '\n' && i != '\r' && i != ':')(input)
}
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
pub enum Chan { pub enum Chan {
/// #<name> — network-global channel, available from any server in the network. /// #<name> — network-global channel, available from any server in the network.

View File

@ -1,5 +1,3 @@
use std::sync::Arc;
use nonempty::NonEmpty; use nonempty::NonEmpty;
use tokio::io::AsyncWrite; use tokio::io::AsyncWrite;
use tokio::io::AsyncWriteExt; use tokio::io::AsyncWriteExt;
@ -154,10 +152,6 @@ pub enum ServerMessageBody {
N903SaslSuccess { N903SaslSuccess {
nick: Str, nick: Str,
message: Str, message: Str,
},
N904SaslFail {
nick: Str,
text: Str,
} }
} }
@ -375,13 +369,6 @@ 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::N904SaslFail { nick, text } => {
writer.write_all(b"904").await?;
writer.write_all(b" ").await?;
writer.write_all(nick.as_bytes()).await?;
writer.write_all(b" :").await?;
writer.write_all(text.as_bytes()).await?;
}
} }
Ok(()) Ok(())
} }
@ -404,7 +391,7 @@ fn server_message_body(input: &str) -> IResult<&str, ServerMessageBody> {
server_message_body_notice, server_message_body_notice,
server_message_body_ping, server_message_body_ping,
server_message_body_pong, server_message_body_pong,
server_message_body_cap server_message_body_cap,
))(input) ))(input)
} }

View File

@ -28,10 +28,10 @@ impl ClientStreamStart {
if let Event::Start(e) = incoming { if let Event::Start(e) = incoming {
let (ns, local) = reader.resolve_element(e.name()); let (ns, local) = reader.resolve_element(e.name());
if ns != ResolveResult::Bound(Namespace(XMLNS.as_bytes())) { if ns != ResolveResult::Bound(Namespace(XMLNS.as_bytes())) {
return Err(anyhow!("Invalid namespace for stream element")); return Err(panic!());
} }
if local.into_inner() != b"stream" { if local.into_inner() != b"stream" {
return Err(anyhow!("Invalid local name for stream element")); return Err(panic!());
} }
let mut to = None; let mut to = None;
let mut lang = None; let mut lang = None;
@ -64,7 +64,7 @@ impl ClientStreamStart {
version: version.unwrap(), version: version.unwrap(),
}) })
} else { } else {
Err(anyhow!("Incoming message does not belong XML Start Event")) Err(panic!())
} }
} }
} }

View File

@ -1 +1 @@
nightly-2024-02-08 nightly-2023-12-07