From 5f7921ea6f5093847133555ce5a906001ee513cf Mon Sep 17 00:00:00 2001 From: hictooth Date: Wed, 21 Jun 2023 20:57:43 +0100 Subject: [PATCH 1/4] implement dragons pets, which are dragons in SoD --- .gitignore | 3 +- README.md | 6 +- mitm-redirect.py | 38 +++- src/Controllers/Common/ContentController.cs | 184 +++++++++++++++++++- src/Model/DBContext.cs | 16 ++ src/Model/Dragon.cs | 20 +++ src/Model/Image.cs | 22 +++ src/Model/Viking.cs | 3 +- src/Schema/CommonInventoryRequest.cs | 29 +++ src/Schema/CommonInventoryResponse.cs | 20 +++ src/Schema/CommonInventoryResponseItem.cs | 17 ++ src/Schema/CreatePetResponse.cs | 14 ++ src/Schema/DataType.cs | 36 ++++ src/Schema/ImageData.cs | 29 +++ src/Schema/ImageDataDecal.cs | 20 +++ src/Schema/ImageDataDecalPosition.cs | 14 ++ src/Schema/PrizeItemResponse.cs | 17 ++ src/Schema/RaisedPetAccessory.cs | 23 +++ src/Schema/RaisedPetAttribute.cs | 17 ++ src/Schema/RaisedPetColor.cs | 20 +++ src/Schema/RaisedPetData.cs | 71 ++++++++ src/Schema/RaisedPetGrowthState.cs | 20 +++ src/Schema/RaisedPetRequest.cs | 32 ++++ src/Schema/RaisedPetSetResult.cs | 18 ++ src/Schema/RaisedPetSkill.cs | 17 ++ src/Schema/RaisedPetState.cs | 14 ++ src/Schema/SetRaisedPetResponse.cs | 17 ++ src/Schema/UserGameCurrency.cs | 20 +++ 28 files changed, 748 insertions(+), 9 deletions(-) create mode 100644 src/Model/Dragon.cs create mode 100644 src/Model/Image.cs create mode 100644 src/Schema/CommonInventoryRequest.cs create mode 100644 src/Schema/CommonInventoryResponse.cs create mode 100644 src/Schema/CommonInventoryResponseItem.cs create mode 100644 src/Schema/CreatePetResponse.cs create mode 100644 src/Schema/DataType.cs create mode 100644 src/Schema/ImageData.cs create mode 100644 src/Schema/ImageDataDecal.cs create mode 100644 src/Schema/ImageDataDecalPosition.cs create mode 100644 src/Schema/PrizeItemResponse.cs create mode 100644 src/Schema/RaisedPetAccessory.cs create mode 100644 src/Schema/RaisedPetAttribute.cs create mode 100644 src/Schema/RaisedPetColor.cs create mode 100644 src/Schema/RaisedPetData.cs create mode 100644 src/Schema/RaisedPetGrowthState.cs create mode 100644 src/Schema/RaisedPetRequest.cs create mode 100644 src/Schema/RaisedPetSetResult.cs create mode 100644 src/Schema/RaisedPetSkill.cs create mode 100644 src/Schema/RaisedPetState.cs create mode 100644 src/Schema/SetRaisedPetResponse.cs create mode 100644 src/Schema/UserGameCurrency.cs diff --git a/.gitignore b/.gitignore index 0355c6d..b2ad85a 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ src/bin src/obj src/sodoff.db src/sodoff.db-shm -src/sodoff.db-wal \ No newline at end of file +src/sodoff.db-wal +__pycache__/ diff --git a/README.md b/README.md index 05bd180..4c91cb6 100644 --- a/README.md +++ b/README.md @@ -45,12 +45,17 @@ Then run School of Dragons. - SetAvatar - RegisterParent - RegisterChild +- SetRaisedPet +- GetAllActivePetsByuserId +- SetImage +- GetImage #### Implemented enough (probably) - GetRules (doesn't return any rules, probably doesn't need to) - GetQuestions (doesn't return all questions, probably doesn't need to) - GetSubscriptionInfo (always returns member, with end date 10 years from now) - SetTaskState (only the TaskCanBeDone status is supported) +- CreatePet (doesn't handle SetAsSelectedPet/UnSelectOtherPets) #### Partially implemented - GetUserProfileByUserID (a lot is still placeholder) @@ -64,7 +69,6 @@ Then run School of Dragons. - GetStore (needs to filter out stores from request) - GetAllRanks (needs to be populated with what ranks the user has) - GetCommonInventory -- GetAllActivePetsByuserId (always returns null) - GetPetAchievementsByUserId (always returns null) - GetUserUpcomingMissionState (returns no missions) - GetUserCompletedMissionState (returns no missions) diff --git a/mitm-redirect.py b/mitm-redirect.py index 509c2fd..ee0a843 100644 --- a/mitm-redirect.py +++ b/mitm-redirect.py @@ -1,10 +1,44 @@ from mitmproxy import ctx import mitmproxy.http +methods = [ + 'GetRules', + 'LoginParent', + 'RegisterParent', + 'GetSubscriptionInfo', + 'GetUserInfoByApiToken', + 'IsValidApiToken_V2', + 'ValidateName', + 'GetDefaultNameSuggestion', + 'RegisterChild', + 'GetProfileByUserId', + 'LoginChild', + 'GetUserProfileByUserID', + 'GetKeyValuePair', + 'SetKeyValuePair', + 'GetKeyValuePairByUserID', + 'SetKeyValuePairByUserID', + 'GetUserProfile', + 'GetQuestions', + 'GetCommonInventory', + 'GetAuthoritativeTime', + 'SetAvatar', + 'GetAllActivePetsByuserId', + 'GetPetAchievementsByUserID', + 'GetDetailedChildList', + 'GetStore', + 'GetAllRanks', + 'GetUserUpcomingMissionState', + 'GetUserActiveMissionState', + 'GetUserCompletedMissionState', + 'SetTaskState', + 'CreatePet', + 'SetRaisedPet', + 'SetImage', + 'GetImage' +] def routable(path): - methods = ['GetRules', 'LoginParent', 'RegisterParent', 'GetSubscriptionInfo', 'GetUserInfoByApiToken', 'IsValidApiToken_V2', 'ValidateName', 'GetDefaultNameSuggestion', 'RegisterChild', 'GetProfileByUserId', 'LoginChild', 'GetUserProfileByUserID', 'GetKeyValuePair', 'SetKeyValuePair', 'GetKeyValuePairByUserID', 'SetKeyValuePairByUserID', 'GetUserProfile', 'GetQuestions', 'GetCommonInventory', -'GetAuthoritativeTime', 'SetAvatar', 'GetAllActivePetsByuserId', 'GetPetAchievementsByUserID', 'GetDetailedChildList', 'GetStore', 'GetAllRanks', 'GetUserUpcomingMissionState', 'GetUserActiveMissionState', 'GetUserCompletedMissionState', 'SetTaskState'] for method in methods: if method in path: return True diff --git a/src/Controllers/Common/ContentController.cs b/src/Controllers/Common/ContentController.cs index b584175..730909b 100644 --- a/src/Controllers/Common/ContentController.cs +++ b/src/Controllers/Common/ContentController.cs @@ -5,6 +5,7 @@ using sodoff.Model; using sodoff.Schema; using sodoff.Services; using sodoff.Util; +using System; namespace sodoff.Controllers.Common; public class ContentController : Controller { @@ -196,11 +197,186 @@ public class ContentController : Controller { } [HttpPost] - //[Produces("application/xml")] + [Produces("application/xml")] + [Route("V2/ContentWebService.asmx/CreatePet")] + public IActionResult CreatePet([FromForm] string apiToken, [FromForm] string request) { + Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; + if (viking is null) { + // TODO: result for invalid session + return Ok(); + } + + RaisedPetRequest raisedPetRequest = XmlUtil.DeserializeXml(request); + // TODO: Investigate SetAsSelectedPet and UnSelectOtherPets - they don't seem to do anything + + // Update the RaisedPetData with the info + String dragonId = Guid.NewGuid().ToString(); + raisedPetRequest.RaisedPetData.IsPetCreated = true; + raisedPetRequest.RaisedPetData.RaisedPetID = 0; // Initially make zero, so the db auto-fills + raisedPetRequest.RaisedPetData.EntityID = Guid.Parse(dragonId); + raisedPetRequest.RaisedPetData.Name = string.Concat("Dragon-", dragonId.AsSpan(0, 8)); // Start off with a random name + raisedPetRequest.RaisedPetData.IsSelected = false; // The api returns false, not sure why + raisedPetRequest.RaisedPetData.CreateDate = new DateTime(DateTime.Now.Ticks); + raisedPetRequest.RaisedPetData.UpdateDate = new DateTime(DateTime.Now.Ticks); + + // Save the dragon in the db + Dragon dragon = new Dragon { + EntityId = Guid.NewGuid().ToString(), + Viking = viking, + RaisedPetData = XmlUtil.SerializeXml(raisedPetRequest.RaisedPetData), + }; + ctx.Dragons.Add(dragon); + ctx.SaveChanges(); + + // Now update the RaisedPetData with the dragon id + raisedPetRequest.RaisedPetData.RaisedPetID = dragon.Id; + dragon.RaisedPetData = XmlUtil.SerializeXml(raisedPetRequest.RaisedPetData); + ctx.Dragons.Update(dragon); + ctx.SaveChanges(); + + return Ok(new CreatePetResponse { + RaisedPetData = raisedPetRequest.RaisedPetData + }); + } + + [HttpPost] + [Produces("application/xml")] + [Route("v3/ContentWebService.asmx/SetRaisedPet")] + public IActionResult SetRaisedPet([FromForm] string apiToken, [FromForm] string request) { + Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; + if (viking is null) { + // TODO: result for invalid session + return Ok(); + } + + RaisedPetRequest raisedPetRequest = XmlUtil.DeserializeXml(request); + + // Find the dragon + Dragon? dragon = viking.Dragons.FirstOrDefault(e => e.Id == raisedPetRequest.RaisedPetData.RaisedPetID); + if (dragon is null) { + return Ok(new SetRaisedPetResponse { + RaisedPetSetResult = RaisedPetSetResult.Invalid + }); + } + + dragon.RaisedPetData = XmlUtil.SerializeXml(raisedPetRequest.RaisedPetData); + ctx.SaveChanges(); + + return Ok(new SetRaisedPetResponse { + RaisedPetSetResult = RaisedPetSetResult.Success + }); + } + + [HttpPost] + [Produces("application/xml")] + [Route("ContentWebService.asmx/SetSelectedPet")] + public IActionResult SetSelectedPet([FromForm] string apiToken, [FromForm] int raisedPetID) { + Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; + if (viking is null) { + // TODO: result for invalid session + return Ok(); + } + + // Find the dragon + Dragon? dragon = viking.Dragons.FirstOrDefault(e => e.Id == raisedPetID); + if (dragon is null) { + return Ok(new SetRaisedPetResponse { + RaisedPetSetResult = RaisedPetSetResult.Invalid + }); + } + + // Set the dragon as selected + RaisedPetData dragonData = XmlUtil.DeserializeXml(dragon.RaisedPetData); + dragonData.IsSelected = true; + dragon.RaisedPetData = XmlUtil.SerializeXml(dragonData); + ctx.SaveChanges(); + + // TODO: make all other dragons unselected + + return Ok(new SetRaisedPetResponse { + RaisedPetSetResult = RaisedPetSetResult.Success + }); + } + + [HttpPost] + [Produces("application/xml")] [Route("V2/ContentWebService.asmx/GetAllActivePetsByuserId")] - public IActionResult GetAllActivePetsByuserId() { - // TODO, this is a placeholder - return Ok("\n"); + [Route("ContentWebService.asmx/GetSelectedRaisedPet")] + public RaisedPetData[]? GetAllActivePetsByuserId([FromForm] string apiToken, [FromForm] string userId, [FromForm] bool active, [FromForm] bool isActive) { + Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; + if (viking is null) { + return null; + } + + // GetAllActivePetsByuserId uses active, and GetSelectedRaisedPet uses active, so OR them together + bool isActiveSet = active || isActive; + + RaisedPetData[] dragons = viking.Dragons + .Where(d => d.RaisedPetData is not null) + .Select(d => XmlUtil.DeserializeXml(d.RaisedPetData)) + .ToArray(); + + if (dragons.Length == 0) { + return null; + } + return dragons; + } + + [HttpPost] + [Produces("application/xml")] + [Route("ContentWebService.asmx/SetImage")] + public bool SetImage([FromForm] string apiToken, [FromForm] string ImageType, [FromForm] int ImageSlot, [FromForm] string contentXML, [FromForm] string imageFile) { + Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; + if (viking is null || viking.Dragons is null) { + return false; + } + + // TODO: the other properties of contentXML + ImageData data = XmlUtil.DeserializeXml(contentXML); + + bool newImage = false; + Image? image = viking.Images.FirstOrDefault(e => e.ImageType == ImageType && e.ImageSlot == ImageSlot); + if (image is null) { + image = new Image { + ImageType = ImageType, + ImageSlot = ImageSlot, + Viking = viking, + }; + } + + // Save the image in the db + image.ImageData = imageFile; + image.TemplateName = data.TemplateName; + + if (newImage) { + ctx.Images.Add(image); + } else { + ctx.Images.Update(image); + } + ctx.SaveChanges(); + + return true; + } + + [HttpPost] + [Produces("application/xml")] + [Route("ContentWebService.asmx/GetImage")] + public ImageData? GetImage([FromForm] string apiToken, [FromForm] string ImageType, [FromForm] int ImageSlot) { + Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; + if (viking is null || viking.Images is null) { + return null; + } + + Image? image = viking.Images.FirstOrDefault(e => e.ImageType == ImageType && e.ImageSlot == ImageSlot); + if (image is null) { + return null; + } + + // TODO: test this + return new ImageData { + ImageURL = image.ImageData, + TemplateName = image.TemplateName, + }; } [HttpPost] diff --git a/src/Model/DBContext.cs b/src/Model/DBContext.cs index 8b0698f..a0cd29d 100644 --- a/src/Model/DBContext.cs +++ b/src/Model/DBContext.cs @@ -4,6 +4,8 @@ namespace sodoff.Model; public class DBContext : DbContext { public DbSet Users { get; set; } = null!; public DbSet Vikings { get; set; } = null!; + public DbSet Dragons { get; set; } = null!; + public DbSet Images { get; set; } = null!; public DbSet Sessions { get; set; } = null!; public DbSet Pairs { get; set; } = null!; public DbSet PairData { get; set; } = null!; @@ -39,6 +41,20 @@ public class DBContext : DbContext { builder.Entity().HasMany(u => u.Vikings) .WithOne(e => e.User); + builder.Entity().HasOne(s => s.Viking) + .WithMany(e => e.Dragons) + .HasForeignKey(e => e.VikingId); + + builder.Entity().HasMany(u => u.Dragons) + .WithOne(e => e.Viking); + + builder.Entity().HasOne(s => s.Viking) + .WithMany(e => e.Images) + .HasForeignKey(e => e.VikingId); + + builder.Entity().HasMany(u => u.Images) + .WithOne(e => e.Viking); + builder.Entity() .HasKey(e => e.Id); diff --git a/src/Model/Dragon.cs b/src/Model/Dragon.cs new file mode 100644 index 0000000..890ded5 --- /dev/null +++ b/src/Model/Dragon.cs @@ -0,0 +1,20 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace sodoff.Model; + +public class Dragon { + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; set; } + + [Required] + public string EntityId { get; set; } = null!; + + [Required] + public string VikingId { get; set; } = null!; + + public string? RaisedPetData { get; set; } + + public virtual Viking Viking { get; set; } = null!; +} diff --git a/src/Model/Image.cs b/src/Model/Image.cs new file mode 100644 index 0000000..df06a29 --- /dev/null +++ b/src/Model/Image.cs @@ -0,0 +1,22 @@ +using System.ComponentModel.DataAnnotations; +using Microsoft.EntityFrameworkCore; + +namespace sodoff.Model; + +[PrimaryKey(nameof(ImageType), nameof(ImageSlot), nameof(VikingId))] +public class Image { + [Required] + public string ImageType { get; set; } = null!; + + [Required] + public int ImageSlot { get; set; } + + [Required] + public string VikingId { get; set; } = null!; + + public string? ImageData { get; set; } + + public string? TemplateName { get; set; } + + public virtual Viking Viking { get; set; } = null!; +} diff --git a/src/Model/Viking.cs b/src/Model/Viking.cs index bcdff21..4e43b61 100644 --- a/src/Model/Viking.cs +++ b/src/Model/Viking.cs @@ -14,6 +14,7 @@ public class Viking { public string? AvatarSerialized { get; set; } public virtual ICollection Sessions { get; set; } = null!; - public virtual User User { get; set; } = null!; + public virtual ICollection Dragons { get; set; } = null!; + public virtual ICollection Images { get; set; } = null!; } diff --git a/src/Schema/CommonInventoryRequest.cs b/src/Schema/CommonInventoryRequest.cs new file mode 100644 index 0000000..e8e5d9b --- /dev/null +++ b/src/Schema/CommonInventoryRequest.cs @@ -0,0 +1,29 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema; + +[XmlRoot(ElementName = "CIRT", Namespace = "")] +[Serializable] +public class CommonInventoryRequest +{ + [XmlElement(ElementName = "uipid")] + public int? UserItemPositionID { get; set; } + + [XmlElement(ElementName = "u")] + public int? Uses { get; set; } + + [XmlElement(ElementName = "uia", IsNullable = true)] + public PairData UserItemAttributes { get; set; } + + [XmlElement(ElementName = "im", IsNullable = true)] + public int? InventoryMax { get; set; } + + [XmlElement(ElementName = "iid")] + public int? ItemID; + + [XmlElement(ElementName = "cid")] + public int? CommonInventoryID; + + [XmlElement(ElementName = "q")] + public int Quantity; +} diff --git a/src/Schema/CommonInventoryResponse.cs b/src/Schema/CommonInventoryResponse.cs new file mode 100644 index 0000000..08d8906 --- /dev/null +++ b/src/Schema/CommonInventoryResponse.cs @@ -0,0 +1,20 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema; + +[XmlRoot(ElementName = "CIRS", Namespace = "")] +[Serializable] +public class CommonInventoryResponse +{ + [XmlElement(ElementName = "pir", IsNullable = true)] + public List PrizeItems { get; set; } + + [XmlElement(ElementName = "s")] + public bool Success; + + [XmlElement(ElementName = "cids")] + public CommonInventoryResponseItem[] CommonInventoryIDs; + + [XmlElement(ElementName = "ugc", IsNullable = true)] + public UserGameCurrency UserGameCurrency; +} diff --git a/src/Schema/CommonInventoryResponseItem.cs b/src/Schema/CommonInventoryResponseItem.cs new file mode 100644 index 0000000..d2f558c --- /dev/null +++ b/src/Schema/CommonInventoryResponseItem.cs @@ -0,0 +1,17 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema; + +[XmlRoot(ElementName = "CIRI", Namespace = "")] +[Serializable] +public class CommonInventoryResponseItem +{ + [XmlElement(ElementName = "iid")] + public int ItemID; + + [XmlElement(ElementName = "cid")] + public int CommonInventoryID; + + [XmlElement(ElementName = "qty")] + public int Quantity; +} diff --git a/src/Schema/CreatePetResponse.cs b/src/Schema/CreatePetResponse.cs new file mode 100644 index 0000000..373427f --- /dev/null +++ b/src/Schema/CreatePetResponse.cs @@ -0,0 +1,14 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema; + +[XmlRoot(ElementName = "CPR", Namespace = "")] +[Serializable] +public class CreatePetResponse +{ + [XmlElement(ElementName = "rpd")] + public RaisedPetData RaisedPetData { get; set; } + + [XmlElement(ElementName = "cir")] + public CommonInventoryResponse UserCommonInventoryResponse { get; set; } +} diff --git a/src/Schema/DataType.cs b/src/Schema/DataType.cs new file mode 100644 index 0000000..ec555fd --- /dev/null +++ b/src/Schema/DataType.cs @@ -0,0 +1,36 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema; + +[Flags] +public enum DataType +{ + [XmlEnum("1")] + BOOL = 1, + [XmlEnum("2")] + BYTE = 2, + [XmlEnum("3")] + CHAR = 3, + [XmlEnum("4")] + DECIMAL = 4, + [XmlEnum("5")] + DOUBLE = 5, + [XmlEnum("6")] + FLOAT = 6, + [XmlEnum("7")] + INT = 7, + [XmlEnum("8")] + LONG = 8, + [XmlEnum("9")] + SBYTE = 9, + [XmlEnum("10")] + SHORT = 10, + [XmlEnum("11")] + STRING = 11, + [XmlEnum("12")] + UINT = 12, + [XmlEnum("13")] + ULONG = 13, + [XmlEnum("14")] + USHORT = 14 +} diff --git a/src/Schema/ImageData.cs b/src/Schema/ImageData.cs new file mode 100644 index 0000000..c6cb642 --- /dev/null +++ b/src/Schema/ImageData.cs @@ -0,0 +1,29 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema; + +[XmlRoot(ElementName = "ImageData", Namespace = "", IsNullable = true)] +[Serializable] +public class ImageData { + + [XmlElement(ElementName = "ImageURL")] + public string ImageURL; + + [XmlElement(ElementName = "TemplateName")] + public string TemplateName; + + [XmlElement(ElementName = "SubType", IsNullable = true)] + public string SubType; + + [XmlElement(ElementName = "PhotoFrame", IsNullable = true)] + public string PhotoFrame; + + [XmlElement(ElementName = "PhotoFrameMask", IsNullable = true)] + public string PhotoFrameMask; + + [XmlElement(ElementName = "Border", IsNullable = true)] + public string Border; + + [XmlElement(ElementName = "Decal")] + public ImageDataDecal[] Decal; +} diff --git a/src/Schema/ImageDataDecal.cs b/src/Schema/ImageDataDecal.cs new file mode 100644 index 0000000..01e203d --- /dev/null +++ b/src/Schema/ImageDataDecal.cs @@ -0,0 +1,20 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema; + +[XmlRoot(ElementName = "ImageDataDecal", Namespace = "")] +[Serializable] +public class ImageDataDecal +{ + [XmlElement(ElementName = "Name")] + public string Name; + + [XmlElement(ElementName = "Position")] + public ImageDataDecalPosition Position; + + [XmlElement(ElementName = "Width")] + public int Width; + + [XmlElement(ElementName = "Height")] + public int Height; +} diff --git a/src/Schema/ImageDataDecalPosition.cs b/src/Schema/ImageDataDecalPosition.cs new file mode 100644 index 0000000..1442f6a --- /dev/null +++ b/src/Schema/ImageDataDecalPosition.cs @@ -0,0 +1,14 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema; + +[XmlRoot(ElementName = "ImageDataDecalPosition", Namespace = "")] +[Serializable] +public class ImageDataDecalPosition +{ + [XmlElement(ElementName = "X")] + public int X; + + [XmlElement(ElementName = "Y")] + public int Y; +} diff --git a/src/Schema/PrizeItemResponse.cs b/src/Schema/PrizeItemResponse.cs new file mode 100644 index 0000000..16a5f27 --- /dev/null +++ b/src/Schema/PrizeItemResponse.cs @@ -0,0 +1,17 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema; + +[XmlRoot(ElementName = "pir", Namespace = "")] +[Serializable] +public class PrizeItemResponse +{ + [XmlElement(ElementName = "i")] + public int ItemID { get; set; } + + [XmlElement(ElementName = "pi")] + public int PrizeItemID { get; set; } + + [XmlElement(ElementName = "pis", IsNullable = true)] + public List MysteryPrizeItems { get; set; } +} diff --git a/src/Schema/RaisedPetAccessory.cs b/src/Schema/RaisedPetAccessory.cs new file mode 100644 index 0000000..d8ea783 --- /dev/null +++ b/src/Schema/RaisedPetAccessory.cs @@ -0,0 +1,23 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema; + +[XmlRoot(ElementName = "RPAC", Namespace = "")] +[Serializable] +public class RaisedPetAccessory +{ + [XmlElement(ElementName = "tp")] + public string Type; + + [XmlElement(ElementName = "g")] + public string Geometry; + + [XmlElement(ElementName = "t")] + public string Texture; + + [XmlElement(ElementName = "uiid", IsNullable = true)] + public int? UserInventoryCommonID; + + [XmlElement(ElementName = "uid", IsNullable = true)] + public UserItemData UserItemData; +} diff --git a/src/Schema/RaisedPetAttribute.cs b/src/Schema/RaisedPetAttribute.cs new file mode 100644 index 0000000..a11f226 --- /dev/null +++ b/src/Schema/RaisedPetAttribute.cs @@ -0,0 +1,17 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema; + +[XmlRoot(ElementName = "RPAT", Namespace = "")] +[Serializable] +public class RaisedPetAttribute +{ + [XmlElement(ElementName = "k")] + public string Key; + + [XmlElement(ElementName = "v")] + public string Value; + + [XmlElement(ElementName = "dt")] + public DataType Type; +} diff --git a/src/Schema/RaisedPetColor.cs b/src/Schema/RaisedPetColor.cs new file mode 100644 index 0000000..dbe0a1f --- /dev/null +++ b/src/Schema/RaisedPetColor.cs @@ -0,0 +1,20 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema; + +[XmlRoot(ElementName = "RPC", Namespace = "")] +[Serializable] +public class RaisedPetColor +{ + [XmlElement(ElementName = "o")] + public int Order; + + [XmlElement(ElementName = "r")] + public float Red; + + [XmlElement(ElementName = "g")] + public float Green; + + [XmlElement(ElementName = "b")] + public float Blue; +} diff --git a/src/Schema/RaisedPetData.cs b/src/Schema/RaisedPetData.cs new file mode 100644 index 0000000..2f1a2c7 --- /dev/null +++ b/src/Schema/RaisedPetData.cs @@ -0,0 +1,71 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema; + +[XmlRoot(ElementName = "RPD", Namespace = "")] +[Serializable] +public class RaisedPetData +{ + [XmlElement(ElementName = "ispetcreated")] + public bool IsPetCreated { get; set; } + + [XmlElement(ElementName = "validationmessage")] + public string ValidationMessage { get; set; } + + [XmlElement(ElementName = "id")] + public int RaisedPetID; + + [XmlElement(ElementName = "eid", IsNullable = true)] + public Guid? EntityID; + + [XmlElement(ElementName = "uid")] + public Guid UserID; + + [XmlElement(ElementName = "n")] + public string Name; + + [XmlElement(ElementName = "ptid")] + public int PetTypeID; + + [XmlElement(ElementName = "gs")] + public RaisedPetGrowthState GrowthState; + + [XmlElement(ElementName = "ip", IsNullable = true)] + public int? ImagePosition; + + [XmlElement(ElementName = "g")] + public string Geometry; + + [XmlElement(ElementName = "t")] + public string Texture; + + [XmlElement(ElementName = "gd")] + public Gender Gender; + + [XmlElement(ElementName = "ac")] + public RaisedPetAccessory[] Accessories; + + [XmlElement(ElementName = "at")] + public RaisedPetAttribute[] Attributes; + + [XmlElement(ElementName = "c")] + public RaisedPetColor[] Colors; + + [XmlElement(ElementName = "sk")] + public RaisedPetSkill[] Skills; + + [XmlElement(ElementName = "st")] + public RaisedPetState[] States; + + [XmlElement(ElementName = "is")] + public bool IsSelected; + + [XmlElement(ElementName = "ir")] + public bool IsReleased; + + [XmlElement(ElementName = "cdt")] + public DateTime CreateDate; + + [XmlElement(ElementName = "updt")] + public DateTime UpdateDate; +} diff --git a/src/Schema/RaisedPetGrowthState.cs b/src/Schema/RaisedPetGrowthState.cs new file mode 100644 index 0000000..6ef1870 --- /dev/null +++ b/src/Schema/RaisedPetGrowthState.cs @@ -0,0 +1,20 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema; + +[XmlRoot(ElementName = "RPGS", Namespace = "")] +[Serializable] +public class RaisedPetGrowthState +{ + [XmlElement(ElementName = "id")] + public int GrowthStateID; + + [XmlElement(ElementName = "n")] + public string Name; + + [XmlElement(ElementName = "ptid")] + public int PetTypeID; + + [XmlElement(ElementName = "o")] + public int Order; +} diff --git a/src/Schema/RaisedPetRequest.cs b/src/Schema/RaisedPetRequest.cs new file mode 100644 index 0000000..942d857 --- /dev/null +++ b/src/Schema/RaisedPetRequest.cs @@ -0,0 +1,32 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema; + +[XmlRoot(ElementName = "RPR", Namespace = "")] +[Serializable] +public class RaisedPetRequest +{ + [XmlElement(ElementName = "ptid")] + public int PetTypeID { get; set; } + + [XmlElement(ElementName = "uid")] + public Guid? UserID { get; set; } + + [XmlElement(ElementName = "SASP")] + public bool? SetAsSelectedPet { get; set; } + + [XmlElement(ElementName = "USOP")] + public bool? UnSelectOtherPets { get; set; } + + [XmlElement(ElementName = "pgid")] + public int? ProductGroupID { get; set; } + + [XmlElement(ElementName = "cid")] + public int? ContainerId { get; set; } + + [XmlElement(ElementName = "cir")] + public CommonInventoryRequest[] CommonInventoryRequests { get; set; } + + [XmlElement(ElementName = "rpd")] + public RaisedPetData RaisedPetData { get; set; } +} diff --git a/src/Schema/RaisedPetSetResult.cs b/src/Schema/RaisedPetSetResult.cs new file mode 100644 index 0000000..021dd9a --- /dev/null +++ b/src/Schema/RaisedPetSetResult.cs @@ -0,0 +1,18 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema; + +public enum RaisedPetSetResult +{ + [XmlEnum("1")] + Success = 1, + + [XmlEnum("2")] + Failure, + + [XmlEnum("3")] + Invalid, + + [XmlEnum("4")] + InvalidPetName +} diff --git a/src/Schema/RaisedPetSkill.cs b/src/Schema/RaisedPetSkill.cs new file mode 100644 index 0000000..b176ae8 --- /dev/null +++ b/src/Schema/RaisedPetSkill.cs @@ -0,0 +1,17 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema; + +[XmlRoot(ElementName = "RPSK", Namespace = "")] +[Serializable] +public class RaisedPetSkill +{ + [XmlElement(ElementName = "k")] + public string Key; + + [XmlElement(ElementName = "v")] + public float Value; + + [XmlElement(ElementName = "ud")] + public DateTime UpdateDate; +} diff --git a/src/Schema/RaisedPetState.cs b/src/Schema/RaisedPetState.cs new file mode 100644 index 0000000..cf5bd1b --- /dev/null +++ b/src/Schema/RaisedPetState.cs @@ -0,0 +1,14 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema; + +[XmlRoot(ElementName = "RPST", Namespace = "")] +[Serializable] +public class RaisedPetState +{ + [XmlElement(ElementName = "k")] + public string Key; + + [XmlElement(ElementName = "v")] + public float Value; +} diff --git a/src/Schema/SetRaisedPetResponse.cs b/src/Schema/SetRaisedPetResponse.cs new file mode 100644 index 0000000..9a69c08 --- /dev/null +++ b/src/Schema/SetRaisedPetResponse.cs @@ -0,0 +1,17 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema; + +[XmlRoot(ElementName = "SetRaisedPetResponse", Namespace = "")] +[Serializable] +public class SetRaisedPetResponse +{ + [XmlElement(ElementName = "ErrorMessage")] + public string ErrorMessage { get; set; } + + [XmlElement(ElementName = "RaisedPetSetResult")] + public RaisedPetSetResult RaisedPetSetResult { get; set; } + + [XmlElement(ElementName = "cir")] + public CommonInventoryResponse UserCommonInventoryResponse { get; set; } +} diff --git a/src/Schema/UserGameCurrency.cs b/src/Schema/UserGameCurrency.cs new file mode 100644 index 0000000..6fea247 --- /dev/null +++ b/src/Schema/UserGameCurrency.cs @@ -0,0 +1,20 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema; + +[XmlRoot(ElementName = "UserGameCurrency", Namespace = "")] +[Serializable] +public class UserGameCurrency +{ + [XmlElement(ElementName = "id")] + public int? UserGameCurrencyID; + + [XmlElement(ElementName = "uid")] + public Guid? UserID; + + [XmlElement(ElementName = "gc")] + public int? GameCurrency; + + [XmlElement(ElementName = "cc")] + public int? CashCurrency; +} From 1fdff9d27be9b2d4d45d4a882728ee4550cb581c Mon Sep 17 00:00:00 2001 From: hictooth Date: Thu, 22 Jun 2023 10:39:06 +0100 Subject: [PATCH 2/4] fix dragons and images --- mitm-redirect.py | 5 +- src/Controllers/Common/ContentController.cs | 95 +++++++++++++++------ src/Controllers/Common/ImageController.cs | 34 ++++++++ src/Model/DBContext.cs | 8 ++ src/Model/Dragon.cs | 3 + src/Model/Viking.cs | 3 + 6 files changed, 122 insertions(+), 26 deletions(-) create mode 100644 src/Controllers/Common/ImageController.cs diff --git a/mitm-redirect.py b/mitm-redirect.py index ee0a843..9bd6c87 100644 --- a/mitm-redirect.py +++ b/mitm-redirect.py @@ -34,8 +34,11 @@ methods = [ 'SetTaskState', 'CreatePet', 'SetRaisedPet', + 'SetSelectedPet', + 'GetSelectedRaisedPet', 'SetImage', - 'GetImage' + 'GetImage', + 'GetImageByUserId' ] def routable(path): diff --git a/src/Controllers/Common/ContentController.cs b/src/Controllers/Common/ContentController.cs index 730909b..389984d 100644 --- a/src/Controllers/Common/ContentController.cs +++ b/src/Controllers/Common/ContentController.cs @@ -199,6 +199,7 @@ public class ContentController : Controller { [HttpPost] [Produces("application/xml")] [Route("V2/ContentWebService.asmx/CreatePet")] + [SignResponse] public IActionResult CreatePet([FromForm] string apiToken, [FromForm] string request) { Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; if (viking is null) { @@ -225,23 +226,23 @@ public class ContentController : Controller { Viking = viking, RaisedPetData = XmlUtil.SerializeXml(raisedPetRequest.RaisedPetData), }; + + if (raisedPetRequest.SetAsSelectedPet == true) { + viking.SelectedDragon = dragon; + ctx.Update(viking); + } ctx.Dragons.Add(dragon); ctx.SaveChanges(); - // Now update the RaisedPetData with the dragon id - raisedPetRequest.RaisedPetData.RaisedPetID = dragon.Id; - dragon.RaisedPetData = XmlUtil.SerializeXml(raisedPetRequest.RaisedPetData); - ctx.Dragons.Update(dragon); - ctx.SaveChanges(); - return Ok(new CreatePetResponse { - RaisedPetData = raisedPetRequest.RaisedPetData + RaisedPetData = GetRaisedPetDataFromDragon(dragon) }); } [HttpPost] [Produces("application/xml")] [Route("v3/ContentWebService.asmx/SetRaisedPet")] + [SignResponse] public IActionResult SetRaisedPet([FromForm] string apiToken, [FromForm] string request) { Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; if (viking is null) { @@ -260,6 +261,7 @@ public class ContentController : Controller { } dragon.RaisedPetData = XmlUtil.SerializeXml(raisedPetRequest.RaisedPetData); + ctx.Update(dragon); ctx.SaveChanges(); return Ok(new SetRaisedPetResponse { @@ -270,6 +272,7 @@ public class ContentController : Controller { [HttpPost] [Produces("application/xml")] [Route("ContentWebService.asmx/SetSelectedPet")] + [SignResponse] public IActionResult SetSelectedPet([FromForm] string apiToken, [FromForm] int raisedPetID) { Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; if (viking is null) { @@ -286,13 +289,10 @@ public class ContentController : Controller { } // Set the dragon as selected - RaisedPetData dragonData = XmlUtil.DeserializeXml(dragon.RaisedPetData); - dragonData.IsSelected = true; - dragon.RaisedPetData = XmlUtil.SerializeXml(dragonData); + viking.SelectedDragon = dragon; + ctx.Update(viking); ctx.SaveChanges(); - // TODO: make all other dragons unselected - return Ok(new SetRaisedPetResponse { RaisedPetSetResult = RaisedPetSetResult.Success }); @@ -301,19 +301,16 @@ public class ContentController : Controller { [HttpPost] [Produces("application/xml")] [Route("V2/ContentWebService.asmx/GetAllActivePetsByuserId")] - [Route("ContentWebService.asmx/GetSelectedRaisedPet")] - public RaisedPetData[]? GetAllActivePetsByuserId([FromForm] string apiToken, [FromForm] string userId, [FromForm] bool active, [FromForm] bool isActive) { + [SignResponse] + public RaisedPetData[]? GetAllActivePetsByuserId([FromForm] string apiToken, [FromForm] string userId, [FromForm] bool active) { Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; if (viking is null) { return null; } - // GetAllActivePetsByuserId uses active, and GetSelectedRaisedPet uses active, so OR them together - bool isActiveSet = active || isActive; - RaisedPetData[] dragons = viking.Dragons .Where(d => d.RaisedPetData is not null) - .Select(d => XmlUtil.DeserializeXml(d.RaisedPetData)) + .Select(GetRaisedPetDataFromDragon) .ToArray(); if (dragons.Length == 0) { @@ -322,6 +319,26 @@ public class ContentController : Controller { return dragons; } + [HttpPost] + [Produces("application/xml")] + [Route("ContentWebService.asmx/GetSelectedRaisedPet")] + [SignResponse] + public RaisedPetData[]? GetSelectedRaisedPet([FromForm] string apiToken, [FromForm] string userId, [FromForm] bool isActive) { + Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; + if (viking is null) { + return null; + } + + Dragon? dragon = viking.SelectedDragon; + if (dragon is null) { + return null; + } + + return new RaisedPetData[] { + GetRaisedPetDataFromDragon(dragon) + }; + } + [HttpPost] [Produces("application/xml")] [Route("ContentWebService.asmx/SetImage")] @@ -342,6 +359,7 @@ public class ContentController : Controller { ImageSlot = ImageSlot, Viking = viking, }; + newImage = true; } // Save the image in the db @@ -367,16 +385,21 @@ public class ContentController : Controller { return null; } - Image? image = viking.Images.FirstOrDefault(e => e.ImageType == ImageType && e.ImageSlot == ImageSlot); - if (image is null) { + return GetImageData(viking, ImageType, ImageSlot); + } + + [HttpPost] + [Produces("application/xml")] + [Route("ContentWebService.asmx/GetImageByUserId")] + public ImageData? GetImageByUserId([FromForm] string userId, [FromForm] string ImageType, [FromForm] int ImageSlot) { + Viking? viking = ctx.Vikings.FirstOrDefault(e => e.Id == userId); + if (viking is null || viking.Images is null) { return null; } - // TODO: test this - return new ImageData { - ImageURL = image.ImageData, - TemplateName = image.TemplateName, - }; + // TODO: should we restrict images to only those the caller owns? + + return GetImageData(viking, ImageType, ImageSlot); } [HttpPost] @@ -464,4 +487,26 @@ public class ContentController : Controller { return Ok(new SetTaskStateResult { Success = true, Status = SetTaskStateStatus.TaskCanBeDone }); } + + private RaisedPetData GetRaisedPetDataFromDragon (Dragon dragon) { + RaisedPetData data = XmlUtil.DeserializeXml(dragon.RaisedPetData); + data.RaisedPetID = dragon.Id; + data.EntityID = Guid.Parse(dragon.EntityId); + data.IsSelected = dragon.SelectedViking is not null; + return data; + } + + private ImageData? GetImageData (Viking viking, String ImageType, int ImageSlot) { + Image? image = viking.Images.FirstOrDefault(e => e.ImageType == ImageType && e.ImageSlot == ImageSlot); + if (image is null) { + return null; + } + + string imageUrl = string.Format("{0}://{1}/RawImage/{2}/{3}/{4}", HttpContext.Request.Scheme, HttpContext.Request.Host, viking.Id, ImageType, ImageSlot); + + return new ImageData { + ImageURL = imageUrl, + TemplateName = image.TemplateName, + }; + } } diff --git a/src/Controllers/Common/ImageController.cs b/src/Controllers/Common/ImageController.cs new file mode 100644 index 0000000..bdfc0d8 --- /dev/null +++ b/src/Controllers/Common/ImageController.cs @@ -0,0 +1,34 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using sodoff.Attributes; +using sodoff.Model; +using sodoff.Schema; +using sodoff.Services; +using sodoff.Util; +using System; + +namespace sodoff.Controllers.Common; +public class ImageController : Controller { + + private readonly DBContext ctx; + private KeyValueService keyValueService; + public ImageController(DBContext ctx, KeyValueService keyValueService) { + this.ctx = ctx; + this.keyValueService = keyValueService; + } + + // SetImage and GetImage are defined in ContentController + + [HttpGet] + [Route("RawImage/{VikingId}/{ImageType}/{ImageSlot}")] + public IActionResult RawImage(String VikingId, String ImageType, int ImageSlot) { + Image? image = ctx.Images.FirstOrDefault(e => e.VikingId == VikingId && e.ImageType == ImageType && e.ImageSlot == ImageSlot); + if (image is null) { + return null; + } + + byte[] imageBytes = Convert.FromBase64String(image.ImageData); + var imageStream = new MemoryStream(imageBytes, 0, imageBytes.Length); + return File(imageStream, "image/jpeg"); + } +} diff --git a/src/Model/DBContext.cs b/src/Model/DBContext.cs index a0cd29d..75f713e 100644 --- a/src/Model/DBContext.cs +++ b/src/Model/DBContext.cs @@ -48,6 +48,14 @@ public class DBContext : DbContext { builder.Entity().HasMany(u => u.Dragons) .WithOne(e => e.Viking); + builder.Entity().HasOne(s => s.SelectedDragon) + .WithOne(e => e.SelectedViking) + .HasForeignKey(e => e.SelectedVikingId); + + builder.Entity().HasOne(s => s.SelectedViking) + .WithOne(e => e.SelectedDragon) + .HasForeignKey(e => e.SelectedDragonId); + builder.Entity().HasOne(s => s.Viking) .WithMany(e => e.Images) .HasForeignKey(e => e.VikingId); diff --git a/src/Model/Dragon.cs b/src/Model/Dragon.cs index 890ded5..1d80e8b 100644 --- a/src/Model/Dragon.cs +++ b/src/Model/Dragon.cs @@ -14,7 +14,10 @@ public class Dragon { [Required] public string VikingId { get; set; } = null!; + public string? SelectedVikingId { get; set; } + public string? RaisedPetData { get; set; } public virtual Viking Viking { get; set; } = null!; + public virtual Viking SelectedViking { get; set; } = null!; } diff --git a/src/Model/Viking.cs b/src/Model/Viking.cs index 4e43b61..8a40863 100644 --- a/src/Model/Viking.cs +++ b/src/Model/Viking.cs @@ -13,8 +13,11 @@ public class Viking { public string? AvatarSerialized { get; set; } + public int? SelectedDragonId { get; set; } + public virtual ICollection Sessions { get; set; } = null!; public virtual User User { get; set; } = null!; public virtual ICollection Dragons { get; set; } = null!; public virtual ICollection Images { get; set; } = null!; + public virtual Dragon? SelectedDragon { get; set; } } From 4a2641916024fb492839cf2c174290b124c653bb Mon Sep 17 00:00:00 2001 From: hictooth Date: Thu, 22 Jun 2023 10:39:49 +0100 Subject: [PATCH 3/4] update readme --- README.md | 5 ++++- mitm-redirect.py | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4c91cb6..fe45c11 100644 --- a/README.md +++ b/README.md @@ -45,17 +45,20 @@ Then run School of Dragons. - SetAvatar - RegisterParent - RegisterChild +- CreatePet - SetRaisedPet +- SetSelectedPet - GetAllActivePetsByuserId +- GetSelectedRaisedPet - SetImage - GetImage +- GetImageByUserId #### Implemented enough (probably) - GetRules (doesn't return any rules, probably doesn't need to) - GetQuestions (doesn't return all questions, probably doesn't need to) - GetSubscriptionInfo (always returns member, with end date 10 years from now) - SetTaskState (only the TaskCanBeDone status is supported) -- CreatePet (doesn't handle SetAsSelectedPet/UnSelectOtherPets) #### Partially implemented - GetUserProfileByUserID (a lot is still placeholder) diff --git a/mitm-redirect.py b/mitm-redirect.py index 9bd6c87..564e777 100644 --- a/mitm-redirect.py +++ b/mitm-redirect.py @@ -23,7 +23,6 @@ methods = [ 'GetCommonInventory', 'GetAuthoritativeTime', 'SetAvatar', - 'GetAllActivePetsByuserId', 'GetPetAchievementsByUserID', 'GetDetailedChildList', 'GetStore', @@ -35,6 +34,7 @@ methods = [ 'CreatePet', 'SetRaisedPet', 'SetSelectedPet', + 'GetAllActivePetsByuserId', 'GetSelectedRaisedPet', 'SetImage', 'GetImage', From d71bf05fb204327050f65f9a17e29964de9b62ba Mon Sep 17 00:00:00 2001 From: hictooth Date: Thu, 22 Jun 2023 11:15:46 +0100 Subject: [PATCH 4/4] remove response signing --- src/Controllers/Common/ContentController.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Controllers/Common/ContentController.cs b/src/Controllers/Common/ContentController.cs index 389984d..6372e46 100644 --- a/src/Controllers/Common/ContentController.cs +++ b/src/Controllers/Common/ContentController.cs @@ -199,7 +199,6 @@ public class ContentController : Controller { [HttpPost] [Produces("application/xml")] [Route("V2/ContentWebService.asmx/CreatePet")] - [SignResponse] public IActionResult CreatePet([FromForm] string apiToken, [FromForm] string request) { Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; if (viking is null) { @@ -242,7 +241,6 @@ public class ContentController : Controller { [HttpPost] [Produces("application/xml")] [Route("v3/ContentWebService.asmx/SetRaisedPet")] - [SignResponse] public IActionResult SetRaisedPet([FromForm] string apiToken, [FromForm] string request) { Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; if (viking is null) { @@ -272,7 +270,6 @@ public class ContentController : Controller { [HttpPost] [Produces("application/xml")] [Route("ContentWebService.asmx/SetSelectedPet")] - [SignResponse] public IActionResult SetSelectedPet([FromForm] string apiToken, [FromForm] int raisedPetID) { Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; if (viking is null) { @@ -301,7 +298,6 @@ public class ContentController : Controller { [HttpPost] [Produces("application/xml")] [Route("V2/ContentWebService.asmx/GetAllActivePetsByuserId")] - [SignResponse] public RaisedPetData[]? GetAllActivePetsByuserId([FromForm] string apiToken, [FromForm] string userId, [FromForm] bool active) { Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; if (viking is null) { @@ -322,7 +318,6 @@ public class ContentController : Controller { [HttpPost] [Produces("application/xml")] [Route("ContentWebService.asmx/GetSelectedRaisedPet")] - [SignResponse] public RaisedPetData[]? GetSelectedRaisedPet([FromForm] string apiToken, [FromForm] string userId, [FromForm] bool isActive) { Viking? viking = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking; if (viking is null) {