Reviewed-on: #1129
This commit is contained in:
commit
dd3a5f4a5b
7 changed files with 105 additions and 47 deletions
|
@ -561,7 +561,7 @@ mod tests {
|
|||
use once_cell::sync::Lazy;
|
||||
use openssl::{hash::MessageDigest, pkey::PKey, rsa::Rsa};
|
||||
|
||||
static MY_SIGNER: Lazy<MySigner> = Lazy::new(|| MySigner::new());
|
||||
static MY_SIGNER: Lazy<MySigner> = Lazy::new(MySigner::new);
|
||||
|
||||
struct MySigner {
|
||||
public_key: String,
|
||||
|
@ -596,7 +596,7 @@ mod tests {
|
|||
.unwrap();
|
||||
let mut verifier = openssl::sign::Verifier::new(MessageDigest::sha256(), &key).unwrap();
|
||||
verifier.update(data.as_bytes()).unwrap();
|
||||
verifier.verify(&signature).map_err(|_| SignError())
|
||||
verifier.verify(signature).map_err(|_| SignError())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -782,7 +782,7 @@ mod tests {
|
|||
.done();
|
||||
assert!(res.is_err());
|
||||
|
||||
let res: Result<(), ()> = Inbox::handle(&(), act.clone())
|
||||
let res: Result<(), ()> = Inbox::handle(&(), act)
|
||||
.with::<FailingActor, Create, MyObject>(None)
|
||||
.with::<MyActor, Create, MyObject>(None)
|
||||
.done();
|
||||
|
|
|
@ -518,7 +518,8 @@ mod tests {
|
|||
use super::*;
|
||||
use activitystreams::{
|
||||
activity::{ActorAndObjectRef, Create},
|
||||
object::kind::ArticleType,
|
||||
object::{kind::ArticleType, Image},
|
||||
prelude::{ApActorExt, BaseExt, ExtendsExt, ObjectExt},
|
||||
};
|
||||
use assert_json_diff::assert_json_eq;
|
||||
use serde_json::{from_str, json, to_value};
|
||||
|
@ -592,7 +593,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn de_custom_group() {
|
||||
fn se_custom_group() {
|
||||
let group = CustomGroup::new(
|
||||
ApActor::new("https://example.com/inbox".parse().unwrap(), Group::new()),
|
||||
ApSignature {
|
||||
|
@ -625,6 +626,71 @@ mod tests {
|
|||
assert_eq!(to_value(group).unwrap(), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn de_custom_group() {
|
||||
let value: CustomGroup = from_str(
|
||||
r#"
|
||||
{
|
||||
"icon": {
|
||||
"type": "Image"
|
||||
},
|
||||
"id": "https://plume01.localhost/~/Plume01%20Blog%202/",
|
||||
"image": {
|
||||
"type": "Image"
|
||||
},
|
||||
"inbox": "https://plume01.localhost/~/Plume01%20Blog%202/inbox",
|
||||
"name": "Plume01 Blog 2",
|
||||
"outbox": "https://plume01.localhost/~/Plume01%20Blog%202/outbox",
|
||||
"preferredUsername": "Plume01 Blog 2",
|
||||
"publicKey": {
|
||||
"id": "https://plume01.localhost/~/Plume01%20Blog%202/#main-key",
|
||||
"owner": "https://plume01.localhost/~/Plume01%20Blog%202/",
|
||||
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwPGtKkl/iMsNAyeVaJGz\noEz5PoNkjRnKK7G97MFvb4zw9zs5SpzWW7b/pKHa4dODcGDJXmkCJ1H5JWyguzN8\n2GNoFjtEOJHxEGwBHSYDsTmhuLNB0DKxMU2iu55g8iIiXhZiIW1FBNGs/Geaymvr\nh/TEtzdReN8wzloRR55kOVcU49xBkqx8cfDSk/lrrDLlpveHdqgaFnIvuw2vycK0\nxFzS3xlEUpzJk9kHxoR1uEAfZ+gCv26Sgo/HqOAhqSD5IU3QZC3kdkr/hwVqtr8U\nXGkGG6Mo1rgzhkYiCFkWrV2WoKkcEHD4nEzbgoZZ5MyuSoloxnyF3NiScqmqW+Yx\nkQIDAQAB\n-----END PUBLIC KEY-----\n"
|
||||
},
|
||||
"source": {
|
||||
"content": "",
|
||||
"mediaType": "text/markdown"
|
||||
},
|
||||
"summary": "",
|
||||
"type": "Group"
|
||||
}
|
||||
"#
|
||||
).unwrap();
|
||||
let mut expected = CustomGroup::new(
|
||||
ApActor::new("https://plume01.localhost/~/Plume01%20Blog%202/inbox".parse().unwrap(), Group::new()),
|
||||
ApSignature {
|
||||
public_key: PublicKey {
|
||||
id: "https://plume01.localhost/~/Plume01%20Blog%202/#main-key".parse().unwrap(),
|
||||
owner: "https://plume01.localhost/~/Plume01%20Blog%202/".parse().unwrap(),
|
||||
public_key_pem: "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwPGtKkl/iMsNAyeVaJGz\noEz5PoNkjRnKK7G97MFvb4zw9zs5SpzWW7b/pKHa4dODcGDJXmkCJ1H5JWyguzN8\n2GNoFjtEOJHxEGwBHSYDsTmhuLNB0DKxMU2iu55g8iIiXhZiIW1FBNGs/Geaymvr\nh/TEtzdReN8wzloRR55kOVcU49xBkqx8cfDSk/lrrDLlpveHdqgaFnIvuw2vycK0\nxFzS3xlEUpzJk9kHxoR1uEAfZ+gCv26Sgo/HqOAhqSD5IU3QZC3kdkr/hwVqtr8U\nXGkGG6Mo1rgzhkYiCFkWrV2WoKkcEHD4nEzbgoZZ5MyuSoloxnyF3NiScqmqW+Yx\nkQIDAQAB\n-----END PUBLIC KEY-----\n".into(),
|
||||
}
|
||||
},
|
||||
SourceProperty {
|
||||
source: Source {
|
||||
content: String::from(""),
|
||||
media_type: String::from("text/markdown")
|
||||
}
|
||||
}
|
||||
);
|
||||
expected.set_icon(Image::new().into_any_base().unwrap());
|
||||
expected.set_id(
|
||||
"https://plume01.localhost/~/Plume01%20Blog%202/"
|
||||
.parse()
|
||||
.unwrap(),
|
||||
);
|
||||
expected.set_image(Image::new().into_any_base().unwrap());
|
||||
expected.set_name("Plume01 Blog 2");
|
||||
expected.set_outbox(
|
||||
"https://plume01.localhost/~/Plume01%20Blog%202/outbox"
|
||||
.parse()
|
||||
.unwrap(),
|
||||
);
|
||||
expected.set_preferred_username("Plume01 Blog 2");
|
||||
expected.set_summary("");
|
||||
|
||||
assert_json_eq!(value, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn se_licensed_article() {
|
||||
let object = ApObject::new(Article::new());
|
||||
|
|
|
@ -253,7 +253,7 @@ mod tests {
|
|||
.unwrap();
|
||||
let mut verifier = openssl::sign::Verifier::new(MessageDigest::sha256(), &key).unwrap();
|
||||
verifier.update(data.as_bytes()).unwrap();
|
||||
verifier.verify(&signature).map_err(|_| Error())
|
||||
verifier.verify(signature).map_err(|_| Error())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -262,7 +262,7 @@ mod tests {
|
|||
let signer = MySigner::new();
|
||||
let headers = HeaderMap::new();
|
||||
let result = signature(&signer, &headers, ("post", "/inbox", None)).unwrap();
|
||||
let fields: Vec<&str> = result.to_str().unwrap().split(",").collect();
|
||||
let fields: Vec<&str> = result.to_str().unwrap().split(',').collect();
|
||||
assert_eq!(r#"headers="(request-target)""#, fields[2]);
|
||||
let sign = &fields[3][11..(fields[3].len() - 1)];
|
||||
assert!(signer.verify("post /inbox", sign.as_bytes()).is_ok());
|
||||
|
|
|
@ -18,10 +18,13 @@ use openssl::{
|
|||
rsa::Rsa,
|
||||
sign::{Signer, Verifier},
|
||||
};
|
||||
use plume_common::activity_pub::{
|
||||
inbox::{AsActor, FromId},
|
||||
sign, ActivityStream, ApSignature, CustomGroup, Id, IntoId, PublicKey, Source, SourceProperty,
|
||||
ToAsString, ToAsUri,
|
||||
use plume_common::{
|
||||
activity_pub::{
|
||||
inbox::{AsActor, FromId},
|
||||
sign, ActivityStream, ApSignature, CustomGroup, Id, IntoId, PublicKey, Source,
|
||||
SourceProperty, ToAsString, ToAsUri,
|
||||
},
|
||||
utils::iri_percent_encode_seg,
|
||||
};
|
||||
use webfinger::*;
|
||||
|
||||
|
@ -83,9 +86,13 @@ impl Blog {
|
|||
|
||||
if inserted.fqn.is_empty() {
|
||||
if instance.local {
|
||||
inserted.fqn = inserted.actor_id.clone();
|
||||
inserted.fqn = iri_percent_encode_seg(&inserted.actor_id.clone());
|
||||
} else {
|
||||
inserted.fqn = format!("{}@{}", inserted.actor_id, instance.public_domain);
|
||||
inserted.fqn = format!(
|
||||
"{}@{}",
|
||||
iri_percent_encode_seg(&inserted.actor_id),
|
||||
instance.public_domain
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -166,7 +173,7 @@ impl Blog {
|
|||
|
||||
pub fn to_activity(&self, conn: &Connection) -> Result<CustomGroup> {
|
||||
let mut blog = ApActor::new(self.inbox_url.parse()?, Group::new());
|
||||
blog.set_preferred_username(self.actor_id.clone());
|
||||
blog.set_preferred_username(iri_percent_encode_seg(&self.actor_id));
|
||||
blog.set_name(self.title.clone());
|
||||
blog.set_outbox(self.outbox_url.parse()?);
|
||||
blog.set_summary(self.summary_html.to_string());
|
||||
|
@ -381,6 +388,7 @@ impl FromId<DbConn> for Blog {
|
|||
.ok_or(Error::MissingApProperty)?
|
||||
.to_string();
|
||||
if name.contains(&['<', '>', '&', '@', '\'', '"', ' ', '\t'][..]) {
|
||||
tracing::error!("preferredUsername includes invalid character(s): {}", &name);
|
||||
return Err(Error::InvalidValue);
|
||||
}
|
||||
(
|
||||
|
|
|
@ -9,7 +9,7 @@ use crate::{
|
|||
use chrono::NaiveDateTime;
|
||||
use diesel::{self, result::Error::NotFound, ExpressionMethods, QueryDsl, RunQueryDsl};
|
||||
use once_cell::sync::OnceCell;
|
||||
use plume_common::utils::{md_to_html, iri_percent_encode_seg};
|
||||
use plume_common::utils::{iri_percent_encode_seg, md_to_html};
|
||||
use std::sync::RwLock;
|
||||
|
||||
#[derive(Clone, Identifiable, Queryable)]
|
||||
|
|
|
@ -45,7 +45,10 @@ impl Actor for RemoteFetchActor {
|
|||
RemoteUserFound(user) => match self.conn.get() {
|
||||
Ok(conn) => {
|
||||
let conn = DbConn(conn);
|
||||
if user.get_instance(&conn).map_or(false, |instance| instance.blocked) {
|
||||
if user
|
||||
.get_instance(&conn)
|
||||
.map_or(false, |instance| instance.blocked)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Don't call these functions in parallel
|
||||
|
|
|
@ -246,20 +246,7 @@ impl User {
|
|||
fn fetch(url: &str) -> Result<CustomPerson> {
|
||||
let res = get(url, Self::get_sender(), CONFIG.proxy().cloned())?;
|
||||
let text = &res.text()?;
|
||||
// without this workaround, publicKey is not correctly deserialized
|
||||
let ap_sign = serde_json::from_str::<ApSignature>(text)?;
|
||||
let person = serde_json::from_str::<Person>(text)?;
|
||||
let json = CustomPerson::new(
|
||||
ApActor::new(
|
||||
person
|
||||
.clone()
|
||||
.id_unchecked()
|
||||
.ok_or(Error::MissingApProperty)?
|
||||
.to_owned(),
|
||||
person,
|
||||
),
|
||||
ap_sign,
|
||||
); // FIXME: Don't clone()
|
||||
let json = serde_json::from_str::<CustomPerson>(text)?;
|
||||
Ok(json)
|
||||
}
|
||||
|
||||
|
@ -269,23 +256,13 @@ impl User {
|
|||
|
||||
pub fn refetch(&self, conn: &Connection) -> Result<()> {
|
||||
User::fetch(&self.ap_url.clone()).and_then(|json| {
|
||||
let avatar = Media::save_remote(
|
||||
conn,
|
||||
json.ap_actor_ref()
|
||||
.icon()
|
||||
.ok_or(Error::MissingApProperty)? // FIXME: Fails when icon is not set
|
||||
.iter()
|
||||
.next()
|
||||
.and_then(|i| {
|
||||
i.clone()
|
||||
.extend::<Image, ImageType>() // FIXME: Don't clone()
|
||||
.ok()?
|
||||
.and_then(|url| Some(url.id_unchecked()?.to_string()))
|
||||
})
|
||||
.ok_or(Error::MissingApProperty)?,
|
||||
self,
|
||||
)
|
||||
.ok();
|
||||
let avatar = json
|
||||
.icon()
|
||||
.and_then(|icon| icon.iter().next())
|
||||
.and_then(|i| i.clone().extend::<Image, ImageType>().ok())
|
||||
.and_then(|image| image)
|
||||
.and_then(|image| image.id_unchecked().map(|url| url.to_string()))
|
||||
.and_then(|url| Media::save_remote(conn, url, self).ok());
|
||||
|
||||
let pub_key = &json.ext_one.public_key.public_key_pem;
|
||||
diesel::update(self)
|
||||
|
@ -960,6 +937,10 @@ impl FromId<DbConn> for User {
|
|||
.to_string();
|
||||
|
||||
if username.contains(&['<', '>', '&', '@', '\'', '"', ' ', '\t'][..]) {
|
||||
tracing::error!(
|
||||
"preferredUsername includes invalid character(s): {}",
|
||||
&username
|
||||
);
|
||||
return Err(Error::InvalidValue);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue