diff --git a/gts/admin/Sessions.aspx.cs b/gts/admin/Sessions.aspx.cs
index 2b3d5a6b..7972347a 100644
--- a/gts/admin/Sessions.aspx.cs
+++ b/gts/admin/Sessions.aspx.cs
@@ -13,47 +13,10 @@ namespace PkmnFoundations.GTS.admin
{
protected void Page_Load(object sender, EventArgs e)
{
- GtsSessionManager manager = GtsSessionManager.FromContext(Context);
-
StringBuilder builder = new StringBuilder();
- builder.Append("Active GenIV sessions (");
- builder.Append(manager.Sessions4.Count);
- builder.Append("):
");
- foreach (KeyValuePair session in manager.Sessions4)
- {
- builder.Append("PID: ");
- builder.Append(session.Value.PID);
- builder.Append("
Token: ");
- builder.Append(session.Value.Token);
- builder.Append("
Hash: ");
- builder.Append(session.Value.Hash);
- builder.Append("
URL: ");
- builder.Append(session.Value.URL);
- builder.Append("
Expires: ");
- builder.Append(session.Value.ExpiryDate);
- builder.Append("
");
- }
-
- builder.Append("Active GenV sessions (");
- builder.Append(manager.Sessions5.Count);
- builder.Append("):
");
- foreach (KeyValuePair session in manager.Sessions5)
- {
- builder.Append("PID: ");
- builder.Append(session.Value.PID);
- builder.Append("
Token: ");
- builder.Append(session.Value.Token);
- builder.Append("
Hash: ");
- builder.Append(session.Value.Hash);
- builder.Append("
URL: ");
- builder.Append(session.Value.URL);
- builder.Append("
Expires: ");
- builder.Append(session.Value.ExpiryDate);
- builder.Append("
");
- }
GamestatsSessionManager gsm = GamestatsSessionManager.FromContext(Context);
- builder.Append("Active GSM sessions (");
+ builder.Append("Active sessions (");
builder.Append(gsm.Sessions.Count);
builder.Append("):
");
foreach (KeyValuePair session in gsm.Sessions)
@@ -73,7 +36,6 @@ namespace PkmnFoundations.GTS.admin
builder.Append("
");
}
-
litDebug.Text = builder.ToString();
}
}
diff --git a/gts/gts.csproj b/gts/gts.csproj
index 62a55543..f02780a1 100644
--- a/gts/gts.csproj
+++ b/gts/gts.csproj
@@ -3544,7 +3544,6 @@
RoomLeaders.aspx
-
AddDressup.aspx
@@ -3588,9 +3587,6 @@
pokemondpds.ashx
-
-
-
Default.aspx
ASPXCodeBehind
@@ -3609,7 +3605,6 @@
MasterPage.master
-
VideoId.aspx
ASPXCodeBehind
diff --git a/gts/masters/MasterPage.master.cs b/gts/masters/MasterPage.master.cs
index e4365686..93656716 100644
--- a/gts/masters/MasterPage.master.cs
+++ b/gts/masters/MasterPage.master.cs
@@ -12,12 +12,8 @@ namespace PkmnFoundations.GTS
{
protected void Page_Load(object sender, EventArgs e)
{
- // todo: I should store the available pokemon count
- // on the cache in the same way so the website doesn't
- // have a dependency on running in the same application
- // as the gamestats server.
- GtsSessionManager manager = GtsSessionManager.FromContext(Context);
- int availTotal = manager.AvailablePokemon4 + manager.AvailablePokemon5;
+ // todo: Cache this
+ int availTotal = Database.Instance.GtsAvailablePokemon4() + Database.Instance.GtsAvailablePokemon5();
litPokemon.Text = availTotal.ToString();
ulong bvCount4, bvCount5;
diff --git a/gts/src/GamestatsSessionPlat.cs b/gts/src/GamestatsSessionPlat.cs
deleted file mode 100644
index 5a153af0..00000000
--- a/gts/src/GamestatsSessionPlat.cs
+++ /dev/null
@@ -1,94 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Web;
-using System.Security.Cryptography;
-using System.IO;
-using System.Net;
-using GamestatsBase;
-
-namespace PkmnFoundations.GTS
-{
- public class GamestatsSessionPlat : GtsSessionBase
- {
- public GamestatsSessionPlat(int pid, String url)
- : base(pid, url)
- {
- Hash = ComputeHash(Token);
- }
-
- public static String ComputeHash(String token)
- {
- // todo: add unit tests with some wiresharked examples.
-
- if (m_sha1 == null) m_sha1 = SHA1.Create();
-
- String longToken = "uLMOGEiiJogofchScpXb" + token;
-
- byte[] data = new byte[longToken.Length];
- MemoryStream stream = new MemoryStream(data);
- StreamWriter writer = new StreamWriter(stream);
- writer.Write(longToken); // fixme: this throws an OutOfBoundsException if the passed token contains non-ascii.
- writer.Flush();
-
- return m_sha1.ComputeHash(data).ToHexStringLower();
- }
-
- ///
- /// Decrypts the NDS &data= querystring into readable binary data.
- /// The PID (little endian) is left at the start of the output
- /// but the (unencrypted) checksum is removed.
- ///
- public static byte[] DecryptData(String data)
- {
- byte[] data2 = FromUrlSafeBase64String(data);
- if (data2.Length < 4) throw new FormatException("Data must contain at least 4 bytes.");
-
- byte[] data3 = new byte[data2.Length - 4];
- int checksum = BitConverter.ToInt32(data2, 0);
- checksum = IPAddress.NetworkToHostOrder(checksum); // endian flip
- // overlay_0066.bin offset 0x2b2bc contains the evil xor mask I've been looking for,
- // encoded ... in ASCII... >__< (I was looking for binary)
- // uLMOGEiiJogofchScpXb000244fd00006015100000005b440e7epokemondpds
- checksum ^= 0x5b440e7e;
- int rand = checksum | (checksum << 16);
-
- // todo: prune first 8 bytes, pass pid to this function to validate
- for (int pos = 0; pos < data3.Length; pos++)
- {
- rand = DecryptRNG(rand);
- data3[pos] = (byte)(data2[pos + 4] ^ (byte)(rand >> 16));
- }
-
- // todo: validate and prune length, as in BW
-
- int checkedsum = 0;
- foreach (byte b in data3)
- checkedsum += b;
-
- if (checkedsum != checksum) throw new FormatException("Data checksum is incorrect.");
-
- return data3;
- }
-
- private static int DecryptRNG(int prev)
- {
- return (prev * 0x000244fd + 0x00006015) & ~0x10000000;
- }
-
- public static String ResponseChecksum(byte[] responseArray)
- {
- if (m_sha1 == null) m_sha1 = SHA1.Create();
-
- String toCheck = "uLMOGEiiJogofchScpXb" + ToUrlSafeBase64String(responseArray) + "uLMOGEiiJogofchScpXb";
-
- byte[] data = new byte[toCheck.Length];
- MemoryStream stream = new MemoryStream(data);
- StreamWriter writer = new StreamWriter(stream);
- writer.Write(toCheck);
- writer.Flush();
-
- return m_sha1.ComputeHash(data).ToHexStringLower();
- }
- }
-}
diff --git a/gts/src/GtsSession4.cs b/gts/src/GtsSession4.cs
deleted file mode 100644
index 01f742ca..00000000
--- a/gts/src/GtsSession4.cs
+++ /dev/null
@@ -1,77 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Web;
-using System.Security.Cryptography;
-using System.IO;
-using System.Net;
-using GamestatsBase;
-
-namespace PkmnFoundations.GTS
-{
- public class GtsSession4 : GtsSessionBase
- {
- public GtsSession4(int pid, String url) : base(pid, url)
- {
- Hash = ComputeHash(Token);
- }
-
- public static String ComputeHash(String token)
- {
- // todo: add unit tests with some wiresharked examples.
- // examples: (token -> hash)
- // bTII8cU1Kx86cTZPhEqXqLivqpRUUVpU -> 72bd08d60755b572da85d714508d14e68596bbdc
- // 7BEqRQlKsqRh8wTdL3rfgFxu053pgPzO -> e1c8f8b5b4cc0f1062cf215b1e7f36afed124f1e
- // 081PAAfk5SQhC7LTu1Iq7mwGtQ77xPOR -> ef8321dbb5b562d0bf2f3342008a1ba53851a14f
-
- if (m_sha1 == null) m_sha1 = SHA1.Create();
-
- String longToken = "sAdeqWo3voLeC5r16DYv" + token;
-
- byte[] data = new byte[longToken.Length];
- MemoryStream stream = new MemoryStream(data);
- StreamWriter writer = new StreamWriter(stream);
- writer.Write(longToken); // fixme: this throws an OutOfBoundsException if the passed token contains non-ascii.
- writer.Flush();
-
- return m_sha1.ComputeHash(data).ToHexStringLower();
- }
-
- ///
- /// Decrypts the NDS &data= querystring into readable binary data.
- /// The PID (little endian) is left at the start of the output
- /// but the (unencrypted) checksum is removed.
- ///
- public static byte[] DecryptData(String data)
- {
- byte[] data2 = FromUrlSafeBase64String(data);
- if (data2.Length < 4) throw new FormatException("Data must contain at least 4 bytes.");
-
- byte[] data3 = new byte[data2.Length - 4];
- int checksum = BitConverter.ToInt32(data2, 0);
- checksum = IPAddress.NetworkToHostOrder(checksum); // endian flip
- checksum ^= 0x4a3b2c1d;
- int rand = checksum | (checksum << 16);
-
- // todo: prune first 8 bytes, pass pid to this function to validate
- for (int pos = 0; pos < data3.Length; pos++)
- {
- rand = DecryptRNG(rand);
- data3[pos] = (byte)(data2[pos + 4] ^ (byte)(rand >> 16));
- }
-
- int checkedsum = 0;
- foreach (byte b in data3)
- checkedsum += b;
-
- if (checkedsum != checksum) throw new FormatException("Data checksum is incorrect.");
-
- return data3;
- }
-
- private static int DecryptRNG(int prev)
- {
- return (prev * 0x45 + 0x1111) & 0x7fffffff;
- }
- }
-}
diff --git a/gts/src/GtsSession5.cs b/gts/src/GtsSession5.cs
deleted file mode 100644
index 4934245d..00000000
--- a/gts/src/GtsSession5.cs
+++ /dev/null
@@ -1,84 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Web;
-using System.Security.Cryptography;
-using System.IO;
-using System.Net;
-using GamestatsBase;
-
-namespace PkmnFoundations.GTS
-{
- public class GtsSession5 : GtsSessionBase
- {
- public GtsSession5(int pid, String url) : base(pid, url)
- {
- Hash = ComputeHash(Token);
- }
-
- public static String ComputeHash(String token)
- {
- // todo: add unit tests with some wiresharked examples.
-
- if (m_sha1 == null) m_sha1 = SHA1.Create();
-
- String longToken = "HZEdGCzcGGLvguqUEKQN" + token;
-
- byte[] data = new byte[longToken.Length];
- MemoryStream stream = new MemoryStream(data);
- StreamWriter writer = new StreamWriter(stream);
- writer.Write(longToken); // fixme: this throws an OutOfBoundsException if the passed token contains non-ascii.
- writer.Flush();
-
- return m_sha1.ComputeHash(data).ToHexStringLower();
- }
-
- ///
- /// Decrypts the NDS &data= querystring into readable binary data.
- /// The PID (little endian) is left at the start of the output
- /// but the (unencrypted) checksum is removed.
- ///
- public static byte[] DecryptData(String data)
- {
- byte[] data2 = FromUrlSafeBase64String(data);
- if (data2.Length < 12) throw new FormatException("Data must contain at least 12 bytes.");
-
- byte[] data3 = new byte[data2.Length - 4];
- int checksum = BitConverter.ToInt32(data2, 0);
- checksum = IPAddress.NetworkToHostOrder(checksum); // endian flip
- checksum ^= 0x2db842b2;
-
- int length = BitConverter.ToInt32(data2, 8);
-
- // prune the checksum but keep pid and length.
- // this maximizes similarity with genIV's and allows
- // the ashx to check for pids to match.
- // todo: prune first 12 bytes, pass pid to this function to validate
- Array.Copy(data2, 4, data3, 0, data2.Length - 4);
-
- if (length + 8 != data3.Length) throw new FormatException("Data length is incorrect.");
- int checkedsum = 0;
- foreach (byte b in data3)
- checkedsum += b;
-
- if (checkedsum != checksum) throw new FormatException("Data checksum is incorrect.");
-
- return data3;
- }
-
- public static String ResponseChecksum(byte[] responseArray)
- {
- if (m_sha1 == null) m_sha1 = SHA1.Create();
-
- String toCheck = "HZEdGCzcGGLvguqUEKQN" + ToUrlSafeBase64String(responseArray) + "HZEdGCzcGGLvguqUEKQN";
-
- byte[] data = new byte[toCheck.Length];
- MemoryStream stream = new MemoryStream(data);
- StreamWriter writer = new StreamWriter(stream);
- writer.Write(toCheck);
- writer.Flush();
-
- return m_sha1.ComputeHash(data).ToHexStringLower();
- }
- }
-}
diff --git a/gts/src/GtsSessionBase.cs b/gts/src/GtsSessionBase.cs
deleted file mode 100644
index 7ec3f853..00000000
--- a/gts/src/GtsSessionBase.cs
+++ /dev/null
@@ -1,137 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Web;
-using System.Security.Cryptography;
-
-namespace PkmnFoundations.GTS
-{
- public class GtsSessionBase
- {
- protected static RNGCryptoServiceProvider m_rng;
- protected static SHA1 m_sha1;
-
- private int m_pid;
- private String m_url;
- private String m_token;
- private String m_hash;
- private DateTime m_expiry_date;
-
- protected GtsSessionBase(int pid, String url)
- {
- PID = pid;
- URL = url;
- ExpiryDate = DateTime.UtcNow.AddMinutes(10);
- Token = CreateToken();
- }
-
- ///
- /// A PID is a user ID which is associated with a game cartridge.
- ///
- public int PID
- {
- get
- {
- return m_pid;
- }
- protected set
- {
- m_pid = value;
- }
- }
-
- ///
- /// The URL in which this session began
- ///
- public String URL
- {
- get
- {
- return m_url;
- }
- protected set
- {
- m_url = value;
- }
- }
-
- ///
- /// 32 chars of random data which both functions as a challenge
- /// and as a session ID
- ///
- public String Token
- {
- get
- {
- return m_token;
- }
- protected set
- {
- m_token = value;
- }
- }
-
- public String Hash
- {
- get
- {
- return m_hash;
- }
- protected set
- {
- m_hash = value;
- }
- }
-
- public DateTime ExpiryDate
- {
- get
- {
- return m_expiry_date;
- }
- protected set
- {
- m_expiry_date = value;
- }
- }
-
- public object Tag
- {
- get;
- set;
- }
-
- public static String CreateToken()
- {
- if (m_rng == null) m_rng = new RNGCryptoServiceProvider();
-
- char[] token = new char[32];
- byte[] data = new byte[4];
-
- for (int x = 0; x < token.Length; x++)
- {
- // tokens have 62 possible chars: 0-9, A-Z, and a-z
- m_rng.GetBytes(data);
- uint rand = BitConverter.ToUInt32(data, 0) % 62u;
-
- if (rand < 10)
- token[x] = (char)('0' + rand);
- else if (rand < 36)
- token[x] = (char)('7' + rand); // 'A' + rand - 10
- else
- token[x] = (char)('=' + rand); // 'a' + rand - 36
- }
- return new String(token);
- }
-
- public static byte[] FromUrlSafeBase64String(String data)
- {
- return Convert.FromBase64String(data.Replace('-', '+').Replace('_', '/'));
- }
-
- public static String ToUrlSafeBase64String(byte[] data)
- {
- return Convert.ToBase64String(data).Replace('+', '-').Replace('/', '_');
- }
- }
-}
diff --git a/gts/src/GtsSessionManager.cs b/gts/src/GtsSessionManager.cs
deleted file mode 100644
index e07320d7..00000000
--- a/gts/src/GtsSessionManager.cs
+++ /dev/null
@@ -1,165 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Web;
-using PkmnFoundations.Data;
-
-namespace PkmnFoundations.GTS
-{
- ///
- /// Contains collections of GTS sessions (both generations)
- /// and some indexes for fast lookup
- ///
- public class GtsSessionManager
- {
- public readonly Dictionary Sessions4;
- public readonly Dictionary Sessions5;
-
- public GtsSessionManager()
- {
- Sessions4 = new Dictionary();
- Sessions5 = new Dictionary();
- RefreshStats();
- }
-
- public void PruneSessions()
- {
- PruneSessions4();
- PruneSessions5();
- }
-
- public void PruneSessions4()
- {
- Dictionary sessions = Sessions4;
- DateTime now = DateTime.UtcNow;
-
- lock (sessions)
- {
- 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());
- }
- }
- }
-
- public void PruneSessions5()
- {
- Dictionary sessions = Sessions5;
- DateTime now = DateTime.UtcNow;
-
- lock (sessions)
- {
- 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());
- }
- }
- }
-
- public void Add(GtsSession4 session)
- {
- Sessions4.Add(session.Hash, session);
- }
-
- public void Add(GtsSession5 session)
- {
- Sessions5.Add(session.Hash, session);
- }
-
- public void Remove(GtsSession4 session)
- {
- Sessions4.Remove(session.Hash);
- }
-
- public void Remove(GtsSession5 session)
- {
- Sessions5.Remove(session.Hash);
- }
-
- ///
- /// Retrieves the GtsSessionManager from the context's application state.
- ///
- public static GtsSessionManager FromContext(HttpContext context)
- {
- object oManager = context.Application["GtsSessionManager"];
- GtsSessionManager manager = oManager as GtsSessionManager;
-
- if (manager == null)
- {
- manager = new GtsSessionManager();
- context.Application.Add("GtsSessionManager", manager);
- }
-
- return manager;
- }
-
- public GtsSession4 FindSession4(int pid, String url)
- {
- // todo: keep a hash table of pids that maps them onto session objects
- GtsSession4 result = null;
-
- foreach (GtsSession4 sess in Sessions4.Values)
- {
- if (sess.PID == pid && sess.URL == url)
- {
- if (result != null)
- {
- // todo: there's more than one matching session... delete them all.
- }
- return sess; // temp until I get it to cleanup old sessions
- result = sess;
- }
- }
- return result;
- }
-
- public GtsSession5 FindSession5(int pid, String url)
- {
- // todo: keep a hash table of pids that maps them onto session objects
- GtsSession5 result = null;
-
- foreach (GtsSession5 sess in Sessions5.Values)
- {
- if (sess.PID == pid && sess.URL == url)
- {
- if (result != null)
- {
- // todo: there's more than one matching session... delete them all.
- }
- return sess; // temp until I get it to cleanup old sessions
- result = sess;
- }
- }
- return result;
- }
-
- public void RefreshStats()
- {
- AvailablePokemon4 = Database.Instance.GtsAvailablePokemon4();
- AvailablePokemon5 = Database.Instance.GtsAvailablePokemon5();
- }
-
- public int AvailablePokemon4
- {
- get;
- private set;
- }
-
- public int AvailablePokemon5
- {
- get;
- private set;
- }
-
- }
-}
\ No newline at end of file
diff --git a/gts/test/Decode.aspx.cs b/gts/test/Decode.aspx.cs
index cf3e3b20..01b92887 100644
--- a/gts/test/Decode.aspx.cs
+++ b/gts/test/Decode.aspx.cs
@@ -26,7 +26,11 @@ namespace PkmnFoundations.GTS.debug
try
{
- data = GtsSession4.DecryptData(txtData.Text);
+ GamestatsHandler gs4 = new GamestatsHandler("sAdeqWo3voLeC5r16DYv",
+ 0x45, 0x1111, 0x80000000, 0x4a3b2c1d, "pokemondpds",
+ GamestatsRequestVersions.Version2, GamestatsResponseVersions.Version1, true);
+
+ data = gs4.DecryptData(txtData.Text);
litGeneration.Text = "4";
}
catch (FormatException)
@@ -35,7 +39,9 @@ namespace PkmnFoundations.GTS.debug
if (data == null) try
{
- data = GtsSession5.DecryptData(txtData.Text);
+ GamestatsHandler gs5 = new GamestatsHandler("HZEdGCzcGGLvguqUEKQN0001d93500002dd5000000082db842b2syachi2ds",
+ GamestatsRequestVersions.Version3, GamestatsResponseVersions.Version2, false);
+ data = gs5.DecryptData(txtData.Text);
litGeneration.Text = "5";
}
catch (FormatException)
@@ -44,7 +50,9 @@ namespace PkmnFoundations.GTS.debug
if (data == null) try
{
- data = GamestatsSessionPlat.DecryptData(txtData.Text);
+ GamestatsHandler gsPlat = new GamestatsHandler("uLMOGEiiJogofchScpXb000244fd00006015100000005b440e7epokemondpds",
+ GamestatsRequestVersions.Version3, GamestatsResponseVersions.Version2, true);
+ data = gsPlat.DecryptData(txtData.Text);
litGeneration.Text = "Platinum";
}
catch (FormatException)
@@ -69,7 +77,7 @@ namespace PkmnFoundations.GTS.debug
if (data == null) try
{
- data = GtsSessionBase.FromUrlSafeBase64String(txtData.Text);
+ data = GamestatsHandler.FromUrlSafeBase64String(txtData.Text);
litGeneration.Text = "Unknown (are you sure this is gamestats data?)";
litChecksum.Text = "";
@@ -93,7 +101,7 @@ namespace PkmnFoundations.GTS.debug
public static byte[] DecryptData(String data)
{
- byte[] data2 = GtsSessionBase.FromUrlSafeBase64String(data);
+ byte[] data2 = GamestatsHandler.FromUrlSafeBase64String(data);
if (data2.Length < 12) throw new FormatException("Data must contain at least 12 bytes.");
int checksum = BitConverter.ToInt32(data2, 0);