seekia/internal/network/networkJobs/networkJobs.go

1778 lines
68 KiB
Go
Raw Normal View History

// networkJobs provides functions to perform network jobs
// An example is downloading a user's inbox messages
// All of these jobs are run in the background by backgroundJobs (see backgroundJobs.go)
package networkJobs
//TODO: Add all of these jobs to backgroundJobs.go
//TODO: Implement these network jobs:
// Download message funded statuses for hosting
// Download message funded statuses for moderation
// Download message funded statuses for reading (this is to make sure messages we have received are funded)
// Download Host identity funded statuses
// Download Mate identity/profile funded statuses for hosting
// Download Mate identity/profile funded statuses for moderation
// Download Mate identity/profile funded statuses for browsing
// Download Mate identity/profile funded statuses for contacts/chat recipients
// Download report funded statuses for hosting
// Download report funded statuses for moderation
// Broadcast my Mate profile
// Broadcast my Host profile
// Broadcast my Moderator profile/reviews
// Broadcast my Mate messages
// Broadcast my Moderator messages
// Update Existing Mate User Profiles
// -We need a way for a client to user know if another user has changed their profile to no longer fulfill our downloads criteria
// -We need to download updated profiles for specific identities, without providing a Criteria in the request
// -We should download the newest viewable profile for all Mate users whose stored profile fulfills our criteria.
// -If the user's newer downloaded profile does not fulfill our criteria, we should delete their old profiles.
//TODO: More jobs
//TODO: Add limits to the number of hosts per job, and the number of items per request
// Otherwise, some of these jobs could take a very long time to complete, due to the number of hosts being contacted.
//TODO: The Mate outlier lists can be reduced by removing all of the mate outliers whose profiles/viewable statuses will be downloaded by other jobs.
import "seekia/internal/byteRange"
import "seekia/internal/badgerDatabase"
import "seekia/internal/contentMetadata"
import "seekia/internal/desires/myMateDesires"
import "seekia/internal/helpers"
import "seekia/internal/logger"
import "seekia/internal/messaging/myChatMessages"
import "seekia/internal/messaging/myInbox"
import "seekia/internal/messaging/peerChatKeys"
import "seekia/internal/moderation/myReviews"
import "seekia/internal/myBlockedUsers"
import "seekia/internal/myContacts"
import "seekia/internal/myIdentity"
import "seekia/internal/myLikedUsers"
import "seekia/internal/myRanges"
import "seekia/internal/mySettings"
import "seekia/internal/network/fundedStatus"
import "seekia/internal/network/mateCriteria"
import "seekia/internal/network/myMateCriteria"
import "seekia/internal/network/queryHosts"
import "seekia/internal/profiles/calculatedAttributes"
import "seekia/internal/profiles/profileStorage"
import "seekia/internal/profiles/readProfiles"
import "seekia/internal/profiles/viewableProfiles"
import "errors"
// This function will download and update the network-wide parameters files
func DownloadParameters(networkType byte)error{
isValid := helpers.VerifyNetworkType(networkType)
if (isValid == false){
networkTypeString := helpers.ConvertByteToString(networkType)
return errors.New("DownloadParameters called with invalid networkType: " + networkTypeString)
}
err := queryHosts.DownloadParametersFromHosts(true, networkType, 5)
if (err != nil) { return err }
return nil
}
// This function will download all of the network's newest viewable host/moderator profiles
// -This is used by all users to download host profiles
// -Users will only connect to Viewable hosts, whom are not banned
// -This is used by moderators/hosts to download all moderator profiles
// All hosts/moderators must download all newest viewable Moderator profiles
func DownloadAllNewestViewableUserProfiles(profileType string, networkType byte)error{
isValid := helpers.VerifyNetworkType(networkType)
if (isValid == false){
networkTypeString := helpers.ConvertByteToString(networkType)
return errors.New("DownloadAllNewestViewableUserProfiles called with invalid networkType: " + networkTypeString)
}
// This functions is not used for Mate profiles
// Mate profiles are always downloaded based on a range, whereas in this function, we download all newest viewable profiles.
if (profileType != "Host" && profileType != "Moderator"){
return errors.New("DownloadAllNewestViewableUserProfiles called with invalid profileType: " + profileType)
}
checkIfProfileShouldBeDownloaded := func(_ [28]byte, profileAuthor [16]byte, profileBroadcastTime int64)(bool, error){
// Check to see if our newest profile is older than the received profile
newestViewableProfileExists, _, _, _, storedProfileBroadcastTime, _, err := viewableProfiles.GetNewestViewableUserProfile(profileAuthor, networkType, true, false, true)
if (err != nil) { return false, err }
if (newestViewableProfileExists == false){
// We do not have any viewable profiles for this host
// Download this profile
return true, nil
}
if (profileBroadcastTime <= storedProfileBroadcastTime){
// Host we are retrieving from has a profile that is not newer than our existing profile
// We can skip this profile
return false, nil
}
// This profile is newer than our existing newest viewable profile
// We download it.
return true, nil
}
minimumRange, maximumRange := byteRange.GetMinimumMaximumIdentityHashBounds()
emptyList := make([][16]byte, 0)
err := queryHosts.DownloadProfilesFromHosts(false, networkType, profileType, minimumRange, maximumRange, emptyList, nil, true, true, false, checkIfProfileShouldBeDownloaded, 10)
if (err != nil) { return err }
return nil
}
// This function will download newest viewable mate profiles that fulfill user's downloads criteria
// It is used by users who are downloading profiles to find matches.
func DownloadMateProfilesToBrowse(networkType byte)error{
isValid := helpers.VerifyNetworkType(networkType)
if (isValid == false){
networkTypeString := helpers.ConvertByteToString(networkType)
return errors.New("DownloadMateProfilesToBrowse called with invalid networkType: " + networkTypeString)
}
minimumRange, maximumRange := byteRange.GetMinimumMaximumIdentityHashBounds()
getMyCriteria := func()([]byte, error){
exists, myCriteria, err := myMateCriteria.GetMyMateDownloadsCriteria()
if (err != nil) { return nil, err }
if (exists == false){
return nil, nil
}
return myCriteria, nil
}
myCriteria, err := getMyCriteria()
if (err != nil) { return err }
getDownloadAllBool := func()(bool, error){
//TODO: Fix below
desiresPruningMode := false
if (desiresPruningMode == true){
return true, nil
}
return false, nil
}
downloadAllBool, err := getDownloadAllBool()
if (err != nil) { return err }
emptyList := make([][16]byte, 0)
checkIfProfileShouldBeDownloaded := func(_ [28]byte, profileAuthor [16]byte, profileBroadcastTime int64)(bool, error){
// This function is only called if profile hash is not already downloaded
// We check if we have a profile that is newer (and viewable)
// If we have a newer viewable profile, we will skip downloading this profile
// We wont check, but if we have a newer profile that is not known to be viewable, we will still download this profile
// We will delete this older profile if and when the newer profile becomes viewable
profileExists, _, _, _, storedProfileBroadcastTime, _, err := viewableProfiles.GetNewestViewableUserProfile(profileAuthor, networkType, true, false, true)
if (err != nil) { return false, err }
if (profileExists == false){
return true, nil
}
if (storedProfileBroadcastTime >= profileBroadcastTime){
// The profile the host is offering is not newer than our existing
// We will skip it
return false, nil
}
// Profile is newer than the profile we already have, or we dont have any profile for this identity
// We will download it
return true, nil
}
err = queryHosts.DownloadProfilesFromHosts(false, networkType, "Mate", minimumRange, maximumRange, emptyList, myCriteria, true, true, downloadAllBool, checkIfProfileShouldBeDownloaded, 10)
if (err != nil) { return err }
return nil
}
// This function will download the newest viewable profiles for a user's mate outliers
// Outliers are either contacts, likes, or chat recipients.
// We download them so the user's client will have their profiles downloaded, even if the users do not fulfill our criteria
// This is done so that a user's client has the profiles for users within their contacts and users whom they are chatting with
// These are downloaded one-by-one to prevent hosts from learning a user's contacts/likes/chat recipients
func DownloadMateOutlierProfiles(outlierType string, networkType byte, missingOrExisting string)error{
if (outlierType != "Contacts" && outlierType != "Likes" && outlierType != "ChatRecipients"){
return errors.New("DownloadMateOutlierProfiles called with invalid outlierType: " + outlierType)
}
isValid := helpers.VerifyNetworkType(networkType)
if (isValid == false){
networkTypeString := helpers.ConvertByteToString(networkType)
return errors.New("DownloadMateOutlierProfiles called with invalid networkType: " + networkTypeString)
}
if (missingOrExisting != "Missing" && missingOrExisting != "Existing"){
return errors.New("DownloadMateOutlierProfiles called with invalid missingOrExisting: " + missingOrExisting)
}
//Outputs:
// -[][16]byte: List of identities
// -error
getMyOutlierIdentitiesList := func()([][16]byte, error){
if (outlierType == "Contacts"){
myContactIdentityHashesList, err := myContacts.GetMyContactsList("Mate")
if (err != nil) { return nil, err }
return myContactIdentityHashesList, nil
}
if (outlierType == "Likes"){
myLikedUsersList, err := myLikedUsers.GetMyLikedUsersList()
if (err != nil) { return nil, err }
return myLikedUsersList, nil
}
myIdentityExists, chatRecipientIdentityHashesList, err := myChatMessages.GetAllMyNonBlockedChatRecipients("Mate", networkType)
if (err != nil) { return nil, err }
if (myIdentityExists == false){
// Nothing to do, mate identity does not exist
emptyList := make([][16]byte, 0)
return emptyList, nil
}
return chatRecipientIdentityHashesList, nil
}
myOutlierIdentitiesList, err := getMyOutlierIdentitiesList()
if (err != nil) { return err }
if (len(myOutlierIdentitiesList) == 0){
return nil
}
helpers.RandomizeListOrder(myOutlierIdentitiesList)
// We will attempt to retrieve the newest viewable profiles for the identities
for _, userIdentityHash := range myOutlierIdentitiesList{
statusIsKnown, identityIsFunded, err := fundedStatus.GetIdentityIsFundedStatus(userIdentityHash, networkType)
if (err != nil) { return err }
if (statusIsKnown == true && identityIsFunded == false){
// The user's identity not funded
// This means that none of their profiles will be hosted by the network
// We will not try to download their profile, because it will not exist on the network
continue
}
// We check to see if the user's active chat keys exist
// We do this because even if a user's profile exists, it may not contain the user's newest chat keys
keysAreMissing, err := peerChatKeys.CheckIfUsersChatKeysAreMissing(userIdentityHash, networkType)
if (err != nil) { return err }
if (keysAreMissing == true){
if (missingOrExisting == "Existing"){
continue
}
}
profileExists, _, _, _, _, _, err := viewableProfiles.GetNewestViewableUserProfile(userIdentityHash, networkType, true, false, true)
if (err != nil) { return err }
if (profileExists == false){
if (missingOrExisting == "Existing"){
continue
}
} else {
if (missingOrExisting == "Missing"){
continue
}
}
checkIfProfileShouldBeDownloaded := func(_ [28]byte, profileAuthor [16]byte, profileBroadcastTime int64)(bool, error){
// We check to see if this profile is newer than our stored newest viewable profile for the identity
// If it is, we download the profile
profileExists, _, _, _, existingProfileBroadcastTime, _, err := viewableProfiles.GetNewestViewableUserProfile(profileAuthor, networkType, true, false, true)
if (err != nil) { return false, err }
if (profileExists == false){
return true, nil
}
if (profileBroadcastTime <= existingProfileBroadcastTime){
return false, nil
}
return true, nil
}
identitiesList := [][16]byte{userIdentityHash}
minimumRange, maximumRange := byteRange.GetMinimumMaximumIdentityHashBounds()
err = queryHosts.DownloadProfilesFromHosts(true, networkType, "Mate", minimumRange, maximumRange, identitiesList, nil, true, true, false, checkIfProfileShouldBeDownloaded, 1)
if (err != nil) { return err }
}
return nil
}
// This function will download profiles within our host range
// This should be called if a user is in Host mode.
func DownloadProfilesToHost(profileType string, networkType byte)error{
if (profileType != "Mate" && profileType != "Host" && profileType != "Moderator"){
return errors.New("DownloadProfilesToHost called with invalid profileType: " + profileType)
}
isValid := helpers.VerifyNetworkType(networkType)
if (isValid == false){
networkTypeString := helpers.ConvertByteToString(networkType)
return errors.New("DownloadProfilesToHost called with invalid networkType: " + networkTypeString)
}
hostModeEnabled, hostingAny, myIdentitiesToHostRangeStart, myIdentitiesToHostRangeEnd, err := myRanges.GetMyIdentitiesToHostRange(profileType)
if (err != nil) { return err }
if (hostModeEnabled == false){
// Host mode must have been turned off recently.
err := logger.AddLogEntry("Network", "DownloadProfilesToHost called when Host mode is disabled.")
if (err != nil) { return err }
return nil
}
if (hostingAny == false) {
// No profiles to host of this profileType. Nothing to do.
return nil
}
checkIfProfileShouldBeDownloaded := func(profileHash [28]byte, profileAuthor [16]byte, profileBroadcastTime int64)(bool, error){
//TODO
// First we check the moderator consensus of the identity
// If consensus is ban, we will only download profile if time it has been banned is not older than maximum time to store banned content
// Then we check to see if we have profile metadata
// If we don't, we download the profile.
// At this point, we have the profile metadata but not the profile
// That means we thought it was worth deleting at one point (or it was downloaded for mate/moderator reasons)
// Then we check the moderator consensus of profile
// If consensus is ban, we will only download profile if time it has been banned is not older than maximum time to store banned content
// Otherwise, we will not download profile
// At this point, consensus for profile is approve/none and identity is not banned
// We then check to see if we have a newer profile by the same identity
// If there is no newer profile, we download the profile
// At this point, there is a newer profile for the identity
// We only want to download this older profile if it can be used by moderators to determine if the identity should be banned
// We dont want this to be abused, if an attacker created a report for many old profiles that existed on the network, they could cause hosts to download all those old profiles
// So, if profile has been approved for a long enough period of time, it does not need to be hosted anymore
// We cannot trust the broadcastTimes for reviews, reports, or profiles, so each host keeps track of the time that a consensus has existed based on the reviews it has downloaded
// We use verdictHistory for this
// If offered profile is approved, we check to see if profile has been approved for at least the maximum time to store old approved profiles
// If it has been approved for at least that long, we will not download the profile
// If it has been approved but not for that long, we will download the profile, just so that moderators can determine if consensus is wrong before profile is dropped from network
// At this point, consensus for profile is none, and it is not the user's newest profile
// We check to see if any ban reviews and reports exist for the profile
// If there are any ban reviews or reports, we check to see how long time that consensus has been none.
// If that time is older than maximum time to store banned and reported no consensus old content, we will not download it
// If that time has not passed, we will download the profile
// At this point, the profile has no ban reviews/reports and consensus is none
// We will check if profile's no consensus time is older than maximum time to store unreported and unbanned no consensus old content
// If the profile is older than that time, we will not download it
// If the profile is newer than that time, we will download it
// This is quite complicated and could be simplified
// Basically, we want to profiles on the network for long enough so the moderators can review them and ban any moderators who wrongly banned/approved them
return true, nil
}
getGetViewableProfilesOnlyBool := func()(bool, error){
if (profileType == "Host"){
// Hosts must download all peer host profiles, regardless of viewable status
// This is because (a) malicious moderator(s) could ban all Host profiles and cripple the network
// Host profiles have no images, so they are much less legally risky to download anyway.
//TODO: Make it clear in the GUI that hosts will host all unviewable host profiles, even if HostUnviewableProfiles is disabled.
return false, nil
}
exists, hostUnviewableStatus, err := mySettings.GetSetting("HostUnviewableProfilesOnOffStatus")
if (err != nil) { return false, err }
if (exists == true && hostUnviewableStatus == "On") {
return false, nil
}
return true, nil
}
getViewableProfilesOnlyBool, err := getGetViewableProfilesOnlyBool()
if (err != nil) { return err }
emptyList := make([][16]byte, 0)
err = queryHosts.DownloadProfilesFromHosts(true, networkType, profileType, myIdentitiesToHostRangeStart, myIdentitiesToHostRangeEnd, emptyList, nil, false, getViewableProfilesOnlyBool, false, checkIfProfileShouldBeDownloaded, 10)
if (err != nil) { return err }
return nil
}
// This function will download profiles within our moderation range
func DownloadProfilesToModerate(profileType string, networkType byte)error{
if (profileType != "Mate" && profileType != "Host" && profileType != "Moderator"){
return errors.New("DownloadProfilesToModerate called with invalid profileType: " + profileType)
}
isValid := helpers.VerifyNetworkType(networkType)
if (isValid == false){
networkTypeString := helpers.ConvertByteToString(networkType)
return errors.New("DownloadProfilesToModerate called with invalid networkType: " + networkTypeString)
}
moderatorModeEnabled, moderatingAny, myIdentitiesToModerateRangeStart, myIdentitiesToModerateRangeEnd, err := myRanges.GetMyIdentitiesToModerateRange(profileType)
if (err != nil) { return err }
if (moderatorModeEnabled == false){
// This should not happen unless moderator mode was turned off recently
err := logger.AddLogEntry("Network", "DownloadProfilesToModerate called when moderator mode is disabled.")
if (err != nil) { return err }
return nil
}
if (moderatingAny == false){
// We are not moderating any profiles
return nil
}
checkIfProfileShouldBeDownloaded := func(profileHash [28]byte, profileIdentityHash [16]byte, profileBroadcastTime int64)(bool, error){
//TODO: See if we have already reviewed the profile, if yes, then we don't need to download it.
// Also, if we have the profile's metadata, and it is not the user's newest profile, and it has no ban reviews, we don't need to download it.
// We must have the profile metadata downloaded because it is the only way we can be sure the profile has no ban reviews
return true, nil
}
emptyList := make([][16]byte, 0)
err = queryHosts.DownloadProfilesFromHosts(true, networkType, profileType, myIdentitiesToModerateRangeStart, myIdentitiesToModerateRangeEnd, emptyList, nil, false, false, false, checkIfProfileShouldBeDownloaded, 10)
if (err != nil) { return err }
return nil
}
// This function will download messages in our inboxes
// Each inbox has to be queried seperately from a different host to prevent linking the inboxes together
func DownloadMyInboxMessages(identityType string, networkType byte)error{
if (identityType != "Mate" && identityType != "Moderator"){
return errors.New("DownloadMyInboxMessages called with invalid identityType: " + identityType)
}
isValid := helpers.VerifyNetworkType(networkType)
if (isValid == false){
networkTypeString := helpers.ConvertByteToString(networkType)
return errors.New("DownloadMyInboxMessages called with invalid networkType: " + networkTypeString)
}
myIdentityFound, myIdentityHash, err := myIdentity.GetMyIdentityHash(identityType)
if (err != nil) { return err }
if (myIdentityFound == false){
return nil
}
myInboxesList, err := myInbox.GetAllMyActiveInboxes(myIdentityHash, networkType)
if (err != nil) { return err }
helpers.RandomizeListOrder(myInboxesList)
minimumInboxRange, maximumInboxRange := byteRange.GetMinimumMaximumInboxBounds()
for _, inbox := range myInboxesList{
inboxAsList := [][10]byte{inbox}
checkIfMessageShouldBeDownloaded := func(messageHash [26]byte)(bool, error){
metadataExists, _, messageNetworkType, _, messageInbox, _, err := contentMetadata.GetMessageMetadata(messageHash)
if (err != nil) { return false, err }
if (metadataExists == false){
return true, nil
}
// We already downloaded the message at some point
// First we see if the message inbox/networkType matches what we requested
if (messageNetworkType != networkType || messageInbox != inbox){
// The host is offering us a message we know does not belong to the inbox/networkType we requested
// The host is malicious.
// We download the message so they do not learn that we downloaded this message at one point (to prevent fingerprinting)
// We should have already checked for this within queryHosts.DownloadMessagesFromHosts
// The only way we would not have known is if we downloaded the message recently
err := logger.AddLogEntry("Network", "checkIfMessageShouldBeDownloaded called when inbox/networkType does not match message we have metadata for.")
if (err != nil) { return false, err }
return true, nil
}
// Now we check to see if we have already imported, deleted, or failed to decrypt the message
isDeleted, err := myChatMessages.CheckIfMessageIsDeleted(messageHash)
if (err != nil) { return false, err }
if (isDeleted == true){
return false, nil
}
isUndecryptable, err := myChatMessages.CheckIfMessageIsUndecryptable(messageHash)
if (err != nil) { return false, err }
if (isUndecryptable == true){
return false, nil
}
isImported, err := myChatMessages.CheckIfMessageIsImported(messageHash, identityType, messageNetworkType)
if (err != nil) { return false, err }
if (isImported == true){
return false, nil
}
return true, nil
}
err := queryHosts.DownloadMessagesFromHosts(false, networkType, minimumInboxRange, maximumInboxRange, inboxAsList, false, false, checkIfMessageShouldBeDownloaded, 1)
if (err != nil) { return err }
}
return nil
}
// This function will download messages within our hosting range
// This should be called periodically if we are in Host mode
func DownloadMessagesToHost(networkType byte)error{
isValid := helpers.VerifyNetworkType(networkType)
if (isValid == false){
networkTypeString := helpers.ConvertByteToString(networkType)
return errors.New("DownloadMessagesToHost called with invalid networkType: " + networkTypeString)
}
hostModeEnabled, hostingAny, myInboxRangeStart, myInboxRangeEnd, err := myRanges.GetMyInboxesToHostRange()
if (err != nil) { return err }
if (hostModeEnabled == false){
// Host mode is disabled. Nothing to do.
// This should not happen unless host mode was turned off recently
err := logger.AddLogEntry("Network", "DownloadMessagesToHost called when Host mode is disabled.")
if (err != nil) { return err }
return nil
}
if (hostingAny == false){
// Not hosting any messages. Nothing to do.
return nil
}
// We are not retrieving based on a list of inboxes
inboxesToRetrieveList := make([][10]byte, 0)
getGetViewableMessagesOnlyBool := func()(bool, error){
exists, hostUnviewableStatus, err := mySettings.GetSetting("HostUnviewableMessagesOnOffStatus")
if (err != nil) { return false, err }
if (exists == true && hostUnviewableStatus == "On") {
return false, nil
}
return true, nil
}
getViewableMessagesOnlyBool, err := getGetViewableMessagesOnlyBool()
if (err != nil) { return err }
checkIfMessageShouldBeDownloaded := func(inputMessageHash [26]byte)(bool, error){
//TODO:
// This should be similar to the function in DownloadProfilesToHost
return true, nil
}
err = queryHosts.DownloadMessagesFromHosts(true, networkType, myInboxRangeStart, myInboxRangeEnd, inboxesToRetrieveList, getViewableMessagesOnlyBool, false, checkIfMessageShouldBeDownloaded, 5)
if (err != nil) { return err }
return nil
}
// This function will download messages within our moderation range
// This should be called periodically if the user is in Moderator mode.
func DownloadMessagesToModerate(networkType byte)error{
isValid := helpers.VerifyNetworkType(networkType)
if (isValid == false){
networkTypeString := helpers.ConvertByteToString(networkType)
return errors.New("DownloadMessagesToModerate called with invalid networkType: " + networkTypeString)
}
moderatorModeEnabled, moderatingAny, myInboxRangeStart, myInboxRangeEnd, err := myRanges.GetMyInboxesToModerateRange()
if (err != nil) { return err }
if (moderatorModeEnabled == false){
// User must have disabled moderator mode recently
err := logger.AddLogEntry("Network", "DownloadMessagesToModerate called when user is not in Moderator mode.")
if (err != nil) { return err }
return nil
}
if (moderatingAny == false){
// We are not moderating any messages.
return nil
}
checkIfMessageShouldBeDownloaded := func(inputMessageHash [26]byte)(bool, error){
// This function is only called if we don't already have the message downloaded
metadataExists, _, messageNetworkType, _, messageInbox, _, err := contentMetadata.GetMessageMetadata(inputMessageHash)
if (err != nil) { return false, err }
if (metadataExists == false){
return true, nil
}
if (messageNetworkType != networkType){
// The host is offering us a message we know does not belong to the networkType we requested
// The host is malicious.
// We download the message so they do not learn that we downloaded this message at one point (to prevent fingerprinting)
return true, nil
}
isWithinRequestRange, err := byteRange.CheckIfInboxIsWithinRange(myInboxRangeStart, myInboxRangeEnd, messageInbox)
if (err != nil) { return false, err }
if (isWithinRequestRange == false){
// The host is offering us a message we know does not belong to the inbox range we requested
// The host is malicious.
// We download the message so they do not learn that we downloaded this message at one point (to prevent fingerprinting)
return true, nil
}
myIdentityExists, messageMetadataIsKnown, iHaveReviewed, _, err := myReviews.GetMyNewestMessageModerationVerdict(inputMessageHash)
if (err != nil) { return false, err }
if (myIdentityExists == false){
// Without an identity, we would only use moderator mode to browse content
// We should therefore download the message
return true, nil
}
if (messageMetadataIsKnown == false){
// We must have just deleted our message metadata
//TODO: Log this
return true, nil
}
if (iHaveReviewed == true){
// We can skip messages that the user has already reviewed
//TODO: Create a mode where this behavior can be disabled
// Some moderators may want to keep those messages so they can reference them again, until they
// expire from the network, or they have been sufficiently banned
return false, nil
}
return true, nil
}
emptyList := make([][10]byte, 0)
err = queryHosts.DownloadMessagesFromHosts(true, networkType, myInboxRangeStart, myInboxRangeEnd, emptyList, false, true, checkIfMessageShouldBeDownloaded, 5)
if (err != nil) { return err }
return nil
}
// This function will download all reviews banning moderator identities.
// This is necessary if Moderator/Host mode is enabled.
// These reviews determine which moderators are banned, so they are needed to determine the moderation verdict for all identities/content.
// Thus, they must be downloaded by all hosts and moderators.
func DownloadModeratorIdentityBanningReviews(networkType byte)error{
isValid := helpers.VerifyNetworkType(networkType)
if (isValid == false){
networkTypeString := helpers.ConvertByteToString(networkType)
return errors.New("DownloadModeratorIdentityBanningReviews called with invalid networkType: " + networkTypeString)
}
minimumRange, maximumRange := byteRange.GetMinimumMaximumIdentityHashBounds()
emptyListA := make([][16]byte, 0)
emptyListB := make([][16]byte, 0)
checkIfReviewShouldBeDownloadedFunction := func(_ [29]byte, reviewedHash []byte)(bool, error){
reviewedType, err := helpers.GetReviewedTypeFromReviewedHash(reviewedHash)
if (err != nil) { return false, err }
if (reviewedType != "Identity" && reviewedType != "Profile" && reviewedType != "Attribute"){
return false, errors.New("DownloadIdentityReviewsFromHosts not checking that identity reviewed hash is valid.")
}
if (reviewedType == "Identity"){
return true, nil
}
return false, nil
}
err := queryHosts.DownloadIdentityReviewsFromHosts(false, networkType, "Moderator", minimumRange, maximumRange, emptyListA, emptyListB, checkIfReviewShouldBeDownloadedFunction, 5)
if (err != nil) { return err }
return nil
}
// This function will download reviews for identities/profiles/attributes within our Host range
// It is called periodically if Host mode is enabled.
func DownloadIdentityReviewsToHost(identityTypeToRetrieve string, networkType byte)error{
if (identityTypeToRetrieve != "Mate" && identityTypeToRetrieve != "Host" && identityTypeToRetrieve != "Moderator"){
return errors.New("DownloadIdentityReviewsToHost called with invalid identityTypeToRetrieve: " + identityTypeToRetrieve)
}
isValid := helpers.VerifyNetworkType(networkType)
if (isValid == false){
networkTypeString := helpers.ConvertByteToString(networkType)
return errors.New("DownloadIdentityReviewsToHost called with invalid networkType: " + networkTypeString)
}
hostModeEnabled, hostingAnyIdentities, myIdentityRangeStart, myIdentityRangeEnd, err := myRanges.GetMyIdentitiesToHostRange(identityTypeToRetrieve)
if (err != nil) { return err }
if (hostModeEnabled == false){
// Host mode is disabled. Nothing to do.
// This should not happen unless host mode was turned off recently
err := logger.AddLogEntry("Network", "DownloadIdentityReviewsToHost called when Host mode is disabled.")
if (err != nil) { return err }
return nil
}
if (hostingAnyIdentities == false){
// We are not hosting any identity reviews of the provided identityType
return nil
}
emptyListA := make([][16]byte, 0)
emptyListB := make([][16]byte, 0)
checkIfReviewShouldBeDownloadedFunction := func(_ [29]byte, _ []byte)(bool, error){
//TODO:
// We want to defend against downloading reviews that we will delete immediately.
// Don't download reviews by moderators who have been banned for a long enough period of time
// Don't download reviews for content/identities that have been expired for long enough
// Any hosts who offers us content that should no longer exist on the network would be a malicious host.
return true, nil
}
err = queryHosts.DownloadIdentityReviewsFromHosts(false, networkType, identityTypeToRetrieve, myIdentityRangeStart, myIdentityRangeEnd, emptyListA, emptyListB, checkIfReviewShouldBeDownloadedFunction, 5)
if (err != nil) { return err }
return nil
}
// This function will download reviews for messages within our Host range
// It is called periodically if Host mode is enabled.
func DownloadMessageReviewsToHost(networkType byte)error{
isValid := helpers.VerifyNetworkType(networkType)
if (isValid == false){
networkTypeString := helpers.ConvertByteToString(networkType)
return errors.New("DownloadMessageReviewsToHost called with invalid networkType: " + networkTypeString)
}
hostModeEnabled, hostingAnyInboxes, myInboxRangeStart, myInboxRangeEnd, err := myRanges.GetMyInboxesToHostRange()
if (err != nil) { return err }
if (hostModeEnabled == false){
// Host mode is disabled. Nothing to do.
// This should not happen unless host mode was turned off recently
err := logger.AddLogEntry("Network", "DownloadMessageReviewsToHost called when Host mode is disabled.")
if (err != nil) { return err }
return nil
}
if (hostingAnyInboxes == false){
// We are not hosting any message reviews
return nil
}
emptyListA := make([][26]byte, 0)
emptyListB := make([][16]byte, 0)
emptyMap := make(map[[26]byte][10]byte)
checkIfReviewShouldBeDownloadedFunction := func(reviewHash [29]byte, messageHash [26]byte)(bool, error){
//TODO:
// We want to defend against downloading reviews that we will delete immediately.
// Don't download reviews by moderators who have been banned for a long enough period of time
// Don't download reviews for messages that have been expired for long enough
// Any hosts who offers us content that should no longer exist on the network would be a malicious host.
return true, nil
}
err = queryHosts.DownloadMessageReviewsFromHosts(false, networkType, myInboxRangeStart, myInboxRangeEnd, emptyListA, emptyListB, emptyMap, checkIfReviewShouldBeDownloadedFunction, 5)
if (err != nil) { return err }
return nil
}
// This function will download reviews for identities/profiles/attributes within our moderation range
// This will be called periodically if Moderator mode is enabled.
func DownloadIdentityReviewsForModeration(identityTypeToRetrieve string, networkType byte)error{
if (identityTypeToRetrieve != "Mate" && identityTypeToRetrieve != "Host" && identityTypeToRetrieve != "Moderator"){
return errors.New("DownloadIdentityReviewsForModeration called with invalid identityTypeToRetrieve: " + identityTypeToRetrieve)
}
isValid := helpers.VerifyNetworkType(networkType)
if (isValid == false){
networkTypeString := helpers.ConvertByteToString(networkType)
return errors.New("DownloadIdentityReviewsForModeration called with invalid networkType: " + networkTypeString)
}
moderatorModeEnabled, moderatingAnyIdentities, myIdentityRangeStart, myIdentityRangeEnd, err := myRanges.GetMyIdentitiesToModerateRange(identityTypeToRetrieve)
if (err != nil) { return err }
if (moderatorModeEnabled == false){
// Moderator mode must have been disabled recently
err := logger.AddLogEntry("Network", "DownloadIdentityReviewsForModeration called when user is not in Moderator mode.")
if (err != nil) { return err }
return nil
}
if (moderatingAnyIdentities == false){
// We are not moderating any identities of the provided identityType
// We don't need to download any reviews for the identities
return nil
}
emptyListA := make([][16]byte, 0)
emptyListB := make([][16]byte, 0)
checkIfReviewShouldBeDownloadedFunction := func(reviewHash [29]byte, reviewedHash []byte)(bool, error){
//TODO
// see DownloadIdentityReviewsToHost for some ideas on what restrictions to add
return true, nil
}
err = queryHosts.DownloadIdentityReviewsFromHosts(false, networkType, identityTypeToRetrieve, myIdentityRangeStart, myIdentityRangeEnd, emptyListA, emptyListB, checkIfReviewShouldBeDownloadedFunction, 5)
if (err != nil) { return err }
return nil
}
// This function will download reviews for messages within our moderation range
// This will be called periodically if Moderator mode is enabled.
func DownloadMessageReviewsForModeration(networkType byte)error{
isValid := helpers.VerifyNetworkType(networkType)
if (isValid == false){
networkTypeString := helpers.ConvertByteToString(networkType)
return errors.New("DownloadMessageReviewsForModeration called with invalid networkType: " + networkTypeString)
}
moderatorModeEnabled, moderatingAnyInboxes, myInboxRangeStart, myInboxRangeEnd, err := myRanges.GetMyInboxesToModerateRange()
if (err != nil) { return err }
if (moderatorModeEnabled == false){
// Moderator mode must have been disabled recently
err := logger.AddLogEntry("Network", "DownloadMessageReviewsForModeration called when user is not in Moderator mode.")
if (err != nil) { return err }
return nil
}
if (moderatingAnyInboxes == false){
// We are not moderating any message inboxes
// We don't need to download any message reviews
return nil
}
emptyListA := make([][26]byte, 0)
emptyListB := make([][16]byte, 0)
emptyMap := make(map[[26]byte][10]byte)
checkIfReviewShouldBeDownloadedFunction := func(reviewHash [29]byte, reviewedMessageHash [26]byte)(bool, error){
//TODO
// see DownloadMessageReviewsToHost for some ideas on what restrictions to add
return true, nil
}
err = queryHosts.DownloadMessageReviewsFromHosts(false, networkType, myInboxRangeStart, myInboxRangeEnd, emptyListA, emptyListB, emptyMap, checkIfReviewShouldBeDownloadedFunction, 5)
if (err != nil) { return err }
return nil
}
// This function will download reports for identities/profiles/attributes within our host range
// It must be called if Host mode is enabled
func DownloadIdentityReportsToHost(identityTypeToRetrieve string, networkType byte)error{
if (identityTypeToRetrieve != "Mate" && identityTypeToRetrieve != "Host" && identityTypeToRetrieve != "Moderator"){
return errors.New("DownloadIdentityReportsToHost called with invalid identityTypeToRetrieve: " + identityTypeToRetrieve)
}
isValid := helpers.VerifyNetworkType(networkType)
if (isValid == false){
networkTypeString := helpers.ConvertByteToString(networkType)
return errors.New("DownloadIdentityReportsToHost called with invalid networkType: " + networkTypeString)
}
hostModeEnabled, hostingAnyIdentities, myIdentityRangeStart, myIdentityRangeEnd, err := myRanges.GetMyIdentitiesToHostRange(identityTypeToRetrieve)
if (err != nil) { return err }
if (hostModeEnabled == false){
// Host mode is disabled. Nothing to do.
// This should not happen unless host mode was turned off recently
err := logger.AddLogEntry("Network", "DownloadIdentityReportsToHost called when Host mode is disabled.")
if (err != nil) { return err }
return nil
}
if (hostingAnyIdentities == false){
return nil
}
checkIfReportShouldBeDownloaded := func(reportHash [30]byte, reportedHash []byte)(bool, error){
//TODO
// see DownloadReviewsToHost for some ideas on what restrictions to add
return true, nil
}
emptyList := make([][16]byte, 0)
err = queryHosts.DownloadIdentityReportsFromHosts(true, networkType, identityTypeToRetrieve, myIdentityRangeStart, myIdentityRangeEnd, emptyList, checkIfReportShouldBeDownloaded, 5)
if (err != nil) { return err }
return nil
}
// This function will download reports for messages within our host range
// It must be called if Host mode is enabled
func DownloadMessageReportsToHost(networkType byte)error{
isValid := helpers.VerifyNetworkType(networkType)
if (isValid == false){
networkTypeString := helpers.ConvertByteToString(networkType)
return errors.New("DownloadMessageReportsToHost called with invalid networkType: " + networkTypeString)
}
hostModeEnabled, hostingAnyInboxes, myInboxRangeStart, myInboxRangeEnd, err := myRanges.GetMyInboxesToHostRange()
if (err != nil) { return err }
if (hostModeEnabled == false){
// Host mode is disabled. Nothing to do.
// This should not happen unless host mode was turned off recently
err := logger.AddLogEntry("Network", "DownloadMessageReportsToHost called when Host mode is disabled.")
if (err != nil) { return err }
return nil
}
if (hostingAnyInboxes == false){
return nil
}
checkIfReportShouldBeDownloaded := func(reportHash [30]byte, reportedMessageHash [26]byte)(bool, error){
//TODO
// see DownloadMessageReportsToHost for some ideas on what restrictions to add
return true, nil
}
emptyList := make([][26]byte, 0)
emptyMap := make(map[[26]byte][10]byte)
err = queryHosts.DownloadMessageReportsFromHosts(true, networkType, myInboxRangeStart, myInboxRangeEnd, emptyList, emptyMap, checkIfReportShouldBeDownloaded, 5)
if (err != nil) { return err }
return nil
}
// This function will download reports for identities/profiles/attributes within our moderation range
// It is called periodically if Moderator mode is enabled
func DownloadIdentityReportsForModeration(identityTypeToRetrieve string, networkType byte)error{
if (identityTypeToRetrieve != "Mate" && identityTypeToRetrieve != "Host" && identityTypeToRetrieve != "Moderator"){
return errors.New("DownloadIdentityReportsForModeration called with invalid identityTypeToRetrieve: " + identityTypeToRetrieve)
}
isValid := helpers.VerifyNetworkType(networkType)
if (isValid == false){
networkTypeString := helpers.ConvertByteToString(networkType)
return errors.New("DownloadIdentityReportsForModeration called with invalid networkType: " + networkTypeString)
}
moderatorModeEnabled, moderatingAny, myRangeStart, myRangeEnd, err := myRanges.GetMyIdentitiesToModerateRange(identityTypeToRetrieve)
if (err != nil) { return err }
if (moderatorModeEnabled == false){
// Moderator mode must have been disabled recently
err := logger.AddLogEntry("Network", "DownloadIdentityReportsForModeration called when user is not in Moderator mode.")
if (err != nil) { return err }
return nil
}
if (moderatingAny == false){
// Not moderating any identities of provided identityType
// We don't need to download reports
return nil
}
checkIfReportShouldBeDownloaded := func(reportHash [30]byte, reportedHash []byte)(bool, error){
//TODO
// see DownloadIdentityReviewsToHost for some ideas on what restrictions to add
return true, nil
}
emptyList := make([][16]byte, 0)
err = queryHosts.DownloadIdentityReportsFromHosts(true, networkType, identityTypeToRetrieve, myRangeStart, myRangeEnd, emptyList, checkIfReportShouldBeDownloaded, 5)
if (err != nil) { return err }
return nil
}
// This function will download reports for messages/profiles/identities within our moderation range
// It is called periodically if Moderator mode is enabled
func DownloadMessageReportsForModeration(networkType byte)error{
isValid := helpers.VerifyNetworkType(networkType)
if (isValid == false){
networkTypeString := helpers.ConvertByteToString(networkType)
return errors.New("DownloadMessageReportsForModeration called with invalid networkType: " + networkTypeString)
}
moderatorModeEnabled, moderatingAny, myInboxRangeStart, myInboxRangeEnd, err := myRanges.GetMyInboxesToModerateRange()
if (err != nil) { return err }
if (moderatorModeEnabled == false){
// Moderator mode must have been disabled recently
err := logger.AddLogEntry("Network", "DownloadMessageReportsForModeration called when user is not in Moderator mode.")
if (err != nil) { return err }
return nil
}
if (moderatingAny == false){
// Not moderating any messages
// We don't need to download any message reports
return nil
}
checkIfReportShouldBeDownloaded := func(reportHash [30]byte, reportedMessageHash [26]byte)(bool, error){
//TODO
// see DownloadMessageReviewsToHost for some ideas on what restrictions to add
return true, nil
}
emptyList := make([][26]byte, 0)
emptyMap := make(map[[26]byte][10]byte)
err = queryHosts.DownloadMessageReportsFromHosts(true, networkType, myInboxRangeStart, myInboxRangeEnd, emptyList, emptyMap, checkIfReportShouldBeDownloaded, 5)
if (err != nil) { return err }
return nil
}
// This function will download trusted viewable statuses for downloaded host identities/profiles.
// Downloading these statuses is not needed if a user is able to determine these statuses themselves
//
// Hosts who are hosting host identities will download all host profile reviews, so they can calculate the viewable status themselves
// Moderators who are moderating Host identities can also calculate the viewable status for host identities/profiles within their moderation range
func DownloadHostViewableStatuses(networkType byte, knownOrUnknown string)error{
isValid := helpers.VerifyNetworkType(networkType)
if (isValid == false){
networkTypeString := helpers.ConvertByteToString(networkType)
return errors.New("DownloadHostViewableStatuses called with invalid networkType: " + networkTypeString)
}
if (knownOrUnknown != "Known" && knownOrUnknown != "Unknown"){
return errors.New("DownloadHostViewableStatuses called with invalid knownOrUnknown: " + knownOrUnknown)
}
hostModeEnabled, hostingAny, _, _, err := myRanges.GetMyIdentitiesToHostRange("Host")
if (err != nil) { return err }
if (hostModeEnabled == true && hostingAny == true){
// We are already hosting all reviews for host identities, so we can calculate the viewable status of host profiles ourselves
// Thus, we don't need to download any trusted viewable statuses for host identitites/profiles
return nil
}
allHostProfileIdentityHashesList, err := badgerDatabase.GetAllProfileIdentityHashes("Host")
if (err != nil) { return err }
getRelevantHostProfileIdentityHashesList := func()([][16]byte, error){
moderatorModeEnabled, moderatingAny, identityRangeStart, identityRangeEnd, err := myRanges.GetMyIdentitiesToModerateRange("Host")
if (err != nil) { return nil, err }
if (moderatorModeEnabled == false || moderatingAny == false){
// We are not moderating any host identities
// We do not need to reduce the list at all
return allHostProfileIdentityHashesList, nil
}
relevantHostProfileIdentityHashesList := make([][16]byte, 0)
for _, hostIdentityHash := range allHostProfileIdentityHashesList{
isWithinMyRange, err := byteRange.CheckIfIdentityHashIsWithinRange(identityRangeStart, identityRangeEnd, hostIdentityHash)
if (err != nil) { return nil, err }
if (isWithinMyRange == true){
// We don't need to download this host's viewable status, because we can calculate it ourselves.
continue
}
relevantHostProfileIdentityHashesList = append(relevantHostProfileIdentityHashesList, hostIdentityHash)
}
return relevantHostProfileIdentityHashesList, nil
}
relevantHostProfileIdentityHashesList, err := getRelevantHostProfileIdentityHashesList()
if (err != nil) { return err }
// Map Structure: Profile Hash -> Author identity hash
profileHashesToRetrieveMap := make(map[[28]byte][16]byte)
for _, identityHash := range relevantHostProfileIdentityHashesList{
exists, profileHashesList, err := badgerDatabase.GetIdentityProfileHashesList(identityHash)
if (err != nil) { return err }
if (exists == false){
// Entry must have been deleted. Will be fixed automatically
continue
}
if (len(profileHashesList) == 0){
continue
}
for _, profileHash := range profileHashesList{
profileMetadataExists, _, profileNetworkType, profileAuthor, _, profileIsDisabled, _, _, err := contentMetadata.GetProfileMetadata(profileHash)
if (err != nil) { return err }
if (profileMetadataExists == false){
// Profile is not downloaded, skip it.
continue
}
if (profileNetworkType != networkType){
continue
}
if (profileAuthor != identityHash){
return errors.New("Database corrupt: Host identity profile hashes list contains profile of different identity")
}
if (profileIsDisabled == true){
continue
}
profileHashesToRetrieveMap[profileHash] = identityHash
}
}
err = queryHosts.DownloadViewableStatusesFromHosts(false, networkType, knownOrUnknown, relevantHostProfileIdentityHashesList, profileHashesToRetrieveMap, 5)
if (err != nil) { return err }
return nil
}
// This function will download trusted viewable statuses for downloaded moderator profiles whose viewable statuses we cannot calculate ourselves
//
// We only need to do this is Moderator mode is enabled.
// This is only needed so moderators can view Moderator profiles whose viewable status we are not aware of and be sure they are viewable
// If Host mode is enabled, all of the moderator profiles we download, we will be able to determine the viewable status of.
// Mate mode will not download any moderator profiles.
//
// We don't need to download viewable statuses for moderator identities
// This is because in Moderator/Host mode, we should be downloading all moderator identity reviews
// Thus, we should be able to determine their viewable statuses ourselves
//
func DownloadModeratorProfileViewableStatuses(networkType byte, knownOrUnknown string)error{
isValid := helpers.VerifyNetworkType(networkType)
if (isValid == false){
networkTypeString := helpers.ConvertByteToString(networkType)
return errors.New("DownloadModeratorProfileViewableStatuses called with invalid networkType: " + networkTypeString)
}
if (knownOrUnknown != "Known" && knownOrUnknown != "Unknown"){
return errors.New("DownloadModeratorProfileViewableStatuses called with invalid knownOrUnknown: " + knownOrUnknown)
}
moderatorModeEnabled, moderatingAnyModeratorIdentities, myIdentityRangeStart, myIdentityRangeEnd, err := myRanges.GetMyIdentitiesToModerateRange("Moderator")
if (err != nil) { return err }
if (moderatorModeEnabled == false){
// Moderator mode must have been disabled recently
err := logger.AddLogEntry("Network", "DownloadModeratorProfileViewableStatuses called when user is not in Moderator mode.")
if (err != nil) { return err }
return nil
}
if (moderatingAnyModeratorIdentities == true){
minimumIdentityBound, maximumIdentityBound := byteRange.GetMinimumMaximumIdentityHashBounds()
if (myIdentityRangeStart == minimumIdentityBound && myIdentityRangeEnd == maximumIdentityBound){
// We are moderating all Moderator identities, so we should be able to determine the viewable status for all moderator profiles
// We don't need to download any moderator profile trusted viewable statuses
return nil
}
}
// Now we see if we are hosting all moderator identities
hostModeEnabled, hostingAny, _, _, err := myRanges.GetMyIdentitiesToHostRange("Moderator")
if (err != nil) { return err }
if (hostModeEnabled == true && hostingAny == true){
// We are hosting all moderator identities
// Thus, we are downloading all reviews for all moderator profiles
// We don't need to download the viewable statuses for any moderator profiles
return nil
}
allModeratorProfileIdentityHashesList, err := badgerDatabase.GetAllProfileIdentityHashes("Moderator")
if (err != nil) { return err }
// Map Structure: Profile Hash -> Author identity hash
profileHashesToRetrieveMap := make(map[[28]byte][16]byte)
for _, moderatorIdentityHash := range allModeratorProfileIdentityHashesList{
if (moderatingAnyModeratorIdentities == true){
// We see if moderator's identity is within our range
// If it is, we don't have to get the status for profiles authored by this identity, because we can determine the viewable statuses ourselves
isWithinRange, err := byteRange.CheckIfIdentityHashIsWithinRange(myIdentityRangeStart, myIdentityRangeEnd, moderatorIdentityHash)
if (err != nil) { return err }
if (isWithinRange == true){
continue
}
}
exists, profileHashesList, err := badgerDatabase.GetIdentityProfileHashesList(moderatorIdentityHash)
if (err != nil) { return err }
if (exists == false){
// Entry must have been deleted. Will be fixed automatically
continue
}
if (len(profileHashesList) == 0){
continue
}
for _, profileHash := range profileHashesList{
profileMetadataExists, _, profileNetworkType, profileAuthor, _, profileIsDisabled, _, _, err := contentMetadata.GetProfileMetadata(profileHash)
if (err != nil) { return err }
if (profileMetadataExists == false){
// Profile is not downloaded, skip it.
continue
}
if (profileNetworkType != networkType){
continue
}
if (profileAuthor != moderatorIdentityHash){
return errors.New("Database corrupt: Moderator identity profile hashes list contains profile of different identity")
}
if (profileIsDisabled == true){
continue
}
profileHashesToRetrieveMap[profileHash] = moderatorIdentityHash
}
}
emptyList := make([][16]byte, 0)
err = queryHosts.DownloadViewableStatusesFromHosts(false, networkType, knownOrUnknown, emptyList, profileHashesToRetrieveMap, 5)
if (err != nil) { return err }
return nil
}
// This function will download viewable statuses for mate identities/profiles we are browsing
// If we are not in DesiresPruningMode, we will download the statuses for all downloaded profiles/identities which fulfill our criteria
// If we are in DesiresPruningMode, we have to download the statuses for our matches profiles/identities one-at-a-time
func DownloadMateViewableStatusesForBrowsing(networkType byte, knownOrUnknown string)error{
isValid := helpers.VerifyNetworkType(networkType)
if (isValid == false){
networkTypeString := helpers.ConvertByteToString(networkType)
return errors.New("DownloadMateViewableStatusesForBrowsing called with invalid networkType: " + networkTypeString)
}
if (knownOrUnknown != "Known" && knownOrUnknown != "Unknown"){
return errors.New("DownloadMateViewableStatusesForBrowsing called with invalid knownOrUnknown: " + knownOrUnknown)
}
//TODO: Fix
desiresPruningMode := false
if (desiresPruningMode == true){
// We will retrieve consensus statuses for all users who could potentially be matches one-by-one
// A user could potentially be a match if their newest profile fulfills our desires
// Their newest profile may not be viewable, so we still need to retrieve statuses for all of their profiles which fulfill our desires
myIdentityExists, myIdentityHash, err := myIdentity.GetMyIdentityHash("Mate")
if (err != nil) { return err }
mateIdentityHashesList, err := badgerDatabase.GetAllProfileIdentityHashes("Mate")
if (err != nil) { return err }
for _, userIdentityHash := range mateIdentityHashesList{
if (myIdentityExists == true && userIdentityHash == myIdentityHash){
continue
}
userIsBlocked, _, _, _, err := myBlockedUsers.CheckIfUserIsBlocked(userIdentityHash)
if (err != nil) { return err }
if (userIsBlocked == true){
// We don't need to get the viewable statuses for blocked users
continue
}
profileExists, profileVersion, newestProfileHash, _, _, newestRawProfileMap, err := profileStorage.GetNewestUserProfile(userIdentityHash, networkType)
if (err != nil) { return err }
if (profileExists == false){
// This user has no profiles, so we do not need to retrieve any viewable statuses for this user
// The user's profile was probably deleted in the background
continue
}
userIsDisabled, _, err := readProfiles.GetFormattedProfileAttributeFromRawProfileMap(newestRawProfileMap, "Disabled")
if (err != nil) { return err }
if (userIsDisabled == true){
// The user will never be a match, because their newest profile is disabled
// Thus, we do not need to retrieve viewable statuses for the user.
continue
}
getAnyProfileAttributeFunction, err := calculatedAttributes.GetRetrieveAnyProfileAttributeIncludingCalculatedFunction(profileVersion, newestRawProfileMap)
if (err != nil){ return err }
profilePassesMyDesires, err := myMateDesires.CheckIfMateProfilePassesAllMyDesires(false, "", getAnyProfileAttributeFunction)
if (err != nil) { return err }
if (profilePassesMyDesires == false){
// The user's newest profile does not fulfill our desires
// We don't need to get this profile's viewable status, because it does not fulfill our desires
// We don't need to get any viewable statuses for this user, unless they are an outlier
continue
}
anyExist, profileHashesList, err := badgerDatabase.GetIdentityProfileHashesList(userIdentityHash)
if (err != nil) { return err }
if (anyExist == false){
// This user has no profiles
continue
}
profileHashesToGetStatusesOfList := [][28]byte{newestProfileHash}
for _, profileHash := range profileHashesList{
if (profileHash == newestProfileHash){
// We are already getting this profile's status
continue
}
profileExists, profileBytes, err := badgerDatabase.GetUserProfile("Mate", profileHash)
if (err != nil) { return err }
if (profileExists == false){
continue
}
ableToRead, profileVersion, profileNetworkType, profileAuthor, _, profileIsDisabled, rawProfileMap, err := readProfiles.ReadProfile(false, profileBytes)
if (err != nil) { return err }
if (ableToRead == false){
return errors.New("Database corrupt: Contains malformed profile.")
}
if (profileNetworkType != networkType){
// Profile belongs to a different network type.
continue
}
if (profileAuthor != userIdentityHash){
return errors.New("Database corrupt: Mate identity profile hashes list contains profile of different identity")
}
if (profileIsDisabled == true){
// We don't need to retrieve status for disabled profiles.
// These profiles will always be viewable, unless their author is banned.
continue
}
getAnyProfileAttributeFunction, err := calculatedAttributes.GetRetrieveAnyProfileAttributeIncludingCalculatedFunction(profileVersion, rawProfileMap)
if (err != nil){ return err }
profilePassesMyDesires, err := myMateDesires.CheckIfMateProfilePassesAllMyDesires(false, "", getAnyProfileAttributeFunction)
if (err != nil) { return err }
if (profilePassesMyDesires == false){
// We don't need to get this profile's viewable status, because it does not fulfill our desires
// Thus, we will not show it to the user unless the author is an outlier
// Outlier viewable statuses are retrieved in a different job
continue
}
profileHashesToGetStatusesOfList = append(profileHashesToGetStatusesOfList, profileHash)
}
// Map Structure: Profile Hash -> User Identity Hash
profileHashesToRetrieveMap := make(map[[28]byte][16]byte)
for _, profileHash := range profileHashesToGetStatusesOfList{
profileHashesToRetrieveMap[profileHash] = userIdentityHash
}
identityHashList := [][16]byte{userIdentityHash}
err = queryHosts.DownloadViewableStatusesFromHosts(false, networkType, knownOrUnknown, identityHashList, profileHashesToRetrieveMap, 1)
if (err != nil) { return err }
}
return nil
}
// We will retrieve statuses for all identities whose newest profile fulfills our downloads criteria, and their profiles that fulfill our criteria
myCriteriaExists, myCriteria, err := myMateCriteria.GetMyMateDownloadsCriteria()
if (err != nil) { return err }
allMateProfileIdentityHashesList, err := badgerDatabase.GetAllProfileIdentityHashes("Mate")
if (err != nil) { return err }
helpers.RandomizeListOrder(allMateProfileIdentityHashesList)
identityHashesToRetrieveList := make([][16]byte, 0)
// Map Structure: Profile Hash -> User Identity Hash
profileHashesToRetrieveMap := make(map[[28]byte][16]byte)
for _, userIdentityHash := range allMateProfileIdentityHashesList{
statusIsKnown, identityIsFunded, err := fundedStatus.GetIdentityIsFundedStatus(userIdentityHash, networkType)
if (err != nil) { return err }
if (statusIsKnown == true && identityIsFunded == false){
// The user's identity is not funded
// This means that none of their profiles will be hosted by the network
// We won't try to retrieve their viewable status, because their profile/identity will not exist on the network
continue
}
profileExists, profileVersion, newestProfileHash, _, _, newestRawProfileMap, err := profileStorage.GetNewestUserProfile(userIdentityHash, networkType)
if (err != nil) { return err }
if (profileExists == false){
continue
}
userIsDisabled, _, err := readProfiles.GetFormattedProfileAttributeFromRawProfileMap(newestRawProfileMap, "Disabled")
if (err != nil) { return err }
if (userIsDisabled == true){
// The user will never be a match, because their newest profile is disabled
// Thus, we do not need to retrieve viewable statuses for the user.
continue
}
if (myCriteriaExists == true){
criteriaIsValid, fulfillsCriteria, err := mateCriteria.CheckIfMateProfileFulfillsCriteria(true, profileVersion, newestRawProfileMap, myCriteria)
if (err != nil) { return err }
if (criteriaIsValid == false){
return errors.New("GetMyMateDownloadsCriteria returning invalid criteria.")
}
if (fulfillsCriteria == false){
// This user's newest profile does not fulfill our criteria. Skip them.
// DatabaseJobs will delete all of their profiles (unless they are an outlier)
continue
}
}
anyExist, profileHashesList, err := badgerDatabase.GetIdentityProfileHashesList(userIdentityHash)
if (err != nil) { return err }
if (anyExist == false){
// User has no profiles
// They must have been deleted after earlier check
continue
}
for _, profileHash := range profileHashesList{
if (profileHash == newestProfileHash){
// We already checked and know that this profile fulfills our criteria
profileHashesToRetrieveMap[profileHash] = userIdentityHash
continue
}
profileExists, profileBytes, err := badgerDatabase.GetUserProfile("Mate", profileHash)
if (err != nil) { return err }
if (profileExists == false){
continue
}
ableToRead, profileVersion, profileNetworkType, profileAuthor, _, profileIsDisabled, rawProfileMap, err := readProfiles.ReadProfile(false, profileBytes)
if (err != nil) { return err }
if (ableToRead == false){
return errors.New("Database corrupt: Contains malformed profile.")
}
if (profileNetworkType != networkType){
// Profile belongs to a different network type.
continue
}
if (profileAuthor != userIdentityHash){
return errors.New("Database corrupt: Mate identity profile hashes list contains profile of different identity")
}
if (profileIsDisabled == true){
// We don't need to retrieve status for disabled profiles. They are always approved, unless identity is banned.
continue
}
if (myCriteriaExists == true){
criteriaIsValid, fulfillsCriteria, err := mateCriteria.CheckIfMateProfileFulfillsCriteria(true, profileVersion, rawProfileMap, myCriteria)
if (err != nil) { return err }
if (criteriaIsValid == false){
return errors.New("GetMyMateDownloadsCriteria returning invalid criteria.")
}
if (fulfillsCriteria == false){
// This profile does not fulfill our criteria
// We don't need to get its viewable status, because it will never be shown to the user
// The exception is if the profile is an outlier, in which case we will retrieve its status using DownloadMateOutlierViewableStatuses
// Another reason we skip the profile is that requesting its status would pose a risk of exposing our older criteria to the host
continue
}
}
profileHashesToRetrieveMap[profileHash] = userIdentityHash
}
identityHashesToRetrieveList = append(identityHashesToRetrieveList, userIdentityHash)
}
if (len(identityHashesToRetrieveList) == 0){
// No users fulfill our criteria. Nothing to do.
return nil
}
err = queryHosts.DownloadViewableStatusesFromHosts(false, networkType, knownOrUnknown, identityHashesToRetrieveList, profileHashesToRetrieveMap, 5)
if (err != nil) { return err }
return nil
}
// This function will download trusted viewable statuses for Mate users whom are our outliers
// Outliers are either contacts, likes, or chat recipients.
// We download them so the user's client will have their downloaded profiles viewable, even if the users do not fulfill our criteria
// These need to be downloaded one-by-one to prevent any host from learning our contacts/likes/chat recipients
func DownloadMateOutlierViewableStatuses(outlierType string, networkType byte, knownOrUnknown string)error{
if (outlierType != "Contacts" && outlierType != "Likes" && outlierType != "ChatRecipients"){
return errors.New("DownloadMateOutlierViewableStatuses called with invalid outlierType: " + outlierType)
}
isValid := helpers.VerifyNetworkType(networkType)
if (isValid == false){
networkTypeString := helpers.ConvertByteToString(networkType)
return errors.New("DownloadMateOutlierViewableStatuses called with invalid networkType: " + networkTypeString)
}
if (knownOrUnknown != "Known" && knownOrUnknown != "Unknown"){
return errors.New("DownloadMateOutlierViewableStatuses called with invalid knownOrUnknown: " + knownOrUnknown)
}
//Outputs:
// -[]string: List of identities
// -error
getMyOutlierIdentitiesList := func()([][16]byte, error){
if (outlierType == "Contacts"){
myContactIdentityHashesList, err := myContacts.GetMyContactsList("Mate")
if (err != nil) { return nil, err }
return myContactIdentityHashesList, nil
}
if (outlierType == "Likes"){
myLikedUsersList, err := myLikedUsers.GetMyLikedUsersList()
if (err != nil) { return nil, err }
return myLikedUsersList, nil
}
myIdentityExists, chatRecipientIdentityHashesList, err := myChatMessages.GetAllMyNonBlockedChatRecipients("Mate", networkType)
if (err != nil) { return nil, err }
if (myIdentityExists == false){
// Nothing to do, mate identity does not exist
emptyList := make([][16]byte, 0)
return emptyList, nil
}
return chatRecipientIdentityHashesList, nil
}
myOutlierIdentityHashesList, err := getMyOutlierIdentitiesList()
if (err != nil) { return err }
if (len(myOutlierIdentityHashesList) == 0){
return nil
}
helpers.RandomizeListOrder(myOutlierIdentityHashesList)
for _, mateIdentityHash := range myOutlierIdentityHashesList{
statusIsKnown, identityIsFunded, err := fundedStatus.GetIdentityIsFundedStatus(mateIdentityHash, networkType)
if (err != nil) { return err }
if (statusIsKnown == true && identityIsFunded == false){
// The user's identity is not funded
// This means that none of their profiles will be hosted by the network
// We won't try to retrieve their viewable status, because their profile/identity will not exist on the network
continue
}
identityHashList := [][16]byte{mateIdentityHash}
// Outputs:
// -map[[28]byte][16]byte: Map of profile hashes whose viewable status we want to retrieve (Profile Hash -> User identity Hash)
// -error
getProfileHashesToRetrieveMap := func()(map[[28]byte][16]byte, error){
profileExists, _, newestProfileHash, _, _, newestRawProfileMap, err := profileStorage.GetNewestUserProfile(mateIdentityHash, networkType)
if (err != nil) { return nil, err }
if (profileExists == false){
// We have no profiles downloaded for this user
emptyMap := make(map[[28]byte][16]byte)
return emptyMap, nil
}
isDisabled, _, err := readProfiles.GetFormattedProfileAttributeFromRawProfileMap(newestRawProfileMap, "Disabled")
if (err != nil) { return nil, err }
if (isDisabled == true){
// User's newest profile is disabled.
// We don't need to download the profile's viewable status, because it cannot be banned
emptyMap := make(map[[28]byte][16]byte)
return emptyMap, nil
}
// We retrieve the viewable status for all of their downloaded profiles
profileHashesToRetrieveMap := map[[28]byte][16]byte{
newestProfileHash: mateIdentityHash,
}
anyExist, identityProfileHashesList, err := badgerDatabase.GetIdentityProfileHashesList(mateIdentityHash)
if (err != nil) { return nil, err }
if (anyExist == true){
for _, profileHash := range identityProfileHashesList{
profileHashesToRetrieveMap[profileHash] = mateIdentityHash
}
}
return profileHashesToRetrieveMap, nil
}
profileHashesToRetrieveMap, err := getProfileHashesToRetrieveMap()
if (err != nil) { return err }
err = queryHosts.DownloadViewableStatusesFromHosts(false, networkType, knownOrUnknown, identityHashList, profileHashesToRetrieveMap, 1)
if (err != nil) { return err }
}
return nil
}
// This function will download the cryptocurrency deposit history for all downloaded moderator identities
// We download deposits for all moderators in bulk
// Because users must download either all or no moderator profiles, there is no fingerprinting risk in downloading them in bulk
// This should be called if Host/Moderator mode is enabled
func DownloadModeratorIdentityDeposits(networkType byte, unknownOrKnown string)error{
isValid := helpers.VerifyNetworkType(networkType)
if (isValid == false){
networkTypeString := helpers.ConvertByteToString(networkType)
return errors.New("DownloadModeratorIdentityDeposits called with invalid networkType: " + networkTypeString)
}
err := queryHosts.DownloadModeratorAddressDepositsFromHosts(true, networkType, "Ethereum", unknownOrKnown, 6)
if (err != nil) { return err }
err = queryHosts.DownloadModeratorAddressDepositsFromHosts(true, networkType, "Cardano", unknownOrKnown, 6)
if (err != nil) { return err }
return nil
}