302 lines
8.2 KiB
Go
302 lines
8.2 KiB
Go
|
|
// 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
|
|
}
|
|
|
|
|
|
|