diff --git a/api/src/auth.rs b/api/src/auth.rs index 3b00fa701..073c9374c 100644 --- a/api/src/auth.rs +++ b/api/src/auth.rs @@ -13,19 +13,25 @@ // limitations under the License. use crate::router::{Handler, HandlerObj, ResponseFuture}; +use crate::web::response; use futures::future::ok; use hyper::header::{HeaderValue, AUTHORIZATION, WWW_AUTHENTICATE}; use hyper::{Body, Request, Response, StatusCode}; use ring::constant_time::verify_slices_are_equal; +lazy_static! { + pub static ref GRIN_BASIC_REALM: HeaderValue = + HeaderValue::from_str("Basic realm=GrinAPI").unwrap(); +} + // Basic Authentication Middleware pub struct BasicAuthMiddleware { api_basic_auth: String, - basic_realm: String, + basic_realm: &'static HeaderValue, } impl BasicAuthMiddleware { - pub fn new(api_basic_auth: String, basic_realm: String) -> BasicAuthMiddleware { + pub fn new(api_basic_auth: String, basic_realm: &'static HeaderValue) -> BasicAuthMiddleware { BasicAuthMiddleware { api_basic_auth, basic_realm, @@ -39,8 +45,12 @@ impl Handler for BasicAuthMiddleware { req: Request, mut handlers: Box>, ) -> ResponseFuture { + let next_handler = match handlers.next() { + Some(h) => h, + None => return response(StatusCode::INTERNAL_SERVER_ERROR, "no handler found"), + }; if req.method().as_str() == "OPTIONS" { - return handlers.next().unwrap().call(req, handlers); + return next_handler.call(req, handlers); } if req.headers().contains_key(AUTHORIZATION) && verify_slices_are_equal( @@ -49,7 +59,7 @@ impl Handler for BasicAuthMiddleware { ) .is_ok() { - handlers.next().unwrap().call(req, handlers) + next_handler.call(req, handlers) } else { // Unauthorized 401 unauthorized_response(&self.basic_realm) @@ -57,13 +67,10 @@ impl Handler for BasicAuthMiddleware { } } -fn unauthorized_response(basic_realm: &str) -> ResponseFuture { +fn unauthorized_response(basic_realm: &HeaderValue) -> ResponseFuture { let response = Response::builder() .status(StatusCode::UNAUTHORIZED) - .header( - WWW_AUTHENTICATE, - HeaderValue::from_str(basic_realm).unwrap(), - ) + .header(WWW_AUTHENTICATE, basic_realm) .body(Body::empty()) .unwrap(); Box::new(ok(response)) diff --git a/api/src/client.rs b/api/src/client.rs index dd279c2f6..6415b31bd 100644 --- a/api/src/client.rs +++ b/api/src/client.rs @@ -136,9 +136,8 @@ fn build_request<'a>( .into() })?; let mut builder = Request::builder(); - if api_secret.is_some() { - let basic_auth = - "Basic ".to_string() + &to_base64(&("grin:".to_string() + &api_secret.unwrap())); + if let Some(api_secret) = api_secret { + let basic_auth = format!("Basic {}", to_base64(&format!("grin:{}", api_secret))); builder.header(AUTHORIZATION, basic_auth); } @@ -224,6 +223,7 @@ fn send_request_async(req: Request) -> Box) -> Result { let task = send_request_async(req); - let mut rt = Runtime::new().unwrap(); + let mut rt = + Runtime::new().context(ErrorKind::Internal("can't create Tokio runtime".to_owned()))?; Ok(rt.block_on(task)?) } diff --git a/api/src/handlers.rs b/api/src/handlers.rs index 3c4fc6088..feb65e343 100644 --- a/api/src/handlers.rs +++ b/api/src/handlers.rs @@ -20,39 +20,26 @@ mod server_api; mod transactions_api; mod utils; -use crate::router::{Router, RouterError}; - -// Server -use self::server_api::IndexHandler; -use self::server_api::StatusHandler; - -// Blocks use self::blocks_api::BlockHandler; use self::blocks_api::HeaderHandler; - -// TX Set -use self::transactions_api::TxHashSetHandler; - -// Chain use self::chain_api::ChainCompactHandler; use self::chain_api::ChainHandler; use self::chain_api::ChainValidationHandler; use self::chain_api::OutputHandler; - -// Pool Handlers -use self::pool_api::PoolInfoHandler; -use self::pool_api::PoolPushHandler; - -// Peers use self::peers_api::PeerHandler; use self::peers_api::PeersAllHandler; use self::peers_api::PeersConnectedHandler; - -use crate::auth::BasicAuthMiddleware; +use self::pool_api::PoolInfoHandler; +use self::pool_api::PoolPushHandler; +use self::server_api::IndexHandler; +use self::server_api::StatusHandler; +use self::transactions_api::TxHashSetHandler; +use crate::auth::{BasicAuthMiddleware, GRIN_BASIC_REALM}; use crate::chain; use crate::p2p; use crate::pool; use crate::rest::*; +use crate::router::{Router, RouterError}; use crate::util; use crate::util::RwLock; use std::net::SocketAddr; @@ -76,11 +63,10 @@ pub fn start_rest_apis( ) -> bool { let mut apis = ApiServer::new(); let mut router = build_router(chain, tx_pool, peers).expect("unable to build API router"); - if api_secret.is_some() { - let api_basic_auth = - "Basic ".to_string() + &util::to_base64(&("grin:".to_string() + &api_secret.unwrap())); - let basic_realm = "Basic realm=GrinAPI".to_string(); - let basic_auth_middleware = Arc::new(BasicAuthMiddleware::new(api_basic_auth, basic_realm)); + if let Some(api_secret) = api_secret { + let api_basic_auth = format!("Basic {}", util::to_base64(&format!("grin:{}", api_secret))); + let basic_auth_middleware = + Arc::new(BasicAuthMiddleware::new(api_basic_auth, &GRIN_BASIC_REALM)); router.add_middleware(basic_auth_middleware); } diff --git a/api/src/handlers/blocks_api.rs b/api/src/handlers/blocks_api.rs index 9da0a1c87..4cea007a5 100644 --- a/api/src/handlers/blocks_api.rs +++ b/api/src/handlers/blocks_api.rs @@ -41,7 +41,7 @@ impl HeaderHandler { return Ok(h); } if let Ok(height) = input.parse() { - match w(&self.chain).get_header_by_height(height) { + match w(&self.chain)?.get_header_by_height(height) { Ok(header) => return Ok(BlockHeaderPrintable::from_header(&header)), Err(_) => return Err(ErrorKind::NotFound)?, } @@ -50,7 +50,7 @@ impl HeaderHandler { let vec = util::from_hex(input) .map_err(|e| ErrorKind::Argument(format!("invalid input: {}", e)))?; let h = Hash::from_vec(&vec); - let header = w(&self.chain) + let header = w(&self.chain)? .get_block_header(&h) .context(ErrorKind::NotFound)?; Ok(BlockHeaderPrintable::from_header(&header)) @@ -58,7 +58,7 @@ impl HeaderHandler { fn get_header_for_output(&self, commit_id: String) -> Result { let oid = get_output(&self.chain, &commit_id)?.1; - match w(&self.chain).get_header_for_output(&oid) { + match w(&self.chain)?.get_header_for_output(&oid) { Ok(header) => Ok(BlockHeaderPrintable::from_header(&header)), Err(_) => Err(ErrorKind::NotFound)?, } @@ -85,22 +85,23 @@ pub struct BlockHandler { impl BlockHandler { fn get_block(&self, h: &Hash) -> Result { - let block = w(&self.chain).get_block(h).context(ErrorKind::NotFound)?; - Ok(BlockPrintable::from_block(&block, w(&self.chain), false)) + let chain = w(&self.chain)?; + let block = chain.get_block(h).context(ErrorKind::NotFound)?; + BlockPrintable::from_block(&block, chain, false) + .map_err(|_| ErrorKind::Internal("chain error".to_owned()).into()) } fn get_compact_block(&self, h: &Hash) -> Result { - let block = w(&self.chain).get_block(h).context(ErrorKind::NotFound)?; - Ok(CompactBlockPrintable::from_compact_block( - &block.into(), - w(&self.chain), - )) + let chain = w(&self.chain)?; + let block = chain.get_block(h).context(ErrorKind::NotFound)?; + CompactBlockPrintable::from_compact_block(&block.into(), chain) + .map_err(|_| ErrorKind::Internal("chain error".to_owned()).into()) } // Try to decode the string as a height or a hash. fn parse_input(&self, input: String) -> Result { if let Ok(height) = input.parse() { - match w(&self.chain).get_header_by_height(height) { + match w(&self.chain)?.get_header_by_height(height) { Ok(header) => return Ok(header.hash()), Err(_) => return Err(ErrorKind::NotFound)?, } diff --git a/api/src/handlers/chain_api.rs b/api/src/handlers/chain_api.rs index d0df2aa4f..1badea37d 100644 --- a/api/src/handlers/chain_api.rs +++ b/api/src/handlers/chain_api.rs @@ -21,6 +21,7 @@ use crate::types::*; use crate::util; use crate::util::secp::pedersen::Commitment; use crate::web::*; +use failure::ResultExt; use hyper::{Body, Request, StatusCode}; use std::sync::Weak; @@ -32,7 +33,7 @@ pub struct ChainHandler { impl ChainHandler { fn get_tip(&self) -> Result { - let head = w(&self.chain) + let head = w(&self.chain)? .head() .map_err(|e| ErrorKind::Internal(format!("can't get head: {}", e)))?; Ok(Tip::from_tip(head)) @@ -53,7 +54,7 @@ pub struct ChainValidationHandler { impl Handler for ChainValidationHandler { fn get(&self, _req: Request) -> ResponseFuture { - match w(&self.chain).validate(true) { + match w_fut!(&self.chain).validate(true) { Ok(_) => response(StatusCode::OK, "{}"), Err(e) => response( StatusCode::INTERNAL_SERVER_ERROR, @@ -72,7 +73,7 @@ pub struct ChainCompactHandler { impl Handler for ChainCompactHandler { fn post(&self, _req: Request) -> ResponseFuture { - match w(&self.chain).compact() { + match w_fut!(&self.chain).compact() { Ok(_) => response(StatusCode::OK, "{}"), Err(e) => response( StatusCode::INTERNAL_SERVER_ERROR, @@ -118,13 +119,14 @@ impl OutputHandler { commitments: Vec, include_proof: bool, ) -> Result { - let header = w(&self.chain) + let header = w(&self.chain)? .get_header_by_height(block_height) .map_err(|_| ErrorKind::NotFound)?; // TODO - possible to compact away blocks we care about // in the period between accepting the block and refreshing the wallet - let block = w(&self.chain) + let chain = w(&self.chain)?; + let block = chain .get_block(&header.hash()) .map_err(|_| ErrorKind::NotFound)?; let outputs = block @@ -132,9 +134,10 @@ impl OutputHandler { .iter() .filter(|output| commitments.is_empty() || commitments.contains(&output.commit)) .map(|output| { - OutputPrintable::from_output(output, w(&self.chain), Some(&header), include_proof) + OutputPrintable::from_output(output, chain.clone(), Some(&header), include_proof) }) - .collect(); + .collect::, _>>() + .context(ErrorKind::Internal("cain error".to_owned()))?; Ok(BlockOutputs { header: BlockHeaderInfo::from_header(&header), diff --git a/api/src/handlers/peers_api.rs b/api/src/handlers/peers_api.rs index 639b2927e..a36813cb1 100644 --- a/api/src/handlers/peers_api.rs +++ b/api/src/handlers/peers_api.rs @@ -26,7 +26,7 @@ pub struct PeersAllHandler { impl Handler for PeersAllHandler { fn get(&self, _req: Request) -> ResponseFuture { - let peers = &w(&self.peers).all_peers(); + let peers = &w_fut!(&self.peers).all_peers(); json_response_pretty(&peers) } } @@ -37,7 +37,7 @@ pub struct PeersConnectedHandler { impl Handler for PeersConnectedHandler { fn get(&self, _req: Request) -> ResponseFuture { - let peers: Vec = w(&self.peers) + let peers: Vec = w_fut!(&self.peers) .connected_peers() .iter() .map(|p| p.info.clone().into()) @@ -73,7 +73,7 @@ impl Handler for PeerHandler { ); } - match w(&self.peers).get_peer(peer_addr) { + match w_fut!(&self.peers).get_peer(peer_addr) { Ok(peer) => json_response(&peer), Err(_) => response(StatusCode::NOT_FOUND, "peer not found"), } @@ -101,8 +101,8 @@ impl Handler for PeerHandler { }; match command { - "ban" => w(&self.peers).ban_peer(addr, ReasonForBan::ManualBan), - "unban" => w(&self.peers).unban_peer(addr), + "ban" => w_fut!(&self.peers).ban_peer(addr, ReasonForBan::ManualBan), + "unban" => w_fut!(&self.peers).unban_peer(addr), _ => return response(StatusCode::BAD_REQUEST, "invalid command"), }; diff --git a/api/src/handlers/pool_api.rs b/api/src/handlers/pool_api.rs index 299b79a28..cf9278cef 100644 --- a/api/src/handlers/pool_api.rs +++ b/api/src/handlers/pool_api.rs @@ -24,7 +24,7 @@ use crate::util; use crate::util::RwLock; use crate::web::*; use failure::ResultExt; -use futures::future::ok; +use futures::future::{err, ok}; use futures::Future; use hyper::{Body, Request, StatusCode}; use std::sync::Weak; @@ -37,7 +37,7 @@ pub struct PoolInfoHandler { impl Handler for PoolInfoHandler { fn get(&self, _req: Request) -> ResponseFuture { - let pool_arc = w(&self.tx_pool); + let pool_arc = w_fut!(&self.tx_pool); let pool = pool_arc.read(); json_response(&PoolInfo { @@ -63,7 +63,11 @@ impl PoolPushHandler { let params = QueryParams::from(req.uri().query()); let fluff = params.get("fluff").is_some(); - let pool_arc = w(&self.tx_pool).clone(); + let pool_arc = match w(&self.tx_pool) { + //w(&self.tx_pool).clone(); + Ok(p) => p, + Err(e) => return Box::new(err(e)), + }; Box::new( parse_body(req) diff --git a/api/src/handlers/server_api.rs b/api/src/handlers/server_api.rs index 42a829a65..d5092b054 100644 --- a/api/src/handlers/server_api.rs +++ b/api/src/handlers/server_api.rs @@ -45,12 +45,12 @@ pub struct StatusHandler { impl StatusHandler { fn get_status(&self) -> Result { - let head = w(&self.chain) + let head = w(&self.chain)? .head() .map_err(|e| ErrorKind::Internal(format!("can't get head: {}", e)))?; Ok(Status::from_tip_and_peers( head, - w(&self.peers).peer_count(), + w(&self.peers)?.peer_count(), )) } } diff --git a/api/src/handlers/transactions_api.rs b/api/src/handlers/transactions_api.rs index 42723e71d..a65047624 100644 --- a/api/src/handlers/transactions_api.rs +++ b/api/src/handlers/transactions_api.rs @@ -45,23 +45,26 @@ pub struct TxHashSetHandler { impl TxHashSetHandler { // gets roots - fn get_roots(&self) -> TxHashSet { - TxHashSet::from_head(w(&self.chain)) + fn get_roots(&self) -> Result { + Ok(TxHashSet::from_head(w(&self.chain)?)) } // gets last n outputs inserted in to the tree - fn get_last_n_output(&self, distance: u64) -> Vec { - TxHashSetNode::get_last_n_output(w(&self.chain), distance) + fn get_last_n_output(&self, distance: u64) -> Result, Error> { + Ok(TxHashSetNode::get_last_n_output(w(&self.chain)?, distance)) } // gets last n outputs inserted in to the tree - fn get_last_n_rangeproof(&self, distance: u64) -> Vec { - TxHashSetNode::get_last_n_rangeproof(w(&self.chain), distance) + fn get_last_n_rangeproof(&self, distance: u64) -> Result, Error> { + Ok(TxHashSetNode::get_last_n_rangeproof( + w(&self.chain)?, + distance, + )) } // gets last n outputs inserted in to the tree - fn get_last_n_kernel(&self, distance: u64) -> Vec { - TxHashSetNode::get_last_n_kernel(w(&self.chain), distance) + fn get_last_n_kernel(&self, distance: u64) -> Result, Error> { + Ok(TxHashSetNode::get_last_n_kernel(w(&self.chain)?, distance)) } // allows traversal of utxo set @@ -70,18 +73,21 @@ impl TxHashSetHandler { if max > 1000 { max = 1000; } - let outputs = w(&self.chain) + let chain = w(&self.chain)?; + let outputs = chain .unspent_outputs_by_insertion_index(start_index, max) .context(ErrorKind::NotFound)?; - Ok(OutputListing { + let out = OutputListing { last_retrieved_index: outputs.0, highest_index: outputs.1, outputs: outputs .2 .iter() - .map(|x| OutputPrintable::from_output(x, w(&self.chain), None, true)) - .collect(), - }) + .map(|x| OutputPrintable::from_output(x, chain.clone(), None, true)) + .collect::, _>>() + .context(ErrorKind::Internal("cain error".to_owned()))?, + }; + Ok(out) } // return a dummy output with merkle proof for position filled out @@ -92,10 +98,9 @@ impl TxHashSetHandler { id )))?; let commit = Commitment::from_vec(c); - let output_pos = w(&self.chain) - .get_output_pos(&commit) - .context(ErrorKind::NotFound)?; - let merkle_proof = chain::Chain::get_merkle_proof_for_pos(&w(&self.chain), commit) + let chain = w(&self.chain)?; + let output_pos = chain.get_output_pos(&commit).context(ErrorKind::NotFound)?; + let merkle_proof = chain::Chain::get_merkle_proof_for_pos(&chain, commit) .map_err(|_| ErrorKind::NotFound)?; Ok(OutputPrintable { output_type: OutputType::Coinbase, @@ -120,10 +125,10 @@ impl Handler for TxHashSetHandler { let id = parse_param_no_err!(params, "id", "".to_owned()); match right_path_element!(req) { - "roots" => json_response_pretty(&self.get_roots()), - "lastoutputs" => json_response_pretty(&self.get_last_n_output(last_n)), - "lastrangeproofs" => json_response_pretty(&self.get_last_n_rangeproof(last_n)), - "lastkernels" => json_response_pretty(&self.get_last_n_kernel(last_n)), + "roots" => result_to_response(self.get_roots()), + "lastoutputs" => result_to_response(self.get_last_n_output(last_n)), + "lastrangeproofs" => result_to_response(self.get_last_n_rangeproof(last_n)), + "lastkernels" => result_to_response(self.get_last_n_kernel(last_n)), "outputs" => result_to_response(self.outputs(start_index, max)), "merkleproof" => result_to_response(self.get_merkle_proof_for_output(&id)), _ => response(StatusCode::BAD_REQUEST, ""), diff --git a/api/src/handlers/utils.rs b/api/src/handlers/utils.rs index bedaf0904..1aa309e98 100644 --- a/api/src/handlers/utils.rs +++ b/api/src/handlers/utils.rs @@ -24,8 +24,9 @@ use std::sync::{Arc, Weak}; // All handlers use `Weak` references instead of `Arc` to avoid cycles that // can never be destroyed. These 2 functions are simple helpers to reduce the // boilerplate of dealing with `Weak`. -pub fn w(weak: &Weak) -> Arc { - weak.upgrade().unwrap() +pub fn w(weak: &Weak) -> Result, Error> { + weak.upgrade() + .ok_or_else(|| ErrorKind::Internal("failed to upgrade weak refernce".to_owned()).into()) } /// Retrieves an output from the chain given a commit id (a tiny bit iteratively) @@ -48,14 +49,16 @@ pub fn get_output( OutputIdentifier::new(OutputFeatures::Coinbase, &commit), ]; - for x in outputs.iter().filter(|x| w(chain).is_unspent(x).is_ok()) { - let block_height = w(chain) + let chain = w(chain)?; + + for x in outputs.iter().filter(|x| chain.is_unspent(x).is_ok()) { + let block_height = chain .get_header_for_output(&x) .context(ErrorKind::Internal( "Can't get header for output".to_owned(), ))? .height; - let output_pos = w(chain).get_output_pos(&x.commit).unwrap_or(0); + let output_pos = chain.get_output_pos(&x.commit).unwrap_or(0); return Ok((Output::new(&commit, block_height, output_pos), x.clone())); } Err(ErrorKind::NotFound)? diff --git a/api/src/lib.rs b/api/src/lib.rs index 282a29009..d9a566e19 100644 --- a/api/src/lib.rs +++ b/api/src/lib.rs @@ -39,7 +39,7 @@ mod rest; mod router; mod types; -pub use crate::auth::BasicAuthMiddleware; +pub use crate::auth::{BasicAuthMiddleware, GRIN_BASIC_REALM}; pub use crate::handlers::start_rest_apis; pub use crate::rest::*; pub use crate::router::*; diff --git a/api/src/rest.rs b/api/src/rest.rs index fa26ef64a..98c1b1314 100644 --- a/api/src/rest.rs +++ b/api/src/rest.rs @@ -19,11 +19,12 @@ //! register them on a ApiServer. use crate::router::{Handler, HandlerObj, ResponseFuture, Router}; +use crate::web::response; use failure::{Backtrace, Context, Fail, ResultExt}; use futures::sync::oneshot; use futures::Stream; use hyper::rt::Future; -use hyper::{rt, Body, Request, Server}; +use hyper::{rt, Body, Request, Server, StatusCode}; use rustls; use rustls::internal::pemfile; use std::fmt::{self, Display}; @@ -264,6 +265,9 @@ impl Handler for LoggingMiddleware { mut handlers: Box>, ) -> ResponseFuture { debug!("REST call: {} {}", req.method(), req.uri().path()); - handlers.next().unwrap().call(req, handlers) + match handlers.next() { + Some(handler) => handler.call(req, handlers), + None => response(StatusCode::INTERNAL_SERVER_ERROR, "no handler found"), + } } } diff --git a/api/src/types.rs b/api/src/types.rs index c069ac014..4ae837177 100644 --- a/api/src/types.rs +++ b/api/src/types.rs @@ -222,7 +222,9 @@ impl<'de> serde::de::Visitor<'de> for PrintableCommitmentVisitor { E: serde::de::Error, { Ok(PrintableCommitment { - commit: pedersen::Commitment::from_vec(util::from_hex(String::from(v)).unwrap()), + commit: pedersen::Commitment::from_vec( + util::from_hex(String::from(v)).map_err(serde::de::Error::custom)?, + ), }) } } @@ -255,7 +257,7 @@ impl OutputPrintable { chain: Arc, block_header: Option<&core::BlockHeader>, include_proof: bool, - ) -> OutputPrintable { + ) -> Result { let output_type = if output.is_coinbase() { OutputType::Coinbase } else { @@ -266,7 +268,7 @@ impl OutputPrintable { let spent = chain.is_unspent(&out_id).is_err(); let block_height = match spent { true => None, - false => Some(chain.get_header_for_output(&out_id).unwrap().height), + false => Some(chain.get_header_for_output(&out_id)?.height), }; let proof = if include_proof { @@ -280,13 +282,15 @@ impl OutputPrintable { // We require the rewind() to be stable even after the PMMR is pruned and // compacted so we can still recreate the necessary proof. let mut merkle_proof = None; - if output.is_coinbase() && !spent && block_header.is_some() { - merkle_proof = chain.get_merkle_proof(&out_id, &block_header.unwrap()).ok() + if output.is_coinbase() && !spent { + if let Some(block_header) = block_header { + merkle_proof = chain.get_merkle_proof(&out_id, &block_header).ok(); + } }; let output_pos = chain.get_output_pos(&output.commit).unwrap_or(0); - OutputPrintable { + Ok(OutputPrintable { output_type, commit: output.commit, spent, @@ -295,7 +299,7 @@ impl OutputPrintable { block_height, merkle_proof, mmr_index: output_pos, - } + }) } pub fn commit(&self) -> Result { @@ -303,12 +307,13 @@ impl OutputPrintable { } pub fn range_proof(&self) -> Result { - let proof_str = self - .proof - .clone() - .ok_or_else(|| ser::Error::HexError(format!("output range_proof missing"))) - .unwrap(); - let p_vec = util::from_hex(proof_str).unwrap(); + let proof_str = match self.proof.clone() { + Some(p) => p, + None => return Err(ser::Error::HexError(format!("output range_proof missing"))), + }; + + let p_vec = util::from_hex(proof_str) + .map_err(|_| ser::Error::HexError(format!("invalud output range_proof")))?; let mut p_bytes = [0; util::secp::constants::MAX_PROOF_SIZE]; for i in 0..p_bytes.len() { p_bytes[i] = p_vec[i]; @@ -428,6 +433,15 @@ impl<'de> serde::de::Deserialize<'de> for OutputPrintable { } } + if output_type.is_none() + || commit.is_none() + || spent.is_none() + || proof_hash.is_none() + || mmr_index.is_none() + { + return Err(serde::de::Error::custom("invalid output")); + } + Ok(OutputPrintable { output_type: output_type.unwrap(), commit: commit.unwrap(), @@ -570,7 +584,7 @@ impl BlockPrintable { block: &core::Block, chain: Arc, include_proof: bool, - ) -> BlockPrintable { + ) -> Result { let inputs = block .inputs() .iter() @@ -587,18 +601,19 @@ impl BlockPrintable { include_proof, ) }) - .collect(); + .collect::, _>>()?; + let kernels = block .kernels() .iter() .map(|kernel| TxKernelPrintable::from_txkernel(kernel)) .collect(); - BlockPrintable { + Ok(BlockPrintable { header: BlockHeaderPrintable::from_header(&block.header), inputs: inputs, outputs: outputs, kernels: kernels, - } + }) } } @@ -620,24 +635,24 @@ impl CompactBlockPrintable { pub fn from_compact_block( cb: &core::CompactBlock, chain: Arc, - ) -> CompactBlockPrintable { - let block = chain.get_block(&cb.hash()).unwrap(); + ) -> Result { + let block = chain.get_block(&cb.hash())?; let out_full = cb .out_full() .iter() .map(|x| OutputPrintable::from_output(x, chain.clone(), Some(&block.header), false)) - .collect(); + .collect::, _>>()?; let kern_full = cb .kern_full() .iter() .map(|x| TxKernelPrintable::from_txkernel(x)) .collect(); - CompactBlockPrintable { + Ok(CompactBlockPrintable { header: BlockHeaderPrintable::from_header(&cb.header), out_full, kern_full, kern_ids: cb.kern_ids().iter().map(|x| x.to_hex()).collect(), - } + }) } } diff --git a/api/src/web.rs b/api/src/web.rs index 1bd296237..eb525bb8e 100644 --- a/api/src/web.rs +++ b/api/src/web.rs @@ -180,3 +180,12 @@ macro_rules! parse_param_no_err( } } )); + +#[macro_export] +macro_rules! w_fut( + ($p: expr) =>( + match w($p) { + Ok(p) => p, + Err(_) => return response(StatusCode::INTERNAL_SERVER_ERROR, "weak reference upgrade failed" ), + } + )); diff --git a/api/tests/rest.rs b/api/tests/rest.rs index 641ce3d2e..3651bf717 100644 --- a/api/tests/rest.rs +++ b/api/tests/rest.rs @@ -2,7 +2,7 @@ use grin_api as api; use grin_util as util; use crate::api::*; -use hyper::{Body, Request}; +use hyper::{Body, Request, StatusCode}; use std::net::SocketAddr; use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; use std::sync::Arc; @@ -43,7 +43,10 @@ impl Handler for CounterMiddleware { mut handlers: Box>, ) -> ResponseFuture { self.counter.fetch_add(1, Ordering::SeqCst); - handlers.next().unwrap().call(req, handlers) + match handlers.next() { + Some(h) => h.call(req, handlers), + None => return response(StatusCode::INTERNAL_SERVER_ERROR, "no handler found"), + } } } diff --git a/wallet/src/controller.rs b/wallet/src/controller.rs index f69a02dd1..996fa04e4 100644 --- a/wallet/src/controller.rs +++ b/wallet/src/controller.rs @@ -16,7 +16,9 @@ //! invocations) as needed. //! Still experimental use crate::adapters::{FileWalletCommAdapter, HTTPWalletCommAdapter, KeybaseWalletCommAdapter}; -use crate::api::{ApiServer, BasicAuthMiddleware, Handler, ResponseFuture, Router, TLSConfig}; +use crate::api::{ + ApiServer, BasicAuthMiddleware, Handler, ResponseFuture, Router, TLSConfig, GRIN_BASIC_REALM, +}; use crate::core::core; use crate::core::core::Transaction; use crate::keychain::Keychain; @@ -89,8 +91,8 @@ where if api_secret.is_some() { let api_basic_auth = "Basic ".to_string() + &to_base64(&("grin:".to_string() + &api_secret.unwrap())); - let basic_realm = "Basic realm=GrinOwnerAPI".to_string(); - let basic_auth_middleware = Arc::new(BasicAuthMiddleware::new(api_basic_auth, basic_realm)); + let basic_auth_middleware = + Arc::new(BasicAuthMiddleware::new(api_basic_auth, &GRIN_BASIC_REALM)); router.add_middleware(basic_auth_middleware); } router diff --git a/wallet/src/test_framework/mod.rs b/wallet/src/test_framework/mod.rs index 3d5d7fddb..b66bd350f 100644 --- a/wallet/src/test_framework/mod.rs +++ b/wallet/src/test_framework/mod.rs @@ -75,7 +75,7 @@ fn get_outputs_by_pmmr_index_local( outputs: outputs .2 .iter() - .map(|x| api::OutputPrintable::from_output(x, chain.clone(), None, true)) + .map(|x| api::OutputPrintable::from_output(x, chain.clone(), None, true).unwrap()) .collect(), } }