Request/Decline access to communities
This commit is contained in:
parent
99a304686f
commit
f115b8d289
|
@ -736,7 +736,7 @@ func _0018_profile_pictures_visibilityUpSql() (*asset, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
info := bindataFileInfo{name: "0018_profile_pictures_visibility.up.sql", size: 84, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)}
|
info := bindataFileInfo{name: "0018_profile_pictures_visibility.up.sql", size: 84, mode: os.FileMode(0644), modTime: time.Unix(1612251705, 0)}
|
||||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xc9, 0xe3, 0xc5, 0xec, 0x83, 0x55, 0x45, 0x57, 0x7a, 0xaa, 0xd2, 0xa7, 0x59, 0xa7, 0x87, 0xef, 0x63, 0x19, 0x9c, 0x46, 0x9c, 0xc5, 0x32, 0x89, 0xa4, 0x68, 0x70, 0xd8, 0x83, 0x43, 0xa4, 0x72}}
|
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xc9, 0xe3, 0xc5, 0xec, 0x83, 0x55, 0x45, 0x57, 0x7a, 0xaa, 0xd2, 0xa7, 0x59, 0xa7, 0x87, 0xef, 0x63, 0x19, 0x9c, 0x46, 0x9c, 0xc5, 0x32, 0x89, 0xa4, 0x68, 0x70, 0xd8, 0x83, 0x43, 0xa4, 0x72}}
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -261,11 +261,11 @@ func OneToOneFromPublicKey(pk *ecdsa.PublicKey, timesource common.TimeSource) *C
|
||||||
chatID := types.EncodeHex(crypto.FromECDSAPub(pk))
|
chatID := types.EncodeHex(crypto.FromECDSAPub(pk))
|
||||||
newChat := CreateOneToOneChat(chatID[:8], pk, timesource)
|
newChat := CreateOneToOneChat(chatID[:8], pk, timesource)
|
||||||
|
|
||||||
return &newChat
|
return newChat
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateOneToOneChat(name string, publicKey *ecdsa.PublicKey, timesource common.TimeSource) Chat {
|
func CreateOneToOneChat(name string, publicKey *ecdsa.PublicKey, timesource common.TimeSource) *Chat {
|
||||||
return Chat{
|
return &Chat{
|
||||||
ID: oneToOneChatID(publicKey),
|
ID: oneToOneChatID(publicKey),
|
||||||
Name: name,
|
Name: name,
|
||||||
Timestamp: int64(timesource.GetCurrentTime()),
|
Timestamp: int64(timesource.GetCurrentTime()),
|
||||||
|
@ -274,13 +274,13 @@ func CreateOneToOneChat(name string, publicKey *ecdsa.PublicKey, timesource comm
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateCommunityChat(orgID, chatID string, orgChat *protobuf.CommunityChat, timesource common.TimeSource) Chat {
|
func CreateCommunityChat(orgID, chatID string, orgChat *protobuf.CommunityChat, timesource common.TimeSource) *Chat {
|
||||||
color := orgChat.Identity.Color
|
color := orgChat.Identity.Color
|
||||||
if color == "" {
|
if color == "" {
|
||||||
color = chatColors[rand.Intn(len(chatColors))] // nolint: gosec
|
color = chatColors[rand.Intn(len(chatColors))] // nolint: gosec
|
||||||
}
|
}
|
||||||
|
|
||||||
return Chat{
|
return &Chat{
|
||||||
CommunityID: orgID,
|
CommunityID: orgID,
|
||||||
Name: orgChat.Identity.DisplayName,
|
Name: orgChat.Identity.DisplayName,
|
||||||
Active: true,
|
Active: true,
|
||||||
|
@ -291,8 +291,8 @@ func CreateCommunityChat(orgID, chatID string, orgChat *protobuf.CommunityChat,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateCommunityChats(org *communities.Community, timesource common.TimeSource) []Chat {
|
func CreateCommunityChats(org *communities.Community, timesource common.TimeSource) []*Chat {
|
||||||
var chats []Chat
|
var chats []*Chat
|
||||||
orgID := org.IDString()
|
orgID := org.IDString()
|
||||||
|
|
||||||
for chatID, chat := range org.Chats() {
|
for chatID, chat := range org.Chats() {
|
||||||
|
@ -301,8 +301,8 @@ func CreateCommunityChats(org *communities.Community, timesource common.TimeSour
|
||||||
return chats
|
return chats
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreatePublicChat(name string, timesource common.TimeSource) Chat {
|
func CreatePublicChat(name string, timesource common.TimeSource) *Chat {
|
||||||
return Chat{
|
return &Chat{
|
||||||
ID: name,
|
ID: name,
|
||||||
Name: name,
|
Name: name,
|
||||||
Active: true,
|
Active: true,
|
||||||
|
@ -316,8 +316,8 @@ func buildProfileChatID(publicKeyString string) string {
|
||||||
return "@" + publicKeyString
|
return "@" + publicKeyString
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateProfileChat(id string, profile string, timesource common.TimeSource) Chat {
|
func CreateProfileChat(id string, profile string, timesource common.TimeSource) *Chat {
|
||||||
return Chat{
|
return &Chat{
|
||||||
ID: id,
|
ID: id,
|
||||||
Name: id,
|
Name: id,
|
||||||
Active: true,
|
Active: true,
|
||||||
|
|
|
@ -75,6 +75,10 @@ func PubkeyToHex(key *ecdsa.PublicKey) string {
|
||||||
return types.EncodeHex(crypto.FromECDSAPub(key))
|
return types.EncodeHex(crypto.FromECDSAPub(key))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func PubkeyToHexBytes(key *ecdsa.PublicKey) types.HexBytes {
|
||||||
|
return crypto.FromECDSAPub(key)
|
||||||
|
}
|
||||||
|
|
||||||
func HexToPubkey(pk string) (*ecdsa.PublicKey, error) {
|
func HexToPubkey(pk string) (*ecdsa.PublicKey, error) {
|
||||||
bytes, err := types.DecodeHex(pk)
|
bytes, err := types.DecodeHex(pk)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -152,6 +152,23 @@ func (p *MessageProcessor) SendPrivate(
|
||||||
return p.sendPrivate(ctx, recipient, rawMessage)
|
return p.sendPrivate(ctx, recipient, rawMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SendCommunityMessage takes encoded data, encrypts it and sends through the wire
|
||||||
|
// using the community topic and their key
|
||||||
|
func (p *MessageProcessor) SendCommunityMessage(
|
||||||
|
ctx context.Context,
|
||||||
|
recipient *ecdsa.PublicKey,
|
||||||
|
rawMessage RawMessage,
|
||||||
|
) ([]byte, error) {
|
||||||
|
p.logger.Debug(
|
||||||
|
"sending a community message",
|
||||||
|
zap.String("public-key", types.EncodeHex(crypto.FromECDSAPub(recipient))),
|
||||||
|
zap.String("site", "SendPrivate"),
|
||||||
|
)
|
||||||
|
rawMessage.Sender = p.identity
|
||||||
|
|
||||||
|
return p.sendCommunity(ctx, recipient, &rawMessage)
|
||||||
|
}
|
||||||
|
|
||||||
// SendGroup takes encoded data, encrypts it and sends through the wire,
|
// SendGroup takes encoded data, encrypts it and sends through the wire,
|
||||||
// always return the messageID
|
// always return the messageID
|
||||||
func (p *MessageProcessor) SendGroup(
|
func (p *MessageProcessor) SendGroup(
|
||||||
|
@ -186,6 +203,38 @@ func (p *MessageProcessor) SendGroup(
|
||||||
return messageID, nil
|
return messageID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sendCommunity sends data to the recipient identifying with a given public key.
|
||||||
|
func (p *MessageProcessor) sendCommunity(
|
||||||
|
ctx context.Context,
|
||||||
|
recipient *ecdsa.PublicKey,
|
||||||
|
rawMessage *RawMessage,
|
||||||
|
) ([]byte, error) {
|
||||||
|
p.logger.Debug("sending community message", zap.String("recipient", types.EncodeHex(crypto.FromECDSAPub(recipient))))
|
||||||
|
|
||||||
|
wrappedMessage, err := p.wrapMessageV1(rawMessage)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to wrap message")
|
||||||
|
}
|
||||||
|
|
||||||
|
messageID := v1protocol.MessageID(&rawMessage.Sender.PublicKey, wrappedMessage)
|
||||||
|
rawMessage.ID = types.EncodeHex(messageID)
|
||||||
|
|
||||||
|
// Notify before dispatching, otherwise the dispatch subscription might happen
|
||||||
|
// earlier than the scheduled
|
||||||
|
p.notifyOnScheduledMessage(rawMessage)
|
||||||
|
|
||||||
|
messageIDs := [][]byte{messageID}
|
||||||
|
hash, newMessage, err := p.sendCommunityRawMessage(ctx, recipient, wrappedMessage, messageIDs)
|
||||||
|
if err != nil {
|
||||||
|
p.logger.Error("failed to send a community message", zap.Error(err))
|
||||||
|
return nil, errors.Wrap(err, "failed to send a message spec")
|
||||||
|
}
|
||||||
|
|
||||||
|
p.transport.Track(messageIDs, hash, newMessage)
|
||||||
|
|
||||||
|
return messageID, nil
|
||||||
|
}
|
||||||
|
|
||||||
// sendPrivate sends data to the recipient identifying with a given public key.
|
// sendPrivate sends data to the recipient identifying with a given public key.
|
||||||
func (p *MessageProcessor) sendPrivate(
|
func (p *MessageProcessor) sendPrivate(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
|
@ -619,6 +668,24 @@ func (p *MessageProcessor) sendPrivateRawMessage(ctx context.Context, rawMessage
|
||||||
return hash, newMessage, nil
|
return hash, newMessage, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sendCommunityRawMessage sends a message not wrapped in an encryption layer
|
||||||
|
// to a community
|
||||||
|
func (p *MessageProcessor) sendCommunityRawMessage(ctx context.Context, publicKey *ecdsa.PublicKey, payload []byte, messageIDs [][]byte) ([]byte, *types.NewMessage, error) {
|
||||||
|
newMessage := &types.NewMessage{
|
||||||
|
TTL: whisperTTL,
|
||||||
|
Payload: payload,
|
||||||
|
PowTarget: calculatePoW(payload),
|
||||||
|
PowTime: whisperPoWTime,
|
||||||
|
}
|
||||||
|
|
||||||
|
hash, err := p.transport.SendCommunityMessage(ctx, newMessage, publicKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return hash, newMessage, nil
|
||||||
|
}
|
||||||
|
|
||||||
// sendMessageSpec analyses the spec properties and selects a proper transport method.
|
// sendMessageSpec analyses the spec properties and selects a proper transport method.
|
||||||
func (p *MessageProcessor) sendMessageSpec(ctx context.Context, publicKey *ecdsa.PublicKey, messageSpec *encryption.ProtocolMessageSpec, messageIDs [][]byte) ([]byte, *types.NewMessage, error) {
|
func (p *MessageProcessor) sendMessageSpec(ctx context.Context, publicKey *ecdsa.PublicKey, messageSpec *encryption.ProtocolMessageSpec, messageIDs [][]byte) ([]byte, *types.NewMessage, error) {
|
||||||
newMessage, err := MessageSpecToWhisper(messageSpec)
|
newMessage, err := MessageSpecToWhisper(messageSpec)
|
||||||
|
@ -690,8 +757,8 @@ func (p *MessageProcessor) notifyOnScheduledMessage(message *RawMessage) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *MessageProcessor) JoinPublic(chatID string) error {
|
func (p *MessageProcessor) JoinPublic(id string) (*transport.Filter, error) {
|
||||||
return p.transport.JoinPublic(chatID)
|
return p.transport.JoinPublic(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddEphemeralKey adds an ephemeral key that we will be listening to
|
// AddEphemeralKey adds an ephemeral key that we will be listening to
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
|
@ -11,6 +12,7 @@ import (
|
||||||
|
|
||||||
"github.com/status-im/status-go/eth-node/crypto"
|
"github.com/status-im/status-go/eth-node/crypto"
|
||||||
"github.com/status-im/status-go/eth-node/types"
|
"github.com/status-im/status-go/eth-node/types"
|
||||||
|
"github.com/status-im/status-go/images"
|
||||||
"github.com/status-im/status-go/protocol/common"
|
"github.com/status-im/status-go/protocol/common"
|
||||||
"github.com/status-im/status-go/protocol/protobuf"
|
"github.com/status-im/status-go/protocol/protobuf"
|
||||||
"github.com/status-im/status-go/protocol/v1"
|
"github.com/status-im/status-go/protocol/v1"
|
||||||
|
@ -24,8 +26,11 @@ type Config struct {
|
||||||
MarshaledCommunityDescription []byte
|
MarshaledCommunityDescription []byte
|
||||||
ID *ecdsa.PublicKey
|
ID *ecdsa.PublicKey
|
||||||
Joined bool
|
Joined bool
|
||||||
|
Requested bool
|
||||||
Verified bool
|
Verified bool
|
||||||
Logger *zap.Logger
|
Logger *zap.Logger
|
||||||
|
RequestedToJoinAt uint64
|
||||||
|
MemberIdentity *ecdsa.PublicKey
|
||||||
}
|
}
|
||||||
|
|
||||||
type Community struct {
|
type Community struct {
|
||||||
|
@ -34,6 +39,10 @@ type Community struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(config Config) (*Community, error) {
|
func New(config Config) (*Community, error) {
|
||||||
|
if config.MemberIdentity == nil {
|
||||||
|
return nil, errors.New("no member identity")
|
||||||
|
}
|
||||||
|
|
||||||
if config.Logger == nil {
|
if config.Logger == nil {
|
||||||
logger, err := zap.NewDevelopment()
|
logger, err := zap.NewDevelopment()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -47,21 +56,80 @@ func New(config Config) (*Community, error) {
|
||||||
return community, nil
|
return community, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CommunityChat struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Members map[string]*protobuf.CommunityMember `json:"members"`
|
||||||
|
Permissions *protobuf.CommunityPermissions `json:"permissions"`
|
||||||
|
CanPost bool `json:"canPost"`
|
||||||
|
}
|
||||||
|
|
||||||
func (o *Community) MarshalJSON() ([]byte, error) {
|
func (o *Community) MarshalJSON() ([]byte, error) {
|
||||||
item := struct {
|
if o.config.MemberIdentity == nil {
|
||||||
*protobuf.CommunityDescription `json:"description"`
|
return nil, errors.New("member identity not set")
|
||||||
ID string `json:"id"`
|
|
||||||
Admin bool `json:"admin"`
|
|
||||||
Verified bool `json:"verified"`
|
|
||||||
Joined bool `json:"joined"`
|
|
||||||
}{
|
|
||||||
ID: o.IDString(),
|
|
||||||
CommunityDescription: o.config.CommunityDescription,
|
|
||||||
Admin: o.IsAdmin(),
|
|
||||||
Verified: o.config.Verified,
|
|
||||||
Joined: o.config.Joined,
|
|
||||||
}
|
}
|
||||||
return json.Marshal(item)
|
communityItem := struct {
|
||||||
|
ID types.HexBytes `json:"id"`
|
||||||
|
Admin bool `json:"admin"`
|
||||||
|
Verified bool `json:"verified"`
|
||||||
|
Joined bool `json:"joined"`
|
||||||
|
RequestedAccessAt int `json:"requestedAccessAt"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Chats map[string]CommunityChat `json:"chats"`
|
||||||
|
Images map[string]images.IdentityImage `json:"images"`
|
||||||
|
Permissions *protobuf.CommunityPermissions `json:"permissions"`
|
||||||
|
Members map[string]*protobuf.CommunityMember `json:"members"`
|
||||||
|
CanRequestAccess bool `json:"canRequestAccess"`
|
||||||
|
CanManageUsers bool `json:"canManageUsers"`
|
||||||
|
CanJoin bool `json:"canJoin"`
|
||||||
|
Color string `json:"color"`
|
||||||
|
RequestedToJoinAt uint64 `json:"requestedToJoinAt,omitempty"`
|
||||||
|
IsMember bool `json:"isMember"`
|
||||||
|
}{
|
||||||
|
ID: o.ID(),
|
||||||
|
Admin: o.IsAdmin(),
|
||||||
|
Verified: o.config.Verified,
|
||||||
|
Chats: make(map[string]CommunityChat),
|
||||||
|
Joined: o.config.Joined,
|
||||||
|
CanRequestAccess: o.CanRequestAccess(o.config.MemberIdentity),
|
||||||
|
CanJoin: o.canJoin(),
|
||||||
|
CanManageUsers: o.CanManageUsers(o.config.MemberIdentity),
|
||||||
|
RequestedToJoinAt: o.RequestedToJoinAt(),
|
||||||
|
IsMember: o.isMember(),
|
||||||
|
}
|
||||||
|
if o.config.CommunityDescription != nil {
|
||||||
|
for id, c := range o.config.CommunityDescription.Chats {
|
||||||
|
canPost, err := o.CanPost(o.config.MemberIdentity, id, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
chat := CommunityChat{
|
||||||
|
ID: id,
|
||||||
|
Name: c.Identity.DisplayName,
|
||||||
|
Permissions: c.Permissions,
|
||||||
|
Members: c.Members,
|
||||||
|
CanPost: canPost,
|
||||||
|
}
|
||||||
|
communityItem.Chats[id] = chat
|
||||||
|
}
|
||||||
|
communityItem.Members = o.config.CommunityDescription.Members
|
||||||
|
communityItem.Permissions = o.config.CommunityDescription.Permissions
|
||||||
|
if o.config.CommunityDescription.Identity != nil {
|
||||||
|
communityItem.Name = o.config.CommunityDescription.Identity.DisplayName
|
||||||
|
communityItem.Color = o.config.CommunityDescription.Identity.Color
|
||||||
|
communityItem.Description = o.config.CommunityDescription.Identity.Description
|
||||||
|
for t, i := range o.config.CommunityDescription.Identity.Images {
|
||||||
|
if communityItem.Images == nil {
|
||||||
|
communityItem.Images = make(map[string]images.IdentityImage)
|
||||||
|
}
|
||||||
|
communityItem.Images[t] = images.IdentityImage{Name: t, Payload: i.Payload}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return json.Marshal(communityItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Community) initialize() {
|
func (o *Community) initialize() {
|
||||||
|
@ -77,23 +145,43 @@ type CommunityChatChanges struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type CommunityChanges struct {
|
type CommunityChanges struct {
|
||||||
MembersAdded map[string]*protobuf.CommunityMember
|
Community *Community `json:"community"`
|
||||||
MembersRemoved map[string]*protobuf.CommunityMember
|
MembersAdded map[string]*protobuf.CommunityMember `json:"membersAdded"`
|
||||||
|
MembersRemoved map[string]*protobuf.CommunityMember `json:"membersRemoved"`
|
||||||
|
|
||||||
ChatsRemoved map[string]*protobuf.CommunityChat
|
ChatsRemoved map[string]*protobuf.CommunityChat `json:"chatsRemoved"`
|
||||||
ChatsAdded map[string]*protobuf.CommunityChat
|
ChatsAdded map[string]*protobuf.CommunityChat `json:"chatsAdded"`
|
||||||
ChatsModified map[string]*CommunityChatChanges
|
ChatsModified map[string]*CommunityChatChanges `json:"chatsModified"`
|
||||||
|
|
||||||
|
// ShouldMemberJoin indicates whether the user should join this community
|
||||||
|
// automatically
|
||||||
|
ShouldMemberJoin bool `json:"memberAdded"`
|
||||||
|
|
||||||
|
// ShouldMemberJoin indicates whether the user should leave this community
|
||||||
|
// automatically
|
||||||
|
ShouldMemberLeave bool `json:"memberRemoved"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func emptyCommunityChanges() *CommunityChanges {
|
func (c *CommunityChanges) HasNewMember(identity string) bool {
|
||||||
return &CommunityChanges{
|
if len(c.MembersAdded) == 0 {
|
||||||
MembersAdded: make(map[string]*protobuf.CommunityMember),
|
return false
|
||||||
MembersRemoved: make(map[string]*protobuf.CommunityMember),
|
|
||||||
|
|
||||||
ChatsRemoved: make(map[string]*protobuf.CommunityChat),
|
|
||||||
ChatsAdded: make(map[string]*protobuf.CommunityChat),
|
|
||||||
ChatsModified: make(map[string]*CommunityChatChanges),
|
|
||||||
}
|
}
|
||||||
|
_, ok := c.MembersAdded[identity]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CommunityChanges) HasMemberLeft(identity string) bool {
|
||||||
|
if len(c.MembersRemoved) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
_, ok := c.MembersRemoved[identity]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Community) emptyCommunityChanges() *CommunityChanges {
|
||||||
|
changes := emptyCommunityChanges()
|
||||||
|
changes.Community = o
|
||||||
|
return changes
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Community) CreateChat(chatID string, chat *protobuf.CommunityChat) (*CommunityChanges, error) {
|
func (o *Community) CreateChat(chatID string, chat *protobuf.CommunityChat) (*CommunityChanges, error) {
|
||||||
|
@ -120,7 +208,7 @@ func (o *Community) CreateChat(chatID string, chat *protobuf.CommunityChat) (*Co
|
||||||
|
|
||||||
o.increaseClock()
|
o.increaseClock()
|
||||||
|
|
||||||
changes := emptyCommunityChanges()
|
changes := o.emptyCommunityChanges()
|
||||||
changes.ChatsAdded[chatID] = chat
|
changes.ChatsAdded[chatID] = chat
|
||||||
return changes, nil
|
return changes, nil
|
||||||
}
|
}
|
||||||
|
@ -221,11 +309,32 @@ func (o *Community) InviteUserToChat(pk *ecdsa.PublicKey, chatID string) (*proto
|
||||||
return response, nil
|
return response, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Community) hasMember(pk *ecdsa.PublicKey) bool {
|
func (o *Community) getMember(pk *ecdsa.PublicKey) *protobuf.CommunityMember {
|
||||||
|
|
||||||
key := common.PubkeyToHex(pk)
|
key := common.PubkeyToHex(pk)
|
||||||
_, ok := o.config.CommunityDescription.Members[key]
|
member := o.config.CommunityDescription.Members[key]
|
||||||
return ok
|
return member
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Community) hasMember(pk *ecdsa.PublicKey) bool {
|
||||||
|
|
||||||
|
member := o.getMember(pk)
|
||||||
|
return member != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Community) hasPermission(pk *ecdsa.PublicKey, role protobuf.CommunityMember_Roles) bool {
|
||||||
|
member := o.getMember(pk)
|
||||||
|
if member == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, r := range member.Roles {
|
||||||
|
if r == role {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Community) HasMember(pk *ecdsa.PublicKey) bool {
|
func (o *Community) HasMember(pk *ecdsa.PublicKey) bool {
|
||||||
|
@ -294,20 +403,11 @@ func (o *Community) RemoveUserFromOrg(pk *ecdsa.PublicKey) (*protobuf.CommunityD
|
||||||
delete(chat.Members, key)
|
delete(chat.Members, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
o.increaseClock()
|
||||||
|
|
||||||
return o.config.CommunityDescription, nil
|
return o.config.CommunityDescription, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: this should accept a request from a user to join and perform any validation
|
|
||||||
func (o *Community) AcceptRequestToJoin(pk *ecdsa.PublicKey) (*protobuf.CommunityRequestJoinResponse, error) {
|
|
||||||
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: this should decline a request from a user to join
|
|
||||||
func (o *Community) DeclineRequestToJoin(pk *ecdsa.PublicKey) (*protobuf.CommunityRequestJoinResponse, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Community) Join() {
|
func (o *Community) Join() {
|
||||||
o.config.Joined = true
|
o.config.Joined = true
|
||||||
}
|
}
|
||||||
|
@ -320,7 +420,8 @@ func (o *Community) Joined() bool {
|
||||||
return o.config.Joined
|
return o.config.Joined
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Community) HandleCommunityDescription(signer *ecdsa.PublicKey, description *protobuf.CommunityDescription, rawMessage []byte) (*CommunityChanges, error) {
|
// UpdateCommunityDescription will update the community to the new community description and return a list of changes
|
||||||
|
func (o *Community) UpdateCommunityDescription(signer *ecdsa.PublicKey, description *protobuf.CommunityDescription, rawMessage []byte) (*CommunityChanges, error) {
|
||||||
o.mutex.Lock()
|
o.mutex.Lock()
|
||||||
defer o.mutex.Unlock()
|
defer o.mutex.Unlock()
|
||||||
|
|
||||||
|
@ -333,14 +434,14 @@ func (o *Community) HandleCommunityDescription(signer *ecdsa.PublicKey, descript
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
response := emptyCommunityChanges()
|
response := o.emptyCommunityChanges()
|
||||||
|
|
||||||
if description.Clock <= o.config.CommunityDescription.Clock {
|
if description.Clock <= o.config.CommunityDescription.Clock {
|
||||||
return response, nil
|
return response, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// We only calculate changes if we joined the org, otherwise not interested
|
// We only calculate changes if we joined the community or we requested access, otherwise not interested
|
||||||
if o.config.Joined {
|
if o.config.Joined || o.config.RequestedToJoinAt > 0 {
|
||||||
// Check for new members at the org level
|
// Check for new members at the org level
|
||||||
for pk, member := range description.Members {
|
for pk, member := range description.Members {
|
||||||
if _, ok := o.config.CommunityDescription.Members[pk]; !ok {
|
if _, ok := o.config.CommunityDescription.Members[pk]; !ok {
|
||||||
|
@ -423,8 +524,8 @@ func (o *Community) HandleCommunityDescription(signer *ecdsa.PublicKey, descript
|
||||||
return response, nil
|
return response, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleRequestJoin handles a request, checks that the right permissions are applied and returns an CommunityRequestJoinResponse
|
// ValidateRequestToJoin validates a request, checks that the right permissions are applied
|
||||||
func (o *Community) HandleRequestJoin(signer *ecdsa.PublicKey, request *protobuf.CommunityRequestJoin) error {
|
func (o *Community) ValidateRequestToJoin(signer *ecdsa.PublicKey, request *protobuf.CommunityRequestToJoin) error {
|
||||||
o.mutex.Lock()
|
o.mutex.Lock()
|
||||||
defer o.mutex.Unlock()
|
defer o.mutex.Unlock()
|
||||||
|
|
||||||
|
@ -439,15 +540,14 @@ func (o *Community) HandleRequestJoin(signer *ecdsa.PublicKey, request *protobuf
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(request.ChatId) != 0 {
|
if len(request.ChatId) != 0 {
|
||||||
return o.handleRequestJoinWithChatID(request)
|
return o.validateRequestToJoinWithChatID(request)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := o.handleRequestJoinWithoutChatID(request)
|
err := o.validateRequestToJoinWithoutChatID(request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store request to join
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -455,7 +555,7 @@ func (o *Community) IsAdmin() bool {
|
||||||
return o.config.PrivateKey != nil
|
return o.config.PrivateKey != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Community) handleRequestJoinWithChatID(request *protobuf.CommunityRequestJoin) error {
|
func (o *Community) validateRequestToJoinWithChatID(request *protobuf.CommunityRequestToJoin) error {
|
||||||
|
|
||||||
chat, ok := o.config.CommunityDescription.Chats[request.ChatId]
|
chat, ok := o.config.CommunityDescription.Chats[request.ChatId]
|
||||||
|
|
||||||
|
@ -475,7 +575,15 @@ func (o *Community) handleRequestJoinWithChatID(request *protobuf.CommunityReque
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Community) handleRequestJoinWithoutChatID(request *protobuf.CommunityRequestJoin) error {
|
func (o *Community) OnRequest() bool {
|
||||||
|
return o.config.CommunityDescription.Permissions.Access == protobuf.CommunityPermissions_ON_REQUEST
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Community) InvitationOnly() bool {
|
||||||
|
return o.config.CommunityDescription.Permissions.Access == protobuf.CommunityPermissions_INVITATION_ONLY
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Community) validateRequestToJoinWithoutChatID(request *protobuf.CommunityRequestToJoin) error {
|
||||||
|
|
||||||
// If they want access to the org only, check that the org is ON_REQUEST
|
// If they want access to the org only, check that the org is ON_REQUEST
|
||||||
if o.config.CommunityDescription.Permissions.Access != protobuf.CommunityPermissions_ON_REQUEST {
|
if o.config.CommunityDescription.Permissions.Access != protobuf.CommunityPermissions_ON_REQUEST {
|
||||||
|
@ -485,7 +593,7 @@ func (o *Community) handleRequestJoinWithoutChatID(request *protobuf.CommunityRe
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Community) ID() []byte {
|
func (o *Community) ID() types.HexBytes {
|
||||||
return crypto.CompressPubkey(o.config.ID)
|
return crypto.CompressPubkey(o.config.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -497,6 +605,10 @@ func (o *Community) PrivateKey() *ecdsa.PrivateKey {
|
||||||
return o.config.PrivateKey
|
return o.config.PrivateKey
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *Community) PublicKey() *ecdsa.PublicKey {
|
||||||
|
return o.config.ID
|
||||||
|
}
|
||||||
|
|
||||||
func (o *Community) marshaledDescription() ([]byte, error) {
|
func (o *Community) marshaledDescription() ([]byte, error) {
|
||||||
return proto.Marshal(o.config.CommunityDescription)
|
return proto.Marshal(o.config.CommunityDescription)
|
||||||
}
|
}
|
||||||
|
@ -702,6 +814,77 @@ func (o *Community) increaseClock() {
|
||||||
o.config.CommunityDescription.Clock = o.nextClock()
|
o.config.CommunityDescription.Clock = o.nextClock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *Community) Clock() uint64 {
|
||||||
|
return o.config.CommunityDescription.Clock
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Community) CanRequestAccess(pk *ecdsa.PublicKey) bool {
|
||||||
|
if o.hasMember(pk) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if o.config.CommunityDescription == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if o.config.CommunityDescription.Permissions == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return o.config.CommunityDescription.Permissions.Access == protobuf.CommunityPermissions_ON_REQUEST
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Community) CanManageUsers(pk *ecdsa.PublicKey) bool {
|
||||||
|
o.mutex.Lock()
|
||||||
|
defer o.mutex.Unlock()
|
||||||
|
|
||||||
|
if o.IsAdmin() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if !o.hasMember(pk) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return o.hasPermission(pk, protobuf.CommunityMember_ROLE_ALL) || o.hasPermission(pk, protobuf.CommunityMember_ROLE_MANAGE_USERS)
|
||||||
|
|
||||||
|
}
|
||||||
|
func (o *Community) isMember() bool {
|
||||||
|
return o.hasMember(o.config.MemberIdentity)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CanJoin returns whether a user can join the community, only if it's
|
||||||
|
func (o *Community) canJoin() bool {
|
||||||
|
if o.config.Joined {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if o.IsAdmin() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if o.config.CommunityDescription.Permissions.Access == protobuf.CommunityPermissions_NO_MEMBERSHIP {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return o.isMember()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Community) RequestedToJoinAt() uint64 {
|
||||||
|
return o.config.RequestedToJoinAt
|
||||||
|
}
|
||||||
|
|
||||||
func (o *Community) nextClock() uint64 {
|
func (o *Community) nextClock() uint64 {
|
||||||
return o.config.CommunityDescription.Clock + 1
|
return o.config.CommunityDescription.Clock + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func emptyCommunityChanges() *CommunityChanges {
|
||||||
|
return &CommunityChanges{
|
||||||
|
MembersAdded: make(map[string]*protobuf.CommunityMember),
|
||||||
|
MembersRemoved: make(map[string]*protobuf.CommunityMember),
|
||||||
|
|
||||||
|
ChatsRemoved: make(map[string]*protobuf.CommunityChat),
|
||||||
|
ChatsAdded: make(map[string]*protobuf.CommunityChat),
|
||||||
|
ChatsModified: make(map[string]*CommunityChatChanges),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -271,7 +271,7 @@ func (s *CommunitySuite) TestDeclineRequestToJoin() {
|
||||||
// TEST CASE 3: Valid
|
// TEST CASE 3: Valid
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *CommunitySuite) TestHandleRequestJoin() {
|
func (s *CommunitySuite) TestValidateRequestToJoin() {
|
||||||
description := &protobuf.CommunityDescription{}
|
description := &protobuf.CommunityDescription{}
|
||||||
|
|
||||||
key, err := crypto.GenerateKey()
|
key, err := crypto.GenerateKey()
|
||||||
|
@ -279,22 +279,22 @@ func (s *CommunitySuite) TestHandleRequestJoin() {
|
||||||
|
|
||||||
signer := &key.PublicKey
|
signer := &key.PublicKey
|
||||||
|
|
||||||
request := &protobuf.CommunityRequestJoin{
|
request := &protobuf.CommunityRequestToJoin{
|
||||||
EnsName: "donvanvliet.stateofus.eth",
|
EnsName: "donvanvliet.stateofus.eth",
|
||||||
CommunityId: s.communityID,
|
CommunityId: s.communityID,
|
||||||
}
|
}
|
||||||
|
|
||||||
requestWithChatID := &protobuf.CommunityRequestJoin{
|
requestWithChatID := &protobuf.CommunityRequestToJoin{
|
||||||
EnsName: "donvanvliet.stateofus.eth",
|
EnsName: "donvanvliet.stateofus.eth",
|
||||||
CommunityId: s.communityID,
|
CommunityId: s.communityID,
|
||||||
ChatId: testChatID1,
|
ChatId: testChatID1,
|
||||||
}
|
}
|
||||||
|
|
||||||
requestWithoutENS := &protobuf.CommunityRequestJoin{
|
requestWithoutENS := &protobuf.CommunityRequestToJoin{
|
||||||
CommunityId: s.communityID,
|
CommunityId: s.communityID,
|
||||||
}
|
}
|
||||||
|
|
||||||
requestWithChatWithoutENS := &protobuf.CommunityRequestJoin{
|
requestWithChatWithoutENS := &protobuf.CommunityRequestToJoin{
|
||||||
CommunityId: s.communityID,
|
CommunityId: s.communityID,
|
||||||
ChatId: testChatID1,
|
ChatId: testChatID1,
|
||||||
}
|
}
|
||||||
|
@ -313,7 +313,7 @@ func (s *CommunitySuite) TestHandleRequestJoin() {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
config Config
|
config Config
|
||||||
request *protobuf.CommunityRequestJoin
|
request *protobuf.CommunityRequestToJoin
|
||||||
signer *ecdsa.PublicKey
|
signer *ecdsa.PublicKey
|
||||||
err error
|
err error
|
||||||
}{
|
}{
|
||||||
|
@ -326,7 +326,7 @@ func (s *CommunitySuite) TestHandleRequestJoin() {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "not admin",
|
name: "not admin",
|
||||||
config: Config{CommunityDescription: description},
|
config: Config{MemberIdentity: signer, CommunityDescription: description},
|
||||||
signer: signer,
|
signer: signer,
|
||||||
request: request,
|
request: request,
|
||||||
err: ErrNotAdmin,
|
err: ErrNotAdmin,
|
||||||
|
@ -421,7 +421,7 @@ func (s *CommunitySuite) TestHandleRequestJoin() {
|
||||||
s.Run(tc.name, func() {
|
s.Run(tc.name, func() {
|
||||||
org, err := New(tc.config)
|
org, err := New(tc.config)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
err = org.HandleRequestJoin(tc.signer, tc.request)
|
err = org.ValidateRequestToJoin(tc.signer, tc.request)
|
||||||
s.Require().Equal(tc.err, err)
|
s.Require().Equal(tc.err, err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -543,6 +543,10 @@ func (s *CommunitySuite) TestHandleCommunityDescription() {
|
||||||
|
|
||||||
signer := &key.PublicKey
|
signer := &key.PublicKey
|
||||||
|
|
||||||
|
buildChanges := func(c *Community) *CommunityChanges {
|
||||||
|
return c.emptyCommunityChanges()
|
||||||
|
}
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
description func(*Community) *protobuf.CommunityDescription
|
description func(*Community) *protobuf.CommunityDescription
|
||||||
|
@ -554,14 +558,14 @@ func (s *CommunitySuite) TestHandleCommunityDescription() {
|
||||||
name: "updated version but no changes",
|
name: "updated version but no changes",
|
||||||
description: s.identicalCommunityDescription,
|
description: s.identicalCommunityDescription,
|
||||||
signer: signer,
|
signer: signer,
|
||||||
changes: func(_ *Community) *CommunityChanges { return emptyCommunityChanges() },
|
changes: buildChanges,
|
||||||
err: nil,
|
err: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "updated version but lower clock",
|
name: "updated version but lower clock",
|
||||||
description: s.oldCommunityDescription,
|
description: s.oldCommunityDescription,
|
||||||
signer: signer,
|
signer: signer,
|
||||||
changes: func(_ *Community) *CommunityChanges { return emptyCommunityChanges() },
|
changes: buildChanges,
|
||||||
err: nil,
|
err: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -569,7 +573,7 @@ func (s *CommunitySuite) TestHandleCommunityDescription() {
|
||||||
description: s.removedMemberCommunityDescription,
|
description: s.removedMemberCommunityDescription,
|
||||||
signer: signer,
|
signer: signer,
|
||||||
changes: func(org *Community) *CommunityChanges {
|
changes: func(org *Community) *CommunityChanges {
|
||||||
changes := emptyCommunityChanges()
|
changes := org.emptyCommunityChanges()
|
||||||
changes.MembersRemoved[s.member1Key] = &protobuf.CommunityMember{}
|
changes.MembersRemoved[s.member1Key] = &protobuf.CommunityMember{}
|
||||||
changes.ChatsModified[testChatID1] = &CommunityChatChanges{
|
changes.ChatsModified[testChatID1] = &CommunityChatChanges{
|
||||||
MembersAdded: make(map[string]*protobuf.CommunityMember),
|
MembersAdded: make(map[string]*protobuf.CommunityMember),
|
||||||
|
@ -586,7 +590,7 @@ func (s *CommunitySuite) TestHandleCommunityDescription() {
|
||||||
description: s.addedMemberCommunityDescription,
|
description: s.addedMemberCommunityDescription,
|
||||||
signer: signer,
|
signer: signer,
|
||||||
changes: func(org *Community) *CommunityChanges {
|
changes: func(org *Community) *CommunityChanges {
|
||||||
changes := emptyCommunityChanges()
|
changes := org.emptyCommunityChanges()
|
||||||
changes.MembersAdded[s.member3Key] = &protobuf.CommunityMember{}
|
changes.MembersAdded[s.member3Key] = &protobuf.CommunityMember{}
|
||||||
changes.ChatsModified[testChatID1] = &CommunityChatChanges{
|
changes.ChatsModified[testChatID1] = &CommunityChatChanges{
|
||||||
MembersAdded: make(map[string]*protobuf.CommunityMember),
|
MembersAdded: make(map[string]*protobuf.CommunityMember),
|
||||||
|
@ -603,7 +607,7 @@ func (s *CommunitySuite) TestHandleCommunityDescription() {
|
||||||
description: s.addedChatCommunityDescription,
|
description: s.addedChatCommunityDescription,
|
||||||
signer: signer,
|
signer: signer,
|
||||||
changes: func(org *Community) *CommunityChanges {
|
changes: func(org *Community) *CommunityChanges {
|
||||||
changes := emptyCommunityChanges()
|
changes := org.emptyCommunityChanges()
|
||||||
changes.MembersAdded[s.member3Key] = &protobuf.CommunityMember{}
|
changes.MembersAdded[s.member3Key] = &protobuf.CommunityMember{}
|
||||||
changes.ChatsAdded[testChatID2] = &protobuf.CommunityChat{Permissions: &protobuf.CommunityPermissions{Access: protobuf.CommunityPermissions_INVITATION_ONLY}, Members: make(map[string]*protobuf.CommunityMember)}
|
changes.ChatsAdded[testChatID2] = &protobuf.CommunityChat{Permissions: &protobuf.CommunityPermissions{Access: protobuf.CommunityPermissions_INVITATION_ONLY}, Members: make(map[string]*protobuf.CommunityMember)}
|
||||||
changes.ChatsAdded[testChatID2].Members[s.member3Key] = &protobuf.CommunityMember{}
|
changes.ChatsAdded[testChatID2].Members[s.member3Key] = &protobuf.CommunityMember{}
|
||||||
|
@ -617,7 +621,7 @@ func (s *CommunitySuite) TestHandleCommunityDescription() {
|
||||||
description: s.removedChatCommunityDescription,
|
description: s.removedChatCommunityDescription,
|
||||||
signer: signer,
|
signer: signer,
|
||||||
changes: func(org *Community) *CommunityChanges {
|
changes: func(org *Community) *CommunityChanges {
|
||||||
changes := emptyCommunityChanges()
|
changes := org.emptyCommunityChanges()
|
||||||
changes.ChatsRemoved[testChatID1] = org.config.CommunityDescription.Chats[testChatID1]
|
changes.ChatsRemoved[testChatID1] = org.config.CommunityDescription.Chats[testChatID1]
|
||||||
|
|
||||||
return changes
|
return changes
|
||||||
|
@ -631,7 +635,7 @@ func (s *CommunitySuite) TestHandleCommunityDescription() {
|
||||||
org := s.buildCommunity(signer)
|
org := s.buildCommunity(signer)
|
||||||
org.Join()
|
org.Join()
|
||||||
expectedChanges := tc.changes(org)
|
expectedChanges := tc.changes(org)
|
||||||
actualChanges, err := org.HandleCommunityDescription(tc.signer, tc.description(org), []byte{0x01})
|
actualChanges, err := org.UpdateCommunityDescription(tc.signer, tc.description(org), []byte{0x01})
|
||||||
s.Require().Equal(tc.err, err)
|
s.Require().Equal(tc.err, err)
|
||||||
s.Require().Equal(expectedChanges, actualChanges)
|
s.Require().Equal(expectedChanges, actualChanges)
|
||||||
})
|
})
|
||||||
|
@ -712,102 +716,74 @@ func (s *CommunitySuite) emptyCommunityDescriptionWithChat() *protobuf.Community
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *CommunitySuite) newConfig(identity *ecdsa.PrivateKey, description *protobuf.CommunityDescription) Config {
|
||||||
|
return Config{
|
||||||
|
MemberIdentity: &identity.PublicKey,
|
||||||
|
ID: &identity.PublicKey,
|
||||||
|
CommunityDescription: description,
|
||||||
|
PrivateKey: identity,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *CommunitySuite) configOnRequest() Config {
|
func (s *CommunitySuite) configOnRequest() Config {
|
||||||
description := s.emptyCommunityDescription()
|
description := s.emptyCommunityDescription()
|
||||||
description.Permissions.Access = protobuf.CommunityPermissions_ON_REQUEST
|
description.Permissions.Access = protobuf.CommunityPermissions_ON_REQUEST
|
||||||
return Config{
|
return s.newConfig(s.identity, description)
|
||||||
ID: &s.identity.PublicKey,
|
|
||||||
CommunityDescription: description,
|
|
||||||
PrivateKey: s.identity,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *CommunitySuite) configInvitationOnly() Config {
|
func (s *CommunitySuite) configInvitationOnly() Config {
|
||||||
description := s.emptyCommunityDescription()
|
description := s.emptyCommunityDescription()
|
||||||
description.Permissions.Access = protobuf.CommunityPermissions_INVITATION_ONLY
|
description.Permissions.Access = protobuf.CommunityPermissions_INVITATION_ONLY
|
||||||
return Config{
|
return s.newConfig(s.identity, description)
|
||||||
ID: &s.identity.PublicKey,
|
|
||||||
CommunityDescription: description,
|
|
||||||
PrivateKey: s.identity,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *CommunitySuite) configNoMembershipOrgNoMembershipChat() Config {
|
func (s *CommunitySuite) configNoMembershipOrgNoMembershipChat() Config {
|
||||||
description := s.emptyCommunityDescriptionWithChat()
|
description := s.emptyCommunityDescriptionWithChat()
|
||||||
description.Permissions.Access = protobuf.CommunityPermissions_NO_MEMBERSHIP
|
description.Permissions.Access = protobuf.CommunityPermissions_NO_MEMBERSHIP
|
||||||
description.Chats[testChatID1].Permissions.Access = protobuf.CommunityPermissions_NO_MEMBERSHIP
|
description.Chats[testChatID1].Permissions.Access = protobuf.CommunityPermissions_NO_MEMBERSHIP
|
||||||
return Config{
|
return s.newConfig(s.identity, description)
|
||||||
ID: &s.identity.PublicKey,
|
|
||||||
CommunityDescription: description,
|
|
||||||
PrivateKey: s.identity,
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *CommunitySuite) configNoMembershipOrgInvitationOnlyChat() Config {
|
func (s *CommunitySuite) configNoMembershipOrgInvitationOnlyChat() Config {
|
||||||
description := s.emptyCommunityDescriptionWithChat()
|
description := s.emptyCommunityDescriptionWithChat()
|
||||||
description.Permissions.Access = protobuf.CommunityPermissions_NO_MEMBERSHIP
|
description.Permissions.Access = protobuf.CommunityPermissions_NO_MEMBERSHIP
|
||||||
description.Chats[testChatID1].Permissions.Access = protobuf.CommunityPermissions_INVITATION_ONLY
|
description.Chats[testChatID1].Permissions.Access = protobuf.CommunityPermissions_INVITATION_ONLY
|
||||||
return Config{
|
return s.newConfig(s.identity, description)
|
||||||
ID: &s.identity.PublicKey,
|
|
||||||
CommunityDescription: description,
|
|
||||||
PrivateKey: s.identity,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *CommunitySuite) configInvitationOnlyOrgInvitationOnlyChat() Config {
|
func (s *CommunitySuite) configInvitationOnlyOrgInvitationOnlyChat() Config {
|
||||||
description := s.emptyCommunityDescriptionWithChat()
|
description := s.emptyCommunityDescriptionWithChat()
|
||||||
description.Permissions.Access = protobuf.CommunityPermissions_INVITATION_ONLY
|
description.Permissions.Access = protobuf.CommunityPermissions_INVITATION_ONLY
|
||||||
description.Chats[testChatID1].Permissions.Access = protobuf.CommunityPermissions_INVITATION_ONLY
|
description.Chats[testChatID1].Permissions.Access = protobuf.CommunityPermissions_INVITATION_ONLY
|
||||||
return Config{
|
return s.newConfig(s.identity, description)
|
||||||
ID: &s.identity.PublicKey,
|
|
||||||
CommunityDescription: description,
|
|
||||||
PrivateKey: s.identity,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *CommunitySuite) configNoMembershipOrgOnRequestChat() Config {
|
func (s *CommunitySuite) configNoMembershipOrgOnRequestChat() Config {
|
||||||
description := s.emptyCommunityDescriptionWithChat()
|
description := s.emptyCommunityDescriptionWithChat()
|
||||||
description.Permissions.Access = protobuf.CommunityPermissions_NO_MEMBERSHIP
|
description.Permissions.Access = protobuf.CommunityPermissions_NO_MEMBERSHIP
|
||||||
description.Chats[testChatID1].Permissions.Access = protobuf.CommunityPermissions_ON_REQUEST
|
description.Chats[testChatID1].Permissions.Access = protobuf.CommunityPermissions_ON_REQUEST
|
||||||
return Config{
|
return s.newConfig(s.identity, description)
|
||||||
ID: &s.identity.PublicKey,
|
|
||||||
CommunityDescription: description,
|
|
||||||
PrivateKey: s.identity,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *CommunitySuite) configOnRequestOrgOnRequestChat() Config {
|
func (s *CommunitySuite) configOnRequestOrgOnRequestChat() Config {
|
||||||
description := s.emptyCommunityDescriptionWithChat()
|
description := s.emptyCommunityDescriptionWithChat()
|
||||||
description.Permissions.Access = protobuf.CommunityPermissions_ON_REQUEST
|
description.Permissions.Access = protobuf.CommunityPermissions_ON_REQUEST
|
||||||
description.Chats[testChatID1].Permissions.Access = protobuf.CommunityPermissions_ON_REQUEST
|
description.Chats[testChatID1].Permissions.Access = protobuf.CommunityPermissions_ON_REQUEST
|
||||||
return Config{
|
return s.newConfig(s.identity, description)
|
||||||
ID: &s.identity.PublicKey,
|
|
||||||
CommunityDescription: description,
|
|
||||||
PrivateKey: s.identity,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *CommunitySuite) configOnRequestOrgInvitationOnlyChat() Config {
|
func (s *CommunitySuite) configOnRequestOrgInvitationOnlyChat() Config {
|
||||||
description := s.emptyCommunityDescriptionWithChat()
|
description := s.emptyCommunityDescriptionWithChat()
|
||||||
description.Permissions.Access = protobuf.CommunityPermissions_ON_REQUEST
|
description.Permissions.Access = protobuf.CommunityPermissions_ON_REQUEST
|
||||||
description.Chats[testChatID1].Permissions.Access = protobuf.CommunityPermissions_INVITATION_ONLY
|
description.Chats[testChatID1].Permissions.Access = protobuf.CommunityPermissions_INVITATION_ONLY
|
||||||
return Config{
|
return s.newConfig(s.identity, description)
|
||||||
ID: &s.identity.PublicKey,
|
|
||||||
CommunityDescription: description,
|
|
||||||
PrivateKey: s.identity,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *CommunitySuite) configOnRequestOrgNoMembershipChat() Config {
|
func (s *CommunitySuite) configOnRequestOrgNoMembershipChat() Config {
|
||||||
description := s.emptyCommunityDescriptionWithChat()
|
description := s.emptyCommunityDescriptionWithChat()
|
||||||
description.Permissions.Access = protobuf.CommunityPermissions_ON_REQUEST
|
description.Permissions.Access = protobuf.CommunityPermissions_ON_REQUEST
|
||||||
description.Chats[testChatID1].Permissions.Access = protobuf.CommunityPermissions_NO_MEMBERSHIP
|
description.Chats[testChatID1].Permissions.Access = protobuf.CommunityPermissions_NO_MEMBERSHIP
|
||||||
return Config{
|
return s.newConfig(s.identity, description)
|
||||||
ID: &s.identity.PublicKey,
|
|
||||||
CommunityDescription: description,
|
|
||||||
PrivateKey: s.identity,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *CommunitySuite) configChatENSOnly() Config {
|
func (s *CommunitySuite) configChatENSOnly() Config {
|
||||||
|
@ -815,22 +791,14 @@ func (s *CommunitySuite) configChatENSOnly() Config {
|
||||||
description.Permissions.Access = protobuf.CommunityPermissions_ON_REQUEST
|
description.Permissions.Access = protobuf.CommunityPermissions_ON_REQUEST
|
||||||
description.Chats[testChatID1].Permissions.Access = protobuf.CommunityPermissions_ON_REQUEST
|
description.Chats[testChatID1].Permissions.Access = protobuf.CommunityPermissions_ON_REQUEST
|
||||||
description.Chats[testChatID1].Permissions.EnsOnly = true
|
description.Chats[testChatID1].Permissions.EnsOnly = true
|
||||||
return Config{
|
return s.newConfig(s.identity, description)
|
||||||
ID: &s.identity.PublicKey,
|
|
||||||
CommunityDescription: description,
|
|
||||||
PrivateKey: s.identity,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *CommunitySuite) configENSOnly() Config {
|
func (s *CommunitySuite) configENSOnly() Config {
|
||||||
description := s.emptyCommunityDescription()
|
description := s.emptyCommunityDescription()
|
||||||
description.Permissions.Access = protobuf.CommunityPermissions_ON_REQUEST
|
description.Permissions.Access = protobuf.CommunityPermissions_ON_REQUEST
|
||||||
description.Permissions.EnsOnly = true
|
description.Permissions.EnsOnly = true
|
||||||
return Config{
|
return s.newConfig(s.identity, description)
|
||||||
ID: &s.identity.PublicKey,
|
|
||||||
CommunityDescription: description,
|
|
||||||
PrivateKey: s.identity,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *CommunitySuite) config() Config {
|
func (s *CommunitySuite) config() Config {
|
||||||
|
|
|
@ -15,4 +15,5 @@ var ErrInvalidCommunityDescriptionMemberInChatButNotInOrg = errors.New("invalid
|
||||||
var ErrNotAdmin = errors.New("no admin privileges for this community")
|
var ErrNotAdmin = errors.New("no admin privileges for this community")
|
||||||
var ErrInvalidGrant = errors.New("invalid grant")
|
var ErrInvalidGrant = errors.New("invalid grant")
|
||||||
var ErrNotAuthorized = errors.New("not authorized")
|
var ErrNotAuthorized = errors.New("not authorized")
|
||||||
|
var ErrAlreadyMember = errors.New("already a member")
|
||||||
var ErrInvalidMessage = errors.New("invalid community description message")
|
var ErrInvalidMessage = errors.New("invalid community description message")
|
||||||
|
|
|
@ -3,6 +3,7 @@ package communities
|
||||||
import (
|
import (
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
|
|
||||||
|
@ -12,16 +13,27 @@ import (
|
||||||
|
|
||||||
"github.com/status-im/status-go/eth-node/crypto"
|
"github.com/status-im/status-go/eth-node/crypto"
|
||||||
"github.com/status-im/status-go/eth-node/types"
|
"github.com/status-im/status-go/eth-node/types"
|
||||||
|
"github.com/status-im/status-go/protocol/common"
|
||||||
|
"github.com/status-im/status-go/protocol/ens"
|
||||||
"github.com/status-im/status-go/protocol/protobuf"
|
"github.com/status-im/status-go/protocol/protobuf"
|
||||||
|
"github.com/status-im/status-go/protocol/requests"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Manager struct {
|
type Manager struct {
|
||||||
persistence *Persistence
|
persistence *Persistence
|
||||||
subscriptions []chan *Subscription
|
ensSubscription chan []*ens.VerificationRecord
|
||||||
logger *zap.Logger
|
subscriptions []chan *Subscription
|
||||||
|
ensVerifier *ens.Verifier
|
||||||
|
identity *ecdsa.PublicKey
|
||||||
|
logger *zap.Logger
|
||||||
|
quit chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewManager(db *sql.DB, logger *zap.Logger) (*Manager, error) {
|
func NewManager(identity *ecdsa.PublicKey, db *sql.DB, logger *zap.Logger, verifier *ens.Verifier) (*Manager, error) {
|
||||||
|
if identity == nil {
|
||||||
|
return nil, errors.New("empty identity")
|
||||||
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
if logger, err = zap.NewDevelopment(); err != nil {
|
if logger, err = zap.NewDevelopment(); err != nil {
|
||||||
|
@ -29,18 +41,34 @@ func NewManager(db *sql.DB, logger *zap.Logger) (*Manager, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Manager{
|
manager := &Manager{
|
||||||
logger: logger,
|
logger: logger,
|
||||||
|
identity: identity,
|
||||||
|
quit: make(chan struct{}),
|
||||||
persistence: &Persistence{
|
persistence: &Persistence{
|
||||||
logger: logger,
|
logger: logger,
|
||||||
db: db,
|
db: db,
|
||||||
},
|
},
|
||||||
}, nil
|
}
|
||||||
|
|
||||||
|
if verifier != nil {
|
||||||
|
|
||||||
|
sub := verifier.Subscribe()
|
||||||
|
manager.ensSubscription = sub
|
||||||
|
manager.ensVerifier = verifier
|
||||||
|
}
|
||||||
|
|
||||||
|
return manager, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type Subscription struct {
|
type Subscription struct {
|
||||||
Community *Community
|
Community *Community
|
||||||
Invitation *protobuf.CommunityInvitation
|
Invitations []*protobuf.CommunityInvitation
|
||||||
|
}
|
||||||
|
|
||||||
|
type CommunityResponse struct {
|
||||||
|
Community *Community `json:"community"`
|
||||||
|
Changes *CommunityChanges `json:"changes"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) Subscribe() chan *Subscription {
|
func (m *Manager) Subscribe() chan *Subscription {
|
||||||
|
@ -49,7 +77,34 @@ func (m *Manager) Subscribe() chan *Subscription {
|
||||||
return subscription
|
return subscription
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Manager) Start() error {
|
||||||
|
if m.ensVerifier != nil {
|
||||||
|
m.runENSVerificationLoop()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Manager) runENSVerificationLoop() {
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-m.quit:
|
||||||
|
m.logger.Debug("quitting ens verification loop")
|
||||||
|
return
|
||||||
|
case records, more := <-m.ensSubscription:
|
||||||
|
if !more {
|
||||||
|
m.logger.Debug("no more ens records, quitting")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
m.logger.Info("received records", zap.Any("records", records))
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
func (m *Manager) Stop() error {
|
func (m *Manager) Stop() error {
|
||||||
|
close(m.quit)
|
||||||
for _, c := range m.subscriptions {
|
for _, c := range m.subscriptions {
|
||||||
close(c)
|
close(c)
|
||||||
}
|
}
|
||||||
|
@ -67,15 +122,15 @@ func (m *Manager) publish(subscription *Subscription) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) All() ([]*Community, error) {
|
func (m *Manager) All() ([]*Community, error) {
|
||||||
return m.persistence.AllCommunities()
|
return m.persistence.AllCommunities(m.identity)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) Joined() ([]*Community, error) {
|
func (m *Manager) Joined() ([]*Community, error) {
|
||||||
return m.persistence.JoinedCommunities()
|
return m.persistence.JoinedCommunities(m.identity)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) Created() ([]*Community, error) {
|
func (m *Manager) Created() ([]*Community, error) {
|
||||||
return m.persistence.CreatedCommunities()
|
return m.persistence.CreatedCommunities(m.identity)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateCommunity takes a description, generates an ID for it, saves it and return it
|
// CreateCommunity takes a description, generates an ID for it, saves it and return it
|
||||||
|
@ -97,6 +152,7 @@ func (m *Manager) CreateCommunity(description *protobuf.CommunityDescription) (*
|
||||||
PrivateKey: key,
|
PrivateKey: key,
|
||||||
Logger: m.logger,
|
Logger: m.logger,
|
||||||
Joined: true,
|
Joined: true,
|
||||||
|
MemberIdentity: m.identity,
|
||||||
CommunityDescription: description,
|
CommunityDescription: description,
|
||||||
}
|
}
|
||||||
community, err := New(config)
|
community, err := New(config)
|
||||||
|
@ -104,6 +160,9 @@ func (m *Manager) CreateCommunity(description *protobuf.CommunityDescription) (*
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We join any community we create
|
||||||
|
community.Join()
|
||||||
|
|
||||||
err = m.persistence.SaveCommunity(community)
|
err = m.persistence.SaveCommunity(community)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -114,8 +173,8 @@ func (m *Manager) CreateCommunity(description *protobuf.CommunityDescription) (*
|
||||||
return community, nil
|
return community, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) ExportCommunity(idString string) (*ecdsa.PrivateKey, error) {
|
func (m *Manager) ExportCommunity(id types.HexBytes) (*ecdsa.PrivateKey, error) {
|
||||||
community, err := m.GetByIDString(idString)
|
community, err := m.GetByID(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -130,7 +189,7 @@ func (m *Manager) ExportCommunity(idString string) (*ecdsa.PrivateKey, error) {
|
||||||
func (m *Manager) ImportCommunity(key *ecdsa.PrivateKey) (*Community, error) {
|
func (m *Manager) ImportCommunity(key *ecdsa.PrivateKey) (*Community, error) {
|
||||||
communityID := crypto.CompressPubkey(&key.PublicKey)
|
communityID := crypto.CompressPubkey(&key.PublicKey)
|
||||||
|
|
||||||
community, err := m.persistence.GetByID(communityID)
|
community, err := m.persistence.GetByID(m.identity, communityID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -145,6 +204,7 @@ func (m *Manager) ImportCommunity(key *ecdsa.PrivateKey) (*Community, error) {
|
||||||
PrivateKey: key,
|
PrivateKey: key,
|
||||||
Logger: m.logger,
|
Logger: m.logger,
|
||||||
Joined: true,
|
Joined: true,
|
||||||
|
MemberIdentity: m.identity,
|
||||||
CommunityDescription: description,
|
CommunityDescription: description,
|
||||||
}
|
}
|
||||||
community, err = New(config)
|
community, err = New(config)
|
||||||
|
@ -163,8 +223,8 @@ func (m *Manager) ImportCommunity(key *ecdsa.PrivateKey) (*Community, error) {
|
||||||
return community, nil
|
return community, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) CreateChat(idString string, chat *protobuf.CommunityChat) (*Community, *CommunityChanges, error) {
|
func (m *Manager) CreateChat(communityID types.HexBytes, chat *protobuf.CommunityChat) (*Community, *CommunityChanges, error) {
|
||||||
community, err := m.GetByIDString(idString)
|
community, err := m.GetByID(communityID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
@ -188,9 +248,9 @@ func (m *Manager) CreateChat(idString string, chat *protobuf.CommunityChat) (*Co
|
||||||
return community, changes, nil
|
return community, changes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) HandleCommunityDescriptionMessage(signer *ecdsa.PublicKey, description *protobuf.CommunityDescription, payload []byte) (*Community, error) {
|
func (m *Manager) HandleCommunityDescriptionMessage(signer *ecdsa.PublicKey, description *protobuf.CommunityDescription, payload []byte) (*CommunityResponse, error) {
|
||||||
id := crypto.CompressPubkey(signer)
|
id := crypto.CompressPubkey(signer)
|
||||||
community, err := m.persistence.GetByID(id)
|
community, err := m.persistence.GetByID(m.identity, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -200,6 +260,7 @@ func (m *Manager) HandleCommunityDescriptionMessage(signer *ecdsa.PublicKey, des
|
||||||
CommunityDescription: description,
|
CommunityDescription: description,
|
||||||
Logger: m.logger,
|
Logger: m.logger,
|
||||||
MarshaledCommunityDescription: payload,
|
MarshaledCommunityDescription: payload,
|
||||||
|
MemberIdentity: m.identity,
|
||||||
ID: signer,
|
ID: signer,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,21 +270,52 @@ func (m *Manager) HandleCommunityDescriptionMessage(signer *ecdsa.PublicKey, des
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = community.HandleCommunityDescription(signer, description, payload)
|
changes, err := community.UpdateCommunityDescription(signer, description, payload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pkString := common.PubkeyToHex(m.identity)
|
||||||
|
|
||||||
|
// If the community require membership, we set whether we should leave/join the community after a state change
|
||||||
|
if community.InvitationOnly() || community.OnRequest() {
|
||||||
|
if changes.HasNewMember(pkString) {
|
||||||
|
hasPendingRequest, err := m.persistence.HasPendingRequestsToJoinForUserAndCommunity(pkString, changes.Community.ID())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// If there's any pending request, we should join the community
|
||||||
|
// automatically
|
||||||
|
changes.ShouldMemberJoin = hasPendingRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
if changes.HasMemberLeft(pkString) {
|
||||||
|
// If we joined previously the community, we should leave it
|
||||||
|
changes.ShouldMemberLeave = community.Joined()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = m.persistence.SaveCommunity(community)
|
err = m.persistence.SaveCommunity(community)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return community, nil
|
// We mark our requests as completed, though maybe we should mark
|
||||||
|
// any request for any user that has been added as completed
|
||||||
|
if err := m.markRequestToJoin(m.identity, community); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Check if there's a change and we should be joining
|
||||||
|
|
||||||
|
return &CommunityResponse{
|
||||||
|
Community: community,
|
||||||
|
Changes: changes,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Finish implementing this
|
// TODO: This is not fully implemented, we want to save the grant passed at
|
||||||
func (m *Manager) HandleCommunityInvitation(signer *ecdsa.PublicKey, invitation *protobuf.CommunityInvitation, payload []byte) (*Community, error) {
|
// this stage and make sure it's used when publishing.
|
||||||
|
func (m *Manager) HandleCommunityInvitation(signer *ecdsa.PublicKey, invitation *protobuf.CommunityInvitation, payload []byte) (*CommunityResponse, error) {
|
||||||
m.logger.Debug("Handling wrapped community description message")
|
m.logger.Debug("Handling wrapped community description message")
|
||||||
|
|
||||||
community, err := m.HandleWrappedCommunityDescriptionMessage(payload)
|
community, err := m.HandleWrappedCommunityDescriptionMessage(payload)
|
||||||
|
@ -236,7 +328,80 @@ func (m *Manager) HandleCommunityInvitation(signer *ecdsa.PublicKey, invitation
|
||||||
return community, nil
|
return community, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) HandleWrappedCommunityDescriptionMessage(payload []byte) (*Community, error) {
|
// markRequestToJoin marks all the pending requests to join as completed
|
||||||
|
// if we are members
|
||||||
|
func (m *Manager) markRequestToJoin(pk *ecdsa.PublicKey, community *Community) error {
|
||||||
|
if community.HasMember(pk) {
|
||||||
|
return m.persistence.SetRequestToJoinState(common.PubkeyToHex(pk), community.ID(), RequestToJoinStateAccepted)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Manager) AcceptRequestToJoin(request *requests.AcceptRequestToJoinCommunity) (*Community, error) {
|
||||||
|
dbRequest, err := m.persistence.GetRequestToJoin(request.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
community, err := m.GetByID(dbRequest.CommunityID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
pk, err := common.HexToPubkey(dbRequest.PublicKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return m.inviteUsersToCommunity(community, []*ecdsa.PublicKey{pk})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Manager) DeclineRequestToJoin(request *requests.DeclineRequestToJoinCommunity) error {
|
||||||
|
dbRequest, err := m.persistence.GetRequestToJoin(request.ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return m.persistence.SetRequestToJoinState(dbRequest.PublicKey, dbRequest.CommunityID, RequestToJoinStateDeclined)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Manager) HandleCommunityRequestToJoin(signer *ecdsa.PublicKey, request *protobuf.CommunityRequestToJoin) (*RequestToJoin, error) {
|
||||||
|
community, err := m.persistence.GetByID(m.identity, request.CommunityId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if community == nil {
|
||||||
|
return nil, ErrOrgNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
// If they are already a member, ignore
|
||||||
|
if community.HasMember(signer) {
|
||||||
|
return nil, ErrAlreadyMember
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := community.ValidateRequestToJoin(signer, request); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
requestToJoin := &RequestToJoin{
|
||||||
|
PublicKey: common.PubkeyToHex(signer),
|
||||||
|
Clock: request.Clock,
|
||||||
|
ENSName: request.EnsName,
|
||||||
|
CommunityID: request.CommunityId,
|
||||||
|
State: RequestToJoinStatePending,
|
||||||
|
}
|
||||||
|
|
||||||
|
requestToJoin.CalculateID()
|
||||||
|
|
||||||
|
if err := m.persistence.SaveRequestToJoin(requestToJoin); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return requestToJoin, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Manager) HandleWrappedCommunityDescriptionMessage(payload []byte) (*CommunityResponse, error) {
|
||||||
m.logger.Debug("Handling wrapped community description message")
|
m.logger.Debug("Handling wrapped community description message")
|
||||||
|
|
||||||
applicationMetadataMessage := &protobuf.ApplicationMetadataMessage{}
|
applicationMetadataMessage := &protobuf.ApplicationMetadataMessage{}
|
||||||
|
@ -262,8 +427,8 @@ func (m *Manager) HandleWrappedCommunityDescriptionMessage(payload []byte) (*Com
|
||||||
return m.HandleCommunityDescriptionMessage(signer, description, payload)
|
return m.HandleCommunityDescriptionMessage(signer, description, payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) JoinCommunity(idString string) (*Community, error) {
|
func (m *Manager) JoinCommunity(id types.HexBytes) (*Community, error) {
|
||||||
community, err := m.GetByIDString(idString)
|
community, err := m.GetByID(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -278,8 +443,8 @@ func (m *Manager) JoinCommunity(idString string) (*Community, error) {
|
||||||
return community, nil
|
return community, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) LeaveCommunity(idString string) (*Community, error) {
|
func (m *Manager) LeaveCommunity(id types.HexBytes) (*Community, error) {
|
||||||
community, err := m.GetByIDString(idString)
|
community, err := m.GetByID(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -294,8 +459,33 @@ func (m *Manager) LeaveCommunity(idString string) (*Community, error) {
|
||||||
return community, nil
|
return community, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) InviteUserToCommunity(idString string, pk *ecdsa.PublicKey) (*Community, error) {
|
func (m *Manager) inviteUsersToCommunity(community *Community, pks []*ecdsa.PublicKey) (*Community, error) {
|
||||||
community, err := m.GetByIDString(idString)
|
var invitations []*protobuf.CommunityInvitation
|
||||||
|
for _, pk := range pks {
|
||||||
|
invitation, err := community.InviteUserToOrg(pk)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// We mark the user request (if any) as completed
|
||||||
|
if err := m.markRequestToJoin(pk, community); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
invitations = append(invitations, invitation)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := m.persistence.SaveCommunity(community)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
m.publish(&Subscription{Community: community, Invitations: invitations})
|
||||||
|
|
||||||
|
return community, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Manager) InviteUsersToCommunity(communityID types.HexBytes, pks []*ecdsa.PublicKey) (*Community, error) {
|
||||||
|
community, err := m.GetByID(communityID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -303,23 +493,11 @@ func (m *Manager) InviteUserToCommunity(idString string, pk *ecdsa.PublicKey) (*
|
||||||
return nil, ErrOrgNotFound
|
return nil, ErrOrgNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
invitation, err := community.InviteUserToOrg(pk)
|
return m.inviteUsersToCommunity(community, pks)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = m.persistence.SaveCommunity(community)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
m.publish(&Subscription{Community: community, Invitation: invitation})
|
|
||||||
|
|
||||||
return community, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) RemoveUserFromCommunity(idString string, pk *ecdsa.PublicKey) (*Community, error) {
|
func (m *Manager) RemoveUserFromCommunity(id types.HexBytes, pk *ecdsa.PublicKey) (*Community, error) {
|
||||||
community, err := m.GetByIDString(idString)
|
community, err := m.GetByID(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -342,16 +520,60 @@ func (m *Manager) RemoveUserFromCommunity(idString string, pk *ecdsa.PublicKey)
|
||||||
return community, nil
|
return community, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Manager) GetByID(id []byte) (*Community, error) {
|
||||||
|
return m.persistence.GetByID(m.identity, id)
|
||||||
|
}
|
||||||
|
|
||||||
func (m *Manager) GetByIDString(idString string) (*Community, error) {
|
func (m *Manager) GetByIDString(idString string) (*Community, error) {
|
||||||
id, err := types.DecodeHex(idString)
|
id, err := types.DecodeHex(idString)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return m.persistence.GetByID(id)
|
return m.GetByID(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) CanPost(pk *ecdsa.PublicKey, orgIDString, chatID string, grant []byte) (bool, error) {
|
func (m *Manager) RequestToJoin(requester *ecdsa.PublicKey, request *requests.RequestToJoinCommunity) (*Community, *RequestToJoin, error) {
|
||||||
community, err := m.GetByIDString(orgIDString)
|
community, err := m.persistence.GetByID(m.identity, request.CommunityID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't allow requesting access if already a member
|
||||||
|
if community.HasMember(m.identity) {
|
||||||
|
return nil, nil, ErrAlreadyMember
|
||||||
|
}
|
||||||
|
|
||||||
|
clock := uint64(time.Now().Unix())
|
||||||
|
requestToJoin := &RequestToJoin{
|
||||||
|
PublicKey: common.PubkeyToHex(requester),
|
||||||
|
Clock: clock,
|
||||||
|
ENSName: request.ENSName,
|
||||||
|
CommunityID: request.CommunityID,
|
||||||
|
State: RequestToJoinStatePending,
|
||||||
|
Our: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
requestToJoin.CalculateID()
|
||||||
|
|
||||||
|
if err := m.persistence.SaveRequestToJoin(requestToJoin); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
community.config.RequestedToJoinAt = uint64(time.Now().Unix())
|
||||||
|
|
||||||
|
return community, requestToJoin, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Manager) PendingRequestsToJoinForUser(pk *ecdsa.PublicKey) ([]*RequestToJoin, error) {
|
||||||
|
return m.persistence.PendingRequestsToJoinForUser(common.PubkeyToHex(pk))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Manager) PendingRequestsToJoinForCommunity(id types.HexBytes) ([]*RequestToJoin, error) {
|
||||||
|
m.logger.Info("fetching pending invitations", zap.String("community-id", id.String()))
|
||||||
|
return m.persistence.PendingRequestsToJoinForCommunity(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Manager) CanPost(pk *ecdsa.PublicKey, communityID string, chatID string, grant []byte) (bool, error) {
|
||||||
|
community, err := m.GetByIDString(communityID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
|
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
|
|
||||||
|
"github.com/status-im/status-go/eth-node/crypto"
|
||||||
"github.com/status-im/status-go/protocol/protobuf"
|
"github.com/status-im/status-go/protocol/protobuf"
|
||||||
"github.com/status-im/status-go/protocol/sqlite"
|
"github.com/status-im/status-go/protocol/sqlite"
|
||||||
)
|
)
|
||||||
|
@ -25,8 +26,12 @@ type ManagerSuite struct {
|
||||||
func (s *ManagerSuite) SetupTest() {
|
func (s *ManagerSuite) SetupTest() {
|
||||||
db, err := sqlite.OpenInMemory()
|
db, err := sqlite.OpenInMemory()
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
m, err := NewManager(db, nil)
|
key, err := crypto.GenerateKey()
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
m, err := NewManager(&key.PublicKey, db, nil, nil)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().NoError(m.Start())
|
||||||
s.manager = m
|
s.manager = m
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
package communities
|
package communities
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"errors"
|
||||||
|
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
|
||||||
"github.com/status-im/status-go/eth-node/crypto"
|
"github.com/status-im/status-go/eth-node/crypto"
|
||||||
|
"github.com/status-im/status-go/protocol/common"
|
||||||
"github.com/status-im/status-go/protocol/protobuf"
|
"github.com/status-im/status-go/protocol/protobuf"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -16,6 +19,8 @@ type Persistence struct {
|
||||||
logger *zap.Logger
|
logger *zap.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const communitiesBaseQuery = `SELECT c.id, c.private_key, c.description,c.joined,c.verified,r.clock FROM communities_communities c LEFT JOIN communities_requests_to_join r ON c.id = r.community_id AND r.public_key = ?`
|
||||||
|
|
||||||
func (p *Persistence) SaveCommunity(community *Community) error {
|
func (p *Persistence) SaveCommunity(community *Community) error {
|
||||||
id := community.ID()
|
id := community.ID()
|
||||||
privateKey := community.PrivateKey()
|
privateKey := community.PrivateKey()
|
||||||
|
@ -28,9 +33,9 @@ func (p *Persistence) SaveCommunity(community *Community) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Persistence) queryCommunities(query string) (response []*Community, err error) {
|
func (p *Persistence) queryCommunities(memberIdentity *ecdsa.PublicKey, query string) (response []*Community, err error) {
|
||||||
|
|
||||||
rows, err := p.db.Query(query)
|
rows, err := p.db.Query(query, common.PubkeyToHex(memberIdentity))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -49,12 +54,13 @@ func (p *Persistence) queryCommunities(query string) (response []*Community, err
|
||||||
var publicKeyBytes, privateKeyBytes, descriptionBytes []byte
|
var publicKeyBytes, privateKeyBytes, descriptionBytes []byte
|
||||||
var joined bool
|
var joined bool
|
||||||
var verified bool
|
var verified bool
|
||||||
err := rows.Scan(&publicKeyBytes, &privateKeyBytes, &descriptionBytes, &joined, &verified)
|
var requestedToJoinAt sql.NullInt64
|
||||||
|
err := rows.Scan(&publicKeyBytes, &privateKeyBytes, &descriptionBytes, &joined, &verified, &requestedToJoinAt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
org, err := unmarshalCommunityFromDB(publicKeyBytes, privateKeyBytes, descriptionBytes, joined, verified, p.logger)
|
org, err := unmarshalCommunityFromDB(memberIdentity, publicKeyBytes, privateKeyBytes, descriptionBytes, joined, verified, uint64(requestedToJoinAt.Int64), p.logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -65,27 +71,27 @@ func (p *Persistence) queryCommunities(query string) (response []*Community, err
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Persistence) AllCommunities() ([]*Community, error) {
|
func (p *Persistence) AllCommunities(memberIdentity *ecdsa.PublicKey) ([]*Community, error) {
|
||||||
query := `SELECT id, private_key, description,joined,verified FROM communities_communities`
|
return p.queryCommunities(memberIdentity, communitiesBaseQuery)
|
||||||
return p.queryCommunities(query)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Persistence) JoinedCommunities() ([]*Community, error) {
|
func (p *Persistence) JoinedCommunities(memberIdentity *ecdsa.PublicKey) ([]*Community, error) {
|
||||||
query := `SELECT id, private_key, description,joined,verified FROM communities_communities WHERE joined`
|
query := communitiesBaseQuery + ` WHERE c.joined`
|
||||||
return p.queryCommunities(query)
|
return p.queryCommunities(memberIdentity, query)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Persistence) CreatedCommunities() ([]*Community, error) {
|
func (p *Persistence) CreatedCommunities(memberIdentity *ecdsa.PublicKey) ([]*Community, error) {
|
||||||
query := `SELECT id, private_key, description,joined,verified FROM communities_communities WHERE private_key IS NOT NULL`
|
query := communitiesBaseQuery + ` WHERE c.private_key IS NOT NULL`
|
||||||
return p.queryCommunities(query)
|
return p.queryCommunities(memberIdentity, query)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Persistence) GetByID(id []byte) (*Community, error) {
|
func (p *Persistence) GetByID(memberIdentity *ecdsa.PublicKey, id []byte) (*Community, error) {
|
||||||
var publicKeyBytes, privateKeyBytes, descriptionBytes []byte
|
var publicKeyBytes, privateKeyBytes, descriptionBytes []byte
|
||||||
var joined bool
|
var joined bool
|
||||||
var verified bool
|
var verified bool
|
||||||
|
var requestedToJoinAt sql.NullInt64
|
||||||
|
|
||||||
err := p.db.QueryRow(`SELECT id, private_key, description, joined,verified FROM communities_communities WHERE id = ?`, id).Scan(&publicKeyBytes, &privateKeyBytes, &descriptionBytes, &joined, &verified)
|
err := p.db.QueryRow(communitiesBaseQuery+` WHERE c.id = ?`, common.PubkeyToHex(memberIdentity), id).Scan(&publicKeyBytes, &privateKeyBytes, &descriptionBytes, &joined, &verified, &requestedToJoinAt)
|
||||||
|
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
@ -93,10 +99,10 @@ func (p *Persistence) GetByID(id []byte) (*Community, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return unmarshalCommunityFromDB(publicKeyBytes, privateKeyBytes, descriptionBytes, joined, verified, p.logger)
|
return unmarshalCommunityFromDB(memberIdentity, publicKeyBytes, privateKeyBytes, descriptionBytes, joined, verified, uint64(requestedToJoinAt.Int64), p.logger)
|
||||||
}
|
}
|
||||||
|
|
||||||
func unmarshalCommunityFromDB(publicKeyBytes, privateKeyBytes, descriptionBytes []byte, joined, verified bool, logger *zap.Logger) (*Community, error) {
|
func unmarshalCommunityFromDB(memberIdentity *ecdsa.PublicKey, publicKeyBytes, privateKeyBytes, descriptionBytes []byte, joined, verified bool, requestedToJoinAt uint64, logger *zap.Logger) (*Community, error) {
|
||||||
|
|
||||||
var privateKey *ecdsa.PrivateKey
|
var privateKey *ecdsa.PrivateKey
|
||||||
var err error
|
var err error
|
||||||
|
@ -129,11 +135,106 @@ func unmarshalCommunityFromDB(publicKeyBytes, privateKeyBytes, descriptionBytes
|
||||||
config := Config{
|
config := Config{
|
||||||
PrivateKey: privateKey,
|
PrivateKey: privateKey,
|
||||||
CommunityDescription: description,
|
CommunityDescription: description,
|
||||||
|
MemberIdentity: memberIdentity,
|
||||||
MarshaledCommunityDescription: descriptionBytes,
|
MarshaledCommunityDescription: descriptionBytes,
|
||||||
Logger: logger,
|
Logger: logger,
|
||||||
ID: id,
|
ID: id,
|
||||||
Verified: verified,
|
Verified: verified,
|
||||||
|
RequestedToJoinAt: requestedToJoinAt,
|
||||||
Joined: joined,
|
Joined: joined,
|
||||||
}
|
}
|
||||||
return New(config)
|
return New(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Persistence) SaveRequestToJoin(request *RequestToJoin) (err error) {
|
||||||
|
tx, err := p.db.BeginTx(context.Background(), &sql.TxOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if err == nil {
|
||||||
|
err = tx.Commit()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// don't shadow original error
|
||||||
|
_ = tx.Rollback()
|
||||||
|
}()
|
||||||
|
|
||||||
|
var clock uint64
|
||||||
|
// Fetch any existing request to join
|
||||||
|
err = tx.QueryRow(`SELECT clock FROM communities_requests_to_join WHERE state = ? AND public_key = ? AND community_id = ?`, RequestToJoinStatePending, request.PublicKey, request.CommunityID).Scan(&clock)
|
||||||
|
if err != nil && err != sql.ErrNoRows {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is already processed
|
||||||
|
if clock >= request.Clock {
|
||||||
|
return errors.New("old request to join")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = tx.Exec(`INSERT INTO communities_requests_to_join(id,public_key,clock,ens_name,chat_id,community_id,state) VALUES (?, ?, ?, ?, ?, ?, ?)`, request.ID, request.PublicKey, request.Clock, request.ENSName, request.ChatID, request.CommunityID, request.State)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Persistence) PendingRequestsToJoinForUser(pk string) ([]*RequestToJoin, error) {
|
||||||
|
var requests []*RequestToJoin
|
||||||
|
rows, err := p.db.Query(`SELECT id,public_key,clock,ens_name,chat_id,community_id,state FROM communities_requests_to_join WHERE state = ? AND public_key = ?`, RequestToJoinStatePending, pk)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
request := &RequestToJoin{}
|
||||||
|
err := rows.Scan(&request.ID, &request.PublicKey, &request.Clock, &request.ENSName, &request.ChatID, &request.CommunityID, &request.State)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
requests = append(requests, request)
|
||||||
|
}
|
||||||
|
return requests, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Persistence) HasPendingRequestsToJoinForUserAndCommunity(userPk string, communityID []byte) (bool, error) {
|
||||||
|
var count int
|
||||||
|
err := p.db.QueryRow(`SELECT count(1) FROM communities_requests_to_join WHERE state = ? AND public_key = ? AND community_id = ?`, RequestToJoinStatePending, userPk, communityID).Scan(&count)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return count > 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Persistence) PendingRequestsToJoinForCommunity(id []byte) ([]*RequestToJoin, error) {
|
||||||
|
var requests []*RequestToJoin
|
||||||
|
rows, err := p.db.Query(`SELECT id,public_key,clock,ens_name,chat_id,community_id,state FROM communities_requests_to_join WHERE state = ? AND community_id = ?`, RequestToJoinStatePending, id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
request := &RequestToJoin{}
|
||||||
|
err := rows.Scan(&request.ID, &request.PublicKey, &request.Clock, &request.ENSName, &request.ChatID, &request.CommunityID, &request.State)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
requests = append(requests, request)
|
||||||
|
}
|
||||||
|
return requests, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Persistence) SetRequestToJoinState(pk string, communityID []byte, state uint) error {
|
||||||
|
_, err := p.db.Exec(`UPDATE communities_requests_to_join SET state = ? WHERE community_id = ? AND public_key = ?`, state, communityID, pk)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Persistence) GetRequestToJoin(id []byte) (*RequestToJoin, error) {
|
||||||
|
request := &RequestToJoin{}
|
||||||
|
err := p.db.QueryRow(`SELECT id,public_key,clock,ens_name,chat_id,community_id,state FROM communities_requests_to_join WHERE id = ?`, id).Scan(&request.ID, &request.PublicKey, &request.Clock, &request.ENSName, &request.ChatID, &request.CommunityID, &request.State)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return request, nil
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
package communities
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/status-im/status-go/eth-node/crypto"
|
||||||
|
"github.com/status-im/status-go/eth-node/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
RequestToJoinStatePending uint = iota + 1
|
||||||
|
RequestToJoinStateDeclined
|
||||||
|
RequestToJoinStateAccepted
|
||||||
|
)
|
||||||
|
|
||||||
|
type RequestToJoin struct {
|
||||||
|
ID types.HexBytes `json:"id"`
|
||||||
|
PublicKey string `json:"publicKey"`
|
||||||
|
Clock uint64 `json:"clock"`
|
||||||
|
ENSName string `json:"ensName,omitempty"`
|
||||||
|
ChatID string `json:"chatId"`
|
||||||
|
CommunityID types.HexBytes `json:"communityId"`
|
||||||
|
State uint `json:"state"`
|
||||||
|
Our bool `json:"our"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RequestToJoin) CalculateID() {
|
||||||
|
idString := fmt.Sprintf("%s-%s", r.PublicKey, r.CommunityID)
|
||||||
|
r.ID = crypto.Keccak256([]byte(idString))
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package protocol
|
package protocol
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"errors"
|
"errors"
|
||||||
|
@ -16,7 +17,9 @@ import (
|
||||||
"github.com/status-im/status-go/eth-node/crypto"
|
"github.com/status-im/status-go/eth-node/crypto"
|
||||||
"github.com/status-im/status-go/eth-node/types"
|
"github.com/status-im/status-go/eth-node/types"
|
||||||
"github.com/status-im/status-go/protocol/common"
|
"github.com/status-im/status-go/protocol/common"
|
||||||
|
"github.com/status-im/status-go/protocol/communities"
|
||||||
"github.com/status-im/status-go/protocol/protobuf"
|
"github.com/status-im/status-go/protocol/protobuf"
|
||||||
|
"github.com/status-im/status-go/protocol/requests"
|
||||||
"github.com/status-im/status-go/protocol/tt"
|
"github.com/status-im/status-go/protocol/tt"
|
||||||
"github.com/status-im/status-go/waku"
|
"github.com/status-im/status-go/waku"
|
||||||
)
|
)
|
||||||
|
@ -95,21 +98,18 @@ func (s *MessengerCommunitiesSuite) newMessenger() *Messenger {
|
||||||
func (s *MessengerCommunitiesSuite) TestRetrieveCommunity() {
|
func (s *MessengerCommunitiesSuite) TestRetrieveCommunity() {
|
||||||
alice := s.newMessenger()
|
alice := s.newMessenger()
|
||||||
|
|
||||||
description := &protobuf.CommunityDescription{
|
description := &requests.CreateCommunity{
|
||||||
Permissions: &protobuf.CommunityPermissions{
|
Membership: protobuf.CommunityPermissions_NO_MEMBERSHIP,
|
||||||
Access: protobuf.CommunityPermissions_NO_MEMBERSHIP,
|
Name: "status",
|
||||||
},
|
Color: "#ffffff",
|
||||||
Identity: &protobuf.ChatIdentity{
|
Description: "status community description",
|
||||||
DisplayName: "status",
|
|
||||||
Description: "status community description",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
response, err := s.bob.CreateCommunity(description)
|
response, err := s.bob.CreateCommunity(description)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.Require().NotNil(response)
|
s.Require().NotNil(response)
|
||||||
s.Require().Len(response.Communities, 1)
|
s.Require().Len(response.Communities(), 1)
|
||||||
community := response.Communities[0]
|
community := response.Communities()[0]
|
||||||
|
|
||||||
// Send an community message
|
// Send an community message
|
||||||
chat := CreateOneToOneChat(common.PubkeyToHex(&alice.identity.PublicKey), &alice.identity.PublicKey, s.alice.transport)
|
chat := CreateOneToOneChat(common.PubkeyToHex(&alice.identity.PublicKey), &alice.identity.PublicKey, s.alice.transport)
|
||||||
|
@ -119,7 +119,7 @@ func (s *MessengerCommunitiesSuite) TestRetrieveCommunity() {
|
||||||
inputMessage.Text = "some text"
|
inputMessage.Text = "some text"
|
||||||
inputMessage.CommunityID = community.IDString()
|
inputMessage.CommunityID = community.IDString()
|
||||||
|
|
||||||
err = s.bob.SaveChat(&chat)
|
err = s.bob.SaveChat(chat)
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
_, err = s.bob.SendChatMessage(context.Background(), inputMessage)
|
_, err = s.bob.SendChatMessage(context.Background(), inputMessage)
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
|
@ -130,7 +130,7 @@ func (s *MessengerCommunitiesSuite) TestRetrieveCommunity() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(response.Communities) == 0 {
|
if len(response.Communities()) == 0 {
|
||||||
return errors.New("community not received")
|
return errors.New("community not received")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -140,29 +140,27 @@ func (s *MessengerCommunitiesSuite) TestRetrieveCommunity() {
|
||||||
communities, err := alice.Communities()
|
communities, err := alice.Communities()
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.Require().Len(communities, 2)
|
s.Require().Len(communities, 2)
|
||||||
s.Require().Len(response.Communities, 1)
|
s.Require().Len(response.Communities(), 1)
|
||||||
s.Require().Len(response.Messages, 1)
|
s.Require().Len(response.Messages, 1)
|
||||||
s.Require().Equal(community.IDString(), response.Messages[0].CommunityID)
|
s.Require().Equal(community.IDString(), response.Messages[0].CommunityID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *MessengerCommunitiesSuite) TestJoinCommunity() {
|
func (s *MessengerCommunitiesSuite) TestJoinCommunity() {
|
||||||
description := &protobuf.CommunityDescription{
|
|
||||||
Permissions: &protobuf.CommunityPermissions{
|
description := &requests.CreateCommunity{
|
||||||
Access: protobuf.CommunityPermissions_NO_MEMBERSHIP,
|
Membership: protobuf.CommunityPermissions_NO_MEMBERSHIP,
|
||||||
},
|
Name: "status",
|
||||||
Identity: &protobuf.ChatIdentity{
|
Color: "#ffffff",
|
||||||
DisplayName: "status",
|
Description: "status community description",
|
||||||
Description: "status community description",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create an community chat
|
// Create an community chat
|
||||||
response, err := s.bob.CreateCommunity(description)
|
response, err := s.bob.CreateCommunity(description)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.Require().NotNil(response)
|
s.Require().NotNil(response)
|
||||||
s.Require().Len(response.Communities, 1)
|
s.Require().Len(response.Communities(), 1)
|
||||||
|
|
||||||
community := response.Communities[0]
|
community := response.Communities()[0]
|
||||||
|
|
||||||
orgChat := &protobuf.CommunityChat{
|
orgChat := &protobuf.CommunityChat{
|
||||||
Permissions: &protobuf.CommunityPermissions{
|
Permissions: &protobuf.CommunityPermissions{
|
||||||
|
@ -173,13 +171,13 @@ func (s *MessengerCommunitiesSuite) TestJoinCommunity() {
|
||||||
Description: "status-core community chat",
|
Description: "status-core community chat",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
response, err = s.bob.CreateCommunityChat(community.IDString(), orgChat)
|
response, err = s.bob.CreateCommunityChat(community.ID(), orgChat)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.Require().NotNil(response)
|
s.Require().NotNil(response)
|
||||||
s.Require().Len(response.Communities, 1)
|
s.Require().Len(response.Communities(), 1)
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
|
|
||||||
createdChat := response.Chats[0]
|
createdChat := response.Chats()[0]
|
||||||
s.Require().Equal(community.IDString(), createdChat.CommunityID)
|
s.Require().Equal(community.IDString(), createdChat.CommunityID)
|
||||||
s.Require().Equal(orgChat.Identity.DisplayName, createdChat.Name)
|
s.Require().Equal(orgChat.Identity.DisplayName, createdChat.Name)
|
||||||
s.Require().NotEmpty(createdChat.ID)
|
s.Require().NotEmpty(createdChat.ID)
|
||||||
|
@ -189,7 +187,7 @@ func (s *MessengerCommunitiesSuite) TestJoinCommunity() {
|
||||||
s.Require().True(strings.HasPrefix(createdChat.ID, community.IDString()))
|
s.Require().True(strings.HasPrefix(createdChat.ID, community.IDString()))
|
||||||
|
|
||||||
// Make sure the changes are reflect in the community
|
// Make sure the changes are reflect in the community
|
||||||
community = response.Communities[0]
|
community = response.Communities()[0]
|
||||||
chats := community.Chats()
|
chats := community.Chats()
|
||||||
s.Require().Len(chats, 1)
|
s.Require().Len(chats, 1)
|
||||||
|
|
||||||
|
@ -201,7 +199,7 @@ func (s *MessengerCommunitiesSuite) TestJoinCommunity() {
|
||||||
inputMessage.Text = "some text"
|
inputMessage.Text = "some text"
|
||||||
inputMessage.CommunityID = community.IDString()
|
inputMessage.CommunityID = community.IDString()
|
||||||
|
|
||||||
err = s.bob.SaveChat(&chat)
|
err = s.bob.SaveChat(chat)
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
_, err = s.bob.SendChatMessage(context.Background(), inputMessage)
|
_, err = s.bob.SendChatMessage(context.Background(), inputMessage)
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
|
@ -212,7 +210,7 @@ func (s *MessengerCommunitiesSuite) TestJoinCommunity() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(response.Communities) == 0 {
|
if len(response.Communities()) == 0 {
|
||||||
return errors.New("community not received")
|
return errors.New("community not received")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -222,20 +220,20 @@ func (s *MessengerCommunitiesSuite) TestJoinCommunity() {
|
||||||
communities, err := s.alice.Communities()
|
communities, err := s.alice.Communities()
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.Require().Len(communities, 2)
|
s.Require().Len(communities, 2)
|
||||||
s.Require().Len(response.Communities, 1)
|
s.Require().Len(response.Communities(), 1)
|
||||||
s.Require().Len(response.Messages, 1)
|
s.Require().Len(response.Messages, 1)
|
||||||
s.Require().Equal(community.IDString(), response.Messages[0].CommunityID)
|
s.Require().Equal(community.IDString(), response.Messages[0].CommunityID)
|
||||||
|
|
||||||
// We join the org
|
// We join the org
|
||||||
response, err = s.alice.JoinCommunity(community.IDString())
|
response, err = s.alice.JoinCommunity(community.ID())
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.Require().NotNil(response)
|
s.Require().NotNil(response)
|
||||||
s.Require().Len(response.Communities, 1)
|
s.Require().Len(response.Communities(), 1)
|
||||||
s.Require().True(response.Communities[0].Joined())
|
s.Require().True(response.Communities()[0].Joined())
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
|
|
||||||
// The chat should be created
|
// The chat should be created
|
||||||
createdChat = response.Chats[0]
|
createdChat = response.Chats()[0]
|
||||||
s.Require().Equal(community.IDString(), createdChat.CommunityID)
|
s.Require().Equal(community.IDString(), createdChat.CommunityID)
|
||||||
s.Require().Equal(orgChat.Identity.DisplayName, createdChat.Name)
|
s.Require().Equal(orgChat.Identity.DisplayName, createdChat.Name)
|
||||||
s.Require().NotEmpty(createdChat.ID)
|
s.Require().NotEmpty(createdChat.ID)
|
||||||
|
@ -254,11 +252,11 @@ func (s *MessengerCommunitiesSuite) TestJoinCommunity() {
|
||||||
Description: "status-core-ui community chat",
|
Description: "status-core-ui community chat",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
response, err = s.bob.CreateCommunityChat(community.IDString(), orgChat)
|
response, err = s.bob.CreateCommunityChat(community.ID(), orgChat)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.Require().NotNil(response)
|
s.Require().NotNil(response)
|
||||||
s.Require().Len(response.Communities, 1)
|
s.Require().Len(response.Communities(), 1)
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
|
|
||||||
// Pull message, this time it should be received as advertised automatically
|
// Pull message, this time it should be received as advertised automatically
|
||||||
err = tt.RetryWithBackOff(func() error {
|
err = tt.RetryWithBackOff(func() error {
|
||||||
|
@ -266,7 +264,7 @@ func (s *MessengerCommunitiesSuite) TestJoinCommunity() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(response.Communities) == 0 {
|
if len(response.Communities()) == 0 {
|
||||||
return errors.New("community not received")
|
return errors.New("community not received")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -276,11 +274,11 @@ func (s *MessengerCommunitiesSuite) TestJoinCommunity() {
|
||||||
communities, err = s.alice.Communities()
|
communities, err = s.alice.Communities()
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.Require().Len(communities, 2)
|
s.Require().Len(communities, 2)
|
||||||
s.Require().Len(response.Communities, 1)
|
s.Require().Len(response.Communities(), 1)
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
|
|
||||||
// The chat should be created
|
// The chat should be created
|
||||||
createdChat = response.Chats[0]
|
createdChat = response.Chats()[0]
|
||||||
s.Require().Equal(community.IDString(), createdChat.CommunityID)
|
s.Require().Equal(community.IDString(), createdChat.CommunityID)
|
||||||
s.Require().Equal(orgChat.Identity.DisplayName, createdChat.Name)
|
s.Require().Equal(orgChat.Identity.DisplayName, createdChat.Name)
|
||||||
s.Require().NotEmpty(createdChat.ID)
|
s.Require().NotEmpty(createdChat.ID)
|
||||||
|
@ -290,39 +288,41 @@ func (s *MessengerCommunitiesSuite) TestJoinCommunity() {
|
||||||
s.Require().True(strings.HasPrefix(createdChat.ID, community.IDString()))
|
s.Require().True(strings.HasPrefix(createdChat.ID, community.IDString()))
|
||||||
|
|
||||||
// We leave the org
|
// We leave the org
|
||||||
response, err = s.alice.LeaveCommunity(community.IDString())
|
response, err = s.alice.LeaveCommunity(community.ID())
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.Require().NotNil(response)
|
s.Require().NotNil(response)
|
||||||
s.Require().Len(response.Communities, 1)
|
s.Require().Len(response.Communities(), 1)
|
||||||
s.Require().False(response.Communities[0].Joined())
|
s.Require().False(response.Communities()[0].Joined())
|
||||||
s.Require().Len(response.RemovedChats, 2)
|
s.Require().Len(response.RemovedChats(), 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *MessengerCommunitiesSuite) TestInviteUserToCommunity() {
|
func (s *MessengerCommunitiesSuite) TestInviteUsersToCommunity() {
|
||||||
description := &protobuf.CommunityDescription{
|
description := &requests.CreateCommunity{
|
||||||
Permissions: &protobuf.CommunityPermissions{
|
Membership: protobuf.CommunityPermissions_NO_MEMBERSHIP,
|
||||||
Access: protobuf.CommunityPermissions_NO_MEMBERSHIP,
|
Name: "status",
|
||||||
},
|
Color: "#ffffff",
|
||||||
Identity: &protobuf.ChatIdentity{
|
Description: "status community description",
|
||||||
DisplayName: "status",
|
|
||||||
Description: "status community description",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create an community chat
|
// Create an community chat
|
||||||
response, err := s.bob.CreateCommunity(description)
|
response, err := s.bob.CreateCommunity(description)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.Require().NotNil(response)
|
s.Require().NotNil(response)
|
||||||
s.Require().Len(response.Communities, 1)
|
s.Require().Len(response.Communities(), 1)
|
||||||
|
|
||||||
community := response.Communities[0]
|
community := response.Communities()[0]
|
||||||
|
|
||||||
response, err = s.bob.InviteUserToCommunity(community.IDString(), common.PubkeyToHex(&s.alice.identity.PublicKey))
|
response, err = s.bob.InviteUsersToCommunity(
|
||||||
|
&requests.InviteUsersToCommunity{
|
||||||
|
CommunityID: community.ID(),
|
||||||
|
Users: []types.HexBytes{common.PubkeyToHexBytes(&s.alice.identity.PublicKey)},
|
||||||
|
},
|
||||||
|
)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.Require().NotNil(response)
|
s.Require().NotNil(response)
|
||||||
s.Require().Len(response.Communities, 1)
|
s.Require().Len(response.Communities(), 1)
|
||||||
|
|
||||||
community = response.Communities[0]
|
community = response.Communities()[0]
|
||||||
s.Require().True(community.HasMember(&s.alice.identity.PublicKey))
|
s.Require().True(community.HasMember(&s.alice.identity.PublicKey))
|
||||||
|
|
||||||
// Pull message and make sure org is received
|
// Pull message and make sure org is received
|
||||||
|
@ -331,7 +331,7 @@ func (s *MessengerCommunitiesSuite) TestInviteUserToCommunity() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(response.Communities) == 0 {
|
if len(response.Communities()) == 0 {
|
||||||
return errors.New("community not received")
|
return errors.New("community not received")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -341,30 +341,27 @@ func (s *MessengerCommunitiesSuite) TestInviteUserToCommunity() {
|
||||||
communities, err := s.alice.Communities()
|
communities, err := s.alice.Communities()
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.Require().Len(communities, 2)
|
s.Require().Len(communities, 2)
|
||||||
s.Require().Len(response.Communities, 1)
|
s.Require().Len(response.Communities(), 1)
|
||||||
|
|
||||||
community = response.Communities[0]
|
community = response.Communities()[0]
|
||||||
s.Require().True(community.HasMember(&s.alice.identity.PublicKey))
|
s.Require().True(community.HasMember(&s.alice.identity.PublicKey))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *MessengerCommunitiesSuite) TestPostToCommunityChat() {
|
func (s *MessengerCommunitiesSuite) TestPostToCommunityChat() {
|
||||||
description := &protobuf.CommunityDescription{
|
description := &requests.CreateCommunity{
|
||||||
Permissions: &protobuf.CommunityPermissions{
|
Membership: protobuf.CommunityPermissions_INVITATION_ONLY,
|
||||||
Access: protobuf.CommunityPermissions_INVITATION_ONLY,
|
Name: "status",
|
||||||
},
|
Color: "#ffffff",
|
||||||
Identity: &protobuf.ChatIdentity{
|
Description: "status community description",
|
||||||
DisplayName: "status",
|
|
||||||
Description: "status community description",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create an community chat
|
// Create an community chat
|
||||||
response, err := s.bob.CreateCommunity(description)
|
response, err := s.bob.CreateCommunity(description)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.Require().NotNil(response)
|
s.Require().NotNil(response)
|
||||||
s.Require().Len(response.Communities, 1)
|
s.Require().Len(response.Communities(), 1)
|
||||||
|
|
||||||
community := response.Communities[0]
|
community := response.Communities()[0]
|
||||||
|
|
||||||
// Create chat
|
// Create chat
|
||||||
orgChat := &protobuf.CommunityChat{
|
orgChat := &protobuf.CommunityChat{
|
||||||
|
@ -377,18 +374,23 @@ func (s *MessengerCommunitiesSuite) TestPostToCommunityChat() {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
response, err = s.bob.CreateCommunityChat(community.IDString(), orgChat)
|
response, err = s.bob.CreateCommunityChat(community.ID(), orgChat)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.Require().NotNil(response)
|
s.Require().NotNil(response)
|
||||||
s.Require().Len(response.Communities, 1)
|
s.Require().Len(response.Communities(), 1)
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
|
|
||||||
response, err = s.bob.InviteUserToCommunity(community.IDString(), common.PubkeyToHex(&s.alice.identity.PublicKey))
|
response, err = s.bob.InviteUsersToCommunity(
|
||||||
|
&requests.InviteUsersToCommunity{
|
||||||
|
CommunityID: community.ID(),
|
||||||
|
Users: []types.HexBytes{common.PubkeyToHexBytes(&s.alice.identity.PublicKey)},
|
||||||
|
},
|
||||||
|
)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.Require().NotNil(response)
|
s.Require().NotNil(response)
|
||||||
s.Require().Len(response.Communities, 1)
|
s.Require().Len(response.Communities(), 1)
|
||||||
|
|
||||||
community = response.Communities[0]
|
community = response.Communities()[0]
|
||||||
s.Require().True(community.HasMember(&s.alice.identity.PublicKey))
|
s.Require().True(community.HasMember(&s.alice.identity.PublicKey))
|
||||||
|
|
||||||
// Pull message and make sure org is received
|
// Pull message and make sure org is received
|
||||||
|
@ -397,7 +399,7 @@ func (s *MessengerCommunitiesSuite) TestPostToCommunityChat() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(response.Communities) == 0 {
|
if len(response.Communities()) == 0 {
|
||||||
return errors.New("community not received")
|
return errors.New("community not received")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -407,29 +409,29 @@ func (s *MessengerCommunitiesSuite) TestPostToCommunityChat() {
|
||||||
communities, err := s.alice.Communities()
|
communities, err := s.alice.Communities()
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.Require().Len(communities, 2)
|
s.Require().Len(communities, 2)
|
||||||
s.Require().Len(response.Communities, 1)
|
s.Require().Len(response.Communities(), 1)
|
||||||
|
|
||||||
// We join the org
|
// We join the org
|
||||||
response, err = s.alice.JoinCommunity(community.IDString())
|
response, err = s.alice.JoinCommunity(community.ID())
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.Require().NotNil(response)
|
s.Require().NotNil(response)
|
||||||
s.Require().Len(response.Communities, 1)
|
s.Require().Len(response.Communities(), 1)
|
||||||
s.Require().True(response.Communities[0].Joined())
|
s.Require().True(response.Communities()[0].Joined())
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
s.Require().Len(response.Filters, 2)
|
s.Require().Len(response.Filters, 2)
|
||||||
|
|
||||||
var orgFilterFound bool
|
var orgFilterFound bool
|
||||||
var chatFilterFound bool
|
var chatFilterFound bool
|
||||||
for _, f := range response.Filters {
|
for _, f := range response.Filters {
|
||||||
orgFilterFound = orgFilterFound || f.ChatID == response.Communities[0].IDString()
|
orgFilterFound = orgFilterFound || f.ChatID == response.Communities()[0].IDString()
|
||||||
chatFilterFound = chatFilterFound || f.ChatID == response.Chats[0].ID
|
chatFilterFound = chatFilterFound || f.ChatID == response.Chats()[0].ID
|
||||||
}
|
}
|
||||||
// Make sure an community filter has been created
|
// Make sure an community filter has been created
|
||||||
s.Require().True(orgFilterFound)
|
s.Require().True(orgFilterFound)
|
||||||
// Make sure the chat filter has been created
|
// Make sure the chat filter has been created
|
||||||
s.Require().True(chatFilterFound)
|
s.Require().True(chatFilterFound)
|
||||||
|
|
||||||
chatID := response.Chats[0].ID
|
chatID := response.Chats()[0].ID
|
||||||
inputMessage := &common.Message{}
|
inputMessage := &common.Message{}
|
||||||
inputMessage.ChatId = chatID
|
inputMessage.ChatId = chatID
|
||||||
inputMessage.ContentType = protobuf.ChatMessage_TEXT_PLAIN
|
inputMessage.ContentType = protobuf.ChatMessage_TEXT_PLAIN
|
||||||
|
@ -452,32 +454,27 @@ func (s *MessengerCommunitiesSuite) TestPostToCommunityChat() {
|
||||||
|
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.Require().Len(response.Messages, 1)
|
s.Require().Len(response.Messages, 1)
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
s.Require().Equal(chatID, response.Chats[0].ID)
|
s.Require().Equal(chatID, response.Chats()[0].ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *MessengerCommunitiesSuite) TestImportCommunity() {
|
func (s *MessengerCommunitiesSuite) TestImportCommunity() {
|
||||||
description := &protobuf.CommunityDescription{
|
description := &requests.CreateCommunity{
|
||||||
Permissions: &protobuf.CommunityPermissions{
|
Membership: protobuf.CommunityPermissions_NO_MEMBERSHIP,
|
||||||
Access: protobuf.CommunityPermissions_NO_MEMBERSHIP,
|
Name: "status",
|
||||||
},
|
Color: "#ffffff",
|
||||||
Identity: &protobuf.ChatIdentity{
|
Description: "status community description",
|
||||||
DisplayName: "status",
|
|
||||||
Description: "status community description",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create an community chat
|
// Create an community chat
|
||||||
response, err := s.bob.CreateCommunity(description)
|
response, err := s.bob.CreateCommunity(description)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.Require().NotNil(response)
|
s.Require().NotNil(response)
|
||||||
s.Require().Len(response.Communities, 1)
|
s.Require().Len(response.Communities(), 1)
|
||||||
|
|
||||||
s.bob.logger.Info("communitise", zap.Any("COMM", response.Communities))
|
community := response.Communities()[0]
|
||||||
|
|
||||||
community := response.Communities[0]
|
privateKey, err := s.bob.ExportCommunity(community.ID())
|
||||||
|
|
||||||
privateKey, err := s.bob.ExportCommunity(community.IDString())
|
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
response, err = s.alice.ImportCommunity(privateKey)
|
response, err = s.alice.ImportCommunity(privateKey)
|
||||||
|
@ -488,7 +485,12 @@ func (s *MessengerCommunitiesSuite) TestImportCommunity() {
|
||||||
newUser, err := crypto.GenerateKey()
|
newUser, err := crypto.GenerateKey()
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
_, err = s.bob.InviteUserToCommunity(community.IDString(), common.PubkeyToHex(&newUser.PublicKey))
|
_, err = s.bob.InviteUsersToCommunity(
|
||||||
|
&requests.InviteUsersToCommunity{
|
||||||
|
CommunityID: community.ID(),
|
||||||
|
Users: []types.HexBytes{common.PubkeyToHexBytes(&newUser.PublicKey)},
|
||||||
|
},
|
||||||
|
)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
// Pull message and make sure org is received
|
// Pull message and make sure org is received
|
||||||
|
@ -497,15 +499,468 @@ func (s *MessengerCommunitiesSuite) TestImportCommunity() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(response.Communities) == 0 {
|
if len(response.Communities()) == 0 {
|
||||||
return errors.New("community not received")
|
return errors.New("community not received")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.Require().Len(response.Communities, 1)
|
s.Require().Len(response.Communities(), 1)
|
||||||
community = response.Communities[0]
|
community = response.Communities()[0]
|
||||||
s.Require().True(community.Joined())
|
s.Require().True(community.Joined())
|
||||||
s.Require().True(community.IsAdmin())
|
s.Require().True(community.IsAdmin())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *MessengerCommunitiesSuite) TestRequestAccess() {
|
||||||
|
description := &requests.CreateCommunity{
|
||||||
|
Membership: protobuf.CommunityPermissions_ON_REQUEST,
|
||||||
|
Name: "status",
|
||||||
|
Color: "#ffffff",
|
||||||
|
Description: "status community description",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an community chat
|
||||||
|
response, err := s.bob.CreateCommunity(description)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().NotNil(response)
|
||||||
|
s.Require().Len(response.Communities(), 1)
|
||||||
|
|
||||||
|
community := response.Communities()[0]
|
||||||
|
|
||||||
|
chat := CreateOneToOneChat(common.PubkeyToHex(&s.alice.identity.PublicKey), &s.alice.identity.PublicKey, s.alice.transport)
|
||||||
|
|
||||||
|
s.Require().NoError(s.bob.SaveChat(chat))
|
||||||
|
|
||||||
|
message := buildTestMessage(*chat)
|
||||||
|
message.CommunityID = community.IDString()
|
||||||
|
|
||||||
|
// We send a community link to alice
|
||||||
|
response, err = s.bob.SendChatMessage(context.Background(), message)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().NotNil(response)
|
||||||
|
|
||||||
|
// Retrieve community link & community
|
||||||
|
err = tt.RetryWithBackOff(func() error {
|
||||||
|
response, err = s.alice.RetrieveAll()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(response.Communities()) == 0 {
|
||||||
|
return errors.New("message not received")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
s.Require().NoError(err)
|
||||||
|
|
||||||
|
request := &requests.RequestToJoinCommunity{CommunityID: community.ID()}
|
||||||
|
// We try to join the org
|
||||||
|
response, err = s.alice.RequestToJoinCommunity(request)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().NotNil(response)
|
||||||
|
s.Require().Len(response.RequestsToJoinCommunity, 1)
|
||||||
|
|
||||||
|
requestToJoin1 := response.RequestsToJoinCommunity[0]
|
||||||
|
s.Require().NotNil(requestToJoin1)
|
||||||
|
s.Require().Equal(community.ID(), requestToJoin1.CommunityID)
|
||||||
|
s.Require().True(requestToJoin1.Our)
|
||||||
|
s.Require().NotEmpty(requestToJoin1.ID)
|
||||||
|
s.Require().NotEmpty(requestToJoin1.Clock)
|
||||||
|
s.Require().Equal(requestToJoin1.PublicKey, common.PubkeyToHex(&s.alice.identity.PublicKey))
|
||||||
|
s.Require().Equal(communities.RequestToJoinStatePending, requestToJoin1.State)
|
||||||
|
|
||||||
|
// Make sure clock is not empty
|
||||||
|
s.Require().NotEmpty(requestToJoin1.Clock)
|
||||||
|
|
||||||
|
s.Require().Len(response.Communities(), 1)
|
||||||
|
s.Require().Equal(response.Communities()[0].RequestedToJoinAt(), requestToJoin1.Clock)
|
||||||
|
|
||||||
|
// pull all communities to make sure we set RequestedToJoinAt
|
||||||
|
|
||||||
|
allCommunities, err := s.alice.Communities()
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().Len(allCommunities, 2)
|
||||||
|
|
||||||
|
if bytes.Equal(allCommunities[0].ID(), community.ID()) {
|
||||||
|
s.Require().Equal(allCommunities[0].RequestedToJoinAt(), requestToJoin1.Clock)
|
||||||
|
} else {
|
||||||
|
s.Require().Equal(allCommunities[1].RequestedToJoinAt(), requestToJoin1.Clock)
|
||||||
|
}
|
||||||
|
|
||||||
|
// pull to make sure it has been saved
|
||||||
|
requestsToJoin, err := s.alice.MyPendingRequestsToJoin()
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().Len(requestsToJoin, 1)
|
||||||
|
|
||||||
|
// Make sure the requests are fetched also by community
|
||||||
|
requestsToJoin, err = s.alice.PendingRequestsToJoinForCommunity(community.ID())
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().Len(requestsToJoin, 1)
|
||||||
|
|
||||||
|
// Retrieve request to join
|
||||||
|
err = tt.RetryWithBackOff(func() error {
|
||||||
|
response, err = s.bob.RetrieveAll()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(response.RequestsToJoinCommunity) == 0 {
|
||||||
|
return errors.New("request to join community not received")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().Len(response.RequestsToJoinCommunity, 1)
|
||||||
|
|
||||||
|
requestToJoin2 := response.RequestsToJoinCommunity[0]
|
||||||
|
|
||||||
|
s.Require().NotNil(requestToJoin2)
|
||||||
|
s.Require().Equal(community.ID(), requestToJoin2.CommunityID)
|
||||||
|
s.Require().False(requestToJoin2.Our)
|
||||||
|
s.Require().NotEmpty(requestToJoin2.ID)
|
||||||
|
s.Require().NotEmpty(requestToJoin2.Clock)
|
||||||
|
s.Require().Equal(requestToJoin2.PublicKey, common.PubkeyToHex(&s.alice.identity.PublicKey))
|
||||||
|
s.Require().Equal(communities.RequestToJoinStatePending, requestToJoin2.State)
|
||||||
|
|
||||||
|
s.Require().Equal(requestToJoin1.ID, requestToJoin2.ID)
|
||||||
|
|
||||||
|
// Accept request
|
||||||
|
|
||||||
|
acceptRequestToJoin := &requests.AcceptRequestToJoinCommunity{ID: requestToJoin1.ID}
|
||||||
|
|
||||||
|
response, err = s.bob.AcceptRequestToJoinCommunity(acceptRequestToJoin)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().NotNil(response)
|
||||||
|
|
||||||
|
s.Require().Len(response.Communities(), 1)
|
||||||
|
|
||||||
|
updatedCommunity := response.Communities()[0]
|
||||||
|
|
||||||
|
s.Require().NotNil(updatedCommunity)
|
||||||
|
s.Require().True(updatedCommunity.HasMember(&s.alice.identity.PublicKey))
|
||||||
|
|
||||||
|
// Pull message and make sure org is received
|
||||||
|
err = tt.RetryWithBackOff(func() error {
|
||||||
|
response, err = s.alice.RetrieveAll()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(response.Communities()) == 0 {
|
||||||
|
return errors.New("community not received")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().NotNil(response)
|
||||||
|
|
||||||
|
s.Require().Len(response.Communities(), 1)
|
||||||
|
|
||||||
|
aliceCommunity := response.Communities()[0]
|
||||||
|
|
||||||
|
s.Require().Equal(community.ID(), aliceCommunity.ID())
|
||||||
|
s.Require().True(aliceCommunity.HasMember(&s.alice.identity.PublicKey))
|
||||||
|
|
||||||
|
// Community should be joined at this point
|
||||||
|
s.Require().True(aliceCommunity.Joined())
|
||||||
|
|
||||||
|
// Make sure the requests are not pending on either sides
|
||||||
|
requestsToJoin, err = s.bob.PendingRequestsToJoinForCommunity(community.ID())
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().Len(requestsToJoin, 0)
|
||||||
|
|
||||||
|
requestsToJoin, err = s.alice.MyPendingRequestsToJoin()
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().Len(requestsToJoin, 0)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MessengerCommunitiesSuite) TestRequestAccessAgain() {
|
||||||
|
description := &requests.CreateCommunity{
|
||||||
|
Membership: protobuf.CommunityPermissions_ON_REQUEST,
|
||||||
|
Name: "status",
|
||||||
|
Color: "#ffffff",
|
||||||
|
Description: "status community description",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an community chat
|
||||||
|
response, err := s.bob.CreateCommunity(description)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().NotNil(response)
|
||||||
|
s.Require().Len(response.Communities(), 1)
|
||||||
|
|
||||||
|
community := response.Communities()[0]
|
||||||
|
|
||||||
|
chat := CreateOneToOneChat(common.PubkeyToHex(&s.alice.identity.PublicKey), &s.alice.identity.PublicKey, s.alice.transport)
|
||||||
|
|
||||||
|
s.Require().NoError(s.bob.SaveChat(chat))
|
||||||
|
|
||||||
|
message := buildTestMessage(*chat)
|
||||||
|
message.CommunityID = community.IDString()
|
||||||
|
|
||||||
|
// We send a community link to alice
|
||||||
|
response, err = s.bob.SendChatMessage(context.Background(), message)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().NotNil(response)
|
||||||
|
|
||||||
|
// Retrieve community link & community
|
||||||
|
err = tt.RetryWithBackOff(func() error {
|
||||||
|
response, err = s.alice.RetrieveAll()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(response.Communities()) == 0 {
|
||||||
|
return errors.New("message not received")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
s.Require().NoError(err)
|
||||||
|
|
||||||
|
request := &requests.RequestToJoinCommunity{CommunityID: community.ID()}
|
||||||
|
// We try to join the org
|
||||||
|
response, err = s.alice.RequestToJoinCommunity(request)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().NotNil(response)
|
||||||
|
s.Require().Len(response.RequestsToJoinCommunity, 1)
|
||||||
|
|
||||||
|
requestToJoin1 := response.RequestsToJoinCommunity[0]
|
||||||
|
s.Require().NotNil(requestToJoin1)
|
||||||
|
s.Require().Equal(community.ID(), requestToJoin1.CommunityID)
|
||||||
|
s.Require().True(requestToJoin1.Our)
|
||||||
|
s.Require().NotEmpty(requestToJoin1.ID)
|
||||||
|
s.Require().NotEmpty(requestToJoin1.Clock)
|
||||||
|
s.Require().Equal(requestToJoin1.PublicKey, common.PubkeyToHex(&s.alice.identity.PublicKey))
|
||||||
|
s.Require().Equal(communities.RequestToJoinStatePending, requestToJoin1.State)
|
||||||
|
|
||||||
|
// Make sure clock is not empty
|
||||||
|
s.Require().NotEmpty(requestToJoin1.Clock)
|
||||||
|
|
||||||
|
s.Require().Len(response.Communities(), 1)
|
||||||
|
s.Require().Equal(response.Communities()[0].RequestedToJoinAt(), requestToJoin1.Clock)
|
||||||
|
|
||||||
|
// pull all communities to make sure we set RequestedToJoinAt
|
||||||
|
|
||||||
|
allCommunities, err := s.alice.Communities()
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().Len(allCommunities, 2)
|
||||||
|
|
||||||
|
if bytes.Equal(allCommunities[0].ID(), community.ID()) {
|
||||||
|
s.Require().Equal(allCommunities[0].RequestedToJoinAt(), requestToJoin1.Clock)
|
||||||
|
} else {
|
||||||
|
s.Require().Equal(allCommunities[1].RequestedToJoinAt(), requestToJoin1.Clock)
|
||||||
|
}
|
||||||
|
|
||||||
|
// pull to make sure it has been saved
|
||||||
|
requestsToJoin, err := s.alice.MyPendingRequestsToJoin()
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().Len(requestsToJoin, 1)
|
||||||
|
|
||||||
|
// Make sure the requests are fetched also by community
|
||||||
|
requestsToJoin, err = s.alice.PendingRequestsToJoinForCommunity(community.ID())
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().Len(requestsToJoin, 1)
|
||||||
|
|
||||||
|
// Retrieve request to join
|
||||||
|
err = tt.RetryWithBackOff(func() error {
|
||||||
|
response, err = s.bob.RetrieveAll()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(response.RequestsToJoinCommunity) == 0 {
|
||||||
|
return errors.New("request to join community not received")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().Len(response.RequestsToJoinCommunity, 1)
|
||||||
|
|
||||||
|
requestToJoin2 := response.RequestsToJoinCommunity[0]
|
||||||
|
|
||||||
|
s.Require().NotNil(requestToJoin2)
|
||||||
|
s.Require().Equal(community.ID(), requestToJoin2.CommunityID)
|
||||||
|
s.Require().False(requestToJoin2.Our)
|
||||||
|
s.Require().NotEmpty(requestToJoin2.ID)
|
||||||
|
s.Require().NotEmpty(requestToJoin2.Clock)
|
||||||
|
s.Require().Equal(requestToJoin2.PublicKey, common.PubkeyToHex(&s.alice.identity.PublicKey))
|
||||||
|
s.Require().Equal(communities.RequestToJoinStatePending, requestToJoin2.State)
|
||||||
|
|
||||||
|
s.Require().Equal(requestToJoin1.ID, requestToJoin2.ID)
|
||||||
|
|
||||||
|
// Accept request
|
||||||
|
|
||||||
|
acceptRequestToJoin := &requests.AcceptRequestToJoinCommunity{ID: requestToJoin1.ID}
|
||||||
|
|
||||||
|
response, err = s.bob.AcceptRequestToJoinCommunity(acceptRequestToJoin)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().NotNil(response)
|
||||||
|
|
||||||
|
s.Require().Len(response.Communities(), 1)
|
||||||
|
|
||||||
|
updatedCommunity := response.Communities()[0]
|
||||||
|
|
||||||
|
s.Require().NotNil(updatedCommunity)
|
||||||
|
s.Require().True(updatedCommunity.HasMember(&s.alice.identity.PublicKey))
|
||||||
|
|
||||||
|
// Pull message and make sure org is received
|
||||||
|
err = tt.RetryWithBackOff(func() error {
|
||||||
|
response, err = s.alice.RetrieveAll()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(response.Communities()) == 0 {
|
||||||
|
return errors.New("community not received")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().NotNil(response)
|
||||||
|
|
||||||
|
s.Require().Len(response.Communities(), 1)
|
||||||
|
|
||||||
|
aliceCommunity := response.Communities()[0]
|
||||||
|
|
||||||
|
s.Require().Equal(community.ID(), aliceCommunity.ID())
|
||||||
|
s.Require().True(aliceCommunity.HasMember(&s.alice.identity.PublicKey))
|
||||||
|
|
||||||
|
// Community should be joined at this point
|
||||||
|
s.Require().True(aliceCommunity.Joined())
|
||||||
|
|
||||||
|
// Make sure the requests are not pending on either sides
|
||||||
|
requestsToJoin, err = s.bob.PendingRequestsToJoinForCommunity(community.ID())
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().Len(requestsToJoin, 0)
|
||||||
|
|
||||||
|
requestsToJoin, err = s.alice.MyPendingRequestsToJoin()
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().Len(requestsToJoin, 0)
|
||||||
|
|
||||||
|
// We request again
|
||||||
|
request2 := &requests.RequestToJoinCommunity{CommunityID: community.ID()}
|
||||||
|
// We try to join the org, it should error as we are already a member
|
||||||
|
response, err = s.alice.RequestToJoinCommunity(request2)
|
||||||
|
s.Require().Error(err)
|
||||||
|
|
||||||
|
// We kick the member
|
||||||
|
response, err = s.bob.RemoveUserFromCommunity(
|
||||||
|
community.ID(),
|
||||||
|
common.PubkeyToHex(&s.alice.identity.PublicKey),
|
||||||
|
)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().NotNil(response)
|
||||||
|
s.Require().Len(response.Communities(), 1)
|
||||||
|
|
||||||
|
community = response.Communities()[0]
|
||||||
|
s.Require().False(community.HasMember(&s.alice.identity.PublicKey))
|
||||||
|
|
||||||
|
// Alice should then be removed
|
||||||
|
err = tt.RetryWithBackOff(func() error {
|
||||||
|
response, err = s.alice.RetrieveAll()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(response.Communities()) == 0 {
|
||||||
|
return errors.New("community not received")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().NotNil(response)
|
||||||
|
|
||||||
|
s.Require().Len(response.Communities(), 1)
|
||||||
|
|
||||||
|
aliceCommunity = response.Communities()[0]
|
||||||
|
|
||||||
|
s.Require().Equal(community.ID(), aliceCommunity.ID())
|
||||||
|
s.Require().False(aliceCommunity.HasMember(&s.alice.identity.PublicKey))
|
||||||
|
|
||||||
|
// Alice can request access again
|
||||||
|
request3 := &requests.RequestToJoinCommunity{CommunityID: community.ID()}
|
||||||
|
response, err = s.alice.RequestToJoinCommunity(request3)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().NotNil(response)
|
||||||
|
s.Require().Len(response.RequestsToJoinCommunity, 1)
|
||||||
|
|
||||||
|
requestToJoin3 := response.RequestsToJoinCommunity[0]
|
||||||
|
s.Require().NotNil(requestToJoin3)
|
||||||
|
s.Require().Equal(community.ID(), requestToJoin3.CommunityID)
|
||||||
|
s.Require().True(requestToJoin3.Our)
|
||||||
|
s.Require().NotEmpty(requestToJoin3.ID)
|
||||||
|
s.Require().NotEmpty(requestToJoin3.Clock)
|
||||||
|
s.Require().Equal(requestToJoin3.PublicKey, common.PubkeyToHex(&s.alice.identity.PublicKey))
|
||||||
|
s.Require().Equal(communities.RequestToJoinStatePending, requestToJoin3.State)
|
||||||
|
|
||||||
|
s.Require().Len(response.Communities(), 1)
|
||||||
|
s.Require().Equal(response.Communities()[0].RequestedToJoinAt(), requestToJoin3.Clock)
|
||||||
|
|
||||||
|
// Retrieve request to join
|
||||||
|
err = tt.RetryWithBackOff(func() error {
|
||||||
|
response, err = s.bob.RetrieveAll()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(response.RequestsToJoinCommunity) == 0 {
|
||||||
|
return errors.New("request to join community not received")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().Len(response.RequestsToJoinCommunity, 1)
|
||||||
|
|
||||||
|
requestToJoin4 := response.RequestsToJoinCommunity[0]
|
||||||
|
|
||||||
|
s.Require().NotNil(requestToJoin4)
|
||||||
|
s.Require().Equal(community.ID(), requestToJoin4.CommunityID)
|
||||||
|
s.Require().False(requestToJoin4.Our)
|
||||||
|
s.Require().NotEmpty(requestToJoin4.ID)
|
||||||
|
s.Require().NotEmpty(requestToJoin4.Clock)
|
||||||
|
s.Require().Equal(requestToJoin4.PublicKey, common.PubkeyToHex(&s.alice.identity.PublicKey))
|
||||||
|
s.Require().Equal(communities.RequestToJoinStatePending, requestToJoin4.State)
|
||||||
|
|
||||||
|
s.Require().Equal(requestToJoin3.ID, requestToJoin4.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MessengerCommunitiesSuite) TestShareCommunity() {
|
||||||
|
description := &requests.CreateCommunity{
|
||||||
|
Membership: protobuf.CommunityPermissions_NO_MEMBERSHIP,
|
||||||
|
Name: "status",
|
||||||
|
Color: "#ffffff",
|
||||||
|
Description: "status community description",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an community chat
|
||||||
|
response, err := s.bob.CreateCommunity(description)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().NotNil(response)
|
||||||
|
s.Require().Len(response.Communities(), 1)
|
||||||
|
|
||||||
|
community := response.Communities()[0]
|
||||||
|
|
||||||
|
response, err = s.bob.ShareCommunity(
|
||||||
|
&requests.ShareCommunity{
|
||||||
|
CommunityID: community.ID(),
|
||||||
|
Users: []types.HexBytes{common.PubkeyToHexBytes(&s.alice.identity.PublicKey)},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().NotNil(response)
|
||||||
|
s.Require().Len(response.Messages, 1)
|
||||||
|
|
||||||
|
// Pull message and make sure org is received
|
||||||
|
err = tt.RetryWithBackOff(func() error {
|
||||||
|
response, err = s.alice.RetrieveAll()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(response.Messages) == 0 {
|
||||||
|
return errors.New("community link not received")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().Len(response.Messages, 1)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -37,13 +37,6 @@ type Contact struct {
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
// EnsVerified whether we verified the name of the contact
|
// EnsVerified whether we verified the name of the contact
|
||||||
ENSVerified bool `json:"ensVerified"`
|
ENSVerified bool `json:"ensVerified"`
|
||||||
// EnsVerifiedAt the time we last verified the name
|
|
||||||
ENSVerifiedAt uint64 `json:"ensVerifiedAt"`
|
|
||||||
// LastENSClockValue is the last clock value of when we
|
|
||||||
// received an ENS name for the user
|
|
||||||
LastENSClockValue uint64 `json:"lastENSClockValue"`
|
|
||||||
// ENSVerificationRetries is how many times we retried the ENS
|
|
||||||
ENSVerificationRetries uint64 `json:"ensVerificationRetries"`
|
|
||||||
// Generated username name of the contact
|
// Generated username name of the contact
|
||||||
Alias string `json:"alias,omitempty"`
|
Alias string `json:"alias,omitempty"`
|
||||||
// Identicon generated from public key
|
// Identicon generated from public key
|
||||||
|
@ -56,7 +49,6 @@ type Contact struct {
|
||||||
SystemTags []string `json:"systemTags"`
|
SystemTags []string `json:"systemTags"`
|
||||||
|
|
||||||
DeviceInfo []ContactDeviceInfo `json:"deviceInfo"`
|
DeviceInfo []ContactDeviceInfo `json:"deviceInfo"`
|
||||||
TributeToTalk string `json:"tributeToTalk,omitempty"`
|
|
||||||
LocalNickname string `json:"localNickname,omitempty"`
|
LocalNickname string `json:"localNickname,omitempty"`
|
||||||
|
|
||||||
Images map[string]images.IdentityImage `json:"images"`
|
Images map[string]images.IdentityImage `json:"images"`
|
||||||
|
@ -94,14 +86,6 @@ func (c *Contact) Remove() {
|
||||||
c.SystemTags = newSystemTags
|
c.SystemTags = newSystemTags
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Contact) ResetENSVerification(clock uint64, name string) {
|
|
||||||
c.ENSVerifiedAt = 0
|
|
||||||
c.ENSVerified = false
|
|
||||||
c.ENSVerificationRetries = 0
|
|
||||||
c.LastENSClockValue = clock
|
|
||||||
c.Name = name
|
|
||||||
}
|
|
||||||
|
|
||||||
// existsInStringSlice checks if a string is in a set.
|
// existsInStringSlice checks if a string is in a set.
|
||||||
func existsInStringSlice(set []string, find string) bool {
|
func existsInStringSlice(set []string, find string) bool {
|
||||||
for _, s := range set {
|
for _, s := range set {
|
||||||
|
|
|
@ -1,63 +0,0 @@
|
||||||
package protocol
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// maxRetries is the maximum number of attempts we do before giving up
|
|
||||||
const maxRetries uint64 = 11
|
|
||||||
|
|
||||||
// ENSBackoffTimeSec is the step of the exponential backoff
|
|
||||||
// we retry roughly for 17 hours after receiving the message 2^11 * 30
|
|
||||||
const ENSBackoffTimeSec uint64 = 30
|
|
||||||
|
|
||||||
// We calculate if it's too early to retry, by exponentially backing off
|
|
||||||
func verifiedENSRecentlyEnough(now, verifiedAt, retries uint64) bool {
|
|
||||||
return now < verifiedAt+ENSBackoffTimeSec*retries*uint64(math.Exp2(float64(retries)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func shouldENSBeVerified(c *Contact, now uint64) bool {
|
|
||||||
if c.Name == "" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.ENSVerified {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.ENSVerificationRetries >= maxRetries {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if verifiedENSRecentlyEnough(now, c.ENSVerifiedAt, c.ENSVerificationRetries) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if !strings.HasSuffix(c.Name, ".eth") {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// This should trigger re-verification of the ENS name for this contact
|
|
||||||
func hasENSNameChanged(c *Contact, newName string, clockValue uint64) bool {
|
|
||||||
if c.LastENSClockValue > clockValue {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if newName == "" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if !strings.HasSuffix(newName, ".eth") {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if newName == c.Name {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
package ens
|
||||||
|
|
||||||
|
// maxRetries is the maximum number of attempts we do before giving up
|
||||||
|
const maxRetries uint64 = 11
|
||||||
|
|
||||||
|
// ENSBackoffTimeSec is the step of the exponential backoff
|
||||||
|
// we retry roughly for 17 hours after receiving the message 2^11 * 30
|
||||||
|
const ENSBackoffTimeSec uint64 = 30
|
|
@ -0,0 +1,105 @@
|
||||||
|
package ens
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Persistence struct {
|
||||||
|
db *sql.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPersistence(db *sql.DB) *Persistence {
|
||||||
|
return &Persistence{db: db}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Persistence) GetENSToBeVerified(now uint64) ([]*VerificationRecord, error) {
|
||||||
|
rows, err := p.db.Query(`SELECT public_key, name, verified, verified_at, clock, verification_retries, next_retry FROM ens_verification_records WHERE NOT(verified) AND verification_retries < ? AND next_retry <= ?`, maxRetries, now)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var records []*VerificationRecord
|
||||||
|
for rows.Next() {
|
||||||
|
var record VerificationRecord
|
||||||
|
err := rows.Scan(&record.PublicKey, &record.Name, &record.Verified, &record.VerifiedAt, &record.Clock, &record.VerificationRetries, &record.NextRetry)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
records = append(records, &record)
|
||||||
|
}
|
||||||
|
|
||||||
|
return records, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Persistence) UpdateRecords(records []*VerificationRecord) (err error) {
|
||||||
|
var tx *sql.Tx
|
||||||
|
tx, err = p.db.BeginTx(context.Background(), &sql.TxOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if err == nil {
|
||||||
|
err = tx.Commit()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// don't shadow original error
|
||||||
|
_ = tx.Rollback()
|
||||||
|
}()
|
||||||
|
|
||||||
|
for _, record := range records {
|
||||||
|
var stmt *sql.Stmt
|
||||||
|
stmt, err = tx.Prepare(`UPDATE ens_verification_records SET verified = ?, verified_at = ?, verification_retries = ?, next_retry = ? WHERE public_key = ?`)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer stmt.Close()
|
||||||
|
_, err = stmt.Exec(record.Verified, record.VerifiedAt, record.VerificationRetries, record.NextRetry, record.PublicKey)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddRecord adds a record or return the latest available if already in the database and
|
||||||
|
// hasn't changed
|
||||||
|
func (p *Persistence) AddRecord(record VerificationRecord) (response *VerificationRecord, err error) {
|
||||||
|
if !record.Valid() {
|
||||||
|
err = errors.New("invalid ens record")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var tx *sql.Tx
|
||||||
|
tx, err = p.db.BeginTx(context.Background(), &sql.TxOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if err == nil {
|
||||||
|
err = tx.Commit()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// don't shadow original error
|
||||||
|
_ = tx.Rollback()
|
||||||
|
}()
|
||||||
|
|
||||||
|
dbRecord := &VerificationRecord{PublicKey: record.PublicKey}
|
||||||
|
|
||||||
|
err = tx.QueryRow(`SELECT name, clock, verified FROM ens_verification_records WHERE public_key = ?`, record.PublicKey).Scan(&dbRecord.Name, &dbRecord.Clock, &dbRecord.Verified)
|
||||||
|
if err != nil && err != sql.ErrNoRows {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if dbRecord.Clock >= record.Clock || dbRecord.Name == record.Name {
|
||||||
|
response = dbRecord
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = tx.Exec(`INSERT INTO ens_verification_records(public_key, name, clock) VALUES (?,?,?)`, record.PublicKey, record.Name, record.Clock)
|
||||||
|
return
|
||||||
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
package ens
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/status-im/status-go/protocol/sqlite"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetENSToBeVerified(t *testing.T) {
|
||||||
|
pk := "1"
|
||||||
|
name := "test.eth"
|
||||||
|
updatedName := "test2.eth"
|
||||||
|
|
||||||
|
db, err := sqlite.Open(sqlite.InMemoryPath, "")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
err = sqlite.Migrate(db)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
persistence := NewPersistence(db)
|
||||||
|
require.NotNil(t, persistence)
|
||||||
|
|
||||||
|
record := VerificationRecord{Name: name, PublicKey: pk, Clock: 2}
|
||||||
|
|
||||||
|
// We add a record, it should be nil
|
||||||
|
response, err := persistence.AddRecord(record)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Nil(t, response)
|
||||||
|
|
||||||
|
// We add a record again, it should return the same record
|
||||||
|
response, err = persistence.AddRecord(record)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, response)
|
||||||
|
|
||||||
|
require.False(t, response.Verified)
|
||||||
|
require.Equal(t, record.Name, response.Name)
|
||||||
|
require.Equal(t, record.PublicKey, response.PublicKey)
|
||||||
|
|
||||||
|
// We add a record again, with a different clock value
|
||||||
|
record.Clock++
|
||||||
|
response, err = persistence.AddRecord(record)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, response)
|
||||||
|
|
||||||
|
require.False(t, response.Verified)
|
||||||
|
require.Equal(t, record.Name, response.Name)
|
||||||
|
require.Equal(t, record.PublicKey, response.PublicKey)
|
||||||
|
|
||||||
|
// We add a record again, with a different name, but lower clock value
|
||||||
|
record.Clock--
|
||||||
|
record.Name = updatedName
|
||||||
|
response, err = persistence.AddRecord(record)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, response)
|
||||||
|
|
||||||
|
require.False(t, response.Verified)
|
||||||
|
require.Equal(t, name, response.Name)
|
||||||
|
require.Equal(t, record.PublicKey, response.PublicKey)
|
||||||
|
|
||||||
|
// We add a record again, with a different name and higher clock value
|
||||||
|
record.Clock += 2
|
||||||
|
record.Name = updatedName
|
||||||
|
response, err = persistence.AddRecord(record)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Nil(t, response)
|
||||||
|
|
||||||
|
// update the record
|
||||||
|
|
||||||
|
record.Verified = false
|
||||||
|
record.VerificationRetries = 10
|
||||||
|
record.NextRetry = 20
|
||||||
|
record.VerifiedAt = 30
|
||||||
|
|
||||||
|
err = persistence.UpdateRecords([]*VerificationRecord{&record})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
toBeVerified, err := persistence.GetENSToBeVerified(20)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, toBeVerified, 1)
|
||||||
|
require.False(t, toBeVerified[0].Verified)
|
||||||
|
require.Equal(t, uint64(10), toBeVerified[0].VerificationRetries)
|
||||||
|
require.Equal(t, uint64(20), toBeVerified[0].NextRetry)
|
||||||
|
require.Equal(t, uint64(30), toBeVerified[0].VerifiedAt)
|
||||||
|
require.Equal(t, updatedName, toBeVerified[0].Name)
|
||||||
|
require.Equal(t, pk, toBeVerified[0].PublicKey)
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
package ens
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type VerificationRecord struct {
|
||||||
|
PublicKey string
|
||||||
|
Name string
|
||||||
|
Clock uint64
|
||||||
|
Verified bool
|
||||||
|
VerifiedAt uint64
|
||||||
|
VerificationRetries uint64
|
||||||
|
NextRetry uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
// We calculate if it's too early to retry, by exponentially backing off
|
||||||
|
func (e *VerificationRecord) CalculateNextRetry() {
|
||||||
|
e.NextRetry = e.VerifiedAt + ENSBackoffTimeSec*uint64(math.Exp2(float64(e.VerificationRetries)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *VerificationRecord) Valid() bool {
|
||||||
|
return e.Name != "" && strings.HasSuffix(e.Name, ".eth") && e.Clock > 0
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package ens
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNextRetry(t *testing.T) {
|
||||||
|
record := VerificationRecord{Name: "vitalik.eth"}
|
||||||
|
record.VerifiedAt = 10
|
||||||
|
record.CalculateNextRetry()
|
||||||
|
|
||||||
|
var expectedNextRetry uint64 = 30 + 10
|
||||||
|
require.Equal(t, expectedNextRetry, record.NextRetry)
|
||||||
|
|
||||||
|
expectedNextRetry = 60 + 10
|
||||||
|
record.VerificationRetries++
|
||||||
|
record.CalculateNextRetry()
|
||||||
|
require.Equal(t, expectedNextRetry, record.NextRetry)
|
||||||
|
|
||||||
|
expectedNextRetry = 120 + 10
|
||||||
|
record.VerificationRetries++
|
||||||
|
record.CalculateNextRetry()
|
||||||
|
require.Equal(t, expectedNextRetry, record.NextRetry)
|
||||||
|
}
|
|
@ -0,0 +1,194 @@
|
||||||
|
package ens
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"go.uber.org/zap"
|
||||||
|
|
||||||
|
"github.com/status-im/status-go/eth-node/types"
|
||||||
|
enstypes "github.com/status-im/status-go/eth-node/types/ens"
|
||||||
|
"github.com/status-im/status-go/protocol/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Verifier struct {
|
||||||
|
node types.Node
|
||||||
|
online bool
|
||||||
|
persistence *Persistence
|
||||||
|
logger *zap.Logger
|
||||||
|
timesource common.TimeSource
|
||||||
|
subscriptions []chan []*VerificationRecord
|
||||||
|
rpcEndpoint string
|
||||||
|
contractAddress string
|
||||||
|
quit chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(node types.Node, logger *zap.Logger, timesource common.TimeSource, db *sql.DB, rpcEndpoint, contractAddress string) *Verifier {
|
||||||
|
persistence := NewPersistence(db)
|
||||||
|
return &Verifier{
|
||||||
|
node: node,
|
||||||
|
logger: logger,
|
||||||
|
persistence: persistence,
|
||||||
|
timesource: timesource,
|
||||||
|
rpcEndpoint: rpcEndpoint,
|
||||||
|
contractAddress: contractAddress,
|
||||||
|
quit: make(chan struct{}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Verifier) Start() error {
|
||||||
|
go v.verifyLoop()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Verifier) Stop() error {
|
||||||
|
close(v.quit)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ENSVerified adds an already verified entry to the ens table
|
||||||
|
func (v *Verifier) ENSVerified(pk, ensName string, clock uint64) error {
|
||||||
|
|
||||||
|
// Add returns nil if no record was available
|
||||||
|
oldRecord, err := v.Add(pk, ensName, clock)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var record *VerificationRecord
|
||||||
|
|
||||||
|
if oldRecord != nil {
|
||||||
|
record = oldRecord
|
||||||
|
} else {
|
||||||
|
record = &VerificationRecord{PublicKey: pk, Name: ensName, Clock: clock}
|
||||||
|
}
|
||||||
|
|
||||||
|
record.VerifiedAt = clock
|
||||||
|
record.Verified = true
|
||||||
|
records := []*VerificationRecord{record}
|
||||||
|
err = v.persistence.UpdateRecords(records)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.publish(records)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Verifier) Add(pk, ensName string, clock uint64) (*VerificationRecord, error) {
|
||||||
|
record := VerificationRecord{PublicKey: pk, Name: ensName, Clock: clock}
|
||||||
|
return v.persistence.AddRecord(record)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Verifier) SetOnline(online bool) {
|
||||||
|
v.online = online
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Verifier) verifyLoop() {
|
||||||
|
|
||||||
|
ticker := time.NewTicker(30 * time.Second)
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
|
||||||
|
case <-v.quit:
|
||||||
|
ticker.Stop()
|
||||||
|
return
|
||||||
|
case <-ticker.C:
|
||||||
|
if !v.online || v.rpcEndpoint == "" || v.contractAddress == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
err := v.verify(v.rpcEndpoint, v.contractAddress)
|
||||||
|
if err != nil {
|
||||||
|
v.logger.Error("verify loop failed", zap.Error(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Verifier) Subscribe() chan []*VerificationRecord {
|
||||||
|
c := make(chan []*VerificationRecord)
|
||||||
|
v.subscriptions = append(v.subscriptions, c)
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Verifier) publish(records []*VerificationRecord) {
|
||||||
|
v.logger.Info("publishing records", zap.Any("records", records))
|
||||||
|
// Publish on channels, drop if buffer is full
|
||||||
|
for _, s := range v.subscriptions {
|
||||||
|
select {
|
||||||
|
case s <- records:
|
||||||
|
default:
|
||||||
|
v.logger.Warn("ens subscription channel full, dropping message")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify verifies that a registered ENS name matches the expected public key
|
||||||
|
func (v *Verifier) verify(rpcEndpoint, contractAddress string) error {
|
||||||
|
v.logger.Debug("verifying ENS Names", zap.String("endpoint", rpcEndpoint))
|
||||||
|
verifier := v.node.NewENSVerifier(v.logger)
|
||||||
|
|
||||||
|
var ensDetails []enstypes.ENSDetails
|
||||||
|
|
||||||
|
// Now in seconds
|
||||||
|
now := v.timesource.GetCurrentTime() / 1000
|
||||||
|
ensToBeVerified, err := v.persistence.GetENSToBeVerified(now)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
recordsMap := make(map[string]*VerificationRecord)
|
||||||
|
|
||||||
|
for _, r := range ensToBeVerified {
|
||||||
|
recordsMap[r.PublicKey] = r
|
||||||
|
ensDetails = append(ensDetails, enstypes.ENSDetails{
|
||||||
|
PublicKeyString: r.PublicKey[2:],
|
||||||
|
Name: r.Name,
|
||||||
|
})
|
||||||
|
v.logger.Debug("verifying ens name", zap.Any("record", r))
|
||||||
|
}
|
||||||
|
|
||||||
|
ensResponse, err := verifier.CheckBatch(ensDetails, rpcEndpoint, contractAddress)
|
||||||
|
if err != nil {
|
||||||
|
v.logger.Error("failed to check batch", zap.Error(err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var records []*VerificationRecord
|
||||||
|
|
||||||
|
for _, details := range ensResponse {
|
||||||
|
pk := "0x" + details.PublicKeyString
|
||||||
|
record := recordsMap[pk]
|
||||||
|
|
||||||
|
if details.Error == nil {
|
||||||
|
record.Verified = details.Verified
|
||||||
|
if !record.Verified {
|
||||||
|
record.VerificationRetries++
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
v.logger.Warn("Failed to resolve ens name",
|
||||||
|
zap.String("name", details.Name),
|
||||||
|
zap.String("publicKey", details.PublicKeyString),
|
||||||
|
zap.Error(details.Error),
|
||||||
|
)
|
||||||
|
record.VerificationRetries++
|
||||||
|
}
|
||||||
|
record.VerifiedAt = now
|
||||||
|
record.CalculateNextRetry()
|
||||||
|
|
||||||
|
records = append(records, record)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = v.persistence.UpdateRecords(records)
|
||||||
|
if err != nil {
|
||||||
|
|
||||||
|
v.logger.Error("failed to update records", zap.Error(err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
v.publish(records)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -1,140 +0,0 @@
|
||||||
package protocol
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/suite"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ENSSuite struct {
|
|
||||||
suite.Suite
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestENSSuite(t *testing.T) {
|
|
||||||
suite.Run(t, new(ENSSuite))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ENSSuite) TestShouldBeVerified() {
|
|
||||||
testCases := []struct {
|
|
||||||
Name string
|
|
||||||
Contact Contact
|
|
||||||
Expected bool
|
|
||||||
TimeNow uint64
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
Name: "valid eth name",
|
|
||||||
Contact: Contact{Name: "vitalik.eth"},
|
|
||||||
Expected: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "valid eth name,some retries",
|
|
||||||
Contact: Contact{
|
|
||||||
Name: "vitalik.eth",
|
|
||||||
ENSVerifiedAt: 10,
|
|
||||||
ENSVerificationRetries: 4,
|
|
||||||
},
|
|
||||||
Expected: true,
|
|
||||||
TimeNow: 10 + ENSBackoffTimeSec*4*16 + 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "Empty name",
|
|
||||||
Contact: Contact{},
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "invalid eth name",
|
|
||||||
Contact: Contact{Name: "vitalik.eth2"},
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "Already verified",
|
|
||||||
Contact: Contact{
|
|
||||||
Name: "vitalik.eth",
|
|
||||||
ENSVerified: true,
|
|
||||||
},
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
Name: "verified recently",
|
|
||||||
Contact: Contact{
|
|
||||||
Name: "vitalik.eth",
|
|
||||||
ENSVerifiedAt: 10,
|
|
||||||
ENSVerificationRetries: 4,
|
|
||||||
},
|
|
||||||
Expected: false,
|
|
||||||
TimeNow: 10 + ENSBackoffTimeSec*4*16 - 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "max retries reached",
|
|
||||||
Contact: Contact{
|
|
||||||
Name: "vitalik.eth",
|
|
||||||
ENSVerifiedAt: 10,
|
|
||||||
ENSVerificationRetries: 11,
|
|
||||||
},
|
|
||||||
Expected: false,
|
|
||||||
TimeNow: 10 + ENSBackoffTimeSec*5*2048 + 1,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tc := range testCases {
|
|
||||||
s.Run(tc.Name, func() {
|
|
||||||
response := shouldENSBeVerified(&tc.Contact, tc.TimeNow)
|
|
||||||
s.Equal(tc.Expected, response)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ENSSuite) TestHasENSNameChanged() {
|
|
||||||
testCases := []struct {
|
|
||||||
Name string
|
|
||||||
Contact Contact
|
|
||||||
NewName string
|
|
||||||
Clock uint64
|
|
||||||
Expected bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
Name: "clock value is greater",
|
|
||||||
Contact: Contact{LastENSClockValue: 0},
|
|
||||||
Clock: 1,
|
|
||||||
NewName: "vitalik.eth",
|
|
||||||
Expected: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "name in empty",
|
|
||||||
Contact: Contact{LastENSClockValue: 0},
|
|
||||||
Clock: 1,
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "name is invalid",
|
|
||||||
Contact: Contact{LastENSClockValue: 0},
|
|
||||||
Clock: 1,
|
|
||||||
NewName: "vitalik.eth2",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "name is identical",
|
|
||||||
Contact: Contact{
|
|
||||||
Name: "vitalik.eth",
|
|
||||||
LastENSClockValue: 0,
|
|
||||||
},
|
|
||||||
Clock: 1,
|
|
||||||
NewName: "vitalik.eth",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
Name: "clock value is less",
|
|
||||||
Contact: Contact{LastENSClockValue: 1},
|
|
||||||
Clock: 0,
|
|
||||||
NewName: "vitalik.eth",
|
|
||||||
Expected: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tc := range testCases {
|
|
||||||
s.Run(tc.Name, func() {
|
|
||||||
response := hasENSNameChanged(&tc.Contact, tc.NewName, tc.Clock)
|
|
||||||
s.Equal(tc.Expected, response)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"github.com/status-im/status-go/protocol/common"
|
"github.com/status-im/status-go/protocol/common"
|
||||||
"github.com/status-im/status-go/protocol/communities"
|
"github.com/status-im/status-go/protocol/communities"
|
||||||
"github.com/status-im/status-go/protocol/encryption/multidevice"
|
"github.com/status-im/status-go/protocol/encryption/multidevice"
|
||||||
|
"github.com/status-im/status-go/protocol/ens"
|
||||||
"github.com/status-im/status-go/protocol/protobuf"
|
"github.com/status-im/status-go/protocol/protobuf"
|
||||||
"github.com/status-im/status-go/protocol/transport"
|
"github.com/status-im/status-go/protocol/transport"
|
||||||
v1protocol "github.com/status-im/status-go/protocol/v1"
|
v1protocol "github.com/status-im/status-go/protocol/v1"
|
||||||
|
@ -31,15 +32,17 @@ type MessageHandler struct {
|
||||||
identity *ecdsa.PrivateKey
|
identity *ecdsa.PrivateKey
|
||||||
persistence *sqlitePersistence
|
persistence *sqlitePersistence
|
||||||
transport transport.Transport
|
transport transport.Transport
|
||||||
|
ensVerifier *ens.Verifier
|
||||||
communitiesManager *communities.Manager
|
communitiesManager *communities.Manager
|
||||||
logger *zap.Logger
|
logger *zap.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func newMessageHandler(identity *ecdsa.PrivateKey, logger *zap.Logger, persistence *sqlitePersistence, communitiesManager *communities.Manager, transport transport.Transport) *MessageHandler {
|
func newMessageHandler(identity *ecdsa.PrivateKey, logger *zap.Logger, persistence *sqlitePersistence, communitiesManager *communities.Manager, transport transport.Transport, ensVerifier *ens.Verifier) *MessageHandler {
|
||||||
return &MessageHandler{
|
return &MessageHandler{
|
||||||
identity: identity,
|
identity: identity,
|
||||||
persistence: persistence,
|
persistence: persistence,
|
||||||
communitiesManager: communitiesManager,
|
communitiesManager: communitiesManager,
|
||||||
|
ensVerifier: ensVerifier,
|
||||||
transport: transport,
|
transport: transport,
|
||||||
logger: logger}
|
logger: logger}
|
||||||
}
|
}
|
||||||
|
@ -141,8 +144,7 @@ func (m *MessageHandler) HandleMembershipUpdate(messageState *ReceivedMessageSta
|
||||||
|
|
||||||
// Store in chats map as it might be a new one
|
// Store in chats map as it might be a new one
|
||||||
messageState.AllChats[chat.ID] = chat
|
messageState.AllChats[chat.ID] = chat
|
||||||
// Set in the map
|
messageState.Response.AddChat(chat)
|
||||||
messageState.ModifiedChats[chat.ID] = true
|
|
||||||
|
|
||||||
if message.Message != nil {
|
if message.Message != nil {
|
||||||
messageState.CurrentMessageState.Message = *message.Message
|
messageState.CurrentMessageState.Message = *message.Message
|
||||||
|
@ -202,7 +204,7 @@ func (m *MessageHandler) handleCommandMessage(state *ReceivedMessageState, messa
|
||||||
// Set chat active
|
// Set chat active
|
||||||
chat.Active = true
|
chat.Active = true
|
||||||
// Set in the modified maps chat
|
// Set in the modified maps chat
|
||||||
state.ModifiedChats[chat.ID] = true
|
state.Response.AddChat(chat)
|
||||||
state.AllChats[chat.ID] = chat
|
state.AllChats[chat.ID] = chat
|
||||||
|
|
||||||
// Add to response
|
// Add to response
|
||||||
|
@ -258,8 +260,8 @@ func (m *MessageHandler) HandleSyncInstallationPublicChat(state *ReceivedMessage
|
||||||
|
|
||||||
chat := CreatePublicChat(chatID, state.Timesource)
|
chat := CreatePublicChat(chatID, state.Timesource)
|
||||||
|
|
||||||
state.AllChats[chat.ID] = &chat
|
state.AllChats[chat.ID] = chat
|
||||||
state.ModifiedChats[chat.ID] = true
|
state.Response.AddChat(chat)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -294,7 +296,7 @@ func (m *MessageHandler) HandleContactUpdate(state *ReceivedMessageState, messag
|
||||||
chat.LastClockValue = message.Clock
|
chat.LastClockValue = message.Clock
|
||||||
}
|
}
|
||||||
|
|
||||||
state.ModifiedChats[chat.ID] = true
|
state.Response.AddChat(chat)
|
||||||
state.AllChats[chat.ID] = chat
|
state.AllChats[chat.ID] = chat
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -326,12 +328,15 @@ func (m *MessageHandler) HandlePairInstallation(state *ReceivedMessageState, mes
|
||||||
|
|
||||||
// HandleCommunityDescription handles an community description
|
// HandleCommunityDescription handles an community description
|
||||||
func (m *MessageHandler) HandleCommunityDescription(state *ReceivedMessageState, signer *ecdsa.PublicKey, description protobuf.CommunityDescription, rawPayload []byte) error {
|
func (m *MessageHandler) HandleCommunityDescription(state *ReceivedMessageState, signer *ecdsa.PublicKey, description protobuf.CommunityDescription, rawPayload []byte) error {
|
||||||
community, err := m.communitiesManager.HandleCommunityDescriptionMessage(signer, &description, rawPayload)
|
communityResponse, err := m.communitiesManager.HandleCommunityDescriptionMessage(signer, &description, rawPayload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
state.AllCommunities[community.IDString()] = community
|
community := communityResponse.Community
|
||||||
|
|
||||||
|
state.Response.AddCommunity(community)
|
||||||
|
state.Response.CommunityChanges = append(state.Response.CommunityChanges, communityResponse.Changes)
|
||||||
|
|
||||||
// If we haven't joined the org, nothing to do
|
// If we haven't joined the org, nothing to do
|
||||||
if !community.Joined() {
|
if !community.Joined() {
|
||||||
|
@ -347,14 +352,14 @@ func (m *MessageHandler) HandleCommunityDescription(state *ReceivedMessageState,
|
||||||
oldChat, ok := state.AllChats[chat.ID]
|
oldChat, ok := state.AllChats[chat.ID]
|
||||||
if !ok {
|
if !ok {
|
||||||
// Beware, don't use the reference in the range (i.e chat) as it's a shallow copy
|
// Beware, don't use the reference in the range (i.e chat) as it's a shallow copy
|
||||||
state.AllChats[chat.ID] = &chats[i]
|
state.AllChats[chat.ID] = chats[i]
|
||||||
|
|
||||||
state.ModifiedChats[chat.ID] = true
|
state.Response.AddChat(chat)
|
||||||
chatIDs = append(chatIDs, chat.ID)
|
chatIDs = append(chatIDs, chat.ID)
|
||||||
// Update name, currently is the only field is mutable
|
// Update name, currently is the only field is mutable
|
||||||
} else if oldChat.Name != chat.Name {
|
} else if oldChat.Name != chat.Name {
|
||||||
state.AllChats[chat.ID].Name = chat.Name
|
state.AllChats[chat.ID].Name = chat.Name
|
||||||
state.ModifiedChats[chat.ID] = true
|
state.Response.AddChat(chat)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -385,17 +390,37 @@ func (m *MessageHandler) HandleCommunityInvitation(state *ReceivedMessageState,
|
||||||
return errors.New("invitation not for us")
|
return errors.New("invitation not for us")
|
||||||
}
|
}
|
||||||
|
|
||||||
community, err := m.communitiesManager.HandleCommunityInvitation(signer, &invitation, rawPayload)
|
communityResponse, err := m.communitiesManager.HandleCommunityInvitation(signer, &invitation, rawPayload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
state.AllCommunities[community.IDString()] = community
|
|
||||||
|
community := communityResponse.Community
|
||||||
|
|
||||||
|
state.Response.AddCommunity(community)
|
||||||
|
state.Response.CommunityChanges = append(state.Response.CommunityChanges, communityResponse.Changes)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleWrappedCommunityDescriptionMessage handles a wrapped community description
|
// HandleCommunityRequestToJoin handles an community request to join
|
||||||
func (m *MessageHandler) HandleWrappedCommunityDescriptionMessage(payload []byte) (*communities.Community, error) {
|
func (m *MessageHandler) HandleCommunityRequestToJoin(state *ReceivedMessageState, signer *ecdsa.PublicKey, requestToJoinProto protobuf.CommunityRequestToJoin) error {
|
||||||
|
if requestToJoinProto.CommunityId == nil {
|
||||||
|
return errors.New("invalid community id")
|
||||||
|
}
|
||||||
|
|
||||||
|
requestToJoin, err := m.communitiesManager.HandleCommunityRequestToJoin(signer, &requestToJoinProto)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
state.Response.RequestsToJoinCommunity = append(state.Response.RequestsToJoinCommunity, requestToJoin)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleWrappedCommunityDescriptionMessage handles a wrapped community description
|
||||||
|
func (m *MessageHandler) handleWrappedCommunityDescriptionMessage(payload []byte) (*communities.CommunityResponse, error) {
|
||||||
return m.communitiesManager.HandleWrappedCommunityDescriptionMessage(payload)
|
return m.communitiesManager.HandleWrappedCommunityDescriptionMessage(payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -466,26 +491,35 @@ func (m *MessageHandler) HandleChatMessage(state *ReceivedMessageState) error {
|
||||||
// Set chat active
|
// Set chat active
|
||||||
chat.Active = true
|
chat.Active = true
|
||||||
// Set in the modified maps chat
|
// Set in the modified maps chat
|
||||||
state.ModifiedChats[chat.ID] = true
|
state.Response.AddChat(chat)
|
||||||
state.AllChats[chat.ID] = chat
|
state.AllChats[chat.ID] = chat
|
||||||
|
|
||||||
contact := state.CurrentMessageState.Contact
|
contact := state.CurrentMessageState.Contact
|
||||||
if hasENSNameChanged(contact, receivedMessage.EnsName, receivedMessage.Clock) {
|
if receivedMessage.EnsName != "" {
|
||||||
contact.ResetENSVerification(receivedMessage.Clock, receivedMessage.EnsName)
|
oldRecord, err := m.ensVerifier.Add(contact.ID, receivedMessage.EnsName, receivedMessage.Clock)
|
||||||
state.ModifiedContacts[contact.ID] = true
|
if err != nil {
|
||||||
state.AllContacts[contact.ID] = contact
|
m.logger.Warn("failed to verify ENS name", zap.Error(err))
|
||||||
|
} else if oldRecord == nil {
|
||||||
|
// If oldRecord is nil, a new verification process will take place
|
||||||
|
// so we reset the record
|
||||||
|
contact.ENSVerified = false
|
||||||
|
state.ModifiedContacts[contact.ID] = true
|
||||||
|
state.AllContacts[contact.ID] = contact
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if receivedMessage.ContentType == protobuf.ChatMessage_COMMUNITY {
|
if receivedMessage.ContentType == protobuf.ChatMessage_COMMUNITY {
|
||||||
m.logger.Debug("Handling community content type")
|
m.logger.Debug("Handling community content type")
|
||||||
|
|
||||||
community, err := m.HandleWrappedCommunityDescriptionMessage(receivedMessage.GetCommunity())
|
communityResponse, err := m.handleWrappedCommunityDescriptionMessage(receivedMessage.GetCommunity())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
community := communityResponse.Community
|
||||||
receivedMessage.CommunityID = community.IDString()
|
receivedMessage.CommunityID = community.IDString()
|
||||||
|
|
||||||
state.AllCommunities[community.IDString()] = community
|
state.Response.AddCommunity(community)
|
||||||
|
state.Response.CommunityChanges = append(state.Response.CommunityChanges, communityResponse.Changes)
|
||||||
}
|
}
|
||||||
// Add to response
|
// Add to response
|
||||||
state.Response.Messages = append(state.Response.Messages, receivedMessage)
|
state.Response.Messages = append(state.Response.Messages, receivedMessage)
|
||||||
|
@ -729,8 +763,7 @@ func (m *MessageHandler) matchChatEntity(chatEntity common.ChatEntity, chats map
|
||||||
return nil, errors.Wrap(err, "failed to decode pubkey")
|
return nil, errors.Wrap(err, "failed to decode pubkey")
|
||||||
}
|
}
|
||||||
|
|
||||||
newChat := CreateOneToOneChat(chatID[:8], pubKey, timesource)
|
chat = CreateOneToOneChat(chatID[:8], pubKey, timesource)
|
||||||
chat = &newChat
|
|
||||||
}
|
}
|
||||||
return chat, nil
|
return chat, nil
|
||||||
case chatEntity.GetMessageType() == protobuf.MessageType_ONE_TO_ONE:
|
case chatEntity.GetMessageType() == protobuf.MessageType_ONE_TO_ONE:
|
||||||
|
@ -740,8 +773,7 @@ func (m *MessageHandler) matchChatEntity(chatEntity common.ChatEntity, chats map
|
||||||
chat := chats[chatID]
|
chat := chats[chatID]
|
||||||
if chat == nil {
|
if chat == nil {
|
||||||
// TODO: this should be a three-word name used in the mobile client
|
// TODO: this should be a three-word name used in the mobile client
|
||||||
newChat := CreateOneToOneChat(chatID[:8], chatEntity.GetSigPubKey(), timesource)
|
chat = CreateOneToOneChat(chatID[:8], chatEntity.GetSigPubKey(), timesource)
|
||||||
chat = &newChat
|
|
||||||
}
|
}
|
||||||
return chat, nil
|
return chat, nil
|
||||||
case chatEntity.GetMessageType() == protobuf.MessageType_COMMUNITY_CHAT:
|
case chatEntity.GetMessageType() == protobuf.MessageType_COMMUNITY_CHAT:
|
||||||
|
@ -863,7 +895,7 @@ func (m *MessageHandler) HandleEmojiReaction(state *ReceivedMessageState, pbEmoj
|
||||||
chat.LastClockValue = pbEmojiR.Clock
|
chat.LastClockValue = pbEmojiR.Clock
|
||||||
}
|
}
|
||||||
|
|
||||||
state.ModifiedChats[chat.ID] = true
|
state.Response.AddChat(chat)
|
||||||
state.AllChats[chat.ID] = chat
|
state.AllChats[chat.ID] = chat
|
||||||
|
|
||||||
// save emoji reaction
|
// save emoji reaction
|
||||||
|
|
|
@ -23,7 +23,6 @@ import (
|
||||||
|
|
||||||
"github.com/status-im/status-go/eth-node/crypto"
|
"github.com/status-im/status-go/eth-node/crypto"
|
||||||
"github.com/status-im/status-go/eth-node/types"
|
"github.com/status-im/status-go/eth-node/types"
|
||||||
enstypes "github.com/status-im/status-go/eth-node/types/ens"
|
|
||||||
userimage "github.com/status-im/status-go/images"
|
userimage "github.com/status-im/status-go/images"
|
||||||
"github.com/status-im/status-go/multiaccounts"
|
"github.com/status-im/status-go/multiaccounts"
|
||||||
"github.com/status-im/status-go/protocol/audio"
|
"github.com/status-im/status-go/protocol/audio"
|
||||||
|
@ -32,6 +31,7 @@ import (
|
||||||
"github.com/status-im/status-go/protocol/encryption"
|
"github.com/status-im/status-go/protocol/encryption"
|
||||||
"github.com/status-im/status-go/protocol/encryption/multidevice"
|
"github.com/status-im/status-go/protocol/encryption/multidevice"
|
||||||
"github.com/status-im/status-go/protocol/encryption/sharedsecret"
|
"github.com/status-im/status-go/protocol/encryption/sharedsecret"
|
||||||
|
"github.com/status-im/status-go/protocol/ens"
|
||||||
"github.com/status-im/status-go/protocol/identity/alias"
|
"github.com/status-im/status-go/protocol/identity/alias"
|
||||||
"github.com/status-im/status-go/protocol/identity/identicon"
|
"github.com/status-im/status-go/protocol/identity/identicon"
|
||||||
"github.com/status-im/status-go/protocol/images"
|
"github.com/status-im/status-go/protocol/images"
|
||||||
|
@ -81,6 +81,7 @@ type Messenger struct {
|
||||||
encryptor *encryption.Protocol
|
encryptor *encryption.Protocol
|
||||||
processor *common.MessageProcessor
|
processor *common.MessageProcessor
|
||||||
handler *MessageHandler
|
handler *MessageHandler
|
||||||
|
ensVerifier *ens.Verifier
|
||||||
pushNotificationClient *pushnotificationclient.Client
|
pushNotificationClient *pushnotificationclient.Client
|
||||||
pushNotificationServer *pushnotificationserver.Server
|
pushNotificationServer *pushnotificationserver.Server
|
||||||
communitiesManager *communities.Manager
|
communitiesManager *communities.Manager
|
||||||
|
@ -271,12 +272,13 @@ func NewMessenger(
|
||||||
|
|
||||||
pushNotificationClient := pushnotificationclient.New(pushNotificationClientPersistence, pushNotificationClientConfig, processor, &sqlitePersistence{db: database})
|
pushNotificationClient := pushnotificationclient.New(pushNotificationClientPersistence, pushNotificationClientConfig, processor, &sqlitePersistence{db: database})
|
||||||
|
|
||||||
communitiesManager, err := communities.NewManager(database, logger)
|
ensVerifier := ens.New(node, logger, transp, database, c.verifyENSURL, c.verifyENSContractAddress)
|
||||||
|
|
||||||
|
communitiesManager, err := communities.NewManager(&identity.PublicKey, database, logger, ensVerifier)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
handler := newMessageHandler(identity, logger, &sqlitePersistence{db: database}, communitiesManager, transp, ensVerifier)
|
||||||
handler := newMessageHandler(identity, logger, &sqlitePersistence{db: database}, communitiesManager, transp)
|
|
||||||
|
|
||||||
messenger = &Messenger{
|
messenger = &Messenger{
|
||||||
config: &c,
|
config: &c,
|
||||||
|
@ -290,6 +292,7 @@ func NewMessenger(
|
||||||
pushNotificationClient: pushNotificationClient,
|
pushNotificationClient: pushNotificationClient,
|
||||||
pushNotificationServer: pushNotificationServer,
|
pushNotificationServer: pushNotificationServer,
|
||||||
communitiesManager: communitiesManager,
|
communitiesManager: communitiesManager,
|
||||||
|
ensVerifier: ensVerifier,
|
||||||
featureFlags: c.featureFlags,
|
featureFlags: c.featureFlags,
|
||||||
systemMessagesTranslations: c.systemMessagesTranslations,
|
systemMessagesTranslations: c.systemMessagesTranslations,
|
||||||
allChats: make(map[string]*Chat),
|
allChats: make(map[string]*Chat),
|
||||||
|
@ -304,6 +307,7 @@ func NewMessenger(
|
||||||
account: c.account,
|
account: c.account,
|
||||||
quit: make(chan struct{}),
|
quit: make(chan struct{}),
|
||||||
shutdownTasks: []func() error{
|
shutdownTasks: []func() error{
|
||||||
|
ensVerifier.Stop,
|
||||||
pushNotificationClient.Stop,
|
pushNotificationClient.Stop,
|
||||||
communitiesManager.Stop,
|
communitiesManager.Stop,
|
||||||
encryptionProtocol.Stop,
|
encryptionProtocol.Stop,
|
||||||
|
@ -413,6 +417,17 @@ func (m *Messenger) Start() (*MessengerResponse, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ensSubscription := m.ensVerifier.Subscribe()
|
||||||
|
|
||||||
|
// Subscrbe
|
||||||
|
if err := m.ensVerifier.Start(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := m.communitiesManager.Start(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// set shared secret handles
|
// set shared secret handles
|
||||||
m.processor.SetHandleSharedSecrets(m.handleSharedSecrets)
|
m.processor.SetHandleSharedSecrets(m.handleSharedSecrets)
|
||||||
|
|
||||||
|
@ -430,6 +445,7 @@ func (m *Messenger) Start() (*MessengerResponse, error) {
|
||||||
m.handleEncryptionLayerSubscriptions(subscriptions)
|
m.handleEncryptionLayerSubscriptions(subscriptions)
|
||||||
m.handleCommunitiesSubscription(m.communitiesManager.Subscribe())
|
m.handleCommunitiesSubscription(m.communitiesManager.Subscribe())
|
||||||
m.handleConnectionChange(m.online())
|
m.handleConnectionChange(m.online())
|
||||||
|
m.handleENSVerificationSubscription(ensSubscription)
|
||||||
m.watchConnectionChange()
|
m.watchConnectionChange()
|
||||||
m.watchExpiredEmojis()
|
m.watchExpiredEmojis()
|
||||||
m.watchIdentityImageChanges()
|
m.watchIdentityImageChanges()
|
||||||
|
@ -498,6 +514,7 @@ func (m *Messenger) handleConnectionChange(online bool) {
|
||||||
m.pushNotificationClient.Offline()
|
m.pushNotificationClient.Offline()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
m.ensVerifier.SetOnline(online)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Messenger) online() bool {
|
func (m *Messenger) online() bool {
|
||||||
|
@ -788,106 +805,56 @@ func (m *Messenger) handleEncryptionLayerSubscriptions(subscriptions *encryption
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Messenger) publishOrg(org *communities.Community) error {
|
func (m *Messenger) handleENSVerified(records []*ens.VerificationRecord) {
|
||||||
m.logger.Debug("publishing org", zap.String("org-id", org.IDString()), zap.Any("org", org))
|
m.mutex.Lock()
|
||||||
payload, err := org.MarshaledDescription()
|
defer m.mutex.Unlock()
|
||||||
if err != nil {
|
|
||||||
return err
|
var contacts []*Contact
|
||||||
|
for _, record := range records {
|
||||||
|
m.logger.Info("handling record", zap.Any("record", record))
|
||||||
|
contact, ok := m.allContacts[record.PublicKey]
|
||||||
|
if !ok {
|
||||||
|
m.logger.Info("contact not found")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
contact.ENSVerified = record.Verified
|
||||||
|
contact.Name = record.Name
|
||||||
|
contacts = append(contacts, contact)
|
||||||
}
|
}
|
||||||
|
|
||||||
rawMessage := common.RawMessage{
|
m.logger.Info("handled records", zap.Any("contacts", contacts))
|
||||||
Payload: payload,
|
if len(contacts) != 0 {
|
||||||
Sender: org.PrivateKey(),
|
if err := m.persistence.SaveContacts(contacts); err != nil {
|
||||||
// we don't want to wrap in an encryption layer message
|
m.logger.Error("failed to save contacts", zap.Error(err))
|
||||||
SkipEncryption: true,
|
return
|
||||||
MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_DESCRIPTION,
|
}
|
||||||
}
|
}
|
||||||
_, err = m.processor.SendPublic(context.Background(), org.IDString(), rawMessage)
|
|
||||||
return err
|
m.logger.Info("calling on contacts")
|
||||||
|
if m.config.onContactENSVerified != nil {
|
||||||
|
m.logger.Info("called on contacts")
|
||||||
|
response := &MessengerResponse{Contacts: contacts}
|
||||||
|
m.config.onContactENSVerified(response)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Messenger) publishOrgInvitation(org *communities.Community, invitation *protobuf.CommunityInvitation) error {
|
func (m *Messenger) handleENSVerificationSubscription(c chan []*ens.VerificationRecord) {
|
||||||
m.logger.Debug("publishing org invitation", zap.String("org-id", org.IDString()), zap.Any("org", org))
|
|
||||||
pk, err := crypto.DecompressPubkey(invitation.PublicKey)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
payload, err := proto.Marshal(invitation)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
rawMessage := common.RawMessage{
|
|
||||||
Payload: payload,
|
|
||||||
Sender: org.PrivateKey(),
|
|
||||||
// we don't want to wrap in an encryption layer message
|
|
||||||
SkipEncryption: true,
|
|
||||||
MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_INVITATION,
|
|
||||||
}
|
|
||||||
_, err = m.processor.SendPrivate(context.Background(), pk, &rawMessage)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// handleCommunitiesSubscription handles events from communities
|
|
||||||
func (m *Messenger) handleCommunitiesSubscription(c chan *communities.Subscription) {
|
|
||||||
|
|
||||||
var lastPublished int64
|
|
||||||
// We check every 5 minutes if we need to publish
|
|
||||||
ticker := time.NewTicker(5 * time.Minute)
|
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case sub, more := <-c:
|
case records, more := <-c:
|
||||||
if !more {
|
if !more {
|
||||||
|
m.logger.Info("No more records, quitting")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if sub.Community != nil {
|
if len(records) != 0 {
|
||||||
err := m.publishOrg(sub.Community)
|
m.logger.Info("handling records", zap.Any("records", records))
|
||||||
if err != nil {
|
m.handleENSVerified(records)
|
||||||
m.logger.Warn("failed to publish org", zap.Error(err))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if sub.Invitation != nil {
|
|
||||||
err := m.publishOrgInvitation(sub.Community, sub.Invitation)
|
|
||||||
if err != nil {
|
|
||||||
m.logger.Warn("failed to publish org invitation", zap.Error(err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m.logger.Debug("published org")
|
|
||||||
case <-ticker.C:
|
|
||||||
// If we are not online, we don't even try
|
|
||||||
if !m.online() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// If not enough time has passed since last advertisement, we skip this
|
|
||||||
if time.Now().Unix()-lastPublished < communityAdvertiseIntervalSecond {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
orgs, err := m.communitiesManager.Created()
|
|
||||||
if err != nil {
|
|
||||||
m.logger.Warn("failed to retrieve orgs", zap.Error(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
for idx := range orgs {
|
|
||||||
org := orgs[idx]
|
|
||||||
err := m.publishOrg(org)
|
|
||||||
if err != nil {
|
|
||||||
m.logger.Warn("failed to publish org", zap.Error(err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// set lastPublished
|
|
||||||
lastPublished = time.Now().Unix()
|
|
||||||
|
|
||||||
case <-m.quit:
|
case <-m.quit:
|
||||||
return
|
return
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
@ -994,15 +961,31 @@ func (m *Messenger) Init() error {
|
||||||
publicKeys []*ecdsa.PublicKey
|
publicKeys []*ecdsa.PublicKey
|
||||||
)
|
)
|
||||||
|
|
||||||
communities, err := m.communitiesManager.Joined()
|
joinedCommunities, err := m.communitiesManager.Joined()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, org := range communities {
|
for _, org := range joinedCommunities {
|
||||||
// the org advertise on the public topic derived by the pk
|
// the org advertise on the public topic derived by the pk
|
||||||
publicChatIDs = append(publicChatIDs, org.IDString())
|
publicChatIDs = append(publicChatIDs, org.IDString())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Init filters for the communities we are an admin of
|
||||||
|
var adminCommunitiesPks []*ecdsa.PrivateKey
|
||||||
|
adminCommunities, err := m.communitiesManager.Created()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range adminCommunities {
|
||||||
|
adminCommunitiesPks = append(adminCommunitiesPks, c.PrivateKey())
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = m.transport.InitCommunityFilters(adminCommunitiesPks)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Get chat IDs and public keys from the existing chats.
|
// Get chat IDs and public keys from the existing chats.
|
||||||
// TODO: Get only active chats by the query.
|
// TODO: Get only active chats by the query.
|
||||||
chats, err := m.persistence.Chats()
|
chats, err := m.persistence.Chats()
|
||||||
|
@ -1182,28 +1165,6 @@ func (m *Messenger) Mailservers() ([]string, error) {
|
||||||
return nil, ErrNotImplemented
|
return nil, ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Messenger) Join(chat Chat) error {
|
|
||||||
switch chat.ChatType {
|
|
||||||
case ChatTypeOneToOne:
|
|
||||||
pk, err := chat.PublicKey()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return m.transport.JoinPrivate(pk)
|
|
||||||
case ChatTypePrivateGroupChat:
|
|
||||||
members, err := chat.MembersAsPublicKeys()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return m.transport.JoinGroup(members)
|
|
||||||
case ChatTypePublic, ChatTypeProfile, ChatTypeTimeline:
|
|
||||||
return m.transport.JoinPublic(chat.ID)
|
|
||||||
default:
|
|
||||||
return errors.New("chat is neither public nor private")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is not accurate, it should not leave transport on removal of chat/group
|
// This is not accurate, it should not leave transport on removal of chat/group
|
||||||
// only once there is no more: Group chat with that member, one-to-one chat, contact added by us
|
// only once there is no more: Group chat with that member, one-to-one chat, contact added by us
|
||||||
func (m *Messenger) Leave(chat Chat) error {
|
func (m *Messenger) Leave(chat Chat) error {
|
||||||
|
@ -1288,7 +1249,7 @@ func (m *Messenger) CreateGroupChatWithMembers(ctx context.Context, name string,
|
||||||
|
|
||||||
chat.updateChatFromGroupMembershipChanges(contactIDFromPublicKey(&m.identity.PublicKey), group)
|
chat.updateChatFromGroupMembershipChanges(contactIDFromPublicKey(&m.identity.PublicKey), group)
|
||||||
|
|
||||||
response.Chats = []*Chat{&chat}
|
response.AddChat(&chat)
|
||||||
response.Messages = buildSystemMessages(chat.MembershipUpdates, m.systemMessagesTranslations)
|
response.Messages = buildSystemMessages(chat.MembershipUpdates, m.systemMessagesTranslations)
|
||||||
err = m.persistence.SaveMessages(response.Messages)
|
err = m.persistence.SaveMessages(response.Messages)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1310,7 +1271,7 @@ func (m *Messenger) CreateGroupChatFromInvitation(name string, chatID string, ad
|
||||||
chat.Name = name
|
chat.Name = name
|
||||||
chat.InvitationAdmin = adminPK
|
chat.InvitationAdmin = adminPK
|
||||||
|
|
||||||
response.Chats = []*Chat{&chat}
|
response.AddChat(&chat)
|
||||||
|
|
||||||
return &response, m.saveChat(&chat)
|
return &response, m.saveChat(&chat)
|
||||||
}
|
}
|
||||||
|
@ -1369,7 +1330,7 @@ func (m *Messenger) RemoveMemberFromGroupChat(ctx context.Context, chatID string
|
||||||
|
|
||||||
chat.updateChatFromGroupMembershipChanges(contactIDFromPublicKey(&m.identity.PublicKey), group)
|
chat.updateChatFromGroupMembershipChanges(contactIDFromPublicKey(&m.identity.PublicKey), group)
|
||||||
|
|
||||||
response.Chats = []*Chat{chat}
|
response.AddChat(chat)
|
||||||
response.Messages = buildSystemMessages(chat.MembershipUpdates, m.systemMessagesTranslations)
|
response.Messages = buildSystemMessages(chat.MembershipUpdates, m.systemMessagesTranslations)
|
||||||
err = m.persistence.SaveMessages(response.Messages)
|
err = m.persistence.SaveMessages(response.Messages)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1458,7 +1419,7 @@ func (m *Messenger) AddMembersToGroupChat(ctx context.Context, chatID string, me
|
||||||
|
|
||||||
chat.updateChatFromGroupMembershipChanges(contactIDFromPublicKey(&m.identity.PublicKey), group)
|
chat.updateChatFromGroupMembershipChanges(contactIDFromPublicKey(&m.identity.PublicKey), group)
|
||||||
|
|
||||||
response.Chats = []*Chat{chat}
|
response.AddChat(chat)
|
||||||
response.Messages = buildSystemMessages([]v1protocol.MembershipUpdateEvent{event}, m.systemMessagesTranslations)
|
response.Messages = buildSystemMessages([]v1protocol.MembershipUpdateEvent{event}, m.systemMessagesTranslations)
|
||||||
err = m.persistence.SaveMessages(response.Messages)
|
err = m.persistence.SaveMessages(response.Messages)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1523,7 +1484,7 @@ func (m *Messenger) ChangeGroupChatName(ctx context.Context, chatID string, name
|
||||||
chat.updateChatFromGroupMembershipChanges(contactIDFromPublicKey(&m.identity.PublicKey), group)
|
chat.updateChatFromGroupMembershipChanges(contactIDFromPublicKey(&m.identity.PublicKey), group)
|
||||||
|
|
||||||
var response MessengerResponse
|
var response MessengerResponse
|
||||||
response.Chats = []*Chat{chat}
|
response.AddChat(chat)
|
||||||
response.Messages = buildSystemMessages([]v1protocol.MembershipUpdateEvent{event}, m.systemMessagesTranslations)
|
response.Messages = buildSystemMessages([]v1protocol.MembershipUpdateEvent{event}, m.systemMessagesTranslations)
|
||||||
err = m.persistence.SaveMessages(response.Messages)
|
err = m.persistence.SaveMessages(response.Messages)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1732,7 +1693,7 @@ func (m *Messenger) AddAdminsToGroupChat(ctx context.Context, chatID string, mem
|
||||||
|
|
||||||
chat.updateChatFromGroupMembershipChanges(contactIDFromPublicKey(&m.identity.PublicKey), group)
|
chat.updateChatFromGroupMembershipChanges(contactIDFromPublicKey(&m.identity.PublicKey), group)
|
||||||
|
|
||||||
response.Chats = []*Chat{chat}
|
response.AddChat(chat)
|
||||||
response.Messages = buildSystemMessages([]v1protocol.MembershipUpdateEvent{event}, m.systemMessagesTranslations)
|
response.Messages = buildSystemMessages([]v1protocol.MembershipUpdateEvent{event}, m.systemMessagesTranslations)
|
||||||
err = m.persistence.SaveMessages(response.Messages)
|
err = m.persistence.SaveMessages(response.Messages)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1753,7 +1714,7 @@ func (m *Messenger) ConfirmJoiningGroup(ctx context.Context, chatID string) (*Me
|
||||||
return nil, ErrChatNotFound
|
return nil, ErrChatNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
err := m.Join(*chat)
|
_, err := m.Join(chat)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -1798,7 +1759,7 @@ func (m *Messenger) ConfirmJoiningGroup(ctx context.Context, chatID string) (*Me
|
||||||
|
|
||||||
chat.updateChatFromGroupMembershipChanges(contactIDFromPublicKey(&m.identity.PublicKey), group)
|
chat.updateChatFromGroupMembershipChanges(contactIDFromPublicKey(&m.identity.PublicKey), group)
|
||||||
|
|
||||||
response.Chats = []*Chat{chat}
|
response.AddChat(chat)
|
||||||
response.Messages = buildSystemMessages([]v1protocol.MembershipUpdateEvent{event}, m.systemMessagesTranslations)
|
response.Messages = buildSystemMessages([]v1protocol.MembershipUpdateEvent{event}, m.systemMessagesTranslations)
|
||||||
err = m.persistence.SaveMessages(response.Messages)
|
err = m.persistence.SaveMessages(response.Messages)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1869,7 +1830,7 @@ func (m *Messenger) LeaveGroupChat(ctx context.Context, chatID string, remove bo
|
||||||
chat.Active = false
|
chat.Active = false
|
||||||
}
|
}
|
||||||
|
|
||||||
response.Chats = []*Chat{chat}
|
response.AddChat(chat)
|
||||||
response.Messages = buildSystemMessages([]v1protocol.MembershipUpdateEvent{event}, m.systemMessagesTranslations)
|
response.Messages = buildSystemMessages([]v1protocol.MembershipUpdateEvent{event}, m.systemMessagesTranslations)
|
||||||
err = m.persistence.SaveMessages(response.Messages)
|
err = m.persistence.SaveMessages(response.Messages)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1879,307 +1840,6 @@ func (m *Messenger) LeaveGroupChat(ctx context.Context, chatID string, remove bo
|
||||||
return &response, m.saveChat(chat)
|
return &response, m.saveChat(chat)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Messenger) saveChat(chat *Chat) error {
|
|
||||||
previousChat, ok := m.allChats[chat.ID]
|
|
||||||
if chat.OneToOne() {
|
|
||||||
name, identicon, err := generateAliasAndIdenticon(chat.ID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
chat.Alias = name
|
|
||||||
chat.Identicon = identicon
|
|
||||||
}
|
|
||||||
// Sync chat if it's a new active public chat
|
|
||||||
if !ok && chat.Active && chat.Public() {
|
|
||||||
|
|
||||||
if err := m.syncPublicChat(context.Background(), chat); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We check if it's a new chat, or chat.Active has changed
|
|
||||||
// we check here, but we only re-register once the chat has been
|
|
||||||
// saved an added
|
|
||||||
shouldRegisterForPushNotifications := chat.Public() && (!ok && chat.Active) || (ok && chat.Active != previousChat.Active)
|
|
||||||
|
|
||||||
err := m.persistence.SaveChat(*chat)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
m.allChats[chat.ID] = chat
|
|
||||||
|
|
||||||
if shouldRegisterForPushNotifications {
|
|
||||||
// Re-register for push notifications, as we want to receive mentions
|
|
||||||
if err := m.reregisterForPushNotifications(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Messenger) saveChats(chats []*Chat) error {
|
|
||||||
err := m.persistence.SaveChats(chats)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, chat := range chats {
|
|
||||||
m.allChats[chat.ID] = chat
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Messenger) SaveChat(chat *Chat) error {
|
|
||||||
m.mutex.Lock()
|
|
||||||
defer m.mutex.Unlock()
|
|
||||||
return m.saveChat(chat)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Messenger) Chats() []*Chat {
|
|
||||||
m.mutex.Lock()
|
|
||||||
defer m.mutex.Unlock()
|
|
||||||
|
|
||||||
var chats []*Chat
|
|
||||||
|
|
||||||
for _, c := range m.allChats {
|
|
||||||
chats = append(chats, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
return chats
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Messenger) Communities() ([]*communities.Community, error) {
|
|
||||||
return m.communitiesManager.All()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Messenger) JoinedCommunities() ([]*communities.Community, error) {
|
|
||||||
return m.communitiesManager.Joined()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Messenger) JoinCommunity(communityID string) (*MessengerResponse, error) {
|
|
||||||
m.mutex.Lock()
|
|
||||||
defer m.mutex.Unlock()
|
|
||||||
|
|
||||||
response := &MessengerResponse{}
|
|
||||||
|
|
||||||
org, err := m.communitiesManager.JoinCommunity(communityID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
chatIDs := []string{org.IDString()}
|
|
||||||
|
|
||||||
chats := CreateCommunityChats(org, m.getTimesource())
|
|
||||||
|
|
||||||
// Beware don't use `chat` as a reference
|
|
||||||
for i, chat := range chats {
|
|
||||||
chatIDs = append(chatIDs, chat.ID)
|
|
||||||
response.Chats = append(response.Chats, &chats[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load transport filters
|
|
||||||
filters, err := m.transport.InitPublicFilters(chatIDs)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
response.Filters = filters
|
|
||||||
response.Communities = []*communities.Community{org}
|
|
||||||
|
|
||||||
return response, m.saveChats(response.Chats)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Messenger) LeaveCommunity(communityID string) (*MessengerResponse, error) {
|
|
||||||
response := &MessengerResponse{}
|
|
||||||
|
|
||||||
org, err := m.communitiesManager.LeaveCommunity(communityID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make chat inactive
|
|
||||||
for chatID := range org.Chats() {
|
|
||||||
orgChatID := communityID + chatID
|
|
||||||
err := m.DeleteChat(orgChatID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
response.RemovedChats = append(response.RemovedChats, orgChatID)
|
|
||||||
|
|
||||||
filter, err := m.transport.RemoveFilterByChatID(orgChatID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if filter != nil {
|
|
||||||
response.RemovedFilters = append(response.RemovedFilters, filter)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
filter, err := m.transport.RemoveFilterByChatID(communityID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if filter != nil {
|
|
||||||
response.RemovedFilters = append(response.RemovedFilters, filter)
|
|
||||||
}
|
|
||||||
|
|
||||||
response.Communities = []*communities.Community{org}
|
|
||||||
return response, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Messenger) CreateCommunityChat(orgID string, c *protobuf.CommunityChat) (*MessengerResponse, error) {
|
|
||||||
org, changes, err := m.communitiesManager.CreateChat(orgID, c)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var chats []*Chat
|
|
||||||
var chatIDs []string
|
|
||||||
for chatID, chat := range changes.ChatsAdded {
|
|
||||||
c := CreateCommunityChat(org.IDString(), chatID, chat, m.getTimesource())
|
|
||||||
chats = append(chats, &c)
|
|
||||||
chatIDs = append(chatIDs, c.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load filters
|
|
||||||
filters, err := m.transport.InitPublicFilters(chatIDs)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &MessengerResponse{
|
|
||||||
Communities: []*communities.Community{org},
|
|
||||||
Chats: chats,
|
|
||||||
Filters: filters,
|
|
||||||
CommunityChanges: []*communities.CommunityChanges{changes},
|
|
||||||
}, m.saveChats(chats)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Messenger) CreateCommunity(description *protobuf.CommunityDescription) (*MessengerResponse, error) {
|
|
||||||
org, err := m.communitiesManager.CreateCommunity(description)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &MessengerResponse{
|
|
||||||
Communities: []*communities.Community{org},
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Messenger) ExportCommunity(id string) (*ecdsa.PrivateKey, error) {
|
|
||||||
return m.communitiesManager.ExportCommunity(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Messenger) ImportCommunity(key *ecdsa.PrivateKey) (*MessengerResponse, error) {
|
|
||||||
org, err := m.communitiesManager.ImportCommunity(key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load filters
|
|
||||||
filters, err := m.transport.InitPublicFilters([]string{org.IDString()})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &MessengerResponse{
|
|
||||||
Filters: filters,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Messenger) InviteUserToCommunity(orgID, pkString string) (*MessengerResponse, error) {
|
|
||||||
publicKey, err := common.HexToPubkey(pkString)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
org, err := m.communitiesManager.InviteUserToCommunity(orgID, publicKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &MessengerResponse{
|
|
||||||
Communities: []*communities.Community{org},
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Messenger) RemoveUserFromCommunity(orgID, pkString string) (*MessengerResponse, error) {
|
|
||||||
publicKey, err := common.HexToPubkey(pkString)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
org, err := m.communitiesManager.RemoveUserFromCommunity(orgID, publicKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &MessengerResponse{
|
|
||||||
Communities: []*communities.Community{org},
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Messenger) DeleteChat(chatID string) error {
|
|
||||||
m.mutex.Lock()
|
|
||||||
defer m.mutex.Unlock()
|
|
||||||
|
|
||||||
err := m.persistence.DeleteChat(chatID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
chat, ok := m.allChats[chatID]
|
|
||||||
|
|
||||||
if ok && chat.Active && chat.Public() {
|
|
||||||
delete(m.allChats, chatID)
|
|
||||||
return m.reregisterForPushNotifications()
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Messenger) DeactivateChat(chatID string) (*MessengerResponse, error) {
|
|
||||||
m.mutex.Lock()
|
|
||||||
defer m.mutex.Unlock()
|
|
||||||
return m.deactivateChat(chatID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Messenger) deactivateChat(chatID string) (*MessengerResponse, error) {
|
|
||||||
var response MessengerResponse
|
|
||||||
chat, ok := m.allChats[chatID]
|
|
||||||
if !ok {
|
|
||||||
return nil, ErrChatNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
clock, _ := chat.NextClockAndTimestamp(m.getTimesource())
|
|
||||||
|
|
||||||
err := m.persistence.DeactivateChat(chat, clock)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// We re-register as our options have changed and we don't want to
|
|
||||||
// receive PN from mentions in this chat anymore
|
|
||||||
if chat.Public() {
|
|
||||||
err := m.reregisterForPushNotifications()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m.allChats[chatID] = chat
|
|
||||||
|
|
||||||
response.Chats = []*Chat{chat}
|
|
||||||
// TODO: Remove filters
|
|
||||||
|
|
||||||
return &response, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Messenger) reregisterForPushNotifications() error {
|
func (m *Messenger) reregisterForPushNotifications() error {
|
||||||
m.logger.Info("contact state changed, re-registering for push notification")
|
m.logger.Info("contact state changed, re-registering for push notification")
|
||||||
if m.pushNotificationClient == nil {
|
if m.pushNotificationClient == nil {
|
||||||
|
@ -2533,7 +2193,7 @@ func (m *Messenger) sendChatMessage(ctx context.Context, message *common.Message
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
response.Chats = []*Chat{chat}
|
response.AddChat(chat)
|
||||||
return &response, m.saveChat(chat)
|
return &response, m.saveChat(chat)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2617,7 +2277,7 @@ func (m *Messenger) SendPairInstallation(ctx context.Context) (*MessengerRespons
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
response.Chats = []*Chat{chat}
|
response.AddChat(chat)
|
||||||
|
|
||||||
chat.LastClockValue = clock
|
chat.LastClockValue = clock
|
||||||
err = m.saveChat(chat)
|
err = m.saveChat(chat)
|
||||||
|
@ -2740,8 +2400,7 @@ type ReceivedMessageState struct {
|
||||||
CurrentMessageState *CurrentMessageState
|
CurrentMessageState *CurrentMessageState
|
||||||
// AllChats in memory
|
// AllChats in memory
|
||||||
AllChats map[string]*Chat
|
AllChats map[string]*Chat
|
||||||
// List of chats modified
|
|
||||||
ModifiedChats map[string]bool
|
|
||||||
// All contacts in memory
|
// All contacts in memory
|
||||||
AllContacts map[string]*Contact
|
AllContacts map[string]*Contact
|
||||||
// List of contacts modified
|
// List of contacts modified
|
||||||
|
@ -2750,8 +2409,6 @@ type ReceivedMessageState struct {
|
||||||
AllInstallations map[string]*multidevice.Installation
|
AllInstallations map[string]*multidevice.Installation
|
||||||
// List of communities modified
|
// List of communities modified
|
||||||
ModifiedInstallations map[string]bool
|
ModifiedInstallations map[string]bool
|
||||||
// List of communities
|
|
||||||
AllCommunities map[string]*communities.Community
|
|
||||||
// List of filters
|
// List of filters
|
||||||
AllFilters map[string]*transport.Filter
|
AllFilters map[string]*transport.Filter
|
||||||
// Map of existing messages
|
// Map of existing messages
|
||||||
|
@ -2829,14 +2486,12 @@ func (m *Messenger) handleRetrievedMessages(chatWithMessages map[transport.Filte
|
||||||
defer m.mutex.Unlock()
|
defer m.mutex.Unlock()
|
||||||
messageState := &ReceivedMessageState{
|
messageState := &ReceivedMessageState{
|
||||||
AllChats: m.allChats,
|
AllChats: m.allChats,
|
||||||
ModifiedChats: make(map[string]bool),
|
|
||||||
AllContacts: m.allContacts,
|
AllContacts: m.allContacts,
|
||||||
ModifiedContacts: make(map[string]bool),
|
ModifiedContacts: make(map[string]bool),
|
||||||
AllInstallations: m.allInstallations,
|
AllInstallations: m.allInstallations,
|
||||||
ModifiedInstallations: m.modifiedInstallations,
|
ModifiedInstallations: m.modifiedInstallations,
|
||||||
ExistingMessagesMap: make(map[string]bool),
|
ExistingMessagesMap: make(map[string]bool),
|
||||||
EmojiReactions: make(map[string]*EmojiReaction),
|
EmojiReactions: make(map[string]*EmojiReaction),
|
||||||
AllCommunities: make(map[string]*communities.Community),
|
|
||||||
AllFilters: make(map[string]*transport.Filter),
|
AllFilters: make(map[string]*transport.Filter),
|
||||||
GroupChatInvitations: make(map[string]*GroupChatInvitation),
|
GroupChatInvitations: make(map[string]*GroupChatInvitation),
|
||||||
Response: &MessengerResponse{},
|
Response: &MessengerResponse{},
|
||||||
|
@ -3180,10 +2835,19 @@ func (m *Messenger) handleRetrievedMessages(chatWithMessages map[transport.Filte
|
||||||
invitation := msg.ParsedMessage.Interface().(protobuf.CommunityInvitation)
|
invitation := msg.ParsedMessage.Interface().(protobuf.CommunityInvitation)
|
||||||
err = m.handler.HandleCommunityInvitation(messageState, publicKey, invitation, invitation.CommunityDescription)
|
err = m.handler.HandleCommunityInvitation(messageState, publicKey, invitation, invitation.CommunityDescription)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Warn("failed to handle CommunityDescription", zap.Error(err))
|
logger.Warn("failed to handle CommunityInvitation", zap.Error(err))
|
||||||
allMessagesProcessed = false
|
allMessagesProcessed = false
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
case protobuf.CommunityRequestToJoin:
|
||||||
|
logger.Debug("Handling CommunityRequestToJoin")
|
||||||
|
request := msg.ParsedMessage.Interface().(protobuf.CommunityRequestToJoin)
|
||||||
|
err = m.handler.HandleCommunityRequestToJoin(messageState, publicKey, request)
|
||||||
|
if err != nil {
|
||||||
|
logger.Warn("failed to handle CommunityRequestToJoin", zap.Error(err))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// Check if is an encrypted PushNotificationRegistration
|
// Check if is an encrypted PushNotificationRegistration
|
||||||
if msg.Type == protobuf.ApplicationMetadataMessage_PUSH_NOTIFICATION_REGISTRATION {
|
if msg.Type == protobuf.ApplicationMetadataMessage_PUSH_NOTIFICATION_REGISTRATION {
|
||||||
|
@ -3208,6 +2872,39 @@ func (m *Messenger) handleRetrievedMessages(chatWithMessages map[transport.Filte
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process any community changes
|
||||||
|
for _, changes := range messageState.Response.CommunityChanges {
|
||||||
|
if changes.ShouldMemberJoin {
|
||||||
|
response, err := m.joinCommunity(changes.Community.ID())
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("cannot join community", zap.Error(err))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := messageState.Response.Merge(response); err != nil {
|
||||||
|
logger.Error("cannot merge join community response", zap.Error(err))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if changes.ShouldMemberLeave {
|
||||||
|
response, err := m.leaveCommunity(changes.Community.ID())
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("cannot join community", zap.Error(err))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := messageState.Response.Merge(response); err != nil {
|
||||||
|
logger.Error("cannot merge join community response", zap.Error(err))
|
||||||
|
continue
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up as not used by clients currently
|
||||||
|
messageState.Response.CommunityChanges = nil
|
||||||
|
|
||||||
if allMessagesProcessed {
|
if allMessagesProcessed {
|
||||||
processedMessages = append(processedMessages, types.EncodeHex(shhMessage.Hash))
|
processedMessages = append(processedMessages, types.EncodeHex(shhMessage.Hash))
|
||||||
}
|
}
|
||||||
|
@ -3234,15 +2931,12 @@ func (m *Messenger) handleRetrievedMessages(chatWithMessages map[transport.Filte
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, community := range messageState.AllCommunities {
|
|
||||||
messageState.Response.Communities = append(messageState.Response.Communities, community)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, filter := range messageState.AllFilters {
|
for _, filter := range messageState.AllFilters {
|
||||||
messageState.Response.Filters = append(messageState.Response.Filters, filter)
|
messageState.Response.Filters = append(messageState.Response.Filters, filter)
|
||||||
}
|
}
|
||||||
|
|
||||||
for id := range messageState.ModifiedChats {
|
// Hydrate chat alias and identicon
|
||||||
|
for id := range messageState.Response.chats {
|
||||||
chat := messageState.AllChats[id]
|
chat := messageState.AllChats[id]
|
||||||
if chat.OneToOne() {
|
if chat.OneToOne() {
|
||||||
contact, ok := m.allContacts[chat.ID]
|
contact, ok := m.allContacts[chat.ID]
|
||||||
|
@ -3252,7 +2946,7 @@ func (m *Messenger) handleRetrievedMessages(chatWithMessages map[transport.Filte
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
messageState.Response.Chats = append(messageState.Response.Chats, chat)
|
messageState.Response.AddChat(chat)
|
||||||
}
|
}
|
||||||
|
|
||||||
for id := range messageState.ModifiedInstallations {
|
for id := range messageState.ModifiedInstallations {
|
||||||
|
@ -3267,12 +2961,13 @@ func (m *Messenger) handleRetrievedMessages(chatWithMessages map[transport.Filte
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
if len(messageState.Response.Chats) > 0 {
|
if len(messageState.Response.chats) > 0 {
|
||||||
err = m.saveChats(messageState.Response.Chats)
|
err = m.saveChats(messageState.Response.Chats())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(messageState.Response.Messages) > 0 {
|
if len(messageState.Response.Messages) > 0 {
|
||||||
err = m.SaveMessages(messageState.Response.Messages)
|
err = m.SaveMessages(messageState.Response.Messages)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -3448,7 +3143,8 @@ func (m *Messenger) clearHistory(id string) (*MessengerResponse, error) {
|
||||||
|
|
||||||
m.allChats[id] = chat
|
m.allChats[id] = chat
|
||||||
|
|
||||||
response := &MessengerResponse{Chats: []*Chat{chat}}
|
response := &MessengerResponse{}
|
||||||
|
response.AddChat(chat)
|
||||||
return response, nil
|
return response, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3539,72 +3235,6 @@ func Identicon(id string) (string, error) {
|
||||||
return identicon.GenerateBase64(id)
|
return identicon.GenerateBase64(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// VerifyENSNames verifies that a registered ENS name matches the expected public key
|
|
||||||
func (m *Messenger) VerifyENSNames(ctx context.Context, rpcEndpoint, contractAddress string) (*MessengerResponse, error) {
|
|
||||||
m.mutex.Lock()
|
|
||||||
defer m.mutex.Unlock()
|
|
||||||
|
|
||||||
m.logger.Debug("verifying ENS Names", zap.String("endpoint", rpcEndpoint))
|
|
||||||
verifier := m.node.NewENSVerifier(m.logger)
|
|
||||||
|
|
||||||
var response MessengerResponse
|
|
||||||
|
|
||||||
var ensDetails []enstypes.ENSDetails
|
|
||||||
|
|
||||||
// Now in seconds
|
|
||||||
now := m.getTimesource().GetCurrentTime() / 1000
|
|
||||||
for _, contact := range m.allContacts {
|
|
||||||
if shouldENSBeVerified(contact, now) {
|
|
||||||
ensDetails = append(ensDetails, enstypes.ENSDetails{
|
|
||||||
PublicKeyString: contact.ID[2:],
|
|
||||||
Name: contact.Name,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ensResponse, err := verifier.CheckBatch(ensDetails, rpcEndpoint, contractAddress)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, details := range ensResponse {
|
|
||||||
contact, ok := m.allContacts["0x"+details.PublicKeyString]
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("contact must be existing")
|
|
||||||
}
|
|
||||||
|
|
||||||
m.logger.Debug("verifying ENS Name", zap.Any("details", details), zap.Any("contact", contact))
|
|
||||||
|
|
||||||
contact.ENSVerifiedAt = uint64(details.VerifiedAt)
|
|
||||||
|
|
||||||
if details.Error == nil {
|
|
||||||
contact.ENSVerified = details.Verified
|
|
||||||
// Increment count if not verified, even if no error
|
|
||||||
if !details.Verified {
|
|
||||||
contact.ENSVerificationRetries++
|
|
||||||
}
|
|
||||||
m.allContacts[contact.ID] = contact
|
|
||||||
} else {
|
|
||||||
m.logger.Warn("Failed to resolve ens name",
|
|
||||||
zap.String("name", details.Name),
|
|
||||||
zap.String("publicKey", details.PublicKeyString),
|
|
||||||
zap.Error(details.Error),
|
|
||||||
)
|
|
||||||
contact.ENSVerificationRetries++
|
|
||||||
}
|
|
||||||
response.Contacts = append(response.Contacts, contact)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(response.Contacts) != 0 {
|
|
||||||
err = m.persistence.SaveContacts(response.Contacts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &response, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenerateAlias name returns the generated name given a public key hex encoded prefixed with 0x
|
// GenerateAlias name returns the generated name given a public key hex encoded prefixed with 0x
|
||||||
func GenerateAlias(id string) (string, error) {
|
func GenerateAlias(id string) (string, error) {
|
||||||
return alias.GenerateFromPublicKeyString(id)
|
return alias.GenerateFromPublicKeyString(id)
|
||||||
|
@ -3683,7 +3313,7 @@ func (m *Messenger) RequestTransaction(ctx context.Context, chatID, value, contr
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
response.Chats = []*Chat{chat}
|
response.AddChat(chat)
|
||||||
response.Messages = []*common.Message{message}
|
response.Messages = []*common.Message{message}
|
||||||
return &response, m.saveChat(chat)
|
return &response, m.saveChat(chat)
|
||||||
}
|
}
|
||||||
|
@ -3760,7 +3390,7 @@ func (m *Messenger) RequestAddressForTransaction(ctx context.Context, chatID, fr
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
response.Chats = []*Chat{chat}
|
response.AddChat(chat)
|
||||||
response.Messages = []*common.Message{message}
|
response.Messages = []*common.Message{message}
|
||||||
return &response, m.saveChat(chat)
|
return &response, m.saveChat(chat)
|
||||||
}
|
}
|
||||||
|
@ -3856,7 +3486,7 @@ func (m *Messenger) AcceptRequestAddressForTransaction(ctx context.Context, mess
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
response.Chats = []*Chat{chat}
|
response.AddChat(chat)
|
||||||
response.Messages = []*common.Message{message}
|
response.Messages = []*common.Message{message}
|
||||||
return &response, m.saveChat(chat)
|
return &response, m.saveChat(chat)
|
||||||
}
|
}
|
||||||
|
@ -3939,7 +3569,7 @@ func (m *Messenger) DeclineRequestTransaction(ctx context.Context, messageID str
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
response.Chats = []*Chat{chat}
|
response.AddChat(chat)
|
||||||
response.Messages = []*common.Message{message}
|
response.Messages = []*common.Message{message}
|
||||||
return &response, m.saveChat(chat)
|
return &response, m.saveChat(chat)
|
||||||
}
|
}
|
||||||
|
@ -4022,7 +3652,7 @@ func (m *Messenger) DeclineRequestAddressForTransaction(ctx context.Context, mes
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
response.Chats = []*Chat{chat}
|
response.AddChat(chat)
|
||||||
response.Messages = []*common.Message{message}
|
response.Messages = []*common.Message{message}
|
||||||
return &response, m.saveChat(chat)
|
return &response, m.saveChat(chat)
|
||||||
}
|
}
|
||||||
|
@ -4122,7 +3752,7 @@ func (m *Messenger) AcceptRequestTransaction(ctx context.Context, transactionHas
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
response.Chats = []*Chat{chat}
|
response.AddChat(chat)
|
||||||
response.Messages = []*common.Message{message}
|
response.Messages = []*common.Message{message}
|
||||||
return &response, m.saveChat(chat)
|
return &response, m.saveChat(chat)
|
||||||
}
|
}
|
||||||
|
@ -4204,7 +3834,7 @@ func (m *Messenger) SendTransaction(ctx context.Context, chatID, value, contract
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
response.Chats = []*Chat{chat}
|
response.AddChat(chat)
|
||||||
response.Messages = []*common.Message{message}
|
response.Messages = []*common.Message{message}
|
||||||
return &response, m.saveChat(chat)
|
return &response, m.saveChat(chat)
|
||||||
}
|
}
|
||||||
|
@ -4216,8 +3846,6 @@ func (m *Messenger) ValidateTransactions(ctx context.Context, addresses []types.
|
||||||
m.mutex.Lock()
|
m.mutex.Lock()
|
||||||
defer m.mutex.Unlock()
|
defer m.mutex.Unlock()
|
||||||
|
|
||||||
modifiedChats := make(map[string]bool)
|
|
||||||
|
|
||||||
logger := m.logger.With(zap.String("site", "ValidateTransactions"))
|
logger := m.logger.With(zap.String("site", "ValidateTransactions"))
|
||||||
logger.Debug("Validating transactions")
|
logger.Debug("Validating transactions")
|
||||||
txs, err := m.persistence.TransactionsToValidate()
|
txs, err := m.persistence.TransactionsToValidate()
|
||||||
|
@ -4303,7 +3931,7 @@ func (m *Messenger) ValidateTransactions(ctx context.Context, addresses []types.
|
||||||
|
|
||||||
response.Messages = append(response.Messages, message)
|
response.Messages = append(response.Messages, message)
|
||||||
m.allChats[chat.ID] = chat
|
m.allChats[chat.ID] = chat
|
||||||
modifiedChats[chat.ID] = true
|
response.AddChat(chat)
|
||||||
|
|
||||||
contact, err := m.getOrBuildContactFromMessage(message)
|
contact, err := m.getOrBuildContactFromMessage(message)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -4316,9 +3944,6 @@ func (m *Messenger) ValidateTransactions(ctx context.Context, addresses []types.
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
for id := range modifiedChats {
|
|
||||||
response.Chats = append(response.Chats, m.allChats[id])
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(response.Messages) > 0 {
|
if len(response.Messages) > 0 {
|
||||||
err = m.SaveMessages(response.Messages)
|
err = m.SaveMessages(response.Messages)
|
||||||
|
@ -4578,7 +4203,7 @@ func (m *Messenger) SendEmojiReaction(ctx context.Context, chatID, messageID str
|
||||||
}
|
}
|
||||||
|
|
||||||
response.EmojiReactions = []*EmojiReaction{emojiR}
|
response.EmojiReactions = []*EmojiReaction{emojiR}
|
||||||
response.Chats = []*Chat{chat}
|
response.AddChat(chat)
|
||||||
|
|
||||||
err = m.persistence.SaveEmojiReaction(emojiR)
|
err = m.persistence.SaveEmojiReaction(emojiR)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -4659,7 +4284,7 @@ func (m *Messenger) SendEmojiReactionRetraction(ctx context.Context, emojiReacti
|
||||||
response := MessengerResponse{}
|
response := MessengerResponse{}
|
||||||
emojiR.Retracted = true
|
emojiR.Retracted = true
|
||||||
response.EmojiReactions = []*EmojiReaction{emojiR}
|
response.EmojiReactions = []*EmojiReaction{emojiR}
|
||||||
response.Chats = []*Chat{chat}
|
response.AddChat(chat)
|
||||||
|
|
||||||
// Persist retraction state for emoji reaction
|
// Persist retraction state for emoji reaction
|
||||||
err = m.persistence.SaveEmojiReaction(emojiR)
|
err = m.persistence.SaveEmojiReaction(emojiR)
|
||||||
|
|
|
@ -0,0 +1,216 @@
|
||||||
|
package protocol
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/status-im/status-go/protocol/common"
|
||||||
|
"github.com/status-im/status-go/protocol/requests"
|
||||||
|
"github.com/status-im/status-go/protocol/transport"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (m *Messenger) Chats() []*Chat {
|
||||||
|
m.mutex.Lock()
|
||||||
|
defer m.mutex.Unlock()
|
||||||
|
|
||||||
|
var chats []*Chat
|
||||||
|
|
||||||
|
for _, c := range m.allChats {
|
||||||
|
chats = append(chats, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
return chats
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Messenger) CreateOneToOneChat(request *requests.CreateOneToOneChat) (*MessengerResponse, error) {
|
||||||
|
m.mutex.Lock()
|
||||||
|
defer m.mutex.Unlock()
|
||||||
|
|
||||||
|
if err := request.Validate(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
chatID := request.ID.String()
|
||||||
|
pk, err := common.HexToPubkey(chatID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
chat, ok := m.allChats[chatID]
|
||||||
|
if !ok {
|
||||||
|
chat = CreateOneToOneChat(chatID, pk, m.getTimesource())
|
||||||
|
}
|
||||||
|
chat.Active = true
|
||||||
|
|
||||||
|
filters, err := m.Join(chat)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = m.saveChat(chat)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
m.allChats[chatID] = chat
|
||||||
|
|
||||||
|
response := &MessengerResponse{
|
||||||
|
Filters: filters,
|
||||||
|
}
|
||||||
|
response.AddChat(chat)
|
||||||
|
|
||||||
|
return response, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Messenger) DeleteChat(chatID string) error {
|
||||||
|
m.mutex.Lock()
|
||||||
|
defer m.mutex.Unlock()
|
||||||
|
|
||||||
|
return m.deleteChat(chatID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Messenger) deleteChat(chatID string) error {
|
||||||
|
err := m.persistence.DeleteChat(chatID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
chat, ok := m.allChats[chatID]
|
||||||
|
|
||||||
|
if ok && chat.Active && chat.Public() {
|
||||||
|
delete(m.allChats, chatID)
|
||||||
|
return m.reregisterForPushNotifications()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Messenger) SaveChat(chat *Chat) error {
|
||||||
|
m.mutex.Lock()
|
||||||
|
defer m.mutex.Unlock()
|
||||||
|
return m.saveChat(chat)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Messenger) DeactivateChat(chatID string) (*MessengerResponse, error) {
|
||||||
|
m.mutex.Lock()
|
||||||
|
defer m.mutex.Unlock()
|
||||||
|
return m.deactivateChat(chatID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Messenger) deactivateChat(chatID string) (*MessengerResponse, error) {
|
||||||
|
var response MessengerResponse
|
||||||
|
chat, ok := m.allChats[chatID]
|
||||||
|
if !ok {
|
||||||
|
return nil, ErrChatNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
clock, _ := chat.NextClockAndTimestamp(m.getTimesource())
|
||||||
|
|
||||||
|
err := m.persistence.DeactivateChat(chat, clock)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// We re-register as our options have changed and we don't want to
|
||||||
|
// receive PN from mentions in this chat anymore
|
||||||
|
if chat.Public() {
|
||||||
|
err := m.reregisterForPushNotifications()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m.allChats[chatID] = chat
|
||||||
|
|
||||||
|
response.AddChat(chat)
|
||||||
|
// TODO: Remove filters
|
||||||
|
|
||||||
|
return &response, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Messenger) saveChats(chats []*Chat) error {
|
||||||
|
err := m.persistence.SaveChats(chats)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, chat := range chats {
|
||||||
|
m.allChats[chat.ID] = chat
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Messenger) saveChat(chat *Chat) error {
|
||||||
|
previousChat, ok := m.allChats[chat.ID]
|
||||||
|
if chat.OneToOne() {
|
||||||
|
name, identicon, err := generateAliasAndIdenticon(chat.ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
chat.Alias = name
|
||||||
|
chat.Identicon = identicon
|
||||||
|
}
|
||||||
|
// Sync chat if it's a new active public chat, but not a timeline chat
|
||||||
|
if !ok && chat.Active && chat.Public() && !strings.HasPrefix(chat.ID, "@") {
|
||||||
|
|
||||||
|
if err := m.syncPublicChat(context.Background(), chat); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We check if it's a new chat, or chat.Active has changed
|
||||||
|
// we check here, but we only re-register once the chat has been
|
||||||
|
// saved an added
|
||||||
|
shouldRegisterForPushNotifications := chat.Public() && (!ok && chat.Active) || (ok && chat.Active != previousChat.Active)
|
||||||
|
|
||||||
|
err := m.persistence.SaveChat(*chat)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
m.allChats[chat.ID] = chat
|
||||||
|
|
||||||
|
if shouldRegisterForPushNotifications {
|
||||||
|
// Re-register for push notifications, as we want to receive mentions
|
||||||
|
if err := m.reregisterForPushNotifications(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Messenger) Join(chat *Chat) ([]*transport.Filter, error) {
|
||||||
|
switch chat.ChatType {
|
||||||
|
case ChatTypeOneToOne:
|
||||||
|
pk, err := chat.PublicKey()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := m.transport.JoinPrivate(pk)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return []*transport.Filter{f}, nil
|
||||||
|
case ChatTypePrivateGroupChat:
|
||||||
|
members, err := chat.MembersAsPublicKeys()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return m.transport.JoinGroup(members)
|
||||||
|
case ChatTypePublic, ChatTypeProfile, ChatTypeTimeline:
|
||||||
|
f, err := m.transport.JoinPublic(chat.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return []*transport.Filter{f}, nil
|
||||||
|
default:
|
||||||
|
return nil, errors.New("chat is neither public nor private")
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,465 @@
|
||||||
|
package protocol
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
|
||||||
|
"github.com/status-im/status-go/eth-node/crypto"
|
||||||
|
"github.com/status-im/status-go/eth-node/types"
|
||||||
|
"github.com/status-im/status-go/protocol/common"
|
||||||
|
"github.com/status-im/status-go/protocol/communities"
|
||||||
|
"github.com/status-im/status-go/protocol/protobuf"
|
||||||
|
"github.com/status-im/status-go/protocol/requests"
|
||||||
|
)
|
||||||
|
|
||||||
|
const communityInvitationText = "Upgrade to see a community invitation"
|
||||||
|
|
||||||
|
func (m *Messenger) publishOrg(org *communities.Community) error {
|
||||||
|
m.logger.Debug("publishing org", zap.String("org-id", org.IDString()), zap.Any("org", org))
|
||||||
|
payload, err := org.MarshaledDescription()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
rawMessage := common.RawMessage{
|
||||||
|
Payload: payload,
|
||||||
|
Sender: org.PrivateKey(),
|
||||||
|
// we don't want to wrap in an encryption layer message
|
||||||
|
SkipEncryption: true,
|
||||||
|
MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_DESCRIPTION,
|
||||||
|
}
|
||||||
|
_, err = m.processor.SendPublic(context.Background(), org.IDString(), rawMessage)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Messenger) publishOrgInvitation(org *communities.Community, invitation *protobuf.CommunityInvitation) error {
|
||||||
|
m.logger.Debug("publishing org invitation", zap.String("org-id", org.IDString()), zap.Any("org", org))
|
||||||
|
pk, err := crypto.DecompressPubkey(invitation.PublicKey)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
payload, err := proto.Marshal(invitation)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
rawMessage := common.RawMessage{
|
||||||
|
Payload: payload,
|
||||||
|
Sender: org.PrivateKey(),
|
||||||
|
// we don't want to wrap in an encryption layer message
|
||||||
|
SkipEncryption: true,
|
||||||
|
MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_INVITATION,
|
||||||
|
}
|
||||||
|
_, err = m.processor.SendPrivate(context.Background(), pk, &rawMessage)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleCommunitiesSubscription handles events from communities
|
||||||
|
func (m *Messenger) handleCommunitiesSubscription(c chan *communities.Subscription) {
|
||||||
|
|
||||||
|
var lastPublished int64
|
||||||
|
// We check every 5 minutes if we need to publish
|
||||||
|
ticker := time.NewTicker(5 * time.Minute)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case sub, more := <-c:
|
||||||
|
if !more {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if sub.Community != nil {
|
||||||
|
err := m.publishOrg(sub.Community)
|
||||||
|
if err != nil {
|
||||||
|
m.logger.Warn("failed to publish org", zap.Error(err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, invitation := range sub.Invitations {
|
||||||
|
err := m.publishOrgInvitation(sub.Community, invitation)
|
||||||
|
if err != nil {
|
||||||
|
m.logger.Warn("failed to publish org invitation", zap.Error(err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m.logger.Debug("published org")
|
||||||
|
case <-ticker.C:
|
||||||
|
// If we are not online, we don't even try
|
||||||
|
if !m.online() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not enough time has passed since last advertisement, we skip this
|
||||||
|
if time.Now().Unix()-lastPublished < communityAdvertiseIntervalSecond {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
orgs, err := m.communitiesManager.Created()
|
||||||
|
if err != nil {
|
||||||
|
m.logger.Warn("failed to retrieve orgs", zap.Error(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
for idx := range orgs {
|
||||||
|
org := orgs[idx]
|
||||||
|
err := m.publishOrg(org)
|
||||||
|
if err != nil {
|
||||||
|
m.logger.Warn("failed to publish org", zap.Error(err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// set lastPublished
|
||||||
|
lastPublished = time.Now().Unix()
|
||||||
|
|
||||||
|
case <-m.quit:
|
||||||
|
return
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Messenger) Communities() ([]*communities.Community, error) {
|
||||||
|
return m.communitiesManager.All()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Messenger) JoinedCommunities() ([]*communities.Community, error) {
|
||||||
|
return m.communitiesManager.Joined()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Messenger) JoinCommunity(communityID types.HexBytes) (*MessengerResponse, error) {
|
||||||
|
m.mutex.Lock()
|
||||||
|
defer m.mutex.Unlock()
|
||||||
|
|
||||||
|
return m.joinCommunity(communityID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Messenger) joinCommunity(communityID types.HexBytes) (*MessengerResponse, error) {
|
||||||
|
response := &MessengerResponse{}
|
||||||
|
|
||||||
|
community, err := m.communitiesManager.JoinCommunity(communityID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
chatIDs := []string{community.IDString()}
|
||||||
|
|
||||||
|
chats := CreateCommunityChats(community, m.getTimesource())
|
||||||
|
response.AddChats(chats)
|
||||||
|
|
||||||
|
for _, chat := range response.Chats() {
|
||||||
|
chatIDs = append(chatIDs, chat.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load transport filters
|
||||||
|
filters, err := m.transport.InitPublicFilters(chatIDs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
response.Filters = filters
|
||||||
|
response.AddCommunity(community)
|
||||||
|
|
||||||
|
return response, m.saveChats(chats)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Messenger) RequestToJoinCommunity(request *requests.RequestToJoinCommunity) (*MessengerResponse, error) {
|
||||||
|
if err := request.Validate(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
community, requestToJoin, err := m.communitiesManager.RequestToJoin(&m.identity.PublicKey, request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
requestToJoinProto := &protobuf.CommunityRequestToJoin{
|
||||||
|
Clock: requestToJoin.Clock,
|
||||||
|
EnsName: requestToJoin.ENSName,
|
||||||
|
CommunityId: community.ID(),
|
||||||
|
}
|
||||||
|
|
||||||
|
payload, err := proto.Marshal(requestToJoinProto)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
rawMessage := common.RawMessage{
|
||||||
|
Payload: payload,
|
||||||
|
SkipEncryption: true,
|
||||||
|
MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_REQUEST_TO_JOIN,
|
||||||
|
}
|
||||||
|
_, err = m.processor.SendCommunityMessage(context.Background(), community.PublicKey(), rawMessage)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
response := &MessengerResponse{RequestsToJoinCommunity: []*communities.RequestToJoin{requestToJoin}}
|
||||||
|
response.AddCommunity(community)
|
||||||
|
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Messenger) AcceptRequestToJoinCommunity(request *requests.AcceptRequestToJoinCommunity) (*MessengerResponse, error) {
|
||||||
|
if err := request.Validate(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
community, err := m.communitiesManager.AcceptRequestToJoin(request)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
response := &MessengerResponse{}
|
||||||
|
response.AddCommunity(community)
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Messenger) DeclineRequestToJoinCommunity(request *requests.DeclineRequestToJoinCommunity) error {
|
||||||
|
if err := request.Validate(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return m.communitiesManager.DeclineRequestToJoin(request)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Messenger) LeaveCommunity(communityID types.HexBytes) (*MessengerResponse, error) {
|
||||||
|
m.mutex.Lock()
|
||||||
|
defer m.mutex.Unlock()
|
||||||
|
|
||||||
|
return m.leaveCommunity(communityID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Messenger) leaveCommunity(communityID types.HexBytes) (*MessengerResponse, error) {
|
||||||
|
response := &MessengerResponse{}
|
||||||
|
|
||||||
|
community, err := m.communitiesManager.LeaveCommunity(communityID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make chat inactive
|
||||||
|
for chatID := range community.Chats() {
|
||||||
|
communityChatID := communityID.String() + chatID
|
||||||
|
err := m.deleteChat(communityChatID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
response.AddRemovedChat(communityChatID)
|
||||||
|
|
||||||
|
filter, err := m.transport.RemoveFilterByChatID(communityChatID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if filter != nil {
|
||||||
|
response.RemovedFilters = append(response.RemovedFilters, filter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
filter, err := m.transport.RemoveFilterByChatID(communityID.String())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if filter != nil {
|
||||||
|
response.RemovedFilters = append(response.RemovedFilters, filter)
|
||||||
|
}
|
||||||
|
|
||||||
|
response.AddCommunity(community)
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Messenger) CreateCommunityChat(communityID types.HexBytes, c *protobuf.CommunityChat) (*MessengerResponse, error) {
|
||||||
|
var response MessengerResponse
|
||||||
|
community, changes, err := m.communitiesManager.CreateChat(communityID, c)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
response.AddCommunity(community)
|
||||||
|
response.CommunityChanges = []*communities.CommunityChanges{changes}
|
||||||
|
|
||||||
|
var chats []*Chat
|
||||||
|
var chatIDs []string
|
||||||
|
for chatID, chat := range changes.ChatsAdded {
|
||||||
|
c := CreateCommunityChat(community.IDString(), chatID, chat, m.getTimesource())
|
||||||
|
chats = append(chats, c)
|
||||||
|
chatIDs = append(chatIDs, c.ID)
|
||||||
|
response.AddChat(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load filters
|
||||||
|
filters, err := m.transport.InitPublicFilters(chatIDs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
response.Filters = filters
|
||||||
|
|
||||||
|
return &response, m.saveChats(chats)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Messenger) CreateCommunity(request *requests.CreateCommunity) (*MessengerResponse, error) {
|
||||||
|
if err := request.Validate(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
description, err := request.ToCommunityDescription()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
description.Members = make(map[string]*protobuf.CommunityMember)
|
||||||
|
description.Members[common.PubkeyToHex(&m.identity.PublicKey)] = &protobuf.CommunityMember{}
|
||||||
|
|
||||||
|
community, err := m.communitiesManager.CreateCommunity(description)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init the community filter so we can receive messages on the community
|
||||||
|
filters, err := m.transport.InitCommunityFilters([]*ecdsa.PrivateKey{community.PrivateKey()})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
response := &MessengerResponse{
|
||||||
|
Filters: filters,
|
||||||
|
}
|
||||||
|
|
||||||
|
response.AddCommunity(community)
|
||||||
|
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Messenger) ExportCommunity(id types.HexBytes) (*ecdsa.PrivateKey, error) {
|
||||||
|
return m.communitiesManager.ExportCommunity(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Messenger) ImportCommunity(key *ecdsa.PrivateKey) (*MessengerResponse, error) {
|
||||||
|
org, err := m.communitiesManager.ImportCommunity(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load filters
|
||||||
|
filters, err := m.transport.InitPublicFilters([]string{org.IDString()})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &MessengerResponse{
|
||||||
|
Filters: filters,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Messenger) InviteUsersToCommunity(request *requests.InviteUsersToCommunity) (*MessengerResponse, error) {
|
||||||
|
if err := request.Validate(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
response := &MessengerResponse{}
|
||||||
|
var messages []*common.Message
|
||||||
|
|
||||||
|
var publicKeys []*ecdsa.PublicKey
|
||||||
|
for _, pkBytes := range request.Users {
|
||||||
|
publicKey, err := common.HexToPubkey(pkBytes.String())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
publicKeys = append(publicKeys, publicKey)
|
||||||
|
|
||||||
|
message := &common.Message{}
|
||||||
|
message.ChatId = pkBytes.String()
|
||||||
|
message.CommunityID = request.CommunityID.String()
|
||||||
|
message.Text = communityInvitationText
|
||||||
|
messages = append(messages, message)
|
||||||
|
r, err := m.CreateOneToOneChat(&requests.CreateOneToOneChat{ID: pkBytes})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := response.Merge(r); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
community, err := m.communitiesManager.InviteUsersToCommunity(request.CommunityID, publicKeys)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
sendMessagesResponse, err := m.SendChatMessages(context.Background(), messages)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := response.Merge(sendMessagesResponse); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
response.AddCommunity(community)
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Messenger) ShareCommunity(request *requests.ShareCommunity) (*MessengerResponse, error) {
|
||||||
|
if err := request.Validate(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
response := &MessengerResponse{}
|
||||||
|
|
||||||
|
var messages []*common.Message
|
||||||
|
for _, pk := range request.Users {
|
||||||
|
message := &common.Message{}
|
||||||
|
message.ChatId = pk.String()
|
||||||
|
message.CommunityID = request.CommunityID.String()
|
||||||
|
message.Text = communityInvitationText
|
||||||
|
messages = append(messages, message)
|
||||||
|
r, err := m.CreateOneToOneChat(&requests.CreateOneToOneChat{ID: pk})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := response.Merge(r); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sendMessagesResponse, err := m.SendChatMessages(context.Background(), messages)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := response.Merge(sendMessagesResponse); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Messenger) MyPendingRequestsToJoin() ([]*communities.RequestToJoin, error) {
|
||||||
|
return m.communitiesManager.PendingRequestsToJoinForUser(&m.identity.PublicKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Messenger) PendingRequestsToJoinForCommunity(id types.HexBytes) ([]*communities.RequestToJoin, error) {
|
||||||
|
return m.communitiesManager.PendingRequestsToJoinForCommunity(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Messenger) RemoveUserFromCommunity(id types.HexBytes, pkString string) (*MessengerResponse, error) {
|
||||||
|
publicKey, err := common.HexToPubkey(pkString)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
community, err := m.communitiesManager.RemoveUserFromCommunity(id, publicKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
response := &MessengerResponse{}
|
||||||
|
response.AddCommunity(community)
|
||||||
|
return response, nil
|
||||||
|
}
|
|
@ -20,7 +20,8 @@ type config struct {
|
||||||
// This needs to be exposed until we move here mailserver logic
|
// This needs to be exposed until we move here mailserver logic
|
||||||
// as otherwise the client is not notified of a new filter and
|
// as otherwise the client is not notified of a new filter and
|
||||||
// won't be pulling messages from mailservers until it reloads the chats/filters
|
// won't be pulling messages from mailservers until it reloads the chats/filters
|
||||||
onNegotiatedFilters func([]*transport.Filter)
|
onNegotiatedFilters func([]*transport.Filter)
|
||||||
|
onContactENSVerified func(*MessengerResponse)
|
||||||
|
|
||||||
// systemMessagesTranslations holds translations for system-messages
|
// systemMessagesTranslations holds translations for system-messages
|
||||||
systemMessagesTranslations map[protobuf.MembershipUpdateEvent_EventType]string
|
systemMessagesTranslations map[protobuf.MembershipUpdateEvent_EventType]string
|
||||||
|
@ -37,7 +38,9 @@ type config struct {
|
||||||
mailserversDatabase *mailservers.Database
|
mailserversDatabase *mailservers.Database
|
||||||
account *multiaccounts.Account
|
account *multiaccounts.Account
|
||||||
|
|
||||||
verifyTransactionClient EthClient
|
verifyTransactionClient EthClient
|
||||||
|
verifyENSURL string
|
||||||
|
verifyENSContractAddress string
|
||||||
|
|
||||||
pushNotificationServerConfig *pushnotificationserver.Config
|
pushNotificationServerConfig *pushnotificationserver.Config
|
||||||
pushNotificationClientConfig *pushnotificationclient.Config
|
pushNotificationClientConfig *pushnotificationclient.Config
|
||||||
|
@ -155,3 +158,12 @@ func WithDeliveredHandler(h MessageDeliveredHandler) Option {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func WithENSVerificationConfig(onENSVerified func(*MessengerResponse), url, address string) Option {
|
||||||
|
return func(c *config) error {
|
||||||
|
c.onContactENSVerified = onENSVerified
|
||||||
|
c.verifyENSURL = url
|
||||||
|
c.verifyENSContractAddress = address
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -80,8 +80,8 @@ func (s *MessengerContactUpdateSuite) TestReceiveContactUpdate() {
|
||||||
contact.SystemTags = []string{contactAdded}
|
contact.SystemTags = []string{contactAdded}
|
||||||
s.Require().NoError(theirMessenger.SaveContact(contact))
|
s.Require().NoError(theirMessenger.SaveContact(contact))
|
||||||
|
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
chat := response.Chats[0]
|
chat := response.Chats()[0]
|
||||||
s.Require().False(chat.Active, "It does not create an active chat")
|
s.Require().False(chat.Active, "It does not create an active chat")
|
||||||
|
|
||||||
// Wait for the message to reach its destination
|
// Wait for the message to reach its destination
|
||||||
|
@ -137,7 +137,7 @@ func (s *MessengerContactUpdateSuite) TestAddContact() {
|
||||||
contact := response.Contacts[0]
|
contact := response.Contacts[0]
|
||||||
|
|
||||||
// It adds the profile chat and the one to one chat
|
// It adds the profile chat and the one to one chat
|
||||||
s.Require().Len(response.Chats, 2)
|
s.Require().Len(response.Chats(), 2)
|
||||||
|
|
||||||
// It should add the contact
|
// It should add the contact
|
||||||
s.Require().True(contact.IsAdded())
|
s.Require().True(contact.IsAdded())
|
||||||
|
|
|
@ -56,12 +56,10 @@ func (m *Messenger) AddContact(ctx context.Context, pubKey string) (*MessengerRe
|
||||||
profileChat, ok := m.allChats[profileChatID]
|
profileChat, ok := m.allChats[profileChatID]
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
builtChat := CreateProfileChat(profileChatID, contact.ID, m.getTimesource())
|
profileChat = CreateProfileChat(profileChatID, contact.ID, m.getTimesource())
|
||||||
profileChat = &builtChat
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: return filters in messenger response
|
filters, err := m.Join(profileChat)
|
||||||
err = m.Join(*profileChat)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -73,7 +71,8 @@ func (m *Messenger) AddContact(ctx context.Context, pubKey string) (*MessengerRe
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
response.Chats = append(response.Chats, profileChat)
|
response.Filters = filters
|
||||||
|
response.AddChat(profileChat)
|
||||||
|
|
||||||
publicKey, err := contact.PublicKey()
|
publicKey, err := contact.PublicKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -291,7 +290,7 @@ func (m *Messenger) sendContactUpdate(ctx context.Context, chatID, ensName, prof
|
||||||
}
|
}
|
||||||
|
|
||||||
response.Contacts = []*Contact{contact}
|
response.Contacts = []*Contact{contact}
|
||||||
response.Chats = []*Chat{chat}
|
response.AddChat(chat)
|
||||||
|
|
||||||
chat.LastClockValue = clock
|
chat.LastClockValue = clock
|
||||||
err = m.saveChat(chat)
|
err = m.saveChat(chat)
|
||||||
|
|
|
@ -74,21 +74,21 @@ func (s *MessengerEmojiSuite) TestSendEmoji() {
|
||||||
|
|
||||||
chat := CreatePublicChat(chatID, alice.transport)
|
chat := CreatePublicChat(chatID, alice.transport)
|
||||||
|
|
||||||
err = alice.SaveChat(&chat)
|
err = alice.SaveChat(chat)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
err = alice.Join(chat)
|
_, err = alice.Join(chat)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
err = bob.SaveChat(&chat)
|
err = bob.SaveChat(chat)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
err = bob.Join(chat)
|
_, err = bob.Join(chat)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
// Send chat message from bob to alice
|
// Send chat message from bob to alice
|
||||||
|
|
||||||
message := buildTestMessage(chat)
|
message := buildTestMessage(*chat)
|
||||||
_, err = alice.SendChatMessage(context.Background(), message)
|
_, err = alice.SendChatMessage(context.Background(), message)
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
|
|
||||||
|
@ -153,7 +153,7 @@ func (s *MessengerEmojiSuite) TestEmojiPrivateGroup() {
|
||||||
response, err := bob.CreateGroupChatWithMembers(context.Background(), "test", []string{})
|
response, err := bob.CreateGroupChatWithMembers(context.Background(), "test", []string{})
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
|
|
||||||
chat := response.Chats[0]
|
chat := response.Chats()[0]
|
||||||
members := []string{types.EncodeHex(crypto.FromECDSAPub(&alice.identity.PublicKey))}
|
members := []string{types.EncodeHex(crypto.FromECDSAPub(&alice.identity.PublicKey))}
|
||||||
_, err = bob.AddMembersToGroupChat(context.Background(), chat.ID, members)
|
_, err = bob.AddMembersToGroupChat(context.Background(), chat.ID, members)
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
|
@ -161,7 +161,7 @@ func (s *MessengerEmojiSuite) TestEmojiPrivateGroup() {
|
||||||
// Retrieve their messages so that the chat is created
|
// Retrieve their messages so that the chat is created
|
||||||
_, err = WaitOnMessengerResponse(
|
_, err = WaitOnMessengerResponse(
|
||||||
alice,
|
alice,
|
||||||
func(r *MessengerResponse) bool { return len(r.Chats) > 0 },
|
func(r *MessengerResponse) bool { return len(r.Chats()) > 0 },
|
||||||
"chat invitation not received",
|
"chat invitation not received",
|
||||||
)
|
)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
@ -172,7 +172,7 @@ func (s *MessengerEmojiSuite) TestEmojiPrivateGroup() {
|
||||||
// Wait for the message to reach its destination
|
// Wait for the message to reach its destination
|
||||||
_, err = WaitOnMessengerResponse(
|
_, err = WaitOnMessengerResponse(
|
||||||
bob,
|
bob,
|
||||||
func(r *MessengerResponse) bool { return len(r.Chats) > 0 },
|
func(r *MessengerResponse) bool { return len(r.Chats()) > 0 },
|
||||||
"no joining group event received",
|
"no joining group event received",
|
||||||
)
|
)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
package protocol
|
||||||
|
|
||||||
|
func (m *Messenger) ENSVerified(pubkey, ensName string) error {
|
||||||
|
clock := m.getTimesource().GetCurrentTime()
|
||||||
|
return m.ensVerifier.ENSVerified(pubkey, ensName, clock)
|
||||||
|
}
|
|
@ -77,8 +77,8 @@ func (s *MessengerInstallationSuite) TestReceiveInstallation() {
|
||||||
response, err := theirMessenger.SendPairInstallation(context.Background())
|
response, err := theirMessenger.SendPairInstallation(context.Background())
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.Require().NotNil(response)
|
s.Require().NotNil(response)
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
s.Require().False(response.Chats[0].Active)
|
s.Require().False(response.Chats()[0].Active)
|
||||||
|
|
||||||
// Wait for the message to reach its destination
|
// Wait for the message to reach its destination
|
||||||
response, err = WaitOnMessengerResponse(
|
response, err = WaitOnMessengerResponse(
|
||||||
|
@ -119,18 +119,18 @@ func (s *MessengerInstallationSuite) TestReceiveInstallation() {
|
||||||
s.Require().True(actualContact.IsAdded())
|
s.Require().True(actualContact.IsAdded())
|
||||||
|
|
||||||
chat := CreatePublicChat(statusChatID, s.m.transport)
|
chat := CreatePublicChat(statusChatID, s.m.transport)
|
||||||
err = s.m.SaveChat(&chat)
|
err = s.m.SaveChat(chat)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
response, err = WaitOnMessengerResponse(
|
response, err = WaitOnMessengerResponse(
|
||||||
theirMessenger,
|
theirMessenger,
|
||||||
func(r *MessengerResponse) bool { return len(r.Chats) > 0 },
|
func(r *MessengerResponse) bool { return len(r.Chats()) > 0 },
|
||||||
"sync chat not received",
|
"sync chat not received",
|
||||||
)
|
)
|
||||||
|
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
actualChat := response.Chats[0]
|
actualChat := response.Chats()[0]
|
||||||
s.Require().Equal(statusChatID, actualChat.ID)
|
s.Require().Equal(statusChatID, actualChat.ID)
|
||||||
s.Require().True(actualChat.Active)
|
s.Require().True(actualChat.Active)
|
||||||
s.Require().NoError(theirMessenger.Shutdown())
|
s.Require().NoError(theirMessenger.Shutdown())
|
||||||
|
@ -151,7 +151,7 @@ func (s *MessengerInstallationSuite) TestSyncInstallation() {
|
||||||
|
|
||||||
// add chat
|
// add chat
|
||||||
chat := CreatePublicChat(statusChatID, s.m.transport)
|
chat := CreatePublicChat(statusChatID, s.m.transport)
|
||||||
err = s.m.SaveChat(&chat)
|
err = s.m.SaveChat(chat)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
// pair
|
// pair
|
||||||
|
@ -166,8 +166,8 @@ func (s *MessengerInstallationSuite) TestSyncInstallation() {
|
||||||
response, err := theirMessenger.SendPairInstallation(context.Background())
|
response, err := theirMessenger.SendPairInstallation(context.Background())
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.Require().NotNil(response)
|
s.Require().NotNil(response)
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
s.Require().False(response.Chats[0].Active)
|
s.Require().False(response.Chats()[0].Active)
|
||||||
|
|
||||||
// Wait for the message to reach its destination
|
// Wait for the message to reach its destination
|
||||||
response, err = WaitOnMessengerResponse(
|
response, err = WaitOnMessengerResponse(
|
||||||
|
@ -200,7 +200,7 @@ func (s *MessengerInstallationSuite) TestSyncInstallation() {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
allChats = append(allChats, response.Chats...)
|
allChats = append(allChats, response.Chats()...)
|
||||||
|
|
||||||
if len(allChats) >= 2 && len(response.Contacts) == 1 {
|
if len(allChats) >= 2 && len(response.Contacts) == 1 {
|
||||||
actualContact = response.Contacts[0]
|
actualContact = response.Contacts[0]
|
||||||
|
@ -243,8 +243,8 @@ func (s *MessengerInstallationSuite) TestSyncInstallationNewMessages() {
|
||||||
response, err := bob2.SendPairInstallation(context.Background())
|
response, err := bob2.SendPairInstallation(context.Background())
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.Require().NotNil(response)
|
s.Require().NotNil(response)
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
s.Require().False(response.Chats[0].Active)
|
s.Require().False(response.Chats()[0].Active)
|
||||||
|
|
||||||
// Wait for the message to reach its destination
|
// Wait for the message to reach its destination
|
||||||
response, err = WaitOnMessengerResponse(
|
response, err = WaitOnMessengerResponse(
|
||||||
|
@ -263,9 +263,9 @@ func (s *MessengerInstallationSuite) TestSyncInstallationNewMessages() {
|
||||||
|
|
||||||
alicePkString := types.EncodeHex(crypto.FromECDSAPub(&alice.identity.PublicKey))
|
alicePkString := types.EncodeHex(crypto.FromECDSAPub(&alice.identity.PublicKey))
|
||||||
chat := CreateOneToOneChat(alicePkString, &alice.identity.PublicKey, bob1.transport)
|
chat := CreateOneToOneChat(alicePkString, &alice.identity.PublicKey, bob1.transport)
|
||||||
s.Require().NoError(bob1.SaveChat(&chat))
|
s.Require().NoError(bob1.SaveChat(chat))
|
||||||
|
|
||||||
inputMessage := buildTestMessage(chat)
|
inputMessage := buildTestMessage(*chat)
|
||||||
_, err = s.m.SendChatMessage(context.Background(), inputMessage)
|
_, err = s.m.SendChatMessage(context.Background(), inputMessage)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
|
|
|
@ -69,13 +69,13 @@ func (s *MessengerMuteSuite) TestSetMute() {
|
||||||
|
|
||||||
chat := CreatePublicChat(chatID, s.m.transport)
|
chat := CreatePublicChat(chatID, s.m.transport)
|
||||||
|
|
||||||
err = s.m.SaveChat(&chat)
|
err = s.m.SaveChat(chat)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
err = s.m.Join(chat)
|
_, err = s.m.Join(chat)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
err = theirMessenger.SaveChat(&chat)
|
err = theirMessenger.SaveChat(chat)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
s.Require().NoError(s.m.MuteChat(chatID))
|
s.Require().NoError(s.m.MuteChat(chatID))
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package protocol
|
package protocol
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/status-im/status-go/protocol/common"
|
"github.com/status-im/status-go/protocol/common"
|
||||||
"github.com/status-im/status-go/protocol/communities"
|
"github.com/status-im/status-go/protocol/communities"
|
||||||
"github.com/status-im/status-go/protocol/encryption/multidevice"
|
"github.com/status-im/status-go/protocol/encryption/multidevice"
|
||||||
|
@ -9,70 +11,224 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type MessengerResponse struct {
|
type MessengerResponse struct {
|
||||||
Chats []*Chat `json:"chats,omitempty"`
|
Messages []*common.Message
|
||||||
RemovedChats []string `json:"removedChats,omitempty"`
|
Contacts []*Contact
|
||||||
Messages []*common.Message `json:"messages,omitempty"`
|
Installations []*multidevice.Installation
|
||||||
Contacts []*Contact `json:"contacts,omitempty"`
|
EmojiReactions []*EmojiReaction
|
||||||
Installations []*multidevice.Installation `json:"installations,omitempty"`
|
Invitations []*GroupChatInvitation
|
||||||
EmojiReactions []*EmojiReaction `json:"emojiReactions,omitempty"`
|
CommunityChanges []*communities.CommunityChanges
|
||||||
Invitations []*GroupChatInvitation `json:"invitations,omitempty"`
|
RequestsToJoinCommunity []*communities.RequestToJoin
|
||||||
Communities []*communities.Community `json:"communities,omitempty"`
|
Filters []*transport.Filter
|
||||||
CommunityChanges []*communities.CommunityChanges `json:"communitiesChanges,omitempty"`
|
RemovedFilters []*transport.Filter
|
||||||
Filters []*transport.Filter `json:"filters,omitempty"`
|
Mailservers []mailservers.Mailserver
|
||||||
RemovedFilters []*transport.Filter `json:"removedFilters,omitempty"`
|
MailserverTopics []mailservers.MailserverTopic
|
||||||
Mailservers []mailservers.Mailserver `json:"mailservers,omitempty"`
|
MailserverRanges []mailservers.ChatRequestRange
|
||||||
MailserverTopics []mailservers.MailserverTopic `json:"mailserverTopics,omitempty"`
|
|
||||||
MailserverRanges []mailservers.ChatRequestRange `json:"mailserverRanges,omitempty"`
|
|
||||||
|
|
||||||
// Notifications a list of MessageNotificationBody derived from received messages that are useful to notify the user about
|
// Notifications a list of MessageNotificationBody derived from received messages that are useful to notify the user about
|
||||||
Notifications []MessageNotificationBody `json:"notifications"`
|
Notifications []MessageNotificationBody
|
||||||
|
|
||||||
|
chats map[string]*Chat
|
||||||
|
removedChats map[string]bool
|
||||||
|
communities map[string]*communities.Community
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MessengerResponse) IsEmpty() bool {
|
func (r *MessengerResponse) MarshalJSON() ([]byte, error) {
|
||||||
return len(m.Chats)+len(m.Messages)+len(m.Contacts)+len(m.Installations)+len(m.Invitations)+len(m.EmojiReactions)+len(m.Communities)+len(m.CommunityChanges)+len(m.Filters)+len(m.RemovedFilters)+len(m.RemovedChats)+len(m.Notifications)+len(m.MailserverTopics)+len(m.Mailservers)+len(m.MailserverRanges) == 0
|
responseItem := struct {
|
||||||
|
Chats []*Chat `json:"chats,omitempty"`
|
||||||
|
RemovedChats []string `json:"removedChats,omitempty"`
|
||||||
|
Messages []*common.Message `json:"messages,omitempty"`
|
||||||
|
Contacts []*Contact `json:"contacts,omitempty"`
|
||||||
|
Installations []*multidevice.Installation `json:"installations,omitempty"`
|
||||||
|
EmojiReactions []*EmojiReaction `json:"emojiReactions,omitempty"`
|
||||||
|
Invitations []*GroupChatInvitation `json:"invitations,omitempty"`
|
||||||
|
CommunityChanges []*communities.CommunityChanges `json:"communityChanges,omitempty"`
|
||||||
|
RequestsToJoinCommunity []*communities.RequestToJoin `json:"requestsToJoinCommunity,omitempty"`
|
||||||
|
Filters []*transport.Filter `json:"filters,omitempty"`
|
||||||
|
RemovedFilters []*transport.Filter `json:"removedFilters,omitempty"`
|
||||||
|
Mailservers []mailservers.Mailserver `json:"mailservers,omitempty"`
|
||||||
|
MailserverTopics []mailservers.MailserverTopic `json:"mailserverTopics,omitempty"`
|
||||||
|
MailserverRanges []mailservers.ChatRequestRange `json:"mailserverRanges,omitempty"`
|
||||||
|
// Notifications a list of MessageNotificationBody derived from received messages that are useful to notify the user about
|
||||||
|
Notifications []MessageNotificationBody `json:"notifications"`
|
||||||
|
Communities []*communities.Community `json:"communities,omitempty"`
|
||||||
|
}{
|
||||||
|
Messages: r.Messages,
|
||||||
|
Contacts: r.Contacts,
|
||||||
|
Installations: r.Installations,
|
||||||
|
EmojiReactions: r.EmojiReactions,
|
||||||
|
Invitations: r.Invitations,
|
||||||
|
CommunityChanges: r.CommunityChanges,
|
||||||
|
RequestsToJoinCommunity: r.RequestsToJoinCommunity,
|
||||||
|
Filters: r.Filters,
|
||||||
|
RemovedFilters: r.RemovedFilters,
|
||||||
|
Mailservers: r.Mailservers,
|
||||||
|
MailserverTopics: r.MailserverTopics,
|
||||||
|
MailserverRanges: r.MailserverRanges,
|
||||||
|
Notifications: r.Notifications,
|
||||||
|
}
|
||||||
|
|
||||||
|
responseItem.Chats = r.Chats()
|
||||||
|
responseItem.Communities = r.Communities()
|
||||||
|
responseItem.RemovedChats = r.RemovedChats()
|
||||||
|
|
||||||
|
return json.Marshal(responseItem)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *MessengerResponse) Chats() []*Chat {
|
||||||
|
var chats []*Chat
|
||||||
|
for _, chat := range r.chats {
|
||||||
|
chats = append(chats, chat)
|
||||||
|
}
|
||||||
|
return chats
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *MessengerResponse) RemovedChats() []string {
|
||||||
|
var chats []string
|
||||||
|
for chatID := range r.removedChats {
|
||||||
|
chats = append(chats, chatID)
|
||||||
|
}
|
||||||
|
return chats
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *MessengerResponse) Communities() []*communities.Community {
|
||||||
|
var communities []*communities.Community
|
||||||
|
for _, c := range r.communities {
|
||||||
|
communities = append(communities, c)
|
||||||
|
}
|
||||||
|
return communities
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *MessengerResponse) IsEmpty() bool {
|
||||||
|
return len(r.chats)+
|
||||||
|
len(r.Messages)+
|
||||||
|
len(r.Contacts)+
|
||||||
|
len(r.Installations)+
|
||||||
|
len(r.Invitations)+
|
||||||
|
len(r.EmojiReactions)+
|
||||||
|
len(r.communities)+
|
||||||
|
len(r.CommunityChanges)+
|
||||||
|
len(r.Filters)+
|
||||||
|
len(r.RemovedFilters)+
|
||||||
|
len(r.removedChats)+
|
||||||
|
len(r.MailserverTopics)+
|
||||||
|
len(r.Mailservers)+
|
||||||
|
len(r.MailserverRanges)+
|
||||||
|
len(r.Notifications)+
|
||||||
|
len(r.RequestsToJoinCommunity) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge takes another response and appends the new Chats & new Messages and replaces
|
// Merge takes another response and appends the new Chats & new Messages and replaces
|
||||||
// the existing Messages & Chats if they have the same ID
|
// the existing Messages & Chats if they have the same ID
|
||||||
func (m *MessengerResponse) Merge(response *MessengerResponse) error {
|
func (r *MessengerResponse) Merge(response *MessengerResponse) error {
|
||||||
if len(response.Contacts)+len(response.Installations)+len(response.EmojiReactions)+len(response.Invitations) != 0 {
|
if len(response.Contacts)+
|
||||||
|
len(response.Installations)+
|
||||||
|
len(response.EmojiReactions)+
|
||||||
|
len(response.Invitations)+
|
||||||
|
len(response.RequestsToJoinCommunity)+
|
||||||
|
len(response.Mailservers)+
|
||||||
|
len(response.MailserverTopics)+
|
||||||
|
len(response.MailserverRanges)+
|
||||||
|
len(response.Notifications)+
|
||||||
|
len(response.EmojiReactions)+
|
||||||
|
len(response.CommunityChanges) != 0 {
|
||||||
return ErrNotImplemented
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
m.overrideChats(response.Chats)
|
r.AddChats(response.Chats())
|
||||||
m.overrideMessages(response.Messages)
|
r.AddRemovedChats(response.RemovedChats())
|
||||||
|
r.overrideMessages(response.Messages)
|
||||||
|
r.overrideFilters(response.Filters)
|
||||||
|
r.overrideRemovedFilters(response.Filters)
|
||||||
|
r.AddCommunities(response.Communities())
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// overrideChats append new chats and override existing ones in response.Chats
|
// overrideMessages append new messages and override existing ones in response.Messages
|
||||||
func (m *MessengerResponse) overrideChats(chats []*Chat) {
|
func (r *MessengerResponse) overrideMessages(messages []*common.Message) {
|
||||||
for _, overrideChat := range chats {
|
for _, overrideMessage := range messages {
|
||||||
var found = false
|
var found = false
|
||||||
for idx, chat := range m.Chats {
|
for idx, chat := range r.Messages {
|
||||||
if chat.ID == overrideChat.ID {
|
if chat.ID == overrideMessage.ID {
|
||||||
m.Chats[idx] = overrideChat
|
r.Messages[idx] = overrideMessage
|
||||||
found = true
|
found = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !found {
|
if !found {
|
||||||
m.Chats = append(m.Chats, overrideChat)
|
r.Messages = append(r.Messages, overrideMessage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// overrideMessages append new messages and override existing ones in response.Messages
|
// overrideFilters append new filters and override existing ones in response.Filters
|
||||||
func (m *MessengerResponse) overrideMessages(messages []*common.Message) {
|
func (r *MessengerResponse) overrideFilters(filters []*transport.Filter) {
|
||||||
for _, overrideMessage := range messages {
|
for _, overrideFilter := range filters {
|
||||||
var found = false
|
var found = false
|
||||||
for idx, chat := range m.Messages {
|
for idx, filter := range r.Filters {
|
||||||
if chat.ID == overrideMessage.ID {
|
if filter.FilterID == overrideFilter.FilterID {
|
||||||
m.Messages[idx] = overrideMessage
|
r.Filters[idx] = overrideFilter
|
||||||
found = true
|
found = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !found {
|
if !found {
|
||||||
m.Messages = append(m.Messages, overrideMessage)
|
r.Filters = append(r.Filters, overrideFilter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// overrideRemovedFilters append removed filters and override existing ones in response.Filters
|
||||||
|
func (r *MessengerResponse) overrideRemovedFilters(filters []*transport.Filter) {
|
||||||
|
for _, overrideFilter := range filters {
|
||||||
|
var found = false
|
||||||
|
for idx, filter := range r.RemovedFilters {
|
||||||
|
if filter.FilterID == overrideFilter.FilterID {
|
||||||
|
r.RemovedFilters[idx] = overrideFilter
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
r.RemovedFilters = append(r.RemovedFilters, overrideFilter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *MessengerResponse) AddCommunities(communities []*communities.Community) {
|
||||||
|
for _, overrideCommunity := range communities {
|
||||||
|
r.AddCommunity(overrideCommunity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *MessengerResponse) AddCommunity(c *communities.Community) {
|
||||||
|
if r.communities == nil {
|
||||||
|
r.communities = make(map[string]*communities.Community)
|
||||||
|
}
|
||||||
|
|
||||||
|
r.communities[c.IDString()] = c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *MessengerResponse) AddChat(c *Chat) {
|
||||||
|
if r.chats == nil {
|
||||||
|
r.chats = make(map[string]*Chat)
|
||||||
|
}
|
||||||
|
|
||||||
|
r.chats[c.ID] = c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *MessengerResponse) AddChats(chats []*Chat) {
|
||||||
|
for _, c := range chats {
|
||||||
|
r.AddChat(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *MessengerResponse) AddRemovedChats(chats []string) {
|
||||||
|
for _, c := range chats {
|
||||||
|
r.AddRemovedChat(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *MessengerResponse) AddRemovedChat(chatID string) {
|
||||||
|
if r.removedChats == nil {
|
||||||
|
r.removedChats = make(map[string]bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
r.removedChats[chatID] = true
|
||||||
|
}
|
||||||
|
|
|
@ -13,19 +13,17 @@ func TestMessengerResponseMergeChats(t *testing.T) {
|
||||||
chat1 := &Chat{ID: "1"}
|
chat1 := &Chat{ID: "1"}
|
||||||
modifiedChat1 := &Chat{ID: "1", Name: "name"}
|
modifiedChat1 := &Chat{ID: "1", Name: "name"}
|
||||||
chat2 := &Chat{ID: "3"}
|
chat2 := &Chat{ID: "3"}
|
||||||
response1 := &MessengerResponse{
|
response1 := &MessengerResponse{}
|
||||||
Chats: []*Chat{chat1},
|
response1.AddChat(chat1)
|
||||||
}
|
|
||||||
|
|
||||||
response2 := &MessengerResponse{
|
response2 := &MessengerResponse{}
|
||||||
Chats: []*Chat{modifiedChat1, chat2},
|
response2.AddChats([]*Chat{modifiedChat1, chat2})
|
||||||
}
|
|
||||||
|
|
||||||
require.NoError(t, response1.Merge(response2))
|
require.NoError(t, response1.Merge(response2))
|
||||||
|
|
||||||
require.Len(t, response1.Chats, 2)
|
require.Len(t, response1.Chats(), 2)
|
||||||
require.Equal(t, modifiedChat1, response1.Chats[0])
|
require.Equal(t, modifiedChat1, response1.chats[modifiedChat1.ID])
|
||||||
require.Equal(t, chat2, response1.Chats[1])
|
require.Equal(t, chat2, response1.chats[chat2.ID])
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMessengerResponseMergeMessages(t *testing.T) {
|
func TestMessengerResponseMergeMessages(t *testing.T) {
|
||||||
|
|
|
@ -334,12 +334,12 @@ func buildTestMessage(chat Chat) *common.Message {
|
||||||
func (s *MessengerSuite) TestMarkMessagesSeen() {
|
func (s *MessengerSuite) TestMarkMessagesSeen() {
|
||||||
chat := CreatePublicChat("test-chat", s.m.transport)
|
chat := CreatePublicChat("test-chat", s.m.transport)
|
||||||
chat.UnviewedMessagesCount = 2
|
chat.UnviewedMessagesCount = 2
|
||||||
err := s.m.SaveChat(&chat)
|
err := s.m.SaveChat(chat)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
inputMessage1 := buildTestMessage(chat)
|
inputMessage1 := buildTestMessage(*chat)
|
||||||
inputMessage1.ID = "1"
|
inputMessage1.ID = "1"
|
||||||
inputMessage1.Seen = false
|
inputMessage1.Seen = false
|
||||||
inputMessage2 := buildTestMessage(chat)
|
inputMessage2 := buildTestMessage(*chat)
|
||||||
inputMessage2.ID = "2"
|
inputMessage2.ID = "2"
|
||||||
inputMessage2.Seen = false
|
inputMessage2.Seen = false
|
||||||
|
|
||||||
|
@ -363,12 +363,12 @@ func (s *MessengerSuite) TestMarkMessagesSeen() {
|
||||||
func (s *MessengerSuite) TestMarkAllRead() {
|
func (s *MessengerSuite) TestMarkAllRead() {
|
||||||
chat := CreatePublicChat("test-chat", s.m.transport)
|
chat := CreatePublicChat("test-chat", s.m.transport)
|
||||||
chat.UnviewedMessagesCount = 2
|
chat.UnviewedMessagesCount = 2
|
||||||
err := s.m.SaveChat(&chat)
|
err := s.m.SaveChat(chat)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
inputMessage1 := buildTestMessage(chat)
|
inputMessage1 := buildTestMessage(*chat)
|
||||||
inputMessage1.ID = "1"
|
inputMessage1.ID = "1"
|
||||||
inputMessage1.Seen = false
|
inputMessage1.Seen = false
|
||||||
inputMessage2 := buildTestMessage(chat)
|
inputMessage2 := buildTestMessage(*chat)
|
||||||
inputMessage2.ID = "2"
|
inputMessage2.ID = "2"
|
||||||
inputMessage2.Seen = false
|
inputMessage2.Seen = false
|
||||||
|
|
||||||
|
@ -386,9 +386,9 @@ func (s *MessengerSuite) TestMarkAllRead() {
|
||||||
func (s *MessengerSuite) TestSendPublic() {
|
func (s *MessengerSuite) TestSendPublic() {
|
||||||
chat := CreatePublicChat("test-chat", s.m.transport)
|
chat := CreatePublicChat("test-chat", s.m.transport)
|
||||||
chat.LastClockValue = uint64(100000000000000)
|
chat.LastClockValue = uint64(100000000000000)
|
||||||
err := s.m.SaveChat(&chat)
|
err := s.m.SaveChat(chat)
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
inputMessage := buildTestMessage(chat)
|
inputMessage := buildTestMessage(*chat)
|
||||||
response, err := s.m.SendChatMessage(context.Background(), inputMessage)
|
response, err := s.m.SendChatMessage(context.Background(), inputMessage)
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
|
|
||||||
|
@ -412,9 +412,9 @@ func (s *MessengerSuite) TestSendPublic() {
|
||||||
func (s *MessengerSuite) TestSendProfile() {
|
func (s *MessengerSuite) TestSendProfile() {
|
||||||
chat := CreateProfileChat("test-chat-profile", "0x"+hex.EncodeToString(crypto.FromECDSAPub(&s.privateKey.PublicKey)), s.m.transport)
|
chat := CreateProfileChat("test-chat-profile", "0x"+hex.EncodeToString(crypto.FromECDSAPub(&s.privateKey.PublicKey)), s.m.transport)
|
||||||
chat.LastClockValue = uint64(100000000000000)
|
chat.LastClockValue = uint64(100000000000000)
|
||||||
err := s.m.SaveChat(&chat)
|
err := s.m.SaveChat(chat)
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
inputMessage := buildTestMessage(chat)
|
inputMessage := buildTestMessage(*chat)
|
||||||
response, err := s.m.SendChatMessage(context.Background(), inputMessage)
|
response, err := s.m.SendChatMessage(context.Background(), inputMessage)
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
|
|
||||||
|
@ -445,7 +445,7 @@ func (s *MessengerSuite) TestSendPrivateOneToOne() {
|
||||||
inputMessage := &common.Message{}
|
inputMessage := &common.Message{}
|
||||||
inputMessage.ChatId = chat.ID
|
inputMessage.ChatId = chat.ID
|
||||||
chat.LastClockValue = uint64(100000000000000)
|
chat.LastClockValue = uint64(100000000000000)
|
||||||
err = s.m.SaveChat(&chat)
|
err = s.m.SaveChat(chat)
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
response, err := s.m.SendChatMessage(context.Background(), inputMessage)
|
response, err := s.m.SendChatMessage(context.Background(), inputMessage)
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
|
@ -466,9 +466,9 @@ func (s *MessengerSuite) TestSendPrivateOneToOne() {
|
||||||
func (s *MessengerSuite) TestSendPrivateGroup() {
|
func (s *MessengerSuite) TestSendPrivateGroup() {
|
||||||
response, err := s.m.CreateGroupChatWithMembers(context.Background(), "test", []string{})
|
response, err := s.m.CreateGroupChatWithMembers(context.Background(), "test", []string{})
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
|
|
||||||
chat := response.Chats[0]
|
chat := response.Chats()[0]
|
||||||
key, err := crypto.GenerateKey()
|
key, err := crypto.GenerateKey()
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
members := []string{"0x" + hex.EncodeToString(crypto.FromECDSAPub(&key.PublicKey))}
|
members := []string{"0x" + hex.EncodeToString(crypto.FromECDSAPub(&key.PublicKey))}
|
||||||
|
@ -499,9 +499,9 @@ func (s *MessengerSuite) TestSendPrivateGroup() {
|
||||||
func (s *MessengerSuite) TestSendPrivateEmptyGroup() {
|
func (s *MessengerSuite) TestSendPrivateEmptyGroup() {
|
||||||
response, err := s.m.CreateGroupChatWithMembers(context.Background(), "test", []string{})
|
response, err := s.m.CreateGroupChatWithMembers(context.Background(), "test", []string{})
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
|
|
||||||
chat := response.Chats[0]
|
chat := response.Chats()[0]
|
||||||
|
|
||||||
inputMessage := &common.Message{}
|
inputMessage := &common.Message{}
|
||||||
inputMessage.ChatId = chat.ID
|
inputMessage.ChatId = chat.ID
|
||||||
|
@ -527,12 +527,12 @@ func (s *MessengerSuite) TestSendPrivateEmptyGroup() {
|
||||||
// Make sure public messages sent by us are not
|
// Make sure public messages sent by us are not
|
||||||
func (s *MessengerSuite) TestRetrieveOwnPublic() {
|
func (s *MessengerSuite) TestRetrieveOwnPublic() {
|
||||||
chat := CreatePublicChat("status", s.m.transport)
|
chat := CreatePublicChat("status", s.m.transport)
|
||||||
err := s.m.SaveChat(&chat)
|
err := s.m.SaveChat(chat)
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
// Right-to-left text
|
// Right-to-left text
|
||||||
text := "پيل اندر خانه يي تاريک بود عرضه را آورده بودندش هنود i\nاز براي ديدنش مردم بسي اندر آن ظلمت همي شد هر کسي"
|
text := "پيل اندر خانه يي تاريک بود عرضه را آورده بودندش هنود i\nاز براي ديدنش مردم بسي اندر آن ظلمت همي شد هر کسي"
|
||||||
|
|
||||||
inputMessage := buildTestMessage(chat)
|
inputMessage := buildTestMessage(*chat)
|
||||||
inputMessage.ChatId = chat.ID
|
inputMessage.ChatId = chat.ID
|
||||||
inputMessage.Text = text
|
inputMessage.Text = text
|
||||||
|
|
||||||
|
@ -548,8 +548,8 @@ func (s *MessengerSuite) TestRetrieveOwnPublic() {
|
||||||
s.True(textMessage.RTL)
|
s.True(textMessage.RTL)
|
||||||
s.Equal(1, textMessage.LineCount)
|
s.Equal(1, textMessage.LineCount)
|
||||||
|
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
actualChat := response.Chats[0]
|
actualChat := response.Chats()[0]
|
||||||
// It does not set the unviewed messages count
|
// It does not set the unviewed messages count
|
||||||
s.Require().Equal(uint(0), actualChat.UnviewedMessagesCount)
|
s.Require().Equal(uint(0), actualChat.UnviewedMessagesCount)
|
||||||
// It updates the last message clock value
|
// It updates the last message clock value
|
||||||
|
@ -564,17 +564,17 @@ func (s *MessengerSuite) TestRetrieveTheirPublic() {
|
||||||
_, err := theirMessenger.Start()
|
_, err := theirMessenger.Start()
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
theirChat := CreatePublicChat("status", s.m.transport)
|
theirChat := CreatePublicChat("status", s.m.transport)
|
||||||
err = theirMessenger.SaveChat(&theirChat)
|
err = theirMessenger.SaveChat(theirChat)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
chat := CreatePublicChat("status", s.m.transport)
|
chat := CreatePublicChat("status", s.m.transport)
|
||||||
err = s.m.SaveChat(&chat)
|
err = s.m.SaveChat(chat)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
err = s.m.Join(chat)
|
_, err = s.m.Join(chat)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
inputMessage := buildTestMessage(chat)
|
inputMessage := buildTestMessage(*chat)
|
||||||
|
|
||||||
sendResponse, err := theirMessenger.SendChatMessage(context.Background(), inputMessage)
|
sendResponse, err := theirMessenger.SendChatMessage(context.Background(), inputMessage)
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
|
@ -591,8 +591,8 @@ func (s *MessengerSuite) TestRetrieveTheirPublic() {
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
s.Require().Len(response.Messages, 1)
|
s.Require().Len(response.Messages, 1)
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
actualChat := response.Chats[0]
|
actualChat := response.Chats()[0]
|
||||||
// It sets the unviewed messages count
|
// It sets the unviewed messages count
|
||||||
s.Require().Equal(uint(1), actualChat.UnviewedMessagesCount)
|
s.Require().Equal(uint(1), actualChat.UnviewedMessagesCount)
|
||||||
// It updates the last message clock value
|
// It updates the last message clock value
|
||||||
|
@ -607,23 +607,23 @@ func (s *MessengerSuite) TestDeletedAtClockValue() {
|
||||||
_, err := theirMessenger.Start()
|
_, err := theirMessenger.Start()
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
theirChat := CreatePublicChat("status", s.m.transport)
|
theirChat := CreatePublicChat("status", s.m.transport)
|
||||||
err = theirMessenger.SaveChat(&theirChat)
|
err = theirMessenger.SaveChat(theirChat)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
chat := CreatePublicChat("status", s.m.transport)
|
chat := CreatePublicChat("status", s.m.transport)
|
||||||
err = s.m.SaveChat(&chat)
|
err = s.m.SaveChat(chat)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
err = s.m.Join(chat)
|
_, err = s.m.Join(chat)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
inputMessage := buildTestMessage(chat)
|
inputMessage := buildTestMessage(*chat)
|
||||||
|
|
||||||
sentResponse, err := theirMessenger.SendChatMessage(context.Background(), inputMessage)
|
sentResponse, err := theirMessenger.SendChatMessage(context.Background(), inputMessage)
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
|
|
||||||
chat.DeletedAtClockValue = sentResponse.Messages[0].Clock
|
chat.DeletedAtClockValue = sentResponse.Messages[0].Clock
|
||||||
err = s.m.SaveChat(&chat)
|
err = s.m.SaveChat(chat)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
// Wait for the message to reach its destination
|
// Wait for the message to reach its destination
|
||||||
|
@ -639,28 +639,27 @@ func (s *MessengerSuite) TestRetrieveBlockedContact() {
|
||||||
_, err := theirMessenger.Start()
|
_, err := theirMessenger.Start()
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
theirChat := CreatePublicChat("status", s.m.transport)
|
theirChat := CreatePublicChat("status", s.m.transport)
|
||||||
err = theirMessenger.SaveChat(&theirChat)
|
err = theirMessenger.SaveChat(theirChat)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
chat := CreatePublicChat("status", s.m.transport)
|
chat := CreatePublicChat("status", s.m.transport)
|
||||||
err = s.m.SaveChat(&chat)
|
err = s.m.SaveChat(chat)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
err = s.m.Join(chat)
|
_, err = s.m.Join(chat)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
publicKeyHex := "0x" + hex.EncodeToString(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey))
|
publicKeyHex := "0x" + hex.EncodeToString(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey))
|
||||||
blockedContact := Contact{
|
blockedContact := Contact{
|
||||||
ID: publicKeyHex,
|
ID: publicKeyHex,
|
||||||
Name: "contact-name",
|
Name: "contact-name",
|
||||||
LastUpdated: 20,
|
LastUpdated: 20,
|
||||||
SystemTags: []string{contactBlocked},
|
SystemTags: []string{contactBlocked},
|
||||||
TributeToTalk: "talk",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Require().NoError(s.m.SaveContact(&blockedContact))
|
s.Require().NoError(s.m.SaveContact(&blockedContact))
|
||||||
|
|
||||||
inputMessage := buildTestMessage(chat)
|
inputMessage := buildTestMessage(*chat)
|
||||||
|
|
||||||
_, err = theirMessenger.SendChatMessage(context.Background(), inputMessage)
|
_, err = theirMessenger.SendChatMessage(context.Background(), inputMessage)
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
|
@ -678,17 +677,17 @@ func (s *MessengerSuite) TestResendPublicMessage() {
|
||||||
_, err := theirMessenger.Start()
|
_, err := theirMessenger.Start()
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
theirChat := CreatePublicChat("status", s.m.transport)
|
theirChat := CreatePublicChat("status", s.m.transport)
|
||||||
err = theirMessenger.SaveChat(&theirChat)
|
err = theirMessenger.SaveChat(theirChat)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
chat := CreatePublicChat("status", s.m.transport)
|
chat := CreatePublicChat("status", s.m.transport)
|
||||||
err = s.m.SaveChat(&chat)
|
err = s.m.SaveChat(chat)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
err = s.m.Join(chat)
|
_, err = s.m.Join(chat)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
inputMessage := buildTestMessage(chat)
|
inputMessage := buildTestMessage(*chat)
|
||||||
|
|
||||||
sendResponse1, err := theirMessenger.SendChatMessage(context.Background(), inputMessage)
|
sendResponse1, err := theirMessenger.SendChatMessage(context.Background(), inputMessage)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
@ -707,8 +706,8 @@ func (s *MessengerSuite) TestResendPublicMessage() {
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
s.Require().Len(response.Messages, 1)
|
s.Require().Len(response.Messages, 1)
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
actualChat := response.Chats[0]
|
actualChat := response.Chats()[0]
|
||||||
// It sets the unviewed messages count
|
// It sets the unviewed messages count
|
||||||
s.Require().Equal(uint(1), actualChat.UnviewedMessagesCount)
|
s.Require().Equal(uint(1), actualChat.UnviewedMessagesCount)
|
||||||
// It updates the last message clock value
|
// It updates the last message clock value
|
||||||
|
@ -733,17 +732,17 @@ func (s *MessengerSuite) TestRetrieveTheirPrivateChatExisting() {
|
||||||
_, err := theirMessenger.Start()
|
_, err := theirMessenger.Start()
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
theirChat := CreateOneToOneChat("XXX", &s.privateKey.PublicKey, s.m.transport)
|
theirChat := CreateOneToOneChat("XXX", &s.privateKey.PublicKey, s.m.transport)
|
||||||
err = theirMessenger.SaveChat(&theirChat)
|
err = theirMessenger.SaveChat(theirChat)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
ourChat := CreateOneToOneChat("our-chat", &theirMessenger.identity.PublicKey, s.m.transport)
|
ourChat := CreateOneToOneChat("our-chat", &theirMessenger.identity.PublicKey, s.m.transport)
|
||||||
ourChat.UnviewedMessagesCount = 1
|
ourChat.UnviewedMessagesCount = 1
|
||||||
// Make chat inactive
|
// Make chat inactive
|
||||||
ourChat.Active = false
|
ourChat.Active = false
|
||||||
err = s.m.SaveChat(&ourChat)
|
err = s.m.SaveChat(ourChat)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
inputMessage := buildTestMessage(theirChat)
|
inputMessage := buildTestMessage(*theirChat)
|
||||||
|
|
||||||
sendResponse, err := theirMessenger.SendChatMessage(context.Background(), inputMessage)
|
sendResponse, err := theirMessenger.SendChatMessage(context.Background(), inputMessage)
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
|
@ -758,8 +757,8 @@ func (s *MessengerSuite) TestRetrieveTheirPrivateChatExisting() {
|
||||||
)
|
)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
s.Require().Equal(len(response.Chats), 1)
|
s.Require().Equal(len(response.Chats()), 1)
|
||||||
actualChat := response.Chats[0]
|
actualChat := response.Chats()[0]
|
||||||
// It updates the unviewed messages count
|
// It updates the unviewed messages count
|
||||||
s.Require().Equal(uint(2), actualChat.UnviewedMessagesCount)
|
s.Require().Equal(uint(2), actualChat.UnviewedMessagesCount)
|
||||||
// It updates the last message clock value
|
// It updates the last message clock value
|
||||||
|
@ -776,10 +775,10 @@ func (s *MessengerSuite) TestRetrieveTheirPrivateChatNonExisting() {
|
||||||
_, err := theirMessenger.Start()
|
_, err := theirMessenger.Start()
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
chat := CreateOneToOneChat("XXX", &s.privateKey.PublicKey, s.m.transport)
|
chat := CreateOneToOneChat("XXX", &s.privateKey.PublicKey, s.m.transport)
|
||||||
err = theirMessenger.SaveChat(&chat)
|
err = theirMessenger.SaveChat(chat)
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
|
|
||||||
inputMessage := buildTestMessage(chat)
|
inputMessage := buildTestMessage(*chat)
|
||||||
|
|
||||||
sendResponse, err := theirMessenger.SendChatMessage(context.Background(), inputMessage)
|
sendResponse, err := theirMessenger.SendChatMessage(context.Background(), inputMessage)
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
|
@ -796,8 +795,8 @@ func (s *MessengerSuite) TestRetrieveTheirPrivateChatNonExisting() {
|
||||||
|
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
actualChat := response.Chats[0]
|
actualChat := response.Chats()[0]
|
||||||
// It updates the unviewed messages count
|
// It updates the unviewed messages count
|
||||||
s.Require().Equal(uint(1), actualChat.UnviewedMessagesCount)
|
s.Require().Equal(uint(1), actualChat.UnviewedMessagesCount)
|
||||||
// It updates the last message clock value
|
// It updates the last message clock value
|
||||||
|
@ -814,10 +813,10 @@ func (s *MessengerSuite) TestRetrieveTheirPublicChatNonExisting() {
|
||||||
_, err := theirMessenger.Start()
|
_, err := theirMessenger.Start()
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
chat := CreatePublicChat("test-chat", s.m.transport)
|
chat := CreatePublicChat("test-chat", s.m.transport)
|
||||||
err = theirMessenger.SaveChat(&chat)
|
err = theirMessenger.SaveChat(chat)
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
|
|
||||||
inputMessage := buildTestMessage(chat)
|
inputMessage := buildTestMessage(*chat)
|
||||||
|
|
||||||
sendResponse, err := theirMessenger.SendChatMessage(context.Background(), inputMessage)
|
sendResponse, err := theirMessenger.SendChatMessage(context.Background(), inputMessage)
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
|
@ -829,7 +828,7 @@ func (s *MessengerSuite) TestRetrieveTheirPublicChatNonExisting() {
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
|
|
||||||
s.Require().Equal(len(response.Messages), 0)
|
s.Require().Equal(len(response.Messages), 0)
|
||||||
s.Require().Equal(len(response.Chats), 0)
|
s.Require().Equal(len(response.Chats()), 0)
|
||||||
s.Require().NoError(theirMessenger.Shutdown())
|
s.Require().NoError(theirMessenger.Shutdown())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -841,9 +840,9 @@ func (s *MessengerSuite) TestRetrieveTheirPrivateGroupChat() {
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
response, err = s.m.CreateGroupChatWithMembers(context.Background(), "id", []string{})
|
response, err = s.m.CreateGroupChatWithMembers(context.Background(), "id", []string{})
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
|
|
||||||
ourChat := response.Chats[0]
|
ourChat := response.Chats()[0]
|
||||||
|
|
||||||
err = s.m.SaveChat(ourChat)
|
err = s.m.SaveChat(ourChat)
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
|
@ -855,7 +854,7 @@ func (s *MessengerSuite) TestRetrieveTheirPrivateGroupChat() {
|
||||||
// Retrieve their messages so that the chat is created
|
// Retrieve their messages so that the chat is created
|
||||||
_, err = WaitOnMessengerResponse(
|
_, err = WaitOnMessengerResponse(
|
||||||
theirMessenger,
|
theirMessenger,
|
||||||
func(r *MessengerResponse) bool { return len(r.Chats) > 0 },
|
func(r *MessengerResponse) bool { return len(r.Chats()) > 0 },
|
||||||
"chat invitation not received",
|
"chat invitation not received",
|
||||||
)
|
)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
@ -866,7 +865,7 @@ func (s *MessengerSuite) TestRetrieveTheirPrivateGroupChat() {
|
||||||
// Wait for the message to reach its destination
|
// Wait for the message to reach its destination
|
||||||
_, err = WaitOnMessengerResponse(
|
_, err = WaitOnMessengerResponse(
|
||||||
s.m,
|
s.m,
|
||||||
func(r *MessengerResponse) bool { return len(r.Chats) > 0 },
|
func(r *MessengerResponse) bool { return len(r.Chats()) > 0 },
|
||||||
"no joining group event received",
|
"no joining group event received",
|
||||||
)
|
)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
@ -886,8 +885,8 @@ func (s *MessengerSuite) TestRetrieveTheirPrivateGroupChat() {
|
||||||
)
|
)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
actualChat := response.Chats[0]
|
actualChat := response.Chats()[0]
|
||||||
// It updates the unviewed messages count
|
// It updates the unviewed messages count
|
||||||
s.Require().Equal(uint(1), actualChat.UnviewedMessagesCount)
|
s.Require().Equal(uint(1), actualChat.UnviewedMessagesCount)
|
||||||
// It updates the last message clock value
|
// It updates the last message clock value
|
||||||
|
@ -904,9 +903,9 @@ func (s *MessengerSuite) TestChangeNameGroupChat() {
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
response, err = s.m.CreateGroupChatWithMembers(context.Background(), "old-name", []string{})
|
response, err = s.m.CreateGroupChatWithMembers(context.Background(), "old-name", []string{})
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
|
|
||||||
ourChat := response.Chats[0]
|
ourChat := response.Chats()[0]
|
||||||
|
|
||||||
err = s.m.SaveChat(ourChat)
|
err = s.m.SaveChat(ourChat)
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
|
@ -918,7 +917,7 @@ func (s *MessengerSuite) TestChangeNameGroupChat() {
|
||||||
// Retrieve their messages so that the chat is created
|
// Retrieve their messages so that the chat is created
|
||||||
_, err = WaitOnMessengerResponse(
|
_, err = WaitOnMessengerResponse(
|
||||||
theirMessenger,
|
theirMessenger,
|
||||||
func(r *MessengerResponse) bool { return len(r.Chats) > 0 },
|
func(r *MessengerResponse) bool { return len(r.Chats()) > 0 },
|
||||||
"chat invitation not received",
|
"chat invitation not received",
|
||||||
)
|
)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
@ -929,7 +928,7 @@ func (s *MessengerSuite) TestChangeNameGroupChat() {
|
||||||
// Wait for join group event
|
// Wait for join group event
|
||||||
_, err = WaitOnMessengerResponse(
|
_, err = WaitOnMessengerResponse(
|
||||||
s.m,
|
s.m,
|
||||||
func(r *MessengerResponse) bool { return len(r.Chats) > 0 },
|
func(r *MessengerResponse) bool { return len(r.Chats()) > 0 },
|
||||||
"no joining group event received",
|
"no joining group event received",
|
||||||
)
|
)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
@ -940,13 +939,13 @@ func (s *MessengerSuite) TestChangeNameGroupChat() {
|
||||||
// Retrieve their messages so that the chat is created
|
// Retrieve their messages so that the chat is created
|
||||||
response, err = WaitOnMessengerResponse(
|
response, err = WaitOnMessengerResponse(
|
||||||
theirMessenger,
|
theirMessenger,
|
||||||
func(r *MessengerResponse) bool { return len(r.Chats) > 0 },
|
func(r *MessengerResponse) bool { return len(r.Chats()) > 0 },
|
||||||
"chat invitation not received",
|
"chat invitation not received",
|
||||||
)
|
)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
actualChat := response.Chats[0]
|
actualChat := response.Chats()[0]
|
||||||
s.Require().Equal(newName, actualChat.Name)
|
s.Require().Equal(newName, actualChat.Name)
|
||||||
s.Require().NoError(theirMessenger.Shutdown())
|
s.Require().NoError(theirMessenger.Shutdown())
|
||||||
}
|
}
|
||||||
|
@ -959,9 +958,9 @@ func (s *MessengerSuite) TestReInvitedToGroupChat() {
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
response, err = s.m.CreateGroupChatWithMembers(context.Background(), "old-name", []string{})
|
response, err = s.m.CreateGroupChatWithMembers(context.Background(), "old-name", []string{})
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
|
|
||||||
ourChat := response.Chats[0]
|
ourChat := response.Chats()[0]
|
||||||
|
|
||||||
err = s.m.SaveChat(ourChat)
|
err = s.m.SaveChat(ourChat)
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
|
@ -973,7 +972,7 @@ func (s *MessengerSuite) TestReInvitedToGroupChat() {
|
||||||
// Retrieve their messages so that the chat is created
|
// Retrieve their messages so that the chat is created
|
||||||
_, err = WaitOnMessengerResponse(
|
_, err = WaitOnMessengerResponse(
|
||||||
theirMessenger,
|
theirMessenger,
|
||||||
func(r *MessengerResponse) bool { return len(r.Chats) > 0 },
|
func(r *MessengerResponse) bool { return len(r.Chats()) > 0 },
|
||||||
"chat invitation not received",
|
"chat invitation not received",
|
||||||
)
|
)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
@ -984,7 +983,7 @@ func (s *MessengerSuite) TestReInvitedToGroupChat() {
|
||||||
// Wait for join group event
|
// Wait for join group event
|
||||||
_, err = WaitOnMessengerResponse(
|
_, err = WaitOnMessengerResponse(
|
||||||
s.m,
|
s.m,
|
||||||
func(r *MessengerResponse) bool { return len(r.Chats) > 0 },
|
func(r *MessengerResponse) bool { return len(r.Chats()) > 0 },
|
||||||
"no joining group event received",
|
"no joining group event received",
|
||||||
)
|
)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
@ -992,13 +991,13 @@ func (s *MessengerSuite) TestReInvitedToGroupChat() {
|
||||||
response, err = theirMessenger.LeaveGroupChat(context.Background(), ourChat.ID, true)
|
response, err = theirMessenger.LeaveGroupChat(context.Background(), ourChat.ID, true)
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
|
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
s.Require().False(response.Chats[0].Active)
|
s.Require().False(response.Chats()[0].Active)
|
||||||
|
|
||||||
// Retrieve messages so user is removed
|
// Retrieve messages so user is removed
|
||||||
_, err = WaitOnMessengerResponse(
|
_, err = WaitOnMessengerResponse(
|
||||||
s.m,
|
s.m,
|
||||||
func(r *MessengerResponse) bool { return len(r.Chats) > 0 && len(r.Chats[0].Members) == 1 },
|
func(r *MessengerResponse) bool { return len(r.Chats()) > 0 && len(r.Chats()[0].Members) == 1 },
|
||||||
"leave group chat not received",
|
"leave group chat not received",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1011,19 +1010,19 @@ func (s *MessengerSuite) TestReInvitedToGroupChat() {
|
||||||
// Retrieve their messages so that the chat is created
|
// Retrieve their messages so that the chat is created
|
||||||
response, err = WaitOnMessengerResponse(
|
response, err = WaitOnMessengerResponse(
|
||||||
theirMessenger,
|
theirMessenger,
|
||||||
func(r *MessengerResponse) bool { return len(r.Chats) > 0 },
|
func(r *MessengerResponse) bool { return len(r.Chats()) > 0 },
|
||||||
"chat invitation not received",
|
"chat invitation not received",
|
||||||
)
|
)
|
||||||
|
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
s.Require().True(response.Chats[0].Active)
|
s.Require().True(response.Chats()[0].Active)
|
||||||
s.Require().NoError(theirMessenger.Shutdown())
|
s.Require().NoError(theirMessenger.Shutdown())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *MessengerSuite) TestChatPersistencePublic() {
|
func (s *MessengerSuite) TestChatPersistencePublic() {
|
||||||
chat := Chat{
|
chat := &Chat{
|
||||||
ID: "chat-name",
|
ID: "chat-name",
|
||||||
Name: "chat-name",
|
Name: "chat-name",
|
||||||
Color: "#fffff",
|
Color: "#fffff",
|
||||||
|
@ -1036,19 +1035,18 @@ func (s *MessengerSuite) TestChatPersistencePublic() {
|
||||||
LastMessage: &common.Message{},
|
LastMessage: &common.Message{},
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Require().NoError(s.m.SaveChat(&chat))
|
s.Require().NoError(s.m.SaveChat(chat))
|
||||||
savedChats := s.m.Chats()
|
savedChats := s.m.Chats()
|
||||||
s.Require().Equal(1, len(savedChats))
|
s.Require().Equal(1, len(savedChats))
|
||||||
|
|
||||||
actualChat := savedChats[0]
|
actualChat := savedChats[0]
|
||||||
expectedChat := &chat
|
|
||||||
|
|
||||||
s.Require().Equal(actualChat, expectedChat)
|
s.Require().Equal(chat, actualChat)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *MessengerSuite) TestDeleteChat() {
|
func (s *MessengerSuite) TestDeleteChat() {
|
||||||
chatID := "chatid"
|
chatID := "chatid"
|
||||||
chat := Chat{
|
chat := &Chat{
|
||||||
ID: chatID,
|
ID: chatID,
|
||||||
Name: "chat-name",
|
Name: "chat-name",
|
||||||
Color: "#fffff",
|
Color: "#fffff",
|
||||||
|
@ -1061,7 +1059,7 @@ func (s *MessengerSuite) TestDeleteChat() {
|
||||||
LastMessage: &common.Message{},
|
LastMessage: &common.Message{},
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Require().NoError(s.m.SaveChat(&chat))
|
s.Require().NoError(s.m.SaveChat(chat))
|
||||||
savedChats := s.m.Chats()
|
savedChats := s.m.Chats()
|
||||||
s.Require().Equal(1, len(savedChats))
|
s.Require().Equal(1, len(savedChats))
|
||||||
|
|
||||||
|
@ -1071,7 +1069,7 @@ func (s *MessengerSuite) TestDeleteChat() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *MessengerSuite) TestChatPersistenceUpdate() {
|
func (s *MessengerSuite) TestChatPersistenceUpdate() {
|
||||||
chat := Chat{
|
chat := &Chat{
|
||||||
ID: "chat-name",
|
ID: "chat-name",
|
||||||
Name: "chat-name",
|
Name: "chat-name",
|
||||||
Color: "#fffff",
|
Color: "#fffff",
|
||||||
|
@ -1084,28 +1082,26 @@ func (s *MessengerSuite) TestChatPersistenceUpdate() {
|
||||||
LastMessage: &common.Message{},
|
LastMessage: &common.Message{},
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Require().NoError(s.m.SaveChat(&chat))
|
s.Require().NoError(s.m.SaveChat(chat))
|
||||||
savedChats := s.m.Chats()
|
savedChats := s.m.Chats()
|
||||||
s.Require().Equal(1, len(savedChats))
|
s.Require().Equal(1, len(savedChats))
|
||||||
|
|
||||||
actualChat := savedChats[0]
|
actualChat := savedChats[0]
|
||||||
expectedChat := &chat
|
|
||||||
|
|
||||||
s.Require().Equal(expectedChat, actualChat)
|
s.Require().Equal(chat, actualChat)
|
||||||
|
|
||||||
chat.Name = "updated-name-1"
|
chat.Name = "updated-name-1"
|
||||||
s.Require().NoError(s.m.SaveChat(&chat))
|
s.Require().NoError(s.m.SaveChat(chat))
|
||||||
updatedChats := s.m.Chats()
|
updatedChats := s.m.Chats()
|
||||||
s.Require().Equal(1, len(updatedChats))
|
s.Require().Equal(1, len(updatedChats))
|
||||||
|
|
||||||
actualUpdatedChat := updatedChats[0]
|
actualUpdatedChat := updatedChats[0]
|
||||||
expectedUpdatedChat := &chat
|
|
||||||
|
|
||||||
s.Require().Equal(expectedUpdatedChat, actualUpdatedChat)
|
s.Require().Equal(chat, actualUpdatedChat)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *MessengerSuite) TestChatPersistenceOneToOne() {
|
func (s *MessengerSuite) TestChatPersistenceOneToOne() {
|
||||||
chat := Chat{
|
chat := &Chat{
|
||||||
ID: testPK,
|
ID: testPK,
|
||||||
Name: testPK,
|
Name: testPK,
|
||||||
Color: "#fffff",
|
Color: "#fffff",
|
||||||
|
@ -1127,20 +1123,19 @@ func (s *MessengerSuite) TestChatPersistenceOneToOne() {
|
||||||
pk, err := crypto.UnmarshalPubkey(publicKeyBytes)
|
pk, err := crypto.UnmarshalPubkey(publicKeyBytes)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
s.Require().NoError(s.m.SaveChat(&chat))
|
s.Require().NoError(s.m.SaveChat(chat))
|
||||||
s.Require().NoError(s.m.SaveContact(&contact))
|
s.Require().NoError(s.m.SaveContact(&contact))
|
||||||
savedChats := s.m.Chats()
|
savedChats := s.m.Chats()
|
||||||
s.Require().Equal(1, len(savedChats))
|
s.Require().Equal(1, len(savedChats))
|
||||||
|
|
||||||
actualChat := savedChats[0]
|
actualChat := savedChats[0]
|
||||||
expectedChat := &chat
|
|
||||||
|
|
||||||
actualPk, err := actualChat.PublicKey()
|
actualPk, err := actualChat.PublicKey()
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
s.Require().Equal(pk, actualPk)
|
s.Require().Equal(pk, actualPk)
|
||||||
|
|
||||||
s.Require().Equal(expectedChat, actualChat)
|
s.Require().Equal(chat, actualChat)
|
||||||
s.Require().NotEmpty(actualChat.Identicon)
|
s.Require().NotEmpty(actualChat.Identicon)
|
||||||
s.Require().NotEmpty(actualChat.Alias)
|
s.Require().NotEmpty(actualChat.Alias)
|
||||||
}
|
}
|
||||||
|
@ -1159,7 +1154,7 @@ func (s *MessengerSuite) TestChatPersistencePrivateGroupChat() {
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
member3ID := types.EncodeHex(crypto.FromECDSAPub(&member3Key.PublicKey))
|
member3ID := types.EncodeHex(crypto.FromECDSAPub(&member3Key.PublicKey))
|
||||||
|
|
||||||
chat := Chat{
|
chat := &Chat{
|
||||||
ID: "chat-id",
|
ID: "chat-id",
|
||||||
Name: "chat-id",
|
Name: "chat-id",
|
||||||
Color: "#fffff",
|
Color: "#fffff",
|
||||||
|
@ -1206,14 +1201,13 @@ func (s *MessengerSuite) TestChatPersistencePrivateGroupChat() {
|
||||||
UnviewedMessagesCount: 40,
|
UnviewedMessagesCount: 40,
|
||||||
LastMessage: &common.Message{},
|
LastMessage: &common.Message{},
|
||||||
}
|
}
|
||||||
s.Require().NoError(s.m.SaveChat(&chat))
|
s.Require().NoError(s.m.SaveChat(chat))
|
||||||
savedChats := s.m.Chats()
|
savedChats := s.m.Chats()
|
||||||
s.Require().Equal(1, len(savedChats))
|
s.Require().Equal(1, len(savedChats))
|
||||||
|
|
||||||
actualChat := savedChats[0]
|
actualChat := savedChats[0]
|
||||||
expectedChat := &chat
|
|
||||||
|
|
||||||
s.Require().Equal(expectedChat, actualChat)
|
s.Require().Equal(chat, actualChat)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *MessengerSuite) TestBlockContact() {
|
func (s *MessengerSuite) TestBlockContact() {
|
||||||
|
@ -1234,10 +1228,9 @@ func (s *MessengerSuite) TestBlockContact() {
|
||||||
FCMToken: "token-2",
|
FCMToken: "token-2",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
TributeToTalk: "talk",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
chat1 := Chat{
|
chat1 := &Chat{
|
||||||
ID: contact.ID,
|
ID: contact.ID,
|
||||||
Name: "chat-name",
|
Name: "chat-name",
|
||||||
Color: "#fffff",
|
Color: "#fffff",
|
||||||
|
@ -1249,7 +1242,7 @@ func (s *MessengerSuite) TestBlockContact() {
|
||||||
UnviewedMessagesCount: 40,
|
UnviewedMessagesCount: 40,
|
||||||
}
|
}
|
||||||
|
|
||||||
chat2 := Chat{
|
chat2 := &Chat{
|
||||||
ID: "chat-2",
|
ID: "chat-2",
|
||||||
Name: "chat-name",
|
Name: "chat-name",
|
||||||
Color: "#fffff",
|
Color: "#fffff",
|
||||||
|
@ -1261,7 +1254,7 @@ func (s *MessengerSuite) TestBlockContact() {
|
||||||
UnviewedMessagesCount: 40,
|
UnviewedMessagesCount: 40,
|
||||||
}
|
}
|
||||||
|
|
||||||
chat3 := Chat{
|
chat3 := &Chat{
|
||||||
ID: "chat-3",
|
ID: "chat-3",
|
||||||
Name: "chat-name",
|
Name: "chat-name",
|
||||||
Color: "#fffff",
|
Color: "#fffff",
|
||||||
|
@ -1273,9 +1266,9 @@ func (s *MessengerSuite) TestBlockContact() {
|
||||||
UnviewedMessagesCount: 40,
|
UnviewedMessagesCount: 40,
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Require().NoError(s.m.SaveChat(&chat1))
|
s.Require().NoError(s.m.SaveChat(chat1))
|
||||||
s.Require().NoError(s.m.SaveChat(&chat2))
|
s.Require().NoError(s.m.SaveChat(chat2))
|
||||||
s.Require().NoError(s.m.SaveChat(&chat3))
|
s.Require().NoError(s.m.SaveChat(chat3))
|
||||||
|
|
||||||
s.Require().NoError(s.m.SaveContact(&contact))
|
s.Require().NoError(s.m.SaveContact(&contact))
|
||||||
|
|
||||||
|
@ -1416,7 +1409,6 @@ func (s *MessengerSuite) TestContactPersistence() {
|
||||||
FCMToken: "token-2",
|
FCMToken: "token-2",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
TributeToTalk: "talk",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Require().NoError(s.m.SaveContact(&contact))
|
s.Require().NoError(s.m.SaveContact(&contact))
|
||||||
|
@ -1450,7 +1442,6 @@ func (s *MessengerSuite) TestContactPersistenceUpdate() {
|
||||||
FCMToken: "token-2",
|
FCMToken: "token-2",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
TributeToTalk: "talk",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Require().NoError(s.m.SaveContact(&contact))
|
s.Require().NoError(s.m.SaveContact(&contact))
|
||||||
|
@ -1485,9 +1476,9 @@ func (s *MessengerSuite) TestCreateGroupChatWithMembers() {
|
||||||
members := []string{testPK}
|
members := []string{testPK}
|
||||||
response, err := s.m.CreateGroupChatWithMembers(context.Background(), "test", members)
|
response, err := s.m.CreateGroupChatWithMembers(context.Background(), "test", members)
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
|
|
||||||
chat := response.Chats[0]
|
chat := response.Chats()[0]
|
||||||
|
|
||||||
s.Require().Equal("test", chat.Name)
|
s.Require().Equal("test", chat.Name)
|
||||||
publicKeyHex := "0x" + hex.EncodeToString(crypto.FromECDSAPub(&s.m.identity.PublicKey))
|
publicKeyHex := "0x" + hex.EncodeToString(crypto.FromECDSAPub(&s.m.identity.PublicKey))
|
||||||
|
@ -1499,9 +1490,9 @@ func (s *MessengerSuite) TestCreateGroupChatWithMembers() {
|
||||||
func (s *MessengerSuite) TestAddMembersToChat() {
|
func (s *MessengerSuite) TestAddMembersToChat() {
|
||||||
response, err := s.m.CreateGroupChatWithMembers(context.Background(), "test", []string{})
|
response, err := s.m.CreateGroupChatWithMembers(context.Background(), "test", []string{})
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
|
|
||||||
chat := response.Chats[0]
|
chat := response.Chats()[0]
|
||||||
|
|
||||||
key, err := crypto.GenerateKey()
|
key, err := crypto.GenerateKey()
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
@ -1509,10 +1500,10 @@ func (s *MessengerSuite) TestAddMembersToChat() {
|
||||||
|
|
||||||
response, err = s.m.AddMembersToGroupChat(context.Background(), chat.ID, members)
|
response, err = s.m.AddMembersToGroupChat(context.Background(), chat.ID, members)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
s.Require().Len(response.Messages, 1)
|
s.Require().Len(response.Messages, 1)
|
||||||
|
|
||||||
chat = response.Chats[0]
|
chat = response.Chats()[0]
|
||||||
|
|
||||||
publicKeyHex := "0x" + hex.EncodeToString(crypto.FromECDSAPub(&s.m.identity.PublicKey))
|
publicKeyHex := "0x" + hex.EncodeToString(crypto.FromECDSAPub(&s.m.identity.PublicKey))
|
||||||
keyHex := "0x" + hex.EncodeToString(crypto.FromECDSAPub(&key.PublicKey))
|
keyHex := "0x" + hex.EncodeToString(crypto.FromECDSAPub(&key.PublicKey))
|
||||||
|
@ -1528,7 +1519,7 @@ func (s *MessengerSuite) TestDeclineRequestAddressForTransaction() {
|
||||||
theirPkString := types.EncodeHex(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey))
|
theirPkString := types.EncodeHex(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey))
|
||||||
|
|
||||||
chat := CreateOneToOneChat(theirPkString, &theirMessenger.identity.PublicKey, s.m.transport)
|
chat := CreateOneToOneChat(theirPkString, &theirMessenger.identity.PublicKey, s.m.transport)
|
||||||
err = s.m.SaveChat(&chat)
|
err = s.m.SaveChat(chat)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
myAddress := crypto.PubkeyToAddress(s.m.identity.PublicKey)
|
myAddress := crypto.PubkeyToAddress(s.m.identity.PublicKey)
|
||||||
|
@ -1536,7 +1527,7 @@ func (s *MessengerSuite) TestDeclineRequestAddressForTransaction() {
|
||||||
response, err := s.m.RequestAddressForTransaction(context.Background(), theirPkString, myAddress.Hex(), value, contract)
|
response, err := s.m.RequestAddressForTransaction(context.Background(), theirPkString, myAddress.Hex(), value, contract)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.Require().NotNil(response)
|
s.Require().NotNil(response)
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
s.Require().Len(response.Messages, 1)
|
s.Require().Len(response.Messages, 1)
|
||||||
|
|
||||||
senderMessage := response.Messages[0]
|
senderMessage := response.Messages[0]
|
||||||
|
@ -1559,7 +1550,7 @@ func (s *MessengerSuite) TestDeclineRequestAddressForTransaction() {
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
s.Require().NotNil(response)
|
s.Require().NotNil(response)
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
s.Require().Len(response.Messages, 1)
|
s.Require().Len(response.Messages, 1)
|
||||||
|
|
||||||
receiverMessage := response.Messages[0]
|
receiverMessage := response.Messages[0]
|
||||||
|
@ -1574,7 +1565,7 @@ func (s *MessengerSuite) TestDeclineRequestAddressForTransaction() {
|
||||||
// We decline the request
|
// We decline the request
|
||||||
response, err = theirMessenger.DeclineRequestAddressForTransaction(context.Background(), receiverMessage.ID)
|
response, err = theirMessenger.DeclineRequestAddressForTransaction(context.Background(), receiverMessage.ID)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
s.Require().Len(response.Messages, 1)
|
s.Require().Len(response.Messages, 1)
|
||||||
|
|
||||||
senderMessage = response.Messages[0]
|
senderMessage = response.Messages[0]
|
||||||
|
@ -1595,7 +1586,7 @@ func (s *MessengerSuite) TestDeclineRequestAddressForTransaction() {
|
||||||
)
|
)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
s.Require().Len(response.Messages, 1)
|
s.Require().Len(response.Messages, 1)
|
||||||
|
|
||||||
receiverMessage = response.Messages[0]
|
receiverMessage = response.Messages[0]
|
||||||
|
@ -1623,7 +1614,7 @@ func (s *MessengerSuite) TestSendEthTransaction() {
|
||||||
receiverAddressString := strings.ToLower(receiverAddress.Hex())
|
receiverAddressString := strings.ToLower(receiverAddress.Hex())
|
||||||
|
|
||||||
chat := CreateOneToOneChat(theirPkString, &theirMessenger.identity.PublicKey, s.m.transport)
|
chat := CreateOneToOneChat(theirPkString, &theirMessenger.identity.PublicKey, s.m.transport)
|
||||||
err = s.m.SaveChat(&chat)
|
err = s.m.SaveChat(chat)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
transactionHash := testTransactionHash
|
transactionHash := testTransactionHash
|
||||||
|
@ -1633,7 +1624,7 @@ func (s *MessengerSuite) TestSendEthTransaction() {
|
||||||
response, err := s.m.SendTransaction(context.Background(), theirPkString, value, contract, transactionHash, signature)
|
response, err := s.m.SendTransaction(context.Background(), theirPkString, value, contract, transactionHash, signature)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.Require().NotNil(response)
|
s.Require().NotNil(response)
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
s.Require().Len(response.Messages, 1)
|
s.Require().Len(response.Messages, 1)
|
||||||
|
|
||||||
senderMessage := response.Messages[0]
|
senderMessage := response.Messages[0]
|
||||||
|
@ -1695,7 +1686,7 @@ func (s *MessengerSuite) TestSendEthTransaction() {
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
s.Require().NotNil(response)
|
s.Require().NotNil(response)
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
s.Require().Len(response.Messages, 1)
|
s.Require().Len(response.Messages, 1)
|
||||||
|
|
||||||
receiverMessage := response.Messages[0]
|
receiverMessage := response.Messages[0]
|
||||||
|
@ -1727,7 +1718,7 @@ func (s *MessengerSuite) TestSendTokenTransaction() {
|
||||||
receiverAddressString := strings.ToLower(receiverAddress.Hex())
|
receiverAddressString := strings.ToLower(receiverAddress.Hex())
|
||||||
|
|
||||||
chat := CreateOneToOneChat(theirPkString, &theirMessenger.identity.PublicKey, s.m.transport)
|
chat := CreateOneToOneChat(theirPkString, &theirMessenger.identity.PublicKey, s.m.transport)
|
||||||
err = s.m.SaveChat(&chat)
|
err = s.m.SaveChat(chat)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
transactionHash := testTransactionHash
|
transactionHash := testTransactionHash
|
||||||
|
@ -1737,7 +1728,7 @@ func (s *MessengerSuite) TestSendTokenTransaction() {
|
||||||
response, err := s.m.SendTransaction(context.Background(), theirPkString, value, contract, transactionHash, signature)
|
response, err := s.m.SendTransaction(context.Background(), theirPkString, value, contract, transactionHash, signature)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.Require().NotNil(response)
|
s.Require().NotNil(response)
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
s.Require().Len(response.Messages, 1)
|
s.Require().Len(response.Messages, 1)
|
||||||
|
|
||||||
senderMessage := response.Messages[0]
|
senderMessage := response.Messages[0]
|
||||||
|
@ -1799,7 +1790,7 @@ func (s *MessengerSuite) TestSendTokenTransaction() {
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
s.Require().NotNil(response)
|
s.Require().NotNil(response)
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
s.Require().Len(response.Messages, 1)
|
s.Require().Len(response.Messages, 1)
|
||||||
|
|
||||||
receiverMessage := response.Messages[0]
|
receiverMessage := response.Messages[0]
|
||||||
|
@ -1829,13 +1820,13 @@ func (s *MessengerSuite) TestAcceptRequestAddressForTransaction() {
|
||||||
myAddress := crypto.PubkeyToAddress(s.m.identity.PublicKey)
|
myAddress := crypto.PubkeyToAddress(s.m.identity.PublicKey)
|
||||||
|
|
||||||
chat := CreateOneToOneChat(theirPkString, &theirMessenger.identity.PublicKey, s.m.transport)
|
chat := CreateOneToOneChat(theirPkString, &theirMessenger.identity.PublicKey, s.m.transport)
|
||||||
err = s.m.SaveChat(&chat)
|
err = s.m.SaveChat(chat)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
response, err := s.m.RequestAddressForTransaction(context.Background(), theirPkString, myAddress.Hex(), value, contract)
|
response, err := s.m.RequestAddressForTransaction(context.Background(), theirPkString, myAddress.Hex(), value, contract)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.Require().NotNil(response)
|
s.Require().NotNil(response)
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
s.Require().Len(response.Messages, 1)
|
s.Require().Len(response.Messages, 1)
|
||||||
|
|
||||||
senderMessage := response.Messages[0]
|
senderMessage := response.Messages[0]
|
||||||
|
@ -1858,7 +1849,7 @@ func (s *MessengerSuite) TestAcceptRequestAddressForTransaction() {
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
s.Require().NotNil(response)
|
s.Require().NotNil(response)
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
s.Require().Len(response.Messages, 1)
|
s.Require().Len(response.Messages, 1)
|
||||||
|
|
||||||
receiverMessage := response.Messages[0]
|
receiverMessage := response.Messages[0]
|
||||||
|
@ -1873,7 +1864,7 @@ func (s *MessengerSuite) TestAcceptRequestAddressForTransaction() {
|
||||||
// We accept the request
|
// We accept the request
|
||||||
response, err = theirMessenger.AcceptRequestAddressForTransaction(context.Background(), receiverMessage.ID, "some-address")
|
response, err = theirMessenger.AcceptRequestAddressForTransaction(context.Background(), receiverMessage.ID, "some-address")
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
s.Require().Len(response.Messages, 1)
|
s.Require().Len(response.Messages, 1)
|
||||||
|
|
||||||
senderMessage = response.Messages[0]
|
senderMessage = response.Messages[0]
|
||||||
|
@ -1895,7 +1886,7 @@ func (s *MessengerSuite) TestAcceptRequestAddressForTransaction() {
|
||||||
)
|
)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
s.Require().Len(response.Messages, 1)
|
s.Require().Len(response.Messages, 1)
|
||||||
|
|
||||||
receiverMessage = response.Messages[0]
|
receiverMessage = response.Messages[0]
|
||||||
|
@ -1922,13 +1913,13 @@ func (s *MessengerSuite) TestDeclineRequestTransaction() {
|
||||||
theirPkString := types.EncodeHex(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey))
|
theirPkString := types.EncodeHex(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey))
|
||||||
|
|
||||||
chat := CreateOneToOneChat(theirPkString, &theirMessenger.identity.PublicKey, s.m.transport)
|
chat := CreateOneToOneChat(theirPkString, &theirMessenger.identity.PublicKey, s.m.transport)
|
||||||
err = s.m.SaveChat(&chat)
|
err = s.m.SaveChat(chat)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
response, err := s.m.RequestTransaction(context.Background(), theirPkString, value, contract, receiverAddressString)
|
response, err := s.m.RequestTransaction(context.Background(), theirPkString, value, contract, receiverAddressString)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.Require().NotNil(response)
|
s.Require().NotNil(response)
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
s.Require().Len(response.Messages, 1)
|
s.Require().Len(response.Messages, 1)
|
||||||
|
|
||||||
senderMessage := response.Messages[0]
|
senderMessage := response.Messages[0]
|
||||||
|
@ -1952,7 +1943,7 @@ func (s *MessengerSuite) TestDeclineRequestTransaction() {
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
s.Require().NotNil(response)
|
s.Require().NotNil(response)
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
s.Require().Len(response.Messages, 1)
|
s.Require().Len(response.Messages, 1)
|
||||||
|
|
||||||
receiverMessage := response.Messages[0]
|
receiverMessage := response.Messages[0]
|
||||||
|
@ -1968,7 +1959,7 @@ func (s *MessengerSuite) TestDeclineRequestTransaction() {
|
||||||
response, err = theirMessenger.DeclineRequestTransaction(context.Background(), initialCommandID)
|
response, err = theirMessenger.DeclineRequestTransaction(context.Background(), initialCommandID)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.Require().NotNil(response)
|
s.Require().NotNil(response)
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
s.Require().Len(response.Messages, 1)
|
s.Require().Len(response.Messages, 1)
|
||||||
|
|
||||||
senderMessage = response.Messages[0]
|
senderMessage = response.Messages[0]
|
||||||
|
@ -1988,7 +1979,7 @@ func (s *MessengerSuite) TestDeclineRequestTransaction() {
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
s.Require().NotNil(response)
|
s.Require().NotNil(response)
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
s.Require().Len(response.Messages, 1)
|
s.Require().Len(response.Messages, 1)
|
||||||
|
|
||||||
receiverMessage = response.Messages[0]
|
receiverMessage = response.Messages[0]
|
||||||
|
@ -2012,13 +2003,13 @@ func (s *MessengerSuite) TestRequestTransaction() {
|
||||||
theirPkString := types.EncodeHex(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey))
|
theirPkString := types.EncodeHex(crypto.FromECDSAPub(&theirMessenger.identity.PublicKey))
|
||||||
|
|
||||||
chat := CreateOneToOneChat(theirPkString, &theirMessenger.identity.PublicKey, s.m.transport)
|
chat := CreateOneToOneChat(theirPkString, &theirMessenger.identity.PublicKey, s.m.transport)
|
||||||
err = s.m.SaveChat(&chat)
|
err = s.m.SaveChat(chat)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
response, err := s.m.RequestTransaction(context.Background(), theirPkString, value, contract, receiverAddressString)
|
response, err := s.m.RequestTransaction(context.Background(), theirPkString, value, contract, receiverAddressString)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.Require().NotNil(response)
|
s.Require().NotNil(response)
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
s.Require().Len(response.Messages, 1)
|
s.Require().Len(response.Messages, 1)
|
||||||
|
|
||||||
senderMessage := response.Messages[0]
|
senderMessage := response.Messages[0]
|
||||||
|
@ -2042,7 +2033,7 @@ func (s *MessengerSuite) TestRequestTransaction() {
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
s.Require().NotNil(response)
|
s.Require().NotNil(response)
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
s.Require().Len(response.Messages, 1)
|
s.Require().Len(response.Messages, 1)
|
||||||
|
|
||||||
receiverMessage := response.Messages[0]
|
receiverMessage := response.Messages[0]
|
||||||
|
@ -2061,7 +2052,7 @@ func (s *MessengerSuite) TestRequestTransaction() {
|
||||||
response, err = theirMessenger.AcceptRequestTransaction(context.Background(), transactionHash, initialCommandID, signature)
|
response, err = theirMessenger.AcceptRequestTransaction(context.Background(), transactionHash, initialCommandID, signature)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.Require().NotNil(response)
|
s.Require().NotNil(response)
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
s.Require().Len(response.Messages, 1)
|
s.Require().Len(response.Messages, 1)
|
||||||
|
|
||||||
senderMessage = response.Messages[0]
|
senderMessage = response.Messages[0]
|
||||||
|
@ -2128,7 +2119,7 @@ func (s *MessengerSuite) TestRequestTransaction() {
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
s.Require().NotNil(response)
|
s.Require().NotNil(response)
|
||||||
s.Require().Len(response.Chats, 1)
|
s.Require().Len(response.Chats(), 1)
|
||||||
s.Require().Len(response.Messages, 1)
|
s.Require().Len(response.Messages, 1)
|
||||||
|
|
||||||
receiverMessage = response.Messages[0]
|
receiverMessage = response.Messages[0]
|
||||||
|
@ -2225,9 +2216,9 @@ func (s *MessengerSuite) TestSentEventTracking() {
|
||||||
|
|
||||||
//when message sent, its sent field should be "false" until we got confirmation
|
//when message sent, its sent field should be "false" until we got confirmation
|
||||||
chat := CreatePublicChat("test-chat", s.m.transport)
|
chat := CreatePublicChat("test-chat", s.m.transport)
|
||||||
err := s.m.SaveChat(&chat)
|
err := s.m.SaveChat(chat)
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
inputMessage := buildTestMessage(chat)
|
inputMessage := buildTestMessage(*chat)
|
||||||
|
|
||||||
_, err = s.m.SendChatMessage(context.Background(), inputMessage)
|
_, err = s.m.SendChatMessage(context.Background(), inputMessage)
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
|
@ -2248,9 +2239,9 @@ func (s *MessengerSuite) TestSentEventTracking() {
|
||||||
func (s *MessengerSuite) TestLastSentField() {
|
func (s *MessengerSuite) TestLastSentField() {
|
||||||
//send message
|
//send message
|
||||||
chat := CreatePublicChat("test-chat", s.m.transport)
|
chat := CreatePublicChat("test-chat", s.m.transport)
|
||||||
err := s.m.SaveChat(&chat)
|
err := s.m.SaveChat(chat)
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
inputMessage := buildTestMessage(chat)
|
inputMessage := buildTestMessage(*chat)
|
||||||
|
|
||||||
_, err = s.m.SendChatMessage(context.Background(), inputMessage)
|
_, err = s.m.SendChatMessage(context.Background(), inputMessage)
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
|
@ -2335,9 +2326,9 @@ func (s *MessengerSuite) TestShouldResendEmoji() {
|
||||||
func (s *MessengerSuite) TestMessageSent() {
|
func (s *MessengerSuite) TestMessageSent() {
|
||||||
//send message
|
//send message
|
||||||
chat := CreatePublicChat("test-chat", s.m.transport)
|
chat := CreatePublicChat("test-chat", s.m.transport)
|
||||||
err := s.m.SaveChat(&chat)
|
err := s.m.SaveChat(chat)
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
inputMessage := buildTestMessage(chat)
|
inputMessage := buildTestMessage(*chat)
|
||||||
|
|
||||||
_, err = s.m.SendChatMessage(context.Background(), inputMessage)
|
_, err = s.m.SendChatMessage(context.Background(), inputMessage)
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
|
@ -2360,9 +2351,9 @@ func (s *MessengerSuite) TestMessageSent() {
|
||||||
func (s *MessengerSuite) TestResendExpiredEmojis() {
|
func (s *MessengerSuite) TestResendExpiredEmojis() {
|
||||||
//send message
|
//send message
|
||||||
chat := CreatePublicChat("test-chat", s.m.transport)
|
chat := CreatePublicChat("test-chat", s.m.transport)
|
||||||
err := s.m.SaveChat(&chat)
|
err := s.m.SaveChat(chat)
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
inputMessage := buildTestMessage(chat)
|
inputMessage := buildTestMessage(*chat)
|
||||||
|
|
||||||
_, err = s.m.SendChatMessage(context.Background(), inputMessage)
|
_, err = s.m.SendChatMessage(context.Background(), inputMessage)
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
|
@ -2431,7 +2422,7 @@ func (s *MessageHandlerSuite) TestRun() {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
Name string
|
Name string
|
||||||
Error bool
|
Error bool
|
||||||
Chat Chat // Chat to create
|
Chat *Chat // Chat to create
|
||||||
Message common.Message
|
Message common.Message
|
||||||
SigPubKey *ecdsa.PublicKey
|
SigPubKey *ecdsa.PublicKey
|
||||||
ExpectedChatID string
|
ExpectedChatID string
|
||||||
|
@ -2518,8 +2509,8 @@ func (s *MessageHandlerSuite) TestRun() {
|
||||||
for idx, tc := range testCases {
|
for idx, tc := range testCases {
|
||||||
s.Run(tc.Name, func() {
|
s.Run(tc.Name, func() {
|
||||||
chatsMap := make(map[string]*Chat)
|
chatsMap := make(map[string]*Chat)
|
||||||
if tc.Chat.ID != "" {
|
if tc.Chat != nil && tc.Chat.ID != "" {
|
||||||
chatsMap[tc.Chat.ID] = &tc.Chat
|
chatsMap[tc.Chat.ID] = tc.Chat
|
||||||
}
|
}
|
||||||
|
|
||||||
message := tc.Message
|
message := tc.Message
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
// 1610959908_add_dont_wrap_to_raw_messages.up.sql (83B)
|
// 1610959908_add_dont_wrap_to_raw_messages.up.sql (83B)
|
||||||
// 1610960912_add_send_on_personal_topic.up.sql (82B)
|
// 1610960912_add_send_on_personal_topic.up.sql (82B)
|
||||||
// 1612870480_add_datasync_id.up.sql (111B)
|
// 1612870480_add_datasync_id.up.sql (111B)
|
||||||
|
// 1614152139_add_communities_request_to_join.up.sql (831B)
|
||||||
// README.md (554B)
|
// README.md (554B)
|
||||||
// doc.go (850B)
|
// doc.go (850B)
|
||||||
|
|
||||||
|
@ -45,7 +46,7 @@ import (
|
||||||
func bindataRead(data []byte, name string) ([]byte, error) {
|
func bindataRead(data []byte, name string) ([]byte, error) {
|
||||||
gz, err := gzip.NewReader(bytes.NewBuffer(data))
|
gz, err := gzip.NewReader(bytes.NewBuffer(data))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("read %q: %w", name, err)
|
return nil, fmt.Errorf("read %q: %v", name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
|
@ -53,7 +54,7 @@ func bindataRead(data []byte, name string) ([]byte, error) {
|
||||||
clErr := gz.Close()
|
clErr := gz.Close()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("read %q: %w", name, err)
|
return nil, fmt.Errorf("read %q: %v", name, err)
|
||||||
}
|
}
|
||||||
if clErr != nil {
|
if clErr != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -109,7 +110,7 @@ func _000001_initDownDbSql() (*asset, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
info := bindataFileInfo{name: "000001_init.down.db.sql", size: 65, mode: os.FileMode(0644), modTime: time.Unix(1608547984, 0)}
|
info := bindataFileInfo{name: "000001_init.down.db.sql", size: 65, mode: os.FileMode(0644), modTime: time.Unix(1610007618, 0)}
|
||||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x5e, 0xbb, 0x3f, 0x1, 0x75, 0x19, 0x70, 0x86, 0xa7, 0x34, 0x40, 0x17, 0x34, 0x3e, 0x18, 0x51, 0x79, 0xd4, 0x22, 0xad, 0x8f, 0x80, 0xcc, 0xa6, 0xcc, 0x6, 0x2b, 0x62, 0x2, 0x47, 0xba, 0xf9}}
|
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x5e, 0xbb, 0x3f, 0x1, 0x75, 0x19, 0x70, 0x86, 0xa7, 0x34, 0x40, 0x17, 0x34, 0x3e, 0x18, 0x51, 0x79, 0xd4, 0x22, 0xad, 0x8f, 0x80, 0xcc, 0xa6, 0xcc, 0x6, 0x2b, 0x62, 0x2, 0x47, 0xba, 0xf9}}
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
@ -129,7 +130,7 @@ func _000001_initUpDbSql() (*asset, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
info := bindataFileInfo{name: "000001_init.up.db.sql", size: 2719, mode: os.FileMode(0644), modTime: time.Unix(1608547984, 0)}
|
info := bindataFileInfo{name: "000001_init.up.db.sql", size: 2719, mode: os.FileMode(0644), modTime: time.Unix(1610007618, 0)}
|
||||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x60, 0xdc, 0xeb, 0xe, 0xc2, 0x4f, 0x75, 0xa, 0xf6, 0x3e, 0xc7, 0xc4, 0x4, 0xe2, 0xe1, 0xa4, 0x73, 0x2f, 0x4a, 0xad, 0x1a, 0x0, 0xc3, 0x93, 0x9d, 0x77, 0x3e, 0x31, 0x91, 0x77, 0x2e, 0xc8}}
|
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x60, 0xdc, 0xeb, 0xe, 0xc2, 0x4f, 0x75, 0xa, 0xf6, 0x3e, 0xc7, 0xc4, 0x4, 0xe2, 0xe1, 0xa4, 0x73, 0x2f, 0x4a, 0xad, 0x1a, 0x0, 0xc3, 0x93, 0x9d, 0x77, 0x3e, 0x31, 0x91, 0x77, 0x2e, 0xc8}}
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
@ -149,7 +150,7 @@ func _000002_add_last_ens_clock_valueUpSql() (*asset, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
info := bindataFileInfo{name: "000002_add_last_ens_clock_value.up.sql", size: 77, mode: os.FileMode(0644), modTime: time.Unix(1608547984, 0)}
|
info := bindataFileInfo{name: "000002_add_last_ens_clock_value.up.sql", size: 77, mode: os.FileMode(0644), modTime: time.Unix(1610007618, 0)}
|
||||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x4d, 0x3, 0x8f, 0xd5, 0x85, 0x83, 0x47, 0xbe, 0xf9, 0x82, 0x7e, 0x81, 0xa4, 0xbd, 0xaa, 0xd5, 0x98, 0x18, 0x5, 0x2d, 0x82, 0x42, 0x3b, 0x3, 0x50, 0xc3, 0x1e, 0x84, 0x35, 0xf, 0xb6, 0x2b}}
|
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x4d, 0x3, 0x8f, 0xd5, 0x85, 0x83, 0x47, 0xbe, 0xf9, 0x82, 0x7e, 0x81, 0xa4, 0xbd, 0xaa, 0xd5, 0x98, 0x18, 0x5, 0x2d, 0x82, 0x42, 0x3b, 0x3, 0x50, 0xc3, 0x1e, 0x84, 0x35, 0xf, 0xb6, 0x2b}}
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
@ -169,7 +170,7 @@ func _1586358095_add_replaceUpSql() (*asset, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
info := bindataFileInfo{name: "1586358095_add_replace.up.sql", size: 224, mode: os.FileMode(0644), modTime: time.Unix(1608547984, 0)}
|
info := bindataFileInfo{name: "1586358095_add_replace.up.sql", size: 224, mode: os.FileMode(0644), modTime: time.Unix(1611588719, 0)}
|
||||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd2, 0xb3, 0xa9, 0xc7, 0x7f, 0x9d, 0x8f, 0x43, 0x8c, 0x9e, 0x58, 0x8d, 0x44, 0xbc, 0xfa, 0x6b, 0x5f, 0x3f, 0x5a, 0xbe, 0xe8, 0xb1, 0x16, 0xf, 0x91, 0x2a, 0xa0, 0x71, 0xbb, 0x8d, 0x6b, 0xcb}}
|
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd2, 0xb3, 0xa9, 0xc7, 0x7f, 0x9d, 0x8f, 0x43, 0x8c, 0x9e, 0x58, 0x8d, 0x44, 0xbc, 0xfa, 0x6b, 0x5f, 0x3f, 0x5a, 0xbe, 0xe8, 0xb1, 0x16, 0xf, 0x91, 0x2a, 0xa0, 0x71, 0xbb, 0x8d, 0x6b, 0xcb}}
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
@ -189,7 +190,7 @@ func _1588665364_add_image_dataUpSql() (*asset, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
info := bindataFileInfo{name: "1588665364_add_image_data.up.sql", size: 186, mode: os.FileMode(0644), modTime: time.Unix(1608547984, 0)}
|
info := bindataFileInfo{name: "1588665364_add_image_data.up.sql", size: 186, mode: os.FileMode(0644), modTime: time.Unix(1611588719, 0)}
|
||||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd6, 0xc6, 0x35, 0xb4, 0x4c, 0x39, 0x96, 0x29, 0x30, 0xda, 0xf4, 0x8f, 0xcb, 0xf1, 0x9f, 0x84, 0xdc, 0x88, 0xd4, 0xd5, 0xbc, 0xb6, 0x5b, 0x46, 0x78, 0x67, 0x76, 0x1a, 0x5, 0x36, 0xdc, 0xe5}}
|
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd6, 0xc6, 0x35, 0xb4, 0x4c, 0x39, 0x96, 0x29, 0x30, 0xda, 0xf4, 0x8f, 0xcb, 0xf1, 0x9f, 0x84, 0xdc, 0x88, 0xd4, 0xd5, 0xbc, 0xb6, 0x5b, 0x46, 0x78, 0x67, 0x76, 0x1a, 0x5, 0x36, 0xdc, 0xe5}}
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
@ -209,7 +210,7 @@ func _1589365189_add_pow_targetUpSql() (*asset, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
info := bindataFileInfo{name: "1589365189_add_pow_target.up.sql", size: 66, mode: os.FileMode(0644), modTime: time.Unix(1608547984, 0)}
|
info := bindataFileInfo{name: "1589365189_add_pow_target.up.sql", size: 66, mode: os.FileMode(0644), modTime: time.Unix(1611588719, 0)}
|
||||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x4e, 0x3a, 0xe2, 0x2e, 0x7d, 0xaf, 0xbb, 0xcc, 0x21, 0xa1, 0x7a, 0x41, 0x9a, 0xd0, 0xbb, 0xa9, 0xc8, 0x35, 0xf9, 0x32, 0x34, 0x46, 0x44, 0x9a, 0x86, 0x40, 0x7c, 0xb9, 0x23, 0xc7, 0x3, 0x3f}}
|
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x4e, 0x3a, 0xe2, 0x2e, 0x7d, 0xaf, 0xbb, 0xcc, 0x21, 0xa1, 0x7a, 0x41, 0x9a, 0xd0, 0xbb, 0xa9, 0xc8, 0x35, 0xf9, 0x32, 0x34, 0x46, 0x44, 0x9a, 0x86, 0x40, 0x7c, 0xb9, 0x23, 0xc7, 0x3, 0x3f}}
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
@ -229,7 +230,7 @@ func _1591277220_add_index_messagesUpSql() (*asset, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
info := bindataFileInfo{name: "1591277220_add_index_messages.up.sql", size: 240, mode: os.FileMode(0644), modTime: time.Unix(1608547984, 0)}
|
info := bindataFileInfo{name: "1591277220_add_index_messages.up.sql", size: 240, mode: os.FileMode(0644), modTime: time.Unix(1614068874, 0)}
|
||||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x9c, 0xfe, 0xbe, 0xd5, 0xb8, 0x8f, 0xdd, 0xef, 0xbb, 0xa8, 0xad, 0x7f, 0xed, 0x5b, 0x5b, 0x2f, 0xe6, 0x82, 0x27, 0x78, 0x1f, 0xb9, 0x57, 0xdc, 0x8, 0xc2, 0xb2, 0xa9, 0x9a, 0x4, 0xe1, 0x7a}}
|
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x9c, 0xfe, 0xbe, 0xd5, 0xb8, 0x8f, 0xdd, 0xef, 0xbb, 0xa8, 0xad, 0x7f, 0xed, 0x5b, 0x5b, 0x2f, 0xe6, 0x82, 0x27, 0x78, 0x1f, 0xb9, 0x57, 0xdc, 0x8, 0xc2, 0xb2, 0xa9, 0x9a, 0x4, 0xe1, 0x7a}}
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
@ -249,7 +250,7 @@ func _1593087212_add_mute_chat_and_raw_message_fieldsUpSql() (*asset, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
info := bindataFileInfo{name: "1593087212_add_mute_chat_and_raw_message_fields.up.sql", size: 215, mode: os.FileMode(0644), modTime: time.Unix(1608547984, 0)}
|
info := bindataFileInfo{name: "1593087212_add_mute_chat_and_raw_message_fields.up.sql", size: 215, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)}
|
||||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x73, 0x99, 0x61, 0xd1, 0xaa, 0xb4, 0xbf, 0xaf, 0xd7, 0x20, 0x17, 0x40, 0xf9, 0x2, 0xfb, 0xcc, 0x40, 0x2a, 0xd, 0x86, 0x36, 0x30, 0x88, 0x89, 0x25, 0x80, 0x42, 0xb0, 0x5b, 0xe9, 0x73, 0x78}}
|
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x73, 0x99, 0x61, 0xd1, 0xaa, 0xb4, 0xbf, 0xaf, 0xd7, 0x20, 0x17, 0x40, 0xf9, 0x2, 0xfb, 0xcc, 0x40, 0x2a, 0xd, 0x86, 0x36, 0x30, 0x88, 0x89, 0x25, 0x80, 0x42, 0xb0, 0x5b, 0xe9, 0x73, 0x78}}
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
@ -269,7 +270,7 @@ func _1595862781_add_audio_dataUpSql() (*asset, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
info := bindataFileInfo{name: "1595862781_add_audio_data.up.sql", size: 246, mode: os.FileMode(0644), modTime: time.Unix(1608547984, 0)}
|
info := bindataFileInfo{name: "1595862781_add_audio_data.up.sql", size: 246, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)}
|
||||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xae, 0xd2, 0xee, 0x55, 0xfb, 0x36, 0xa4, 0x92, 0x66, 0xe, 0x81, 0x62, 0x1e, 0x7a, 0x69, 0xa, 0xd5, 0x4b, 0xa5, 0x6a, 0x8d, 0x1d, 0xce, 0xf3, 0x3e, 0xc0, 0x5f, 0x9c, 0x66, 0x1b, 0xb4, 0xed}}
|
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xae, 0xd2, 0xee, 0x55, 0xfb, 0x36, 0xa4, 0x92, 0x66, 0xe, 0x81, 0x62, 0x1e, 0x7a, 0x69, 0xa, 0xd5, 0x4b, 0xa5, 0x6a, 0x8d, 0x1d, 0xce, 0xf3, 0x3e, 0xc0, 0x5f, 0x9c, 0x66, 0x1b, 0xb4, 0xed}}
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
@ -289,7 +290,7 @@ func _1595865249_create_emoji_reactions_tableUpSql() (*asset, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
info := bindataFileInfo{name: "1595865249_create_emoji_reactions_table.up.sql", size: 300, mode: os.FileMode(0644), modTime: time.Unix(1608547984, 0)}
|
info := bindataFileInfo{name: "1595865249_create_emoji_reactions_table.up.sql", size: 300, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)}
|
||||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x3e, 0xc5, 0x43, 0x5c, 0x3d, 0x53, 0x43, 0x2c, 0x1a, 0xa5, 0xb6, 0xbf, 0x7, 0x4, 0x5a, 0x3e, 0x40, 0x8b, 0xa4, 0x57, 0x12, 0x58, 0xbc, 0x42, 0xe2, 0xc3, 0xde, 0x76, 0x98, 0x80, 0xe2, 0xbe}}
|
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x3e, 0xc5, 0x43, 0x5c, 0x3d, 0x53, 0x43, 0x2c, 0x1a, 0xa5, 0xb6, 0xbf, 0x7, 0x4, 0x5a, 0x3e, 0x40, 0x8b, 0xa4, 0x57, 0x12, 0x58, 0xbc, 0x42, 0xe2, 0xc3, 0xde, 0x76, 0x98, 0x80, 0xe2, 0xbe}}
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
@ -309,7 +310,7 @@ func _1596805115_create_group_chat_invitations_tableUpSql() (*asset, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
info := bindataFileInfo{name: "1596805115_create_group_chat_invitations_table.up.sql", size: 231, mode: os.FileMode(0644), modTime: time.Unix(1608547984, 0)}
|
info := bindataFileInfo{name: "1596805115_create_group_chat_invitations_table.up.sql", size: 231, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)}
|
||||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x6d, 0xb1, 0x14, 0x6d, 0x54, 0x28, 0x67, 0xc3, 0x23, 0x6a, 0xfc, 0x80, 0xdf, 0x9e, 0x4c, 0x35, 0x36, 0xf, 0xf8, 0xf3, 0x5f, 0xae, 0xad, 0xb, 0xc1, 0x51, 0x8e, 0x17, 0x7, 0xe5, 0x7f, 0x91}}
|
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x6d, 0xb1, 0x14, 0x6d, 0x54, 0x28, 0x67, 0xc3, 0x23, 0x6a, 0xfc, 0x80, 0xdf, 0x9e, 0x4c, 0x35, 0x36, 0xf, 0xf8, 0xf3, 0x5f, 0xae, 0xad, 0xb, 0xc1, 0x51, 0x8e, 0x17, 0x7, 0xe5, 0x7f, 0x91}}
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
@ -329,7 +330,7 @@ func _1597322655_add_invitation_admin_chat_fieldUpSql() (*asset, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
info := bindataFileInfo{name: "1597322655_add_invitation_admin_chat_field.up.sql", size: 54, mode: os.FileMode(0644), modTime: time.Unix(1608547984, 0)}
|
info := bindataFileInfo{name: "1597322655_add_invitation_admin_chat_field.up.sql", size: 54, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)}
|
||||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xa9, 0x7a, 0xa0, 0xf2, 0xdb, 0x13, 0x91, 0x91, 0xa8, 0x34, 0x1a, 0xa1, 0x49, 0x68, 0xd5, 0xae, 0x2c, 0xd8, 0xd5, 0xea, 0x8f, 0x8c, 0xc7, 0x2, 0x4e, 0x58, 0x2c, 0x3a, 0x14, 0xd4, 0x4f, 0x2c}}
|
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xa9, 0x7a, 0xa0, 0xf2, 0xdb, 0x13, 0x91, 0x91, 0xa8, 0x34, 0x1a, 0xa1, 0x49, 0x68, 0xd5, 0xae, 0x2c, 0xd8, 0xd5, 0xea, 0x8f, 0x8c, 0xc7, 0x2, 0x4e, 0x58, 0x2c, 0x3a, 0x14, 0xd4, 0x4f, 0x2c}}
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
@ -349,7 +350,7 @@ func _1597757544_add_nicknameUpSql() (*asset, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
info := bindataFileInfo{name: "1597757544_add_nickname.up.sql", size: 52, mode: os.FileMode(0644), modTime: time.Unix(1608547984, 0)}
|
info := bindataFileInfo{name: "1597757544_add_nickname.up.sql", size: 52, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)}
|
||||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf4, 0xa2, 0x64, 0x50, 0xc5, 0x4, 0xb9, 0x8b, 0xd1, 0x18, 0x9b, 0xc3, 0x91, 0x36, 0x2a, 0x1f, 0xc3, 0x6c, 0x2d, 0x92, 0xf8, 0x5e, 0xff, 0xb1, 0x59, 0x61, 0x2, 0x1c, 0xe1, 0x85, 0x90, 0xa4}}
|
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf4, 0xa2, 0x64, 0x50, 0xc5, 0x4, 0xb9, 0x8b, 0xd1, 0x18, 0x9b, 0xc3, 0x91, 0x36, 0x2a, 0x1f, 0xc3, 0x6c, 0x2d, 0x92, 0xf8, 0x5e, 0xff, 0xb1, 0x59, 0x61, 0x2, 0x1c, 0xe1, 0x85, 0x90, 0xa4}}
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
@ -369,7 +370,7 @@ func _1598955122_add_mentionsUpSql() (*asset, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
info := bindataFileInfo{name: "1598955122_add_mentions.up.sql", size: 52, mode: os.FileMode(0644), modTime: time.Unix(1608547984, 0)}
|
info := bindataFileInfo{name: "1598955122_add_mentions.up.sql", size: 52, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)}
|
||||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x8d, 0x22, 0x17, 0x92, 0xd2, 0x11, 0x4e, 0x7, 0x93, 0x9a, 0x55, 0xfd, 0xb, 0x97, 0xc4, 0x63, 0x6a, 0x81, 0x97, 0xcd, 0xb2, 0xf8, 0x4b, 0x5f, 0x3c, 0xfa, 0x3a, 0x38, 0x53, 0x10, 0xed, 0x9d}}
|
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x8d, 0x22, 0x17, 0x92, 0xd2, 0x11, 0x4e, 0x7, 0x93, 0x9a, 0x55, 0xfd, 0xb, 0x97, 0xc4, 0x63, 0x6a, 0x81, 0x97, 0xcd, 0xb2, 0xf8, 0x4b, 0x5f, 0x3c, 0xfa, 0x3a, 0x38, 0x53, 0x10, 0xed, 0x9d}}
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
@ -389,7 +390,7 @@ func _1599641390_add_emoji_reactions_indexUpSql() (*asset, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
info := bindataFileInfo{name: "1599641390_add_emoji_reactions_index.up.sql", size: 126, mode: os.FileMode(0644), modTime: time.Unix(1608547984, 0)}
|
info := bindataFileInfo{name: "1599641390_add_emoji_reactions_index.up.sql", size: 126, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)}
|
||||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf9, 0xd8, 0xdc, 0xa7, 0xb, 0x92, 0x7a, 0x61, 0x37, 0x24, 0x1c, 0x77, 0x5e, 0xe, 0x7e, 0xfc, 0x9f, 0x98, 0x7b, 0x65, 0xe7, 0xf9, 0x71, 0x57, 0x89, 0x2d, 0x90, 0x1b, 0xf6, 0x5e, 0x37, 0xe8}}
|
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf9, 0xd8, 0xdc, 0xa7, 0xb, 0x92, 0x7a, 0x61, 0x37, 0x24, 0x1c, 0x77, 0x5e, 0xe, 0x7e, 0xfc, 0x9f, 0x98, 0x7b, 0x65, 0xe7, 0xf9, 0x71, 0x57, 0x89, 0x2d, 0x90, 0x1b, 0xf6, 0x5e, 0x37, 0xe8}}
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
@ -409,7 +410,7 @@ func _1599720851_add_seen_index_remove_long_messagesUpSql() (*asset, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
info := bindataFileInfo{name: "1599720851_add_seen_index_remove_long_messages.up.sql", size: 150, mode: os.FileMode(0644), modTime: time.Unix(1608547984, 0)}
|
info := bindataFileInfo{name: "1599720851_add_seen_index_remove_long_messages.up.sql", size: 150, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)}
|
||||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x24, 0x1c, 0xc4, 0x78, 0x91, 0xc7, 0xeb, 0xfe, 0xc8, 0xa0, 0xd8, 0x13, 0x27, 0x97, 0xc8, 0x96, 0x56, 0x97, 0x33, 0x2c, 0x1e, 0x16, 0x8a, 0xd3, 0x49, 0x99, 0x3, 0xe9, 0xbb, 0xc4, 0x5, 0x3c}}
|
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x24, 0x1c, 0xc4, 0x78, 0x91, 0xc7, 0xeb, 0xfe, 0xc8, 0xa0, 0xd8, 0x13, 0x27, 0x97, 0xc8, 0x96, 0x56, 0x97, 0x33, 0x2c, 0x1e, 0x16, 0x8a, 0xd3, 0x49, 0x99, 0x3, 0xe9, 0xbb, 0xc4, 0x5, 0x3c}}
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
@ -429,7 +430,7 @@ func _1603198582_add_profile_chat_fieldUpSql() (*asset, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
info := bindataFileInfo{name: "1603198582_add_profile_chat_field.up.sql", size: 45, mode: os.FileMode(0644), modTime: time.Unix(1608547984, 0)}
|
info := bindataFileInfo{name: "1603198582_add_profile_chat_field.up.sql", size: 45, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)}
|
||||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xaa, 0xca, 0xe, 0x46, 0xa0, 0x9, 0x9d, 0x47, 0x57, 0xe9, 0xfb, 0x17, 0xeb, 0x9c, 0xf6, 0xb8, 0x1d, 0xe9, 0xd, 0x0, 0xd5, 0xe5, 0xd8, 0x9e, 0x60, 0xa, 0xbf, 0x32, 0x2c, 0x52, 0x7f, 0x6a}}
|
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xaa, 0xca, 0xe, 0x46, 0xa0, 0x9, 0x9d, 0x47, 0x57, 0xe9, 0xfb, 0x17, 0xeb, 0x9c, 0xf6, 0xb8, 0x1d, 0xe9, 0xd, 0x0, 0xd5, 0xe5, 0xd8, 0x9e, 0x60, 0xa, 0xbf, 0x32, 0x2c, 0x52, 0x7f, 0x6a}}
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
@ -449,7 +450,7 @@ func _1603816533_add_linksUpSql() (*asset, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
info := bindataFileInfo{name: "1603816533_add_links.up.sql", size: 48, mode: os.FileMode(0644), modTime: time.Unix(1608547984, 0)}
|
info := bindataFileInfo{name: "1603816533_add_links.up.sql", size: 48, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)}
|
||||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xc9, 0x24, 0xd6, 0x1d, 0xa, 0x83, 0x1e, 0x4d, 0xf, 0xae, 0x4d, 0x8c, 0x51, 0x32, 0xa8, 0x37, 0xb0, 0x14, 0xfb, 0x32, 0x34, 0xc8, 0xc, 0x4e, 0x5b, 0xc5, 0x15, 0x65, 0x73, 0x0, 0x0, 0x1d}}
|
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xc9, 0x24, 0xd6, 0x1d, 0xa, 0x83, 0x1e, 0x4d, 0xf, 0xae, 0x4d, 0x8c, 0x51, 0x32, 0xa8, 0x37, 0xb0, 0x14, 0xfb, 0x32, 0x34, 0xc8, 0xc, 0x4e, 0x5b, 0xc5, 0x15, 0x65, 0x73, 0x0, 0x0, 0x1d}}
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
@ -469,7 +470,7 @@ func _1603888149_create_chat_identity_last_published_tableUpSql() (*asset, error
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
info := bindataFileInfo{name: "1603888149_create_chat_identity_last_published_table.up.sql", size: 407, mode: os.FileMode(0644), modTime: time.Unix(1608547984, 0)}
|
info := bindataFileInfo{name: "1603888149_create_chat_identity_last_published_table.up.sql", size: 407, mode: os.FileMode(0644), modTime: time.Unix(1611588835, 0)}
|
||||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x7f, 0x9, 0xf, 0xfb, 0xdb, 0x3c, 0x86, 0x70, 0x82, 0xda, 0x10, 0x25, 0xe2, 0x4e, 0x40, 0x45, 0xab, 0x8b, 0x1c, 0x91, 0x7c, 0xf1, 0x70, 0x2e, 0x81, 0xf3, 0x71, 0x45, 0xda, 0xe2, 0xa4, 0x57}}
|
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x7f, 0x9, 0xf, 0xfb, 0xdb, 0x3c, 0x86, 0x70, 0x82, 0xda, 0x10, 0x25, 0xe2, 0x4e, 0x40, 0x45, 0xab, 0x8b, 0x1c, 0x91, 0x7c, 0xf1, 0x70, 0x2e, 0x81, 0xf3, 0x71, 0x45, 0xda, 0xe2, 0xa4, 0x57}}
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
@ -489,7 +490,7 @@ func _1605075346_add_communitiesUpSql() (*asset, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
info := bindataFileInfo{name: "1605075346_add_communities.up.sql", size: 6971, mode: os.FileMode(0644), modTime: time.Unix(1610097152, 0)}
|
info := bindataFileInfo{name: "1605075346_add_communities.up.sql", size: 6971, mode: os.FileMode(0644), modTime: time.Unix(1612251705, 0)}
|
||||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x1f, 0x64, 0xea, 0xb4, 0xae, 0x9e, 0xdb, 0x9, 0x58, 0xb6, 0x5c, 0x7a, 0x50, 0xc5, 0xfe, 0x93, 0x5d, 0x36, 0x85, 0x5d, 0x6a, 0xba, 0xc9, 0x7e, 0x84, 0xd7, 0xbf, 0x2a, 0x53, 0xf3, 0x97, 0xf1}}
|
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x1f, 0x64, 0xea, 0xb4, 0xae, 0x9e, 0xdb, 0x9, 0x58, 0xb6, 0x5c, 0x7a, 0x50, 0xc5, 0xfe, 0x93, 0x5d, 0x36, 0x85, 0x5d, 0x6a, 0xba, 0xc9, 0x7e, 0x84, 0xd7, 0xbf, 0x2a, 0x53, 0xf3, 0x97, 0xf1}}
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
@ -509,7 +510,7 @@ func _1610117927_add_message_cacheUpSql() (*asset, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
info := bindataFileInfo{name: "1610117927_add_message_cache.up.sql", size: 142, mode: os.FileMode(0644), modTime: time.Unix(1613123938, 0)}
|
info := bindataFileInfo{name: "1610117927_add_message_cache.up.sql", size: 142, mode: os.FileMode(0644), modTime: time.Unix(1612251705, 0)}
|
||||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x34, 0xf1, 0xf0, 0x82, 0x79, 0x28, 0x19, 0xc2, 0x39, 0x6a, 0xa5, 0x96, 0x59, 0x23, 0xa0, 0xed, 0x60, 0x58, 0x86, 0x9, 0xb9, 0xad, 0xfb, 0xa, 0xe3, 0x47, 0x6e, 0xa1, 0x18, 0xe8, 0x39, 0x2c}}
|
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x34, 0xf1, 0xf0, 0x82, 0x79, 0x28, 0x19, 0xc2, 0x39, 0x6a, 0xa5, 0x96, 0x59, 0x23, 0xa0, 0xed, 0x60, 0x58, 0x86, 0x9, 0xb9, 0xad, 0xfb, 0xa, 0xe3, 0x47, 0x6e, 0xa1, 0x18, 0xe8, 0x39, 0x2c}}
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
@ -529,7 +530,7 @@ func _1610959908_add_dont_wrap_to_raw_messagesUpSql() (*asset, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
info := bindataFileInfo{name: "1610959908_add_dont_wrap_to_raw_messages.up.sql", size: 83, mode: os.FileMode(0644), modTime: time.Unix(1613123938, 0)}
|
info := bindataFileInfo{name: "1610959908_add_dont_wrap_to_raw_messages.up.sql", size: 83, mode: os.FileMode(0644), modTime: time.Unix(1612251705, 0)}
|
||||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x71, 0x2, 0x9a, 0xca, 0xd4, 0x38, 0x44, 0x30, 0x2b, 0xa8, 0x27, 0x32, 0x63, 0x53, 0x22, 0x60, 0x59, 0x84, 0x23, 0x96, 0x77, 0xf0, 0x56, 0xd7, 0x94, 0xe0, 0x95, 0x28, 0x6, 0x1d, 0x4e, 0xb1}}
|
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x71, 0x2, 0x9a, 0xca, 0xd4, 0x38, 0x44, 0x30, 0x2b, 0xa8, 0x27, 0x32, 0x63, 0x53, 0x22, 0x60, 0x59, 0x84, 0x23, 0x96, 0x77, 0xf0, 0x56, 0xd7, 0x94, 0xe0, 0x95, 0x28, 0x6, 0x1d, 0x4e, 0xb1}}
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
@ -549,7 +550,7 @@ func _1610960912_add_send_on_personal_topicUpSql() (*asset, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
info := bindataFileInfo{name: "1610960912_add_send_on_personal_topic.up.sql", size: 82, mode: os.FileMode(0644), modTime: time.Unix(1613123938, 0)}
|
info := bindataFileInfo{name: "1610960912_add_send_on_personal_topic.up.sql", size: 82, mode: os.FileMode(0644), modTime: time.Unix(1612251705, 0)}
|
||||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x77, 0xac, 0x2f, 0xc4, 0xd, 0xa7, 0x1b, 0x37, 0x30, 0xc2, 0x68, 0xee, 0xde, 0x54, 0x5e, 0xbf, 0x3f, 0xa0, 0xd6, 0xc6, 0x9f, 0xd4, 0x34, 0x12, 0x76, 0x1e, 0x66, 0x4a, 0xfc, 0xf, 0xee, 0xc9}}
|
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x77, 0xac, 0x2f, 0xc4, 0xd, 0xa7, 0x1b, 0x37, 0x30, 0xc2, 0x68, 0xee, 0xde, 0x54, 0x5e, 0xbf, 0x3f, 0xa0, 0xd6, 0xc6, 0x9f, 0xd4, 0x34, 0x12, 0x76, 0x1e, 0x66, 0x4a, 0xfc, 0xf, 0xee, 0xc9}}
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
@ -569,11 +570,31 @@ func _1612870480_add_datasync_idUpSql() (*asset, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
info := bindataFileInfo{name: "1612870480_add_datasync_id.up.sql", size: 111, mode: os.FileMode(0644), modTime: time.Unix(1613649828, 0)}
|
info := bindataFileInfo{name: "1612870480_add_datasync_id.up.sql", size: 111, mode: os.FileMode(0644), modTime: time.Unix(1614151150, 0)}
|
||||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x34, 0x9a, 0xbc, 0xfa, 0xaa, 0x8c, 0x9c, 0x37, 0x67, 0x15, 0x9c, 0x7e, 0x78, 0x75, 0x66, 0x82, 0x18, 0x72, 0x10, 0xbc, 0xd4, 0xab, 0x44, 0xfe, 0x57, 0x85, 0x6d, 0x19, 0xf5, 0x96, 0x8a, 0xbe}}
|
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x34, 0x9a, 0xbc, 0xfa, 0xaa, 0x8c, 0x9c, 0x37, 0x67, 0x15, 0x9c, 0x7e, 0x78, 0x75, 0x66, 0x82, 0x18, 0x72, 0x10, 0xbc, 0xd4, 0xab, 0x44, 0xfe, 0x57, 0x85, 0x6d, 0x19, 0xf5, 0x96, 0x8a, 0xbe}}
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var __1614152139_add_communities_request_to_joinUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x8c\x90\x41\x6f\xe2\x30\x14\x84\xef\xf9\x15\x4f\x9c\x40\xca\x61\xef\x9c\x9c\xec\x8b\x88\xd6\xd8\xc8\x98\xad\x38\x59\xa9\xe3\xaa\x2e\x60\xb7\xb1\xa9\xca\xbf\xaf\x12\x5a\x20\x40\xa1\x47\xfb\xcd\x8c\x66\xbe\x5c\x20\x91\x08\x92\x64\x14\x41\xfb\xcd\x66\xeb\x6c\xb4\x26\xa8\xc6\xbc\x6d\x4d\x88\x41\x45\xaf\x5e\xbc\x75\x00\xc3\x04\xc0\xd6\x90\x51\x9e\x01\xe3\x12\xd8\x82\xd2\x34\x01\x78\xdd\x3e\xae\xad\x56\x2b\xb3\x83\xff\x44\xe4\x13\x22\x7a\x67\xbd\xf6\x7a\x05\x25\x93\xbd\x5f\xe3\x82\x72\xd5\xc6\x5c\x58\xe0\x2f\x16\x64\x41\x25\x0c\x06\x9d\xfb\xb9\x8a\xca\xd6\x77\x65\x5f\xcd\x77\xea\x5a\xc3\x10\xab\x68\x7a\x15\x0e\xf6\x3f\xed\x7d\x26\xca\x29\x11\x4b\xf8\x87\x4b\x18\xda\x7a\x04\x9c\x41\xce\x59\x41\xcb\x5c\x82\xc0\x19\x25\x39\x26\xa3\x71\x92\x24\x3d\x5c\xed\x86\x77\xd3\xd8\x27\xab\xab\x68\xbd\x53\x8d\xd1\xbe\xa9\x43\x47\xea\x0e\x95\xab\xdb\xdb\xc3\x3e\xd0\xd4\x90\x71\x4e\x91\xb0\xcb\xca\x05\xa1\x73\x3c\x95\xaa\x2a\xde\x18\x77\xc9\xbf\x7f\x3f\x5b\x10\x1b\x6b\xc2\x0d\xb9\x33\x1f\xb1\x93\xed\x7e\x0b\xf4\x48\xe2\x67\xb0\x25\x9b\xa3\x90\x6d\x22\xbf\x81\xf5\x98\x94\x76\x00\xd3\x03\x82\xf4\x14\x46\xba\xdf\x3c\x82\x39\x52\xcc\x25\xd8\xfa\x5b\x7e\x8c\x6e\x2d\xa7\xaf\xce\x76\xf6\x01\x85\xe0\x53\xd0\xde\xc5\x4a\xc7\x00\x0f\x13\x14\xd8\xd3\x8c\x93\xcf\x00\x00\x00\xff\xff\xbf\xa2\xec\x31\x3f\x03\x00\x00")
|
||||||
|
|
||||||
|
func _1614152139_add_communities_request_to_joinUpSqlBytes() ([]byte, error) {
|
||||||
|
return bindataRead(
|
||||||
|
__1614152139_add_communities_request_to_joinUpSql,
|
||||||
|
"1614152139_add_communities_request_to_join.up.sql",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _1614152139_add_communities_request_to_joinUpSql() (*asset, error) {
|
||||||
|
bytes, err := _1614152139_add_communities_request_to_joinUpSqlBytes()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
info := bindataFileInfo{name: "1614152139_add_communities_request_to_join.up.sql", size: 831, mode: os.FileMode(0644), modTime: time.Unix(1614152078, 0)}
|
||||||
|
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x11, 0x3, 0x26, 0xf9, 0x29, 0x50, 0x4f, 0xcd, 0x46, 0xe5, 0xb1, 0x6b, 0xb9, 0x2, 0x40, 0xb1, 0xdf, 0x4a, 0x4c, 0x7a, 0xda, 0x3, 0x35, 0xcd, 0x2d, 0xcc, 0x80, 0x7d, 0x57, 0x5f, 0x3, 0x5c}}
|
||||||
|
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")
|
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) {
|
func readmeMdBytes() ([]byte, error) {
|
||||||
|
@ -589,7 +610,7 @@ func readmeMd() (*asset, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
info := bindataFileInfo{name: "README.md", size: 554, mode: os.FileMode(0644), modTime: time.Unix(1610097152, 0)}
|
info := bindataFileInfo{name: "README.md", size: 554, mode: os.FileMode(0644), modTime: time.Unix(1612251705, 0)}
|
||||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x1c, 0x6e, 0xfb, 0xcc, 0x81, 0x94, 0x4d, 0x8c, 0xa0, 0x3b, 0x5, 0xb0, 0x18, 0xd6, 0xbb, 0xb3, 0x79, 0xc8, 0x8f, 0xff, 0xc1, 0x10, 0xf9, 0xf, 0x20, 0x1b, 0x4a, 0x74, 0x96, 0x42, 0xd7, 0xa8}}
|
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x1c, 0x6e, 0xfb, 0xcc, 0x81, 0x94, 0x4d, 0x8c, 0xa0, 0x3b, 0x5, 0xb0, 0x18, 0xd6, 0xbb, 0xb3, 0x79, 0xc8, 0x8f, 0xff, 0xc1, 0x10, 0xf9, 0xf, 0x20, 0x1b, 0x4a, 0x74, 0x96, 0x42, 0xd7, 0xa8}}
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
@ -609,7 +630,7 @@ func docGo() (*asset, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
info := bindataFileInfo{name: "doc.go", size: 850, mode: os.FileMode(0644), modTime: time.Unix(1608547984, 0)}
|
info := bindataFileInfo{name: "doc.go", size: 850, mode: os.FileMode(0644), modTime: time.Unix(1611588719, 0)}
|
||||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xa0, 0xcc, 0x41, 0xe1, 0x61, 0x12, 0x97, 0xe, 0x36, 0x8c, 0xa7, 0x9e, 0xe0, 0x6e, 0x59, 0x9e, 0xee, 0xd5, 0x4a, 0xcf, 0x1e, 0x60, 0xd6, 0xc3, 0x3a, 0xc9, 0x6c, 0xf2, 0x86, 0x5a, 0xb4, 0x1e}}
|
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xa0, 0xcc, 0x41, 0xe1, 0x61, 0x12, 0x97, 0xe, 0x36, 0x8c, 0xa7, 0x9e, 0xe0, 0x6e, 0x59, 0x9e, 0xee, 0xd5, 0x4a, 0xcf, 0x1e, 0x60, 0xd6, 0xc3, 0x3a, 0xc9, 0x6c, 0xf2, 0x86, 0x5a, 0xb4, 0x1e}}
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
@ -705,36 +726,60 @@ func AssetNames() []string {
|
||||||
|
|
||||||
// _bindata is a table, holding each asset generator, mapped to its name.
|
// _bindata is a table, holding each asset generator, mapped to its name.
|
||||||
var _bindata = map[string]func() (*asset, error){
|
var _bindata = map[string]func() (*asset, error){
|
||||||
"000001_init.down.db.sql": _000001_initDownDbSql,
|
"000001_init.down.db.sql": _000001_initDownDbSql,
|
||||||
"000001_init.up.db.sql": _000001_initUpDbSql,
|
|
||||||
"000002_add_last_ens_clock_value.up.sql": _000002_add_last_ens_clock_valueUpSql,
|
|
||||||
"1586358095_add_replace.up.sql": _1586358095_add_replaceUpSql,
|
|
||||||
"1588665364_add_image_data.up.sql": _1588665364_add_image_dataUpSql,
|
|
||||||
"1589365189_add_pow_target.up.sql": _1589365189_add_pow_targetUpSql,
|
|
||||||
"1591277220_add_index_messages.up.sql": _1591277220_add_index_messagesUpSql,
|
|
||||||
"1593087212_add_mute_chat_and_raw_message_fields.up.sql": _1593087212_add_mute_chat_and_raw_message_fieldsUpSql,
|
|
||||||
"1595862781_add_audio_data.up.sql": _1595862781_add_audio_dataUpSql,
|
|
||||||
"1595865249_create_emoji_reactions_table.up.sql": _1595865249_create_emoji_reactions_tableUpSql,
|
|
||||||
"1596805115_create_group_chat_invitations_table.up.sql": _1596805115_create_group_chat_invitations_tableUpSql,
|
|
||||||
"1597322655_add_invitation_admin_chat_field.up.sql": _1597322655_add_invitation_admin_chat_fieldUpSql,
|
|
||||||
"1597757544_add_nickname.up.sql": _1597757544_add_nicknameUpSql,
|
|
||||||
"1598955122_add_mentions.up.sql": _1598955122_add_mentionsUpSql,
|
|
||||||
"1599641390_add_emoji_reactions_index.up.sql": _1599641390_add_emoji_reactions_indexUpSql,
|
|
||||||
"1599720851_add_seen_index_remove_long_messages.up.sql": _1599720851_add_seen_index_remove_long_messagesUpSql,
|
|
||||||
"1603198582_add_profile_chat_field.up.sql": _1603198582_add_profile_chat_fieldUpSql,
|
|
||||||
"1603816533_add_links.up.sql": _1603816533_add_linksUpSql,
|
|
||||||
"1603888149_create_chat_identity_last_published_table.up.sql": _1603888149_create_chat_identity_last_published_tableUpSql,
|
|
||||||
"1605075346_add_communities.up.sql": _1605075346_add_communitiesUpSql,
|
|
||||||
"1610117927_add_message_cache.up.sql": _1610117927_add_message_cacheUpSql,
|
|
||||||
"1610959908_add_dont_wrap_to_raw_messages.up.sql": _1610959908_add_dont_wrap_to_raw_messagesUpSql,
|
|
||||||
"1610960912_add_send_on_personal_topic.up.sql": _1610960912_add_send_on_personal_topicUpSql,
|
|
||||||
"1612870480_add_datasync_id.up.sql": _1612870480_add_datasync_idUpSql,
|
|
||||||
"README.md": readmeMd,
|
|
||||||
"doc.go": docGo,
|
|
||||||
}
|
|
||||||
|
|
||||||
// AssetDebug is true if the assets were built with the debug flag enabled.
|
"000001_init.up.db.sql": _000001_initUpDbSql,
|
||||||
const AssetDebug = false
|
|
||||||
|
"000002_add_last_ens_clock_value.up.sql": _000002_add_last_ens_clock_valueUpSql,
|
||||||
|
|
||||||
|
"1586358095_add_replace.up.sql": _1586358095_add_replaceUpSql,
|
||||||
|
|
||||||
|
"1588665364_add_image_data.up.sql": _1588665364_add_image_dataUpSql,
|
||||||
|
|
||||||
|
"1589365189_add_pow_target.up.sql": _1589365189_add_pow_targetUpSql,
|
||||||
|
|
||||||
|
"1591277220_add_index_messages.up.sql": _1591277220_add_index_messagesUpSql,
|
||||||
|
|
||||||
|
"1593087212_add_mute_chat_and_raw_message_fields.up.sql": _1593087212_add_mute_chat_and_raw_message_fieldsUpSql,
|
||||||
|
|
||||||
|
"1595862781_add_audio_data.up.sql": _1595862781_add_audio_dataUpSql,
|
||||||
|
|
||||||
|
"1595865249_create_emoji_reactions_table.up.sql": _1595865249_create_emoji_reactions_tableUpSql,
|
||||||
|
|
||||||
|
"1596805115_create_group_chat_invitations_table.up.sql": _1596805115_create_group_chat_invitations_tableUpSql,
|
||||||
|
|
||||||
|
"1597322655_add_invitation_admin_chat_field.up.sql": _1597322655_add_invitation_admin_chat_fieldUpSql,
|
||||||
|
|
||||||
|
"1597757544_add_nickname.up.sql": _1597757544_add_nicknameUpSql,
|
||||||
|
|
||||||
|
"1598955122_add_mentions.up.sql": _1598955122_add_mentionsUpSql,
|
||||||
|
|
||||||
|
"1599641390_add_emoji_reactions_index.up.sql": _1599641390_add_emoji_reactions_indexUpSql,
|
||||||
|
|
||||||
|
"1599720851_add_seen_index_remove_long_messages.up.sql": _1599720851_add_seen_index_remove_long_messagesUpSql,
|
||||||
|
|
||||||
|
"1603198582_add_profile_chat_field.up.sql": _1603198582_add_profile_chat_fieldUpSql,
|
||||||
|
|
||||||
|
"1603816533_add_links.up.sql": _1603816533_add_linksUpSql,
|
||||||
|
|
||||||
|
"1603888149_create_chat_identity_last_published_table.up.sql": _1603888149_create_chat_identity_last_published_tableUpSql,
|
||||||
|
|
||||||
|
"1605075346_add_communities.up.sql": _1605075346_add_communitiesUpSql,
|
||||||
|
|
||||||
|
"1610117927_add_message_cache.up.sql": _1610117927_add_message_cacheUpSql,
|
||||||
|
|
||||||
|
"1610959908_add_dont_wrap_to_raw_messages.up.sql": _1610959908_add_dont_wrap_to_raw_messagesUpSql,
|
||||||
|
|
||||||
|
"1610960912_add_send_on_personal_topic.up.sql": _1610960912_add_send_on_personal_topicUpSql,
|
||||||
|
|
||||||
|
"1612870480_add_datasync_id.up.sql": _1612870480_add_datasync_idUpSql,
|
||||||
|
|
||||||
|
"1614152139_add_communities_request_to_join.up.sql": _1614152139_add_communities_request_to_joinUpSql,
|
||||||
|
|
||||||
|
"README.md": readmeMd,
|
||||||
|
|
||||||
|
"doc.go": docGo,
|
||||||
|
}
|
||||||
|
|
||||||
// AssetDir returns the file names below a certain
|
// AssetDir returns the file names below a certain
|
||||||
// directory embedded in the file by go-bindata.
|
// directory embedded in the file by go-bindata.
|
||||||
|
@ -777,32 +822,33 @@ type bintree struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
var _bintree = &bintree{nil, map[string]*bintree{
|
var _bintree = &bintree{nil, map[string]*bintree{
|
||||||
"000001_init.down.db.sql": {_000001_initDownDbSql, map[string]*bintree{}},
|
"000001_init.down.db.sql": &bintree{_000001_initDownDbSql, map[string]*bintree{}},
|
||||||
"000001_init.up.db.sql": {_000001_initUpDbSql, map[string]*bintree{}},
|
"000001_init.up.db.sql": &bintree{_000001_initUpDbSql, map[string]*bintree{}},
|
||||||
"000002_add_last_ens_clock_value.up.sql": {_000002_add_last_ens_clock_valueUpSql, map[string]*bintree{}},
|
"000002_add_last_ens_clock_value.up.sql": &bintree{_000002_add_last_ens_clock_valueUpSql, map[string]*bintree{}},
|
||||||
"1586358095_add_replace.up.sql": {_1586358095_add_replaceUpSql, map[string]*bintree{}},
|
"1586358095_add_replace.up.sql": &bintree{_1586358095_add_replaceUpSql, map[string]*bintree{}},
|
||||||
"1588665364_add_image_data.up.sql": {_1588665364_add_image_dataUpSql, map[string]*bintree{}},
|
"1588665364_add_image_data.up.sql": &bintree{_1588665364_add_image_dataUpSql, map[string]*bintree{}},
|
||||||
"1589365189_add_pow_target.up.sql": {_1589365189_add_pow_targetUpSql, map[string]*bintree{}},
|
"1589365189_add_pow_target.up.sql": &bintree{_1589365189_add_pow_targetUpSql, map[string]*bintree{}},
|
||||||
"1591277220_add_index_messages.up.sql": {_1591277220_add_index_messagesUpSql, map[string]*bintree{}},
|
"1591277220_add_index_messages.up.sql": &bintree{_1591277220_add_index_messagesUpSql, map[string]*bintree{}},
|
||||||
"1593087212_add_mute_chat_and_raw_message_fields.up.sql": {_1593087212_add_mute_chat_and_raw_message_fieldsUpSql, map[string]*bintree{}},
|
"1593087212_add_mute_chat_and_raw_message_fields.up.sql": &bintree{_1593087212_add_mute_chat_and_raw_message_fieldsUpSql, map[string]*bintree{}},
|
||||||
"1595862781_add_audio_data.up.sql": {_1595862781_add_audio_dataUpSql, map[string]*bintree{}},
|
"1595862781_add_audio_data.up.sql": &bintree{_1595862781_add_audio_dataUpSql, map[string]*bintree{}},
|
||||||
"1595865249_create_emoji_reactions_table.up.sql": {_1595865249_create_emoji_reactions_tableUpSql, map[string]*bintree{}},
|
"1595865249_create_emoji_reactions_table.up.sql": &bintree{_1595865249_create_emoji_reactions_tableUpSql, map[string]*bintree{}},
|
||||||
"1596805115_create_group_chat_invitations_table.up.sql": {_1596805115_create_group_chat_invitations_tableUpSql, map[string]*bintree{}},
|
"1596805115_create_group_chat_invitations_table.up.sql": &bintree{_1596805115_create_group_chat_invitations_tableUpSql, map[string]*bintree{}},
|
||||||
"1597322655_add_invitation_admin_chat_field.up.sql": {_1597322655_add_invitation_admin_chat_fieldUpSql, map[string]*bintree{}},
|
"1597322655_add_invitation_admin_chat_field.up.sql": &bintree{_1597322655_add_invitation_admin_chat_fieldUpSql, map[string]*bintree{}},
|
||||||
"1597757544_add_nickname.up.sql": {_1597757544_add_nicknameUpSql, map[string]*bintree{}},
|
"1597757544_add_nickname.up.sql": &bintree{_1597757544_add_nicknameUpSql, map[string]*bintree{}},
|
||||||
"1598955122_add_mentions.up.sql": {_1598955122_add_mentionsUpSql, map[string]*bintree{}},
|
"1598955122_add_mentions.up.sql": &bintree{_1598955122_add_mentionsUpSql, map[string]*bintree{}},
|
||||||
"1599641390_add_emoji_reactions_index.up.sql": {_1599641390_add_emoji_reactions_indexUpSql, map[string]*bintree{}},
|
"1599641390_add_emoji_reactions_index.up.sql": &bintree{_1599641390_add_emoji_reactions_indexUpSql, map[string]*bintree{}},
|
||||||
"1599720851_add_seen_index_remove_long_messages.up.sql": {_1599720851_add_seen_index_remove_long_messagesUpSql, map[string]*bintree{}},
|
"1599720851_add_seen_index_remove_long_messages.up.sql": &bintree{_1599720851_add_seen_index_remove_long_messagesUpSql, map[string]*bintree{}},
|
||||||
"1603198582_add_profile_chat_field.up.sql": {_1603198582_add_profile_chat_fieldUpSql, map[string]*bintree{}},
|
"1603198582_add_profile_chat_field.up.sql": &bintree{_1603198582_add_profile_chat_fieldUpSql, map[string]*bintree{}},
|
||||||
"1603816533_add_links.up.sql": {_1603816533_add_linksUpSql, map[string]*bintree{}},
|
"1603816533_add_links.up.sql": &bintree{_1603816533_add_linksUpSql, map[string]*bintree{}},
|
||||||
"1603888149_create_chat_identity_last_published_table.up.sql": {_1603888149_create_chat_identity_last_published_tableUpSql, map[string]*bintree{}},
|
"1603888149_create_chat_identity_last_published_table.up.sql": &bintree{_1603888149_create_chat_identity_last_published_tableUpSql, map[string]*bintree{}},
|
||||||
"1605075346_add_communities.up.sql": {_1605075346_add_communitiesUpSql, map[string]*bintree{}},
|
"1605075346_add_communities.up.sql": &bintree{_1605075346_add_communitiesUpSql, map[string]*bintree{}},
|
||||||
"1610117927_add_message_cache.up.sql": {_1610117927_add_message_cacheUpSql, map[string]*bintree{}},
|
"1610117927_add_message_cache.up.sql": &bintree{_1610117927_add_message_cacheUpSql, map[string]*bintree{}},
|
||||||
"1610959908_add_dont_wrap_to_raw_messages.up.sql": {_1610959908_add_dont_wrap_to_raw_messagesUpSql, map[string]*bintree{}},
|
"1610959908_add_dont_wrap_to_raw_messages.up.sql": &bintree{_1610959908_add_dont_wrap_to_raw_messagesUpSql, map[string]*bintree{}},
|
||||||
"1610960912_add_send_on_personal_topic.up.sql": {_1610960912_add_send_on_personal_topicUpSql, map[string]*bintree{}},
|
"1610960912_add_send_on_personal_topic.up.sql": &bintree{_1610960912_add_send_on_personal_topicUpSql, map[string]*bintree{}},
|
||||||
"1612870480_add_datasync_id.up.sql": {_1612870480_add_datasync_idUpSql, map[string]*bintree{}},
|
"1612870480_add_datasync_id.up.sql": &bintree{_1612870480_add_datasync_idUpSql, map[string]*bintree{}},
|
||||||
"README.md": {readmeMd, map[string]*bintree{}},
|
"1614152139_add_communities_request_to_join.up.sql": &bintree{_1614152139_add_communities_request_to_joinUpSql, map[string]*bintree{}},
|
||||||
"doc.go": {docGo, map[string]*bintree{}},
|
"README.md": &bintree{readmeMd, map[string]*bintree{}},
|
||||||
|
"doc.go": &bintree{docGo, map[string]*bintree{}},
|
||||||
}}
|
}}
|
||||||
|
|
||||||
// RestoreAsset restores an asset under the given directory.
|
// RestoreAsset restores an asset under the given directory.
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
CREATE TABLE communities_requests_to_join (
|
||||||
|
id BLOB NOT NULL,
|
||||||
|
public_key VARCHAR NOT NULL,
|
||||||
|
clock INT NOT NULL,
|
||||||
|
ens_name VARCHAR NOT NULL DEFAULT "",
|
||||||
|
chat_id VARCHAR NOT NULL DEFAULT "",
|
||||||
|
community_id BLOB NOT NULL,
|
||||||
|
state INT NOT NULL DEFAULT 0,
|
||||||
|
PRIMARY KEY (id) ON CONFLICT REPLACE
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
CREATE TABLE ens_verification_records (
|
||||||
|
public_key VARCHAR NOT NULL,
|
||||||
|
name VARCHAR NOT NULL,
|
||||||
|
verified BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
|
verified_at INT NOT NULL DEFAULT 0,
|
||||||
|
clock INT NOT NULL DEFAULT 0,
|
||||||
|
verification_retries INT NOT NULL DEFAULT 0,
|
||||||
|
next_retry INT NOT NULL DEFAULT 0,
|
||||||
|
PRIMARY KEY (public_key) ON CONFLICT REPLACE
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO ens_verification_records (public_key, name, verified, verified_at, clock) SELECT id, name, ens_verified, ens_verified_at, ens_verified_at FROM contacts WHERE ens_verified;
|
|
@ -409,19 +409,17 @@ func (db sqlitePersistence) Contacts() ([]*Contact, error) {
|
||||||
SELECT
|
SELECT
|
||||||
c.id,
|
c.id,
|
||||||
c.address,
|
c.address,
|
||||||
c.name,
|
v.name,
|
||||||
|
v.verified,
|
||||||
c.alias,
|
c.alias,
|
||||||
c.identicon,
|
c.identicon,
|
||||||
c.last_updated,
|
c.last_updated,
|
||||||
c.system_tags,
|
c.system_tags,
|
||||||
c.device_info,
|
c.device_info,
|
||||||
c.ens_verified,
|
|
||||||
c.ens_verified_at,
|
|
||||||
c.tribute_to_talk,
|
|
||||||
c.local_nickname,
|
c.local_nickname,
|
||||||
i.image_type,
|
i.image_type,
|
||||||
i.payload
|
i.payload
|
||||||
FROM contacts c LEFT JOIN chat_identity_contacts i ON c.id = i.contact_id
|
FROM contacts c LEFT JOIN chat_identity_contacts i ON c.id = i.contact_id LEFT JOIN ens_verification_records v ON c.id = v.public_key
|
||||||
`)
|
`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -436,6 +434,8 @@ func (db sqlitePersistence) Contacts() ([]*Contact, error) {
|
||||||
encodedSystemTags []byte
|
encodedSystemTags []byte
|
||||||
nickname sql.NullString
|
nickname sql.NullString
|
||||||
imageType sql.NullString
|
imageType sql.NullString
|
||||||
|
ensName sql.NullString
|
||||||
|
ensVerified sql.NullBool
|
||||||
imagePayload []byte
|
imagePayload []byte
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -444,15 +444,13 @@ func (db sqlitePersistence) Contacts() ([]*Contact, error) {
|
||||||
err := rows.Scan(
|
err := rows.Scan(
|
||||||
&contact.ID,
|
&contact.ID,
|
||||||
&contact.Address,
|
&contact.Address,
|
||||||
&contact.Name,
|
&ensName,
|
||||||
|
&ensVerified,
|
||||||
&contact.Alias,
|
&contact.Alias,
|
||||||
&contact.Identicon,
|
&contact.Identicon,
|
||||||
&contact.LastUpdated,
|
&contact.LastUpdated,
|
||||||
&encodedSystemTags,
|
&encodedSystemTags,
|
||||||
&encodedDeviceInfo,
|
&encodedDeviceInfo,
|
||||||
&contact.ENSVerified,
|
|
||||||
&contact.ENSVerifiedAt,
|
|
||||||
&contact.TributeToTalk,
|
|
||||||
&nickname,
|
&nickname,
|
||||||
&imageType,
|
&imageType,
|
||||||
&imagePayload,
|
&imagePayload,
|
||||||
|
@ -465,6 +463,14 @@ func (db sqlitePersistence) Contacts() ([]*Contact, error) {
|
||||||
contact.LocalNickname = nickname.String
|
contact.LocalNickname = nickname.String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ensName.Valid {
|
||||||
|
contact.Name = ensName.String
|
||||||
|
}
|
||||||
|
|
||||||
|
if ensVerified.Valid {
|
||||||
|
contact.ENSVerified = ensVerified.Bool
|
||||||
|
}
|
||||||
|
|
||||||
if encodedDeviceInfo != nil {
|
if encodedDeviceInfo != nil {
|
||||||
// Restore device info
|
// Restore device info
|
||||||
deviceInfoDecoder := gob.NewDecoder(bytes.NewBuffer(encodedDeviceInfo))
|
deviceInfoDecoder := gob.NewDecoder(bytes.NewBuffer(encodedDeviceInfo))
|
||||||
|
@ -798,6 +804,9 @@ func (db sqlitePersistence) SaveContact(contact *Contact, tx *sql.Tx) (err error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert record
|
// Insert record
|
||||||
|
// NOTE: tribute_to_talk is not used anymore, but it's not nullable
|
||||||
|
// Removing it requires copying over the table which might be expensive
|
||||||
|
// when there are many contacts, so best avoiding it
|
||||||
stmt, err := tx.Prepare(`
|
stmt, err := tx.Prepare(`
|
||||||
INSERT INTO contacts(
|
INSERT INTO contacts(
|
||||||
id,
|
id,
|
||||||
|
@ -808,12 +817,10 @@ func (db sqlitePersistence) SaveContact(contact *Contact, tx *sql.Tx) (err error
|
||||||
last_updated,
|
last_updated,
|
||||||
system_tags,
|
system_tags,
|
||||||
device_info,
|
device_info,
|
||||||
ens_verified,
|
|
||||||
ens_verified_at,
|
|
||||||
tribute_to_talk,
|
|
||||||
local_nickname,
|
local_nickname,
|
||||||
photo
|
photo,
|
||||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?, ?)
|
tribute_to_talk
|
||||||
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?,?, ?, "")
|
||||||
`)
|
`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@ -829,9 +836,6 @@ func (db sqlitePersistence) SaveContact(contact *Contact, tx *sql.Tx) (err error
|
||||||
contact.LastUpdated,
|
contact.LastUpdated,
|
||||||
encodedSystemTags.Bytes(),
|
encodedSystemTags.Bytes(),
|
||||||
encodedDeviceInfo.Bytes(),
|
encodedDeviceInfo.Bytes(),
|
||||||
contact.ENSVerified,
|
|
||||||
contact.ENSVerifiedAt,
|
|
||||||
contact.TributeToTalk,
|
|
||||||
contact.LocalNickname,
|
contact.LocalNickname,
|
||||||
// Photo is not used anymore but constrained to be NOT NULL
|
// Photo is not used anymore but constrained to be NOT NULL
|
||||||
// we set it to blank for now to avoid a migration of the table
|
// we set it to blank for now to avoid a migration of the table
|
||||||
|
|
|
@ -606,12 +606,12 @@ func TestSaveChat(t *testing.T) {
|
||||||
|
|
||||||
chat := CreatePublicChat("test-chat", &testTimeSource{})
|
chat := CreatePublicChat("test-chat", &testTimeSource{})
|
||||||
chat.LastMessage = &common.Message{}
|
chat.LastMessage = &common.Message{}
|
||||||
err = p.SaveChat(chat)
|
err = p.SaveChat(*chat)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
retrievedChat, err := p.Chat(chat.ID)
|
retrievedChat, err := p.Chat(chat.ID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, &chat, retrievedChat)
|
require.Equal(t, chat, retrievedChat)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSaveMentions(t *testing.T) {
|
func TestSaveMentions(t *testing.T) {
|
||||||
|
@ -821,7 +821,7 @@ func TestDeactivatePublicChat(t *testing.T) {
|
||||||
publicChat.LastMessage = &lastMessage
|
publicChat.LastMessage = &lastMessage
|
||||||
publicChat.UnviewedMessagesCount = 1
|
publicChat.UnviewedMessagesCount = 1
|
||||||
|
|
||||||
err = p.DeactivateChat(&publicChat, currentClockValue)
|
err = p.DeactivateChat(publicChat, currentClockValue)
|
||||||
|
|
||||||
// It does not set deleted at for a public chat
|
// It does not set deleted at for a public chat
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -890,7 +890,7 @@ func TestDeactivateOneToOneChat(t *testing.T) {
|
||||||
chat.LastMessage = &lastMessage
|
chat.LastMessage = &lastMessage
|
||||||
chat.UnviewedMessagesCount = 1
|
chat.UnviewedMessagesCount = 1
|
||||||
|
|
||||||
err = p.DeactivateChat(&chat, currentClockValue)
|
err = p.DeactivateChat(chat, currentClockValue)
|
||||||
|
|
||||||
// It does set deleted at for a public chat
|
// It does set deleted at for a public chat
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
|
@ -50,6 +50,7 @@ const (
|
||||||
ApplicationMetadataMessage_CHAT_IDENTITY ApplicationMetadataMessage_Type = 24
|
ApplicationMetadataMessage_CHAT_IDENTITY ApplicationMetadataMessage_Type = 24
|
||||||
ApplicationMetadataMessage_COMMUNITY_DESCRIPTION ApplicationMetadataMessage_Type = 25
|
ApplicationMetadataMessage_COMMUNITY_DESCRIPTION ApplicationMetadataMessage_Type = 25
|
||||||
ApplicationMetadataMessage_COMMUNITY_INVITATION ApplicationMetadataMessage_Type = 26
|
ApplicationMetadataMessage_COMMUNITY_INVITATION ApplicationMetadataMessage_Type = 26
|
||||||
|
ApplicationMetadataMessage_COMMUNITY_REQUEST_TO_JOIN ApplicationMetadataMessage_Type = 27
|
||||||
)
|
)
|
||||||
|
|
||||||
var ApplicationMetadataMessage_Type_name = map[int32]string{
|
var ApplicationMetadataMessage_Type_name = map[int32]string{
|
||||||
|
@ -80,6 +81,7 @@ var ApplicationMetadataMessage_Type_name = map[int32]string{
|
||||||
24: "CHAT_IDENTITY",
|
24: "CHAT_IDENTITY",
|
||||||
25: "COMMUNITY_DESCRIPTION",
|
25: "COMMUNITY_DESCRIPTION",
|
||||||
26: "COMMUNITY_INVITATION",
|
26: "COMMUNITY_INVITATION",
|
||||||
|
27: "COMMUNITY_REQUEST_TO_JOIN",
|
||||||
}
|
}
|
||||||
|
|
||||||
var ApplicationMetadataMessage_Type_value = map[string]int32{
|
var ApplicationMetadataMessage_Type_value = map[string]int32{
|
||||||
|
@ -110,6 +112,7 @@ var ApplicationMetadataMessage_Type_value = map[string]int32{
|
||||||
"CHAT_IDENTITY": 24,
|
"CHAT_IDENTITY": 24,
|
||||||
"COMMUNITY_DESCRIPTION": 25,
|
"COMMUNITY_DESCRIPTION": 25,
|
||||||
"COMMUNITY_INVITATION": 26,
|
"COMMUNITY_INVITATION": 26,
|
||||||
|
"COMMUNITY_REQUEST_TO_JOIN": 27,
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x ApplicationMetadataMessage_Type) String() string {
|
func (x ApplicationMetadataMessage_Type) String() string {
|
||||||
|
@ -188,38 +191,39 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
var fileDescriptor_ad09a6406fcf24c7 = []byte{
|
var fileDescriptor_ad09a6406fcf24c7 = []byte{
|
||||||
// 527 bytes of a gzipped FileDescriptorProto
|
// 539 bytes of a gzipped FileDescriptorProto
|
||||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x93, 0x5d, 0x53, 0xd3, 0x4e,
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x93, 0x4d, 0x53, 0xdb, 0x3e,
|
||||||
0x14, 0xc6, 0xff, 0x05, 0xfe, 0x14, 0x0e, 0x2f, 0x2e, 0x07, 0x90, 0x00, 0xf2, 0x62, 0x75, 0x14,
|
0x10, 0xc6, 0xff, 0x01, 0xfe, 0x04, 0x96, 0x97, 0x8a, 0x05, 0x8a, 0x81, 0xf2, 0xd2, 0xb4, 0xd3,
|
||||||
0x75, 0xa6, 0x17, 0x7a, 0xed, 0xc5, 0xb2, 0x39, 0xd0, 0xd5, 0x66, 0x13, 0x76, 0x37, 0x38, 0xbd,
|
0xd2, 0x76, 0x26, 0x87, 0xf6, 0xdc, 0x83, 0x90, 0x17, 0x10, 0x8d, 0x25, 0x23, 0xc9, 0x74, 0x72,
|
||||||
0xda, 0x09, 0x12, 0x99, 0xce, 0x00, 0xcd, 0xd0, 0x70, 0xd1, 0x4f, 0xe3, 0xa7, 0xf0, 0xfb, 0x39,
|
0xd2, 0x98, 0xe2, 0x32, 0xcc, 0x00, 0xf1, 0x80, 0x39, 0xf0, 0xe5, 0xfa, 0x29, 0xfa, 0x81, 0x3a,
|
||||||
0x49, 0x5b, 0x5b, 0x6c, 0x91, 0xab, 0xcc, 0x3e, 0xcf, 0xef, 0x9c, 0x33, 0xe7, 0xd9, 0x2c, 0xd4,
|
0x76, 0x12, 0x02, 0x4d, 0x28, 0x27, 0x8f, 0x9e, 0xe7, 0xb7, 0x2b, 0xef, 0xb3, 0x36, 0x34, 0xd2,
|
||||||
0x92, 0x2c, 0xbb, 0x6e, 0x7f, 0x4f, 0xf2, 0x76, 0xe7, 0xd6, 0xdd, 0xa4, 0x79, 0x72, 0x99, 0xe4,
|
0x3c, 0xbf, 0x38, 0xff, 0x91, 0x16, 0xe7, 0x9d, 0x2b, 0x7f, 0x99, 0x15, 0xe9, 0x69, 0x5a, 0xa4,
|
||||||
0x89, 0xbb, 0x49, 0xbb, 0xdd, 0xe4, 0x2a, 0xad, 0x67, 0x77, 0x9d, 0xbc, 0x83, 0x0b, 0xe5, 0xe7,
|
0xfe, 0x32, 0xbb, 0xb9, 0x49, 0xcf, 0xb2, 0x66, 0x7e, 0xdd, 0x29, 0x3a, 0x38, 0x55, 0x3d, 0x4e,
|
||||||
0xe2, 0xfe, 0x47, 0xed, 0x57, 0x15, 0x76, 0xf8, 0xa8, 0x20, 0x18, 0xf0, 0x41, 0x1f, 0xc7, 0x17,
|
0x6e, 0x7f, 0x36, 0x7e, 0xd7, 0x61, 0x8d, 0x0f, 0x0a, 0xa2, 0x1e, 0x1f, 0x75, 0x71, 0x7c, 0x05,
|
||||||
0xb0, 0xd8, 0x6d, 0x5f, 0xdd, 0x26, 0xf9, 0xfd, 0x5d, 0xea, 0x55, 0x0e, 0x2b, 0x47, 0xcb, 0x7a,
|
0xd3, 0x37, 0xe7, 0x67, 0x57, 0x69, 0x71, 0x7b, 0x9d, 0x05, 0xb5, 0xed, 0xda, 0xce, 0xac, 0x19,
|
||||||
0x24, 0xa0, 0x07, 0xd5, 0x2c, 0xe9, 0x5d, 0x77, 0x92, 0x4b, 0x6f, 0xa6, 0xf4, 0x86, 0x47, 0xfc,
|
0x08, 0x18, 0x40, 0x3d, 0x4f, 0xef, 0x2e, 0x3a, 0xe9, 0x69, 0x30, 0x56, 0x79, 0xfd, 0x23, 0x7e,
|
||||||
0x0c, 0x73, 0x79, 0x2f, 0x4b, 0xbd, 0xd9, 0xc3, 0xca, 0xd1, 0xea, 0xc7, 0x77, 0xf5, 0xe1, 0xbc,
|
0x85, 0x89, 0xe2, 0x2e, 0xcf, 0x82, 0xf1, 0xed, 0xda, 0xce, 0xfc, 0xe7, 0x0f, 0xcd, 0xfe, 0x7d,
|
||||||
0xfa, 0xe3, 0xb3, 0xea, 0xb6, 0x97, 0xa5, 0xba, 0x2c, 0xab, 0xfd, 0x9c, 0x87, 0xb9, 0xe2, 0x88,
|
0xcd, 0xa7, 0xef, 0x6a, 0xba, 0xbb, 0x3c, 0x33, 0x55, 0x59, 0xe3, 0xd7, 0x24, 0x4c, 0x94, 0x47,
|
||||||
0x4b, 0x50, 0x8d, 0xd5, 0x57, 0x15, 0x7e, 0x53, 0xec, 0x3f, 0x64, 0xb0, 0x2c, 0x1a, 0xdc, 0xba,
|
0x9c, 0x81, 0x7a, 0xa2, 0xbe, 0x29, 0xfd, 0x5d, 0xb1, 0xff, 0x90, 0xc1, 0xac, 0x38, 0xe0, 0xce,
|
||||||
0x80, 0x8c, 0xe1, 0xa7, 0xc4, 0x2a, 0x88, 0xb0, 0x2a, 0x42, 0x65, 0xb9, 0xb0, 0x2e, 0x8e, 0x7c,
|
0x47, 0x64, 0x2d, 0xdf, 0x27, 0x56, 0x43, 0x84, 0x79, 0xa1, 0x95, 0xe3, 0xc2, 0xf9, 0x24, 0x0e,
|
||||||
0x6e, 0x89, 0xcd, 0xe0, 0x1e, 0x6c, 0x07, 0x14, 0x1c, 0x93, 0x36, 0x0d, 0x19, 0x0d, 0xe4, 0x3f,
|
0xb9, 0x23, 0x36, 0x86, 0x1b, 0xb0, 0x1a, 0x51, 0xb4, 0x4b, 0xc6, 0x1e, 0xc8, 0xb8, 0x27, 0xdf,
|
||||||
0x25, 0xb3, 0xb8, 0x09, 0x6b, 0x11, 0x97, 0xda, 0x49, 0x65, 0x2c, 0x6f, 0x36, 0xb9, 0x95, 0xa1,
|
0x97, 0x8c, 0xe3, 0x32, 0x2c, 0xc4, 0x5c, 0x1a, 0x2f, 0x95, 0x75, 0xbc, 0xd5, 0xe2, 0x4e, 0x6a,
|
||||||
0x62, 0x73, 0x85, 0x6c, 0x5a, 0x4a, 0x3c, 0x94, 0xff, 0xc7, 0x57, 0x70, 0xa0, 0xe9, 0x2c, 0x26,
|
0xc5, 0x26, 0x4a, 0xd9, 0xb6, 0x95, 0x78, 0x2c, 0xff, 0x8f, 0x6f, 0x60, 0xcb, 0xd0, 0x51, 0x42,
|
||||||
0x63, 0x1d, 0xf7, 0x7d, 0x4d, 0xc6, 0xb8, 0x93, 0x50, 0x3b, 0xab, 0xb9, 0x32, 0x5c, 0x94, 0xd0,
|
0xd6, 0x79, 0x1e, 0x86, 0x86, 0xac, 0xf5, 0x7b, 0xda, 0x78, 0x67, 0xb8, 0xb2, 0x5c, 0x54, 0xd0,
|
||||||
0x3c, 0xbe, 0x87, 0x37, 0x5c, 0x08, 0x8a, 0xac, 0x7b, 0x8a, 0xad, 0xe2, 0x07, 0x78, 0xeb, 0x93,
|
0x24, 0x7e, 0x84, 0x77, 0x5c, 0x08, 0x8a, 0x9d, 0x7f, 0x8e, 0xad, 0xe3, 0x27, 0x78, 0x1f, 0x92,
|
||||||
0x68, 0x4a, 0x45, 0x4f, 0xc2, 0x0b, 0xb8, 0x05, 0xeb, 0x43, 0x68, 0xdc, 0x58, 0xc4, 0x0d, 0x60,
|
0x68, 0x49, 0x45, 0xcf, 0xc2, 0x53, 0xb8, 0x02, 0x8b, 0x7d, 0xe8, 0xa1, 0x31, 0x8d, 0x4b, 0xc0,
|
||||||
0x86, 0x94, 0xff, 0x40, 0x05, 0x3c, 0x80, 0xdd, 0xbf, 0x7b, 0x8f, 0x03, 0x4b, 0x45, 0x34, 0x13,
|
0x2c, 0xa9, 0xf0, 0x91, 0x0a, 0xb8, 0x05, 0xeb, 0x7f, 0xf7, 0x7e, 0x08, 0xcc, 0x94, 0xd1, 0x0c,
|
||||||
0x4b, 0xba, 0x41, 0x80, 0x6c, 0x79, 0xba, 0xcd, 0x85, 0x08, 0x63, 0x65, 0xd9, 0x0a, 0xbe, 0x84,
|
0x0d, 0xe9, 0x7b, 0x01, 0xb2, 0xd9, 0xd1, 0x36, 0x17, 0x42, 0x27, 0xca, 0xb1, 0x39, 0x7c, 0x0d,
|
||||||
0xbd, 0x49, 0x3b, 0x8a, 0x8f, 0x9b, 0x52, 0xb8, 0xe2, 0x5e, 0xd8, 0x2a, 0xee, 0xc3, 0xce, 0xf0,
|
0x1b, 0xc3, 0x76, 0x9c, 0xec, 0xb6, 0xa4, 0xf0, 0xe5, 0x5e, 0xd8, 0x3c, 0x6e, 0xc2, 0x5a, 0x7f,
|
||||||
0x3e, 0x44, 0xe8, 0x93, 0xe3, 0xfe, 0x39, 0x69, 0x2b, 0x0d, 0x05, 0xa4, 0x2c, 0x7b, 0x86, 0x35,
|
0x1f, 0x42, 0x87, 0xe4, 0x79, 0x78, 0x4c, 0xc6, 0x49, 0x4b, 0x11, 0x29, 0xc7, 0x5e, 0x60, 0x03,
|
||||||
0xd8, 0x8f, 0x62, 0xd3, 0x70, 0x2a, 0xb4, 0xf2, 0x44, 0x8a, 0x7e, 0x0b, 0x4d, 0xa7, 0xd2, 0x58,
|
0x36, 0xe3, 0xc4, 0x1e, 0x78, 0xa5, 0x9d, 0xdc, 0x93, 0xa2, 0xdb, 0xc2, 0xd0, 0xbe, 0xb4, 0xce,
|
||||||
0xdd, 0x8f, 0x9c, 0x15, 0x09, 0xfd, 0x9b, 0x71, 0x9a, 0x4c, 0x14, 0x2a, 0x43, 0x6c, 0x0d, 0x77,
|
0x74, 0x23, 0x67, 0x65, 0x42, 0xff, 0x66, 0xbc, 0x21, 0x1b, 0x6b, 0x65, 0x89, 0x2d, 0xe0, 0x3a,
|
||||||
0x61, 0x6b, 0x12, 0x3e, 0x8b, 0x49, 0xb7, 0x18, 0xe2, 0x6b, 0x38, 0x7c, 0xc4, 0x1c, 0xb5, 0x58,
|
0xac, 0x0c, 0xc3, 0x47, 0x09, 0x99, 0x36, 0x43, 0x7c, 0x0b, 0xdb, 0x4f, 0x98, 0x83, 0x16, 0x8b,
|
||||||
0x2f, 0xb6, 0x9e, 0x36, 0xaf, 0xcc, 0x8f, 0x6d, 0x14, 0x2b, 0x4d, 0xb3, 0x07, 0xe5, 0x9b, 0xc5,
|
0xe5, 0xd4, 0xa3, 0xee, 0xab, 0xf2, 0x63, 0x4b, 0xe5, 0x48, 0xa3, 0xec, 0x5e, 0xf9, 0x72, 0xf9,
|
||||||
0x2f, 0x48, 0x41, 0xf8, 0x45, 0x3a, 0x4d, 0x83, 0x9c, 0x9f, 0xe3, 0x36, 0x6c, 0x9e, 0xea, 0x30,
|
0x09, 0x52, 0xa4, 0x0f, 0xa5, 0x37, 0xd4, 0xcb, 0xf9, 0x25, 0xae, 0xc2, 0xf2, 0xbe, 0xd1, 0x49,
|
||||||
0x8e, 0xca, 0x58, 0x9c, 0x54, 0xe7, 0xd2, 0xf6, 0xb7, 0xdb, 0xc2, 0x35, 0x58, 0xe9, 0x8b, 0x3e,
|
0x5c, 0xc5, 0xe2, 0xa5, 0x3a, 0x96, 0xae, 0x3b, 0xdd, 0x0a, 0x2e, 0xc0, 0x5c, 0x57, 0x0c, 0x49,
|
||||||
0x29, 0x2b, 0x6d, 0x8b, 0x79, 0x05, 0x2d, 0xc2, 0x20, 0x88, 0x95, 0xb4, 0x2d, 0xe7, 0x93, 0x11,
|
0x39, 0xe9, 0xda, 0x2c, 0x28, 0x69, 0xa1, 0xa3, 0x28, 0x51, 0xd2, 0xb5, 0x7d, 0x48, 0x56, 0x18,
|
||||||
0x5a, 0x46, 0x25, 0xbd, 0x8d, 0x1e, 0x6c, 0x8c, 0xac, 0xb1, 0x3e, 0x3b, 0x17, 0xf3, 0xe5, 0x8b,
|
0x19, 0x57, 0xf4, 0x2a, 0x06, 0xb0, 0x34, 0xb0, 0x1e, 0xf4, 0x59, 0x2b, 0xdf, 0x7a, 0xe0, 0xdc,
|
||||||
0xfa, 0xf4, 0x3b, 0x00, 0x00, 0xff, 0xff, 0x42, 0x01, 0x7e, 0x48, 0xee, 0x03, 0x00, 0x00,
|
0x6f, 0x5b, 0xfb, 0x43, 0x2d, 0x15, 0x5b, 0x3f, 0x99, 0xac, 0x7e, 0xb8, 0x2f, 0x7f, 0x02, 0x00,
|
||||||
|
0x00, 0xff, 0xff, 0xf0, 0x9e, 0xc6, 0x34, 0x0d, 0x04, 0x00, 0x00,
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,5 +39,6 @@ message ApplicationMetadataMessage {
|
||||||
CHAT_IDENTITY = 24;
|
CHAT_IDENTITY = 24;
|
||||||
COMMUNITY_DESCRIPTION = 25;
|
COMMUNITY_DESCRIPTION = 25;
|
||||||
COMMUNITY_INVITATION = 26;
|
COMMUNITY_INVITATION = 26;
|
||||||
|
COMMUNITY_REQUEST_TO_JOIN = 27;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,34 @@ var _ = math.Inf
|
||||||
// proto package needs to be updated.
|
// proto package needs to be updated.
|
||||||
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
|
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
|
||||||
|
|
||||||
|
type CommunityMember_Roles int32
|
||||||
|
|
||||||
|
const (
|
||||||
|
CommunityMember_UNKNOWN_ROLE CommunityMember_Roles = 0
|
||||||
|
CommunityMember_ROLE_ALL CommunityMember_Roles = 1
|
||||||
|
CommunityMember_ROLE_MANAGE_USERS CommunityMember_Roles = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
var CommunityMember_Roles_name = map[int32]string{
|
||||||
|
0: "UNKNOWN_ROLE",
|
||||||
|
1: "ROLE_ALL",
|
||||||
|
2: "ROLE_MANAGE_USERS",
|
||||||
|
}
|
||||||
|
|
||||||
|
var CommunityMember_Roles_value = map[string]int32{
|
||||||
|
"UNKNOWN_ROLE": 0,
|
||||||
|
"ROLE_ALL": 1,
|
||||||
|
"ROLE_MANAGE_USERS": 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x CommunityMember_Roles) String() string {
|
||||||
|
return proto.EnumName(CommunityMember_Roles_name, int32(x))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (CommunityMember_Roles) EnumDescriptor() ([]byte, []int) {
|
||||||
|
return fileDescriptor_f937943d74c1cd8b, []int{1, 0}
|
||||||
|
}
|
||||||
|
|
||||||
type CommunityPermissions_Access int32
|
type CommunityPermissions_Access int32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -115,9 +143,10 @@ func (m *Grant) GetClock() uint64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
type CommunityMember struct {
|
type CommunityMember struct {
|
||||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
Roles []CommunityMember_Roles `protobuf:"varint,1,rep,packed,name=roles,proto3,enum=protobuf.CommunityMember_Roles" json:"roles,omitempty"`
|
||||||
XXX_unrecognized []byte `json:"-"`
|
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||||
XXX_sizecache int32 `json:"-"`
|
XXX_unrecognized []byte `json:"-"`
|
||||||
|
XXX_sizecache int32 `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *CommunityMember) Reset() { *m = CommunityMember{} }
|
func (m *CommunityMember) Reset() { *m = CommunityMember{} }
|
||||||
|
@ -145,6 +174,13 @@ func (m *CommunityMember) XXX_DiscardUnknown() {
|
||||||
|
|
||||||
var xxx_messageInfo_CommunityMember proto.InternalMessageInfo
|
var xxx_messageInfo_CommunityMember proto.InternalMessageInfo
|
||||||
|
|
||||||
|
func (m *CommunityMember) GetRoles() []CommunityMember_Roles {
|
||||||
|
if m != nil {
|
||||||
|
return m.Roles
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type CommunityPermissions struct {
|
type CommunityPermissions struct {
|
||||||
EnsOnly bool `protobuf:"varint,1,opt,name=ens_only,json=ensOnly,proto3" json:"ens_only,omitempty"`
|
EnsOnly bool `protobuf:"varint,1,opt,name=ens_only,json=ensOnly,proto3" json:"ens_only,omitempty"`
|
||||||
// https://gitlab.matrix.org/matrix-org/olm/blob/master/docs/megolm.md is a candidate for the algorithm to be used in case we want to have private communityal chats, lighter than pairwise encryption using the DR, less secure, but more efficient for large number of participants
|
// https://gitlab.matrix.org/matrix-org/olm/blob/master/docs/megolm.md is a candidate for the algorithm to be used in case we want to have private communityal chats, lighter than pairwise encryption using the DR, less secure, but more efficient for large number of participants
|
||||||
|
@ -390,110 +426,126 @@ func (m *CommunityInvitation) GetPublicKey() []byte {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type CommunityRequestJoin struct {
|
type CommunityRequestToJoin struct {
|
||||||
EnsName string `protobuf:"bytes,1,opt,name=ens_name,json=ensName,proto3" json:"ens_name,omitempty"`
|
Clock uint64 `protobuf:"varint,1,opt,name=clock,proto3" json:"clock,omitempty"`
|
||||||
ChatId string `protobuf:"bytes,2,opt,name=chat_id,json=chatId,proto3" json:"chat_id,omitempty"`
|
EnsName string `protobuf:"bytes,2,opt,name=ens_name,json=ensName,proto3" json:"ens_name,omitempty"`
|
||||||
CommunityId []byte `protobuf:"bytes,3,opt,name=community_id,json=communityId,proto3" json:"community_id,omitempty"`
|
ChatId string `protobuf:"bytes,3,opt,name=chat_id,json=chatId,proto3" json:"chat_id,omitempty"`
|
||||||
|
CommunityId []byte `protobuf:"bytes,4,opt,name=community_id,json=communityId,proto3" json:"community_id,omitempty"`
|
||||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||||
XXX_unrecognized []byte `json:"-"`
|
XXX_unrecognized []byte `json:"-"`
|
||||||
XXX_sizecache int32 `json:"-"`
|
XXX_sizecache int32 `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *CommunityRequestJoin) Reset() { *m = CommunityRequestJoin{} }
|
func (m *CommunityRequestToJoin) Reset() { *m = CommunityRequestToJoin{} }
|
||||||
func (m *CommunityRequestJoin) String() string { return proto.CompactTextString(m) }
|
func (m *CommunityRequestToJoin) String() string { return proto.CompactTextString(m) }
|
||||||
func (*CommunityRequestJoin) ProtoMessage() {}
|
func (*CommunityRequestToJoin) ProtoMessage() {}
|
||||||
func (*CommunityRequestJoin) Descriptor() ([]byte, []int) {
|
func (*CommunityRequestToJoin) Descriptor() ([]byte, []int) {
|
||||||
return fileDescriptor_f937943d74c1cd8b, []int{6}
|
return fileDescriptor_f937943d74c1cd8b, []int{6}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *CommunityRequestJoin) XXX_Unmarshal(b []byte) error {
|
func (m *CommunityRequestToJoin) XXX_Unmarshal(b []byte) error {
|
||||||
return xxx_messageInfo_CommunityRequestJoin.Unmarshal(m, b)
|
return xxx_messageInfo_CommunityRequestToJoin.Unmarshal(m, b)
|
||||||
}
|
}
|
||||||
func (m *CommunityRequestJoin) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
func (m *CommunityRequestToJoin) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||||
return xxx_messageInfo_CommunityRequestJoin.Marshal(b, m, deterministic)
|
return xxx_messageInfo_CommunityRequestToJoin.Marshal(b, m, deterministic)
|
||||||
}
|
}
|
||||||
func (m *CommunityRequestJoin) XXX_Merge(src proto.Message) {
|
func (m *CommunityRequestToJoin) XXX_Merge(src proto.Message) {
|
||||||
xxx_messageInfo_CommunityRequestJoin.Merge(m, src)
|
xxx_messageInfo_CommunityRequestToJoin.Merge(m, src)
|
||||||
}
|
}
|
||||||
func (m *CommunityRequestJoin) XXX_Size() int {
|
func (m *CommunityRequestToJoin) XXX_Size() int {
|
||||||
return xxx_messageInfo_CommunityRequestJoin.Size(m)
|
return xxx_messageInfo_CommunityRequestToJoin.Size(m)
|
||||||
}
|
}
|
||||||
func (m *CommunityRequestJoin) XXX_DiscardUnknown() {
|
func (m *CommunityRequestToJoin) XXX_DiscardUnknown() {
|
||||||
xxx_messageInfo_CommunityRequestJoin.DiscardUnknown(m)
|
xxx_messageInfo_CommunityRequestToJoin.DiscardUnknown(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
var xxx_messageInfo_CommunityRequestJoin proto.InternalMessageInfo
|
var xxx_messageInfo_CommunityRequestToJoin proto.InternalMessageInfo
|
||||||
|
|
||||||
func (m *CommunityRequestJoin) GetEnsName() string {
|
func (m *CommunityRequestToJoin) GetClock() uint64 {
|
||||||
|
if m != nil {
|
||||||
|
return m.Clock
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *CommunityRequestToJoin) GetEnsName() string {
|
||||||
if m != nil {
|
if m != nil {
|
||||||
return m.EnsName
|
return m.EnsName
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *CommunityRequestJoin) GetChatId() string {
|
func (m *CommunityRequestToJoin) GetChatId() string {
|
||||||
if m != nil {
|
if m != nil {
|
||||||
return m.ChatId
|
return m.ChatId
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *CommunityRequestJoin) GetCommunityId() []byte {
|
func (m *CommunityRequestToJoin) GetCommunityId() []byte {
|
||||||
if m != nil {
|
if m != nil {
|
||||||
return m.CommunityId
|
return m.CommunityId
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type CommunityRequestJoinResponse struct {
|
type CommunityRequestToJoinResponse struct {
|
||||||
Community *CommunityDescription `protobuf:"bytes,1,opt,name=community,proto3" json:"community,omitempty"`
|
Clock uint64 `protobuf:"varint,1,opt,name=clock,proto3" json:"clock,omitempty"`
|
||||||
Accepted bool `protobuf:"varint,2,opt,name=accepted,proto3" json:"accepted,omitempty"`
|
Community *CommunityDescription `protobuf:"bytes,2,opt,name=community,proto3" json:"community,omitempty"`
|
||||||
Grant []byte `protobuf:"bytes,3,opt,name=grant,proto3" json:"grant,omitempty"`
|
Accepted bool `protobuf:"varint,3,opt,name=accepted,proto3" json:"accepted,omitempty"`
|
||||||
|
Grant []byte `protobuf:"bytes,4,opt,name=grant,proto3" json:"grant,omitempty"`
|
||||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||||
XXX_unrecognized []byte `json:"-"`
|
XXX_unrecognized []byte `json:"-"`
|
||||||
XXX_sizecache int32 `json:"-"`
|
XXX_sizecache int32 `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *CommunityRequestJoinResponse) Reset() { *m = CommunityRequestJoinResponse{} }
|
func (m *CommunityRequestToJoinResponse) Reset() { *m = CommunityRequestToJoinResponse{} }
|
||||||
func (m *CommunityRequestJoinResponse) String() string { return proto.CompactTextString(m) }
|
func (m *CommunityRequestToJoinResponse) String() string { return proto.CompactTextString(m) }
|
||||||
func (*CommunityRequestJoinResponse) ProtoMessage() {}
|
func (*CommunityRequestToJoinResponse) ProtoMessage() {}
|
||||||
func (*CommunityRequestJoinResponse) Descriptor() ([]byte, []int) {
|
func (*CommunityRequestToJoinResponse) Descriptor() ([]byte, []int) {
|
||||||
return fileDescriptor_f937943d74c1cd8b, []int{7}
|
return fileDescriptor_f937943d74c1cd8b, []int{7}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *CommunityRequestJoinResponse) XXX_Unmarshal(b []byte) error {
|
func (m *CommunityRequestToJoinResponse) XXX_Unmarshal(b []byte) error {
|
||||||
return xxx_messageInfo_CommunityRequestJoinResponse.Unmarshal(m, b)
|
return xxx_messageInfo_CommunityRequestToJoinResponse.Unmarshal(m, b)
|
||||||
}
|
}
|
||||||
func (m *CommunityRequestJoinResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
func (m *CommunityRequestToJoinResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||||
return xxx_messageInfo_CommunityRequestJoinResponse.Marshal(b, m, deterministic)
|
return xxx_messageInfo_CommunityRequestToJoinResponse.Marshal(b, m, deterministic)
|
||||||
}
|
}
|
||||||
func (m *CommunityRequestJoinResponse) XXX_Merge(src proto.Message) {
|
func (m *CommunityRequestToJoinResponse) XXX_Merge(src proto.Message) {
|
||||||
xxx_messageInfo_CommunityRequestJoinResponse.Merge(m, src)
|
xxx_messageInfo_CommunityRequestToJoinResponse.Merge(m, src)
|
||||||
}
|
}
|
||||||
func (m *CommunityRequestJoinResponse) XXX_Size() int {
|
func (m *CommunityRequestToJoinResponse) XXX_Size() int {
|
||||||
return xxx_messageInfo_CommunityRequestJoinResponse.Size(m)
|
return xxx_messageInfo_CommunityRequestToJoinResponse.Size(m)
|
||||||
}
|
}
|
||||||
func (m *CommunityRequestJoinResponse) XXX_DiscardUnknown() {
|
func (m *CommunityRequestToJoinResponse) XXX_DiscardUnknown() {
|
||||||
xxx_messageInfo_CommunityRequestJoinResponse.DiscardUnknown(m)
|
xxx_messageInfo_CommunityRequestToJoinResponse.DiscardUnknown(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
var xxx_messageInfo_CommunityRequestJoinResponse proto.InternalMessageInfo
|
var xxx_messageInfo_CommunityRequestToJoinResponse proto.InternalMessageInfo
|
||||||
|
|
||||||
func (m *CommunityRequestJoinResponse) GetCommunity() *CommunityDescription {
|
func (m *CommunityRequestToJoinResponse) GetClock() uint64 {
|
||||||
|
if m != nil {
|
||||||
|
return m.Clock
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *CommunityRequestToJoinResponse) GetCommunity() *CommunityDescription {
|
||||||
if m != nil {
|
if m != nil {
|
||||||
return m.Community
|
return m.Community
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *CommunityRequestJoinResponse) GetAccepted() bool {
|
func (m *CommunityRequestToJoinResponse) GetAccepted() bool {
|
||||||
if m != nil {
|
if m != nil {
|
||||||
return m.Accepted
|
return m.Accepted
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *CommunityRequestJoinResponse) GetGrant() []byte {
|
func (m *CommunityRequestToJoinResponse) GetGrant() []byte {
|
||||||
if m != nil {
|
if m != nil {
|
||||||
return m.Grant
|
return m.Grant
|
||||||
}
|
}
|
||||||
|
@ -501,6 +553,7 @@ func (m *CommunityRequestJoinResponse) GetGrant() []byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
proto.RegisterEnum("protobuf.CommunityMember_Roles", CommunityMember_Roles_name, CommunityMember_Roles_value)
|
||||||
proto.RegisterEnum("protobuf.CommunityPermissions_Access", CommunityPermissions_Access_name, CommunityPermissions_Access_value)
|
proto.RegisterEnum("protobuf.CommunityPermissions_Access", CommunityPermissions_Access_name, CommunityPermissions_Access_value)
|
||||||
proto.RegisterType((*Grant)(nil), "protobuf.Grant")
|
proto.RegisterType((*Grant)(nil), "protobuf.Grant")
|
||||||
proto.RegisterType((*CommunityMember)(nil), "protobuf.CommunityMember")
|
proto.RegisterType((*CommunityMember)(nil), "protobuf.CommunityMember")
|
||||||
|
@ -511,8 +564,8 @@ func init() {
|
||||||
proto.RegisterType((*CommunityChat)(nil), "protobuf.CommunityChat")
|
proto.RegisterType((*CommunityChat)(nil), "protobuf.CommunityChat")
|
||||||
proto.RegisterMapType((map[string]*CommunityMember)(nil), "protobuf.CommunityChat.MembersEntry")
|
proto.RegisterMapType((map[string]*CommunityMember)(nil), "protobuf.CommunityChat.MembersEntry")
|
||||||
proto.RegisterType((*CommunityInvitation)(nil), "protobuf.CommunityInvitation")
|
proto.RegisterType((*CommunityInvitation)(nil), "protobuf.CommunityInvitation")
|
||||||
proto.RegisterType((*CommunityRequestJoin)(nil), "protobuf.CommunityRequestJoin")
|
proto.RegisterType((*CommunityRequestToJoin)(nil), "protobuf.CommunityRequestToJoin")
|
||||||
proto.RegisterType((*CommunityRequestJoinResponse)(nil), "protobuf.CommunityRequestJoinResponse")
|
proto.RegisterType((*CommunityRequestToJoinResponse)(nil), "protobuf.CommunityRequestToJoinResponse")
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -520,47 +573,51 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
var fileDescriptor_f937943d74c1cd8b = []byte{
|
var fileDescriptor_f937943d74c1cd8b = []byte{
|
||||||
// 662 bytes of a gzipped FileDescriptorProto
|
// 734 bytes of a gzipped FileDescriptorProto
|
||||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x54, 0xdd, 0x6e, 0xd3, 0x4a,
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x54, 0xdd, 0x6e, 0xd3, 0x4a,
|
||||||
0x10, 0x3e, 0xb6, 0x9b, 0xc4, 0x99, 0xf4, 0x27, 0xdd, 0xf6, 0x9c, 0xba, 0x39, 0x80, 0x82, 0x05,
|
0x10, 0xee, 0xe6, 0xd7, 0x99, 0xa4, 0xa9, 0xbb, 0xfd, 0x73, 0x73, 0x74, 0x7a, 0x72, 0x2c, 0x90,
|
||||||
0x52, 0x10, 0x22, 0x48, 0xe9, 0x0d, 0x42, 0xfc, 0x95, 0x62, 0x81, 0x29, 0x75, 0xda, 0x4d, 0x0a,
|
0x82, 0x10, 0x41, 0x4a, 0x85, 0x84, 0x10, 0x14, 0x42, 0xb1, 0x8a, 0x69, 0xe2, 0xb4, 0x9b, 0x04,
|
||||||
0xe2, 0xca, 0x72, 0xec, 0x05, 0xac, 0xc6, 0x6b, 0xe3, 0x75, 0x22, 0xe5, 0x25, 0xb8, 0xe6, 0x82,
|
0xc4, 0x95, 0xe5, 0x38, 0x0b, 0x58, 0x4d, 0xec, 0xe0, 0x75, 0x22, 0xe5, 0x01, 0x90, 0x78, 0x04,
|
||||||
0xc7, 0xe2, 0x01, 0x78, 0x14, 0xe4, 0x5d, 0x3b, 0x76, 0xc1, 0x85, 0x4a, 0x88, 0xab, 0x64, 0x77,
|
0x2e, 0xb8, 0xe6, 0x89, 0x78, 0x00, 0x1e, 0x05, 0x79, 0x37, 0x89, 0xdd, 0x92, 0x94, 0x4a, 0x88,
|
||||||
0xf6, 0xfb, 0x66, 0xe6, 0x9b, 0xf1, 0x07, 0x9b, 0x6e, 0x18, 0x04, 0x33, 0xea, 0x27, 0x3e, 0x61,
|
0x2b, 0x7b, 0x76, 0x66, 0xbe, 0x9d, 0xf9, 0x66, 0xf6, 0x83, 0x4d, 0xdb, 0x1b, 0x0e, 0xc7, 0xae,
|
||||||
0xfd, 0x28, 0x0e, 0x93, 0x10, 0xa9, 0xfc, 0x67, 0x32, 0x7b, 0xd7, 0xd9, 0x72, 0x3f, 0x38, 0x89,
|
0x13, 0x38, 0x94, 0x55, 0x47, 0xbe, 0x17, 0x78, 0x58, 0xe2, 0x9f, 0xde, 0xf8, 0x5d, 0x69, 0xcb,
|
||||||
0xed, 0x7b, 0x84, 0x26, 0x7e, 0xb2, 0x10, 0x61, 0x7d, 0x0e, 0xb5, 0xe7, 0xb1, 0x43, 0x13, 0x74,
|
0xfe, 0x60, 0x05, 0xa6, 0xd3, 0xa7, 0x6e, 0xe0, 0x04, 0x53, 0xe1, 0x56, 0x27, 0x90, 0x3e, 0xf1,
|
||||||
0x1d, 0x56, 0x73, 0xf0, 0xc2, 0xf6, 0x3d, 0x4d, 0xea, 0x4a, 0xbd, 0x55, 0xdc, 0x5a, 0xde, 0x99,
|
0x2d, 0x37, 0xc0, 0xff, 0x43, 0x61, 0x9e, 0x3c, 0x35, 0x9d, 0xbe, 0x82, 0xca, 0xa8, 0x52, 0x20,
|
||||||
0x1e, 0xfa, 0x1f, 0x9a, 0x01, 0x09, 0x26, 0x24, 0x4e, 0xe3, 0x32, 0x8f, 0xab, 0xe2, 0xc2, 0xf4,
|
0xf9, 0xc5, 0x99, 0xde, 0xc7, 0xff, 0x40, 0x6e, 0x48, 0x87, 0x3d, 0xea, 0x87, 0xfe, 0x04, 0xf7,
|
||||||
0xd0, 0x0e, 0x34, 0x32, 0x7e, 0x4d, 0xe9, 0x4a, 0xbd, 0x26, 0xae, 0xa7, 0x47, 0xd3, 0x43, 0xdb,
|
0x4b, 0xe2, 0x40, 0xef, 0xe3, 0x3d, 0xc8, 0xce, 0xf0, 0x95, 0x64, 0x19, 0x55, 0x72, 0x24, 0x13,
|
||||||
0x50, 0x73, 0xa7, 0xa1, 0x7b, 0xa6, 0xad, 0x74, 0xa5, 0xde, 0x0a, 0x16, 0x07, 0x7d, 0x13, 0x36,
|
0x9a, 0x7a, 0x1f, 0x6f, 0x43, 0xda, 0x1e, 0x78, 0xf6, 0x85, 0x92, 0x2a, 0xa3, 0x4a, 0x8a, 0x08,
|
||||||
0x0e, 0x72, 0xea, 0x23, 0xce, 0xa1, 0x7f, 0x93, 0x60, 0x7b, 0x79, 0x77, 0x4c, 0xe2, 0xc0, 0x67,
|
0x43, 0xfd, 0x8c, 0x60, 0xe3, 0x78, 0x8e, 0xdd, 0xe4, 0x20, 0xf8, 0x01, 0xa4, 0x7d, 0x6f, 0x40,
|
||||||
0xcc, 0x0f, 0x29, 0x43, 0xbb, 0xa0, 0x12, 0xca, 0xec, 0x90, 0x4e, 0x17, 0xbc, 0x2c, 0x15, 0x37,
|
0x99, 0x82, 0xca, 0xc9, 0x4a, 0xb1, 0xf6, 0x5f, 0x75, 0x5e, 0x7a, 0xf5, 0x4a, 0x64, 0x95, 0x84,
|
||||||
0x08, 0x65, 0x43, 0x3a, 0x5d, 0x20, 0x0d, 0x1a, 0x51, 0xec, 0xcf, 0x9d, 0x84, 0xf0, 0x82, 0x54,
|
0x61, 0x44, 0x44, 0xab, 0x47, 0x90, 0xe6, 0x36, 0x96, 0xa1, 0xd0, 0x35, 0x4e, 0x8d, 0xd6, 0x1b,
|
||||||
0x9c, 0x1f, 0xd1, 0x43, 0xa8, 0x3b, 0xae, 0x4b, 0x18, 0xe3, 0xe5, 0xac, 0x0f, 0x6e, 0xf6, 0x73,
|
0xc3, 0x24, 0xad, 0x86, 0x26, 0xaf, 0xe1, 0x02, 0x48, 0xe1, 0x9f, 0x59, 0x6f, 0x34, 0x64, 0x84,
|
||||||
0x21, 0xfa, 0x55, 0x49, 0xfa, 0xfb, 0xfc, 0x31, 0xce, 0x40, 0xfa, 0x18, 0xea, 0xe2, 0x06, 0x21,
|
0x77, 0x60, 0x93, 0x5b, 0xcd, 0xba, 0x51, 0x3f, 0xd1, 0xcc, 0x6e, 0x5b, 0x23, 0x6d, 0x39, 0xa1,
|
||||||
0x58, 0x3f, 0xb5, 0x0e, 0xad, 0xe1, 0x1b, 0xcb, 0xde, 0x3f, 0x38, 0x30, 0x46, 0xa3, 0xf6, 0x3f,
|
0xfe, 0x40, 0xb0, 0xbd, 0xb8, 0xe0, 0x8c, 0xfa, 0x43, 0x87, 0x31, 0xc7, 0x73, 0x19, 0xde, 0x07,
|
||||||
0x68, 0x13, 0xd6, 0xac, 0xa1, 0x7d, 0x64, 0x1c, 0x3d, 0x35, 0xf0, 0xe8, 0x85, 0x79, 0xdc, 0x96,
|
0x89, 0xba, 0xcc, 0xf4, 0xdc, 0xc1, 0x94, 0xd3, 0x21, 0x91, 0x2c, 0x75, 0x59, 0xcb, 0x1d, 0x4c,
|
||||||
0xd0, 0x16, 0x6c, 0x98, 0xd6, 0x6b, 0x73, 0xbc, 0x3f, 0x36, 0x87, 0x96, 0x3d, 0xb4, 0x5e, 0xbd,
|
0xb1, 0x02, 0xd9, 0x91, 0xef, 0x4c, 0xac, 0x80, 0x72, 0x22, 0x24, 0x32, 0x37, 0xf1, 0x13, 0xc8,
|
||||||
0x6d, 0xcb, 0x68, 0x1d, 0x60, 0x68, 0xd9, 0xd8, 0x38, 0x39, 0x35, 0x46, 0xe3, 0xb6, 0xa2, 0x7f,
|
0x58, 0xb6, 0x4d, 0x19, 0xe3, 0x34, 0x14, 0x6b, 0xb7, 0x97, 0x74, 0x11, 0xbb, 0xa4, 0x5a, 0xe7,
|
||||||
0x55, 0x4a, 0x2d, 0x3e, 0x23, 0xcc, 0x8d, 0xfd, 0x28, 0xf1, 0x43, 0x5a, 0x88, 0x24, 0x95, 0x44,
|
0xc1, 0x64, 0x96, 0xa4, 0x76, 0x20, 0x23, 0x4e, 0x30, 0x86, 0xe2, 0xbc, 0x9b, 0xfa, 0xf1, 0xb1,
|
||||||
0x42, 0x06, 0x34, 0x84, 0xbe, 0x4c, 0x93, 0xbb, 0x4a, 0xaf, 0x35, 0xb8, 0x5d, 0xd1, 0x44, 0x89,
|
0xd6, 0x6e, 0xcb, 0x6b, 0x78, 0x13, 0xd6, 0x8d, 0x96, 0xd9, 0xd4, 0x9a, 0xcf, 0x35, 0xd2, 0x7e,
|
||||||
0xa6, 0x2f, 0x94, 0x64, 0x06, 0x4d, 0xe2, 0x05, 0xce, 0xb1, 0xe8, 0x09, 0xb4, 0xa2, 0xa2, 0x53,
|
0xa9, 0x9f, 0xc9, 0x08, 0x6f, 0xc1, 0x86, 0x6e, 0xbc, 0xd6, 0x3b, 0xf5, 0x8e, 0xde, 0x32, 0xcc,
|
||||||
0xae, 0x47, 0x6b, 0x70, 0xed, 0xd7, 0x7a, 0xe0, 0x32, 0x04, 0x0d, 0x40, 0xcd, 0xf7, 0x46, 0xab,
|
0x96, 0xd1, 0x78, 0x2b, 0x27, 0x70, 0x11, 0xa0, 0x65, 0x98, 0x44, 0x3b, 0xef, 0x6a, 0xed, 0x8e,
|
||||||
0x71, 0xf8, 0x7f, 0x25, 0x38, 0x9f, 0xb3, 0x88, 0xe2, 0xe5, 0x3b, 0xf4, 0x18, 0x6a, 0xe9, 0x06,
|
0x9c, 0x54, 0xbf, 0x27, 0x63, 0x2d, 0xbe, 0xa0, 0xcc, 0xf6, 0x9d, 0x51, 0xe0, 0x78, 0x6e, 0x34,
|
||||||
0x30, 0xad, 0xce, 0x4b, 0xbf, 0xf5, 0x9b, 0xd2, 0x53, 0x96, 0xac, 0x70, 0x81, 0xeb, 0x9c, 0xc2,
|
0x1c, 0x14, 0x1b, 0x0e, 0xd6, 0x20, 0x2b, 0xe6, 0xca, 0x94, 0x44, 0x39, 0x59, 0xc9, 0xd7, 0xee,
|
||||||
0x6a, 0xb9, 0x1f, 0xd4, 0x06, 0xe5, 0x8c, 0x88, 0x0d, 0x68, 0xe2, 0xf4, 0x2f, 0xba, 0x0b, 0xb5,
|
0x2e, 0x69, 0x22, 0x06, 0x53, 0x15, 0x63, 0x61, 0x9a, 0x1b, 0xf8, 0x53, 0x32, 0xcf, 0xc5, 0xcf,
|
||||||
0xb9, 0x33, 0x9d, 0x89, 0xd9, 0xb7, 0x06, 0xbb, 0x15, 0x29, 0x04, 0x03, 0x16, 0xef, 0xee, 0xcb,
|
0x20, 0x3f, 0x8a, 0x3a, 0xe5, 0x7c, 0xe4, 0x6b, 0x07, 0xd7, 0xf3, 0x41, 0xe2, 0x29, 0xb8, 0x06,
|
||||||
0xf7, 0xa4, 0xce, 0x09, 0x40, 0x91, 0xab, 0x82, 0xf4, 0xce, 0x79, 0xd2, 0x9d, 0x0a, 0xd2, 0x14,
|
0xd2, 0x7c, 0x5f, 0x95, 0x34, 0x4f, 0xdf, 0x8d, 0xa5, 0xf3, 0xfd, 0x12, 0x5e, 0xb2, 0x88, 0xc3,
|
||||||
0x5f, 0xa2, 0xd4, 0xbf, 0xc8, 0xb0, 0x76, 0x2e, 0x88, 0x1e, 0x15, 0x93, 0x93, 0x78, 0xfb, 0x37,
|
0x4f, 0x21, 0x1d, 0x6e, 0x1e, 0x53, 0x32, 0xbc, 0xf4, 0x3b, 0xbf, 0x29, 0x3d, 0x44, 0x99, 0x15,
|
||||||
0x2e, 0xa0, 0xb9, 0xdc, 0xc8, 0xe4, 0x3f, 0x1b, 0x99, 0x72, 0xb9, 0x91, 0xfd, 0x25, 0xc5, 0xf5,
|
0x2e, 0xf2, 0x4a, 0x5d, 0x28, 0xc4, 0xfb, 0xc1, 0x32, 0x24, 0x2f, 0xa8, 0xd8, 0x80, 0x1c, 0x09,
|
||||||
0xcf, 0x12, 0x6c, 0x2d, 0xc3, 0x26, 0x9d, 0xfb, 0x89, 0xc3, 0x97, 0x7e, 0x0f, 0xfe, 0x2d, 0x2c,
|
0x7f, 0xf1, 0x7d, 0x48, 0x4f, 0xac, 0xc1, 0x58, 0xcc, 0x3e, 0x5f, 0xdb, 0x5f, 0xb9, 0xa8, 0x44,
|
||||||
0xc7, 0x2b, 0x76, 0x21, 0xf3, 0x9e, 0x6d, 0xf7, 0x82, 0x2f, 0xe5, 0x7d, 0x6a, 0x58, 0x99, 0x01,
|
0xc4, 0x3d, 0x4a, 0x3c, 0x44, 0xa5, 0x73, 0x80, 0xe8, 0xae, 0x25, 0xa0, 0xf7, 0x2e, 0x83, 0xee,
|
||||||
0x89, 0xc3, 0xc5, 0xee, 0x73, 0x15, 0x20, 0x9a, 0x4d, 0xa6, 0xbe, 0x6b, 0xa7, 0x9d, 0xac, 0x70,
|
0x2d, 0x01, 0x0d, 0xf3, 0x63, 0x90, 0xea, 0xd7, 0x04, 0xac, 0x5f, 0x72, 0xe2, 0xa3, 0x68, 0x72,
|
||||||
0x4c, 0x53, 0xdc, 0x1c, 0x92, 0x85, 0x1e, 0x94, 0xbe, 0x47, 0x4c, 0x3e, 0xce, 0x08, 0x4b, 0x5e,
|
0x88, 0xb7, 0x7f, 0x6b, 0x05, 0xcc, 0xcd, 0x46, 0x96, 0xf8, 0xb3, 0x91, 0x25, 0x6f, 0x36, 0xb2,
|
||||||
0x86, 0x3e, 0xcd, 0x2d, 0x87, 0x3a, 0x01, 0xc9, 0xda, 0x4f, 0x2d, 0xc7, 0x72, 0x02, 0x52, 0x4e,
|
0xbf, 0xc4, 0xb8, 0xfa, 0x05, 0xc1, 0xd6, 0xc2, 0xad, 0xbb, 0x13, 0x27, 0xb0, 0xf8, 0xd2, 0x1f,
|
||||||
0x25, 0x9f, 0x4b, 0xf5, 0xa3, 0x83, 0x2a, 0x3f, 0x39, 0xa8, 0xfe, 0x49, 0x82, 0x2b, 0x55, 0xf9,
|
0xc2, 0x4e, 0x24, 0x75, 0xfd, 0x68, 0x17, 0x66, 0x9a, 0xb7, 0x6d, 0xaf, 0x78, 0x29, 0xef, 0x43,
|
||||||
0x30, 0x61, 0x51, 0x48, 0x19, 0x41, 0x0f, 0xa0, 0xb9, 0x7c, 0xcf, 0x13, 0x57, 0x4f, 0xbd, 0x24,
|
0xa1, 0x9c, 0x09, 0x9f, 0x30, 0x56, 0xab, 0xde, 0xbf, 0x00, 0xa3, 0x71, 0x6f, 0xe0, 0xd8, 0x66,
|
||||||
0x08, 0x2e, 0x00, 0xa8, 0x03, 0x6a, 0x6a, 0x5f, 0x51, 0x42, 0xbc, 0xcc, 0x0e, 0x97, 0xe7, 0x42,
|
0xd8, 0x49, 0x8a, 0xe7, 0xe4, 0xc4, 0xc9, 0x29, 0x9d, 0xaa, 0x9f, 0x10, 0xec, 0x2e, 0x4a, 0x23,
|
||||||
0x37, 0xa5, 0xa4, 0xdb, 0xa4, 0xce, 0xb9, 0xf7, 0xbe, 0x07, 0x00, 0x00, 0xff, 0xff, 0x84, 0x86,
|
0xf4, 0xe3, 0x98, 0xb2, 0xa0, 0xe3, 0xbd, 0xf2, 0x9c, 0x55, 0x4f, 0x72, 0xa6, 0x45, 0xae, 0x35,
|
||||||
0xd5, 0x32, 0x39, 0x06, 0x00, 0x00,
|
0x14, 0x1c, 0xe4, 0xb8, 0x16, 0x19, 0xd6, 0x90, 0xae, 0xae, 0xe1, 0xaa, 0xa4, 0xa7, 0x7e, 0x91,
|
||||||
|
0x74, 0xf5, 0x1b, 0x82, 0x83, 0xe5, 0x75, 0x10, 0xca, 0x46, 0x9e, 0xcb, 0xe8, 0x8a, 0x7a, 0x1e,
|
||||||
|
0x43, 0x6e, 0x81, 0x73, 0xcd, 0x9a, 0xc4, 0x18, 0x24, 0x51, 0x02, 0x2e, 0x81, 0x14, 0xea, 0xdd,
|
||||||
|
0x28, 0xa0, 0xa2, 0x66, 0x89, 0x2c, 0xec, 0x88, 0xe8, 0x54, 0x8c, 0xe8, 0x5e, 0x86, 0x63, 0x1f,
|
||||||
|
0xfe, 0x0c, 0x00, 0x00, 0xff, 0xff, 0x1a, 0x7c, 0x38, 0x45, 0xe2, 0x06, 0x00, 0x00,
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,12 @@ message Grant {
|
||||||
}
|
}
|
||||||
|
|
||||||
message CommunityMember {
|
message CommunityMember {
|
||||||
|
enum Roles {
|
||||||
|
UNKNOWN_ROLE = 0;
|
||||||
|
ROLE_ALL = 1;
|
||||||
|
ROLE_MANAGE_USERS = 2;
|
||||||
|
}
|
||||||
|
repeated Roles roles = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message CommunityPermissions {
|
message CommunityPermissions {
|
||||||
|
@ -49,14 +55,16 @@ message CommunityInvitation {
|
||||||
bytes public_key = 4;
|
bytes public_key = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message CommunityRequestJoin {
|
message CommunityRequestToJoin {
|
||||||
string ens_name = 1;
|
uint64 clock = 1;
|
||||||
string chat_id = 2;
|
string ens_name = 2;
|
||||||
bytes community_id = 3;
|
string chat_id = 3;
|
||||||
|
bytes community_id = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message CommunityRequestJoinResponse {
|
message CommunityRequestToJoinResponse {
|
||||||
CommunityDescription community = 1;
|
uint64 clock = 1;
|
||||||
bool accepted = 2;
|
CommunityDescription community = 2;
|
||||||
bytes grant = 3;
|
bool accepted = 3;
|
||||||
|
bytes grant = 4;
|
||||||
}
|
}
|
||||||
|
|
|
@ -185,8 +185,8 @@ func (s *MessengerPushNotificationSuite) TestReceivePushNotification() {
|
||||||
// Create one to one chat & send message
|
// Create one to one chat & send message
|
||||||
pkString := hex.EncodeToString(crypto.FromECDSAPub(&s.m.identity.PublicKey))
|
pkString := hex.EncodeToString(crypto.FromECDSAPub(&s.m.identity.PublicKey))
|
||||||
chat := CreateOneToOneChat(pkString, &s.m.identity.PublicKey, alice.transport)
|
chat := CreateOneToOneChat(pkString, &s.m.identity.PublicKey, alice.transport)
|
||||||
s.Require().NoError(alice.SaveChat(&chat))
|
s.Require().NoError(alice.SaveChat(chat))
|
||||||
inputMessage := buildTestMessage(chat)
|
inputMessage := buildTestMessage(*chat)
|
||||||
response, err := alice.SendChatMessage(context.Background(), inputMessage)
|
response, err := alice.SendChatMessage(context.Background(), inputMessage)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
messageIDString := response.Messages[0].ID
|
messageIDString := response.Messages[0].ID
|
||||||
|
@ -344,8 +344,8 @@ func (s *MessengerPushNotificationSuite) TestReceivePushNotificationFromContactO
|
||||||
// Create one to one chat & send message
|
// Create one to one chat & send message
|
||||||
pkString := hex.EncodeToString(crypto.FromECDSAPub(&s.m.identity.PublicKey))
|
pkString := hex.EncodeToString(crypto.FromECDSAPub(&s.m.identity.PublicKey))
|
||||||
chat := CreateOneToOneChat(pkString, &s.m.identity.PublicKey, alice.transport)
|
chat := CreateOneToOneChat(pkString, &s.m.identity.PublicKey, alice.transport)
|
||||||
s.Require().NoError(alice.SaveChat(&chat))
|
s.Require().NoError(alice.SaveChat(chat))
|
||||||
inputMessage := buildTestMessage(chat)
|
inputMessage := buildTestMessage(*chat)
|
||||||
response, err := alice.SendChatMessage(context.Background(), inputMessage)
|
response, err := alice.SendChatMessage(context.Background(), inputMessage)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
messageIDString := response.Messages[0].ID
|
messageIDString := response.Messages[0].ID
|
||||||
|
@ -500,8 +500,8 @@ func (s *MessengerPushNotificationSuite) TestReceivePushNotificationRetries() {
|
||||||
// Create one to one chat & send message
|
// Create one to one chat & send message
|
||||||
pkString := hex.EncodeToString(crypto.FromECDSAPub(&s.m.identity.PublicKey))
|
pkString := hex.EncodeToString(crypto.FromECDSAPub(&s.m.identity.PublicKey))
|
||||||
chat := CreateOneToOneChat(pkString, &s.m.identity.PublicKey, alice.transport)
|
chat := CreateOneToOneChat(pkString, &s.m.identity.PublicKey, alice.transport)
|
||||||
s.Require().NoError(alice.SaveChat(&chat))
|
s.Require().NoError(alice.SaveChat(chat))
|
||||||
inputMessage := buildTestMessage(chat)
|
inputMessage := buildTestMessage(*chat)
|
||||||
_, err = alice.SendChatMessage(context.Background(), inputMessage)
|
_, err = alice.SendChatMessage(context.Background(), inputMessage)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
|
@ -571,7 +571,7 @@ func (s *MessengerPushNotificationSuite) TestReceivePushNotificationRetries() {
|
||||||
s.Require().NotEqual(newBobServers[0].AccessToken, bobServers[0].AccessToken)
|
s.Require().NotEqual(newBobServers[0].AccessToken, bobServers[0].AccessToken)
|
||||||
|
|
||||||
// Send another message, here the token will not be valid
|
// Send another message, here the token will not be valid
|
||||||
inputMessage = buildTestMessage(chat)
|
inputMessage = buildTestMessage(*chat)
|
||||||
response, err := alice.SendChatMessage(context.Background(), inputMessage)
|
response, err := alice.SendChatMessage(context.Background(), inputMessage)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
messageIDString := response.Messages[0].ID
|
messageIDString := response.Messages[0].ID
|
||||||
|
@ -720,16 +720,16 @@ func (s *MessengerPushNotificationSuite) TestReceivePushNotificationMention() {
|
||||||
|
|
||||||
// Create public chat and join for both alice and bob
|
// Create public chat and join for both alice and bob
|
||||||
chat := CreatePublicChat("status", s.m.transport)
|
chat := CreatePublicChat("status", s.m.transport)
|
||||||
err = bob.SaveChat(&chat)
|
err = bob.SaveChat(chat)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
err = bob.Join(chat)
|
_, err = bob.Join(chat)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
err = alice.SaveChat(&chat)
|
err = alice.SaveChat(chat)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
err = alice.Join(chat)
|
_, err = alice.Join(chat)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
// Register bob
|
// Register bob
|
||||||
|
@ -772,7 +772,7 @@ func (s *MessengerPushNotificationSuite) TestReceivePushNotificationMention() {
|
||||||
bobServers, err := bob.GetPushNotificationsServers()
|
bobServers, err := bob.GetPushNotificationsServers()
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
inputMessage := buildTestMessage(chat)
|
inputMessage := buildTestMessage(*chat)
|
||||||
// message contains a mention
|
// message contains a mention
|
||||||
inputMessage.Text = "Hey @" + types.EncodeHex(crypto.FromECDSAPub(&bob.identity.PublicKey))
|
inputMessage.Text = "Hey @" + types.EncodeHex(crypto.FromECDSAPub(&bob.identity.PublicKey))
|
||||||
response, err := alice.SendChatMessage(context.Background(), inputMessage)
|
response, err := alice.SendChatMessage(context.Background(), inputMessage)
|
||||||
|
|
|
@ -460,7 +460,8 @@ func (s *Server) listenToPublicKeyQueryTopic(hashedPublicKey []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
encodedPublicKey := hex.EncodeToString(hashedPublicKey)
|
encodedPublicKey := hex.EncodeToString(hashedPublicKey)
|
||||||
return s.messageProcessor.JoinPublic(encodedPublicKey)
|
_, err := s.messageProcessor.JoinPublic(encodedPublicKey)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// buildPushNotificationRegistrationResponse will check the registration is valid, save it, and listen to the topic for the queries
|
// buildPushNotificationRegistrationResponse will check the registration is valid, save it, and listen to the topic for the queries
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
package requests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/status-im/status-go/eth-node/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ErrAcceptRequestToJoinCommunityInvalidID = errors.New("accept-request-to-join-community: invalid id")
|
||||||
|
|
||||||
|
type AcceptRequestToJoinCommunity struct {
|
||||||
|
ID types.HexBytes
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *AcceptRequestToJoinCommunity) Validate() error {
|
||||||
|
if len(j.ID) == 0 {
|
||||||
|
return ErrAcceptRequestToJoinCommunityInvalidID
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
package requests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
userimages "github.com/status-im/status-go/images"
|
||||||
|
"github.com/status-im/status-go/protocol/images"
|
||||||
|
"github.com/status-im/status-go/protocol/protobuf"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrCreateCommunityInvalidName = errors.New("create-community: invalid name")
|
||||||
|
ErrCreateCommunityInvalidColor = errors.New("create-community: invalid color")
|
||||||
|
ErrCreateCommunityInvalidDescription = errors.New("create-community: invalid description")
|
||||||
|
ErrCreateCommunityInvalidMembership = errors.New("create-community: invalid membership")
|
||||||
|
)
|
||||||
|
|
||||||
|
type CreateCommunity struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Color string `json:"color"`
|
||||||
|
Membership protobuf.CommunityPermissions_Access `json:"membership"`
|
||||||
|
EnsOnly bool `json:"ensOnly"`
|
||||||
|
Image string `json:"image"`
|
||||||
|
ImageAx int `json:"imageAx"`
|
||||||
|
ImageAy int `json:"imageAy"`
|
||||||
|
ImageBx int `json:"imageBx"`
|
||||||
|
ImageBy int `json:"imageBy"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func adaptIdentityImageToProtobuf(img *userimages.IdentityImage) *protobuf.IdentityImage {
|
||||||
|
return &protobuf.IdentityImage{
|
||||||
|
Payload: img.Payload,
|
||||||
|
SourceType: protobuf.IdentityImage_RAW_PAYLOAD,
|
||||||
|
ImageType: images.ImageType(img.Payload),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CreateCommunity) Validate() error {
|
||||||
|
if c.Name == "" {
|
||||||
|
return ErrCreateCommunityInvalidName
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Description == "" {
|
||||||
|
return ErrCreateCommunityInvalidDescription
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Membership == protobuf.CommunityPermissions_UNKNOWN_ACCESS {
|
||||||
|
return ErrCreateCommunityInvalidMembership
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Color == "" {
|
||||||
|
return ErrCreateCommunityInvalidColor
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CreateCommunity) ToCommunityDescription() (*protobuf.CommunityDescription, error) {
|
||||||
|
ci := &protobuf.ChatIdentity{
|
||||||
|
DisplayName: c.Name,
|
||||||
|
Color: c.Color,
|
||||||
|
Description: c.Description,
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Image != "" {
|
||||||
|
log.Info("has-image", "image", c.Image)
|
||||||
|
ciis := make(map[string]*protobuf.IdentityImage)
|
||||||
|
imgs, err := userimages.GenerateIdentityImages(c.Image, c.ImageAx, c.ImageAy, c.ImageBx, c.ImageBy)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, img := range imgs {
|
||||||
|
ciis[img.Name] = adaptIdentityImageToProtobuf(img)
|
||||||
|
}
|
||||||
|
ci.Images = ciis
|
||||||
|
log.Info("set images", "images", ci)
|
||||||
|
}
|
||||||
|
|
||||||
|
description := &protobuf.CommunityDescription{
|
||||||
|
Identity: ci,
|
||||||
|
Permissions: &protobuf.CommunityPermissions{
|
||||||
|
Access: c.Membership,
|
||||||
|
EnsOnly: c.EnsOnly,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return description, nil
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package requests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/status-im/status-go/eth-node/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ErrCreateOneToOneChatInvalidID = errors.New("create-one-to-one-chat: invalid id")
|
||||||
|
|
||||||
|
type CreateOneToOneChat struct {
|
||||||
|
ID types.HexBytes
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *CreateOneToOneChat) Validate() error {
|
||||||
|
if len(j.ID) == 0 {
|
||||||
|
return ErrCreateOneToOneChatInvalidID
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package requests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/status-im/status-go/eth-node/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ErrDeclineRequestToJoinCommunityInvalidID = errors.New("accept-request-to-join-community: invalid id")
|
||||||
|
|
||||||
|
type DeclineRequestToJoinCommunity struct {
|
||||||
|
ID types.HexBytes
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *DeclineRequestToJoinCommunity) Validate() error {
|
||||||
|
if len(j.ID) == 0 {
|
||||||
|
return ErrDeclineRequestToJoinCommunityInvalidID
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
package requests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/status-im/status-go/eth-node/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ErrInviteUsersToCommunityInvalidID = errors.New("invite-users-to-community: invalid id")
|
||||||
|
var ErrInviteUsersToCommunityEmptyUsers = errors.New("invite-users-to-community: empty users")
|
||||||
|
|
||||||
|
type InviteUsersToCommunity struct {
|
||||||
|
CommunityID types.HexBytes
|
||||||
|
Users []types.HexBytes
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *InviteUsersToCommunity) Validate() error {
|
||||||
|
if len(j.CommunityID) == 0 {
|
||||||
|
return ErrInviteUsersToCommunityInvalidID
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(j.Users) == 0 {
|
||||||
|
return ErrInviteUsersToCommunityEmptyUsers
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package requests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/status-im/status-go/eth-node/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ErrRequestToJoinCommunityInvalidCommunityID = errors.New("request-to-join-community: invalid community id")
|
||||||
|
|
||||||
|
type RequestToJoinCommunity struct {
|
||||||
|
CommunityID types.HexBytes `json:"communityId"`
|
||||||
|
ENSName string `json:"ensName"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *RequestToJoinCommunity) Validate() error {
|
||||||
|
if len(j.CommunityID) == 0 {
|
||||||
|
return ErrRequestToJoinCommunityInvalidCommunityID
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
package requests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/status-im/status-go/eth-node/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ErrShareCommunityInvalidID = errors.New("share-community: invalid id")
|
||||||
|
var ErrShareCommunityEmptyUsers = errors.New("share-community: empty users")
|
||||||
|
|
||||||
|
type ShareCommunity struct {
|
||||||
|
CommunityID types.HexBytes
|
||||||
|
Users []types.HexBytes
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *ShareCommunity) Validate() error {
|
||||||
|
if len(j.CommunityID) == 0 {
|
||||||
|
return ErrShareCommunityInvalidID
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(j.Users) == 0 {
|
||||||
|
return ErrShareCommunityEmptyUsers
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -75,9 +75,6 @@ func (s *FiltersManager) Init(
|
||||||
chatIDs []string,
|
chatIDs []string,
|
||||||
publicKeys []*ecdsa.PublicKey,
|
publicKeys []*ecdsa.PublicKey,
|
||||||
) ([]*Filter, error) {
|
) ([]*Filter, error) {
|
||||||
logger := s.logger.With(zap.String("site", "Init"))
|
|
||||||
|
|
||||||
logger.Info("initializing")
|
|
||||||
|
|
||||||
// Load our contact code.
|
// Load our contact code.
|
||||||
_, err := s.LoadContactCode(&s.privateKey.PublicKey)
|
_, err := s.LoadContactCode(&s.privateKey.PublicKey)
|
||||||
|
@ -135,6 +132,36 @@ func (s *FiltersManager) InitPublicFilters(chatIDs []string) ([]*Filter, error)
|
||||||
return filters, nil
|
return filters, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *FiltersManager) InitCommunityFilters(pks []*ecdsa.PrivateKey) ([]*Filter, error) {
|
||||||
|
var filters []*Filter
|
||||||
|
s.mutex.Lock()
|
||||||
|
defer s.mutex.Unlock()
|
||||||
|
|
||||||
|
for _, pk := range pks {
|
||||||
|
|
||||||
|
identityStr := PublicKeyToStr(&pk.PublicKey)
|
||||||
|
rawFilter, err := s.addAsymmetric(identityStr, pk, true)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
|
||||||
|
}
|
||||||
|
filterID := identityStr + "-admin"
|
||||||
|
filter := &Filter{
|
||||||
|
ChatID: filterID,
|
||||||
|
FilterID: rawFilter.FilterID,
|
||||||
|
Topic: rawFilter.Topic,
|
||||||
|
Identity: identityStr,
|
||||||
|
Listen: true,
|
||||||
|
OneToOne: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
s.filters[filterID] = filter
|
||||||
|
|
||||||
|
filters = append(filters, filter)
|
||||||
|
}
|
||||||
|
return filters, nil
|
||||||
|
}
|
||||||
|
|
||||||
// DEPRECATED
|
// DEPRECATED
|
||||||
func (s *FiltersManager) InitWithFilters(filters []*Filter) ([]*Filter, error) {
|
func (s *FiltersManager) InitWithFilters(filters []*Filter) ([]*Filter, error) {
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -4,17 +4,18 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
|
|
||||||
|
"github.com/status-im/status-go/eth-node/crypto"
|
||||||
"github.com/status-im/status-go/eth-node/types"
|
"github.com/status-im/status-go/eth-node/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Transport interface {
|
type Transport interface {
|
||||||
Stop() error
|
Stop() error
|
||||||
|
|
||||||
JoinPrivate(publicKey *ecdsa.PublicKey) error
|
JoinPrivate(publicKey *ecdsa.PublicKey) (*Filter, error)
|
||||||
LeavePrivate(publicKey *ecdsa.PublicKey) error
|
LeavePrivate(publicKey *ecdsa.PublicKey) error
|
||||||
JoinGroup(publicKeys []*ecdsa.PublicKey) error
|
JoinGroup(publicKeys []*ecdsa.PublicKey) ([]*Filter, error)
|
||||||
LeaveGroup(publicKeys []*ecdsa.PublicKey) error
|
LeaveGroup(publicKeys []*ecdsa.PublicKey) error
|
||||||
JoinPublic(chatID string) error
|
JoinPublic(chatID string) (*Filter, error)
|
||||||
LeavePublic(chatID string) error
|
LeavePublic(chatID string) error
|
||||||
GetCurrentTime() uint64
|
GetCurrentTime() uint64
|
||||||
MaxMessageSize() uint32
|
MaxMessageSize() uint32
|
||||||
|
@ -23,6 +24,7 @@ type Transport interface {
|
||||||
SendPrivateWithSharedSecret(ctx context.Context, newMessage *types.NewMessage, publicKey *ecdsa.PublicKey, secret []byte) ([]byte, error)
|
SendPrivateWithSharedSecret(ctx context.Context, newMessage *types.NewMessage, publicKey *ecdsa.PublicKey, secret []byte) ([]byte, error)
|
||||||
SendPrivateWithPartitioned(ctx context.Context, newMessage *types.NewMessage, publicKey *ecdsa.PublicKey) ([]byte, error)
|
SendPrivateWithPartitioned(ctx context.Context, newMessage *types.NewMessage, publicKey *ecdsa.PublicKey) ([]byte, error)
|
||||||
SendPrivateOnPersonalTopic(ctx context.Context, newMessage *types.NewMessage, publicKey *ecdsa.PublicKey) ([]byte, error)
|
SendPrivateOnPersonalTopic(ctx context.Context, newMessage *types.NewMessage, publicKey *ecdsa.PublicKey) ([]byte, error)
|
||||||
|
SendCommunityMessage(ctx context.Context, newMessage *types.NewMessage, publicKey *ecdsa.PublicKey) ([]byte, error)
|
||||||
SendMessagesRequest(
|
SendMessagesRequest(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
peerID []byte,
|
peerID []byte,
|
||||||
|
@ -34,6 +36,7 @@ type Transport interface {
|
||||||
|
|
||||||
InitFilters(chatIDs []string, publicKeys []*ecdsa.PublicKey) ([]*Filter, error)
|
InitFilters(chatIDs []string, publicKeys []*ecdsa.PublicKey) ([]*Filter, error)
|
||||||
InitPublicFilters(chatIDs []string) ([]*Filter, error)
|
InitPublicFilters(chatIDs []string) ([]*Filter, error)
|
||||||
|
InitCommunityFilters(pks []*ecdsa.PrivateKey) ([]*Filter, error)
|
||||||
LoadFilters(filters []*Filter) ([]*Filter, error)
|
LoadFilters(filters []*Filter) ([]*Filter, error)
|
||||||
RemoveFilters(filters []*Filter) error
|
RemoveFilters(filters []*Filter) error
|
||||||
RemoveFilterByChatID(string) (*Filter, error)
|
RemoveFilterByChatID(string) (*Filter, error)
|
||||||
|
@ -48,3 +51,7 @@ type Transport interface {
|
||||||
|
|
||||||
SetEnvelopeEventsHandler(handler EnvelopeEventsHandler) error
|
SetEnvelopeEventsHandler(handler EnvelopeEventsHandler) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func PubkeyToHex(key *ecdsa.PublicKey) string {
|
||||||
|
return types.EncodeHex(crypto.FromECDSAPub(key))
|
||||||
|
}
|
||||||
|
|
|
@ -145,6 +145,10 @@ func (a *Transport) LoadFilters(filters []*transport.Filter) ([]*transport.Filte
|
||||||
return a.filters.InitWithFilters(filters)
|
return a.filters.InitWithFilters(filters)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *Transport) InitCommunityFilters(pks []*ecdsa.PrivateKey) ([]*transport.Filter, error) {
|
||||||
|
return a.filters.InitCommunityFilters(pks)
|
||||||
|
}
|
||||||
|
|
||||||
func (a *Transport) RemoveFilters(filters []*transport.Filter) error {
|
func (a *Transport) RemoveFilters(filters []*transport.Filter) error {
|
||||||
return a.filters.Remove(filters...)
|
return a.filters.Remove(filters...)
|
||||||
}
|
}
|
||||||
|
@ -165,9 +169,8 @@ func (a *Transport) ProcessNegotiatedSecret(secret types.NegotiatedSecret) (*tra
|
||||||
return filter, nil
|
return filter, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Transport) JoinPublic(chatID string) error {
|
func (a *Transport) JoinPublic(chatID string) (*transport.Filter, error) {
|
||||||
_, err := a.filters.LoadPublic(chatID)
|
return a.filters.LoadPublic(chatID)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Transport) LeavePublic(chatID string) error {
|
func (a *Transport) LeavePublic(chatID string) error {
|
||||||
|
@ -178,13 +181,8 @@ func (a *Transport) LeavePublic(chatID string) error {
|
||||||
return a.filters.Remove(chat)
|
return a.filters.Remove(chat)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Transport) JoinPrivate(publicKey *ecdsa.PublicKey) error {
|
func (a *Transport) JoinPrivate(publicKey *ecdsa.PublicKey) (*transport.Filter, error) {
|
||||||
_, err := a.filters.LoadDiscovery()
|
return a.filters.LoadContactCode(publicKey)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_, err = a.filters.LoadContactCode(publicKey)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Transport) LeavePrivate(publicKey *ecdsa.PublicKey) error {
|
func (a *Transport) LeavePrivate(publicKey *ecdsa.PublicKey) error {
|
||||||
|
@ -192,18 +190,17 @@ func (a *Transport) LeavePrivate(publicKey *ecdsa.PublicKey) error {
|
||||||
return a.filters.Remove(filters...)
|
return a.filters.Remove(filters...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Transport) JoinGroup(publicKeys []*ecdsa.PublicKey) error {
|
func (a *Transport) JoinGroup(publicKeys []*ecdsa.PublicKey) ([]*transport.Filter, error) {
|
||||||
_, err := a.filters.LoadDiscovery()
|
var filters []*transport.Filter
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, pk := range publicKeys {
|
for _, pk := range publicKeys {
|
||||||
_, err = a.filters.LoadContactCode(pk)
|
f, err := a.filters.LoadContactCode(pk)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
filters = append(filters, f)
|
||||||
|
|
||||||
}
|
}
|
||||||
return nil
|
return filters, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Transport) LeaveGroup(publicKeys []*ecdsa.PublicKey) error {
|
func (a *Transport) LeaveGroup(publicKeys []*ecdsa.PublicKey) error {
|
||||||
|
@ -333,20 +330,22 @@ func (a *Transport) LoadKeyFilters(key *ecdsa.PrivateKey) (*transport.Filter, er
|
||||||
return a.filters.LoadEphemeral(&key.PublicKey, key, true)
|
return a.filters.LoadEphemeral(&key.PublicKey, key, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Transport) SendPrivateOnDiscovery(ctx context.Context, newMessage *types.NewMessage, publicKey *ecdsa.PublicKey) ([]byte, error) {
|
func (a *Transport) SendCommunityMessage(ctx context.Context, newMessage *types.NewMessage, publicKey *ecdsa.PublicKey) ([]byte, error) {
|
||||||
if err := a.addSig(newMessage); err != nil {
|
if err := a.addSig(newMessage); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// There is no need to load any chat
|
// We load the filter to make sure we can post on it
|
||||||
// because listening on the discovery topic
|
filter, err := a.filters.LoadPublic(transport.PubkeyToHex(publicKey)[2:])
|
||||||
// is done automatically.
|
if err != nil {
|
||||||
// TODO: change this anyway, it should be explicit
|
return nil, err
|
||||||
// and idempotent.
|
}
|
||||||
|
|
||||||
newMessage.Topic = types.BytesToTopic(transport.ToTopic(transport.DiscoveryTopic()))
|
newMessage.Topic = filter.Topic
|
||||||
newMessage.PublicKey = crypto.FromECDSAPub(publicKey)
|
newMessage.PublicKey = crypto.FromECDSAPub(publicKey)
|
||||||
|
|
||||||
|
a.logger.Debug("SENDING message", zap.Binary("topic", filter.Topic[:]))
|
||||||
|
|
||||||
return a.api.Post(ctx, *newMessage)
|
return a.api.Post(ctx, *newMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -131,6 +131,10 @@ func (a *Transport) InitPublicFilters(chatIDs []string) ([]*transport.Filter, er
|
||||||
return a.filters.InitPublicFilters(chatIDs)
|
return a.filters.InitPublicFilters(chatIDs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *Transport) InitCommunityFilters(pks []*ecdsa.PrivateKey) ([]*transport.Filter, error) {
|
||||||
|
return a.filters.InitCommunityFilters(pks)
|
||||||
|
}
|
||||||
|
|
||||||
func (a *Transport) Filters() []*transport.Filter {
|
func (a *Transport) Filters() []*transport.Filter {
|
||||||
return a.filters.Filters()
|
return a.filters.Filters()
|
||||||
}
|
}
|
||||||
|
@ -139,6 +143,23 @@ func (a *Transport) LoadFilters(filters []*transport.Filter) ([]*transport.Filte
|
||||||
return a.filters.InitWithFilters(filters)
|
return a.filters.InitWithFilters(filters)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *Transport) SendCommunityMessage(ctx context.Context, newMessage *types.NewMessage, publicKey *ecdsa.PublicKey) ([]byte, error) {
|
||||||
|
if err := a.addSig(newMessage); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// We load the filter to make sure we can post on it
|
||||||
|
filter, err := a.filters.LoadPublic(transport.PubkeyToHex(publicKey))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
newMessage.Topic = filter.Topic
|
||||||
|
newMessage.PublicKey = crypto.FromECDSAPub(publicKey)
|
||||||
|
|
||||||
|
return a.shhAPI.Post(ctx, *newMessage)
|
||||||
|
}
|
||||||
|
|
||||||
func (a *Transport) RemoveFilters(filters []*transport.Filter) error {
|
func (a *Transport) RemoveFilters(filters []*transport.Filter) error {
|
||||||
return a.filters.Remove(filters...)
|
return a.filters.Remove(filters...)
|
||||||
}
|
}
|
||||||
|
@ -159,9 +180,8 @@ func (a *Transport) ProcessNegotiatedSecret(secret types.NegotiatedSecret) (*tra
|
||||||
return filter, nil
|
return filter, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Transport) JoinPublic(chatID string) error {
|
func (a *Transport) JoinPublic(chatID string) (*transport.Filter, error) {
|
||||||
_, err := a.filters.LoadPublic(chatID)
|
return a.filters.LoadPublic(chatID)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Transport) LeavePublic(chatID string) error {
|
func (a *Transport) LeavePublic(chatID string) error {
|
||||||
|
@ -172,13 +192,8 @@ func (a *Transport) LeavePublic(chatID string) error {
|
||||||
return a.filters.Remove(chat)
|
return a.filters.Remove(chat)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Transport) JoinPrivate(publicKey *ecdsa.PublicKey) error {
|
func (a *Transport) JoinPrivate(publicKey *ecdsa.PublicKey) (*transport.Filter, error) {
|
||||||
_, err := a.filters.LoadDiscovery()
|
return a.filters.LoadContactCode(publicKey)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_, err = a.filters.LoadContactCode(publicKey)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Transport) LeavePrivate(publicKey *ecdsa.PublicKey) error {
|
func (a *Transport) LeavePrivate(publicKey *ecdsa.PublicKey) error {
|
||||||
|
@ -186,18 +201,16 @@ func (a *Transport) LeavePrivate(publicKey *ecdsa.PublicKey) error {
|
||||||
return a.filters.Remove(filters...)
|
return a.filters.Remove(filters...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Transport) JoinGroup(publicKeys []*ecdsa.PublicKey) error {
|
func (a *Transport) JoinGroup(publicKeys []*ecdsa.PublicKey) ([]*transport.Filter, error) {
|
||||||
_, err := a.filters.LoadDiscovery()
|
var filters []*transport.Filter
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, pk := range publicKeys {
|
for _, pk := range publicKeys {
|
||||||
_, err = a.filters.LoadContactCode(pk)
|
f, err := a.filters.LoadContactCode(pk)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
filters = append(filters, f)
|
||||||
}
|
}
|
||||||
return nil
|
return filters, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Transport) LeaveGroup(publicKeys []*ecdsa.PublicKey) error {
|
func (a *Transport) LeaveGroup(publicKeys []*ecdsa.PublicKey) error {
|
||||||
|
|
|
@ -225,6 +225,8 @@ func (m *StatusMessage) HandleApplication() error {
|
||||||
return m.unmarshalProtobufData(new(protobuf.CommunityDescription))
|
return m.unmarshalProtobufData(new(protobuf.CommunityDescription))
|
||||||
case protobuf.ApplicationMetadataMessage_COMMUNITY_INVITATION:
|
case protobuf.ApplicationMetadataMessage_COMMUNITY_INVITATION:
|
||||||
return m.unmarshalProtobufData(new(protobuf.CommunityInvitation))
|
return m.unmarshalProtobufData(new(protobuf.CommunityInvitation))
|
||||||
|
case protobuf.ApplicationMetadataMessage_COMMUNITY_REQUEST_TO_JOIN:
|
||||||
|
return m.unmarshalProtobufData(new(protobuf.CommunityRequestToJoin))
|
||||||
case protobuf.ApplicationMetadataMessage_PUSH_NOTIFICATION_REGISTRATION:
|
case protobuf.ApplicationMetadataMessage_PUSH_NOTIFICATION_REGISTRATION:
|
||||||
// This message is a bit different as it's encrypted, so we pass it straight through
|
// This message is a bit different as it's encrypted, so we pass it straight through
|
||||||
v := reflect.ValueOf(m.UnwrappedPayload)
|
v := reflect.ValueOf(m.UnwrappedPayload)
|
||||||
|
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"github.com/status-im/status-go/protocol/encryption/multidevice"
|
"github.com/status-im/status-go/protocol/encryption/multidevice"
|
||||||
"github.com/status-im/status-go/protocol/protobuf"
|
"github.com/status-im/status-go/protocol/protobuf"
|
||||||
"github.com/status-im/status-go/protocol/pushnotificationclient"
|
"github.com/status-im/status-go/protocol/pushnotificationclient"
|
||||||
|
"github.com/status-im/status-go/protocol/requests"
|
||||||
"github.com/status-im/status-go/protocol/transport"
|
"github.com/status-im/status-go/protocol/transport"
|
||||||
"github.com/status-im/status-go/protocol/urls"
|
"github.com/status-im/status-go/protocol/urls"
|
||||||
"github.com/status-im/status-go/services/ext/mailservers"
|
"github.com/status-im/status-go/services/ext/mailservers"
|
||||||
|
@ -200,10 +201,6 @@ func (api *PublicAPI) ConfirmMessagesProcessedByID(messageConfirmations []*Metad
|
||||||
return api.service.ConfirmMessagesProcessed(encryptionIDs)
|
return api.service.ConfirmMessagesProcessed(encryptionIDs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *PublicAPI) Join(chat protocol.Chat) error {
|
|
||||||
return api.service.messenger.Join(chat)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (api *PublicAPI) Leave(chat protocol.Chat) error {
|
func (api *PublicAPI) Leave(chat protocol.Chat) error {
|
||||||
return api.service.messenger.Leave(chat)
|
return api.service.messenger.Leave(chat)
|
||||||
}
|
}
|
||||||
|
@ -260,6 +257,10 @@ func (api *PublicAPI) SaveChat(parent context.Context, chat *protocol.Chat) erro
|
||||||
return api.service.messenger.SaveChat(chat)
|
return api.service.messenger.SaveChat(chat)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (api *PublicAPI) CreateOneToOneChat(parent context.Context, request *requests.CreateOneToOneChat) (*protocol.MessengerResponse, error) {
|
||||||
|
return api.service.messenger.CreateOneToOneChat(request)
|
||||||
|
}
|
||||||
|
|
||||||
func (api *PublicAPI) Chats(parent context.Context) []*protocol.Chat {
|
func (api *PublicAPI) Chats(parent context.Context) []*protocol.Chat {
|
||||||
return api.service.messenger.Chats()
|
return api.service.messenger.Chats()
|
||||||
}
|
}
|
||||||
|
@ -328,28 +329,28 @@ func (api *PublicAPI) JoinedCommunities(parent context.Context) ([]*communities.
|
||||||
}
|
}
|
||||||
|
|
||||||
// JoinCommunity joins a community with the given ID
|
// JoinCommunity joins a community with the given ID
|
||||||
func (api *PublicAPI) JoinCommunity(parent context.Context, communityID string) (*protocol.MessengerResponse, error) {
|
func (api *PublicAPI) JoinCommunity(parent context.Context, communityID types.HexBytes) (*protocol.MessengerResponse, error) {
|
||||||
return api.service.messenger.JoinCommunity(communityID)
|
return api.service.messenger.JoinCommunity(communityID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LeaveCommunity leaves a commuity with the given ID
|
// LeaveCommunity leaves a commuity with the given ID
|
||||||
func (api *PublicAPI) LeaveCommunity(parent context.Context, communityID string) (*protocol.MessengerResponse, error) {
|
func (api *PublicAPI) LeaveCommunity(parent context.Context, communityID types.HexBytes) (*protocol.MessengerResponse, error) {
|
||||||
return api.service.messenger.LeaveCommunity(communityID)
|
return api.service.messenger.LeaveCommunity(communityID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateCommunity creates a new community with the provided description
|
// CreateCommunity creates a new community with the provided description
|
||||||
func (api *PublicAPI) CreateCommunity(description *protobuf.CommunityDescription) (*protocol.MessengerResponse, error) {
|
func (api *PublicAPI) CreateCommunity(request *requests.CreateCommunity) (*protocol.MessengerResponse, error) {
|
||||||
return api.service.messenger.CreateCommunity(description)
|
return api.service.messenger.CreateCommunity(request)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExportCommunity exports the private key of the community with given ID
|
// ExportCommunity exports the private key of the community with given ID
|
||||||
func (api *PublicAPI) ExportCommunity(id string) (string, error) {
|
func (api *PublicAPI) ExportCommunity(id types.HexBytes) (types.HexBytes, error) {
|
||||||
key, err := api.service.messenger.ExportCommunity(id)
|
key, err := api.service.messenger.ExportCommunity(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
return types.EncodeHex(crypto.FromECDSA(key)), nil
|
return crypto.FromECDSA(key), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ImportCommunity imports a community with the given private key in hex
|
// ImportCommunity imports a community with the given private key in hex
|
||||||
|
@ -364,18 +365,48 @@ func (api *PublicAPI) ImportCommunity(hexPrivateKey string) (*protocol.Messenger
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateCommunityChat creates a community chat in the given community
|
// CreateCommunityChat creates a community chat in the given community
|
||||||
func (api *PublicAPI) CreateCommunityChat(orgID string, c *protobuf.CommunityChat) (*protocol.MessengerResponse, error) {
|
func (api *PublicAPI) CreateCommunityChat(communityID types.HexBytes, c *protobuf.CommunityChat) (*protocol.MessengerResponse, error) {
|
||||||
return api.service.messenger.CreateCommunityChat(orgID, c)
|
return api.service.messenger.CreateCommunityChat(communityID, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InviteUserToCommunity invites the user with pk to the community with ID
|
// InviteUsersToCommunity invites the users with pks to the community with ID
|
||||||
func (api *PublicAPI) InviteUserToCommunity(orgID, userPublicKey string) (*protocol.MessengerResponse, error) {
|
func (api *PublicAPI) InviteUsersToCommunity(request *requests.InviteUsersToCommunity) (*protocol.MessengerResponse, error) {
|
||||||
return api.service.messenger.InviteUserToCommunity(orgID, userPublicKey)
|
return api.service.messenger.InviteUsersToCommunity(request)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ShareCommunity share the community with a set of users
|
||||||
|
func (api *PublicAPI) ShareCommunity(request *requests.ShareCommunity) (*protocol.MessengerResponse, error) {
|
||||||
|
return api.service.messenger.ShareCommunity(request)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveUserFromCommunity removes the user with pk from the community with ID
|
// RemoveUserFromCommunity removes the user with pk from the community with ID
|
||||||
func (api *PublicAPI) RemoveUserFromCommunity(orgID, userPublicKey string) (*protocol.MessengerResponse, error) {
|
func (api *PublicAPI) RemoveUserFromCommunity(communityID types.HexBytes, userPublicKey string) (*protocol.MessengerResponse, error) {
|
||||||
return api.service.messenger.RemoveUserFromCommunity(orgID, userPublicKey)
|
return api.service.messenger.RemoveUserFromCommunity(communityID, userPublicKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MyPendingRequestsToJoin returns the pending requests for the logged in user
|
||||||
|
func (api *PublicAPI) MyPendingRequestsToJoin() ([]*communities.RequestToJoin, error) {
|
||||||
|
return api.service.messenger.MyPendingRequestsToJoin()
|
||||||
|
}
|
||||||
|
|
||||||
|
// PendingRequestsToJoinForCommunity returns the pending requests to join for a given community
|
||||||
|
func (api *PublicAPI) PendingRequestsToJoinForCommunity(id types.HexBytes) ([]*communities.RequestToJoin, error) {
|
||||||
|
return api.service.messenger.PendingRequestsToJoinForCommunity(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AcceptRequestToJoinCommunity accepts a pending request to join a community
|
||||||
|
func (api *PublicAPI) AcceptRequestToJoinCommunity(request *requests.AcceptRequestToJoinCommunity) (*protocol.MessengerResponse, error) {
|
||||||
|
return api.service.messenger.AcceptRequestToJoinCommunity(request)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeclineRequestToJoinCommunity accepts a pending request to join a community
|
||||||
|
func (api *PublicAPI) DeclineRequestToJoinCommunity(request *requests.DeclineRequestToJoinCommunity) error {
|
||||||
|
return api.service.messenger.DeclineRequestToJoinCommunity(request)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequestToJoinCommunity requests to join a particular community
|
||||||
|
func (api *PublicAPI) RequestToJoinCommunity(request *requests.RequestToJoinCommunity) (*protocol.MessengerResponse, error) {
|
||||||
|
return api.service.messenger.RequestToJoinCommunity(request)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ApplicationMessagesResponse struct {
|
type ApplicationMessagesResponse struct {
|
||||||
|
@ -656,6 +687,10 @@ func (api *PublicAPI) GetLinkPreviewData(link string) (previewData urls.LinkPrev
|
||||||
return urls.GetLinkPreviewData(link)
|
return urls.GetLinkPreviewData(link)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (api *PublicAPI) EnsVerified(pk, ensName string) error {
|
||||||
|
return api.service.messenger.ENSVerified(pk, ensName)
|
||||||
|
}
|
||||||
|
|
||||||
// Echo is a method for testing purposes.
|
// Echo is a method for testing purposes.
|
||||||
func (api *PublicAPI) Echo(ctx context.Context, message string) (string, error) {
|
func (api *PublicAPI) Echo(ctx context.Context, message string) (string, error) {
|
||||||
return message, nil
|
return message, nil
|
||||||
|
|
|
@ -180,10 +180,18 @@ func (s *Service) StartMessenger() (*protocol.MessengerResponse, error) {
|
||||||
}
|
}
|
||||||
go s.retrieveMessagesLoop(time.Second, s.cancelMessenger)
|
go s.retrieveMessagesLoop(time.Second, s.cancelMessenger)
|
||||||
go s.verifyTransactionLoop(30*time.Second, s.cancelMessenger)
|
go s.verifyTransactionLoop(30*time.Second, s.cancelMessenger)
|
||||||
go s.verifyENSLoop(30*time.Second, s.cancelMessenger)
|
|
||||||
return response, nil
|
return response, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func publishMessengerResponse(response *protocol.MessengerResponse) {
|
||||||
|
if !response.IsEmpty() {
|
||||||
|
PublisherSignalHandler{}.NewMessages(response)
|
||||||
|
localnotifications.SendMessageNotifications(response.Notifications)
|
||||||
|
// Clear notifications as not used for now
|
||||||
|
response.Notifications = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Service) retrieveMessagesLoop(tick time.Duration, cancel <-chan struct{}) {
|
func (s *Service) retrieveMessagesLoop(tick time.Duration, cancel <-chan struct{}) {
|
||||||
ticker := time.NewTicker(tick)
|
ticker := time.NewTicker(tick)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
|
@ -196,10 +204,7 @@ func (s *Service) retrieveMessagesLoop(tick time.Duration, cancel <-chan struct{
|
||||||
log.Error("failed to retrieve raw messages", "err", err)
|
log.Error("failed to retrieve raw messages", "err", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !response.IsEmpty() {
|
publishMessengerResponse(response)
|
||||||
PublisherSignalHandler{}.NewMessages(response)
|
|
||||||
localnotifications.SendMessageNotifications(response.Notifications)
|
|
||||||
}
|
|
||||||
case <-cancel:
|
case <-cancel:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -270,35 +275,6 @@ func (c *verifyTransactionClient) TransactionByHash(ctx context.Context, hash ty
|
||||||
return coremessage, coretypes.TransactionStatus(receipt.Status), nil
|
return coremessage, coretypes.TransactionStatus(receipt.Status), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) verifyENSLoop(tick time.Duration, cancel <-chan struct{}) {
|
|
||||||
if s.config.VerifyENSURL == "" || s.config.VerifyENSContractAddress == "" {
|
|
||||||
log.Warn("not starting ENS loop")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ticker := time.NewTicker(tick)
|
|
||||||
defer ticker.Stop()
|
|
||||||
|
|
||||||
ctx, cancelVerifyENS := context.WithCancel(context.Background())
|
|
||||||
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-ticker.C:
|
|
||||||
response, err := s.messenger.VerifyENSNames(ctx, s.config.VerifyENSURL, s.config.VerifyENSContractAddress)
|
|
||||||
if err != nil {
|
|
||||||
log.Error("failed to validate ens", "err", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !response.IsEmpty() {
|
|
||||||
PublisherSignalHandler{}.NewMessages(response)
|
|
||||||
}
|
|
||||||
case <-cancel:
|
|
||||||
cancelVerifyENS()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) verifyTransactionLoop(tick time.Duration, cancel <-chan struct{}) {
|
func (s *Service) verifyTransactionLoop(tick time.Duration, cancel <-chan struct{}) {
|
||||||
if s.config.VerifyTransactionURL == "" {
|
if s.config.VerifyTransactionURL == "" {
|
||||||
log.Warn("not starting transaction loop")
|
log.Warn("not starting transaction loop")
|
||||||
|
@ -329,10 +305,8 @@ func (s *Service) verifyTransactionLoop(tick time.Duration, cancel <-chan struct
|
||||||
log.Error("failed to validate transactions", "err", err)
|
log.Error("failed to validate transactions", "err", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !response.IsEmpty() {
|
publishMessengerResponse(response)
|
||||||
PublisherSignalHandler{}.NewMessages(response)
|
|
||||||
localnotifications.SendMessageNotifications(response.Notifications)
|
|
||||||
}
|
|
||||||
case <-cancel:
|
case <-cancel:
|
||||||
cancelVerifyTransaction()
|
cancelVerifyTransaction()
|
||||||
return
|
return
|
||||||
|
@ -478,11 +452,14 @@ func buildMessengerOptions(
|
||||||
protocol.WithAccount(account),
|
protocol.WithAccount(account),
|
||||||
protocol.WithEnvelopesMonitorConfig(envelopesMonitorConfig),
|
protocol.WithEnvelopesMonitorConfig(envelopesMonitorConfig),
|
||||||
protocol.WithOnNegotiatedFilters(onNegotiatedFilters),
|
protocol.WithOnNegotiatedFilters(onNegotiatedFilters),
|
||||||
protocol.WithDeliveredHandler(messageDeliveredHandler)}
|
protocol.WithDeliveredHandler(messageDeliveredHandler),
|
||||||
|
protocol.WithENSVerificationConfig(publishMessengerResponse, config.VerifyENSURL, config.VerifyENSContractAddress),
|
||||||
|
}
|
||||||
|
|
||||||
if config.DataSyncEnabled {
|
if config.DataSyncEnabled {
|
||||||
options = append(options, protocol.WithDatasync())
|
options = append(options, protocol.WithDatasync())
|
||||||
}
|
}
|
||||||
|
|
||||||
settings, err := accountsDB.GetSettings()
|
settings, err := accountsDB.GetSettings()
|
||||||
if err != sql.ErrNoRows && err != nil {
|
if err != sql.ErrNoRows && err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
Loading…
Reference in New Issue