diff --git a/Cargo.toml b/Cargo.toml index 9b7707636..d6c26105b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,30 +9,54 @@ repository = "https://github.com/collinsmuriuki/mpesa-rust" readme = "./README.md" license = "MIT" +[features] +default = [ + "account_balance", + "b2b", + "b2c", + "bill_manager", + "c2b_register", + "c2b_simulate", + "express_request", + "transaction_reversal", + "transaction_status", +] +account_balance = [] +b2b = ["dep:base64", "dep:x509-parser", "dep:rsa", "dep:rand"] +b2c = ["dep:base64", "dep:x509-parser", "dep:rsa", "dep:rand"] +bill_manager = ["dep:chrono"] +c2b_register = [] +c2b_simulate = [] +express_request = ["dep:chrono", "dep:base64"] +transaction_reversal = ["dep:base64", "dep:x509-parser", "dep:rsa", "dep:rand"] +transaction_status = ["dep:base64", "dep:x509-parser", "dep:rsa", "dep:rand"] + + [dependencies] -chrono = {version = "0.4", optional = true, default-features = false, features = ["clock", "serde"] } -openssl = {version = "0.10", optional = true} -reqwest = {version = "0.11", features = ["json"]} -secrecy = "0.8.0" -serde = {version="1.0", features= ["derive"]} +base64 = { version = "0.21", optional = true } +chrono = { version = "0.4", optional = true, default-features = false, features = [ + "clock", + "serde", +] } +rand = { version = "0.8", optional = true, default-features = false, features = [ + "std", +] } +reqwest = { version = "0.11", features = ["json"] } +rsa = { version = "0.9", optional = true } +secrecy = "0.8" +serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" serde_repr = "0.1" -thiserror = "1.0.37" -wiremock = "0.5" +thiserror = "1.0" +x509-parser = { version = "0.15", optional = true } + [dev-dependencies] dotenv = "0.15" -tokio = {version = "1", features = ["rt", "rt-multi-thread", "macros"]} +tokio = { version = "1", features = ["rt", "rt-multi-thread", "macros"] } wiremock = "0.5" -[features] -default = ["account_balance", "b2b", "b2c", "bill_manager", "c2b_register", "c2b_simulate", "express_request", "transaction_reversal", "transaction_status"] -account_balance = ["dep:openssl"] -b2b = ["dep:openssl"] -b2c = ["dep:openssl"] -bill_manager = ["dep:chrono"] -c2b_register = [] -c2b_simulate = [] -express_request = ["dep:chrono"] -transaction_reversal = ["dep:openssl"] -transaction_status= ["dep:openssl"] + +# Support Wasm +[target.'cfg(target_arch = "wasm32")'.dependencies] +getrandom = { version = "0.2", features = ["js"] } diff --git a/src/client.rs b/src/client.rs index 3a9640e4b..19212afd8 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,3 +1,12 @@ +use std::cell::RefCell; + +use base64::engine::general_purpose; +use base64::Engine as _; +use reqwest::Client as HttpClient; +use rsa::{BigUint, Pkcs1v15Encrypt}; +use secrecy::{ExposeSecret, Secret}; +use serde_json::Value; + use crate::environment::ApiEnvironment; use crate::services::{ AccountBalanceBuilder, B2bBuilder, B2cBuilder, BulkInvoiceBuilder, C2bRegisterBuilder, @@ -6,18 +15,10 @@ use crate::services::{ TransactionStatusBuilder, }; use crate::{ApiError, MpesaError}; -use openssl::base64; -use openssl::rsa::Padding; -use openssl::x509::X509; -use reqwest::Client as HttpClient; -use secrecy::{ExposeSecret, Secret}; -use serde_json::Value; -use std::cell::RefCell; /// Source: [test credentials](https://developer.safaricom.co.ke/test_credentials) const DEFAULT_INITIATOR_PASSWORD: &str = "Safcom496!"; /// Get current package version from metadata -const CARGO_PACKAGE_VERSION: &str = env!("CARGO_PKG_VERSION"); /// `Result` enum type alias pub type MpesaResult = Result; @@ -47,13 +48,16 @@ impl<'mpesa, Env: ApiEnvironment> Mpesa { /// # Panics /// This method can panic if a TLS backend cannot be initialized for the internal http_client pub fn new>(client_key: S, client_secret: S, environment: Env) -> Self { + #[cfg(target_arch = "wasm32")] + let http_client = HttpClient::new(); + + #[cfg(not(target_arch = "wasm32"))] let http_client = HttpClient::builder() .connect_timeout(std::time::Duration::from_millis(10_000)) - .user_agent(format!("mpesa-rust@{CARGO_PACKAGE_VERSION}")) - // TODO: Potentialy return a `Result` enum from Mpesa::new? - // Making assumption that creation of http client cannot fail + .user_agent(format!("mpesa-rust@{}", env!("CARGO_PKG_VERSION"))) .build() .expect("Error building http client"); + Self { client_key: client_key.into(), client_secret: Secret::new(client_secret.into()), @@ -508,30 +512,51 @@ impl<'mpesa, Env: ApiEnvironment> Mpesa { /// /// # Errors /// Returns `EncryptionError` variant of `MpesaError` + pub(crate) fn gen_security_credentials(&self) -> MpesaResult { let pem = self.environment.get_certificate().as_bytes(); - let cert = X509::from_pem(pem)?; - // getting the public and rsa keys - let pub_key = cert.public_key()?; - let rsa_key = pub_key.rsa()?; - // configuring the buffer - let buf_len = pub_key.size(); - let mut buffer = vec![0; buf_len]; - - rsa_key.public_encrypt( - self.initiator_password().as_bytes(), - &mut buffer, - Padding::PKCS1, - )?; - Ok(base64::encode_block(&buffer)) + + let (_, cert) = x509_parser::pem::parse_x509_pem(pem) + .map_err(|e| MpesaError::EncryptionError(e.to_string()))?; + + let cert = cert + .parse_x509() + .map_err(|e| MpesaError::EncryptionError(e.to_string()))?; + + let key = cert + .public_key() + .parsed() + .map_err(|e| MpesaError::EncryptionError(e.to_string()))?; + + let rsa = match key { + x509_parser::public_key::PublicKey::RSA(rsa_key) => rsa_key, + _ => unreachable!("Invalid public key type"), + }; + + let value = rsa::RsaPublicKey::new( + BigUint::from_bytes_be(rsa.modulus), + BigUint::from_bytes_be(rsa.exponent), + ) + .map_err(|e| MpesaError::EncryptionError(e.to_string()))?; + + let value = value + .encrypt( + &mut rand::rngs::OsRng, + Pkcs1v15Encrypt, + self.initiator_password().as_bytes(), + ) + .map_err(|e| MpesaError::EncryptionError(e.to_string()))?; + + let value = general_purpose::STANDARD.encode(value); + + Ok(value) } } #[cfg(test)] mod tests { - use crate::Sandbox; - use super::*; + use crate::Sandbox; #[test] fn test_setting_initator_password() { diff --git a/src/constants.rs b/src/constants.rs index 418ad5a52..0bdd9fa1b 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -1,7 +1,8 @@ +use std::fmt::{Display, Formatter, Result as FmtResult}; + use chrono::prelude::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; -use std::fmt::{Display, Formatter, Result as FmtResult}; /// Mpesa command ids #[derive(Debug, Serialize, Deserialize)] diff --git a/src/environment.rs b/src/environment.rs index eb6f1f579..0000cb959 100644 --- a/src/environment.rs +++ b/src/environment.rs @@ -10,8 +10,10 @@ //! and the `public key` an X509 certificate used for encrypting initiator passwords. You can read more about that from //! the Safaricom API [docs](https://developer.safaricom.co.ke/docs?javascript#security-credentials). +use std::convert::TryFrom; +use std::str::FromStr; + use crate::MpesaError; -use std::{convert::TryFrom, str::FromStr}; #[derive(Debug, Clone)] /// Enum to map to desired environment so as to access certificate diff --git a/src/errors.rs b/src/errors.rs index 2adc20891..dba407616 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,5 +1,7 @@ +use std::env::VarError; +use std::fmt; + use serde::{Deserialize, Serialize}; -use std::{env::VarError, fmt}; /// Mpesa error stack #[derive(thiserror::Error, Debug)] @@ -41,7 +43,7 @@ pub enum MpesaError { #[error("An error has occured while retreiving an environmental variable")] EnvironmentalVariableError(#[from] VarError), #[error("An error has occurred while generating security credentials")] - EncryptionError(#[from] openssl::error::ErrorStack), + EncryptionError(String), #[error("{0}")] Message(&'static str), } diff --git a/src/services/account_balance.rs b/src/services/account_balance.rs index b3d7ba4d4..b59bf8b4f 100644 --- a/src/services/account_balance.rs +++ b/src/services/account_balance.rs @@ -1,8 +1,9 @@ +use serde::{Deserialize, Serialize}; + use crate::client::MpesaResult; use crate::constants::{CommandId, IdentifierTypes}; use crate::environment::ApiEnvironment; use crate::{Mpesa, MpesaError}; -use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize)] /// Account Balance payload diff --git a/src/services/b2b.rs b/src/services/b2b.rs index 08746109e..aaaab1341 100644 --- a/src/services/b2b.rs +++ b/src/services/b2b.rs @@ -1,8 +1,9 @@ +use serde::{Deserialize, Serialize}; + use crate::client::{Mpesa, MpesaResult}; use crate::constants::{CommandId, IdentifierTypes}; use crate::environment::ApiEnvironment; use crate::errors::MpesaError; -use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize)] struct B2bPayload<'mpesa> { diff --git a/src/services/b2c.rs b/src/services/b2c.rs index 6ae46cfdc..6489ef329 100644 --- a/src/services/b2c.rs +++ b/src/services/b2c.rs @@ -1,7 +1,8 @@ +use serde::{Deserialize, Serialize}; + use crate::client::MpesaResult; use crate::environment::ApiEnvironment; use crate::{CommandId, Mpesa, MpesaError}; -use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize)] /// Payload to allow for b2c transactions: diff --git a/src/services/bill_manager/bulk_invoice.rs b/src/services/bill_manager/bulk_invoice.rs index 15618b9b1..6eeee012c 100644 --- a/src/services/bill_manager/bulk_invoice.rs +++ b/src/services/bill_manager/bulk_invoice.rs @@ -1,8 +1,9 @@ +use serde::Deserialize; + use crate::client::{Mpesa, MpesaResult}; use crate::constants::Invoice; use crate::environment::ApiEnvironment; use crate::errors::MpesaError; -use serde::Deserialize; #[derive(Clone, Debug, Deserialize)] pub struct BulkInvoiceResponse { diff --git a/src/services/bill_manager/cancel_invoice.rs b/src/services/bill_manager/cancel_invoice.rs index aa159dd30..2b6c23641 100644 --- a/src/services/bill_manager/cancel_invoice.rs +++ b/src/services/bill_manager/cancel_invoice.rs @@ -1,7 +1,8 @@ +use serde::{Deserialize, Serialize}; + use crate::client::{Mpesa, MpesaResult}; use crate::environment::ApiEnvironment; use crate::errors::MpesaError; -use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] diff --git a/src/services/bill_manager/onboard.rs b/src/services/bill_manager/onboard.rs index 9bb6f20dd..a6456c9d3 100644 --- a/src/services/bill_manager/onboard.rs +++ b/src/services/bill_manager/onboard.rs @@ -1,8 +1,9 @@ +use serde::{Deserialize, Serialize}; + use crate::client::{Mpesa, MpesaResult}; use crate::constants::SendRemindersTypes; use crate::environment::ApiEnvironment; use crate::errors::MpesaError; -use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize)] /// Payload to opt you in as a biller to the bill manager features. diff --git a/src/services/bill_manager/onboard_modify.rs b/src/services/bill_manager/onboard_modify.rs index 36ff7e069..fecb33b03 100644 --- a/src/services/bill_manager/onboard_modify.rs +++ b/src/services/bill_manager/onboard_modify.rs @@ -1,8 +1,9 @@ +use serde::{Deserialize, Serialize}; + use crate::client::{Mpesa, MpesaResult}; use crate::constants::SendRemindersTypes; use crate::environment::ApiEnvironment; use crate::errors::MpesaError; -use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize)] /// Payload to modify opt-in details to the bill manager api. diff --git a/src/services/bill_manager/reconciliation.rs b/src/services/bill_manager/reconciliation.rs index baf470b6f..59a7d6842 100644 --- a/src/services/bill_manager/reconciliation.rs +++ b/src/services/bill_manager/reconciliation.rs @@ -1,8 +1,9 @@ +use chrono::prelude::{DateTime, Utc}; +use serde::{Deserialize, Serialize}; + use crate::client::{Mpesa, MpesaResult}; use crate::environment::ApiEnvironment; use crate::errors::MpesaError; -use chrono::prelude::{DateTime, Utc}; -use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] diff --git a/src/services/bill_manager/single_invoice.rs b/src/services/bill_manager/single_invoice.rs index 5ce438bc0..a04c774d3 100644 --- a/src/services/bill_manager/single_invoice.rs +++ b/src/services/bill_manager/single_invoice.rs @@ -1,9 +1,10 @@ +use chrono::prelude::{DateTime, Utc}; +use serde::Deserialize; + use crate::client::{Mpesa, MpesaResult}; use crate::constants::{Invoice, InvoiceItem}; use crate::environment::ApiEnvironment; use crate::errors::MpesaError; -use chrono::prelude::{DateTime, Utc}; -use serde::Deserialize; #[derive(Clone, Debug, Deserialize)] pub struct SingleInvoiceResponse { diff --git a/src/services/c2b_register.rs b/src/services/c2b_register.rs index fe214e7e6..3e4ad85a7 100644 --- a/src/services/c2b_register.rs +++ b/src/services/c2b_register.rs @@ -1,8 +1,9 @@ +use serde::{Deserialize, Serialize}; + use crate::client::{Mpesa, MpesaResult}; use crate::constants::ResponseType; use crate::environment::ApiEnvironment; use crate::errors::MpesaError; -use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize)] /// Payload to register the 3rd party’s confirmation and validation URLs to M-Pesa diff --git a/src/services/c2b_simulate.rs b/src/services/c2b_simulate.rs index b9a41fdb6..157642ecc 100644 --- a/src/services/c2b_simulate.rs +++ b/src/services/c2b_simulate.rs @@ -1,8 +1,9 @@ +use serde::{Deserialize, Serialize}; + use crate::client::{Mpesa, MpesaResult}; use crate::constants::CommandId; use crate::environment::ApiEnvironment; use crate::errors::MpesaError; -use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize)] /// Payload to make payment requests from C2B. diff --git a/src/services/express_request.rs b/src/services/express_request.rs index a08ce2d16..f5421363d 100644 --- a/src/services/express_request.rs +++ b/src/services/express_request.rs @@ -1,10 +1,12 @@ +use base64::engine::general_purpose; +use base64::Engine as _; +use chrono::prelude::Local; +use serde::{Deserialize, Serialize}; + use crate::client::{Mpesa, MpesaResult}; use crate::constants::CommandId; use crate::environment::ApiEnvironment; use crate::errors::MpesaError; -use chrono::prelude::Local; -use openssl::base64; -use serde::{Deserialize, Serialize}; /// Source: [test credentials](https://developer.safaricom.co.ke/test_credentials) static DEFAULT_PASSKEY: &str = "bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919"; @@ -100,7 +102,7 @@ impl<'mpesa, Env: ApiEnvironment> MpesaExpressRequestBuilder<'mpesa, Env> { /// Returns the encoded password and a timestamp string fn generate_password_and_timestamp(&self) -> (String, String) { let timestamp = Local::now().format("%Y%m%d%H%M%S").to_string(); - let encoded_password = base64::encode_block( + let encoded_password = general_purpose::STANDARD.encode( format!( "{}{}{}", self.business_short_code(), diff --git a/src/services/transaction_reversal.rs b/src/services/transaction_reversal.rs index 5aec81853..0080485ce 100644 --- a/src/services/transaction_reversal.rs +++ b/src/services/transaction_reversal.rs @@ -1,12 +1,6 @@ -use serde::Deserialize; -use serde::Serialize; - -use crate::ApiEnvironment; -use crate::CommandId; -use crate::IdentifierTypes; -use crate::Mpesa; -use crate::MpesaError; -use crate::MpesaResult; +use serde::{Deserialize, Serialize}; + +use crate::{ApiEnvironment, CommandId, IdentifierTypes, Mpesa, MpesaError, MpesaResult}; #[derive(Debug, Serialize)] pub struct TransactionReversalPayload<'mpesa> { diff --git a/src/services/transaction_status.rs b/src/services/transaction_status.rs index eac9f5552..5a7a50b99 100644 --- a/src/services/transaction_status.rs +++ b/src/services/transaction_status.rs @@ -1,12 +1,6 @@ -use serde::Deserialize; -use serde::Serialize; - -use crate::ApiEnvironment; -use crate::CommandId; -use crate::IdentifierTypes; -use crate::Mpesa; -use crate::MpesaError; -use crate::MpesaResult; +use serde::{Deserialize, Serialize}; + +use crate::{ApiEnvironment, CommandId, IdentifierTypes, Mpesa, MpesaError, MpesaResult}; #[derive(Debug, Serialize)] pub struct TransactionStatusPayload<'mpesa> { diff --git a/tests/mpesa-rust/account_balance_test.rs b/tests/mpesa-rust/account_balance_test.rs index 034311f09..ebbc65a9d 100644 --- a/tests/mpesa-rust/account_balance_test.rs +++ b/tests/mpesa-rust/account_balance_test.rs @@ -1,9 +1,10 @@ -use crate::get_mpesa_client; use mpesa::MpesaError; use serde_json::json; use wiremock::matchers::{method, path}; use wiremock::{Mock, ResponseTemplate}; +use crate::get_mpesa_client; + #[tokio::test] async fn account_balance_success() { let (client, server) = get_mpesa_client!(); diff --git a/tests/mpesa-rust/b2c_test.rs b/tests/mpesa-rust/b2c_test.rs index 821a4a8da..39dec8ed4 100644 --- a/tests/mpesa-rust/b2c_test.rs +++ b/tests/mpesa-rust/b2c_test.rs @@ -1,9 +1,10 @@ -use crate::get_mpesa_client; use mpesa::MpesaError; use serde_json::json; use wiremock::matchers::{method, path}; use wiremock::{Mock, ResponseTemplate}; +use crate::get_mpesa_client; + #[tokio::test] async fn b2c_success() { let (client, server) = get_mpesa_client!(); diff --git a/tests/mpesa-rust/bill_manager_test/bulk_invoice_test.rs b/tests/mpesa-rust/bill_manager_test/bulk_invoice_test.rs index 591a373b0..6e05928e9 100644 --- a/tests/mpesa-rust/bill_manager_test/bulk_invoice_test.rs +++ b/tests/mpesa-rust/bill_manager_test/bulk_invoice_test.rs @@ -1,10 +1,11 @@ -use crate::get_mpesa_client; use chrono::prelude::Utc; use mpesa::{Invoice, InvoiceItem, MpesaError}; use serde_json::json; use wiremock::matchers::{method, path}; use wiremock::{Mock, ResponseTemplate}; +use crate::get_mpesa_client; + fn sample_response() -> ResponseTemplate { let sample_response = json!({ "rescode": "200", diff --git a/tests/mpesa-rust/bill_manager_test/cancel_invoice_test.rs b/tests/mpesa-rust/bill_manager_test/cancel_invoice_test.rs index 64d361055..201bbce3c 100644 --- a/tests/mpesa-rust/bill_manager_test/cancel_invoice_test.rs +++ b/tests/mpesa-rust/bill_manager_test/cancel_invoice_test.rs @@ -1,8 +1,9 @@ -use crate::get_mpesa_client; use serde_json::json; use wiremock::matchers::{method, path}; use wiremock::{Mock, ResponseTemplate}; +use crate::get_mpesa_client; + fn sample_response() -> ResponseTemplate { let sample_response = json!({ "rescode": "200", diff --git a/tests/mpesa-rust/bill_manager_test/onboard_modify_test.rs b/tests/mpesa-rust/bill_manager_test/onboard_modify_test.rs index dcf629dcc..3e0376940 100644 --- a/tests/mpesa-rust/bill_manager_test/onboard_modify_test.rs +++ b/tests/mpesa-rust/bill_manager_test/onboard_modify_test.rs @@ -1,8 +1,9 @@ -use crate::get_mpesa_client; use serde_json::json; use wiremock::matchers::{method, path}; use wiremock::{Mock, ResponseTemplate}; +use crate::get_mpesa_client; + fn sample_response() -> ResponseTemplate { let sample_response_body = json!({ "rescode": "200", diff --git a/tests/mpesa-rust/bill_manager_test/onboard_test.rs b/tests/mpesa-rust/bill_manager_test/onboard_test.rs index 2b2332468..b9a813112 100644 --- a/tests/mpesa-rust/bill_manager_test/onboard_test.rs +++ b/tests/mpesa-rust/bill_manager_test/onboard_test.rs @@ -1,9 +1,10 @@ -use crate::get_mpesa_client; use mpesa::MpesaError; use serde_json::json; use wiremock::matchers::{method, path}; use wiremock::{Mock, ResponseTemplate}; +use crate::get_mpesa_client; + fn sample_response() -> ResponseTemplate { let sample_response_body = json!({ "app_key": "kfpB9X4o0H", diff --git a/tests/mpesa-rust/bill_manager_test/reconciliation_test.rs b/tests/mpesa-rust/bill_manager_test/reconciliation_test.rs index 02489be15..c555c8b1c 100644 --- a/tests/mpesa-rust/bill_manager_test/reconciliation_test.rs +++ b/tests/mpesa-rust/bill_manager_test/reconciliation_test.rs @@ -1,10 +1,11 @@ -use crate::get_mpesa_client; use chrono::prelude::Utc; use mpesa::MpesaError; use serde_json::json; use wiremock::matchers::{method, path}; use wiremock::{Mock, ResponseTemplate}; +use crate::get_mpesa_client; + fn sample_response() -> ResponseTemplate { let sample_response = json!({ "rescode": "200", diff --git a/tests/mpesa-rust/bill_manager_test/single_invoice_test.rs b/tests/mpesa-rust/bill_manager_test/single_invoice_test.rs index a9622050b..b876de4f9 100644 --- a/tests/mpesa-rust/bill_manager_test/single_invoice_test.rs +++ b/tests/mpesa-rust/bill_manager_test/single_invoice_test.rs @@ -1,10 +1,11 @@ -use crate::get_mpesa_client; use chrono::prelude::Utc; use mpesa::{InvoiceItem, MpesaError}; use serde_json::json; use wiremock::matchers::{method, path}; use wiremock::{Mock, ResponseTemplate}; +use crate::get_mpesa_client; + fn sample_response() -> ResponseTemplate { let sample_response = json!({ "rescode": "200", diff --git a/tests/mpesa-rust/c2b_register_test.rs b/tests/mpesa-rust/c2b_register_test.rs index c50815455..18bcee648 100644 --- a/tests/mpesa-rust/c2b_register_test.rs +++ b/tests/mpesa-rust/c2b_register_test.rs @@ -1,9 +1,10 @@ -use crate::get_mpesa_client; use mpesa::MpesaError; use serde_json::json; use wiremock::matchers::{method, path}; use wiremock::{Mock, ResponseTemplate}; +use crate::get_mpesa_client; + #[tokio::test] async fn c2b_register_success() { let (client, server) = get_mpesa_client!(); diff --git a/tests/mpesa-rust/c2b_simulate_test.rs b/tests/mpesa-rust/c2b_simulate_test.rs index 3a70e23e8..0ff085188 100644 --- a/tests/mpesa-rust/c2b_simulate_test.rs +++ b/tests/mpesa-rust/c2b_simulate_test.rs @@ -1,9 +1,10 @@ -use crate::get_mpesa_client; use mpesa::MpesaError; use serde_json::json; use wiremock::matchers::{method, path}; use wiremock::{Mock, ResponseTemplate}; +use crate::get_mpesa_client; + #[tokio::test] async fn c2b_simulate_success() { let (client, server) = get_mpesa_client!(); diff --git a/tests/mpesa-rust/stk_push_test.rs b/tests/mpesa-rust/stk_push_test.rs index 19be8c512..dec5815da 100644 --- a/tests/mpesa-rust/stk_push_test.rs +++ b/tests/mpesa-rust/stk_push_test.rs @@ -1,9 +1,10 @@ -use crate::get_mpesa_client; use mpesa::MpesaError; use serde_json::json; use wiremock::matchers::{method, path}; use wiremock::{Mock, ResponseTemplate}; +use crate::get_mpesa_client; + #[tokio::test] async fn stk_push_success_success() { let (client, server) = get_mpesa_client!(); diff --git a/tests/mpesa-rust/transaction_reversal_test.rs b/tests/mpesa-rust/transaction_reversal_test.rs index a5b39ad9a..017ac4583 100644 --- a/tests/mpesa-rust/transaction_reversal_test.rs +++ b/tests/mpesa-rust/transaction_reversal_test.rs @@ -1,9 +1,10 @@ -use crate::get_mpesa_client; use mpesa::MpesaError; use serde_json::json; use wiremock::matchers::{method, path}; use wiremock::{Mock, ResponseTemplate}; +use crate::get_mpesa_client; + #[tokio::test] async fn transaction_reversal_success() { let (client, server) = get_mpesa_client!(); diff --git a/tests/mpesa-rust/transaction_status_test.rs b/tests/mpesa-rust/transaction_status_test.rs index b0011c1a2..46f0aa008 100644 --- a/tests/mpesa-rust/transaction_status_test.rs +++ b/tests/mpesa-rust/transaction_status_test.rs @@ -1,5 +1,4 @@ use mpesa::MpesaError; - use serde_json::json; use wiremock::matchers::{method, path}; use wiremock::{Mock, ResponseTemplate};