diff --git a/gts/BoxUploadDecode.aspx b/gts/BoxUploadDecode.aspx new file mode 100644 index 00000000..9f6eeb8c --- /dev/null +++ b/gts/BoxUploadDecode.aspx @@ -0,0 +1,24 @@ +<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="BoxUploadDecode.aspx.cs" Inherits="PokeFoundations.GTS.BoxUploadDecode" %> + + + + + + + + +
+ +

Please upload your captured TCP request here:

+
+ + +
+
+ +
+ + +
+ + diff --git a/gts/BoxUploadDecode.aspx.cs b/gts/BoxUploadDecode.aspx.cs new file mode 100644 index 00000000..eec29f87 --- /dev/null +++ b/gts/BoxUploadDecode.aspx.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.UI; +using System.Web.UI.WebControls; +using System.Text; + +namespace PokeFoundations.GTS +{ + public partial class BoxUploadDecode : System.Web.UI.Page + { + protected void Page_Load(object sender, EventArgs e) + { + byte data = 0x00; + + StringBuilder builder = new StringBuilder(); + + for (int x = 0; x < 512; x++) + { + data = runRng(data); + builder.Append(data.ToString("x2")); + builder.Append(" "); + if (x % 16 == 15) builder.Append("
"); + } + + litDecrypted.Text = builder.ToString(); + } + + private byte runRng(byte data) + { + return (byte)((data + 0x4f) * 0x1c); + } + } +} \ No newline at end of file diff --git a/gts/BoxUploadDecode.aspx.designer.cs b/gts/BoxUploadDecode.aspx.designer.cs new file mode 100644 index 00000000..6618171f --- /dev/null +++ b/gts/BoxUploadDecode.aspx.designer.cs @@ -0,0 +1,51 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace PokeFoundations.GTS { + + + public partial class BoxUploadDecode { + + /// + /// form1 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.HtmlControls.HtmlForm form1; + + /// + /// fuRequest control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.FileUpload fuRequest; + + /// + /// btnUpload control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Button btnUpload; + + /// + /// litDecrypted control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Literal litDecrypted; + } +} diff --git a/gts/Default.aspx b/gts/Default.aspx index cf29973c..77cae1a8 100644 --- a/gts/Default.aspx +++ b/gts/Default.aspx @@ -4,6 +4,5 @@ -customGTS
diff --git a/gts/gts.csproj b/gts/gts.csproj index 4ae7fc55..e0064db0 100644 --- a/gts/gts.csproj +++ b/gts/gts.csproj @@ -34,6 +34,9 @@ + + ..\library\lib\mysql.data.dll + @@ -51,6 +54,7 @@ + @@ -62,6 +66,13 @@ + + BoxUploadDecode.aspx + ASPXCodeBehind + + + BoxUploadDecode.aspx + pokemondpds.ashx @@ -100,6 +111,12 @@ + + + {408EFC7E-C6B0-4160-8628-2679E34385CE} + Library + + diff --git a/gts/pokemondpds.ashx.cs b/gts/pokemondpds.ashx.cs index dcebc3de..09f14ae0 100644 --- a/gts/pokemondpds.ashx.cs +++ b/gts/pokemondpds.ashx.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.SessionState; +using PokeFoundations.Data; namespace PokeFoundations.GTS { @@ -41,8 +42,9 @@ namespace PokeFoundations.GTS context.Request.QueryString["data"].Length < 12) { // arguments missing, partial check for data length. - // (require data to hold at least 7 bytes. - // In reality, it must hold at least 8.) + // (Here, we require data to hold at least 7 bytes. + // In reality, it must hold at least 8, which is checked + // for below after decoding) Error400(context); return; } @@ -63,6 +65,8 @@ namespace PokeFoundations.GTS if (data.Length < 4) { // data too short to contain a pid + // We check for 4 bytes, not 8, since the decrypt seed + // isn't included in DecryptData's result. Error400(context); return; } @@ -87,13 +91,34 @@ namespace PokeFoundations.GTS { default: // unrecognized page url + // should be error 404 once we're done debugging context.Response.Write("Almost there. Your path is:\n"); context.Response.Write(session.URL); return; + + case "/worldexchange/info.asp": - context.Response.Write("It worked"); + context.Response.OutputStream.Write(new byte[] { 0x01, 0x00 }, 0, 2); break; + + case "/common/setProfile.asp": + // todo: Figure out what fun stuff is contained in this blob! + + context.Response.OutputStream.Write(new byte[] + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + 0, 8); + break; + + + case "/worldexchange/result.asp": + { + + + } + break; + + } } else diff --git a/gts/src/GtsContextExtender.cs b/gts/src/GtsContextExtender.cs index c5a9fe72..eedcebaf 100644 --- a/gts/src/GtsContextExtender.cs +++ b/gts/src/GtsContextExtender.cs @@ -30,10 +30,19 @@ namespace PokeFoundations.GTS Dictionary sessions = context.AllSessions4(); DateTime now = DateTime.UtcNow; - foreach (KeyValuePair session in sessions) + lock (sessions) { - if (session.Value.ExpiryDate < now) sessions.Remove(session.Key); + Queue toRemove = new Queue(); + foreach (KeyValuePair session in sessions) + { + if (session.Value.ExpiryDate < now) toRemove.Enqueue(session.Key); + } + while (toRemove.Count > 0) + { + sessions.Remove(toRemove.Dequeue()); + } } } + } } \ No newline at end of file diff --git a/gts/src/GtsSession4.cs b/gts/src/GtsSession4.cs index 9ee22278..f00642ea 100644 --- a/gts/src/GtsSession4.cs +++ b/gts/src/GtsSession4.cs @@ -30,7 +30,7 @@ namespace PokeFoundations.GTS byte[] data = new byte[longToken.Length]; MemoryStream stream = new MemoryStream(data); StreamWriter writer = new StreamWriter(stream); - writer.Write(longToken); + writer.Write(longToken); // fixme: this throws an OutOfBoundsException if the passed token contains non-ascii. writer.Flush(); return m_sha1.ComputeHash(data).ToHexStringLower(); diff --git a/gts/src/GtsSessionBase.cs b/gts/src/GtsSessionBase.cs index 87259eec..83d28f00 100644 --- a/gts/src/GtsSessionBase.cs +++ b/gts/src/GtsSessionBase.cs @@ -104,7 +104,7 @@ namespace PokeFoundations.GTS for (int x = 0; x < token.Length; x++) { - // tokens have 62 chars: 0-9, A-Z, and a-z + // tokens have 62 possible chars: 0-9, A-Z, and a-z m_rng.GetBytes(data); uint rand = BitConverter.ToUInt32(data, 0) % 62u; diff --git a/library/Data/DataAbstract.cs b/library/Data/DataAbstract.cs index e6fb9066..a37e34a4 100644 --- a/library/Data/DataAbstract.cs +++ b/library/Data/DataAbstract.cs @@ -3,22 +3,40 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Data; +using PokeFoundations.Structures; namespace PokeFoundations.Data { public abstract class DataAbstract { - public static String SqlSanitize(String s) - { - return SqlSanitize(s, ""); - } + #region Initialization + private static DataAbstract m_instance; - public static String SqlSanitize(String s, String newChar) + public static DataAbstract Instance { - String result = s.Replace("\'", newChar).Replace("[", newChar).Replace("]", newChar).Replace("`", newChar); - int x = result.IndexOf("--"); - if (x != -1) result = result.Substring(0, x); - return result; + get + { + if (m_instance == null) + { + m_instance = new DataMysql(); + } + return m_instance; + } } + #endregion + + #region Utility + #endregion + + #region GTS + public abstract GtsDatagram4 GtsDataForUser4(int pid); + + public abstract void GtsDepositPokemon4(GtsDatagram4 datagram); + + public abstract void GtsDeletePokemon4(int pid); + + public abstract void GtsTradePokemon4(int pidSrc, int pidDest); + + #endregion } } diff --git a/library/Data/DataMysql.cs b/library/Data/DataMysql.cs index 80ac6638..45743813 100644 --- a/library/Data/DataMysql.cs +++ b/library/Data/DataMysql.cs @@ -4,14 +4,173 @@ using System.Linq; using System.Text; using System.Data; using MySql.Data.MySqlClient; +using PokeFoundations.Structures; +using PokeFoundations.Support; namespace PokeFoundations.Data { public class DataMysql : DataAbstract { + #region Initialization private MySqlConnection CreateConnection() { - return new MySqlConnection("Server=localhost;Database=pfound;User ID=pfound;Password=goldeen need log;Pooling=true;"); + // hard-coded for now, will need to add configuration later + return new MySqlConnection("Server=10.211.55.2;Database=gts;User ID=gts;Password=gts;Pooling=true;"); } + #endregion + + #region Utility + public static String SqlSanitize(String s) + { + return SqlSanitize(s, ""); + } + + public static String SqlSanitize(String s, String newChar) + { + String result = s.Replace("\'", newChar).Replace("[", newChar).Replace("]", newChar).Replace("`", newChar); + int x = result.IndexOf("--"); + if (x != -1) result = result.Substring(0, x); + return result; + } + #endregion + + #region GTS + public override GtsDatagram4 GtsDataForUser4(int pid) + { + using (MySqlConnection db = CreateConnection()) + { + db.Open(); + MySqlDataReader reader = (MySqlDataReader)db.ExecuteReader("SELECT Data, Species, Gender, Level, " + + "RequestedSpecies, RequestedGender, RequestedMinLevel, RequestedMaxLevel, " + + "Unknown1, TrainerGender, Unknown2, TimeDeposited, TimeWithdrawn, pid, " + + "TrainerName, TrainerOT, TrainerCountry, TrainerRegion, TrainerClass, " + + "IsExchanged, TrainerVersion, TrainerLanguage FROM GtsPokemon4 WHERE pid = @pid", + new MySqlParameter("@pid", pid)); + + if (!reader.Read()) return null; + GtsDatagram4 result = new GtsDatagram4(); + + byte[] data = new byte[236]; + reader.GetBytes(0, 0, data, 0, 236); + result.Data = data; + data = null; + + result.Species = reader.GetUInt16(1); + result.Gender = (Genders)reader.GetByte(2); + result.Level = reader.GetByte(3); + result.RequestedSpecies = reader.GetUInt16(4); + result.RequestedGender = (Genders)reader.GetByte(5); + result.RequestedMinLevel = reader.GetByte(6); + result.RequestedMaxLevel = reader.GetByte(7); + result.Unknown1 = reader.GetByte(8); + result.TrainerGender = (GtsTrainerGenders)reader.GetByte(9); + result.Unknown2 = reader.GetByte(10); + result.TimeDeposited = reader.GetDateTime(11); + result.TimeWithdrawn = reader.GetDateTime(12); + result.PID = reader.GetInt32(13); + + data = new byte[16]; + reader.GetBytes(14, 0, data, 0, 16); + result.TrainerName = data; + data = null; + + result.TrainerOT = reader.GetUInt16(15); + result.TrainerCountry = reader.GetByte(16); + result.TrainerRegion = reader.GetByte(17); + result.TrainerClass = reader.GetByte(18); + result.IsExchanged = reader.GetByte(19); + result.TrainerVersion = reader.GetByte(20); + result.TrainerLanguage = reader.GetByte(21); +#if DEBUG + AssertHelper.Equals(result.PID, pid); +#endif + reader.Close(); + return result; + } + } + + public override bool GtsDepositPokemon4(GtsDatagram4 datagram) + { + if (datagram.Data.Length != 236) throw new FormatException("pkm data must be 236 bytes."); + if (datagram.TrainerName.Length != 16) throw new FormatException("Trainer name must be 16 bytes."); + // note that IsTraded being true in the datagram is not an error condition + // since it might have use later on. You should check for this in the upload handler. + + using (MySqlConnection db = CreateConnection()) + { + db.Open(); + + /* + MySqlDataReader reader = (MySqlDataReader)db.ExecuteReader("SELECT Data, Species, Gender, Level, " + + "RequestedSpecies, RequestedGender, RequestedMinLevel, RequestedMaxLevel, " + + "Unknown1, TrainerGender, Unknown2, TimeDeposited, TimeWithdrawn, pid, " + + "TrainerName, TrainerOT, TrainerCountry, TrainerRegion, TrainerClass, " + + "IsExchanged, TrainerVersion, TrainerLanguage FROM GtsPokemon4 WHERE pid = @pid", + new MySqlParameter("@pid", pid)); + * + * */ + + MySqlTransaction tran = db.BeginTransaction(); + + int count = (int)tran.ExecuteScalar("SELECT Count(*) FROM GtsPokemon4 WHERE pid = @pid", + new MySqlParameter("@pid", datagram.PID)); + + if (count > 0) + { + // This player already has a pokemon in the system. + // we can possibly allow multiples under some future conditions + tran.Rollback(); + return false; + } + + tran.ExecuteNonQuery("INSERT INTO GtsPokemon4 " + + "(Data, Species, Gender, Level, RequestedSpecies, RequestedGender, " + + "RequestedMinLevel, RequestedMaxLevel, Unknown1, TrainerGender, " + + "Unknown2, TimeDeposited, TimeWithdrawn, pid, TrainerName, TrainerOT, " + + "TrainerCountry, TrainerRegion, TrainerClass, IsExchanged, TrainerVersion, " + + "TrainerLanguage) " + + "VALUES (@Data, @Species, @Gender, @Level, @RequestedSpecies, " + + "@RequestedGender, @RequestedMinLevel, @RequestedMaxLevel, @Unknown1, " + + "@TrainerGender, @Unknown2, @TimeDeposited, @TimeWithdrawn, @pid, " + + "@TrainerName, @TrainerOT, @TrainerCountry, @TrainerRegion, @TrainerClass, " + + "@IsExchanged, @TrainerVersion, @TrainerLanguage)", + new MySqlParameter("@Data", datagram.Data), + new MySqlParameter("@Species", datagram.Species), + new MySqlParameter("@Gender", (byte)datagram.Gender), + new MySqlParameter("@Level", datagram.Level), + new MySqlParameter("@RequestedSpecies", datagram.RequestedSpecies), + new MySqlParameter("@RequestedGender", (byte)datagram.RequestedGender), + new MySqlParameter("@RequestedMinLevel", datagram.RequestedMinLevel), + new MySqlParameter("@RequestedMaxLevel", datagram.RequestedMaxLevel), + new MySqlParameter("@Unknown1", datagram.Unknown1), + new MySqlParameter("@TrainerGender", (byte)datagram.TrainerGender), + new MySqlParameter("@Unknown2", datagram.Unknown2), + new MySqlParameter("@TimeDeposited", datagram.TimeDeposited), + new MySqlParameter("@TimeWithdrawn", datagram.TimeWithdrawn), + new MySqlParameter("@pid", datagram.PID), + new MySqlParameter("@TrainerName", datagram.TrainerName), + new MySqlParameter("@TrainerOT", datagram.TrainerOT), + new MySqlParameter("@TrainerCountry", datagram.TrainerCountry), + new MySqlParameter("@TrainerRegion", datagram.TrainerRegion), + new MySqlParameter("@TrainerClass", datagram.TrainerClass), + new MySqlParameter("@IsExchanged", datagram.IsExchanged), + new MySqlParameter("@TrainerVersion", datagram.TrainerVersion), + new MySqlParameter("@TrainerLanguage", datagram.TrainerLanguage)); + + tran.Commit(); + + return true; + } + } + + public override void GtsDeletePokemon4(int pid) + { + } + + public override void GtsTradePokemon4(int pidSrc, int pidDest) + { + } + + #endregion } } diff --git a/library/Library.csproj b/library/Library.csproj index d7b7f1c1..43953da8 100644 --- a/library/Library.csproj +++ b/library/Library.csproj @@ -53,6 +53,10 @@ + + + +