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

chore: Release 2.0.0 #49

Merged
merged 6 commits into from
Apr 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading