632 lines
18 KiB
C#
632 lines
18 KiB
C#
using System;
|
|
using GameAnalyticsSDK.Net.Logging;
|
|
using GameAnalyticsSDK.Net.Utilities;
|
|
using GameAnalyticsSDK.Net.State;
|
|
using GameAnalyticsSDK.Net.Http;
|
|
|
|
namespace GameAnalyticsSDK.Net.Validators
|
|
{
|
|
internal static class GAValidator
|
|
{
|
|
#region Public methods
|
|
|
|
public static bool ValidateBusinessEvent(string currency, long amount, string cartType, string itemType, string itemId)
|
|
{
|
|
// validate currency
|
|
if (!ValidateCurrency(currency))
|
|
{
|
|
GALogger.W("Validation fail - business event - currency: Cannot be (null) and need to be A-Z, 3 characters and in the standard at openexchangerates.org. Failed currency: " + currency);
|
|
return false;
|
|
}
|
|
|
|
if (amount < 0)
|
|
{
|
|
GALogger.W("Validation fail - business event - amount. Cannot be less than 0. Failed amount: " + amount);
|
|
return false;
|
|
}
|
|
|
|
// validate cartType
|
|
if (!ValidateShortString(cartType, true))
|
|
{
|
|
GALogger.W("Validation fail - business event - cartType. Cannot be above 32 length. String: " + cartType);
|
|
return false;
|
|
}
|
|
|
|
// validate itemType length
|
|
if (!ValidateEventPartLength(itemType, false))
|
|
{
|
|
GALogger.W("Validation fail - business event - itemType: Cannot be (null), empty or above 64 characters. String: " + itemType);
|
|
return false;
|
|
}
|
|
|
|
// validate itemType chars
|
|
if (!ValidateEventPartCharacters(itemType))
|
|
{
|
|
GALogger.W("Validation fail - business event - itemType: Cannot contain other characters than A-z, 0-9, -_., ()!?. String: " + itemType);
|
|
return false;
|
|
}
|
|
|
|
// validate itemId
|
|
if (!ValidateEventPartLength(itemId, false))
|
|
{
|
|
GALogger.W("Validation fail - business event - itemId. Cannot be (null), empty or above 64 characters. String: " + itemId);
|
|
return false;
|
|
}
|
|
|
|
if (!ValidateEventPartCharacters(itemId))
|
|
{
|
|
GALogger.W("Validation fail - business event - itemId: Cannot contain other characters than A-z, 0-9, -_., ()!?. String: " + itemId);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public static bool ValidateResourceEvent(EGAResourceFlowType flowType, string currency, long amount, string itemType, string itemId)
|
|
{
|
|
if (flowType == EGAResourceFlowType.Undefined)
|
|
{
|
|
GALogger.W("Validation fail - resource event - flowType: Invalid flow type.");
|
|
return false;
|
|
}
|
|
if (string.IsNullOrEmpty(currency))
|
|
{
|
|
GALogger.W("Validation fail - resource event - currency: Cannot be (null)");
|
|
return false;
|
|
}
|
|
if (!GAState.HasAvailableResourceCurrency(currency))
|
|
{
|
|
GALogger.W("Validation fail - resource event - currency: Not found in list of pre-defined available resource currencies. String: " + currency);
|
|
return false;
|
|
}
|
|
if (!(amount > 0))
|
|
{
|
|
GALogger.W("Validation fail - resource event - amount: Float amount cannot be 0 or negative. Value: " + amount);
|
|
return false;
|
|
}
|
|
if (string.IsNullOrEmpty(itemType))
|
|
{
|
|
GALogger.W("Validation fail - resource event - itemType: Cannot be (null)");
|
|
return false;
|
|
}
|
|
if (!ValidateEventPartLength(itemType, false))
|
|
{
|
|
GALogger.W("Validation fail - resource event - itemType: Cannot be (null), empty or above 64 characters. String: " + itemType);
|
|
return false;
|
|
}
|
|
if (!ValidateEventPartCharacters(itemType))
|
|
{
|
|
GALogger.W("Validation fail - resource event - itemType: Cannot contain other characters than A-z, 0-9, -_., ()!?. String: " + itemType);
|
|
return false;
|
|
}
|
|
if (!GAState.HasAvailableResourceItemType(itemType))
|
|
{
|
|
GALogger.W("Validation fail - resource event - itemType: Not found in list of pre-defined available resource itemTypes. String: " + itemType);
|
|
return false;
|
|
}
|
|
if (!ValidateEventPartLength(itemId, false))
|
|
{
|
|
GALogger.W("Validation fail - resource event - itemId: Cannot be (null), empty or above 64 characters. String: " + itemId);
|
|
return false;
|
|
}
|
|
if (!ValidateEventPartCharacters(itemId))
|
|
{
|
|
GALogger.W("Validation fail - resource event - itemId: Cannot contain other characters than A-z, 0-9, -_., ()!?. String: " + itemId);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static bool ValidateProgressionEvent(EGAProgressionStatus progressionStatus, string progression01, string progression02, string progression03)
|
|
{
|
|
if (progressionStatus == EGAProgressionStatus.Undefined)
|
|
{
|
|
GALogger.W("Validation fail - progression event: Invalid progression status.");
|
|
return false;
|
|
}
|
|
|
|
// Make sure progressions are defined as either 01, 01+02 or 01+02+03
|
|
if (!string.IsNullOrEmpty(progression03) && !(!string.IsNullOrEmpty(progression02) || string.IsNullOrEmpty(progression01)))
|
|
{
|
|
GALogger.W("Validation fail - progression event: 03 found but 01+02 are invalid. Progression must be set as either 01, 01+02 or 01+02+03.");
|
|
return false;
|
|
}
|
|
else if (!string.IsNullOrEmpty(progression02) && string.IsNullOrEmpty(progression01))
|
|
{
|
|
GALogger.W("Validation fail - progression event: 02 found but not 01. Progression must be set as either 01, 01+02 or 01+02+03");
|
|
return false;
|
|
}
|
|
else if (string.IsNullOrEmpty(progression01))
|
|
{
|
|
GALogger.W("Validation fail - progression event: progression01 not valid. Progressions must be set as either 01, 01+02 or 01+02+03");
|
|
return false;
|
|
}
|
|
|
|
// progression01 (required)
|
|
if (!ValidateEventPartLength(progression01, false))
|
|
{
|
|
GALogger.W("Validation fail - progression event - progression01: Cannot be (null), empty or above 64 characters. String: " + progression01);
|
|
return false;
|
|
}
|
|
if (!ValidateEventPartCharacters(progression01))
|
|
{
|
|
GALogger.W("Validation fail - progression event - progression01: Cannot contain other characters than A-z, 0-9, -_., ()!?. String: " + progression01);
|
|
return false;
|
|
}
|
|
// progression02
|
|
if (!string.IsNullOrEmpty(progression02))
|
|
{
|
|
if (!ValidateEventPartLength(progression02, true))
|
|
{
|
|
GALogger.W("Validation fail - progression event - progression02: Cannot be empty or above 64 characters. String: " + progression02);
|
|
return false;
|
|
}
|
|
if (!ValidateEventPartCharacters(progression02))
|
|
{
|
|
GALogger.W("Validation fail - progression event - progression02: Cannot contain other characters than A-z, 0-9, -_., ()!?. String: " + progression02);
|
|
return false;
|
|
}
|
|
}
|
|
// progression03
|
|
if (!string.IsNullOrEmpty(progression03))
|
|
{
|
|
if (!ValidateEventPartLength(progression03, true))
|
|
{
|
|
GALogger.W("Validation fail - progression event - progression03: Cannot be empty or above 64 characters. String: " + progression03);
|
|
return false;
|
|
}
|
|
if (!ValidateEventPartCharacters(progression03))
|
|
{
|
|
GALogger.W("Validation fail - progression event - progression03: Cannot contain other characters than A-z, 0-9, -_., ()!?. String: " + progression03);
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static bool ValidateDesignEvent(string eventId, double value)
|
|
{
|
|
if (!ValidateEventIdLength(eventId))
|
|
{
|
|
GALogger.W("Validation fail - design event - eventId: Cannot be (null) or empty. Only 5 event parts allowed seperated by :. Each part need to be 32 characters or less. String: " + eventId);
|
|
return false;
|
|
}
|
|
if (!ValidateEventIdCharacters(eventId))
|
|
{
|
|
GALogger.W("Validation fail - design event - eventId: Non valid characters. Only allowed A-z, 0-9, -_., ()!?. String: " + eventId);
|
|
return false;
|
|
}
|
|
// value: allow 0, negative and nil (not required)
|
|
return true;
|
|
}
|
|
|
|
public static bool ValidateErrorEvent(EGAErrorSeverity severity, string message)
|
|
{
|
|
if (severity == EGAErrorSeverity.Undefined)
|
|
{
|
|
GALogger.W("Validation fail - error event - severity: Severity was unsupported value.");
|
|
return false;
|
|
}
|
|
if (!ValidateLongString(message, true))
|
|
{
|
|
GALogger.W("Validation fail - error event - message: Message cannot be above 8192 characters.");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static bool ValidateSdkErrorEvent(string gameKey, string gameSecret, EGASdkErrorType type)
|
|
{
|
|
if(!ValidateKeys(gameKey, gameSecret))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (type == EGASdkErrorType.Undefined)
|
|
{
|
|
GALogger.W("Validation fail - sdk error event - type: Type was unsupported value.");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static bool ValidateKeys(string gameKey, string gameSecret)
|
|
{
|
|
if (GAUtilities.StringMatch(gameKey, "^[A-z0-9]{32}$"))
|
|
{
|
|
if (GAUtilities.StringMatch(gameSecret, "^[A-z0-9]{40}$"))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static bool ValidateCurrency(string currency)
|
|
{
|
|
if (string.IsNullOrEmpty(currency))
|
|
{
|
|
return false;
|
|
}
|
|
if (!GAUtilities.StringMatch(currency, "^[A-Z]{3}$"))
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static bool ValidateEventPartLength(string eventPart, bool allowNull)
|
|
{
|
|
if (allowNull == true && string.IsNullOrEmpty(eventPart))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (string.IsNullOrEmpty(eventPart))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (eventPart.Length > 64)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static bool ValidateEventPartCharacters(string eventPart)
|
|
{
|
|
if (!GAUtilities.StringMatch(eventPart, "^[A-Za-z0-9\\s\\-_\\.\\(\\)\\!\\?]{1,64}$"))
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static bool ValidateEventIdLength(string eventId)
|
|
{
|
|
if (string.IsNullOrEmpty(eventId))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!GAUtilities.StringMatch(eventId, "^[^:]{1,64}(?::[^:]{1,64}){0,4}$"))
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static bool ValidateEventIdCharacters(string eventId)
|
|
{
|
|
if (string.IsNullOrEmpty(eventId))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!GAUtilities.StringMatch(eventId, "^[A-Za-z0-9\\s\\-_\\.\\(\\)\\!\\?]{1,64}(:[A-Za-z0-9\\s\\-_\\.\\(\\)\\!\\?]{1,64}){0,4}$"))
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static JSONObject ValidateAndCleanInitRequestResponse(JSONNode initResponse)
|
|
{
|
|
// make sure we have a valid dict
|
|
if (initResponse == null)
|
|
{
|
|
GALogger.W("validateInitRequestResponse failed - no response dictionary.");
|
|
return null;
|
|
}
|
|
|
|
JSONObject validatedDict = new JSONObject();
|
|
|
|
// validate enabled field
|
|
try
|
|
{
|
|
validatedDict.Add("enabled", new JSONBool(initResponse["enabled"].IsBoolean ? initResponse["enabled"].AsBool : true));
|
|
}
|
|
catch (Exception)
|
|
{
|
|
GALogger.W("validateInitRequestResponse failed - invalid type in 'enabled' field.");
|
|
return null;
|
|
}
|
|
|
|
// validate server_ts
|
|
try
|
|
{
|
|
long serverTsNumber = initResponse["server_ts"].IsNumber ? initResponse["server_ts"].AsLong : -1;
|
|
if (serverTsNumber > 0)
|
|
{
|
|
validatedDict.Add("server_ts", new JSONNumber(serverTsNumber));
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
GALogger.W("validateInitRequestResponse failed - invalid type in 'server_ts' field. type=" + initResponse["server_ts"].GetType() + ", value=" + initResponse["server_ts"] + ", " + e);
|
|
return null;
|
|
}
|
|
|
|
// validate configurations field
|
|
try
|
|
{
|
|
validatedDict.Add("configurations", initResponse["configurations"].IsArray ? initResponse["configurations"].AsArray : new JSONArray());
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
GALogger.W("validateInitRequestResponse failed - invalid type in 'configurations' field. type=" + initResponse["configurations"].GetType() + ", value=" + initResponse["configurations"] + ", " + e);
|
|
return null;
|
|
}
|
|
|
|
return validatedDict;
|
|
}
|
|
|
|
public static bool ValidateBuild(string build)
|
|
{
|
|
if (!ValidateShortString(build, false))
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static bool ValidateSdkWrapperVersion(string wrapperVersion)
|
|
{
|
|
if (!GAUtilities.StringMatch(wrapperVersion, "^(unity) [0-9]{0,5}(\\.[0-9]{0,5}){0,2}$"))
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static bool ValidateEngineVersion(string engineVersion)
|
|
{
|
|
if (engineVersion == null || !GAUtilities.StringMatch(engineVersion, "^(unity) [0-9]{0,5}(\\.[0-9]{0,5}){0,2}$"))
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static bool ValidateUserId(string uId)
|
|
{
|
|
if (!ValidateString(uId, false))
|
|
{
|
|
GALogger.W("Validation fail - user id: id cannot be (null), empty or above 64 characters.");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static bool ValidateShortString(string shortString, bool canBeEmpty)
|
|
{
|
|
// String is allowed to be empty or nil
|
|
if (canBeEmpty && string.IsNullOrEmpty(shortString))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (string.IsNullOrEmpty(shortString) || shortString.Length > 32)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static bool ValidateString(string s, bool canBeEmpty)
|
|
{
|
|
// String is allowed to be empty or nil
|
|
if (canBeEmpty && string.IsNullOrEmpty(s))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (string.IsNullOrEmpty(s) || s.Length > 64)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static bool ValidateLongString(string longString, bool canBeEmpty)
|
|
{
|
|
// String is allowed to be empty
|
|
if (canBeEmpty && string.IsNullOrEmpty(longString))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (string.IsNullOrEmpty(longString) || longString.Length > 8192)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static bool ValidateConnectionType(string connectionType)
|
|
{
|
|
return GAUtilities.StringMatch(connectionType, "^(wwan|wifi|lan|offline)$");
|
|
}
|
|
|
|
public static bool ValidateCustomDimensions(params string[] customDimensions)
|
|
{
|
|
return ValidateArrayOfStrings(20, 32, false, "custom dimensions", customDimensions);
|
|
}
|
|
|
|
public static bool ValidateResourceCurrencies(params string[] resourceCurrencies)
|
|
{
|
|
if (!ValidateArrayOfStrings(20, 64, false, "resource currencies", resourceCurrencies))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// validate each string for regex
|
|
foreach (string resourceCurrency in resourceCurrencies)
|
|
{
|
|
if (!GAUtilities.StringMatch(resourceCurrency, "^[A-Za-z]+$"))
|
|
{
|
|
GALogger.W("resource currencies validation failed: a resource currency can only be A-Z, a-z. String was: " + resourceCurrency);
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static bool ValidateResourceItemTypes(params string[] resourceItemTypes)
|
|
{
|
|
if (!ValidateArrayOfStrings(20, 32, false, "resource item types", resourceItemTypes))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// validate each resourceItemType for eventpart validation
|
|
foreach (string resourceItemType in resourceItemTypes)
|
|
{
|
|
if (!ValidateEventPartCharacters(resourceItemType))
|
|
{
|
|
GALogger.W("resource item types validation failed: a resource item type cannot contain other characters than A-z, 0-9, -_., ()!?. String was: " + resourceItemType);
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static bool ValidateDimension01(string dimension01)
|
|
{
|
|
// allow nil
|
|
if (string.IsNullOrEmpty(dimension01))
|
|
{
|
|
return true;
|
|
}
|
|
if (!GAState.HasAvailableCustomDimensions01(dimension01))
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static bool ValidateDimension02(string dimension02)
|
|
{
|
|
// allow nil
|
|
if (string.IsNullOrEmpty(dimension02))
|
|
{
|
|
return true;
|
|
}
|
|
if (!GAState.HasAvailableCustomDimensions02(dimension02))
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static bool ValidateDimension03(string dimension03)
|
|
{
|
|
// allow nil
|
|
if (string.IsNullOrEmpty(dimension03))
|
|
{
|
|
return true;
|
|
}
|
|
if (!GAState.HasAvailableCustomDimensions03(dimension03))
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static bool ValidateArrayOfStrings(long maxCount, long maxStringLength, bool allowNoValues, string logTag, params string[] arrayOfStrings)
|
|
{
|
|
string arrayTag = logTag;
|
|
|
|
// use arrayTag to annotate warning log
|
|
if (string.IsNullOrEmpty(arrayTag))
|
|
{
|
|
arrayTag = "Array";
|
|
}
|
|
|
|
if(arrayOfStrings == null)
|
|
{
|
|
GALogger.W(arrayTag + " validation failed: array cannot be null. ");
|
|
return false;
|
|
}
|
|
|
|
// check if empty
|
|
if (allowNoValues == false && arrayOfStrings.Length == 0)
|
|
{
|
|
GALogger.W(arrayTag + " validation failed: array cannot be empty. ");
|
|
return false;
|
|
}
|
|
|
|
// check if exceeding max count
|
|
if (maxCount > 0 && arrayOfStrings.Length > maxCount)
|
|
{
|
|
GALogger.W(arrayTag + " validation failed: array cannot exceed " + maxCount + " values. It has " + arrayOfStrings.Length + " values.");
|
|
return false;
|
|
}
|
|
|
|
// validate each string
|
|
foreach (string arrayString in arrayOfStrings)
|
|
{
|
|
int stringLength = arrayString == null ? 0 : arrayString.Length;
|
|
// check if empty (not allowed)
|
|
if (stringLength == 0)
|
|
{
|
|
GALogger.W(arrayTag + " validation failed: contained an empty string.");
|
|
return false;
|
|
}
|
|
|
|
// check if exceeding max length
|
|
if (maxStringLength > 0 && stringLength > maxStringLength)
|
|
{
|
|
GALogger.W(arrayTag + " validation failed: a string exceeded max allowed length (which is: " + maxStringLength + "). String was: " + arrayString);
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static bool ValidateFacebookId(string facebookId)
|
|
{
|
|
if (!ValidateString(facebookId, false))
|
|
{
|
|
GALogger.W("Validation fail - facebook id: id cannot be (null), empty or above 64 characters.");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static bool ValidateGender(EGAGender gender)
|
|
{
|
|
if (gender == EGAGender.Undefined || !(gender == EGAGender.Male || gender == EGAGender.Female))
|
|
{
|
|
GALogger.W("Validation fail - gender: Has to be 'male' or 'female'.");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static bool ValidateBirthyear(long birthYear)
|
|
{
|
|
if (birthYear < 0 || birthYear > 9999)
|
|
{
|
|
GALogger.W("Validation fail - birthYear: Cannot be (null) or invalid range.");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static bool ValidateClientTs(long clientTs)
|
|
{
|
|
// TODO(nikolaj): validate other way? (instead of max possible)
|
|
if (clientTs < (long.MinValue+1) || clientTs > (long.MaxValue-1))
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
#endregion // Public methods
|
|
}
|
|
}
|
|
|