/// <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);
        }
Beispiel #2
0
 public void NullsEqual()
 {
     Assert.Equal(0, _comparer.Compare(null, null));
     Assert.True(ByteArrayComparer.ArraysEqual(null, null));
     Assert.True(_comparer.Equals(null, null));
 }
        /// <summary>
        /// Checks whether the create activity request is valid.
        /// <para>This function does not verify the uniqueness of the activity identifier.
        /// It also does not verify whether a closer proximity server exists.</para>
        /// </summary>
        /// <param name="CreateActivityRequest">Create activity request part of the client's request message.</param>
        /// <param name="Client">Client that sent the request.</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 create activity request can be applied, false otherwise.</returns>
        public static bool ValidateCreateActivityRequest(CreateActivityRequest CreateActivityRequest, IncomingClient Client, ProxProtocolMessage RequestMessage, out ProxProtocolMessage ErrorResponse)
        {
            log.Trace("()");

            bool res = false;

            ErrorResponse = null;
            string details = null;

            if (CreateActivityRequest == null)
            {
                CreateActivityRequest = new CreateActivityRequest();
            }
            if (CreateActivityRequest.Activity == null)
            {
                CreateActivityRequest.Activity = new ActivityInformation();
            }
            if (CreateActivityRequest.Activity.ProfileServerContact == null)
            {
                CreateActivityRequest.Activity.ProfileServerContact = new ServerContactInfo();
            }

            SignedActivityInformation signedActivity = new SignedActivityInformation()
            {
                Activity  = CreateActivityRequest.Activity,
                Signature = RequestMessage.Request.ConversationRequest.Signature
            };


            if (ValidateSignedActivityInformation(signedActivity, Client.PublicKey, Client.MessageBuilder, RequestMessage, "", false, out ErrorResponse))
            {
                byte[] ownerPubKey = CreateActivityRequest.Activity.OwnerPublicKey.ToByteArray();

                if (!ByteArrayComparer.Equals(Client.PublicKey, ownerPubKey))
                {
                    log.Debug("Client's public key '{0}' does not match activity owner's public key '{1}'.", Client.PublicKey.ToHex(), ownerPubKey.ToHex());
                    details = "activity.ownerPublicKey";
                }


                if (details == null)
                {
                    int index = 0;
                    foreach (ByteString serverId in CreateActivityRequest.IgnoreServerIds)
                    {
                        if (serverId.Length != ProtocolHelper.NetworkIdentifierLength)
                        {
                            log.Debug("Ignored server ID #{0} is not a valid network ID as its length is {1} bytes.", index, serverId.Length);
                            details = "ignoreServerIds";
                            break;
                        }

                        index++;
                    }
                }

                if (details == null)
                {
                    res = true;
                }
                else
                {
                    ErrorResponse = Client.MessageBuilder.CreateErrorInvalidValueResponse(RequestMessage, details);
                }
            }

            log.Trace("(-):{0}", res);
            return(res);
        }
Beispiel #4
0
        /// <summary>
        /// Checks whether the contract received from user with hosting registration request is valid.
        /// <para>This function does not verify that the hosting plan exists.</para>
        /// </summary>
        /// <param name="IdentityPublicKey">Public key of the identity that wants to register hosting.</param>
        /// <param name="Contract">Description of the contract.</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 update request can be applied, false otherwise.</returns>
        public static bool ValidateRegisterHostingRequest(byte[] IdentityPublicKey, HostingPlanContract Contract, PsMessageBuilder MessageBuilder, PsProtocolMessage RequestMessage, out PsProtocolMessage ErrorResponse)
        {
            log.Trace("(IdentityPublicKey:'{0}')", IdentityPublicKey.ToHex());

            bool res = false;

            ErrorResponse = null;
            string details = null;

            if (Contract == null)
            {
                Contract = new HostingPlanContract();
            }

            if (!MessageBuilder.VerifySignedConversationRequestBodyPart(RequestMessage, Contract.ToByteArray(), IdentityPublicKey))
            {
                log.Debug("Contract signature is invalid.");
                ErrorResponse = MessageBuilder.CreateErrorInvalidSignatureResponse(RequestMessage);
                details       = "";
            }


            if (details == null)
            {
                byte[] contractPubKey = Contract.IdentityPublicKey.ToByteArray();
                bool   publicKeyValid = ByteArrayComparer.Equals(contractPubKey, IdentityPublicKey);
                if (!publicKeyValid)
                {
                    log.Debug("Contract public key '{0}' does not match client's public key '{1}'.", contractPubKey.ToHex(), IdentityPublicKey.ToHex());
                    details = "contract.identityPublicKey";
                }
            }

            if (details == null)
            {
                DateTime?startTime      = ProtocolHelper.UnixTimestampMsToDateTime(Contract.StartTime);
                bool     startTimeValid = (startTime != null) && ((startTime.Value - DateTime.UtcNow).TotalMinutes >= -60);

                if (!startTimeValid)
                {
                    if (startTime == null)
                    {
                        log.Debug("Invalid contract start time timestamp {0}.", Contract.StartTime);
                    }
                    else
                    {
                        log.Debug("Contract start time {0} is more than 1 hour in the past.", startTime.Value.ToString("yyyy-MM-dd HH:mm:ss"));
                    }
                    details = "contract.startTime";
                }
            }

            if (details == null)
            {
                int  typeSize  = Encoding.UTF8.GetByteCount(Contract.IdentityType);
                bool typeValid = (0 < typeSize) && (typeSize <= IdentityBase.MaxProfileTypeLengthBytes);
                if (!typeValid)
                {
                    log.Debug("Invalid contract identity type size in bytes {0}.", typeSize);
                    details = "contract.identityType";
                }
            }

            if (details == null)
            {
                res = true;
            }
            else
            {
                if (ErrorResponse == null)
                {
                    ErrorResponse = MessageBuilder.CreateErrorInvalidValueResponse(RequestMessage, details);
                }
            }

            log.Trace("(-):{0}", res);
            return(res);
        }
Beispiel #5
0
        /// <summary>
        /// Checks whether AddRelatedIdentityRequest request is valid.
        /// </summary>
        /// <param name="Client">Client that sent the request.</param>
        /// <param name="AddRelatedIdentityRequest">Client's request message to validate.</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 update request can be applied, false otherwise.</returns>
        public static bool ValidateAddRelatedIdentityRequest(IncomingClient Client, AddRelatedIdentityRequest AddRelatedIdentityRequest, PsMessageBuilder MessageBuilder, PsProtocolMessage RequestMessage, out PsProtocolMessage ErrorResponse)
        {
            log.Trace("()");

            bool res = false;

            ErrorResponse = null;
            string details = null;

            if (AddRelatedIdentityRequest == null)
            {
                AddRelatedIdentityRequest = new AddRelatedIdentityRequest();
            }
            if (AddRelatedIdentityRequest.CardApplication == null)
            {
                AddRelatedIdentityRequest.CardApplication = new CardApplicationInformation();
            }
            if (AddRelatedIdentityRequest.SignedCard == null)
            {
                AddRelatedIdentityRequest.SignedCard = new SignedRelationshipCard();
            }
            if (AddRelatedIdentityRequest.SignedCard.Card == null)
            {
                AddRelatedIdentityRequest.SignedCard.Card = new RelationshipCard();
            }

            CardApplicationInformation cardApplication = AddRelatedIdentityRequest.CardApplication;
            SignedRelationshipCard     signedCard      = AddRelatedIdentityRequest.SignedCard;
            RelationshipCard           card            = signedCard.Card;

            byte[] applicationId = cardApplication.ApplicationId.ToByteArray();
            byte[] cardId        = card.CardId.ToByteArray();

            if ((applicationId.Length == 0) || (applicationId.Length > RelatedIdentity.CardIdentifierLength))
            {
                log.Debug("Card application ID is invalid.");
                details = "cardApplication.applicationId";
            }

            if (details == null)
            {
                byte[] appCardId = cardApplication.CardId.ToByteArray();
                if (!ByteArrayComparer.Equals(cardId, appCardId))
                {
                    log.Debug("Card IDs in application card and relationship card do not match.");
                    details = "cardApplication.cardId";
                }
            }

            if (details == null)
            {
                if (card.ValidFrom > card.ValidTo)
                {
                    log.Debug("Card validFrom field is greater than validTo field.");
                    details = "signedCard.card.validFrom";
                }
                else
                {
                    DateTime?cardValidFrom = ProtocolHelper.UnixTimestampMsToDateTime(card.ValidFrom);
                    DateTime?cardValidTo   = ProtocolHelper.UnixTimestampMsToDateTime(card.ValidTo);
                    if (cardValidFrom == null)
                    {
                        log.Debug("Card validFrom value '{0}' is not a valid timestamp.", card.ValidFrom);
                        details = "signedCard.card.validFrom";
                    }
                    else if (cardValidTo == null)
                    {
                        log.Debug("Card validTo value '{0}' is not a valid timestamp.", card.ValidTo);
                        details = "signedCard.card.validTo";
                    }
                }
            }

            if (details == null)
            {
                byte[] issuerPublicKey = card.IssuerPublicKey.ToByteArray();
                bool   pubKeyValid     = (0 < issuerPublicKey.Length) && (issuerPublicKey.Length <= ProtocolHelper.MaxPublicKeyLengthBytes);
                if (!pubKeyValid)
                {
                    log.Debug("Issuer public key has invalid length {0} bytes.", issuerPublicKey.Length);
                    details = "signedCard.card.issuerPublicKey";
                }
            }

            if (details == null)
            {
                byte[] recipientPublicKey = card.RecipientPublicKey.ToByteArray();
                if (!ByteArrayComparer.Equals(recipientPublicKey, Client.PublicKey))
                {
                    log.Debug("Caller is not recipient of the card.");
                    details = "signedCard.card.recipientPublicKey";
                }
            }

            if (details == null)
            {
                if (!Client.MessageBuilder.VerifySignedConversationRequestBodyPart(RequestMessage, cardApplication.ToByteArray(), Client.PublicKey))
                {
                    log.Debug("Caller is not recipient of the card.");
                    ErrorResponse = Client.MessageBuilder.CreateErrorInvalidSignatureResponse(RequestMessage);
                    details       = "";
                }
            }

            if (details == null)
            {
                SemVer cardVersion = new SemVer(card.Version);
                if (!cardVersion.Equals(SemVer.V100))
                {
                    log.Debug("Card version is invalid or not supported.");
                    details = "signedCard.card.version";
                }
            }

            if (details == null)
            {
                if (Encoding.UTF8.GetByteCount(card.Type) > PsMessageBuilder.MaxRelationshipCardTypeLengthBytes)
                {
                    log.Debug("Card type is too long.");
                    details = "signedCard.card.type";
                }
            }

            if (details == null)
            {
                RelationshipCard emptyIdCard = new RelationshipCard()
                {
                    CardId             = ProtocolHelper.ByteArrayToByteString(new byte[RelatedIdentity.CardIdentifierLength]),
                    Version            = card.Version,
                    IssuerPublicKey    = card.IssuerPublicKey,
                    RecipientPublicKey = card.RecipientPublicKey,
                    Type      = card.Type,
                    ValidFrom = card.ValidFrom,
                    ValidTo   = card.ValidTo
                };

                byte[] hash = Crypto.Sha256(emptyIdCard.ToByteArray());
                if (!ByteArrayComparer.Equals(hash, cardId))
                {
                    log.Debug("Card ID '{0}' does not match its hash '{1}'.", cardId.ToHex(64), hash.ToHex());
                    details = "signedCard.card.cardId";
                }
            }

            if (details == null)
            {
                byte[] issuerSignature = signedCard.IssuerSignature.ToByteArray();
                byte[] issuerPublicKey = card.IssuerPublicKey.ToByteArray();
                if (!Ed25519.Verify(issuerSignature, cardId, issuerPublicKey))
                {
                    log.Debug("Issuer signature is invalid.");
                    details = "signedCard.issuerSignature";
                }
            }

            if (details == null)
            {
                res = true;
            }
            else
            {
                if (ErrorResponse == null)
                {
                    ErrorResponse = MessageBuilder.CreateErrorInvalidValueResponse(RequestMessage, details);
                }
            }

            log.Trace("(-):{0}", res);
            return(res);
        }
Beispiel #6
0
        /// <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>
        /// Compares this activity to other activity and returns list of changed properties.
        /// </summary>
        /// <param name="Other">Other activity to compare to.</param>
        /// <returns>Bit mask information about which properties are different.</returns>
        public ActivityChange CompareChangeTo(ActivityBase Other)
        {
            ActivityChange res = ActivityChange.None;

            SemVer thisVersion  = new SemVer(this.Version);
            SemVer otherVersion = new SemVer(Other.Version);

            if (!thisVersion.Equals(otherVersion))
            {
                res |= ActivityChange.Version;
            }

            if (this.ActivityId != Other.ActivityId)
            {
                res |= ActivityChange.ActivityId;
            }

            if (!ByteArrayComparer.Equals(this.OwnerIdentityId, Other.OwnerIdentityId))
            {
                res |= ActivityChange.OwnerIdentityId;
            }

            if (!ByteArrayComparer.Equals(this.OwnerPublicKey, Other.OwnerPublicKey))
            {
                res |= ActivityChange.OwnerPublicKey;
            }

            if (!ByteArrayComparer.Equals(this.OwnerProfileServerId, Other.OwnerProfileServerId))
            {
                res |= ActivityChange.OwnerProfileServerId;
            }

            if (!ByteArrayComparer.Equals(this.OwnerProfileServerIpAddress, Other.OwnerProfileServerIpAddress))
            {
                res |= ActivityChange.OwnerProfileServerIpAddress;
            }

            if (this.OwnerProfileServerPrimaryPort != Other.OwnerProfileServerPrimaryPort)
            {
                res |= ActivityChange.OwnerProfileServerPrimaryPort;
            }

            if (this.Type != Other.Type)
            {
                res |= ActivityChange.Type;
            }

            if (this.LocationLatitude != Other.LocationLatitude)
            {
                res |= ActivityChange.LocationLatitude;
            }

            if (this.LocationLongitude != Other.LocationLongitude)
            {
                res |= ActivityChange.LocationLongitude;
            }

            if (this.PrecisionRadius != Other.PrecisionRadius)
            {
                res |= ActivityChange.PrecisionRadius;
            }

            if (this.StartTime != Other.StartTime)
            {
                res |= ActivityChange.StartTime;
            }

            if (this.ExpirationTime != Other.ExpirationTime)
            {
                res |= ActivityChange.ExpirationTime;
            }

            if (this.ExtraData != Other.ExtraData)
            {
                res |= ActivityChange.ExtraData;
            }

            return(res);
        }