Fix(Profile): Remove profile showcase from general response via signal (#4982)

* Fix(Profile): Remove profile showcase from general responce via signal

* Fix(Profile): Restore community membership validation for the prodile showcase

* feat: Make profile validation optional

* fix: review fixes
This commit is contained in:
Mikhail Rogachev 2024-03-29 11:22:44 +01:00 committed by GitHub
parent e4c1abb5ce
commit 30e143ca40
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 256 additions and 123 deletions

View File

@ -86,8 +86,10 @@ type ProfileShowcasePreferences struct {
// Profile showcase for a contact
type ProfileShowcaseCommunity struct {
CommunityID string `json:"communityId"`
Order int `json:"order"`
CommunityID string `json:"communityId"`
Order int `json:"order"`
MembershipStatus ProfileShowcaseMembershipStatus `json:"membershipStatus"`
Grant []byte `json:"grant,omitempty"`
}
type ProfileShowcaseAccount struct {

View File

@ -3057,6 +3057,7 @@ func (m *Messenger) HandleChatIdentity(state *ReceivedMessageState, ci *protobuf
if err != nil {
return err
}
state.Response.AddUpdatedProfileShowcaseContactID(contact.ID)
}
}

View File

@ -1,6 +1,7 @@
package protocol
import (
"bytes"
"context"
"crypto/ecdsa"
crand "crypto/rand"
@ -15,6 +16,7 @@ import (
eth_common "github.com/ethereum/go-ethereum/common"
"github.com/status-im/status-go/eth-node/crypto"
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/multiaccounts/accounts"
"github.com/status-im/status-go/protocol/common"
@ -107,6 +109,60 @@ func (m *Messenger) validateCollectiblesOwnership(accounts []*identity.ProfileSh
return nil
}
func (m *Messenger) validateCommunityMembershipEntry(
entry *identity.ProfileShowcaseCommunity,
community *communities.Community,
contactPubKey *ecdsa.PublicKey) (identity.ProfileShowcaseMembershipStatus, error) {
if community == nil {
return identity.ProfileShowcaseMembershipStatusUnproven, nil
}
if community.Encrypted() {
grant, err := community.VerifyGrantSignature(entry.Grant)
if err != nil {
m.logger.Warn("failed to verify grant signature ", zap.Error(err))
return identity.ProfileShowcaseMembershipStatusNotAMember, nil
}
if grant != nil && bytes.Equal(grant.MemberId, crypto.CompressPubkey(contactPubKey)) {
return identity.ProfileShowcaseMembershipStatusProvenMember, nil
}
// Show as not a member if membership can't be proven
return identity.ProfileShowcaseMembershipStatusNotAMember, nil
}
if community.HasMember(contactPubKey) {
return identity.ProfileShowcaseMembershipStatusProvenMember, nil
}
return identity.ProfileShowcaseMembershipStatusNotAMember, nil
}
func (m *Messenger) validateCommunitiesMembership(communities []*identity.ProfileShowcaseCommunity, contactPubKey *ecdsa.PublicKey) ([]*identity.ProfileShowcaseCommunity, error) {
validatedCommunities := []*identity.ProfileShowcaseCommunity{}
for _, communityEntry := range communities {
community, err := m.FetchCommunity(&FetchCommunityRequest{
CommunityKey: communityEntry.CommunityID,
Shard: nil,
TryDatabase: true,
WaitForResponse: true,
})
if err != nil {
m.logger.Warn("failed to fetch community for profile entry ", zap.Error(err))
continue
}
communityEntry.MembershipStatus, err = m.validateCommunityMembershipEntry(communityEntry, community, contactPubKey)
if err != nil {
m.logger.Warn("failed to verify grant signature ", zap.Error(err))
}
validatedCommunities = append(validatedCommunities, communityEntry)
}
return validatedCommunities, nil
}
func (m *Messenger) toProfileShowcaseCommunityProto(preferences []*identity.ProfileShowcaseCommunityPreference, visibility identity.ProfileShowcaseVisibility) []*protobuf.ProfileShowcaseCommunity {
entries := []*protobuf.ProfileShowcaseCommunity{}
for _, preference := range preferences {
@ -230,11 +286,13 @@ func (m *Messenger) toProfileShowcaseSocialLinksProto(preferences []*identity.Pr
}
func (m *Messenger) fromProfileShowcaseCommunityProto(senderPubKey *ecdsa.PublicKey, messages []*protobuf.ProfileShowcaseCommunity) []*identity.ProfileShowcaseCommunity {
// NOTE: no requests to the network are allowed to be made here, called in the receiver thread
entries := []*identity.ProfileShowcaseCommunity{}
for _, message := range messages {
entry := &identity.ProfileShowcaseCommunity{
CommunityID: message.CommunityId,
Order: int(message.Order),
Grant: message.Grant,
}
entries = append(entries, entry)
@ -243,6 +301,7 @@ func (m *Messenger) fromProfileShowcaseCommunityProto(senderPubKey *ecdsa.Public
}
func (m *Messenger) fromProfileShowcaseAccountProto(messages []*protobuf.ProfileShowcaseAccount) []*identity.ProfileShowcaseAccount {
// NOTE: no requests to the network are allowed to be made here, called in the receiver thread
entries := []*identity.ProfileShowcaseAccount{}
for _, entry := range messages {
entries = append(entries, &identity.ProfileShowcaseAccount{
@ -257,6 +316,7 @@ func (m *Messenger) fromProfileShowcaseAccountProto(messages []*protobuf.Profile
}
func (m *Messenger) fromProfileShowcaseCollectibleProto(messages []*protobuf.ProfileShowcaseCollectible) []*identity.ProfileShowcaseCollectible {
// NOTE: no requests to the network are allowed to be made here, called in the receiver thread
entries := []*identity.ProfileShowcaseCollectible{}
for _, message := range messages {
entry := &identity.ProfileShowcaseCollectible{
@ -271,6 +331,7 @@ func (m *Messenger) fromProfileShowcaseCollectibleProto(messages []*protobuf.Pro
}
func (m *Messenger) fromProfileShowcaseVerifiedTokenProto(messages []*protobuf.ProfileShowcaseVerifiedToken) []*identity.ProfileShowcaseVerifiedToken {
// NOTE: no requests to the network are allowed to be made here, called in the receiver thread
entries := []*identity.ProfileShowcaseVerifiedToken{}
for _, entry := range messages {
entries = append(entries, &identity.ProfileShowcaseVerifiedToken{
@ -282,6 +343,7 @@ func (m *Messenger) fromProfileShowcaseVerifiedTokenProto(messages []*protobuf.P
}
func (m *Messenger) fromProfileShowcaseUnverifiedTokenProto(messages []*protobuf.ProfileShowcaseUnverifiedToken) []*identity.ProfileShowcaseUnverifiedToken {
// NOTE: no requests to the network are allowed to be made here, called in the receiver thread
entries := []*identity.ProfileShowcaseUnverifiedToken{}
for _, entry := range messages {
entries = append(entries, &identity.ProfileShowcaseUnverifiedToken{
@ -294,6 +356,7 @@ func (m *Messenger) fromProfileShowcaseUnverifiedTokenProto(messages []*protobuf
}
func (m *Messenger) fromProfileShowcaseSocialLinkProto(messages []*protobuf.ProfileShowcaseSocialLink) []*identity.ProfileShowcaseSocialLink {
// NOTE: no requests to the network are allowed to be made here, called in the receiver thread
entries := []*identity.ProfileShowcaseSocialLink{}
for _, entry := range messages {
entries = append(entries, &identity.ProfileShowcaseSocialLink{
@ -349,8 +412,29 @@ func (m *Messenger) GetProfileShowcasePreferences() (*identity.ProfileShowcasePr
return m.persistence.GetProfileShowcasePreferences()
}
func (m *Messenger) GetProfileShowcaseForContact(contactID string) (*identity.ProfileShowcase, error) {
return m.persistence.GetProfileShowcaseForContact(contactID)
func (m *Messenger) GetProfileShowcaseForContact(contactID string, validate bool) (*identity.ProfileShowcase, error) {
profileShowcase, err := m.persistence.GetProfileShowcaseForContact(contactID)
if err != nil {
return nil, err
}
if !validate {
return profileShowcase, nil
}
contactPubKey, err := common.HexToPubkey(contactID)
if err != nil {
return nil, err
}
profileShowcase.Communities, err = m.validateCommunitiesMembership(profileShowcase.Communities, contactPubKey)
if err != nil {
return nil, err
}
// TODO: validate collectibles & assets ownership, https://github.com/status-im/status-desktop/issues/14129
return profileShowcase, nil
}
func (m *Messenger) GetProfileShowcaseAccountsByAddress(address string) ([]*identity.ProfileShowcaseAccount, error) {
@ -600,7 +684,6 @@ func (m *Messenger) BuildProfileShowcaseFromIdentity(state *ReceivedMessageState
return err
}
state.Response.AddProfileShowcase(newShowcase)
return nil
}

View File

@ -471,17 +471,23 @@ func (s *TestMessengerProfileShowcase) TestShareShowcasePreferences() {
contactID := types.EncodeHex(crypto.FromECDSAPub(&s.m.identity.PublicKey))
// Get summarised profile data for mutual contact
resp, err := WaitOnMessengerResponse(
_, err = WaitOnMessengerResponse(
mutualContact,
func(r *MessengerResponse) bool {
return len(r.updatedProfileShowcases) > 0 && r.updatedProfileShowcases[contactID] != nil
return r.updatedProfileShowcaseContactIDs[contactID] == true
},
"no messages",
)
s.Require().NoError(err)
s.Require().Len(resp.updatedProfileShowcases, 1)
profileShowcase := resp.updatedProfileShowcases[contactID]
profileShowcase, err := mutualContact.GetProfileShowcaseForContact(contactID, false)
s.Require().NoError(err)
s.Require().Len(profileShowcase.Communities, 2)
s.Require().Equal(profileShowcase.Communities[0].CommunityID, request.Communities[0].CommunityID)
s.Require().Equal(profileShowcase.Communities[0].Order, request.Communities[0].Order)
s.Require().Equal(profileShowcase.Communities[1].CommunityID, request.Communities[1].CommunityID)
s.Require().Equal(profileShowcase.Communities[1].Order, request.Communities[1].Order)
s.Require().Len(profileShowcase.Accounts, 2)
s.Require().Equal(profileShowcase.Accounts[0].Address, request.Accounts[0].Address)
@ -516,18 +522,16 @@ func (s *TestMessengerProfileShowcase) TestShareShowcasePreferences() {
s.Require().Equal(profileShowcase.SocialLinks[1].Order, request.SocialLinks[2].Order)
// Get summarised profile data for verified contact
resp, err = WaitOnMessengerResponse(
_, err = WaitOnMessengerResponse(
verifiedContact,
func(r *MessengerResponse) bool {
return len(r.updatedProfileShowcases) > 0 && r.updatedProfileShowcases[contactID] != nil
return r.updatedProfileShowcaseContactIDs[contactID] == true
},
"no messages",
)
s.Require().NoError(err)
s.Require().Len(resp.updatedProfileShowcases, 1)
// Here let's try synchronous
profileShowcase, err = verifiedContact.GetProfileShowcaseForContact(contactID)
profileShowcase, err = verifiedContact.GetProfileShowcaseForContact(contactID, false)
s.Require().NoError(err)
s.Require().Len(profileShowcase.Accounts, 2)
@ -613,22 +617,24 @@ func (s *TestMessengerProfileShowcase) TestProfileShowcaseProofOfMembershipUnenc
s.Require().NoError(err)
contactID := types.EncodeHex(crypto.FromECDSAPub(&alice.identity.PublicKey))
resp, err := WaitOnMessengerResponse(
_, err = WaitOnMessengerResponse(
bob,
func(r *MessengerResponse) bool {
return len(r.updatedProfileShowcases) > 0 && r.updatedProfileShowcases[contactID] != nil
return r.updatedProfileShowcaseContactIDs[contactID] == true
},
"no messages",
)
s.Require().NoError(err)
s.Require().Len(resp.updatedProfileShowcases, 1)
profileShowcase := resp.updatedProfileShowcases[contactID]
profileShowcase, err := bob.GetProfileShowcaseForContact(contactID, true)
s.Require().NoError(err)
// Verify community's data
s.Require().Len(profileShowcase.Communities, 2)
s.Require().Equal(profileShowcase.Communities[0].CommunityID, aliceCommunity.IDString())
s.Require().Equal(profileShowcase.Communities[0].MembershipStatus, identity.ProfileShowcaseMembershipStatusProvenMember)
s.Require().Equal(profileShowcase.Communities[1].CommunityID, bobCommunity.IDString())
s.Require().Equal(profileShowcase.Communities[1].MembershipStatus, identity.ProfileShowcaseMembershipStatusNotAMember)
}
func (s *TestMessengerProfileShowcase) TestProfileShowcaseProofOfMembershipEncryptedCommunity() {
@ -679,20 +685,22 @@ func (s *TestMessengerProfileShowcase) TestProfileShowcaseProofOfMembershipEncry
s.Require().NoError(err)
contactID := types.EncodeHex(crypto.FromECDSAPub(&alice.identity.PublicKey))
resp, err := WaitOnMessengerResponse(
_, err = WaitOnMessengerResponse(
bob,
func(r *MessengerResponse) bool {
return len(r.updatedProfileShowcases) > 0 && r.updatedProfileShowcases[contactID] != nil
return r.updatedProfileShowcaseContactIDs[contactID] == true
},
"no messages",
)
s.Require().NoError(err)
s.Require().Len(resp.updatedProfileShowcases, 1)
profileShowcase := resp.updatedProfileShowcases[contactID]
profileShowcase, err := bob.GetProfileShowcaseForContact(contactID, true)
s.Require().NoError(err)
// Verify community's data
s.Require().Len(profileShowcase.Communities, 2)
s.Require().Equal(profileShowcase.Communities[0].CommunityID, aliceCommunity.IDString())
s.Require().Equal(profileShowcase.Communities[0].MembershipStatus, identity.ProfileShowcaseMembershipStatusProvenMember)
s.Require().Equal(profileShowcase.Communities[1].CommunityID, bobCommunity.IDString())
s.Require().Equal(profileShowcase.Communities[1].MembershipStatus, identity.ProfileShowcaseMembershipStatusNotAMember)
}

View File

@ -69,32 +69,32 @@ type MessengerResponse struct {
// notifications a list of notifications derived from messenger events
// that are useful to notify the user about
notifications map[string]*localnotifications.Notification
requestsToJoinCommunity map[string]*communities.RequestToJoin
chats map[string]*Chat
removedChats map[string]bool
removedMessages map[string]*RemovedMessage
deletedMessages map[string]string
communities map[string]*communities.Community
communitiesSettings map[string]*communities.CommunitySettings
activityCenterNotifications map[string]*ActivityCenterNotification
activityCenterState *ActivityCenterState
messages map[string]*common.Message
pinMessages map[string]*common.PinMessage
discordMessages map[string]*protobuf.DiscordMessage
discordMessageAttachments map[string]*protobuf.DiscordMessageAttachment
discordMessageAuthors map[string]*protobuf.DiscordMessageAuthor
currentStatus *UserStatus
statusUpdates map[string]UserStatus
clearedHistories map[string]*ClearedHistory
verificationRequests map[string]*verification.Request
trustStatus map[string]verification.TrustStatus
emojiReactions map[string]*EmojiReaction
savedAddresses map[string]*wallet.SavedAddress
SocialLinksInfo *identity.SocialLinksInfo
ensUsernameDetails []*ensservice.UsernameDetail
updatedProfileShowcases map[string]*identity.ProfileShowcase
seenAndUnseenMessages map[string]*SeenUnseenMessages
notifications map[string]*localnotifications.Notification
requestsToJoinCommunity map[string]*communities.RequestToJoin
chats map[string]*Chat
removedChats map[string]bool
removedMessages map[string]*RemovedMessage
deletedMessages map[string]string
communities map[string]*communities.Community
communitiesSettings map[string]*communities.CommunitySettings
activityCenterNotifications map[string]*ActivityCenterNotification
activityCenterState *ActivityCenterState
messages map[string]*common.Message
pinMessages map[string]*common.PinMessage
discordMessages map[string]*protobuf.DiscordMessage
discordMessageAttachments map[string]*protobuf.DiscordMessageAttachment
discordMessageAuthors map[string]*protobuf.DiscordMessageAuthor
currentStatus *UserStatus
statusUpdates map[string]UserStatus
clearedHistories map[string]*ClearedHistory
verificationRequests map[string]*verification.Request
trustStatus map[string]verification.TrustStatus
emojiReactions map[string]*EmojiReaction
savedAddresses map[string]*wallet.SavedAddress
SocialLinksInfo *identity.SocialLinksInfo
ensUsernameDetails []*ensservice.UsernameDetail
updatedProfileShowcaseContactIDs map[string]bool
seenAndUnseenMessages map[string]*SeenUnseenMessages
}
func (r *MessengerResponse) MarshalJSON() ([]byte, error) {
@ -119,31 +119,31 @@ func (r *MessengerResponse) MarshalJSON() ([]byte, error) {
TrustStatus map[string]verification.TrustStatus `json:"trustStatus,omitempty"`
// Notifications a list of notifications derived from messenger events
// that are useful to notify the user about
Notifications []*localnotifications.Notification `json:"notifications"`
Communities []*communities.Community `json:"communities,omitempty"`
CommunitiesSettings []*communities.CommunitySettings `json:"communitiesSettings,omitempty"`
ActivityCenterNotifications []*ActivityCenterNotification `json:"activityCenterNotifications,omitempty"`
ActivityCenterState *ActivityCenterState `json:"activityCenterState,omitempty"`
CurrentStatus *UserStatus `json:"currentStatus,omitempty"`
StatusUpdates []UserStatus `json:"statusUpdates,omitempty"`
Settings []*settings.SyncSettingField `json:"settings,omitempty"`
IdentityImages []images.IdentityImage `json:"identityImages,omitempty"`
CustomizationColor string `json:"customizationColor,omitempty"`
WatchOnlyAccounts []*accounts.Account `json:"watchOnlyAccounts,omitempty"`
Keypairs []*accounts.Keypair `json:"keypairs,omitempty"`
AccountsPositions []*accounts.Account `json:"accountsPositions,omitempty"`
TokenPreferences []walletsettings.TokenPreferences `json:"tokenPreferences,omitempty"`
CollectiblePreferences []walletsettings.CollectiblePreferences `json:"collectiblePreferences,omitempty"`
DiscordCategories []*discord.Category `json:"discordCategories,omitempty"`
DiscordChannels []*discord.Channel `json:"discordChannels,omitempty"`
DiscordOldestMessageTimestamp int `json:"discordOldestMessageTimestamp"`
DiscordMessages []*protobuf.DiscordMessage `json:"discordMessages,omitempty"`
DiscordMessageAttachments []*protobuf.DiscordMessageAttachment `json:"discordMessageAtachments,omitempty"`
SavedAddresses []*wallet.SavedAddress `json:"savedAddresses,omitempty"`
SocialLinksInfo *identity.SocialLinksInfo `json:"socialLinksInfo,omitempty"`
EnsUsernameDetails []*ensservice.UsernameDetail `json:"ensUsernameDetails,omitempty"`
UpdatedProfileShowcases []*identity.ProfileShowcase `json:"updatedProfileShowcases,omitempty"`
SeenAndUnseenMessages []*SeenUnseenMessages `json:"seenAndUnseenMessages,omitempty"`
Notifications []*localnotifications.Notification `json:"notifications"`
Communities []*communities.Community `json:"communities,omitempty"`
CommunitiesSettings []*communities.CommunitySettings `json:"communitiesSettings,omitempty"`
ActivityCenterNotifications []*ActivityCenterNotification `json:"activityCenterNotifications,omitempty"`
ActivityCenterState *ActivityCenterState `json:"activityCenterState,omitempty"`
CurrentStatus *UserStatus `json:"currentStatus,omitempty"`
StatusUpdates []UserStatus `json:"statusUpdates,omitempty"`
Settings []*settings.SyncSettingField `json:"settings,omitempty"`
IdentityImages []images.IdentityImage `json:"identityImages,omitempty"`
CustomizationColor string `json:"customizationColor,omitempty"`
WatchOnlyAccounts []*accounts.Account `json:"watchOnlyAccounts,omitempty"`
Keypairs []*accounts.Keypair `json:"keypairs,omitempty"`
AccountsPositions []*accounts.Account `json:"accountsPositions,omitempty"`
TokenPreferences []walletsettings.TokenPreferences `json:"tokenPreferences,omitempty"`
CollectiblePreferences []walletsettings.CollectiblePreferences `json:"collectiblePreferences,omitempty"`
DiscordCategories []*discord.Category `json:"discordCategories,omitempty"`
DiscordChannels []*discord.Channel `json:"discordChannels,omitempty"`
DiscordOldestMessageTimestamp int `json:"discordOldestMessageTimestamp"`
DiscordMessages []*protobuf.DiscordMessage `json:"discordMessages,omitempty"`
DiscordMessageAttachments []*protobuf.DiscordMessageAttachment `json:"discordMessageAtachments,omitempty"`
SavedAddresses []*wallet.SavedAddress `json:"savedAddresses,omitempty"`
SocialLinksInfo *identity.SocialLinksInfo `json:"socialLinksInfo,omitempty"`
EnsUsernameDetails []*ensservice.UsernameDetail `json:"ensUsernameDetails,omitempty"`
UpdatedProfileShowcaseContactIDs []string `json:"updatedProfileShowcaseContactIDs,omitempty"`
SeenAndUnseenMessages []*SeenUnseenMessages `json:"seenAndUnseenMessages,omitempty"`
}{
Contacts: r.Contacts,
Installations: r.Installations,
@ -163,29 +163,29 @@ func (r *MessengerResponse) MarshalJSON() ([]byte, error) {
TokenPreferences: r.TokenPreferences,
CollectiblePreferences: r.CollectiblePreferences,
Messages: r.Messages(),
VerificationRequests: r.VerificationRequests(),
SavedAddresses: r.SavedAddresses(),
Notifications: r.Notifications(),
Chats: r.Chats(),
Communities: r.Communities(),
CommunitiesSettings: r.CommunitiesSettings(),
RemovedChats: r.RemovedChats(),
RemovedMessages: r.RemovedMessages(),
DeletedMessages: r.DeletedMessagesInChats(),
ClearedHistories: r.ClearedHistories(),
ActivityCenterNotifications: r.ActivityCenterNotifications(),
ActivityCenterState: r.ActivityCenterState(),
PinMessages: r.PinMessages(),
EmojiReactions: r.EmojiReactions(),
StatusUpdates: r.StatusUpdates(),
DiscordCategories: r.DiscordCategories,
DiscordChannels: r.DiscordChannels,
DiscordOldestMessageTimestamp: r.DiscordOldestMessageTimestamp,
SocialLinksInfo: r.SocialLinksInfo,
EnsUsernameDetails: r.EnsUsernameDetails(),
UpdatedProfileShowcases: r.GetUpdatedProfileShowcases(),
SeenAndUnseenMessages: r.GetSeenAndUnseenMessages(),
Messages: r.Messages(),
VerificationRequests: r.VerificationRequests(),
SavedAddresses: r.SavedAddresses(),
Notifications: r.Notifications(),
Chats: r.Chats(),
Communities: r.Communities(),
CommunitiesSettings: r.CommunitiesSettings(),
RemovedChats: r.RemovedChats(),
RemovedMessages: r.RemovedMessages(),
DeletedMessages: r.DeletedMessagesInChats(),
ClearedHistories: r.ClearedHistories(),
ActivityCenterNotifications: r.ActivityCenterNotifications(),
ActivityCenterState: r.ActivityCenterState(),
PinMessages: r.PinMessages(),
EmojiReactions: r.EmojiReactions(),
StatusUpdates: r.StatusUpdates(),
DiscordCategories: r.DiscordCategories,
DiscordChannels: r.DiscordChannels,
DiscordOldestMessageTimestamp: r.DiscordOldestMessageTimestamp,
SocialLinksInfo: r.SocialLinksInfo,
EnsUsernameDetails: r.EnsUsernameDetails(),
UpdatedProfileShowcaseContactIDs: r.GetUpdatedProfileShowcaseContactIDs(),
SeenAndUnseenMessages: r.GetSeenAndUnseenMessages(),
}
responseItem.TrustStatus = r.TrustStatus()
@ -328,7 +328,7 @@ func (r *MessengerResponse) IsEmpty() bool {
len(r.verificationRequests)+
len(r.requestsToJoinCommunity)+
len(r.savedAddresses)+
len(r.updatedProfileShowcases)+
len(r.updatedProfileShowcaseContactIDs)+
len(r.seenAndUnseenMessages)+
len(r.ensUsernameDetails) == 0 &&
r.currentStatus == nil &&
@ -368,7 +368,7 @@ func (r *MessengerResponse) Merge(response *MessengerResponse) error {
r.AddEnsUsernameDetails(response.EnsUsernameDetails())
r.AddRequestsToJoinCommunity(response.RequestsToJoinCommunity())
r.AddBookmarks(response.GetBookmarks())
r.AddProfileShowcases(response.GetUpdatedProfileShowcases())
r.AddSeveralUpdatedProfileShowcaseContactIDs(response.GetUpdatedProfileShowcaseContactIDs())
r.AddSeveralSeenAndUnseenMessages(response.GetSeenAndUnseenMessages())
r.CommunityChanges = append(r.CommunityChanges, response.CommunityChanges...)
r.BackupHandled = response.BackupHandled
@ -870,26 +870,30 @@ func (r *MessengerResponse) HasDiscordChannel(id string) bool {
return false
}
func (r *MessengerResponse) AddProfileShowcases(showcases []*identity.ProfileShowcase) {
for _, showcase := range showcases {
r.AddProfileShowcase(showcase)
func (r *MessengerResponse) AddSeveralUpdatedProfileShowcaseContactIDs(contactIDs []string) {
for _, contactID := range contactIDs {
r.AddUpdatedProfileShowcaseContactID(contactID)
}
}
func (r *MessengerResponse) AddProfileShowcase(showcase *identity.ProfileShowcase) {
if r.updatedProfileShowcases == nil {
r.updatedProfileShowcases = make(map[string]*identity.ProfileShowcase)
func (r *MessengerResponse) AddUpdatedProfileShowcaseContactID(contactID string) {
if r.updatedProfileShowcaseContactIDs == nil {
r.updatedProfileShowcaseContactIDs = make(map[string]bool)
}
r.updatedProfileShowcases[showcase.ContactID] = showcase
if _, exists := r.updatedProfileShowcaseContactIDs[contactID]; exists {
return
}
r.updatedProfileShowcaseContactIDs[contactID] = true
}
func (r *MessengerResponse) GetUpdatedProfileShowcases() []*identity.ProfileShowcase {
var showcases []*identity.ProfileShowcase
for _, showcase := range r.updatedProfileShowcases {
showcases = append(showcases, showcase)
func (r *MessengerResponse) GetUpdatedProfileShowcaseContactIDs() []string {
var contactIDs []string
for contactID := range r.updatedProfileShowcaseContactIDs {
contactIDs = append(contactIDs, contactID)
}
return showcases
return contactIDs
}
func (r *MessengerResponse) AddSeveralSeenAndUnseenMessages(messages []*SeenUnseenMessages) {

View File

@ -417,7 +417,16 @@ func RandomBytes(length int) []byte {
func DummyProfileShowcasePreferences(withCollectibles bool) *identity.ProfileShowcasePreferences {
preferences := &identity.ProfileShowcasePreferences{
Communities: []*identity.ProfileShowcaseCommunityPreference{}, // empty to avoid fetching
Communities: []*identity.ProfileShowcaseCommunityPreference{
{
CommunityID: "0x254254546768764565565",
ShowcaseVisibility: identity.ProfileShowcaseVisibilityEveryone,
},
{
CommunityID: "0x865241434343432412343",
ShowcaseVisibility: identity.ProfileShowcaseVisibilityContacts,
},
},
Accounts: []*identity.ProfileShowcaseAccountPreference{
{
Address: "0x0000000000000000000000000033433445133423",

View File

@ -130,6 +130,7 @@
// 1709805967_simplify_profile_showcase_preferences.up.sql (701B)
// 1709828431_add_community_description_cache.up.sql (730B)
// 1710331283_add_bio_to_contacts.up.sql (42B)
// 1711389881_add_profile_showcase_community_grant.up.sql (86B)
// README.md (554B)
// doc.go (870B)
@ -2799,6 +2800,26 @@ func _1710331283_add_bio_to_contactsUpSql() (*asset, error) {
return a, nil
}
var __1711389881_add_profile_showcase_community_grantUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x04\xc0\x41\x0e\x02\x21\x0c\x05\xd0\xbd\xa7\xf8\xf7\x70\x55\x04\x57\x75\x26\x31\xb0\x26\xa4\x41\x25\x71\xa8\xa1\x35\x5e\xdf\x47\x9c\xd3\x1d\x99\x02\x27\x7c\x96\x3e\xc6\xbb\x57\x7b\xe9\x4f\x9a\xf5\x2a\x7a\x1c\xdf\x39\x7c\x74\xab\xa2\xd3\x9b\xb8\x81\x62\xc4\x65\xe7\x72\xdb\xf0\x5c\x6d\x3a\x02\xef\x01\x31\x5d\xa9\x70\xc6\x56\x98\xcf\xa7\x7f\x00\x00\x00\xff\xff\x50\x71\xc8\xa0\x56\x00\x00\x00")
func _1711389881_add_profile_showcase_community_grantUpSqlBytes() ([]byte, error) {
return bindataRead(
__1711389881_add_profile_showcase_community_grantUpSql,
"1711389881_add_profile_showcase_community_grant.up.sql",
)
}
func _1711389881_add_profile_showcase_community_grantUpSql() (*asset, error) {
bytes, err := _1711389881_add_profile_showcase_community_grantUpSqlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "1711389881_add_profile_showcase_community_grant.up.sql", size: 86, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x45, 0x39, 0x37, 0xf3, 0x6a, 0xb, 0xb8, 0x38, 0x8, 0xcb, 0x62, 0xe1, 0x5b, 0xf2, 0xc, 0x6c, 0xf2, 0xa3, 0x5c, 0xeb, 0x22, 0x4f, 0x6c, 0xe1, 0x56, 0xd1, 0xd1, 0x3, 0xf9, 0x6d, 0x5e, 0x69}}
return a, nil
}
var _readmeMd = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x54\x91\xc1\xce\xd3\x30\x10\x84\xef\x7e\x8a\x91\x7a\x01\xa9\x2a\x8f\xc0\x0d\x71\x82\x03\x48\x1c\xc9\x36\x9e\x36\x96\x1c\x6f\xf0\xae\x93\xe6\xed\x91\xa3\xc2\xdf\xff\x66\xed\xd8\x33\xdf\x78\x4f\xa7\x13\xbe\xea\x06\x57\x6c\x35\x39\x31\xa7\x7b\x15\x4f\x5a\xec\x73\x08\xbf\x08\x2d\x79\x7f\x4a\x43\x5b\x86\x17\xfd\x8c\x21\xea\x56\x5e\x47\x90\x4a\x14\x75\x48\xde\x64\x37\x2c\x6a\x96\xae\x99\x48\x05\xf6\x27\x77\x13\xad\x08\xae\x8a\x51\xe7\x25\xf3\xf1\xa9\x9f\xf9\x58\x58\x2c\xad\xbc\xe0\x8b\x56\xf0\x21\x5d\xeb\x4c\x95\xb3\xae\x84\x60\xd4\xdc\xe6\x82\x5d\x1b\x36\x6d\x39\x62\x92\xf5\xb8\x11\xdb\x92\xd3\x28\xce\xe0\x13\xe1\x72\xcd\x3c\x63\xd4\x65\x87\xae\xac\xe8\xc3\x28\x2e\x67\x44\x66\x3a\x21\x25\xa2\x72\xac\x14\x67\xbc\x84\x9f\x53\x32\x8c\x52\x70\x25\x56\xd6\xfd\x8d\x05\x37\xad\x30\x9d\x9f\xa6\x86\x0f\xcd\x58\x7f\xcf\x34\x93\x3b\xed\x90\x9f\xa4\x1f\xcf\x30\x85\x4d\x07\x58\xaf\x7f\x25\xc4\x9d\xf3\x72\x64\x84\xd0\x7f\xf9\x9b\x3a\x2d\x84\xef\x85\x48\x66\x8d\xd8\x88\x9b\x8c\x8c\x98\x5b\xf6\x74\x14\x4e\x33\x0d\xc9\xe0\x93\x38\xda\x12\xc5\x69\xbd\xe4\xf0\x2e\x7a\x78\x07\x1c\xfe\x13\x9f\x91\x29\x31\x95\x7b\x7f\x62\x59\x37\xb4\xe5\x5e\x25\xfe\x33\xee\xd5\x53\x71\xd6\xda\x3a\xd8\xcb\xde\x2e\xf8\xa1\x90\x55\x53\x0c\xc7\xaa\x0d\xe9\x76\x14\x29\x1c\x7b\x68\xdd\x2f\xe1\x6f\x00\x00\x00\xff\xff\x3c\x0a\xc2\xfe\x2a\x02\x00\x00")
func readmeMdBytes() ([]byte, error) {
@ -3060,8 +3081,9 @@ var _bindata = map[string]func() (*asset, error){
"1709805967_simplify_profile_showcase_preferences.up.sql": _1709805967_simplify_profile_showcase_preferencesUpSql,
"1709828431_add_community_description_cache.up.sql": _1709828431_add_community_description_cacheUpSql,
"1710331283_add_bio_to_contacts.up.sql": _1710331283_add_bio_to_contactsUpSql,
"README.md": readmeMd,
"doc.go": docGo,
"1711389881_add_profile_showcase_community_grant.up.sql": _1711389881_add_profile_showcase_community_grantUpSql,
"README.md": readmeMd,
"doc.go": docGo,
}
// AssetDebug is true if the assets were built with the debug flag enabled.
@ -3240,8 +3262,9 @@ var _bintree = &bintree{nil, map[string]*bintree{
"1709805967_simplify_profile_showcase_preferences.up.sql": {_1709805967_simplify_profile_showcase_preferencesUpSql, map[string]*bintree{}},
"1709828431_add_community_description_cache.up.sql": {_1709828431_add_community_description_cacheUpSql, map[string]*bintree{}},
"1710331283_add_bio_to_contacts.up.sql": {_1710331283_add_bio_to_contactsUpSql, map[string]*bintree{}},
"README.md": {readmeMd, map[string]*bintree{}},
"doc.go": {docGo, map[string]*bintree{}},
"1711389881_add_profile_showcase_community_grant.up.sql": {_1711389881_add_profile_showcase_community_grantUpSql, map[string]*bintree{}},
"README.md": {readmeMd, map[string]*bintree{}},
"doc.go": {docGo, map[string]*bintree{}},
}}
// RestoreAsset restores an asset under the given directory.

View File

@ -0,0 +1 @@
ALTER TABLE profile_showcase_communities_contacts ADD COLUMN grant BLOB DEFAULT NULL;

View File

@ -40,10 +40,9 @@ const selectProfileShowcaseSocialLinkPreferenceQuery = "SELECT url, text, visibi
const clearProfileShowcaseSocialLinkPreferencesQuery = "DELETE FROM profile_showcase_social_links_preferences" // #nosec G101
// Profile showcase for a contact
const upsertContactProfileShowcaseCommunityQuery = "INSERT OR REPLACE INTO profile_showcase_communities_contacts(contact_id, community_id, sort_order) VALUES (?, ?, ?)" // #nosec G101
const selectContactProfileShowcaseCommunityQuery = "SELECT community_id, sort_order FROM profile_showcase_communities_contacts WHERE contact_id = ?" // #nosec G101
const removeContactProfileShowcaseCommunityQuery = "DELETE FROM profile_showcase_communities_contacts WHERE contact_id = ?" // #nosec G101
const upsertContactProfileShowcaseCommunityQuery = "INSERT OR REPLACE INTO profile_showcase_communities_contacts(contact_id, community_id, sort_order, grant) VALUES (?, ?, ?, ?)" // #nosec G101
const selectContactProfileShowcaseCommunityQuery = "SELECT community_id, sort_order, grant FROM profile_showcase_communities_contacts WHERE contact_id = ?" // #nosec G101
const removeContactProfileShowcaseCommunityQuery = "DELETE FROM profile_showcase_communities_contacts WHERE contact_id = ?" // #nosec G101
const upsertContactProfileShowcaseAccountQuery = "INSERT OR REPLACE INTO profile_showcase_accounts_contacts(contact_id, address, name, color_id, emoji, sort_order) VALUES (?, ?, ?, ?, ?, ?)" // #nosec G101
const selectContactProfileShowcaseAccountQuery = "SELECT * FROM profile_showcase_accounts_contacts WHERE contact_id = ?" // #nosec G101
@ -391,6 +390,7 @@ func (db sqlitePersistence) saveProfileShowcaseCommunityContact(tx *sql.Tx, cont
contactID,
community.CommunityID,
community.Order,
community.Grant,
)
return err
@ -405,9 +405,11 @@ func (db sqlitePersistence) getProfileShowcaseCommunitiesContact(tx *sql.Tx, con
communities := []*identity.ProfileShowcaseCommunity{}
for rows.Next() {
community := &identity.ProfileShowcaseCommunity{}
community := &identity.ProfileShowcaseCommunity{
MembershipStatus: identity.ProfileShowcaseMembershipStatusUnproven,
}
err := rows.Scan(&community.CommunityID, &community.Order)
err := rows.Scan(&community.CommunityID, &community.Order, &community.Grant)
if err != nil {
return nil, err
}

View File

@ -1697,8 +1697,8 @@ func (api *PublicAPI) GetProfileShowcasePreferences() (*identity.ProfileShowcase
}
// Get profile showcase for a contact
func (api *PublicAPI) GetProfileShowcaseForContact(contactID string) (*identity.ProfileShowcase, error) {
return api.service.messenger.GetProfileShowcaseForContact(contactID)
func (api *PublicAPI) GetProfileShowcaseForContact(contactID string, validate bool) (*identity.ProfileShowcase, error) {
return api.service.messenger.GetProfileShowcaseForContact(contactID, validate)
}
// Get profile showcase accounts by address