seekia/internal/moderation/reportStorage/reportStorage.go

304 lines
9.5 KiB
Go
Raw Normal View History

// reportStorage provides functions to manage stored reports.
// Reports are created by users to report unruleful content.
package reportStorage
import "seekia/internal/badgerDatabase"
import "seekia/internal/encoding"
import "seekia/internal/helpers"
import "seekia/internal/messaging/readMessages"
import "seekia/internal/moderation/readReports"
import "seekia/internal/mySettings"
import "bytes"
import "errors"
func GetNumberOfStoredReports()(int64, error){
numberOfReports, err := badgerDatabase.GetNumberOfReports()
if (err != nil) { return 0, err }
return numberOfReports, nil
}
//Outputs:
// -bool: Report is well formed
// -error
func AddReport(newReport []byte)(bool, error){
ableToRead, reportHash, _, _, _, reportType, reportedHash, _, err := readReports.ReadReportAndHash(true, newReport)
if (err != nil){ return false, err }
if (ableToRead == false){
// Report is malformed.
// Host who sent report must be malicious.
return false, nil
}
exists, _, err := badgerDatabase.GetReport(reportHash)
if (err != nil) { return false, err }
if (exists == true){
// Report is already imported.
return true, nil
}
err = badgerDatabase.AddReport(reportHash, newReport)
if (err != nil) { return false, err }
err = mySettings.SetSetting("ViewedContentNeedsRefreshYesNo", "Yes")
if (err != nil) { return false, err }
if (reportType == "Identity"){
if (len(reportedHash) != 16){
return false, errors.New("ReadReport returning invalid length reportedHash for Identity report.")
}
reportedIdentityHash := [16]byte(reportedHash)
err := badgerDatabase.AddIdentityReportToList(reportedIdentityHash, reportHash)
if (err != nil) { return false, err }
return true, nil
}
if (reportType == "Profile"){
if (len(reportedHash) != 28){
return false, errors.New("ReadReport returning invalid length reportedHash for Profile report.")
}
reportedProfileHash := [28]byte(reportedHash)
err = badgerDatabase.AddProfileReportToList(reportedProfileHash, reportHash)
if (err != nil) { return false, err }
return true, nil
}
if (reportType == "Attribute"){
if (len(reportedHash) != 27){
return false, errors.New("ReadReport returning invalid length reportedHash for Attribute report.")
}
reportedAttributeHash := [27]byte(reportedHash)
err = badgerDatabase.AddProfileAttributeReportToList(reportedAttributeHash, reportHash)
if (err != nil) { return false, err }
return true, nil
}
if (reportType == "Message"){
if (len(reportedHash) != 26){
return false, errors.New("ReadReport returning invalid length reportedHash for Message report.")
}
reportedMessageHash := [26]byte(reportedHash)
err = badgerDatabase.AddMessageReportToList(reportedMessageHash, reportHash)
if (err != nil) { return false, err }
return true, nil
}
return false, errors.New("ReadReport returning invalid reportType: " + reportType)
}
func GetNumberOfReportsForReportedHash(reportedHash []byte, networkType byte)(int64, error){
reportedType, err := helpers.GetReportedTypeFromReportedHash(reportedHash)
if (err != nil){
reportedHashHex := encoding.EncodeBytesToHexString(reportedHash)
return 0, errors.New("GetNumberOfReportsForReportedHash called with invalid reportedHash: " + reportedHashHex)
}
isValid := helpers.VerifyNetworkType(networkType)
if (isValid == false){
networkTypeString := helpers.ConvertByteToString(networkType)
return 0, errors.New("GetNumberOfReportsForReportedHash called with invalid networkType: " + networkTypeString)
}
//Outputs:
// -bool: Any report hashes found
// -[][30]byte: Report hashes list for reportedHash
// -error
getReportHashesList := func()(bool, [][30]byte, error){
if (reportedType == "Identity"){
if (len(reportedHash) != 16){
return false, nil, errors.New("GetReportedTypeFromReportedHash returning Identity for invalid length identity hash.")
}
reportedIdentityHash := [16]byte(reportedHash)
exists, reportHashesList, err := badgerDatabase.GetIdentityReportsList(reportedIdentityHash)
return exists, reportHashesList, err
}
if (reportedType == "Profile"){
if (len(reportedHash) != 28){
return false, nil, errors.New("GetReportedTypeFromReportedHash returning Profile for invalid length profile hash.")
}
reportedProfileHash := [28]byte(reportedHash)
exists, reportHashesList, err := badgerDatabase.GetProfileReportsList(reportedProfileHash)
return exists, reportHashesList, err
}
if (reportedType == "Attribute"){
if (len(reportedHash) != 27){
return false, nil, errors.New("GetReportedTypeFromReportedHash returning Attribute for invalid length attribute hash.")
}
reportedAttributeHash := [27]byte(reportedHash)
exists, reportedHashesList, err := badgerDatabase.GetProfileAttributeReportsList(reportedAttributeHash)
return exists, reportedHashesList, err
}
if (reportedType == "Message"){
if (len(reportedHash) != 26){
return false, nil, errors.New("GetReportedTypeFromReportedHash returning Message for invalid length message hash.")
}
reportedMessageHash := [26]byte(reportedHash)
exists, reportHashesList, err := badgerDatabase.GetMessageReportsList(reportedMessageHash)
return exists, reportHashesList, err
}
return false, nil, errors.New("GetReportedTypeFromReportedHash returning invalid reportedType: " + reportedType)
}
exists, reportHashesList, err := getReportHashesList()
if (err != nil) { return 0, err }
if (exists == false){
return 0, nil
}
numberOfReports := int64(0)
for _, reportHash := range reportHashesList{
exists, reportBytes, err := badgerDatabase.GetReport(reportHash)
if (err != nil) { return 0, err }
if (exists == false){
// Report has been deleted, reports list will be updated in the background
continue
}
ableToRead, _, reportNetworkType, _, reportType, reportReportedHash, _, err := readReports.ReadReport(false, reportBytes)
if (err != nil) { return 0, err }
if (ableToRead == false){
return 0, errors.New("Database corrupt: Contains invalid report.")
}
if (reportNetworkType != networkType){
continue
}
if (reportType != reportedType){
return 0, errors.New("getReportHashesList returning report of different reportedType.")
}
areEqual := bytes.Equal(reportedHash, reportReportedHash)
if (areEqual == false){
return 0, errors.New("getReportHashesList returning report for different reportedHash.")
}
numberOfReports += 1
}
return numberOfReports, nil
}
// We use this function to find a valid message cipher key to decrypt a message for moderation
// We verify the message CipherKeyHash to make sure the author of the report has seen the message
// If the cipher key does not decrypt the message, then we know the author of the report and the message are malicious
//Outputs:
// -bool: Message cipher key found
// -[32]byte: Message Cipher key
// -error
func GetMessageCipherKeyFromAnyReport(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("GetMessageCipherKeyFromAnyReport called with invalid messageNetworkType: " + messageNetworkTypeString)
}
exists, reportHashesList, err := badgerDatabase.GetMessageReportsList(messageHash)
if (err != nil) { return false, [32]byte{}, err }
if (exists == false){
return false, [32]byte{}, nil
}
if (len(reportHashesList) == 0){
return false, [32]byte{}, nil
}
for _, reportHash := range reportHashesList{
exists, reportBytes, err := badgerDatabase.GetReport(reportHash)
if (err != nil) { return false, [32]byte{}, err }
if (exists == false){
// Report must have been deleted. Database will be updated automatically.
continue
}
ableToRead, _, reportNetworkType, _, reportType, reportedHash, reportMap, err := readReports.ReadReport(false, reportBytes)
if (err != nil) { return false, [32]byte{}, err }
if (ableToRead == false){
return false, [32]byte{}, errors.New("Database corrupt: Contains invalid report.")
}
if (reportNetworkType != messageNetworkType){
// Person who created this report must be malicious
// We skip the report, even if we could use it to retrieve the message cipher key hash
// This is because we want all moderators to see the same reports, regardless of if they previously accessed a different network
continue
}
if (reportType != "Message") {
return false, [32]byte{}, errors.New("Corrupt database: ReportType does not match reports list.")
}
areEqual := bytes.Equal(reportedHash, messageHash[:])
if (areEqual == false){
return false, [32]byte{}, errors.New("Corrupt database: Reported message does not match reports list.")
}
messageCipherKeyString, exists := reportMap["MessageCipherKey"]
if (exists == false) {
return false, [32]byte{}, errors.New("Corrupt database: Contains report missing MessageCipherKey")
}
messageCipherKey, err := readMessages.ReadMessageCipherKeyHex(messageCipherKeyString)
if (err != nil){
return false, [32]byte{}, errors.New("Corrupt database: Contains report with invalid MessageCipherKey: " + messageCipherKeyString + ". Reason: " + err.Error())
}
currentMessageCipherKeyHash, err := readMessages.ConvertMessageCipherKeyToCipherKeyHash(messageCipherKey)
if (err != nil){ return false, [32]byte{}, err }
if (currentMessageCipherKeyHash != messageCipherKeyHash){
// Report author is malicious.
continue
}
return true, messageCipherKey, nil
}
// No valid reports found for message
return false, [32]byte{}, nil
}