Add compressed key to multiaccount/messages/contacts

This commit is contained in:
Andrea Maria Piana 2023-01-20 18:51:36 +00:00
parent d024d36718
commit 7e1a894ab8
16 changed files with 276 additions and 34 deletions

View File

@ -1 +1 @@
0.125.2
0.125.4

View File

@ -3,8 +3,10 @@ package generator
import (
"crypto/ecdsa"
"crypto/sha256"
"encoding/json"
"time"
"github.com/status-im/status-go/api/multiformat"
"github.com/status-im/status-go/eth-node/crypto"
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/extkeys"
@ -65,6 +67,24 @@ type AccountInfo struct {
Address string `json:"address"`
}
func (a AccountInfo) MarshalJSON() ([]byte, error) {
type Alias AccountInfo
item := struct {
Alias
CompressedKey string `json:"compressedKey"`
}{
Alias: (Alias)(a),
}
compressedKey, err := multiformat.SerializeLegacyKey(item.PublicKey)
if err != nil {
return nil, err
}
item.CompressedKey = compressedKey
return json.Marshal(item)
}
// IdentifiedAccountInfo contains AccountInfo and the ID of an account.
type IdentifiedAccountInfo struct {
AccountInfo
@ -77,10 +97,30 @@ type IdentifiedAccountInfo struct {
KeyUID string `json:"keyUid"`
}
func (iai *IdentifiedAccountInfo) ToMultiAccount() *multiaccounts.Account {
func (i IdentifiedAccountInfo) MarshalJSON() ([]byte, error) {
accountInfoJSON, err := i.AccountInfo.MarshalJSON()
if err != nil {
return nil, err
}
type info struct {
ID string `json:"id"`
KeyUID string `json:"keyUid"`
}
infoJSON, err := json.Marshal(info{
ID: i.ID,
KeyUID: i.KeyUID,
})
if err != nil {
return nil, err
}
infoJSON[0] = ','
return append(accountInfoJSON[:len(accountInfoJSON)-1], infoJSON...), nil
}
func (i *IdentifiedAccountInfo) ToMultiAccount() *multiaccounts.Account {
return &multiaccounts.Account{
Timestamp: time.Now().Unix(),
KeyUID: iai.KeyUID,
KeyUID: i.KeyUID,
}
}
@ -90,9 +130,27 @@ type GeneratedAccountInfo struct {
Mnemonic string `json:"mnemonic"`
}
func (a GeneratedAccountInfo) toGeneratedAndDerived(derived map[string]AccountInfo) GeneratedAndDerivedAccountInfo {
func (g GeneratedAccountInfo) MarshalJSON() ([]byte, error) {
accountInfoJSON, err := g.IdentifiedAccountInfo.MarshalJSON()
if err != nil {
return nil, err
}
type info struct {
Mnemonic string `json:"mnemonic"`
}
infoJSON, err := json.Marshal(info{
Mnemonic: g.Mnemonic,
})
if err != nil {
return nil, err
}
infoJSON[0] = ','
return append(accountInfoJSON[:len(accountInfoJSON)-1], infoJSON...), nil
}
func (g GeneratedAccountInfo) toGeneratedAndDerived(derived map[string]AccountInfo) GeneratedAndDerivedAccountInfo {
return GeneratedAndDerivedAccountInfo{
GeneratedAccountInfo: a,
GeneratedAccountInfo: g,
Derived: derived,
}
}
@ -102,3 +160,21 @@ type GeneratedAndDerivedAccountInfo struct {
GeneratedAccountInfo
Derived map[string]AccountInfo `json:"derived"`
}
func (g GeneratedAndDerivedAccountInfo) MarshalJSON() ([]byte, error) {
accountInfoJSON, err := g.GeneratedAccountInfo.MarshalJSON()
if err != nil {
return nil, err
}
type info struct {
Derived map[string]AccountInfo `json:"derived"`
}
infoJSON, err := json.Marshal(info{
Derived: g.Derived,
})
if err != nil {
return nil, err
}
infoJSON[0] = ','
return append(accountInfoJSON[:len(accountInfoJSON)-1], infoJSON...), nil
}

View File

@ -2,6 +2,7 @@ package multiformat
import (
"crypto/elliptic"
"errors"
"fmt"
"math/big"
@ -17,6 +18,7 @@ const (
secp256k1KeyType = 0xe7
bls12p381g1KeyType = 0xea
bls12p381g2KeyType = 0xeb
legacyKeyLength = 132
)
// SerializePublicKey serialises a non-serialised multibase encoded multicodec identified EC public key
@ -65,6 +67,17 @@ func DeserializePublicKey(key, outputBase string) (string, error) {
return multibaseEncode(outputBase, pk)
}
// SerializeLegacyKey converts a secp251k1 uncompressed key to
// a base58 compressed key
func SerializeLegacyKey(key string) (string, error) {
if len(key) != legacyKeyLength {
return "", errors.New("invalid key length")
}
keyWithPrefix := fmt.Sprintf("0x%x01%s", secp256k1KeyType, key[2:])
return SerializePublicKey(keyWithPrefix, "z")
}
// getPublicKeyType wrapper for the `varint.FromUvarint()` func
func getPublicKeyType(key []byte) (uint64, int, error) {
return varint.FromUvarint(key)

View File

@ -291,3 +291,20 @@ func TestDeserialisePublicKey(t *testing.T) {
require.NoError(t, err, c.Description)
}
}
func TestSerializeLegacyKey(t *testing.T) {
key := "0x04deaafa03e3a646e54a36ec3f6968c1d3686847d88420f00c0ab6ee517ee1893398fca28aacd2af74f2654738c21d10bad3d88dc64201ebe0de5cf1e313970d3d"
expected := "zQ3shudJrBctPznsRLvbsCtvZFTdi3b34uzYDuqE9Wq9m9T1C"
res, err := SerializeLegacyKey(key)
require.NoError(t, err)
require.Equal(t, expected, res)
wrongKey := key[3:]
_, err = SerializeLegacyKey(wrongKey)
require.Error(t, err)
}

View File

@ -770,6 +770,16 @@ func CompressPublicKey(key string) string {
return types.EncodeHex(crypto.CompressPubkey(pubKey))
}
// SerializeLegacyKey compresses an old format public key (0x04...) to the new one zQ...
func SerializeLegacyKey(key string) string {
cpk, err := multiformat.SerializeLegacyKey(key)
if err != nil {
return makeJSONResponse(err)
}
return cpk
}
// SerializePublicKey compresses an uncompressed multibase encoded multicodec identified EC public key
// For details on usage see specs https://specs.status.im/spec/2#public-key-serialization
func MultiformatSerializePublicKey(key, outBase string) string {

View File

@ -2,6 +2,7 @@ package settings
import (
"encoding/json"
"strings"
"testing"
"github.com/stretchr/testify/require"
@ -44,6 +45,16 @@ func TestSyncSettingField_MarshalJSON(t *testing.T) {
}
}
func TestJSONEncoding(t *testing.T) {
settings := Settings{
PublicKey: "0x04deaafa03e3a646e54a36ec3f6968c1d3686847d88420f00c0ab6ee517ee1893398fca28aacd2af74f2654738c21d10bad3d88dc64201ebe0de5cf1e313970d3d",
}
encoded, err := json.Marshal(settings)
require.NoError(t, err)
require.True(t, strings.Contains(string(encoded), "\"compressed-key\":\"zQ3shudJrBctPznsRLvbsCtvZFTdi3b34uzYDuqE9Wq9m9T1C\""))
}
// TestGetFieldFromProtobufType checks if all the protobuf.SyncSetting_Type_value are assigned to a SettingField
func TestGetFieldFromProtobufType(t *testing.T) {
for _, sst := range protobuf.SyncSetting_Type_value {

View File

@ -3,6 +3,7 @@ package settings
import (
"encoding/json"
"github.com/status-im/status-go/api/multiformat"
"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"
@ -187,3 +188,21 @@ type Settings struct {
GifAPIKey string `json:"gifs/api-key"`
TestNetworksEnabled bool `json:"test-networks-enabled?,omitempty"`
}
func (s Settings) MarshalJSON() ([]byte, error) {
type Alias Settings
item := struct {
Alias
CompressedKey string `json:"compressed-key"`
}{
Alias: (Alias)(s),
}
compressedKey, err := multiformat.SerializeLegacyKey(item.PublicKey)
if err != nil {
return nil, err
}
item.CompressedKey = compressedKey
return json.Marshal(item)
}

View File

@ -127,6 +127,7 @@ func (s *ChatTestSuite) TestSerializeJSON() {
message := &common.Message{}
chat := &Chat{}
message.From = "0x04deaafa03e3a646e54a36ec3f6968c1d3686847d88420f00c0ab6ee517ee1893398fca28aacd2af74f2654738c21d10bad3d88dc64201ebe0de5cf1e313970d3d"
message.Clock = 1
message.Text = "`some markdown text`"
s.Require().NoError(message.PrepareContent(""))

View File

@ -16,6 +16,7 @@ import (
"github.com/status-im/markdown"
"github.com/status-im/markdown/ast"
"github.com/status-im/status-go/api/multiformat"
"github.com/status-im/status-go/eth-node/crypto"
"github.com/status-im/status-go/images"
"github.com/status-im/status-go/protocol/protobuf"
@ -226,6 +227,7 @@ func (m *Message) MarshalJSON() ([]byte, error) {
ID string `json:"id"`
WhisperTimestamp uint64 `json:"whisperTimestamp"`
From string `json:"from"`
CompressedKey string `json:"compressedKey"`
Alias string `json:"alias"`
Identicon string `json:"identicon"`
Seen bool `json:"seen"`
@ -308,6 +310,14 @@ func (m *Message) MarshalJSON() ([]byte, error) {
ContactRequestState: m.ContactRequestState,
ContactVerificationState: m.ContactVerificationState,
}
if item.From != "" {
compressedKey, err := multiformat.SerializeLegacyKey(item.From)
if err != nil {
return nil, err
}
item.CompressedKey = compressedKey
}
if sticker := m.GetSticker(); sticker != nil {
item.Sticker = &StickerAlias{
Pack: sticker.Pack,

View File

@ -1,8 +1,10 @@
package common
import (
"encoding/json"
"io/ioutil"
"os"
"strings"
"testing"
"github.com/stretchr/testify/require"
@ -128,3 +130,15 @@ func TestPrepareSimplifiedText(t *testing.T) {
require.NoError(t, err)
require.Equal(t, "hey "+canonicalName1+" "+canonicalName2, simplifiedText)
}
func TestMarshalMessageJSON(t *testing.T) {
message := &Message{}
from, err := crypto.GenerateKey()
require.NoError(t, err)
message.From = PubkeyToHex(&from.PublicKey)
encodedMessage, err := json.Marshal(message)
require.NoError(t, err)
require.True(t, strings.Contains(string(encodedMessage), "compressedKey\":\"zQ"))
}

View File

@ -2,7 +2,9 @@ package protocol
import (
"crypto/ecdsa"
"encoding/json"
"github.com/status-im/status-go/api/multiformat"
"github.com/status-im/status-go/eth-node/crypto"
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/images"
@ -264,3 +266,21 @@ func contactIDFromPublicKeyString(key string) (string, error) {
return contactIDFromPublicKey(pubKey), nil
}
func (c *Contact) MarshalJSON() ([]byte, error) {
type Alias Contact
item := struct {
*Alias
CompressedKey string `json:"compressedKey"`
}{
Alias: (*Alias)(c),
}
compressedKey, err := multiformat.SerializeLegacyKey(item.ID)
if err != nil {
return nil, err
}
item.CompressedKey = compressedKey
return json.Marshal(item)
}

24
protocol/contact_test.go Normal file
View File

@ -0,0 +1,24 @@
package protocol
import (
"encoding/json"
"strings"
"testing"
"github.com/stretchr/testify/require"
"github.com/status-im/status-go/eth-node/crypto"
"github.com/status-im/status-go/protocol/common"
)
func TestMarshalContactJSON(t *testing.T) {
contact := &Contact{}
id, err := crypto.GenerateKey()
require.NoError(t, err)
contact.ID = common.PubkeyToHex(&id.PublicKey)
encodedContact, err := json.Marshal(contact)
require.NoError(t, err)
require.True(t, strings.Contains(string(encodedContact), "compressedKey\":\"zQ"))
}

View File

@ -933,3 +933,15 @@ func (m *Messenger) PendingContactRequests(cursor string, limit int) ([]*common.
func defaultContactRequestID(contactID string) string {
return "0x" + types.Bytes2Hex(append(types.Hex2Bytes(contactID), 0x20))
}
func (m *Messenger) BuildContact(pubKey string) (*Contact, error) {
contact, ok := m.allContacts.Load(pubKey)
if !ok {
var err error
contact, err = buildContactFromPkString(pubKey)
if err != nil {
return nil, err
}
}
return contact, nil
}

View File

@ -1342,6 +1342,16 @@ func (s *MessengerSuite) TestBlockContact() {
Added: true,
}
key2, err := crypto.GenerateKey()
s.Require().NoError(err)
contact2 := Contact{
ID: common.PubkeyToHex(&key2.PublicKey),
EnsName: "contact-name",
LastUpdated: 20,
Added: true,
}
chat1 := &Chat{
ID: contact.ID,
Name: "chat-name",
@ -1385,7 +1395,7 @@ func (s *MessengerSuite) TestBlockContact() {
s.Require().NoError(s.m.SaveChat(chat2))
s.Require().NoError(s.m.SaveChat(chat3))
_, err := s.m.AddContact(context.Background(), &requests.AddContact{ID: types.Hex2Bytes(contact.ID)})
_, err = s.m.AddContact(context.Background(), &requests.AddContact{ID: types.Hex2Bytes(contact.ID)})
s.Require().NoError(err)
messages := []*common.Message{
@ -1418,7 +1428,7 @@ func (s *MessengerSuite) TestBlockContact() {
Clock: 3,
},
Seen: false,
From: "test",
From: contact2.ID,
},
{
ID: "test-4",
@ -1429,7 +1439,7 @@ func (s *MessengerSuite) TestBlockContact() {
Clock: 4,
},
Seen: false,
From: "test",
From: contact2.ID,
},
{
ID: "test-5",
@ -1440,7 +1450,7 @@ func (s *MessengerSuite) TestBlockContact() {
Clock: 5,
},
Seen: true,
From: "test",
From: contact2.ID,
},
{
ID: "test-6",
@ -1462,7 +1472,7 @@ func (s *MessengerSuite) TestBlockContact() {
Clock: 7,
},
Seen: false,
From: "test",
From: contact2.ID,
},
}
@ -1470,9 +1480,10 @@ func (s *MessengerSuite) TestBlockContact() {
s.Require().NoError(err)
response, err := s.m.BlockContact(contact.ID)
chats := response.Chats()
s.Require().NoError(err)
chats := response.Chats()
var actualChat2, actualChat3 *Chat
for idx := range chats {
if chats[idx].ID == chat2.ID {
@ -2235,7 +2246,7 @@ func (s *MessengerSuite) TestMessageJSON() {
Text: "test-1",
Clock: 1,
},
From: "from-field",
From: testPK,
}
_, err := json.Marshal(message)

View File

@ -180,7 +180,7 @@ func TestMessageByChatID(t *testing.T) {
ChatMessage: protobuf.ChatMessage{
Clock: uint64(i),
},
From: "me",
From: testPK,
})
// Add some other chats.
@ -192,7 +192,7 @@ func TestMessageByChatID(t *testing.T) {
Clock: uint64(i),
},
From: "me",
From: testPK,
})
}
}
@ -208,7 +208,7 @@ func TestMessageByChatID(t *testing.T) {
Clock: uint64(i),
},
From: "me",
From: testPK,
})
}
@ -263,7 +263,7 @@ func TestFirstUnseenMessageIDByChatID(t *testing.T) {
ChatMessage: protobuf.ChatMessage{
Clock: 1,
Text: "some-text"},
From: "me",
From: testPK,
Seen: true,
},
{
@ -272,7 +272,7 @@ func TestFirstUnseenMessageIDByChatID(t *testing.T) {
ChatMessage: protobuf.ChatMessage{
Clock: 2,
Text: "some-text"},
From: "me",
From: testPK,
Seen: false,
},
{
@ -281,7 +281,7 @@ func TestFirstUnseenMessageIDByChatID(t *testing.T) {
ChatMessage: protobuf.ChatMessage{
Clock: 3,
Text: "some-text"},
From: "me",
From: testPK,
Seen: false,
},
})
@ -339,7 +339,7 @@ func TestOldestMessageWhisperTimestampByChatID(t *testing.T) {
Clock: uint64(i),
},
WhisperTimestamp: uint64(i + 10),
From: "me",
From: testPK,
})
}
@ -370,12 +370,12 @@ func TestPinMessageByChatID(t *testing.T) {
ChatMessage: protobuf.ChatMessage{
Clock: uint64(i),
},
From: "me",
From: testPK,
})
// Pin this message
if i%100 == 0 {
from := "me"
from := testPK
if i == 100 {
from = "them"
}
@ -397,7 +397,7 @@ func TestPinMessageByChatID(t *testing.T) {
unpinMessage := &common.PinMessage{
ID: strconv.Itoa(i),
LocalChatID: chatID,
From: "me",
From: testPK,
}
pinMessage.MessageId = strconv.Itoa(i)
unpinMessage.Clock = 333
@ -409,7 +409,7 @@ func TestPinMessageByChatID(t *testing.T) {
pinMessage2 := &common.PinMessage{
ID: strconv.Itoa(i),
LocalChatID: chatID,
From: "me",
From: testPK,
}
pinMessage2.MessageId = strconv.Itoa(i)
pinMessage2.Clock = 222
@ -427,7 +427,7 @@ func TestPinMessageByChatID(t *testing.T) {
Clock: uint64(i),
},
From: "me",
From: testPK,
})
}
}
@ -472,7 +472,7 @@ func TestPinMessageByChatID(t *testing.T) {
require.Equal(t, "them", result[len(result)-1].PinnedBy)
for i := 0; i < len(result)-1; i++ {
require.Equal(t, "me", result[i].PinnedBy)
require.Equal(t, testPK, result[i].PinnedBy)
}
}
@ -578,7 +578,7 @@ func TestMessageByChatIDWithTheSameClocks(t *testing.T) {
ChatMessage: protobuf.ChatMessage{
Clock: clock,
},
From: "me",
From: testPK,
})
}
@ -879,7 +879,7 @@ func insertMinimalMessage(p *sqlitePersistence, id string) error {
ID: id,
LocalChatID: testPublicChatID,
ChatMessage: protobuf.ChatMessage{Text: "some-text"},
From: "me",
From: testPK,
}})
}
@ -889,7 +889,7 @@ func insertMinimalDeletedMessage(p *sqlitePersistence, id string) error {
Deleted: true,
LocalChatID: testPublicChatID,
ChatMessage: protobuf.ChatMessage{Text: "some-text"},
From: "me",
From: testPK,
}})
}
@ -899,7 +899,7 @@ func insertMinimalDeletedForMeMessage(p *sqlitePersistence, id string) error {
DeletedForMe: true,
LocalChatID: testPublicChatID,
ChatMessage: protobuf.ChatMessage{Text: "some-text"},
From: "me",
From: testPK,
}})
}
@ -949,7 +949,7 @@ func insertMinimalDiscordMessage(p *sqlitePersistence, id string, discordMessage
return p.SaveMessages([]*common.Message{{
ID: id,
LocalChatID: testPublicChatID,
From: "me",
From: testPK,
ChatMessage: protobuf.ChatMessage{
Text: "some-text",
ContentType: protobuf.ChatMessage_DISCORD_MESSAGE,
@ -1021,7 +1021,7 @@ func TestSaveMentions(t *testing.T) {
ID: "1",
LocalChatID: chatID,
ChatMessage: protobuf.ChatMessage{Text: "some-text"},
From: "me",
From: testPK,
Mentions: []string{pkString},
}
@ -1156,7 +1156,7 @@ func TestSaveLinks(t *testing.T) {
ID: "1",
LocalChatID: chatID,
ChatMessage: protobuf.ChatMessage{Text: "some-text"},
From: "me",
From: testPK,
Links: []string{"https://github.com/status-im/status-mobile"},
}
@ -1214,7 +1214,7 @@ func TestDeactivatePublicChat(t *testing.T) {
ID: "0x01",
LocalChatID: publicChatID,
ChatMessage: protobuf.ChatMessage{Text: "some-text"},
From: "me",
From: testPK,
}
lastMessage.Clock = 20
@ -1284,7 +1284,7 @@ func TestDeactivateOneToOneChat(t *testing.T) {
ID: "0x01",
LocalChatID: chat.ID,
ChatMessage: protobuf.ChatMessage{Text: "some-text"},
From: "me",
From: testPK,
}
lastMessage.Clock = 20

View File

@ -1251,6 +1251,10 @@ func (api *PublicAPI) RequestCancelDiscordCommunityImport(id string) {
api.service.messenger.MarkDiscordCommunityImportAsCancelled(id)
}
func (api *PublicAPI) BuildContact(publicKey string) (*protocol.Contact, error) {
return api.service.messenger.BuildContact(publicKey)
}
// -----
// HELPER
// -----