601 lines
23 KiB
Go
601 lines
23 KiB
Go
|
|
// 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)
|
|
newestProfileBroadcastTime := int64(0)
|
|
|
|
for _, profileBytes := range broadcastProfilesList{
|
|
|
|
ableToRead, profileHash, profileVersion, profileNetworkType, profileIdentityHash, profileBroadcastTime, _, rawProfileMap, err := readProfiles.ReadProfileAndHash(true, profileBytes)
|
|
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
|
|
}
|
|
|
|
if (anyProfileFound == false || profileBroadcastTime > newestProfileBroadcastTime){
|
|
|
|
anyProfileFound = true
|
|
newestProfileVersion = profileVersion
|
|
newestProfileHash = profileHash
|
|
newestProfileBytes = profileBytes
|
|
newestProfileRawProfileMap = rawProfileMap
|
|
newestProfileBroadcastTime = profileBroadcastTime
|
|
}
|
|
}
|
|
|
|
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.")
|
|
}
|
|
|
|
ableToRead, newProfileHash, _, newProfileNetworkType, profileIdentityHash, newProfileBroadcastTime, _, newProfileRawProfileMap, err := readProfiles.ReadProfileAndHash(true, newProfileBytes)
|
|
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){
|
|
|
|
err := myChatKeys.SetMyChatKeysLatestUpdateTime(myIdentityHash, networkType, newProfileBroadcastTime)
|
|
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
|
|
}
|
|
|
|
|
|
|
|
|