/// <summary> /// Checks whether the activity search request is valid. /// </summary> /// <param name="ActivitySearchRequest">Activity search request part of the client's request message.</param> /// <param name="MessageBuilder">Client's network message builder.</param> /// <param name="RequestMessage">Full request message from client.</param> /// <param name="ErrorResponse">If the function fails, this is filled with error response message that is ready to be sent to the client.</param> /// <returns>true if the search request is valid, false otherwise.</returns> public static bool ValidateActivitySearchRequest(ActivitySearchRequest ActivitySearchRequest, ProxMessageBuilder MessageBuilder, ProxProtocolMessage RequestMessage, out ProxProtocolMessage ErrorResponse) { log.Trace("()"); bool res = false; ErrorResponse = null; string details = null; int responseResultLimit = ProxMessageProcessor.ActivitySearchMaxResponseRecords; int totalResultLimit = ProxMessageProcessor.ActivitySearchMaxTotalRecords; bool maxResponseRecordCountValid = (1 <= ActivitySearchRequest.MaxResponseRecordCount) && (ActivitySearchRequest.MaxResponseRecordCount <= responseResultLimit); if (!maxResponseRecordCountValid) { log.Debug("Invalid maxResponseRecordCount value '{0}'.", ActivitySearchRequest.MaxResponseRecordCount); details = "maxResponseRecordCount"; } if (details == null) { bool maxTotalRecordCountValid = (1 <= ActivitySearchRequest.MaxTotalRecordCount) && (ActivitySearchRequest.MaxTotalRecordCount <= totalResultLimit) && (ActivitySearchRequest.MaxResponseRecordCount <= ActivitySearchRequest.MaxTotalRecordCount); if (!maxTotalRecordCountValid) { log.Debug("Invalid maxTotalRecordCount value '{0}'.", ActivitySearchRequest.MaxTotalRecordCount); details = "maxTotalRecordCount"; } } if ((details == null) && (ActivitySearchRequest.OwnerNetworkId.Length > 0)) { bool ownerNetworkIdValid = ActivitySearchRequest.OwnerNetworkId.Length == ProtocolHelper.NetworkIdentifierLength; if (!ownerNetworkIdValid) { log.Debug("Invalid owner network ID length '{0}'.", ActivitySearchRequest.OwnerNetworkId.Length); details = "ownerNetworkId"; } } if ((details == null) && (ActivitySearchRequest.Type != null)) { bool typeValid = Encoding.UTF8.GetByteCount(ActivitySearchRequest.Type) <= ProxMessageBuilder.MaxActivitySearchTypeLengthBytes; if (!typeValid) { log.Debug("Invalid type value length '{0}'.", ActivitySearchRequest.Type.Length); details = "type"; } } if ((details == null) && ((ActivitySearchRequest.StartNotAfter != 0) || (ActivitySearchRequest.ExpirationNotBefore != 0))) { DateTime?startNotAfter = null; DateTime?expirationNotBefore = null; if (ActivitySearchRequest.StartNotAfter != 0) { startNotAfter = ProtocolHelper.UnixTimestampMsToDateTime(ActivitySearchRequest.StartNotAfter); bool startNotAfterValid = startNotAfter != null; if (!startNotAfterValid) { log.Debug("Start not after {0} is not a valid timestamp value.", ActivitySearchRequest.StartNotAfter); details = "startNotAfter"; } } if ((details == null) && (ActivitySearchRequest.ExpirationNotBefore != 0)) { expirationNotBefore = ProtocolHelper.UnixTimestampMsToDateTime(ActivitySearchRequest.ExpirationNotBefore); bool expirationNotBeforeValid = expirationNotBefore != null; if (!expirationNotBeforeValid) { log.Debug("Expiration not before {0} is not a valid timestamp value.", ActivitySearchRequest.ExpirationNotBefore); details = "expirationNotBefore"; } else if (ActivitySearchRequest.StartNotAfter != 0) { expirationNotBeforeValid = ActivitySearchRequest.StartNotAfter <= ActivitySearchRequest.ExpirationNotBefore; if (!expirationNotBeforeValid) { log.Debug("Expiration not before {0} is smaller than start not after {1}.", ActivitySearchRequest.StartNotAfter, ActivitySearchRequest.ExpirationNotBefore); details = "expirationNotBefore"; } } } } if ((details == null) && (ActivitySearchRequest.Latitude != GpsLocation.NoLocationLocationType)) { GpsLocation locLat = new GpsLocation(ActivitySearchRequest.Latitude, 0); GpsLocation locLong = new GpsLocation(0, ActivitySearchRequest.Longitude); if (!locLat.IsValid()) { log.Debug("Latitude '{0}' is not a valid GPS latitude value.", ActivitySearchRequest.Latitude); details = "latitude"; } else if (!locLong.IsValid()) { log.Debug("Longitude '{0}' is not a valid GPS longitude value.", ActivitySearchRequest.Longitude); details = "longitude"; } } if ((details == null) && (ActivitySearchRequest.Latitude != GpsLocation.NoLocationLocationType)) { bool radiusValid = ActivitySearchRequest.Radius > 0; if (!radiusValid) { log.Debug("Invalid radius value '{0}'.", ActivitySearchRequest.Radius); details = "radius"; } } if ((details == null) && (ActivitySearchRequest.ExtraData != null)) { bool validLength = (Encoding.UTF8.GetByteCount(ActivitySearchRequest.ExtraData) <= ProxMessageBuilder.MaxActivitySearchExtraDataLengthBytes); bool extraDataValid = RegexTypeValidator.ValidateRegex(ActivitySearchRequest.ExtraData); if (!validLength || !extraDataValid) { log.Debug("Invalid extraData regular expression filter."); details = "extraData"; } } if (details == null) { res = true; } else { ErrorResponse = MessageBuilder.CreateErrorInvalidValueResponse(RequestMessage, details); } log.Trace("(-):{0}", res); return(res); }
/// <summary> /// Checks whether a profile information is valid. /// </summary> /// <param name="Profile">Profile information to check.</param> /// <param name="IdentityPublicKey">Public key of the profile's identity.</param> /// <param name="MessageBuilder">Client's network message builder.</param> /// <param name="RequestMessage">Full request message from client.</param> /// <param name="ErrorPrefix">Prefix to add to the validation error details.</param> /// <param name="ErrorResponse">If the function fails, this is filled with error response message that is ready to be sent to the client.</param> /// <returns>true if the signed profile information is valid, false otherwise.</returns> public static bool ValidateProfileInformation(ProfileInformation Profile, byte[] IdentityPublicKey, PsMessageBuilder MessageBuilder, PsProtocolMessage RequestMessage, string ErrorPrefix, out PsProtocolMessage ErrorResponse) { log.Trace("()"); bool res = false; ErrorResponse = null; string details = null; if (Profile == null) { Profile = new ProfileInformation(); } SemVer version = new SemVer(Profile.Version); // Currently only supported version is 1.0.0. if (!version.Equals(SemVer.V100)) { log.Debug("Unsupported version '{0}'.", version); details = "version"; } if (details == null) { byte[] pubKey = Profile.PublicKey.ToByteArray(); bool pubKeyValid = (0 < pubKey.Length) && (pubKey.Length <= ProtocolHelper.MaxPublicKeyLengthBytes) && ByteArrayComparer.Equals(IdentityPublicKey, pubKey); if (!pubKeyValid) { log.Debug("Invalid public key '{0}' does not match identity public key '{1}'.", pubKey.ToHex(), IdentityPublicKey.ToHex()); details = "publicKey"; } } if (details == null) { int typeSize = Encoding.UTF8.GetByteCount(Profile.Type); bool typeValid = (0 < typeSize) && (typeSize <= IdentityBase.MaxProfileTypeLengthBytes); if (!typeValid) { log.Debug("Invalid type size in bytes {0}.", typeSize); details = "type"; } } if (details == null) { int nameSize = Encoding.UTF8.GetByteCount(Profile.Name); bool nameValid = (0 < nameSize) && (nameSize <= IdentityBase.MaxProfileNameLengthBytes); if (!nameValid) { log.Debug("Invalid name size in bytes {0}.", nameSize); details = "name"; } } if (details == null) { GpsLocation locLat = new GpsLocation(Profile.Latitude, 0); if (!locLat.IsValid()) { log.Debug("Invalid latitude {0}.", Profile.Latitude); details = "latitude"; } } if (details == null) { GpsLocation locLon = new GpsLocation(0, Profile.Longitude); if (!locLon.IsValid()) { log.Debug("Invalid longitude {0}.", Profile.Longitude); details = "longitude"; } } if (details == null) { int extraDataSize = Encoding.UTF8.GetByteCount(Profile.ExtraData); bool extraDataValid = extraDataSize <= IdentityBase.MaxProfileExtraDataLengthBytes; if (!extraDataValid) { log.Debug("Invalid extraData size in bytes {0}.", extraDataSize); details = "extraData"; } } if (details == null) { bool profileImageHashValid = (Profile.ProfileImageHash.Length == 0) || (Profile.ProfileImageHash.Length == ProtocolHelper.HashLengthBytes); if (!profileImageHashValid) { log.Debug("Invalid profile image hash size {0} bytes.", Profile.ProfileImageHash.Length); details = "profileImageHash"; } } if (details == null) { bool thumbnailImageHashValid = (Profile.ThumbnailImageHash.Length == 0) || (Profile.ThumbnailImageHash.Length == ProtocolHelper.HashLengthBytes); if (!thumbnailImageHashValid) { log.Debug("Invalid thumbnail image hash size {0} bytes.", Profile.ThumbnailImageHash.Length); details = "thumbnailImageHash"; } } if (details == null) { res = true; } else { ErrorResponse = MessageBuilder.CreateErrorInvalidValueResponse(RequestMessage, ErrorPrefix + details); } log.Trace("(-):{0}", res); return(res); }
/// <summary> /// Validates ActivityInformation structure by itself. This function does not touch database and does not validate /// anything that depends on the context. /// </summary> /// <param name="Activity">Description of the activity to validate.</param> /// <param name="OwnerIdentityPublicKey">Public key of the activity's owner identity.</param> /// <param name="MessageBuilder">Network message builder of the client who sent this activity description.</param> /// <param name="RequestMessage">Full request message from client.</param> /// <param name="ErrorPrefix">Prefix to add to the validation error details.</param> /// <param name="ErrorResponse">If the function fails, this is filled with error response message that is ready to be sent to the client.</param> /// <returns>true if the activity information is valid, false otherwise.</returns> public static bool ValidateActivityInformation(ActivityInformation Activity, byte[] OwnerIdentityPublicKey, ProxMessageBuilder MessageBuilder, ProxProtocolMessage RequestMessage, string ErrorPrefix, out ProxProtocolMessage ErrorResponse) { log.Trace("()"); bool res = false; ErrorResponse = null; string details = null; if (Activity == null) { Activity = new ActivityInformation(); } if (Activity.ProfileServerContact == null) { Activity.ProfileServerContact = new ServerContactInfo(); } SemVer version = new SemVer(Activity.Version); // Currently only supported version is 1.0.0. if (!version.Equals(SemVer.V100)) { log.Debug("Unsupported version '{0}'.", version); details = "version"; } if (details == null) { uint activityId = Activity.Id; // 0 is not a valid activity identifier. if (activityId == 0) { log.Debug("Invalid activity ID '{0}'.", activityId); details = "id"; } } if (details == null) { byte[] pubKey = Activity.OwnerPublicKey.ToByteArray(); bool pubKeyValid = (0 < pubKey.Length) && (pubKey.Length <= ProtocolHelper.MaxPublicKeyLengthBytes) && ByteArrayComparer.Equals(OwnerIdentityPublicKey, pubKey); if (!pubKeyValid) { log.Debug("Invalid public key '{0}' does not match identity public key '{1}'.", pubKey.ToHex(), OwnerIdentityPublicKey.ToHex()); details = "ownerPublicKey"; } } if (details == null) { ServerContactInfo sci = Activity.ProfileServerContact; bool networkIdValid = sci.NetworkId.Length == ProtocolHelper.NetworkIdentifierLength; IPAddress ipAddress = IPAddressExtensions.IpFromBytes(sci.IpAddress.ToByteArray()); bool ipAddressValid = (ipAddress != null) && (Config.Configuration.TestModeEnabled || !ipAddress.IsReservedOrLocal()); bool portValid = (1 <= sci.PrimaryPort) && (sci.PrimaryPort <= 65535); if (!networkIdValid || !ipAddressValid || !portValid) { log.Debug("Profile server contact's network ID is {0}, IP address is {1}, port is {2}.", networkIdValid ? "valid" : "invalid", ipAddressValid ? "valid" : "invalid", portValid ? "valid" : "invalid"); if (!networkIdValid) { details = "profileServerContact.networkId"; } else if (!ipAddressValid) { details = "profileServerContact.ipAddress"; } else if (!portValid) { details = "profileServerContact.primaryPort"; } } } if (details == null) { string activityType = Activity.Type; if (activityType == null) { activityType = ""; } int byteLen = Encoding.UTF8.GetByteCount(activityType); bool activityTypeValid = (0 < byteLen) && (byteLen <= ProxMessageBuilder.MaxActivityTypeLengthBytes); if (!activityTypeValid) { log.Debug("Activity type too long or zero length ({0} bytes, limit is {1}).", byteLen, ProxMessageBuilder.MaxActivityTypeLengthBytes); details = "type"; } } if (details == null) { GpsLocation locLat = new GpsLocation(Activity.Latitude, 0); GpsLocation locLong = new GpsLocation(0, Activity.Longitude); if (!locLat.IsValid()) { log.Debug("Latitude '{0}' is not a valid GPS latitude value.", Activity.Latitude); details = "latitude"; } else if (!locLong.IsValid()) { log.Debug("Longitude '{0}' is not a valid GPS longitude value.", Activity.Longitude); details = "longitude"; } } if (details == null) { uint precision = Activity.Precision; bool precisionValid = (0 <= precision) && (precision <= ProxMessageBuilder.MaxLocationPrecision); if (!precisionValid) { log.Debug("Precision '{0}' is not an integer between 0 and {1}.", precision, ProxMessageBuilder.MaxLocationPrecision); details = "precision"; } } if (details == null) { DateTime?startTime = ProtocolHelper.UnixTimestampMsToDateTime(Activity.StartTime); DateTime?expirationTime = ProtocolHelper.UnixTimestampMsToDateTime(Activity.ExpirationTime); if (startTime == null) { log.Debug("Invalid activity start time timestamp '{0}'.", Activity.StartTime); details = "startTime"; } else if (expirationTime == null) { log.Debug("Invalid activity expiration time timestamp '{0}'.", Activity.ExpirationTime); details = "expirationTime"; } else { if (startTime > expirationTime) { log.Debug("Activity expiration time has to be greater than or equal to its start time."); details = "expirationTime"; } else if (expirationTime.Value > DateTime.UtcNow.AddHours(ActivityBase.MaxActivityLifeTimeHours)) { log.Debug("Activity expiration time {0} is more than {1} hours in the future.", expirationTime.Value.ToString("yyyy-MM-dd HH:mm:ss"), ActivityBase.MaxActivityLifeTimeHours); details = "expirationTime"; } } } if (details == null) { string extraData = Activity.ExtraData; if (extraData == null) { extraData = ""; } // Extra data is semicolon separated 'key=value' list, max ActivityBase.MaxActivityExtraDataLengthBytes bytes long. int byteLen = Encoding.UTF8.GetByteCount(extraData); if (byteLen > ProxMessageBuilder.MaxActivityExtraDataLengthBytes) { log.Debug("Extra data too large ({0} bytes, limit is {1}).", byteLen, ProxMessageBuilder.MaxActivityExtraDataLengthBytes); details = "extraData"; } } if (details == null) { res = true; } else { ErrorResponse = MessageBuilder.CreateErrorInvalidValueResponse(RequestMessage, ErrorPrefix + details); } log.Trace("(-):{0}", res); return(res); }
/// <summary> /// Checks whether the profile search request is valid. /// </summary> /// <param name="ProfileSearchRequest">Profile search request part of the client's request message.</param> /// <param name="MessageBuilder">Client's network message builder.</param> /// <param name="RequestMessage">Full request message from client.</param> /// <param name="ErrorResponse">If the function fails, this is filled with error response message that is ready to be sent to the client.</param> /// <returns>true if the profile search request is valid, false otherwise.</returns> public static bool ValidateProfileSearchRequest(ProfileSearchRequest ProfileSearchRequest, PsMessageBuilder MessageBuilder, PsProtocolMessage RequestMessage, out PsProtocolMessage ErrorResponse) { log.Trace("()"); bool res = false; ErrorResponse = null; string details = null; if (ProfileSearchRequest == null) { ProfileSearchRequest = new ProfileSearchRequest(); } bool includeImages = ProfileSearchRequest.IncludeThumbnailImages; int responseResultLimit = includeImages ? PsMessageProcessor.ProfileSearchMaxResponseRecordsWithImage : PsMessageProcessor.ProfileSearchMaxResponseRecordsWithoutImage; int totalResultLimit = includeImages ? PsMessageProcessor.ProfileSearchMaxTotalRecordsWithImage : PsMessageProcessor.ProfileSearchMaxTotalRecordsWithoutImage; bool maxResponseRecordCountValid = (1 <= ProfileSearchRequest.MaxResponseRecordCount) && (ProfileSearchRequest.MaxResponseRecordCount <= responseResultLimit); if (!maxResponseRecordCountValid) { log.Debug("Invalid maxResponseRecordCount value '{0}'.", ProfileSearchRequest.MaxResponseRecordCount); details = "maxResponseRecordCount"; } if (details == null) { bool maxTotalRecordCountValid = (1 <= ProfileSearchRequest.MaxTotalRecordCount) && (ProfileSearchRequest.MaxTotalRecordCount <= totalResultLimit) && (ProfileSearchRequest.MaxResponseRecordCount <= ProfileSearchRequest.MaxTotalRecordCount); if (!maxTotalRecordCountValid) { log.Debug("Invalid maxTotalRecordCount value '{0}'.", ProfileSearchRequest.MaxTotalRecordCount); details = "maxTotalRecordCount"; } } if ((details == null) && (ProfileSearchRequest.Type != null)) { bool typeValid = Encoding.UTF8.GetByteCount(ProfileSearchRequest.Type) <= PsMessageBuilder.MaxProfileSearchTypeLengthBytes; if (!typeValid) { log.Debug("Invalid type value length '{0}'.", ProfileSearchRequest.Type.Length); details = "type"; } } if ((details == null) && (ProfileSearchRequest.Name != null)) { bool nameValid = Encoding.UTF8.GetByteCount(ProfileSearchRequest.Name) <= PsMessageBuilder.MaxProfileSearchNameLengthBytes; if (!nameValid) { log.Debug("Invalid name value length '{0}'.", ProfileSearchRequest.Name.Length); details = "name"; } } if ((details == null) && (ProfileSearchRequest.Latitude != GpsLocation.NoLocationLocationType)) { GpsLocation locLat = new GpsLocation(ProfileSearchRequest.Latitude, 0); GpsLocation locLong = new GpsLocation(0, ProfileSearchRequest.Longitude); if (!locLat.IsValid()) { log.Debug("Latitude '{0}' is not a valid GPS latitude value.", ProfileSearchRequest.Latitude); details = "latitude"; } else if (!locLong.IsValid()) { log.Debug("Longitude '{0}' is not a valid GPS longitude value.", ProfileSearchRequest.Longitude); details = "longitude"; } } if ((details == null) && (ProfileSearchRequest.Latitude != GpsLocation.NoLocationLocationType)) { bool radiusValid = ProfileSearchRequest.Radius > 0; if (!radiusValid) { log.Debug("Invalid radius value '{0}'.", ProfileSearchRequest.Radius); details = "radius"; } } if ((details == null) && (ProfileSearchRequest.ExtraData != null)) { bool validLength = (Encoding.UTF8.GetByteCount(ProfileSearchRequest.ExtraData) <= PsMessageBuilder.MaxProfileSearchExtraDataLengthBytes); bool extraDataValid = RegexTypeValidator.ValidateRegex(ProfileSearchRequest.ExtraData); if (!validLength || !extraDataValid) { log.Debug("Invalid extraData regular expression filter."); details = "extraData"; } } if (details == null) { res = true; } else { ErrorResponse = MessageBuilder.CreateErrorInvalidValueResponse(RequestMessage, details); } log.Trace("(-):{0}", res); return(res); }