From 073edb57b575e53a1fff65b61fb864ddf361d5b2 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Wed, 17 Jan 2024 13:30:31 +0100 Subject: [PATCH 01/18] add logging view class for community and use it in dht-node --- database/logging/AbstractLogging.view.ts | 33 +++++++++++++++++++++++ database/logging/CommunityLogging.view.ts | 26 ++++++++++++++++++ dht-node/src/dht_node/index.ts | 5 ++-- dht-node/tsconfig.json | 3 ++- 4 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 database/logging/AbstractLogging.view.ts create mode 100644 database/logging/CommunityLogging.view.ts diff --git a/database/logging/AbstractLogging.view.ts b/database/logging/AbstractLogging.view.ts new file mode 100644 index 000000000..a30254b86 --- /dev/null +++ b/database/logging/AbstractLogging.view.ts @@ -0,0 +1,33 @@ +import util from 'util' + +import { Decimal } from 'decimal.js-light' + +export abstract class AbstractLoggingView { + protected bufferStringFormat: BufferEncoding = 'hex' + + // This function gets called automatically when JSON.stringify() is called on this class instance + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public abstract toJSON(): any + public toString(): string { + return JSON.stringify(this.toJSON(), null, 2) + } + + // called form console.log or log4js logging functions + [util.inspect.custom](): string { + return this.toString() + } + + public dateToString(date: Date | undefined | null): string | undefined { + if (date) { + return date.toISOString() + } + return undefined + } + + public decimalToString(number: Decimal | undefined | null): string | undefined { + if (number) { + return number.toString() + } + return undefined + } +} diff --git a/database/logging/CommunityLogging.view.ts b/database/logging/CommunityLogging.view.ts new file mode 100644 index 000000000..1c6d74626 --- /dev/null +++ b/database/logging/CommunityLogging.view.ts @@ -0,0 +1,26 @@ +import { Community } from '../entity/Community' + +import { AbstractLoggingView } from './AbstractLogging.view' + +export class CommunityLoggingView extends AbstractLoggingView { + public constructor(private self: Community) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + id: this.self.id, + foreign: this.self.foreign, + url: this.self.url, + publicKey: this.self.publicKey.toString(this.bufferStringFormat), + communityUuid: this.self.communityUuid, + authenticatedAt: this.dateToString(this.self.authenticatedAt), + name: this.self.name, + description: this.self.description?.substring(0, 24), + creationDate: this.dateToString(this.self.creationDate), + createdAt: this.dateToString(this.self.createdAt), + updatedAt: this.dateToString(this.self.updatedAt), + } + } +} diff --git a/dht-node/src/dht_node/index.ts b/dht-node/src/dht_node/index.ts index c9fad8762..536966591 100644 --- a/dht-node/src/dht_node/index.ts +++ b/dht-node/src/dht_node/index.ts @@ -3,6 +3,7 @@ import { Community as DbCommunity } from '@entity/Community' import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity' import DHT from '@hyperswarm/dht' +import { CommunityLoggingView } from '@logging/CommunityLogging.view' import { v4 as uuidv4 } from 'uuid' import { CONFIG } from '@/config' @@ -227,7 +228,7 @@ async function writeHomeCommunityEntry(keyPair: KeyPair): Promise { homeCom.name = CONFIG.COMMUNITY_NAME homeCom.description = CONFIG.COMMUNITY_DESCRIPTION await DbCommunity.save(homeCom) - logger.info(`home-community updated successfully:`, homeCom) + logger.info(`home-community updated successfully:`, new CommunityLoggingView(homeCom)) } else { // insert a new homecommunity entry including a new ID and a new but ensured unique UUID homeCom = new DbCommunity() @@ -240,7 +241,7 @@ async function writeHomeCommunityEntry(keyPair: KeyPair): Promise { homeCom.description = CONFIG.COMMUNITY_DESCRIPTION homeCom.creationDate = new Date() await DbCommunity.insert(homeCom) - logger.info(`home-community inserted successfully:`, homeCom) + logger.info(`home-community inserted successfully:`, new CommunityLoggingView(homeCom)) } } catch (err) { throw new Error(`Federation: Error writing HomeCommunity-Entry: ${err}`) diff --git a/dht-node/tsconfig.json b/dht-node/tsconfig.json index 2c6104021..33362b054 100644 --- a/dht-node/tsconfig.json +++ b/dht-node/tsconfig.json @@ -52,7 +52,8 @@ /* external */ "@typeorm/*": ["../backend/src/typeorm/*", "../../backend/src/typeorm/*"], "@dbTools/*": ["../database/src/*", "../../database/build/src/*"], - "@entity/*": ["../database/entity/*", "../../database/build/entity/*"] + "@entity/*": ["../database/entity/*", "../../database/build/entity/*"], + "@logging/*": ["../database/logging/*", "../../database/build/logging/*"] }, // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ "typeRoots": ["src/dht_node/@types", "node_modules/@types"], /* List of folders to include type definitions from. */ From 17a067e99b57b4fe9f69f95e812ed3cb987b2394 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Thu, 18 Jan 2024 13:10:58 +0100 Subject: [PATCH 02/18] add and use logging view class, annonce only configured api version --- .../client/1_0/AuthenticationClient.ts | 6 +- .../federation/client/1_0/FederationClient.ts | 26 +++--- .../federation/client/1_0/SendCoinsClient.ts | 72 ++++++++++------- .../PublicCommunityInfoLogging.view.ts | 19 +++++ .../1_0/logging/SendCoinsArgsLogging.view.ts | 24 ++++++ .../logging/SendCoinsResultLogging.view.ts | 20 +++++ .../client/1_0/model/GetPublicKeyResult.ts | 13 +++ backend/src/federation/validateCommunities.ts | 16 ++-- backend/tsconfig.json | 3 +- database/logging/AbstractLogging.view.ts | 9 ++- .../logging/FederatedCommunityLogging.view.ts | 24 ++++++ dht-node/.env.dist | 4 +- dht-node/.env.template | 3 +- dht-node/src/config/index.ts | 4 +- dht-node/src/dht_node/index.ts | 10 ++- ...etPublicCommunityInfoResultLogging.view.ts | 18 +++++ .../1_0/logger/SendCoinsArgsLogging.view.ts | 23 ++++++ .../1_0/model/GetPublicCommunityInfoResult.ts | 2 +- .../1_0/resolver/AuthenticationResolver.ts | 17 ++-- .../resolver/PublicCommunityInfoResolver.ts | 7 +- .../api/1_0/resolver/PublicKeyResolver.ts | 6 +- .../api/1_0/resolver/SendCoinsResolver.ts | 81 +++++-------------- .../api/1_0/util/authenticateCommunity.ts | 22 ++++- federation/tsconfig.json | 3 +- 24 files changed, 292 insertions(+), 140 deletions(-) create mode 100644 backend/src/federation/client/1_0/logging/PublicCommunityInfoLogging.view.ts create mode 100644 backend/src/federation/client/1_0/logging/SendCoinsArgsLogging.view.ts create mode 100644 backend/src/federation/client/1_0/logging/SendCoinsResultLogging.view.ts create mode 100644 backend/src/federation/client/1_0/model/GetPublicKeyResult.ts create mode 100644 database/logging/FederatedCommunityLogging.view.ts create mode 100644 federation/src/graphql/api/1_0/logger/GetPublicCommunityInfoResultLogging.view.ts create mode 100644 federation/src/graphql/api/1_0/logger/SendCoinsArgsLogging.view.ts diff --git a/backend/src/federation/client/1_0/AuthenticationClient.ts b/backend/src/federation/client/1_0/AuthenticationClient.ts index abc903778..f73393255 100644 --- a/backend/src/federation/client/1_0/AuthenticationClient.ts +++ b/backend/src/federation/client/1_0/AuthenticationClient.ts @@ -28,9 +28,9 @@ export class AuthenticationClient { async openConnection(args: OpenConnectionArgs): Promise { logger.debug(`Authentication: openConnection at ${this.endpoint} for args:`, args) try { - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const { data } = await this.client.rawRequest(openConnection, { args }) - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + const { data } = await this.client.rawRequest<{ openConnection: boolean }>(openConnection, { + args, + }) if (!data?.openConnection) { logger.warn( 'Authentication: openConnection without response data from endpoint', diff --git a/backend/src/federation/client/1_0/FederationClient.ts b/backend/src/federation/client/1_0/FederationClient.ts index 8d915c751..4a10ddc7e 100644 --- a/backend/src/federation/client/1_0/FederationClient.ts +++ b/backend/src/federation/client/1_0/FederationClient.ts @@ -5,9 +5,10 @@ import { getPublicCommunityInfo } from '@/federation/client/1_0/query/getPublicC import { getPublicKey } from '@/federation/client/1_0/query/getPublicKey' import { backendLogger as logger } from '@/server/logger' +import { PublicCommunityInfoLoggingView } from './logging/PublicCommunityInfoLogging.view' +import { GetPublicKeyResult } from './model/GetPublicKeyResult' import { PublicCommunityInfo } from './model/PublicCommunityInfo' -// eslint-disable-next-line camelcase export class FederationClient { dbCom: DbFederatedCommunity endpoint: string @@ -30,9 +31,10 @@ export class FederationClient { getPublicKey = async (): Promise => { logger.debug('Federation: getPublicKey from endpoint', this.endpoint) try { - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const { data } = await this.client.rawRequest(getPublicKey, {}) - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + const { data } = await this.client.rawRequest<{ getPublicKey: GetPublicKeyResult }>( + getPublicKey, + {}, + ) if (!data?.getPublicKey?.publicKey) { logger.warn('Federation: getPublicKey without response data from endpoint', this.endpoint) return @@ -40,10 +42,8 @@ export class FederationClient { logger.debug( 'Federation: getPublicKey successful from endpoint', this.endpoint, - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access data.getPublicKey.publicKey, ) - // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access return data.getPublicKey.publicKey } catch (err) { logger.warn('Federation: getPublicKey failed for endpoint', this.endpoint) @@ -53,9 +53,10 @@ export class FederationClient { getPublicCommunityInfo = async (): Promise => { logger.debug(`Federation: getPublicCommunityInfo with endpoint='${this.endpoint}'...`) try { - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const { data } = await this.client.rawRequest(getPublicCommunityInfo, {}) - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + const { data } = await this.client.rawRequest<{ + getPublicCommunityInfo: PublicCommunityInfo + }>(getPublicCommunityInfo, {}) + if (!data?.getPublicCommunityInfo?.name) { logger.warn( 'Federation: getPublicCommunityInfo without response data from endpoint', @@ -64,9 +65,10 @@ export class FederationClient { return } logger.debug(`Federation: getPublicCommunityInfo successful from endpoint=${this.endpoint}`) - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - logger.debug(`publicCommunityInfo:`, data.getPublicCommunityInfo) - // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access + logger.debug( + `publicCommunityInfo:`, + new PublicCommunityInfoLoggingView(data.getPublicCommunityInfo), + ) return data.getPublicCommunityInfo } catch (err) { logger.warn('Federation: getPublicCommunityInfo failed for endpoint', this.endpoint) diff --git a/backend/src/federation/client/1_0/SendCoinsClient.ts b/backend/src/federation/client/1_0/SendCoinsClient.ts index c96961103..bcf303584 100644 --- a/backend/src/federation/client/1_0/SendCoinsClient.ts +++ b/backend/src/federation/client/1_0/SendCoinsClient.ts @@ -4,6 +4,8 @@ import { GraphQLClient } from 'graphql-request' import { LogError } from '@/server/LogError' import { backendLogger as logger } from '@/server/logger' +import { SendCoinsArgsLoggingView } from './logging/SendCoinsArgsLogging.view' +import { SendCoinsResultLoggingView } from './logging/SendCoinsResultLogging.view' import { SendCoinsArgs } from './model/SendCoinsArgs' import { SendCoinsResult } from './model/SendCoinsResult' import { revertSendCoins as revertSendCoinsQuery } from './query/revertSendCoins' @@ -11,7 +13,6 @@ import { revertSettledSendCoins as revertSettledSendCoinsQuery } from './query/r import { settleSendCoins as settleSendCoinsQuery } from './query/settleSendCoins' import { voteForSendCoins as voteForSendCoinsQuery } from './query/voteForSendCoins' -// eslint-disable-next-line camelcase export class SendCoinsClient { dbCom: DbFederatedCommunity endpoint: string @@ -34,26 +35,26 @@ export class SendCoinsClient { async voteForSendCoins(args: SendCoinsArgs): Promise { logger.debug('X-Com: voteForSendCoins against endpoint=', this.endpoint) try { - logger.debug(`X-Com: SendCoinsClient: voteForSendCoins with args=`, args) - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const { data } = await this.client.rawRequest(voteForSendCoinsQuery, { args }) - logger.debug(`X-Com: SendCoinsClient: after rawRequest...data:`, data) - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + logger.debug( + `X-Com: SendCoinsClient: voteForSendCoins with args=`, + new SendCoinsArgsLoggingView(args), + ) + const { data } = await this.client.rawRequest<{ voteForSendCoins: SendCoinsResult }>( + voteForSendCoinsQuery, + { args }, + ) + const result = data.voteForSendCoins if (!data?.voteForSendCoins?.vote) { - logger.debug('X-Com: voteForSendCoins failed with: ', data) + logger.debug( + 'X-Com: voteForSendCoins failed with: ', + new SendCoinsResultLoggingView(result), + ) return new SendCoinsResult() } - const result = new SendCoinsResult() - result.vote = true - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment - result.recipGradidoID = data.voteForSendCoins.recipGradidoID - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment - result.recipFirstName = data.voteForSendCoins.recipFirstName - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment - result.recipLastName = data.voteForSendCoins.recipLastName - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment - result.recipAlias = data.voteForSendCoins.recipAlias - logger.debug('X-Com: voteForSendCoins successful with result=', result) + logger.debug( + 'X-Com: voteForSendCoins successful with result=', + new SendCoinsResultLoggingView(result), + ) return result } catch (err) { throw new LogError(`X-Com: voteForSendCoins failed for endpoint=${this.endpoint}:`, err) @@ -63,11 +64,15 @@ export class SendCoinsClient { async revertSendCoins(args: SendCoinsArgs): Promise { logger.debug('X-Com: revertSendCoins against endpoint=', this.endpoint) try { - logger.debug(`X-Com: SendCoinsClient: revertSendCoins with args=`, args) - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const { data } = await this.client.rawRequest(revertSendCoinsQuery, { args }) + logger.debug( + `X-Com: SendCoinsClient: revertSendCoins with args=`, + new SendCoinsArgsLoggingView(args), + ) + const { data } = await this.client.rawRequest<{ revertSendCoins: boolean }>( + revertSendCoinsQuery, + { args }, + ) logger.debug(`X-Com: SendCoinsClient: after revertSendCoins: data=`, data) - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access if (!data?.revertSendCoins) { logger.warn('X-Com: revertSendCoins without response data from endpoint', this.endpoint) return false @@ -88,11 +93,15 @@ export class SendCoinsClient { async settleSendCoins(args: SendCoinsArgs): Promise { logger.debug(`X-Com: settleSendCoins against endpoint='${this.endpoint}'...`) try { - logger.debug(`X-Com: SendCoinsClient: settleSendCoins with args=`, args) - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const { data } = await this.client.rawRequest(settleSendCoinsQuery, { args }) + logger.debug( + `X-Com: SendCoinsClient: settleSendCoins with args=`, + new SendCoinsArgsLoggingView(args), + ) + const { data } = await this.client.rawRequest<{ settleSendCoins: boolean }>( + settleSendCoinsQuery, + { args }, + ) logger.debug(`X-Com: SendCoinsClient: after settleSendCoins: data=`, data) - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access if (!data?.settleSendCoins) { logger.warn( 'X-Com: SendCoinsClient: settleSendCoins without response data from endpoint', @@ -115,9 +124,14 @@ export class SendCoinsClient { async revertSettledSendCoins(args: SendCoinsArgs): Promise { logger.debug(`X-Com: revertSettledSendCoins against endpoint='${this.endpoint}'...`) try { - logger.debug(`X-Com: SendCoinsClient: revertSettledSendCoins with args=`, args) - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const { data } = await this.client.rawRequest(revertSettledSendCoinsQuery, { args }) + logger.debug( + `X-Com: SendCoinsClient: revertSettledSendCoins with args=`, + new SendCoinsArgsLoggingView(args), + ) + const { data } = await this.client.rawRequest<{ revertSettledSendCoins: boolean }>( + revertSettledSendCoinsQuery, + { args }, + ) logger.debug(`X-Com: SendCoinsClient: after revertSettledSendCoins: data=`, data) // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access if (!data?.revertSettledSendCoins) { diff --git a/backend/src/federation/client/1_0/logging/PublicCommunityInfoLogging.view.ts b/backend/src/federation/client/1_0/logging/PublicCommunityInfoLogging.view.ts new file mode 100644 index 000000000..3151bbb31 --- /dev/null +++ b/backend/src/federation/client/1_0/logging/PublicCommunityInfoLogging.view.ts @@ -0,0 +1,19 @@ +import { AbstractLoggingView } from '@logging/AbstractLogging.view' + +import { PublicCommunityInfo } from '@/federation/client/1_0/model/PublicCommunityInfo' + +export class PublicCommunityInfoLoggingView extends AbstractLoggingView { + public constructor(private self: PublicCommunityInfo) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + name: this.self.name, + description: this.self.description, + creationDate: this.dateToString(this.self.creationDate), + publicKey: this.self.publicKey, + } + } +} diff --git a/backend/src/federation/client/1_0/logging/SendCoinsArgsLogging.view.ts b/backend/src/federation/client/1_0/logging/SendCoinsArgsLogging.view.ts new file mode 100644 index 000000000..2df149133 --- /dev/null +++ b/backend/src/federation/client/1_0/logging/SendCoinsArgsLogging.view.ts @@ -0,0 +1,24 @@ +import { AbstractLoggingView } from '@logging/AbstractLogging.view' + +import { SendCoinsArgs } from '@/federation/client/1_0/model/SendCoinsArgs' + +export class SendCoinsArgsLoggingView extends AbstractLoggingView { + public constructor(private self: SendCoinsArgs) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + recipientCommunityUuid: this.self.recipientCommunityUuid, + recipientUserIdentifier: this.self.recipientUserIdentifier, + creationDate: this.self.creationDate, + amount: this.decimalToString(this.self.amount), + memoLength: this.self.memo.length, + senderCommunityUuid: this.self.senderCommunityUuid, + senderUserUuid: this.self.senderUserUuid, + senderUserName: this.self.senderUserName.substring(0, 3), + senderAlias: this.self.senderAlias?.substring(0, 3), + } + } +} diff --git a/backend/src/federation/client/1_0/logging/SendCoinsResultLogging.view.ts b/backend/src/federation/client/1_0/logging/SendCoinsResultLogging.view.ts new file mode 100644 index 000000000..b605eb1db --- /dev/null +++ b/backend/src/federation/client/1_0/logging/SendCoinsResultLogging.view.ts @@ -0,0 +1,20 @@ +import { AbstractLoggingView } from '@logging/AbstractLogging.view' + +import { SendCoinsResult } from '@/federation/client/1_0/model/SendCoinsResult' + +export class SendCoinsResultLoggingView extends AbstractLoggingView { + public constructor(private self: SendCoinsResult) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + vote: this.self.vote, + recipGradidoID: this.self.recipGradidoID, + recipFirstName: this.self.recipFirstName?.substring(0, 3), + recipLastName: this.self.recipLastName?.substring(0, 3), + recipAlias: this.self.recipAlias?.substring(0, 3), + } + } +} diff --git a/backend/src/federation/client/1_0/model/GetPublicKeyResult.ts b/backend/src/federation/client/1_0/model/GetPublicKeyResult.ts new file mode 100644 index 000000000..696c96cfe --- /dev/null +++ b/backend/src/federation/client/1_0/model/GetPublicKeyResult.ts @@ -0,0 +1,13 @@ +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import { Field, ObjectType } from 'type-graphql' + +@ObjectType() +// eslint-disable-next-line @typescript-eslint/no-unused-vars +export class GetPublicKeyResult { + constructor(pubKey: string) { + this.publicKey = pubKey + } + + @Field(() => String) + publicKey: string +} diff --git a/backend/src/federation/validateCommunities.ts b/backend/src/federation/validateCommunities.ts index 69b69070a..f19d606bd 100644 --- a/backend/src/federation/validateCommunities.ts +++ b/backend/src/federation/validateCommunities.ts @@ -3,14 +3,15 @@ import { IsNull } from '@dbTools/typeorm' import { Community as DbCommunity } from '@entity/Community' import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity' +import { FederatedCommunityLoggingView } from '@logging/FederatedCommunityLogging.view' -// eslint-disable-next-line camelcase import { FederationClient as V1_0_FederationClient } from '@/federation/client/1_0/FederationClient' import { PublicCommunityInfo } from '@/federation/client/1_0/model/PublicCommunityInfo' import { FederationClientFactory } from '@/federation/client/FederationClientFactory' import { backendLogger as logger } from '@/server/logger' import { startCommunityAuthentication } from './authenticateCommunities' +import { PublicCommunityInfoLoggingView } from './client/1_0/logging/PublicCommunityInfoLogging.view' import { ApiVersionType } from './enum/apiVersionType' export async function startValidateCommunities(timerInterval: number): Promise { @@ -37,7 +38,7 @@ export async function validateCommunities(): Promise { logger.debug(`Federation: found ${dbFederatedCommunities.length} dbCommunities`) for (const dbCom of dbFederatedCommunities) { - logger.debug('Federation: dbCom', dbCom) + logger.debug('Federation: dbCom', new FederatedCommunityLoggingView(dbCom)) const apiValueStrings: string[] = Object.values(ApiVersionType) logger.debug(`suppported ApiVersions=`, apiValueStrings) if (!apiValueStrings.includes(dbCom.apiVersion)) { @@ -53,7 +54,7 @@ export async function validateCommunities(): Promise { // eslint-disable-next-line camelcase if (client instanceof V1_0_FederationClient) { const pubKey = await client.getPublicKey() - if (pubKey && pubKey === dbCom.publicKey.toString()) { + if (pubKey && pubKey === dbCom.publicKey.toString('hex')) { await DbFederatedCommunity.update({ id: dbCom.id }, { verifiedAt: new Date() }) logger.debug(`Federation: verified community with:`, dbCom.endPoint) const pubComInfo = await client.getPublicCommunityInfo() @@ -68,7 +69,7 @@ export async function validateCommunities(): Promise { logger.debug( 'Federation: received not matching publicKey:', pubKey, - dbCom.publicKey.toString(), + dbCom.publicKey.toString('hex'), ) } } @@ -82,10 +83,11 @@ async function writeForeignCommunity( dbCom: DbFederatedCommunity, pubInfo: PublicCommunityInfo, ): Promise { - if (!dbCom || !pubInfo || !(dbCom.publicKey.toString() === pubInfo.publicKey)) { + if (!dbCom || !pubInfo || !(dbCom.publicKey.toString('hex') === pubInfo.publicKey)) { + const pubInfoView = new PublicCommunityInfoLoggingView(pubInfo) logger.error( - `Error in writeForeignCommunity: missmatching parameters or publicKey. pubInfo:${JSON.stringify( - pubInfo, + `Error in writeForeignCommunity: missmatching parameters or publicKey. pubInfo:${pubInfoView.toString( + true, )}`, ) } else { diff --git a/backend/tsconfig.json b/backend/tsconfig.json index 7e329926b..28ddf1c38 100644 --- a/backend/tsconfig.json +++ b/backend/tsconfig.json @@ -58,7 +58,8 @@ "@test/*": ["test/*"], /* external */ "@dbTools/*": ["../database/src/*", "../../database/build/src/*"], - "@entity/*": ["../database/entity/*", "../../database/build/entity/*"] + "@entity/*": ["../database/entity/*", "../../database/build/entity/*"], + "@logging/*": ["../database/logging/*", "../../database/build/logging/*"] }, // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ "typeRoots": ["@types", "node_modules/@types"], /* List of folders to include type definitions from. */ diff --git a/database/logging/AbstractLogging.view.ts b/database/logging/AbstractLogging.view.ts index a30254b86..e51f3823d 100644 --- a/database/logging/AbstractLogging.view.ts +++ b/database/logging/AbstractLogging.view.ts @@ -3,13 +3,18 @@ import util from 'util' import { Decimal } from 'decimal.js-light' export abstract class AbstractLoggingView { + // eslint-disable-next-line no-undef protected bufferStringFormat: BufferEncoding = 'hex' // This function gets called automatically when JSON.stringify() is called on this class instance // eslint-disable-next-line @typescript-eslint/no-explicit-any public abstract toJSON(): any - public toString(): string { - return JSON.stringify(this.toJSON(), null, 2) + public toString(compact = false): string { + if (compact) { + return JSON.stringify(this.toJSON()) + } else { + return JSON.stringify(this.toJSON(), null, 2) + } } // called form console.log or log4js logging functions diff --git a/database/logging/FederatedCommunityLogging.view.ts b/database/logging/FederatedCommunityLogging.view.ts new file mode 100644 index 000000000..4e36cc236 --- /dev/null +++ b/database/logging/FederatedCommunityLogging.view.ts @@ -0,0 +1,24 @@ +import { FederatedCommunity } from '../entity/FederatedCommunity' +import { AbstractLoggingView } from './AbstractLogging.view' + +export class FederatedCommunityLoggingView extends AbstractLoggingView { + public constructor(private self: FederatedCommunity) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + id: this.self.id, + foreign: this.self.foreign, + publicKey: this.self.publicKey.toString(this.bufferStringFormat), + apiVersion: this.self.apiVersion, + endPoint: this.self.endPoint, + lastAnnouncedAt: this.dateToString(this.self.lastAnnouncedAt), + verifiedAt: this.self.verifiedAt, + lastErrorAt: this.self.lastErrorAt, + createdAt: this.dateToString(this.self.createdAt), + updatedAt: this.dateToString(this.self.updatedAt), + } + } +} diff --git a/dht-node/.env.dist b/dht-node/.env.dist index 51728d3e1..fa07fc904 100644 --- a/dht-node/.env.dist +++ b/dht-node/.env.dist @@ -15,5 +15,5 @@ TYPEORM_LOGGING_RELATIVE_PATH=typeorm.dht-node.log FEDERATION_DHT_TOPIC=GRADIDO_HUB # FEDERATION_DHT_SEED=64ebcb0e3ad547848fef4197c6e2332f FEDERATION_COMMUNITY_URL=http://localhost -# the api port is the dht baseport, which will be added with the supported api-versions, e.g. 1_0 = 5010 -FEDERATION_COMMUNITY_API_PORT=5000 +# comma separated values, which apis should be announced +FEDERATION_COMMUNITY_APIS=1_0 \ No newline at end of file diff --git a/dht-node/.env.template b/dht-node/.env.template index 1278f61be..324d2c3a7 100644 --- a/dht-node/.env.template +++ b/dht-node/.env.template @@ -20,4 +20,5 @@ FEDERATION_DHT_CONFIG_VERSION=$FEDERATION_DHT_CONFIG_VERSION FEDERATION_DHT_TOPIC=$FEDERATION_DHT_TOPIC FEDERATION_DHT_SEED=$FEDERATION_DHT_SEED FEDERATION_COMMUNITY_URL=$FEDERATION_COMMUNITY_URL -FEDERATION_COMMUNITY_API_PORT=$FEDERATION_COMMUNITY_API_PORT +# comma separated values, which apis should be announced +FEDERATION_COMMUNITY_APIS=$FEDERATION_COMMUNITY_APIS \ No newline at end of file diff --git a/dht-node/src/config/index.ts b/dht-node/src/config/index.ts index 3459ec058..3599dd3c4 100644 --- a/dht-node/src/config/index.ts +++ b/dht-node/src/config/index.ts @@ -10,7 +10,7 @@ const constants = { LOG_LEVEL: process.env.LOG_LEVEL || 'info', CONFIG_VERSION: { DEFAULT: 'DEFAULT', - EXPECTED: 'v3.2023-04-26', + EXPECTED: 'v4.2024-01-17', CURRENT: '', }, } @@ -39,7 +39,7 @@ const federation = { FEDERATION_DHT_TOPIC: process.env.FEDERATION_DHT_TOPIC || 'GRADIDO_HUB', FEDERATION_DHT_SEED: process.env.FEDERATION_DHT_SEED || null, FEDERATION_COMMUNITY_URL: process.env.FEDERATION_COMMUNITY_URL || 'http://localhost', - FEDERATION_COMMUNITY_API_PORT: process.env.FEDERATION_COMMUNITY_API_PORT || '5000', + FEDERATION_COMMUNITY_APIS: process.env.FEDERATION_COMMUNITY_APIS || '1_0', } // Check config version diff --git a/dht-node/src/dht_node/index.ts b/dht-node/src/dht_node/index.ts index 536966591..dd17b7049 100644 --- a/dht-node/src/dht_node/index.ts +++ b/dht-node/src/dht_node/index.ts @@ -18,8 +18,8 @@ const ANNOUNCETIME = 30000 enum ApiVersionType { V1_0 = '1_0', - V1_1 = '1_1', - V2_0 = '2_0', + V1_1 = '1_1', // currently no changes + V2_0 = '2_0', // not exist } type CommunityApi = { api: string @@ -191,9 +191,11 @@ export const startDHT = async (topic: string): Promise => { } async function writeFederatedHomeCommunityEntries(pubKey: string): Promise { - const homeApiVersions: CommunityApi[] = Object.values(ApiVersionType).map(function (apiEnum) { + const homeApiVersions: CommunityApi[] = CONFIG.FEDERATION_COMMUNITY_APIS.split(',').map(function ( + api, + ) { const comApi: CommunityApi = { - api: apiEnum, + api, url: CONFIG.FEDERATION_COMMUNITY_URL + '/api/', } return comApi diff --git a/federation/src/graphql/api/1_0/logger/GetPublicCommunityInfoResultLogging.view.ts b/federation/src/graphql/api/1_0/logger/GetPublicCommunityInfoResultLogging.view.ts new file mode 100644 index 000000000..669170b98 --- /dev/null +++ b/federation/src/graphql/api/1_0/logger/GetPublicCommunityInfoResultLogging.view.ts @@ -0,0 +1,18 @@ +import { GetPublicCommunityInfoResult } from '@/graphql/api/1_0/model/GetPublicCommunityInfoResult' +import { AbstractLoggingView } from '@logging/AbstractLogging.view' + +export class GetPublicCommunityInfoResultLoggingView extends AbstractLoggingView { + public constructor(private self: GetPublicCommunityInfoResult) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + name: this.self.name, + description: this.self.description, + creationDate: this.dateToString(this.self.creationDate), + publicKey: this.self.publicKey, + } + } +} diff --git a/federation/src/graphql/api/1_0/logger/SendCoinsArgsLogging.view.ts b/federation/src/graphql/api/1_0/logger/SendCoinsArgsLogging.view.ts new file mode 100644 index 000000000..a12ff6372 --- /dev/null +++ b/federation/src/graphql/api/1_0/logger/SendCoinsArgsLogging.view.ts @@ -0,0 +1,23 @@ +import { AbstractLoggingView } from '@logging/AbstractLogging.view' +import { SendCoinsArgs } from '@/graphql/api/1_0/model/SendCoinsArgs' + +export class SendCoinsArgsLoggingView extends AbstractLoggingView { + public constructor(private self: SendCoinsArgs) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + recipientCommunityUuid: this.self.recipientCommunityUuid, + recipientUserIdentifier: this.self.recipientUserIdentifier, + creationDate: this.self.creationDate, + amount: this.decimalToString(this.self.amount), + memoLength: this.self.memo.length, + senderCommunityUuid: this.self.senderCommunityUuid, + senderUserUuid: this.self.senderUserUuid, + senderUserName: this.self.senderUserName.substring(0, 3), + senderAlias: this.self.senderAlias?.substring(0, 3), + } + } +} diff --git a/federation/src/graphql/api/1_0/model/GetPublicCommunityInfoResult.ts b/federation/src/graphql/api/1_0/model/GetPublicCommunityInfoResult.ts index 86ea480df..d51b3af93 100644 --- a/federation/src/graphql/api/1_0/model/GetPublicCommunityInfoResult.ts +++ b/federation/src/graphql/api/1_0/model/GetPublicCommunityInfoResult.ts @@ -7,7 +7,7 @@ import { Field, ObjectType } from 'type-graphql' // eslint-disable-next-line @typescript-eslint/no-unused-vars export class GetPublicCommunityInfoResult { constructor(dbCom: DbCommunity) { - this.publicKey = dbCom.publicKey.toString() + this.publicKey = dbCom.publicKey.toString('hex') this.name = dbCom.name this.description = dbCom.description this.creationDate = dbCom.creationDate diff --git a/federation/src/graphql/api/1_0/resolver/AuthenticationResolver.ts b/federation/src/graphql/api/1_0/resolver/AuthenticationResolver.ts index 8f7b510cf..393fe3b65 100644 --- a/federation/src/graphql/api/1_0/resolver/AuthenticationResolver.ts +++ b/federation/src/graphql/api/1_0/resolver/AuthenticationResolver.ts @@ -3,6 +3,8 @@ import { Arg, Mutation, Resolver } from 'type-graphql' import { federationLogger as logger } from '@/server/logger' import { Community as DbCommunity } from '@entity/Community' import { FederatedCommunity as DbFedCommunity } from '@entity/FederatedCommunity' +import { CommunityLoggingView } from '@logging/CommunityLogging.view' +import { FederatedCommunityLoggingView } from '@logging/FederatedCommunityLogging.view' import { LogError } from '@/server/LogError' import { OpenConnectionArgs } from '../model/OpenConnectionArgs' import { startAuthentication, startOpenConnectionCallback } from '../util/authenticateCommunity' @@ -11,7 +13,6 @@ import { CONFIG } from '@/config' import { AuthenticationArgs } from '../model/AuthenticationArgs' @Resolver() -// eslint-disable-next-line @typescript-eslint/no-unused-vars export class AuthenticationResolver { @Mutation(() => Boolean) async openConnection( @@ -28,7 +29,7 @@ export class AuthenticationResolver { if (!comA) { throw new LogError(`unknown requesting community with publicKey`, pubKeyBuf.toString('hex')) } - logger.debug(`Authentication: found requestedCom:`, comA) + logger.debug(`Authentication: found requestedCom:`, new CommunityLoggingView(comA)) // no await to respond immediatly and invoke callback-request asynchron void startOpenConnectionCallback(args, comA, CONFIG.FEDERATION_API) return true @@ -48,7 +49,10 @@ export class AuthenticationResolver { if (!fedComB) { throw new LogError(`unknown callback community with url`, args.url) } - logger.debug(`Authentication: found fedComB and start authentication:`, fedComB) + logger.debug( + `Authentication: found fedComB and start authentication:`, + new FederatedCommunityLoggingView(fedComB), + ) // no await to respond immediatly and invoke authenticate-request asynchron void startAuthentication(args.oneTimeCode, fedComB) return true @@ -61,13 +65,16 @@ export class AuthenticationResolver { ): Promise { logger.debug(`Authentication: authenticate() via apiVersion=1_0 ...`, args) const authCom = await DbCommunity.findOneByOrFail({ communityUuid: args.oneTimeCode }) - logger.debug('Authentication: found authCom:', authCom) + logger.debug('Authentication: found authCom:', new CommunityLoggingView(authCom)) if (authCom) { // TODO decrypt args.uuid with authCom.publicKey authCom.communityUuid = args.uuid authCom.authenticatedAt = new Date() await DbCommunity.save(authCom) - logger.debug('Authentication: store authCom.uuid successfully:', authCom) + logger.debug( + 'Authentication: store authCom.uuid successfully:', + new CommunityLoggingView(authCom), + ) const homeCom = await DbCommunity.findOneByOrFail({ foreign: false }) // TODO encrypt homeCom.uuid with homeCom.privateKey if (homeCom.communityUuid) { diff --git a/federation/src/graphql/api/1_0/resolver/PublicCommunityInfoResolver.ts b/federation/src/graphql/api/1_0/resolver/PublicCommunityInfoResolver.ts index 339314f86..c1535b713 100644 --- a/federation/src/graphql/api/1_0/resolver/PublicCommunityInfoResolver.ts +++ b/federation/src/graphql/api/1_0/resolver/PublicCommunityInfoResolver.ts @@ -3,16 +3,19 @@ import { Query, Resolver } from 'type-graphql' import { federationLogger as logger } from '@/server/logger' import { Community as DbCommunity } from '@entity/Community' import { GetPublicCommunityInfoResult } from '../model/GetPublicCommunityInfoResult' +import { GetPublicCommunityInfoResultLoggingView } from '../logger/GetPublicCommunityInfoResultLogging.view' @Resolver() -// eslint-disable-next-line @typescript-eslint/no-unused-vars export class PublicCommunityInfoResolver { @Query(() => GetPublicCommunityInfoResult) async getPublicCommunityInfo(): Promise { logger.debug(`getPublicCommunityInfo() via apiVersion=1_0 ...`) const homeCom = await DbCommunity.findOneByOrFail({ foreign: false }) const result = new GetPublicCommunityInfoResult(homeCom) - logger.debug(`getPublicCommunityInfo()-1_0... return publicInfo=${JSON.stringify(result)}`) + const publicInfoView = new GetPublicCommunityInfoResultLoggingView(result) + logger.debug( + `getPublicCommunityInfo()-1_0... return publicInfo=${publicInfoView.toString(true)}`, + ) return result } } diff --git a/federation/src/graphql/api/1_0/resolver/PublicKeyResolver.ts b/federation/src/graphql/api/1_0/resolver/PublicKeyResolver.ts index bab0e25f5..3fb3b2c0d 100644 --- a/federation/src/graphql/api/1_0/resolver/PublicKeyResolver.ts +++ b/federation/src/graphql/api/1_0/resolver/PublicKeyResolver.ts @@ -5,7 +5,6 @@ import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCom import { GetPublicKeyResult } from '../model/GetPublicKeyResult' @Resolver() -// eslint-disable-next-line @typescript-eslint/no-unused-vars export class PublicKeyResolver { @Query(() => GetPublicKeyResult) async getPublicKey(): Promise { @@ -16,7 +15,8 @@ export class PublicKeyResolver { apiVersion: '1_0', }, }) - logger.debug(`getPublicKey()-1_0... return publicKey=${homeCom.publicKey}`) - return new GetPublicKeyResult(homeCom.publicKey.toString()) + const publicKeyHex = homeCom.publicKey.toString('hex') + logger.debug(`getPublicKey()-1_0... return publicKey=${publicKeyHex}`) + return new GetPublicKeyResult(publicKeyHex) } } diff --git a/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.ts b/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.ts index aa6e2300e..dd5a81a45 100644 --- a/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.ts +++ b/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.ts @@ -1,5 +1,4 @@ -// eslint-disable-next-line @typescript-eslint/no-unused-vars -import { Arg, Args, Mutation, Resolver } from 'type-graphql' +import { Arg, Mutation, Resolver } from 'type-graphql' import { federationLogger as logger } from '@/server/logger' import { Community as DbCommunity } from '@entity/Community' import { PendingTransaction as DbPendingTransaction } from '@entity/PendingTransaction' @@ -16,27 +15,16 @@ import { findUserByIdentifier } from '@/graphql/util/findUserByIdentifier' import { SendCoinsResult } from '../model/SendCoinsResult' import Decimal from 'decimal.js-light' import { storeForeignUser } from '../util/storeForeignUser' +import { SendCoinsArgsLoggingView } from '../logger/SendCoinsArgsLogging.view' @Resolver() -// eslint-disable-next-line @typescript-eslint/no-unused-vars export class SendCoinsResolver { @Mutation(() => SendCoinsResult) async voteForSendCoins( @Arg('data') args: SendCoinsArgs, ): Promise { - logger.debug( - `voteForSendCoins() via apiVersion=1_0 ...`, - args.recipientCommunityUuid, - args.recipientUserIdentifier, - args.creationDate, - args.amount.toString(), - args.memo, - args.senderCommunityUuid, - args.senderUserUuid, - args.senderUserName, - args.senderAlias, - ) + logger.debug(`voteForSendCoins() via apiVersion=1_0 ...`, new SendCoinsArgsLoggingView(args)) const result = new SendCoinsResult() // first check if receiver community is correct const homeCom = await DbCommunity.findOneBy({ @@ -167,19 +155,11 @@ export class SendCoinsResolver { pendingTx?.amount.toString(), args.amount.toString(), ) - throw new LogError( - `Can't find in revertSendCoins the pending receiver TX for args=`, - args.recipientCommunityUuid, - args.recipientUserIdentifier, - PendingTransactionState.NEW, - TransactionTypeId.RECEIVE, - args.creationDate, - args.amount, - args.memo, - args.senderCommunityUuid, - args.senderUserUuid, - args.senderUserName, - ) + throw new LogError(`Can't find in revertSendCoins the pending receiver TX for `, { + args: new SendCoinsArgsLoggingView(args), + pendingTransactionState: PendingTransactionState.NEW, + transactionType: TransactionTypeId.RECEIVE, + }) } logger.debug(`revertSendCoins()-1_0... successfull`) return true @@ -193,15 +173,7 @@ export class SendCoinsResolver { @Arg('data') args: SendCoinsArgs, ): Promise { - logger.debug( - `settleSendCoins() via apiVersion=1_0 ...userCommunityUuid=${ - args.recipientCommunityUuid - }, userGradidoID=${args.recipientUserIdentifier}, balanceDate=${ - args.creationDate - },amount=${args.amount.valueOf()}, memo=${args.memo}, linkedUserCommunityUuid = ${ - args.senderCommunityUuid - }, userSenderIdentifier=${args.senderUserUuid}, userSenderName=${args.senderUserName}`, - ) + logger.debug(`settleSendCoins() via apiVersion=1_0 ...`, new SendCoinsArgsLoggingView(args)) // first check if receiver community is correct const homeCom = await DbCommunity.findOneBy({ communityUuid: args.recipientCommunityUuid, @@ -256,17 +228,12 @@ export class SendCoinsResolver { } else { logger.debug('XCom: settlePendingReceiveTransaction NOT matching pendingTX for settlement...') throw new LogError( - `Can't find in settlePendingReceiveTransaction the pending receiver TX for args=`, - args.recipientCommunityUuid, - args.recipientUserIdentifier, - PendingTransactionState.NEW, - TransactionTypeId.RECEIVE, - args.creationDate, - args.amount, - args.memo, - args.senderCommunityUuid, - args.senderUserUuid, - args.senderUserName, + `Can't find in settlePendingReceiveTransaction the pending receiver TX for `, + { + args: new SendCoinsArgsLoggingView(args), + pendingTransactionState: PendingTransactionState.NEW, + transactionTypeId: TransactionTypeId.RECEIVE, + }, ) } } @@ -322,19 +289,11 @@ export class SendCoinsResolver { } } else { logger.debug('XCom: revertSettledSendCoins NOT matching pendingTX...') - throw new LogError( - `Can't find in revertSettledSendCoins the pending receiver TX for args=`, - args.recipientCommunityUuid, - args.recipientUserIdentifier, - PendingTransactionState.SETTLED, - TransactionTypeId.RECEIVE, - args.creationDate, - args.amount, - args.memo, - args.senderCommunityUuid, - args.senderUserUuid, - args.senderUserName, - ) + throw new LogError(`Can't find in revertSettledSendCoins the pending receiver TX for `, { + args: new SendCoinsArgsLoggingView(args), + pendingTransactionState: PendingTransactionState.SETTLED, + transactionTypeId: TransactionTypeId.RECEIVE, + }) } logger.debug(`revertSendCoins()-1_0... successfull`) return true diff --git a/federation/src/graphql/api/1_0/util/authenticateCommunity.ts b/federation/src/graphql/api/1_0/util/authenticateCommunity.ts index 0af3475ef..b672fe7fd 100644 --- a/federation/src/graphql/api/1_0/util/authenticateCommunity.ts +++ b/federation/src/graphql/api/1_0/util/authenticateCommunity.ts @@ -9,13 +9,18 @@ import { AuthenticationClientFactory } from '@/client/AuthenticationClientFactor // eslint-disable-next-line camelcase import { AuthenticationClient as V1_0_AuthenticationClient } from '@/client/1_0/AuthenticationClient' import { AuthenticationArgs } from '../model/AuthenticationArgs' +import { CommunityLoggingView } from '@logging/CommunityLogging.view' +import { FederatedCommunityLoggingView } from '@logging/FederatedCommunityLogging.view' export async function startOpenConnectionCallback( args: OpenConnectionArgs, comA: DbCommunity, api: string, ): Promise { - logger.debug(`Authentication: startOpenConnectionCallback() with:`, args, comA) + logger.debug(`Authentication: startOpenConnectionCallback() with:`, { + args, + comA: new CommunityLoggingView(comA), + }) try { const homeFedCom = await DbFedCommunity.findOneByOrFail({ foreign: false, @@ -30,7 +35,10 @@ export async function startOpenConnectionCallback( // store oneTimeCode in requestedCom.community_uuid as authenticate-request-identifier comA.communityUuid = oneTimeCode.toString() await DbCommunity.save(comA) - logger.debug(`Authentication: stored oneTimeCode in requestedCom:`, comA) + logger.debug( + `Authentication: stored oneTimeCode in requestedCom:`, + new CommunityLoggingView(comA), + ) const client = AuthenticationClientFactory.getInstance(fedComA) // eslint-disable-next-line camelcase @@ -57,7 +65,10 @@ export async function startAuthentication( oneTimeCode: string, fedComB: DbFedCommunity, ): Promise { - logger.debug(`Authentication: startAuthentication()...`, oneTimeCode, fedComB) + logger.debug(`Authentication: startAuthentication()...`, { + oneTimeCode, + fedComB: new FederatedCommunityLoggingView(fedComB), + }) try { const homeCom = await DbCommunity.findOneByOrFail({ foreign: false }) @@ -88,7 +99,10 @@ export async function startAuthentication( callbackCom.communityUuid = fedComUuid callbackCom.authenticatedAt = new Date() await DbCommunity.save(callbackCom) - logger.debug('Authentication: Community Authentication successful:', callbackCom) + logger.debug( + 'Authentication: Community Authentication successful:', + new CommunityLoggingView(callbackCom), + ) } else { logger.error('Authentication: Community Authentication failed:', authenticationArgs) } diff --git a/federation/tsconfig.json b/federation/tsconfig.json index 50ce9d0c7..0f96e80e5 100644 --- a/federation/tsconfig.json +++ b/federation/tsconfig.json @@ -60,7 +60,8 @@ /* external */ "@typeorm/*": ["../backend/src/typeorm/*", "../../backend/src/typeorm/*"], "@dbTools/*": ["../database/src/*", "../../database/build/src/*"], - "@entity/*": ["../database/entity/*", "../../database/build/entity/*"] + "@entity/*": ["../database/entity/*", "../../database/build/entity/*"], + "@logging/*": ["../database/logging/*", "../../database/build/logging/*"] }, // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ "typeRoots": ["node_modules/@types"], /* List of folders to include type definitions from. */ From dd53870dcfa8a53356a562a5272b02c66813d3e4 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Thu, 18 Jan 2024 13:14:05 +0100 Subject: [PATCH 03/18] use hex format --- backend/src/graphql/model/FederatedCommunity.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/graphql/model/FederatedCommunity.ts b/backend/src/graphql/model/FederatedCommunity.ts index 856a10d23..61ffd8f5b 100644 --- a/backend/src/graphql/model/FederatedCommunity.ts +++ b/backend/src/graphql/model/FederatedCommunity.ts @@ -6,7 +6,7 @@ export class FederatedCommunity { constructor(dbCom: DbFederatedCommunity) { this.id = dbCom.id this.foreign = dbCom.foreign - this.publicKey = dbCom.publicKey.toString() + this.publicKey = dbCom.publicKey.toString('hex') this.url = (dbCom.endPoint.endsWith('/') ? dbCom.endPoint : dbCom.endPoint + '/') + dbCom.apiVersion this.lastAnnouncedAt = dbCom.lastAnnouncedAt From 9e0b1f72e83bc390330f8d40ff8ab4b3f01558aa Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Thu, 18 Jan 2024 14:36:18 +0100 Subject: [PATCH 04/18] fix test --- dht-node/jest.config.js | 5 +++++ dht-node/src/dht_node/index.test.ts | 7 ++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/dht-node/jest.config.js b/dht-node/jest.config.js index 6540cc68f..12543f8e2 100644 --- a/dht-node/jest.config.js +++ b/dht-node/jest.config.js @@ -21,6 +21,11 @@ module.exports = { process.env.NODE_ENV === 'development' ? '/../database/entity/$1' : '/../database/build/entity/$1', + '@logging/(.*)': + // eslint-disable-next-line n/no-process-env + process.env.NODE_ENV === 'development' + ? '/../database/logging/$1' + : '/../database/build/logging/$1', '@dbTools/(.*)': // eslint-disable-next-line n/no-process-env process.env.NODE_ENV === 'development' diff --git a/dht-node/src/dht_node/index.test.ts b/dht-node/src/dht_node/index.test.ts index 4370a2528..fc2ce7d12 100644 --- a/dht-node/src/dht_node/index.test.ts +++ b/dht-node/src/dht_node/index.test.ts @@ -14,6 +14,7 @@ import { CONFIG } from '@/config' import { startDHT } from './index' CONFIG.FEDERATION_DHT_SEED = '64ebcb0e3ad547848fef4197c6e2332f' +CONFIG.FEDERATION_COMMUNITY_APIS = '1_0,1_1,2_0' jest.mock('@hyperswarm/dht') @@ -248,7 +249,7 @@ describe('federation', () => { it('logs an error of unexpected data format and structure', () => { expect(logger.error).toBeCalledWith( 'Error on receiving data from socket:', - new SyntaxError('Unexpected token \'o\', "no-json string" is not valid JSON'), + new SyntaxError('Unexpected token o in JSON at position 1'), ) }) }) @@ -267,7 +268,7 @@ describe('federation', () => { it('logs an error of unexpected data format and structure', () => { expect(logger.error).toBeCalledWith( 'Error on receiving data from socket:', - new SyntaxError('Unexpected token \'i\', "invalid ty"... is not valid JSON'), + new SyntaxError('Unexpected token i in JSON at position 0'), ) }) }) @@ -291,7 +292,7 @@ describe('federation', () => { it('logs an error of unexpected data format and structure', () => { expect(logger.error).toBeCalledWith( 'Error on receiving data from socket:', - new SyntaxError('Unexpected token \'a\', "api,url,in"... is not valid JSON'), + new SyntaxError('Unexpected token a in JSON at position 0'), ) }) }) From 54d6eb03c562b0e0995051f2608c383e8bda3134 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Thu, 18 Jan 2024 19:59:05 +0100 Subject: [PATCH 05/18] fix missing file --- dht-node/jest.config.js | 2 +- dht-node/src/dht_node/ApiVersionType.ts | 5 +++++ dht-node/src/dht_node/index.ts | 9 ++++----- 3 files changed, 10 insertions(+), 6 deletions(-) create mode 100644 dht-node/src/dht_node/ApiVersionType.ts diff --git a/dht-node/jest.config.js b/dht-node/jest.config.js index 12543f8e2..0bb09f0e4 100644 --- a/dht-node/jest.config.js +++ b/dht-node/jest.config.js @@ -7,7 +7,7 @@ module.exports = { collectCoverageFrom: ['src/**/*.ts', '!**/node_modules/**', '!src/seeds/**', '!build/**'], coverageThreshold: { global: { - lines: 83, + lines: 82, }, }, setupFiles: ['/test/testSetup.ts'], diff --git a/dht-node/src/dht_node/ApiVersionType.ts b/dht-node/src/dht_node/ApiVersionType.ts new file mode 100644 index 000000000..84eb3e39b --- /dev/null +++ b/dht-node/src/dht_node/ApiVersionType.ts @@ -0,0 +1,5 @@ +export enum ApiVersionType { + V1_0 = '1_0', + V1_1 = '1_1', // currently no changes + V2_0 = '2_0', // not exist +} diff --git a/dht-node/src/dht_node/index.ts b/dht-node/src/dht_node/index.ts index dd17b7049..657dac8d0 100644 --- a/dht-node/src/dht_node/index.ts +++ b/dht-node/src/dht_node/index.ts @@ -8,6 +8,7 @@ import { v4 as uuidv4 } from 'uuid' import { CONFIG } from '@/config' import { logger } from '@/server/logger' +import { ApiVersionType } from './ApiVersionType' const KEY_SECRET_SEEDBYTES = 32 @@ -16,11 +17,6 @@ const SUCCESSTIME = 120000 const ERRORTIME = 240000 const ANNOUNCETIME = 30000 -enum ApiVersionType { - V1_0 = '1_0', - V1_1 = '1_1', // currently no changes - V2_0 = '2_0', // not exist -} type CommunityApi = { api: string url: string @@ -194,6 +190,9 @@ async function writeFederatedHomeCommunityEntries(pubKey: string): Promise Date: Fri, 19 Jan 2024 11:42:32 +0100 Subject: [PATCH 06/18] fix lint --- dht-node/src/dht_node/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/dht-node/src/dht_node/index.ts b/dht-node/src/dht_node/index.ts index 657dac8d0..c5f5cf4c2 100644 --- a/dht-node/src/dht_node/index.ts +++ b/dht-node/src/dht_node/index.ts @@ -8,6 +8,7 @@ import { v4 as uuidv4 } from 'uuid' import { CONFIG } from '@/config' import { logger } from '@/server/logger' + import { ApiVersionType } from './ApiVersionType' const KEY_SECRET_SEEDBYTES = 32 From 74186e21ae23afa3049328db3e5802257c63a9db Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Fri, 19 Jan 2024 13:40:21 +0100 Subject: [PATCH 07/18] more logging classes, fix test --- database/logging/ContributionLogging.view.ts | 45 ++++++++++++++ .../ContributionMessageLogging.view.ts | 30 ++++++++++ .../logging/DltTransactionLogging.view.ts | 23 +++++++ .../logging/PendingTransactionLogging.view.ts | 27 +++++++++ database/logging/TransactionLogging.view.ts | 56 +++++++++++++++++ database/logging/UserContactLogging.view.ts | 35 +++++++++++ database/logging/UserLogging.view.ts | 60 +++++++++++++++++++ database/logging/UserRoleLogging.view.ts | 22 +++++++ federation/jest.config.js | 5 ++ .../PublicCommunityInfoResolver.test.ts | 7 ++- .../1_0/resolver/PublicKeyResolver.test.ts | 7 ++- .../api/1_0/resolver/SendCoinsResolver.ts | 16 ++++- .../api/1_0/util/authenticateCommunity.ts | 2 +- .../util/revertSettledReceiveTransaction.ts | 27 ++++++--- .../util/settlePendingReceiveTransaction.ts | 12 +++- .../graphql/api/1_0/util/storeForeignUser.ts | 15 ++--- .../1_1/resolver/PublicKeyResolver.test.ts | 7 ++- 17 files changed, 369 insertions(+), 27 deletions(-) create mode 100644 database/logging/ContributionLogging.view.ts create mode 100644 database/logging/ContributionMessageLogging.view.ts create mode 100644 database/logging/DltTransactionLogging.view.ts create mode 100644 database/logging/PendingTransactionLogging.view.ts create mode 100644 database/logging/TransactionLogging.view.ts create mode 100644 database/logging/UserContactLogging.view.ts create mode 100644 database/logging/UserLogging.view.ts create mode 100644 database/logging/UserRoleLogging.view.ts diff --git a/database/logging/ContributionLogging.view.ts b/database/logging/ContributionLogging.view.ts new file mode 100644 index 000000000..c924525d2 --- /dev/null +++ b/database/logging/ContributionLogging.view.ts @@ -0,0 +1,45 @@ +import { Contribution } from '../entity/Contribution' +import { AbstractLoggingView } from './AbstractLogging.view' +import { ContributionMessageLoggingView } from './ContributionMessageLogging.view' +import { TransactionLoggingView } from './TransactionLogging.view' +import { UserLoggingView } from './UserLogging.view' + +export class ContributionLoggingView extends AbstractLoggingView { + public constructor(private self: Contribution) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + id: this.self.id, + user: this.self.user + ? new UserLoggingView(this.self.user).toJSON() + : { id: this.self.userId }, + createdAt: this.dateToString(this.self.createdAt), + resubmissionAt: this.dateToString(this.self.resubmissionAt), + contributionDate: this.dateToString(this.self.contributionDate), + memoLength: this.self.memo.length, + amount: this.decimalToString(this.self.amount), + moderatorId: this.self.moderatorId, + contributionLinkId: this.self.contributionLinkId, + confirmedBy: this.self.confirmedBy, + confirmedAt: this.dateToString(this.self.confirmedAt), + deniedBy: this.self.deniedBy, + deniedAt: this.dateToString(this.self.deniedAt), + contributionType: this.self.contributionType, + contributionStatus: this.self.contributionStatus, + transactionId: this.self.transactionId, + updatedAt: this.dateToString(this.self.updatedAt), + updatedBy: this.self.updatedBy, + deletedAt: this.dateToString(this.self.deletedAt), + deletedBy: this.self.deletedBy, + messages: this.self.messages + ? this.self.messages.map((message) => new ContributionMessageLoggingView(message).toJSON()) + : undefined, + transaction: this.self.transaction + ? new TransactionLoggingView(this.self.transaction).toJSON() + : { id: this.self.transactionId }, + } + } +} diff --git a/database/logging/ContributionMessageLogging.view.ts b/database/logging/ContributionMessageLogging.view.ts new file mode 100644 index 000000000..d05c000bb --- /dev/null +++ b/database/logging/ContributionMessageLogging.view.ts @@ -0,0 +1,30 @@ +import { ContributionMessage } from '../entity/ContributionMessage' +import { AbstractLoggingView } from './AbstractLogging.view' +import { ContributionLoggingView } from './ContributionLogging.view' +import { UserLoggingView } from './UserLogging.view' + +export class ContributionMessageLoggingView extends AbstractLoggingView { + public constructor(private self: ContributionMessage) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + id: this.self.id, + contribution: this.self.contribution + ? new ContributionLoggingView(this.self.contribution).toJSON() + : { id: this.self.contributionId }, + user: this.self.user + ? new UserLoggingView(this.self.user).toJSON() + : { id: this.self.userId }, + messageLength: this.self.message.length, + createdAt: this.dateToString(this.self.createdAt), + updatedAt: this.dateToString(this.self.updatedAt), + deletedAt: this.dateToString(this.self.deletedAt), + deletedBy: this.self.deletedBy, + type: this.self.type, + isModerator: this.self.isModerator, + } + } +} diff --git a/database/logging/DltTransactionLogging.view.ts b/database/logging/DltTransactionLogging.view.ts new file mode 100644 index 000000000..7d1681ce2 --- /dev/null +++ b/database/logging/DltTransactionLogging.view.ts @@ -0,0 +1,23 @@ +import { DltTransaction } from '../entity/DltTransaction' +import { AbstractLoggingView } from './AbstractLogging.view' +import { TransactionLoggingView } from './TransactionLogging.view' + +export class DltTransactionLoggingView extends AbstractLoggingView { + public constructor(private self: DltTransaction) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + id: this.self.id, + transaction: this.self.transaction + ? new TransactionLoggingView(this.self.transaction).toJSON() + : { id: this.self.transactionId }, + messageId: this.self.messageId, + verified: this.self.verified, + createdAt: this.dateToString(this.self.createdAt), + verifiedAt: this.dateToString(this.self.verifiedAt), + } + } +} diff --git a/database/logging/PendingTransactionLogging.view.ts b/database/logging/PendingTransactionLogging.view.ts new file mode 100644 index 000000000..84b7f35b9 --- /dev/null +++ b/database/logging/PendingTransactionLogging.view.ts @@ -0,0 +1,27 @@ +/* eslint-disable no-unused-vars */ +import { PendingTransaction } from '../entity/PendingTransaction' +import { Transaction } from '../entity/Transaction' +import { AbstractLoggingView } from './AbstractLogging.view' +import { TransactionLoggingView } from './TransactionLogging.view' + +// TODO: move enum into database, maybe rename database +enum PendingTransactionState { + NEW = 1, + PENDING = 2, + SETTLED = 3, + REVERTED = 4, +} + +export class PendingTransactionLoggingView extends AbstractLoggingView { + public constructor(private self: PendingTransaction) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + ...new TransactionLoggingView(this.self as Transaction).toJSON(), + state: PendingTransactionState[this.self.state], + } + } +} diff --git a/database/logging/TransactionLogging.view.ts b/database/logging/TransactionLogging.view.ts new file mode 100644 index 000000000..7912c7e5d --- /dev/null +++ b/database/logging/TransactionLogging.view.ts @@ -0,0 +1,56 @@ +/* eslint-disable no-unused-vars */ +import { Transaction } from '../entity/Transaction' +import { AbstractLoggingView } from './AbstractLogging.view' +import { ContributionLoggingView } from './ContributionLogging.view' +import { DltTransactionLoggingView } from './DltTransactionLogging.view' + +// TODO: move enum into database, maybe rename database +enum TransactionTypeId { + CREATION = 1, + SEND = 2, + RECEIVE = 3, + // This is a virtual property, never occurring on the database + DECAY = 4, + LINK_SUMMARY = 5, +} + +export class TransactionLoggingView extends AbstractLoggingView { + public constructor(private self: Transaction) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + id: this.self.id, + previous: this.self.previous, + typeId: TransactionTypeId[this.self.typeId], + transactionLinkId: this.self.transactionLinkId, + amount: this.decimalToString(this.self.amount), + balance: this.decimalToString(this.self.balance), + balanceDate: this.dateToString(this.self.balanceDate), + decay: this.decimalToString(this.self.decay), + decayStart: this.dateToString(this.self.decayStart), + memoLength: this.self.memo.length, + creationDate: this.dateToString(this.self.creationDate), + userId: this.self.userId, + userCommunityUuid: this.self.userCommunityUuid, + userGradidoId: this.self.userGradidoID, + userName: this.self.userName?.substring(0, 3) + '...', + linkedUserId: this.self.linkedUserId, + linkedUserCommunityUuid: this.self.linkedUserCommunityUuid, + linkedUserGradidoID: this.self.linkedUserGradidoID, + linkedUserName: this.self.linkedUserName?.substring(0, 3) + '...', + linkedTransactionId: this.self.linkedTransactionId, + contribution: this.self.contribution + ? new ContributionLoggingView(this.self.contribution) + : undefined, + dltTransaction: this.self.dltTransaction + ? new DltTransactionLoggingView(this.self.dltTransaction).toJSON() + : undefined, + previousTransaction: this.self.previousTransaction + ? new TransactionLoggingView(this.self.previousTransaction).toJSON() + : undefined, + } + } +} diff --git a/database/logging/UserContactLogging.view.ts b/database/logging/UserContactLogging.view.ts new file mode 100644 index 000000000..ebc05843a --- /dev/null +++ b/database/logging/UserContactLogging.view.ts @@ -0,0 +1,35 @@ +/* eslint-disable no-unused-vars */ +import { UserContact } from '../entity/UserContact' +import { AbstractLoggingView } from './AbstractLogging.view' +import { UserLoggingView } from './UserLogging.view' + +enum OptInType { + EMAIL_OPT_IN_REGISTER = 1, + EMAIL_OPT_IN_RESET_PASSWORD = 2, +} + +export class UserContactLoggingView extends AbstractLoggingView { + public constructor(private self: UserContact) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + id: this.self.id, + type: this.self.type, + user: this.self.user + ? new UserLoggingView(this.self.user).toJSON() + : { id: this.self.userId }, + email: this.self.email?.substring(0, 3) + '...', + emailVerificationCode: this.self.emailVerificationCode?.substring(0, 4) + '...', + emailOptInTypeId: OptInType[this.self.emailOptInTypeId], + emailResendCount: this.self.emailResendCount, + emailChecked: this.self.emailChecked, + phone: this.self.phone ? this.self.phone.substring(0, 3) + '...' : undefined, + createdAt: this.dateToString(this.self.createdAt), + updatedAt: this.dateToString(this.self.updatedAt), + deletedAt: this.dateToString(this.self.deletedAt), + } + } +} diff --git a/database/logging/UserLogging.view.ts b/database/logging/UserLogging.view.ts new file mode 100644 index 000000000..19b3ca911 --- /dev/null +++ b/database/logging/UserLogging.view.ts @@ -0,0 +1,60 @@ +/* eslint-disable no-unused-vars */ +import { User } from '../entity/User' +import { AbstractLoggingView } from './AbstractLogging.view' +import { ContributionLoggingView } from './ContributionLogging.view' +import { ContributionMessageLoggingView } from './ContributionMessageLogging.view' +import { UserContactLoggingView } from './UserContactLogging.view' +import { UserRoleLoggingView } from './UserRoleLogging.view' + +enum PasswordEncryptionType { + NO_PASSWORD = 0, + EMAIL = 1, + GRADIDO_ID = 2, +} + +export class UserLoggingView extends AbstractLoggingView { + public constructor(private self: User) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + id: this.self.id, + foreign: this.self.foreign, + gradidoID: this.self.gradidoID, + communityUuid: this.self.communityUuid, + alias: this.self.alias?.substring(0, 3) + '...', + emailContact: this.self.emailContact + ? new UserContactLoggingView(this.self.emailContact).toJSON() + : { id: this.self.emailId }, + firstName: this.self.firstName?.substring(0, 3) + '...', + lastName: this.self.lastName?.substring(0, 3) + '...', + createdAt: this.dateToString(this.self.createdAt), + deletedAt: this.dateToString(this.self.deletedAt), + passwordEncryptionType: this.self.passwordEncryptionType as PasswordEncryptionType, + language: this.self.language, + hideAmountGDD: this.self.hideAmountGDD, + hideAmountGDT: this.self.hideAmountGDT, + userRoles: this.self.userRoles + ? this.self.userRoles.map((userRole) => new UserRoleLoggingView(userRole).toJSON()) + : undefined, + referrerId: this.self.referrerId, + contributionLinkId: this.self.contributionLinkId, + publisherId: this.self.publisherId, + contributions: this.self.contributions + ? this.self.contributions.map((contribution) => + new ContributionLoggingView(contribution).toJSON(), + ) + : undefined, + messages: this.self.messages + ? this.self.messages.map((message) => new ContributionMessageLoggingView(message).toJSON()) + : undefined, + userContacts: this.self.userContacts + ? this.self.userContacts.map((userContact) => + new UserContactLoggingView(userContact).toJSON(), + ) + : undefined, + } + } +} diff --git a/database/logging/UserRoleLogging.view.ts b/database/logging/UserRoleLogging.view.ts new file mode 100644 index 000000000..19050367b --- /dev/null +++ b/database/logging/UserRoleLogging.view.ts @@ -0,0 +1,22 @@ +import { UserRole } from '../entity/UserRole' +import { AbstractLoggingView } from './AbstractLogging.view' +import { UserLoggingView } from './UserLogging.view' + +export class UserRoleLoggingView extends AbstractLoggingView { + public constructor(private self: UserRole) { + super() + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public toJSON(): any { + return { + id: this.self.id, + user: this.self.user + ? new UserLoggingView(this.self.user).toJSON() + : { id: this.self.userId }, + role: this.self.role, + createdAt: this.dateToString(this.self.createdAt), + updatedAt: this.dateToString(this.self.updatedAt), + } + } +} diff --git a/federation/jest.config.js b/federation/jest.config.js index bd41344f5..42bac0002 100644 --- a/federation/jest.config.js +++ b/federation/jest.config.js @@ -24,6 +24,11 @@ module.exports = { process.env.NODE_ENV === 'development' ? '/../database/entity/$1' : '/../database/build/entity/$1', + '@logging/(.*)': + // eslint-disable-next-line n/no-process-env + process.env.NODE_ENV === 'development' + ? '/../database/logging/$1' + : '/../database/build/logging/$1', '@dbTools/(.*)': process.env.NODE_ENV === 'development' ? '/../database/src/$1' diff --git a/federation/src/graphql/api/1_0/resolver/PublicCommunityInfoResolver.test.ts b/federation/src/graphql/api/1_0/resolver/PublicCommunityInfoResolver.test.ts index 08544834f..2f83b4819 100644 --- a/federation/src/graphql/api/1_0/resolver/PublicCommunityInfoResolver.test.ts +++ b/federation/src/graphql/api/1_0/resolver/PublicCommunityInfoResolver.test.ts @@ -46,7 +46,10 @@ describe('PublicCommunityInfoResolver', () => { homeCom.name = 'Community-Name' homeCom.description = 'Community-Description' homeCom.creationDate = new Date() - homeCom.publicKey = Buffer.from('homeCommunity-publicKey') + homeCom.publicKey = Buffer.from( + '316f2951501f27c664e188d5128505917e8673e8bebce141f86e70907e782a08', + 'hex', + ) await DbCommunity.insert(homeCom) }) @@ -57,7 +60,7 @@ describe('PublicCommunityInfoResolver', () => { name: 'Community-Name', description: 'Community-Description', creationDate: homeCom.creationDate?.toISOString(), - publicKey: expect.stringMatching('homeCommunity-publicKey'), + publicKey: '316f2951501f27c664e188d5128505917e8673e8bebce141f86e70907e782a08', }, }, }) diff --git a/federation/src/graphql/api/1_0/resolver/PublicKeyResolver.test.ts b/federation/src/graphql/api/1_0/resolver/PublicKeyResolver.test.ts index 83c024c9f..eafd9cba7 100644 --- a/federation/src/graphql/api/1_0/resolver/PublicKeyResolver.test.ts +++ b/federation/src/graphql/api/1_0/resolver/PublicKeyResolver.test.ts @@ -39,7 +39,10 @@ describe('PublicKeyResolver', () => { homeCom.foreign = false homeCom.apiVersion = '1_0' homeCom.endPoint = 'endpoint-url' - homeCom.publicKey = Buffer.from('homeCommunity-publicKey') + homeCom.publicKey = Buffer.from( + '9f6dcd0d985cc7105cd71c3417d9c291b126c8ca90513197de02191f928ef713', + 'hex', + ) await DbFederatedCommunity.insert(homeCom) }) @@ -47,7 +50,7 @@ describe('PublicKeyResolver', () => { await expect(query({ query: getPublicKeyQuery })).resolves.toMatchObject({ data: { getPublicKey: { - publicKey: expect.stringMatching('homeCommunity-publicKey'), + publicKey: '9f6dcd0d985cc7105cd71c3417d9c291b126c8ca90513197de02191f928ef713', }, }, }) diff --git a/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.ts b/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.ts index dd5a81a45..e90a7818c 100644 --- a/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.ts +++ b/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.ts @@ -1,5 +1,6 @@ import { Arg, Mutation, Resolver } from 'type-graphql' import { federationLogger as logger } from '@/server/logger' +import { PendingTransactionLoggingView } from '@logging/PendingTransactionLogging.view' import { Community as DbCommunity } from '@entity/Community' import { PendingTransaction as DbPendingTransaction } from '@entity/PendingTransaction' import { SendCoinsArgs } from '../model/SendCoinsArgs' @@ -140,7 +141,10 @@ export class SendCoinsResolver { linkedUserCommunityUuid: args.senderCommunityUuid, linkedUserGradidoID: args.senderUserUuid, }) - logger.debug('XCom: revertSendCoins found pendingTX=', pendingTx) + logger.debug( + 'XCom: revertSendCoins found pendingTX=', + pendingTx ? new PendingTransactionLoggingView(pendingTx) : 'null', + ) if (pendingTx && pendingTx.amount.toString() === args.amount.toString()) { logger.debug('XCom: revertSendCoins matching pendingTX for remove...') try { @@ -204,7 +208,10 @@ export class SendCoinsResolver { linkedUserCommunityUuid: args.senderCommunityUuid, linkedUserGradidoID: args.senderUserUuid, }) - logger.debug('XCom: settleSendCoins found pendingTX=', pendingTx?.toString()) + logger.debug( + 'XCom: settleSendCoins found pendingTX=', + pendingTx ? new PendingTransactionLoggingView(pendingTx) : 'null', + ) if ( pendingTx && pendingTx.amount.toString() === args.amount.toString() && @@ -274,7 +281,10 @@ export class SendCoinsResolver { linkedUserCommunityUuid: args.senderCommunityUuid, linkedUserGradidoID: args.senderUserUuid, }) - logger.debug('XCom: revertSettledSendCoins found pendingTX=', pendingTx) + logger.debug( + 'XCom: revertSettledSendCoins found pendingTX=', + pendingTx ? new PendingTransactionLoggingView(pendingTx) : 'null', + ) if ( pendingTx && pendingTx.amount.toString() === args.amount.toString() && diff --git a/federation/src/graphql/api/1_0/util/authenticateCommunity.ts b/federation/src/graphql/api/1_0/util/authenticateCommunity.ts index b672fe7fd..1d3365d9c 100644 --- a/federation/src/graphql/api/1_0/util/authenticateCommunity.ts +++ b/federation/src/graphql/api/1_0/util/authenticateCommunity.ts @@ -89,7 +89,7 @@ export async function startAuthentication( logger.debug( `Authentication: received communityUUid for callbackFedCom:`, fedComUuid, - fedComB, + new FederatedCommunityLoggingView(fedComB), ) const callbackCom = await DbCommunity.findOneByOrFail({ foreign: true, diff --git a/federation/src/graphql/api/1_0/util/revertSettledReceiveTransaction.ts b/federation/src/graphql/api/1_0/util/revertSettledReceiveTransaction.ts index 4b1075cb2..bb5adec5c 100644 --- a/federation/src/graphql/api/1_0/util/revertSettledReceiveTransaction.ts +++ b/federation/src/graphql/api/1_0/util/revertSettledReceiveTransaction.ts @@ -15,6 +15,10 @@ import { federationLogger as logger } from '@/server/logger' import { getLastTransaction } from '@/graphql/util/getLastTransaction' import { TRANSACTIONS_LOCK } from '@/graphql/util/TRANSACTIONS_LOCK' +import { CommunityLoggingView } from '@logging/CommunityLogging.view' +import { UserLoggingView } from '@logging/UserLogging.view' +import { PendingTransactionLoggingView } from '@logging/PendingTransactionLogging.view' +import { TransactionLoggingView } from '@logging/TransactionLogging.view' export async function revertSettledReceiveTransaction( homeCom: DbCommunity, @@ -30,7 +34,11 @@ export async function revertSettledReceiveTransaction( logger.debug(`start Transaction for write-access...`) try { - logger.info('X-Com: revertSettledReceiveTransaction:', homeCom, receiverUser, pendingTx) + logger.info('X-Com: revertSettledReceiveTransaction:', { + homeCom: new CommunityLoggingView(homeCom), + receiverUser: new UserLoggingView(receiverUser), + pendingTx: new PendingTransactionLoggingView(pendingTx), + }) // ensure that no other pendingTx with the same sender or recipient exists const openSenderPendingTx = await DbPendingTransaction.count({ @@ -68,6 +76,7 @@ export async function revertSettledReceiveTransaction( pendingTx.balanceDate.toISOString(), ) logger.debug(`GradidoID:`, lastTransaction?.userGradidoID, pendingTx.userGradidoID) + // todo: Data privacy: personal user data in log file? logger.debug(`Name:`, lastTransaction?.userName, pendingTx.userName) logger.debug(`amount:`, lastTransaction?.amount.toString(), pendingTx.amount.toString()) logger.debug(`memo:`, lastTransaction?.memo, pendingTx.memo) @@ -90,7 +99,10 @@ export async function revertSettledReceiveTransaction( lastTransaction.linkedUserName === pendingTx.linkedUserName ) { await queryRunner.manager.remove(dbTransaction, lastTransaction) - logger.debug(`X-Com: revert settlement receive Transaction removed:`, lastTransaction) + logger.debug( + `X-Com: revert settlement receive Transaction removed:`, + new TransactionLoggingView(lastTransaction), + ) // and mark the pendingTx in the pending_transactions table as reverted pendingTx.state = PendingTransactionState.REVERTED await queryRunner.manager.save(DbPendingTransaction, pendingTx) @@ -98,12 +110,11 @@ export async function revertSettledReceiveTransaction( await queryRunner.commitTransaction() logger.debug(`commit revert settlement recipient Transaction successful...`) } else { - // TODO: if the last TX is not equivelant to pendingTX, the transactions must be corrected in EXPERT-MODE - throw new LogError( - `X-Com: missmatching transaction order for revert settlement!`, - lastTransaction, - pendingTx, - ) + // TODO: if the last TX is not equivalent to pendingTX, the transactions must be corrected in EXPERT-MODE + throw new LogError(`X-Com: mismatching transaction order for revert settlement!`, { + lastTransaction: lastTransaction ? new TransactionLoggingView(lastTransaction) : 'null', + pendingTx: new PendingTransactionLoggingView(pendingTx), + }) } /* diff --git a/federation/src/graphql/api/1_0/util/settlePendingReceiveTransaction.ts b/federation/src/graphql/api/1_0/util/settlePendingReceiveTransaction.ts index e73e7a5fd..0eadbe1c2 100644 --- a/federation/src/graphql/api/1_0/util/settlePendingReceiveTransaction.ts +++ b/federation/src/graphql/api/1_0/util/settlePendingReceiveTransaction.ts @@ -17,6 +17,10 @@ import { getLastTransaction } from '@/graphql/util/getLastTransaction' import { TRANSACTIONS_LOCK } from '@/graphql/util/TRANSACTIONS_LOCK' import { calculateRecipientBalance } from './calculateRecipientBalance' import Decimal from 'decimal.js-light' +import { CommunityLoggingView } from '@logging/CommunityLogging.view' +import { UserLoggingView } from '@logging/UserLogging.view' +import { PendingTransactionLoggingView } from '@logging/PendingTransactionLogging.view' +import { TransactionLoggingView } from '@logging/TransactionLogging.view' export async function settlePendingReceiveTransaction( homeCom: DbCommunity, @@ -32,7 +36,11 @@ export async function settlePendingReceiveTransaction( logger.debug(`start Transaction for write-access...`) try { - logger.info('X-Com: settlePendingReceiveTransaction:', homeCom, receiverUser, pendingTx) + logger.info('X-Com: settlePendingReceiveTransaction:', { + homeCom: new CommunityLoggingView(homeCom), + receiverUser: new UserLoggingView(receiverUser), + pendingTx: new PendingTransactionLoggingView(pendingTx), + }) // ensure that no other pendingTx with the same sender or recipient exists const openSenderPendingTx = await DbPendingTransaction.count({ @@ -84,7 +92,7 @@ export async function settlePendingReceiveTransaction( transactionReceive.previous = receiveBalance ? receiveBalance.lastTransactionId : null transactionReceive.linkedTransactionId = pendingTx.linkedTransactionId await queryRunner.manager.insert(dbTransaction, transactionReceive) - logger.debug(`receive Transaction inserted: ${dbTransaction}`) + logger.debug(`receive Transaction inserted: ${new TransactionLoggingView(transactionReceive)}`) // and mark the pendingTx in the pending_transactions table as settled pendingTx.state = PendingTransactionState.SETTLED diff --git a/federation/src/graphql/api/1_0/util/storeForeignUser.ts b/federation/src/graphql/api/1_0/util/storeForeignUser.ts index eeeb76a8f..861702d11 100644 --- a/federation/src/graphql/api/1_0/util/storeForeignUser.ts +++ b/federation/src/graphql/api/1_0/util/storeForeignUser.ts @@ -2,6 +2,8 @@ import { User as DbUser } from '@entity/User' import { federationLogger as logger } from '@/server/logger' import { SendCoinsArgs } from '../model/SendCoinsArgs' +import { UserLoggingView } from '@logging/UserLogging.view' +import { SendCoinsArgsLoggingView } from '../logger/SendCoinsArgsLogging.view' export async function storeForeignUser(args: SendCoinsArgs): Promise { if (args.senderCommunityUuid !== null && args.senderUserUuid !== null) { @@ -34,7 +36,7 @@ export async function storeForeignUser(args: SendCoinsArgs): Promise { } foreignUser.gradidoID = args.senderUserUuid foreignUser = await DbUser.save(foreignUser) - logger.debug('X-Com: new foreignUser inserted:', foreignUser) + logger.debug('X-Com: new foreignUser inserted:', new UserLoggingView(foreignUser)) return true } else if ( @@ -43,14 +45,13 @@ export async function storeForeignUser(args: SendCoinsArgs): Promise { args.senderUserName.slice(args.senderUserName.indexOf(' '), args.senderUserName.length) || user.alias !== args.senderAlias ) { - logger.warn( - 'X-Com: foreignUser still exists, but with different name or alias:', - user, - args, - ) + logger.warn('X-Com: foreignUser still exists, but with different name or alias:', { + user: new UserLoggingView(user), + args: new SendCoinsArgsLoggingView(args), + }) return false } else { - logger.debug('X-Com: foreignUser still exists...:', user) + logger.debug('X-Com: foreignUser still exists...:', new UserLoggingView(user)) return true } } catch (err) { diff --git a/federation/src/graphql/api/1_1/resolver/PublicKeyResolver.test.ts b/federation/src/graphql/api/1_1/resolver/PublicKeyResolver.test.ts index d41b53263..7ccec73af 100644 --- a/federation/src/graphql/api/1_1/resolver/PublicKeyResolver.test.ts +++ b/federation/src/graphql/api/1_1/resolver/PublicKeyResolver.test.ts @@ -39,7 +39,10 @@ describe('PublicKeyResolver', () => { homeCom.foreign = false homeCom.apiVersion = '1_0' homeCom.endPoint = 'endpoint-url' - homeCom.publicKey = Buffer.from('homeCommunity-publicKey') + homeCom.publicKey = Buffer.from( + '9f6dcd0d985cc7105cd71c3417d9c291b126c8ca90513197de02191f928ef713', + 'hex', + ) await DbFederatedCommunity.insert(homeCom) }) @@ -47,7 +50,7 @@ describe('PublicKeyResolver', () => { await expect(query({ query: getPublicKeyQuery })).resolves.toMatchObject({ data: { getPublicKey: { - publicKey: expect.stringMatching('homeCommunity-publicKey'), + publicKey: '9f6dcd0d985cc7105cd71c3417d9c291b126c8ca90513197de02191f928ef713', }, }, }) From f7a680c2af8d4d941b35fcb6de193be8731c071e Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Fri, 19 Jan 2024 14:20:47 +0100 Subject: [PATCH 08/18] fix test --- backend/jest.config.js | 5 + .../federation/validateCommunities.test.ts | 8 +- .../resolver/CommunityResolver.test.ts | 100 ++++++++++++++---- 3 files changed, 86 insertions(+), 27 deletions(-) diff --git a/backend/jest.config.js b/backend/jest.config.js index 32606c382..f7edec3dd 100644 --- a/backend/jest.config.js +++ b/backend/jest.config.js @@ -28,6 +28,11 @@ module.exports = { process.env.NODE_ENV === 'development' ? '/../database/entity/$1' : '/../database/build/entity/$1', + '@logging/(.*)': + // eslint-disable-next-line n/no-process-env + process.env.NODE_ENV === 'development' + ? '/../database/logging/$1' + : '/../database/build/logging/$1', '@dbTools/(.*)': // eslint-disable-next-line n/no-process-env process.env.NODE_ENV === 'development' diff --git a/backend/src/federation/validateCommunities.test.ts b/backend/src/federation/validateCommunities.test.ts index 4f6339771..9ff8d545f 100644 --- a/backend/src/federation/validateCommunities.test.ts +++ b/backend/src/federation/validateCommunities.test.ts @@ -68,7 +68,7 @@ describe('validate Communities', () => { return { data: {} } as Response }) const variables1 = { - publicKey: Buffer.from('11111111111111111111111111111111'), + publicKey: Buffer.from('11111111111111111111111111111111', 'hex'), apiVersion: '1_0', endPoint: 'http//localhost:5001/api/', lastAnnouncedAt: new Date(), @@ -113,7 +113,7 @@ describe('validate Communities', () => { } as Response }) const variables1 = { - publicKey: Buffer.from('11111111111111111111111111111111'), + publicKey: Buffer.from('11111111111111111111111111111111', 'hex'), apiVersion: '1_0', endPoint: 'http//localhost:5001/api/', lastAnnouncedAt: new Date(), @@ -195,7 +195,7 @@ describe('validate Communities', () => { } as Response }) const variables1 = { - publicKey: Buffer.from('11111111111111111111111111111111'), + publicKey: Buffer.from('11111111111111111111111111111111', 'hex'), apiVersion: '1_0', endPoint: 'http//localhost:5001/api/', lastAnnouncedAt: new Date(), @@ -315,7 +315,7 @@ describe('validate Communities', () => { } as Response }) const variables3 = { - publicKey: Buffer.from('11111111111111111111111111111111'), + publicKey: Buffer.from('11111111111111111111111111111111', 'hex'), apiVersion: '2_0', endPoint: 'http//localhost:5001/api/', lastAnnouncedAt: new Date(), diff --git a/backend/src/graphql/resolver/CommunityResolver.test.ts b/backend/src/graphql/resolver/CommunityResolver.test.ts index 011670e87..4f42e9455 100644 --- a/backend/src/graphql/resolver/CommunityResolver.test.ts +++ b/backend/src/graphql/resolver/CommunityResolver.test.ts @@ -62,7 +62,10 @@ describe('CommunityResolver', () => { homeCom1 = DbFederatedCommunity.create() homeCom1.foreign = false - homeCom1.publicKey = Buffer.from('publicKey-HomeCommunity') + homeCom1.publicKey = Buffer.from( + '75bb92ee197a5f5b645669b26b933558870d72791860e4854a41d6bb28e7d61c', + 'hex', + ) homeCom1.apiVersion = '1_0' homeCom1.endPoint = 'http://localhost/api' homeCom1.createdAt = new Date() @@ -70,7 +73,10 @@ describe('CommunityResolver', () => { homeCom2 = DbFederatedCommunity.create() homeCom2.foreign = false - homeCom2.publicKey = Buffer.from('publicKey-HomeCommunity') + homeCom2.publicKey = Buffer.from( + '5b47388f9e8db5416201e485398ed0d72ab20d9ee951ccc1754245278e3ae6c6', + 'hex', + ) homeCom2.apiVersion = '1_1' homeCom2.endPoint = 'http://localhost/api' homeCom2.createdAt = new Date() @@ -78,7 +84,10 @@ describe('CommunityResolver', () => { homeCom3 = DbFederatedCommunity.create() homeCom3.foreign = false - homeCom3.publicKey = Buffer.from('publicKey-HomeCommunity') + homeCom3.publicKey = Buffer.from( + '2ca593275aa4c11f9c3d43cd4d39586c70e2b7f4359739381940b62d1c8e8928', + 'hex', + ) homeCom3.apiVersion = '2_0' homeCom3.endPoint = 'http://localhost/api' homeCom3.createdAt = new Date() @@ -92,7 +101,9 @@ describe('CommunityResolver', () => { { id: 3, foreign: homeCom3.foreign, - publicKey: expect.stringMatching('publicKey-HomeCommunity'), + publicKey: expect.stringMatching( + '2ca593275aa4c11f9c3d43cd4d39586c70e2b7f4359739381940b62d1c8e8928', + ), url: expect.stringMatching('http://localhost/api/2_0'), lastAnnouncedAt: null, verifiedAt: null, @@ -103,7 +114,9 @@ describe('CommunityResolver', () => { { id: 2, foreign: homeCom2.foreign, - publicKey: expect.stringMatching('publicKey-HomeCommunity'), + publicKey: expect.stringMatching( + '5b47388f9e8db5416201e485398ed0d72ab20d9ee951ccc1754245278e3ae6c6', + ), url: expect.stringMatching('http://localhost/api/1_1'), lastAnnouncedAt: null, verifiedAt: null, @@ -114,7 +127,9 @@ describe('CommunityResolver', () => { { id: 1, foreign: homeCom1.foreign, - publicKey: expect.stringMatching('publicKey-HomeCommunity'), + publicKey: expect.stringMatching( + '75bb92ee197a5f5b645669b26b933558870d72791860e4854a41d6bb28e7d61c', + ), url: expect.stringMatching('http://localhost/api/1_0'), lastAnnouncedAt: null, verifiedAt: null, @@ -134,7 +149,10 @@ describe('CommunityResolver', () => { foreignCom1 = DbFederatedCommunity.create() foreignCom1.foreign = true - foreignCom1.publicKey = Buffer.from('publicKey-ForeignCommunity') + foreignCom1.publicKey = Buffer.from( + '08520bf2990274f829d2a2d45c802e4e854a768ed1c757ea99571a24bbfd87b2', + 'hex', + ) foreignCom1.apiVersion = '1_0' foreignCom1.endPoint = 'http://remotehost/api' foreignCom1.createdAt = new Date() @@ -142,7 +160,10 @@ describe('CommunityResolver', () => { foreignCom2 = DbFederatedCommunity.create() foreignCom2.foreign = true - foreignCom2.publicKey = Buffer.from('publicKey-ForeignCommunity') + foreignCom2.publicKey = Buffer.from( + '43c72cb81416121f5eb98affa4fb3360088719e80db6aaa13ff7e74d3f669307', + 'hex', + ) foreignCom2.apiVersion = '1_1' foreignCom2.endPoint = 'http://remotehost/api' foreignCom2.createdAt = new Date() @@ -150,7 +171,10 @@ describe('CommunityResolver', () => { foreignCom3 = DbFederatedCommunity.create() foreignCom3.foreign = true - foreignCom3.publicKey = Buffer.from('publicKey-ForeignCommunity') + foreignCom3.publicKey = Buffer.from( + '4e3bf9536f694124c527b0aaf45aa6aea6c8c5d570d96b54f56f583724212b73', + 'hex', + ) foreignCom3.apiVersion = '1_2' foreignCom3.endPoint = 'http://remotehost/api' foreignCom3.createdAt = new Date() @@ -164,7 +188,7 @@ describe('CommunityResolver', () => { { id: 3, foreign: homeCom3.foreign, - publicKey: expect.stringMatching('publicKey-HomeCommunity'), + publicKey: expect.stringMatching(homeCom3.publicKey.toString('hex')), url: expect.stringMatching('http://localhost/api/2_0'), lastAnnouncedAt: null, verifiedAt: null, @@ -175,7 +199,7 @@ describe('CommunityResolver', () => { { id: 2, foreign: homeCom2.foreign, - publicKey: expect.stringMatching('publicKey-HomeCommunity'), + publicKey: expect.stringMatching(homeCom2.publicKey.toString('hex')), url: expect.stringMatching('http://localhost/api/1_1'), lastAnnouncedAt: null, verifiedAt: null, @@ -186,7 +210,7 @@ describe('CommunityResolver', () => { { id: 1, foreign: homeCom1.foreign, - publicKey: expect.stringMatching('publicKey-HomeCommunity'), + publicKey: expect.stringMatching(homeCom1.publicKey.toString('hex')), url: expect.stringMatching('http://localhost/api/1_0'), lastAnnouncedAt: null, verifiedAt: null, @@ -197,7 +221,9 @@ describe('CommunityResolver', () => { { id: 6, foreign: foreignCom3.foreign, - publicKey: expect.stringMatching('publicKey-ForeignCommunity'), + publicKey: expect.stringMatching( + '4e3bf9536f694124c527b0aaf45aa6aea6c8c5d570d96b54f56f583724212b73', + ), url: expect.stringMatching('http://remotehost/api/1_2'), lastAnnouncedAt: null, verifiedAt: null, @@ -208,7 +234,9 @@ describe('CommunityResolver', () => { { id: 5, foreign: foreignCom2.foreign, - publicKey: expect.stringMatching('publicKey-ForeignCommunity'), + publicKey: expect.stringMatching( + '43c72cb81416121f5eb98affa4fb3360088719e80db6aaa13ff7e74d3f669307', + ), url: expect.stringMatching('http://remotehost/api/1_1'), lastAnnouncedAt: null, verifiedAt: null, @@ -219,7 +247,9 @@ describe('CommunityResolver', () => { { id: 4, foreign: foreignCom1.foreign, - publicKey: expect.stringMatching('publicKey-ForeignCommunity'), + publicKey: expect.stringMatching( + '08520bf2990274f829d2a2d45c802e4e854a768ed1c757ea99571a24bbfd87b2', + ), url: expect.stringMatching('http://remotehost/api/1_0'), lastAnnouncedAt: null, verifiedAt: null, @@ -264,8 +294,14 @@ describe('CommunityResolver', () => { homeCom1 = DbCommunity.create() homeCom1.foreign = false homeCom1.url = 'http://localhost/api' - homeCom1.publicKey = Buffer.from('publicKey-HomeCommunity') - homeCom1.privateKey = Buffer.from('privateKey-HomeCommunity') + homeCom1.publicKey = Buffer.from( + '75bb92ee197a5f5b645669b26b933558870d72791860e4854a41d6bb28e7d61c', + 'hex', + ) + homeCom1.privateKey = Buffer.from( + 'ddfa39122c9b1951da10a773fc0d3d020e770d89afb489691e247e08c2b7b8aa990b7dda99c5ec5df88bd9a94bc34e2e68a91d05a224ef88fa916e5a1fbb47cb', + 'hex', + ) homeCom1.communityUuid = 'HomeCom-UUID' homeCom1.authenticatedAt = new Date() homeCom1.name = 'HomeCommunity-name' @@ -302,8 +338,14 @@ describe('CommunityResolver', () => { homeCom1 = DbCommunity.create() homeCom1.foreign = false homeCom1.url = 'http://localhost/api' - homeCom1.publicKey = Buffer.from('publicKey-HomeCommunity') - homeCom1.privateKey = Buffer.from('privateKey-HomeCommunity') + homeCom1.publicKey = Buffer.from( + '75bb92ee197a5f5b645669b26b933558870d72791860e4854a41d6bb28e7d61c', + 'hex', + ) + homeCom1.privateKey = Buffer.from( + 'ddfa39122c9b1951da10a773fc0d3d020e770d89afb489691e247e08c2b7b8aa990b7dda99c5ec5df88bd9a94bc34e2e68a91d05a224ef88fa916e5a1fbb47cb', + 'hex', + ) homeCom1.communityUuid = 'HomeCom-UUID' homeCom1.authenticatedAt = new Date() homeCom1.name = 'HomeCommunity-name' @@ -314,8 +356,14 @@ describe('CommunityResolver', () => { foreignCom1 = DbCommunity.create() foreignCom1.foreign = true foreignCom1.url = 'http://stage-2.gradido.net/api' - foreignCom1.publicKey = Buffer.from('publicKey-stage-2_Community') - foreignCom1.privateKey = Buffer.from('privateKey-stage-2_Community') + foreignCom1.publicKey = Buffer.from( + '08520bf2990274f829d2a2d45c802e4e854a768ed1c757ea99571a24bbfd87b2', + 'hex', + ) + foreignCom1.privateKey = Buffer.from( + 'd967220052995169b20b89a0c6190ee8aa9ca501d7a6df81c49a97003edca2ed724d69eaf55e62290d699d7c3ec8b44985fffd57def98d51b2202f2bd82330b3', + 'hex', + ) // foreignCom1.communityUuid = 'Stage2-Com-UUID' // foreignCom1.authenticatedAt = new Date() foreignCom1.name = 'Stage-2_Community-name' @@ -326,8 +374,14 @@ describe('CommunityResolver', () => { foreignCom2 = DbCommunity.create() foreignCom2.foreign = true foreignCom2.url = 'http://stage-3.gradido.net/api' - foreignCom2.publicKey = Buffer.from('publicKey-stage-3_Community') - foreignCom2.privateKey = Buffer.from('privateKey-stage-3_Community') + foreignCom2.publicKey = Buffer.from( + '43c72cb81416121f5eb98affa4fb3360088719e80db6aaa13ff7e74d3f669307', + 'hex', + ) + foreignCom2.privateKey = Buffer.from( + '0ae8921a204bd27e1ba834ffa2f4480cca867b4def783934f3032e19c54d6e7c9fb3233eff07a0086f6bd8486e7220136ce941abdd51d268bfaca0cc3181f162', + 'hex', + ) foreignCom2.communityUuid = 'Stage3-Com-UUID' foreignCom2.authenticatedAt = new Date() foreignCom2.name = 'Stage-3_Community-name' From a1776ae67985193ca6836350547acb428bf4a34c Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Fri, 19 Jan 2024 17:36:26 +0100 Subject: [PATCH 09/18] fix test, json error message differ from node version to node version --- dht-node/src/dht_node/index.test.ts | 29 ++++++++++++++++++++++++++--- dht-node/src/dht_node/index.ts | 13 +++++++++++++ 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/dht-node/src/dht_node/index.test.ts b/dht-node/src/dht_node/index.test.ts index fc2ce7d12..c31869551 100644 --- a/dht-node/src/dht_node/index.test.ts +++ b/dht-node/src/dht_node/index.test.ts @@ -249,7 +249,30 @@ describe('federation', () => { it('logs an error of unexpected data format and structure', () => { expect(logger.error).toBeCalledWith( 'Error on receiving data from socket:', - new SyntaxError('Unexpected token o in JSON at position 1'), + new SyntaxError('Unexpected token \'o\', "no-json string" is not valid JSON'), + ) + }) + }) + + describe('with receiving non ascii character', () => { + beforeEach(() => { + jest.clearAllMocks() + // containing non-ascii character copyright symbol, U+00A9 + socketEventMocks.data(Buffer.from('48656C6C6F2C20C2A92048656C6C6F21', 'hex')) + /* + const buffer = Buffer.from('48656C6C6F2C20C2A92048656C6C6F21', 'hex') + for (const byte of buffer) { + console.log('byte: %o', byte) + if (byte > 127) { + console.log('non ascii char spotted') + } + } + */ + }) + + it('logs the binary data as hex', () => { + expect(logger.warn).toBeCalledWith( + 'received non ascii character, content as hex: 48656c6c6f2c20c2a92048656c6c6f21', ) }) }) @@ -268,7 +291,7 @@ describe('federation', () => { it('logs an error of unexpected data format and structure', () => { expect(logger.error).toBeCalledWith( 'Error on receiving data from socket:', - new SyntaxError('Unexpected token i in JSON at position 0'), + new SyntaxError('Unexpected token \'i\', "invalid ty"... is not valid JSON'), ) }) }) @@ -292,7 +315,7 @@ describe('federation', () => { it('logs an error of unexpected data format and structure', () => { expect(logger.error).toBeCalledWith( 'Error on receiving data from socket:', - new SyntaxError('Unexpected token a in JSON at position 0'), + new SyntaxError('Unexpected token \'a\', "api,url,in"... is not valid JSON'), ) }) }) diff --git a/dht-node/src/dht_node/index.ts b/dht-node/src/dht_node/index.ts index c5f5cf4c2..fab67e839 100644 --- a/dht-node/src/dht_node/index.ts +++ b/dht-node/src/dht_node/index.ts @@ -25,6 +25,15 @@ type CommunityApi = { type KeyPair = { publicKey: Buffer; secretKey: Buffer } +function isAscii(buffer: Buffer): boolean { + for (const byte of buffer) { + if (byte > 127) { + return false + } + } + return true +} + export const startDHT = async (topic: string): Promise => { try { const TOPIC = DHT.hash(Buffer.from(topic)) @@ -57,6 +66,10 @@ export const startDHT = async (topic: string): Promise => { ) return } + if (!isAscii(data)) { + logger.warn(`received non ascii character, content as hex: ${data.toString('hex')}`) + return + } logger.info(`data: ${data.toString('ascii')}`) const recApiVersions: CommunityApi[] = JSON.parse(data.toString('ascii')) From 0a553b88961729afd5b884f7a2907f8f673011fd Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Fri, 19 Jan 2024 17:57:43 +0100 Subject: [PATCH 10/18] update deployment config --- deployment/bare_metal/.env.dist | 6 +++--- dht-node/.env.template | 2 +- federation/.env.template | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/deployment/bare_metal/.env.dist b/deployment/bare_metal/.env.dist index eb1e45f79..96df6f81b 100644 --- a/deployment/bare_metal/.env.dist +++ b/deployment/bare_metal/.env.dist @@ -25,8 +25,8 @@ DATABASE_CONFIG_VERSION=v1.2022-03-18 BACKEND_CONFIG_VERSION=v21.2024-01-06 FRONTEND_CONFIG_VERSION=v5.2024-01-08 ADMIN_CONFIG_VERSION=v2.2024-01-04 -FEDERATION_CONFIG_VERSION=v1.2023-01-09 -FEDERATION_DHT_CONFIG_VERSION=v3.2023-04-26 +FEDERATION_CONFIG_VERSION=v2.2023-08-24 +FEDERATION_DHT_CONFIG_VERSION=v4.2024-01-17 FEDERATION_DHT_TOPIC=GRADIDO_HUB @@ -76,7 +76,7 @@ FEDERATION_COMMUNITY_API_PORT=5000 FEDERATION_VALIDATE_COMMUNITY_TIMER=60000 # comma separated list of api-versions, which cause starting several federation modules -FEDERATION_COMMUNITY_APIS=1_0,1_1 +FEDERATION_COMMUNITY_APIS=1_0 # externe gradido services (more added in future) GDT_API_URL=https://gdt.gradido.net diff --git a/dht-node/.env.template b/dht-node/.env.template index 3517ccc9a..629aaf069 100644 --- a/dht-node/.env.template +++ b/dht-node/.env.template @@ -1,5 +1,5 @@ # must match the CONFIG_VERSION.EXPECTED definition in scr/config/index.ts -CONFIG_VERSION=v3.2023-04-26 +CONFIG_VERSION=$FEDERATION_DHT_CONFIG_VERSION # Database DB_HOST=localhost diff --git a/federation/.env.template b/federation/.env.template index 91fb1c692..9a029c3d1 100644 --- a/federation/.env.template +++ b/federation/.env.template @@ -1,5 +1,5 @@ # must match the CONFIG_VERSION.EXPECTED definition in scr/config/index.ts -CONFIG_VERSION=v2.2023-08-24 +CONFIG_VERSION=$FEDERATION_CONFIG_VERSION LOG_LEVEL=$LOG_LEVEL # this is set fix to false, because it is important for 'production' environments. only set to true if a graphql-playground should be in use From eb51fa8719761580048972d62802c3185c9af2b2 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Fri, 19 Jan 2024 19:16:31 +0100 Subject: [PATCH 11/18] fix bug, add FEDERATION_XCOM_SENDCOINS_ENABLED to deployment script --- backend/.env.template | 1 + deployment/bare_metal/.env.dist | 3 +++ dht-node/.env.template | 1 - 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/backend/.env.template b/backend/.env.template index 1cf7d9dee..5165dcef3 100644 --- a/backend/.env.template +++ b/backend/.env.template @@ -62,3 +62,4 @@ WEBHOOK_ELOPAGE_SECRET=$WEBHOOK_ELOPAGE_SECRET # Federation FEDERATION_VALIDATE_COMMUNITY_TIMER=$FEDERATION_VALIDATE_COMMUNITY_TIMER +FEDERATION_XCOM_SENDCOINS_ENABLED=$FEDERATION_XCOM_SENDCOINS_ENABLED \ No newline at end of file diff --git a/deployment/bare_metal/.env.dist b/deployment/bare_metal/.env.dist index 96df6f81b..deba914b1 100644 --- a/deployment/bare_metal/.env.dist +++ b/deployment/bare_metal/.env.dist @@ -12,6 +12,9 @@ EMAIL_PASSWORD=1234 EMAIL_SMTP_URL=smtp.lustig.de EMAIL_SMTP_PORT=587 +# if set to true allow sending gradidos to another communities +FEDERATION_XCOM_SENDCOINS_ENABLED=false + # how many minutes email verification code is valid # also used for password reset code EMAIL_CODE_VALID_TIME=1440 diff --git a/dht-node/.env.template b/dht-node/.env.template index 629aaf069..b4cef7f5e 100644 --- a/dht-node/.env.template +++ b/dht-node/.env.template @@ -19,7 +19,6 @@ FEDERATION_DHT_CONFIG_VERSION=$FEDERATION_DHT_CONFIG_VERSION # on an hash created from this topic FEDERATION_DHT_TOPIC=$FEDERATION_DHT_TOPIC FEDERATION_DHT_SEED=$FEDERATION_DHT_SEED -FEDERATION_COMMUNITY_URL=$FEDERATION_COMMUNITY_URL # comma separated values, which apis should be announced FEDERATION_COMMUNITY_APIS=$FEDERATION_COMMUNITY_APIS COMMUNITY_HOST=$COMMUNITY_HOST From 3e32726fa103262cd2a8af0335996a48b8587165 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Mon, 22 Jan 2024 12:00:14 +0100 Subject: [PATCH 12/18] give infos for exceptions --- backend/.env.dist | 3 ++- backend/src/federation/client/1_0/FederationClient.ts | 10 ++++++++-- federation/src/client/1_0/AuthenticationClient.ts | 5 ++++- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/backend/.env.dist b/backend/.env.dist index 96afd1ab5..82f489f6c 100644 --- a/backend/.env.dist +++ b/backend/.env.dist @@ -62,4 +62,5 @@ WEBHOOK_ELOPAGE_SECRET=secret # LOG_LEVEL=info # Federation -FEDERATION_VALIDATE_COMMUNITY_TIMER=60000 \ No newline at end of file +FEDERATION_VALIDATE_COMMUNITY_TIMER=60000 +FEDERATION_XCOM_SENDCOINS_ENABLED=false \ No newline at end of file diff --git a/backend/src/federation/client/1_0/FederationClient.ts b/backend/src/federation/client/1_0/FederationClient.ts index 4a10ddc7e..8fd7744e7 100644 --- a/backend/src/federation/client/1_0/FederationClient.ts +++ b/backend/src/federation/client/1_0/FederationClient.ts @@ -46,7 +46,10 @@ export class FederationClient { ) return data.getPublicKey.publicKey } catch (err) { - logger.warn('Federation: getPublicKey failed for endpoint', this.endpoint) + logger.warn('Federation: getPublicKey failed for endpoint', { + endpoint: this.endpoint, + err, + }) } } @@ -71,7 +74,10 @@ export class FederationClient { ) return data.getPublicCommunityInfo } catch (err) { - logger.warn('Federation: getPublicCommunityInfo failed for endpoint', this.endpoint) + logger.warn('Federation: getPublicCommunityInfo failed for endpoint', { + endpoint: this.endpoint, + err, + }) } } } diff --git a/federation/src/client/1_0/AuthenticationClient.ts b/federation/src/client/1_0/AuthenticationClient.ts index bed6b88c4..3a94746b1 100644 --- a/federation/src/client/1_0/AuthenticationClient.ts +++ b/federation/src/client/1_0/AuthenticationClient.ts @@ -63,7 +63,10 @@ export class AuthenticationClient { return authUuid } } catch (err) { - logger.error('Authentication: authenticate failed for endpoint', this.endpoint) + logger.error('Authentication: authenticate failed', { + endpoint: this.endpoint, + err, + }) } return null } From eaa4161d14637fc2e7277eb2a8283ea5fe0b5a6e Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Mon, 22 Jan 2024 12:10:46 +0100 Subject: [PATCH 13/18] fix problem with lost update --- .../federation/client/1_0/FederationClient.ts | 4 ++++ .../client/FederationClientFactory.ts | 20 ++++++++++++++----- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/backend/src/federation/client/1_0/FederationClient.ts b/backend/src/federation/client/1_0/FederationClient.ts index 8fd7744e7..e3df5ecf8 100644 --- a/backend/src/federation/client/1_0/FederationClient.ts +++ b/backend/src/federation/client/1_0/FederationClient.ts @@ -28,6 +28,10 @@ export class FederationClient { }) } + getEndpoint = () => { + return this.endpoint + } + getPublicKey = async (): Promise => { logger.debug('Federation: getPublicKey from endpoint', this.endpoint) try { diff --git a/backend/src/federation/client/FederationClientFactory.ts b/backend/src/federation/client/FederationClientFactory.ts index d057ffd04..fe2ff0dbd 100644 --- a/backend/src/federation/client/FederationClientFactory.ts +++ b/backend/src/federation/client/FederationClientFactory.ts @@ -47,15 +47,25 @@ export class FederationClientFactory { const instance = FederationClientFactory.instanceArray.find( (instance) => instance.id === dbCom.id, ) - if (instance) { + // TODO: found a way to prevent double code with FederationClient::constructor + const endpoint = `${dbCom.endPoint.endsWith('/') ? dbCom.endPoint : dbCom.endPoint + '/'}${ + dbCom.apiVersion + }/` + // check if endpoint is still the same and not changed meanwhile + if (instance && instance.client.getEndpoint() === endpoint) { return instance.client } const client = FederationClientFactory.createFederationClient(dbCom) if (client) { - FederationClientFactory.instanceArray.push({ - id: dbCom.id, - client, - } as FederationClientInstance) + // only update instance if we already have one + if (instance) { + instance.client = client + } else { + FederationClientFactory.instanceArray.push({ + id: dbCom.id, + client, + } as FederationClientInstance) + } } return client } From 0640c8e371c03ab09d86ee6e9e01e12a5442341c Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Mon, 22 Jan 2024 12:33:55 +0100 Subject: [PATCH 14/18] shorting result if response was a website --- backend/src/federation/client/1_0/FederationClient.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/backend/src/federation/client/1_0/FederationClient.ts b/backend/src/federation/client/1_0/FederationClient.ts index e3df5ecf8..0b55c80a6 100644 --- a/backend/src/federation/client/1_0/FederationClient.ts +++ b/backend/src/federation/client/1_0/FederationClient.ts @@ -50,9 +50,10 @@ export class FederationClient { ) return data.getPublicKey.publicKey } catch (err) { + const errorString = JSON.stringify(err) logger.warn('Federation: getPublicKey failed for endpoint', { endpoint: this.endpoint, - err, + err: errorString.length <= 100 ? errorString : errorString.substring(0, 200) + '...', }) } } @@ -78,9 +79,10 @@ export class FederationClient { ) return data.getPublicCommunityInfo } catch (err) { + const errorString = JSON.stringify(err) logger.warn('Federation: getPublicCommunityInfo failed for endpoint', { endpoint: this.endpoint, - err, + err: errorString.length <= 100 ? errorString : errorString.substring(0, 200) + '...', }) } } From ac0244ade0be604d592e691cb3f324a21a26d996 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Tue, 23 Jan 2024 11:35:22 +0100 Subject: [PATCH 15/18] change condition to 200 --- backend/src/federation/client/1_0/FederationClient.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/federation/client/1_0/FederationClient.ts b/backend/src/federation/client/1_0/FederationClient.ts index 0b55c80a6..b9939a12c 100644 --- a/backend/src/federation/client/1_0/FederationClient.ts +++ b/backend/src/federation/client/1_0/FederationClient.ts @@ -53,7 +53,7 @@ export class FederationClient { const errorString = JSON.stringify(err) logger.warn('Federation: getPublicKey failed for endpoint', { endpoint: this.endpoint, - err: errorString.length <= 100 ? errorString : errorString.substring(0, 200) + '...', + err: errorString.length <= 200 ? errorString : errorString.substring(0, 200) + '...', }) } } @@ -82,7 +82,7 @@ export class FederationClient { const errorString = JSON.stringify(err) logger.warn('Federation: getPublicCommunityInfo failed for endpoint', { endpoint: this.endpoint, - err: errorString.length <= 100 ? errorString : errorString.substring(0, 200) + '...', + err: errorString.length <= 200 ? errorString : errorString.substring(0, 200) + '...', }) } } From 50ebcbb57b183da27a166e2f4b94bfd11bdfacd7 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Tue, 23 Jan 2024 12:11:05 +0100 Subject: [PATCH 16/18] improve tests --- .../resolver/CommunityResolver.test.ts | 154 +++++++++--------- 1 file changed, 77 insertions(+), 77 deletions(-) diff --git a/backend/src/graphql/resolver/CommunityResolver.test.ts b/backend/src/graphql/resolver/CommunityResolver.test.ts index 4f42e9455..e0cdc06fa 100644 --- a/backend/src/graphql/resolver/CommunityResolver.test.ts +++ b/backend/src/graphql/resolver/CommunityResolver.test.ts @@ -34,6 +34,60 @@ afterAll(async () => { await con.close() }) +// real valid ed25519 key pairs +const ed25519KeyPairStaticHex = [ + { + public: '264c1e88914d18166cc31e8d6c2111c03ac83f5910398eb45cd425c6c3836367', + private: + '0ddcafd5e2da92e171ccc974af22fee3ad8407475e330586c8f259837d4fedc6264c1e88914d18166cc31e8d6c2111c03ac83f5910398eb45cd425c6c3836367', + }, + { + public: 'ac18a8754f725079f93d27b9054f2eff536109a2fd439f9755941abdd639baf0', + private: + '45325a0d0f22655095321d9d05999c65245da02130318ff51da1ee423b836117ac18a8754f725079f93d27b9054f2eff536109a2fd439f9755941abdd639baf0', + }, + { + public: '6f7d4ccde610db1e1a33fabbb444d5400013c168296b03fd50bc686d4c1ad0ed', + private: + '8ab6d5da8b666ef5b3d754559c028806a1e2f8142a3e7ada411a8b6a3fe70eeb6f7d4ccde610db1e1a33fabbb444d5400013c168296b03fd50bc686d4c1ad0ed', + }, + { + public: '85fbbce0763db24677cf7cb579a743013557a4fea0a9a624245f3ae8cd785e1d', + private: + '0369ea7c80c3134c2872c3cf77a68f12d57de57359145b550e3a0c4c8170a31785fbbce0763db24677cf7cb579a743013557a4fea0a9a624245f3ae8cd785e1d', + }, + { + public: 'b099d023476ece01f231c269cbe496139ca73b3b4eb705816a511a1ca09661d0', + private: + '015ac650157b9e9bdbe718940606242daa318a251e8417b49440495e5afe3750b099d023476ece01f231c269cbe496139ca73b3b4eb705816a511a1ca09661d0', + }, + { + public: '9f8dc17f1af9f71e9b9a1cd49ca295b89049863515a487578ad4f90b307abf39', + private: + '0c13e71c55a3c03bd5df05c92bbccde88ad4a47f3bac6bdc5383ef1ec946cfdc9f8dc17f1af9f71e9b9a1cd49ca295b89049863515a487578ad4f90b307abf39', + }, + { + public: '34218b2f570d341370dd2db111d0ef2415c03a110c3bf3127c6b2337af71753a', + private: + '60f3479bba44d035886ac21c362bceece9f9ec81859c9b37f734b6442a06c93b34218b2f570d341370dd2db111d0ef2415c03a110c3bf3127c6b2337af71753a', + }, + { + public: 'a447404f5e04ed4896ed64d0f704574ed780b52e90868d4b83e1afb8ea687ff6', + private: + 'ea85ebb4332a52d87fe6f322dcd23ad4afc5eafb93dfff2216f3ffa9f0730e8aa447404f5e04ed4896ed64d0f704574ed780b52e90868d4b83e1afb8ea687ff6', + }, + { + public: 'b8b987c55da62b30d929672520551033eb37abdd88f9ea104db5d107c19680b4', + private: + '29475dbbc96d694b3c653a1e143caf084f6daf2d35267522c4096c55b47e2b76b8b987c55da62b30d929672520551033eb37abdd88f9ea104db5d107c19680b4', + }, + { + public: '40203d18a6ff8fb3c4c62d78e4807036fc9207782ce97a9bcf3be0755c236c37', + private: + '0b5c4d536d222e88b561ea495e15918fb8cba61a3f8c261ec9e587cca560804040203d18a6ff8fb3c4c62d78e4807036fc9207782ce97a9bcf3be0755c236c37', + }, +] + describe('CommunityResolver', () => { describe('getCommunities', () => { let homeCom1: DbFederatedCommunity @@ -62,10 +116,7 @@ describe('CommunityResolver', () => { homeCom1 = DbFederatedCommunity.create() homeCom1.foreign = false - homeCom1.publicKey = Buffer.from( - '75bb92ee197a5f5b645669b26b933558870d72791860e4854a41d6bb28e7d61c', - 'hex', - ) + homeCom1.publicKey = Buffer.from(ed25519KeyPairStaticHex[0].public, 'hex') homeCom1.apiVersion = '1_0' homeCom1.endPoint = 'http://localhost/api' homeCom1.createdAt = new Date() @@ -73,10 +124,7 @@ describe('CommunityResolver', () => { homeCom2 = DbFederatedCommunity.create() homeCom2.foreign = false - homeCom2.publicKey = Buffer.from( - '5b47388f9e8db5416201e485398ed0d72ab20d9ee951ccc1754245278e3ae6c6', - 'hex', - ) + homeCom2.publicKey = Buffer.from(ed25519KeyPairStaticHex[1].public, 'hex') homeCom2.apiVersion = '1_1' homeCom2.endPoint = 'http://localhost/api' homeCom2.createdAt = new Date() @@ -84,10 +132,7 @@ describe('CommunityResolver', () => { homeCom3 = DbFederatedCommunity.create() homeCom3.foreign = false - homeCom3.publicKey = Buffer.from( - '2ca593275aa4c11f9c3d43cd4d39586c70e2b7f4359739381940b62d1c8e8928', - 'hex', - ) + homeCom3.publicKey = Buffer.from(ed25519KeyPairStaticHex[2].public, 'hex') homeCom3.apiVersion = '2_0' homeCom3.endPoint = 'http://localhost/api' homeCom3.createdAt = new Date() @@ -101,9 +146,7 @@ describe('CommunityResolver', () => { { id: 3, foreign: homeCom3.foreign, - publicKey: expect.stringMatching( - '2ca593275aa4c11f9c3d43cd4d39586c70e2b7f4359739381940b62d1c8e8928', - ), + publicKey: expect.stringMatching(ed25519KeyPairStaticHex[2].public), url: expect.stringMatching('http://localhost/api/2_0'), lastAnnouncedAt: null, verifiedAt: null, @@ -114,9 +157,7 @@ describe('CommunityResolver', () => { { id: 2, foreign: homeCom2.foreign, - publicKey: expect.stringMatching( - '5b47388f9e8db5416201e485398ed0d72ab20d9ee951ccc1754245278e3ae6c6', - ), + publicKey: expect.stringMatching(ed25519KeyPairStaticHex[1].public), url: expect.stringMatching('http://localhost/api/1_1'), lastAnnouncedAt: null, verifiedAt: null, @@ -127,9 +168,7 @@ describe('CommunityResolver', () => { { id: 1, foreign: homeCom1.foreign, - publicKey: expect.stringMatching( - '75bb92ee197a5f5b645669b26b933558870d72791860e4854a41d6bb28e7d61c', - ), + publicKey: expect.stringMatching(ed25519KeyPairStaticHex[0].public), url: expect.stringMatching('http://localhost/api/1_0'), lastAnnouncedAt: null, verifiedAt: null, @@ -149,10 +188,7 @@ describe('CommunityResolver', () => { foreignCom1 = DbFederatedCommunity.create() foreignCom1.foreign = true - foreignCom1.publicKey = Buffer.from( - '08520bf2990274f829d2a2d45c802e4e854a768ed1c757ea99571a24bbfd87b2', - 'hex', - ) + foreignCom1.publicKey = Buffer.from(ed25519KeyPairStaticHex[3].public, 'hex') foreignCom1.apiVersion = '1_0' foreignCom1.endPoint = 'http://remotehost/api' foreignCom1.createdAt = new Date() @@ -160,10 +196,7 @@ describe('CommunityResolver', () => { foreignCom2 = DbFederatedCommunity.create() foreignCom2.foreign = true - foreignCom2.publicKey = Buffer.from( - '43c72cb81416121f5eb98affa4fb3360088719e80db6aaa13ff7e74d3f669307', - 'hex', - ) + foreignCom2.publicKey = Buffer.from(ed25519KeyPairStaticHex[4].public, 'hex') foreignCom2.apiVersion = '1_1' foreignCom2.endPoint = 'http://remotehost/api' foreignCom2.createdAt = new Date() @@ -171,10 +204,7 @@ describe('CommunityResolver', () => { foreignCom3 = DbFederatedCommunity.create() foreignCom3.foreign = true - foreignCom3.publicKey = Buffer.from( - '4e3bf9536f694124c527b0aaf45aa6aea6c8c5d570d96b54f56f583724212b73', - 'hex', - ) + foreignCom3.publicKey = Buffer.from(ed25519KeyPairStaticHex[5].public, 'hex') foreignCom3.apiVersion = '1_2' foreignCom3.endPoint = 'http://remotehost/api' foreignCom3.createdAt = new Date() @@ -188,7 +218,7 @@ describe('CommunityResolver', () => { { id: 3, foreign: homeCom3.foreign, - publicKey: expect.stringMatching(homeCom3.publicKey.toString('hex')), + publicKey: expect.stringMatching(ed25519KeyPairStaticHex[2].public), url: expect.stringMatching('http://localhost/api/2_0'), lastAnnouncedAt: null, verifiedAt: null, @@ -199,7 +229,7 @@ describe('CommunityResolver', () => { { id: 2, foreign: homeCom2.foreign, - publicKey: expect.stringMatching(homeCom2.publicKey.toString('hex')), + publicKey: expect.stringMatching(ed25519KeyPairStaticHex[1].public), url: expect.stringMatching('http://localhost/api/1_1'), lastAnnouncedAt: null, verifiedAt: null, @@ -210,7 +240,7 @@ describe('CommunityResolver', () => { { id: 1, foreign: homeCom1.foreign, - publicKey: expect.stringMatching(homeCom1.publicKey.toString('hex')), + publicKey: expect.stringMatching(ed25519KeyPairStaticHex[0].public), url: expect.stringMatching('http://localhost/api/1_0'), lastAnnouncedAt: null, verifiedAt: null, @@ -221,9 +251,7 @@ describe('CommunityResolver', () => { { id: 6, foreign: foreignCom3.foreign, - publicKey: expect.stringMatching( - '4e3bf9536f694124c527b0aaf45aa6aea6c8c5d570d96b54f56f583724212b73', - ), + publicKey: expect.stringMatching(ed25519KeyPairStaticHex[5].public), url: expect.stringMatching('http://remotehost/api/1_2'), lastAnnouncedAt: null, verifiedAt: null, @@ -234,9 +262,7 @@ describe('CommunityResolver', () => { { id: 5, foreign: foreignCom2.foreign, - publicKey: expect.stringMatching( - '43c72cb81416121f5eb98affa4fb3360088719e80db6aaa13ff7e74d3f669307', - ), + publicKey: expect.stringMatching(ed25519KeyPairStaticHex[4].public), url: expect.stringMatching('http://remotehost/api/1_1'), lastAnnouncedAt: null, verifiedAt: null, @@ -247,9 +273,7 @@ describe('CommunityResolver', () => { { id: 4, foreign: foreignCom1.foreign, - publicKey: expect.stringMatching( - '08520bf2990274f829d2a2d45c802e4e854a768ed1c757ea99571a24bbfd87b2', - ), + publicKey: expect.stringMatching(ed25519KeyPairStaticHex[3].public), url: expect.stringMatching('http://remotehost/api/1_0'), lastAnnouncedAt: null, verifiedAt: null, @@ -294,14 +318,8 @@ describe('CommunityResolver', () => { homeCom1 = DbCommunity.create() homeCom1.foreign = false homeCom1.url = 'http://localhost/api' - homeCom1.publicKey = Buffer.from( - '75bb92ee197a5f5b645669b26b933558870d72791860e4854a41d6bb28e7d61c', - 'hex', - ) - homeCom1.privateKey = Buffer.from( - 'ddfa39122c9b1951da10a773fc0d3d020e770d89afb489691e247e08c2b7b8aa990b7dda99c5ec5df88bd9a94bc34e2e68a91d05a224ef88fa916e5a1fbb47cb', - 'hex', - ) + homeCom1.publicKey = Buffer.from(ed25519KeyPairStaticHex[0].public, 'hex') + homeCom1.privateKey = Buffer.from(ed25519KeyPairStaticHex[0].private, 'hex') homeCom1.communityUuid = 'HomeCom-UUID' homeCom1.authenticatedAt = new Date() homeCom1.name = 'HomeCommunity-name' @@ -338,14 +356,8 @@ describe('CommunityResolver', () => { homeCom1 = DbCommunity.create() homeCom1.foreign = false homeCom1.url = 'http://localhost/api' - homeCom1.publicKey = Buffer.from( - '75bb92ee197a5f5b645669b26b933558870d72791860e4854a41d6bb28e7d61c', - 'hex', - ) - homeCom1.privateKey = Buffer.from( - 'ddfa39122c9b1951da10a773fc0d3d020e770d89afb489691e247e08c2b7b8aa990b7dda99c5ec5df88bd9a94bc34e2e68a91d05a224ef88fa916e5a1fbb47cb', - 'hex', - ) + homeCom1.publicKey = Buffer.from(ed25519KeyPairStaticHex[0].public, 'hex') + homeCom1.privateKey = Buffer.from(ed25519KeyPairStaticHex[0].private, 'hex') homeCom1.communityUuid = 'HomeCom-UUID' homeCom1.authenticatedAt = new Date() homeCom1.name = 'HomeCommunity-name' @@ -356,14 +368,8 @@ describe('CommunityResolver', () => { foreignCom1 = DbCommunity.create() foreignCom1.foreign = true foreignCom1.url = 'http://stage-2.gradido.net/api' - foreignCom1.publicKey = Buffer.from( - '08520bf2990274f829d2a2d45c802e4e854a768ed1c757ea99571a24bbfd87b2', - 'hex', - ) - foreignCom1.privateKey = Buffer.from( - 'd967220052995169b20b89a0c6190ee8aa9ca501d7a6df81c49a97003edca2ed724d69eaf55e62290d699d7c3ec8b44985fffd57def98d51b2202f2bd82330b3', - 'hex', - ) + foreignCom1.publicKey = Buffer.from(ed25519KeyPairStaticHex[3].public, 'hex') + foreignCom1.privateKey = Buffer.from(ed25519KeyPairStaticHex[3].private, 'hex') // foreignCom1.communityUuid = 'Stage2-Com-UUID' // foreignCom1.authenticatedAt = new Date() foreignCom1.name = 'Stage-2_Community-name' @@ -374,14 +380,8 @@ describe('CommunityResolver', () => { foreignCom2 = DbCommunity.create() foreignCom2.foreign = true foreignCom2.url = 'http://stage-3.gradido.net/api' - foreignCom2.publicKey = Buffer.from( - '43c72cb81416121f5eb98affa4fb3360088719e80db6aaa13ff7e74d3f669307', - 'hex', - ) - foreignCom2.privateKey = Buffer.from( - '0ae8921a204bd27e1ba834ffa2f4480cca867b4def783934f3032e19c54d6e7c9fb3233eff07a0086f6bd8486e7220136ce941abdd51d268bfaca0cc3181f162', - 'hex', - ) + foreignCom2.publicKey = Buffer.from(ed25519KeyPairStaticHex[4].public, 'hex') + foreignCom2.privateKey = Buffer.from(ed25519KeyPairStaticHex[4].private, 'hex') foreignCom2.communityUuid = 'Stage3-Com-UUID' foreignCom2.authenticatedAt = new Date() foreignCom2.name = 'Stage-3_Community-name' From 0dd70db539b5bb800aff93f48cded0c90bb7d7be Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Wed, 24 Jan 2024 18:15:33 +0100 Subject: [PATCH 17/18] fix not working fail2ban, add jails for nginx --- deployment/bare_metal/nginx/common/limit_requests.conf | 3 ++- deployment/hetzner_cloud/cloudConfig.yaml | 1 + deployment/hetzner_cloud/install.sh | 8 ++++++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/deployment/bare_metal/nginx/common/limit_requests.conf b/deployment/bare_metal/nginx/common/limit_requests.conf index e9026ee81..c9501fd64 100644 --- a/deployment/bare_metal/nginx/common/limit_requests.conf +++ b/deployment/bare_metal/nginx/common/limit_requests.conf @@ -1,3 +1,4 @@ limit_req_zone $binary_remote_addr zone=frontend:20m rate=5r/s; limit_req_zone $binary_remote_addr zone=backend:25m rate=15r/s; -limit_req_zone $binary_remote_addr zone=api:5m rate=30r/s; \ No newline at end of file +limit_req_zone $binary_remote_addr zone=api:5m rate=30r/s; +limit_conn_zone $binary_remote_addr zone=addr:10m; \ No newline at end of file diff --git a/deployment/hetzner_cloud/cloudConfig.yaml b/deployment/hetzner_cloud/cloudConfig.yaml index 86e7d5724..84658705f 100644 --- a/deployment/hetzner_cloud/cloudConfig.yaml +++ b/deployment/hetzner_cloud/cloudConfig.yaml @@ -9,6 +9,7 @@ users: packages: - fail2ban + - python3-systemd - ufw - git - mariadb-server diff --git a/deployment/hetzner_cloud/install.sh b/deployment/hetzner_cloud/install.sh index ee539370c..e9ed69e76 100755 --- a/deployment/hetzner_cloud/install.sh +++ b/deployment/hetzner_cloud/install.sh @@ -80,6 +80,14 @@ expect eof ") echo "$SECURE_MYSQL" +# Configure fail2ban, seems to not run out of the box on Debian 12 +echo -e "[sshd]\nbackend = systemd" | tee /etc/fail2ban/jail.d/sshd.conf +# enable nginx-limit-req filter to block also user which exceed nginx request limiter +echo -e "[nginx-limit-req]\nenabled = true\nlogpath = $SCRIPT_PATH/log/nginx-error.*.log" | tee /etc/fail2ban/jail.d/nginx-limit-req.conf +# enable nginx bad request filter +echo -e "[nginx-bad-request]\nenabled = true\nlogpath = $SCRIPT_PATH/log/nginx-error.*.log" | tee /etc/fail2ban/jail.d/nginx-bad-request.conf +systemctl restart fail2ban + # Configure nginx rm /etc/nginx/sites-enabled/default envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $SCRIPT_PATH/nginx/sites-available/gradido.conf.template > $SCRIPT_PATH/nginx/sites-available/gradido.conf From 491c09f835c8cd700b97c9556adfba060128c6c5 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Wed, 24 Jan 2024 18:28:28 +0100 Subject: [PATCH 18/18] move definition of zones --- .../bare_metal/nginx/sites-available/gradido.conf.ssl.template | 3 ++- .../bare_metal/nginx/sites-available/gradido.conf.template | 3 ++- .../nginx/sites-available/update-page.conf.ssl.template | 2 +- .../bare_metal/nginx/sites-available/update-page.conf.template | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/deployment/bare_metal/nginx/sites-available/gradido.conf.ssl.template b/deployment/bare_metal/nginx/sites-available/gradido.conf.ssl.template index 822c326d0..d8ed50ba4 100644 --- a/deployment/bare_metal/nginx/sites-available/gradido.conf.ssl.template +++ b/deployment/bare_metal/nginx/sites-available/gradido.conf.ssl.template @@ -1,3 +1,5 @@ +include /etc/nginx/common/limit_requests.conf; + server { if ($host = $COMMUNITY_HOST) { return 301 https://$host$request_uri; @@ -21,7 +23,6 @@ server { include /etc/nginx/common/protect.conf; include /etc/nginx/common/protect_add_header.conf; - include /etc/nginx/common/limit_requests.conf; # protect from slow loris client_body_timeout 10s; diff --git a/deployment/bare_metal/nginx/sites-available/gradido.conf.template b/deployment/bare_metal/nginx/sites-available/gradido.conf.template index 1f673ee41..e0f382467 100644 --- a/deployment/bare_metal/nginx/sites-available/gradido.conf.template +++ b/deployment/bare_metal/nginx/sites-available/gradido.conf.template @@ -1,3 +1,5 @@ +include /etc/nginx/common/limit_requests.conf; + server { server_name $COMMUNITY_HOST; @@ -6,7 +8,6 @@ server { include /etc/nginx/common/protect.conf; include /etc/nginx/common/protect_add_header.conf; - include /etc/nginx/common/limit_requests.conf; # protect from slow loris client_body_timeout 10s; diff --git a/deployment/bare_metal/nginx/sites-available/update-page.conf.ssl.template b/deployment/bare_metal/nginx/sites-available/update-page.conf.ssl.template index ee7732230..fd41c333d 100644 --- a/deployment/bare_metal/nginx/sites-available/update-page.conf.ssl.template +++ b/deployment/bare_metal/nginx/sites-available/update-page.conf.ssl.template @@ -1,3 +1,4 @@ +include /etc/nginx/common/limit_requests.conf; server { if ($host = $COMMUNITY_HOST) { @@ -21,7 +22,6 @@ server { include /etc/nginx/common/protect.conf; include /etc/nginx/common/protect_add_header.conf; - include /etc/nginx/common/limit_requests.conf; # protect from slow loris client_body_timeout 10s; diff --git a/deployment/bare_metal/nginx/sites-available/update-page.conf.template b/deployment/bare_metal/nginx/sites-available/update-page.conf.template index 38dfb2d02..be91abc88 100644 --- a/deployment/bare_metal/nginx/sites-available/update-page.conf.template +++ b/deployment/bare_metal/nginx/sites-available/update-page.conf.template @@ -1,3 +1,4 @@ +include /etc/nginx/common/limit_requests.conf; server { server_name $COMMUNITY_HOST; @@ -6,7 +7,6 @@ server { include /etc/nginx/common/protect.conf; include /etc/nginx/common/protect_add_header.conf; - include /etc/nginx/common/limit_requests.conf; # protect from slow loris client_body_timeout 10s;