Simplify signing code
This commit is contained in:
parent
8daf72278d
commit
5284dc0c52
7 changed files with 25 additions and 59 deletions
|
@ -201,7 +201,7 @@ impl Perform<CommunityResponse> for Oper<CreateCommunity> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// When you create a community, make sure the user becomes a moderator and a follower
|
// When you create a community, make sure the user becomes a moderator and a follower
|
||||||
let keypair = generate_actor_keypair();
|
let keypair = generate_actor_keypair()?;
|
||||||
|
|
||||||
let community_form = CommunityForm {
|
let community_form = CommunityForm {
|
||||||
name: data.name.to_owned(),
|
name: data.name.to_owned(),
|
||||||
|
|
|
@ -252,7 +252,7 @@ impl Perform<LoginResponse> for Oper<Register> {
|
||||||
return Err(APIError::err("admin_already_created").into());
|
return Err(APIError::err("admin_already_created").into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let keypair = generate_actor_keypair();
|
let keypair = generate_actor_keypair()?;
|
||||||
|
|
||||||
// Register the new user
|
// Register the new user
|
||||||
let user_form = UserForm {
|
let user_form = UserForm {
|
||||||
|
@ -296,7 +296,7 @@ impl Perform<LoginResponse> for Oper<Register> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let keypair = generate_actor_keypair();
|
let keypair = generate_actor_keypair()?;
|
||||||
|
|
||||||
// Create the main community if it doesn't exist
|
// Create the main community if it doesn't exist
|
||||||
let main_community: Community = match Community::read(&conn, 2) {
|
let main_community: Community = match Community::read(&conn, 2) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::apub::is_apub_id_valid;
|
use crate::apub::is_apub_id_valid;
|
||||||
use crate::apub::signatures::{sign, Keypair};
|
use crate::apub::signatures::sign;
|
||||||
use crate::db::community::Community;
|
use crate::db::community::Community;
|
||||||
use crate::db::community_view::CommunityFollowerView;
|
use crate::db::community_view::CommunityFollowerView;
|
||||||
use crate::db::post::Post;
|
use crate::db::post::Post;
|
||||||
|
@ -36,7 +36,7 @@ fn populate_object_props(
|
||||||
/// Send an activity to a list of recipients, using the correct headers etc.
|
/// Send an activity to a list of recipients, using the correct headers etc.
|
||||||
fn send_activity<A>(
|
fn send_activity<A>(
|
||||||
activity: &A,
|
activity: &A,
|
||||||
keypair: &Keypair,
|
private_key: &str,
|
||||||
sender_id: &str,
|
sender_id: &str,
|
||||||
to: Vec<String>,
|
to: Vec<String>,
|
||||||
) -> Result<(), Error>
|
) -> Result<(), Error>
|
||||||
|
@ -52,7 +52,7 @@ where
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let request = Request::post(t).header("Host", to_url.domain().unwrap());
|
let request = Request::post(t).header("Host", to_url.domain().unwrap());
|
||||||
let signature = sign(&request, keypair, sender_id)?;
|
let signature = sign(&request, private_key, sender_id)?;
|
||||||
let res = request
|
let res = request
|
||||||
.header("Signature", signature)
|
.header("Signature", signature)
|
||||||
.header("Content-Type", "application/json")
|
.header("Content-Type", "application/json")
|
||||||
|
@ -90,7 +90,7 @@ pub fn post_create(post: &Post, creator: &User_, conn: &PgConnection) -> Result<
|
||||||
.set_object_base_box(page)?;
|
.set_object_base_box(page)?;
|
||||||
send_activity(
|
send_activity(
|
||||||
&create,
|
&create,
|
||||||
&creator.get_keypair().unwrap(),
|
&creator.private_key.as_ref().unwrap(),
|
||||||
&creator.actor_id,
|
&creator.actor_id,
|
||||||
get_follower_inboxes(conn, &community)?,
|
get_follower_inboxes(conn, &community)?,
|
||||||
)?;
|
)?;
|
||||||
|
@ -113,7 +113,7 @@ pub fn post_update(post: &Post, creator: &User_, conn: &PgConnection) -> Result<
|
||||||
.set_object_base_box(page)?;
|
.set_object_base_box(page)?;
|
||||||
send_activity(
|
send_activity(
|
||||||
&update,
|
&update,
|
||||||
&creator.get_keypair().unwrap(),
|
&creator.private_key.as_ref().unwrap(),
|
||||||
&creator.actor_id,
|
&creator.actor_id,
|
||||||
get_follower_inboxes(conn, &community)?,
|
get_follower_inboxes(conn, &community)?,
|
||||||
)?;
|
)?;
|
||||||
|
@ -139,7 +139,7 @@ pub fn follow_community(
|
||||||
let to = format!("{}/inbox", community.actor_id);
|
let to = format!("{}/inbox", community.actor_id);
|
||||||
send_activity(
|
send_activity(
|
||||||
&follow,
|
&follow,
|
||||||
&community.get_keypair().unwrap(),
|
&community.private_key.as_ref().unwrap(),
|
||||||
&community.actor_id,
|
&community.actor_id,
|
||||||
vec![to],
|
vec![to],
|
||||||
)?;
|
)?;
|
||||||
|
@ -172,7 +172,7 @@ pub fn accept_follow(follow: &Follow, conn: &PgConnection) -> Result<(), Error>
|
||||||
let to = format!("{}/inbox", community_uri);
|
let to = format!("{}/inbox", community_uri);
|
||||||
send_activity(
|
send_activity(
|
||||||
&accept,
|
&accept,
|
||||||
&community.get_keypair().unwrap(),
|
&community.private_key.unwrap(),
|
||||||
&community.actor_id,
|
&community.actor_id,
|
||||||
vec![to],
|
vec![to],
|
||||||
)?;
|
)?;
|
||||||
|
|
|
@ -14,23 +14,20 @@ pub struct Keypair {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate the asymmetric keypair for ActivityPub HTTP signatures.
|
/// Generate the asymmetric keypair for ActivityPub HTTP signatures.
|
||||||
pub fn generate_actor_keypair() -> Keypair {
|
pub fn generate_actor_keypair() -> Result<Keypair, Error> {
|
||||||
let rsa = Rsa::generate(2048).expect("sign::gen_keypair: key generation error");
|
let rsa = Rsa::generate(2048)?;
|
||||||
let pkey = PKey::from_rsa(rsa).expect("sign::gen_keypair: parsing error");
|
let pkey = PKey::from_rsa(rsa)?;
|
||||||
let public_key = pkey
|
let public_key = pkey.public_key_to_pem()?;
|
||||||
.public_key_to_pem()
|
let private_key = pkey.private_key_to_pem_pkcs8()?;
|
||||||
.expect("sign::gen_keypair: public key encoding error");
|
Ok(Keypair {
|
||||||
let private_key = pkey
|
private_key: String::from_utf8(private_key)?,
|
||||||
.private_key_to_pem_pkcs8()
|
public_key: String::from_utf8(public_key)?,
|
||||||
.expect("sign::gen_keypair: private key encoding error");
|
})
|
||||||
Keypair {
|
|
||||||
private_key: String::from_utf8_lossy(&private_key).into_owned(),
|
|
||||||
public_key: String::from_utf8_lossy(&public_key).into_owned(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Signs request headers with the given keypair.
|
/// Signs request headers with the given keypair.
|
||||||
pub fn sign(request: &Builder, keypair: &Keypair, sender_id: &str) -> Result<String, Error> {
|
/// TODO: would be nice to pass the sending actor in, instead of raw privatekey/id strings
|
||||||
|
pub fn sign(request: &Builder, private_key: &str, sender_id: &str) -> Result<String, Error> {
|
||||||
let signing_key_id = format!("{}#main-key", sender_id);
|
let signing_key_id = format!("{}#main-key", sender_id);
|
||||||
let config = Config::new();
|
let config = Config::new();
|
||||||
|
|
||||||
|
@ -55,7 +52,7 @@ pub fn sign(request: &Builder, keypair: &Keypair, sender_id: &str) -> Result<Str
|
||||||
headers,
|
headers,
|
||||||
)
|
)
|
||||||
.sign(signing_key_id, |signing_string| {
|
.sign(signing_key_id, |signing_string| {
|
||||||
let private_key = PKey::private_key_from_pem(keypair.private_key.as_bytes())?;
|
let private_key = PKey::private_key_from_pem(private_key.as_bytes())?;
|
||||||
let mut signer = Signer::new(MessageDigest::sha256(), &private_key).unwrap();
|
let mut signer = Signer::new(MessageDigest::sha256(), &private_key).unwrap();
|
||||||
signer.update(signing_string.as_bytes()).unwrap();
|
signer.update(signing_string.as_bytes()).unwrap();
|
||||||
Ok(base64::encode(signer.sign_to_vec()?)) as Result<_, Error>
|
Ok(base64::encode(signer.sign_to_vec()?)) as Result<_, Error>
|
||||||
|
|
|
@ -7,6 +7,7 @@ use super::*;
|
||||||
use crate::apub::signatures::generate_actor_keypair;
|
use crate::apub::signatures::generate_actor_keypair;
|
||||||
use crate::apub::{make_apub_endpoint, EndpointType};
|
use crate::apub::{make_apub_endpoint, EndpointType};
|
||||||
use crate::naive_now;
|
use crate::naive_now;
|
||||||
|
use failure::Error;
|
||||||
use log::info;
|
use log::info;
|
||||||
|
|
||||||
pub fn run_advanced_migrations(conn: &PgConnection) -> Result<(), Error> {
|
pub fn run_advanced_migrations(conn: &PgConnection) -> Result<(), Error> {
|
||||||
|
@ -30,7 +31,7 @@ fn user_updates_2020_04_02(conn: &PgConnection) -> Result<(), Error> {
|
||||||
.load::<User_>(conn)?;
|
.load::<User_>(conn)?;
|
||||||
|
|
||||||
for cuser in &incorrect_users {
|
for cuser in &incorrect_users {
|
||||||
let keypair = generate_actor_keypair();
|
let keypair = generate_actor_keypair()?;
|
||||||
|
|
||||||
let form = UserForm {
|
let form = UserForm {
|
||||||
name: cuser.name.to_owned(),
|
name: cuser.name.to_owned(),
|
||||||
|
@ -77,7 +78,7 @@ fn community_updates_2020_04_02(conn: &PgConnection) -> Result<(), Error> {
|
||||||
.load::<Community>(conn)?;
|
.load::<Community>(conn)?;
|
||||||
|
|
||||||
for ccommunity in &incorrect_communities {
|
for ccommunity in &incorrect_communities {
|
||||||
let keypair = generate_actor_keypair();
|
let keypair = generate_actor_keypair()?;
|
||||||
|
|
||||||
let form = CommunityForm {
|
let form = CommunityForm {
|
||||||
name: ccommunity.name.to_owned(),
|
name: ccommunity.name.to_owned(),
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::apub::signatures::Keypair;
|
|
||||||
use crate::schema::{community, community_follower, community_moderator, community_user_ban};
|
use crate::schema::{community, community_follower, community_moderator, community_user_ban};
|
||||||
|
|
||||||
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
|
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
|
||||||
|
@ -96,21 +95,6 @@ impl Community {
|
||||||
pub fn get_url(&self) -> String {
|
pub fn get_url(&self) -> String {
|
||||||
format!("https://{}/c/{}", Settings::get().hostname, self.name)
|
format!("https://{}/c/{}", Settings::get().hostname, self.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_keypair(&self) -> Option<Keypair> {
|
|
||||||
if let Some(private) = self.private_key.to_owned() {
|
|
||||||
if let Some(public) = self.public_key.to_owned() {
|
|
||||||
Some(Keypair {
|
|
||||||
private_key: private,
|
|
||||||
public_key: public,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
|
#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::apub::signatures::Keypair;
|
|
||||||
use crate::schema::user_;
|
use crate::schema::user_;
|
||||||
use crate::schema::user_::dsl::*;
|
use crate::schema::user_::dsl::*;
|
||||||
use crate::{is_email_regex, naive_now, Settings};
|
use crate::{is_email_regex, naive_now, Settings};
|
||||||
|
@ -125,21 +124,6 @@ impl User_ {
|
||||||
use crate::schema::user_::dsl::*;
|
use crate::schema::user_::dsl::*;
|
||||||
user_.filter(actor_id.eq(object_id)).first::<Self>(conn)
|
user_.filter(actor_id.eq(object_id)).first::<Self>(conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_keypair(&self) -> Option<Keypair> {
|
|
||||||
if let Some(private) = self.private_key.to_owned() {
|
|
||||||
if let Some(public) = self.public_key.to_owned() {
|
|
||||||
Some(Keypair {
|
|
||||||
private_key: private,
|
|
||||||
public_key: public,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
|
Loading…
Reference in a new issue