Implement Cardmng shims

This commit is contained in:
BtbN 2019-06-01 00:49:01 +02:00
parent e901a9c0be
commit 162b646163
12 changed files with 419 additions and 151 deletions

View File

@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Xml.Linq;
using Microsoft.AspNetCore.Mvc;
using ClanServer.Formatters;
using ClanServer.Routing;
namespace ClanServer.Controllers.Core
{
[ApiController, Route("core")]
public class CardmngController : ControllerBase
{
[HttpPost, XrpcCall("cardmng.inquire")]
public ActionResult<EamuseXrpcData> Inquire([FromBody] EamuseXrpcData data)
{
string cardid = data.Document.Element("call").Element("cardmng").Attribute("cardid").Value;
string cardType = data.Document.Element("call").Element("cardmng").Attribute("cardtype").Value;
string update = data.Document.Element("call").Element("cardmng").Attribute("update").Value;
if (update != "") // TODO: actually register cards
{
data.Document = new XDocument(new XElement("response", new XElement("cardmng",
new XAttribute("binded", "1"),
new XAttribute("dataid", "DD389C3FFB6F47BA"),
new XAttribute("refid", "DD389C3FFB6F47BA"),
new XAttribute("ecflag", "1"),
new XAttribute("newflag", "0"),
new XAttribute("expired", "0")
)));
}
else
{
data.Document = new XDocument(new XElement("response", new XElement("cardmng",
new XAttribute("status", "112")
)));
}
return data;
}
[HttpPost, XrpcCall("cardmng.authpass")]
public ActionResult<EamuseXrpcData> Authpass([FromBody] EamuseXrpcData data)
{
data.Document = new XDocument(new XElement("response", new XElement("cardmng",
new XAttribute("status", "0")
)));
return data;
}
}
}

View File

@ -6,7 +6,8 @@ using System.Xml.Linq;
using System.Text;
using Microsoft.AspNetCore.Mvc;
using ClanServer.Formatters;
using eAmuseCore.KBinXML;
using ClanServer.Routing;
namespace ClanServer.Controllers.Core
@ -21,50 +22,44 @@ namespace ClanServer.Controllers.Core
string requestedEncoding = facilityReq.Attribute("encoding").Value;
string method = facilityReq.Attribute("method").Value;
var Str = new XAttribute("__type", "str");
var U8 = new XAttribute("__type", "u8");
var U16 = new XAttribute("__type", "u16");
var S32 = new XAttribute("__type", "s32");
var IP4 = new XAttribute("__type", "ip4");
data.Document = new XDocument(new XElement("response", new XElement("facility",
new XElement("location",
new XElement("id", Str, "53BDC526"),
new XElement("country", Str, "US"),
new XElement("region", Str, "1"),
new XElement("name", Str, ""),
new XElement("type", U8, "0")
new KStr("id", "53BDC526"),
new KStr("country", "US"),
new KStr("region", "1"),
new KStr("name", ""),
new KU8("type", 0)
),
new XElement("line",
new XElement("id", Str, ""),
new XElement("class", U8, "0")
new KStr("id", ""),
new KU8("class", 0)
),
new XElement("portfw",
new XElement("globalip", IP4, HttpContext.Connection.RemoteIpAddress.MapToIPv4().ToString()),
new XElement("globalport", U16, "5700"),
new XElement("privateport", U16, "5700")
new KIP4("globalip", HttpContext.Connection.RemoteIpAddress),
new KU16("globalport", 5700),
new KU16("privateport", 5700)
),
new XElement("public",
new XElement("flag", U8, "0"),
new XElement("name", Str, ""),
new XElement("latitude", Str, ""),
new XElement("longitude", Str, "")
new KU8("flag", 0),
new KStr("name", ""),
new KStr("latitude", ""),
new KStr("longitude", "")
),
new XElement("share",
new XElement("eacoin",
new XElement("notchamount", S32, "0"),
new XElement("notchcount", S32, "0"),
new XElement("supplylimit", S32, "100000")
new KS32("notchamount", 0),
new KS32("notchcount", 0),
new KS32("supplylimit", 100000)
),
new XElement("url",
new XElement("eapass", Str, "http://eagate.573.jp/"),
new XElement("arcadefan", Str, "http://eagate.573.jp/"),
new XElement("konaminetdx", Str, "http://eagate.573.jp/"),
new XElement("konamiid", Str, "http://eagate.573.jp/"),
new XElement("eagate", Str, "http://eagate.573.jp/")
new KStr("eapass", "http://eagate.573.jp/"),
new KStr("arcadefan", "http://eagate.573.jp/"),
new KStr("konaminetdx", "http://eagate.573.jp/"),
new KStr("konamiid", "http://eagate.573.jp/"),
new KStr("eagate", "http://eagate.573.jp/")
)
)
)));
))); ;
if (requestedEncoding == "Shift-JIS")
{

View File

@ -16,7 +16,9 @@ namespace ClanServer.Controllers.Core
[HttpPost, XrpcCall("pcbtracker.alive")]
public ActionResult<EamuseXrpcData> Alive([FromBody] EamuseXrpcData data, [FromQuery] string model)
{
data.Document = new XDocument(new XElement("response", new XElement("pcbtracker", new XAttribute("ecenable", "1"))));
data.Document = new XDocument(new XElement("response", new XElement("pcbtracker",
new XAttribute("ecenable", "1")
)));
return data;
}

View File

@ -21,7 +21,23 @@ namespace ClanServer.Controllers.Core
string modelUrl;
string[] modelItems;
if (model == "L44:J:E:A:2018070901")
string[] coreItems = new[]
{
"cardmng",
"facility",
"message",
"numbering",
"package",
"pcbevent",
"pcbtracker",
"pkglist",
"posevent",
"userdata",
"userid",
"eacoin",
};
if (model.StartsWith("L44:J:E:A:2018"))
{
modelItems = new[]
{
@ -44,22 +60,6 @@ namespace ClanServer.Controllers.Core
new XAttribute("mode", "operation"),
new XAttribute("status", "0"));
string[] coreItems = new[]
{
"cardmng",
"facility",
"message",
"numbering",
"package",
"pcbevent",
"pcbtracker",
"pkglist",
"posevent",
"userdata",
"userid",
"eacoin",
};
foreach (string coreItem in coreItems)
servicesElement.Add(new XElement("item", new XAttribute("name", coreItem), new XAttribute("url", coreUrl)));

View File

@ -5,7 +5,8 @@ using System.Threading.Tasks;
using System.Xml.Linq;
using Microsoft.AspNetCore.Mvc;
using ClanServer.Formatters;
using eAmuseCore.KBinXML;
using ClanServer.Routing;
namespace ClanServer.Controllers.Core
@ -16,11 +17,8 @@ namespace ClanServer.Controllers.Core
[HttpPost, Route("8"), XrpcCall("demodata.get_info")]
public ActionResult<EamuseXrpcData> GetInfo([FromBody] EamuseXrpcData data)
{
var S32 = new XAttribute("__type", "s32");
var C64 = new XAttribute("__count", "64");
data.Document = new XDocument(new XElement("response", new XElement("demodata", new XElement("data", new XElement("info",
new XElement("black_jacket_list", S32, C64, "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0")
data.Document = new XDocument(new XElement("response", new XElement("demodata", new XElement("data", new XElement("info",
new KS32("black_jacket_list", 64, 0)
)))));
return data;

View File

@ -5,6 +5,8 @@ using System.Threading.Tasks;
using System.Xml.Linq;
using Microsoft.AspNetCore.Mvc;
using eAmuseCore.KBinXML;
using ClanServer.Formatters;
using ClanServer.Routing;
@ -18,53 +20,42 @@ namespace ClanServer.Controllers.Core
{
string locationId = data.Document.Element("call").Element("shopinfo").Element("shop").Element("locationid").Value;
var Str = new XAttribute("__type", "str");
var U8 = new XAttribute("__type", "u8");
var S16 = new XAttribute("__type", "s16");
var S32 = new XAttribute("__type", "s32");
var U32 = new XAttribute("__type", "u32");
var U64 = new XAttribute("__type", "u64");
var Bool = new XAttribute("__type", "bool");
var C16 = new XAttribute("__count", "16");
var C64 = new XAttribute("__count", "64");
data.Document = new XDocument(new XElement("response", new XElement("shopinfo", new XElement("data",
new XElement("cabid", U32, "1"),
new XElement("locationid", Str, locationId),
new XElement("tax_phase", U8, "0"),
new KU32("cabid", 1),
new KStr("locationid", locationId),
new KU8("tax_phase", 0),
new XElement("facility",
new XElement("exist", U32, "0")
new KU32("exist", 0)
),
new XElement("event_flag", U64, "0"),
new KU64("event_flag", 0),
new XElement("info",
new XElement("event_info",
new XElement("event", new XAttribute("type", "15"),
new XElement("state", U8, "1")
new KU8("state", 1)
),
new XElement("event", new XAttribute("type", "5"),
new XElement("state", U8, "0")
new KU8("state", 0)
),
new XElement("event", new XAttribute("type", "6"),
new XElement("state", U8, "0")
new KU8("state", 0)
)
),
new XElement("share_music"),
new XElement("genre_def_music"),
new XElement("black_jacket_list", S32, C64, "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"),
new XElement("white_music_list", S32, C64, "-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1"),
new XElement("white_marker_list", S32, C16, "-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1"),
new XElement("white_theme_list", S32, C16, "-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1"),
new XElement("open_music_list", S32, C64, "-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1"),
new XElement("shareable_music_list", S32, C64, "-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1"),
new KS32("black_jacket_list", 64, 0),
new KS32("white_music_list", 64, -1),
new KS32("white_marker_list", 16, -1),
new KS32("white_theme_list", 16, -1),
new KS32("open_music_list", 64, -1),
new KS32("shareable_music_list", 64, -1),
new XElement("jbox",
new XElement("point", S32, "1"),
new KS32("point", 1),
new XElement("emblem",
new XElement("normal",
new XElement("index", S16, "50")
new KS16("index", 50)
),
new XElement("premium",
new XElement("index", S16, "50")
new KS16("index", 50)
)
)
),
@ -72,10 +63,10 @@ namespace ClanServer.Controllers.Core
new XElement("rating_s")
),
new XElement("expert_option",
new XElement("is_available", Bool, "1")
new KBool("is_available", true)
),
new XElement("all_music_matching",
new XElement("is_available", Bool, "0")
new KBool("is_available", false)
),
new XElement("department",
new XElement("pack_list")

View File

@ -0,0 +1,12 @@
using System.Xml.Linq;
using System.Text;
namespace ClanServer
{
public class EamuseXrpcData
{
public XDocument Document;
public Encoding Encoding;
public string EamuseInfo;
}
}

View File

@ -14,13 +14,6 @@ using System.Text;
namespace ClanServer.Formatters
{
public class EamuseXrpcData
{
public XDocument Document;
public Encoding Encoding;
public string EamuseInfo;
}
public class EamuseXrpcInputFormatter : InputFormatter
{
public EamuseXrpcInputFormatter()
@ -116,6 +109,7 @@ namespace ClanServer.Formatters
}
catch (Exception)
{
Console.WriteLine("Got invalid binary XML input!");
return null;
}
});
@ -131,56 +125,4 @@ namespace ClanServer.Formatters
});
}
}
public class EamuseXrpcOutputFormatter : OutputFormatter
{
public EamuseXrpcOutputFormatter()
{
SupportedMediaTypes.Add("application/octet-stream");
}
protected override bool CanWriteType(Type type)
{
return type == typeof(EamuseXrpcData);
}
public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context)
{
var response = context.HttpContext.Response;
if (!(context.Object is EamuseXrpcData data))
throw new ArgumentNullException("Input EamuseXrpcData is null");
(byte[] rawData, string compAlgo) = await Task.Run(() =>
{
byte[] resData;
if (data.Encoding != null)
resData = new KBinXML(data.Document, data.Encoding).Bytes;
else
resData = new KBinXML(data.Document).Bytes;
string algo = "none";
var compressed = LZ77.Compress(resData).ToArray();
if (compressed.Length < resData.Length)
{
resData = compressed;
algo = "lz77";
}
compressed = null;
if (data.EamuseInfo != null)
resData = RC4.ApplyEAmuseInfo(data.EamuseInfo, resData).ToArray();
return (resData, algo);
});
response.Headers.Add("X-Eamuse-Info", data.EamuseInfo);
response.Headers.Add("X-Compress", compAlgo);
response.ContentType = "application/octet-stream";
response.ContentLength = rawData.Length;
await response.Body.WriteAsync(rawData, 0, rawData.Length);
}
}
}

View File

@ -0,0 +1,67 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Formatters;
using eAmuseCore.Compression;
using eAmuseCore.Crypto;
using eAmuseCore.KBinXML;
namespace ClanServer.Formatters
{
public class EamuseXrpcOutputFormatter : OutputFormatter
{
public EamuseXrpcOutputFormatter()
{
SupportedMediaTypes.Add("application/octet-stream");
}
protected override bool CanWriteType(Type type)
{
return type == typeof(EamuseXrpcData);
}
public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context)
{
var response = context.HttpContext.Response;
if (!(context.Object is EamuseXrpcData data))
throw new ArgumentNullException("Input EamuseXrpcData is null");
(byte[] rawData, string compAlgo) = await Task.Run(() =>
{
byte[] resData;
if (data.Encoding != null)
resData = new KBinXML(data.Document, data.Encoding).Bytes;
else
resData = new KBinXML(data.Document).Bytes;
string algo = "none";
var compressed = LZ77.Compress(resData).ToArray();
if (compressed.Length < resData.Length)
{
resData = compressed;
algo = "lz77";
}
compressed = null;
if (data.EamuseInfo != null)
resData = RC4.ApplyEAmuseInfo(data.EamuseInfo, resData).ToArray();
return (resData, algo);
});
if (data.EamuseInfo != null)
response.Headers.Add("X-Eamuse-Info", data.EamuseInfo);
response.Headers.Add("X-Compress", compAlgo);
response.ContentType = "application/octet-stream";
response.ContentLength = rawData.Length;
await response.Body.WriteAsync(rawData, 0, rawData.Length);
}
}
}

View File

@ -0,0 +1,205 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Linq;
namespace eAmuseCore.KBinXML
{
public class KElement : XElement
{
public KElement(string name, string kType, params string[] vals)
: base(name, new XAttribute("__type", kType))
{
if (vals.Length > 1)
Add(new XAttribute("__count", vals.Length));
Value = string.Join(" ", vals);
}
}
public class KStr : KElement
{
const string KType = "str";
public KStr(string name, string value)
: base(name, KType, value)
{}
}
public class KBool : KElement
{
const string KType = "bool";
public KBool(string name, bool value)
: base(name, KType, value ? "1" : "0")
{}
}
public class KIP4 : KElement
{
const string KType = "ip4";
public KIP4(string name, System.Net.IPAddress address)
: base(name, KType, address.MapToIPv4().ToString())
{}
}
public class KInteger<T> : KElement
{
public KInteger(string name, string kType, T[] vals)
: base(name, kType, Array.ConvertAll(vals, val => val.ToString()))
{}
public KInteger(string name, string kType, T val)
: this(name, kType, new[] { val })
{}
public KInteger(string name, string kType, int cnt, T val)
: this(name, kType, InitArray(cnt, val))
{}
private static T[] InitArray(int cnt, T val)
{
T[] res = new T[cnt];
for (int i = 0; i < cnt; ++i)
res[i] = val;
return res;
}
}
public class KS8 : KInteger<sbyte>
{
const string KType = "s8";
public KS8(string name, sbyte[] vals)
: base(name, KType, vals)
{}
public KS8(string name, sbyte val)
: base(name, KType, val)
{}
public KS8(string name, int cnt, sbyte val)
: base(name, KType, cnt, val)
{}
}
public class KU8 : KInteger<byte>
{
const string KType = "u8";
public KU8(string name, byte[] vals)
: base(name, KType, vals)
{}
public KU8(string name, byte val)
: base(name, KType, val)
{}
public KU8(string name, int cnt, byte val)
: base(name, KType, cnt, val)
{}
}
public class KS16 : KInteger<short>
{
const string KType = "s16";
public KS16(string name, short[] vals)
: base(name, KType, vals)
{ }
public KS16(string name, short val)
: base(name, KType, val)
{ }
public KS16(string name, int cnt, short val)
: base(name, KType, cnt, val)
{ }
}
public class KU16 : KInteger<ushort>
{
const string KType = "u16";
public KU16(string name, ushort[] vals)
: base(name, KType, vals)
{ }
public KU16(string name, ushort val)
: base(name, KType, val)
{ }
public KU16(string name, int cnt, ushort val)
: base(name, KType, cnt, val)
{ }
}
public class KS32 : KInteger<int>
{
const string KType = "s32";
public KS32(string name, int[] vals)
: base(name, KType, vals)
{ }
public KS32(string name, int val)
: base(name, KType, val)
{ }
public KS32(string name, int cnt, int val)
: base(name, KType, cnt, val)
{ }
}
public class KU32 : KInteger<uint>
{
const string KType = "u32";
public KU32(string name, uint[] vals)
: base(name, KType, vals)
{ }
public KU32(string name, uint val)
: base(name, KType, val)
{ }
public KU32(string name, int cnt, uint val)
: base(name, KType, cnt, val)
{ }
}
public class KS64 : KInteger<long>
{
const string KType = "s64";
public KS64(string name, long[] vals)
: base(name, KType, vals)
{ }
public KS64(string name, long val)
: base(name, KType, val)
{ }
public KS64(string name, int cnt, long val)
: base(name, KType, cnt, val)
{ }
}
public class KU64 : KInteger<ulong>
{
const string KType = "u64";
public KU64(string name, ulong[] vals)
: base(name, KType, vals)
{ }
public KU64(string name, ulong val)
: base(name, KType, val)
{ }
public KU64(string name, int cnt, ulong val)
: base(name, KType, cnt, val)
{ }
}
}

View File

@ -111,26 +111,28 @@ namespace eAmuseCore.KBinXML
string[] names = Names.Select(name => count.ToString() + name).ToArray();
int size = Size * count;
KBinFromString fromString = (s, o) =>
byte[] fromString(string[] s, int o)
{
if (s.Length - o < count)
throw new ArgumentException("input does not contain enough elements");
byte[] res = new byte[size];
for (int i = 0; i < count; ++i)
Buffer.BlockCopy(Converter.KFromString(s, o + i), 0, res, i * Size, Size);
return res;
};
KBinToString toString = (b, o) =>
}
string toString(byte[] b, int o)
{
string[] res = new string[count];
for (int i = 0; i < count; ++i)
res[i] = Converter.KToString(b, i * Size + o);
return string.Join(" ", res);
};
}
return new XmlType(size, new KBinConverter(fromString, toString), count, names);
}

View File

@ -15,9 +15,9 @@ namespace eAmuseTest
{
static void Main(string[] args)
{
string compress = "lz77";
string eamuse_info = "1-5cf049c8-6ec5";
byte[] data = HexToBytes("6e84f02c117651c66313a5c17fa0ddc40e3f4cd52a94bd34f460e763f610e03d5d01f876");
string compress = "none";
string eamuse_info = "1-5cf04a26-56c5";
byte[] data = HexToBytes("a7a4eef0f58176b89e5f6d0c91df45549f0fdb12a7ea731e9f2f52a85db742ed71eceeee848cfcedf8ca2b59161900ba");
compress = compress.ToLower();