Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sanitize all playlist descriptions #573

Merged
merged 4 commits into from
Dec 28, 2024
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
12 changes: 12 additions & 0 deletions psst-gui/src/data/playlist.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::sync::Arc;

use druid::{im::Vector, Data, Lens};
use sanitize_html::rules::predefined::DEFAULT;
use sanitize_html::sanitize_str;
use serde::{Deserialize, Deserializer, Serialize};

use crate::data::{user::PublicUser, Image, Promise, Track, TrackId};
Expand Down Expand Up @@ -29,6 +31,7 @@ pub struct Playlist {
pub name: Arc<str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub images: Option<Vector<Image>>,
#[serde(deserialize_with = "deserialize_description")]
pub description: Arc<str>,
#[serde(rename = "tracks")]
#[serde(deserialize_with = "deserialize_track_count")]
Expand Down Expand Up @@ -89,3 +92,12 @@ where

Ok(PlaylistTracksRef::deserialize(deserializer)?.total)
}

fn deserialize_description<'de, D>(deserializer: D) -> Result<Arc<str>, D::Error>
where
D: Deserializer<'de>,
{
let description: String = String::deserialize(deserializer)?;
let sanitized = sanitize_str(&DEFAULT, &description).unwrap_or_default();
Ok(Arc::from(sanitized.replace("&amp;", "&")))
}
52 changes: 26 additions & 26 deletions psst-gui/src/webapi/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ use druid::{
use itertools::Itertools;
use once_cell::sync::OnceCell;
use parking_lot::Mutex;
use sanitize_html::rules::predefined::DEFAULT;
use sanitize_html::sanitize_str;
use serde::{de::DeserializeOwned, Deserialize};
use serde_json::json;
use ureq::{Agent, Request, Response};
Expand All @@ -39,6 +37,9 @@ use crate::{
};

use super::{cache::WebApiCache, local::LocalTrackManager};
use sanitize_html::rules::predefined::DEFAULT;
use sanitize_html::sanitize_str;

pub struct WebApi {
session: SessionService,
agent: Agent,
Expand Down Expand Up @@ -128,8 +129,7 @@ impl WebApi {
/// Send a request with a empty JSON object, throw away the response body.
/// Use for POST/PUT/DELETE requests.
fn send_empty_json(&self, request: Request) -> Result<(), Error> {
Self::with_retry(|| Ok(request.clone().send_string("{}")?))
.map(|_| ())
Self::with_retry(|| Ok(request.clone().send_string("{}")?)).map(|_| ())
}

/// Send a request and return the deserialized JSON body. Use for GET
Expand Down Expand Up @@ -486,23 +486,21 @@ impl WebApi {
},
)),
description: {
let desc = sanitize_str(
&DEFAULT,
item.content
.data
.description
.as_deref()
.unwrap_or_default(),
)
.unwrap_or_default();
let desc = item
.content
.data
.description
.as_deref()
.unwrap_or_default()
.to_string();
// This is roughly 3 lines of description, truncated if too long
if desc.chars().count() > 55 {
desc.chars().take(52).collect::<String>() + "..."
} else {
desc
}
.into()
},
}
.into(),
track_count: item.content.data.attributes.as_ref().and_then(
|attrs| {
attrs
Expand All @@ -513,13 +511,14 @@ impl WebApi {
),
owner: PublicUser {
id: Arc::from(""),
display_name: Arc::from(item
.content
.data
.owner_v2
.as_ref()
.map(|owner| owner.data.name.as_str())
.unwrap_or_default())
display_name: Arc::from(
item.content
.data
.owner_v2
.as_ref()
.map(|owner| owner.data.name.as_str())
.unwrap_or_default(),
),
},
collaborative: false,
});
Expand Down Expand Up @@ -1200,7 +1199,7 @@ impl WebApi {
// https://developer.spotify.com/documentation/web-api/reference/get-a-list-of-current-users-playlists
pub fn get_playlists(&self) -> Result<Vector<Playlist>, Error> {
let request = self.get("v1/me/playlists", None)?;
let result = self.load_all_pages(request)?;
let result: Vector<Playlist> = self.load_all_pages(request)?;
Ok(result)
}

Expand All @@ -1219,7 +1218,7 @@ impl WebApi {
// https://developer.spotify.com/documentation/web-api/reference/get-playlist
pub fn get_playlist(&self, id: &str) -> Result<Playlist, Error> {
let request = self.get(format!("v1/playlists/{}", id), None)?;
let result = self.load(request)?;
let result: Playlist = self.load(request)?;
Ok(result)
}

Expand Down Expand Up @@ -1318,14 +1317,15 @@ impl WebApi {
let artists = result.artists.map_or_else(Vector::new, |page| page.items);
let albums = result.albums.map_or_else(Vector::new, |page| page.items);
let tracks = result.tracks.map_or_else(Vector::new, |page| page.items);
let playlist = result.playlists.map_or_else(Vector::new, |page| page.items);
let playlists = result.playlists.map_or_else(Vector::new, |page| page.items);
let shows = result.shows.map_or_else(Vector::new, |page| page.items);

Ok(SearchResults {
query: query.into(),
artists,
albums,
tracks,
playlists: playlist,
playlists,
shows,
})
}
Expand Down
Loading