diff --git a/go.mod b/go.mod index 0bf14f4ac73b575a9957204bbd4e5daf0cf1c7a6..24f71d5f7a4a7c6d79ac846c000543fabfee1719 100644 --- a/go.mod +++ b/go.mod @@ -7,8 +7,8 @@ require ( github.com/hack-pad/go-indexeddb v0.2.0 github.com/pkg/errors v0.9.1 github.com/spf13/jwalterweatherman v1.1.0 - gitlab.com/elixxir/client v1.5.1-0.20221022011543-5e9ddca52454 - gitlab.com/elixxir/crypto v0.0.7-0.20221021185743-d26832a1197a + gitlab.com/elixxir/client v1.5.1-0.20221022020343-af368242bb1e + gitlab.com/elixxir/crypto v0.0.7-0.20221022003355-d8a6158b32a7 gitlab.com/elixxir/primitives v0.0.3-0.20221017172918-6176818d1aba gitlab.com/xx_network/crypto v0.0.5-0.20221017172404-b384a8d8b171 gitlab.com/xx_network/primitives v0.0.4-0.20221017171439-42169a3e5c0d diff --git a/go.sum b/go.sum index c3ae3eb2e677517cba4f6aa3e1ef0b7eb61942cb..1ab9e902391102d9cbac2c86292ca3dc6bebbcb2 100644 --- a/go.sum +++ b/go.sum @@ -616,15 +616,15 @@ github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo= github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4= gitlab.com/elixxir/bloomfilter v0.0.0-20211222005329-7d931ceead6f h1:yXGvNBqzZwAhDYlSnxPRbgor6JWoOt1Z7s3z1O9JR40= gitlab.com/elixxir/bloomfilter v0.0.0-20211222005329-7d931ceead6f/go.mod h1:H6jztdm0k+wEV2QGK/KYA+MY9nj9Zzatux/qIvDDv3k= -gitlab.com/elixxir/client v1.5.1-0.20221022011543-5e9ddca52454 h1:9b6XWDs8WywoydY9CvJ+EOQmaWa9Ivg7YDyu/JQlS2M= -gitlab.com/elixxir/client v1.5.1-0.20221022011543-5e9ddca52454/go.mod h1:vADvJNa+AD599FSMC8UB1Adulg1b0JQu37weyfeMFvA= +gitlab.com/elixxir/client v1.5.1-0.20221022020343-af368242bb1e h1:30XqsYQCvNarkq9GT3wm9UL/o00VPcPzi5hKvha5e4M= +gitlab.com/elixxir/client v1.5.1-0.20221022020343-af368242bb1e/go.mod h1:a5pLHWVKdwacbyL9yGlV/xP5xHbhC2ycqTbEsDyzjo4= gitlab.com/elixxir/comms v0.0.4-0.20221017173926-4eaa6061dfaa h1:/FEpu0N0rAyq74FkvO3uY8BcQoWLSbVPhj/s5QfscZw= gitlab.com/elixxir/comms v0.0.4-0.20221017173926-4eaa6061dfaa/go.mod h1:rW7xdbHntP2MoF3q+2+f+IR8OHol94MRyviotfR5rXg= gitlab.com/elixxir/crypto v0.0.0-20200804182833-984246dea2c4/go.mod h1:ucm9SFKJo+K0N2GwRRpaNr+tKXMIOVWzmyUD0SbOu2c= gitlab.com/elixxir/crypto v0.0.3/go.mod h1:ZNgBOblhYToR4m8tj4cMvJ9UsJAUKq+p0gCp07WQmhA= gitlab.com/elixxir/crypto v0.0.7-0.20221017173452-565da4101a3b/go.mod h1:1rftbwSVdy49LkBIkPr+w+P2mDOerYeBKoZuB3r0yqI= -gitlab.com/elixxir/crypto v0.0.7-0.20221021185743-d26832a1197a h1:niF6yQflBFYXKl95pJLMWQCmwH2D29lovZlTqoAzbEY= -gitlab.com/elixxir/crypto v0.0.7-0.20221021185743-d26832a1197a/go.mod h1:1rftbwSVdy49LkBIkPr+w+P2mDOerYeBKoZuB3r0yqI= +gitlab.com/elixxir/crypto v0.0.7-0.20221022003355-d8a6158b32a7 h1:+8DHBxZxJcmJSmcUFK4ZjjXgwV3wSo9O4+4NCaLdO4c= +gitlab.com/elixxir/crypto v0.0.7-0.20221022003355-d8a6158b32a7/go.mod h1:P/S3pEPYl7fuHQ1m4mL2pIaCxAjYIXrJml/pnfofI+U= gitlab.com/elixxir/ekv v0.2.1 h1:dtwbt6KmAXG2Tik5d60iDz2fLhoFBgWwST03p7T+9Is= gitlab.com/elixxir/ekv v0.2.1/go.mod h1:USLD7xeDnuZEavygdrgzNEwZXeLQJK/w1a+htpN+JEU= gitlab.com/elixxir/primitives v0.0.0-20200731184040-494269b53b4d/go.mod h1:OQgUZq7SjnE0b+8+iIAT2eqQF+2IFHn73tOo+aV11mg= diff --git a/main.go b/main.go index c600ad1eccdec90397ef1b2ecc3071a74db68b2a..fbec3d118fd1cff67c6a825f16c39e1f1636645b 100644 --- a/main.go +++ b/main.go @@ -13,7 +13,7 @@ import ( "fmt" jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/client/bindings" - "gitlab.com/elixxir/xxdk-wasm/creds" + "gitlab.com/elixxir/xxdk-wasm/storage" "gitlab.com/elixxir/xxdk-wasm/utils" "gitlab.com/elixxir/xxdk-wasm/wasm" "os" @@ -28,7 +28,7 @@ func init() { jww.SetStdoutThreshold(jww.LevelFatal + 1) // Check that the WASM binary version is correct - err := utils.CheckAndStoreVersions() + err := storage.CheckAndStoreVersions() if err != nil { jww.FATAL.Panicf("WASM binary version error: %+v", err) } @@ -38,11 +38,11 @@ func main() { fmt.Println("Starting xxDK WebAssembly bindings.") fmt.Printf("Client version %s\n", bindings.GetVersion()) - // creds/password.go - js.Global().Set("GetOrInitPassword", js.FuncOf(creds.GetOrInitPassword)) + // storage/password.go + js.Global().Set("GetOrInitPassword", js.FuncOf(storage.GetOrInitPassword)) js.Global().Set("ChangeExternalPassword", - js.FuncOf(creds.ChangeExternalPassword)) - js.Global().Set("VerifyPassword", js.FuncOf(creds.VerifyPassword)) + js.FuncOf(storage.ChangeExternalPassword)) + js.Global().Set("VerifyPassword", js.FuncOf(storage.VerifyPassword)) // utils/array.go js.Global().Set("Uint8ArrayToBase64", js.FuncOf(utils.Uint8ArrayToBase64)) @@ -75,6 +75,9 @@ func main() { js.Global().Set("NewChannelsManagerWithIndexedDbUnsafe", js.FuncOf(wasm.NewChannelsManagerWithIndexedDbUnsafe)) js.Global().Set("GenerateChannel", js.FuncOf(wasm.GenerateChannel)) + js.Global().Set("DecodePublicURL", js.FuncOf(wasm.DecodePublicURL)) + js.Global().Set("DecodePrivateURL", js.FuncOf(wasm.DecodePrivateURL)) + js.Global().Set("GetChannelJSON", js.FuncOf(wasm.GetChannelJSON)) js.Global().Set("GetChannelInfo", js.FuncOf(wasm.GetChannelInfo)) js.Global().Set("GetShareUrlType", js.FuncOf(wasm.GetShareUrlType)) js.Global().Set("IsNicknameValid", js.FuncOf(wasm.IsNicknameValid)) diff --git a/utils/localStorage.go b/storage/localStorage.go similarity index 99% rename from utils/localStorage.go rename to storage/localStorage.go index b0bd76be067b850043c69733f58770957e9d695c..2f2329209ca951c5f1dcc4e063dfde9ba9edc7f4 100644 --- a/utils/localStorage.go +++ b/storage/localStorage.go @@ -7,7 +7,7 @@ //go:build js && wasm -package utils +package storage import ( "encoding/base64" diff --git a/utils/localStorage_test.go b/storage/localStorage_test.go similarity index 99% rename from utils/localStorage_test.go rename to storage/localStorage_test.go index e102a1052c5c22042c1b5f5dc6c0c352855147a7..155bd7c4c32a558f05ea14989f18c1cb83a38051 100644 --- a/utils/localStorage_test.go +++ b/storage/localStorage_test.go @@ -7,7 +7,7 @@ //go:build js && wasm -package utils +package storage import ( "bytes" diff --git a/creds/password.go b/storage/password.go similarity index 97% rename from creds/password.go rename to storage/password.go index 58eb8d9ffe3c002963702d6f2573ec4c031d3ca9..6b838a1fd492d6a4e71b69ce815a21d07195865f 100644 --- a/creds/password.go +++ b/storage/password.go @@ -7,7 +7,7 @@ //go:build js && wasm -package creds +package storage import ( "crypto/cipher" @@ -130,7 +130,7 @@ func VerifyPassword(_ js.Value, args []js.Value) interface{} { // getOrInit is the private function for GetOrInitPassword that is used for // testing. func getOrInit(externalPassword string) ([]byte, error) { - localStorage := utils.GetLocalStorage() + localStorage := GetLocalStorage() internalPassword, err := getInternalPassword(externalPassword, localStorage) if err != nil { if errors.Is(err, os.ErrNotExist) { @@ -148,7 +148,7 @@ func getOrInit(externalPassword string) ([]byte, error) { // changeExternalPassword is the private function for ChangeExternalPassword // that is used for testing. func changeExternalPassword(oldExternalPassword, newExternalPassword string) error { - localStorage := utils.GetLocalStorage() + localStorage := GetLocalStorage() internalPassword, err := getInternalPassword(oldExternalPassword, localStorage) if err != nil { return err @@ -172,14 +172,14 @@ func changeExternalPassword(oldExternalPassword, newExternalPassword string) err // verifyPassword is the private function for VerifyPassword that is used for // testing. func verifyPassword(externalPassword string) bool { - _, err := getInternalPassword(externalPassword, utils.GetLocalStorage()) + _, err := getInternalPassword(externalPassword, GetLocalStorage()) return err == nil } // initInternalPassword generates a new internal password, stores an encrypted // version in local storage, and returns it. func initInternalPassword(externalPassword string, - localStorage *utils.LocalStorage, csprng io.Reader, + localStorage *LocalStorage, csprng io.Reader, params argonParams) ([]byte, error) { internalPassword := make([]byte, internalPasswordLen) @@ -217,7 +217,7 @@ func initInternalPassword(externalPassword string, // getInternalPassword retrieves the internal password from local storage, // decrypts it, and returns it. func getInternalPassword( - externalPassword string, localStorage *utils.LocalStorage) ([]byte, error) { + externalPassword string, localStorage *LocalStorage) ([]byte, error) { encryptedInternalPassword, err := localStorage.GetItem(passwordKey) if err != nil { return nil, errors.WithMessage(err, getPasswordStorageErr) diff --git a/creds/password_test.go b/storage/password_test.go similarity index 97% rename from creds/password_test.go rename to storage/password_test.go index ff9c71c5c3935c19d4fd4e8122978ce1c45a162d..24f1ed035197a1856c9f1750d2072609d9feb9c1 100644 --- a/creds/password_test.go +++ b/storage/password_test.go @@ -7,14 +7,13 @@ //go:build js && wasm -package creds +package storage import ( "bytes" "crypto/rand" "encoding/base64" "fmt" - "gitlab.com/elixxir/xxdk-wasm/utils" "gitlab.com/xx_network/crypto/csprng" "strings" "testing" @@ -78,7 +77,7 @@ func Test_changeExternalPassword(t *testing.T) { // Tests that verifyPassword returns true for a valid password and false for an // invalid password func Test_verifyPassword(t *testing.T) { - utils.GetLocalStorage().Clear() + GetLocalStorage().Clear() externalPassword := "myPassword" if _, err := getOrInit(externalPassword); err != nil { @@ -98,7 +97,7 @@ func Test_verifyPassword(t *testing.T) { // the encrypted one saved to local storage. func Test_initInternalPassword(t *testing.T) { externalPassword := "myPassword" - ls := utils.GetLocalStorage() + ls := GetLocalStorage() rng := csprng.NewSystemRNG() internalPassword, err := initInternalPassword( @@ -139,7 +138,7 @@ func Test_initInternalPassword(t *testing.T) { // error when read. func Test_initInternalPassword_CsprngReadError(t *testing.T) { externalPassword := "myPassword" - ls := utils.GetLocalStorage() + ls := GetLocalStorage() b := bytes.NewBuffer([]byte{}) expectedErr := strings.Split(readInternalPasswordErr, "%")[0] @@ -155,7 +154,7 @@ func Test_initInternalPassword_CsprngReadError(t *testing.T) { // return enough bytes. func Test_initInternalPassword_CsprngReadNumBytesError(t *testing.T) { externalPassword := "myPassword" - ls := utils.GetLocalStorage() + ls := GetLocalStorage() b := bytes.NewBuffer(make([]byte, internalPasswordLen/2)) expectedErr := fmt.Sprintf( @@ -172,7 +171,7 @@ func Test_initInternalPassword_CsprngReadNumBytesError(t *testing.T) { // to local storage by initInternalPassword. func Test_getInternalPassword(t *testing.T) { externalPassword := "myPassword" - ls := utils.GetLocalStorage() + ls := GetLocalStorage() rng := csprng.NewSystemRNG() internalPassword, err := initInternalPassword( @@ -197,7 +196,7 @@ func Test_getInternalPassword(t *testing.T) { // loaded from local storage. func Test_getInternalPassword_LocalStorageGetPasswordError(t *testing.T) { externalPassword := "myPassword" - ls := utils.GetLocalStorage() + ls := GetLocalStorage() ls.Clear() expectedErr := strings.Split(getPasswordStorageErr, "%")[0] @@ -213,7 +212,7 @@ func Test_getInternalPassword_LocalStorageGetPasswordError(t *testing.T) { // loaded from local storage. func Test_getInternalPassword_LocalStorageGetError(t *testing.T) { externalPassword := "myPassword" - ls := utils.GetLocalStorage() + ls := GetLocalStorage() ls.Clear() ls.SetItem(passwordKey, []byte("password")) @@ -230,7 +229,7 @@ func Test_getInternalPassword_LocalStorageGetError(t *testing.T) { // decrypted. func Test_getInternalPassword_DecryptPasswordError(t *testing.T) { externalPassword := "myPassword" - ls := utils.GetLocalStorage() + ls := GetLocalStorage() ls.Clear() ls.SetItem(saltKey, []byte("salt")) ls.SetItem(passwordKey, []byte("password")) diff --git a/utils/version.go b/storage/version.go similarity index 99% rename from utils/version.go rename to storage/version.go index ab26b463c72f958700840212795c6df63258d6c9..263ad6a9c4c17762d84b6229f50b5c371fea2e65 100644 --- a/utils/version.go +++ b/storage/version.go @@ -7,7 +7,7 @@ //go:build js && wasm -package utils +package storage import ( "github.com/pkg/errors" diff --git a/utils/version_test.go b/storage/version_test.go similarity index 99% rename from utils/version_test.go rename to storage/version_test.go index f54465033749f094b03a705a552e464933bb04d5..596034090ba07fd5bcf71f42b44e16e9517774c5 100644 --- a/utils/version_test.go +++ b/storage/version_test.go @@ -7,7 +7,7 @@ //go:build js && wasm -package utils +package storage import ( "testing" diff --git a/wasm/channels.go b/wasm/channels.go index 4a44c049be2c5c8c064eb264ac0af7f997d4b01c..6531aff770cd71f620b1d3fbe9d16c406bb3ff93 100644 --- a/wasm/channels.go +++ b/wasm/channels.go @@ -36,12 +36,11 @@ func newChannelsManagerJS(api *bindings.ChannelsManager) map[string]interface{} cm := ChannelsManager{api} channelsManagerMap := map[string]interface{}{ // Basic Channel API - "GetID": js.FuncOf(cm.GetID), - "JoinChannel": js.FuncOf(cm.JoinChannel), - "JoinChannelFromURL": js.FuncOf(cm.JoinChannelFromURL), - "GetChannels": js.FuncOf(cm.GetChannels), - "LeaveChannel": js.FuncOf(cm.LeaveChannel), - "ReplayChannel": js.FuncOf(cm.ReplayChannel), + "GetID": js.FuncOf(cm.GetID), + "JoinChannel": js.FuncOf(cm.JoinChannel), + "GetChannels": js.FuncOf(cm.GetChannels), + "LeaveChannel": js.FuncOf(cm.LeaveChannel), + "ReplayChannel": js.FuncOf(cm.ReplayChannel), // Share URL "GetShareURL": js.FuncOf(cm.GetShareURL), @@ -548,13 +547,85 @@ func GenerateChannel(_ js.Value, args []js.Value) interface{} { return utils.CopyBytesToJS(gen) } +// DecodePublicURL decodes the channel URL into a channel pretty print. This +// function can only be used for public channel URLs. To get the privacy level +// of a channel URL, use [GetShareUrlType]. +// +// Parameters: +// - args[0] - The channel's share URL (string). Should be received from +// another user or generated via [GetShareURL]. +// +// Returns: +// - The channel pretty print (string). +func DecodePublicURL(_ js.Value, args []js.Value) interface{} { + c, err := bindings.DecodePublicURL(args[0].String()) + if err != nil { + utils.Throw(utils.TypeError, err) + return nil + } + + return c +} + +// DecodePrivateURL decodes the channel URL, using the password, into a channel +// pretty print. This function can only be used for private or secret channel +// URLs. To get the privacy level of a channel URL, use [GetShareUrlType]. +// +// Parameters: +// - args[0] - The channel's share URL (string). Should be received from +// another user or generated via [GetShareURL]. +// - args[1] - The password needed to decrypt the secret data in the URL +// (string). +// +// Returns: +// - The channel pretty print (string) +func DecodePrivateURL(_ js.Value, args []js.Value) interface{} { + c, err := bindings.DecodePrivateURL(args[0].String(), args[1].String()) + if err != nil { + utils.Throw(utils.TypeError, err) + return nil + } + + return c +} + +// GetChannelJSON returns the JSON of the channel for the given pretty print. +// +// Parameters: +// - args[0] - The pretty print of the channel (string). +// +// Returns: +// - JSON of the [broadcast.Channel] object (Uint8Array). +// +// Example JSON of [broadcast.Channel]: +// { +// "ReceptionID": "Ja/+Jh+1IXZYUOn+IzE3Fw/VqHOscomD0Q35p4Ai//kD", +// "Name": "My_Channel", +// "Description": "Here is information about my channel.", +// "Salt": "+tlrU/htO6rrV3UFDfpQALUiuelFZ+Cw9eZCwqRHk+g=", +// "RsaPubKeyHash": "PViT1mYkGBj6AYmE803O2RpA7BX24EjgBdldu3pIm4o=", +// "RsaPubKeyLength": 5, +// "RSASubPayloads": 1, +// "Secret": "JxZt/wPx2luoPdHY6jwbXqNlKnixVU/oa9DgypZOuyI=", +// "Level": 0 +// } +func GetChannelJSON(_ js.Value, args []js.Value) interface{} { + c, err := bindings.GetChannelJSON(args[0].String()) + if err != nil { + utils.Throw(utils.TypeError, err) + return nil + } + + return c +} + // GetChannelInfo returns the info about a channel from its public description. // // Parameters: // - args[0] - The pretty print of the channel (string). // // The pretty print will be of the format: -// <Speakeasy-v1:Test Channel,description:This is a test channel,secrets:YxHhRAKy2D4XU2oW5xnW/3yaqOeh8nO+ZSd3nUmiQ3c=,6pXN2H9FXcOj7pjJIZoq6nMi4tGX2s53fWH5ze2dU1g=,493,1,MVjkHlm0JuPxQNAn6WHsPdOw9M/BUF39p7XB/QEkQyc=> +// <Speakeasy-v2:Test_Channel|description:Channel description.|level:Public|secrets:+oHcqDbJPZaT3xD5NcdLY8OjOMtSQNKdKgLPmr7ugdU=|rCI0wr01dHFStjSFMvsBzFZClvDIrHLL5xbCOPaUOJ0=|493|1|7cBhJxVfQxWo+DypOISRpeWdQBhuQpAZtUbQHjBm8NQ=> // // Returns: // - JSON of [bindings.ChannelInfo], which describes all relevant channel info @@ -578,7 +649,7 @@ func GetChannelInfo(_ js.Value, args []js.Value) interface{} { // or generated via GenerateChannel (string). // // The pretty print will be of the format: -// <Speakeasy-v1:Test Channel,description:This is a test channel,secrets:YxHhRAKy2D4XU2oW5xnW/3yaqOeh8nO+ZSd3nUmiQ3c=,6pXN2H9FXcOj7pjJIZoq6nMi4tGX2s53fWH5ze2dU1g=,493,1,MVjkHlm0JuPxQNAn6WHsPdOw9M/BUF39p7XB/QEkQyc=> +// <Speakeasy-v2:Test_Channel|description:Channel description.|level:Public|secrets:+oHcqDbJPZaT3xD5NcdLY8OjOMtSQNKdKgLPmr7ugdU=|rCI0wr01dHFStjSFMvsBzFZClvDIrHLL5xbCOPaUOJ0=|493|1|7cBhJxVfQxWo+DypOISRpeWdQBhuQpAZtUbQHjBm8NQ=> // // Returns: // - JSON of [bindings.ChannelInfo], which describes all relevant channel info @@ -594,32 +665,6 @@ func (ch *ChannelsManager) JoinChannel(_ js.Value, args []js.Value) interface{} return utils.CopyBytesToJS(ci) } -// JoinChannelFromURL joins the given channel from a URL. It will fail if the -// channel has already been joined. A password is required unless it is of the -// privacy level [broadcast.Public], in which case it can be left empty. To get -// the privacy level of a channel URL, use [GetShareUrlType]. -// -// Parameters: -// - args[0] - The channel's share URL. Should be received from another user -// or generated via [ChannelsManager.GetShareURL] (string). -// - args[1] - The password needed to decrypt the secret data in the URL -// (string). Only required for private or secret channels. Use empty string -// ("") for public channels. -// -// Returns: -// - JSON of [bindings.ChannelInfo], which describes all relevant channel info -// (Uint8Array). -// - Throws a TypeError if joining the channel fails. -func (ch *ChannelsManager) JoinChannelFromURL(_ js.Value, args []js.Value) interface{} { - ci, err := ch.api.JoinChannelFromURL(args[0].String(), args[1].String()) - if err != nil { - utils.Throw(utils.TypeError, err) - return nil - } - - return utils.CopyBytesToJS(ci) -} - // GetChannels returns the IDs of all channels that have been joined. // // Returns: @@ -1363,7 +1408,7 @@ func newChannelDbCipherJS(api *bindings.ChannelDbCipher) map[string]interface{} // in an error (int). // // Returns: -// - A JavaScript representation of the [ChannelDbCipher] object. +// - JavaScript representation of the [ChannelDbCipher] object. // - Throws a TypeError if creating the cipher fails. func NewChannelsDatabaseCipher(_ js.Value, args []js.Value) interface{} { cmixId := args[0].Int() diff --git a/wasm/version.go b/wasm/version.go index 0ffab9a2814c96fad9f2c8db37fd2064de922611..27388fad345b55f90bbe511d07dbf3b4a15ee8f1 100644 --- a/wasm/version.go +++ b/wasm/version.go @@ -11,7 +11,7 @@ package wasm import ( "gitlab.com/elixxir/client/bindings" - "gitlab.com/elixxir/xxdk-wasm/utils" + "gitlab.com/elixxir/xxdk-wasm/storage" "syscall/js" ) @@ -20,7 +20,7 @@ import ( // Returns: // - Current version (string). func GetVersion(js.Value, []js.Value) interface{} { - return utils.SEMVER + return storage.SEMVER } // GetClientVersion returns the current client xxDK semantic version diff --git a/wasm_test.go b/wasm_test.go index 38d1bdd30e9cd3efe0569afe50903b94948761af..3b64f93caf929c4f9aee0119a2696949af945f38 100644 --- a/wasm_test.go +++ b/wasm_test.go @@ -25,9 +25,10 @@ func TestPublicFunctions(t *testing.T) { // not implemented. excludeList := map[string]struct{}{ // Notifications are not available in the browser - "GetNotificationsReport": {}, - "RegisterForNotifications": {}, - "UnregisterForNotifications": {}, + "GetNotificationsReport": {}, + "RegisterForNotifications": {}, + "UnregisterForNotifications": {}, + "GetChannelDbCipherTrackerFromID": {}, // UD not available in the browser "IsRegisteredWithUD": {},