Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add unpack command #433

Merged
merged 1 commit into from
Jun 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions api/src/owner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2123,6 +2123,7 @@ where
///
/// * `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
///
/// # Returns
/// * Ok with a [Slatepack](../grin_wallet_libwallet/slatepack/types/struct.Slatepack.html) if successful
Expand All @@ -2142,13 +2143,18 @@ where
/// # let slatepack_string = String::from("");
/// // .. receive a slatepack from somewhere
/// let res = api_owner.decode_slatepack_message(
/// slatepack_string
/// slatepack_string,
/// false,
/// );
///
/// ```

pub fn decode_slatepack_message(&self, slatepack: String) -> Result<Slatepack, Error> {
owner::decode_slatepack_message(slatepack)
pub fn decode_slatepack_message(
&self,
slatepack: String,
decrypt: bool,
) -> Result<Slatepack, Error> {
owner::decode_slatepack_message(slatepack, decrypt)
}

// PAYMENT PROOFS
Expand Down
17 changes: 13 additions & 4 deletions api/src/owner_rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1577,7 +1577,8 @@ pub trait OwnerRpc {
"jsonrpc": "2.0",
"method": "decode_slatepack_message",
"params": {
"message": "BEGINSLATEPACK. 8GQrdcwdLKJD28F 3a9siP7ZhZgAh7w\nBR2EiZHza5WMWmZ Cc8zBUemrrYRjhq j3VBwA8vYnvXXKU\nBDmQBN2yKgmR8mX UzvXHezfznA61d7 qFZYChhz94vd8Ew\nNEPLz7jmcVN2C3w wrfHbeiLubYozP2 uhLouFiYRrbe3fQ\n4uhWGfT3sQYXScT dAeo29EaZJpfauh j8VL5jsxST2SPHq\nnzXFC2w9yYVjt7D ju7GSgHEp5aHz9R xstGbHjbsb4JQod\nkYLuELta1ohUwDD pvjhyJmsbLcsPei k5AQhZsJ8RJGBtY\nbou6cU7tZeFJvor 4LB9CBfFB3pmVWD vSLd5RPS75dcnHP\nnbXD8mSDZ8hJS2Q A9wgvppWzuWztJ2 dLUU8f9tLJgsRBw\nYZAs71HiVeg7. ENDSLATEPACK.\n"
"message": "BEGINSLATEPACK. 8GQrdcwdLKJD28F 3a9siP7ZhZgAh7w\nBR2EiZHza5WMWmZ Cc8zBUemrrYRjhq j3VBwA8vYnvXXKU\nBDmQBN2yKgmR8mX UzvXHezfznA61d7 qFZYChhz94vd8Ew\nNEPLz7jmcVN2C3w wrfHbeiLubYozP2 uhLouFiYRrbe3fQ\n4uhWGfT3sQYXScT dAeo29EaZJpfauh j8VL5jsxST2SPHq\nnzXFC2w9yYVjt7D ju7GSgHEp5aHz9R xstGbHjbsb4JQod\nkYLuELta1ohUwDD pvjhyJmsbLcsPei k5AQhZsJ8RJGBtY\nbou6cU7tZeFJvor 4LB9CBfFB3pmVWD vSLd5RPS75dcnHP\nnbXD8mSDZ8hJS2Q A9wgvppWzuWztJ2 dLUU8f9tLJgsRBw\nYZAs71HiVeg7. ENDSLATEPACK.\n",
"decrypt" : false
},
"id": 1
}
Expand All @@ -1601,7 +1602,11 @@ pub trait OwnerRpc {
```
*/

fn decode_slatepack_message(&self, message: String) -> Result<Slatepack, ErrorKind>;
fn decode_slatepack_message(
&self,
message: String,
decrypt: bool,
) -> Result<Slatepack, ErrorKind>;

/**
Networked version of [Owner::retrieve_payment_proof](struct.Owner.html#method.retrieve_payment_proof).
Expand Down Expand Up @@ -2069,8 +2074,12 @@ where
Ok(VersionedSlate::into_version(slate, version).map_err(|e| e.kind())?)
}

fn decode_slatepack_message(&self, message: String) -> Result<Slatepack, ErrorKind> {
Owner::decode_slatepack_message(self, message).map_err(|e| e.kind())
fn decode_slatepack_message(
&self,
message: String,
decrypt: bool,
) -> Result<Slatepack, ErrorKind> {
Owner::decode_slatepack_message(self, message, decrypt).map_err(|e| e.kind())
}

fn retrieve_payment_proof(
Expand Down
84 changes: 81 additions & 3 deletions controller/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use crate::impls::SlateGetter as _;
use crate::impls::{HttpSlateSender, PathToSlate, PathToSlatepack, SlatePutter};
use crate::keychain;
use crate::libwallet::{
self, InitTxArgs, IssueInvoiceTxArgs, NodeClient, PaymentProof, Slate, SlateVersion,
self, InitTxArgs, IssueInvoiceTxArgs, NodeClient, PaymentProof, Slate, SlateVersion, Slatepack,
SlatepackAddress, Slatepacker, SlatepackerArgs, WalletLCProvider,
};
use crate::util::secp::key::SecretKey;
Expand Down Expand Up @@ -603,7 +603,7 @@ where
});
let pts = PathToSlatepack::new(f.into(), &packer, true);
sl = Some(pts.get_tx()?.0);
ret_address = pts.get_slatepack()?.sender;
ret_address = pts.get_slatepack(true)?.sender;
Ok(())
})?;
}
Expand All @@ -626,7 +626,7 @@ where
|api, m| {
slate =
api.slate_from_slatepack_message(m, message.clone(), vec![0])?;
let slatepack = api.decode_slatepack_message(message)?;
let slatepack = api.decode_slatepack_message(message, true)?;
ret_address = slatepack.sender;
Ok(())
},
Expand Down Expand Up @@ -713,6 +713,84 @@ where
}
}

pub fn unpack<L, C, K>(
owner_api: &mut Owner<L, C, K>,
keychain_mask: Option<&SecretKey>,
args: ReceiveArgs,
) -> Result<(), Error>
where
L: WalletLCProvider<'static, C, K> + 'static,
C: NodeClient + 'static,
K: keychain::Keychain + 'static,
{
let mut slatepack = match args.input_file {
Some(f) => {
let packer = Slatepacker::new(SlatepackerArgs {
sender: None,
recipients: vec![],
dec_key: None,
});
PathToSlatepack::new(f.into(), &packer, true).get_slatepack(false)?
}
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)?;
Ok(())
})?;
sp
}
None => {
return Err(ErrorKind::ArgumentError("Invalid Slatepack Input".into()).into());
}
},
};
println!();
println!("SLATEPACK CONTENTS");
println!("------------------");
println!("{}", slatepack);
println!("------------------");

let packer = Slatepacker::new(SlatepackerArgs {
sender: None,
recipients: vec![],
dec_key: None,
});

if slatepack.mode == 1 {
controller::owner_single_use(None, keychain_mask, Some(owner_api), |api, m| {
let dec_key = api.get_slatepack_secret_key(m, 0)?;
match slatepack.try_decrypt_payload(Some(&dec_key)) {
Ok(_) => {
println!("Slatepack is encrypted for this wallet");
println!();
println!("DECRYPTED SLATEPACK");
println!("-------------------");
println!("{}", slatepack);
let slate = packer.get_slate(&slatepack)?;
println!();
println!("DECRYPTED SLATE");
println!("---------------");
println!("{}", slate);
}
Err(_) => {
println!("Slatepack payload cannot be decrypted by this wallet");
}
}
Ok(())
})?;
} else {
let slate = packer.get_slate(&slatepack)?;
println!("Slatepack is not encrypted");
println!();
println!("SLATE");
println!("-----");
println!("{}", slate);
}
Ok(())
}

/// Finalize command args
#[derive(Clone)]
pub struct FinalizeArgs {
Expand Down
4 changes: 2 additions & 2 deletions controller/tests/slatepack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ fn slate_from_packed(
if armored {
file = format!("{}.armored", file);
}
let slatepack = PathToSlatepack::new(file.into(), &packer, armored).get_slatepack()?;
let slatepack = PathToSlatepack::new(file.into(), &packer, armored).get_slatepack(true)?;
Ok((slatepack.clone(), packer.get_slate(&slatepack)?))
}

Expand Down Expand Up @@ -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())?;
let slatepack_raw = api.decode_slatepack_message(slatepack.clone(), true)?;
println!("{}", slatepack_raw);
let decoded_slate = api.slate_from_slatepack_message(m, slatepack, vec![0])?;
println!("{}", decoded_slate);
Expand Down
6 changes: 3 additions & 3 deletions impls/src/adapters/slatepack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ impl<'a> PathToSlatepack<'a> {
Ok(data)
}

pub fn get_slatepack(&self) -> Result<Slatepack, Error> {
pub fn get_slatepack(&self, decrypt: bool) -> Result<Slatepack, Error> {
let data = self.get_slatepack_file_contents()?;
self.packer.deser_slatepack(data)
self.packer.deser_slatepack(data, decrypt)
}
}

Expand Down Expand Up @@ -80,7 +80,7 @@ impl<'a> SlatePutter for PathToSlatepack<'a> {
impl<'a> SlateGetter for PathToSlatepack<'a> {
fn get_tx(&self) -> Result<(Slate, bool), Error> {
let data = self.get_slatepack_file_contents()?;
let slatepack = self.packer.deser_slatepack(data)?;
let slatepack = self.packer.deser_slatepack(data, true)?;
Ok((self.packer.get_slate(&slatepack)?, true))
}
}
8 changes: 4 additions & 4 deletions libwallet/src/api_impl/owner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ where
recipients: vec![],
dec_key: None,
});
let slatepack = packer.deser_slatepack(slatepack.as_bytes().to_vec())?;
let slatepack = packer.deser_slatepack(slatepack.as_bytes().to_vec(), true)?;
return packer.get_slate(&slatepack);
} else {
for index in secret_indices {
Expand All @@ -183,7 +183,7 @@ where
recipients: vec![],
dec_key: (&dec_key).as_ref(),
});
let res = packer.deser_slatepack(slatepack.as_bytes().to_vec());
let res = packer.deser_slatepack(slatepack.as_bytes().to_vec(), true);
let slatepack = match res {
Ok(sp) => sp,
Err(_) => {
Expand All @@ -201,13 +201,13 @@ where
}

/// Decode a slatepack message, to allow viewing
pub fn decode_slatepack_message(slatepack: String) -> Result<Slatepack, Error> {
pub fn decode_slatepack_message(slatepack: String, decrypt: bool) -> Result<Slatepack, Error> {
let packer = Slatepacker::new(SlatepackerArgs {
sender: None,
recipients: vec![],
dec_key: None,
});
packer.deser_slatepack(slatepack.as_bytes().to_vec())
packer.deser_slatepack(slatepack.as_bytes().to_vec(), decrypt)
}

/// retrieve outputs
Expand Down
6 changes: 4 additions & 2 deletions libwallet/src/slatepack/packer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ impl<'a> Slatepacker<'a> {
}

/// return slatepack
pub fn deser_slatepack(&self, data: Vec<u8>) -> Result<Slatepack, Error> {
pub fn deser_slatepack(&self, data: Vec<u8>, decrypt: bool) -> Result<Slatepack, Error> {
// check if data is armored, if so, remove and continue
if data.len() < super::armor::HEADER.len() {
let msg = format!("Data too short");
Expand Down Expand Up @@ -90,7 +90,9 @@ impl<'a> Slatepacker<'a> {
};

slatepack.ver_check_warn();
slatepack.try_decrypt_payload(self.0.dec_key)?;
if decrypt {
slatepack.try_decrypt_payload(self.0.dec_key)?;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand correctly when calling the unpack API with decrypt true and if the slatepack is not encrypted that will fail?
Why not:

  1. Try to decrypt by default without failing in a specific context.
  2. Do not return an error when unpacking with true and simply failover false case.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nevermind missed

	pub fn try_decrypt_payload(&mut self, dec_key: Option<&edSecretKey>) -> Result<(), Error> {
		if self.mode == 0 {
			return Ok(());
		}

}
Ok(slatepack)
}

Expand Down
26 changes: 17 additions & 9 deletions src/bin/grin-wallet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ subcommands:
long: run_foreign
takes_value: false
- send:
about: Builds a transaction to send coins and sends to the specified listener directly
about: Builds a transaction to send coins and sends to the recipient via the Slatepack workflow
args:
- amount:
help: Number of coins to send with optional fraction, e.g. 12.423
Expand Down Expand Up @@ -119,7 +119,7 @@ subcommands:
default_value: "1"
takes_value: true
- dest:
help: Send the transaction to the provided server (start with http://) or save as file.
help: Intended recipient's Slatepack Address (or http listener address (DEPRECATED))
short: d
long: dest
takes_value: true
Expand All @@ -146,16 +146,24 @@ subcommands:
help: Output a V4 slate prior to HF3 block
long: v4
takes_value: false
- unpack:
about: Unpack and display an armored Slatepack Message, decrypting if possible
args:
- input:
help: File containing a Slatepack Message
short: i
long: input
takes_value: true
- receive:
about: Processes a transaction file to accept a transfer from a sender
about: Processes a Slatepack Message to accept a transfer from a sender
args:
- input:
help: Partial transaction to process, expects the sender's transaction file.
help: File containing a Slatepack Message
short: i
long: input
takes_value: true
- finalize:
about: Processes a receiver's transaction file to finalize a transfer.
about: Processes a Slatepack Message to finalize a transfer.
args:
- input:
help: Partial transaction to process, expects the receiver's transaction file.
Expand All @@ -171,13 +179,13 @@ subcommands:
short: n
long: nopost
- invoice:
about: Initialize an invoice transaction.
about: Initialize an invoice transaction, outputting a Slatepack Message with the result
args:
- amount:
help: Number of coins to invoice with optional fraction, e.g. 12.423
index: 1
- dest:
help: Name of destination slate output file
help: Intended recipient's Slatepack Address
short: d
long: dest
takes_value: true
Expand Down Expand Up @@ -209,12 +217,12 @@ subcommands:
short: e
long: estimate-selection
- dest:
help: Send the transaction to the provided server (start with http://) or save as file.
help: The Slatepack address of the invoicing party's wallet (will override the address contained in the Slatepack)
short: d
long: dest
takes_value: true
- input:
help: Partial transaction to process, expects the invoicer's transaction file.
help: Incoming Slatepack Message to process
short: i
long: input
takes_value: true
Expand Down
30 changes: 30 additions & 0 deletions src/cmd/wallet_args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,32 @@ pub fn parse_receive_args(args: &ArgMatches) -> Result<command::ReceiveArgs, Par
})
}

pub fn parse_unpack_args(args: &ArgMatches) -> Result<command::ReceiveArgs, ParseError> {
// input file
let input_file = match args.is_present("input") {
true => {
let file = args.value_of("input").unwrap().to_owned();
// validate input
if !Path::new(&file).is_file() {
let msg = format!("File {} not found.", &file);
return Err(ParseError::ArgumentError(msg));
}
Some(file)
}
false => None,
};

let mut input_slatepack_message = None;
if input_file.is_none() {
input_slatepack_message = Some(prompt_slatepack()?);
}

Ok(command::ReceiveArgs {
input_file,
input_slatepack_message,
})
}

pub fn parse_finalize_args(args: &ArgMatches) -> Result<command::FinalizeArgs, ParseError> {
let fluff = args.is_present("fluff");
let nopost = args.is_present("nopost");
Expand Down Expand Up @@ -1134,6 +1160,10 @@ where
test_mode,
)
}
("unpack", Some(args)) => {
let a = arg_parse!(parse_unpack_args(&args));
command::unpack(owner_api, km, a)
}
("finalize", Some(args)) => {
let a = arg_parse!(parse_finalize_args(&args));
command::finalize(owner_api, km, a)
Expand Down