mirror of
https://github.com/EpinelPS/EpinelPS.git
synced 2025-12-13 15:34:36 +01:00
refactoring
This commit is contained in:
@@ -15,7 +15,7 @@ namespace ProtobufViewUtil
|
||||
s.MergeFrom(inn);
|
||||
Console.WriteLine(s.ToString());
|
||||
var outt = s.ToByteArray();
|
||||
|
||||
|
||||
if (inn.SequenceEqual(outt))
|
||||
{
|
||||
Console.WriteLine("Check OK");
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using EmbedIO;
|
||||
using nksrv.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -19,14 +20,14 @@ namespace nksrv.IntlServer
|
||||
protected override async Task HandleAsync()
|
||||
{
|
||||
Console.WriteLine("li-sg redirect in: " + Content);
|
||||
HttpClientHandler handler = new HttpClientHandler()
|
||||
HttpClientHandler handler = new()
|
||||
{
|
||||
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate,
|
||||
ServerCertificateCustomValidationCallback = (httpRequestMessage, cert, cetChain, policyErrors) => true,
|
||||
AllowAutoRedirect = true // from gameassembly dll
|
||||
};
|
||||
|
||||
HttpClient client = new HttpClient(new LoggingHandler(handler));
|
||||
HttpClient client = new(new LoggingHttpHandler(handler));
|
||||
client.DefaultRequestHeaders
|
||||
.Accept
|
||||
.Add(new MediaTypeWithQualityHeaderValue("*/*"));//ACCEPT header
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using EmbedIO;
|
||||
using nksrv.Utils;
|
||||
|
||||
namespace nksrv.IntlServer
|
||||
{
|
||||
@@ -19,14 +20,14 @@ namespace nksrv.IntlServer
|
||||
protected override async Task HandleAsync()
|
||||
{
|
||||
Console.WriteLine("AWS NA redirect in: " + Content);
|
||||
HttpClientHandler handler = new HttpClientHandler()
|
||||
HttpClientHandler handler = new()
|
||||
{
|
||||
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate,
|
||||
ServerCertificateCustomValidationCallback = (httpRequestMessage, cert, cetChain, policyErrors) => true,
|
||||
AllowAutoRedirect = true // from gameassembly dll
|
||||
};
|
||||
|
||||
HttpClient client = new HttpClient(new LoggingHandler(handler));
|
||||
HttpClient client = new(new LoggingHttpHandler(handler));
|
||||
client.DefaultRequestHeaders
|
||||
.Accept
|
||||
.Add(new MediaTypeWithQualityHeaderValue("*/*"));//ACCEPT header
|
||||
@@ -36,7 +37,7 @@ namespace nksrv.IntlServer
|
||||
|
||||
// client.DefaultRequestHeaders.Remove("User-agent");
|
||||
|
||||
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "https://50.18.221.30" + ctx.Request.RawUrl);
|
||||
HttpRequestMessage request = new(HttpMethod.Post, "https://50.18.221.30" + ctx.Request.RawUrl);
|
||||
request.Version = HttpVersion.Version11;
|
||||
request.Headers.TryAddWithoutValidation("Host", "aws-na.intlgame.com");
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace nksrv.LobbyServer
|
||||
UserId = 0;
|
||||
ctx = null;
|
||||
}
|
||||
|
||||
|
||||
public async Task HandleAsync(IHttpContext ctx)
|
||||
{
|
||||
this.ctx = ctx;
|
||||
@@ -93,7 +93,7 @@ namespace nksrv.LobbyServer
|
||||
{
|
||||
if (ctx == null)
|
||||
{
|
||||
T msg2 = new T();
|
||||
T msg2 = new();
|
||||
msg2.MergeFrom(Contents);
|
||||
return msg2;
|
||||
}
|
||||
@@ -102,16 +102,8 @@ namespace nksrv.LobbyServer
|
||||
var bin = await PacketDecryption.DecryptOrReturnContentAsync(ctx);
|
||||
|
||||
// return grpc IMessage from byte array with type T
|
||||
T msg = default(T);
|
||||
try
|
||||
{
|
||||
msg = new T();
|
||||
msg.MergeFrom(bin.Contents);
|
||||
}
|
||||
catch
|
||||
{
|
||||
;
|
||||
}
|
||||
T msg = new();
|
||||
msg.MergeFrom(bin.Contents);
|
||||
|
||||
UserId = bin.UserId;
|
||||
UsedAuthToken = bin.UsedAuthToken;
|
||||
@@ -122,9 +114,7 @@ namespace nksrv.LobbyServer
|
||||
|
||||
public User GetUser()
|
||||
{
|
||||
User? user = JsonDb.GetUser(UserId);
|
||||
if (user == null) throw new Exception("null user");
|
||||
return user;
|
||||
return JsonDb.GetUser(UserId) ?? throw new Exception("null user");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace nksrv.LobbyServer.Msgs
|
||||
AllowAutoRedirect = true // from gameassembly dll
|
||||
};
|
||||
|
||||
HttpClient client = new HttpClient(new LoggingHandler(handler));
|
||||
HttpClient client = new(new LoggingHttpHandler(handler));
|
||||
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/octet-stream+protobuf"));
|
||||
client.BaseAddress = new Uri("https://global-lobby.nikke-kr.com");
|
||||
client.DefaultRequestVersion = HttpVersion.Version20;
|
||||
@@ -47,38 +47,21 @@ namespace nksrv.LobbyServer.Msgs
|
||||
ctx.Response.OutputStream.Flush();
|
||||
}
|
||||
|
||||
public static async Task<PacketDecryptResponse> DecryptOrReturnContentAsync(IHttpContext ctx, bool decompress = false)
|
||||
public static async Task<PacketDecryptResponse> DecryptOrReturnContentAsync(IHttpContext ctx)
|
||||
{
|
||||
byte[] bin = Array.Empty<byte>();
|
||||
|
||||
using MemoryStream buffer = new MemoryStream();
|
||||
|
||||
var stream = ctx.Request.InputStream;
|
||||
|
||||
var encoding = ctx.Request.Headers[HttpHeaderNames.ContentEncoding]?.Trim();
|
||||
|
||||
Stream decryptedStream;
|
||||
switch (encoding)
|
||||
Stream decryptedStream = encoding switch
|
||||
{
|
||||
case CompressionMethodNames.Gzip:
|
||||
decryptedStream = new GZipStream(stream, CompressionMode.Decompress);
|
||||
break;
|
||||
case CompressionMethodNames.Deflate:
|
||||
decryptedStream = new DeflateStream(stream, CompressionMode.Decompress);
|
||||
break;
|
||||
case CompressionMethodNames.None:
|
||||
case null:
|
||||
decryptedStream = stream;
|
||||
break;
|
||||
case "gzip,enc":
|
||||
|
||||
decryptedStream = stream;
|
||||
break;
|
||||
default:
|
||||
throw HttpException.BadRequest($"Unsupported content encoding \"{encoding}\"");
|
||||
}
|
||||
|
||||
|
||||
CompressionMethodNames.Gzip => new GZipStream(stream, CompressionMode.Decompress),
|
||||
CompressionMethodNames.Deflate => new DeflateStream(stream, CompressionMode.Decompress),
|
||||
CompressionMethodNames.None or null => stream,
|
||||
"gzip,enc" => stream,
|
||||
_ => throw HttpException.BadRequest($"Unsupported content encoding \"{encoding}\""),
|
||||
};
|
||||
await stream.CopyToAsync(buffer, 81920, ctx.CancellationToken).ConfigureAwait(continueOnCapturedContext: false);
|
||||
return new PacketDecryptResponse() { Contents = buffer.ToArray() };
|
||||
}
|
||||
|
||||
314
nksrv/Program.cs
314
nksrv/Program.cs
@@ -24,7 +24,8 @@ namespace nksrv
|
||||
{
|
||||
internal class Program
|
||||
{
|
||||
static async Task Main(string[] args)
|
||||
private static readonly HttpClient AssetDownloader = new();
|
||||
static async Task Main()
|
||||
{
|
||||
Logger.UnregisterLogger<ConsoleLogger>();
|
||||
Logger.RegisterLogger(new GreatLogger());
|
||||
@@ -32,12 +33,9 @@ namespace nksrv
|
||||
LobbyHandler.Init();
|
||||
|
||||
// Start Webserver
|
||||
using (var server = CreateWebServer())
|
||||
{
|
||||
await server.RunAsync();
|
||||
}
|
||||
using var server = CreateWebServer();
|
||||
await server.RunAsync();
|
||||
}
|
||||
|
||||
private static WebServer CreateWebServer()
|
||||
{
|
||||
var cert = new X509Certificate2(new X509Certificate(@"C:\Users\Misha\nkcert\site.pfx"));
|
||||
@@ -61,22 +59,21 @@ namespace nksrv
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
private static async Task HandleBatchRequests(IHttpContext ctx)
|
||||
{
|
||||
var theBytes = await PacketDecryption.DecryptOrReturnContentAsync(ctx, true);
|
||||
var theBytes = await PacketDecryption.DecryptOrReturnContentAsync(ctx);
|
||||
|
||||
// this actually uses gzip compression, unlike other requests.
|
||||
|
||||
using MemoryStream streamforparser = new MemoryStream(theBytes.Contents);
|
||||
var content = new StreamContent(streamforparser);
|
||||
using MemoryStream streamforparser = new(theBytes.Contents);
|
||||
StreamContent content = new(streamforparser);
|
||||
content.Headers.Remove("Content-Type");
|
||||
content.Headers.TryAddWithoutValidation("Content-Type", ctx.Request.Headers["Content-Type"]);
|
||||
|
||||
// we have the form contents,
|
||||
var multipart = await content.ReadAsMultipartAsync();
|
||||
|
||||
HttpClient cl = new HttpClient();
|
||||
HttpClient cl = new();
|
||||
|
||||
// TODO: the server returns different boundary each time, looks like a GUID
|
||||
List<byte> response = [.. Encoding.UTF8.GetBytes("--f5d5cf4d-5627-422f-b3c6-532f1a0cbc0a\r\n")];
|
||||
@@ -102,7 +99,7 @@ namespace nksrv
|
||||
.. Encoding.UTF8.GetBytes($"\r\n"),
|
||||
.. res,
|
||||
];
|
||||
response.AddRange(ResponseWithBytes.ToArray());
|
||||
response.AddRange([.. ResponseWithBytes]);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -128,149 +125,45 @@ namespace nksrv
|
||||
ctx.Response.ContentType = "multipart/mixed; boundary=\"f5d5cf4d-5627-422f-b3c6-532f1a0cbc0a\"";
|
||||
ctx.Response.OutputStream.Write(responseBytes);
|
||||
}
|
||||
private static (string key, string value) GetHeader(string line)
|
||||
{
|
||||
var pieces = line.Split([':'], 2);
|
||||
|
||||
return (pieces[0].Trim(), pieces[1].Trim());
|
||||
}
|
||||
private static async Task<byte[]?> SendReqLocalAndReadResponseAsync(byte[] bytes)
|
||||
{
|
||||
int line = 0;
|
||||
var bodyStartStr = Encoding.UTF8.GetString(bytes);
|
||||
|
||||
string method = "";
|
||||
string url = "";
|
||||
string httpVer = "";
|
||||
string authToken = "";
|
||||
List<NameValueHeaderValue> headers = new List<NameValueHeaderValue>();
|
||||
|
||||
int currentByte = 0;
|
||||
|
||||
foreach (var item in bodyStartStr.Split("\r\n"))
|
||||
{
|
||||
if (line == 0)
|
||||
{
|
||||
var parts = item.Split(" ");
|
||||
method = parts[0];
|
||||
url = parts[1];
|
||||
httpVer = parts[2];
|
||||
}
|
||||
else if (item == null || string.IsNullOrEmpty(item))
|
||||
{
|
||||
currentByte += 2;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
var h = GetHeader(item);
|
||||
headers.Add(new NameValueHeaderValue(h.key, h.value));
|
||||
|
||||
if (h.key == "Authorization")
|
||||
{
|
||||
authToken = h.value.Replace("Bearer ", "");
|
||||
}
|
||||
}
|
||||
currentByte += (2 + item.Length);
|
||||
line++;
|
||||
}
|
||||
byte[] body;
|
||||
if (currentByte == bytes.Length)
|
||||
{
|
||||
// empty body
|
||||
body = [];
|
||||
}
|
||||
else
|
||||
{
|
||||
// not empty body, TODO
|
||||
File.WriteAllBytes("notemptybody", bytes);
|
||||
body = bytes.Skip(currentByte).ToArray();
|
||||
}
|
||||
|
||||
if (!url.StartsWith("/v1/"))
|
||||
{
|
||||
throw new NotImplementedException("handler for " + url + " not implemented");
|
||||
}
|
||||
|
||||
url = url.Replace("/v1", "");
|
||||
|
||||
// find appropriate handler
|
||||
Logger.Info("BATCH: /v1" + url);
|
||||
|
||||
foreach (var item in LobbyHandler.Handlers)
|
||||
{
|
||||
if (item.Key == url)
|
||||
{
|
||||
item.Value.Reset();
|
||||
item.Value.Contents = body;
|
||||
await item.Value.HandleAsync(authToken);
|
||||
return item.Value.ReturnBytes;
|
||||
}
|
||||
}
|
||||
Logger.Error("HANDLER NOT FOUND: " + url);
|
||||
return null;
|
||||
}
|
||||
|
||||
private static byte[] ReadStream(Stream stream)
|
||||
{
|
||||
byte[] data = new byte[1024];
|
||||
List<byte> allData = new List<byte>();
|
||||
do
|
||||
{
|
||||
int numBytesRead = stream.Read(data, 0, data.Length);
|
||||
|
||||
if (numBytesRead == data.Length)
|
||||
{
|
||||
allData.AddRange(data);
|
||||
}
|
||||
else if (numBytesRead > 0)
|
||||
{
|
||||
allData.AddRange(data.Take(numBytesRead));
|
||||
}
|
||||
else if (numBytesRead == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
} while (true);
|
||||
return allData.ToArray();
|
||||
}
|
||||
|
||||
private static async Task HandleDataEndpoint(IHttpContext ctx)
|
||||
{
|
||||
// this endpoint does not appear to be needed, it is used for telemetry
|
||||
if (ctx.RequestedPath == "/v1/dsr/query")
|
||||
{
|
||||
WriteJsonString(ctx, "{\"ret\":0,\"msg\":\"\",\"status\":0,\"created_at\":\"0\",\"target_destroy_at\":\"0\",\"destroyed_at\":\"0\",\"err_code\":0,\"seq\":\"1\"}");
|
||||
await WriteJsonStringAsync(ctx, "{\"ret\":0,\"msg\":\"\",\"status\":0,\"created_at\":\"0\",\"target_destroy_at\":\"0\",\"destroyed_at\":\"0\",\"err_code\":0,\"seq\":\"1\"}");
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.Response.StatusCode = 404;
|
||||
}
|
||||
}
|
||||
|
||||
private static HttpClient hs = new HttpClient();
|
||||
private static async Task HandleAsset(IHttpContext ctx)
|
||||
{
|
||||
string fs = AppDomain.CurrentDomain.BaseDirectory + "cache" + ctx.RequestedPath;
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(fs));
|
||||
if (!File.Exists(fs))
|
||||
string targetFile = AppDomain.CurrentDomain.BaseDirectory + "cache" + ctx.RequestedPath;
|
||||
var targetDir = Path.GetDirectoryName(targetFile);
|
||||
if (targetDir == null)
|
||||
{
|
||||
Logger.Info("Download " + fs);
|
||||
Logger.Error($"ERROR: Directory name cannot be null for request " + ctx.RequestedPath + ", file path is " + targetFile);
|
||||
return;
|
||||
}
|
||||
Directory.CreateDirectory(targetDir);
|
||||
|
||||
if (!File.Exists(targetFile))
|
||||
{
|
||||
Logger.Info("Download " + targetFile);
|
||||
|
||||
// TODO: Ip might change
|
||||
string @base = ctx.Request.RawUrl.StartsWith("/prdenv") ? "prdenv" : "media";
|
||||
var requestUri = new Uri("https://43.132.66.200/" + @base + ctx.RequestedPath);
|
||||
using var request = new HttpRequestMessage(HttpMethod.Get, requestUri);
|
||||
request.Headers.TryAddWithoutValidation("host", "cloud.nikke-kr.com");
|
||||
using var response = await hs.SendAsync(request);
|
||||
using var response = await AssetDownloader.SendAsync(request);
|
||||
if (response.StatusCode == HttpStatusCode.OK)
|
||||
{
|
||||
using (var fss = new FileStream(fs, FileMode.CreateNew))
|
||||
{
|
||||
await response.Content.CopyToAsync(fss);
|
||||
using var fss = new FileStream(targetFile, FileMode.CreateNew);
|
||||
await response.Content.CopyToAsync(fss, ctx.CancellationToken);
|
||||
|
||||
fss.Close();
|
||||
}
|
||||
fss.Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -281,56 +174,28 @@ namespace nksrv
|
||||
}
|
||||
try
|
||||
{
|
||||
|
||||
|
||||
|
||||
using (var fss = new FileStream(fs, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
using var fss = new FileStream(targetFile, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
using var responseStream = ctx.OpenResponseStream();
|
||||
if (ctx.RequestedPath.EndsWith(".mp4"))
|
||||
{
|
||||
using (var responseStream = ctx.OpenResponseStream())
|
||||
{
|
||||
if (ctx.RequestedPath.EndsWith(".mp4"))
|
||||
{
|
||||
ctx.Response.ContentType = "video/mp4";
|
||||
}
|
||||
else if (ctx.RequestedPath.EndsWith(".json"))
|
||||
{
|
||||
ctx.Response.ContentType = "application/json";
|
||||
}
|
||||
ctx.Response.StatusCode = 200;
|
||||
//ctx.Response.ContentLength64 = fss.Length;
|
||||
|
||||
|
||||
fss.CopyTo(responseStream);
|
||||
fss.Close();
|
||||
}
|
||||
ctx.Response.ContentType = "video/mp4";
|
||||
}
|
||||
else if (ctx.RequestedPath.EndsWith(".json"))
|
||||
{
|
||||
ctx.Response.ContentType = "application/json";
|
||||
}
|
||||
ctx.Response.StatusCode = 200;
|
||||
//ctx.Response.ContentLength64 = fss.Length; // TODO: This causes chrome to download content very slowl
|
||||
|
||||
await fss.CopyToAsync(responseStream, ctx.CancellationToken);
|
||||
fss.Close();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error(ex.ToString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void WriteData<T>(IHttpContext ctx, T data, bool encrypted = false) where T : IMessage, new()
|
||||
{
|
||||
ctx.Response.ContentEncoding = null;
|
||||
ctx.Response.ContentType = "application/octet-stream+protobuf";
|
||||
ctx.Response.ContentLength64 = data.CalculateSize();
|
||||
var x = new CodedOutputStream(ctx.Response.OutputStream);
|
||||
data.WriteTo(x);
|
||||
x.Flush();
|
||||
}
|
||||
private static void WriteJsonString(IHttpContext ctx, string data)
|
||||
{
|
||||
var bt = Encoding.UTF8.GetBytes(data);
|
||||
ctx.Response.ContentEncoding = null;
|
||||
ctx.Response.ContentType = "application/json";
|
||||
ctx.Response.ContentLength64 = bt.Length;
|
||||
ctx.Response.OutputStream.Write(bt, 0, bt.Length);
|
||||
ctx.Response.OutputStream.Flush();
|
||||
}
|
||||
|
||||
private static async Task HandleRouteData(IHttpContext ctx)
|
||||
{
|
||||
if (ctx.RequestedPath.Contains("/route_config.json"))
|
||||
@@ -406,35 +271,96 @@ namespace nksrv
|
||||
ctx.Response.StatusCode = 404;
|
||||
}
|
||||
}
|
||||
}
|
||||
public class LoggingHandler : DelegatingHandler
|
||||
{
|
||||
public LoggingHandler(HttpMessageHandler innerHandler)
|
||||
: base(innerHandler)
|
||||
private static async Task WriteJsonStringAsync(IHttpContext ctx, string data)
|
||||
{
|
||||
var bt = Encoding.UTF8.GetBytes(data);
|
||||
ctx.Response.ContentEncoding = null;
|
||||
ctx.Response.ContentType = "application/json";
|
||||
ctx.Response.ContentLength64 = bt.Length;
|
||||
await ctx.Response.OutputStream.WriteAsync(bt, ctx.CancellationToken);
|
||||
await ctx.Response.OutputStream.FlushAsync();
|
||||
}
|
||||
|
||||
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
private static (string key, string value) GetHeader(string line)
|
||||
{
|
||||
Console.WriteLine("Request:");
|
||||
Console.WriteLine(request.ToString());
|
||||
if (request.Content != null)
|
||||
var pieces = line.Split([':'], 2);
|
||||
|
||||
return (pieces[0].Trim(), pieces[1].Trim());
|
||||
}
|
||||
private static async Task<byte[]?> SendReqLocalAndReadResponseAsync(byte[] bytes)
|
||||
{
|
||||
int line = 0;
|
||||
var bodyStartStr = Encoding.UTF8.GetString(bytes);
|
||||
|
||||
string method;
|
||||
string url = "";
|
||||
string httpVer;
|
||||
string authToken = "";
|
||||
List<NameValueHeaderValue> headers = [];
|
||||
|
||||
int currentByte = 0;
|
||||
|
||||
foreach (var item in bodyStartStr.Split("\r\n"))
|
||||
{
|
||||
Console.WriteLine(await request.Content.ReadAsStringAsync());
|
||||
if (line == 0)
|
||||
{
|
||||
var parts = item.Split(" ");
|
||||
method = parts[0];
|
||||
url = parts[1];
|
||||
httpVer = parts[2];
|
||||
}
|
||||
else if (item == null || string.IsNullOrEmpty(item))
|
||||
{
|
||||
currentByte += 2;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
var (key, value) = GetHeader(item);
|
||||
headers.Add(new NameValueHeaderValue(key, value));
|
||||
|
||||
if (key == "Authorization")
|
||||
{
|
||||
authToken = value.Replace("Bearer ", "");
|
||||
}
|
||||
}
|
||||
currentByte += 2 + item.Length;
|
||||
line++;
|
||||
}
|
||||
Console.WriteLine();
|
||||
|
||||
HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
|
||||
|
||||
Console.WriteLine("Response:");
|
||||
Console.WriteLine(response.ToString());
|
||||
if (response.Content != null)
|
||||
byte[] body;
|
||||
if (currentByte == bytes.Length)
|
||||
{
|
||||
Console.WriteLine(await response.Content.ReadAsStringAsync());
|
||||
// empty body
|
||||
body = [];
|
||||
}
|
||||
else
|
||||
{
|
||||
// not empty body, TODO
|
||||
File.WriteAllBytes("notemptybody", bytes);
|
||||
body = bytes.Skip(currentByte).ToArray();
|
||||
}
|
||||
Console.WriteLine();
|
||||
|
||||
return response;
|
||||
if (!url.StartsWith("/v1/"))
|
||||
{
|
||||
throw new NotImplementedException("handler for " + url + " not implemented");
|
||||
}
|
||||
|
||||
url = url.Replace("/v1", "");
|
||||
|
||||
// find appropriate handler
|
||||
Logger.Info("BATCH: /v1" + url);
|
||||
|
||||
foreach (var item in LobbyHandler.Handlers)
|
||||
{
|
||||
if (item.Key == url)
|
||||
{
|
||||
item.Value.Reset();
|
||||
item.Value.Contents = body;
|
||||
await item.Value.HandleAsync(authToken);
|
||||
return item.Value.ReturnBytes;
|
||||
}
|
||||
}
|
||||
Logger.Error("HANDLER NOT FOUND: " + url);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,18 +10,15 @@ namespace nksrv.Utils
|
||||
public class GreatLogger : ILogger
|
||||
{
|
||||
public LogLevel LogLevel => LogLevel.Info;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
||||
}
|
||||
static object lockObject = new object();
|
||||
static readonly object lockObject = new();
|
||||
public void Log(LogMessageReceivedEventArgs logEvent)
|
||||
{
|
||||
var msg = logEvent.Message;
|
||||
if (msg.StartsWith("["))
|
||||
|
||||
// strip out request id that embedio prints
|
||||
if (msg.StartsWith('['))
|
||||
{
|
||||
msg = msg.Substring(msg.IndexOf("]") + 2);
|
||||
msg = msg[(msg.IndexOf("]") + 2)..];
|
||||
}
|
||||
|
||||
// ignore telemtry server errors
|
||||
@@ -42,31 +39,27 @@ namespace nksrv.Utils
|
||||
|
||||
}
|
||||
|
||||
private ConsoleColor GetColorForMsg(LogMessageReceivedEventArgs logEvent)
|
||||
private static ConsoleColor GetColorForMsg(LogMessageReceivedEventArgs logEvent)
|
||||
{
|
||||
if (logEvent.Message.Contains("404 Not Found"))
|
||||
return ConsoleColor.Red;
|
||||
else if (logEvent.Message.Contains("200 OK"))
|
||||
return ConsoleColor.DarkGreen;
|
||||
switch (logEvent.MessageType)
|
||||
return logEvent.MessageType switch
|
||||
{
|
||||
case LogLevel.None:
|
||||
return ConsoleColor.White;
|
||||
case LogLevel.Trace:
|
||||
return ConsoleColor.Gray;
|
||||
case LogLevel.Debug:
|
||||
return ConsoleColor.Gray;
|
||||
case LogLevel.Info:
|
||||
return ConsoleColor.Gray;
|
||||
case LogLevel.Warning:
|
||||
return ConsoleColor.Yellow;
|
||||
case LogLevel.Error:
|
||||
return ConsoleColor.Red;
|
||||
case LogLevel.Fatal:
|
||||
return ConsoleColor.Red;
|
||||
default:
|
||||
return ConsoleColor.White;
|
||||
}
|
||||
LogLevel.None => ConsoleColor.White,
|
||||
LogLevel.Trace => ConsoleColor.Gray,
|
||||
LogLevel.Debug => ConsoleColor.Gray,
|
||||
LogLevel.Info => ConsoleColor.Gray,
|
||||
LogLevel.Warning => ConsoleColor.Yellow,
|
||||
LogLevel.Error => ConsoleColor.Red,
|
||||
LogLevel.Fatal => ConsoleColor.Red,
|
||||
_ => ConsoleColor.White,
|
||||
};
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,13 +13,13 @@ namespace nksrv.Utils
|
||||
{
|
||||
public class AccessToken
|
||||
{
|
||||
public string Token;
|
||||
public string Token = "";
|
||||
public long ExpirationTime;
|
||||
public ulong UserID;
|
||||
}
|
||||
public class FieldInfo
|
||||
{
|
||||
public List<NetFieldStageData> CompletedStages = new();
|
||||
public List<NetFieldStageData> CompletedStages = [];
|
||||
}
|
||||
|
||||
public class Character
|
||||
@@ -49,26 +49,26 @@ namespace nksrv.Utils
|
||||
|
||||
|
||||
// Game data
|
||||
public List<string> CompletedScenarios = new();
|
||||
public Dictionary<int, FieldInfo> FieldInfo = new();
|
||||
public Dictionary<string, string> MapJson = new();
|
||||
public Dictionary<CurrencyType, long> Currency = new Dictionary<CurrencyType, long>() {
|
||||
public List<string> CompletedScenarios = [];
|
||||
public Dictionary<int, FieldInfo> FieldInfo = [];
|
||||
public Dictionary<string, string> MapJson = [];
|
||||
public Dictionary<CurrencyType, long> Currency = new() {
|
||||
{ CurrencyType.ContentStamina, 2 },
|
||||
{ CurrencyType.CharPremiumTicket, 23422 }
|
||||
};
|
||||
|
||||
public List<Character> Characters = new();
|
||||
public List<Character> Characters = [];
|
||||
public NetWholeUserTeamData TeamData = new();
|
||||
public List<int> ClearedTutorials = new();
|
||||
public List<int> ClearedTutorials = [];
|
||||
}
|
||||
public class CoreInfo
|
||||
{
|
||||
public List<User> Users = new List<User>();
|
||||
public List<User> Users = [];
|
||||
|
||||
public List<AccessToken> LauncherAccessTokens = new List<AccessToken>();
|
||||
public List<AccessToken> LauncherAccessTokens = [];
|
||||
|
||||
|
||||
public Dictionary<string, GameClientInfo> GameClientTokens = new Dictionary<string, GameClientInfo>();
|
||||
public Dictionary<string, GameClientInfo> GameClientTokens = [];
|
||||
}
|
||||
internal class JsonDb
|
||||
{
|
||||
|
||||
34
nksrv/Utils/LoggingHttpHandler.cs
Normal file
34
nksrv/Utils/LoggingHttpHandler.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace nksrv.Utils
|
||||
{
|
||||
public class LoggingHttpHandler(HttpMessageHandler innerHandler) : DelegatingHandler(innerHandler)
|
||||
{
|
||||
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
{
|
||||
Console.WriteLine("Request:");
|
||||
Console.WriteLine(request.ToString());
|
||||
if (request.Content != null)
|
||||
{
|
||||
Console.WriteLine(await request.Content.ReadAsStringAsync(cancellationToken));
|
||||
}
|
||||
Console.WriteLine();
|
||||
|
||||
HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
|
||||
|
||||
Console.WriteLine("Response:");
|
||||
Console.WriteLine(response.ToString());
|
||||
if (response.Content != null)
|
||||
{
|
||||
Console.WriteLine(await response.Content.ReadAsStringAsync(cancellationToken));
|
||||
}
|
||||
Console.WriteLine();
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,11 +15,11 @@ namespace nksrv.Utils
|
||||
{
|
||||
public class PacketDecryption
|
||||
{
|
||||
public static async Task<PacketDecryptResponse> DecryptOrReturnContentAsync(IHttpContext ctx, bool decompress = false)
|
||||
public static async Task<PacketDecryptResponse> DecryptOrReturnContentAsync(IHttpContext ctx)
|
||||
{
|
||||
byte[] bin = Array.Empty<byte>();
|
||||
byte[] bin = [];
|
||||
|
||||
using MemoryStream buffer = new MemoryStream();
|
||||
using MemoryStream buffer = new();
|
||||
|
||||
var stream = ctx.Request.InputStream;
|
||||
|
||||
@@ -46,20 +46,15 @@ namespace nksrv.Utils
|
||||
var decryptionToken = CBorReadString(stream);
|
||||
var nonce = CBorReadByteString(stream);
|
||||
|
||||
MemoryStream encryptedBytes = new MemoryStream();
|
||||
MemoryStream encryptedBytes = new();
|
||||
stream.CopyTo(encryptedBytes);
|
||||
|
||||
var bytes = encryptedBytes.ToArray();
|
||||
|
||||
var key = LobbyHandler.GetInfo(decryptionToken);
|
||||
if (key == null)
|
||||
{
|
||||
throw HttpException.BadRequest("Invalid decryption token");
|
||||
}
|
||||
|
||||
var key = LobbyHandler.GetInfo(decryptionToken) ?? throw HttpException.BadRequest("Invalid decryption token");
|
||||
var additionalData = GenerateAdditionalData(decryptionToken, false);
|
||||
|
||||
var x = SecretAeadXChaCha20Poly1305.Decrypt(bytes, nonce, key.Keys.ReadSharedSecret, additionalData.ToArray());
|
||||
var x = SecretAeadXChaCha20Poly1305.Decrypt(bytes, nonce, key.Keys.ReadSharedSecret, [.. additionalData]);
|
||||
|
||||
var ms = new MemoryStream(x);
|
||||
// File.WriteAllBytes("fullPkt-decr", ms.ToArray());
|
||||
@@ -78,7 +73,7 @@ namespace nksrv.Utils
|
||||
//File.WriteAllBytes("contentsgzip", contents);
|
||||
// gzip compression is used
|
||||
using Stream csStream = new GZipStream(new MemoryStream(contents), CompressionMode.Decompress);
|
||||
using MemoryStream decoded = new MemoryStream();
|
||||
using MemoryStream decoded = new();
|
||||
csStream.CopyTo(decoded);
|
||||
|
||||
contents = decoded.ToArray();
|
||||
@@ -159,13 +154,8 @@ namespace nksrv.Utils
|
||||
|
||||
public static byte[] EncryptData(byte[] message, string authToken)
|
||||
{
|
||||
var key = LobbyHandler.GetInfo(authToken);
|
||||
if (key == null)
|
||||
{
|
||||
throw HttpException.BadRequest("Invalid decryption token");
|
||||
}
|
||||
|
||||
MemoryStream m = new MemoryStream();
|
||||
var key = LobbyHandler.GetInfo(authToken) ?? throw HttpException.BadRequest("Invalid decryption token");
|
||||
MemoryStream m = new();
|
||||
|
||||
m.WriteByte(89); // cbor ushort
|
||||
|
||||
@@ -205,13 +195,13 @@ namespace nksrv.Utils
|
||||
var additionalData = GenerateAdditionalData(authToken, true);
|
||||
|
||||
// prep payload
|
||||
MemoryStream msm = new MemoryStream();
|
||||
MemoryStream msm = new();
|
||||
msm.WriteByte(88);
|
||||
msm.WriteByte(0);
|
||||
|
||||
msm.Write(message);
|
||||
|
||||
var encryptedBytes = SecretAeadXChaCha20Poly1305.Encrypt(msm.ToArray(), nonce, key.Keys.TransferSharedSecret, additionalData.ToArray());
|
||||
var encryptedBytes = SecretAeadXChaCha20Poly1305.Encrypt(msm.ToArray(), nonce, key.Keys.TransferSharedSecret, [.. additionalData]);
|
||||
|
||||
// write encrypted data
|
||||
m.Write(encryptedBytes);
|
||||
@@ -293,16 +283,18 @@ namespace nksrv.Utils
|
||||
{
|
||||
var b = s.ReadByte();
|
||||
var type = b & 0x1f;
|
||||
var res = new CBorItem();
|
||||
res.MajorType = (b >> 5) & 7;
|
||||
CBorItem res = new()
|
||||
{
|
||||
MajorType = (b >> 5) & 7
|
||||
};
|
||||
switch (type)
|
||||
{
|
||||
case 24:
|
||||
// byte
|
||||
res.ByteValue = new byte[] { (byte)s.ReadByte() };
|
||||
res.ByteValue = [(byte)s.ReadByte()];
|
||||
res.type = CBorItemType.Byte;
|
||||
|
||||
res.FullValue = (int)res.ByteValue[0];
|
||||
res.FullValue = res.ByteValue[0];
|
||||
break;
|
||||
case 25:
|
||||
byte[] arr = new byte[2];
|
||||
@@ -331,9 +323,7 @@ namespace nksrv.Utils
|
||||
while (i != buf.Length)
|
||||
{
|
||||
if (i > buf.Length)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
||||
var pos = buf.Length - i;
|
||||
throw new ArgumentOutOfRangeException(nameof(buf));
|
||||
var read = s.Read(buf, i, buf.Length - i);
|
||||
if (read == 0)
|
||||
break;
|
||||
@@ -349,13 +339,13 @@ namespace nksrv.Utils
|
||||
public class PacketDecryptResponse
|
||||
{
|
||||
public ulong UserId;
|
||||
public string UsedAuthToken;
|
||||
public byte[] Contents;
|
||||
public string UsedAuthToken = "";
|
||||
public byte[] Contents = [];
|
||||
}
|
||||
public class CBorItem
|
||||
{
|
||||
public CBorItemType type;
|
||||
public byte[] ByteValue;
|
||||
public byte[] ByteValue = [];
|
||||
public ushort UShortValue;
|
||||
public int MajorType;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user