Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 43 additions & 1 deletion up-subscription/src/handlers/subscribe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ impl RequestHandler for SubscriptionRequestHandler {
));
};

// [impl->dsn~usubscription-subscribe-invalid-topic~1]
helpers::validate_uri(topic).map_err(|e| {
ServiceInvocationError::InvalidArgument(format!("Invalid topic uri '{topic}': {e}"))
})?;

// Provisionally compute milliseconds to subscription expiry, from protobuf.google.Timestamp input in second granularity (we ignore the nanos).
// Likely to change in the future, when we get rid of the protobuf.google.Timestamp type and track in milliseconds throughought.
let expiry: Option<usubscription::ExpiryTimestamp> =
Expand Down Expand Up @@ -116,9 +121,13 @@ impl RequestHandler for SubscriptionRequestHandler {

#[cfg(test)]
mod tests {
use std::str::FromStr;

use super::*;
use test_case::test_case;
use tokio::sync::mpsc::{self};
use up_rust::core::usubscription::State;

use up_rust::{core::usubscription::State, UUri};

use crate::{helpers, tests::test_lib};

Expand Down Expand Up @@ -387,4 +396,37 @@ mod tests {

assert!(result.is_err_and(|e| matches!(e, ServiceInvocationError::InvalidArgument(_))));
}

// [utest->dsn~usubscription-subscribe-invalid-topic~1]
#[test_case("up:/0/0/0"; "Bad topic UUri")]
#[test_case("up://*/100000/1/8AC7"; "Wildcard authority in topic UUri")]
#[test_case("up://LOCAL/FFFF0000/1/8AC7"; "Wildcard entity id in topic UUri")]
#[test_case("up://LOCAL/100000/1/FFFF"; "Wildcard resource id in topic UUri")]
#[tokio::test]
async fn test_invalid_topic_uri(topic: &str) {
helpers::init_once();

// create request and other required object(s)
let topic = UUri::from_str(topic).expect("Test parameter UUri failed to parse");
let subscribe_request = test_lib::helpers::subscription_request(topic, None);
let request_payload = UPayload::try_from_protobuf(subscribe_request.clone()).unwrap();
let message_attributes = UAttributes {
source: Some(test_lib::helpers::subscriber_uri1()).into(),
..Default::default()
};
let (subscription_sender, _) = mpsc::channel::<SubscriptionEvent>(1);

// create handler and perform tested operation
let request_handler = SubscriptionRequestHandler::new(subscription_sender);

let result = request_handler
.handle_request(
up_rust::core::usubscription::RESOURCE_ID_SUBSCRIBE,
&message_attributes,
Some(request_payload),
)
.await;

assert!(result.is_err_and(|err| matches!(err, ServiceInvocationError::InvalidArgument(_))));
}
}
54 changes: 53 additions & 1 deletion up-subscription/src/handlers/unregister_for_notifications.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,27 @@ impl RequestHandler for UnregisterNotificationsRequestHandler {
request_payload: Option<UPayload>,
) -> Result<Option<UPayload>, ServiceInvocationError> {
// [impl->dsn~usubscription-unregister-notifications-protobuf~1]
let (_subscription_request, source) = helpers::extract_inputs::<NotificationsRequest>(
let (notification_request, source) = helpers::extract_inputs::<NotificationsRequest>(
RESOURCE_ID_UNREGISTER_FOR_NOTIFICATIONS,
resource_id,
&request_payload,
message_attributes,
)?;

let Some(topic) = notification_request.topic.as_ref() else {
return Err(ServiceInvocationError::InvalidArgument(
"No topic defined in request".to_string(),
));
};

// [impl->dsn~usubscription-unregister-notifications-invalid-topic~1]
helpers::validate_uri(topic).map_err(|e| {
ServiceInvocationError::InvalidArgument(format!("Invalid topic uri '{topic}': {e}"))
})?;

// TODO: can/should we actually use the topic alongside the subscriber, for notification-removal?
// UGH - this entire notifications storage thing doesn't work, can only store one topic per subscriber atm. Needs fixed...

// Interact with notification manager backend
let se = NotificationEvent::RemoveNotifyee {
subscriber: source.clone(),
Expand All @@ -78,8 +92,12 @@ impl RequestHandler for UnregisterNotificationsRequestHandler {
#[cfg(test)]
mod tests {
use super::*;
use std::str::FromStr;
use test_case::test_case;
use tokio::sync::mpsc::{self};

use up_rust::UUri;

use crate::{helpers, tests::test_lib};

// [utest->dsn~usubscription-unregister-notifications-protobuf~1]
Expand Down Expand Up @@ -236,4 +254,38 @@ mod tests {

assert!(result.is_err_and(|err| matches!(err, ServiceInvocationError::InvalidArgument(_))));
}

// [utest->dsn~usubscription-unregister-notifications-invalid-topic~1]
#[test_case("up:/0/0/0"; "Bad topic UUri")]
#[test_case("up://*/100000/1/8AC7"; "Wildcard authority in topic UUri")]
#[test_case("up://LOCAL/FFFF0000/1/8AC7"; "Wildcard entity id in topic UUri")]
#[test_case("up://LOCAL/100000/1/FFFF"; "Wildcard resource id in topic UUri")]
#[tokio::test]
async fn test_invalid_topic_uri(topic: &str) {
helpers::init_once();

// create request and other required object(s)
let topic = UUri::from_str(topic).expect("Test parameter UUri failed to parse");
// create request and other required object(s)
let subscribe_request = test_lib::helpers::subscription_request(topic, None);
let request_payload = UPayload::try_from_protobuf(subscribe_request.clone()).unwrap();
let message_attributes = UAttributes {
source: Some(test_lib::helpers::subscriber_uri1()).into(),
..Default::default()
};
let (subscription_sender, _) = mpsc::channel::<NotificationEvent>(1);

// create handler and perform tested operation
let request_handler = UnregisterNotificationsRequestHandler::new(subscription_sender);

let result = request_handler
.handle_request(
up_rust::core::usubscription::RESOURCE_ID_UNREGISTER_FOR_NOTIFICATIONS,
&message_attributes,
Some(request_payload),
)
.await;

assert!(result.is_err_and(|err| matches!(err, ServiceInvocationError::InvalidArgument(_))));
}
}
43 changes: 42 additions & 1 deletion up-subscription/src/handlers/unsubscribe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ impl RequestHandler for UnubscribeRequestHandler {
));
};

// [impl->dsn~usubscription-unsubscribe-invalid-topic~1]
helpers::validate_uri(topic).map_err(|e| {
ServiceInvocationError::InvalidArgument(format!("Invalid topic uri '{topic}': {e}"))
})?;

let (respond_to, receive_from) = oneshot::channel::<SubscriptionStatus>();
let se = SubscriptionEvent::RemoveSubscription {
subscriber: source.clone(),
Expand Down Expand Up @@ -91,8 +96,11 @@ impl RequestHandler for UnubscribeRequestHandler {
#[cfg(test)]
mod tests {
use super::*;
use std::str::FromStr;
use test_case::test_case;
use tokio::sync::mpsc::{self};
use up_rust::core::usubscription::State;

use up_rust::{core::usubscription::State, UUri};

use crate::{helpers, tests::test_lib};

Expand Down Expand Up @@ -258,4 +266,37 @@ mod tests {

assert!(result.is_err_and(|err| matches!(err, ServiceInvocationError::InvalidArgument(_))));
}

// [utest->dsn~usubscription-unsubscribe-invalid-topic~1]
#[test_case("up:/0/0/0"; "Bad topic UUri")]
#[test_case("up://*/100000/1/8AC7"; "Wildcard authority in topic UUri")]
#[test_case("up://LOCAL/FFFF0000/1/8AC7"; "Wildcard entity id in topic UUri")]
#[test_case("up://LOCAL/100000/1/FFFF"; "Wildcard resource id in topic UUri")]
#[tokio::test]
async fn test_invalid_topic_uri(topic: &str) {
helpers::init_once();

// create request and other required object(s)
let topic = UUri::from_str(topic).expect("Test parameter UUri failed to parse");
let subscribe_request = test_lib::helpers::subscription_request(topic, None);
let request_payload = UPayload::try_from_protobuf(subscribe_request.clone()).unwrap();
let message_attributes = UAttributes {
source: Some(test_lib::helpers::subscriber_uri1()).into(),
..Default::default()
};
let (subscription_sender, _) = mpsc::channel::<SubscriptionEvent>(1);

// create handler and perform tested operation
let request_handler = UnubscribeRequestHandler::new(subscription_sender);

let result = request_handler
.handle_request(
up_rust::core::usubscription::RESOURCE_ID_UNSUBSCRIBE,
&message_attributes,
Some(request_payload),
)
.await;

assert!(result.is_err_and(|err| matches!(err, ServiceInvocationError::InvalidArgument(_))));
}
}