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

[WIP] Server authentication in transactions #186

Closed
wants to merge 12 commits into from
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 9 additions & 10 deletions api/src/owner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use std::sync::Arc;
use uuid::Uuid;

use crate::core::core::Transaction;
use crate::impls::{HTTPWalletCommAdapter, KeybaseWalletCommAdapter};
use crate::impls::create_sender;
use crate::keychain::{Identifier, Keychain};
use crate::libwallet::api_impl::owner;
use crate::libwallet::{
Expand Down Expand Up @@ -498,21 +498,20 @@ where
// Helper functionality. If send arguments exist, attempt to send
match send_args {
Some(sa) => {
//TODO: in case of keybase, the response might take 60s and leave the service hanging
match sa.method.as_ref() {
"http" => {
slate = HTTPWalletCommAdapter::new().send_tx_sync(&sa.dest, &slate)?
}
"keybase" => {
//TODO: in case of keybase, the response might take 60s and leave the service hanging
slate = KeybaseWalletCommAdapter::new().send_tx_sync(&sa.dest, &slate)?;
}
"http" | "keybase" => {}
_ => {
error!("unsupported payment method: {}", sa.method);
return Err(ErrorKind::ClientCallback(
"unsupported payment method".to_owned(),
))?;
)
.into());
}
}
};
let comm_adapter = create_sender(&sa.method, &sa.dest)
.map_err(|e| ErrorKind::GenericError(format!("{}", e)))?;
slate = comm_adapter.send_tx(&slate)?;
self.tx_lock_outputs(&slate, 0)?;
let slate = match sa.finalize {
true => self.finalize_tx(&slate)?,
Expand Down
170 changes: 77 additions & 93 deletions controller/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,31 +12,28 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::util::{Mutex, ZeroingString};
use std::collections::HashMap;
/// Grin wallet command-line function implementations
use std::fs::File;
use std::io::Write;
use std::sync::Arc;
use std::thread;
use std::time::Duration;

use serde_json as json;
use uuid::Uuid;
//! Grin wallet command-line function implementations

use crate::api::TLSConfig;
use crate::core::core;
use crate::keychain;

use crate::config::WalletConfig;
use crate::core::core;
use crate::error::{Error, ErrorKind};
use crate::impls::{
instantiate_wallet, FileWalletCommAdapter, HTTPWalletCommAdapter, KeybaseWalletCommAdapter,
LMDBBackend, NullWalletCommAdapter,
create_sender, HTTPNodeClient, KeybaseAllChannels, SlateGetter as _, SlateReceiver as _,
WalletSeed,
};
use crate::impls::{HTTPNodeClient, WalletSeed};
use crate::impls::{instantiate_wallet, LMDBBackend, PathToSlate, SlatePutter};
use crate::keychain;
use crate::libwallet::{InitTxArgs, IssueInvoiceTxArgs, NodeClient, WalletInst};
use crate::util::{Mutex, ZeroingString};
use crate::{controller, display};
use serde_json as json;
use std::fs::File;
use std::io::Write;
use std::sync::Arc;
use std::thread;
use std::time::Duration;
use uuid::Uuid;

/// Arguments common to all wallet commands
#[derive(Clone)]
Expand Down Expand Up @@ -116,12 +113,6 @@ pub struct ListenArgs {
}

pub fn listen(config: &WalletConfig, args: &ListenArgs, g_args: &GlobalArgs) -> Result<(), Error> {
let mut params = HashMap::new();
params.insert("api_listen_addr".to_owned(), config.api_listen_addr());
if let Some(t) = g_args.tls_conf.as_ref() {
params.insert("certificate".to_owned(), t.certificate.clone());
params.insert("private_key".to_owned(), t.private_key.clone());
}
let res = match args.method.as_str() {
"http" => {
// HTTP adapter can't use the listen trait method because of the
Expand All @@ -136,28 +127,24 @@ pub fn listen(config: &WalletConfig, args: &ListenArgs, g_args: &GlobalArgs) ->
&g_args.password.clone().unwrap(),
&g_args.account,
)?;
let listen_addr = params.get("api_listen_addr").unwrap();
let tls_conf = match params.get("certificate") {
Some(s) => Some(TLSConfig::new(
s.to_owned(),
params.get("private_key").unwrap().to_owned(),
)),
None => None,
};
controller::foreign_listener(wallet.clone(), &listen_addr, tls_conf)?;
Ok(())
}
"keybase" => {
let adapter = KeybaseWalletCommAdapter::new();
adapter.listen(
params,
config.clone(),
&g_args.password.clone().unwrap(),
&g_args.account,
g_args.node_api_secret.clone(),
controller::foreign_listener(
wallet.clone(),
&config.api_listen_addr(),
g_args.tls_conf.clone(),
)
}
_ => Ok(()),
"keybase" => KeybaseAllChannels::new()?.listen(
config.clone(),
&g_args.password.clone().unwrap(),
&g_args.account,
g_args.node_api_secret.clone(),
),
method => {
return Err(ErrorKind::ArgumentError(format!(
"No listener for method \"{}\".",
method
)).into());
}
};

if let Err(e) = res {
Expand Down Expand Up @@ -291,42 +278,41 @@ pub fn send(
return Err(e);
}
};
let adapter = match args.method.as_str() {
"http" => HTTPWalletCommAdapter::new(),
"file" => FileWalletCommAdapter::new(),
"keybase" => KeybaseWalletCommAdapter::new(),
"self" => NullWalletCommAdapter::new(),
_ => NullWalletCommAdapter::new(),
};
if adapter.supports_sync() {
slate = adapter.send_tx_sync(&args.dest, &slate)?;
api.tx_lock_outputs(&slate, 0)?;
if args.method == "self" {

match args.method.as_str() {
"file" => {
PathToSlate((&args.dest).into()).put_tx(&slate)?;
api.tx_lock_outputs(&slate, 0)?;
return Ok(());
}
"self" => {
api.tx_lock_outputs(&slate, 0)?;
controller::foreign_single_use(wallet, |api| {
slate = api.receive_tx(&slate, Some(&args.dest), None)?;
Ok(())
})?;
}
if let Err(e) = api.verify_slate_messages(&slate) {
error!("Error validating participant messages: {}", e);
return Err(e);
method => {
let sender = create_sender(method, &args.dest)?;
slate = sender.send_tx(&slate)?;
api.tx_lock_outputs(&slate, 0)?;
}
slate = api.finalize_tx(&slate)?;
} else {
adapter.send_tx_async(&args.dest, &slate)?;
api.tx_lock_outputs(&slate, 0)?;
}
if adapter.supports_sync() {
let result = api.post_tx(&slate.tx, args.fluff);
match result {
Ok(_) => {
info!("Tx sent ok",);
return Ok(());
}
Err(e) => {
error!("Tx sent fail: {}", e);
return Err(e);
}

api.verify_slate_messages(&slate).map_err(|e| {
error!("Error validating participant messages: {}", e);
e
})?;
slate = api.finalize_tx(&slate)?;
let result = api.post_tx(&slate.tx, args.fluff);
match result {
Ok(_) => {
info!("Tx sent ok",);
return Ok(());
}
Err(e) => {
error!("Tx sent fail: {}", e);
return Err(e);
}
}
}
Expand All @@ -346,8 +332,7 @@ pub fn receive(
g_args: &GlobalArgs,
args: ReceiveArgs,
) -> Result<(), Error> {
let adapter = FileWalletCommAdapter::new();
let mut slate = adapter.receive_tx_async(&args.input)?;
let mut slate = PathToSlate((&args.input).into()).get_tx()?;
controller::foreign_single_use(wallet, |api| {
if let Err(e) = api.verify_slate_messages(&slate) {
error!("Error validating participant messages: {}", e);
Expand All @@ -356,8 +341,7 @@ pub fn receive(
slate = api.receive_tx(&slate, Some(&g_args.account), args.message.clone())?;
Ok(())
})?;
let send_tx = format!("{}.response", args.input);
adapter.send_tx_async(&send_tx, &slate)?;
PathToSlate(format!("{}.response", args.input).into()).put_tx(&slate)?;
info!(
"Response file {}.response generated, and can be sent back to the transaction originator.",
args.input
Expand All @@ -375,8 +359,8 @@ pub fn finalize(
wallet: Arc<Mutex<WalletInst<impl NodeClient + 'static, keychain::ExtKeychain>>>,
args: FinalizeArgs,
) -> Result<(), Error> {
let adapter = FileWalletCommAdapter::new();
let mut slate = adapter.receive_tx_async(&args.input)?;
let mut slate = PathToSlate((&args.input).into()).get_tx()?;

// Rather than duplicating the entire command, we'll just
// try to determine what kind of finalization this is
// based on the slate contents
Expand Down Expand Up @@ -472,8 +456,7 @@ pub fn process_invoice(
args: ProcessInvoiceArgs,
dark_scheme: bool,
) -> Result<(), Error> {
let adapter = FileWalletCommAdapter::new();
let slate = adapter.receive_tx_async(&args.input)?;
let slate = PathToSlate((&args.input).into()).get_tx()?;
controller::owner_single_use(wallet.clone(), |api| {
if args.estimate_selection_strategies {
let strategies = vec!["smallest", "all"]
Expand Down Expand Up @@ -526,24 +509,25 @@ pub fn process_invoice(
return Err(e);
}
};
let adapter = match args.method.as_str() {
"http" => HTTPWalletCommAdapter::new(),
"file" => FileWalletCommAdapter::new(),
"self" => NullWalletCommAdapter::new(),
_ => NullWalletCommAdapter::new(),
};
if adapter.supports_sync() {
slate = adapter.send_tx_sync(&args.dest, &slate)?;
api.tx_lock_outputs(&slate, 0)?;
if args.method == "self" {

match args.method.as_str() {
"file" => {
let slate_putter = PathToSlate((&args.dest).into());
slate_putter.put_tx(&slate)?;
api.tx_lock_outputs(&slate, 0)?;
}
"self" => {
api.tx_lock_outputs(&slate, 0)?;
controller::foreign_single_use(wallet, |api| {
slate = api.finalize_invoice_tx(&slate)?;
Ok(())
})?;
}
} else {
adapter.send_tx_async(&args.dest, &slate)?;
api.tx_lock_outputs(&slate, 0)?;
method => {
let sender = create_sender(method, &args.dest)?;
slate = sender.send_tx(&slate)?;
api.tx_lock_outputs(&slate, 0)?;
}
}
}
Ok(())
Expand Down
5 changes: 2 additions & 3 deletions controller/tests/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use self::core::global::ChainTypes;
use self::keychain::ExtKeychain;
use grin_wallet_libwallet as libwallet;
use impls::test_framework::{self, LocalWalletClient, WalletProxy};
use impls::FileWalletCommAdapter;
use impls::{PathToSlate, SlateGetter as _, SlatePutter as _};
use libwallet::{InitTxArgs, WalletInst};
use std::fs;
use std::thread;
Expand Down Expand Up @@ -189,9 +189,8 @@ fn check_repair_impl(test_dir: &str) -> Result<(), libwallet::Error> {
};
let mut slate = api.init_send_tx(args)?;
// output tx file
let file_adapter = FileWalletCommAdapter::new();
let send_file = format!("{}/part_tx_1.tx", test_dir);
file_adapter.send_tx_async(&send_file, &mut slate)?;
PathToSlate(send_file.into()).put_tx(&slate)?;
api.tx_lock_outputs(&slate, 0)?;
Ok(())
})?;
Expand Down
13 changes: 5 additions & 8 deletions controller/tests/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use self::core::global::ChainTypes;
use self::keychain::ExtKeychain;
use grin_wallet_libwallet as libwallet;
use impls::test_framework::{self, LocalWalletClient, WalletProxy};
use impls::FileWalletCommAdapter;
use impls::{PathToSlate, SlateGetter as _, SlatePutter as _};
use std::fs;
use std::thread;
use std::time::Duration;
Expand Down Expand Up @@ -119,8 +119,7 @@ fn file_exchange_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
};
let mut slate = api.init_send_tx(args)?;
// output tx file
let file_adapter = FileWalletCommAdapter::new();
file_adapter.send_tx_async(&send_file, &mut slate)?;
PathToSlate((&send_file).into()).put_tx(&mut slate)?;
api.tx_lock_outputs(&slate, 0)?;
Ok(())
})?;
Expand All @@ -131,8 +130,7 @@ fn file_exchange_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
w.set_parent_key_id_by_name("account1")?;
}

let adapter = FileWalletCommAdapter::new();
let mut slate = adapter.receive_tx_async(&send_file)?;
let mut slate = PathToSlate((&send_file).into()).get_tx()?;
let mut naughty_slate = slate.clone();
naughty_slate.participant_data[0].message = Some("I changed the message".to_owned());

Expand All @@ -148,14 +146,13 @@ fn file_exchange_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
// wallet 2 receives file, completes, sends file back
wallet::controller::foreign_single_use(wallet2.clone(), |api| {
slate = api.receive_tx(&slate, None, Some(sender2_message.clone()))?;
adapter.send_tx_async(&receive_file, &mut slate)?;
PathToSlate((&receive_file).into()).put_tx(&slate)?;
Ok(())
})?;

// wallet 1 finalises and posts
wallet::controller::owner_single_use(wallet1.clone(), |api| {
let adapter = FileWalletCommAdapter::new();
let mut slate = adapter.receive_tx_async(&receive_file)?;
let mut slate = PathToSlate(receive_file.into()).get_tx()?;
api.verify_slate_messages(&slate)?;
slate = api.finalize_tx(&slate)?;
api.post_tx(&slate.tx, false)?;
Expand Down
Loading