diff --git a/crates/lib/actix_artcraft/src/anonymous_visitor_tracking/avt_cookie_error.rs b/crates/lib/actix_artcraft/src/anonymous_visitor_tracking/avt_cookie_error.rs new file mode 100644 index 0000000000..13f88ebaed --- /dev/null +++ b/crates/lib/actix_artcraft/src/anonymous_visitor_tracking/avt_cookie_error.rs @@ -0,0 +1,34 @@ +use std::error::Error; +use std::fmt::{Display, Formatter}; + +use jwt_signer::jwt_signer_error::JwtSignerError; + +#[derive(Debug)] +pub enum AvtCookieError { + /// AVT cookie payload is missing a required field. + MissingField(&'static str), + + /// Generic decode error (e.g. invalid integer for cookie_version). + DecodeError(String), + + /// Error encoding, decoding, or constructing the JWT signer. + JwtSigner(JwtSignerError), +} + +impl Display for AvtCookieError { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Self::MissingField(field) => write!(f, "AVT cookie missing field: {}", field), + Self::DecodeError(reason) => write!(f, "AVT cookie decode error: {}", reason), + Self::JwtSigner(e) => write!(f, "JWT signer error: {}", e), + } + } +} + +impl Error for AvtCookieError {} + +impl From for AvtCookieError { + fn from(err: JwtSignerError) -> Self { + Self::JwtSigner(err) + } +} diff --git a/crates/service/web/storyteller_web/src/http_server/cookies/anonymous_visitor_tracking/avt_cookie_manager.rs b/crates/lib/actix_artcraft/src/anonymous_visitor_tracking/avt_cookie_manager.rs similarity index 84% rename from crates/service/web/storyteller_web/src/http_server/cookies/anonymous_visitor_tracking/avt_cookie_manager.rs rename to crates/lib/actix_artcraft/src/anonymous_visitor_tracking/avt_cookie_manager.rs index 9023bb46a9..4053368391 100644 --- a/crates/service/web/storyteller_web/src/http_server/cookies/anonymous_visitor_tracking/avt_cookie_manager.rs +++ b/crates/lib/actix_artcraft/src/anonymous_visitor_tracking/avt_cookie_manager.rs @@ -1,13 +1,11 @@ use actix_web::cookie::time::OffsetDateTime; use actix_web::cookie::{Cookie, SameSite}; use actix_web::HttpRequest; -use anyhow::anyhow; use log::warn; -use crate::error::internal_error::InternalError; -use crate::http_server::cookies::anonymous_visitor_tracking::avt_cookie_payload::AvtCookiePayload; +use crate::anonymous_visitor_tracking::avt_cookie_error::AvtCookieError; +use crate::anonymous_visitor_tracking::avt_cookie_payload::AvtCookiePayload; use jwt_signer::jwt_signer::JwtSigner; -use errors::AnyhowResult; use tokens::tokens::anonymous_visitor_tracking::AnonymousVisitorTrackingToken; const VISITOR_COOKIE_NAME : &str = "visitor"; @@ -23,19 +21,19 @@ pub struct AvtCookieManager { impl AvtCookieManager { - pub fn new(cookie_domain: &str, hmac_secret: &str) -> AnyhowResult { + pub fn new(cookie_domain: &str, hmac_secret: &str) -> Result { Ok(Self { cookie_domain: cookie_domain.to_string(), jwt_signer: JwtSigner::new(hmac_secret)?, }) } - pub fn make_new_cookie(&self) -> AnyhowResult { + pub fn make_new_cookie(&self) -> Result { let token = AnonymousVisitorTrackingToken::generate(); self.make_new_cookie_with_apriori_token(&token) } - pub fn make_new_cookie_with_apriori_token(&self, token: &AnonymousVisitorTrackingToken) -> AnyhowResult { + pub fn make_new_cookie_with_apriori_token(&self, token: &AnonymousVisitorTrackingToken) -> Result { let payload = AvtCookiePayload::from_token(token.clone()); let claims = payload.to_map(); let jwt_string = self.jwt_signer.claims_to_jwt(&claims)?; @@ -68,14 +66,14 @@ impl AvtCookieManager { cookie } - pub fn decode_cookie_payload(&self, visitor_cookie: &Cookie) -> AnyhowResult { + pub fn decode_cookie_payload(&self, visitor_cookie: &Cookie) -> Result { let cookie_contents = visitor_cookie.value().to_string(); let claims = self.jwt_signer.jwt_to_claims(&cookie_contents)?; let payload = AvtCookiePayload::from_map(claims)?; Ok(payload) } - pub fn decode_cookie_payload_from_request(&self, request: &HttpRequest) -> Result, InternalError> { + pub fn decode_cookie_payload_from_request(&self, request: &HttpRequest) -> Result, AvtCookieError> { let cookie = match request.cookie(VISITOR_COOKIE_NAME) { None => return Ok(None), Some(cookie) => cookie, @@ -84,7 +82,7 @@ impl AvtCookieManager { match self.decode_cookie_payload(&cookie) { Err(e) => { warn!("Visitor cookie decode error: {:?}", e); - Err(InternalError::VisitorCookieError(e.to_string())) + Err(e) }, Ok(payload) => Ok(Some(payload)), } diff --git a/crates/service/web/storyteller_web/src/http_server/cookies/anonymous_visitor_tracking/avt_cookie_payload.rs b/crates/lib/actix_artcraft/src/anonymous_visitor_tracking/avt_cookie_payload.rs similarity index 86% rename from crates/service/web/storyteller_web/src/http_server/cookies/anonymous_visitor_tracking/avt_cookie_payload.rs rename to crates/lib/actix_artcraft/src/anonymous_visitor_tracking/avt_cookie_payload.rs index 0ed768f511..aea918adae 100644 --- a/crates/service/web/storyteller_web/src/http_server/cookies/anonymous_visitor_tracking/avt_cookie_payload.rs +++ b/crates/lib/actix_artcraft/src/anonymous_visitor_tracking/avt_cookie_payload.rs @@ -1,7 +1,7 @@ use std::collections::BTreeMap; use std::str::FromStr; -use crate::error::internal_error::InternalError; +use crate::anonymous_visitor_tracking::avt_cookie_error::AvtCookieError; use tokens::tokens::anonymous_visitor_tracking::AnonymousVisitorTrackingToken; /** @@ -43,18 +43,18 @@ impl AvtCookiePayload { } } - pub fn from_map(map: BTreeMap) -> Result { + pub fn from_map(map: BTreeMap) -> Result { let avt_token = map.get("avt_token") - .ok_or_else(|| InternalError::VisitorCookieMissingField("avt_token"))?; + .ok_or(AvtCookieError::MissingField("avt_token"))?; let cookie_version = map .get("cookie_version") - .ok_or_else(|| InternalError::VisitorCookieMissingField("cookie_version"))?; + .ok_or(AvtCookieError::MissingField("cookie_version"))?; let avt_token = AnonymousVisitorTrackingToken::new_from_str(avt_token); let cookie_version = u32::from_str(cookie_version) - .map_err(|e| InternalError::VisitorCookieError( + .map_err(|e| AvtCookieError::DecodeError( format!("invalid integer for cookie_version: {:?}, version: {}", e, cookie_version)))?; Ok(AvtCookiePayload { @@ -75,7 +75,7 @@ impl AvtCookiePayload { mod tests { use tokens::tokens::anonymous_visitor_tracking::AnonymousVisitorTrackingToken; - use crate::http_server::cookies::anonymous_visitor_tracking::avt_cookie_payload::AvtCookiePayload; + use crate::anonymous_visitor_tracking::avt_cookie_payload::AvtCookiePayload; #[test] fn test_new() { diff --git a/crates/lib/actix_artcraft/src/anonymous_visitor_tracking/mod.rs b/crates/lib/actix_artcraft/src/anonymous_visitor_tracking/mod.rs new file mode 100644 index 0000000000..70c65ba639 --- /dev/null +++ b/crates/lib/actix_artcraft/src/anonymous_visitor_tracking/mod.rs @@ -0,0 +1,3 @@ +pub mod avt_cookie_error; +pub mod avt_cookie_manager; +pub mod avt_cookie_payload; diff --git a/crates/lib/actix_artcraft/src/lib.rs b/crates/lib/actix_artcraft/src/lib.rs index 9e41e41f35..5576a65a6a 100644 --- a/crates/lib/actix_artcraft/src/lib.rs +++ b/crates/lib/actix_artcraft/src/lib.rs @@ -17,5 +17,6 @@ #![allow(dead_code)] #![allow(non_snake_case)] +pub mod anonymous_visitor_tracking; pub mod requests; pub mod sessions; \ No newline at end of file diff --git a/crates/service/web/storyteller_web/src/http_server/common_responses/advanced_common_web_error.rs b/crates/service/web/storyteller_web/src/http_server/common_responses/advanced_common_web_error.rs index 2c7f06e09b..07186997a8 100644 --- a/crates/service/web/storyteller_web/src/http_server/common_responses/advanced_common_web_error.rs +++ b/crates/service/web/storyteller_web/src/http_server/common_responses/advanced_common_web_error.rs @@ -204,6 +204,13 @@ impl From for AdvancedCommonWebError { } } +impl From for AdvancedCommonWebError { + fn from(err: actix_artcraft::anonymous_visitor_tracking::avt_cookie_error::AvtCookieError) -> Self { + // AVT cookie errors are non-critical: log and treat as a server error. + Self::from_error(err) + } +} + impl From for AdvancedCommonWebError { fn from(value: SessionCheckerError) -> Self { match value { diff --git a/crates/service/web/storyteller_web/src/http_server/cookies/anonymous_visitor_tracking/mod.rs b/crates/service/web/storyteller_web/src/http_server/cookies/anonymous_visitor_tracking/mod.rs deleted file mode 100644 index 8192e11c00..0000000000 --- a/crates/service/web/storyteller_web/src/http_server/cookies/anonymous_visitor_tracking/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod avt_cookie_manager; -pub mod avt_cookie_payload; \ No newline at end of file diff --git a/crates/service/web/storyteller_web/src/http_server/cookies/mod.rs b/crates/service/web/storyteller_web/src/http_server/cookies/mod.rs deleted file mode 100644 index 610601f9e8..0000000000 --- a/crates/service/web/storyteller_web/src/http_server/cookies/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod anonymous_visitor_tracking; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/app_state/get_app_state_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/app_state/get_app_state_handler.rs index ec4f5ea416..a213562309 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/app_state/get_app_state_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/app_state/get_app_state_handler.rs @@ -1,4 +1,4 @@ -use crate::http_server::cookies::anonymous_visitor_tracking::avt_cookie_manager::AvtCookieManager; +use actix_artcraft::anonymous_visitor_tracking::avt_cookie_manager::AvtCookieManager; use crate::http_server::endpoints::app_state::components::get_permissions::{get_permissions, AppStatePermissions}; use crate::http_server::endpoints::app_state::components::get_premium_info::{get_premium_info, AppStatePremiumInfo}; use crate::http_server::endpoints::app_state::components::get_server_info::{get_server_info, AppStateServerInfo}; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/users/session_info_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/users/session_info_handler.rs index 27186681ee..d57c6f061d 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/users/session_info_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/users/session_info_handler.rs @@ -12,7 +12,7 @@ use enums::by_table::users::user_feature_flag::UserFeatureFlag; use crate::http_server::common_responses::advanced_common_web_error::AdvancedCommonWebError; use crate::http_server::common_responses::user_details_lite_builder::UserDetailsLightBuilder; -use crate::http_server::cookies::anonymous_visitor_tracking::avt_cookie_manager::AvtCookieManager; +use actix_artcraft::anonymous_visitor_tracking::avt_cookie_manager::AvtCookieManager; use crate::http_server::session::lookup::user_session_feature_flags::UserSessionFeatureFlags; use crate::http_server::session::session_checker::SessionChecker; diff --git a/crates/service/web/storyteller_web/src/http_server/mod.rs b/crates/service/web/storyteller_web/src/http_server/mod.rs index b3bef446c3..82a70137ab 100644 --- a/crates/service/web/storyteller_web/src/http_server/mod.rs +++ b/crates/service/web/storyteller_web/src/http_server/mod.rs @@ -1,7 +1,6 @@ pub mod common_requests; pub mod common_responses; pub mod endpoint_helpers; -pub mod cookies; pub mod deprecated_endpoints; pub mod endpoints; pub mod middleware; diff --git a/crates/service/web/storyteller_web/src/main.rs b/crates/service/web/storyteller_web/src/main.rs index 3195f655ec..033cddeee2 100644 --- a/crates/service/web/storyteller_web/src/main.rs +++ b/crates/service/web/storyteller_web/src/main.rs @@ -71,7 +71,7 @@ use crate::billing::stripe_internal_user_lookup_impl::StripeInternalUserLookupIm use crate::configs::app_startup::redis_rate_limiters::configure_redis_rate_limiters; use crate::configs::connect_to_database::connect_to_database; use crate::configs::static_api_tokens::StaticApiTokenSet; -use crate::http_server::cookies::anonymous_visitor_tracking::avt_cookie_manager::AvtCookieManager; +use actix_artcraft::anonymous_visitor_tracking::avt_cookie_manager::AvtCookieManager; use crate::http_server::middleware::error_alerting_middleware::error_alerting_middleware::ErrorAlertingMiddleware; use crate::http_server::middleware::pushback_filter_middleware::PushbackFilter; use crate::http_server::routes::add_routes::add_routes; diff --git a/crates/service/web/storyteller_web/src/state/server_state.rs b/crates/service/web/storyteller_web/src/state/server_state.rs index 0bf8e52377..2813c44f32 100644 --- a/crates/service/web/storyteller_web/src/state/server_state.rs +++ b/crates/service/web/storyteller_web/src/state/server_state.rs @@ -25,7 +25,7 @@ use url_config::third_party_url_redirector::ThirdPartyUrlRedirector; use crate::configs::app_startup::username_set::UsernameSet; use crate::configs::static_api_tokens::StaticApiTokenSet; -use crate::http_server::cookies::anonymous_visitor_tracking::avt_cookie_manager::AvtCookieManager; +use actix_artcraft::anonymous_visitor_tracking::avt_cookie_manager::AvtCookieManager; use crate::http_server::deprecated_endpoints::categories::tts::list_fully_computed_assigned_tts_categories::list_fully_computed_assigned_tts_categories::ModelTokensByCategoryToken; use crate::http_server::deprecated_endpoints::leaderboard::get_leaderboard::LeaderboardInfo; use crate::http_server::endpoints::media_files::list::list_featured_media_files_handler::ListFeaturedMediaFilesQueryParams;