seekia/internal/network/mateCriteria/mateCriteria.go

172 lines
5.5 KiB
Go
Raw Normal View History

// 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
}