LibHac/Net/NetContext.cs

139 lines
4.7 KiB
C#
Raw Normal View History

2018-07-28 20:33:34 +02:00
using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using libhac;
namespace Net
{
internal class NetContext
{
private X509Certificate2 Certificate { get; set; }
private string Eid { get; } = "lp1";
private ulong Did { get; }
private string Firmware { get; } = "5.1.0-3.0";
private string CachePath { get; } = "titles";
private Context ToolCtx { get; }
public NetContext(Context ctx)
{
ToolCtx = ctx;
Did = ctx.Options.DeviceId;
if (ctx.Options.CertFile != null)
{
SetCertificate(ctx.Options.CertFile);
}
}
public void SetCertificate(string filename)
{
Certificate = new X509Certificate2(filename, "switch");
}
public Cnmt GetCnmt(ulong titleId, int version)
{
using (var stream = GetCnmtFile(titleId, version))
{
var nca = new Nca(ToolCtx.Keyset, stream, true);
Stream sect = nca.OpenSection(0, false);
var pfs0 = new Pfs0(sect);
var file = pfs0.GetFile(0);
var cnmt = new Cnmt(new MemoryStream(file));
return cnmt;
}
}
public Stream GetCnmtFile(ulong titleId, int version)
{
var cnmt = GetCnmtFileFromCache(titleId, version);
if (cnmt != null) return cnmt;
if (Certificate == null) return null;
DownloadCnmt(titleId, version);
return GetCnmtFileFromCache(titleId, version);
}
public Stream GetCnmtFileFromCache(ulong titleId, int version)
{
string titleDir = GetTitleDir(titleId, version);
var cnmtFiles = Directory.GetFiles(titleDir, "*.cnmt.nca").ToArray();
if (cnmtFiles.Length == 1)
{
return new FileStream(cnmtFiles[0], FileMode.Open, FileAccess.Read, FileShare.Read);
}
if (cnmtFiles.Length > 1)
{
throw new FileNotFoundException($"More than cnmt file exists for {titleId:x16}v{version}");
}
return null;
}
private void DownloadCnmt(ulong titleId, int version)
{
var titleDir = GetTitleDir(titleId, version);
var ncaId = GetMetadataNcaId(titleId, version);
var filename = $"{ncaId}.cnmt.nca";
var filePath = Path.Combine(titleDir, filename);
DownloadFile(GetContentUrl(ncaId), filePath);
}
public void DownloadFile(string url, string filePath)
{
var response = Request("GET", url);
using (var responseStream = response.GetResponseStream())
using (var outStream = new FileStream(filePath, FileMode.Create, FileAccess.ReadWrite))
{
var dir = Path.GetDirectoryName(filePath) ?? throw new DirectoryNotFoundException();
Directory.CreateDirectory(dir);
responseStream.CopyStream(outStream, response.ContentLength, ToolCtx.Logger);
}
}
private string GetTitleDir(ulong titleId, int version)
{
var titleDir = Path.Combine(CachePath, $"{titleId:x16}", $"{version}");
Directory.CreateDirectory(titleDir);
return titleDir;
}
public string GetContentUrl(string ncaId)
{
string url = $"{GetAtumUrl()}/c/a/{ncaId}";
return url;
}
public string GetMetadataNcaId(ulong titleId, int version)
{
string url = $"{GetAtumUrl()}/t/a/{titleId:x16}/{version}?deviceid={Did}";
using (WebResponse response = Request("HEAD", url))
{
return response.Headers.Get("X-Nintendo-Content-ID");
}
}
private string GetAtumUrl()
{
return $"https://atum.hac.{Eid}.d4c.nintendo.net";
}
public WebResponse Request(string method, string url)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.ClientCertificates.Add(Certificate);
request.UserAgent = string.Format("NintendoSDK Firmware/{0} (platform:NX; did:{1}; eid:{2})", Firmware, Did, Eid);
request.Method = method;
ServicePointManager.ServerCertificateValidationCallback = ((sender, certificate, chain, sslPolicyErrors) => true);
if (((HttpWebResponse)request.GetResponse()).StatusCode != HttpStatusCode.OK) { Console.WriteLine("http error"); return null; }
return request.GetResponse();
}
}
}