在花了很多天试图解决这个问题之后,我想我开始破解这个问题了。我不确定(也许我是)Apple 是否故意让这变得困难,但这比它应该的更困难。
这是我什至获取联系人必须做的事情(完全不知道如何添加、更新、删除它们):
步骤 1> 使用 Apple id 和密码请求令牌。如果 2FA 被激活,您将不会在响应标头中收到身份验证令牌和身份验证用户 cookie。但这没关系,我们将在下一步中讨论。请注意,现在很可能提取 AUTH-TOKEN 和 AUTH-USER 将失败。此外,我们将在稍后需要的响应中收到地区信息和联系链接。
public sealed partial class MainPage : Page
{
String contactLink = "";
String authToken = "";
String authUser = "";
public MainPage()
{
this.InitializeComponent();
}
private async void IcloudBtn_Click(object sender, RoutedEventArgs e)
{
HttpResponseHeaderCollection respHeaders = await ContactApple();
ContactsBlock.Text += "CONTACT LINK: " + contactLink + "\n";
ContactsBlock.Text += authToken + "\n";
ContactsBlock.Text += authUser + "\n";
}
private async void GetToken_Click(object sender, RoutedEventArgs e)
{
HttpResponseHeaderCollection respHeaders = await ContactApple(AuthenticationCode.Text);
ContactsBlock.Text += "CONTACT LINK: " + contactLink + "\n";
ContactsBlock.Text += authToken + "\n";
ContactsBlock.Text += authUser + "\n";
}
private async void GetContacts_Click(object sender, RoutedEventArgs e)
{
Uri contactUri = new Uri(contactLink + "/co/startup?locale=en_US&order=last%2Cfirst");
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("Origin", "https://www.icloud.com");
client.DefaultRequestHeaders.Add("Cookie", authToken + ";" + authUser + ";");
HttpResponseMessage hrm = await client.GetAsync(contactUri);
JObject contactJson = JObject.Parse(await hrm.Content.ReadAsStringAsync());
ContactsBlock.Text += contactJson["contacts"];
}
private async Task<HttpResponseHeaderCollection> ContactApple(String authentication = "")
{
// The apple id and the password
String appleId = "AppleID";
String password = "Password" + authentication;
// https://stackoverflow.com/questions/31457068/get-icloud-contact-list-in-c-sharp?noredirect=1&lq=1
// Post request will have this in the content
String data = "{\"apple_id\":" + appleId + ", \"password\":" + password + ", \"extended_login\":true}";
HttpStringContent content = new HttpStringContent(data, UnicodeEncoding.Utf8);
// The URI to get the tokens from:
Uri requestUri = new Uri("https://setup.icloud.com/setup/ws/1/accountLogin");
// Create an instance of the HttpClient (Windows.Web.Http)
HttpClient client = new HttpClient();
// Add Origin = https://www.icloud.com in the header.
client.DefaultRequestHeaders.Add("Origin", "https://www.icloud.com");
// Post request and read response as JSON object (NewtonSoft)
HttpResponseMessage hrm = await client.PostAsync(requestUri, content);
JObject resp = JObject.Parse(await hrm.Content.ReadAsStringAsync());
// Get the URL to the contacts
contactLink = (String)resp["webservices"]["contacts"]["url"];
// Read the headers for AUTH-TOKEN and AUTH-USER Cookies,
HttpResponseHeaderCollection headers = hrm.Headers;
if (headers.ContainsKey("Set-Cookie"))
{
String cookie = headers["Set-Cookie"];
char[] separators = { ';', ',' };
String[] tokens = cookie.Split(separators);
foreach (String token in tokens)
{
int length = token.Length;
if (token.Contains("X-APPLE-WEBAUTH-TOKEN"))
{
authToken = token;
}
if (token.Contains("X-APPLE-WEBAUTH-USER"))
{
authUser = token;
}
}
}
return headers;
}
}
步骤 2> 如果 2FA 被激活,您将在您的 Apple 设备上收到授权登录并使用提供的代码登录的请求。获得代码后,重复与上述相同的步骤,只需附加通过在授权代码文本字段中提供您的密码。
请注意,您需要输入授权码。
步骤 3> 希望您现在已经收到获取联系人所需的令牌。现在,您可以在获取令牌并附加“/co/startup?locale=XXXXX&order=last%2Cfirst”时使用响应正文中获取的联系人链接来获取联系人
请注意,您必须使用适合您需要的语言环境。我需要使用“en_US”,因为这是我在响应中的语言环境中的内容。您需要使用请求中返回的语言环境。
XAML:
<Page
x:Class="AddressBook.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:AddressBook"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel x:Name="MainStack">
<Button x:Name="IcloudBtn" Content="Request Code" Click="IcloudBtn_Click"/>
<TextBox x:Name="AuthenticationCode" Text="Authentication Code here." TextWrapping="Wrap"/>
<Button x:Name="GetToken" Content="Get Token" Click="GetToken_Click"/>
<Button x:Name="GetContacts" Content="Get Contacts" Click="GetContacts_Click"/>
<TextBox x:Name="ContactsBlock" TextWrapping="Wrap"/>
</StackPanel>
</Page>
但是,我仍然不知道如何实际操作联系人列表。我想如果我发现了,我会在这里更新。