WIP: make it possible for users to sign activities
This commit is contained in:
		
							parent
							
								
									b844257e34
								
							
						
					
					
						commit
						6b372861d6
					
				
							
								
								
									
										3
									
								
								migrations/2018-05-03-163427_user_add_keys/down.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								migrations/2018-05-03-163427_user_add_keys/down.sql
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| -- This file should undo anything in `up.sql` | ||||
| ALTER TABLE users DROP COLUMN private_key; | ||||
| ALTER TABLE users DROP COLUMN public_key; | ||||
							
								
								
									
										3
									
								
								migrations/2018-05-03-163427_user_add_keys/up.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								migrations/2018-05-03-163427_user_add_keys/up.sql
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| -- Your SQL goes here | ||||
| ALTER TABLE users ADD COLUMN private_key TEXT; | ||||
| ALTER TABLE users ADD COLUMN public_key TEXT NOT NULL DEFAULT ''; | ||||
| @ -1,20 +1,19 @@ | ||||
| use base64; | ||||
| use diesel::PgConnection; | ||||
| use hex; | ||||
| use chrono::Utc; | ||||
| use openssl::sha::sha256; | ||||
| use serde_json; | ||||
| 
 | ||||
| // (Comments are from the Mastodon source code, to remember what to do.)
 | ||||
| 
 | ||||
| pub trait Signer { | ||||
|     fn get_key_id(&self) -> String; | ||||
|     fn get_key_id(&self, conn: &PgConnection) -> String; | ||||
|     
 | ||||
|     /// Sign some data with the signer keypair
 | ||||
|     fn sign(&self, to_sign: String) -> String; // Base64.strict_encode64(creator.keypair.sign(OpenSSL::Digest::SHA256.new, to_be_signed))
 | ||||
|     fn sign(&self, to_sign: String) -> Vec<u8>; | ||||
| } | ||||
| 
 | ||||
| pub trait Signable { | ||||
|     fn sign<T>(&mut self, creator: T) -> &mut Self where T: Signer; | ||||
|     fn sign<T>(&mut self, creator: T, conn: &PgConnection) -> &mut Self where T: Signer; | ||||
| 
 | ||||
|     fn hash(data: String) -> String { | ||||
|         let bytes = data.into_bytes(); | ||||
| @ -23,15 +22,18 @@ pub trait Signable { | ||||
| } | ||||
| 
 | ||||
| impl Signable for serde_json::Value { | ||||
|     fn sign<T>(&mut self, creator: T) -> &mut serde_json::Value where T: Signer { | ||||
|     fn sign<T: Signer>(&mut self, creator: T, conn: &PgConnection) -> &mut serde_json::Value { | ||||
|         let creation_date = Utc::now().to_rfc3339(); | ||||
|         let mut options = json!({ | ||||
|             "type": "RsaSignature2017", | ||||
|             "creator": creator.get_key_id(), // [ActivityPub::TagManager.instance.uri_for(creator), '#main-key'].join,
 | ||||
|             "created": Utc::now().to_rfc3339() | ||||
|             "creator": creator.get_key_id(conn), | ||||
|             "created": creation_date | ||||
|         }); | ||||
| 
 | ||||
|         //options_hash  = hash(options.without('type', 'id', 'signatureValue').merge('@context' => CONTEXT))
 | ||||
|         let options_hash = Self::hash(String::from("")); | ||||
|         let options_hash  = Self::hash(json!({ | ||||
|             "@context": "https://w3id.org/identity/v1", | ||||
|             "created": creation_date | ||||
|         }).to_string()); | ||||
|         let document_hash = Self::hash(self.to_string()); | ||||
|         let to_be_signed = options_hash + &document_hash; | ||||
| 
 | ||||
|  | ||||
| @ -2,6 +2,10 @@ use bcrypt; | ||||
| use chrono::NaiveDateTime; | ||||
| use diesel::{self, QueryDsl, RunQueryDsl, ExpressionMethods, BelongingToDsl, PgConnection}; | ||||
| use diesel::dsl::any; | ||||
| use openssl::hash::MessageDigest; | ||||
| use openssl::pkey::{PKey, Private}; | ||||
| use openssl::rsa::Rsa; | ||||
| use openssl::sign::Signer; | ||||
| use reqwest::Client; | ||||
| use reqwest::header::{Accept, qitem}; | ||||
| use reqwest::mime::Mime; | ||||
| @ -16,6 +20,7 @@ use activity_pub::activity::{Create, Activity}; | ||||
| use activity_pub::actor::{ActorType, Actor}; | ||||
| use activity_pub::inbox::Inbox; | ||||
| use activity_pub::outbox::Outbox; | ||||
| use activity_pub::sign; | ||||
| use activity_pub::webfinger::{Webfinger, resolve}; | ||||
| use db_conn::DbConn; | ||||
| use models::follows::Follow; | ||||
| @ -39,7 +44,9 @@ pub struct User { | ||||
|     pub hashed_password: Option<String>, | ||||
|     pub instance_id: i32, | ||||
|     pub creation_date: NaiveDateTime, | ||||
|     pub ap_url: String | ||||
|     pub ap_url: String, | ||||
|     pub private_key: Option<String>, | ||||
|     pub public_key: String     | ||||
| } | ||||
| 
 | ||||
| #[derive(Insertable)] | ||||
| @ -54,7 +61,9 @@ pub struct NewUser { | ||||
|     pub email: Option<String>, | ||||
|     pub hashed_password: Option<String>, | ||||
|     pub instance_id: i32, | ||||
|     pub ap_url: String | ||||
|     pub ap_url: String, | ||||
|     pub private_key: Option<String>, | ||||
|     pub public_key: String     | ||||
| } | ||||
| 
 | ||||
| impl User { | ||||
| @ -153,7 +162,9 @@ impl User { | ||||
|             email: None, | ||||
|             hashed_password: None, | ||||
|             instance_id: instance.id, | ||||
|             ap_url: acct["id"].as_str().unwrap().to_string() | ||||
|             ap_url: acct["id"].as_str().unwrap().to_string(), | ||||
|             public_key: acct["publicKey"]["publicKeyPem"].as_str().unwrap().to_string(), | ||||
|             private_key: None | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
| @ -208,6 +219,10 @@ impl User { | ||||
|         let follows = follows::table.filter(follows::follower_id.eq(self.id)).select(follows::following_id); | ||||
|         users::table.filter(users::id.eq(any(follows))).load::<User>(conn).unwrap() | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_keypair(&self) -> PKey<Private> { | ||||
|         PKey::from_rsa(Rsa::private_key_from_pem(self.private_key.clone().unwrap().as_ref()).unwrap()).unwrap() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<'a, 'r> FromRequest<'a, 'r> for User { | ||||
| @ -303,6 +318,19 @@ impl Webfinger for User { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl sign::Signer for User { | ||||
|     fn get_key_id(&self, conn: &PgConnection) -> String { | ||||
|         format!("{}#main-key", self.compute_id(conn)) | ||||
|     } | ||||
| 
 | ||||
|     fn sign(&self, to_sign: String) -> Vec<u8> { | ||||
|         let key = self.get_keypair(); | ||||
|         let mut signer = Signer::new(MessageDigest::sha256(), &key).unwrap(); | ||||
|         signer.update(to_sign.as_bytes()).unwrap(); | ||||
|         signer.sign_to_vec().unwrap() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl NewUser { | ||||
|     /// Creates a new local user
 | ||||
|     pub fn new_local( | ||||
| @ -314,6 +342,7 @@ impl NewUser { | ||||
|         password: String, | ||||
|         instance_id: i32 | ||||
|     ) -> NewUser { | ||||
|         let (pub_key, priv_key) = NewUser::gen_keypair(); | ||||
|         NewUser { | ||||
|             username: username, | ||||
|             display_name: display_name, | ||||
| @ -324,7 +353,16 @@ impl NewUser { | ||||
|             email: Some(email), | ||||
|             hashed_password: Some(password), | ||||
|             instance_id: instance_id, | ||||
|             ap_url: String::from("") | ||||
|             ap_url: String::from(""), | ||||
|             public_key: String::from_utf8(pub_key).unwrap(), | ||||
|             private_key: Some(String::from_utf8(priv_key).unwrap()) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Returns (public key, private key)
 | ||||
|     fn gen_keypair() -> (Vec<u8>, Vec<u8>) { | ||||
|         let keypair = Rsa::generate(2048).unwrap(); | ||||
|         let keypair = PKey::from_rsa(keypair).unwrap(); | ||||
|         (keypair.public_key_to_pem().unwrap(), keypair.private_key_to_pem_pkcs8().unwrap()) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -75,6 +75,8 @@ table! { | ||||
|         instance_id -> Int4, | ||||
|         creation_date -> Timestamp, | ||||
|         ap_url -> Text, | ||||
|         private_key -> Nullable<Text>, | ||||
|         public_key -> Text, | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user