This commit is contained in:
Alex Barney 2019-02-06 13:08:41 -06:00
parent 9875880e32
commit a1063aa08d
7 changed files with 152 additions and 35 deletions

68
src/Net/Cache.cs Normal file
View file

@ -0,0 +1,68 @@
using System.Linq;
using LibHac;
using LibHac.IO;
namespace Net
{
public class Cache
{
private IFileSystem CacheFs { get; }
public Cache(IFileSystem cacheFs)
{
CacheFs = cacheFs;
}
public bool TryOpenNca(ulong titleId, int version, byte[] ncaId, out IFile file)
{
file = default;
string titleDir = GetTitleDir(titleId, version);
if (!CacheFs.DirectoryExists(titleDir)) return false;
string filePath = $"{titleDir}/{ncaId.ToHexString().ToLower()}.nca");
if (CacheFs.FileExists(filePath))
{
file = CacheFs.OpenFile(filePath, OpenMode.Read);
return true;
}
return false;
}
public bool TryOpenMetaNca(ulong titleId, int version, out IFile file)
{
file = default;
string titleDir = GetTitleDir(titleId, version);
if (!CacheFs.DirectoryExists(titleDir)) return false;
IDirectory dir = CacheFs.OpenDirectory(titleDir, OpenDirectoryMode.All);
DirectoryEntry[] metaFiles = dir.EnumerateEntries("*.cnmt.nca", SearchOptions.Default).ToArray();
if (metaFiles.Length == 1)
{
file = CacheFs.OpenFile(metaFiles[0].FullPath, OpenMode.Read);
return true;
}
if (metaFiles.Length > 1)
{
throw new System.IO.FileNotFoundException($"More than 1 cnmt file exists for {titleId:x16}v{version}");
}
return false;
}
private string GetTitleDir(ulong titleId, int version = -1)
{
if (version >= 0)
{
return $"/{titleId:x16}/{version}";
}
return $"/{titleId:x16}";
}
}
}

View file

@ -9,15 +9,8 @@ namespace Net
{ {
private static readonly CliOption[] CliOptions = private static readonly CliOption[] CliOptions =
{ {
new CliOption("keyset", 'k', 1, (o, a) => o.Keyfile = a[0]),
new CliOption("titlekeys", 1, (o, a) => o.TitleKeyFile = a[0]),
new CliOption("consolekeys", 1, (o, a) => o.ConsoleKeyFile = a[0]),
new CliOption("title", 1, (o, a) => o.TitleId = ParseTitleId(a[0])), new CliOption("title", 1, (o, a) => o.TitleId = ParseTitleId(a[0])),
new CliOption("version", 1, (o, a) => o.Version = ParseVersion(a[0])), new CliOption("version", 1, (o, a) => o.Version = ParseVersion(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("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)
}; };
@ -62,12 +55,11 @@ namespace Net
option.Assigner(options, optionArgs); option.Assigner(options, optionArgs);
i += option.ArgsNeeded; i += option.ArgsNeeded;
} }
return options; return options;
} }
private static ulong ParseTitleId(string input) public static ulong ParseTitleId(string input)
{ {
if (input.Length != 16) if (input.Length != 16)
{ {

34
src/Net/ContentManager.cs Normal file
View file

@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Text;
using LibHac;
using LibHac.IO;
namespace Net
{
public class ContentManager
{
private IFileSystem ContentFs { get; }
private Cache ContentCache { get; }
public ContentManager(IFileSystem contentFs)
{
ContentFs = contentFs;
ContentCache = new Cache(contentFs);
}
public bool OpenCnmtFile(ulong titleId, int version, out IFile file)
{
if (ContentCache.TryOpenMetaNca(titleId, version, out file))
{
return true;
}
if (cnmt != null) return cnmt;
if (Certificate == null) return null;
DownloadCnmt(titleId, version);
return GetCnmtFileFromCache(titleId, version);
}
}
}

View file

@ -17,7 +17,7 @@ namespace Net
private string Token { get; } 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; } = "6.0.0-5.0"; private string Firmware { get; } = "7.0.0-1.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; }
@ -284,8 +284,9 @@ namespace Net
try try
{ {
if (((HttpWebResponse)request.GetResponse()).StatusCode == HttpStatusCode.OK) var response = (HttpWebResponse) request.GetResponse();
return request.GetResponse(); if (response.StatusCode == HttpStatusCode.OK)
return response;
} }
catch (WebException ex) catch (WebException ex)
{ {

View file

@ -4,9 +4,6 @@ namespace Net
{ {
internal class Options internal class Options
{ {
public string Keyfile;
public string TitleKeyFile;
public string ConsoleKeyFile;
public ulong TitleId; public ulong TitleId;
public int Version; public int Version;
public ulong DeviceId; public ulong DeviceId;

View file

@ -10,11 +10,22 @@ namespace Net
{ {
public static class Program public static class Program
{ {
private const string DidFile = "device_id.txt";
private const string TokenFile = "edge_token.txt";
private const string CertFile = "nx_tls_client_cert.pfx";
private const string CommonCertFile = "ShopN.p12";
public static void Main(string[] args) public static void Main(string[] args)
{ {
Console.OutputEncoding = Encoding.UTF8; Console.OutputEncoding = Encoding.UTF8;
var ctx = new Context(); var ctx = new Context();
ctx.Options = CliParser.Parse(args); ctx.Options = CliParser.Parse(args);
ctx.Options.DeviceId = CliParser.ParseTitleId(File.ReadAllText(DidFile));
ctx.Options.Token = File.ReadAllText(TokenFile);
ctx.Options.CertFile = CertFile;
ctx.Options.CommonCertFile = CommonCertFile;
if (ctx.Options == null) return; if (ctx.Options == null) return;
using (var logger = new ProgressBar()) using (var logger = new ProgressBar())
@ -153,26 +164,8 @@ namespace Net
string homeKeyFile = Path.Combine(home, ".switch", "prod.keys"); string homeKeyFile = Path.Combine(home, ".switch", "prod.keys");
string homeTitleKeyFile = Path.Combine(home, ".switch", "title.keys"); string homeTitleKeyFile = Path.Combine(home, ".switch", "title.keys");
string homeConsoleKeyFile = Path.Combine(home, ".switch", "console.keys"); string homeConsoleKeyFile = Path.Combine(home, ".switch", "console.keys");
string keyFile = ctx.Options.Keyfile;
string titleKeyFile = ctx.Options.TitleKeyFile;
string consoleKeyFile = ctx.Options.ConsoleKeyFile;
if (keyFile == null && File.Exists(homeKeyFile)) ctx.Keyset = ExternalKeys.ReadKeyFile(homeKeyFile, homeTitleKeyFile, homeConsoleKeyFile, ctx.Logger);
{
keyFile = homeKeyFile;
}
if (titleKeyFile == null && File.Exists(homeTitleKeyFile))
{
titleKeyFile = homeTitleKeyFile;
}
if (consoleKeyFile == null && File.Exists(homeConsoleKeyFile))
{
consoleKeyFile = homeConsoleKeyFile;
}
ctx.Keyset = ExternalKeys.ReadKeyFile(keyFile, titleKeyFile, consoleKeyFile, ctx.Logger);
} }
private static List<ulong> GetTitleIds(string filename) private static List<ulong> GetTitleIds(string filename)

32
src/Net/Urls.cs Normal file
View file

@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Net
{
public static class Urls
{
private const string Eid = "lp1";
public static string Did { get; set; }
public static string GetSuperflyUrl(ulong titleId)
{
return $"https://superfly.hac.{Eid}.d4c.nintendo.net/v1/a/{titleId:x16}/dv";
}
public static string GetMetaQueryUrl(ulong titleId, int version)
{
return $"https://atum.hac.{Eid}.d4c.nintendo.net/t/a/{titleId:x16}/{version}?deviceid={Did}";
}
public static string GetMetaContentUrl(string ncaId)
{
return $"https://atum.hac.{Eid}.d4c.nintendo.net/c/a/{ncaId}";
}
public static string GetContentUrl(string ncaId)
{
return $"https://atum.hac.{Eid}.d4c.nintendo.net/c/c/{ncaId}";
}
}
}