// mateCriteria provides functions to read/create profile criterias for server requests // These are used to filter mate profiles from a host using the user's desires // They have their own encoding package mateCriteria import "seekia/internal/desires/mateDesires" import "seekia/internal/encoding" import "seekia/internal/profiles/calculatedAttributes" import "seekia/internal/profiles/readProfiles" import messagepack "github.com/vmihailenco/msgpack/v5" import "strings" import "errors" //Outputs: // -bool: Criteria is valid // -bool: Profile fulfills criteria // -error func CheckIfMateProfileFulfillsCriteria(allowParameters bool, profileVersion int, rawProfileMap map[int]messagepack.RawMessage, criteriaBytes []byte)(bool, bool, error){ profileIsDisabled, _, err := readProfiles.GetFormattedProfileAttributeFromRawProfileMap(rawProfileMap, "Disabled") if (err != nil) { return false, false, err } if (profileIsDisabled == true){ return true, false, nil } exists, profileType, err := readProfiles.GetFormattedProfileAttributeFromRawProfileMap(rawProfileMap, "ProfileType") if (err != nil) { return false, false, err } if (exists == false){ return false, false, errors.New("CheckIfMateProfileFulfillsCriteria called profile missing ProfileType.") } if (profileType != "Mate"){ return false, false, errors.New("CheckIfMateProfileFulfillsCriteria called with non-mate profileType: " + profileType) } getAnyProfileAttributeFunction, err := calculatedAttributes.GetRetrieveAnyProfileAttributeIncludingCalculatedFunction(profileVersion, rawProfileMap) if (err != nil) { return false, false, err } criteriaMap := make(map[string]string) err = encoding.DecodeMessagePackBytes(false, criteriaBytes, &criteriaMap) if (err != nil) { return false, false, err } getAnyDesireFunction := func(desireName string)(bool, string, error){ desireValue, exists := criteriaMap[desireName] if (exists == false){ return false, "", nil } return true, desireValue, nil } allDesiresList := mateDesires.GetAllDesiresList(false) for _, desireName := range allDesiresList{ if (desireName == "HasMessagedMe" || desireName == "IHaveMessaged" || desireName == "HasRejectedMe" || desireName == "IsLiked" || desireName == "IsIgnored" || desireName == "IsMyContact" || desireName == "Distance" || desireName == "OffspringProbabilityOfAnyMonogenicDisease"){ // These desires are not used in criteria continue } if (desireName == "Wealth"){ // Criteria does not use the Wealth desire. It instead uses the WealthInGold desire continue } desireIsFilterAll := strings.HasSuffix(desireName, "_FilterAll") if (desireIsFilterAll == true){ // We use these to convey if a desire is a FilterAll desire continue } desireIsRequireResponse := strings.HasSuffix(desireName, "_RequireResponse") if (desireIsRequireResponse == true){ // We use these to convey if a desire is a ResponseRequired desire continue } if (allowParameters == false){ // We do not allow reliance on parameters to determine if the profile passes criteria // This will only be false when we are trying to determine if a host is malicious // A host's parameters might be different than our own // Without this bool, we could falsely believe that a host was malicious // The host could serve us a profile that fulfills our criteria when using their parameters, // while our parameters would result in the profile not fulfilling our criteria if (desireName == "WealthInGold"){ // Calculating this requires reliance on the currency exchange rate parameters continue } } desireAllowsResponseRequired, attributeNameToCheck := mateDesires.CheckIfDesireAllowsRequireResponse(desireName) if (desireAllowsResponseRequired == true){ // We check to see if the user requires a response getRequireResponseBool := func()bool{ requireResponseStatus, exists := criteriaMap[desireName + "_RequireResponse"] if (exists == true && requireResponseStatus == "Yes"){ return true } return false } requireResponseBool := getRequireResponseBool() profileContainsAttribute, _, _, err := getAnyProfileAttributeFunction(attributeNameToCheck) if (err != nil) { return false, false, err } if (profileContainsAttribute == false){ // Profile is missing a response if (requireResponseBool == true){ // Criteria requires a response return true, false, nil } // Criteria does not require a response continue } } getFilterAllBool := func()bool{ filterAllStatus, exists := criteriaMap[desireName + "_FilterAll"] if (exists == true && filterAllStatus == "Yes"){ return true } return false } filterAllBool := getFilterAllBool() if (filterAllBool == false){ // User passes this desire continue } anyDesireExists, desireIsValid, userResponseExists, userFulfillsDesire, err := mateDesires.CheckIfMateProfileFulfillsDesire(desireName, getAnyDesireFunction, getAnyProfileAttributeFunction) if (err != nil) { return false, false, err } if (anyDesireExists == false){ continue } if (desireIsValid == false){ // Criteria is invalid. Requestor must be malicious (or a bug in Seekia). return false, false, nil } if (userResponseExists == false){ // We already checked for this earlier return false, false, errors.New("CheckIfMateProfileFulfillsDesire says user has no response, but we already checked.") } if (userFulfillsDesire == false){ return true, false, nil } } // Profile passed all desires return true, true, nil }