Create GPSOAuthSharp.cs

Baha Striker [2016-07-28 22:51:39]
Create GPSOAuthSharp.cs
Filename
PokemonGo/RocketAPI/GPSOAuthSharp.cs
diff --git a/PokemonGo/RocketAPI/GPSOAuthSharp.cs b/PokemonGo/RocketAPI/GPSOAuthSharp.cs
new file mode 100644
index 0000000..9415c32
--- /dev/null
+++ b/PokemonGo/RocketAPI/GPSOAuthSharp.cs
@@ -0,0 +1,177 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Security.Cryptography;
+using System.Text;
+
+namespace DankMemes.GPSOAuthSharp
+{
+    // gpsoauth:__init__.py
+    // URL: https://github.com/simon-weber/gpsoauth/blob/master/gpsoauth/__init__.py
+    public class GPSOAuthClient
+    {
+        static string b64Key = "AAAAgMom/1a/v0lblO2Ubrt60J2gcuXSljGFQXgcyZWveWLEwo6prwgi3" +
+            "iJIZdodyhKZQrNWp5nKJ3srRXcUW+F1BD3baEVGcmEgqaLZUNBjm057pK" +
+            "RI16kB0YppeGx5qIQ5QjKzsR8ETQbKLNWgRY0QRNVz34kMJR3P/LgHax/" +
+            "6rmf5AAAAAwEAAQ==";
+        static RSAParameters androidKey = GoogleKeyUtils.KeyFromB64(b64Key);
+
+        static string version = "0.0.5";
+        static string authUrl = "https://android.clients.google.com/auth";
+        static string userAgent = "GPSOAuthSharp/" + version;
+
+        private string email;
+        private string password;
+
+        public GPSOAuthClient(string email, string password)
+        {
+            this.email = email;
+            this.password = password;
+        }
+
+        // _perform_auth_request
+        private Dictionary<string, string> PerformAuthRequest(Dictionary<string, string> data)
+        {
+            NameValueCollection nvc = new NameValueCollection();
+            foreach (var kvp in data)
+            {
+                nvc.Add(kvp.Key.ToString(), kvp.Value.ToString());
+            }
+            using (WebClient client = new WebClient())
+            {
+                client.Headers.Add(HttpRequestHeader.UserAgent, userAgent);
+                string result;
+                try
+                {
+                    byte[] response = client.UploadValues(authUrl, nvc);
+                    result = Encoding.UTF8.GetString(response);
+                }
+                catch (WebException e)
+                {
+                    result = new StreamReader(e.Response.GetResponseStream()).ReadToEnd();
+                }
+                return GoogleKeyUtils.ParseAuthResponse(result);
+            }
+        }
+
+        // perform_master_login
+        public Dictionary<string, string> PerformMasterLogin(string service = "ac2dm",
+            string deviceCountry = "us", string operatorCountry = "us", string lang = "en", int sdkVersion = 21)
+        {
+            string signature = GoogleKeyUtils.CreateSignature(email, password, androidKey);
+            var dict = new Dictionary<string, string> {
+                { "accountType", "HOSTED_OR_GOOGLE" },
+                { "Email", email },
+                { "has_permission", 1.ToString() },
+                { "add_account", 1.ToString() },
+                { "EncryptedPasswd",  signature},
+                { "service", service },
+                { "source", "android" },
+                { "device_country", deviceCountry },
+                { "operatorCountry", operatorCountry },
+                { "lang", lang },
+                { "sdk_version", sdkVersion.ToString() }
+            };
+            return PerformAuthRequest(dict);
+        }
+
+        // perform_oauth
+        public Dictionary<string, string> PerformOAuth(string masterToken, string service, string app, string clientSig,
+            string deviceCountry = "us", string operatorCountry = "us", string lang = "en", int sdkVersion = 21)
+        {
+            var dict = new Dictionary<string, string> {
+                { "accountType", "HOSTED_OR_GOOGLE" },
+                { "Email", email },
+                { "has_permission", 1.ToString() },
+                { "EncryptedPasswd",  masterToken},
+                { "service", service },
+                { "source", "android" },
+                { "app", app },
+                { "client_sig", clientSig },
+                { "device_country", deviceCountry },
+                { "operatorCountry", operatorCountry },
+                { "lang", lang },
+                { "sdk_version", sdkVersion.ToString() }
+            };
+            return PerformAuthRequest(dict);
+        }
+    }
+
+    // gpsoauth:google.py
+    // URL: https://github.com/simon-weber/gpsoauth/blob/master/gpsoauth/google.py
+    class GoogleKeyUtils
+    {
+        // key_from_b64
+        // BitConverter has different endianness, hence the Reverse()
+        public static RSAParameters KeyFromB64(string b64Key)
+        {
+            byte[] decoded = Convert.FromBase64String(b64Key);
+            int modLength = BitConverter.ToInt32(decoded.Take(4).Reverse().ToArray(), 0);
+            byte[] mod = decoded.Skip(4).Take(modLength).ToArray();
+            int expLength = BitConverter.ToInt32(decoded.Skip(modLength + 4).Take(4).Reverse().ToArray(), 0);
+            byte[] exponent = decoded.Skip(modLength + 8).Take(expLength).ToArray();
+            RSAParameters rsaKeyInfo = new RSAParameters();
+            rsaKeyInfo.Modulus = mod;
+            rsaKeyInfo.Exponent = exponent;
+            return rsaKeyInfo;
+        }
+
+        // key_to_struct
+        // Python version returns a string, but we use byte[] to get the same results
+        public static byte[] KeyToStruct(RSAParameters key)
+        {
+            byte[] modLength = { 0x00, 0x00, 0x00, 0x80 };
+            byte[] mod = key.Modulus;
+            byte[] expLength = { 0x00, 0x00, 0x00, 0x03 };
+            byte[] exponent = key.Exponent;
+            return DataTypeUtils.CombineBytes(modLength, mod, expLength, exponent);
+        }
+
+        // parse_auth_response
+        public static Dictionary<string, string> ParseAuthResponse(string text)
+        {
+            Dictionary<string, string> responseData = new Dictionary<string, string>();
+            foreach (string line in text.Split(new string[] { "\n", "\r\n" }, StringSplitOptions.RemoveEmptyEntries))
+            {
+                string[] parts = line.Split('=');
+                responseData.Add(parts[0], parts[1]);
+            }
+            return responseData;
+        }
+
+        // signature
+        public static string CreateSignature(string email, string password, RSAParameters key)
+        {
+            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
+            rsa.ImportParameters(key);
+            SHA1 sha1 = SHA1.Create();
+            byte[] prefix = { 0x00 };
+            byte[] hash = sha1.ComputeHash(GoogleKeyUtils.KeyToStruct(key)).Take(4).ToArray();
+            byte[] encrypted = rsa.Encrypt(Encoding.UTF8.GetBytes(email + "\x00" + password), true);
+            return DataTypeUtils.UrlSafeBase64(DataTypeUtils.CombineBytes(prefix, hash, encrypted));
+        }
+    }
+
+    class DataTypeUtils
+    {
+        public static string UrlSafeBase64(byte[] byteArray)
+        {
+            return Convert.ToBase64String(byteArray).Replace('+', '-').Replace('/', '_');
+        }
+
+        public static byte[] CombineBytes(params byte[][] arrays)
+        {
+            byte[] rv = new byte[arrays.Sum(a => a.Length)];
+            int offset = 0;
+            foreach (byte[] array in arrays)
+            {
+                Buffer.BlockCopy(array, 0, rv, offset, array.Length);
+                offset += array.Length;
+            }
+            return rv;
+        }
+    }
+}
You may download the files in Public Git.