diff options
-rw-r--r-- | src/database/mod.rs | 9 | ||||
-rw-r--r-- | src/database/postgres/mod.rs | 67 | ||||
-rw-r--r-- | src/frontend/mod.rs | 2 | ||||
-rw-r--r-- | src/frontend/onboarding.rs | 7 | ||||
-rw-r--r-- | src/indieauth/mod.rs | 4 | ||||
-rw-r--r-- | src/lib.rs | 2 | ||||
-rw-r--r-- | src/login.rs | 5 | ||||
-rw-r--r-- | src/media/storage/file.rs | 8 | ||||
-rw-r--r-- | src/micropub/mod.rs | 27 | ||||
-rw-r--r-- | src/webmentions/check.rs | 4 | ||||
-rw-r--r-- | src/webmentions/check/rcdom.rs | 2 | ||||
-rw-r--r-- | templates/build.rs | 8 | ||||
-rw-r--r-- | util/src/lib.rs | 8 | ||||
-rw-r--r-- | util/src/micropub.rs | 3 |
14 files changed, 38 insertions, 118 deletions
diff --git a/src/database/mod.rs b/src/database/mod.rs index 7b50196..3b13cb3 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -55,7 +55,9 @@ pub mod settings { /// implementations, as it wouldn't make sense to add new settings /// that aren't used by Kittybox itself. pub trait Setting<'de>: private::Sealed + std::fmt::Debug + Default + Clone + serde::Serialize + serde::de::DeserializeOwned + /*From<Settings> +*/ Send + Sync { + /// The data that the setting carries. type Data: std::fmt::Debug + Send + Sync; + /// The string ID for the setting, usable as an identifier in the database. const ID: &'static str; /// Unwrap the setting type, returning owned data contained within. @@ -89,11 +91,6 @@ pub mod settings { Self(data) } } - impl SiteName { - fn from_str(data: &str) -> Self { - Self(data.to_owned()) - } - } /// Participation status in the IndieWeb Webring: https://πΈπ.ws/dashboard #[derive(Debug, Default, serde::Deserialize, serde::Serialize, Clone, Copy, PartialEq, Eq)] @@ -600,7 +597,7 @@ mod tests { .await .unwrap(); - for (i, post) in posts.iter().rev().enumerate() { + for post in posts.iter().rev() { backend .put_post(post, &"https://fireburn.ru/".parse().unwrap()) .await diff --git a/src/database/postgres/mod.rs b/src/database/postgres/mod.rs index 1780672..b2d4339 100644 --- a/src/database/postgres/mod.rs +++ b/src/database/postgres/mod.rs @@ -247,11 +247,6 @@ WHERE #[tracing::instrument(skip(self))] async fn get_channels(&self, user: &url::Url) -> Result<Vec<MicropubChannel>> { - /*sqlx::query_as::<_, MicropubChannel>("SELECT name, uid FROM kittybox.channels WHERE owner = $1") - .bind(user) - .fetch_all(&self.db) - .await - .map_err(|err| err.into())*/ sqlx::query_as::<_, MicropubChannel>(r#"SELECT mf2 #>> '{properties,name,0}' as name, uid FROM kittybox.mf2_json WHERE '["h-feed"]'::jsonb @> mf2['type'] AND owner = $1"#) .bind(user.authority()) .fetch_all(&self.db) @@ -263,67 +258,11 @@ WHERE async fn read_feed_with_limit( &self, url: &'_ str, - after: Option<&str>, - limit: usize, - // BUG: this doesn't seem to be used?! - user: Option<&url::Url>, + _after: Option<&str>, + _limit: usize, + _user: Option<&url::Url>, ) -> Result<Option<serde_json::Value>> { unimplemented!("read_feed_with_limit is insecure and deprecated"); - let mut feed = match sqlx::query_as::<_, (serde_json::Value,)>(" -SELECT jsonb_set( - mf2, - '{properties,author,0}', - (SELECT mf2 FROM kittybox.mf2_json - WHERE uid = mf2 #>> '{properties,author,0}') -) FROM kittybox.mf2_json WHERE uid = $1 OR mf2['properties']['url'] ? $1 -") - .bind(url) - .fetch_optional(&self.db) - .await? - .map(|v| v.0) - { - Some(feed) => feed, - None => return Ok(None) - }; - - let posts: Vec<String> = { - let mut posts_iter = feed["children"] - .as_array() - .cloned() - .unwrap_or_default() - .into_iter() - .map(|s| s.as_str().unwrap().to_string()); - if let Some(after) = after { - for s in posts_iter.by_ref() { - if &s == after { - break; - } - } - }; - - posts_iter.take(limit).collect::<Vec<_>>() - }; - feed["children"] = serde_json::Value::Array( - sqlx::query_as::<_, (serde_json::Value,)>(" -SELECT jsonb_set( - mf2, - '{properties,author,0}', - (SELECT mf2 FROM kittybox.mf2_json - WHERE uid = mf2 #>> '{properties,author,0}') -) FROM kittybox.mf2_json -WHERE uid = ANY($1) -ORDER BY mf2 #>> '{properties,published,0}' DESC -") - .bind(&posts[..]) - .fetch_all(&self.db) - .await? - .into_iter() - .map(|v| v.0) - .collect::<Vec<_>>() - ); - - Ok(Some(feed)) - } #[tracing::instrument(skip(self))] diff --git a/src/frontend/mod.rs b/src/frontend/mod.rs index 81a03ed..4120b55 100644 --- a/src/frontend/mod.rs +++ b/src/frontend/mod.rs @@ -192,7 +192,7 @@ async fn get_post_from_database<S: Storage>( .await { Ok(result) => match result { - Some((post, cursor)) => match filter_post(post, user.as_deref()) { + Some((post, cursor)) => match filter_post(post, user) { Some(post) => Ok((post, cursor)), None => { // TODO: Authentication diff --git a/src/frontend/onboarding.rs b/src/frontend/onboarding.rs index 9f3f36b..be1669f 100644 --- a/src/frontend/onboarding.rs +++ b/src/frontend/onboarding.rs @@ -75,13 +75,6 @@ async fn onboard<D: Storage + 'static>( } tracing::debug!("Setting settings..."); - let user_domain = format!( - "{}{}", - user.me.host_str().unwrap(), - user.me.port() - .map(|port| format!(":{}", port)) - .unwrap_or_default() - ); db.set_setting::<settings::SiteName>(&user.me, data.blog_name.to_owned()) .await .map_err(FrontendError::from)?; diff --git a/src/indieauth/mod.rs b/src/indieauth/mod.rs index 036a379..322a0e2 100644 --- a/src/indieauth/mod.rs +++ b/src/indieauth/mod.rs @@ -3,7 +3,7 @@ use microformats::types::Class; use tracing::error; use serde::Deserialize; use axum::{ - extract::{Form, FromRef, Host, Json, Query, State}, http::StatusCode, response::{Html, IntoResponse, Response}, Extension + extract::{Form, FromRef, Host, Json, Query, State}, http::StatusCode, response::{Html, IntoResponse, Response} }; #[cfg_attr(not(feature = "webauthn"), allow(unused_imports))] use axum_extra::extract::cookie::{CookieJar, Cookie}; @@ -154,7 +154,7 @@ async fn authorization_endpoint_get<A: AuthBackend, D: Storage + 'static>( let text = response.text().await.unwrap(); tracing::debug!("Received {} bytes in response", text.len()); match microformats::from_html(&text, url) { - Ok(mut mf2) => { + Ok(mf2) => { if let Some(relation) = mf2.rels.items.get(&request.redirect_uri) { if !relation.rels.iter().any(|i| i == "redirect_uri") { return (StatusCode::BAD_REQUEST, diff --git a/src/lib.rs b/src/lib.rs index f1a563e..596ffc0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,7 @@ use std::sync::Arc; -use axum::{extract::{FromRef, FromRequestParts}, response::IntoResponse}; +use axum::extract::{FromRef, FromRequestParts}; use axum_extra::extract::{cookie::Key, SignedCookieJar}; use database::{FileStorage, PostgresStorage, Storage}; use indieauth::backend::{AuthBackend, FileBackend as FileAuthBackend}; diff --git a/src/login.rs b/src/login.rs index f1e2c81..bfa84b3 100644 --- a/src/login.rs +++ b/src/login.rs @@ -1,8 +1,8 @@ use std::borrow::Cow; use futures_util::FutureExt; -use axum::{extract::{FromRef, Host, OriginalUri, Query, State}, http::HeaderValue, response::IntoResponse, Form}; -use axum_extra::{extract::{cookie::{self, Cookie}, CookieJar, SignedCookieJar}, headers::Header, TypedHeader}; +use axum::{extract::{FromRef, Host, Query, State}, http::HeaderValue, response::IntoResponse, Form}; +use axum_extra::extract::{cookie::{self, Cookie}, SignedCookieJar}; use hyper::{header::{CACHE_CONTROL, LOCATION}, StatusCode}; use kittybox_frontend_renderer::{Template, LoginPage, LogoutPage}; use kittybox_indieauth::{AuthorizationResponse, Error, GrantType, PKCEVerifier, Scope, Scopes}; @@ -94,6 +94,7 @@ async fn post( }; // XXX: Blocked on https://github.com/hyperium/headers/pull/113 + // use axum_extra::{headers::Header, TypedHeader}; // let links = response // .headers() // .iter() diff --git a/src/media/storage/file.rs b/src/media/storage/file.rs index 7250a6b..b9ab541 100644 --- a/src/media/storage/file.rs +++ b/src/media/storage/file.rs @@ -4,7 +4,7 @@ use std::{path::PathBuf, fmt::Debug}; use tokio::fs::OpenOptions; use tokio::io::{BufReader, BufWriter, AsyncWriteExt, AsyncSeekExt}; use futures::{StreamExt, TryStreamExt}; -use std::ops::{Bound, RangeBounds, Neg}; +use std::ops::{Bound, Neg}; use std::pin::Pin; use sha2::Digest; use futures::FutureExt; @@ -73,7 +73,7 @@ impl MediaStore for FileStore { let chunk = chunk.clone(); let tempfile = &mut tempfile; async move { - tempfile.write_all(&*chunk).await + tempfile.write_all(&chunk).await } }, { @@ -102,7 +102,7 @@ impl MediaStore for FileStore { tempfile.into_inner().sync_all().await?; let hash = hasher.finalize(); - debug!("Pending upload hash: {}", hex::encode(&hash)); + debug!("Pending upload hash: {}", hex::encode(hash)); let filename = format!( "{}/{}/{}/{}/{}", hex::encode([hash[0]]), @@ -117,7 +117,7 @@ impl MediaStore for FileStore { let metapath = self.base.join(domain_str.as_str()).join(&metafilename); let metatemppath = self.base.join(domain_str.as_str()).join(metafilename + ".tmp"); metadata.length = std::num::NonZeroUsize::new(length); - metadata.etag = Some(hex::encode(&hash)); + metadata.etag = Some(hex::encode(hash)); debug!("File path: {}, metadata: {}", filepath.display(), metapath.display()); { let parent = filepath.parent().unwrap(); diff --git a/src/micropub/mod.rs b/src/micropub/mod.rs index 65519e4..08150d2 100644 --- a/src/micropub/mod.rs +++ b/src/micropub/mod.rs @@ -67,7 +67,7 @@ fn populate_reply_context( if item.is_object() && (i != &item) { if let Some(props) = item["properties"].as_object_mut() { // Fixup the item: if it lacks a URL, add one. - if !props.get("url").and_then(serde_json::Value::as_array).map(|a| a.len() > 0).unwrap_or(false) { + if !props.get("url").and_then(serde_json::Value::as_array).map(|a| !a.is_empty()).unwrap_or(false) { props.insert("url".to_owned(), json!([i.as_str()])); } } @@ -191,9 +191,9 @@ async fn background_processing<D: 'static + Storage>( tokio_stream::iter( post_contexts .into_iter() - .filter(|(url, ctx)| ctx.webmention.is_some()), + .filter(|(_url, ctx)| ctx.webmention.is_some()), ) - .for_each_concurrent(2, |(url, ctx)| async move { + .for_each_concurrent(2, |(_url, ctx)| async move { let mut map = std::collections::HashMap::new(); map.insert("source", uid); map.insert("target", ctx.url.as_str()); @@ -274,13 +274,6 @@ pub(crate) async fn _post<D: 'static + Storage>( error_description: "UID clash was detected, operation aborted.".to_owned(), }); } - let user_domain = format!( - "{}{}", - user.me.host_str().unwrap(), - user.me.port() - .map(|port| format!(":{}", port)) - .unwrap_or_default() - ); // Save the post tracing::debug!("Saving post to database..."); db.put_post(&mf2, &user.me).await?; @@ -303,7 +296,7 @@ pub(crate) async fn _post<D: 'static + Storage>( .unwrap() .to_string(); let food_channel = user.me.join(util::FOOD_CHANNEL_PATH).unwrap().to_string(); - let default_channels = vec![default_channel, vcards_channel, food_channel]; + let default_channels = [default_channel, vcards_channel, food_channel]; for chan in &mut channels { debug!("Adding post {} to channel {}", uid, chan); @@ -562,13 +555,7 @@ pub(crate) async fn query<D: Storage, A: AuthBackend>( } // TODO: consider replacing by `user.me.authority()`? - let user_domain = format!( - "{}{}", - user.me.host_str().unwrap(), - user.me.port() - .map(|port| format!(":{}", port)) - .unwrap_or_default() - ); + let user_domain = user.me.authority(); match query.q { QueryType::Config => { let channels: Vec<MicropubChannel> = match db.get_channels(&user.me).await { @@ -645,7 +632,7 @@ pub(crate) async fn query<D: Storage, A: AuthBackend>( axum::response::Json(json!({ "syndicate-to": [] })).into_response() }, QueryType::Category => { - let categories = match db.categories(&user_domain).await { + let categories = match db.categories(user_domain).await { Ok(categories) => categories, Err(err) => { return MicropubError::new( @@ -844,7 +831,7 @@ mod tests { #[tokio::test] async fn test_query_foreign_url() { - let mut res = super::query( + let res = super::query( State(crate::database::MemoryStorage::default()), Some(axum::extract::Query(super::MicropubQuery::source( "https://aaronparecki.com/feeds/main", diff --git a/src/webmentions/check.rs b/src/webmentions/check.rs index 178c008..683cc6b 100644 --- a/src/webmentions/check.rs +++ b/src/webmentions/check.rs @@ -38,7 +38,7 @@ pub fn check_mention(document: impl AsRef<str> + std::fmt::Debug, base_url: &url if let PropertyValue::Url(url) = val { if url == link { tracing::debug!("URL matches! Webmention is valid"); - return Ok(Some((interaction_type, serde_json::to_value(&*item).unwrap()))) + return Ok(Some((interaction_type, serde_json::to_value(item).unwrap()))) } } } @@ -101,7 +101,7 @@ pub fn check_mention(document: impl AsRef<str> + std::fmt::Debug, base_url: &url } } if is_mention { - return Ok(Some((MentionType::Mention, serde_json::to_value(&*item).unwrap()))); + return Ok(Some((MentionType::Mention, serde_json::to_value(item).unwrap()))); } } } diff --git a/src/webmentions/check/rcdom.rs b/src/webmentions/check/rcdom.rs index 549610f..08408a2 100644 --- a/src/webmentions/check/rcdom.rs +++ b/src/webmentions/check/rcdom.rs @@ -7,7 +7,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(missing_docs)] +#![allow(missing_docs, dead_code)] //! A simple reference-counted DOM. //! diff --git a/templates/build.rs b/templates/build.rs index bdf99fa..ac77059 100644 --- a/templates/build.rs +++ b/templates/build.rs @@ -22,7 +22,7 @@ fn main() -> Result<(), std::io::Error> { println!("cargo:rerun-if-changed=assets/"); let assets_path = std::path::Path::new("assets"); - let mut assets = WalkDir::new(&assets_path) + let mut assets = WalkDir::new(assets_path) .into_iter(); while let Some(Ok(entry)) = assets.next() { if entry.file_type().is_dir() { @@ -64,19 +64,19 @@ fn main() -> Result<(), std::io::Error> { .write(true) .open(&gzip_path)?; - let mut in_file = std::fs::File::open(&normal_path)?; + let mut in_file = std::fs::File::open(normal_path)?; let mut encoder = Encoder::new(&mut out_file)?; std::io::copy(&mut in_file, &mut encoder)?; encoder.finish().into_result()?; } - let normal_len: f64 = std::fs::metadata(&normal_path).unwrap().len() as f64; + let normal_len: f64 = std::fs::metadata(normal_path).unwrap().len() as f64; let gzipped_len: f64 = std::fs::metadata(&gzip_path).unwrap().len() as f64; let ratio = gzipped_len / normal_len; eprintln!("Ratio: {}", ratio); if ratio <= 0.9 { - std::fs::remove_file(&normal_path)? + std::fs::remove_file(normal_path)? } else { println!( "cargo:warning={} compression ratio is {} (> 0.9), leaving as is", diff --git a/util/src/lib.rs b/util/src/lib.rs index f92ee1b..cb5f666 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -22,13 +22,13 @@ pub enum MentionType { /// Common data-types useful in creating smart authentication systems. pub mod auth { + /// Various types of credentials Kittybox can use. #[derive(PartialEq, Eq, Hash, Clone, Copy)] pub enum EnrolledCredential { - /// An indicator that a password is enrolled. Passwords can be - /// used to recover from a lost token. + /// Denotes availability of a password. Passwords can be + /// used to recover from a lost passkey. Password, - /// An indicator that one or more WebAuthn credentials were - /// enrolled. + /// Denotes availability of one or more passkeys. WebAuthn } } diff --git a/util/src/micropub.rs b/util/src/micropub.rs index ce9e2d7..6127079 100644 --- a/util/src/micropub.rs +++ b/util/src/micropub.rs @@ -1,3 +1,6 @@ +//! Common protocol types for Micropub. +//! +//! Check out the [`kittybox-indieauth`] crate that gives similar treatment to IndieAuth. use std::collections::HashMap; use serde::{Deserialize, Serialize}; |