Check owner, member and author prior handling (#283)
* check owner, member and author * fix isOwner
This commit is contained in:
parent
cb88ee7a62
commit
0a30fe0cf6
|
@ -25,6 +25,7 @@ export type ChatMessage = ChatMessageProto & {
|
||||||
pinned: boolean
|
pinned: boolean
|
||||||
reactions: Reactions
|
reactions: Reactions
|
||||||
chatUuid: string
|
chatUuid: string
|
||||||
|
signer: string
|
||||||
responseToMessage?: Omit<ChatMessage, 'responseToMessage'>
|
responseToMessage?: Omit<ChatMessage, 'responseToMessage'>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,7 +216,11 @@ export class Chat {
|
||||||
this.emitMessages(this.messages)
|
this.emitMessages(this.messages)
|
||||||
}
|
}
|
||||||
|
|
||||||
public handleEditedMessage = (messageId: string, text: string) => {
|
public handleEditedMessage = (
|
||||||
|
messageId: string,
|
||||||
|
text: string,
|
||||||
|
signerPublicKey: string
|
||||||
|
) => {
|
||||||
let messageIndex = this.messages.length
|
let messageIndex = this.messages.length
|
||||||
while (--messageIndex >= 0) {
|
while (--messageIndex >= 0) {
|
||||||
const _message = this.messages[messageIndex]
|
const _message = this.messages[messageIndex]
|
||||||
|
@ -230,6 +235,10 @@ export class Chat {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this.isAuthor(this.messages[messageIndex], signerPublicKey)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
this.messages[messageIndex] = {
|
this.messages[messageIndex] = {
|
||||||
...this.messages[messageIndex],
|
...this.messages[messageIndex],
|
||||||
text,
|
text,
|
||||||
|
@ -239,7 +248,10 @@ export class Chat {
|
||||||
this.emitMessages(this.messages)
|
this.emitMessages(this.messages)
|
||||||
}
|
}
|
||||||
|
|
||||||
public handleDeletedMessage = (messageId: string) => {
|
public handleDeletedMessage = (
|
||||||
|
messageId: string,
|
||||||
|
signerPublicKey: string
|
||||||
|
) => {
|
||||||
let messageIndex = this.messages.length
|
let messageIndex = this.messages.length
|
||||||
while (--messageIndex >= 0) {
|
while (--messageIndex >= 0) {
|
||||||
const _message = this.messages[messageIndex]
|
const _message = this.messages[messageIndex]
|
||||||
|
@ -253,6 +265,10 @@ export class Chat {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this.isAuthor(this.messages[messageIndex], signerPublicKey)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
this.messages.splice(messageIndex, 1)
|
this.messages.splice(messageIndex, 1)
|
||||||
|
|
||||||
this.emitMessages(this.messages)
|
this.emitMessages(this.messages)
|
||||||
|
@ -380,7 +396,31 @@ export class Chat {
|
||||||
}
|
}
|
||||||
|
|
||||||
public editMessage = async (messageId: string, text: string) => {
|
public editMessage = async (messageId: string, text: string) => {
|
||||||
// todo?: check if message exists
|
if (!this.client.account) {
|
||||||
|
throw new Error('Text message cannot be edited without a created account')
|
||||||
|
}
|
||||||
|
|
||||||
|
let messageIndex = this.messages.length
|
||||||
|
while (--messageIndex >= 0) {
|
||||||
|
const _message = this.messages[messageIndex]
|
||||||
|
|
||||||
|
if (_message.messageId === messageId) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (messageIndex < 0) {
|
||||||
|
throw new Error('Text message was not found')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
!this.isAuthor(
|
||||||
|
this.messages[messageIndex],
|
||||||
|
`0x${this.client.account.publicKey}`
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
throw new Error('Text message can only be edited by its author')
|
||||||
|
}
|
||||||
|
|
||||||
if (text === '') {
|
if (text === '') {
|
||||||
throw new Error('Text message cannot be empty')
|
throw new Error('Text message cannot be empty')
|
||||||
|
@ -404,7 +444,33 @@ export class Chat {
|
||||||
}
|
}
|
||||||
|
|
||||||
public deleteMessage = async (messageId: string) => {
|
public deleteMessage = async (messageId: string) => {
|
||||||
// todo: check if message exists
|
if (!this.client.account) {
|
||||||
|
throw new Error(
|
||||||
|
'Text message cannot be deleted without a created account'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
let messageIndex = this.messages.length
|
||||||
|
while (--messageIndex >= 0) {
|
||||||
|
const _message = this.messages[messageIndex]
|
||||||
|
|
||||||
|
if (_message.messageId === messageId) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (messageIndex < 0) {
|
||||||
|
throw new Error('Text message was not found')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
!this.isAuthor(
|
||||||
|
this.messages[messageIndex],
|
||||||
|
`0x${this.client.account.publicKey}`
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
throw new Error('Text message can only be deleted by its author')
|
||||||
|
}
|
||||||
|
|
||||||
const payload = DeleteMessage.encode({
|
const payload = DeleteMessage.encode({
|
||||||
clock: BigInt(Date.now()),
|
clock: BigInt(Date.now()),
|
||||||
|
@ -457,4 +523,11 @@ export class Chat {
|
||||||
this.symmetricKey
|
this.symmetricKey
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public isAuthor = (
|
||||||
|
message: ChatMessage,
|
||||||
|
signerPublicKey: string
|
||||||
|
): boolean => {
|
||||||
|
return message.signer === signerPublicKey
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { CommunityRequestToJoin } from '~/protos/communities'
|
||||||
import { MessageType } from '~/protos/enums'
|
import { MessageType } from '~/protos/enums'
|
||||||
import { getDifferenceByKeys } from '~/src/helpers/get-difference-by-keys'
|
import { getDifferenceByKeys } from '~/src/helpers/get-difference-by-keys'
|
||||||
import { getObjectsDifference } from '~/src/helpers/get-objects-difference'
|
import { getObjectsDifference } from '~/src/helpers/get-objects-difference'
|
||||||
|
import { compressPublicKey } from '~/src/utils/compress-public-key'
|
||||||
|
|
||||||
import { idToContentTopic } from '../../contentTopic'
|
import { idToContentTopic } from '../../contentTopic'
|
||||||
import { createSymKeyFromPassword } from '../../encryption'
|
import { createSymKeyFromPassword } from '../../encryption'
|
||||||
|
@ -20,6 +21,7 @@ import type {
|
||||||
export class Community {
|
export class Community {
|
||||||
private client: Client
|
private client: Client
|
||||||
|
|
||||||
|
/** Compressed. */
|
||||||
public publicKey: string
|
public publicKey: string
|
||||||
public id: string
|
public id: string
|
||||||
private contentTopic!: string
|
private contentTopic!: string
|
||||||
|
@ -254,4 +256,15 @@ export class Community {
|
||||||
this.symmetricKey
|
this.symmetricKey
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public isOwner = (
|
||||||
|
/** Uncompressed. */
|
||||||
|
signerPublicKey: string
|
||||||
|
): boolean => {
|
||||||
|
return this.publicKey === `0x${compressPublicKey(signerPublicKey)}`
|
||||||
|
}
|
||||||
|
|
||||||
|
public isMember = (signerPublicKey: string): boolean => {
|
||||||
|
return this.getMember(signerPublicKey) !== undefined
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,15 +52,16 @@ export function handleWakuMessage(
|
||||||
}
|
}
|
||||||
messageToDecode = decodedMetadata.payload
|
messageToDecode = decodedMetadata.payload
|
||||||
|
|
||||||
const publicKey = recoverPublicKey(
|
const signerPublicKeyBytes = recoverPublicKey(
|
||||||
decodedMetadata.signature,
|
decodedMetadata.signature,
|
||||||
decodedMetadata.payload
|
decodedMetadata.payload
|
||||||
)
|
)
|
||||||
|
|
||||||
const messageId = payloadToId(
|
const messageId = payloadToId(
|
||||||
decodedProtocol?.publicMessage ?? wakuMessage.payload,
|
decodedProtocol?.publicMessage ?? wakuMessage.payload,
|
||||||
publicKey
|
signerPublicKeyBytes
|
||||||
)
|
)
|
||||||
|
const signerPublicKey = `0x${bytesToHex(signerPublicKeyBytes)}`
|
||||||
|
|
||||||
// already handled
|
// already handled
|
||||||
if (client.wakuMessages.has(messageId)) {
|
if (client.wakuMessages.has(messageId)) {
|
||||||
|
@ -76,6 +77,10 @@ export function handleWakuMessage(
|
||||||
// decode
|
// decode
|
||||||
const decodedPayload = CommunityDescription.decode(messageToDecode)
|
const decodedPayload = CommunityDescription.decode(messageToDecode)
|
||||||
|
|
||||||
|
if (!community.isOwner(signerPublicKey)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// handle (state and callback)
|
// handle (state and callback)
|
||||||
community.handleDescription(decodedPayload)
|
community.handleDescription(decodedPayload)
|
||||||
|
|
||||||
|
@ -88,16 +93,26 @@ export function handleWakuMessage(
|
||||||
|
|
||||||
switch (decodedPayload.messageType) {
|
switch (decodedPayload.messageType) {
|
||||||
case MessageType.COMMUNITY_CHAT: {
|
case MessageType.COMMUNITY_CHAT: {
|
||||||
|
if (!community.isMember(signerPublicKey)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const chatUuid = getChatUuid(decodedPayload.chatId)
|
const chatUuid = getChatUuid(decodedPayload.chatId)
|
||||||
|
const chat = community.chats.get(chatUuid)
|
||||||
|
|
||||||
|
if (!chat) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// map
|
// map
|
||||||
const chatMessage = mapChatMessage(decodedPayload, {
|
const chatMessage = mapChatMessage(decodedPayload, {
|
||||||
messageId,
|
messageId,
|
||||||
chatUuid,
|
chatUuid,
|
||||||
|
signerPublicKey,
|
||||||
})
|
})
|
||||||
|
|
||||||
// handle
|
// handle
|
||||||
community.chats.get(chatUuid)?.handleNewMessage(chatMessage)
|
chat.handleNewMessage(chatMessage)
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -115,12 +130,23 @@ export function handleWakuMessage(
|
||||||
|
|
||||||
switch (decodedPayload.messageType) {
|
switch (decodedPayload.messageType) {
|
||||||
case MessageType.COMMUNITY_CHAT: {
|
case MessageType.COMMUNITY_CHAT: {
|
||||||
|
if (!community.isMember(signerPublicKey)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const messageId = decodedPayload.messageId
|
const messageId = decodedPayload.messageId
|
||||||
const chatUuid = getChatUuid(decodedPayload.chatId)
|
const chatUuid = getChatUuid(decodedPayload.chatId)
|
||||||
|
const chat = community.chats.get(chatUuid)
|
||||||
|
|
||||||
community.chats
|
if (!chat) {
|
||||||
.get(chatUuid)
|
return
|
||||||
?.handleEditedMessage(messageId, decodedPayload.text)
|
}
|
||||||
|
|
||||||
|
chat.handleEditedMessage(
|
||||||
|
messageId,
|
||||||
|
decodedPayload.text,
|
||||||
|
signerPublicKey
|
||||||
|
)
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -138,10 +164,19 @@ export function handleWakuMessage(
|
||||||
|
|
||||||
switch (decodedPayload.messageType) {
|
switch (decodedPayload.messageType) {
|
||||||
case MessageType.COMMUNITY_CHAT: {
|
case MessageType.COMMUNITY_CHAT: {
|
||||||
|
if (!community.isMember(signerPublicKey)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const messageId = decodedPayload.messageId
|
const messageId = decodedPayload.messageId
|
||||||
const chatUuid = getChatUuid(decodedPayload.chatId)
|
const chatUuid = getChatUuid(decodedPayload.chatId)
|
||||||
|
const chat = community.chats.get(chatUuid)
|
||||||
|
|
||||||
community.chats.get(chatUuid)?.handleDeletedMessage(messageId)
|
if (!chat) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
chat.handleDeletedMessage(messageId, signerPublicKey)
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -159,12 +194,19 @@ export function handleWakuMessage(
|
||||||
|
|
||||||
switch (decodedPayload.messageType) {
|
switch (decodedPayload.messageType) {
|
||||||
case MessageType.COMMUNITY_CHAT: {
|
case MessageType.COMMUNITY_CHAT: {
|
||||||
|
if (!community.isMember(signerPublicKey)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const messageId = decodedPayload.messageId
|
const messageId = decodedPayload.messageId
|
||||||
const chatUuid = getChatUuid(decodedPayload.chatId)
|
const chatUuid = getChatUuid(decodedPayload.chatId)
|
||||||
|
const chat = community.chats.get(chatUuid)
|
||||||
|
|
||||||
community.chats
|
if (!chat) {
|
||||||
.get(chatUuid)
|
return
|
||||||
?.handlePinnedMessage(messageId, decodedPayload.pinned)
|
}
|
||||||
|
|
||||||
|
chat.handlePinnedMessage(messageId, decodedPayload.pinned)
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -182,16 +224,19 @@ export function handleWakuMessage(
|
||||||
|
|
||||||
switch (decodedPayload.messageType) {
|
switch (decodedPayload.messageType) {
|
||||||
case MessageType.COMMUNITY_CHAT: {
|
case MessageType.COMMUNITY_CHAT: {
|
||||||
|
if (!community.isMember(signerPublicKey)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const messageId = decodedPayload.messageId
|
const messageId = decodedPayload.messageId
|
||||||
const chatUuid = getChatUuid(decodedPayload.chatId)
|
const chatUuid = getChatUuid(decodedPayload.chatId)
|
||||||
|
|
||||||
const chat = community.chats.get(chatUuid)
|
const chat = community.chats.get(chatUuid)
|
||||||
|
|
||||||
chat?.handleEmojiReaction(
|
if (!chat) {
|
||||||
messageId,
|
return
|
||||||
decodedPayload,
|
}
|
||||||
`0x${bytesToHex(publicKey)}`
|
|
||||||
)
|
chat.handleEmojiReaction(messageId, decodedPayload, signerPublicKey)
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,17 +6,17 @@ export function mapChatMessage(
|
||||||
props: {
|
props: {
|
||||||
messageId: string
|
messageId: string
|
||||||
chatUuid: string
|
chatUuid: string
|
||||||
publicKey: string
|
signerPublicKey: string
|
||||||
}
|
}
|
||||||
): ChatMessage {
|
): ChatMessage {
|
||||||
const { messageId, chatUuid, publicKey } = props
|
const { messageId, chatUuid, signerPublicKey } = props
|
||||||
|
|
||||||
const message = {
|
const message: ChatMessage = {
|
||||||
...decodedMessage,
|
...decodedMessage,
|
||||||
messageId,
|
messageId,
|
||||||
chatUuid,
|
chatUuid,
|
||||||
pinned: false,
|
pinned: false,
|
||||||
signer: publicKey,
|
signer: signerPublicKey,
|
||||||
reactions: {
|
reactions: {
|
||||||
THUMBS_UP: new Set<string>(),
|
THUMBS_UP: new Set<string>(),
|
||||||
THUMBS_DOWN: new Set<string>(),
|
THUMBS_DOWN: new Set<string>(),
|
||||||
|
|
Loading…
Reference in New Issue