private static Dictionary <string, string> DecodeTickets() { Console.Write("Checking Title Keys validity against Nintendo CDN."); ConsoleUtils.PrintColorfulLine(ConsoleColor.Green, " This might take a while..."); ConsoleUtils.PrintColorfulLine( ConsoleColor.Green, "Parsing only Games and Addon DLCs. Ticket count might decrease as we weed out invalid tickets."); Func <string, bool> gameOrDlc = titleId => Nintendo3DSRelease.GetTitleType(titleId) == "Unknown Type" || Nintendo3DSRelease.GetTitleType(titleId) == "Addon DLC" || Nintendo3DSRelease.GetTitleType(titleId) == "3DS Game"; var ticketsDictionary = ParseDecTitleKeysBin(); ticketsDictionary = new SortedDictionary <string, string>( ticketsDictionary.Where(a => gameOrDlc(a.Key)).ToDictionary(a => a.Key, a => a.Value)); var validKeys = new Dictionary <string, string>(); var processedTickets = 0; var totalTickets = ticketsDictionary.Count; foreach (var pair in ticketsDictionary) { var titleId = pair.Key; var titleKey = pair.Value; var valid = CDNUtils.TitleKeyIsValid(titleId, titleKey); if (valid) { validKeys[titleId] = titleKey; const int TitleTypePad = 10; Console.Write('\r' + Nintendo3DSRelease.GetTitleType(titleId).PadRight(TitleTypePad) + pair.Key + ": Valid | "); ConsoleUtils.PrintColorful(ConsoleColor.Green, $"({++processedTickets}/{totalTickets} valid)"); } else { totalTickets--; } } Console.WriteLine(); Console.Write("Found "); ConsoleUtils.PrintColorful(ConsoleColor.Green, ticketsDictionary.Count - totalTickets); Console.WriteLine(" invalid tickets. Searching through databases for the valid ones..."); return(validKeys); }
public static void Main(string[] args) { ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true; Console.OutputEncoding = Encoding.UTF8; #if !DEBUG try { #endif PrintProgramVersion(); ProcessArgs(args); if (!File.Exists(Files.DecTitleKeysPath)) { ConsoleUtils.PrintColorfulLine( ConsoleColor.Red, "decTitleKeys.bin not found! Get it from Decrypt9. Press any key to exit."); Console.ReadKey(); Environment.Exit(1); } var decTitleKeysFile = File.ReadAllBytes(Files.DecTitleKeysPath); var computedHash = BitConversion.BytesToHex(MD5.Create().ComputeHash(decTitleKeysFile)); var shouldRecheck = false; if (!File.Exists(Files.DecTitleKeysMd5)) { File.WriteAllText(Files.DecTitleKeysMd5, computedHash); } else { var savedHash = File.ReadAllText(Files.DecTitleKeysMd5); if (savedHash != computedHash) { Console.WriteLine("Different decTitleKeys.bin found!"); Console.Write("Recheck titles? y/n: "); var keyChosen = Console.ReadKey().Key; if (keyChosen == ConsoleKey.Y) { shouldRecheck = true; File.WriteAllText(Files.DecTitleKeysMd5, computedHash); } } } if (args != null && args.Contains("-update")) { UpdateDependencies(); } else { Files.CheckFor3dsDb(); Files.CheckForGroovyCiaDb(); } var tickets = new Dictionary <string, string>(); if ((!File.Exists(Files.ValidTicketsPath) || new FileInfo(Files.ValidTicketsPath).Length == 0) || shouldRecheck) { Console.WriteLine("Decoding valid tickets..."); tickets = DecodeTickets(); var ticketsAsStrings = tickets.Select(ticket => ticket.Key + " " + ticket.Value).ToList(); File.WriteAllText(Files.ValidTicketsPath, string.Join(Environment.NewLine, ticketsAsStrings)); Console.WriteLine("Wrote valid tickets to ValidTickets.txt"); } var parsedTickets = ParseTickets(tickets).ToArray(); var titlesFound = ParseTicketsFromGroovyCiaDb(parsedTickets, Files.GroovyCiaPath); titlesFound = ParseTicketsFrom3DsDb(titlesFound); var longestTitleLength = titlesFound.Max(a => a.Name.Length) + 2; var longestPublisherLength = titlesFound.Max(a => a.Publisher.Length) + 2; PrintNumberOfTicketsFound(titlesFound, parsedTickets); Console.WriteLine(PrintTitleLegend(longestTitleLength, longestPublisherLength)); // titlesFound = titlesFound.OrderBy(r => Nintendo3DSRelease.GetTitleType(r.TitleId)).ThenBy(r => r.Name).ToList(); foreach (var title in titlesFound) { var fullWidthExtraPadName = GetFullWidthExtraPad(title.Name); var fullWidthExtraPadPublisher = GetFullWidthExtraPad(title.Publisher); Console.WriteLine( $"{title.TitleId} {title.DecTitleKey} | {title.Name.PadRight(longestTitleLength - fullWidthExtraPadName)}{title.Publisher.PadRight(longestPublisherLength - fullWidthExtraPadPublisher)}{title.Region}"); } Console.WriteLine( "\r\nTitles which 3dsdb or the GroovyCIA db couldn't find but we'll look up from the Nintendo CDN:"); Console.WriteLine(PrintTitleLegend(longestTitleLength, longestPublisherLength)); var remainingTitles = parsedTickets.Except(titlesFound).ToList(); remainingTitles = LookUpRemainingTitles(remainingTitles, longestTitleLength, longestPublisherLength) .OrderBy(r => Nintendo3DSRelease.GetTitleType(r.TitleId)) .ThenBy(r => r.Name) .ToList(); WriteOutputToFile(longestTitleLength, longestPublisherLength, titlesFound, remainingTitles); WriteOutputToCsv(titlesFound, remainingTitles); Console.Write("Done! Tickets and titles exported to "); ConsoleUtils.PrintColorfulLine(ConsoleColor.Green, Files.OutputFile); Console.Write("Detailed info exported to "); ConsoleUtils.PrintColorfulLine(ConsoleColor.Green, Files.DetailedOutputFile); // #if !DEBUG Console.Write("Press any key to exit..."); Console.ReadKey(); // #endif #if !DEBUG } catch (Exception ex) { ConsoleUtils.PrintColorfulLine(ConsoleColor.Red, "Fatal Error: " + ex.Message); Console.WriteLine(ex.StackTrace); } #endif }