fix: Upgrade status-go to the most recent version of release branch which contains memory fix

Fix #4990
This commit is contained in:
Michal Iskierko 2024-05-13 12:21:03 +02:00 committed by Michał Iskierko
parent 03d490156a
commit 66cf3d21b9
230 changed files with 30930 additions and 14243 deletions

6
go.mod
View File

@ -44,7 +44,7 @@ require (
github.com/sirupsen/logrus v1.9.3
github.com/slack-go/slack v0.12.2
github.com/spf13/viper v1.16.0
github.com/status-im/status-go v0.174.7-0.20240222013825-0aeaf82915d8
github.com/status-im/status-go v0.177.1-0.20240502181839-d59ff96b54fa
github.com/stretchr/testify v1.8.4
github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a
github.com/vincent-petithory/dataurl v1.0.0
@ -165,7 +165,7 @@ require (
github.com/ipfs/go-log/v2 v2.5.1 // indirect
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect
github.com/jellydator/ttlcache/v3 v3.1.0 // indirect
github.com/jellydator/ttlcache/v3 v3.2.0 // indirect
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a // indirect
github.com/jmoiron/sqlx v1.3.5 // indirect
github.com/json-iterator/go v1.1.12 // indirect
@ -315,7 +315,7 @@ require (
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
github.com/waku-org/go-discover v0.0.0-20240129014929-85f2c00b96a3 // indirect
github.com/waku-org/go-libp2p-rendezvous v0.0.0-20230628220917-7b4e5ae4c0e7 // indirect
github.com/waku-org/go-waku v0.8.1-0.20240220211751-9bb2c8e39680 // indirect
github.com/waku-org/go-waku v0.8.1-0.20240322182925-dd81e1d46971 // indirect
github.com/waku-org/go-zerokit-rln v0.1.14-0.20240102145250-fa738c0bdf59 // indirect
github.com/waku-org/go-zerokit-rln-apple v0.0.0-20230916172309-ee0ee61dde2b // indirect
github.com/waku-org/go-zerokit-rln-arm v0.0.0-20230916171929-1dd9494ff065 // indirect

12
go.sum
View File

@ -1420,8 +1420,8 @@ github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABo
github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk=
github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU=
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
github.com/jellydator/ttlcache/v3 v3.1.0 h1:0gPFG0IHHP6xyUyXq+JaD8fwkDCqgqwohXNJBcYE71g=
github.com/jellydator/ttlcache/v3 v3.1.0/go.mod h1:hi7MGFdMAwZna5n2tuvh63DvFLzVKySzCVW6+0gA2n4=
github.com/jellydator/ttlcache/v3 v3.2.0 h1:6lqVJ8X3ZaUwvzENqPAobDsXNExfUJd61u++uW8a3LE=
github.com/jellydator/ttlcache/v3 v3.2.0/go.mod h1:hi7MGFdMAwZna5n2tuvh63DvFLzVKySzCVW6+0gA2n4=
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
@ -2418,8 +2418,8 @@ github.com/status-im/rendezvous v1.3.7 h1:rZGWsFCjPV3MWeUkLkZSOGTAvyRf+rxx5hnEGL
github.com/status-im/rendezvous v1.3.7/go.mod h1:r0vCbQJByTteMajN0f+Mcet/Vd7uAXxFPfewNpI2iXQ=
github.com/status-im/resize v0.0.0-20201215164250-7c6d9f0d3088 h1:ClCAP2FPCvl8hGMhbUx/tq/sOu2wibztAa5jAvQEe4Q=
github.com/status-im/resize v0.0.0-20201215164250-7c6d9f0d3088/go.mod h1:+92j1tN27DypDeBFxkg0uzkqfh1bNHTZe3Bv2PjvxpM=
github.com/status-im/status-go v0.174.7-0.20240222013825-0aeaf82915d8 h1:vjCXgZTfsIAibudrQyMVRzdKRrHKSptxFsP4Mjt5I/E=
github.com/status-im/status-go v0.174.7-0.20240222013825-0aeaf82915d8/go.mod h1:8M6g7DyP9Y0zE/I9KY/v/v7ZqNIsF/3pBb8LSjE6Hl4=
github.com/status-im/status-go v0.177.1-0.20240502181839-d59ff96b54fa h1:KgvJynkucsTM0XuQ4fIZ9tThEjkAlZtzMwX5yMCa86M=
github.com/status-im/status-go v0.177.1-0.20240502181839-d59ff96b54fa/go.mod h1:UfDzdoAlPk2Kt+TM4opcsH/rdW/Zanh5FelcZyRbmRw=
github.com/status-im/status-go/extkeys v1.1.2 h1:FSjARgDathJ3rIapJt851LsIXP9Oyuu2M2jPJKuzloU=
github.com/status-im/status-go/extkeys v1.1.2/go.mod h1:hCmFzb2jiiVF2voZKYbzuhOQiHHCmyLJsZJXrFFg7BY=
github.com/status-im/tcp-shaker v1.1.1-status h1:TnVeeWlq2SKCWotHc4Vi6qZQfY8TTe3VLmu1xpEFYhg=
@ -2550,8 +2550,8 @@ github.com/waku-org/go-discover v0.0.0-20240129014929-85f2c00b96a3 h1:Kk0KYXZE/u
github.com/waku-org/go-discover v0.0.0-20240129014929-85f2c00b96a3/go.mod h1:eBHgM6T4EG0RZzxpxKy+rGz/6Dw2Nd8DWxS0lm9ESDw=
github.com/waku-org/go-libp2p-rendezvous v0.0.0-20230628220917-7b4e5ae4c0e7 h1:0e1h+p84yBp0IN7AqgbZlV7lgFBjm214lgSOE7CeJmE=
github.com/waku-org/go-libp2p-rendezvous v0.0.0-20230628220917-7b4e5ae4c0e7/go.mod h1:pFvOZ9YTFsW0o5zJW7a0B5tr1owAijRWJctXJ2toL04=
github.com/waku-org/go-waku v0.8.1-0.20240220211751-9bb2c8e39680 h1:WGPMcGDmW7q9ZPoD5V53T1ak36/qo1rYLE9bv4g5BVY=
github.com/waku-org/go-waku v0.8.1-0.20240220211751-9bb2c8e39680/go.mod h1:RjTvkTrIwpoT1cM9HeQqwa2Q7t7WOkb3hpuB/zuZ6SM=
github.com/waku-org/go-waku v0.8.1-0.20240322182925-dd81e1d46971 h1:HSR8JmscSmCtpIAzFO5sNZRyYZbO8nw7rGM3QcC9bak=
github.com/waku-org/go-waku v0.8.1-0.20240322182925-dd81e1d46971/go.mod h1:RjTvkTrIwpoT1cM9HeQqwa2Q7t7WOkb3hpuB/zuZ6SM=
github.com/waku-org/go-zerokit-rln v0.1.14-0.20240102145250-fa738c0bdf59 h1:jisj+OCI6QydLtFq3Pyhu49wl9ytPN7oAHjMfepHDrA=
github.com/waku-org/go-zerokit-rln v0.1.14-0.20240102145250-fa738c0bdf59/go.mod h1:1PdBdPzyTaKt3VnpAHk3zj+r9dXPFOr3IHZP9nFle6E=
github.com/waku-org/go-zerokit-rln-apple v0.0.0-20230916172309-ee0ee61dde2b h1:KgZVhsLkxsj5gb/FfndSCQu6VYwALrCOgYI3poR95yE=

View File

@ -148,6 +148,10 @@ func (c *Cache[K, V]) set(key K, value V, ttl time.Duration) *Item[K, V] {
c.evict(EvictionReasonCapacityReached, c.items.lru.Back())
}
if ttl == PreviousOrDefaultTTL {
ttl = c.options.ttl
}
// create a new item
item := newItem(key, value, ttl, c.options.enableVersionTracking)
elem = c.items.lru.PushFront(item)
@ -478,6 +482,13 @@ func (c *Cache[K, V]) Items() map[K]*Item[K, V] {
// Range stops the iteration.
func (c *Cache[K, V]) Range(fn func(item *Item[K, V]) bool) {
c.items.mu.RLock()
// Check if cache is empty
if c.items.lru.Len() == 0 {
c.items.mu.RUnlock()
return
}
for item := c.items.lru.Front(); item != c.items.lru.Back().Next(); item = item.Next() {
i := item.Value.(*Item[K, V])
c.items.mu.RUnlock()

View File

@ -9,6 +9,10 @@ const (
// NoTTL indicates that an item should never expire.
NoTTL time.Duration = -1
// PreviousOrDefaultTTL indicates that existing TTL of item should be used
// default TTL will be used as fallback if item doesn't exist
PreviousOrDefaultTTL time.Duration = -2
// DefaultTTL indicates that the default TTL value of the cache
// instance should be used.
DefaultTTL time.Duration = 0
@ -58,17 +62,23 @@ func (item *Item[K, V]) update(value V, ttl time.Duration) {
defer item.mu.Unlock()
item.value = value
// update version if enabled
if item.version > -1 {
item.version++
}
// no need to update ttl or expiry in this case
if ttl == PreviousOrDefaultTTL {
return
}
item.ttl = ttl
// reset expiration timestamp because the new TTL may be
// 0 or below
item.expiresAt = time.Time{}
item.touchUnsafe()
// update version if enabled
if item.version > -1 {
item.version++
}
}
// touch updates the item's expiration timestamp.

View File

@ -89,10 +89,8 @@ func (o *Onboarding) generateAccount(mnemonicPhraseLength int) (*OnboardingAccou
ChatPubKey: walletPubKey,
}
uuid := uuid.NewRandom().String()
account := &OnboardingAccount{
ID: uuid,
ID: uuid.NewRandom().String(),
mnemonic: mnemonicPhrase,
Info: info,
}

View File

@ -1,7 +1,6 @@
package account
import (
"encoding/json"
"errors"
"fmt"
@ -32,37 +31,6 @@ func (e *ErrZeroAddress) Error() string {
return fmt.Sprintf("%s contains an empty address", e.field)
}
func newErrZeroAddress(field string) *ErrZeroAddress {
return &ErrZeroAddress{
field: field,
}
}
func ParseLoginParams(paramsJSON string) (LoginParams, error) {
var (
params LoginParams
zeroAddress types.Address
)
if err := json.Unmarshal([]byte(paramsJSON), &params); err != nil {
return params, err
}
if params.ChatAddress == zeroAddress {
return params, newErrZeroAddress("ChatAddress")
}
if params.MainAccount == zeroAddress {
return params, newErrZeroAddress("MainAccount")
}
for _, address := range params.WatchAddresses {
if address == zeroAddress {
return params, newErrZeroAddress("WatchAddresses")
}
}
return params, nil
}
// Info contains wallet and chat addresses and public keys of an account.
type Info struct {
WalletAddress string

View File

@ -45,11 +45,11 @@ var mainnet = params.Network{
var goerli = params.Network{
ChainID: goerliChainID,
ChainName: "Ethereum Goerli",
RPCURL: "https://goerli-archival.rpc.grove.city/v1/",
FallbackURL: "https://goerli.infura.io/v3/",
RPCURL: "https://goerli.infura.io/v3/",
FallbackURL: "",
BlockExplorerURL: "https://goerli.etherscan.io/",
IconURL: "network/Network=Testnet",
ChainColor: "#939BA1",
ChainColor: "#627EEA",
ShortName: "goEth",
NativeCurrencyName: "Ether",
NativeCurrencySymbol: "ETH",
@ -63,11 +63,11 @@ var goerli = params.Network{
var sepolia = params.Network{
ChainID: sepoliaChainID,
ChainName: "Ethereum Sepolia",
RPCURL: "https://sepolia-archival.rpc.grove.city/v1/",
FallbackURL: "https://sepolia.infura.io/v3/",
RPCURL: "https://sepolia.infura.io/v3/",
FallbackURL: "",
BlockExplorerURL: "https://sepolia.etherscan.io/",
IconURL: "network/Network=Testnet",
ChainColor: "#51D0F0",
ChainColor: "#627EEA",
ShortName: "eth",
NativeCurrencyName: "Ether",
NativeCurrencySymbol: "ETH",
@ -103,7 +103,7 @@ var optimismGoerli = params.Network{
FallbackURL: "",
BlockExplorerURL: "https://goerli-optimism.etherscan.io/",
IconURL: "network/Network=Testnet",
ChainColor: "#939BA1",
ChainColor: "#E90101",
ShortName: "goOpt",
NativeCurrencyName: "Ether",
NativeCurrencySymbol: "ETH",
@ -121,7 +121,7 @@ var optimismSepolia = params.Network{
FallbackURL: "",
BlockExplorerURL: "https://sepolia-optimism.etherscan.io/",
IconURL: "network/Network=Testnet",
ChainColor: "#939BA1",
ChainColor: "#E90101",
ShortName: "opt",
NativeCurrencyName: "Ether",
NativeCurrencySymbol: "ETH",
@ -157,7 +157,7 @@ var arbitrumGoerli = params.Network{
FallbackURL: "",
BlockExplorerURL: "https://goerli.arbiscan.io/",
IconURL: "network/Network=Testnet",
ChainColor: "#939BA1",
ChainColor: "#51D0F0",
ShortName: "goArb",
NativeCurrencyName: "Ether",
NativeCurrencySymbol: "ETH",

View File

@ -27,23 +27,7 @@ const defaultKeycardPairingDataFile = "/ethereum/mainnet_rpc/keycard/pairings.js
var paths = []string{pathWalletRoot, pathEIP1581, pathDefaultChat, pathDefaultWallet}
const (
statusProdFleet = "status.prod"
statusTestFleet = "status.test"
wakuv2ProdFleet = "wakuv2.prod"
wakuv2TestFleet = "wakuv2.test"
shardsTest = "shards.test"
)
var DefaultWakuNodes = map[string][]string{
statusProdFleet: []string{"enrtree://AL65EKLJAUXKKPG43HVTML5EFFWEZ7L4LOKTLZCLJASG4DSESQZEC@prod.status.nodes.status.im"},
statusTestFleet: []string{"enrtree://AIO6LUM3IVWCU2KCPBBI6FEH2W42IGK3ASCZHZGG5TIXUR56OGQUO@test.status.nodes.status.im"},
wakuv2ProdFleet: []string{"enrtree://ANEDLO25QVUGJOUTQFRYKWX6P4Z4GKVESBMHML7DZ6YK4LGS5FC5O@prod.wakuv2.nodes.status.im"},
wakuv2TestFleet: []string{"enrtree://AO47IDOLBKH72HIZZOXQP6NMRESAN7CHYWIBNXDXWRJRZWLODKII6@test.wakuv2.nodes.status.im"},
shardsTest: []string{"enrtree://AMOJVZX4V6EXP7NTJPMAYJYST2QP6AJXYW76IU6VGJS7UVSNDYZG4@boot.test.shards.nodes.status.im"},
}
var DefaultFleet = shardsTest
var DefaultFleet = params.FleetShardsTest
func defaultSettings(generatedAccountInfo generator.GeneratedAccountInfo, derivedAddresses map[string]generator.AccountInfo, mnemonic *string) (*settings.Settings, error) {
chatKeyString := derivedAddresses[pathDefaultChat].PublicKey
@ -83,6 +67,7 @@ func defaultSettings(generatedAccountInfo generator.GeneratedAccountInfo, derive
s.UseMailservers = true
s.PreviewPrivacy = true
s.PeerSyncingEnabled = false
s.Currency = "usd"
s.LinkPreviewRequestEnabled = true
@ -125,7 +110,6 @@ func SetFleet(fleet string, nodeConfig *params.NodeConfig) error {
DiscoveryLimit: 20,
Host: "0.0.0.0",
AutoUpdate: true,
PeerExchange: true,
}
clusterConfig, err := params.LoadClusterConfigFromFleet(fleet)
@ -134,10 +118,10 @@ func SetFleet(fleet string, nodeConfig *params.NodeConfig) error {
}
nodeConfig.ClusterConfig = *clusterConfig
nodeConfig.ClusterConfig.Fleet = fleet
nodeConfig.ClusterConfig.WakuNodes = DefaultWakuNodes[fleet]
nodeConfig.ClusterConfig.DiscV5BootstrapNodes = DefaultWakuNodes[fleet]
nodeConfig.ClusterConfig.WakuNodes = params.DefaultWakuNodes(fleet)
nodeConfig.ClusterConfig.DiscV5BootstrapNodes = params.DefaultWakuNodes(fleet)
if fleet == shardsTest {
if fleet == params.FleetShardsTest {
nodeConfig.ClusterConfig.ClusterID = shardsTestClusterID
nodeConfig.WakuV2Config.UseShardAsDefaultTopic = true
}
@ -202,7 +186,7 @@ func buildWalletConfig(request *requests.WalletSecretsConfig) params.WalletConfi
return walletConfig
}
func defaultNodeConfig(installationID string, request *requests.CreateAccount) (*params.NodeConfig, error) {
func defaultNodeConfig(installationID string, request *requests.CreateAccount, opts ...params.Option) (*params.NodeConfig, error) {
// Set mainnet
nodeConfig := &params.NodeConfig{}
nodeConfig.NetworkID = request.NetworkID
@ -288,6 +272,12 @@ func defaultNodeConfig(installationID string, request *requests.CreateAccount) (
nodeConfig.Networks = BuildDefaultNetworks(request)
for _, opt := range opts {
if err := opt(nodeConfig); err != nil {
return nil, err
}
}
return nodeConfig, nil
}

View File

@ -18,7 +18,6 @@ import (
"github.com/imdario/mergo"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
ethcrypto "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log"
@ -49,7 +48,6 @@ import (
"github.com/status-im/status-go/services/ext"
"github.com/status-im/status-go/services/personal"
"github.com/status-im/status-go/services/typeddata"
wcommon "github.com/status-im/status-go/services/wallet/common"
"github.com/status-im/status-go/signal"
"github.com/status-im/status-go/transactions"
"github.com/status-im/status-go/walletdatabase"
@ -624,20 +622,7 @@ func (b *GethStatusBackend) loginAccount(request *requests.Login) error {
defaultCfg.WalletConfig = buildWalletConfig(&request.WalletSecretsConfig)
settings, err := b.GetSettings()
if err != nil {
return err
}
var fleet string
fleetPtr := settings.Fleet
if fleetPtr == nil || *fleetPtr == "" {
fleet = DefaultFleet
} else {
fleet = *fleetPtr
}
err = SetFleet(fleet, defaultCfg)
err = b.UpdateNodeConfigFleet(acc, password, defaultCfg)
if err != nil {
return err
}
@ -705,7 +690,41 @@ func (b *GethStatusBackend) loginAccount(request *requests.Login) error {
}
return nil
}
// UpdateNodeConfigFleet loads the fleet from the settings and updates the node configuration
// If the fleet in settings is empty, or not supported anymore, it will be overridden with the default fleet.
// In that case settings fleet value remain the same, only runtime node configuration is updated.
func (b *GethStatusBackend) UpdateNodeConfigFleet(acc multiaccounts.Account, password string, config *params.NodeConfig) error {
if config == nil {
return nil
}
err := b.ensureDBsOpened(acc, password)
if err != nil {
return err
}
accountSettings, err := b.GetSettings()
if err != nil {
return err
}
fleet := accountSettings.GetFleet()
if !params.IsFleetSupported(fleet) {
b.log.Warn("fleet is not supported, overriding with default value",
"fleet", fleet,
"defaultFleet", DefaultFleet)
fleet = DefaultFleet
}
err = SetFleet(fleet, config)
if err != nil {
return err
}
return nil
}
func (b *GethStatusBackend) startNodeWithAccount(acc multiaccounts.Account, password string, inputNodeCfg *params.NodeConfig) error {
@ -1279,7 +1298,7 @@ func (b *GethStatusBackend) GetKeyUIDByMnemonic(mnemonic string) (string, error)
return info.KeyUID, nil
}
func (b *GethStatusBackend) generateOrImportAccount(mnemonic string, customizationColorClock uint64, request *requests.CreateAccount) (*multiaccounts.Account, error) {
func (b *GethStatusBackend) generateOrImportAccount(mnemonic string, customizationColorClock uint64, request *requests.CreateAccount, opts ...params.Option) (*multiaccounts.Account, error) {
keystoreDir := keystoreRelativePath
b.UpdateRootDataDir(request.BackupDisabledDataDir)
@ -1363,7 +1382,7 @@ func (b *GethStatusBackend) generateOrImportAccount(mnemonic string, customizati
//settings.MnemonicWasNotShown = true
}
nodeConfig, err := defaultNodeConfig(settings.InstallationID, request)
nodeConfig, err := defaultNodeConfig(settings.InstallationID, request, opts...)
if err != nil {
return nil, err
}
@ -1411,12 +1430,12 @@ func (b *GethStatusBackend) generateOrImportAccount(mnemonic string, customizati
return &account, nil
}
func (b *GethStatusBackend) CreateAccountAndLogin(request *requests.CreateAccount) (*multiaccounts.Account, error) {
func (b *GethStatusBackend) CreateAccountAndLogin(request *requests.CreateAccount, opts ...params.Option) (*multiaccounts.Account, error) {
if err := request.Validate(); err != nil {
return nil, err
}
return b.generateOrImportAccount("", 1, request)
return b.generateOrImportAccount("", 1, request, opts...)
}
func (b *GethStatusBackend) ConvertToRegularAccount(mnemonic string, currPassword string, newPassword string) error {
@ -1890,24 +1909,7 @@ func (b *GethStatusBackend) SendTransaction(sendArgs transactions.SendTxArgs, pa
return hash, err
}
hash, err = b.transactor.SendTransaction(sendArgs, verifiedAccount)
if err != nil {
return
}
err = b.statusNode.PendingTracker().TrackPendingTransaction(
wcommon.ChainID(b.transactor.NetworkID()),
common.Hash(hash),
common.Address(sendArgs.From),
transactions.WalletTransfer,
transactions.AutoDelete,
)
if err != nil {
log.Error("TrackPendingTransaction error", "error", err)
return
}
return
return b.transactor.SendTransaction(sendArgs, verifiedAccount)
}
func (b *GethStatusBackend) SendTransactionWithChainID(chainID uint64, sendArgs transactions.SendTxArgs, password string) (hash types.Hash, err error) {
@ -1916,45 +1918,11 @@ func (b *GethStatusBackend) SendTransactionWithChainID(chainID uint64, sendArgs
return hash, err
}
hash, err = b.transactor.SendTransactionWithChainID(chainID, sendArgs, verifiedAccount)
if err != nil {
return
}
err = b.statusNode.PendingTracker().TrackPendingTransaction(
wcommon.ChainID(b.transactor.NetworkID()),
common.Hash(hash),
common.Address(sendArgs.From),
transactions.WalletTransfer,
transactions.AutoDelete,
)
if err != nil {
log.Error("TrackPendingTransaction error", "error", err)
return
}
return
return b.transactor.SendTransactionWithChainID(chainID, sendArgs, verifiedAccount)
}
func (b *GethStatusBackend) SendTransactionWithSignature(sendArgs transactions.SendTxArgs, sig []byte) (hash types.Hash, err error) {
hash, err = b.transactor.BuildTransactionAndSendWithSignature(b.transactor.NetworkID(), sendArgs, sig)
if err != nil {
return
}
err = b.statusNode.PendingTracker().TrackPendingTransaction(
wcommon.ChainID(b.transactor.NetworkID()),
common.Hash(hash),
common.Address(sendArgs.From),
transactions.WalletTransfer,
transactions.AutoDelete,
)
if err != nil {
log.Error("TrackPendingTransaction error", "error", err)
return
}
return
return b.transactor.BuildTransactionAndSendWithSignature(b.transactor.NetworkID(), sendArgs, sig)
}
// HashTransaction validate the transaction and returns new sendArgs and the transaction hash.

File diff suppressed because one or more lines are too long

View File

@ -53,7 +53,7 @@
// 1635942154_add_backup_setting.up.sql (287B)
// 1637745568_add_auto_message_setting.up.sql (122B)
// 1640111208_nodeconfig.up.sql (7.659kB)
// doc.go (85B)
// doc.go (105B)
package migrationsprevnodecfg
@ -136,7 +136,7 @@ func _0001_appDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0001_app.down.sql", size: 356, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "0001_app.down.sql", size: 356, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xb5, 0x25, 0xa0, 0xf8, 0x7d, 0x2d, 0xd, 0xcf, 0x18, 0xe4, 0x73, 0xc3, 0x95, 0xf5, 0x24, 0x20, 0xa9, 0xe6, 0x9e, 0x1d, 0x93, 0xe5, 0xc5, 0xad, 0x93, 0x8f, 0x5e, 0x40, 0xb5, 0x30, 0xaa, 0x25}}
return a, nil
}
@ -156,7 +156,7 @@ func _0001_appUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0001_app.up.sql", size: 2967, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "0001_app.up.sql", size: 2967, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf7, 0x3a, 0xa7, 0xf2, 0x8f, 0xfa, 0x82, 0x7c, 0xc5, 0x49, 0xac, 0xac, 0xf, 0xc, 0x77, 0xe2, 0xba, 0xe8, 0x4d, 0xe, 0x6f, 0x5d, 0x2c, 0x2c, 0x18, 0x80, 0xc2, 0x1d, 0xe, 0x25, 0xe, 0x18}}
return a, nil
}
@ -176,7 +176,7 @@ func _0002_tokensDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0002_tokens.down.sql", size: 19, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "0002_tokens.down.sql", size: 19, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd1, 0x31, 0x2, 0xcc, 0x2f, 0x38, 0x90, 0xf7, 0x58, 0x37, 0x47, 0xf4, 0x18, 0xf7, 0x72, 0x74, 0x67, 0x14, 0x7e, 0xf3, 0xb1, 0xd6, 0x5f, 0xb0, 0xd5, 0xe7, 0x91, 0xf4, 0x26, 0x77, 0x8e, 0x68}}
return a, nil
}
@ -196,7 +196,7 @@ func _0002_tokensUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0002_tokens.up.sql", size: 248, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "0002_tokens.up.sql", size: 248, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xcc, 0xd6, 0xde, 0xd3, 0x7b, 0xee, 0x92, 0x11, 0x38, 0xa4, 0xeb, 0x84, 0xca, 0xcb, 0x37, 0x75, 0x5, 0x77, 0x7f, 0x14, 0x39, 0xee, 0xa1, 0x8b, 0xd4, 0x5c, 0x6e, 0x55, 0x6, 0x50, 0x16, 0xd4}}
return a, nil
}
@ -216,7 +216,7 @@ func _0003_settingsDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0003_settings.down.sql", size: 118, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "0003_settings.down.sql", size: 118, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe5, 0xa6, 0xf5, 0xc0, 0x60, 0x64, 0x77, 0xe2, 0xe7, 0x3c, 0x9b, 0xb1, 0x52, 0xa9, 0x95, 0x16, 0xf8, 0x60, 0x2f, 0xa5, 0xeb, 0x46, 0xb9, 0xb9, 0x8f, 0x4c, 0xf4, 0xfd, 0xbb, 0xe7, 0xe5, 0xe5}}
return a, nil
}
@ -236,7 +236,7 @@ func _0003_settingsUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0003_settings.up.sql", size: 1311, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "0003_settings.up.sql", size: 1311, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xea, 0x35, 0x0, 0xeb, 0xe2, 0x33, 0x68, 0xb9, 0xf4, 0xf6, 0x8e, 0x9e, 0x10, 0xe9, 0x58, 0x68, 0x28, 0xb, 0xcd, 0xec, 0x74, 0x71, 0xa7, 0x9a, 0x5a, 0x77, 0x59, 0xb1, 0x13, 0x1c, 0xa1, 0x5b}}
return a, nil
}
@ -256,7 +256,7 @@ func _0004_pending_stickersDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0004_pending_stickers.down.sql", size: 0, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "0004_pending_stickers.down.sql", size: 0, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}}
return a, nil
}
@ -276,7 +276,7 @@ func _0004_pending_stickersUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0004_pending_stickers.up.sql", size: 61, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "0004_pending_stickers.up.sql", size: 61, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x3c, 0xed, 0x25, 0xdf, 0x75, 0x2, 0x6c, 0xf0, 0xa2, 0xa8, 0x37, 0x62, 0x65, 0xad, 0xfd, 0x98, 0xa0, 0x9d, 0x63, 0x94, 0xdf, 0x6b, 0x46, 0xe0, 0x68, 0xec, 0x9c, 0x7f, 0x77, 0xdd, 0xb3, 0x6}}
return a, nil
}
@ -296,7 +296,7 @@ func _0005_waku_modeDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0005_waku_mode.down.sql", size: 0, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "0005_waku_mode.down.sql", size: 0, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}}
return a, nil
}
@ -316,7 +316,7 @@ func _0005_waku_modeUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0005_waku_mode.up.sql", size: 146, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "0005_waku_mode.up.sql", size: 146, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xa6, 0x91, 0xc, 0xd7, 0x89, 0x61, 0x2e, 0x4c, 0x5a, 0xb6, 0x67, 0xd1, 0xc1, 0x42, 0x24, 0x38, 0xd6, 0x1b, 0x75, 0x41, 0x9c, 0x23, 0xb0, 0xca, 0x5c, 0xf1, 0x5c, 0xd0, 0x13, 0x92, 0x3e, 0xe1}}
return a, nil
}
@ -336,7 +336,7 @@ func _0006_appearanceUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0006_appearance.up.sql", size: 67, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "0006_appearance.up.sql", size: 67, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xae, 0x6, 0x25, 0x6c, 0xe4, 0x9d, 0xa7, 0x72, 0xe8, 0xbc, 0xe4, 0x1f, 0x1e, 0x2d, 0x7c, 0xb7, 0xf6, 0xa3, 0xec, 0x3b, 0x4e, 0x93, 0x2e, 0xa4, 0xec, 0x6f, 0xe5, 0x95, 0x94, 0xe8, 0x4, 0xfb}}
return a, nil
}
@ -356,7 +356,7 @@ func _0007_enable_waku_defaultUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0007_enable_waku_default.up.sql", size: 38, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "0007_enable_waku_default.up.sql", size: 38, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd4, 0x42, 0xb6, 0xe5, 0x48, 0x41, 0xeb, 0xc0, 0x7e, 0x3b, 0xe6, 0x8e, 0x96, 0x33, 0x20, 0x92, 0x24, 0x5a, 0x60, 0xfa, 0xa0, 0x3, 0x5e, 0x76, 0x4b, 0x89, 0xaa, 0x37, 0x66, 0xbc, 0x26, 0x11}}
return a, nil
}
@ -376,7 +376,7 @@ func _0008_add_push_notificationsUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0008_add_push_notifications.up.sql", size: 349, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "0008_add_push_notifications.up.sql", size: 349, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x5a, 0x0, 0xbf, 0xd0, 0xdd, 0xcd, 0x73, 0xe0, 0x7c, 0x56, 0xef, 0xdc, 0x57, 0x61, 0x94, 0x64, 0x70, 0xb9, 0xfa, 0xa1, 0x2a, 0x36, 0xc, 0x2f, 0xf8, 0x95, 0xa, 0x57, 0x3e, 0x7a, 0xd7, 0x12}}
return a, nil
}
@ -396,7 +396,7 @@ func _0009_enable_sending_push_notificationsDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0009_enable_sending_push_notifications.down.sql", size: 49, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "0009_enable_sending_push_notifications.down.sql", size: 49, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe9, 0xae, 0x1b, 0x41, 0xcb, 0x9c, 0x2c, 0x93, 0xc6, 0x2a, 0x77, 0x3, 0xb9, 0x51, 0xe0, 0x68, 0x68, 0x0, 0xf7, 0x5b, 0xb3, 0x1e, 0x94, 0x44, 0xba, 0x9c, 0xd0, 0x3b, 0x80, 0x21, 0x6f, 0xb5}}
return a, nil
}
@ -416,7 +416,7 @@ func _0009_enable_sending_push_notificationsUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0009_enable_sending_push_notifications.up.sql", size: 49, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "0009_enable_sending_push_notifications.up.sql", size: 49, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x1b, 0x80, 0xe4, 0x9c, 0xc8, 0xb8, 0xd5, 0xef, 0xce, 0x74, 0x9b, 0x7b, 0xdd, 0xa, 0x99, 0x1e, 0xef, 0x7f, 0xb8, 0x99, 0x84, 0x4, 0x0, 0x6b, 0x1d, 0x2c, 0xa, 0xf8, 0x2c, 0x4f, 0xb5, 0x44}}
return a, nil
}
@ -436,7 +436,7 @@ func _0010_add_block_mentionsDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0010_add_block_mentions.down.sql", size: 83, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "0010_add_block_mentions.down.sql", size: 83, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x6d, 0x9e, 0x27, 0x1e, 0xba, 0x9f, 0xca, 0xae, 0x98, 0x2e, 0x6e, 0xe3, 0xdd, 0xac, 0x73, 0x34, 0x4e, 0x69, 0x92, 0xb5, 0xf6, 0x9, 0xab, 0x50, 0x35, 0xd, 0xee, 0xeb, 0x3e, 0xcc, 0x7e, 0xce}}
return a, nil
}
@ -456,7 +456,7 @@ func _0010_add_block_mentionsUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0010_add_block_mentions.up.sql", size: 89, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "0010_add_block_mentions.up.sql", size: 89, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd7, 0x23, 0x85, 0xa2, 0xb5, 0xb6, 0xb4, 0x3f, 0xdc, 0x4e, 0xff, 0xe2, 0x6b, 0x66, 0x68, 0x5e, 0xb2, 0xb4, 0x14, 0xb2, 0x1b, 0x4d, 0xb1, 0xce, 0xf7, 0x6, 0x58, 0xa7, 0xaf, 0x93, 0x3f, 0x25}}
return a, nil
}
@ -476,7 +476,7 @@ func _0011_allow_webview_permission_requestsDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0011_allow_webview_permission_requests.down.sql", size: 0, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "0011_allow_webview_permission_requests.down.sql", size: 0, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}}
return a, nil
}
@ -496,7 +496,7 @@ func _0011_allow_webview_permission_requestsUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0011_allow_webview_permission_requests.up.sql", size: 88, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "0011_allow_webview_permission_requests.up.sql", size: 88, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x43, 0x5f, 0x22, 0x4c, 0x98, 0x1d, 0xc6, 0xf4, 0x89, 0xaf, 0xf4, 0x44, 0xba, 0xf8, 0x28, 0xa7, 0xb5, 0xb9, 0xf0, 0xf2, 0xcb, 0x5, 0x59, 0x7a, 0xc, 0xdf, 0xd3, 0x38, 0xa4, 0xb8, 0x98, 0xc2}}
return a, nil
}
@ -516,7 +516,7 @@ func _0012_pending_transactionsDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0012_pending_transactions.down.sql", size: 33, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "0012_pending_transactions.down.sql", size: 33, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x7e, 0x41, 0xfe, 0x5c, 0xd8, 0xc3, 0x29, 0xfd, 0x31, 0x78, 0x99, 0x7a, 0xeb, 0x17, 0x62, 0x88, 0x41, 0xb3, 0xe7, 0xb5, 0x5, 0x0, 0x90, 0xa1, 0x7, 0x1a, 0x23, 0x88, 0x81, 0xba, 0x56, 0x9d}}
return a, nil
}
@ -536,7 +536,7 @@ func _0012_pending_transactionsUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0012_pending_transactions.up.sql", size: 321, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "0012_pending_transactions.up.sql", size: 321, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd, 0x17, 0xff, 0xd7, 0xa7, 0x49, 0x1e, 0x7b, 0x34, 0x63, 0x7c, 0x53, 0xaa, 0x6b, 0x2d, 0xc8, 0xe0, 0x82, 0x21, 0x90, 0x3a, 0x94, 0xf1, 0xa6, 0xe4, 0x70, 0xe5, 0x85, 0x1a, 0x48, 0x25, 0xb}}
return a, nil
}
@ -556,7 +556,7 @@ func _0013_favouritesDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0013_favourites.down.sql", size: 23, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "0013_favourites.down.sql", size: 23, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x32, 0xf8, 0x55, 0x13, 0x4f, 0x4a, 0x19, 0x83, 0x9c, 0xda, 0x34, 0xb8, 0x3, 0x54, 0x82, 0x1e, 0x99, 0x36, 0x6b, 0x42, 0x3, 0xf6, 0x43, 0xde, 0xe6, 0x32, 0xb6, 0xdf, 0xe2, 0x59, 0x8c, 0x84}}
return a, nil
}
@ -576,7 +576,7 @@ func _0013_favouritesUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0013_favourites.up.sql", size: 132, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "0013_favourites.up.sql", size: 132, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xbe, 0x1, 0x27, 0x38, 0x76, 0xf5, 0xcb, 0x61, 0xda, 0x5b, 0xce, 0xd9, 0x8b, 0x18, 0x77, 0x61, 0x84, 0xe7, 0x22, 0xe2, 0x13, 0x99, 0xab, 0x32, 0xbc, 0xbe, 0xed, 0x1f, 0x2f, 0xb0, 0xe4, 0x8d}}
return a, nil
}
@ -596,7 +596,7 @@ func _0014_add_use_mailserversDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0014_add_use_mailservers.down.sql", size: 0, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "0014_add_use_mailservers.down.sql", size: 0, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}}
return a, nil
}
@ -616,7 +616,7 @@ func _0014_add_use_mailserversUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0014_add_use_mailservers.up.sql", size: 111, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "0014_add_use_mailservers.up.sql", size: 111, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xc9, 0xba, 0x65, 0xbf, 0x1b, 0xc9, 0x6d, 0x45, 0xf2, 0xf5, 0x30, 0x7c, 0xc1, 0xde, 0xb8, 0xe3, 0x3f, 0xa9, 0x2f, 0x9f, 0xea, 0x1, 0x29, 0x29, 0x65, 0xe7, 0x38, 0xab, 0xa4, 0x62, 0xf, 0xd0}}
return a, nil
}
@ -636,7 +636,7 @@ func _0015_link_previewsDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0015_link_previews.down.sql", size: 0, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "0015_link_previews.down.sql", size: 0, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}}
return a, nil
}
@ -656,7 +656,7 @@ func _0015_link_previewsUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0015_link_previews.up.sql", size: 203, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "0015_link_previews.up.sql", size: 203, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xb1, 0xf7, 0x38, 0x25, 0xa6, 0xfc, 0x6b, 0x9, 0xe4, 0xd9, 0xbf, 0x58, 0x7b, 0x80, 0xd8, 0x48, 0x63, 0xde, 0xa5, 0x5e, 0x30, 0xa3, 0xeb, 0x68, 0x8e, 0x6a, 0x9f, 0xfd, 0xf4, 0x46, 0x41, 0x34}}
return a, nil
}
@ -676,7 +676,7 @@ func _0016_local_notifications_preferencesDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0016_local_notifications_preferences.down.sql", size: 43, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "0016_local_notifications_preferences.down.sql", size: 43, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe0, 0x50, 0xc7, 0xdd, 0x53, 0x9c, 0x5d, 0x1e, 0xb5, 0x71, 0x25, 0x50, 0x58, 0xcf, 0x6d, 0xbe, 0x5a, 0x8, 0x12, 0xc9, 0x13, 0xd, 0x9a, 0x3d, 0x4b, 0x7a, 0x2f, 0x1b, 0xe5, 0x23, 0x52, 0x78}}
return a, nil
}
@ -696,7 +696,7 @@ func _0016_local_notifications_preferencesUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0016_local_notifications_preferences.up.sql", size: 204, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "0016_local_notifications_preferences.up.sql", size: 204, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x3f, 0x3a, 0x16, 0x25, 0xdf, 0xba, 0x62, 0xd3, 0x81, 0x73, 0xc, 0x10, 0x85, 0xbc, 0x8d, 0xe, 0x1d, 0x62, 0xcb, 0xb, 0x6d, 0x8c, 0x4f, 0x63, 0x5f, 0xe2, 0xd, 0xc5, 0x46, 0xa8, 0x35, 0x5b}}
return a, nil
}
@ -716,7 +716,7 @@ func _0017_bookmarksDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0017_bookmarks.down.sql", size: 22, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "0017_bookmarks.down.sql", size: 22, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x9a, 0x13, 0x2a, 0x44, 0xb0, 0x3, 0x18, 0x63, 0xb8, 0x33, 0xda, 0x3a, 0xeb, 0xb8, 0xcb, 0xd1, 0x98, 0x29, 0xa7, 0xf0, 0x6, 0x9d, 0xc9, 0x62, 0xe7, 0x89, 0x7f, 0x77, 0xaf, 0xec, 0x6b, 0x8f}}
return a, nil
}
@ -736,7 +736,7 @@ func _0017_bookmarksUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0017_bookmarks.up.sql", size: 147, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "0017_bookmarks.up.sql", size: 147, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xbc, 0x47, 0xe1, 0xe3, 0xd8, 0xc6, 0x4, 0x6d, 0x5f, 0x2f, 0xa, 0x51, 0xa6, 0x8c, 0x6a, 0xe0, 0x3d, 0x8c, 0x91, 0x47, 0xbc, 0x1, 0x75, 0x46, 0x92, 0x2, 0x18, 0x6e, 0xe3, 0x4f, 0x18, 0x57}}
return a, nil
}
@ -756,7 +756,7 @@ func _0018_profile_pictures_visibilityUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0018_profile_pictures_visibility.up.sql", size: 84, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "0018_profile_pictures_visibility.up.sql", size: 84, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 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}}
return a, nil
}
@ -776,7 +776,7 @@ func _0019_blocks_ranges_extra_dataUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0019_blocks_ranges_extra_data.up.sql", size: 89, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "0019_blocks_ranges_extra_data.up.sql", size: 89, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xa3, 0x96, 0x32, 0x58, 0xf0, 0xb9, 0xe1, 0x70, 0x81, 0xca, 0x8d, 0x45, 0x57, 0x8a, 0x7, 0x5d, 0x9e, 0x2a, 0x30, 0xb, 0xad, 0x5f, 0xf8, 0xd4, 0x30, 0x94, 0x73, 0x37, 0x8d, 0xc1, 0x9a, 0xed}}
return a, nil
}
@ -796,7 +796,7 @@ func _0020_metricsUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0020_metrics.up.sql", size: 235, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "0020_metrics.up.sql", size: 235, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe8, 0x32, 0xbc, 0xb6, 0x9b, 0x5a, 0x8f, 0x9f, 0x4c, 0x90, 0x81, 0x3e, 0x2e, 0xd1, 0x23, 0xcd, 0xf1, 0x83, 0x35, 0xca, 0x66, 0x87, 0x52, 0x4e, 0x30, 0x3e, 0x4f, 0xa8, 0xfd, 0x30, 0x16, 0xbd}}
return a, nil
}
@ -816,7 +816,7 @@ func _0021_add_session_id_to_metricsUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0021_add_session_id_to_metrics.up.sql", size: 55, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "0021_add_session_id_to_metrics.up.sql", size: 55, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xb7, 0x81, 0xfc, 0x97, 0xd1, 0x8b, 0xea, 0x8e, 0xd7, 0xc2, 0x53, 0x62, 0xe9, 0xbc, 0xf, 0x8c, 0x46, 0x41, 0x41, 0xb7, 0x6, 0x35, 0xf5, 0xba, 0xbb, 0x28, 0x50, 0x48, 0xbf, 0x36, 0x90, 0x5c}}
return a, nil
}
@ -836,7 +836,7 @@ func _0022_pending_transfersUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0022_pending_transfers.up.sql", size: 706, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "0022_pending_transfers.up.sql", size: 706, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x6a, 0x9, 0xe6, 0x6, 0xae, 0x60, 0xdd, 0xbb, 0x76, 0xac, 0xe0, 0x57, 0x30, 0x67, 0x37, 0x93, 0x40, 0x13, 0xec, 0xf2, 0x6e, 0x61, 0xa, 0x14, 0xb2, 0xb1, 0xbd, 0x91, 0xf8, 0x89, 0xb3, 0xe3}}
return a, nil
}
@ -856,7 +856,7 @@ func _1618237885_settings_anon_metrics_should_sendUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1618237885_settings_anon_metrics_should_send.up.sql", size: 80, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "1618237885_settings_anon_metrics_should_send.up.sql", size: 80, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xea, 0x6c, 0x1d, 0x1f, 0x54, 0x62, 0x18, 0x22, 0x5c, 0xa7, 0x8c, 0x59, 0x24, 0xd3, 0x4d, 0x55, 0xc4, 0x2a, 0x9e, 0x4c, 0x37, 0x6b, 0xfd, 0xac, 0xec, 0xb7, 0x68, 0x21, 0x26, 0x26, 0xf3, 0x92}}
return a, nil
}
@ -876,7 +876,7 @@ func _1618395756_contacts_onlyUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1618395756_contacts_only.up.sql", size: 136, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "1618395756_contacts_only.up.sql", size: 136, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x1, 0xe3, 0xd0, 0xe7, 0xf2, 0x6e, 0xbf, 0x27, 0xf6, 0xe2, 0x2e, 0x16, 0x4b, 0x52, 0x3b, 0xcf, 0x63, 0x52, 0xfc, 0x1d, 0x43, 0xba, 0x42, 0xf9, 0x1e, 0x1e, 0x39, 0x40, 0xed, 0x0, 0x20, 0xa8}}
return a, nil
}
@ -896,7 +896,7 @@ func _1622184614_add_default_sync_periodUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1622184614_add_default_sync_period.up.sql", size: 125, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "1622184614_add_default_sync_period.up.sql", size: 125, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x60, 0x39, 0xeb, 0x8f, 0xdc, 0x1, 0x56, 0xc1, 0x9b, 0xaa, 0xda, 0x44, 0xe0, 0xdb, 0xda, 0x2c, 0xe7, 0x71, 0x8d, 0xbc, 0xc1, 0x9a, 0x4f, 0x48, 0xe0, 0x5e, 0x81, 0x1e, 0x8e, 0x6a, 0x4d, 0x3}}
return a, nil
}
@ -916,7 +916,7 @@ func _1625872445_user_statusUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1625872445_user_status.up.sql", size: 351, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "1625872445_user_status.up.sql", size: 351, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf5, 0xa, 0xfe, 0x7a, 0xcc, 0x9e, 0x35, 0x26, 0xb, 0xc8, 0xf2, 0x7d, 0xfa, 0x4b, 0xcf, 0x53, 0x20, 0x76, 0xc7, 0xd, 0xbc, 0x78, 0x4f, 0x74, 0x2d, 0x2e, 0x2e, 0x7e, 0x62, 0xae, 0x78, 0x1f}}
return a, nil
}
@ -936,7 +936,7 @@ func _1627983977_add_gif_to_settingsUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1627983977_add_gif_to_settings.up.sql", size: 102, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "1627983977_add_gif_to_settings.up.sql", size: 102, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x63, 0xe6, 0xe1, 0x97, 0x64, 0x4c, 0xe2, 0x14, 0xb1, 0x96, 0x3a, 0xb0, 0xb9, 0xb7, 0xb5, 0x78, 0x4a, 0x39, 0x69, 0x89, 0xb7, 0x89, 0x19, 0xb8, 0x89, 0x1, 0xc5, 0xc2, 0x85, 0x53, 0xe2, 0x83}}
return a, nil
}
@ -956,7 +956,7 @@ func _1628580203_add_hidden_accountUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1628580203_add_hidden_account.up.sql", size: 67, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "1628580203_add_hidden_account.up.sql", size: 67, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xcb, 0x30, 0xf1, 0xd4, 0x60, 0xe2, 0x28, 0x14, 0xcb, 0x16, 0xb, 0x9, 0xea, 0x17, 0xa, 0x9e, 0x89, 0xa8, 0x32, 0x32, 0xf8, 0x4d, 0xa0, 0xe1, 0xe5, 0x79, 0xbd, 0x7d, 0x79, 0xe9, 0x4c, 0x9e}}
return a, nil
}
@ -976,7 +976,7 @@ func _1629123384_add_id_to_app_metricsUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1629123384_add_id_to_app_metrics.up.sql", size: 589, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "1629123384_add_id_to_app_metrics.up.sql", size: 589, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xdf, 0x66, 0xc0, 0x69, 0xb, 0xad, 0x49, 0x7c, 0x8c, 0x67, 0xb8, 0xd6, 0x8d, 0x5d, 0x86, 0x1f, 0xa4, 0x53, 0xf5, 0x8, 0x1, 0xfd, 0x38, 0x49, 0xee, 0x84, 0xc0, 0xd8, 0x17, 0x72, 0x3, 0xb3}}
return a, nil
}
@ -996,7 +996,7 @@ func _1630401853_add_opensea_enabled_to_settingsUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1630401853_add_opensea_enabled_to_settings.up.sql", size: 70, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "1630401853_add_opensea_enabled_to_settings.up.sql", size: 70, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x6, 0x91, 0x86, 0x15, 0xc8, 0x99, 0xe3, 0xae, 0xa, 0x6e, 0x94, 0x48, 0x51, 0x5b, 0x18, 0xe0, 0xbc, 0xaf, 0x34, 0x75, 0x55, 0x61, 0xd4, 0xc1, 0x85, 0xc7, 0x3d, 0x99, 0x9e, 0x1f, 0x37, 0x56}}
return a, nil
}
@ -1016,7 +1016,7 @@ func _1630464455_createSaved_addressesTableDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1630464455_create-saved_addresses-table.down.sql", size: 28, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "1630464455_create-saved_addresses-table.down.sql", size: 28, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x23, 0x52, 0x39, 0xb5, 0x42, 0xac, 0xcb, 0xa1, 0x44, 0xb7, 0x94, 0x26, 0x24, 0xb2, 0x12, 0xc, 0xc5, 0xbf, 0x63, 0x13, 0x6f, 0x3c, 0x4, 0x7b, 0xf0, 0xd, 0xfa, 0x55, 0x9e, 0x51, 0xf9, 0x7a}}
return a, nil
}
@ -1036,7 +1036,7 @@ func _1630464455_createSaved_addressesTableUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1630464455_create-saved_addresses-table.up.sql", size: 187, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "1630464455_create-saved_addresses-table.up.sql", size: 187, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x32, 0xf, 0x56, 0x18, 0xeb, 0x4e, 0xac, 0xd8, 0xd6, 0x91, 0xae, 0x83, 0xcf, 0x91, 0x9e, 0x4, 0x4b, 0x2, 0x1f, 0x6d, 0xba, 0xf6, 0x3, 0xf2, 0x98, 0x72, 0xf6, 0x91, 0x29, 0x96, 0x0, 0x35}}
return a, nil
}
@ -1056,7 +1056,7 @@ func _1630485153_networksDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1630485153_networks.down.sql", size: 21, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "1630485153_networks.down.sql", size: 21, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xbb, 0x3e, 0x57, 0xb7, 0xf7, 0x8, 0xbd, 0xb5, 0xc2, 0xea, 0xc, 0x45, 0xb7, 0x7, 0x9, 0xca, 0xe7, 0x48, 0x7e, 0x56, 0x4e, 0x44, 0x78, 0x8e, 0xe3, 0x87, 0x63, 0xaf, 0x16, 0x3f, 0xf9, 0x71}}
return a, nil
}
@ -1076,7 +1076,7 @@ func _1630485153_networksUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1630485153_networks.up.sql", size: 394, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "1630485153_networks.up.sql", size: 394, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xed, 0x9, 0x1d, 0x3, 0x86, 0xbd, 0xc5, 0xde, 0x3c, 0x1b, 0x40, 0x41, 0x7c, 0x61, 0x8, 0x80, 0x53, 0x87, 0x1b, 0x5a, 0x56, 0xd, 0x88, 0x1d, 0x60, 0x24, 0xce, 0x7b, 0x8f, 0xff, 0xaf, 0x36}}
return a, nil
}
@ -1096,7 +1096,7 @@ func _1632262444_profile_pictures_show_toUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1632262444_profile_pictures_show_to.up.sql", size: 81, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "1632262444_profile_pictures_show_to.up.sql", size: 81, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xc3, 0xa2, 0x5a, 0x94, 0xde, 0x86, 0x2a, 0x29, 0xf5, 0xb3, 0x36, 0xe7, 0x53, 0x81, 0x55, 0xc9, 0xb5, 0xc3, 0xf4, 0x8c, 0x65, 0x2c, 0x4c, 0x48, 0xfd, 0x3c, 0xb7, 0x14, 0xb4, 0xea, 0x7a, 0x13}}
return a, nil
}
@ -1116,7 +1116,7 @@ func _1635942153_add_telemetry_server_url_to_settingsUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1635942153_add_telemetry_server_url_to_settings.up.sql", size: 128, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "1635942153_add_telemetry_server_url_to_settings.up.sql", size: 128, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x6e, 0x9b, 0x1d, 0x39, 0x9c, 0x8d, 0x50, 0x86, 0xdf, 0xe5, 0x81, 0x55, 0xdc, 0x31, 0xcd, 0xb7, 0xc7, 0x5a, 0x67, 0x3b, 0x21, 0x99, 0xa5, 0x74, 0xb8, 0xd3, 0x58, 0xae, 0x29, 0x68, 0x2a, 0x8d}}
return a, nil
}
@ -1136,7 +1136,7 @@ func _1635942154_add_backup_settingUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1635942154_add_backup_setting.up.sql", size: 287, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "1635942154_add_backup_setting.up.sql", size: 287, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xb7, 0xe7, 0xfb, 0x70, 0x80, 0x5, 0xb4, 0x7b, 0x67, 0x8, 0x6e, 0x5f, 0x45, 0x17, 0xd9, 0x5f, 0x18, 0x66, 0x2f, 0x8a, 0x4f, 0xd4, 0x15, 0xe5, 0x2b, 0xbb, 0x25, 0x7a, 0x30, 0xad, 0x4c, 0x1a}}
return a, nil
}
@ -1156,7 +1156,7 @@ func _1637745568_add_auto_message_settingUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1637745568_add_auto_message_setting.up.sql", size: 122, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "1637745568_add_auto_message_setting.up.sql", size: 122, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x1d, 0xd8, 0xd2, 0xc2, 0x3a, 0xd7, 0xf1, 0x96, 0x6a, 0x35, 0xe5, 0x5c, 0xb9, 0xed, 0x4b, 0xf2, 0x5f, 0x80, 0x43, 0xca, 0x40, 0x57, 0x7e, 0xd7, 0x41, 0x9f, 0x70, 0x9f, 0xaf, 0x2a, 0xfc, 0x8f}}
return a, nil
}
@ -1176,12 +1176,12 @@ func _1640111208_nodeconfigUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1640111208_nodeconfig.up.sql", size: 7659, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
info := bindataFileInfo{name: "1640111208_nodeconfig.up.sql", size: 7659, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x8e, 0x5a, 0xc6, 0xed, 0x6, 0xcb, 0x51, 0x8b, 0x78, 0xe9, 0x10, 0x37, 0xd1, 0xad, 0x9b, 0x76, 0x9a, 0xb9, 0x72, 0x85, 0xe7, 0x8a, 0x7f, 0xf0, 0x81, 0xf8, 0x33, 0x59, 0x67, 0x8e, 0xeb, 0xb1}}
return a, nil
}
var _docGo = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x2c\xca\xb1\x11\x85\x20\x0c\x06\xe0\x9e\x29\xb2\x00\x49\xff\xb6\xc9\x83\xf8\x1f\x87\x26\x08\x9c\xf3\xdb\xd8\x7f\x43\x4b\x57\x18\xad\xfb\x4c\x49\x04\xf1\x83\xb9\x4d\xdd\x46\x88\xfc\x6f\x5e\x75\x2b\xe5\xd1\x41\x57\xc3\xd4\xdd\xc2\xd7\x98\xf6\x78\x54\x2b\x07\x28\x07\x31\xcb\x07\x19\x41\x2c\xe9\x0d\x00\x00\xff\xff\x09\x8c\xb2\x2f\x55\x00\x00\x00")
var _docGo = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x2c\xcb\x41\x0e\xc2\x20\x10\x05\xd0\x3d\xa7\xf8\x17\x00\x74\x65\x62\xe2\x61\xc6\x32\xfe\x90\xca\x0c\xd2\x89\xe7\xef\xa6\x6f\xff\xa6\x6c\xbb\x50\x71\xfc\xbe\x29\xd5\x4a\x7f\x52\x4d\x97\x84\x82\x9e\xdf\xdd\x9a\x84\x20\x0f\x6f\xd1\x87\xbe\xee\x8f\xdb\x05\x79\xee\xc4\xe8\x5c\x12\xdd\xed\x98\x4b\xff\xe6\x4d\xb7\x0f\x91\x1d\xa5\xd4\x2b\x17\x3a\x4a\x4d\x67\x00\x00\x00\xff\xff\x2c\x75\x2e\x34\x69\x00\x00\x00")
func docGoBytes() ([]byte, error) {
return bindataRead(
@ -1196,8 +1196,8 @@ func docGo() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "doc.go", size: 85, mode: os.FileMode(0644), modTime: time.Unix(1704726857, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe5, 0xd2, 0xea, 0xc5, 0xd, 0xc4, 0x7f, 0x95, 0x8e, 0xd5, 0xf5, 0x96, 0xf2, 0x1b, 0xcb, 0xc7, 0xc2, 0x46, 0x1, 0x78, 0x1d, 0x5d, 0x59, 0x19, 0x99, 0xdd, 0x5b, 0xf5, 0x63, 0xa5, 0x25, 0xb8}}
info := bindataFileInfo{name: "doc.go", size: 105, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x4f, 0xf, 0x66, 0x70, 0xa7, 0xe9, 0xe9, 0x73, 0xeb, 0x3e, 0x5e, 0x83, 0xab, 0x85, 0x52, 0x1d, 0x10, 0xb5, 0x18, 0xb4, 0x9c, 0x58, 0x69, 0x74, 0x61, 0xb7, 0xcf, 0xd5, 0x23, 0x3a, 0x1e, 0x3c}}
return a, nil
}

View File

@ -0,0 +1,135 @@
package circuitbreaker
import (
"fmt"
"strings"
"github.com/afex/hystrix-go/hystrix"
)
type FallbackFunc func() ([]any, error)
type CommandResult struct {
res []any
err error
}
func (cr CommandResult) Result() []any {
return cr.res
}
func (cr CommandResult) Error() error {
return cr.err
}
type Command struct {
functors []*Functor
}
func NewCommand(functors []*Functor) *Command {
return &Command{
functors: functors,
}
}
func (cmd *Command) Add(ftor *Functor) {
cmd.functors = append(cmd.functors, ftor)
}
func (cmd *Command) IsEmpty() bool {
return len(cmd.functors) == 0
}
type Config struct {
CommandName string
Timeout int
MaxConcurrentRequests int
RequestVolumeThreshold int
SleepWindow int
ErrorPercentThreshold int
}
type CircuitBreaker struct {
config Config
}
func NewCircuitBreaker(config Config) *CircuitBreaker {
return &CircuitBreaker{
config: config,
}
}
type Functor struct {
Exec FallbackFunc
}
func NewFunctor(exec FallbackFunc) *Functor {
return &Functor{
Exec: exec,
}
}
// This a blocking function
func (eh *CircuitBreaker) Execute(cmd Command) CommandResult {
resultChan := make(chan CommandResult, 1)
var result CommandResult
for i := 0; i < len(cmd.functors); i += 2 {
f1 := cmd.functors[i]
var f2 *Functor
if i+1 < len(cmd.functors) {
f2 = cmd.functors[i+1]
}
circuitName := fmt.Sprintf("%s_%d", eh.config.CommandName, i)
if hystrix.GetCircuitSettings()[circuitName] == nil {
hystrix.ConfigureCommand(circuitName, hystrix.CommandConfig{
Timeout: eh.config.Timeout,
MaxConcurrentRequests: eh.config.MaxConcurrentRequests,
RequestVolumeThreshold: eh.config.RequestVolumeThreshold,
SleepWindow: eh.config.SleepWindow,
ErrorPercentThreshold: eh.config.ErrorPercentThreshold,
})
}
// If circuit is the same for all functions, in case of len(cmd.functors) > 2,
// main and fallback providers are different next run if first two fail,
// which causes health issues for both main and fallback and ErrorPercentThreshold
// is reached faster than it should be.
errChan := hystrix.Go(circuitName, func() error {
res, err := f1.Exec()
// Write to resultChan only if success
if err == nil {
resultChan <- CommandResult{res: res, err: err}
}
return err
}, func(err error) error {
// In case of concurrency, we should not execute the fallback
if f2 == nil || err == hystrix.ErrMaxConcurrency {
return err
}
res, err := f2.Exec()
if err == nil {
resultChan <- CommandResult{res: res, err: err}
}
return err
})
select {
case result = <-resultChan:
if result.err == nil {
return result
}
case err := <-errChan:
result = CommandResult{err: err}
// In case of max concurrency, we should delay the execution and stop iterating over fallbacks
// No error unwrapping here, so use strings.Contains
if strings.Contains(err.Error(), hystrix.ErrMaxConcurrency.Error()) {
return result
}
}
}
return result
}

View File

@ -18,6 +18,7 @@ var contractAddressByChainID = map[uint64]common.Address{
421613: common.HexToAddress("0x7Ff554af5b6624db2135E4364F416d1D397f43e6"), // Arbitrum Goerli
11155111: common.HexToAddress("0xCDE984e57cdb88c70b53437cc694345B646371f9"), // Sepolia
421614: common.HexToAddress("0x7Ff554af5b6624db2135E4364F416d1D397f43e6"), // Arbitrum Sepolia
11155420: common.HexToAddress("0xcE2A896eEA2F585BC0C3753DC8116BbE2AbaE541"), // Optimism Sepolia
}
func ContractAddress(chainID uint64) (common.Address, error) {

View File

@ -0,0 +1,24 @@
package gaspriceoracle
import (
"errors"
"github.com/ethereum/go-ethereum/common"
wallet_common "github.com/status-im/status-go/services/wallet/common"
)
var ErrorNotAvailableOnChainID = errors.New("not available for chainID")
var contractAddressByChainID = map[uint64]common.Address{
wallet_common.OptimismMainnet: common.HexToAddress("0x8527c030424728cF93E72bDbf7663281A44Eeb22"),
wallet_common.OptimismSepolia: common.HexToAddress("0x5230210c2b4995FD5084b0F5FD0D7457aebb5010"),
}
func ContractAddress(chainID uint64) (common.Address, error) {
addr, exists := contractAddressByChainID[chainID]
if !exists {
return *new(common.Address), ErrorNotAvailableOnChainID
}
return addr, nil
}

View File

@ -0,0 +1,3 @@
package gaspriceoracle
//go:generate abigen -abi gaspriceoracle.abi -pkg gaspriceoracle -out gaspriceoracle.go

View File

@ -0,0 +1,316 @@
[
{
"inputs": [],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "DecimalsUpdated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "GasPriceUpdated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "L1BaseFeeUpdated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "OverheadUpdated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "ScalarUpdated",
"type": "event"
},
{
"inputs": [],
"name": "admin",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "target",
"type": "address"
},
{
"internalType": "bytes",
"name": "data",
"type": "bytes"
}
],
"name": "adminCall",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [],
"name": "decimals",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "gasPrice",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getAdmin",
"outputs": [
{
"internalType": "address",
"name": "adminAddress",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes",
"name": "_data",
"type": "bytes"
}
],
"name": "getL1Fee",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes",
"name": "_data",
"type": "bytes"
}
],
"name": "getL1GasUsed",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes",
"name": "initPayload",
"type": "bytes"
}
],
"name": "init",
"outputs": [
{
"internalType": "bytes4",
"name": "",
"type": "bytes4"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "l1BaseFee",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "overhead",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "scalar",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "adminAddress",
"type": "address"
}
],
"name": "setAdmin",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_decimals",
"type": "uint256"
}
],
"name": "setDecimals",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_gasPrice",
"type": "uint256"
}
],
"name": "setGasPrice",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_baseFee",
"type": "uint256"
}
],
"name": "setL1BaseFee",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_overhead",
"type": "uint256"
}
],
"name": "setOverhead",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_scalar",
"type": "uint256"
}
],
"name": "setScalar",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]

File diff suppressed because it is too large Load Diff

View File

@ -9,8 +9,9 @@ import (
var errorNotAvailableOnChainID = errors.New("not available for chainID")
var contractAddressByChainID = map[uint64]common.Address{
1: common.HexToAddress("0x744d70fdbe2ba4cf95131626614a1763df805b9e"), // mainnet
5: common.HexToAddress("0x3d6afaa395c31fcd391fe3d562e75fe9e8ec7e6a"), // goerli
1: common.HexToAddress("0x744d70fdbe2ba4cf95131626614a1763df805b9e"), // mainnet
5: common.HexToAddress("0x3d6afaa395c31fcd391fe3d562e75fe9e8ec7e6a"), // goerli
11155111: common.HexToAddress("0xE452027cdEF746c7Cd3DB31CB700428b16cD8E51"), // sepolia
}
func ContractAddress(chainID uint64) (common.Address, error) {

View File

@ -54,6 +54,16 @@ func (u *ConnStatusSubscription) Unsubscribe() {
u.active = false
}
func (u *ConnStatusSubscription) Send(s ConnStatus) bool {
u.RLock()
defer u.RUnlock()
if !u.active {
return false
}
u.C <- s
return true
}
type WakuKeyManager interface {
// GetPrivateKey retrieves the private key of the specified identity.
GetPrivateKey(id string) (*ecdsa.PrivateKey, error)

View File

@ -11,13 +11,35 @@ import (
"io/ioutil"
"net/http"
"os"
"regexp"
"time"
"unicode/utf8"
"golang.org/x/image/webp"
"github.com/ethereum/go-ethereum/log"
)
var (
htmlCommentRegex = regexp.MustCompile(`(?i)<!--([\\s\\S]*?)-->`)
svgRegex = regexp.MustCompile(`(?i)^\s*(?:<\?xml[^>]*>\s*)?(?:<!doctype svg[^>]*>\s*)?<svg[^>]*>[^*]*<\/svg>\s*$`)
)
// IsSVG returns true if the given buffer is a valid SVG image.
func IsSVG(buf []byte) bool {
var isBinary bool
if len(buf) < 24 {
isBinary = false
}
for i := 0; i < 14; i++ {
charCode, _ := utf8.DecodeRuneInString(string(buf[i]))
if charCode == 65533 || charCode <= 8 {
isBinary = true
}
}
return !isBinary && svgRegex.Match(htmlCommentRegex.ReplaceAll(buf, []byte{}))
}
func Decode(fileName string) (image.Image, error) {
file, err := os.Open(fileName)
if err != nil {
@ -109,6 +131,8 @@ func GetType(buf []byte) ImageType {
return GIF
case IsWebp(buf):
return WEBP
case IsIco(buf):
return ICO
default:
return UNKNOWN
}
@ -124,6 +148,10 @@ func GetMimeType(buf []byte) (string, error) {
return "gif", nil
case IsWebp(buf):
return "webp", nil
case IsIco(buf):
return "ico", nil
case IsSVG(buf):
return "svg", nil
default:
return "", errors.New("image format not supported")
}
@ -153,6 +181,12 @@ func IsWebp(buf []byte) bool {
buf[10] == 0x42 && buf[11] == 0x50
}
func IsIco(buf []byte) bool {
return len(buf) > 4 &&
buf[0] == 0 && buf[1] == 0 && buf[2] == 1 || buf[2] == 2 &&
buf[4] > 0
}
func GetImageDimensions(imgBytes []byte) (int, int, error) {
// Decode image bytes
img, _, err := image.Decode(bytes.NewReader(imgBytes))

View File

@ -8,6 +8,7 @@ const (
PNG
GIF
WEBP
ICO
)
const (

File diff suppressed because one or more lines are too long

View File

@ -2,7 +2,7 @@
// sources:
// 1557732988_initialize_db.down.sql (72B)
// 1557732988_initialize_db.up.sql (278B)
// static.go (178B)
// static.go (198B)
package migrations
@ -85,7 +85,7 @@ func _1557732988_initialize_dbDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1557732988_initialize_db.down.sql", size: 72, mode: os.FileMode(0644), modTime: time.Unix(1704726859, 0)}
info := bindataFileInfo{name: "1557732988_initialize_db.down.sql", size: 72, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x77, 0x40, 0x78, 0xb7, 0x71, 0x3c, 0x20, 0x3b, 0xc9, 0xb, 0x2f, 0x49, 0xe4, 0xff, 0x1c, 0x84, 0x54, 0xa1, 0x30, 0xe3, 0x90, 0xf8, 0x73, 0xda, 0xb0, 0x2a, 0xea, 0x8e, 0xf1, 0x82, 0xe7, 0xd2}}
return a, nil
}
@ -105,12 +105,12 @@ func _1557732988_initialize_dbUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1557732988_initialize_db.up.sql", size: 278, mode: os.FileMode(0644), modTime: time.Unix(1704726859, 0)}
info := bindataFileInfo{name: "1557732988_initialize_db.up.sql", size: 278, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf5, 0x85, 0x41, 0x7a, 0xba, 0x4f, 0xa3, 0x43, 0xc0, 0x63, 0xfa, 0x2c, 0xd1, 0xc5, 0xbb, 0x20, 0xa0, 0x64, 0xa8, 0x3b, 0x65, 0x82, 0xa2, 0x14, 0x28, 0x18, 0x7c, 0x8b, 0x3a, 0x7a, 0xfd, 0xe0}}
return a, nil
}
var _staticGo = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x54\x8c\x41\x6a\xc3\x40\x0c\x45\xf7\x73\x8a\xbf\x6c\xa1\x1e\xed\x7b\x82\x52\x12\x08\x24\x17\x90\x6d\x21\x0b\xc7\x33\x46\x52\x72\xfe\x6c\x12\x42\x96\x8f\xc7\x7b\x44\x38\xf1\xb4\xb2\x0a\x22\x39\x6d\x82\x6c\xa3\xcc\xf1\xa2\xaf\xff\xf3\x0f\xfe\x2e\xc7\xc3\x37\x5c\xa2\xdf\x7c\x92\x80\x9b\x2e\x09\x6b\xd9\x91\x8b\x60\xb4\xc6\x6e\x12\x65\xff\x38\x95\x42\xa4\xfd\x57\xa5\x89\x73\x0a\xb4\x0f\xa3\xb5\x99\x93\x31\xec\xab\x62\x33\x75\x4e\xeb\x2d\x30\x74\xd4\x4a\xb5\xd2\xc6\x76\x0d\xf1\xbb\x38\xbd\x35\x3d\xb3\xaa\x1d\xb5\x3c\x02\x00\x00\xff\xff\xf4\xe4\x35\xe2\xb2\x00\x00\x00")
var _staticGo = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x54\xcc\x31\x4a\x06\x41\x0c\xc5\xf1\x7e\x4e\xf1\x4a\x05\x67\xa2\x95\x20\xd8\x8b\x28\x08\x7a\x81\xec\x6e\xc8\x17\xd6\x99\x2c\x99\xe8\xf9\x6d\x56\xc4\xd7\x3d\xfe\xf0\x23\xc2\x1b\xaf\x3b\xab\x60\x26\xa7\xad\x90\xbe\xc8\x36\x7f\xdf\xd5\xf3\xfb\x0d\x9e\x3e\x5e\x5f\xae\x11\x32\xfd\x2b\x56\x99\x08\xd3\x4b\xc2\x46\x3a\xf2\x22\x58\x6c\x70\x98\xcc\x72\xfc\x93\x4a\x21\x52\x7f\x50\x19\x12\x9c\x02\xf5\xba\xd8\xd8\x38\x19\xb5\xfb\x96\xd6\xe5\xf1\xee\xfe\xf6\x1c\xea\xb1\x2b\xba\x69\x70\x9a\x8f\x89\xea\x68\x8d\x5a\xa3\xce\xf6\x39\x25\xbe\x25\xe8\x2f\xd3\x49\x35\x75\xb4\xf2\x13\x00\x00\xff\xff\x9a\xab\xca\x11\xc6\x00\x00\x00")
func staticGoBytes() ([]byte, error) {
return bindataRead(
@ -125,8 +125,8 @@ func staticGo() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "static.go", size: 178, mode: os.FileMode(0644), modTime: time.Unix(1704726859, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xab, 0x8a, 0xf4, 0x27, 0x24, 0x9d, 0x2a, 0x1, 0x7b, 0x54, 0xea, 0xae, 0x4a, 0x35, 0x40, 0x92, 0xb5, 0xf9, 0xb3, 0x54, 0x3e, 0x3a, 0x1a, 0x2b, 0xae, 0xfb, 0x9e, 0x82, 0xeb, 0x4c, 0xf, 0x6}}
info := bindataFileInfo{name: "static.go", size: 198, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xb, 0xd2, 0xfd, 0xbf, 0xe5, 0xff, 0xcb, 0x54, 0xec, 0x41, 0x23, 0x7b, 0xc0, 0xeb, 0x55, 0xb8, 0x69, 0xd7, 0x57, 0xf1, 0x83, 0x13, 0x88, 0x55, 0xd9, 0x73, 0xdc, 0x93, 0xee, 0x23, 0xe3, 0xe9}}
return a, nil
}

View File

@ -961,7 +961,7 @@ func (db *Database) updateKeypairClock(tx *sql.Tx, keyUID string, clock uint64)
return err
}
func (db *Database) saveOrUpdateAccounts(tx *sql.Tx, accounts []*Account, updateKeypairClock, isSepoliaEnabled bool) (err error) {
func (db *Database) saveOrUpdateAccounts(tx *sql.Tx, accounts []*Account, updateKeypairClock, isGoerliEnabled bool) (err error) {
if tx == nil {
return errDbTransactionIsNil
}
@ -994,10 +994,10 @@ func (db *Database) saveOrUpdateAccounts(tx *sql.Tx, accounts []*Account, update
}
if acc.TestPreferredChainIDs == "" {
if isSepoliaEnabled {
acc.TestPreferredChainIDs = TestSepoliaPreferredChainIDsDefault
} else {
if isGoerliEnabled {
acc.TestPreferredChainIDs = TestPreferredChainIDsDefault
} else {
acc.TestPreferredChainIDs = TestSepoliaPreferredChainIDsDefault
}
}
}
@ -1090,7 +1090,7 @@ func (db *Database) SaveOrUpdateAccounts(accounts []*Account, updateKeypairClock
if len(accounts) == 0 {
return errors.New("no provided accounts to save/update")
}
isSepoliaEnabled, err := db.GetIsSepoliaEnabled()
isGoerliEnabled, err := db.GetIsGoerliEnabled()
if err != nil {
return err
}
@ -1106,7 +1106,7 @@ func (db *Database) SaveOrUpdateAccounts(accounts []*Account, updateKeypairClock
}
_ = tx.Rollback()
}()
err = db.saveOrUpdateAccounts(tx, accounts, updateKeypairClock, isSepoliaEnabled)
err = db.saveOrUpdateAccounts(tx, accounts, updateKeypairClock, isGoerliEnabled)
return err
}
@ -1119,7 +1119,7 @@ func (db *Database) SaveOrUpdateKeypair(keypair *Keypair) error {
return errDbPassedParameterIsNil
}
isSepoliaEnabled, err := db.GetIsSepoliaEnabled()
isGoerliEnabled, err := db.GetIsGoerliEnabled()
if err != nil {
return err
}
@ -1173,7 +1173,7 @@ func (db *Database) SaveOrUpdateKeypair(keypair *Keypair) error {
if err != nil {
return err
}
return db.saveOrUpdateAccounts(tx, keypair.Accounts, false, isSepoliaEnabled)
return db.saveOrUpdateAccounts(tx, keypair.Accounts, false, isGoerliEnabled)
}
func (db *Database) UpdateKeypairName(keyUID string, name string, clock uint64, updateChatAccountName bool) error {

View File

@ -31,6 +31,10 @@ type Account struct {
CustomizationColorClock uint64 `json:"-"`
}
func (a *Account) RefersToKeycard() bool {
return a.KeycardPairing != ""
}
func (a *Account) ToProtobuf() *protobuf.MultiAccount {
var colorHashes []*protobuf.MultiAccount_ColorHash
for _, index := range a.ColorHash {

View File

@ -12,7 +12,7 @@
// 1660238799_accounts_kdf.up.sql (115B)
// 1679505708_add_customization_color.up.sql (78B)
// 1687853321_add_customization_color_updated_at.up.sql (80B)
// doc.go (74B)
// doc.go (94B)
package migrations
@ -95,7 +95,7 @@ func _0001_accountsDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0001_accounts.down.sql", size: 21, mode: os.FileMode(0644), modTime: time.Unix(1704726861, 0)}
info := bindataFileInfo{name: "0001_accounts.down.sql", size: 21, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd2, 0x61, 0x4c, 0x18, 0xfc, 0xc, 0xdf, 0x5c, 0x1f, 0x5e, 0xd3, 0xbd, 0xfa, 0x12, 0x5e, 0x8d, 0x8d, 0x8b, 0xb9, 0x5f, 0x99, 0x46, 0x63, 0xa5, 0xe3, 0xa6, 0x8a, 0x4, 0xf1, 0x73, 0x8a, 0xe9}}
return a, nil
}
@ -115,7 +115,7 @@ func _0001_accountsUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "0001_accounts.up.sql", size: 163, mode: os.FileMode(0644), modTime: time.Unix(1704726861, 0)}
info := bindataFileInfo{name: "0001_accounts.up.sql", size: 163, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf2, 0xfa, 0x99, 0x8e, 0x96, 0xb3, 0x13, 0x6c, 0x1f, 0x6, 0x27, 0xc5, 0xd2, 0xd4, 0xe0, 0xa5, 0x26, 0x82, 0xa7, 0x26, 0xf2, 0x68, 0x9d, 0xed, 0x9c, 0x3d, 0xbb, 0xdc, 0x37, 0x28, 0xbc, 0x1}}
return a, nil
}
@ -135,7 +135,7 @@ func _1605007189_identity_imagesDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1605007189_identity_images.down.sql", size: 29, mode: os.FileMode(0644), modTime: time.Unix(1704726861, 0)}
info := bindataFileInfo{name: "1605007189_identity_images.down.sql", size: 29, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x2f, 0xcf, 0xa7, 0xae, 0xd5, 0x4f, 0xcd, 0x14, 0x63, 0x9, 0xbe, 0x39, 0x49, 0x18, 0x96, 0xb2, 0xa3, 0x8, 0x7d, 0x41, 0xdb, 0x50, 0x5d, 0xf5, 0x4d, 0xa2, 0xd, 0x8f, 0x57, 0x79, 0x77, 0x67}}
return a, nil
}
@ -155,7 +155,7 @@ func _1605007189_identity_imagesUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1605007189_identity_images.up.sql", size: 268, mode: os.FileMode(0644), modTime: time.Unix(1704726861, 0)}
info := bindataFileInfo{name: "1605007189_identity_images.up.sql", size: 268, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x50, 0xb6, 0xc1, 0x5c, 0x76, 0x72, 0x6b, 0x22, 0x34, 0xdc, 0x96, 0xdc, 0x2b, 0xfd, 0x2d, 0xbe, 0xcc, 0x1e, 0xd4, 0x5, 0x93, 0xd, 0xc2, 0x51, 0xf3, 0x1a, 0xef, 0x2b, 0x26, 0xa4, 0xeb, 0x65}}
return a, nil
}
@ -175,7 +175,7 @@ func _1606224181_drop_photo_path_from_accountsDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1606224181_drop_photo_path_from_accounts.down.sql", size: 892, mode: os.FileMode(0644), modTime: time.Unix(1704726861, 0)}
info := bindataFileInfo{name: "1606224181_drop_photo_path_from_accounts.down.sql", size: 892, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x90, 0x24, 0x17, 0x7, 0x80, 0x93, 0x6f, 0x8d, 0x5d, 0xaa, 0x8c, 0x79, 0x15, 0x5d, 0xb3, 0x19, 0xd7, 0xd8, 0x39, 0xf9, 0x3a, 0x63, 0x8f, 0x81, 0x15, 0xb6, 0xd6, 0x9a, 0x37, 0xa8, 0x8e, 0x9b}}
return a, nil
}
@ -195,7 +195,7 @@ func _1606224181_drop_photo_path_from_accountsUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1606224181_drop_photo_path_from_accounts.up.sql", size: 866, mode: os.FileMode(0644), modTime: time.Unix(1704726861, 0)}
info := bindataFileInfo{name: "1606224181_drop_photo_path_from_accounts.up.sql", size: 866, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xff, 0x4c, 0x97, 0xee, 0xef, 0x82, 0xb8, 0x6c, 0x71, 0xbb, 0x50, 0x7b, 0xe6, 0xd9, 0x22, 0x31, 0x7c, 0x1a, 0xfe, 0x91, 0x28, 0xf6, 0x6, 0x36, 0xe, 0xb1, 0xf1, 0xc8, 0x25, 0xac, 0x7e, 0xd6}}
return a, nil
}
@ -215,7 +215,7 @@ func _1648646095_image_clockDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1648646095_image_clock.down.sql", size: 939, mode: os.FileMode(0644), modTime: time.Unix(1704726861, 0)}
info := bindataFileInfo{name: "1648646095_image_clock.down.sql", size: 939, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x4d, 0xa8, 0x1f, 0xf, 0xe0, 0xd7, 0xc9, 0x68, 0x98, 0xd8, 0x37, 0xb8, 0xba, 0x9e, 0xb2, 0x19, 0xf3, 0xc4, 0x73, 0x80, 0x3, 0x17, 0x2a, 0x53, 0x68, 0x10, 0x13, 0x54, 0x99, 0xb1, 0xf5, 0x1c}}
return a, nil
}
@ -235,7 +235,7 @@ func _1648646095_image_clockUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1648646095_image_clock.up.sql", size: 69, mode: os.FileMode(0644), modTime: time.Unix(1704726861, 0)}
info := bindataFileInfo{name: "1648646095_image_clock.up.sql", size: 69, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x98, 0xa6, 0xa4, 0x4e, 0x4e, 0xca, 0x17, 0x56, 0xea, 0xfb, 0xf0, 0xa9, 0x81, 0x95, 0xe, 0x80, 0x52, 0x1, 0x47, 0x9b, 0xde, 0x14, 0xfa, 0x72, 0xc9, 0x62, 0x6f, 0x24, 0xa2, 0xc, 0x32, 0x50}}
return a, nil
}
@ -255,7 +255,7 @@ func _1649317600_add_color_hashUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1649317600_add_color_hash.up.sql", size: 201, mode: os.FileMode(0644), modTime: time.Unix(1704726861, 0)}
info := bindataFileInfo{name: "1649317600_add_color_hash.up.sql", size: 201, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x1a, 0xf, 0x37, 0x6d, 0xcf, 0x99, 0xc9, 0x2e, 0xdc, 0x70, 0x11, 0xb4, 0x36, 0x26, 0x4f, 0x39, 0xa8, 0x44, 0xf, 0xcb, 0xcc, 0x81, 0x74, 0x7a, 0x88, 0xaa, 0x54, 0x8c, 0xc4, 0xe, 0x56, 0x4f}}
return a, nil
}
@ -275,7 +275,7 @@ func _1660238799_accounts_kdfUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1660238799_accounts_kdf.up.sql", size: 115, mode: os.FileMode(0644), modTime: time.Unix(1704726861, 0)}
info := bindataFileInfo{name: "1660238799_accounts_kdf.up.sql", size: 115, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xdf, 0xe6, 0x7a, 0x69, 0x25, 0x42, 0x3b, 0x9c, 0x20, 0xf5, 0xcb, 0xae, 0xb0, 0xb3, 0x1b, 0x66, 0xc2, 0x5d, 0xd0, 0xc1, 0x59, 0xe8, 0xa9, 0xc5, 0x69, 0x58, 0x8f, 0xae, 0xe6, 0xd1, 0x4c, 0x53}}
return a, nil
}
@ -295,7 +295,7 @@ func _1679505708_add_customization_colorUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1679505708_add_customization_color.up.sql", size: 78, mode: os.FileMode(0644), modTime: time.Unix(1704726861, 0)}
info := bindataFileInfo{name: "1679505708_add_customization_color.up.sql", size: 78, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xa9, 0xe1, 0x3d, 0xaa, 0x5d, 0x35, 0x87, 0x8a, 0x8b, 0xe9, 0x4a, 0xa6, 0x7b, 0x85, 0xbc, 0x33, 0x11, 0xc7, 0x7d, 0x61, 0xac, 0x65, 0x59, 0xda, 0x32, 0x59, 0x68, 0x9d, 0xa1, 0x10, 0x7b, 0xa9}}
return a, nil
}
@ -315,12 +315,12 @@ func _1687853321_add_customization_color_updated_atUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1687853321_add_customization_color_updated_at.up.sql", size: 80, mode: os.FileMode(0644), modTime: time.Unix(1704726861, 0)}
info := bindataFileInfo{name: "1687853321_add_customization_color_updated_at.up.sql", size: 80, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xa8, 0xc2, 0x9, 0xec, 0xf4, 0xd1, 0x46, 0x29, 0xc5, 0xce, 0x4d, 0xd4, 0xf, 0x9c, 0xfa, 0x62, 0x1, 0x29, 0xe6, 0xd2, 0xd5, 0xe, 0xf0, 0x27, 0x81, 0x4a, 0x82, 0x25, 0x5f, 0x67, 0xff, 0xd1}}
return a, nil
}
var _docGo = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x2c\xc9\xb1\x0d\xc4\x20\x0c\x05\xd0\x9e\x29\xfe\x02\xd8\xfd\x6d\xe3\x4b\xac\x2f\x44\x82\x09\x78\x7f\xa5\x49\xfd\xa6\x1d\xdd\xe8\xd8\xcf\x55\x8a\x2a\xe3\x47\x1f\xbe\x2c\x1d\x8c\xfa\x6f\xe3\xb4\x34\xd4\xd9\x89\xbb\x71\x59\xb6\x18\x1b\x35\x20\xa2\x9f\x0a\x03\xa2\xe5\x0d\x00\x00\xff\xff\x60\xcd\x06\xbe\x4a\x00\x00\x00")
var _docGo = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x2c\xcb\x41\x0e\x02\x31\x08\x05\xd0\x7d\x4f\xf1\x2f\x00\xe8\xca\xc4\xc4\xc3\xa0\x43\x08\x19\x5b\xc6\x96\xfb\xc7\x4d\xdf\xfe\x5d\xfa\x39\xd5\x0d\xeb\xf7\x6d\x4d\xc4\xf3\xe9\x36\x6c\x6a\x19\x3c\xe9\x1d\xe3\xd0\x52\x50\xcf\xa3\xa2\xdb\xeb\xfe\xb8\x6d\xa0\xeb\x74\xf4\xf0\xa9\x15\x39\x16\x28\xc1\x2c\x7b\xb0\x27\x58\xda\x3f\x00\x00\xff\xff\x57\xd4\xd5\x90\x5e\x00\x00\x00")
func docGoBytes() ([]byte, error) {
return bindataRead(
@ -335,8 +335,8 @@ func docGo() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "doc.go", size: 74, mode: os.FileMode(0644), modTime: time.Unix(1704726861, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xde, 0x7c, 0x28, 0xcd, 0x47, 0xf2, 0xfa, 0x7c, 0x51, 0x2d, 0xd8, 0x38, 0xb, 0xb0, 0x34, 0x9d, 0x4c, 0x62, 0xa, 0x9e, 0x28, 0xc3, 0x31, 0x23, 0xd9, 0xbb, 0x89, 0x9f, 0xa0, 0x89, 0x1f, 0xe8}}
info := bindataFileInfo{name: "doc.go", size: 94, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x2f, 0x81, 0x21, 0x7a, 0x87, 0xd2, 0xef, 0xcc, 0x25, 0x5e, 0x95, 0x3f, 0x25, 0x79, 0xf7, 0x18, 0xaf, 0x57, 0xe7, 0x1e, 0x58, 0x50, 0xbb, 0xea, 0x27, 0x98, 0x89, 0xe1, 0x9f, 0x5c, 0xf6, 0x0}}
return a, nil
}

View File

@ -392,9 +392,9 @@ var (
dBColumnName: "test_networks_enabled",
valueHandler: BoolHandler,
}
IsSepoliaEnabled = SettingField{
reactFieldName: "is-sepolia-enabled?",
dBColumnName: "is_sepolia_enabled",
IsGoerliEnabled = SettingField{
reactFieldName: "is-goerli-enabled?",
dBColumnName: "is_goerli_enabled",
valueHandler: BoolHandler,
}
TokenGroupByCommunity = SettingField{
@ -425,9 +425,10 @@ var (
},
}
DisplayAssetsBelowBalanceThreshold = SettingField{
reactFieldName: "display-assets-below-balance-threshold",
dBColumnName: "wallet_display_assets_below_balance_threshold",
valueHandler: Int64Handler,
reactFieldName: "display-assets-below-balance-threshold",
dBColumnName: "wallet_display_assets_below_balance_threshold",
valueHandler: Int64Handler,
valueCastHandler: Float64ToInt64Handler,
syncProtobufFactory: &SyncProtobufFactory{
fromInterface: displayAssetsBelowBalanceThresholdProtobufFactory,
fromStruct: displayAssetsBelowBalanceThresholdProtobufFactoryStruct,
@ -505,13 +506,21 @@ var (
dBColumnName: "mnemonic_was_not_shown",
valueHandler: BoolHandler,
}
PeerSyncingEnabled = SettingField{
reactFieldName: "peer-syncing-enabled?",
dBColumnName: "peer_syncing_enabled",
valueHandler: BoolHandler,
}
SettingFieldRegister = []SettingField{
AnonMetricsShouldSend,
Appearance,
AutoMessageEnabled,
BackupEnabled,
BackupFetched,
Bio,
ChaosMode,
CollectibleGroupByCollection,
CollectibleGroupByCommunity,
Currency,
CurrentUserStatus,
CustomBootNodes,
@ -519,14 +528,16 @@ var (
DappsAddress,
DefaultSyncPeriod,
DeviceName,
DisplayAssetsBelowBalance,
DisplayAssetsBelowBalanceThreshold,
DisplayName,
Bio,
EIP1581Address,
Fleet,
GifAPIKey,
GifFavourites,
GifRecents,
HideHomeTooltip,
IsGoerliEnabled,
KeycardInstanceUID,
KeycardPairedOn,
KeycardPairing,
@ -546,10 +557,12 @@ var (
NodeConfig,
NotificationsEnabled,
OpenseaEnabled,
PeerSyncingEnabled,
PhotoPath,
PinnedMailservers,
PreferredName,
PreviewPrivacy,
ProfileMigrationNeeded,
ProfilePicturesShowTo,
ProfilePicturesVisibility,
PublicKey,
@ -560,27 +573,21 @@ var (
RemotePushNotificationsEnabled,
SendPushNotifications,
SendStatusUpdates,
ShowCommunityAssetWhenSendingTokens,
StickersPacksInstalled,
StickersPacksPending,
StickersRecentStickers,
SyncingOnMobileNetwork,
TelemetryServerURL,
TestNetworksEnabled,
TokenGroupByCommunity,
URLUnfurlingMode,
UseMailservers,
WakuBloomFilterMode,
WalletRootAddress,
WalletSetUpPassed,
WalletVisibleTokens,
WebviewAllowPermissionRequests,
ProfileMigrationNeeded,
IsSepoliaEnabled,
TokenGroupByCommunity,
ShowCommunityAssetWhenSendingTokens,
DisplayAssetsBelowBalance,
DisplayAssetsBelowBalanceThreshold,
CollectibleGroupByCollection,
CollectibleGroupByCommunity,
URLUnfurlingMode,
}
)

View File

@ -255,6 +255,13 @@ func (db *Database) saveSetting(setting SettingField, value interface{}) error {
}
func (db *Database) parseSaveAndSyncSetting(sf SettingField, value interface{}) (err error) {
if sf.ValueCastHandler() != nil {
value, err = sf.ValueCastHandler()(value)
if err != nil {
return err
}
}
if sf.ValueHandler() != nil {
value, err = sf.ValueHandler()(value)
if err != nil {
@ -382,9 +389,10 @@ func (db *Database) GetSettings() (Settings, error) {
profile_pictures_show_to, profile_pictures_visibility, wallet_root_address, wallet_set_up_passed, wallet_visible_tokens,
waku_bloom_filter_mode, webview_allow_permission_requests, current_user_status, send_status_updates, gif_recents,
gif_favorites, opensea_enabled, last_backup, backup_enabled, telemetry_server_url, auto_message_enabled, gif_api_key,
test_networks_enabled, mutual_contact_enabled, profile_migration_needed, is_sepolia_enabled, wallet_token_preferences_group_by_community, url_unfurling_mode,
test_networks_enabled, mutual_contact_enabled, profile_migration_needed, is_goerli_enabled, wallet_token_preferences_group_by_community, url_unfurling_mode,
omit_transfers_history_scan, mnemonic_was_not_shown, wallet_show_community_asset_when_sending_tokens, wallet_display_assets_below_balance,
wallet_display_assets_below_balance_threshold, wallet_collectible_preferences_group_by_collection, wallet_collectible_preferences_group_by_community
wallet_display_assets_below_balance_threshold, wallet_collectible_preferences_group_by_collection, wallet_collectible_preferences_group_by_community,
peer_syncing_enabled
FROM
settings
WHERE
@ -458,7 +466,7 @@ func (db *Database) GetSettings() (Settings, error) {
&s.TestNetworksEnabled,
&s.MutualContactEnabled,
&s.ProfileMigrationNeeded,
&s.IsSepoliaEnabled,
&s.IsGoerliEnabled,
&s.TokenGroupByCommunity,
&s.URLUnfurlingMode,
&s.OmitTransfersHistoryScan,
@ -468,6 +476,7 @@ func (db *Database) GetSettings() (Settings, error) {
&s.DisplayAssetsBelowBalanceThreshold,
&s.CollectibleGroupByCollection,
&s.CollectibleGroupByCommunity,
&s.PeerSyncingEnabled,
)
return s, err
@ -748,8 +757,20 @@ func (db *Database) GetTestNetworksEnabled() (result bool, err error) {
return result, err
}
func (db *Database) GetIsSepoliaEnabled() (result bool, err error) {
err = db.makeSelectRow(IsSepoliaEnabled).Scan(&result)
func (db *Database) GetIsGoerliEnabled() (result bool, err error) {
err = db.makeSelectRow(IsGoerliEnabled).Scan(&result)
if err == sql.ErrNoRows {
return result, nil
}
return result, err
}
func (db *Database) SetPeerSyncingEnabled(value bool) error {
return db.SaveSettingField(PeerSyncingEnabled, value)
}
func (db *Database) GetPeerSyncingEnabled() (result bool, err error) {
err = db.makeSelectRow(PeerSyncingEnabled).Scan(&result)
if err == sql.ErrNoRows {
return result, nil
}

View File

@ -36,7 +36,7 @@ type DatabaseSettingsManager interface {
GetEIP1581Address() (rst types.Address, err error)
GetMasterAddress() (rst types.Address, err error)
GetTestNetworksEnabled() (result bool, err error)
GetIsSepoliaEnabled() (result bool, err error)
GetIsGoerliEnabled() (result bool, err error)
GetTokenGroupByCommunity() (result bool, err error)
GetCollectibleGroupByCommunity() (result bool, err error)
GetCollectibleGroupByCollection() (result bool, err error)
@ -49,6 +49,7 @@ type DatabaseSettingsManager interface {
SetPinnedMailservers(mailservers map[string]string) error
SetUseMailservers(value bool) error
SetTokenGroupByCommunity(value bool) error
SetPeerSyncingEnabled(value bool) error
CreateSettings(s Settings, n params.NodeConfig) error
SaveSetting(setting string, value interface{}) error
@ -76,4 +77,5 @@ type DatabaseSettingsManager interface {
URLUnfurlingMode() (result int64, err error)
SubscribeToChanges() chan *SyncSettingField
MnemonicWasShown() error
GetPeerSyncingEnabled() (result bool, err error)
}

View File

@ -6,11 +6,13 @@ import (
accountJson "github.com/status-im/status-go/account/json"
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/params"
"github.com/status-im/status-go/protocol/common"
"github.com/status-im/status-go/protocol/protobuf"
)
type ValueHandler func(interface{}) (interface{}, error)
type ValueCastHandler func(interface{}) (interface{}, error)
type SyncSettingProtobufFactoryInterface func(interface{}, uint64, string) (*common.RawMessage, *protobuf.SyncSetting, error)
type SyncSettingProtobufFactoryStruct func(Settings, uint64, string) (*common.RawMessage, *protobuf.SyncSetting, error)
type SyncSettingProtobufToValue func(setting *protobuf.SyncSetting) interface{}
@ -69,6 +71,7 @@ type SettingField struct {
dBColumnName string
valueHandler ValueHandler
syncProtobufFactory *SyncProtobufFactory
valueCastHandler ValueCastHandler
}
func (s SettingField) GetReactName() string {
@ -83,6 +86,10 @@ func (s SettingField) ValueHandler() ValueHandler {
return s.valueHandler
}
func (s SettingField) ValueCastHandler() ValueCastHandler {
return s.valueCastHandler
}
func (s SettingField) SyncProtobufFactory() *SyncProtobufFactory {
return s.syncProtobufFactory
}
@ -153,9 +160,18 @@ type Settings struct {
NotificationsEnabled bool `json:"notifications-enabled?,omitempty"`
PhotoPath string `json:"photo-path"`
PinnedMailserver *json.RawMessage `json:"pinned-mailservers,omitempty"`
PreferredName *string `json:"preferred-name,omitempty"`
PreviewPrivacy bool `json:"preview-privacy?"`
PublicKey string `json:"public-key"`
// PreferredName represents the user's preferred Ethereum Name Service (ENS) name.
// If a user has multiple ENS names, they can select one as the PreferredName.
// When PreferredName is set, it takes precedence over the DisplayName for displaying the user's name.
// If PreferredName is empty or doesn't match any of the user's ENS names, the DisplayName is used instead.
//
// There is a race condition between updating DisplayName and PreferredName, where the account.Name field
// could be incorrectly updated based on the order in which the backup messages (BackedUpProfile/BackedUpSettings) arrive.
// To handle this race condition, the code checks the LastSynced clock value for both DisplayName and PreferredName,
// and updates account.Name with the value that has the latest clock
PreferredName *string `json:"preferred-name,omitempty"`
PreviewPrivacy bool `json:"preview-privacy?"`
PublicKey string `json:"public-key"`
// PushNotificationsServerEnabled indicates whether we should be running a push notification server
PushNotificationsServerEnabled bool `json:"push-notifications-server-enabled?,omitempty"`
// PushNotificationsFromContactsOnly indicates whether we should only receive push notifications from contacts
@ -198,7 +214,7 @@ type Settings struct {
GifAPIKey string `json:"gifs/api-key"`
TestNetworksEnabled bool `json:"test-networks-enabled?,omitempty"`
ProfileMigrationNeeded bool `json:"profile-migration-needed,omitempty"`
IsSepoliaEnabled bool `json:"is-sepolia-enabled?,omitempty"`
IsGoerliEnabled bool `json:"is-goerli-enabled?,omitempty"`
TokenGroupByCommunity bool `json:"token-group-by-community?,omitempty"`
ShowCommunityAssetWhenSendingTokens bool `json:"show-community-asset-when-sending-tokens?,omitempty"`
DisplayAssetsBelowBalance bool `json:"display-assets-below-balance?,omitempty"`
@ -206,6 +222,7 @@ type Settings struct {
CollectibleGroupByCollection bool `json:"collectible-group-by-collection?,omitempty"`
CollectibleGroupByCommunity bool `json:"collectible-group-by-community?,omitempty"`
URLUnfurlingMode URLUnfurlingModeType `json:"url-unfurling-mode,omitempty"`
PeerSyncingEnabled bool `json:"peer-syncing-enabled?,omitempty"`
}
func (s Settings) MarshalJSON() ([]byte, error) {
@ -224,3 +241,10 @@ func (s Settings) IsEmpty() bool {
empty := reflect.Zero(reflect.TypeOf(s)).Interface()
return reflect.DeepEqual(s, empty)
}
func (s Settings) GetFleet() string {
if s.Fleet == nil {
return params.FleetUndefined
}
return *s.Fleet
}

View File

@ -341,6 +341,8 @@ func stickersRecentStickersProtobufFactoryStruct(s Settings, clock uint64, chatI
return buildRawStickersRecentStickersSyncMessage(srs, clock, chatID)
}
// Helpers
func assertBytes(value interface{}) ([]byte, error) {
v, ok := value.([]byte)
if !ok {

View File

@ -72,3 +72,12 @@ func NodeConfigHandler(value interface{}) (interface{}, error) {
return nodeConfig, nil
}
func Float64ToInt64Handler(value interface{}) (interface{}, error) {
floatValue, ok := value.(float64)
if !ok {
// Ignore if not float64
return value, nil
}
return int64(floatValue), nil
}

View File

@ -477,11 +477,11 @@ func (n *StatusNode) stop() error {
n.downloader = nil
if n.db != nil {
err := n.db.Close()
if err = n.db.Close(); err != nil {
n.log.Error("Error closing the leveldb of status node", "error", err)
return err
}
n.db = nil
return err
}
n.rpcFiltersSrvc = nil

View File

@ -318,14 +318,12 @@ func (b *StatusNode) wakuV2Service(nodeConfig *params.NodeConfig, telemetryServe
KeepAliveInterval: nodeConfig.WakuV2Config.KeepAliveInterval,
Rendezvous: nodeConfig.Rendezvous,
WakuNodes: nodeConfig.ClusterConfig.WakuNodes,
PeerExchange: nodeConfig.WakuV2Config.PeerExchange,
EnableStore: nodeConfig.WakuV2Config.EnableStore,
StoreCapacity: nodeConfig.WakuV2Config.StoreCapacity,
StoreSeconds: nodeConfig.WakuV2Config.StoreSeconds,
DiscoveryLimit: nodeConfig.WakuV2Config.DiscoveryLimit,
DiscV5BootstrapNodes: nodeConfig.ClusterConfig.DiscV5BootstrapNodes,
Nameserver: nodeConfig.WakuV2Config.Nameserver,
EnableDiscV5: nodeConfig.WakuV2Config.EnableDiscV5,
UDPPort: nodeConfig.WakuV2Config.UDPPort,
AutoUpdate: nodeConfig.WakuV2Config.AutoUpdate,
DefaultShardPubsubTopic: shard.DefaultShardPubsubTopic(),
@ -334,6 +332,17 @@ func (b *StatusNode) wakuV2Service(nodeConfig *params.NodeConfig, telemetryServe
ClusterID: nodeConfig.ClusterConfig.ClusterID,
}
// Configure peer exchange and discv5 settings based on node type
if cfg.LightClient {
cfg.EnablePeerExchangeServer = false
cfg.EnablePeerExchangeClient = true
cfg.EnableDiscV5 = false
} else {
cfg.EnablePeerExchangeServer = true
cfg.EnablePeerExchangeClient = false
cfg.EnableDiscV5 = true
}
if nodeConfig.WakuV2Config.MaxMessageSize > 0 {
cfg.MaxMessageSize = nodeConfig.WakuV2Config.MaxMessageSize
}
@ -443,6 +452,9 @@ func (b *StatusNode) ensService(timesource func() time.Time) *ens.Service {
func (b *StatusNode) pendingTrackerService(walletFeed *event.Feed) *transactions.PendingTxTracker {
if b.pendingTracker == nil {
b.pendingTracker = transactions.NewPendingTxTracker(b.walletDB, b.rpcClient, b.rpcFiltersSrvc, walletFeed, transactions.PendingCheckInterval)
if b.transactor != nil {
b.transactor.SetPendingTracker(b.pendingTracker)
}
}
return b.pendingTracker
}

View File

@ -20,3 +20,23 @@ type Cluster struct {
MailServers []string `json:"mailservers"` // list of trusted mail servers
RendezvousNodes []string `json:"rendezvousnodes"`
}
// DefaultWakuNodes is a list of "supported" fleets. This list is populated to clients UI settings.
var supportedFleets = map[string][]string{
FleetWakuV2Prod: {"enrtree://ANEDLO25QVUGJOUTQFRYKWX6P4Z4GKVESBMHML7DZ6YK4LGS5FC5O@prod.wakuv2.nodes.status.im"},
FleetWakuV2Test: {"enrtree://AO47IDOLBKH72HIZZOXQP6NMRESAN7CHYWIBNXDXWRJRZWLODKII6@test.wakuv2.nodes.status.im"},
FleetShardsTest: {"enrtree://AMOJVZX4V6EXP7NTJPMAYJYST2QP6AJXYW76IU6VGJS7UVSNDYZG4@boot.test.shards.nodes.status.im"},
}
func DefaultWakuNodes(fleet string) []string {
return supportedFleets[fleet]
}
func IsFleetSupported(fleet string) bool {
_, ok := supportedFleets[fleet]
return ok
}
func GetSupportedFleets() map[string][]string {
return supportedFleets
}

View File

@ -189,12 +189,14 @@ type WakuV2Config struct {
CustomNodes map[string]string
// PeerExchange determines whether WakuV2 Peer Exchange is enabled or not
// Deprecated: will be calculated based on LightClient
PeerExchange bool
// Nameserver determines which nameserver will be used for dns discovery
Nameserver string
// EnableDiscV5 indicates if DiscoveryV5 is enabled or not
// Deprecated: will be calculated based on LightClient
EnableDiscV5 bool
// UDPPort number to start discovery v5

View File

@ -7,6 +7,7 @@ import (
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/protocol/common"
"github.com/status-im/status-go/protocol/verification"
"github.com/status-im/status-go/services/wallet/thirdparty"
)
// The activity center is a place where we store incoming notifications before
@ -36,6 +37,9 @@ const (
ActivityCenterNotificationTypeSetSignerDeclined
ActivityCenterNotificationTypeShareAccounts
ActivityCenterNotificationTypeCommunityTokenReceived
ActivityCenterNotificationTypeFirstCommunityTokenReceived
ActivityCenterNotificationTypeCommunityBanned
ActivityCenterNotificationTypeCommunityUnbanned
)
type ActivityCenterMembershipStatus int
@ -60,6 +64,22 @@ const (
var ErrInvalidActivityCenterNotification = errors.New("invalid activity center notification")
type ActivityTokenData struct {
ChainID uint64 `json:"chainId,omitempty"`
CollectibleID thirdparty.CollectibleUniqueID `json:"collectibleId,omitempty"`
TxHash string `json:"txHash,omitempty"`
WalletAddress string `json:"walletAddress,omitempty"`
IsFirst bool `json:"isFirst,omitempty"`
// Community data
CommunityID string `json:"communityId,omitempty"`
// Token data
Amount string `json:"amount,omitempty"`
Name string `json:"name,omitempty"`
Symbol string `json:"symbol,omitempty"`
ImageURL string `json:"imageUrl,omitempty"`
TokenType int `json:"tokenType,omitempty"`
}
type ActivityCenterNotification struct {
ID types.HexBytes `json:"id"`
ChatID string `json:"chatId"`
@ -77,6 +97,7 @@ type ActivityCenterNotification struct {
Deleted bool `json:"deleted"`
Accepted bool `json:"accepted"`
ContactVerificationStatus verification.RequestStatus `json:"contactVerificationStatus"`
TokenData *ActivityTokenData `json:"tokenData"`
//Used for synchronization. Each update should increment the UpdatedAt.
//The value should represent the time when the update occurred.
UpdatedAt uint64 `json:"updatedAt"`

View File

@ -11,8 +11,8 @@ import (
"github.com/status-im/status-go/protocol/common"
)
const allFieldsForTableActivityCenterNotification = `id, timestamp, notification_type, chat_id, read, dismissed, accepted, message, author,
reply_message, community_id, membership_status, contact_verification_status, deleted, updated_at`
const allFieldsForTableActivityCenterNotification = `id, timestamp, notification_type, chat_id, read, dismissed, accepted, message, author,
reply_message, community_id, membership_status, contact_verification_status, token_data, deleted, updated_at`
var emptyNotifications = make([]*ActivityCenterNotification, 0)
@ -125,6 +125,15 @@ func (db sqlitePersistence) SaveActivityCenterNotification(notification *Activit
}
}
// encode token data
var encodedTokenData []byte
if notification.TokenData != nil {
encodedTokenData, err = json.Marshal(notification.TokenData)
if err != nil {
return 0, err
}
}
result, err := tx.Exec(`
INSERT OR REPLACE
INTO activity_center_notifications (
@ -141,10 +150,11 @@ func (db sqlitePersistence) SaveActivityCenterNotification(notification *Activit
read,
accepted,
dismissed,
token_data,
deleted,
updated_at
)
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
`,
notification.ID,
notification.Timestamp,
@ -159,9 +169,9 @@ func (db sqlitePersistence) SaveActivityCenterNotification(notification *Activit
notification.Read,
notification.Accepted,
notification.Dismissed,
encodedTokenData,
notification.Deleted,
notification.UpdatedAt,
notification.ID,
)
if err != nil {
return 0, err
@ -187,6 +197,7 @@ func (db sqlitePersistence) parseRowFromTableActivityCenterNotification(rows *sq
var communityID sql.NullString
var messageBytes []byte
var replyMessageBytes []byte
var tokenDataBytes []byte
var author sql.NullString
notification := &ActivityCenterNotification{}
err := rows.Scan(
@ -203,6 +214,7 @@ func (db sqlitePersistence) parseRowFromTableActivityCenterNotification(rows *sq
&communityID,
&notification.MembershipStatus,
&notification.ContactVerificationStatus,
&tokenDataBytes,
&notification.Deleted,
&notification.UpdatedAt,
)
@ -222,6 +234,13 @@ func (db sqlitePersistence) parseRowFromTableActivityCenterNotification(rows *sq
notification.Author = author.String
}
if len(tokenDataBytes) > 0 {
err = json.Unmarshal(tokenDataBytes, &notification.TokenData)
if err != nil {
return nil, err
}
}
if len(messageBytes) > 0 {
err = json.Unmarshal(messageBytes, &notification.Message)
if err != nil {
@ -251,6 +270,7 @@ func (db sqlitePersistence) unmarshalActivityCenterNotificationRow(row *sql.Row)
var lastMessageBytes []byte
var messageBytes []byte
var replyMessageBytes []byte
var tokenDataBytes []byte
var name sql.NullString
var author sql.NullString
notification := &ActivityCenterNotification{}
@ -271,6 +291,7 @@ func (db sqlitePersistence) unmarshalActivityCenterNotificationRow(row *sql.Row)
&notification.ContactVerificationStatus,
&name,
&author,
&tokenDataBytes,
&notification.UpdatedAt)
if err != nil {
@ -293,6 +314,13 @@ func (db sqlitePersistence) unmarshalActivityCenterNotificationRow(row *sql.Row)
notification.Author = author.String
}
if len(tokenDataBytes) > 0 {
err = json.Unmarshal(tokenDataBytes, &notification.TokenData)
if err != nil {
return nil, err
}
}
// Restore last message
if lastMessageBytes != nil {
lastMessage := common.NewMessage()
@ -332,6 +360,7 @@ func (db sqlitePersistence) unmarshalActivityCenterNotificationRows(rows *sql.Ro
var lastMessageBytes []byte
var messageBytes []byte
var replyMessageBytes []byte
var tokenDataBytes []byte
var name sql.NullString
var author sql.NullString
notification := &ActivityCenterNotification{}
@ -351,6 +380,7 @@ func (db sqlitePersistence) unmarshalActivityCenterNotificationRows(rows *sql.Ro
&notification.ContactVerificationStatus,
&name,
&author,
&tokenDataBytes,
&latestCursor,
&notification.UpdatedAt)
if err != nil {
@ -373,6 +403,14 @@ func (db sqlitePersistence) unmarshalActivityCenterNotificationRows(rows *sql.Ro
notification.Author = author.String
}
if len(tokenDataBytes) > 0 {
tokenData := &ActivityTokenData{}
if err = json.Unmarshal(tokenDataBytes, &tokenData); err != nil {
return "", nil, err
}
notification.TokenData = tokenData
}
// Restore last message
if lastMessageBytes != nil {
lastMessage := common.NewMessage()
@ -503,6 +541,7 @@ func (db sqlitePersistence) buildActivityCenterQuery(tx *sql.Tx, params activity
a.contact_verification_status,
c.name,
a.author,
a.token_data,
substr('0000000000000000000000000000000000000000000000000000000000000000' || a.timestamp, -64, 64) || hex(a.id) as cursor,
a.updated_at
FROM activity_center_notifications a
@ -567,7 +606,7 @@ func (db sqlitePersistence) GetToProcessActivityCenterNotificationIds() ([][]byt
return db.runActivityCenterIDQuery(`
SELECT a.id
FROM activity_center_notifications a
WHERE NOT a.dismissed AND NOT a.accepted AND NOT a.deleted
WHERE NOT a.dismissed AND NOT a.accepted AND NOT a.deleted
`)
}
@ -623,6 +662,7 @@ func (db sqlitePersistence) GetActivityCenterNotificationsByID(ids []types.HexBy
a.contact_verification_status,
c.name,
a.author,
a.token_data,
substr('0000000000000000000000000000000000000000000000000000000000000000' || a.timestamp, -64, 64) || hex(a.id) as cursor,
a.updated_at
FROM activity_center_notifications a
@ -663,6 +703,7 @@ func (db sqlitePersistence) GetActivityCenterNotificationByID(id types.HexBytes)
a.contact_verification_status,
c.name,
a.author,
a.token_data,
a.updated_at
FROM activity_center_notifications a
LEFT JOIN chats c
@ -733,10 +774,10 @@ func (db sqlitePersistence) DismissAllActivityCenterNotificationsFromUser(userPu
_ = tx.Rollback()
}()
query := fmt.Sprintf(`SELECT %s FROM activity_center_notifications WHERE
author = ? AND
NOT deleted AND
NOT dismissed AND
query := fmt.Sprintf(`SELECT %s FROM activity_center_notifications WHERE
author = ? AND
NOT deleted AND
NOT dismissed AND
NOT accepted`, allFieldsForTableActivityCenterNotification)
rows, err := tx.Query(query, userPublicKey)
if err != nil {
@ -874,8 +915,9 @@ func (db sqlitePersistence) DismissActivityCenterNotificationsByCommunity(commun
_ = tx.Rollback()
}()
query := "UPDATE activity_center_notifications SET read = 1, dismissed = 1, updated_at = ? WHERE community_id = ? AND notification_type IN (?, ?) AND NOT deleted" // nolint: gosec
_, err = tx.Exec(query, updatedAt, communityID, ActivityCenterNotificationTypeCommunityRequest, ActivityCenterNotificationTypeCommunityKicked)
query := "UPDATE activity_center_notifications SET read = 1, dismissed = 1, updated_at = ? WHERE community_id = ? AND notification_type IN (?, ?, ?, ?) AND NOT deleted" // nolint: gosec
_, err = tx.Exec(query, updatedAt, communityID,
ActivityCenterNotificationTypeCommunityRequest, ActivityCenterNotificationTypeCommunityKicked, ActivityCenterNotificationTypeCommunityBanned, ActivityCenterNotificationTypeCommunityUnbanned)
if err != nil {
return nil, err
}
@ -963,10 +1005,10 @@ func (db sqlitePersistence) DismissAllActivityCenterNotificationsFromChatID(chat
_ = tx.Rollback()
}()
query := fmt.Sprintf(`SELECT %s FROM activity_center_notifications
WHERE chat_id = ?
AND NOT deleted
AND NOT accepted
query := fmt.Sprintf(`SELECT %s FROM activity_center_notifications
WHERE chat_id = ?
AND NOT deleted
AND NOT accepted
AND notification_type != ?`, allFieldsForTableActivityCenterNotification)
rows, err := tx.Query(query, chatID, ActivityCenterNotificationTypeContactRequest)
if err != nil {
@ -986,7 +1028,7 @@ func (db sqlitePersistence) DismissAllActivityCenterNotificationsFromChatID(chat
query = `
UPDATE activity_center_notifications
SET read = 1, dismissed = 1, updated_at = ?
WHERE chat_id = ?
WHERE chat_id = ?
AND NOT deleted
AND NOT accepted
AND notification_type != ?
@ -1092,11 +1134,11 @@ func (db sqlitePersistence) AcceptActivityCenterNotificationsForInvitesFromUser(
_ = tx.Rollback()
}()
query := fmt.Sprintf(`SELECT %s FROM activity_center_notifications
WHERE author = ?
AND NOT deleted
AND NOT dismissed
AND NOT accepted
query := fmt.Sprintf(`SELECT %s FROM activity_center_notifications
WHERE author = ?
AND NOT deleted
AND NOT dismissed
AND NOT accepted
AND notification_type = ?`, allFieldsForTableActivityCenterNotification)
rows, err := tx.Query(query, userPublicKey, ActivityCenterNotificationTypeNewPrivateGroupChat)
if err != nil {
@ -1113,8 +1155,8 @@ func (db sqlitePersistence) AcceptActivityCenterNotificationsForInvitesFromUser(
_, err = tx.Exec(`
UPDATE activity_center_notifications
SET read = 1, accepted = 1, updated_at = ?
WHERE author = ?
SET read = 1, accepted = 1, updated_at = ?
WHERE author = ?
AND NOT deleted
AND NOT dismissed
AND NOT accepted
@ -1295,10 +1337,11 @@ func (db sqlitePersistence) ActiveContactRequestNotification(contactID string) (
a.contact_verification_status,
c.name,
a.author,
a.token_data,
a.updated_at
FROM activity_center_notifications a
LEFT JOIN chats c ON c.id = a.chat_id
WHERE a.author = ?
WHERE a.author = ?
AND NOT a.deleted
AND NOT a.dismissed
AND NOT a.accepted
@ -1329,7 +1372,7 @@ func (db sqlitePersistence) DeleteChatContactRequestActivityCenterNotifications(
}
_, err = db.db.Exec(`
UPDATE activity_center_notifications SET deleted = 1, updated_at = ?
UPDATE activity_center_notifications SET deleted = 1, updated_at = ?
WHERE
chat_id = ?
AND NOT deleted

View File

@ -2,7 +2,7 @@
// sources:
// 1619446565_postgres_make_anon_metrics_table.down.sql (24B)
// 1619446565_postgres_make_anon_metrics_table.up.sql (443B)
// doc.go (380B)
// doc.go (400B)
package migrations
@ -85,7 +85,7 @@ func _1619446565_postgres_make_anon_metrics_tableDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1619446565_postgres_make_anon_metrics_table.down.sql", size: 24, mode: os.FileMode(0644), modTime: time.Unix(1704739012, 0)}
info := bindataFileInfo{name: "1619446565_postgres_make_anon_metrics_table.down.sql", size: 24, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x75, 0xea, 0x1, 0x74, 0xe6, 0xa3, 0x11, 0xd0, 0x86, 0x87, 0x7e, 0x31, 0xb4, 0x1a, 0x27, 0x5d, 0xda, 0x77, 0xa3, 0xf5, 0x1d, 0x88, 0x79, 0xcf, 0xd5, 0x95, 0x75, 0xd, 0x47, 0xa1, 0x90, 0x5}}
return a, nil
}
@ -105,12 +105,12 @@ func _1619446565_postgres_make_anon_metrics_tableUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1619446565_postgres_make_anon_metrics_table.up.sql", size: 443, mode: os.FileMode(0644), modTime: time.Unix(1704739012, 0)}
info := bindataFileInfo{name: "1619446565_postgres_make_anon_metrics_table.up.sql", size: 443, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd5, 0xdc, 0x72, 0x28, 0x3c, 0xf6, 0x94, 0xb0, 0x47, 0x3d, 0xca, 0x55, 0x3d, 0xf7, 0x83, 0xb8, 0x7d, 0x2f, 0x1e, 0x98, 0xb7, 0xde, 0xa, 0xff, 0xa0, 0x52, 0x60, 0x83, 0x56, 0xc5, 0xd1, 0xa2}}
return a, nil
}
var _docGo = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x84\x8f\xbd\x6e\xf3\x30\x0c\x45\x77\x3f\xc5\x45\x96\x2c\x9f\xa5\xe5\x9b\xba\x75\xec\xde\x17\x60\xe4\x6b\x49\x88\x2d\x1a\x22\xf3\xf7\xf6\x85\xd3\x02\xcd\xd6\xf5\x00\xe7\xf0\x32\x46\x7c\x96\x6a\x98\xeb\x42\x54\x43\x63\xa2\x99\xf4\x07\x4e\x4c\x72\x31\xe2\x90\xab\x97\xcb\x29\x24\x5d\xa3\xb9\xf8\xc5\xc6\xba\xc6\xb5\xe6\x2e\xce\x78\xfd\x7f\x18\x62\x44\x92\x76\x74\x14\x69\xd3\xc2\x67\xcb\x60\x2e\xdd\x6b\xcb\xb8\x55\x2f\x10\x6c\x9d\x73\xbd\x07\xbc\x3b\x16\x8a\x39\xbc\x88\x1f\x0d\x5e\x88\x24\xc6\x3d\x33\x6b\x47\xd6\xf1\x54\xdb\x24\x2e\x61\x47\x1f\xf3\x0b\xd9\x17\x26\x59\x16\x4e\x98\xbb\xae\x4f\xd7\x64\x25\xa6\xda\x99\x5c\xfb\xe3\x1f\xc4\x8c\x8e\x26\x2b\x6d\xf7\x8b\x5c\x89\xa6\x3f\xe7\x21\x6d\xfa\xfb\x23\xdc\xb4\x9f\x0d\x62\xe0\x7d\x63\x72\x4e\x61\x18\x36\x49\x67\xc9\xc4\xa6\xe6\xb9\xd3\x86\x21\xc6\xac\x6f\x99\x8d\xbb\xf7\xba\x72\xdc\xce\x19\xdf\xbd\xaa\xcd\x30\x2a\x42\x88\xbf\x20\x64\x45\x88\xc3\x57\x00\x00\x00\xff\xff\xa9\xf1\x73\x83\x7c\x01\x00\x00")
var _docGo = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x84\x8f\xbd\x6a\x03\x31\x10\x84\xfb\x7b\x8a\xc1\x8d\x9b\x9c\x94\x40\x20\x10\x48\x91\x32\x7d\x5e\x60\x2d\xed\x49\xc2\x27\xed\xa1\xdd\xf3\xcf\xdb\x87\x73\x0c\x71\x97\x2d\x3f\xf8\x66\x66\xbd\xc7\x77\x2e\x8a\xa9\xcc\x8c\xa2\x68\x1c\x58\x95\xfa\x15\x07\x0e\xb4\x2a\x63\x97\x8a\xe5\xf5\xe0\x82\x54\xaf\x46\xb6\xea\x58\xaa\xaf\x25\x75\x32\xf6\xa7\xd7\xdd\xe0\x3d\x02\xb5\xbd\x21\x53\x8b\x33\xdf\xb2\x14\x6a\xd4\xad\xb4\x84\x73\xb1\x0c\xc2\xd2\x79\x2a\x17\x87\x4f\xc3\xcc\xa4\x06\xcb\x64\x7b\x85\x65\x46\x20\xe5\x2d\x66\x92\x8e\x24\xe3\xa1\xb4\x48\x46\x6e\x43\x5f\xd3\x03\xd9\x16\x06\x9a\x67\x8e\x98\xba\xd4\x9b\xab\x54\x19\xb1\x74\x0e\x26\xfd\xfa\x04\x52\x65\x43\xa3\xca\xba\xf9\x99\x4e\x8c\x26\xf7\x7a\x50\x8b\xff\x7f\x84\xb3\xf4\xa3\x82\x14\x7c\x59\x38\x18\x47\x37\x0c\x0b\x85\x23\x25\xc6\x22\x6a\xa9\xb3\x0e\x83\xf7\x49\xde\x13\x37\xde\xbc\xc7\x95\x63\x95\x68\xa5\xf2\xc7\xcb\xdb\xf3\xfd\x30\x2e\xc7\x84\xdf\x8e\x22\x4d\x31\x0a\x9c\xf3\x7f\xc0\x25\x81\xf3\xc3\x4f\x00\x00\x00\xff\xff\xe2\x75\x5f\x6c\x90\x01\x00\x00")
func docGoBytes() ([]byte, error) {
return bindataRead(
@ -125,8 +125,8 @@ func docGo() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "doc.go", size: 380, mode: os.FileMode(0644), modTime: time.Unix(1704739012, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x49, 0x1, 0xd4, 0xd6, 0xc7, 0x44, 0xd4, 0xfd, 0x7b, 0x69, 0x1f, 0xe3, 0xe, 0x48, 0x14, 0x99, 0xf0, 0x8e, 0x43, 0xae, 0x54, 0x64, 0xa2, 0x8b, 0x82, 0x1c, 0x2b, 0xb, 0xec, 0xf5, 0xb3, 0xfc}}
info := bindataFileInfo{name: "doc.go", size: 400, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf0, 0xa9, 0x91, 0x6, 0x5d, 0x91, 0xf7, 0x39, 0x3d, 0xc3, 0xf8, 0x5e, 0x4f, 0x7e, 0x7a, 0x8c, 0x60, 0x68, 0x66, 0x7d, 0x52, 0xe4, 0xd8, 0x23, 0x84, 0x55, 0x2c, 0x38, 0xa1, 0x64, 0xe7, 0xe6}}
return a, nil
}

View File

@ -31,6 +31,8 @@ var chatColors = []string{
type ChatType int
type ChatContext string
const (
ChatTypeOneToOne ChatType = iota + 1
ChatTypePublic
@ -85,6 +87,9 @@ type Chat struct {
// Active indicates whether the chat has been soft deleted
Active bool `json:"active"`
// ViewersCanPostReactions indicates whether users can post reactions in view only mode
ViewersCanPostReactions bool `json:"viewersCanPostReactions"`
ChatType ChatType `json:"chatType"`
// Timestamp indicates the last time this chat has received/sent a message
@ -155,6 +160,9 @@ type Chat struct {
// Image of the chat in Base64 format
Base64Image string `json:"image,omitempty"`
// If true, the chat is invisible if permissions are not met
HideIfPermissionsNotMet bool `json:"hideIfPermissionsNotMet,omitempty"`
}
type ChatPreview struct {
@ -487,6 +495,7 @@ func CreateCommunityChat(orgID, chatID string, orgChat *protobuf.CommunityChat,
return &Chat{
CommunityID: orgID,
CategoryID: orgChat.CategoryId,
HideIfPermissionsNotMet: orgChat.HideIfPermissionsNotMet,
Name: orgChat.Identity.DisplayName,
Description: orgChat.Identity.Description,
Active: true,
@ -498,6 +507,7 @@ func CreateCommunityChat(orgID, chatID string, orgChat *protobuf.CommunityChat,
ReadMessagesAtClockValue: 0,
ChatType: ChatTypeCommunityChat,
FirstMessageTimestamp: orgChat.Identity.FirstMessageTimestamp,
ViewersCanPostReactions: orgChat.ViewersCanPostReactions,
}
}
@ -636,3 +646,12 @@ func stringSliceContains(slice []string, item string) bool {
}
return false
}
func GetChatContextFromChatType(chatType ChatType) ChatContext {
switch chatType {
case ChatTypeOneToOne, ChatTypePrivateGroupChat:
return privateChat
default:
return publicChat
}
}

View File

@ -0,0 +1,11 @@
package common
type CodeControlFlags struct {
// AutoRequestHistoricMessages indicates whether we should automatically request
// historic messages on getting online, connecting to store node, etc.
AutoRequestHistoricMessages bool
// CuratedCommunitiesUpdateLoopEnabled indicates whether we should disable the curated communities update loop.
// Usually should be disabled in tests.
CuratedCommunitiesUpdateLoopEnabled bool
}

View File

@ -26,8 +26,4 @@ type FeatureFlags struct {
// Peersyncing indicates whether we should advertise and sync messages with other peers
Peersyncing bool
// AutoRequestHistoricMessages indicates whether we should automatically request
// historic messages on getting online, connecting to store node, etc.
AutoRequestHistoricMessages bool
}

View File

@ -49,6 +49,7 @@ type QuotedMessage struct {
DeletedForMe bool `json:"deletedForMe,omitempty"`
DiscordMessage *protobuf.DiscordMessage `json:"discordMessage,omitempty"`
BridgeMessage *protobuf.BridgeMessage `json:"bridgeMessage,omitempty"`
}
type CommandState int

View File

@ -15,8 +15,8 @@ type MakeMediaServerURLType func(msgID string, previewURL string, imageID MediaS
type MakeMediaServerURLMessageWrapperType func(previewURL string, imageID MediaServerImageID) string
type LinkPreviewThumbnail struct {
Width int `json:"width"`
Height int `json:"height"`
Width int `json:"width,omitempty"`
Height int `json:"height,omitempty"`
// Non-empty when the thumbnail is available via the media server, i.e. after
// the chat message is sent.
URL string `json:"url,omitempty"`
@ -31,6 +31,7 @@ type LinkPreview struct {
Hostname string `json:"hostname"`
Title string `json:"title,omitempty"`
Description string `json:"description,omitempty"`
Favicon LinkPreviewThumbnail `json:"favicon,omitempty"`
Thumbnail LinkPreviewThumbnail `json:"thumbnail,omitempty"`
}
@ -288,12 +289,19 @@ func (m *Message) ConvertLinkPreviewsToProto() ([]*protobuf.UnfurledLink, error)
return nil, fmt.Errorf("invalid link preview, url='%s': %w", preview.URL, err)
}
var payload []byte
var thumbnailPayload []byte
var faviconPayload []byte
var err error
if preview.Thumbnail.DataURI != "" {
payload, err = images.GetPayloadFromURI(preview.Thumbnail.DataURI)
thumbnailPayload, err = images.GetPayloadFromURI(preview.Thumbnail.DataURI)
if err != nil {
return nil, fmt.Errorf("could not get data URI payload, url='%s': %w", preview.URL, err)
return nil, fmt.Errorf("could not get data URI payload for link preview thumbnail, url='%s': %w", preview.URL, err)
}
}
if preview.Favicon.DataURI != "" {
faviconPayload, err = images.GetPayloadFromURI(preview.Favicon.DataURI)
if err != nil {
return nil, fmt.Errorf("could not get data URI payload for link preview favicon, url='%s': %w", preview.URL, err)
}
}
@ -304,7 +312,8 @@ func (m *Message) ConvertLinkPreviewsToProto() ([]*protobuf.UnfurledLink, error)
Description: preview.Description,
ThumbnailWidth: uint32(preview.Thumbnail.Width),
ThumbnailHeight: uint32(preview.Thumbnail.Height),
ThumbnailPayload: payload,
ThumbnailPayload: thumbnailPayload,
FaviconPayload: faviconPayload,
}
unfurledLinks = append(unfurledLinks, ul)
}
@ -312,7 +321,8 @@ func (m *Message) ConvertLinkPreviewsToProto() ([]*protobuf.UnfurledLink, error)
return unfurledLinks, nil
}
func (m *Message) ConvertFromProtoToLinkPreviews(makeMediaServerURL func(msgID string, previewURL string) string) []LinkPreview {
func (m *Message) ConvertFromProtoToLinkPreviews(makeThumbnailMediaServerURL func(msgID string, previewURL string) string,
makeFaviconMediaServerURL func(msgID string, previewURL string) string) []LinkPreview {
var links []*protobuf.UnfurledLink
if links = m.GetUnfurledLinks(); links == nil {
@ -340,13 +350,20 @@ func (m *Message) ConvertFromProtoToLinkPreviews(makeMediaServerURL func(msgID s
}
mediaURL := ""
if len(link.ThumbnailPayload) > 0 {
mediaURL = makeMediaServerURL(m.ID, link.Url)
mediaURL = makeThumbnailMediaServerURL(m.ID, link.Url)
}
if link.GetThumbnailPayload() != nil {
lp.Thumbnail.Width = int(link.ThumbnailWidth)
lp.Thumbnail.Height = int(link.ThumbnailHeight)
lp.Thumbnail.URL = mediaURL
}
faviconMediaURL := ""
if len(link.FaviconPayload) > 0 {
faviconMediaURL = makeFaviconMediaServerURL(m.ID, link.Url)
}
if link.GetFaviconPayload() != nil {
lp.Favicon.URL = faviconMediaURL
}
previews = append(previews, lp)
}

View File

@ -82,7 +82,8 @@ type MessageSender struct {
ephemeralKeysMutex sync.Mutex
// messageEventsSubscriptions contains all the subscriptions for message events
messageEventsSubscriptions []chan<- *MessageEvent
messageEventsSubscriptions []chan<- *MessageEvent
messageEventsSubscriptionsMutex sync.Mutex
featureFlags FeatureFlags
@ -114,6 +115,9 @@ func NewMessageSender(
}
func (s *MessageSender) Stop() {
s.messageEventsSubscriptionsMutex.Lock()
defer s.messageEventsSubscriptionsMutex.Unlock()
for _, c := range s.messageEventsSubscriptions {
close(c)
}
@ -1184,6 +1188,10 @@ func (s *MessageSender) notifyOnSentMessage(sentMessage *SentMessage) {
Type: MessageSent,
SentMessage: sentMessage,
}
s.messageEventsSubscriptionsMutex.Lock()
defer s.messageEventsSubscriptionsMutex.Unlock()
// Publish on channels, drop if buffer is full
for _, c := range s.messageEventsSubscriptions {
select {
@ -1202,6 +1210,9 @@ func (s *MessageSender) notifyOnScheduledMessage(recipient *ecdsa.PublicKey, mes
RawMessage: message,
}
s.messageEventsSubscriptionsMutex.Lock()
defer s.messageEventsSubscriptionsMutex.Unlock()
// Publish on channels, drop if buffer is full
for _, c := range s.messageEventsSubscriptions {
select {

View File

@ -23,11 +23,13 @@ type HighestRoleResponse struct {
Criteria []*PermissionTokenCriteriaResult `json:"criteria"`
}
var joiningRoleOrders = map[protobuf.CommunityTokenPermission_Type]int{
protobuf.CommunityTokenPermission_BECOME_MEMBER: 1,
protobuf.CommunityTokenPermission_BECOME_ADMIN: 2,
protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER: 3,
protobuf.CommunityTokenPermission_BECOME_TOKEN_OWNER: 4,
var roleOrders = map[protobuf.CommunityTokenPermission_Type]int{
protobuf.CommunityTokenPermission_BECOME_MEMBER: 1,
protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL: 2,
protobuf.CommunityTokenPermission_CAN_VIEW_AND_POST_CHANNEL: 3,
protobuf.CommunityTokenPermission_BECOME_ADMIN: 4,
protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER: 5,
protobuf.CommunityTokenPermission_BECOME_TOKEN_OWNER: 6,
}
type ByRoleDesc []*HighestRoleResponse
@ -35,7 +37,7 @@ type ByRoleDesc []*HighestRoleResponse
func (a ByRoleDesc) Len() int { return len(a) }
func (a ByRoleDesc) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByRoleDesc) Less(i, j int) bool {
return joiningRoleOrders[a[i].Role] > joiningRoleOrders[a[j].Role]
return roleOrders[a[i].Role] > roleOrders[a[j].Role]
}
type rolesAndHighestRole struct {
@ -47,7 +49,7 @@ func calculateRolesAndHighestRole(permissions map[string]*PermissionTokenCriteri
item := &rolesAndHighestRole{}
byRoleMap := make(map[protobuf.CommunityTokenPermission_Type]*HighestRoleResponse)
for _, p := range permissions {
if joiningRoleOrders[p.Role] == 0 {
if roleOrders[p.Role] == 0 {
continue
}
if byRoleMap[p.Role] == nil {

View File

@ -6,11 +6,14 @@ import (
"encoding/json"
"errors"
"fmt"
"math"
"math/big"
"sync"
"time"
"github.com/golang/protobuf/proto"
"go.uber.org/zap"
slices "golang.org/x/exp/slices"
"github.com/ethereum/go-ethereum/common/hexutil"
@ -93,16 +96,20 @@ type CommunityAdminSettings struct {
}
type CommunityChat struct {
ID string `json:"id"`
Name string `json:"name"`
Color string `json:"color"`
Emoji string `json:"emoji"`
Description string `json:"description"`
Members map[string]*protobuf.CommunityMember `json:"members"`
Permissions *protobuf.CommunityPermissions `json:"permissions"`
CanPost bool `json:"canPost"`
Position int `json:"position"`
CategoryID string `json:"categoryID"`
ID string `json:"id"`
Name string `json:"name"`
Color string `json:"color"`
Emoji string `json:"emoji"`
Description string `json:"description"`
Members map[string]*protobuf.CommunityMember `json:"members"`
Permissions *protobuf.CommunityPermissions `json:"permissions"`
CanPost bool `json:"canPost"`
CanView bool `json:"canView"`
ViewersCanPostReactions bool `json:"viewersCanPostReactions"`
Position int `json:"position"`
CategoryID string `json:"categoryID"`
TokenGated bool `json:"tokenGated"`
HideIfPermissionsNotMet bool `json:"hideIfPermissionsNotMet"`
}
type CommunityCategory struct {
@ -123,6 +130,7 @@ const (
CommunityMemberBanPending
CommunityMemberUnbanPending
CommunityMemberKickPending
CommunityMemberBanWithAllMessagesDelete
)
func (o *Community) MarshalPublicAPIJSON() ([]byte, error) {
@ -174,21 +182,29 @@ func (o *Community) MarshalPublicAPIJSON() ([]byte, error) {
communityItem.Encrypted = o.Encrypted()
}
for id, c := range o.config.CommunityDescription.Chats {
canPost, err := o.CanPost(o.config.MemberIdentity, id)
// NOTE: Here `CanPost` is only set for ChatMessage. But it can be different for reactions/pin/etc.
// Consider adding more properties to `CommunityChat` to reflect that.
canPost, err := o.CanPost(o.config.MemberIdentity, id, protobuf.ApplicationMetadataMessage_CHAT_MESSAGE)
if err != nil {
return nil, err
}
canView := o.CanView(o.config.MemberIdentity, id)
chat := CommunityChat{
ID: id,
Name: c.Identity.DisplayName,
Color: c.Identity.Color,
Emoji: c.Identity.Emoji,
Description: c.Identity.Description,
Permissions: c.Permissions,
Members: c.Members,
CanPost: canPost,
CategoryID: c.CategoryId,
Position: int(c.Position),
ID: id,
Name: c.Identity.DisplayName,
Color: c.Identity.Color,
Emoji: c.Identity.Emoji,
Description: c.Identity.Description,
Permissions: c.Permissions,
Members: c.Members,
CanPost: canPost,
CanView: canView,
ViewersCanPostReactions: c.ViewersCanPostReactions,
TokenGated: o.channelEncrypted(id),
CategoryID: c.CategoryId,
HideIfPermissionsNotMet: c.HideIfPermissionsNotMet,
Position: int(c.Position),
}
communityItem.Chats[id] = chat
}
@ -272,8 +288,10 @@ func (o *Community) MarshalJSON() ([]byte, error) {
PubsubTopicKey string `json:"pubsubTopicKey"`
Shard *shard.Shard `json:"shard"`
LastOpenedAt int64 `json:"lastOpenedAt"`
Clock uint64 `json:"clock"`
}{
ID: o.ID(),
Clock: o.Clock(),
MemberRole: o.MemberRole(o.MemberIdentity()),
IsControlNode: o.IsControlNode(),
Verified: o.config.Verified,
@ -308,21 +326,29 @@ func (o *Community) MarshalJSON() ([]byte, error) {
communityItem.Categories[id] = category
}
for id, c := range o.config.CommunityDescription.Chats {
canPost, err := o.CanPost(o.config.MemberIdentity, id)
// NOTE: Here `CanPost` is only set for ChatMessage. But it can be different for reactions/pin/etc.
// Consider adding more properties to `CommunityChat` to reflect that.
canPost, err := o.CanPost(o.config.MemberIdentity, id, protobuf.ApplicationMetadataMessage_CHAT_MESSAGE)
if err != nil {
return nil, err
}
canView := o.CanView(o.config.MemberIdentity, id)
chat := CommunityChat{
ID: id,
Name: c.Identity.DisplayName,
Emoji: c.Identity.Emoji,
Color: c.Identity.Color,
Description: c.Identity.Description,
Permissions: c.Permissions,
Members: c.Members,
CanPost: canPost,
CategoryID: c.CategoryId,
Position: int(c.Position),
ID: id,
Name: c.Identity.DisplayName,
Emoji: c.Identity.Emoji,
Color: c.Identity.Color,
Description: c.Identity.Description,
Permissions: c.Permissions,
Members: c.Members,
CanPost: canPost,
CanView: canView,
ViewersCanPostReactions: c.ViewersCanPostReactions,
TokenGated: o.channelEncrypted(id),
CategoryID: c.CategoryId,
HideIfPermissionsNotMet: c.HideIfPermissionsNotMet,
Position: int(c.Position),
}
communityItem.Chats[id] = chat
}
@ -516,16 +542,6 @@ type CommunitySettings struct {
Clock uint64 `json:"clock"`
}
// `CommunityAdminEventChanges contain additional changes that don't live on
// a `Community` but still have to be propagated to other admin and control nodes
type CommunityEventChanges struct {
*CommunityChanges
// `RejectedRequestsToJoin` is a map of signer keys to requests to join
RejectedRequestsToJoin map[string]*protobuf.CommunityRequestToJoin `json:"rejectedRequestsToJoin"`
// `AcceptedRequestsToJoin` is a map of signer keys to requests to join
AcceptedRequestsToJoin map[string]*protobuf.CommunityRequestToJoin `json:"acceptedRequestsToJoin"`
}
func (o *Community) emptyCommunityChanges() *CommunityChanges {
changes := EmptyCommunityChanges()
changes.Community = o
@ -621,6 +637,15 @@ func (o *Community) GetMember(pk *ecdsa.PublicKey) *protobuf.CommunityMember {
return o.getMember(pk)
}
func (o *Community) GetChat(chatID string) (*protobuf.CommunityChat, error) {
chat, ok := o.config.CommunityDescription.Chats[chatID]
if !ok {
return nil, ErrChatNotFound
}
return chat, nil
}
func (o *Community) getChatMember(pk *ecdsa.PublicKey, chatID string) *protobuf.CommunityMember {
if !o.hasMember(pk) {
return nil
@ -648,14 +673,17 @@ func (o *Community) IsBanned(pk *ecdsa.PublicKey) bool {
}
func (o *Community) isBanned(pk *ecdsa.PublicKey) bool {
key := common.PubkeyToHex(pk)
for _, k := range o.config.CommunityDescription.BanList {
if k == key {
return true
}
banned := slices.Contains(o.config.CommunityDescription.BanList, key)
if o.config.CommunityDescription.BannedMembers != nil && !banned {
_, banned = o.config.CommunityDescription.BannedMembers[key]
}
return false
return banned
}
func (o *Community) rolesOf(pk *ecdsa.PublicKey) []protobuf.CommunityMember_Roles {
@ -850,7 +878,7 @@ func (o *Community) UnbanUserFromCommunity(pk *ecdsa.PublicKey) (*protobuf.Commu
return o.config.CommunityDescription, nil
}
func (o *Community) BanUserFromCommunity(pk *ecdsa.PublicKey) (*protobuf.CommunityDescription, error) {
func (o *Community) BanUserFromCommunity(pk *ecdsa.PublicKey, communityBanInfo *protobuf.CommunityBanInfo) (*protobuf.CommunityDescription, error) {
o.mutex.Lock()
defer o.mutex.Unlock()
@ -863,13 +891,20 @@ func (o *Community) BanUserFromCommunity(pk *ecdsa.PublicKey) (*protobuf.Communi
}
if o.IsControlNode() {
o.banUserFromCommunity(pk)
o.banUserFromCommunity(pk, communityBanInfo)
o.increaseClock()
} else {
err := o.addNewCommunityEvent(o.ToBanCommunityMemberCommunityEvent(common.PubkeyToHex(pk)))
pkStr := common.PubkeyToHex(pk)
err := o.addNewCommunityEvent(o.ToBanCommunityMemberCommunityEvent(pkStr))
if err != nil {
return nil, err
}
if communityBanInfo.DeleteAllMessages {
err := o.addNewCommunityEvent(o.ToDeleteAllMemberMessagesEvent(pkStr))
if err != nil {
return nil, err
}
}
}
return o.config.CommunityDescription, nil
@ -969,6 +1004,13 @@ func (o *Community) Edit(description *protobuf.CommunityDescription) {
o.config.CommunityDescription.AdminSettings.PinMessageAllMembersEnabled = description.AdminSettings.PinMessageAllMembersEnabled
}
func (o *Community) EditPermissionAccess(permissionAccess protobuf.CommunityPermissions_Access) {
o.config.CommunityDescription.Permissions.Access = permissionAccess
if o.IsControlNode() {
o.increaseClock()
}
}
func (o *Community) Join() {
o.config.Joined = true
o.config.JoinedAt = time.Now().Unix()
@ -1039,7 +1081,8 @@ func (o *Community) UpdateCommunityDescription(description *protobuf.CommunityDe
response := o.emptyCommunityChanges()
if description.Clock <= o.config.CommunityDescription.Clock {
// Enables processing of identical clocks. Identical descriptions may be reprocessed upon subsequent receipt of the previously missing encryption key.
if description.Clock < o.config.CommunityDescription.Clock {
return response, nil
}
@ -1140,7 +1183,12 @@ func (o *Community) ValidateEditSharedAddresses(signer *ecdsa.PublicKey, request
return errors.New("no addresses were shared")
}
if request.Clock < o.config.CommunityDescription.Members[common.PubkeyToHex(signer)].LastUpdateClock {
member, exists := o.config.CommunityDescription.Members[common.PubkeyToHex(signer)]
if !exists {
return errors.New("signer is not a community member")
}
if request.Clock < member.LastUpdateClock {
return errors.New("edit request is older than the last one we have. Ignore")
}
@ -1391,6 +1439,17 @@ func (o *Community) Description() *protobuf.CommunityDescription {
return o.config.CommunityDescription
}
func (o *Community) EncryptedDescription() (*protobuf.CommunityDescription, error) {
clone := proto.Clone(o.config.CommunityDescription).(*protobuf.CommunityDescription)
if o.encryptor != nil {
err := encryptDescription(o.encryptor, o, clone)
if err != nil {
return nil, err
}
}
return clone, nil
}
func (o *Community) DescriptionProtocolMessage() []byte {
return o.config.CommunityDescriptionProtocolMessage
}
@ -1477,6 +1536,37 @@ func hydrateChannelsMembers(communityID string, description *protobuf.CommunityD
}
}
func upgradeTokenPermissions(description *protobuf.CommunityDescription) {
floatToWeiIntFunc := func(floatStr string, decimals uint64) string {
bigfloat := new(big.Float)
bigfloat.SetString(floatStr)
multiplier := big.NewFloat(math.Pow(10, float64(decimals)))
bigfloat.Mul(bigfloat, multiplier)
result := new(big.Int)
bigfloat.Int(result)
return result.String()
}
for _, permission := range description.TokenPermissions {
for _, criteria := range permission.TokenCriteria {
if criteria.AmountInWei != "" {
continue
}
// set AmountInWei if missing
// Amount format (deprecated): "0.123"
// AmountInWei format: "123000..000"
if criteria.Type == protobuf.CommunityTokenType_ERC20 {
criteria.AmountInWei = floatToWeiIntFunc(criteria.Amount, criteria.Decimals)
} else {
criteria.AmountInWei = criteria.Amount
}
}
}
}
func (o *Community) Chats() map[string]*protobuf.CommunityChat {
// Why are we checking here for nil, it should be the responsibility of the caller
if o == nil {
@ -1583,8 +1673,20 @@ func (o *Community) tokenPermissions() map[string]*CommunityTokenPermission {
func (o *Community) PendingAndBannedMembers() map[string]CommunityMemberState {
result := make(map[string]CommunityMemberState)
if o.config.CommunityDescription.BannedMembers != nil {
for bannedMemberID, banInfo := range o.config.CommunityDescription.BannedMembers {
state := CommunityMemberBanned
if banInfo.DeleteAllMessages {
state = CommunityMemberBanWithAllMessagesDelete
}
result[bannedMemberID] = state
}
}
for _, bannedMemberID := range o.config.CommunityDescription.BanList {
result[bannedMemberID] = CommunityMemberBanned
if _, exists := result[bannedMemberID]; !exists {
result[bannedMemberID] = CommunityMemberBanned
}
}
if o.config.EventsData == nil {
@ -1805,53 +1907,71 @@ func (o *Community) VerifyGrantSignature(data []byte) (*protobuf.Grant, error) {
return grant, nil
}
func (o *Community) CanPost(pk *ecdsa.PublicKey, chatID string) (bool, error) {
func (o *Community) CanView(pk *ecdsa.PublicKey, chatID string) bool {
if o.config.CommunityDescription.Chats == nil {
o.config.Logger.Debug("Community.CanPost: no-chats")
return false, nil
o.config.Logger.Debug("Community.CanView: no-chats")
return false
}
chat, ok := o.config.CommunityDescription.Chats[chatID]
if !ok {
o.config.Logger.Debug("Community.CanPost: no chat with id", zap.String("chat-id", chatID))
return false, nil
o.config.Logger.Debug("Community.CanView: no chat with id", zap.String("chat-id", chatID))
return false
}
// community creator can always post, return immediately
if common.IsPubKeyEqual(pk, o.ControlNode()) {
return true, nil
return true
}
if o.isBanned(pk) {
o.config.Logger.Debug("Community.CanPost: user is banned", zap.String("chat-id", chatID))
return false, nil
o.config.Logger.Debug("Community.CanView: user is banned", zap.String("chat-id", chatID))
return false
}
if o.config.CommunityDescription.Members == nil {
o.config.Logger.Debug("Community.CanPost: no members in org", zap.String("chat-id", chatID))
return false, nil
o.config.Logger.Debug("Community.CanView: no members in org", zap.String("chat-id", chatID))
return false
}
// If community member, also check chat membership next
_, ok = o.config.CommunityDescription.Members[common.PubkeyToHex(pk)]
if !ok {
o.config.Logger.Debug("Community.CanPost: not a community member", zap.String("chat-id", chatID))
return false, nil
o.config.Logger.Debug("Community.CanView: not a community member", zap.String("chat-id", chatID))
return false
}
if chat.Members == nil {
o.config.Logger.Debug("Community.CanPost: no members in chat", zap.String("chat-id", chatID))
o.config.Logger.Debug("Community.CanView: no members in chat", zap.String("chat-id", chatID))
return false
}
_, isChatMember := chat.Members[common.PubkeyToHex(pk)]
return isChatMember
}
func (o *Community) CanPost(pk *ecdsa.PublicKey, chatID string, messageType protobuf.ApplicationMetadataMessage_Type) (bool, error) {
hasAccessToChat := o.CanView(pk, chatID)
if !hasAccessToChat {
return false, nil
}
// Need to also be a chat member to post
if !o.IsMemberInChat(pk, chatID) {
o.config.Logger.Debug("Community.CanPost: not a chat member", zap.String("chat-id", chatID))
return false, nil
}
chat := o.config.CommunityDescription.Chats[chatID]
member := chat.Members[common.PubkeyToHex(pk)]
// all conditions satisfied, user can post after all
return true, nil
switch messageType {
case protobuf.ApplicationMetadataMessage_PIN_MESSAGE:
pinAllowed := o.IsPrivilegedMember(pk) || o.AllowsAllMembersToPinMessage()
return pinAllowed, nil
case protobuf.ApplicationMetadataMessage_EMOJI_REACTION:
isPoster := member.GetChannelRole() == protobuf.CommunityMember_CHANNEL_ROLE_POSTER
isViewer := member.GetChannelRole() == protobuf.CommunityMember_CHANNEL_ROLE_VIEWER
return isPoster || (isViewer && chat.ViewersCanPostReactions), nil
default:
return member.GetChannelRole() == protobuf.CommunityMember_CHANNEL_ROLE_POSTER, nil
}
}
func (o *Community) BuildGrant(key *ecdsa.PublicKey, chatID string) ([]byte, error) {
@ -1926,8 +2046,8 @@ func (o *Community) isMember() bool {
return o.hasMember(o.config.MemberIdentity)
}
func (o *Community) CanMemberIdentityPost(chatID string) (bool, error) {
return o.CanPost(o.config.MemberIdentity, chatID)
func (o *Community) CanMemberIdentityPost(chatID string, messageType protobuf.ApplicationMetadataMessage_Type) (bool, error) {
return o.CanPost(o.config.MemberIdentity, chatID, messageType)
}
// CanJoin returns whether a user can join the community, only if it's
@ -2010,7 +2130,9 @@ func (o *Community) AddMember(publicKey *ecdsa.PublicKey, roles []protobuf.Commu
return changes, nil
}
func (o *Community) AddMemberToChat(chatID string, publicKey *ecdsa.PublicKey, roles []protobuf.CommunityMember_Roles) (*CommunityChanges, error) {
func (o *Community) AddMemberToChat(chatID string, publicKey *ecdsa.PublicKey,
roles []protobuf.CommunityMember_Roles, channelRole protobuf.CommunityMember_ChannelRole) (*CommunityChanges, error) {
o.mutex.Lock()
defer o.mutex.Unlock()
@ -2030,7 +2152,8 @@ func (o *Community) AddMemberToChat(chatID string, publicKey *ecdsa.PublicKey, r
chat.Members = make(map[string]*protobuf.CommunityMember)
}
chat.Members[memberKey] = &protobuf.CommunityMember{
Roles: roles,
Roles: roles,
ChannelRole: channelRole,
}
changes.ChatsModified[chatID] = &CommunityChatChanges{
ChatModified: chat,
@ -2187,9 +2310,13 @@ func (o *Community) unbanUserFromCommunity(pk *ecdsa.PublicKey) {
break
}
}
if o.config.CommunityDescription.BannedMembers != nil {
delete(o.config.CommunityDescription.BannedMembers, key)
}
}
func (o *Community) banUserFromCommunity(pk *ecdsa.PublicKey) {
func (o *Community) banUserFromCommunity(pk *ecdsa.PublicKey, communityBanInfo *protobuf.CommunityBanInfo) {
key := common.PubkeyToHex(pk)
if o.hasMember(pk) {
// Remove from org
@ -2201,6 +2328,14 @@ func (o *Community) banUserFromCommunity(pk *ecdsa.PublicKey) {
}
}
if o.config.CommunityDescription.BannedMembers == nil {
o.config.CommunityDescription.BannedMembers = make(map[string]*protobuf.CommunityBanInfo)
}
if _, exists := o.config.CommunityDescription.BannedMembers[key]; !exists {
o.config.CommunityDescription.BannedMembers[key] = communityBanInfo
}
for _, u := range o.config.CommunityDescription.BanList {
if u == key {
return
@ -2210,6 +2345,21 @@ func (o *Community) banUserFromCommunity(pk *ecdsa.PublicKey) {
o.config.CommunityDescription.BanList = append(o.config.CommunityDescription.BanList, key)
}
func (o *Community) deleteBannedMemberAllMessages(pk *ecdsa.PublicKey) error {
key := common.PubkeyToHex(pk)
if o.config.CommunityDescription.BannedMembers == nil {
return ErrBannedMemberNotFound
}
if _, exists := o.config.CommunityDescription.BannedMembers[key]; !exists {
return ErrBannedMemberNotFound
}
o.config.CommunityDescription.BannedMembers[key].DeleteAllMessages = true
return nil
}
func (o *Community) editChat(chatID string, chat *protobuf.CommunityChat) error {
err := validateCommunityChat(o.config.CommunityDescription, chat)
if err != nil {
@ -2343,20 +2493,14 @@ func (o *Community) DeclineRequestToJoin(dbRequest *RequestToJoin) (adminEventCr
}
if o.IsControlNode() {
// typically, community's clock is increased implicitly when making changes
// to it, however in this scenario there are no changes in the community, yet
// we need to increase the clock to ensure the owner event is processed by other
// nodes.
pk, err := common.HexToPubkey(dbRequest.PublicKey)
if err != nil {
return false, err
}
o.removeMemberFromOrg(pk)
o.increaseClock()
} else {
rejectedRequestsToJoin := make(map[string]*protobuf.CommunityRequestToJoin)
rejectedRequestsToJoin[dbRequest.PublicKey] = dbRequest.ToCommunityRequestToJoinProtobuf()
adminChanges := &CommunityEventChanges{
CommunityChanges: o.emptyCommunityChanges(),
RejectedRequestsToJoin: rejectedRequestsToJoin,
}
err = o.addNewCommunityEvent(o.ToCommunityRequestToJoinRejectCommunityEvent(adminChanges))
err = o.addNewCommunityEvent(o.ToCommunityRequestToJoinRejectCommunityEvent(dbRequest.PublicKey, dbRequest.ToCommunityRequestToJoinProtobuf()))
if err != nil {
return adminEventCreated, err
}
@ -2367,11 +2511,8 @@ func (o *Community) DeclineRequestToJoin(dbRequest *RequestToJoin) (adminEventCr
return adminEventCreated, err
}
func (o *Community) ValidateEvent(event *CommunityEvent, signer *ecdsa.PublicKey) error {
o.mutex.Lock()
defer o.mutex.Unlock()
err := validateCommunityEvent(event)
func (o *Community) validateEvent(event *CommunityEvent, signer *ecdsa.PublicKey) error {
err := event.Validate()
if err != nil {
return err
}
@ -2397,6 +2538,12 @@ func (o *Community) ValidateEvent(event *CommunityEvent, signer *ecdsa.PublicKey
return nil
}
func (o *Community) ValidateEvent(event *CommunityEvent, signer *ecdsa.PublicKey) error {
o.mutex.Lock()
defer o.mutex.Unlock()
return o.validateEvent(event, signer)
}
func (o *Community) MemberCanManageToken(member *ecdsa.PublicKey, token *community_token.CommunityToken) bool {
return o.IsMemberOwner(member) || o.IsControlNode() || (o.IsMemberTokenMaster(member) &&
token.PrivilegesLevel != community_token.OwnerLevel && token.PrivilegesLevel != community_token.MasterLevel)

View File

@ -3,6 +3,8 @@ package communities
import (
"crypto/ecdsa"
slices "golang.org/x/exp/slices"
"github.com/status-im/status-go/protocol/protobuf"
)
@ -20,8 +22,10 @@ type CommunityChanges struct {
ControlNodeChanged *ecdsa.PublicKey `json:"controlNodeChanged"`
MembersAdded map[string]*protobuf.CommunityMember `json:"membersAdded"`
MembersRemoved map[string]*protobuf.CommunityMember `json:"membersRemoved"`
MembersAdded map[string]*protobuf.CommunityMember `json:"membersAdded"`
MembersRemoved map[string]*protobuf.CommunityMember `json:"membersRemoved"`
MembersBanned map[string]bool `json:"membersBanned"`
MembersUnbanned map[string]bool `json:"membersUnbanned"`
TokenPermissionsAdded map[string]*CommunityTokenPermission `json:"tokenPermissionsAdded"`
TokenPermissionsModified map[string]*CommunityTokenPermission `json:"tokenPermissionsModified"`
@ -48,8 +52,10 @@ type CommunityChanges struct {
func EmptyCommunityChanges() *CommunityChanges {
return &CommunityChanges{
MembersAdded: make(map[string]*protobuf.CommunityMember),
MembersRemoved: make(map[string]*protobuf.CommunityMember),
MembersAdded: make(map[string]*protobuf.CommunityMember),
MembersRemoved: make(map[string]*protobuf.CommunityMember),
MembersBanned: make(map[string]bool),
MembersUnbanned: make(map[string]bool),
TokenPermissionsAdded: make(map[string]*CommunityTokenPermission),
TokenPermissionsModified: make(map[string]*CommunityTokenPermission),
@ -84,6 +90,22 @@ func (c *CommunityChanges) HasMemberLeft(identity string) bool {
return ok
}
func (c *CommunityChanges) IsMemberBanned(identity string) bool {
if len(c.MembersBanned) == 0 {
return false
}
_, ok := c.MembersBanned[identity]
return ok
}
func (c *CommunityChanges) IsMemberUnbanned(identity string) bool {
if len(c.MembersUnbanned) == 0 {
return false
}
_, ok := c.MembersUnbanned[identity]
return ok
}
func EvaluateCommunityChanges(origin, modified *Community) *CommunityChanges {
changes := evaluateCommunityChangesByDescription(origin.Description(), modified.Description())
@ -122,19 +144,23 @@ func evaluateCommunityChangesByDescription(origin, modified *protobuf.CommunityD
// Check for new members at the org level
for pk, member := range modified.Members {
if _, ok := origin.Members[pk]; !ok {
if changes.MembersAdded == nil {
changes.MembersAdded = make(map[string]*protobuf.CommunityMember)
}
changes.MembersAdded[pk] = member
}
}
// Check ban/unban
findDiffInBannedMembers(modified.BannedMembers, origin.BannedMembers, changes.MembersBanned)
findDiffInBannedMembers(origin.BannedMembers, modified.BannedMembers, changes.MembersUnbanned)
// Check for new banned members (from deprecated BanList)
findDiffInBanList(modified.BanList, origin.BanList, changes.MembersBanned)
// Check for new unbanned members (from deprecated BanList)
findDiffInBanList(origin.BanList, modified.BanList, changes.MembersUnbanned)
// Check for removed members at the org level
for pk, member := range origin.Members {
if _, ok := modified.Members[pk]; !ok {
if changes.MembersRemoved == nil {
changes.MembersRemoved = make(map[string]*protobuf.CommunityMember)
}
changes.MembersRemoved[pk] = member
}
}
@ -145,10 +171,6 @@ func evaluateCommunityChangesByDescription(origin, modified *protobuf.CommunityD
modified.Chats = make(map[string]*protobuf.CommunityChat)
}
if _, ok := modified.Chats[chatID]; !ok {
if changes.ChatsRemoved == nil {
changes.ChatsRemoved = make(map[string]*protobuf.CommunityChat)
}
changes.ChatsRemoved[chatID] = chat
}
}
@ -159,10 +181,6 @@ func evaluateCommunityChangesByDescription(origin, modified *protobuf.CommunityD
}
if _, ok := origin.Chats[chatID]; !ok {
if changes.ChatsAdded == nil {
changes.ChatsAdded = make(map[string]*protobuf.CommunityChat)
}
changes.ChatsAdded[chatID] = chat
} else {
// Check for members added
@ -232,10 +250,6 @@ func evaluateCommunityChangesByDescription(origin, modified *protobuf.CommunityD
origin.Categories = make(map[string]*protobuf.CommunityCategory)
}
if _, ok := origin.Categories[categoryID]; !ok {
if changes.CategoriesAdded == nil {
changes.CategoriesAdded = make(map[string]*protobuf.CommunityCategory)
}
changes.CategoriesAdded[categoryID] = category
} else {
if origin.Categories[categoryID].Name != category.Name || origin.Categories[categoryID].Position != category.Position {
@ -268,3 +282,33 @@ func evaluateCommunityChangesByDescription(origin, modified *protobuf.CommunityD
return changes
}
func findDiffInBanList(searchFrom []string, searchIn []string, storeTo map[string]bool) {
for _, memberToFind := range searchFrom {
if _, stored := storeTo[memberToFind]; stored {
continue
}
exists := slices.Contains(searchIn, memberToFind)
if !exists {
storeTo[memberToFind] = false
}
}
}
func findDiffInBannedMembers(searchFrom map[string]*protobuf.CommunityBanInfo, searchIn map[string]*protobuf.CommunityBanInfo, storeTo map[string]bool) {
if searchFrom == nil {
return
} else if searchIn == nil {
for memberToFind, value := range searchFrom {
storeTo[memberToFind] = value.DeleteAllMessages
}
} else {
for memberToFind, value := range searchFrom {
if _, exists := searchIn[memberToFind]; !exists {
storeTo[memberToFind] = value.DeleteAllMessages
}
}
}
}

View File

@ -1,8 +1,6 @@
package communities
import (
"github.com/golang/protobuf/proto"
"go.uber.org/zap"
"github.com/status-im/status-go/eth-node/types"
@ -26,7 +24,7 @@ func encryptDescription(encryptor DescriptionEncryptor, community *Community, de
descriptionToEncrypt := &protobuf.CommunityDescription{
Chats: map[string]*protobuf.CommunityChat{
channelID: proto.Clone(channel).(*protobuf.CommunityChat),
channelID: channel,
},
}
@ -42,8 +40,10 @@ func encryptDescription(encryptor DescriptionEncryptor, community *Community, de
if community.Encrypted() {
descriptionToEncrypt := &protobuf.CommunityDescription{
Members: description.Members,
Chats: description.Chats,
Members: description.Members,
ActiveMembersCount: description.ActiveMembersCount,
Chats: description.Chats,
Categories: description.Categories,
}
keyIDSeqNo, encryptedDescription, err := encryptor.encryptCommunityDescription(community, descriptionToEncrypt)
@ -51,10 +51,12 @@ func encryptDescription(encryptor DescriptionEncryptor, community *Community, de
return err
}
// Set private data and cleanup unencrypted members and chats
// Set private data and cleanup unencrypted members, chats and categories
description.PrivateData[keyIDSeqNo] = encryptedDescription
description.Members = make(map[string]*protobuf.CommunityMember)
description.ActiveMembersCount = 0
description.Chats = make(map[string]*protobuf.CommunityChat)
description.Categories = make(map[string]*protobuf.CommunityCategory)
}
return nil
@ -85,11 +87,12 @@ func decryptDescription(id types.HexBytes, encryptor DescriptionEncryptor, descr
}
decryptedDescription := decryptedDescriptionResponse.Description
for pk, member := range decryptedDescription.Members {
if description.Members == nil {
description.Members = make(map[string]*protobuf.CommunityMember)
}
description.Members[pk] = member
if len(decryptedDescription.Members) > 0 {
description.Members = decryptedDescription.Members
}
if decryptedDescription.ActiveMembersCount > 0 {
description.ActiveMembersCount = decryptedDescription.ActiveMembersCount
}
for id, decryptedChannel := range decryptedDescription.Chats {
@ -98,13 +101,17 @@ func decryptDescription(id types.HexBytes, encryptor DescriptionEncryptor, descr
}
if channel := description.Chats[id]; channel != nil {
if len(channel.Members) == 0 {
if len(decryptedChannel.Members) > 0 {
channel.Members = decryptedChannel.Members
}
} else {
description.Chats[id] = decryptedChannel
}
}
if len(decryptedDescription.Categories) > 0 {
description.Categories = decryptedDescription.Categories
}
}
return failedToDecrypt, nil

View File

@ -2,413 +2,262 @@ package communities
import (
"crypto/ecdsa"
"encoding/json"
"errors"
"time"
"fmt"
"github.com/golang/protobuf/proto"
utils "github.com/status-im/status-go/common"
"github.com/status-im/status-go/protocol/common"
"github.com/status-im/status-go/eth-node/crypto"
"github.com/status-im/status-go/protocol/protobuf"
)
var ErrInvalidCommunityEventClock = errors.New("clock for admin event message is outdated")
type CommunityEvent struct {
CommunityEventClock uint64 `json:"communityEventClock"`
Type protobuf.CommunityEvent_EventType `json:"type"`
CommunityConfig *protobuf.CommunityConfig `json:"communityConfig,omitempty"`
TokenPermission *protobuf.CommunityTokenPermission `json:"tokenPermissions,omitempty"`
CategoryData *protobuf.CategoryData `json:"categoryData,omitempty"`
ChannelData *protobuf.ChannelData `json:"channelData,omitempty"`
MemberToAction string `json:"memberToAction,omitempty"`
RequestToJoin *protobuf.CommunityRequestToJoin `json:"requestToJoin,omitempty"`
TokenMetadata *protobuf.CommunityTokenMetadata `json:"tokenMetadata,omitempty"`
Payload []byte `json:"payload"`
Signature []byte `json:"signature"`
}
func (o *Community) ToCreateChannelCommunityEvent(channelID string, channel *protobuf.CommunityChat) *CommunityEvent {
return &CommunityEvent{
CommunityEventClock: o.NewCommunityEventClock(),
Type: protobuf.CommunityEvent_COMMUNITY_CHANNEL_CREATE,
ChannelData: &protobuf.ChannelData{
ChannelId: channelID,
Channel: channel,
},
func (e *CommunityEvent) ToProtobuf() *protobuf.CommunityEvent {
var acceptedRequestsToJoin map[string]*protobuf.CommunityRequestToJoin
var rejectedRequestsToJoin map[string]*protobuf.CommunityRequestToJoin
switch e.Type {
case protobuf.CommunityEvent_COMMUNITY_REQUEST_TO_JOIN_ACCEPT:
acceptedRequestsToJoin = make(map[string]*protobuf.CommunityRequestToJoin)
acceptedRequestsToJoin[e.MemberToAction] = e.RequestToJoin
case protobuf.CommunityEvent_COMMUNITY_REQUEST_TO_JOIN_REJECT:
rejectedRequestsToJoin = make(map[string]*protobuf.CommunityRequestToJoin)
rejectedRequestsToJoin[e.MemberToAction] = e.RequestToJoin
}
return &protobuf.CommunityEvent{
CommunityEventClock: e.CommunityEventClock,
Type: e.Type,
CommunityConfig: e.CommunityConfig,
TokenPermission: e.TokenPermission,
CategoryData: e.CategoryData,
ChannelData: e.ChannelData,
MemberToAction: e.MemberToAction,
RejectedRequestsToJoin: rejectedRequestsToJoin,
AcceptedRequestsToJoin: acceptedRequestsToJoin,
TokenMetadata: e.TokenMetadata,
}
}
func (o *Community) ToEditChannelCommunityEvent(channelID string, channel *protobuf.CommunityChat) *CommunityEvent {
return &CommunityEvent{
CommunityEventClock: o.NewCommunityEventClock(),
Type: protobuf.CommunityEvent_COMMUNITY_CHANNEL_EDIT,
ChannelData: &protobuf.ChannelData{
ChannelId: channelID,
Channel: channel,
},
func communityEventFromProtobuf(msg *protobuf.SignedCommunityEvent) (*CommunityEvent, error) {
decodedEvent := protobuf.CommunityEvent{}
err := proto.Unmarshal(msg.Payload, &decodedEvent)
if err != nil {
return nil, err
}
memberToAction := decodedEvent.MemberToAction
var requestToJoin *protobuf.CommunityRequestToJoin
switch decodedEvent.Type {
case protobuf.CommunityEvent_COMMUNITY_REQUEST_TO_JOIN_ACCEPT:
for member, request := range decodedEvent.AcceptedRequestsToJoin {
memberToAction = member
requestToJoin = request
break
}
case protobuf.CommunityEvent_COMMUNITY_REQUEST_TO_JOIN_REJECT:
for member, request := range decodedEvent.RejectedRequestsToJoin {
memberToAction = member
requestToJoin = request
break
}
}
return &CommunityEvent{
CommunityEventClock: decodedEvent.CommunityEventClock,
Type: decodedEvent.Type,
CommunityConfig: decodedEvent.CommunityConfig,
TokenPermission: decodedEvent.TokenPermission,
CategoryData: decodedEvent.CategoryData,
ChannelData: decodedEvent.ChannelData,
MemberToAction: memberToAction,
RequestToJoin: requestToJoin,
TokenMetadata: decodedEvent.TokenMetadata,
Payload: msg.Payload,
Signature: msg.Signature,
}, nil
}
func (o *Community) ToDeleteChannelCommunityEvent(channelID string) *CommunityEvent {
return &CommunityEvent{
CommunityEventClock: o.NewCommunityEventClock(),
Type: protobuf.CommunityEvent_COMMUNITY_CHANNEL_DELETE,
ChannelData: &protobuf.ChannelData{
ChannelId: channelID,
},
func (e *CommunityEvent) RecoverSigner() (*ecdsa.PublicKey, error) {
if e.Signature == nil || len(e.Signature) == 0 {
return nil, errors.New("missing signature")
}
signer, err := crypto.SigToPub(
crypto.Keccak256(e.Payload),
e.Signature,
)
if err != nil {
return nil, errors.New("failed to recover signer")
}
return signer, nil
}
func (o *Community) ToReorderChannelCommunityEvent(categoryID string, channelID string, position int) *CommunityEvent {
return &CommunityEvent{
CommunityEventClock: o.NewCommunityEventClock(),
Type: protobuf.CommunityEvent_COMMUNITY_CHANNEL_REORDER,
ChannelData: &protobuf.ChannelData{
CategoryId: categoryID,
ChannelId: channelID,
Position: int32(position),
},
}
}
func (o *Community) ToCreateCategoryCommunityEvent(categoryID string, categoryName string, channelsIds []string) *CommunityEvent {
return &CommunityEvent{
CommunityEventClock: o.NewCommunityEventClock(),
Type: protobuf.CommunityEvent_COMMUNITY_CATEGORY_CREATE,
CategoryData: &protobuf.CategoryData{
Name: categoryName,
CategoryId: categoryID,
ChannelsIds: channelsIds,
},
}
}
func (o *Community) ToEditCategoryCommunityEvent(categoryID string, categoryName string, channelsIds []string) *CommunityEvent {
return &CommunityEvent{
CommunityEventClock: o.NewCommunityEventClock(),
Type: protobuf.CommunityEvent_COMMUNITY_CATEGORY_EDIT,
CategoryData: &protobuf.CategoryData{
Name: categoryName,
CategoryId: categoryID,
ChannelsIds: channelsIds,
},
}
}
func (o *Community) ToDeleteCategoryCommunityEvent(categoryID string) *CommunityEvent {
return &CommunityEvent{
CommunityEventClock: o.NewCommunityEventClock(),
Type: protobuf.CommunityEvent_COMMUNITY_CATEGORY_DELETE,
CategoryData: &protobuf.CategoryData{
CategoryId: categoryID,
},
}
}
func (o *Community) ToReorderCategoryCommunityEvent(categoryID string, position int) *CommunityEvent {
return &CommunityEvent{
CommunityEventClock: o.NewCommunityEventClock(),
Type: protobuf.CommunityEvent_COMMUNITY_CATEGORY_REORDER,
CategoryData: &protobuf.CategoryData{
CategoryId: categoryID,
Position: int32(position),
},
}
}
func (o *Community) ToBanCommunityMemberCommunityEvent(pubkey string) *CommunityEvent {
return &CommunityEvent{
CommunityEventClock: o.NewCommunityEventClock(),
Type: protobuf.CommunityEvent_COMMUNITY_MEMBER_BAN,
MemberToAction: pubkey,
}
}
func (o *Community) ToUnbanCommunityMemberCommunityEvent(pubkey string) *CommunityEvent {
return &CommunityEvent{
CommunityEventClock: o.NewCommunityEventClock(),
Type: protobuf.CommunityEvent_COMMUNITY_MEMBER_UNBAN,
MemberToAction: pubkey,
}
}
func (o *Community) ToKickCommunityMemberCommunityEvent(pubkey string) *CommunityEvent {
return &CommunityEvent{
CommunityEventClock: o.NewCommunityEventClock(),
Type: protobuf.CommunityEvent_COMMUNITY_MEMBER_KICK,
MemberToAction: pubkey,
}
}
func (o *Community) ToCommunityEditCommunityEvent(description *protobuf.CommunityDescription) *CommunityEvent {
return &CommunityEvent{
CommunityEventClock: o.NewCommunityEventClock(),
Type: protobuf.CommunityEvent_COMMUNITY_EDIT,
CommunityConfig: &protobuf.CommunityConfig{
Identity: description.Identity,
Permissions: description.Permissions,
AdminSettings: description.AdminSettings,
IntroMessage: description.IntroMessage,
OutroMessage: description.OutroMessage,
Tags: description.Tags,
},
}
}
func (o *Community) ToCommunityTokenPermissionChangeCommunityEvent(permission *protobuf.CommunityTokenPermission) *CommunityEvent {
return &CommunityEvent{
CommunityEventClock: o.NewCommunityEventClock(),
Type: protobuf.CommunityEvent_COMMUNITY_MEMBER_TOKEN_PERMISSION_CHANGE,
TokenPermission: permission,
}
}
func (o *Community) ToCommunityTokenPermissionDeleteCommunityEvent(permission *protobuf.CommunityTokenPermission) *CommunityEvent {
return &CommunityEvent{
CommunityEventClock: o.NewCommunityEventClock(),
Type: protobuf.CommunityEvent_COMMUNITY_MEMBER_TOKEN_PERMISSION_DELETE,
TokenPermission: permission,
}
}
func (o *Community) ToCommunityRequestToJoinAcceptCommunityEvent(changes *CommunityEventChanges) *CommunityEvent {
return &CommunityEvent{
CommunityEventClock: o.NewCommunityEventClock(),
Type: protobuf.CommunityEvent_COMMUNITY_REQUEST_TO_JOIN_ACCEPT,
AcceptedRequestsToJoin: changes.AcceptedRequestsToJoin,
}
}
func (o *Community) ToCommunityRequestToJoinRejectCommunityEvent(changes *CommunityEventChanges) *CommunityEvent {
return &CommunityEvent{
CommunityEventClock: o.NewCommunityEventClock(),
Type: protobuf.CommunityEvent_COMMUNITY_REQUEST_TO_JOIN_REJECT,
RejectedRequestsToJoin: changes.RejectedRequestsToJoin,
}
}
func (o *Community) ToAddTokenMetadataCommunityEvent(tokenMetadata *protobuf.CommunityTokenMetadata) *CommunityEvent {
return &CommunityEvent{
CommunityEventClock: o.NewCommunityEventClock(),
Type: protobuf.CommunityEvent_COMMUNITY_TOKEN_ADD,
TokenMetadata: tokenMetadata,
}
}
func (o *Community) UpdateCommunityByEvents(communityEventMessage *CommunityEventsMessage) error {
o.mutex.Lock()
defer o.mutex.Unlock()
// Validate that EventsBaseCommunityDescription was signed by the control node
description, err := validateAndGetEventsMessageCommunityDescription(communityEventMessage.EventsBaseCommunityDescription, o.ControlNode())
if err != nil {
return err
}
if description.Clock != o.config.CommunityDescription.Clock {
return ErrInvalidCommunityEventClock
}
// Merge community events to existing community. Community events must be stored to the db
// during saving the community
o.mergeCommunityEvents(communityEventMessage)
if o.encryptor != nil {
_, err = decryptDescription(o.ID(), o.encryptor, description, o.config.Logger)
if err != nil {
return err
}
}
o.config.CommunityDescription = description
o.config.CommunityDescriptionProtocolMessage = communityEventMessage.EventsBaseCommunityDescription
// Update the copy of the CommunityDescription by community events
err = o.updateCommunityDescriptionByEvents()
func (e *CommunityEvent) Sign(pk *ecdsa.PrivateKey) error {
sig, err := crypto.Sign(crypto.Keccak256(e.Payload), pk)
if err != nil {
return err
}
e.Signature = sig
return nil
}
func (o *Community) updateCommunityDescriptionByEvents() error {
if o.config.EventsData == nil {
return nil
}
for _, event := range o.config.EventsData.Events {
err := o.updateCommunityDescriptionByCommunityEvent(event)
if err != nil {
return err
}
}
return nil
}
func (o *Community) updateCommunityDescriptionByCommunityEvent(communityEvent CommunityEvent) error {
switch communityEvent.Type {
func (e *CommunityEvent) Validate() error {
switch e.Type {
case protobuf.CommunityEvent_COMMUNITY_EDIT:
o.config.CommunityDescription.Identity = communityEvent.CommunityConfig.Identity
o.config.CommunityDescription.Permissions = communityEvent.CommunityConfig.Permissions
o.config.CommunityDescription.AdminSettings = communityEvent.CommunityConfig.AdminSettings
o.config.CommunityDescription.IntroMessage = communityEvent.CommunityConfig.IntroMessage
o.config.CommunityDescription.OutroMessage = communityEvent.CommunityConfig.OutroMessage
o.config.CommunityDescription.Tags = communityEvent.CommunityConfig.Tags
if e.CommunityConfig == nil || e.CommunityConfig.Identity == nil ||
e.CommunityConfig.Permissions == nil || e.CommunityConfig.AdminSettings == nil {
return errors.New("invalid config change admin event")
}
case protobuf.CommunityEvent_COMMUNITY_MEMBER_TOKEN_PERMISSION_CHANGE:
if o.IsControlNode() {
_, err := o.upsertTokenPermission(communityEvent.TokenPermission)
if err != nil {
return err
}
if e.TokenPermission == nil || len(e.TokenPermission.Id) == 0 {
return errors.New("invalid token permission change event")
}
case protobuf.CommunityEvent_COMMUNITY_MEMBER_TOKEN_PERMISSION_DELETE:
if o.IsControlNode() {
_, err := o.deleteTokenPermission(communityEvent.TokenPermission.Id)
if err != nil {
return err
}
if e.TokenPermission == nil || len(e.TokenPermission.Id) == 0 {
return errors.New("invalid token permission delete event")
}
case protobuf.CommunityEvent_COMMUNITY_CATEGORY_CREATE:
_, err := o.createCategory(communityEvent.CategoryData.CategoryId, communityEvent.CategoryData.Name, communityEvent.CategoryData.ChannelsIds)
if err != nil {
return err
if e.CategoryData == nil || len(e.CategoryData.CategoryId) == 0 {
return errors.New("invalid community category create event")
}
case protobuf.CommunityEvent_COMMUNITY_CATEGORY_DELETE:
_, err := o.deleteCategory(communityEvent.CategoryData.CategoryId)
if err != nil {
return err
if e.CategoryData == nil || len(e.CategoryData.CategoryId) == 0 {
return errors.New("invalid community category delete event")
}
case protobuf.CommunityEvent_COMMUNITY_CATEGORY_EDIT:
_, err := o.editCategory(communityEvent.CategoryData.CategoryId, communityEvent.CategoryData.Name, communityEvent.CategoryData.ChannelsIds)
if err != nil {
return err
if e.CategoryData == nil || len(e.CategoryData.CategoryId) == 0 {
return errors.New("invalid community category edit event")
}
case protobuf.CommunityEvent_COMMUNITY_CHANNEL_CREATE:
err := o.createChat(communityEvent.ChannelData.ChannelId, communityEvent.ChannelData.Channel)
if err != nil {
return err
if e.ChannelData == nil || len(e.ChannelData.ChannelId) == 0 ||
e.ChannelData.Channel == nil {
return errors.New("invalid community channel create event")
}
case protobuf.CommunityEvent_COMMUNITY_CHANNEL_DELETE:
o.deleteChat(communityEvent.ChannelData.ChannelId)
if e.ChannelData == nil || len(e.ChannelData.ChannelId) == 0 {
return errors.New("invalid community channel delete event")
}
case protobuf.CommunityEvent_COMMUNITY_CHANNEL_EDIT:
err := o.editChat(communityEvent.ChannelData.ChannelId, communityEvent.ChannelData.Channel)
if err != nil {
return err
if e.ChannelData == nil || len(e.ChannelData.ChannelId) == 0 ||
e.ChannelData.Channel == nil {
return errors.New("invalid community channel edit event")
}
case protobuf.CommunityEvent_COMMUNITY_CHANNEL_REORDER:
_, err := o.reorderChat(communityEvent.ChannelData.CategoryId, communityEvent.ChannelData.ChannelId, int(communityEvent.ChannelData.Position))
if err != nil {
return err
if e.ChannelData == nil || len(e.ChannelData.ChannelId) == 0 {
return errors.New("invalid community channel reorder event")
}
case protobuf.CommunityEvent_COMMUNITY_CATEGORY_REORDER:
_, err := o.reorderCategories(communityEvent.CategoryData.CategoryId, int(communityEvent.CategoryData.Position))
if err != nil {
return err
if e.CategoryData == nil || len(e.CategoryData.CategoryId) == 0 {
return errors.New("invalid community category reorder event")
}
case protobuf.CommunityEvent_COMMUNITY_REQUEST_TO_JOIN_ACCEPT, protobuf.CommunityEvent_COMMUNITY_REQUEST_TO_JOIN_REJECT:
if len(e.MemberToAction) == 0 || e.RequestToJoin == nil {
return errors.New("invalid community request to join event")
}
case protobuf.CommunityEvent_COMMUNITY_MEMBER_KICK:
if o.IsControlNode() {
pk, err := common.HexToPubkey(communityEvent.MemberToAction)
if err != nil {
return err
}
o.removeMemberFromOrg(pk)
if len(e.MemberToAction) == 0 {
return errors.New("invalid community member kick event")
}
case protobuf.CommunityEvent_COMMUNITY_MEMBER_BAN:
if o.IsControlNode() {
pk, err := common.HexToPubkey(communityEvent.MemberToAction)
if err != nil {
return err
}
o.banUserFromCommunity(pk)
if len(e.MemberToAction) == 0 {
return errors.New("invalid community member ban event")
}
case protobuf.CommunityEvent_COMMUNITY_MEMBER_UNBAN:
if o.IsControlNode() {
pk, err := common.HexToPubkey(communityEvent.MemberToAction)
if err != nil {
return err
}
o.unbanUserFromCommunity(pk)
if len(e.MemberToAction) == 0 {
return errors.New("invalid community member unban event")
}
case protobuf.CommunityEvent_COMMUNITY_TOKEN_ADD:
o.config.CommunityDescription.CommunityTokensMetadata = append(o.config.CommunityDescription.CommunityTokensMetadata, communityEvent.TokenMetadata)
if e.TokenMetadata == nil || len(e.TokenMetadata.ContractAddresses) == 0 {
return errors.New("invalid add community token event")
}
case protobuf.CommunityEvent_COMMUNITY_DELETE_BANNED_MEMBER_MESSAGES:
if len(e.MemberToAction) == 0 {
return errors.New("invalid delete all community member messages event")
}
}
return nil
}
func (o *Community) NewCommunityEventClock() uint64 {
return uint64(time.Now().Unix())
// EventTypeID constructs a unique identifier for an event and its associated target.
func (e *CommunityEvent) EventTypeID() string {
switch e.Type {
case protobuf.CommunityEvent_COMMUNITY_EDIT:
return fmt.Sprintf("%d", e.Type)
case protobuf.CommunityEvent_COMMUNITY_MEMBER_TOKEN_PERMISSION_CHANGE,
protobuf.CommunityEvent_COMMUNITY_MEMBER_TOKEN_PERMISSION_DELETE:
return fmt.Sprintf("%d-%s", e.Type, e.TokenPermission.Id)
case protobuf.CommunityEvent_COMMUNITY_CATEGORY_CREATE,
protobuf.CommunityEvent_COMMUNITY_CATEGORY_DELETE,
protobuf.CommunityEvent_COMMUNITY_CATEGORY_EDIT,
protobuf.CommunityEvent_COMMUNITY_CATEGORY_REORDER:
return fmt.Sprintf("%d-%s", e.Type, e.CategoryData.CategoryId)
case protobuf.CommunityEvent_COMMUNITY_CHANNEL_CREATE,
protobuf.CommunityEvent_COMMUNITY_CHANNEL_DELETE,
protobuf.CommunityEvent_COMMUNITY_CHANNEL_EDIT,
protobuf.CommunityEvent_COMMUNITY_CHANNEL_REORDER:
return fmt.Sprintf("%d-%s", e.Type, e.ChannelData.ChannelId)
case protobuf.CommunityEvent_COMMUNITY_REQUEST_TO_JOIN_ACCEPT,
protobuf.CommunityEvent_COMMUNITY_REQUEST_TO_JOIN_REJECT,
protobuf.CommunityEvent_COMMUNITY_MEMBER_KICK,
protobuf.CommunityEvent_COMMUNITY_MEMBER_BAN,
protobuf.CommunityEvent_COMMUNITY_MEMBER_UNBAN,
protobuf.CommunityEvent_COMMUNITY_DELETE_BANNED_MEMBER_MESSAGES:
return fmt.Sprintf("%d-%s", e.Type, e.MemberToAction)
case protobuf.CommunityEvent_COMMUNITY_TOKEN_ADD:
return fmt.Sprintf("%d-%s", e.Type, e.TokenMetadata.Name)
}
return ""
}
func (o *Community) addNewCommunityEvent(event *CommunityEvent) error {
err := validateCommunityEvent(event)
if err != nil {
return err
}
// All events must be built on top of the control node CommunityDescription
// If there were no events before, extract CommunityDescription from CommunityDescriptionProtocolMessage
// and check the signature
if o.config.EventsData == nil || len(o.config.EventsData.EventsBaseCommunityDescription) == 0 {
_, err := validateAndGetEventsMessageCommunityDescription(o.config.CommunityDescriptionProtocolMessage, o.ControlNode())
if err != nil {
return err
}
o.config.EventsData = &EventsData{
EventsBaseCommunityDescription: o.config.CommunityDescriptionProtocolMessage,
Events: []CommunityEvent{},
}
}
event.Payload, err = proto.Marshal(event.ToProtobuf())
if err != nil {
return err
}
o.config.EventsData.Events = append(o.config.EventsData.Events, *event)
return nil
func communityEventsToJSONEncodedBytes(communityEvents []CommunityEvent) ([]byte, error) {
return json.Marshal(communityEvents)
}
func (o *Community) ToCommunityEventsMessage() *CommunityEventsMessage {
return &CommunityEventsMessage{
CommunityID: o.ID(),
EventsBaseCommunityDescription: o.config.EventsData.EventsBaseCommunityDescription,
Events: o.config.EventsData.Events,
}
}
func validateAndGetEventsMessageCommunityDescription(signedDescription []byte, signerPubkey *ecdsa.PublicKey) (*protobuf.CommunityDescription, error) {
metadata := &protobuf.ApplicationMetadataMessage{}
err := proto.Unmarshal(signedDescription, metadata)
func communityEventsFromJSONEncodedBytes(jsonEncodedRawEvents []byte) ([]CommunityEvent, error) {
var events []CommunityEvent
err := json.Unmarshal(jsonEncodedRawEvents, &events)
if err != nil {
return nil, err
}
if metadata.Type != protobuf.ApplicationMetadataMessage_COMMUNITY_DESCRIPTION {
return nil, ErrInvalidMessage
}
signer, err := utils.RecoverKey(metadata)
if err != nil {
return nil, err
}
if signer == nil {
return nil, errors.New("CommunityDescription does not contain the control node signature")
}
if !signer.Equal(signerPubkey) {
return nil, errors.New("CommunityDescription was not signed by an owner")
}
description := &protobuf.CommunityDescription{}
err = proto.Unmarshal(metadata.Payload, description)
if err != nil {
return nil, err
}
return description, nil
return events, nil
}

View File

@ -1,100 +1,11 @@
package communities
import (
"bytes"
"crypto/ecdsa"
"encoding/json"
"errors"
"sort"
"github.com/golang/protobuf/proto"
"github.com/status-im/status-go/eth-node/crypto"
"github.com/status-im/status-go/protocol/protobuf"
)
type CommunityEvent struct {
CommunityEventClock uint64 `json:"communityEventClock"`
Type protobuf.CommunityEvent_EventType `json:"type"`
CommunityConfig *protobuf.CommunityConfig `json:"communityConfig,omitempty"`
TokenPermission *protobuf.CommunityTokenPermission `json:"tokenPermissions,omitempty"`
CategoryData *protobuf.CategoryData `json:"categoryData,omitempty"`
ChannelData *protobuf.ChannelData `json:"channelData,omitempty"`
MemberToAction string `json:"memberToAction,omitempty"`
MembersAdded map[string]*protobuf.CommunityMember `json:"membersAdded,omitempty"`
RejectedRequestsToJoin map[string]*protobuf.CommunityRequestToJoin `json:"rejectedRequestsToJoin,omitempty"`
AcceptedRequestsToJoin map[string]*protobuf.CommunityRequestToJoin `json:"acceptedRequestsToJoin,omitempty"`
TokenMetadata *protobuf.CommunityTokenMetadata `json:"tokenMetadata,omitempty"`
Payload []byte `json:"payload"`
Signature []byte `json:"signature"`
}
func (e *CommunityEvent) ToProtobuf() *protobuf.CommunityEvent {
return &protobuf.CommunityEvent{
CommunityEventClock: e.CommunityEventClock,
Type: e.Type,
CommunityConfig: e.CommunityConfig,
TokenPermission: e.TokenPermission,
CategoryData: e.CategoryData,
ChannelData: e.ChannelData,
MemberToAction: e.MemberToAction,
MembersAdded: e.MembersAdded,
RejectedRequestsToJoin: e.RejectedRequestsToJoin,
AcceptedRequestsToJoin: e.AcceptedRequestsToJoin,
TokenMetadata: e.TokenMetadata,
}
}
func communityEventFromProtobuf(msg *protobuf.SignedCommunityEvent) (*CommunityEvent, error) {
decodedEvent := protobuf.CommunityEvent{}
err := proto.Unmarshal(msg.Payload, &decodedEvent)
if err != nil {
return nil, err
}
return &CommunityEvent{
CommunityEventClock: decodedEvent.CommunityEventClock,
Type: decodedEvent.Type,
CommunityConfig: decodedEvent.CommunityConfig,
TokenPermission: decodedEvent.TokenPermission,
CategoryData: decodedEvent.CategoryData,
ChannelData: decodedEvent.ChannelData,
MemberToAction: decodedEvent.MemberToAction,
MembersAdded: decodedEvent.MembersAdded,
RejectedRequestsToJoin: decodedEvent.RejectedRequestsToJoin,
AcceptedRequestsToJoin: decodedEvent.AcceptedRequestsToJoin,
TokenMetadata: decodedEvent.TokenMetadata,
Payload: msg.Payload,
Signature: msg.Signature,
}, nil
}
func (e *CommunityEvent) RecoverSigner() (*ecdsa.PublicKey, error) {
if e.Signature == nil || len(e.Signature) == 0 {
return nil, errors.New("missing signature")
}
signer, err := crypto.SigToPub(
crypto.Keccak256(e.Payload),
e.Signature,
)
if err != nil {
return nil, errors.New("failed to recover signer")
}
return signer, nil
}
func (e *CommunityEvent) Sign(pk *ecdsa.PrivateKey) error {
sig, err := crypto.Sign(crypto.Keccak256(e.Payload), pk)
if err != nil {
return err
}
e.Signature = sig
return nil
}
type CommunityEventsMessage struct {
CommunityID []byte `json:"communityId"`
EventsBaseCommunityDescription []byte `json:"eventsBaseCommunityDescription"`
@ -141,145 +52,3 @@ func (m *CommunityEventsMessage) Marshal() ([]byte, error) {
pb := m.ToProtobuf()
return proto.Marshal(pb)
}
func (c *Community) mergeCommunityEvents(communityEventMessage *CommunityEventsMessage) {
if c.config.EventsData == nil {
c.config.EventsData = &EventsData{
EventsBaseCommunityDescription: communityEventMessage.EventsBaseCommunityDescription,
Events: communityEventMessage.Events,
}
return
}
for _, update := range communityEventMessage.Events {
var exists bool
for _, existing := range c.config.EventsData.Events {
if isCommunityEventsEqual(update, existing) {
exists = true
break
}
}
if !exists {
c.config.EventsData.Events = append(c.config.EventsData.Events, update)
}
}
c.sortCommunityEvents()
}
func (c *Community) sortCommunityEvents() {
sort.Slice(c.config.EventsData.Events, func(i, j int) bool {
return c.config.EventsData.Events[i].CommunityEventClock < c.config.EventsData.Events[j].CommunityEventClock
})
}
func validateCommunityEvent(communityEvent *CommunityEvent) error {
switch communityEvent.Type {
case protobuf.CommunityEvent_COMMUNITY_EDIT:
if communityEvent.CommunityConfig == nil || communityEvent.CommunityConfig.Identity == nil ||
communityEvent.CommunityConfig.Permissions == nil || communityEvent.CommunityConfig.AdminSettings == nil {
return errors.New("invalid config change admin event")
}
case protobuf.CommunityEvent_COMMUNITY_MEMBER_TOKEN_PERMISSION_CHANGE:
if communityEvent.TokenPermission == nil || len(communityEvent.TokenPermission.Id) == 0 {
return errors.New("invalid token permission change event")
}
case protobuf.CommunityEvent_COMMUNITY_MEMBER_TOKEN_PERMISSION_DELETE:
if communityEvent.TokenPermission == nil || len(communityEvent.TokenPermission.Id) == 0 {
return errors.New("invalid token permission delete event")
}
case protobuf.CommunityEvent_COMMUNITY_CATEGORY_CREATE:
if communityEvent.CategoryData == nil || len(communityEvent.CategoryData.CategoryId) == 0 {
return errors.New("invalid community category create event")
}
case protobuf.CommunityEvent_COMMUNITY_CATEGORY_DELETE:
if communityEvent.CategoryData == nil || len(communityEvent.CategoryData.CategoryId) == 0 {
return errors.New("invalid community category delete event")
}
case protobuf.CommunityEvent_COMMUNITY_CATEGORY_EDIT:
if communityEvent.CategoryData == nil || len(communityEvent.CategoryData.CategoryId) == 0 {
return errors.New("invalid community category edit event")
}
case protobuf.CommunityEvent_COMMUNITY_CHANNEL_CREATE:
if communityEvent.ChannelData == nil || len(communityEvent.ChannelData.ChannelId) == 0 ||
communityEvent.ChannelData.Channel == nil {
return errors.New("invalid community channel create event")
}
case protobuf.CommunityEvent_COMMUNITY_CHANNEL_DELETE:
if communityEvent.ChannelData == nil || len(communityEvent.ChannelData.ChannelId) == 0 {
return errors.New("invalid community channel delete event")
}
case protobuf.CommunityEvent_COMMUNITY_CHANNEL_EDIT:
if communityEvent.ChannelData == nil || len(communityEvent.ChannelData.ChannelId) == 0 ||
communityEvent.ChannelData.Channel == nil {
return errors.New("invalid community channel edit event")
}
case protobuf.CommunityEvent_COMMUNITY_CHANNEL_REORDER:
if communityEvent.ChannelData == nil || len(communityEvent.ChannelData.ChannelId) == 0 {
return errors.New("invalid community channel reorder event")
}
case protobuf.CommunityEvent_COMMUNITY_CATEGORY_REORDER:
if communityEvent.CategoryData == nil || len(communityEvent.CategoryData.CategoryId) == 0 {
return errors.New("invalid community category reorder event")
}
case protobuf.CommunityEvent_COMMUNITY_REQUEST_TO_JOIN_ACCEPT:
if communityEvent.AcceptedRequestsToJoin == nil {
return errors.New("invalid community request to join accepted event")
}
case protobuf.CommunityEvent_COMMUNITY_REQUEST_TO_JOIN_REJECT:
if communityEvent.RejectedRequestsToJoin == nil {
return errors.New("invalid community request to join reject event")
}
case protobuf.CommunityEvent_COMMUNITY_MEMBER_KICK:
if len(communityEvent.MemberToAction) == 0 {
return errors.New("invalid community member kick event")
}
case protobuf.CommunityEvent_COMMUNITY_MEMBER_BAN:
if len(communityEvent.MemberToAction) == 0 {
return errors.New("invalid community member ban event")
}
case protobuf.CommunityEvent_COMMUNITY_MEMBER_UNBAN:
if len(communityEvent.MemberToAction) == 0 {
return errors.New("invalid community member unban event")
}
case protobuf.CommunityEvent_COMMUNITY_TOKEN_ADD:
if communityEvent.TokenMetadata == nil || len(communityEvent.TokenMetadata.ContractAddresses) == 0 {
return errors.New("invalid add community token event")
}
}
return nil
}
func isCommunityEventsEqual(left CommunityEvent, right CommunityEvent) bool {
return bytes.Equal(left.Payload, right.Payload)
}
func communityEventsToJSONEncodedBytes(communityEvents []CommunityEvent) ([]byte, error) {
return json.Marshal(communityEvents)
}
func communityEventsFromJSONEncodedBytes(jsonEncodedRawEvents []byte) ([]CommunityEvent, error) {
var events []CommunityEvent
err := json.Unmarshal(jsonEncodedRawEvents, &events)
if err != nil {
return nil, err
}
return events, nil
}

View File

@ -0,0 +1,207 @@
package communities
import "github.com/status-im/status-go/protocol/protobuf"
func (o *Community) ToCreateChannelCommunityEvent(channelID string, channel *protobuf.CommunityChat) *CommunityEvent {
return &CommunityEvent{
CommunityEventClock: o.nextEventClock(),
Type: protobuf.CommunityEvent_COMMUNITY_CHANNEL_CREATE,
ChannelData: &protobuf.ChannelData{
ChannelId: channelID,
Channel: channel,
},
}
}
func (o *Community) ToEditChannelCommunityEvent(channelID string, channel *protobuf.CommunityChat) *CommunityEvent {
return &CommunityEvent{
CommunityEventClock: o.nextEventClock(),
Type: protobuf.CommunityEvent_COMMUNITY_CHANNEL_EDIT,
ChannelData: &protobuf.ChannelData{
ChannelId: channelID,
Channel: channel,
},
}
}
func (o *Community) ToDeleteChannelCommunityEvent(channelID string) *CommunityEvent {
return &CommunityEvent{
CommunityEventClock: o.nextEventClock(),
Type: protobuf.CommunityEvent_COMMUNITY_CHANNEL_DELETE,
ChannelData: &protobuf.ChannelData{
ChannelId: channelID,
},
}
}
func (o *Community) ToReorderChannelCommunityEvent(categoryID string, channelID string, position int) *CommunityEvent {
return &CommunityEvent{
CommunityEventClock: o.nextEventClock(),
Type: protobuf.CommunityEvent_COMMUNITY_CHANNEL_REORDER,
ChannelData: &protobuf.ChannelData{
CategoryId: categoryID,
ChannelId: channelID,
Position: int32(position),
},
}
}
func (o *Community) ToCreateCategoryCommunityEvent(categoryID string, categoryName string, channelsIds []string) *CommunityEvent {
return &CommunityEvent{
CommunityEventClock: o.nextEventClock(),
Type: protobuf.CommunityEvent_COMMUNITY_CATEGORY_CREATE,
CategoryData: &protobuf.CategoryData{
Name: categoryName,
CategoryId: categoryID,
ChannelsIds: channelsIds,
},
}
}
func (o *Community) ToEditCategoryCommunityEvent(categoryID string, categoryName string, channelsIds []string) *CommunityEvent {
return &CommunityEvent{
CommunityEventClock: o.nextEventClock(),
Type: protobuf.CommunityEvent_COMMUNITY_CATEGORY_EDIT,
CategoryData: &protobuf.CategoryData{
Name: categoryName,
CategoryId: categoryID,
ChannelsIds: channelsIds,
},
}
}
func (o *Community) ToDeleteCategoryCommunityEvent(categoryID string) *CommunityEvent {
return &CommunityEvent{
CommunityEventClock: o.nextEventClock(),
Type: protobuf.CommunityEvent_COMMUNITY_CATEGORY_DELETE,
CategoryData: &protobuf.CategoryData{
CategoryId: categoryID,
},
}
}
func (o *Community) ToReorderCategoryCommunityEvent(categoryID string, position int) *CommunityEvent {
return &CommunityEvent{
CommunityEventClock: o.nextEventClock(),
Type: protobuf.CommunityEvent_COMMUNITY_CATEGORY_REORDER,
CategoryData: &protobuf.CategoryData{
CategoryId: categoryID,
Position: int32(position),
},
}
}
func (o *Community) ToBanCommunityMemberCommunityEvent(pubkey string) *CommunityEvent {
return &CommunityEvent{
CommunityEventClock: o.nextEventClock(),
Type: protobuf.CommunityEvent_COMMUNITY_MEMBER_BAN,
MemberToAction: pubkey,
}
}
func (o *Community) ToDeleteAllMemberMessagesEvent(pubkey string) *CommunityEvent {
return &CommunityEvent{
CommunityEventClock: o.nextEventClock(),
Type: protobuf.CommunityEvent_COMMUNITY_DELETE_BANNED_MEMBER_MESSAGES,
MemberToAction: pubkey,
}
}
func (o *Community) ToUnbanCommunityMemberCommunityEvent(pubkey string) *CommunityEvent {
return &CommunityEvent{
CommunityEventClock: o.nextEventClock(),
Type: protobuf.CommunityEvent_COMMUNITY_MEMBER_UNBAN,
MemberToAction: pubkey,
}
}
func (o *Community) ToKickCommunityMemberCommunityEvent(pubkey string) *CommunityEvent {
return &CommunityEvent{
CommunityEventClock: o.nextEventClock(),
Type: protobuf.CommunityEvent_COMMUNITY_MEMBER_KICK,
MemberToAction: pubkey,
}
}
func (o *Community) ToCommunityEditCommunityEvent(description *protobuf.CommunityDescription) *CommunityEvent {
return &CommunityEvent{
CommunityEventClock: o.nextEventClock(),
Type: protobuf.CommunityEvent_COMMUNITY_EDIT,
CommunityConfig: &protobuf.CommunityConfig{
Identity: description.Identity,
Permissions: description.Permissions,
AdminSettings: description.AdminSettings,
IntroMessage: description.IntroMessage,
OutroMessage: description.OutroMessage,
Tags: description.Tags,
},
}
}
func (o *Community) ToCommunityTokenPermissionChangeCommunityEvent(permission *protobuf.CommunityTokenPermission) *CommunityEvent {
return &CommunityEvent{
CommunityEventClock: o.nextEventClock(),
Type: protobuf.CommunityEvent_COMMUNITY_MEMBER_TOKEN_PERMISSION_CHANGE,
TokenPermission: permission,
}
}
func (o *Community) ToCommunityTokenPermissionDeleteCommunityEvent(permission *protobuf.CommunityTokenPermission) *CommunityEvent {
return &CommunityEvent{
CommunityEventClock: o.nextEventClock(),
Type: protobuf.CommunityEvent_COMMUNITY_MEMBER_TOKEN_PERMISSION_DELETE,
TokenPermission: permission,
}
}
func (o *Community) ToCommunityRequestToJoinAcceptCommunityEvent(member string, request *protobuf.CommunityRequestToJoin) *CommunityEvent {
return &CommunityEvent{
CommunityEventClock: o.nextEventClock(),
Type: protobuf.CommunityEvent_COMMUNITY_REQUEST_TO_JOIN_ACCEPT,
MemberToAction: member,
RequestToJoin: request,
}
}
func (o *Community) ToCommunityRequestToJoinRejectCommunityEvent(member string, request *protobuf.CommunityRequestToJoin) *CommunityEvent {
return &CommunityEvent{
CommunityEventClock: o.nextEventClock(),
Type: protobuf.CommunityEvent_COMMUNITY_REQUEST_TO_JOIN_REJECT,
MemberToAction: member,
RequestToJoin: request,
}
}
func (o *Community) ToAddTokenMetadataCommunityEvent(tokenMetadata *protobuf.CommunityTokenMetadata) *CommunityEvent {
return &CommunityEvent{
CommunityEventClock: o.nextEventClock(),
Type: protobuf.CommunityEvent_COMMUNITY_TOKEN_ADD,
TokenMetadata: tokenMetadata,
}
}
func (o *Community) nextEventClock() uint64 {
latestEventClock := uint64(0)
if o.config.EventsData != nil {
for _, event := range o.config.EventsData.Events {
if event.CommunityEventClock > latestEventClock {
latestEventClock = event.CommunityEventClock
}
}
}
clock := o.config.CommunityDescription.Clock
if latestEventClock > clock {
clock = latestEventClock
}
// lamport timestamp
timestamp := o.timesource.GetCurrentTime()
if clock == 0 || clock < timestamp {
clock = timestamp
} else {
clock = clock + 1
}
return clock
}

View File

@ -0,0 +1,354 @@
package communities
import (
"crypto/ecdsa"
"errors"
"sort"
"github.com/golang/protobuf/proto"
"go.uber.org/zap"
utils "github.com/status-im/status-go/common"
"github.com/status-im/status-go/protocol/common"
"github.com/status-im/status-go/protocol/protobuf"
)
var ErrInvalidCommunityEventClock = errors.New("clock for admin event message is outdated")
func (o *Community) processEvents(message *CommunityEventsMessage, lastlyAppliedEvents map[string]uint64) error {
processor := &eventsProcessor{
community: o,
message: message,
logger: o.config.Logger.Named("eventsProcessor"),
lastlyAppliedEvents: lastlyAppliedEvents,
}
return processor.exec()
}
type eventsProcessor struct {
community *Community
message *CommunityEventsMessage
logger *zap.Logger
lastlyAppliedEvents map[string]uint64
eventsToApply []CommunityEvent
}
func (e *eventsProcessor) exec() error {
e.community.mutex.Lock()
defer e.community.mutex.Unlock()
err := e.validateDescription()
if err != nil {
return err
}
e.filterEvents()
e.mergeEvents()
e.retainNewestEventsPerEventTypeID()
e.sortEvents()
e.applyEvents()
return nil
}
func (e *eventsProcessor) validateDescription() error {
description, err := validateAndGetEventsMessageCommunityDescription(e.message.EventsBaseCommunityDescription, e.community.ControlNode())
if err != nil {
return err
}
// Control node is the only entity that can apply events from past description.
// In this case, events are compared against the clocks of the most recently applied events.
if e.community.IsControlNode() && description.Clock < e.community.config.CommunityDescription.Clock {
return nil
}
if description.Clock != e.community.config.CommunityDescription.Clock {
return ErrInvalidCommunityEventClock
}
return nil
}
func (e *eventsProcessor) validateEvent(event *CommunityEvent) error {
if e.lastlyAppliedEvents != nil {
if clock, found := e.lastlyAppliedEvents[event.EventTypeID()]; found && clock >= event.CommunityEventClock {
return errors.New("event outdated")
}
}
signer, err := event.RecoverSigner()
if err != nil {
return err
}
return e.community.validateEvent(event, signer)
}
// Filter invalid and outdated events.
func (e *eventsProcessor) filterEvents() {
for _, ev := range e.message.Events {
event := ev
if err := e.validateEvent(&event); err == nil {
e.eventsToApply = append(e.eventsToApply, event)
} else {
e.logger.Warn("invalid community event", zap.String("EventTypeID", event.EventTypeID()), zap.Uint64("clock", event.CommunityEventClock), zap.Error(err))
}
}
}
// Merge message's events with community's events.
func (e *eventsProcessor) mergeEvents() {
if e.community.config.EventsData != nil {
for _, ev := range e.community.config.EventsData.Events {
event := ev
if err := e.validateEvent(&event); err == nil {
e.eventsToApply = append(e.eventsToApply, event)
} else {
// NOTE: this should not happen, events should be validated before they are saved in the db.
// It has been identified that an invalid event is saved to the database for some reason.
// The code flow leading to this behavior is not yet known.
// https://github.com/status-im/status-desktop/issues/14106
e.logger.Error("invalid community event read from db", zap.String("EventTypeID", event.EventTypeID()), zap.Uint64("clock", event.CommunityEventClock), zap.Error(err))
}
}
}
}
// Keep only the newest event per PropertyTypeID.
func (e *eventsProcessor) retainNewestEventsPerEventTypeID() {
eventsMap := make(map[string]CommunityEvent)
for _, event := range e.eventsToApply {
if existingEvent, found := eventsMap[event.EventTypeID()]; !found || event.CommunityEventClock > existingEvent.CommunityEventClock {
eventsMap[event.EventTypeID()] = event
}
}
e.eventsToApply = []CommunityEvent{}
for _, event := range eventsMap {
e.eventsToApply = append(e.eventsToApply, event)
}
}
// Sorts events by clock.
func (e *eventsProcessor) sortEvents() {
sort.Slice(e.eventsToApply, func(i, j int) bool {
if e.eventsToApply[i].CommunityEventClock == e.eventsToApply[j].CommunityEventClock {
return e.eventsToApply[i].Type < e.eventsToApply[j].Type
}
return e.eventsToApply[i].CommunityEventClock < e.eventsToApply[j].CommunityEventClock
})
}
func (e *eventsProcessor) applyEvents() {
if e.community.config.EventsData == nil {
e.community.config.EventsData = &EventsData{
EventsBaseCommunityDescription: e.message.EventsBaseCommunityDescription,
}
}
e.community.config.EventsData.Events = e.eventsToApply
e.community.applyEvents()
}
func (o *Community) applyEvents() {
if o.config.EventsData == nil {
return
}
for _, event := range o.config.EventsData.Events {
err := o.applyEvent(event)
if err != nil {
o.config.Logger.Warn("failed to apply event", zap.String("EventTypeID", event.EventTypeID()), zap.Uint64("clock", event.CommunityEventClock), zap.Error(err))
}
}
}
func (o *Community) applyEvent(communityEvent CommunityEvent) error {
switch communityEvent.Type {
case protobuf.CommunityEvent_COMMUNITY_EDIT:
o.config.CommunityDescription.Identity = communityEvent.CommunityConfig.Identity
o.config.CommunityDescription.Permissions = communityEvent.CommunityConfig.Permissions
o.config.CommunityDescription.AdminSettings = communityEvent.CommunityConfig.AdminSettings
o.config.CommunityDescription.IntroMessage = communityEvent.CommunityConfig.IntroMessage
o.config.CommunityDescription.OutroMessage = communityEvent.CommunityConfig.OutroMessage
o.config.CommunityDescription.Tags = communityEvent.CommunityConfig.Tags
case protobuf.CommunityEvent_COMMUNITY_MEMBER_TOKEN_PERMISSION_CHANGE:
if o.IsControlNode() {
_, err := o.upsertTokenPermission(communityEvent.TokenPermission)
if err != nil {
return err
}
}
case protobuf.CommunityEvent_COMMUNITY_MEMBER_TOKEN_PERMISSION_DELETE:
if o.IsControlNode() {
_, err := o.deleteTokenPermission(communityEvent.TokenPermission.Id)
if err != nil {
return err
}
}
case protobuf.CommunityEvent_COMMUNITY_CATEGORY_CREATE:
_, err := o.createCategory(communityEvent.CategoryData.CategoryId, communityEvent.CategoryData.Name, communityEvent.CategoryData.ChannelsIds)
if err != nil {
return err
}
case protobuf.CommunityEvent_COMMUNITY_CATEGORY_DELETE:
_, err := o.deleteCategory(communityEvent.CategoryData.CategoryId)
if err != nil {
return err
}
case protobuf.CommunityEvent_COMMUNITY_CATEGORY_EDIT:
_, err := o.editCategory(communityEvent.CategoryData.CategoryId, communityEvent.CategoryData.Name, communityEvent.CategoryData.ChannelsIds)
if err != nil {
return err
}
case protobuf.CommunityEvent_COMMUNITY_CHANNEL_CREATE:
err := o.createChat(communityEvent.ChannelData.ChannelId, communityEvent.ChannelData.Channel)
if err != nil {
return err
}
case protobuf.CommunityEvent_COMMUNITY_CHANNEL_DELETE:
o.deleteChat(communityEvent.ChannelData.ChannelId)
case protobuf.CommunityEvent_COMMUNITY_CHANNEL_EDIT:
err := o.editChat(communityEvent.ChannelData.ChannelId, communityEvent.ChannelData.Channel)
if err != nil {
return err
}
case protobuf.CommunityEvent_COMMUNITY_CHANNEL_REORDER:
_, err := o.reorderChat(communityEvent.ChannelData.CategoryId, communityEvent.ChannelData.ChannelId, int(communityEvent.ChannelData.Position))
if err != nil {
return err
}
case protobuf.CommunityEvent_COMMUNITY_CATEGORY_REORDER:
_, err := o.reorderCategories(communityEvent.CategoryData.CategoryId, int(communityEvent.CategoryData.Position))
if err != nil {
return err
}
case protobuf.CommunityEvent_COMMUNITY_MEMBER_KICK:
if o.IsControlNode() {
pk, err := common.HexToPubkey(communityEvent.MemberToAction)
if err != nil {
return err
}
o.removeMemberFromOrg(pk)
}
case protobuf.CommunityEvent_COMMUNITY_MEMBER_BAN:
if o.IsControlNode() {
pk, err := common.HexToPubkey(communityEvent.MemberToAction)
if err != nil {
return err
}
o.banUserFromCommunity(pk, &protobuf.CommunityBanInfo{DeleteAllMessages: false})
}
case protobuf.CommunityEvent_COMMUNITY_MEMBER_UNBAN:
if o.IsControlNode() {
pk, err := common.HexToPubkey(communityEvent.MemberToAction)
if err != nil {
return err
}
o.unbanUserFromCommunity(pk)
}
case protobuf.CommunityEvent_COMMUNITY_TOKEN_ADD:
o.config.CommunityDescription.CommunityTokensMetadata = append(o.config.CommunityDescription.CommunityTokensMetadata, communityEvent.TokenMetadata)
case protobuf.CommunityEvent_COMMUNITY_DELETE_BANNED_MEMBER_MESSAGES:
if o.IsControlNode() {
pk, err := common.HexToPubkey(communityEvent.MemberToAction)
if err != nil {
return err
}
err = o.deleteBannedMemberAllMessages(pk)
if err != nil {
return err
}
}
}
return nil
}
func (o *Community) addNewCommunityEvent(event *CommunityEvent) error {
err := event.Validate()
if err != nil {
return err
}
// All events must be built on top of the control node CommunityDescription
// If there were no events before, extract CommunityDescription from CommunityDescriptionProtocolMessage
// and check the signature
if o.config.EventsData == nil || len(o.config.EventsData.EventsBaseCommunityDescription) == 0 {
_, err := validateAndGetEventsMessageCommunityDescription(o.config.CommunityDescriptionProtocolMessage, o.ControlNode())
if err != nil {
return err
}
o.config.EventsData = &EventsData{
EventsBaseCommunityDescription: o.config.CommunityDescriptionProtocolMessage,
Events: []CommunityEvent{},
}
}
event.Payload, err = proto.Marshal(event.ToProtobuf())
if err != nil {
return err
}
o.config.EventsData.Events = append(o.config.EventsData.Events, *event)
return nil
}
func (o *Community) toCommunityEventsMessage() *CommunityEventsMessage {
return &CommunityEventsMessage{
CommunityID: o.ID(),
EventsBaseCommunityDescription: o.config.EventsData.EventsBaseCommunityDescription,
Events: o.config.EventsData.Events,
}
}
func validateAndGetEventsMessageCommunityDescription(signedDescription []byte, signerPubkey *ecdsa.PublicKey) (*protobuf.CommunityDescription, error) {
metadata := &protobuf.ApplicationMetadataMessage{}
err := proto.Unmarshal(signedDescription, metadata)
if err != nil {
return nil, err
}
if metadata.Type != protobuf.ApplicationMetadataMessage_COMMUNITY_DESCRIPTION {
return nil, ErrInvalidMessage
}
signer, err := utils.RecoverKey(metadata)
if err != nil {
return nil, err
}
if signer == nil {
return nil, errors.New("CommunityDescription does not contain the control node signature")
}
if !signer.Equal(signerPubkey) {
return nil, errors.New("CommunityDescription was not signed by an owner")
}
description := &protobuf.CommunityDescription{}
err = proto.Unmarshal(metadata.Payload, description)
if err != nil {
return nil, err
}
return description, nil
}

View File

@ -45,3 +45,4 @@ var ErrRevealedAccountsAbsent = errors.New("revealed accounts is absent")
var ErrNoRevealedAccountsSignature = errors.New("revealed accounts without the signature")
var ErrNoFreeSpaceForHistoryArchives = errors.New("history archive: No free space for downloading history archives")
var ErrPermissionToJoinNotSatisfied = errors.New("permission to join not satisfied")
var ErrBannedMemberNotFound = errors.New("banned member not found")

File diff suppressed because it is too large Load Diff

View File

@ -3,9 +3,8 @@ package communities
import (
"context"
"errors"
"math"
"fmt"
"math/big"
"strconv"
"strings"
"go.uber.org/zap"
@ -330,7 +329,7 @@ func (p *DefaultPermissionChecker) CheckPermissions(permissions []*CommunityToke
continue
}
accumulatedBalance := new(big.Float)
accumulatedBalance := new(big.Int)
chainIDLoopERC20:
for chainID, address := range tokenRequirement.ContractAddresses {
@ -345,16 +344,11 @@ func (p *DefaultPermissionChecker) CheckPermissions(permissions []*CommunityToke
value := ownedERC20TokenBalances[chainID][account][contractAddress]
accountChainBalance := new(big.Float).Quo(
new(big.Float).SetInt(value.ToInt()),
big.NewFloat(math.Pow(10, float64(tokenRequirement.Decimals))),
)
if _, exists := accountsChainIDsCombinations[account]; !exists {
accountsChainIDsCombinations[account] = make(map[uint64]bool)
}
if accountChainBalance.Cmp(big.NewFloat(0)) > 0 {
if value.ToInt().Cmp(big.NewInt(0)) > 0 {
// account has balance > 0 on this chain for this token, so let's add it the chain IDs
accountsChainIDsCombinations[account][chainID] = true
}
@ -362,14 +356,14 @@ func (p *DefaultPermissionChecker) CheckPermissions(permissions []*CommunityToke
// check if adding current chain account balance to accumulated balance
// satisfies required amount
prevBalance := accumulatedBalance
accumulatedBalance.Add(prevBalance, accountChainBalance)
accumulatedBalance.Add(prevBalance, value.ToInt())
requiredAmount, err := strconv.ParseFloat(tokenRequirement.Amount, 32)
if err != nil {
return nil, err
requiredAmount, success := new(big.Int).SetString(tokenRequirement.AmountInWei, 10)
if !success {
return nil, fmt.Errorf("amountInWeis value is incorrect")
}
if accumulatedBalance.Cmp(big.NewFloat(requiredAmount)) != -1 {
if accumulatedBalance.Cmp(requiredAmount) != -1 {
tokenRequirementMet = true
if shortcircuit {
break chainIDLoopERC20

View File

@ -18,6 +18,7 @@ import (
"github.com/status-im/status-go/protocol/common"
"github.com/status-im/status-go/protocol/common/shard"
"github.com/status-im/status-go/protocol/communities/token"
"github.com/status-im/status-go/protocol/encryption"
"github.com/status-im/status-go/protocol/protobuf"
"github.com/status-im/status-go/services/wallet/bigint"
)
@ -591,6 +592,9 @@ func (p *Persistence) GetPermissionTokenCriteriaResult(permissionID string, comm
criteria := make([]bool, 0)
for _, r := range strings.Split(criteriaString, ",") {
if r == "" {
continue
}
val, err := strconv.ParseBool(r)
if err != nil {
return nil, err
@ -838,6 +842,15 @@ func (p *Persistence) GetRequestToJoin(id []byte) (*RequestToJoin, error) {
return request, nil
}
func (p *Persistence) GetNumberOfPendingRequestsToJoin(communityID types.HexBytes) (int, error) {
var count int
err := p.db.QueryRow(`SELECT count(1) FROM communities_requests_to_join WHERE community_id = ? AND state = ?`, communityID, RequestToJoinStatePending).Scan(&count)
if err != nil {
return 0, err
}
return count, nil
}
func (p *Persistence) GetRequestToJoinByPkAndCommunityID(pk string, communityID []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 public_key = ? AND community_id = ?`, pk, communityID).Scan(&request.ID, &request.PublicKey, &request.Clock, &request.ENSName, &request.ChatID, &request.CommunityID, &request.State)
@ -1326,6 +1339,31 @@ func (p *Persistence) RemoveCommunityToken(chainID int, contractAddress string)
return err
}
func (p *Persistence) GetCommunityGrant(communityID string) ([]byte, uint64, error) {
var grant []byte
var clock uint64
err := p.db.QueryRow(`SELECT grant, clock FROM community_grants WHERE community_id = ?`, communityID).Scan(&grant, &clock)
if err == sql.ErrNoRows {
return []byte{}, 0, nil
} else if err != nil {
return []byte{}, 0, err
}
return grant, clock, nil
}
func (p *Persistence) SaveCommunityGrant(communityID string, grant []byte, clock uint64) error {
_, err := p.db.Exec(`INSERT OR REPLACE INTO community_grants(community_id, grant, clock) VALUES (?, ?, ?)`,
communityID, grant, clock)
return err
}
func (p *Persistence) RemoveCommunityGrant(communityID string) error {
_, err := p.db.Exec(`DELETE FROM community_grants WHERE community_id = ?`, communityID)
return err
}
func decodeWrappedCommunityDescription(wrappedDescriptionBytes []byte) (*protobuf.CommunityDescription, error) {
metadata := &protobuf.ApplicationMetadataMessage{}
@ -1781,3 +1819,216 @@ func (p *Persistence) DeleteCommunityShard(communityID types.HexBytes) error {
_, err := p.db.Exec(`DELETE FROM communities_shards WHERE community_id = ?`, communityID)
return err
}
func (p *Persistence) GetAppliedCommunityEvents(communityID types.HexBytes) (map[string]uint64, error) {
rows, err := p.db.Query(`SELECT event_type_id, clock FROM applied_community_events WHERE community_id = ?`, communityID.String())
if err != nil {
return nil, err
}
defer rows.Close()
result := map[string]uint64{}
eventTypeID := ""
clock := uint64(0)
for rows.Next() {
err := rows.Scan(&eventTypeID, &clock)
if err != nil {
return nil, err
}
result[eventTypeID] = clock
}
return result, nil
}
func (p *Persistence) UpsertAppliedCommunityEvents(communityID types.HexBytes, processedEvents map[string]uint64) 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()
}()
for eventTypeID, newClock := range processedEvents {
var currentClock uint64
err = tx.QueryRow(`
SELECT clock
FROM applied_community_events
WHERE community_id = ? AND event_type_id = ?`,
communityID.String(), eventTypeID).Scan(&currentClock)
if err != nil && err != sql.ErrNoRows {
return err
}
if newClock > currentClock {
_, err = tx.Exec(`
INSERT OR REPLACE INTO applied_community_events(community_id, event_type_id, clock)
VALUES (?, ?, ?)`,
communityID.String(), eventTypeID, newClock)
if err != nil {
return err
}
}
}
return err
}
func (p *Persistence) InvalidateDecryptedCommunityCacheForKeys(keys []*encryption.HashRatchetInfo) 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()
}()
if len(keys) == 0 {
return nil
}
idsArgs := make([]interface{}, 0, len(keys))
for _, k := range keys {
idsArgs = append(idsArgs, k.KeyID)
}
inVector := strings.Repeat("?, ", len(keys)-1) + "?"
query := "SELECT DISTINCT(community_id) FROM encrypted_community_description_missing_keys WHERE key_id IN (" + inVector + ")" // nolint: gosec
var communityIDs []interface{}
rows, err := tx.Query(query, idsArgs...)
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
var communityID []byte
err = rows.Scan(&communityID)
if err != nil {
return err
}
communityIDs = append(communityIDs, communityID)
}
if len(communityIDs) == 0 {
return nil
}
inVector = strings.Repeat("?, ", len(communityIDs)-1) + "?"
query = "DELETE FROM encrypted_community_description_cache WHERE community_id IN (" + inVector + ")" //nolint: gosec
_, err = tx.Exec(query, communityIDs...)
return err
}
func (p *Persistence) SaveDecryptedCommunityDescription(communityID []byte, missingKeys []*CommunityPrivateDataFailedToDecrypt, description *protobuf.CommunityDescription) error {
if description == nil {
return nil
}
marshaledDescription, err := proto.Marshal(description)
if err != nil {
return err
}
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()
}()
previousCommunity, err := p.getDecryptedCommunityDescriptionByID(tx, communityID)
if err != nil {
return err
}
if previousCommunity != nil && previousCommunity.Clock >= description.Clock {
return nil
}
insertCommunity := "INSERT INTO encrypted_community_description_cache (community_id, clock, description) VALUES (?, ?, ?);"
_, err = tx.Exec(insertCommunity, communityID, description.Clock, marshaledDescription)
if err != nil {
return err
}
for _, key := range missingKeys {
insertKey := "INSERT INTO encrypted_community_description_missing_keys (community_id, key_id) VALUES(?, ?)"
_, err = tx.Exec(insertKey, communityID, key.KeyID)
if err != nil {
return err
}
}
return nil
}
func (p *Persistence) GetDecryptedCommunityDescription(communityID []byte, clock uint64) (*protobuf.CommunityDescription, error) {
return p.getDecryptedCommunityDescriptionByIDAndClock(communityID, clock)
}
func (p *Persistence) getDecryptedCommunityDescriptionByIDAndClock(communityID []byte, clock uint64) (*protobuf.CommunityDescription, error) {
query := "SELECT description FROM encrypted_community_description_cache WHERE community_id = ? AND clock = ?"
qr := p.db.QueryRow(query, communityID, clock)
var descriptionBytes []byte
err := qr.Scan(&descriptionBytes)
switch err {
case sql.ErrNoRows:
return nil, nil
case nil:
var communityDescription protobuf.CommunityDescription
err := proto.Unmarshal(descriptionBytes, &communityDescription)
if err != nil {
return nil, err
}
return &communityDescription, nil
default:
return nil, err
}
}
func (p *Persistence) getDecryptedCommunityDescriptionByID(tx *sql.Tx, communityID []byte) (*protobuf.CommunityDescription, error) {
query := "SELECT description FROM encrypted_community_description_cache WHERE community_id = ?"
qr := tx.QueryRow(query, communityID)
var descriptionBytes []byte
err := qr.Scan(&descriptionBytes)
switch err {
case sql.ErrNoRows:
return nil, nil
case nil:
var communityDescription protobuf.CommunityDescription
err := proto.Unmarshal(descriptionBytes, &communityDescription)
if err != nil {
return nil, err
}
return &communityDescription, nil
default:
return nil, err
}
}

View File

@ -23,6 +23,7 @@ var adminAuthorizedEventTypes = []protobuf.CommunityEvent_EventType{
protobuf.CommunityEvent_COMMUNITY_MEMBER_KICK,
protobuf.CommunityEvent_COMMUNITY_MEMBER_BAN,
protobuf.CommunityEvent_COMMUNITY_MEMBER_UNBAN,
protobuf.CommunityEvent_COMMUNITY_DELETE_BANNED_MEMBER_MESSAGES,
}
var tokenMasterAuthorizedEventTypes = append(adminAuthorizedEventTypes, []protobuf.CommunityEvent_EventType{
@ -112,7 +113,9 @@ func RolesAuthorizedToPerformEvent(senderRoles []protobuf.CommunityMember_Roles,
}
if event.Type == protobuf.CommunityEvent_COMMUNITY_MEMBER_BAN ||
event.Type == protobuf.CommunityEvent_COMMUNITY_MEMBER_KICK {
event.Type == protobuf.CommunityEvent_COMMUNITY_MEMBER_KICK ||
event.Type == protobuf.CommunityEvent_COMMUNITY_MEMBER_UNBAN ||
event.Type == protobuf.CommunityEvent_COMMUNITY_DELETE_BANNED_MEMBER_MESSAGES {
return canRolesKickOrBanMember(senderRoles, memberRoles)
}

View File

@ -109,6 +109,7 @@ type Contact struct {
// Bio - description of the contact (tell us about yourself)
Bio string `json:"bio"`
// Deprecated: use social links from ProfileShowcasePreferences
SocialLinks identity.SocialLinks `json:"socialLinks"`
Images map[string]images.IdentityImage `json:"images"`

View File

@ -19,7 +19,9 @@
// 1632236298_add_communities.down.sql (151B)
// 1632236298_add_communities.up.sql (584B)
// 1636536507_add_index_bundles.up.sql (347B)
// doc.go (377B)
// 1698137564_add_migration_index.up.sql (483B)
// 1709200114_add_migration_index.up.sql (483B)
// doc.go (397B)
package migrations
@ -102,7 +104,7 @@ func _1536754952_initial_schemaDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1536754952_initial_schema.down.sql", size: 83, mode: os.FileMode(0644), modTime: time.Unix(1704739012, 0)}
info := bindataFileInfo{name: "1536754952_initial_schema.down.sql", size: 83, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x44, 0xcf, 0x76, 0x71, 0x1f, 0x5e, 0x9a, 0x43, 0xd8, 0xcd, 0xb8, 0xc3, 0x70, 0xc3, 0x7f, 0xfc, 0x90, 0xb4, 0x25, 0x1e, 0xf4, 0x66, 0x20, 0xb8, 0x33, 0x7e, 0xb0, 0x76, 0x1f, 0xc, 0xc0, 0x75}}
return a, nil
}
@ -122,7 +124,7 @@ func _1536754952_initial_schemaUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1536754952_initial_schema.up.sql", size: 962, mode: os.FileMode(0644), modTime: time.Unix(1704739012, 0)}
info := bindataFileInfo{name: "1536754952_initial_schema.up.sql", size: 962, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xea, 0x90, 0x5a, 0x59, 0x3e, 0x3, 0xe2, 0x3c, 0x81, 0x42, 0xcd, 0x4c, 0x9a, 0xe8, 0xda, 0x93, 0x2b, 0x70, 0xa4, 0xd5, 0x29, 0x3e, 0xd5, 0xc9, 0x27, 0xb6, 0xb7, 0x65, 0xff, 0x0, 0xcb, 0xde}}
return a, nil
}
@ -142,7 +144,7 @@ func _1539249977_update_ratchet_infoDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1539249977_update_ratchet_info.down.sql", size: 311, mode: os.FileMode(0644), modTime: time.Unix(1704739012, 0)}
info := bindataFileInfo{name: "1539249977_update_ratchet_info.down.sql", size: 311, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x1, 0xa4, 0xeb, 0xa0, 0xe6, 0xa0, 0xd4, 0x48, 0xbb, 0xad, 0x6f, 0x7d, 0x67, 0x8c, 0xbd, 0x25, 0xde, 0x1f, 0x73, 0x9a, 0xbb, 0xa8, 0xc9, 0x30, 0xb7, 0xa9, 0x7c, 0xaf, 0xb5, 0x1, 0x61, 0xdd}}
return a, nil
}
@ -162,7 +164,7 @@ func _1539249977_update_ratchet_infoUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1539249977_update_ratchet_info.up.sql", size: 368, mode: os.FileMode(0644), modTime: time.Unix(1704739012, 0)}
info := bindataFileInfo{name: "1539249977_update_ratchet_info.up.sql", size: 368, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xc, 0x8e, 0xbf, 0x6f, 0xa, 0xc0, 0xe1, 0x3c, 0x42, 0x28, 0x88, 0x1d, 0xdb, 0xba, 0x1c, 0x83, 0xec, 0xba, 0xd3, 0x5f, 0x5c, 0x77, 0x5e, 0xa7, 0x46, 0x36, 0xec, 0x69, 0xa, 0x4b, 0x17, 0x79}}
return a, nil
}
@ -182,7 +184,7 @@ func _1540715431_add_versionDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1540715431_add_version.down.sql", size: 127, mode: os.FileMode(0644), modTime: time.Unix(1704739012, 0)}
info := bindataFileInfo{name: "1540715431_add_version.down.sql", size: 127, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf5, 0x9, 0x4, 0xe3, 0x76, 0x2e, 0xb8, 0x9, 0x23, 0xf0, 0x70, 0x93, 0xc4, 0x50, 0xe, 0x9d, 0x84, 0x22, 0x8c, 0x94, 0xd3, 0x24, 0x9, 0x9a, 0xc1, 0xa1, 0x48, 0x45, 0xfd, 0x40, 0x6e, 0xe6}}
return a, nil
}
@ -202,7 +204,7 @@ func _1540715431_add_versionUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1540715431_add_version.up.sql", size: 265, mode: os.FileMode(0644), modTime: time.Unix(1704739012, 0)}
info := bindataFileInfo{name: "1540715431_add_version.up.sql", size: 265, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xc7, 0x4c, 0x36, 0x96, 0xdf, 0x16, 0x10, 0xa6, 0x27, 0x1a, 0x79, 0x8b, 0x42, 0x83, 0x23, 0xc, 0x7e, 0xb6, 0x3d, 0x2, 0xda, 0xa4, 0xb4, 0xd, 0x27, 0x55, 0xba, 0xdc, 0xb2, 0x88, 0x8f, 0xa6}}
return a, nil
}
@ -222,7 +224,7 @@ func _1541164797_add_installationsDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1541164797_add_installations.down.sql", size: 26, mode: os.FileMode(0644), modTime: time.Unix(1704739012, 0)}
info := bindataFileInfo{name: "1541164797_add_installations.down.sql", size: 26, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf5, 0xfd, 0xe6, 0xd8, 0xca, 0x3b, 0x38, 0x18, 0xee, 0x0, 0x5f, 0x36, 0x9e, 0x1e, 0xd, 0x19, 0x3e, 0xb4, 0x73, 0x53, 0xe9, 0xa5, 0xac, 0xdd, 0xa1, 0x2f, 0xc7, 0x6c, 0xa8, 0xd9, 0xa, 0x88}}
return a, nil
}
@ -242,7 +244,7 @@ func _1541164797_add_installationsUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1541164797_add_installations.up.sql", size: 216, mode: os.FileMode(0644), modTime: time.Unix(1704739012, 0)}
info := bindataFileInfo{name: "1541164797_add_installations.up.sql", size: 216, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x2d, 0x18, 0x26, 0xb8, 0x88, 0x47, 0xdb, 0x83, 0xcc, 0xb6, 0x9d, 0x1c, 0x1, 0xae, 0x2f, 0xde, 0x97, 0x82, 0x3, 0x30, 0xa8, 0x63, 0xa1, 0x78, 0x4b, 0xa5, 0x9, 0x8, 0x75, 0xa2, 0x57, 0x81}}
return a, nil
}
@ -262,7 +264,7 @@ func _1558084410_add_secretDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1558084410_add_secret.down.sql", size: 56, mode: os.FileMode(0644), modTime: time.Unix(1704739012, 0)}
info := bindataFileInfo{name: "1558084410_add_secret.down.sql", size: 56, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x49, 0xb, 0x65, 0xdf, 0x59, 0xbf, 0xe9, 0x5, 0x5b, 0x6f, 0xd5, 0x3a, 0xb7, 0x57, 0xe8, 0x78, 0x38, 0x73, 0x53, 0x57, 0xf7, 0x24, 0x4, 0xe4, 0xa2, 0x49, 0x22, 0xa2, 0xc6, 0xfd, 0x80, 0xa4}}
return a, nil
}
@ -282,7 +284,7 @@ func _1558084410_add_secretUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1558084410_add_secret.up.sql", size: 301, mode: os.FileMode(0644), modTime: time.Unix(1704739012, 0)}
info := bindataFileInfo{name: "1558084410_add_secret.up.sql", size: 301, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf5, 0x32, 0x36, 0x8e, 0x47, 0xb0, 0x8f, 0xc1, 0xc6, 0xf7, 0xc6, 0x9f, 0x2d, 0x44, 0x75, 0x2b, 0x26, 0xec, 0x6, 0xa0, 0x7b, 0xa5, 0xbd, 0xc8, 0x76, 0x8a, 0x82, 0x68, 0x2, 0x42, 0xb5, 0xf4}}
return a, nil
}
@ -302,7 +304,7 @@ func _1558588866_add_versionDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1558588866_add_version.down.sql", size: 47, mode: os.FileMode(0644), modTime: time.Unix(1704739012, 0)}
info := bindataFileInfo{name: "1558588866_add_version.down.sql", size: 47, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xde, 0x52, 0x34, 0x3c, 0x46, 0x4a, 0xf0, 0x72, 0x47, 0x6f, 0x49, 0x5c, 0xc7, 0xf9, 0x32, 0xce, 0xc4, 0x3d, 0xfd, 0x61, 0xa1, 0x8b, 0x8f, 0xf2, 0x31, 0x34, 0xde, 0x15, 0x49, 0xa6, 0xde, 0xb9}}
return a, nil
}
@ -322,7 +324,7 @@ func _1558588866_add_versionUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1558588866_add_version.up.sql", size: 57, mode: os.FileMode(0644), modTime: time.Unix(1704739012, 0)}
info := bindataFileInfo{name: "1558588866_add_version.up.sql", size: 57, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x2a, 0xea, 0x64, 0x39, 0x61, 0x20, 0x83, 0x83, 0xb, 0x2e, 0x79, 0x64, 0xb, 0x53, 0xfa, 0xfe, 0xc6, 0xf7, 0x67, 0x42, 0xd3, 0x4f, 0xdc, 0x7e, 0x30, 0x32, 0xe8, 0x14, 0x41, 0xe9, 0xe7, 0x3b}}
return a, nil
}
@ -342,7 +344,7 @@ func _1559627659_add_contact_codeDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1559627659_add_contact_code.down.sql", size: 32, mode: os.FileMode(0644), modTime: time.Unix(1704739012, 0)}
info := bindataFileInfo{name: "1559627659_add_contact_code.down.sql", size: 32, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x5d, 0x64, 0x6d, 0xce, 0x24, 0x42, 0x20, 0x8d, 0x4f, 0x37, 0xaa, 0x9d, 0xc, 0x57, 0x98, 0xc1, 0xd1, 0x1a, 0x34, 0xcd, 0x9f, 0x8f, 0x34, 0x86, 0xb3, 0xd3, 0xdc, 0xf1, 0x7d, 0xe5, 0x1b, 0x6e}}
return a, nil
}
@ -362,7 +364,7 @@ func _1559627659_add_contact_codeUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1559627659_add_contact_code.up.sql", size: 198, mode: os.FileMode(0644), modTime: time.Unix(1704739012, 0)}
info := bindataFileInfo{name: "1559627659_add_contact_code.up.sql", size: 198, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x16, 0xf6, 0xc2, 0x62, 0x9c, 0xd2, 0xc9, 0x1e, 0xd8, 0xea, 0xaa, 0xea, 0x95, 0x8f, 0x89, 0x6a, 0x85, 0x5d, 0x9d, 0x99, 0x78, 0x3c, 0x90, 0x66, 0x99, 0x3e, 0x4b, 0x19, 0x62, 0xfb, 0x31, 0x4d}}
return a, nil
}
@ -382,7 +384,7 @@ func _1561368210_add_installation_metadataDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1561368210_add_installation_metadata.down.sql", size: 35, mode: os.FileMode(0644), modTime: time.Unix(1704739012, 0)}
info := bindataFileInfo{name: "1561368210_add_installation_metadata.down.sql", size: 35, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xa8, 0xde, 0x3f, 0xd2, 0x4a, 0x50, 0x98, 0x56, 0xe3, 0xc0, 0xcd, 0x9d, 0xb0, 0x34, 0x3b, 0xe5, 0x62, 0x18, 0xb5, 0x20, 0xc9, 0x3e, 0xdc, 0x6a, 0x40, 0x36, 0x66, 0xea, 0x51, 0x8c, 0x71, 0xf5}}
return a, nil
}
@ -402,7 +404,7 @@ func _1561368210_add_installation_metadataUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1561368210_add_installation_metadata.up.sql", size: 267, mode: os.FileMode(0644), modTime: time.Unix(1704739012, 0)}
info := bindataFileInfo{name: "1561368210_add_installation_metadata.up.sql", size: 267, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xb4, 0x71, 0x8f, 0x29, 0xb1, 0xaa, 0xd6, 0xd1, 0x8c, 0x17, 0xef, 0x6c, 0xd5, 0x80, 0xb8, 0x2c, 0xc3, 0xfe, 0xec, 0x24, 0x4d, 0xc8, 0x25, 0xd3, 0xb4, 0xcd, 0xa9, 0xac, 0x63, 0x61, 0xb2, 0x9c}}
return a, nil
}
@ -422,7 +424,7 @@ func _1632236298_add_communitiesDownSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1632236298_add_communities.down.sql", size: 151, mode: os.FileMode(0644), modTime: time.Unix(1704739012, 0)}
info := bindataFileInfo{name: "1632236298_add_communities.down.sql", size: 151, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x26, 0xe5, 0x47, 0xd1, 0xe5, 0xec, 0x5b, 0x3e, 0xdc, 0x22, 0xf4, 0x27, 0xee, 0x70, 0xf3, 0x9, 0x4f, 0xd2, 0x9f, 0x92, 0xf, 0x5a, 0x18, 0x11, 0xb7, 0x40, 0xab, 0xf1, 0x98, 0x72, 0xd6, 0x60}}
return a, nil
}
@ -442,7 +444,7 @@ func _1632236298_add_communitiesUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1632236298_add_communities.up.sql", size: 584, mode: os.FileMode(0644), modTime: time.Unix(1704739012, 0)}
info := bindataFileInfo{name: "1632236298_add_communities.up.sql", size: 584, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x8f, 0xe0, 0x1, 0x6e, 0x84, 0xc, 0x35, 0xe4, 0x5a, 0xf, 0xbe, 0xcb, 0xf7, 0xd2, 0xa8, 0x25, 0xf5, 0xdb, 0x7, 0xcb, 0xa3, 0xe6, 0xf4, 0xc4, 0x1b, 0xa5, 0xec, 0x32, 0x1e, 0x1e, 0x48, 0x60}}
return a, nil
}
@ -462,12 +464,52 @@ func _1636536507_add_index_bundlesUpSql() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "1636536507_add_index_bundles.up.sql", size: 347, mode: os.FileMode(0644), modTime: time.Unix(1704739012, 0)}
info := bindataFileInfo{name: "1636536507_add_index_bundles.up.sql", size: 347, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf1, 0xb9, 0x3c, 0x16, 0xfc, 0xfb, 0xb2, 0xb4, 0x3b, 0xfe, 0xdc, 0xf5, 0x9c, 0x42, 0xa0, 0xa0, 0xd4, 0xd, 0x5b, 0x97, 0x10, 0x80, 0x95, 0xe, 0x13, 0xc1, 0x18, 0x8, 0xee, 0xf, 0x99, 0xee}}
return a, nil
}
var _docGo = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x84\x8f\xbb\x6e\xc3\x30\x0c\x45\x77\x7f\xc5\x45\x96\x2c\xb5\xb4\x74\xea\xd6\xb1\x7b\x7f\x80\x91\x68\x89\x88\x1e\xae\x48\xe7\xf1\xf7\x85\xd3\x02\xcd\xd6\xf5\x00\xe7\xf0\xd2\x7b\x7c\x66\x51\x2c\x52\x18\xa2\x68\x1c\x58\x95\xc6\x1d\x27\x0e\xb4\x29\xe3\x90\xc4\xf2\x76\x72\xa1\x57\xaf\x46\xb6\xe9\x2c\xd5\x57\x49\x83\x8c\xfd\xe5\xf5\x30\x79\x8f\x40\xed\x68\xc8\xd4\x62\xe1\x47\x4b\xa1\x46\xc3\xa4\x25\x5c\xc5\x32\x08\xeb\xe0\x45\x6e\x0e\xef\x86\xc2\xa4\x06\xcb\x64\x47\x85\x65\x46\x20\xe5\x3d\xb3\xf4\x81\xd4\xe7\x93\xb4\x48\x46\x6e\x47\x1f\xcb\x13\xd9\x17\x06\x2a\x85\x23\x96\xd1\xeb\xc3\x55\xaa\x8c\x28\x83\x83\xf5\x71\x7f\x01\xa9\xb2\xa1\x51\x65\xdd\xfd\x4c\x17\x46\xeb\xbf\xe7\x41\x2d\xfe\xff\x11\xae\x7d\x9c\x15\xa4\xe0\xdb\xca\xc1\x38\xba\x69\x5a\x29\x9c\x29\x31\xf4\xab\x88\xf1\x34\x79\x9f\xfa\x5b\xe2\xc6\xbb\xf5\xbc\x71\x5e\xcf\x09\x3f\x35\xe9\x4d\x31\x77\x38\xe7\xff\x80\x4b\x1d\x6e\xfa\x0e\x00\x00\xff\xff\x9d\x60\x3d\x88\x79\x01\x00\x00")
var __1698137564_add_migration_indexUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xa4\x90\xc1\xaa\xc2\x30\x10\x45\xf7\xfd\x8a\x59\xbe\x07\xfe\x81\x2b\x69\x23\x74\xd3\x82\xed\xa2\xbb\x21\x24\x83\x09\xa5\x6d\x4c\x46\x30\x7f\x2f\x25\x16\x41\xb1\x2a\x6e\x66\x36\xf7\xdc\x03\x37\x3f\x88\x5d\x2b\xa0\xac\x0a\xd1\x41\xb9\x87\xaa\x6e\x41\x74\x65\xd3\x36\x60\xf5\x05\x8f\x7e\x3a\x3b\x64\x3b\x50\x60\x39\x38\xd4\x14\x54\x56\x57\x60\x64\x30\xe8\x25\x2b\x43\x8c\x34\x2a\x1f\x1d\xdb\x69\x84\xbf\x04\x58\xbd\x81\x9e\xe2\x1d\x84\x42\x34\xf9\xff\x36\xcb\xde\xf8\x5e\xf4\x62\x4f\x31\xcc\x07\xad\x5e\xd5\xa7\xc8\xaf\x22\x4d\xce\x93\x92\x4c\xfa\x13\xe7\x53\xfa\x5b\xbd\x92\xca\x10\x2e\xcb\xdd\x4a\x30\xd0\x09\xc7\x69\xc5\x9c\xb8\xc7\xc9\xe7\x9f\xd0\x65\xf3\x6b\x00\x00\x00\xff\xff\x97\xf4\x28\xe3\xe3\x01\x00\x00")
func _1698137564_add_migration_indexUpSqlBytes() ([]byte, error) {
return bindataRead(
__1698137564_add_migration_indexUpSql,
"1698137564_add_migration_index.up.sql",
)
}
func _1698137564_add_migration_indexUpSql() (*asset, error) {
bytes, err := _1698137564_add_migration_indexUpSqlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "1698137564_add_migration_index.up.sql", size: 483, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe2, 0xec, 0xd4, 0x54, 0xff, 0x5e, 0x6e, 0xaf, 0x3f, 0x2b, 0xb5, 0x76, 0xe9, 0x84, 0x2a, 0x4d, 0x1f, 0xd8, 0x22, 0x8b, 0x4b, 0x5c, 0xf1, 0xe0, 0x3a, 0x34, 0xc5, 0xed, 0xef, 0x74, 0xe4, 0x2b}}
return a, nil
}
var __1709200114_add_migration_indexUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xa4\x90\xc1\xaa\xc2\x30\x10\x45\xf7\xfd\x8a\x59\xbe\x07\xfe\x81\x2b\x69\x23\x74\xd3\x82\xed\xa2\xbb\x21\x24\x83\x09\xa5\x6d\x4c\x46\x30\x7f\x2f\x25\x16\x41\xb1\x2a\x6e\x66\x36\xf7\xdc\x03\x37\x3f\x88\x5d\x2b\xa0\xac\x0a\xd1\x41\xb9\x87\xaa\x6e\x41\x74\x65\xd3\x36\x60\xf5\x05\x8f\x7e\x3a\x3b\x64\x3b\x50\x60\x39\x38\xd4\x14\x54\x56\x57\x60\x64\x30\xe8\x25\x2b\x43\x8c\x34\x2a\x1f\x1d\xdb\x69\x84\xbf\x04\x58\xbd\x81\x9e\xe2\x1d\x84\x42\x34\xf9\xff\x36\xcb\xde\xf8\x5e\xf4\x62\x4f\x31\xcc\x07\xad\x5e\xd5\xa7\xc8\xaf\x22\x4d\xce\x93\x92\x4c\xfa\x13\xe7\x53\xfa\x5b\xbd\x92\xca\x10\x2e\xcb\xdd\x4a\x30\xd0\x09\xc7\x69\xc5\x9c\xb8\xc7\xc9\xe7\x9f\xd0\x65\xf3\x6b\x00\x00\x00\xff\xff\x97\xf4\x28\xe3\xe3\x01\x00\x00")
func _1709200114_add_migration_indexUpSqlBytes() ([]byte, error) {
return bindataRead(
__1709200114_add_migration_indexUpSql,
"1709200114_add_migration_index.up.sql",
)
}
func _1709200114_add_migration_indexUpSql() (*asset, error) {
bytes, err := _1709200114_add_migration_indexUpSqlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "1709200114_add_migration_index.up.sql", size: 483, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe2, 0xec, 0xd4, 0x54, 0xff, 0x5e, 0x6e, 0xaf, 0x3f, 0x2b, 0xb5, 0x76, 0xe9, 0x84, 0x2a, 0x4d, 0x1f, 0xd8, 0x22, 0x8b, 0x4b, 0x5c, 0xf1, 0xe0, 0x3a, 0x34, 0xc5, 0xed, 0xef, 0x74, 0xe4, 0x2b}}
return a, nil
}
var _docGo = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x84\x8f\xbd\x6a\x2b\x31\x10\x85\xfb\x7d\x8a\x83\x1b\x37\x77\xa5\x1b\x08\x04\x02\x29\x52\xa6\xcf\x0b\x8c\xa5\x59\x69\xf0\x4a\xda\x68\x66\xfd\xf3\xf6\x61\x1d\x43\xdc\x65\xca\x0f\xbe\x73\xce\x78\x8f\xcf\x2c\x8a\x49\x66\x86\x28\x2a\x07\x56\xa5\x7e\xc5\x81\x03\xad\xca\xd8\x25\xb1\xbc\x1e\x5c\x68\xc5\xab\x91\xad\x3a\x4a\xf1\x45\x52\x27\x63\x7f\x7a\xde\x0d\xde\x23\x50\xdd\x1b\x32\xd5\x38\xf3\x2d\x4b\xa1\x46\xdd\xa4\x26\x9c\xc5\x32\x08\x4b\xe7\x49\x2e\x0e\xef\x86\x99\x49\x0d\x96\xc9\xf6\x0a\xcb\x8c\x40\xca\x5b\xcc\xd4\x3a\x52\x1b\x0f\x52\x23\x19\xb9\x0d\x7d\x4c\x0f\x64\x5b\x18\x68\x9e\x39\x62\xea\xad\xdc\x5c\xa5\xc2\x88\xd2\x39\x58\xeb\xd7\x7f\x20\x55\x36\x54\x2a\xac\x9b\x9f\xe9\xc4\xa8\xed\x5e\x0f\xaa\xf1\xef\x8f\x70\x6e\xfd\xa8\x20\x05\x5f\x16\x0e\xc6\xd1\x0d\xc3\x42\xe1\x48\x89\xa1\x5f\xb3\x18\x0f\x83\xf7\xa9\xbd\x26\xae\xbc\x59\x8f\x1b\xc7\xd2\xa2\x49\xe1\xb7\xa7\x97\xff\xf7\xc3\xb8\x1c\x13\x7e\x1a\xa4\x55\xc5\xd8\xe0\x9c\xff\x05\x2e\x35\xb8\xe1\x3b\x00\x00\xff\xff\x73\x18\x09\xa7\x8d\x01\x00\x00")
func docGoBytes() ([]byte, error) {
return bindataRead(
@ -482,8 +524,8 @@ func docGo() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "doc.go", size: 377, mode: os.FileMode(0644), modTime: time.Unix(1704739012, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xef, 0xaf, 0xdf, 0xcf, 0x65, 0xae, 0x19, 0xfc, 0x9d, 0x29, 0xc1, 0x91, 0xaf, 0xb5, 0xd5, 0xb1, 0x56, 0xf3, 0xee, 0xa8, 0xba, 0x13, 0x65, 0xdb, 0xab, 0xcf, 0x4e, 0xac, 0x92, 0xe9, 0x60, 0xf1}}
info := bindataFileInfo{name: "doc.go", size: 397, mode: os.FileMode(0644), modTime: time.Unix(1700000000, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x6, 0xd0, 0xec, 0xce, 0xa1, 0x5d, 0x5f, 0x7d, 0x3d, 0xc5, 0xba, 0xdd, 0xe3, 0x71, 0xc9, 0x56, 0xc3, 0x54, 0xd7, 0x57, 0x2d, 0xca, 0xd5, 0x87, 0x1a, 0xa9, 0xff, 0x23, 0xf6, 0xa2, 0x1, 0xb7}}
return a, nil
}
@ -597,6 +639,8 @@ var _bindata = map[string]func() (*asset, error){
"1632236298_add_communities.down.sql": _1632236298_add_communitiesDownSql,
"1632236298_add_communities.up.sql": _1632236298_add_communitiesUpSql,
"1636536507_add_index_bundles.up.sql": _1636536507_add_index_bundlesUpSql,
"1698137564_add_migration_index.up.sql": _1698137564_add_migration_indexUpSql,
"1709200114_add_migration_index.up.sql": _1709200114_add_migration_indexUpSql,
"doc.go": docGo,
}
@ -665,6 +709,8 @@ var _bintree = &bintree{nil, map[string]*bintree{
"1632236298_add_communities.down.sql": {_1632236298_add_communitiesDownSql, map[string]*bintree{}},
"1632236298_add_communities.up.sql": {_1632236298_add_communitiesUpSql, map[string]*bintree{}},
"1636536507_add_index_bundles.up.sql": {_1636536507_add_index_bundlesUpSql, map[string]*bintree{}},
"1698137564_add_migration_index.up.sql": {_1698137564_add_migration_indexUpSql, map[string]*bintree{}},
"1709200114_add_migration_index.up.sql": {_1709200114_add_migration_indexUpSql, map[string]*bintree{}},
"doc.go": {docGo, map[string]*bintree{}},
}}

View File

@ -1,6 +1,7 @@
package encryption
import (
"context"
"crypto/ecdsa"
"database/sql"
"errors"
@ -742,52 +743,53 @@ type HRCache struct {
// If cache data with given seqNo (e.g. 0) is not found,
// then the query will return the cache data with the latest seqNo
func (s *sqlitePersistence) GetHashRatchetCache(ratchet *HashRatchetKeyCompatibility, seqNo uint32) (*HRCache, error) {
stmt, err := s.DB.Prepare(`WITH input AS (
select ? AS group_id, ? AS key_id, ? as seq_no, ? AS old_key_id
),
cec AS (
SELECT e.key, c.seq_no, c.hash FROM hash_ratchet_encryption e, input i
LEFT JOIN hash_ratchet_encryption_cache c ON e.group_id=c.group_id AND (e.key_id=c.key_id OR e.deprecated_key_id=c.key_id)
WHERE (e.key_id=i.key_id OR e.deprecated_key_id=i.old_key_id) AND e.group_id=i.group_id),
seq_nos AS (
select CASE
WHEN EXISTS (SELECT c.seq_no from cec c, input i where c.seq_no=i.seq_no)
THEN i.seq_no
ELSE (select max(seq_no) from cec)
END as seq_no from input i
)
SELECT c.key, c.seq_no, c.hash FROM cec c, input i, seq_nos s
where case when not exists(select seq_no from seq_nos where seq_no is not null)
then 1 else c.seq_no = s.seq_no end`)
tx, err := s.DB.BeginTx(context.Background(), &sql.TxOptions{})
if err != nil {
return nil, err
}
defer stmt.Close()
defer func() {
if err == nil {
err = tx.Commit()
return
}
// don't shadow original error
_ = tx.Rollback()
}()
var key, hash []byte
var seqNoPtr *uint32
oldFormat := ratchet.IsOldFormat()
if oldFormat {
// Query using the deprecated format
err = stmt.QueryRow(ratchet.GroupID, nil, seqNo, ratchet.DeprecatedKeyID()).Scan(&key, &seqNoPtr, &hash) //nolint: ineffassign
} else {
keyID, err := ratchet.GetKeyID()
var key, keyID []byte
if !ratchet.IsOldFormat() {
keyID, err = ratchet.GetKeyID()
if err != nil {
return nil, err
}
err = stmt.QueryRow(ratchet.GroupID, keyID, seqNo, ratchet.DeprecatedKeyID()).Scan(&key, &seqNoPtr, &hash) //nolint: ineffassign,staticcheck
}
if len(hash) == 0 && len(key) == 0 {
err = tx.QueryRow("SELECT key FROM hash_ratchet_encryption WHERE key_id = ? OR deprecated_key_id = ?", keyID, ratchet.DeprecatedKeyID()).Scan(&key)
if err == sql.ErrNoRows {
return nil, nil
}
if err != nil {
return nil, err
}
args := make([]interface{}, 0)
args = append(args, ratchet.GroupID)
args = append(args, keyID)
args = append(args, ratchet.DeprecatedKeyID())
var query string
if seqNo == 0 {
query = "SELECT seq_no, hash FROM hash_ratchet_encryption_cache WHERE group_id = ? AND (key_id = ? OR key_id = ?) ORDER BY seq_no DESC limit 1"
} else {
query = "SELECT seq_no, hash FROM hash_ratchet_encryption_cache WHERE group_id = ? AND (key_id = ? OR key_id = ?) AND seq_no == ? ORDER BY seq_no DESC limit 1"
args = append(args, seqNo)
}
var hash []byte
var seqNoPtr *uint32
err = tx.QueryRow(query, args...).Scan(&seqNoPtr, &hash) //nolint: ineffassign,staticcheck
switch err {
case sql.ErrNoRows:
return nil, nil
case nil:
case sql.ErrNoRows, nil:
var seqNoResult uint32
if seqNoPtr == nil {
seqNoResult = 0

View File

@ -26,6 +26,7 @@ const (
sharedSecretNegotiationVersion = 1
partitionedTopicMinVersion = 1
defaultMinVersion = 0
maxKeysChannelSize = 10000
)
type PartitionTopicMode int
@ -121,9 +122,10 @@ func NewWithEncryptorConfig(
}
type Subscriptions struct {
SharedSecrets []*sharedsecret.Secret
SendContactCode <-chan struct{}
Quit chan struct{}
SharedSecrets []*sharedsecret.Secret
SendContactCode <-chan struct{}
NewHashRatchetKeys chan []*HashRatchetInfo
Quit chan struct{}
}
func (p *Protocol) Start(myIdentity *ecdsa.PrivateKey) (*Subscriptions, error) {
@ -133,9 +135,10 @@ func (p *Protocol) Start(myIdentity *ecdsa.PrivateKey) (*Subscriptions, error) {
return nil, errors.Wrap(err, "failed to get all secrets")
}
p.subscriptions = &Subscriptions{
SharedSecrets: secrets,
SendContactCode: p.publisher.Start(),
Quit: make(chan struct{}),
SharedSecrets: secrets,
SendContactCode: p.publisher.Start(),
NewHashRatchetKeys: make(chan []*HashRatchetInfo, maxKeysChannelSize),
Quit: make(chan struct{}),
}
return p.subscriptions, nil
}
@ -234,16 +237,45 @@ func (p *Protocol) GenerateHashRatchetKey(groupID []byte) (*HashRatchetKeyCompat
return p.encryptor.GenerateHashRatchetKey(groupID)
}
func (p *Protocol) GetAllHREncodedKeys(groupID []byte) ([]byte, error) {
keys, err := p.encryptor.persistence.GetKeysForGroup(groupID)
// Deprecated: This function is deprecated as it does not marshal groupID. Kept for backward compatibility.
func (p *Protocol) GetAllHRKeysMarshaledV1(groupID []byte) ([]byte, error) {
keys, err := p.GetAllHRKeys(groupID)
if err != nil {
return nil, err
}
if len(keys) == 0 {
if keys == nil {
return nil, nil
}
return p.GetMarshaledHREncodedKeys(groupID, keys)
return proto.Marshal(keys)
}
func (p *Protocol) GetAllHRKeysMarshaledV2(groupID []byte) ([]byte, error) {
keys, err := p.GetAllHRKeys(groupID)
if err != nil {
return nil, err
}
if keys == nil {
return nil, nil
}
header := &HRHeader{
SeqNo: 0,
GroupId: groupID,
Keys: keys,
}
return proto.Marshal(header)
}
func (p *Protocol) GetAllHRKeys(groupID []byte) (*HRKeys, error) {
ratchets, err := p.encryptor.persistence.GetKeysForGroup(groupID)
if err != nil {
return nil, err
}
if len(ratchets) == 0 {
return nil, nil
}
return p.GetHRKeys(ratchets), nil
}
// GetKeyIDsForGroup returns a slice of key IDs belonging to a given group ID
@ -251,7 +283,7 @@ func (p *Protocol) GetKeysForGroup(groupID []byte) ([]*HashRatchetKeyCompatibili
return p.encryptor.persistence.GetKeysForGroup(groupID)
}
func (p *Protocol) GetHREncodedKeys(groupID []byte, ratchets []*HashRatchetKeyCompatibility) *HRKeys {
func (p *Protocol) GetHRKeys(ratchets []*HashRatchetKeyCompatibility) *HRKeys {
keys := &HRKeys{}
for _, ratchet := range ratchets {
key := &HRKey{
@ -265,11 +297,6 @@ func (p *Protocol) GetHREncodedKeys(groupID []byte, ratchets []*HashRatchetKeyCo
return keys
}
func (p *Protocol) GetMarshaledHREncodedKeys(groupID []byte, ratchets []*HashRatchetKeyCompatibility) ([]byte, error) {
keys := p.GetHREncodedKeys(groupID, ratchets)
return proto.Marshal(keys)
}
// BuildHashRatchetRekeyGroup builds a public message
// with the new key
func (p *Protocol) BuildHashRatchetReKeyGroupMessage(myIdentityKey *ecdsa.PrivateKey, recipients []*ecdsa.PublicKey, groupID []byte, payload []byte, ratchet *HashRatchetKeyCompatibility) (*ProtocolMessageSpec, error) {
@ -313,7 +340,7 @@ func (p *Protocol) BuildHashRatchetReKeyGroupMessage(myIdentityKey *ecdsa.Privat
// containing newly generated hash ratchet key
func (p *Protocol) BuildHashRatchetKeyExchangeMessage(myIdentityKey *ecdsa.PrivateKey, publicKey *ecdsa.PublicKey, groupID []byte, ratchets []*HashRatchetKeyCompatibility) (*ProtocolMessageSpec, error) {
keys := p.GetHREncodedKeys(groupID, ratchets)
keys := p.GetHRKeys(ratchets)
encodedKeys, err := proto.Marshal(keys)
if err != nil {
@ -342,7 +369,7 @@ func (p *Protocol) BuildHashRatchetKeyExchangeMessage(myIdentityKey *ecdsa.Priva
func (p *Protocol) BuildHashRatchetKeyExchangeMessageWithPayload(myIdentityKey *ecdsa.PrivateKey, publicKey *ecdsa.PublicKey, groupID []byte, ratchets []*HashRatchetKeyCompatibility, payload []byte) (*ProtocolMessageSpec, error) {
keys := p.GetHREncodedKeys(groupID, ratchets)
keys := p.GetHRKeys(ratchets)
response, err := p.BuildEncryptedMessage(myIdentityKey, publicKey, payload)
if err != nil {
@ -578,7 +605,6 @@ type DecryptMessageResponse struct {
}
func (p *Protocol) HandleHashRatchetKeysPayload(groupID, encodedKeys []byte, myIdentityKey *ecdsa.PrivateKey, theirIdentityKey *ecdsa.PublicKey) ([]*HashRatchetInfo, error) {
keys := &HRKeys{}
err := proto.Unmarshal(encodedKeys, keys)
if err != nil {
@ -587,6 +613,21 @@ func (p *Protocol) HandleHashRatchetKeysPayload(groupID, encodedKeys []byte, myI
return p.HandleHashRatchetKeys(groupID, keys, myIdentityKey, theirIdentityKey)
}
func (p *Protocol) HandleHashRatchetHeadersPayload(encodedHeaders [][]byte) error {
for _, encodedHeader := range encodedHeaders {
header := &HRHeader{}
err := proto.Unmarshal(encodedHeader, header)
if err != nil {
return err
}
_, err = p.HandleHashRatchetKeys(header.GroupId, header.Keys, nil, nil)
if err != nil {
return err
}
}
return nil
}
func (p *Protocol) HandleHashRatchetKeys(groupID []byte, keys *HRKeys, myIdentityKey *ecdsa.PrivateKey, theirIdentityKey *ecdsa.PublicKey) ([]*HashRatchetInfo, error) {
if keys == nil {
return nil, nil
@ -653,6 +694,10 @@ func (p *Protocol) HandleHashRatchetKeys(groupID []byte, keys *HRKeys, myIdentit
}
}
if p.subscriptions != nil {
p.subscriptions.NewHashRatchetKeys <- info
}
return info, nil
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,164 @@
package identity
import "errors"
var ErrorNoAccountProvidedWithTokenOrCollectible = errors.New("no account provided with tokens or collectible")
var ErrorExceedMaxProfileShowcaseCommunitiesLimit = errors.New("exeed maximum profile showcase communities limit")
var ErrorExceedMaxProfileShowcaseAccountsLimit = errors.New("exeed maximum profile showcase accounts limit")
var ErrorExceedMaxProfileShowcaseCollectiblesLimit = errors.New("exeed maximum profile showcase collectibles limit")
var ErrorExceedMaxProfileShowcaseVerifiedTokensLimit = errors.New("exeed maximum profile showcase verified tokens limit")
var ErrorExceedMaxProfileShowcaseUnverifiedTokensLimit = errors.New("exeed maximum profile showcase unverified tokens limit")
var ErrorExceedMaxProfileShowcaseSocialLinksLimit = errors.New("exeed maximum profile showcase communities limit")
const MaxProfileShowcaseSocialLinksLimit = 20
const MaxProfileShowcaseEntriesLimit = 100
type ProfileShowcaseVisibility int
const (
ProfileShowcaseVisibilityNoOne ProfileShowcaseVisibility = iota
ProfileShowcaseVisibilityIDVerifiedContacts
ProfileShowcaseVisibilityContacts
ProfileShowcaseVisibilityEveryone
)
type ProfileShowcaseMembershipStatus int
const (
ProfileShowcaseMembershipStatusUnproven ProfileShowcaseMembershipStatus = iota
ProfileShowcaseMembershipStatusProvenMember
ProfileShowcaseMembershipStatusNotAMember
)
// Profile showcase preferences
type ProfileShowcaseCommunityPreference struct {
CommunityID string `json:"communityId"`
ShowcaseVisibility ProfileShowcaseVisibility `json:"showcaseVisibility"`
Order int `json:"order"`
}
type ProfileShowcaseAccountPreference struct {
Address string `json:"address"`
ShowcaseVisibility ProfileShowcaseVisibility `json:"showcaseVisibility"`
Order int `json:"order"`
}
type ProfileShowcaseCollectiblePreference struct {
ContractAddress string `json:"contractAddress"`
ChainID uint64 `json:"chainId"`
TokenID string `json:"tokenId"`
ShowcaseVisibility ProfileShowcaseVisibility `json:"showcaseVisibility"`
Order int `json:"order"`
}
type ProfileShowcaseVerifiedTokenPreference struct {
Symbol string `json:"symbol"`
ShowcaseVisibility ProfileShowcaseVisibility `json:"showcaseVisibility"`
Order int `json:"order"`
}
type ProfileShowcaseUnverifiedTokenPreference struct {
ContractAddress string `json:"contractAddress"`
ChainID uint64 `json:"chainId"`
ShowcaseVisibility ProfileShowcaseVisibility `json:"showcaseVisibility"`
Order int `json:"order"`
}
type ProfileShowcaseSocialLinkPreference struct {
URL string `json:"url"`
Text string `json:"text"`
ShowcaseVisibility ProfileShowcaseVisibility `json:"showcaseVisibility"`
Order int `json:"order"`
}
type ProfileShowcasePreferences struct {
Clock uint64 `json:"clock"`
Communities []*ProfileShowcaseCommunityPreference `json:"communities"`
Accounts []*ProfileShowcaseAccountPreference `json:"accounts"`
Collectibles []*ProfileShowcaseCollectiblePreference `json:"collectibles"`
VerifiedTokens []*ProfileShowcaseVerifiedTokenPreference `json:"verifiedTokens"`
UnverifiedTokens []*ProfileShowcaseUnverifiedTokenPreference `json:"unverifiedTokens"`
SocialLinks []*ProfileShowcaseSocialLinkPreference `json:"socialLinks"`
}
// Profile showcase for a contact
type ProfileShowcaseCommunity struct {
CommunityID string `json:"communityId"`
Order int `json:"order"`
MembershipStatus ProfileShowcaseMembershipStatus `json:"membershipStatus"`
Grant []byte `json:"grant,omitempty"`
}
type ProfileShowcaseAccount struct {
ContactID string `json:"contactId"`
Address string `json:"address"`
Name string `json:"name"`
ColorID string `json:"colorId"`
Emoji string `json:"emoji"`
Order int `json:"order"`
}
type ProfileShowcaseCollectible struct {
ContractAddress string `json:"contractAddress"`
ChainID uint64 `json:"chainId"`
TokenID string `json:"tokenId"`
Order int `json:"order"`
}
type ProfileShowcaseVerifiedToken struct {
Symbol string `json:"symbol"`
Order int `json:"order"`
}
type ProfileShowcaseUnverifiedToken struct {
ContractAddress string `json:"contractAddress"`
ChainID uint64 `json:"chainId"`
Order int `json:"order"`
}
type ProfileShowcaseSocialLink struct {
URL string `json:"url"`
Text string `json:"text"`
Order int `json:"order"`
}
type ProfileShowcase struct {
ContactID string `json:"contactId"`
Communities []*ProfileShowcaseCommunity `json:"communities"`
Accounts []*ProfileShowcaseAccount `json:"accounts"`
Collectibles []*ProfileShowcaseCollectible `json:"collectibles"`
VerifiedTokens []*ProfileShowcaseVerifiedToken `json:"verifiedTokens"`
UnverifiedTokens []*ProfileShowcaseUnverifiedToken `json:"unverifiedTokens"`
SocialLinks []*ProfileShowcaseSocialLink `json:"socialLinks"`
}
func Validate(preferences *ProfileShowcasePreferences) error {
if len(preferences.Communities) > MaxProfileShowcaseEntriesLimit {
return ErrorExceedMaxProfileShowcaseCommunitiesLimit
}
if len(preferences.Accounts) > MaxProfileShowcaseEntriesLimit {
return ErrorExceedMaxProfileShowcaseAccountsLimit
}
if len(preferences.Collectibles) > MaxProfileShowcaseEntriesLimit {
return ErrorExceedMaxProfileShowcaseCollectiblesLimit
}
if len(preferences.VerifiedTokens) > MaxProfileShowcaseEntriesLimit {
return ErrorExceedMaxProfileShowcaseVerifiedTokensLimit
}
if len(preferences.UnverifiedTokens) > MaxProfileShowcaseEntriesLimit {
return ErrorExceedMaxProfileShowcaseUnverifiedTokensLimit
}
if len(preferences.SocialLinks) > MaxProfileShowcaseSocialLinksLimit {
return ErrorExceedMaxProfileShowcaseSocialLinksLimit
}
if (len(preferences.VerifiedTokens) > 0 || len(preferences.UnverifiedTokens) > 0 || len(preferences.Collectibles) > 0) &&
len(preferences.Accounts) == 0 {
return ErrorNoAccountProvidedWithTokenOrCollectible
}
return nil
}

View File

@ -6,9 +6,11 @@ import (
"io/ioutil"
"net/http"
neturl "net/url"
"strings"
"github.com/keighl/metabolize"
"go.uber.org/zap"
"golang.org/x/net/html"
"github.com/status-im/status-go/images"
"github.com/status-im/status-go/protocol/common"
@ -38,6 +40,43 @@ func NewOpenGraphUnfurler(URL *neturl.URL, logger *zap.Logger, httpClient *http.
}
}
func GetFavicon(bodyBytes []byte) string {
htmlTokens := html.NewTokenizer(bytes.NewBuffer(bodyBytes))
loop:
for {
tt := htmlTokens.Next()
switch tt {
case html.ErrorToken:
break loop
case html.StartTagToken:
t := htmlTokens.Token()
if t.Data != "link" {
continue
}
isIcon := false
href := ""
for _, attr := range t.Attr {
k := attr.Key
v := attr.Val
if k == "rel" && (v == "icon" || v == "shortcut icon") {
isIcon = true
} else if k == "href" &&
(strings.Contains(v, ".ico") ||
strings.Contains(v, ".png") ||
strings.Contains(v, ".svg")) {
href = v
}
}
if isIcon && href != "" {
return href
}
}
}
return ""
}
func (u *OpenGraphUnfurler) Unfurl() (*common.LinkPreview, error) {
preview := newDefaultLinkPreview(u.url)
preview.Type = protobuf.UnfurledLink_LINK
@ -58,6 +97,13 @@ func (u *OpenGraphUnfurler) Unfurl() (*common.LinkPreview, error) {
return preview, fmt.Errorf("failed to parse OpenGraph data")
}
faviconPath := GetFavicon(bodyBytes)
t, err := fetchImage(u.logger, u.httpClient, faviconPath, false)
if err != nil {
u.logger.Info("failed to fetch favicon", zap.String("url", u.url.String()), zap.Error(err))
} else {
preview.Favicon.DataURI = t.DataURI
}
// There are URLs like https://wikipedia.org/ that don't have an OpenGraph
// title tag, but article pages do. In the future, we can fallback to the
// website's title by using the <title> tag.
@ -66,7 +112,7 @@ func (u *OpenGraphUnfurler) Unfurl() (*common.LinkPreview, error) {
}
if ogMetadata.ThumbnailURL != "" {
t, err := fetchThumbnail(u.logger, u.httpClient, ogMetadata.ThumbnailURL)
t, err := fetchImage(u.logger, u.httpClient, ogMetadata.ThumbnailURL, true)
if err != nil {
// Given we want to fetch thumbnails on a best-effort basis, if an error
// happens we simply log it.
@ -78,24 +124,25 @@ func (u *OpenGraphUnfurler) Unfurl() (*common.LinkPreview, error) {
preview.Title = ogMetadata.Title
preview.Description = ogMetadata.Description
return preview, nil
}
func fetchThumbnail(logger *zap.Logger, httpClient *http.Client, url string) (common.LinkPreviewThumbnail, error) {
func fetchImage(logger *zap.Logger, httpClient *http.Client, url string, getDimensions bool) (common.LinkPreviewThumbnail, error) {
var thumbnail common.LinkPreviewThumbnail
imgBytes, err := fetchBody(logger, httpClient, url, nil)
if err != nil {
return thumbnail, fmt.Errorf("could not fetch thumbnail url='%s': %w", url, err)
}
width, height, err := images.GetImageDimensions(imgBytes)
if err != nil {
return thumbnail, fmt.Errorf("could not get image dimensions url='%s': %w", url, err)
if getDimensions {
width, height, err := images.GetImageDimensions(imgBytes)
if err != nil {
return thumbnail, fmt.Errorf("could not get image dimensions url='%s': %w", url, err)
}
thumbnail.Width = width
thumbnail.Height = height
}
thumbnail.Width = width
thumbnail.Height = height
dataURI, err := images.GetPayloadDataURI(imgBytes)
if err != nil {
return thumbnail, fmt.Errorf("could not build data URI url='%s': %w", url, err)

View File

@ -34,6 +34,8 @@ LEFT JOIN discord_message_authors m2_dm_author
ON m2_dm.author_id = m2_dm_author.id
LEFT JOIN bridge_messages bm
ON m1.id = bm.user_messages_id
LEFT JOIN bridge_messages bm_response
ON m2.id = bm_response.user_messages_id
`
var basicInsertDiscordMessageAuthorQuery = `INSERT OR REPLACE INTO discord_message_authors(id,name,discriminator,nickname,avatar_url, avatar_image_payload) VALUES (?,?,?,?,?,?)`
@ -205,7 +207,12 @@ func (db sqlitePersistence) tableUserMessagesAllFieldsJoin() string {
COALESCE(bm.user_id, ""),
COALESCE(bm.content, ""),
COALESCE(bm.message_id, ""),
COALESCE(bm.parent_message_id, "")`
COALESCE(bm.parent_message_id, ""),
COALESCE(bm_response.bridge_name, ""),
COALESCE(bm_response.user_name, ""),
COALESCE(bm_response.user_avatar, ""),
COALESCE(bm_response.user_id, ""),
COALESCE(bm_response.content, "")`
}
func (db sqlitePersistence) tableUserMessagesAllFieldsCount() int {
@ -256,6 +263,8 @@ func (db sqlitePersistence) tableUserMessagesScanAllFields(row scanner, message
}
bridgeMessage := &protobuf.BridgeMessage{}
quotedBridgeMessage := &protobuf.BridgeMessage{}
quotedDiscordMessage := &protobuf.DiscordMessage{
Author: &protobuf.DiscordMessageAuthor{},
}
@ -354,6 +363,11 @@ func (db sqlitePersistence) tableUserMessagesScanAllFields(row scanner, message
&bridgeMessage.Content,
&bridgeMessage.MessageID,
&bridgeMessage.ParentMessageID,
&quotedBridgeMessage.BridgeName,
&quotedBridgeMessage.UserName,
&quotedBridgeMessage.UserAvatar,
&quotedBridgeMessage.UserID,
&quotedBridgeMessage.Content,
}
err := row.Scan(append(args, others...)...)
if err != nil {
@ -407,6 +421,9 @@ func (db sqlitePersistence) tableUserMessagesScanAllFields(row scanner, message
if message.QuotedMessage.ContentType == int64(protobuf.ChatMessage_DISCORD_MESSAGE) {
message.QuotedMessage.DiscordMessage = quotedDiscordMessage
}
if message.QuotedMessage.ContentType == int64(protobuf.ChatMessage_BRIDGE_MESSAGE) {
message.QuotedMessage.BridgeMessage = quotedBridgeMessage
}
}
}
message.Alias = alias.String
@ -648,6 +665,9 @@ func (db sqlitePersistence) messageByID(tx *sql.Tx, id string) (*common.Message,
}
func (db sqlitePersistence) albumMessages(chatID, albumID string) ([]*common.Message, error) {
if albumID == "" {
return nil, nil
}
query := db.buildMessagesQuery("WHERE m1.album_id = ? and m1.local_chat_id = ?")
rows, err := db.db.Query(query, albumID, chatID)
if err != nil {
@ -1191,6 +1211,9 @@ func (db sqlitePersistence) PinnedMessageByChatIDs(chatIDs []string, currCursor
LEFT JOIN bridge_messages bm
ON m1.id = bm.user_messages_id
LEFT JOIN bridge_messages bm_response
ON m2.id = bm_response.user_messages_id
WHERE
pm.pinned = 1
AND NOT(m1.hide) AND m1.local_chat_id IN %s %s
@ -1529,6 +1552,22 @@ func (db sqlitePersistence) SaveMessages(messages []*common.Message) (err error)
if msg.ContentType == protobuf.ChatMessage_BRIDGE_MESSAGE {
err = db.saveBridgeMessage(tx, msg.GetBridgeMessage(), msg.ID)
if err != nil {
return
}
// handle replies
err = db.findAndUpdateReplies(tx, msg.GetBridgeMessage().MessageID, msg.ID)
if err != nil {
return
}
parentMessageID := msg.GetBridgeMessage().ParentMessageID
if parentMessageID != "" {
err = db.findAndUpdateRepliedTo(tx, parentMessageID, msg.ID)
if err != nil {
return
}
}
}
}
return
@ -1998,11 +2037,11 @@ func (db sqlitePersistence) MarkMessageAsUnread(chatID string, messageID string)
}
_, err = tx.Exec(
`UPDATE user_messages
SET seen = 0
WHERE local_chat_id = ?
AND seen = 1
AND NOT(mentioned OR replied)
`UPDATE user_messages
SET seen = 0
WHERE local_chat_id = ?
AND seen = 1
AND NOT(mentioned OR replied)
AND timestamp >= (SELECT timestamp FROM user_messages WHERE id = ?)`, chatID, messageID)
if err != nil {
return 0, 0, err
@ -2583,7 +2622,7 @@ func (db sqlitePersistence) GetDeletes(messageID string, from string) ([]*Delete
}
func (db sqlitePersistence) SaveOrUpdateDeleteForMeMessage(deleteForMeMessage *protobuf.SyncDeleteForMeMessage) error {
_, err := db.db.Exec(`INSERT OR REPLACE INTO user_messages_deleted_for_mes (clock, message_id)
_, err := db.db.Exec(`INSERT OR REPLACE INTO user_messages_deleted_for_mes (clock, message_id)
SELECT ?,? WHERE NOT EXISTS (SELECT 1 FROM user_messages_deleted_for_mes WHERE message_id = ? AND clock >= ?)`,
deleteForMeMessage.Clock, deleteForMeMessage.MessageId, deleteForMeMessage.MessageId, deleteForMeMessage.Clock)
return err
@ -2882,3 +2921,124 @@ func (db sqlitePersistence) saveBridgeMessage(tx *sql.Tx, message *protobuf.Brid
)
return
}
func (db sqlitePersistence) GetCommunityMemberMessagesToDelete(member string, communityID string) ([]*protobuf.DeleteCommunityMemberMessage, error) {
rows, err := db.db.Query(`SELECT m.id, m.chat_id FROM user_messages as m
INNER JOIN chats AS ch ON ch.id = m.chat_id AND ch.community_id = ?
WHERE m.source = ?`, communityID, member)
if err != nil {
return nil, err
}
defer rows.Close()
result := []*protobuf.DeleteCommunityMemberMessage{}
for rows.Next() {
removeMsgsInfo := &protobuf.DeleteCommunityMemberMessage{}
err = rows.Scan(&removeMsgsInfo.Id, &removeMsgsInfo.ChatId)
if err != nil {
return nil, err
}
result = append(result, removeMsgsInfo)
}
return result, nil
}
// Finds status messages id which are replies for bridgeMessageID
func (db sqlitePersistence) findStatusMessageIdsReplies(tx *sql.Tx, bridgeMessageID string) ([]string, error) {
rows, err := tx.Query(`SELECT user_messages_id FROM bridge_messages WHERE parent_message_id = ?`, bridgeMessageID)
if err != nil {
return []string{}, err
}
defer rows.Close()
var statusMessageIDs []string
for rows.Next() {
var statusMessageID string
err = rows.Scan(&statusMessageID)
if err != nil {
return []string{}, err
}
statusMessageIDs = append(statusMessageIDs, statusMessageID)
}
return statusMessageIDs, nil
}
// Finds status messages id which are replies for bridgeMessageID
func (db sqlitePersistence) findStatusMessageIdsRepliedTo(tx *sql.Tx, parentMessageID string) (string, error) {
rows, err := tx.Query(`SELECT user_messages_id FROM bridge_messages WHERE message_id = ?`, parentMessageID)
if err != nil {
return "", err
}
defer rows.Close()
if rows.Next() {
var statusMessageID string
err = rows.Scan(&statusMessageID)
if err != nil {
return "", err
}
return statusMessageID, nil
}
return "", nil
}
func (db sqlitePersistence) updateStatusMessagesWithResponse(tx *sql.Tx, statusMessagesToUpdate []string, responseValue string) error {
sql := "UPDATE user_messages SET response_to = ? WHERE id IN (?" + strings.Repeat(",?", len(statusMessagesToUpdate)-1) + ")"
stmt, err := tx.Prepare(sql)
if err != nil {
return err
}
defer stmt.Close()
args := make([]interface{}, 0, len(statusMessagesToUpdate)+1)
args = append(args, responseValue)
for _, msgToUpdate := range statusMessagesToUpdate {
args = append(args, msgToUpdate)
}
_, err = stmt.Exec(args...)
return err
}
// Finds if there are any messages that are replies to that message (in case replies were received earlier)
func (db sqlitePersistence) findAndUpdateReplies(tx *sql.Tx, bridgeMessageID string, statusMessageID string) error {
replyMessageIds, err := db.findStatusMessageIdsReplies(tx, bridgeMessageID)
if err != nil {
return err
}
if len(replyMessageIds) == 0 {
return nil
}
return db.updateStatusMessagesWithResponse(tx, replyMessageIds, statusMessageID)
}
func (db sqlitePersistence) findAndUpdateRepliedTo(tx *sql.Tx, discordParentMessageID string, statusMessageID string) error {
repliedMessageID, err := db.findStatusMessageIdsRepliedTo(tx, discordParentMessageID)
if err != nil {
return err
}
if repliedMessageID == "" {
return nil
}
return db.updateStatusMessagesWithResponse(tx, []string{statusMessageID}, repliedMessageID)
}
func (db sqlitePersistence) GetCommunityMemberAllMessages(member string, communityID string) ([]*common.Message, error) {
additionalRequestData := "INNER JOIN chats AS ch ON ch.id = m1.chat_id AND ch.community_id = ? WHERE m1.source = ?"
query := db.buildMessagesQueryWithAdditionalFields("", additionalRequestData)
rows, err := db.db.Query(query, communityID, member)
if err != nil {
if err == sql.ErrNoRows {
return []*common.Message{}, nil
}
return nil, err
}
return getMessagesFromScanRows(db, rows, false)
}

View File

@ -55,6 +55,7 @@ import (
"github.com/status-im/status-go/protocol/pushnotificationserver"
"github.com/status-im/status-go/protocol/requests"
"github.com/status-im/status-go/protocol/sqlite"
"github.com/status-im/status-go/protocol/storenodes"
"github.com/status-im/status-go/protocol/transport"
v1protocol "github.com/status-im/status-go/protocol/v1"
"github.com/status-im/status-go/protocol/verification"
@ -72,16 +73,13 @@ import (
"github.com/status-im/status-go/telemetry"
)
// todo: kozieiev: get rid of wakutransp word
type chatContext string
const (
PubKeyStringLength = 132
transactionSentTxt = "Transaction sent"
publicChat chatContext = "public-chat"
privateChat chatContext = "private-chat"
publicChat ChatContext = "public-chat"
privateChat ChatContext = "private-chat"
)
var communityAdvertiseIntervalSecond int64 = 60 * 60
@ -134,6 +132,7 @@ type Messenger struct {
modifiedInstallations *stringBoolMap
installationID string
mailserverCycle mailserverCycle
communityStorenodes *storenodes.CommunityStorenodes
database *sql.DB
multiAccounts *multiaccounts.Database
settings *accounts.Database
@ -142,6 +141,7 @@ type Messenger struct {
browserDatabase *browsers.Database
httpServer *server.MediaServer
started bool
quit chan struct{}
ctx context.Context
cancel context.CancelFunc
@ -164,7 +164,7 @@ type Messenger struct {
// TODO(samyoul) Determine if/how the remaining usage of this mutex can be removed
mutex sync.Mutex
mailPeersMutex sync.Mutex
mailPeersMutex sync.RWMutex
handleMessagesMutex sync.Mutex
handleImportMessagesMutex sync.Mutex
@ -449,17 +449,16 @@ func NewMessenger(
ensVerifier := ens.New(node, logger, transp, database, c.verifyENSURL, c.verifyENSContractAddress)
var walletAPI *wallet.API
if c.walletService != nil {
walletAPI = wallet.NewAPI(c.walletService)
}
managerOptions := []communities.ManagerOption{
communities.WithAccountManager(c.accountsManager),
}
if walletAPI != nil {
var walletAPI *wallet.API
if c.walletService != nil {
walletAPI = wallet.NewAPI(c.walletService)
managerOptions = append(managerOptions, communities.WithCollectiblesManager(walletAPI))
} else if c.collectiblesManager != nil {
managerOptions = append(managerOptions, communities.WithCollectiblesManager(c.collectiblesManager))
}
if c.tokenManager != nil {
@ -544,6 +543,7 @@ func NewMessenger(
availabilitySubscriptions: make([]chan struct{}, 0),
},
mailserversDatabase: c.mailserversDatabase,
communityStorenodes: storenodes.NewCommunityStorenodes(storenodes.NewDB(database), logger),
account: c.account,
quit: make(chan struct{}),
ctx: ctx,
@ -681,7 +681,8 @@ func (m *Messenger) shouldResendMessage(message *common.RawMessage, t common.Tim
return false, nil
}
//exponential backoff depends on how many attempts to send message already made
backoff := uint64(math.Pow(2, float64(message.SendCount-1))) * uint64(m.config.messageResendMinDelay) * uint64(time.Second.Milliseconds())
power := math.Pow(2, float64(message.SendCount-1))
backoff := uint64(power) * uint64(m.config.messageResendMinDelay.Milliseconds())
backoffElapsed := t.GetCurrentTime() > (message.LastSent + backoff)
return backoffElapsed, nil
}
@ -744,6 +745,11 @@ func (m *Messenger) ToBackground() {
}
func (m *Messenger) Start() (*MessengerResponse, error) {
if m.started {
return nil, errors.New("messenger already started")
}
m.started = true
now := time.Now().UnixMilli()
if err := m.settings.CheckAndDeleteExpiredKeypairsAndAccounts(uint64(now)); err != nil {
return nil, err
@ -828,7 +834,9 @@ func (m *Messenger) Start() (*MessengerResponse, error) {
m.startSyncSettingsLoop()
m.startSettingsChangesLoop()
m.startCommunityRekeyLoop()
m.startCuratedCommunitiesUpdateLoop()
if m.config.codeControlFlags.CuratedCommunitiesUpdateLoopEnabled {
m.startCuratedCommunitiesUpdateLoop()
}
m.startMessageSegmentsCleanupLoop()
if err := m.cleanTopics(); err != nil {
@ -847,6 +855,10 @@ func (m *Messenger) Start() (*MessengerResponse, error) {
return nil, err
}
if err := m.communityStorenodes.ReloadFromDB(); err != nil {
return nil, err
}
controlledCommunities, err := m.communitiesManager.Controlled()
if err != nil {
return nil, err
@ -950,7 +962,7 @@ func (m *Messenger) handleConnectionChange(online bool) {
}
// Start fetching messages from store nodes
if online && m.config.featureFlags.AutoRequestHistoricMessages {
if online && m.config.codeControlFlags.AutoRequestHistoricMessages {
m.asyncRequestAllHistoricMessages()
}
@ -1114,7 +1126,9 @@ func (m *Messenger) handleStandaloneChatIdentity(chat *Chat) error {
return nil
}
ci, err := m.createChatIdentity(publicChat)
chatContext := GetChatContextFromChatType(chat.ChatType)
ci, err := m.createChatIdentity(chatContext)
if err != nil {
return err
}
@ -1261,7 +1275,7 @@ func (m *Messenger) shouldPublishChatIdentity(chatID string) (bool, error) {
// createChatIdentity creates a context based protobuf.ChatIdentity.
// context 'public-chat' will attach only the 'thumbnail' IdentityImage
// context 'private-chat' will attach all IdentityImage
func (m *Messenger) createChatIdentity(context chatContext) (*protobuf.ChatIdentity, error) {
func (m *Messenger) createChatIdentity(context ChatContext) (*protobuf.ChatIdentity, error) {
m.logger.Info(fmt.Sprintf("account keyUID '%s'", m.account.KeyUID))
m.logger.Info(fmt.Sprintf("context '%s'", context))
@ -1311,7 +1325,7 @@ func (m *Messenger) adaptIdentityImageToProtobuf(img *images.IdentityImage) *pro
}
}
func (m *Messenger) attachIdentityImagesToChatIdentity(context chatContext, ci *protobuf.ChatIdentity) error {
func (m *Messenger) attachIdentityImagesToChatIdentity(context ChatContext, ci *protobuf.ChatIdentity) error {
s, err := m.getSettings()
if err != nil {
return err
@ -1414,6 +1428,13 @@ func (m *Messenger) handleEncryptionLayerSubscriptions(subscriptions *encryption
m.logger.Error("failed to clean processed messages", zap.Error(err))
}
case keys := <-subscriptions.NewHashRatchetKeys:
if m.communitiesManager == nil {
continue
}
if err := m.communitiesManager.NewHashRatchetKeys(keys); err != nil {
m.logger.Error("failed to invalidate cache for decrypted communities", zap.Error(err))
}
case <-subscriptions.Quit:
m.logger.Debug("quitting encryption subscription loop")
return
@ -1537,7 +1558,7 @@ func (m *Messenger) watchChatsAndCommunitiesToUnmute() {
go func() {
for {
select {
case <-time.After(3 * time.Second): // Poll every 3 seconds
case <-time.After(1 * time.Minute):
response := &MessengerResponse{}
m.allChats.Range(func(chatID string, c *Chat) bool {
chatMuteTill, _ := time.Parse(time.RFC3339, c.MuteTill.Format(time.RFC3339))
@ -1572,7 +1593,7 @@ func (m *Messenger) watchCommunitiesToUnmute() {
go func() {
for {
select {
case <-time.After(3 * time.Second): // Poll every 3 seconds
case <-time.After(1 * time.Minute):
response, err := m.CheckCommunitiesToUnmute()
if err != nil {
return
@ -1930,6 +1951,15 @@ func (m *Messenger) Shutdown() (err error) {
if m == nil {
return nil
}
select {
case _, ok := <-m.quit:
if !ok {
return errors.New("messenger already shutdown")
}
default:
}
close(m.quit)
m.cancel()
m.shutdownWaitGroup.Wait()
@ -2205,22 +2235,26 @@ func (m *Messenger) dispatchMessage(ctx context.Context, rawMessage common.RawMe
if err != nil {
return rawMessage, err
}
case ChatTypeCommunityChat:
case ChatTypeCommunityChat:
community, err := m.communitiesManager.GetByIDString(chat.CommunityID)
if err != nil {
return rawMessage, err
}
rawMessage.PubsubTopic = community.PubsubTopic()
canPost, err := m.communitiesManager.CanPost(&m.identity.PublicKey, chat.CommunityID, chat.CommunityChatID())
canPost, err := m.communitiesManager.CanPost(&m.identity.PublicKey, chat.CommunityID, chat.CommunityChatID(), rawMessage.MessageType)
if err != nil {
return rawMessage, err
}
if !canPost {
m.logger.Error("can't post on chat", zap.String("chat-id", chat.ID), zap.String("chat-name", chat.Name))
return rawMessage, errors.New("can't post on chat")
m.logger.Error("can't post on chat",
zap.String("chatID", chat.ID),
zap.String("chatName", chat.Name),
zap.Any("messageType", rawMessage.MessageType),
)
return rawMessage, fmt.Errorf("can't post message type '%d' on chat '%s'", rawMessage.MessageType, chat.ID)
}
logger.Debug("sending community chat message", zap.String("chatName", chat.Name))
@ -2835,7 +2869,17 @@ func (m *Messenger) SyncDevices(ctx context.Context, ensName, photoPath string,
return err
}
return m.syncSocialLinks(context.Background(), rawMessageHandler)
err = m.syncSocialLinks(context.Background(), rawMessageHandler)
if err != nil {
return err
}
err = m.syncProfileShowcasePreferences(context.Background(), rawMessageHandler)
if err != nil {
return err
}
return nil
}
func (m *Messenger) syncContactRequestDecision(ctx context.Context, requestID string, accepted bool, rawMessageHandler RawMessageHandler) error {
@ -3105,6 +3149,36 @@ func (m *Messenger) syncContact(ctx context.Context, contact *Contact, rawMessag
return m.saveChat(chat)
}
func (m *Messenger) propagateSyncInstallationCommunityWithHRKeys(msg *protobuf.SyncInstallationCommunity, c *communities.Community) error {
communityKeys, err := m.encryptor.GetAllHRKeysMarshaledV1(c.ID())
if err != nil {
return err
}
msg.EncryptionKeysV1 = communityKeys
communityAndChannelKeys := [][]byte{}
communityKeys, err = m.encryptor.GetAllHRKeysMarshaledV2(c.ID())
if err != nil {
return err
}
if len(communityKeys) > 0 {
communityAndChannelKeys = append(communityAndChannelKeys, communityKeys)
}
for channelID := range c.Chats() {
channelKeys, err := m.encryptor.GetAllHRKeysMarshaledV2([]byte(c.IDString() + channelID))
if err != nil {
return err
}
if len(channelKeys) > 0 {
communityAndChannelKeys = append(communityAndChannelKeys, channelKeys)
}
}
msg.EncryptionKeysV2 = communityAndChannelKeys
return nil
}
func (m *Messenger) syncCommunity(ctx context.Context, community *communities.Community, rawMessageHandler RawMessageHandler) error {
logger := m.logger.Named("syncCommunity")
if !m.hasPairedDevices() {
@ -3130,11 +3204,10 @@ func (m *Messenger) syncCommunity(ctx context.Context, community *communities.Co
return err
}
encodedKeys, err := m.encryptor.GetAllHREncodedKeys(community.ID())
err = m.propagateSyncInstallationCommunityWithHRKeys(syncMessage, community)
if err != nil {
return err
}
syncMessage.EncryptionKeys = encodedKeys
encodedMessage, err := proto.Marshal(syncMessage)
if err != nil {
@ -3416,6 +3489,10 @@ func (m *Messenger) GetStats() types.StatsSummary {
return m.transport.GetStats()
}
func (m *Messenger) GetTransport() *transport.Transport {
return m.transport
}
type CurrentMessageState struct {
// Message is the protobuf message received
Message *protobuf.ChatMessage
@ -3631,6 +3708,19 @@ func (m *Messenger) outputToCSV(timestamp uint32, messageID types.HexBytes, from
}
}
func (m *Messenger) shouldSkipDuplicate(messageType protobuf.ApplicationMetadataMessage_Type) bool {
// Permit re-processing of ApplicationMetadataMessage_COMMUNITY_DESCRIPTION messages,
// as they may be queued pending receipt of decryption keys.
allowedDuplicateTypes := map[protobuf.ApplicationMetadataMessage_Type]struct{}{
protobuf.ApplicationMetadataMessage_COMMUNITY_DESCRIPTION: struct{}{},
}
if _, isAllowedDuplicate := allowedDuplicateTypes[messageType]; isAllowedDuplicate {
return false
}
return true
}
func (m *Messenger) handleImportedMessages(messagesToHandle map[transport.Filter][]*types.Message) error {
messageState := m.buildMessageState()
@ -3654,14 +3744,21 @@ func (m *Messenger) handleImportedMessages(messagesToHandle map[transport.Filter
publicKey := msg.SigPubKey()
senderID := contactIDFromPublicKey(publicKey)
if len(msg.EncryptionLayer.HashRatchetInfo) != 0 {
err := m.communitiesManager.NewHashRatchetKeys(msg.EncryptionLayer.HashRatchetInfo)
if err != nil {
m.logger.Warn("failed to invalidate communities description cache", zap.Error(err))
}
}
// Don't process duplicates
messageID := msg.TransportLayer.Message.ThirdPartyID
exists, err := m.messageExists(messageID, messageState.ExistingMessagesMap)
if err != nil {
logger.Warn("failed to check message exists", zap.Error(err))
}
if exists {
logger.Debug("messageExists", zap.String("messageID", messageID))
if exists && m.shouldSkipDuplicate(msg.ApplicationLayer.Type) {
logger.Debug("skipping duplicate", zap.String("messageID", messageID))
continue
}
@ -3859,8 +3956,8 @@ func (m *Messenger) handleRetrievedMessages(chatWithMessages map[transport.Filte
if err != nil {
logger.Warn("failed to check message exists", zap.Error(err))
}
if exists {
logger.Debug("messageExists", zap.String("messageID", messageID))
if exists && m.shouldSkipDuplicate(msg.ApplicationLayer.Type) {
logger.Debug("skipping duplicate", zap.String("messageID", messageID))
continue
}
@ -4143,9 +4240,8 @@ func (m *Messenger) MessageByChatID(chatID, cursor string, limit int) ([]*common
}
if m.httpServer != nil {
for idx := range msgs {
err = m.prepareMessage(msgs[idx], m.httpServer)
for _, msg := range msgs {
err = m.prepareMessage(msg, m.httpServer)
if err != nil {
return nil, "", err
}
@ -4156,13 +4252,13 @@ func (m *Messenger) MessageByChatID(chatID, cursor string, limit int) ([]*common
}
func (m *Messenger) prepareMessages(messages map[string]*common.Message) error {
if m.httpServer != nil {
for idx := range messages {
err := m.prepareMessage(messages[idx], m.httpServer)
if err != nil {
return err
}
if m.httpServer == nil {
return nil
}
for idx := range messages {
err := m.prepareMessage(messages[idx], m.httpServer)
if err != nil {
return err
}
}
return nil
@ -4179,6 +4275,15 @@ func extractQuotedImages(messages []*common.Message, s *server.MediaServer) []st
return quotedImages
}
func (m *Messenger) prepareTokenData(tokenData *ActivityTokenData, s *server.MediaServer) error {
if tokenData.TokenType == int(protobuf.CommunityTokenType_ERC721) {
tokenData.ImageURL = s.MakeWalletCollectibleImagesURL(tokenData.CollectibleID)
} else if tokenData.TokenType == int(protobuf.CommunityTokenType_ERC20) {
tokenData.ImageURL = s.MakeCommunityTokenImagesURL(tokenData.CommunityID, tokenData.ChainID, tokenData.Symbol)
}
return nil
}
func (m *Messenger) prepareMessage(msg *common.Message, s *server.MediaServer) error {
if msg.QuotedMessage != nil && msg.QuotedMessage.ContentType == int64(protobuf.ChatMessage_IMAGE) {
msg.QuotedMessage.ImageLocalURL = s.MakeImageURL(msg.QuotedMessage.ID)
@ -4192,18 +4297,22 @@ func (m *Messenger) prepareMessage(msg *common.Message, s *server.MediaServer) e
}
if quotedMessage.ChatMessage != nil {
image := quotedMessage.ChatMessage.GetImage()
albumID := quotedMessage.ChatMessage.GetImage().AlbumId
albumMessages, err := m.persistence.albumMessages(quotedMessage.LocalChatID, albumID)
if err != nil {
return err
}
var quotedImages = extractQuotedImages(albumMessages, s)
if image != nil && image.GetAlbumId() != "" {
albumMessages, err := m.persistence.albumMessages(quotedMessage.LocalChatID, albumID)
if err != nil {
return err
}
quotedImages := extractQuotedImages(albumMessages, s)
quotedImagesJSON, err := json.Marshal(quotedImages)
if err != nil {
return err
}
if quotedImagesJSON, err := json.Marshal(quotedImages); err == nil {
msg.QuotedMessage.AlbumImages = quotedImagesJSON
} else {
return err
}
}
}
@ -4264,8 +4373,7 @@ func (m *Messenger) prepareMessage(msg *common.Message, s *server.MediaServer) e
if msg.ContentType == protobuf.ChatMessage_STICKER {
msg.StickerLocalURL = s.MakeStickerURL(msg.GetSticker().Hash)
}
msg.LinkPreviews = msg.ConvertFromProtoToLinkPreviews(s.MakeLinkPreviewThumbnailURL)
msg.LinkPreviews = msg.ConvertFromProtoToLinkPreviews(s.MakeLinkPreviewThumbnailURL, s.MakeLinkPreviewFaviconURL)
msg.StatusLinkPreviews = msg.ConvertFromProtoToStatusLinkPreviews(s.MakeStatusLinkPreviewThumbnailURL)
return nil
@ -5619,143 +5727,6 @@ func generateAliasAndIdenticon(pk string) (string, string, error) {
}
func (m *Messenger) SendEmojiReaction(ctx context.Context, chatID, messageID string, emojiID protobuf.EmojiReaction_Type) (*MessengerResponse, error) {
var response MessengerResponse
chat, ok := m.allChats.Load(chatID)
if !ok {
return nil, ErrChatNotFound
}
clock, _ := chat.NextClockAndTimestamp(m.getTimesource())
emojiR := &EmojiReaction{
EmojiReaction: &protobuf.EmojiReaction{
Clock: clock,
MessageId: messageID,
ChatId: chatID,
Type: emojiID,
},
LocalChatID: chatID,
From: types.EncodeHex(crypto.FromECDSAPub(&m.identity.PublicKey)),
}
encodedMessage, err := m.encodeChatEntity(chat, emojiR)
if err != nil {
return nil, err
}
_, err = m.dispatchMessage(ctx, common.RawMessage{
LocalChatID: chatID,
Payload: encodedMessage,
SkipGroupMessageWrap: true,
MessageType: protobuf.ApplicationMetadataMessage_EMOJI_REACTION,
// Don't resend using datasync, that would create quite a lot
// of traffic if clicking too eagelry
ResendAutomatically: false,
})
if err != nil {
return nil, err
}
response.AddEmojiReaction(emojiR)
response.AddChat(chat)
err = m.persistence.SaveEmojiReaction(emojiR)
if err != nil {
return nil, errors.Wrap(err, "Can't save emoji reaction in db")
}
return &response, nil
}
func (m *Messenger) EmojiReactionsByChatID(chatID string, cursor string, limit int) ([]*EmojiReaction, error) {
chat, err := m.persistence.Chat(chatID)
if err != nil {
return nil, err
}
if chat.Timeline() {
var chatIDs = []string{"@" + contactIDFromPublicKey(&m.identity.PublicKey)}
m.allContacts.Range(func(contactID string, contact *Contact) (shouldContinue bool) {
if contact.added() {
chatIDs = append(chatIDs, "@"+contact.ID)
}
return true
})
return m.persistence.EmojiReactionsByChatIDs(chatIDs, cursor, limit)
}
return m.persistence.EmojiReactionsByChatID(chatID, cursor, limit)
}
func (m *Messenger) EmojiReactionsByChatIDMessageID(chatID string, messageID string) ([]*EmojiReaction, error) {
_, err := m.persistence.Chat(chatID)
if err != nil {
return nil, err
}
return m.persistence.EmojiReactionsByChatIDMessageID(chatID, messageID)
}
func (m *Messenger) SendEmojiReactionRetraction(ctx context.Context, emojiReactionID string) (*MessengerResponse, error) {
emojiR, err := m.persistence.EmojiReactionByID(emojiReactionID)
if err != nil {
return nil, err
}
// Check that the sender is the key owner
pk := types.EncodeHex(crypto.FromECDSAPub(&m.identity.PublicKey))
if emojiR.From != pk {
return nil, errors.Errorf("identity mismatch, "+
"emoji reactions can only be retracted by the reaction sender, "+
"emoji reaction sent by '%s', current identity '%s'",
emojiR.From, pk,
)
}
// Get chat and clock
chat, ok := m.allChats.Load(emojiR.GetChatId())
if !ok {
return nil, ErrChatNotFound
}
clock, _ := chat.NextClockAndTimestamp(m.getTimesource())
// Update the relevant fields
emojiR.Clock = clock
emojiR.Retracted = true
encodedMessage, err := m.encodeChatEntity(chat, emojiR)
if err != nil {
return nil, err
}
// Send the marshalled EmojiReactionRetraction protobuf
_, err = m.dispatchMessage(ctx, common.RawMessage{
LocalChatID: emojiR.GetChatId(),
Payload: encodedMessage,
SkipGroupMessageWrap: true,
MessageType: protobuf.ApplicationMetadataMessage_EMOJI_REACTION,
// Don't resend using datasync, that would create quite a lot
// of traffic if clicking too eagelry
ResendAutomatically: false,
})
if err != nil {
return nil, err
}
// Update MessengerResponse
response := MessengerResponse{}
emojiR.Retracted = true
response.AddEmojiReaction(emojiR)
response.AddChat(chat)
// Persist retraction state for emoji reaction
err = m.persistence.SaveEmojiReaction(emojiR)
if err != nil {
return nil, err
}
return &response, nil
}
func (m *Messenger) encodeChatEntity(chat *Chat, message common.ChatEntity) ([]byte, error) {
var encodedMessage []byte
var err error

View File

@ -70,6 +70,14 @@ func (m *Messenger) ActivityCenterNotifications(request ActivityCenterNotificati
}
}
}
if notification.TokenData != nil {
if notification.Type == ActivityCenterNotificationTypeCommunityTokenReceived || notification.Type == ActivityCenterNotificationTypeFirstCommunityTokenReceived {
err = m.prepareTokenData(notification.TokenData, m.httpServer)
if err != nil {
return nil, err
}
}
}
}
}

View File

@ -315,11 +315,10 @@ func (m *Messenger) backupCommunities(ctx context.Context, clock uint64) ([]*pro
return nil, err
}
encodedKeys, err := m.encryptor.GetAllHREncodedKeys(c.ID())
err = m.propagateSyncInstallationCommunityWithHRKeys(syncMessage, c)
if err != nil {
return nil, err
}
syncMessage.EncryptionKeys = encodedKeys
backupMessage := &protobuf.Backup{
Communities: []*protobuf.SyncInstallationCommunity{syncMessage},
@ -475,14 +474,20 @@ func (m *Messenger) backupProfile(ctx context.Context, clock uint64) ([]*protobu
}
}
profileShowcasePreferences, err := m.GetProfileShowcasePreferences()
if err != nil {
return nil, err
}
backupMessage := &protobuf.Backup{
Profile: &protobuf.BackedUpProfile{
KeyUid: keyUID,
DisplayName: displayName,
Pictures: pictureProtos,
DisplayNameClock: displayNameClock,
SocialLinks: syncSocialLinks,
EnsUsernameDetails: ensUsernameDetailProtos,
KeyUid: keyUID,
DisplayName: displayName,
Pictures: pictureProtos,
DisplayNameClock: displayNameClock,
SocialLinks: syncSocialLinks,
EnsUsernameDetails: ensUsernameDetailProtos,
ProfileShowcasePreferences: ToProfileShowcasePreferencesProto(profileShowcasePreferences),
},
}
@ -492,7 +497,7 @@ func (m *Messenger) backupProfile(ctx context.Context, clock uint64) ([]*protobu
}
func (m *Messenger) backupKeypairs() ([]*protobuf.Backup, error) {
keypairs, err := m.settings.GetActiveKeypairs()
keypairs, err := m.settings.GetAllKeypairs()
if err != nil {
return nil, err
}

View File

@ -7,6 +7,7 @@ import (
"github.com/status-im/status-go/images"
"github.com/status-im/status-go/multiaccounts/errors"
"github.com/status-im/status-go/multiaccounts/settings"
"github.com/status-im/status-go/protocol/identity"
"github.com/status-im/status-go/protocol/protobuf"
v1protocol "github.com/status-im/status-go/protocol/v1"
@ -177,6 +178,14 @@ func (m *Messenger) handleBackedUpProfile(message *protobuf.BackedUpProfile, bac
return err
}
profileShowcasePreferences, err := m.saveProfileShowcasePreferencesProto(message.ProfileShowcasePreferences, false)
if err != nil {
return err
}
if profileShowcasePreferences != nil {
response.SetProfileShowcasePreferences(profileShowcasePreferences)
}
var ensUsernameDetails []*ensservice.UsernameDetail
for _, d := range message.EnsUsernameDetails {
dd, err := m.saveEnsUsernameDetailProto(d)
@ -212,12 +221,21 @@ func (m *Messenger) handleBackedUpSettings(message *protobuf.SyncSetting) error
if settingField != nil {
if message.GetType() == protobuf.SyncSetting_PREFERRED_NAME && message.GetValueString() != "" {
m.account.Name = message.GetValueString()
err = m.multiAccounts.SaveAccount(*m.account)
displayNameClock, err := m.settings.GetSettingLastSynced(settings.DisplayName)
if err != nil {
m.logger.Warn("[handleBackedUpSettings] failed to save account", zap.Error(err))
m.logger.Warn("failed to get last synced clock for display name", zap.Error(err))
return nil
}
// there is a race condition between display name and preferred name on updating m.account.Name, so we need to check the clock
// there is also a similar check within SaveSyncDisplayName
if displayNameClock < message.GetClock() {
m.account.Name = message.GetValueString()
err = m.multiAccounts.SaveAccount(*m.account)
if err != nil {
m.logger.Warn("[handleBackedUpSettings] failed to save account", zap.Error(err))
return nil
}
}
}
if m.config.messengerSignalsHandler != nil {
@ -242,7 +260,7 @@ func (m *Messenger) handleKeypair(message *protobuf.SyncKeypair) error {
}
// If user is recovering his account via seed phrase, but the backed up messages indicate that the profile keypair
// is a keycard related profile, then we need to remove related profile keycards (only profile, other keycards should remain).
if multiAcc != nil && multiAcc.KeyUID == message.KeyUid && multiAcc.KeycardPairing == "" && len(message.Keycards) > 0 {
if multiAcc != nil && multiAcc.KeyUID == message.KeyUid && !multiAcc.RefersToKeycard() && len(message.Keycards) > 0 {
message.Keycards = []*protobuf.SyncKeycard{}
}

View File

@ -7,6 +7,7 @@ import (
"encoding/json"
"errors"
"fmt"
"strings"
"sync"
"time"
@ -156,36 +157,6 @@ func (m *Messenger) publishCommunityEvents(community *communities.Community, msg
return err
}
func (m *Messenger) publishCommunityEventsRejected(community *communities.Community, msg *communities.CommunityEventsMessage) error {
if !community.IsControlNode() {
return communities.ErrNotControlNode
}
m.logger.Debug("publishing community events rejected", zap.Any("event", msg))
communityEventsMessage := msg.ToProtobuf()
communityEventsMessageRejected := &protobuf.CommunityEventsMessageRejected{
Msg: communityEventsMessage,
}
payload, err := proto.Marshal(communityEventsMessageRejected)
if err != nil {
return err
}
rawMessage := common.RawMessage{
Payload: payload,
Sender: community.PrivateKey(),
// we don't want to wrap in an encryption layer message
SkipEncryptionLayer: true,
MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_EVENTS_MESSAGE_REJECTED,
PubsubTopic: community.PubsubTopic(), // TODO: confirm if it should be sent in community pubsub topic
}
// TODO: resend in case of failure?
_, err = m.sender.SendPublic(context.Background(), types.EncodeHex(msg.CommunityID), rawMessage)
return err
}
func (m *Messenger) publishCommunityPrivilegedMemberSyncMessage(msg *communities.CommunityPrivilegedMemberSyncMessage) error {
m.logger.Debug("publishing privileged user sync message", zap.Any("event", msg))
@ -409,14 +380,6 @@ func (m *Messenger) handleCommunitiesSubscription(c chan *communities.Subscripti
}
}
if sub.CommunityEventsMessageInvalidClock != nil {
err := m.publishCommunityEventsRejected(sub.CommunityEventsMessageInvalidClock.Community,
sub.CommunityEventsMessageInvalidClock.CommunityEventsMessage)
if err != nil {
m.logger.Warn("failed to publish community events rejected", zap.Error(err))
}
}
if sub.AcceptedRequestsToJoin != nil {
for _, requestID := range sub.AcceptedRequestsToJoin {
accept := &requests.AcceptRequestToJoinCommunity{
@ -637,6 +600,31 @@ func (m *Messenger) JoinedCommunities() ([]*communities.Community, error) {
return m.communitiesManager.Joined()
}
func (m *Messenger) IsDisplayNameDupeOfCommunityMember(name string) (bool, error) {
controlled, err := m.communitiesManager.Controlled()
if err != nil {
return false, err
}
joined, err := m.communitiesManager.Joined()
if err != nil {
return false, err
}
for _, community := range append(controlled, joined...) {
for memberKey := range community.Members() {
contact := m.GetContactByID(memberKey)
if contact == nil {
continue
}
if strings.Compare(contact.DisplayName, name) == 0 {
return true, nil
}
}
}
return false, nil
}
func (m *Messenger) CommunityUpdateLastOpenedAt(communityID string) (int64, error) {
id, err := hexutil.Decode(communityID)
if err != nil {
@ -1565,11 +1553,16 @@ func (m *Messenger) acceptRequestToJoinCommunity(requestToJoin *communities.Requ
}
}
encryptedDescription, err := community.EncryptedDescription()
if err != nil {
return nil, err
}
requestToJoinResponseProto := &protobuf.CommunityRequestToJoinResponse{
Clock: community.Clock(),
Accepted: true,
CommunityId: community.ID(),
Community: community.Description(),
Community: encryptedDescription,
Grant: grant,
ProtectedTopicPrivateKey: crypto.FromECDSA(key),
Shard: community.Shard().Protobuffer(),
@ -1831,17 +1824,19 @@ func (m *Messenger) leaveCommunity(communityID types.HexBytes) (*MessengerRespon
return response, nil
}
func (m *Messenger) kickedOutOfCommunity(communityID types.HexBytes) (*MessengerResponse, error) {
func (m *Messenger) kickedOutOfCommunity(communityID types.HexBytes, spectateMode bool) (*MessengerResponse, error) {
response := &MessengerResponse{}
community, err := m.communitiesManager.KickedOutOfCommunity(communityID)
community, err := m.communitiesManager.KickedOutOfCommunity(communityID, spectateMode)
if err != nil {
return nil, err
}
err = m.DeleteProfileShowcaseCommunity(community)
if err != nil {
return nil, err
if !spectateMode {
err = m.DeleteProfileShowcaseCommunity(community)
if err != nil {
return nil, err
}
}
response.AddCommunity(community)
@ -2216,6 +2211,51 @@ func (m *Messenger) RemovePubsubTopicPrivateKey(topic string) error {
return m.transport.RemovePubsubTopicKey(topic)
}
func (m *Messenger) SetCommunityStorenodes(request *requests.SetCommunityStorenodes) (*MessengerResponse, error) {
if err := request.Validate(); err != nil {
return nil, err
}
community, err := m.communitiesManager.GetByID(request.CommunityID)
if err != nil {
return nil, err
}
if !community.IsControlNode() {
return nil, errors.New("not admin or owner")
}
if err := m.communityStorenodes.UpdateStorenodesInDB(request.CommunityID, request.Storenodes, 0); err != nil {
return nil, err
}
err = m.sendCommunityPublicStorenodesInfo(community, request.Storenodes)
if err != nil {
return nil, err
}
response := &MessengerResponse{
CommunityStorenodes: request.Storenodes,
}
return response, nil
}
func (m *Messenger) GetCommunityStorenodes(communityID types.HexBytes) (*MessengerResponse, error) {
community, err := m.communitiesManager.GetByID(communityID)
if err != nil {
return nil, err
}
if community == nil {
return nil, communities.ErrOrgNotFound
}
snodes, err := m.communityStorenodes.GetStorenodesFromDB(communityID)
if err != nil {
return nil, err
}
response := &MessengerResponse{
CommunityStorenodes: snodes,
}
return response, nil
}
func (m *Messenger) UpdateCommunityFilters(community *communities.Community) error {
defaultFilters := m.DefaultFilters(community)
publicFiltersToInit := make([]transport.FiltersToInitialize, 0, len(defaultFilters)+len(community.Chats()))
@ -2259,6 +2299,8 @@ func (m *Messenger) UpdateCommunityFilters(community *communities.Community) err
}
func (m *Messenger) CreateCommunityTokenPermission(request *requests.CreateCommunityTokenPermission) (*MessengerResponse, error) {
request.FillDeprecatedAmount()
if err := request.Validate(); err != nil {
return nil, err
}
@ -2279,6 +2321,12 @@ func (m *Messenger) CreateCommunityTokenPermission(request *requests.CreateCommu
}()
}
// ensure HRkeys are synced
err = m.syncCommunity(context.Background(), community, m.dispatchMessage)
if err != nil {
return nil, err
}
response := &MessengerResponse{}
response.AddCommunity(community)
response.CommunityChanges = []*communities.CommunityChanges{changes}
@ -2287,6 +2335,8 @@ func (m *Messenger) CreateCommunityTokenPermission(request *requests.CreateCommu
}
func (m *Messenger) EditCommunityTokenPermission(request *requests.EditCommunityTokenPermission) (*MessengerResponse, error) {
request.FillDeprecatedAmount()
if err := request.Validate(); err != nil {
return nil, err
}
@ -2342,6 +2392,23 @@ func (m *Messenger) DeleteCommunityTokenPermission(request *requests.DeleteCommu
return response, nil
}
func (m *Messenger) HandleCommunityReevaluatePermissionsRequest(state *ReceivedMessageState, request *protobuf.CommunityReevaluatePermissionsRequest, statusMessage *v1protocol.StatusMessage) error {
community, err := m.communitiesManager.GetByID(request.CommunityId)
if err != nil {
return err
}
if !community.IsControlNode() {
return communities.ErrNotControlNode
}
if !community.IsMemberTokenMaster(statusMessage.SigPubKey()) {
return communities.ErrNotAuthorized
}
return m.communitiesManager.ScheduleMembersReevaluation(request.CommunityId)
}
func (m *Messenger) ReevaluateCommunityMembersPermissions(request *requests.ReevaluateCommunityMembersPermissions) (*MessengerResponse, error) {
if err := request.Validate(); err != nil {
return nil, err
@ -2352,14 +2419,37 @@ func (m *Messenger) ReevaluateCommunityMembersPermissions(request *requests.Reev
return nil, err
}
if err = m.communitiesManager.ReevaluateCommunityMembersPermissions(community); err != nil {
return nil, err
if community.IsControlNode() {
err = m.communitiesManager.ScheduleMembersReevaluation(request.CommunityID)
if err != nil {
return nil, err
}
} else if community.IsTokenMaster() {
reevaluateRequest := &protobuf.CommunityReevaluatePermissionsRequest{
CommunityId: request.CommunityID,
}
encodedMessage, err := proto.Marshal(reevaluateRequest)
if err != nil {
return nil, err
}
rawMessage := common.RawMessage{
Payload: encodedMessage,
CommunityID: request.CommunityID,
SkipEncryptionLayer: true,
MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_REEVALUATE_PERMISSIONS_REQUEST,
PubsubTopic: community.PubsubTopic(),
}
_, err = m.SendMessageToControlNode(community, rawMessage)
if err != nil {
return nil, err
}
} else {
return nil, communities.ErrNotAuthorized
}
response := &MessengerResponse{}
response.AddCommunity(community)
return response, nil
return &MessengerResponse{}, nil
}
func (m *Messenger) EditCommunity(request *requests.EditCommunity) (*MessengerResponse, error) {
@ -2656,6 +2746,24 @@ func (m *Messenger) BanUserFromCommunity(ctx context.Context, request *requests.
}
response.AddCommunity(community)
if request.DeleteAllMessages && community.IsControlNode() {
deleteMessagesResponse, err := m.deleteCommunityMemberMessages(request.User.String(), request.CommunityID.String(), []*protobuf.DeleteCommunityMemberMessage{})
if err != nil {
return nil, err
}
err = response.Merge(deleteMessagesResponse)
if err != nil {
return nil, err
}
// signal client with community and messages changes
if m.config.messengerSignalsHandler != nil {
m.config.messengerSignalsHandler.MessengerResponse(deleteMessagesResponse)
}
}
return response, nil
}
@ -2791,6 +2899,21 @@ func (m *Messenger) handleCommunityDescription(state *ReceivedMessageState, sign
func (m *Messenger) handleCommunityResponse(state *ReceivedMessageState, communityResponse *communities.CommunityResponse) error {
community := communityResponse.Community
if len(communityResponse.Changes.MembersBanned) > 0 {
for memberID, deleteAllMessages := range communityResponse.Changes.MembersBanned {
if deleteAllMessages {
response, err := m.deleteCommunityMemberMessages(memberID, community.IDString(), []*protobuf.DeleteCommunityMemberMessage{})
if err != nil {
return err
}
if err = state.Response.Merge(response); err != nil {
return err
}
}
}
}
state.Response.AddCommunity(community)
state.Response.CommunityChanges = append(state.Response.CommunityChanges, communityResponse.Changes)
state.Response.AddRequestsToJoinCommunity(communityResponse.RequestsToJoin)
@ -2835,11 +2958,13 @@ func (m *Messenger) handleCommunityResponse(state *ReceivedMessageState, communi
oldChat.Description != chat.Description ||
oldChat.Emoji != chat.Emoji ||
oldChat.Color != chat.Color ||
oldChat.HideIfPermissionsNotMet != chat.HideIfPermissionsNotMet ||
oldChat.UpdateFirstMessageTimestamp(chat.FirstMessageTimestamp) {
oldChat.Name = chat.Name
oldChat.Description = chat.Description
oldChat.Emoji = chat.Emoji
oldChat.Color = chat.Color
oldChat.HideIfPermissionsNotMet = chat.HideIfPermissionsNotMet
// TODO(samyoul) remove storing of an updated reference pointer?
state.AllChats.Store(chat.ID, oldChat)
state.Response.AddChat(chat)
@ -2919,7 +3044,7 @@ func (m *Messenger) HandleCommunityUserKicked(state *ReceivedMessageState, messa
return nil
}
response, err := m.kickedOutOfCommunity(community.ID())
response, err := m.kickedOutOfCommunity(community.ID(), false)
if err != nil {
m.logger.Error("cannot leave community", zap.Error(err))
return err
@ -3168,10 +3293,18 @@ func (m *Messenger) handleSyncInstallationCommunity(messageState *ReceivedMessag
return nil
}
// Handle community keys
if len(syncCommunity.EncryptionKeys) != 0 {
// Handle deprecated community keys
if len(syncCommunity.EncryptionKeysV1) != 0 {
// We pass nil,nil as private key/public key as they won't be encrypted
_, err := m.encryptor.HandleHashRatchetKeysPayload(syncCommunity.Id, syncCommunity.EncryptionKeys, nil, nil)
_, err := m.encryptor.HandleHashRatchetKeysPayload(syncCommunity.Id, syncCommunity.EncryptionKeysV1, nil, nil)
if err != nil {
return err
}
}
// Handle community and channel keys
if len(syncCommunity.EncryptionKeysV2) != 0 {
err := m.encryptor.HandleHashRatchetHeadersPayload(syncCommunity.EncryptionKeysV2)
if err != nil {
return err
}
@ -3377,7 +3510,8 @@ func (m *Messenger) InitHistoryArchiveTasks(communities []*communities.Community
}
// Request possibly missed waku messages for community
_, err = m.syncFiltersFrom(filters, uint32(latestWakuMessageTimestamp))
ms := m.getActiveMailserver(c.ID().String())
_, err = m.syncFiltersFrom(*ms, filters, uint32(latestWakuMessageTimestamp))
if err != nil {
m.communitiesManager.LogStdout("failed to request missing messages", zap.Error(err))
continue
@ -3933,28 +4067,53 @@ func (m *Messenger) CheckPermissionsToJoinCommunity(request *requests.CheckPermi
return m.communitiesManager.CheckPermissionToJoin(request.CommunityID, addresses)
}
func (m *Messenger) CheckCommunityChannelPermissions(request *requests.CheckCommunityChannelPermissions) (*communities.CheckChannelPermissionsResponse, error) {
if err := request.Validate(); err != nil {
return nil, err
func (m *Messenger) getSharedAddresses(communityID types.HexBytes, requestAddresses []string) ([]gethcommon.Address, error) {
addressesMap := make(map[string]struct{})
for _, v := range requestAddresses {
addressesMap[v] = struct{}{}
}
var addresses []gethcommon.Address
if len(requestAddresses) == 0 {
sharedAddresses, err := m.GetRevealedAccounts(communityID, common.PubkeyToHex(&m.identity.PublicKey))
if err != nil {
return nil, err
}
if len(request.Addresses) == 0 {
for _, v := range sharedAddresses {
addressesMap[v.Address] = struct{}{}
}
}
if len(addressesMap) == 0 {
accounts, err := m.settings.GetActiveAccounts()
if err != nil {
return nil, err
}
for _, a := range accounts {
addresses = append(addresses, gethcommon.HexToAddress(a.Address.Hex()))
}
} else {
for _, v := range request.Addresses {
addresses = append(addresses, gethcommon.HexToAddress(v))
addressesMap[a.Address.Hex()] = struct{}{}
}
}
var addresses []gethcommon.Address
for addr := range addressesMap {
addresses = append(addresses, gethcommon.HexToAddress(addr))
}
return addresses, nil
}
func (m *Messenger) CheckCommunityChannelPermissions(request *requests.CheckCommunityChannelPermissions) (*communities.CheckChannelPermissionsResponse, error) {
if err := request.Validate(); err != nil {
return nil, err
}
addresses, err := m.getSharedAddresses(request.CommunityID, request.Addresses)
if err != nil {
return nil, err
}
return m.communitiesManager.CheckChannelPermissions(request.CommunityID, request.ChatID, addresses)
}
@ -3963,21 +4122,9 @@ func (m *Messenger) CheckAllCommunityChannelsPermissions(request *requests.Check
return nil, err
}
var addresses []gethcommon.Address
if len(request.Addresses) == 0 {
accounts, err := m.settings.GetActiveAccounts()
if err != nil {
return nil, err
}
for _, a := range accounts {
addresses = append(addresses, gethcommon.HexToAddress(a.Address.Hex()))
}
} else {
for _, v := range request.Addresses {
addresses = append(addresses, gethcommon.HexToAddress(v))
}
addresses, err := m.getSharedAddresses(request.CommunityID, request.Addresses)
if err != nil {
return nil, err
}
return m.communitiesManager.CheckAllChannelsPermissions(request.CommunityID, addresses)
@ -4145,6 +4292,7 @@ func (m *Messenger) GetCommunityMembersForWalletAddresses(communityID types.HexB
func (m *Messenger) processCommunityChanges(messageState *ReceivedMessageState) {
// Process any community changes
pkString := common.PubkeyToHex(&m.identity.PublicKey)
for _, changes := range messageState.Response.CommunityChanges {
if changes.ShouldMemberJoin {
response, err := m.joinCommunity(context.TODO(), changes.Community.ID(), false)
@ -4159,38 +4307,13 @@ func (m *Messenger) processCommunityChanges(messageState *ReceivedMessageState)
}
} else if changes.MemberKicked {
response, err := m.kickedOutOfCommunity(changes.Community.ID())
if err != nil {
m.logger.Error("cannot leave community", zap.Error(err))
continue
}
if err := messageState.Response.Merge(response); err != nil {
m.logger.Error("cannot merge join community response", zap.Error(err))
continue
}
// Activity Center notification
now := m.GetCurrentTimeInMillis()
notification := &ActivityCenterNotification{
ID: types.FromHex(uuid.New().String()),
Type: ActivityCenterNotificationTypeCommunityKicked,
Timestamp: now,
CommunityID: changes.Community.IDString(),
Read: false,
UpdatedAt: now,
}
err = m.addActivityCenterNotification(response, notification, nil)
if err != nil {
m.logger.Error("failed to save notification", zap.Error(err))
continue
}
if err := messageState.Response.Merge(response); err != nil {
m.logger.Error("cannot merge notification response", zap.Error(err))
continue
notificationType := ActivityCenterNotificationTypeCommunityKicked
if changes.IsMemberBanned(pkString) {
notificationType = ActivityCenterNotificationTypeCommunityBanned
}
m.leaveCommunityDueToKickOrBan(changes, notificationType, messageState.Response)
} else if changes.IsMemberUnbanned(pkString) {
m.AddActivityCenterNotificationToResponse(changes.Community.IDString(), ActivityCenterNotificationTypeCommunityUnbanned, messageState.Response)
}
}
// Clean up as not used by clients currently
@ -4241,7 +4364,13 @@ func (m *Messenger) PromoteSelfToControlNode(communityID types.HexBytes) (*Messe
return &response, nil
}
func (m *Messenger) CreateResponseWithACNotification(communityID string, acType ActivityCenterType, isRead bool) (*MessengerResponse, error) {
func (m *Messenger) CreateResponseWithACNotification(communityID string, acType ActivityCenterType, isRead bool, tokenDataJSON string) (*MessengerResponse, error) {
tokenData := ActivityTokenData{}
err := json.Unmarshal([]byte(tokenDataJSON), &tokenData)
if len(tokenDataJSON) > 0 && err != nil {
// Only return error when activityDataString is not empty
return nil, err
}
// Activity center notification
notification := &ActivityCenterNotification{
ID: types.FromHex(uuid.New().String()),
@ -4251,11 +4380,17 @@ func (m *Messenger) CreateResponseWithACNotification(communityID string, acType
Read: isRead,
Deleted: false,
UpdatedAt: m.GetCurrentTimeInMillis(),
TokenData: &tokenData,
}
err = m.prepareTokenData(notification.TokenData, m.httpServer)
if err != nil {
return nil, err
}
response := &MessengerResponse{}
err := m.addActivityCenterNotification(response, notification, nil)
err = m.addActivityCenterNotification(response, notification, nil)
if err != nil {
m.logger.Error("failed to save notification", zap.Error(err))
return response, err
@ -4289,3 +4424,137 @@ func (m *Messenger) AddActivityCenterNotificationToResponse(communityID string,
m.logger.Error("failed to save notification", zap.Error(err))
}
}
func (m *Messenger) leaveCommunityDueToKickOrBan(changes *communities.CommunityChanges, acType ActivityCenterType, stateResponse *MessengerResponse) {
// during the ownership change kicked user must stay in the spectate mode
ownerhipChange := changes.ControlNodeChanged != nil
response, err := m.kickedOutOfCommunity(changes.Community.ID(), ownerhipChange)
if err != nil {
m.logger.Error("cannot leave community", zap.Error(err))
return
}
if !ownerhipChange {
// Activity Center notification
notification := &ActivityCenterNotification{
ID: types.FromHex(uuid.New().String()),
Type: acType,
Timestamp: m.getTimesource().GetCurrentTime(),
CommunityID: changes.Community.IDString(),
Read: false,
UpdatedAt: m.GetCurrentTimeInMillis(),
}
err = m.addActivityCenterNotification(response, notification, nil)
if err != nil {
m.logger.Error("failed to save notification", zap.Error(err))
return
}
}
if err := stateResponse.Merge(response); err != nil {
m.logger.Error("cannot merge leave and notification response", zap.Error(err))
}
}
func (m *Messenger) GetCommunityMemberAllMessages(request *requests.CommunityMemberMessages) ([]*common.Message, error) {
if err := request.Validate(); err != nil {
return nil, err
}
messages, err := m.persistence.GetCommunityMemberAllMessages(request.MemberPublicKey, request.CommunityID)
if err != nil {
return nil, err
}
for _, message := range messages {
updatedMessages, err := m.persistence.MessagesByResponseTo(message.ID)
if err != nil {
return nil, err
}
messages = append(messages, updatedMessages...)
}
return messages, nil
}
func (m *Messenger) DeleteCommunityMemberMessages(request *requests.DeleteCommunityMemberMessages) (*MessengerResponse, error) {
if err := request.Validate(); err != nil {
return nil, err
}
community, err := m.GetCommunityByID(request.CommunityID)
if err != nil {
return nil, err
}
if community == nil {
return nil, communities.ErrOrgNotFound
}
if !community.IsControlNode() && !community.IsPrivilegedMember(m.IdentityPublicKey()) {
return nil, communities.ErrNotEnoughPermissions
}
memberPubKey, err := common.HexToPubkey(request.MemberPubKey)
if err != nil {
return nil, err
}
if community.IsMemberOwner(memberPubKey) && !m.IdentityPublicKey().Equal(memberPubKey) {
return nil, communities.ErrNotOwner
}
deleteMessagesResponse, err := m.deleteCommunityMemberMessages(request.MemberPubKey, request.CommunityID.String(), request.Messages)
if err != nil {
return nil, err
}
deletedMessages := &protobuf.DeleteCommunityMemberMessages{
Clock: uint64(time.Now().Unix()),
CommunityId: community.ID(),
MemberId: request.MemberPubKey,
Messages: request.Messages,
}
payload, err := proto.Marshal(deletedMessages)
if err != nil {
return nil, err
}
rawMessage := common.RawMessage{
Payload: payload,
Sender: community.PrivateKey(),
SkipEncryptionLayer: true,
MessageType: protobuf.ApplicationMetadataMessage_DELETE_COMMUNITY_MEMBER_MESSAGES,
PubsubTopic: community.PubsubTopic(),
}
_, err = m.sender.SendPublic(context.Background(), community.IDString(), rawMessage)
return deleteMessagesResponse, err
}
func (m *Messenger) HandleDeleteCommunityMemberMessages(state *ReceivedMessageState, request *protobuf.DeleteCommunityMemberMessages, statusMessage *v1protocol.StatusMessage) error {
community, err := m.communitiesManager.GetByID(request.CommunityId)
if err != nil {
return err
}
if community == nil {
return communities.ErrOrgNotFound
}
if !community.ControlNode().Equal(state.CurrentMessageState.PublicKey) && !community.IsPrivilegedMember(state.CurrentMessageState.PublicKey) {
return communities.ErrNotAuthorized
}
deleteMessagesResponse, err := m.deleteCommunityMemberMessages(request.MemberId, community.IDString(), request.Messages)
if err != nil {
return err
}
return state.Response.Merge(deleteMessagesResponse)
}

View File

@ -500,7 +500,8 @@ func createCommunityChannelForImport(request *requests.ImportDiscordChannel) *pr
Description: request.Description,
Color: request.Color,
},
CategoryId: "",
CategoryId: "",
HideIfPermissionsNotMet: false,
}
}
@ -1210,7 +1211,8 @@ func (m *Messenger) RequestImportDiscordCommunity(request *requests.ImportDiscor
Description: channel.Channel.Description,
Color: discordCommunity.Color(),
},
CategoryId: processedCategoriesIds[channel.Channel.CategoryID],
CategoryId: processedCategoriesIds[channel.Channel.CategoryID],
HideIfPermissionsNotMet: false,
}
// We call `CreateChat` on `communitiesManager` directly to get more control

View File

@ -126,7 +126,7 @@ func (m *Messenger) CreateTokenGatedCommunity() (*MessengerResponse, error) {
Type: protobuf.CommunityTokenType_ERC20,
Symbol: "STT",
Name: "Status Test Token",
Amount: "10",
AmountInWei: "10000000000000000000",
Decimals: 18,
}},
ChatIds: []string{generalChatID},

View File

@ -2,7 +2,6 @@ package protocol
import (
"context"
"crypto/ecdsa"
"errors"
"github.com/golang/protobuf/proto"
@ -75,13 +74,7 @@ func (m *Messenger) HandleCommunityPublicShardInfo(state *ReceivedMessageState,
m.logger.Error("HandleCommunityPublicShardInfo failed: ", zap.Error(err), zap.String("communityID", types.EncodeHex(publicShardInfo.CommunityId)))
}
signer, err := recoverCommunityShardInfoSignature(a)
if err != nil {
logError(err)
return err
}
err = m.verifyCommunityPublicShardInfo(publicShardInfo, signer)
err = m.verifyCommunitySignature(a.Payload, a.Signature, publicShardInfo.CommunityId, publicShardInfo.ChainId)
if err != nil {
logError(err)
return err
@ -95,26 +88,25 @@ func (m *Messenger) HandleCommunityPublicShardInfo(state *ReceivedMessageState,
return nil
}
func recoverCommunityShardInfoSignature(rawShardInfo *protobuf.CommunityPublicShardInfo) (*ecdsa.PublicKey, error) {
if rawShardInfo.Signature == nil || len(rawShardInfo.Signature) == 0 {
return nil, errors.New("missing shard info signature")
func (m *Messenger) verifyCommunitySignature(payload, signature, communityID []byte, chainID uint64) error {
if len(signature) == 0 {
return errors.New("missing signature")
}
return crypto.SigToPub(crypto.Keccak256(rawShardInfo.Payload), rawShardInfo.Signature)
}
func (m *Messenger) verifyCommunityPublicShardInfo(publicShardInfo *protobuf.PublicShardInfo, signer *ecdsa.PublicKey) error {
pubKeyStr := common.PubkeyToHex(signer)
pubKey, err := crypto.SigToPub(crypto.Keccak256(payload), signature)
if err != nil {
return err
}
pubKeyStr := common.PubkeyToHex(pubKey)
var ownerPublicKey string
if publicShardInfo.ChainId > 0 {
owner, err := m.communitiesManager.SafeGetSignerPubKey(publicShardInfo.ChainId, types.EncodeHex(publicShardInfo.CommunityId))
if chainID > 0 {
owner, err := m.communitiesManager.SafeGetSignerPubKey(chainID, types.EncodeHex(communityID))
if err != nil {
return err
}
ownerPublicKey = owner
} else {
communityPubkey, err := crypto.DecompressPubkey(publicShardInfo.CommunityId)
communityPubkey, err := crypto.DecompressPubkey(communityID)
if err != nil {
return err
}

View File

@ -0,0 +1,92 @@
package protocol
import (
"context"
"errors"
"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/storenodes"
v1protocol "github.com/status-im/status-go/protocol/v1"
)
func (m *Messenger) sendCommunityPublicStorenodesInfo(community *communities.Community, snodes storenodes.Storenodes) error {
if !community.IsControlNode() {
return communities.ErrNotControlNode
}
clock, _ := m.getLastClockWithRelatedChat()
pb := &protobuf.CommunityStorenodes{
Clock: clock,
CommunityId: community.ID(),
Storenodes: snodes.ToProtobuf(),
ChainId: communities.CommunityDescriptionTokenOwnerChainID(community.Description()),
}
snPayload, err := proto.Marshal(pb)
if err != nil {
return err
}
signature, err := crypto.Sign(crypto.Keccak256(snPayload), community.PrivateKey())
if err != nil {
return err
}
signedStorenodesInfo := &protobuf.CommunityPublicStorenodesInfo{
Signature: signature,
Payload: snPayload,
}
signedPayload, err := proto.Marshal(signedStorenodesInfo)
if err != nil {
return err
}
rawMessage := common.RawMessage{
Payload: signedPayload,
Sender: community.PrivateKey(),
SkipEncryptionLayer: true,
MessageType: protobuf.ApplicationMetadataMessage_COMMUNITY_PUBLIC_STORENODES_INFO,
PubsubTopic: community.PubsubTopic(),
}
_, err = m.sender.SendPublic(context.Background(), community.IDString(), rawMessage)
return err
}
// HandleCommunityPublicStorenodesInfo will process the control message sent by the community owner on updating the community storenodes for his community (sendCommunityPublicStorenodesInfo).
// The message will be received by many peers that are not interested on that community, so if we don't have this community in our DB we just ignore this message.
func (m *Messenger) HandleCommunityPublicStorenodesInfo(state *ReceivedMessageState, a *protobuf.CommunityPublicStorenodesInfo, statusMessage *v1protocol.StatusMessage) error {
sn := &protobuf.CommunityStorenodes{}
err := proto.Unmarshal(a.Payload, sn)
if err != nil {
return err
}
logger := m.logger.Named("HandleCommunityPublicStorenodesInfo").With(zap.String("communityID", types.EncodeHex(sn.CommunityId)))
err = m.verifyCommunitySignature(a.Payload, a.Signature, sn.CommunityId, sn.ChainId)
if err != nil {
logger.Error("failed to verify community signature", zap.Error(err))
return err
}
// verify if we are interested in this control message
_, err = m.communitiesManager.GetByID(sn.CommunityId)
if err != nil {
if errors.Is(err, communities.ErrOrgNotFound) {
logger.Debug("ignoring control message, community not found")
return nil
}
logger.Error("failed get community by id", zap.Error(err))
return err
}
if err := m.communityStorenodes.UpdateStorenodesInDB(sn.CommunityId, storenodes.FromProtobuf(sn.Storenodes, sn.Clock), sn.Clock); err != nil {
logger.Error("failed to update storenodes for community", zap.Error(err))
return err
}
return nil
}

View File

@ -3,6 +3,7 @@ package protocol
import (
"database/sql"
"encoding/json"
"time"
"github.com/status-im/status-go/account"
"github.com/status-im/status-go/rpc"
@ -75,7 +76,8 @@ type config struct {
// Config for the envelopes monitor
envelopesMonitorConfig *transport.EnvelopesMonitorConfig
featureFlags common.FeatureFlags
featureFlags common.FeatureFlags
codeControlFlags common.CodeControlFlags
appDb *sql.DB
walletDb *sql.DB
@ -92,6 +94,7 @@ type config struct {
httpServer *server.MediaServer
rpcClient *rpc.Client
tokenManager communities.TokenManager
collectiblesManager communities.CollectiblesManager
accountsManager account.Manager
verifyTransactionClient EthClient
@ -113,17 +116,18 @@ type config struct {
telemetryServerURL string
wakuService *wakuv2.Waku
messageResendMinDelay int
messageResendMinDelay time.Duration
messageResendMaxCount int
}
func messengerDefaultConfig() config {
c := config{
messageResendMinDelay: 30,
messageResendMinDelay: 30 * time.Second,
messageResendMaxCount: 3,
}
c.featureFlags.AutoRequestHistoricMessages = true
c.codeControlFlags.AutoRequestHistoricMessages = true
c.codeControlFlags.CuratedCommunitiesUpdateLoopEnabled = true
return c
}
@ -152,7 +156,7 @@ func WithVerifyTransactionClient(client EthClient) Option {
}
}
func WithResendParams(minDelay int, maxCount int) Option {
func WithResendParams(minDelay time.Duration, maxCount int) Option {
return func(c *config) error {
c.messageResendMinDelay = minDelay
c.messageResendMaxCount = maxCount
@ -394,16 +398,16 @@ func WithTokenManager(tokenManager communities.TokenManager) Option {
}
}
func WithCollectiblesManager(collectiblesManager communities.CollectiblesManager) Option {
return func(c *config) error {
c.collectiblesManager = collectiblesManager
return nil
}
}
func WithAccountManager(accountManager account.Manager) Option {
return func(c *config) error {
c.accountsManager = accountManager
return nil
}
}
func WithAutoRequestHistoricMessages(enabled bool) Option {
return func(c *config) error {
c.featureFlags.AutoRequestHistoricMessages = enabled
return nil
}
}

View File

@ -869,20 +869,20 @@ func (m *Messenger) HandleAcceptContactVerification(state *ReceivedMessageState,
return err
}
if persistedVR != nil && persistedVR.RepliedAt > request.Clock {
return nil // older message, ignore it
}
if persistedVR.RequestStatus == verification.RequestStatusCANCELED {
return nil // Do nothing, We have already cancelled the verification request
}
if persistedVR == nil {
// This is a response for which we have not received its request before
persistedVR = &verification.Request{}
persistedVR.ID = request.Id
persistedVR.From = contactID
persistedVR.To = myPubKey
} else {
if persistedVR.RepliedAt > request.Clock {
return nil // older message, ignore it
}
if persistedVR.RequestStatus == verification.RequestStatusCANCELED {
return nil // Do nothing, We have already cancelled the verification request
}
}
persistedVR.RequestStatus = verification.RequestStatusACCEPTED

View File

@ -27,6 +27,8 @@ const incomingMutualStateEventSentDefaultText = "@%s sent you a contact request"
const incomingMutualStateEventAcceptedDefaultText = "@%s accepted your contact request"
const incomingMutualStateEventRemovedDefaultText = "@%s removed you as a contact"
var ErrGetLatestContactRequestForContactInvalidID = errors.New("get-latest-contact-request-for-contact: invalid id")
type SelfContactChangeEvent struct {
DisplayNameChanged bool
PreferredNameChanged bool
@ -854,6 +856,7 @@ func (m *Messenger) blockContact(ctx context.Context, response *MessengerRespons
return err
}
contactWasAdded := contact.added()
contact.Block(clock)
contact.LastUpdatedLocally = m.getTimesource().GetCurrentTime()
@ -876,9 +879,11 @@ func (m *Messenger) blockContact(ctx context.Context, response *MessengerRespons
}
if !fromSyncing {
err = m.sendRetractContactRequest(contact)
if err != nil {
return err
if contactWasAdded {
err = m.sendRetractContactRequest(contact)
if err != nil {
return err
}
}
err = m.syncContact(context.Background(), contact, m.dispatchMessage)
@ -1158,6 +1163,28 @@ func (m *Messenger) sendRetractContactRequest(contact *Contact) error {
return err
}
func (m *Messenger) GetLatestContactRequestForContact(contactID string) (*MessengerResponse, error) {
if len(contactID) == 0 {
return nil, ErrGetLatestContactRequestForContactInvalidID
}
contactRequestID, err := m.persistence.LatestPendingContactRequestIDForContact(contactID)
if err != nil {
return nil, err
}
contactRequest, err := m.persistence.MessageByID(contactRequestID)
if err != nil {
m.logger.Error("contact request not found", zap.String("contactRequestID", contactRequestID), zap.Error(err))
return nil, err
}
response := &MessengerResponse{}
response.AddMessage(contactRequest)
return response, nil
}
func (m *Messenger) AcceptLatestContactRequestForContact(ctx context.Context, request *requests.AcceptLatestContactRequestForContact) (*MessengerResponse, error) {
if err := request.Validate(); err != nil {
return nil, err

View File

@ -20,7 +20,12 @@ const (
// Regularly gets list of curated communities and signals them to client
func (m *Messenger) startCuratedCommunitiesUpdateLoop() {
logger := m.logger.Named("startCuratedCommunitiesUpdateLoop")
logger := m.logger.Named("curatedCommunitiesUpdateLoop")
if m.contractMaker == nil {
logger.Warn("not starting curated communities loop: contract maker not initialized")
return
}
go func() {
// Initialize interval to 0 for immediate execution
@ -76,7 +81,6 @@ func (m *Messenger) startCuratedCommunitiesUpdateLoop() {
func (m *Messenger) getCuratedCommunitiesFromContract() (*communities.CuratedCommunities, error) {
if m.contractMaker == nil {
m.logger.Warn("contract maker not initialized")
return nil, errors.New("contract maker not initialized")
}

View File

@ -0,0 +1,149 @@
package protocol
import (
"context"
"github.com/pkg/errors"
"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/protobuf"
)
func (m *Messenger) SendEmojiReaction(ctx context.Context, chatID, messageID string, emojiID protobuf.EmojiReaction_Type) (*MessengerResponse, error) {
var response MessengerResponse
chat, ok := m.allChats.Load(chatID)
if !ok {
return nil, ErrChatNotFound
}
clock, _ := chat.NextClockAndTimestamp(m.getTimesource())
emojiR := &EmojiReaction{
EmojiReaction: &protobuf.EmojiReaction{
Clock: clock,
MessageId: messageID,
ChatId: chatID,
Type: emojiID,
},
LocalChatID: chatID,
From: types.EncodeHex(crypto.FromECDSAPub(&m.identity.PublicKey)),
}
encodedMessage, err := m.encodeChatEntity(chat, emojiR)
if err != nil {
return nil, err
}
_, err = m.dispatchMessage(ctx, common.RawMessage{
LocalChatID: chatID,
Payload: encodedMessage,
SkipGroupMessageWrap: true,
MessageType: protobuf.ApplicationMetadataMessage_EMOJI_REACTION,
// Don't resend using datasync, that would create quite a lot
// of traffic if clicking too eagelry
ResendAutomatically: false,
})
if err != nil {
return nil, err
}
response.AddEmojiReaction(emojiR)
response.AddChat(chat)
err = m.persistence.SaveEmojiReaction(emojiR)
if err != nil {
return nil, errors.Wrap(err, "Can't save emoji reaction in db")
}
return &response, nil
}
func (m *Messenger) EmojiReactionsByChatID(chatID string, cursor string, limit int) ([]*EmojiReaction, error) {
chat, err := m.persistence.Chat(chatID)
if err != nil {
return nil, err
}
if chat.Timeline() {
var chatIDs = []string{"@" + contactIDFromPublicKey(&m.identity.PublicKey)}
m.allContacts.Range(func(contactID string, contact *Contact) (shouldContinue bool) {
if contact.added() {
chatIDs = append(chatIDs, "@"+contact.ID)
}
return true
})
return m.persistence.EmojiReactionsByChatIDs(chatIDs, cursor, limit)
}
return m.persistence.EmojiReactionsByChatID(chatID, cursor, limit)
}
func (m *Messenger) EmojiReactionsByChatIDMessageID(chatID string, messageID string) ([]*EmojiReaction, error) {
_, err := m.persistence.Chat(chatID)
if err != nil {
return nil, err
}
return m.persistence.EmojiReactionsByChatIDMessageID(chatID, messageID)
}
func (m *Messenger) SendEmojiReactionRetraction(ctx context.Context, emojiReactionID string) (*MessengerResponse, error) {
emojiR, err := m.persistence.EmojiReactionByID(emojiReactionID)
if err != nil {
return nil, err
}
// Check that the sender is the key owner
pk := types.EncodeHex(crypto.FromECDSAPub(&m.identity.PublicKey))
if emojiR.From != pk {
return nil, errors.Errorf("identity mismatch, "+
"emoji reactions can only be retracted by the reaction sender, "+
"emoji reaction sent by '%s', current identity '%s'",
emojiR.From, pk,
)
}
// Get chat and clock
chat, ok := m.allChats.Load(emojiR.GetChatId())
if !ok {
return nil, ErrChatNotFound
}
clock, _ := chat.NextClockAndTimestamp(m.getTimesource())
// Update the relevant fields
emojiR.Clock = clock
emojiR.Retracted = true
encodedMessage, err := m.encodeChatEntity(chat, emojiR)
if err != nil {
return nil, err
}
// Send the marshalled EmojiReactionRetraction protobuf
_, err = m.dispatchMessage(ctx, common.RawMessage{
LocalChatID: emojiR.GetChatId(),
Payload: encodedMessage,
SkipGroupMessageWrap: true,
MessageType: protobuf.ApplicationMetadataMessage_EMOJI_REACTION,
// Don't resend using datasync, that would create quite a lot
// of traffic if clicking too eagelry
ResendAutomatically: false,
})
if err != nil {
return nil, err
}
// Update MessengerResponse
response := MessengerResponse{}
emojiR.Retracted = true
response.AddEmojiReaction(emojiR)
response.AddChat(chat)
// Persist retraction state for emoji reaction
err = m.persistence.SaveEmojiReaction(emojiR)
if err != nil {
return nil, err
}
return &response, nil
}

View File

@ -393,7 +393,26 @@ func (m *Messenger) handleCommandMessage(state *ReceivedMessageState, message *c
if err := message.PrepareContent(common.PubkeyToHex(&m.identity.PublicKey)); err != nil {
return fmt.Errorf("failed to prepare content: %v", err)
}
chat, err := m.matchChatEntity(message)
// Get Application layer messageType from commandState
// Currently this is not really used in `matchChatEntity`, but I did want to pass UNKNOWN there.
var messageType protobuf.ApplicationMetadataMessage_Type
switch message.CommandParameters.CommandState {
case common.CommandStateRequestAddressForTransaction:
messageType = protobuf.ApplicationMetadataMessage_REQUEST_ADDRESS_FOR_TRANSACTION
case common.CommandStateRequestAddressForTransactionAccepted:
messageType = protobuf.ApplicationMetadataMessage_ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION
case common.CommandStateRequestAddressForTransactionDeclined:
messageType = protobuf.ApplicationMetadataMessage_DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION
case common.CommandStateRequestTransaction:
messageType = protobuf.ApplicationMetadataMessage_REQUEST_TRANSACTION
case common.CommandStateRequestTransactionDeclined:
messageType = protobuf.ApplicationMetadataMessage_DECLINE_REQUEST_TRANSACTION
default:
messageType = protobuf.ApplicationMetadataMessage_UNKNOWN
}
chat, err := m.matchChatEntity(message, messageType)
if err != nil {
return err
}
@ -862,7 +881,7 @@ func (m *Messenger) handlePinMessage(pinner *Contact, whisperTimestamp uint64, r
Alias: pinner.Alias,
}
chat, err := m.matchChatEntity(pinMessage)
chat, err := m.matchChatEntity(pinMessage, protobuf.ApplicationMetadataMessage_PIN_MESSAGE)
if err != nil {
return err // matchChatEntity returns a descriptive error message
}
@ -2092,6 +2111,7 @@ func (m *Messenger) handleChatMessage(state *ReceivedMessageState, forceSeen boo
logger.Warn("failed to validate message", zap.Error(err))
return err
}
receivedMessage := &common.Message{
ID: state.CurrentMessageState.MessageID,
ChatMessage: state.CurrentMessageState.Message,
@ -2126,7 +2146,7 @@ func (m *Messenger) handleChatMessage(state *ReceivedMessageState, forceSeen boo
}
}
chat, err := m.matchChatEntity(receivedMessage)
chat, err := m.matchChatEntity(receivedMessage, protobuf.ApplicationMetadataMessage_CHAT_MESSAGE)
if err != nil {
return err // matchChatEntity returns a descriptive error message
}
@ -2144,6 +2164,39 @@ func (m *Messenger) handleChatMessage(state *ReceivedMessageState, forceSeen boo
return ErrMessageNotAllowed
}
if chat.ChatType == ChatTypeCommunityChat {
communityID, err := types.DecodeHex(chat.CommunityID)
if err != nil {
return err
}
community, err := m.GetCommunityByID(communityID)
if err != nil {
return err
}
if community == nil {
logger.Warn("community not found for msg",
zap.String("messageID", receivedMessage.ID),
zap.String("from", receivedMessage.From),
zap.String("communityID", chat.CommunityID))
return communities.ErrOrgNotFound
}
pk, err := common.HexToPubkey(state.CurrentMessageState.Contact.ID)
if err != nil {
return err
}
if community.IsBanned(pk) {
logger.Warn("skipping msg from banned user",
zap.String("messageID", receivedMessage.ID),
zap.String("from", receivedMessage.From),
zap.String("communityID", chat.CommunityID))
return errors.New("received a messaged from banned user")
}
}
// It looks like status-mobile created profile chats as public chats
// so for now we need to check for the presence of "@" in their chatID
if chat.Public() && !chat.ProfileUpdates() {
@ -2650,7 +2703,7 @@ func (m *Messenger) HandleDeclineRequestTransaction(messageState *ReceivedMessag
return m.handleCommandMessage(messageState, oldMessage)
}
func (m *Messenger) matchChatEntity(chatEntity common.ChatEntity) (*Chat, error) {
func (m *Messenger) matchChatEntity(chatEntity common.ChatEntity, messageType protobuf.ApplicationMetadataMessage_Type) (*Chat, error) {
if chatEntity.GetSigPubKey() == nil {
m.logger.Error("public key can't be empty")
return nil, errors.New("received a chatEntity with empty public key")
@ -2719,7 +2772,7 @@ func (m *Messenger) matchChatEntity(chatEntity common.ChatEntity) (*Chat, error)
return nil, errors.New("not an community chat")
}
canPost, err := m.communitiesManager.CanPost(chatEntity.GetSigPubKey(), chat.CommunityID, chat.CommunityChatID())
canPost, err := m.communitiesManager.CanPost(chatEntity.GetSigPubKey(), chat.CommunityID, chat.CommunityChatID(), messageType)
if err != nil {
return nil, err
}
@ -2728,21 +2781,8 @@ func (m *Messenger) matchChatEntity(chatEntity common.ChatEntity) (*Chat, error)
return nil, errors.New("user can't post in community")
}
_, isPinMessage := chatEntity.(*common.PinMessage)
if isPinMessage {
community, err := m.communitiesManager.GetByIDString(chat.CommunityID)
if err != nil {
return nil, err
}
hasPermission := community.IsPrivilegedMember(chatEntity.GetSigPubKey())
pinMessageAllowed := community.AllowsAllMembersToPinMessage()
if !hasPermission && !pinMessageAllowed {
return nil, errors.New("user can't pin message")
}
}
return chat, nil
case chatEntity.GetMessageType() == protobuf.MessageType_PRIVATE_GROUP:
// In the case of a group chatEntity, ChatID is the same for all messages belonging to a group.
// It needs to be verified if the signature public key belongs to the chat.
@ -2819,7 +2859,7 @@ func (m *Messenger) HandleEmojiReaction(state *ReceivedMessageState, pbEmojiR *p
return nil
}
chat, err := m.matchChatEntity(emojiReaction)
chat, err := m.matchChatEntity(emojiReaction, protobuf.ApplicationMetadataMessage_EMOJI_REACTION)
if err != nil {
return err // matchChatEntity returns a descriptive error message
}
@ -3016,6 +3056,7 @@ func (m *Messenger) HandleChatIdentity(state *ReceivedMessageState, ci *protobuf
if err != nil {
return err
}
state.Response.AddUpdatedProfileShowcaseContactID(contact.ID)
}
}
@ -3213,13 +3254,13 @@ func mapSyncAccountToAccount(message *protobuf.SyncAccount, accountOperability a
}
}
func (m *Messenger) resolveAccountOperability(syncAcc *protobuf.SyncAccount, syncKpMigratedToKeycard bool,
dbKpMigratedToKeycard bool, accountReceivedFromLocalPairing bool) (accounts.AccountOperable, error) {
func (m *Messenger) resolveAccountOperability(syncAcc *protobuf.SyncAccount, recoverinrecoveringFromWakuInitiatedByKeycard bool,
syncKpMigratedToKeycard bool, dbKpMigratedToKeycard bool, accountReceivedFromLocalPairing bool) (accounts.AccountOperable, error) {
if accountReceivedFromLocalPairing {
return accounts.AccountOperable(syncAcc.Operable), nil
}
if syncKpMigratedToKeycard || m.account.KeyUID == syncAcc.KeyUid {
if syncKpMigratedToKeycard || recoverinrecoveringFromWakuInitiatedByKeycard && m.account.KeyUID == syncAcc.KeyUid {
return accounts.AccountFullyOperable, nil
}
@ -3500,18 +3541,19 @@ func (m *Messenger) handleSyncKeypair(message *protobuf.SyncKeypair, fromLocalPa
}
syncKpMigratedToKeycard := len(message.Keycards) > 0
recoveringFromWaku := message.SyncedFrom == accounts.SyncedFromBackup
multiAcc, err := m.multiAccounts.GetAccount(kp.KeyUID)
if err != nil {
return nil, err
}
recoverinrecoveringFromWakuInitiatedByKeycard := recoveringFromWaku && multiAcc != nil && multiAcc.RefersToKeycard()
for _, sAcc := range message.Accounts {
if message.SyncedFrom == accounts.SyncedFromBackup && kp.Type == accounts.KeypairTypeProfile {
// if a profile keypair is coming from backup, we're handling within this block the case when a recovering
// was inititiated via keycard, while backed up profile keypair data refers to a regular profile
multiAcc, err := m.multiAccounts.GetAccount(kp.KeyUID)
if err != nil {
return nil, err
}
syncKpMigratedToKeycard = multiAcc != nil && multiAcc.KeycardPairing != ""
}
accountOperability, err := m.resolveAccountOperability(sAcc, syncKpMigratedToKeycard,
dbKeypair != nil && dbKeypair.MigratedToKeycard(), fromLocalPairing)
accountOperability, err := m.resolveAccountOperability(sAcc,
recoverinrecoveringFromWakuInitiatedByKeycard,
syncKpMigratedToKeycard,
dbKeypair != nil && dbKeypair.MigratedToKeycard(),
fromLocalPairing)
if err != nil {
return nil, err
}
@ -3520,7 +3562,7 @@ func (m *Messenger) handleSyncKeypair(message *protobuf.SyncKeypair, fromLocalPa
kp.Accounts = append(kp.Accounts, acc)
}
if !fromLocalPairing {
if !fromLocalPairing && !recoverinrecoveringFromWakuInitiatedByKeycard {
if kp.Removed ||
dbKeypair != nil && !dbKeypair.MigratedToKeycard() && syncKpMigratedToKeycard {
// delete all keystore files
@ -3895,3 +3937,8 @@ func (m *Messenger) addNewKeypairAddedOnPairedDeviceACNotification(keyUID string
}
return nil
}
func (m *Messenger) HandleSyncProfileShowcasePreferences(state *ReceivedMessageState, p *protobuf.SyncProfileShowcasePreferences, statusMessage *v1protocol.StatusMessage) error {
_, err := m.saveProfileShowcasePreferencesProto(p, false)
return err
}

View File

@ -244,6 +244,18 @@ func (m *Messenger) dispatchToHandler(messageState *ReceivedMessageState, protoB
case protobuf.ApplicationMetadataMessage_COMMUNITY_USER_KICKED:
return m.handleCommunityUserKickedProtobuf(messageState, protoBytes, msg, filter)
case protobuf.ApplicationMetadataMessage_SYNC_PROFILE_SHOWCASE_PREFERENCES:
return m.handleSyncProfileShowcasePreferencesProtobuf(messageState, protoBytes, msg, filter)
case protobuf.ApplicationMetadataMessage_COMMUNITY_PUBLIC_STORENODES_INFO:
return m.handleCommunityPublicStorenodesInfoProtobuf(messageState, protoBytes, msg, filter)
case protobuf.ApplicationMetadataMessage_COMMUNITY_REEVALUATE_PERMISSIONS_REQUEST:
return m.handleCommunityReevaluatePermissionsRequestProtobuf(messageState, protoBytes, msg, filter)
case protobuf.ApplicationMetadataMessage_DELETE_COMMUNITY_MEMBER_MESSAGES:
return m.handleDeleteCommunityMemberMessagesProtobuf(messageState, protoBytes, msg, filter)
default:
m.logger.Info("protobuf type not found", zap.String("type", string(msg.ApplicationLayer.Type)))
return errors.New("protobuf type not found")
@ -1749,3 +1761,80 @@ func (m *Messenger) handleCommunityUserKickedProtobuf(messageState *ReceivedMess
}
func (m *Messenger) handleSyncProfileShowcasePreferencesProtobuf(messageState *ReceivedMessageState, protoBytes []byte, msg *v1protocol.StatusMessage, filter transport.Filter) error {
m.logger.Info("handling SyncProfileShowcasePreferences")
if !common.IsPubKeyEqual(messageState.CurrentMessageState.PublicKey, &m.identity.PublicKey) {
m.logger.Warn("not coming from us, ignoring")
return nil
}
p := &protobuf.SyncProfileShowcasePreferences{}
err := proto.Unmarshal(protoBytes, p)
if err != nil {
return err
}
m.outputToCSV(msg.TransportLayer.Message.Timestamp, msg.ApplicationLayer.ID, messageState.CurrentMessageState.Contact.ID, filter.ContentTopic, filter.ChatID, msg.ApplicationLayer.Type, p)
return m.HandleSyncProfileShowcasePreferences(messageState, p, msg)
}
func (m *Messenger) handleCommunityPublicStorenodesInfoProtobuf(messageState *ReceivedMessageState, protoBytes []byte, msg *v1protocol.StatusMessage, filter transport.Filter) error {
m.logger.Info("handling CommunityPublicStorenodesInfo")
p := &protobuf.CommunityPublicStorenodesInfo{}
err := proto.Unmarshal(protoBytes, p)
if err != nil {
return err
}
m.outputToCSV(msg.TransportLayer.Message.Timestamp, msg.ApplicationLayer.ID, messageState.CurrentMessageState.Contact.ID, filter.ContentTopic, filter.ChatID, msg.ApplicationLayer.Type, p)
return m.HandleCommunityPublicStorenodesInfo(messageState, p, msg)
}
func (m *Messenger) handleCommunityReevaluatePermissionsRequestProtobuf(messageState *ReceivedMessageState, protoBytes []byte, msg *v1protocol.StatusMessage, filter transport.Filter) error {
m.logger.Info("handling CommunityReevaluatePermissionsRequest")
p := &protobuf.CommunityReevaluatePermissionsRequest{}
err := proto.Unmarshal(protoBytes, p)
if err != nil {
return err
}
m.outputToCSV(msg.TransportLayer.Message.Timestamp, msg.ApplicationLayer.ID, messageState.CurrentMessageState.Contact.ID, filter.ContentTopic, filter.ChatID, msg.ApplicationLayer.Type, p)
return m.HandleCommunityReevaluatePermissionsRequest(messageState, p, msg)
}
func (m *Messenger) handleDeleteCommunityMemberMessagesProtobuf(messageState *ReceivedMessageState, protoBytes []byte, msg *v1protocol.StatusMessage, filter transport.Filter) error {
m.logger.Info("handling DeleteCommunityMemberMessages")
p := &protobuf.DeleteCommunityMemberMessages{}
err := proto.Unmarshal(protoBytes, p)
if err != nil {
return err
}
m.outputToCSV(msg.TransportLayer.Message.Timestamp, msg.ApplicationLayer.ID, messageState.CurrentMessageState.Contact.ID, filter.ContentTopic, filter.ChatID, msg.ApplicationLayer.Type, p)
return m.HandleDeleteCommunityMemberMessages(messageState, p, msg)
}

View File

@ -26,6 +26,7 @@ var ErrInvalidDisplayNameEthSuffix = errors.New(`usernames ending with "eth" are
var ErrInvalidDisplayNameNotAllowed = errors.New("name is not allowed")
var ErrInvalidBioLength = errors.New("invalid bio length")
var ErrInvalidSocialLinkTextLength = errors.New("invalid social link text length")
var ErrDisplayNameDupeOfCommunityMember = errors.New("display name duplicates on of community members")
func ValidateDisplayName(displayName *string) error {
name := strings.TrimSpace(*displayName)
@ -66,6 +67,15 @@ func (m *Messenger) SetDisplayName(displayName string) error {
return err
}
isDupe, err := m.IsDisplayNameDupeOfCommunityMember(displayName)
if err != nil {
return err
}
if isDupe {
return ErrDisplayNameDupeOfCommunityMember
}
m.account.Name = displayName
err = m.multiAccounts.UpdateDisplayName(m.account.KeyUID, displayName)
if err != nil {
@ -95,11 +105,15 @@ func (m *Messenger) SaveSyncDisplayName(displayName string, clock uint64) error
if err != nil {
return err
}
preferredNameClock, err := m.settings.GetSettingLastSynced(settings.PreferredName)
if err != nil {
return err
}
// check clock of preferred name to avoid override account name
// When either the display name or preferred name changes, m.account.Name should be updated.
// However, a race condition can occur during BackupData, where m.account.Name could be incorrectly updated.
// The final value of m.account.Name depending on which backup message(BackedUpProfile/BackedUpSettings) arrives later.
// So we should check the clock of the preferred name and only update m.account.Name if it's older than the display name.
if preferredNameClock < clock {
m.account.Name = displayName
return m.multiAccounts.SaveAccount(*m.account)

View File

@ -41,6 +41,7 @@ var maxTopicsPerRequest int = 10
var ErrNoFiltersForChat = errors.New("no filter registered for given chat")
func (m *Messenger) shouldSync() (bool, error) {
// TODO (pablo) support community store node as well
if m.mailserverCycle.activeMailserver == nil || !m.Online() {
return false, nil
}
@ -66,8 +67,9 @@ func (m *Messenger) scheduleSyncChat(chat *Chat) (bool, error) {
}
go func() {
_, err := m.performMailserverRequest(func() (*MessengerResponse, error) {
response, err := m.syncChatWithFilters(chat.ID)
ms := m.getActiveMailserver(chat.CommunityID)
_, err = m.performMailserverRequest(ms, func(mailServer mailservers.Mailserver) (*MessengerResponse, error) {
response, err := m.syncChatWithFilters(mailServer, chat.ID)
if err != nil {
m.logger.Error("failed to sync chat", zap.Error(err))
@ -102,45 +104,42 @@ func (m *Messenger) connectToNewMailserverAndWait() error {
return m.findNewMailserver()
}
func (m *Messenger) performMailserverRequest(fn func() (*MessengerResponse, error)) (*MessengerResponse, error) {
func (m *Messenger) performMailserverRequest(ms *mailservers.Mailserver, fn func(mailServer mailservers.Mailserver) (*MessengerResponse, error)) (*MessengerResponse, error) {
if ms == nil {
return nil, errors.New("mailserver not available")
}
m.mailserverCycle.RLock()
defer m.mailserverCycle.RUnlock()
var tries uint = 0
for tries < mailserverMaxTries {
if !m.isActiveMailserverAvailable() {
return nil, errors.New("mailserver not available")
}
m.logger.Info("trying performing mailserver requests", zap.Uint("try", tries))
activeMailserver := m.getActiveMailserver()
// Make sure we are connected to a mailserver
if activeMailserver == nil {
if !m.communityStorenodes.IsCommunityStoreNode(ms.ID) && !m.isMailserverAvailable(ms.ID) {
return nil, errors.New("mailserver not available")
}
m.logger.Info("trying performing mailserver requests", zap.Uint("try", tries), zap.String("mailserverID", ms.ID))
// Peform request
response, err := fn()
response, err := fn(*ms) // pass by value because we don't want the fn to modify the mailserver
if err == nil {
// Reset failed requests
m.logger.Debug("mailserver request performed successfully",
zap.String("mailserverID", activeMailserver.ID))
activeMailserver.FailedRequests = 0
zap.String("mailserverID", ms.ID))
ms.FailedRequests = 0
return response, nil
}
m.logger.Error("failed to perform mailserver request",
zap.String("mailserverID", activeMailserver.ID),
zap.String("mailserverID", ms.ID),
zap.Uint("tries", tries),
zap.Error(err),
)
tries++
// Increment failed requests
activeMailserver.FailedRequests++
ms.FailedRequests++
// Change mailserver
if activeMailserver.FailedRequests >= mailserverMaxFailedRequests {
if ms.FailedRequests >= mailserverMaxFailedRequests {
return nil, errors.New("too many failed requests")
}
// Wait a couple of second not to spam
@ -162,21 +161,26 @@ func (m *Messenger) scheduleSyncFilters(filters []*transport.Filter) (bool, erro
}
go func() {
_, err := m.performMailserverRequest(func() (*MessengerResponse, error) {
response, err := m.syncFilters(filters)
// split filters by community store node so we can request the filters to the correct mailserver
filtersByMs := m.SplitFiltersByStoreNode(filters)
for communityID, filtersForMs := range filtersByMs {
ms := m.getActiveMailserver(communityID)
_, err := m.performMailserverRequest(ms, func(ms mailservers.Mailserver) (*MessengerResponse, error) {
response, err := m.syncFilters(ms, filtersForMs)
if err != nil {
m.logger.Error("failed to sync filter", zap.Error(err))
return nil, err
}
if m.config.messengerSignalsHandler != nil {
m.config.messengerSignalsHandler.MessengerResponse(response)
}
return response, nil
})
if err != nil {
m.logger.Error("failed to sync filter", zap.Error(err))
return nil, err
m.logger.Error("failed to perform mailserver request", zap.Error(err))
}
if m.config.messengerSignalsHandler != nil {
m.config.messengerSignalsHandler.MessengerResponse(response)
}
return response, nil
})
if err != nil {
m.logger.Error("failed to perform mailserver request", zap.Error(err))
}
}()
@ -242,12 +246,13 @@ func (m *Messenger) topicsForChat(chatID string) (string, []types.TopicType, err
return filters[0].PubsubTopic, contentTopics, nil
}
func (m *Messenger) syncChatWithFilters(chatID string) (*MessengerResponse, error) {
func (m *Messenger) syncChatWithFilters(ms mailservers.Mailserver, chatID string) (*MessengerResponse, error) {
filters, err := m.filtersForChat(chatID)
if err != nil {
return nil, err
}
return m.syncFilters(filters)
return m.syncFilters(ms, filters)
}
func (m *Messenger) syncBackup() error {
@ -260,7 +265,8 @@ func (m *Messenger) syncBackup() error {
from, to := m.calculateMailserverTimeBounds(oneMonthDuration)
batch := MailserverBatch{From: from, To: to, Topics: []types.TopicType{filter.ContentTopic}}
err := m.processMailserverBatch(batch)
ms := m.getActiveMailserver(filter.ChatID)
err := m.processMailserverBatch(*ms, batch)
if err != nil {
return err
}
@ -303,14 +309,24 @@ func (m *Messenger) resetFiltersPriority(filters []*transport.Filter) {
}
}
func (m *Messenger) RequestAllHistoricMessagesWithRetries(forceFetchingBackup bool) (*MessengerResponse, error) {
return m.performMailserverRequest(func() (*MessengerResponse, error) {
return m.RequestAllHistoricMessages(forceFetchingBackup)
})
func (m *Messenger) SplitFiltersByStoreNode(filters []*transport.Filter) map[string][]*transport.Filter {
// split filters by community store node so we can request the filters to the correct mailserver
filtersByMs := make(map[string][]*transport.Filter, len(filters))
for _, f := range filters {
communityID := "" // none by default
if chat, ok := m.allChats.Load(f.ChatID); ok && chat.CommunityChat() && m.communityStorenodes.HasStorenodeSetup(chat.CommunityID) {
communityID = chat.CommunityID
}
if _, exists := filtersByMs[communityID]; !exists {
filtersByMs[communityID] = make([]*transport.Filter, 0, len(filters))
}
filtersByMs[communityID] = append(filtersByMs[communityID], f)
}
return filtersByMs
}
// RequestAllHistoricMessages requests all the historic messages for any topic
func (m *Messenger) RequestAllHistoricMessages(forceFetchingBackup bool) (*MessengerResponse, error) {
func (m *Messenger) RequestAllHistoricMessages(forceFetchingBackup, withRetries bool) (*MessengerResponse, error) {
shouldSync, err := m.shouldSync()
if err != nil {
return nil, err
@ -337,18 +353,37 @@ func (m *Messenger) RequestAllHistoricMessages(forceFetchingBackup bool) (*Messe
filters := m.transport.Filters()
m.updateFiltersPriority(filters)
defer m.resetFiltersPriority(filters)
response, err := m.syncFilters(filters)
if err != nil {
return nil, err
filtersByMs := m.SplitFiltersByStoreNode(filters)
allResponses := &MessengerResponse{}
for communityID, filtersForMs := range filtersByMs {
ms := m.getActiveMailserver(communityID)
if withRetries {
response, err := m.performMailserverRequest(ms, func(ms mailservers.Mailserver) (*MessengerResponse, error) {
return m.syncFilters(ms, filtersForMs)
})
if err != nil {
return nil, err
}
allResponses.AddChats(response.Chats())
allResponses.AddMessages(response.Messages())
continue
}
response, err := m.syncFilters(*ms, filtersForMs)
if err != nil {
return nil, err
}
allResponses.AddChats(response.Chats())
allResponses.AddMessages(response.Messages())
}
return response, nil
return allResponses, nil
}
func getPrioritizedBatches() []int {
return []int{1, 5, 10}
}
func (m *Messenger) syncFiltersFrom(filters []*transport.Filter, lastRequest uint32) (*MessengerResponse, error) {
func (m *Messenger) syncFiltersFrom(ms mailservers.Mailserver, filters []*transport.Filter, lastRequest uint32) (*MessengerResponse, error) {
response := &MessengerResponse{}
topicInfo, err := m.mailserversDatabase.Topics()
if err != nil {
@ -519,10 +554,8 @@ func (m *Messenger) syncFiltersFrom(filters []*transport.Filter, lastRequest uin
}
}
i := 0
for _, batch := range batches24h {
i++
err := m.processMailserverBatch(batch)
err := m.processMailserverBatch(ms, batch)
if err != nil {
m.logger.Error("error syncing topics", zap.Error(err))
return nil, err
@ -580,8 +613,8 @@ func (m *Messenger) syncFiltersFrom(filters []*transport.Filter, lastRequest uin
return response, nil
}
func (m *Messenger) syncFilters(filters []*transport.Filter) (*MessengerResponse, error) {
return m.syncFiltersFrom(filters, 0)
func (m *Messenger) syncFilters(ms mailservers.Mailserver, filters []*transport.Filter) (*MessengerResponse, error) {
return m.syncFiltersFrom(ms, filters, 0)
}
func (m *Messenger) calculateGapForChat(chat *Chat, from uint32) (*common.Message, error) {
@ -802,30 +835,30 @@ loop:
return result
}
func (m *Messenger) processMailserverBatch(batch MailserverBatch) error {
func (m *Messenger) processMailserverBatch(ms mailservers.Mailserver, batch MailserverBatch) error {
if m.featureFlags.StoreNodesDisabled {
return nil
}
mailserverID, err := m.activeMailserverID()
mailserverID, err := ms.IDBytes()
if err != nil {
return err
}
return processMailserverBatch(m.ctx, m.transport, batch, mailserverID, m.logger, defaultStoreNodeRequestPageSize, nil, false)
logger := m.logger.With(zap.String("mailserverID", ms.ID))
return processMailserverBatch(m.ctx, m.transport, batch, mailserverID, logger, defaultStoreNodeRequestPageSize, nil, false)
}
func (m *Messenger) processMailserverBatchWithOptions(batch MailserverBatch, pageLimit uint32, shouldProcessNextPage func(int) (bool, uint32), processEnvelopes bool) error {
func (m *Messenger) processMailserverBatchWithOptions(ms mailservers.Mailserver, batch MailserverBatch, pageLimit uint32, shouldProcessNextPage func(int) (bool, uint32), processEnvelopes bool) error {
if m.featureFlags.StoreNodesDisabled {
return nil
}
mailserverID, err := m.activeMailserverID()
mailserverID, err := ms.IDBytes()
if err != nil {
return err
}
return processMailserverBatch(m.ctx, m.transport, batch, mailserverID, m.logger, pageLimit, shouldProcessNextPage, processEnvelopes)
logger := m.logger.With(zap.String("mailserverID", ms.ID))
return processMailserverBatch(m.ctx, m.transport, batch, mailserverID, logger, pageLimit, shouldProcessNextPage, processEnvelopes)
}
type MailserverBatch struct {
@ -838,18 +871,19 @@ type MailserverBatch struct {
}
func (m *Messenger) SyncChatFromSyncedFrom(chatID string) (uint32, error) {
chat, ok := m.allChats.Load(chatID)
if !ok {
return 0, ErrChatNotFound
}
ms := m.getActiveMailserver(chat.CommunityID)
var from uint32
_, err := m.performMailserverRequest(func() (*MessengerResponse, error) {
_, err := m.performMailserverRequest(ms, func(ms mailservers.Mailserver) (*MessengerResponse, error) {
pubsubTopic, topics, err := m.topicsForChat(chatID)
if err != nil {
return nil, nil
}
chat, ok := m.allChats.Load(chatID)
if !ok {
return nil, ErrChatNotFound
}
defaultSyncPeriod, err := m.settings.GetDefaultSyncPeriod()
if err != nil {
return nil, err
@ -866,7 +900,7 @@ func (m *Messenger) SyncChatFromSyncedFrom(chatID string) (uint32, error) {
m.config.messengerSignalsHandler.HistoryRequestStarted(1)
}
err = m.processMailserverBatch(batch)
err = m.processMailserverBatch(ms, batch)
if err != nil {
return nil, err
}
@ -897,7 +931,7 @@ func (m *Messenger) FillGaps(chatID string, messageIDs []string) error {
return err
}
_, ok := m.allChats.Load(chatID)
chat, ok := m.allChats.Load(chatID)
if !ok {
return errors.New("chat not existing")
}
@ -935,7 +969,8 @@ func (m *Messenger) FillGaps(chatID string, messageIDs []string) error {
m.config.messengerSignalsHandler.HistoryRequestStarted(1)
}
err = m.processMailserverBatch(batch)
ms := m.getActiveMailserver(chat.CommunityID)
err = m.processMailserverBatch(*ms, batch)
if err != nil {
return err
}
@ -1017,17 +1052,19 @@ func (m *Messenger) ConnectionChanged(state connection.State) {
func (m *Messenger) fetchMessages(chatID string, duration time.Duration) (uint32, error) {
from, to := m.calculateMailserverTimeBounds(duration)
_, err := m.performMailserverRequest(func() (*MessengerResponse, error) {
chat, ok := m.allChats.Load(chatID)
if !ok {
return 0, ErrChatNotFound
}
ms := m.getActiveMailserver(chat.CommunityID)
_, err := m.performMailserverRequest(ms, func(ms mailservers.Mailserver) (*MessengerResponse, error) {
m.logger.Debug("fetching messages", zap.String("chatID", chatID), zap.String("mailserver", ms.Name))
pubsubTopic, topics, err := m.topicsForChat(chatID)
if err != nil {
return nil, nil
}
chat, ok := m.allChats.Load(chatID)
if !ok {
return nil, ErrChatNotFound
}
batch := MailserverBatch{
ChatIDs: []string{chatID},
From: from,
@ -1039,7 +1076,7 @@ func (m *Messenger) fetchMessages(chatID string, duration time.Duration) (uint32
m.config.messengerSignalsHandler.HistoryRequestStarted(1)
}
err = m.processMailserverBatch(batch)
err = m.processMailserverBatch(ms, batch)
if err != nil {
return nil, err
}

View File

@ -18,6 +18,7 @@ import (
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/status-im/status-go/params"
"github.com/status-im/status-go/protocol/storenodes"
"github.com/status-im/status-go/services/mailservers"
"github.com/status-im/status-go/signal"
)
@ -50,14 +51,6 @@ func (s byRTTMsAndCanConnectBefore) Less(i, j int) bool {
return s[i].CanConnectAfter.Before(s[j].CanConnectAfter)
}
func (m *Messenger) activeMailserverID() ([]byte, error) {
if m.mailserverCycle.activeMailserver == nil {
return nil, nil
}
return m.mailserverCycle.activeMailserver.IDBytes()
}
func (m *Messenger) StartMailserverCycle(mailservers []mailservers.Mailserver) error {
m.mailserverCycle.allMailservers = mailservers
@ -353,19 +346,14 @@ func (m *Messenger) findNewMailserver() error {
}
func (m *Messenger) activeMailserverStatus() (connStatus, error) {
if m.mailserverCycle.activeMailserver == nil {
return disconnected, errors.New("Active mailserver is not set")
func (m *Messenger) mailserverStatus(mailserverID string) connStatus {
m.mailPeersMutex.RLock()
defer m.mailPeersMutex.RUnlock()
peer, ok := m.mailserverCycle.peers[mailserverID]
if !ok {
return disconnected
}
mailserverID := m.mailserverCycle.activeMailserver.ID
m.mailPeersMutex.Lock()
status := m.mailserverCycle.peers[mailserverID].status
m.mailPeersMutex.Unlock()
return status, nil
return peer.status
}
func (m *Messenger) connectToMailserver(ms mailservers.Mailserver) error {
@ -380,11 +368,7 @@ func (m *Messenger) connectToMailserver(ms mailservers.Mailserver) error {
// received after the peer was added. So we first set the peer status as
// Connecting and once a peerConnected signal is received, we mark it as
// Connected
activeMailserverStatus, err := m.activeMailserverStatus()
if err != nil {
return err
}
activeMailserverStatus := m.mailserverStatus(ms.ID)
if ms.Version != m.transport.WakuVersion() {
return errors.New("mailserver waku version doesn't match")
}
@ -425,28 +409,51 @@ func (m *Messenger) connectToMailserver(ms mailservers.Mailserver) error {
signal.SendMailserverAvailable(m.mailserverCycle.activeMailserver.Address, m.mailserverCycle.activeMailserver.ID)
// Query mailserver
if m.config.featureFlags.AutoRequestHistoricMessages {
m.asyncRequestAllHistoricMessages()
if m.config.codeControlFlags.AutoRequestHistoricMessages {
go func() {
_, err := m.performMailserverRequest(&ms, func(_ mailservers.Mailserver) (*MessengerResponse, error) {
return m.RequestAllHistoricMessages(false, false)
})
if err != nil {
m.logger.Error("could not perform mailserver request", zap.Error(err))
}
}()
}
}
}
return nil
}
func (m *Messenger) getActiveMailserver() *mailservers.Mailserver {
return m.mailserverCycle.activeMailserver
}
func (m *Messenger) isActiveMailserverAvailable() bool {
mailserverStatus, err := m.activeMailserverStatus()
if err != nil {
return false
// getActiveMailserver returns the active mailserver if a communityID is present then it'll return the mailserver
// for that community if it has a mailserver setup otherwise it'll return the global mailserver
func (m *Messenger) getActiveMailserver(communityID ...string) *mailservers.Mailserver {
if len(communityID) == 0 || communityID[0] == "" {
return m.mailserverCycle.activeMailserver
}
return mailserverStatus == connected
ms, err := m.communityStorenodes.GetStorenodeByCommunnityID(communityID[0])
if err != nil {
if !errors.Is(err, storenodes.ErrNotFound) {
m.logger.Error("getting storenode for community, using global", zap.String("communityID", communityID[0]), zap.Error(err))
}
// if we don't find a specific mailserver for the community, we just use the regular mailserverCycle's one
return m.mailserverCycle.activeMailserver
}
return &ms
}
func (m *Messenger) mailserverAddressToID(uniqueID string, allMailservers []mailservers.Mailserver) (string, error) {
func (m *Messenger) getActiveMailserverID(communityID ...string) string {
ms := m.getActiveMailserver(communityID...)
if ms == nil {
return ""
}
return ms.ID
}
func (m *Messenger) isMailserverAvailable(mailserverID string) bool {
return m.mailserverStatus(mailserverID) == connected
}
func mailserverAddressToID(uniqueID string, allMailservers []mailservers.Mailserver) (string, error) {
for _, ms := range allMailservers {
if uniqueID == ms.UniqueID() {
return ms.ID, nil
@ -485,6 +492,7 @@ func (m *Messenger) penalizeMailserver(id string) {
m.mailserverCycle.peers[id] = pInfo
}
// handleMailserverCycleEvent runs every 1 second or when updating peers to keep the data of the active mailserver updated
func (m *Messenger) handleMailserverCycleEvent(connectedPeers []ConnectedPeer) error {
m.logger.Debug("mailserver cycle event",
zap.Any("connected", connectedPeers),
@ -501,7 +509,7 @@ func (m *Messenger) handleMailserverCycleEvent(connectedPeers []ConnectedPeer) e
found := false
for _, connectedPeer := range connectedPeers {
id, err := m.mailserverAddressToID(connectedPeer.UniqueID, m.mailserverCycle.allMailservers)
id, err := mailserverAddressToID(connectedPeer.UniqueID, m.mailserverCycle.allMailservers)
if err != nil {
m.logger.Error("failed to convert id to hex", zap.Error(err))
return err
@ -527,7 +535,7 @@ func (m *Messenger) handleMailserverCycleEvent(connectedPeers []ConnectedPeer) e
// not available error
if m.mailserverCycle.activeMailserver != nil {
for _, connectedPeer := range connectedPeers {
id, err := m.mailserverAddressToID(connectedPeer.UniqueID, m.mailserverCycle.allMailservers)
id, err := mailserverAddressToID(connectedPeer.UniqueID, m.mailserverCycle.allMailservers)
if err != nil {
m.logger.Error("failed to convert id to hex", zap.Error(err))
return err
@ -554,8 +562,13 @@ func (m *Messenger) handleMailserverCycleEvent(connectedPeers []ConnectedPeer) e
signal.SendMailserverAvailable(m.mailserverCycle.activeMailserver.Address, m.mailserverCycle.activeMailserver.ID)
}
// Query mailserver
if m.config.featureFlags.AutoRequestHistoricMessages {
m.asyncRequestAllHistoricMessages()
if m.config.codeControlFlags.AutoRequestHistoricMessages {
go func() {
_, err := m.RequestAllHistoricMessages(false, true)
if err != nil {
m.logger.Error("failed to request historic messages", zap.Error(err))
}
}()
}
} else {
m.mailPeersMutex.Unlock()
@ -600,7 +613,7 @@ func (m *Messenger) handleMailserverCycleEvent(connectedPeers []ConnectedPeer) e
func (m *Messenger) asyncRequestAllHistoricMessages() {
m.logger.Debug("asyncRequestAllHistoricMessages")
go func() {
_, err := m.RequestAllHistoricMessagesWithRetries(false)
_, err := m.RequestAllHistoricMessages(false, true)
if err != nil {
m.logger.Error("failed to request historic messages", zap.Error(err))
}
@ -760,7 +773,7 @@ func (m *Messenger) waitForAvailableStoreNode(timeout time.Duration) bool {
defer func() {
wg.Done()
}()
for !m.isActiveMailserverAvailable() {
for !m.isMailserverAvailable(m.getActiveMailserverID()) {
select {
case <-m.SubscribeMailserverAvailable():
case <-cancel:
@ -784,5 +797,5 @@ func (m *Messenger) waitForAvailableStoreNode(timeout time.Duration) bool {
close(cancel)
}
return m.isActiveMailserverAvailable()
return m.isMailserverAvailable(m.getActiveMailserverID())
}

View File

@ -518,3 +518,42 @@ func (m *Messenger) SendGroupChatMessage(request *requests.SendGroupChatMessage)
return m.sendChatMessage(context.Background(), message)
}
func (m *Messenger) deleteCommunityMemberMessages(member string, communityID string, deleteMessages []*protobuf.DeleteCommunityMemberMessage) (*MessengerResponse, error) {
messagesToDelete := deleteMessages
var err error
if len(deleteMessages) == 0 {
messagesToDelete, err = m.persistence.GetCommunityMemberMessagesToDelete(member, communityID)
if err != nil {
return nil, err
}
}
response := &MessengerResponse{}
if len(messagesToDelete) == 0 {
return response, nil
}
for _, messageToDelete := range messagesToDelete {
updatedMessages, err := m.persistence.MessagesByResponseTo(messageToDelete.Id)
if err != nil {
return nil, err
}
response.AddMessages(updatedMessages)
}
response.AddDeletedMessages(messagesToDelete)
messageIDs := make([]string, 0, len(messagesToDelete))
for _, rm := range messagesToDelete {
messageIDs = append(messageIDs, rm.Id)
}
if err = m.persistence.DeleteMessages(messageIDs); err != nil {
return nil, err
}
return response, nil
}

View File

@ -62,7 +62,15 @@ func (m *Messenger) handleDatasyncMetadata(response *common.HandleMessageRespons
return nil
}
err := m.OnDatasyncOffer(response)
isPeerSyncingEnabled, err := m.settings.GetPeerSyncingEnabled()
if err != nil {
return err
}
if !isPeerSyncingEnabled {
return nil
}
err = m.OnDatasyncOffer(response)
if err != nil {
return err
}
@ -102,6 +110,14 @@ func (m *Messenger) sendDatasyncOffers() error {
return nil
}
isPeerSyncingEnabled, err := m.settings.GetPeerSyncingEnabled()
if err != nil {
return err
}
if !isPeerSyncingEnabled {
return nil
}
communities, err := m.communitiesManager.Joined()
if err != nil {
return err

View File

@ -31,24 +31,6 @@ func (m *Messenger) sendPinMessage(ctx context.Context, message *common.PinMessa
return nil, errors.New("chat not found")
}
if chat.CommunityChat() {
community, err := m.communitiesManager.GetByIDString(chat.CommunityID)
if err != nil {
return nil, err
}
hasPermission := community.IsPrivilegedMember(&m.identity.PublicKey)
pinMessageAllowed := community.AllowsAllMembersToPinMessage()
canPost, err := community.CanPost(&m.identity.PublicKey, chat.CommunityChatID())
if err != nil {
return nil, err
}
if !canPost && !pinMessageAllowed && !hasPermission {
return nil, errors.New("can't pin message")
}
}
err := m.handleStandaloneChatIdentity(chat)
if err != nil {
return nil, err

View File

@ -1,125 +1,311 @@
package protocol
import (
"context"
"crypto/ecdsa"
crand "crypto/rand"
"errors"
"math/big"
"reflect"
"sort"
"strings"
"github.com/golang/protobuf/proto"
"go.uber.org/zap"
eth_common "github.com/ethereum/go-ethereum/common"
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/multiaccounts/accounts"
"github.com/status-im/status-go/protocol/common"
"github.com/status-im/status-go/protocol/communities"
"github.com/status-im/status-go/protocol/identity"
"github.com/status-im/status-go/protocol/protobuf"
"github.com/status-im/status-go/services/wallet/bigint"
w_common "github.com/status-im/status-go/services/wallet/common"
"github.com/status-im/status-go/services/wallet/thirdparty"
)
var errorNoAccountProvidedWithTokenOrCollectible = errors.New("no account provided with tokens or collectible")
var errorDublicateAccountAddress = errors.New("duplicate account address")
// NOTE: this error is temporary unused because we don't know account on this stage
// var errorNoAccountAddressForCollectible = errors.New("no account found for collectible")
var errorAccountVisibilityLowerThanCollectible = errors.New("account visibility lower than collectible")
var errorDecryptingPayloadEncryptionKey = errors.New("decrypting the payload encryption key resulted in no error and a nil key")
var errorConvertCollectibleTokenIDToInt = errors.New("failed to convert collectible token id to bigint")
var errorNoAccountPresentedForCollectible = errors.New("account holding the collectible is not presented in the profile showcase")
var errorDublicateAccountAddress = errors.New("duplicate account address")
var errorAccountVisibilityLowerThanCollectible = errors.New("account visibility lower than collectible")
func toProfileShowcaseCommunityProto(preferences []*ProfileShowcaseCommunityPreference, visibility ProfileShowcaseVisibility) []*protobuf.ProfileShowcaseCommunity {
communities := []*protobuf.ProfileShowcaseCommunity{}
for _, preference := range preferences {
if preference.ShowcaseVisibility != visibility {
continue
}
communities = append(communities, &protobuf.ProfileShowcaseCommunity{
CommunityId: preference.CommunityID,
Order: uint32(preference.Order),
})
}
return communities
func sortProfileEntyByOrder(slice interface{}, getOrder func(int) int) {
sort.Slice(slice, func(i, j int) bool {
return getOrder(j) > getOrder(i)
})
}
func toProfileShowcaseAccountProto(preferences []*ProfileShowcaseAccountPreference, visibility ProfileShowcaseVisibility) []*protobuf.ProfileShowcaseAccount {
accounts := []*protobuf.ProfileShowcaseAccount{}
func toCollectibleUniqueID(contractAddress string, tokenID string, chainID uint64) (thirdparty.CollectibleUniqueID, error) {
tokenIDInt := new(big.Int)
tokenIDInt, isTokenIDOk := tokenIDInt.SetString(tokenID, 10)
if !isTokenIDOk {
return thirdparty.CollectibleUniqueID{}, errorConvertCollectibleTokenIDToInt
}
return thirdparty.CollectibleUniqueID{
ContractID: thirdparty.ContractID{
ChainID: w_common.ChainID(chainID),
Address: eth_common.HexToAddress(contractAddress),
},
TokenID: &bigint.BigInt{Int: tokenIDInt},
}, nil
}
func (m *Messenger) fetchCollectibleOwner(contractAddress string, tokenID string, chainID uint64) ([]thirdparty.AccountBalance, error) {
collectibleID, err := toCollectibleUniqueID(contractAddress, tokenID, chainID)
if err != nil {
return nil, err
}
balance, err := m.communitiesManager.GetCollectiblesManager().GetCollectibleOwnership(collectibleID)
if err != nil {
return nil, err
}
return balance, nil
}
func (m *Messenger) validateCollectiblesOwnership(accounts []*identity.ProfileShowcaseAccountPreference,
collectibles []*identity.ProfileShowcaseCollectiblePreference) error {
accountsMap := make(map[string]identity.ProfileShowcaseVisibility)
for _, accountProfile := range accounts {
addressCapitalized := strings.ToUpper(accountProfile.Address)
if _, ok := accountsMap[addressCapitalized]; ok {
return errorDublicateAccountAddress
}
accountsMap[addressCapitalized] = accountProfile.ShowcaseVisibility
}
for _, collectibleProfile := range collectibles {
balances, err := m.fetchCollectibleOwner(collectibleProfile.ContractAddress, collectibleProfile.TokenID,
collectibleProfile.ChainID)
if err != nil {
return err
}
// NOTE: ERC721 tokens can have only a single holder
// but ERC1155 which can be supported later can have more than one holder and balances > 1
found := false
for _, balance := range balances {
addressCapitalized := strings.ToUpper(balance.Address.String())
if accountShowcaseVisibility, ok := accountsMap[addressCapitalized]; ok {
if accountShowcaseVisibility < collectibleProfile.ShowcaseVisibility {
return errorAccountVisibilityLowerThanCollectible
}
found = true
break
}
}
if !found {
return errorNoAccountPresentedForCollectible
}
}
return nil
}
func (m *Messenger) validateCommunityMembershipEntry(
entry *identity.ProfileShowcaseCommunity,
community *communities.Community,
contactPubKey *ecdsa.PublicKey) (identity.ProfileShowcaseMembershipStatus, error) {
if community == nil {
return identity.ProfileShowcaseMembershipStatusUnproven, nil
}
if community.Encrypted() {
// NOTE: commentend for 0.177.x release, actual fix is here:
// https://github.com/status-im/status-go/pull/5024
return identity.ProfileShowcaseMembershipStatusProvenMember, nil
// grant, err := community.VerifyGrantSignature(entry.Grant)
// if err != nil {
// m.logger.Warn("failed to verify grant signature ", zap.Error(err))
// return identity.ProfileShowcaseMembershipStatusNotAMember, nil
// }
// if grant != nil && bytes.Equal(grant.MemberId, crypto.CompressPubkey(contactPubKey)) {
// return identity.ProfileShowcaseMembershipStatusProvenMember, nil
// }
// // Show as not a member if membership can't be proven
// return identity.ProfileShowcaseMembershipStatusNotAMember, nil
}
if community.HasMember(contactPubKey) {
return identity.ProfileShowcaseMembershipStatusProvenMember, nil
}
return identity.ProfileShowcaseMembershipStatusNotAMember, nil
}
func (m *Messenger) validateCommunitiesMembership(communities []*identity.ProfileShowcaseCommunity, contactPubKey *ecdsa.PublicKey) ([]*identity.ProfileShowcaseCommunity, error) {
validatedCommunities := []*identity.ProfileShowcaseCommunity{}
for _, communityEntry := range communities {
community, err := m.FetchCommunity(&FetchCommunityRequest{
CommunityKey: communityEntry.CommunityID,
Shard: nil,
TryDatabase: true,
WaitForResponse: true,
})
if err != nil {
m.logger.Warn("failed to fetch community for profile entry ", zap.Error(err))
continue
}
communityEntry.MembershipStatus, err = m.validateCommunityMembershipEntry(communityEntry, community, contactPubKey)
if err != nil {
m.logger.Warn("failed to verify grant signature ", zap.Error(err))
}
validatedCommunities = append(validatedCommunities, communityEntry)
}
return validatedCommunities, nil
}
func (m *Messenger) toProfileShowcaseCommunityProto(preferences []*identity.ProfileShowcaseCommunityPreference, visibility identity.ProfileShowcaseVisibility) []*protobuf.ProfileShowcaseCommunity {
entries := []*protobuf.ProfileShowcaseCommunity{}
for _, preference := range preferences {
if preference.ShowcaseVisibility != visibility {
continue
}
accounts = append(accounts, &protobuf.ProfileShowcaseAccount{
entry := &protobuf.ProfileShowcaseCommunity{
CommunityId: preference.CommunityID,
Order: uint32(preference.Order),
}
community, err := m.communitiesManager.GetByIDString(preference.CommunityID)
if err != nil {
m.logger.Warn("failed to get community for profile entry ", zap.Error(err))
}
if community != nil && community.Encrypted() {
grant, _, err := m.communitiesManager.GetCommunityGrant(preference.CommunityID)
if err != nil {
m.logger.Warn("failed to get community for profile entry ", zap.Error(err))
}
entry.Grant = grant
}
entries = append(entries, entry)
}
return entries
}
func (m *Messenger) toProfileShowcaseAccountProto(preferences []*identity.ProfileShowcaseAccountPreference, visibility identity.ProfileShowcaseVisibility) []*protobuf.ProfileShowcaseAccount {
entries := []*protobuf.ProfileShowcaseAccount{}
for _, preference := range preferences {
if preference.ShowcaseVisibility != visibility {
continue
}
account, err := m.settings.GetAccountByAddress(types.HexToAddress(preference.Address))
if err != nil {
m.logger.Warn("failed to get account for profile entry ", zap.Error(err))
}
if account == nil {
m.logger.Warn("can not find wallet account for profile entry ")
continue
}
entries = append(entries, &protobuf.ProfileShowcaseAccount{
Address: preference.Address,
Name: preference.Name,
ColorId: preference.ColorID,
Emoji: preference.Emoji,
Name: account.Name,
ColorId: string(account.ColorID),
Emoji: account.Emoji,
Order: uint32(preference.Order),
})
}
return accounts
return entries
}
func toProfileShowcaseCollectibleProto(preferences []*ProfileShowcaseCollectiblePreference, visibility ProfileShowcaseVisibility) []*protobuf.ProfileShowcaseCollectible {
collectibles := []*protobuf.ProfileShowcaseCollectible{}
func (m *Messenger) toProfileShowcaseCollectibleProto(preferences []*identity.ProfileShowcaseCollectiblePreference, visibility identity.ProfileShowcaseVisibility) []*protobuf.ProfileShowcaseCollectible {
entries := []*protobuf.ProfileShowcaseCollectible{}
for _, preference := range preferences {
if preference.ShowcaseVisibility != visibility {
continue
}
collectibles = append(collectibles, &protobuf.ProfileShowcaseCollectible{
entries = append(entries, &protobuf.ProfileShowcaseCollectible{
ContractAddress: preference.ContractAddress,
ChainId: preference.ChainID,
TokenId: preference.TokenID,
CommunityId: preference.CommunityID,
AccountAddress: preference.AccountAddress,
Order: uint32(preference.Order),
})
}
return collectibles
return entries
}
func toProfileShowcaseVerifiedTokensProto(preferences []*ProfileShowcaseVerifiedTokenPreference, visibility ProfileShowcaseVisibility) []*protobuf.ProfileShowcaseVerifiedToken {
tokens := []*protobuf.ProfileShowcaseVerifiedToken{}
func (m *Messenger) toProfileShowcaseVerifiedTokensProto(preferences []*identity.ProfileShowcaseVerifiedTokenPreference, visibility identity.ProfileShowcaseVisibility) []*protobuf.ProfileShowcaseVerifiedToken {
entries := []*protobuf.ProfileShowcaseVerifiedToken{}
for _, preference := range preferences {
if preference.ShowcaseVisibility != visibility {
continue
}
tokens = append(tokens, &protobuf.ProfileShowcaseVerifiedToken{
entries = append(entries, &protobuf.ProfileShowcaseVerifiedToken{
Symbol: preference.Symbol,
Order: uint32(preference.Order),
})
}
return tokens
return entries
}
func toProfileShowcaseUnverifiedTokensProto(preferences []*ProfileShowcaseUnverifiedTokenPreference, visibility ProfileShowcaseVisibility) []*protobuf.ProfileShowcaseUnverifiedToken {
tokens := []*protobuf.ProfileShowcaseUnverifiedToken{}
func (m *Messenger) toProfileShowcaseUnverifiedTokensProto(preferences []*identity.ProfileShowcaseUnverifiedTokenPreference, visibility identity.ProfileShowcaseVisibility) []*protobuf.ProfileShowcaseUnverifiedToken {
entries := []*protobuf.ProfileShowcaseUnverifiedToken{}
for _, preference := range preferences {
if preference.ShowcaseVisibility != visibility {
continue
}
tokens = append(tokens, &protobuf.ProfileShowcaseUnverifiedToken{
entries = append(entries, &protobuf.ProfileShowcaseUnverifiedToken{
ContractAddress: preference.ContractAddress,
ChainId: preference.ChainID,
Order: uint32(preference.Order),
})
}
return tokens
return entries
}
func fromProfileShowcaseCommunityProto(messages []*protobuf.ProfileShowcaseCommunity) []*ProfileShowcaseCommunity {
communities := []*ProfileShowcaseCommunity{}
for _, entry := range messages {
communities = append(communities, &ProfileShowcaseCommunity{
CommunityID: entry.CommunityId,
Order: int(entry.Order),
func (m *Messenger) toProfileShowcaseSocialLinksProto(preferences []*identity.ProfileShowcaseSocialLinkPreference, visibility identity.ProfileShowcaseVisibility) []*protobuf.ProfileShowcaseSocialLink {
entries := []*protobuf.ProfileShowcaseSocialLink{}
for _, preference := range preferences {
if preference.ShowcaseVisibility != visibility {
continue
}
entries = append(entries, &protobuf.ProfileShowcaseSocialLink{
Text: preference.Text,
Url: preference.URL,
Order: uint32(preference.Order),
})
}
return communities
return entries
}
func fromProfileShowcaseAccountProto(messages []*protobuf.ProfileShowcaseAccount) []*ProfileShowcaseAccount {
accounts := []*ProfileShowcaseAccount{}
func (m *Messenger) fromProfileShowcaseCommunityProto(senderPubKey *ecdsa.PublicKey, messages []*protobuf.ProfileShowcaseCommunity) []*identity.ProfileShowcaseCommunity {
// NOTE: no requests to the network are allowed to be made here, called in the receiver thread
entries := []*identity.ProfileShowcaseCommunity{}
for _, message := range messages {
entry := &identity.ProfileShowcaseCommunity{
CommunityID: message.CommunityId,
Order: int(message.Order),
Grant: message.Grant,
}
entries = append(entries, entry)
}
return entries
}
func (m *Messenger) fromProfileShowcaseAccountProto(messages []*protobuf.ProfileShowcaseAccount) []*identity.ProfileShowcaseAccount {
// NOTE: no requests to the network are allowed to be made here, called in the receiver thread
entries := []*identity.ProfileShowcaseAccount{}
for _, entry := range messages {
accounts = append(accounts, &ProfileShowcaseAccount{
entries = append(entries, &identity.ProfileShowcaseAccount{
Address: entry.Address,
Name: entry.Name,
ColorID: entry.ColorId,
@ -127,78 +313,75 @@ func fromProfileShowcaseAccountProto(messages []*protobuf.ProfileShowcaseAccount
Order: int(entry.Order),
})
}
return accounts
return entries
}
func fromProfileShowcaseCollectibleProto(messages []*protobuf.ProfileShowcaseCollectible) []*ProfileShowcaseCollectible {
collectibles := []*ProfileShowcaseCollectible{}
for _, entry := range messages {
collectibles = append(collectibles, &ProfileShowcaseCollectible{
ContractAddress: entry.ContractAddress,
ChainID: entry.ChainId,
TokenID: entry.TokenId,
CommunityID: entry.CommunityId,
AccountAddress: entry.AccountAddress,
Order: int(entry.Order),
})
func (m *Messenger) fromProfileShowcaseCollectibleProto(messages []*protobuf.ProfileShowcaseCollectible) []*identity.ProfileShowcaseCollectible {
// NOTE: no requests to the network are allowed to be made here, called in the receiver thread
entries := []*identity.ProfileShowcaseCollectible{}
for _, message := range messages {
entry := &identity.ProfileShowcaseCollectible{
ContractAddress: message.ContractAddress,
ChainID: message.ChainId,
TokenID: message.TokenId,
Order: int(message.Order),
}
entries = append(entries, entry)
}
return collectibles
return entries
}
func fromProfileShowcaseVerifiedTokenProto(messages []*protobuf.ProfileShowcaseVerifiedToken) []*ProfileShowcaseVerifiedToken {
tokens := []*ProfileShowcaseVerifiedToken{}
func (m *Messenger) fromProfileShowcaseVerifiedTokenProto(messages []*protobuf.ProfileShowcaseVerifiedToken) []*identity.ProfileShowcaseVerifiedToken {
// NOTE: no requests to the network are allowed to be made here, called in the receiver thread
entries := []*identity.ProfileShowcaseVerifiedToken{}
for _, entry := range messages {
tokens = append(tokens, &ProfileShowcaseVerifiedToken{
entries = append(entries, &identity.ProfileShowcaseVerifiedToken{
Symbol: entry.Symbol,
Order: int(entry.Order),
})
}
return tokens
return entries
}
func fromProfileShowcaseUnverifiedTokenProto(messages []*protobuf.ProfileShowcaseUnverifiedToken) []*ProfileShowcaseUnverifiedToken {
tokens := []*ProfileShowcaseUnverifiedToken{}
func (m *Messenger) fromProfileShowcaseUnverifiedTokenProto(messages []*protobuf.ProfileShowcaseUnverifiedToken) []*identity.ProfileShowcaseUnverifiedToken {
// NOTE: no requests to the network are allowed to be made here, called in the receiver thread
entries := []*identity.ProfileShowcaseUnverifiedToken{}
for _, entry := range messages {
tokens = append(tokens, &ProfileShowcaseUnverifiedToken{
entries = append(entries, &identity.ProfileShowcaseUnverifiedToken{
ContractAddress: entry.ContractAddress,
ChainID: entry.ChainId,
Order: int(entry.Order),
})
}
return tokens
return entries
}
func Validate(preferences *ProfileShowcasePreferences) error {
if (len(preferences.VerifiedTokens) > 0 || len(preferences.UnverifiedTokens) > 0 || len(preferences.Collectibles) > 0) &&
len(preferences.Accounts) == 0 {
return errorNoAccountProvidedWithTokenOrCollectible
func (m *Messenger) fromProfileShowcaseSocialLinkProto(messages []*protobuf.ProfileShowcaseSocialLink) []*identity.ProfileShowcaseSocialLink {
// NOTE: no requests to the network are allowed to be made here, called in the receiver thread
entries := []*identity.ProfileShowcaseSocialLink{}
for _, entry := range messages {
entries = append(entries, &identity.ProfileShowcaseSocialLink{
Text: entry.Text,
URL: entry.Url,
Order: int(entry.Order),
})
}
accountsMap := make(map[string]*ProfileShowcaseAccountPreference)
for _, account := range preferences.Accounts {
if _, ok := accountsMap[account.Address]; ok {
return errorDublicateAccountAddress
}
accountsMap[account.Address] = account
}
for _, collectible := range preferences.Collectibles {
account, ok := accountsMap[collectible.AccountAddress]
if !ok {
return nil
// NOTE: with current wallet collectible implementation we don't know account on this stage
// return errorNoAccountAddressForCollectible
}
if account.ShowcaseVisibility < collectible.ShowcaseVisibility {
return errorAccountVisibilityLowerThanCollectible
}
}
return nil
return entries
}
func (m *Messenger) SetProfileShowcasePreferences(preferences *ProfileShowcasePreferences) error {
err := Validate(preferences)
func (m *Messenger) SetProfileShowcasePreferences(preferences *identity.ProfileShowcasePreferences, sync bool) error {
clock, _ := m.getLastClockWithRelatedChat()
preferences.Clock = clock
return m.setProfileShowcasePreferences(preferences, sync)
}
func (m *Messenger) setProfileShowcasePreferences(preferences *identity.ProfileShowcasePreferences, sync bool) error {
err := identity.Validate(preferences)
if err != nil {
return err
}
err = m.validateCollectiblesOwnership(preferences.Accounts, preferences.Collectibles)
if err != nil {
return err
}
@ -208,25 +391,65 @@ func (m *Messenger) SetProfileShowcasePreferences(preferences *ProfileShowcasePr
return err
}
if sync {
err = m.syncProfileShowcasePreferences(context.Background(), m.dispatchMessage)
if err != nil {
return err
}
}
return m.DispatchProfileShowcase()
}
func (m *Messenger) DispatchProfileShowcase() error {
return m.publishContactCode()
err := m.publishContactCode()
if err != nil {
return err
}
return nil
}
func (m *Messenger) GetProfileShowcasePreferences() (*ProfileShowcasePreferences, error) {
func (m *Messenger) GetProfileShowcasePreferences() (*identity.ProfileShowcasePreferences, error) {
return m.persistence.GetProfileShowcasePreferences()
}
func (m *Messenger) GetProfileShowcaseForContact(contactID string) (*ProfileShowcase, error) {
return m.persistence.GetProfileShowcaseForContact(contactID)
func (m *Messenger) GetProfileShowcaseForContact(contactID string, validate bool) (*identity.ProfileShowcase, error) {
profileShowcase, err := m.persistence.GetProfileShowcaseForContact(contactID)
if err != nil {
return nil, err
}
if !validate {
return profileShowcase, nil
}
contactPubKey, err := common.HexToPubkey(contactID)
if err != nil {
return nil, err
}
profileShowcase.Communities, err = m.validateCommunitiesMembership(profileShowcase.Communities, contactPubKey)
if err != nil {
return nil, err
}
// TODO: validate collectibles & assets ownership, https://github.com/status-im/status-desktop/issues/14129
return profileShowcase, nil
}
func (m *Messenger) GetProfileShowcaseAccountsByAddress(address string) ([]*ProfileShowcaseAccount, error) {
func (m *Messenger) GetProfileShowcaseAccountsByAddress(address string) ([]*identity.ProfileShowcaseAccount, error) {
return m.persistence.GetProfileShowcaseAccountsByAddress(address)
}
func (m *Messenger) GetProfileShowcaseSocialLinksLimit() (int, error) {
return identity.MaxProfileShowcaseSocialLinksLimit, nil
}
func (m *Messenger) GetProfileShowcaseEntriesLimit() (int, error) {
return identity.MaxProfileShowcaseEntriesLimit, nil
}
func (m *Messenger) EncryptProfileShowcaseEntriesWithContactPubKeys(entries *protobuf.ProfileShowcaseEntries, contacts []*Contact) (*protobuf.ProfileShowcaseEntriesEncrypted, error) {
// Make AES key
AESKey := make([]byte, 32)
@ -324,27 +547,30 @@ func (m *Messenger) GetProfileShowcaseForSelfIdentity() (*protobuf.ProfileShowca
}
forEveryone := &protobuf.ProfileShowcaseEntries{
Communities: toProfileShowcaseCommunityProto(preferences.Communities, ProfileShowcaseVisibilityEveryone),
Accounts: toProfileShowcaseAccountProto(preferences.Accounts, ProfileShowcaseVisibilityEveryone),
Collectibles: toProfileShowcaseCollectibleProto(preferences.Collectibles, ProfileShowcaseVisibilityEveryone),
VerifiedTokens: toProfileShowcaseVerifiedTokensProto(preferences.VerifiedTokens, ProfileShowcaseVisibilityEveryone),
UnverifiedTokens: toProfileShowcaseUnverifiedTokensProto(preferences.UnverifiedTokens, ProfileShowcaseVisibilityEveryone),
Communities: m.toProfileShowcaseCommunityProto(preferences.Communities, identity.ProfileShowcaseVisibilityEveryone),
Accounts: m.toProfileShowcaseAccountProto(preferences.Accounts, identity.ProfileShowcaseVisibilityEveryone),
Collectibles: m.toProfileShowcaseCollectibleProto(preferences.Collectibles, identity.ProfileShowcaseVisibilityEveryone),
VerifiedTokens: m.toProfileShowcaseVerifiedTokensProto(preferences.VerifiedTokens, identity.ProfileShowcaseVisibilityEveryone),
UnverifiedTokens: m.toProfileShowcaseUnverifiedTokensProto(preferences.UnverifiedTokens, identity.ProfileShowcaseVisibilityEveryone),
SocialLinks: m.toProfileShowcaseSocialLinksProto(preferences.SocialLinks, identity.ProfileShowcaseVisibilityEveryone),
}
forContacts := &protobuf.ProfileShowcaseEntries{
Communities: toProfileShowcaseCommunityProto(preferences.Communities, ProfileShowcaseVisibilityContacts),
Accounts: toProfileShowcaseAccountProto(preferences.Accounts, ProfileShowcaseVisibilityContacts),
Collectibles: toProfileShowcaseCollectibleProto(preferences.Collectibles, ProfileShowcaseVisibilityContacts),
VerifiedTokens: toProfileShowcaseVerifiedTokensProto(preferences.VerifiedTokens, ProfileShowcaseVisibilityContacts),
UnverifiedTokens: toProfileShowcaseUnverifiedTokensProto(preferences.UnverifiedTokens, ProfileShowcaseVisibilityContacts),
Communities: m.toProfileShowcaseCommunityProto(preferences.Communities, identity.ProfileShowcaseVisibilityContacts),
Accounts: m.toProfileShowcaseAccountProto(preferences.Accounts, identity.ProfileShowcaseVisibilityContacts),
Collectibles: m.toProfileShowcaseCollectibleProto(preferences.Collectibles, identity.ProfileShowcaseVisibilityContacts),
VerifiedTokens: m.toProfileShowcaseVerifiedTokensProto(preferences.VerifiedTokens, identity.ProfileShowcaseVisibilityContacts),
UnverifiedTokens: m.toProfileShowcaseUnverifiedTokensProto(preferences.UnverifiedTokens, identity.ProfileShowcaseVisibilityContacts),
SocialLinks: m.toProfileShowcaseSocialLinksProto(preferences.SocialLinks, identity.ProfileShowcaseVisibilityContacts),
}
forIDVerifiedContacts := &protobuf.ProfileShowcaseEntries{
Communities: toProfileShowcaseCommunityProto(preferences.Communities, ProfileShowcaseVisibilityIDVerifiedContacts),
Accounts: toProfileShowcaseAccountProto(preferences.Accounts, ProfileShowcaseVisibilityIDVerifiedContacts),
Collectibles: toProfileShowcaseCollectibleProto(preferences.Collectibles, ProfileShowcaseVisibilityIDVerifiedContacts),
VerifiedTokens: toProfileShowcaseVerifiedTokensProto(preferences.VerifiedTokens, ProfileShowcaseVisibilityIDVerifiedContacts),
UnverifiedTokens: toProfileShowcaseUnverifiedTokensProto(preferences.UnverifiedTokens, ProfileShowcaseVisibilityIDVerifiedContacts),
Communities: m.toProfileShowcaseCommunityProto(preferences.Communities, identity.ProfileShowcaseVisibilityIDVerifiedContacts),
Accounts: m.toProfileShowcaseAccountProto(preferences.Accounts, identity.ProfileShowcaseVisibilityIDVerifiedContacts),
Collectibles: m.toProfileShowcaseCollectibleProto(preferences.Collectibles, identity.ProfileShowcaseVisibilityIDVerifiedContacts),
VerifiedTokens: m.toProfileShowcaseVerifiedTokensProto(preferences.VerifiedTokens, identity.ProfileShowcaseVisibilityIDVerifiedContacts),
UnverifiedTokens: m.toProfileShowcaseUnverifiedTokensProto(preferences.UnverifiedTokens, identity.ProfileShowcaseVisibilityIDVerifiedContacts),
SocialLinks: m.toProfileShowcaseSocialLinksProto(preferences.SocialLinks, identity.ProfileShowcaseVisibilityIDVerifiedContacts),
}
mutualContacts := []*Contact{}
@ -378,32 +604,35 @@ func (m *Messenger) GetProfileShowcaseForSelfIdentity() (*protobuf.ProfileShowca
}
func (m *Messenger) BuildProfileShowcaseFromIdentity(state *ReceivedMessageState, message *protobuf.ProfileShowcase) error {
communities := []*ProfileShowcaseCommunity{}
accounts := []*ProfileShowcaseAccount{}
collectibles := []*ProfileShowcaseCollectible{}
verifiedTokens := []*ProfileShowcaseVerifiedToken{}
unverifiedTokens := []*ProfileShowcaseUnverifiedToken{}
communities = append(communities, fromProfileShowcaseCommunityProto(message.ForEveryone.Communities)...)
accounts = append(accounts, fromProfileShowcaseAccountProto(message.ForEveryone.Accounts)...)
collectibles = append(collectibles, fromProfileShowcaseCollectibleProto(message.ForEveryone.Collectibles)...)
verifiedTokens = append(verifiedTokens, fromProfileShowcaseVerifiedTokenProto(message.ForEveryone.VerifiedTokens)...)
unverifiedTokens = append(unverifiedTokens, fromProfileShowcaseUnverifiedTokenProto(message.ForEveryone.UnverifiedTokens)...)
senderPubKey := state.CurrentMessageState.PublicKey
contactID := state.CurrentMessageState.Contact.ID
communities := []*identity.ProfileShowcaseCommunity{}
accounts := []*identity.ProfileShowcaseAccount{}
collectibles := []*identity.ProfileShowcaseCollectible{}
verifiedTokens := []*identity.ProfileShowcaseVerifiedToken{}
unverifiedTokens := []*identity.ProfileShowcaseUnverifiedToken{}
socialLinks := []*identity.ProfileShowcaseSocialLink{}
communities = append(communities, m.fromProfileShowcaseCommunityProto(senderPubKey, message.ForEveryone.Communities)...)
accounts = append(accounts, m.fromProfileShowcaseAccountProto(message.ForEveryone.Accounts)...)
collectibles = append(collectibles, m.fromProfileShowcaseCollectibleProto(message.ForEveryone.Collectibles)...)
verifiedTokens = append(verifiedTokens, m.fromProfileShowcaseVerifiedTokenProto(message.ForEveryone.VerifiedTokens)...)
unverifiedTokens = append(unverifiedTokens, m.fromProfileShowcaseUnverifiedTokenProto(message.ForEveryone.UnverifiedTokens)...)
socialLinks = append(socialLinks, m.fromProfileShowcaseSocialLinkProto(message.ForEveryone.SocialLinks)...)
forContacts, err := m.DecryptProfileShowcaseEntriesWithPubKey(senderPubKey, message.ForContacts)
if err != nil {
return err
}
if forContacts != nil {
communities = append(communities, fromProfileShowcaseCommunityProto(forContacts.Communities)...)
accounts = append(accounts, fromProfileShowcaseAccountProto(forContacts.Accounts)...)
collectibles = append(collectibles, fromProfileShowcaseCollectibleProto(forContacts.Collectibles)...)
verifiedTokens = append(verifiedTokens, fromProfileShowcaseVerifiedTokenProto(forContacts.VerifiedTokens)...)
unverifiedTokens = append(unverifiedTokens, fromProfileShowcaseUnverifiedTokenProto(forContacts.UnverifiedTokens)...)
communities = append(communities, m.fromProfileShowcaseCommunityProto(senderPubKey, forContacts.Communities)...)
accounts = append(accounts, m.fromProfileShowcaseAccountProto(forContacts.Accounts)...)
collectibles = append(collectibles, m.fromProfileShowcaseCollectibleProto(forContacts.Collectibles)...)
verifiedTokens = append(verifiedTokens, m.fromProfileShowcaseVerifiedTokenProto(forContacts.VerifiedTokens)...)
unverifiedTokens = append(unverifiedTokens, m.fromProfileShowcaseUnverifiedTokenProto(forContacts.UnverifiedTokens)...)
socialLinks = append(socialLinks, m.fromProfileShowcaseSocialLinkProto(forContacts.SocialLinks)...)
}
forIDVerifiedContacts, err := m.DecryptProfileShowcaseEntriesWithPubKey(senderPubKey, message.ForIdVerifiedContacts)
@ -412,23 +641,29 @@ func (m *Messenger) BuildProfileShowcaseFromIdentity(state *ReceivedMessageState
}
if forIDVerifiedContacts != nil {
communities = append(communities, fromProfileShowcaseCommunityProto(forIDVerifiedContacts.Communities)...)
accounts = append(accounts, fromProfileShowcaseAccountProto(forIDVerifiedContacts.Accounts)...)
collectibles = append(collectibles, fromProfileShowcaseCollectibleProto(forIDVerifiedContacts.Collectibles)...)
verifiedTokens = append(verifiedTokens, fromProfileShowcaseVerifiedTokenProto(forIDVerifiedContacts.VerifiedTokens)...)
unverifiedTokens = append(unverifiedTokens, fromProfileShowcaseUnverifiedTokenProto(forIDVerifiedContacts.UnverifiedTokens)...)
communities = append(communities, m.fromProfileShowcaseCommunityProto(senderPubKey, forIDVerifiedContacts.Communities)...)
accounts = append(accounts, m.fromProfileShowcaseAccountProto(forIDVerifiedContacts.Accounts)...)
collectibles = append(collectibles, m.fromProfileShowcaseCollectibleProto(forIDVerifiedContacts.Collectibles)...)
verifiedTokens = append(verifiedTokens, m.fromProfileShowcaseVerifiedTokenProto(forIDVerifiedContacts.VerifiedTokens)...)
unverifiedTokens = append(unverifiedTokens, m.fromProfileShowcaseUnverifiedTokenProto(forIDVerifiedContacts.UnverifiedTokens)...)
socialLinks = append(socialLinks, m.fromProfileShowcaseSocialLinkProto(forIDVerifiedContacts.SocialLinks)...)
}
// TODO: validate community membership here (https://github.com/status-im/status-desktop/issues/13081)
// TODO: validate collectible ownership here (https://github.com/status-im/status-desktop/issues/13073)
sortProfileEntyByOrder(communities, func(i int) int { return communities[i].Order })
sortProfileEntyByOrder(accounts, func(i int) int { return accounts[i].Order })
sortProfileEntyByOrder(collectibles, func(i int) int { return collectibles[i].Order })
sortProfileEntyByOrder(verifiedTokens, func(i int) int { return verifiedTokens[i].Order })
sortProfileEntyByOrder(unverifiedTokens, func(i int) int { return unverifiedTokens[i].Order })
sortProfileEntyByOrder(socialLinks, func(i int) int { return socialLinks[i].Order })
newShowcase := &ProfileShowcase{
newShowcase := &identity.ProfileShowcase{
ContactID: contactID,
Communities: communities,
Accounts: accounts,
Collectibles: collectibles,
VerifiedTokens: verifiedTokens,
UnverifiedTokens: unverifiedTokens,
SocialLinks: socialLinks,
}
oldShowcase, err := m.persistence.GetProfileShowcaseForContact(contactID)
@ -450,7 +685,6 @@ func (m *Messenger) BuildProfileShowcaseFromIdentity(state *ReceivedMessageState
return err
}
state.Response.AddProfileShowcase(newShowcase)
return nil
}
@ -465,15 +699,6 @@ func (m *Messenger) UpdateProfileShowcaseWalletAccount(account *accounts.Account
return nil
}
profileAccount.Name = account.Name
profileAccount.ColorID = string(account.ColorID)
profileAccount.Emoji = account.Emoji
err = m.persistence.SaveProfileShowcaseAccountPreference(profileAccount)
if err != nil {
return err
}
return m.DispatchProfileShowcase()
}
@ -500,3 +725,35 @@ func (m *Messenger) DeleteProfileShowcaseCommunity(community *communities.Commun
}
return nil
}
func (m *Messenger) saveProfileShowcasePreferencesProto(p *protobuf.SyncProfileShowcasePreferences, shouldSync bool) (*identity.ProfileShowcasePreferences, error) {
if p == nil {
return nil, nil
}
preferences := FromProfileShowcasePreferencesProto(p)
return preferences, m.setProfileShowcasePreferences(preferences, shouldSync)
}
func (m *Messenger) syncProfileShowcasePreferences(ctx context.Context, rawMessageHandler RawMessageHandler) error {
preferences, err := m.GetProfileShowcasePreferences()
if err != nil {
return err
}
syncMessage := ToProfileShowcasePreferencesProto(preferences)
encodedMessage, err := proto.Marshal(syncMessage)
if err != nil {
return err
}
_, chat := m.getLastClockWithRelatedChat()
rawMessage := common.RawMessage{
LocalChatID: chat.ID,
Payload: encodedMessage,
MessageType: protobuf.ApplicationMetadataMessage_SYNC_PROFILE_SHOWCASE_PREFERENCES,
ResendAutomatically: true,
}
_, err = rawMessageHandler(ctx, rawMessage)
return err
}

View File

@ -0,0 +1,231 @@
package protocol
import (
"github.com/status-im/status-go/protocol/identity"
"github.com/status-im/status-go/protocol/protobuf"
)
func FromProfileShowcaseCommunityPreferenceProto(p *protobuf.ProfileShowcaseCommunityPreference) *identity.ProfileShowcaseCommunityPreference {
return &identity.ProfileShowcaseCommunityPreference{
CommunityID: p.GetCommunityId(),
ShowcaseVisibility: identity.ProfileShowcaseVisibility(p.ShowcaseVisibility),
Order: int(p.Order),
}
}
func FromProfileShowcaseCommunitiesPreferencesProto(preferences []*protobuf.ProfileShowcaseCommunityPreference) []*identity.ProfileShowcaseCommunityPreference {
out := make([]*identity.ProfileShowcaseCommunityPreference, 0, len(preferences))
for _, p := range preferences {
out = append(out, FromProfileShowcaseCommunityPreferenceProto(p))
}
return out
}
func ToProfileShowcaseCommunityPreferenceProto(p *identity.ProfileShowcaseCommunityPreference) *protobuf.ProfileShowcaseCommunityPreference {
return &protobuf.ProfileShowcaseCommunityPreference{
CommunityId: p.CommunityID,
ShowcaseVisibility: protobuf.ProfileShowcaseVisibility(p.ShowcaseVisibility),
Order: uint32(p.Order),
}
}
func ToProfileShowcaseCommunitiesPreferencesProto(preferences []*identity.ProfileShowcaseCommunityPreference) []*protobuf.ProfileShowcaseCommunityPreference {
out := make([]*protobuf.ProfileShowcaseCommunityPreference, 0, len(preferences))
for _, p := range preferences {
out = append(out, ToProfileShowcaseCommunityPreferenceProto(p))
}
return out
}
func FromProfileShowcaseAccountPreferenceProto(p *protobuf.ProfileShowcaseAccountPreference) *identity.ProfileShowcaseAccountPreference {
return &identity.ProfileShowcaseAccountPreference{
Address: p.GetAddress(),
ShowcaseVisibility: identity.ProfileShowcaseVisibility(p.ShowcaseVisibility),
Order: int(p.Order),
}
}
func FromProfileShowcaseAccountsPreferencesProto(preferences []*protobuf.ProfileShowcaseAccountPreference) []*identity.ProfileShowcaseAccountPreference {
out := make([]*identity.ProfileShowcaseAccountPreference, 0, len(preferences))
for _, p := range preferences {
out = append(out, FromProfileShowcaseAccountPreferenceProto(p))
}
return out
}
func ToProfileShowcaseAccountPreferenceProto(p *identity.ProfileShowcaseAccountPreference) *protobuf.ProfileShowcaseAccountPreference {
return &protobuf.ProfileShowcaseAccountPreference{
Address: p.Address,
ShowcaseVisibility: protobuf.ProfileShowcaseVisibility(p.ShowcaseVisibility),
Order: uint32(p.Order),
}
}
func ToProfileShowcaseAccountsPreferenceProto(preferences []*identity.ProfileShowcaseAccountPreference) []*protobuf.ProfileShowcaseAccountPreference {
out := make([]*protobuf.ProfileShowcaseAccountPreference, 0, len(preferences))
for _, p := range preferences {
out = append(out, ToProfileShowcaseAccountPreferenceProto(p))
}
return out
}
func FromProfileShowcaseCollectiblePreferenceProto(p *protobuf.ProfileShowcaseCollectiblePreference) *identity.ProfileShowcaseCollectiblePreference {
return &identity.ProfileShowcaseCollectiblePreference{
ContractAddress: p.GetContractAddress(),
ChainID: p.GetChainId(),
TokenID: p.GetTokenId(),
ShowcaseVisibility: identity.ProfileShowcaseVisibility(p.ShowcaseVisibility),
Order: int(p.Order),
}
}
func FromProfileShowcaseCollectiblesPreferencesProto(preferences []*protobuf.ProfileShowcaseCollectiblePreference) []*identity.ProfileShowcaseCollectiblePreference {
out := make([]*identity.ProfileShowcaseCollectiblePreference, 0, len(preferences))
for _, p := range preferences {
out = append(out, FromProfileShowcaseCollectiblePreferenceProto(p))
}
return out
}
func ToProfileShowcaseCollectiblePreferenceProto(p *identity.ProfileShowcaseCollectiblePreference) *protobuf.ProfileShowcaseCollectiblePreference {
return &protobuf.ProfileShowcaseCollectiblePreference{
ContractAddress: p.ContractAddress,
ChainId: p.ChainID,
TokenId: p.TokenID,
ShowcaseVisibility: protobuf.ProfileShowcaseVisibility(p.ShowcaseVisibility),
Order: uint32(p.Order),
}
}
func ToProfileShowcaseCollectiblesPreferenceProto(preferences []*identity.ProfileShowcaseCollectiblePreference) []*protobuf.ProfileShowcaseCollectiblePreference {
out := make([]*protobuf.ProfileShowcaseCollectiblePreference, 0, len(preferences))
for _, p := range preferences {
out = append(out, ToProfileShowcaseCollectiblePreferenceProto(p))
}
return out
}
func FromProfileShowcaseVerifiedTokenPreferenceProto(p *protobuf.ProfileShowcaseVerifiedTokenPreference) *identity.ProfileShowcaseVerifiedTokenPreference {
return &identity.ProfileShowcaseVerifiedTokenPreference{
Symbol: p.GetSymbol(),
ShowcaseVisibility: identity.ProfileShowcaseVisibility(p.ShowcaseVisibility),
Order: int(p.Order),
}
}
func FromProfileShowcaseVerifiedTokensPreferencesProto(preferences []*protobuf.ProfileShowcaseVerifiedTokenPreference) []*identity.ProfileShowcaseVerifiedTokenPreference {
out := make([]*identity.ProfileShowcaseVerifiedTokenPreference, 0, len(preferences))
for _, p := range preferences {
out = append(out, FromProfileShowcaseVerifiedTokenPreferenceProto(p))
}
return out
}
func ToProfileShowcaseVerifiedTokenPreferenceProto(p *identity.ProfileShowcaseVerifiedTokenPreference) *protobuf.ProfileShowcaseVerifiedTokenPreference {
return &protobuf.ProfileShowcaseVerifiedTokenPreference{
Symbol: p.Symbol,
ShowcaseVisibility: protobuf.ProfileShowcaseVisibility(p.ShowcaseVisibility),
Order: uint32(p.Order),
}
}
func ToProfileShowcaseVerifiedTokensPreferenceProto(preferences []*identity.ProfileShowcaseVerifiedTokenPreference) []*protobuf.ProfileShowcaseVerifiedTokenPreference {
out := make([]*protobuf.ProfileShowcaseVerifiedTokenPreference, 0, len(preferences))
for _, p := range preferences {
out = append(out, ToProfileShowcaseVerifiedTokenPreferenceProto(p))
}
return out
}
func FromProfileShowcaseUnverifiedTokenPreferenceProto(p *protobuf.ProfileShowcaseUnverifiedTokenPreference) *identity.ProfileShowcaseUnverifiedTokenPreference {
return &identity.ProfileShowcaseUnverifiedTokenPreference{
ContractAddress: p.GetContractAddress(),
ChainID: p.GetChainId(),
ShowcaseVisibility: identity.ProfileShowcaseVisibility(p.ShowcaseVisibility),
Order: int(p.Order),
}
}
func FromProfileShowcaseUnverifiedTokensPreferencesProto(preferences []*protobuf.ProfileShowcaseUnverifiedTokenPreference) []*identity.ProfileShowcaseUnverifiedTokenPreference {
out := make([]*identity.ProfileShowcaseUnverifiedTokenPreference, 0, len(preferences))
for _, p := range preferences {
out = append(out, FromProfileShowcaseUnverifiedTokenPreferenceProto(p))
}
return out
}
func ToProfileShowcaseUnverifiedTokenPreferenceProto(p *identity.ProfileShowcaseUnverifiedTokenPreference) *protobuf.ProfileShowcaseUnverifiedTokenPreference {
return &protobuf.ProfileShowcaseUnverifiedTokenPreference{
ContractAddress: p.ContractAddress,
ChainId: p.ChainID,
ShowcaseVisibility: protobuf.ProfileShowcaseVisibility(p.ShowcaseVisibility),
Order: uint32(p.Order),
}
}
func ToProfileShowcaseUnverifiedTokensPreferenceProto(preferences []*identity.ProfileShowcaseUnverifiedTokenPreference) []*protobuf.ProfileShowcaseUnverifiedTokenPreference {
out := make([]*protobuf.ProfileShowcaseUnverifiedTokenPreference, 0, len(preferences))
for _, p := range preferences {
out = append(out, ToProfileShowcaseUnverifiedTokenPreferenceProto(p))
}
return out
}
func FromProfileShowcaseSocialLinkPreferenceProto(p *protobuf.ProfileShowcaseSocialLinkPreference) *identity.ProfileShowcaseSocialLinkPreference {
return &identity.ProfileShowcaseSocialLinkPreference{
Text: p.GetText(),
URL: p.GetUrl(),
ShowcaseVisibility: identity.ProfileShowcaseVisibility(p.ShowcaseVisibility),
Order: int(p.Order),
}
}
func FromProfileShowcaseSocialLinksPreferencesProto(preferences []*protobuf.ProfileShowcaseSocialLinkPreference) []*identity.ProfileShowcaseSocialLinkPreference {
out := make([]*identity.ProfileShowcaseSocialLinkPreference, 0, len(preferences))
for _, p := range preferences {
out = append(out, FromProfileShowcaseSocialLinkPreferenceProto(p))
}
return out
}
func ToProfileShowcaseSocialLinkPreferenceProto(p *identity.ProfileShowcaseSocialLinkPreference) *protobuf.ProfileShowcaseSocialLinkPreference {
return &protobuf.ProfileShowcaseSocialLinkPreference{
Text: p.Text,
Url: p.URL,
ShowcaseVisibility: protobuf.ProfileShowcaseVisibility(p.ShowcaseVisibility),
Order: uint32(p.Order),
}
}
func ToProfileShowcaseSocialLinksPreferenceProto(preferences []*identity.ProfileShowcaseSocialLinkPreference) []*protobuf.ProfileShowcaseSocialLinkPreference {
out := make([]*protobuf.ProfileShowcaseSocialLinkPreference, 0, len(preferences))
for _, p := range preferences {
out = append(out, ToProfileShowcaseSocialLinkPreferenceProto(p))
}
return out
}
func FromProfileShowcasePreferencesProto(p *protobuf.SyncProfileShowcasePreferences) *identity.ProfileShowcasePreferences {
return &identity.ProfileShowcasePreferences{
Clock: p.GetClock(),
Communities: FromProfileShowcaseCommunitiesPreferencesProto(p.Communities),
Accounts: FromProfileShowcaseAccountsPreferencesProto(p.Accounts),
Collectibles: FromProfileShowcaseCollectiblesPreferencesProto(p.Collectibles),
VerifiedTokens: FromProfileShowcaseVerifiedTokensPreferencesProto(p.VerifiedTokens),
UnverifiedTokens: FromProfileShowcaseUnverifiedTokensPreferencesProto(p.UnverifiedTokens),
SocialLinks: FromProfileShowcaseSocialLinksPreferencesProto(p.SocialLinks),
}
}
func ToProfileShowcasePreferencesProto(p *identity.ProfileShowcasePreferences) *protobuf.SyncProfileShowcasePreferences {
return &protobuf.SyncProfileShowcasePreferences{
Clock: p.Clock,
Communities: ToProfileShowcaseCommunitiesPreferencesProto(p.Communities),
Accounts: ToProfileShowcaseAccountsPreferenceProto(p.Accounts),
Collectibles: ToProfileShowcaseCollectiblesPreferenceProto(p.Collectibles),
VerifiedTokens: ToProfileShowcaseVerifiedTokensPreferenceProto(p.VerifiedTokens),
UnverifiedTokens: ToProfileShowcaseUnverifiedTokensPreferenceProto(p.UnverifiedTokens),
SocialLinks: ToProfileShowcaseSocialLinksPreferenceProto(p.SocialLinks),
}
}

View File

@ -21,6 +21,7 @@ import (
"github.com/status-im/status-go/protocol/encryption/multidevice"
"github.com/status-im/status-go/protocol/identity"
"github.com/status-im/status-go/protocol/protobuf"
"github.com/status-im/status-go/protocol/storenodes"
"github.com/status-im/status-go/protocol/verification"
localnotifications "github.com/status-im/status-go/services/local-notifications"
"github.com/status-im/status-go/services/mailservers"
@ -51,6 +52,7 @@ type MessengerResponse struct {
CommunityChanges []*communities.CommunityChanges
AnonymousMetrics []*appmetrics.AppMetric
Mailservers []mailservers.Mailserver
CommunityStorenodes []storenodes.Storenode
Bookmarks []*browsers.Bookmark
Settings []*settings.SyncSettingField
IdentityImages []images.IdentityImage
@ -67,31 +69,32 @@ type MessengerResponse struct {
// notifications a list of notifications derived from messenger events
// that are useful to notify the user about
notifications map[string]*localnotifications.Notification
requestsToJoinCommunity map[string]*communities.RequestToJoin
chats map[string]*Chat
removedChats map[string]bool
removedMessages map[string]*RemovedMessage
communities map[string]*communities.Community
communitiesSettings map[string]*communities.CommunitySettings
activityCenterNotifications map[string]*ActivityCenterNotification
activityCenterState *ActivityCenterState
messages map[string]*common.Message
pinMessages map[string]*common.PinMessage
discordMessages map[string]*protobuf.DiscordMessage
discordMessageAttachments map[string]*protobuf.DiscordMessageAttachment
discordMessageAuthors map[string]*protobuf.DiscordMessageAuthor
currentStatus *UserStatus
statusUpdates map[string]UserStatus
clearedHistories map[string]*ClearedHistory
verificationRequests map[string]*verification.Request
trustStatus map[string]verification.TrustStatus
emojiReactions map[string]*EmojiReaction
savedAddresses map[string]*wallet.SavedAddress
SocialLinksInfo *identity.SocialLinksInfo
ensUsernameDetails []*ensservice.UsernameDetail
updatedProfileShowcases map[string]*ProfileShowcase
seenAndUnseenMessages map[string]*SeenUnseenMessages
notifications map[string]*localnotifications.Notification
requestsToJoinCommunity map[string]*communities.RequestToJoin
chats map[string]*Chat
removedChats map[string]bool
removedMessages map[string]*RemovedMessage
deletedMessages map[string]string
communities map[string]*communities.Community
communitiesSettings map[string]*communities.CommunitySettings
activityCenterNotifications map[string]*ActivityCenterNotification
activityCenterState *ActivityCenterState
messages map[string]*common.Message
pinMessages map[string]*common.PinMessage
discordMessages map[string]*protobuf.DiscordMessage
discordMessageAttachments map[string]*protobuf.DiscordMessageAttachment
discordMessageAuthors map[string]*protobuf.DiscordMessageAuthor
currentStatus *UserStatus
statusUpdates map[string]UserStatus
clearedHistories map[string]*ClearedHistory
verificationRequests map[string]*verification.Request
trustStatus map[string]verification.TrustStatus
emojiReactions map[string]*EmojiReaction
savedAddresses map[string]*wallet.SavedAddress
SocialLinksInfo *identity.SocialLinksInfo
ensUsernameDetails []*ensservice.UsernameDetail
updatedProfileShowcaseContactIDs map[string]bool
seenAndUnseenMessages map[string]*SeenUnseenMessages
}
func (r *MessengerResponse) MarshalJSON() ([]byte, error) {
@ -99,6 +102,7 @@ func (r *MessengerResponse) MarshalJSON() ([]byte, error) {
Chats []*Chat `json:"chats,omitempty"`
RemovedChats []string `json:"removedChats,omitempty"`
RemovedMessages []*RemovedMessage `json:"removedMessages,omitempty"`
DeletedMessages map[string][]string `json:"deletedMessages,omitempty"`
Messages []*common.Message `json:"messages,omitempty"`
Contacts []*Contact `json:"contacts,omitempty"`
Installations []*multidevice.Installation `json:"installations,omitempty"`
@ -108,37 +112,38 @@ func (r *MessengerResponse) MarshalJSON() ([]byte, error) {
CommunityChanges []*communities.CommunityChanges `json:"communityChanges,omitempty"`
RequestsToJoinCommunity []*communities.RequestToJoin `json:"requestsToJoinCommunity,omitempty"`
Mailservers []mailservers.Mailserver `json:"mailservers,omitempty"`
CommunityStorenodes []storenodes.Storenode `json:"communityStorenodes,omitempty"`
Bookmarks []*browsers.Bookmark `json:"bookmarks,omitempty"`
ClearedHistories []*ClearedHistory `json:"clearedHistories,omitempty"`
VerificationRequests []*verification.Request `json:"verificationRequests,omitempty"`
TrustStatus map[string]verification.TrustStatus `json:"trustStatus,omitempty"`
// Notifications a list of notifications derived from messenger events
// that are useful to notify the user about
Notifications []*localnotifications.Notification `json:"notifications"`
Communities []*communities.Community `json:"communities,omitempty"`
CommunitiesSettings []*communities.CommunitySettings `json:"communitiesSettings,omitempty"`
ActivityCenterNotifications []*ActivityCenterNotification `json:"activityCenterNotifications,omitempty"`
ActivityCenterState *ActivityCenterState `json:"activityCenterState,omitempty"`
CurrentStatus *UserStatus `json:"currentStatus,omitempty"`
StatusUpdates []UserStatus `json:"statusUpdates,omitempty"`
Settings []*settings.SyncSettingField `json:"settings,omitempty"`
IdentityImages []images.IdentityImage `json:"identityImages,omitempty"`
CustomizationColor string `json:"customizationColor,omitempty"`
WatchOnlyAccounts []*accounts.Account `json:"watchOnlyAccounts,omitempty"`
Keypairs []*accounts.Keypair `json:"keypairs,omitempty"`
AccountsPositions []*accounts.Account `json:"accountsPositions,omitempty"`
TokenPreferences []walletsettings.TokenPreferences `json:"tokenPreferences,omitempty"`
CollectiblePreferences []walletsettings.CollectiblePreferences `json:"collectiblePreferences,omitempty"`
DiscordCategories []*discord.Category `json:"discordCategories,omitempty"`
DiscordChannels []*discord.Channel `json:"discordChannels,omitempty"`
DiscordOldestMessageTimestamp int `json:"discordOldestMessageTimestamp"`
DiscordMessages []*protobuf.DiscordMessage `json:"discordMessages,omitempty"`
DiscordMessageAttachments []*protobuf.DiscordMessageAttachment `json:"discordMessageAtachments,omitempty"`
SavedAddresses []*wallet.SavedAddress `json:"savedAddresses,omitempty"`
SocialLinksInfo *identity.SocialLinksInfo `json:"socialLinksInfo,omitempty"`
EnsUsernameDetails []*ensservice.UsernameDetail `json:"ensUsernameDetails,omitempty"`
UpdatedProfileShowcases []*ProfileShowcase `json:"updatedProfileShowcases,omitempty"`
SeenAndUnseenMessages []*SeenUnseenMessages `json:"seenAndUnseenMessages,omitempty"`
Notifications []*localnotifications.Notification `json:"notifications"`
Communities []*communities.Community `json:"communities,omitempty"`
CommunitiesSettings []*communities.CommunitySettings `json:"communitiesSettings,omitempty"`
ActivityCenterNotifications []*ActivityCenterNotification `json:"activityCenterNotifications,omitempty"`
ActivityCenterState *ActivityCenterState `json:"activityCenterState,omitempty"`
CurrentStatus *UserStatus `json:"currentStatus,omitempty"`
StatusUpdates []UserStatus `json:"statusUpdates,omitempty"`
Settings []*settings.SyncSettingField `json:"settings,omitempty"`
IdentityImages []images.IdentityImage `json:"identityImages,omitempty"`
CustomizationColor string `json:"customizationColor,omitempty"`
WatchOnlyAccounts []*accounts.Account `json:"watchOnlyAccounts,omitempty"`
Keypairs []*accounts.Keypair `json:"keypairs,omitempty"`
AccountsPositions []*accounts.Account `json:"accountsPositions,omitempty"`
TokenPreferences []walletsettings.TokenPreferences `json:"tokenPreferences,omitempty"`
CollectiblePreferences []walletsettings.CollectiblePreferences `json:"collectiblePreferences,omitempty"`
DiscordCategories []*discord.Category `json:"discordCategories,omitempty"`
DiscordChannels []*discord.Channel `json:"discordChannels,omitempty"`
DiscordOldestMessageTimestamp int `json:"discordOldestMessageTimestamp"`
DiscordMessages []*protobuf.DiscordMessage `json:"discordMessages,omitempty"`
DiscordMessageAttachments []*protobuf.DiscordMessageAttachment `json:"discordMessageAtachments,omitempty"`
SavedAddresses []*wallet.SavedAddress `json:"savedAddresses,omitempty"`
SocialLinksInfo *identity.SocialLinksInfo `json:"socialLinksInfo,omitempty"`
EnsUsernameDetails []*ensservice.UsernameDetail `json:"ensUsernameDetails,omitempty"`
UpdatedProfileShowcaseContactIDs []string `json:"updatedProfileShowcaseContactIDs,omitempty"`
SeenAndUnseenMessages []*SeenUnseenMessages `json:"seenAndUnseenMessages,omitempty"`
}{
Contacts: r.Contacts,
Installations: r.Installations,
@ -146,6 +151,7 @@ func (r *MessengerResponse) MarshalJSON() ([]byte, error) {
CommunityChanges: r.CommunityChanges,
RequestsToJoinCommunity: r.RequestsToJoinCommunity(),
Mailservers: r.Mailservers,
CommunityStorenodes: r.CommunityStorenodes,
Bookmarks: r.Bookmarks,
CurrentStatus: r.currentStatus,
Settings: r.Settings,
@ -157,28 +163,29 @@ func (r *MessengerResponse) MarshalJSON() ([]byte, error) {
TokenPreferences: r.TokenPreferences,
CollectiblePreferences: r.CollectiblePreferences,
Messages: r.Messages(),
VerificationRequests: r.VerificationRequests(),
SavedAddresses: r.SavedAddresses(),
Notifications: r.Notifications(),
Chats: r.Chats(),
Communities: r.Communities(),
CommunitiesSettings: r.CommunitiesSettings(),
RemovedChats: r.RemovedChats(),
RemovedMessages: r.RemovedMessages(),
ClearedHistories: r.ClearedHistories(),
ActivityCenterNotifications: r.ActivityCenterNotifications(),
ActivityCenterState: r.ActivityCenterState(),
PinMessages: r.PinMessages(),
EmojiReactions: r.EmojiReactions(),
StatusUpdates: r.StatusUpdates(),
DiscordCategories: r.DiscordCategories,
DiscordChannels: r.DiscordChannels,
DiscordOldestMessageTimestamp: r.DiscordOldestMessageTimestamp,
SocialLinksInfo: r.SocialLinksInfo,
EnsUsernameDetails: r.EnsUsernameDetails(),
UpdatedProfileShowcases: r.GetUpdatedProfileShowcases(),
SeenAndUnseenMessages: r.GetSeenAndUnseenMessages(),
Messages: r.Messages(),
VerificationRequests: r.VerificationRequests(),
SavedAddresses: r.SavedAddresses(),
Notifications: r.Notifications(),
Chats: r.Chats(),
Communities: r.Communities(),
CommunitiesSettings: r.CommunitiesSettings(),
RemovedChats: r.RemovedChats(),
RemovedMessages: r.RemovedMessages(),
DeletedMessages: r.DeletedMessagesInChats(),
ClearedHistories: r.ClearedHistories(),
ActivityCenterNotifications: r.ActivityCenterNotifications(),
ActivityCenterState: r.ActivityCenterState(),
PinMessages: r.PinMessages(),
EmojiReactions: r.EmojiReactions(),
StatusUpdates: r.StatusUpdates(),
DiscordCategories: r.DiscordCategories,
DiscordChannels: r.DiscordChannels,
DiscordOldestMessageTimestamp: r.DiscordOldestMessageTimestamp,
SocialLinksInfo: r.SocialLinksInfo,
EnsUsernameDetails: r.EnsUsernameDetails(),
UpdatedProfileShowcaseContactIDs: r.GetUpdatedProfileShowcaseContactIDs(),
SeenAndUnseenMessages: r.GetSeenAndUnseenMessages(),
}
responseItem.TrustStatus = r.TrustStatus()
@ -209,6 +216,18 @@ func (r *MessengerResponse) RemovedMessages() []*RemovedMessage {
return messages
}
func (r *MessengerResponse) DeletedMessages() map[string]string {
return r.deletedMessages
}
func (r *MessengerResponse) DeletedMessagesInChats() map[string][]string {
deletedMessagesInChats := make(map[string][]string)
for messageID, chatID := range r.deletedMessages {
deletedMessagesInChats[chatID] = append(deletedMessagesInChats[chatID], messageID)
}
return deletedMessagesInChats
}
func (r *MessengerResponse) ClearedHistories() []*ClearedHistory {
var clearedHistories []*ClearedHistory
for chatID := range r.clearedHistories {
@ -293,7 +312,9 @@ func (r *MessengerResponse) IsEmpty() bool {
len(r.CommunityChanges)+
len(r.removedChats)+
len(r.removedMessages)+
len(r.deletedMessages)+
len(r.Mailservers)+
len(r.CommunityStorenodes)+
len(r.IdentityImages)+
len(r.WatchOnlyAccounts)+
len(r.Keypairs)+
@ -307,7 +328,7 @@ func (r *MessengerResponse) IsEmpty() bool {
len(r.verificationRequests)+
len(r.requestsToJoinCommunity)+
len(r.savedAddresses)+
len(r.updatedProfileShowcases)+
len(r.updatedProfileShowcaseContactIDs)+
len(r.seenAndUnseenMessages)+
len(r.ensUsernameDetails) == 0 &&
r.currentStatus == nil &&
@ -330,6 +351,7 @@ func (r *MessengerResponse) Merge(response *MessengerResponse) error {
r.AddChats(response.Chats())
r.AddRemovedChats(response.RemovedChats())
r.AddRemovedMessages(response.RemovedMessages())
r.MergeDeletedMessages(response.DeletedMessages())
r.AddNotifications(response.Notifications())
r.AddMessages(response.Messages())
r.AddContacts(response.Contacts)
@ -346,7 +368,7 @@ func (r *MessengerResponse) Merge(response *MessengerResponse) error {
r.AddEnsUsernameDetails(response.EnsUsernameDetails())
r.AddRequestsToJoinCommunity(response.RequestsToJoinCommunity())
r.AddBookmarks(response.GetBookmarks())
r.AddProfileShowcases(response.GetUpdatedProfileShowcases())
r.AddSeveralUpdatedProfileShowcaseContactIDs(response.GetUpdatedProfileShowcaseContactIDs())
r.AddSeveralSeenAndUnseenMessages(response.GetSeenAndUnseenMessages())
r.CommunityChanges = append(r.CommunityChanges, response.CommunityChanges...)
r.BackupHandled = response.BackupHandled
@ -578,6 +600,26 @@ func (r *MessengerResponse) AddRemovedMessage(rm *RemovedMessage) {
}
}
func (r *MessengerResponse) AddDeletedMessages(messagesToAdd []*protobuf.DeleteCommunityMemberMessage) {
if r.deletedMessages == nil {
r.deletedMessages = make(map[string]string)
}
for _, message := range messagesToAdd {
r.deletedMessages[message.Id] = message.ChatId
}
}
func (r *MessengerResponse) MergeDeletedMessages(messagesToAdd map[string]string) {
if r.deletedMessages == nil {
r.deletedMessages = make(map[string]string)
}
for messageID, chatID := range messagesToAdd {
r.deletedMessages[messageID] = chatID
}
}
func (r *MessengerResponse) AddClearedHistory(ch *ClearedHistory) {
if r.clearedHistories == nil {
r.clearedHistories = make(map[string]*ClearedHistory)
@ -682,6 +724,13 @@ func (r *MessengerResponse) DiscordMessageAttachments() []*protobuf.DiscordMessa
return attachments
}
// Messages extracts the messages from the response and returns them as a slice.
// Since 'r.messages' is a map, the order of messages in the resulting slice is not
// guaranteed and can vary with each call to this method. This is inherent to Go's map
// iteration behavior, which does not define a sequence for the order of map elements.
// Consumers should not depend on the ordering of messages in the slice for any logic
// that requires consistent ordering, as map iteration order can change when keys are
// added or deleted. Consider sorting the slice after retrieval if a specific order is needed.
func (r *MessengerResponse) Messages() []*common.Message {
var ms []*common.Message
for _, m := range r.messages {
@ -821,26 +870,30 @@ func (r *MessengerResponse) HasDiscordChannel(id string) bool {
return false
}
func (r *MessengerResponse) AddProfileShowcases(showcases []*ProfileShowcase) {
for _, showcase := range showcases {
r.AddProfileShowcase(showcase)
func (r *MessengerResponse) AddSeveralUpdatedProfileShowcaseContactIDs(contactIDs []string) {
for _, contactID := range contactIDs {
r.AddUpdatedProfileShowcaseContactID(contactID)
}
}
func (r *MessengerResponse) AddProfileShowcase(showcase *ProfileShowcase) {
if r.updatedProfileShowcases == nil {
r.updatedProfileShowcases = make(map[string]*ProfileShowcase)
func (r *MessengerResponse) AddUpdatedProfileShowcaseContactID(contactID string) {
if r.updatedProfileShowcaseContactIDs == nil {
r.updatedProfileShowcaseContactIDs = make(map[string]bool)
}
r.updatedProfileShowcases[showcase.ContactID] = showcase
if _, exists := r.updatedProfileShowcaseContactIDs[contactID]; exists {
return
}
r.updatedProfileShowcaseContactIDs[contactID] = true
}
func (r *MessengerResponse) GetUpdatedProfileShowcases() []*ProfileShowcase {
var showcases []*ProfileShowcase
for _, showcase := range r.updatedProfileShowcases {
showcases = append(showcases, showcase)
func (r *MessengerResponse) GetUpdatedProfileShowcaseContactIDs() []string {
var contactIDs []string
for contactID := range r.updatedProfileShowcaseContactIDs {
contactIDs = append(contactIDs, contactID)
}
return showcases
return contactIDs
}
func (r *MessengerResponse) AddSeveralSeenAndUnseenMessages(messages []*SeenUnseenMessages) {

View File

@ -57,3 +57,15 @@ func (m *Messenger) SetCustomizationColor(ctx context.Context, request *requests
}
return nil
}
func (m *Messenger) TogglePeerSyncing(request *requests.TogglePeerSyncingRequest) error {
if err := request.Validate(); err != nil {
return err
}
err := m.settings.SetPeerSyncingEnabled(request.Enabled)
if err != nil {
return err
}
return nil
}

View File

@ -15,6 +15,7 @@ import (
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/protocol/communities"
"github.com/status-im/status-go/protocol/transport"
"github.com/status-im/status-go/services/mailservers"
)
const (
@ -32,6 +33,17 @@ type storeNodeRequestID struct {
DataID string `json:"dataID"`
}
func (r *storeNodeRequestID) getCommunityID() string {
switch r.RequestType {
case storeNodeCommunityRequest:
return r.DataID
case storeNodeShardRequest:
return strings.TrimSuffix(r.DataID, transport.CommunityShardInfoTopicPrefix())
default:
return ""
}
}
type StoreNodeRequestManager struct {
messenger *Messenger
logger *zap.Logger
@ -225,9 +237,7 @@ func (m *StoreNodeRequestManager) getFilter(requestType storeNodeRequestType, da
}
switch requestType {
case storeNodeShardRequest:
fallthrough
case storeNodeCommunityRequest:
case storeNodeShardRequest, storeNodeCommunityRequest:
// If filter wasn't installed we create it and
// remember for uninstalling after response is received
filters, err := m.messenger.transport.InitPublicFilters([]transport.FiltersToInitialize{{
@ -503,23 +513,29 @@ func (r *storeNodeRequest) routine() {
r.finalize()
}()
if !r.manager.messenger.waitForAvailableStoreNode(storeNodeAvailableTimeout) {
r.result.err = fmt.Errorf("store node is not available")
return
communityID := r.requestID.getCommunityID()
if r.requestID.RequestType != storeNodeCommunityRequest || !r.manager.messenger.communityStorenodes.HasStorenodeSetup(communityID) {
if !r.manager.messenger.waitForAvailableStoreNode(storeNodeAvailableTimeout) {
r.result.err = fmt.Errorf("store node is not available")
return
}
}
storeNode := r.manager.messenger.getActiveMailserver(communityID)
// Check if community already exists locally and get Clock.
localCommunity, _ := r.manager.messenger.communitiesManager.GetByIDString(r.requestID.DataID)
if localCommunity != nil {
r.minimumDataClock = localCommunity.Clock()
if r.requestID.RequestType == storeNodeCommunityRequest {
localCommunity, _ := r.manager.messenger.communitiesManager.GetByIDString(communityID)
if localCommunity != nil {
r.minimumDataClock = localCommunity.Clock()
}
}
// Start store node request
from, to := r.manager.messenger.calculateMailserverTimeBounds(oneMonthDuration)
_, err := r.manager.messenger.performMailserverRequest(func() (*MessengerResponse, error) {
_, err := r.manager.messenger.performMailserverRequest(storeNode, func(ms mailservers.Mailserver) (*MessengerResponse, error) {
batch := MailserverBatch{
From: from,
To: to,
@ -531,7 +547,7 @@ func (r *storeNodeRequest) routine() {
r.manager.onPerformingBatch(batch)
}
return nil, r.manager.messenger.processMailserverBatchWithOptions(batch, r.config.InitialPageSize, r.shouldFetchNextPage, true)
return nil, r.manager.messenger.processMailserverBatchWithOptions(ms, batch, r.config.InitialPageSize, r.shouldFetchNextPage, true)
})
r.result.err = err

View File

@ -327,6 +327,16 @@ func (m *Messenger) HandleSyncRawMessages(rawMessages []*protobuf.RawMessage) er
if err != nil {
return err
}
case protobuf.ApplicationMetadataMessage_SYNC_PROFILE_SHOWCASE_PREFERENCES:
var message protobuf.SyncProfileShowcasePreferences
err := proto.Unmarshal(rawMessage.GetPayload(), &message)
if err != nil {
return err
}
_, err = m.saveProfileShowcasePreferencesProto(&message, false)
if err != nil {
return err
}
}
}
response, err := m.saveDataAndPrepareResponse(state)

View File

@ -4,10 +4,18 @@ import (
"context"
"crypto/rand"
"errors"
"fmt"
"math/big"
"sync"
"time"
"github.com/status-im/status-go/protocol/wakusync"
"github.com/status-im/status-go/protocol/identity"
"github.com/status-im/status-go/eth-node/types"
waku2 "github.com/status-im/status-go/wakuv2"
"golang.org/x/exp/maps"
"github.com/stretchr/testify/suite"
@ -46,8 +54,18 @@ func WaitOnMessengerResponse(m *Messenger, condition func(*MessengerResponse) bo
type MessengerSignalsHandlerMock struct {
MessengerSignalsHandler
responseChan chan *MessengerResponse
communityFoundChan chan *communities.Community
responseChan chan *MessengerResponse
communityFoundChan chan *communities.Community
wakuBackedUpDataResponseChan chan *wakusync.WakuBackedUpDataResponse
}
func (m *MessengerSignalsHandlerMock) SendWakuFetchingBackupProgress(response *wakusync.WakuBackedUpDataResponse) {
m.wakuBackedUpDataResponseChan <- response
}
func (m *MessengerSignalsHandlerMock) SendWakuBackedUpProfile(*wakusync.WakuBackedUpDataResponse) {}
func (m *MessengerSignalsHandlerMock) SendWakuBackedUpSettings(*wakusync.WakuBackedUpDataResponse) {}
func (m *MessengerSignalsHandlerMock) SendWakuBackedUpKeypair(*wakusync.WakuBackedUpDataResponse) {}
func (m *MessengerSignalsHandlerMock) SendWakuBackedUpWatchOnlyAccount(*wakusync.WakuBackedUpDataResponse) {
}
func (m *MessengerSignalsHandlerMock) MessengerResponse(response *MessengerResponse) {
@ -67,6 +85,42 @@ func (m *MessengerSignalsHandlerMock) CommunityInfoFound(community *communities.
}
}
func WaitOnSignaledSendWakuFetchingBackupProgress(m *Messenger, condition func(*wakusync.WakuBackedUpDataResponse) bool, errorMessage string) (*wakusync.WakuBackedUpDataResponse, error) {
interval := 500 * time.Millisecond
timeoutChan := time.After(10 * time.Second)
if m.config.messengerSignalsHandler != nil {
return nil, errors.New("messengerSignalsHandler already provided/mocked")
}
responseChan := make(chan *wakusync.WakuBackedUpDataResponse, 1000)
m.config.messengerSignalsHandler = &MessengerSignalsHandlerMock{
wakuBackedUpDataResponseChan: responseChan,
}
defer func() {
m.config.messengerSignalsHandler = nil
}()
for {
_, err := m.RetrieveAll()
if err != nil {
return nil, err
}
select {
case r := <-responseChan:
if condition(r) {
return r, nil
}
case <-timeoutChan:
return nil, errors.New("timed out: " + errorMessage)
default: // No immediate response, rest & loop back to retrieve again
time.Sleep(interval)
}
}
}
func WaitOnSignaledMessengerResponse(m *Messenger, condition func(*MessengerResponse) bool, errorMessage string) (*MessengerResponse, error) {
interval := 500 * time.Millisecond
timeoutChan := time.After(10 * time.Second)
@ -75,7 +129,7 @@ func WaitOnSignaledMessengerResponse(m *Messenger, condition func(*MessengerResp
return nil, errors.New("messengerSignalsHandler already provided/mocked")
}
responseChan := make(chan *MessengerResponse, 1)
responseChan := make(chan *MessengerResponse, 64)
m.config.messengerSignalsHandler = &MessengerSignalsHandlerMock{
responseChan: responseChan,
}
@ -95,10 +149,9 @@ func WaitOnSignaledMessengerResponse(m *Messenger, condition func(*MessengerResp
if condition(r) {
return r, nil
}
return nil, errors.New(errorMessage)
case <-timeoutChan:
return nil, errors.New("timed out: " + errorMessage)
return nil, errors.New(errorMessage)
default: // No immediate response, rest & loop back to retrieve again
time.Sleep(interval)
@ -138,6 +191,66 @@ func WaitOnSignaledCommunityFound(m *Messenger, action func(), condition func(co
}
}
func WaitForConnectionStatus(s *suite.Suite, waku *waku2.Waku, action func() bool) {
subscription := waku.SubscribeToConnStatusChanges()
defer subscription.Unsubscribe()
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
// Action should return the desired online status
wantedOnline := action()
for {
select {
case status := <-subscription.C:
if status.IsOnline == wantedOnline {
return
}
case <-ctx.Done():
s.Require().Fail(fmt.Sprintf("timeout waiting for waku connection status '%t'", wantedOnline))
return
}
}
}
func hasAllPeers(m map[string]types.WakuV2Peer, checkSlice []string) bool {
for _, check := range checkSlice {
if _, ok := m[check]; !ok {
return false
}
}
return true
}
func WaitForPeersConnected(s *suite.Suite, waku *waku2.Waku, action func() []string) {
subscription := waku.SubscribeToConnStatusChanges()
defer subscription.Unsubscribe()
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
// Action should return the desired peer ID
peerIDs := action()
if hasAllPeers(waku.Peers(), peerIDs) {
return
}
for {
select {
case status := <-subscription.C:
if hasAllPeers(status.Peers, peerIDs) {
// Give some time for p2p events, otherwise might look like peer is available, but fail to send a message.
time.Sleep(100 * time.Millisecond)
return
}
case <-ctx.Done():
s.Require().Fail(fmt.Sprintf("timeout waiting for peers connected '%+v'", peerIDs))
return
}
}
}
func FindFirstByContentType(messages []*common.Message, contentType protobuf.ChatMessage_ContentType) *common.Message {
for _, message := range messages {
if message.ContentType == contentType {
@ -302,3 +415,97 @@ func RandomBytes(length int) []byte {
}
return out
}
func DummyProfileShowcasePreferences(withCollectibles bool) *identity.ProfileShowcasePreferences {
preferences := &identity.ProfileShowcasePreferences{
Communities: []*identity.ProfileShowcaseCommunityPreference{
{
CommunityID: "0x254254546768764565565",
ShowcaseVisibility: identity.ProfileShowcaseVisibilityEveryone,
},
{
CommunityID: "0x865241434343432412343",
ShowcaseVisibility: identity.ProfileShowcaseVisibilityContacts,
},
},
Accounts: []*identity.ProfileShowcaseAccountPreference{
{
Address: "0x0000000000000000000000000033433445133423",
ShowcaseVisibility: identity.ProfileShowcaseVisibilityEveryone,
Order: 0,
},
{
Address: "0x0000000000000000000000000032433445133424",
ShowcaseVisibility: identity.ProfileShowcaseVisibilityContacts,
Order: 1,
},
},
VerifiedTokens: []*identity.ProfileShowcaseVerifiedTokenPreference{
{
Symbol: "ETH",
ShowcaseVisibility: identity.ProfileShowcaseVisibilityEveryone,
Order: 1,
},
{
Symbol: "DAI",
ShowcaseVisibility: identity.ProfileShowcaseVisibilityIDVerifiedContacts,
Order: 2,
},
{
Symbol: "SNT",
ShowcaseVisibility: identity.ProfileShowcaseVisibilityNoOne,
Order: 3,
},
},
UnverifiedTokens: []*identity.ProfileShowcaseUnverifiedTokenPreference{
{
ContractAddress: "0x454525452023452",
ChainID: 11155111,
ShowcaseVisibility: identity.ProfileShowcaseVisibilityEveryone,
Order: 0,
},
{
ContractAddress: "0x12312323323233",
ChainID: 1,
ShowcaseVisibility: identity.ProfileShowcaseVisibilityContacts,
Order: 1,
},
},
SocialLinks: []*identity.ProfileShowcaseSocialLinkPreference{
&identity.ProfileShowcaseSocialLinkPreference{
Text: identity.TwitterID,
URL: "https://twitter.com/ethstatus",
ShowcaseVisibility: identity.ProfileShowcaseVisibilityEveryone,
Order: 1,
},
&identity.ProfileShowcaseSocialLinkPreference{
Text: identity.TwitterID,
URL: "https://twitter.com/StatusIMBlog",
ShowcaseVisibility: identity.ProfileShowcaseVisibilityIDVerifiedContacts,
Order: 2,
},
&identity.ProfileShowcaseSocialLinkPreference{
Text: identity.GithubID,
URL: "https://github.com/status-im",
ShowcaseVisibility: identity.ProfileShowcaseVisibilityContacts,
Order: 3,
},
},
}
if withCollectibles {
preferences.Collectibles = []*identity.ProfileShowcaseCollectiblePreference{
{
ContractAddress: "0x12378534257568678487683576",
ChainID: 1,
TokenID: "12321389592999903",
ShowcaseVisibility: identity.ProfileShowcaseVisibilityEveryone,
Order: 0,
},
}
} else {
preferences.Collectibles = []*identity.ProfileShowcaseCollectiblePreference{}
}
return preferences
}

File diff suppressed because it is too large Load Diff

View File

@ -571,6 +571,7 @@ func (db sqlitePersistence) Contacts() ([]*Contact, error) {
c.last_updated_locally,
c.blocked,
c.removed,
c.bio,
c.local_nickname,
c.contact_request_state,
c.contact_request_local_clock,
@ -606,6 +607,7 @@ func (db sqlitePersistence) Contacts() ([]*Contact, error) {
ensVerified sql.NullBool
blocked sql.NullBool
removed sql.NullBool
bio sql.NullString
lastUpdatedLocally sql.NullInt64
identityImageClock sql.NullInt64
imagePayload []byte
@ -625,6 +627,7 @@ func (db sqlitePersistence) Contacts() ([]*Contact, error) {
&lastUpdatedLocally,
&blocked,
&removed,
&bio,
&nickname,
&contactRequestLocalState,
&contactRequestLocalClock,
@ -644,6 +647,10 @@ func (db sqlitePersistence) Contacts() ([]*Contact, error) {
contact.LocalNickname = nickname.String
}
if bio.Valid {
contact.Bio = bio.String
}
if contactRequestLocalState.Valid {
contact.ContactRequestLocalState = ContactRequestState(contactRequestLocalState.Int64)
}
@ -966,10 +973,11 @@ func (db sqlitePersistence) SaveContact(contact *Contact, tx *sql.Tx) (err error
blocked,
removed,
verification_status,
bio,
name,
photo,
tribute_to_talk
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`)
if err != nil {
return
@ -992,6 +1000,7 @@ func (db sqlitePersistence) SaveContact(contact *Contact, tx *sql.Tx) (err error
contact.Blocked,
contact.Removed,
contact.VerificationStatus,
contact.Bio,
//TODO we need to drop these columns
"",
"",

View File

@ -4,54 +4,65 @@ import (
"context"
"database/sql"
"errors"
"github.com/status-im/status-go/protocol/identity"
)
type ProfileShowcaseVisibility int
const (
ProfileShowcaseVisibilityNoOne ProfileShowcaseVisibility = iota
ProfileShowcaseVisibilityIDVerifiedContacts
ProfileShowcaseVisibilityContacts
ProfileShowcaseVisibilityEveryone
)
// Profile showcase preferences
const upsertProfileShowcasePreferencesQuery = "UPDATE profile_showcase_preferences SET clock=? WHERE NOT EXISTS (SELECT 1 FROM profile_showcase_preferences WHERE clock >= ?)"
const selectProfileShowcasePreferencesQuery = "SELECT clock FROM profile_showcase_preferences"
const upsertProfileShowcaseCommunityPreferenceQuery = "INSERT OR REPLACE INTO profile_showcase_communities_preferences(community_id, visibility, sort_order) VALUES (?, ?, ?)" // #nosec G101
const selectProfileShowcaseCommunityPreferenceQuery = "SELECT community_id, visibility, sort_order FROM profile_showcase_communities_preferences" // #nosec G101
const deleteProfileShowcaseCommunityPreferenceQuery = "DELETE FROM profile_showcase_communities_preferences WHERE community_id = ?" // #nosec G101
const clearProfileShowcaseCommunitiyPreferencesQuery = "DELETE FROM profile_showcase_communities_preferences" // #nosec G101
const upsertProfileShowcaseAccountPreferenceQuery = "INSERT OR REPLACE INTO profile_showcase_accounts_preferences(address, name, color_id, emoji, visibility, sort_order) VALUES (?, ?, ?, ?, ?, ?)" // #nosec G101
const selectProfileShowcaseAccountPreferenceQuery = "SELECT address, name, color_id, emoji, visibility, sort_order FROM profile_showcase_accounts_preferences" // #nosec G101
const selectSpecifiedShowcaseAccountPreferenceQuery = "SELECT address, name, color_id, emoji, visibility, sort_order FROM profile_showcase_accounts_preferences WHERE address = ?" // #nosec G101
const deleteProfileShowcaseAccountPreferenceQuery = "DELETE FROM profile_showcase_accounts_preferences WHERE address = ?" // #nosec G101
const upsertProfileShowcaseAccountPreferenceQuery = "INSERT OR REPLACE INTO profile_showcase_accounts_preferences(address, visibility, sort_order) VALUES (?, ?, ?)" // #nosec G101
const selectProfileShowcaseAccountPreferenceQuery = "SELECT address, visibility, sort_order FROM profile_showcase_accounts_preferences" // #nosec G101
const selectSpecifiedShowcaseAccountPreferenceQuery = "SELECT address, visibility, sort_order FROM profile_showcase_accounts_preferences WHERE address = ?" // #nosec G101
const deleteProfileShowcaseAccountPreferenceQuery = "DELETE FROM profile_showcase_accounts_preferences WHERE address = ?" // #nosec G101
const clearProfileShowcaseAccountPreferencesQuery = "DELETE FROM profile_showcase_accounts_preferences" // #nosec G101
const upsertProfileShowcaseCollectiblePreferenceQuery = "INSERT OR REPLACE INTO profile_showcase_collectibles_preferences(contract_address, chain_id, token_id, community_id, account_address, visibility, sort_order) VALUES (?, ?, ?, ?, ?, ?, ?)" // #nosec G101
const selectProfileShowcaseCollectiblePreferenceQuery = "SELECT contract_address, chain_id, token_id, community_id, account_address, visibility, sort_order FROM profile_showcase_collectibles_preferences" // #nosec G101
const upsertProfileShowcaseCollectiblePreferenceQuery = "INSERT OR REPLACE INTO profile_showcase_collectibles_preferences(contract_address, chain_id, token_id, visibility, sort_order) VALUES (?, ?, ?, ?, ?)" // #nosec G101
const selectProfileShowcaseCollectiblePreferenceQuery = "SELECT contract_address, chain_id, token_id, visibility, sort_order FROM profile_showcase_collectibles_preferences" // #nosec G101
const clearProfileShowcaseCollectiblePreferencesQuery = "DELETE FROM profile_showcase_collectibles_preferences" // #nosec G101
const upsertProfileShowcaseVerifiedTokenPreferenceQuery = "INSERT OR REPLACE INTO profile_showcase_verified_tokens_preferences(symbol, visibility, sort_order) VALUES (?, ?, ?)" // #nosec G101
const selectProfileShowcaseVerifiedTokenPreferenceQuery = "SELECT symbol, visibility, sort_order FROM profile_showcase_verified_tokens_preferences" // #nosec G101
const clearProfileShowcaseVerifiedTokenPreferencesQuery = "DELETE FROM profile_showcase_verified_tokens_preferences" // #nosec G101
const upsertProfileShowcaseUnverifiedTokenPreferenceQuery = "INSERT OR REPLACE INTO profile_showcase_unverified_tokens_preferences(contract_address, chain_id, community_id, visibility, sort_order) VALUES (?, ?, ?, ?, ?)" // #nosec G101
const selectProfileShowcaseUnverifiedTokenPreferenceQuery = "SELECT contract_address, chain_id, community_id, visibility, sort_order FROM profile_showcase_unverified_tokens_preferences" // #nosec G101
const upsertProfileShowcaseUnverifiedTokenPreferenceQuery = "INSERT OR REPLACE INTO profile_showcase_unverified_tokens_preferences(contract_address, chain_id, visibility, sort_order) VALUES (?, ?, ?, ?)" // #nosec G101
const selectProfileShowcaseUnverifiedTokenPreferenceQuery = "SELECT contract_address, chain_id, visibility, sort_order FROM profile_showcase_unverified_tokens_preferences" // #nosec G101
const clearProfileShowcaseUnverifiedTokenPreferencesQuery = "DELETE FROM profile_showcase_unverified_tokens_preferences" // #nosec G101
const upsertContactProfileShowcaseCommunityQuery = "INSERT OR REPLACE INTO profile_showcase_communities_contacts(contact_id, community_id, sort_order) VALUES (?, ?, ?)" // #nosec G101
const selectContactProfileShowcaseCommunityQuery = "SELECT community_id, sort_order FROM profile_showcase_communities_contacts WHERE contact_id = ?" // #nosec G101
const removeContactProfileShowcaseCommunityQuery = "DELETE FROM profile_showcase_communities_contacts WHERE contact_id = ?" // #nosec G101
const upsertProfileShowcaseSocialLinkPreferenceQuery = "INSERT OR REPLACE INTO profile_showcase_social_links_preferences(url, text, visibility, sort_order) VALUES (?, ?, ?, ?)" // #nosec G101
const selectProfileShowcaseSocialLinkPreferenceQuery = "SELECT url, text, visibility, sort_order FROM profile_showcase_social_links_preferences" // #nosec G101
const clearProfileShowcaseSocialLinkPreferencesQuery = "DELETE FROM profile_showcase_social_links_preferences" // #nosec G101
// Profile showcase for a contact
const upsertContactProfileShowcaseCommunityQuery = "INSERT OR REPLACE INTO profile_showcase_communities_contacts(contact_id, community_id, sort_order, grant) VALUES (?, ?, ?, ?)" // #nosec G101
const selectContactProfileShowcaseCommunityQuery = "SELECT community_id, sort_order, grant FROM profile_showcase_communities_contacts WHERE contact_id = ?" // #nosec G101
const removeContactProfileShowcaseCommunityQuery = "DELETE FROM profile_showcase_communities_contacts WHERE contact_id = ?" // #nosec G101
const upsertContactProfileShowcaseAccountQuery = "INSERT OR REPLACE INTO profile_showcase_accounts_contacts(contact_id, address, name, color_id, emoji, sort_order) VALUES (?, ?, ?, ?, ?, ?)" // #nosec G101
const selectContactProfileShowcaseAccountQuery = "SELECT * FROM profile_showcase_accounts_contacts WHERE contact_id = ?" // #nosec G101
const removeContactProfileShowcaseAccountQuery = "DELETE FROM profile_showcase_accounts_contacts WHERE contact_id = ?" // #nosec G101
const upsertContactProfileShowcaseCollectibleQuery = "INSERT OR REPLACE INTO profile_showcase_collectibles_contacts(contact_id, contract_address, chain_id, token_id, community_id, account_address, sort_order) VALUES (?, ?, ?, ?, ?, ?, ?)" // #nosec G101
const selectContactProfileShowcaseCollectibleQuery = "SELECT contract_address, chain_id, token_id, community_id, account_address, sort_order FROM profile_showcase_collectibles_contacts WHERE contact_id = ?" // #nosec G101
const removeContactProfileShowcaseCollectibleQuery = "DELETE FROM profile_showcase_collectibles_contacts WHERE contact_id = ?" // #nosec G101
const upsertContactProfileShowcaseCollectibleQuery = "INSERT OR REPLACE INTO profile_showcase_collectibles_contacts(contact_id, contract_address, chain_id, token_id, sort_order) VALUES (?, ?, ?, ?, ?)" // #nosec G101
const selectContactProfileShowcaseCollectibleQuery = "SELECT contract_address, chain_id, token_id, sort_order FROM profile_showcase_collectibles_contacts WHERE contact_id = ?" // #nosec G101
const removeContactProfileShowcaseCollectibleQuery = "DELETE FROM profile_showcase_collectibles_contacts WHERE contact_id = ?" // #nosec G101
const upsertContactProfileShowcaseVerifiedTokenQuery = "INSERT OR REPLACE INTO profile_showcase_verified_tokens_contacts(contact_id, symbol, sort_order) VALUES (?, ?, ?)" // #nosec G101
const selectContactProfileShowcaseVerifiedTokenQuery = "SELECT symbol, sort_order FROM profile_showcase_verified_tokens_contacts WHERE contact_id = ?" // #nosec G101
const removeContactProfileShowcaseVerifiedTokenQuery = "DELETE FROM profile_showcase_verified_tokens_contacts WHERE contact_id = ?" // #nosec G101
const upsertContactProfileShowcaseUnverifiedTokenQuery = "INSERT OR REPLACE INTO profile_showcase_unverified_tokens_contacts(contact_id, contract_address, chain_id, community_id, sort_order) VALUES (?, ?, ?, ?, ?)" // #nosec G101
const selectContactProfileShowcaseUnverifiedTokenQuery = "SELECT contract_address, chain_id, community_id, sort_order FROM profile_showcase_unverified_tokens_contacts WHERE contact_id = ?" // #nosec G101
const removeContactProfileShowcaseUnverifiedTokenQuery = "DELETE FROM profile_showcase_unverified_tokens_contacts WHERE contact_id = ?" // #nosec G101
const upsertContactProfileShowcaseUnverifiedTokenQuery = "INSERT OR REPLACE INTO profile_showcase_unverified_tokens_contacts(contact_id, contract_address, chain_id, sort_order) VALUES (?, ?, ?, ?)" // #nosec G101
const selectContactProfileShowcaseUnverifiedTokenQuery = "SELECT contract_address, chain_id, sort_order FROM profile_showcase_unverified_tokens_contacts WHERE contact_id = ?" // #nosec G101
const removeContactProfileShowcaseUnverifiedTokenQuery = "DELETE FROM profile_showcase_unverified_tokens_contacts WHERE contact_id = ?" // #nosec G101
const upsertContactProfileShowcaseSocialLinkQuery = "INSERT OR REPLACE INTO profile_showcase_social_links_contacts(contact_id, url, text, sort_order) VALUES (?, ?, ?, ?)" // #nosec G101
const selectContactProfileShowcaseSocialLinkQuery = "SELECT url, text, sort_order FROM profile_showcase_social_links_contacts WHERE contact_id = ?" // #nosec G101
const removeContactProfileShowcaseSocialLinkQuery = "DELETE FROM profile_showcase_social_links_contacts WHERE contact_id = ?" // #nosec G101
const selectProfileShowcaseAccountsWhichMatchTheAddress = `
SELECT psa.*
@ -65,99 +76,20 @@ WHERE
psa.address = ?
`
type ProfileShowcaseCommunityPreference struct {
CommunityID string `json:"communityId"`
ShowcaseVisibility ProfileShowcaseVisibility `json:"showcaseVisibility"`
Order int `json:"order"`
// Queries for the profile showcase preferences
func (db sqlitePersistence) saveProfileShowcasePreferencesClock(tx *sql.Tx, clock uint64) error {
_, err := tx.Exec(upsertProfileShowcasePreferencesQuery, clock, clock)
return err
}
type ProfileShowcaseAccountPreference struct {
Address string `json:"address"`
Name string `json:"name"`
ColorID string `json:"colorId"`
Emoji string `json:"emoji"`
ShowcaseVisibility ProfileShowcaseVisibility `json:"showcaseVisibility"`
Order int `json:"order"`
func (db sqlitePersistence) getProfileShowcasePreferencesClock(tx *sql.Tx) (uint64, error) {
var clock uint64
err := tx.QueryRow(selectProfileShowcasePreferencesQuery).Scan(&clock)
return clock, err
}
type ProfileShowcaseCollectiblePreference struct {
ContractAddress string `json:"contractAddress"`
ChainID uint64 `json:"chainId"`
TokenID string `json:"tokenId"`
CommunityID string `json:"communityId"`
AccountAddress string `json:"accountAddress"`
ShowcaseVisibility ProfileShowcaseVisibility `json:"showcaseVisibility"`
Order int `json:"order"`
}
type ProfileShowcaseVerifiedTokenPreference struct {
Symbol string `json:"symbol"`
ShowcaseVisibility ProfileShowcaseVisibility `json:"showcaseVisibility"`
Order int `json:"order"`
}
type ProfileShowcaseUnverifiedTokenPreference struct {
ContractAddress string `json:"contractAddress"`
ChainID uint64 `json:"chainId"`
CommunityID string `json:"communityId"`
ShowcaseVisibility ProfileShowcaseVisibility `json:"showcaseVisibility"`
Order int `json:"order"`
}
type ProfileShowcasePreferences struct {
Communities []*ProfileShowcaseCommunityPreference `json:"communities"`
Accounts []*ProfileShowcaseAccountPreference `json:"accounts"`
Collectibles []*ProfileShowcaseCollectiblePreference `json:"collectibles"`
VerifiedTokens []*ProfileShowcaseVerifiedTokenPreference `json:"verifiedTokens"`
UnverifiedTokens []*ProfileShowcaseUnverifiedTokenPreference `json:"unverifiedTokens"`
}
type ProfileShowcaseCommunity struct {
CommunityID string `json:"communityId"`
Order int `json:"order"`
}
type ProfileShowcaseAccount struct {
ContactID string `json:"contactId"`
Address string `json:"address"`
Name string `json:"name"`
ColorID string `json:"colorId"`
Emoji string `json:"emoji"`
Order int `json:"order"`
}
type ProfileShowcaseCollectible struct {
ContractAddress string `json:"contractAddress"`
ChainID uint64 `json:"chainId"`
TokenID string `json:"tokenId"`
CommunityID string `json:"communityId"`
AccountAddress string `json:"accountAddress"`
Order int `json:"order"`
}
type ProfileShowcaseVerifiedToken struct {
Symbol string `json:"symbol"`
Order int `json:"order"`
}
type ProfileShowcaseUnverifiedToken struct {
ContractAddress string `json:"contractAddress"`
ChainID uint64 `json:"chainId"`
CommunityID string `json:"communityId"`
Order int `json:"order"`
}
type ProfileShowcase struct {
ContactID string `json:"contactId"`
Communities []*ProfileShowcaseCommunity `json:"communities"`
Accounts []*ProfileShowcaseAccount `json:"accounts"`
Collectibles []*ProfileShowcaseCollectible `json:"collectibles"`
VerifiedTokens []*ProfileShowcaseVerifiedToken `json:"verifiedTokens"`
UnverifiedTokens []*ProfileShowcaseUnverifiedToken `json:"unverifiedTokens"`
}
// Queries for showcase preferences
func (db sqlitePersistence) saveProfileShowcaseCommunityPreference(tx *sql.Tx, community *ProfileShowcaseCommunityPreference) error {
func (db sqlitePersistence) saveProfileShowcaseCommunityPreference(tx *sql.Tx, community *identity.ProfileShowcaseCommunityPreference) error {
_, err := tx.Exec(upsertProfileShowcaseCommunityPreferenceQuery,
community.CommunityID,
community.ShowcaseVisibility,
@ -167,16 +99,16 @@ func (db sqlitePersistence) saveProfileShowcaseCommunityPreference(tx *sql.Tx, c
return err
}
func (db sqlitePersistence) getProfileShowcaseCommunitiesPreferences(tx *sql.Tx) ([]*ProfileShowcaseCommunityPreference, error) {
func (db sqlitePersistence) getProfileShowcaseCommunitiesPreferences(tx *sql.Tx) ([]*identity.ProfileShowcaseCommunityPreference, error) {
rows, err := tx.Query(selectProfileShowcaseCommunityPreferenceQuery)
if err != nil {
return nil, err
}
communities := []*ProfileShowcaseCommunityPreference{}
communities := []*identity.ProfileShowcaseCommunityPreference{}
for rows.Next() {
community := &ProfileShowcaseCommunityPreference{}
community := &identity.ProfileShowcaseCommunityPreference{}
err := rows.Scan(
&community.CommunityID,
@ -193,12 +125,24 @@ func (db sqlitePersistence) getProfileShowcaseCommunitiesPreferences(tx *sql.Tx)
return communities, nil
}
func (db sqlitePersistence) saveProfileShowcaseAccountPreference(tx *sql.Tx, account *ProfileShowcaseAccountPreference) error {
func (db sqlitePersistence) DeleteProfileShowcaseCommunityPreference(communityID string) (bool, error) {
result, err := db.db.Exec(deleteProfileShowcaseCommunityPreferenceQuery, communityID)
if err != nil {
return false, err
}
rows, err := result.RowsAffected()
return rows > 0, err
}
func (db sqlitePersistence) clearProfileShowcaseCommunityPreferences(tx *sql.Tx) error {
_, err := tx.Exec(clearProfileShowcaseCommunitiyPreferencesQuery)
return err
}
func (db sqlitePersistence) saveProfileShowcaseAccountPreference(tx *sql.Tx, account *identity.ProfileShowcaseAccountPreference) error {
_, err := tx.Exec(upsertProfileShowcaseAccountPreferenceQuery,
account.Address,
account.Name,
account.ColorID,
account.Emoji,
account.ShowcaseVisibility,
account.Order,
)
@ -206,19 +150,16 @@ func (db sqlitePersistence) saveProfileShowcaseAccountPreference(tx *sql.Tx, acc
return err
}
func (db sqlitePersistence) processProfileShowcaseAccountPreferences(rows *sql.Rows) (result []*ProfileShowcaseAccountPreference, err error) {
func (db sqlitePersistence) processProfileShowcaseAccountPreferences(rows *sql.Rows) (result []*identity.ProfileShowcaseAccountPreference, err error) {
if rows == nil {
return nil, errors.New("rows is nil")
}
for rows.Next() {
account := &ProfileShowcaseAccountPreference{}
account := &identity.ProfileShowcaseAccountPreference{}
err := rows.Scan(
&account.Address,
&account.Name,
&account.ColorID,
&account.Emoji,
&account.ShowcaseVisibility,
&account.Order,
)
@ -234,7 +175,7 @@ func (db sqlitePersistence) processProfileShowcaseAccountPreferences(rows *sql.R
return
}
func (db sqlitePersistence) getProfileShowcaseAccountsPreferences(tx *sql.Tx) ([]*ProfileShowcaseAccountPreference, error) {
func (db sqlitePersistence) getProfileShowcaseAccountsPreferences(tx *sql.Tx) ([]*identity.ProfileShowcaseAccountPreference, error) {
rows, err := tx.Query(selectProfileShowcaseAccountPreferenceQuery)
if err != nil {
return nil, err
@ -243,7 +184,7 @@ func (db sqlitePersistence) getProfileShowcaseAccountsPreferences(tx *sql.Tx) ([
return db.processProfileShowcaseAccountPreferences(rows)
}
func (db sqlitePersistence) GetProfileShowcaseAccountPreference(accountAddress string) (*ProfileShowcaseAccountPreference, error) {
func (db sqlitePersistence) GetProfileShowcaseAccountPreference(accountAddress string) (*identity.ProfileShowcaseAccountPreference, error) {
rows, err := db.db.Query(selectSpecifiedShowcaseAccountPreferenceQuery, accountAddress)
if err != nil {
return nil, err
@ -266,23 +207,16 @@ func (db sqlitePersistence) DeleteProfileShowcaseAccountPreference(accountAddres
return rows > 0, err
}
func (db sqlitePersistence) DeleteProfileShowcaseCommunityPreference(communityID string) (bool, error) {
result, err := db.db.Exec(deleteProfileShowcaseCommunityPreferenceQuery, communityID)
if err != nil {
return false, err
}
rows, err := result.RowsAffected()
return rows > 0, err
func (db sqlitePersistence) clearProfileShowcaseAccountPreferences(tx *sql.Tx) error {
_, err := tx.Exec(clearProfileShowcaseAccountPreferencesQuery)
return err
}
func (db sqlitePersistence) saveProfileShowcaseCollectiblePreference(tx *sql.Tx, collectible *ProfileShowcaseCollectiblePreference) error {
func (db sqlitePersistence) saveProfileShowcaseCollectiblePreference(tx *sql.Tx, collectible *identity.ProfileShowcaseCollectiblePreference) error {
_, err := tx.Exec(upsertProfileShowcaseCollectiblePreferenceQuery,
collectible.ContractAddress,
collectible.ChainID,
collectible.TokenID,
collectible.CommunityID,
collectible.AccountAddress,
collectible.ShowcaseVisibility,
collectible.Order,
)
@ -290,23 +224,21 @@ func (db sqlitePersistence) saveProfileShowcaseCollectiblePreference(tx *sql.Tx,
return err
}
func (db sqlitePersistence) getProfileShowcaseCollectiblesPreferences(tx *sql.Tx) ([]*ProfileShowcaseCollectiblePreference, error) {
func (db sqlitePersistence) getProfileShowcaseCollectiblesPreferences(tx *sql.Tx) ([]*identity.ProfileShowcaseCollectiblePreference, error) {
rows, err := tx.Query(selectProfileShowcaseCollectiblePreferenceQuery)
if err != nil {
return nil, err
}
collectibles := []*ProfileShowcaseCollectiblePreference{}
collectibles := []*identity.ProfileShowcaseCollectiblePreference{}
for rows.Next() {
collectible := &ProfileShowcaseCollectiblePreference{}
collectible := &identity.ProfileShowcaseCollectiblePreference{}
err := rows.Scan(
&collectible.ContractAddress,
&collectible.ChainID,
&collectible.TokenID,
&collectible.CommunityID,
&collectible.AccountAddress,
&collectible.ShowcaseVisibility,
&collectible.Order,
)
@ -320,7 +252,12 @@ func (db sqlitePersistence) getProfileShowcaseCollectiblesPreferences(tx *sql.Tx
return collectibles, nil
}
func (db sqlitePersistence) saveProfileShowcaseVerifiedTokenPreference(tx *sql.Tx, token *ProfileShowcaseVerifiedTokenPreference) error {
func (db sqlitePersistence) clearProfileShowcaseCollectiblePreferences(tx *sql.Tx) error {
_, err := tx.Exec(clearProfileShowcaseCollectiblePreferencesQuery)
return err
}
func (db sqlitePersistence) saveProfileShowcaseVerifiedTokenPreference(tx *sql.Tx, token *identity.ProfileShowcaseVerifiedTokenPreference) error {
_, err := tx.Exec(upsertProfileShowcaseVerifiedTokenPreferenceQuery,
token.Symbol,
token.ShowcaseVisibility,
@ -330,28 +267,16 @@ func (db sqlitePersistence) saveProfileShowcaseVerifiedTokenPreference(tx *sql.T
return err
}
func (db sqlitePersistence) saveProfileShowcaseUnverifiedTokenPreference(tx *sql.Tx, token *ProfileShowcaseUnverifiedTokenPreference) error {
_, err := tx.Exec(upsertProfileShowcaseUnverifiedTokenPreferenceQuery,
token.ContractAddress,
token.ChainID,
token.CommunityID,
token.ShowcaseVisibility,
token.Order,
)
return err
}
func (db sqlitePersistence) getProfileShowcaseVerifiedTokensPreferences(tx *sql.Tx) ([]*ProfileShowcaseVerifiedTokenPreference, error) {
func (db sqlitePersistence) getProfileShowcaseVerifiedTokensPreferences(tx *sql.Tx) ([]*identity.ProfileShowcaseVerifiedTokenPreference, error) {
rows, err := tx.Query(selectProfileShowcaseVerifiedTokenPreferenceQuery)
if err != nil {
return nil, err
}
tokens := []*ProfileShowcaseVerifiedTokenPreference{}
tokens := []*identity.ProfileShowcaseVerifiedTokenPreference{}
for rows.Next() {
token := &ProfileShowcaseVerifiedTokenPreference{}
token := &identity.ProfileShowcaseVerifiedTokenPreference{}
err := rows.Scan(
&token.Symbol,
@ -368,21 +293,36 @@ func (db sqlitePersistence) getProfileShowcaseVerifiedTokensPreferences(tx *sql.
return tokens, nil
}
func (db sqlitePersistence) getProfileShowcaseUnverifiedTokensPreferences(tx *sql.Tx) ([]*ProfileShowcaseUnverifiedTokenPreference, error) {
func (db sqlitePersistence) clearProfileShowcaseVerifiedTokenPreferences(tx *sql.Tx) error {
_, err := tx.Exec(clearProfileShowcaseVerifiedTokenPreferencesQuery)
return err
}
func (db sqlitePersistence) saveProfileShowcaseUnverifiedTokenPreference(tx *sql.Tx, token *identity.ProfileShowcaseUnverifiedTokenPreference) error {
_, err := tx.Exec(upsertProfileShowcaseUnverifiedTokenPreferenceQuery,
token.ContractAddress,
token.ChainID,
token.ShowcaseVisibility,
token.Order,
)
return err
}
func (db sqlitePersistence) getProfileShowcaseUnverifiedTokensPreferences(tx *sql.Tx) ([]*identity.ProfileShowcaseUnverifiedTokenPreference, error) {
rows, err := tx.Query(selectProfileShowcaseUnverifiedTokenPreferenceQuery)
if err != nil {
return nil, err
}
tokens := []*ProfileShowcaseUnverifiedTokenPreference{}
tokens := []*identity.ProfileShowcaseUnverifiedTokenPreference{}
for rows.Next() {
token := &ProfileShowcaseUnverifiedTokenPreference{}
token := &identity.ProfileShowcaseUnverifiedTokenPreference{}
err := rows.Scan(
&token.ContractAddress,
&token.ChainID,
&token.CommunityID,
&token.ShowcaseVisibility,
&token.Order,
)
@ -396,29 +336,78 @@ func (db sqlitePersistence) getProfileShowcaseUnverifiedTokensPreferences(tx *sq
return tokens, nil
}
// Queries for contacts showcase
func (db sqlitePersistence) saveProfileShowcaseCommunityContact(tx *sql.Tx, contactID string, community *ProfileShowcaseCommunity) error {
_, err := tx.Exec(upsertContactProfileShowcaseCommunityQuery,
contactID,
community.CommunityID,
community.Order,
func (db sqlitePersistence) clearProfileShowcaseUnverifiedTokenPreferences(tx *sql.Tx) error {
_, err := tx.Exec(clearProfileShowcaseUnverifiedTokenPreferencesQuery)
return err
}
func (db sqlitePersistence) saveProfileShowcaseSocialLinkPreference(tx *sql.Tx, link *identity.ProfileShowcaseSocialLinkPreference) error {
_, err := tx.Exec(upsertProfileShowcaseSocialLinkPreferenceQuery,
link.URL,
link.Text,
link.ShowcaseVisibility,
link.Order,
)
return err
}
func (db sqlitePersistence) getProfileShowcaseCommunitiesContact(tx *sql.Tx, contactID string) ([]*ProfileShowcaseCommunity, error) {
func (db sqlitePersistence) getProfileShowcaseSocialLinkPreferences(tx *sql.Tx) ([]*identity.ProfileShowcaseSocialLinkPreference, error) {
rows, err := tx.Query(selectProfileShowcaseSocialLinkPreferenceQuery)
if err != nil {
return nil, err
}
links := []*identity.ProfileShowcaseSocialLinkPreference{}
for rows.Next() {
link := &identity.ProfileShowcaseSocialLinkPreference{}
err := rows.Scan(
&link.URL,
&link.Text,
&link.ShowcaseVisibility,
&link.Order,
)
if err != nil {
return nil, err
}
links = append(links, link)
}
return links, nil
}
func (db sqlitePersistence) clearProfileShowcaseSocialLinkPreferences(tx *sql.Tx) error {
_, err := tx.Exec(clearProfileShowcaseSocialLinkPreferencesQuery)
return err
}
// Queries for the profile showcase for a contact
func (db sqlitePersistence) saveProfileShowcaseCommunityContact(tx *sql.Tx, contactID string, community *identity.ProfileShowcaseCommunity) error {
_, err := tx.Exec(upsertContactProfileShowcaseCommunityQuery,
contactID,
community.CommunityID,
community.Order,
community.Grant,
)
return err
}
func (db sqlitePersistence) getProfileShowcaseCommunitiesContact(tx *sql.Tx, contactID string) ([]*identity.ProfileShowcaseCommunity, error) {
rows, err := tx.Query(selectContactProfileShowcaseCommunityQuery, contactID)
if err != nil {
return nil, err
}
communities := []*ProfileShowcaseCommunity{}
communities := []*identity.ProfileShowcaseCommunity{}
for rows.Next() {
community := &ProfileShowcaseCommunity{}
community := &identity.ProfileShowcaseCommunity{}
err := rows.Scan(&community.CommunityID, &community.Order)
err := rows.Scan(&community.CommunityID, &community.Order, &community.Grant)
if err != nil {
return nil, err
}
@ -437,7 +426,7 @@ func (db sqlitePersistence) clearProfileShowcaseCommunityContact(tx *sql.Tx, con
return nil
}
func (db sqlitePersistence) saveProfileShowcaseAccountContact(tx *sql.Tx, contactID string, account *ProfileShowcaseAccount) error {
func (db sqlitePersistence) saveProfileShowcaseAccountContact(tx *sql.Tx, contactID string, account *identity.ProfileShowcaseAccount) error {
_, err := tx.Exec(upsertContactProfileShowcaseAccountQuery,
contactID,
account.Address,
@ -450,14 +439,13 @@ func (db sqlitePersistence) saveProfileShowcaseAccountContact(tx *sql.Tx, contac
return err
}
func (db sqlitePersistence) processProfileShowcaseAccounts(rows *sql.Rows) (result []*ProfileShowcaseAccount, err error) {
func (db sqlitePersistence) processProfileShowcaseAccounts(rows *sql.Rows) (result []*identity.ProfileShowcaseAccount, err error) {
if rows == nil {
return nil, errors.New("rows is nil")
}
for rows.Next() {
account := &ProfileShowcaseAccount{}
account := &identity.ProfileShowcaseAccount{}
err = rows.Scan(&account.Address, &account.Name, &account.ColorID, &account.Emoji, &account.Order, &account.ContactID)
if err != nil {
return
@ -470,7 +458,7 @@ func (db sqlitePersistence) processProfileShowcaseAccounts(rows *sql.Rows) (resu
return
}
func (db sqlitePersistence) getProfileShowcaseAccountsContact(tx *sql.Tx, contactID string) ([]*ProfileShowcaseAccount, error) {
func (db sqlitePersistence) getProfileShowcaseAccountsContact(tx *sql.Tx, contactID string) ([]*identity.ProfileShowcaseAccount, error) {
rows, err := tx.Query(selectContactProfileShowcaseAccountQuery, contactID)
if err != nil {
return nil, err
@ -479,7 +467,7 @@ func (db sqlitePersistence) getProfileShowcaseAccountsContact(tx *sql.Tx, contac
return db.processProfileShowcaseAccounts(rows)
}
func (db sqlitePersistence) GetProfileShowcaseAccountsByAddress(address string) ([]*ProfileShowcaseAccount, error) {
func (db sqlitePersistence) GetProfileShowcaseAccountsByAddress(address string) ([]*identity.ProfileShowcaseAccount, error) {
rows, err := db.db.Query(selectProfileShowcaseAccountsWhichMatchTheAddress, address)
if err != nil {
return nil, err
@ -493,37 +481,33 @@ func (db sqlitePersistence) clearProfileShowcaseAccountsContact(tx *sql.Tx, cont
return err
}
func (db sqlitePersistence) saveProfileShowcaseCollectibleContact(tx *sql.Tx, contactID string, collectible *ProfileShowcaseCollectible) error {
func (db sqlitePersistence) saveProfileShowcaseCollectibleContact(tx *sql.Tx, contactID string, collectible *identity.ProfileShowcaseCollectible) error {
_, err := tx.Exec(upsertContactProfileShowcaseCollectibleQuery,
contactID,
collectible.ContractAddress,
collectible.ChainID,
collectible.TokenID,
collectible.CommunityID,
collectible.AccountAddress,
collectible.Order,
)
return err
}
func (db sqlitePersistence) getProfileShowcaseCollectiblesContact(tx *sql.Tx, contactID string) ([]*ProfileShowcaseCollectible, error) {
func (db sqlitePersistence) getProfileShowcaseCollectiblesContact(tx *sql.Tx, contactID string) ([]*identity.ProfileShowcaseCollectible, error) {
rows, err := tx.Query(selectContactProfileShowcaseCollectibleQuery, contactID)
if err != nil {
return nil, err
}
collectibles := []*ProfileShowcaseCollectible{}
collectibles := []*identity.ProfileShowcaseCollectible{}
for rows.Next() {
collectible := &ProfileShowcaseCollectible{}
collectible := &identity.ProfileShowcaseCollectible{}
err := rows.Scan(
&collectible.ContractAddress,
&collectible.ChainID,
&collectible.TokenID,
&collectible.CommunityID,
&collectible.AccountAddress,
&collectible.Order)
if err != nil {
return nil, err
@ -539,7 +523,7 @@ func (db sqlitePersistence) clearProfileShowcaseCollectiblesContact(tx *sql.Tx,
return err
}
func (db sqlitePersistence) saveProfileShowcaseVerifiedTokenContact(tx *sql.Tx, contactID string, token *ProfileShowcaseVerifiedToken) error {
func (db sqlitePersistence) saveProfileShowcaseVerifiedTokenContact(tx *sql.Tx, contactID string, token *identity.ProfileShowcaseVerifiedToken) error {
_, err := tx.Exec(upsertContactProfileShowcaseVerifiedTokenQuery,
contactID,
token.Symbol,
@ -549,28 +533,16 @@ func (db sqlitePersistence) saveProfileShowcaseVerifiedTokenContact(tx *sql.Tx,
return err
}
func (db sqlitePersistence) saveProfileShowcaseUnverifiedTokenContact(tx *sql.Tx, contactID string, token *ProfileShowcaseUnverifiedToken) error {
_, err := tx.Exec(upsertContactProfileShowcaseUnverifiedTokenQuery,
contactID,
token.ContractAddress,
token.ChainID,
token.CommunityID,
token.Order,
)
return err
}
func (db sqlitePersistence) getProfileShowcaseVerifiedTokensContact(tx *sql.Tx, contactID string) ([]*ProfileShowcaseVerifiedToken, error) {
func (db sqlitePersistence) getProfileShowcaseVerifiedTokensContact(tx *sql.Tx, contactID string) ([]*identity.ProfileShowcaseVerifiedToken, error) {
rows, err := tx.Query(selectContactProfileShowcaseVerifiedTokenQuery, contactID)
if err != nil {
return nil, err
}
tokens := []*ProfileShowcaseVerifiedToken{}
tokens := []*identity.ProfileShowcaseVerifiedToken{}
for rows.Next() {
token := &ProfileShowcaseVerifiedToken{}
token := &identity.ProfileShowcaseVerifiedToken{}
err := rows.Scan(
&token.Symbol,
@ -584,43 +556,97 @@ func (db sqlitePersistence) getProfileShowcaseVerifiedTokensContact(tx *sql.Tx,
return tokens, nil
}
func (db sqlitePersistence) getProfileShowcaseUnverifiedTokensContact(tx *sql.Tx, contactID string) ([]*ProfileShowcaseUnverifiedToken, error) {
rows, err := tx.Query(selectContactProfileShowcaseUnverifiedTokenQuery, contactID)
if err != nil {
return nil, err
}
tokens := []*ProfileShowcaseUnverifiedToken{}
for rows.Next() {
token := &ProfileShowcaseUnverifiedToken{}
err := rows.Scan(
&token.ContractAddress,
&token.ChainID,
&token.CommunityID,
&token.Order)
if err != nil {
return nil, err
}
tokens = append(tokens, token)
}
return tokens, nil
}
func (db sqlitePersistence) clearProfileShowcaseVerifiedTokensContact(tx *sql.Tx, contactID string) error {
_, err := tx.Exec(removeContactProfileShowcaseVerifiedTokenQuery, contactID)
return err
}
func (db sqlitePersistence) saveProfileShowcaseUnverifiedTokenContact(tx *sql.Tx, contactID string, token *identity.ProfileShowcaseUnverifiedToken) error {
_, err := tx.Exec(upsertContactProfileShowcaseUnverifiedTokenQuery,
contactID,
token.ContractAddress,
token.ChainID,
token.Order,
)
return err
}
func (db sqlitePersistence) getProfileShowcaseUnverifiedTokensContact(tx *sql.Tx, contactID string) ([]*identity.ProfileShowcaseUnverifiedToken, error) {
rows, err := tx.Query(selectContactProfileShowcaseUnverifiedTokenQuery, contactID)
if err != nil {
return nil, err
}
tokens := []*identity.ProfileShowcaseUnverifiedToken{}
for rows.Next() {
token := &identity.ProfileShowcaseUnverifiedToken{}
err := rows.Scan(
&token.ContractAddress,
&token.ChainID,
&token.Order)
if err != nil {
return nil, err
}
tokens = append(tokens, token)
}
return tokens, nil
}
func (db sqlitePersistence) clearProfileShowcaseUnverifiedTokensContact(tx *sql.Tx, contactID string) error {
_, err := tx.Exec(removeContactProfileShowcaseUnverifiedTokenQuery, contactID)
return err
}
func (db sqlitePersistence) saveProfileShowcaseSocialLinkContact(tx *sql.Tx, contactID string, link *identity.ProfileShowcaseSocialLink) error {
_, err := tx.Exec(upsertContactProfileShowcaseSocialLinkQuery,
contactID,
link.URL,
link.Text,
link.Order,
)
return err
}
func (db sqlitePersistence) getProfileShowcaseSocialLinksContact(tx *sql.Tx, contactID string) ([]*identity.ProfileShowcaseSocialLink, error) {
rows, err := tx.Query(selectContactProfileShowcaseSocialLinkQuery, contactID)
if err != nil {
return nil, err
}
links := []*identity.ProfileShowcaseSocialLink{}
for rows.Next() {
link := &identity.ProfileShowcaseSocialLink{}
err := rows.Scan(
&link.URL,
&link.Text,
&link.Order)
if err != nil {
return nil, err
}
links = append(links, link)
}
err = rows.Err()
if err != nil {
return nil, err
}
return links, nil
}
func (db sqlitePersistence) clearProfileShowcaseSocialLinksContact(tx *sql.Tx, contactID string) error {
_, err := tx.Exec(removeContactProfileShowcaseSocialLinkQuery, contactID)
return err
}
// public functions
func (db sqlitePersistence) SaveProfileShowcasePreferences(preferences *ProfileShowcasePreferences) error {
func (db sqlitePersistence) SaveProfileShowcasePreferences(preferences *identity.ProfileShowcasePreferences) error {
tx, err := db.db.BeginTx(context.Background(), &sql.TxOptions{})
if err != nil {
return err
@ -634,6 +660,11 @@ func (db sqlitePersistence) SaveProfileShowcasePreferences(preferences *ProfileS
_ = tx.Rollback()
}()
err = db.clearProfileShowcaseCommunityPreferences(tx)
if err != nil {
return err
}
for _, community := range preferences.Communities {
err = db.saveProfileShowcaseCommunityPreference(tx, community)
if err != nil {
@ -641,6 +672,11 @@ func (db sqlitePersistence) SaveProfileShowcasePreferences(preferences *ProfileS
}
}
err = db.clearProfileShowcaseAccountPreferences(tx)
if err != nil {
return err
}
for _, account := range preferences.Accounts {
err = db.saveProfileShowcaseAccountPreference(tx, account)
if err != nil {
@ -648,6 +684,11 @@ func (db sqlitePersistence) SaveProfileShowcasePreferences(preferences *ProfileS
}
}
err = db.clearProfileShowcaseCollectiblePreferences(tx)
if err != nil {
return err
}
for _, collectible := range preferences.Collectibles {
err = db.saveProfileShowcaseCollectiblePreference(tx, collectible)
if err != nil {
@ -655,6 +696,11 @@ func (db sqlitePersistence) SaveProfileShowcasePreferences(preferences *ProfileS
}
}
err = db.clearProfileShowcaseVerifiedTokenPreferences(tx)
if err != nil {
return err
}
for _, token := range preferences.VerifiedTokens {
err = db.saveProfileShowcaseVerifiedTokenPreference(tx, token)
if err != nil {
@ -662,6 +708,11 @@ func (db sqlitePersistence) SaveProfileShowcasePreferences(preferences *ProfileS
}
}
err = db.clearProfileShowcaseUnverifiedTokenPreferences(tx)
if err != nil {
return err
}
for _, token := range preferences.UnverifiedTokens {
err = db.saveProfileShowcaseUnverifiedTokenPreference(tx, token)
if err != nil {
@ -669,10 +720,27 @@ func (db sqlitePersistence) SaveProfileShowcasePreferences(preferences *ProfileS
}
}
err = db.clearProfileShowcaseSocialLinkPreferences(tx)
if err != nil {
return err
}
for _, link := range preferences.SocialLinks {
err = db.saveProfileShowcaseSocialLinkPreference(tx, link)
if err != nil {
return err
}
}
err = db.saveProfileShowcasePreferencesClock(tx, preferences.Clock)
if err != nil {
return err
}
return nil
}
func (db sqlitePersistence) SaveProfileShowcaseAccountPreference(account *ProfileShowcaseAccountPreference) error {
func (db sqlitePersistence) SaveProfileShowcaseAccountPreference(account *identity.ProfileShowcaseAccountPreference) error {
tx, err := db.db.BeginTx(context.Background(), &sql.TxOptions{})
if err != nil {
return err
@ -688,7 +756,7 @@ func (db sqlitePersistence) SaveProfileShowcaseAccountPreference(account *Profil
return db.saveProfileShowcaseAccountPreference(tx, account)
}
func (db sqlitePersistence) GetProfileShowcasePreferences() (*ProfileShowcasePreferences, error) {
func (db sqlitePersistence) GetProfileShowcasePreferences() (*identity.ProfileShowcasePreferences, error) {
tx, err := db.db.BeginTx(context.Background(), &sql.TxOptions{})
if err != nil {
return nil, err
@ -702,6 +770,11 @@ func (db sqlitePersistence) GetProfileShowcasePreferences() (*ProfileShowcasePre
_ = tx.Rollback()
}()
clock, err := db.getProfileShowcasePreferencesClock(tx)
if err != nil {
return nil, err
}
communities, err := db.getProfileShowcaseCommunitiesPreferences(tx)
if err != nil {
return nil, err
@ -727,16 +800,23 @@ func (db sqlitePersistence) GetProfileShowcasePreferences() (*ProfileShowcasePre
return nil, err
}
return &ProfileShowcasePreferences{
socialLinks, err := db.getProfileShowcaseSocialLinkPreferences(tx)
if err != nil {
return nil, err
}
return &identity.ProfileShowcasePreferences{
Clock: clock,
Communities: communities,
Accounts: accounts,
Collectibles: collectibles,
VerifiedTokens: verifiedTokens,
UnverifiedTokens: unverifiedTokens,
SocialLinks: socialLinks,
}, nil
}
func (db sqlitePersistence) SaveProfileShowcaseForContact(showcase *ProfileShowcase) error {
func (db sqlitePersistence) SaveProfileShowcaseForContact(showcase *identity.ProfileShowcase) error {
tx, err := db.db.BeginTx(context.Background(), &sql.TxOptions{})
if err != nil {
return err
@ -785,10 +865,17 @@ func (db sqlitePersistence) SaveProfileShowcaseForContact(showcase *ProfileShowc
}
}
for _, link := range showcase.SocialLinks {
err = db.saveProfileShowcaseSocialLinkContact(tx, showcase.ContactID, link)
if err != nil {
return err
}
}
return nil
}
func (db sqlitePersistence) GetProfileShowcaseForContact(contactID string) (*ProfileShowcase, error) {
func (db sqlitePersistence) GetProfileShowcaseForContact(contactID string) (*identity.ProfileShowcase, error) {
tx, err := db.db.BeginTx(context.Background(), &sql.TxOptions{})
if err != nil {
return nil, err
@ -827,13 +914,19 @@ func (db sqlitePersistence) GetProfileShowcaseForContact(contactID string) (*Pro
return nil, err
}
return &ProfileShowcase{
socialLinks, err := db.getProfileShowcaseSocialLinksContact(tx, contactID)
if err != nil {
return nil, err
}
return &identity.ProfileShowcase{
ContactID: contactID,
Communities: communities,
Accounts: accounts,
Collectibles: collectibles,
VerifiedTokens: verifiedTokens,
UnverifiedTokens: unverifiedTokens,
SocialLinks: socialLinks,
}, nil
}
@ -876,5 +969,10 @@ func (db sqlitePersistence) ClearProfileShowcaseForContact(contactID string) err
return err
}
err = db.clearProfileShowcaseSocialLinksContact(tx, contactID)
if err != nil {
return err
}
return nil
}

View File

@ -1,28 +1,32 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.29.1
// protoc v3.20.3
// source: anon_metrics.proto
package protobuf
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
math "math"
reflect "reflect"
sync "sync"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// AnonymousMetric represents a single metric data point
type AnonymousMetric struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// id is the unique id of the metric message
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
// event is the app metric event type
@ -36,153 +40,243 @@ type AnonymousMetric struct {
// session_id is the id of the session the metric was recorded in
SessionId string `protobuf:"bytes,6,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"`
// created_at is the datetime at which the metric was stored in the local db
CreatedAt *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
CreatedAt *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"`
}
func (m *AnonymousMetric) Reset() { *m = AnonymousMetric{} }
func (m *AnonymousMetric) String() string { return proto.CompactTextString(m) }
func (*AnonymousMetric) ProtoMessage() {}
func (x *AnonymousMetric) Reset() {
*x = AnonymousMetric{}
if protoimpl.UnsafeEnabled {
mi := &file_anon_metrics_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AnonymousMetric) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AnonymousMetric) ProtoMessage() {}
func (x *AnonymousMetric) ProtoReflect() protoreflect.Message {
mi := &file_anon_metrics_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AnonymousMetric.ProtoReflect.Descriptor instead.
func (*AnonymousMetric) Descriptor() ([]byte, []int) {
return fileDescriptor_4be044a92fa0408c, []int{0}
return file_anon_metrics_proto_rawDescGZIP(), []int{0}
}
func (m *AnonymousMetric) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_AnonymousMetric.Unmarshal(m, b)
}
func (m *AnonymousMetric) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_AnonymousMetric.Marshal(b, m, deterministic)
}
func (m *AnonymousMetric) XXX_Merge(src proto.Message) {
xxx_messageInfo_AnonymousMetric.Merge(m, src)
}
func (m *AnonymousMetric) XXX_Size() int {
return xxx_messageInfo_AnonymousMetric.Size(m)
}
func (m *AnonymousMetric) XXX_DiscardUnknown() {
xxx_messageInfo_AnonymousMetric.DiscardUnknown(m)
}
var xxx_messageInfo_AnonymousMetric proto.InternalMessageInfo
func (m *AnonymousMetric) GetId() string {
if m != nil {
return m.Id
func (x *AnonymousMetric) GetId() string {
if x != nil {
return x.Id
}
return ""
}
func (m *AnonymousMetric) GetEvent() string {
if m != nil {
return m.Event
func (x *AnonymousMetric) GetEvent() string {
if x != nil {
return x.Event
}
return ""
}
func (m *AnonymousMetric) GetValue() []byte {
if m != nil {
return m.Value
func (x *AnonymousMetric) GetValue() []byte {
if x != nil {
return x.Value
}
return nil
}
func (m *AnonymousMetric) GetAppVersion() string {
if m != nil {
return m.AppVersion
func (x *AnonymousMetric) GetAppVersion() string {
if x != nil {
return x.AppVersion
}
return ""
}
func (m *AnonymousMetric) GetOs() string {
if m != nil {
return m.Os
func (x *AnonymousMetric) GetOs() string {
if x != nil {
return x.Os
}
return ""
}
func (m *AnonymousMetric) GetSessionId() string {
if m != nil {
return m.SessionId
func (x *AnonymousMetric) GetSessionId() string {
if x != nil {
return x.SessionId
}
return ""
}
func (m *AnonymousMetric) GetCreatedAt() *timestamppb.Timestamp {
if m != nil {
return m.CreatedAt
func (x *AnonymousMetric) GetCreatedAt() *timestamppb.Timestamp {
if x != nil {
return x.CreatedAt
}
return nil
}
// AnonymousMetricBatch represents a batch of AnonymousMetrics allowing broadcast of AnonymousMetrics with fewer messages
type AnonymousMetricBatch struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// metrics is an array of AnonymousMetric metrics
Metrics []*AnonymousMetric `protobuf:"bytes,1,rep,name=metrics,proto3" json:"metrics,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
Metrics []*AnonymousMetric `protobuf:"bytes,1,rep,name=metrics,proto3" json:"metrics,omitempty"`
}
func (m *AnonymousMetricBatch) Reset() { *m = AnonymousMetricBatch{} }
func (m *AnonymousMetricBatch) String() string { return proto.CompactTextString(m) }
func (*AnonymousMetricBatch) ProtoMessage() {}
func (x *AnonymousMetricBatch) Reset() {
*x = AnonymousMetricBatch{}
if protoimpl.UnsafeEnabled {
mi := &file_anon_metrics_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AnonymousMetricBatch) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AnonymousMetricBatch) ProtoMessage() {}
func (x *AnonymousMetricBatch) ProtoReflect() protoreflect.Message {
mi := &file_anon_metrics_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AnonymousMetricBatch.ProtoReflect.Descriptor instead.
func (*AnonymousMetricBatch) Descriptor() ([]byte, []int) {
return fileDescriptor_4be044a92fa0408c, []int{1}
return file_anon_metrics_proto_rawDescGZIP(), []int{1}
}
func (m *AnonymousMetricBatch) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_AnonymousMetricBatch.Unmarshal(m, b)
}
func (m *AnonymousMetricBatch) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_AnonymousMetricBatch.Marshal(b, m, deterministic)
}
func (m *AnonymousMetricBatch) XXX_Merge(src proto.Message) {
xxx_messageInfo_AnonymousMetricBatch.Merge(m, src)
}
func (m *AnonymousMetricBatch) XXX_Size() int {
return xxx_messageInfo_AnonymousMetricBatch.Size(m)
}
func (m *AnonymousMetricBatch) XXX_DiscardUnknown() {
xxx_messageInfo_AnonymousMetricBatch.DiscardUnknown(m)
}
var xxx_messageInfo_AnonymousMetricBatch proto.InternalMessageInfo
func (m *AnonymousMetricBatch) GetMetrics() []*AnonymousMetric {
if m != nil {
return m.Metrics
func (x *AnonymousMetricBatch) GetMetrics() []*AnonymousMetric {
if x != nil {
return x.Metrics
}
return nil
}
func init() {
proto.RegisterType((*AnonymousMetric)(nil), "protobuf.AnonymousMetric")
proto.RegisterType((*AnonymousMetricBatch)(nil), "protobuf.AnonymousMetricBatch")
var File_anon_metrics_proto protoreflect.FileDescriptor
var file_anon_metrics_proto_rawDesc = []byte{
0x0a, 0x12, 0x61, 0x6e, 0x6f, 0x6e, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x1a, 0x1f,
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f,
0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22,
0xd8, 0x01, 0x0a, 0x0f, 0x41, 0x6e, 0x6f, 0x6e, 0x79, 0x6d, 0x6f, 0x75, 0x73, 0x4d, 0x65, 0x74,
0x72, 0x69, 0x63, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01,
0x28, 0x09, 0x52, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c,
0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12,
0x1f, 0x0a, 0x0b, 0x61, 0x70, 0x70, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04,
0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x70, 0x70, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
0x12, 0x0e, 0x0a, 0x02, 0x6f, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x6f, 0x73,
0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x06,
0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12,
0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x07, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52,
0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0x4b, 0x0a, 0x14, 0x41, 0x6e,
0x6f, 0x6e, 0x79, 0x6d, 0x6f, 0x75, 0x73, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x42, 0x61, 0x74,
0x63, 0x68, 0x12, 0x33, 0x0a, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x18, 0x01, 0x20,
0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41,
0x6e, 0x6f, 0x6e, 0x79, 0x6d, 0x6f, 0x75, 0x73, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x52, 0x07,
0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x42, 0x0d, 0x5a, 0x0b, 0x2e, 0x2f, 0x3b, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
func init() {
proto.RegisterFile("anon_metrics.proto", fileDescriptor_4be044a92fa0408c)
var (
file_anon_metrics_proto_rawDescOnce sync.Once
file_anon_metrics_proto_rawDescData = file_anon_metrics_proto_rawDesc
)
func file_anon_metrics_proto_rawDescGZIP() []byte {
file_anon_metrics_proto_rawDescOnce.Do(func() {
file_anon_metrics_proto_rawDescData = protoimpl.X.CompressGZIP(file_anon_metrics_proto_rawDescData)
})
return file_anon_metrics_proto_rawDescData
}
var fileDescriptor_4be044a92fa0408c = []byte{
// 269 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x5c, 0x90, 0x3d, 0x6b, 0xc3, 0x30,
0x10, 0x86, 0x51, 0xd2, 0x24, 0xf5, 0xb9, 0x1f, 0x20, 0x32, 0xa8, 0x81, 0x12, 0x93, 0xc9, 0x93,
0x0d, 0xc9, 0x54, 0x3a, 0x25, 0x5b, 0x29, 0x5d, 0x4c, 0xe9, 0xd0, 0xc5, 0x28, 0xb6, 0x9a, 0x0a,
0x62, 0x9d, 0xb0, 0x64, 0x43, 0xff, 0x69, 0x7f, 0x4e, 0xb1, 0x64, 0x51, 0xc8, 0x24, 0xdd, 0xa3,
0xf7, 0x5e, 0x78, 0x04, 0x94, 0x2b, 0x54, 0x65, 0x23, 0x6c, 0x2b, 0x2b, 0x93, 0xe9, 0x16, 0x2d,
0xd2, 0x6b, 0x77, 0x1c, 0xbb, 0xaf, 0xd5, 0xfa, 0x84, 0x78, 0x3a, 0x8b, 0x3c, 0x80, 0xdc, 0xca,
0x46, 0x18, 0xcb, 0x1b, 0xed, 0xa3, 0x9b, 0x5f, 0x02, 0xf7, 0x7b, 0x85, 0xea, 0xa7, 0xc1, 0xce,
0xbc, 0xb9, 0x16, 0x7a, 0x07, 0x13, 0x59, 0x33, 0x92, 0x90, 0x34, 0x2a, 0x26, 0xb2, 0xa6, 0x4b,
0x98, 0x89, 0x5e, 0x28, 0xcb, 0x26, 0x0e, 0xf9, 0x61, 0xa0, 0x3d, 0x3f, 0x77, 0x82, 0x4d, 0x13,
0x92, 0xde, 0x14, 0x7e, 0xa0, 0x6b, 0x88, 0xb9, 0xd6, 0x65, 0x2f, 0x5a, 0x23, 0x51, 0xb1, 0x2b,
0xb7, 0x01, 0x5c, 0xeb, 0x0f, 0x4f, 0x86, 0x72, 0x34, 0x6c, 0xe6, 0xcb, 0xd1, 0xd0, 0x47, 0x00,
0x23, 0xcc, 0xf0, 0x54, 0xca, 0x9a, 0xcd, 0x1d, 0x8f, 0x46, 0xf2, 0x52, 0xd3, 0x27, 0x80, 0xaa,
0x15, 0xdc, 0x8a, 0xba, 0xe4, 0x96, 0x2d, 0x12, 0x92, 0xc6, 0xdb, 0x55, 0xe6, 0xad, 0xb2, 0x60,
0x95, 0xbd, 0x07, 0xab, 0x22, 0x1a, 0xd3, 0x7b, 0xbb, 0x79, 0x85, 0xe5, 0x85, 0xd9, 0x81, 0xdb,
0xea, 0x9b, 0xee, 0x60, 0x31, 0x7e, 0x17, 0x23, 0xc9, 0x34, 0x8d, 0xb7, 0x0f, 0xff, 0x45, 0x17,
0x0b, 0x45, 0x48, 0x1e, 0x6e, 0x3f, 0xe3, 0x2c, 0x7f, 0x0e, 0xb9, 0xe3, 0xdc, 0xdd, 0x76, 0x7f,
0x01, 0x00, 0x00, 0xff, 0xff, 0xc7, 0x86, 0xa1, 0x32, 0x7e, 0x01, 0x00, 0x00,
var file_anon_metrics_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_anon_metrics_proto_goTypes = []interface{}{
(*AnonymousMetric)(nil), // 0: protobuf.AnonymousMetric
(*AnonymousMetricBatch)(nil), // 1: protobuf.AnonymousMetricBatch
(*timestamppb.Timestamp)(nil), // 2: google.protobuf.Timestamp
}
var file_anon_metrics_proto_depIdxs = []int32{
2, // 0: protobuf.AnonymousMetric.created_at:type_name -> google.protobuf.Timestamp
0, // 1: protobuf.AnonymousMetricBatch.metrics:type_name -> protobuf.AnonymousMetric
2, // [2:2] is the sub-list for method output_type
2, // [2:2] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
}
func init() { file_anon_metrics_proto_init() }
func file_anon_metrics_proto_init() {
if File_anon_metrics_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_anon_metrics_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*AnonymousMetric); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_anon_metrics_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*AnonymousMetricBatch); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_anon_metrics_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_anon_metrics_proto_goTypes,
DependencyIndexes: file_anon_metrics_proto_depIdxs,
MessageInfos: file_anon_metrics_proto_msgTypes,
}.Build()
File_anon_metrics_proto = out.File
file_anon_metrics_proto_rawDesc = nil
file_anon_metrics_proto_goTypes = nil
file_anon_metrics_proto_depIdxs = nil
}

View File

@ -1,54 +1,56 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.29.1
// protoc v3.20.3
// source: application_metadata_message.proto
package protobuf
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
math "math"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type ApplicationMetadataMessage_Type int32
const (
ApplicationMetadataMessage_UNKNOWN ApplicationMetadataMessage_Type = 0
ApplicationMetadataMessage_CHAT_MESSAGE ApplicationMetadataMessage_Type = 1
ApplicationMetadataMessage_CONTACT_UPDATE ApplicationMetadataMessage_Type = 2
ApplicationMetadataMessage_MEMBERSHIP_UPDATE_MESSAGE ApplicationMetadataMessage_Type = 3
ApplicationMetadataMessage_SYNC_PAIR_INSTALLATION ApplicationMetadataMessage_Type = 4
ApplicationMetadataMessage_DEPRECATED_SYNC_INSTALLATION ApplicationMetadataMessage_Type = 5 // Deprecated: Do not use.
ApplicationMetadataMessage_REQUEST_ADDRESS_FOR_TRANSACTION ApplicationMetadataMessage_Type = 6
ApplicationMetadataMessage_ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION ApplicationMetadataMessage_Type = 7
ApplicationMetadataMessage_DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION ApplicationMetadataMessage_Type = 8
ApplicationMetadataMessage_REQUEST_TRANSACTION ApplicationMetadataMessage_Type = 9
ApplicationMetadataMessage_SEND_TRANSACTION ApplicationMetadataMessage_Type = 10
ApplicationMetadataMessage_DECLINE_REQUEST_TRANSACTION ApplicationMetadataMessage_Type = 11
ApplicationMetadataMessage_SYNC_INSTALLATION_CONTACT_V2 ApplicationMetadataMessage_Type = 12
ApplicationMetadataMessage_SYNC_INSTALLATION_ACCOUNT ApplicationMetadataMessage_Type = 13
ApplicationMetadataMessage_CONTACT_CODE_ADVERTISEMENT ApplicationMetadataMessage_Type = 15
ApplicationMetadataMessage_PUSH_NOTIFICATION_REGISTRATION ApplicationMetadataMessage_Type = 16
ApplicationMetadataMessage_PUSH_NOTIFICATION_REGISTRATION_RESPONSE ApplicationMetadataMessage_Type = 17
ApplicationMetadataMessage_PUSH_NOTIFICATION_QUERY ApplicationMetadataMessage_Type = 18
ApplicationMetadataMessage_PUSH_NOTIFICATION_QUERY_RESPONSE ApplicationMetadataMessage_Type = 19
ApplicationMetadataMessage_PUSH_NOTIFICATION_REQUEST ApplicationMetadataMessage_Type = 20
ApplicationMetadataMessage_PUSH_NOTIFICATION_RESPONSE ApplicationMetadataMessage_Type = 21
ApplicationMetadataMessage_EMOJI_REACTION ApplicationMetadataMessage_Type = 22
ApplicationMetadataMessage_GROUP_CHAT_INVITATION ApplicationMetadataMessage_Type = 23
ApplicationMetadataMessage_CHAT_IDENTITY ApplicationMetadataMessage_Type = 24
ApplicationMetadataMessage_COMMUNITY_DESCRIPTION ApplicationMetadataMessage_Type = 25
ApplicationMetadataMessage_COMMUNITY_INVITATION ApplicationMetadataMessage_Type = 26 // Deprecated: Do not use.
ApplicationMetadataMessage_UNKNOWN ApplicationMetadataMessage_Type = 0
ApplicationMetadataMessage_CHAT_MESSAGE ApplicationMetadataMessage_Type = 1
ApplicationMetadataMessage_CONTACT_UPDATE ApplicationMetadataMessage_Type = 2
ApplicationMetadataMessage_MEMBERSHIP_UPDATE_MESSAGE ApplicationMetadataMessage_Type = 3
ApplicationMetadataMessage_SYNC_PAIR_INSTALLATION ApplicationMetadataMessage_Type = 4
// Deprecated: Marked as deprecated in application_metadata_message.proto.
ApplicationMetadataMessage_DEPRECATED_SYNC_INSTALLATION ApplicationMetadataMessage_Type = 5
ApplicationMetadataMessage_REQUEST_ADDRESS_FOR_TRANSACTION ApplicationMetadataMessage_Type = 6
ApplicationMetadataMessage_ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION ApplicationMetadataMessage_Type = 7
ApplicationMetadataMessage_DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION ApplicationMetadataMessage_Type = 8
ApplicationMetadataMessage_REQUEST_TRANSACTION ApplicationMetadataMessage_Type = 9
ApplicationMetadataMessage_SEND_TRANSACTION ApplicationMetadataMessage_Type = 10
ApplicationMetadataMessage_DECLINE_REQUEST_TRANSACTION ApplicationMetadataMessage_Type = 11
ApplicationMetadataMessage_SYNC_INSTALLATION_CONTACT_V2 ApplicationMetadataMessage_Type = 12
ApplicationMetadataMessage_SYNC_INSTALLATION_ACCOUNT ApplicationMetadataMessage_Type = 13
ApplicationMetadataMessage_CONTACT_CODE_ADVERTISEMENT ApplicationMetadataMessage_Type = 15
ApplicationMetadataMessage_PUSH_NOTIFICATION_REGISTRATION ApplicationMetadataMessage_Type = 16
ApplicationMetadataMessage_PUSH_NOTIFICATION_REGISTRATION_RESPONSE ApplicationMetadataMessage_Type = 17
ApplicationMetadataMessage_PUSH_NOTIFICATION_QUERY ApplicationMetadataMessage_Type = 18
ApplicationMetadataMessage_PUSH_NOTIFICATION_QUERY_RESPONSE ApplicationMetadataMessage_Type = 19
ApplicationMetadataMessage_PUSH_NOTIFICATION_REQUEST ApplicationMetadataMessage_Type = 20
ApplicationMetadataMessage_PUSH_NOTIFICATION_RESPONSE ApplicationMetadataMessage_Type = 21
ApplicationMetadataMessage_EMOJI_REACTION ApplicationMetadataMessage_Type = 22
ApplicationMetadataMessage_GROUP_CHAT_INVITATION ApplicationMetadataMessage_Type = 23
ApplicationMetadataMessage_CHAT_IDENTITY ApplicationMetadataMessage_Type = 24
ApplicationMetadataMessage_COMMUNITY_DESCRIPTION ApplicationMetadataMessage_Type = 25
// Deprecated: Marked as deprecated in application_metadata_message.proto.
ApplicationMetadataMessage_COMMUNITY_INVITATION ApplicationMetadataMessage_Type = 26
ApplicationMetadataMessage_COMMUNITY_REQUEST_TO_JOIN ApplicationMetadataMessage_Type = 27
ApplicationMetadataMessage_PIN_MESSAGE ApplicationMetadataMessage_Type = 28
ApplicationMetadataMessage_EDIT_MESSAGE ApplicationMetadataMessage_Type = 29
@ -101,319 +103,522 @@ const (
ApplicationMetadataMessage_COMMUNITY_PUBLIC_SHARD_INFO ApplicationMetadataMessage_Type = 79
ApplicationMetadataMessage_SYNC_COLLECTIBLE_PREFERENCES ApplicationMetadataMessage_Type = 80
ApplicationMetadataMessage_COMMUNITY_USER_KICKED ApplicationMetadataMessage_Type = 81
ApplicationMetadataMessage_SYNC_PROFILE_SHOWCASE_PREFERENCES ApplicationMetadataMessage_Type = 82
ApplicationMetadataMessage_COMMUNITY_PUBLIC_STORENODES_INFO ApplicationMetadataMessage_Type = 83
ApplicationMetadataMessage_COMMUNITY_REEVALUATE_PERMISSIONS_REQUEST ApplicationMetadataMessage_Type = 84
ApplicationMetadataMessage_DELETE_COMMUNITY_MEMBER_MESSAGES ApplicationMetadataMessage_Type = 85
)
var ApplicationMetadataMessage_Type_name = map[int32]string{
0: "UNKNOWN",
1: "CHAT_MESSAGE",
2: "CONTACT_UPDATE",
3: "MEMBERSHIP_UPDATE_MESSAGE",
4: "SYNC_PAIR_INSTALLATION",
5: "DEPRECATED_SYNC_INSTALLATION",
6: "REQUEST_ADDRESS_FOR_TRANSACTION",
7: "ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION",
8: "DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION",
9: "REQUEST_TRANSACTION",
10: "SEND_TRANSACTION",
11: "DECLINE_REQUEST_TRANSACTION",
12: "SYNC_INSTALLATION_CONTACT_V2",
13: "SYNC_INSTALLATION_ACCOUNT",
15: "CONTACT_CODE_ADVERTISEMENT",
16: "PUSH_NOTIFICATION_REGISTRATION",
17: "PUSH_NOTIFICATION_REGISTRATION_RESPONSE",
18: "PUSH_NOTIFICATION_QUERY",
19: "PUSH_NOTIFICATION_QUERY_RESPONSE",
20: "PUSH_NOTIFICATION_REQUEST",
21: "PUSH_NOTIFICATION_RESPONSE",
22: "EMOJI_REACTION",
23: "GROUP_CHAT_INVITATION",
24: "CHAT_IDENTITY",
25: "COMMUNITY_DESCRIPTION",
26: "COMMUNITY_INVITATION",
27: "COMMUNITY_REQUEST_TO_JOIN",
28: "PIN_MESSAGE",
29: "EDIT_MESSAGE",
30: "STATUS_UPDATE",
31: "DELETE_MESSAGE",
32: "SYNC_INSTALLATION_COMMUNITY",
33: "ANONYMOUS_METRIC_BATCH",
34: "SYNC_CHAT_REMOVED",
35: "SYNC_CHAT_MESSAGES_READ",
36: "BACKUP",
37: "SYNC_ACTIVITY_CENTER_READ",
38: "SYNC_ACTIVITY_CENTER_ACCEPTED",
39: "SYNC_ACTIVITY_CENTER_DISMISSED",
40: "SYNC_BOOKMARK",
41: "SYNC_CLEAR_HISTORY",
42: "SYNC_SETTING",
43: "COMMUNITY_MESSAGE_ARCHIVE_MAGNETLINK",
44: "SYNC_PROFILE_PICTURES",
45: "SYNC_ACCOUNT",
46: "ACCEPT_CONTACT_REQUEST",
47: "RETRACT_CONTACT_REQUEST",
48: "COMMUNITY_REQUEST_TO_JOIN_RESPONSE",
49: "SYNC_COMMUNITY_SETTINGS",
50: "REQUEST_CONTACT_VERIFICATION",
51: "ACCEPT_CONTACT_VERIFICATION",
52: "DECLINE_CONTACT_VERIFICATION",
53: "SYNC_TRUSTED_USER",
54: "SYNC_VERIFICATION_REQUEST",
56: "SYNC_CONTACT_REQUEST_DECISION",
57: "COMMUNITY_REQUEST_TO_LEAVE",
58: "SYNC_DELETE_FOR_ME_MESSAGE",
59: "SYNC_SAVED_ADDRESS",
60: "COMMUNITY_CANCEL_REQUEST_TO_JOIN",
61: "CANCEL_CONTACT_VERIFICATION",
62: "SYNC_KEYPAIR",
63: "SYNC_SOCIAL_LINKS",
64: "SYNC_ENS_USERNAME_DETAIL",
67: "COMMUNITY_EVENTS_MESSAGE",
68: "COMMUNITY_EDIT_SHARED_ADDRESSES",
69: "SYNC_ACCOUNT_CUSTOMIZATION_COLOR",
70: "SYNC_ACCOUNTS_POSITIONS",
71: "COMMUNITY_EVENTS_MESSAGE_REJECTED",
72: "COMMUNITY_PRIVILEGED_USER_SYNC_MESSAGE",
73: "COMMUNITY_SHARD_KEY",
74: "SYNC_CHAT",
75: "SYNC_ACTIVITY_CENTER_DELETED",
76: "SYNC_ACTIVITY_CENTER_UNREAD",
77: "SYNC_ACTIVITY_CENTER_COMMUNITY_REQUEST_DECISION",
78: "SYNC_TOKEN_PREFERENCES",
79: "COMMUNITY_PUBLIC_SHARD_INFO",
80: "SYNC_COLLECTIBLE_PREFERENCES",
81: "COMMUNITY_USER_KICKED",
}
// Enum value maps for ApplicationMetadataMessage_Type.
var (
ApplicationMetadataMessage_Type_name = map[int32]string{
0: "UNKNOWN",
1: "CHAT_MESSAGE",
2: "CONTACT_UPDATE",
3: "MEMBERSHIP_UPDATE_MESSAGE",
4: "SYNC_PAIR_INSTALLATION",
5: "DEPRECATED_SYNC_INSTALLATION",
6: "REQUEST_ADDRESS_FOR_TRANSACTION",
7: "ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION",
8: "DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION",
9: "REQUEST_TRANSACTION",
10: "SEND_TRANSACTION",
11: "DECLINE_REQUEST_TRANSACTION",
12: "SYNC_INSTALLATION_CONTACT_V2",
13: "SYNC_INSTALLATION_ACCOUNT",
15: "CONTACT_CODE_ADVERTISEMENT",
16: "PUSH_NOTIFICATION_REGISTRATION",
17: "PUSH_NOTIFICATION_REGISTRATION_RESPONSE",
18: "PUSH_NOTIFICATION_QUERY",
19: "PUSH_NOTIFICATION_QUERY_RESPONSE",
20: "PUSH_NOTIFICATION_REQUEST",
21: "PUSH_NOTIFICATION_RESPONSE",
22: "EMOJI_REACTION",
23: "GROUP_CHAT_INVITATION",
24: "CHAT_IDENTITY",
25: "COMMUNITY_DESCRIPTION",
26: "COMMUNITY_INVITATION",
27: "COMMUNITY_REQUEST_TO_JOIN",
28: "PIN_MESSAGE",
29: "EDIT_MESSAGE",
30: "STATUS_UPDATE",
31: "DELETE_MESSAGE",
32: "SYNC_INSTALLATION_COMMUNITY",
33: "ANONYMOUS_METRIC_BATCH",
34: "SYNC_CHAT_REMOVED",
35: "SYNC_CHAT_MESSAGES_READ",
36: "BACKUP",
37: "SYNC_ACTIVITY_CENTER_READ",
38: "SYNC_ACTIVITY_CENTER_ACCEPTED",
39: "SYNC_ACTIVITY_CENTER_DISMISSED",
40: "SYNC_BOOKMARK",
41: "SYNC_CLEAR_HISTORY",
42: "SYNC_SETTING",
43: "COMMUNITY_MESSAGE_ARCHIVE_MAGNETLINK",
44: "SYNC_PROFILE_PICTURES",
45: "SYNC_ACCOUNT",
46: "ACCEPT_CONTACT_REQUEST",
47: "RETRACT_CONTACT_REQUEST",
48: "COMMUNITY_REQUEST_TO_JOIN_RESPONSE",
49: "SYNC_COMMUNITY_SETTINGS",
50: "REQUEST_CONTACT_VERIFICATION",
51: "ACCEPT_CONTACT_VERIFICATION",
52: "DECLINE_CONTACT_VERIFICATION",
53: "SYNC_TRUSTED_USER",
54: "SYNC_VERIFICATION_REQUEST",
56: "SYNC_CONTACT_REQUEST_DECISION",
57: "COMMUNITY_REQUEST_TO_LEAVE",
58: "SYNC_DELETE_FOR_ME_MESSAGE",
59: "SYNC_SAVED_ADDRESS",
60: "COMMUNITY_CANCEL_REQUEST_TO_JOIN",
61: "CANCEL_CONTACT_VERIFICATION",
62: "SYNC_KEYPAIR",
63: "SYNC_SOCIAL_LINKS",
64: "SYNC_ENS_USERNAME_DETAIL",
67: "COMMUNITY_EVENTS_MESSAGE",
68: "COMMUNITY_EDIT_SHARED_ADDRESSES",
69: "SYNC_ACCOUNT_CUSTOMIZATION_COLOR",
70: "SYNC_ACCOUNTS_POSITIONS",
71: "COMMUNITY_EVENTS_MESSAGE_REJECTED",
72: "COMMUNITY_PRIVILEGED_USER_SYNC_MESSAGE",
73: "COMMUNITY_SHARD_KEY",
74: "SYNC_CHAT",
75: "SYNC_ACTIVITY_CENTER_DELETED",
76: "SYNC_ACTIVITY_CENTER_UNREAD",
77: "SYNC_ACTIVITY_CENTER_COMMUNITY_REQUEST_DECISION",
78: "SYNC_TOKEN_PREFERENCES",
79: "COMMUNITY_PUBLIC_SHARD_INFO",
80: "SYNC_COLLECTIBLE_PREFERENCES",
81: "COMMUNITY_USER_KICKED",
82: "SYNC_PROFILE_SHOWCASE_PREFERENCES",
83: "COMMUNITY_PUBLIC_STORENODES_INFO",
84: "COMMUNITY_REEVALUATE_PERMISSIONS_REQUEST",
85: "DELETE_COMMUNITY_MEMBER_MESSAGES",
}
ApplicationMetadataMessage_Type_value = map[string]int32{
"UNKNOWN": 0,
"CHAT_MESSAGE": 1,
"CONTACT_UPDATE": 2,
"MEMBERSHIP_UPDATE_MESSAGE": 3,
"SYNC_PAIR_INSTALLATION": 4,
"DEPRECATED_SYNC_INSTALLATION": 5,
"REQUEST_ADDRESS_FOR_TRANSACTION": 6,
"ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION": 7,
"DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION": 8,
"REQUEST_TRANSACTION": 9,
"SEND_TRANSACTION": 10,
"DECLINE_REQUEST_TRANSACTION": 11,
"SYNC_INSTALLATION_CONTACT_V2": 12,
"SYNC_INSTALLATION_ACCOUNT": 13,
"CONTACT_CODE_ADVERTISEMENT": 15,
"PUSH_NOTIFICATION_REGISTRATION": 16,
"PUSH_NOTIFICATION_REGISTRATION_RESPONSE": 17,
"PUSH_NOTIFICATION_QUERY": 18,
"PUSH_NOTIFICATION_QUERY_RESPONSE": 19,
"PUSH_NOTIFICATION_REQUEST": 20,
"PUSH_NOTIFICATION_RESPONSE": 21,
"EMOJI_REACTION": 22,
"GROUP_CHAT_INVITATION": 23,
"CHAT_IDENTITY": 24,
"COMMUNITY_DESCRIPTION": 25,
"COMMUNITY_INVITATION": 26,
"COMMUNITY_REQUEST_TO_JOIN": 27,
"PIN_MESSAGE": 28,
"EDIT_MESSAGE": 29,
"STATUS_UPDATE": 30,
"DELETE_MESSAGE": 31,
"SYNC_INSTALLATION_COMMUNITY": 32,
"ANONYMOUS_METRIC_BATCH": 33,
"SYNC_CHAT_REMOVED": 34,
"SYNC_CHAT_MESSAGES_READ": 35,
"BACKUP": 36,
"SYNC_ACTIVITY_CENTER_READ": 37,
"SYNC_ACTIVITY_CENTER_ACCEPTED": 38,
"SYNC_ACTIVITY_CENTER_DISMISSED": 39,
"SYNC_BOOKMARK": 40,
"SYNC_CLEAR_HISTORY": 41,
"SYNC_SETTING": 42,
"COMMUNITY_MESSAGE_ARCHIVE_MAGNETLINK": 43,
"SYNC_PROFILE_PICTURES": 44,
"SYNC_ACCOUNT": 45,
"ACCEPT_CONTACT_REQUEST": 46,
"RETRACT_CONTACT_REQUEST": 47,
"COMMUNITY_REQUEST_TO_JOIN_RESPONSE": 48,
"SYNC_COMMUNITY_SETTINGS": 49,
"REQUEST_CONTACT_VERIFICATION": 50,
"ACCEPT_CONTACT_VERIFICATION": 51,
"DECLINE_CONTACT_VERIFICATION": 52,
"SYNC_TRUSTED_USER": 53,
"SYNC_VERIFICATION_REQUEST": 54,
"SYNC_CONTACT_REQUEST_DECISION": 56,
"COMMUNITY_REQUEST_TO_LEAVE": 57,
"SYNC_DELETE_FOR_ME_MESSAGE": 58,
"SYNC_SAVED_ADDRESS": 59,
"COMMUNITY_CANCEL_REQUEST_TO_JOIN": 60,
"CANCEL_CONTACT_VERIFICATION": 61,
"SYNC_KEYPAIR": 62,
"SYNC_SOCIAL_LINKS": 63,
"SYNC_ENS_USERNAME_DETAIL": 64,
"COMMUNITY_EVENTS_MESSAGE": 67,
"COMMUNITY_EDIT_SHARED_ADDRESSES": 68,
"SYNC_ACCOUNT_CUSTOMIZATION_COLOR": 69,
"SYNC_ACCOUNTS_POSITIONS": 70,
"COMMUNITY_EVENTS_MESSAGE_REJECTED": 71,
"COMMUNITY_PRIVILEGED_USER_SYNC_MESSAGE": 72,
"COMMUNITY_SHARD_KEY": 73,
"SYNC_CHAT": 74,
"SYNC_ACTIVITY_CENTER_DELETED": 75,
"SYNC_ACTIVITY_CENTER_UNREAD": 76,
"SYNC_ACTIVITY_CENTER_COMMUNITY_REQUEST_DECISION": 77,
"SYNC_TOKEN_PREFERENCES": 78,
"COMMUNITY_PUBLIC_SHARD_INFO": 79,
"SYNC_COLLECTIBLE_PREFERENCES": 80,
"COMMUNITY_USER_KICKED": 81,
"SYNC_PROFILE_SHOWCASE_PREFERENCES": 82,
"COMMUNITY_PUBLIC_STORENODES_INFO": 83,
"COMMUNITY_REEVALUATE_PERMISSIONS_REQUEST": 84,
"DELETE_COMMUNITY_MEMBER_MESSAGES": 85,
}
)
var ApplicationMetadataMessage_Type_value = map[string]int32{
"UNKNOWN": 0,
"CHAT_MESSAGE": 1,
"CONTACT_UPDATE": 2,
"MEMBERSHIP_UPDATE_MESSAGE": 3,
"SYNC_PAIR_INSTALLATION": 4,
"DEPRECATED_SYNC_INSTALLATION": 5,
"REQUEST_ADDRESS_FOR_TRANSACTION": 6,
"ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION": 7,
"DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION": 8,
"REQUEST_TRANSACTION": 9,
"SEND_TRANSACTION": 10,
"DECLINE_REQUEST_TRANSACTION": 11,
"SYNC_INSTALLATION_CONTACT_V2": 12,
"SYNC_INSTALLATION_ACCOUNT": 13,
"CONTACT_CODE_ADVERTISEMENT": 15,
"PUSH_NOTIFICATION_REGISTRATION": 16,
"PUSH_NOTIFICATION_REGISTRATION_RESPONSE": 17,
"PUSH_NOTIFICATION_QUERY": 18,
"PUSH_NOTIFICATION_QUERY_RESPONSE": 19,
"PUSH_NOTIFICATION_REQUEST": 20,
"PUSH_NOTIFICATION_RESPONSE": 21,
"EMOJI_REACTION": 22,
"GROUP_CHAT_INVITATION": 23,
"CHAT_IDENTITY": 24,
"COMMUNITY_DESCRIPTION": 25,
"COMMUNITY_INVITATION": 26,
"COMMUNITY_REQUEST_TO_JOIN": 27,
"PIN_MESSAGE": 28,
"EDIT_MESSAGE": 29,
"STATUS_UPDATE": 30,
"DELETE_MESSAGE": 31,
"SYNC_INSTALLATION_COMMUNITY": 32,
"ANONYMOUS_METRIC_BATCH": 33,
"SYNC_CHAT_REMOVED": 34,
"SYNC_CHAT_MESSAGES_READ": 35,
"BACKUP": 36,
"SYNC_ACTIVITY_CENTER_READ": 37,
"SYNC_ACTIVITY_CENTER_ACCEPTED": 38,
"SYNC_ACTIVITY_CENTER_DISMISSED": 39,
"SYNC_BOOKMARK": 40,
"SYNC_CLEAR_HISTORY": 41,
"SYNC_SETTING": 42,
"COMMUNITY_MESSAGE_ARCHIVE_MAGNETLINK": 43,
"SYNC_PROFILE_PICTURES": 44,
"SYNC_ACCOUNT": 45,
"ACCEPT_CONTACT_REQUEST": 46,
"RETRACT_CONTACT_REQUEST": 47,
"COMMUNITY_REQUEST_TO_JOIN_RESPONSE": 48,
"SYNC_COMMUNITY_SETTINGS": 49,
"REQUEST_CONTACT_VERIFICATION": 50,
"ACCEPT_CONTACT_VERIFICATION": 51,
"DECLINE_CONTACT_VERIFICATION": 52,
"SYNC_TRUSTED_USER": 53,
"SYNC_VERIFICATION_REQUEST": 54,
"SYNC_CONTACT_REQUEST_DECISION": 56,
"COMMUNITY_REQUEST_TO_LEAVE": 57,
"SYNC_DELETE_FOR_ME_MESSAGE": 58,
"SYNC_SAVED_ADDRESS": 59,
"COMMUNITY_CANCEL_REQUEST_TO_JOIN": 60,
"CANCEL_CONTACT_VERIFICATION": 61,
"SYNC_KEYPAIR": 62,
"SYNC_SOCIAL_LINKS": 63,
"SYNC_ENS_USERNAME_DETAIL": 64,
"COMMUNITY_EVENTS_MESSAGE": 67,
"COMMUNITY_EDIT_SHARED_ADDRESSES": 68,
"SYNC_ACCOUNT_CUSTOMIZATION_COLOR": 69,
"SYNC_ACCOUNTS_POSITIONS": 70,
"COMMUNITY_EVENTS_MESSAGE_REJECTED": 71,
"COMMUNITY_PRIVILEGED_USER_SYNC_MESSAGE": 72,
"COMMUNITY_SHARD_KEY": 73,
"SYNC_CHAT": 74,
"SYNC_ACTIVITY_CENTER_DELETED": 75,
"SYNC_ACTIVITY_CENTER_UNREAD": 76,
"SYNC_ACTIVITY_CENTER_COMMUNITY_REQUEST_DECISION": 77,
"SYNC_TOKEN_PREFERENCES": 78,
"COMMUNITY_PUBLIC_SHARD_INFO": 79,
"SYNC_COLLECTIBLE_PREFERENCES": 80,
"COMMUNITY_USER_KICKED": 81,
func (x ApplicationMetadataMessage_Type) Enum() *ApplicationMetadataMessage_Type {
p := new(ApplicationMetadataMessage_Type)
*p = x
return p
}
func (x ApplicationMetadataMessage_Type) String() string {
return proto.EnumName(ApplicationMetadataMessage_Type_name, int32(x))
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (ApplicationMetadataMessage_Type) Descriptor() protoreflect.EnumDescriptor {
return file_application_metadata_message_proto_enumTypes[0].Descriptor()
}
func (ApplicationMetadataMessage_Type) Type() protoreflect.EnumType {
return &file_application_metadata_message_proto_enumTypes[0]
}
func (x ApplicationMetadataMessage_Type) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use ApplicationMetadataMessage_Type.Descriptor instead.
func (ApplicationMetadataMessage_Type) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_ad09a6406fcf24c7, []int{0, 0}
return file_application_metadata_message_proto_rawDescGZIP(), []int{0, 0}
}
type ApplicationMetadataMessage struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Signature of the payload field
Signature []byte `protobuf:"bytes,1,opt,name=signature,proto3" json:"signature,omitempty"`
// This is the encoded protobuf of the application level message, i.e ChatMessage
Payload []byte `protobuf:"bytes,2,opt,name=payload,proto3" json:"payload,omitempty"`
// The type of protobuf message sent
Type ApplicationMetadataMessage_Type `protobuf:"varint,3,opt,name=type,proto3,enum=protobuf.ApplicationMetadataMessage_Type" json:"type,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
Type ApplicationMetadataMessage_Type `protobuf:"varint,3,opt,name=type,proto3,enum=protobuf.ApplicationMetadataMessage_Type" json:"type,omitempty"`
}
func (m *ApplicationMetadataMessage) Reset() { *m = ApplicationMetadataMessage{} }
func (m *ApplicationMetadataMessage) String() string { return proto.CompactTextString(m) }
func (*ApplicationMetadataMessage) ProtoMessage() {}
func (x *ApplicationMetadataMessage) Reset() {
*x = ApplicationMetadataMessage{}
if protoimpl.UnsafeEnabled {
mi := &file_application_metadata_message_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ApplicationMetadataMessage) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ApplicationMetadataMessage) ProtoMessage() {}
func (x *ApplicationMetadataMessage) ProtoReflect() protoreflect.Message {
mi := &file_application_metadata_message_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ApplicationMetadataMessage.ProtoReflect.Descriptor instead.
func (*ApplicationMetadataMessage) Descriptor() ([]byte, []int) {
return fileDescriptor_ad09a6406fcf24c7, []int{0}
return file_application_metadata_message_proto_rawDescGZIP(), []int{0}
}
func (m *ApplicationMetadataMessage) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ApplicationMetadataMessage.Unmarshal(m, b)
}
func (m *ApplicationMetadataMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ApplicationMetadataMessage.Marshal(b, m, deterministic)
}
func (m *ApplicationMetadataMessage) XXX_Merge(src proto.Message) {
xxx_messageInfo_ApplicationMetadataMessage.Merge(m, src)
}
func (m *ApplicationMetadataMessage) XXX_Size() int {
return xxx_messageInfo_ApplicationMetadataMessage.Size(m)
}
func (m *ApplicationMetadataMessage) XXX_DiscardUnknown() {
xxx_messageInfo_ApplicationMetadataMessage.DiscardUnknown(m)
}
var xxx_messageInfo_ApplicationMetadataMessage proto.InternalMessageInfo
func (m *ApplicationMetadataMessage) GetSignature() []byte {
if m != nil {
return m.Signature
func (x *ApplicationMetadataMessage) GetSignature() []byte {
if x != nil {
return x.Signature
}
return nil
}
func (m *ApplicationMetadataMessage) GetPayload() []byte {
if m != nil {
return m.Payload
func (x *ApplicationMetadataMessage) GetPayload() []byte {
if x != nil {
return x.Payload
}
return nil
}
func (m *ApplicationMetadataMessage) GetType() ApplicationMetadataMessage_Type {
if m != nil {
return m.Type
func (x *ApplicationMetadataMessage) GetType() ApplicationMetadataMessage_Type {
if x != nil {
return x.Type
}
return ApplicationMetadataMessage_UNKNOWN
}
func init() {
proto.RegisterEnum("protobuf.ApplicationMetadataMessage_Type", ApplicationMetadataMessage_Type_name, ApplicationMetadataMessage_Type_value)
proto.RegisterType((*ApplicationMetadataMessage)(nil), "protobuf.ApplicationMetadataMessage")
var File_application_metadata_message_proto protoreflect.FileDescriptor
var file_application_metadata_message_proto_rawDesc = []byte{
0x0a, 0x22, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x65,
0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x22, 0xc1,
0x15, 0x0a, 0x1a, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65,
0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a,
0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c,
0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70,
0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61,
0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x3d, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20,
0x01, 0x28, 0x0e, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41,
0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61,
0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04,
0x74, 0x79, 0x70, 0x65, 0x22, 0xab, 0x14, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a,
0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, 0x43, 0x48,
0x41, 0x54, 0x5f, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x10, 0x01, 0x12, 0x12, 0x0a, 0x0e,
0x43, 0x4f, 0x4e, 0x54, 0x41, 0x43, 0x54, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x02,
0x12, 0x1d, 0x0a, 0x19, 0x4d, 0x45, 0x4d, 0x42, 0x45, 0x52, 0x53, 0x48, 0x49, 0x50, 0x5f, 0x55,
0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x10, 0x03, 0x12,
0x1a, 0x0a, 0x16, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x50, 0x41, 0x49, 0x52, 0x5f, 0x49, 0x4e, 0x53,
0x54, 0x41, 0x4c, 0x4c, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x04, 0x12, 0x24, 0x0a, 0x1c, 0x44,
0x45, 0x50, 0x52, 0x45, 0x43, 0x41, 0x54, 0x45, 0x44, 0x5f, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x49,
0x4e, 0x53, 0x54, 0x41, 0x4c, 0x4c, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x05, 0x1a, 0x02, 0x08,
0x01, 0x12, 0x23, 0x0a, 0x1f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x5f, 0x41, 0x44, 0x44,
0x52, 0x45, 0x53, 0x53, 0x5f, 0x46, 0x4f, 0x52, 0x5f, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x41, 0x43,
0x54, 0x49, 0x4f, 0x4e, 0x10, 0x06, 0x12, 0x2a, 0x0a, 0x26, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54,
0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x5f, 0x41, 0x44, 0x44, 0x52, 0x45, 0x53, 0x53,
0x5f, 0x46, 0x4f, 0x52, 0x5f, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e,
0x10, 0x07, 0x12, 0x2b, 0x0a, 0x27, 0x44, 0x45, 0x43, 0x4c, 0x49, 0x4e, 0x45, 0x5f, 0x52, 0x45,
0x51, 0x55, 0x45, 0x53, 0x54, 0x5f, 0x41, 0x44, 0x44, 0x52, 0x45, 0x53, 0x53, 0x5f, 0x46, 0x4f,
0x52, 0x5f, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x08, 0x12,
0x17, 0x0a, 0x13, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x5f, 0x54, 0x52, 0x41, 0x4e, 0x53,
0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x09, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x45, 0x4e, 0x44,
0x5f, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x0a, 0x12, 0x1f,
0x0a, 0x1b, 0x44, 0x45, 0x43, 0x4c, 0x49, 0x4e, 0x45, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53,
0x54, 0x5f, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x0b, 0x12,
0x20, 0x0a, 0x1c, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x49, 0x4e, 0x53, 0x54, 0x41, 0x4c, 0x4c, 0x41,
0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x43, 0x4f, 0x4e, 0x54, 0x41, 0x43, 0x54, 0x5f, 0x56, 0x32, 0x10,
0x0c, 0x12, 0x1d, 0x0a, 0x19, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x49, 0x4e, 0x53, 0x54, 0x41, 0x4c,
0x4c, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x41, 0x43, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x10, 0x0d,
0x12, 0x1e, 0x0a, 0x1a, 0x43, 0x4f, 0x4e, 0x54, 0x41, 0x43, 0x54, 0x5f, 0x43, 0x4f, 0x44, 0x45,
0x5f, 0x41, 0x44, 0x56, 0x45, 0x52, 0x54, 0x49, 0x53, 0x45, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x0f,
0x12, 0x22, 0x0a, 0x1e, 0x50, 0x55, 0x53, 0x48, 0x5f, 0x4e, 0x4f, 0x54, 0x49, 0x46, 0x49, 0x43,
0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x52, 0x45, 0x47, 0x49, 0x53, 0x54, 0x52, 0x41, 0x54, 0x49,
0x4f, 0x4e, 0x10, 0x10, 0x12, 0x2b, 0x0a, 0x27, 0x50, 0x55, 0x53, 0x48, 0x5f, 0x4e, 0x4f, 0x54,
0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x52, 0x45, 0x47, 0x49, 0x53, 0x54,
0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45, 0x10,
0x11, 0x12, 0x1b, 0x0a, 0x17, 0x50, 0x55, 0x53, 0x48, 0x5f, 0x4e, 0x4f, 0x54, 0x49, 0x46, 0x49,
0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x51, 0x55, 0x45, 0x52, 0x59, 0x10, 0x12, 0x12, 0x24,
0x0a, 0x20, 0x50, 0x55, 0x53, 0x48, 0x5f, 0x4e, 0x4f, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54,
0x49, 0x4f, 0x4e, 0x5f, 0x51, 0x55, 0x45, 0x52, 0x59, 0x5f, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e,
0x53, 0x45, 0x10, 0x13, 0x12, 0x1d, 0x0a, 0x19, 0x50, 0x55, 0x53, 0x48, 0x5f, 0x4e, 0x4f, 0x54,
0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53,
0x54, 0x10, 0x14, 0x12, 0x1e, 0x0a, 0x1a, 0x50, 0x55, 0x53, 0x48, 0x5f, 0x4e, 0x4f, 0x54, 0x49,
0x46, 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53,
0x45, 0x10, 0x15, 0x12, 0x12, 0x0a, 0x0e, 0x45, 0x4d, 0x4f, 0x4a, 0x49, 0x5f, 0x52, 0x45, 0x41,
0x43, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x16, 0x12, 0x19, 0x0a, 0x15, 0x47, 0x52, 0x4f, 0x55, 0x50,
0x5f, 0x43, 0x48, 0x41, 0x54, 0x5f, 0x49, 0x4e, 0x56, 0x49, 0x54, 0x41, 0x54, 0x49, 0x4f, 0x4e,
0x10, 0x17, 0x12, 0x11, 0x0a, 0x0d, 0x43, 0x48, 0x41, 0x54, 0x5f, 0x49, 0x44, 0x45, 0x4e, 0x54,
0x49, 0x54, 0x59, 0x10, 0x18, 0x12, 0x19, 0x0a, 0x15, 0x43, 0x4f, 0x4d, 0x4d, 0x55, 0x4e, 0x49,
0x54, 0x59, 0x5f, 0x44, 0x45, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x19,
0x12, 0x1c, 0x0a, 0x14, 0x43, 0x4f, 0x4d, 0x4d, 0x55, 0x4e, 0x49, 0x54, 0x59, 0x5f, 0x49, 0x4e,
0x56, 0x49, 0x54, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x1a, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x1d,
0x0a, 0x19, 0x43, 0x4f, 0x4d, 0x4d, 0x55, 0x4e, 0x49, 0x54, 0x59, 0x5f, 0x52, 0x45, 0x51, 0x55,
0x45, 0x53, 0x54, 0x5f, 0x54, 0x4f, 0x5f, 0x4a, 0x4f, 0x49, 0x4e, 0x10, 0x1b, 0x12, 0x0f, 0x0a,
0x0b, 0x50, 0x49, 0x4e, 0x5f, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x10, 0x1c, 0x12, 0x10,
0x0a, 0x0c, 0x45, 0x44, 0x49, 0x54, 0x5f, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x10, 0x1d,
0x12, 0x11, 0x0a, 0x0d, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54,
0x45, 0x10, 0x1e, 0x12, 0x12, 0x0a, 0x0e, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x4d, 0x45,
0x53, 0x53, 0x41, 0x47, 0x45, 0x10, 0x1f, 0x12, 0x1f, 0x0a, 0x1b, 0x53, 0x59, 0x4e, 0x43, 0x5f,
0x49, 0x4e, 0x53, 0x54, 0x41, 0x4c, 0x4c, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x43, 0x4f, 0x4d,
0x4d, 0x55, 0x4e, 0x49, 0x54, 0x59, 0x10, 0x20, 0x12, 0x1a, 0x0a, 0x16, 0x41, 0x4e, 0x4f, 0x4e,
0x59, 0x4d, 0x4f, 0x55, 0x53, 0x5f, 0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, 0x5f, 0x42, 0x41, 0x54,
0x43, 0x48, 0x10, 0x21, 0x12, 0x15, 0x0a, 0x11, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x43, 0x48, 0x41,
0x54, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x56, 0x45, 0x44, 0x10, 0x22, 0x12, 0x1b, 0x0a, 0x17, 0x53,
0x59, 0x4e, 0x43, 0x5f, 0x43, 0x48, 0x41, 0x54, 0x5f, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45,
0x53, 0x5f, 0x52, 0x45, 0x41, 0x44, 0x10, 0x23, 0x12, 0x0a, 0x0a, 0x06, 0x42, 0x41, 0x43, 0x4b,
0x55, 0x50, 0x10, 0x24, 0x12, 0x1d, 0x0a, 0x19, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x41, 0x43, 0x54,
0x49, 0x56, 0x49, 0x54, 0x59, 0x5f, 0x43, 0x45, 0x4e, 0x54, 0x45, 0x52, 0x5f, 0x52, 0x45, 0x41,
0x44, 0x10, 0x25, 0x12, 0x21, 0x0a, 0x1d, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x41, 0x43, 0x54, 0x49,
0x56, 0x49, 0x54, 0x59, 0x5f, 0x43, 0x45, 0x4e, 0x54, 0x45, 0x52, 0x5f, 0x41, 0x43, 0x43, 0x45,
0x50, 0x54, 0x45, 0x44, 0x10, 0x26, 0x12, 0x22, 0x0a, 0x1e, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x41,
0x43, 0x54, 0x49, 0x56, 0x49, 0x54, 0x59, 0x5f, 0x43, 0x45, 0x4e, 0x54, 0x45, 0x52, 0x5f, 0x44,
0x49, 0x53, 0x4d, 0x49, 0x53, 0x53, 0x45, 0x44, 0x10, 0x27, 0x12, 0x11, 0x0a, 0x0d, 0x53, 0x59,
0x4e, 0x43, 0x5f, 0x42, 0x4f, 0x4f, 0x4b, 0x4d, 0x41, 0x52, 0x4b, 0x10, 0x28, 0x12, 0x16, 0x0a,
0x12, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x43, 0x4c, 0x45, 0x41, 0x52, 0x5f, 0x48, 0x49, 0x53, 0x54,
0x4f, 0x52, 0x59, 0x10, 0x29, 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x53, 0x45,
0x54, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x2a, 0x12, 0x28, 0x0a, 0x24, 0x43, 0x4f, 0x4d, 0x4d, 0x55,
0x4e, 0x49, 0x54, 0x59, 0x5f, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x41, 0x52, 0x43,
0x48, 0x49, 0x56, 0x45, 0x5f, 0x4d, 0x41, 0x47, 0x4e, 0x45, 0x54, 0x4c, 0x49, 0x4e, 0x4b, 0x10,
0x2b, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x50, 0x52, 0x4f, 0x46, 0x49, 0x4c,
0x45, 0x5f, 0x50, 0x49, 0x43, 0x54, 0x55, 0x52, 0x45, 0x53, 0x10, 0x2c, 0x12, 0x10, 0x0a, 0x0c,
0x53, 0x59, 0x4e, 0x43, 0x5f, 0x41, 0x43, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x10, 0x2d, 0x12, 0x1a,
0x0a, 0x16, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54, 0x5f, 0x43, 0x4f, 0x4e, 0x54, 0x41, 0x43, 0x54,
0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x10, 0x2e, 0x12, 0x1b, 0x0a, 0x17, 0x52, 0x45,
0x54, 0x52, 0x41, 0x43, 0x54, 0x5f, 0x43, 0x4f, 0x4e, 0x54, 0x41, 0x43, 0x54, 0x5f, 0x52, 0x45,
0x51, 0x55, 0x45, 0x53, 0x54, 0x10, 0x2f, 0x12, 0x26, 0x0a, 0x22, 0x43, 0x4f, 0x4d, 0x4d, 0x55,
0x4e, 0x49, 0x54, 0x59, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x5f, 0x54, 0x4f, 0x5f,
0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45, 0x10, 0x30, 0x12,
0x1b, 0x0a, 0x17, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x43, 0x4f, 0x4d, 0x4d, 0x55, 0x4e, 0x49, 0x54,
0x59, 0x5f, 0x53, 0x45, 0x54, 0x54, 0x49, 0x4e, 0x47, 0x53, 0x10, 0x31, 0x12, 0x20, 0x0a, 0x1c,
0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x5f, 0x43, 0x4f, 0x4e, 0x54, 0x41, 0x43, 0x54, 0x5f,
0x56, 0x45, 0x52, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x32, 0x12, 0x1f,
0x0a, 0x1b, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54, 0x5f, 0x43, 0x4f, 0x4e, 0x54, 0x41, 0x43, 0x54,
0x5f, 0x56, 0x45, 0x52, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x33, 0x12,
0x20, 0x0a, 0x1c, 0x44, 0x45, 0x43, 0x4c, 0x49, 0x4e, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x54, 0x41,
0x43, 0x54, 0x5f, 0x56, 0x45, 0x52, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10,
0x34, 0x12, 0x15, 0x0a, 0x11, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x54, 0x52, 0x55, 0x53, 0x54, 0x45,
0x44, 0x5f, 0x55, 0x53, 0x45, 0x52, 0x10, 0x35, 0x12, 0x1d, 0x0a, 0x19, 0x53, 0x59, 0x4e, 0x43,
0x5f, 0x56, 0x45, 0x52, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x52, 0x45,
0x51, 0x55, 0x45, 0x53, 0x54, 0x10, 0x36, 0x12, 0x21, 0x0a, 0x1d, 0x53, 0x59, 0x4e, 0x43, 0x5f,
0x43, 0x4f, 0x4e, 0x54, 0x41, 0x43, 0x54, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x5f,
0x44, 0x45, 0x43, 0x49, 0x53, 0x49, 0x4f, 0x4e, 0x10, 0x38, 0x12, 0x1e, 0x0a, 0x1a, 0x43, 0x4f,
0x4d, 0x4d, 0x55, 0x4e, 0x49, 0x54, 0x59, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x5f,
0x54, 0x4f, 0x5f, 0x4c, 0x45, 0x41, 0x56, 0x45, 0x10, 0x39, 0x12, 0x1e, 0x0a, 0x1a, 0x53, 0x59,
0x4e, 0x43, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x46, 0x4f, 0x52, 0x5f, 0x4d, 0x45,
0x5f, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x10, 0x3a, 0x12, 0x16, 0x0a, 0x12, 0x53, 0x59,
0x4e, 0x43, 0x5f, 0x53, 0x41, 0x56, 0x45, 0x44, 0x5f, 0x41, 0x44, 0x44, 0x52, 0x45, 0x53, 0x53,
0x10, 0x3b, 0x12, 0x24, 0x0a, 0x20, 0x43, 0x4f, 0x4d, 0x4d, 0x55, 0x4e, 0x49, 0x54, 0x59, 0x5f,
0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x5f, 0x54,
0x4f, 0x5f, 0x4a, 0x4f, 0x49, 0x4e, 0x10, 0x3c, 0x12, 0x1f, 0x0a, 0x1b, 0x43, 0x41, 0x4e, 0x43,
0x45, 0x4c, 0x5f, 0x43, 0x4f, 0x4e, 0x54, 0x41, 0x43, 0x54, 0x5f, 0x56, 0x45, 0x52, 0x49, 0x46,
0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x3d, 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x59, 0x4e,
0x43, 0x5f, 0x4b, 0x45, 0x59, 0x50, 0x41, 0x49, 0x52, 0x10, 0x3e, 0x12, 0x15, 0x0a, 0x11, 0x53,
0x59, 0x4e, 0x43, 0x5f, 0x53, 0x4f, 0x43, 0x49, 0x41, 0x4c, 0x5f, 0x4c, 0x49, 0x4e, 0x4b, 0x53,
0x10, 0x3f, 0x12, 0x1c, 0x0a, 0x18, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x45, 0x4e, 0x53, 0x5f, 0x55,
0x53, 0x45, 0x52, 0x4e, 0x41, 0x4d, 0x45, 0x5f, 0x44, 0x45, 0x54, 0x41, 0x49, 0x4c, 0x10, 0x40,
0x12, 0x1c, 0x0a, 0x18, 0x43, 0x4f, 0x4d, 0x4d, 0x55, 0x4e, 0x49, 0x54, 0x59, 0x5f, 0x45, 0x56,
0x45, 0x4e, 0x54, 0x53, 0x5f, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x10, 0x43, 0x12, 0x23,
0x0a, 0x1f, 0x43, 0x4f, 0x4d, 0x4d, 0x55, 0x4e, 0x49, 0x54, 0x59, 0x5f, 0x45, 0x44, 0x49, 0x54,
0x5f, 0x53, 0x48, 0x41, 0x52, 0x45, 0x44, 0x5f, 0x41, 0x44, 0x44, 0x52, 0x45, 0x53, 0x53, 0x45,
0x53, 0x10, 0x44, 0x12, 0x24, 0x0a, 0x20, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x41, 0x43, 0x43, 0x4f,
0x55, 0x4e, 0x54, 0x5f, 0x43, 0x55, 0x53, 0x54, 0x4f, 0x4d, 0x49, 0x5a, 0x41, 0x54, 0x49, 0x4f,
0x4e, 0x5f, 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x10, 0x45, 0x12, 0x1b, 0x0a, 0x17, 0x53, 0x59, 0x4e,
0x43, 0x5f, 0x41, 0x43, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x53, 0x5f, 0x50, 0x4f, 0x53, 0x49, 0x54,
0x49, 0x4f, 0x4e, 0x53, 0x10, 0x46, 0x12, 0x25, 0x0a, 0x21, 0x43, 0x4f, 0x4d, 0x4d, 0x55, 0x4e,
0x49, 0x54, 0x59, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x53, 0x5f, 0x4d, 0x45, 0x53, 0x53, 0x41,
0x47, 0x45, 0x5f, 0x52, 0x45, 0x4a, 0x45, 0x43, 0x54, 0x45, 0x44, 0x10, 0x47, 0x12, 0x2a, 0x0a,
0x26, 0x43, 0x4f, 0x4d, 0x4d, 0x55, 0x4e, 0x49, 0x54, 0x59, 0x5f, 0x50, 0x52, 0x49, 0x56, 0x49,
0x4c, 0x45, 0x47, 0x45, 0x44, 0x5f, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x53, 0x59, 0x4e, 0x43, 0x5f,
0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x10, 0x48, 0x12, 0x17, 0x0a, 0x13, 0x43, 0x4f, 0x4d,
0x4d, 0x55, 0x4e, 0x49, 0x54, 0x59, 0x5f, 0x53, 0x48, 0x41, 0x52, 0x44, 0x5f, 0x4b, 0x45, 0x59,
0x10, 0x49, 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x43, 0x48, 0x41, 0x54, 0x10,
0x4a, 0x12, 0x20, 0x0a, 0x1c, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x56, 0x49,
0x54, 0x59, 0x5f, 0x43, 0x45, 0x4e, 0x54, 0x45, 0x52, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45,
0x44, 0x10, 0x4b, 0x12, 0x1f, 0x0a, 0x1b, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x41, 0x43, 0x54, 0x49,
0x56, 0x49, 0x54, 0x59, 0x5f, 0x43, 0x45, 0x4e, 0x54, 0x45, 0x52, 0x5f, 0x55, 0x4e, 0x52, 0x45,
0x41, 0x44, 0x10, 0x4c, 0x12, 0x33, 0x0a, 0x2f, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x41, 0x43, 0x54,
0x49, 0x56, 0x49, 0x54, 0x59, 0x5f, 0x43, 0x45, 0x4e, 0x54, 0x45, 0x52, 0x5f, 0x43, 0x4f, 0x4d,
0x4d, 0x55, 0x4e, 0x49, 0x54, 0x59, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x5f, 0x44,
0x45, 0x43, 0x49, 0x53, 0x49, 0x4f, 0x4e, 0x10, 0x4d, 0x12, 0x1a, 0x0a, 0x16, 0x53, 0x59, 0x4e,
0x43, 0x5f, 0x54, 0x4f, 0x4b, 0x45, 0x4e, 0x5f, 0x50, 0x52, 0x45, 0x46, 0x45, 0x52, 0x45, 0x4e,
0x43, 0x45, 0x53, 0x10, 0x4e, 0x12, 0x1f, 0x0a, 0x1b, 0x43, 0x4f, 0x4d, 0x4d, 0x55, 0x4e, 0x49,
0x54, 0x59, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x5f, 0x53, 0x48, 0x41, 0x52, 0x44, 0x5f,
0x49, 0x4e, 0x46, 0x4f, 0x10, 0x4f, 0x12, 0x20, 0x0a, 0x1c, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x43,
0x4f, 0x4c, 0x4c, 0x45, 0x43, 0x54, 0x49, 0x42, 0x4c, 0x45, 0x5f, 0x50, 0x52, 0x45, 0x46, 0x45,
0x52, 0x45, 0x4e, 0x43, 0x45, 0x53, 0x10, 0x50, 0x12, 0x19, 0x0a, 0x15, 0x43, 0x4f, 0x4d, 0x4d,
0x55, 0x4e, 0x49, 0x54, 0x59, 0x5f, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x4b, 0x49, 0x43, 0x4b, 0x45,
0x44, 0x10, 0x51, 0x12, 0x25, 0x0a, 0x21, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x50, 0x52, 0x4f, 0x46,
0x49, 0x4c, 0x45, 0x5f, 0x53, 0x48, 0x4f, 0x57, 0x43, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x52, 0x45,
0x46, 0x45, 0x52, 0x45, 0x4e, 0x43, 0x45, 0x53, 0x10, 0x52, 0x12, 0x24, 0x0a, 0x20, 0x43, 0x4f,
0x4d, 0x4d, 0x55, 0x4e, 0x49, 0x54, 0x59, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x5f, 0x53,
0x54, 0x4f, 0x52, 0x45, 0x4e, 0x4f, 0x44, 0x45, 0x53, 0x5f, 0x49, 0x4e, 0x46, 0x4f, 0x10, 0x53,
0x12, 0x2c, 0x0a, 0x28, 0x43, 0x4f, 0x4d, 0x4d, 0x55, 0x4e, 0x49, 0x54, 0x59, 0x5f, 0x52, 0x45,
0x45, 0x56, 0x41, 0x4c, 0x55, 0x41, 0x54, 0x45, 0x5f, 0x50, 0x45, 0x52, 0x4d, 0x49, 0x53, 0x53,
0x49, 0x4f, 0x4e, 0x53, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x10, 0x54, 0x12, 0x24,
0x0a, 0x20, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x4d, 0x55, 0x4e, 0x49,
0x54, 0x59, 0x5f, 0x4d, 0x45, 0x4d, 0x42, 0x45, 0x52, 0x5f, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47,
0x45, 0x53, 0x10, 0x55, 0x22, 0x04, 0x08, 0x0e, 0x10, 0x0e, 0x22, 0x04, 0x08, 0x41, 0x10, 0x41,
0x22, 0x04, 0x08, 0x42, 0x10, 0x42, 0x2a, 0x1d, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x49, 0x4e, 0x53,
0x54, 0x41, 0x4c, 0x4c, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43,
0x5f, 0x43, 0x48, 0x41, 0x54, 0x2a, 0x22, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x41, 0x43, 0x54, 0x49,
0x56, 0x49, 0x54, 0x59, 0x5f, 0x43, 0x45, 0x4e, 0x54, 0x45, 0x52, 0x5f, 0x4e, 0x4f, 0x54, 0x49,
0x46, 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x2a, 0x27, 0x53, 0x59, 0x4e, 0x43, 0x5f,
0x41, 0x43, 0x54, 0x49, 0x56, 0x49, 0x54, 0x59, 0x5f, 0x43, 0x45, 0x4e, 0x54, 0x45, 0x52, 0x5f,
0x4e, 0x4f, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41,
0x54, 0x45, 0x42, 0x0d, 0x5a, 0x0b, 0x2e, 0x2f, 0x3b, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
func init() {
proto.RegisterFile("application_metadata_message.proto", fileDescriptor_ad09a6406fcf24c7)
var (
file_application_metadata_message_proto_rawDescOnce sync.Once
file_application_metadata_message_proto_rawDescData = file_application_metadata_message_proto_rawDesc
)
func file_application_metadata_message_proto_rawDescGZIP() []byte {
file_application_metadata_message_proto_rawDescOnce.Do(func() {
file_application_metadata_message_proto_rawDescData = protoimpl.X.CompressGZIP(file_application_metadata_message_proto_rawDescData)
})
return file_application_metadata_message_proto_rawDescData
}
var fileDescriptor_ad09a6406fcf24c7 = []byte{
// 1177 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x56, 0x6d, 0x73, 0x13, 0x37,
0x17, 0x7d, 0x02, 0x7e, 0xc0, 0x28, 0x24, 0x08, 0x11, 0xc0, 0x09, 0x0e, 0x04, 0x13, 0x92, 0x10,
0x5a, 0xa7, 0x4d, 0xda, 0x4e, 0x5b, 0x4a, 0x5b, 0x59, 0xba, 0xb6, 0x15, 0xef, 0x4a, 0x1b, 0x49,
0xeb, 0x8e, 0xf9, 0xa2, 0x31, 0xc5, 0x65, 0x32, 0x03, 0xc4, 0x43, 0xcc, 0x87, 0xfc, 0x85, 0xfe,
0x8a, 0xfe, 0xd4, 0x8e, 0xf6, 0xd5, 0x89, 0x9d, 0xe6, 0x53, 0x62, 0xdd, 0xa3, 0x97, 0x73, 0xee,
0xb9, 0xf7, 0x2e, 0x6a, 0x0c, 0xc7, 0xe3, 0x0f, 0xc7, 0x7f, 0x0e, 0x27, 0xc7, 0x27, 0x9f, 0xdc,
0xc7, 0xd1, 0x64, 0xf8, 0x6e, 0x38, 0x19, 0xba, 0x8f, 0xa3, 0xd3, 0xd3, 0xe1, 0xfb, 0x51, 0x73,
0xfc, 0xf9, 0x64, 0x72, 0x42, 0xaa, 0xc9, 0x9f, 0xb7, 0x5f, 0xfe, 0x6a, 0xfc, 0xb3, 0x82, 0xd6,
0x68, 0xb9, 0x21, 0xcc, 0xf0, 0x61, 0x0a, 0x27, 0x75, 0x74, 0xeb, 0xf4, 0xf8, 0xfd, 0xa7, 0xe1,
0xe4, 0xcb, 0xe7, 0x51, 0x6d, 0x61, 0x63, 0x61, 0xe7, 0xb6, 0x2e, 0x17, 0x48, 0x0d, 0xdd, 0x1c,
0x0f, 0xcf, 0x3e, 0x9c, 0x0c, 0xdf, 0xd5, 0xae, 0x25, 0xb1, 0xfc, 0x27, 0x79, 0x8d, 0x2a, 0x93,
0xb3, 0xf1, 0xa8, 0x76, 0x7d, 0x63, 0x61, 0x67, 0x79, 0xff, 0x45, 0x33, 0xbf, 0xaf, 0x79, 0xf9,
0x5d, 0x4d, 0x7b, 0x36, 0x1e, 0xe9, 0x64, 0x5b, 0xe3, 0xef, 0x7b, 0xa8, 0xe2, 0x7f, 0x92, 0x45,
0x74, 0x33, 0x96, 0x3d, 0xa9, 0xfe, 0x90, 0xf8, 0x7f, 0x04, 0xa3, 0xdb, 0xac, 0x4b, 0xad, 0x0b,
0xc1, 0x18, 0xda, 0x01, 0xbc, 0x40, 0x08, 0x5a, 0x66, 0x4a, 0x5a, 0xca, 0xac, 0x8b, 0x23, 0x4e,
0x2d, 0xe0, 0x6b, 0x64, 0x1d, 0xad, 0x86, 0x10, 0xb6, 0x40, 0x9b, 0xae, 0x88, 0xb2, 0xe5, 0x62,
0xcb, 0x75, 0xb2, 0x86, 0x1e, 0x98, 0x81, 0x64, 0x2e, 0xa2, 0x42, 0x3b, 0x21, 0x8d, 0xa5, 0x41,
0x40, 0xad, 0x50, 0x12, 0x57, 0xc8, 0x26, 0xaa, 0x73, 0x88, 0x34, 0x30, 0x6a, 0x81, 0xbb, 0x04,
0x76, 0x0e, 0xf1, 0xff, 0xb5, 0x6b, 0xd5, 0x05, 0xf2, 0x0c, 0x3d, 0xd1, 0x70, 0x14, 0x83, 0xb1,
0x8e, 0x72, 0xae, 0xc1, 0x18, 0xd7, 0x56, 0xda, 0x59, 0x4d, 0xa5, 0xa1, 0x2c, 0x01, 0xde, 0x20,
0xbb, 0x68, 0x8b, 0x32, 0x06, 0x91, 0x75, 0x57, 0x61, 0x6f, 0x92, 0x97, 0x68, 0x9b, 0x03, 0x0b,
0x84, 0x84, 0x2b, 0xc1, 0x55, 0xf2, 0x10, 0xdd, 0xcb, 0x41, 0xd3, 0x81, 0x5b, 0x64, 0x05, 0x61,
0x03, 0x92, 0x9f, 0x5b, 0x45, 0xe4, 0x09, 0x7a, 0x74, 0xf1, 0xec, 0x69, 0xc0, 0x22, 0xd9, 0x40,
0xf5, 0x19, 0xa2, 0x2e, 0x17, 0xb5, 0xbf, 0x8f, 0x6f, 0x7b, 0x41, 0x67, 0x11, 0x94, 0x31, 0x15,
0x4b, 0x8b, 0x97, 0xc8, 0x63, 0xb4, 0x96, 0xc3, 0x99, 0xe2, 0xe0, 0x28, 0xef, 0x83, 0xb6, 0xc2,
0x40, 0x08, 0xd2, 0xe2, 0x3b, 0xa4, 0x81, 0x1e, 0x47, 0xb1, 0xe9, 0x3a, 0xa9, 0xac, 0x68, 0x0b,
0x96, 0x6e, 0xd7, 0xd0, 0x11, 0xc6, 0xea, 0x54, 0x56, 0xec, 0x15, 0xf8, 0x6f, 0x8c, 0xd3, 0x60,
0x22, 0x25, 0x0d, 0xe0, 0xbb, 0xe4, 0x11, 0x7a, 0x38, 0x0b, 0x3e, 0x8a, 0x41, 0x0f, 0x30, 0x21,
0x9b, 0x68, 0xe3, 0x92, 0x60, 0x79, 0xc4, 0x3d, 0x4f, 0x69, 0xde, 0x7d, 0x89, 0x3e, 0x78, 0xc5,
0x53, 0x9a, 0x17, 0xce, 0xb6, 0xdf, 0xf7, 0xb6, 0x83, 0x50, 0x1d, 0x0a, 0xa7, 0x21, 0xd3, 0xf1,
0x01, 0x59, 0x45, 0xf7, 0x3b, 0x5a, 0xc5, 0x91, 0x4b, 0x2c, 0x2a, 0x64, 0x5f, 0xd8, 0x94, 0xdd,
0x43, 0x72, 0x17, 0x2d, 0xa5, 0x8b, 0x1c, 0xa4, 0x15, 0x76, 0x80, 0x6b, 0x1e, 0xcd, 0x54, 0x18,
0xc6, 0x52, 0xd8, 0x81, 0xe3, 0x60, 0x98, 0x16, 0x51, 0x82, 0x5e, 0x25, 0x75, 0xb4, 0x52, 0x86,
0xa6, 0xce, 0x59, 0x4b, 0xcc, 0xb7, 0x8e, 0x56, 0xcb, 0x68, 0x91, 0x51, 0xe5, 0x0e, 0x95, 0x90,
0xf8, 0x11, 0xb9, 0x83, 0x16, 0x23, 0x21, 0x0b, 0xbb, 0xd7, 0x7d, 0xcd, 0x00, 0x17, 0x65, 0xcd,
0xac, 0xfb, 0xd7, 0x18, 0x4b, 0x6d, 0x6c, 0xf2, 0x92, 0x79, 0xec, 0xf9, 0x70, 0x08, 0x60, 0xaa,
0x4e, 0x9e, 0x78, 0xe3, 0xcc, 0xf3, 0x45, 0x76, 0x35, 0xde, 0xf0, 0x85, 0x44, 0xa5, 0x92, 0x83,
0x50, 0xc5, 0xc6, 0x85, 0x60, 0xb5, 0x60, 0xae, 0x45, 0x2d, 0xeb, 0xe2, 0xa7, 0xe4, 0x3e, 0xba,
0x9b, 0x6c, 0x4e, 0x68, 0x6b, 0x08, 0x55, 0x1f, 0x38, 0x6e, 0xf8, 0xcc, 0x95, 0xcb, 0xd9, 0x55,
0xc6, 0x8b, 0xc8, 0xf1, 0x33, 0x82, 0xd0, 0x8d, 0x16, 0x65, 0xbd, 0x38, 0xc2, 0x9b, 0x85, 0xe5,
0xbc, 0xba, 0x7d, 0xcf, 0x94, 0x81, 0xb4, 0xa0, 0x53, 0xe8, 0x73, 0xf2, 0x14, 0xad, 0xcf, 0x0d,
0xa7, 0x15, 0x07, 0x1c, 0x6f, 0x79, 0xd7, 0xcd, 0x85, 0x70, 0x61, 0x42, 0x61, 0x0c, 0x70, 0xbc,
0x9d, 0x28, 0xe1, 0x31, 0x2d, 0xa5, 0x7a, 0x21, 0xd5, 0x3d, 0xbc, 0x43, 0x1e, 0x20, 0x92, 0xbe,
0x30, 0x00, 0xaa, 0x5d, 0x57, 0x18, 0xab, 0xf4, 0x00, 0xbf, 0xf0, 0x32, 0x26, 0xeb, 0x06, 0xac,
0x15, 0xb2, 0x83, 0x77, 0xc9, 0x0e, 0xda, 0x2c, 0x13, 0x91, 0x71, 0x71, 0x54, 0xb3, 0xae, 0xe8,
0x83, 0x0b, 0x69, 0x47, 0x82, 0x0d, 0x84, 0xec, 0xe1, 0x97, 0x3e, 0xd7, 0x69, 0xc7, 0xd1, 0xaa,
0x2d, 0x02, 0x70, 0x91, 0x60, 0x36, 0xd6, 0x60, 0xf0, 0x57, 0xc5, 0xb1, 0x79, 0x35, 0x7d, 0x9d,
0xa8, 0x9a, 0xf6, 0x8d, 0xbc, 0xa8, 0x72, 0x5b, 0x36, 0xbd, 0x7c, 0x1a, 0xac, 0x4e, 0x2b, 0xed,
0x7c, 0x70, 0x8f, 0x6c, 0xa1, 0xc6, 0xa5, 0xc6, 0x28, 0xbd, 0xfb, 0x4d, 0x99, 0x83, 0x02, 0x9c,
0x71, 0x32, 0xf8, 0x5b, 0xdf, 0x0c, 0xf2, 0xad, 0x45, 0x0b, 0x00, 0x5d, 0xd4, 0x00, 0xde, 0xf7,
0xb6, 0xb8, 0xf0, 0xbe, 0x73, 0x80, 0x03, 0x7f, 0x44, 0xde, 0x70, 0xe6, 0x22, 0xbe, 0x2b, 0xcc,
0x61, 0x75, 0x6c, 0x7c, 0x9f, 0x8d, 0x0d, 0x68, 0xfc, 0x7d, 0x91, 0xf3, 0x69, 0x74, 0xc1, 0xef,
0x87, 0x22, 0xe7, 0x17, 0x98, 0x3b, 0x0e, 0x4c, 0x18, 0x7f, 0xf0, 0x8f, 0x69, 0x27, 0x9a, 0x23,
0x41, 0x00, 0xb4, 0x0f, 0xf8, 0x27, 0x1f, 0x4f, 0x8e, 0xc8, 0xbc, 0xee, 0x7b, 0x6b, 0x58, 0x5a,
0xfe, 0xe7, 0x22, 0xf9, 0x86, 0xf6, 0x81, 0xe7, 0x2d, 0x18, 0xbf, 0xf2, 0x3d, 0xa5, 0x3c, 0x97,
0x51, 0xc9, 0x20, 0x98, 0x29, 0xbd, 0x5f, 0xbc, 0x32, 0x59, 0x6c, 0x2e, 0xef, 0xd7, 0x45, 0xb2,
0x7b, 0x30, 0xf0, 0xc3, 0x07, 0xff, 0x5a, 0x28, 0x61, 0x14, 0x13, 0x34, 0x70, 0xde, 0x2f, 0x06,
0xff, 0x46, 0xea, 0xa8, 0x96, 0x2c, 0x83, 0x34, 0x89, 0x38, 0x92, 0x86, 0xe0, 0x38, 0x58, 0x2a,
0x02, 0xfc, 0xbb, 0x8f, 0x96, 0xaf, 0x81, 0x3e, 0x48, 0x6b, 0x0a, 0x0e, 0xcc, 0x0f, 0xa7, 0xa9,
0xa8, 0xaf, 0x7c, 0xd3, 0xa5, 0xba, 0xa4, 0x03, 0x06, 0x73, 0x4f, 0x68, 0xda, 0x76, 0x8e, 0xc5,
0xc6, 0xaa, 0x50, 0xbc, 0xc9, 0x8b, 0x3c, 0x50, 0x1a, 0x43, 0xe1, 0x94, 0x0c, 0x65, 0x5c, 0xa4,
0x8c, 0xf0, 0x08, 0x83, 0xdb, 0xe4, 0x39, 0x7a, 0x7a, 0xd9, 0x2b, 0x9c, 0x86, 0x43, 0x60, 0xbe,
0x0c, 0x3b, 0x7e, 0x0c, 0x96, 0xb0, 0x48, 0x8b, 0xbe, 0x08, 0xa0, 0x93, 0xe5, 0x3c, 0x1d, 0xb0,
0xf9, 0xd3, 0xbb, 0x7e, 0xb2, 0x4d, 0x99, 0xb2, 0x4b, 0x35, 0xf7, 0x52, 0x61, 0x41, 0x96, 0xd0,
0xad, 0xa2, 0x6d, 0xe0, 0xc3, 0x62, 0x62, 0xcd, 0x94, 0x76, 0x92, 0x56, 0x8e, 0x7b, 0x45, 0xef,
0xba, 0x88, 0x88, 0x65, 0xd2, 0x40, 0x02, 0x72, 0x80, 0xf6, 0xe6, 0x02, 0x66, 0xed, 0x53, 0xd8,
0x2b, 0x2c, 0xbe, 0x1c, 0xac, 0xea, 0x81, 0x74, 0x91, 0x86, 0x36, 0x68, 0x90, 0x0c, 0x0c, 0x96,
0x49, 0xf2, 0x4b, 0x9e, 0x71, 0x2b, 0x10, 0x2c, 0xa3, 0x20, 0x64, 0x5b, 0x61, 0x55, 0x3c, 0x9a,
0xa9, 0x20, 0x00, 0x66, 0x45, 0xcb, 0x37, 0x82, 0xa9, 0x23, 0xa2, 0xf3, 0x23, 0x21, 0xd1, 0xa7,
0x27, 0x58, 0x0f, 0x38, 0x3e, 0x6a, 0x54, 0xaa, 0xcb, 0x78, 0xb9, 0x51, 0xa9, 0x52, 0x4c, 0x1b,
0x95, 0x6a, 0x0b, 0xb7, 0x76, 0xd7, 0x67, 0x7b, 0x73, 0x76, 0xab, 0x17, 0x69, 0xb7, 0x31, 0x97,
0xdd, 0xf4, 0x38, 0x33, 0xbb, 0xdb, 0x57, 0x62, 0x9c, 0x9f, 0x13, 0xd0, 0x5a, 0x7a, 0xb3, 0xd8,
0xdc, 0x7b, 0x95, 0x7f, 0xc1, 0xbd, 0xbd, 0x91, 0xfc, 0x77, 0xf0, 0x6f, 0x00, 0x00, 0x00, 0xff,
0xff, 0x37, 0xfa, 0x36, 0xf9, 0x68, 0x0a, 0x00, 0x00,
var file_application_metadata_message_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_application_metadata_message_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_application_metadata_message_proto_goTypes = []interface{}{
(ApplicationMetadataMessage_Type)(0), // 0: protobuf.ApplicationMetadataMessage.Type
(*ApplicationMetadataMessage)(nil), // 1: protobuf.ApplicationMetadataMessage
}
var file_application_metadata_message_proto_depIdxs = []int32{
0, // 0: protobuf.ApplicationMetadataMessage.type:type_name -> protobuf.ApplicationMetadataMessage.Type
1, // [1:1] is the sub-list for method output_type
1, // [1:1] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
}
func init() { file_application_metadata_message_proto_init() }
func file_application_metadata_message_proto_init() {
if File_application_metadata_message_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_application_metadata_message_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ApplicationMetadataMessage); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_application_metadata_message_proto_rawDesc,
NumEnums: 1,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_application_metadata_message_proto_goTypes,
DependencyIndexes: file_application_metadata_message_proto_depIdxs,
EnumInfos: file_application_metadata_message_proto_enumTypes,
MessageInfos: file_application_metadata_message_proto_msgTypes,
}.Build()
File_application_metadata_message_proto = out.File
file_application_metadata_message_proto_rawDesc = nil
file_application_metadata_message_proto_goTypes = nil
file_application_metadata_message_proto_depIdxs = nil
}

Some files were not shown because too many files have changed in this diff Show More