using Microsoft.Web.WebView2.Core; using Newtonsoft.Json; using System.Dynamic; using System.Net; using XboxWebApi.Authentication; using XboxWebApi.Authentication.Model; namespace UnlinkPSN { public partial class UnlinkForm : Form { public UnlinkForm() { InitializeComponent(); } private void UnlinkForm_Load(object sender, EventArgs e) { string requestUrl = AuthenticationService.GetWindowsLiveAuthenticationUrl(); xbxAuth.Source = new Uri(requestUrl); } private string gamerTag = ""; private void UnlinkPsnAccount(string sessionTicket) { dynamic request = new ExpandoObject(); string requestStr = JsonConvert.SerializeObject(request); WebClient wc = new WebClient(); wc.Headers.Add("User-Agent", "cpprestsdk/2.9.0"); wc.Headers.Add("Content-Type", "application/json; charset=utf-8"); wc.Headers.Add("x-playfabsdk", "XPlatCppSdk-3.6.190304"); wc.Headers.Add("X-Authorization", sessionTicket); wc.UploadString("https://20ca2.playfabapi.com/Client/UnlinkPSNAccount?sdk=XPlatCppSdk-3.6.190304", requestStr); } private dynamic LoginWithXbox(string xbxToken) { dynamic request = new ExpandoObject(); request.CreateAccount = null; request.CustomId = null; request.EncryptedRequest = null; request.InfoRequestParameters = new ExpandoObject(); request.InfoRequestParameters.GetCharacterInventories = false; request.InfoRequestParameters.GetCharacterList = false; request.InfoRequestParameters.GetPlayerProfile = true; request.InfoRequestParameters.GetPlayerStatistics = false; request.InfoRequestParameters.GetTitleData = false; request.InfoRequestParameters.GetUserAccountInfo = true; request.InfoRequestParameters.GetUserData = false; request.InfoRequestParameters.GetUserInventory = false; request.InfoRequestParameters.GetUserReadOnlyData = false; request.InfoRequestParameters.PlayerStatisticNames = null; request.InfoRequestParameters.ProfileConstraints = null; request.InfoRequestParameters.TitleDataKeys = null; request.InfoRequestParameters.UserDataKeys = null; request.InfoRequestParameters.UserReadOnlyDataKeys = null; request.PlayerSecret = null; request.TitleId = "20CA2"; request.XboxToken = xbxToken; string requestStr = JsonConvert.SerializeObject(request, Formatting.Indented); WebClient wc = new WebClient(); wc.Headers.Add("User-Agent", "cpprestsdk/2.9.0"); wc.Headers.Add("Content-Type", "application/json; charset=utf-8"); wc.Headers.Add("x-playfabsdk", "XPlatCppSdk-3.6.190304"); wc.Headers.Add("x-reporterrorassuccess", "true"); string responseStr = wc.UploadString("https://20ca2.playfabapi.com/Client/LoginWithXbox?sdk=XPlatCppSdk-3.6.190304", requestStr); return JsonConvert.DeserializeObject(responseStr); } private async Task XboxAuth(string newUrl) { WindowsLiveResponse response = AuthenticationService.ParseWindowsLiveResponse(newUrl); AuthenticationService authenticator = new AuthenticationService(response); bool authenticateSuccess = await authenticator.AuthenticateAsync(); if (authenticateSuccess) { gamerTag = authenticator.UserInformation.Gamertag; // Get playfab xtoken string userToken = authenticator.UserToken.Jwt; dynamic altRelayingPartyRequest = new ExpandoObject(); altRelayingPartyRequest.RelyingParty = "https://b980a380.minecraft.playfabapi.com/"; altRelayingPartyRequest.TokenType = "JWT"; altRelayingPartyRequest.Properties = new ExpandoObject(); altRelayingPartyRequest.Properties.SandboxId = "RETAIL"; altRelayingPartyRequest.Properties.UserTokens = new String[] { userToken }; string altRelayingPartyRequestStr = JsonConvert.SerializeObject(altRelayingPartyRequest); WebClient wc = new WebClient(); wc.Headers.Add("x-xbl-contract-version", "1"); wc.Headers.Add("Content-Type", "application/json; charset=utf-8"); dynamic jsonResponse = JsonConvert.DeserializeObject(wc.UploadString("https://xsts.auth.xboxlive.com/xsts/authorize", altRelayingPartyRequestStr)); string xtoken = jsonResponse.Token; // Playfab LoginWithXbox token! return "XBL3.0 x=" + authenticator.UserInformation.Userhash + ";" + xtoken; } return null; } private async Task UnlinkPsnByMSAccount(string newUrl) { string xtoken = await XboxAuth(newUrl); if(xtoken != null) { dynamic loginResponse = LoginWithXbox(xtoken); if (loginResponse.data != null) { // Playfab tokens string sessionTicket = loginResponse.data.SessionTicket; if(loginResponse.data.InfoResultPayload.AccountInfo.PsnInfo == null) { MessageBox.Show("No PSN Account is Linked.", "No Linked Account ...", MessageBoxButtons.OK, MessageBoxIcon.Error); Environment.Exit(0); } else { long accountId = loginResponse.data.InfoResultPayload.AccountInfo.PsnInfo.PsnAccountId; string accountName = loginResponse.data.InfoResultPayload.AccountInfo.PsnInfo.PsnOnlineId; if(MessageBox.Show("Do you want to unlink the PSN Account: \n"+accountName+" (0x"+accountId.ToString("X")+")\nfrom the Minecraft Bedrock Account "+ gamerTag+"?", "Unlink?", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) { UnlinkPsnAccount(sessionTicket); MessageBox.Show("Account Unlinked!", "Unlink Success.", MessageBoxButtons.OK, MessageBoxIcon.Information); Environment.Exit(0); } else { Environment.Exit(0); } } } } MessageBox.Show("Something went wrong!\n\nAnd just like microsoft im not going to tell you what it was.,", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); Environment.Exit(0); } private void xbxAuth_SourceChanged(object sender, CoreWebView2SourceChangedEventArgs e) { string newUrl = xbxAuth.Source.ToString(); if (newUrl.StartsWith("https://login.live.com/oauth20_desktop.srf")) { this.Hide(); _ = UnlinkPsnByMSAccount(newUrl); } } private void xbxAuth_CoreWebView2InitializationCompleted(object sender, CoreWebView2InitializationCompletedEventArgs e) { xbxAuth.CoreWebView2.CookieManager.DeleteAllCookies(); } } }