Skip to content

Commit

Permalink
Merge pull request #49 from namecare/develop
Browse files Browse the repository at this point in the history
chore: Release 2.0.0
  • Loading branch information
tikhop authored Apr 3, 2024
2 parents 8bff0dc + 4767fdd commit 51d5ded
Show file tree
Hide file tree
Showing 11 changed files with 224 additions and 42 deletions.
32 changes: 16 additions & 16 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,36 +14,36 @@ edition = "2021"
[dependencies]

# Cryptography
x509-parser = { version = "0.15.1", features = ["verify", "validate"] }
jsonwebtoken = { version = "9.2.0" }
ring = "0.17.7"
x509-parser = { version = "0.16.0", features = ["verify", "validate"] }
jsonwebtoken = { version = "9.3.0" }
ring = "0.17.8"
pem = "3.0.3"

# Serialization
serde = { version = "1.0.195", features = ["derive"] }
serde_json = { version = "1.0.111" }
serde_with = { version = "3.5.0", features = ["chrono"] }
serde = { version = "1.0.197", features = ["derive"] }
serde_json = { version = "1.0.115" }
serde_with = { version = "3.7.0", features = ["chrono"] }
serde_repr = "0.1.18"
uuid = { version = "1.7.0", features = ["serde", "v4"] }
chrono = { version = "0.4.32", features = ["serde"] }
base64 = "0.21.7"
asn1-rs = { version = "0.5.2", optional = true }
uuid = { version = "1.8.0", features = ["serde", "v4"] }
chrono = { version = "0.4.37", features = ["serde"] }
base64 = "0.22.0"
asn1-rs = { version = "0.6.1", optional = true }

# Networking
reqwest = { version = "0.11.23", features = ["json"], optional = true }
reqwest = { version = "0.12.2", features = ["json"], optional = true }

# Utils
thiserror = "1.0.56"
thiserror = "1.0.58"

# Tools
regex = { version = "1.10.3", optional = true }
regex = { version = "1.10.4", optional = true }
url = "2.5.0"


[dev-dependencies]
http = "1.0.0"
tokio = { version = "1.35.1", features = ["test-util", "macros"] }
jsonwebtoken = { version = "9.2.0", features = ["use_pem"] }
http = "1.1.0"
tokio = { version = "1.37.0", features = ["test-util", "macros"] }
jsonwebtoken = { version = "9.3.0", features = ["use_pem"] }

[features]
api-client = ["dep:reqwest"]
Expand Down
13 changes: 13 additions & 0 deletions assets/signedExternalPurchaseTokenNotification.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"notificationType": "EXTERNAL_PURCHASE_TOKEN",
"subtype": "UNREPORTED",
"notificationUUID": "002e14d5-51f5-4503-b5a8-c3a1af68eb20",
"version": "2.0",
"signedDate": 1698148900000,
"externalPurchaseToken": {
"externalPurchaseId": "b2158121-7af9-49d4-9561-1f588205523e",
"tokenCreationDate": 1698148950000,
"appAppleId": 55555,
"bundleId": "com.example"
}
}
13 changes: 13 additions & 0 deletions assets/signedExternalPurchaseTokenSandboxNotification.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"notificationType": "EXTERNAL_PURCHASE_TOKEN",
"subtype": "UNREPORTED",
"notificationUUID": "002e14d5-51f5-4503-b5a8-c3a1af68eb20",
"version": "2.0",
"signedDate": 1698148900000,
"externalPurchaseToken": {
"externalPurchaseId": "SANDBOX_b2158121-7af9-49d4-9561-1f588205523e",
"tokenCreationDate": 1698148950000,
"appAppleId": 55555,
"bundleId": "com.example"
}
}
27 changes: 13 additions & 14 deletions src/api_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,6 @@ mod tests {
use http::StatusCode;
use serde_json::Value;
use chrono::DateTime;
use chrono::NaiveDateTime;
use url::Url;
use uuid::Uuid;
use base64::prelude::BASE64_STANDARD_NO_PAD;
Expand Down Expand Up @@ -750,11 +749,11 @@ mod tests {

let send_attempt_items = vec![
SendAttemptItem {
attempt_date: DateTime::from_naive_utc_and_offset(NaiveDateTime::from_timestamp_opt(1698148900, 0).unwrap(), Utc).into(),
attempt_date: DateTime::from_timestamp(1698148900, 0),
send_attempt_result: SendAttemptResult::NoResponse.into(),
},
SendAttemptItem {
attempt_date: DateTime::from_naive_utc_and_offset(NaiveDateTime::from_timestamp_opt(1698148950, 0).unwrap(), Utc).into(),
attempt_date: DateTime::from_timestamp(1698148950, 0),
send_attempt_result: SendAttemptResult::Success.into(),
},
];
Expand All @@ -777,8 +776,8 @@ mod tests {
}));

let notification_history_request = NotificationHistoryRequest {
start_date: DateTime::from_naive_utc_and_offset(NaiveDateTime::from_timestamp_opt(1698148900, 0).unwrap(), Utc).into(),
end_date: DateTime::from_naive_utc_and_offset(NaiveDateTime::from_timestamp_opt(1698148950, 0).unwrap(), Utc).into(),
start_date:DateTime::from_timestamp(1698148900, 0),
end_date:DateTime::from_timestamp(1698148950, 0),
notification_type: NotificationTypeV2::Subscribed.into(),
notification_subtype: Subtype::InitialBuy.into(),
transaction_id: "999733843".to_string().into(),
Expand All @@ -794,11 +793,11 @@ mod tests {
signed_payload: "signed_payload_one".to_string().into(),
send_attempts: vec![
SendAttemptItem {
attempt_date: DateTime::from_naive_utc_and_offset(NaiveDateTime::from_timestamp_opt(1698148900, 0).unwrap(), Utc).into(),
attempt_date: DateTime::from_timestamp(1698148900, 0),
send_attempt_result: SendAttemptResult::NoResponse.into(),
},
SendAttemptItem {
attempt_date: DateTime::from_naive_utc_and_offset(NaiveDateTime::from_timestamp_opt(1698148950, 0).unwrap(), Utc).into(),
attempt_date: DateTime::from_timestamp(1698148950, 0),
send_attempt_result: SendAttemptResult::Success.into(),
},
].into(),
Expand All @@ -807,7 +806,7 @@ mod tests {
signed_payload: "signed_payload_two".to_string().into(),
send_attempts: vec![
SendAttemptItem {
attempt_date: DateTime::from_naive_utc_and_offset(NaiveDateTime::from_timestamp_opt(1698148800, 0).unwrap(), Utc).into(),
attempt_date: DateTime::from_timestamp(1698148800, 0),
send_attempt_result: SendAttemptResult::CircularRedirect.into(),
},
].into(),
Expand Down Expand Up @@ -839,8 +838,8 @@ mod tests {
}));

let request = TransactionHistoryRequest {
start_date: DateTime::from_naive_utc_and_offset(NaiveDateTime::from_timestamp_opt(123, 455000000).unwrap(), Utc).into(),
end_date: DateTime::from_naive_utc_and_offset(NaiveDateTime::from_timestamp_opt(123, 456000000).unwrap(), Utc).into(),
start_date: DateTime::from_timestamp(123, 455000000),
end_date: DateTime::from_timestamp(123, 456000000),
product_ids: vec!["com.example.1", "com.example.2"].into_iter().map(String::from).collect::<Vec<String>>().into(),
product_types: vec![ProductType::Consumable, ProductType::AutoRenewable].into(),
sort: Order::Ascending.into(),
Expand Down Expand Up @@ -1014,8 +1013,8 @@ mod tests {
let client = app_store_server_api_client_with_body_from_file("assets/models/transactionHistoryResponseWithMalformedEnvironment.json", StatusCode::OK, None);

let request = TransactionHistoryRequest {
start_date: DateTime::from_naive_utc_and_offset(NaiveDateTime::from_timestamp_opt(123, 455000000).unwrap(), Utc).into(),
end_date: DateTime::from_naive_utc_and_offset(NaiveDateTime::from_timestamp_opt(123, 456000000).unwrap(), Utc).into(),
start_date: DateTime::from_timestamp(123, 455000000),
end_date: DateTime::from_timestamp(123, 456000000),
product_ids: vec!["com.example.1".to_string(), "com.example.2".to_string()].into(),
product_types: vec![ProductType::Consumable, ProductType::AutoRenewable].into(),
sort: Some(Order::Ascending),
Expand All @@ -1033,8 +1032,8 @@ mod tests {
let client = app_store_server_api_client_with_body_from_file("assets/models/transactionHistoryResponseWithMalformedAppAppleId.json", StatusCode::OK, None);

let request = TransactionHistoryRequest {
start_date: DateTime::from_naive_utc_and_offset(NaiveDateTime::from_timestamp_opt(123, 455000000).unwrap(), Utc).into(),
end_date: DateTime::from_naive_utc_and_offset(NaiveDateTime::from_timestamp_opt(123, 456000000).unwrap(), Utc).into(),
start_date: DateTime::from_timestamp(123, 455000000),
end_date: DateTime::from_timestamp(123, 456000000),
product_ids: vec!["com.example.1".to_string(), "com.example.2".to_string()].into(),
product_types: vec![ProductType::Consumable, ProductType::AutoRenewable].into(),
sort: Some(Order::Ascending),
Expand Down
37 changes: 37 additions & 0 deletions src/primitives/external_purchase_token.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use serde_with::formats::Flexible;
use serde_with::TimestampMilliSeconds;

/// The payload data that contains an external purchase token.
///
/// [externalPurchaseToken](https://developer.apple.com/documentation/appstoreservernotifications/externalpurchasetoken)
#[serde_with::serde_as]
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct ExternalPurchaseToken {
/// The field of an external purchase token that uniquely identifies the token.
///
/// [externalPurchaseId](https://developer.apple.com/documentation/appstoreservernotifications/externalpurchaseid)
#[serde(rename = "externalPurchaseId")]
pub external_purchase_id: Option<String>,

/// The field of an external purchase token that contains the UNIX date, in milliseconds,
/// when the system created the token.
///
/// [tokenCreationDate](https://developer.apple.com/documentation/appstoreservernotifications/tokencreationdate)
#[serde(rename = "tokenCreationDate")]
#[serde_as(as = "Option<TimestampMilliSeconds<String, Flexible>>")]
pub token_creation_date: Option<DateTime<Utc>>,

/// The unique identifier of an app in the App Store.
///
/// [appAppleId](https://developer.apple.com/documentation/appstoreservernotifications/appappleid)
#[serde(rename = "appAppleId")]
pub app_apple_id: Option<i64>,

/// The bundle identifier of an app.
///
/// [bundleId](https://developer.apple.com/documentation/appstoreservernotifications/bundleid)
#[serde(rename = "bundleId")]
pub bundle_id: Option<String>,
}
4 changes: 2 additions & 2 deletions src/primitives/jws_transaction_decoded_payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,10 @@ pub struct JWSTransactionDecodedPayload {
/// [currency](https://developer.apple.com/documentation/appstoreserverapi/currency)
pub currency: Option<String>,

/// The price of the in-app purchase or subscription offer that you configured in App Store Connect, as an integer.
/// The price, in milliunits, of the in-app purchase or subscription offer that you configured in App Store Connect.
///
/// [price](https://developer.apple.com/documentation/appstoreserverapi/price)
pub price: Option<i32>,
pub price: Option<i64>,

/// The payment mode you configure for an introductory offer, promotional offer, or offer code on an auto-renewable subscription.
///
Expand Down
1 change: 1 addition & 0 deletions src/primitives/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,4 @@ pub mod transaction_history_request;
pub mod transaction_info_response;
pub mod transaction_reason;
pub mod user_status;
pub mod external_purchase_token;
2 changes: 2 additions & 0 deletions src/primitives/notification_type_v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,6 @@ pub enum NotificationTypeV2 {
RenewalExtension,
#[serde(rename = "REFUND_REVERSED")]
RefundReversed,
#[serde(rename = "EXTERNAL_PURCHASE_TOKEN")]
ExternalPurchaseToken,
}
12 changes: 10 additions & 2 deletions src/primitives/response_body_v2_decoded_payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::primitives::summary::Summary;
use ::chrono::{DateTime, Utc};
use serde_with::formats::Flexible;
use serde_with::TimestampMilliSeconds;
use crate::primitives::external_purchase_token::ExternalPurchaseToken;

/// A decoded payload containing the version 2 notification data.
///
Expand All @@ -31,7 +32,7 @@ pub struct ResponseBodyV2DecodedPayload {
pub notification_uuid: String,

/// The object that contains the app metadata and signed renewal and transaction information.
/// The data and summary fields are mutually exclusive. The payload contains one of the fields, but not both.
/// The data, summary, and externalPurchaseToken fields are mutually exclusive. The payload contains only one of these fields.
///
/// [data](https://developer.apple.com/documentation/appstoreservernotifications/data)
pub data: Option<Data>,
Expand All @@ -49,8 +50,15 @@ pub struct ResponseBodyV2DecodedPayload {
pub signed_date: Option<DateTime<Utc>>,

/// The summary data that appears when the App Store server completes your request to extend a subscription renewal date for eligible subscribers.
/// The data and summary fields are mutually exclusive. The payload contains one of the fields, but not both.
/// The data, summary, and externalPurchaseToken fields are mutually exclusive. The payload contains only one of these fields.
///
/// [summary](https://developer.apple.com/documentation/appstoreservernotifications/summary)
pub summary: Option<Summary>,

/// This field appears when the notificationType is EXTERNAL_PURCHASE_TOKEN.
/// The data, summary, and externalPurchaseToken fields are mutually exclusive. The payload contains only one of these fields.
///
/// [externalPurchaseToken](https://developer.apple.com/documentation/appstoreservernotifications/externalpurchasetoken)
#[serde(rename = "externalPurchaseToken")]
pub external_purchase_token: Option<ExternalPurchaseToken>
}
2 changes: 2 additions & 0 deletions src/primitives/subtype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,6 @@ pub enum Subtype {
Summary,
#[serde(rename = "FAILURE")]
Failure,
#[serde(rename = "UNREPORTED")]
Unreported,
}
Loading

0 comments on commit 51d5ded

Please sign in to comment.