httpd: Improve data-uri support

We were just using `strip_prefix` with a hardcoded value, which wasn't
able to adjust to URIs that start with `data:image/png` or other content
and types.

Signed-off-by: Sebastian Martinez <me@sebastinez.dev>
This commit is contained in:
Sebastian Martinez 2023-09-19 16:00:21 +02:00 committed by cloudhead
parent e57dbc337a
commit 5acfffb352
No known key found for this signature in database
2 changed files with 41 additions and 29 deletions

View File

@ -10,13 +10,14 @@ use axum::http::Method;
use axum::response::{IntoResponse, Json};
use axum::routing::get;
use axum::Router;
use base64::prelude::{Engine, BASE64_STANDARD};
use serde::{Deserialize, Serialize};
use serde_json::json;
use tokio::sync::RwLock;
use tower_http::cors::{self, CorsLayer};
use radicle::cob::issue;
use radicle::cob::patch;
use radicle::cob::{issue, Uri};
use radicle::identity::Id;
use radicle::node::routing::Store;
use radicle::storage::{ReadRepository, ReadStorage};
@ -204,3 +205,29 @@ mod project {
pub trackings: usize,
}
}
/// A `data:` URI.
#[derive(Debug, Clone)]
pub struct DataUri(Vec<u8>);
impl From<DataUri> for Vec<u8> {
fn from(value: DataUri) -> Self {
value.0
}
}
impl TryFrom<&Uri> for DataUri {
type Error = Uri;
fn try_from(value: &Uri) -> Result<Self, Self::Error> {
if let Some(data_uri) = value.as_str().strip_prefix("data:") {
let (_, uri_data) = data_uri.split_once(',').ok_or(value.clone())?;
let uri_data = BASE64_STANDARD
.decode(uri_data)
.map_err(|_| value.clone())?;
return Ok(DataUri(uri_data));
}
Err(value.clone())
}
}

View File

@ -7,7 +7,6 @@ use axum::response::IntoResponse;
use axum::routing::{get, patch, post};
use axum::{Json, Router};
use axum_auth::AuthBearer;
use base64::prelude::{Engine, BASE64_STANDARD};
use hyper::StatusCode;
use radicle_surf::blob::{Blob, BlobRef};
use serde::{Deserialize, Serialize};
@ -25,7 +24,7 @@ use radicle_surf::{diff, Glob, Oid, Repository};
use crate::api::error::Error;
use crate::api::project::Info;
use crate::api::{self, CobsQuery, Context, PaginationQuery};
use crate::api::{self, CobsQuery, Context, DataUri, PaginationQuery};
use crate::axum_extra::{Path, Query};
const CACHE_1_HOUR: &str = "public, max-age=3600, must-revalidate";
@ -534,18 +533,11 @@ async fn issue_create_handler(
.embeds
.into_iter()
.filter_map(|embed| {
if let Some(content) = embed
.content
.as_str()
.strip_prefix("data:content/type;base64,")
{
return BASE64_STANDARD.decode(content).ok().map(|content| Embed {
name: embed.name,
content,
});
}
None
let content = TryInto::<DataUri>::try_into(&embed.content).ok()?;
Some(Embed {
name: embed.name,
content: content.into(),
})
})
.collect();
@ -604,18 +596,11 @@ async fn issue_update_handler(
let embeds: Vec<Embed> = embeds
.into_iter()
.filter_map(|embed| {
if let Some(content) = embed
.content
.as_str()
.strip_prefix("data:content/type;base64,")
{
return BASE64_STANDARD.decode(content).ok().map(|content| Embed {
name: embed.name,
content,
});
}
None
let content = TryInto::<DataUri>::try_into(&embed.content).ok()?;
Some(Embed {
name: embed.name,
content: content.into(),
})
})
.collect();
if let Some(to) = reply_to {
@ -1848,7 +1833,7 @@ mod routes {
"embeds": [
{
"name": "example.html",
"content": "data:content/type;base64,PGh0bWw+SGVsbG8gV29ybGQhPC9odG1sPg=="
"content": "data:image/png;base64,PGh0bWw+SGVsbG8gV29ybGQhPC9odG1sPg=="
}
],
"assignees": [],
@ -1924,7 +1909,7 @@ mod routes {
"embeds": [
{
"name": "image.jpg",
"content": "data:content/type;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAADElEQVR4nGP4//8/AAX+Av4N70a4AAAAAElFTkSuQmCC"
"content": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAADElEQVR4nGP4//8/AAX+Av4N70a4AAAAAElFTkSuQmCC"
}
],
"replyTo": CONTRIBUTOR_ISSUE_ID,