pub mod appstore;
pub mod playstore;
#[cfg(test)]
mod tests {
use crate::appstore::model::{AppStoreVerifyError, IAPRequest};
use crate::appstore::validator::{IAPClient, IAPVerifier};
use crate::playstore::validator::{
verify_signature, IABClient, IABProduct, IABSubscription, SignatureError,
};
#[tokio::test]
async fn appstore_verify_success() {
let v = IAPRequest {
receipt_data: std::env::var("IAP_TEST_IOS_RECEIPT").unwrap(),
password: None,
exclude_old_transactions: false,
};
let client = IAPClient::new(reqwest::Client::new());
let res = client.verify(&v).await;
assert_eq!(false, res.is_err());
assert_eq!(true, res.unwrap().error().is_none());
}
#[tokio::test]
async fn appstore_verify_error() {
let v = IAPRequest {
receipt_data: String::from("aaa"),
password: None,
exclude_old_transactions: false,
};
let client = IAPClient::new(reqwest::Client::new());
let res = client.verify(&v).await;
assert_eq!(false, res.is_err());
assert_eq!(
res.unwrap().error().unwrap(),
AppStoreVerifyError::InvalidReceiptData
);
}
async fn create_iab_client() -> IABClient {
let decoded_key =
base64::decode(std::env::var("IAP_TEST_JSONKEY").unwrap().as_bytes()).unwrap();
return IABClient::new(
&decoded_key,
hyper::Client::builder().build(hyper_rustls::HttpsConnector::with_native_roots()),
)
.await;
}
fn assert_invalid_value(res: google_androidpublisher3::Result<()>) {
assert_eq!(true, res.is_err());
match res.err().unwrap() {
google_androidpublisher3::client::Error::BadRequest(e) => {
assert_eq!("Invalid Value", e.error.message);
assert_eq!(400, e.error.code);
}
_ => assert_eq!(false, true),
};
}
fn assert_no_application(res: google_androidpublisher3::Result<()>) {
assert_eq!(true, res.is_err());
match res.err().unwrap() {
google_androidpublisher3::client::Error::BadRequest(e) => {
assert_eq!(
"No application was found for the given package name.",
e.error.message
);
assert_eq!(404, e.error.code);
}
_ => assert_eq!(false, true),
};
}
#[tokio::test]
async fn playstore_verify_success() {
let client = create_iab_client().await;
let res = client
.verify(
"com.yoshidan.UnityIAP",
"item_18",
std::env::var("IAP_TEST_ANDROID_TOKEN").unwrap().as_str(),
)
.await;
assert_eq!(false, res.is_err());
let value = res.unwrap();
assert_eq!(value.acknowledgement_state.unwrap(), 1);
assert_eq!(
value.obfuscated_external_account_id.unwrap(),
"npbunneskhjD3q6TLd/yHFexJM6SQej93ZebDOheqGc="
);
}
#[tokio::test]
async fn playstore_verify_error() {
let client = create_iab_client().await;
let res = client.verify("nopackage", "item_18", "hogehoge").await;
assert_invalid_value(Err(res.err().unwrap()));
}
#[tokio::test]
async fn playstore_acknowledge_acknowledged() {
let client = create_iab_client().await;
let res = client
.acknowledge(
"com.yoshidan.UnityIAP",
"item_1",
std::env::var("IAP_TEST_ANDROID_TOKEN").unwrap().as_str(),
None,
)
.await;
assert_eq!(true, res.is_err());
match res.err().unwrap() {
google_androidpublisher3::client::Error::BadRequest(e) => {
assert_eq!(
"The purchase is not in a valid state to perform the desired operation.",
e.error.message
);
assert_eq!(400, e.error.code);
}
_ => assert_eq!(false, true),
};
}
#[tokio::test]
async fn playstore_acknowledge_error() {
let client = create_iab_client().await;
let res = client
.acknowledge("nopackage", "item_18", "hoge", None)
.await;
assert_invalid_value(res);
}
#[tokio::test]
async fn playstore_acknowledge_subscription_error() {
let client = create_iab_client().await;
let res = client
.acknowledge_subscription("nopackage", "item_18", "hoge", None)
.await;
assert_invalid_value(res);
}
#[tokio::test]
async fn playstore_cancel_subscription_error() {
let client = create_iab_client().await;
let res = client
.cancel_subscription("nopackage", "item_18", "hoge")
.await;
assert_invalid_value(res);
}
#[tokio::test]
async fn playstore_refund_subscription_error() {
let client = create_iab_client().await;
let res = client
.refund_subscription("nopackage", "item_18", "hoge")
.await;
assert_no_application(res);
}
#[tokio::test]
async fn playstore_revoke_subscription_error() {
let client = create_iab_client().await;
let res = client
.revoke_subscription("nopackage", "item_18", "hoge")
.await;
assert_no_application(res);
}
#[tokio::test]
async fn playstore_rerify_subscription_error() {
let client = create_iab_client().await;
let res = client
.verify_subscription("nopackage", "item_18", "hoge")
.await;
assert_invalid_value(Err(res.err().unwrap()));
}
#[tokio::test]
async fn playstore_verify_signature_success() {
let receipt = r#"{"orderId":"GPA.xxxx-xxxx-xxxx-xxxxx","packageName":"my.package","productId":"myproduct","purchaseTime":1437564796303,"purchaseState":0,"developerPayload":"user001","purchaseToken":"some-token"}"#;
let pub_key = b"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDGvModvVUrqJ9C5fy8J77ZQ7JDC6+tf5iK8C74/3mjmcvwo4nmprCgzR/BQIEuZWJi8KX+jiJUXKXF90JPsXHkKAPq6A1SCga7kWvs/M8srMpjNS9zJdwZF+eDOR0+lJEihO04zlpAV9ybPJ3Q621y1HUeVpwdxDNLQpJTuIflnwIDAQAB";
let signature = b"gj0N8LANKXOw4OhWkS1UZmDVUxM1UIP28F6bDzEp7BCqcVAe0DuDxmAY5wXdEgMRx/VM1Nl2crjogeV60OqCsbIaWqS/ZJwdP127aKR0jk8sbX36ssyYZ0DdZdBdCr1tBZ/eSW1GlGuD/CgVaxns0JaWecXakgoV7j+RF2AFbS4=";
assert_eq!(
false,
verify_signature(pub_key, receipt.as_bytes(), signature).is_err()
)
}
#[tokio::test]
async fn playstore_verify_signature_error() {
let receipt = r#"{"orderId":"GPA.xxxx-xxxx-xxxx-xxxx","packageName":"my.package","productId":"myproduct","purchaseTime":1437564796303,"purchaseState":0,"developerPayload":"user001","purchaseToken":"some-token"}"#;
let pub_key = b"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDGvModvVUrqJ9C5fy8J77ZQ7JDC6+tf5iK8C74/3mjmcvwo4nmprCgzR/BQIEuZWJi8KX+jiJUXKXF90JPsXHkKAPq6A1SCga7kWvs/M8srMpjNS9zJdwZF+eDOR0+lJEihO04zlpAV9ybPJ3Q621y1HUeVpwdxDNLQpJTuIflnwIDAQAB";
let signature = b"gj0N8LANKXOw4OhWkS1UZmDVUxM1UIP28F6bDzEp7BCqcVAe0DuDxmAY5wXdEgMRx/VM1Nl2crjogeV60OqCsbIaWqS/ZJwdP127aKR0jk8sbX36ssyYZ0DdZdBdCr1tBZ/eSW1GlGuD/CgVaxns0JaWecXakgoV7j+RF2AFbS4=";
let err = verify_signature(pub_key, receipt.as_bytes(), signature)
.err()
.unwrap();
assert_eq!(
SignatureError::VerifyError("verification error".to_string()),
err
);
}
#[tokio::test]
async fn playstore_verify_signature_pubkey_error() {
let receipt = r#"{"orderId":"GPA.xxxx-xxxx-xxxx-xxxx","packageName":"my.package","productId":"myproduct","purchaseTime":1437564796303,"purchaseState":0,"developerPayload":"user001","purchaseToken":"some-token"}"#;
let pub_key = b"KIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDGvModvVUrqJ9C5fy8J77ZQ7JDC6+tf5iK8C74/3mjmcvwo4nmprCgzR/BQIEuZWJi8KX+jiJUXKXF90JPsXHkKAPq6A1SCga7kWvs/M8srMpjNS9zJdwZF+eDOR0+lJEihO04zlpAV9ybPJ3Q621y1HUeVpwdxDNLQpJTuIflnwIDAQAB";
let signature = b"";
match verify_signature(pub_key, receipt.as_bytes(), signature)
.err()
.unwrap()
{
SignatureError::X509Error(s) => {
assert_eq!("Parsing Error: Der(InvalidTag)".to_string(), s);
}
_ => assert_eq!(false, true),
}
}
}