From 040b28f35a7b9a17f37b4fdaa273fedd3a8dddea Mon Sep 17 00:00:00 2001
From: Yeastplume <yeastplume@protonmail.com>
Date: Mon, 15 Jun 2020 14:39:52 +0100
Subject: [PATCH] rework decode_slatepack function to accept decryption key
 indices (#445)

---
 api/src/owner.rs                | 20 ++++++++++++-----
 api/src/owner_rpc.rs            | 19 +++++++++++-----
 controller/src/command.rs       |  7 +++---
 controller/tests/slatepack.rs   |  2 +-
 libwallet/src/api_impl/owner.rs | 40 +++++++++++++++++++++++++++++++--
 5 files changed, 72 insertions(+), 16 deletions(-)

diff --git a/api/src/owner.rs b/api/src/owner.rs
index 92119b5e..13726946 100644
--- a/api/src/owner.rs
+++ b/api/src/owner.rs
@@ -2117,13 +2117,16 @@ where
 	}
 
 	/// Decode an armored slatepack, returning a Slatepack object that can be
-	/// viewed, manipulated, output as json, etc
+	/// viewed, manipulated, output as json, etc. The resulting slatepack will be
+	/// decrypted by this wallet if possible
 	///
 	/// # Arguments
 	///
 	/// * `keychain_mask` - Wallet secret mask to XOR against the stored wallet seed before using
 	/// * `slatepack` - A string representing an armored slatepack
-	/// * `decrypt` - If true and the slatepack message content is encrypted, attempt to decrypt
+	/// * `secret_indices` - Indices along this wallet's deriviation path with which to attempt
+	/// decryption. If this wallet can't decrypt this slatepack, the payload of the returned
+	/// Slatepack will remain encrypted.
 	///
 	/// # Returns
 	/// * Ok with a [Slatepack](../grin_wallet_libwallet/slatepack/types/struct.Slatepack.html) if successful
@@ -2143,18 +2146,25 @@ where
 	/// # let slatepack_string = String::from("");
 	/// // .. receive a slatepack from somewhere
 	/// let res = api_owner.decode_slatepack_message(
+	///    None,
 	///    slatepack_string,
-	///    false,
+	///    vec![0, 1, 2],
 	/// );
 	///
 	/// ```
 
 	pub fn decode_slatepack_message(
 		&self,
+		keychain_mask: Option<&SecretKey>,
 		slatepack: String,
-		decrypt: bool,
+		secret_indices: Vec<u32>,
 	) -> Result<Slatepack, Error> {
-		owner::decode_slatepack_message(slatepack, decrypt)
+		owner::decode_slatepack_message(
+			self.wallet_inst.clone(),
+			keychain_mask,
+			slatepack,
+			secret_indices,
+		)
 	}
 
 	// PAYMENT PROOFS
diff --git a/api/src/owner_rpc.rs b/api/src/owner_rpc.rs
index 2ff1373f..dbcb3829 100644
--- a/api/src/owner_rpc.rs
+++ b/api/src/owner_rpc.rs
@@ -1577,8 +1577,9 @@ pub trait OwnerRpc {
 		"jsonrpc": "2.0",
 		"method": "decode_slatepack_message",
 		"params": {
-			"message": "BEGINSLATEPACK. t9EcGgrKr1GFCQB SK2jPCxME6Hgpqx bntpQm3zKFycoPY nW4UeoL4KQ7ExNK At6EQsvpz6MjUs8 6WG8KHEbMfqufJQ ZJTw2gkcdJmJjiJ f29oGgYqqXDZox4 ujPSjrtoxCN4h3e i1sZ8dYsm3dPeXL 7VQLsYNjAefciqj ZJXPm4Pqd7VDdd4 okGBGBu3YJvYzT6 arAxeCEx66us31h AJLcDweFwyWBkW5 J1DLiYAjt5ftFTo CjpfW9KjiLq2LM5 jepXWEHJPSDAYVK 4macDZUhRbJiG6E hrQcPrJBVC716mb Hw5E1PFrE6on5wq oEmrS4j9vaB5nw8 Z9ZyXvPc2LN7tER yt6pSHZeY9EpYdY zv4bthzfRfF8ePT TMeMpV2gpgyRXQa CPD2TR. ENDSLATEPACK.\n",
-			"decrypt" : false
+			"token": "d202964900000000d302964900000000d402964900000000d502964900000000",
+			"secret_indices": [0],
+			"message": "BEGINSLATEPACK. t9EcGgrKr1GFCQB SK2jPCxME6Hgpqx bntpQm3zKFycoPY nW4UeoL4KQ7ExNK At6EQsvpz6MjUs8 6WG8KHEbMfqufJQ ZJTw2gkcdJmJjiJ f29oGgYqqXDZox4 ujPSjrtoxCN4h3e i1sZ8dYsm3dPeXL 7VQLsYNjAefciqj ZJXPm4Pqd7VDdd4 okGBGBu3YJvYzT6 arAxeCEx66us31h AJLcDweFwyWBkW5 J1DLiYAjt5ftFTo CjpfW9KjiLq2LM5 jepXWEHJPSDAYVK 4macDZUhRbJiG6E hrQcPrJBVC716mb Hw5E1PFrE6on5wq oEmrS4j9vaB5nw8 Z9ZyXvPc2LN7tER yt6pSHZeY9EpYdY zv4bthzfRfF8ePT TMeMpV2gpgyRXQa CPD2TR. ENDSLATEPACK.\n"
 		},
 		"id": 1
 	}
@@ -1604,8 +1605,9 @@ pub trait OwnerRpc {
 
 	fn decode_slatepack_message(
 		&self,
+		token: Token,
 		message: String,
-		decrypt: bool,
+		secret_indices: Vec<u32>,
 	) -> Result<Slatepack, ErrorKind>;
 
 	/**
@@ -2077,10 +2079,17 @@ where
 
 	fn decode_slatepack_message(
 		&self,
+		token: Token,
 		message: String,
-		decrypt: bool,
+		secret_indices: Vec<u32>,
 	) -> Result<Slatepack, ErrorKind> {
-		Owner::decode_slatepack_message(self, message, decrypt).map_err(|e| e.kind())
+		Owner::decode_slatepack_message(
+			self,
+			(&token.keychain_mask).as_ref(),
+			message,
+			secret_indices,
+		)
+		.map_err(|e| e.kind())
 	}
 
 	fn retrieve_payment_proof(
diff --git a/controller/src/command.rs b/controller/src/command.rs
index ba6579a4..59299f0e 100644
--- a/controller/src/command.rs
+++ b/controller/src/command.rs
@@ -626,7 +626,8 @@ where
 						|api, m| {
 							slate =
 								api.slate_from_slatepack_message(m, message.clone(), vec![0])?;
-							let slatepack = api.decode_slatepack_message(message, true)?;
+							let slatepack =
+								api.decode_slatepack_message(m, message.clone(), vec![0])?;
 							ret_address = slatepack.sender;
 							Ok(())
 						},
@@ -735,8 +736,8 @@ where
 		None => match args.input_slatepack_message {
 			Some(mes) => {
 				let mut sp = Slatepack::default();
-				controller::owner_single_use(None, keychain_mask, Some(owner_api), |api, _| {
-					sp = api.decode_slatepack_message(mes, false)?;
+				controller::owner_single_use(None, keychain_mask, Some(owner_api), |api, m| {
+					sp = api.decode_slatepack_message(m, mes, vec![])?;
 					Ok(())
 				})?;
 				sp
diff --git a/controller/tests/slatepack.rs b/controller/tests/slatepack.rs
index bc7c8cc5..4dc06a50 100644
--- a/controller/tests/slatepack.rs
+++ b/controller/tests/slatepack.rs
@@ -496,7 +496,7 @@ fn slatepack_api_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
 		let enc_addr = api.get_slatepack_address(m, 0)?;
 		let slatepack = api.create_slatepack_message(m, &slate, Some(0), vec![enc_addr])?;
 		println!("{}", slatepack);
-		let slatepack_raw = api.decode_slatepack_message(slatepack.clone(), true)?;
+		let slatepack_raw = api.decode_slatepack_message(m, slatepack.clone(), vec![0])?;
 		println!("{}", slatepack_raw);
 		let decoded_slate = api.slate_from_slatepack_message(m, slatepack, vec![0])?;
 		println!("{}", decoded_slate);
diff --git a/libwallet/src/api_impl/owner.rs b/libwallet/src/api_impl/owner.rs
index aaa41f7a..b327c051 100644
--- a/libwallet/src/api_impl/owner.rs
+++ b/libwallet/src/api_impl/owner.rs
@@ -201,13 +201,49 @@ where
 }
 
 /// Decode a slatepack message, to allow viewing
-pub fn decode_slatepack_message(slatepack: String, decrypt: bool) -> Result<Slatepack, Error> {
+/// Will decrypt if possible, otherwise will return
+/// undecrypted slatepack
+pub fn decode_slatepack_message<'a, L, C, K>(
+	wallet_inst: Arc<Mutex<Box<dyn WalletInst<'a, L, C, K>>>>,
+	keychain_mask: Option<&SecretKey>,
+	slatepack: String,
+	secret_indices: Vec<u32>,
+) -> Result<Slatepack, Error>
+where
+	L: WalletLCProvider<'a, C, K>,
+	C: NodeClient + 'a,
+	K: Keychain + 'a,
+{
 	let packer = Slatepacker::new(SlatepackerArgs {
 		sender: None,
 		recipients: vec![],
 		dec_key: None,
 	});
-	packer.deser_slatepack(slatepack.as_bytes().to_vec(), decrypt)
+	if secret_indices.is_empty() {
+		packer.deser_slatepack(slatepack.as_bytes().to_vec(), false)
+	} else {
+		for index in secret_indices {
+			let dec_key = Some(get_slatepack_secret_key(
+				wallet_inst.clone(),
+				keychain_mask,
+				index,
+			)?);
+			let packer = Slatepacker::new(SlatepackerArgs {
+				sender: None,
+				recipients: vec![],
+				dec_key: (&dec_key).as_ref(),
+			});
+			let res = packer.deser_slatepack(slatepack.as_bytes().to_vec(), true);
+			let slatepack = match res {
+				Ok(sp) => sp,
+				Err(_) => {
+					continue;
+				}
+			};
+			return Ok(slatepack);
+		}
+		packer.deser_slatepack(slatepack.as_bytes().to_vec(), false)
+	}
 }
 
 /// retrieve outputs