From 97234ccc8c4518bf9a4e2ebddf7384b93ec1f13e Mon Sep 17 00:00:00 2001 From: Jono Wenger <jono@elixxir.io> Date: Mon, 5 Dec 2022 15:20:10 -0800 Subject: [PATCH] Update bindings to match admin command updates --- go.mod | 2 +- go.sum | 4 +- wasm/channels.go | 300 +++++++++++++++++++++++++---------------------- wasm/docs.go | 2 + 4 files changed, 164 insertions(+), 144 deletions(-) diff --git a/go.mod b/go.mod index 5ea142db..9da6c724 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ 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/v4 v4.3.9-0.20221205203130-cceb2467241d + gitlab.com/elixxir/client/v4 v4.3.9-0.20221205230100-8d476bdbd896 gitlab.com/elixxir/crypto v0.0.7-0.20221202020255-46eeab272a7f gitlab.com/elixxir/primitives v0.0.3-0.20221114231218-cc461261a6af gitlab.com/xx_network/crypto v0.0.5-0.20221121220724-8eefdbb0eb46 diff --git a/go.sum b/go.sum index d31035e8..c92a367c 100644 --- a/go.sum +++ b/go.sum @@ -369,8 +369,8 @@ 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/v4 v4.3.9-0.20221205203130-cceb2467241d h1:AGrBjrjhI6+Vef9Cw3MswBkcVer8G/hpQYuOHzNOgnU= -gitlab.com/elixxir/client/v4 v4.3.9-0.20221205203130-cceb2467241d/go.mod h1:6zBHVEOwB42N3Ba3879GW0huu595RLSar04KlNsa7QE= +gitlab.com/elixxir/client/v4 v4.3.9-0.20221205230100-8d476bdbd896 h1:I/72gteNvOzH1ipt2QxmyQZ8xRrmZHm4yMwffl5T0RY= +gitlab.com/elixxir/client/v4 v4.3.9-0.20221205230100-8d476bdbd896/go.mod h1:6zBHVEOwB42N3Ba3879GW0huu595RLSar04KlNsa7QE= gitlab.com/elixxir/comms v0.0.4-0.20221110181420-84bca6216fe4 h1:bLRjVCyMVde4n2hTVgoyyIAWrKI4CevpChchkPeb6A0= gitlab.com/elixxir/comms v0.0.4-0.20221110181420-84bca6216fe4/go.mod h1:XhI2/CMng+xcH3mAs+1aPz29PSNu1079XMJ8V+xxihw= gitlab.com/elixxir/crypto v0.0.7-0.20221202020255-46eeab272a7f h1:e7h3InxgzRnYOqgUgHrTfK6CW8qNM2SiYRj9tOvsFjA= diff --git a/wasm/channels.go b/wasm/channels.go index 9d98db35..6f733d66 100644 --- a/wasm/channels.go +++ b/wasm/channels.go @@ -64,6 +64,11 @@ func newChannelsManagerJS(api *bindings.ChannelsManager) map[string]any { "DeleteNickname": js.FuncOf(cm.DeleteNickname), "GetNickname": js.FuncOf(cm.GetNickname), "Muted": js.FuncOf(cm.Muted), + "IsChannelAdmin": js.FuncOf(cm.IsChannelAdmin), + "ExportChannelAdminKey": js.FuncOf(cm.ExportChannelAdminKey), + "VerifyChannelAdminKey": js.FuncOf(cm.VerifyChannelAdminKey), + "ImportChannelAdminKey": js.FuncOf(cm.ImportChannelAdminKey), + "DeleteChannelAdminKey": js.FuncOf(cm.DeleteChannelAdminKey), // Channel Receiving Logic and Callback Registration "RegisterReceiveHandler": js.FuncOf(cm.RegisterReceiveHandler), @@ -227,28 +232,6 @@ func GetPublicChannelIdentityFromPrivate(_ js.Value, args []js.Value) any { return utils.CopyBytesToJS(identity) } -// eventModelBuilder adheres to the [bindings.EventModelBuilder] interface. -type eventModelBuilder struct { - build func(args ...any) js.Value -} - -// Build initializes and returns the event model. It wraps a Javascript object -// that has all the methods in [bindings.EventModel] to make it adhere to the Go -// interface [bindings.EventModel]. -func (emb *eventModelBuilder) Build(path string) bindings.EventModel { - emJs := emb.build(path) - return &eventModel{ - joinChannel: utils.WrapCB(emJs, "JoinChannel"), - leaveChannel: utils.WrapCB(emJs, "LeaveChannel"), - receiveMessage: utils.WrapCB(emJs, "ReceiveMessage"), - receiveReply: utils.WrapCB(emJs, "ReceiveReply"), - receiveReaction: utils.WrapCB(emJs, "ReceiveReaction"), - updateFromUUID: utils.WrapCB(emJs, "UpdateFromUUID"), - updateFromMessageID: utils.WrapCB(emJs, "UpdateFromMessageID"), - getMessage: utils.WrapCB(emJs, "GetMessage"), - } -} - // NewChannelsManager creates a new [ChannelsManager] from a new private // identity ([channel.PrivateIdentity]). // @@ -517,6 +500,10 @@ func loadChannelsManagerWithIndexedDb(cmixID int, storageTag string, return utils.CreatePromise(promiseFn) } +//////////////////////////////////////////////////////////////////////////////// +// Channel Actions // +//////////////////////////////////////////////////////////////////////////////// + // 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]. @@ -628,9 +615,8 @@ func GetChannelInfo(_ js.Value, args []js.Value) any { // optional but cannot be longer than 144 characters and can include all // Unicode characters. It cannot be changed once a channel is created. // - args[2] - The [broadcast.PrivacyLevel] of the channel (int). 0 = public, -// -// // 1 = private, and 2 = secret. Refer to the comment below for more -// // information. +// 1 = private, and 2 = secret. Refer to the comment below for more +// information. // // Returns: // - The pretty print of the channel (string). @@ -681,28 +667,6 @@ func (cm *ChannelsManager) JoinChannel(_ js.Value, args []js.Value) any { return utils.CopyBytesToJS(ci) } -// GetChannels returns the IDs of all channels that have been joined. -// -// Returns: -// - JSON of an array of marshalled [id.ID] (Uint8Array). -// - Throws a TypeError if getting the channels fails. -// -// JSON Example: -// -// { -// "U4x/lrFkvxuXu59LtHLon1sUhPJSCcnZND6SugndnVID", -// "15tNdkKbYXoMn58NO6VbDMDWFEyIhTWEGsvgcJsHWAgD" -// } -func (cm *ChannelsManager) GetChannels(js.Value, []js.Value) any { - channelList, err := cm.api.GetChannels() - if err != nil { - utils.Throw(utils.TypeError, err) - return nil - } - - return utils.CopyBytesToJS(channelList) -} - // LeaveChannel leaves the given channel. It will return an error if the channel // was not previously joined. // @@ -743,6 +707,28 @@ func (cm *ChannelsManager) ReplayChannel(_ js.Value, args []js.Value) any { return nil } +// GetChannels returns the IDs of all channels that have been joined. +// +// Returns: +// - JSON of an array of marshalled [id.ID] (Uint8Array). +// - Throws a TypeError if getting the channels fails. +// +// JSON Example: +// +// { +// "U4x/lrFkvxuXu59LtHLon1sUhPJSCcnZND6SugndnVID", +// "15tNdkKbYXoMn58NO6VbDMDWFEyIhTWEGsvgcJsHWAgD" +// } +func (cm *ChannelsManager) GetChannels(js.Value, []js.Value) any { + channelList, err := cm.api.GetChannels() + if err != nil { + utils.Throw(utils.TypeError, err) + return nil + } + + return utils.CopyBytesToJS(channelList) +} + //////////////////////////////////////////////////////////////////////////////// // Channel Share URL // //////////////////////////////////////////////////////////////////////////////// @@ -870,50 +856,6 @@ func (cm *ChannelsManager) SendGeneric(_ js.Value, args []js.Value) any { return utils.CreatePromise(promiseFn) } -// SendAdminGeneric is used to send a raw message over a channel encrypted with -// admin keys, identifying it as sent by the admin. In general, it should be -// wrapped in a function that defines the wire protocol. If the final message, -// before being sent over the wire, is too long, this will return an error. The -// message must be at most 510 bytes long. -// -// Parameters: -// - args[0] - The PEM-encode admin RSA private key (Uint8Array). -// - args[1] - Marshalled bytes of the channel [id.ID] (Uint8Array). -// - args[2] - The message type of the message. This will be a valid -// [channels.MessageType] (int). -// - args[3] - The contents of the message (Uint8Array). -// - args[4] - The lease of the message. This will be how long the message is -// valid until, in milliseconds. As per the [channels.Manager] -// documentation, this has different meanings depending on the use case. -// These use cases may be generic enough that they will not be enumerated -// here (int). -// - args[5] - JSON of [xxdk.CMIXParams]. If left empty -// [bindings.GetDefaultCMixParams] will be used internally (Uint8Array). -// -// Returns a promise: -// - Resolves to the JSON of [bindings.ChannelSendReport] (Uint8Array). -// - Rejected with an error if sending fails. -func (cm *ChannelsManager) SendAdminGeneric(_ js.Value, args []js.Value) any { - adminPrivateKey := utils.CopyBytesToGo(args[0]) - marshalledChanId := utils.CopyBytesToGo(args[1]) - messageType := args[2].Int() - message := utils.CopyBytesToGo(args[3]) - leaseTimeMS := int64(args[4].Int()) - cmixParamsJSON := utils.CopyBytesToGo(args[5]) - - promiseFn := func(resolve, reject func(args ...any) js.Value) { - sendReport, err := cm.api.SendAdminGeneric(adminPrivateKey, - marshalledChanId, messageType, message, leaseTimeMS, cmixParamsJSON) - if err != nil { - reject(utils.JsTrace(err)) - } else { - resolve(utils.CopyBytesToJS(sendReport)) - } - } - - return utils.CreatePromise(promiseFn) -} - // SendMessage is used to send a formatted message over a channel. // Due to the underlying encoding using compression, it isn't possible to define // the largest payload that can be sent, but it will always be possible to send @@ -1045,38 +987,89 @@ func (cm *ChannelsManager) SendReaction(_ js.Value, args []js.Value) any { return utils.CreatePromise(promiseFn) } +//////////////////////////////////////////////////////////////////////////////// +// Admin Sending // +//////////////////////////////////////////////////////////////////////////////// + +// SendAdminGeneric is used to send a raw message over a channel encrypted with +// admin keys, identifying it as sent by the admin. In general, it should be +// wrapped in a function that defines the wire protocol. +// +// If the final message, before being sent over the wire, is too long, this will +// return an error. The message must be at most 510 bytes long. +// +// If the user is not an admin of the channel (i.e. does not have a private key +// for the channel saved to storage), then the error [channels.NotAnAdminErr] is +// returned. +// +// Parameters: +// - args[0] - Marshalled bytes of the channel [id.ID] (Uint8Array). +// - args[1] - The message type of the message. This will be a valid +// [channels.MessageType] (int). +// - args[2] - The contents of the message (Uint8Array). The message should be +// at most 510 bytes. +// - args[3] - The lease of the message. This will be how long the message is +// valid until, in milliseconds. As per the [channels.Manager] +// documentation, this has different meanings depending on the use case. +// These use cases may be generic enough that they will not be enumerated +// here (int). +// - args[4] - JSON of [xxdk.CMIXParams]. If left empty +// [bindings.GetDefaultCMixParams] will be used internally (Uint8Array). +// +// Returns a promise: +// - Resolves to the JSON of [bindings.ChannelSendReport] (Uint8Array). +// - Rejected with an error if sending fails. +func (cm *ChannelsManager) SendAdminGeneric(_ js.Value, args []js.Value) any { + marshalledChanId := utils.CopyBytesToGo(args[0]) + messageType := args[1].Int() + message := utils.CopyBytesToGo(args[2]) + leaseTimeMS := int64(args[3].Int()) + cmixParamsJSON := utils.CopyBytesToGo(args[4]) + + promiseFn := func(resolve, reject func(args ...any) js.Value) { + sendReport, err := cm.api.SendAdminGeneric( + marshalledChanId, messageType, message, leaseTimeMS, cmixParamsJSON) + if err != nil { + reject(utils.JsTrace(err)) + } else { + resolve(utils.CopyBytesToJS(sendReport)) + } + } + + return utils.CreatePromise(promiseFn) +} + // DeleteMessage deletes the targeted message from user's view. Users may delete -// their own messages (by leaving the private key as nil) but only the channel -// admin can delete other user's messages. +// their own messages but only the channel admin can delete other user's +// messages. If the user is not an admin of the channel or if they are not the +// sender of the targetMessage, then the error [channels.NotAnAdminErr] is +// returned. // // If undoAction is true, then the targeted message is un-deleted. // -// Clients will drop the deletion if they do not recognize the target message. +// Clients will drop the deletion if they do not recognize the target +// message. // // Parameters: -// - args[0] - The PEM-encoded admin RSA private key for the channel -// (Uint8Array). If a user is trying to delete their own message, make this -// empty. -// - args[1] - Marshalled bytes of channel [id.ID] (Uint8Array). -// - args[2] - The marshalled [channel.MessageID] of the message you want to +// - args[0] - Marshalled bytes of channel [id.ID] (Uint8Array). +// - args[1] - The marshalled [channel.MessageID] of the message you want to // delete (Uint8Array). -// - args[3] - Set to true to un-delete the message (boolean). -// - args[4] - JSON of [xxdk.CMIXParams]. This may be empty, and +// - args[2] - Set to true to un-delete the message (boolean). +// - args[3] - JSON of [xxdk.CMIXParams]. This may be empty, and // [GetDefaultCMixParams] will be used internally (Uint8Array). // // Returns: // - Resolves to the JSON of [bindings.ChannelSendReport] (Uint8Array). // - Rejected with an error if sending fails. func (cm *ChannelsManager) DeleteMessage(_ js.Value, args []js.Value) any { - adminPrivateKey := utils.CopyBytesToGo(args[0]) - channelIdBytes := utils.CopyBytesToGo(args[1]) - targetMessageIdBytes := utils.CopyBytesToGo(args[2]) - undoAction := args[3].Bool() - cmixParamsJSON := utils.CopyBytesToGo(args[4]) + channelIdBytes := utils.CopyBytesToGo(args[0]) + targetMessageIdBytes := utils.CopyBytesToGo(args[1]) + undoAction := args[2].Bool() + cmixParamsJSON := utils.CopyBytesToGo(args[3]) promiseFn := func(resolve, reject func(args ...any) js.Value) { - sendReport, err := cm.api.DeleteMessage(adminPrivateKey, channelIdBytes, - targetMessageIdBytes, undoAction, cmixParamsJSON) + sendReport, err := cm.api.DeleteMessage( + channelIdBytes, targetMessageIdBytes, undoAction, cmixParamsJSON) if err != nil { reject(utils.JsTrace(err)) } else { @@ -1087,35 +1080,35 @@ func (cm *ChannelsManager) DeleteMessage(_ js.Value, args []js.Value) any { return utils.CreatePromise(promiseFn) } -// PinMessage pins the target message to the top of a channel view for all users -// in the specified channel. Only the channel admin can pin user messages. +// PinMessage pins the target message to the top of a channel view for all +// users in the specified channel. Only the channel admin can pin user +// messages; if the user is not an admin of the channel, then the error +// [channels.NotAnAdminErr] is returned. // // If undoAction is true, then the targeted message is unpinned. // // Clients will drop the pin if they do not recognize the target message. // // Parameters: -// - args[0] - The PEM-encoded admin RSA private key for the channel -// (Uint8Array). -// - args[1] - Marshalled bytes of channel [id.ID] (Uint8Array). -// - args[2] - The marshalled [channel.MessageID] of the message you want to +// - args[0] - Marshalled bytes of channel [id.ID] (Uint8Array). +// - args[1] - The marshalled [channel.MessageID] of the message you want to // pin (Uint8Array). -// - args[3] - Set to true to unpin the message (boolean). -// - args[4] - JSON of [xxdk.CMIXParams]. This may be empty, and +// - args[2] - Set to true to unpin the message (boolean). +// - args[3] - JSON of [xxdk.CMIXParams]. This may be empty, and // [GetDefaultCMixParams] will be used internally (Uint8Array). // // Returns: -// - []byte - JSON of [ChannelSendReport]. +// - Resolves to the JSON of [bindings.ChannelSendReport] (Uint8Array). +// - Rejected with an error if sending fails. func (cm *ChannelsManager) PinMessage(_ js.Value, args []js.Value) any { - adminPrivateKey := utils.CopyBytesToGo(args[0]) - channelIdBytes := utils.CopyBytesToGo(args[1]) - targetMessageIdBytes := utils.CopyBytesToGo(args[2]) - undoAction := args[3].Bool() - cmixParamsJSON := utils.CopyBytesToGo(args[4]) + channelIdBytes := utils.CopyBytesToGo(args[0]) + targetMessageIdBytes := utils.CopyBytesToGo(args[1]) + undoAction := args[2].Bool() + cmixParamsJSON := utils.CopyBytesToGo(args[3]) promiseFn := func(resolve, reject func(args ...any) js.Value) { - sendReport, err := cm.api.PinMessage(adminPrivateKey, channelIdBytes, - targetMessageIdBytes, undoAction, cmixParamsJSON) + sendReport, err := cm.api.PinMessage( + channelIdBytes, targetMessageIdBytes, undoAction, cmixParamsJSON) if err != nil { reject(utils.JsTrace(err)) } else { @@ -1128,32 +1121,32 @@ func (cm *ChannelsManager) PinMessage(_ js.Value, args []js.Value) any { // MuteUser is used to mute a user in a channel. Muting a user will cause all // future messages from the user being hidden from view. Muted users are also -// unable to send messages. Only the channel admin can mute a user. +// unable to send messages. Only the channel admin can mute a user; if the user +// is not an admin of the channel, then the error [channels.NotAnAdminErr] is +// returned. // // If undoAction is true, then the targeted user will be unmuted. // // Parameters: -// - args[0] - The PEM-encoded admin RSA private key for the channel +// - args[0] - Marshalled bytes of channel [id.ID] (Uint8Array). +// - args[1] - The [ed25519.PublicKey] of the user you want to mute // (Uint8Array). -// - args[1] - Marshalled bytes of channel [id.ID] (Uint8Array). -// - mutedUserPubKeyBytes - The [ed25519.PublicKey] of the user you want to -// mute. -// - args[3] - Set to true to unmute the message (boolean). -// - args[4] - JSON of [xxdk.CMIXParams]. This may be empty, and +// - args[2] - Set to true to unmute the message (boolean). +// - args[3] - JSON of [xxdk.CMIXParams]. This may be empty, and // [GetDefaultCMixParams] will be used internally (Uint8Array). // // Returns: -// - []byte - JSON of [ChannelSendReport]. +// - Resolves to the JSON of [bindings.ChannelSendReport] (Uint8Array). +// - Rejected with an error if sending fails. func (cm *ChannelsManager) MuteUser(_ js.Value, args []js.Value) any { - adminPrivateKey := utils.CopyBytesToGo(args[0]) - channelIdBytes := utils.CopyBytesToGo(args[1]) - mutedUserPubKeyBytes := utils.CopyBytesToGo(args[2]) - undoAction := args[3].Bool() - cmixParamsJSON := utils.CopyBytesToGo(args[4]) + channelIdBytes := utils.CopyBytesToGo(args[0]) + mutedUserPubKeyBytes := utils.CopyBytesToGo(args[1]) + undoAction := args[2].Bool() + cmixParamsJSON := utils.CopyBytesToGo(args[3]) promiseFn := func(resolve, reject func(args ...any) js.Value) { - sendReport, err := cm.api.MuteUser(adminPrivateKey, channelIdBytes, - mutedUserPubKeyBytes, undoAction, cmixParamsJSON) + sendReport, err := cm.api.MuteUser( + channelIdBytes, mutedUserPubKeyBytes, undoAction, cmixParamsJSON) if err != nil { reject(utils.JsTrace(err)) } else { @@ -1164,6 +1157,10 @@ func (cm *ChannelsManager) MuteUser(_ js.Value, args []js.Value) any { return utils.CreatePromise(promiseFn) } +//////////////////////////////////////////////////////////////////////////////// +// Other Channel Actions // +//////////////////////////////////////////////////////////////////////////////// + // GetIdentity returns the marshaled public identity ([channel.Identity]) that // the channel is using. // @@ -1500,6 +1497,28 @@ func (cm *ChannelsManager) RegisterReceiveHandler(_ js.Value, args []js.Value) a // Event Model Logic // //////////////////////////////////////////////////////////////////////////////// +// eventModelBuilder adheres to the [bindings.EventModelBuilder] interface. +type eventModelBuilder struct { + build func(args ...any) js.Value +} + +// Build initializes and returns the event model. It wraps a Javascript object +// that has all the methods in [bindings.EventModel] to make it adhere to the Go +// interface [bindings.EventModel]. +func (emb *eventModelBuilder) Build(path string) bindings.EventModel { + emJs := emb.build(path) + return &eventModel{ + joinChannel: utils.WrapCB(emJs, "JoinChannel"), + leaveChannel: utils.WrapCB(emJs, "LeaveChannel"), + receiveMessage: utils.WrapCB(emJs, "ReceiveMessage"), + receiveReply: utils.WrapCB(emJs, "ReceiveReply"), + receiveReaction: utils.WrapCB(emJs, "ReceiveReaction"), + updateFromUUID: utils.WrapCB(emJs, "UpdateFromUUID"), + updateFromMessageID: utils.WrapCB(emJs, "UpdateFromMessageID"), + getMessage: utils.WrapCB(emJs, "GetMessage"), + } +} + // eventModel wraps Javascript callbacks to adhere to the [bindings.EventModel] // interface. type eventModel struct { @@ -1862,8 +1881,7 @@ func (c *ChannelDbCipher) MarshalJSON(js.Value, []js.Value) any { return utils.CopyBytesToJS(data) } -// UnmarshalJSON unmarshalls JSON into the cipher. This function adheres to the -// json.Unmarshaler interface. +// 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. diff --git a/wasm/docs.go b/wasm/docs.go index 33b0d56e..5e0466b5 100644 --- a/wasm/docs.go +++ b/wasm/docs.go @@ -10,6 +10,7 @@ package wasm import ( + "crypto/ed25519" "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/client/v4/auth" "gitlab.com/elixxir/client/v4/catalog" @@ -67,4 +68,5 @@ var ( _ = broadcast.PrivacyLevel(0) _ = broadcast.Channel{} _ = netTime.Now + _ = ed25519.PublicKey{} ) -- GitLab