Check owner, member and author prior handling (#283)

* check owner, member and author

* fix isOwner
This commit is contained in:
Felicio Mununga 2022-06-22 13:30:24 +02:00 committed by GitHub
parent cb88ee7a62
commit 0a30fe0cf6
No known key found for this signature in database
GPG Key ID: 0EB8D75C775AB6F1
4 changed files with 155 additions and 24 deletions

View File

@ -25,6 +25,7 @@ export type ChatMessage = ChatMessageProto & {
pinned: boolean
reactions: Reactions
chatUuid: string
signer: string
responseToMessage?: Omit<ChatMessage, 'responseToMessage'>
}
@ -215,7 +216,11 @@ export class Chat {
this.emitMessages(this.messages)
}
public handleEditedMessage = (messageId: string, text: string) => {
public handleEditedMessage = (
messageId: string,
text: string,
signerPublicKey: string
) => {
let messageIndex = this.messages.length
while (--messageIndex >= 0) {
const _message = this.messages[messageIndex]
@ -230,6 +235,10 @@ export class Chat {
return
}
if (!this.isAuthor(this.messages[messageIndex], signerPublicKey)) {
return
}
this.messages[messageIndex] = {
...this.messages[messageIndex],
text,
@ -239,7 +248,10 @@ export class Chat {
this.emitMessages(this.messages)
}
public handleDeletedMessage = (messageId: string) => {
public handleDeletedMessage = (
messageId: string,
signerPublicKey: string
) => {
let messageIndex = this.messages.length
while (--messageIndex >= 0) {
const _message = this.messages[messageIndex]
@ -253,6 +265,10 @@ export class Chat {
return
}
if (!this.isAuthor(this.messages[messageIndex], signerPublicKey)) {
return
}
this.messages.splice(messageIndex, 1)
this.emitMessages(this.messages)
@ -380,7 +396,31 @@ export class Chat {
}
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 === '') {
throw new Error('Text message cannot be empty')
@ -404,7 +444,33 @@ export class Chat {
}
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({
clock: BigInt(Date.now()),
@ -457,4 +523,11 @@ export class Chat {
this.symmetricKey
)
}
public isAuthor = (
message: ChatMessage,
signerPublicKey: string
): boolean => {
return message.signer === signerPublicKey
}
}

View File

@ -5,6 +5,7 @@ import { CommunityRequestToJoin } from '~/protos/communities'
import { MessageType } from '~/protos/enums'
import { getDifferenceByKeys } from '~/src/helpers/get-difference-by-keys'
import { getObjectsDifference } from '~/src/helpers/get-objects-difference'
import { compressPublicKey } from '~/src/utils/compress-public-key'
import { idToContentTopic } from '../../contentTopic'
import { createSymKeyFromPassword } from '../../encryption'
@ -20,6 +21,7 @@ import type {
export class Community {
private client: Client
/** Compressed. */
public publicKey: string
public id: string
private contentTopic!: string
@ -254,4 +256,15 @@ export class Community {
this.symmetricKey
)
}
public isOwner = (
/** Uncompressed. */
signerPublicKey: string
): boolean => {
return this.publicKey === `0x${compressPublicKey(signerPublicKey)}`
}
public isMember = (signerPublicKey: string): boolean => {
return this.getMember(signerPublicKey) !== undefined
}
}

View File

@ -52,15 +52,16 @@ export function handleWakuMessage(
}
messageToDecode = decodedMetadata.payload
const publicKey = recoverPublicKey(
const signerPublicKeyBytes = recoverPublicKey(
decodedMetadata.signature,
decodedMetadata.payload
)
const messageId = payloadToId(
decodedProtocol?.publicMessage ?? wakuMessage.payload,
publicKey
signerPublicKeyBytes
)
const signerPublicKey = `0x${bytesToHex(signerPublicKeyBytes)}`
// already handled
if (client.wakuMessages.has(messageId)) {
@ -76,6 +77,10 @@ export function handleWakuMessage(
// decode
const decodedPayload = CommunityDescription.decode(messageToDecode)
if (!community.isOwner(signerPublicKey)) {
return
}
// handle (state and callback)
community.handleDescription(decodedPayload)
@ -88,16 +93,26 @@ export function handleWakuMessage(
switch (decodedPayload.messageType) {
case MessageType.COMMUNITY_CHAT: {
if (!community.isMember(signerPublicKey)) {
return
}
const chatUuid = getChatUuid(decodedPayload.chatId)
const chat = community.chats.get(chatUuid)
if (!chat) {
return
}
// map
const chatMessage = mapChatMessage(decodedPayload, {
messageId,
chatUuid,
signerPublicKey,
})
// handle
community.chats.get(chatUuid)?.handleNewMessage(chatMessage)
chat.handleNewMessage(chatMessage)
break
}
@ -115,12 +130,23 @@ export function handleWakuMessage(
switch (decodedPayload.messageType) {
case MessageType.COMMUNITY_CHAT: {
if (!community.isMember(signerPublicKey)) {
return
}
const messageId = decodedPayload.messageId
const chatUuid = getChatUuid(decodedPayload.chatId)
const chat = community.chats.get(chatUuid)
community.chats
.get(chatUuid)
?.handleEditedMessage(messageId, decodedPayload.text)
if (!chat) {
return
}
chat.handleEditedMessage(
messageId,
decodedPayload.text,
signerPublicKey
)
break
}
@ -138,10 +164,19 @@ export function handleWakuMessage(
switch (decodedPayload.messageType) {
case MessageType.COMMUNITY_CHAT: {
if (!community.isMember(signerPublicKey)) {
return
}
const messageId = decodedPayload.messageId
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
}
@ -159,12 +194,19 @@ export function handleWakuMessage(
switch (decodedPayload.messageType) {
case MessageType.COMMUNITY_CHAT: {
if (!community.isMember(signerPublicKey)) {
return
}
const messageId = decodedPayload.messageId
const chatUuid = getChatUuid(decodedPayload.chatId)
const chat = community.chats.get(chatUuid)
community.chats
.get(chatUuid)
?.handlePinnedMessage(messageId, decodedPayload.pinned)
if (!chat) {
return
}
chat.handlePinnedMessage(messageId, decodedPayload.pinned)
break
}
@ -182,16 +224,19 @@ export function handleWakuMessage(
switch (decodedPayload.messageType) {
case MessageType.COMMUNITY_CHAT: {
if (!community.isMember(signerPublicKey)) {
return
}
const messageId = decodedPayload.messageId
const chatUuid = getChatUuid(decodedPayload.chatId)
const chat = community.chats.get(chatUuid)
chat?.handleEmojiReaction(
messageId,
decodedPayload,
`0x${bytesToHex(publicKey)}`
)
if (!chat) {
return
}
chat.handleEmojiReaction(messageId, decodedPayload, signerPublicKey)
break
}

View File

@ -6,17 +6,17 @@ export function mapChatMessage(
props: {
messageId: string
chatUuid: string
publicKey: string
signerPublicKey: string
}
): ChatMessage {
const { messageId, chatUuid, publicKey } = props
const { messageId, chatUuid, signerPublicKey } = props
const message = {
const message: ChatMessage = {
...decodedMessage,
messageId,
chatUuid,
pinned: false,
signer: publicKey,
signer: signerPublicKey,
reactions: {
THUMBS_UP: new Set<string>(),
THUMBS_DOWN: new Set<string>(),