using Newtonsoft.Json; using System; using System.Dynamic; using System.Net; using System.Security.Cryptography; using System.Text; namespace PlayFab { public class PlayFab { public static string PLAYFAB_VERSION = "XPlatCppSdk-3.6.190304"; public static string CPP_REST_VERSION = "cpprestsdk/2.9.0"; public static string TITLE_ID = "20CA2"; public static string TITLE_SECRET = "S8RS53ZEIGMYTYG856U3U19AORWXQXF41J7FT3X9YCWAC7I35X"; public static byte[] PUBLIC_KEY = null; public static string ENTITY_TOKEN = null; public static string ENTITY_ID = null; public static string ENTITY_TYPE = null; public static dynamic GetProductInformation(string uuid) { dynamic dyn = new ExpandoObject(); dyn.ItemId = uuid; dyn.ETag = ""; return POST(dyn, "/Catalog/GetPublishedItem"); } public static dynamic Search(string query, string filter = "", int skip = 0, string orderBy= "creationDate DESC") { dynamic dyn = new ExpandoObject(); dyn.count = true; dyn.filter = filter; dyn.search = query; dyn.orderBy = orderBy; dyn.top = 300; dyn.skip = skip; return POST(dyn, "/Catalog/Search"); } public static dynamic POST(dynamic data, string url, string clientsecret = null, bool incSDK = false) { McClient wc = new McClient(); string body = JsonConvert.SerializeObject(data, (incSDK ? Formatting.Indented : Formatting.None)); // Pretend to be minecraft ... wc.Headers.Set("Accept", "application/json"); wc.Headers.Set("Accept-Language", "en-US"); wc.Headers.Set("Accept-Encoding", "gzip, deflate, br"); wc.Headers.Set("User-Agent", CPP_REST_VERSION); wc.Headers.Set("x-playfabsdk", PLAYFAB_VERSION); wc.Headers.Set("x-reporterrorassuccess", "true"); wc.Headers.Set("content-type", "application/json; charset=utf-8"); if (clientsecret != null) { string signature; string timestamp = DateTime.UtcNow.ToString("O"); using (SHA256 hash = SHA256.Create()) { string msg = body + "." + timestamp + "." + clientsecret; byte[] bytesToHash = Encoding.UTF8.GetBytes(msg); signature = Convert.ToBase64String(hash.ComputeHash(bytesToHash)); } wc.Headers.Set("x-playfab-signature", signature); wc.Headers.Set("x-playfab-timestamp", timestamp); } if (ENTITY_TOKEN != null) wc.Headers.Set("x-entitytoken", ENTITY_TOKEN); string response = wc.UploadString(GetPlayfabApiUrl() + url + (incSDK ? SdkMsg() : ""), body); dynamic resp = JsonConvert.DeserializeObject(response); wc.Dispose(); return resp.data; } public static string RefreshEntityTokenBullshit() { dynamic dyn = new ExpandoObject(); dyn.Entity = new ExpandoObject(); dyn.Entity.Id = ENTITY_ID; dyn.Entity.Type = ENTITY_TYPE; dynamic resp = POST(dyn, "/Authentication/GetEntityToken", null, true); ENTITY_TOKEN = resp.EntityToken.ToString(); return ENTITY_TOKEN; } public static string SdkMsg() { return "?sdk=" + PLAYFAB_VERSION; } public static string GenerateClientSecret() { Random r = new Random(Guid.NewGuid().GetHashCode()); byte[] clientSecret = new byte[0x20]; r.NextBytes(clientSecret); return Convert.ToBase64String(clientSecret); } public static string GenerateCustomId() { Random r = new Random(Guid.NewGuid().GetHashCode()); byte[] customId = new byte[0x10]; r.NextBytes(customId); return "MCPF" + BitConverter.ToString(customId).Replace("-", "").ToUpper(); } public static string GetPlayfabApiUrl() { return "https://" + TITLE_ID + ".playfabapi.com"; } // How 2 find TitleSharedSecret: // 1- delete all mc data // 2- open fiddler // 3- open minecraft // 4- check for https://20ca2.playfabapi.com/Client/GetTitlePublicKey... public static void GetPublicKeyAndMicrosoftTakesABigL() { dynamic dyn = new ExpandoObject(); dyn.TitleId = TITLE_ID; dyn.TitleSharedSecret = TITLE_SECRET; dynamic resp = POST(dyn, "/Client/GetTitlePublicKey", null, true); PUBLIC_KEY = Convert.FromBase64String(resp.RSAPublicKey.ToString()); } public static string EncryptCustomIdLoginToken(string customId, string clientSecret) { dynamic dyn = new ExpandoObject(); dyn.CustomId = customId; dyn.PlayerSecret = clientSecret; return EncryptRequest(JsonConvert.SerializeObject(dyn)); } public static string LoginWithCustomId(bool newUser = true, string customId = null, string clientSecret = null) { dynamic dyn = new ExpandoObject(); if (newUser) dyn.CreateAccount = true; else dyn.CreateAccount = null; dyn.CustomId = customId; if (clientSecret == null) clientSecret = GenerateClientSecret(); if (customId == null) customId = GenerateCustomId(); if (newUser) dyn.EncryptedRequest = EncryptCustomIdLoginToken(customId, clientSecret); else dyn.EncryptedRequest = null; dyn.InfoRequestParameters = new ExpandoObject(); dyn.InfoRequestParameters.GetCharacterInventories = false; dyn.InfoRequestParameters.GetCharacterList = false; dyn.InfoRequestParameters.GetPlayerProfile = true; dyn.InfoRequestParameters.GetPlayerStatistics = false; dyn.InfoRequestParameters.GetTitleData = false; dyn.InfoRequestParameters.GetUserAccountInfo = true; dyn.InfoRequestParameters.GetUserData = false; dyn.InfoRequestParameters.GetUserInventory = false; dyn.InfoRequestParameters.GetUserReadOnlyData = false; dyn.InfoRequestParameters.PlayerStatisticNames = null; dyn.InfoRequestParameters.ProfileConstraints = null; dyn.InfoRequestParameters.TitleDataKeys = null; dyn.InfoRequestParameters.UserDataKeys = null; dyn.InfoRequestParameters.UserReadOnlyDataKeys = null; dyn.PlayerSecret = null; dyn.TitleId = TITLE_ID; dynamic resp = POST(dyn, "/Client/LoginWithCustomID", newUser ? null : clientSecret, true); Config.WriteConfValue("CustomId", customId); Config.WriteConfValue("ClientSecret", clientSecret); ENTITY_TOKEN = resp.EntityToken.EntityToken.ToString(); ENTITY_ID = resp.PlayFabId.ToString(); ENTITY_TYPE = "master_player_account"; return ENTITY_TOKEN; } public static string EncryptRequest(string plaintext) { using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) { rsa.ImportCspBlob(PUBLIC_KEY); byte[] bytesToEncrypt = Encoding.UTF8.GetBytes(plaintext); byte[] encryptedBytes = rsa.Encrypt(bytesToEncrypt, false); return Convert.ToBase64String(encryptedBytes); } } public static string PullEntityTokenOutOfMyAss() { if (Config.GetConfValue("CustomId") == null && Config.GetConfValue("ClientSecret") == null) { GetPublicKeyAndMicrosoftTakesABigL(); LoginWithCustomId(); return RefreshEntityTokenBullshit(); } else { string customId = Config.GetConfValue("CustomId"); string clientSecret = Config.GetConfValue("ClientSecret"); LoginWithCustomId(false, customId, clientSecret); return RefreshEntityTokenBullshit(); } } } }