// readReports provides functions to read reports. package readReports import "seekia/internal/allowedText" import "seekia/internal/cryptography/blake3" import "seekia/internal/encoding" import "seekia/internal/helpers" import messagepack "github.com/vmihailenco/msgpack/v5" import "errors" func VerifyReport(inputReport []byte)(bool, error){ ableToRead, _, _, _, _, _, _, err := ReadReport(true, inputReport) if (err != nil){ return false, err } if (ableToRead == false){ return false, nil } return true, nil } // This is used to verify report hashes func VerifyReportHash(inputHash [30]byte, reportTypeProvided bool, expectedReportType string)(bool, error){ if (reportTypeProvided == true){ if (expectedReportType != "Identity" && expectedReportType != "Profile" && expectedReportType != "Attribute" && expectedReportType != "Message"){ return false, errors.New("VerifyReportHash called with invalid expectedReportType: " + expectedReportType) } } reportType, err := GetReportTypeFromReportHash(inputHash) if (err != nil){ return false, nil } if (reportTypeProvided == true){ if (reportType != expectedReportType){ return false, nil } } return true, nil } func GetReportTypeFromReportHash(inputHash [30]byte)(string, error){ metadataByte := inputHash[29] if (metadataByte == 1){ return "Identity", nil } if (metadataByte == 2){ return "Profile", nil } if (metadataByte == 3){ return "Attribute", nil } if (metadataByte == 4){ return "Message", nil } reportHashHex := encoding.EncodeBytesToHexString(inputHash[:]) return "", errors.New("GetReportTypeFromReportHash called with invalid reportHash: " + reportHashHex) } // This function computes the report hash and returns it //Outputs: // -bool: Able to read // -[30]byte: Report Hash // -int: Report Version // -byte: Network Type (1 == Mainnet, 2 == Testnet1) // -int64: Broadcast Time (alleged, could be fake, like all broadcast times) // -string: Report Type // -[]byte: Reported Hash // -map[string]string: Report map // -error func ReadReportAndHash(verifyReport bool, inputReport []byte)(bool, [30]byte, int, byte, int64, string, []byte, map[string]string, error){ ableToRead, reportVersion, reportNetworkType, reportBroadcastTime, reportType, reportedHash, reportMap, err := ReadReport(verifyReport, inputReport) if (err != nil){ return false, [30]byte{}, 0, 0, 0, "", nil, nil, err } if (ableToRead == false){ return false, [30]byte{}, 0, 0, 0, "", nil, nil, nil } reportHashWithoutMetadataByte, err := blake3.GetBlake3HashAsBytes(29, inputReport) if (err != nil){ return false, [30]byte{}, 0, 0, 0, "", nil, nil, err } getReportHashMetadataByte := func()(byte, error){ if (reportType == "Identity"){ return 1, nil } if (reportType == "Profile"){ return 2, nil } if (reportType == "Attribute"){ return 3, nil } if (reportType == "Message"){ return 4, nil } return 0, errors.New("ReadReport returning invalid reportType: " + reportType) } reportHashMetadataByte, err := getReportHashMetadataByte() if (err != nil){ return false, [30]byte{}, 0, 0, 0, "", nil, nil, err } reportHashSlice := append(reportHashWithoutMetadataByte, reportHashMetadataByte) reportHash := [30]byte(reportHashSlice) return true, reportHash, reportVersion, reportNetworkType, reportBroadcastTime, reportType, reportedHash, reportMap, nil } // This function does not compute the report hash, thus it is faster //Outputs: // -bool: Able to read // -int: Report Version // -byte: Network Type (1 == Mainnet, 2 == Testnet1) // -int64: Broadcast Time (alleged, could be fake, like all broadcast times) // -string: Report Type // -[]byte: Reported Hash // -map[string]string: Report map // -error func ReadReport(verifyReport bool, inputReport []byte)(bool, int, byte, int64, string, []byte, map[string]string, error){ reportContentMap := make(map[int]messagepack.RawMessage) err := messagepack.Unmarshal(inputReport, &reportContentMap) if (err != nil) { // Invalid Report: Invalid Messagepack return false, 0, 0, 0, "", nil, nil, nil } reportVersionMessagepack, exists := reportContentMap[1] if (exists == false){ // Invalid Report: Missing ReportVersion return false, 0, 0, 0, "", nil, nil, nil } reportVersion, err := encoding.DecodeRawMessagePackToInt(reportVersionMessagepack) if (err != nil) { // Invalid Report: Invalid report version return false, 0, 0, 0, "", nil, nil, nil } if (reportVersion != 1){ // We cannot read this report. It was created by a newer version of Seekia. return false, 0, 0, 0, "", nil, nil, nil } networkTypeMessagepack, exists := reportContentMap[2] if (exists == false){ // Invalid Report: Missing NetworkType return false, 0, 0, 0, "", nil, nil, nil } reportNetworkType, err := encoding.DecodeRawMessagePackToByte(networkTypeMessagepack) if (err != nil) { // Invalid Report: Invalid NetworkType return false, 0, 0, 0, "", nil, nil, nil } isValid := helpers.VerifyNetworkType(reportNetworkType) if (isValid == false){ // Invalid Report: Invalid NetworkType return false, 0, 0, 0, "", nil, nil, nil } broadcastTimeMessagepack, exists := reportContentMap[3] if (exists == false){ // Invalid Report: Missing BroadcastTime return false, 0, 0, 0, "", nil, nil, nil } broadcastTime, err := encoding.DecodeRawMessagePackToInt64(broadcastTimeMessagepack) if (err != nil) { // Invalid Report: Invalid BroadcastTime return false, 0, 0, 0, "", nil, nil, nil } reportedHashMessagepack, exists := reportContentMap[4] if (exists == false){ // Invalid Report: Missing ReportedHash return false, 0, 0, 0, "", nil, nil, nil } reportedHash, err := encoding.DecodeRawMessagePackToBytes(reportedHashMessagepack) if (err != nil) { // Invalid Report: Invalid ReportedHash return false, 0, 0, 0, "", nil, nil, nil } reportType, err := helpers.GetReportedTypeFromReportedHash(reportedHash) if (err != nil){ // Invalid Report: Invalid ReportedHash return false, 0, 0, 0, "", nil, nil, nil } // These variables are only included in some reports var reason string var messageCipherKeyBytes []byte reasonMessagepack, exists := reportContentMap[5] if (exists == true){ err = messagepack.Unmarshal(reasonMessagepack, &reason) if (err != nil) { // Invalid Report: Invalid Reason return false, 0, 0, 0, "", nil, nil, nil } } if (reportType == "Message"){ messageCipherKeyMessagepack, exists := reportContentMap[6] if (exists == false){ // Invalid Report: Missing MessageCipherKey return false, 0, 0, 0, "", nil, nil, nil } err = messagepack.Unmarshal(messageCipherKeyMessagepack, &messageCipherKeyBytes) if (err != nil) { // Invalid Report: Invalid Reason return false, 0, 0, 0, "", nil, nil, nil } } if (verifyReport == true){ isValid := helpers.VerifyBroadcastTime(broadcastTime) if (isValid == false){ // Invalid report: Invalid broadcast time return false, 0, 0, 0, "", nil, nil, nil } if (reportType == "Message"){ if (len(messageCipherKeyBytes) != 32){ // Invalid Report: Report contains invalid messageCipherKey return false, 0, 0, 0, "", nil, nil, nil } } if (reason != "") { if (len(reason) > 200) { // Invalid report: Report contains invalid reason return false, 0, 0, 0, "", nil, nil, nil } isAllowed := allowedText.VerifyStringIsAllowed(reason) if (isAllowed == false){ // Invalid report: Report contains invalid reason return false, 0, 0, 0, "", nil, nil, nil } } } reportVersionString := helpers.ConvertIntToString(reportVersion) reportNetworkTypeString := helpers.ConvertByteToString(reportNetworkType) broadcastTimeString := helpers.ConvertInt64ToString(broadcastTime) reportedHashString, err := helpers.EncodeReportedHashBytesToString(reportedHash) if (err != nil) { return false, 0, 0, 0, "", nil, nil, err } reportMap := map[string]string{ "ReportVersion": reportVersionString, "NetworkType": reportNetworkTypeString, "BroadcastTime": broadcastTimeString, "ReportedHash": reportedHashString, } if (reportType == "Message"){ messageCipherKey := encoding.EncodeBytesToHexString(messageCipherKeyBytes) reportMap["MessageCipherKey"] = messageCipherKey } if (reason != ""){ reportMap["Reason"] = reason } return true, 1, reportNetworkType, broadcastTime, reportType, reportedHash, reportMap, nil }