diff --git a/Makefile b/Makefile index cd183023d09da89d457b2f7a4ec08d33ab75db15..693d4c626a8ceecb85204819f36ccca46e203d3c 100644 --- a/Makefile +++ b/Makefile @@ -11,20 +11,20 @@ build: GOOS=js GOARCH=wasm go build ./... update_release: - GOFLAGS="" go get gitlab.com/elixxir/wasm-utils@release GOFLAGS="" go get gitlab.com/xx_network/primitives@release GOFLAGS="" go get gitlab.com/elixxir/primitives@release GOFLAGS="" go get gitlab.com/xx_network/crypto@release GOFLAGS="" go get gitlab.com/elixxir/crypto@release - GOFLAGS="" go get -d gitlab.com/elixxir/client/v4@project/HavenBeta + GOFLAGS="" go get -d gitlab.com/elixxir/client/v4@release + GOFLAGS="" go get gitlab.com/elixxir/wasm-utils@release update_master: - GOFLAGS="" go get gitlab.com/elixxir/wasm-utils@master GOFLAGS="" go get gitlab.com/xx_network/primitives@master GOFLAGS="" go get gitlab.com/elixxir/primitives@master GOFLAGS="" go get gitlab.com/xx_network/crypto@master GOFLAGS="" go get gitlab.com/elixxir/crypto@master GOFLAGS="" go get -d gitlab.com/elixxir/client/v4@master + GOFLAGS="" go get gitlab.com/elixxir/wasm-utils@master binary: GOOS=js GOARCH=wasm go build -ldflags '-w -s' -trimpath -o xxdk.wasm main.go diff --git a/go.mod b/go.mod index 9afb4df05b449b791d4a5df76681991a1b32002f..72228bffc17b7aadb4927722e1fdce07594bb1c3 100644 --- a/go.mod +++ b/go.mod @@ -9,8 +9,8 @@ require ( github.com/spf13/cobra v1.7.0 github.com/spf13/jwalterweatherman v1.1.0 github.com/stretchr/testify v1.8.2 - gitlab.com/elixxir/client/v4 v4.6.4-0.20230601191407-1b0289b33708 - gitlab.com/elixxir/crypto v0.0.7-0.20230522162218-45433d877235 + gitlab.com/elixxir/client/v4 v4.6.4-0.20230607172502-b56996e764f5 + gitlab.com/elixxir/crypto v0.0.7-0.20230607170539-92d9508c78f9 gitlab.com/elixxir/primitives v0.0.3-0.20230214180039-9a25e2d3969c gitlab.com/elixxir/wasm-utils v0.0.0-20230522231408-a43b2c1481b2 gitlab.com/xx_network/crypto v0.0.5-0.20230214003943-8a09396e95dd @@ -21,6 +21,7 @@ require ( require ( filippo.io/edwards25519 v1.0.0 // indirect git.xx.network/elixxir/grpc-web-go-client v0.0.0-20230214175953-5b5a8c33d28a // indirect + github.com/Max-Sum/base32768 v0.0.0-20230304063302-18e6ce5945fd // indirect github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect github.com/badoux/checkmail v1.2.1 // indirect github.com/cenkalti/backoff/v4 v4.1.3 // indirect diff --git a/go.sum b/go.sum index 73f80ff896fd23f961e61e7c74b4aed600bf767f..7a76f7af79184ab39ab0dac3c8edf792824442ec 100644 --- a/go.sum +++ b/go.sum @@ -43,6 +43,8 @@ git.xx.network/elixxir/grpc-web-go-client v0.0.0-20230214175953-5b5a8c33d28a/go. github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/Max-Sum/base32768 v0.0.0-20230304063302-18e6ce5945fd h1:nzE1YQBdx1bq9IlZinHa+HVffy+NmVRoKr+wHN8fpLE= +github.com/Max-Sum/base32768 v0.0.0-20230304063302-18e6ce5945fd/go.mod h1:C8yoIfvESpM3GD07OCHU7fqI7lhwyZ2Td1rbNbTAhnc= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= @@ -545,12 +547,14 @@ gitlab.com/elixxir/client/v4 v4.6.4-0.20230531224642-b24cd3f5e4a4 h1:YacWU7IJUfi gitlab.com/elixxir/client/v4 v4.6.4-0.20230531224642-b24cd3f5e4a4/go.mod h1:fegbuF1/6a+H3QgsoMG8teLnyuKtDxkELMw8pn5WlZ8= gitlab.com/elixxir/client/v4 v4.6.4-0.20230601191407-1b0289b33708 h1:wNIKci4XuDfzAJM8+4awP5CgY0jlOEaVbHgp+BkEtz4= gitlab.com/elixxir/client/v4 v4.6.4-0.20230601191407-1b0289b33708/go.mod h1:fegbuF1/6a+H3QgsoMG8teLnyuKtDxkELMw8pn5WlZ8= +gitlab.com/elixxir/client/v4 v4.6.4-0.20230607172502-b56996e764f5 h1:TbuQ5a0HJifvNaUey1AnqpX8v/OPdb2GvNmHPy2hm9g= +gitlab.com/elixxir/client/v4 v4.6.4-0.20230607172502-b56996e764f5/go.mod h1:LmbxL4WIT2qiDN7wzpcJG+U13jn3pSqUHtT1+uxN4VI= gitlab.com/elixxir/comms v0.0.4-0.20230519211512-4a998f4b0938 h1:f27+QUFiGWrprKm+fstOg3ABkYLpWcZi3+8Lf5eDnqY= gitlab.com/elixxir/comms v0.0.4-0.20230519211512-4a998f4b0938/go.mod h1:z+qW0D9VpY5QKTd7wRlb5SK4kBNqLYsa4DXBcUXue9Q= -gitlab.com/elixxir/crypto v0.0.7-0.20230522162218-45433d877235 h1:0BySdXTzRWxzH8k5RiNNMmmn2lpuQWLVcDDA/7ehyqc= -gitlab.com/elixxir/crypto v0.0.7-0.20230522162218-45433d877235/go.mod h1:IYInxKr5Q7EH3oNhg1QX1/sTTRNi7L0JkcyfdRegoio= -gitlab.com/elixxir/ekv v0.3.1-0.20230525165450-f444c687504b h1:hf28yepO93tCacx1bUAh8vVFkBUEuBaJhOjifBxEQK4= -gitlab.com/elixxir/ekv v0.3.1-0.20230525165450-f444c687504b/go.mod h1:EMaUQrsOxvEPQ0/8V/PSkGqFmEC2axBG/uqY0oW2uJM= +gitlab.com/elixxir/crypto v0.0.7-0.20230531164732-6951a4e33a55 h1:J0h3APo7OcIWPnmtIJCyeMOkE9wT6vI8Bw+oZq53S8E= +gitlab.com/elixxir/crypto v0.0.7-0.20230531164732-6951a4e33a55/go.mod h1:lAib0KO9TeTLWbwgFk2uszRxPkHeu843xqnYdkzdEB0= +gitlab.com/elixxir/crypto v0.0.7-0.20230607170539-92d9508c78f9 h1:+RZcoU7NOPXCenkKM/ImYyLcNDdG4vsWrJyKqoAAv8k= +gitlab.com/elixxir/crypto v0.0.7-0.20230607170539-92d9508c78f9/go.mod h1:lAib0KO9TeTLWbwgFk2uszRxPkHeu843xqnYdkzdEB0= gitlab.com/elixxir/ekv v0.3.1-0.20230525213559-f9da13f4fce1 h1:8XBo6QQBXXGCTrgXHFuqPL21mROLKLAoO3X9xR5TwA0= gitlab.com/elixxir/ekv v0.3.1-0.20230525213559-f9da13f4fce1/go.mod h1:UStTZ9d1UVn9Ahyb49lrbPKyr/Wb8xFWqMXbDgIqQhE= gitlab.com/elixxir/primitives v0.0.3-0.20230214180039-9a25e2d3969c h1:muG8ff95woeVVwQoJHCEclxBFB22lc7EixPylEkYDRU= diff --git a/indexedDb/impl/channels/callbacks.go b/indexedDb/impl/channels/callbacks.go index 2a901597117fac367e360ee2f80a2567fcab036f..7fe0a8a13385c5984ccc005853231634a9d4a8d6 100644 --- a/indexedDb/impl/channels/callbacks.go +++ b/indexedDb/impl/channels/callbacks.go @@ -18,8 +18,8 @@ import ( "gitlab.com/elixxir/client/v4/channels" "gitlab.com/elixxir/client/v4/cmix/rounds" cryptoBroadcast "gitlab.com/elixxir/crypto/broadcast" - cryptoChannel "gitlab.com/elixxir/crypto/channel" "gitlab.com/elixxir/crypto/fastRNG" + idbCrypto "gitlab.com/elixxir/crypto/indexedDb" "gitlab.com/elixxir/crypto/message" wChannels "gitlab.com/elixxir/xxdk-wasm/indexedDb/worker/channels" "gitlab.com/elixxir/xxdk-wasm/worker" @@ -64,7 +64,7 @@ func (m *manager) newWASMEventModelCB(data []byte) ([]byte, error) { // Create new encryption cipher rng := fastRNG.NewStreamGenerator(12, 1024, csprng.NewSystemRNG) - encryption, err := cryptoChannel.NewCipherFromJSON( + encryption, err := idbCrypto.NewCipherFromJSON( []byte(msg.EncryptionJSON), rng.GetStream()) if err != nil { return []byte{}, errors.Errorf( diff --git a/indexedDb/impl/channels/implementation.go b/indexedDb/impl/channels/implementation.go index e755acbafb3f750e577305fb9e241c537f30febe..dfc000eba4476870a38b3e6dbd7c8181f55fb5f3 100644 --- a/indexedDb/impl/channels/implementation.go +++ b/indexedDb/impl/channels/implementation.go @@ -25,7 +25,7 @@ import ( "gitlab.com/elixxir/client/v4/channels" "gitlab.com/elixxir/client/v4/cmix/rounds" cryptoBroadcast "gitlab.com/elixxir/crypto/broadcast" - cryptoChannel "gitlab.com/elixxir/crypto/channel" + idbCrypto "gitlab.com/elixxir/crypto/indexedDb" "gitlab.com/elixxir/crypto/message" "gitlab.com/elixxir/wasm-utils/utils" "gitlab.com/elixxir/xxdk-wasm/indexedDb/impl" @@ -37,7 +37,7 @@ import ( // caller to ensure that its methods are called sequentially. type wasmModel struct { db *idb.Database - cipher cryptoChannel.Cipher + cipher idbCrypto.Cipher eventUpdate func(eventType int64, jsonMarshallable any) } @@ -145,12 +145,11 @@ func (w *wasmModel) ReceiveMessage(channelID *id.ID, messageID message.ID, nickname, text string, pubKey ed25519.PublicKey, dmToken uint32, codeset uint8, timestamp time.Time, lease time.Duration, round rounds.Round, mType channels.MessageType, status channels.SentStatus, hidden bool) uint64 { - textBytes := []byte(text) var err error // Handle encryption, if it is present if w.cipher != nil { - textBytes, err = w.cipher.Encrypt([]byte(text)) + text, err = w.cipher.Encrypt([]byte(text)) if err != nil { jww.ERROR.Printf("Failed to encrypt Message: %+v", err) return 0 @@ -161,7 +160,7 @@ func (w *wasmModel) ReceiveMessage(channelID *id.ID, messageID message.ID, msgToInsert := buildMessage( channelIDBytes, messageID.Bytes(), nil, nickname, - textBytes, pubKey, dmToken, codeset, timestamp, lease, round.ID, mType, + text, pubKey, dmToken, codeset, timestamp, lease, round.ID, mType, false, hidden, status) uuid, err := w.upsertMessage(msgToInsert) @@ -189,12 +188,11 @@ func (w *wasmModel) ReceiveReply(channelID *id.ID, messageID, dmToken uint32, codeset uint8, timestamp time.Time, lease time.Duration, round rounds.Round, mType channels.MessageType, status channels.SentStatus, hidden bool) uint64 { - textBytes := []byte(text) var err error // Handle encryption, if it is present if w.cipher != nil { - textBytes, err = w.cipher.Encrypt([]byte(text)) + text, err = w.cipher.Encrypt([]byte(text)) if err != nil { jww.ERROR.Printf("Failed to encrypt Message: %+v", err) return 0 @@ -204,7 +202,7 @@ func (w *wasmModel) ReceiveReply(channelID *id.ID, messageID, channelIDBytes := channelID.Marshal() msgToInsert := buildMessage(channelIDBytes, messageID.Bytes(), - replyTo.Bytes(), nickname, textBytes, pubKey, dmToken, codeset, + replyTo.Bytes(), nickname, text, pubKey, dmToken, codeset, timestamp, lease, round.ID, mType, hidden, false, status) uuid, err := w.upsertMessage(msgToInsert) @@ -232,12 +230,11 @@ func (w *wasmModel) ReceiveReaction(channelID *id.ID, messageID, dmToken uint32, codeset uint8, timestamp time.Time, lease time.Duration, round rounds.Round, mType channels.MessageType, status channels.SentStatus, hidden bool) uint64 { - textBytes := []byte(reaction) var err error // Handle encryption, if it is present if w.cipher != nil { - textBytes, err = w.cipher.Encrypt([]byte(reaction)) + reaction, err = w.cipher.Encrypt([]byte(reaction)) if err != nil { jww.ERROR.Printf("Failed to encrypt Message: %+v", err) return 0 @@ -247,7 +244,7 @@ func (w *wasmModel) ReceiveReaction(channelID *id.ID, messageID, channelIDBytes := channelID.Marshal() msgToInsert := buildMessage( channelIDBytes, messageID.Bytes(), reactionTo.Bytes(), nickname, - textBytes, pubKey, dmToken, codeset, timestamp, lease, round.ID, mType, + reaction, pubKey, dmToken, codeset, timestamp, lease, round.ID, mType, false, hidden, status) uuid, err := w.upsertMessage(msgToInsert) @@ -349,8 +346,8 @@ func (w *wasmModel) UpdateFromMessageID(messageID message.ID, // NOTE: ID is not set inside this function because we want to use the // autoincrement key by default. If you are trying to overwrite an existing // message, then you need to set it manually yourself. -func buildMessage(channelID, messageID, parentID []byte, nickname string, - text []byte, pubKey ed25519.PublicKey, dmToken uint32, codeset uint8, +func buildMessage(channelID, messageID, parentID []byte, nickname, + text string, pubKey ed25519.PublicKey, dmToken uint32, codeset uint8, timestamp time.Time, lease time.Duration, round id.Round, mType channels.MessageType, pinned, hidden bool, status channels.SentStatus) *Message { @@ -499,7 +496,7 @@ func (w *wasmModel) GetMessage( Status: channels.SentStatus(lookupResult.Status), Hidden: lookupResult.Hidden, Pinned: lookupResult.Pinned, - Content: lookupResult.Text, + Content: []byte(lookupResult.Text), Type: channels.MessageType(lookupResult.Type), Round: id.Round(lookupResult.Round), PubKey: lookupResult.Pubkey, diff --git a/indexedDb/impl/channels/implementation_test.go b/indexedDb/impl/channels/implementation_test.go index f596065dcc47aa39e3b5aeda7b97a1f389071977..58cd04a1c6d346a02d0073ef33e9e5e292c8607e 100644 --- a/indexedDb/impl/channels/implementation_test.go +++ b/indexedDb/impl/channels/implementation_test.go @@ -27,8 +27,8 @@ import ( cft "gitlab.com/elixxir/client/v4/channelsFileTransfer" "gitlab.com/elixxir/client/v4/cmix/rounds" cryptoBroadcast "gitlab.com/elixxir/crypto/broadcast" - cryptoChannel "gitlab.com/elixxir/crypto/channel" "gitlab.com/elixxir/crypto/fileTransfer" + idbCrypto "gitlab.com/elixxir/crypto/indexedDb" "gitlab.com/elixxir/crypto/message" "gitlab.com/elixxir/wasm-utils/storage" "gitlab.com/elixxir/xxdk-wasm/indexedDb/impl" @@ -120,12 +120,12 @@ func TestWasmModel_ReceiveFile(t *testing.T) { // Happy path, insert message and look it up func TestWasmModel_GetMessage(t *testing.T) { - cipher, err := cryptoChannel.NewCipher( + cipher, err := idbCrypto.NewCipher( []byte("testPass"), []byte("testSalt"), 128, csprng.NewSystemRNG()) if err != nil { t.Fatalf("Failed to create cipher") } - for _, c := range []cryptoChannel.Cipher{nil, cipher} { + for _, c := range []idbCrypto.Cipher{nil, cipher} { cs := "" if c != nil { cs = "_withCipher" @@ -142,7 +142,7 @@ func TestWasmModel_GetMessage(t *testing.T) { } testMsg := buildMessage(id.NewIdFromBytes([]byte(testString), t).Marshal(), - testMsgId.Bytes(), nil, testString, []byte(testString), + testMsgId.Bytes(), nil, testString, testString, []byte{8, 6, 7, 5}, 0, 0, netTime.Now(), time.Second, 0, 0, false, false, channels.Sent) _, err = eventModel.upsertMessage(testMsg) @@ -173,7 +173,7 @@ func TestWasmModel_DeleteMessage(t *testing.T) { // Insert a message testMsg := buildMessage([]byte(testString), testMsgId.Bytes(), nil, - testString, []byte(testString), []byte{8, 6, 7, 5}, 0, 0, netTime.Now(), + testString, testString, []byte{8, 6, 7, 5}, 0, 0, netTime.Now(), time.Second, 0, 0, false, false, channels.Sent) _, err = eventModel.upsertMessage(testMsg) if err != nil { @@ -207,12 +207,12 @@ func TestWasmModel_DeleteMessage(t *testing.T) { // Test wasmModel.UpdateSentStatus happy path and ensure fields don't change. func Test_wasmModel_UpdateSentStatus(t *testing.T) { - cipher, err := cryptoChannel.NewCipher( + cipher, err := idbCrypto.NewCipher( []byte("testPass"), []byte("testSalt"), 128, csprng.NewSystemRNG()) if err != nil { t.Fatalf("Failed to create cipher") } - for _, c := range []cryptoChannel.Cipher{nil, cipher} { + for _, c := range []idbCrypto.Cipher{nil, cipher} { cs := "" if c != nil { cs = "_withCipher" @@ -234,7 +234,7 @@ func Test_wasmModel_UpdateSentStatus(t *testing.T) { // Store a test message testMsg := buildMessage(cid.Bytes(), testMsgId.Bytes(), nil, - testString, []byte(testString), []byte{8, 6, 7, 5}, 0, 0, + testString, testString, []byte{8, 6, 7, 5}, 0, 0, netTime.Now(), time.Second, 0, 0, false, false, channels.Sent) uuid, err2 := eventModel.upsertMessage(testMsg) if err2 != nil { @@ -282,12 +282,12 @@ func Test_wasmModel_UpdateSentStatus(t *testing.T) { // Smoke test wasmModel.JoinChannel/wasmModel.LeaveChannel happy paths. func Test_wasmModel_JoinChannel_LeaveChannel(t *testing.T) { - cipher, err := cryptoChannel.NewCipher( + cipher, err := idbCrypto.NewCipher( []byte("testPass"), []byte("testSalt"), 128, csprng.NewSystemRNG()) if err != nil { t.Fatalf("Failed to create cipher") } - for _, c := range []cryptoChannel.Cipher{nil, cipher} { + for _, c := range []idbCrypto.Cipher{nil, cipher} { cs := "" if c != nil { cs = "_withCipher" @@ -334,12 +334,12 @@ func Test_wasmModel_JoinChannel_LeaveChannel(t *testing.T) { // Test UUID gets returned when different messages are added. func Test_wasmModel_UUIDTest(t *testing.T) { - cipher, err := cryptoChannel.NewCipher( + cipher, err := idbCrypto.NewCipher( []byte("testPass"), []byte("testSalt"), 128, csprng.NewSystemRNG()) if err != nil { t.Fatalf("Failed to create cipher") } - for _, c := range []cryptoChannel.Cipher{nil, cipher} { + for _, c := range []idbCrypto.Cipher{nil, cipher} { cs := "" if c != nil { cs = "_withCipher" @@ -381,12 +381,12 @@ func Test_wasmModel_UUIDTest(t *testing.T) { // Tests if the same message ID being sent always returns the same UUID. func Test_wasmModel_DuplicateReceives(t *testing.T) { - cipher, err := cryptoChannel.NewCipher( + cipher, err := idbCrypto.NewCipher( []byte("testPass"), []byte("testSalt"), 128, csprng.NewSystemRNG()) if err != nil { t.Fatalf("Failed to create cipher") } - for _, c := range []cryptoChannel.Cipher{nil, cipher} { + for _, c := range []idbCrypto.Cipher{nil, cipher} { cs := "" if c != nil { cs = "_withCipher" @@ -428,12 +428,12 @@ func Test_wasmModel_DuplicateReceives(t *testing.T) { // Happy path: Inserts many messages, deletes some, and checks that the final // result is as expected. func Test_wasmModel_deleteMsgByChannel(t *testing.T) { - cipher, err := cryptoChannel.NewCipher( + cipher, err := idbCrypto.NewCipher( []byte("testPass"), []byte("testSalt"), 128, csprng.NewSystemRNG()) if err != nil { t.Fatalf("Failed to create cipher") } - for _, c := range []cryptoChannel.Cipher{nil, cipher} { + for _, c := range []idbCrypto.Cipher{nil, cipher} { cs := "" if c != nil { cs = "_withCipher" @@ -501,12 +501,12 @@ func Test_wasmModel_deleteMsgByChannel(t *testing.T) { // This test is designed to prove the behavior of unique indexes. // Inserts will not fail, they simply will not happen. func TestWasmModel_receiveHelper_UniqueIndex(t *testing.T) { - cipher, err := cryptoChannel.NewCipher( + cipher, err := idbCrypto.NewCipher( []byte("testPass"), []byte("testSalt"), 128, csprng.NewSystemRNG()) if err != nil { t.Fatalf("Failed to create cipher") } - for i, c := range []cryptoChannel.Cipher{nil, cipher} { + for i, c := range []idbCrypto.Cipher{nil, cipher} { cs := "" if c != nil { cs = "_withCipher" @@ -542,12 +542,12 @@ func TestWasmModel_receiveHelper_UniqueIndex(t *testing.T) { testMsgId := message.DeriveChannelMessageID(&id.ID{1}, 0, []byte(testString)) testMsg := buildMessage([]byte(testString), testMsgId.Bytes(), nil, - testString, []byte(testString), []byte{8, 6, 7, 5}, 0, 0, + testString, testString, []byte{8, 6, 7, 5}, 0, 0, netTime.Now(), time.Second, 0, 0, false, false, channels.Sent) testMsgId2 := message.DeriveChannelMessageID(&id.ID{2}, 0, []byte(testString)) testMsg2 := buildMessage([]byte(testString), testMsgId2.Bytes(), nil, - testString, []byte(testString), []byte{8, 6, 7, 5}, 0, 0, + testString, testString, []byte{8, 6, 7, 5}, 0, 0, netTime.Now(), time.Second, 0, 0, false, false, channels.Sent) // First message insert should succeed diff --git a/indexedDb/impl/channels/init.go b/indexedDb/impl/channels/init.go index 48f5359f9b61c67b42533a42fa37cec4c3c917e7..e604b666636e0953a0a9e19947c53550972d1e76 100644 --- a/indexedDb/impl/channels/init.go +++ b/indexedDb/impl/channels/init.go @@ -18,7 +18,7 @@ import ( "gitlab.com/elixxir/client/v4/bindings" "gitlab.com/elixxir/client/v4/channels" - cryptoChannel "gitlab.com/elixxir/crypto/channel" + idbCrypto "gitlab.com/elixxir/crypto/indexedDb" "gitlab.com/elixxir/xxdk-wasm/indexedDb/impl" ) @@ -29,13 +29,13 @@ const currentVersion uint = 1 // NewWASMEventModel returns a [channels.EventModel] backed by a wasmModel. // The name should be a base64 encoding of the users public key. Returns the // EventModel based on IndexedDb and the database name as reported by IndexedDb. -func NewWASMEventModel(databaseName string, encryption cryptoChannel.Cipher, +func NewWASMEventModel(databaseName string, encryption idbCrypto.Cipher, uiCallbacks bindings.ChannelUICallbacks) (channels.EventModel, error) { return newWASMModel(databaseName, encryption, uiCallbacks) } // newWASMModel creates the given [idb.Database] and returns a wasmModel. -func newWASMModel(databaseName string, encryption cryptoChannel.Cipher, +func newWASMModel(databaseName string, encryption idbCrypto.Cipher, uiCallbacks bindings.ChannelUICallbacks) (*wasmModel, error) { // Attempt to open database object ctx, cancel := impl.NewContext() diff --git a/indexedDb/impl/channels/model.go b/indexedDb/impl/channels/model.go index e5d3e00aa5209985de60a77f5330a53208b1af88..702d489b04d4eb6bfac510a5b9e77f753f411cee 100644 --- a/indexedDb/impl/channels/model.go +++ b/indexedDb/impl/channels/model.go @@ -56,7 +56,7 @@ type Message struct { Status uint8 `json:"status"` Hidden bool `json:"hidden"` Pinned bool `json:"pinned"` // Index - Text []byte `json:"text"` + Text string `json:"text"` Type uint16 `json:"type"` Round uint64 `json:"round"` diff --git a/indexedDb/impl/dm/callbacks.go b/indexedDb/impl/dm/callbacks.go index 380f04d9953fdda65c4b0d80a66e7b40a7edc2b1..061c46a31b5667dd6c04303def1b3b1bab57a66a 100644 --- a/indexedDb/impl/dm/callbacks.go +++ b/indexedDb/impl/dm/callbacks.go @@ -17,8 +17,8 @@ import ( jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/client/v4/dm" - cryptoChannel "gitlab.com/elixxir/crypto/channel" "gitlab.com/elixxir/crypto/fastRNG" + idbCrypto "gitlab.com/elixxir/crypto/indexedDb" wDm "gitlab.com/elixxir/xxdk-wasm/indexedDb/worker/dm" "gitlab.com/elixxir/xxdk-wasm/worker" "gitlab.com/xx_network/crypto/csprng" @@ -61,7 +61,7 @@ func (m *manager) newWASMEventModelCB(data []byte) ([]byte, error) { // Create new encryption cipher rng := fastRNG.NewStreamGenerator(12, 1024, csprng.NewSystemRNG) - encryption, err := cryptoChannel.NewCipherFromJSON( + encryption, err := idbCrypto.NewCipherFromJSON( []byte(msg.EncryptionJSON), rng.GetStream()) if err != nil { return []byte{}, errors.Errorf("failed to JSON unmarshal channel "+ diff --git a/indexedDb/impl/dm/implementation.go b/indexedDb/impl/dm/implementation.go index a92691878ebc4b6c21cd1d38297aca23e4109920..f40791ece46d05b397dadd6766ec455045168452 100644 --- a/indexedDb/impl/dm/implementation.go +++ b/indexedDb/impl/dm/implementation.go @@ -24,7 +24,7 @@ import ( "gitlab.com/elixxir/client/v4/cmix/rounds" "gitlab.com/elixxir/client/v4/dm" - cryptoChannel "gitlab.com/elixxir/crypto/channel" + idbCrypto "gitlab.com/elixxir/crypto/indexedDb" "gitlab.com/elixxir/crypto/message" "gitlab.com/elixxir/wasm-utils/utils" "gitlab.com/elixxir/xxdk-wasm/indexedDb/impl" @@ -36,7 +36,7 @@ import ( // caller to ensure that its methods are called sequentially. type wasmModel struct { db *idb.Database - cipher cryptoChannel.Cipher + cipher idbCrypto.Cipher receivedMessageCB MessageReceivedCallback } @@ -81,7 +81,7 @@ func (w *wasmModel) upsertConversation(nickname string, // NOTE: ID is not set inside this function because we want to use the // autoincrement key by default. If you are trying to overwrite an existing // message, then you need to set it manually yourself. -func buildMessage(messageID, parentID, text []byte, partnerKey, +func buildMessage(messageID, parentID []byte, text string, partnerKey []byte, senderKey ed25519.PublicKey, timestamp time.Time, round id.Round, mType dm.MessageType, codeset uint8, status dm.Status) *Message { return &Message{ @@ -276,9 +276,8 @@ func (w *wasmModel) receiveWrapper(messageID message.ID, parentID *message.ID, n } // Handle encryption, if it is present - textBytes := []byte(data) if w.cipher != nil { - textBytes, err = w.cipher.Encrypt(textBytes) + data, err = w.cipher.Encrypt([]byte(data)) if err != nil { return 0, err } @@ -289,7 +288,7 @@ func (w *wasmModel) receiveWrapper(messageID message.ID, parentID *message.ID, n parentIdBytes = parentID.Marshal() } - msgToInsert := buildMessage(messageID.Bytes(), parentIdBytes, textBytes, + msgToInsert := buildMessage(messageID.Bytes(), parentIdBytes, data, partnerKey, senderKey, timestamp, round.ID, mType, codeset, status) uuid, err := w.upsertMessage(msgToInsert) diff --git a/indexedDb/impl/dm/init.go b/indexedDb/impl/dm/init.go index 8332866b95055e7d322308cdf8669d1be78a95ac..aabad5c593eaca751ada0e364893aa6382135f35 100644 --- a/indexedDb/impl/dm/init.go +++ b/indexedDb/impl/dm/init.go @@ -17,7 +17,7 @@ import ( jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/client/v4/dm" - cryptoChannel "gitlab.com/elixxir/crypto/channel" + idbCrypto "gitlab.com/elixxir/crypto/indexedDb" "gitlab.com/elixxir/xxdk-wasm/indexedDb/impl" ) @@ -35,13 +35,13 @@ type MessageReceivedCallback func( // NewWASMEventModel returns a [channels.EventModel] backed by a wasmModel. // The name should be a base64 encoding of the users public key. Returns the // EventModel based on IndexedDb and the database name as reported by IndexedDb. -func NewWASMEventModel(databaseName string, encryption cryptoChannel.Cipher, +func NewWASMEventModel(databaseName string, encryption idbCrypto.Cipher, cb MessageReceivedCallback) (dm.EventModel, error) { return newWASMModel(databaseName, encryption, cb) } // newWASMModel creates the given [idb.Database] and returns a wasmModel. -func newWASMModel(databaseName string, encryption cryptoChannel.Cipher, +func newWASMModel(databaseName string, encryption idbCrypto.Cipher, cb MessageReceivedCallback) (*wasmModel, error) { // Attempt to open database object ctx, cancel := impl.NewContext() diff --git a/indexedDb/impl/dm/model.go b/indexedDb/impl/dm/model.go index 774d011fe4987078808febd74a1657839e06dc8a..6893fc3a6a7fffd95eb31e389e8352040e797b9f 100644 --- a/indexedDb/impl/dm/model.go +++ b/indexedDb/impl/dm/model.go @@ -46,7 +46,7 @@ type Message struct { SenderPubKey []byte `json:"sender_pub_key"` // Index CodesetVersion uint8 `json:"codeset_version"` Status uint8 `json:"status"` - Text []byte `json:"text"` + Text string `json:"text"` Type uint16 `json:"type"` Round uint64 `json:"round"` } diff --git a/indexedDb/worker/channels/init.go b/indexedDb/worker/channels/init.go index d24120aa445d6c161bf148a242439f4a6bf05eb1..d14a80ebfc5d91dd3e100e58d7ec2cb45f7d281e 100644 --- a/indexedDb/worker/channels/init.go +++ b/indexedDb/worker/channels/init.go @@ -18,8 +18,7 @@ import ( jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/client/v4/bindings" "gitlab.com/elixxir/client/v4/channels" - - cryptoChannel "gitlab.com/elixxir/crypto/channel" + idbCrypto "gitlab.com/elixxir/crypto/indexedDb" "gitlab.com/elixxir/xxdk-wasm/storage" "gitlab.com/elixxir/xxdk-wasm/worker" ) @@ -36,7 +35,7 @@ type eventUpdateCallback func(eventType int64, jsonData []byte) // the channel manager to define the path but the callback is the same // across the board. func NewWASMEventModelBuilder(wasmJsPath string, - encryption cryptoChannel.Cipher, + encryption idbCrypto.Cipher, channelCbs bindings.ChannelUICallbacks) channels.EventModelBuilder { fn := func(path string) (channels.EventModel, error) { return NewWASMEventModel(path, wasmJsPath, encryption, @@ -54,7 +53,7 @@ type NewWASMEventModelMessage struct { // NewWASMEventModel returns a [channels.EventModel] backed by a wasmModel. // The name should be a base64 encoding of the users public key. -func NewWASMEventModel(path, wasmJsPath string, encryption cryptoChannel.Cipher, +func NewWASMEventModel(path, wasmJsPath string, encryption idbCrypto.Cipher, channelCbs bindings.ChannelUICallbacks) ( channels.EventModel, error) { databaseName := path + databaseSuffix diff --git a/indexedDb/worker/dm/init.go b/indexedDb/worker/dm/init.go index 3fd1cd13897bdc8684e2efc13750e1fed20ff000..b7afc2b2237c2258feb91084e644402e775c45f1 100644 --- a/indexedDb/worker/dm/init.go +++ b/indexedDb/worker/dm/init.go @@ -18,7 +18,7 @@ import ( jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/client/v4/dm" - cryptoChannel "gitlab.com/elixxir/crypto/channel" + idbCrypto "gitlab.com/elixxir/crypto/indexedDb" "gitlab.com/elixxir/xxdk-wasm/storage" "gitlab.com/elixxir/xxdk-wasm/worker" ) @@ -42,7 +42,7 @@ type NewWASMEventModelMessage struct { // NewWASMEventModel returns a [channels.EventModel] backed by a wasmModel. // The name should be a base64 encoding of the users public key. -func NewWASMEventModel(path, wasmJsPath string, encryption cryptoChannel.Cipher, +func NewWASMEventModel(path, wasmJsPath string, encryption idbCrypto.Cipher, cb MessageReceivedCallback) (dm.EventModel, error) { databaseName := path + databaseSuffix diff --git a/main.go b/main.go index 5315e3738a2c8825791ac725026aa5c828a5ea44..b2a964719718eb79e9a006ec3e8b225c0e075b17 100644 --- a/main.go +++ b/main.go @@ -136,8 +136,12 @@ func setGlobals() { js.FuncOf(wasm.GetChannelNotificationReportsForMe)) js.Global().Set("GetNoMessageErr", js.FuncOf(wasm.GetNoMessageErr)) js.Global().Set("CheckNoMessageErr", js.FuncOf(wasm.CheckNoMessageErr)) - js.Global().Set("NewChannelsDatabaseCipher", - js.FuncOf(wasm.NewChannelsDatabaseCipher)) + js.Global().Set("GetNotificationReportsForMe", + js.FuncOf(wasm.GetChannelNotificationReportsForMe)) + + // wasm/cipher.go + js.Global().Set("NewDatabaseCipher", + js.FuncOf(wasm.NewDatabaseCipher)) // wasm/dm.go js.Global().Set("InitChannelsFileTransfer", @@ -150,7 +154,7 @@ func setGlobals() { js.Global().Set("NewDMClientWithIndexedDbUnsafe", js.FuncOf(wasm.NewDMClientWithIndexedDbUnsafe)) js.Global().Set("NewDMsDatabaseCipher", - js.FuncOf(wasm.NewDMsDatabaseCipher)) + js.FuncOf(wasm.NewDatabaseCipher)) // wasm/cmix.go js.Global().Set("NewCmix", js.FuncOf(wasm.NewCmix)) diff --git a/storage/password.go b/storage/password.go index 7be49b310b54b7aa2764678f35d0b91550d2c491..5dec9055907b819c3290be05cd07454ddd312036 100644 --- a/storage/password.go +++ b/storage/password.go @@ -23,6 +23,7 @@ import ( "github.com/pkg/errors" jww "github.com/spf13/jwalterweatherman" + "gitlab.com/elixxir/crypto/hash" "gitlab.com/elixxir/wasm-utils/exception" "gitlab.com/elixxir/wasm-utils/storage" "gitlab.com/elixxir/wasm-utils/utils" @@ -40,6 +41,8 @@ const ( // saltLen is the length of the salt. Recommended to be 16 bytes here: // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-argon2-04#section-3.1 saltLen = 16 + + internalPasswordConstant = "XXInternalPassword" ) // Storage keys. @@ -58,7 +61,7 @@ const ( // Error messages. const ( // initInternalPassword - readInternalPasswordErr = "could not generate internal password: %+v" + readInternalPasswordErr = "could not generate" internalPasswordNumBytesErr = "expected %d bytes for internal password, found %d bytes" // getInternalPassword @@ -153,6 +156,9 @@ func getOrInit(externalPassword string) ([]byte, error) { // changeExternalPassword is the private function for ChangeExternalPassword // that is used for testing. func changeExternalPassword(oldExternalPassword, newExternalPassword string) error { + // NOTE: the following no longer works in synchronized environments, so + // disabled in produciton. + jww.FATAL.Panicf("cannot change password, unimplemented") localStorage := storage.GetLocalStorage() internalPassword, err := getInternalPassword( oldExternalPassword, localStorage) @@ -193,14 +199,22 @@ func initInternalPassword(externalPassword string, params argonParams) ([]byte, error) { internalPassword := make([]byte, internalPasswordLen) + // FIXME: The internal password is now just an expansion of + // the users password text. We couldn't preserve the following + // when doing cross-device sync. + h := hash.CMixHash.New() + h.Write([]byte(externalPassword)) + h.Write(internalPassword) + copy(internalPassword, h.Sum(nil)[:internalPasswordLen]) + // Generate internal password - n, err := csprng.Read(internalPassword) - if err != nil { - return nil, errors.Errorf(readInternalPasswordErr, err) - } else if n != internalPasswordLen { - return nil, errors.Errorf( - internalPasswordNumBytesErr, internalPasswordLen, n) - } + // n, err := csprng.Read(internalPassword) + // if err != nil { + // return nil, errors.Errorf(readInternalPasswordErr, err) + // } else if n != internalPasswordLen { + // return nil, errors.Errorf( + // internalPasswordNumBytesErr, internalPasswordLen, n) + // } // Generate and store salt salt, err := makeSalt(csprng) diff --git a/storage/password_test.go b/storage/password_test.go index 0e4c4c64105e93247cf24d1665360fdbd834a687..fecd785c51c7e919ab511e2d8d5821dd6f4b37f5 100644 --- a/storage/password_test.go +++ b/storage/password_test.go @@ -44,37 +44,37 @@ func Test_getOrInit(t *testing.T) { // Tests that changeExternalPassword correctly changes the password and updates // the encryption. -func Test_changeExternalPassword(t *testing.T) { - oldExternalPassword := "myPassword" - newExternalPassword := "hunter2" - oldInternalPassword, err := getOrInit(oldExternalPassword) - if err != nil { - t.Errorf("%+v", err) - } - - err = changeExternalPassword(oldExternalPassword, newExternalPassword) - if err != nil { - t.Errorf("%+v", err) - } - - newInternalPassword, err := getOrInit(newExternalPassword) - if err != nil { - t.Errorf("%+v", err) - } - - if !bytes.Equal(oldInternalPassword, newInternalPassword) { - t.Errorf("Internal password was not changed in storage. Old and new "+ - "should be different.\nold: %+v\nnew: %+v", - oldInternalPassword, newInternalPassword) - } - - _, err = getOrInit(oldExternalPassword) - expectedErr := strings.Split(decryptWithPasswordErr, "%")[0] - if err == nil || !strings.Contains(err.Error(), expectedErr) { - t.Errorf("Unexpected error when trying to get internal password with "+ - "old external password.\nexpected: %s\nreceived: %+v", expectedErr, err) - } -} +// func Test_changeExternalPassword(t *testing.T) { +// oldExternalPassword := "myPassword" +// newExternalPassword := "hunter2" +// oldInternalPassword, err := getOrInit(oldExternalPassword) +// if err != nil { +// t.Errorf("%+v", err) +// } + +// err = changeExternalPassword(oldExternalPassword, newExternalPassword) +// if err != nil { +// t.Errorf("%+v", err) +// } + +// newInternalPassword, err := getOrInit(newExternalPassword) +// if err != nil { +// t.Errorf("%+v", err) +// } + +// if !bytes.Equal(oldInternalPassword, newInternalPassword) { +// t.Errorf("Internal password was not changed in storage. Old and new "+ +// "should be different.\nold: %+v\nnew: %+v", +// oldInternalPassword, newInternalPassword) +// } + +// _, err = getOrInit(oldExternalPassword) +// expectedErr := strings.Split(decryptWithPasswordErr, "%")[0] +// if err == nil || !strings.Contains(err.Error(), expectedErr) { +// t.Errorf("Unexpected error when trying to get internal password with "+ +// "old external password.\nexpected: %s\nreceived: %+v", expectedErr, err) +// } +// } // Tests that verifyPassword returns true for a valid password and false for an // invalid password @@ -154,20 +154,20 @@ func Test_initInternalPassword_CsprngReadError(t *testing.T) { // Tests that initInternalPassword returns an error when the RNG does not // return enough bytes. -func Test_initInternalPassword_CsprngReadNumBytesError(t *testing.T) { - externalPassword := "myPassword" - ls := storage.GetLocalStorage() - b := bytes.NewBuffer(make([]byte, internalPasswordLen/2)) - - expectedErr := fmt.Sprintf( - internalPasswordNumBytesErr, internalPasswordLen, internalPasswordLen/2) - - _, err := initInternalPassword(externalPassword, ls, b, defaultParams()) - if err == nil || !strings.Contains(err.Error(), expectedErr) { - t.Errorf("Unexpected error when RNG does not return enough bytes."+ - "\nexpected: %s\nreceived: %+v", expectedErr, err) - } -} +// func Test_initInternalPassword_CsprngReadNumBytesError(t *testing.T) { +// externalPassword := "myPassword" +// ls := storage.GetLocalStorage() +// b := bytes.NewBuffer(make([]byte, internalPasswordLen/2)) + +// expectedErr := fmt.Sprintf( +// internalPasswordNumBytesErr, internalPasswordLen, internalPasswordLen/2) + +// _, err := initInternalPassword(externalPassword, ls, b, defaultParams()) +// if err == nil || !strings.Contains(err.Error(), expectedErr) { +// t.Errorf("Unexpected error when RNG does not return enough bytes."+ +// "\nexpected: %s\nreceived: %+v", expectedErr, err) +// } +// } // Tests that getInternalPassword returns the internal password that is saved // to local storage by initInternalPassword. diff --git a/wasm/channels.go b/wasm/channels.go index 13562a200cef571cad1f3d881ee172e6c5f6d399..b3535c9c8be609ab9cf992c8de440797d3ee4723 100644 --- a/wasm/channels.go +++ b/wasm/channels.go @@ -369,9 +369,9 @@ func LoadChannelsManager(_ js.Value, args []js.Value) any { // [bindings.ChannelUICallbacks]. It is a callback that informs the UI about // various events. The entire interface can be nil, but if defined, each // method must be implemented. -// - args[6] - ID of [ChannelDbCipher] object in tracker (int). Create this -// object with [NewChannelsDatabaseCipher] and get its id with -// [ChannelDbCipher.GetID]. +// - args[6] - ID of [DbCipher] object in tracker (int). Create this +// object with [NewDatabaseCipher] and get its id with +// [DbCipher.GetID]. // // Returns a promise: // - Resolves to a Javascript representation of the [ChannelsManager] object. @@ -386,7 +386,7 @@ func NewChannelsManagerWithIndexedDb(_ js.Value, args []js.Value) any { cUI := newChannelUI(args[5]) cipherID := args[6].Int() - cipher, err := bindings.GetChannelDbCipherTrackerFromID(cipherID) + cipher, err := dbCipherTrackerSingleton.get(cipherID) if err != nil { exception.ThrowTrace(err) } @@ -444,10 +444,10 @@ func NewChannelsManagerWithIndexedDbUnsafe(_ js.Value, args []js.Value) any { func newChannelsManagerWithIndexedDb(cmixID int, wasmJsPath string, privateIdentity, extensionBuilderIDsJSON []byte, notificationsID int, channelsCbs bindings.ChannelUICallbacks, - cipher *bindings.ChannelDbCipher) any { + cipher *DbCipher) any { model := channelsDb.NewWASMEventModelBuilder( - wasmJsPath, cipher, channelsCbs) + wasmJsPath, cipher.api, channelsCbs) promiseFn := func(resolve, reject func(args ...any) js.Value) { cm, err := bindings.NewChannelsManagerGoEventModel(cmixID, @@ -487,9 +487,9 @@ func newChannelsManagerWithIndexedDb(cmixID int, wasmJsPath string, // [bindings.ChannelUICallbacks]. It is a callback that informs the UI about // various events. The entire interface can be nil, but if defined, each // method must be implemented. -// - args[6] - ID of [ChannelDbCipher] object in tracker (int). Create this -// object with [NewChannelsDatabaseCipher] and get its id with -// [ChannelDbCipher.GetID]. +// - args[6] - ID of [DbCipher] object in tracker (int). Create this +// object with [NewDatabaseCipher] and get its id with +// [DbCipher.GetID]. // // Returns a promise: // - Resolves to a Javascript representation of the [ChannelsManager] object. @@ -504,7 +504,7 @@ func LoadChannelsManagerWithIndexedDb(_ js.Value, args []js.Value) any { channelsCbs := newChannelUI(args[5]) cipherID := args[6].Int() - cipher, err := bindings.GetChannelDbCipherTrackerFromID(cipherID) + cipher, err := dbCipherTrackerSingleton.get(cipherID) if err != nil { exception.ThrowTrace(err) } @@ -557,10 +557,10 @@ func LoadChannelsManagerWithIndexedDbUnsafe(_ js.Value, args []js.Value) any { func loadChannelsManagerWithIndexedDb(cmixID int, wasmJsPath, storageTag string, extensionBuilderIDsJSON []byte, notificationsID int, channelsCbs bindings.ChannelUICallbacks, - cipher *bindings.ChannelDbCipher) any { + cipher *DbCipher) any { model := channelsDb.NewWASMEventModelBuilder( - wasmJsPath, cipher, channelsCbs) + wasmJsPath, cipher.api, channelsCbs) promiseFn := func(resolve, reject func(args ...any) js.Value) { cm, err := bindings.LoadChannelsManagerGoEventModel( @@ -2315,145 +2315,6 @@ type MessageAndError struct { Error string } -//////////////////////////////////////////////////////////////////////////////// -// Channel Cipher // -//////////////////////////////////////////////////////////////////////////////// - -// ChannelDbCipher wraps the [bindings.ChannelDbCipher] object so its methods -// can be wrapped to be Javascript compatible. -type ChannelDbCipher struct { - api *bindings.ChannelDbCipher -} - -// newChannelDbCipherJS creates a new Javascript compatible object -// (map[string]any) that matches the [ChannelDbCipher] structure. -func newChannelDbCipherJS(api *bindings.ChannelDbCipher) map[string]any { - c := ChannelDbCipher{api} - channelDbCipherMap := map[string]any{ - "GetID": js.FuncOf(c.GetID), - "Encrypt": js.FuncOf(c.Encrypt), - "Decrypt": js.FuncOf(c.Decrypt), - "MarshalJSON": js.FuncOf(c.MarshalJSON), - "UnmarshalJSON": js.FuncOf(c.UnmarshalJSON), - } - - return channelDbCipherMap -} - -// NewChannelsDatabaseCipher constructs a [ChannelDbCipher] object. -// -// Parameters: -// - args[0] - The tracked [Cmix] object ID (int). -// - args[1] - The password for storage. This should be the same password -// passed into [NewCmix] (Uint8Array). -// - args[2] - The maximum size of a payload to be encrypted. A payload passed -// into [ChannelDbCipher.Encrypt] that is larger than this value will result -// in an error (int). -// -// Returns: -// - JavaScript representation of the [ChannelDbCipher] object. -// - Throws an error if creating the cipher fails. -func NewChannelsDatabaseCipher(_ js.Value, args []js.Value) any { - cmixId := args[0].Int() - password := utils.CopyBytesToGo(args[1]) - plaintTextBlockSize := args[2].Int() - - cipher, err := bindings.NewChannelsDatabaseCipher( - cmixId, password, plaintTextBlockSize) - if err != nil { - exception.ThrowTrace(err) - return nil - } - - return newChannelDbCipherJS(cipher) -} - -// GetID returns the ID for this [bindings.ChannelDbCipher] in the -// channelDbCipherTracker. -// -// Returns: -// - Tracker ID (int). -func (c *ChannelDbCipher) GetID(js.Value, []js.Value) any { - return c.api.GetID() -} - -// Encrypt will encrypt the raw data. It will return a ciphertext. Padding is -// done on the plaintext so all encrypted data looks uniform at rest. -// -// Parameters: -// - args[0] - The data to be encrypted (Uint8Array). This must be smaller -// than the block size passed into [NewChannelsDatabaseCipher]. If it is -// larger, this will return an error. -// -// Returns: -// - The ciphertext of the plaintext passed in (Uint8Array). -// - Throws an error if it fails to encrypt the plaintext. -func (c *ChannelDbCipher) Encrypt(_ js.Value, args []js.Value) any { - ciphertext, err := c.api.Encrypt(utils.CopyBytesToGo(args[0])) - if err != nil { - exception.ThrowTrace(err) - return nil - } - - return utils.CopyBytesToJS(ciphertext) -} - -// Decrypt will decrypt the passed in encrypted value. The plaintext will be -// returned by this function. Any padding will be discarded within this -// function. -// -// Parameters: -// - args[0] - the encrypted data returned by [ChannelDbCipher.Encrypt] -// (Uint8Array). -// -// Returns: -// - The plaintext of the ciphertext passed in (Uint8Array). -// - Throws an error if it fails to encrypt the plaintext. -func (c *ChannelDbCipher) Decrypt(_ js.Value, args []js.Value) any { - plaintext, err := c.api.Decrypt(utils.CopyBytesToGo(args[0])) - if err != nil { - exception.ThrowTrace(err) - return nil - } - - return utils.CopyBytesToJS(plaintext) -} - -// MarshalJSON marshals the cipher into valid JSON. -// -// Returns: -// - JSON of the cipher (Uint8Array). -// - Throws an error if marshalling fails. -func (c *ChannelDbCipher) MarshalJSON(js.Value, []js.Value) any { - data, err := c.api.MarshalJSON() - if err != nil { - exception.ThrowTrace(err) - return nil - } - - return utils.CopyBytesToJS(data) -} - -// UnmarshalJSON unmarshalls JSON into the cipher. -// -// Note that this function does not transfer the internal RNG. Use -// [channel.NewCipherFromJSON] to properly reconstruct a cipher from JSON. -// -// Parameters: -// - args[0] - JSON data to unmarshal (Uint8Array). -// -// Returns: -// - JSON of the cipher (Uint8Array). -// - Throws an error if marshalling fails. -func (c *ChannelDbCipher) UnmarshalJSON(_ js.Value, args []js.Value) any { - err := c.api.UnmarshalJSON(utils.CopyBytesToGo(args[0])) - if err != nil { - exception.ThrowTrace(err) - return nil - } - return nil -} - // newChannelUI maps the methods on the Javascript object to the // channelUI callbacks implementation struct. func newChannelUI(cbImpl js.Value) *channelUI { diff --git a/wasm/channels_test.go b/wasm/channels_test.go index 1b4d9eb555177951ea66e9fb81ed7420418f2b22..9ebbc691debd6d330a9cadc3a4aa4c9c62d342ad 100644 --- a/wasm/channels_test.go +++ b/wasm/channels_test.go @@ -60,47 +60,6 @@ func Test_ChannelsManagerMethods(t *testing.T) { } } -// Tests that the map representing ChannelDbCipher returned by -// newChannelDbCipherJS contains all of the methods on ChannelDbCipher. -func Test_newChannelDbCipherJS(t *testing.T) { - cipherType := reflect.TypeOf(&ChannelDbCipher{}) - - cipher := newChannelDbCipherJS(&bindings.ChannelDbCipher{}) - if len(cipher) != cipherType.NumMethod() { - t.Errorf("ChannelDbCipher JS object does not have all methods."+ - "\nexpected: %d\nreceived: %d", cipherType.NumMethod(), len(cipher)) - } - - for i := 0; i < cipherType.NumMethod(); i++ { - method := cipherType.Method(i) - - if _, exists := cipher[method.Name]; !exists { - t.Errorf("Method %s does not exist.", method.Name) - } - } -} - -// Tests that ChannelDbCipher has all the methods that -// [bindings.ChannelDbCipher] has. -func Test_ChannelDbCipherMethods(t *testing.T) { - cipherType := reflect.TypeOf(&ChannelDbCipher{}) - binCipherType := reflect.TypeOf(&bindings.ChannelDbCipher{}) - - if binCipherType.NumMethod() != cipherType.NumMethod() { - t.Errorf("WASM ChannelDbCipher object does not have all methods from "+ - "bindings.\nexpected: %d\nreceived: %d", - binCipherType.NumMethod(), cipherType.NumMethod()) - } - - for i := 0; i < binCipherType.NumMethod(); i++ { - method := binCipherType.Method(i) - - if _, exists := cipherType.MethodByName(method.Name); !exists { - t.Errorf("Method %s does not exist.", method.Name) - } - } -} - type jsIdentity struct { pubKey js.Value codeset js.Value diff --git a/wasm/cipher.go b/wasm/cipher.go new file mode 100644 index 0000000000000000000000000000000000000000..5504d2f3a426c78640ff1611e025103e91fb876e --- /dev/null +++ b/wasm/cipher.go @@ -0,0 +1,232 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright © 2022 xx foundation // +// // +// Use of this source code is governed by a license that can be found in the // +// LICENSE file. // +//////////////////////////////////////////////////////////////////////////////// + +//go:build js && wasm + +package wasm + +import ( + "github.com/pkg/errors" + "gitlab.com/elixxir/client/v4/bindings" + "gitlab.com/elixxir/client/v4/storage/utility" + "gitlab.com/elixxir/crypto/indexedDb" + "gitlab.com/elixxir/wasm-utils/exception" + "gitlab.com/elixxir/wasm-utils/utils" + "sync" + "syscall/js" +) + +// dbCipherTrackerSingleton is used to track DbCipher objects +// so that they can be referenced by ID back over the bindings. +var dbCipherTrackerSingleton = &DbCipherTracker{ + tracked: make(map[int]*DbCipher), + count: 0, +} + +// DbCipherTracker is a singleton used to keep track of extant +// DbCipher objects, preventing race conditions created by passing it +// over the bindings. +type DbCipherTracker struct { + tracked map[int]*DbCipher + count int + mux sync.RWMutex +} + +// create creates a DbCipher from a [indexedDb.Cipher], assigns it a unique +// ID, and adds it to the DbCipherTracker. +func (ct *DbCipherTracker) create(c indexedDb.Cipher) *DbCipher { + ct.mux.Lock() + defer ct.mux.Unlock() + + chID := ct.count + ct.count++ + + ct.tracked[chID] = &DbCipher{ + api: c, + id: chID, + } + + return ct.tracked[chID] +} + +// get an DbCipher from the DbCipherTracker given its ID. +func (ct *DbCipherTracker) get(id int) (*DbCipher, error) { + ct.mux.RLock() + defer ct.mux.RUnlock() + + c, exist := ct.tracked[id] + if !exist { + return nil, errors.Errorf( + "Cannot get DbCipher for ID %d, does not exist", id) + } + + return c, nil +} + +// delete removes a DbCipherTracker from the DbCipherTracker. +func (ct *DbCipherTracker) delete(id int) { + ct.mux.Lock() + defer ct.mux.Unlock() + + delete(ct.tracked, id) +} + +// DbCipher wraps the [indexedDb.Cipher] object so its methods +// can be wrapped to be Javascript compatible. +type DbCipher struct { + api indexedDb.Cipher + salt []byte + id int +} + +// newDbCipherJS creates a new Javascript compatible object +// (map[string]any) that matches the [DbCipher] structure. +func newDbCipherJS(c *DbCipher) map[string]any { + DbCipherMap := map[string]any{ + "GetID": js.FuncOf(c.GetID), + "Encrypt": js.FuncOf(c.Encrypt), + "Decrypt": js.FuncOf(c.Decrypt), + "MarshalJSON": js.FuncOf(c.MarshalJSON), + "UnmarshalJSON": js.FuncOf(c.UnmarshalJSON), + } + + return DbCipherMap +} + +// NewDatabaseCipher constructs a [DbCipher] object. +// +// Parameters: +// - args[0] - The tracked [Cmix] object ID (int). +// - args[1] - The password for storage. This should be the same password +// passed into [NewCmix] (Uint8Array). +// - args[2] - The maximum size of a payload to be encrypted. A payload passed +// into [DbCipher.Encrypt] that is larger than this value will result +// in an error (int). +// +// Returns: +// - JavaScript representation of the [DbCipher] object. +// - Throws an error if creating the cipher fails. +func NewDatabaseCipher(_ js.Value, args []js.Value) any { + cmixId := args[0].Int() + password := utils.CopyBytesToGo(args[1]) + plaintTextBlockSize := args[2].Int() + + // Get user from singleton + user, err := bindings.GetCMixInstance(cmixId) + if err != nil { + exception.ThrowTrace(err) + return nil + } + + // Generate RNG + stream := user.GetRng().GetStream() + + // Load or generate a salt + salt, err := utility.NewOrLoadSalt( + user.GetStorage().GetKV(), stream) + if err != nil { + exception.ThrowTrace(err) + return nil + } + + // Construct a cipher + c, err := indexedDb.NewCipher( + password, salt, plaintTextBlockSize, stream) + if err != nil { + exception.ThrowTrace(err) + return nil + } + + // Add to singleton and return + return newDbCipherJS(dbCipherTrackerSingleton.create(c)) +} + +// GetID returns the ID for this [DbCipher] in the +// DbCipherTracker. +// +// Returns: +// - Tracker ID (int). +func (c *DbCipher) GetID(js.Value, []js.Value) any { + return c.id +} + +// Encrypt will encrypt the raw data. It will return a ciphertext. Padding is +// done on the plaintext so all encrypted data looks uniform at rest. +// +// Parameters: +// - args[0] - The data to be encrypted (Uint8Array). This must be smaller +// than the block size passed into [NewDatabaseCipher]. If it is +// larger, this will return an error. +// +// Returns: +// - The ciphertext of the plaintext passed in (String). +// - Throws an error if it fails to encrypt the plaintext. +func (c *DbCipher) Encrypt(_ js.Value, args []js.Value) any { + ciphertext, err := c.api.Encrypt(utils.CopyBytesToGo(args[0])) + if err != nil { + exception.ThrowTrace(err) + return nil + } + + return ciphertext +} + +// Decrypt will decrypt the passed in encrypted value. The plaintext will be +// returned by this function. Any padding will be discarded within this +// function. +// +// Parameters: +// - args[0] - the encrypted data returned by [DbCipher.Encrypt] +// (String). +// +// Returns: +// - The plaintext of the ciphertext passed in (Uint8Array). +// - Throws an error if it fails to encrypt the plaintext. +func (c *DbCipher) Decrypt(_ js.Value, args []js.Value) any { + plaintext, err := c.api.Decrypt(args[0].String()) + if err != nil { + exception.ThrowTrace(err) + return nil + } + + return utils.CopyBytesToJS(plaintext) +} + +// MarshalJSON marshals the cipher into valid JSON. +// +// Returns: +// - JSON of the cipher (Uint8Array). +// - Throws an error if marshalling fails. +func (c *DbCipher) MarshalJSON(js.Value, []js.Value) any { + data, err := c.api.MarshalJSON() + if err != nil { + exception.ThrowTrace(err) + return nil + } + + return utils.CopyBytesToJS(data) +} + +// UnmarshalJSON unmarshalls JSON into the cipher. +// +// Note that this function does not transfer the internal RNG. Use +// [indexedDb.NewCipherFromJSON] to properly reconstruct a cipher from JSON. +// +// Parameters: +// - args[0] - JSON data to unmarshal (Uint8Array). +// +// Returns: +// - JSON of the cipher (Uint8Array). +// - Throws an error if marshalling fails. +func (c *DbCipher) UnmarshalJSON(_ js.Value, args []js.Value) any { + err := c.api.UnmarshalJSON(utils.CopyBytesToGo(args[0])) + if err != nil { + exception.ThrowTrace(err) + return nil + } + return nil +} diff --git a/wasm/cipher_test.go b/wasm/cipher_test.go new file mode 100644 index 0000000000000000000000000000000000000000..0f83461509bc0f70ff5afd7104de9ab5fb3e6e11 --- /dev/null +++ b/wasm/cipher_test.go @@ -0,0 +1,35 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright © 2022 xx foundation // +// // +// Use of this source code is governed by a license that can be found in the // +// LICENSE file. // +//////////////////////////////////////////////////////////////////////////////// + +//go:build js && wasm + +package wasm + +import ( + "reflect" + "testing" +) + +// Tests that the map representing DbCipher returned by +// newDbCipherJS contains all the methods on DbCipher. +func Test_newChannelDbCipherJS(t *testing.T) { + cipherType := reflect.TypeOf(&DbCipher{}) + + cipher := newDbCipherJS(&DbCipher{}) + if len(cipher) != cipherType.NumMethod() { + t.Errorf("DbCipher JS object does not have all methods."+ + "\nexpected: %d\nreceived: %d", cipherType.NumMethod(), len(cipher)) + } + + for i := 0; i < cipherType.NumMethod(); i++ { + method := cipherType.Method(i) + + if _, exists := cipher[method.Name]; !exists { + t.Errorf("Method %s does not exist.", method.Name) + } + } +} diff --git a/wasm/collective.go b/wasm/collective.go index 5bd0fa145fd214752475bc1eaa9601dc881297e5..5c2eb771502e3206210cfc0dca78b3743f7b3fc0 100644 --- a/wasm/collective.go +++ b/wasm/collective.go @@ -516,13 +516,12 @@ func (rsCB *RemoteStore) Write(path string, data []byte) error { // Returns: // - JSON of [bindings.RemoteStoreReport] (Uint8Array). // - Catches any thrown errors (of type Error) and returns it as an error. -func (rsCB *RemoteStore) GetLastModified(path string) ([]byte, error) { - fn := func() js.Value { return rsCB.getLastModified(path) } - v, err := exception.RunAndCatch(fn) +func (rsCB *RemoteStore) GetLastModified(path string) (string, error) { + v, err := utils.Await(rsCB.getLastModified(path)) if err != nil { - return nil, err + return "", js.Error{Value: err[0]} } - return utils.CopyBytesToGo(v), err + return v[0].String(), nil } // GetLastWrite implements [bindings.RemoteStore.GetLastWrite() @@ -530,13 +529,12 @@ func (rsCB *RemoteStore) GetLastModified(path string) ([]byte, error) { // Returns: // - JSON of [bindings.RemoteStoreReport] (Uint8Array). // - Catches any thrown errors (of type Error) and returns it as an error. -func (rsCB *RemoteStore) GetLastWrite() ([]byte, error) { - fn := func() js.Value { return rsCB.getLastWrite() } - v, err := exception.RunAndCatch(fn) +func (rsCB *RemoteStore) GetLastWrite() (string, error) { + v, err := utils.Await(rsCB.getLastWrite()) if err != nil { - return nil, err + return "", js.Error{Value: err[0]} } - return utils.CopyBytesToGo(v), err + return v[0].String(), nil } // ReadDir implements [bindings.RemoteStore.ReadDir] diff --git a/wasm/dm.go b/wasm/dm.go index 53d123a26c3f92743f9868e03017e7c1858ca9bb..3786b0df32a68b9b0b70c09a9d5664263df3792f 100644 --- a/wasm/dm.go +++ b/wasm/dm.go @@ -128,8 +128,8 @@ func NewDMClient(_ js.Value, args []js.Value) any { // The row in the database that was updated can be found using the UUID. // messageUpdate is true if the message already exists and was edited. // conversationUpdate is true if the Conversation was created or modified. -// - args[4] - ID of [DMDbCipher] object in tracker (int). Create this object -// with [NewDMsDatabaseCipher] and get its id with [DMDbCipher.GetID]. +// - args[4] - ID of [DbCipher] object in tracker (int). Create this object +// with [NewDatabaseCipher] and get its id with [DbCipher.GetID]. // // Returns: // - Resolves to a Javascript representation of the [DMClient] object. @@ -142,7 +142,7 @@ func NewDMClientWithIndexedDb(_ js.Value, args []js.Value) any { messageReceivedCB := args[3] cipherID := args[4].Int() - cipher, err := bindings.GetDMDbCipherTrackerFromID(cipherID) + cipher, err := dbCipherTrackerSingleton.get(cipherID) if err != nil { exception.ThrowTrace(err) } @@ -190,7 +190,7 @@ func NewDMClientWithIndexedDbUnsafe(_ js.Value, args []js.Value) any { } func newDMClientWithIndexedDb(cmixID int, wasmJsPath string, - privateIdentity []byte, cb js.Value, cipher *bindings.DMDbCipher) any { + privateIdentity []byte, cb js.Value, cipher *DbCipher) any { messageReceivedCB := func(uuid uint64, pubKey ed25519.PublicKey, messageUpdate, conversationUpdate bool) { @@ -206,7 +206,7 @@ func newDMClientWithIndexedDb(cmixID int, wasmJsPath string, } dmPath := base64.RawStdEncoding.EncodeToString(pi.PubKey[:]) model, err := indexDB.NewWASMEventModel( - dmPath, wasmJsPath, cipher, messageReceivedCB) + dmPath, wasmJsPath, cipher.api, messageReceivedCB) if err != nil { reject(exception.NewTrace(err)) } @@ -671,35 +671,6 @@ func DecodeDMShareURL(_ js.Value, args []js.Value) any { return utils.CopyBytesToJS(report) } -//////////////////////////////////////////////////////////////////////////////// -// Channel Receiving Logic and Callback Registration // -//////////////////////////////////////////////////////////////////////////////// - -// channelMessageReceptionCallback wraps Javascript callbacks to adhere to the -// [bindings.ChannelMessageReceptionCallback] interface. -type dmReceptionCallback struct { - callback func(args ...any) js.Value -} - -// Callback returns the context for a channel message. -// -// Parameters: -// - receivedChannelMessageReport - Returns the JSON of -// [bindings.ReceivedChannelMessageReport] (Uint8Array). -// - err - Returns an error on failure (Error). -// -// Returns: -// - It must return a unique UUID for the message that it can be referenced by -// later (int). -func (cmrCB *dmReceptionCallback) Callback( - receivedChannelMessageReport []byte, err error) int { - uuid := cmrCB.callback( - utils.CopyBytesToJS(receivedChannelMessageReport), - exception.NewTrace(err)) - - return uuid.Int() -} - //////////////////////////////////////////////////////////////////////////////// // Event Model Logic // //////////////////////////////////////////////////////////////////////////////// @@ -990,146 +961,6 @@ func (em *dmReceiver) GetConversations() []byte { return conversationsBytes } -//////////////////////////////////////////////////////////////////////////////// -// DM DB Cipher // -//////////////////////////////////////////////////////////////////////////////// - -// DMDbCipher wraps the [bindings.DMDbCipher] object so its methods -// can be wrapped to be Javascript compatible. -type DMDbCipher struct { - api *bindings.DMDbCipher -} - -// newDMDbCipherJS creates a new Javascript compatible object -// (map[string]any) that matches the [DMDbCipher] structure. -func newDMDbCipherJS(api *bindings.DMDbCipher) map[string]any { - c := DMDbCipher{api} - channelDbCipherMap := map[string]any{ - "GetID": js.FuncOf(c.GetID), - "Encrypt": js.FuncOf(c.Encrypt), - "Decrypt": js.FuncOf(c.Decrypt), - "MarshalJSON": js.FuncOf(c.MarshalJSON), - "UnmarshalJSON": js.FuncOf(c.UnmarshalJSON), - } - - return channelDbCipherMap -} - -// NewDMsDatabaseCipher constructs a [DMDbCipher] object. -// -// Parameters: -// - args[0] - The tracked [Cmix] object ID (int). -// - args[1] - The password for storage. This should be the same password -// passed into [NewCmix] (Uint8Array). -// - args[2] - The maximum size of a payload to be encrypted. A payload passed -// into [DMDbCipher.Encrypt] that is larger than this value will result -// in an error (int). -// -// Returns: -// - JavaScript representation of the [DMDbCipher] object. -// - Throws an error if creating the cipher fails. -func NewDMsDatabaseCipher(_ js.Value, args []js.Value) any { - cmixId := args[0].Int() - password := utils.CopyBytesToGo(args[1]) - plaintTextBlockSize := args[2].Int() - - cipher, err := bindings.NewDMsDatabaseCipher( - cmixId, password, plaintTextBlockSize) - if err != nil { - exception.ThrowTrace(err) - return nil - } - - return newDMDbCipherJS(cipher) -} - -// GetID returns the ID for this [bindings.DMDbCipher] in the -// channelDbCipherTracker. -// -// Returns: -// - Tracker ID (int). -func (c *DMDbCipher) GetID(js.Value, []js.Value) any { - return c.api.GetID() -} - -// Encrypt will encrypt the raw data. It will return a ciphertext. Padding is -// done on the plaintext so all encrypted data looks uniform at rest. -// -// Parameters: -// - args[0] - The data to be encrypted (Uint8Array). This must be smaller -// than the block size passed into [NewDMsDatabaseCipher]. If it is -// larger, this will return an error. -// -// Returns: -// - The ciphertext of the plaintext passed in (Uint8Array). -// - Throws an error if it fails to encrypt the plaintext. -func (c *DMDbCipher) Encrypt(_ js.Value, args []js.Value) any { - ciphertext, err := c.api.Encrypt(utils.CopyBytesToGo(args[0])) - if err != nil { - exception.ThrowTrace(err) - return nil - } - - return utils.CopyBytesToJS(ciphertext) -} - -// Decrypt will decrypt the passed in encrypted value. The plaintext will be -// returned by this function. Any padding will be discarded within this -// function. -// -// Parameters: -// - args[0] - the encrypted data returned by [DMDbCipher.Encrypt] -// (Uint8Array). -// -// Returns: -// - The plaintext of the ciphertext passed in (Uint8Array). -// - Throws an error if it fails to encrypt the plaintext. -func (c *DMDbCipher) Decrypt(_ js.Value, args []js.Value) any { - plaintext, err := c.api.Decrypt(utils.CopyBytesToGo(args[0])) - if err != nil { - exception.ThrowTrace(err) - return nil - } - - return utils.CopyBytesToJS(plaintext) -} - -// MarshalJSON marshals the cipher into valid JSON. -// -// Returns: -// - JSON of the cipher (Uint8Array). -// - Throws an error if marshalling fails. -func (c *DMDbCipher) MarshalJSON(js.Value, []js.Value) any { - data, err := c.api.MarshalJSON() - if err != nil { - exception.ThrowTrace(err) - return nil - } - - return utils.CopyBytesToJS(data) -} - -// UnmarshalJSON unmarshalls JSON into the cipher. This function adheres to the -// json.Unmarshaler interface. -// -// Note that this function does not transfer the internal RNG. Use -// [channel.NewCipherFromJSON] to properly reconstruct a cipher from JSON. -// -// Parameters: -// - args[0] - JSON data to unmarshal (Uint8Array). -// -// Returns: -// - JSON of the cipher (Uint8Array). -// - Throws an error if marshalling fails. -func (c *DMDbCipher) UnmarshalJSON(_ js.Value, args []js.Value) any { - err := c.api.UnmarshalJSON(utils.CopyBytesToGo(args[0])) - if err != nil { - exception.ThrowTrace(err) - return nil - } - return nil -} - // truncate truncates the string to length n. If the string is trimmed, then // ellipses (...) are appended. func truncate(s string, n int) string { diff --git a/wasm/dm_test.go b/wasm/dm_test.go index 58f837ea0bb857deaede29fd9f5c37f4cd936e34..f959c9463fe793d7cac78927dcdc8eba5980d5f7 100644 --- a/wasm/dm_test.go +++ b/wasm/dm_test.go @@ -62,43 +62,3 @@ func Test_DMClientMethods(t *testing.T) { } } } - -// Tests that the map representing DMDbCipher returned by newDMDbCipherJS -// contains all of the methods on DMDbCipher. -func Test_newDMDbCipherJS(t *testing.T) { - cipherType := reflect.TypeOf(&DMDbCipher{}) - - cipher := newDMDbCipherJS(&bindings.DMDbCipher{}) - if len(cipher) != cipherType.NumMethod() { - t.Errorf("DMDbCipher JS object does not have all methods."+ - "\nexpected: %d\nreceived: %d", cipherType.NumMethod(), len(cipher)) - } - - for i := 0; i < cipherType.NumMethod(); i++ { - method := cipherType.Method(i) - - if _, exists := cipher[method.Name]; !exists { - t.Errorf("Method %s does not exist.", method.Name) - } - } -} - -// Tests that DMDbCipher has all the methods that [bindings.DMDbCipher] has. -func Test_DMDbCipherMethods(t *testing.T) { - cipherType := reflect.TypeOf(&DMDbCipher{}) - binCipherType := reflect.TypeOf(&bindings.DMDbCipher{}) - - if binCipherType.NumMethod() != cipherType.NumMethod() { - t.Errorf("WASM DMDbCipher object does not have all methods from "+ - "bindings.\nexpected: %d\nreceived: %d", - binCipherType.NumMethod(), cipherType.NumMethod()) - } - - for i := 0; i < binCipherType.NumMethod(); i++ { - method := binCipherType.Method(i) - - if _, exists := cipherType.MethodByName(method.Name); !exists { - t.Errorf("Method %s does not exist.", method.Name) - } - } -} diff --git a/wasm_test.go b/wasm_test.go index b415ece5623aa4e235511fb1f9cb24058e02e384..1e0494dbe4f6e08ec9276aa3b984b5c245cfa7e8 100644 --- a/wasm_test.go +++ b/wasm_test.go @@ -42,7 +42,7 @@ func TestPublicFunctions(t *testing.T) { "NewEventModel": {}, "NewChannelsManagerGoEventModel": {}, "LoadChannelsManagerGoEventModel": {}, - "GetChannelDbCipherTrackerFromID": {}, + "GetDbCipherTrackerFromID": {}, // Version functions were renamed to differentiate between WASM and // client versions