1673
vendor/github.com/status-im/status-go/multiaccounts/accounts/database.go
generated
vendored
Normal file
1673
vendor/github.com/status-im/status-go/multiaccounts/accounts/database.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
6
vendor/github.com/status-im/status-go/multiaccounts/accounts/doc.go
generated
vendored
Normal file
6
vendor/github.com/status-im/status-go/multiaccounts/accounts/doc.go
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
package accounts
|
||||
|
||||
const (
|
||||
// NodeConfigTag tag for a node configuration.
|
||||
NodeConfigTag = "node_config"
|
||||
)
|
||||
477
vendor/github.com/status-im/status-go/multiaccounts/accounts/keycard_database.go
generated
vendored
Normal file
477
vendor/github.com/status-im/status-go/multiaccounts/accounts/keycard_database.go
generated
vendored
Normal file
@@ -0,0 +1,477 @@
|
||||
package accounts
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/status-im/status-go/eth-node/types"
|
||||
"github.com/status-im/status-go/protocol/protobuf"
|
||||
)
|
||||
|
||||
var (
|
||||
errKeycardDbTransactionIsNil = errors.New("keycard: database transaction is nil")
|
||||
errCannotAddKeycardForUnknownKeypair = errors.New("keycard: cannot add keycard for an unknown keyapir")
|
||||
ErrNoKeycardForPassedKeycardUID = errors.New("keycard: no keycard for the passed keycard uid")
|
||||
)
|
||||
|
||||
type Keycard struct {
|
||||
KeycardUID string `json:"keycard-uid"`
|
||||
KeycardName string `json:"keycard-name"`
|
||||
KeycardLocked bool `json:"keycard-locked"`
|
||||
AccountsAddresses []types.Address `json:"accounts-addresses"`
|
||||
KeyUID string `json:"key-uid"`
|
||||
Position uint64
|
||||
}
|
||||
|
||||
func (kp *Keycard) ToSyncKeycard() *protobuf.SyncKeycard {
|
||||
kc := &protobuf.SyncKeycard{
|
||||
Uid: kp.KeycardUID,
|
||||
Name: kp.KeycardName,
|
||||
Locked: kp.KeycardLocked,
|
||||
KeyUid: kp.KeyUID,
|
||||
Position: kp.Position,
|
||||
}
|
||||
|
||||
for _, addr := range kp.AccountsAddresses {
|
||||
kc.Addresses = append(kc.Addresses, addr.Bytes())
|
||||
}
|
||||
|
||||
return kc
|
||||
}
|
||||
|
||||
func (kp *Keycard) FromSyncKeycard(kc *protobuf.SyncKeycard) {
|
||||
kp.KeycardUID = kc.Uid
|
||||
kp.KeycardName = kc.Name
|
||||
kp.KeycardLocked = kc.Locked
|
||||
kp.KeyUID = kc.KeyUid
|
||||
kp.Position = kc.Position
|
||||
|
||||
for _, addr := range kc.Addresses {
|
||||
kp.AccountsAddresses = append(kp.AccountsAddresses, types.BytesToAddress(addr))
|
||||
}
|
||||
}
|
||||
|
||||
func containsAddress(addresses []types.Address, address types.Address) bool {
|
||||
for _, addr := range addresses {
|
||||
if addr == address {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (db *Database) processResult(rows *sql.Rows) ([]*Keycard, error) {
|
||||
keycards := []*Keycard{}
|
||||
for rows.Next() {
|
||||
keycard := &Keycard{}
|
||||
var accAddress sql.NullString
|
||||
err := rows.Scan(&keycard.KeycardUID, &keycard.KeycardName, &keycard.KeycardLocked, &accAddress, &keycard.KeyUID,
|
||||
&keycard.Position)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
addr := types.Address{}
|
||||
if accAddress.Valid {
|
||||
addr = types.BytesToAddress([]byte(accAddress.String))
|
||||
}
|
||||
|
||||
foundAtIndex := -1
|
||||
for i := range keycards {
|
||||
if keycards[i].KeycardUID == keycard.KeycardUID {
|
||||
foundAtIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if foundAtIndex == -1 {
|
||||
keycard.AccountsAddresses = append(keycard.AccountsAddresses, addr)
|
||||
keycards = append(keycards, keycard)
|
||||
} else {
|
||||
if containsAddress(keycards[foundAtIndex].AccountsAddresses, addr) {
|
||||
continue
|
||||
}
|
||||
keycards[foundAtIndex].AccountsAddresses = append(keycards[foundAtIndex].AccountsAddresses, addr)
|
||||
}
|
||||
}
|
||||
|
||||
return keycards, nil
|
||||
}
|
||||
|
||||
func (db *Database) getKeycards(tx *sql.Tx, keyUID string, keycardUID string) ([]*Keycard, error) {
|
||||
query := `
|
||||
SELECT
|
||||
kc.keycard_uid,
|
||||
kc.keycard_name,
|
||||
kc.keycard_locked,
|
||||
ka.account_address,
|
||||
kc.key_uid,
|
||||
kc.position
|
||||
FROM
|
||||
keycards AS kc
|
||||
LEFT JOIN
|
||||
keycards_accounts AS ka
|
||||
ON
|
||||
kc.keycard_uid = ka.keycard_uid
|
||||
LEFT JOIN
|
||||
keypairs_accounts AS kpa
|
||||
ON
|
||||
ka.account_address = kpa.address
|
||||
%s
|
||||
ORDER BY
|
||||
kc.position, kpa.position`
|
||||
|
||||
var where string
|
||||
var args []interface{}
|
||||
|
||||
if keyUID != "" {
|
||||
where = "WHERE kc.key_uid = ?"
|
||||
args = append(args, keyUID)
|
||||
if keycardUID != "" {
|
||||
where += " AND kc.keycard_uid = ?"
|
||||
args = append(args, keycardUID)
|
||||
}
|
||||
} else if keycardUID != "" {
|
||||
where = "WHERE kc.keycard_uid = ?"
|
||||
args = append(args, keycardUID)
|
||||
}
|
||||
|
||||
query = fmt.Sprintf(query, where)
|
||||
|
||||
var (
|
||||
stmt *sql.Stmt
|
||||
err error
|
||||
)
|
||||
if tx == nil {
|
||||
stmt, err = db.db.Prepare(query)
|
||||
} else {
|
||||
stmt, err = tx.Prepare(query)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer stmt.Close()
|
||||
|
||||
rows, err := stmt.Query(args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
return db.processResult(rows)
|
||||
}
|
||||
|
||||
func (db *Database) getKeycardByKeycardUID(tx *sql.Tx, keycardUID string) (*Keycard, error) {
|
||||
keycards, err := db.getKeycards(tx, "", keycardUID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(keycards) == 0 {
|
||||
return nil, ErrNoKeycardForPassedKeycardUID
|
||||
}
|
||||
|
||||
return keycards[0], nil
|
||||
}
|
||||
|
||||
func (db *Database) GetAllKnownKeycards() ([]*Keycard, error) {
|
||||
return db.getKeycards(nil, "", "")
|
||||
}
|
||||
|
||||
func (db *Database) GetKeycardsWithSameKeyUID(keyUID string) ([]*Keycard, error) {
|
||||
return db.getKeycards(nil, keyUID, "")
|
||||
}
|
||||
|
||||
func (db *Database) GetKeycardByKeycardUID(keycardUID string) (*Keycard, error) {
|
||||
return db.getKeycardByKeycardUID(nil, keycardUID)
|
||||
}
|
||||
|
||||
func (db *Database) saveOrUpdateKeycardAccounts(tx *sql.Tx, kcUID string, accountsAddresses []types.Address) (err error) {
|
||||
if tx == nil {
|
||||
return errKeycardDbTransactionIsNil
|
||||
}
|
||||
|
||||
for i := range accountsAddresses {
|
||||
addr := accountsAddresses[i]
|
||||
|
||||
_, err = tx.Exec(`
|
||||
INSERT OR IGNORE INTO
|
||||
keycards_accounts
|
||||
(
|
||||
keycard_uid,
|
||||
account_address
|
||||
)
|
||||
VALUES
|
||||
(?, ?);
|
||||
`, kcUID, addr)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *Database) deleteKeycard(tx *sql.Tx, kcUID string) (err error) {
|
||||
if tx == nil {
|
||||
return errKeycardDbTransactionIsNil
|
||||
}
|
||||
|
||||
delete, err := tx.Prepare(`
|
||||
DELETE
|
||||
FROM
|
||||
keycards
|
||||
WHERE
|
||||
keycard_uid = ?
|
||||
`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer delete.Close()
|
||||
|
||||
_, err = delete.Exec(kcUID)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *Database) deleteAllKeycardsWithKeyUID(tx *sql.Tx, keyUID string) (err error) {
|
||||
if tx == nil {
|
||||
return errKeycardDbTransactionIsNil
|
||||
}
|
||||
|
||||
delete, err := tx.Prepare(`
|
||||
DELETE
|
||||
FROM
|
||||
keycards
|
||||
WHERE
|
||||
key_uid = ?
|
||||
`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer delete.Close()
|
||||
|
||||
_, err = delete.Exec(keyUID)
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *Database) deleteKeycardAccounts(tx *sql.Tx, kcUID string, accountAddresses []types.Address) (err error) {
|
||||
if tx == nil {
|
||||
return errKeycardDbTransactionIsNil
|
||||
}
|
||||
|
||||
inVector := strings.Repeat(",?", len(accountAddresses)-1)
|
||||
query := `
|
||||
DELETE
|
||||
FROM
|
||||
keycards_accounts
|
||||
WHERE
|
||||
keycard_uid = ?
|
||||
AND
|
||||
account_address IN (?` + inVector + `)`
|
||||
|
||||
delete, err := tx.Prepare(query)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer delete.Close()
|
||||
|
||||
args := make([]interface{}, len(accountAddresses)+1)
|
||||
args[0] = kcUID
|
||||
for i, addr := range accountAddresses {
|
||||
args[i+1] = addr
|
||||
}
|
||||
|
||||
_, err = delete.Exec(args...)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *Database) SaveOrUpdateKeycard(keycard Keycard, clock uint64, updateKeypairClock bool) error {
|
||||
tx, err := db.db.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err == nil {
|
||||
err = tx.Commit()
|
||||
return
|
||||
}
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
relatedKeypairExists, err := db.keypairExists(tx, keycard.KeyUID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !relatedKeypairExists {
|
||||
return errCannotAddKeycardForUnknownKeypair
|
||||
}
|
||||
|
||||
_, err = tx.Exec(`
|
||||
INSERT OR IGNORE INTO
|
||||
keycards
|
||||
(
|
||||
keycard_uid,
|
||||
keycard_name,
|
||||
key_uid
|
||||
)
|
||||
VALUES
|
||||
(?, ?, ?);
|
||||
|
||||
UPDATE
|
||||
keycards
|
||||
SET
|
||||
keycard_name = ?,
|
||||
keycard_locked = ?,
|
||||
position = ?
|
||||
WHERE
|
||||
keycard_uid = ?;
|
||||
`, keycard.KeycardUID, keycard.KeycardName, keycard.KeyUID,
|
||||
keycard.KeycardName, keycard.KeycardLocked, keycard.Position, keycard.KeycardUID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = db.saveOrUpdateKeycardAccounts(tx, keycard.KeycardUID, keycard.AccountsAddresses)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if updateKeypairClock {
|
||||
return db.updateKeypairClock(tx, keycard.KeyUID, clock)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *Database) execKeycardUpdateQuery(kcUID string, clock uint64, field string, value interface{}) (err error) {
|
||||
tx, err := db.db.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err == nil {
|
||||
err = tx.Commit()
|
||||
return
|
||||
}
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
keycard, err := db.getKeycardByKeycardUID(tx, kcUID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sql := fmt.Sprintf(`UPDATE keycards SET %s = ? WHERE keycard_uid = ?`, field) // nolint: gosec
|
||||
_, err = tx.Exec(sql, value, kcUID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return db.updateKeypairClock(tx, keycard.KeyUID, clock)
|
||||
}
|
||||
|
||||
func (db *Database) KeycardLocked(kcUID string, clock uint64) (err error) {
|
||||
return db.execKeycardUpdateQuery(kcUID, clock, "keycard_locked", true)
|
||||
}
|
||||
|
||||
func (db *Database) KeycardUnlocked(kcUID string, clock uint64) (err error) {
|
||||
return db.execKeycardUpdateQuery(kcUID, clock, "keycard_locked", false)
|
||||
}
|
||||
|
||||
func (db *Database) UpdateKeycardUID(oldKcUID string, newKcUID string, clock uint64) (err error) {
|
||||
return db.execKeycardUpdateQuery(oldKcUID, clock, "keycard_uid", newKcUID)
|
||||
}
|
||||
|
||||
func (db *Database) SetKeycardName(kcUID string, kpName string, clock uint64) (err error) {
|
||||
return db.execKeycardUpdateQuery(kcUID, clock, "keycard_name", kpName)
|
||||
}
|
||||
|
||||
func (db *Database) DeleteKeycardAccounts(kcUID string, accountAddresses []types.Address, clock uint64) (err error) {
|
||||
tx, err := db.db.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err == nil {
|
||||
err = tx.Commit()
|
||||
return
|
||||
}
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
keycard, err := db.getKeycardByKeycardUID(tx, kcUID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = db.deleteKeycardAccounts(tx, kcUID, accountAddresses)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return db.updateKeypairClock(tx, keycard.KeyUID, clock)
|
||||
}
|
||||
|
||||
func (db *Database) DeleteKeycard(kcUID string, clock uint64) (err error) {
|
||||
tx, err := db.db.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err == nil {
|
||||
err = tx.Commit()
|
||||
return
|
||||
}
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
keycard, err := db.getKeycardByKeycardUID(tx, kcUID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = db.deleteKeycard(tx, kcUID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return db.updateKeypairClock(tx, keycard.KeyUID, clock)
|
||||
}
|
||||
|
||||
func (db *Database) DeleteAllKeycardsWithKeyUID(keyUID string, clock uint64) (err error) {
|
||||
tx, err := db.db.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err == nil {
|
||||
err = tx.Commit()
|
||||
return
|
||||
}
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
err = db.deleteAllKeycardsWithKeyUID(tx, keyUID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return db.updateKeypairClock(tx, keyUID, clock)
|
||||
}
|
||||
|
||||
func (db *Database) GetPositionForNextNewKeycard() (uint64, error) {
|
||||
var pos sql.NullInt64
|
||||
err := db.db.QueryRow("SELECT MAX(position) FROM keycards").Scan(&pos)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if pos.Valid {
|
||||
return uint64(pos.Int64) + 1, nil
|
||||
}
|
||||
return 0, nil
|
||||
}
|
||||
434
vendor/github.com/status-im/status-go/multiaccounts/accounts/test_helper.go
generated
vendored
Normal file
434
vendor/github.com/status-im/status-go/multiaccounts/accounts/test_helper.go
generated
vendored
Normal file
@@ -0,0 +1,434 @@
|
||||
package accounts
|
||||
|
||||
import (
|
||||
"github.com/status-im/status-go/eth-node/types"
|
||||
"github.com/status-im/status-go/multiaccounts/common"
|
||||
)
|
||||
|
||||
func GetWatchOnlyAccountsForTest() []*Account {
|
||||
wo1 := &Account{
|
||||
Address: types.Address{0x11},
|
||||
Type: AccountTypeWatch,
|
||||
Name: "WatchOnlyAcc1",
|
||||
ColorID: common.CustomizationColorPrimary,
|
||||
Emoji: "emoji-1",
|
||||
}
|
||||
wo2 := &Account{
|
||||
Address: types.Address{0x12},
|
||||
Type: AccountTypeWatch,
|
||||
Name: "WatchOnlyAcc2",
|
||||
ColorID: common.CustomizationColorPrimary,
|
||||
Emoji: "emoji-1",
|
||||
}
|
||||
wo3 := &Account{
|
||||
Address: types.Address{0x13},
|
||||
Type: AccountTypeWatch,
|
||||
Name: "WatchOnlyAcc3",
|
||||
ColorID: common.CustomizationColorPrimary,
|
||||
Emoji: "emoji-1",
|
||||
}
|
||||
|
||||
return []*Account{wo1, wo2, wo3}
|
||||
}
|
||||
|
||||
func GetProfileKeypairForTest(includeChatAccount bool, includeDefaultWalletAccount bool, includeAdditionalAccounts bool) *Keypair {
|
||||
kp := &Keypair{
|
||||
KeyUID: "0000000000000000000000000000000000000000000000000000000000000001",
|
||||
Name: "Profile Name",
|
||||
Type: KeypairTypeProfile,
|
||||
DerivedFrom: "0x0001",
|
||||
}
|
||||
|
||||
if includeChatAccount {
|
||||
profileAccount := &Account{
|
||||
Address: types.Address{0x01},
|
||||
KeyUID: kp.KeyUID,
|
||||
Wallet: false,
|
||||
Chat: true,
|
||||
Type: AccountTypeGenerated,
|
||||
Path: "m/43'/60'/1581'/0'/0",
|
||||
PublicKey: types.Hex2Bytes("0x000000001"),
|
||||
Name: "Profile Name",
|
||||
Operable: AccountFullyOperable,
|
||||
ProdPreferredChainIDs: "1",
|
||||
TestPreferredChainIDs: "5",
|
||||
}
|
||||
kp.Accounts = append(kp.Accounts, profileAccount)
|
||||
}
|
||||
|
||||
if includeDefaultWalletAccount {
|
||||
defaultWalletAccount := &Account{
|
||||
Address: types.Address{0x02},
|
||||
KeyUID: kp.KeyUID,
|
||||
Wallet: true,
|
||||
Chat: false,
|
||||
Type: AccountTypeGenerated,
|
||||
Path: "m/44'/60'/0'/0/0",
|
||||
PublicKey: types.Hex2Bytes("0x000000002"),
|
||||
Name: "Generated Acc 1",
|
||||
Emoji: "emoji-1",
|
||||
ColorID: common.CustomizationColorPrimary,
|
||||
Hidden: false,
|
||||
Clock: 0,
|
||||
Removed: false,
|
||||
Operable: AccountFullyOperable,
|
||||
ProdPreferredChainIDs: "1",
|
||||
TestPreferredChainIDs: "5",
|
||||
}
|
||||
kp.Accounts = append(kp.Accounts, defaultWalletAccount)
|
||||
kp.LastUsedDerivationIndex = 0
|
||||
}
|
||||
|
||||
if includeAdditionalAccounts {
|
||||
generatedWalletAccount1 := &Account{
|
||||
Address: types.Address{0x03},
|
||||
KeyUID: kp.KeyUID,
|
||||
Wallet: false,
|
||||
Chat: false,
|
||||
Type: AccountTypeGenerated,
|
||||
Path: "m/44'/60'/0'/0/1",
|
||||
PublicKey: types.Hex2Bytes("0x000000003"),
|
||||
Name: "Generated Acc 2",
|
||||
Emoji: "emoji-2",
|
||||
ColorID: common.CustomizationColorPrimary,
|
||||
Hidden: false,
|
||||
Clock: 0,
|
||||
Removed: false,
|
||||
Operable: AccountFullyOperable,
|
||||
ProdPreferredChainIDs: "1",
|
||||
TestPreferredChainIDs: "5",
|
||||
}
|
||||
kp.Accounts = append(kp.Accounts, generatedWalletAccount1)
|
||||
kp.LastUsedDerivationIndex = 1
|
||||
|
||||
generatedWalletAccount2 := &Account{
|
||||
Address: types.Address{0x04},
|
||||
KeyUID: kp.KeyUID,
|
||||
Wallet: false,
|
||||
Chat: false,
|
||||
Type: AccountTypeGenerated,
|
||||
Path: "m/44'/60'/0'/0/2",
|
||||
PublicKey: types.Hex2Bytes("0x000000004"),
|
||||
Name: "Generated Acc 3",
|
||||
Emoji: "emoji-3",
|
||||
ColorID: common.CustomizationColorPrimary,
|
||||
Hidden: false,
|
||||
Clock: 0,
|
||||
Removed: false,
|
||||
Operable: AccountFullyOperable,
|
||||
ProdPreferredChainIDs: "1",
|
||||
TestPreferredChainIDs: "5",
|
||||
}
|
||||
kp.Accounts = append(kp.Accounts, generatedWalletAccount2)
|
||||
kp.LastUsedDerivationIndex = 2
|
||||
}
|
||||
|
||||
return kp
|
||||
}
|
||||
|
||||
func GetSeedImportedKeypair1ForTest() *Keypair {
|
||||
kp := &Keypair{
|
||||
KeyUID: "0000000000000000000000000000000000000000000000000000000000000002",
|
||||
Name: "Seed Imported 1",
|
||||
Type: KeypairTypeSeed,
|
||||
DerivedFrom: "0x0002",
|
||||
}
|
||||
|
||||
seedGeneratedWalletAccount1 := &Account{
|
||||
Address: types.Address{0x21},
|
||||
KeyUID: kp.KeyUID,
|
||||
Wallet: false,
|
||||
Chat: false,
|
||||
Type: AccountTypeSeed,
|
||||
Path: "m/44'/60'/0'/0/0",
|
||||
PublicKey: types.Hex2Bytes("0x000000021"),
|
||||
Name: "Seed Impo 1 Acc 1",
|
||||
Emoji: "emoji-1",
|
||||
ColorID: common.CustomizationColorPrimary,
|
||||
Hidden: false,
|
||||
Clock: 0,
|
||||
Removed: false,
|
||||
Operable: AccountFullyOperable,
|
||||
}
|
||||
kp.Accounts = append(kp.Accounts, seedGeneratedWalletAccount1)
|
||||
kp.LastUsedDerivationIndex = 0
|
||||
|
||||
seedGeneratedWalletAccount2 := &Account{
|
||||
Address: types.Address{0x22},
|
||||
KeyUID: kp.KeyUID,
|
||||
Wallet: false,
|
||||
Chat: false,
|
||||
Type: AccountTypeSeed,
|
||||
Path: "m/44'/60'/0'/0/1",
|
||||
PublicKey: types.Hex2Bytes("0x000000022"),
|
||||
Name: "Seed Impo 1 Acc 2",
|
||||
Emoji: "emoji-2",
|
||||
ColorID: common.CustomizationColorPrimary,
|
||||
Hidden: false,
|
||||
Clock: 0,
|
||||
Removed: false,
|
||||
Operable: AccountFullyOperable,
|
||||
}
|
||||
kp.Accounts = append(kp.Accounts, seedGeneratedWalletAccount2)
|
||||
kp.LastUsedDerivationIndex = 1
|
||||
|
||||
return kp
|
||||
}
|
||||
|
||||
func GetSeedImportedKeypair2ForTest() *Keypair {
|
||||
kp := &Keypair{
|
||||
KeyUID: "0000000000000000000000000000000000000000000000000000000000000003",
|
||||
Name: "Seed Imported 2",
|
||||
Type: KeypairTypeSeed,
|
||||
DerivedFrom: "0x0003",
|
||||
}
|
||||
|
||||
seedGeneratedWalletAccount1 := &Account{
|
||||
Address: types.Address{0x31},
|
||||
KeyUID: kp.KeyUID,
|
||||
Wallet: false,
|
||||
Chat: false,
|
||||
Type: AccountTypeSeed,
|
||||
Path: "m/44'/60'/0'/0/0",
|
||||
PublicKey: types.Hex2Bytes("0x000000031"),
|
||||
Name: "Seed Impo 2 Acc 1",
|
||||
Emoji: "emoji-1",
|
||||
ColorID: common.CustomizationColorPrimary,
|
||||
Hidden: false,
|
||||
Clock: 0,
|
||||
Removed: false,
|
||||
Operable: AccountFullyOperable,
|
||||
}
|
||||
kp.Accounts = append(kp.Accounts, seedGeneratedWalletAccount1)
|
||||
kp.LastUsedDerivationIndex = 0
|
||||
|
||||
seedGeneratedWalletAccount2 := &Account{
|
||||
Address: types.Address{0x32},
|
||||
KeyUID: kp.KeyUID,
|
||||
Wallet: false,
|
||||
Chat: false,
|
||||
Type: AccountTypeSeed,
|
||||
Path: "m/44'/60'/0'/0/1",
|
||||
PublicKey: types.Hex2Bytes("0x000000032"),
|
||||
Name: "Seed Impo 2 Acc 2",
|
||||
Emoji: "emoji-2",
|
||||
ColorID: common.CustomizationColorPrimary,
|
||||
Hidden: false,
|
||||
Clock: 0,
|
||||
Removed: false,
|
||||
Operable: AccountFullyOperable,
|
||||
}
|
||||
kp.Accounts = append(kp.Accounts, seedGeneratedWalletAccount2)
|
||||
kp.LastUsedDerivationIndex = 1
|
||||
|
||||
return kp
|
||||
}
|
||||
|
||||
func GetPrivKeyImportedKeypairForTest() *Keypair {
|
||||
kp := &Keypair{
|
||||
KeyUID: "0000000000000000000000000000000000000000000000000000000000000004",
|
||||
Name: "Priv Key Imported",
|
||||
Type: KeypairTypeKey,
|
||||
DerivedFrom: "", // no derived from for private key imported kp
|
||||
}
|
||||
|
||||
privKeyWalletAccount := &Account{
|
||||
Address: types.Address{0x41},
|
||||
KeyUID: kp.KeyUID,
|
||||
Wallet: false,
|
||||
Chat: false,
|
||||
Type: AccountTypeKey,
|
||||
Path: "m",
|
||||
PublicKey: types.Hex2Bytes("0x000000041"),
|
||||
Name: "Priv Key Impo Acc",
|
||||
Emoji: "emoji-1",
|
||||
ColorID: common.CustomizationColorPrimary,
|
||||
Hidden: false,
|
||||
Clock: 0,
|
||||
Removed: false,
|
||||
Operable: AccountFullyOperable,
|
||||
}
|
||||
kp.Accounts = append(kp.Accounts, privKeyWalletAccount)
|
||||
|
||||
return kp
|
||||
}
|
||||
|
||||
func GetProfileKeycardForTest() *Keycard {
|
||||
profileKp := GetProfileKeypairForTest(true, true, true)
|
||||
keycard1Addresses := []types.Address{}
|
||||
for _, acc := range profileKp.Accounts {
|
||||
keycard1Addresses = append(keycard1Addresses, acc.Address)
|
||||
}
|
||||
return &Keycard{
|
||||
KeycardUID: "00000000000000000000000000000001",
|
||||
KeycardName: "Card01",
|
||||
KeycardLocked: false,
|
||||
AccountsAddresses: keycard1Addresses,
|
||||
KeyUID: profileKp.KeyUID,
|
||||
Position: 0,
|
||||
}
|
||||
}
|
||||
|
||||
func GetKeycardForSeedImportedKeypair1ForTest() *Keycard {
|
||||
seed1Kp := GetSeedImportedKeypair1ForTest()
|
||||
keycard2Addresses := []types.Address{}
|
||||
for _, acc := range seed1Kp.Accounts {
|
||||
keycard2Addresses = append(keycard2Addresses, acc.Address)
|
||||
}
|
||||
return &Keycard{
|
||||
KeycardUID: "00000000000000000000000000000002",
|
||||
KeycardName: "Card02",
|
||||
KeycardLocked: false,
|
||||
AccountsAddresses: keycard2Addresses,
|
||||
KeyUID: seed1Kp.KeyUID,
|
||||
Position: 1,
|
||||
}
|
||||
}
|
||||
|
||||
func GetKeycardForSeedImportedKeypair2ForTest() *Keycard {
|
||||
seed2Kp := GetSeedImportedKeypair2ForTest()
|
||||
keycard4Addresses := []types.Address{}
|
||||
for _, acc := range seed2Kp.Accounts {
|
||||
keycard4Addresses = append(keycard4Addresses, acc.Address)
|
||||
}
|
||||
return &Keycard{
|
||||
KeycardUID: "00000000000000000000000000000003",
|
||||
KeycardName: "Card03",
|
||||
KeycardLocked: false,
|
||||
AccountsAddresses: keycard4Addresses,
|
||||
KeyUID: seed2Kp.KeyUID,
|
||||
Position: 2,
|
||||
}
|
||||
}
|
||||
|
||||
func Contains[T comparable](container []T, element T, isEqual func(T, T) bool) bool {
|
||||
for _, e := range container {
|
||||
if isEqual(e, element) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func HaveSameElements[T comparable](a []T, b []T, isEqual func(T, T) bool) bool {
|
||||
for _, v := range a {
|
||||
if !Contains(b, v, isEqual) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func SameAccounts(expected, real *Account) bool {
|
||||
return expected.Address == real.Address &&
|
||||
expected.KeyUID == real.KeyUID &&
|
||||
expected.Wallet == real.Wallet &&
|
||||
expected.Chat == real.Chat &&
|
||||
expected.Type == real.Type &&
|
||||
expected.Path == real.Path &&
|
||||
string(expected.PublicKey) == string(real.PublicKey) &&
|
||||
expected.Name == real.Name &&
|
||||
expected.Emoji == real.Emoji &&
|
||||
expected.ColorID == real.ColorID &&
|
||||
expected.Hidden == real.Hidden &&
|
||||
expected.Clock == real.Clock &&
|
||||
expected.Removed == real.Removed &&
|
||||
expected.ProdPreferredChainIDs == real.ProdPreferredChainIDs &&
|
||||
expected.TestPreferredChainIDs == real.TestPreferredChainIDs
|
||||
}
|
||||
|
||||
func SameAccountsIncludingPosition(expected, real *Account) bool {
|
||||
return SameAccounts(expected, real) && expected.Position == real.Position
|
||||
}
|
||||
|
||||
func SameAccountsWithDifferentOperable(expected, real *Account, expectedOperableValue AccountOperable) bool {
|
||||
return SameAccounts(expected, real) && real.Operable == expectedOperableValue
|
||||
}
|
||||
|
||||
func SameKeypairs(expected, real *Keypair) bool {
|
||||
same := expected.KeyUID == real.KeyUID &&
|
||||
expected.Name == real.Name &&
|
||||
expected.Type == real.Type &&
|
||||
expected.DerivedFrom == real.DerivedFrom &&
|
||||
expected.LastUsedDerivationIndex == real.LastUsedDerivationIndex &&
|
||||
expected.Clock == real.Clock &&
|
||||
len(expected.Accounts) == len(real.Accounts)
|
||||
|
||||
if same {
|
||||
for i := range expected.Accounts {
|
||||
found := false
|
||||
for j := range real.Accounts {
|
||||
if SameAccounts(expected.Accounts[i], real.Accounts[j]) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return same
|
||||
}
|
||||
|
||||
func SameKeypairsWithDifferentSyncedFrom(expected, real *Keypair, ignoreSyncedFrom bool, expectedSyncedFromValue string,
|
||||
expectedOperableValue AccountOperable) bool {
|
||||
same := expected.KeyUID == real.KeyUID &&
|
||||
expected.Name == real.Name &&
|
||||
expected.Type == real.Type &&
|
||||
expected.DerivedFrom == real.DerivedFrom &&
|
||||
expected.LastUsedDerivationIndex == real.LastUsedDerivationIndex &&
|
||||
expected.Clock == real.Clock &&
|
||||
len(expected.Accounts) == len(real.Accounts)
|
||||
|
||||
if same && !ignoreSyncedFrom {
|
||||
same = same && real.SyncedFrom == expectedSyncedFromValue
|
||||
}
|
||||
|
||||
if same {
|
||||
for i := range expected.Accounts {
|
||||
found := false
|
||||
for j := range real.Accounts {
|
||||
if SameAccountsWithDifferentOperable(expected.Accounts[i], real.Accounts[j], expectedOperableValue) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return same
|
||||
}
|
||||
|
||||
func SameKeycards(expected, real *Keycard) bool {
|
||||
same := expected.KeycardUID == real.KeycardUID &&
|
||||
expected.KeyUID == real.KeyUID &&
|
||||
expected.KeycardName == real.KeycardName &&
|
||||
expected.KeycardLocked == real.KeycardLocked &&
|
||||
expected.Position == real.Position &&
|
||||
len(expected.AccountsAddresses) == len(real.AccountsAddresses)
|
||||
|
||||
if same {
|
||||
for i := range expected.AccountsAddresses {
|
||||
found := false
|
||||
for j := range real.AccountsAddresses {
|
||||
if expected.AccountsAddresses[i] == real.AccountsAddresses[j] {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return same
|
||||
}
|
||||
24
vendor/github.com/status-im/status-go/multiaccounts/common/const.go
generated
vendored
Normal file
24
vendor/github.com/status-im/status-go/multiaccounts/common/const.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
package common
|
||||
|
||||
type CustomizationColor string
|
||||
|
||||
const (
|
||||
CustomizationColorPrimary CustomizationColor = "primary"
|
||||
CustomizationColorPurple CustomizationColor = "purple"
|
||||
CustomizationColorIndigo CustomizationColor = "indigo"
|
||||
CustomizationColorTurquoise CustomizationColor = "turquoise"
|
||||
CustomizationColorBlue CustomizationColor = "blue"
|
||||
CustomizationColorGreen CustomizationColor = "green"
|
||||
CustomizationColorYellow CustomizationColor = "yellow"
|
||||
CustomizationColorOrange CustomizationColor = "orange"
|
||||
CustomizationColorRed CustomizationColor = "red"
|
||||
CustomizationColorFlamingo CustomizationColor = "flamingo"
|
||||
CustomizationColorBrown CustomizationColor = "brown"
|
||||
CustomizationColorSky CustomizationColor = "sky"
|
||||
CustomizationColorArmy CustomizationColor = "army"
|
||||
CustomizationColorMagenta CustomizationColor = "magenta"
|
||||
CustomizationColorCopper CustomizationColor = "copper"
|
||||
CustomizationColorCamel CustomizationColor = "camel"
|
||||
CustomizationColorYinYang CustomizationColor = "yinyang"
|
||||
CustomizationColorBeige CustomizationColor = "beige"
|
||||
)
|
||||
480
vendor/github.com/status-im/status-go/multiaccounts/database.go
generated
vendored
Normal file
480
vendor/github.com/status-im/status-go/multiaccounts/database.go
generated
vendored
Normal file
@@ -0,0 +1,480 @@
|
||||
package multiaccounts
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/status-im/status-go/common/dbsetup"
|
||||
"github.com/status-im/status-go/images"
|
||||
"github.com/status-im/status-go/multiaccounts/common"
|
||||
"github.com/status-im/status-go/multiaccounts/migrations"
|
||||
"github.com/status-im/status-go/protocol/protobuf"
|
||||
"github.com/status-im/status-go/sqlite"
|
||||
)
|
||||
|
||||
type ColorHash [][2]int
|
||||
|
||||
// Account stores public information about account.
|
||||
type Account struct {
|
||||
Name string `json:"name"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
Identicon string `json:"identicon"`
|
||||
ColorHash ColorHash `json:"colorHash"`
|
||||
ColorID int64 `json:"colorId"`
|
||||
CustomizationColor common.CustomizationColor `json:"customizationColor,omitempty"`
|
||||
KeycardPairing string `json:"keycard-pairing"`
|
||||
KeyUID string `json:"key-uid"`
|
||||
Images []images.IdentityImage `json:"images"`
|
||||
KDFIterations int `json:"kdfIterations,omitempty"`
|
||||
CustomizationColorClock uint64 `json:"-"`
|
||||
}
|
||||
|
||||
func (a *Account) ToProtobuf() *protobuf.MultiAccount {
|
||||
var colorHashes []*protobuf.MultiAccount_ColorHash
|
||||
for _, index := range a.ColorHash {
|
||||
var i []int64
|
||||
for _, is := range index {
|
||||
i = append(i, int64(is))
|
||||
}
|
||||
|
||||
colorHashes = append(colorHashes, &protobuf.MultiAccount_ColorHash{Index: i})
|
||||
}
|
||||
|
||||
var identityImages []*protobuf.MultiAccount_IdentityImage
|
||||
for _, ii := range a.Images {
|
||||
identityImages = append(identityImages, ii.ToProtobuf())
|
||||
}
|
||||
|
||||
return &protobuf.MultiAccount{
|
||||
Name: a.Name,
|
||||
Timestamp: a.Timestamp,
|
||||
Identicon: a.Identicon,
|
||||
ColorHash: colorHashes,
|
||||
ColorId: a.ColorID,
|
||||
CustomizationColor: string(a.CustomizationColor),
|
||||
KeycardPairing: a.KeycardPairing,
|
||||
KeyUid: a.KeyUID,
|
||||
Images: identityImages,
|
||||
CustomizationColorClock: a.CustomizationColorClock,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Account) FromProtobuf(ma *protobuf.MultiAccount) {
|
||||
var colorHash ColorHash
|
||||
for _, index := range ma.ColorHash {
|
||||
var i [2]int
|
||||
for n, is := range index.Index {
|
||||
i[n] = int(is)
|
||||
}
|
||||
|
||||
colorHash = append(colorHash, i)
|
||||
}
|
||||
|
||||
var identityImages []images.IdentityImage
|
||||
for _, ii := range ma.Images {
|
||||
iii := images.IdentityImage{}
|
||||
iii.FromProtobuf(ii)
|
||||
identityImages = append(identityImages, iii)
|
||||
}
|
||||
|
||||
a.Name = ma.Name
|
||||
a.Timestamp = ma.Timestamp
|
||||
a.Identicon = ma.Identicon
|
||||
a.ColorHash = colorHash
|
||||
a.ColorID = ma.ColorId
|
||||
a.KeycardPairing = ma.KeycardPairing
|
||||
a.CustomizationColor = common.CustomizationColor(ma.CustomizationColor)
|
||||
a.KeyUID = ma.KeyUid
|
||||
a.Images = identityImages
|
||||
a.CustomizationColorClock = ma.CustomizationColorClock
|
||||
}
|
||||
|
||||
type MultiAccountMarshaller interface {
|
||||
ToMultiAccount() *Account
|
||||
}
|
||||
|
||||
type IdentityImageSubscriptionChange struct {
|
||||
PublishExpected bool
|
||||
}
|
||||
|
||||
type Database struct {
|
||||
db *sql.DB
|
||||
identityImageSubscriptions []chan *IdentityImageSubscriptionChange
|
||||
}
|
||||
|
||||
// InitializeDB creates db file at a given path and applies migrations.
|
||||
func InitializeDB(path string) (*Database, error) {
|
||||
db, err := sqlite.OpenUnecryptedDB(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = migrations.Migrate(db, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Database{db: db}, nil
|
||||
}
|
||||
|
||||
func (db *Database) Close() error {
|
||||
return db.db.Close()
|
||||
}
|
||||
|
||||
func (db *Database) GetAccountKDFIterationsNumber(keyUID string) (kdfIterationsNumber int, err error) {
|
||||
err = db.db.QueryRow("SELECT kdfIterations FROM accounts WHERE keyUid = ?", keyUID).Scan(&kdfIterationsNumber)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (db *Database) GetAccounts() (rst []Account, err error) {
|
||||
rows, err := db.db.Query("SELECT a.name, a.loginTimestamp, a.identicon, a.colorHash, a.colorId, a.customizationColor, a.customizationColorClock, a.keycardPairing, a.keyUid, a.kdfIterations, ii.name, ii.image_payload, ii.width, ii.height, ii.file_size, ii.resize_target, ii.clock FROM accounts AS a LEFT JOIN identity_images AS ii ON ii.key_uid = a.keyUid ORDER BY loginTimestamp DESC")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
errClose := rows.Close()
|
||||
err = valueOr(err, errClose)
|
||||
}()
|
||||
|
||||
for rows.Next() {
|
||||
acc := Account{}
|
||||
accLoginTimestamp := sql.NullInt64{}
|
||||
accIdenticon := sql.NullString{}
|
||||
accColorHash := sql.NullString{}
|
||||
accColorID := sql.NullInt64{}
|
||||
ii := &images.IdentityImage{}
|
||||
iiName := sql.NullString{}
|
||||
iiWidth := sql.NullInt64{}
|
||||
iiHeight := sql.NullInt64{}
|
||||
iiFileSize := sql.NullInt64{}
|
||||
iiResizeTarget := sql.NullInt64{}
|
||||
iiClock := sql.NullInt64{}
|
||||
|
||||
err = rows.Scan(
|
||||
&acc.Name,
|
||||
&accLoginTimestamp,
|
||||
&accIdenticon,
|
||||
&accColorHash,
|
||||
&accColorID,
|
||||
&acc.CustomizationColor,
|
||||
&acc.CustomizationColorClock,
|
||||
&acc.KeycardPairing,
|
||||
&acc.KeyUID,
|
||||
&acc.KDFIterations,
|
||||
&iiName,
|
||||
&ii.Payload,
|
||||
&iiWidth,
|
||||
&iiHeight,
|
||||
&iiFileSize,
|
||||
&iiResizeTarget,
|
||||
&iiClock,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
acc.Timestamp = accLoginTimestamp.Int64
|
||||
acc.Identicon = accIdenticon.String
|
||||
acc.ColorID = accColorID.Int64
|
||||
if len(accColorHash.String) != 0 {
|
||||
err = json.Unmarshal([]byte(accColorHash.String), &acc.ColorHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
ii.KeyUID = acc.KeyUID
|
||||
ii.Name = iiName.String
|
||||
ii.Width = int(iiWidth.Int64)
|
||||
ii.Height = int(iiHeight.Int64)
|
||||
ii.FileSize = int(iiFileSize.Int64)
|
||||
ii.ResizeTarget = int(iiResizeTarget.Int64)
|
||||
ii.Clock = uint64(iiClock.Int64)
|
||||
|
||||
if ii.Name == "" && len(ii.Payload) == 0 && ii.Width == 0 && ii.Height == 0 && ii.FileSize == 0 && ii.ResizeTarget == 0 {
|
||||
ii = nil
|
||||
}
|
||||
|
||||
// Last index
|
||||
li := len(rst) - 1
|
||||
|
||||
// Don't process nil identity images
|
||||
if ii != nil {
|
||||
// attach the identity image to a previously created account if present, check keyUID matches
|
||||
if len(rst) > 0 && rst[li].KeyUID == acc.KeyUID {
|
||||
rst[li].Images = append(rst[li].Images, *ii)
|
||||
// else attach the identity image to the newly created account
|
||||
} else {
|
||||
acc.Images = append(acc.Images, *ii)
|
||||
}
|
||||
}
|
||||
|
||||
// Append newly created account only if this is the first loop or the keyUID doesn't match
|
||||
if len(rst) == 0 || rst[li].KeyUID != acc.KeyUID {
|
||||
rst = append(rst, acc)
|
||||
}
|
||||
}
|
||||
|
||||
return rst, nil
|
||||
}
|
||||
|
||||
func (db *Database) GetAccount(keyUID string) (*Account, error) {
|
||||
rows, err := db.db.Query("SELECT a.name, a.loginTimestamp, a.identicon, a.colorHash, a.colorId, a.customizationColor, a.customizationColorClock, a.keycardPairing, a.keyUid, a.kdfIterations, ii.key_uid, ii.name, ii.image_payload, ii.width, ii.height, ii.file_size, ii.resize_target, ii.clock FROM accounts AS a LEFT JOIN identity_images AS ii ON ii.key_uid = a.keyUid WHERE a.keyUid = ? ORDER BY loginTimestamp DESC", keyUID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
errClose := rows.Close()
|
||||
err = valueOr(err, errClose)
|
||||
}()
|
||||
|
||||
acc := new(Account)
|
||||
|
||||
for rows.Next() {
|
||||
accLoginTimestamp := sql.NullInt64{}
|
||||
accIdenticon := sql.NullString{}
|
||||
accColorHash := sql.NullString{}
|
||||
accColorID := sql.NullInt64{}
|
||||
ii := &images.IdentityImage{}
|
||||
iiKeyUID := sql.NullString{}
|
||||
iiName := sql.NullString{}
|
||||
iiWidth := sql.NullInt64{}
|
||||
iiHeight := sql.NullInt64{}
|
||||
iiFileSize := sql.NullInt64{}
|
||||
iiResizeTarget := sql.NullInt64{}
|
||||
iiClock := sql.NullInt64{}
|
||||
|
||||
err = rows.Scan(
|
||||
&acc.Name,
|
||||
&accLoginTimestamp,
|
||||
&accIdenticon,
|
||||
&accColorHash,
|
||||
&accColorID,
|
||||
&acc.CustomizationColor,
|
||||
&acc.CustomizationColorClock,
|
||||
&acc.KeycardPairing,
|
||||
&acc.KeyUID,
|
||||
&acc.KDFIterations,
|
||||
&iiKeyUID,
|
||||
&iiName,
|
||||
&ii.Payload,
|
||||
&iiWidth,
|
||||
&iiHeight,
|
||||
&iiFileSize,
|
||||
&iiResizeTarget,
|
||||
&iiClock,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
acc.Timestamp = accLoginTimestamp.Int64
|
||||
acc.Identicon = accIdenticon.String
|
||||
acc.ColorID = accColorID.Int64
|
||||
if len(accColorHash.String) != 0 {
|
||||
err = json.Unmarshal([]byte(accColorHash.String), &acc.ColorHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
ii.KeyUID = iiKeyUID.String
|
||||
ii.Name = iiName.String
|
||||
ii.Width = int(iiWidth.Int64)
|
||||
ii.Height = int(iiHeight.Int64)
|
||||
ii.FileSize = int(iiFileSize.Int64)
|
||||
ii.ResizeTarget = int(iiResizeTarget.Int64)
|
||||
ii.Clock = uint64(iiClock.Int64)
|
||||
|
||||
// Don't process empty identity images
|
||||
if !ii.IsEmpty() {
|
||||
acc.Images = append(acc.Images, *ii)
|
||||
}
|
||||
}
|
||||
|
||||
return acc, nil
|
||||
}
|
||||
|
||||
func (db *Database) SaveAccount(account Account) error {
|
||||
colorHash, err := json.Marshal(account.ColorHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if account.KDFIterations <= 0 {
|
||||
account.KDFIterations = dbsetup.ReducedKDFIterationsNumber
|
||||
}
|
||||
|
||||
_, err = db.db.Exec("INSERT OR REPLACE INTO accounts (name, identicon, colorHash, colorId, customizationColor, customizationColorClock, keycardPairing, keyUid, kdfIterations) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", account.Name, account.Identicon, colorHash, account.ColorID, account.CustomizationColor, account.CustomizationColorClock, account.KeycardPairing, account.KeyUID, account.KDFIterations)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if account.Images == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return db.StoreIdentityImages(account.KeyUID, account.Images, false)
|
||||
}
|
||||
|
||||
func (db *Database) UpdateDisplayName(keyUID string, displayName string) error {
|
||||
_, err := db.db.Exec("UPDATE accounts SET name = ? WHERE keyUid = ?", displayName, keyUID)
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *Database) UpdateAccount(account Account) error {
|
||||
colorHash, err := json.Marshal(account.ColorHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if account.KDFIterations <= 0 {
|
||||
account.KDFIterations = dbsetup.ReducedKDFIterationsNumber
|
||||
}
|
||||
|
||||
_, err = db.db.Exec("UPDATE accounts SET name = ?, identicon = ?, colorHash = ?, colorId = ?, customizationColor = ?, customizationColorClock = ?, keycardPairing = ?, kdfIterations = ? WHERE keyUid = ?", account.Name, account.Identicon, colorHash, account.ColorID, account.CustomizationColor, account.CustomizationColorClock, account.KeycardPairing, account.KDFIterations, account.KeyUID)
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *Database) UpdateAccountKeycardPairing(keyUID string, keycardPairing string) error {
|
||||
_, err := db.db.Exec("UPDATE accounts SET keycardPairing = ? WHERE keyUid = ?", keycardPairing, keyUID)
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *Database) UpdateAccountTimestamp(keyUID string, loginTimestamp int64) error {
|
||||
_, err := db.db.Exec("UPDATE accounts SET loginTimestamp = ? WHERE keyUid = ?", loginTimestamp, keyUID)
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *Database) UpdateAccountCustomizationColor(keyUID string, color string, clock uint64) (int64, error) {
|
||||
result, err := db.db.Exec("UPDATE accounts SET customizationColor = ?, customizationColorClock = ? WHERE keyUid = ? AND customizationColorClock < ?", color, clock, keyUID, clock)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return result.RowsAffected()
|
||||
}
|
||||
|
||||
func (db *Database) DeleteAccount(keyUID string) error {
|
||||
_, err := db.db.Exec("DELETE FROM accounts WHERE keyUid = ?", keyUID)
|
||||
return err
|
||||
}
|
||||
|
||||
// Account images
|
||||
func (db *Database) GetIdentityImages(keyUID string) (iis []*images.IdentityImage, err error) {
|
||||
rows, err := db.db.Query(`SELECT key_uid, name, image_payload, width, height, file_size, resize_target, clock FROM identity_images WHERE key_uid = ?`, keyUID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
errClose := rows.Close()
|
||||
err = valueOr(err, errClose)
|
||||
}()
|
||||
|
||||
for rows.Next() {
|
||||
ii := &images.IdentityImage{}
|
||||
err = rows.Scan(&ii.KeyUID, &ii.Name, &ii.Payload, &ii.Width, &ii.Height, &ii.FileSize, &ii.ResizeTarget, &ii.Clock)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
iis = append(iis, ii)
|
||||
}
|
||||
|
||||
return iis, nil
|
||||
}
|
||||
|
||||
func (db *Database) GetIdentityImage(keyUID, it string) (*images.IdentityImage, error) {
|
||||
var ii images.IdentityImage
|
||||
err := db.db.QueryRow("SELECT key_uid, name, image_payload, width, height, file_size, resize_target, clock FROM identity_images WHERE key_uid = ? AND name = ?", keyUID, it).Scan(&ii.KeyUID, &ii.Name, &ii.Payload, &ii.Width, &ii.Height, &ii.FileSize, &ii.ResizeTarget, &ii.Clock)
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ii, nil
|
||||
}
|
||||
|
||||
func (db *Database) StoreIdentityImages(keyUID string, iis []images.IdentityImage, publish bool) (err error) {
|
||||
// Because SQL INSERTs are triggered in a loop use a tx to ensure a single call to the DB.
|
||||
tx, err := db.db.BeginTx(context.Background(), &sql.TxOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err == nil {
|
||||
err = tx.Commit()
|
||||
return
|
||||
}
|
||||
|
||||
errRollback := tx.Rollback()
|
||||
err = valueOr(err, errRollback)
|
||||
}()
|
||||
|
||||
for i, ii := range iis {
|
||||
if ii.IsEmpty() {
|
||||
continue
|
||||
}
|
||||
iis[i].KeyUID = keyUID
|
||||
_, err := tx.Exec(
|
||||
"INSERT INTO identity_images (key_uid, name, image_payload, width, height, file_size, resize_target, clock) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
keyUID,
|
||||
ii.Name,
|
||||
ii.Payload,
|
||||
ii.Width,
|
||||
ii.Height,
|
||||
ii.FileSize,
|
||||
ii.ResizeTarget,
|
||||
ii.Clock,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
db.publishOnIdentityImageSubscriptions(&IdentityImageSubscriptionChange{
|
||||
PublishExpected: publish,
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *Database) SubscribeToIdentityImageChanges() chan *IdentityImageSubscriptionChange {
|
||||
s := make(chan *IdentityImageSubscriptionChange, 100)
|
||||
db.identityImageSubscriptions = append(db.identityImageSubscriptions, s)
|
||||
return s
|
||||
}
|
||||
|
||||
func (db *Database) publishOnIdentityImageSubscriptions(change *IdentityImageSubscriptionChange) {
|
||||
// Publish on channels, drop if buffer is full
|
||||
for _, s := range db.identityImageSubscriptions {
|
||||
select {
|
||||
case s <- change:
|
||||
default:
|
||||
log.Warn("subscription channel full, dropping message")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (db *Database) DeleteIdentityImage(keyUID string) error {
|
||||
_, err := db.db.Exec(`DELETE FROM identity_images WHERE key_uid = ?`, keyUID)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
db.publishOnIdentityImageSubscriptions(&IdentityImageSubscriptionChange{
|
||||
PublishExpected: true,
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func valueOr(value error, or error) error {
|
||||
if value != nil {
|
||||
return value
|
||||
}
|
||||
return or
|
||||
}
|
||||
19
vendor/github.com/status-im/status-go/multiaccounts/errors/errors.go
generated
vendored
Normal file
19
vendor/github.com/status-im/status-go/multiaccounts/errors/errors.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
package errors
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrWalletNotUnique returned if another account has `wallet` field set to true.
|
||||
ErrWalletNotUnique = errors.New("another account is set to be default wallet. disable it before using new")
|
||||
// ErrChatNotUnique returned if another account has `chat` field set to true.
|
||||
ErrChatNotUnique = errors.New("another account is set to be default chat. disable it before using new")
|
||||
// ErrInvalidConfig returned if config isn't allowed
|
||||
ErrInvalidConfig = errors.New("configuration value not allowed")
|
||||
// ErrNewClockOlderThanCurrent returned if a given clock is older than the current clock
|
||||
ErrNewClockOlderThanCurrent = errors.New("the new clock value is older than the current clock value")
|
||||
// ErrUnrecognisedSyncSettingProtobufType returned if there is no handler or record of a given protobuf.SyncSetting_Type
|
||||
ErrUnrecognisedSyncSettingProtobufType = errors.New("unrecognised protobuf.SyncSetting_Type")
|
||||
ErrDbTransactionIsNil = errors.New("database transaction is nil")
|
||||
)
|
||||
551
vendor/github.com/status-im/status-go/multiaccounts/migrations/bindata.go
generated
vendored
Normal file
551
vendor/github.com/status-im/status-go/multiaccounts/migrations/bindata.go
generated
vendored
Normal file
@@ -0,0 +1,551 @@
|
||||
// Code generated by go-bindata. DO NOT EDIT.
|
||||
// sources:
|
||||
// 0001_accounts.down.sql (21B)
|
||||
// 0001_accounts.up.sql (163B)
|
||||
// 1605007189_identity_images.down.sql (29B)
|
||||
// 1605007189_identity_images.up.sql (268B)
|
||||
// 1606224181_drop_photo_path_from_accounts.down.sql (892B)
|
||||
// 1606224181_drop_photo_path_from_accounts.up.sql (866B)
|
||||
// 1648646095_image_clock.down.sql (939B)
|
||||
// 1648646095_image_clock.up.sql (69B)
|
||||
// 1649317600_add_color_hash.up.sql (201B)
|
||||
// 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)
|
||||
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func bindataRead(data []byte, name string) ([]byte, error) {
|
||||
gz, err := gzip.NewReader(bytes.NewBuffer(data))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read %q: %w", name, err)
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
_, err = io.Copy(&buf, gz)
|
||||
clErr := gz.Close()
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read %q: %w", name, err)
|
||||
}
|
||||
if clErr != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
type asset struct {
|
||||
bytes []byte
|
||||
info os.FileInfo
|
||||
digest [sha256.Size]byte
|
||||
}
|
||||
|
||||
type bindataFileInfo struct {
|
||||
name string
|
||||
size int64
|
||||
mode os.FileMode
|
||||
modTime time.Time
|
||||
}
|
||||
|
||||
func (fi bindataFileInfo) Name() string {
|
||||
return fi.name
|
||||
}
|
||||
func (fi bindataFileInfo) Size() int64 {
|
||||
return fi.size
|
||||
}
|
||||
func (fi bindataFileInfo) Mode() os.FileMode {
|
||||
return fi.mode
|
||||
}
|
||||
func (fi bindataFileInfo) ModTime() time.Time {
|
||||
return fi.modTime
|
||||
}
|
||||
func (fi bindataFileInfo) IsDir() bool {
|
||||
return false
|
||||
}
|
||||
func (fi bindataFileInfo) Sys() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
var __0001_accountsDownSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\x09\xf2\x0f\x50\x08\x71\x74\xf2\x71\x55\x48\x4c\x4e\xce\x2f\xcd\x2b\x29\xb6\xe6\x02\x04\x00\x00\xff\xff\x96\x1e\x13\xa1\x15\x00\x00\x00")
|
||||
|
||||
func _0001_accountsDownSqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
__0001_accountsDownSql,
|
||||
"0001_accounts.down.sql",
|
||||
)
|
||||
}
|
||||
|
||||
func _0001_accountsDownSql() (*asset, error) {
|
||||
bytes, err := _0001_accountsDownSqlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "0001_accounts.down.sql", size: 21, mode: os.FileMode(0644), modTime: time.Unix(1704726861, 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
|
||||
}
|
||||
|
||||
var __0001_accountsUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x1c\xcc\xb1\x6e\x83\x30\x14\x46\xe1\xdd\x4f\xf1\x8f\xad\xe4\x37\xe8\x64\xa8\x5b\xae\x42\x00\x99\x4b\x80\xd1\x02\x04\x56\x82\x8d\xc0\x19\xf2\xf6\x51\x58\x8f\xf4\x9d\xd4\x68\xc5\x1a\xac\x92\x5c\x83\xfe\x50\x94\x0c\xdd\x51\xcd\x35\xec\x30\x84\xa7\x8f\x07\xbe\xc4\x7d\x7a\x35\x6e\xc4\x4d\x99\x34\x53\x06\x95\xa1\xab\x32\x3d\x2e\xba\x97\xc2\xdb\x75\x02\xeb\x8e\x4f\x5b\x34\x79\x2e\xc5\x23\xcc\xce\xb3\x5b\xa7\x23\xda\x75\x43\x42\xff\xa0\x82\xa5\xd8\x96\x10\x43\x65\xe3\x72\x02\xf9\xf9\x0e\x76\x1f\x2b\xeb\x76\xe7\xe7\x33\x8a\x6f\xb4\xc4\x59\xd9\x30\x4c\xd9\xd2\xef\x8f\x78\x07\x00\x00\xff\xff\xab\xcf\xa2\xbd\xa3\x00\x00\x00")
|
||||
|
||||
func _0001_accountsUpSqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
__0001_accountsUpSql,
|
||||
"0001_accounts.up.sql",
|
||||
)
|
||||
}
|
||||
|
||||
func _0001_accountsUpSql() (*asset, error) {
|
||||
bytes, err := _0001_accountsUpSqlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "0001_accounts.up.sql", size: 163, mode: os.FileMode(0644), modTime: time.Unix(1704726861, 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
|
||||
}
|
||||
|
||||
var __1605007189_identity_imagesDownSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\x09\xf2\x0f\x50\x08\x71\x74\xf2\x71\x55\xc8\x4c\x49\xcd\x2b\xc9\x2c\xa9\x8c\xcf\xcc\x4d\x4c\x4f\x2d\xb6\xe6\xe5\x02\x04\x00\x00\xff\xff\xa1\x22\x72\x37\x1d\x00\x00\x00")
|
||||
|
||||
func _1605007189_identity_imagesDownSqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
__1605007189_identity_imagesDownSql,
|
||||
"1605007189_identity_images.down.sql",
|
||||
)
|
||||
}
|
||||
|
||||
func _1605007189_identity_imagesDownSql() (*asset, error) {
|
||||
bytes, err := _1605007189_identity_imagesDownSqlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1605007189_identity_images.down.sql", size: 29, mode: os.FileMode(0644), modTime: time.Unix(1704726861, 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
|
||||
}
|
||||
|
||||
var __1605007189_identity_imagesUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x5c\xce\xc1\x6a\xc3\x30\x10\x04\xd0\xbb\xc1\xff\x30\xc7\x04\xf2\x07\x3d\xc9\xaa\x42\x44\x55\x29\x28\x4a\xd3\x9c\x84\x40\x5b\x7b\x69\xe2\x96\x58\xa5\xb8\x5f\x5f\xea\xfa\x60\x72\xdc\xc7\xec\x30\xd2\x2b\x11\x14\x82\x68\x8c\x82\xde\xc2\xba\x00\xf5\xaa\x0f\xe1\x00\xce\xd4\x17\x2e\x63\xe4\x6b\x6a\x69\x58\xd5\x15\x00\xbc\xd3\x18\xbf\x38\xe3\x45\x78\xb9\x13\x7e\xf3\xaf\x7d\xba\xd2\x1d\x4d\x5f\xf1\x33\x8d\x97\x8f\x94\xd1\x18\xd7\x4c\xe5\xf6\x68\xcc\x9c\xf8\xe6\x5c\x3a\x70\x5f\xe6\xbb\x23\x6e\xbb\xb2\x80\x37\xbe\x50\x1c\xf8\x87\x16\x76\xa3\x3f\x88\x25\xdd\x5a\x5a\x66\xf7\x5e\x3f\x0b\x7f\xc6\x93\x3a\x63\x35\x8f\xdc\x4c\xbb\xd6\x70\x16\xd2\xd9\xad\xd1\x32\xc0\xab\xbd\x11\x52\xd5\xd5\x1a\x27\x1d\x76\xee\x18\xe0\xdd\x49\x3f\x3e\xd4\xd5\x6f\x00\x00\x00\xff\xff\x8c\x6a\x0a\x57\x0c\x01\x00\x00")
|
||||
|
||||
func _1605007189_identity_imagesUpSqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
__1605007189_identity_imagesUpSql,
|
||||
"1605007189_identity_images.up.sql",
|
||||
)
|
||||
}
|
||||
|
||||
func _1605007189_identity_imagesUpSql() (*asset, error) {
|
||||
bytes, err := _1605007189_identity_imagesUpSqlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1605007189_identity_images.up.sql", size: 268, mode: os.FileMode(0644), modTime: time.Unix(1704726861, 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
|
||||
}
|
||||
|
||||
var __1606224181_drop_photo_path_from_accountsDownSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xd4\x93\xc1\x6e\x9c\x30\x18\x84\xef\x3c\xc5\x1c\xdb\x95\x25\x1e\x60\x4f\x04\x9c\xc4\x2a\x0b\xc8\x98\x66\x73\x6a\x1c\xb0\x82\x15\xb0\x11\x6b\x54\xed\xdb\x57\x6b\x58\x76\x8b\xd4\xaa\xd7\x5e\xff\xf9\x7f\xcf\x68\x3e\x39\xdc\x21\xb6\xc3\x19\xae\x55\x90\x75\x6d\x27\xe3\x4e\x70\xf2\xbd\x53\xd0\xc6\x59\x48\x38\xd5\x0f\xf3\x84\x80\x1e\xe3\xb4\x4a\xa8\xdf\x7e\xd3\x8d\x32\x4e\xd7\xd6\xbc\xa1\xb6\xdd\xd4\x1b\x48\xd3\x80\x65\x77\x2b\x43\x6b\x9d\x2d\xa4\x6b\xd7\x95\x5d\x18\xc4\x9c\x46\x82\x42\xd0\x43\x91\xf3\x88\xbf\x42\x44\x0f\x29\x5d\xdd\x7f\xbc\xcb\xfa\x73\x1a\xbe\x04\x00\xf0\xa9\xce\x95\x6e\xf0\x3d\xe2\xf1\x73\xc4\x51\x70\x76\xb8\x5c\x7c\xa3\xaf\xc4\xeb\x46\xf6\x0a\x82\x1e\x05\xb2\x5c\x20\xab\xd2\x74\x9e\x77\xf6\x43\x1b\xa1\x7b\x75\x72\xb2\x1f\xf0\xc0\x9e\xc0\x32\x31\x6b\x6b\x28\x7f\x48\xae\x3e\xb5\x1c\x9b\x42\xea\x51\x9b\x0f\x2f\x04\x5f\xf1\xc2\xc4\x73\x5e\x09\xf0\xfc\x85\x25\xfb\x80\x65\x25\xe5\xe2\xf2\x50\xbe\x4d\x8b\x92\xa6\x34\x16\x4b\x5e\xe2\x73\x91\x4d\x0a\x82\xb5\x31\xb2\x35\x7c\xe4\xf9\x61\x7d\x73\x1f\x04\xe1\x0e\xc9\x68\x07\xdf\xa2\xed\x9a\x2d\x9a\x4b\xd1\xa3\xaa\x47\x25\x9d\xc2\x4f\xed\x5a\xc8\xae\x5b\x2a\x3e\x2d\x94\x58\xf6\xf4\x1b\xa3\x1b\x1c\xaf\xdc\xa1\xd9\x85\x41\xc2\xf3\x62\xc3\x61\xbf\x82\xf2\x63\xf6\xe8\x2b\xa6\x47\x56\x8a\xf2\x96\xe7\x3f\xc1\xf4\x6f\x7c\x56\xcb\xbf\xf3\x59\x98\xcf\x98\x84\x6e\xce\x98\x06\x82\xe6\xca\xeb\xf6\x61\xfe\xd0\xec\xf5\xfe\x57\x00\x00\x00\xff\xff\x72\x67\x20\xf9\x7c\x03\x00\x00")
|
||||
|
||||
func _1606224181_drop_photo_path_from_accountsDownSqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
__1606224181_drop_photo_path_from_accountsDownSql,
|
||||
"1606224181_drop_photo_path_from_accounts.down.sql",
|
||||
)
|
||||
}
|
||||
|
||||
func _1606224181_drop_photo_path_from_accountsDownSql() (*asset, error) {
|
||||
bytes, err := _1606224181_drop_photo_path_from_accountsDownSqlBytes()
|
||||
if err != nil {
|
||||
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)}
|
||||
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
|
||||
}
|
||||
|
||||
var __1606224181_drop_photo_path_from_accountsUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x93\xc1\x8e\x9b\x30\x18\x84\xef\x3c\xc5\x1c\x5b\x64\x89\x07\xc8\x89\x05\x77\xd7\x2a\x01\xe4\x35\xdd\xdd\x53\x71\xc0\x0a\x56\xc0\x46\xc4\xa8\xca\xdb\x57\x01\x42\x54\xd4\x56\xb9\xed\xf5\x1f\xff\xff\x8c\xe6\x93\x03\x1f\x91\xed\x2f\x70\x8d\x82\xac\x2a\x3b\x1a\x77\x86\x93\x87\x56\x41\x1b\x67\x21\xe1\x54\xd7\xcf\x13\x02\xfa\x1e\x25\x45\x4c\xa7\xd7\x65\xdf\x58\x67\x73\xe9\x9a\x12\xd2\xd4\x60\xe9\xac\x95\xba\x56\xc6\xe9\xca\x9a\x12\x95\x6d\xc7\xce\xc0\x0f\xbc\x88\xd3\x50\x50\x08\xba\xcf\x33\x1e\xf2\x0f\x88\xf0\x29\xa1\xab\xe5\xcf\x83\xac\x4e\x63\xff\xc5\x03\x80\x93\xba\x14\xba\xc6\x8f\x90\x47\x2f\x21\x47\xce\xd9\xfe\xba\xf1\x9d\x7e\x90\x49\x37\xb2\x53\x10\xf4\x5d\x20\xcd\x04\xd2\x22\x49\xe6\x79\x6b\x8f\xda\x08\xdd\xa9\xb3\x93\x5d\x8f\x27\xf6\x0c\x96\x8a\x59\x5b\x43\x4d\x8b\xe4\xe6\x53\xc9\xa1\xce\xa5\x1e\xb4\x39\x4e\x82\xf7\x15\x6f\x4c\xbc\x64\x85\x00\xcf\xde\x58\xbc\xf3\x58\xfa\x4a\xb9\xb8\x1e\xca\xb6\x69\xf1\x4a\x13\x1a\x89\x25\x2f\x99\x72\x91\x4d\x0a\x82\xb5\x26\xb2\x35\xfc\xc6\xb3\xfd\x7a\x73\xe7\x79\x81\x8f\x78\xb0\xfd\xd4\xae\x6d\xeb\x2d\x8f\x6b\xc9\x83\xaa\x06\x25\x9d\xc2\x2f\xed\x1a\xc8\xb6\x5d\x2a\x3e\x2f\x68\x58\xfa\xfc\x0f\x30\x93\x72\x47\xe3\x07\x5e\xcc\xb3\x7c\x83\x61\xb7\x72\xfa\x63\xfc\xf9\x58\xf0\x10\x97\xc7\x80\xac\x9e\xff\x07\xb2\x40\x9e\xb9\x08\x5d\x5f\x30\xf6\x04\xf5\x0d\xd0\xfd\x5b\xe0\xef\x5d\xde\xf6\x7f\x07\x00\x00\xff\xff\xc4\x05\x28\x49\x62\x03\x00\x00")
|
||||
|
||||
func _1606224181_drop_photo_path_from_accountsUpSqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
__1606224181_drop_photo_path_from_accountsUpSql,
|
||||
"1606224181_drop_photo_path_from_accounts.up.sql",
|
||||
)
|
||||
}
|
||||
|
||||
func _1606224181_drop_photo_path_from_accountsUpSql() (*asset, error) {
|
||||
bytes, err := _1606224181_drop_photo_path_from_accountsUpSqlBytes()
|
||||
if err != nil {
|
||||
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)}
|
||||
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
|
||||
}
|
||||
|
||||
var __1648646095_image_clockDownSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xdc\x92\xbf\x6e\xdb\x30\x18\xc4\x77\x3e\xc5\x8d\x49\x40\x20\x0f\xe0\x49\x56\x68\x84\x28\x2d\xaa\x14\xd3\x34\x93\xc0\x48\x5f\x25\x22\xfa\x07\x89\x42\xe0\x3e\x7d\x61\xd9\xb0\x6b\xa3\xf5\xd6\xa5\xe3\x77\x3c\x92\x77\xfc\xf1\xf1\x01\xd9\x57\xe5\x03\xa1\xec\x69\x42\xd7\x07\x4c\xf3\x30\xf4\x63\x40\x39\xf6\xc3\xe0\xbb\x0a\x45\xdf\xcc\x6d\x37\x71\xd4\xd4\x15\x84\x4f\x42\x3b\x4f\x01\xc5\x48\x2e\x10\x1c\x02\xb5\x03\x82\x7b\x6f\x08\x0f\x8f\x2c\x36\x22\xb2\x02\x56\x6c\x53\x6d\x22\xf3\x06\x1b\xad\x95\x80\x2f\xa9\x0b\x3e\xec\x72\xdf\xba\x8a\xa6\xfc\xdd\x15\x1f\xf3\x70\xc7\x00\xe0\x83\x76\xf9\xec\x4b\x7c\x8b\x4c\xfc\x1c\x19\xbe\x88\x9d\x6b\xe9\x52\x59\x76\xe6\x83\xdb\x35\xbd\x2b\xb1\x56\x7a\x8d\x44\x5b\x24\x2f\x4a\x1d\x0c\x9f\xbe\x0c\x35\x7c\x17\x0e\x63\x4d\xbe\xaa\xc3\x79\xfe\xe1\x1b\xca\x27\xff\x93\xce\xd2\x48\xfb\x39\x0f\x6e\xac\xe8\x37\x67\x6a\xe4\x76\x1f\xfd\x8b\x78\xc3\xdd\x31\x1d\x5f\x12\xdd\x43\x27\x88\x75\xb2\x51\x32\xb6\x30\x22\x55\x51\x2c\xd8\x3d\x5e\xa5\x7d\xd6\x2f\x16\x46\xbf\xca\xa7\x15\x63\x32\xc9\x84\xb1\x90\x89\xd5\x7f\xa9\x8e\x4c\x28\x11\x5b\x5c\x1c\xcf\x2f\x4b\xf2\x43\x25\x7e\xac\xc2\xcf\x15\xf8\x55\xf4\x8d\xd1\xdb\xeb\x8b\x56\x8c\x3d\x19\x9d\xfe\x19\xc0\x8a\xb1\x13\xaa\x65\x5d\x6e\x96\xd7\x14\xdf\x65\x66\xb3\x6b\xf7\x7f\xcb\xe9\x16\xa8\x7f\x4f\xe8\xf8\x15\x6e\x82\x3a\x79\x7e\x05\x00\x00\xff\xff\xce\x2f\xe3\x37\xab\x03\x00\x00")
|
||||
|
||||
func _1648646095_image_clockDownSqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
__1648646095_image_clockDownSql,
|
||||
"1648646095_image_clock.down.sql",
|
||||
)
|
||||
}
|
||||
|
||||
func _1648646095_image_clockDownSql() (*asset, error) {
|
||||
bytes, err := _1648646095_image_clockDownSqlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1648646095_image_clock.down.sql", size: 939, mode: os.FileMode(0644), modTime: time.Unix(1704726861, 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
|
||||
}
|
||||
|
||||
var __1648646095_image_clockUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\xf4\x09\x71\x0d\x52\x08\x71\x74\xf2\x71\x55\xc8\x4c\x49\xcd\x2b\xc9\x2c\xa9\x8c\xcf\xcc\x4d\x4c\x4f\x2d\x56\x70\x74\x71\x51\x70\xf6\xf7\x09\xf5\xf5\x53\x48\xce\xc9\x4f\xce\x56\xf0\xf4\x0b\x51\xf0\xf3\x0f\x51\xf0\x0b\xf5\xf1\x51\x70\x71\x75\x73\x0c\xf5\x09\x51\x30\xb0\xe6\x02\x04\x00\x00\xff\xff\x22\x35\x20\xbf\x45\x00\x00\x00")
|
||||
|
||||
func _1648646095_image_clockUpSqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
__1648646095_image_clockUpSql,
|
||||
"1648646095_image_clock.up.sql",
|
||||
)
|
||||
}
|
||||
|
||||
func _1648646095_image_clockUpSql() (*asset, error) {
|
||||
bytes, err := _1648646095_image_clockUpSqlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1648646095_image_clock.up.sql", size: 69, mode: os.FileMode(0644), modTime: time.Unix(1704726861, 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
|
||||
}
|
||||
|
||||
var __1649317600_add_color_hashUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\xf4\x09\x71\x0d\x52\x08\x71\x74\xf2\x71\x55\x48\x4c\x4e\xce\x2f\xcd\x2b\x29\x56\x70\x74\x71\x51\x70\xf6\xf7\x09\xf5\xf5\x53\x48\xce\xcf\xc9\x2f\xf2\x48\x2c\xce\x50\x08\x71\x8d\x08\x51\xf0\xf3\x0f\x51\xf0\x0b\xf5\xf1\x51\x70\x71\x75\x73\x0c\xf5\x09\x51\x50\x52\xb2\xe6\x22\xca\x0c\xcf\x14\x05\x4f\x3f\x2c\x06\x18\x58\x73\x85\x06\xb8\x38\x86\x20\x69\x0d\x76\x0d\x41\xb2\xd7\x16\x6c\x07\x4e\x35\x9e\x29\x0a\xb6\x20\x43\x00\x01\x00\x00\xff\xff\xfa\xaf\xaf\xd9\xc9\x00\x00\x00")
|
||||
|
||||
func _1649317600_add_color_hashUpSqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
__1649317600_add_color_hashUpSql,
|
||||
"1649317600_add_color_hash.up.sql",
|
||||
)
|
||||
}
|
||||
|
||||
func _1649317600_add_color_hashUpSql() (*asset, error) {
|
||||
bytes, err := _1649317600_add_color_hashUpSqlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1649317600_add_color_hash.up.sql", size: 201, mode: os.FileMode(0644), modTime: time.Unix(1704726861, 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
|
||||
}
|
||||
|
||||
var __1660238799_accounts_kdfUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\xf4\x09\x71\x0d\x52\x08\x71\x74\xf2\x71\x55\x48\x4c\x4e\xce\x2f\xcd\x2b\x29\x56\x70\x74\x71\x51\x70\xf6\xf7\x09\xf5\xf5\x53\xc8\x4e\x49\xf3\x2c\x49\x2d\x4a\x2c\xc9\xcc\xcf\x2b\x56\xf0\xf4\x0b\x51\xf0\xf3\x0f\x51\xf0\x0b\xf5\xf1\x51\x70\x71\x75\x73\x0c\xf5\x09\x51\x30\x36\x32\x30\xb0\xe6\x0a\x0d\x70\x71\x0c\x41\x32\x23\xd8\x35\x04\x4d\xb3\x2d\x54\x25\x20\x00\x00\xff\xff\x37\x9c\xbc\xd5\x73\x00\x00\x00")
|
||||
|
||||
func _1660238799_accounts_kdfUpSqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
__1660238799_accounts_kdfUpSql,
|
||||
"1660238799_accounts_kdf.up.sql",
|
||||
)
|
||||
}
|
||||
|
||||
func _1660238799_accounts_kdfUpSql() (*asset, error) {
|
||||
bytes, err := _1660238799_accounts_kdfUpSqlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1660238799_accounts_kdf.up.sql", size: 115, mode: os.FileMode(0644), modTime: time.Unix(1704726861, 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
|
||||
}
|
||||
|
||||
var __1679505708_add_customization_colorUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\xf4\x09\x71\x0d\x52\x08\x71\x74\xf2\x71\x55\x48\x4c\x4e\xce\x2f\xcd\x2b\x29\x56\x70\x74\x71\x51\x70\xf6\xf7\x09\xf5\xf5\x53\x48\x2e\x2d\x2e\xc9\xcf\xcd\xac\x4a\x2c\xc9\xcc\xcf\x73\xce\xcf\xc9\x2f\x52\x08\x73\x0c\x72\xf6\x70\x0c\x52\x70\x71\x75\x73\x0c\xf5\x09\x51\x50\x2a\x28\xca\xcc\x4d\x2c\xaa\x54\xb2\xe6\x02\x04\x00\x00\xff\xff\x08\xb6\x89\xf4\x4e\x00\x00\x00")
|
||||
|
||||
func _1679505708_add_customization_colorUpSqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
__1679505708_add_customization_colorUpSql,
|
||||
"1679505708_add_customization_color.up.sql",
|
||||
)
|
||||
}
|
||||
|
||||
func _1679505708_add_customization_colorUpSql() (*asset, error) {
|
||||
bytes, err := _1679505708_add_customization_colorUpSqlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1679505708_add_customization_color.up.sql", size: 78, mode: os.FileMode(0644), modTime: time.Unix(1704726861, 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
|
||||
}
|
||||
|
||||
var __1687853321_add_customization_color_updated_atUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x04\xc0\x31\x0a\x43\x21\x0c\x06\xe0\xbd\xa7\xf8\x8f\xd0\xbd\x53\xaa\x16\x0a\x69\x84\x12\x0f\x20\x99\xa4\xd6\xc0\x53\x97\x77\xfa\xf7\x11\x6b\xfa\x42\xe9\xc9\x09\xd5\xcc\xf7\x58\x13\x14\x23\x42\xe6\xf2\x11\xd8\x9e\xcb\xff\xed\xac\xab\xf9\x08\xde\xfd\x08\xdd\xed\x87\xb7\x28\x24\x2b\xa4\x30\x23\xa6\x17\x15\x56\xdc\x1f\xb7\x2b\x00\x00\xff\xff\xfd\x48\x7a\xa4\x50\x00\x00\x00")
|
||||
|
||||
func _1687853321_add_customization_color_updated_atUpSqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
__1687853321_add_customization_color_updated_atUpSql,
|
||||
"1687853321_add_customization_color_updated_at.up.sql",
|
||||
)
|
||||
}
|
||||
|
||||
func _1687853321_add_customization_color_updated_atUpSql() (*asset, error) {
|
||||
bytes, err := _1687853321_add_customization_color_updated_atUpSqlBytes()
|
||||
if err != nil {
|
||||
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)}
|
||||
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")
|
||||
|
||||
func docGoBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
_docGo,
|
||||
"doc.go",
|
||||
)
|
||||
}
|
||||
|
||||
func docGo() (*asset, error) {
|
||||
bytes, err := docGoBytes()
|
||||
if err != nil {
|
||||
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}}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
// Asset loads and returns the asset for the given name.
|
||||
// It returns an error if the asset could not be found or
|
||||
// could not be loaded.
|
||||
func Asset(name string) ([]byte, error) {
|
||||
canonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
if f, ok := _bindata[canonicalName]; ok {
|
||||
a, err := f()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err)
|
||||
}
|
||||
return a.bytes, nil
|
||||
}
|
||||
return nil, fmt.Errorf("Asset %s not found", name)
|
||||
}
|
||||
|
||||
// AssetString returns the asset contents as a string (instead of a []byte).
|
||||
func AssetString(name string) (string, error) {
|
||||
data, err := Asset(name)
|
||||
return string(data), err
|
||||
}
|
||||
|
||||
// MustAsset is like Asset but panics when Asset would return an error.
|
||||
// It simplifies safe initialization of global variables.
|
||||
func MustAsset(name string) []byte {
|
||||
a, err := Asset(name)
|
||||
if err != nil {
|
||||
panic("asset: Asset(" + name + "): " + err.Error())
|
||||
}
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
// MustAssetString is like AssetString but panics when Asset would return an
|
||||
// error. It simplifies safe initialization of global variables.
|
||||
func MustAssetString(name string) string {
|
||||
return string(MustAsset(name))
|
||||
}
|
||||
|
||||
// AssetInfo loads and returns the asset info for the given name.
|
||||
// It returns an error if the asset could not be found or
|
||||
// could not be loaded.
|
||||
func AssetInfo(name string) (os.FileInfo, error) {
|
||||
canonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
if f, ok := _bindata[canonicalName]; ok {
|
||||
a, err := f()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err)
|
||||
}
|
||||
return a.info, nil
|
||||
}
|
||||
return nil, fmt.Errorf("AssetInfo %s not found", name)
|
||||
}
|
||||
|
||||
// AssetDigest returns the digest of the file with the given name. It returns an
|
||||
// error if the asset could not be found or the digest could not be loaded.
|
||||
func AssetDigest(name string) ([sha256.Size]byte, error) {
|
||||
canonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
if f, ok := _bindata[canonicalName]; ok {
|
||||
a, err := f()
|
||||
if err != nil {
|
||||
return [sha256.Size]byte{}, fmt.Errorf("AssetDigest %s can't read by error: %v", name, err)
|
||||
}
|
||||
return a.digest, nil
|
||||
}
|
||||
return [sha256.Size]byte{}, fmt.Errorf("AssetDigest %s not found", name)
|
||||
}
|
||||
|
||||
// Digests returns a map of all known files and their checksums.
|
||||
func Digests() (map[string][sha256.Size]byte, error) {
|
||||
mp := make(map[string][sha256.Size]byte, len(_bindata))
|
||||
for name := range _bindata {
|
||||
a, err := _bindata[name]()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mp[name] = a.digest
|
||||
}
|
||||
return mp, nil
|
||||
}
|
||||
|
||||
// AssetNames returns the names of the assets.
|
||||
func AssetNames() []string {
|
||||
names := make([]string, 0, len(_bindata))
|
||||
for name := range _bindata {
|
||||
names = append(names, name)
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
// _bindata is a table, holding each asset generator, mapped to its name.
|
||||
var _bindata = map[string]func() (*asset, error){
|
||||
"0001_accounts.down.sql": _0001_accountsDownSql,
|
||||
"0001_accounts.up.sql": _0001_accountsUpSql,
|
||||
"1605007189_identity_images.down.sql": _1605007189_identity_imagesDownSql,
|
||||
"1605007189_identity_images.up.sql": _1605007189_identity_imagesUpSql,
|
||||
"1606224181_drop_photo_path_from_accounts.down.sql": _1606224181_drop_photo_path_from_accountsDownSql,
|
||||
"1606224181_drop_photo_path_from_accounts.up.sql": _1606224181_drop_photo_path_from_accountsUpSql,
|
||||
"1648646095_image_clock.down.sql": _1648646095_image_clockDownSql,
|
||||
"1648646095_image_clock.up.sql": _1648646095_image_clockUpSql,
|
||||
"1649317600_add_color_hash.up.sql": _1649317600_add_color_hashUpSql,
|
||||
"1660238799_accounts_kdf.up.sql": _1660238799_accounts_kdfUpSql,
|
||||
"1679505708_add_customization_color.up.sql": _1679505708_add_customization_colorUpSql,
|
||||
"1687853321_add_customization_color_updated_at.up.sql": _1687853321_add_customization_color_updated_atUpSql,
|
||||
"doc.go": docGo,
|
||||
}
|
||||
|
||||
// AssetDebug is true if the assets were built with the debug flag enabled.
|
||||
const AssetDebug = false
|
||||
|
||||
// AssetDir returns the file names below a certain
|
||||
// directory embedded in the file by go-bindata.
|
||||
// For example if you run go-bindata on data/... and data contains the
|
||||
// following hierarchy:
|
||||
//
|
||||
// data/
|
||||
// foo.txt
|
||||
// img/
|
||||
// a.png
|
||||
// b.png
|
||||
//
|
||||
// then AssetDir("data") would return []string{"foo.txt", "img"},
|
||||
// AssetDir("data/img") would return []string{"a.png", "b.png"},
|
||||
// AssetDir("foo.txt") and AssetDir("notexist") would return an error, and
|
||||
// AssetDir("") will return []string{"data"}.
|
||||
func AssetDir(name string) ([]string, error) {
|
||||
node := _bintree
|
||||
if len(name) != 0 {
|
||||
canonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
pathList := strings.Split(canonicalName, "/")
|
||||
for _, p := range pathList {
|
||||
node = node.Children[p]
|
||||
if node == nil {
|
||||
return nil, fmt.Errorf("Asset %s not found", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
if node.Func != nil {
|
||||
return nil, fmt.Errorf("Asset %s not found", name)
|
||||
}
|
||||
rv := make([]string, 0, len(node.Children))
|
||||
for childName := range node.Children {
|
||||
rv = append(rv, childName)
|
||||
}
|
||||
return rv, nil
|
||||
}
|
||||
|
||||
type bintree struct {
|
||||
Func func() (*asset, error)
|
||||
Children map[string]*bintree
|
||||
}
|
||||
|
||||
var _bintree = &bintree{nil, map[string]*bintree{
|
||||
"0001_accounts.down.sql": {_0001_accountsDownSql, map[string]*bintree{}},
|
||||
"0001_accounts.up.sql": {_0001_accountsUpSql, map[string]*bintree{}},
|
||||
"1605007189_identity_images.down.sql": {_1605007189_identity_imagesDownSql, map[string]*bintree{}},
|
||||
"1605007189_identity_images.up.sql": {_1605007189_identity_imagesUpSql, map[string]*bintree{}},
|
||||
"1606224181_drop_photo_path_from_accounts.down.sql": {_1606224181_drop_photo_path_from_accountsDownSql, map[string]*bintree{}},
|
||||
"1606224181_drop_photo_path_from_accounts.up.sql": {_1606224181_drop_photo_path_from_accountsUpSql, map[string]*bintree{}},
|
||||
"1648646095_image_clock.down.sql": {_1648646095_image_clockDownSql, map[string]*bintree{}},
|
||||
"1648646095_image_clock.up.sql": {_1648646095_image_clockUpSql, map[string]*bintree{}},
|
||||
"1649317600_add_color_hash.up.sql": {_1649317600_add_color_hashUpSql, map[string]*bintree{}},
|
||||
"1660238799_accounts_kdf.up.sql": {_1660238799_accounts_kdfUpSql, map[string]*bintree{}},
|
||||
"1679505708_add_customization_color.up.sql": {_1679505708_add_customization_colorUpSql, map[string]*bintree{}},
|
||||
"1687853321_add_customization_color_updated_at.up.sql": {_1687853321_add_customization_color_updated_atUpSql, map[string]*bintree{}},
|
||||
"doc.go": {docGo, map[string]*bintree{}},
|
||||
}}
|
||||
|
||||
// RestoreAsset restores an asset under the given directory.
|
||||
func RestoreAsset(dir, name string) error {
|
||||
data, err := Asset(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
info, err := AssetInfo(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime())
|
||||
}
|
||||
|
||||
// RestoreAssets restores an asset under the given directory recursively.
|
||||
func RestoreAssets(dir, name string) error {
|
||||
children, err := AssetDir(name)
|
||||
// File
|
||||
if err != nil {
|
||||
return RestoreAsset(dir, name)
|
||||
}
|
||||
// Dir
|
||||
for _, child := range children {
|
||||
err = RestoreAssets(dir, filepath.Join(name, child))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func _filePath(dir, name string) string {
|
||||
canonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
return filepath.Join(append([]string{dir}, strings.Split(canonicalName, "/")...)...)
|
||||
}
|
||||
20
vendor/github.com/status-im/status-go/multiaccounts/migrations/migrate.go
generated
vendored
Normal file
20
vendor/github.com/status-im/status-go/multiaccounts/migrations/migrate.go
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
||||
bindata "github.com/status-im/migrate/v4/source/go_bindata"
|
||||
|
||||
"github.com/status-im/status-go/sqlite"
|
||||
)
|
||||
|
||||
// Migrate applies migrations.
|
||||
// see Migrate in vendor/status-go/sqlite/migrate.go
|
||||
func Migrate(db *sql.DB, customSteps []*sqlite.PostStep) error {
|
||||
return sqlite.Migrate(db, bindata.Resource(
|
||||
AssetNames(),
|
||||
func(name string) ([]byte, error) {
|
||||
return Asset(name)
|
||||
},
|
||||
), customSteps, nil)
|
||||
}
|
||||
602
vendor/github.com/status-im/status-go/multiaccounts/settings/columns.go
generated
vendored
Normal file
602
vendor/github.com/status-im/status-go/multiaccounts/settings/columns.go
generated
vendored
Normal file
@@ -0,0 +1,602 @@
|
||||
package settings
|
||||
|
||||
import (
|
||||
"github.com/status-im/status-go/multiaccounts/errors"
|
||||
"github.com/status-im/status-go/protocol/protobuf"
|
||||
)
|
||||
|
||||
const (
|
||||
DBColumnMnemonic = "mnemonic"
|
||||
)
|
||||
|
||||
var (
|
||||
AnonMetricsShouldSend = SettingField{
|
||||
reactFieldName: "anon-metrics/should-send?",
|
||||
dBColumnName: "anon_metrics_should_send",
|
||||
valueHandler: BoolHandler,
|
||||
}
|
||||
Appearance = SettingField{
|
||||
reactFieldName: "appearance",
|
||||
dBColumnName: "appearance",
|
||||
}
|
||||
AutoMessageEnabled = SettingField{
|
||||
reactFieldName: "auto-message-enabled?",
|
||||
dBColumnName: "auto_message_enabled",
|
||||
valueHandler: BoolHandler,
|
||||
}
|
||||
BackupEnabled = SettingField{
|
||||
reactFieldName: "backup-enabled?",
|
||||
dBColumnName: "backup_enabled",
|
||||
valueHandler: BoolHandler,
|
||||
}
|
||||
BackupFetched = SettingField{
|
||||
reactFieldName: "backup-fetched?",
|
||||
dBColumnName: "backup_fetched",
|
||||
valueHandler: BoolHandler,
|
||||
}
|
||||
ChaosMode = SettingField{
|
||||
reactFieldName: "chaos-mode?",
|
||||
dBColumnName: "chaos_mode",
|
||||
valueHandler: BoolHandler,
|
||||
}
|
||||
Currency = SettingField{
|
||||
reactFieldName: "currency",
|
||||
dBColumnName: "currency",
|
||||
syncProtobufFactory: &SyncProtobufFactory{
|
||||
fromInterface: currencyProtobufFactory,
|
||||
fromStruct: currencyProtobufFactoryStruct,
|
||||
valueFromProtobuf: StringFromSyncProtobuf,
|
||||
protobufType: protobuf.SyncSetting_CURRENCY,
|
||||
},
|
||||
}
|
||||
CurrentUserStatus = SettingField{
|
||||
reactFieldName: "current-user-status",
|
||||
dBColumnName: "current_user_status",
|
||||
valueHandler: JSONBlobHandler,
|
||||
}
|
||||
CustomBootNodes = SettingField{
|
||||
reactFieldName: "custom-bootnodes",
|
||||
dBColumnName: "custom_bootnodes",
|
||||
valueHandler: JSONBlobHandler,
|
||||
}
|
||||
CustomBootNodesEnabled = SettingField{
|
||||
reactFieldName: "custom-bootnodes-enabled?",
|
||||
dBColumnName: "custom_bootnodes_enabled",
|
||||
valueHandler: JSONBlobHandler,
|
||||
}
|
||||
DappsAddress = SettingField{
|
||||
reactFieldName: "dapps-address",
|
||||
dBColumnName: "dapps_address",
|
||||
valueHandler: AddressHandler,
|
||||
}
|
||||
DefaultSyncPeriod = SettingField{
|
||||
reactFieldName: "default-sync-period",
|
||||
dBColumnName: "default_sync_period",
|
||||
}
|
||||
DeviceName = SettingField{
|
||||
reactFieldName: "device-name",
|
||||
dBColumnName: "device_name",
|
||||
}
|
||||
DisplayName = SettingField{
|
||||
reactFieldName: "display-name",
|
||||
dBColumnName: "display_name",
|
||||
syncProtobufFactory: &SyncProtobufFactory{
|
||||
fromInterface: displayNameProtobufFactory,
|
||||
fromStruct: displayNameProtobufFactoryStruct,
|
||||
valueFromProtobuf: StringFromSyncProtobuf,
|
||||
protobufType: protobuf.SyncSetting_DISPLAY_NAME,
|
||||
},
|
||||
}
|
||||
Bio = SettingField{
|
||||
reactFieldName: "bio",
|
||||
dBColumnName: "bio",
|
||||
syncProtobufFactory: &SyncProtobufFactory{
|
||||
fromInterface: bioProtobufFactory,
|
||||
fromStruct: bioProtobufFactoryStruct,
|
||||
valueFromProtobuf: StringFromSyncProtobuf,
|
||||
protobufType: protobuf.SyncSetting_BIO,
|
||||
},
|
||||
}
|
||||
EIP1581Address = SettingField{
|
||||
reactFieldName: "eip1581-address",
|
||||
dBColumnName: "eip1581_address",
|
||||
valueHandler: AddressHandler,
|
||||
}
|
||||
Fleet = SettingField{
|
||||
reactFieldName: "fleet",
|
||||
dBColumnName: "fleet",
|
||||
}
|
||||
GifAPIKey = SettingField{
|
||||
reactFieldName: "gifs/api-key",
|
||||
dBColumnName: "gif_api_key",
|
||||
}
|
||||
GifFavourites = SettingField{
|
||||
reactFieldName: "gifs/favorite-gifs",
|
||||
dBColumnName: "gif_favorites",
|
||||
valueHandler: JSONBlobHandler,
|
||||
// TODO resolve issue 8 https://github.com/status-im/status-mobile/pull/13053#issuecomment-1065179963
|
||||
// The reported issue is not directly related, but I suspect that gifs suffer the same issue
|
||||
syncProtobufFactory: &SyncProtobufFactory{
|
||||
inactive: true, // Remove after issue is resolved
|
||||
fromInterface: gifFavouritesProtobufFactory,
|
||||
fromStruct: gifFavouritesProtobufFactoryStruct,
|
||||
valueFromProtobuf: BytesFromSyncProtobuf,
|
||||
protobufType: protobuf.SyncSetting_GIF_FAVOURITES,
|
||||
},
|
||||
}
|
||||
GifRecents = SettingField{
|
||||
reactFieldName: "gifs/recent-gifs",
|
||||
dBColumnName: "gif_recents",
|
||||
valueHandler: JSONBlobHandler,
|
||||
// TODO resolve issue 8 https://github.com/status-im/status-mobile/pull/13053#issuecomment-1065179963
|
||||
// The reported issue is not directly related, but I suspect that gifs suffer the same issue
|
||||
syncProtobufFactory: &SyncProtobufFactory{
|
||||
inactive: true, // Remove after issue is resolved
|
||||
fromInterface: gifRecentsProtobufFactory,
|
||||
fromStruct: gifRecentsProtobufFactoryStruct,
|
||||
valueFromProtobuf: BytesFromSyncProtobuf,
|
||||
protobufType: protobuf.SyncSetting_GIF_RECENTS,
|
||||
},
|
||||
}
|
||||
HideHomeTooltip = SettingField{
|
||||
reactFieldName: "hide-home-tooltip?",
|
||||
dBColumnName: "hide_home_tooltip",
|
||||
valueHandler: BoolHandler,
|
||||
}
|
||||
KeycardInstanceUID = SettingField{
|
||||
reactFieldName: "keycard-instance_uid",
|
||||
dBColumnName: "keycard_instance_uid",
|
||||
}
|
||||
KeycardPairedOn = SettingField{
|
||||
reactFieldName: "keycard-paired_on",
|
||||
dBColumnName: "keycard_paired_on",
|
||||
}
|
||||
KeycardPairing = SettingField{
|
||||
reactFieldName: "keycard-pairing",
|
||||
dBColumnName: "keycard_pairing",
|
||||
}
|
||||
LastBackup = SettingField{
|
||||
reactFieldName: "last-backup",
|
||||
dBColumnName: "last_backup",
|
||||
}
|
||||
LastUpdated = SettingField{
|
||||
reactFieldName: "last-updated",
|
||||
dBColumnName: "last_updated",
|
||||
}
|
||||
LatestDerivedPath = SettingField{
|
||||
reactFieldName: "latest-derived-path",
|
||||
dBColumnName: "latest_derived_path",
|
||||
}
|
||||
LinkPreviewRequestEnabled = SettingField{
|
||||
reactFieldName: "link-preview-request-enabled",
|
||||
dBColumnName: "link_preview_request_enabled",
|
||||
valueHandler: BoolHandler,
|
||||
}
|
||||
LinkPreviewsEnabledSites = SettingField{
|
||||
reactFieldName: "link-previews-enabled-sites",
|
||||
dBColumnName: "link_previews_enabled_sites",
|
||||
valueHandler: JSONBlobHandler,
|
||||
}
|
||||
LogLevel = SettingField{
|
||||
reactFieldName: "log-level",
|
||||
dBColumnName: "log_level",
|
||||
}
|
||||
MessagesFromContactsOnly = SettingField{
|
||||
reactFieldName: "messages-from-contacts-only",
|
||||
dBColumnName: "messages_from_contacts_only",
|
||||
valueHandler: BoolHandler,
|
||||
syncProtobufFactory: &SyncProtobufFactory{
|
||||
fromInterface: messagesFromContactsOnlyProtobufFactory,
|
||||
fromStruct: messagesFromContactsOnlyProtobufFactoryStruct,
|
||||
valueFromProtobuf: BoolFromSyncProtobuf,
|
||||
protobufType: protobuf.SyncSetting_MESSAGES_FROM_CONTACTS_ONLY,
|
||||
},
|
||||
}
|
||||
Mnemonic = SettingField{
|
||||
reactFieldName: DBColumnMnemonic,
|
||||
dBColumnName: DBColumnMnemonic,
|
||||
}
|
||||
|
||||
MnemonicRemoved = SettingField{
|
||||
reactFieldName: "mnemonic-removed?",
|
||||
dBColumnName: "mnemonic_removed",
|
||||
valueHandler: BoolHandler,
|
||||
syncProtobufFactory: &SyncProtobufFactory{
|
||||
fromInterface: mnemonicRemovedProtobufFactory,
|
||||
fromStruct: mnemonicRemovedProtobufFactoryStruct,
|
||||
valueFromProtobuf: BoolFromSyncProtobuf,
|
||||
protobufType: protobuf.SyncSetting_MNEMONIC_REMOVED,
|
||||
},
|
||||
}
|
||||
|
||||
MutualContactEnabled = SettingField{
|
||||
reactFieldName: "mutual-contact-enabled?",
|
||||
dBColumnName: "mutual_contact_enabled",
|
||||
valueHandler: BoolHandler,
|
||||
}
|
||||
Name = SettingField{
|
||||
reactFieldName: "name",
|
||||
dBColumnName: "name",
|
||||
}
|
||||
NetworksCurrentNetwork = SettingField{
|
||||
reactFieldName: "networks/current-network",
|
||||
dBColumnName: "current_network",
|
||||
}
|
||||
NetworksNetworks = SettingField{
|
||||
reactFieldName: "networks/networks",
|
||||
dBColumnName: "networks",
|
||||
valueHandler: JSONBlobHandler,
|
||||
}
|
||||
NodeConfig = SettingField{
|
||||
reactFieldName: "node-config",
|
||||
dBColumnName: "node_config",
|
||||
valueHandler: NodeConfigHandler,
|
||||
}
|
||||
// NotificationsEnabled - we should remove this and realated things once mobile team starts usign `settings_notifications` package
|
||||
NotificationsEnabled = SettingField{
|
||||
reactFieldName: "notifications-enabled?",
|
||||
dBColumnName: "notifications_enabled",
|
||||
valueHandler: BoolHandler,
|
||||
}
|
||||
OpenseaEnabled = SettingField{
|
||||
reactFieldName: "opensea-enabled?",
|
||||
dBColumnName: "opensea_enabled",
|
||||
valueHandler: BoolHandler,
|
||||
}
|
||||
PhotoPath = SettingField{
|
||||
reactFieldName: "photo-path",
|
||||
dBColumnName: "photo_path",
|
||||
}
|
||||
PinnedMailservers = SettingField{
|
||||
reactFieldName: "pinned-mailservers",
|
||||
dBColumnName: "pinned_mailservers",
|
||||
valueHandler: JSONBlobHandler,
|
||||
}
|
||||
PreferredName = SettingField{
|
||||
reactFieldName: "preferred-name",
|
||||
dBColumnName: "preferred_name",
|
||||
syncProtobufFactory: &SyncProtobufFactory{
|
||||
fromInterface: preferredNameProtobufFactory,
|
||||
fromStruct: preferredNameProtobufFactoryStruct,
|
||||
valueFromProtobuf: StringFromSyncProtobuf,
|
||||
protobufType: protobuf.SyncSetting_PREFERRED_NAME,
|
||||
},
|
||||
}
|
||||
PreviewPrivacy = SettingField{
|
||||
reactFieldName: "preview-privacy?",
|
||||
dBColumnName: "preview_privacy",
|
||||
valueHandler: BoolHandler,
|
||||
// TODO resolved issue 7 https://github.com/status-im/status-mobile/pull/13053#issuecomment-1065179963
|
||||
syncProtobufFactory: &SyncProtobufFactory{
|
||||
inactive: true, // Remove after issue is resolved
|
||||
fromInterface: previewPrivacyProtobufFactory,
|
||||
fromStruct: previewPrivacyProtobufFactoryStruct,
|
||||
valueFromProtobuf: BoolFromSyncProtobuf,
|
||||
protobufType: protobuf.SyncSetting_PREVIEW_PRIVACY,
|
||||
},
|
||||
}
|
||||
ProfilePicturesShowTo = SettingField{
|
||||
reactFieldName: "profile-pictures-show-to",
|
||||
dBColumnName: "profile_pictures_show_to",
|
||||
syncProtobufFactory: &SyncProtobufFactory{
|
||||
fromInterface: profilePicturesShowToProtobufFactory,
|
||||
fromStruct: profilePicturesShowToProtobufFactoryStruct,
|
||||
valueFromProtobuf: Int64FromSyncProtobuf,
|
||||
protobufType: protobuf.SyncSetting_PROFILE_PICTURES_SHOW_TO,
|
||||
},
|
||||
}
|
||||
ProfilePicturesVisibility = SettingField{
|
||||
reactFieldName: "profile-pictures-visibility",
|
||||
dBColumnName: "profile_pictures_visibility",
|
||||
syncProtobufFactory: &SyncProtobufFactory{
|
||||
fromInterface: profilePicturesVisibilityProtobufFactory,
|
||||
fromStruct: profilePicturesVisibilityProtobufFactoryStruct,
|
||||
valueFromProtobuf: Int64FromSyncProtobuf,
|
||||
protobufType: protobuf.SyncSetting_PROFILE_PICTURES_VISIBILITY,
|
||||
},
|
||||
}
|
||||
PublicKey = SettingField{
|
||||
reactFieldName: "public-key",
|
||||
dBColumnName: "public_key",
|
||||
}
|
||||
PushNotificationsBlockMentions = SettingField{
|
||||
reactFieldName: "push-notifications-block-mentions?",
|
||||
dBColumnName: "push_notifications_block_mentions",
|
||||
valueHandler: BoolHandler,
|
||||
}
|
||||
PushNotificationsFromContactsOnly = SettingField{
|
||||
reactFieldName: "push-notifications-from-contacts-only?",
|
||||
dBColumnName: "push_notifications_from_contacts_only",
|
||||
valueHandler: BoolHandler,
|
||||
}
|
||||
PushNotificationsServerEnabled = SettingField{
|
||||
reactFieldName: "push-notifications-server-enabled?",
|
||||
dBColumnName: "push_notifications_server_enabled",
|
||||
valueHandler: BoolHandler,
|
||||
}
|
||||
RememberSyncingChoice = SettingField{
|
||||
reactFieldName: "remember-syncing-choice?",
|
||||
dBColumnName: "remember_syncing_choice",
|
||||
valueHandler: BoolHandler,
|
||||
}
|
||||
RemotePushNotificationsEnabled = SettingField{
|
||||
reactFieldName: "remote-push-notifications-enabled?",
|
||||
dBColumnName: "remote_push_notifications_enabled",
|
||||
valueHandler: BoolHandler,
|
||||
}
|
||||
SendPushNotifications = SettingField{
|
||||
reactFieldName: "send-push-notifications?",
|
||||
dBColumnName: "send_push_notifications",
|
||||
valueHandler: BoolHandler,
|
||||
}
|
||||
SendStatusUpdates = SettingField{
|
||||
reactFieldName: "send-status-updates?",
|
||||
dBColumnName: "send_status_updates",
|
||||
valueHandler: BoolHandler,
|
||||
// TODO resolve issue 10 https://github.com/status-im/status-mobile/pull/13053#issuecomment-1075352256
|
||||
syncProtobufFactory: &SyncProtobufFactory{
|
||||
inactive: true, // Remove after issue is resolved
|
||||
fromInterface: sendStatusUpdatesProtobufFactory,
|
||||
fromStruct: sendStatusUpdatesProtobufFactoryStruct,
|
||||
valueFromProtobuf: BoolFromSyncProtobuf,
|
||||
protobufType: protobuf.SyncSetting_SEND_STATUS_UPDATES,
|
||||
},
|
||||
}
|
||||
StickersPacksInstalled = SettingField{
|
||||
reactFieldName: "stickers/packs-installed",
|
||||
dBColumnName: "stickers_packs_installed",
|
||||
valueHandler: JSONBlobHandler,
|
||||
syncProtobufFactory: &SyncProtobufFactory{
|
||||
inactive: true, // TODO current version of stickers introduces a regression on deleting sticker packs
|
||||
fromInterface: stickersPacksInstalledProtobufFactory,
|
||||
fromStruct: stickersPacksInstalledProtobufFactoryStruct,
|
||||
valueFromProtobuf: BytesFromSyncProtobuf,
|
||||
protobufType: protobuf.SyncSetting_STICKERS_PACKS_INSTALLED,
|
||||
},
|
||||
}
|
||||
StickersPacksPending = SettingField{
|
||||
reactFieldName: "stickers/packs-pending",
|
||||
dBColumnName: "stickers_packs_pending",
|
||||
valueHandler: JSONBlobHandler,
|
||||
syncProtobufFactory: &SyncProtobufFactory{
|
||||
inactive: true, // TODO current version of stickers introduces a regression on deleting sticker packs
|
||||
fromInterface: stickersPacksPendingProtobufFactory,
|
||||
fromStruct: stickersPacksPendingProtobufFactoryStruct,
|
||||
valueFromProtobuf: BytesFromSyncProtobuf,
|
||||
protobufType: protobuf.SyncSetting_STICKERS_PACKS_PENDING,
|
||||
},
|
||||
}
|
||||
StickersRecentStickers = SettingField{
|
||||
reactFieldName: "stickers/recent-stickers",
|
||||
dBColumnName: "stickers_recent_stickers",
|
||||
valueHandler: JSONBlobHandler,
|
||||
syncProtobufFactory: &SyncProtobufFactory{
|
||||
inactive: true, // TODO current version of stickers introduces a regression on deleting sticker packs
|
||||
fromInterface: stickersRecentStickersProtobufFactory,
|
||||
fromStruct: stickersRecentStickersProtobufFactoryStruct,
|
||||
valueFromProtobuf: BytesFromSyncProtobuf,
|
||||
protobufType: protobuf.SyncSetting_STICKERS_RECENT_STICKERS,
|
||||
},
|
||||
}
|
||||
SyncingOnMobileNetwork = SettingField{
|
||||
reactFieldName: "syncing-on-mobile-network?",
|
||||
dBColumnName: "syncing_on_mobile_network",
|
||||
valueHandler: BoolHandler,
|
||||
}
|
||||
TelemetryServerURL = SettingField{
|
||||
reactFieldName: "telemetry-server-url",
|
||||
dBColumnName: "telemetry_server_url",
|
||||
}
|
||||
TestNetworksEnabled = SettingField{
|
||||
reactFieldName: "test-networks-enabled?",
|
||||
dBColumnName: "test_networks_enabled",
|
||||
valueHandler: BoolHandler,
|
||||
}
|
||||
IsSepoliaEnabled = SettingField{
|
||||
reactFieldName: "is-sepolia-enabled?",
|
||||
dBColumnName: "is_sepolia_enabled",
|
||||
valueHandler: BoolHandler,
|
||||
}
|
||||
TokenGroupByCommunity = SettingField{
|
||||
reactFieldName: "token-group-by-community?",
|
||||
dBColumnName: "wallet_token_preferences_group_by_community",
|
||||
valueHandler: BoolHandler,
|
||||
}
|
||||
ShowCommunityAssetWhenSendingTokens = SettingField{
|
||||
reactFieldName: "show-community-asset-when-sending-tokens?",
|
||||
dBColumnName: "wallet_show_community_asset_when_sending_tokens",
|
||||
valueHandler: BoolHandler,
|
||||
syncProtobufFactory: &SyncProtobufFactory{
|
||||
fromInterface: showCommunityAssetWhenSendingTokensProtobufFactory,
|
||||
fromStruct: showCommunityAssetWhenSendingTokensProtobufFactoryStruct,
|
||||
valueFromProtobuf: BoolFromSyncProtobuf,
|
||||
protobufType: protobuf.SyncSetting_SHOW_COMMUNITY_ASSET_WHEN_SENDING_TOKENS,
|
||||
},
|
||||
}
|
||||
DisplayAssetsBelowBalance = SettingField{
|
||||
reactFieldName: "display-assets-below-balance?",
|
||||
dBColumnName: "wallet_display_assets_below_balance",
|
||||
valueHandler: BoolHandler,
|
||||
syncProtobufFactory: &SyncProtobufFactory{
|
||||
fromInterface: displayAssetsBelowBalanceProtobufFactory,
|
||||
fromStruct: displayAssetsBelowBalanceProtobufFactoryStruct,
|
||||
valueFromProtobuf: BoolFromSyncProtobuf,
|
||||
protobufType: protobuf.SyncSetting_DISPLAY_ASSETS_BELOW_BALANCE,
|
||||
},
|
||||
}
|
||||
DisplayAssetsBelowBalanceThreshold = SettingField{
|
||||
reactFieldName: "display-assets-below-balance-threshold",
|
||||
dBColumnName: "wallet_display_assets_below_balance_threshold",
|
||||
valueHandler: Int64Handler,
|
||||
syncProtobufFactory: &SyncProtobufFactory{
|
||||
fromInterface: displayAssetsBelowBalanceThresholdProtobufFactory,
|
||||
fromStruct: displayAssetsBelowBalanceThresholdProtobufFactoryStruct,
|
||||
valueFromProtobuf: Int64FromSyncProtobuf,
|
||||
protobufType: protobuf.SyncSetting_DISPLAY_ASSETS_BELOW_BALANCE_THRESHOLD,
|
||||
},
|
||||
}
|
||||
CollectibleGroupByCollection = SettingField{
|
||||
reactFieldName: "collectible-group-by-collection?",
|
||||
dBColumnName: "wallet_collectible_preferences_group_by_collection",
|
||||
valueHandler: BoolHandler,
|
||||
}
|
||||
CollectibleGroupByCommunity = SettingField{
|
||||
reactFieldName: "collectible-group-by-community?",
|
||||
dBColumnName: "wallet_collectible_preferences_group_by_community",
|
||||
valueHandler: BoolHandler,
|
||||
}
|
||||
UseMailservers = SettingField{
|
||||
reactFieldName: "use-mailservers?",
|
||||
dBColumnName: "use_mailservers",
|
||||
valueHandler: BoolHandler,
|
||||
}
|
||||
WakuBloomFilterMode = SettingField{
|
||||
reactFieldName: "waku-bloom-filter-mode",
|
||||
dBColumnName: "waku_bloom_filter_mode",
|
||||
valueHandler: BoolHandler,
|
||||
}
|
||||
WalletSetUpPassed = SettingField{
|
||||
reactFieldName: "wallet-set-up-passed?",
|
||||
dBColumnName: "wallet_set_up_passed",
|
||||
valueHandler: BoolHandler,
|
||||
}
|
||||
WalletVisibleTokens = SettingField{
|
||||
reactFieldName: "wallet/visible-tokens",
|
||||
dBColumnName: "wallet_visible_tokens",
|
||||
valueHandler: JSONBlobHandler,
|
||||
}
|
||||
WebviewAllowPermissionRequests = SettingField{
|
||||
reactFieldName: "webview-allow-permission-requests?",
|
||||
dBColumnName: "webview_allow_permission_requests",
|
||||
valueHandler: BoolHandler,
|
||||
}
|
||||
WalletRootAddress = SettingField{
|
||||
reactFieldName: "wallet-root-address",
|
||||
dBColumnName: "wallet_root_address",
|
||||
valueHandler: AddressHandler,
|
||||
}
|
||||
MasterAddress = SettingField{
|
||||
reactFieldName: "address",
|
||||
dBColumnName: "address",
|
||||
valueHandler: AddressHandler,
|
||||
}
|
||||
ProfileMigrationNeeded = SettingField{
|
||||
reactFieldName: "profile-migration-needed",
|
||||
dBColumnName: "profile_migration_needed",
|
||||
valueHandler: BoolHandler,
|
||||
}
|
||||
URLUnfurlingMode = SettingField{
|
||||
reactFieldName: "url-unfurling-mode",
|
||||
dBColumnName: "url_unfurling_mode",
|
||||
syncProtobufFactory: &SyncProtobufFactory{
|
||||
fromInterface: urlUnfurlingModeProtobufFactory,
|
||||
fromStruct: urlUnfurlingModeProtobufFactoryStruct,
|
||||
valueFromProtobuf: Int64FromSyncProtobuf,
|
||||
protobufType: protobuf.SyncSetting_URL_UNFURLING_MODE,
|
||||
},
|
||||
}
|
||||
OmitTransfersHistoryScan = SettingField{
|
||||
reactFieldName: "omit-transfers-history-scan",
|
||||
dBColumnName: "omit_transfers_history_scan",
|
||||
valueHandler: BoolHandler,
|
||||
}
|
||||
MnemonicWasNotShown = SettingField{
|
||||
reactFieldName: "mnemonic-was-not-shown?",
|
||||
dBColumnName: "mnemonic_was_not_shown",
|
||||
valueHandler: BoolHandler,
|
||||
}
|
||||
SettingFieldRegister = []SettingField{
|
||||
AnonMetricsShouldSend,
|
||||
Appearance,
|
||||
AutoMessageEnabled,
|
||||
BackupEnabled,
|
||||
BackupFetched,
|
||||
ChaosMode,
|
||||
Currency,
|
||||
CurrentUserStatus,
|
||||
CustomBootNodes,
|
||||
CustomBootNodesEnabled,
|
||||
DappsAddress,
|
||||
DefaultSyncPeriod,
|
||||
DeviceName,
|
||||
DisplayName,
|
||||
Bio,
|
||||
EIP1581Address,
|
||||
Fleet,
|
||||
GifAPIKey,
|
||||
GifFavourites,
|
||||
GifRecents,
|
||||
HideHomeTooltip,
|
||||
KeycardInstanceUID,
|
||||
KeycardPairedOn,
|
||||
KeycardPairing,
|
||||
LastBackup,
|
||||
LastUpdated,
|
||||
LatestDerivedPath,
|
||||
LinkPreviewRequestEnabled,
|
||||
LinkPreviewsEnabledSites,
|
||||
LogLevel,
|
||||
MessagesFromContactsOnly,
|
||||
Mnemonic,
|
||||
MnemonicRemoved,
|
||||
MutualContactEnabled,
|
||||
Name,
|
||||
NetworksCurrentNetwork,
|
||||
NetworksNetworks,
|
||||
NodeConfig,
|
||||
NotificationsEnabled,
|
||||
OpenseaEnabled,
|
||||
PhotoPath,
|
||||
PinnedMailservers,
|
||||
PreferredName,
|
||||
PreviewPrivacy,
|
||||
ProfilePicturesShowTo,
|
||||
ProfilePicturesVisibility,
|
||||
PublicKey,
|
||||
PushNotificationsBlockMentions,
|
||||
PushNotificationsFromContactsOnly,
|
||||
PushNotificationsServerEnabled,
|
||||
RememberSyncingChoice,
|
||||
RemotePushNotificationsEnabled,
|
||||
SendPushNotifications,
|
||||
SendStatusUpdates,
|
||||
StickersPacksInstalled,
|
||||
StickersPacksPending,
|
||||
StickersRecentStickers,
|
||||
SyncingOnMobileNetwork,
|
||||
TelemetryServerURL,
|
||||
TestNetworksEnabled,
|
||||
UseMailservers,
|
||||
WakuBloomFilterMode,
|
||||
WalletRootAddress,
|
||||
WalletSetUpPassed,
|
||||
WalletVisibleTokens,
|
||||
WebviewAllowPermissionRequests,
|
||||
ProfileMigrationNeeded,
|
||||
IsSepoliaEnabled,
|
||||
TokenGroupByCommunity,
|
||||
ShowCommunityAssetWhenSendingTokens,
|
||||
DisplayAssetsBelowBalance,
|
||||
DisplayAssetsBelowBalanceThreshold,
|
||||
CollectibleGroupByCollection,
|
||||
CollectibleGroupByCommunity,
|
||||
URLUnfurlingMode,
|
||||
}
|
||||
)
|
||||
|
||||
func GetFieldFromProtobufType(pbt protobuf.SyncSetting_Type) (SettingField, error) {
|
||||
if pbt == protobuf.SyncSetting_UNKNOWN {
|
||||
return SettingField{}, errors.ErrUnrecognisedSyncSettingProtobufType
|
||||
}
|
||||
|
||||
for _, s := range SettingFieldRegister {
|
||||
if s.SyncProtobufFactory() == nil {
|
||||
continue
|
||||
}
|
||||
if s.SyncProtobufFactory().SyncSettingProtobufType() == pbt {
|
||||
return s, nil
|
||||
}
|
||||
}
|
||||
|
||||
return SettingField{}, errors.ErrUnrecognisedSyncSettingProtobufType
|
||||
}
|
||||
831
vendor/github.com/status-im/status-go/multiaccounts/settings/database.go
generated
vendored
Normal file
831
vendor/github.com/status-im/status-go/multiaccounts/settings/database.go
generated
vendored
Normal file
@@ -0,0 +1,831 @@
|
||||
package settings
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
|
||||
"github.com/status-im/status-go/common/dbsetup"
|
||||
"github.com/status-im/status-go/eth-node/types"
|
||||
"github.com/status-im/status-go/multiaccounts/errors"
|
||||
"github.com/status-im/status-go/nodecfg"
|
||||
"github.com/status-im/status-go/params"
|
||||
"github.com/status-im/status-go/sqlite"
|
||||
)
|
||||
|
||||
type Notifier func(SettingField, interface{})
|
||||
|
||||
var (
|
||||
// dbInstances holds a map of singleton instances of Database
|
||||
dbInstances map[string]*Database
|
||||
|
||||
// mutex guards the instantiation of the dbInstances values, to prevent any concurrent instantiations
|
||||
mutex sync.Mutex
|
||||
)
|
||||
|
||||
// Database sql wrapper for operations with browser objects.
|
||||
type Database struct {
|
||||
db *sql.DB
|
||||
SyncQueue chan SyncSettingField
|
||||
changesSubscriptions []chan *SyncSettingField
|
||||
notifier Notifier
|
||||
}
|
||||
|
||||
// MakeNewDB ensures that a singleton instance of Database is returned per sqlite db file
|
||||
func MakeNewDB(db *sql.DB) (*Database, error) {
|
||||
filename, err := dbsetup.GetDBFilename(db)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
d := &Database{
|
||||
db: db,
|
||||
SyncQueue: make(chan SyncSettingField, 100),
|
||||
}
|
||||
|
||||
// An empty filename means that the sqlite database is held in memory
|
||||
// In this case we don't want to restrict the instantiation
|
||||
if filename == "" {
|
||||
return d, nil
|
||||
}
|
||||
|
||||
// Lock to protect the map from concurrent access
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
|
||||
// init dbInstances if it hasn't been already
|
||||
if dbInstances == nil {
|
||||
dbInstances = map[string]*Database{}
|
||||
}
|
||||
|
||||
// If we haven't seen this database file before make an instance
|
||||
if _, ok := dbInstances[filename]; !ok {
|
||||
dbInstances[filename] = d
|
||||
}
|
||||
|
||||
// Check if the current dbInstance is closed, if closed assign new Database
|
||||
if err := dbInstances[filename].db.Ping(); err != nil {
|
||||
dbInstances[filename] = d
|
||||
}
|
||||
|
||||
return dbInstances[filename], nil
|
||||
}
|
||||
|
||||
func (db *Database) GetDB() *sql.DB {
|
||||
return db.db
|
||||
}
|
||||
|
||||
func (db *Database) GetSyncQueue() chan SyncSettingField {
|
||||
return db.SyncQueue
|
||||
}
|
||||
|
||||
func (db *Database) GetChangesSubscriptions() []chan *SyncSettingField {
|
||||
return db.changesSubscriptions
|
||||
}
|
||||
|
||||
func (db *Database) GetNotifier() Notifier {
|
||||
return db.notifier
|
||||
}
|
||||
|
||||
func (db *Database) SetSettingsNotifier(n Notifier) {
|
||||
db.notifier = n
|
||||
}
|
||||
|
||||
// TODO remove photoPath from settings
|
||||
func (db *Database) CreateSettings(s Settings, n params.NodeConfig) error {
|
||||
tx, err := db.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()
|
||||
}()
|
||||
|
||||
_, err = tx.Exec(`
|
||||
INSERT INTO settings (
|
||||
address,
|
||||
currency,
|
||||
current_network,
|
||||
dapps_address,
|
||||
device_name,
|
||||
preferred_name,
|
||||
display_name,
|
||||
bio,
|
||||
eip1581_address,
|
||||
installation_id,
|
||||
key_uid,
|
||||
keycard_instance_uid,
|
||||
keycard_paired_on,
|
||||
keycard_pairing,
|
||||
latest_derived_path,
|
||||
mnemonic,
|
||||
name,
|
||||
networks,
|
||||
photo_path,
|
||||
preview_privacy,
|
||||
public_key,
|
||||
signing_phrase,
|
||||
wallet_root_address,
|
||||
synthetic_id,
|
||||
current_user_status,
|
||||
profile_pictures_show_to,
|
||||
profile_pictures_visibility,
|
||||
url_unfurling_mode,
|
||||
omit_transfers_history_scan,
|
||||
mnemonic_was_not_shown,
|
||||
wallet_token_preferences_group_by_community,
|
||||
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
|
||||
) VALUES (
|
||||
?,?,?,?,?,?,?,?,?,?,?,?,?,?,
|
||||
?,?,?,?,?,?,?,?,?,'id',?,?,?,?,?,?,?,?,?,?,?,?)`,
|
||||
s.Address,
|
||||
s.Currency,
|
||||
s.CurrentNetwork,
|
||||
s.DappsAddress,
|
||||
s.DeviceName,
|
||||
s.PreferredName,
|
||||
s.DisplayName,
|
||||
s.Bio,
|
||||
s.EIP1581Address,
|
||||
s.InstallationID,
|
||||
s.KeyUID,
|
||||
s.KeycardInstanceUID,
|
||||
s.KeycardPairedOn,
|
||||
s.KeycardPairing,
|
||||
s.LatestDerivedPath,
|
||||
s.Mnemonic,
|
||||
s.Name,
|
||||
s.Networks,
|
||||
s.PhotoPath,
|
||||
s.PreviewPrivacy,
|
||||
s.PublicKey,
|
||||
s.SigningPhrase,
|
||||
s.WalletRootAddress,
|
||||
s.CurrentUserStatus,
|
||||
s.ProfilePicturesShowTo,
|
||||
s.ProfilePicturesVisibility,
|
||||
s.URLUnfurlingMode,
|
||||
s.OmitTransfersHistoryScan,
|
||||
s.MnemonicWasNotShown,
|
||||
s.TokenGroupByCommunity,
|
||||
s.ShowCommunityAssetWhenSendingTokens,
|
||||
s.DisplayAssetsBelowBalance,
|
||||
s.DisplayAssetsBelowBalanceThreshold,
|
||||
s.CollectibleGroupByCollection,
|
||||
s.CollectibleGroupByCommunity,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if s.DisplayName != "" {
|
||||
now := time.Now().Unix()
|
||||
query := db.buildUpdateSyncClockQueryForField(DisplayName)
|
||||
_, err := tx.Exec(query, uint64(now), uint64(now))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nodecfg.SaveConfigWithTx(tx, &n)
|
||||
}
|
||||
|
||||
func (db *Database) getSettingFieldFromReactName(reactName string) (SettingField, error) {
|
||||
for _, s := range SettingFieldRegister {
|
||||
if s.GetReactName() == reactName {
|
||||
return s, nil
|
||||
}
|
||||
}
|
||||
return SettingField{}, errors.ErrInvalidConfig
|
||||
}
|
||||
|
||||
func (db *Database) makeSelectRow(setting SettingField) *sql.Row {
|
||||
query := "SELECT %s FROM settings WHERE synthetic_id = 'id'"
|
||||
query = fmt.Sprintf(query, setting.GetDBName())
|
||||
return db.db.QueryRow(query)
|
||||
}
|
||||
|
||||
func (db *Database) makeSelectString(setting SettingField) (string, error) {
|
||||
var result sql.NullString
|
||||
err := db.makeSelectRow(setting).Scan(&result)
|
||||
if err == sql.ErrNoRows {
|
||||
return "", nil
|
||||
}
|
||||
if result.Valid {
|
||||
return result.String, nil
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
|
||||
func (db *Database) saveSetting(setting SettingField, value interface{}) error {
|
||||
query := "UPDATE settings SET %s = ? WHERE synthetic_id = 'id'"
|
||||
query = fmt.Sprintf(query, setting.GetDBName())
|
||||
|
||||
update, err := db.db.Prepare(query)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = update.Exec(value)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if db.notifier != nil {
|
||||
db.notifier(setting, value)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *Database) parseSaveAndSyncSetting(sf SettingField, value interface{}) (err error) {
|
||||
if sf.ValueHandler() != nil {
|
||||
value, err = sf.ValueHandler()(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(samyoul) this is ugly as hell need a more elegant solution
|
||||
if NodeConfig.GetReactName() == sf.GetReactName() {
|
||||
if err = nodecfg.SaveNodeConfig(db.db, value.(*params.NodeConfig)); err != nil {
|
||||
return err
|
||||
}
|
||||
value = nil
|
||||
}
|
||||
|
||||
err = db.saveSetting(sf, value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if sf.GetDBName() == DBColumnMnemonic {
|
||||
mnemonicRemoved := value == nil || value.(string) == ""
|
||||
err = db.saveSetting(MnemonicRemoved, mnemonicRemoved)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sf = MnemonicRemoved
|
||||
value = mnemonicRemoved
|
||||
}
|
||||
|
||||
if sf.CanSync(FromInterface) {
|
||||
db.SyncQueue <- SyncSettingField{sf, value}
|
||||
}
|
||||
|
||||
db.postChangesToSubscribers(&SyncSettingField{sf, value})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SaveSetting stores data from any non-sync source
|
||||
// If the field requires syncing the field data is pushed on to the SyncQueue
|
||||
func (db *Database) SaveSetting(setting string, value interface{}) error {
|
||||
sf, err := db.getSettingFieldFromReactName(setting)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return db.parseSaveAndSyncSetting(sf, value)
|
||||
}
|
||||
|
||||
// SaveSettingField is identical in functionality to SaveSetting, except the setting parameter is a SettingField and
|
||||
// doesn't require any SettingFieldRegister lookup.
|
||||
// This func is useful if you already know the SettingField to save
|
||||
func (db *Database) SaveSettingField(sf SettingField, value interface{}) error {
|
||||
return db.parseSaveAndSyncSetting(sf, value)
|
||||
}
|
||||
|
||||
func (db *Database) DeleteMnemonic() error {
|
||||
return db.saveSetting(Mnemonic, nil)
|
||||
}
|
||||
|
||||
// SaveSyncSetting stores setting data from a sync protobuf source, note it does not call SettingField.ValueHandler()
|
||||
// nor does this function attempt to write to the Database.SyncQueue,
|
||||
// yet it still writes to Database.changesSubscriptions.
|
||||
func (db *Database) SaveSyncSetting(setting SettingField, value interface{}, clock uint64) error {
|
||||
ls, err := db.GetSettingLastSynced(setting)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if clock <= ls {
|
||||
return errors.ErrNewClockOlderThanCurrent
|
||||
}
|
||||
|
||||
err = db.SetSettingLastSynced(setting, clock)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = db.saveSetting(setting, value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
db.postChangesToSubscribers(&SyncSettingField{setting, value})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *Database) GetSettingLastSynced(setting SettingField) (result uint64, err error) {
|
||||
query := "SELECT %s FROM settings_sync_clock WHERE synthetic_id = 'id'"
|
||||
query = fmt.Sprintf(query, setting.GetDBName())
|
||||
|
||||
err = db.db.QueryRow(query).Scan(&result)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (db *Database) buildUpdateSyncClockQueryForField(setting SettingField) string {
|
||||
query := "UPDATE settings_sync_clock SET %s = ? WHERE synthetic_id = 'id' AND %s < ?"
|
||||
return fmt.Sprintf(query, setting.GetDBName(), setting.GetDBName())
|
||||
}
|
||||
|
||||
func (db *Database) SetSettingLastSynced(setting SettingField, clock uint64) error {
|
||||
query := db.buildUpdateSyncClockQueryForField(setting)
|
||||
|
||||
_, err := db.db.Exec(query, clock, clock)
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *Database) GetSettings() (Settings, error) {
|
||||
var s Settings
|
||||
err := db.db.QueryRow(`
|
||||
SELECT
|
||||
address, anon_metrics_should_send, chaos_mode, currency, current_network,
|
||||
custom_bootnodes, custom_bootnodes_enabled, dapps_address, display_name, bio, eip1581_address, fleet,
|
||||
hide_home_tooltip, installation_id, key_uid, keycard_instance_uid, keycard_paired_on, keycard_pairing,
|
||||
last_updated, latest_derived_path, link_preview_request_enabled, link_previews_enabled_sites, log_level,
|
||||
mnemonic, mnemonic_removed, name, networks, notifications_enabled, push_notifications_server_enabled,
|
||||
push_notifications_from_contacts_only, remote_push_notifications_enabled, send_push_notifications,
|
||||
push_notifications_block_mentions, photo_path, pinned_mailservers, preferred_name, preview_privacy, public_key,
|
||||
remember_syncing_choice, signing_phrase, stickers_packs_installed, stickers_packs_pending, stickers_recent_stickers,
|
||||
syncing_on_mobile_network, default_sync_period, use_mailservers, messages_from_contacts_only, usernames, appearance,
|
||||
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,
|
||||
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
|
||||
FROM
|
||||
settings
|
||||
WHERE
|
||||
synthetic_id = 'id'`).Scan(
|
||||
&s.Address,
|
||||
&s.AnonMetricsShouldSend,
|
||||
&s.ChaosMode,
|
||||
&s.Currency,
|
||||
&s.CurrentNetwork,
|
||||
&s.CustomBootnodes,
|
||||
&s.CustomBootnodesEnabled,
|
||||
&s.DappsAddress,
|
||||
&s.DisplayName,
|
||||
&s.Bio,
|
||||
&s.EIP1581Address,
|
||||
&s.Fleet,
|
||||
&s.HideHomeTooltip,
|
||||
&s.InstallationID,
|
||||
&s.KeyUID,
|
||||
&s.KeycardInstanceUID,
|
||||
&s.KeycardPairedOn,
|
||||
&s.KeycardPairing,
|
||||
&s.LastUpdated,
|
||||
&s.LatestDerivedPath,
|
||||
&s.LinkPreviewRequestEnabled,
|
||||
&s.LinkPreviewsEnabledSites,
|
||||
&s.LogLevel,
|
||||
&s.Mnemonic,
|
||||
&s.MnemonicRemoved,
|
||||
&s.Name,
|
||||
&s.Networks,
|
||||
&s.NotificationsEnabled,
|
||||
&s.PushNotificationsServerEnabled,
|
||||
&s.PushNotificationsFromContactsOnly,
|
||||
&s.RemotePushNotificationsEnabled,
|
||||
&s.SendPushNotifications,
|
||||
&s.PushNotificationsBlockMentions,
|
||||
&s.PhotoPath,
|
||||
&s.PinnedMailserver,
|
||||
&s.PreferredName,
|
||||
&s.PreviewPrivacy,
|
||||
&s.PublicKey,
|
||||
&s.RememberSyncingChoice,
|
||||
&s.SigningPhrase,
|
||||
&s.StickerPacksInstalled,
|
||||
&s.StickerPacksPending,
|
||||
&s.StickersRecentStickers,
|
||||
&s.SyncingOnMobileNetwork,
|
||||
&s.DefaultSyncPeriod,
|
||||
&s.UseMailservers,
|
||||
&s.MessagesFromContactsOnly,
|
||||
&s.Usernames,
|
||||
&s.Appearance,
|
||||
&s.ProfilePicturesShowTo,
|
||||
&s.ProfilePicturesVisibility,
|
||||
&s.WalletRootAddress,
|
||||
&s.WalletSetUpPassed,
|
||||
&s.WalletVisibleTokens,
|
||||
&s.WakuBloomFilterMode,
|
||||
&s.WebViewAllowPermissionRequests,
|
||||
&sqlite.JSONBlob{Data: &s.CurrentUserStatus},
|
||||
&s.SendStatusUpdates,
|
||||
&sqlite.JSONBlob{Data: &s.GifRecents},
|
||||
&sqlite.JSONBlob{Data: &s.GifFavorites},
|
||||
&s.OpenseaEnabled,
|
||||
&s.LastBackup,
|
||||
&s.BackupEnabled,
|
||||
&s.TelemetryServerURL,
|
||||
&s.AutoMessageEnabled,
|
||||
&s.GifAPIKey,
|
||||
&s.TestNetworksEnabled,
|
||||
&s.MutualContactEnabled,
|
||||
&s.ProfileMigrationNeeded,
|
||||
&s.IsSepoliaEnabled,
|
||||
&s.TokenGroupByCommunity,
|
||||
&s.URLUnfurlingMode,
|
||||
&s.OmitTransfersHistoryScan,
|
||||
&s.MnemonicWasNotShown,
|
||||
&s.ShowCommunityAssetWhenSendingTokens,
|
||||
&s.DisplayAssetsBelowBalance,
|
||||
&s.DisplayAssetsBelowBalanceThreshold,
|
||||
&s.CollectibleGroupByCollection,
|
||||
&s.CollectibleGroupByCommunity,
|
||||
)
|
||||
|
||||
return s, err
|
||||
}
|
||||
|
||||
// We should remove this and realated things once mobile team starts usign `settings_notifications` package
|
||||
func (db *Database) GetNotificationsEnabled() (result bool, err error) {
|
||||
err = db.makeSelectRow(NotificationsEnabled).Scan(&result)
|
||||
if err == sql.ErrNoRows {
|
||||
return result, nil
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (db *Database) GetProfilePicturesVisibility() (result int, err error) {
|
||||
err = db.makeSelectRow(ProfilePicturesVisibility).Scan(&result)
|
||||
if err == sql.ErrNoRows {
|
||||
return result, nil
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (db *Database) GetPublicKey() (string, error) {
|
||||
return db.makeSelectString(PublicKey)
|
||||
}
|
||||
|
||||
func (db *Database) GetFleet() (string, error) {
|
||||
return db.makeSelectString(Fleet)
|
||||
}
|
||||
|
||||
func (db *Database) GetDappsAddress() (rst types.Address, err error) {
|
||||
err = db.makeSelectRow(DappsAddress).Scan(&rst)
|
||||
if err == sql.ErrNoRows {
|
||||
return rst, nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (db *Database) GetPinnedMailservers() (rst map[string]string, err error) {
|
||||
rst = make(map[string]string)
|
||||
var pinnedMailservers string
|
||||
err = db.db.QueryRow("SELECT COALESCE(pinned_mailservers, '') FROM settings WHERE synthetic_id = 'id'").Scan(&pinnedMailservers)
|
||||
if err == sql.ErrNoRows || pinnedMailservers == "" {
|
||||
return rst, nil
|
||||
}
|
||||
|
||||
err = json.Unmarshal([]byte(pinnedMailservers), &rst)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (db *Database) CanUseMailservers() (result bool, err error) {
|
||||
err = db.makeSelectRow(UseMailservers).Scan(&result)
|
||||
if err == sql.ErrNoRows {
|
||||
return result, nil
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (db *Database) CanSyncOnMobileNetwork() (result bool, err error) {
|
||||
err = db.makeSelectRow(SyncingOnMobileNetwork).Scan(&result)
|
||||
if err == sql.ErrNoRows {
|
||||
return result, nil
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (db *Database) GetDefaultSyncPeriod() (result uint32, err error) {
|
||||
err = db.makeSelectRow(DefaultSyncPeriod).Scan(&result)
|
||||
if err == sql.ErrNoRows {
|
||||
return result, nil
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (db *Database) GetMessagesFromContactsOnly() (result bool, err error) {
|
||||
err = db.makeSelectRow(MessagesFromContactsOnly).Scan(&result)
|
||||
if err == sql.ErrNoRows {
|
||||
return result, nil
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (db *Database) GetProfilePicturesShowTo() (result int64, err error) {
|
||||
err = db.makeSelectRow(ProfilePicturesShowTo).Scan(&result)
|
||||
if err == sql.ErrNoRows {
|
||||
return result, nil
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (db *Database) GetLatestDerivedPath() (result uint, err error) {
|
||||
err = db.makeSelectRow(LatestDerivedPath).Scan(&result)
|
||||
return
|
||||
}
|
||||
|
||||
func (db *Database) GetCurrentStatus(status interface{}) error {
|
||||
err := db.makeSelectRow(CurrentUserStatus).Scan(&sqlite.JSONBlob{Data: &status})
|
||||
if err == sql.ErrNoRows {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *Database) ShouldBroadcastUserStatus() (result bool, err error) {
|
||||
err = db.makeSelectRow(SendStatusUpdates).Scan(&result)
|
||||
// If the `send_status_updates` value is nil the sql.ErrNoRows will be returned
|
||||
// because this feature is opt out, `true` should be returned in the case where no value is found
|
||||
if err == sql.ErrNoRows {
|
||||
return true, nil
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (db *Database) BackupEnabled() (result bool, err error) {
|
||||
err = db.makeSelectRow(BackupEnabled).Scan(&result)
|
||||
if err == sql.ErrNoRows {
|
||||
return true, nil
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (db *Database) AutoMessageEnabled() (result bool, err error) {
|
||||
err = db.makeSelectRow(AutoMessageEnabled).Scan(&result)
|
||||
if err == sql.ErrNoRows {
|
||||
return true, nil
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (db *Database) LastBackup() (result uint64, err error) {
|
||||
err = db.makeSelectRow(LastBackup).Scan(&result)
|
||||
if err == sql.ErrNoRows {
|
||||
return 0, nil
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (db *Database) SetLastBackup(time uint64) error {
|
||||
return db.SaveSettingField(LastBackup, time)
|
||||
}
|
||||
|
||||
func (db *Database) SetBackupFetched(fetched bool) error {
|
||||
return db.SaveSettingField(BackupFetched, fetched)
|
||||
}
|
||||
|
||||
func (db *Database) BackupFetched() (result bool, err error) {
|
||||
err = db.makeSelectRow(BackupFetched).Scan(&result)
|
||||
if err == sql.ErrNoRows {
|
||||
return true, nil
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (db *Database) ENSName() (string, error) {
|
||||
return db.makeSelectString(PreferredName)
|
||||
}
|
||||
|
||||
func (db *Database) DeviceName() (string, error) {
|
||||
return db.makeSelectString(DeviceName)
|
||||
}
|
||||
|
||||
func (db *Database) DisplayName() (string, error) {
|
||||
return db.makeSelectString(DisplayName)
|
||||
}
|
||||
|
||||
func (db *Database) Bio() (string, error) {
|
||||
return db.makeSelectString(Bio)
|
||||
}
|
||||
|
||||
func (db *Database) Mnemonic() (string, error) {
|
||||
return db.makeSelectString(Mnemonic)
|
||||
}
|
||||
|
||||
func (db *Database) MnemonicRemoved() (result bool, err error) {
|
||||
err = db.makeSelectRow(MnemonicRemoved).Scan(&result)
|
||||
if err == sql.ErrNoRows {
|
||||
return result, nil
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (db *Database) GetMnemonicWasNotShown() (result bool, err error) {
|
||||
err = db.makeSelectRow(MnemonicWasNotShown).Scan(&result)
|
||||
if err == sql.ErrNoRows {
|
||||
return result, nil
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (db *Database) GifAPIKey() (string, error) {
|
||||
return db.makeSelectString(GifAPIKey)
|
||||
}
|
||||
|
||||
func (db *Database) MutualContactEnabled() (result bool, err error) {
|
||||
err = db.makeSelectRow(MutualContactEnabled).Scan(&result)
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (db *Database) GifRecents() (recents json.RawMessage, err error) {
|
||||
err = db.makeSelectRow(GifRecents).Scan(&sqlite.JSONBlob{Data: &recents})
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, err
|
||||
}
|
||||
return recents, nil
|
||||
}
|
||||
|
||||
func (db *Database) GifFavorites() (favorites json.RawMessage, err error) {
|
||||
err = db.makeSelectRow(GifFavourites).Scan(&sqlite.JSONBlob{Data: &favorites})
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, err
|
||||
}
|
||||
return favorites, nil
|
||||
}
|
||||
|
||||
func (db *Database) GetPreferredUsername() (string, error) {
|
||||
return db.makeSelectString(PreferredName)
|
||||
}
|
||||
|
||||
func (db *Database) GetCurrency() (string, error) {
|
||||
return db.makeSelectString(Currency)
|
||||
}
|
||||
|
||||
func (db *Database) GetInstalledStickerPacks() (rst *json.RawMessage, err error) {
|
||||
err = db.makeSelectRow(StickersPacksInstalled).Scan(&rst)
|
||||
return
|
||||
}
|
||||
|
||||
func (db *Database) GetPendingStickerPacks() (rst *json.RawMessage, err error) {
|
||||
err = db.makeSelectRow(StickersPacksPending).Scan(&rst)
|
||||
return
|
||||
}
|
||||
|
||||
func (db *Database) GetRecentStickers() (rst *json.RawMessage, err error) {
|
||||
err = db.makeSelectRow(StickersRecentStickers).Scan(&rst)
|
||||
return
|
||||
}
|
||||
|
||||
func (db *Database) SetPinnedMailservers(mailservers map[string]string) error {
|
||||
return db.SaveSettingField(PinnedMailservers, mailservers)
|
||||
}
|
||||
|
||||
func (db *Database) SetUseMailservers(value bool) error {
|
||||
return db.SaveSettingField(UseMailservers, value)
|
||||
}
|
||||
|
||||
func (db *Database) GetWalletRootAddress() (rst types.Address, err error) {
|
||||
err = db.makeSelectRow(WalletRootAddress).Scan(&rst)
|
||||
if err == sql.ErrNoRows {
|
||||
return rst, nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (db *Database) GetEIP1581Address() (rst types.Address, err error) {
|
||||
err = db.makeSelectRow(EIP1581Address).Scan(&rst)
|
||||
if err == sql.ErrNoRows {
|
||||
return rst, nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (db *Database) GetMasterAddress() (rst types.Address, err error) {
|
||||
err = db.makeSelectRow(MasterAddress).Scan(&rst)
|
||||
if err == sql.ErrNoRows {
|
||||
return rst, nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (db *Database) GetTestNetworksEnabled() (result bool, err error) {
|
||||
err = db.makeSelectRow(TestNetworksEnabled).Scan(&result)
|
||||
if err == sql.ErrNoRows {
|
||||
return result, nil
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (db *Database) GetIsSepoliaEnabled() (result bool, err error) {
|
||||
err = db.makeSelectRow(IsSepoliaEnabled).Scan(&result)
|
||||
if err == sql.ErrNoRows {
|
||||
return result, nil
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (db *Database) GetTokenGroupByCommunity() (result bool, err error) {
|
||||
err = db.makeSelectRow(TokenGroupByCommunity).Scan(&result)
|
||||
if err == sql.ErrNoRows {
|
||||
return result, nil
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (db *Database) SetTokenGroupByCommunity(value bool) error {
|
||||
return db.SaveSettingField(TokenGroupByCommunity, value)
|
||||
}
|
||||
|
||||
func (db *Database) GetCollectibleGroupByCollection() (result bool, err error) {
|
||||
err = db.makeSelectRow(CollectibleGroupByCollection).Scan(&result)
|
||||
if err == sql.ErrNoRows {
|
||||
return result, nil
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (db *Database) SetCollectibleGroupByCollection(value bool) error {
|
||||
return db.SaveSettingField(CollectibleGroupByCollection, value)
|
||||
}
|
||||
|
||||
func (db *Database) GetCollectibleGroupByCommunity() (result bool, err error) {
|
||||
err = db.makeSelectRow(CollectibleGroupByCommunity).Scan(&result)
|
||||
if err == sql.ErrNoRows {
|
||||
return result, nil
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (db *Database) SetCollectibleGroupByCommunity(value bool) error {
|
||||
return db.SaveSettingField(CollectibleGroupByCommunity, value)
|
||||
}
|
||||
|
||||
func (db *Database) GetTelemetryServerURL() (string, error) {
|
||||
return db.makeSelectString(TelemetryServerURL)
|
||||
}
|
||||
|
||||
func (db *Database) ProfileMigrationNeeded() (result bool, err error) {
|
||||
err = db.makeSelectRow(ProfileMigrationNeeded).Scan(&result)
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (db *Database) URLUnfurlingMode() (result int64, err error) {
|
||||
err = db.makeSelectRow(URLUnfurlingMode).Scan(&result)
|
||||
if err == sql.ErrNoRows {
|
||||
return result, nil
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (db *Database) SubscribeToChanges() chan *SyncSettingField {
|
||||
s := make(chan *SyncSettingField, 100)
|
||||
db.changesSubscriptions = append(db.changesSubscriptions, s)
|
||||
return s
|
||||
}
|
||||
|
||||
func (db *Database) postChangesToSubscribers(change *SyncSettingField) {
|
||||
// Publish on channels, drop if buffer is full
|
||||
for _, s := range db.changesSubscriptions {
|
||||
select {
|
||||
case s <- change:
|
||||
default:
|
||||
log.Warn("settings changes subscription channel full, dropping message")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (db *Database) MnemonicWasShown() error {
|
||||
return db.SaveSettingField(MnemonicWasNotShown, false)
|
||||
}
|
||||
79
vendor/github.com/status-im/status-go/multiaccounts/settings/database_settings_manager.go
generated
vendored
Normal file
79
vendor/github.com/status-im/status-go/multiaccounts/settings/database_settings_manager.go
generated
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
package settings
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/status-im/status-go/eth-node/types"
|
||||
"github.com/status-im/status-go/params"
|
||||
)
|
||||
|
||||
type DatabaseSettingsManager interface {
|
||||
GetDB() *sql.DB
|
||||
GetSyncQueue() chan SyncSettingField
|
||||
GetChangesSubscriptions() []chan *SyncSettingField
|
||||
GetNotifier() Notifier
|
||||
GetSettingLastSynced(setting SettingField) (result uint64, err error)
|
||||
GetSettings() (Settings, error)
|
||||
GetNotificationsEnabled() (result bool, err error)
|
||||
GetProfilePicturesVisibility() (result int, err error)
|
||||
GetPublicKey() (string, error)
|
||||
GetFleet() (string, error)
|
||||
GetDappsAddress() (rst types.Address, err error)
|
||||
GetPinnedMailservers() (rst map[string]string, err error)
|
||||
GetDefaultSyncPeriod() (result uint32, err error)
|
||||
GetMessagesFromContactsOnly() (result bool, err error)
|
||||
GetProfilePicturesShowTo() (result int64, err error)
|
||||
GetLatestDerivedPath() (result uint, err error)
|
||||
GetCurrentStatus(status interface{}) error
|
||||
GetMnemonicWasNotShown() (result bool, err error)
|
||||
GetPreferredUsername() (string, error)
|
||||
GetCurrency() (string, error)
|
||||
GetInstalledStickerPacks() (rst *json.RawMessage, err error)
|
||||
GetPendingStickerPacks() (rst *json.RawMessage, err error)
|
||||
GetRecentStickers() (rst *json.RawMessage, err error)
|
||||
GetWalletRootAddress() (rst types.Address, err error)
|
||||
GetEIP1581Address() (rst types.Address, err error)
|
||||
GetMasterAddress() (rst types.Address, err error)
|
||||
GetTestNetworksEnabled() (result bool, err error)
|
||||
GetIsSepoliaEnabled() (result bool, err error)
|
||||
GetTokenGroupByCommunity() (result bool, err error)
|
||||
GetCollectibleGroupByCommunity() (result bool, err error)
|
||||
GetCollectibleGroupByCollection() (result bool, err error)
|
||||
GetTelemetryServerURL() (string, error)
|
||||
|
||||
SetSettingsNotifier(n Notifier)
|
||||
SetSettingLastSynced(setting SettingField, clock uint64) error
|
||||
SetLastBackup(time uint64) error
|
||||
SetBackupFetched(fetched bool) error
|
||||
SetPinnedMailservers(mailservers map[string]string) error
|
||||
SetUseMailservers(value bool) error
|
||||
SetTokenGroupByCommunity(value bool) error
|
||||
|
||||
CreateSettings(s Settings, n params.NodeConfig) error
|
||||
SaveSetting(setting string, value interface{}) error
|
||||
SaveSettingField(sf SettingField, value interface{}) error
|
||||
DeleteMnemonic() error
|
||||
SaveSyncSetting(setting SettingField, value interface{}, clock uint64) error
|
||||
CanUseMailservers() (result bool, err error)
|
||||
CanSyncOnMobileNetwork() (result bool, err error)
|
||||
ShouldBroadcastUserStatus() (result bool, err error)
|
||||
BackupEnabled() (result bool, err error)
|
||||
AutoMessageEnabled() (result bool, err error)
|
||||
LastBackup() (result uint64, err error)
|
||||
BackupFetched() (result bool, err error)
|
||||
ENSName() (string, error)
|
||||
DeviceName() (string, error)
|
||||
DisplayName() (string, error)
|
||||
Bio() (string, error)
|
||||
Mnemonic() (string, error)
|
||||
MnemonicRemoved() (result bool, err error)
|
||||
GifAPIKey() (string, error)
|
||||
MutualContactEnabled() (result bool, err error)
|
||||
GifRecents() (recents json.RawMessage, err error)
|
||||
GifFavorites() (favorites json.RawMessage, err error)
|
||||
ProfileMigrationNeeded() (result bool, err error)
|
||||
URLUnfurlingMode() (result int64, err error)
|
||||
SubscribeToChanges() chan *SyncSettingField
|
||||
MnemonicWasShown() error
|
||||
}
|
||||
32
vendor/github.com/status-im/status-go/multiaccounts/settings/enums.go
generated
vendored
Normal file
32
vendor/github.com/status-im/status-go/multiaccounts/settings/enums.go
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
package settings
|
||||
|
||||
type SyncSource int
|
||||
|
||||
const (
|
||||
FromInterface SyncSource = iota + 1
|
||||
FromStruct
|
||||
)
|
||||
|
||||
type ProfilePicturesVisibilityType int
|
||||
|
||||
const (
|
||||
ProfilePicturesVisibilityContactsOnly ProfilePicturesVisibilityType = iota + 1
|
||||
ProfilePicturesVisibilityEveryone
|
||||
ProfilePicturesVisibilityNone
|
||||
)
|
||||
|
||||
type ProfilePicturesShowToType int
|
||||
|
||||
const (
|
||||
ProfilePicturesShowToContactsOnly ProfilePicturesShowToType = iota + 1
|
||||
ProfilePicturesShowToEveryone
|
||||
ProfilePicturesShowToNone
|
||||
)
|
||||
|
||||
type URLUnfurlingModeType int
|
||||
|
||||
const (
|
||||
URLUnfurlingAlwaysAsk URLUnfurlingModeType = iota + 1
|
||||
URLUnfurlingEnableAll
|
||||
URLUnfurlingDisableAll
|
||||
)
|
||||
226
vendor/github.com/status-im/status-go/multiaccounts/settings/structs.go
generated
vendored
Normal file
226
vendor/github.com/status-im/status-go/multiaccounts/settings/structs.go
generated
vendored
Normal file
@@ -0,0 +1,226 @@
|
||||
package settings
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
|
||||
accountJson "github.com/status-im/status-go/account/json"
|
||||
"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"
|
||||
)
|
||||
|
||||
type ValueHandler 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{}
|
||||
|
||||
// SyncProtobufFactory represents a collection of functionality to generate and parse *protobuf.SyncSetting
|
||||
type SyncProtobufFactory struct {
|
||||
inactive bool
|
||||
fromInterface SyncSettingProtobufFactoryInterface
|
||||
fromStruct SyncSettingProtobufFactoryStruct
|
||||
valueFromProtobuf SyncSettingProtobufToValue
|
||||
protobufType protobuf.SyncSetting_Type
|
||||
}
|
||||
|
||||
func (spf *SyncProtobufFactory) Inactive() bool {
|
||||
return spf.inactive
|
||||
}
|
||||
|
||||
func (spf *SyncProtobufFactory) FromInterface() SyncSettingProtobufFactoryInterface {
|
||||
return spf.fromInterface
|
||||
}
|
||||
|
||||
func (spf *SyncProtobufFactory) FromStruct() SyncSettingProtobufFactoryStruct {
|
||||
return spf.fromStruct
|
||||
}
|
||||
|
||||
func (spf *SyncProtobufFactory) ExtractValueFromProtobuf() SyncSettingProtobufToValue {
|
||||
return spf.valueFromProtobuf
|
||||
}
|
||||
|
||||
func (spf *SyncProtobufFactory) SyncSettingProtobufType() protobuf.SyncSetting_Type {
|
||||
return spf.protobufType
|
||||
}
|
||||
|
||||
// SyncSettingField represents a binding between a Value and a SettingField
|
||||
type SyncSettingField struct {
|
||||
SettingField
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
func (s SyncSettingField) MarshalJSON() ([]byte, error) {
|
||||
alias := struct {
|
||||
Name string `json:"name"`
|
||||
Value interface{} `json:"value"`
|
||||
}{
|
||||
s.reactFieldName,
|
||||
s.Value,
|
||||
}
|
||||
|
||||
return json.Marshal(alias)
|
||||
}
|
||||
|
||||
// SettingField represents an individual setting in the database, it contains context dependant names and optional
|
||||
// pre-store value parsing, along with optional *SyncProtobufFactory
|
||||
type SettingField struct {
|
||||
reactFieldName string
|
||||
dBColumnName string
|
||||
valueHandler ValueHandler
|
||||
syncProtobufFactory *SyncProtobufFactory
|
||||
}
|
||||
|
||||
func (s SettingField) GetReactName() string {
|
||||
return s.reactFieldName
|
||||
}
|
||||
|
||||
func (s SettingField) GetDBName() string {
|
||||
return s.dBColumnName
|
||||
}
|
||||
|
||||
func (s SettingField) ValueHandler() ValueHandler {
|
||||
return s.valueHandler
|
||||
}
|
||||
|
||||
func (s SettingField) SyncProtobufFactory() *SyncProtobufFactory {
|
||||
return s.syncProtobufFactory
|
||||
}
|
||||
|
||||
// CanSync checks if a SettingField has functions supporting the syncing of
|
||||
func (s SettingField) CanSync(source SyncSource) bool {
|
||||
spf := s.syncProtobufFactory
|
||||
|
||||
if spf == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if spf.inactive {
|
||||
return false
|
||||
}
|
||||
|
||||
switch source {
|
||||
case FromInterface:
|
||||
return spf.fromInterface != nil
|
||||
case FromStruct:
|
||||
return spf.fromStruct != nil
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (s SettingField) Equals(other SettingField) bool {
|
||||
return s.reactFieldName == other.reactFieldName
|
||||
}
|
||||
|
||||
// Settings represents the entire setting row stored in the application db
|
||||
type Settings struct {
|
||||
// required
|
||||
Address types.Address `json:"address"`
|
||||
AnonMetricsShouldSend bool `json:"anon-metrics/should-send?,omitempty"`
|
||||
ChaosMode bool `json:"chaos-mode?,omitempty"`
|
||||
Currency string `json:"currency,omitempty"`
|
||||
CurrentNetwork string `json:"networks/current-network"`
|
||||
CustomBootnodes *json.RawMessage `json:"custom-bootnodes,omitempty"`
|
||||
CustomBootnodesEnabled *json.RawMessage `json:"custom-bootnodes-enabled?,omitempty"`
|
||||
DappsAddress types.Address `json:"dapps-address"`
|
||||
DeviceName string `json:"device-name"`
|
||||
DisplayName string `json:"display-name"`
|
||||
Bio string `json:"bio,omitempty"`
|
||||
EIP1581Address types.Address `json:"eip1581-address"`
|
||||
Fleet *string `json:"fleet,omitempty"`
|
||||
HideHomeTooltip bool `json:"hide-home-tooltip?,omitempty"`
|
||||
InstallationID string `json:"installation-id"`
|
||||
KeyUID string `json:"key-uid"`
|
||||
KeycardInstanceUID string `json:"keycard-instance-uid,omitempty"`
|
||||
KeycardPairedOn int64 `json:"keycard-paired-on,omitempty"`
|
||||
KeycardPairing string `json:"keycard-pairing,omitempty"`
|
||||
LastUpdated *int64 `json:"last-updated,omitempty"`
|
||||
LatestDerivedPath uint `json:"latest-derived-path"`
|
||||
LinkPreviewRequestEnabled bool `json:"link-preview-request-enabled,omitempty"`
|
||||
LinkPreviewsEnabledSites *json.RawMessage `json:"link-previews-enabled-sites,omitempty"`
|
||||
LogLevel *string `json:"log-level,omitempty"`
|
||||
MessagesFromContactsOnly bool `json:"messages-from-contacts-only"`
|
||||
Mnemonic *string `json:"mnemonic,omitempty"`
|
||||
// NOTE(rasom): negation here because it safer/simpler to have false by default
|
||||
MnemonicWasNotShown bool `json:"mnemonic-was-not-shown?,omitempty"`
|
||||
MnemonicRemoved bool `json:"mnemonic-removed?,omitempty"`
|
||||
OmitTransfersHistoryScan bool `json:"omit-transfers-history-scan?,omitempty"`
|
||||
MutualContactEnabled bool `json:"mutual-contact-enabled?"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Networks *json.RawMessage `json:"networks/networks"`
|
||||
// NotificationsEnabled indicates whether local notifications should be enabled (android only)
|
||||
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"`
|
||||
// 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
|
||||
PushNotificationsFromContactsOnly bool `json:"push-notifications-from-contacts-only?,omitempty"`
|
||||
// PushNotificationsBlockMentions indicates whether we should receive notifications for mentions
|
||||
PushNotificationsBlockMentions bool `json:"push-notifications-block-mentions?,omitempty"`
|
||||
RememberSyncingChoice bool `json:"remember-syncing-choice?,omitempty"`
|
||||
// RemotePushNotificationsEnabled indicates whether we should be using remote notifications (ios only for now)
|
||||
RemotePushNotificationsEnabled bool `json:"remote-push-notifications-enabled?,omitempty"`
|
||||
SigningPhrase string `json:"signing-phrase"`
|
||||
StickerPacksInstalled *json.RawMessage `json:"stickers/packs-installed,omitempty"`
|
||||
StickerPacksPending *json.RawMessage `json:"stickers/packs-pending,omitempty"`
|
||||
StickersRecentStickers *json.RawMessage `json:"stickers/recent-stickers,omitempty"`
|
||||
SyncingOnMobileNetwork bool `json:"syncing-on-mobile-network?,omitempty"`
|
||||
// DefaultSyncPeriod is how far back in seconds we should pull messages from a mailserver
|
||||
DefaultSyncPeriod uint `json:"default-sync-period"`
|
||||
// SendPushNotifications indicates whether we should send push notifications for other clients
|
||||
SendPushNotifications bool `json:"send-push-notifications?,omitempty"`
|
||||
Appearance uint `json:"appearance"`
|
||||
// ProfilePicturesShowTo indicates to whom the user shows their profile picture to (contacts, everyone)
|
||||
ProfilePicturesShowTo ProfilePicturesShowToType `json:"profile-pictures-show-to"`
|
||||
// ProfilePicturesVisibility indicates who we want to see profile pictures of (contacts, everyone or none)
|
||||
ProfilePicturesVisibility ProfilePicturesVisibilityType `json:"profile-pictures-visibility"`
|
||||
UseMailservers bool `json:"use-mailservers?"`
|
||||
Usernames *json.RawMessage `json:"usernames,omitempty"`
|
||||
WalletRootAddress types.Address `json:"wallet-root-address,omitempty"`
|
||||
WalletSetUpPassed bool `json:"wallet-set-up-passed?,omitempty"`
|
||||
WalletVisibleTokens *json.RawMessage `json:"wallet/visible-tokens,omitempty"`
|
||||
WakuBloomFilterMode bool `json:"waku-bloom-filter-mode,omitempty"`
|
||||
WebViewAllowPermissionRequests bool `json:"webview-allow-permission-requests?,omitempty"`
|
||||
SendStatusUpdates bool `json:"send-status-updates?,omitempty"`
|
||||
CurrentUserStatus *json.RawMessage `json:"current-user-status"`
|
||||
GifRecents *json.RawMessage `json:"gifs/recent-gifs"`
|
||||
GifFavorites *json.RawMessage `json:"gifs/favorite-gifs"`
|
||||
OpenseaEnabled bool `json:"opensea-enabled?,omitempty"`
|
||||
TelemetryServerURL string `json:"telemetry-server-url,omitempty"`
|
||||
LastBackup uint64 `json:"last-backup,omitempty"`
|
||||
BackupEnabled bool `json:"backup-enabled?,omitempty"`
|
||||
AutoMessageEnabled bool `json:"auto-message-enabled?,omitempty"`
|
||||
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"`
|
||||
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"`
|
||||
DisplayAssetsBelowBalanceThreshold int64 `json:"display-assets-below-balance-threshold,omitempty"`
|
||||
CollectibleGroupByCollection bool `json:"collectible-group-by-collection?,omitempty"`
|
||||
CollectibleGroupByCommunity bool `json:"collectible-group-by-community?,omitempty"`
|
||||
URLUnfurlingMode URLUnfurlingModeType `json:"url-unfurling-mode,omitempty"`
|
||||
}
|
||||
|
||||
func (s Settings) MarshalJSON() ([]byte, error) {
|
||||
// We need this typedef in order to overcome stack overflow
|
||||
// when marshaling JSON
|
||||
type Alias Settings
|
||||
|
||||
ext, err := accountJson.ExtendStructWithPubKeyData(s.PublicKey, Alias(s))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(ext)
|
||||
}
|
||||
|
||||
func (s Settings) IsEmpty() bool {
|
||||
empty := reflect.Zero(reflect.TypeOf(s)).Interface()
|
||||
return reflect.DeepEqual(s, empty)
|
||||
}
|
||||
618
vendor/github.com/status-im/status-go/multiaccounts/settings/sync_protobuf_factories.go
generated
vendored
Normal file
618
vendor/github.com/status-im/status-go/multiaccounts/settings/sync_protobuf_factories.go
generated
vendored
Normal file
@@ -0,0 +1,618 @@
|
||||
package settings
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/status-im/status-go/protocol/common"
|
||||
"github.com/status-im/status-go/protocol/protobuf"
|
||||
"github.com/status-im/status-go/sqlite"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrTypeAssertionFailed = errors.New("type assertion of interface value failed")
|
||||
)
|
||||
|
||||
func buildRawSyncSettingMessage(msg *protobuf.SyncSetting, chatID string) (*common.RawMessage, error) {
|
||||
encodedMessage, err := proto.Marshal(msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &common.RawMessage{
|
||||
LocalChatID: chatID,
|
||||
Payload: encodedMessage,
|
||||
MessageType: protobuf.ApplicationMetadataMessage_SYNC_SETTING,
|
||||
ResendAutomatically: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Currency
|
||||
|
||||
func buildRawCurrencySyncMessage(v string, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
pb := &protobuf.SyncSetting{
|
||||
Type: protobuf.SyncSetting_CURRENCY,
|
||||
Value: &protobuf.SyncSetting_ValueString{ValueString: v},
|
||||
Clock: clock,
|
||||
}
|
||||
rm, err := buildRawSyncSettingMessage(pb, chatID)
|
||||
return rm, pb, err
|
||||
}
|
||||
|
||||
func currencyProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
v, err := assertString(value)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return buildRawCurrencySyncMessage(v, clock, chatID)
|
||||
}
|
||||
|
||||
func currencyProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
return buildRawCurrencySyncMessage(s.Currency, clock, chatID)
|
||||
}
|
||||
|
||||
// GifFavorites
|
||||
|
||||
func buildRawGifFavoritesSyncMessage(v []byte, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
pb := &protobuf.SyncSetting{
|
||||
Type: protobuf.SyncSetting_GIF_FAVOURITES,
|
||||
Value: &protobuf.SyncSetting_ValueBytes{ValueBytes: v},
|
||||
Clock: clock,
|
||||
}
|
||||
rm, err := buildRawSyncSettingMessage(pb, chatID)
|
||||
return rm, pb, err
|
||||
}
|
||||
|
||||
func gifFavouritesProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
v, err := assertBytes(value)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return buildRawGifFavoritesSyncMessage(v, clock, chatID)
|
||||
}
|
||||
|
||||
func gifFavouritesProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
gf := extractJSONRawMessage(s.GifFavorites)
|
||||
return buildRawGifFavoritesSyncMessage(gf, clock, chatID)
|
||||
}
|
||||
|
||||
// GifRecents
|
||||
|
||||
func buildRawGifRecentsSyncMessage(v []byte, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
pb := &protobuf.SyncSetting{
|
||||
Type: protobuf.SyncSetting_GIF_RECENTS,
|
||||
Value: &protobuf.SyncSetting_ValueBytes{ValueBytes: v},
|
||||
Clock: clock,
|
||||
}
|
||||
rm, err := buildRawSyncSettingMessage(pb, chatID)
|
||||
return rm, pb, err
|
||||
}
|
||||
|
||||
func gifRecentsProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
v, err := assertBytes(value)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return buildRawGifRecentsSyncMessage(v, clock, chatID)
|
||||
}
|
||||
|
||||
func gifRecentsProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
gr := extractJSONRawMessage(s.GifRecents)
|
||||
return buildRawGifRecentsSyncMessage(gr, clock, chatID)
|
||||
}
|
||||
|
||||
// MessagesFromContactsOnly
|
||||
|
||||
func buildRawMessagesFromContactsOnlySyncMessage(v bool, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
pb := &protobuf.SyncSetting{
|
||||
Type: protobuf.SyncSetting_MESSAGES_FROM_CONTACTS_ONLY,
|
||||
Value: &protobuf.SyncSetting_ValueBool{ValueBool: v},
|
||||
Clock: clock,
|
||||
}
|
||||
rm, err := buildRawSyncSettingMessage(pb, chatID)
|
||||
return rm, pb, err
|
||||
}
|
||||
|
||||
func messagesFromContactsOnlyProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
v, err := assertBool(value)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return buildRawMessagesFromContactsOnlySyncMessage(v, clock, chatID)
|
||||
}
|
||||
|
||||
func messagesFromContactsOnlyProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
return buildRawMessagesFromContactsOnlySyncMessage(s.MessagesFromContactsOnly, clock, chatID)
|
||||
}
|
||||
|
||||
// PreferredName
|
||||
|
||||
func buildRawPreferredNameSyncMessage(v string, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
pb := &protobuf.SyncSetting{
|
||||
Type: protobuf.SyncSetting_PREFERRED_NAME,
|
||||
Value: &protobuf.SyncSetting_ValueString{ValueString: v},
|
||||
Clock: clock,
|
||||
}
|
||||
rm, err := buildRawSyncSettingMessage(pb, chatID)
|
||||
return rm, pb, err
|
||||
}
|
||||
|
||||
func preferredNameProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
v, err := assertString(value)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return buildRawPreferredNameSyncMessage(v, clock, chatID)
|
||||
}
|
||||
|
||||
func preferredNameProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
var pn string
|
||||
if s.PreferredName != nil {
|
||||
pn = *s.PreferredName
|
||||
}
|
||||
|
||||
return buildRawPreferredNameSyncMessage(pn, clock, chatID)
|
||||
}
|
||||
|
||||
// PreviewPrivacy
|
||||
|
||||
func buildRawPreviewPrivacySyncMessage(v bool, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
pb := &protobuf.SyncSetting{
|
||||
Type: protobuf.SyncSetting_PREVIEW_PRIVACY,
|
||||
Value: &protobuf.SyncSetting_ValueBool{ValueBool: v},
|
||||
Clock: clock,
|
||||
}
|
||||
rm, err := buildRawSyncSettingMessage(pb, chatID)
|
||||
return rm, pb, err
|
||||
}
|
||||
|
||||
func previewPrivacyProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
v, err := assertBool(value)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return buildRawPreviewPrivacySyncMessage(v, clock, chatID)
|
||||
}
|
||||
|
||||
func previewPrivacyProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
return buildRawPreviewPrivacySyncMessage(s.PreviewPrivacy, clock, chatID)
|
||||
}
|
||||
|
||||
// ProfilePicturesShowTo
|
||||
|
||||
func buildRawProfilePicturesShowToSyncMessage(v int64, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
pb := &protobuf.SyncSetting{
|
||||
Type: protobuf.SyncSetting_PROFILE_PICTURES_SHOW_TO,
|
||||
Value: &protobuf.SyncSetting_ValueInt64{ValueInt64: v},
|
||||
Clock: clock,
|
||||
}
|
||||
rm, err := buildRawSyncSettingMessage(pb, chatID)
|
||||
return rm, pb, err
|
||||
}
|
||||
|
||||
func profilePicturesShowToProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
v, err := parseNumberToInt64(value)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return buildRawProfilePicturesShowToSyncMessage(v, clock, chatID)
|
||||
}
|
||||
|
||||
func profilePicturesShowToProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
return buildRawProfilePicturesShowToSyncMessage(int64(s.ProfilePicturesShowTo), clock, chatID)
|
||||
}
|
||||
|
||||
// ProfilePicturesVisibility
|
||||
|
||||
func buildRawProfilePicturesVisibilitySyncMessage(v int64, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
pb := &protobuf.SyncSetting{
|
||||
Type: protobuf.SyncSetting_PROFILE_PICTURES_VISIBILITY,
|
||||
Value: &protobuf.SyncSetting_ValueInt64{ValueInt64: v},
|
||||
Clock: clock,
|
||||
}
|
||||
rm, err := buildRawSyncSettingMessage(pb, chatID)
|
||||
return rm, pb, err
|
||||
}
|
||||
|
||||
func profilePicturesVisibilityProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
v, err := parseNumberToInt64(value)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return buildRawProfilePicturesVisibilitySyncMessage(v, clock, chatID)
|
||||
}
|
||||
|
||||
func profilePicturesVisibilityProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
return buildRawProfilePicturesVisibilitySyncMessage(int64(s.ProfilePicturesVisibility), clock, chatID)
|
||||
}
|
||||
|
||||
// SendStatusUpdates
|
||||
|
||||
func buildRawSendStatusUpdatesSyncMessage(v bool, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
pb := &protobuf.SyncSetting{
|
||||
Type: protobuf.SyncSetting_SEND_STATUS_UPDATES,
|
||||
Value: &protobuf.SyncSetting_ValueBool{ValueBool: v},
|
||||
Clock: clock,
|
||||
}
|
||||
rm, err := buildRawSyncSettingMessage(pb, chatID)
|
||||
return rm, pb, err
|
||||
}
|
||||
|
||||
func sendStatusUpdatesProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
v, err := assertBool(value)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return buildRawSendStatusUpdatesSyncMessage(v, clock, chatID)
|
||||
}
|
||||
|
||||
func sendStatusUpdatesProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
return buildRawSendStatusUpdatesSyncMessage(s.SendStatusUpdates, clock, chatID)
|
||||
}
|
||||
|
||||
// StickerPacksInstalled
|
||||
|
||||
func buildRawStickerPacksInstalledSyncMessage(v []byte, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
pb := &protobuf.SyncSetting{
|
||||
Type: protobuf.SyncSetting_STICKERS_PACKS_INSTALLED,
|
||||
Value: &protobuf.SyncSetting_ValueBytes{ValueBytes: v},
|
||||
Clock: clock,
|
||||
}
|
||||
rm, err := buildRawSyncSettingMessage(pb, chatID)
|
||||
return rm, pb, err
|
||||
}
|
||||
|
||||
func stickersPacksInstalledProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
v, err := parseJSONBlobData(value)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return buildRawStickerPacksInstalledSyncMessage(v, clock, chatID)
|
||||
}
|
||||
|
||||
func stickersPacksInstalledProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
spi := extractJSONRawMessage(s.StickerPacksInstalled)
|
||||
return buildRawStickerPacksInstalledSyncMessage(spi, clock, chatID)
|
||||
}
|
||||
|
||||
// StickerPacksPending
|
||||
|
||||
func buildRawStickerPacksPendingSyncMessage(v []byte, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
pb := &protobuf.SyncSetting{
|
||||
Type: protobuf.SyncSetting_STICKERS_PACKS_PENDING,
|
||||
Value: &protobuf.SyncSetting_ValueBytes{ValueBytes: v},
|
||||
Clock: clock,
|
||||
}
|
||||
rm, err := buildRawSyncSettingMessage(pb, chatID)
|
||||
return rm, pb, err
|
||||
}
|
||||
|
||||
func stickersPacksPendingProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
v, err := parseJSONBlobData(value)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return buildRawStickerPacksPendingSyncMessage(v, clock, chatID)
|
||||
}
|
||||
|
||||
func stickersPacksPendingProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
spp := extractJSONRawMessage(s.StickerPacksPending)
|
||||
return buildRawStickerPacksPendingSyncMessage(spp, clock, chatID)
|
||||
}
|
||||
|
||||
// StickersRecentStickers
|
||||
|
||||
func buildRawStickersRecentStickersSyncMessage(v []byte, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
pb := &protobuf.SyncSetting{
|
||||
Type: protobuf.SyncSetting_STICKERS_RECENT_STICKERS,
|
||||
Value: &protobuf.SyncSetting_ValueBytes{ValueBytes: v},
|
||||
Clock: clock,
|
||||
}
|
||||
rm, err := buildRawSyncSettingMessage(pb, chatID)
|
||||
return rm, pb, err
|
||||
}
|
||||
|
||||
func stickersRecentStickersProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
v, err := parseJSONBlobData(value)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return buildRawStickersRecentStickersSyncMessage(v, clock, chatID)
|
||||
}
|
||||
|
||||
func stickersRecentStickersProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
srs := extractJSONRawMessage(s.StickersRecentStickers)
|
||||
return buildRawStickersRecentStickersSyncMessage(srs, clock, chatID)
|
||||
}
|
||||
|
||||
func assertBytes(value interface{}) ([]byte, error) {
|
||||
v, ok := value.([]byte)
|
||||
if !ok {
|
||||
return nil, errors.Wrapf(ErrTypeAssertionFailed, "expected '[]byte', received %T", value)
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func assertBool(value interface{}) (bool, error) {
|
||||
v, ok := value.(bool)
|
||||
if !ok {
|
||||
return false, errors.Wrapf(ErrTypeAssertionFailed, "expected 'bool', received %T", value)
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func assertString(value interface{}) (string, error) {
|
||||
rv := reflect.ValueOf(value)
|
||||
if rv.Kind() == reflect.Ptr {
|
||||
value = *value.(*string)
|
||||
}
|
||||
v, ok := value.(string)
|
||||
if !ok {
|
||||
return "", errors.Wrapf(ErrTypeAssertionFailed, "expected 'string', received %T", value)
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func parseJSONBlobData(value interface{}) ([]byte, error) {
|
||||
switch v := value.(type) {
|
||||
case []byte:
|
||||
return v, nil
|
||||
case *sqlite.JSONBlob:
|
||||
return extractJSONBlob(v)
|
||||
default:
|
||||
return nil, errors.Wrapf(ErrTypeAssertionFailed, "expected []byte or *sqlite.JSONBlob, received %T", value)
|
||||
}
|
||||
}
|
||||
|
||||
func parseNumberToInt64(value interface{}) (int64, error) {
|
||||
switch v := value.(type) {
|
||||
case float32:
|
||||
return int64(v), nil
|
||||
case float64:
|
||||
return int64(v), nil
|
||||
case int:
|
||||
return int64(v), nil
|
||||
case int8:
|
||||
return int64(v), nil
|
||||
case int16:
|
||||
return int64(v), nil
|
||||
case int32:
|
||||
return int64(v), nil
|
||||
case int64:
|
||||
return v, nil
|
||||
case uint:
|
||||
return int64(v), nil
|
||||
case uint8:
|
||||
return int64(v), nil
|
||||
case uint16:
|
||||
return int64(v), nil
|
||||
case uint32:
|
||||
return int64(v), nil
|
||||
case uint64:
|
||||
return int64(v), nil
|
||||
case ProfilePicturesShowToType:
|
||||
return int64(v), nil
|
||||
case ProfilePicturesVisibilityType:
|
||||
return int64(v), nil
|
||||
case URLUnfurlingModeType:
|
||||
return int64(v), nil
|
||||
default:
|
||||
return 0, errors.Wrapf(ErrTypeAssertionFailed, "expected a numeric type, received %T", value)
|
||||
}
|
||||
}
|
||||
|
||||
func extractJSONBlob(jb *sqlite.JSONBlob) ([]byte, error) {
|
||||
value, err := jb.Value()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if value == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return value.([]byte), nil
|
||||
}
|
||||
|
||||
func extractJSONRawMessage(jrm *json.RawMessage) []byte {
|
||||
if jrm == nil {
|
||||
return nil
|
||||
}
|
||||
out, _ := jrm.MarshalJSON() // Don't need to parse error because it is always nil
|
||||
if len(out) == 0 || bytes.Equal(out, []byte("null")) {
|
||||
return nil
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// DisplayName
|
||||
|
||||
func buildRawDisplayNameSyncMessage(v string, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
pb := &protobuf.SyncSetting{
|
||||
Type: protobuf.SyncSetting_DISPLAY_NAME,
|
||||
Value: &protobuf.SyncSetting_ValueString{ValueString: v},
|
||||
Clock: clock,
|
||||
}
|
||||
rm, err := buildRawSyncSettingMessage(pb, chatID)
|
||||
return rm, pb, err
|
||||
}
|
||||
|
||||
func displayNameProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
v, err := assertString(value)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return buildRawDisplayNameSyncMessage(v, clock, chatID)
|
||||
}
|
||||
|
||||
func displayNameProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
|
||||
return buildRawDisplayNameSyncMessage(s.DisplayName, clock, chatID)
|
||||
}
|
||||
|
||||
// Bio
|
||||
|
||||
func buildRawBioSyncMessage(v string, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
pb := &protobuf.SyncSetting{
|
||||
Type: protobuf.SyncSetting_BIO,
|
||||
Value: &protobuf.SyncSetting_ValueString{ValueString: v},
|
||||
Clock: clock,
|
||||
}
|
||||
rm, err := buildRawSyncSettingMessage(pb, chatID)
|
||||
return rm, pb, err
|
||||
}
|
||||
|
||||
func bioProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
v, err := assertString(value)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return buildRawBioSyncMessage(v, clock, chatID)
|
||||
}
|
||||
|
||||
func bioProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
return buildRawBioSyncMessage(s.Bio, clock, chatID)
|
||||
}
|
||||
|
||||
// MnemonicRemoved
|
||||
|
||||
func buildRawMnemonicRemovedSyncMessage(v bool, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
pb := &protobuf.SyncSetting{
|
||||
Type: protobuf.SyncSetting_MNEMONIC_REMOVED,
|
||||
Value: &protobuf.SyncSetting_ValueBool{ValueBool: v},
|
||||
Clock: clock,
|
||||
}
|
||||
rm, err := buildRawSyncSettingMessage(pb, chatID)
|
||||
return rm, pb, err
|
||||
}
|
||||
|
||||
func mnemonicRemovedProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
v, err := assertBool(value)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return buildRawMnemonicRemovedSyncMessage(v, clock, chatID)
|
||||
}
|
||||
|
||||
func mnemonicRemovedProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
return buildRawMnemonicRemovedSyncMessage(s.MnemonicRemoved, clock, chatID)
|
||||
}
|
||||
|
||||
// UrlUnfurlingMode
|
||||
|
||||
func buildRawURLUnfurlingModeSyncMessage(v int64, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
pb := &protobuf.SyncSetting{
|
||||
Type: protobuf.SyncSetting_URL_UNFURLING_MODE,
|
||||
Value: &protobuf.SyncSetting_ValueInt64{ValueInt64: v},
|
||||
Clock: clock,
|
||||
}
|
||||
rm, err := buildRawSyncSettingMessage(pb, chatID)
|
||||
return rm, pb, err
|
||||
}
|
||||
|
||||
func urlUnfurlingModeProtobufFactory(value any, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
v, err := parseNumberToInt64(value)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return buildRawURLUnfurlingModeSyncMessage(v, clock, chatID)
|
||||
}
|
||||
|
||||
func urlUnfurlingModeProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
return buildRawURLUnfurlingModeSyncMessage(int64(s.URLUnfurlingMode), clock, chatID)
|
||||
}
|
||||
|
||||
// ShowCommunityAssetWhenSendingTokens
|
||||
|
||||
func buildRawShowCommunityAssetWhenSendingTokensSyncMessage(v bool, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
pb := &protobuf.SyncSetting{
|
||||
Type: protobuf.SyncSetting_SHOW_COMMUNITY_ASSET_WHEN_SENDING_TOKENS,
|
||||
Value: &protobuf.SyncSetting_ValueBool{ValueBool: v},
|
||||
Clock: clock,
|
||||
}
|
||||
rm, err := buildRawSyncSettingMessage(pb, chatID)
|
||||
return rm, pb, err
|
||||
}
|
||||
|
||||
func showCommunityAssetWhenSendingTokensProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
v, err := assertBool(value)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return buildRawShowCommunityAssetWhenSendingTokensSyncMessage(v, clock, chatID)
|
||||
}
|
||||
|
||||
func showCommunityAssetWhenSendingTokensProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
return buildRawShowCommunityAssetWhenSendingTokensSyncMessage(s.ShowCommunityAssetWhenSendingTokens, clock, chatID)
|
||||
}
|
||||
|
||||
// DisplayAssetsBelowBalance
|
||||
|
||||
func buildRawDisplayAssetsBelowBalanceSyncMessage(v bool, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
pb := &protobuf.SyncSetting{
|
||||
Type: protobuf.SyncSetting_DISPLAY_ASSETS_BELOW_BALANCE,
|
||||
Value: &protobuf.SyncSetting_ValueBool{ValueBool: v},
|
||||
Clock: clock,
|
||||
}
|
||||
rm, err := buildRawSyncSettingMessage(pb, chatID)
|
||||
return rm, pb, err
|
||||
}
|
||||
|
||||
func displayAssetsBelowBalanceProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
v, err := assertBool(value)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return buildRawDisplayAssetsBelowBalanceSyncMessage(v, clock, chatID)
|
||||
}
|
||||
|
||||
func displayAssetsBelowBalanceProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
return buildRawDisplayAssetsBelowBalanceSyncMessage(s.DisplayAssetsBelowBalance, clock, chatID)
|
||||
}
|
||||
|
||||
// DisplayAssetsBelowBalanceThreshold
|
||||
|
||||
func buildRawDisplayAssetsBelowBalanceThresholdSyncMessage(v int64, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
pb := &protobuf.SyncSetting{
|
||||
Type: protobuf.SyncSetting_DISPLAY_ASSETS_BELOW_BALANCE_THRESHOLD,
|
||||
Value: &protobuf.SyncSetting_ValueInt64{ValueInt64: v},
|
||||
Clock: clock,
|
||||
}
|
||||
rm, err := buildRawSyncSettingMessage(pb, chatID)
|
||||
return rm, pb, err
|
||||
}
|
||||
|
||||
func displayAssetsBelowBalanceThresholdProtobufFactory(value any, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
v, err := parseNumberToInt64(value)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return buildRawDisplayAssetsBelowBalanceThresholdSyncMessage(v, clock, chatID)
|
||||
}
|
||||
|
||||
func displayAssetsBelowBalanceThresholdProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
|
||||
return buildRawDisplayAssetsBelowBalanceThresholdSyncMessage(s.DisplayAssetsBelowBalanceThreshold, clock, chatID)
|
||||
}
|
||||
74
vendor/github.com/status-im/status-go/multiaccounts/settings/value_handlers.go
generated
vendored
Normal file
74
vendor/github.com/status-im/status-go/multiaccounts/settings/value_handlers.go
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
package settings
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/status-im/status-go/eth-node/types"
|
||||
"github.com/status-im/status-go/multiaccounts/errors"
|
||||
"github.com/status-im/status-go/params"
|
||||
"github.com/status-im/status-go/protocol/protobuf"
|
||||
"github.com/status-im/status-go/sqlite"
|
||||
)
|
||||
|
||||
func StringFromSyncProtobuf(ss *protobuf.SyncSetting) interface{} {
|
||||
return ss.GetValueString()
|
||||
}
|
||||
|
||||
func BoolFromSyncProtobuf(ss *protobuf.SyncSetting) interface{} {
|
||||
return ss.GetValueBool()
|
||||
}
|
||||
|
||||
func BytesFromSyncProtobuf(ss *protobuf.SyncSetting) interface{} {
|
||||
return ss.GetValueBytes()
|
||||
}
|
||||
|
||||
func Int64FromSyncProtobuf(ss *protobuf.SyncSetting) interface{} {
|
||||
return ss.GetValueInt64()
|
||||
}
|
||||
|
||||
func BoolHandler(value interface{}) (interface{}, error) {
|
||||
_, ok := value.(bool)
|
||||
if !ok {
|
||||
return value, errors.ErrInvalidConfig
|
||||
}
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func Int64Handler(value interface{}) (interface{}, error) {
|
||||
_, ok := value.(int64)
|
||||
if !ok {
|
||||
return value, errors.ErrInvalidConfig
|
||||
}
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func JSONBlobHandler(value interface{}) (interface{}, error) {
|
||||
return &sqlite.JSONBlob{Data: value}, nil
|
||||
}
|
||||
|
||||
func AddressHandler(value interface{}) (interface{}, error) {
|
||||
str, ok := value.(string)
|
||||
if ok {
|
||||
value = types.HexToAddress(str)
|
||||
} else {
|
||||
return value, errors.ErrInvalidConfig
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func NodeConfigHandler(value interface{}) (interface{}, error) {
|
||||
jsonString, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nodeConfig := new(params.NodeConfig)
|
||||
err = json.Unmarshal(jsonString, nodeConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nodeConfig, nil
|
||||
}
|
||||
315
vendor/github.com/status-im/status-go/multiaccounts/settings_notifications/database.go
generated
vendored
Normal file
315
vendor/github.com/status-im/status-go/multiaccounts/settings_notifications/database.go
generated
vendored
Normal file
@@ -0,0 +1,315 @@
|
||||
package notificationssettings
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type settingType int
|
||||
|
||||
const (
|
||||
stringType settingType = iota
|
||||
integerType
|
||||
boolType
|
||||
)
|
||||
|
||||
// Columns' names
|
||||
type column string
|
||||
|
||||
const (
|
||||
columnTextValue column = "text_value"
|
||||
columnIntValue column = "int_value"
|
||||
columnBoolValue column = "bool_value"
|
||||
columnExMuteAllMessages column = "ex_mute_all_messages"
|
||||
columnExPersonalMentions column = "ex_personal_mentions"
|
||||
columnExGlobalMentions column = "ex_global_mentions"
|
||||
columnExOtherMessages column = "ex_other_messages"
|
||||
)
|
||||
|
||||
// Static ids we use for notifications settings
|
||||
const (
|
||||
keyAllowNotifications = "AllowNotifications"
|
||||
keyOneToOneChats = "OneToOneChats"
|
||||
keyGroupChats = "GroupChats"
|
||||
keyPersonalMentions = "PersonalMentions"
|
||||
keyGlobalMentions = "GlobalMentions"
|
||||
keyAllMessages = "AllMessages"
|
||||
keyContactRequests = "ContactRequests"
|
||||
keyIdentityVerificationRequests = "IdentityVerificationRequests"
|
||||
keySoundEnabled = "SoundEnabled"
|
||||
keyVolume = "Volume"
|
||||
keyMessagePreview = "MessagePreview"
|
||||
)
|
||||
|
||||
// Possible values
|
||||
const (
|
||||
valueSendAlerts = "SendAlerts"
|
||||
//valueDeliverQuietly = "DeliverQuietly" // currently unused
|
||||
valueTurnOff = "TurnOff"
|
||||
)
|
||||
|
||||
// Default values
|
||||
const (
|
||||
defaultAllowNotificationsValue = true
|
||||
defaultOneToOneChatsValue = valueSendAlerts
|
||||
defaultGroupChatsValue = valueSendAlerts
|
||||
defaultPersonalMentionsValue = valueSendAlerts
|
||||
defaultGlobalMentionsValue = valueSendAlerts
|
||||
defaultAllMessagesValue = valueTurnOff
|
||||
defaultContactRequestsValue = valueSendAlerts
|
||||
defaultIdentityVerificationRequestsValue = valueSendAlerts
|
||||
defaultSoundEnabledValue = true
|
||||
defaultVolumeValue = 50
|
||||
defaultMessagePreviewValue = 2
|
||||
defaultExMuteAllMessagesValue = false
|
||||
defaultExPersonalMentionsValue = valueSendAlerts
|
||||
defaultExGlobalMentionsValue = valueSendAlerts
|
||||
defaultExOtherMessagesValue = valueTurnOff
|
||||
)
|
||||
|
||||
type NotificationsSettings struct {
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
func NewNotificationsSettings(db *sql.DB) *NotificationsSettings {
|
||||
return &NotificationsSettings{
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
func (ns *NotificationsSettings) buildSelectQuery(column column) string {
|
||||
return fmt.Sprintf("SELECT %s FROM notifications_settings WHERE id = ?", column)
|
||||
}
|
||||
|
||||
func (ns *NotificationsSettings) buildInsertOrUpdateQuery(isExemption bool, settingType settingType) string {
|
||||
var values string
|
||||
if isExemption {
|
||||
values = "VALUES(?, 1, NULL, NULL, NULL, ?, ?, ?, ?)"
|
||||
} else {
|
||||
switch settingType {
|
||||
case stringType:
|
||||
values = "VALUES(?, 0, ?, NULL, NULL, NULL, NULL, NULL, NULL)"
|
||||
case integerType:
|
||||
values = "VALUES(?, 0, NULL, ?, NULL, NULL, NULL, NULL, NULL)"
|
||||
case boolType:
|
||||
values = "VALUES(?, 0, NULL, NULL, ?, NULL, NULL, NULL, NULL)"
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf(`INSERT INTO notifications_settings (
|
||||
id,
|
||||
exemption,
|
||||
text_value,
|
||||
int_value,
|
||||
bool_value,
|
||||
ex_mute_all_messages,
|
||||
ex_personal_mentions,
|
||||
ex_global_mentions,
|
||||
ex_other_messages)
|
||||
%s;`, values)
|
||||
}
|
||||
|
||||
// Non exemption settings
|
||||
func (ns *NotificationsSettings) GetAllowNotifications() (result bool, err error) {
|
||||
err = ns.db.QueryRow(ns.buildSelectQuery(columnBoolValue), keyAllowNotifications).Scan(&result)
|
||||
if err != nil && err == sql.ErrNoRows {
|
||||
return defaultAllowNotificationsValue, err
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (ns *NotificationsSettings) SetAllowNotifications(value bool) error {
|
||||
_, err := ns.db.Exec(ns.buildInsertOrUpdateQuery(false, boolType), keyAllowNotifications, value, value)
|
||||
return err
|
||||
}
|
||||
|
||||
func (ns *NotificationsSettings) GetOneToOneChats() (result string, err error) {
|
||||
err = ns.db.QueryRow(ns.buildSelectQuery(columnTextValue), keyOneToOneChats).Scan(&result)
|
||||
if err != nil && err == sql.ErrNoRows {
|
||||
return defaultOneToOneChatsValue, err
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (ns *NotificationsSettings) SetOneToOneChats(value string) error {
|
||||
_, err := ns.db.Exec(ns.buildInsertOrUpdateQuery(false, stringType), keyOneToOneChats, value, value)
|
||||
return err
|
||||
}
|
||||
|
||||
func (ns *NotificationsSettings) GetGroupChats() (result string, err error) {
|
||||
err = ns.db.QueryRow(ns.buildSelectQuery(columnTextValue), keyGroupChats).Scan(&result)
|
||||
if err != nil && err == sql.ErrNoRows {
|
||||
return defaultGroupChatsValue, err
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (ns *NotificationsSettings) SetGroupChats(value string) error {
|
||||
_, err := ns.db.Exec(ns.buildInsertOrUpdateQuery(false, stringType), keyGroupChats, value, value)
|
||||
return err
|
||||
}
|
||||
|
||||
func (ns *NotificationsSettings) GetPersonalMentions() (result string, err error) {
|
||||
err = ns.db.QueryRow(ns.buildSelectQuery(columnTextValue), keyPersonalMentions).Scan(&result)
|
||||
if err != nil && err == sql.ErrNoRows {
|
||||
return defaultPersonalMentionsValue, err
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (ns *NotificationsSettings) SetPersonalMentions(value string) error {
|
||||
_, err := ns.db.Exec(ns.buildInsertOrUpdateQuery(false, stringType), keyPersonalMentions, value, value)
|
||||
return err
|
||||
}
|
||||
|
||||
func (ns *NotificationsSettings) GetGlobalMentions() (result string, err error) {
|
||||
err = ns.db.QueryRow(ns.buildSelectQuery(columnTextValue), keyGlobalMentions).Scan(&result)
|
||||
if err != nil && err == sql.ErrNoRows {
|
||||
return defaultGlobalMentionsValue, err
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (ns *NotificationsSettings) SetGlobalMentions(value string) error {
|
||||
_, err := ns.db.Exec(ns.buildInsertOrUpdateQuery(false, stringType), keyGlobalMentions, value, value)
|
||||
return err
|
||||
}
|
||||
|
||||
func (ns *NotificationsSettings) GetAllMessages() (result string, err error) {
|
||||
err = ns.db.QueryRow(ns.buildSelectQuery(columnTextValue), keyAllMessages).Scan(&result)
|
||||
if err != nil && err == sql.ErrNoRows {
|
||||
return defaultAllMessagesValue, err
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (ns *NotificationsSettings) SetAllMessages(value string) error {
|
||||
_, err := ns.db.Exec(ns.buildInsertOrUpdateQuery(false, stringType), keyAllMessages, value, value)
|
||||
return err
|
||||
}
|
||||
|
||||
func (ns *NotificationsSettings) GetContactRequests() (result string, err error) {
|
||||
err = ns.db.QueryRow(ns.buildSelectQuery(columnTextValue), keyContactRequests).Scan(&result)
|
||||
if err != nil && err == sql.ErrNoRows {
|
||||
return defaultContactRequestsValue, err
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (ns *NotificationsSettings) SetContactRequests(value string) error {
|
||||
_, err := ns.db.Exec(ns.buildInsertOrUpdateQuery(false, stringType), keyContactRequests, value, value)
|
||||
return err
|
||||
}
|
||||
|
||||
func (ns *NotificationsSettings) GetIdentityVerificationRequests() (result string, err error) {
|
||||
err = ns.db.QueryRow(ns.buildSelectQuery(columnTextValue), keyIdentityVerificationRequests).Scan(&result)
|
||||
if err != nil && err == sql.ErrNoRows {
|
||||
return defaultIdentityVerificationRequestsValue, err
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (ns *NotificationsSettings) SetIdentityVerificationRequests(value string) error {
|
||||
_, err := ns.db.Exec(ns.buildInsertOrUpdateQuery(false, stringType), keyIdentityVerificationRequests, value, value)
|
||||
return err
|
||||
}
|
||||
|
||||
func (ns *NotificationsSettings) GetSoundEnabled() (result bool, err error) {
|
||||
err = ns.db.QueryRow(ns.buildSelectQuery(columnBoolValue), keySoundEnabled).Scan(&result)
|
||||
if err != nil && err == sql.ErrNoRows {
|
||||
return defaultSoundEnabledValue, err
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (ns *NotificationsSettings) SetSoundEnabled(value bool) error {
|
||||
_, err := ns.db.Exec(ns.buildInsertOrUpdateQuery(false, boolType), keySoundEnabled, value, value)
|
||||
return err
|
||||
}
|
||||
|
||||
func (ns *NotificationsSettings) GetVolume() (result int, err error) {
|
||||
err = ns.db.QueryRow(ns.buildSelectQuery(columnIntValue), keyVolume).Scan(&result)
|
||||
if err != nil && err == sql.ErrNoRows {
|
||||
return defaultVolumeValue, err
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (ns *NotificationsSettings) SetVolume(value int) error {
|
||||
_, err := ns.db.Exec(ns.buildInsertOrUpdateQuery(false, integerType), keyVolume, value, value)
|
||||
return err
|
||||
}
|
||||
|
||||
func (ns *NotificationsSettings) GetMessagePreview() (result int, err error) {
|
||||
err = ns.db.QueryRow(ns.buildSelectQuery(columnIntValue), keyMessagePreview).Scan(&result)
|
||||
if err != nil && err == sql.ErrNoRows {
|
||||
return defaultMessagePreviewValue, err
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (ns *NotificationsSettings) SetMessagePreview(value int) error {
|
||||
_, err := ns.db.Exec(ns.buildInsertOrUpdateQuery(false, integerType), keyMessagePreview, value, value)
|
||||
return err
|
||||
}
|
||||
|
||||
// Exemption settings
|
||||
func (ns *NotificationsSettings) GetExMuteAllMessages(id string) (result bool, err error) {
|
||||
err = ns.db.QueryRow(ns.buildSelectQuery(columnExMuteAllMessages), id).Scan(&result)
|
||||
if err != nil && err == sql.ErrNoRows {
|
||||
return defaultExMuteAllMessagesValue, nil
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (ns *NotificationsSettings) GetExPersonalMentions(id string) (result string, err error) {
|
||||
err = ns.db.QueryRow(ns.buildSelectQuery(columnExPersonalMentions), id).Scan(&result)
|
||||
if err != nil && err == sql.ErrNoRows {
|
||||
return defaultExPersonalMentionsValue, nil
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (ns *NotificationsSettings) GetExGlobalMentions(id string) (result string, err error) {
|
||||
err = ns.db.QueryRow(ns.buildSelectQuery(columnExGlobalMentions), id).Scan(&result)
|
||||
if err != nil && err == sql.ErrNoRows {
|
||||
return defaultExGlobalMentionsValue, nil
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (ns *NotificationsSettings) GetExOtherMessages(id string) (result string, err error) {
|
||||
err = ns.db.QueryRow(ns.buildSelectQuery(columnExOtherMessages), id).Scan(&result)
|
||||
if err != nil && err == sql.ErrNoRows {
|
||||
return defaultExOtherMessagesValue, nil
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (ns *NotificationsSettings) SetExemptions(id string, muteAllMessages bool, personalMentions string,
|
||||
globalMentions string, otherMessages string) error {
|
||||
_, err := ns.db.Exec(ns.buildInsertOrUpdateQuery(true, stringType), id, muteAllMessages, personalMentions, globalMentions,
|
||||
otherMessages)
|
||||
return err
|
||||
}
|
||||
|
||||
func (ns *NotificationsSettings) DeleteExemptions(id string) error {
|
||||
switch id {
|
||||
case
|
||||
keyAllowNotifications,
|
||||
keyOneToOneChats,
|
||||
keyGroupChats,
|
||||
keyPersonalMentions,
|
||||
keyGlobalMentions,
|
||||
keyAllMessages,
|
||||
keyContactRequests,
|
||||
keyIdentityVerificationRequests,
|
||||
keySoundEnabled,
|
||||
keyVolume,
|
||||
keyMessagePreview:
|
||||
return fmt.Errorf("%s, static notifications settings cannot be deleted", id)
|
||||
}
|
||||
|
||||
_, err := ns.db.Exec("DELETE FROM notifications_settings WHERE id = ?", id)
|
||||
return err
|
||||
}
|
||||
143
vendor/github.com/status-im/status-go/multiaccounts/settings_social_links/database.go
generated
vendored
Normal file
143
vendor/github.com/status-im/status-go/multiaccounts/settings_social_links/database.go
generated
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
package sociallinkssettings
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
|
||||
"github.com/status-im/status-go/protocol/identity"
|
||||
)
|
||||
|
||||
const (
|
||||
MaxNumOfSocialLinks = 20
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNilSocialLinkProvided = errors.New("social links, nil object provided")
|
||||
ErrOlderSocialLinksProvided = errors.New("older social links provided")
|
||||
)
|
||||
|
||||
type SocialLinksSettings struct {
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
func NewSocialLinksSettings(db *sql.DB) *SocialLinksSettings {
|
||||
return &SocialLinksSettings{
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SocialLinksSettings) getSocialLinksClock(tx *sql.Tx) (result uint64, err error) {
|
||||
query := "SELECT social_links FROM settings_sync_clock WHERE synthetic_id = 'id'"
|
||||
if tx == nil {
|
||||
err = s.db.QueryRow(query).Scan(&result)
|
||||
} else {
|
||||
err = tx.QueryRow(query).Scan(&result)
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *SocialLinksSettings) getSocialLinks(tx *sql.Tx) (identity.SocialLinks, error) {
|
||||
var (
|
||||
rows *sql.Rows
|
||||
err error
|
||||
)
|
||||
query := "SELECT text, url FROM profile_social_links ORDER BY position ASC"
|
||||
|
||||
if tx == nil {
|
||||
rows, err = s.db.Query(query)
|
||||
} else {
|
||||
rows, err = tx.Query(query)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var socialLinks identity.SocialLinks
|
||||
for rows.Next() {
|
||||
socialLink := &identity.SocialLink{}
|
||||
err := rows.Scan(&socialLink.Text, &socialLink.URL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
socialLinks = append(socialLinks, socialLink)
|
||||
}
|
||||
|
||||
err = rows.Err()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return socialLinks, nil
|
||||
}
|
||||
|
||||
func (s *SocialLinksSettings) GetSocialLinks() (identity.SocialLinks, error) {
|
||||
return s.getSocialLinks(nil)
|
||||
}
|
||||
|
||||
func (s *SocialLinksSettings) GetSocialLinksClock() (result uint64, err error) {
|
||||
return s.getSocialLinksClock(nil)
|
||||
}
|
||||
|
||||
func (s *SocialLinksSettings) AddOrReplaceSocialLinksIfNewer(links identity.SocialLinks, clock uint64) error {
|
||||
tx, err := s.db.BeginTx(context.Background(), &sql.TxOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err == nil {
|
||||
err = tx.Commit()
|
||||
return
|
||||
}
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
dbClock, err := s.getSocialLinksClock(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if dbClock > clock {
|
||||
return ErrOlderSocialLinksProvided
|
||||
}
|
||||
|
||||
dbLinks, err := s.getSocialLinks(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(dbLinks) > 0 {
|
||||
_, err = tx.Exec("DELETE from profile_social_links")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
stmt, err := tx.Prepare("INSERT INTO profile_social_links (text, url, position) VALUES (?, ?, ?)")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer stmt.Close()
|
||||
|
||||
for position, link := range links {
|
||||
if link == nil {
|
||||
return ErrNilSocialLinkProvided
|
||||
}
|
||||
_, err = stmt.Exec(
|
||||
link.Text,
|
||||
link.URL,
|
||||
position,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
stmt, err = tx.Prepare("UPDATE settings_sync_clock SET social_links = ? WHERE synthetic_id = 'id'")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = stmt.Exec(clock)
|
||||
return err
|
||||
}
|
||||
229
vendor/github.com/status-im/status-go/multiaccounts/settings_wallet/database.go
generated
vendored
Normal file
229
vendor/github.com/status-im/status-go/multiaccounts/settings_wallet/database.go
generated
vendored
Normal file
@@ -0,0 +1,229 @@
|
||||
package walletsettings
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
)
|
||||
|
||||
type TokenPreferences struct {
|
||||
Key string `json:"key"`
|
||||
Position int `json:"position"`
|
||||
GroupPosition int `json:"groupPosition"`
|
||||
Visible bool `json:"visible"`
|
||||
CommunityID string `json:"communityId"`
|
||||
}
|
||||
|
||||
type CollectiblePreferencesType int
|
||||
|
||||
const (
|
||||
CollectiblePreferencesTypeNonCommunityCollectible CollectiblePreferencesType = iota + 1
|
||||
CollectiblePreferencesTypeCommunityCollectible
|
||||
CollectiblePreferencesTypeCollection
|
||||
CollectiblePreferencesTypeCommunity
|
||||
)
|
||||
|
||||
type CollectiblePreferences struct {
|
||||
Type CollectiblePreferencesType `json:"type"`
|
||||
Key string `json:"key"`
|
||||
Position int `json:"position"`
|
||||
Visible bool `json:"visible"`
|
||||
}
|
||||
|
||||
type WalletSettings struct {
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
func NewWalletSettings(db *sql.DB) *WalletSettings {
|
||||
return &WalletSettings{
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
// This function should not be used directly, it is called from the functions which update token preferences.
|
||||
func (ws *WalletSettings) setClockOfLastTokenPreferencesChange(tx *sql.Tx, clock uint64) error {
|
||||
if tx == nil {
|
||||
return errors.New("database transaction is nil")
|
||||
}
|
||||
_, err := tx.Exec("UPDATE settings SET wallet_token_preferences_change_clock = ? WHERE synthetic_id = 'id'", clock)
|
||||
return err
|
||||
}
|
||||
|
||||
func (ws *WalletSettings) GetClockOfLastTokenPreferencesChange() (result uint64, err error) {
|
||||
query := "SELECT wallet_token_preferences_change_clock FROM settings WHERE synthetic_id = 'id'"
|
||||
err = ws.db.QueryRow(query).Scan(&result)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (ws *WalletSettings) UpdateTokenPreferences(preferences []TokenPreferences, groupByCommunity bool, testNetworksEnabled bool, clock uint64) error {
|
||||
if len(preferences) == 0 {
|
||||
return errors.New("tokens: trying to create custom order with empty list")
|
||||
}
|
||||
|
||||
tx, err := ws.db.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var mainError error = nil
|
||||
|
||||
defer func() {
|
||||
if mainError == nil {
|
||||
err = tx.Commit()
|
||||
return
|
||||
}
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
_, mainError = tx.Exec("DELETE FROM token_preferences WHERE testnet = ?", testNetworksEnabled)
|
||||
if mainError != nil {
|
||||
return mainError
|
||||
}
|
||||
|
||||
for _, p := range preferences {
|
||||
if p.Position < 0 {
|
||||
mainError = errors.New("tokens: trying to create custom order with negative position")
|
||||
return mainError
|
||||
}
|
||||
_, err := tx.Exec("INSERT INTO token_preferences (key, position, group_position, visible, community_id, testnet) VALUES (?, ?, ?, ?, ?, ?)", p.Key, p.Position, p.GroupPosition, p.Visible, p.CommunityID, testNetworksEnabled)
|
||||
if err != nil {
|
||||
mainError = err
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if groupByCommunity {
|
||||
// Find community tokens without group position
|
||||
// Group position can be -1 if it wasn't created yet. Values must be consitstent across all tokens
|
||||
rows, err := tx.Query(`SELECT COUNT(*) FROM token_preferences WHERE testnet = ? AND group_position = -1 AND community_id != '' AND visible GROUP BY community_id HAVING COUNT(*) > 0`, testNetworksEnabled)
|
||||
if err != nil {
|
||||
mainError = err
|
||||
return err
|
||||
}
|
||||
if rows.Next() {
|
||||
mainError = errors.New("tokens: not all community tokens have assigned the group position")
|
||||
return mainError
|
||||
}
|
||||
}
|
||||
|
||||
mainError = ws.setClockOfLastTokenPreferencesChange(tx, clock)
|
||||
if mainError != nil {
|
||||
return mainError
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ws *WalletSettings) GetTokenPreferences(testNetworksEnabled bool) ([]TokenPreferences, error) {
|
||||
rows, err := ws.db.Query("SELECT key, position, group_position, visible, community_id FROM token_preferences WHERE testnet = ?", testNetworksEnabled)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var result []TokenPreferences
|
||||
|
||||
for rows.Next() {
|
||||
token := TokenPreferences{}
|
||||
err := rows.Scan(&token.Key, &token.Position, &token.GroupPosition, &token.Visible, &token.CommunityID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result = append(result, token)
|
||||
}
|
||||
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (ws *WalletSettings) setClockOfLastCollectiblePreferencesChange(tx *sql.Tx, clock uint64) error {
|
||||
if tx == nil {
|
||||
return errors.New("database transaction is nil")
|
||||
}
|
||||
_, err := tx.Exec("UPDATE settings SET wallet_collectible_preferences_change_clock = ? WHERE synthetic_id = 'id'", clock)
|
||||
return err
|
||||
}
|
||||
|
||||
func (ws *WalletSettings) GetClockOfLastCollectiblePreferencesChange() (result uint64, err error) {
|
||||
query := "SELECT wallet_collectible_preferences_change_clock FROM settings WHERE synthetic_id = 'id'"
|
||||
err = ws.db.QueryRow(query).Scan(&result)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (ws *WalletSettings) UpdateCollectiblePreferences(preferences []CollectiblePreferences, groupByCommunity bool, groupByCollection bool, testNetworksEnabled bool, clock uint64) error {
|
||||
if len(preferences) == 0 {
|
||||
return errors.New("collectibles: trying to create custom order with empty list")
|
||||
}
|
||||
|
||||
tx, err := ws.db.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var mainError error = nil
|
||||
|
||||
defer func() {
|
||||
if mainError == nil {
|
||||
err = tx.Commit()
|
||||
return
|
||||
}
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
_, mainError = tx.Exec("DELETE FROM collectible_preferences WHERE testnet = ?", testNetworksEnabled)
|
||||
if mainError != nil {
|
||||
return mainError
|
||||
}
|
||||
|
||||
for _, p := range preferences {
|
||||
if p.Position < 0 {
|
||||
mainError = errors.New("collectibles: trying to create custom order with negative position")
|
||||
return mainError
|
||||
}
|
||||
_, err := tx.Exec("INSERT INTO collectible_preferences (type, key, position, visible, testnet) VALUES (?, ?, ?, ?, ?)", p.Type, p.Key, p.Position, p.Visible, testNetworksEnabled)
|
||||
if err != nil {
|
||||
mainError = err
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
mainError = ws.setClockOfLastCollectiblePreferencesChange(tx, clock)
|
||||
if mainError != nil {
|
||||
return mainError
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ws *WalletSettings) GetCollectiblePreferences(testNetworksEnabled bool) ([]CollectiblePreferences, error) {
|
||||
rows, err := ws.db.Query("SELECT type, key, position, visible FROM collectible_preferences WHERE testnet = ?", testNetworksEnabled)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var result []CollectiblePreferences
|
||||
|
||||
for rows.Next() {
|
||||
p := CollectiblePreferences{}
|
||||
err := rows.Scan(&p.Type, &p.Key, &p.Position, &p.Visible)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result = append(result, p)
|
||||
}
|
||||
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
Reference in New Issue
Block a user