seekia/internal/network/serverResponse/serverResponse.go

1719 lines
56 KiB
Go

// serverResponse provides functions to create and read server responses
package serverResponse
// See a description of each response and its purpose in Specification.md
//TODO: Verify all received values and function inputs
import "seekia/internal/cryptography/blake3"
import "seekia/internal/cryptography/chaPolyShrink"
import "seekia/internal/cryptography/edwardsKeys"
import "seekia/internal/cryptography/kyber"
import "seekia/internal/cryptography/nacl"
import "seekia/internal/encoding"
import "seekia/internal/helpers"
import "seekia/internal/identity"
import "seekia/internal/messaging/readMessages"
import "seekia/internal/moderation/readReports"
import "seekia/internal/moderation/readReviews"
import "seekia/internal/parameters/readParameters"
import "seekia/internal/profiles/readProfiles"
import messagepack "github.com/vmihailenco/msgpack/v5"
import "slices"
import "crypto/rand"
import "errors"
// The variables below specify the maximum number of items that can fit into a response
// They are used when making requests to know when to break up the request so it does not exceed the maximum size
//TODO: Make these numbers accurate
const MaximumProfilesInResponse_GetProfilesInfo int = 100000
const MaximumMessageHashesInResponse_GetMessageHashesList int = 100000
const MaximumMessagesInResponse_GetMessages int = 100000
const MaximumReviewHashesInResponse_GetReviewHashesList int = 100000
const MaximumReviewsInResponse_GetIdentityReviewsInfo int = 100000
const MaximumReviewsInResponse_GetMessageReviewsInfo int = 100000
const MaximumReviewsInResponse_GetReviews int = 100000
const MaximumReportsInResponse_GetIdentityReportsInfo int = 100000
const MaximumReportsInResponse_GetMessageReportsInfo int = 100000
const MaximumReportsInResponse_GetReports int = 100000
const MaximumBalancesInResponse_GetAddressDeposits int = 100000
const MaximumProfilesInResponse_GetProfileViewableStatuses int = 10000
const MaximumIdentitiesInResponse_GetIdentityViewableStatuses int = 1000
func GetMaximumProfilesInResponse_GetProfiles(profileType string)(int, error){
if (profileType == "Mate"){
return 1000, nil
}
if (profileType == "Host"){
return 10000, nil
}
if (profileType == "Moderator"){
return 10000, nil
}
return 0, errors.New("GetMaximumProfilesInResponse_GetProfiles called with invalid profile type: " + profileType)
}
//Outputs:
// -[]byte: Response bytes
// -[32]byte: Connection Key
// -error
func CreateServerResponse_EstablishConnectionKey(hostPublicIdentityKey [32]byte, hostPrivateIdentityKey [64]byte, requestIdentifier [16]byte, requestorNaclPublicKey [32]byte, requestorKyberPublicKey [1568]byte)([]byte, [32]byte, error){
var connectionKey [32]byte
_, err := rand.Read(connectionKey[:])
if (err != nil) { return nil, [32]byte{}, err }
type responseStruct struct{
HostIdentityKey [32]byte
RequestIdentifier [16]byte
ResponseType string
ConnectionKey [32]byte
}
responseObject := responseStruct{
HostIdentityKey: hostPublicIdentityKey,
RequestIdentifier: requestIdentifier,
ResponseType: "EstablishConnectionKey",
ConnectionKey: connectionKey,
}
responseContentBytes, err := encoding.EncodeMessagePackBytes(responseObject)
if (err != nil) { return nil, [32]byte{}, err }
responseSignedBytes, err := createResponseSignedContent(hostPrivateIdentityKey, responseContentBytes)
if (err != nil) { return nil, [32]byte{}, err }
chaPolyKey, err := helpers.GetNewRandom32ByteArray()
if (err != nil) { return nil, [32]byte{}, err }
chaPolyNonce, err := helpers.GetNewRandom24ByteArray()
if (err != nil) { return nil, [32]byte{}, err }
cipheredContent, err := chaPolyShrink.EncryptChaPolyShrink(responseSignedBytes, chaPolyKey, chaPolyNonce, true, 50, false, [32]byte{})
if (err != nil) { return nil, [32]byte{}, err }
keyPieceA, err := helpers.GetNewRandom32ByteArray()
if (err != nil) { return nil, [32]byte{}, err }
keyPieceB := helpers.XORTwo32ByteArrays(keyPieceA, chaPolyKey)
naclEncryptedKeyPieceA, err := nacl.EncryptKeyWithNacl(requestorNaclPublicKey, keyPieceA)
if (err != nil) { return nil, [32]byte{}, err }
kyberEncryptedKeyPieceB, err := kyber.EncryptKeyWithKyber(requestorKyberPublicKey, keyPieceB)
if (err != nil) { return nil, [32]byte{}, err }
keyPiecesList := slices.Concat(naclEncryptedKeyPieceA[:], kyberEncryptedKeyPieceB[:])
type encryptedResponseStruct struct{
KeyPieces []byte
ChaPolyNonce [24]byte
CipheredContent []byte
}
encryptedResponseObject := encryptedResponseStruct{
KeyPieces: keyPiecesList,
ChaPolyNonce: chaPolyNonce,
CipheredContent: cipheredContent,
}
encryptedResponseBytes, err := encoding.EncodeMessagePackBytes(encryptedResponseObject)
if (err != nil) { return nil, [32]byte{}, err }
return encryptedResponseBytes, connectionKey, nil
}
//Outputs:
// -bool: Able to read
// -[16]byte: Request identifier
// -[16]byte: Host Identity Hash
// -[32]byte: Connection key
// -error (if inputs to function are invalid)
func ReadServerResponse_EstablishConnectionKey(responseBytes []byte, requestorNaclPublicKey [32]byte, requestorNaclPrivateKey [32]byte, requestorKyberPrivateKey [1536]byte)(bool, [16]byte, [16]byte, [32]byte, error){
type encryptedResponseStruct struct{
KeyPieces [1648]byte
ChaPolyNonce [24]byte
CipheredContent []byte
}
var encryptedResponseObject encryptedResponseStruct
err := encoding.DecodeMessagePackBytes(false, responseBytes, &encryptedResponseObject)
if (err != nil) {
return false, [16]byte{}, [16]byte{}, [32]byte{}, nil
}
keyPiecesListArray := encryptedResponseObject.KeyPieces
chaPolyNonce := encryptedResponseObject.ChaPolyNonce
cipheredContent := encryptedResponseObject.CipheredContent
naclEncryptedKeyPieceA := [80]byte(keyPiecesListArray[:80])
kyberEncryptedKeyPieceB := [1568]byte(keyPiecesListArray[80:])
ableToDecrypt, keyPieceA, err := nacl.DecryptNaclEncryptedKey(naclEncryptedKeyPieceA, requestorNaclPublicKey, requestorNaclPrivateKey)
if (err != nil) { return false, [16]byte{}, [16]byte{}, [32]byte{}, err }
if (ableToDecrypt == false){
return false, [16]byte{}, [16]byte{}, [32]byte{}, nil
}
keyPieceB, err := kyber.DecryptKyberEncryptedKey(kyberEncryptedKeyPieceB, requestorKyberPrivateKey)
if (err != nil) {
return false, [16]byte{}, [16]byte{}, [32]byte{}, nil
}
contentChaPolyKey := helpers.XORTwo32ByteArrays(keyPieceA, keyPieceB)
ableToDecrypt, decryptedResponseBytes, err := chaPolyShrink.DecryptChaPolyShrink(cipheredContent, contentChaPolyKey, chaPolyNonce, false, [32]byte{})
if (err != nil) {
return false, [16]byte{}, [16]byte{}, [32]byte{}, nil
}
if (ableToDecrypt == false){
return false, [16]byte{}, [16]byte{}, [32]byte{}, nil
}
ableToRead, requestIdentifier, hostIdentityHash, contentBytes, err := readResponseSignedContent(decryptedResponseBytes, "EstablishConnectionKey")
if (err != nil) { return false, [16]byte{}, [16]byte{}, [32]byte{}, err }
if (ableToRead == false){
return false, [16]byte{}, [16]byte{}, [32]byte{}, nil
}
type responseContentStruct struct{
ConnectionKey [32]byte
}
var responseContentObject responseContentStruct
err = encoding.DecodeMessagePackBytes(true, contentBytes, &responseContentObject)
if (err != nil) {
return false, [16]byte{}, [16]byte{}, [32]byte{}, nil
}
connectionKey := responseContentObject.ConnectionKey
return true, requestIdentifier, hostIdentityHash, connectionKey, nil
}
//Outputs:
// -[]byte: Response bytes
// -error
func CreateServerResponse_GetParametersInfo(hostPublicIdentityKey [32]byte, hostPrivateIdentityKey [64]byte, connectionKey [32]byte, requestIdentifier [16]byte, parametersInfoMap map[string]int64)([]byte, error){
if (len(parametersInfoMap) == 0){
return nil, errors.New("CreateServerResponse_GetParametersInfo called with empty ParametersInfoMap")
}
type responseContentStruct struct{
HostIdentityKey [32]byte
RequestIdentifier [16]byte
ResponseType string
ParametersInfo map[string]int64 // Parameters Type -> Parameters broadcast time
}
responseContentObject := responseContentStruct{
HostIdentityKey: hostPublicIdentityKey,
RequestIdentifier: requestIdentifier,
ResponseType: "GetParametersInfo",
ParametersInfo: parametersInfoMap,
}
innerResponseBytes, err := encoding.EncodeMessagePackBytes(responseContentObject)
if (err != nil) { return nil, err }
encryptedResponse, err := createEncryptedAndSignedResponse(connectionKey, hostPrivateIdentityKey, innerResponseBytes)
if (err != nil) { return nil, err }
return encryptedResponse, nil
}
//Outputs:
// -bool: Able to read server response
// -[16]byte: Request Identifier
// -[16]byte: Host Identity Hash
// -map[string]int64: Parameters Info map (Parameters Type -> Parameters broadcast time)
// -error (returns err if input keys are invalid)
func ReadServerResponse_GetParametersInfo(responseBytes []byte, connectionKey [32]byte)(bool, [16]byte, [16]byte, map[string]int64, error){
ableToRead, requestIdentifier, hostIdentityHash, decryptedContentBytes, err := readEncryptedAndSignedResponse(responseBytes, connectionKey, "GetParametersInfo")
if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err }
if (ableToRead == false){
//Response is malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
type responseContentStruct struct{
ParametersInfo map[string]int64
}
var responseContentObject responseContentStruct
err = encoding.DecodeMessagePackBytes(true, decryptedContentBytes, &responseContentObject)
if (err != nil) {
// Response malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
parametersInfoMap := responseContentObject.ParametersInfo
//TODO: Verify parameters
return true, requestIdentifier, hostIdentityHash, parametersInfoMap, nil
}
//Outputs:
// -[]byte: Response bytes
// -error
func CreateServerResponse_GetParameters(hostPublicIdentityKey [32]byte, hostPrivateIdentityKey [64]byte, connectionKey [32]byte, requestIdentifier [16]byte, parametersList [][]byte)([]byte, error){
//TODO: Verify inputs
messagepackParametersList := make([]messagepack.RawMessage, 0, len(parametersList))
for _, parametersBytes := range parametersList{
messagepackParametersList = append(messagepackParametersList, parametersBytes)
}
type responseContentStruct struct{
HostIdentityKey [32]byte
RequestIdentifier [16]byte
ResponseType string
ParametersList []messagepack.RawMessage
}
responseContentObject := responseContentStruct{
HostIdentityKey: hostPublicIdentityKey,
RequestIdentifier: requestIdentifier,
ResponseType: "GetParameters",
ParametersList: messagepackParametersList,
}
innerResponseBytes, err := encoding.EncodeMessagePackBytes(responseContentObject)
if (err != nil) { return nil, err }
encryptedResponse, err := createEncryptedAndSignedResponse(connectionKey, hostPrivateIdentityKey, innerResponseBytes)
if (err != nil) { return nil, err }
return encryptedResponse, nil
}
//Outputs:
// -bool: Able to read server response
// -[16]byte: Request Identifier
// -[16]byte: Host Identity Hash
// -[][]byte: Parameters list
// -error (returns err if input keys are invalid)
func ReadServerResponse_GetParameters(responseBytes []byte, connectionKey [32]byte)(bool, [16]byte, [16]byte, [][]byte, error){
//TODO: Verify inputs
ableToRead, requestIdentifier, hostIdentityHash, decryptedContentBytes, err := readEncryptedAndSignedResponse(responseBytes, connectionKey, "GetParameters")
if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err }
if (ableToRead == false){
//Response is malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
type responseContentStruct struct{
ParametersList []messagepack.RawMessage
}
var responseContentObject responseContentStruct
err = encoding.DecodeMessagePackBytes(true, decryptedContentBytes, &responseContentObject)
if (err != nil) {
// Response is malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
parametersListRawMessagepack := responseContentObject.ParametersList
// We use the map below to ensure we only received each parameter type once
receivedParametersTypesMap := make(map[string]struct{})
// We use this to ensure that all parameters network types are the same
parametersNetworkType := byte(0)
parametersList := make([][]byte, 0, len(parametersListRawMessagepack))
for index, parametersBytes := range parametersListRawMessagepack{
ableToRead, _, currentNetworkType, _, parametersType, _, _, err := readParameters.ReadParameters(true, parametersBytes)
if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err }
if (ableToRead == false){
// Response is malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
if (index == 0){
parametersNetworkType = currentNetworkType
} else if (parametersNetworkType != currentNetworkType){
// We received two parameters with different network types.
// Response is malformed.
return false, [16]byte{}, [16]byte{}, nil, nil
}
_, exists := receivedParametersTypesMap[parametersType]
if (exists == true){
// We received a duplicate parameters type. Response is malformed.
return false, [16]byte{}, [16]byte{}, nil, nil
}
receivedParametersTypesMap[parametersType] = struct{}{}
parametersList = append(parametersList, parametersBytes)
}
return true, requestIdentifier, hostIdentityHash, parametersList, nil
}
// This is used for the GetProfilesInfo request
type ProfileInfoStruct struct{
ProfileHash [28]byte
ProfileAuthor [16]byte
ProfileBroadcastTime int64
}
//Outputs:
// -[]byte: Response bytes
// -error
func CreateServerResponse_GetProfilesInfo(hostPublicIdentityKey [32]byte, hostPrivateIdentityKey [64]byte, connectionKey [32]byte, requestIdentifier [16]byte, profileInfoObjectsList []ProfileInfoStruct)([]byte, error){
//TODO: Verify inputs
for _, profileInfoObject := range profileInfoObjectsList{
profileHash := profileInfoObject.ProfileHash
profileAuthor := profileInfoObject.ProfileAuthor
profileBroadcastTime := profileInfoObject.ProfileBroadcastTime
profileType, _, err := readProfiles.ReadProfileHashMetadata(profileHash)
if (err != nil){
profileHashHex := encoding.EncodeBytesToHexString(profileHash[:])
return nil, errors.New("Cannot create response: Invalid profileInfoObjectsList: Invalid ProfileHash: " + profileHashHex + ". Reason: " + err.Error())
}
authorIdentityType, err := identity.GetIdentityTypeFromIdentityHash(profileAuthor)
if (err != nil){
profileAuthorHex := encoding.EncodeBytesToHexString(profileAuthor[:])
return nil, errors.New("Cannot create response: invalid profileInfoObjectsList: Invalid profileAuthor: " + profileAuthorHex)
}
if (authorIdentityType != profileType){
return nil, errors.New("Cannot create response: Invalid profileInfoObjectsList: ProfileHash profile type does not match profileAuthor identity type.")
}
isValid := helpers.VerifyBroadcastTime(profileBroadcastTime)
if (isValid == false){
broadcastTimeString := helpers.ConvertInt64ToString(profileBroadcastTime)
return nil, errors.New("Cannot create response: Invalid profileInfoObjectsList: Invalid broadcastTime: " + broadcastTimeString)
}
}
type responseContentStruct struct{
HostIdentityKey [32]byte
RequestIdentifier [16]byte
ResponseType string
ProfilesInfo []ProfileInfoStruct
}
responseContentObject := responseContentStruct{
HostIdentityKey: hostPublicIdentityKey,
RequestIdentifier: requestIdentifier,
ResponseType: "GetProfilesInfo",
ProfilesInfo: profileInfoObjectsList,
}
innerResponseBytes, err := encoding.EncodeMessagePackBytes(responseContentObject)
if (err != nil) { return nil, err }
encryptedResponse, err := createEncryptedAndSignedResponse(connectionKey, hostPrivateIdentityKey, innerResponseBytes)
if (err != nil) { return nil, err }
return encryptedResponse, nil
}
//Outputs:
// -bool: Able to read server response
// -[16]byte: Request Identifier
// -[16]byte: Host Identity Hash
// -[]ProfileInfoStruct: Profiles Info map list
// -error (returns err if input keys are invalid)
func ReadServerResponse_GetProfilesInfo(responseBytes []byte, connectionKey [32]byte)(bool, [16]byte, [16]byte, []ProfileInfoStruct, error){
//TODO: Verify inputs
ableToRead, requestIdentifier, hostIdentityHash, decryptedContentBytes, err := readEncryptedAndSignedResponse(responseBytes, connectionKey, "GetProfilesInfo")
if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err }
if (ableToRead == false){
//Response is malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
type responseContentStruct struct{
ProfilesInfo []ProfileInfoStruct
}
var responseContentObject responseContentStruct
err = encoding.DecodeMessagePackBytes(true, decryptedContentBytes, &responseContentObject)
if (err != nil) {
// Response malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
//TODO: Validate info
profileInfoObjectsList := responseContentObject.ProfilesInfo
return true, requestIdentifier, hostIdentityHash, profileInfoObjectsList, nil
}
//Outputs:
// -[]byte: Response bytes
// -error
func CreateServerResponse_GetProfiles(hostPublicIdentityKey [32]byte, hostPrivateIdentityKey [64]byte, connectionKey [32]byte, requestIdentifier [16]byte, profilesList [][]byte)([]byte, error){
//TODO: Verify inputs
messagepackProfilesList := make([]messagepack.RawMessage, 0, len(profilesList))
for _, profileBytes := range profilesList{
messagepackProfilesList = append(messagepackProfilesList, profileBytes)
}
type responseContentStruct struct{
HostIdentityKey [32]byte
RequestIdentifier [16]byte
ResponseType string
ProfilesList []messagepack.RawMessage
}
responseContentObject := responseContentStruct{
HostIdentityKey: hostPublicIdentityKey,
RequestIdentifier: requestIdentifier,
ResponseType: "GetProfiles",
ProfilesList: messagepackProfilesList,
}
innerResponseBytes, err := encoding.EncodeMessagePackBytes(responseContentObject)
if (err != nil) { return nil, err }
encryptedResponse, err := createEncryptedAndSignedResponse(connectionKey, hostPrivateIdentityKey, innerResponseBytes)
if (err != nil) { return nil, err }
return encryptedResponse, nil
}
//Outputs:
// -bool: Able to read server response
// -[16]byte: Request Identifier
// -[16]byte: Host Identity Hash
// -[][]byte: Profiles list
// -error (returns err if input keys are invalid)
func ReadServerResponse_GetProfiles(responseBytes []byte, connectionKey [32]byte)(bool, [16]byte, [16]byte, [][]byte, error){
//TODO: Verify inputs
ableToRead, requestIdentifier, hostIdentityHash, decryptedContentBytes, err := readEncryptedAndSignedResponse(responseBytes, connectionKey, "GetProfiles")
if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err }
if (ableToRead == false){
//Response is malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
type responseContentStruct struct{
ProfilesList []messagepack.RawMessage
}
var responseContentObject responseContentStruct
err = encoding.DecodeMessagePackBytes(true, decryptedContentBytes, &responseContentObject)
if (err != nil) {
// Response is malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
messagepackProfilesList := responseContentObject.ProfilesList
// We use the map below to ensure we only received each profile once
receivedProfileHashesMap := make(map[[28]byte]struct{})
profilesList := make([][]byte, 0, len(messagepackProfilesList))
// We use this variable to make sure the network type of each profile is the same
profilesNetworkType := byte(0)
for index, profileBytes := range messagepackProfilesList{
ableToRead, profileHash, _, profileNetworkType, _, _, _, _, err := readProfiles.ReadProfileAndHash(true, profileBytes)
if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err }
if (ableToRead == false){
// Profile is malformed. Host is malicious.
return false, [16]byte{}, [16]byte{}, nil, nil
}
_, exists := receivedProfileHashesMap[profileHash]
if (exists == true){
// We received a duplicate profile. Host is malicious.
return false, [16]byte{}, [16]byte{}, nil, nil
}
receivedProfileHashesMap[profileHash] = struct{}{}
if (index == 0){
profilesNetworkType = profileNetworkType
} else if (profilesNetworkType != profileNetworkType){
// Profiles of differing network type cannot be sent in the same response
// Response is malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
profilesList = append(profilesList, profileBytes)
}
return true, requestIdentifier, hostIdentityHash, profilesList, nil
}
//Outputs:
// -[]byte: Response bytes
// -error
func CreateServerResponse_GetMessageHashesList(hostPublicIdentityKey [32]byte, hostPrivateIdentityKey [64]byte, connectionKey [32]byte, requestIdentifier [16]byte, messageHashesList [][26]byte)([]byte, error){
type responseContentStruct struct{
HostIdentityKey [32]byte
RequestIdentifier [16]byte
ResponseType string
MessageHashesList [][26]byte
}
responseContentObject := responseContentStruct{
HostIdentityKey: hostPublicIdentityKey,
RequestIdentifier: requestIdentifier,
ResponseType: "GetMessageHashesList",
MessageHashesList: messageHashesList,
}
innerResponseBytes, err := encoding.EncodeMessagePackBytes(responseContentObject)
if (err != nil) { return nil, err }
encryptedResponse, err := createEncryptedAndSignedResponse(connectionKey, hostPrivateIdentityKey, innerResponseBytes)
if (err != nil) { return nil, err }
return encryptedResponse, nil
}
//Outputs:
// -bool: Able to read server response
// -[16]byte: Request Identifier
// -[16]byte: Host Identity Hash
// -[][26]byte: Message Hashes List
// -error (returns err if input keys are invalid)
func ReadServerResponse_GetMessageHashesList(responseBytes []byte, connectionKey [32]byte)(bool, [16]byte, [16]byte, [][26]byte, error){
//TODO: Verify inputs
ableToRead, requestIdentifier, hostIdentityHash, decryptedContentBytes, err := readEncryptedAndSignedResponse(responseBytes, connectionKey, "GetMessageHashesList")
if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err }
if (ableToRead == false){
//Response is malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
type responseContentStruct struct{
MessageHashesList [][26]byte
}
var responseContentObject responseContentStruct
err = encoding.DecodeMessagePackBytes(true, decryptedContentBytes, &responseContentObject)
if (err != nil) {
// Response malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
messageHashesList := responseContentObject.MessageHashesList
return true, requestIdentifier, hostIdentityHash, messageHashesList, nil
}
//Outputs:
// -[]byte: Response bytes
// -error
func CreateServerResponse_GetMessages(hostPublicIdentityKey [32]byte, hostPrivateIdentityKey [64]byte, connectionKey [32]byte, requestIdentifier [16]byte, messagesList [][]byte)([]byte, error){
//TODO: Verify inputs
messagepackMessagesList := make([]messagepack.RawMessage, 0, len(messagesList))
for _, messageBytes := range messagesList{
messagepackMessagesList = append(messagepackMessagesList, messageBytes)
}
type responseContentStruct struct{
HostIdentityKey [32]byte
RequestIdentifier [16]byte
ResponseType string
MessagesList []messagepack.RawMessage
}
responseContentObject := responseContentStruct{
HostIdentityKey: hostPublicIdentityKey,
RequestIdentifier: requestIdentifier,
ResponseType: "GetMessages",
MessagesList: messagepackMessagesList,
}
innerResponseBytes, err := encoding.EncodeMessagePackBytes(responseContentObject)
if (err != nil) { return nil, err }
encryptedResponse, err := createEncryptedAndSignedResponse(connectionKey, hostPrivateIdentityKey, innerResponseBytes)
if (err != nil) { return nil, err }
return encryptedResponse, nil
}
//Outputs:
// -bool: Able to read server response
// -[16]byte: Request Identifier
// -[16]byte: Host Identity Hash
// -[][]byte: Messages list
// -error (returns err if input keys are invalid)
func ReadServerResponse_GetMessages(responseBytes []byte, connectionKey [32]byte)(bool, [16]byte, [16]byte, [][]byte, error){
//TODO: Verify inputs
ableToRead, requestIdentifier, hostIdentityHash, decryptedContentBytes, err := readEncryptedAndSignedResponse(responseBytes, connectionKey, "GetMessages")
if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err }
if (ableToRead == false){
//Response is malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
type responseContentStruct struct{
MessagesList []messagepack.RawMessage
}
var responseContentObject responseContentStruct
err = encoding.DecodeMessagePackBytes(true, decryptedContentBytes, &responseContentObject)
if (err != nil) {
// Response is malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
messagepackMessagesList := responseContentObject.MessagesList
// We use this map to detect duplicates
messageHashesMap := make(map[[26]byte]struct{})
messagesList := make([][]byte, 0, len(messagepackMessagesList))
// We use this variable to make sure the network type of all messages in the response is the same
messagesNetworkType := byte(0)
for index, messageBytes := range messagepackMessagesList{
ableToRead, messageHash, _, messageNetworkType, _, _, _, _, _, _, _, err := readMessages.ReadChatMessagePublicDataAndHash(true, messageBytes)
if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err }
if (ableToRead == false){
// Message is invalid, host must be malicious.
return false, [16]byte{}, [16]byte{}, nil, nil
}
_, exists := messageHashesMap[messageHash]
if (exists == true){
// Host sent duplicate message.
return false, [16]byte{}, [16]byte{}, nil, nil
}
messageHashesMap[messageHash] = struct{}{}
if (index == 0){
messagesNetworkType = messageNetworkType
} else if (messagesNetworkType != messageNetworkType){
// All messages in the response must contain the same networkType
return false, [16]byte{}, [16]byte{}, nil, nil
}
messagesList = append(messagesList, messageBytes)
}
return true, requestIdentifier, hostIdentityHash, messagesList, nil
}
//Outputs:
// -[]byte: Response bytes
// -error
func CreateServerResponse_GetIdentityReviewsInfo(hostPublicIdentityKey [32]byte, hostPrivateIdentityKey [64]byte, connectionKey [32]byte, requestIdentifier [16]byte, reviewsInfoMap map[[29]byte][]byte)([]byte, error){
//TODO: Verify inputs
type responseContentStruct struct{
HostIdentityKey [32]byte
RequestIdentifier [16]byte
ResponseType string
ReviewsInfo map[[29]byte][]byte // ReviewHash -> ReviewedHash
}
responseContentObject := responseContentStruct{
HostIdentityKey: hostPublicIdentityKey,
RequestIdentifier: requestIdentifier,
ResponseType: "GetIdentityReviewsInfo",
ReviewsInfo: reviewsInfoMap,
}
innerResponseBytes, err := encoding.EncodeMessagePackBytes(responseContentObject)
if (err != nil) { return nil, err }
encryptedResponse, err := createEncryptedAndSignedResponse(connectionKey, hostPrivateIdentityKey, innerResponseBytes)
if (err != nil) { return nil, err }
return encryptedResponse, nil
}
//Outputs:
// -bool: Able to read server response
// -[16]byte: Request Identifier
// -[16]byte: Host Identity Hash
// -map[[29]byte][]byte: Reviews Info map (Review Hash -> Reviewed Hash)
// -error (returns err if input keys are invalid)
func ReadServerResponse_GetIdentityReviewsInfo(responseBytes []byte, connectionKey [32]byte)(bool, [16]byte, [16]byte, map[[29]byte][]byte, error){
//TODO: Verify inputs
ableToRead, requestIdentifier, hostIdentityHash, decryptedContentBytes, err := readEncryptedAndSignedResponse(responseBytes, connectionKey, "GetIdentityReviewsInfo")
if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err }
if (ableToRead == false){
//Response is malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
type responseContentStruct struct{
ReviewsInfo map[[29]byte][]byte
}
var responseContentObject responseContentStruct
err = encoding.DecodeMessagePackBytes(true, decryptedContentBytes, &responseContentObject)
if (err != nil) {
// Response malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
reviewsInfoMap := responseContentObject.ReviewsInfo
for reviewHash, reviewedHash := range reviewsInfoMap{
reviewedType, err := helpers.GetReviewedTypeFromReviewedHash(reviewedHash)
if (err != nil) {
// Response is malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
if (reviewedType != "Identity" && reviewedType != "Profile" && reviewedType != "Attribute"){
// Response is malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
isValid, err := readReviews.VerifyReviewHash(reviewHash, true, reviewedType)
if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err }
if (isValid == false){
// Received reviewsInfoMap contains invalid reviewHash
// Response is malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
}
return true, requestIdentifier, hostIdentityHash, reviewsInfoMap, nil
}
//Outputs:
// -[]byte: Response bytes
// -error
func CreateServerResponse_GetMessageReviewsInfo(hostPublicIdentityKey [32]byte, hostPrivateIdentityKey [64]byte, connectionKey [32]byte, requestIdentifier [16]byte, reviewsInfoMap map[[29]byte][26]byte)([]byte, error){
//TODO: Verify inputs
type responseContentStruct struct{
HostIdentityKey [32]byte
RequestIdentifier [16]byte
ResponseType string
ReviewsInfo map[[29]byte][26]byte // Review Hash -> Reviewed Message Hash
}
responseContentObject := responseContentStruct{
HostIdentityKey: hostPublicIdentityKey,
RequestIdentifier: requestIdentifier,
ResponseType: "GetMessageReviewsInfo",
ReviewsInfo: reviewsInfoMap,
}
innerResponseBytes, err := encoding.EncodeMessagePackBytes(responseContentObject)
if (err != nil) { return nil, err }
encryptedResponse, err := createEncryptedAndSignedResponse(connectionKey, hostPrivateIdentityKey, innerResponseBytes)
if (err != nil) { return nil, err }
return encryptedResponse, nil
}
//Outputs:
// -bool: Able to read server response
// -[16]byte: Request Identifier
// -[16]byte: Host Identity Hash
// -map[[29]byte][26]byte: Reviews Info map (Review Hash -> Reviewed Message Hash)
// -error (returns err if input keys are invalid)
func ReadServerResponse_GetMessageReviewsInfo(responseBytes []byte, connectionKey [32]byte)(bool, [16]byte, [16]byte, map[[29]byte][26]byte, error){
//TODO: Verify inputs
ableToRead, requestIdentifier, hostIdentityHash, decryptedContentBytes, err := readEncryptedAndSignedResponse(responseBytes, connectionKey, "GetMessageReviewsInfo")
if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err }
if (ableToRead == false){
//Response is malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
type responseContentStruct struct{
ReviewsInfo map[[29]byte][26]byte
}
var responseContentObject responseContentStruct
err = encoding.DecodeMessagePackBytes(true, decryptedContentBytes, &responseContentObject)
if (err != nil) {
// Response malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
reviewsInfoMap := responseContentObject.ReviewsInfo
for reviewHash, _ := range reviewsInfoMap{
isValid, err := readReviews.VerifyReviewHash(reviewHash, true, "Message")
if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err }
if (isValid == false){
// Received reviewsInfoMap contains invalid reviewHash
// Response is malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
}
return true, requestIdentifier, hostIdentityHash, reviewsInfoMap, nil
}
//Outputs:
// -[]byte: Response bytes
// -error
func CreateServerResponse_GetReviews(hostPublicIdentityKey [32]byte, hostPrivateIdentityKey [64]byte, connectionKey [32]byte, requestIdentifier [16]byte, reviewsList [][]byte)([]byte, error){
//TODO: Verify inputs
messagepackReviewsList := make([]messagepack.RawMessage, 0, len(reviewsList))
for _, reviewBytes := range reviewsList{
messagepackReviewsList = append(messagepackReviewsList, reviewBytes)
}
type responseContentStruct struct{
HostIdentityKey [32]byte
RequestIdentifier [16]byte
ResponseType string
ReviewsList []messagepack.RawMessage
}
responseContentObject := responseContentStruct{
HostIdentityKey: hostPublicIdentityKey,
RequestIdentifier: requestIdentifier,
ResponseType: "GetReviews",
ReviewsList: messagepackReviewsList,
}
innerResponseBytes, err := encoding.EncodeMessagePackBytes(responseContentObject)
if (err != nil) { return nil, err }
encryptedResponse, err := createEncryptedAndSignedResponse(connectionKey, hostPrivateIdentityKey, innerResponseBytes)
if (err != nil) { return nil, err }
return encryptedResponse, nil
}
//Outputs:
// -bool: Able to read server response
// -[16]byte: Request Identifier
// -[16]byte: Host Identity Hash
// -[][]byte: Reviews list
// -error (returns err if input keys are invalid)
func ReadServerResponse_GetReviews(responseBytes []byte, connectionKey [32]byte)(bool, [16]byte, [16]byte, [][]byte, error){
//TODO: Verify inputs
ableToRead, requestIdentifier, hostIdentityHash, decryptedContentBytes, err := readEncryptedAndSignedResponse(responseBytes, connectionKey, "GetReviews")
if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err }
if (ableToRead == false){
//Response is malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
type responseContentStruct struct{
ReviewsList []messagepack.RawMessage
}
var responseContentObject responseContentStruct
err = encoding.DecodeMessagePackBytes(true, decryptedContentBytes, &responseContentObject)
if (err != nil) {
// Response is malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
messagepackReviewsList := responseContentObject.ReviewsList
// We use a map to detect duplicates
reviewHashesMap := make(map[[29]byte]struct{})
reviewsList := make([][]byte, 0, len(messagepackReviewsList))
// We use this variable to ensure that all reviews in the response belong to the same networkType
reviewsNetworkType := byte(0)
for index, reviewBytes := range messagepackReviewsList{
ableToRead, reviewHash, _, reviewNetworkType, _, _, _, _, _, _, err := readReviews.ReadReviewAndHash(true, reviewBytes)
if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err }
if (ableToRead == false){
// Review is invalid, host must be malicious.
return false, [16]byte{}, [16]byte{}, nil, nil
}
_, exists := reviewHashesMap[reviewHash]
if (exists == true){
// Duplicate review exists
// Response is malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
reviewHashesMap[reviewHash] = struct{}{}
if (index == 0){
reviewsNetworkType = reviewNetworkType
} else if (reviewsNetworkType != reviewNetworkType){
// Response contains two reviews with differing networkType
// Response is malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
reviewsList = append(reviewsList, reviewBytes)
}
return true, requestIdentifier, hostIdentityHash, reviewsList, nil
}
//Outputs:
// -[]byte: Response bytes
// -error
func CreateServerResponse_GetIdentityReportsInfo(hostPublicIdentityKey [32]byte, hostPrivateIdentityKey [64]byte, connectionKey [32]byte, requestIdentifier [16]byte, reportsInfoMap map[[30]byte][]byte)([]byte, error){
//TODO: Verify inputs
type responseContentStruct struct{
HostIdentityKey [32]byte
RequestIdentifier [16]byte
ResponseType string
ReportsInfo map[[30]byte][]byte // Report hash -> Reported hash
}
responseContentObject := responseContentStruct{
HostIdentityKey: hostPublicIdentityKey,
RequestIdentifier: requestIdentifier,
ResponseType: "GetIdentityReportsInfo",
ReportsInfo: reportsInfoMap,
}
innerResponseBytes, err := encoding.EncodeMessagePackBytes(responseContentObject)
if (err != nil) { return nil, err }
encryptedResponse, err := createEncryptedAndSignedResponse(connectionKey, hostPrivateIdentityKey, innerResponseBytes)
if (err != nil) { return nil, err }
return encryptedResponse, nil
}
//Outputs:
// -bool: Able to read server response
// -[16]byte: Request Identifier
// -[16]byte: Host Identity Hash
// -map[[30]byte][]byte: Reports Info map (Report Hash -> Reported hash)
// -error (returns err if input keys are invalid)
func ReadServerResponse_GetIdentityReportsInfo(responseBytes []byte, connectionKey [32]byte)(bool, [16]byte, [16]byte, map[[30]byte][]byte, error){
//TODO: Verify inputs
ableToRead, requestIdentifier, hostIdentityHash, decryptedContentBytes, err := readEncryptedAndSignedResponse(responseBytes, connectionKey, "GetIdentityReportsInfo")
if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err }
if (ableToRead == false){
//Response is malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
type responseContentStruct struct{
ReportsInfo map[[30]byte][]byte
}
var responseContentObject responseContentStruct
err = encoding.DecodeMessagePackBytes(true, decryptedContentBytes, &responseContentObject)
if (err != nil) {
// Response malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
reportsInfoMap := responseContentObject.ReportsInfo
for reportHash, reportedHash := range reportsInfoMap{
reportedType, err := helpers.GetReportedTypeFromReportedHash(reportedHash)
if (err != nil) {
// Response is malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
if (reportedType != "Identity" && reportedType != "Profile" && reportedType != "Attribute"){
// Response is malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
isValid, err := readReports.VerifyReportHash(reportHash, true, reportedType)
if (err != nil){ return false, [16]byte{}, [16]byte{}, nil, err }
if (isValid == false){
//Response contains invalid reportHash
// Response is malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
}
return true, requestIdentifier, hostIdentityHash, reportsInfoMap, nil
}
//Outputs:
// -[]byte: Response bytes
// -error
func CreateServerResponse_GetMessageReportsInfo(hostPublicIdentityKey [32]byte, hostPrivateIdentityKey [64]byte, connectionKey [32]byte, requestIdentifier [16]byte, reportsInfoMap map[[30]byte][26]byte)([]byte, error){
//TODO: Verify inputs
type responseContentStruct struct{
HostIdentityKey [32]byte
RequestIdentifier [16]byte
ResponseType string
ReportsInfo map[[30]byte][26]byte // Report Hash -> Reported message hash
}
responseContentObject := responseContentStruct{
HostIdentityKey: hostPublicIdentityKey,
RequestIdentifier: requestIdentifier,
ResponseType: "GetMessageReportsInfo",
ReportsInfo: reportsInfoMap,
}
innerResponseBytes, err := encoding.EncodeMessagePackBytes(responseContentObject)
if (err != nil) { return nil, err }
encryptedResponse, err := createEncryptedAndSignedResponse(connectionKey, hostPrivateIdentityKey, innerResponseBytes)
if (err != nil) { return nil, err }
return encryptedResponse, nil
}
//Outputs:
// -bool: Able to read server response
// -[16]byte: Request Identifier
// -[16]byte: Host Identity Hash
// -map[[30]byte][26]byte: Reports Info map (Report hash -> Reported message hash)
// -error (returns err if input keys are invalid)
func ReadServerResponse_GetMessageReportsInfo(responseBytes []byte, connectionKey [32]byte)(bool, [16]byte, [16]byte, map[[30]byte][26]byte, error){
//TODO: Verify inputs
ableToRead, requestIdentifier, hostIdentityHash, decryptedContentBytes, err := readEncryptedAndSignedResponse(responseBytes, connectionKey, "GetMessageReportsInfo")
if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err }
if (ableToRead == false){
//Response is malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
type responseContentStruct struct{
ReportsInfo map[[30]byte][26]byte
}
var responseContentObject responseContentStruct
err = encoding.DecodeMessagePackBytes(true, decryptedContentBytes, &responseContentObject)
if (err != nil) {
// Response malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
reportsInfoMap := responseContentObject.ReportsInfo
for reportHash, _ := range reportsInfoMap{
isValid, err := readReports.VerifyReportHash(reportHash, true, "Message")
if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err }
if (isValid == false){
// Response contains invalid reportHash
// Response is malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
}
return true, requestIdentifier, hostIdentityHash, reportsInfoMap, nil
}
//Outputs:
// -[]byte: Response bytes
// -error
func CreateServerResponse_GetReports(hostPublicIdentityKey [32]byte, hostPrivateIdentityKey [64]byte, connectionKey [32]byte, requestIdentifier [16]byte, reportsList [][]byte)([]byte, error){
//TODO: Verify inputs
messagepackReportsList := make([]messagepack.RawMessage, 0, len(reportsList))
for _, reportBytes := range reportsList{
messagepackReportsList = append(messagepackReportsList, reportBytes)
}
type responseContentStruct struct{
HostIdentityKey [32]byte
RequestIdentifier [16]byte
ResponseType string
ReportsList []messagepack.RawMessage
}
responseContentObject := responseContentStruct{
HostIdentityKey: hostPublicIdentityKey,
RequestIdentifier: requestIdentifier,
ResponseType: "GetReports",
ReportsList: messagepackReportsList,
}
innerResponseBytes, err := encoding.EncodeMessagePackBytes(responseContentObject)
if (err != nil) { return nil, err }
encryptedResponse, err := createEncryptedAndSignedResponse(connectionKey, hostPrivateIdentityKey, innerResponseBytes)
if (err != nil) { return nil, err }
return encryptedResponse, nil
}
//Outputs:
// -bool: Able to read server response
// -[16]byte: Request Identifier
// -[16]byte: Host Identity Hash
// -[][]byte: Reports list
// -error (returns err if input keys are invalid)
func ReadServerResponse_GetReports(responseBytes []byte, connectionKey [32]byte)(bool, [16]byte, [16]byte, [][]byte, error){
//TODO: Verify inputs
ableToRead, requestIdentifier, hostIdentityHash, decryptedContentBytes, err := readEncryptedAndSignedResponse(responseBytes, connectionKey, "GetReports")
if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err }
if (ableToRead == false){
//Response is malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
type responseContentStruct struct{
ReportsList []messagepack.RawMessage
}
var responseContentObject responseContentStruct
err = encoding.DecodeMessagePackBytes(true, decryptedContentBytes, &responseContentObject)
if (err != nil) {
// Response is malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
messagepackReportsList := responseContentObject.ReportsList
// We use this map to detect duplicates
reportHashesMap := make(map[[30]byte]struct{})
reportsList := make([][]byte, 0, len(messagepackReportsList))
// We use this variable to ensure all reports in response belong to the same network type
reportsNetworkType := byte(0)
for index, reportBytes := range messagepackReportsList{
ableToRead, reportHash, _, reportNetworkType, _, _, _, _, err := readReports.ReadReportAndHash(true, reportBytes)
if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err }
if (ableToRead == false){
// Response is malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
_, exists := reportHashesMap[reportHash]
if (exists == true){
// A duplicate report exists
// Response is malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
reportHashesMap[reportHash] = struct{}{}
if (index == 0){
reportsNetworkType = reportNetworkType
} else if (reportsNetworkType != reportNetworkType){
// All reports in response must belong to the same network type
// Response is malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
reportsList = append(reportsList, reportBytes)
}
return true, requestIdentifier, hostIdentityHash, reportsList, nil
}
// This object type is used to represent a deposit to an address
type DepositStruct struct{
// The cryptocurrency address where funds were deposited
Address string
// The unix time of the block when deposit(s) were made
DepositTime int64
// The sum of all deposit amounts in the block to the specified address, in crypto atomic units (example: wei)
//TODO: Change this to big.Int
DepositAmount int64
}
//Outputs:
// -[]byte: Response bytes
// -error
func CreateServerResponse_GetAddressDeposits(hostPublicIdentityKey [32]byte, hostPrivateIdentityKey [64]byte, connectionKey [32]byte, requestIdentifier [16]byte, depositObjectsList []DepositStruct)([]byte, error){
//TODO: Verify inputs
type responseContentStruct struct{
HostIdentityKey [32]byte
RequestIdentifier [16]byte
ResponseType string
AddressDepositsList []DepositStruct
}
responseContentObject := responseContentStruct{
HostIdentityKey: hostPublicIdentityKey,
RequestIdentifier: requestIdentifier,
ResponseType: "GetAddressDeposits",
AddressDepositsList: depositObjectsList,
}
innerResponseBytes, err := encoding.EncodeMessagePackBytes(responseContentObject)
if (err != nil) { return nil, err }
encryptedResponse, err := createEncryptedAndSignedResponse(connectionKey, hostPrivateIdentityKey, innerResponseBytes)
if (err != nil) { return nil, err }
return encryptedResponse, nil
}
//Outputs:
// -bool: Able to read server response
// -[16]byte: Request Identifier
// -[16]byte: Host Identity Hash
// -[]DepositStruct: Deposit objects list
// -error (returns err if input keys are invalid)
func ReadServerResponse_GetAddressDeposits(responseBytes []byte, connectionKey [32]byte)(bool, [16]byte, [16]byte, []DepositStruct, error){
//TODO: Verify inputs
ableToRead, requestIdentifier, hostIdentityHash, decryptedContentBytes, err := readEncryptedAndSignedResponse(responseBytes, connectionKey, "GetAddressDeposits")
if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err }
if (ableToRead == false){
//Response is malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
type responseContentStruct struct{
AddressDepositsList []DepositStruct
}
var responseContentObject responseContentStruct
err = encoding.DecodeMessagePackBytes(true, decryptedContentBytes, &responseContentObject)
if (err != nil) {
// Response malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
addressDepositsList := responseContentObject.AddressDepositsList
//TODO: validate info
return true, requestIdentifier, hostIdentityHash, addressDepositsList, nil
}
//Outputs:
// -[]byte: Response bytes
// -error
func CreateServerResponse_GetViewableStatuses(hostPublicIdentityKey [32]byte, hostPrivateIdentityKey [64]byte, connectionKey [32]byte, requestIdentifier [16]byte, identityHashStatusesMap map[[16]byte]bool, profileHashStatusesMap map[[28]byte]bool)([]byte, error){
//TODO: Verify inputs
type responseContentStruct struct{
HostIdentityKey [32]byte
RequestIdentifier [16]byte
ResponseType string
IdentityHashStatuses map[[16]byte]bool
ProfileHashStatuses map[[28]byte]bool
}
responseContentObject := responseContentStruct{
HostIdentityKey: hostPublicIdentityKey,
RequestIdentifier: requestIdentifier,
ResponseType: "GetViewableStatuses",
IdentityHashStatuses: identityHashStatusesMap,
ProfileHashStatuses: profileHashStatusesMap,
}
innerResponseBytes, err := encoding.EncodeMessagePackBytes(responseContentObject)
if (err != nil) { return nil, err }
encryptedResponse, err := createEncryptedAndSignedResponse(connectionKey, hostPrivateIdentityKey, innerResponseBytes)
if (err != nil) { return nil, err }
return encryptedResponse, nil
}
//Outputs:
// -bool: Able to read server response
// -[16]byte: Request Identifier
// -[16]byte: Host Identity Hash
// -map[[16]byte]bool: Identity Hash Statuses Map (Identity Hash -> true/false)( true = viewable, false = unviewable)
// -map[[28]byte]bool: Profile hash statuses map (Profile Hash -> true/false)( true = viewable, false = unviewable)
// -error (returns err if input keys are invalid)
func ReadServerResponse_GetViewableStatuses(responseBytes []byte, connectionKey [32]byte)(bool, [16]byte, [16]byte, map[[16]byte]bool, map[[28]byte]bool, error){
ableToRead, requestIdentifier, hostIdentityHash, decryptedContentBytes, err := readEncryptedAndSignedResponse(responseBytes, connectionKey, "GetViewableStatuses")
if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, nil, err }
if (ableToRead == false){
//Response is malformed
return false, [16]byte{}, [16]byte{}, nil, nil, nil
}
type responseContentStruct struct{
IdentityHashStatuses map[[16]byte]bool
ProfileHashStatuses map[[28]byte]bool
}
var responseContentObject responseContentStruct
err = encoding.DecodeMessagePackBytes(true, decryptedContentBytes, &responseContentObject)
if (err != nil) {
// Response malformed
return false, [16]byte{}, [16]byte{}, nil, nil, nil
}
identityHashStatusesMap := responseContentObject.IdentityHashStatuses
profileHashStatusesMap := responseContentObject.ProfileHashStatuses
//TODO: Verify maps
return true, requestIdentifier, hostIdentityHash, identityHashStatusesMap, profileHashStatusesMap, nil
}
//Outputs:
// -[]byte: Response bytes
// -error
func CreateServerResponse_BroadcastContent(hostPublicIdentityKey [32]byte, hostPrivateIdentityKey [64]byte, connectionKey [32]byte, requestIdentifier [16]byte, contentAcceptedInfoMap map[string]bool)([]byte, error){
//TODO: Verify inputs
type responseContentStruct struct{
HostIdentityKey [32]byte
RequestIdentifier [16]byte
ResponseType string
ContentAcceptedInfo map[string]bool //Content Hash -> true/false
}
responseContentObject := responseContentStruct{
HostIdentityKey: hostPublicIdentityKey,
RequestIdentifier: requestIdentifier,
ResponseType: "BroadcastContent",
ContentAcceptedInfo: contentAcceptedInfoMap,
}
innerResponseBytes, err := encoding.EncodeMessagePackBytes(responseContentObject)
if (err != nil) { return nil, err }
encryptedResponse, err := createEncryptedAndSignedResponse(connectionKey, hostPrivateIdentityKey, innerResponseBytes)
if (err != nil) { return nil, err }
return encryptedResponse, nil
}
//Outputs:
// -bool: Able to read server response
// -[16]byte: Request Identifier
// -[16]byte: Host Identity Hash
// -map[string]bool: Content Accepted Info Map (Content Hash -> true/false)
// -error (returns err if input keys are invalid)
func ReadServerResponse_BroadcastContent(responseBytes []byte, connectionKey [32]byte)(bool, [16]byte, [16]byte, map[string]bool, error){
//TODO: Verify stuff
ableToRead, requestIdentifier, hostIdentityHash, decryptedContentBytes, err := readEncryptedAndSignedResponse(responseBytes, connectionKey, "BroadcastContent")
if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err }
if (ableToRead == false){
//Response is malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
type responseContentStruct struct{
ContentAcceptedInfo map[string]bool
}
var responseContentObject responseContentStruct
err = encoding.DecodeMessagePackBytes(true, decryptedContentBytes, &responseContentObject)
if (err != nil) {
// Response is malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
contentAcceptedInfoMap := responseContentObject.ContentAcceptedInfo
for contentHash, _ := range contentAcceptedInfoMap{
_, err := helpers.GetContentTypeFromContentHash([]byte(contentHash))
if (err != nil){
// Invalid content hash
return false, [16]byte{}, [16]byte{}, nil, nil
}
}
return true, requestIdentifier, hostIdentityHash, contentAcceptedInfoMap, nil
}
func createEncryptedAndSignedResponse(connectionKey [32]byte, hostPrivateIdentityKey [64]byte, innerResponseBytes []byte)([]byte, error){
responseSignedBytes, err := createResponseSignedContent(hostPrivateIdentityKey, innerResponseBytes)
if (err != nil) { return nil, err }
encryptedResponse, err := createEncryptedResponse(responseSignedBytes, connectionKey)
if (err != nil) { return nil, err }
return encryptedResponse, nil
}
//Outputs:
// -bool: Able to read (response is valid)
// -[16]byte: Request identifier
// -[16]byte: Host identity hash
// -[]byte: Content Bytes
// -error (return err if there is a bug in the function)
func readEncryptedAndSignedResponse(inputResponse []byte, connectionKey [32]byte, expectedResponseType string)(bool, [16]byte, [16]byte, []byte, error){
ableToDecrypt, decryptedResponseBytes, err := readEncryptedResponse(inputResponse, connectionKey)
if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err }
if (ableToDecrypt == false){
return false, [16]byte{}, [16]byte{}, nil, nil
}
ableToRead, requestIdentifier, hostIdentityHash, contentBytes, err := readResponseSignedContent(decryptedResponseBytes, expectedResponseType)
if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err }
if (ableToRead == false){
//Response is malformed
return false, [16]byte{}, [16]byte{}, nil, nil
}
return true, requestIdentifier, hostIdentityHash, contentBytes, nil
}
func createEncryptedResponse(contentToEncrypt []byte, connectionKey [32]byte)([]byte, error){
chaPolyNonce, err := helpers.GetNewRandom24ByteArray()
if (err != nil) { return nil, err }
cipheredContent, err := chaPolyShrink.EncryptChaPolyShrink(contentToEncrypt, connectionKey, chaPolyNonce, true, 100, false, [32]byte{})
if (err != nil) { return nil, err }
type encryptedResponseStruct struct{
ChaPolyNonce [24]byte
CipheredContent []byte
}
encryptedResponseObject := encryptedResponseStruct{
ChaPolyNonce: chaPolyNonce,
CipheredContent: cipheredContent,
}
encryptedResponseBytes, err := encoding.EncodeMessagePackBytes(encryptedResponseObject)
if (err != nil) { return nil, err }
return encryptedResponseBytes, nil
}
//Outputs:
// -bool: Response well formed and able to decrypt
// -[]byte: Decrypted response
// -error (decryption key inputs are malformed)
func readEncryptedResponse(inputResponse []byte, connectionKey [32]byte)(bool, []byte, error){
type encryptedResponseStruct struct{
ChaPolyNonce [24]byte
CipheredContent []byte
}
var encryptedResponseObject encryptedResponseStruct
err := encoding.DecodeMessagePackBytes(true, inputResponse, &encryptedResponseObject)
if (err != nil) {
return false, nil, nil
}
chaPolyNonce := encryptedResponseObject.ChaPolyNonce
cipheredContent := encryptedResponseObject.CipheredContent
ableToDecrypt, decryptedBytes, err := chaPolyShrink.DecryptChaPolyShrink(cipheredContent, connectionKey, chaPolyNonce, false, [32]byte{})
if (err != nil) {
return false, nil, nil
}
if (ableToDecrypt == false){
return false, nil, nil
}
return true, decryptedBytes, nil
}
func createResponseSignedContent(hostIdentityPrivateKey [64]byte, responseContent messagepack.RawMessage)([]byte, error){
contentHash, err := blake3.Get32ByteBlake3Hash(responseContent)
if (err != nil) { return nil, err }
responseSignature := edwardsKeys.CreateSignature(hostIdentityPrivateKey, contentHash)
type finalResponseStruct struct {
Signature [64]byte
Content messagepack.RawMessage
}
finalResponseObject := finalResponseStruct{
Signature: responseSignature,
Content: responseContent,
}
finalResponseBytes, err := encoding.EncodeMessagePackBytes(finalResponseObject)
if (err != nil) { return nil, err }
return finalResponseBytes, nil
}
//Outputs:
// -bool: Able to read (response is valid)
// -[16]byte: Request identifier
// -[16]byte: Host identity hash
// -[]byte: Content bytes
// -error (return err if there is a bug in the function)
func readResponseSignedContent(inputBytes []byte, expectedResponseType string)(bool, [16]byte, [16]byte, []byte, error){
type outerResponseStruct struct{
Signature [64]byte
Content messagepack.RawMessage
}
var outerResponseObject outerResponseStruct
err := encoding.DecodeMessagePackBytes(true, inputBytes, &outerResponseObject)
if (err != nil) {
return false, [16]byte{}, [16]byte{}, nil, nil
}
responseSignature := outerResponseObject.Signature
responseContentBytes := outerResponseObject.Content
if (len(responseContentBytes) == 0){
return false, [16]byte{}, [16]byte{}, nil, nil
}
responseContentHashed, err := blake3.Get32ByteBlake3Hash(responseContentBytes)
if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err }
type partialResponseStruct struct {
HostIdentityKey [32]byte
RequestIdentifier [16]byte
ResponseType string
}
var partialResponseObject partialResponseStruct
err = encoding.DecodeMessagePackBytes(true, responseContentBytes, &partialResponseObject)
if (err != nil) {
return false, [16]byte{}, [16]byte{}, nil, nil
}
requestIdentifier := partialResponseObject.RequestIdentifier
hostIdentityKey := partialResponseObject.HostIdentityKey
responseType := partialResponseObject.ResponseType
isValid := edwardsKeys.VerifySignature(hostIdentityKey, responseSignature, responseContentHashed)
if (isValid == false){
return false, [16]byte{}, [16]byte{}, nil, nil
}
hostIdentityHash, err := identity.ConvertIdentityKeyToIdentityHash(hostIdentityKey, "Host")
if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err }
if (responseType != expectedResponseType){
return false, [16]byte{}, [16]byte{}, nil, nil
}
return true, requestIdentifier, hostIdentityHash, responseContentBytes, nil
}