244 lines
8.5 KiB
Go
244 lines
8.5 KiB
Go
|
|
// bannedModeratorConsensus provides functions to determine which moderators are banned
|
|
|
|
package bannedModeratorConsensus
|
|
|
|
import "seekia/internal/badgerDatabase"
|
|
import "seekia/internal/encoding"
|
|
import "seekia/internal/helpers"
|
|
import "seekia/internal/identity"
|
|
import "seekia/internal/moderation/moderatorRanking"
|
|
import "seekia/internal/moderation/moderatorScores"
|
|
import "seekia/internal/moderation/readReviews"
|
|
import "seekia/internal/parameters/getParameters"
|
|
|
|
import "slices"
|
|
import "sync"
|
|
import "errors"
|
|
|
|
var bannedModeratorsListMutex sync.RWMutex
|
|
|
|
// This list stores all banned moderators
|
|
// It will not necessarily be up to date
|
|
var bannedModeratorsList [][16]byte
|
|
|
|
// This variable keeps track of the networkType of the bannedModeratorsList
|
|
var bannedModeratorsListNetworkType byte
|
|
|
|
|
|
// This function should be called whenever the app network type is changed.
|
|
func UpdateBannedModeratorsList(networkType byte)error{
|
|
|
|
isValid := helpers.VerifyNetworkType(networkType)
|
|
if (isValid == false){
|
|
networkTypeString := helpers.ConvertByteToString(networkType)
|
|
return errors.New("UpdateBannedModeratorsList called with invalid networkType: " + networkTypeString)
|
|
}
|
|
|
|
bannedModeratorsListMutex.Lock()
|
|
bannedModeratorsList = nil
|
|
bannedModeratorsListNetworkType = 0
|
|
bannedModeratorsListMutex.Unlock()
|
|
|
|
_, _, _, err := GetBannedModeratorsList(false, networkType)
|
|
if (err != nil) { return err }
|
|
|
|
return nil
|
|
}
|
|
|
|
|
|
//Outputs:
|
|
// -bool: Moderator reviews and profiles are being downloaded (required to check if a moderator is banned)
|
|
// -bool: Parameters exist
|
|
// -bool: Moderator is banned
|
|
// -error
|
|
func GetModeratorIsBannedStatus(allowCache bool, identityHash [16]byte, networkType byte)(bool, bool, bool, error){
|
|
|
|
isValid, err := identity.VerifyIdentityHash(identityHash, true, "Moderator")
|
|
if (err != nil) { return false, false, false, err }
|
|
if (isValid == false){
|
|
identityHashHex := encoding.EncodeBytesToHexString(identityHash[:])
|
|
return false, false, false, errors.New("GetModeratorIsBannedStatus called with invalid identity hash: " + identityHashHex)
|
|
}
|
|
|
|
//TODO: Make it possible to retrieve the isBanned status without copying the cache list
|
|
|
|
downloadingRequiredData, parametersExist, bannedModeratorsList, err := GetBannedModeratorsList(allowCache, networkType)
|
|
if (err != nil) { return false, false, false, err }
|
|
if (downloadingRequiredData == false){
|
|
return false, false, false, nil
|
|
}
|
|
if (parametersExist == false){
|
|
return true, false, false, nil
|
|
}
|
|
|
|
isBanned := slices.Contains(bannedModeratorsList, identityHash)
|
|
|
|
return true, true, isBanned, nil
|
|
}
|
|
|
|
//Outputs:
|
|
// -bool: Moderator reviews and profiles are being downloaded (required to calculate the banned moderators list)
|
|
// -bool: Parameters exist
|
|
// -[][16]byte: List of banned moderators
|
|
// -error
|
|
func GetBannedModeratorsList(allowCache bool, networkType byte)(bool, bool, [][16]byte, error){
|
|
|
|
//TODO: Check if parameters exist and moderator reviews/profiles are being downloaded
|
|
|
|
isValid := helpers.VerifyNetworkType(networkType)
|
|
if (isValid == false){
|
|
networkTypeString := helpers.ConvertByteToString(networkType)
|
|
return false, false, nil, errors.New("GetBannedModeratorsList called with invalid networkType: " + networkTypeString)
|
|
}
|
|
|
|
if (allowCache == true){
|
|
|
|
bannedModeratorsListMutex.RLock()
|
|
|
|
if (bannedModeratorsList != nil && bannedModeratorsListNetworkType == networkType){
|
|
|
|
// Cache list has been generated and belongs to the specified network type.
|
|
|
|
listCopy := slices.Clone(bannedModeratorsList)
|
|
|
|
bannedModeratorsListMutex.RUnlock()
|
|
|
|
return true, true, listCopy, nil
|
|
}
|
|
|
|
bannedModeratorsListMutex.RUnlock()
|
|
}
|
|
|
|
// We must generate a new banned moderators cache list
|
|
|
|
rankedModeratorsList, err := moderatorRanking.GetRankedModeratorsList(networkType)
|
|
if (err != nil) { return false, false, nil, err }
|
|
|
|
// We start with the highest ranked moderator, and ban moderators as we traverse the list
|
|
// If an identity is found to be banned, all of its reviews are ignored
|
|
|
|
// Supermoderators are all-powerful moderators who can only be banned by higher-ranked supermoderators
|
|
// They are appointed by the admin(s)
|
|
|
|
parametersExist, supermoderatorsList, err := getParameters.GetSupermoderatorIdentityHashesList(networkType)
|
|
if (err != nil) { return false, false, nil, err }
|
|
if (parametersExist == false){
|
|
return true, false, nil, nil
|
|
}
|
|
|
|
// Supermoderators are added to the beginning of the ranked moderators list
|
|
rankedModeratorsList = append(supermoderatorsList, rankedModeratorsList...)
|
|
|
|
// Approved Moderators are the moderators who were not banned by anyone of a higher rank
|
|
// Map structure: Approved Moderator Identity Hash -> Nothing
|
|
approvedModeratorsMap := make(map[[16]byte]struct{})
|
|
|
|
// This map stores all banned identities
|
|
// Map structure: Banned Moderator Identity Hash -> Nothing
|
|
bannedModeratorsMap := make(map[[16]byte]struct{})
|
|
|
|
for _, moderatorIdentityHash := range rankedModeratorsList{
|
|
|
|
_, exists := bannedModeratorsMap[moderatorIdentityHash]
|
|
if (exists == true){
|
|
// This moderator has been banned, none of their reviews are counted. Skip them.
|
|
continue
|
|
}
|
|
|
|
// We make sure moderator is eligible
|
|
|
|
moderatorIsSupermoderator := slices.Contains(supermoderatorsList, moderatorIdentityHash)
|
|
if (moderatorIsSupermoderator == false){
|
|
|
|
// Moderator is not a supermoderator, so we make sure they are funded enough to be able to ban other moderators
|
|
|
|
scoreIsKnown, _, scoreIsSufficient, canBanModerators, _, err := moderatorScores.GetModeratorIdentityScore(moderatorIdentityHash)
|
|
if (err != nil) { return false, false, nil, err }
|
|
if (scoreIsKnown == false || scoreIsSufficient == false || canBanModerators == false){
|
|
// This moderator is not funded, or cannot ban moderators
|
|
continue
|
|
}
|
|
}
|
|
|
|
// This moderator is approved (not banned by any moderators with a higher rank)
|
|
approvedModeratorsMap[moderatorIdentityHash] = struct{}{}
|
|
|
|
// We create a list of all identity reviews created by this moderator
|
|
|
|
exists, reviewHashesList, err := badgerDatabase.GetReviewerReviewHashesList(moderatorIdentityHash, "Identity")
|
|
if (err != nil) { return false, false, nil, err }
|
|
if (exists == false){
|
|
// This moderator has not authored any reviews
|
|
continue
|
|
}
|
|
|
|
moderatorReviewsList := make([]readReviews.ReviewWithHash, 0)
|
|
|
|
for _, reviewHash := range reviewHashesList{
|
|
|
|
exists, reviewBytes, err := badgerDatabase.GetReview(reviewHash)
|
|
if (err != nil) { return false, false, nil, err }
|
|
if (exists == false){
|
|
// Review has been deleted. The missing entry will be removed automatically in the background.
|
|
continue
|
|
}
|
|
|
|
reviewObject := readReviews.ReviewWithHash{
|
|
ReviewHash: reviewHash,
|
|
ReviewBytes: reviewBytes,
|
|
}
|
|
|
|
moderatorReviewsList = append(moderatorReviewsList, reviewObject)
|
|
}
|
|
|
|
moderatorReviewsMap, err := readReviews.GetNewestModeratorReviewsMapFromReviewsList(moderatorReviewsList, moderatorIdentityHash, networkType, true, "Identity")
|
|
if (err != nil){ return false, false, nil, err }
|
|
|
|
for reviewedIdentityHashString, _ := range moderatorReviewsMap{
|
|
|
|
reviewedIdentityHashBytes := []byte(reviewedIdentityHashString)
|
|
|
|
if (len(reviewedIdentityHashBytes) != 16){
|
|
reviewedIdentityHashHex := encoding.EncodeBytesToHexString(reviewedIdentityHashBytes)
|
|
return false, false, nil, errors.New("GetNewestModeratorReviewsMapFromReviewsList returning non-identity reviewedHash: " + reviewedIdentityHashHex)
|
|
}
|
|
|
|
reviewedIdentityHash := [16]byte(reviewedIdentityHashBytes)
|
|
|
|
// Each reviewedIdentityHash is an identity this moderator has banned
|
|
|
|
identityType, err := identity.GetIdentityTypeFromIdentityHash(reviewedIdentityHash)
|
|
if (err != nil) {
|
|
reviewedIdentityHashHex := encoding.EncodeBytesToHexString(reviewedIdentityHash[:])
|
|
return false, false, nil, errors.New("GetNewestModeratorReviewsMapFromReviewsList returning non-identity reviewedHash: " + reviewedIdentityHashHex)
|
|
}
|
|
if (identityType != "Moderator"){
|
|
continue
|
|
}
|
|
|
|
_, exists = approvedModeratorsMap[reviewedIdentityHash]
|
|
if (exists == true){
|
|
//The current moderator cannot ban this moderator, because they are of a lower rank.
|
|
continue
|
|
}
|
|
bannedModeratorsMap[reviewedIdentityHash] = struct{}{}
|
|
}
|
|
}
|
|
|
|
// bannedModeratorsMap is a map whose keys are the identity hashes of banned moderators
|
|
newBannedModeratorsList := helpers.GetListOfMapKeys(bannedModeratorsMap)
|
|
|
|
bannedModeratorsListMutex.Lock()
|
|
|
|
bannedModeratorsList = newBannedModeratorsList
|
|
bannedModeratorsListNetworkType = networkType
|
|
|
|
listCopy := slices.Clone(bannedModeratorsList)
|
|
|
|
bannedModeratorsListMutex.Unlock()
|
|
|
|
return true, true, listCopy, nil
|
|
}
|
|
|
|
|