2024-04-11 15:51:56 +02:00
// myBroadcasts provides functions to manage a user's broadcast content
// This is content that will be broadcast or has already been broadcast
// The app will automatically broadcast the content in the background
package myBroadcasts
//TODO: Add reports and parameters
//TODO: Keep track of how many times each piece of content has been broadcast, and use that information to
// broadcast older content less over time
//TODO: Add functions to prune old broadcasted profiles, messages, reports, and parameters
import "seekia/internal/cryptography/nacl"
import "seekia/internal/cryptography/kyber"
import "seekia/internal/encoding"
import "seekia/internal/helpers"
import "seekia/internal/identity"
import "seekia/internal/localFilesystem"
import "seekia/internal/messaging/myChatKeys"
import "seekia/internal/messaging/readMessages"
import "seekia/internal/moderation/mySkippedContent"
import "seekia/internal/moderation/readReviews"
import "seekia/internal/moderation/reviewStorage"
import "seekia/internal/myIdentity"
import "seekia/internal/network/appNetworkType/getAppNetworkType"
import "seekia/internal/profiles/calculatedAttributes"
import "seekia/internal/profiles/myProfileExports"
import "seekia/internal/profiles/profileStorage"
import "seekia/internal/profiles/readProfiles"
import messagepack "github.com/vmihailenco/msgpack/v5"
import goFilepath "path/filepath"
import "os"
import "errors"
func InitializeMyBroadcastsFolders ( ) error {
userDirectory , err := localFilesystem . GetAppUserFolderPath ( )
if ( err != nil ) { return err }
myBroadcastsFolderpath := goFilepath . Join ( userDirectory , "MyBroadcasts" )
_ , err = localFilesystem . CreateFolder ( myBroadcastsFolderpath )
if ( err != nil ) { return err }
profilesFolderpath := goFilepath . Join ( userDirectory , "MyBroadcasts" , "Profiles" )
messagesFolderpath := goFilepath . Join ( userDirectory , "MyBroadcasts" , "Messages" )
reportsFolderpath := goFilepath . Join ( userDirectory , "MyBroadcasts" , "Reports" )
parametersFolderpath := goFilepath . Join ( userDirectory , "MyBroadcasts" , "Parameters" )
folderpathsList := [ ] string { profilesFolderpath , messagesFolderpath , reportsFolderpath , parametersFolderpath }
for _ , folderpath := range folderpathsList {
_ , err := localFilesystem . CreateFolder ( folderpath )
if ( err != nil ) { return err }
network1Folderpath := goFilepath . Join ( folderpath , "Network1" )
network2Folderpath := goFilepath . Join ( folderpath , "Network2" )
_ , err = localFilesystem . CreateFolder ( network1Folderpath )
if ( err != nil ) { return err }
_ , err = localFilesystem . CreateFolder ( network2Folderpath )
if ( err != nil ) { return err }
}
reviewsFolderpath := goFilepath . Join ( userDirectory , "MyBroadcasts" , "Reviews" )
_ , err = localFilesystem . CreateFolder ( reviewsFolderpath )
if ( err != nil ) { return err }
// We create reviews subfolders for each reviewType
// We use subfolders so retrieval is faster
// The speedup will be significant for moderators with tens of thousands of reviews
// Reports do not need subfolders because users will typically create very few reports
identityReviewsFolderpath := goFilepath . Join ( userDirectory , "MyBroadcasts" , "Reviews" , "Identity" )
profileReviewsFolderpath := goFilepath . Join ( userDirectory , "MyBroadcasts" , "Reviews" , "Profile" )
attributeReviewsFolderpath := goFilepath . Join ( userDirectory , "MyBroadcasts" , "Reviews" , "Attribute" )
messageReviewsFolderpath := goFilepath . Join ( userDirectory , "MyBroadcasts" , "Reviews" , "Message" )
folderpathsList = [ ] string { identityReviewsFolderpath , profileReviewsFolderpath , attributeReviewsFolderpath , messageReviewsFolderpath }
for _ , folderpath := range folderpathsList {
_ , err := localFilesystem . CreateFolder ( folderpath )
if ( err != nil ) { return err }
network1Folderpath := goFilepath . Join ( folderpath , "Network1" )
network2Folderpath := goFilepath . Join ( folderpath , "Network2" )
_ , err = localFilesystem . CreateFolder ( network1Folderpath )
if ( err != nil ) { return err }
_ , err = localFilesystem . CreateFolder ( network2Folderpath )
if ( err != nil ) { return err }
}
return nil
}
//Outputs:
// -bool: My Identity exists
// -bool: Profile exists
// -int: Profile version
// -bool: Attribute exists
// -string: Attribute value
// -error
func GetAnyAttributeFromMyBroadcastProfile ( myIdentityHash [ 16 ] byte , networkType byte , attribute string ) ( bool , bool , int , bool , string , error ) {
isValid := helpers . VerifyNetworkType ( networkType )
if ( isValid == false ) {
networkTypeString := helpers . ConvertByteToString ( networkType )
return false , false , 0 , false , "" , errors . New ( "GetAnyAttributeFromMyBroadcastProfile called with invalid networkType: " + networkTypeString )
}
identityExists , profileExists , _ , getAnyAttributeFunction , err := GetRetrieveAnyAttributeFromMyBroadcastProfileFunction ( myIdentityHash , networkType )
if ( err != nil ) { return false , false , 0 , false , "" , err }
if ( identityExists == false ) {
return false , false , 0 , false , "" , nil
}
if ( profileExists == false ) {
return true , false , 0 , false , "" , nil
}
attributeExists , profileVersion , attributeValue , err := getAnyAttributeFunction ( attribute )
if ( err != nil ) { return false , false , 0 , false , "" , err }
if ( attributeExists == false ) {
return true , true , 0 , false , "" , nil
}
return true , true , profileVersion , true , attributeValue , nil
}
//Outputs:
// -bool: My identity exists
// -bool: Profile exists
// -[28]byte: Profile hash
// -func(attributeName string)(bool, int, string, error)
// -error
func GetRetrieveAnyAttributeFromMyBroadcastProfileFunction ( myIdentityHash [ 16 ] byte , networkType byte ) ( bool , bool , [ 28 ] byte , func ( string ) ( bool , int , string , error ) , error ) {
isValid := helpers . VerifyNetworkType ( networkType )
if ( isValid == false ) {
networkTypeString := helpers . ConvertByteToString ( networkType )
return false , false , [ 28 ] byte { } , nil , errors . New ( "GetRetrieveAnyAttributeFromMyBroadcastProfileFunction called with invalid networkType: " + networkTypeString )
}
identityExists , _ , err := myIdentity . CheckIfIdentityHashIsMine ( myIdentityHash )
if ( err != nil ) { return false , false , [ 28 ] byte { } , nil , err }
if ( identityExists == false ) {
return false , false , [ 28 ] byte { } , nil , nil
}
profileExists , profileVersion , profileHash , _ , rawProfileMap , err := GetMyNewestBroadcastProfile ( myIdentityHash , networkType )
if ( err != nil ) { return false , false , [ 28 ] byte { } , nil , err }
if ( profileExists == false ) {
return true , false , [ 28 ] byte { } , nil , nil
}
getAnyAttributeFunction , err := calculatedAttributes . GetRetrieveAnyProfileAttributeIncludingCalculatedFunction ( profileVersion , rawProfileMap )
if ( err != nil ) { return false , false , [ 28 ] byte { } , nil , err }
return true , true , profileHash , getAnyAttributeFunction , nil
}
//Outputs:
// -bool: Profile found
// -int: Profile version
// -[28]byte: Profile hash
// -[]byte: Profile bytes
// -map[int]messagepack.RawMessage: Raw profile map
// -error
func GetMyNewestBroadcastProfile ( myIdentityHash [ 16 ] byte , networkType byte ) ( bool , int , [ 28 ] byte , [ ] byte , map [ int ] messagepack . RawMessage , error ) {
identityExists , _ , err := myIdentity . CheckIfIdentityHashIsMine ( myIdentityHash )
if ( err != nil ) { return false , 0 , [ 28 ] byte { } , nil , nil , err }
if ( identityExists == false ) {
return false , 0 , [ 28 ] byte { } , nil , nil , errors . New ( "GetMyNewestBroadcastProfile called with identity that is not mine." )
}
isValid := helpers . VerifyNetworkType ( networkType )
if ( isValid == false ) {
networkTypeString := helpers . ConvertByteToString ( networkType )
return false , 0 , [ 28 ] byte { } , nil , nil , errors . New ( "GetMyNewestBroadcastProfile called with invalid networkType: " + networkTypeString )
}
userDirectory , err := localFilesystem . GetAppUserFolderPath ( )
if ( err != nil ) { return false , 0 , [ 28 ] byte { } , nil , nil , err }
networkTypeString := helpers . ConvertByteToString ( networkType )
networkTypeFoldername := "Network" + networkTypeString
profilesFolderPath := goFilepath . Join ( userDirectory , "MyBroadcasts" , "Profiles" , networkTypeFoldername )
broadcastProfilesList , err := localFilesystem . GetAllFilesInFolderAsList ( profilesFolderPath )
if ( err != nil ) { return false , 0 , [ 28 ] byte { } , nil , nil , err }
anyProfileFound := false
newestProfileVersion := 0
var newestProfileHash [ 28 ] byte
newestProfileBytes := make ( [ ] byte , 0 )
newestProfileRawProfileMap := make ( map [ int ] messagepack . RawMessage )
2024-06-11 06:59:06 +02:00
newestProfileCreationTime := int64 ( 0 )
2024-04-11 15:51:56 +02:00
for _ , profileBytes := range broadcastProfilesList {
2024-06-11 06:59:06 +02:00
ableToRead , profileHash , profileVersion , profileNetworkType , profileIdentityHash , profileCreationTime , _ , rawProfileMap , err := readProfiles . ReadProfileAndHash ( true , profileBytes )
2024-04-11 15:51:56 +02:00
if ( err != nil ) { return false , 0 , [ 28 ] byte { } , nil , nil , err }
if ( ableToRead == false ) {
return false , 0 , [ 28 ] byte { } , nil , nil , errors . New ( "MyBroadcasts contains invalid profile." )
}
if ( profileNetworkType != networkType ) {
return false , 0 , [ 28 ] byte { } , nil , nil , errors . New ( "MyBroadcasts contains profile for different networkType." )
}
if ( profileIdentityHash != myIdentityHash ) {
continue
}
2024-06-11 06:59:06 +02:00
if ( anyProfileFound == false || profileCreationTime > newestProfileCreationTime ) {
2024-04-11 15:51:56 +02:00
anyProfileFound = true
newestProfileVersion = profileVersion
newestProfileHash = profileHash
newestProfileBytes = profileBytes
newestProfileRawProfileMap = rawProfileMap
2024-06-11 06:59:06 +02:00
newestProfileCreationTime = profileCreationTime
2024-04-11 15:51:56 +02:00
}
}
if ( anyProfileFound == false ) {
return false , 0 , [ 28 ] byte { } , nil , nil , nil
}
return true , newestProfileVersion , newestProfileHash , newestProfileBytes , newestProfileRawProfileMap , nil
}
// This function overwrites an identity's existing broadcast profile with current exported profile
//Outputs:
// -bool: My identity exists
// -[28]byte: Profile hash of new broadcast profile
// -error
func UpdateMyBroadcastProfile ( myIdentityType string , networkType byte ) ( bool , [ 28 ] byte , error ) {
isValid := helpers . VerifyNetworkType ( networkType )
if ( isValid == false ) {
networkTypeString := helpers . ConvertByteToString ( networkType )
return false , [ 28 ] byte { } , errors . New ( "UpdateMyBroadcastProfile called with invalid networkType: " + networkTypeString )
}
myIdentityExists , myIdentityHash , err := myIdentity . GetMyIdentityHash ( myIdentityType )
if ( err != nil ) { return false , [ 28 ] byte { } , err }
if ( myIdentityExists == false ) {
return false , [ 28 ] byte { } , nil
}
newProfileFound , exportProfileHash , newProfileBytes , _ , err := myProfileExports . GetMyExportedProfile ( myIdentityType , networkType )
if ( err != nil ) { return false , [ 28 ] byte { } , err }
if ( newProfileFound == false ) {
return false , [ 28 ] byte { } , errors . New ( "UpdateMyBroadcastProfile called when export profile is missing." )
}
2024-06-11 06:59:06 +02:00
ableToRead , newProfileHash , _ , newProfileNetworkType , profileIdentityHash , newProfileCreationTime , _ , newProfileRawProfileMap , err := readProfiles . ReadProfileAndHash ( true , newProfileBytes )
2024-04-11 15:51:56 +02:00
if ( err != nil ) { return false , [ 28 ] byte { } , err }
if ( ableToRead == false ) {
return false , [ 28 ] byte { } , errors . New ( "MyExports contains invalid profile." )
}
if ( newProfileNetworkType != networkType ) {
return false , [ 28 ] byte { } , errors . New ( "GetMyExportedProfile returning profile with different networkType." )
}
if ( exportProfileHash != newProfileHash ) {
return false , [ 28 ] byte { } , errors . New ( "GetMyExportedProfile returning different profileHash than the profileBytes" )
}
if ( profileIdentityHash != myIdentityHash ) {
return false , [ 28 ] byte { } , errors . New ( "New profile identity hash is not mine." )
}
checkIfProfileHasChatKeys := func ( ) ( bool , error ) {
profileIsDisabled , _ , err := readProfiles . GetFormattedProfileAttributeFromRawProfileMap ( newProfileRawProfileMap , "Disabled" )
if ( err != nil ) { return false , err }
if ( profileIsDisabled == true ) {
return false , nil
}
if ( myIdentityType == "Mate" || myIdentityType == "Moderator" ) {
return true , nil
}
return false , nil
}
profileHasChatKeys , err := checkIfProfileHasChatKeys ( )
if ( err != nil ) { return false , [ 28 ] byte { } , err }
if ( profileHasChatKeys == true ) {
// We deal with updating the user's latest chat keys update time
// We keep track of this locally and send it within all of our chat messages
// The exported profile's chat keys latest update time will be accurate, based on our existing chat keys
exists , newProfileChatKeysLatestUpdateTimeString , err := readProfiles . GetFormattedProfileAttributeFromRawProfileMap ( newProfileRawProfileMap , "ChatKeysLatestUpdateTime" )
if ( err != nil ) { return false , [ 28 ] byte { } , err }
if ( exists == false ) {
return false , [ 28 ] byte { } , errors . New ( "Invalid exported profile: Missing ChatKeysLatestUpdateTime" )
}
newProfileChatKeysLatestUpdateTime , err := helpers . ConvertStringToInt64 ( newProfileChatKeysLatestUpdateTimeString )
if ( err != nil ) {
return false , [ 28 ] byte { } , errors . New ( "Invalid exported profile: Contains invalid ChatKeysLatestUpdateTime: " + newProfileChatKeysLatestUpdateTimeString )
}
getLatestChatKeysTimeNeedsUpdateBool := func ( ) ( bool , error ) {
latestUpdateTimeExists , existingChatKeysLatestUpdateTime , err := myChatKeys . GetMyChatKeysLatestUpdateTime ( myIdentityHash , networkType )
if ( err != nil ) { return false , err }
if ( latestUpdateTimeExists == false ) {
// No time exists, we need to update it.
return true , nil
}
if ( newProfileChatKeysLatestUpdateTime > existingChatKeysLatestUpdateTime ) {
// The profile we are broadcasting has new chat keys.
return true , nil
}
return false , nil
}
latestChatKeysTimeNeedsUpdate , err := getLatestChatKeysTimeNeedsUpdateBool ( )
if ( err != nil ) { return false , [ 28 ] byte { } , err }
if ( latestChatKeysTimeNeedsUpdate == true ) {
2024-06-11 06:59:06 +02:00
err := myChatKeys . SetMyChatKeysLatestUpdateTime ( myIdentityHash , networkType , newProfileCreationTime )
2024-04-11 15:51:56 +02:00
if ( err != nil ) { return false , [ 28 ] byte { } , err }
}
exists , newProfileNaclKeyString , err := readProfiles . GetFormattedProfileAttributeFromRawProfileMap ( newProfileRawProfileMap , "NaclKey" )
if ( err != nil ) { return false , [ 28 ] byte { } , err }
if ( exists == false ) {
return false , [ 28 ] byte { } , errors . New ( "Invalid export profile: Missing NaclKey" )
}
exists , newProfileKyberKeyString , err := readProfiles . GetFormattedProfileAttributeFromRawProfileMap ( newProfileRawProfileMap , "KyberKey" )
if ( err != nil ) { return false , [ 28 ] byte { } , err }
if ( exists == false ) {
return false , [ 28 ] byte { } , errors . New ( "Invalid export profile: Missing KyberKey" )
}
newProfileNaclKey , err := nacl . ReadNaclPublicKeyString ( newProfileNaclKeyString )
if ( err != nil ) {
return false , [ 28 ] byte { } , errors . New ( "Invalid export profile: Contains invalid NaclKey: " + newProfileNaclKeyString )
}
newProfileKyberKey , err := kyber . ReadKyberPublicKeyString ( newProfileKyberKeyString )
if ( err != nil ) {
return false , [ 28 ] byte { } , errors . New ( "Invalid export profile: Contains invalid KyberKey: " + newProfileKyberKeyString )
}
// These keys may not be different from the existing keys we have saved
// We dont have to check if they are different, we will set them anyway
err = myChatKeys . SetMyNewestBroadcastPublicChatKeys ( myIdentityHash , networkType , newProfileNaclKey , newProfileKyberKey )
if ( err != nil ) { return false , [ 28 ] byte { } , err }
}
err = DeleteMyBroadcastProfiles ( myIdentityHash )
if ( err != nil ) { return false , [ 28 ] byte { } , err }
userDirectory , err := localFilesystem . GetAppUserFolderPath ( )
if ( err != nil ) { return false , [ 28 ] byte { } , err }
networkTypeString := helpers . ConvertByteToString ( networkType )
networkTypeFoldername := "Network" + networkTypeString
profilesFolderPath := goFilepath . Join ( userDirectory , "MyBroadcasts" , "Profiles" , networkTypeFoldername )
newProfileHashHex := encoding . EncodeBytesToHexString ( newProfileHash [ : ] )
filename := newProfileHashHex + ".messagepack"
err = localFilesystem . CreateOrOverwriteFile ( newProfileBytes , profilesFolderPath , filename )
if ( err != nil ) { return false , [ 28 ] byte { } , err }
// We add the profile to our database
// For moderators, this will help with determining moderation details, such as what is banned/approved
// For hosts, this will broadcast our profile during our standard host profile seeding tasks
//
// TODO: Skip/delay this step for Mate users?
// For Mate users, this could reveal their identity if the user fulfills their own criteria
// For example, a user who requests to download profiles after being offline for a while could reveal their identity.
// 1. User makes a request to download profiles which fulfill their criteria within the host's range
// 2. Host offers many profiles, some of which have been updated since the user last connected to network
// 3. User requests to download all profiles which are newer than a given time EXCEPT for their own profile
// The user has a newer version of their own profile which the user has recently broadcasted
// The host has not received the profile yet via network propagation.
wellFormed , _ , err := profileStorage . AddUserProfile ( newProfileBytes )
if ( err != nil ) { return false , [ 28 ] byte { } , err }
if ( wellFormed == false ) {
return false , [ 28 ] byte { } , errors . New ( "Profile to broadcast is not well formed after being well formed already." )
}
return true , newProfileHash , nil
}
// This function will delete all broadcast profiles for a provided identity hash
func DeleteMyBroadcastProfiles ( myIdentityHash [ 16 ] byte ) error {
isValid , err := identity . VerifyIdentityHash ( myIdentityHash , false , "" )
if ( err != nil ) { return err }
if ( isValid == false ) {
myIdentityHashHex := encoding . EncodeBytesToHexString ( myIdentityHash [ : ] )
return errors . New ( "DeleteMyBroadcastProfiles called with invalid identityHash: " + myIdentityHashHex )
}
userDirectory , err := localFilesystem . GetAppUserFolderPath ( )
if ( err != nil ) { return err }
profilesFolderPath := goFilepath . Join ( userDirectory , "MyBroadcasts" , "Profiles" )
network1ProfilesFolderpath := goFilepath . Join ( profilesFolderPath , "Network1" )
network2ProfilesFolderpath := goFilepath . Join ( profilesFolderPath , "Network2" )
deleteMyProfilesInFolder := func ( folderPath string , networkType byte ) error {
fileList , err := os . ReadDir ( folderPath )
if ( err != nil ) { return err }
for _ , fileObject := range fileList {
fileName := fileObject . Name ( )
filePath := goFilepath . Join ( folderPath , fileName )
fileBytes , err := os . ReadFile ( filePath )
if ( err != nil ) { return err }
ableToRead , _ , profileNetworkType , profileAuthor , _ , _ , _ , err := readProfiles . ReadProfile ( true , fileBytes )
if ( err != nil ) { return err }
if ( ableToRead == false ) {
return errors . New ( "MyBroadcasts malformed: Contains invalid profile." )
}
if ( profileNetworkType != networkType ) {
return errors . New ( "MyBroadcasts malformed: Contains profile from different networkType." )
}
if ( profileAuthor != myIdentityHash ) {
continue
}
err = os . Remove ( filePath )
if ( err != nil ) { return err }
}
return nil
}
err = deleteMyProfilesInFolder ( network1ProfilesFolderpath , 1 )
if ( err != nil ) { return err }
err = deleteMyProfilesInFolder ( network2ProfilesFolderpath , 2 )
if ( err != nil ) { return err }
return nil
}
func BroadcastMyMessage ( messageBytes [ ] byte ) error {
ableToRead , messageHash , _ , messageNetworkType , _ , _ , _ , _ , _ , _ , _ , err := readMessages . ReadChatMessagePublicDataAndHash ( true , messageBytes )
if ( err != nil ) { return err }
if ( ableToRead == false ) {
return errors . New ( "BroadcastMyMessage called with invalid message." )
}
userDirectory , err := localFilesystem . GetAppUserFolderPath ( )
if ( err != nil ) { return err }
appNetworkType , err := getAppNetworkType . GetAppNetworkType ( )
if ( err != nil ) { return err }
if ( appNetworkType != messageNetworkType ) {
return errors . New ( "BroadcastMyMessage called with message for different networkType than application." )
}
messageNetworkTypeString := helpers . ConvertByteToString ( messageNetworkType )
networkTypeFoldername := "Network" + messageNetworkTypeString
messagesFolderPath := goFilepath . Join ( userDirectory , "MyBroadcasts" , "Messages" , networkTypeFoldername )
messageHashHex := encoding . EncodeBytesToHexString ( messageHash [ : ] )
filename := messageHashHex + ".messagepack"
err = localFilesystem . CreateOrOverwriteFile ( messageBytes , messagesFolderPath , filename )
if ( err != nil ) { return err }
return nil
}
// This function should only be called via the myReviews.CreateAndBroadcastMyReview function
func BroadcastMyReview ( newReview [ ] byte ) error {
myIdentityExists , myIdentityHash , err := myIdentity . GetMyIdentityHash ( "Moderator" )
if ( err != nil ) { return err }
if ( myIdentityExists == false ) {
return errors . New ( "Trying to broadcast review when my moderator identity does not exist." )
}
ableToRead , newReviewHash , _ , newReviewNetworkType , reviewerIdentityHash , _ , newReviewType , newReviewedHash , _ , _ , err := readReviews . ReadReviewAndHash ( true , newReview )
if ( err != nil ) { return err }
if ( ableToRead == false ) {
return errors . New ( "Trying to broadcast invalid review." )
}
if ( myIdentityHash != reviewerIdentityHash ) {
return errors . New ( "Trying to broadcast review not created by current moderator identity." )
}
userDirectory , err := localFilesystem . GetAppUserFolderPath ( )
if ( err != nil ) { return err }
newReviewNetworkTypeString := helpers . ConvertByteToString ( newReviewNetworkType )
networkTypeFoldername := "Network" + newReviewNetworkTypeString
reviewTypeFolderPath := goFilepath . Join ( userDirectory , "MyBroadcasts" , "Reviews" , newReviewType , networkTypeFoldername )
newReviewHashHex := encoding . EncodeBytesToHexString ( newReviewHash [ : ] )
newReviewFilename := newReviewHashHex + ".messagepack"
err = localFilesystem . CreateOrOverwriteFile ( newReview , reviewTypeFolderPath , newReviewFilename )
if ( err != nil ) { return err }
wellFormed , err := reviewStorage . AddReview ( newReview )
if ( err != nil ) { return err }
if ( wellFormed == false ) {
return errors . New ( "New review to broadcast is not well formed after being verified already." )
}
if ( newReviewType == "Profile" ) {
if ( len ( newReviewedHash ) != 28 ) {
reviewedHashHex := encoding . EncodeBytesToHexString ( newReviewedHash )
return errors . New ( "ReadReview returning invalid length reviewedHash for profile review: " + reviewedHashHex )
}
newReviewedProfileHash := [ 28 ] byte ( newReviewedHash )
err = mySkippedContent . DeleteProfileFromMySkippedProfilesMap ( newReviewedProfileHash )
if ( err != nil ) { return err }
} else if ( newReviewType == "Attribute" ) {
if ( len ( newReviewedHash ) != 27 ) {
reviewedHashHex := encoding . EncodeBytesToHexString ( newReviewedHash )
return errors . New ( "ReadReview returning invalid length reviewedHash for Attribute review: " + reviewedHashHex )
}
newReviewedAttributeHash := [ 27 ] byte ( newReviewedHash )
err = mySkippedContent . DeleteAttributeFromMySkippedAttributesMap ( newReviewedAttributeHash )
if ( err != nil ) { return err }
} else if ( newReviewType == "Message" ) {
if ( len ( newReviewedHash ) != 26 ) {
reviewedHashHex := encoding . EncodeBytesToHexString ( newReviewedHash )
return errors . New ( "ReadReview returning invalid length reviewedHash for Message review: " + reviewedHashHex )
}
newReviewedMessageHash := [ 26 ] byte ( newReviewedHash )
err = mySkippedContent . DeleteMessageFromMySkippedMessagesMap ( newReviewedMessageHash )
if ( err != nil ) { return err }
}
return nil
}
// This function will prune old reviews that have been replaced by new reviews
// For example, if we approved a message, then banned the same message later, we need to prune the approve review from our broadcasts
func PruneMyBroadcastedReviews ( ) error {
//TODO
// If our moderator identity does not exist, delete all of our revies
// We also need to deal with the reality that full profile approve verdicts replace attribute ban verdicts
// We also need to deal with the reality that attribute ban verdicts replace full profile approve verdicts
// We have to delete all reviews that are not the newest.
// None reviews must be kept, when they are not replaced by other reviews
return nil
}