Skip to content

Commit 0ede2ab

Browse files
author
KitaitiMakoto
committed
Merge pull request 'Fixes #936: Sign GET request' (#957) from sign-get into main
Reviewed-on: https://git.joinplu.me/Plume/Plume/pulls/957
2 parents 5815602 + 43656d8 commit 0ede2ab

File tree

21 files changed

+400
-142
lines changed

21 files changed

+400
-142
lines changed

.circleci/config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ commands:
6363
type: boolean
6464
default: false
6565
steps:
66-
- run: cargo clippy <<^parameters.no_feature>>--no-default-features --features="${FEATURES}"<</parameters.no_feature>> --release -p <<parameters.package>> -- -D warnings
66+
- run: cargo clippy <<^parameters.no_feature>>--no-default-features --features="${FEATURES}"<</parameters.no_feature>> --release -p <<parameters.package>> -- -D warnings -A clippy::needless_borrow
6767

6868
run_with_coverage:
6969
description: run command with environment for coverage

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
- Upgrade Tantivy to 0.13.3 and lindera-tantivy to 0.7.1 (#878)
2121
- Run searcher on actor system (#870)
2222
- Use article title as its slug instead of capitalizing and inserting hyphens (#920)
23+
- Sign GET requests to other instances (#957)
2324

2425
### Fixed
2526

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

plume-cli/src/instance.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,6 @@ fn new<'a>(args: &ArgMatches<'a>, conn: &Connection) {
6868
},
6969
)
7070
.expect("Couldn't save instance");
71+
Instance::cache_local(conn);
72+
Instance::create_local_instance_user(conn).expect("Couldn't save local instance user");
7173
}

plume-cli/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ fn main() {
2525
e => e.map(|_| ()).unwrap(),
2626
}
2727
let conn = Conn::establish(CONFIG.database_url.as_str());
28-
let _ = conn.as_ref().map(|conn| Instance::cache_local(conn));
28+
let _ = conn.as_ref().map(Instance::cache_local);
2929

3030
match matches.subcommand() {
3131
("instance", Some(args)) => {

plume-common/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,6 @@ version = "0.4"
3333
default-features = false
3434
git = "https://git.joinplu.me/Plume/pulldown-cmark"
3535
branch = "bidi-plume"
36+
37+
[dev-dependencies]
38+
once_cell = "1.5.2"

plume-common/src/activity_pub/inbox.rs

Lines changed: 173 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
use reqwest::header::{HeaderValue, ACCEPT};
1+
use reqwest;
22
use std::fmt::Debug;
33

4+
use super::{request, sign::Signer};
5+
46
/// Represents an ActivityPub inbox.
57
///
68
/// It routes an incoming Activity through the registered handlers.
@@ -10,7 +12,50 @@ use std::fmt::Debug;
1012
/// ```rust
1113
/// # extern crate activitypub;
1214
/// # use activitypub::{actor::Person, activity::{Announce, Create}, object::Note};
15+
/// # use openssl::{hash::MessageDigest, pkey::PKey, rsa::Rsa};
16+
/// # use once_cell::sync::Lazy;
1317
/// # use plume_common::activity_pub::inbox::*;
18+
/// # use plume_common::activity_pub::sign::{gen_keypair, Error as SignError, Result as SignResult, Signer};
19+
/// #
20+
/// # static MY_SIGNER: Lazy<MySigner> = Lazy::new(|| MySigner::new());
21+
/// #
22+
/// # struct MySigner {
23+
/// # public_key: String,
24+
/// # private_key: String,
25+
/// # }
26+
/// #
27+
/// # impl MySigner {
28+
/// # fn new() -> Self {
29+
/// # let (pub_key, priv_key) = gen_keypair();
30+
/// # Self {
31+
/// # public_key: String::from_utf8(pub_key).unwrap(),
32+
/// # private_key: String::from_utf8(priv_key).unwrap(),
33+
/// # }
34+
/// # }
35+
/// # }
36+
/// #
37+
/// # impl Signer for MySigner {
38+
/// # fn get_key_id(&self) -> String {
39+
/// # "mysigner".into()
40+
/// # }
41+
/// #
42+
/// # fn sign(&self, to_sign: &str) -> SignResult<Vec<u8>> {
43+
/// # let key = PKey::from_rsa(Rsa::private_key_from_pem(self.private_key.as_ref()).unwrap())
44+
/// # .unwrap();
45+
/// # let mut signer = openssl::sign::Signer::new(MessageDigest::sha256(), &key).unwrap();
46+
/// # signer.update(to_sign.as_bytes()).unwrap();
47+
/// # signer.sign_to_vec().map_err(|_| SignError())
48+
/// # }
49+
/// #
50+
/// # fn verify(&self, data: &str, signature: &[u8]) -> SignResult<bool> {
51+
/// # let key = PKey::from_rsa(Rsa::public_key_from_pem(self.public_key.as_ref()).unwrap())
52+
/// # .unwrap();
53+
/// # let mut verifier = openssl::sign::Verifier::new(MessageDigest::sha256(), &key).unwrap();
54+
/// # verifier.update(data.as_bytes()).unwrap();
55+
/// # verifier.verify(&signature).map_err(|_| SignError())
56+
/// # }
57+
/// # }
58+
/// #
1459
/// # struct User;
1560
/// # impl FromId<()> for User {
1661
/// # type Error = ();
@@ -23,6 +68,10 @@ use std::fmt::Debug;
2368
/// # fn from_activity(_: &(), obj: Person) -> Result<Self, Self::Error> {
2469
/// # Ok(User)
2570
/// # }
71+
/// #
72+
/// # fn get_sender() -> &'static dyn Signer {
73+
/// # &*MY_SIGNER
74+
/// # }
2675
/// # }
2776
/// # impl AsActor<&()> for User {
2877
/// # fn get_inbox_url(&self) -> String {
@@ -42,6 +91,10 @@ use std::fmt::Debug;
4291
/// # fn from_activity(_: &(), obj: Note) -> Result<Self, Self::Error> {
4392
/// # Ok(Message)
4493
/// # }
94+
/// #
95+
/// # fn get_sender() -> &'static dyn Signer {
96+
/// # &*MY_SIGNER
97+
/// # }
4598
/// # }
4699
/// # impl AsObject<User, Create, &()> for Message {
47100
/// # type Error = ();
@@ -311,42 +364,25 @@ pub trait FromId<C>: Sized {
311364
id: &str,
312365
proxy: Option<reqwest::Proxy>,
313366
) -> Result<Self::Object, (Option<serde_json::Value>, Self::Error)> {
314-
if let Some(proxy) = proxy {
315-
reqwest::ClientBuilder::new().proxy(proxy)
316-
} else {
317-
reqwest::ClientBuilder::new()
318-
}
319-
.connect_timeout(Some(std::time::Duration::from_secs(5)))
320-
.build()
321-
.map_err(|_| (None, InboxError::DerefError.into()))?
322-
.get(id)
323-
.header(
324-
ACCEPT,
325-
HeaderValue::from_str(
326-
&super::ap_accept_header()
327-
.into_iter()
328-
.collect::<Vec<_>>()
329-
.join(", "),
330-
)
331-
.map_err(|_| (None, InboxError::DerefError.into()))?,
332-
)
333-
.send()
334-
.map_err(|_| (None, InboxError::DerefError))
335-
.and_then(|mut r| {
336-
let json: serde_json::Value = r
337-
.json()
338-
.map_err(|_| (None, InboxError::InvalidObject(None)))?;
339-
serde_json::from_value(json.clone())
340-
.map_err(|_| (Some(json), InboxError::InvalidObject(None)))
341-
})
342-
.map_err(|(json, e)| (json, e.into()))
367+
request::get(id, Self::get_sender(), proxy)
368+
.map_err(|_| (None, InboxError::DerefError))
369+
.and_then(|mut r| {
370+
let json: serde_json::Value = r
371+
.json()
372+
.map_err(|_| (None, InboxError::InvalidObject(None)))?;
373+
serde_json::from_value(json.clone())
374+
.map_err(|_| (Some(json), InboxError::InvalidObject(None)))
375+
})
376+
.map_err(|(json, e)| (json, e.into()))
343377
}
344378

345379
/// Builds a `Self` from its ActivityPub representation
346380
fn from_activity(ctx: &C, activity: Self::Object) -> Result<Self, Self::Error>;
347381

348382
/// Tries to find a `Self` with a given ID (`id`), using `ctx` (a database)
349383
fn from_db(ctx: &C, id: &str) -> Result<Self, Self::Error>;
384+
385+
fn get_sender() -> &'static dyn Signer;
350386
}
351387

352388
/// Should be implemented by anything representing an ActivityPub actor.
@@ -385,6 +421,49 @@ pub trait AsActor<C> {
385421
/// # extern crate activitypub;
386422
/// # use activitypub::{activity::Create, actor::Person, object::Note};
387423
/// # use plume_common::activity_pub::inbox::{AsActor, AsObject, FromId};
424+
/// # use plume_common::activity_pub::sign::{gen_keypair, Error as SignError, Result as SignResult, Signer};
425+
/// # use openssl::{hash::MessageDigest, pkey::PKey, rsa::Rsa};
426+
/// # use once_cell::sync::Lazy;
427+
/// #
428+
/// # static MY_SIGNER: Lazy<MySigner> = Lazy::new(|| MySigner::new());
429+
/// #
430+
/// # struct MySigner {
431+
/// # public_key: String,
432+
/// # private_key: String,
433+
/// # }
434+
/// #
435+
/// # impl MySigner {
436+
/// # fn new() -> Self {
437+
/// # let (pub_key, priv_key) = gen_keypair();
438+
/// # Self {
439+
/// # public_key: String::from_utf8(pub_key).unwrap(),
440+
/// # private_key: String::from_utf8(priv_key).unwrap(),
441+
/// # }
442+
/// # }
443+
/// # }
444+
/// #
445+
/// # impl Signer for MySigner {
446+
/// # fn get_key_id(&self) -> String {
447+
/// # "mysigner".into()
448+
/// # }
449+
/// #
450+
/// # fn sign(&self, to_sign: &str) -> SignResult<Vec<u8>> {
451+
/// # let key = PKey::from_rsa(Rsa::private_key_from_pem(self.private_key.as_ref()).unwrap())
452+
/// # .unwrap();
453+
/// # let mut signer = openssl::sign::Signer::new(MessageDigest::sha256(), &key).unwrap();
454+
/// # signer.update(to_sign.as_bytes()).unwrap();
455+
/// # signer.sign_to_vec().map_err(|_| SignError())
456+
/// # }
457+
/// #
458+
/// # fn verify(&self, data: &str, signature: &[u8]) -> SignResult<bool> {
459+
/// # let key = PKey::from_rsa(Rsa::public_key_from_pem(self.public_key.as_ref()).unwrap())
460+
/// # .unwrap();
461+
/// # let mut verifier = openssl::sign::Verifier::new(MessageDigest::sha256(), &key).unwrap();
462+
/// # verifier.update(data.as_bytes()).unwrap();
463+
/// # verifier.verify(&signature).map_err(|_| SignError())
464+
/// # }
465+
/// # }
466+
/// #
388467
/// # struct Account;
389468
/// # impl FromId<()> for Account {
390469
/// # type Error = ();
@@ -397,6 +476,10 @@ pub trait AsActor<C> {
397476
/// # fn from_activity(_: &(), obj: Person) -> Result<Self, Self::Error> {
398477
/// # Ok(Account)
399478
/// # }
479+
/// #
480+
/// # fn get_sender() -> &'static dyn Signer {
481+
/// # &*MY_SIGNER
482+
/// # }
400483
/// # }
401484
/// # impl AsActor<()> for Account {
402485
/// # fn get_inbox_url(&self) -> String {
@@ -420,6 +503,10 @@ pub trait AsActor<C> {
420503
/// fn from_activity(_: &(), obj: Note) -> Result<Self, Self::Error> {
421504
/// Ok(Message { text: obj.object_props.content_string().map_err(|_| ())? })
422505
/// }
506+
///
507+
/// fn get_sender() -> &'static dyn Signer {
508+
/// &*MY_SIGNER
509+
/// }
423510
/// }
424511
///
425512
/// impl AsObject<Account, Create, ()> for Message {
@@ -459,7 +546,51 @@ where
459546
#[cfg(test)]
460547
mod tests {
461548
use super::*;
549+
use crate::activity_pub::sign::{
550+
gen_keypair, Error as SignError, Result as SignResult, Signer,
551+
};
462552
use activitypub::{activity::*, actor::Person, object::Note};
553+
use once_cell::sync::Lazy;
554+
use openssl::{hash::MessageDigest, pkey::PKey, rsa::Rsa};
555+
556+
static MY_SIGNER: Lazy<MySigner> = Lazy::new(|| MySigner::new());
557+
558+
struct MySigner {
559+
public_key: String,
560+
private_key: String,
561+
}
562+
563+
impl MySigner {
564+
fn new() -> Self {
565+
let (pub_key, priv_key) = gen_keypair();
566+
Self {
567+
public_key: String::from_utf8(pub_key).unwrap(),
568+
private_key: String::from_utf8(priv_key).unwrap(),
569+
}
570+
}
571+
}
572+
573+
impl Signer for MySigner {
574+
fn get_key_id(&self) -> String {
575+
"mysigner".into()
576+
}
577+
578+
fn sign(&self, to_sign: &str) -> SignResult<Vec<u8>> {
579+
let key = PKey::from_rsa(Rsa::private_key_from_pem(self.private_key.as_ref()).unwrap())
580+
.unwrap();
581+
let mut signer = openssl::sign::Signer::new(MessageDigest::sha256(), &key).unwrap();
582+
signer.update(to_sign.as_bytes()).unwrap();
583+
signer.sign_to_vec().map_err(|_| SignError())
584+
}
585+
586+
fn verify(&self, data: &str, signature: &[u8]) -> SignResult<bool> {
587+
let key = PKey::from_rsa(Rsa::public_key_from_pem(self.public_key.as_ref()).unwrap())
588+
.unwrap();
589+
let mut verifier = openssl::sign::Verifier::new(MessageDigest::sha256(), &key).unwrap();
590+
verifier.update(data.as_bytes()).unwrap();
591+
verifier.verify(&signature).map_err(|_| SignError())
592+
}
593+
}
463594

464595
struct MyActor;
465596
impl FromId<()> for MyActor {
@@ -473,6 +604,10 @@ mod tests {
473604
fn from_activity(_: &(), _obj: Person) -> Result<Self, Self::Error> {
474605
Ok(MyActor)
475606
}
607+
608+
fn get_sender() -> &'static dyn Signer {
609+
&*MY_SIGNER
610+
}
476611
}
477612

478613
impl AsActor<&()> for MyActor {
@@ -497,6 +632,10 @@ mod tests {
497632
fn from_activity(_: &(), _obj: Note) -> Result<Self, Self::Error> {
498633
Ok(MyObject)
499634
}
635+
636+
fn get_sender() -> &'static dyn Signer {
637+
&*MY_SIGNER
638+
}
500639
}
501640
impl AsObject<MyActor, Create, &()> for MyObject {
502641
type Error = ();
@@ -601,6 +740,10 @@ mod tests {
601740
fn from_activity(_: &(), _obj: Person) -> Result<Self, Self::Error> {
602741
Err(())
603742
}
743+
744+
fn get_sender() -> &'static dyn Signer {
745+
&*MY_SIGNER
746+
}
604747
}
605748
impl AsActor<&()> for FailingActor {
606749
fn get_inbox_url(&self) -> String {

0 commit comments

Comments
 (0)