diff options
author | Vika <vika@fireburn.ru> | 2024-08-20 00:35:30 +0300 |
---|---|---|
committer | Vika <vika@fireburn.ru> | 2024-08-20 01:46:13 +0300 |
commit | d6a8525274ccd96a5ce9540ea2ba1e463c84ff90 (patch) | |
tree | 9daa6fceda3f019629f99acb1b150882a5e151d4 /src/micropub | |
parent | a46e16258f83cc5939c568bba3a62ccc28114365 (diff) | |
download | kittybox-d6a8525274ccd96a5ce9540ea2ba1e463c84ff90.tar.zst |
kittybox-util: 0.1.0 -> 0.2.0
Micropub types are now more coherent and gathered in one place.
Diffstat (limited to 'src/micropub')
-rw-r--r-- | src/micropub/mod.rs | 87 |
1 files changed, 43 insertions, 44 deletions
diff --git a/src/micropub/mod.rs b/src/micropub/mod.rs index 63b81c5..65519e4 100644 --- a/src/micropub/mod.rs +++ b/src/micropub/mod.rs @@ -18,17 +18,7 @@ use tokio::sync::Mutex; use tokio::task::JoinSet; use tracing::{debug, error, info, warn}; use kittybox_indieauth::{Scope, TokenData}; -use kittybox_util::{MicropubError, ErrorType}; - -#[derive(Serialize, Deserialize, Debug, PartialEq)] -#[serde(rename_all = "kebab-case")] -enum QueryType { - Source, - Config, - Channel, - SyndicateTo, - Category -} +use kittybox_util::micropub::{Error as MicropubError, ErrorKind, QueryType}; #[derive(Serialize, Deserialize, Debug)] pub struct MicropubQuery { @@ -40,8 +30,8 @@ impl From<StorageError> for MicropubError { fn from(err: StorageError) -> Self { Self { error: match err.kind() { - crate::database::ErrorKind::NotFound => ErrorType::NotFound, - _ => ErrorType::InternalServerError, + crate::database::ErrorKind::NotFound => ErrorKind::NotFound, + _ => ErrorKind::InternalServerError, }, error_description: format!("Backend error: {}", err), } @@ -257,7 +247,7 @@ pub(crate) async fn _post<D: 'static + Storage>( // Security check! Do we have an OAuth2 scope to proceed? if !user.check_scope(&Scope::Create) { return Err(MicropubError { - error: ErrorType::InvalidScope, + error: ErrorKind::InvalidScope, error_description: "Not enough privileges - try acquiring the \"create\" scope." .to_owned(), }); @@ -272,7 +262,7 @@ pub(crate) async fn _post<D: 'static + Storage>( .any(|url| !url.as_str().unwrap().starts_with(user.me.as_str())) { return Err(MicropubError { - error: ErrorType::Forbidden, + error: ErrorKind::Forbidden, error_description: "You're posting to a website that's not yours.".to_owned(), }); } @@ -280,7 +270,7 @@ pub(crate) async fn _post<D: 'static + Storage>( // Security check #3! Are we overwriting an existing document? if db.post_exists(&uid).await? { return Err(MicropubError { - error: ErrorType::AlreadyExists, + error: ErrorKind::AlreadyExists, error_description: "UID clash was detected, operation aborted.".to_owned(), }); } @@ -399,7 +389,7 @@ async fn post_action<D: Storage, A: AuthBackend>( uri } else { return Err(MicropubError { - error: ErrorType::InvalidRequest, + error: ErrorKind::InvalidRequest, error_description: "Your URL doesn't parse properly.".to_owned(), }); }; @@ -414,7 +404,7 @@ async fn post_action<D: Storage, A: AuthBackend>( .unwrap() { return Err(MicropubError { - error: ErrorType::Forbidden, + error: ErrorKind::Forbidden, error_description: "Don't tamper with others' posts!".to_owned(), }); } @@ -423,7 +413,7 @@ async fn post_action<D: Storage, A: AuthBackend>( ActionType::Delete => { if !user.check_scope(&Scope::Delete) { return Err(MicropubError { - error: ErrorType::InvalidScope, + error: ErrorKind::InvalidScope, error_description: "You need a \"delete\" scope for this.".to_owned(), }); } @@ -433,7 +423,7 @@ async fn post_action<D: Storage, A: AuthBackend>( ActionType::Update => { if !user.check_scope(&Scope::Update) { return Err(MicropubError { - error: ErrorType::InvalidScope, + error: ErrorKind::InvalidScope, error_description: "You need an \"update\" scope for this.".to_owned(), }); } @@ -441,7 +431,7 @@ async fn post_action<D: Storage, A: AuthBackend>( db.update_post( &action.url, action.update.ok_or(MicropubError { - error: ErrorType::InvalidRequest, + error: ErrorKind::InvalidRequest, error_description: "Update request is not set.".to_owned(), })? ) @@ -483,7 +473,7 @@ async fn dispatch_body( // quick sanity check if !body.is_object() || !body["type"].is_array() { return Err(MicropubError { - error: ErrorType::InvalidRequest, + error: ErrorKind::InvalidRequest, error_description: "Invalid MF2-JSON detected: `.` should be an object, `.type` should be an array of MF2 types".to_owned() }); } @@ -491,7 +481,7 @@ async fn dispatch_body( Ok(PostBody::MF2(body)) } else { Err(MicropubError { - error: ErrorType::InvalidRequest, + error: ErrorKind::InvalidRequest, error_description: "Invalid JSON object passed.".to_owned(), }) } @@ -502,14 +492,14 @@ async fn dispatch_body( Ok(PostBody::MF2(form_to_mf2_json(body))) } else { Err(MicropubError { - error: ErrorType::InvalidRequest, + error: ErrorKind::InvalidRequest, error_description: "Invalid form-encoded data. Try h=entry&content=Hello!" .to_owned(), }) } } else { Err(MicropubError::new( - ErrorType::UnsupportedMediaType, + ErrorKind::UnsupportedMediaType, "This Content-Type is not recognized. Try application/json instead?", )) } @@ -553,7 +543,7 @@ pub(crate) async fn query<D: Storage, A: AuthBackend>( query } else { return MicropubError::new( - ErrorType::InvalidRequest, + ErrorKind::InvalidRequest, "Invalid query provided. Try ?q=config to see what you can do." ).into_response(); }; @@ -565,7 +555,7 @@ pub(crate) async fn query<D: Storage, A: AuthBackend>( != &host { return MicropubError::new( - ErrorType::NotAuthorized, + ErrorKind::NotAuthorized, "This website doesn't belong to you.", ) .into_response(); @@ -585,26 +575,31 @@ pub(crate) async fn query<D: Storage, A: AuthBackend>( Ok(chans) => chans, Err(err) => { return MicropubError::new( - ErrorType::InternalServerError, + ErrorKind::InternalServerError, &format!("Error fetching channels: {}", err), ) .into_response() } }; - axum::response::Json(json!({ - "q": [ + axum::response::Json(kittybox_util::micropub::Config { + q: vec![ QueryType::Source, QueryType::Config, QueryType::Channel, QueryType::SyndicateTo, QueryType::Category ], - "channels": channels, - "_kittybox_authority": user.me.as_str(), - "syndicate-to": [], - "media-endpoint": user.me.join("/.kittybox/media").unwrap().as_str() - })) + channels: Some(channels), + syndicate_to: None, + media_endpoint: Some(user.me.join("/.kittybox/media").unwrap()), + other: { + let mut map = std::collections::HashMap::new(); + map.insert("kittybox_authority".to_string(), serde_json::Value::String(user.me.to_string())); + + map + } + }) .into_response() } QueryType::Source => { @@ -614,13 +609,13 @@ pub(crate) async fn query<D: Storage, A: AuthBackend>( Ok(some) => match some { Some(post) => axum::response::Json(&post).into_response(), None => MicropubError::new( - ErrorType::NotFound, + ErrorKind::NotFound, "The specified MF2 object was not found in database.", ) .into_response(), }, Err(err) => MicropubError::new( - ErrorType::InternalServerError, + ErrorKind::InternalServerError, &format!("Backend error: {}", err), ) .into_response(), @@ -631,7 +626,7 @@ pub(crate) async fn query<D: Storage, A: AuthBackend>( // Using a pre-made query function can't be done because it does unneeded filtering // Don't implement for now, this is optional MicropubError::new( - ErrorType::InvalidRequest, + ErrorKind::InvalidRequest, "Querying for post list is not implemented yet.", ) .into_response() @@ -641,7 +636,7 @@ pub(crate) async fn query<D: Storage, A: AuthBackend>( QueryType::Channel => match db.get_channels(&user.me).await { Ok(chans) => axum::response::Json(json!({ "channels": chans })).into_response(), Err(err) => MicropubError::new( - ErrorType::InternalServerError, + ErrorKind::InternalServerError, &format!("Error fetching channels: {}", err), ) .into_response(), @@ -654,13 +649,17 @@ pub(crate) async fn query<D: Storage, A: AuthBackend>( Ok(categories) => categories, Err(err) => { return MicropubError::new( - ErrorType::InternalServerError, + ErrorKind::InternalServerError, &format!("Error fetching categories: {}", err) ).into_response() } }; axum::response::Json(json!({ "categories": categories })).into_response() - } + }, + QueryType::Unknown(q) => return MicropubError { + error: ErrorKind::InvalidRequest, + error_description: format!("Invalid query: {}", q) + }.into_response(), } } @@ -776,7 +775,7 @@ mod tests { .await .unwrap_err(); - assert_eq!(err.error, super::ErrorType::InvalidScope); + assert_eq!(err.error, super::ErrorKind::InvalidScope); let hashmap = db.mapping.read().await; assert!(hashmap.is_empty()); @@ -806,7 +805,7 @@ mod tests { .await .unwrap_err(); - assert_eq!(err.error, super::ErrorType::Forbidden); + assert_eq!(err.error, super::ErrorKind::Forbidden); let hashmap = db.mapping.read().await; assert!(hashmap.is_empty()); @@ -873,6 +872,6 @@ mod tests { .by_ref() .fold(Vec::new(), |mut a, i| { a.extend(i); a}); let json: MicropubError = serde_json::from_slice(&body as &[u8]).unwrap(); - assert_eq!(json.error, super::ErrorType::NotAuthorized); + assert_eq!(json.error, super::ErrorKind::NotAuthorized); } } |