Something went wrong. Try again.
shiny crates that could help rewrite iTunes or smth
Something went wrong. Try again.
15 kB · 573 lines
Rust
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574use plist::Dictionary;use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize)]pub struct EmptyResponse {}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]pub struct TeamID(String);
impl TeamID { pub fn as_str(&self) -> &str { &self.0 }}
impl From<String> for TeamID { fn from(value: String) -> Self { Self(value) }}
impl From<&str> for TeamID { fn from(value: &str) -> Self { Self(value.to_string()) }}
impl AsRef<str> for TeamID { fn as_ref(&self) -> &str { self.as_str() }}
#[derive(Debug, Deserialize)]#[serde(rename_all = "camelCase")]pub struct DeveloperTeam { pub name: String, pub team_id: TeamID, #[serde(rename = "type", default)] pub team_type: Option<String>,}
#[derive(Debug, Deserialize)]#[serde(rename_all = "camelCase")]pub struct Developer { pub developer_id: String, pub person_id: u64, pub first_name: String, pub last_name: String, pub ds_first_name: String, pub ds_last_name: String, pub email: String, pub developer_status: String, // TODO: DeveloperStatus enum}
#[derive(Debug, Deserialize)]#[serde(rename_all = "camelCase")]pub struct DeveloperView { pub teams: Vec<DeveloperTeam>, pub developer: Developer,}
#[derive(Debug, Serialize)]pub struct ViewDeveloperAction {}impl_developer_action!(ViewDeveloperAction, "viewDeveloper.action", DeveloperView);
#[derive(Debug, Deserialize)]#[serde(rename_all = "camelCase")]pub struct ListTeamsResponse { pub teams: Vec<DeveloperTeam>,}
#[derive(Debug, Serialize)]pub struct ListTeamsAction {}impl_developer_action!(ListTeamsAction, "listTeams.action", ListTeamsResponse);
#[derive(Debug, Deserialize)]#[serde(rename_all = "camelCase")]pub struct DeveloperDevice { pub device_id: String, pub name: String, pub device_number: String,}
#[derive(Debug, Deserialize)]pub struct ListDevicesResponse { pub devices: Vec<DeveloperDevice>,}
#[derive(Debug, Serialize)]#[serde(rename_all = "camelCase")]pub struct ListDevicesAction { pub team_id: TeamID,}
impl_developer_action!( ListDevicesAction, "listDevices.action", ListDevicesResponse, [crate::IOS, crate::TvOS, crate::WatchOS]);
#[derive(Debug, Deserialize)]pub struct AddDeviceResponse { pub device: DeveloperDevice,}
#[derive(Debug, Serialize)]#[serde(rename_all = "camelCase")]pub struct AddDeviceAction { pub team_id: TeamID, pub name: String, pub device_number: String,}
impl_developer_action!( AddDeviceAction, "addDevice.action", AddDeviceResponse, [crate::IOS, crate::TvOS, crate::WatchOS]);
#[derive(Debug, Serialize)]#[serde(rename_all = "camelCase")]pub struct DeleteDeviceAction { pub team_id: TeamID, pub device_id: String,}
impl_developer_action!( DeleteDeviceAction, "deleteDevice.action", EmptyResponse, [crate::IOS, crate::TvOS, crate::WatchOS]);
#[derive(Debug, Deserialize)]#[serde(rename_all = "camelCase")]pub struct DevelopmentCertificate { pub name: String, pub certificate_id: String, pub serial_number: String, #[serde(with = "serde_bytes")] pub cert_content: Vec<u8>, #[serde(default)] pub machine_name: String,}
#[derive(Debug, Deserialize)]pub struct ListAllDevelopmentCertsResponse { pub certificates: Vec<DevelopmentCertificate>,}
#[derive(Debug, Serialize)]#[serde(rename_all = "camelCase")]pub struct ListAllDevelopmentCertsAction { pub team_id: TeamID,}
impl_developer_action!( ListAllDevelopmentCertsAction, "listAllDevelopmentCerts.action", ListAllDevelopmentCertsResponse, [crate::IOS, crate::TvOS, crate::WatchOS]);
#[derive(Debug, Serialize)]#[serde(rename_all = "camelCase")]pub struct RevokeDevelopmentCertAction { pub team_id: TeamID, pub serial_number: String,}
impl_developer_action!( RevokeDevelopmentCertAction, "revokeDevelopmentCert.action", EmptyResponse, [crate::IOS, crate::TvOS, crate::WatchOS]);
#[derive(Debug, Deserialize)]#[serde(rename_all = "camelCase")]pub struct DevelopmentCertRequest { pub cert_request_id: String,}
#[derive(Debug, Deserialize)]#[serde(rename_all = "camelCase")]pub struct SubmitDevelopmentCsrResponse { pub cert_request: DevelopmentCertRequest,}
#[derive(Debug, Serialize)]#[serde(rename_all = "camelCase")]pub struct SubmitDevelopmentCsrAction { pub team_id: TeamID, pub machine_id: String, pub machine_name: String, pub csr_content: String,}
impl_developer_action!( SubmitDevelopmentCsrAction, "submitDevelopmentCSR.action", SubmitDevelopmentCsrResponse, [crate::IOS, crate::TvOS, crate::WatchOS]);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]pub enum AppIdFeature { #[serde(rename = "push")] Push, #[serde(rename = "iCloud")] ICloud, #[serde(rename = "inAppPurchase")] InAppPurchase, #[serde(rename = "gameCenter")] GameCenter, #[serde(rename = "pass")] Passbook, #[serde(rename = "IAD53UNK2F")] InterAppAudio, #[serde(rename = "V66P55NK2I")] VpnConfiguration, #[serde(rename = "dataProtection")] DataProtection, #[serde(rename = "SKC3T5S89Y")] AssociatedDomains, #[serde(rename = "APG3427HIY")] AppGroup, #[serde(rename = "HK421J6T7P")] HealthKit, #[serde(rename = "homeKit")] HomeKit, #[serde(rename = "WC421J6T7P")] WirelessAccessory, #[serde(rename = "cloudKitVersion")] CloudKitVersion,}
impl AppIdFeature { pub fn as_str(self) -> &'static str { match self { AppIdFeature::Push => "push", AppIdFeature::ICloud => "iCloud", AppIdFeature::InAppPurchase => "inAppPurchase", AppIdFeature::GameCenter => "gameCenter", AppIdFeature::Passbook => "pass", AppIdFeature::InterAppAudio => "IAD53UNK2F", AppIdFeature::VpnConfiguration => "V66P55NK2I", AppIdFeature::DataProtection => "dataProtection", AppIdFeature::AssociatedDomains => "SKC3T5S89Y", AppIdFeature::AppGroup => "APG3427HIY", AppIdFeature::HealthKit => "HK421J6T7P", AppIdFeature::HomeKit => "homeKit", AppIdFeature::WirelessAccessory => "WC421J6T7P", AppIdFeature::CloudKitVersion => "cloudKitVersion", } }}
impl AsRef<str> for AppIdFeature { fn as_ref(&self) -> &str { (*self).as_str() }}
#[derive(Debug, Deserialize)]#[serde(rename_all = "camelCase")]pub struct AppId { pub app_id_id: String, pub identifier: String, pub name: String, pub features: Dictionary, #[serde(default)] pub expiration_date: Option<plist::Date>,}
#[derive(Debug, Deserialize)]#[serde(rename_all = "camelCase")]pub struct ListAppIdsResponse { pub app_ids: Vec<AppId>, #[serde(default = "max_u64")] pub max_quantity: u64, #[serde(default = "max_u64")] pub available_quantity: u64,}
fn max_u64() -> u64 { u64::MAX}
#[derive(Debug, Serialize)]#[serde(rename_all = "camelCase")]pub struct ListAppIdsAction { pub team_id: TeamID,}
impl_developer_action!( ListAppIdsAction, "listAppIds.action", ListAppIdsResponse, [crate::IOS, crate::TvOS, crate::WatchOS]);
#[derive(Debug, Serialize)]#[serde(rename_all = "camelCase")]pub struct AddAppIdAction { pub identifier: String, pub name: String, pub team_id: TeamID,}
impl_developer_action!( AddAppIdAction, "addAppId.action", EmptyResponse, [crate::IOS, crate::TvOS, crate::WatchOS]);
#[derive(Debug, Deserialize)]pub struct UpdatedAppId { pub features: Dictionary,}
#[derive(Debug, Deserialize)]#[serde(rename_all = "camelCase")]pub struct UpdateAppIdResponse { pub app_id: UpdatedAppId,}
#[derive(Debug, Serialize)]#[serde(rename_all = "camelCase")]pub struct UpdateAppIdAction { pub app_id_id: String, pub team_id: TeamID, #[serde( skip_serializing_if = "Option::is_none", serialize_with = "serialize_optional_value" )] pub name: Option<String>, /// Optional legacy feature flags, encoded at the request's top level. #[serde(flatten, skip_serializing_if = "Option::is_none")] pub features: Option<Dictionary>, /// Requested entitlements, encoded as a nested dictionary. #[serde( skip_serializing_if = "Option::is_none", serialize_with = "serialize_optional_value" )] pub entitlements: Option<Dictionary>,}
// plist's map serializer tags Option::Some; these fields must carry the value directly.fn serialize_optional_value<T: Serialize, S: serde::Serializer>( value: &Option<T>, serializer: S,) -> Result<S::Ok, S::Error> { match value { Some(value) => value.serialize(serializer), None => serializer.serialize_none(), }}
impl_developer_action!( UpdateAppIdAction, "updateAppId.action", UpdateAppIdResponse, [crate::IOS, crate::TvOS, crate::WatchOS]);
#[derive(Debug, Serialize)]#[serde(rename_all = "camelCase")]pub struct DeleteAppIdAction { pub app_id_id: String, pub team_id: TeamID,}
impl_developer_action!( DeleteAppIdAction, "deleteAppId.action", EmptyResponse, [crate::IOS, crate::TvOS, crate::WatchOS]);
#[derive(Debug, Deserialize)]#[serde(rename_all = "camelCase")]pub struct ApplicationGroup { pub application_group: String, pub name: String, pub identifier: String,}
#[derive(Debug, Deserialize)]#[serde(rename_all = "camelCase")]pub struct ListApplicationGroupsResponse { pub application_group_list: Vec<ApplicationGroup>,}
#[derive(Debug, Serialize)]#[serde(rename_all = "camelCase")]pub struct ListApplicationGroupsAction { pub team_id: TeamID,}
impl_developer_action!( ListApplicationGroupsAction, "listApplicationGroups.action", ListApplicationGroupsResponse, [crate::IOS, crate::TvOS, crate::WatchOS]);
#[derive(Debug, Deserialize)]#[serde(rename_all = "camelCase")]pub struct AddApplicationGroupResponse { pub application_group: ApplicationGroup,}
#[derive(Debug, Serialize)]#[serde(rename_all = "camelCase")]pub struct AddApplicationGroupAction { pub identifier: String, pub name: String, pub team_id: TeamID,}
impl_developer_action!( AddApplicationGroupAction, "addApplicationGroup.action", AddApplicationGroupResponse, [crate::IOS, crate::TvOS, crate::WatchOS]);
#[derive(Debug, Serialize)]#[serde(rename_all = "camelCase")]pub struct AssignApplicationGroupToAppIdAction { pub app_id_id: String, /// The portal replaces the App ID's groups with these, and refuses an empty list. pub application_groups: Vec<String>, pub team_id: TeamID,}
impl_developer_action!( AssignApplicationGroupToAppIdAction, "assignApplicationGroupToAppId.action", EmptyResponse, [crate::IOS, crate::TvOS, crate::WatchOS]);
#[derive(Debug, Deserialize)]#[serde(rename_all = "camelCase")]pub struct ProvisioningProfile { pub provisioning_profile_id: String, pub name: String, #[serde(with = "serde_bytes")] pub encoded_profile: Vec<u8>,}
#[derive(Debug, Deserialize)]#[serde(rename_all = "camelCase")]pub struct DownloadTeamProvisioningProfileResponse { pub provisioning_profile: ProvisioningProfile,}
#[derive(Debug, Serialize)]#[serde(rename_all = "camelCase")]pub struct DownloadTeamProvisioningProfileAction { pub app_id_id: String, pub team_id: TeamID,}
impl_developer_action!( DownloadTeamProvisioningProfileAction, "downloadTeamProvisioningProfile.action", DownloadTeamProvisioningProfileResponse, [crate::IOS, crate::TvOS, crate::WatchOS]);
#[cfg(test)]mod tests { use super::*; use crate::{DeveloperActionBase, IOSRequest}; use plist::Value;
fn update_request( features: Option<Dictionary>, entitlements: Option<Dictionary>, ) -> Dictionary { let request = IOSRequest::new(UpdateAppIdAction { app_id_id: String::from("APPID"), team_id: TeamID::from("TEAM"), name: None, features, entitlements, }); assert_eq!( IOSRequest::<UpdateAppIdAction>::action(), "ios/updateAppId.action" ); request.request() }
#[test] fn app_id_updates_encode_entitlements_as_a_dictionary() { let entitlements = Dictionary::from_iter([ ("application-identifier", Value::from("com.example.app")), ( "keychain-access-groups", Value::Array(vec![Value::from("com.example.app.*")]), ), ]); let request = update_request(None, Some(entitlements.clone())); assert_eq!(request.get("appIdId"), Some(&Value::from("APPID"))); assert_eq!(request.get("teamId"), Some(&Value::from("TEAM"))); assert_eq!( request.get("entitlements"), Some(&Value::Dictionary(entitlements)) ); assert!(!request.contains_key("application-identifier")); assert!(!request.contains_key("features")); assert!(!request.contains_key("name")); }
#[test] fn app_id_updates_keep_features_flattened_alongside_entitlements() { let features = Dictionary::from_iter([("APG3427HIY", Value::Boolean(true))]); let request = update_request(Some(features), Some(Dictionary::new())); assert_eq!(request.get("APG3427HIY"), Some(&Value::Boolean(true))); assert_eq!( request.get("entitlements"), Some(&Value::Dictionary(Dictionary::new())) ); assert!(!request.contains_key("features")); }
#[test] fn app_id_updates_encode_names_without_option_tags() { let request = IOSRequest::new(UpdateAppIdAction { app_id_id: String::from("APPID"), team_id: TeamID::from("TEAM"), name: Some(String::from("Example")), features: None, entitlements: None, }); assert_eq!(request.request().get("name"), Some(&Value::from("Example"))); }
#[test] fn app_id_updates_omit_unspecified_dictionaries() { let request = update_request(None, None); assert!(!request.contains_key("features")); assert!(!request.contains_key("entitlements")); }
#[test] fn application_groups_are_a_list() { let request = IOSRequest::new(AssignApplicationGroupToAppIdAction { app_id_id: String::from("8T4D9KSP2Q"), application_groups: vec![String::from("GQ2W8R5T3Y"), String::from("HN6M4K9P2X")], team_id: TeamID::from("ABCDE12345"), }); assert_eq!( IOSRequest::<AssignApplicationGroupToAppIdAction>::action(), "ios/assignApplicationGroupToAppId.action" ); assert_eq!( request.request().get("applicationGroups"), Some(&Value::Array(vec![ Value::from("GQ2W8R5T3Y"), Value::from("HN6M4K9P2X"), ])) ); }}