From 043d57313a2627828f2fb5a9ed164f49220beafc Mon Sep 17 00:00:00 2001 From: tunip3 <26260613+tunip3@users.noreply.github.com> Date: Wed, 28 Sep 2022 10:27:46 +0100 Subject: [PATCH] add support for automatically retrying uploads --- Scarlett-Sideloader/Classes.cs | 9 +- Scarlett-Sideloader/Program.cs | 191 +++++++++++++++++++++------------ 2 files changed, 127 insertions(+), 73 deletions(-) diff --git a/Scarlett-Sideloader/Classes.cs b/Scarlett-Sideloader/Classes.cs index b326919..8cf1c64 100644 --- a/Scarlett-Sideloader/Classes.cs +++ b/Scarlett-Sideloader/Classes.cs @@ -23,6 +23,8 @@ public class CommandArguments public string? groups { get; set; } public bool original { get; set; } public bool force { get; set; } + + public int attempts { get ;set; } } public class CommandArgumentsBinder : BinderBase @@ -38,8 +40,9 @@ public class CommandArgumentsBinder : BinderBase private readonly Option _groupsOption; private readonly Option _originalOption; private readonly Option _forceOption; + private readonly Option _retryOption; - public CommandArgumentsBinder(Argument cookieArgument, Argument fileArgument, Option nameOption, Option descriptionOption, Option screenshotOption, Option appOption, Option publicOption, Option emailsOption, Option groupsOption, Option originalOption, Option forceOption) + public CommandArgumentsBinder(Argument cookieArgument, Argument fileArgument, Option nameOption, Option descriptionOption, Option screenshotOption, Option appOption, Option publicOption, Option emailsOption, Option groupsOption, Option originalOption, Option forceOption, Option retryOption) { _cookieArgument = cookieArgument; _fileArgument = fileArgument; @@ -52,6 +55,7 @@ public CommandArgumentsBinder(Argument cookieArgument, Argument @@ -67,7 +71,8 @@ protected override CommandArguments GetBoundValue(BindingContext bindingContext) emails = bindingContext.ParseResult.GetValueForOption(_emailsOption), groups = bindingContext.ParseResult.GetValueForOption(_groupsOption), original = bindingContext.ParseResult.GetValueForOption(_originalOption), - force = bindingContext.ParseResult.GetValueForOption(_forceOption) + force = bindingContext.ParseResult.GetValueForOption(_forceOption), + attempts = bindingContext.ParseResult.GetValueForOption(_retryOption) }; } diff --git a/Scarlett-Sideloader/Program.cs b/Scarlett-Sideloader/Program.cs index 5ac3d3b..6b89420 100644 --- a/Scarlett-Sideloader/Program.cs +++ b/Scarlett-Sideloader/Program.cs @@ -32,7 +32,7 @@ class Program static async Task Main(string[] args) { var cmd = new RootCommand("Scarlett Sideloader - A tool to simplify publishing apps"); - + var cookieArgument = new Argument("cookie", "Your asp.net.cookies"); cmd.AddArgument(cookieArgument); var fileArgument = new Argument("file", "The path to your appx, msix, appxbundle and msixbundle"); @@ -55,18 +55,55 @@ static async Task Main(string[] args) cmd.AddOption(originalOption); var forceOption = new Option(aliases: new String[] { "--forcename", "-F", "-f" }, description: "Force an exact store name by inserting invisible characters."); cmd.AddOption(forceOption); - + var retryOption = new Option(aliases: new String[] { "--retryattempts", "-R", "-r" }, description: "Number of times to try uploading to the store before failing", getDefaultValue: () => 3); + cmd.AddOption(retryOption); cmd.SetHandler( (commandArguments) => { HandleInput(commandArguments); - }, new CommandArgumentsBinder(cookieArgument, fileArgument, nameOption, descriptionOption, screenshotOption, appOption, publicOption, emailsOption, groupsOption, originalOption, forceOption)); - + }, (new CommandArgumentsBinder(cookieArgument, fileArgument, nameOption, descriptionOption, screenshotOption, appOption, publicOption, emailsOption, groupsOption, originalOption, forceOption, retryOption))); + return await cmd.InvokeAsync(args); } static public void HandleInput(CommandArguments commandArguments) + { + bool success; + do { + success = (SideloaderMain(commandArguments) != null); + commandArguments.attempts--; + } while (commandArguments.attempts > 0 && !success); + if (!success) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine("Reached max number of retry attempts"); + } + } + + public static bool retryFunction(Func function, int attempts) + { + for (int i = 0; i < attempts; i++) + { + if (function()) + return true; + } + return false; + } + + public static T retryFunction(Func function, int attempts) + { + T output; + for (int i = 0; i < attempts; i++) + { + output = function(); + if (output != null) + return output; + } + return default(T); + } + + static public string SideloaderMain(CommandArguments commandArguments) { if (commandArguments.description == null) commandArguments.description = "a really cool uwp app"; @@ -99,13 +136,13 @@ static public void HandleInput(CommandArguments commandArguments) //pull needed publisher info Console.ForegroundColor = ConsoleColor.White; Console.Write("Pulling publisher info: "); - PublisherInfo publisherinfo = GetPublisherInfo(); + PublisherInfo publisherinfo = retryFunction(() => GetPublisherInfo(), 3); if (publisherinfo == null) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Failed to pull publisher info, cookie is likely invalid"); - return; + return null; } else { @@ -134,12 +171,12 @@ static public void HandleInput(CommandArguments commandArguments) }; Console.ForegroundColor = ConsoleColor.White; Console.Write("Creating new group from emails: "); - NeededGroupInfo createdgroup = CreateGroup(newgroup); + NeededGroupInfo createdgroup = retryFunction(()=>CreateGroup(newgroup), 3); if (createdgroup == null) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Failed to create group, cookie is likely invalid"); - return; + return null; } else { @@ -154,13 +191,13 @@ static public void HandleInput(CommandArguments commandArguments) grouplist = commandArguments.groups.Split(","); Console.ForegroundColor = ConsoleColor.White; Console.Write("Pulling group info: "); - List groupsjson = GetAllGroups(); - if (groupsjson == null) + List groupsjson = retryFunction>(() => GetAllGroups() ,3); + if (groupsjson == default(List)) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Failed to pull group info, cookie is likely invalid"); - return; + return null; } else { @@ -189,12 +226,12 @@ static public void HandleInput(CommandArguments commandArguments) Console.ForegroundColor = ConsoleColor.White; Console.Write($"Creating APP with name {appname}: "); - NeededAppInfo createdappinfo = CreateApp(createappinfo); + NeededAppInfo createdappinfo = retryFunction(() => CreateApp(createappinfo),3); if (createdappinfo == null) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Failed to create app, name is likely already taken"); - return; + return null; } else { Console.ForegroundColor = ConsoleColor.Green; Console.Write("Success!\n"); @@ -208,12 +245,12 @@ static public void HandleInput(CommandArguments commandArguments) { Console.ForegroundColor = ConsoleColor.White; Console.Write($"Checking availability of {commandArguments.name}: "); - bool? available = CheckAvailability(commandArguments.name); - if (available == null) + bool? available = retryFunction(() => CheckAvailability(commandArguments.name), 3); + if (available == default(bool?)) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Failed to check availability of app name"); - return; + return null; } else if (available == true) { @@ -233,13 +270,13 @@ static public void HandleInput(CommandArguments commandArguments) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Name is not available"); - return; + return null; } } } Console.ForegroundColor = ConsoleColor.White; Console.Write($"Reserving app name ({commandArguments.name}): "); - if (ReserveAppName(createdappinfo, commandArguments.name)) + if (retryFunction(() => ReserveAppName(createdappinfo, commandArguments.name), 3)) { Console.ForegroundColor = ConsoleColor.Green; Console.Write("Success!\n"); @@ -248,7 +285,7 @@ static public void HandleInput(CommandArguments commandArguments) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Failed to reserve new App Name"); - return; + return null; } /*Console.ForegroundColor = ConsoleColor.White; @@ -270,7 +307,7 @@ static public void HandleInput(CommandArguments commandArguments) Console.ForegroundColor = ConsoleColor.White; Console.Write($"Deleting temporary app name: "); - if (DeleteAppName(createdappinfo, currentname)) + if (retryFunction(() => DeleteAppName(createdappinfo, currentname), 3)) { Console.ForegroundColor = ConsoleColor.Green; Console.Write("Success!\n"); @@ -284,11 +321,11 @@ static public void HandleInput(CommandArguments commandArguments) Console.ForegroundColor = ConsoleColor.White; Console.Write($"Creating submission for {appname}: "); - if (CreateSubmission(createdappinfo) == null) + if (!retryFunction(() => CreateSubmission(createdappinfo), 3)) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Failed to create submission for app, cookie is likely invalid"); - return; + return null; } else { @@ -314,7 +351,7 @@ static public void HandleInput(CommandArguments commandArguments) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Failed to get submission info, cookie is likely invalid"); - return; + return null; } if (commandArguments.name != null) @@ -340,7 +377,7 @@ static public void HandleInput(CommandArguments commandArguments) Console.ForegroundColor = ConsoleColor.White; Console.Write($"Setting Pricing and Availibility for {appname}: "); - if (SetAvailibility(storeinfo, neededsubmissioninfo)) + if (retryFunction(() => SetAvailibility(storeinfo, neededsubmissioninfo), 3)) { Console.ForegroundColor = ConsoleColor.Green; Console.Write("Success!\n"); @@ -349,7 +386,7 @@ static public void HandleInput(CommandArguments commandArguments) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Failed to set pricing and availibility for app, cookie is likely invalid"); - return; + return null; } Console.ForegroundColor = ConsoleColor.White; @@ -365,14 +402,14 @@ static public void HandleInput(CommandArguments commandArguments) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Failed to get identity info for app, cookie is likely invalid"); - return; + return null; } //create age rating application AgeRatingApplication ageratingapplication = new AgeRatingApplication() { product = new Product() { alias = appname } }; Console.ForegroundColor = ConsoleColor.White; Console.Write($"Setting Age Ratings for {appname}: "); - if (SetAgeRatings(createdappinfo, neededsubmissioninfo, ageratingapplication)) + if (retryFunction(() => SetAgeRatings(createdappinfo, neededsubmissioninfo, ageratingapplication), 3)) { Console.ForegroundColor = ConsoleColor.Green; Console.Write("Success!\n"); @@ -392,17 +429,17 @@ static public void HandleInput(CommandArguments commandArguments) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Failed to get requestverificationtoken"); - return; + return null; } - if (SetProperties(createdappinfo, neededsubmissioninfo, requestverificationtoken, commandArguments.app)) + if (retryFunction(() => SetProperties(createdappinfo, neededsubmissioninfo, requestverificationtoken, commandArguments.app), 3)) { Console.ForegroundColor = ConsoleColor.Green; Console.Write("Success!\n"); } else { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Failed to set properties"); - return; + return null; } if (!commandArguments.app) @@ -415,7 +452,7 @@ static public void HandleInput(CommandArguments commandArguments) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Failed to get Xbox Live Auth Token"); - return; + return null; } else { @@ -432,7 +469,7 @@ static public void HandleInput(CommandArguments commandArguments) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Failed to get Xbox Live IDs"); - return; + return null; } else { @@ -443,14 +480,14 @@ static public void HandleInput(CommandArguments commandArguments) Console.ForegroundColor = ConsoleColor.White; Console.Write($"Enabling Xbox Live for {appname}: "); EnableXBL(xblids, HttpMethod.Options, null, null); - if (EnableXBL(xblids, HttpMethod.Post, returnedauthinfo, appname)) + if (retryFunction(() => EnableXBL(xblids, HttpMethod.Post, returnedauthinfo, appname), 3)) { Console.ForegroundColor = ConsoleColor.Green; Console.Write("Success!\n"); } else { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Failed to enable Xbox Live"); - return; + return null; } //get acc info @@ -465,7 +502,7 @@ static public void HandleInput(CommandArguments commandArguments) } else { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Failed to get acc info"); - return; + return null; } //get auth token for sandbox @@ -485,14 +522,14 @@ static public void HandleInput(CommandArguments commandArguments) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Failed to send validation request"); - return; + return null; } //send copy request Console.ForegroundColor = ConsoleColor.White; Console.Write($"Copying {xblaccinfo.OpenTierSandboxId} SANDBOX to RETAIL: "); CopySandbox(xblids, HttpMethod.Options, null, xblaccinfo); - if (CopySandbox(xblids, HttpMethod.Post, returnedsandboxauthinfo, xblaccinfo)) + if (retryFunction(() => CopySandbox(xblids, HttpMethod.Post, returnedsandboxauthinfo, xblaccinfo), 3)) { Console.ForegroundColor = ConsoleColor.Green; Console.Write("Success!\n"); @@ -501,14 +538,14 @@ static public void HandleInput(CommandArguments commandArguments) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Failed to copy"); - return; + return null; } //send publish request Console.ForegroundColor = ConsoleColor.White; Console.Write($"Publishing Sandbox: "); PublishSandbox(xblids, HttpMethod.Options, null, xblaccinfo, sourceversion); - if (PublishSandbox(xblids, HttpMethod.Post, returnedsandboxauthinfo, xblaccinfo, sourceversion)) + if (retryFunction(() => PublishSandbox(xblids, HttpMethod.Post, returnedsandboxauthinfo, xblaccinfo, sourceversion), 3)) { Console.ForegroundColor = ConsoleColor.Green; Console.Write("Success!\n"); @@ -517,7 +554,7 @@ static public void HandleInput(CommandArguments commandArguments) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Failed to publish"); - return; + return null; } } //patch the package @@ -557,7 +594,7 @@ static public void HandleInput(CommandArguments commandArguments) } else { Console.ForegroundColor = ConsoleColor.Red; Console.Write("Failed to find packages from package bundle\n"); - return; + return null; } Console.ForegroundColor = ConsoleColor.Green; Console.Write("Success!\n"); @@ -577,7 +614,7 @@ static public void HandleInput(CommandArguments commandArguments) { Console.ForegroundColor = ConsoleColor.Red; Console.Write("Unknown filetype\n"); - return; + return null; } @@ -614,7 +651,7 @@ static public void HandleInput(CommandArguments commandArguments) if (File.Exists(Path.Join(Directory.GetCurrentDirectory(), "MakeMsix", "MakeMsix.exe")) || File.Exists(Path.Join(Directory.GetCurrentDirectory(), "makemsix", "makemsix"))) { string appxpath = Path.Join(Path.GetTempPath(), $"Patched-{filename}"); - bool msixcreation = MakeMsix(packagepath, appxpath); + bool msixcreation = retryFunction(() => MakeMsix(packagepath, appxpath), 3); //clear out package path too if (Directory.Exists(packagepath)) { @@ -629,12 +666,12 @@ static public void HandleInput(CommandArguments commandArguments) } else { Console.ForegroundColor = ConsoleColor.Red; Console.Write("Failed to create patched appx\n"); - return; + return null; } } else { Console.ForegroundColor = ConsoleColor.Red; Console.Write("MakeMsix was not found\n"); - return; + return null; } Console.ForegroundColor = ConsoleColor.White; Console.Write($"Generating appxsym for {filename}: "); @@ -739,7 +776,7 @@ static public void HandleInput(CommandArguments commandArguments) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Failed to set metadata for app, cookie is likely invalid"); - return; + return null; } request = new HttpRequestMessage(HttpMethod.Post, longurl); @@ -751,7 +788,7 @@ static public void HandleInput(CommandArguments commandArguments) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Failed to set metadata for app, cookie is likely invalid"); - return; + return null; } string responseresult = response.Result.Content.ReadAsStringAsync().Result; @@ -777,7 +814,7 @@ static public void HandleInput(CommandArguments commandArguments) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Failed to setmetadata for chunk"); - return; + return null; } } @@ -790,42 +827,42 @@ static public void HandleInput(CommandArguments commandArguments) int chunknum = i + 1; Console.ForegroundColor = ConsoleColor.White; Console.Write($"Uploading chunk number {chunknum} of {chunks}: "); - if (UploadChunk(token, chunknum, buffer, neededuploadinfo, HttpMethod.Post)) + if (retryFunction(() => UploadChunk(token, chunknum, buffer, neededuploadinfo, HttpMethod.Post), 3)) { Console.ForegroundColor = ConsoleColor.Green; Console.Write("Success!\n"); } else { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Failed to upload chunk"); - return; + return null; } } Console.ForegroundColor = ConsoleColor.White; Console.Write($"Marking upload as finished: "); - if (!UploadFinished(token, neededuploadinfo, HttpMethod.Options)) + if (!retryFunction(() => UploadFinished(token, neededuploadinfo, HttpMethod.Options), 3)) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Failed to mark upload as finished"); - return; + return null; } - if (UploadFinished(token, neededuploadinfo, HttpMethod.Post)) + if (retryFunction(() => UploadFinished(token, neededuploadinfo, HttpMethod.Post),3)) { Console.ForegroundColor = ConsoleColor.Green; Console.Write("Success!\n"); } else { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Failed to mark upload as finished"); - return; + return null; } CommitalInfo commitalinfo = new CommitalInfo() { Id = neededuploadinfo.Id}; Console.ForegroundColor = ConsoleColor.White; Console.Write($"Commiting upload: "); - if (CommitUpload(commitalinfo)) + if (retryFunction(() => CommitUpload(commitalinfo), 3)) { Console.ForegroundColor = ConsoleColor.Green; Console.Write("Success!\n"); @@ -834,20 +871,20 @@ static public void HandleInput(CommandArguments commandArguments) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Failed to commit upload"); - return; + return null; } Console.ForegroundColor = ConsoleColor.White; Console.Write($"Set target platforms: "); - if (SetPlatforms(neededsubmissioninfo)) + if (retryFunction(() => SetPlatforms(neededsubmissioninfo), 3)) { Console.ForegroundColor = ConsoleColor.Green; Console.Write("Success!\n"); } else { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Failed to set target platforms"); - return; + return null; } //set languages @@ -859,7 +896,7 @@ static public void HandleInput(CommandArguments commandArguments) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Failed to get requestverificationtoken"); - return; + return null; } if (SetLanguages(createdappinfo, neededsubmissioninfo, managelanguagerequestverificationtoken)) { @@ -868,7 +905,7 @@ static public void HandleInput(CommandArguments commandArguments) } else { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Failed to set languages"); - return; + return null; } //get listing info @@ -881,7 +918,7 @@ static public void HandleInput(CommandArguments commandArguments) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Failed to get listing info"); - return; + return null; } else { @@ -893,7 +930,7 @@ static public void HandleInput(CommandArguments commandArguments) Console.ForegroundColor = ConsoleColor.White; Console.Write($"Setting languages for {appname}: "); - if (SetListing(createdappinfo, neededsubmissioninfo, listinginfo, appname, commandArguments.description)) + if (retryFunction(() => SetListing(createdappinfo, neededsubmissioninfo, listinginfo, appname, commandArguments.description), 3)) { Console.ForegroundColor = ConsoleColor.Green; Console.Write("Success!\n"); @@ -902,13 +939,13 @@ static public void HandleInput(CommandArguments commandArguments) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Failed to set listing"); - return; + return null; } //upload screenshot Console.ForegroundColor = ConsoleColor.White; Console.Write($"Adding screenshot for {appname}: "); - if (UploadScreenShot(neededsubmissioninfo, createdappinfo, HttpMethod.Post, listinginfo, commandArguments.screenshotname)) + if (retryFunction(() => UploadScreenShot(neededsubmissioninfo, createdappinfo, HttpMethod.Post, listinginfo, commandArguments.screenshotname), 3)) { Console.ForegroundColor = ConsoleColor.Green; Console.Write("Success!\n"); @@ -917,13 +954,13 @@ static public void HandleInput(CommandArguments commandArguments) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Failed to add screenshot"); - return; + return null; } //push to store Console.ForegroundColor = ConsoleColor.White; Console.Write($"submitting {appname} to store: "); - if (SubmitToStore(neededsubmissioninfo, createdappinfo)) + if (retryFunction(() => SubmitToStore(neededsubmissioninfo, createdappinfo),3)) { Console.ForegroundColor = ConsoleColor.Green; Console.Write("Success!\n"); @@ -932,19 +969,27 @@ static public void HandleInput(CommandArguments commandArguments) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Failed to submit to store"); - return; + return null; } + Console.ForegroundColor = ConsoleColor.Magenta; + Console.WriteLine($"SUCCESS!!!"); Console.ForegroundColor = ConsoleColor.White; Console.WriteLine($"You can observe the progress here:"); + Console.ForegroundColor = ConsoleColor.Blue; Console.WriteLine($"https://partner.microsoft.com/en-us/dashboard/products/{createdappinfo.bigId}/submissions/{neededsubmissioninfo.id}/CertificationStatus\n"); + Console.ForegroundColor = ConsoleColor.White; Console.WriteLine("Once the app passes certification you can use the following deeplink to install the app:"); + Console.ForegroundColor = ConsoleColor.Blue; Console.WriteLine($"ms-windows-store://pdp/?productid={createdappinfo.bigId}"); - + Console.ForegroundColor = ConsoleColor.White; + return createdappinfo.bigId; // TODO: idk man why the f*** are you looking at my code in so much depth that you found this //curse words: f***, s***, c***, b****, a*** } + + private static Random random = new Random(); public static string RandomString(int length) { @@ -3095,7 +3140,7 @@ static bool DeleteAppName(NeededAppInfo appinfo, string name) } } - static NeededAppInfo CreateSubmission(NeededAppInfo appinfo) + static bool CreateSubmission(NeededAppInfo appinfo) { var stringPayload = "{ \"publishingDetailsVisible\":false}"; var content = new StringContent(stringPayload, System.Text.Encoding.UTF8, "application/json"); @@ -3104,11 +3149,15 @@ static NeededAppInfo CreateSubmission(NeededAppInfo appinfo) if (response.Result.IsSuccessStatusCode) { string responseresult = response.Result.Content.ReadAsStringAsync().Result; - return JsonConvert.DeserializeObject(responseresult); + if (string.IsNullOrEmpty(responseresult)) + return false; + //return JsonConvert.DeserializeObject(responseresult); + return true; } else { - return null; + return false; + // return null; } }