// 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 }