Skip to content

Instantly share code, notes, and snippets.

@mxswd
Created March 6, 2022 02:27
Show Gist options
  • Save mxswd/4a9b59c5ac267fa856870ca2806b3b60 to your computer and use it in GitHub Desktop.
Save mxswd/4a9b59c5ac267fa856870ca2806b3b60 to your computer and use it in GitHub Desktop.
CloudKit Server-to-server API in C#
using System;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace YoApp
{
public class CloudKit
{
string keyId;
string stage;
string container;
IHttpClientFactory httpClientFactory;
ECDsa key;
public CloudKit(string apiStage, IHttpClientFactory httpClientFactory)
{
this.httpClientFactory = httpClientFactory;
container = "iCloud.app.name";
if (apiStage == "Prod")
{
keyId = "a5cf........";
stage = "production";
} else
{
keyId = "b336.........";
stage = "development";
}
key = ECDsa.Create();
key.ImportECPrivateKey(Convert.FromBase64String(Environment.GetEnvironmentVariable("SECRET_KEY_BASE64")), out _);
}
public async Task<JObject> makeRequest(string endpoint, dynamic arguments)
{
var httpClient = httpClientFactory.CreateClient();
httpClient.BaseAddress = new Uri("https://api.apple-cloudkit.com");
var path = $"/database/1/{container}/{stage}/public/{endpoint}";
var datetime = DateTime.UtcNow;
var formattedDate = datetime.ToString("yyyy-MM-ddTHH:mm:ssZ");
var body = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(arguments));
var bodyHash = Convert.ToBase64String(SHA256.HashData(body));
var signatureInput = $"{formattedDate}:{bodyHash}:{path}";
var signature = Convert.ToBase64String(key.SignData(Encoding.UTF8.GetBytes(signatureInput), HashAlgorithmName.SHA256, DSASignatureFormat.Rfc3279DerSequence));
using (var request = new HttpRequestMessage(HttpMethod.Post, path))
{
request.Content = new ByteArrayContent(body);
request.Headers.Add("X-Apple-CloudKit-Request-KeyID", keyId);
request.Headers.Add("X-Apple-CloudKit-Request-ISO8601Date", formattedDate);
request.Headers.Add("X-Apple-CloudKit-Request-SignatureV1", signature);
var response = await httpClient.SendAsync(request);
var data = await response.Content.ReadAsStringAsync();
return JObject.Parse(data);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment