// craftResponses provides a function to craft server responses to peer requests package craftResponses //TODO: Restrict responses based on if host is in HostViewable..Only mode //TODO: Add a response called Response Too Large, which means that the requestor has to // reduce their requested range for the host's response to fit within the maximum allowed size // We can check if a response has become too large as we craft each response import "seekia/internal/badgerDatabase" import "seekia/internal/byteRange" import "seekia/internal/contentMetadata" import "seekia/internal/encoding" import "seekia/internal/helpers" import "seekia/internal/identity" import "seekia/internal/logger" import "seekia/internal/messaging/chatMessageStorage" import "seekia/internal/messaging/readMessages" import "seekia/internal/moderation/moderatorScores" import "seekia/internal/moderation/readReports" import "seekia/internal/moderation/readReviews" import "seekia/internal/moderation/reportStorage" import "seekia/internal/moderation/reviewStorage" import "seekia/internal/moderation/verifiedStickyStatus" import "seekia/internal/myIdentity" import "seekia/internal/myRanges" import "seekia/internal/network/mateCriteria" import "seekia/internal/network/serverRequest" import "seekia/internal/network/serverResponse" import "seekia/internal/network/verifiedFundedStatus" import "seekia/internal/parameters/parametersStorage" import "seekia/internal/parameters/readParameters" import "seekia/internal/profiles/profileStorage" import "seekia/internal/profiles/readProfiles" import "seekia/internal/profiles/viewableProfiles" import "errors" import "slices" var invalidRequestResponse []byte = []byte("Invalid Request") //Outputs: // -bool: Response successfully crafted (request was well formed) // -bool: Identity hash of request matches our own // -bool: Network type of request matches provided network type // -[]byte: establishConnectionKey response // -[32]byte: Connection key in establishConnectionKey response // -error func GetEstablishConnectionKeyResponse(requestBytes []byte, networkType byte)(bool, bool, bool, []byte, [32]byte, error){ isValid := helpers.VerifyNetworkType(networkType) if (isValid == false){ networkTypeString := helpers.ConvertByteToString(networkType) return false, false, false, nil, [32]byte{}, errors.New("GetEstablishConnectionKeyResponse called with invalid networkType: " + networkTypeString) } myIdentityExists, myHostPublicIdentityKey, myHostPrivateIdentityKey, err := myIdentity.GetMyPublicPrivateIdentityKeys("Host") if (err != nil) { return false, false, false, nil, [32]byte{}, err } if (myIdentityExists == false){ return false, false, false, nil, [32]byte{}, errors.New("GetEstablishConnectionKeyResponse called when my host identity is missing.") } exists, myHostIdentityHash, err := myIdentity.GetMyIdentityHash("Host") if (err != nil) { return false, false, false, nil, [32]byte{}, err } if (exists == false){ return false, false, false, nil, [32]byte{}, errors.New("My identity not found after being found already.") } recipientHost, requestIdentifier, requestNetworkType, requestorNaclKey, requestorKyberKey, err := serverRequest.ReadServerRequest_EstablishConnectionKey(requestBytes) if (err != nil) { // Requestor must be malicious return false, false, false, nil, [32]byte{}, nil } if (recipientHost != myHostIdentityHash){ // Requestor is sending request to invalid recipient // Requestor could be malicious or another host could be posting our clearnet/onion address as their own // Either way, we don't continue connection return true, false, false, nil, [32]byte{}, nil } if (requestNetworkType != networkType){ // Either requestor is malicious, or we recently changed our network type // If we recently changed our network type, our old host profile may still exist on the old network // This request could be coming from someone who has our old host profile downloaded // The Seekia app should broadcast a disabled host profile for the old network type before switching network types // Doing this will never solve this issue fully, because the new profile will take time to propagate to users // Users may also connect to outdated host profiles upon startup, so this problem will always exist, which is fine. return true, true, false, nil, [32]byte{}, nil } responseBytes, newConnectionKey, err := serverResponse.CreateServerResponse_EstablishConnectionKey(myHostPublicIdentityKey, myHostPrivateIdentityKey, requestIdentifier, requestorNaclKey, requestorKyberKey) if (err != nil) { return false, false, false, nil, [32]byte{}, err } return true, true, true, responseBytes, newConnectionKey, nil } //Outputs: // -[]byte: Response Bytes // -error func GetServerResponseForRequest(requestBytes []byte, networkType byte, connectionKey [32]byte)([]byte, error){ isValid := helpers.VerifyNetworkType(networkType) if (isValid == false){ networkTypeString := helpers.ConvertByteToString(networkType) return nil, errors.New("GetServerResponseForRequest called with invalid networkType: " + networkTypeString) } myIdentityExists, myHostPublicIdentityKey, myHostPrivateIdentityKey, err := myIdentity.GetMyPublicPrivateIdentityKeys("Host") if (err != nil) { return nil, err } if (myIdentityExists == false){ return nil, errors.New("GetServerResponseForRequest called when my host identity is missing.") } exists, myHostIdentityHash, err := myIdentity.GetMyIdentityHash("Host") if (err != nil) { return nil, err } if (exists == false){ return nil, errors.New("My host identity not found after being found already.") } // First we decrypt the request ableToRead, decryptedRequestBytes, err := serverRequest.ReadEncryptedRequest(requestBytes, connectionKey) if (err != nil) { return nil, err } if (ableToRead == false){ // Cannot read, request is malformed return invalidRequestResponse, nil } // Now we read request to retrieve and verify attributes included in all requests //TODO: Verify everything requestRecipientHost, requestType, requestIdentifier, requestNetworkType, err := serverRequest.ReadDecryptedServerRequest_StandardData(decryptedRequestBytes) if (err != nil){ // decryptedRequestBytes are malformed, requestor must be malicious return invalidRequestResponse, nil } if (requestRecipientHost != myHostIdentityHash){ // Requestor must be malicious, because identity hash never changes during connection return invalidRequestResponse, nil } if (requestNetworkType != networkType){ // Requestor must be malicious, because network type never changes during connection return invalidRequestResponse, nil } // Now we get response based on the requestType if (requestType == "GetParametersInfo"){ //TODO: Check if host is hosting parameters allParametersTypesList := readParameters.GetAllParametersTypesList() parametersInfoMap := make(map[string]int64) for _, parametersType := range allParametersTypesList{ parametersFound, _, _, parametersBroadcastTime, err := parametersStorage.GetAuthorizedParameters(parametersType, networkType) if (err != nil) { return nil, err } if (parametersFound == false){ continue } parametersInfoMap[parametersType] = parametersBroadcastTime } responseBytes, err := serverResponse.CreateServerResponse_GetParametersInfo(myHostPublicIdentityKey, myHostPrivateIdentityKey, connectionKey, requestIdentifier, parametersInfoMap) if (err != nil) { return nil, err } return responseBytes, nil } if (requestType == "GetParameters"){ //TODO: Verify host is hosting network parameters requestedParametersTypesList, err := serverRequest.ReadDecryptedServerRequest_GetParameters(decryptedRequestBytes) if (err != nil){ return invalidRequestResponse, nil } parametersList := make([][]byte, 0) for _, parametersType := range requestedParametersTypesList{ parametersFound, parametersBytes, _, _, err := parametersStorage.GetAuthorizedParameters(parametersType, networkType) if (err != nil) { return nil, err } if (parametersFound == false){ continue } parametersList = append(parametersList, parametersBytes) } responseBytes, err := serverResponse.CreateServerResponse_GetParameters(myHostPublicIdentityKey, myHostPrivateIdentityKey, connectionKey, requestIdentifier, parametersList) if (err != nil) { return nil, err } return responseBytes, nil } if (requestType == "GetProfilesInfo"){ acceptableProfileVersionsList, profileTypeToRetrieve, requestRangeStart, requestRangeEnd, requestedIdentityHashesList, requestCriteria, getNewestProfilesOnly, getViewableProfilesOnly, err := serverRequest.ReadDecryptedServerRequest_GetProfilesInfo(decryptedRequestBytes) if (err != nil){ return invalidRequestResponse, nil } getRelevantIdentityHashesList := func()([][16]byte, error){ // We will find the relevant identity hashes based on either the request range or requested identities list if (len(requestedIdentityHashesList) != 0){ return requestedIdentityHashesList, nil } storedProfileIdentityHashesList, err := badgerDatabase.GetAllProfileIdentityHashes(profileTypeToRetrieve) if (err != nil) { return nil, err } anyExist, identityHashesInRequestRange, err := byteRange.GetAllIdentityHashesInListWithinRange(requestRangeStart, requestRangeEnd, storedProfileIdentityHashesList) if (err != nil) { return nil, err } if (anyExist == false){ emptyList := make([][16]byte, 0) return emptyList, nil } return identityHashesInRequestRange, nil } relevantIdentityHashesList, err := getRelevantIdentityHashesList() if (err != nil) { return nil, err } // We limit request to profiles hosted by host // This is to prevent the requestor from learning information about profiles the host has downloaded // This would be a privacy leak if the host is using Seekia to find matches/moderate. // The requestor would know which profiles outside of the hosted range the host had downloaded // This could potentially tell them the host's location and desires // We reduce requested identity hashes list based on our host range getIdentitiesInMyHostRangeList := func()([][16]byte, error){ hostModeEnabled, hostingAny, myHostRangeStart, myHostRangeEnd, err := myRanges.GetMyIdentitiesToHostRange(profileTypeToRetrieve) if (err != nil) { return nil, err } if (hostModeEnabled == false){ // User must have disabled host mode emptyList := make([][16]byte, 0) return emptyList, nil } if (hostingAny == false){ // We are not hosting any of the requested ProfileType emptyList := make([][16]byte, 0) return emptyList, nil } anyExist, identityHashesInMyHostRangeList, err := byteRange.GetAllIdentityHashesInListWithinRange(myHostRangeStart, myHostRangeEnd, relevantIdentityHashesList) if (err != nil) { return nil, err } if (anyExist == false){ emptyList := make([][16]byte, 0) return emptyList, nil } return identityHashesInMyHostRangeList, nil } requestedIdentitiesInMyHostRangeList, err := getIdentitiesInMyHostRangeList() if (err != nil){ return nil, err } // Now we reduce list to make sure identities are funded fundedIdentitiesList := make([][16]byte, 0) for _, identityHash := range requestedIdentitiesInMyHostRangeList{ if (profileTypeToRetrieve == "Moderator"){ statusIsKnown, _, scoreIsSufficient, _, _, err := moderatorScores.GetModeratorIdentityScore(identityHash) if (err != nil) { return nil, err } if (statusIsKnown == false || scoreIsSufficient == false){ continue } } else { // profileType == "Mate" or "Host" statusIsKnown, isFunded, _, _, err := verifiedFundedStatus.GetVerifiedIdentityIsFundedStatus(identityHash, networkType) if (err != nil) { return nil, err } if (statusIsKnown == false || isFunded == false){ continue } } fundedIdentitiesList = append(fundedIdentitiesList, identityHash) } // Now we iterate through all relevant identity hashes, find which profile(s) to send in response // Then we add those profiles to profilesInfoMapList profileInfoObjectsList := make([]serverResponse.ProfileInfoStruct, 0) for _, identityHash := range fundedIdentitiesList{ //Outputs: // -[][28]byte: List of profile hashes // -error getUserProfileHashesForRequest := func()([][28]byte, error){ if (getNewestProfilesOnly == true){ if (getViewableProfilesOnly == true){ profileExists, _, profileHash, _, _, _, err := viewableProfiles.GetNewestViewableUserProfile(identityHash, networkType, false, false, false) if (err != nil) { return nil, err } if (profileExists == false){ emptyList := make([][28]byte, 0) return emptyList, nil } profileHashesList := [][28]byte{profileHash} return profileHashesList, nil } // getNewestProfilesOnly = true & getViewableProfilesOnly = false profileExists, _, profileHash, _, _, _, err := profileStorage.GetNewestUserProfile(identityHash, networkType) if (err != nil) { return nil, err } if (profileExists == false){ emptyList := make([][28]byte, 0) return emptyList, nil } profileHashesList := [][28]byte{profileHash} return profileHashesList, nil } // getNewestProfilesOnly == false if (getViewableProfilesOnly == true){ // We will check to see if identity is banned downloadingRequiredReviews, parametersExist, stickyStatusEstablished, identityIsViewable, err := verifiedStickyStatus.GetVerifiedIdentityIsViewableStickyStatus(identityHash, networkType) if (err != nil) { return nil, err } if (downloadingRequiredReviews == false || parametersExist == false || stickyStatusEstablished == false){ //We do not know if this identity is banned or not. // We cannot seed any profiles from this user emptyList := make([][28]byte, 0) return emptyList, nil } if (identityIsViewable == false){ // Identity is banned, therefore all profiles are unviewable emptyList := make([][28]byte, 0) return emptyList, nil } } getAllProfileHashesForIdentity := func()([][28]byte, error){ exists, profileHashesList, err := badgerDatabase.GetIdentityProfileHashesList(identityHash) if (err != nil) { return nil, err } if (exists == false){ emptyList := make([][28]byte, 0) return emptyList, nil } return profileHashesList, nil } allProfileHashesForIdentityList, err := getAllProfileHashesForIdentity() if (err != nil) { return nil, err } if (getViewableProfilesOnly == false){ return allProfileHashesForIdentityList, nil } // Now we prune unviewable profiles viewableProfileHashesList := make([][28]byte, 0) for _, profileHash := range allProfileHashesForIdentityList{ profileIsDisabled, profileMetadataIsKnown, profileNetworkType, profileAuthor, downloadingRequiredReviews, parametersExist, stickyStatusEstablished, profileIsViewableStatus, err := verifiedStickyStatus.GetVerifiedProfileIsViewableStickyStatus(profileHash) if (err != nil) { return nil, err } if (profileMetadataIsKnown == false){ continue } if (profileNetworkType != networkType){ continue } if (profileIsDisabled == true){ viewableProfileHashesList = append(viewableProfileHashesList, profileHash) continue } if (profileAuthor != identityHash){ return nil, errors.New("GetVerifiedProfileIsViewableStickyStatus returning different profileAuthor") } if (downloadingRequiredReviews == false){ // This should not happen, because this was checked earlier in function // Maybe client changed hosted range logger.AddLogError("Network", errors.New("Profile not in hosted range anymore.")) break } if (parametersExist == false){ // We cannot determine sticky consensus status for this profile. // We shouldn't be hosting without the parameters anyway emptyList := make([][28]byte, 0) return emptyList, nil } if (stickyStatusEstablished == false){ // We cannot determine sticky consensus for this profile // Continue to next profile continue } if (profileIsViewableStatus == false){ continue } viewableProfileHashesList = append(viewableProfileHashesList, profileHash) } return viewableProfileHashesList, nil } userProfileHashesForRequestList, err := getUserProfileHashesForRequest() if (err != nil) { return nil, err } for _, profileHash := range userProfileHashesForRequestList{ if (profileTypeToRetrieve == "Mate"){ statusIsKnown, isFunded, _, _, err := verifiedFundedStatus.GetVerifiedMateProfileIsFundedStatus(profileHash) if (err != nil) { return nil, err } if (statusIsKnown == false || isFunded == false){ continue } } profileExists, profileBytes, err := badgerDatabase.GetUserProfile(profileTypeToRetrieve, profileHash) if (err != nil) { return nil, err } if (profileExists == false){ // Profile must have been deleted continue } ableToRead, profileHash_Retrieved, profileVersion, profileNetworkType, profileAuthor, profileBroadcastTime, profileIsDisabled, rawProfileMap, err := readProfiles.ReadProfileAndHash(false, profileBytes) if (err != nil) { return nil, err } if (ableToRead == false){ return nil, errors.New("Database corrupt: contains invalid " + profileTypeToRetrieve + " profile") } if (profileHash != profileHash_Retrieved){ return nil, errors.New("Database corrupt: Contains profile with different hash than entry key.") } if (profileAuthor != identityHash){ return nil, errors.New("getIdentityProfilesForRequest returning profile from a different identity hash") } if (profileNetworkType != networkType){ continue } isRequestedVersion := slices.Contains(acceptableProfileVersionsList, profileVersion) if (isRequestedVersion == false){ // The requestor cannot accept this profile's version // We must have a newer or older Seekia application version continue } if (requestCriteria != nil){ if (profileIsDisabled == true){ // Disabled profiles will not fulfill any criteria continue } criteriaIsValid, fulfillsCriteria, err := mateCriteria.CheckIfMateProfileFulfillsCriteria(true, profileVersion, rawProfileMap, requestCriteria) if (err != nil) { return nil, err } if (criteriaIsValid == false){ return nil, errors.New("ReadDecryptedServerRequest_GetProfilesInfo not verifying criteria.") } if (fulfillsCriteria == false){ continue } } profileInfoObject := serverResponse.ProfileInfoStruct{ ProfileHash: profileHash, ProfileAuthor: profileAuthor, ProfileBroadcastTime: profileBroadcastTime, } profileInfoObjectsList = append(profileInfoObjectsList, profileInfoObject) } } responseBytes, err := serverResponse.CreateServerResponse_GetProfilesInfo(myHostPublicIdentityKey, myHostPrivateIdentityKey, connectionKey, requestIdentifier, profileInfoObjectsList) if (err != nil) { return nil, err } return responseBytes, nil } if (requestType == "GetProfiles"){ profileTypeToRetrieve, profileHashesToRetrieveList, err := serverRequest.ReadDecryptedServerRequest_GetProfiles(decryptedRequestBytes) if (err != nil){ // Request is malformed return invalidRequestResponse, nil } // First we get all profiles that we have that the peer is requesting // Then we prune requested profiles list // We prune profiles whose authors are not funded, and profiles that are not funded // We prune profiles whose author is not within our hosted range // This is done for host privacy // Otherwise a malicious requestor could try to find other profiles the host has // This could fingerprint the host and make it possible to link the host identity to their mate/moderator identity/activities getPrunedProfilesList := func()([][]byte, error){ hostModeEnabled, hostingAny, myHostRangeStart, myHostRangeEnd, err := myRanges.GetMyIdentitiesToHostRange(profileTypeToRetrieve) if (err != nil) { return nil, err } if (hostModeEnabled == false){ // Host must have disabled host mode in the background emptyList := make([][]byte, 0) return emptyList, nil } if (hostingAny == false){ // Host is not hosting any of the requested profiles emptyList := make([][]byte, 0) return emptyList, nil } requestedProfilesList := make([][]byte, 0) for _, profileHash := range profileHashesToRetrieveList{ if (profileTypeToRetrieve == "Mate"){ // We make sure profile is funded statusIsKnown, isFunded, _, _, err := verifiedFundedStatus.GetVerifiedMateProfileIsFundedStatus(profileHash) if (err != nil) { return nil, err } if (statusIsKnown == false || isFunded == false){ continue } } profileExists, profileBytes, err := badgerDatabase.GetUserProfile(profileTypeToRetrieve, profileHash) if (err != nil) { return nil, err } if (profileExists == false){ // Profile could have been deleted after profile hashes response was made, or peer is malicious // Either way, skip profile continue } ableToRead, profileHash_Retrieved, _, profileNetworkType, profileAuthor, _, _, _, err := readProfiles.ReadProfileAndHash(false, profileBytes) if (err != nil) { return nil, err } if (ableToRead == false){ return nil, errors.New("Database corrupt: Contains invalid profile.") } if (profileHash_Retrieved != profileHash){ return nil, errors.New("Database corrupt: Contains profile with different hash than entry key.") } if (profileNetworkType != networkType){ // This should not happen unless requestor is malicious // Requestor should only request profile hashes which we served in our GetProfilesInfo response continue } if (profileTypeToRetrieve == "Mate"){ // Because hosts will provide all or no moderator/host profiles // We only need to check if identity is in our range if profileType is Mate isWithinRange, err := byteRange.CheckIfIdentityHashIsWithinRange(myHostRangeStart, myHostRangeEnd, profileAuthor) if (err != nil) { return nil, err } if (isWithinRange == false){ continue } } // We check if author is funded if (profileTypeToRetrieve == "Moderator"){ statusIsKnown, _, scoreIsSufficient, _, _, err := moderatorScores.GetModeratorIdentityScore(profileAuthor) if (err != nil) { return nil, err } if (statusIsKnown == false || scoreIsSufficient == false){ continue } } else { // profileType == "Mate" or "Host" statusIsKnown, isFunded, _, _, err := verifiedFundedStatus.GetVerifiedIdentityIsFundedStatus(profileAuthor, networkType) if (err != nil) { return nil, err } if (statusIsKnown == false || isFunded == false){ continue } } requestedProfilesList = append(requestedProfilesList, profileBytes) } return requestedProfilesList, nil } prunedProfilesList, err := getPrunedProfilesList() if (err != nil) { return nil, err } responseBytes, err := serverResponse.CreateServerResponse_GetProfiles(myHostPublicIdentityKey, myHostPrivateIdentityKey, connectionKey, requestIdentifier, prunedProfilesList) if (err != nil) { return nil, err } return responseBytes, nil } if (requestType == "GetMessageHashesList"){ acceptableMessageVersionsList, requestInboxRangeStart, requestInboxRangeEnd, requestedInboxesList, getViewableMessagesOnly, getDecryptableMessagesOnly, err := serverRequest.ReadDecryptedServerRequest_GetMessageHashesList(decryptedRequestBytes) if (err != nil){ return invalidRequestResponse, nil } getMessageHashesForResponseList := func()([][26]byte, error){ hostModeEnabled, hostingAnyInboxes, myHostedInboxesRangeStart, myHostedInboxesRangeEnd, err := myRanges.GetMyInboxesToHostRange() if (err != nil) { return nil, err } if (hostModeEnabled == false){ // User must have disabled host mode recently emptyList := make([][26]byte, 0) return emptyList, nil } if (hostingAnyInboxes == false){ emptyList := make([][26]byte, 0) return emptyList, nil } getRequestedMessageInboxesList := func()([][10]byte, error){ if (len(requestedInboxesList) != 0){ // We will ignore range and only retrieve based on inboxes list return requestedInboxesList, nil } // We will retrieve messages based on request inbox range allMessageInboxesList, err := badgerDatabase.GetAllMessageInboxes() if (err != nil) { return nil, err } anyFound, intersectionInboxesList, err := byteRange.GetAllInboxesInListWithinRange(requestInboxRangeStart, requestInboxRangeEnd, allMessageInboxesList) if (err != nil) { return nil, err } if (anyFound == false){ emptyList := make([][10]byte, 0) return emptyList, nil } return intersectionInboxesList, nil } requestedMessageInboxesList, err := getRequestedMessageInboxesList() if (err != nil) { return nil, err } messageHashesForResponseList := make([][26]byte, 0) for _, inboxToRetrieve := range requestedMessageInboxesList{ // We check if inbox is in our range isWithinMyRange, err := byteRange.CheckIfInboxIsWithinRange(myHostedInboxesRangeStart, myHostedInboxesRangeEnd, inboxToRetrieve) if (err != nil) { return nil, err } if (isWithinMyRange == false){ continue } anyExist, messageHashesList, err := badgerDatabase.GetChatInboxMessageHashesList(inboxToRetrieve) if (err != nil) { return nil, err } if (anyExist == false){ continue } for _, messageHash := range messageHashesList{ // We make sure each message is of an acceptable version metadataExists, messageVersion, messageNetworkType, _, messageInbox, messageCipherKeyHash, err := contentMetadata.GetMessageMetadata(messageHash) if (err != nil) { return nil, err } if (metadataExists == false){ // We don't have the message stored. continue } if (messageInbox != inboxToRetrieve){ return nil, errors.New("GetChatInboxMessageHashesList returning list with message of different inbox.") } if (messageNetworkType != networkType){ // Message belongs to a different networkType continue } isAcceptable := slices.Contains(acceptableMessageVersionsList, messageVersion) if (isAcceptable == false){ continue } // We make sure each message is funded statusIsKnown, messageIsFunded, _, _, err := verifiedFundedStatus.GetVerifiedMessageIsFundedStatus(messageHash) if (err != nil) { return nil, err } if (statusIsKnown == false || messageIsFunded == false){ continue } if (getViewableMessagesOnly == true){ // We make sure message is viewable messageMetadataIsKnown, messageNetworkType, messageInbox, _, downloadingRequiredReviews, parametersExist, statusEstablished, messageIsViewableStatus, err := verifiedStickyStatus.GetVerifiedMessageIsViewableStickyStatus(messageHash) if (err != nil) { return nil, err } if (messageMetadataIsKnown == false){ // Message was deleted, skip to next message continue } if (messageNetworkType != networkType){ return nil, errors.New("GetVerifiedMessageIsViewableStickyStatus returning different message networkType than contentMetadata.") } if (messageInbox != inboxToRetrieve){ return nil, errors.New("GetVerifiedMessageIsViewableStickyStatus returning invalid message inbox") } if (downloadingRequiredReviews == false){ // This should only happen if hosted inbox range was changed during this operation // All messages for this inbox will be out of range break } if (parametersExist == false){ //We cannot determine sticky status for any messages. Return empty response to peer. emptyList := make([][26]byte, 0) return emptyList, nil } if (statusEstablished == false){ // We do not know sticky consensus for message. Skip message. continue } if (messageIsViewableStatus == false){ continue } } if (getDecryptableMessagesOnly == true){ // We make sure at least 1 review/report with valid cipher key exists for message checkIfMessageCipherKeyExists := func()(bool, error){ cipherKeyFound, _, err := reportStorage.GetMessageCipherKeyFromAnyReport(messageHash, messageNetworkType, messageCipherKeyHash) if (err != nil) { return false, err } if (cipherKeyFound == true){ return true, nil } cipherKeyFound, _, err = reviewStorage.GetMessageCipherKeyFromAnyReview(messageHash, messageNetworkType, messageCipherKeyHash) if (err != nil) { return false, err } if (cipherKeyFound == true){ return true, nil } return false, nil } messageCipherKeyExists, err := checkIfMessageCipherKeyExists() if (err != nil) { return nil, err } if (messageCipherKeyExists == false){ continue } } messageHashesForResponseList = append(messageHashesForResponseList, messageHash) } } return messageHashesForResponseList, nil } messageHashesForResponseList, err := getMessageHashesForResponseList() if (err != nil) { return nil, err } responseBytes, err := serverResponse.CreateServerResponse_GetMessageHashesList(myHostPublicIdentityKey, myHostPrivateIdentityKey, connectionKey, requestIdentifier, messageHashesForResponseList) if (err != nil) { return nil, err } return responseBytes, nil } if (requestType == "GetMessages"){ requestedMessageHashesList, err := serverRequest.ReadDecryptedServerRequest_GetMessages(decryptedRequestBytes) if (err != nil) { return nil, err } getMessagesListForResponse := func()([][]byte, error){ hostModeEnabled, hostingAny, myInboxRangeStart, myInboxRangeEnd, err := myRanges.GetMyInboxesToHostRange() if (err != nil) { return nil, err } if (hostModeEnabled == false){ // User must have disabled host mode emptyList := make([][]byte, 0) return emptyList, nil } if (hostingAny == false){ // We are not hosting any messages emptyList := make([][]byte, 0) return emptyList, nil } messagesListForResponse := make([][]byte, 0) for _, messageHash := range requestedMessageHashesList{ // We make sure each message is funded statusIsKnown, messageIsFunded, _, _, err := verifiedFundedStatus.GetVerifiedMessageIsFundedStatus(messageHash) if (err != nil) { return nil, err } if (statusIsKnown == false || messageIsFunded == false){ continue } messageExists, messageBytes, err := badgerDatabase.GetChatMessage(messageHash) if (err != nil) { return nil, err } if (messageExists == false){ continue } ableToRead, currentMessageHash, _, messageNetworkType, messageInbox, _, _, _, _, _, _, err := readMessages.ReadChatMessagePublicDataAndHash(false, messageBytes) if (err != nil) { return nil, err } if (ableToRead == false){ return nil, errors.New("Database corrupt: Contains malformed message.") } if (messageHash != currentMessageHash){ return nil, errors.New("Database corrupt: Contains message with mismatched messageHash entry key") } if (messageNetworkType != networkType){ // This should not happen unless requestor is malicious // The requestor should only requests messages which we already said were on the connection networkType. continue } isWithinMyRange, err := byteRange.CheckIfInboxIsWithinRange(myInboxRangeStart, myInboxRangeEnd, messageInbox) if (err != nil) { return nil, err } if (isWithinMyRange == false){ continue } messagesListForResponse = append(messagesListForResponse, messageBytes) } return messagesListForResponse, nil } messagesListForResponse, err := getMessagesListForResponse() if (err != nil) { return nil, err } responseBytes, err := serverResponse.CreateServerResponse_GetMessages(myHostPublicIdentityKey, myHostPrivateIdentityKey, connectionKey, requestIdentifier, messagesListForResponse) if (err != nil) { return nil, err } return responseBytes, nil } if (requestType == "GetIdentityReviewsInfo"){ acceptableReviewVersions, identityTypeToRetrieve, requestRangeStart, requestRangeEnd, requestedReviewedIdentityHashesList, requestedReviewersList, err := serverRequest.ReadDecryptedServerRequest_GetIdentityReviewsInfo(decryptedRequestBytes) if (err != nil){ return invalidRequestResponse, nil } getReviewsInfoMap := func()(map[[29]byte][]byte, error){ hostModeEnabled, hostingAny, myIdentityRangeStart, myIdentityRangeEnd, err := myRanges.GetMyIdentitiesToHostRange(identityTypeToRetrieve) if (err != nil) { return nil, err } if (hostModeEnabled == false){ // We must have turned off host mode recently emptyReviewsInfoMap := make(map[[29]byte][]byte) return emptyReviewsInfoMap, nil } if (hostingAny == false){ emptyReviewsInfoMap := make(map[[29]byte][]byte) return emptyReviewsInfoMap, nil } // We include identity, profile and attribute reviews relevantReviewHashesList := make([][29]byte, 0) allReviewedIdentityHashesList, err := badgerDatabase.GetAllReviewedIdentityHashes() if (err != nil) { return nil, err } for _, identityHash := range allReviewedIdentityHashesList{ anyExist, reviewHashesList, err := badgerDatabase.GetIdentityReviewsList(identityHash) if (err != nil) { return nil, err } if (anyExist == true){ relevantReviewHashesList = append(relevantReviewHashesList, reviewHashesList...) } } allReviewedProfileHashesList, err := badgerDatabase.GetAllReviewedProfileHashes() if (err != nil) { return nil, err } for _, profileHash := range allReviewedProfileHashesList{ anyExist, reviewHashesList, err := badgerDatabase.GetProfileReviewsList(profileHash) if (err != nil) { return nil, err } if (anyExist == true){ relevantReviewHashesList = append(relevantReviewHashesList, reviewHashesList...) } } allReviewedAttributeHashesList, err := badgerDatabase.GetAllReviewedProfileAttributeHashes() if (err != nil) { return nil, err } for _, attributeHash := range allReviewedAttributeHashesList{ anyExist, reviewHashesList, err := badgerDatabase.GetProfileAttributeReviewsList(attributeHash) if (err != nil) { return nil, err } if (anyExist == true){ relevantReviewHashesList = append(relevantReviewHashesList, reviewHashesList...) } } // Map structure: Review hash -> Reviewed hash reviewsInfoMap := make(map[[29]byte][]byte) for _, reviewHash := range relevantReviewHashesList{ reviewExists, reviewBytes, err := badgerDatabase.GetReview(reviewHash) if (err != nil) { return nil, err } if (reviewExists == false){ // Review must have been deleted automatically. // The database entry that referenced the review will be deleted automatically continue } ableToRead, currentReviewHash, reviewVersion, reviewNetworkType, reviewerIdentityHash, _, reviewType, reviewedHash, _, _, err := readReviews.ReadReviewAndHash(false, reviewBytes) if (err != nil) { return nil, err } if (ableToRead == false){ return nil, errors.New("Database corrupt: Contains invalid review.") } if (reviewHash != currentReviewHash){ return nil, errors.New("Database corrupt: Review entry key does not match review hash") } isAcceptableVersion := slices.Contains(acceptableReviewVersions, reviewVersion) if (isAcceptableVersion == false){ // Review is of a different version than requestor can accept // We must have a different Seekia app version than them. continue } if (reviewNetworkType != networkType){ // Review belongs to a different networkType continue } if (len(requestedReviewersList) != 0){ isInRequestedList := slices.Contains(requestedReviewersList, reviewerIdentityHash) if (isInRequestedList == false){ continue } } statusIsKnown, _, scoreIsSufficient, _, _, err := moderatorScores.GetModeratorIdentityScore(reviewerIdentityHash) if (err != nil) { return nil, err } if (statusIsKnown == false || scoreIsSufficient == false){ continue } //Outputs: // -bool: Review is malicious // -bool: Reviewed identity hash is known // -[16]byte: Reviewed identity hash // -error getReviewedIdentityHash := func()(bool, bool, [16]byte, error){ if (reviewType == "Identity"){ if (len(reviewedHash) != 16){ reviewedHashHex := encoding.EncodeBytesToHexString(reviewedHash) return false, false, [16]byte{}, errors.New("ReadReview returning invalid reviewedHash length for Identity review: " + reviewedHashHex) } reviewedIdentityHash := [16]byte(reviewedHash) return false, true, reviewedIdentityHash, nil } if (reviewType == "Profile"){ if (len(reviewedHash) != 28){ reviewedHashHex := encoding.EncodeBytesToHexString(reviewedHash) return false, false, [16]byte{}, errors.New("ReadReview returning invalid reviewedHash length for Profile review: " + reviewedHashHex) } reviewedProfileHash := [28]byte(reviewedHash) metadataExists, _, profileNetworkType, profileAuthor, _, _, _, _, err := contentMetadata.GetProfileMetadata(reviewedProfileHash) if (err != nil) { return false, false, [16]byte{}, err } if (metadataExists == false){ return false, false, [16]byte{}, nil } if (profileNetworkType != reviewNetworkType){ // The review is reviewing a profile from a different networkType // The review author must be malicious return true, false, [16]byte{}, nil } return false, true, profileAuthor, nil } if (reviewType == "Attribute"){ if (len(reviewedHash) != 27){ reviewedHashHex := encoding.EncodeBytesToHexString(reviewedHash) return false, false, [16]byte{}, errors.New("ReadReview returning invalid reviewedHash length for Attribute review: " + reviewedHashHex) } reviewedAttributeHash := [27]byte(reviewedHash) attributeMetadataFound, _, authorIdentityHash, attributeNetworkType, _, err := profileStorage.GetProfileAttributeMetadata(reviewedAttributeHash) if (err != nil) { return false, false, [16]byte{}, err } if (attributeMetadataFound == false){ return false, false, [16]byte{}, nil } if (attributeNetworkType != reviewNetworkType){ // The review is reviewing an attribute from a different networkType // The review author must be malicious return true, false, [16]byte{}, nil } return false, true, authorIdentityHash, nil } return false, false, [16]byte{}, errors.New("getReviewedIdentityHash reached during GetIdentityReviewsInfo response craft with invalid reviewType: " + reviewType) } reviewIsMalicious, reviewedIdentityHashIsKnown, reviewedIdentityHash, err := getReviewedIdentityHash() if (err != nil) { return nil, err } if (reviewIsMalicious == true){ // Review is malicious. We will not seed reviews which are known to be malicious // TODO: Skipping these kinds of reviews could be a fingerprinting risk? continue } if (reviewedIdentityHashIsKnown == false){ // We cannot seed reviews whose reviewed identity hash is not known. continue } reviewedIdentityType, err := identity.GetIdentityTypeFromIdentityHash(reviewedIdentityHash) if (err != nil){ return nil, err } if (reviewedIdentityType != identityTypeToRetrieve){ continue } if (len(requestedReviewedIdentityHashesList) != 0){ // We make sure all reviewed identity hashes are within this list isWithinList := slices.Contains(requestedReviewedIdentityHashesList, reviewedIdentityHash) if (isWithinList == false){ continue } } else { identityIsWithinRequestRange, err := byteRange.CheckIfIdentityHashIsWithinRange(requestRangeStart, requestRangeEnd, reviewedIdentityHash) if (err != nil) { return nil, err } if (identityIsWithinRequestRange == false){ continue } } // We make sure identity is within our range isWithinMyRange, err := byteRange.CheckIfIdentityHashIsWithinRange(myIdentityRangeStart, myIdentityRangeEnd, reviewedIdentityHash) if (err != nil) { return nil, err } if (isWithinMyRange == false){ continue } // We make sure reviewed identity is funded if (identityTypeToRetrieve == "Moderator"){ statusIsKnown, _, scoreIsSufficient, _, _, err := moderatorScores.GetModeratorIdentityScore(reviewedIdentityHash) if (err != nil) { return nil, err } if (statusIsKnown == false || scoreIsSufficient == false){ continue } } else { // identityTypeToRetrieve == "Mate" or "Host" statusIsKnown, isFunded, _, _, err := verifiedFundedStatus.GetVerifiedIdentityIsFundedStatus(reviewedIdentityHash, networkType) if (err != nil) { return nil, err } if (statusIsKnown == false || isFunded == false){ continue } } if (identityTypeToRetrieve == "Mate" && reviewType == "Profile"){ // We make sure the mate profile is funded if (len(reviewedHash) != 28){ reviewedHashHex := encoding.EncodeBytesToHexString(reviewedHash) return nil, errors.New("ReadReview returning invalid length reviewedHash for Profile review: " + reviewedHashHex) } reviewedProfileHash := [28]byte(reviewedHash) statusIsKnown, isFunded, _, _, err := verifiedFundedStatus.GetVerifiedMateProfileIsFundedStatus(reviewedProfileHash) if (err != nil) { return nil, err } if (statusIsKnown == false || isFunded == false){ continue } } else if (identityTypeToRetrieve == "Mate" && reviewType == "Attribute"){ // We make sure at least 1 profile with this attribute is funded checkIfAnyAttributeProfileIsFunded := func()(bool, error){ if (len(reviewedHash) != 27){ reviewedHashHex := encoding.EncodeBytesToHexString(reviewedHash) return false, errors.New("ReadReview returning invalid length reviewedHash for attribute review: " + reviewedHashHex) } reviewedAttributeHash := [27]byte(reviewedHash) anyExist, attributeProfileHashesList, err := badgerDatabase.GetAttributeProfilesList(reviewedAttributeHash) if (err != nil) { return false, err } if (anyExist == false){ return false, nil } for _, profileHash := range attributeProfileHashesList{ statusIsKnown, isFunded, _, _, err := verifiedFundedStatus.GetVerifiedMateProfileIsFundedStatus(profileHash) if (err != nil) { return false, err } if (statusIsKnown == true && isFunded == true){ return true, nil } } return false, nil } anyAttributeProfileIsFunded, err := checkIfAnyAttributeProfileIsFunded() if (err != nil) { return nil, err } if (anyAttributeProfileIsFunded == false){ continue } } reviewsInfoMap[reviewHash] = reviewedHash } return reviewsInfoMap, nil } reviewsInfoMap, err := getReviewsInfoMap() if (err != nil) { return nil, err } responseBytes, err := serverResponse.CreateServerResponse_GetIdentityReviewsInfo(myHostPublicIdentityKey, myHostPrivateIdentityKey, connectionKey, requestIdentifier, reviewsInfoMap) if (err != nil) { return nil, err } return responseBytes, nil } if (requestType == "GetMessageReviewsInfo"){ acceptableReviewVersions, requestRangeStart, requestRangeEnd, requestedReviewedMessageHashesList, requestedReviewersList, err := serverRequest.ReadDecryptedServerRequest_GetMessageReviewsInfo(decryptedRequestBytes) if (err != nil){ return invalidRequestResponse, nil } getReviewsInfoMap := func()(map[[29]byte][26]byte, error){ hostModeEnabled, hostingAnyInboxes, myInboxRangeStart, myInboxRangeEnd, err := myRanges.GetMyInboxesToHostRange() if (err != nil) { return nil, err } if (hostModeEnabled == false){ // Host mode must have been disabled recently reviewsInfoMap := make(map[[29]byte][26]byte) return reviewsInfoMap, nil } if (hostingAnyInboxes == false){ // We are not hosting any messages/ message reviews reviewsInfoMap := make(map[[29]byte][26]byte) return reviewsInfoMap, nil } getRelevantMessageHashesList := func()([][26]byte, error){ if (len(requestedReviewedMessageHashesList) != 0){ // We only want to return reviews that review message hashes that are within the requestedReviewedMessageHashesList return requestedReviewedMessageHashesList, nil } // We want to share reviews which review all reviewed message hashes // We will reduce based on requested range later allReviewedMessageHashesList, err := badgerDatabase.GetAllReviewedMessageHashes() if (err != nil) { return nil, err } return allReviewedMessageHashesList, nil } relevantMessageHashesList, err := getRelevantMessageHashesList() if (err != nil){ return nil, err } relevantReviewHashesList := make([][29]byte, 0) for _, messageHash := range relevantMessageHashesList{ anyExist, reviewHashesList, err := badgerDatabase.GetMessageReviewsList(messageHash) if (err != nil) { return nil, err } if (anyExist == true){ relevantReviewHashesList = append(relevantReviewHashesList, reviewHashesList...) } } // Map Structure: Review hash -> Reviewed message hash reviewsInfoMap := make(map[[29]byte][26]byte) for _, reviewHash := range relevantReviewHashesList{ reviewExists, reviewBytes, err := badgerDatabase.GetReview(reviewHash) if (err != nil) { return nil, err } if (reviewExists == false){ continue } ableToRead, currentReviewHash, reviewVersion, reviewNetworkType, reviewerIdentityHash, _, reviewType, reviewedHash, _, _, err := readReviews.ReadReviewAndHash(false, reviewBytes) if (err != nil) { return nil, err } if (ableToRead == false){ return nil, errors.New("Database corrupt: Contains invalid review.") } if (reviewHash != currentReviewHash){ return nil, errors.New("Database corrupt: Review entry key does not match review hash") } isAcceptableVersion := slices.Contains(acceptableReviewVersions, reviewVersion) if (isAcceptableVersion == false){ // Review is of a different version than requestor can accept // We must have a different Seekia app version than them. continue } if (reviewNetworkType != networkType){ // Review belongs to a different networkType continue } if (len(requestedReviewersList) != 0){ isInRequestedList := slices.Contains(requestedReviewersList, reviewerIdentityHash) if (isInRequestedList == false){ continue } } if (reviewType != "Message"){ return nil, errors.New("Database corrupt: Message reviews list contains non-message review") } // We will reduce the requested reviews based on requested inbox range if (len(reviewedHash) != 26){ reviewedHashHex := encoding.EncodeBytesToHexString(reviewedHash) return nil, errors.New("ReadReview returning invalid length reviewedHash for Message review: " + reviewedHashHex) } reviewedMessageHash := [26]byte(reviewedHash) metadataExists, _, messageNetworkType, _, messageInbox, _, err := contentMetadata.GetMessageMetadata(reviewedMessageHash) if (err != nil){ return nil, err } if (metadataExists == false){ // We cannot seed reviews for messages whose metadata we do not know continue } if (messageNetworkType != reviewNetworkType){ // The review author must be malicious continue } isWithinMyRange, err := byteRange.CheckIfInboxIsWithinRange(myInboxRangeStart, myInboxRangeEnd, messageInbox) if (err != nil) { return nil, err } if (isWithinMyRange == false){ continue } // We make sure message inbox is within requested inbox range isWithinRequestRange, err := byteRange.CheckIfInboxIsWithinRange(requestRangeStart, requestRangeEnd, messageInbox) if (err != nil) { return nil, err } if (isWithinRequestRange == false){ continue } // We make sure message is funded statusIsKnown, messageIsFunded, _, _, err := verifiedFundedStatus.GetVerifiedMessageIsFundedStatus(reviewedMessageHash) if (err != nil) { return nil, err } if (statusIsKnown == false || messageIsFunded == false){ continue } reviewsInfoMap[reviewHash] = reviewedMessageHash } return reviewsInfoMap, nil } reviewsInfoMap, err := getReviewsInfoMap() if (err != nil) { return nil, err } responseBytes, err := serverResponse.CreateServerResponse_GetMessageReviewsInfo(myHostPublicIdentityKey, myHostPrivateIdentityKey, connectionKey, requestIdentifier, reviewsInfoMap) if (err != nil) { return nil, err } return responseBytes, nil } if (requestType == "GetReviews"){ requestedReviewHashesList, err := serverRequest.ReadDecryptedServerRequest_GetReviews(decryptedRequestBytes) if (err != nil) { return nil, err } getReviewsListForResponse := func()([][]byte, error){ // We will reduce reviews to only our hosted range // This is done to prevent fingerprinting // We also make sure all reviewers, reviewed content, and reviewed identities are funded reviewsListForResponse := make([][]byte, 0) for _, reviewHash := range requestedReviewHashesList{ reviewExists, reviewBytes, err := badgerDatabase.GetReview(reviewHash) if (err != nil) { return nil, err } if (reviewExists == false){ continue } ableToRead, currentReviewHash, _, reviewNetworkType, reviewerIdentityHash, _, reviewType, reviewedHash, _, _, err := readReviews.ReadReviewAndHash(false, reviewBytes) if (err != nil) { return nil, err } if (ableToRead == false){ return nil, errors.New("Database corrupt: Contains invalid review.") } if (reviewHash != currentReviewHash){ return nil, errors.New("Database corrupt: Contains review with mismatched reviewHash entry key") } if (reviewNetworkType != networkType){ // Requestor must be malicious // They should only request reviews which we told them were on the connection networkType continue } statusIsKnown, _, scoreIsSufficient, _, _, err := moderatorScores.GetModeratorIdentityScore(reviewerIdentityHash) if (err != nil) { return nil, err } if (statusIsKnown == false || scoreIsSufficient == false){ continue } if (reviewType == "Message"){ if (len(reviewedHash) != 26){ reviewedHashHex := encoding.EncodeBytesToHexString(reviewedHash) return nil, errors.New("ReadReview returning invalid length reviewedHash for Message review: " + reviewedHashHex) } reviewedMessageHash := [26]byte(reviewedHash) metadataExists, _, messageNetworkType, _, messageInbox, _, err := contentMetadata.GetMessageMetadata(reviewedMessageHash) if (err != nil) { return nil, err } if (metadataExists == false){ // We cannot serve reviews whose reviewed content we do not have saved continue } if (messageNetworkType != reviewNetworkType){ // Review author must be malicious // We will not serve malicious reviews // Requestor must be malicious, because we would have already checked for this condition // before we offered this review to requestor continue } hostModeEnabled, isWithinMyRange, err := myRanges.CheckIfMessageInboxIsWithinMyHostedRange(messageInbox) if (err != nil) { return nil, err } if (hostModeEnabled == false){ // Host mode must have been disabled after earlier check. emptyList := make([][]byte, 0) return emptyList, nil } if (isWithinMyRange == false){ continue } statusIsKnown, messageIsFunded, _, _, err := verifiedFundedStatus.GetVerifiedMessageIsFundedStatus(reviewedMessageHash) if (err != nil) { return nil, err } if (statusIsKnown == false || messageIsFunded == false){ continue } } else { // reviewType == "Identity" or "Profile" or "Attribute" //Outputs: // -bool: Review is malicious // -bool: Identity hash is known // -[16]byte: Reviewed identity hash // -error getReviewedIdentityHash := func()(bool, bool, [16]byte, error){ if (reviewType == "Identity"){ if (len(reviewedHash) != 16){ reviewedHashHex := encoding.EncodeBytesToHexString(reviewedHash) return false, false, [16]byte{}, errors.New("ReadReview returning invalid length reviewedHash for Identity review: " + reviewedHashHex) } reviewedIdentityHash := [16]byte(reviewedHash) return false, true, reviewedIdentityHash, nil } if (reviewType == "Profile"){ if (len(reviewedHash) != 28){ reviewedHashHex := encoding.EncodeBytesToHexString(reviewedHash) return false, false, [16]byte{}, errors.New("ReadReview returning invalid length reviewedHash for Profile review: " + reviewedHashHex) } reviewedProfileHash := [28]byte(reviewedHash) metadataExists, _, profileNetworkType, profileAuthor, _, _, _, _, err := contentMetadata.GetProfileMetadata(reviewedProfileHash) if (err != nil) { return false, false, [16]byte{}, err } if (metadataExists == false){ return false, false, [16]byte{}, nil } if (profileNetworkType != reviewNetworkType){ // Review author must be malicious return true, false, [16]byte{}, nil } return false, true, profileAuthor, nil } if (reviewType == "Attribute"){ if (len(reviewedHash) != 27){ reviewedHashHex := encoding.EncodeBytesToHexString(reviewedHash) return false, false, [16]byte{}, errors.New("ReadReview returning invalid length reviewedHash for Attribute review: " + reviewedHashHex) } reviewedAttributeHash := [27]byte(reviewedHash) attributeMetadataFound, _, authorIdentityHash, attributeNetworkType, _, err := profileStorage.GetProfileAttributeMetadata(reviewedAttributeHash) if (err != nil) { return false, false, [16]byte{}, err } if (attributeMetadataFound == false){ return false, false, [16]byte{}, nil } if (attributeNetworkType != reviewNetworkType){ // The review is reviewing an attribute from a different networkType // The review author must be malicious return true, true, [16]byte{}, nil } return false, true, authorIdentityHash, nil } return false, false, [16]byte{}, errors.New("ReadReview returning invalid reviewType: " + reviewType) } reviewIsMalicious, metadataExists, reviewedIdentityHash, err := getReviewedIdentityHash() if (err != nil) { return nil, err } if (reviewIsMalicious == true){ // We will not serve malicious reviews // Requestor must be malicious, because we should have already checked for this before // offering a review hash in the Get...ReviewsInfo responses continue } if (metadataExists == false){ // We cannot seed reviews whose reviewed identity hash we do not know continue } hostModeEnabled, isInMyRange, err := myRanges.CheckIfIdentityHashIsWithinMyHostedRange(reviewedIdentityHash) if (err != nil) { return nil, err } if (hostModeEnabled == false){ // Host mode must have been disabled after earlier check. Return empty list. emptyList := make([][]byte, 0) return emptyList, nil } if (isInMyRange == false){ continue } // We make sure reviewed identity is funded reviewedIdentityType, err := identity.GetIdentityTypeFromIdentityHash(reviewedIdentityHash) if (err != nil) { return nil, err } if (reviewedIdentityType == "Moderator"){ statusIsKnown, _, scoreIsSufficient, _, _, err := moderatorScores.GetModeratorIdentityScore(reviewedIdentityHash) if (err != nil) { return nil, err } if (statusIsKnown == false || scoreIsSufficient == false){ continue } } else { // reviewedIdentityType == "Mate" or "Host" statusIsKnown, isFunded, _, _, err := verifiedFundedStatus.GetVerifiedIdentityIsFundedStatus(reviewedIdentityHash, networkType) if (err != nil) { return nil, err } if (statusIsKnown == false || isFunded == false){ continue } } if (reviewedIdentityType == "Mate" && reviewType == "Profile"){ // We make sure profile is funded if (len(reviewedHash) != 28){ reviewedHashHex := encoding.EncodeBytesToHexString(reviewedHash) return nil, errors.New("ReadReview returning invalid length reviewedHash for Profile review: " + reviewedHashHex) } reviewedProfileHash := [28]byte(reviewedHash) statusIsKnown, isFunded, _, _, err := verifiedFundedStatus.GetVerifiedMateProfileIsFundedStatus(reviewedProfileHash) if (err != nil) { return nil, err } if (statusIsKnown == false || isFunded == false){ continue } } else if (reviewedIdentityType == "Mate" && reviewType == "Attribute"){ // We make sure at least 1 profile with this attribute is funded checkIfAnyAttributeProfileIsFunded := func()(bool, error){ if (len(reviewedHash) != 27){ reviewedHashHex := encoding.EncodeBytesToHexString(reviewedHash) return false, errors.New("ReadReview returning invalid length reviewedHash for Attribute review: " + reviewedHashHex) } reviewedAttributeHash := [27]byte(reviewedHash) anyExist, attributeProfileHashesList, err := badgerDatabase.GetAttributeProfilesList(reviewedAttributeHash) if (err != nil) { return false, err } if (anyExist == false){ return false, nil } for _, profileHash := range attributeProfileHashesList{ statusIsKnown, isFunded, _, _, err := verifiedFundedStatus.GetVerifiedMateProfileIsFundedStatus(profileHash) if (err != nil) { return false, err } if (statusIsKnown == true && isFunded == true){ return true, nil } } return false, nil } anyAttributeProfileIsFunded, err := checkIfAnyAttributeProfileIsFunded() if (err != nil) { return nil, err } if (anyAttributeProfileIsFunded == false){ continue } } } reviewsListForResponse = append(reviewsListForResponse, reviewBytes) } return reviewsListForResponse, nil } reviewsListForResponse, err := getReviewsListForResponse() if (err != nil) { return nil, err } responseBytes, err := serverResponse.CreateServerResponse_GetReviews(myHostPublicIdentityKey, myHostPrivateIdentityKey, connectionKey, requestIdentifier, reviewsListForResponse) if (err != nil) { return nil, err } return responseBytes, nil } if (requestType == "GetIdentityReportsInfo"){ acceptableVersionsList, identityTypeToRetrieve, requestRangeStart, requestRangeEnd, requestedReportedIdentityHashesList, err := serverRequest.ReadDecryptedServerRequest_GetIdentityReportsInfo(decryptedRequestBytes) if (err != nil){ return invalidRequestResponse, nil } getReportsInfoMap := func()(map[[30]byte][]byte, error){ hostModeEnabled, hostingAny, myIdentityRangeStart, myIdentityRangeEnd, err := myRanges.GetMyIdentitiesToHostRange(identityTypeToRetrieve) if (err != nil) { return nil, err } if (hostModeEnabled == false){ // We must have turned off host mode recently reportsInfoMap := make(map[[30]byte][]byte) return reportsInfoMap, nil } if (hostingAny == false){ reportsInfoMap := make(map[[30]byte][]byte) return reportsInfoMap, nil } // We include identity, profile and attribute reports relevantReportHashesList := make([][30]byte, 0) allReportedIdentityHashesList, err := badgerDatabase.GetAllReportedIdentityHashes() if (err != nil) { return nil, err } for _, identityHash := range allReportedIdentityHashesList{ anyExist, reportHashesList, err := badgerDatabase.GetIdentityReportsList(identityHash) if (err != nil) { return nil, err } if (anyExist == true){ relevantReportHashesList = append(relevantReportHashesList, reportHashesList...) } } allReportedProfileHashesList, err := badgerDatabase.GetAllReportedProfileHashes() if (err != nil) { return nil, err } for _, profileHash := range allReportedProfileHashesList{ anyExist, reportHashesList, err := badgerDatabase.GetProfileReportsList(profileHash) if (err != nil) { return nil, err } if (anyExist == true){ relevantReportHashesList = append(relevantReportHashesList, reportHashesList...) } } allReportedAttributeHashesList, err := badgerDatabase.GetAllReportedProfileAttributeHashes() if (err != nil) { return nil, err } for _, attributeHash := range allReportedAttributeHashesList{ anyExist, reportHashesList, err := badgerDatabase.GetProfileAttributeReportsList(attributeHash) if (err != nil) { return nil, err } if (anyExist == true){ relevantReportHashesList = append(relevantReportHashesList, reportHashesList...) } } // Map Structure: Report Hash -> Reported Hash reportsInfoMap := make(map[[30]byte][]byte) for _, reportHash := range relevantReportHashesList{ statusIsKnown, reportIsFunded, _, _, err := verifiedFundedStatus.GetVerifiedReportIsFundedStatus(reportHash) if (err != nil) { return nil, err } if (statusIsKnown == false || reportIsFunded == false){ continue } reportExists, reportBytes, err := badgerDatabase.GetReport(reportHash) if (err != nil) { return nil, err } if (reportExists == false){ continue } ableToRead, currentReportHash, reportVersion, reportNetworkType, _, reportType, reportedHash, _, err := readReports.ReadReportAndHash(false, reportBytes) if (err != nil) { return nil, err } if (ableToRead == false){ return nil, errors.New("Database corrupt: Contains invalid report.") } if (reportHash != currentReportHash){ return nil, errors.New("Database corrupt: Report entry key does not match report hash") } isAcceptableVersion := slices.Contains(acceptableVersionsList, reportVersion) if (isAcceptableVersion == false){ // This report is of a version that the requestor cannot accept // We must be running a different version of Seekia than them. continue } if (reportNetworkType != networkType){ // Report belongs to a different networkType continue } //Outputs: // -bool: Report is malicious // -bool: Metadata exists // -[16]byte: Reported identity hash // -error getReportedIdentityHash := func()(bool, bool, [16]byte, error){ if (reportType == "Identity"){ if (len(reportedHash) != 16){ reportedHashHex := encoding.EncodeBytesToHexString(reportedHash) return false, false, [16]byte{}, errors.New("ReadReport returning invalid length reportedHash for Identity report: " + reportedHashHex) } reportedIdentityHash := [16]byte(reportedHash) return false, true, reportedIdentityHash, nil } if (reportType == "Profile"){ if (len(reportedHash) != 28){ reportedHashHex := encoding.EncodeBytesToHexString(reportedHash) return false, false, [16]byte{}, errors.New("ReadReport returning invalid length reportedHash for Profile report: " + reportedHashHex) } reportedProfileHash := [28]byte(reportedHash) metadataExists, _, profileNetworkType, profileAuthor, _, _, _, _, err := contentMetadata.GetProfileMetadata(reportedProfileHash) if (err != nil) { return false, false, [16]byte{}, err } if (metadataExists == false){ return false, false, [16]byte{}, nil } if (profileNetworkType != reportNetworkType){ // Report author must be malicious // Report is reporting a profile on a different network return true, false, [16]byte{}, nil } return false, true, profileAuthor, nil } if (reportType == "Attribute"){ if (len(reportedHash) != 27){ reportedHashHex := encoding.EncodeBytesToHexString(reportedHash) return false, false, [16]byte{}, errors.New("ReadReport returning invalid length reportedHash for Attribute report: " + reportedHashHex) } reportedAttributeHash := [27]byte(reportedHash) metadataExists, _, authorIdentityHash, attributeNetworkType, _, err := profileStorage.GetProfileAttributeMetadata(reportedAttributeHash) if (err != nil){ return false, false, [16]byte{}, err } if (metadataExists == false){ return false, false, [16]byte{}, nil } if (attributeNetworkType != networkType){ // Report author must be malicious // Report is reporting an attribute on a different network return true, false, [16]byte{}, nil } return false, true, authorIdentityHash, nil } return false, false, [16]byte{}, errors.New("getReportedIdentityHash reached with invalid reportType: " + reportType) } reportIsMalicious, metadataExists, reportedIdentityHash, err := getReportedIdentityHash() if (err != nil) { return nil, err } if (reportIsMalicious == true){ // We will not serve malicious reports continue } if (metadataExists == false){ // We cannot serve reports whose reported author we do not know. continue } reportedIdentityType, err := identity.GetIdentityTypeFromIdentityHash(reportedIdentityHash) if (err != nil){ return nil, err } if (reportedIdentityType != identityTypeToRetrieve){ continue } if (len(requestedReportedIdentityHashesList) != 0){ // We will find report hashes from requested reportedHashes list isWithinList := slices.Contains(requestedReportedIdentityHashesList, reportedIdentityHash) if (isWithinList == false){ continue } } else { // We make sure reported identity is within requested range identityIsInRequestRange, err := byteRange.CheckIfIdentityHashIsWithinRange(requestRangeStart, requestRangeEnd, reportedIdentityHash) if (err != nil) { return nil, err } if (identityIsInRequestRange == false){ continue } } // We make sure identity is within our range identityIsInMyRange, err := byteRange.CheckIfIdentityHashIsWithinRange(myIdentityRangeStart, myIdentityRangeEnd, reportedIdentityHash) if (err != nil) { return nil, err } if (identityIsInMyRange == false){ continue } // We make sure that the profile/identity being reported is funded if (reportedIdentityType == "Moderator"){ statusIsKnown, _, scoreIsSufficient, _, _, err := moderatorScores.GetModeratorIdentityScore(reportedIdentityHash) if (err != nil) { return nil, err } if (statusIsKnown == false || scoreIsSufficient == false){ continue } } else { // reviewedIdentityType == "Mate" or "Host" statusIsKnown, isFunded, _, _, err := verifiedFundedStatus.GetVerifiedIdentityIsFundedStatus(reportedIdentityHash, networkType) if (err != nil) { return nil, err } if (statusIsKnown == false || isFunded == false){ continue } } if (reportedIdentityType == "Mate" && reportType == "Profile"){ // We make sure profile is funded if (len(reportedHash) != 28){ reportedHashHex := encoding.EncodeBytesToHexString(reportedHash) return nil, errors.New("ReadReport returning invalid length reportedHash for Profile report: " + reportedHashHex) } reportedProfileHash := [28]byte(reportedHash) statusIsKnown, isFunded, _, _, err := verifiedFundedStatus.GetVerifiedMateProfileIsFundedStatus(reportedProfileHash) if (err != nil) { return nil, err } if (statusIsKnown == false || isFunded == false){ continue } } else if (reportedIdentityType == "Mate" && reportType == "Attribute"){ // We make sure at least 1 profile with this attribute is funded checkIfAnyAttributeProfileIsFunded := func()(bool, error){ if (len(reportedHash) != 27){ reportedHashHex := encoding.EncodeBytesToHexString(reportedHash) return false, errors.New("ReadReport returning invalid length reportedHash for Attribute report: " + reportedHashHex) } reportedAttributeHash := [27]byte(reportedHash) anyExist, attributeProfileHashesList, err := badgerDatabase.GetAttributeProfilesList(reportedAttributeHash) if (err != nil) { return false, err } if (anyExist == false){ return false, nil } for _, profileHash := range attributeProfileHashesList{ statusIsKnown, isFunded, _, _, err := verifiedFundedStatus.GetVerifiedMateProfileIsFundedStatus(profileHash) if (err != nil) { return false, err } if (statusIsKnown == true && isFunded == true){ return true, nil } } return false, nil } anyAttributeProfileIsFunded, err := checkIfAnyAttributeProfileIsFunded() if (err != nil) { return nil, err } if (anyAttributeProfileIsFunded == false){ continue } } reportsInfoMap[reportHash] = reportedHash } return reportsInfoMap, nil } reportsInfoMap, err := getReportsInfoMap() if (err != nil) { return nil, err } responseBytes, err := serverResponse.CreateServerResponse_GetIdentityReportsInfo(myHostPublicIdentityKey, myHostPrivateIdentityKey, connectionKey, requestIdentifier, reportsInfoMap) if (err != nil) { return nil, err } return responseBytes, nil } if (requestType == "GetMessageReportsInfo"){ acceptableVersionsList, requestRangeStart, requestRangeEnd, requestedReportedMessageHashesList, err := serverRequest.ReadDecryptedServerRequest_GetMessageReportsInfo(decryptedRequestBytes) if (err != nil){ return invalidRequestResponse, nil } getReportsInfoMap := func()(map[[30]byte][26]byte, error){ hostModeEnabled, hostingAnyInboxes, myInboxRangeStart, myInboxRangeEnd, err := myRanges.GetMyInboxesToHostRange() if (err != nil) { return nil, err } if (hostModeEnabled == false){ // We must have disabled host mode recently reportsInfoMap := make(map[[30]byte][26]byte) return reportsInfoMap, nil } if (hostingAnyInboxes == false){ // We are not hosting any messages/ message reports reportsInfoMap := make(map[[30]byte][26]byte) return reportsInfoMap, nil } getRelevantMessageHashesList := func()([][26]byte, error){ if (len(requestedReportedMessageHashesList) != 0){ // We will get reports from requested message hashes list return requestedReportedMessageHashesList, nil } allReportedMessageHashesList, err := badgerDatabase.GetAllReportedMessageHashes() if (err != nil) { return nil, err } return allReportedMessageHashesList, nil } relevantMessageHashesList, err := getRelevantMessageHashesList() if (err != nil) { return nil, err } relevantReportHashesList := make([][30]byte, 0) for _, messageHash := range relevantMessageHashesList{ anyExist, reportHashesList, err := badgerDatabase.GetMessageReportsList(messageHash) if (err != nil) { return nil, err } if (anyExist == true){ relevantReportHashesList = append(relevantReportHashesList, reportHashesList...) } } // Map Structure: Report Hash -> Reported Message Hash reportsInfoMap := make(map[[30]byte][26]byte) for _, reportHash := range relevantReportHashesList{ statusIsKnown, reportIsFunded, _, _, err := verifiedFundedStatus.GetVerifiedReportIsFundedStatus(reportHash) if (err != nil) { return nil, err } if (statusIsKnown == false || reportIsFunded == false){ continue } reportExists, reportBytes, err := badgerDatabase.GetReport(reportHash) if (err != nil) { return nil, err } if (reportExists == false){ continue } ableToRead, currentReportHash, reportVersion, reportNetworkType, _, reportType, reportedHash, _, err := readReports.ReadReportAndHash(false, reportBytes) if (err != nil) { return nil, err } if (ableToRead == false){ return nil, errors.New("Database corrupt: Contains invalid report.") } if (reportHash != currentReportHash){ return nil, errors.New("Database corrupt: Report entry key does not match report hash") } if (reportType != "Message"){ return nil, errors.New("Database corrupt: Message reports list contains non-message report") } if (len(reportedHash) != 26){ reportedHashHex := encoding.EncodeBytesToHexString(reportedHash) return nil, errors.New("ReadReport returning invalid length reportedHash for Message report: " + reportedHashHex) } reportedMessageHash := [26]byte(reportedHash) isAcceptableVersion := slices.Contains(acceptableVersionsList, reportVersion) if (isAcceptableVersion == false){ // This report is of a version that the requestor cannot accept // We must be running a different version of Seekia than them. continue } if (reportNetworkType != networkType){ // Report belongs to a different networkType continue } metadataExists, _, messageNetworkType, _, messageInbox, _, err := contentMetadata.GetMessageMetadata(reportedMessageHash) if (err != nil) { return nil, err } if (metadataExists == false){ // We cannot seed reports for messages whose metadata we do not know continue } if (messageNetworkType != networkType){ // Report author must be malicious // They have created a report for a message belonging to a different networkType continue } isWithinMyRange, err := byteRange.CheckIfInboxIsWithinRange(myInboxRangeStart, myInboxRangeEnd, messageInbox) if (err != nil) { return nil, err } if (isWithinMyRange == false){ continue } // We reduce the requested reports based on requested inbox range isWithinRequestRange, err := byteRange.CheckIfInboxIsWithinRange(requestRangeStart, requestRangeEnd, messageInbox) if (err != nil) { return nil, err } if (isWithinRequestRange == false){ continue } // We make sure message is funded statusIsKnown, messageIsFunded, _, _, err := verifiedFundedStatus.GetVerifiedMessageIsFundedStatus(reportedMessageHash) if (err != nil) { return nil, err } if (statusIsKnown == false || messageIsFunded == false){ continue } reportsInfoMap[reportHash] = reportedMessageHash } return reportsInfoMap, nil } reportsInfoMap, err := getReportsInfoMap() if (err != nil) { return nil, err } responseBytes, err := serverResponse.CreateServerResponse_GetMessageReportsInfo(myHostPublicIdentityKey, myHostPrivateIdentityKey, connectionKey, requestIdentifier, reportsInfoMap) if (err != nil) { return nil, err } return responseBytes, nil } if (requestType == "GetReports"){ requestedReportHashesList, err := serverRequest.ReadDecryptedServerRequest_GetReports(decryptedRequestBytes) if (err != nil) { return nil, err } getReportsListForResponse := func()([][]byte, error){ // We will reduce report list to only include reports within our hosted range // This is done to prevent fingerprinting // We also make sure reported identities/profiles/messages are funded reportsListForResponse := make([][]byte, 0) for _, reportHash := range requestedReportHashesList{ reportExists, reportBytes, err := badgerDatabase.GetReport(reportHash) if (err != nil) { return nil, err } if (reportExists == false){ continue } ableToRead, currentReportHash, _, reportNetworkType, _, reportType, reportedHash, _, err := readReports.ReadReportAndHash(false, reportBytes) if (err != nil) { return nil, err } if (ableToRead == false){ return nil, errors.New("Database corrupt: Contains invalid report.") } if (reportHash != currentReportHash){ return nil, errors.New("Database corrupt: Contains report with mismatched reportHash entry key") } if (reportNetworkType != networkType){ // Requestor must be malicious // They should only request reports which we offered them // We will only have offered them reports on the current networkType continue } if (reportType == "Message"){ if (len(reportedHash) != 26){ reportedHashHex := encoding.EncodeBytesToHexString(reportedHash) return nil, errors.New("ReadReport returning invalid length reportedHash for Message report: " + reportedHashHex) } reportedMessageHash := [26]byte(reportedHash) metadataExists, _, messageNetworkType, _, messageInbox, _, err := contentMetadata.GetMessageMetadata(reportedMessageHash) if (err != nil){ return nil, err } if (metadataExists == false){ // We cannot host reports for messages whose metadata we do not have. continue } if (messageNetworkType != networkType){ // This should not happen because we would have already checked for this before serving report info to requestor // Requestor must be maliciously requesting reports we never offered them continue } hostModeEnabled, isWithinMyRange, err := myRanges.CheckIfMessageInboxIsWithinMyHostedRange(messageInbox) if (err != nil) { return nil, err } if (hostModeEnabled == false){ // Host mode must have been disabled after earlier check. Return empty list. emptyList := make([][]byte, 0) return emptyList, nil } if (isWithinMyRange == false){ continue } // We make sure message is funded statusIsKnown, messageIsFunded, _, _, err := verifiedFundedStatus.GetVerifiedMessageIsFundedStatus(reportedMessageHash) if (err != nil) { return nil, err } if (statusIsKnown == false || messageIsFunded == false){ continue } } else { // reportType == "Identity" or "Profile" or "Attribute" //Outputs: // -bool: Report is malicious // -bool: Reported identity hash found // -[16]byte: Reported identity hash // -error getReportedIdentityHash := func()(bool, bool, [16]byte, error){ if (reportType == "Identity"){ if (len(reportedHash) != 16){ reportedHashHex := encoding.EncodeBytesToHexString(reportedHash) return false, false, [16]byte{}, errors.New("ReadReport returning invalid length reportedHash for Identity report: " + reportedHashHex) } reportedIdentityHash := [16]byte(reportedHash) return false, true, reportedIdentityHash, nil } if (reportType == "Profile"){ if (len(reportedHash) != 28){ reportedHashHex := encoding.EncodeBytesToHexString(reportedHash) return false, false, [16]byte{}, errors.New("ReadReport returning invalid length reportedHash for Profile report: " + reportedHashHex) } reportedProfileHash := [28]byte(reportedHash) metadataExists, _, profileNetworkType, profileAuthor, _, _, _, _, err := contentMetadata.GetProfileMetadata(reportedProfileHash) if (err != nil) { return false, false, [16]byte{}, err } if (metadataExists == false){ return false, false, [16]byte{}, nil } if (profileNetworkType != networkType){ return true, false, [16]byte{}, nil } return false, true, profileAuthor, nil } if (reportType == "Attribute"){ if (len(reportedHash) != 27){ reportedHashHex := encoding.EncodeBytesToHexString(reportedHash) return false, false, [16]byte{}, errors.New("ReadReport returning invalid length reportedHash for Attribute report: " + reportedHashHex) } reportedAttributeHash := [27]byte(reportedHash) metadataExists, _, authorIdentityHash, attributeNetworkType, _, err := profileStorage.GetProfileAttributeMetadata(reportedAttributeHash) if (err != nil){ return false, false, [16]byte{}, err } if (metadataExists == false){ return false, false, [16]byte{}, nil } if (attributeNetworkType != networkType){ return true, false, [16]byte{}, nil } return false, true, authorIdentityHash, nil } return false, false, [16]byte{}, errors.New("ReadReport returning invalid reportType: " + reportType) } reportIsMalicious, metadataExists, reportedIdentityHash, err := getReportedIdentityHash() if (err != nil) { return nil, err } if (reportIsMalicious == true){ // The requestor must be malicious, because we should have already checked for this condition // before serving this report hash in our Get...ReportsInfo responses. continue } if (metadataExists == false){ // We cannot seed a report whose reported identity hash we do not know continue } // We make sure identity is within our hosted range hostModeEnabled, isInMyRange, err := myRanges.CheckIfIdentityHashIsWithinMyHostedRange(reportedIdentityHash) if (err != nil) { return nil, err } if (hostModeEnabled == false){ // Host mode must have been disabled after earlier check. Return empty list. emptyList := make([][]byte, 0) return emptyList, nil } if (isInMyRange == false){ continue } // We make sure identity is funded reportedIdentityType, err := identity.GetIdentityTypeFromIdentityHash(reportedIdentityHash) if (err != nil){ return nil, err } if (reportedIdentityType == "Moderator"){ statusIsKnown, _, scoreIsSufficient, _, _, err := moderatorScores.GetModeratorIdentityScore(reportedIdentityHash) if (err != nil) { return nil, err } if (statusIsKnown == false || scoreIsSufficient == false){ continue } } else { // reportedIdentityType == "Mate" or "Host" statusIsKnown, isFunded, _, _, err := verifiedFundedStatus.GetVerifiedIdentityIsFundedStatus(reportedIdentityHash, networkType) if (err != nil) { return nil, err } if (statusIsKnown == false || isFunded == false){ continue } } if (reportedIdentityType == "Mate" && reportType == "Profile"){ // We make sure profile is funded if (len(reportedHash) != 28){ reportedHashHex := encoding.EncodeBytesToHexString(reportedHash) return nil, errors.New("ReadReport returning invalid length reportedHash for Profile report: " + reportedHashHex) } reportedProfileHash := [28]byte(reportedHash) statusIsKnown, isFunded, _, _, err := verifiedFundedStatus.GetVerifiedMateProfileIsFundedStatus(reportedProfileHash) if (err != nil) { return nil, err } if (statusIsKnown == false || isFunded == false){ continue } } else if (reportedIdentityType == "Mate" && reportType == "Attribute"){ // We make sure at least 1 profile with this attribute is funded if (len(reportedHash) != 27){ reportedHashHex := encoding.EncodeBytesToHexString(reportedHash) return nil, errors.New("ReadReport returning invalid length reportedHash for Attribute report: " + reportedHashHex) } reportedAttributeHash := [27]byte(reportedHash) checkIfAnyAttributeProfileIsFunded := func()(bool, error){ anyExist, attributeProfileHashesList, err := badgerDatabase.GetAttributeProfilesList(reportedAttributeHash) if (err != nil) { return false, err } if (anyExist == false){ return false, nil } for _, profileHash := range attributeProfileHashesList{ statusIsKnown, isFunded, _, _, err := verifiedFundedStatus.GetVerifiedMateProfileIsFundedStatus(profileHash) if (err != nil) { return false, err } if (statusIsKnown == true && isFunded == true){ return true, nil } } return false, nil } anyAttributeProfileIsFunded, err := checkIfAnyAttributeProfileIsFunded() if (err != nil) { return nil, err } if (anyAttributeProfileIsFunded == false){ continue } } } reportsListForResponse = append(reportsListForResponse, reportBytes) } return reportsListForResponse, nil } reportsListForResponse, err := getReportsListForResponse() if (err != nil) { return nil, err } responseBytes, err := serverResponse.CreateServerResponse_GetReports(myHostPublicIdentityKey, myHostPrivateIdentityKey, connectionKey, requestIdentifier, reportsListForResponse) if (err != nil) { return nil, err } return responseBytes, nil } if (requestType == "GetViewableStatuses"){ requestedIdentityHashesList, requestedProfileHashesList, err := serverRequest.ReadDecryptedServerRequest_GetViewableStatuses(decryptedRequestBytes) if (err != nil){ return invalidRequestResponse, nil } getIdentityHashStatusesMap := func()(map[[16]byte]bool, error){ // Map Structure: Identity Hash -> Is Viewable status identityHashStatusesMap := make(map[[16]byte]bool) for _, userIdentityHash := range requestedIdentityHashesList{ hostModeEnabled, isWithinMyRange, err := myRanges.CheckIfIdentityHashIsWithinMyHostedRange(userIdentityHash) if (err != nil) { return nil, err } if (hostModeEnabled == false){ // Host mode has been disabled. We return empty response. emptyMap := make(map[[16]byte]bool) return emptyMap, nil } if (isWithinMyRange == false){ continue } // We make sure identity is funded userIdentityType, err := identity.GetIdentityTypeFromIdentityHash(userIdentityHash) if (err != nil) { return nil, err } if (userIdentityType == "Moderator"){ statusIsKnown, _, scoreIsSufficient, _, _, err := moderatorScores.GetModeratorIdentityScore(userIdentityHash) if (err != nil) { return nil, err } if (statusIsKnown == false || scoreIsSufficient == false){ continue } } else { // userIdentityType == "Mate" or "Host" statusIsKnown, isFunded, _, _, err := verifiedFundedStatus.GetVerifiedIdentityIsFundedStatus(userIdentityHash, networkType) if (err != nil) { return nil, err } if (statusIsKnown == false || isFunded == false){ continue } } downloadingRequiredReviews, parametersExist, stickyStatusEstablished, identityIsViewableStatus, err := verifiedStickyStatus.GetVerifiedIdentityIsViewableStickyStatus(userIdentityHash, networkType) if (err != nil) { return nil, err } if (downloadingRequiredReviews == false){ continue } if (parametersExist == false){ // Host needs to download required moderation parameters to know sticky consensuses. // We skip identities. break } if (stickyStatusEstablished == false){ continue } identityHashStatusesMap[userIdentityHash] = identityIsViewableStatus } return identityHashStatusesMap, nil } identityHashStatusesMap, err := getIdentityHashStatusesMap() if (err != nil) { return nil, err } getProfileHashStatusesMap := func()(map[[28]byte]bool, error){ // Map Structure: Profile Hash -> Is Viewable status profileHashStatusesMap := make(map[[28]byte]bool) for _, profileHash := range requestedProfileHashesList{ profileIsDisabled, profileMetadataIsKnown, profileNetworkType, profileAuthor, downloadingRequiredReviews, parametersFound, stickyStatusEstablished, profileIsViewableStatus, err := verifiedStickyStatus.GetVerifiedProfileIsViewableStickyStatus(profileHash) if (err != nil) { return nil, err } if (profileMetadataIsKnown == false){ // We don't know profile author, so we cannot check if author is banned, or if profile is banned. // We don't know sticky status. We skip profile. continue } if (profileNetworkType != networkType){ // Requestor must be malicious // They should only request viewable statuses for profiles on our networkType continue } if (profileIsDisabled == false){ if (downloadingRequiredReviews == false){ continue } if (parametersFound == false){ // Host needs to download required network parameters to host sticky consensuses. // We skip all profiles. break } if (stickyStatusEstablished == false){ continue } } hostModeEnabled, isWithinMyRange, err := myRanges.CheckIfIdentityHashIsWithinMyHostedRange(profileAuthor) if (err != nil) { return nil, err } if (hostModeEnabled == false){ // Host mode has been disabled. Return empty response. emptyMap := make(map[[28]byte]bool) return emptyMap, nil } if (isWithinMyRange == false){ continue } // We make sure identity is funded profileIdentityType, err := identity.GetIdentityTypeFromIdentityHash(profileAuthor) if (err != nil){ return nil, err } if (profileIdentityType == "Moderator"){ statusIsKnown, _, scoreIsSufficient, _, _, err := moderatorScores.GetModeratorIdentityScore(profileAuthor) if (err != nil) { return nil, err } if (statusIsKnown == false || scoreIsSufficient == false){ continue } } else { // profileIdentityType == "Mate" or "Host" statusIsKnown, isFunded, _, _, err := verifiedFundedStatus.GetVerifiedIdentityIsFundedStatus(profileAuthor, networkType) if (err != nil) { return nil, err } if (statusIsKnown == false || isFunded == false){ continue } } // If profile is Mate, we make sure it is funded if (profileIdentityType == "Mate"){ statusIsKnown, isFunded, _, _, err := verifiedFundedStatus.GetVerifiedMateProfileIsFundedStatus(profileHash) if (err != nil) { return nil, err } if (statusIsKnown == false || isFunded == false){ continue } } if (profileIsDisabled == false && profileIsViewableStatus == false){ // Profile is unviewable profileHashStatusesMap[profileHash] = false continue } // Profile is viewable // Now we check to make sure identity is not banned downloadingRequiredReviews, parametersExist, stickyStatusEstablished, identityIsViewableStatus, err := verifiedStickyStatus.GetVerifiedIdentityIsViewableStickyStatus(profileAuthor, networkType) if (err != nil) { return nil, err } if (downloadingRequiredReviews == false){ continue } if (parametersExist == false){ // Host needs to download required moderation parameters to host sticky consensuses. // We skip identity hashes for now. break } if (stickyStatusEstablished == false){ continue } profileHashStatusesMap[profileHash] = identityIsViewableStatus } return profileHashStatusesMap, nil } profileHashStatusesMap, err := getProfileHashStatusesMap() if (err != nil) { return nil, err } responseBytes, err := serverResponse.CreateServerResponse_GetViewableStatuses(myHostPublicIdentityKey, myHostPrivateIdentityKey, connectionKey, requestIdentifier, identityHashStatusesMap, profileHashStatusesMap) if (err != nil) { return nil, err } return responseBytes, nil } if (requestType == "BroadcastContent"){ contentTypeToBroadcast, contentBytesList, err := serverRequest.ReadDecryptedServerRequest_BroadcastContent(decryptedRequestBytes) if (err != nil){ return invalidRequestResponse, nil } // Map Structure: Content Hash -> We will accept and host contentAcceptedInfoMap := make(map[string]bool) // If host mode is disabled during this process, we will set this bool to true // If true, we will return an response which has contentAccepted = "No" for all content hashes hostModeDisabled := false for _, contentBytes := range contentBytesList{ if (contentTypeToBroadcast == "Parameters"){ ableToRead, parametersHash, _, parametersNetworkType, _, _, _, _, err := readParameters.ReadParametersAndHash(false, contentBytes) if (err != nil) { return nil, err } if (ableToRead == false){ return nil, errors.New("ReadDecryptedServerRequest_BroadcastContent not verifying parameters are valid") } if (parametersNetworkType != networkType){ // Requestor must be malicious // They should only broadcast content which belongs to our networkType. contentAcceptedInfoMap[string(parametersHash[:])] = false continue } //TODO: Check if we are hosting parameters contentAcceptedInfoMap[string(parametersHash[:])] = true _, _, err = parametersStorage.AddParameters(contentBytes) if (err != nil) { return nil, err } continue } if (contentTypeToBroadcast == "Message"){ ableToRead, messageHash, _, messageNetworkType, messageInbox, _, _, _, _, _, _, err := readMessages.ReadChatMessagePublicDataAndHash(false, contentBytes) if (err != nil){ return nil, errors.New("ReadDecryptedServerRequest_BroadcastContent not verifying message is valid") } if (ableToRead == false){ return nil, errors.New("ReadDecryptedServerRequest_BroadcastContent not verifying message is valid") } if (messageNetworkType != networkType){ // Requestor must be malicious // They should only broadcast content which belongs to our networkType. contentAcceptedInfoMap[string(messageHash[:])] = false continue } hostModeEnabled, isWithinMyRange, err := myRanges.CheckIfMessageInboxIsWithinMyHostedRange(messageInbox) if (err != nil) { return nil, err } if (hostModeEnabled == false){ hostModeDisabled = true contentAcceptedInfoMap[string(messageHash[:])] = false continue } contentAcceptedInfoMap[string(messageHash[:])] = isWithinMyRange if (isWithinMyRange == true){ // We add message to database messageIsWellFormed, err := chatMessageStorage.AddMessage(contentBytes) if (err != nil) { return nil, err } if (messageIsWellFormed == false){ return nil, errors.New("AddMessage not verifying message the same way ReadChatMessagePublicData is") } } continue } if (contentTypeToBroadcast == "Profile"){ ableToRead, profileHash, _, profileNetworkType, profileAuthor, _, _, _, err := readProfiles.ReadProfileAndHash(false, contentBytes) if (err != nil) { return nil, err } if (ableToRead == false){ return nil, errors.New("ReadDecryptedServerRequest_BroadcastContent not verifying profile is valid.") } if (profileNetworkType != networkType){ // Requestor must be malicious // They should only broadcast content which belongs to our networkType. contentAcceptedInfoMap[string(profileHash[:])] = false continue } hostModeEnabled, isWithinMyRange, err := myRanges.CheckIfIdentityHashIsWithinMyHostedRange(profileAuthor) if (err != nil) { return nil, err } if (hostModeEnabled == false){ hostModeDisabled = true contentAcceptedInfoMap[string(profileHash[:])] = false continue } contentAcceptedInfoMap[string(profileHash[:])] = isWithinMyRange if (isWithinMyRange == true){ // We add profile to database profileIsWellFormed, addedProfileHash, err := profileStorage.AddUserProfile(contentBytes) if (err != nil){ return nil, err } if (profileIsWellFormed == false){ return nil, errors.New("AddUserProfile not verifying profile the same way ReadProfile is") } if (addedProfileHash != profileHash){ return nil, errors.New("AddUserProfile returning mismatched profile hash") } } continue } if (contentTypeToBroadcast == "Review"){ ableToRead, reviewHash, _, reviewNetworkType, _, _, reviewType, reviewedHash, _, _, err := readReviews.ReadReviewAndHash(false, contentBytes) if (err != nil) { return nil, err } if (ableToRead == false){ return nil, errors.New("ReadDecryptedServerRequest_BroadcastContent not verifying review is valid.") } if (reviewNetworkType != networkType){ // Requestor must be malicious // They should only broadcast content which belongs to our networkType. contentAcceptedInfoMap[string(reviewHash[:])] = false continue } //Outputs: // -bool: Host mode is enabled // -bool: We will host review // -error checkIfWeWillHostReview := func()(bool, bool, error){ if (reviewType == "Message"){ if (len(reviewedHash) != 26){ reviewedHashHex := encoding.EncodeBytesToHexString(reviewedHash) return false, false, errors.New("ReadReview returning invalid length reviewedHash for Message review: " + reviewedHashHex) } reviewedMessageHash := [26]byte(reviewedHash) metadataExists, _, messageNetworkType, _, messageInbox, _, err := contentMetadata.GetMessageMetadata(reviewedMessageHash) if (err != nil) { return false, false, err } if (metadataExists == false){ // We cannot accept reviews for messages whose metadata we do not know // This is because we cannot seed reviews for messages whose metadata we do not know return true, false, nil } if (messageNetworkType != reviewNetworkType){ // The review is reviewing a message from a different network type // It is a malicious review. We will not host it. return true, false, nil } hostModeEnabled, isWithinMyRange, err := myRanges.CheckIfMessageInboxIsWithinMyHostedRange(messageInbox) if (err != nil) { return false, false, err } return hostModeEnabled, isWithinMyRange, nil } // reviewType == "Identity" or "Profile" or "Attribute" //Outputs: // -bool: Reviewed identity hash is known // -bool: Review is malicious // -[16]byte: Reviewed identity hash // -error getReviewedIdentityHash := func()(bool, bool, [16]byte, error){ if (reviewType == "Identity"){ if (len(reviewedHash) != 16){ reviewedHashHex := encoding.EncodeBytesToHexString(reviewedHash) return false, false, [16]byte{}, errors.New("ReadReview returning invalid length reviewedHash for Identity review: " + reviewedHashHex) } reviewedIdentityHash := [16]byte(reviewedHash) return true, false, reviewedIdentityHash, nil } if (reviewType == "Profile"){ if (len(reviewedHash) != 28){ reviewedHashHex := encoding.EncodeBytesToHexString(reviewedHash) return false, false, [16]byte{}, errors.New("ReadReview returning invalid length reviewedHash for Profile review: " + reviewedHashHex) } reviewedProfileHash := [28]byte(reviewedHash) metadataExists, _, profileNetworkType, reviewedProfileAuthor, _, _, _, _, err := contentMetadata.GetProfileMetadata(reviewedProfileHash) if (err != nil) { return false, false, [16]byte{}, err } if (metadataExists == false){ return false, false, [16]byte{}, nil } if (profileNetworkType != reviewNetworkType){ // Review is reviewing a profile from a different network type // Review and author of review are malicious return true, true, [16]byte{}, nil } return true, false, reviewedProfileAuthor, nil } if (reviewType == "Attribute"){ if (len(reviewedHash) != 27){ reviewedHashHex := encoding.EncodeBytesToHexString(reviewedHash) return false, false, [16]byte{}, errors.New("ReadReview returning invalid length reviewedHash for Attribute review: " + reviewedHashHex) } reviewedAttributeHash := [27]byte(reviewedHash) metadataExists, _, authorIdentityHash, attributeNetworkType, _, err := profileStorage.GetProfileAttributeMetadata(reviewedAttributeHash) if (err != nil) { return false, false, [16]byte{}, err } if (metadataExists == false){ return false, false, [16]byte{}, nil } if (attributeNetworkType != reviewNetworkType){ // Review is reviewing an attribute from a different network type // Review and author of review are malicious return true, true, [16]byte{}, nil } return true, false, authorIdentityHash, nil } return false, false, [16]byte{}, errors.New("ReadReview returning invalid reviewType: " + reviewType) } reviewedIdentityHashIsKnown, reviewIsMalicious, reviewedIdentityHash, err := getReviewedIdentityHash() if (err != nil) { return false, false, err } if (reviewedIdentityHashIsKnown == false){ return true, false, nil } if (reviewIsMalicious == true){ return true, false, nil } hostModeEnabled, isWithinMyRange, err := myRanges.CheckIfIdentityHashIsWithinMyHostedRange(reviewedIdentityHash) if (err != nil) { return false, false, err } return hostModeEnabled, isWithinMyRange, nil } hostModeIsEnabled, weWillHostReview, err := checkIfWeWillHostReview() if (err != nil) { return nil, err } if (hostModeIsEnabled == false){ hostModeDisabled = true contentAcceptedInfoMap[string(reviewHash[:])] = false continue } if (weWillHostReview == false){ contentAcceptedInfoMap[string(reviewHash[:])] = false continue } contentAcceptedInfoMap[string(reviewHash[:])] = true // We add review to database reviewIsWellFormed, err := reviewStorage.AddReview(contentBytes) if (err != nil) { return nil, err } if (reviewIsWellFormed == false){ return nil, errors.New("ReadReview not verifying review the same way that AddReview is") } continue } if (contentTypeToBroadcast == "Report"){ ableToRead, reportHash, _, reportNetworkType, _, reportType, reportedHash, _, err := readReports.ReadReportAndHash(false, contentBytes) if (err != nil) { return nil, err } if (ableToRead == false){ return nil, errors.New("ReadDecryptedServerRequest_BroadcastContent not verifying report") } if (reportNetworkType != networkType){ // Requestor must be malicious // They should only broadcast content which belongs to our networkType. contentAcceptedInfoMap[string(reportHash[:])] = false continue } //Outputs: // -bool: Host mode enabled // -bool: We will host Report // -error checkIfWeWillHostReport := func()(bool, bool, error){ if (reportType == "Message"){ // We see if we are hosting the reported message if (len(reportedHash) != 26){ reportedHashHex := encoding.EncodeBytesToHexString(reportedHash) return false, false, errors.New("ReadReport returning invalid length reportedHash for Message report: " + reportedHashHex) } reportedMessageHash := [26]byte(reportedHash) metadataExists, _, messageNetworkType, _, messageInbox, _, err := contentMetadata.GetMessageMetadata(reportedMessageHash) if (err != nil) { return false, false, err } if (metadataExists == false){ // We cannot accept reports for messages whose metadata we do not know // This is because we cannot seed reports for messages whose metadata we do not know return true, false, nil } if (messageNetworkType != reportNetworkType){ // Report is reporting a message from a different networkType // Report and report author must be malicious return true, false, nil } hostModeEnabled, isWithinMyRange, err := myRanges.CheckIfMessageInboxIsWithinMyHostedRange(messageInbox) if (err != nil) { return false, false, err } return hostModeEnabled, isWithinMyRange, nil } // reportType = "Identity" or "Profile" or "Attribute" //Outputs: // -bool: Reported identity hash is known // -bool: Report is malicious // -[16]byte: Reported identity hash // -error getReportedIdentityHash := func()(bool, bool, [16]byte, error){ if (reportType == "Identity"){ if (len(reportedHash) != 16){ reportedHashHex := encoding.EncodeBytesToHexString(reportedHash) return false, false, [16]byte{}, errors.New("ReadReport returning invalid length reportedHash for Identity report: " + reportedHashHex) } reportedIdentityHash := [16]byte(reportedHash) return true, false, reportedIdentityHash, nil } if (reportType == "Profile"){ if (len(reportedHash) != 28){ reportedHashHex := encoding.EncodeBytesToHexString(reportedHash) return false, false, [16]byte{}, errors.New("ReadReport returning invalid length reportedHash for Profile report: " + reportedHashHex) } reportedProfileHash := [28]byte(reportedHash) metadataExists, _, profileNetworkType, reportedProfileAuthor, _, _, _, _, err := contentMetadata.GetProfileMetadata(reportedProfileHash) if (err != nil) { return false, false, [16]byte{}, err } if (metadataExists == false){ return false, false, [16]byte{}, nil } if (profileNetworkType != reportNetworkType){ // Report is reporting a profile from a different networkType // Report and report author must be malicious return true, true, [16]byte{}, nil } return true, false, reportedProfileAuthor, nil } if (reportType == "Attribute"){ if (len(reportedHash) != 27){ reportedHashHex := encoding.EncodeBytesToHexString(reportedHash) return false, false, [16]byte{}, errors.New("ReadReport returning invalid length reportedHash for Attribute report: " + reportedHashHex) } reportedAttributeHash := [27]byte(reportedHash) metadataExists, _, authorIdentityHash, attributeNetworkType, _, err := profileStorage.GetProfileAttributeMetadata(reportedAttributeHash) if (err != nil) { return false, false, [16]byte{}, err } if (metadataExists == false){ return false, false, [16]byte{}, nil } if (attributeNetworkType != reportNetworkType){ // Report is reporting an attribute from a different networkType // Report and report author must be malicious return true, true, [16]byte{}, nil } return true, false, authorIdentityHash, nil } return false, false, [16]byte{}, errors.New("ReadReport returning invalid reportType: " + reportType) } reportedIdentityHashIsKnown, reportIsMalicious, reportedIdentityHash, err := getReportedIdentityHash() if (err != nil) { return false, false, err } if (reportedIdentityHashIsKnown == false){ return true, false, nil } if (reportIsMalicious == true){ return true, false, nil } hostModeEnabled, isWithinMyRange, err := myRanges.CheckIfIdentityHashIsWithinMyHostedRange(reportedIdentityHash) if (err != nil) { return false, false, err } return hostModeEnabled, isWithinMyRange, nil } hostModeIsEnabled, weWillHostReport, err := checkIfWeWillHostReport() if (err != nil) { return nil, err } if (hostModeIsEnabled == false){ hostModeDisabled = true contentAcceptedInfoMap[string(reportHash[:])] = false continue } if (weWillHostReport == false){ contentAcceptedInfoMap[string(reportHash[:])] = false continue } contentAcceptedInfoMap[string(reportHash[:])] = true // We add report to database reportIsWellFormed, err := reportStorage.AddReport(contentBytes) if (err != nil) { return nil, err } if (reportIsWellFormed == false){ return nil, errors.New("ReadReport not verifying report the same way as AddReport is") } continue } return nil, errors.New("ReadDecryptedServerRequest_BroadcastContent returning invalid contentTypeToBroadcast: " + contentTypeToBroadcast) } if (hostModeDisabled == true){ // Host mode is disabled, so we cannot accept any content for contentHash, _ := range contentAcceptedInfoMap{ contentAcceptedInfoMap[contentHash] = false } } responseBytes, err := serverResponse.CreateServerResponse_BroadcastContent(myHostPublicIdentityKey, myHostPrivateIdentityKey, connectionKey, requestIdentifier, contentAcceptedInfoMap) if (err != nil) { return nil, err } return responseBytes, nil } //TODO: GetAddressDeposits, GetFundedStatuses // Request contains unknown requestType return invalidRequestResponse, nil }