304 lines
9.5 KiB
Go
304 lines
9.5 KiB
Go
|
|
||
|
// 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
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|