Net update

This commit is contained in:
Alex Barney 2018-09-27 18:33:27 -05:00
parent 20a4473abf
commit 764b551767
6 changed files with 156 additions and 78 deletions

View file

@ -17,6 +17,7 @@ namespace Net
new CliOption("did", 1, (o, a) => o.DeviceId = ParseTitleId(a[0])), new CliOption("did", 1, (o, a) => o.DeviceId = ParseTitleId(a[0])),
new CliOption("cert", 1, (o, a) => o.CertFile = a[0]), new CliOption("cert", 1, (o, a) => o.CertFile = a[0]),
new CliOption("commoncert", 1, (o, a) => o.CommonCertFile = a[0]), new CliOption("commoncert", 1, (o, a) => o.CommonCertFile = a[0]),
new CliOption("token", 1, (o, a) => o.Token = a[0]),
new CliOption("metadata", 0, (o, a) => o.GetMetadata = true) new CliOption("metadata", 0, (o, a) => o.GetMetadata = true)
}; };

View file

@ -9,7 +9,7 @@ namespace Net
{ {
public class Database public class Database
{ {
public Dictionary<long, TitleMetadata> Titles { get; set; } = new Dictionary<long, TitleMetadata>(); public Dictionary<ulong, TitleMetadata> Titles { get; set; } = new Dictionary<ulong, TitleMetadata>();
public DateTime VersionListTime { get; set; } public DateTime VersionListTime { get; set; }
public string Serialize() public string Serialize()
@ -30,36 +30,39 @@ namespace Net
public void ImportVersionList(VersionList list) public void ImportVersionList(VersionList list)
{ {
foreach (var title in list.titles) foreach (VersionListTitle title in list.titles)
{ {
var mainId = long.Parse(title.id, NumberStyles.HexNumber, CultureInfo.InvariantCulture); ulong mainId = ulong.Parse(title.id, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
long updateId = 0;
bool isUpdate = (mainId & 0x800) != 0; AddTitle(mainId);
if (isUpdate) }
{
updateId = mainId;
mainId &= ~0x800;
} }
if (!Titles.TryGetValue(mainId, out TitleMetadata titleDb)) public void AddTitle(ulong id, int version = -1)
{ {
titleDb = new TitleMetadata(); bool isUpdate = (id & 0x800) != 0;
Titles[mainId] = titleDb;
if (!Titles.TryGetValue(id, out TitleMetadata titleDb))
{
titleDb = new TitleMetadata { Id = id };
Titles[id] = titleDb;
} }
titleDb.Id = mainId; if (version >= 0)
titleDb.UpdateId = updateId;
titleDb.MaxVersion = title.version;
int maxVersionShort = title.version >> 16;
for (int i = 0; i <= maxVersionShort; i++)
{ {
var version = i << 16; titleDb.MaxVersion = version;
if (!titleDb.Versions.TryGetValue(version, out TitleVersion versionDb)) int minVersion = isUpdate ? 1 : 0;
int maxVersionShort = titleDb.MaxVersion >> 16;
for (int i = minVersion; i <= maxVersionShort; i++)
{ {
versionDb = new TitleVersion { Version = version }; int longVersion = i << 16;
titleDb.Versions.Add(version, versionDb);
if (!titleDb.Versions.TryGetValue(longVersion, out TitleVersion versionDb))
{
versionDb = new TitleVersion { Version = longVersion };
titleDb.Versions.Add(longVersion, versionDb);
} }
} }
} }
@ -74,46 +77,21 @@ namespace Net
{ {
foreach (string id in titleIds) foreach (string id in titleIds)
{ {
var mainId = long.Parse(id, NumberStyles.HexNumber, CultureInfo.InvariantCulture); ulong mainId = ulong.Parse(id, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
long updateId = 0; AddTitle(mainId);
bool isUpdate = (mainId & 0x800) != 0;
if (isUpdate)
{
updateId = mainId;
mainId &= ~0x800;
}
var titleDb = new TitleMetadata();
Titles[mainId] = titleDb;
titleDb.Id = mainId;
titleDb.UpdateId = mainId | 0x800;
titleDb.MaxVersion = 5 << 16;
int maxVersionShort = 5;
for (int i = 0; i <= maxVersionShort; i++)
{
var version = i << 16;
if (!titleDb.Versions.TryGetValue(version, out TitleVersion versionDb))
{
versionDb = new TitleVersion { Version = version };
titleDb.Versions.Add(version, versionDb);
}
}
} }
} }
} }
public class TitleMetadata public class TitleMetadata
{ {
public long Id { get; set; } public ulong Id { get; set; }
public long UpdateId { get; set; }
public List<long> AocIds { get; set; } = new List<long>();
public int MaxVersion { get; set; } public int MaxVersion { get; set; }
public List<SuperflyInfo> Superfly { get; set; } = new List<SuperflyInfo>();
public DateTime SuperflyTime { get; set; }
public Dictionary<int, TitleVersion> Versions { get; set; } = new Dictionary<int, TitleVersion>(); public Dictionary<int, TitleVersion> Versions { get; set; } = new Dictionary<int, TitleVersion>();
public bool IsSuperflyCurrent() => SuperflyTime.AddDays(15) > DateTime.UtcNow;
} }
public class TitleVersion public class TitleVersion

View file

@ -14,6 +14,12 @@ namespace Net
var versionList = JsonConvert.DeserializeObject<VersionList>(text); var versionList = JsonConvert.DeserializeObject<VersionList>(text);
return versionList; return versionList;
} }
public static List<SuperflyInfo> ReadSuperfly(string filename)
{
string text = File.ReadAllText(filename);
return JsonConvert.DeserializeObject<List<SuperflyInfo>>(text);
}
} }
public class VersionList public class VersionList
@ -29,4 +35,11 @@ namespace Net
public int version { get; set; } public int version { get; set; }
public int required_version { get; set; } public int required_version { get; set; }
} }
public class SuperflyInfo
{
public string title_id { get; set; }
public int version { get; set; }
public string title_type { get; set; }
}
} }

View file

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
@ -11,9 +12,10 @@ namespace Net
{ {
private X509Certificate2 Certificate { get; set; } private X509Certificate2 Certificate { get; set; }
private X509Certificate2 CertificateCommon { get; set; } private X509Certificate2 CertificateCommon { get; set; }
private string Token { get; }
private string Eid { get; } = "lp1"; private string Eid { get; } = "lp1";
private ulong Did { get; } private ulong Did { get; }
private string Firmware { get; } = "5.1.0-3.0"; private string Firmware { get; } = "6.0.0-5.0";
private string CachePath { get; } = "titles"; private string CachePath { get; } = "titles";
private Context ToolCtx { get; } private Context ToolCtx { get; }
public Database Db { get; } public Database Db { get; }
@ -24,6 +26,8 @@ namespace Net
{ {
ToolCtx = ctx; ToolCtx = ctx;
Did = ctx.Options.DeviceId; Did = ctx.Options.DeviceId;
Token = ctx.Options.Token;
if (ctx.Options.CertFile != null) if (ctx.Options.CertFile != null)
{ {
SetCertificate(ctx.Options.CertFile); SetCertificate(ctx.Options.CertFile);
@ -62,7 +66,7 @@ namespace Net
if (stream == null) return null; if (stream == null) return null;
var nca = new Nca(ToolCtx.Keyset, stream, true); var nca = new Nca(ToolCtx.Keyset, stream, true);
Stream sect = nca.OpenSection(0, false); Stream sect = nca.OpenSection(0, false, true);
var pfs0 = new Pfs(sect); var pfs0 = new Pfs(sect);
var file = pfs0.OpenFile(pfs0.Files[0]); var file = pfs0.OpenFile(pfs0.Files[0]);
@ -112,7 +116,7 @@ namespace Net
if (controlNca == null) return null; if (controlNca == null) return null;
var nca = new Nca(ToolCtx.Keyset, controlNca, true); var nca = new Nca(ToolCtx.Keyset, controlNca, true);
var romfs = new Romfs(nca.OpenSection(0, false)); var romfs = new Romfs(nca.OpenSection(0, false, true));
var controlNacp = romfs.GetFile("/control.nacp"); var controlNacp = romfs.GetFile("/control.nacp");
var reader = new BinaryReader(new MemoryStream(controlNacp)); var reader = new BinaryReader(new MemoryStream(controlNacp));
@ -136,6 +140,27 @@ namespace Net
return new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read); return new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
} }
public List<SuperflyInfo> GetSuperfly(ulong titleId)
{
var filename = GetSuperflyFile(titleId);
return Json.ReadSuperfly(filename);
}
public string GetSuperflyFile(ulong titleId)
{
string titleDir = GetTitleDir(titleId);
var filePath = Path.Combine(titleDir, $"{titleId:x16}.json");
if (!File.Exists(filePath))
{
DownloadFile(GetSuperflyUrl(titleId), filePath);
}
if (!File.Exists(filePath)) return null;
return filePath;
}
private void DownloadCnmt(ulong titleId, int version) private void DownloadCnmt(ulong titleId, int version)
{ {
var titleDir = GetTitleDir(titleId, version); var titleDir = GetTitleDir(titleId, version);
@ -179,11 +204,16 @@ namespace Net
} }
} }
private string GetTitleDir(ulong titleId, int version) private string GetTitleDir(ulong titleId, int version = -1)
{
if (version >= 0)
{ {
return Path.Combine(CachePath, $"{titleId:x16}", $"{version}"); return Path.Combine(CachePath, $"{titleId:x16}", $"{version}");
} }
return Path.Combine(CachePath, $"{titleId:x16}");
}
public string GetMetaUrl(string ncaId) public string GetMetaUrl(string ncaId)
{ {
string url = $"{GetAtumUrl()}/c/a/{ncaId.ToLower()}"; string url = $"{GetAtumUrl()}/c/a/{ncaId.ToLower()}";
@ -196,6 +226,12 @@ namespace Net
return url; return url;
} }
public string GetSuperflyUrl(ulong titleId)
{
string url = $"https://superfly.hac.{Eid}.d4c.nintendo.net/v1/a/{titleId:x16}/dv";
return url;
}
public string GetMetadataNcaId(ulong titleId, int version) public string GetMetadataNcaId(ulong titleId, int version)
{ {
string url = $"{GetAtumUrl()}/t/a/{titleId:x16}/{version}?deviceid={Did}"; string url = $"{GetAtumUrl()}/t/a/{titleId:x16}/{version}?deviceid={Did}";
@ -239,7 +275,9 @@ namespace Net
{ {
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.ClientCertificates.Add(Certificate); request.ClientCertificates.Add(Certificate);
request.Accept = "*/*";
request.UserAgent = $"NintendoSDK Firmware/{Firmware} (platform:NX; did:{Did}; eid:{Eid})"; request.UserAgent = $"NintendoSDK Firmware/{Firmware} (platform:NX; did:{Did}; eid:{Eid})";
request.Headers.Add("X-Nintendo-DenebEdgeToken", Token);
request.Method = method; request.Method = method;
ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true; ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true;

View file

@ -12,6 +12,7 @@ namespace Net
public ulong DeviceId; public ulong DeviceId;
public string CertFile; public string CertFile;
public string CommonCertFile; public string CommonCertFile;
public string Token;
public bool GetMetadata; public bool GetMetadata;
} }

View file

@ -45,8 +45,14 @@ namespace Net
return; return;
} }
var tid = ctx.Options.TitleId; if (string.IsNullOrWhiteSpace(ctx.Options.Token))
var ver = ctx.Options.Version; {
CliParser.PrintWithUsage("A token must be set.");
return;
}
ulong tid = ctx.Options.TitleId;
int ver = ctx.Options.Version;
var net = new NetContext(ctx); var net = new NetContext(ctx);
var cnmt = net.GetCnmt(tid, ver); var cnmt = net.GetCnmt(tid, ver);
@ -66,38 +72,79 @@ namespace Net
private static void GetMetadata(NetContext net, IProgressReport logger = null) private static void GetMetadata(NetContext net, IProgressReport logger = null)
{ {
var versionList = net.GetVersionList(); VersionList versionList = net.GetVersionList();
net.Db.ImportVersionList(versionList); net.Db.ImportVersionList(versionList);
//net.Db.ImportList("titles.txt"); //net.Db.ImportList("titles.txt");
net.Save(); net.Save();
ReadMetaNcas(net, logger);
foreach (var title in net.Db.Titles.Values) net.Save();
}
private static void ReadMetaNcas(NetContext net, IProgressReport logger = null)
{ {
foreach (var version in title.Versions.Values.Where(x => x.Exists)) foreach (TitleMetadata title in net.Db.Titles.Values.ToArray())
{ {
var titleId = version.Version == 0 ? title.Id : title.UpdateId; if (title.Versions.Count == 0)
{
int version = 0;
if ((title.Id & 0x800) != 0)
{
version = 1 << 16;
}
title.Versions.Add(version, new TitleVersion { Version = version });
}
foreach (TitleVersion version in title.Versions.Values.Where(x => x.Exists))
{
ulong titleId = title.Id;
try try
{ {
var control = net.GetControl((ulong)titleId, version.Version); Cnmt meta = net.GetCnmt(titleId, version.Version);
version.Control = control;
if (control == null) version.Exists = false;
Cnmt meta = net.GetCnmt((ulong)titleId, version.Version);
version.ContentMetadata = meta; version.ContentMetadata = meta;
if (meta == null) version.Exists = false; if (meta == null)
{
version.Exists = false;
logger?.LogMessage($"{titleId:x16}v{version.Version} not found.");
continue;
}
logger?.LogMessage($"{titleId}v{version.Version}"); Nacp control = net.GetControl(titleId, version.Version);
version.Control = control;
if (!net.Db.Titles.ContainsKey(meta.ApplicationTitleId))
{
net.Db.AddTitle(meta.ApplicationTitleId);
logger?.LogMessage($"Found title {meta.ApplicationTitleId:x16}");
}
if (meta.Type == TitleType.Application)
{
ReadSuperfly(title, net, logger);
}
logger?.LogMessage($"{titleId:x16}v{version.Version}");
//Thread.Sleep(300); //Thread.Sleep(300);
} }
catch (Exception ex) catch (Exception ex)
{ {
logger?.LogMessage($"Failed getting {titleId}v{version.Version}\n{ex.Message}"); logger?.LogMessage($"Failed getting {titleId:x16}v{version.Version}\n{ex.Message}");
} }
} }
// net.Save(); // net.Save();
} }
}
net.Save(); private static void ReadSuperfly(TitleMetadata titleDb, NetContext net, IProgressReport logger = null)
{
titleDb.Superfly = net.GetSuperfly(titleDb.Id);
foreach (SuperflyInfo title in titleDb.Superfly)
{
ulong id = ulong.Parse(title.title_id, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
net.Db.AddTitle(id, title.version);
}
} }
private static void OpenKeyset(Context ctx) private static void OpenKeyset(Context ctx)