seekia/internal/contentMetadata/contentMetadata.go

225 lines
10 KiB
Go

// contentMetadata provides functions to store and retrieve metadata about profiles and messages
// Content metadata is stored in the database, so the content can be deleted and the metadata can still be retained
package contentMetadata
// Storing content metadata in the database enables:
// 1. We do not have to calculate the ProfileIsCanonical status and the attribute hashes for the same profile more than once
// 2. Hosts/Moderators can delete banned messages and still keep the cipher key hash to verify reviews for the messages
// 3. Hosts can delete banned profiles/messages and still be aware if those profile's/message's reviews are within their range
// Knowing if a profile's/message's reviews are within your range requires knowing the profile author/message inbox
// 4. Hosts can delete banned profiles and still be aware of why those profiles were banned (if their attributes were banned)
// We need to keep track of the profile's attribute hashes to be able to determine the profile's verdict consensus
// 5. It is faster to retrieve metadata than to read it from the profile/message
// This is because we do not need to read the entire message/profile into memory
// Profile metadata:
// -Profile version
// -Profile network type
// -Profile identity Hash
// -Profile creation time
// -Profile is disabled status
// -Profile is canonical status
// -Profile attribute hashes map
// Message metadata:
// -Message version
// -Message network type
// -Message size in bytes
// -Message Inbox
// -Message Cipher key hash
import "seekia/internal/encoding"
import "seekia/internal/badgerDatabase"
import "seekia/internal/profiles/readProfiles"
import "seekia/internal/messaging/readMessages"
import messagepack "github.com/vmihailenco/msgpack/v5"
import "errors"
//Outputs:
// -bool: Profile metadata exists
// -int: Profile Version
// -byte: Profile network type (1 == Mainnet, 2 == Testnet1)
// -[16]byte: Profile author identity Hash
// -int64: Profile creation time
// -bool: Profile is disabled
// -bool: Profile is canonical
// -map[int][27]byte: Map of Attribute identifier -> Attribute hash
// -error
func GetProfileMetadata(profileHash [28]byte)(bool, int, byte, [16]byte, int64, bool, bool, map[int][27]byte, error){
metadataExists, profileMetadata, err := badgerDatabase.GetProfileMetadata(profileHash)
if (err != nil) { return false, 0, 0, [16]byte{}, 0, false, false, nil, err }
if (metadataExists == true){
type profileMetadataStruct struct{
ProfileVersion int
NetworkType byte
IdentityHash [16]byte
CreationTime int64
IsDisabled bool
IsCanonical bool
AttributeHashesMap map[int][27]byte
}
var profileMetadataObject profileMetadataStruct
err := encoding.DecodeMessagePackBytes(false, profileMetadata, &profileMetadataObject)
if (err != nil) {
return false, 0, 0, [16]byte{}, 0, false, false, nil, errors.New("Database malformed: contains invalid profile metadata: " + err.Error())
}
profileVersion := profileMetadataObject.ProfileVersion
profileNetworkType := profileMetadataObject.NetworkType
profileIdentityHash := profileMetadataObject.IdentityHash
profileCreationTime := profileMetadataObject.CreationTime
profileIsDisabled := profileMetadataObject.IsDisabled
profileIsCanonical := profileMetadataObject.IsCanonical
attributeHashesMap := profileMetadataObject.AttributeHashesMap
if (profileIsDisabled == true){
emptyMap := make(map[int][27]byte)
return true, profileVersion, profileNetworkType, profileIdentityHash, profileCreationTime, true, true, emptyMap, nil
}
return true, profileVersion, profileNetworkType, profileIdentityHash, profileCreationTime, false, profileIsCanonical, attributeHashesMap, nil
}
profileType, _, err := readProfiles.ReadProfileHashMetadata(profileHash)
if (err != nil) { return false, 0, 0, [16]byte{}, 0, false, false, nil, err }
profileExists, profileBytes, err := badgerDatabase.GetUserProfile(profileType, profileHash)
if (err != nil) { return false, 0, 0, [16]byte{}, 0, false, false, nil, err }
if (profileExists == false){
return false, 0, 0, [16]byte{}, 0, false, false, nil, nil
}
ableToRead, profileHash_Retrieved, profileVersion, profileNetworkType, profileIdentityHash, profileCreationTime, profileIsDisabled, rawProfileMap, err := readProfiles.ReadProfileAndHash(false, profileBytes)
if (err != nil) { return false, 0, 0, [16]byte{}, 0, false, false, nil, err }
if (ableToRead == false){
return false, 0, 0, [16]byte{}, 0, false, false, nil, errors.New("Database corrupt: Contains invalid profile: " + err.Error())
}
if (profileHash != profileHash_Retrieved){
return false, 0, 0, [16]byte{}, 0, false, false, nil, errors.New("Database corrupt: Profile hash does not match profile entry key")
}
profileAttributeHashesMap, profileIsCanonical, err := readProfiles.GetProfileAttributeHashesMap(profileIdentityHash, profileVersion, profileNetworkType, rawProfileMap)
if (err != nil) { return false, 0, 0, [16]byte{}, 0, false, false, nil, err }
profileVersionEncoded, err := encoding.EncodeMessagePackBytes(profileVersion)
if (err != nil){ return false, 0, 0, [16]byte{}, 0, false, false, nil, err }
profileNetworkTypeEncoded, err := encoding.EncodeMessagePackBytes(profileNetworkType)
if (err != nil){ return false, 0, 0, [16]byte{}, 0, false, false, nil, err }
identityHashEncoded, err := encoding.EncodeMessagePackBytes(profileIdentityHash)
if (err != nil){ return false, 0, 0, [16]byte{}, 0, false, false, nil, err }
creationTimeEncoded, err := encoding.EncodeMessagePackBytes(profileCreationTime)
if (err != nil){ return false, 0, 0, [16]byte{}, 0, false, false, nil, err }
isDisabledEncoded, err := encoding.EncodeMessagePackBytes(profileIsDisabled)
if (err != nil){ return false, 0, 0, [16]byte{}, 0, false, false, nil, err }
isCanonicalEncoded, err := encoding.EncodeMessagePackBytes(profileIsCanonical)
if (err != nil){ return false, 0, 0, [16]byte{}, 0, false, false, nil, err }
attributeHashesMapEncoded, err := encoding.EncodeMessagePackBytes(profileAttributeHashesMap)
if (err != nil){ return false, 0, 0, [16]byte{}, 0, false, false, nil, err }
profileMetadataSlice := []messagepack.RawMessage{profileVersionEncoded, profileNetworkTypeEncoded, identityHashEncoded, creationTimeEncoded, isDisabledEncoded, isCanonicalEncoded, attributeHashesMapEncoded}
profileMetadataBytes, err := encoding.EncodeMessagePackBytes(profileMetadataSlice)
if (err != nil) { return false, 0, 0, [16]byte{}, 0, false, false, nil, err }
err = badgerDatabase.AddProfileMetadata(profileHash, profileMetadataBytes)
if (err != nil) { return false, 0, 0, [16]byte{}, 0, false, false, nil, err }
return true, profileVersion, profileNetworkType, profileIdentityHash, profileCreationTime, profileIsDisabled, profileIsCanonical, profileAttributeHashesMap, nil
}
//Outputs:
// -bool: Message metadata exists
// -int: Message version
// -byte: Message network type (1 == Mainnet, 2 == Testnet1)
// -int: Message size in bytes
// -[10]byte: Message inbox
// -[25]byte: Message cipher key hash
// -error
func GetMessageMetadata(messageHash [26]byte)(bool, int, byte, int, [10]byte, [25]byte, error){
exists, messageMetadata, err := badgerDatabase.GetMessageMetadata(messageHash)
if (err != nil) { return false, 0, 0, 0, [10]byte{}, [25]byte{}, err }
if (exists == true){
type messageMetadataStruct struct{
MessageVersion int
MessageNetworkType byte
MessageSize int
MessageInbox [10]byte
MessageCipherKeyHash [25]byte
}
var messageMetadataObject messageMetadataStruct
err := encoding.DecodeMessagePackBytes(false, messageMetadata, &messageMetadataObject)
if (err != nil) {
return false, 0, 0, 0, [10]byte{}, [25]byte{}, errors.New("Database malformed: contains invalid message metadata: " + err.Error())
}
messageVersion := messageMetadataObject.MessageVersion
messageNetworkType := messageMetadataObject.MessageNetworkType
messageSize := messageMetadataObject.MessageSize
messageInbox := messageMetadataObject.MessageInbox
messageCipherKeyHash := messageMetadataObject.MessageCipherKeyHash
return true, messageVersion, messageNetworkType, messageSize, messageInbox, messageCipherKeyHash, nil
}
messageExists, messageBytes, err := badgerDatabase.GetChatMessage(messageHash)
if (err != nil) { return false, 0, 0, 0, [10]byte{}, [25]byte{}, err }
if (messageExists == false){
return false, 0, 0, 0, [10]byte{}, [25]byte{}, nil
}
ableToRead, messageHash_Retrieved, messageVersion, messageNetworkType, messageInbox, _, _, _, messageCipherKeyHash, _, _, err := readMessages.ReadChatMessagePublicDataAndHash(false, messageBytes)
if (err != nil) { return false, 0, 0, 0, [10]byte{}, [25]byte{}, err }
if (ableToRead == false){
return false, 0, 0, 0, [10]byte{}, [25]byte{}, errors.New("Database corrupt: Contains invalid message.")
}
if (messageHash != messageHash_Retrieved){
return false, 0, 0, 0, [10]byte{}, [25]byte{}, errors.New("Database corrupt: Chat message entry key does not match message hash.")
}
messageSize := len(messageBytes)
messageVersionEncoded, err := encoding.EncodeMessagePackBytes(messageVersion)
if (err != nil) { return false, 0, 0, 0, [10]byte{}, [25]byte{}, err }
messageNetworkTypeEncoded, err := encoding.EncodeMessagePackBytes(messageNetworkType)
if (err != nil) { return false, 0, 0, 0, [10]byte{}, [25]byte{}, err }
messageSizeEncoded, err := encoding.EncodeMessagePackBytes(messageSize)
if (err != nil) { return false, 0, 0, 0, [10]byte{}, [25]byte{}, err }
messageInboxEncoded, err := encoding.EncodeMessagePackBytes(messageInbox)
if (err != nil) { return false, 0, 0, 0, [10]byte{}, [25]byte{}, err }
messageCipherKeyHashEncoded, err := encoding.EncodeMessagePackBytes(messageCipherKeyHash)
if (err != nil) { return false, 0, 0, 0, [10]byte{}, [25]byte{}, err }
messageSlice := []messagepack.RawMessage{messageVersionEncoded, messageNetworkTypeEncoded, messageSizeEncoded, messageInboxEncoded, messageCipherKeyHashEncoded}
newMessageMetadata, err := encoding.EncodeMessagePackBytes(messageSlice)
if (err != nil) { return false, 0, 0, 0, [10]byte{}, [25]byte{}, err }
err = badgerDatabase.AddMessageMetadata(messageHash, newMessageMetadata)
if (err != nil) { return false, 0, 0, 0, [10]byte{}, [25]byte{}, err }
return true, messageVersion, messageNetworkType, messageSize, messageInbox, messageCipherKeyHash, nil
}