🏡 index : ~doyle/titanirc.git

author Jordan Doyle <jordan@doyle.la> 2023-02-04 14:19:24.0 +00:00:00
committer Jordan Doyle <jordan@doyle.la> 2023-02-04 14:19:24.0 +00:00:00
commit
cdea0f994227f584828c9a081d4f54a05221d92c [patch]
tree
01139ec2c45d91c77fb3667e277c50c2534e91a2
parent
a3859aad43815e1529d5d100ad0ee2432b8f73e5
download
cdea0f994227f584828c9a081d4f54a05221d92c.tar.gz

Implement responses for more error cases



Diff

 src/channel.rs             | 34 ++++++++++++++++++++++++++++------
 src/channel/permissions.rs |  4 ++--
 src/channel/response.rs    | 36 ++++++++++++++++++++++++++++++++++++
 src/client.rs              | 15 +++++++++++----
 src/connection.rs          |  6 +++---
 5 files changed, 80 insertions(+), 15 deletions(-)

diff --git a/src/channel.rs b/src/channel.rs
index 9daa630..15100d9 100644
--- a/src/channel.rs
+++ b/src/channel.rs
@@ -9,7 +9,7 @@ use actix::{
};
use chrono::{DateTime, Utc};
use futures::future::Either;
use irc_proto::{Command, Message, Mode};
use irc_proto::{Command, Message, Mode, Response};
use tracing::{debug, error, info, instrument, warn, Span};

use crate::{
@@ -17,6 +17,7 @@ use crate::{
        permissions::Permission,
        response::{
            ChannelInviteResult, ChannelJoinRejectionReason, ChannelNamesList, ChannelTopic,
            MissingPrivileges,
        },
    },
    client::Client,
@@ -137,8 +138,22 @@ impl Handler<ChannelMessage> for Channel {
        };

        if !self.get_user_permissions(sender.user_id).can_chatter() {
            // TODO
            error!("User cannot send message to channel");
            msg.client.do_send(Broadcast {
                message: Message {
                    tags: None,
                    prefix: None,
                    command: Command::Response(
                        Response::ERR_CANNOTSENDTOCHAN,
                        vec![
                            sender.to_nick().to_string(),
                            self.name.to_string(),
                            "Cannot send to channel".to_string(),
                        ],
                    ),
                },
                span: Span::current(),
            });

            return;
        }

@@ -421,8 +436,12 @@ impl Handler<ChannelUpdateTopic> for Channel {
            .get_user_permissions(client_info.user_id)
            .can_set_topic()
        {
            // TODO
            error!("User cannot set channel topic");
            error!("User attempted to set channel topic without privileges");
            msg.client.do_send(Broadcast {
                message: MissingPrivileges(client_info.to_nick(), self.name.to_string())
                    .into_message(),
                span: Span::current(),
            });
            return;
        }

@@ -455,8 +474,11 @@ impl Handler<ChannelKickUser> for Channel {
        };

        if !self.get_user_permissions(kicker.user_id).can_kick() {
            // TODO
            error!("Kicker can not kick people from the channel");
            msg.client.do_send(Broadcast {
                message: MissingPrivileges(kicker.to_nick(), self.name.to_string()).into_message(),
                span: Span::current(),
            });
            return;
        }

diff --git a/src/channel/permissions.rs b/src/channel/permissions.rs
index af63c85..6351713 100644
--- a/src/channel/permissions.rs
+++ b/src/channel/permissions.rs
@@ -90,8 +90,8 @@ impl Permission {

    /// Returns true, if the user is allowed to kick people from the channel.
    #[must_use]
    pub fn can_kick(self) -> bool {
        self == Self::Operator
    pub const fn can_kick(self) -> bool {
        (self as i16) >= (Self::HalfOperator as i16)
    }

    /// Returns true, if the user is allowed to set the given permission on another
diff --git a/src/channel/response.rs b/src/channel/response.rs
index 2bec2e8..68bc75c 100644
--- a/src/channel/response.rs
+++ b/src/channel/response.rs
@@ -183,3 +183,39 @@ impl ChannelInviteResult {
pub enum ChannelJoinRejectionReason {
    Banned,
}

impl ChannelJoinRejectionReason {
    #[must_use]
    pub fn into_message(self) -> Message {
        match self {
            Self::Banned => Message {
                tags: None,
                prefix: Some(Prefix::ServerName(SERVER_NAME.to_string())),
                command: Command::Response(
                    Response::ERR_BANNEDFROMCHAN,
                    vec!["Cannot join channel (+b)".to_string()],
                ),
            },
        }
    }
}

pub struct MissingPrivileges(pub Prefix, pub String);

impl MissingPrivileges {
    #[must_use]
    pub fn into_message(self) -> Message {
        Message {
            tags: None,
            prefix: None,
            command: Command::Response(
                Response::ERR_CHANOPRIVSNEEDED,
                vec![
                    self.0.to_string(),
                    self.1,
                    "You're not channel operator".to_string(),
                ],
            ),
        }
    }
}
diff --git a/src/client.rs b/src/client.rs
index 6c2636d..3d38d16 100644
--- a/src/client.rs
+++ b/src/client.rs
@@ -15,7 +15,10 @@ use tracing::{debug, error, info, info_span, instrument, warn, Instrument, Span}

use crate::{
    channel::Channel,
    connection::{sasl::SaslAlreadyAuthenticated, Capability, InitiatedConnection, MessageSink},
    connection::{
        sasl::SaslAlreadyAuthenticated, Capability, InitiatedConnection, MessageSink,
        NickNotOwnedByUser,
    },
    messages::{
        Broadcast, ChannelFetchTopic, ChannelInvite, ChannelJoin, ChannelKickUser, ChannelList,
        ChannelMemberList, ChannelMessage, ChannelPart, ChannelSetMode, ChannelUpdateTopic,
@@ -263,7 +266,8 @@ impl Handler<JoinChannelRequest> for Client {
                let handle = match handle {
                    Ok(v) => v,
                    Err(error) => {
                        error!(?error, "Failed to join user to channel");
                        error!(?error, "User failed to join channel");
                        this.writer.write(error.into_message());
                        continue;
                    }
                };
@@ -346,7 +350,10 @@ impl Handler<UserNickChangeInternal> for Client {
            .into_actor(self)
            .map(|res, this, ctx| {
                if !res.unwrap() {
                    // TODO: send notification to user to say the nick isn't available
                    ctx.notify(Broadcast {
                        message: NickNotOwnedByUser(msg.new_nick).into_message(),
                        span: Span::current(),
                    });
                    return;
                }

@@ -667,7 +674,7 @@ impl StreamHandler<Result<irc_proto::Message, ProtocolError>> for Client {

                self.writer.write(Message {
                    tags: None,
                    prefix: Some(Prefix::ServerName(SERVER_NAME.to_string())),
                    prefix: None,
                    command: Command::Response(
                        Response::RPL_TIME,
                        vec![
diff --git a/src/connection.rs b/src/connection.rs
index ad1bf46..84fd8ab 100644
--- a/src/connection.rs
+++ b/src/connection.rs
@@ -226,7 +226,7 @@ pub async fn negotiate_client_connection(
    Ok(Some(initiated))
}

pub struct NickNotOwnedByUser(String);
pub struct NickNotOwnedByUser(pub String);

impl NickNotOwnedByUser {
    #[must_use]
@@ -235,8 +235,8 @@ impl NickNotOwnedByUser {
            tags: None,
            prefix: None,
            command: Command::Response(
                Response::ERR_NICKLOCKED,
                vec![self.0, "You must use a nick assigned to you".to_string()],
                Response::ERR_NICKNAMEINUSE,
                vec![self.0, "Nickname is already in use".to_string()],
            ),
        }
    }