1042 lines
39 KiB
Go
1042 lines
39 KiB
Go
|
|
// reviewStorage provides functions to manage stored moderator reviews
|
|
// Reviews are created by moderators and determine the moderation verdict of messages, profiles, and identities.
|
|
|
|
package reviewStorage
|
|
|
|
import "seekia/internal/badgerDatabase"
|
|
import "seekia/internal/contentMetadata"
|
|
import "seekia/internal/encoding"
|
|
import "seekia/internal/helpers"
|
|
import "seekia/internal/identity"
|
|
import "seekia/internal/messaging/readMessages"
|
|
import "seekia/internal/moderation/readReviews"
|
|
import "seekia/internal/mySettings"
|
|
import "seekia/internal/network/appNetworkType/getAppNetworkType"
|
|
import "seekia/internal/network/backgroundDownloads"
|
|
import "seekia/internal/profiles/readProfiles"
|
|
|
|
import "bytes"
|
|
import "errors"
|
|
|
|
func GetNumberOfStoredReviews()(int64, error){
|
|
|
|
numberOfReviews, err := badgerDatabase.GetNumberOfReviews()
|
|
if (err != nil) { return 0, err }
|
|
|
|
return numberOfReviews, nil
|
|
}
|
|
|
|
|
|
//Outputs:
|
|
// -bool: Review is well formed
|
|
// -error
|
|
func AddReview(newReview []byte)(bool, error){
|
|
|
|
ableToRead, reviewHash, _, _, reviewerIdentityHash, _, reviewType, reviewedHash, _, _, err := readReviews.ReadReviewAndHash(true, newReview)
|
|
if (err != nil){ return false, err }
|
|
if (ableToRead == false){
|
|
// Review is malformed, do nothing
|
|
// Host who sent review must be malicious.
|
|
return false, nil
|
|
}
|
|
|
|
exists, _, err := badgerDatabase.GetReview(reviewHash)
|
|
if (err != nil) { return false, err }
|
|
if (exists == true){
|
|
// Review already imported, nothing to do.
|
|
return true, nil
|
|
}
|
|
|
|
err = badgerDatabase.AddReview(reviewHash, newReview)
|
|
if (err != nil) { return false, err }
|
|
|
|
err = mySettings.SetSetting("ViewedContentNeedsRefreshYesNo", "Yes")
|
|
if (err != nil) { return false, err }
|
|
|
|
err = badgerDatabase.AddReviewerReviewHash(reviewerIdentityHash, reviewHash)
|
|
if (err != nil) { return false, err }
|
|
|
|
if (reviewType == "Identity"){
|
|
|
|
if (len(reviewedHash) != 16){
|
|
reviewedHashHex := encoding.EncodeBytesToHexString(reviewedHash)
|
|
return false, errors.New("ReadReview returning invalid length reviewed Identity hash: " + reviewedHashHex)
|
|
}
|
|
|
|
reviewedIdentityHash := [16]byte(reviewedHash)
|
|
|
|
err := badgerDatabase.AddIdentityReviewToList(reviewedIdentityHash, reviewHash)
|
|
if (err != nil) { return false, err }
|
|
|
|
return true, nil
|
|
}
|
|
if (reviewType == "Profile"){
|
|
|
|
if (len(reviewedHash) != 28){
|
|
reviewedHashHex := encoding.EncodeBytesToHexString(reviewedHash)
|
|
return false, errors.New("ReadReview returning invalid length reviewed Profile hash: " + reviewedHashHex)
|
|
}
|
|
|
|
reviewedProfileHash := [28]byte(reviewedHash)
|
|
|
|
err = badgerDatabase.AddProfileReviewToList(reviewedProfileHash, reviewHash)
|
|
if (err != nil) { return false, err }
|
|
|
|
return true, nil
|
|
}
|
|
if (reviewType == "Attribute"){
|
|
|
|
if (len(reviewedHash) != 27){
|
|
reviewedHashHex := encoding.EncodeBytesToHexString(reviewedHash)
|
|
return false, errors.New("ReadReview returning invalid length reviewed Attribute hash: " + reviewedHashHex)
|
|
}
|
|
|
|
reviewedAttributeHash := [27]byte(reviewedHash)
|
|
|
|
err = badgerDatabase.AddProfileAttributeReviewToList(reviewedAttributeHash, reviewHash)
|
|
if (err != nil) { return false, err }
|
|
|
|
return true, nil
|
|
}
|
|
if (reviewType == "Message"){
|
|
|
|
if (len(reviewedHash) != 26){
|
|
reviewedHashHex := encoding.EncodeBytesToHexString(reviewedHash)
|
|
return false, errors.New("ReadReview returning invalid length reviewed Message hash: " + reviewedHashHex)
|
|
}
|
|
|
|
reviewedMessageHash := [26]byte(reviewedHash)
|
|
|
|
err = badgerDatabase.AddMessageReviewToList(reviewedMessageHash, reviewHash)
|
|
if (err != nil) { return false, err }
|
|
|
|
return true, nil
|
|
}
|
|
|
|
return false, errors.New("ReadReview returning invalid reviewType: " + reviewType)
|
|
}
|
|
|
|
//Outputs:
|
|
// -bool: Review exists
|
|
// -[]byte: Review bytes
|
|
// -map[string]string: Review map
|
|
// -error
|
|
func GetModeratorNewestIdentityReview(moderatorIdentityHash [16]byte, reviewedIdentityHash [16]byte, networkType byte)(bool, []byte, map[string]string, error){
|
|
|
|
isValid, err := identity.VerifyIdentityHash(moderatorIdentityHash, true, "Moderator")
|
|
if (err != nil) { return false, nil, nil, err }
|
|
if (isValid == false){
|
|
moderatorIdentityHashHex := encoding.EncodeBytesToHexString(moderatorIdentityHash[:])
|
|
return false, nil, nil, errors.New("GetModeratorNewestIdentityReview called with invalid moderatorIdentityHash: " + moderatorIdentityHashHex)
|
|
}
|
|
|
|
isValid, err = identity.VerifyIdentityHash(reviewedIdentityHash, false, "")
|
|
if (err != nil) { return false, nil, nil, err }
|
|
if (isValid == false){
|
|
reviewedIdentityHashHex := encoding.EncodeBytesToHexString(reviewedIdentityHash[:])
|
|
return false, nil, nil, errors.New("GetModeratorNewestIdentityReview called with invalid reviewedIdentityHash: " + reviewedIdentityHashHex)
|
|
}
|
|
|
|
isValid = helpers.VerifyNetworkType(networkType)
|
|
if (isValid == false){
|
|
networkTypeString := helpers.ConvertByteToString(networkType)
|
|
return false, nil, nil, errors.New("GetModeratorNewestIdentityReview called with invalid networkType: " + networkTypeString)
|
|
}
|
|
|
|
anyReviewsExist, reviewHashesList, err := badgerDatabase.GetIdentityReviewsList(reviewedIdentityHash)
|
|
if (err != nil) { return false, nil, nil, err }
|
|
if (anyReviewsExist == false){
|
|
return false, nil, nil, nil
|
|
}
|
|
|
|
reviewsList := make([]readReviews.ReviewWithHash, 0)
|
|
|
|
for _, reviewHash := range reviewHashesList{
|
|
|
|
exists, reviewBytes, err := badgerDatabase.GetReview(reviewHash)
|
|
if (err != nil) { return false, nil, nil, err }
|
|
if (exists == false){
|
|
// Review has been deleted. This missing entry will be removed automatically.
|
|
continue
|
|
}
|
|
|
|
newReviewObject := readReviews.ReviewWithHash{
|
|
ReviewHash: reviewHash,
|
|
ReviewBytes: reviewBytes,
|
|
}
|
|
|
|
reviewsList = append(reviewsList, newReviewObject)
|
|
}
|
|
|
|
verdictExists, reviewBytes, newestReviewMap, err := readReviews.GetModeratorNewestIdentityReviewFromReviewsList(reviewsList, moderatorIdentityHash, reviewedIdentityHash, networkType)
|
|
if (err != nil) { return false, nil, nil, err }
|
|
if (verdictExists == false){
|
|
return false, nil, nil, nil
|
|
}
|
|
return true, reviewBytes, newestReviewMap, nil
|
|
}
|
|
|
|
|
|
//Outputs:
|
|
// -bool: Profile verdict exists (At least 1 attribute ban, or a full profile approve/ban review exists)
|
|
// -string: Profile verdict "Ban"/"Approve" (incorporates full profile reviews and attribute bans)
|
|
// -bool: Full profile review exists
|
|
// -[]byte: Full profile review bytes
|
|
// -map[string]string: Full profile review map
|
|
// -map[[27]byte][]byte: Map of attribute approve reviews (Attribute hash -> Attribute review)
|
|
// -map[[27]byte][]byte: Map of attribute ban reviews (Attribute hash -> Attribute review)
|
|
// -error
|
|
func GetModeratorNewestProfileReviews(moderatorIdentityHash [16]byte, profileHash [28]byte, profileNetworkType byte, profileAttributeHashesList [][27]byte)(bool, string, bool, []byte, map[string]string, map[[27]byte][]byte, map[[27]byte][]byte, error){
|
|
|
|
isValid := helpers.VerifyNetworkType(profileNetworkType)
|
|
if (isValid == false){
|
|
profileNetworkTypeString := helpers.ConvertByteToString(profileNetworkType)
|
|
return false, "", false, nil, nil, nil, nil, errors.New("GetModeratorNewestProfileReviews called with invalid profileNetworkType: " + profileNetworkTypeString)
|
|
}
|
|
|
|
fullProfileReviewExists, fullProfileReviewBytes, fullProfileReviewMap, fullProfileReviewVerdict, fullProfileReviewTime, err := getModeratorNewestFullProfileReview(moderatorIdentityHash, profileHash, profileNetworkType)
|
|
if (err != nil) { return false, "", false, nil, nil, nil, nil, err }
|
|
|
|
// Full profile approvals can be overwritten by an attribute ban of any attribute within the profile
|
|
// We check for attribute reviews
|
|
|
|
//Map Structure: Attribute hash -> Attribute review bytes
|
|
approvedAttributesMap := make(map[[27]byte][]byte)
|
|
|
|
//Map Structure: Attribute hash -> Attribute review bytes
|
|
bannedAttributesMap := make(map[[27]byte][]byte)
|
|
|
|
for _, attributeHash := range profileAttributeHashesList{
|
|
|
|
attributeReviewExists, attributeReviewType, attributeReviewBytes, _, attributeReviewVerdict, attributeReviewTime, err := GetModeratorNewestProfileAttributeReview(moderatorIdentityHash, attributeHash, profileNetworkType, false)
|
|
if (err != nil){ return false, "", false, nil, nil, nil, nil, err }
|
|
if (attributeReviewExists == false){
|
|
continue
|
|
}
|
|
|
|
if (attributeReviewType != "Attribute"){
|
|
return false, "", false, nil, nil, nil, nil, errors.New("GetModeratorNewestProfileAttributeReview returning non-attribute review when integrateFullProfileApprovals == false")
|
|
}
|
|
|
|
if (attributeReviewVerdict == "Approve"){
|
|
// Attribute approve reviews do not change full profile ban reviews
|
|
approvedAttributesMap[attributeHash] = attributeReviewBytes
|
|
continue
|
|
}
|
|
|
|
if (fullProfileReviewExists == true && fullProfileReviewVerdict == "Approve"){
|
|
if (fullProfileReviewTime > attributeReviewTime){
|
|
// This attribute ban was created before the moderator approved the full profile
|
|
// It has therefore been overwritten
|
|
continue
|
|
}
|
|
}
|
|
|
|
bannedAttributesMap[attributeHash] = attributeReviewBytes
|
|
}
|
|
|
|
if (len(bannedAttributesMap) > 0){
|
|
|
|
// Profile is banned by moderator
|
|
|
|
if (fullProfileReviewExists == true && fullProfileReviewVerdict == "Approve"){
|
|
// An attribute was banned, which overwrites the full profile review
|
|
|
|
return true, "Ban", false, nil, nil, approvedAttributesMap, bannedAttributesMap, nil
|
|
}
|
|
|
|
return true, "Ban", fullProfileReviewExists, fullProfileReviewBytes, fullProfileReviewMap, approvedAttributesMap, bannedAttributesMap, nil
|
|
}
|
|
|
|
if (fullProfileReviewExists == false){
|
|
return false, "", false, nil, nil, approvedAttributesMap, bannedAttributesMap, nil
|
|
}
|
|
|
|
return true, fullProfileReviewVerdict, true, fullProfileReviewBytes, fullProfileReviewMap, approvedAttributesMap, bannedAttributesMap, nil
|
|
}
|
|
|
|
|
|
// This function does not integrate the moderator's attribute reviews
|
|
//Outputs:
|
|
// -bool: Review exists
|
|
// -[]byte: Review bytes
|
|
// -map[string]string: Review map
|
|
// -string: Review verdict
|
|
// -int64: Review creation time
|
|
// -error
|
|
func getModeratorNewestFullProfileReview(moderatorIdentityHash [16]byte, profileHash [28]byte, profileNetworkType byte)(bool, []byte, map[string]string, string, int64, error){
|
|
|
|
isValid, err := identity.VerifyIdentityHash(moderatorIdentityHash, true, "Moderator")
|
|
if (err != nil) { return false, nil, nil, "", 0, err }
|
|
if (isValid == false){
|
|
moderatorIdentityHashHex := encoding.EncodeBytesToHexString(moderatorIdentityHash[:])
|
|
return false, nil, nil, "", 0, errors.New("getModeratorNewestFullProfileReview called with invalid moderatorIdentityHash: " + moderatorIdentityHashHex)
|
|
}
|
|
|
|
isValid, err = readProfiles.VerifyProfileHash(profileHash, false, "", true, false)
|
|
if (err != nil){ return false, nil, nil, "", 0, err }
|
|
if (isValid == false){
|
|
profileHashHex := encoding.EncodeBytesToHexString(profileHash[:])
|
|
return false, nil, nil, "", 0, errors.New("getModeratorNewestFullProfileReview called with invalid profileHash: " + profileHashHex)
|
|
}
|
|
|
|
isValid = helpers.VerifyNetworkType(profileNetworkType)
|
|
if (isValid == false){
|
|
profileNetworkTypeString := helpers.ConvertByteToString(profileNetworkType)
|
|
return false, nil, nil, "", 0, errors.New("getModeratorNewestFullProfileReview called with invalid profileNetworkType: " + profileNetworkTypeString)
|
|
}
|
|
|
|
anyReviewsExist, reviewHashesList, err := badgerDatabase.GetProfileReviewsList(profileHash)
|
|
if (err != nil) { return false, nil, nil, "", 0, err }
|
|
if (anyReviewsExist == false){
|
|
return false, nil, nil, "", 0, nil
|
|
}
|
|
|
|
reviewsList := make([]readReviews.ReviewWithHash, 0)
|
|
|
|
for _, reviewHash := range reviewHashesList{
|
|
|
|
exists, reviewBytes, err := badgerDatabase.GetReview(reviewHash)
|
|
if (err != nil) { return false, nil, nil, "", 0, err }
|
|
if (exists == false){
|
|
// Review has been deleted. This missing entry will be removed automatically.
|
|
continue
|
|
}
|
|
|
|
reviewObject := readReviews.ReviewWithHash{
|
|
ReviewHash: reviewHash,
|
|
ReviewBytes: reviewBytes,
|
|
}
|
|
|
|
reviewsList = append(reviewsList, reviewObject)
|
|
}
|
|
|
|
reviewExists, reviewBytes, reviewMap, reviewVerdict, reviewTime, err := readReviews.GetModeratorNewestProfileReviewFromReviewsList(reviewsList, moderatorIdentityHash, profileHash, profileNetworkType)
|
|
if (err != nil) { return false, nil, nil, "", 0, err }
|
|
if (reviewExists == false){
|
|
return false, nil, nil, "", 0, nil
|
|
}
|
|
|
|
return true, reviewBytes, reviewMap, reviewVerdict, reviewTime, nil
|
|
}
|
|
|
|
|
|
//Outputs:
|
|
// -bool: Review exists
|
|
// -string: Review Type ("Profile"/"Attribute")
|
|
// -[]byte: Review bytes
|
|
// -map[string]string: Review map
|
|
// -string: Review verdict
|
|
// -int64: Time of review
|
|
// -error
|
|
func GetModeratorNewestProfileAttributeReview(moderatorIdentityHash [16]byte, attributeHash [27]byte, attributeNetworkType byte, integrateFullProfileApprovals bool)(bool, string, []byte, map[string]string, string, int64, error){
|
|
|
|
isValid, err := identity.VerifyIdentityHash(moderatorIdentityHash, true, "Moderator")
|
|
if (err != nil) { return false, "", nil, nil, "", 0, err }
|
|
if (isValid == false){
|
|
moderatorIdentityHashHex := encoding.EncodeBytesToHexString(moderatorIdentityHash[:])
|
|
return false, "", nil, nil, "", 0, errors.New("GetModeratorNewestProfileAttributeReview called with invalid moderatorIdentityHash: " + moderatorIdentityHashHex)
|
|
}
|
|
|
|
isValid, err = readProfiles.VerifyAttributeHash(attributeHash, false, "", false, false)
|
|
if (err != nil) { return false, "", nil, nil, "", 0, err }
|
|
if (isValid == false){
|
|
attributeHashHex := encoding.EncodeBytesToHexString(attributeHash[:])
|
|
return false, "", nil, nil, "", 0, errors.New("GetModeratorNewestProfileAttributeReview called with invalid attributeHash: " + attributeHashHex)
|
|
}
|
|
|
|
isValid = helpers.VerifyNetworkType(attributeNetworkType)
|
|
if (isValid == false){
|
|
attributeNetworkTypeString := helpers.ConvertByteToString(attributeNetworkType)
|
|
return false, "", nil, nil, "", 0, errors.New("GetModeratorNewestProfileAttributeReview called with invalid attributeNetworkType: " + attributeNetworkTypeString)
|
|
}
|
|
|
|
//Outputs:
|
|
// -bool: Attribute review exists
|
|
// -[]byte: Review bytes
|
|
// -map[string]string: Review map
|
|
// -string: Review verdict
|
|
// -int64: Review creation time
|
|
// -error
|
|
getModeratorNewestAttributeReview := func()(bool, []byte, map[string]string, string, int64, error){
|
|
|
|
anyReviewsExist, reviewHashesList, err := badgerDatabase.GetProfileAttributeReviewsList(attributeHash)
|
|
if (err != nil) { return false, nil, nil, "", 0, err }
|
|
if (anyReviewsExist == false){
|
|
return false, nil, nil, "", 0, nil
|
|
}
|
|
|
|
reviewsList := make([]readReviews.ReviewWithHash, 0)
|
|
|
|
for _, reviewHash := range reviewHashesList{
|
|
|
|
exists, reviewBytes, err := badgerDatabase.GetReview(reviewHash)
|
|
if (err != nil) { return false, nil, nil, "", 0, err }
|
|
if (exists == false){
|
|
// Review has been deleted. This missing entry will be removed automatically.
|
|
continue
|
|
}
|
|
|
|
reviewObject := readReviews.ReviewWithHash{
|
|
ReviewHash: reviewHash,
|
|
ReviewBytes: reviewBytes,
|
|
}
|
|
|
|
reviewsList = append(reviewsList, reviewObject)
|
|
}
|
|
|
|
attributeReviewExists, attributeReviewBytes, attributeReviewMap, attributeReviewVerdict, attributeReviewTime, err := readReviews.GetModeratorNewestProfileAttributeReviewFromReviewsList(reviewsList, moderatorIdentityHash, attributeHash, attributeNetworkType)
|
|
if (err != nil) { return false, nil, nil, "", 0, err }
|
|
if (attributeReviewExists == false){
|
|
return false, nil, nil, "", 0, nil
|
|
}
|
|
|
|
return true, attributeReviewBytes, attributeReviewMap, attributeReviewVerdict, attributeReviewTime, nil
|
|
}
|
|
|
|
attributeReviewExists, attributeReviewBytes, attributeReviewMap, attributeReviewVerdict, attributeReviewTime, err := getModeratorNewestAttributeReview()
|
|
if (err != nil) { return false, "", nil, nil, "", 0, err }
|
|
|
|
if (integrateFullProfileApprovals == false){
|
|
|
|
if (attributeReviewExists == false){
|
|
return false, "", nil, nil, "", 0, nil
|
|
}
|
|
|
|
return true, "Attribute", attributeReviewBytes, attributeReviewMap, attributeReviewVerdict, attributeReviewTime, nil
|
|
}
|
|
|
|
if (attributeReviewExists == true && attributeReviewVerdict == "Approve"){
|
|
|
|
// The user approved the attribute
|
|
// We don't have to check for full profile approvals, because they would not change this verdict
|
|
|
|
return true, "Attribute", attributeReviewBytes, attributeReviewMap, "Approve", attributeReviewTime, nil
|
|
}
|
|
|
|
// Now we check for full profile approvals
|
|
// A full profile approval is equivalent to an attribute approval for all attributes within the profile
|
|
// attributeProfileHashesList is a list of all profile hashes for profiles which contain the attribute
|
|
|
|
anyExist, attributeProfileHashesList, err := badgerDatabase.GetAttributeProfilesList(attributeHash)
|
|
if (err != nil) { return false, "", nil, nil, "", 0, err }
|
|
if (anyExist == true){
|
|
|
|
for _, profileHash := range attributeProfileHashesList{
|
|
|
|
// We are only checking for full profile approvals
|
|
// We don't need to check for profile attribute bans, because we are only concerned with the provided attribute's status
|
|
// A full profile approval approves all attributes.
|
|
// If a user bans a full profile, it does not change the status of any of their attribute approvals of the profile
|
|
|
|
fullProfileReviewExists, fullProfileReviewBytes, fullProfileReviewMap, fullProfileVerdict, fullProfileVerdictTime, err := getModeratorNewestFullProfileReview(moderatorIdentityHash, profileHash, attributeNetworkType)
|
|
if (err != nil){ return false, "", nil, nil, "", 0, err }
|
|
if (fullProfileReviewExists == true && fullProfileVerdict == "Approve"){
|
|
|
|
if (attributeReviewExists == true && fullProfileVerdictTime < attributeReviewTime){
|
|
// The moderator banned the attribute after approving the full profile
|
|
// The profile approval is therefore disregarded.
|
|
continue
|
|
}
|
|
// The moderator approved the full profile after banning the attribute, thus, the attribute is approved
|
|
|
|
return true, "Profile", fullProfileReviewBytes, fullProfileReviewMap, "Approve", fullProfileVerdictTime, nil
|
|
}
|
|
}
|
|
}
|
|
|
|
if (attributeReviewExists == true){
|
|
// We could not find any full profile approvals that undo the attribute ban
|
|
return true, "Attribute", attributeReviewBytes, attributeReviewMap, "Ban", attributeReviewTime, nil
|
|
}
|
|
|
|
return false, "", nil, nil, "", 0, nil
|
|
}
|
|
|
|
|
|
//Outputs:
|
|
// -bool: Review exists
|
|
// -[]byte: Review bytes
|
|
// -map[string]string: Review map
|
|
// -error
|
|
func GetModeratorNewestMessageReview(moderatorIdentityHash [16]byte, messageHash [26]byte, messageNetworkType byte, messageCipherKey [25]byte)(bool, []byte, map[string]string, error){
|
|
|
|
isValid, err := identity.VerifyIdentityHash(moderatorIdentityHash, true, "Moderator")
|
|
if (err != nil) { return false, nil, nil, err }
|
|
if (isValid == false){
|
|
moderatorIdentityHashHex := encoding.EncodeBytesToHexString(moderatorIdentityHash[:])
|
|
return false, nil, nil, errors.New("GetModeratorNewestMessageReview called with invalid moderatorIdentityHash: " + moderatorIdentityHashHex)
|
|
}
|
|
|
|
isValid = helpers.VerifyNetworkType(messageNetworkType)
|
|
if (isValid == false){
|
|
messageNetworkTypeString := helpers.ConvertByteToString(messageNetworkType)
|
|
return false, nil, nil, errors.New("GetModeratorNewestMessageReview called with invalid messageNetworkType: " + messageNetworkTypeString)
|
|
}
|
|
|
|
anyReviewsExist, reviewHashesList, err := badgerDatabase.GetMessageReviewsList(messageHash)
|
|
if (err != nil) { return false, nil, nil, err }
|
|
if (anyReviewsExist == false){
|
|
return false, nil, nil, nil
|
|
}
|
|
|
|
reviewsList := make([]readReviews.ReviewWithHash, 0)
|
|
|
|
for _, reviewHash := range reviewHashesList{
|
|
|
|
exists, reviewBytes, err := badgerDatabase.GetReview(reviewHash)
|
|
if (err != nil) { return false, nil, nil, err }
|
|
if (exists == false){
|
|
// Review has been deleted. This missing entry will be removed automatically.
|
|
continue
|
|
}
|
|
|
|
reviewObject := readReviews.ReviewWithHash{
|
|
ReviewHash: reviewHash,
|
|
ReviewBytes: reviewBytes,
|
|
}
|
|
|
|
reviewsList = append(reviewsList, reviewObject)
|
|
}
|
|
|
|
reviewExists, reviewBytes, reviewMap, _, err := readReviews.GetModeratorNewestMessageReviewFromReviewsList(reviewsList, moderatorIdentityHash, messageHash, messageNetworkType, messageCipherKey)
|
|
if (err != nil) { return false, nil, nil, err }
|
|
if (reviewExists == false){
|
|
return false, nil, nil, nil
|
|
}
|
|
|
|
return true, reviewBytes, reviewMap, nil
|
|
}
|
|
|
|
// This function returns all reviews by a provided moderator, omitting older reviews for the same reviewed hashes
|
|
// Will omit None reviews
|
|
//Outputs:
|
|
// -[][]byte: List of reviews
|
|
// -error
|
|
func GetAllNewestReviewsCreatedByModerator(moderatorIdentityHash [16]byte, reviewType string, networkType byte)([][]byte, error){
|
|
|
|
isValid := helpers.VerifyNetworkType(networkType)
|
|
if (isValid == false){
|
|
networkTypeString := helpers.ConvertByteToString(networkType)
|
|
return nil, errors.New("GetAllNewestReviewsCreatedByModerator called with invalid networkType: " + networkTypeString)
|
|
}
|
|
|
|
exists, reviewHashesList, err := badgerDatabase.GetReviewerReviewHashesList(moderatorIdentityHash, reviewType)
|
|
if (err != nil) { return nil, err }
|
|
if (exists == false){
|
|
emptyList := make([][]byte, 0)
|
|
return emptyList, nil
|
|
}
|
|
|
|
reviewsList := make([]readReviews.ReviewWithHash, 0)
|
|
|
|
for _, reviewHash := range reviewHashesList{
|
|
|
|
exists, reviewBytes, err := badgerDatabase.GetReview(reviewHash)
|
|
if (err != nil) { return 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,
|
|
}
|
|
|
|
reviewsList = append(reviewsList, reviewObject)
|
|
}
|
|
|
|
reviewsMap, err := readReviews.GetNewestModeratorReviewsMapFromReviewsList(reviewsList, moderatorIdentityHash, networkType, true, reviewType)
|
|
if (err != nil) { return nil, err }
|
|
|
|
newestReviewsList := helpers.GetListOfMapValues(reviewsMap)
|
|
|
|
return newestReviewsList, nil
|
|
}
|
|
|
|
|
|
// This function returns the number of ban advocates for a user
|
|
// This returns all advocates, banned or not
|
|
//Outputs:
|
|
// -bool: Downloading required reviews and profiles
|
|
// -int: Number of ban advocates
|
|
// -error
|
|
func GetNumberOfBanAdvocatesForIdentity(identityHash [16]byte, networkType byte)(bool, int, error){
|
|
|
|
isValid := helpers.VerifyNetworkType(networkType)
|
|
if (isValid == false){
|
|
networkTypeString := helpers.ConvertByteToString(networkType)
|
|
return false, 0, errors.New("GetNumberOfBanAdvocatesForIdentity called with invalid networkType: " + networkTypeString)
|
|
}
|
|
|
|
appNetworkType, err := getAppNetworkType.GetAppNetworkType()
|
|
if (err != nil) { return false, 0, err }
|
|
if (appNetworkType != networkType){
|
|
// We are not downloading reviews for this network type.
|
|
return false, 0, nil
|
|
}
|
|
|
|
downloadingRequiredReviews, err := backgroundDownloads.CheckIfAppCanDetermineIdentityVerdicts(identityHash)
|
|
if (err != nil) { return false, 0, err }
|
|
if (downloadingRequiredReviews == false){
|
|
return false, 0, nil
|
|
}
|
|
|
|
banAdvocatesMap, err := GetIdentityBanAdvocatesMap(identityHash, networkType)
|
|
if (err != nil) { return false, 0, err }
|
|
|
|
numberOfBanAdvocates := len(banAdvocatesMap)
|
|
|
|
return true, numberOfBanAdvocates, nil
|
|
}
|
|
|
|
|
|
//Outputs:
|
|
// -bool: Message metadata is known
|
|
// -bool: Downloading required reviews and profiles
|
|
// -int: Number of reviewers
|
|
// -error
|
|
func GetNumberOfMessageReviewers(messageHash [26]byte)(bool, bool, int, error){
|
|
|
|
metadataExists, _, messageNetworkType, _, messageInbox, messageCipherKeyHash, err := contentMetadata.GetMessageMetadata(messageHash)
|
|
if (err != nil) { return false, false, 0, err }
|
|
if (metadataExists == false){
|
|
return false, false, 0, nil
|
|
}
|
|
|
|
downloadingRequiredData, err := backgroundDownloads.CheckIfAppCanDetermineMessageVerdict(messageNetworkType, messageInbox, true, messageHash)
|
|
if (err != nil) { return false, false, 0, err }
|
|
if (downloadingRequiredData == false){
|
|
return true, false, 0, nil
|
|
}
|
|
|
|
approveAdvocatesMap, banAdvocatesMap, err := GetMessageVerdictMaps(messageHash, messageNetworkType, messageCipherKeyHash)
|
|
if (err != nil) { return false, false, 0, err }
|
|
|
|
numberOfReviewers := len(approveAdvocatesMap) + len(banAdvocatesMap)
|
|
|
|
return true, true, numberOfReviewers, nil
|
|
}
|
|
|
|
// This function will integrate attribute bans
|
|
//Outputs:
|
|
// -bool: Profile metadata is known
|
|
// -bool: Downloading required reviews and profiles
|
|
// -int: Number of reviewers
|
|
// -error
|
|
func GetNumberOfProfileReviewers(profileHash [28]byte)(bool, bool, int, error){
|
|
|
|
metadataExists, _, profileNetworkType, profileAuthor, _, profileIsDisabled, _, profileAttributeHashesMap, err := contentMetadata.GetProfileMetadata(profileHash)
|
|
if (err != nil) { return false, false, 0, err }
|
|
if (metadataExists == false){
|
|
return false, false, 0, nil
|
|
}
|
|
if (profileIsDisabled == true){
|
|
// Disabled profiles cannot be reviewed
|
|
return true, true, 0, nil
|
|
}
|
|
|
|
appNetworkType, err := getAppNetworkType.GetAppNetworkType()
|
|
if (err != nil) { return false, false, 0, err }
|
|
if (appNetworkType != profileNetworkType){
|
|
// We are not downloading reviews for this network type.
|
|
return true, false, 0, nil
|
|
}
|
|
|
|
downloadingRequiredReviews, err := backgroundDownloads.CheckIfAppCanDetermineIdentityVerdicts(profileAuthor)
|
|
if (err != nil) { return false, false, 0, err }
|
|
if (downloadingRequiredReviews == false){
|
|
return true, false, 0, nil
|
|
}
|
|
|
|
// profileAttributeHashesMap is a map whose values are the attribute hashes of the profile
|
|
profileAttributeHashesList := helpers.GetListOfMapValues(profileAttributeHashesMap)
|
|
|
|
approveAdvocatesMap, banAdvocatesMap, err := GetProfileVerdictMaps(profileHash, profileNetworkType, true, profileAttributeHashesList)
|
|
if (err != nil) { return false, false, 0, err }
|
|
|
|
numberOfReviewers := len(approveAdvocatesMap) + len(banAdvocatesMap)
|
|
|
|
return true, true, numberOfReviewers, nil
|
|
}
|
|
|
|
// This function will go through all reviews for an identity and return the ban advocates
|
|
//Outputs:
|
|
// -map[[16]byte]int64: Ban advocate identity hash -> Time of ban
|
|
// -error
|
|
func GetIdentityBanAdvocatesMap(identityHash [16]byte, networkType byte)(map[[16]byte]int64, error){
|
|
|
|
isValid := helpers.VerifyNetworkType(networkType)
|
|
if (isValid == false){
|
|
networkTypeString := helpers.ConvertByteToString(networkType)
|
|
return nil, errors.New("GetIdentityBanAdvocatesMap called with invalid networkType: " + networkTypeString)
|
|
}
|
|
|
|
exists, reviewHashesList, err := badgerDatabase.GetIdentityReviewsList(identityHash)
|
|
if (err != nil) { return nil, err }
|
|
if (exists == false){
|
|
emptyMap := make(map[[16]byte]int64)
|
|
return emptyMap, nil
|
|
}
|
|
|
|
reviewsList := make([]readReviews.ReviewWithHash, 0)
|
|
|
|
for _, reviewHash := range reviewHashesList{
|
|
|
|
exists, reviewBytes, err := badgerDatabase.GetReview(reviewHash)
|
|
if (err != nil) { return nil, err }
|
|
if (exists == false){
|
|
// Review must have been deleted. The missing review entry will be pruned automatically
|
|
continue
|
|
}
|
|
|
|
reviewObject := readReviews.ReviewWithHash{
|
|
ReviewHash: reviewHash,
|
|
ReviewBytes: reviewBytes,
|
|
}
|
|
|
|
reviewsList = append(reviewsList, reviewObject)
|
|
}
|
|
|
|
banAdvocatesMap, err := readReviews.GetIdentityBanAdvocatesMapFromReviewsList(reviewsList, identityHash, networkType)
|
|
if (err != nil) { return nil, err }
|
|
|
|
return banAdvocatesMap, nil
|
|
}
|
|
|
|
// This function will go through all reviews for a profile and return the approve and ban advocates
|
|
// If integrateAttributeBans == false, we will only check for full profile approvals/bans
|
|
//Outputs:
|
|
// -map[[16]byte]int64: Approve advocates map (Moderator identity hash -> Time of review)
|
|
// -map[[16]byte]int64: Ban advocates map (Moderator identity hash -> Time of review)
|
|
// -error
|
|
func GetProfileVerdictMaps(profileHash [28]byte, profileNetworkType byte, integrateAttributeBans bool, attributeHashesList [][27]byte)(map[[16]byte]int64, map[[16]byte]int64, error){
|
|
|
|
isValid := helpers.VerifyNetworkType(profileNetworkType)
|
|
if (isValid == false){
|
|
profileNetworkTypeString := helpers.ConvertByteToString(profileNetworkType)
|
|
return nil, nil, errors.New("GetProfileVerdictMaps called with invalid profileNetworkType: " + profileNetworkTypeString)
|
|
}
|
|
|
|
exists, reviewHashesList, err := badgerDatabase.GetProfileReviewsList(profileHash)
|
|
if (err != nil) { return nil, nil, err }
|
|
if (exists == false){
|
|
emptyMapA := make(map[[16]byte]int64)
|
|
emptyMapB := make(map[[16]byte]int64)
|
|
|
|
return emptyMapA, emptyMapB, nil
|
|
}
|
|
|
|
reviewsList := make([]readReviews.ReviewWithHash, 0)
|
|
|
|
for _, reviewHash := range reviewHashesList{
|
|
|
|
exists, reviewBytes, err := badgerDatabase.GetReview(reviewHash)
|
|
if (err != nil) { return nil, nil, err }
|
|
if (exists == false){
|
|
// Review has been deleted. The missing review entry will be pruned automatically.
|
|
continue
|
|
}
|
|
|
|
reviewObject := readReviews.ReviewWithHash{
|
|
ReviewHash: reviewHash,
|
|
ReviewBytes: reviewBytes,
|
|
}
|
|
|
|
reviewsList = append(reviewsList, reviewObject)
|
|
}
|
|
|
|
approveAdvocatesMap, banAdvocatesMap, err := readReviews.GetProfileVerdictMapsFromReviewsList(reviewsList, profileHash, profileNetworkType)
|
|
if (err != nil) { return nil, nil, err }
|
|
|
|
if (integrateAttributeBans == false){
|
|
return approveAdvocatesMap, banAdvocatesMap, nil
|
|
}
|
|
|
|
// Now we check for attribute ban advocates
|
|
// A ban of any attribute within the profile is equivalent to a profile ban
|
|
// attributeHashesList is a list of all attribute hashes within the provided profile
|
|
|
|
integrateProfileAttributeBans := func()error{
|
|
|
|
for _, attributeHash := range attributeHashesList{
|
|
|
|
// We have to check for full profile reviews of all profiles by the user that contain this attribute
|
|
// Any of these full profile approvals are equivalent to approving all profile attributes
|
|
|
|
getAttributeProfileHashesList := func()([][28]byte, error){
|
|
|
|
exists, attributeProfilesList, err := badgerDatabase.GetAttributeProfilesList(attributeHash)
|
|
if (err != nil) { return nil, err }
|
|
if (exists == false){
|
|
emptyList := make([][28]byte, 0)
|
|
return emptyList, nil
|
|
}
|
|
|
|
// We can omit the current profileHash, because we are already checking it
|
|
attributeProfileHashesList, _ := helpers.DeleteAllMatchingItemsFromProfileHashList(attributeProfilesList, profileHash)
|
|
|
|
return attributeProfileHashesList, nil
|
|
}
|
|
|
|
attributeProfileHashesList, err := getAttributeProfileHashesList()
|
|
if (err != nil) { return err }
|
|
|
|
_, attributeBanAdvocatesMap, err := GetProfileAttributeVerdictMaps(attributeHash, profileNetworkType, true, attributeProfileHashesList)
|
|
if (err != nil) { return err }
|
|
|
|
for moderatorIdentityHash, attributeBanTime := range attributeBanAdvocatesMap{
|
|
|
|
existingApproveTime, exists := approveAdvocatesMap[moderatorIdentityHash]
|
|
if (exists == true){
|
|
if (existingApproveTime < attributeBanTime){
|
|
// The moderator banned a profile attribute after approving the profile
|
|
delete(approveAdvocatesMap, moderatorIdentityHash)
|
|
banAdvocatesMap[moderatorIdentityHash] = attributeBanTime
|
|
|
|
// We don't have to check for any more attribute bans
|
|
// They can only cause an full profile approval to change to a ban
|
|
|
|
return nil
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
err = integrateProfileAttributeBans()
|
|
if (err != nil) { return nil, nil, err }
|
|
|
|
return approveAdvocatesMap, banAdvocatesMap, nil
|
|
}
|
|
|
|
// This function will go through all reviews for a profile attribute and return the approve and ban advocates
|
|
// This also finds full profile approve reviews and treats them as approvals for all attributes within the profile
|
|
//Outputs:
|
|
// -map[[16]byte]int64: Approve advocates map (Moderator identity hash -> Time of approval)
|
|
// -map[[16]byte]int64: Ban advocates map (Moderator identity hash -> Time of ban)
|
|
// -error
|
|
func GetProfileAttributeVerdictMaps(attributeHash [27]byte, attributeNetworkType byte, integrateFullProfileApprovals bool, attributeProfileHashesList [][28]byte)(map[[16]byte]int64, map[[16]byte]int64, error){
|
|
|
|
isValid := helpers.VerifyNetworkType(attributeNetworkType)
|
|
if (isValid == false){
|
|
attributeNetworkTypeString := helpers.ConvertByteToString(attributeNetworkType)
|
|
return nil, nil, errors.New("GetProfileAttributeVerdictMaps called with invalid attributeNetworkType: " + attributeNetworkTypeString)
|
|
}
|
|
|
|
exists, reviewHashesList, err := badgerDatabase.GetProfileAttributeReviewsList(attributeHash)
|
|
if (err != nil) { return nil, nil, err }
|
|
if (exists == false){
|
|
emptyMapA := make(map[[16]byte]int64)
|
|
emptyMapB := make(map[[16]byte]int64)
|
|
|
|
return emptyMapA, emptyMapB, nil
|
|
}
|
|
|
|
reviewsList := make([]readReviews.ReviewWithHash, 0)
|
|
|
|
for _, reviewHash := range reviewHashesList{
|
|
|
|
exists, reviewBytes, err := badgerDatabase.GetReview(reviewHash)
|
|
if (err != nil) { return nil, nil, err }
|
|
if (exists == false){
|
|
// Review has been deleted. The missing review entry will be pruned automatically
|
|
continue
|
|
}
|
|
|
|
reviewObject := readReviews.ReviewWithHash{
|
|
ReviewHash: reviewHash,
|
|
ReviewBytes: reviewBytes,
|
|
}
|
|
|
|
reviewsList = append(reviewsList, reviewObject)
|
|
}
|
|
|
|
approveAdvocatesMap, banAdvocatesMap, err := readReviews.GetProfileAttributeVerdictMapsFromReviewsList(reviewsList, attributeHash, attributeNetworkType)
|
|
if (err != nil) { return nil, nil, err }
|
|
|
|
if (integrateFullProfileApprovals == false){
|
|
return approveAdvocatesMap, banAdvocatesMap, nil
|
|
}
|
|
|
|
// Now we check for full profile approve advocates
|
|
// A full profile approval is equivalent to an attribute approval for all attributes within the profile
|
|
// attributeProfileHashesList is a list of all profile hashes for profiles which contain the attribute
|
|
|
|
integrateProfileApprovals := func()error{
|
|
|
|
for _, profileHash := range attributeProfileHashesList{
|
|
|
|
// We are only checking for full profile approvals
|
|
// We don't need to check for profile attribute bans, because we are only concerned with the provided attribute's status
|
|
// A full profile approval approves all attributes.
|
|
// If the user bans a profile's attribute after approving the full profile, the other attributes are still considered approved by the user
|
|
|
|
fullProfileApproveAdvocatesMap, _, err := GetProfileVerdictMaps(profileHash, attributeNetworkType, false, nil)
|
|
if (err != nil) { return err }
|
|
|
|
for moderatorIdentityHash, fullProfileApproveTime := range fullProfileApproveAdvocatesMap{
|
|
|
|
existingBanTime, exists := banAdvocatesMap[moderatorIdentityHash]
|
|
if (exists == true){
|
|
if (existingBanTime < fullProfileApproveTime){
|
|
// The moderator approved the full profile after banning the attribute
|
|
delete(banAdvocatesMap, moderatorIdentityHash)
|
|
approveAdvocatesMap[moderatorIdentityHash] = fullProfileApproveTime
|
|
|
|
// We don't have to check for any more full profile approvals
|
|
// They can only cause an attribute ban to change to an approval
|
|
|
|
return nil
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
err = integrateProfileApprovals()
|
|
if (err != nil) { return nil, nil, err }
|
|
|
|
return approveAdvocatesMap, banAdvocatesMap, nil
|
|
}
|
|
|
|
|
|
|
|
// This function will go through all reviews for a message and return the approve and ban advocates
|
|
// We use the provided message CipherKeyHash to ensure the reviewers have seen the message
|
|
//Outputs:
|
|
// -map[[16]byte]int64: Approve advocate identity hash -> Time of approval
|
|
// -map[[16]byte]int64: Ban advocate identity hash -> Time of ban
|
|
// -error
|
|
func GetMessageVerdictMaps(messageHash [26]byte, messageNetworkType byte, messageCipherKeyHash [25]byte)(map[[16]byte]int64, map[[16]byte]int64, error){
|
|
|
|
isValid := helpers.VerifyNetworkType(messageNetworkType)
|
|
if (isValid == false){
|
|
messageNetworkTypeString := helpers.ConvertByteToString(messageNetworkType)
|
|
return nil, nil, errors.New("GetMessageVerdictMaps called with invalid messageNetworkType: " + messageNetworkTypeString)
|
|
}
|
|
|
|
exists, reviewHashesList, err := badgerDatabase.GetMessageReviewsList(messageHash)
|
|
if (err != nil) { return nil, nil, err }
|
|
if (exists == false){
|
|
|
|
// There are no reviews for this message
|
|
|
|
emptyMapA := make(map[[16]byte]int64)
|
|
emptyMapB := make(map[[16]byte]int64)
|
|
|
|
return emptyMapA, emptyMapB, nil
|
|
}
|
|
|
|
reviewsList := make([]readReviews.ReviewWithHash, 0)
|
|
|
|
for _, reviewHash := range reviewHashesList{
|
|
|
|
exists, reviewBytes, err := badgerDatabase.GetReview(reviewHash)
|
|
if (err != nil) { return nil, nil, err }
|
|
if (exists == false){
|
|
// Review has been deleted. Missing review entry will be pruned automatically
|
|
continue
|
|
}
|
|
|
|
reviewObject := readReviews.ReviewWithHash{
|
|
ReviewHash: reviewHash,
|
|
ReviewBytes: reviewBytes,
|
|
}
|
|
|
|
reviewsList = append(reviewsList, reviewObject)
|
|
}
|
|
|
|
approveAdvocatesMap, banAdvocatesMap, err := readReviews.GetMessageVerdictMapsFromReviewsList(reviewsList, messageHash, messageNetworkType, messageCipherKeyHash)
|
|
if (err != nil) { return nil, nil, err }
|
|
|
|
return approveAdvocatesMap, banAdvocatesMap, nil
|
|
}
|
|
|
|
// We use this function to find a valid message cipher key to decrypt a message for moderation
|
|
// We use the message's CipherKeyHash to verify that the author of the review has seen the decrypted message
|
|
// If the cipher key does not decrypt the message, then we know the author of the review and the message are malicious
|
|
//Outputs:
|
|
// -bool: Message cipher key found
|
|
// -[32]byte: Message Cipher key
|
|
// -error
|
|
func GetMessageCipherKeyFromAnyReview(messageHash [26]byte, messageNetworkType byte, messageCipherKeyHash [25]byte)(bool, [32]byte, error){
|
|
|
|
isValid := helpers.VerifyNetworkType(messageNetworkType)
|
|
if (isValid == false){
|
|
messageNetworkTypeString := helpers.ConvertByteToString(messageNetworkType)
|
|
return false, [32]byte{}, errors.New("GetMessageCipherKeyFromAnyReview called with invalid messageNetworkType: " + messageNetworkTypeString)
|
|
}
|
|
|
|
exists, reviewHashesList, err := badgerDatabase.GetMessageReviewsList(messageHash)
|
|
if (err != nil) { return false, [32]byte{}, err }
|
|
if (exists == false){
|
|
return false, [32]byte{}, nil
|
|
}
|
|
if (len(reviewHashesList) == 0){
|
|
return false, [32]byte{}, nil
|
|
}
|
|
|
|
for _, reviewHash := range reviewHashesList{
|
|
|
|
exists, reviewBytes, err := badgerDatabase.GetReview(reviewHash)
|
|
if (err != nil) { return false, [32]byte{}, err }
|
|
if (exists == false){
|
|
// Message must have been deleted.
|
|
// The missing reviewsList entry will be removed automatically.
|
|
continue
|
|
}
|
|
|
|
ableToRead, _, reviewNetworkType, _, _, reviewType, reviewedHash, _, reviewMap, err := readReviews.ReadReview(false, reviewBytes)
|
|
if (err != nil) { return false, [32]byte{}, err }
|
|
if (ableToRead == false){
|
|
return false, [32]byte{}, errors.New("Database corrupt: Contains invalid review.")
|
|
}
|
|
if (reviewNetworkType != messageNetworkType){
|
|
// The author of this review is malicious
|
|
// We will not try to get the message cipher key from the review, even if it exists
|
|
// This is because we want all moderators to see the same messages to review, regardless of if they were previously on a different network.
|
|
continue
|
|
}
|
|
if (reviewType != "Message") {
|
|
return false, [32]byte{}, errors.New("Corrupt database: ReviewType does not match reviews list.")
|
|
}
|
|
|
|
areEqual := bytes.Equal(reviewedHash, messageHash[:])
|
|
if (areEqual == false){
|
|
return false, [32]byte{}, errors.New("Corrupt database: Reviewed message hash does not match reviews list.")
|
|
}
|
|
|
|
messageCipherKeyString, exists := reviewMap["MessageCipherKey"]
|
|
if (exists == false) {
|
|
return false, [32]byte{}, errors.New("Corrupt database: Contains review missing MessageCipherKey")
|
|
}
|
|
|
|
messageCipherKey, err := readMessages.ReadMessageCipherKeyHex(messageCipherKeyString)
|
|
if (err != nil){
|
|
return false, [32]byte{}, errors.New("Corrupt database: Contains review with invalid MessageCipherKey: " + messageCipherKeyString + ". Reason: " + err.Error())
|
|
}
|
|
|
|
currentMessageCipherKeyHash, err := readMessages.ConvertMessageCipherKeyToCipherKeyHash(messageCipherKey)
|
|
if (err != nil){ return false, [32]byte{}, err }
|
|
|
|
if (currentMessageCipherKeyHash != messageCipherKeyHash){
|
|
// Reviewer is malicious.
|
|
continue
|
|
}
|
|
|
|
return true, messageCipherKey, nil
|
|
}
|
|
|
|
// No valid reviews found for message
|
|
|
|
return false, [32]byte{}, nil
|
|
}
|
|
|
|
|