Skip to content
Snippets Groups Projects
Commit 04b0ed0d authored by Jono Wenger's avatar Jono Wenger
Browse files

XX-4333 / Mute User

parent a309da16
No related branches found
No related tags found
3 merge requests!60Revert "Fail a test to be sure it works",!33XX-4333 / Mute User,!32Admin Commands
......@@ -7,10 +7,10 @@ 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.20221121234059-3f75d507e3c8
gitlab.com/elixxir/client v1.5.1-0.20221122004847-08fb6e6d3c0e
gitlab.com/elixxir/crypto v0.0.7-0.20221121233335-83f145891bc7
gitlab.com/elixxir/primitives v0.0.3-0.20221110181119-e83320a48b13
gitlab.com/xx_network/crypto v0.0.5-0.20221110181048-76f0c556fe95
gitlab.com/elixxir/primitives v0.0.3-0.20221114231218-cc461261a6af
gitlab.com/xx_network/crypto v0.0.5-0.20221121220724-8eefdbb0eb46
gitlab.com/xx_network/primitives v0.0.4-0.20221110180011-fd6ea3058225
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa
)
......
......@@ -368,20 +368,20 @@ 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.20221121234059-3f75d507e3c8 h1:DWzodsczpQh9Y5415grILfP/xd0ol0mKczUyTJ5Gp0k=
gitlab.com/elixxir/client v1.5.1-0.20221121234059-3f75d507e3c8/go.mod h1:ZUvPwnyqsvQaiZCkWKb4coWa5nwv6XxRthV/64rZK4s=
gitlab.com/elixxir/client v1.5.1-0.20221122004847-08fb6e6d3c0e h1:HZuKqQqgwKjXzMVY3/n0nlAd/+0aFRvJKD4/LIrNEew=
gitlab.com/elixxir/client v1.5.1-0.20221122004847-08fb6e6d3c0e/go.mod h1:ZUvPwnyqsvQaiZCkWKb4coWa5nwv6XxRthV/64rZK4s=
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.20221121233335-83f145891bc7 h1:yhc8jQ27JKypdRE41NpfJPaYRS0sNkOwugaIyoscDiU=
gitlab.com/elixxir/crypto v0.0.7-0.20221121233335-83f145891bc7/go.mod h1:oRh3AwveOEvpk9E3kRcMGK8fImcEnN0PY4jr9HDgQE8=
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.3-0.20221110181119-e83320a48b13 h1:U3tbClFN5BLYlAoMj+o6VWAs9akbFiJstMGCuk1aB94=
gitlab.com/elixxir/primitives v0.0.3-0.20221110181119-e83320a48b13/go.mod h1:DUnCTXYKgjpro5+6ITySKIf+qzW2vhW40IVHMimdsqw=
gitlab.com/elixxir/primitives v0.0.3-0.20221114231218-cc461261a6af h1:xcPqknK1ehNb9xwcutTdoR0YgD7DC/ySh9z49tIpSxQ=
gitlab.com/elixxir/primitives v0.0.3-0.20221114231218-cc461261a6af/go.mod h1:DUnCTXYKgjpro5+6ITySKIf+qzW2vhW40IVHMimdsqw=
gitlab.com/xx_network/comms v0.0.4-0.20221110181111-4f0694876936 h1:eQQ4zUvGWIzCWdBJ6qlysWUMwrc2tM8GripFqdT1SAs=
gitlab.com/xx_network/comms v0.0.4-0.20221110181111-4f0694876936/go.mod h1:+RfHgk75ywMvmucOpPS7rSUlsnbPyBuLsr13tsthUTE=
gitlab.com/xx_network/crypto v0.0.5-0.20221110181048-76f0c556fe95 h1:rC6lx6sD6u617Qu0ZndKZQRjXuRkyrI9Q6Y0Ki+dnK4=
gitlab.com/xx_network/crypto v0.0.5-0.20221110181048-76f0c556fe95/go.mod h1:acWUBKCpae/XVaQF7J9RnLAlBT13i5r7gnON+mrIxBk=
gitlab.com/xx_network/crypto v0.0.5-0.20221121220724-8eefdbb0eb46 h1:6AHgUpWdJ72RVTTdJSvfThZiYTQNUnrPaTCl/EkRLpg=
gitlab.com/xx_network/crypto v0.0.5-0.20221121220724-8eefdbb0eb46/go.mod h1:acWUBKCpae/XVaQF7J9RnLAlBT13i5r7gnON+mrIxBk=
gitlab.com/xx_network/primitives v0.0.4-0.20221110180011-fd6ea3058225 h1:TAn87e6Zt9KwcSnWKyIul5eu8T0RHY9FDubCGs3G0dw=
gitlab.com/xx_network/primitives v0.0.4-0.20221110180011-fd6ea3058225/go.mod h1:rP/2IsqIFHapuIB4mstXKItvwoJRQ9Wlms/NGeutHsk=
gitlab.com/xx_network/ring v0.0.3-0.20220902183151-a7d3b15bc981 h1:1s0vX9BbkiD0IVXwr3LOaTBcq1wBrWcUWMBK0s8r0Z0=
......
......@@ -205,7 +205,7 @@ func (w *wasmModel) ReceiveMessage(channelID *id.ID,
messageID cryptoChannel.MessageID, nickname, text string,
pubKey ed25519.PublicKey, codeset uint8,
timestamp time.Time, lease time.Duration, round rounds.Round,
mType channels.MessageType, status channels.SentStatus) uint64 {
mType channels.MessageType, status channels.SentStatus, hidden bool) uint64 {
textBytes := []byte(text)
var err error
......@@ -220,7 +220,8 @@ func (w *wasmModel) ReceiveMessage(channelID *id.ID,
msgToInsert := buildMessage(
channelID.Marshal(), messageID.Bytes(), nil, nickname,
textBytes, pubKey, codeset, timestamp, lease, round.ID, mType, status)
textBytes, pubKey, codeset, timestamp, lease, round.ID, mType,
false, hidden, status)
uuid, err := w.receiveHelper(msgToInsert, false)
if err != nil {
......@@ -241,7 +242,7 @@ func (w *wasmModel) ReceiveReply(channelID *id.ID,
messageID cryptoChannel.MessageID, replyTo cryptoChannel.MessageID,
nickname, text string, pubKey ed25519.PublicKey, codeset uint8,
timestamp time.Time, lease time.Duration, round rounds.Round,
mType channels.MessageType, status channels.SentStatus) uint64 {
mType channels.MessageType, status channels.SentStatus, hidden bool) uint64 {
textBytes := []byte(text)
var err error
......@@ -256,7 +257,7 @@ func (w *wasmModel) ReceiveReply(channelID *id.ID,
msgToInsert := buildMessage(channelID.Marshal(), messageID.Bytes(),
replyTo.Bytes(), nickname, textBytes, pubKey, codeset, timestamp, lease,
round.ID, mType, status)
round.ID, mType, false, hidden, status)
uuid, err := w.receiveHelper(msgToInsert, false)
......@@ -277,7 +278,7 @@ func (w *wasmModel) ReceiveReaction(channelID *id.ID,
messageID cryptoChannel.MessageID, reactionTo cryptoChannel.MessageID,
nickname, reaction string, pubKey ed25519.PublicKey, codeset uint8,
timestamp time.Time, lease time.Duration, round rounds.Round,
mType channels.MessageType, status channels.SentStatus) uint64 {
mType channels.MessageType, status channels.SentStatus, hidden bool) uint64 {
textBytes := []byte(reaction)
var err error
......@@ -292,7 +293,8 @@ func (w *wasmModel) ReceiveReaction(channelID *id.ID,
msgToInsert := buildMessage(
channelID.Marshal(), messageID.Bytes(), reactionTo.Bytes(), nickname,
textBytes, pubKey, codeset, timestamp, lease, round.ID, mType, status)
textBytes, pubKey, codeset, timestamp, lease, round.ID, mType,
false, hidden, status)
uuid, err := w.receiveHelper(msgToInsert, false)
if err != nil {
......@@ -302,15 +304,52 @@ func (w *wasmModel) ReceiveReaction(channelID *id.ID,
return uuid
}
// UpdateSentStatus is called whenever the [channels.SentStatus] of a message
// has changed. At this point the message ID goes from empty/unknown to
// populated.
// UpdateFromMessageID is called whenever a message with the message ID is
// modified.
//
// TODO: Potential race condition due to separate get/update operations.
func (w *wasmModel) UpdateSentStatus(uuid uint64,
messageID cryptoChannel.MessageID, timestamp time.Time, round rounds.Round,
status channels.SentStatus) {
parentErr := errors.New("failed to UpdateSentStatus")
// The API needs to return the UUID of the modified message that can be
// referenced at a later time.
//
// timestamp, round, pinned, and hidden are all nillable and may be updated
// based upon the UUID at a later date. If a nil value is passed, then make
// no update.
func (w *wasmModel) UpdateFromMessageID(messageID cryptoChannel.MessageID,
timestamp *time.Time, round *rounds.Round, pinned, hidden *bool,
status *channels.SentStatus) uint64 {
parentErr := errors.New("failed to UpdateFromMessageID")
// FIXME: this is a bit of race condition without the mux.
// This should be done via the transactions (i.e., make a
// special version of receiveHelper)
w.updateMux.Lock()
defer w.updateMux.Unlock()
msgIDStr := base64.StdEncoding.EncodeToString(messageID.Marshal())
currentMsgObj, err := w.getIndex(messageStoreName,
messageStoreMessageIndex, js.ValueOf(msgIDStr))
if err != nil {
jww.ERROR.Printf("%+v", errors.WithMessagef(parentErr,
"Failed to get message by index: %+v", err))
return 0
}
currentMsg := utils.JsToJson(currentMsgObj)
uuid, err := w.updateMessage(currentMsg, &messageID, timestamp,
round, pinned, hidden, status)
if err != nil {
jww.ERROR.Printf("%+v", errors.WithMessagef(parentErr,
"Unable to updateMessage: %+v", err))
}
return uuid
}
// messageID, timestamp, round, pinned, and hidden are all nillable and may
// be updated based upon the UUID at a later date. If a nil value is passed,
// then make no update.
func (w *wasmModel) UpdateFromUUID(uuid uint64, messageID *cryptoChannel.MessageID,
timestamp *time.Time, round *rounds.Round, pinned, hidden *bool,
status *channels.SentStatus) {
parentErr := errors.New("failed to UpdateFromUUID")
// FIXME: this is a bit of race condition without the mux.
// This should be done via the transactions (i.e., make a
......@@ -324,36 +363,64 @@ func (w *wasmModel) UpdateSentStatus(uuid uint64,
// Use the key to get the existing Message
currentMsg, err := w.get(messageStoreName, key)
if err != nil {
jww.ERROR.Printf("%+v", errors.WithMessagef(parentErr,
"Failed to get message: %+v", err))
return
}
// Extract the existing Message and update the Status
_, err = w.updateMessage(currentMsg, messageID, timestamp,
round, pinned, hidden, status)
if err != nil {
jww.ERROR.Printf("%+v", errors.WithMessagef(parentErr,
"Unable to updateMessage: %+v", err))
}
}
// updateMessage is a helper for updating a stored message.
func (w *wasmModel) updateMessage(currentMsgJson string,
messageID *cryptoChannel.MessageID, timestamp *time.Time,
round *rounds.Round, pinned, hidden *bool,
status *channels.SentStatus) (uint64, error) {
newMessage := &Message{}
err = json.Unmarshal([]byte(currentMsg), newMessage)
err := json.Unmarshal([]byte(currentMsgJson), newMessage)
if err != nil {
return
return 0, nil
}
newMessage.Status = uint8(status)
if !messageID.Equals(cryptoChannel.MessageID{}) {
newMessage.MessageID = messageID.Bytes()
if status != nil {
newMessage.Status = uint8(*status)
}
if messageID != nil {
newMessage.MessageID = messageID.Marshal()
}
if round.ID != 0 {
if round != nil {
newMessage.Round = uint64(round.ID)
}
if !timestamp.Equal(time.Time{}) {
newMessage.Timestamp = timestamp
if timestamp != nil {
newMessage.Timestamp = *timestamp
}
if pinned != nil {
newMessage.Pinned = *pinned
}
if hidden != nil {
newMessage.Hidden = *hidden
}
// Store the updated Message
_, err = w.receiveHelper(newMessage, true)
uuid, err := w.receiveHelper(newMessage, true)
if err != nil {
jww.ERROR.Printf("%+v", errors.Wrap(parentErr, err.Error()))
return 0, err
}
channelID := &id.ID{}
copy(channelID[:], newMessage.ChannelID)
go w.receivedMessageCB(uuid, channelID, true)
return uuid, nil
}
// buildMessage is a private helper that converts typical [channels.EventModel]
......@@ -365,7 +432,7 @@ func (w *wasmModel) UpdateSentStatus(uuid uint64,
func buildMessage(channelID, messageID, parentID []byte, nickname string,
text []byte, pubKey ed25519.PublicKey, codeset uint8, timestamp time.Time,
lease time.Duration, round id.Round, mType channels.MessageType,
status channels.SentStatus) *Message {
pinned, hidden bool, status channels.SentStatus) *Message {
return &Message{
MessageID: messageID,
Nickname: nickname,
......@@ -374,8 +441,8 @@ func buildMessage(channelID, messageID, parentID []byte, nickname string,
Timestamp: timestamp,
Lease: lease,
Status: uint8(status),
Hidden: false,
Pinned: false,
Hidden: hidden,
Pinned: pinned,
Text: text,
Type: uint16(mType),
Round: uint64(round),
......@@ -435,9 +502,9 @@ func (w *wasmModel) receiveHelper(newMessage *Message, isUpdate bool) (uint64,
if res.IsUndefined() {
msgID := cryptoChannel.MessageID{}
copy(msgID[:], newMessage.MessageID)
uuid, errLookup := w.msgIDLookup(msgID)
if uuid != 0 && errLookup == nil {
return uuid, nil
msg, errLookup := w.msgIDLookup(msgID)
if msg.ID != 0 && errLookup == nil {
return msg.ID, nil
}
return 0, errors.Errorf("uuid lookup failure: %+v", err)
}
......@@ -447,6 +514,48 @@ func (w *wasmModel) receiveHelper(newMessage *Message, isUpdate bool) (uint64,
return uuid, nil
}
// GetMessage returns the message with the given [channel.MessageID].
func (w *wasmModel) GetMessage(messageID cryptoChannel.MessageID) (channels.ModelMessage, error) {
lookupResult, err := w.msgIDLookup(messageID)
if err != nil {
return channels.ModelMessage{}, err
}
var channelId *id.ID
if lookupResult.ChannelID != nil {
channelId, err = id.Unmarshal(lookupResult.ChannelID)
if err != nil {
return channels.ModelMessage{}, err
}
}
var parentMsgId cryptoChannel.MessageID
if lookupResult.ParentMessageID != nil {
parentMsgId, err = cryptoChannel.UnmarshalMessageID(lookupResult.ParentMessageID)
if err != nil {
return channels.ModelMessage{}, err
}
}
return channels.ModelMessage{
UUID: lookupResult.ID,
Nickname: lookupResult.Nickname,
MessageID: messageID,
ChannelID: channelId,
ParentMessageID: parentMsgId,
Timestamp: lookupResult.Timestamp,
Lease: lookupResult.Lease,
Status: channels.SentStatus(lookupResult.Status),
Hidden: lookupResult.Hidden,
Pinned: lookupResult.Pinned,
Content: lookupResult.Text,
Type: channels.MessageType(lookupResult.Type),
Round: id.Round(lookupResult.Round),
PubKey: lookupResult.Pubkey,
CodesetVersion: lookupResult.CodesetVersion,
}, nil
}
// get is a generic private helper for getting values from the given
// [idb.ObjectStore].
func (w *wasmModel) get(objectStoreName string, key js.Value) (string, error) {
......@@ -486,54 +595,70 @@ func (w *wasmModel) get(objectStoreName string, key js.Value) (string, error) {
return resultStr, nil
}
func (w *wasmModel) msgIDLookup(messageID cryptoChannel.MessageID) (uint64,
error) {
parentErr := errors.Errorf("failed to get %s/%s", messageStoreName,
messageID)
// getIndex is a generic private helper for getting values from the given
// [idb.ObjectStore] using a [idb.Index].
func (w *wasmModel) getIndex(objectStoreName string,
indexName string, key js.Value) (js.Value, error) {
parentErr := errors.Errorf("failed to getIndex %s/%s/%s",
objectStoreName, indexName, key)
// Prepare the Transaction
txn, err := w.db.Transaction(idb.TransactionReadOnly, messageStoreName)
txn, err := w.db.Transaction(idb.TransactionReadOnly, objectStoreName)
if err != nil {
return 0, errors.WithMessagef(parentErr,
return js.Null(), errors.WithMessagef(parentErr,
"Unable to create Transaction: %+v", err)
}
store, err := txn.ObjectStore(messageStoreName)
store, err := txn.ObjectStore(objectStoreName)
if err != nil {
return 0, errors.WithMessagef(parentErr,
return js.Null(), errors.WithMessagef(parentErr,
"Unable to get ObjectStore: %+v", err)
}
idx, err := store.Index(messageStoreMessageIndex)
idx, err := store.Index(indexName)
if err != nil {
return 0, errors.WithMessagef(parentErr,
return js.Null(), errors.WithMessagef(parentErr,
"Unable to get index: %+v", err)
}
msgIDStr := base64.StdEncoding.EncodeToString(messageID.Bytes())
keyReq, err := idx.Get(js.ValueOf(msgIDStr))
// Perform the operation
getRequest, err := idx.Get(key)
if err != nil {
return 0, errors.WithMessagef(parentErr,
"Unable to get keyReq: %+v", err)
return js.Null(), errors.WithMessagef(parentErr,
"Unable to Get from ObjectStore: %+v", err)
}
// Wait for the operation to return
ctx, cancel := newContext()
keyObj, err := keyReq.Await(ctx)
resultObj, err := getRequest.Await(ctx)
cancel()
if err != nil {
return 0, errors.WithMessagef(parentErr,
return js.Null(), errors.WithMessagef(parentErr,
"Unable to get from ObjectStore: %+v", err)
}
// Process result into string
resultStr := utils.JsToJson(keyObj)
jww.DEBUG.Printf("Index lookup of %s/%s/%s: %s", messageStoreName,
messageStoreMessageIndex, msgIDStr, resultStr)
jww.DEBUG.Printf("Got via index from %s/%s/%s: %s",
objectStoreName, indexName, key, resultObj.String())
return resultObj, nil
}
uuid := uint64(0)
if !keyObj.IsUndefined() {
uuid = uint64(keyObj.Get("id").Int())
func (w *wasmModel) msgIDLookup(messageID cryptoChannel.MessageID) (*Message,
error) {
msgIDStr := base64.StdEncoding.EncodeToString(messageID.Marshal())
keyObj, err := w.getIndex(messageStoreName,
messageStoreMessageIndex, js.ValueOf(msgIDStr))
if err != nil {
return nil, err
} else if keyObj.IsUndefined() {
return nil, errors.Errorf("no message for %s found", msgIDStr)
}
return uuid, nil
// Process result into string
resultMsg := &Message{}
err = json.Unmarshal([]byte(utils.JsToJson(keyObj)), resultMsg)
if err != nil {
return nil, err
}
return resultMsg, nil
}
// dump returns the given [idb.ObjectStore] contents to string slice for
......
......@@ -47,7 +47,7 @@ func Test_wasmModel_UpdateSentStatus(t *testing.T) {
// Store a test message
testMsg := buildMessage([]byte(testString), testMsgId.Bytes(), nil,
testString, []byte(testString), []byte{8, 6, 7, 5}, 0, netTime.Now(),
time.Second, 0, 0, channels.Sent)
time.Second, 0, 0, false, false, channels.Sent)
uuid, err := eventModel.receiveHelper(testMsg, false)
if err != nil {
t.Fatalf("%+v", err)
......@@ -64,8 +64,8 @@ func Test_wasmModel_UpdateSentStatus(t *testing.T) {
// Update the sentStatus
expectedStatus := channels.Failed
eventModel.UpdateSentStatus(uuid, testMsgId, netTime.Now(),
rounds.Round{ID: 8675309}, expectedStatus)
eventModel.UpdateFromUUID(uuid, nil, nil,
nil, nil, nil, &expectedStatus)
// Check the resulting status
results, err = eventModel.dump(messageStoreName)
......@@ -147,7 +147,7 @@ func Test_wasmModel_UUIDTest(t *testing.T) {
rnd := rounds.Round{ID: id.Round(42)}
uuid := eventModel.ReceiveMessage(channelID, msgID, "test",
testString+fmt.Sprintf("%d", i), []byte{8, 6, 7, 5}, 0,
netTime.Now(), time.Hour, rnd, 0, channels.Sent)
netTime.Now(), time.Hour, rnd, 0, channels.Sent, false)
uuids[i] = uuid
}
......@@ -182,7 +182,7 @@ func Test_wasmModel_DuplicateReceives(t *testing.T) {
rnd := rounds.Round{ID: id.Round(42)}
uuid := eventModel.ReceiveMessage(channelID, msgID, "test",
testString+fmt.Sprintf("%d", i), []byte{8, 6, 7, 5}, 0,
netTime.Now(), time.Hour, rnd, 0, channels.Sent)
netTime.Now(), time.Hour, rnd, 0, channels.Sent, false)
uuids[i] = uuid
}
......@@ -226,7 +226,7 @@ func Test_wasmModel_deleteMsgByChannel(t *testing.T) {
testMsgId := channel.MakeMessageID([]byte(testStr), &id.ID{1})
eventModel.ReceiveMessage(thisChannel, testMsgId, testStr, testStr,
[]byte{8, 6, 7, 5}, 0, netTime.Now(), time.Second,
rounds.Round{ID: id.Round(0)}, 0, channels.Sent)
rounds.Round{ID: id.Round(0)}, 0, channels.Sent, false)
}
// Check pre-results
......@@ -286,7 +286,7 @@ func TestWasmModel_receiveHelper_UniqueIndex(t *testing.T) {
testMsgId := channel.MakeMessageID([]byte(testString), &id.ID{1})
testMsg := buildMessage([]byte(testString), testMsgId.Bytes(), nil,
testString, []byte(testString), []byte{8, 6, 7, 5}, 0, netTime.Now(),
time.Second, 0, 0, channels.Sent)
time.Second, 0, 0, false, false, channels.Sent)
_, err = eventModel.receiveHelper(testMsg, false)
if err != nil {
t.Fatal(err)
......@@ -309,7 +309,7 @@ func TestWasmModel_receiveHelper_UniqueIndex(t *testing.T) {
testMsgId2 := channel.MakeMessageID([]byte(testString), &id.ID{2})
testMsg = buildMessage([]byte(testString), testMsgId2.Bytes(), nil,
testString, []byte(testString), []byte{8, 6, 7, 5}, 0, netTime.Now(),
time.Second, 0, 0, channels.Sent)
time.Second, 0, 0, false, false, channels.Sent)
primaryKey, err := eventModel.receiveHelper(testMsg, false)
if err != nil {
t.Fatal(err)
......
......@@ -53,12 +53,16 @@ func newChannelsManagerJS(api *bindings.ChannelsManager) map[string]interface{}
"SendMessage": js.FuncOf(cm.SendMessage),
"SendReply": js.FuncOf(cm.SendReply),
"SendReaction": js.FuncOf(cm.SendReaction),
"DeleteMessage": js.FuncOf(cm.DeleteMessage),
"PinMessage": js.FuncOf(cm.PinMessage),
"MuteUser": js.FuncOf(cm.MuteUser),
"GetIdentity": js.FuncOf(cm.GetIdentity),
"ExportPrivateIdentity": js.FuncOf(cm.ExportPrivateIdentity),
"GetStorageTag": js.FuncOf(cm.GetStorageTag),
"SetNickname": js.FuncOf(cm.SetNickname),
"DeleteNickname": js.FuncOf(cm.DeleteNickname),
"GetNickname": js.FuncOf(cm.GetNickname),
"Muted": js.FuncOf(cm.Muted),
// Channel Receiving Logic and Callback Registration
"RegisterReceiveHandler": js.FuncOf(cm.RegisterReceiveHandler),
......@@ -1105,6 +1109,122 @@ func (ch *ChannelsManager) SendReaction(_ js.Value, args []js.Value) interface{}
return utils.CreatePromise(promiseFn)
}
// DeleteMessage is used to send a reaction to a message over a channel. The
// reaction must be a single emoji with no other characters, and will be
// rejected otherwise.
//
// Users will drop the reaction if they do not recognize the reactTo 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
// delete (Uint8Array).
// - args[3] - Set to true to un-delete the message (boolean).
// - args[4] - 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 (ch *ChannelsManager) DeleteMessage(_ js.Value, args []js.Value) interface{} {
adminPrivateKey := utils.CopyBytesToGo(args[0])
channelIdBytes := utils.CopyBytesToGo(args[1])
targetMessageIdBytes := utils.CopyBytesToGo(args[2])
undoAction := args[3].Bool()
cmixParamsJSON := utils.CopyBytesToGo(args[4])
promiseFn := func(resolve, reject func(args ...interface{}) js.Value) {
sendReport, err := ch.api.DeleteMessage(adminPrivateKey, channelIdBytes,
targetMessageIdBytes, undoAction, cmixParamsJSON)
if err != nil {
reject(utils.JsTrace(err))
} else {
resolve(utils.CopyBytesToJS(sendReport))
}
}
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.
//
// 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
// pin (Uint8Array).
// - args[3] - Set to true to un-delete the message (boolean).
// - args[4] - JSON of [xxdk.CMIXParams]. This may be empty, and
// [GetDefaultCMixParams] will be used internally (Uint8Array).
//
// Returns:
// - []byte - JSON of [ChannelSendReport].
func (ch *ChannelsManager) PinMessage(_ js.Value, args []js.Value) interface{} {
adminPrivateKey := utils.CopyBytesToGo(args[0])
channelIdBytes := utils.CopyBytesToGo(args[1])
targetMessageIdBytes := utils.CopyBytesToGo(args[2])
undoAction := args[3].Bool()
cmixParamsJSON := utils.CopyBytesToGo(args[4])
promiseFn := func(resolve, reject func(args ...interface{}) js.Value) {
sendReport, err := ch.api.PinMessage(adminPrivateKey, channelIdBytes,
targetMessageIdBytes, undoAction, cmixParamsJSON)
if err != nil {
reject(utils.JsTrace(err))
} else {
resolve(utils.CopyBytesToJS(sendReport))
}
}
return utils.CreatePromise(promiseFn)
}
// 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.
//
// If undoAction is true, then the targeted user will be unmuted.
//
// Parameters:
// - args[0] - The PEM-encoded admin RSA private key for the channel
// (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 un-delete the message (boolean).
// - args[4] - JSON of [xxdk.CMIXParams]. This may be empty, and
// [GetDefaultCMixParams] will be used internally (Uint8Array).
//
// Returns:
// - []byte - JSON of [ChannelSendReport].
func (ch *ChannelsManager) MuteUser(_ js.Value, args []js.Value) interface{} {
adminPrivateKey := utils.CopyBytesToGo(args[0])
channelIdBytes := utils.CopyBytesToGo(args[1])
mutedUserPubKeyBytes := utils.CopyBytesToGo(args[2])
undoAction := args[3].Bool()
cmixParamsJSON := utils.CopyBytesToGo(args[4])
promiseFn := func(resolve, reject func(args ...interface{}) js.Value) {
sendReport, err := ch.api.MuteUser(adminPrivateKey, channelIdBytes,
mutedUserPubKeyBytes, undoAction, cmixParamsJSON)
if err != nil {
reject(utils.JsTrace(err))
} else {
resolve(utils.CopyBytesToJS(sendReport))
}
}
return utils.CreatePromise(promiseFn)
}
// GetIdentity returns the marshaled public identity ([channel.Identity]) that
// the channel is using.
//
......@@ -1224,6 +1344,27 @@ func IsNicknameValid(_ js.Value, args []js.Value) interface{} {
return nil
}
// Muted returns true if the user is currently muted in the given channel.
//
// Parameters:
// - args[0] - Marshalled bytes if the channel's [id.ID] (Uint8Array).
//
// Returns:
// - Returns true if the user is muted in the channel and false otherwise
// (boolean).
// - Throws a TypeError if the channel ID cannot be unmarshalled.
func (ch *ChannelsManager) Muted(_ js.Value, args []js.Value) interface{} {
channelIDBytes := utils.CopyBytesToGo(args[0])
muted, err := ch.api.Muted(channelIDBytes)
if err != nil {
utils.Throw(utils.TypeError, err)
return nil
}
return muted
}
////////////////////////////////////////////////////////////////////////////////
// Channel Receiving Logic and Callback Registration //
////////////////////////////////////////////////////////////////////////////////
......@@ -1345,11 +1486,11 @@ func (em *eventModel) LeaveChannel(channelID []byte) {
// later with [eventModel.UpdateSentStatus].
func (em *eventModel) ReceiveMessage(channelID, messageID []byte, nickname,
text string, pubKey []byte, codeset int, timestamp, lease, roundId, msgType,
status int64) int64 {
status int64, hidden bool) int64 {
uuid := em.receiveMessage(utils.CopyBytesToJS(channelID),
utils.CopyBytesToJS(messageID), nickname, text,
utils.CopyBytesToJS(pubKey), codeset, timestamp, lease, roundId,
msgType, status)
msgType, status, hidden)
return int64(uuid.Int())
}
......@@ -1389,11 +1530,11 @@ func (em *eventModel) ReceiveMessage(channelID, messageID []byte, nickname,
// later with [eventModel.UpdateSentStatus].
func (em *eventModel) ReceiveReply(channelID, messageID, reactionTo []byte,
senderUsername, text string, pubKey []byte, codeset int, timestamp, lease,
roundId, msgType, status int64) int64 {
roundId, msgType, status int64, hidden bool) int64 {
uuid := em.receiveReply(utils.CopyBytesToJS(channelID),
utils.CopyBytesToJS(messageID), utils.CopyBytesToJS(reactionTo),
senderUsername, text, utils.CopyBytesToJS(pubKey), codeset,
timestamp, lease, roundId, msgType, status)
timestamp, lease, roundId, msgType, status, hidden)
return int64(uuid.Int())
}
......@@ -1433,11 +1574,11 @@ func (em *eventModel) ReceiveReply(channelID, messageID, reactionTo []byte,
// later with [eventModel.UpdateSentStatus].
func (em *eventModel) ReceiveReaction(channelID, messageID, reactionTo []byte,
senderUsername, reaction string, pubKey []byte, codeset int, timestamp,
lease, roundId, msgType, status int64) int64 {
lease, roundId, msgType, status int64, hidden bool) int64 {
uuid := em.receiveReaction(utils.CopyBytesToJS(channelID),
utils.CopyBytesToJS(messageID), utils.CopyBytesToJS(reactionTo),
senderUsername, reaction, utils.CopyBytesToJS(pubKey), codeset,
timestamp, lease, roundId, msgType, status)
timestamp, lease, roundId, msgType, status, hidden)
return int64(uuid.Int())
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment