diff --git a/POGOLib.Official/Configuration.cs b/POGOLib.Official/Configuration.cs
index 3d3e0f6c1..46969e532 100644
--- a/POGOLib.Official/Configuration.cs
+++ b/POGOLib.Official/Configuration.cs
@@ -1,9 +1,4 @@
using POGOLib.Official.Util.Hash;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
namespace POGOLib.Official
{
diff --git a/POGOLib.Official/Constants.cs b/POGOLib.Official/Constants.cs
index aa06472c3..867d41f5e 100644
--- a/POGOLib.Official/Constants.cs
+++ b/POGOLib.Official/Constants.cs
@@ -1,9 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-
-namespace POGOLib.Official
+namespace POGOLib.Official
{
public static class Constants
{
diff --git a/POGOLib.Official/Exceptions/SessionStateException.cs b/POGOLib.Official/Exceptions/SessionStateException.cs
new file mode 100644
index 000000000..7bb781227
--- /dev/null
+++ b/POGOLib.Official/Exceptions/SessionStateException.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace POGOLib.Official.Exceptions
+{
+ public class SessionStateException : Exception
+ {
+ public SessionStateException(string message) : base(message)
+ {
+ }
+ }
+}
diff --git a/POGOLib.Official/Extensions/RandomExtension.cs b/POGOLib.Official/Extensions/RandomExtension.cs
index 3e258e5a5..b3b4271c6 100644
--- a/POGOLib.Official/Extensions/RandomExtension.cs
+++ b/POGOLib.Official/Extensions/RandomExtension.cs
@@ -1,7 +1,5 @@
using System;
-using System.Collections.Generic;
using System.Linq;
-using System.Threading.Tasks;
namespace POGOLib.Official.Extensions
{
diff --git a/POGOLib.Official/Logging/LogLevel.cs b/POGOLib.Official/Logging/LogLevel.cs
index bb1b1584d..d18a75e06 100644
--- a/POGOLib.Official/Logging/LogLevel.cs
+++ b/POGOLib.Official/Logging/LogLevel.cs
@@ -1,9 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-
-namespace POGOLib.Official.Logging
+namespace POGOLib.Official.Logging
{
public enum LogLevel
{
diff --git a/POGOLib.Official/Logging/Logger.cs b/POGOLib.Official/Logging/Logger.cs
index 855508c4b..56d7347d8 100644
--- a/POGOLib.Official/Logging/Logger.cs
+++ b/POGOLib.Official/Logging/Logger.cs
@@ -1,7 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
+using System.Collections.Generic;
namespace POGOLib.Official.Logging
{
@@ -43,7 +40,7 @@ public static void Error(string message)
private static void Output(LogLevel logLevel, string message)
{
- foreach (var logOutput in LogOutputs)
+ foreach(var logOutput in LogOutputs)
{
logOutput(logLevel, message);
}
diff --git a/POGOLib.Official/LoginProviders/ILoginProvider.cs b/POGOLib.Official/LoginProviders/ILoginProvider.cs
index 469ae3142..5ce89c667 100644
--- a/POGOLib.Official/LoginProviders/ILoginProvider.cs
+++ b/POGOLib.Official/LoginProviders/ILoginProvider.cs
@@ -1,8 +1,5 @@
-using POGOLib.Official.Net.Authentication.Data;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
+using System.Threading.Tasks;
+using POGOLib.Official.Net.Authentication.Data;
namespace POGOLib.Official.LoginProviders
{
diff --git a/POGOLib.Official/LoginProviders/PtcLoginException.cs b/POGOLib.Official/LoginProviders/PtcLoginException.cs
index 7fcf03038..4b0f21814 100644
--- a/POGOLib.Official/LoginProviders/PtcLoginException.cs
+++ b/POGOLib.Official/LoginProviders/PtcLoginException.cs
@@ -1,7 +1,4 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
namespace POGOLib.Official.LoginProviders
{
diff --git a/POGOLib.Official/LoginProviders/PtcLoginProvider.cs b/POGOLib.Official/LoginProviders/PtcLoginProvider.cs
index 22d200374..fe856a7ae 100644
--- a/POGOLib.Official/LoginProviders/PtcLoginProvider.cs
+++ b/POGOLib.Official/LoginProviders/PtcLoginProvider.cs
@@ -1,16 +1,16 @@
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
-using POGOLib.Official.Logging;
-using POGOLib.Official.Net.Authentication.Data;
-using System;
+using System;
using System.Collections.Generic;
-using System.Linq;
using System.Net.Http;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using POGOLib.Official.Logging;
+using POGOLib.Official.Net.Authentication.Data;
namespace POGOLib.Official.LoginProviders
{
+
///
/// The for Pokemon Trainer Club.
/// Use this if you want to authenticate to PokemonGo using a Pokemon Trainer Club account.
diff --git a/POGOLib.Official/Net/Authentication/Data/AccessToken.cs b/POGOLib.Official/Net/Authentication/Data/AccessToken.cs
index e012b7404..7a6cbfe4f 100644
--- a/POGOLib.Official/Net/Authentication/Data/AccessToken.cs
+++ b/POGOLib.Official/Net/Authentication/Data/AccessToken.cs
@@ -1,9 +1,6 @@
-using Newtonsoft.Json;
+using System;
+using Newtonsoft.Json;
using POGOProtos.Networking.Envelopes;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
namespace POGOLib.Official.Net.Authentication.Data
{
diff --git a/POGOLib.Official/Net/Authentication/Data/LoginData.cs b/POGOLib.Official/Net/Authentication/Data/LoginData.cs
index 3b52912f4..f86939ae1 100644
--- a/POGOLib.Official/Net/Authentication/Data/LoginData.cs
+++ b/POGOLib.Official/Net/Authentication/Data/LoginData.cs
@@ -1,8 +1,4 @@
using Newtonsoft.Json;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
namespace POGOLib.Official.Net.Authentication.Data
{
diff --git a/POGOLib.Official/Net/Authentication/Exceptions/WrongCredentialsException.cs b/POGOLib.Official/Net/Authentication/Exceptions/WrongCredentialsException.cs
index bb04741ec..768587ec4 100644
--- a/POGOLib.Official/Net/Authentication/Exceptions/WrongCredentialsException.cs
+++ b/POGOLib.Official/Net/Authentication/Exceptions/WrongCredentialsException.cs
@@ -1,15 +1,14 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
namespace POGOLib.Official.Net.Authentication.Exceptions
{
public class WrongCredentialsException : Exception
{
+
public WrongCredentialsException(string message) : base(message)
{
-
+
}
+
}
}
diff --git a/POGOLib.Official/Net/Authentication/Login.cs b/POGOLib.Official/Net/Authentication/Login.cs
index c7200a73a..7ea1769cc 100644
--- a/POGOLib.Official/Net/Authentication/Login.cs
+++ b/POGOLib.Official/Net/Authentication/Login.cs
@@ -1,11 +1,9 @@
-using GeoCoordinatePortable;
+using System;
+using System.Threading.Tasks;
+using GeoCoordinatePortable;
using POGOLib.Official.Logging;
using POGOLib.Official.LoginProviders;
using POGOLib.Official.Net.Authentication.Data;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
using static POGOProtos.Networking.Envelopes.Signature.Types;
namespace POGOLib.Official.Net.Authentication
@@ -77,6 +75,6 @@ public static async Task GetSession(ILoginProvider loginProvider, GeoCo
{
return new Session(loginProvider, await loginProvider.GetAccessToken(), coordinate, deviceInfo);
}
-
+
}
}
diff --git a/POGOLib.Official/Net/Captcha/CaptchaEventArgs.cs b/POGOLib.Official/Net/Captcha/CaptchaEventArgs.cs
new file mode 100644
index 000000000..52ee5050c
--- /dev/null
+++ b/POGOLib.Official/Net/Captcha/CaptchaEventArgs.cs
@@ -0,0 +1,14 @@
+using System;
+
+namespace POGOLib.Official.Net.Captcha
+{
+ public class CaptchaEventArgs : EventArgs
+ {
+ public CaptchaEventArgs(string captchaUrl)
+ {
+ CaptchaUrl = captchaUrl;
+ }
+
+ public string CaptchaUrl { get; }
+ }
+}
diff --git a/POGOLib.Official/Net/RpcClient.cs b/POGOLib.Official/Net/RpcClient.cs
index b47fa046a..f6b9f4e06 100644
--- a/POGOLib.Official/Net/RpcClient.cs
+++ b/POGOLib.Official/Net/RpcClient.cs
@@ -1,31 +1,30 @@
-using GeoCoordinatePortable;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.Http;
+using System.Text.RegularExpressions;
+using System.Threading;
+using System.Threading.Tasks;
+using GeoCoordinatePortable;
using Google.Protobuf;
using Newtonsoft.Json;
using POGOLib.Official.Logging;
using POGOLib.Official.Util;
-using POGOProtos.Enums;
using POGOProtos.Map;
using POGOProtos.Networking.Envelopes;
-using POGOProtos.Networking.Platform;
-using POGOProtos.Networking.Platform.Requests;
-using POGOProtos.Networking.Platform.Responses;
using POGOProtos.Networking.Requests;
using POGOProtos.Networking.Requests.Messages;
using POGOProtos.Networking.Responses;
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Linq;
-using System.Net.Http;
-using System.Text.RegularExpressions;
-using System.Threading;
-using System.Threading.Tasks;
+using POGOProtos.Enums;
+using POGOProtos.Networking.Platform;
+using POGOProtos.Networking.Platform.Requests;
+using POGOProtos.Networking.Platform.Responses;
namespace POGOLib.Official.Net
{
public class RpcClient : IDisposable
{
-
///
/// The authenticated .
///
@@ -61,9 +60,8 @@ public class RpcClient : IDisposable
private readonly ConcurrentDictionary _rpcResponses = new ConcurrentDictionary();
- private static readonly Semaphore RpcQueueMutex = new Semaphore(1, 1);
+ private readonly Semaphore _rpcQueueMutex = new Semaphore(1, 1);
- public event EventHandler CheckChallengeReceived;
public event EventHandler HatchedEggsReceived;
public event EventHandler CheckAwardedBadgesReceived;
@@ -79,17 +77,12 @@ internal RpcClient(Session session)
internal DateTime LastRpcMapObjectsRequest { get; private set; }
internal GeoCoordinate LastGeoCoordinateMapObjectsRequest { get; private set; } = new GeoCoordinate();
-
+
internal Platform GetPlatform()
{
return _session.DeviceInfo.DeviceBrand == "Apple" ? Platform.Ios : Platform.Android;
}
- internal void ResetLastTimestampSinceStart()
- {
- _rpcEncryption.ResetLastTimestampSinceStart();
- }
-
private long PositiveRandom()
{
long ret = _session.Random.Next() | (_session.Random.Next() << 32);
@@ -115,7 +108,7 @@ private void IncrementRequestCount()
break;
}
}
-
+
///
/// Sends all requests which the (ios-)client sends on startup
///
@@ -269,30 +262,38 @@ public async Task RefreshMapObjectsAsync()
}.ToByteString()
});
- var mapObjects = GetMapObjectsResponse.Parser.ParseFrom(response);
- if (mapObjects.Status == MapObjectsStatus.Success)
+ if (response != null)
{
- // TODO: Cleaner?
- var pokemonCatchable = mapObjects.MapCells.SelectMany(c => c.CatchablePokemons).Count();
- var pokemonWild = mapObjects.MapCells.SelectMany(c => c.WildPokemons).Count();
- var pokemonNearby = mapObjects.MapCells.SelectMany(c => c.NearbyPokemons).Count();
- var pokemonCount = pokemonCatchable + pokemonWild + pokemonNearby;
+ var mapObjects = GetMapObjectsResponse.Parser.ParseFrom(response);
+ if (mapObjects.Status == MapObjectsStatus.Success)
+ {
+ // TODO: Cleaner?
+ var pokemonCatchable = mapObjects.MapCells.SelectMany(c => c.CatchablePokemons).Count();
+ var pokemonWild = mapObjects.MapCells.SelectMany(c => c.WildPokemons).Count();
+ var pokemonNearby = mapObjects.MapCells.SelectMany(c => c.NearbyPokemons).Count();
+ var pokemonCount = pokemonCatchable + pokemonWild + pokemonNearby;
- Logger.Debug($"Received '{mapObjects.MapCells.Count}' map cells.");
- Logger.Debug($"Received '{pokemonCount}' pokemons. Catchable({pokemonCatchable}) Wild({pokemonWild}) Nearby({pokemonNearby})");
- Logger.Debug($"Received '{mapObjects.MapCells.SelectMany(c => c.Forts).Count()}' forts.");
+ Logger.Debug($"Received '{mapObjects.MapCells.Count}' map cells.");
+ Logger.Debug($"Received '{pokemonCount}' pokemons. Catchable({pokemonCatchable}) Wild({pokemonWild}) Nearby({pokemonNearby})");
+ Logger.Debug($"Received '{mapObjects.MapCells.SelectMany(c => c.Forts).Count()}' forts.");
+
+ if (mapObjects.MapCells.Count == 0)
+ {
+ Logger.Error("We received 0 map cells, are your GPS coordinates correct?");
+ return;
+ }
- if (mapObjects.MapCells.Count == 0)
+ _session.Map.Cells = mapObjects.MapCells;
+ }
+ else
{
- Logger.Error("We received 0 map cells, are your GPS coordinates correct?");
- return;
+ Logger.Error($"GetMapObjects status is: '{mapObjects.Status}'.");
}
-
- _session.Map.Cells = mapObjects.MapCells;
}
- else
+ else if (_session.State != SessionState.Paused)
{
- Logger.Error($"GetMapObjects status is: '{mapObjects.Status}'.");
+ // POGOLib didn't expect this.
+ throw new NullReferenceException(nameof(response));
}
}
@@ -379,8 +380,7 @@ private IEnumerable GetDefaultRequests()
}.ToByteString()
});
}
-
-
+
//If Incense is active we add this:
//request.Add(new Request
//{
@@ -471,14 +471,14 @@ public async Task SendRemoteProcedureCallAsync(RequestType requestTy
});
}
- public async Task SendRemoteProcedureCallAsync(Request request, bool sendDefaultRequests = true)
+ public async Task SendRemoteProcedureCallAsync(Request request, bool addDefaultRequests = true)
{
- return await SendRemoteProcedureCall(await GetRequestEnvelopeAsync(new[] { request }, sendDefaultRequests));
+ return await SendRemoteProcedureCall(await GetRequestEnvelopeAsync(new[] {request}, addDefaultRequests));
}
- public async Task SendRemoteProcedureCallAsync(Request[] request)
+ public async Task SendRemoteProcedureCallAsync(Request[] request, bool addDefaultRequests = false)
{
- return await SendRemoteProcedureCall(await GetRequestEnvelopeAsync(request, false));
+ return await SendRemoteProcedureCall(await GetRequestEnvelopeAsync(request, addDefaultRequests));
}
private Task SendRemoteProcedureCall(RequestEnvelope requestEnvelope)
@@ -489,7 +489,7 @@ private Task SendRemoteProcedureCall(RequestEnvelope requestEnvelope
try
{
- RpcQueueMutex.WaitOne();
+ _rpcQueueMutex.WaitOne();
RequestEnvelope processRequestEnvelope;
while (_rpcQueue.TryDequeue(out processRequestEnvelope))
@@ -511,7 +511,7 @@ private Task SendRemoteProcedureCall(RequestEnvelope requestEnvelope
}
finally
{
- RpcQueueMutex.Release();
+ _rpcQueueMutex.Release();
}
});
}
@@ -520,6 +520,22 @@ private async Task PerformRemoteProcedureCallAsync(RequestEnvelope r
{
try
{
+ switch (_session.State)
+ {
+ case SessionState.Stopped:
+ Logger.Error("We tried to send a request while the session was stopped.");
+ return null;
+
+ case SessionState.Paused:
+ var requests = requestEnvelope.Requests.Select(x => x.RequestType).ToList();
+ if (requests.Count != 1 || requests[0] != RequestType.VerifyChallenge)
+ {
+ Logger.Error("We tried to send a request while the session was paused. The only request allowed is VerifyChallenge.");
+ return null;
+ }
+ break;
+ }
+
using (var requestData = new ByteArrayContent(requestEnvelope.ToByteArray()))
{
Logger.Debug($"Sending RPC Request: '{string.Join(", ", requestEnvelope.Requests.Select(x => x.RequestType))}'");
@@ -540,10 +556,10 @@ private async Task PerformRemoteProcedureCallAsync(RequestEnvelope r
switch (responseEnvelope.StatusCode)
{
// Valid response.
- case ResponseEnvelope.Types.StatusCode.Ok:
+ case ResponseEnvelope.Types.StatusCode.Ok:
// Success!?
break;
-
+
// Valid response and new rpc url.
case ResponseEnvelope.Types.StatusCode.OkRpcUrlInResponse:
if (Regex.IsMatch(responseEnvelope.ApiUrl, "pgorelease\\.nianticlabs\\.com\\/plfe\\/\\d+"))
@@ -557,7 +573,7 @@ private async Task PerformRemoteProcedureCallAsync(RequestEnvelope r
break;
// A new rpc endpoint is available.
- case ResponseEnvelope.Types.StatusCode.Redirect:
+ case ResponseEnvelope.Types.StatusCode.Redirect:
if (Regex.IsMatch(responseEnvelope.ApiUrl, "pgorelease\\.nianticlabs\\.com\\/plfe\\/\\d+"))
{
_requestUrl = $"https://{responseEnvelope.ApiUrl}/rpc";
@@ -622,7 +638,7 @@ private async Task PerformRemoteProcedureCallAsync(RequestEnvelope r
var unknownPtr8Response = UnknownPtr8Response.Parser.ParseFrom(mapPlatform.Response);
_mapKey = unknownPtr8Response.Message;
}
-
+
return HandleResponseEnvelope(requestEnvelope, responseEnvelope);
}
}
@@ -702,7 +718,7 @@ private void HandleInventoryResponses(Request request, ByteString requestRespons
private void HandleDefaultResponses(RequestEnvelope requestEnvelope, IList returns)
{
var responseIndexes = new Dictionary();
-
+
for (var i = 0; i < requestEnvelope.Requests.Count; i++)
{
var request = requestEnvelope.Requests[i];
@@ -773,15 +789,13 @@ private void HandleDefaultResponses(RequestEnvelope requestEnvelope, IList
/// The authenticated .
///
@@ -37,11 +36,6 @@ internal class RpcEncryption
///
private long _lastTimestampSinceStart;
- public void ResetLastTimestampSinceStart()
- {
- _lastTimestampSinceStart = 0;
- }
-
internal RpcEncryption(Session session)
{
_session = session;
@@ -55,8 +49,7 @@ internal RpcEncryption(Session session)
}
private long TimestampSinceStartMs => _stopwatch.ElapsedMilliseconds;
-
-
+
///
/// Generates a few random es to act like a real GPS sensor.
///
@@ -67,73 +60,66 @@ private List BuildLocationFixes(RequestEnvelope requestEnvelope, lo
{
var locationFixes = new List();
- try
- {
- if (requestEnvelope.Requests.Count == 0 || requestEnvelope.Requests[0] == null)
- return locationFixes;
-
- // Determine amount of location fixes.
- // We look for the amount of seconds that have passed since the last location fixes request.
- // If that results in 0, send 1 location fix.
- var millisecondsPerFix = _session.Random.Next(995, 999);
- var providerCount = Math.Min((timestampSinceStart - _lastTimestampSinceStart) / millisecondsPerFix, _session.Random.Next(8, 11));
- if (providerCount == 0)
- providerCount = 1;
-
- // Determine size of the "play around" window.
- // Not so relevant when starting up.
- var totalMilliseconds = providerCount * millisecondsPerFix;
- var baseTimestampSnapshot = Math.Max(timestampSinceStart - totalMilliseconds, 0);
- var playAroundWindow = baseTimestampSnapshot - _lastTimestampSinceStart;
-
- if (playAroundWindow == 0 && providerCount == 1 && millisecondsPerFix >= timestampSinceStart)
- {
- // We really need an offset for this one..
- playAroundWindow = _session.Random.Next(0, (int)timestampSinceStart);
- }
- else
- {
- // A small offset between location fixes.
- playAroundWindow = Math.Min(playAroundWindow, providerCount * 2);
- }
-
- // Share "play around" window over all location fixes.
- var playAroundWindowPart = playAroundWindow != 0
- ? playAroundWindow / providerCount
- : 1;
+ if (requestEnvelope.Requests.Count == 0 || requestEnvelope.Requests[0] == null)
+ return locationFixes;
- for (var i = 0; i < providerCount; i++)
- {
- var timestampSnapshot = baseTimestampSnapshot;
- // Apply current location fix position.
- timestampSnapshot += i * millisecondsPerFix;
- // Apply an offset.
- timestampSnapshot += _session.Random.Next(0, (int)((i + 1) * Math.Abs(playAroundWindowPart)));
+ // Determine amount of location fixes.
+ // We look for the amount of seconds that have passed since the last location fixes request.
+ // If that results in 0, send 1 location fix.
+ var millisecondsPerFix = _session.Random.Next(995, 999);
+ var providerCount = Math.Min((timestampSinceStart - _lastTimestampSinceStart) / millisecondsPerFix, _session.Random.Next(8, 11));
+ if (providerCount == 0)
+ providerCount = 1;
- locationFixes.Add(new LocationFix
- {
- TimestampSnapshot = (ulong)timestampSnapshot,
- Latitude = LocationUtil.OffsetLatitudeLongitude(_session.Player.Coordinate.Latitude, _session.Random.Next(100) + 10),
- Longitude = LocationUtil.OffsetLatitudeLongitude(_session.Player.Coordinate.Longitude, _session.Random.Next(100) + 10),
- HorizontalAccuracy = (float)_session.Random.NextDouble(5.0, 25.0),
- VerticalAccuracy = (float)_session.Random.NextDouble(5.0, 25.0),
- Altitude = (float)_session.Random.NextDouble(10.0, 30.0),
- Provider = "fused",
- ProviderStatus = 3,
- LocationType = 1,
- Course = -1,
- Speed = -1
- // Floor = 0
- });
- }
+ // Determine size of the "play around" window.
+ // Not so relevant when starting up.
+ var totalMilliseconds = providerCount * millisecondsPerFix;
+ var baseTimestampSnapshot = Math.Max(timestampSinceStart - totalMilliseconds, 0);
+ var playAroundWindow = Math.Max(0, baseTimestampSnapshot - _lastTimestampSinceStart);
- _lastTimestampSinceStart = timestampSinceStart;
+ if (playAroundWindow == 0 && providerCount == 1 && millisecondsPerFix >= timestampSinceStart)
+ {
+ // We really need an offset for this one..
+ playAroundWindow = _session.Random.Next(0, (int) timestampSinceStart);
}
- catch (Exception ex)
+ else
{
+ // A small offset between location fixes.
+ playAroundWindow = Math.Min(playAroundWindow, providerCount * 2);
+ }
+ // Share "play around" window over all location fixes.
+ var playAroundWindowPart = playAroundWindow != 0
+ ? playAroundWindow / providerCount
+ : 1;
+
+ for (var i = 0; i < providerCount; i++)
+ {
+ var timestampSnapshot = baseTimestampSnapshot;
+ // Apply current location fix position.
+ timestampSnapshot += i * millisecondsPerFix;
+ // Apply an offset.
+ timestampSnapshot += _session.Random.Next(0, (int) ((i + 1) * playAroundWindowPart));
+
+ locationFixes.Add(new LocationFix
+ {
+ TimestampSnapshot = (ulong) timestampSnapshot,
+ Latitude = LocationUtil.OffsetLatitudeLongitude(_session.Player.Coordinate.Latitude, _session.Random.Next(100) + 10),
+ Longitude = LocationUtil.OffsetLatitudeLongitude(_session.Player.Coordinate.Longitude, _session.Random.Next(100) + 10),
+ HorizontalAccuracy = (float) _session.Random.NextDouble(5.0, 25.0),
+ VerticalAccuracy = (float) _session.Random.NextDouble(5.0, 25.0),
+ Altitude = (float) _session.Random.NextDouble(10.0, 30.0),
+ Provider = "fused",
+ ProviderStatus = 3,
+ LocationType = 1,
+ Course = -1,
+ Speed = -1
+ // Floor = 0
+ });
}
+ _lastTimestampSinceStart = timestampSinceStart;
+
return locationFixes;
}
@@ -157,7 +143,7 @@ internal async Task GenerateSignatureAsync(RequestEnvelope requ
_session.Player.Coordinate.Altitude = locationFix.Altitude;
requestEnvelope.Accuracy = _session.Player.Coordinate.Altitude; // _session.Player.Coordinate.HorizontalAccuracy;
- requestEnvelope.MsSinceLastLocationfix = timestampSinceStart - (long)locationFix.TimestampSnapshot;
+ requestEnvelope.MsSinceLastLocationfix = timestampSinceStart - (long) locationFix.TimestampSnapshot;
var signature = new Signature
{
@@ -204,8 +190,8 @@ internal async Task GenerateSignatureAsync(RequestEnvelope requ
var requestsBytes = requestEnvelope.Requests.Select(x => x.ToByteArray()).ToArray();
var hashData = await Configuration.Hasher.GetHashDataAsync(requestEnvelope, signature, locationBytes, requestsBytes, serializedTicket);
- signature.LocationHash1 = (int)hashData.LocationAuthHash;
- signature.LocationHash2 = (int)hashData.LocationHash;
+ signature.LocationHash1 = (int) hashData.LocationAuthHash;
+ signature.LocationHash2 = (int) hashData.LocationHash;
signature.RequestHash.AddRange(hashData.RequestHashes);
@@ -217,9 +203,8 @@ internal async Task GenerateSignatureAsync(RequestEnvelope requ
EncryptedSignature = ByteString.CopyFrom(Configuration.Hasher.GetEncryptedSignature(signature.ToByteArray(), (uint)timestampSinceStart))
}.ToByteString()
};
-
+
return encryptedSignature;
}
-
}
}
diff --git a/POGOLib.Official/Net/Session.cs b/POGOLib.Official/Net/Session.cs
index 2afd67bd8..d76e4521b 100644
--- a/POGOLib.Official/Net/Session.cs
+++ b/POGOLib.Official/Net/Session.cs
@@ -1,18 +1,19 @@
-using GeoCoordinatePortable;
+using System;
+using System.Linq;
+using System.Net;
+using System.Net.Http;
+using System.Threading;
+using System.Threading.Tasks;
+using GeoCoordinatePortable;
+using POGOLib.Official.Exceptions;
using POGOLib.Official.Logging;
using POGOLib.Official.LoginProviders;
using POGOLib.Official.Net.Authentication.Data;
+using POGOLib.Official.Net.Captcha;
using POGOLib.Official.Pokemon;
using POGOLib.Official.Util.Device;
using POGOLib.Official.Util.Hash;
using POGOProtos.Settings;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Net;
-using System.Net.Http;
-using System.Threading;
-using System.Threading.Tasks;
using static POGOProtos.Networking.Envelopes.Signature.Types;
namespace POGOLib.Official.Net
@@ -22,6 +23,7 @@ namespace POGOLib.Official.Net
///
public class Session : IDisposable
{
+ private SessionState _state;
///
/// This is the which is responsible for retrieving events and updating gps location.
@@ -49,6 +51,8 @@ internal Session(ILoginProvider loginProvider, AccessToken accessToken, GeoCoord
throw new ArgumentException($"LoginProvider ID must be one of the following: {string.Join(", ", ValidLoginProviders)}");
}
+ State = SessionState.Stopped;
+
HttpClient = new HttpClient(new HttpClientHandler
{
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
@@ -59,12 +63,26 @@ internal Session(ILoginProvider loginProvider, AccessToken accessToken, GeoCoord
DeviceInfo = deviceInfo ?? DeviceInfoUtil.GetRandomDevice(this);
AccessToken = accessToken;
LoginProvider = loginProvider;
- Player = new Player(geoCoordinate);
+ Player = new Player(this, geoCoordinate);
Map = new Map(this);
RpcClient = new RpcClient(this);
_heartbeat = new HeartbeatDispatcher(this);
}
+ ///
+ /// Gets the of the .
+ ///
+ public SessionState State
+ {
+ get { return _state; }
+ private set
+ {
+ _state = value;
+
+ Logger.Debug($"Session state was set to {_state}.");
+ }
+ }
+
///
/// Gets the of the .
///
@@ -114,34 +132,62 @@ internal Session(ILoginProvider loginProvider, AccessToken accessToken, GeoCoord
public async Task StartupAsync()
{
+ if (State != SessionState.Stopped)
+ {
+ throw new SessionStateException("The session has already been started.");
+ }
+
if (!Configuration.IgnoreHashVersion)
{
await CheckHasherVersion();
}
- if (!await RpcClient.StartupAsync().ConfigureAwait(false))
+ State = SessionState.Started;
+
+ if (!await RpcClient.StartupAsync())
{
return false;
}
- await _heartbeat.StartDispatcher().ConfigureAwait(false);
+ await _heartbeat.StartDispatcherAsync();
return true;
}
public void Pause()
{
- _heartbeat.PauseDispatcher();
+ if (State != SessionState.Started &&
+ State != SessionState.Resumed)
+ {
+ throw new SessionStateException("The session is not running.");
+ }
+
+ State = SessionState.Paused;
+
+ _heartbeat.StopDispatcher();
}
- public void Resume()
+ public async Task ResumeAsync()
{
- RpcClient.ResetLastTimestampSinceStart();
- _heartbeat.ResumeDispatcher();
+ if (State != SessionState.Paused)
+ {
+ throw new SessionStateException("The session is not paused.");
+ }
+
+ State = SessionState.Resumed;
+
+ await _heartbeat.StartDispatcherAsync();
}
public void Shutdown()
{
+ if (State == SessionState.Stopped)
+ {
+ throw new SessionStateException("The session has already been stopped.");
+ }
+
+ State = SessionState.Stopped;
+
_heartbeat.StopDispatcher();
}
@@ -158,7 +204,7 @@ public async Task CheckHasherVersion()
var pogoVersion = new Version(pogoVersionRaw);
var result = Configuration.Hasher.PokemonVersion.CompareTo(pogoVersion);
- if (result != 0)
+ if (result < 0)
{
throw new HashVersionMismatchException($"The version of the {nameof(Configuration.Hasher)} ({Configuration.Hasher.PokemonVersion}) does not match the minimal API version of PokemonGo ({pogoVersion}).");
}
@@ -188,7 +234,7 @@ internal async Task Reauthenticate()
{
if (accessToken == null)
{
- var sleepSeconds = Math.Min(60, ++tries * 5);
+ var sleepSeconds = Math.Min(60, ++tries*5);
Logger.Error($"Reauthentication failed, trying again in {sleepSeconds} seconds.");
await Task.Delay(TimeSpan.FromMilliseconds(sleepSeconds * 1000));
}
@@ -200,17 +246,43 @@ internal async Task Reauthenticate()
ReauthenticateMutex.Release();
}
+ #region Events
private void OnAccessTokenUpdated()
{
AccessTokenUpdated?.Invoke(this, EventArgs.Empty);
}
+ internal void OnInventoryUpdate()
+ {
+ InventoryUpdate?.Invoke(this, EventArgs.Empty);
+ }
+
+ internal void OnMapUpdate()
+ {
+ MapUpdate?.Invoke(this, EventArgs.Empty);
+ }
+
+ internal void OnCaptchaReceived(string url)
+ {
+ CaptchaReceived?.Invoke(this, new CaptchaEventArgs(url));
+ }
+
public event EventHandler AccessTokenUpdated;
+ public event EventHandler InventoryUpdate;
+
+ public event EventHandler MapUpdate;
+
+ ///
+ /// If you have successfully solved the captcha using VerifyChallegenge,
+ /// you can resume POGOLib by using .
+ ///
+ public event EventHandler CaptchaReceived;
+ #endregion
+
public void Dispose()
{
Dispose(true);
- GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
diff --git a/POGOLib.Official/Net/SessionState.cs b/POGOLib.Official/Net/SessionState.cs
new file mode 100644
index 000000000..003b1e466
--- /dev/null
+++ b/POGOLib.Official/Net/SessionState.cs
@@ -0,0 +1,10 @@
+namespace POGOLib.Official.Net
+{
+ public enum SessionState
+ {
+ Started,
+ Stopped,
+ Paused,
+ Resumed
+ }
+}
diff --git a/POGOLib.Official/POGOLib.Official.csproj b/POGOLib.Official/POGOLib.Official.csproj
index ab55383e1..804b184f5 100644
--- a/POGOLib.Official/POGOLib.Official.csproj
+++ b/POGOLib.Official/POGOLib.Official.csproj
@@ -40,6 +40,7 @@
+
@@ -50,13 +51,16 @@
+
+
+
@@ -65,6 +69,7 @@
+
diff --git a/POGOLib.Official/Pokemon/HeartbeatDispatcher.cs b/POGOLib.Official/Pokemon/HeartbeatDispatcher.cs
index 4d247b76d..167745f83 100644
--- a/POGOLib.Official/Pokemon/HeartbeatDispatcher.cs
+++ b/POGOLib.Official/Pokemon/HeartbeatDispatcher.cs
@@ -1,10 +1,8 @@
-using POGOLib.Official.Logging;
-using POGOLib.Official.Net;
-using System;
-using System.Collections.Generic;
-using System.Linq;
+using System;
using System.Threading;
using System.Threading.Tasks;
+using POGOLib.Official.Logging;
+using POGOLib.Official.Net;
namespace POGOLib.Official.Pokemon
{
@@ -23,8 +21,6 @@ internal class HeartbeatDispatcher
private Task _heartbeatTask;
- private bool _isActive;
-
internal HeartbeatDispatcher(Session session)
{
_session = session;
@@ -35,7 +31,7 @@ internal HeartbeatDispatcher(Session session)
///
private async Task CheckDispatch(TaskCompletionSource firstRefreshCompleted)
{
- while (!_heartbeatCancellation.IsCancellationRequested)
+ while (!_heartbeatCancellation.IsCancellationRequested && (_session.State == SessionState.Started || _session.State == SessionState.Resumed))
{
var canRefresh = false;
if (_session.GlobalSettings != null)
@@ -93,21 +89,22 @@ private async Task CheckDispatch(TaskCompletionSource firstRefreshComplete
// cancelled
catch (OperationCanceledException)
{
- return;
+ break;
}
}
+
+ Logger.Debug("Heartbeat got cancelled");
}
- internal async Task StartDispatcher()
+ internal async Task StartDispatcherAsync()
{
if (_heartbeatTask != null)
{
throw new Exception("Heartbeat task already running");
}
+
var firstRefreshCompleted = new TaskCompletionSource();
_heartbeatCancellation = new CancellationTokenSource();
-
- _isActive = true;
_heartbeatTask = CheckDispatch(firstRefreshCompleted);
// wait for first heartbeat to complete
@@ -116,26 +113,13 @@ internal async Task StartDispatcher()
internal void StopDispatcher()
{
- _isActive = false;
-
_heartbeatCancellation?.Cancel();
_heartbeatTask = null;
}
- internal void PauseDispatcher()
- {
- //_isActive = false;
- }
-
- internal void ResumeDispatcher()
- {
- _isActive = true;
- }
-
private async Task Dispatch()
{
- if (_isActive)
- await _session.RpcClient.RefreshMapObjectsAsync();
+ await _session.RpcClient.RefreshMapObjectsAsync();
}
}
}
\ No newline at end of file
diff --git a/POGOLib.Official/Pokemon/Inventory.cs b/POGOLib.Official/Pokemon/Inventory.cs
index 5ebce7c6c..700962af4 100644
--- a/POGOLib.Official/Pokemon/Inventory.cs
+++ b/POGOLib.Official/Pokemon/Inventory.cs
@@ -1,9 +1,8 @@
-using Google.Protobuf.Collections;
-using POGOProtos.Inventory;
-using System;
-using System.Collections.Generic;
+using System.Collections.Generic;
using System.Linq;
-using System.Threading.Tasks;
+using Google.Protobuf.Collections;
+using POGOLib.Official.Net;
+using POGOProtos.Inventory;
namespace POGOLib.Official.Pokemon
{
@@ -12,8 +11,15 @@ namespace POGOLib.Official.Pokemon
///
public class Inventory
{
+ private readonly Session _session;
+
internal long LastInventoryTimestampMs;
+ public Inventory(Session session)
+ {
+ _session = session;
+ }
+
///
/// Gets the last received from PokémonGo.
/// Only use this if you know what you are doing.
@@ -26,7 +32,8 @@ internal void RemoveInventoryItems(IEnumerable items)
{
InventoryItems.Remove(item);
}
- Update?.Invoke(this, EventArgs.Empty);
+
+ _session.OnInventoryUpdate();
}
internal void UpdateInventoryItems(InventoryDelta delta)
@@ -129,9 +136,8 @@ internal void UpdateInventoryItems(InventoryDelta delta)
InventoryItems.Remove(oldItem);
}
}
- Update?.Invoke(this, EventArgs.Empty);
- }
- public event EventHandler Update;
+ _session.OnInventoryUpdate();
+ }
}
}
\ No newline at end of file
diff --git a/POGOLib.Official/Pokemon/Map.cs b/POGOLib.Official/Pokemon/Map.cs
index ffc5e7a6b..ccf663572 100644
--- a/POGOLib.Official/Pokemon/Map.cs
+++ b/POGOLib.Official/Pokemon/Map.cs
@@ -1,12 +1,11 @@
-using GeoCoordinatePortable;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using GeoCoordinatePortable;
using Google.Protobuf.Collections;
using POGOLib.Official.Net;
using POGOProtos.Map;
using POGOProtos.Map.Fort;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
namespace POGOLib.Official.Pokemon
{
@@ -40,7 +39,7 @@ public RepeatedField Cells
internal set
{
_cells = value;
- Update?.Invoke(this, EventArgs.Empty);
+ _session.OnMapUpdate();
}
}
@@ -65,7 +64,5 @@ public List GetFortsSortedByDistance(Func filter = nul
return sorted;
}
-
- public event EventHandler Update;
}
}
\ No newline at end of file
diff --git a/POGOLib.Official/Pokemon/Player.cs b/POGOLib.Official/Pokemon/Player.cs
index fc26f332c..3a9f500b4 100644
--- a/POGOLib.Official/Pokemon/Player.cs
+++ b/POGOLib.Official/Pokemon/Player.cs
@@ -1,20 +1,19 @@
-using GeoCoordinatePortable;
+using System;
+using System.Linq;
+using GeoCoordinatePortable;
+using POGOLib.Official.Net;
using POGOProtos.Data;
using POGOProtos.Data.Player;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
namespace POGOLib.Official.Pokemon
{
public class Player
{
- internal Player(GeoCoordinate coordinate)
+ internal Player(Session session, GeoCoordinate coordinate)
{
Coordinate = coordinate;
- Inventory = new Inventory();
- Inventory.Update += InventoryOnUpdate;
+ Inventory = new Inventory(session);
+ session.InventoryUpdate += InventoryOnUpdate;
}
///
@@ -42,8 +41,8 @@ internal Player(GeoCoordinate coordinate)
/// Gets the of the beautiful object by PokémonGo.
///
public PlayerStats Stats { get; private set; }
-
- public PlayerData Data { get; set; }
+
+ public PlayerData Data { get; set; }
///
/// Sets the of the .
@@ -55,7 +54,7 @@ public void SetCoordinates(double latitude, double longitude, double altitude =
{
Coordinate = new GeoCoordinate(latitude, longitude, altitude);
}
-
+
///
/// Sets the of the .
///
diff --git a/POGOLib.Official/Pokemon/Templates.cs b/POGOLib.Official/Pokemon/Templates.cs
new file mode 100644
index 000000000..bdf36a039
--- /dev/null
+++ b/POGOLib.Official/Pokemon/Templates.cs
@@ -0,0 +1,70 @@
+namespace POGOLib.Official.Pokemon
+{
+ /*
+ public class Templates
+ {
+ private GetAssetDigestResponse _assetDigestResponse;
+ private DownloadItemTemplatesResponse _itemTemplatesResponse;
+
+ public Templates(IDataCache templateDataCache)
+ {
+ _templateDataCache = templateDataCache;
+ _assetDigestResponse = LoadAssetDigest();
+ _itemTemplatesResponse = LoadItemTemplates();
+ }
+
+ public RepeatedField AssetDigests => _assetDigestResponse?.Digest;
+
+ public RepeatedField ItemTemplates
+ => _itemTemplatesResponse?.ItemTemplates;
+
+ public string AssetDigestFile => "templates.asset-digests.dat";
+
+ public string ItemTemplatesFile => "templates.items.dat";
+
+ public void SetAssetDigests(GetAssetDigestResponse assetDigestResponse)
+ {
+ if (_assetDigestResponse == null || assetDigestResponse.TimestampMs > _assetDigestResponse.TimestampMs)
+ {
+ _assetDigestResponse = assetDigestResponse;
+ _templateDataCache.SaveTemplateDate(AssetDigestFile, _assetDigestResponse.ToByteString().ToByteArray());
+ }
+ }
+
+ public void SetItemTemplates(DownloadItemTemplatesResponse itemTemplatesResponse)
+ {
+ if (_itemTemplatesResponse == null || itemTemplatesResponse.TimestampMs > _itemTemplatesResponse.TimestampMs)
+ {
+ _itemTemplatesResponse = itemTemplatesResponse;
+ _templateDataCache.SaveTemplateDate(ItemTemplatesFile, _itemTemplatesResponse.ToByteString().ToByteArray());
+ }
+ }
+
+ private GetAssetDigestResponse LoadAssetDigest()
+ {
+ if (_templateDataCache.HasTemplateData(AssetDigestFile))
+ {
+ var bytes = _templateDataCache.GetTemplateDataCache(AssetDigestFile);
+ if (bytes?.Any() ?? false)
+ {
+ return GetAssetDigestResponse.Parser.ParseFrom(bytes);
+ }
+ }
+ return null;
+ }
+
+ private DownloadItemTemplatesResponse LoadItemTemplates()
+ {
+ if (_templateDataCache.HasTemplateData(ItemTemplatesFile))
+ {
+ var bytes = _templateDataCache.GetTemplateDataCache(ItemTemplatesFile);
+ if (bytes?.Any() ?? false)
+ {
+ return DownloadItemTemplatesResponse.Parser.ParseFrom(bytes);
+ }
+ }
+ return null;
+ }
+
+ }*/
+}
\ No newline at end of file
diff --git a/POGOLib.Official/Properties/AssemblyInfo.cs b/POGOLib.Official/Properties/AssemblyInfo.cs
index ca8831978..e4c1bed18 100644
--- a/POGOLib.Official/Properties/AssemblyInfo.cs
+++ b/POGOLib.Official/Properties/AssemblyInfo.cs
@@ -26,5 +26,5 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: AssemblyVersion("1.4.0.0")]
+[assembly: AssemblyFileVersion("1.4.0.0")]
diff --git a/POGOLib.Official/Util/Data/IDataCache.cs b/POGOLib.Official/Util/Data/IDataCache.cs
index 8f343e1d4..5f29bcbed 100644
--- a/POGOLib.Official/Util/Data/IDataCache.cs
+++ b/POGOLib.Official/Util/Data/IDataCache.cs
@@ -1,9 +1,5 @@
using Google.Protobuf;
using POGOProtos.Networking.Responses;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
namespace POGOLib.Official.Util.Data
{
diff --git a/POGOLib.Official/Util/Data/MemoryDataCache.cs b/POGOLib.Official/Util/Data/MemoryDataCache.cs
index d1ae07d0b..5ed76def1 100644
--- a/POGOLib.Official/Util/Data/MemoryDataCache.cs
+++ b/POGOLib.Official/Util/Data/MemoryDataCache.cs
@@ -1,8 +1,5 @@
-using Google.Protobuf;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
+using System.Collections.Generic;
+using Google.Protobuf;
namespace POGOLib.Official.Util.Data
{
diff --git a/POGOLib.Official/Util/Device/DeviceInfoUtil.cs b/POGOLib.Official/Util/Device/DeviceInfoUtil.cs
index 53f9dd64e..3eabee246 100644
--- a/POGOLib.Official/Util/Device/DeviceInfoUtil.cs
+++ b/POGOLib.Official/Util/Device/DeviceInfoUtil.cs
@@ -1,9 +1,5 @@
using POGOLib.Official.Extensions;
using POGOLib.Official.Net;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
using static POGOProtos.Networking.Envelopes.Signature.Types;
namespace POGOLib.Official.Util.Device
diff --git a/POGOLib.Official/Util/Encryption/Legacy/NiaHashLegacy.cs b/POGOLib.Official/Util/Encryption/Legacy/NiaHashLegacy.cs
index 74bdf9130..3bf076312 100644
--- a/POGOLib.Official/Util/Encryption/Legacy/NiaHashLegacy.cs
+++ b/POGOLib.Official/Util/Encryption/Legacy/NiaHashLegacy.cs
@@ -1,10 +1,7 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
namespace POGOLib.Official.Util.Encryption.Legacy
-{
+{
///
/// This is the legacy NiaHash used by POGOLib.
///
@@ -81,12 +78,12 @@ private static ulong Hash(byte[] input)
// copy tail, pad with zeroes
var tail = new byte[128];
var tailSize = len % 128;
- Buffer.BlockCopy(input, (int)(len - tailSize), tail, 0, (int)tailSize);
+ Buffer.BlockCopy(input, (int) (len - tailSize), tail, 0, (int) tailSize);
UInt128 hash;
- hash = numChunks != 0
- ? hash_chunk(input, 128, 0)
+ hash = numChunks != 0
+ ? hash_chunk(input, 128, 0)
: hash_chunk(tail, tailSize, 0);
hash += RoundMagic;
diff --git a/POGOLib.Official/Util/Encryption/Legacy/PCryptLegacy.cs b/POGOLib.Official/Util/Encryption/Legacy/PCryptLegacy.cs
index 1449a5566..ffcd8ec8a 100644
--- a/POGOLib.Official/Util/Encryption/Legacy/PCryptLegacy.cs
+++ b/POGOLib.Official/Util/Encryption/Legacy/PCryptLegacy.cs
@@ -1,8 +1,6 @@
using System;
-using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
-using System.Threading.Tasks;
namespace POGOLib.Official.Util.Encryption.Legacy
{
diff --git a/POGOLib.Official/Util/Encryption/Legacy/ShufflesLegacy.cs b/POGOLib.Official/Util/Encryption/Legacy/ShufflesLegacy.cs
index 082e6ac79..0ac442527 100644
--- a/POGOLib.Official/Util/Encryption/Legacy/ShufflesLegacy.cs
+++ b/POGOLib.Official/Util/Encryption/Legacy/ShufflesLegacy.cs
@@ -1,7 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
+using POGOLib.Official.Util.Hash;
namespace POGOLib.Official.Util.Encryption.Legacy
{
diff --git a/POGOLib.Official/Util/Encryption/PokeHash/PCryptPokeHash.cs b/POGOLib.Official/Util/Encryption/PokeHash/PCryptPokeHash.cs
index 73b0a5384..d55d7f1e7 100644
--- a/POGOLib.Official/Util/Encryption/PokeHash/PCryptPokeHash.cs
+++ b/POGOLib.Official/Util/Encryption/PokeHash/PCryptPokeHash.cs
@@ -1,224 +1,102 @@
-using POGOLib.Official.Util.Encryption.Legacy;
-using System;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Linq;
-using System.Threading.Tasks;
+using System;
namespace POGOLib.Official.Util.Encryption.PokeHash
{
///
/// This is the PCrypt used by POGOLib. It should always match the used PokeHash version.
///
- /// Android version: 0.51.0
- /// IOS version: 1.21.0
+ /// Android version: 0.59.1
+ /// IOS version: 1.29.1
///
internal static class PCryptPokeHash
{
- private static byte Rot18(byte val, int bits)
- {
- return (byte)(((val << bits) | (val >> (8 - bits))) & 0xff);
- }
-
- private static byte GenerateRand(ref uint rand)
- {
- rand = rand * 0x41c64e6d + 12345;
- return (byte)((rand >> 16) & 0xff);
- }
-
- private static byte[] Cipher8FromIv(byte[] iv)
- {
- var ret = new byte[256];
- for (var i = 0; i < 8; i++)
- {
- for (var j = 0; j < 32; j++)
- {
- ret[32 * i * j] = Rot18(iv[j], i);
- }
- }
- return ret;
- }
-
- private static byte[] Cipher8FromRand(ref uint rand)
- {
- var ret = new byte[256];
- for (var i = 0; i < 256; i++)
- {
- ret[i] = GenerateRand(ref rand);
- }
- return ret;
- }
-
- private static byte MakeIntegrityByte(byte b)
- {
- return (byte)(b & 0xe3 | 0x10);
- }
-
- public static byte[] Encrypt(byte[] input, uint ms)
- {
- var ct = new CipherText(input, ms);
- var iv = Cipher8FromRand(ref ms);
-
- //encrypt
- foreach (var bytes in ct.Content)
- {
- for (var j = 0; j < 256; j++)
- {
- bytes[j] ^= iv[j];
- }
-
- var temp2 = new uint[0x100 / 4];
- Buffer.BlockCopy(bytes, 0, temp2, 0, 0x100);
- ShufflesLegacy.Shuffle2(temp2);
-
- Buffer.BlockCopy(temp2, 0, iv, 0, 0x100);
- Buffer.BlockCopy(temp2, 0, bytes, 0, 0x100);
- }
-
- return ct.GetBytes(ref ms);
- }
-
- //this returns an empty buffer if error
- public static byte[] Decrypt(byte[] input, out int length)
- {
- int version, len = input.Length;
- if (len < 261)
- {
- length = 0;
- return new byte[] { };
- }
-
- var modSize = len % 256;
- switch (modSize)
- {
- case 32:
- version = 1;
- break;
- case 33:
- version = 2;
- break;
- case 5:
- version = 3;
- break;
- default:
- length = 0; return new byte[] { };
- }
-
- byte[] cipher8, output;
- int outputLen;
- switch (version)
- {
- case 1:
- outputLen = len - 32;
- output = new byte[outputLen];
- Buffer.BlockCopy(input, 32, output, 0, outputLen);
- cipher8 = Cipher8FromIv(input);
- break;
- case 2:
- outputLen = len - 33;
- output = new byte[outputLen];
- Buffer.BlockCopy(input, 32, output, 0, outputLen);
- cipher8 = Cipher8FromIv(input);
- break;
- default:
- outputLen = len - 5;
- output = new byte[outputLen];
- Buffer.BlockCopy(input, 4, output, 0, outputLen);
- var tmp = new byte[4];
- Buffer.BlockCopy(input, 0, tmp, 0, 4);
- Array.Reverse(tmp);
- var ms = BitConverter.ToUInt32(tmp, 0);
- cipher8 = Cipher8FromRand(ref ms);
- if (input[len - 1] != MakeIntegrityByte(GenerateRand(ref ms))) { length = 0; return new byte[] { }; }
- break;
- }
-
- var outputcontent = new Collection();
-
- //break into chunks of 256
- var roundedsize = (outputLen + 255) / 256; //round up
- for (var i = 0; i < roundedsize; i++)
- outputcontent.Add(new byte[256]);
- for (var i = 0; i < outputLen; i++)
- outputcontent[i / 256][i % 256] = output[i];
-
- foreach (var bytes in outputcontent)
- {
- var temp2 = new uint[0x100 / 4];
- var temp3 = new uint[0x100 / 4];
- Buffer.BlockCopy(bytes, 0, temp2, 0, 0x100);
- Buffer.BlockCopy(temp2, 0, temp3, 0, 0x100);
-
- if (version == 1)
- ShufflesLegacy.Unshuffle(temp2);
- else
- ShufflesLegacy.Unshuffle2(temp2);
-
- Buffer.BlockCopy(temp2, 0, bytes, 0, 0x100);
- for (var j = 0; j < 256; j++)
- {
- bytes[j] ^= cipher8[j];
- }
- Buffer.BlockCopy(temp3, 0, cipher8, 0, 0x100);
- }
-
- var ret = new byte[outputLen];
- for (var i = 0; i < outputcontent.Count; i++)
- {
- Buffer.BlockCopy(outputcontent[i], 0, ret, i * 256, 0x100);
- }
- length = outputLen - ret.Last();
- return ret;
- }
-
- private class CipherText
- {
- private readonly byte[] _prefix;
- private readonly int _totalsize;
-
- public readonly Collection Content;
-
- private static byte[] IntToBytes(int x)
- {
- return BitConverter.GetBytes(x);
- }
-
- public CipherText(byte[] input, uint ms)
- {
- var inputlen = input.Length;
- _prefix = new byte[32];
-
- //allocate blocks of 256 bytes
- Content = new Collection();
- var roundedsize = inputlen + (256 - (inputlen % 256));
- for (var i = 0; i < roundedsize / 256; i++)
- Content.Add(new byte[256]);
- _totalsize = roundedsize + 5;
-
- //first 32 bytes, pcrypt.c:68
- _prefix = IntToBytes((int)ms);
- Array.Reverse(_prefix);
-
- //split input into 256
- for (var i = 0; i < inputlen; i++) Content[i / 256][i % 256] = input[i];
-
- //pcrypt.c:75
- Content.Last()[Content.Last().Length - 1] = (byte)(256 - (input.Length % 256));
- }
-
- public byte[] GetBytes(ref uint ms)
- {
- var ret = new byte[_totalsize];
- Buffer.BlockCopy(_prefix, 0, ret, 0, _prefix.Length);
- var offset = _prefix.Length;
- foreach (var bytes in Content)
- {
- Buffer.BlockCopy(bytes, 0, ret, offset, bytes.Length);
- offset += bytes.Length;
- }
- ret[ret.Length - 1] = MakeIntegrityByte(GenerateRand(ref ms));
- return ret;
- }
- }
+ public static byte[] KEY = new byte[]
+ {
+ (byte) 0x4F, (byte) 0xEB, (byte) 0x1C, (byte) 0xA5, (byte) 0xF6, (byte) 0x1A, (byte) 0x67, (byte) 0xCE,
+ (byte) 0x43, (byte) 0xF3, (byte) 0xF0, (byte) 0x0C, (byte) 0xB1, (byte) 0x23, (byte) 0x88, (byte) 0x35,
+ (byte) 0xE9, (byte) 0x8B, (byte) 0xE8, (byte) 0x39, (byte) 0xD8, (byte) 0x89, (byte) 0x8F, (byte) 0x5A,
+ (byte) 0x3B, (byte) 0x51, (byte) 0x2E, (byte) 0xA9, (byte) 0x47, (byte) 0x38, (byte) 0xC4, (byte) 0x14
+ };
+
+ public static object _twoFish { get; private set; }
+
+ public static byte[] MakeIv(Rand rand)
+ {
+ byte[] iv = new byte[TwoFish.BLOCK_SIZE];
+ for (int i = 0; i < iv.Length; i++)
+ {
+ iv[i] = rand.Next();
+ }
+ return iv;
+ }
+
+ public static byte MakeIntegrityByte(Rand rand)
+ {
+ return 0x21;
+ }
+
+ /**
+ * Encrypts the given signature
+ *
+ * @param input input data
+ * @param msSinceStart time since start
+ * @return encrypted signature
+ */
+ public static byte[] Encrypt(byte[] input, uint msSinceStart)
+ {
+ try
+ {
+ object[] key = TwoFish.MakeKey(KEY);
+
+ Rand rand = new Rand(msSinceStart);
+ byte[] iv = MakeIv(rand);
+ int blockCount = (input.Length + 256) / 256;
+ int outputSize = (blockCount * 256) + 5;
+ byte[] output = new byte[outputSize];
+
+ output[0] = (byte)(msSinceStart >> 24);
+ output[1] = (byte)(msSinceStart >> 16);
+ output[2] = (byte)(msSinceStart >> 8);
+ output[3] = (byte)msSinceStart;
+
+ Array.Copy(input, 0, output, 4, input.Length);
+ output[outputSize - 2] = (byte)(256 - input.Length % 256);
+
+ for (int offset = 0; offset < blockCount * 256; offset += TwoFish.BLOCK_SIZE)
+ {
+ for (int i = 0; i < TwoFish.BLOCK_SIZE; i++)
+ {
+ output[4 + offset + i] ^= iv[i];
+ }
+
+ byte[] block = TwoFish.blockEncrypt(output, offset + 4, key);
+ Array.Copy(block, 0, output, offset + 4, block.Length);
+ Array.Copy(output, 4 + offset, iv, 0, TwoFish.BLOCK_SIZE);
+ }
+
+ output[outputSize - 1] = MakeIntegrityByte(rand);
+ return output;
+ }
+ catch (Exception)
+ {
+ return null;
+ }
+ }
+
+ public class Rand
+ {
+ private long state;
+
+ public Rand(long state)
+ {
+ this.state = state;
+ }
+
+ public byte Next()
+ {
+ state = (state * 0x41C64E6D) + 0x3039;
+ return (byte)((state >> 16) & 0xFF);
+ }
+ }
}
}
diff --git a/POGOLib.Official/Util/Encryption/PokeHash/TwoFish.cs b/POGOLib.Official/Util/Encryption/PokeHash/TwoFish.cs
new file mode 100644
index 000000000..9d1086153
--- /dev/null
+++ b/POGOLib.Official/Util/Encryption/PokeHash/TwoFish.cs
@@ -0,0 +1,603 @@
+using System;
+
+namespace POGOLib.Official.Util.Encryption.PokeHash
+{
+ public static class TwoFish
+ {
+ public static int BLOCK_SIZE = 16;
+ private static int ROUNDS = 16;
+
+ private static int INPUT_WHITEN = 0;
+ private static int OUTPUT_WHITEN = INPUT_WHITEN + BLOCK_SIZE / 4;
+ private static int ROUND_SUBKEYS = OUTPUT_WHITEN + BLOCK_SIZE / 4;
+
+ private static int SK_STEP = 0x02020202;
+ private static int SK_BUMP = 0x01010101;
+ private static int SK_ROTL = 9;
+
+ /**
+ * Fixed 8x8 permutation S-boxes
+ */
+ private static byte[][] P = new byte[2][]
+ {
+ new byte[256]{
+ (byte) 0xA9, (byte) 0x67, (byte) 0xB3, (byte) 0xE8,
+ (byte) 0x04, (byte) 0xFD, (byte) 0xA3, (byte) 0x76,
+ (byte) 0x9A, (byte) 0x92, (byte) 0x80, (byte) 0x78,
+ (byte) 0xE4, (byte) 0xDD, (byte) 0xD1, (byte) 0x38,
+ (byte) 0x0D, (byte) 0xC6, (byte) 0x35, (byte) 0x98,
+ (byte) 0x18, (byte) 0xF7, (byte) 0xEC, (byte) 0x6C,
+ (byte) 0x43, (byte) 0x75, (byte) 0x37, (byte) 0x26,
+ (byte) 0xFA, (byte) 0x13, (byte) 0x94, (byte) 0x48,
+ (byte) 0xF2, (byte) 0xD0, (byte) 0x8B, (byte) 0x30,
+ (byte) 0x84, (byte) 0x54, (byte) 0xDF, (byte) 0x23,
+ (byte) 0x19, (byte) 0x5B, (byte) 0x3D, (byte) 0x59,
+ (byte) 0xF3, (byte) 0xAE, (byte) 0xA2, (byte) 0x82,
+ (byte) 0x63, (byte) 0x01, (byte) 0x83, (byte) 0x2E,
+ (byte) 0xD9, (byte) 0x51, (byte) 0x9B, (byte) 0x7C,
+ (byte) 0xA6, (byte) 0xEB, (byte) 0xA5, (byte) 0xBE,
+ (byte) 0x16, (byte) 0x0C, (byte) 0xE3, (byte) 0x61,
+ (byte) 0xC0, (byte) 0x8C, (byte) 0x3A, (byte) 0xF5,
+ (byte) 0x73, (byte) 0x2C, (byte) 0x25, (byte) 0x0B,
+ (byte) 0xBB, (byte) 0x4E, (byte) 0x89, (byte) 0x6B,
+ (byte) 0x53, (byte) 0x6A, (byte) 0xB4, (byte) 0xF1,
+ (byte) 0xE1, (byte) 0xE6, (byte) 0xBD, (byte) 0x45,
+ (byte) 0xE2, (byte) 0xF4, (byte) 0xB6, (byte) 0x66,
+ (byte) 0xCC, (byte) 0x95, (byte) 0x03, (byte) 0x56,
+ (byte) 0xD4, (byte) 0x1C, (byte) 0x1E, (byte) 0xD7,
+ (byte) 0xFB, (byte) 0xC3, (byte) 0x8E, (byte) 0xB5,
+ (byte) 0xE9, (byte) 0xCF, (byte) 0xBF, (byte) 0xBA,
+ (byte) 0xEA, (byte) 0x77, (byte) 0x39, (byte) 0xAF,
+ (byte) 0x33, (byte) 0xC9, (byte) 0x62, (byte) 0x71,
+ (byte) 0x81, (byte) 0x79, (byte) 0x09, (byte) 0xAD,
+ (byte) 0x24, (byte) 0xCD, (byte) 0xF9, (byte) 0xD8,
+ (byte) 0xE5, (byte) 0xC5, (byte) 0xB9, (byte) 0x4D,
+ (byte) 0x44, (byte) 0x08, (byte) 0x86, (byte) 0xE7,
+ (byte) 0xA1, (byte) 0x1D, (byte) 0xAA, (byte) 0xED,
+ (byte) 0x06, (byte) 0x70, (byte) 0xB2, (byte) 0xD2,
+ (byte) 0x41, (byte) 0x7B, (byte) 0xA0, (byte) 0x11,
+ (byte) 0x31, (byte) 0xC2, (byte) 0x27, (byte) 0x90,
+ (byte) 0x20, (byte) 0xF6, (byte) 0x60, (byte) 0xFF,
+ (byte) 0x96, (byte) 0x5C, (byte) 0xB1, (byte) 0xAB,
+ (byte) 0x9E, (byte) 0x9C, (byte) 0x52, (byte) 0x1B,
+ (byte) 0x5F, (byte) 0x93, (byte) 0x0A, (byte) 0xEF,
+ (byte) 0x91, (byte) 0x85, (byte) 0x49, (byte) 0xEE,
+ (byte) 0x2D, (byte) 0x4F, (byte) 0x8F, (byte) 0x3B,
+ (byte) 0x47, (byte) 0x87, (byte) 0x6D, (byte) 0x46,
+ (byte) 0xD6, (byte) 0x3E, (byte) 0x69, (byte) 0x64,
+ (byte) 0x2A, (byte) 0xCE, (byte) 0xCB, (byte) 0x2F,
+ (byte) 0xFC, (byte) 0x97, (byte) 0x05, (byte) 0x7A,
+ (byte) 0xAC, (byte) 0x7F, (byte) 0xD5, (byte) 0x1A,
+ (byte) 0x4B, (byte) 0x0E, (byte) 0xA7, (byte) 0x5A,
+ (byte) 0x28, (byte) 0x14, (byte) 0x3F, (byte) 0x29,
+ (byte) 0x88, (byte) 0x3C, (byte) 0x4C, (byte) 0x02,
+ (byte) 0xB8, (byte) 0xDA, (byte) 0xB0, (byte) 0x17,
+ (byte) 0x55, (byte) 0x1F, (byte) 0x8A, (byte) 0x7D,
+ (byte) 0x57, (byte) 0xC7, (byte) 0x8D, (byte) 0x74,
+ (byte) 0xB7, (byte) 0xC4, (byte) 0x9F, (byte) 0x72,
+ (byte) 0x7E, (byte) 0x15, (byte) 0x22, (byte) 0x12,
+ (byte) 0x58, (byte) 0x07, (byte) 0x99, (byte) 0x34,
+ (byte) 0x6E, (byte) 0x50, (byte) 0xDE, (byte) 0x68,
+ (byte) 0x65, (byte) 0xBC, (byte) 0xDB, (byte) 0xF8,
+ (byte) 0xC8, (byte) 0xA8, (byte) 0x2B, (byte) 0x40,
+ (byte) 0xDC, (byte) 0xFE, (byte) 0x32, (byte) 0xA4,
+ (byte) 0xCA, (byte) 0x10, (byte) 0x21, (byte) 0xF0,
+ (byte) 0xD3, (byte) 0x5D, (byte) 0x0F, (byte) 0x00,
+ (byte) 0x6F, (byte) 0x9D, (byte) 0x36, (byte) 0x42,
+ (byte) 0x4A, (byte) 0x5E, (byte) 0xC1, (byte) 0xE0
+ },
+ new byte[256] {
+ (byte) 0x75, (byte) 0xF3, (byte) 0xC6, (byte) 0xF4,
+ (byte) 0xDB, (byte) 0x7B, (byte) 0xFB, (byte) 0xC8,
+ (byte) 0x4A, (byte) 0xD3, (byte) 0xE6, (byte) 0x6B,
+ (byte) 0x45, (byte) 0x7D, (byte) 0xE8, (byte) 0x4B,
+ (byte) 0xD6, (byte) 0x32, (byte) 0xD8, (byte) 0xFD,
+ (byte) 0x37, (byte) 0x71, (byte) 0xF1, (byte) 0xE1,
+ (byte) 0x30, (byte) 0x0F, (byte) 0xF8, (byte) 0x1B,
+ (byte) 0x87, (byte) 0xFA, (byte) 0x06, (byte) 0x3F,
+ (byte) 0x5E, (byte) 0xBA, (byte) 0xAE, (byte) 0x5B,
+ (byte) 0x8A, (byte) 0x00, (byte) 0xBC, (byte) 0x9D,
+ (byte) 0x6D, (byte) 0xC1, (byte) 0xB1, (byte) 0x0E,
+ (byte) 0x80, (byte) 0x5D, (byte) 0xD2, (byte) 0xD5,
+ (byte) 0xA0, (byte) 0x84, (byte) 0x07, (byte) 0x14,
+ (byte) 0xB5, (byte) 0x90, (byte) 0x2C, (byte) 0xA3,
+ (byte) 0xB2, (byte) 0x73, (byte) 0x4C, (byte) 0x54,
+ (byte) 0x92, (byte) 0x74, (byte) 0x36, (byte) 0x51,
+ (byte) 0x38, (byte) 0xB0, (byte) 0xBD, (byte) 0x5A,
+ (byte) 0xFC, (byte) 0x60, (byte) 0x62, (byte) 0x96,
+ (byte) 0x6C, (byte) 0x42, (byte) 0xF7, (byte) 0x10,
+ (byte) 0x7C, (byte) 0x28, (byte) 0x27, (byte) 0x8C,
+ (byte) 0x13, (byte) 0x95, (byte) 0x9C, (byte) 0xC7,
+ (byte) 0x24, (byte) 0x46, (byte) 0x3B, (byte) 0x70,
+ (byte) 0xCA, (byte) 0xE3, (byte) 0x85, (byte) 0xCB,
+ (byte) 0x11, (byte) 0xD0, (byte) 0x93, (byte) 0xB8,
+ (byte) 0xA6, (byte) 0x83, (byte) 0x20, (byte) 0xFF,
+ (byte) 0x9F, (byte) 0x77, (byte) 0xC3, (byte) 0xCC,
+ (byte) 0x03, (byte) 0x6F, (byte) 0x08, (byte) 0xBF,
+ (byte) 0x40, (byte) 0xE7, (byte) 0x2B, (byte) 0xE2,
+ (byte) 0x79, (byte) 0x0C, (byte) 0xAA, (byte) 0x82,
+ (byte) 0x41, (byte) 0x3A, (byte) 0xEA, (byte) 0xB9,
+ (byte) 0xE4, (byte) 0x9A, (byte) 0xA4, (byte) 0x97,
+ (byte) 0x7E, (byte) 0xDA, (byte) 0x7A, (byte) 0x17,
+ (byte) 0x66, (byte) 0x94, (byte) 0xA1, (byte) 0x1D,
+ (byte) 0x3D, (byte) 0xF0, (byte) 0xDE, (byte) 0xB3,
+ (byte) 0x0B, (byte) 0x72, (byte) 0xA7, (byte) 0x1C,
+ (byte) 0xEF, (byte) 0xD1, (byte) 0x53, (byte) 0x3E,
+ (byte) 0x8F, (byte) 0x33, (byte) 0x26, (byte) 0x5F,
+ (byte) 0xEC, (byte) 0x76, (byte) 0x2A, (byte) 0x49,
+ (byte) 0x81, (byte) 0x88, (byte) 0xEE, (byte) 0x21,
+ (byte) 0xC4, (byte) 0x1A, (byte) 0xEB, (byte) 0xD9,
+ (byte) 0xC5, (byte) 0x39, (byte) 0x99, (byte) 0xCD,
+ (byte) 0xAD, (byte) 0x31, (byte) 0x8B, (byte) 0x01,
+ (byte) 0x18, (byte) 0x23, (byte) 0xDD, (byte) 0x1F,
+ (byte) 0x4E, (byte) 0x2D, (byte) 0xF9, (byte) 0x48,
+ (byte) 0x4F, (byte) 0xF2, (byte) 0x65, (byte) 0x8E,
+ (byte) 0x78, (byte) 0x5C, (byte) 0x58, (byte) 0x19,
+ (byte) 0x8D, (byte) 0xE5, (byte) 0x98, (byte) 0x57,
+ (byte) 0x67, (byte) 0x7F, (byte) 0x05, (byte) 0x64,
+ (byte) 0xAF, (byte) 0x63, (byte) 0xB6, (byte) 0xFE,
+ (byte) 0xF5, (byte) 0xB7, (byte) 0x3C, (byte) 0xA5,
+ (byte) 0xCE, (byte) 0xE9, (byte) 0x68, (byte) 0x44,
+ (byte) 0xE0, (byte) 0x4D, (byte) 0x43, (byte) 0x69,
+ (byte) 0x29, (byte) 0x2E, (byte) 0xAC, (byte) 0x15,
+ (byte) 0x59, (byte) 0xA8, (byte) 0x0A, (byte) 0x9E,
+ (byte) 0x6E, (byte) 0x47, (byte) 0xDF, (byte) 0x34,
+ (byte) 0x35, (byte) 0x6A, (byte) 0xCF, (byte) 0xDC,
+ (byte) 0x22, (byte) 0xC9, (byte) 0xC0, (byte) 0x9B,
+ (byte) 0x89, (byte) 0xD4, (byte) 0xED, (byte) 0xAB,
+ (byte) 0x12, (byte) 0xA2, (byte) 0x0D, (byte) 0x52,
+ (byte) 0xBB, (byte) 0x02, (byte) 0x2F, (byte) 0xA9,
+ (byte) 0xD7, (byte) 0x61, (byte) 0x1E, (byte) 0xB4,
+ (byte) 0x50, (byte) 0x04, (byte) 0xF6, (byte) 0xC2,
+ (byte) 0x16, (byte) 0x25, (byte) 0x86, (byte) 0x56,
+ (byte) 0x55, (byte) 0x09, (byte) 0xBE, (byte) 0x91
+ }
+ };
+
+ /**
+ * Define the fixed p0/p1 permutations used in keyed S-box lookup.
+ * By changing the following constant definitions, the S-boxes will
+ * automatically get changed in the Twofish engine.
+ */
+ private static int P_00 = 1;
+ private static int P_01 = 0;
+ private static int P_02 = 0;
+ private static int P_03 = P_01 ^ 1;
+ private static int P_04 = 1;
+
+ private static int P_10 = 0;
+ private static int P_11 = 0;
+ private static int P_12 = 1;
+ private static int P_13 = P_11 ^ 1;
+ private static int P_14 = 0;
+
+ private static int P_20 = 1;
+ private static int P_21 = 1;
+ private static int P_22 = 0;
+ private static int P_23 = P_21 ^ 1;
+ private static int P_24 = 0;
+
+ private static int P_30 = 0;
+ private static int P_31 = 1;
+ private static int P_32 = 1;
+ private static int P_33 = P_31 ^ 1;
+ private static int P_34 = 1;
+
+ /**
+ * Primitive polynomial for GF(256)
+ */
+ private static int GF256_FDBK_2 = 0x169 / 2;
+ private static int GF256_FDBK_4 = 0x169 / 4;
+
+ /**
+ * MDS matrix
+ */
+ private static int[][] MDS = new int[4][];
+
+ private static int RS_GF_FDBK = 0x14D;
+
+ static TwoFish()
+ {
+ int[] m1 = new int[2];
+ int[] mxArray = new int[2];
+ int[] myArray = new int[2];
+ int first;
+ int second = 0;
+
+ for (int i = 0; i < MDS.Length; i++)
+ {
+ MDS[i] = new int[256];
+ }
+
+ for (first = 0; first < 256; first++)
+ {
+ second = P[0][first] & 0xFF;
+ m1[0] = second;
+ mxArray[0] = mxX(second) & 0xFF;
+ myArray[0] = mxY(second) & 0xFF;
+
+ second = P[1][first] & 0xFF;
+ m1[1] = second;
+ mxArray[1] = mxX(second) & 0xFF;
+ myArray[1] = mxY(second) & 0xFF;
+
+ MDS[0][first] = m1[P_00]
+ | mxArray[P_00] << 8
+ | myArray[P_00] << 16
+ | myArray[P_00] << 24;
+ MDS[1][first] = myArray[P_10]
+ | myArray[P_10] << 8
+ | mxArray[P_10] << 16
+ | m1[P_10] << 24;
+ MDS[2][first] = mxArray[P_20]
+ | myArray[P_20] << 8
+ | m1[P_20] << 16
+ | myArray[P_20] << 24;
+ MDS[3][first] = mxArray[P_30]
+ | m1[P_30] << 8
+ | myArray[P_30] << 16
+ | mxArray[P_30] << 24;
+ }
+ }
+
+ private static int lfsr1(int x)
+ {
+ return (x >> 1) ^ ((x & 0x01) != 0 ? GF256_FDBK_2 : 0);
+ }
+
+ private static int lfsr2(int x)
+ {
+ return (x >> 2) ^ ((x & 0x02) != 0 ? GF256_FDBK_2 : 0) ^ ((x & 0x01) != 0 ? GF256_FDBK_4 : 0);
+ }
+
+ private static int mxX(int x)
+ {
+ return x ^ lfsr2(x);
+ }
+
+ private static int mxY(int x)
+ {
+ return x ^ lfsr1(x) ^ lfsr2(x);
+ }
+
+ /**
+ * Expand a user-supplied key material into a session key.
+ *
+ * @param k The 64/128/192/256-bit user-key to use.
+ * @return This cipher's round keys.
+ * @throws InvalidKeyException If the key is invalid.
+ */
+ public static object[] MakeKey(byte[] k)
+ {
+ if (k == null)
+ throw new Exception("Empty key");
+ int length = k.Length;
+ if (!(length == 8 || length == 16 || length == 24 || length == 32))
+ throw new Exception("Incorrect key length");
+
+ int k64Cnt = length / 8;
+ int subkeyCnt = ROUND_SUBKEYS + 2 * ROUNDS;
+ int[] k32e = new int[4];
+ int[] k32o = new int[4];
+ int[] sBoxKey = new int[4];
+ int i, j, offset = 0;
+ for (i = 0, j = k64Cnt - 1; i < 4 && offset < length; i++, j--)
+ {
+ k32e[i] = (k[offset++] & 0xFF)
+ | (k[offset++] & 0xFF) << 8
+ | (k[offset++] & 0xFF) << 16
+ | (k[offset++] & 0xFF) << 24;
+ k32o[i] = (k[offset++] & 0xFF)
+ | (k[offset++] & 0xFF) << 8
+ | (k[offset++] & 0xFF) << 16
+ | (k[offset++] & 0xFF) << 24;
+ sBoxKey[j] = rsMdsEncode(k32e[i], k32o[i]);
+ }
+ int q, A, B;
+ int[] subKeys = new int[subkeyCnt];
+ for (i = q = 0; i < subkeyCnt / 2; i++, q += SK_STEP)
+ {
+ A = f32(k64Cnt, q, k32e);
+ B = f32(k64Cnt, q + SK_BUMP, k32o);
+ B = B << 8 | RightUShift(B, 24);
+ A += B;
+ subKeys[2 * i] = A;
+ A += B;
+ subKeys[2 * i + 1] = A << SK_ROTL | RightUShift(A, (32 - SK_ROTL));
+ }
+ int k0 = sBoxKey[0];
+ int k1 = sBoxKey[1];
+ int k2 = sBoxKey[2];
+ int k3 = sBoxKey[3];
+ int b0, b1, b2, b3;
+ int[] sBox = new int[4 * 256];
+ for (i = 0; i < 256; i++)
+ {
+ b0 = b1 = b2 = b3 = i;
+
+ int val = k64Cnt & 3;
+
+ if (val == 1)
+ {
+ sBox[2 * i] = MDS[0][(P[P_01][b0] & 0xFF) ^ _b0(k0)];
+ sBox[2 * i + 1] = MDS[1][(P[P_11][b1] & 0xFF) ^ _b1(k0)];
+ sBox[0x200 + 2 * i] = MDS[2][(P[P_21][b2] & 0xFF) ^ _b2(k0)];
+ sBox[0x200 + 2 * i + 1] = MDS[3][(P[P_31][b3] & 0xFF) ^ _b3(k0)];
+ }
+ switch (k64Cnt & 3)
+ {
+ case 1:
+ sBox[2 * i] = MDS[0][(P[P_01][b0] & 0xFF) ^ _b0(k0)];
+ sBox[2 * i + 1] = MDS[1][(P[P_11][b1] & 0xFF) ^ _b1(k0)];
+ sBox[0x200 + 2 * i] = MDS[2][(P[P_21][b2] & 0xFF) ^ _b2(k0)];
+ sBox[0x200 + 2 * i + 1] = MDS[3][(P[P_31][b3] & 0xFF) ^ _b3(k0)];
+ break;
+ case 0:
+ b0 = (P[P_04][b0] & 0xFF) ^ _b0(k3);
+ b1 = (P[P_14][b1] & 0xFF) ^ _b1(k3);
+ b2 = (P[P_24][b2] & 0xFF) ^ _b2(k3);
+ b3 = (P[P_34][b3] & 0xFF) ^ _b3(k3);
+
+
+ b0 = (P[P_03][b0] & 0xFF) ^ _b0(k2);
+ b1 = (P[P_13][b1] & 0xFF) ^ _b1(k2);
+ b2 = (P[P_23][b2] & 0xFF) ^ _b2(k2);
+ b3 = (P[P_33][b3] & 0xFF) ^ _b3(k2);
+
+
+ sBox[2 * i] = MDS[0][(P[P_01][(P[P_02][b0] & 0xFF) ^ _b0(k1)] & 0xFF) ^ _b0(k0)];
+ sBox[2 * i + 1] = MDS[1][(P[P_11][(P[P_12][b1] & 0xFF) ^ _b1(k1)] & 0xFF) ^ _b1(k0)];
+ sBox[0x200 + 2 * i] = MDS[2][(P[P_21][(P[P_22][b2] & 0xFF) ^ _b2(k1)] & 0xFF) ^ _b2(k0)];
+ sBox[0x200 + 2 * i + 1] = MDS[3][(P[P_31][(P[P_32][b3] & 0xFF) ^ _b3(k1)] & 0xFF) ^ _b3(k0)];
+ break;
+ case 3:
+ b0 = (P[P_03][b0] & 0xFF) ^ _b0(k2);
+ b1 = (P[P_13][b1] & 0xFF) ^ _b1(k2);
+ b2 = (P[P_23][b2] & 0xFF) ^ _b2(k2);
+ b3 = (P[P_33][b3] & 0xFF) ^ _b3(k2);
+
+ sBox[2 * i] = MDS[0][(P[P_01][(P[P_02][b0] & 0xFF) ^ _b0(k1)] & 0xFF) ^ _b0(k0)];
+ sBox[2 * i + 1] = MDS[1][(P[P_11][(P[P_12][b1] & 0xFF) ^ _b1(k1)] & 0xFF) ^ _b1(k0)];
+ sBox[0x200 + 2 * i] = MDS[2][(P[P_21][(P[P_22][b2] & 0xFF) ^ _b2(k1)] & 0xFF) ^ _b2(k0)];
+ sBox[0x200 + 2 * i + 1] = MDS[3][(P[P_31][(P[P_32][b3] & 0xFF) ^ _b3(k1)] & 0xFF) ^ _b3(k0)];
+ break;
+ case 2:
+ sBox[2 * i] = MDS[0][(P[P_01][(P[P_02][b0] & 0xFF) ^ _b0(k1)] & 0xFF) ^ _b0(k0)];
+ sBox[2 * i + 1] = MDS[1][(P[P_11][(P[P_12][b1] & 0xFF) ^ _b1(k1)] & 0xFF) ^ _b1(k0)];
+ sBox[0x200 + 2 * i] = MDS[2][(P[P_21][(P[P_22][b2] & 0xFF) ^ _b2(k1)] & 0xFF) ^ _b2(k0)];
+ sBox[0x200 + 2 * i + 1] = MDS[3][(P[P_31][(P[P_32][b3] & 0xFF) ^ _b3(k1)] & 0xFF) ^ _b3(k0)];
+ break;
+ }
+ }
+ return new object[] { sBox, subKeys };
+ }
+
+ public static int RightUShift(int val, int shift)
+ {
+ return (int)((uint)val >> shift);
+ }
+
+ /**
+ * Encrypt exactly one block of plaintext.
+ *
+ * @param in The plaintext.
+ * @param inOffset Index of in from which to start considering data.
+ * @param sessionKey The session key to use for encryption.
+ * @return The ciphertext generated from a plaintext using the session key.
+ */
+ public static byte[] blockEncrypt(byte[] bArray, int inOffset, Object sessionKey)
+ {
+ Object[] sk = (Object[])sessionKey;
+ int[] sBox = (int[])sk[0];
+ int[] sKey = (int[])sk[1];
+
+ int x0 = (bArray[inOffset++] & 0xFF)
+ | (bArray[inOffset++] & 0xFF) << 8
+ | (bArray[inOffset++] & 0xFF) << 16
+ | (bArray[inOffset++] & 0xFF) << 24;
+ int x1 = (bArray[inOffset++] & 0xFF)
+ | (bArray[inOffset++] & 0xFF) << 8
+ | (bArray[inOffset++] & 0xFF) << 16
+ | (bArray[inOffset++] & 0xFF) << 24;
+ int x2 = (bArray[inOffset++] & 0xFF)
+ | (bArray[inOffset++] & 0xFF) << 8
+ | (bArray[inOffset++] & 0xFF) << 16
+ | (bArray[inOffset++] & 0xFF) << 24;
+ int x3 = (bArray[inOffset++] & 0xFF)
+ | (bArray[inOffset++] & 0xFF) << 8
+ | (bArray[inOffset++] & 0xFF) << 16
+ | (bArray[inOffset++] & 0xFF) << 24;
+
+ x0 ^= sKey[INPUT_WHITEN];
+ x1 ^= sKey[INPUT_WHITEN + 1];
+ x2 ^= sKey[INPUT_WHITEN + 2];
+ x3 ^= sKey[INPUT_WHITEN + 3];
+
+ int t0, t1;
+ int k = ROUND_SUBKEYS;
+ for (int R = 0; R < ROUNDS; R += 2)
+ {
+ t0 = fe32(sBox, x0, 0);
+ t1 = fe32(sBox, x1, 3);
+ x2 ^= t0 + t1 + sKey[k++];
+ x2 = RightUShift(x2, 1) | x2 << 31;
+ x3 = x3 << 1 | RightUShift(x3, 31);
+ x3 ^= t0 + 2 * t1 + sKey[k++];
+
+ t0 = fe32(sBox, x2, 0);
+ t1 = fe32(sBox, x3, 3);
+ x0 ^= t0 + t1 + sKey[k++];
+ x0 = RightUShift(x0, 1) | x0 << 31;
+ x1 = x1 << 1 | RightUShift(x1, 31);
+ x1 ^= t0 + 2 * t1 + sKey[k++];
+ }
+ x2 ^= sKey[OUTPUT_WHITEN];
+ x3 ^= sKey[OUTPUT_WHITEN + 1];
+ x0 ^= sKey[OUTPUT_WHITEN + 2];
+ x1 ^= sKey[OUTPUT_WHITEN + 3];
+
+ return new byte[]{
+ (byte) x2, (byte) RightUShift(x2, 8), (byte) RightUShift(x2, 16), (byte) RightUShift(x2, 24),
+ (byte) x3, (byte) RightUShift(x3, 8), (byte) RightUShift(x3, 16), (byte) RightUShift(x3, 24),
+ (byte) x0, (byte) RightUShift(x0, 8), (byte) RightUShift(x0, 16), (byte) RightUShift(x0, 24),
+ (byte) x1, (byte) RightUShift(x1, 8), (byte) RightUShift(x1, 16), (byte) RightUShift(x1, 24),
+ };
+ }
+
+ private static int _b0(int x) { return x & 0xFF; }
+
+ private static int _b1(int x) { return RightUShift(x, 8) & 0xFF; }
+
+ private static int _b2(int x) { return RightUShift(x, 16) & 0xFF; }
+
+ private static int _b3(int x) { return RightUShift(x, 24) & 0xFF; }
+
+ /**
+ * Use (12, 8) Reed-Solomon code over GF(256) to produce a key S-box
+ * 32-bit entity from two key material 32-bit entities.
+ *
+ * @param k0 1st 32-bit entity.
+ * @param k1 2nd 32-bit entity.
+ * @return Remainder polynomial generated using RS code
+ */
+ private static int rsMdsEncode(int k0, int k1)
+ {
+ int r = k1;
+ for (int i = 0; i < 4; i++)
+ {
+ r = rsRem(r);
+ }
+ r ^= k0;
+ for (int i = 0; i < 4; i++)
+ {
+ r = rsRem(r);
+ }
+ return r;
+ }
+
+ private static int rsRem(int x)
+ {
+ int b = RightUShift(x, 24) & 0xFF;
+ int g2 = ((b << 1) ^ ((b & 0x80) != 0 ? RS_GF_FDBK : 0)) & 0xFF;
+ int g3 = RightUShift(b, 1) ^ ((b & 0x01) != 0 ? RightUShift(RS_GF_FDBK, 1) : 0) ^ g2;
+ int result = (x << 8) ^ (g3 << 24) ^ (g2 << 16) ^ (g3 << 8) ^ b;
+ return result;
+ }
+
+ private static int f32(int k64Cnt, int x, int[] k32)
+ {
+ int b0 = _b0(x);
+ int b1 = _b1(x);
+ int b2 = _b2(x);
+ int b3 = _b3(x);
+ int k0 = k32[0];
+ int k1 = k32[1];
+ int k2 = k32[2];
+ int k3 = k32[3];
+
+ int result = 0;
+ switch (k64Cnt & 3)
+ {
+ case 1:
+ result =
+ MDS[0][(P[P_01][b0] & 0xFF)
+ ^ _b0(k0)]
+ ^ MDS[1][(P[P_11][b1] & 0xFF)
+ ^ _b1(k0)]
+ ^ MDS[2][(P[P_21][b2] & 0xFF)
+ ^ _b2(k0)]
+ ^ MDS[3][(P[P_31][b3] & 0xFF)
+ ^ _b3(k0)];
+ break;
+ case 0:
+ b0 = (P[P_04][b0] & 0xFF) ^ _b0(k3);
+ b1 = (P[P_14][b1] & 0xFF) ^ _b1(k3);
+ b2 = (P[P_24][b2] & 0xFF) ^ _b2(k3);
+ b3 = (P[P_34][b3] & 0xFF) ^ _b3(k3);
+
+
+ b0 = (P[P_03][b0] & 0xFF) ^ _b0(k2);
+ b1 = (P[P_13][b1] & 0xFF) ^ _b1(k2);
+ b2 = (P[P_23][b2] & 0xFF) ^ _b2(k2);
+ b3 = (P[P_33][b3] & 0xFF) ^ _b3(k2);
+
+ result =
+ MDS[0][(P[P_01][(P[P_02][b0] & 0xFF)
+ ^ _b0(k1)] & 0xFF)
+ ^ _b0(k0)]
+ ^ MDS[1][(P[P_11][(P[P_12][b1] & 0xFF)
+ ^ _b1(k1)] & 0xFF) ^ _b1(k0)]
+ ^ MDS[2][(P[P_21][(P[P_22][b2] & 0xFF)
+ ^ _b2(k1)] & 0xFF)
+ ^ _b2(k0)]
+ ^ MDS[3][(P[P_31][(P[P_32][b3] & 0xFF)
+ ^ _b3(k1)] & 0xFF)
+ ^ _b3(k0)];
+ break;
+ case 3:
+ b0 = (P[P_03][b0] & 0xFF) ^ _b0(k2);
+ b1 = (P[P_13][b1] & 0xFF) ^ _b1(k2);
+ b2 = (P[P_23][b2] & 0xFF) ^ _b2(k2);
+ b3 = (P[P_33][b3] & 0xFF) ^ _b3(k2);
+
+ result =
+ MDS[0][(P[P_01][(P[P_02][b0] & 0xFF)
+ ^ _b0(k1)] & 0xFF)
+ ^ _b0(k0)]
+ ^ MDS[1][(P[P_11][(P[P_12][b1] & 0xFF)
+ ^ _b1(k1)] & 0xFF) ^ _b1(k0)]
+ ^ MDS[2][(P[P_21][(P[P_22][b2] & 0xFF)
+ ^ _b2(k1)] & 0xFF)
+ ^ _b2(k0)]
+ ^ MDS[3][(P[P_31][(P[P_32][b3] & 0xFF)
+ ^ _b3(k1)] & 0xFF)
+ ^ _b3(k0)];
+ break;
+ case 2:
+ result =
+ MDS[0][(P[P_01][(P[P_02][b0] & 0xFF)
+ ^ _b0(k1)] & 0xFF)
+ ^ _b0(k0)]
+ ^ MDS[1][(P[P_11][(P[P_12][b1] & 0xFF)
+ ^ _b1(k1)] & 0xFF) ^ _b1(k0)]
+ ^ MDS[2][(P[P_21][(P[P_22][b2] & 0xFF)
+ ^ _b2(k1)] & 0xFF)
+ ^ _b2(k0)]
+ ^ MDS[3][(P[P_31][(P[P_32][b3] & 0xFF)
+ ^ _b3(k1)] & 0xFF)
+ ^ _b3(k0)];
+ break;
+ }
+ return result;
+ }
+
+ private static int fe32(int[] sBox, int x, int r)
+ {
+ return sBox[2 * b(x, r)]
+ ^ sBox[2 * b(x, r + 1) + 1]
+ ^ sBox[0x200 + 2 * b(x, r + 2)]
+ ^ sBox[0x200 + 2 * b(x, r + 3) + 1];
+ }
+
+ private static int b(int x, int n)
+ {
+ int result = 0;
+ switch (n % 4)
+ {
+ case 0:
+ result = _b0(x);
+ break;
+ case 1:
+ result = _b1(x);
+ break;
+ case 2:
+ result = _b2(x);
+ break;
+ case 3:
+ result = _b3(x);
+ break;
+ }
+ return result;
+ }
+ }
+}
\ No newline at end of file
diff --git a/POGOLib.Official/Util/Hash/HashData.cs b/POGOLib.Official/Util/Hash/HashData.cs
index 238b88b11..035aed96b 100644
--- a/POGOLib.Official/Util/Hash/HashData.cs
+++ b/POGOLib.Official/Util/Hash/HashData.cs
@@ -1,10 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace POGOLib.Official.Util.Hash
+namespace POGOLib.Official.Util.Hash
{
public class HashData
{
diff --git a/POGOLib.Official/Util/Hash/HashVersionMismatchException.cs b/POGOLib.Official/Util/Hash/HashVersionMismatchException.cs
index f704e9ce6..8f17ad63c 100644
--- a/POGOLib.Official/Util/Hash/HashVersionMismatchException.cs
+++ b/POGOLib.Official/Util/Hash/HashVersionMismatchException.cs
@@ -1,8 +1,4 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
namespace POGOLib.Official.Util.Hash
{
diff --git a/POGOLib.Official/Util/Hash/IHasher.cs b/POGOLib.Official/Util/Hash/IHasher.cs
index f22bf16eb..5810de98f 100644
--- a/POGOLib.Official/Util/Hash/IHasher.cs
+++ b/POGOLib.Official/Util/Hash/IHasher.cs
@@ -1,9 +1,6 @@
-using POGOProtos.Networking.Envelopes;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
+using System;
using System.Threading.Tasks;
+using POGOProtos.Networking.Envelopes;
namespace POGOLib.Official.Util.Hash
{
diff --git a/POGOLib.Official/Util/Hash/LegacyHasher.cs b/POGOLib.Official/Util/Hash/LegacyHasher.cs
index 9eb156c73..cb5cf9207 100644
--- a/POGOLib.Official/Util/Hash/LegacyHasher.cs
+++ b/POGOLib.Official/Util/Hash/LegacyHasher.cs
@@ -1,10 +1,8 @@
-using POGOLib.Official.Util.Encryption.Legacy;
-using POGOProtos.Networking.Envelopes;
-using System;
-using System.Collections.Generic;
+using System;
using System.Linq;
-using System.Text;
using System.Threading.Tasks;
+using POGOLib.Official.Util.Encryption.Legacy;
+using POGOProtos.Networking.Envelopes;
namespace POGOLib.Official.Util.Hash
{
diff --git a/POGOLib.Official/Util/Hash/PokeHash/PokeHashAuthKey.cs b/POGOLib.Official/Util/Hash/PokeHash/PokeHashAuthKey.cs
index 9262a2d08..15607dd28 100644
--- a/POGOLib.Official/Util/Hash/PokeHash/PokeHashAuthKey.cs
+++ b/POGOLib.Official/Util/Hash/PokeHash/PokeHashAuthKey.cs
@@ -1,7 +1,4 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
namespace POGOLib.Official.Util.Hash.PokeHash
{
diff --git a/POGOLib.Official/Util/Hash/PokeHash/PokeHashRequest.cs b/POGOLib.Official/Util/Hash/PokeHash/PokeHashRequest.cs
index 3a25814d7..ca3629bab 100644
--- a/POGOLib.Official/Util/Hash/PokeHash/PokeHashRequest.cs
+++ b/POGOLib.Official/Util/Hash/PokeHash/PokeHashRequest.cs
@@ -1,7 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
+using System.Collections.Generic;
namespace POGOLib.Official.Util.Hash.PokeHash
{
diff --git a/POGOLib.Official/Util/Hash/PokeHash/PokeHashResponse.cs b/POGOLib.Official/Util/Hash/PokeHash/PokeHashResponse.cs
index 724a200f0..d58097d72 100644
--- a/POGOLib.Official/Util/Hash/PokeHash/PokeHashResponse.cs
+++ b/POGOLib.Official/Util/Hash/PokeHash/PokeHashResponse.cs
@@ -1,7 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
+using System.Collections.Generic;
namespace POGOLib.Official.Util.Hash.PokeHash
{
diff --git a/POGOLib.Official/Util/Hash/PokeHashHasher.cs b/POGOLib.Official/Util/Hash/PokeHashHasher.cs
index 602d9ea5a..c5786e437 100644
--- a/POGOLib.Official/Util/Hash/PokeHashHasher.cs
+++ b/POGOLib.Official/Util/Hash/PokeHashHasher.cs
@@ -21,26 +21,26 @@ namespace POGOLib.Official.Util.Hash
/// to buy an API key, go to this url.
/// https://talk.pogodev.org/d/51-api-hashing-service-by-pokefarmer
///
- /// Android version: 0.51.0
- /// IOS version: 1.21.0
+ /// Android version: 0.59.1
+ /// IOS version: 1.29.1
///
public class PokeHashHasher : IHasher
{
private const string PokeHashUrl = "https://pokehash.buddyauth.com/";
- private const string PokeHashEndpoint = "api/v127_4/hash";
+ private const string PokeHashEndpoint = "api/v129_1/hash";
private readonly List _authKeys;
private readonly HttpClient _httpClient;
private readonly Semaphore _keySelection;
-
+
///
/// Initializes the .
///
/// The PokeHash authkey obtained from https://talk.pogodev.org/d/51-api-hashing-service-by-pokefarmer.
- public PokeHashHasher(string authKey) : this(new[] { authKey })
+ public PokeHashHasher(string authKey) : this(new []{ authKey })
{
}
@@ -55,7 +55,7 @@ public PokeHashHasher(string[] authKeys)
throw new ArgumentException($"{nameof(authKeys)} may not be empty.");
_authKeys = new List();
-
+
// We don't want any duplicate keys.
foreach (var authKey in authKeys)
{
@@ -79,9 +79,9 @@ public PokeHashHasher(string[] authKeys)
_keySelection = new Semaphore(1, 1);
}
- public Version PokemonVersion { get; } = new Version("0.57.4");
+ public Version PokemonVersion { get; } = new Version("0.59.1");
- public long Unknown25 { get; } = -816976800928766045;
+ public long Unknown25 { get; } = -3226782243204485589;
public async Task GetHashDataAsync(RequestEnvelope requestEnvelope, Signature signature, byte[] locationBytes, byte[][] requestsBytes, byte[] serializedTicket)
{
@@ -97,11 +97,11 @@ public async Task GetHashDataAsync(RequestEnvelope requestEnvelope, Si
};
var requestContent = new StringContent(JsonConvert.SerializeObject(requestData), Encoding.UTF8, "application/json");
-
+
using (var response = await PerformRequest(requestContent))
{
var responseContent = await response.Content.ReadAsStringAsync();
-
+
string message;
switch (response.StatusCode)
@@ -114,7 +114,7 @@ public async Task GetHashDataAsync(RequestEnvelope requestEnvelope, Si
LocationAuthHash = responseData.LocationAuthHash,
LocationHash = responseData.LocationHash,
RequestHashes = responseData.RequestHashes
- .Select(x => (ulong)x)
+ .Select(x => (ulong) x)
.ToArray()
};
@@ -125,12 +125,12 @@ public async Task GetHashDataAsync(RequestEnvelope requestEnvelope, Si
case HttpStatusCode.BadRequest:
message = $"Bad request sent to the hashing server! {responseContent}";
break;
-
+
case HttpStatusCode.Unauthorized:
message = "The auth key supplied for PokeHash was invalid.";
break;
-
- case (HttpStatusCode)429:
+
+ case (HttpStatusCode) 429:
message = $"Your request has been limited. {responseContent}";
break;
@@ -146,7 +146,7 @@ public async Task GetHashDataAsync(RequestEnvelope requestEnvelope, Si
throw new Exception(message);
}
}
-
+
private Task PerformRequest(HttpContent requestContent)
{
return Task.Run(async () =>
@@ -159,15 +159,15 @@ private Task PerformRequest(HttpContent requestContent)
{
_keySelection.WaitOne();
- //Logger.Warn(">>> Entering key selection.");
-
+// Logger.Warn(">>> Entering key selection.");
+
var availableKeys = _authKeys.Where(x => x.Requests < x.MaxRequestCount).ToArray();
if (availableKeys.Length > 0)
{
authKey = availableKeys.First();
authKey.Requests += 1;
- //Logger.Warn("Found available auth key.");
+// Logger.Warn("Found available auth key.");
// If the auth key has not been initialized yet, we need to have control a bit longer
// to configure it properly.
@@ -176,16 +176,15 @@ private Task PerformRequest(HttpContent requestContent)
}
else
{
- Logger.Warn("No available auth keys found.");
+// Logger.Warn("No available auth keys found.");
authKey = _authKeys
.OrderBy(x => x.RatePeriodEnd)
.First();
- var sleepTime = (int)Math.Ceiling(authKey.RatePeriodEnd.Subtract(DateTime.UtcNow).TotalMilliseconds);
-
- Logger.Warn($"Key selection is sleeping for {sleepTime}ms.");
+ var sleepTime = (int) Math.Ceiling(authKey.RatePeriodEnd.Subtract(DateTime.UtcNow).TotalMilliseconds);
+// Logger.Warn($"Key selection is sleeping for {sleepTime}ms.");
PokehashSleeping?.Invoke(this, sleepTime);
await Task.Delay(sleepTime);
@@ -195,23 +194,23 @@ private Task PerformRequest(HttpContent requestContent)
// We have to receive the new rate period end.
extendedSelection = true;
- Logger.Warn("Key selection is done sleeping.");
+// Logger.Warn("Key selection is done with sleeping.");
}
}
finally
{
if (!extendedSelection)
{
- //Logger.Warn("<<< Exiting key selection.");
+// Logger.Warn("<<< Exiting key selection.");
_keySelection.Release();
}
else
{
- Logger.Warn("=== Holding key selection.");
+// Logger.Warn("=== Holding key selection.");
}
}
-
+
requestContent.Headers.Add("X-AuthToken", authKey.AuthKey);
HttpResponseMessage response = null;
@@ -227,45 +226,43 @@ private Task PerformRequest(HttpContent requestContent)
// Handle response
try
{
- int maxRequestCount = 150;
- int secs = 60;
- int remaining = maxRequestCount;
-
- IEnumerable requestCountHeader;
- if (response.Headers.TryGetValues("X-MaxRequestCount", out requestCountHeader))
+ // Parse headers
+ int maxRequestCount;
+ int rateRequestsRemaining;
+ int ratePeriodEndSeconds;
+
+ IEnumerable maxRequestsValue;
+ IEnumerable requestsRemainingValue;
+ IEnumerable ratePeriodEndValue;
+
+ if (response.Headers.TryGetValues("X-MaxRequestCount", out maxRequestsValue) &&
+ response.Headers.TryGetValues("X-RateRequestsRemaining", out requestsRemainingValue) &&
+ response.Headers.TryGetValues("X-RatePeriodEnd", out ratePeriodEndValue))
{
- int.TryParse(requestCountHeader.FirstOrDefault() ?? "1", out maxRequestCount);
- }
-
- IEnumerable ratePeriodEndHeader;
- if (response.Headers.TryGetValues("X-RatePeriodEnd", out ratePeriodEndHeader))
- {
- int.TryParse(ratePeriodEndHeader.FirstOrDefault() ?? "1", out secs);
-
- //Logger.Warn($"Resets: {TimeUtil.GetDateTimeFromSeconds(secs)}");
+ if (!int.TryParse(maxRequestsValue.First(), out maxRequestCount) ||
+ !int.TryParse(requestsRemainingValue.First(), out rateRequestsRemaining) ||
+ !int.TryParse(ratePeriodEndValue.FirstOrDefault(), out ratePeriodEndSeconds))
+ {
+ throw new Exception("Failed parsing pokehash response header values.");
+ }
}
-
- IEnumerable rateRequestsRemainingHeader;
- if (response.Headers.TryGetValues("X-RateRequestsRemaining", out rateRequestsRemainingHeader))
+ else
{
- int.TryParse(rateRequestsRemainingHeader.FirstOrDefault() ?? "1", out remaining);
-
- //Logger.Warn($"Remaining / Max: {remaining} / {authKey.MaxRequestCount}");
- //Logger.Warn($"Requests / ShouldBe: {authKey.Requests} / {authKey.MaxRequestCount - remaining}");
+ throw new Exception("Failed parsing pokehash response headers.");
}
// Use parsed headers
if (!authKey.IsInitialized)
{
authKey.MaxRequestCount = maxRequestCount;
- authKey.Requests = authKey.MaxRequestCount - remaining;
+ authKey.Requests = authKey.MaxRequestCount - rateRequestsRemaining;
authKey.IsInitialized = true;
}
-
- var ratePeriodEnd = TimeUtil.GetDateTimeFromSeconds(secs);
+
+ var ratePeriodEnd = TimeUtil.GetDateTimeFromSeconds(ratePeriodEndSeconds);
if (ratePeriodEnd > authKey.RatePeriodEnd)
{
- //Logger.Warn($"[AuthKey: {authKey.AuthKey}] {authKey.RatePeriodEnd} increased to {ratePeriodEnd}.");
+// Logger.Warn($"[AuthKey: {authKey.AuthKey}] {authKey.RatePeriodEnd} increased to {ratePeriodEnd}.");
authKey.RatePeriodEnd = ratePeriodEnd;
}
@@ -276,7 +273,7 @@ private Task PerformRequest(HttpContent requestContent)
{
if (extendedSelection)
{
- //Logger.Warn("<<< Exiting extended key selection.");
+// Logger.Warn("<<< Exiting extended key selection.");
_keySelection.Release();
}
diff --git a/POGOLib.Official/Util/LocationUtil.cs b/POGOLib.Official/Util/LocationUtil.cs
index 265f20dad..18b9f38c6 100644
--- a/POGOLib.Official/Util/LocationUtil.cs
+++ b/POGOLib.Official/Util/LocationUtil.cs
@@ -1,7 +1,4 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
namespace POGOLib.Official.Util
{
diff --git a/POGOLib.Official/Util/MapUtil.cs b/POGOLib.Official/Util/MapUtil.cs
index b0a7ab462..a03e8bce9 100644
--- a/POGOLib.Official/Util/MapUtil.cs
+++ b/POGOLib.Official/Util/MapUtil.cs
@@ -1,8 +1,5 @@
-using Google.Common.Geometry;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
+using System.Collections.Generic;
+using Google.Common.Geometry;
namespace POGOLib.Official.Util
{
diff --git a/POGOLib.Official/Util/TimeUtil.cs b/POGOLib.Official/Util/TimeUtil.cs
index 8d56c42e8..ac022d5f0 100644
--- a/POGOLib.Official/Util/TimeUtil.cs
+++ b/POGOLib.Official/Util/TimeUtil.cs
@@ -1,7 +1,4 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
namespace POGOLib.Official.Util
{
diff --git a/POGOLib.Official/project.json b/POGOLib.Official/project.json
index 8ca3fa60e..05fc57fa3 100644
--- a/POGOLib.Official/project.json
+++ b/POGOLib.Official/project.json
@@ -1,10 +1,10 @@
-{
+{
"supports": {},
"dependencies": {
"GeoCoordinate.NetStandard1": "1.0.0",
"Google.Protobuf": "3.2.0",
"Newtonsoft.Json": "9.0.1",
- "POGOProtos.NetStandard1": "2.7.0",
+ "POGOProtos.NetStandard1": "2.8.0",
"S2Geometry": "1.0.3"
},
"frameworks": {
diff --git a/PokemonGo-UWP/Assets/Icons/ic_ivpercentage.png b/PokemonGo-UWP/Assets/Icons/ic_ivpercentage.png
index 3a5699caf..4aa4ac218 100644
Binary files a/PokemonGo-UWP/Assets/Icons/ic_ivpercentage.png and b/PokemonGo-UWP/Assets/Icons/ic_ivpercentage.png differ
diff --git a/PokemonGo-UWP/Assets/Icons/ic_level.png b/PokemonGo-UWP/Assets/Icons/ic_level.png
index 78d2cb673..97febfb48 100644
Binary files a/PokemonGo-UWP/Assets/Icons/ic_level.png and b/PokemonGo-UWP/Assets/Icons/ic_level.png differ
diff --git a/PokemonGo-UWP/Utils/GameClient.cs b/PokemonGo-UWP/Utils/GameClient.cs
index 9cae5df29..cee85a6e4 100644
--- a/PokemonGo-UWP/Utils/GameClient.cs
+++ b/PokemonGo-UWP/Utils/GameClient.cs
@@ -51,6 +51,7 @@
using Template10.Services.NavigationService;
using POGOProtos.Data.Battle;
using PokemonGo_UWP.Exceptions;
+using POGOLib.Official.Net.Captcha;
namespace PokemonGo_UWP.Utils
{
@@ -393,9 +394,9 @@ private async static Task CreateSession(Geoposition pos)
if (_session != null)
{
_session.AccessTokenUpdated -= SessionOnAccessTokenUpdated;
- _session.Player.Inventory.Update -= InventoryOnUpdate;
- _session.Map.Update -= MapOnUpdate;
- _session.RpcClient.CheckChallengeReceived -= SessionOnCheckChallengeReceived;
+ _session.InventoryUpdate -= InventoryOnUpdate;
+ _session.MapUpdate -= MapOnUpdate;
+ _session.CaptchaReceived -= SessionOnCaptchaReceived;
_session.RpcClient.HatchedEggsReceived -= SessionOnHatchedEggsReceived;
_session.RpcClient.CheckAwardedBadgesReceived -= SessionOnCheckAwardedBadgesReceived;
}
@@ -445,9 +446,9 @@ private async static Task CreateSession(Geoposition pos)
}
_session.AccessTokenUpdated += SessionOnAccessTokenUpdated;
- _session.Player.Inventory.Update += InventoryOnUpdate;
- _session.Map.Update += MapOnUpdate;
- _session.RpcClient.CheckChallengeReceived += SessionOnCheckChallengeReceived;
+ _session.InventoryUpdate += InventoryOnUpdate;
+ _session.MapUpdate += MapOnUpdate;
+ _session.CaptchaReceived += SessionOnCaptchaReceived;
_session.RpcClient.HatchedEggsReceived += SessionOnHatchedEggsReceived;
_session.RpcClient.CheckAwardedBadgesReceived += SessionOnCheckAwardedBadgesReceived;
@@ -522,25 +523,20 @@ private static void SessionOnAccessTokenUpdated(object sender, EventArgs eventAr
Logger.Info("Saved access token to file.");
}
- private static async void SessionOnCheckChallengeReceived(object sender, CheckChallengeResponse e)
+ private static async void SessionOnCaptchaReceived(object sender, CaptchaEventArgs e)
{
- if (e.ShowChallenge && !String.IsNullOrWhiteSpace(e.ChallengeUrl) && e.ChallengeUrl.Length > 5)
- {
- // Captcha is shown in checkChallengeResponse.ChallengeUrl
- Logger.Warn($"ChallengeURL: {e.ChallengeUrl}");
- // breakpoint here to manually resolve Captcha in a browser
- // after that set token to str variable from browser (see screenshot)
- Logger.Warn("Pause");
+ var session = (Session)sender;
+
+ Logger.Warn($"Captcha received: {e.CaptchaUrl}");
- //GOTO THE REQUIRED PAGE
- if (BootStrapper.Current.NavigationService.CurrentPageType != typeof(ChallengePage))
+ //GOTO THE REQUIRED PAGE
+ if (BootStrapper.Current.NavigationService.CurrentPageType != typeof(ChallengePage))
+ {
+ await DispatcherHelper.RunInDispatcherAndAwait(() =>
{
- await DispatcherHelper.RunInDispatcherAndAwait(() =>
- {
- // We are not in UI thread probably, so run this via dispatcher
- BootStrapper.Current.NavigationService.Navigate(typeof(ChallengePage), e.ChallengeUrl);
- });
- }
+ // We are not in UI thread probably, so run this via dispatcher
+ BootStrapper.Current.NavigationService.Navigate(typeof(ChallengePage), e.CaptchaUrl);
+ });
}
}
@@ -554,18 +550,20 @@ private static void SessionOnCheckAwardedBadgesReceived(object sender, CheckAwar
OnAwardedBadgesReceived?.Invoke(sender, e);
}
- private static void InventoryOnUpdate(object sender, EventArgs eventArgs)
+ private static void InventoryOnUpdate(object sender, EventArgs e)
{
- Inventory inventory = sender as Inventory;
+ Session session = sender as Session;
+ Inventory inventory = session.Player.Inventory;
UpdateLocalInventory(inventory);
Logger.Info("Inventory was updated.");
}
- private async static void MapOnUpdate(object sender, EventArgs eventArgs)
+ private async static void MapOnUpdate(object sender, EventArgs e)
{
if (_isSessionEnabled)
{
- Map map = sender as Map;
+ Session session = sender as Session;
+ Map map = session.Map;
await UpdateMapObjects(map);
Logger.Info("Map was updated.");
}
@@ -1656,9 +1654,16 @@ public static async Task UseCaptureItem(ulong encounterI
SpawnPointId = spawnpointId
}.ToByteString()
});
- var useItemCaptureResponse = UseItemCaptureResponse.Parser.ParseFrom(response);
- return useItemCaptureResponse;
+ try
+ {
+ var useItemCaptureResponse = UseItemCaptureResponse.Parser.ParseFrom(response);
+ return useItemCaptureResponse;
+ }
+ catch (Exception)
+ {
+ return new UseItemCaptureResponse() { Success = false };
+ }
}
///
@@ -1680,9 +1685,16 @@ public static async Task UseItemEncounter(ulong encoun
SpawnPointGuid = spawnpointId
}.ToByteString()
});
- var useItemEncounterResponse = UseItemEncounterResponse.Parser.ParseFrom(response);
- return useItemEncounterResponse;
+ try
+ {
+ var useItemEncounterResponse = UseItemEncounterResponse.Parser.ParseFrom(response);
+ return useItemEncounterResponse;
+ }
+ catch (Exception)
+ {
+ return new UseItemEncounterResponse() { Status = UseItemEncounterResponse.Types.Status.AlreadyCompleted };
+ }
}
#endregion
@@ -2021,9 +2033,16 @@ public static async Task UseIncense(ItemId item)
IncenseType = item
}.ToByteString()
});
- var useIncenseResponse = UseIncenseResponse.Parser.ParseFrom(response);
- return useIncenseResponse;
+ try
+ {
+ var useIncenseResponse = UseIncenseResponse.Parser.ParseFrom(response);
+ return useIncenseResponse;
+ }
+ catch (Exception)
+ {
+ return new UseIncenseResponse() { Result = UseIncenseResponse.Types.Result.Unknown };
+ }
}
///
@@ -2041,9 +2060,16 @@ public static async Task UseXpBoost(ItemId item)
ItemId = item
}.ToByteString()
});
- var useItemXpBoostResponse = UseItemXpBoostResponse.Parser.ParseFrom(response);
- return useItemXpBoostResponse;
+ try
+ {
+ var useItemXpBoostResponse = UseItemXpBoostResponse.Parser.ParseFrom(response);
+ return useItemXpBoostResponse;
+ }
+ catch (Exception)
+ {
+ return new UseItemXpBoostResponse() { Result = UseItemXpBoostResponse.Types.Result.Unset };
+ }
}
public static async Task UseItemRevive(ItemId item, ulong pokemonId)
@@ -2057,9 +2083,16 @@ public static async Task UseItemRevive(ItemId item, ulong
ItemId = item
}.ToByteString()
});
- var useItemReviveResponse = UseItemReviveResponse.Parser.ParseFrom(response);
- return useItemReviveResponse;
+ try
+ {
+ var useItemReviveResponse = UseItemReviveResponse.Parser.ParseFrom(response);
+ return useItemReviveResponse;
+ }
+ catch (Exception)
+ {
+ return new UseItemReviveResponse() { Result = UseItemReviveResponse.Types.Result.Unset };
+ }
}
public static async Task UseItemPotion(ItemId item, ulong pokemonId)
@@ -2073,9 +2106,16 @@ public static async Task UseItemPotion(ItemId item, ulong
ItemId = item
}.ToByteString()
});
- var useItemPotionResponse = UseItemPotionResponse.Parser.ParseFrom(response);
- return useItemPotionResponse;
+ try
+ {
+ var useItemPotionResponse = UseItemPotionResponse.Parser.ParseFrom(response);
+ return useItemPotionResponse;
+ }
+ catch(Exception)
+ {
+ return new UseItemPotionResponse() { Result = UseItemPotionResponse.Types.Result.Unset };
+ }
}
///
@@ -2121,9 +2161,16 @@ public static async Task UseEggIncubator(EggIncubat
PokemonId = egg.Id
}.ToByteString()
});
- var useItemEggIncubatorResponse = UseItemEggIncubatorResponse.Parser.ParseFrom(response);
- return useItemEggIncubatorResponse;
+ try
+ {
+ var useItemEggIncubatorResponse = UseItemEggIncubatorResponse.Parser.ParseFrom(response);
+ return useItemEggIncubatorResponse;
+ }
+ catch (Exception)
+ {
+ return new UseItemEggIncubatorResponse() { Result = UseItemEggIncubatorResponse.Types.Result.Unset };
+ }
}
///
diff --git a/PokemonGo-UWP/ViewModels/ItemsInventoryPageViewModel.cs b/PokemonGo-UWP/ViewModels/ItemsInventoryPageViewModel.cs
index cde52037e..730dd7725 100644
--- a/PokemonGo-UWP/ViewModels/ItemsInventoryPageViewModel.cs
+++ b/PokemonGo-UWP/ViewModels/ItemsInventoryPageViewModel.cs
@@ -313,7 +313,9 @@ private void AskAndUsePotion(ItemDataWrapper item)
{
PokemonInventory = new ObservableCollection(GameClient.PokemonsInventory
.Select(pokemonData => new PokemonDataWrapper(pokemonData))
- .Where(pokemonData => pokemonData.Stamina != pokemonData.StaminaMax));
+ .Where(pokemonData => pokemonData.Stamina != pokemonData.StaminaMax && // Not completely healthy
+ pokemonData.Stamina != 0 && // Not fainted
+ String.IsNullOrEmpty(pokemonData.DeployedFortId))); // Not deployed to fort
CurrentUseItem = item;
@@ -327,7 +329,9 @@ private void AskAndUseRevive(ItemDataWrapper item)
{
PokemonInventory = new ObservableCollection(GameClient.PokemonsInventory
.Select(pokemonData => new PokemonDataWrapper(pokemonData))
- .Where(pokemonData => pokemonData.Stamina ==0));
+ //.Where(pokemonData => pokemonData.Stamina == 0));
+ .Where(pokemonData => pokemonData.Stamina == 0 && // Fainted
+ String.IsNullOrEmpty(pokemonData.DeployedFortId))); // Not deployed to fort
CurrentUseItem = item;
diff --git a/PokemonGo-UWP/Views/EnterGymPage.xaml b/PokemonGo-UWP/Views/EnterGymPage.xaml
index c05ada0a9..0e19bd26c 100644
--- a/PokemonGo-UWP/Views/EnterGymPage.xaml
+++ b/PokemonGo-UWP/Views/EnterGymPage.xaml
@@ -503,7 +503,7 @@
Width="60" Height="60" Margin="8,0,0,0"
Command="{Binding AutoSelectCommand}"
Style="{ThemeResource ImageButtonStyle}">
-
+