From c0c6d543e11a77239c08a9b75ed4475570b8b210 Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Thu, 4 Jul 2024 12:38:17 +0200 Subject: [PATCH 01/27] add HaltedMessages to dbb schema --- .../migrations/20240704093840_/migration.sql | 13 +++++++++++++ .../migrations/20240704094732_/migration.sql | 8 ++++++++ packages/backend/schema.prisma | 13 ++++++++++++- 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 packages/backend/migrations/20240704093840_/migration.sql create mode 100644 packages/backend/migrations/20240704094732_/migration.sql diff --git a/packages/backend/migrations/20240704093840_/migration.sql b/packages/backend/migrations/20240704093840_/migration.sql new file mode 100644 index 000000000..ec445e6c2 --- /dev/null +++ b/packages/backend/migrations/20240704093840_/migration.sql @@ -0,0 +1,13 @@ +-- CreateTable +CREATE TABLE "HaltedMessage" ( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "encryptedEnvelopContainer" TEXT NOT NULL, + "encryptedContactName" TEXT NOT NULL, + "ownerId" TEXT NOT NULL, + + CONSTRAINT "HaltedMessage_pkey" PRIMARY KEY ("id") +); + +-- AddForeignKey +ALTER TABLE "HaltedMessage" ADD CONSTRAINT "HaltedMessage_ownerId_fkey" FOREIGN KEY ("ownerId") REFERENCES "Account"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/packages/backend/migrations/20240704094732_/migration.sql b/packages/backend/migrations/20240704094732_/migration.sql new file mode 100644 index 000000000..8691a3e66 --- /dev/null +++ b/packages/backend/migrations/20240704094732_/migration.sql @@ -0,0 +1,8 @@ +/* + Warnings: + + - You are about to drop the column `encryptedContactName` on the `HaltedMessage` table. All the data in the column will be lost. + +*/ +-- AlterTable +ALTER TABLE "HaltedMessage" DROP COLUMN "encryptedContactName"; diff --git a/packages/backend/schema.prisma b/packages/backend/schema.prisma index 286829ed5..1ace5e645 100644 --- a/packages/backend/schema.prisma +++ b/packages/backend/schema.prisma @@ -1,5 +1,7 @@ datasource db { - url = env("DATABASE_URL") + //Use this URL for local development + url = "postgresql://prisma:prisma@localhost:5433/tests" + //url = env("DATABASE_URL") provider = "postgresql" } @@ -18,6 +20,14 @@ model EncryptedMessage { owner Account @relation(fields: [ownerId], references: [id]) } +model HaltedMessage { + id String @id + createdAt DateTime @default(now()) + encryptedEnvelopContainer String + ownerId String + owner Account @relation(fields: [ownerId], references: [id]) +} + model Conversation { id String @id @default(uuid()) updatedAt DateTime @default(now()) @@ -32,4 +42,5 @@ model Account { id String @id conversations Conversation[] EncryptedMessage EncryptedMessage[] + HaltedMessage HaltedMessage[] } From 7c7194f6a10a906b269c8c85f4f17a652021e2a8 Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Thu, 4 Jul 2024 12:38:38 +0200 Subject: [PATCH 02/27] add deleteHaltedMessage --- .../haltedMessage/deleteHaltedMessage.test.ts | 56 +++++++++++++++++++ .../haltedMessage/deleteHaltedMessage.ts | 27 +++++++++ 2 files changed, 83 insertions(+) create mode 100644 packages/backend/src/persistence/storage/postgres/haltedMessage/deleteHaltedMessage.test.ts create mode 100644 packages/backend/src/persistence/storage/postgres/haltedMessage/deleteHaltedMessage.ts diff --git a/packages/backend/src/persistence/storage/postgres/haltedMessage/deleteHaltedMessage.test.ts b/packages/backend/src/persistence/storage/postgres/haltedMessage/deleteHaltedMessage.test.ts new file mode 100644 index 000000000..b6f7b1d33 --- /dev/null +++ b/packages/backend/src/persistence/storage/postgres/haltedMessage/deleteHaltedMessage.test.ts @@ -0,0 +1,56 @@ +import { PrismaClient } from '@prisma/client'; +import { deleteHaltedMessage } from './deleteHaltedMessage'; +import { getOrCreateAccount } from '../utils/getOrCreateAccount'; + +// Mock the PrismaClient +const mockDb = new PrismaClient(); + +describe('deleteHaltedMessage', () => { + let prismaClient: PrismaClient; + + beforeEach(async () => { + prismaClient = new PrismaClient(); + }); + + afterEach(async () => { + await prismaClient.haltedMessage.deleteMany({}); + await prismaClient.encryptedMessage.deleteMany({}); + await prismaClient.conversation.deleteMany({}); + await prismaClient.account.deleteMany({}); + + prismaClient.$disconnect(); + }); + it('should return false if account does not exist', async () => { + const result = await deleteHaltedMessage(mockDb)( + 'bob.eth', + 'messageId', + ); + expect(result).toBe(false); + }); + + it('should return true if message is successfully deleted', async () => { + const account = await getOrCreateAccount(prismaClient, 'bob.eth'); + //create message first + await mockDb.haltedMessage.create({ + data: { + id: 'messageId', + createdAt: new Date(1234), + encryptedEnvelopContainer: 'encryptedEnvelopContainer', + ownerId: account.id, + }, + }); + const result = await deleteHaltedMessage(mockDb)( + 'bob.eth', + 'messageId', + ); + expect(result).toBe(true); + }); + + it('should return false if deletion fails', async () => { + const result = await deleteHaltedMessage(mockDb)( + 'existing', + 'messageId', + ); + expect(result).toBe(false); + }); +}); diff --git a/packages/backend/src/persistence/storage/postgres/haltedMessage/deleteHaltedMessage.ts b/packages/backend/src/persistence/storage/postgres/haltedMessage/deleteHaltedMessage.ts new file mode 100644 index 000000000..fad342828 --- /dev/null +++ b/packages/backend/src/persistence/storage/postgres/haltedMessage/deleteHaltedMessage.ts @@ -0,0 +1,27 @@ +import { PrismaClient } from '@prisma/client'; + +export const deleteHaltedMessage = + (db: PrismaClient) => async (ensName: string, messageId: string) => { + //Find the account first we want to get the messages for + const account = await db.account.findFirst({ + where: { + id: ensName, + }, + }); + //If the contact does not exist, there is no message that can be deleted + if (!account) { + return false; + } + + try { + await db.haltedMessage.delete({ + where: { + id: messageId, + }, + }); + return true; + } catch (e) { + console.log('deleteHaltedMessage error', e); + return false; + } + }; From 30d83a651c25984fbe63918c37aec2421c259ac5 Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Thu, 4 Jul 2024 12:47:26 +0200 Subject: [PATCH 03/27] add addhaltedMessages --- .../haltedMessage/addHaltedMessage.test.ts | 46 +++++++++++++++++++ .../haltedMessage/addHaltedMessage.ts | 22 +++++++++ 2 files changed, 68 insertions(+) create mode 100644 packages/backend/src/persistence/storage/postgres/haltedMessage/addHaltedMessage.test.ts create mode 100644 packages/backend/src/persistence/storage/postgres/haltedMessage/addHaltedMessage.ts diff --git a/packages/backend/src/persistence/storage/postgres/haltedMessage/addHaltedMessage.test.ts b/packages/backend/src/persistence/storage/postgres/haltedMessage/addHaltedMessage.test.ts new file mode 100644 index 000000000..a369a2fb9 --- /dev/null +++ b/packages/backend/src/persistence/storage/postgres/haltedMessage/addHaltedMessage.test.ts @@ -0,0 +1,46 @@ +import { PrismaClient } from '@prisma/client'; +import { getOrCreateAccount } from '../utils/getOrCreateAccount'; +import { addHaltedMessage } from './addHaltedMessage'; + +describe('addHaltedMessage', () => { + let prismaClient: PrismaClient; + + beforeEach(async () => { + prismaClient = new PrismaClient(); + }); + + afterEach(async () => { + await prismaClient.haltedMessage.deleteMany({}); + await prismaClient.encryptedMessage.deleteMany({}); + await prismaClient.conversation.deleteMany({}); + await prismaClient.account.deleteMany({}); + + prismaClient.$disconnect(); + }); + it('should add a halted message', async () => { + const ensName = 'test'; + const messageRecord = { + messageId: '1', + createdAt: new Date().toISOString(), + encryptedEnvelopContainer: 'encrypted', + }; + + const account = await getOrCreateAccount(prismaClient, ensName); + + await addHaltedMessage(prismaClient)(ensName, messageRecord); + //read message from db + + const haltedMessage = await prismaClient.haltedMessage.findUnique({ + where: { + id: messageRecord.messageId, + }, + }); + + expect(haltedMessage).toEqual({ + id: messageRecord.messageId, + createdAt: new Date(messageRecord.createdAt), + encryptedEnvelopContainer: messageRecord.encryptedEnvelopContainer, + ownerId: account.id, + }); + }); +}); diff --git a/packages/backend/src/persistence/storage/postgres/haltedMessage/addHaltedMessage.ts b/packages/backend/src/persistence/storage/postgres/haltedMessage/addHaltedMessage.ts new file mode 100644 index 000000000..a6bd112d9 --- /dev/null +++ b/packages/backend/src/persistence/storage/postgres/haltedMessage/addHaltedMessage.ts @@ -0,0 +1,22 @@ +import { PrismaClient } from '@prisma/client'; +import { MessageRecord } from '../dto/MessageRecord'; +import { getOrCreateAccount } from '../utils/getOrCreateAccount'; + +export const addHaltedMessage = + (db: PrismaClient) => + async ( + ensName: string, + { messageId, createdAt, encryptedEnvelopContainer }: MessageRecord, + ) => { + const account = await getOrCreateAccount(db, ensName); + + //Create a new halted message + return await db.haltedMessage.create({ + data: { + id: messageId, + createdAt: new Date(createdAt), + encryptedEnvelopContainer, + ownerId: account.id, + }, + }); + }; From ee4be4080e2ccfe0d9b1431df3baa7e3c3180de4 Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Thu, 4 Jul 2024 12:50:16 +0200 Subject: [PATCH 04/27] add getHaltedMEssages --- .../haltedMessage/getHaltedMessages.test.ts | 40 +++++++++++++++++++ .../haltedMessage/getHaltedMessages.ts | 20 ++++++++++ 2 files changed, 60 insertions(+) create mode 100644 packages/backend/src/persistence/storage/postgres/haltedMessage/getHaltedMessages.test.ts create mode 100644 packages/backend/src/persistence/storage/postgres/haltedMessage/getHaltedMessages.ts diff --git a/packages/backend/src/persistence/storage/postgres/haltedMessage/getHaltedMessages.test.ts b/packages/backend/src/persistence/storage/postgres/haltedMessage/getHaltedMessages.test.ts new file mode 100644 index 000000000..b625d3b93 --- /dev/null +++ b/packages/backend/src/persistence/storage/postgres/haltedMessage/getHaltedMessages.test.ts @@ -0,0 +1,40 @@ +import { PrismaClient } from '@prisma/client'; +import { getHaltedMessages } from './getHaltedMessages'; +import { getOrCreateAccount } from '../utils/getOrCreateAccount'; +import { addHaltedMessage } from './addHaltedMessage'; + +describe('getHaltedMessages', () => { + let prismaClient: PrismaClient; + + beforeEach(async () => { + prismaClient = new PrismaClient(); + }); + + afterEach(async () => { + await prismaClient.haltedMessage.deleteMany({}); + await prismaClient.account.deleteMany({}); + prismaClient.$disconnect(); + }); + + it('should get halted messages for a given account', async () => { + const ensName = 'test'; + const messageRecord = { + messageId: '1', + createdAt: new Date().toISOString(), + encryptedEnvelopContainer: 'encrypted', + }; + + await getOrCreateAccount(prismaClient, ensName); + await addHaltedMessage(prismaClient)(ensName, messageRecord); + + const haltedMessages = await getHaltedMessages(prismaClient)(ensName); + + expect(haltedMessages).toHaveLength(1); + expect(haltedMessages[0]).toEqual({ + id: messageRecord.messageId, + createdAt: new Date(messageRecord.createdAt), + encryptedEnvelopContainer: messageRecord.encryptedEnvelopContainer, + ownerId: ensName, + }); + }); +}); diff --git a/packages/backend/src/persistence/storage/postgres/haltedMessage/getHaltedMessages.ts b/packages/backend/src/persistence/storage/postgres/haltedMessage/getHaltedMessages.ts new file mode 100644 index 000000000..c6e49555c --- /dev/null +++ b/packages/backend/src/persistence/storage/postgres/haltedMessage/getHaltedMessages.ts @@ -0,0 +1,20 @@ +export const getHaltedMessages = + (db: PrismaClient) => async (ensName: string) => { + //Find the account first we want to get the messages for + const account = await db.account.findFirst({ + where: { + id: ensName, + }, + }); + + //If the contact does not exist, return an empty array + if (!account) { + return []; + } + + return await db.haltedMessage.findMany({ + where: { + ownerId: account.id, + }, + }); + }; From 6ef8f4f895691c1c4944a5e51e7f022cd6fcaed1 Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Thu, 4 Jul 2024 14:18:30 +0200 Subject: [PATCH 05/27] fix imports --- .../storage/postgres/haltedMessage/getHaltedMessages.test.ts | 2 +- .../storage/postgres/haltedMessage/getHaltedMessages.ts | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/backend/src/persistence/storage/postgres/haltedMessage/getHaltedMessages.test.ts b/packages/backend/src/persistence/storage/postgres/haltedMessage/getHaltedMessages.test.ts index b625d3b93..9f8d57d08 100644 --- a/packages/backend/src/persistence/storage/postgres/haltedMessage/getHaltedMessages.test.ts +++ b/packages/backend/src/persistence/storage/postgres/haltedMessage/getHaltedMessages.test.ts @@ -20,7 +20,7 @@ describe('getHaltedMessages', () => { const ensName = 'test'; const messageRecord = { messageId: '1', - createdAt: new Date().toISOString(), + createdAt: 123, encryptedEnvelopContainer: 'encrypted', }; diff --git a/packages/backend/src/persistence/storage/postgres/haltedMessage/getHaltedMessages.ts b/packages/backend/src/persistence/storage/postgres/haltedMessage/getHaltedMessages.ts index c6e49555c..e6ce09a51 100644 --- a/packages/backend/src/persistence/storage/postgres/haltedMessage/getHaltedMessages.ts +++ b/packages/backend/src/persistence/storage/postgres/haltedMessage/getHaltedMessages.ts @@ -1,3 +1,5 @@ +import { PrismaClient } from '@prisma/client'; + export const getHaltedMessages = (db: PrismaClient) => async (ensName: string) => { //Find the account first we want to get the messages for From 00940d7c7045b444520a2c747c7015af2ca954c0 Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Thu, 4 Jul 2024 15:35:15 +0200 Subject: [PATCH 06/27] add AddHaltedMessageRequest schema --- packages/backend/schemas.sh | 2 ++ .../AddHaltedMessageRequest.schema.json | 26 +++++++++++++++++++ .../schema/storage/AddHaltedMessageSchema.ts | 9 +++++++ 3 files changed, 37 insertions(+) create mode 100644 packages/backend/src/schema/storage/AddHaltedMessageRequest.schema.json create mode 100644 packages/backend/src/schema/storage/AddHaltedMessageSchema.ts diff --git a/packages/backend/schemas.sh b/packages/backend/schemas.sh index b44d34170..0391a7dfc 100644 --- a/packages/backend/schemas.sh +++ b/packages/backend/schemas.sh @@ -5,3 +5,5 @@ yarn ts-json-schema-generator -f tsconfig.json --path schema/storage/AddMessageB yarn ts-json-schema-generator -f tsconfig.json --path schema/storage/AddMessageRequest.ts --type _AddMessageRequest -o ./src/schema/storage/AddMessageRequest.schema.json --no-type-check \ yarn ts-json-schema-generator -f tsconfig.json --path schema/storage/PaginatedRequest.ts --type _PaginatedRequest -o ./src/schema/storage/PaginatedRequest.schema.json --no-type-check \ + +yarn ts-json-schema-generator -f tsconfig.json --path schema/storage/AddHaltedMessageRequest.ts --type _AddHaltedMessageRequest -o ./src/schema/storage/AddHaltedMessageRequest.schema.json --no-type-check \ diff --git a/packages/backend/src/schema/storage/AddHaltedMessageRequest.schema.json b/packages/backend/src/schema/storage/AddHaltedMessageRequest.schema.json new file mode 100644 index 000000000..e96d4382b --- /dev/null +++ b/packages/backend/src/schema/storage/AddHaltedMessageRequest.schema.json @@ -0,0 +1,26 @@ +{ + "$ref": "#/definitions/_AddHaltedMessageRequest", + "$schema": "http://json-schema.org/draft-07/schema#", + "definitions": { + "_AddHaltedMessageRequest": { + "additionalProperties": false, + "properties": { + "createdAt": { + "type": "number" + }, + "encryptedEnvelopContainer": { + "type": "string" + }, + "messageId": { + "type": "string" + } + }, + "required": [ + "messageId", + "createdAt", + "encryptedEnvelopContainer" + ], + "type": "object" + } + } +} \ No newline at end of file diff --git a/packages/backend/src/schema/storage/AddHaltedMessageSchema.ts b/packages/backend/src/schema/storage/AddHaltedMessageSchema.ts new file mode 100644 index 000000000..1bf618c5c --- /dev/null +++ b/packages/backend/src/schema/storage/AddHaltedMessageSchema.ts @@ -0,0 +1,9 @@ +import AddHaltedMessageRequestSchema from './AddHaltedMessageRequest.schema.json'; + +//This schema defines how the body of the AddHaltedMessage request has to look like +export interface _AddHaltedMessageRequest { + messageId: string; + createdAt: number; + encryptedEnvelopContainer: string; +} +export const AddHaltedMessageRequest = AddHaltedMessageRequestSchema; From a253ab15e770d37ce516866bc1a4ba87469a2625 Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Thu, 4 Jul 2024 15:35:40 +0200 Subject: [PATCH 07/27] add endpoints for haltDelivery --- .../backend/src/persistence/getDatabase.ts | 16 ++ .../backend/src/persistence/storage/index.ts | 6 + packages/backend/src/storage.test.ts | 146 ++++++++++++++++++ packages/backend/src/storage.ts | 69 +++++++++ 4 files changed, 237 insertions(+) diff --git a/packages/backend/src/persistence/getDatabase.ts b/packages/backend/src/persistence/getDatabase.ts index 55f19c99b..a8ff26998 100644 --- a/packages/backend/src/persistence/getDatabase.ts +++ b/packages/backend/src/persistence/getDatabase.ts @@ -8,6 +8,7 @@ import Session from './session'; import Storage from './storage'; import { MessageRecord } from './storage/postgres/dto/MessageRecord'; import { ConversationRecord } from './storage/postgres/dto/ConversationRecord'; +import { deleteHaltedMessage } from './storage/postgres/haltedMessage/deleteHaltedMessage'; export enum RedisPrefix { Conversation = 'conversation:', @@ -88,6 +89,12 @@ export async function getDatabase( getNumberOfConverations: Storage.getNumberOfConversations(prisma), //Storage Toggle Hide Conversation toggleHideConversation: Storage.toggleHideConversation(prisma), + //Storage Get Halted Messages + getHaltedMessages: Storage.getHaltedMessages(prisma), + //Storage Add Halted Message + addHaltedMessage: Storage.addHaltedMessage(prisma), + //Storage Delete Halted Message + deleteHaltedMessage: Storage.deleteHaltedMessage(prisma), //Get the user db migration status getUserDbMigrationStatus: Storage.getUserDbMigrationStatus(redis), //Set the user db migration status to true @@ -145,6 +152,15 @@ export interface IDatabase extends ISessionDatabase { encryptedContactName: string, isHidden: boolean, ) => Promise; + getHaltedMessages: (ensName: string) => Promise; + addHaltedMessage: ( + ensName: string, + messagesRecord: MessageRecord, + ) => Promise; + deleteHaltedMessage: ( + ensName: string, + messageId: string, + ) => Promise; getUserDbMigrationStatus: (ensName: string) => Promise; setUserDbMigrated: (ensName: string) => Promise; } diff --git a/packages/backend/src/persistence/storage/index.ts b/packages/backend/src/persistence/storage/index.ts index 6383776e4..df51a399d 100644 --- a/packages/backend/src/persistence/storage/index.ts +++ b/packages/backend/src/persistence/storage/index.ts @@ -11,6 +11,9 @@ import { toggleHideConversation } from './postgres/toggleHideConversation'; import { MessageRecord } from './postgres/dto/MessageRecord'; import { getUserDbMigrationStatus } from './getUserDbMigrationStatus'; import { setUserDbMigrated } from './setUserDbMigrated'; +import { getHaltedMessages } from './postgres/haltedMessage/getHaltedMessages'; +import { deleteHaltedMessage } from './postgres/haltedMessage/deleteHaltedMessage'; +import { addHaltedMessage } from './postgres/haltedMessage/addHaltedMessage'; export default { getUserStorageOld, @@ -23,6 +26,9 @@ export default { getNumberOfConversations, getNumberOfMessages, toggleHideConversation, + getHaltedMessages, + deleteHaltedMessage, + addHaltedMessage, getUserDbMigrationStatus, setUserDbMigrated, }; diff --git a/packages/backend/src/storage.test.ts b/packages/backend/src/storage.test.ts index a2c9d0c6a..2beceacf2 100644 --- a/packages/backend/src/storage.test.ts +++ b/packages/backend/src/storage.test.ts @@ -123,6 +123,7 @@ describe('Storage', () => { }); afterEach(async () => { + await prisma.haltedMessage.deleteMany(); await prisma.encryptedMessage.deleteMany(); await prisma.conversation.deleteMany(); await prisma.account.deleteMany(); @@ -950,6 +951,151 @@ describe('Storage', () => { ).toStrictEqual(envelop); }); }); + describe('halted Messages', () => { + describe('schema', () => { + it('should return 400 if encryptedEnvelopContainer is missing', async () => { + const body = { + encryptedContactName: 'encryptedContactName', + messageId: 'messageId', + createdAt: 123, + }; + const response = await request(app) + .post('/new/bob.eth/addHaltedMessage') + .set({ + authorization: 'Bearer ' + token, + }) + .send(body); + expect(response.status).toBe(400); + }); + + it('should return 400 if messageId is missing', async () => { + const body = { + encryptedEnvelopContainer: 'encryptedEnvelopContainer', + createdAt: 123, + }; + const response = await request(app) + .post('/new/bob.eth/addHaltedMessage') + .set({ + authorization: 'Bearer ' + token, + }) + .send(body); + expect(response.status).toBe(400); + }); + + it('should return 400 if createdAt is missing', async () => { + const body = { + encryptedEnvelopContainer: 'encryptedEnvelopContainer', + encryptedContactName: 'encryptedContactName', + messageId: 'messageId', + }; + const response = await request(app) + .post('/new/bob.eth/addHaltedMessage') + .set({ + authorization: 'Bearer ' + token, + }) + .send(body); + expect(response.status).toBe(400); + }); + }); + it('can add halted message', async () => { + const messageFactory = MockMessageFactory( + sender, + receiver, + deliveryService, + ); + const envelop1 = await messageFactory.createEncryptedEnvelop( + 'Hello1', + ); + + const { status } = await request(app) + .post(`/new/bob.eth/addHaltedMessage`) + .set({ + authorization: 'Bearer ' + token, + }) + .send({ + encryptedEnvelopContainer: JSON.stringify(envelop1), + messageId: '123', + createdAt: 1, + }); + expect(status).toBe(200); + + const { status: getMessagesStatus, body: messages } = await request( + app, + ) + .get(`/new/bob.eth/getHaltedMessages/`) + .set({ + authorization: 'Bearer ' + token, + }) + .send(); + + expect(getMessagesStatus).toBe(200); + expect(messages.length).toBe(1); + expect( + JSON.parse(messages[0].encryptedEnvelopContainer), + ).toStrictEqual(envelop1); + }); + it('can delete halted message', async () => { + const messageFactory = MockMessageFactory( + sender, + receiver, + deliveryService, + ); + const envelop1 = await messageFactory.createEncryptedEnvelop( + 'Hello1', + ); + + const { status } = await request(app) + .post(`/new/bob.eth/addHaltedMessage`) + .set({ + authorization: 'Bearer ' + token, + }) + .send({ + encryptedEnvelopContainer: JSON.stringify(envelop1), + messageId: '123', + createdAt: 1, + }); + expect(status).toBe(200); + + const { status: getMessagesStatus, body: messages } = await request( + app, + ) + .get(`/new/bob.eth/getHaltedMessages/`) + .set({ + authorization: 'Bearer ' + token, + }) + .send(); + + expect(getMessagesStatus).toBe(200); + expect(messages.length).toBe(1); + expect( + JSON.parse(messages[0].encryptedEnvelopContainer), + ).toStrictEqual(envelop1); + + const { status: deleteStatus } = await request(app) + .post(`/new/bob.eth/deleteHaltedMessage/`) + .set({ + authorization: 'Bearer ' + token, + }) + .send({ + messageId: 123, + }); + + expect(deleteStatus).toBe(200); + + const { + status: getMessagesStatusAfterDelete, + body: messagesAfterDelete, + } = await request(app) + .get(`/new/bob.eth/getHaltedMessages/`) + .set({ + authorization: 'Bearer ' + token, + }) + .send(); + + expect(getMessagesStatusAfterDelete).toBe(200); + expect(messagesAfterDelete.length).toBe(0); + }); + }); describe('addMessageBatch', () => { describe('schema', () => { it('should return 400 if encryptedContactName is missing', async () => { diff --git a/packages/backend/src/storage.ts b/packages/backend/src/storage.ts index 12e3303ad..1f8777ef9 100644 --- a/packages/backend/src/storage.ts +++ b/packages/backend/src/storage.ts @@ -10,6 +10,7 @@ import { AddMessageBatchRequest } from './schema/storage/AddMessageBatchRequest' import { AddMessageRequest } from './schema/storage/AddMesssageRequest'; import { EditMessageBatchRequest } from './schema/storage/EditMessageBatchRequest'; import { PaginatedRequest } from './schema/storage/PaginatedRequest'; +import { AddHaltedMessageRequest } from './schema/storage/AddHaltedMessageSchema'; const DEFAULT_CONVERSATION_PAGE_SIZE = 10; const DEFAULT_MESSAGE_PAGE_SIZE = 100; @@ -254,6 +255,74 @@ export default ( }, ); + router.get('/new/:ensName/getHaltedMessages', async (req, res, next) => { + try { + const ensName = normalizeEnsName(req.params.ensName); + const messages = await db.getHaltedMessages(ensName); + return res.json(messages); + } catch (err) { + next(err); + } + }); + router.post('/new/:ensName/addHaltedMessage', async (req, res, next) => { + try { + const schemaIsValid = validateSchema( + AddHaltedMessageRequest, + req.body, + ); + + if (!schemaIsValid) { + res.status(400).send('invalid schema'); + return; + } + const { encryptedEnvelopContainer, messageId, createdAt } = + req.body; + + const ensName = normalizeEnsName(req.params.ensName); + //Since the message is fully encrypted, we cannot use the messageHash as an identifier. + //Instead we use the hash of the ensName and the messageId to have a unique identifier + const uniqueMessageId = sha256(ensName + messageId); + const success = await db.addHaltedMessage(ensName, { + messageId: uniqueMessageId, + createdAt, + encryptedEnvelopContainer, + }); + + if (success) { + return res.send(); + } + res.status(400).send('unable to add halted message'); + } catch (err) { + next(err); + } + }); + router.post('/new/:ensName/deleteHaltedMessage', async (req, res, next) => { + try { + const { messageId } = req.body; + + if (!messageId) { + res.status(400).send('invalid schema'); + return; + } + + const ensName = normalizeEnsName(req.params.ensName); + //Since the message is fully encrypted, we cannot use the messageHash as an identifier. + //Instead we use the hash of the ensName and the messageId to have a unique identifier + const uniqueMessageId = sha256(ensName + messageId); + const success = await db.deleteHaltedMessage( + ensName, + uniqueMessageId, + ); + + if (success) { + return res.send(); + } + res.status(400).send('unable to add halted message'); + } catch (err) { + next(err); + } + }); + router.post( '/new/:ensName/toggleHideConversation', async (req, res, next) => { From a3d810ab91e8f1bf44f2a07870c60ebf5f93a678 Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Thu, 4 Jul 2024 15:42:09 +0200 Subject: [PATCH 08/27] fix tests in halted Messages --- .../haltedMessage/addHaltedMessage.test.ts | 2 +- .../haltedMessage/addHaltedMessage.ts | 25 +++++++++++-------- .../haltedMessage/deleteHaltedMessage.ts | 2 +- .../haltedMessage/getHaltedMessages.test.ts | 5 ++-- .../haltedMessage/getHaltedMessages.ts | 12 ++++++++- 5 files changed, 30 insertions(+), 16 deletions(-) diff --git a/packages/backend/src/persistence/storage/postgres/haltedMessage/addHaltedMessage.test.ts b/packages/backend/src/persistence/storage/postgres/haltedMessage/addHaltedMessage.test.ts index a369a2fb9..8fb4d0b85 100644 --- a/packages/backend/src/persistence/storage/postgres/haltedMessage/addHaltedMessage.test.ts +++ b/packages/backend/src/persistence/storage/postgres/haltedMessage/addHaltedMessage.test.ts @@ -21,7 +21,7 @@ describe('addHaltedMessage', () => { const ensName = 'test'; const messageRecord = { messageId: '1', - createdAt: new Date().toISOString(), + createdAt: 123, encryptedEnvelopContainer: 'encrypted', }; diff --git a/packages/backend/src/persistence/storage/postgres/haltedMessage/addHaltedMessage.ts b/packages/backend/src/persistence/storage/postgres/haltedMessage/addHaltedMessage.ts index a6bd112d9..17980b73e 100644 --- a/packages/backend/src/persistence/storage/postgres/haltedMessage/addHaltedMessage.ts +++ b/packages/backend/src/persistence/storage/postgres/haltedMessage/addHaltedMessage.ts @@ -9,14 +9,19 @@ export const addHaltedMessage = { messageId, createdAt, encryptedEnvelopContainer }: MessageRecord, ) => { const account = await getOrCreateAccount(db, ensName); - - //Create a new halted message - return await db.haltedMessage.create({ - data: { - id: messageId, - createdAt: new Date(createdAt), - encryptedEnvelopContainer, - ownerId: account.id, - }, - }); + try { + //Create a new halted message + await db.haltedMessage.create({ + data: { + id: messageId, + createdAt: new Date(createdAt), + encryptedEnvelopContainer, + ownerId: account.id, + }, + }); + return true; + } catch (err) { + console.error('addHaltedMessage error ', err); + return false; + } }; diff --git a/packages/backend/src/persistence/storage/postgres/haltedMessage/deleteHaltedMessage.ts b/packages/backend/src/persistence/storage/postgres/haltedMessage/deleteHaltedMessage.ts index fad342828..d0b1284f7 100644 --- a/packages/backend/src/persistence/storage/postgres/haltedMessage/deleteHaltedMessage.ts +++ b/packages/backend/src/persistence/storage/postgres/haltedMessage/deleteHaltedMessage.ts @@ -21,7 +21,7 @@ export const deleteHaltedMessage = }); return true; } catch (e) { - console.log('deleteHaltedMessage error', e); + console.error('deleteHaltedMessage error', e); return false; } }; diff --git a/packages/backend/src/persistence/storage/postgres/haltedMessage/getHaltedMessages.test.ts b/packages/backend/src/persistence/storage/postgres/haltedMessage/getHaltedMessages.test.ts index 9f8d57d08..08b6f9904 100644 --- a/packages/backend/src/persistence/storage/postgres/haltedMessage/getHaltedMessages.test.ts +++ b/packages/backend/src/persistence/storage/postgres/haltedMessage/getHaltedMessages.test.ts @@ -31,10 +31,9 @@ describe('getHaltedMessages', () => { expect(haltedMessages).toHaveLength(1); expect(haltedMessages[0]).toEqual({ - id: messageRecord.messageId, - createdAt: new Date(messageRecord.createdAt), + messageId: messageRecord.messageId, + createdAt: new Date(123), encryptedEnvelopContainer: messageRecord.encryptedEnvelopContainer, - ownerId: ensName, }); }); }); diff --git a/packages/backend/src/persistence/storage/postgres/haltedMessage/getHaltedMessages.ts b/packages/backend/src/persistence/storage/postgres/haltedMessage/getHaltedMessages.ts index e6ce09a51..b262e744f 100644 --- a/packages/backend/src/persistence/storage/postgres/haltedMessage/getHaltedMessages.ts +++ b/packages/backend/src/persistence/storage/postgres/haltedMessage/getHaltedMessages.ts @@ -14,9 +14,19 @@ export const getHaltedMessages = return []; } - return await db.haltedMessage.findMany({ + const messageRecord = await db.haltedMessage.findMany({ where: { ownerId: account.id, }, }); + + if (messageRecord.length === 0) { + return []; + } + + return messageRecord.map((message: any) => ({ + messageId: message.id, + encryptedEnvelopContainer: message.encryptedEnvelopContainer, + createdAt: message.createdAt, + })); }; From cc6d472e740fbdb240adff5e30d03e8dadac8670 Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Thu, 4 Jul 2024 17:42:17 +0200 Subject: [PATCH 09/27] streamline database layout --- .../migrations/20240704141910_/migration.sql | 14 +++ packages/backend/schema.prisma | 10 +- .../backend/src/persistence/getDatabase.ts | 13 +- .../backend/src/persistence/storage/index.ts | 6 +- .../storage/postgres/addMessageBatch.ts | 8 +- .../storage/postgres/dto/MessageRecord.ts | 2 + .../haltedMessage/addHaltedMessage.test.ts | 46 ------- .../haltedMessage/addHaltedMessage.ts | 27 ---- ...age.test.ts => clearHaltedMessage.test.ts} | 51 ++++---- ...HaltedMessage.ts => clearHaltedMessage.ts} | 20 ++- .../haltedMessage/getHaltedMessages.test.ts | 69 ++++++++++- .../haltedMessage/getHaltedMessages.ts | 4 +- .../AddMessageBatchRequest.schema.json | 6 +- .../storage/AddMessageRequest.schema.json | 6 +- .../src/schema/storage/AddMesssageRequest.ts | 2 + .../EditMessageBatchRequest.schema.json | 6 +- packages/backend/src/storage.test.ts | 117 +++++------------- packages/backend/src/storage.ts | 37 +----- .../src/hooks/haltDelivery/useHaltDelivery.ts | 3 + 19 files changed, 195 insertions(+), 252 deletions(-) create mode 100644 packages/backend/migrations/20240704141910_/migration.sql delete mode 100644 packages/backend/src/persistence/storage/postgres/haltedMessage/addHaltedMessage.test.ts delete mode 100644 packages/backend/src/persistence/storage/postgres/haltedMessage/addHaltedMessage.ts rename packages/backend/src/persistence/storage/postgres/haltedMessage/{deleteHaltedMessage.test.ts => clearHaltedMessage.test.ts} (52%) rename packages/backend/src/persistence/storage/postgres/haltedMessage/{deleteHaltedMessage.ts => clearHaltedMessage.ts} (58%) create mode 100644 packages/messenger-widget/src/hooks/haltDelivery/useHaltDelivery.ts diff --git a/packages/backend/migrations/20240704141910_/migration.sql b/packages/backend/migrations/20240704141910_/migration.sql new file mode 100644 index 000000000..10f1fc0b7 --- /dev/null +++ b/packages/backend/migrations/20240704141910_/migration.sql @@ -0,0 +1,14 @@ +/* + Warnings: + + - You are about to drop the `HaltedMessage` table. If the table is not empty, all the data it contains will be lost. + +*/ +-- DropForeignKey +ALTER TABLE "HaltedMessage" DROP CONSTRAINT "HaltedMessage_ownerId_fkey"; + +-- AlterTable +ALTER TABLE "EncryptedMessage" ADD COLUMN "isHalted" BOOLEAN NOT NULL DEFAULT false; + +-- DropTable +DROP TABLE "HaltedMessage"; diff --git a/packages/backend/schema.prisma b/packages/backend/schema.prisma index 1ace5e645..eafb19e7b 100644 --- a/packages/backend/schema.prisma +++ b/packages/backend/schema.prisma @@ -18,14 +18,7 @@ model EncryptedMessage { conversation Conversation @relation(fields: [conversationId], references: [id]) ownerId String owner Account @relation(fields: [ownerId], references: [id]) -} - -model HaltedMessage { - id String @id - createdAt DateTime @default(now()) - encryptedEnvelopContainer String - ownerId String - owner Account @relation(fields: [ownerId], references: [id]) + isHalted Boolean @default(false) } model Conversation { @@ -42,5 +35,4 @@ model Account { id String @id conversations Conversation[] EncryptedMessage EncryptedMessage[] - HaltedMessage HaltedMessage[] } diff --git a/packages/backend/src/persistence/getDatabase.ts b/packages/backend/src/persistence/getDatabase.ts index a8ff26998..40def5519 100644 --- a/packages/backend/src/persistence/getDatabase.ts +++ b/packages/backend/src/persistence/getDatabase.ts @@ -6,9 +6,8 @@ import { createClient } from 'redis'; import Pending from './pending'; import Session from './session'; import Storage from './storage'; -import { MessageRecord } from './storage/postgres/dto/MessageRecord'; import { ConversationRecord } from './storage/postgres/dto/ConversationRecord'; -import { deleteHaltedMessage } from './storage/postgres/haltedMessage/deleteHaltedMessage'; +import { MessageRecord } from './storage/postgres/dto/MessageRecord'; export enum RedisPrefix { Conversation = 'conversation:', @@ -91,10 +90,8 @@ export async function getDatabase( toggleHideConversation: Storage.toggleHideConversation(prisma), //Storage Get Halted Messages getHaltedMessages: Storage.getHaltedMessages(prisma), - //Storage Add Halted Message - addHaltedMessage: Storage.addHaltedMessage(prisma), //Storage Delete Halted Message - deleteHaltedMessage: Storage.deleteHaltedMessage(prisma), + clearHaltedMessage: Storage.clearHaltedMessage(prisma), //Get the user db migration status getUserDbMigrationStatus: Storage.getUserDbMigrationStatus(redis), //Set the user db migration status to true @@ -153,11 +150,7 @@ export interface IDatabase extends ISessionDatabase { isHidden: boolean, ) => Promise; getHaltedMessages: (ensName: string) => Promise; - addHaltedMessage: ( - ensName: string, - messagesRecord: MessageRecord, - ) => Promise; - deleteHaltedMessage: ( + clearHaltedMessage: ( ensName: string, messageId: string, ) => Promise; diff --git a/packages/backend/src/persistence/storage/index.ts b/packages/backend/src/persistence/storage/index.ts index df51a399d..3563533eb 100644 --- a/packages/backend/src/persistence/storage/index.ts +++ b/packages/backend/src/persistence/storage/index.ts @@ -12,8 +12,7 @@ import { MessageRecord } from './postgres/dto/MessageRecord'; import { getUserDbMigrationStatus } from './getUserDbMigrationStatus'; import { setUserDbMigrated } from './setUserDbMigrated'; import { getHaltedMessages } from './postgres/haltedMessage/getHaltedMessages'; -import { deleteHaltedMessage } from './postgres/haltedMessage/deleteHaltedMessage'; -import { addHaltedMessage } from './postgres/haltedMessage/addHaltedMessage'; +import { clearHaltedMessage } from './postgres/haltedMessage/clearHaltedMessage'; export default { getUserStorageOld, @@ -27,8 +26,7 @@ export default { getNumberOfMessages, toggleHideConversation, getHaltedMessages, - deleteHaltedMessage, - addHaltedMessage, + clearHaltedMessage, getUserDbMigrationStatus, setUserDbMigrated, }; diff --git a/packages/backend/src/persistence/storage/postgres/addMessageBatch.ts b/packages/backend/src/persistence/storage/postgres/addMessageBatch.ts index 856abf32c..608383fae 100644 --- a/packages/backend/src/persistence/storage/postgres/addMessageBatch.ts +++ b/packages/backend/src/persistence/storage/postgres/addMessageBatch.ts @@ -21,7 +21,12 @@ export const addMessageBatch = ); //store each message in the db const createMessagePromises = messageBatch.map( - ({ messageId, createdAt, encryptedEnvelopContainer }) => { + ({ + messageId, + createdAt, + encryptedEnvelopContainer, + isHalted, + }) => { //The database stores the date as an ISO 8601 string. Hence we need to convert it to a Date object const createAtDate = new Date(createdAt); return db.encryptedMessage.create({ @@ -32,6 +37,7 @@ export const addMessageBatch = conversationId: conversation.id, encryptedContactName, encryptedEnvelopContainer, + isHalted, }, }); }, diff --git a/packages/backend/src/persistence/storage/postgres/dto/MessageRecord.ts b/packages/backend/src/persistence/storage/postgres/dto/MessageRecord.ts index 78913695b..d904a2d80 100644 --- a/packages/backend/src/persistence/storage/postgres/dto/MessageRecord.ts +++ b/packages/backend/src/persistence/storage/postgres/dto/MessageRecord.ts @@ -7,4 +7,6 @@ export type MessageRecord = { messageId: string; //The actual encrypted message encryptedEnvelopContainer: string; + //The message is halted if the message hasnot been delivered yet + isHalted: boolean; }; diff --git a/packages/backend/src/persistence/storage/postgres/haltedMessage/addHaltedMessage.test.ts b/packages/backend/src/persistence/storage/postgres/haltedMessage/addHaltedMessage.test.ts deleted file mode 100644 index 8fb4d0b85..000000000 --- a/packages/backend/src/persistence/storage/postgres/haltedMessage/addHaltedMessage.test.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { PrismaClient } from '@prisma/client'; -import { getOrCreateAccount } from '../utils/getOrCreateAccount'; -import { addHaltedMessage } from './addHaltedMessage'; - -describe('addHaltedMessage', () => { - let prismaClient: PrismaClient; - - beforeEach(async () => { - prismaClient = new PrismaClient(); - }); - - afterEach(async () => { - await prismaClient.haltedMessage.deleteMany({}); - await prismaClient.encryptedMessage.deleteMany({}); - await prismaClient.conversation.deleteMany({}); - await prismaClient.account.deleteMany({}); - - prismaClient.$disconnect(); - }); - it('should add a halted message', async () => { - const ensName = 'test'; - const messageRecord = { - messageId: '1', - createdAt: 123, - encryptedEnvelopContainer: 'encrypted', - }; - - const account = await getOrCreateAccount(prismaClient, ensName); - - await addHaltedMessage(prismaClient)(ensName, messageRecord); - //read message from db - - const haltedMessage = await prismaClient.haltedMessage.findUnique({ - where: { - id: messageRecord.messageId, - }, - }); - - expect(haltedMessage).toEqual({ - id: messageRecord.messageId, - createdAt: new Date(messageRecord.createdAt), - encryptedEnvelopContainer: messageRecord.encryptedEnvelopContainer, - ownerId: account.id, - }); - }); -}); diff --git a/packages/backend/src/persistence/storage/postgres/haltedMessage/addHaltedMessage.ts b/packages/backend/src/persistence/storage/postgres/haltedMessage/addHaltedMessage.ts deleted file mode 100644 index 17980b73e..000000000 --- a/packages/backend/src/persistence/storage/postgres/haltedMessage/addHaltedMessage.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { PrismaClient } from '@prisma/client'; -import { MessageRecord } from '../dto/MessageRecord'; -import { getOrCreateAccount } from '../utils/getOrCreateAccount'; - -export const addHaltedMessage = - (db: PrismaClient) => - async ( - ensName: string, - { messageId, createdAt, encryptedEnvelopContainer }: MessageRecord, - ) => { - const account = await getOrCreateAccount(db, ensName); - try { - //Create a new halted message - await db.haltedMessage.create({ - data: { - id: messageId, - createdAt: new Date(createdAt), - encryptedEnvelopContainer, - ownerId: account.id, - }, - }); - return true; - } catch (err) { - console.error('addHaltedMessage error ', err); - return false; - } - }; diff --git a/packages/backend/src/persistence/storage/postgres/haltedMessage/deleteHaltedMessage.test.ts b/packages/backend/src/persistence/storage/postgres/haltedMessage/clearHaltedMessage.test.ts similarity index 52% rename from packages/backend/src/persistence/storage/postgres/haltedMessage/deleteHaltedMessage.test.ts rename to packages/backend/src/persistence/storage/postgres/haltedMessage/clearHaltedMessage.test.ts index b6f7b1d33..a41f4fab9 100644 --- a/packages/backend/src/persistence/storage/postgres/haltedMessage/deleteHaltedMessage.test.ts +++ b/packages/backend/src/persistence/storage/postgres/haltedMessage/clearHaltedMessage.test.ts @@ -1,6 +1,7 @@ import { PrismaClient } from '@prisma/client'; -import { deleteHaltedMessage } from './deleteHaltedMessage'; +import { clearHaltedMessage } from './clearHaltedMessage'; import { getOrCreateAccount } from '../utils/getOrCreateAccount'; +import { addMessageBatch } from '../addMessageBatch'; // Mock the PrismaClient const mockDb = new PrismaClient(); @@ -13,7 +14,6 @@ describe('deleteHaltedMessage', () => { }); afterEach(async () => { - await prismaClient.haltedMessage.deleteMany({}); await prismaClient.encryptedMessage.deleteMany({}); await prismaClient.conversation.deleteMany({}); await prismaClient.account.deleteMany({}); @@ -21,8 +21,13 @@ describe('deleteHaltedMessage', () => { prismaClient.$disconnect(); }); it('should return false if account does not exist', async () => { - const result = await deleteHaltedMessage(mockDb)( - 'bob.eth', + const result = await clearHaltedMessage(mockDb)('bob.eth', 'messageId'); + expect(result).toBe(false); + }); + + it('should return false if message does not exist', async () => { + const result = await clearHaltedMessage(mockDb)( + 'existing', 'messageId', ); expect(result).toBe(false); @@ -31,26 +36,28 @@ describe('deleteHaltedMessage', () => { it('should return true if message is successfully deleted', async () => { const account = await getOrCreateAccount(prismaClient, 'bob.eth'); //create message first - await mockDb.haltedMessage.create({ - data: { - id: 'messageId', - createdAt: new Date(1234), - encryptedEnvelopContainer: 'encryptedEnvelopContainer', - ownerId: account.id, - }, - }); - const result = await deleteHaltedMessage(mockDb)( + const messageRecord1 = { + messageId: 'messageId1', + createdAt: 123, + encryptedEnvelopContainer: 'encryptedEnvelopContainer', + isHalted: true, + }; + const messageRecord2 = { + messageId: 'messageId2', + createdAt: 456, + encryptedEnvelopContainer: 'encryptedEnvelopContainer', + isHalted: false, + }; + + await addMessageBatch(prismaClient)('bob.eth', 'alice.eth', [ + messageRecord1, + messageRecord2, + ]); + + const result = await clearHaltedMessage(mockDb)( 'bob.eth', - 'messageId', + 'messageId1', ); expect(result).toBe(true); }); - - it('should return false if deletion fails', async () => { - const result = await deleteHaltedMessage(mockDb)( - 'existing', - 'messageId', - ); - expect(result).toBe(false); - }); }); diff --git a/packages/backend/src/persistence/storage/postgres/haltedMessage/deleteHaltedMessage.ts b/packages/backend/src/persistence/storage/postgres/haltedMessage/clearHaltedMessage.ts similarity index 58% rename from packages/backend/src/persistence/storage/postgres/haltedMessage/deleteHaltedMessage.ts rename to packages/backend/src/persistence/storage/postgres/haltedMessage/clearHaltedMessage.ts index d0b1284f7..191e23cd7 100644 --- a/packages/backend/src/persistence/storage/postgres/haltedMessage/deleteHaltedMessage.ts +++ b/packages/backend/src/persistence/storage/postgres/haltedMessage/clearHaltedMessage.ts @@ -1,6 +1,6 @@ import { PrismaClient } from '@prisma/client'; -export const deleteHaltedMessage = +export const clearHaltedMessage = (db: PrismaClient) => async (ensName: string, messageId: string) => { //Find the account first we want to get the messages for const account = await db.account.findFirst({ @@ -13,15 +13,29 @@ export const deleteHaltedMessage = return false; } + const message = await db.encryptedMessage.findFirst({ + where: { + id: messageId, + }, + }); + + if (!message) { + return false; + } + try { - await db.haltedMessage.delete({ + await db.encryptedMessage.update({ where: { id: messageId, }, + data: { + //Message is no longer halted + isHalted: false, + }, }); return true; } catch (e) { - console.error('deleteHaltedMessage error', e); + console.error('clear halted error', e); return false; } }; diff --git a/packages/backend/src/persistence/storage/postgres/haltedMessage/getHaltedMessages.test.ts b/packages/backend/src/persistence/storage/postgres/haltedMessage/getHaltedMessages.test.ts index 08b6f9904..f0c5ec50e 100644 --- a/packages/backend/src/persistence/storage/postgres/haltedMessage/getHaltedMessages.test.ts +++ b/packages/backend/src/persistence/storage/postgres/haltedMessage/getHaltedMessages.test.ts @@ -1,7 +1,8 @@ import { PrismaClient } from '@prisma/client'; import { getHaltedMessages } from './getHaltedMessages'; import { getOrCreateAccount } from '../utils/getOrCreateAccount'; -import { addHaltedMessage } from './addHaltedMessage'; +import { addMessageBatch } from '../addMessageBatch'; +import { clearHaltedMessage } from './clearHaltedMessage'; describe('getHaltedMessages', () => { let prismaClient: PrismaClient; @@ -11,29 +12,85 @@ describe('getHaltedMessages', () => { }); afterEach(async () => { - await prismaClient.haltedMessage.deleteMany({}); + await prismaClient.encryptedMessage.deleteMany({}); + await prismaClient.conversation.deleteMany({}); await prismaClient.account.deleteMany({}); prismaClient.$disconnect(); }); it('should get halted messages for a given account', async () => { const ensName = 'test'; - const messageRecord = { + const messageRecord1 = { + messageId: 'messageId1', + createdAt: 123, + encryptedEnvelopContainer: 'encrypted', + isHalted: true, + }; + + const messageRecord2 = { + messageId: 'messageId2', + createdAt: 456, + encryptedEnvelopContainer: 'encryptedEnvelopContainer', + isHalted: false, + }; + + await getOrCreateAccount(prismaClient, ensName); + await addMessageBatch(prismaClient)(ensName, 'alice.eth', [ + messageRecord1, + messageRecord2, + ]); + + const haltedMessages = await getHaltedMessages(prismaClient)(ensName); + + expect(haltedMessages).toHaveLength(1); + expect(haltedMessages[0]).toEqual({ + messageId: messageRecord1.messageId, + createdAt: new Date(123), + isHalted: true, + encryptedEnvelopContainer: messageRecord1.encryptedEnvelopContainer, + }); + }); + it('should not return messages that has been cleared', async () => { + const ensName = 'test'; + const messageRecord1 = { messageId: '1', createdAt: 123, encryptedEnvelopContainer: 'encrypted', + isHalted: true, + }; + + const messageRecord2 = { + messageId: 'messageId2', + createdAt: 456, + encryptedEnvelopContainer: 'encryptedEnvelopContainer', + isHalted: false, }; await getOrCreateAccount(prismaClient, ensName); - await addHaltedMessage(prismaClient)(ensName, messageRecord); + await addMessageBatch(prismaClient)(ensName, 'alice.eth', [ + messageRecord1, + messageRecord2, + ]); const haltedMessages = await getHaltedMessages(prismaClient)(ensName); + console.log(haltedMessages); expect(haltedMessages).toHaveLength(1); expect(haltedMessages[0]).toEqual({ - messageId: messageRecord.messageId, + messageId: messageRecord1.messageId, createdAt: new Date(123), - encryptedEnvelopContainer: messageRecord.encryptedEnvelopContainer, + isHalted: true, + encryptedEnvelopContainer: messageRecord1.encryptedEnvelopContainer, }); + + await clearHaltedMessage(prismaClient)( + ensName, + messageRecord1.messageId, + ); + + const haltedMessagesAfterClear = await getHaltedMessages(prismaClient)( + ensName, + ); + expect(haltedMessagesAfterClear).toHaveLength(0); }); }); diff --git a/packages/backend/src/persistence/storage/postgres/haltedMessage/getHaltedMessages.ts b/packages/backend/src/persistence/storage/postgres/haltedMessage/getHaltedMessages.ts index b262e744f..b643b0311 100644 --- a/packages/backend/src/persistence/storage/postgres/haltedMessage/getHaltedMessages.ts +++ b/packages/backend/src/persistence/storage/postgres/haltedMessage/getHaltedMessages.ts @@ -14,9 +14,10 @@ export const getHaltedMessages = return []; } - const messageRecord = await db.haltedMessage.findMany({ + const messageRecord = await db.encryptedMessage.findMany({ where: { ownerId: account.id, + isHalted: true, }, }); @@ -28,5 +29,6 @@ export const getHaltedMessages = messageId: message.id, encryptedEnvelopContainer: message.encryptedEnvelopContainer, createdAt: message.createdAt, + isHalted: message.isHalted, })); }; diff --git a/packages/backend/src/schema/storage/AddMessageBatchRequest.schema.json b/packages/backend/src/schema/storage/AddMessageBatchRequest.schema.json index 153b4f606..abd31670b 100644 --- a/packages/backend/src/schema/storage/AddMessageBatchRequest.schema.json +++ b/packages/backend/src/schema/storage/AddMessageBatchRequest.schema.json @@ -11,6 +11,9 @@ "encryptedEnvelopContainer": { "type": "string" }, + "isHalted": { + "type": "boolean" + }, "messageId": { "type": "string" } @@ -18,7 +21,8 @@ "required": [ "createdAt", "messageId", - "encryptedEnvelopContainer" + "encryptedEnvelopContainer", + "isHalted" ], "type": "object" }, diff --git a/packages/backend/src/schema/storage/AddMessageRequest.schema.json b/packages/backend/src/schema/storage/AddMessageRequest.schema.json index 1a923e698..b4474cdc8 100644 --- a/packages/backend/src/schema/storage/AddMessageRequest.schema.json +++ b/packages/backend/src/schema/storage/AddMessageRequest.schema.json @@ -14,6 +14,9 @@ "encryptedEnvelopContainer": { "type": "string" }, + "isHalted": { + "type": "boolean" + }, "messageId": { "type": "string" } @@ -22,7 +25,8 @@ "encryptedEnvelopContainer", "encryptedContactName", "messageId", - "createdAt" + "createdAt", + "isHalted" ], "type": "object" } diff --git a/packages/backend/src/schema/storage/AddMesssageRequest.ts b/packages/backend/src/schema/storage/AddMesssageRequest.ts index e678a8ef9..73c046bbf 100644 --- a/packages/backend/src/schema/storage/AddMesssageRequest.ts +++ b/packages/backend/src/schema/storage/AddMesssageRequest.ts @@ -10,6 +10,8 @@ export interface _AddMessageRequest { messageId: string; //The time the message was created, also defined by the client createdAt: number; + //The message is halted if the message has not been delivered yet + isHalted: boolean; } export const AddMessageRequest = AddMessageRequestSchema.definitions._AddMessageRequest; diff --git a/packages/backend/src/schema/storage/EditMessageBatchRequest.schema.json b/packages/backend/src/schema/storage/EditMessageBatchRequest.schema.json index 906133877..c5c786128 100644 --- a/packages/backend/src/schema/storage/EditMessageBatchRequest.schema.json +++ b/packages/backend/src/schema/storage/EditMessageBatchRequest.schema.json @@ -11,6 +11,9 @@ "encryptedEnvelopContainer": { "type": "string" }, + "isHalted": { + "type": "boolean" + }, "messageId": { "type": "string" } @@ -18,7 +21,8 @@ "required": [ "createdAt", "messageId", - "encryptedEnvelopContainer" + "encryptedEnvelopContainer", + "isHalted" ], "type": "object" }, diff --git a/packages/backend/src/storage.test.ts b/packages/backend/src/storage.test.ts index 2beceacf2..1e27b9d7d 100644 --- a/packages/backend/src/storage.test.ts +++ b/packages/backend/src/storage.test.ts @@ -123,7 +123,6 @@ describe('Storage', () => { }); afterEach(async () => { - await prisma.haltedMessage.deleteMany(); await prisma.encryptedMessage.deleteMany(); await prisma.conversation.deleteMany(); await prisma.account.deleteMany(); @@ -457,6 +456,7 @@ describe('Storage', () => { encryptedContactName: sha256(receiver.account.ensName), messageId: '123', createdAt: 0, + isHalted: false, }); await request(app) .post(`/new/bob.eth/addMessage`) @@ -468,6 +468,7 @@ describe('Storage', () => { encryptedContactName: sha256(receiver.account.ensName), messageId: '456', createdAt: 1, + isHalted: false, }); await request(app) .post(`/new/bob.eth/addMessage`) @@ -479,6 +480,7 @@ describe('Storage', () => { encryptedContactName: sha256(receiver.account.ensName), messageId: '789', createdAt: 2, + isHalted: false, }); const { body } = await request(app) @@ -622,6 +624,7 @@ describe('Storage', () => { encryptedContactName: sha256(receiver.account.ensName), messageId: '123', createdAt: 1, + isHalted: false, }); expect(status).toBe(200); @@ -675,6 +678,7 @@ describe('Storage', () => { encryptedContactName: sha256(receiver.account.ensName), messageId: sha256('bob.eth' + '123'), createdAt: 2, + isHalted: false, }); const tokenAlice = generateAuthJWT('alice.eth', serverSecret); @@ -689,6 +693,7 @@ describe('Storage', () => { encryptedContactName: sha256(sender.account.ensName), messageId: sha256('alice.eth' + '123'), createdAt: 2, + isHalted: false, }); const { body: bobConversations } = await request(app) @@ -794,6 +799,7 @@ describe('Storage', () => { encryptedContactName: 'alice.eth', messageId: sha256('alice.eth' + '123'), createdAt: 1, + isHalted: false, }); const { body: bobConversations } = await request(app) @@ -837,6 +843,7 @@ describe('Storage', () => { encryptedContactName: sha256(receiver.account.ensName), messageId: '123', createdAt: 2, + isHalted: false, }); expect(status).toBe(200); @@ -890,6 +897,7 @@ describe('Storage', () => { encryptedContactName: sha256(receiver.account.ensName), messageId: '123', createdAt: 1, + isHalted: false, }); await request(app) .post(`/new/bob.eth/addMessage`) @@ -901,6 +909,7 @@ describe('Storage', () => { encryptedContactName: sha256(receiver.account.ensName), messageId: '456', createdAt: 2, + isHalted: false, }); const { status } = await request(app) @@ -913,6 +922,7 @@ describe('Storage', () => { encryptedContactName: sha256(receiver.account.ensName), messageId: '123', createdAt: 3, + isHalted: false, }); expect(status).toBe(400); @@ -952,89 +962,7 @@ describe('Storage', () => { }); }); describe('halted Messages', () => { - describe('schema', () => { - it('should return 400 if encryptedEnvelopContainer is missing', async () => { - const body = { - encryptedContactName: 'encryptedContactName', - messageId: 'messageId', - createdAt: 123, - }; - const response = await request(app) - .post('/new/bob.eth/addHaltedMessage') - .set({ - authorization: 'Bearer ' + token, - }) - .send(body); - expect(response.status).toBe(400); - }); - - it('should return 400 if messageId is missing', async () => { - const body = { - encryptedEnvelopContainer: 'encryptedEnvelopContainer', - createdAt: 123, - }; - const response = await request(app) - .post('/new/bob.eth/addHaltedMessage') - .set({ - authorization: 'Bearer ' + token, - }) - .send(body); - expect(response.status).toBe(400); - }); - - it('should return 400 if createdAt is missing', async () => { - const body = { - encryptedEnvelopContainer: 'encryptedEnvelopContainer', - encryptedContactName: 'encryptedContactName', - messageId: 'messageId', - }; - const response = await request(app) - .post('/new/bob.eth/addHaltedMessage') - .set({ - authorization: 'Bearer ' + token, - }) - .send(body); - expect(response.status).toBe(400); - }); - }); - it('can add halted message', async () => { - const messageFactory = MockMessageFactory( - sender, - receiver, - deliveryService, - ); - const envelop1 = await messageFactory.createEncryptedEnvelop( - 'Hello1', - ); - - const { status } = await request(app) - .post(`/new/bob.eth/addHaltedMessage`) - .set({ - authorization: 'Bearer ' + token, - }) - .send({ - encryptedEnvelopContainer: JSON.stringify(envelop1), - messageId: '123', - createdAt: 1, - }); - expect(status).toBe(200); - - const { status: getMessagesStatus, body: messages } = await request( - app, - ) - .get(`/new/bob.eth/getHaltedMessages/`) - .set({ - authorization: 'Bearer ' + token, - }) - .send(); - - expect(getMessagesStatus).toBe(200); - expect(messages.length).toBe(1); - expect( - JSON.parse(messages[0].encryptedEnvelopContainer), - ).toStrictEqual(envelop1); - }); - it('can delete halted message', async () => { + it('clears halted message', async () => { const messageFactory = MockMessageFactory( sender, receiver, @@ -1045,14 +973,16 @@ describe('Storage', () => { ); const { status } = await request(app) - .post(`/new/bob.eth/addHaltedMessage`) + .post(`/new/bob.eth/addMessage`) .set({ authorization: 'Bearer ' + token, }) .send({ encryptedEnvelopContainer: JSON.stringify(envelop1), + encryptedContactName: sha256(receiver.account.ensName), messageId: '123', createdAt: 1, + isHalted: true, }); expect(status).toBe(200); @@ -1072,7 +1002,7 @@ describe('Storage', () => { ).toStrictEqual(envelop1); const { status: deleteStatus } = await request(app) - .post(`/new/bob.eth/deleteHaltedMessage/`) + .post(`/new/bob.eth/clearHaltedMessage/`) .set({ authorization: 'Bearer ' + token, }) @@ -1166,11 +1096,13 @@ describe('Storage', () => { encryptedEnvelopContainer: JSON.stringify(envelop), messageId: '123', createdAt: 1, + isHalted: false, }, { encryptedEnvelopContainer: JSON.stringify(envelop), messageId: '456', createdAt: 2, + isHalted: false, }, ], }); @@ -1217,7 +1149,7 @@ describe('Storage', () => { const envelop = await messageFactory.createEncryptedEnvelop( 'Hello1', ); - await request(app) + const x = await request(app) .post(`/new/bob.eth/addMessage`) .set({ authorization: 'Bearer ' + token, @@ -1227,8 +1159,12 @@ describe('Storage', () => { encryptedContactName: sha256(receiver.account.ensName), messageId: '123', createdAt: 1, + isHalted: false, }); + console.log('xxxx', x.status); + console.log('xxxx', x.body); + await request(app) .post(`/new/bob.eth/addMessage`) .set({ @@ -1239,6 +1175,7 @@ describe('Storage', () => { encryptedContactName: sha256(receiver.account.ensName), messageId: '456', createdAt: 2, + isHalted: false, }); const { status: addDuplicateStatus } = await request(app) @@ -1251,6 +1188,7 @@ describe('Storage', () => { encryptedContactName: sha256(receiver.account.ensName), messageId: '123', createdAt: 3, + isHalted: false, }); const { status, body } = await request(app) @@ -1322,6 +1260,7 @@ describe('Storage', () => { messageId: 'testMessageId', encryptedEnvelopContainer: 'testEncryptedEnvelopContainer', + isHalted: false, }, ], }; @@ -1370,6 +1309,7 @@ describe('Storage', () => { createdAt: 123, messageId: 'testMessageId', encryptedEnvelopContainer: 'testEncryptedEnvelopContainer', + isHalted: false, }, ]; @@ -1406,6 +1346,7 @@ describe('Storage', () => { createdAt: 123, messageId: 'testMessageId', encryptedEnvelopContainer: 'testEncryptedEnvelopContainer', + isHalted: false, }, ]; const { status } = await request(app) @@ -1418,6 +1359,7 @@ describe('Storage', () => { encryptedContactName: sha256(receiver.account.ensName), messageId: '123', createdAt: 123456, + isHalted: false, }); expect(status).toBe(200); @@ -1426,6 +1368,7 @@ describe('Storage', () => { createdAt: 123, messageId: 'testMessageId', encryptedEnvelopContainer: 'NEW ENVELOP', + isHalted: false, }, ]; diff --git a/packages/backend/src/storage.ts b/packages/backend/src/storage.ts index 1f8777ef9..8c8bac9b3 100644 --- a/packages/backend/src/storage.ts +++ b/packages/backend/src/storage.ts @@ -73,6 +73,7 @@ export default ( encryptedContactName, messageId, createdAt, + isHalted, } = req.body; const schemaIsValid = validateSchema(AddMessageRequest, req.body); @@ -95,6 +96,7 @@ export default ( messageId: uniqueMessageId, encryptedEnvelopContainer, createdAt, + isHalted, }, ], ); @@ -264,39 +266,8 @@ export default ( next(err); } }); - router.post('/new/:ensName/addHaltedMessage', async (req, res, next) => { - try { - const schemaIsValid = validateSchema( - AddHaltedMessageRequest, - req.body, - ); - if (!schemaIsValid) { - res.status(400).send('invalid schema'); - return; - } - const { encryptedEnvelopContainer, messageId, createdAt } = - req.body; - - const ensName = normalizeEnsName(req.params.ensName); - //Since the message is fully encrypted, we cannot use the messageHash as an identifier. - //Instead we use the hash of the ensName and the messageId to have a unique identifier - const uniqueMessageId = sha256(ensName + messageId); - const success = await db.addHaltedMessage(ensName, { - messageId: uniqueMessageId, - createdAt, - encryptedEnvelopContainer, - }); - - if (success) { - return res.send(); - } - res.status(400).send('unable to add halted message'); - } catch (err) { - next(err); - } - }); - router.post('/new/:ensName/deleteHaltedMessage', async (req, res, next) => { + router.post('/new/:ensName/clearHaltedMessage', async (req, res, next) => { try { const { messageId } = req.body; @@ -309,7 +280,7 @@ export default ( //Since the message is fully encrypted, we cannot use the messageHash as an identifier. //Instead we use the hash of the ensName and the messageId to have a unique identifier const uniqueMessageId = sha256(ensName + messageId); - const success = await db.deleteHaltedMessage( + const success = await db.clearHaltedMessage( ensName, uniqueMessageId, ); diff --git a/packages/messenger-widget/src/hooks/haltDelivery/useHaltDelivery.ts b/packages/messenger-widget/src/hooks/haltDelivery/useHaltDelivery.ts new file mode 100644 index 000000000..bd435c936 --- /dev/null +++ b/packages/messenger-widget/src/hooks/haltDelivery/useHaltDelivery.ts @@ -0,0 +1,3 @@ +export const useHaltDelivery = () => { + return {}; +}; From 659a966900759f46ad1ad2650d6fb93ce287c887 Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Fri, 5 Jul 2024 10:25:50 +0200 Subject: [PATCH 10/27] revert to database url from env --- packages/backend/schema.prisma | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/backend/schema.prisma b/packages/backend/schema.prisma index eafb19e7b..38bb48aaa 100644 --- a/packages/backend/schema.prisma +++ b/packages/backend/schema.prisma @@ -1,7 +1,7 @@ datasource db { //Use this URL for local development - url = "postgresql://prisma:prisma@localhost:5433/tests" - //url = env("DATABASE_URL") + //url = "postgresql://prisma:prisma@localhost:5433/tests" + url = env("DATABASE_URL") provider = "postgresql" } From 493ee2f66c68069ff6eee9ad84c52e9046b17e10 Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Fri, 5 Jul 2024 10:26:26 +0200 Subject: [PATCH 11/27] add isHalted to addMessage clientside --- .../storage/postgres/editMessageBatch.ts | 1 - packages/lib/shared/src/IBackendConnector.ts | 2 + .../src/new/cloudStorage/getCloudStorage.ts | 21 +++ packages/lib/storage/src/new/types.ts | 2 + .../src/context/BackendContext.tsx | 6 + .../src/context/StorageContext.tsx | 6 + .../testHelper/getMockedStorageContext.ts | 3 + .../conversation/useConversation.test.tsx | 29 ++-- .../haltDelivery/useHaltDelivery.test.tsx | 130 ++++++++++++++++++ .../src/hooks/haltDelivery/useHaltDelivery.ts | 11 ++ .../src/hooks/messages/useMessage.tsx | 3 +- .../src/hooks/server-side/BackendConnector.ts | 8 ++ .../src/hooks/server-side/useBackend.ts | 5 + .../src/hooks/storage/useStorage.tsx | 13 +- packages/messenger-widget/src/version.ts | 2 +- 15 files changed, 223 insertions(+), 19 deletions(-) create mode 100644 packages/messenger-widget/src/hooks/haltDelivery/useHaltDelivery.test.tsx diff --git a/packages/backend/src/persistence/storage/postgres/editMessageBatch.ts b/packages/backend/src/persistence/storage/postgres/editMessageBatch.ts index bbec9ac11..3a63cb2c3 100644 --- a/packages/backend/src/persistence/storage/postgres/editMessageBatch.ts +++ b/packages/backend/src/persistence/storage/postgres/editMessageBatch.ts @@ -10,7 +10,6 @@ export const editMessageBatch = encryptedContactName: string, editMessageBatchPayload: MessageRecord[], ) => { - console.log('editMessageBatchPayload', editMessageBatchPayload); const account = await getOrCreateAccount(db, ensName); await Promise.all( diff --git a/packages/lib/shared/src/IBackendConnector.ts b/packages/lib/shared/src/IBackendConnector.ts index b37dd01e4..12a8bd5a3 100644 --- a/packages/lib/shared/src/IBackendConnector.ts +++ b/packages/lib/shared/src/IBackendConnector.ts @@ -21,12 +21,14 @@ export interface IBackendConnector { pageSize: number, offset: number, ): Promise; + getHaltedMessages: (ensName: string) => Promise; addMessage( ensName: string, encryptedContactName: string, messageId: string, createdAt: number, encryptedEnvelopContainer: string, + isHalted: boolean, ): Promise; addMessageBatch( ensName: string, diff --git a/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts b/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts index cc6ca9333..3aa972fd6 100644 --- a/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts +++ b/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts @@ -72,10 +72,29 @@ export const getCloudStorage = ( return decryptedMessageRecords as StorageEnvelopContainer[]; }; + const getHaltedMessages = async () => { + const messages = await backendConnector.getHaltedMessages(ensName); + const decryptedMessages = await Promise.all( + messages.map(async (message: MessageRecord) => { + const decryptedEnvelopContainer = await encryption.decryptAsync( + message.encryptedEnvelopContainer, + ); + console.log( + 'decryptedEnvelopContainer haltedMessages', + decryptedEnvelopContainer, + ); + + return JSON.parse(decryptedEnvelopContainer); + }), + ); + + return decryptedMessages as StorageEnvelopContainer[]; + }; const _addMessage = async ( contactEnsName: string, envelop: StorageEnvelopContainer, + isHalted: boolean, ) => { const encryptedContactName = await encryption.encryptSync( contactEnsName, @@ -94,6 +113,7 @@ export const getCloudStorage = ( envelop.envelop.id, createdAt, encryptedEnvelopContainer, + isHalted, ); return ''; @@ -205,6 +225,7 @@ export const getCloudStorage = ( addMessage: _addMessage, addMessageBatch: _addMessageBatch, editMessageBatch: _editMessageBatch, + getHaltedMessages, getNumberOfMessages: _getNumberOfMessages, getNumberOfConverations: _getNumberOfConversations, toggleHideConversation: _toggleHideConversation, diff --git a/packages/lib/storage/src/new/types.ts b/packages/lib/storage/src/new/types.ts index 36bbab1cf..39fd1a2d9 100644 --- a/packages/lib/storage/src/new/types.ts +++ b/packages/lib/storage/src/new/types.ts @@ -7,6 +7,7 @@ export interface StorageAPI { pageSize: number, offset: number, ) => Promise; + getHaltedMessages: () => Promise; addMessageBatch: ( contactEnsName: string, batch: StorageEnvelopContainer[], @@ -21,6 +22,7 @@ export interface StorageAPI { addMessage: ( contactEnsName: string, envelop: StorageEnvelopContainer, + ishalted: boolean, ) => Promise; toggleHideConversation: ( contactEnsName: string, diff --git a/packages/messenger-widget/src/context/BackendContext.tsx b/packages/messenger-widget/src/context/BackendContext.tsx index 53b2ece63..608a11721 100644 --- a/packages/messenger-widget/src/context/BackendContext.tsx +++ b/packages/messenger-widget/src/context/BackendContext.tsx @@ -1,5 +1,6 @@ import React from 'react'; import { useBackend } from '../hooks/server-side/useBackend'; +import { MessageRecord } from '@dm3-org/dm3-lib-storage'; export type BackendContextType = { isInitialized: boolean; @@ -25,12 +26,14 @@ export type BackendContextType = { pageSize: number, offset: number, ) => Promise; + getHaltedMessages: (ensName: string) => Promise; addMessage: ( ensName: string, encryptedContactName: string, messageId: string, createdAt: number, encryptedEnvelopContainer: string, + isHalted: boolean, ) => Promise; addMessageBatch: ( ensName: string, @@ -55,6 +58,7 @@ export const BackendContext = React.createContext({ getConversations: async () => [], toggleHideConversation: () => {}, getMessagesFromStorage: async () => [], + getHaltedMessages: async (ensName: string) => [], addMessage: async () => {}, addMessageBatch: () => {}, editMessageBatch: () => {}, @@ -69,6 +73,7 @@ export const BackendContextProvider = ({ children }: { children?: any }) => { getConversations, toggleHideConversation, getMessagesFromStorage, + getHaltedMessages, addMessage, addMessageBatch, editMessageBatch, @@ -84,6 +89,7 @@ export const BackendContextProvider = ({ children }: { children?: any }) => { getConversations, toggleHideConversation, getMessagesFromStorage, + getHaltedMessages, addMessage, addMessageBatch, editMessageBatch, diff --git a/packages/messenger-widget/src/context/StorageContext.tsx b/packages/messenger-widget/src/context/StorageContext.tsx index a2bf8d254..d076e68b5 100644 --- a/packages/messenger-widget/src/context/StorageContext.tsx +++ b/packages/messenger-widget/src/context/StorageContext.tsx @@ -3,6 +3,7 @@ import React, { useContext } from 'react'; import { AddConversation, GetConversations, + GetHaltedMessages, GetMessages, GetNumberOfMessages, StoreMessageAsync, @@ -22,6 +23,7 @@ export type StorageContextType = { addConversationAsync: AddConversation; getNumberOfMessages: GetNumberOfMessages; getMessages: GetMessages; + getHaltedMessages: GetHaltedMessages; toggleHideContactAsync: ToggleHideContactAsync; initialized: boolean; }; @@ -30,6 +32,7 @@ export const StorageContext = React.createContext({ storeMessage: async ( contact: string, envelop: StorageEnvelopContainer, + isHalted?: boolean, ) => {}, storeMessageBatch: async ( contact: string, @@ -44,6 +47,7 @@ export const StorageContext = React.createContext({ addConversationAsync: (contact: string) => {}, getMessages: async (contact: string, pageSize: number, offset: number) => Promise.resolve([]), + getHaltedMessages: async () => Promise.resolve([]), getNumberOfMessages: async (contact: string) => Promise.resolve(0), toggleHideContactAsync: async (contact: string, value: boolean) => {}, initialized: false, @@ -61,6 +65,7 @@ export const StorageContextProvider = ({ children }: { children?: any }) => { addConversationAsync, getNumberOfMessages, getMessages, + getHaltedMessages, toggleHideContactAsync, initialized, } = useStorage(account, backendContext, profileKeys); @@ -74,6 +79,7 @@ export const StorageContextProvider = ({ children }: { children?: any }) => { addConversationAsync, getNumberOfMessages, getMessages, + getHaltedMessages, toggleHideContactAsync, initialized, }} diff --git a/packages/messenger-widget/src/context/testHelper/getMockedStorageContext.ts b/packages/messenger-widget/src/context/testHelper/getMockedStorageContext.ts index 3210e4784..25e993999 100644 --- a/packages/messenger-widget/src/context/testHelper/getMockedStorageContext.ts +++ b/packages/messenger-widget/src/context/testHelper/getMockedStorageContext.ts @@ -55,6 +55,9 @@ export const getMockedStorageContext = ( ): Promise { throw new Error('Function not implemented.'); }, + getHaltedMessages: function (): Promise { + throw new Error('Function not implemented.'); + }, toggleHideContactAsync: function ( contact: string, value: boolean, diff --git a/packages/messenger-widget/src/hooks/conversation/useConversation.test.tsx b/packages/messenger-widget/src/hooks/conversation/useConversation.test.tsx index 1c69506e5..e8f330ff3 100644 --- a/packages/messenger-widget/src/hooks/conversation/useConversation.test.tsx +++ b/packages/messenger-widget/src/hooks/conversation/useConversation.test.tsx @@ -2,13 +2,26 @@ import { Conversation, StorageEnvelopContainer, } from '@dm3-org/dm3-lib-storage'; +import { + MockDeliveryServiceProfile, + MockedUserProfile, + getMockDeliveryServiceProfile, + mockUserProfile, +} from '@dm3-org/dm3-lib-test-helper'; import '@testing-library/jest-dom'; import { act, renderHook, waitFor } from '@testing-library/react'; +import axios from 'axios'; +import MockAdapter from 'axios-mock-adapter'; +import { ethers } from 'ethers'; import { AuthContext, AuthContextType } from '../../context/AuthContext'; import { DeliveryServiceContext, DeliveryServiceContextType, } from '../../context/DeliveryServiceContext'; +import { + MainnetProviderContext, + MainnetProviderContextType, +} from '../../context/ProviderContext'; import { StorageContext, StorageContextType, @@ -20,25 +33,11 @@ import { DEFAULT_DM3_CONFIGURATION, getMockedDm3Configuration, } from '../../context/testHelper/getMockedDm3Configuration'; +import { getMockedMainnetProviderContext } from '../../context/testHelper/getMockedMainnetProviderContext'; import { getMockedStorageContext } from '../../context/testHelper/getMockedStorageContext'; import { getMockedTldContext } from '../../context/testHelper/getMockedTldContext'; import { DM3Configuration } from '../../widget'; import { useConversation } from './useConversation'; -import { - MainnetProviderContext, - MainnetProviderContextType, -} from '../../context/ProviderContext'; -import { getMockedMainnetProviderContext } from '../../context/testHelper/getMockedMainnetProviderContext'; -import { ethers } from 'ethers'; -import { - MockDeliveryServiceProfile, - MockedUserProfile, - getMockDeliveryServiceProfile, - mockUserProfile, -} from '@dm3-org/dm3-lib-test-helper'; -import MockAdapter from 'axios-mock-adapter'; -import axios from 'axios'; -import { Envelop } from '@dm3-org/dm3-lib-messaging'; describe('useConversation hook test cases', () => { let sender: MockedUserProfile; diff --git a/packages/messenger-widget/src/hooks/haltDelivery/useHaltDelivery.test.tsx b/packages/messenger-widget/src/hooks/haltDelivery/useHaltDelivery.test.tsx new file mode 100644 index 000000000..3a6767511 --- /dev/null +++ b/packages/messenger-widget/src/hooks/haltDelivery/useHaltDelivery.test.tsx @@ -0,0 +1,130 @@ +import { Conversation } from '@dm3-org/dm3-lib-storage'; +import { + MockDeliveryServiceProfile, + MockedUserProfile, + getMockDeliveryServiceProfile, + mockUserProfile, +} from '@dm3-org/dm3-lib-test-helper'; +import '@testing-library/jest-dom'; +import { renderHook } from '@testing-library/react'; +import MockAdapter from 'axios-mock-adapter'; +import { ethers } from 'ethers'; +import { AuthContext, AuthContextType } from '../../context/AuthContext'; +import { + DeliveryServiceContext, + DeliveryServiceContextType, +} from '../../context/DeliveryServiceContext'; +import { + StorageContext, + StorageContextType, +} from '../../context/StorageContext'; +import { getMockedAuthContext } from '../../context/testHelper/getMockedAuthContext'; +import { getMockedDeliveryServiceContext } from '../../context/testHelper/getMockedDeliveryServiceContext'; +import { + DEFAULT_DM3_CONFIGURATION, + getMockedDm3Configuration, +} from '../../context/testHelper/getMockedDm3Configuration'; +import { getMockedStorageContext } from '../../context/testHelper/getMockedStorageContext'; +import { DM3Configuration } from '../../widget'; +import { useHaltDelivery } from './useHaltDelivery'; + +describe('useConversation hook test cases', () => { + let sender: MockedUserProfile; + let receiver: MockedUserProfile; + let ds1: MockDeliveryServiceProfile; + let ds2: MockDeliveryServiceProfile; + + let axiosMock: MockAdapter; + + beforeEach(async () => { + sender = await mockUserProfile( + ethers.Wallet.createRandom(), + 'alice.eth', + ['ds1.eth', 'ds2.eth'], + ); + receiver = await mockUserProfile( + ethers.Wallet.createRandom(), + 'bob.eth', + ['ds1.eth'], + ); + ds1 = await getMockDeliveryServiceProfile( + ethers.Wallet.createRandom(), + 'http://ds1.api', + ); + ds2 = await getMockDeliveryServiceProfile( + ethers.Wallet.createRandom(), + 'http://ds2.api', + ); + }); + + const configurationContext = getMockedDm3Configuration({ + dm3Configuration: { + ...DEFAULT_DM3_CONFIGURATION, + }, + }); + const config: DM3Configuration = configurationContext.dm3Configuration!; + + describe('halt delivery', () => { + it('Should select a contact', async () => { + const authContext: AuthContextType = getMockedAuthContext({ + account: { + ensName: 'alice.eth', + profile: { + deliveryServices: ['ds.eth'], + publicEncryptionKey: '', + publicSigningKey: '', + }, + }, + }); + + const storageContext: StorageContextType = getMockedStorageContext({ + getConversations: function ( + page: number, + ): Promise { + return Promise.resolve([]); + }, + addConversationAsync: jest.fn(), + toggleHideContactAsync: jest.fn(), + initialized: true, + }); + const deliveryServiceContext: DeliveryServiceContextType = + getMockedDeliveryServiceContext({ + fetchIncommingMessages: function (ensName: string) { + return Promise.resolve([]); + }, + getDeliveryServiceProperties: function (): Promise { + return Promise.resolve([{ sizeLimit: 0 }]); + }, + isInitialized: true, + }); + + const wrapper = ({ children }: { children: any }) => ( + <> + + + + {children} + + + + + ); + const { result } = renderHook(() => useHaltDelivery(), { + wrapper, + }); + // await act(async () => result.current.addConversation(CONTACT_NAME)); + // expect(result.current.selectedContact).toBe(undefined); + // await act(async () => + // result.current.setSelectedContactName(CONTACT_NAME), + // ); + // await waitFor(() => { + // const { selectedContact } = result.current; + // expect(selectedContact?.contactDetails.account.ensName).toBe( + // CONTACT_NAME, + // ); + // }); + }); + }); +}); diff --git a/packages/messenger-widget/src/hooks/haltDelivery/useHaltDelivery.ts b/packages/messenger-widget/src/hooks/haltDelivery/useHaltDelivery.ts index bd435c936..ba7d06905 100644 --- a/packages/messenger-widget/src/hooks/haltDelivery/useHaltDelivery.ts +++ b/packages/messenger-widget/src/hooks/haltDelivery/useHaltDelivery.ts @@ -1,3 +1,14 @@ +import { useContext, useEffect } from 'react'; +import { StorageContext } from '../../context/StorageContext'; + export const useHaltDelivery = () => { + const { getHaltedMessages } = useContext(StorageContext); + useEffect(() => { + // Fetch all messages the user has halted. Then check if they can be delivered now. + const handleHaltedMessages = async () => { + const haltedMessages = await getHaltedMessages(); + }; + }, []); + return {}; }; diff --git a/packages/messenger-widget/src/hooks/messages/useMessage.tsx b/packages/messenger-widget/src/hooks/messages/useMessage.tsx index 703b828ef..ed6043eef 100644 --- a/packages/messenger-widget/src/hooks/messages/useMessage.tsx +++ b/packages/messenger-widget/src/hooks/messages/useMessage.tsx @@ -249,7 +249,8 @@ export const useMessage = () => { [contact]: [...(prev[contact] ?? []), messageModel], }; }); - storeMessage(contact, messageModel); + //Store the message and mark it as halted + storeMessage(contact, messageModel, true); return { isSuccess: true }; } diff --git a/packages/messenger-widget/src/hooks/server-side/BackendConnector.ts b/packages/messenger-widget/src/hooks/server-side/BackendConnector.ts index 0924b8012..8ad2ec069 100644 --- a/packages/messenger-widget/src/hooks/server-side/BackendConnector.ts +++ b/packages/messenger-widget/src/hooks/server-side/BackendConnector.ts @@ -70,12 +70,19 @@ export class BackendConnector ); } + public async getHaltedMessages(ensName: string) { + const url = `/storage/new/${normalizeEnsName(ensName)}/getMessages/`; + const { data } = await this.getAuthenticatedAxiosClient().get(url, {}); + return data ?? []; + } + public async addMessage( ensName: string, encryptedContactName: string, messageId: string, createdAt: number, encryptedEnvelopContainer: string, + isHalted: boolean, ) { const url = `/storage/new/${normalizeEnsName(ensName)}/addMessage`; await this.getAuthenticatedAxiosClient().post(url, { @@ -83,6 +90,7 @@ export class BackendConnector messageId, createdAt, encryptedEnvelopContainer, + isHalted, }); } diff --git a/packages/messenger-widget/src/hooks/server-side/useBackend.ts b/packages/messenger-widget/src/hooks/server-side/useBackend.ts index 4e81afc90..89d622d53 100644 --- a/packages/messenger-widget/src/hooks/server-side/useBackend.ts +++ b/packages/messenger-widget/src/hooks/server-side/useBackend.ts @@ -86,12 +86,16 @@ export const useBackend = (): IBackendConnector & { offset, ); }, + getHaltedMessages: async (ensName: string) => { + return beConnector?.getHaltedMessages(ensName); + }, addMessage: async ( ensName: string, encryptedContactName: string, messageId: string, createdAt: number, encryptedEnvelopContainer: string, + isHalted: boolean, ) => { return beConnector?.addMessage( ensName, @@ -99,6 +103,7 @@ export const useBackend = (): IBackendConnector & { messageId, createdAt, encryptedEnvelopContainer, + isHalted, ); }, addMessageBatch: ( diff --git a/packages/messenger-widget/src/hooks/storage/useStorage.tsx b/packages/messenger-widget/src/hooks/storage/useStorage.tsx index 927ddf714..496e0a225 100644 --- a/packages/messenger-widget/src/hooks/storage/useStorage.tsx +++ b/packages/messenger-widget/src/hooks/storage/useStorage.tsx @@ -101,11 +101,12 @@ export const useStorage = ( const storeMessageAsync = ( contact: string, envelop: StorageEnvelopContainerNew, + isHalted: boolean = false, ) => { if (!storageApi) { throw Error('Storage not initialized'); } - storageApi.addMessage(contact, envelop); + storageApi.addMessage(contact, envelop, isHalted); }; const storeMessageBatch = async ( contact: string, @@ -140,6 +141,13 @@ export const useStorage = ( return storageApi.getMessages(contact, pageSize, offset); }; + const getHaltedMessages = async () => { + if (!storageApi) { + return Promise.resolve([]); + } + return storageApi.getHaltedMessages(); + }; + const getNumberOfMessages = async (contact: string) => { if (!storageApi) { return Promise.resolve(0); @@ -161,6 +169,7 @@ export const useStorage = ( getConversations, addConversationAsync, getMessages, + getHaltedMessages, getNumberOfMessages, toggleHideContactAsync, initialized, @@ -170,6 +179,7 @@ export const useStorage = ( export type StoreMessageAsync = ( contact: string, envelop: StorageEnvelopContainerNew, + isHalted?: boolean, ) => void; export type editMessageBatchAsync = ( contact: string, @@ -189,5 +199,6 @@ export type GetMessages = ( pageSize: number, offset: number, ) => Promise; +export type GetHaltedMessages = () => Promise; export type GetNumberOfMessages = (contact: string) => Promise; export type ToggleHideContactAsync = (contact: string, value: boolean) => void; diff --git a/packages/messenger-widget/src/version.ts b/packages/messenger-widget/src/version.ts index d63c15fa1..68549e134 100644 --- a/packages/messenger-widget/src/version.ts +++ b/packages/messenger-widget/src/version.ts @@ -1 +1 @@ -export const version = '1.4.1'; +export const version = '1.4.3'; From 552bc0419bdbf96a59e1e8a6d68c17a43ebe4ab3 Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Fri, 5 Jul 2024 11:08:55 +0200 Subject: [PATCH 12/27] add useDelivery in useMEssage hook --- .../src/hooks/haltDelivery/useHaltDelivery.ts | 7 +++++-- .../messenger-widget/src/hooks/messages/useMessage.tsx | 4 ++++ .../src/hooks/server-side/BackendConnector.ts | 4 +++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/messenger-widget/src/hooks/haltDelivery/useHaltDelivery.ts b/packages/messenger-widget/src/hooks/haltDelivery/useHaltDelivery.ts index ba7d06905..3298033f3 100644 --- a/packages/messenger-widget/src/hooks/haltDelivery/useHaltDelivery.ts +++ b/packages/messenger-widget/src/hooks/haltDelivery/useHaltDelivery.ts @@ -2,13 +2,16 @@ import { useContext, useEffect } from 'react'; import { StorageContext } from '../../context/StorageContext'; export const useHaltDelivery = () => { - const { getHaltedMessages } = useContext(StorageContext); + const { getHaltedMessages, initialized: storageInitialized } = + useContext(StorageContext); useEffect(() => { // Fetch all messages the user has halted. Then check if they can be delivered now. const handleHaltedMessages = async () => { const haltedMessages = await getHaltedMessages(); + console.log('haltedMessages', haltedMessages); }; - }, []); + handleHaltedMessages(); + }, [storageInitialized]); return {}; }; diff --git a/packages/messenger-widget/src/hooks/messages/useMessage.tsx b/packages/messenger-widget/src/hooks/messages/useMessage.tsx index ed6043eef..bf9383a40 100644 --- a/packages/messenger-widget/src/hooks/messages/useMessage.tsx +++ b/packages/messenger-widget/src/hooks/messages/useMessage.tsx @@ -22,6 +22,7 @@ import { checkIfEnvelopAreInSizeLimit } from './sizeLimit/checkIfEnvelopIsInSize import { handleMessagesFromDeliveryService } from './sources/handleMessagesFromDeliveryService'; import { handleMessagesFromStorage } from './sources/handleMessagesFromStorage'; import { handleMessagesFromWebSocket } from './sources/handleMessagesFromWebSocket'; +import { useHaltDelivery } from '../haltDelivery/useHaltDelivery'; const DEFAULT_MESSAGE_PAGESIZE = 100; @@ -69,6 +70,9 @@ export const useMessage = () => { initialized: storageInitialized, } = useContext(StorageContext); + //load halt delivery here to be able to store messages as halted + useHaltDelivery(); + const [messages, setMessages] = useState({}); const [contactsLoading, setContactsLoading] = useState([]); diff --git a/packages/messenger-widget/src/hooks/server-side/BackendConnector.ts b/packages/messenger-widget/src/hooks/server-side/BackendConnector.ts index 8ad2ec069..64f5f6401 100644 --- a/packages/messenger-widget/src/hooks/server-side/BackendConnector.ts +++ b/packages/messenger-widget/src/hooks/server-side/BackendConnector.ts @@ -71,7 +71,9 @@ export class BackendConnector } public async getHaltedMessages(ensName: string) { - const url = `/storage/new/${normalizeEnsName(ensName)}/getMessages/`; + const url = `/storage/new/${normalizeEnsName( + ensName, + )}/getHaltedMessages/`; const { data } = await this.getAuthenticatedAxiosClient().get(url, {}); return data ?? []; } From 9dd8ba4df8414678a9856e5c8f15f8ce6942985a Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Fri, 5 Jul 2024 16:07:58 +0200 Subject: [PATCH 13/27] submit halted messgaes to receivers DS --- .../src/components/Contacts/Contacts.tsx | 1 - .../src/hooks/conversation/hydrateContact.ts | 44 +------- .../src/hooks/haltDelivery/useHaltDelivery.ts | 105 +++++++++++++++++- .../src/hooks/messages/useMessage.tsx | 20 +--- .../utils/deliveryService/fetchDsProfiles.ts | 46 ++++++++ .../submitEnvelopsToReceiversDs.ts | 19 ++++ 6 files changed, 173 insertions(+), 62 deletions(-) create mode 100644 packages/messenger-widget/src/utils/deliveryService/fetchDsProfiles.ts create mode 100644 packages/messenger-widget/src/utils/deliveryService/submitEnvelopsToReceiversDs.ts diff --git a/packages/messenger-widget/src/components/Contacts/Contacts.tsx b/packages/messenger-widget/src/components/Contacts/Contacts.tsx index a8b827a1d..63b07132c 100644 --- a/packages/messenger-widget/src/components/Contacts/Contacts.tsx +++ b/packages/messenger-widget/src/components/Contacts/Contacts.tsx @@ -112,7 +112,6 @@ export function Contacts() { const contact = contacts.find( (c) => c.contactDetails.account.ensName === _contact, ); - console.log('display preview msg', contact?.name, contact?.message); const previewMessage = contact?.message; return previewMessage ?? ''; }; diff --git a/packages/messenger-widget/src/hooks/conversation/hydrateContact.ts b/packages/messenger-widget/src/hooks/conversation/hydrateContact.ts index c9ea8ff81..131913726 100644 --- a/packages/messenger-widget/src/hooks/conversation/hydrateContact.ts +++ b/packages/messenger-widget/src/hooks/conversation/hydrateContact.ts @@ -1,15 +1,13 @@ import { Account, - DeliveryServiceProfile, - getDeliveryServiceProfile, getUserProfile, normalizeEnsName, } from '@dm3-org/dm3-lib-profile'; import { Conversation } from '@dm3-org/dm3-lib-storage/dist/new/types'; -import axios from 'axios'; import { ethers } from 'ethers'; import { Contact } from '../../interfaces/context'; import { ContactPreview } from '../../interfaces/utils'; +import { fetchDsProfiles } from '../../utils/deliveryService/fetchDsProfiles'; import { getAvatarProfilePic } from '../../utils/ens-utils'; import { fetchMessageSizeLimit } from '../messages/sizeLimit/fetchSizeLimit'; @@ -22,7 +20,7 @@ export const hydrateContract = async ( //If the profile property of the account is defined the user has already used DM3 previously const account = await _fetchAccount(provider, conversation.contactEnsName); //Has to become fetchMultipleDsProfiles - const contact = await _fetchDsProfiles(provider, account); + const contact = await fetchDsProfiles(provider, account); //get the maximum size limit by looking for the smallest size limit of every ds const maximumSizeLimit = await fetchMessageSizeLimit( @@ -89,41 +87,3 @@ const _fetchAccount = async ( }; } }; - -const _fetchDsProfiles = async ( - provider: ethers.providers.JsonRpcProvider, - account: Account, -): Promise => { - const deliveryServiceEnsNames = account.profile?.deliveryServices ?? []; - if (deliveryServiceEnsNames.length === 0) { - //If there is nop DS profile the message will be storaged at the client side until they recipient has createed an account - console.debug( - '[fetchDeliverServicePorfile] Cant resolve deliveryServiceEnsName', - ); - return { - account, - deliveryServiceProfiles: [], - }; - } - - //Resolve every ds profile in the contacts profile - const dsProfilesWithUnknowns = await Promise.all( - deliveryServiceEnsNames.map((deliveryServiceEnsName: string) => { - console.debug('fetch ds profile of', deliveryServiceEnsName); - return getDeliveryServiceProfile( - deliveryServiceEnsName, - provider!, - async (url: string) => (await axios.get(url)).data, - ); - }), - ); - //filter unknown profiles. A profile if unknown if the profile could not be fetched. We don't want to deal with them in the UI - const deliveryServiceProfiles = dsProfilesWithUnknowns.filter( - (profile): profile is DeliveryServiceProfile => profile !== undefined, - ); - - return { - account, - deliveryServiceProfiles, - }; -}; diff --git a/packages/messenger-widget/src/hooks/haltDelivery/useHaltDelivery.ts b/packages/messenger-widget/src/hooks/haltDelivery/useHaltDelivery.ts index 3298033f3..89f09bb5f 100644 --- a/packages/messenger-widget/src/hooks/haltDelivery/useHaltDelivery.ts +++ b/packages/messenger-widget/src/hooks/haltDelivery/useHaltDelivery.ts @@ -1,15 +1,118 @@ import { useContext, useEffect } from 'react'; import { StorageContext } from '../../context/StorageContext'; +import { TLDContext } from '../../context/TLDContext'; +import { + Account, + DeliveryServiceProfile, + getUserProfile, +} from '@dm3-org/dm3-lib-profile'; +import { MainnetProviderContext } from '../../context/ProviderContext'; +import { buildEnvelop } from '@dm3-org/dm3-lib-messaging'; +import { encryptAsymmetric } from '@dm3-org/dm3-lib-crypto'; +import { AuthContext } from '../../context/AuthContext'; +import { fetchDsProfiles } from '../../utils/deliveryService/fetchDsProfiles'; +import { submitEnvelopsToReceiversDs } from '../../utils/deliveryService/submitEnvelopsToReceiversDs'; export const useHaltDelivery = () => { const { getHaltedMessages, initialized: storageInitialized } = useContext(StorageContext); + + const { account: sendersAccount, profileKeys } = useContext(AuthContext); + const { provider } = useContext(MainnetProviderContext); + useEffect(() => { // Fetch all messages the user has halted. Then check if they can be delivered now. const handleHaltedMessages = async () => { const haltedMessages = await getHaltedMessages(); - console.log('haltedMessages', haltedMessages); + //Get all recipients of the halted messages + const recipients = Array.from( + new Set( + haltedMessages.map( + (message) => message.envelop.message.metadata.to, + ), + ), + ); + + //For each recipient, get the users account + const withAccounts = await Promise.all( + recipients.map(async (ensName) => ({ + ensName, + profile: (await getUserProfile(provider, ensName))?.profile, + })), + ); + //Filter out users that have no profile + const dm3Users = withAccounts.filter( + (account: Account) => account.profile !== undefined, + ); + + //for every dm3User find every message + + const dm3UsersWithMessages = dm3Users.map((dm3User) => { + const messages = haltedMessages.filter( + (message) => + message.envelop.message.metadata.to === dm3User.ensName, + ); + return { ...dm3User, messages }; + }); + + console.log('haltedMessages', dm3UsersWithMessages); + + console.log('withUserProfiles', withAccounts); + console.log('dm3Users', dm3Users); + //fetch the ds profiles of every recipient + + const withDsProfile = await Promise.all( + dm3UsersWithMessages.map(async (dm3User) => ({ + ...dm3User, + deliveryServiceProfiles: ( + await fetchDsProfiles(provider, dm3User) + ).deliveryServiceProfiles, + })), + ); + + const envelops = await Promise.all( + withDsProfile.map((receiverAccount) => { + return Promise.all( + //Outer loop gets through every message + receiverAccount.messages.map((message) => { + return Promise.all( + //Inner loop gets through every ds profile + //messsage x dsProfile = envelops + receiverAccount.deliveryServiceProfiles.map( + (dsProfile: DeliveryServiceProfile) => + buildEnvelop( + message.envelop.message, + (publicKey: string, msg: string) => + encryptAsymmetric( + publicKey, + msg, + ), + { + from: sendersAccount!, + to: receiverAccount!, + deliverServiceProfile: + dsProfile, + keys: profileKeys!, + }, + ), + ), + ); + }), + ); + }), + ); + //because we have a nested array we have to flatten it 2 times + //The envelops are now ready to be disptched + const dispatchableEnvelops = envelops.flat(2); + + console.log('flat dispatchableenvelops', dispatchableEnvelops); + + await submitEnvelopsToReceiversDs(dispatchableEnvelops); + + //Check if + // console.log('haltedMessages', resolvedAlias); }; + handleHaltedMessages(); }, [storageInitialized]); diff --git a/packages/messenger-widget/src/hooks/messages/useMessage.tsx b/packages/messenger-widget/src/hooks/messages/useMessage.tsx index bf9383a40..5ff2a7cf7 100644 --- a/packages/messenger-widget/src/hooks/messages/useMessage.tsx +++ b/packages/messenger-widget/src/hooks/messages/useMessage.tsx @@ -23,6 +23,7 @@ import { handleMessagesFromDeliveryService } from './sources/handleMessagesFromD import { handleMessagesFromStorage } from './sources/handleMessagesFromStorage'; import { handleMessagesFromWebSocket } from './sources/handleMessagesFromWebSocket'; import { useHaltDelivery } from '../haltDelivery/useHaltDelivery'; +import { submitEnvelopsToReceiversDs } from '../../utils/deliveryService/submitEnvelopsToReceiversDs'; const DEFAULT_MESSAGE_PAGESIZE = 100; @@ -330,27 +331,10 @@ export const useMessage = () => { }; } //Send the envelops to the delivery service - await submitEnveloptsToReceiversDs(envelops); + await submitEnvelopsToReceiversDs(envelops); return { isSuccess: true }; }; - const submitEnveloptsToReceiversDs = async ( - envelops: DispatchableEnvelop[], - ) => { - //Every DispatchableEnvelop is sent to the delivery service - await Promise.all( - envelops.map(async (envelop) => { - return await axios - .create({ baseURL: envelop.deliveryServiceUrl }) - .post('/rpc', { - jsonrpc: '2.0', - method: 'dm3_submitMessage', - params: [JSON.stringify(envelop.encryptedEnvelop)], - }); - }), - ); - }; - const loadInitialMessages = async (_contactName: string) => { const contactName = normalizeEnsName(_contactName); const initialMessages = await Promise.all([ diff --git a/packages/messenger-widget/src/utils/deliveryService/fetchDsProfiles.ts b/packages/messenger-widget/src/utils/deliveryService/fetchDsProfiles.ts new file mode 100644 index 000000000..ce7035296 --- /dev/null +++ b/packages/messenger-widget/src/utils/deliveryService/fetchDsProfiles.ts @@ -0,0 +1,46 @@ +import { + getDeliveryServiceProfile, + DeliveryServiceProfile, + Account, +} from '@dm3-org/dm3-lib-profile'; +import axios from 'axios'; +import { ethers } from 'ethers'; +import { Contact } from '../../interfaces/context'; + +export const fetchDsProfiles = async ( + provider: ethers.providers.JsonRpcProvider, + account: Account, +): Promise => { + const deliveryServiceEnsNames = account.profile?.deliveryServices ?? []; + if (deliveryServiceEnsNames.length === 0) { + //If there is nop DS profile the message will be storaged at the client side until they recipient has createed an account + console.debug( + '[fetchDeliverServicePorfile] Cant resolve deliveryServiceEnsName', + ); + return { + account, + deliveryServiceProfiles: [], + }; + } + + //Resolve every ds profile in the contacts profile + const dsProfilesWithUnknowns = await Promise.all( + deliveryServiceEnsNames.map((deliveryServiceEnsName: string) => { + console.debug('fetch ds profile of', deliveryServiceEnsName); + return getDeliveryServiceProfile( + deliveryServiceEnsName, + provider!, + async (url: string) => (await axios.get(url)).data, + ); + }), + ); + //filter unknown profiles. A profile if unknown if the profile could not be fetched. We don't want to deal with them in the UI + const deliveryServiceProfiles = dsProfilesWithUnknowns.filter( + (profile): profile is DeliveryServiceProfile => profile !== undefined, + ); + + return { + account, + deliveryServiceProfiles, + }; +}; diff --git a/packages/messenger-widget/src/utils/deliveryService/submitEnvelopsToReceiversDs.ts b/packages/messenger-widget/src/utils/deliveryService/submitEnvelopsToReceiversDs.ts new file mode 100644 index 000000000..81229b95e --- /dev/null +++ b/packages/messenger-widget/src/utils/deliveryService/submitEnvelopsToReceiversDs.ts @@ -0,0 +1,19 @@ +import { DispatchableEnvelop } from '@dm3-org/dm3-lib-messaging'; +import axios from 'axios'; + +export const submitEnvelopsToReceiversDs = async ( + envelops: DispatchableEnvelop[], +) => { + //Every DispatchableEnvelop is sent to the delivery service + await Promise.all( + envelops.map(async (envelop) => { + return await axios + .create({ baseURL: envelop.deliveryServiceUrl }) + .post('/rpc', { + jsonrpc: '2.0', + method: 'dm3_submitMessage', + params: [JSON.stringify(envelop.encryptedEnvelop)], + }); + }), + ); +}; From 71aaf948e5f6b92f0084a1ff504379906d62b7d7 Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Fri, 5 Jul 2024 16:14:57 +0200 Subject: [PATCH 14/27] add isHalted to addMessageBatch --- packages/backend/src/storage.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/backend/src/storage.ts b/packages/backend/src/storage.ts index 8c8bac9b3..b9bbce931 100644 --- a/packages/backend/src/storage.ts +++ b/packages/backend/src/storage.ts @@ -11,6 +11,7 @@ import { AddMessageRequest } from './schema/storage/AddMesssageRequest'; import { EditMessageBatchRequest } from './schema/storage/EditMessageBatchRequest'; import { PaginatedRequest } from './schema/storage/PaginatedRequest'; import { AddHaltedMessageRequest } from './schema/storage/AddHaltedMessageSchema'; +import { MessageRecord } from './persistence/storage'; const DEFAULT_CONVERSATION_PAGE_SIZE = 10; const DEFAULT_MESSAGE_PAGE_SIZE = 100; @@ -126,11 +127,12 @@ export default ( await db.addMessageBatch( ensName, encryptedContactName, - messageBatch.map((message: any) => ({ + messageBatch.map((message: MessageRecord) => ({ messageId: getUniqueMessageId(message.messageId), createdAt: message.createdAt, encryptedEnvelopContainer: message.encryptedEnvelopContainer, + isHalted: message.isHalted, })), ); return res.send(); From 3a2199f0e65ead4f15b689588c6c192b2e56ac3b Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Thu, 11 Jul 2024 14:50:34 +0200 Subject: [PATCH 15/27] add alias field to clearHaltedMessages --- .../backend/src/persistence/getDatabase.ts | 1 + .../haltedMessage/clearHaltedMessage.test.ts | 55 ++++++++++++++++++- .../haltedMessage/clearHaltedMessage.ts | 21 ++++++- .../haltedMessage/getHaltedMessages.test.ts | 1 + packages/backend/src/storage.ts | 4 +- 5 files changed, 79 insertions(+), 3 deletions(-) diff --git a/packages/backend/src/persistence/getDatabase.ts b/packages/backend/src/persistence/getDatabase.ts index 40def5519..faa510a6b 100644 --- a/packages/backend/src/persistence/getDatabase.ts +++ b/packages/backend/src/persistence/getDatabase.ts @@ -152,6 +152,7 @@ export interface IDatabase extends ISessionDatabase { getHaltedMessages: (ensName: string) => Promise; clearHaltedMessage: ( ensName: string, + aliasName: string, messageId: string, ) => Promise; getUserDbMigrationStatus: (ensName: string) => Promise; diff --git a/packages/backend/src/persistence/storage/postgres/haltedMessage/clearHaltedMessage.test.ts b/packages/backend/src/persistence/storage/postgres/haltedMessage/clearHaltedMessage.test.ts index a41f4fab9..4ee194c70 100644 --- a/packages/backend/src/persistence/storage/postgres/haltedMessage/clearHaltedMessage.test.ts +++ b/packages/backend/src/persistence/storage/postgres/haltedMessage/clearHaltedMessage.test.ts @@ -21,12 +21,17 @@ describe('deleteHaltedMessage', () => { prismaClient.$disconnect(); }); it('should return false if account does not exist', async () => { - const result = await clearHaltedMessage(mockDb)('bob.eth', 'messageId'); + const result = await clearHaltedMessage(mockDb)( + 'bob.eth', + 'bob.eth', + 'messageId', + ); expect(result).toBe(false); }); it('should return false if message does not exist', async () => { const result = await clearHaltedMessage(mockDb)( + 'existing', 'existing', 'messageId', ); @@ -56,8 +61,56 @@ describe('deleteHaltedMessage', () => { const result = await clearHaltedMessage(mockDb)( 'bob.eth', + 'bob.eth', + 'messageId1', + ); + expect(result).toBe(true); + }); + it('should rename to aliasName', async () => { + const account = await getOrCreateAccount(prismaClient, 'bob.eth'); + //create message first + const messageRecord1 = { + messageId: 'messageId1', + createdAt: 123, + encryptedEnvelopContainer: 'encryptedEnvelopContainer', + isHalted: true, + }; + const messageRecord2 = { + messageId: 'messageId2', + createdAt: 456, + encryptedEnvelopContainer: 'encryptedEnvelopContainer', + isHalted: false, + }; + + await addMessageBatch(prismaClient)('bob.eth', 'alice.eth', [ + messageRecord1, + messageRecord2, + ]); + + const beforeClearHaltedMessage = + await prismaClient.encryptedMessage.findFirst({ + where: { + id: 'messageId1', + }, + }); + + expect(beforeClearHaltedMessage?.encryptedContactName).toBe( + 'alice.eth', + ); + + const result = await clearHaltedMessage(mockDb)( + 'bob.eth', + '0x123.addr.dm3.eth', 'messageId1', ); + + const message = await prismaClient.encryptedMessage.findFirst({ + where: { + id: 'messageId1', + }, + }); + + expect(message?.encryptedContactName).toBe('0x123.addr.dm3.eth'); expect(result).toBe(true); }); }); diff --git a/packages/backend/src/persistence/storage/postgres/haltedMessage/clearHaltedMessage.ts b/packages/backend/src/persistence/storage/postgres/haltedMessage/clearHaltedMessage.ts index 191e23cd7..de01c6f8a 100644 --- a/packages/backend/src/persistence/storage/postgres/haltedMessage/clearHaltedMessage.ts +++ b/packages/backend/src/persistence/storage/postgres/haltedMessage/clearHaltedMessage.ts @@ -1,7 +1,15 @@ import { PrismaClient } from '@prisma/client'; export const clearHaltedMessage = - (db: PrismaClient) => async (ensName: string, messageId: string) => { + (db: PrismaClient) => + /** + * + * @param ensName the ensName the messages have been stored originally i.E alice.eth + * @param aliasName the aliasNamespace the cleint uses after resolving the ensName i.E Alice. ie addr.user.dm3.eth + * @param messageId the messageId + * @returns + */ + async (ensName: string, aliasName: string, messageId: string) => { //Find the account first we want to get the messages for const account = await db.account.findFirst({ where: { @@ -31,6 +39,17 @@ export const clearHaltedMessage = data: { //Message is no longer halted isHalted: false, + //Use alias name + encryptedContactName: aliasName, + }, + }); + + await db.conversation.update({ + where: { + id: message.conversationId, + }, + data: { + encryptedContactName: aliasName, }, }); return true; diff --git a/packages/backend/src/persistence/storage/postgres/haltedMessage/getHaltedMessages.test.ts b/packages/backend/src/persistence/storage/postgres/haltedMessage/getHaltedMessages.test.ts index f0c5ec50e..8e8e64131 100644 --- a/packages/backend/src/persistence/storage/postgres/haltedMessage/getHaltedMessages.test.ts +++ b/packages/backend/src/persistence/storage/postgres/haltedMessage/getHaltedMessages.test.ts @@ -84,6 +84,7 @@ describe('getHaltedMessages', () => { }); await clearHaltedMessage(prismaClient)( + ensName, ensName, messageRecord1.messageId, ); diff --git a/packages/backend/src/storage.ts b/packages/backend/src/storage.ts index b9bbce931..bcb479bf0 100644 --- a/packages/backend/src/storage.ts +++ b/packages/backend/src/storage.ts @@ -271,7 +271,7 @@ export default ( router.post('/new/:ensName/clearHaltedMessage', async (req, res, next) => { try { - const { messageId } = req.body; + const { messageId, aliasName } = req.body; if (!messageId) { res.status(400).send('invalid schema'); @@ -284,6 +284,8 @@ export default ( const uniqueMessageId = sha256(ensName + messageId); const success = await db.clearHaltedMessage( ensName, + //If the aliasName is not provided, we use the ensName as the client has no intention to use an alias + aliasName ?? ensName, uniqueMessageId, ); From 1858b3df11c1ac747ff49f3821591d4a9f900c29 Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Thu, 11 Jul 2024 15:50:40 +0200 Subject: [PATCH 16/27] finish halt Delivery for addresses --- .../lib/storage/src/new/cloudStorage/getCloudStorage.ts | 1 + .../src/hooks/haltDelivery/useHaltDelivery.ts | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts b/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts index 3aa972fd6..e5a9f922a 100644 --- a/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts +++ b/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts @@ -178,6 +178,7 @@ export const getCloudStorage = ( storageEnvelopContainer.envelop.metadata ?.encryptedMessageHash!, createdAt, + isHalted: false, }; }, ), diff --git a/packages/messenger-widget/src/hooks/haltDelivery/useHaltDelivery.ts b/packages/messenger-widget/src/hooks/haltDelivery/useHaltDelivery.ts index 89f09bb5f..4c7844f70 100644 --- a/packages/messenger-widget/src/hooks/haltDelivery/useHaltDelivery.ts +++ b/packages/messenger-widget/src/hooks/haltDelivery/useHaltDelivery.ts @@ -21,6 +21,9 @@ export const useHaltDelivery = () => { const { provider } = useContext(MainnetProviderContext); useEffect(() => { + if (!storageInitialized) { + return; + } // Fetch all messages the user has halted. Then check if they can be delivered now. const handleHaltedMessages = async () => { const haltedMessages = await getHaltedMessages(); @@ -108,9 +111,6 @@ export const useHaltDelivery = () => { console.log('flat dispatchableenvelops', dispatchableEnvelops); await submitEnvelopsToReceiversDs(dispatchableEnvelops); - - //Check if - // console.log('haltedMessages', resolvedAlias); }; handleHaltedMessages(); From 79085a0d66408b0066faf816d68f4de6b2939c6e Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Fri, 12 Jul 2024 10:52:32 +0200 Subject: [PATCH 17/27] add clearHaltedMessages to client --- packages/backend/src/storage.ts | 4 +- packages/lib/shared/src/IBackendConnector.ts | 5 + .../src/new/cloudStorage/getCloudStorage.ts | 13 +++ packages/lib/storage/src/new/types.ts | 4 + packages/messenger-demo/src/App.tsx | 2 +- .../src/context/BackendContext.tsx | 8 ++ .../src/context/StorageContext.tsx | 6 ++ .../testHelper/getMockedStorageContext.ts | 6 ++ .../src/hooks/haltDelivery/useHaltDelivery.ts | 93 ++++++++++++++----- .../src/hooks/server-side/BackendConnector.ts | 14 +++ .../src/hooks/server-side/useBackend.ts | 12 +++ .../src/hooks/storage/useStorage.tsx | 14 +++ 12 files changed, 156 insertions(+), 25 deletions(-) diff --git a/packages/backend/src/storage.ts b/packages/backend/src/storage.ts index bcb479bf0..a710f706a 100644 --- a/packages/backend/src/storage.ts +++ b/packages/backend/src/storage.ts @@ -292,8 +292,10 @@ export default ( if (success) { return res.send(); } - res.status(400).send('unable to add halted message'); + res.status(400).send('unable to clear halted message'); } catch (err) { + console.error('clearHaltedMessage error'); + console.error(err); next(err); } }); diff --git a/packages/lib/shared/src/IBackendConnector.ts b/packages/lib/shared/src/IBackendConnector.ts index 12a8bd5a3..f950a9e78 100644 --- a/packages/lib/shared/src/IBackendConnector.ts +++ b/packages/lib/shared/src/IBackendConnector.ts @@ -22,6 +22,11 @@ export interface IBackendConnector { offset: number, ): Promise; getHaltedMessages: (ensName: string) => Promise; + clearHaltedMessages: ( + ensName: string, + messageId: string, + aliasName: string, + ) => Promise; addMessage( ensName: string, encryptedContactName: string, diff --git a/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts b/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts index e5a9f922a..c4b4c435b 100644 --- a/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts +++ b/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts @@ -91,6 +91,18 @@ export const getCloudStorage = ( return decryptedMessages as StorageEnvelopContainer[]; }; + const clearHaltedMessages = async ( + messageId: string, + aliasName: string, + ) => { + const encryptedAliasName = await encryption.encryptSync(aliasName); + await backendConnector.clearHaltedMessages( + ensName, + messageId, + encryptedAliasName, + ); + }; + const _addMessage = async ( contactEnsName: string, envelop: StorageEnvelopContainer, @@ -227,6 +239,7 @@ export const getCloudStorage = ( addMessageBatch: _addMessageBatch, editMessageBatch: _editMessageBatch, getHaltedMessages, + clearHaltedMessages, getNumberOfMessages: _getNumberOfMessages, getNumberOfConverations: _getNumberOfConversations, toggleHideConversation: _toggleHideConversation, diff --git a/packages/lib/storage/src/new/types.ts b/packages/lib/storage/src/new/types.ts index 39fd1a2d9..d99afdbd5 100644 --- a/packages/lib/storage/src/new/types.ts +++ b/packages/lib/storage/src/new/types.ts @@ -8,6 +8,10 @@ export interface StorageAPI { offset: number, ) => Promise; getHaltedMessages: () => Promise; + clearHaltedMessages: ( + messageId: string, + aliasName: string, + ) => Promise; addMessageBatch: ( contactEnsName: string, batch: StorageEnvelopContainer[], diff --git a/packages/messenger-demo/src/App.tsx b/packages/messenger-demo/src/App.tsx index a19bb5b1e..06442e444 100644 --- a/packages/messenger-demo/src/App.tsx +++ b/packages/messenger-demo/src/App.tsx @@ -25,7 +25,7 @@ import { DM3, DM3Configuration } from '@dm3-org/dm3-messenger-widget'; // {children} // // ); -// }; +// };p function App() { const props: DM3Configuration = { diff --git a/packages/messenger-widget/src/context/BackendContext.tsx b/packages/messenger-widget/src/context/BackendContext.tsx index 608a11721..1593ccdf9 100644 --- a/packages/messenger-widget/src/context/BackendContext.tsx +++ b/packages/messenger-widget/src/context/BackendContext.tsx @@ -27,6 +27,11 @@ export type BackendContextType = { offset: number, ) => Promise; getHaltedMessages: (ensName: string) => Promise; + clearHaltedMessages: ( + ensName: string, + aliasName: string, + messageId: string, + ) => Promise; addMessage: ( ensName: string, encryptedContactName: string, @@ -59,6 +64,7 @@ export const BackendContext = React.createContext({ toggleHideConversation: () => {}, getMessagesFromStorage: async () => [], getHaltedMessages: async (ensName: string) => [], + clearHaltedMessages: async () => {}, addMessage: async () => {}, addMessageBatch: () => {}, editMessageBatch: () => {}, @@ -74,6 +80,7 @@ export const BackendContextProvider = ({ children }: { children?: any }) => { toggleHideConversation, getMessagesFromStorage, getHaltedMessages, + clearHaltedMessages, addMessage, addMessageBatch, editMessageBatch, @@ -90,6 +97,7 @@ export const BackendContextProvider = ({ children }: { children?: any }) => { toggleHideConversation, getMessagesFromStorage, getHaltedMessages, + clearHaltedMessages, addMessage, addMessageBatch, editMessageBatch, diff --git a/packages/messenger-widget/src/context/StorageContext.tsx b/packages/messenger-widget/src/context/StorageContext.tsx index d076e68b5..69ae2603b 100644 --- a/packages/messenger-widget/src/context/StorageContext.tsx +++ b/packages/messenger-widget/src/context/StorageContext.tsx @@ -2,6 +2,7 @@ import { StorageEnvelopContainer } from '@dm3-org/dm3-lib-storage'; import React, { useContext } from 'react'; import { AddConversation, + ClearHaltedMessages, GetConversations, GetHaltedMessages, GetMessages, @@ -24,6 +25,7 @@ export type StorageContextType = { getNumberOfMessages: GetNumberOfMessages; getMessages: GetMessages; getHaltedMessages: GetHaltedMessages; + clearHaltedMessages: ClearHaltedMessages; toggleHideContactAsync: ToggleHideContactAsync; initialized: boolean; }; @@ -48,6 +50,8 @@ export const StorageContext = React.createContext({ getMessages: async (contact: string, pageSize: number, offset: number) => Promise.resolve([]), getHaltedMessages: async () => Promise.resolve([]), + clearHaltedMessages: async (messageId: string, aliasName: string) => + Promise.resolve(), getNumberOfMessages: async (contact: string) => Promise.resolve(0), toggleHideContactAsync: async (contact: string, value: boolean) => {}, initialized: false, @@ -66,6 +70,7 @@ export const StorageContextProvider = ({ children }: { children?: any }) => { getNumberOfMessages, getMessages, getHaltedMessages, + clearHaltedMessages, toggleHideContactAsync, initialized, } = useStorage(account, backendContext, profileKeys); @@ -80,6 +85,7 @@ export const StorageContextProvider = ({ children }: { children?: any }) => { getNumberOfMessages, getMessages, getHaltedMessages, + clearHaltedMessages, toggleHideContactAsync, initialized, }} diff --git a/packages/messenger-widget/src/context/testHelper/getMockedStorageContext.ts b/packages/messenger-widget/src/context/testHelper/getMockedStorageContext.ts index 25e993999..aeeebf04a 100644 --- a/packages/messenger-widget/src/context/testHelper/getMockedStorageContext.ts +++ b/packages/messenger-widget/src/context/testHelper/getMockedStorageContext.ts @@ -58,6 +58,12 @@ export const getMockedStorageContext = ( getHaltedMessages: function (): Promise { throw new Error('Function not implemented.'); }, + clearHaltedMessages: function ( + messageId: string, + aliasName: string, + ): Promise { + throw new Error('Function not implemented.'); + }, toggleHideContactAsync: function ( contact: string, value: boolean, diff --git a/packages/messenger-widget/src/hooks/haltDelivery/useHaltDelivery.ts b/packages/messenger-widget/src/hooks/haltDelivery/useHaltDelivery.ts index 4c7844f70..f215e0322 100644 --- a/packages/messenger-widget/src/hooks/haltDelivery/useHaltDelivery.ts +++ b/packages/messenger-widget/src/hooks/haltDelivery/useHaltDelivery.ts @@ -7,18 +7,22 @@ import { getUserProfile, } from '@dm3-org/dm3-lib-profile'; import { MainnetProviderContext } from '../../context/ProviderContext'; -import { buildEnvelop } from '@dm3-org/dm3-lib-messaging'; +import { DispatchableEnvelop, buildEnvelop } from '@dm3-org/dm3-lib-messaging'; import { encryptAsymmetric } from '@dm3-org/dm3-lib-crypto'; import { AuthContext } from '../../context/AuthContext'; import { fetchDsProfiles } from '../../utils/deliveryService/fetchDsProfiles'; import { submitEnvelopsToReceiversDs } from '../../utils/deliveryService/submitEnvelopsToReceiversDs'; export const useHaltDelivery = () => { - const { getHaltedMessages, initialized: storageInitialized } = - useContext(StorageContext); + const { + getHaltedMessages, + clearHaltedMessages, + initialized: storageInitialized, + } = useContext(StorageContext); const { account: sendersAccount, profileKeys } = useContext(AuthContext); const { provider } = useContext(MainnetProviderContext); + const { resolveTLDtoAlias } = useContext(TLDContext); useEffect(() => { if (!storageInitialized) { @@ -35,14 +39,34 @@ export const useHaltDelivery = () => { ), ), ); - - //For each recipient, get the users account - const withAccounts = await Promise.all( + //Resolve the tldNames to their aliases + const resolvedAliases = await Promise.all( recipients.map(async (ensName) => ({ ensName, - profile: (await getUserProfile(provider, ensName))?.profile, + aliasName: await resolveTLDtoAlias(ensName), })), ); + + console.log('resolvedAliases', resolvedAliases); + + //For each recipient, get the users account + const withAccounts = await Promise.all( + resolvedAliases.map( + async ({ + ensName, + aliasName, + }: { + ensName: string; + aliasName: string; + }) => ({ + ensName, + aliasName, + profile: ( + await getUserProfile(provider, aliasName) + )?.profile, + }), + ), + ); //Filter out users that have no profile const dm3Users = withAccounts.filter( (account: Account) => account.profile !== undefined, @@ -82,22 +106,36 @@ export const useHaltDelivery = () => { //Inner loop gets through every ds profile //messsage x dsProfile = envelops receiverAccount.deliveryServiceProfiles.map( - (dsProfile: DeliveryServiceProfile) => - buildEnvelop( - message.envelop.message, - (publicKey: string, msg: string) => - encryptAsymmetric( - publicKey, - msg, - ), - { - from: sendersAccount!, - to: receiverAccount!, - deliverServiceProfile: - dsProfile, - keys: profileKeys!, - }, - ), + async ( + dsProfile: DeliveryServiceProfile, + ) => { + //build the dispatchable envelop + const dispatchableEnvelop = + await buildEnvelop( + message.envelop.message, + ( + publicKey: string, + msg: string, + ) => + encryptAsymmetric( + publicKey, + msg, + ), + { + from: sendersAccount!, + to: receiverAccount!, + deliverServiceProfile: + dsProfile, + keys: profileKeys!, + }, + ); + return { + ...dispatchableEnvelop, + //we keep the alias name for the receiver. In case it differes from the ensName + aliasName: + receiverAccount.aliasName, + }; + }, ), ); }), @@ -111,6 +149,15 @@ export const useHaltDelivery = () => { console.log('flat dispatchableenvelops', dispatchableEnvelops); await submitEnvelopsToReceiversDs(dispatchableEnvelops); + + dispatchableEnvelops.map((envelop) => { + clearHaltedMessages( + envelop.envelop.metadata?.encryptedMessageHash!, + envelop.aliasName, + ); + }); + + //Clear messages after they have been dispatched }; handleHaltedMessages(); diff --git a/packages/messenger-widget/src/hooks/server-side/BackendConnector.ts b/packages/messenger-widget/src/hooks/server-side/BackendConnector.ts index 64f5f6401..2b616d63a 100644 --- a/packages/messenger-widget/src/hooks/server-side/BackendConnector.ts +++ b/packages/messenger-widget/src/hooks/server-side/BackendConnector.ts @@ -77,6 +77,20 @@ export class BackendConnector const { data } = await this.getAuthenticatedAxiosClient().get(url, {}); return data ?? []; } + public async clearHaltedMessages( + ensName: string, + messageId: string, + aliasName: string, + ) { + const url = `/storage/new/${normalizeEnsName( + ensName, + )}/clearHaltedMessage/`; + const { data } = await this.getAuthenticatedAxiosClient().post(url, { + aliasName, + messageId, + }); + return data ?? []; + } public async addMessage( ensName: string, diff --git a/packages/messenger-widget/src/hooks/server-side/useBackend.ts b/packages/messenger-widget/src/hooks/server-side/useBackend.ts index 89d622d53..813ad5552 100644 --- a/packages/messenger-widget/src/hooks/server-side/useBackend.ts +++ b/packages/messenger-widget/src/hooks/server-side/useBackend.ts @@ -3,6 +3,7 @@ import { DM3ConfigurationContext } from '../../context/DM3ConfigurationContext'; import { AuthContext } from '../../context/AuthContext'; import { BackendConnector } from './BackendConnector'; import { IBackendConnector } from '@dm3-org/dm3-lib-shared'; +import { clearHaltedMessage } from '../../../../backend/src/persistence/storage/postgres/haltedMessage/clearHaltedMessage'; export const useBackend = (): IBackendConnector & { isInitialized: boolean; @@ -89,6 +90,17 @@ export const useBackend = (): IBackendConnector & { getHaltedMessages: async (ensName: string) => { return beConnector?.getHaltedMessages(ensName); }, + clearHaltedMessages: async ( + ensName: string, + aliasName: string, + messageId: string, + ) => { + return beConnector?.clearHaltedMessages( + ensName, + aliasName, + messageId, + ); + }, addMessage: async ( ensName: string, encryptedContactName: string, diff --git a/packages/messenger-widget/src/hooks/storage/useStorage.tsx b/packages/messenger-widget/src/hooks/storage/useStorage.tsx index 496e0a225..91745bba9 100644 --- a/packages/messenger-widget/src/hooks/storage/useStorage.tsx +++ b/packages/messenger-widget/src/hooks/storage/useStorage.tsx @@ -140,6 +140,15 @@ export const useStorage = ( } return storageApi.getMessages(contact, pageSize, offset); }; + const clearHaltedMessages = async ( + messageId: string, + aliasName: string, + ) => { + if (!storageApi) { + return Promise.resolve(); + } + return storageApi.clearHaltedMessages(messageId, aliasName); + }; const getHaltedMessages = async () => { if (!storageApi) { @@ -170,6 +179,7 @@ export const useStorage = ( addConversationAsync, getMessages, getHaltedMessages, + clearHaltedMessages, getNumberOfMessages, toggleHideContactAsync, initialized, @@ -200,5 +210,9 @@ export type GetMessages = ( offset: number, ) => Promise; export type GetHaltedMessages = () => Promise; +export type ClearHaltedMessages = ( + messageId: string, + aliasName: string, +) => Promise; export type GetNumberOfMessages = (contact: string) => Promise; export type ToggleHideContactAsync = (contact: string, value: boolean) => void; From 8ac5e4ea3bb147281d2bebcfca55687a24793a03 Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Fri, 12 Jul 2024 11:19:41 +0200 Subject: [PATCH 18/27] remove wrong backend import --- packages/messenger-demo/src/App.tsx | 2 +- packages/messenger-widget/src/hooks/server-side/useBackend.ts | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/messenger-demo/src/App.tsx b/packages/messenger-demo/src/App.tsx index 06442e444..a19bb5b1e 100644 --- a/packages/messenger-demo/src/App.tsx +++ b/packages/messenger-demo/src/App.tsx @@ -25,7 +25,7 @@ import { DM3, DM3Configuration } from '@dm3-org/dm3-messenger-widget'; // {children} // // ); -// };p +// }; function App() { const props: DM3Configuration = { diff --git a/packages/messenger-widget/src/hooks/server-side/useBackend.ts b/packages/messenger-widget/src/hooks/server-side/useBackend.ts index 813ad5552..63f71e31f 100644 --- a/packages/messenger-widget/src/hooks/server-side/useBackend.ts +++ b/packages/messenger-widget/src/hooks/server-side/useBackend.ts @@ -3,7 +3,6 @@ import { DM3ConfigurationContext } from '../../context/DM3ConfigurationContext'; import { AuthContext } from '../../context/AuthContext'; import { BackendConnector } from './BackendConnector'; import { IBackendConnector } from '@dm3-org/dm3-lib-shared'; -import { clearHaltedMessage } from '../../../../backend/src/persistence/storage/postgres/haltedMessage/clearHaltedMessage'; export const useBackend = (): IBackendConnector & { isInitialized: boolean; From 2d314c48a81ce6697d0aadf54e01b8bc8f0c711f Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Fri, 12 Jul 2024 11:57:03 +0200 Subject: [PATCH 19/27] add logs --- .../postgres/haltedMessage/clearHaltedMessage.ts | 2 ++ packages/backend/src/storage.ts | 10 +++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/backend/src/persistence/storage/postgres/haltedMessage/clearHaltedMessage.ts b/packages/backend/src/persistence/storage/postgres/haltedMessage/clearHaltedMessage.ts index de01c6f8a..60d15ded4 100644 --- a/packages/backend/src/persistence/storage/postgres/haltedMessage/clearHaltedMessage.ts +++ b/packages/backend/src/persistence/storage/postgres/haltedMessage/clearHaltedMessage.ts @@ -18,6 +18,7 @@ export const clearHaltedMessage = }); //If the contact does not exist, there is no message that can be deleted if (!account) { + console.log('cleatHaltedMessages: account not found'); return false; } @@ -28,6 +29,7 @@ export const clearHaltedMessage = }); if (!message) { + console.log(`cleatHaltedMessages: message ${messageId} not found`); return false; } diff --git a/packages/backend/src/storage.ts b/packages/backend/src/storage.ts index a710f706a..00288534d 100644 --- a/packages/backend/src/storage.ts +++ b/packages/backend/src/storage.ts @@ -282,10 +282,18 @@ export default ( //Since the message is fully encrypted, we cannot use the messageHash as an identifier. //Instead we use the hash of the ensName and the messageId to have a unique identifier const uniqueMessageId = sha256(ensName + messageId); + + console.log( + 'clearHaltedMessage uniqueMessageId ', + uniqueMessageId, + ensName, + messageId, + ); + const success = await db.clearHaltedMessage( ensName, //If the aliasName is not provided, we use the ensName as the client has no intention to use an alias - aliasName ?? ensName, + aliasName, uniqueMessageId, ); From 4d127a9a96c3e53889dc7d71d9b9dadb7ddeb4b5 Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Fri, 12 Jul 2024 12:56:41 +0200 Subject: [PATCH 20/27] use messageId input instead of sha256 --- .../storage/postgres/haltedMessage/clearHaltedMessage.ts | 1 + packages/backend/src/storage.ts | 5 ++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/backend/src/persistence/storage/postgres/haltedMessage/clearHaltedMessage.ts b/packages/backend/src/persistence/storage/postgres/haltedMessage/clearHaltedMessage.ts index 60d15ded4..1abf02eb5 100644 --- a/packages/backend/src/persistence/storage/postgres/haltedMessage/clearHaltedMessage.ts +++ b/packages/backend/src/persistence/storage/postgres/haltedMessage/clearHaltedMessage.ts @@ -25,6 +25,7 @@ export const clearHaltedMessage = const message = await db.encryptedMessage.findFirst({ where: { id: messageId, + ownerId: account.id, }, }); diff --git a/packages/backend/src/storage.ts b/packages/backend/src/storage.ts index 00288534d..8823b727e 100644 --- a/packages/backend/src/storage.ts +++ b/packages/backend/src/storage.ts @@ -281,11 +281,10 @@ export default ( const ensName = normalizeEnsName(req.params.ensName); //Since the message is fully encrypted, we cannot use the messageHash as an identifier. //Instead we use the hash of the ensName and the messageId to have a unique identifier - const uniqueMessageId = sha256(ensName + messageId); console.log( 'clearHaltedMessage uniqueMessageId ', - uniqueMessageId, + messageId, ensName, messageId, ); @@ -294,7 +293,7 @@ export default ( ensName, //If the aliasName is not provided, we use the ensName as the client has no intention to use an alias aliasName, - uniqueMessageId, + messageId, ); if (success) { From 1a319e2b179cf016cbf855c384a75bfd3cac2a52 Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Fri, 12 Jul 2024 15:11:32 +0200 Subject: [PATCH 21/27] clean up --- .../src/hooks/haltDelivery/useHaltDelivery.ts | 34 +++++++------------ 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/packages/messenger-widget/src/hooks/haltDelivery/useHaltDelivery.ts b/packages/messenger-widget/src/hooks/haltDelivery/useHaltDelivery.ts index f215e0322..17e8f88f4 100644 --- a/packages/messenger-widget/src/hooks/haltDelivery/useHaltDelivery.ts +++ b/packages/messenger-widget/src/hooks/haltDelivery/useHaltDelivery.ts @@ -1,15 +1,15 @@ -import { useContext, useEffect } from 'react'; -import { StorageContext } from '../../context/StorageContext'; -import { TLDContext } from '../../context/TLDContext'; +import { encryptAsymmetric } from '@dm3-org/dm3-lib-crypto'; +import { buildEnvelop } from '@dm3-org/dm3-lib-messaging'; import { Account, DeliveryServiceProfile, getUserProfile, } from '@dm3-org/dm3-lib-profile'; -import { MainnetProviderContext } from '../../context/ProviderContext'; -import { DispatchableEnvelop, buildEnvelop } from '@dm3-org/dm3-lib-messaging'; -import { encryptAsymmetric } from '@dm3-org/dm3-lib-crypto'; +import { useContext, useEffect } from 'react'; import { AuthContext } from '../../context/AuthContext'; +import { MainnetProviderContext } from '../../context/ProviderContext'; +import { StorageContext } from '../../context/StorageContext'; +import { TLDContext } from '../../context/TLDContext'; import { fetchDsProfiles } from '../../utils/deliveryService/fetchDsProfiles'; import { submitEnvelopsToReceiversDs } from '../../utils/deliveryService/submitEnvelopsToReceiversDs'; @@ -47,8 +47,6 @@ export const useHaltDelivery = () => { })), ); - console.log('resolvedAliases', resolvedAliases); - //For each recipient, get the users account const withAccounts = await Promise.all( resolvedAliases.map( @@ -82,12 +80,7 @@ export const useHaltDelivery = () => { return { ...dm3User, messages }; }); - console.log('haltedMessages', dm3UsersWithMessages); - - console.log('withUserProfiles', withAccounts); - console.log('dm3Users', dm3Users); //fetch the ds profiles of every recipient - const withDsProfile = await Promise.all( dm3UsersWithMessages.map(async (dm3User) => ({ ...dm3User, @@ -109,7 +102,7 @@ export const useHaltDelivery = () => { async ( dsProfile: DeliveryServiceProfile, ) => { - //build the dispatchable envelop + //build the dispatchable envelop containing the deliveryInformation of the receiver const dispatchableEnvelop = await buildEnvelop( message.envelop.message, @@ -130,6 +123,10 @@ export const useHaltDelivery = () => { }, ); return { + //To clear the envelop that has been used to store the halted message + haltedEnvelopId: + message.envelop.metadata + ?.encryptedMessageHash!, ...dispatchableEnvelop, //we keep the alias name for the receiver. In case it differes from the ensName aliasName: @@ -146,18 +143,11 @@ export const useHaltDelivery = () => { //The envelops are now ready to be disptched const dispatchableEnvelops = envelops.flat(2); - console.log('flat dispatchableenvelops', dispatchableEnvelops); - await submitEnvelopsToReceiversDs(dispatchableEnvelops); dispatchableEnvelops.map((envelop) => { - clearHaltedMessages( - envelop.envelop.metadata?.encryptedMessageHash!, - envelop.aliasName, - ); + clearHaltedMessages(envelop.haltedEnvelopId, envelop.aliasName); }); - - //Clear messages after they have been dispatched }; handleHaltedMessages(); From 39ba931f337aab1b25d513719f9205c123d21e79 Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Fri, 12 Jul 2024 15:23:11 +0200 Subject: [PATCH 22/27] clean up tests --- .../lib/storage/src/migrate-storage.test.ts | 166 ------------------ .../haltDelivery/useHaltDelivery.test.tsx | 1 + 2 files changed, 1 insertion(+), 166 deletions(-) delete mode 100644 packages/lib/storage/src/migrate-storage.test.ts diff --git a/packages/lib/storage/src/migrate-storage.test.ts b/packages/lib/storage/src/migrate-storage.test.ts deleted file mode 100644 index a7762b081..000000000 --- a/packages/lib/storage/src/migrate-storage.test.ts +++ /dev/null @@ -1,166 +0,0 @@ -import { - createStorageKey, - getStorageKeyCreationMessage, -} from '@dm3-org/dm3-lib-crypto'; -import { createProfileKeys } from '@dm3-org/dm3-lib-profile'; -import { ethers } from 'ethers'; -import { StorageEnvelopContainer } from './new/types'; -import { Message, Envelop, MessageState } from '@dm3-org/dm3-lib-messaging'; -import { StorageAPI } from '../dist'; -import { Conversation } from './new/types'; -import { migrageStorage } from './new/migrateStorage'; -import { createDB } from './Storage'; - -const USER_1 = 'alice.eth'; -const USER_2 = 'bob.eth'; - -const getMockProfileKeys = async () => { - const nonce = '0'; - const wallet = new ethers.Wallet( - '0xac58f2f021d6f148fd621b355edbd0ebadcf9682019015ef1219cf9c0c2ddc8b', - ); - - const nonceMsg = getStorageKeyCreationMessage(nonce, wallet.address); - const signedMessage = await wallet.signMessage(nonceMsg); - - return await createProfileKeys( - await createStorageKey(signedMessage), - nonce, - ); -}; -const getStorageEnvelopeContainer = (msg: string, timestamp: number = 0) => { - const message: Message = { - metadata: { - to: '', - from: USER_1, - timestamp, - type: 'NEW', - }, - message: msg, - signature: '', - }; - - const envelop: Envelop = { - message, - metadata: { - deliveryInformation: { - from: '', - to: '', - deliveryInstruction: '', - }, - encryptedMessageHash: '', - version: '', - encryptionScheme: '', - signature: '', - }, - }; - - return { - messageState: MessageState.Created, - envelop: envelop, - deliveryServiceIncommingTimestamp: 123, - } as StorageEnvelopContainer; -}; -describe('MigrateStorage', () => { - let newStorage: StorageAPI; - - beforeEach(() => { - //Mock newStorage - newStorage = (() => { - const conversations = new Map(); - - return { - getConversations: async (page: number) => - Array.from(conversations.keys()).map((contactEnsName) => ({ - contactEnsName, - isHidden: false, - previewMessage: undefined, - })), - getMessages: async (contactEnsName: string, page: number) => [], - addMessageBatch: async ( - contactEnsName: string, - batch: StorageEnvelopContainer[], - ) => { - conversations.set(contactEnsName, [ - ...(conversations.get(contactEnsName) ?? []), - ...batch, - ]); - return ''; - }, - editMessageBatch: async ( - contactEnsName: string, - editedMessage: StorageEnvelopContainer[], - ) => {}, - getNumberOfMessages: async (contactEnsName: string) => 0, - getNumberOfConverations: async () => 0, - addConversation: async (contactEnsName: string) => { - conversations.set(contactEnsName, []); - }, - addMessage: async ( - contactEnsName: string, - envelop: StorageEnvelopContainer, - ) => '', - toggleHideConversation: async ( - contactEnsName: string, - isHidden: boolean, - ) => {}, - }; - })(); - }); - it('should migrate storage', async () => { - const profileKeys = await getMockProfileKeys(); - const db = createDB(profileKeys); - db.conversations.set(USER_1, [ - getStorageEnvelopeContainer('hello', 1), - getStorageEnvelopeContainer('dm3', 2), - ]); - db.conversations.set(USER_2, [ - getStorageEnvelopeContainer('123', 1), - getStorageEnvelopeContainer('456', 2), - ]); - - const tldResolver = async (ensName: string) => { - return ensName.replace('.eth', '.addr.user.dm3.eth'); - }; - - await migrageStorage(db, newStorage, tldResolver); - - const newConversations = await newStorage.getConversations(100, 0); - 0.45; - expect(newConversations.length).toBe(2); - expect(newConversations[0].contactEnsName).toBe( - 'alice.addr.user.dm3.eth', - ); - expect(newConversations[1].contactEnsName).toBe( - 'bob.addr.user.dm3.eth', - ); - }); - it('resolve tld names', async () => { - const profileKeys = await getMockProfileKeys(); - const db = createDB(profileKeys); - db.conversations.set(USER_1, [ - getStorageEnvelopeContainer('hello', 1), - getStorageEnvelopeContainer('dm3', 2), - ]); - db.conversations.set('foo.addr.user.dm3.gno', [ - getStorageEnvelopeContainer('123', 1), - getStorageEnvelopeContainer('456', 2), - ]); - - const tldResolver = async (ensName: string) => { - return ensName.replace('.eth', '.addr.user.dm3.eth'); - }; - - await migrageStorage(db, newStorage, tldResolver); - - const newConversations = await newStorage.getConversations(100, 0); - 0.45; - expect(newConversations.length).toBe(2); - expect(newConversations[0].contactEnsName).toBe( - 'alice.addr.user.dm3.eth', - ); - expect(newConversations[1].contactEnsName).toBe( - 'foo.addr.user.dm3.gno', - ); - }); -}); diff --git a/packages/messenger-widget/src/hooks/haltDelivery/useHaltDelivery.test.tsx b/packages/messenger-widget/src/hooks/haltDelivery/useHaltDelivery.test.tsx index 3a6767511..10f5defc1 100644 --- a/packages/messenger-widget/src/hooks/haltDelivery/useHaltDelivery.test.tsx +++ b/packages/messenger-widget/src/hooks/haltDelivery/useHaltDelivery.test.tsx @@ -85,6 +85,7 @@ describe('useConversation hook test cases', () => { }, addConversationAsync: jest.fn(), toggleHideContactAsync: jest.fn(), + getHaltedMessages: () => Promise.resolve([]), initialized: true, }); const deliveryServiceContext: DeliveryServiceContextType = From 1a0da75cf85f0d3dc27c1fa202a8e03153385c5b Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Fri, 12 Jul 2024 16:13:16 +0200 Subject: [PATCH 23/27] fix broken test --- packages/backend/src/storage.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/backend/src/storage.test.ts b/packages/backend/src/storage.test.ts index 1e27b9d7d..acb4b8d2d 100644 --- a/packages/backend/src/storage.test.ts +++ b/packages/backend/src/storage.test.ts @@ -980,7 +980,7 @@ describe('Storage', () => { .send({ encryptedEnvelopContainer: JSON.stringify(envelop1), encryptedContactName: sha256(receiver.account.ensName), - messageId: '123', + messageId: envelop1.metadata.encryptedMessageHash, createdAt: 1, isHalted: true, }); @@ -1007,7 +1007,7 @@ describe('Storage', () => { authorization: 'Bearer ' + token, }) .send({ - messageId: 123, + messageId: messages[0].messageId, }); expect(deleteStatus).toBe(200); From b3dc03d65f2703ec8f962ef4a67f31a30b6dcda1 Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Mon, 15 Jul 2024 09:48:37 +0200 Subject: [PATCH 24/27] remove console.log from storage test --- packages/backend/src/storage.test.ts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/packages/backend/src/storage.test.ts b/packages/backend/src/storage.test.ts index acb4b8d2d..5f99e60ab 100644 --- a/packages/backend/src/storage.test.ts +++ b/packages/backend/src/storage.test.ts @@ -490,8 +490,6 @@ describe('Storage', () => { }) .send(); - console.log(body); - expect(body.length).toBe(1); expect(body[0].contact).toEqual(sha256(receiver.account.ensName)); expect(JSON.parse(body[0].previewMessage)).toEqual(envelop3); @@ -508,8 +506,6 @@ describe('Storage', () => { }) .send(); - console.log(body); - expect(status).toBe(400); }); @@ -522,8 +518,6 @@ describe('Storage', () => { }) .send(); - console.log(body); - expect(status).toBe(400); }); }); @@ -1162,9 +1156,6 @@ describe('Storage', () => { isHalted: false, }); - console.log('xxxx', x.status); - console.log('xxxx', x.body); - await request(app) .post(`/new/bob.eth/addMessage`) .set({ From f79413fdc99bfeafd345162a83d3b73c43c0283e Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Mon, 15 Jul 2024 09:51:10 +0200 Subject: [PATCH 25/27] remove console.log from storage --- packages/backend/src/storage.ts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/packages/backend/src/storage.ts b/packages/backend/src/storage.ts index 8823b727e..2c4a122d5 100644 --- a/packages/backend/src/storage.ts +++ b/packages/backend/src/storage.ts @@ -279,15 +279,6 @@ export default ( } const ensName = normalizeEnsName(req.params.ensName); - //Since the message is fully encrypted, we cannot use the messageHash as an identifier. - //Instead we use the hash of the ensName and the messageId to have a unique identifier - - console.log( - 'clearHaltedMessage uniqueMessageId ', - messageId, - ensName, - messageId, - ); const success = await db.clearHaltedMessage( ensName, From 2545d160be22884631a84b8fd4f6d498e6cf038e Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Mon, 15 Jul 2024 09:52:56 +0200 Subject: [PATCH 26/27] clena up getCloudStorage --- packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts b/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts index c4b4c435b..8ef0b388b 100644 --- a/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts +++ b/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts @@ -79,10 +79,6 @@ export const getCloudStorage = ( const decryptedEnvelopContainer = await encryption.decryptAsync( message.encryptedEnvelopContainer, ); - console.log( - 'decryptedEnvelopContainer haltedMessages', - decryptedEnvelopContainer, - ); return JSON.parse(decryptedEnvelopContainer); }), From 802882f8b19667c17cd4f14971563342b97189e5 Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Mon, 15 Jul 2024 10:12:26 +0200 Subject: [PATCH 27/27] optimize imports --- .../hooks/conversation/useConversation.test.tsx | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/packages/messenger-widget/src/hooks/conversation/useConversation.test.tsx b/packages/messenger-widget/src/hooks/conversation/useConversation.test.tsx index 50d0ee4ef..9fc82a286 100644 --- a/packages/messenger-widget/src/hooks/conversation/useConversation.test.tsx +++ b/packages/messenger-widget/src/hooks/conversation/useConversation.test.tsx @@ -38,22 +38,6 @@ import { getMockedStorageContext } from '../../context/testHelper/getMockedStora import { getMockedTldContext } from '../../context/testHelper/getMockedTldContext'; import { DM3Configuration } from '../../widget'; import { useConversation } from './useConversation'; -import { - MainnetProviderContext, - MainnetProviderContextType, -} from '../../context/ProviderContext'; -import { getMockedMainnetProviderContext } from '../../context/testHelper/getMockedMainnetProviderContext'; -import { ethers } from 'ethers'; -import { - MockDeliveryServiceProfile, - MockedUserProfile, - getMockDeliveryServiceProfile, - mockUserProfile, -} from '@dm3-org/dm3-lib-test-helper'; -import MockAdapter from 'axios-mock-adapter'; -import axios from 'axios'; -import { Envelop } from '@dm3-org/dm3-lib-messaging'; -import { getDeliveryServiceProfile } from '@dm3-org/dm3-lib-profile'; describe('useConversation hook test cases', () => { let sender: MockedUserProfile;