2024-04-11 15:51:56 +02:00
// 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 )
}
2024-06-11 06:59:06 +02:00
checkIfProfileShouldBeDownloaded := func ( _ [ 28 ] byte , profileAuthor [ 16 ] byte , profileCreationTime int64 ) ( bool , error ) {
2024-04-11 15:51:56 +02:00
// Check to see if our newest profile is older than the received profile
2024-06-11 06:59:06 +02:00
newestViewableProfileExists , _ , _ , _ , storedProfileCreationTime , _ , err := viewableProfiles . GetNewestViewableUserProfile ( profileAuthor , networkType , true , false , true )
2024-04-11 15:51:56 +02:00
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
}
2024-06-11 06:59:06 +02:00
if ( profileCreationTime <= storedProfileCreationTime ) {
2024-04-11 15:51:56 +02:00
// 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 )
2024-06-11 06:59:06 +02:00
checkIfProfileShouldBeDownloaded := func ( _ [ 28 ] byte , profileAuthor [ 16 ] byte , profileCreationTime int64 ) ( bool , error ) {
2024-04-11 15:51:56 +02:00
// 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
2024-06-11 06:59:06 +02:00
profileExists , _ , _ , _ , storedProfileCreationTime , _ , err := viewableProfiles . GetNewestViewableUserProfile ( profileAuthor , networkType , true , false , true )
2024-04-11 15:51:56 +02:00
if ( err != nil ) { return false , err }
if ( profileExists == false ) {
return true , nil
}
2024-06-11 06:59:06 +02:00
if ( storedProfileCreationTime >= profileCreationTime ) {
2024-04-11 15:51:56 +02:00
// 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
}
}
2024-06-11 06:59:06 +02:00
checkIfProfileShouldBeDownloaded := func ( _ [ 28 ] byte , profileAuthor [ 16 ] byte , profileCreationTime int64 ) ( bool , error ) {
2024-04-11 15:51:56 +02:00
// 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
2024-06-11 06:59:06 +02:00
profileExists , _ , _ , _ , existingProfileCreationTime , _ , err := viewableProfiles . GetNewestViewableUserProfile ( profileAuthor , networkType , true , false , true )
2024-04-11 15:51:56 +02:00
if ( err != nil ) { return false , err }
if ( profileExists == false ) {
return true , nil
}
2024-06-11 06:59:06 +02:00
if ( profileCreationTime <= existingProfileCreationTime ) {
2024-04-11 15:51:56 +02:00
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
}
2024-06-11 06:59:06 +02:00
checkIfProfileShouldBeDownloaded := func ( profileHash [ 28 ] byte , profileAuthor [ 16 ] byte , profileCreationTime int64 ) ( bool , error ) {
2024-04-11 15:51:56 +02:00
//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
2024-06-11 06:59:06 +02:00
// We cannot trust the creationTimes 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
2024-04-11 15:51:56 +02:00
// 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
}
2024-06-11 06:59:06 +02:00
checkIfProfileShouldBeDownloaded := func ( profileHash [ 28 ] byte , profileIdentityHash [ 16 ] byte , profileCreationTime int64 ) ( bool , error ) {
2024-04-11 15:51:56 +02:00
//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
}