From 98a4d55516d1bfac2d72f0ba23a7872ba8be9912 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Thu, 27 Apr 2023 03:25:13 +0200 Subject: [PATCH 01/17] add graphql-client and -endpoint for community-publicInfo --- .../client/1_0/FederationClientImpl.ts | 83 +++++++++++++++++++ .../client/1_1/FederationClientImpl.ts | 83 +++++++++++++++++++ .../src/federation/client/FederationClient.ts | 13 +++ backend/src/federation/validateCommunities.ts | 55 +++++++++--- .../api/1_0/model/GetPublicInfoResult.ts | 26 ++++++ .../api/1_0/resolver/PublicInfoResolver.ts | 18 ++++ 6 files changed, 267 insertions(+), 11 deletions(-) create mode 100644 backend/src/federation/client/1_0/FederationClientImpl.ts create mode 100644 backend/src/federation/client/1_1/FederationClientImpl.ts create mode 100644 backend/src/federation/client/FederationClient.ts create mode 100644 federation/src/graphql/api/1_0/model/GetPublicInfoResult.ts create mode 100644 federation/src/graphql/api/1_0/resolver/PublicInfoResolver.ts diff --git a/backend/src/federation/client/1_0/FederationClientImpl.ts b/backend/src/federation/client/1_0/FederationClientImpl.ts new file mode 100644 index 000000000..deb2c959f --- /dev/null +++ b/backend/src/federation/client/1_0/FederationClientImpl.ts @@ -0,0 +1,83 @@ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +/* eslint-disable @typescript-eslint/no-unsafe-return */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity' +import { gql } from 'graphql-request' + +import { GraphQLGetClient } from '@/federation/client/GraphQLGetClient' +import { LogError } from '@/server/LogError' +import { backendLogger as logger } from '@/server/logger' + +// eslint-disable-next-line import/no-relative-parent-imports +import { FederationClient, PublicInfo } from '../FederationClient' + +export class FederationClientImpl implements FederationClient { + public async requestGetPublicKey(dbCom: DbFederatedCommunity): Promise { + let endpoint = dbCom.endPoint.endsWith('/') ? dbCom.endPoint : dbCom.endPoint + '/' + endpoint = `${endpoint}${dbCom.apiVersion}/` + logger.info(`requestGetPublicKey with endpoint='${endpoint}'...`) + + const graphQLClient = GraphQLGetClient.getInstance(endpoint) + logger.debug(`graphQLClient=${JSON.stringify(graphQLClient)}`) + const query = gql` + query { + getPublicKey { + publicKey + } + } + ` + const variables = {} + + try { + const { data, errors, extensions, headers, status } = await graphQLClient.rawRequest( + query, + variables, + ) + logger.debug(`Response-Data:`, data, errors, extensions, headers, status) + if (data) { + logger.debug(`Response-PublicKey:`, data.getPublicKey.publicKey) + logger.info(`requestGetPublicKey processed successfully`) + return data.getPublicKey.publicKey + } + logger.warn(`requestGetPublicKey processed without response data`) + } catch (err) { + throw new LogError(`Request-Error:`, err) + } + } + + public async requestGetPublicInfo(dbCom: DbFederatedCommunity): Promise { + let endpoint = dbCom.endPoint.endsWith('/') ? dbCom.endPoint : dbCom.endPoint + '/' + endpoint = `${endpoint}${dbCom.apiVersion}/` + logger.info(`requestGetPublicInfo with endpoint='${endpoint}'...`) + + const graphQLClient = GraphQLGetClient.getInstance(endpoint) + logger.debug(`graphQLClient=${JSON.stringify(graphQLClient)}`) + const query = gql` + query { + getPublicInfo { + name + description + createdAt + publicKey + } + } + ` + const variables = {} + + try { + const { data, errors, extensions, headers, status } = await graphQLClient.rawRequest( + query, + variables, + ) + logger.debug(`Response-Data:`, data, errors, extensions, headers, status) + if (data) { + logger.debug(`Response-PublicInfo:`, data.getPublicInfo.publicInfo) + logger.info(`requestGetPublicInfo processed successfully`) + return data.getPublicInfo.publicInfo + } + logger.warn(`requestGetPublicInfo processed without response data`) + } catch (err) { + throw new LogError(`Request-Error:`, err) + } + } +} diff --git a/backend/src/federation/client/1_1/FederationClientImpl.ts b/backend/src/federation/client/1_1/FederationClientImpl.ts new file mode 100644 index 000000000..472edcdbd --- /dev/null +++ b/backend/src/federation/client/1_1/FederationClientImpl.ts @@ -0,0 +1,83 @@ +/* eslint-disable @typescript-eslint/no-unsafe-return */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity' +import { gql } from 'graphql-request' + +import { GraphQLGetClient } from '@/federation/client/GraphQLGetClient' +import { LogError } from '@/server/LogError' +import { backendLogger as logger } from '@/server/logger' + +// eslint-disable-next-line import/no-relative-parent-imports +import { FederationClient, PublicInfo } from '../FederationClient' + +export class FederationClientImpl implements FederationClient { + async requestGetPublicKey(dbCom: DbFederatedCommunity): Promise { + let endpoint = dbCom.endPoint.endsWith('/') ? dbCom.endPoint : dbCom.endPoint + '/' + endpoint = `${endpoint}${dbCom.apiVersion}/` + logger.info(`requestGetPublicKey with endpoint='${endpoint}'...`) + + const graphQLClient = GraphQLGetClient.getInstance(endpoint) + logger.debug(`graphQLClient=${JSON.stringify(graphQLClient)}`) + const query = gql` + query { + getPublicKey { + publicKey + } + } + ` + const variables = {} + + try { + const { data, errors, extensions, headers, status } = await graphQLClient.rawRequest( + query, + variables, + ) + logger.debug(`Response-Data:`, data, errors, extensions, headers, status) + if (data) { + logger.debug(`Response-PublicKey:`, data.getPublicKey.publicKey) + logger.info(`requestGetPublicKey processed successfully`) + return data.getPublicKey.publicKey + } + logger.warn(`requestGetPublicKey processed without response data`) + } catch (err) { + throw new LogError(`Request-Error:`, err) + } + } + + async requestGetPublicInfo(dbCom: DbFederatedCommunity): Promise { + let endpoint = dbCom.endPoint.endsWith('/') ? dbCom.endPoint : dbCom.endPoint + '/' + endpoint = `${endpoint}${dbCom.apiVersion}/` + logger.info(`requestGetPublicInfo with endpoint='${endpoint}'...`) + + const graphQLClient = GraphQLGetClient.getInstance(endpoint) + logger.debug(`graphQLClient=${JSON.stringify(graphQLClient)}`) + const query = gql` + query { + getPublicInfo { + name + description + createdAt + publicKey + } + } + ` + const variables = {} + + try { + const { data, errors, extensions, headers, status } = await graphQLClient.rawRequest( + query, + variables, + ) + logger.debug(`Response-Data:`, data, errors, extensions, headers, status) + if (data) { + logger.debug(`Response-PublicInfo:`, data.getPublicInfo.publicInfo) + logger.info(`requestGetPublicInfo processed successfully`) + return data.getPublicInfo.publicInfo + } + logger.warn(`requestGetPublicInfo processed without response data`) + } catch (err) { + throw new LogError(`Request-Error:`, err) + } + } +} diff --git a/backend/src/federation/client/FederationClient.ts b/backend/src/federation/client/FederationClient.ts new file mode 100644 index 000000000..3ddd80cfb --- /dev/null +++ b/backend/src/federation/client/FederationClient.ts @@ -0,0 +1,13 @@ +import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity' + +export type PublicInfo = { + name: string + description: string + createdAt: Date + publicKey: string +} + +export interface FederationClient { + requestGetPublicKey(dbCom: DbFederatedCommunity): Promise + requestGetPublicInfo(dbCom: DbFederatedCommunity): Promise +} diff --git a/backend/src/federation/validateCommunities.ts b/backend/src/federation/validateCommunities.ts index b38f38ee9..da8484318 100644 --- a/backend/src/federation/validateCommunities.ts +++ b/backend/src/federation/validateCommunities.ts @@ -1,15 +1,17 @@ -/** eslint-disable @typescript-eslint/no-unsafe-call */ /** eslint-disable @typescript-eslint/no-unsafe-assignment */ +/** eslint-disable @typescript-eslint/no-unsafe-call */ import { IsNull } from '@dbTools/typeorm' +import { Community as DbCommunity } from '@entity/Community' import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity' import { LogError } from '@/server/LogError' import { backendLogger as logger } from '@/server/logger' // eslint-disable-next-line camelcase -import { requestGetPublicKey as v1_0_requestGetPublicKey } from './client/1_0/FederationClient' +import { FederationClientImpl as V1_0_FederationClientImpl } from './client/1_0/FederationClientImpl' // eslint-disable-next-line camelcase -import { requestGetPublicKey as v1_1_requestGetPublicKey } from './client/1_1/FederationClient' +import { FederationClientImpl as V1_1_FederationClientImpl } from './client/1_1/FederationClientImpl' +import { FederationClient, PublicInfo } from './client/FederationClient' import { ApiVersionType } from './enum/apiVersionType' export function startValidateCommunities(timerInterval: number): void { @@ -41,7 +43,10 @@ export async function validateCommunities(): Promise { `Federation: validate publicKey for dbCom: ${dbCom.id} with apiVersion=${dbCom.apiVersion}`, ) try { - const pubKey = await invokeVersionedRequestGetPublicKey(dbCom) + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + const pubKey = await getVersionedFederationClient(dbCom.apiVersion).requestGetPublicKey( + dbCom, + ) logger.info( 'Federation: received publicKey from endpoint', pubKey, @@ -51,6 +56,17 @@ export async function validateCommunities(): Promise { logger.info(`Federation: matching publicKey: ${pubKey}`) await DbFederatedCommunity.update({ id: dbCom.id }, { verifiedAt: new Date() }) logger.debug(`Federation: updated dbCom: ${JSON.stringify(dbCom)}`) + + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const pubInfo = await getVersionedFederationClient(dbCom.apiVersion).requestGetPublicInfo( + dbCom, + ) + logger.debug(`Federation: getPublicInfo pubInfo: ${JSON.stringify(pubInfo)}`) + if (pubInfo) { + logger.info(`Federation: write foreign community...`) + await writeForeignCommunity(dbCom, pubInfo) + logger.info(`Federation: write foreign community... successfully`) + } } else { logger.warn( `Federation: received not matching publicKey -> received: ${ @@ -73,19 +89,36 @@ export async function validateCommunities(): Promise { } } +async function writeForeignCommunity( + dbCom: DbFederatedCommunity, + pubInfo: PublicInfo, +): Promise { + if (dbCom && pubInfo) { + const foreignCom = DbCommunity.create() + foreignCom.foreign = true + foreignCom.publicKey = dbCom.publicKey + foreignCom.url = dbCom.endPoint + foreignCom.name = pubInfo.name + foreignCom.description = pubInfo.description + foreignCom.creationDate = pubInfo.createdAt + await DbCommunity.save(foreignCom) + } +} + function isLogError(err: unknown) { return err instanceof LogError } -async function invokeVersionedRequestGetPublicKey( - dbCom: DbFederatedCommunity, -): Promise { - switch (dbCom.apiVersion) { +function getVersionedFederationClient(apiVersion: string): FederationClient { + switch (apiVersion) { case ApiVersionType.V1_0: - return v1_0_requestGetPublicKey(dbCom) + // eslint-disable-next-line camelcase + return new V1_0_FederationClientImpl() case ApiVersionType.V1_1: - return v1_1_requestGetPublicKey(dbCom) + // eslint-disable-next-line camelcase + return new V1_1_FederationClientImpl() default: - return undefined + // eslint-disable-next-line camelcase + return new V1_0_FederationClientImpl() } } diff --git a/federation/src/graphql/api/1_0/model/GetPublicInfoResult.ts b/federation/src/graphql/api/1_0/model/GetPublicInfoResult.ts new file mode 100644 index 000000000..102f446ba --- /dev/null +++ b/federation/src/graphql/api/1_0/model/GetPublicInfoResult.ts @@ -0,0 +1,26 @@ +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import { Community as DbCommunity } from '@entity/Community' +import { Field, ObjectType } from 'type-graphql' + +@ObjectType() +// eslint-disable-next-line @typescript-eslint/no-unused-vars +export class GetPublicInfoResult { + constructor(dbCom: DbCommunity) { + this.publicKey = dbCom.publicKey.toString('hex') + this.name = dbCom.name + this.description = dbCom.description + this.createdAt = dbCom.creationDate + } + + @Field(() => String) + name: string | null + + @Field(() => String) + description: string | null + + @Field(() => Date) + createdAt: Date | null + + @Field(() => String) + publicKey: string +} diff --git a/federation/src/graphql/api/1_0/resolver/PublicInfoResolver.ts b/federation/src/graphql/api/1_0/resolver/PublicInfoResolver.ts new file mode 100644 index 000000000..ad988670b --- /dev/null +++ b/federation/src/graphql/api/1_0/resolver/PublicInfoResolver.ts @@ -0,0 +1,18 @@ +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import { Query, Resolver } from 'type-graphql' +import { federationLogger as logger } from '@/server/logger' +import { Community as DbCommunity } from '@entity/Community' +import { GetPublicInfoResult } from '../model/GetPublicInfoResult' + +@Resolver() +// eslint-disable-next-line @typescript-eslint/no-unused-vars +export class PublicInfoResolver { + @Query(() => GetPublicInfoResult) + async getPublicInfo(): Promise { + logger.debug(`getPublicInfo() via apiVersion=1_0 ...`) + const homeCom = await DbCommunity.findOneOrFail({ foreign: false }) + const result = new GetPublicInfoResult(homeCom) + logger.info(`getPublicInfo()-1_0... return publicInfo=${result}`) + return result + } +} From a824ff0876eac665b5a3f4def51ec0425556e01d Mon Sep 17 00:00:00 2001 From: hrsof Date: Tue, 2 May 2023 15:25:21 +0200 Subject: [PATCH 02/17] rework graphql client and endpoint for community public info --- .../federation/client/1_0/FederationClient.ts | 44 ------------------- .../client/1_0/FederationClientImpl.ts | 14 +++--- .../federation/client/1_1/FederationClient.ts | 44 ------------------- .../client/1_1/FederationClientImpl.ts | 17 ++++--- .../src/federation/client/FederationClient.ts | 6 ++- backend/src/federation/validateCommunities.ts | 10 ++--- ...ult.ts => GetPublicCommunityInfoResult.ts} | 2 +- .../resolver/PublicCommunityInfoResolver.ts | 18 ++++++++ .../api/1_0/resolver/PublicInfoResolver.ts | 18 -------- 9 files changed, 47 insertions(+), 126 deletions(-) delete mode 100644 backend/src/federation/client/1_0/FederationClient.ts delete mode 100644 backend/src/federation/client/1_1/FederationClient.ts rename federation/src/graphql/api/1_0/model/{GetPublicInfoResult.ts => GetPublicCommunityInfoResult.ts} (93%) create mode 100644 federation/src/graphql/api/1_0/resolver/PublicCommunityInfoResolver.ts delete mode 100644 federation/src/graphql/api/1_0/resolver/PublicInfoResolver.ts diff --git a/backend/src/federation/client/1_0/FederationClient.ts b/backend/src/federation/client/1_0/FederationClient.ts deleted file mode 100644 index 743d17348..000000000 --- a/backend/src/federation/client/1_0/FederationClient.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-unsafe-return */ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ -import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity' -import { gql } from 'graphql-request' - -import { GraphQLGetClient } from '@/federation/client/GraphQLGetClient' -import { LogError } from '@/server/LogError' -import { backendLogger as logger } from '@/server/logger' - -export async function requestGetPublicKey( - dbCom: DbFederatedCommunity, -): Promise { - let endpoint = dbCom.endPoint.endsWith('/') ? dbCom.endPoint : dbCom.endPoint + '/' - endpoint = `${endpoint}${dbCom.apiVersion}/` - logger.info(`requestGetPublicKey with endpoint='${endpoint}'...`) - - const graphQLClient = GraphQLGetClient.getInstance(endpoint) - logger.debug(`graphQLClient=${JSON.stringify(graphQLClient)}`) - const query = gql` - query { - getPublicKey { - publicKey - } - } - ` - const variables = {} - - try { - const { data, errors, extensions, headers, status } = await graphQLClient.rawRequest( - query, - variables, - ) - logger.debug(`Response-Data:`, data, errors, extensions, headers, status) - if (data) { - logger.debug(`Response-PublicKey:`, data.getPublicKey.publicKey) - logger.info(`requestGetPublicKey processed successfully`) - return data.getPublicKey.publicKey - } - logger.warn(`requestGetPublicKey processed without response data`) - } catch (err) { - throw new LogError(`Request-Error:`, err) - } -} diff --git a/backend/src/federation/client/1_0/FederationClientImpl.ts b/backend/src/federation/client/1_0/FederationClientImpl.ts index deb2c959f..4bd194594 100644 --- a/backend/src/federation/client/1_0/FederationClientImpl.ts +++ b/backend/src/federation/client/1_0/FederationClientImpl.ts @@ -9,7 +9,7 @@ import { LogError } from '@/server/LogError' import { backendLogger as logger } from '@/server/logger' // eslint-disable-next-line import/no-relative-parent-imports -import { FederationClient, PublicInfo } from '../FederationClient' +import { FederationClient, PublicCommunityInfo } from '../FederationClient' export class FederationClientImpl implements FederationClient { public async requestGetPublicKey(dbCom: DbFederatedCommunity): Promise { @@ -45,16 +45,18 @@ export class FederationClientImpl implements FederationClient { } } - public async requestGetPublicInfo(dbCom: DbFederatedCommunity): Promise { + public async requestGetPublicCommunityInfo( + dbCom: DbFederatedCommunity, + ): Promise { let endpoint = dbCom.endPoint.endsWith('/') ? dbCom.endPoint : dbCom.endPoint + '/' endpoint = `${endpoint}${dbCom.apiVersion}/` - logger.info(`requestGetPublicInfo with endpoint='${endpoint}'...`) + logger.info(`requestGetPublicCommunityInfo with endpoint='${endpoint}'...`) const graphQLClient = GraphQLGetClient.getInstance(endpoint) logger.debug(`graphQLClient=${JSON.stringify(graphQLClient)}`) const query = gql` query { - getPublicInfo { + getPublicCommunityInfo { name description createdAt @@ -71,8 +73,8 @@ export class FederationClientImpl implements FederationClient { ) logger.debug(`Response-Data:`, data, errors, extensions, headers, status) if (data) { - logger.debug(`Response-PublicInfo:`, data.getPublicInfo.publicInfo) - logger.info(`requestGetPublicInfo processed successfully`) + logger.debug(`Response-PublicCommunityInfo:`, data.getPublicInfo.publicInfo) + logger.info(`requestGetPublicCommunityInfo processed successfully`) return data.getPublicInfo.publicInfo } logger.warn(`requestGetPublicInfo processed without response data`) diff --git a/backend/src/federation/client/1_1/FederationClient.ts b/backend/src/federation/client/1_1/FederationClient.ts deleted file mode 100644 index 35c88bf3b..000000000 --- a/backend/src/federation/client/1_1/FederationClient.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unsafe-return */ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity' -import { gql } from 'graphql-request' - -import { GraphQLGetClient } from '@/federation/client/GraphQLGetClient' -import { LogError } from '@/server/LogError' -import { backendLogger as logger } from '@/server/logger' - -export async function requestGetPublicKey( - dbCom: DbFederatedCommunity, -): Promise { - let endpoint = dbCom.endPoint.endsWith('/') ? dbCom.endPoint : dbCom.endPoint + '/' - endpoint = `${endpoint}${dbCom.apiVersion}/` - logger.info(`requestGetPublicKey with endpoint='${endpoint}'...`) - - const graphQLClient = GraphQLGetClient.getInstance(endpoint) - logger.debug(`graphQLClient=${JSON.stringify(graphQLClient)}`) - const query = gql` - query { - getPublicKey { - publicKey - } - } - ` - const variables = {} - - try { - const { data, errors, extensions, headers, status } = await graphQLClient.rawRequest( - query, - variables, - ) - logger.debug(`Response-Data:`, data, errors, extensions, headers, status) - if (data) { - logger.debug(`Response-PublicKey:`, data.getPublicKey.publicKey) - logger.info(`requestGetPublicKey processed successfully`) - return data.getPublicKey.publicKey - } - logger.warn(`requestGetPublicKey processed without response data`) - } catch (err) { - throw new LogError(`Request-Error:`, err) - } -} diff --git a/backend/src/federation/client/1_1/FederationClientImpl.ts b/backend/src/federation/client/1_1/FederationClientImpl.ts index 472edcdbd..14153723d 100644 --- a/backend/src/federation/client/1_1/FederationClientImpl.ts +++ b/backend/src/federation/client/1_1/FederationClientImpl.ts @@ -9,7 +9,7 @@ import { LogError } from '@/server/LogError' import { backendLogger as logger } from '@/server/logger' // eslint-disable-next-line import/no-relative-parent-imports -import { FederationClient, PublicInfo } from '../FederationClient' +import { FederationClient, PublicCommunityInfo } from '../FederationClient' export class FederationClientImpl implements FederationClient { async requestGetPublicKey(dbCom: DbFederatedCommunity): Promise { @@ -45,16 +45,18 @@ export class FederationClientImpl implements FederationClient { } } - async requestGetPublicInfo(dbCom: DbFederatedCommunity): Promise { + async requestGetPublicCommunityInfo( + dbCom: DbFederatedCommunity, + ): Promise { let endpoint = dbCom.endPoint.endsWith('/') ? dbCom.endPoint : dbCom.endPoint + '/' endpoint = `${endpoint}${dbCom.apiVersion}/` - logger.info(`requestGetPublicInfo with endpoint='${endpoint}'...`) + logger.info(`requestGetPublicCommunityInfo with endpoint='${endpoint}'...`) const graphQLClient = GraphQLGetClient.getInstance(endpoint) logger.debug(`graphQLClient=${JSON.stringify(graphQLClient)}`) const query = gql` query { - getPublicInfo { + getPublicCommunityInfo { name description createdAt @@ -71,9 +73,12 @@ export class FederationClientImpl implements FederationClient { ) logger.debug(`Response-Data:`, data, errors, extensions, headers, status) if (data) { - logger.debug(`Response-PublicInfo:`, data.getPublicInfo.publicInfo) + logger.debug( + `Response-PublicCommunityInfo:`, + data.getPublicCommunityInfo.publicCommunityInfo, + ) logger.info(`requestGetPublicInfo processed successfully`) - return data.getPublicInfo.publicInfo + return data.getPublicCommunityInfo.publicCommunityInfo } logger.warn(`requestGetPublicInfo processed without response data`) } catch (err) { diff --git a/backend/src/federation/client/FederationClient.ts b/backend/src/federation/client/FederationClient.ts index 3ddd80cfb..2af13e002 100644 --- a/backend/src/federation/client/FederationClient.ts +++ b/backend/src/federation/client/FederationClient.ts @@ -1,6 +1,6 @@ import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity' -export type PublicInfo = { +export type PublicCommunityInfo = { name: string description: string createdAt: Date @@ -9,5 +9,7 @@ export type PublicInfo = { export interface FederationClient { requestGetPublicKey(dbCom: DbFederatedCommunity): Promise - requestGetPublicInfo(dbCom: DbFederatedCommunity): Promise + requestGetPublicCommunityInfo( + dbCom: DbFederatedCommunity, + ): Promise } diff --git a/backend/src/federation/validateCommunities.ts b/backend/src/federation/validateCommunities.ts index da8484318..1338279fd 100644 --- a/backend/src/federation/validateCommunities.ts +++ b/backend/src/federation/validateCommunities.ts @@ -11,7 +11,7 @@ import { backendLogger as logger } from '@/server/logger' import { FederationClientImpl as V1_0_FederationClientImpl } from './client/1_0/FederationClientImpl' // eslint-disable-next-line camelcase import { FederationClientImpl as V1_1_FederationClientImpl } from './client/1_1/FederationClientImpl' -import { FederationClient, PublicInfo } from './client/FederationClient' +import { FederationClient, PublicCommunityInfo } from './client/FederationClient' import { ApiVersionType } from './enum/apiVersionType' export function startValidateCommunities(timerInterval: number): void { @@ -58,9 +58,9 @@ export async function validateCommunities(): Promise { logger.debug(`Federation: updated dbCom: ${JSON.stringify(dbCom)}`) // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const pubInfo = await getVersionedFederationClient(dbCom.apiVersion).requestGetPublicInfo( - dbCom, - ) + const pubInfo = await getVersionedFederationClient( + dbCom.apiVersion, + ).requestGetPublicCommunityInfo(dbCom) logger.debug(`Federation: getPublicInfo pubInfo: ${JSON.stringify(pubInfo)}`) if (pubInfo) { logger.info(`Federation: write foreign community...`) @@ -91,7 +91,7 @@ export async function validateCommunities(): Promise { async function writeForeignCommunity( dbCom: DbFederatedCommunity, - pubInfo: PublicInfo, + pubInfo: PublicCommunityInfo, ): Promise { if (dbCom && pubInfo) { const foreignCom = DbCommunity.create() diff --git a/federation/src/graphql/api/1_0/model/GetPublicInfoResult.ts b/federation/src/graphql/api/1_0/model/GetPublicCommunityInfoResult.ts similarity index 93% rename from federation/src/graphql/api/1_0/model/GetPublicInfoResult.ts rename to federation/src/graphql/api/1_0/model/GetPublicCommunityInfoResult.ts index 102f446ba..bb36cdcda 100644 --- a/federation/src/graphql/api/1_0/model/GetPublicInfoResult.ts +++ b/federation/src/graphql/api/1_0/model/GetPublicCommunityInfoResult.ts @@ -4,7 +4,7 @@ import { Field, ObjectType } from 'type-graphql' @ObjectType() // eslint-disable-next-line @typescript-eslint/no-unused-vars -export class GetPublicInfoResult { +export class GetPublicCommunityInfoResult { constructor(dbCom: DbCommunity) { this.publicKey = dbCom.publicKey.toString('hex') this.name = dbCom.name diff --git a/federation/src/graphql/api/1_0/resolver/PublicCommunityInfoResolver.ts b/federation/src/graphql/api/1_0/resolver/PublicCommunityInfoResolver.ts new file mode 100644 index 000000000..31287c494 --- /dev/null +++ b/federation/src/graphql/api/1_0/resolver/PublicCommunityInfoResolver.ts @@ -0,0 +1,18 @@ +// eslint-disable-next-line @typescript-eslint/no-unused-vars +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' + +@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.findOneOrFail({ foreign: false }) + const result = new GetPublicCommunityInfoResult(homeCom) + logger.info(`getPublicCommunityInfo()-1_0... return publicInfo=${result}`) + return result + } +} diff --git a/federation/src/graphql/api/1_0/resolver/PublicInfoResolver.ts b/federation/src/graphql/api/1_0/resolver/PublicInfoResolver.ts deleted file mode 100644 index ad988670b..000000000 --- a/federation/src/graphql/api/1_0/resolver/PublicInfoResolver.ts +++ /dev/null @@ -1,18 +0,0 @@ -// eslint-disable-next-line @typescript-eslint/no-unused-vars -import { Query, Resolver } from 'type-graphql' -import { federationLogger as logger } from '@/server/logger' -import { Community as DbCommunity } from '@entity/Community' -import { GetPublicInfoResult } from '../model/GetPublicInfoResult' - -@Resolver() -// eslint-disable-next-line @typescript-eslint/no-unused-vars -export class PublicInfoResolver { - @Query(() => GetPublicInfoResult) - async getPublicInfo(): Promise { - logger.debug(`getPublicInfo() via apiVersion=1_0 ...`) - const homeCom = await DbCommunity.findOneOrFail({ foreign: false }) - const result = new GetPublicInfoResult(homeCom) - logger.info(`getPublicInfo()-1_0... return publicInfo=${result}`) - return result - } -} From ac09e641027f6778560ac53e19b67374dca94fbc Mon Sep 17 00:00:00 2001 From: Claus-Peter Huebner Date: Thu, 4 May 2023 18:15:47 +0200 Subject: [PATCH 03/17] change getPublicInfo to getPublicCommunityInfo --- backend/src/federation/client/1_0/FederationClientImpl.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/federation/client/1_0/FederationClientImpl.ts b/backend/src/federation/client/1_0/FederationClientImpl.ts index 4bd194594..543653ea7 100644 --- a/backend/src/federation/client/1_0/FederationClientImpl.ts +++ b/backend/src/federation/client/1_0/FederationClientImpl.ts @@ -73,9 +73,9 @@ export class FederationClientImpl implements FederationClient { ) logger.debug(`Response-Data:`, data, errors, extensions, headers, status) if (data) { - logger.debug(`Response-PublicCommunityInfo:`, data.getPublicInfo.publicInfo) + logger.debug(`Response-PublicCommunityInfo:`, data.getPublicCommunityInfo) logger.info(`requestGetPublicCommunityInfo processed successfully`) - return data.getPublicInfo.publicInfo + return data.getPublicCommunityInfo } logger.warn(`requestGetPublicInfo processed without response data`) } catch (err) { From 85c78b3e36973893f1fa6d5dd278d2cf2aabcb96 Mon Sep 17 00:00:00 2001 From: Claus-Peter Huebner Date: Fri, 5 May 2023 18:11:35 +0200 Subject: [PATCH 04/17] correct writeForeignCommunity --- backend/src/federation/validateCommunities.ts | 35 ++++++++++--------- .../resolver/PublicCommunityInfoResolver.ts | 6 +++- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/backend/src/federation/validateCommunities.ts b/backend/src/federation/validateCommunities.ts index c50e4b827..eee0261f5 100644 --- a/backend/src/federation/validateCommunities.ts +++ b/backend/src/federation/validateCommunities.ts @@ -90,23 +90,24 @@ async function writeForeignCommunity( dbCom: DbFederatedCommunity, pubInfo: PublicCommunityInfo, ): Promise { - const variables = { - public_key: pubInfo.publicKey, - url: dbCom.endPoint, - name: pubInfo.name, - description: pubInfo.description, - creation_date: pubInfo.createdAt, - } - if (dbCom && pubInfo) { - await DbCommunity.createQueryBuilder() - .insert() - .into(DbCommunity) - .values(variables) - .orUpdate({ - conflict_target: ['id', 'public_key'], - overwrite: ['url', 'name', 'description', 'creation_date'], - }) - .execute() + if (!dbCom || !pubInfo || !(dbCom.publicKey.toString('hex') === pubInfo.publicKey)) { + logger.error( + `Error in writeForeignCommunity: missmatching parameters or publicKey. pubInfo:${JSON.stringify( + pubInfo, + )}`, + ) + } else { + let com = await DbCommunity.findOne({ publicKey: dbCom.publicKey }) + if (!com) { + com = DbCommunity.create() + } + com.creationDate = pubInfo.createdAt + com.description = pubInfo.description + com.foreign = true + com.name = pubInfo.name + com.publicKey = dbCom.publicKey + com.url = dbCom.endPoint + await DbCommunity.save(com) } } diff --git a/federation/src/graphql/api/1_0/resolver/PublicCommunityInfoResolver.ts b/federation/src/graphql/api/1_0/resolver/PublicCommunityInfoResolver.ts index 31287c494..3bd02e346 100644 --- a/federation/src/graphql/api/1_0/resolver/PublicCommunityInfoResolver.ts +++ b/federation/src/graphql/api/1_0/resolver/PublicCommunityInfoResolver.ts @@ -12,7 +12,11 @@ export class PublicCommunityInfoResolver { logger.debug(`getPublicCommunityInfo() via apiVersion=1_0 ...`) const homeCom = await DbCommunity.findOneOrFail({ foreign: false }) const result = new GetPublicCommunityInfoResult(homeCom) - logger.info(`getPublicCommunityInfo()-1_0... return publicInfo=${result}`) + logger.info( + `getPublicCommunityInfo()-1_0... return publicInfo=${JSON.stringify( + result + )}` + ) return result } } From 20c8b7573157b4cf367dd0c04b3862dbc75b0827 Mon Sep 17 00:00:00 2001 From: Claus-Peter Huebner Date: Fri, 5 May 2023 21:01:56 +0200 Subject: [PATCH 05/17] not working linting even on using suggestion --- .../src/graphql/api/1_0/model/GetPublicCommunityInfoResult.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/federation/src/graphql/api/1_0/model/GetPublicCommunityInfoResult.ts b/federation/src/graphql/api/1_0/model/GetPublicCommunityInfoResult.ts index bb36cdcda..ea225203a 100644 --- a/federation/src/graphql/api/1_0/model/GetPublicCommunityInfoResult.ts +++ b/federation/src/graphql/api/1_0/model/GetPublicCommunityInfoResult.ts @@ -1,5 +1,6 @@ // eslint-disable-next-line @typescript-eslint/no-unused-vars import { Community as DbCommunity } from '@entity/Community' +/* @typescript-eslint/no-unused-vars */ import { Field, ObjectType } from 'type-graphql' @ObjectType() From 54173857ce61860620b881328032548d0794fab1 Mon Sep 17 00:00:00 2001 From: Claus-Peter Huebner Date: Tue, 16 May 2023 01:14:00 +0200 Subject: [PATCH 06/17] adapt client refactorings, v1_1 not matching --- .../client/1_0/FederationClientImpl.ts | 91 ------------------ .../client/1_1/FederationClientImpl.ts | 94 ------------------- backend/src/federation/client/Client_1_1.ts | 44 ++++++++- .../src/federation/client/FederationClient.ts | 15 --- .../query/getPublicCommunityInfo.ts | 12 +++ 5 files changed, 55 insertions(+), 201 deletions(-) delete mode 100644 backend/src/federation/client/1_0/FederationClientImpl.ts delete mode 100644 backend/src/federation/client/1_1/FederationClientImpl.ts delete mode 100644 backend/src/federation/client/FederationClient.ts create mode 100644 backend/src/federation/query/getPublicCommunityInfo.ts diff --git a/backend/src/federation/client/1_0/FederationClientImpl.ts b/backend/src/federation/client/1_0/FederationClientImpl.ts deleted file mode 100644 index 8dfbd17af..000000000 --- a/backend/src/federation/client/1_0/FederationClientImpl.ts +++ /dev/null @@ -1,91 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-unsafe-return */ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ -import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity' -import { GraphQLError } from 'graphql/error/GraphQLError' -import { gql } from 'graphql-request' - -import { GraphQLGetClient } from '@/federation/client/GraphQLGetClient' -import { backendLogger as logger } from '@/server/logger' - -// eslint-disable-next-line import/no-relative-parent-imports -import { FederationClient, PublicCommunityInfo } from '../FederationClient' - -export class FederationClientImpl implements FederationClient { - public async requestGetPublicKey(dbCom: DbFederatedCommunity): Promise { - let endpoint = dbCom.endPoint.endsWith('/') ? dbCom.endPoint : dbCom.endPoint + '/' - endpoint = `${endpoint}${dbCom.apiVersion}/` - logger.info(`requestGetPublicKey with endpoint='${endpoint}'...`) - - const graphQLClient = GraphQLGetClient.getInstance(endpoint) - logger.debug(`graphQLClient=${JSON.stringify(graphQLClient)}`) - const query = gql` - query { - getPublicKey { - publicKey - } - } - ` - const variables = {} - - try { - const { data, errors, extensions, headers, status } = await graphQLClient.rawRequest( - query, - variables, - ) - logger.debug(`Response-Data:`, data, errors, extensions, headers, status) - if (data) { - logger.debug(`Response-PublicKey:`, data.getPublicKey.publicKey) - logger.info(`requestGetPublicKey processed successfully`) - return data.getPublicKey.publicKey - } - logger.warn(`requestGetPublicKey processed without response data`) - } catch (err) { - if (err instanceof GraphQLError) { - logger.error(`RawRequest-Error on {} with message {}`, endpoint, err.message) - } - throw new Error(`Request-Error in requestGetPublicKey.`) - } - } - - public async requestGetPublicCommunityInfo( - dbCom: DbFederatedCommunity, - ): Promise { - let endpoint = dbCom.endPoint.endsWith('/') ? dbCom.endPoint : dbCom.endPoint + '/' - endpoint = `${endpoint}${dbCom.apiVersion}/` - logger.info(`requestGetPublicCommunityInfo with endpoint='${endpoint}'...`) - - const graphQLClient = GraphQLGetClient.getInstance(endpoint) - logger.debug(`graphQLClient=${JSON.stringify(graphQLClient)}`) - const query = gql` - query { - getPublicCommunityInfo { - name - description - createdAt - publicKey - } - } - ` - const variables = {} - - try { - const { data, errors, extensions, headers, status } = await graphQLClient.rawRequest( - query, - variables, - ) - logger.debug(`Response-Data:`, data, errors, extensions, headers, status) - if (data) { - logger.debug(`Response-PublicCommunityInfo:`, data.getPublicCommunityInfo) - logger.info(`requestGetPublicCommunityInfo processed successfully`) - return data.getPublicCommunityInfo - } - logger.warn(`requestGetPublicInfo processed without response data`) - } catch (err) { - if (err instanceof GraphQLError) { - logger.error(`RawRequest-Error on {} with message {}`, endpoint, err.message) - } - throw new Error(`Request-Error in requestGetPublicCommunityInfo.`) - } - } -} diff --git a/backend/src/federation/client/1_1/FederationClientImpl.ts b/backend/src/federation/client/1_1/FederationClientImpl.ts deleted file mode 100644 index affc9a984..000000000 --- a/backend/src/federation/client/1_1/FederationClientImpl.ts +++ /dev/null @@ -1,94 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unsafe-return */ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity' -import { GraphQLError } from 'graphql/error/GraphQLError' -import { gql } from 'graphql-request' - -import { GraphQLGetClient } from '@/federation/client/GraphQLGetClient' -import { backendLogger as logger } from '@/server/logger' - -// eslint-disable-next-line import/no-relative-parent-imports -import { FederationClient, PublicCommunityInfo } from '../FederationClient' - -export class FederationClientImpl implements FederationClient { - async requestGetPublicKey(dbCom: DbFederatedCommunity): Promise { - let endpoint = dbCom.endPoint.endsWith('/') ? dbCom.endPoint : dbCom.endPoint + '/' - endpoint = `${endpoint}${dbCom.apiVersion}/` - logger.info(`requestGetPublicKey with endpoint='${endpoint}'...`) - - const graphQLClient = GraphQLGetClient.getInstance(endpoint) - logger.debug(`graphQLClient=${JSON.stringify(graphQLClient)}`) - const query = gql` - query { - getPublicKey { - publicKey - } - } - ` - const variables = {} - - try { - const { data, errors, extensions, headers, status } = await graphQLClient.rawRequest( - query, - variables, - ) - logger.debug(`Response-Data:`, data, errors, extensions, headers, status) - if (data) { - logger.debug(`Response-PublicKey:`, data.getPublicKey.publicKey) - logger.info(`requestGetPublicKey processed successfully`) - return data.getPublicKey.publicKey - } - logger.warn(`requestGetPublicKey processed without response data`) - } catch (err) { - if (err instanceof GraphQLError) { - logger.error(`RawRequest-Error on {} with message {}`, endpoint, err.message) - } - throw new Error(`Request-Error in requestGetPublicKey.`) - } - } - - async requestGetPublicCommunityInfo( - dbCom: DbFederatedCommunity, - ): Promise { - let endpoint = dbCom.endPoint.endsWith('/') ? dbCom.endPoint : dbCom.endPoint + '/' - endpoint = `${endpoint}${dbCom.apiVersion}/` - logger.info(`requestGetPublicCommunityInfo with endpoint='${endpoint}'...`) - - const graphQLClient = GraphQLGetClient.getInstance(endpoint) - logger.debug(`graphQLClient=${JSON.stringify(graphQLClient)}`) - const query = gql` - query { - getPublicCommunityInfo { - name - description - createdAt - publicKey - } - } - ` - const variables = {} - - try { - const { data, errors, extensions, headers, status } = await graphQLClient.rawRequest( - query, - variables, - ) - logger.debug(`Response-Data:`, data, errors, extensions, headers, status) - if (data) { - logger.debug( - `Response-PublicCommunityInfo:`, - data.getPublicCommunityInfo.publicCommunityInfo, - ) - logger.info(`requestGetPublicInfo processed successfully`) - return data.getPublicCommunityInfo.publicCommunityInfo - } - logger.warn(`requestGetPublicInfo processed without response data`) - } catch (err) { - if (err instanceof GraphQLError) { - logger.error(`RawRequest-Error on {} with message {}`, endpoint, err.message) - } - throw new Error(`Request-Error in requestGetPublicCommunityInfo.`) - } - } -} diff --git a/backend/src/federation/client/Client_1_1.ts b/backend/src/federation/client/Client_1_1.ts index 8525acc5d..7ef17694e 100644 --- a/backend/src/federation/client/Client_1_1.ts +++ b/backend/src/federation/client/Client_1_1.ts @@ -1,5 +1,47 @@ +import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity' + +import { getPublicCommunityInfo } from '@/federation/query/getPublicCommunityInfo' +import { backendLogger as logger } from '@/server/logger' + // eslint-disable-next-line camelcase import { Client_1_0 } from './Client_1_0' +export interface PublicCommunityInfo { + name: string + description: string + createdAt: Date + publicKey: string +} + // eslint-disable-next-line camelcase -export class Client_1_1 extends Client_1_0 {} +export class Client_1_1 extends Client_1_0 { + constructor(dbCom: DbFederatedCommunity) { + super(dbCom) + } + + getPublicCommunityInfo = async (): Promise => { + logger.info(`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 + if (!data?.getPublicCommunityInfo?.name) { + logger.warn( + 'Federation: getPublicCommunityInfo without response data from endpoint', + this.endpoint, + ) + return + } + logger.info( + 'Federation: getPublicCommunityInfo successful from endpoint', + this.endpoint, + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + data.getPublicCommunityInfo, + ) + // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access + return data.getPublicCommunityInfo + } catch (err) { + logger.warn('Federation: getPublicCommunityInfo failed for endpoint', this.endpoint) + } + } +} diff --git a/backend/src/federation/client/FederationClient.ts b/backend/src/federation/client/FederationClient.ts deleted file mode 100644 index 2af13e002..000000000 --- a/backend/src/federation/client/FederationClient.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity' - -export type PublicCommunityInfo = { - name: string - description: string - createdAt: Date - publicKey: string -} - -export interface FederationClient { - requestGetPublicKey(dbCom: DbFederatedCommunity): Promise - requestGetPublicCommunityInfo( - dbCom: DbFederatedCommunity, - ): Promise -} diff --git a/backend/src/federation/query/getPublicCommunityInfo.ts b/backend/src/federation/query/getPublicCommunityInfo.ts new file mode 100644 index 000000000..4dead00bd --- /dev/null +++ b/backend/src/federation/query/getPublicCommunityInfo.ts @@ -0,0 +1,12 @@ +import { gql } from 'graphql-request' + +export const getPublicCommunityInfo = gql` + query { + getPublicCommunityInfo { + name + description + createdAt + publicKey + } + } +` From 6ec82faa108ff71ada673f1b5c3d76dea6d9ccf3 Mon Sep 17 00:00:00 2001 From: Claus-Peter Huebner Date: Fri, 19 May 2023 14:45:28 +0200 Subject: [PATCH 07/17] changes after refactoring problems, eslint shifted in issue #2997 --- backend/src/federation/client/Client_1_1.ts | 7 ------- backend/src/federation/validateCommunities.ts | 12 +++++++----- .../api/1_0/model/GetPublicCommunityInfoResult.ts | 2 +- federation/tsconfig.json | 2 +- 4 files changed, 9 insertions(+), 14 deletions(-) diff --git a/backend/src/federation/client/Client_1_1.ts b/backend/src/federation/client/Client_1_1.ts index 7ef17694e..9a67757f4 100644 --- a/backend/src/federation/client/Client_1_1.ts +++ b/backend/src/federation/client/Client_1_1.ts @@ -1,5 +1,3 @@ -import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity' - import { getPublicCommunityInfo } from '@/federation/query/getPublicCommunityInfo' import { backendLogger as logger } from '@/server/logger' @@ -13,12 +11,7 @@ export interface PublicCommunityInfo { publicKey: string } -// eslint-disable-next-line camelcase export class Client_1_1 extends Client_1_0 { - constructor(dbCom: DbFederatedCommunity) { - super(dbCom) - } - getPublicCommunityInfo = async (): Promise => { logger.info(`getPublicCommunityInfo with endpoint='${this.endpoint}'...`) try { diff --git a/backend/src/federation/validateCommunities.ts b/backend/src/federation/validateCommunities.ts index f00f4b4b3..adca47f77 100644 --- a/backend/src/federation/validateCommunities.ts +++ b/backend/src/federation/validateCommunities.ts @@ -7,7 +7,7 @@ import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCom import { backendLogger as logger } from '@/server/logger' import { Client } from './client/Client' -import { PublicCommunityInfo } from './client/Client_1_1' +import { PublicCommunityInfo, Client_1_1 } from './client/Client_1_1' import { ApiVersionType } from './enum/apiVersionType' export function startValidateCommunities(timerInterval: number): void { @@ -44,10 +44,12 @@ export async function validateCommunities(): Promise { if (pubKey && pubKey === dbCom.publicKey.toString()) { await DbFederatedCommunity.update({ id: dbCom.id }, { verifiedAt: new Date() }) logger.info('Federation: verified community', dbCom) - const pubComInfo = await client?.getPublicCommunityInfo() - if (pubComInfo) { - await writeForeignCommunity(dbCom, pubComInfo) - logger.info(`Federation: write foreign community... successfully`) + if (client instanceof Client_1_1) { + const pubComInfo = await client.getPublicCommunityInfo() + if (pubComInfo) { + await writeForeignCommunity(dbCom, pubComInfo) + logger.info(`Federation: write foreign community... successfully`) + } } } else { logger.warn( diff --git a/federation/src/graphql/api/1_0/model/GetPublicCommunityInfoResult.ts b/federation/src/graphql/api/1_0/model/GetPublicCommunityInfoResult.ts index ea225203a..91ed5e2ff 100644 --- a/federation/src/graphql/api/1_0/model/GetPublicCommunityInfoResult.ts +++ b/federation/src/graphql/api/1_0/model/GetPublicCommunityInfoResult.ts @@ -1,6 +1,6 @@ // eslint-disable-next-line @typescript-eslint/no-unused-vars import { Community as DbCommunity } from '@entity/Community' -/* @typescript-eslint/no-unused-vars */ +// eslint-disable-next-line @typescript-eslint/no-unused-vars import { Field, ObjectType } from 'type-graphql' @ObjectType() diff --git a/federation/tsconfig.json b/federation/tsconfig.json index b38c43ba1..2326786ac 100644 --- a/federation/tsconfig.json +++ b/federation/tsconfig.json @@ -4,7 +4,7 @@ /* Basic Options */ // "incremental": true, /* Enable incremental compilation */ - "target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */ + "target": "esNext", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */ "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ // "lib": [], /* Specify library files to be included in the compilation. */ // "allowJs": true, /* Allow javascript files to be compiled. */ From 3e22b0780697a2ac2858637d0da3ddcacc1c386a Mon Sep 17 00:00:00 2001 From: Claus-Peter Huebner Date: Fri, 19 May 2023 17:19:21 +0200 Subject: [PATCH 08/17] optimize log-output --- backend/src/federation/client/1_0/FederationClient.ts | 11 ++++------- backend/src/federation/validateCommunities.ts | 10 +++------- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/backend/src/federation/client/1_0/FederationClient.ts b/backend/src/federation/client/1_0/FederationClient.ts index 69e67efcb..170b4e954 100644 --- a/backend/src/federation/client/1_0/FederationClient.ts +++ b/backend/src/federation/client/1_0/FederationClient.ts @@ -51,7 +51,7 @@ export class FederationClient { } getPublicCommunityInfo = async (): Promise => { - logger.info(`getPublicCommunityInfo with endpoint='${this.endpoint}'...`) + logger.info(`Federation: getPublicCommunityInfo with endpoint='${this.endpoint}'...`) try { // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const { data } = await this.client.rawRequest(getPublicCommunityInfo, {}) @@ -63,12 +63,9 @@ export class FederationClient { ) return } - logger.info( - 'Federation: getPublicCommunityInfo successful from endpoint', - this.endpoint, - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - data.getPublicCommunityInfo, - ) + logger.info(`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 return data.getPublicCommunityInfo } catch (err) { diff --git a/backend/src/federation/validateCommunities.ts b/backend/src/federation/validateCommunities.ts index 9fcbdda23..6bb020687 100644 --- a/backend/src/federation/validateCommunities.ts +++ b/backend/src/federation/validateCommunities.ts @@ -47,18 +47,14 @@ export async function validateCommunities(): Promise { const pubKey = await client.getPublicKey() if (pubKey && pubKey === dbCom.publicKey.toString()) { await DbFederatedCommunity.update({ id: dbCom.id }, { verifiedAt: new Date() }) - logger.info('Federation: verified community', dbCom) + logger.info(`Federation: verified community: id=${dbCom.id}, endpoint=${dbCom.endPoint}`) const pubComInfo = await client.getPublicCommunityInfo() if (pubComInfo) { await writeForeignCommunity(dbCom, pubComInfo) - logger.info(`Federation: write foreign community... successfully`) + logger.info(`Federation: write publicInfo of community: name=${pubComInfo.name}`) } } else { - logger.warn( - 'Federation: received not matching publicKey:', - pubKey, - dbCom.publicKey.toString(), - ) + logger.warn(`Federation: received none or not matching publicKey...`) } } } catch (err) { From b4fc67574ec4cc1a8fb50c398164e0b83d2cef48 Mon Sep 17 00:00:00 2001 From: Claus-Peter Huebner Date: Tue, 23 May 2023 01:48:30 +0200 Subject: [PATCH 09/17] first try to extent tests --- .../federation/validateCommunities.test.ts | 38 ++++++++++++++++--- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/backend/src/federation/validateCommunities.test.ts b/backend/src/federation/validateCommunities.test.ts index 0da5914bd..b1f8d0abe 100644 --- a/backend/src/federation/validateCommunities.test.ts +++ b/backend/src/federation/validateCommunities.test.ts @@ -87,7 +87,37 @@ describe('validate Communities', () => { overwrite: ['end_point', 'last_announced_at'], }) .execute() - + /* + // eslint-disable-next-line @typescript-eslint/require-await + jest.spyOn(GraphQLClient.prototype, 'rawRequest').mockImplementation(async () => { + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return { + data: { + getPublicCommunityInfo: { + name: 'Test-Community', + description: 'Description of Test-Community', + createdAt: 'someDate', + publicKey: 'somePubKey', + }, + }, + } as Response + }) + const variables2 = { + publicKey: Buffer.from('11111111111111111111111111111111'), + apiVersion: '1_0', + endPoint: 'http//localhost:5001/api/', + lastAnnouncedAt: new Date(), + } + await DbCommunity.createQueryBuilder() + .insert() + .into(DbFederatedCommunity) + .values(variables1) + .orUpdate({ + conflict_target: ['id', 'publicKey', 'apiVersion'], + overwrite: ['end_point', 'last_announced_at'], + }) + .execute() + */ jest.clearAllMocks() await validateCommunities() }) @@ -102,11 +132,7 @@ describe('validate Communities', () => { ) }) it('logs not matching publicKeys', () => { - expect(logger.warn).toBeCalledWith( - 'Federation: received not matching publicKey:', - 'somePubKey', - expect.stringMatching('11111111111111111111111111111111'), - ) + expect(logger.warn).toBeCalledWith('Federation: received none or not matching publicKey...') }) }) describe('with two Communities of api 1_0 and 1_1', () => { From c3772224c4b20a19f02f0beac1c10281259acc7a Mon Sep 17 00:00:00 2001 From: Claus-Peter Huebner Date: Thu, 25 May 2023 02:26:00 +0200 Subject: [PATCH 10/17] additional test with missing response data --- .../federation/validateCommunities.test.ts | 116 +++++++++++++++++- backend/src/federation/validateCommunities.ts | 8 +- 2 files changed, 116 insertions(+), 8 deletions(-) diff --git a/backend/src/federation/validateCommunities.test.ts b/backend/src/federation/validateCommunities.test.ts index c489798bb..c23bb84c2 100644 --- a/backend/src/federation/validateCommunities.test.ts +++ b/backend/src/federation/validateCommunities.test.ts @@ -59,7 +59,46 @@ describe('validate Communities', () => { expect(logger.debug).toBeCalledWith(`Federation: found 0 dbCommunities`) }) - describe('with one Community of api 1_0', () => { + describe('with one Community of api 1_0 but missing pubKey response', () => { + beforeEach(async () => { + // eslint-disable-next-line @typescript-eslint/require-await + jest.spyOn(GraphQLClient.prototype, 'rawRequest').mockImplementation(async () => { + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return { data: {} } as Response }) + const variables1 = { + publicKey: Buffer.from( + '1111111111111111111111111111111111111111111111111111111111111111', + ), + apiVersion: '1_0', + endPoint: 'http//localhost:5001/api/', + lastAnnouncedAt: new Date(), + } + await DbFederatedCommunity.createQueryBuilder() + .insert() + .into(DbFederatedCommunity) + .values(variables1) + .orUpdate({ + // eslint-disable-next-line camelcase + conflict_target: ['id', 'publicKey', 'apiVersion'], + overwrite: ['end_point', 'last_announced_at'], + }) + .execute() + jest.clearAllMocks() + await validateCommunities() + }) + + it('logs one community found', () => { + expect(logger.debug).toBeCalledWith(`Federation: found 1 dbCommunities`) + }) + it('logs requestGetPublicKey missing response data ', () => { + expect(logger.warn).toBeCalledWith( + 'Federation: getPublicKey without response data from endpoint', + 'http//localhost:5001/api/1_0/', + ) + }) + }) + + describe('with one Community of api 1_0 and not matching pubKey', () => { beforeEach(async () => { // eslint-disable-next-line @typescript-eslint/require-await jest.spyOn(GraphQLClient.prototype, 'rawRequest').mockImplementation(async () => { @@ -73,7 +112,9 @@ describe('validate Communities', () => { } as Response }) const variables1 = { - publicKey: Buffer.from('11111111111111111111111111111111'), + publicKey: Buffer.from( + '1111111111111111111111111111111111111111111111111111111111111111', + ), apiVersion: '1_0', endPoint: 'http//localhost:5001/api/', lastAnnouncedAt: new Date(), @@ -133,7 +174,64 @@ describe('validate Communities', () => { ) }) it('logs not matching publicKeys', () => { - expect(logger.warn).toBeCalledWith('Federation: received none or not matching publicKey...') + expect(logger.warn).toBeCalledWith( + 'Federation: received not matching publicKey:', + 'somePubKey', + expect.stringMatching('1111111111111111111111111111111111111111111111111111111111111111'), + ) + }) + }) + describe('with one Community of api 1_0 and matching pubKey', () => { + beforeEach(async () => { + // eslint-disable-next-line @typescript-eslint/require-await + jest.spyOn(GraphQLClient.prototype, 'rawRequest').mockImplementation(async () => { + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return { + data: { + getPublicKey: { + publicKey: '1111111111111111111111111111111111111111111111111111111111111111', + }, + }, + } as Response + }) + const variables1 = { + publicKey: Buffer.from( + '1111111111111111111111111111111111111111111111111111111111111111', + ), + apiVersion: '1_0', + endPoint: 'http//localhost:5001/api/', + lastAnnouncedAt: new Date(), + } + await DbFederatedCommunity.createQueryBuilder() + .insert() + .into(DbFederatedCommunity) + .values(variables1) + .orUpdate({ + // eslint-disable-next-line camelcase + conflict_target: ['id', 'publicKey', 'apiVersion'], + overwrite: ['end_point', 'last_announced_at'], + }) + .execute() + await DbFederatedCommunity.update({}, { verifiedAt: null }) + jest.clearAllMocks() + await validateCommunities() + }) + + it('logs one community found', () => { + expect(logger.debug).toBeCalledWith(`Federation: found 1 dbCommunities`) + }) + it('logs requestGetPublicKey for community api 1_0 ', () => { + expect(logger.info).toBeCalledWith( + 'Federation: getPublicKey from endpoint', + 'http//localhost:5001/api/1_0/', + ) + }) + it('logs community pubKey verified', () => { + expect(logger.info).toHaveBeenNthCalledWith( + 3, + 'Federation: verified community with:', + 'http//localhost:5001/api/', + ) }) }) describe('with two Communities of api 1_0 and 1_1', () => { @@ -145,13 +243,15 @@ describe('validate Communities', () => { return { data: { getPublicKey: { - publicKey: '11111111111111111111111111111111', + publicKey: '1111111111111111111111111111111111111111111111111111111111111111', }, }, } as Response }) const variables2 = { - publicKey: Buffer.from('11111111111111111111111111111111'), + publicKey: Buffer.from( + '1111111111111111111111111111111111111111111111111111111111111111', + ), apiVersion: '1_1', endPoint: 'http//localhost:5001/api/', lastAnnouncedAt: new Date(), @@ -167,6 +267,7 @@ describe('validate Communities', () => { }) .execute() + await DbFederatedCommunity.update({}, { verifiedAt: null }) jest.clearAllMocks() await validateCommunities() }) @@ -190,7 +291,9 @@ describe('validate Communities', () => { let dbCom: DbFederatedCommunity beforeEach(async () => { const variables3 = { - publicKey: Buffer.from('11111111111111111111111111111111'), + publicKey: Buffer.from( + '1111111111111111111111111111111111111111111111111111111111111111', + ), apiVersion: '2_0', endPoint: 'http//localhost:5001/api/', lastAnnouncedAt: new Date(), @@ -208,6 +311,7 @@ describe('validate Communities', () => { dbCom = await DbFederatedCommunity.findOneOrFail({ where: { publicKey: variables3.publicKey, apiVersion: variables3.apiVersion }, }) + await DbFederatedCommunity.update({}, { verifiedAt: null }) jest.clearAllMocks() await validateCommunities() }) diff --git a/backend/src/federation/validateCommunities.ts b/backend/src/federation/validateCommunities.ts index 6bb020687..3cf30195a 100644 --- a/backend/src/federation/validateCommunities.ts +++ b/backend/src/federation/validateCommunities.ts @@ -47,14 +47,18 @@ export async function validateCommunities(): Promise { const pubKey = await client.getPublicKey() if (pubKey && pubKey === dbCom.publicKey.toString()) { await DbFederatedCommunity.update({ id: dbCom.id }, { verifiedAt: new Date() }) - logger.info(`Federation: verified community: id=${dbCom.id}, endpoint=${dbCom.endPoint}`) + logger.info(`Federation: verified community with:`, dbCom.endPoint) const pubComInfo = await client.getPublicCommunityInfo() if (pubComInfo) { await writeForeignCommunity(dbCom, pubComInfo) logger.info(`Federation: write publicInfo of community: name=${pubComInfo.name}`) } } else { - logger.warn(`Federation: received none or not matching publicKey...`) + logger.warn( + 'Federation: received not matching publicKey:', + pubKey, + dbCom.publicKey.toString(), + ) } } } catch (err) { From 72865bf9f257ec42c4eedc5158aa5ae61b625e10 Mon Sep 17 00:00:00 2001 From: Claus-Peter Huebner Date: Thu, 17 Aug 2023 19:54:09 +0200 Subject: [PATCH 11/17] linting --- database/migrations/0068-community_tables_public_key_length.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/database/migrations/0068-community_tables_public_key_length.ts b/database/migrations/0068-community_tables_public_key_length.ts index 22c04e850..d5d047c26 100644 --- a/database/migrations/0068-community_tables_public_key_length.ts +++ b/database/migrations/0068-community_tables_public_key_length.ts @@ -39,4 +39,4 @@ export async function downgrade(queryFn: (query: string, values?: any[]) => Prom await queryFn( 'ALTER TABLE `communities` MODIFY COLUMN `public_key` binary(64) NULL DEFAULT NULL;', ) -} \ No newline at end of file +} From 986ac2c9986b4a7a8aab9036779eb68a28b10d7f Mon Sep 17 00:00:00 2001 From: Claus-Peter Huebner Date: Thu, 17 Aug 2023 23:58:27 +0200 Subject: [PATCH 12/17] additional testcases --- .../federation/validateCommunities.test.ts | 30 ++-- .../resolver/CommunityResolver.test.ts | 150 +++++++++++++++++- backend/src/seeds/graphql/queries.ts | 15 ++ 3 files changed, 184 insertions(+), 11 deletions(-) diff --git a/backend/src/federation/validateCommunities.test.ts b/backend/src/federation/validateCommunities.test.ts index 1b4f9f4a3..68d2433d8 100644 --- a/backend/src/federation/validateCommunities.test.ts +++ b/backend/src/federation/validateCommunities.test.ts @@ -67,9 +67,7 @@ describe('validate Communities', () => { return { data: {} } as Response }) const variables1 = { - publicKey: Buffer.from( - '1111111111111111111111111111111111111111111111111111111111111111', - ), + publicKey: Buffer.from('11111111111111111111111111111111'), apiVersion: '1_0', endPoint: 'http//localhost:5001/api/', lastAnnouncedAt: new Date(), @@ -113,9 +111,7 @@ describe('validate Communities', () => { } as Response }) const variables1 = { - publicKey: Buffer.from( - '1111111111111111111111111111111111111111111111111111111111111111', - ), + publicKey: Buffer.from('11111111111111111111111111111111'), apiVersion: '1_0', endPoint: 'http//localhost:5001/api/', lastAnnouncedAt: new Date(), @@ -227,10 +223,26 @@ describe('validate Communities', () => { }) it('logs community pubKey verified', () => { expect(logger.debug).toHaveBeenNthCalledWith( - 6, - 'Federation: verified community with', - 'http//localhost:5001/api/', + 5, + 'Federation: getPublicKey successful from endpoint', + 'http//localhost:5001/api/1_0/', + '11111111111111111111111111111111', ) + /* + await expect(DbCommunity.find()).resolves.toContainEqual( + expect.objectContaining({ + foreign: false, + url: 'http://localhost/api', + publicKey: Buffer.from('11111111111111111111111111111111'), + privateKey: expect.any(Buffer), + communityUuid: expect.any(String), + authenticatedAt: expect.any(Date), + name: expect.any(String), + description: expect.any(String), + creationDate: expect.any(Date), + }), + ) + */ }) }) describe('with two Communities of api 1_0 and 1_1', () => { diff --git a/backend/src/graphql/resolver/CommunityResolver.test.ts b/backend/src/graphql/resolver/CommunityResolver.test.ts index 840544e51..4b4101e66 100644 --- a/backend/src/graphql/resolver/CommunityResolver.test.ts +++ b/backend/src/graphql/resolver/CommunityResolver.test.ts @@ -6,12 +6,13 @@ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { Connection } from '@dbTools/typeorm' +import { Community as DbCommunity } from '@entity/Community' import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity' import { ApolloServerTestClient } from 'apollo-server-testing' -import { testEnvironment } from '@test/helpers' +import { cleanDB, testEnvironment } from '@test/helpers' -import { getCommunities } from '@/seeds/graphql/queries' +import { getCommunities, getCommunitySelections } from '@/seeds/graphql/queries' // to do: We need a setup for the tests that closes the connection let query: ApolloServerTestClient['query'], con: Connection @@ -29,6 +30,7 @@ beforeAll(async () => { }) afterAll(async () => { + await cleanDB() await con.close() }) @@ -55,6 +57,7 @@ describe('CommunityResolver', () => { describe('only home-communities entries', () => { beforeEach(async () => { + await cleanDB() jest.clearAllMocks() homeCom1 = DbFederatedCommunity.create() @@ -230,4 +233,147 @@ describe('CommunityResolver', () => { }) }) }) + + describe('getCommunitySelections', () => { + let homeCom1: DbCommunity + let foreignCom1: DbCommunity + let foreignCom2: DbCommunity + + describe('with empty list', () => { + beforeEach(async () => { + await cleanDB() + jest.clearAllMocks() + }) + + it('returns no community entry', async () => { + // const result: Community[] = await query({ query: getCommunities }) + // expect(result.length).toEqual(0) + await expect(query({ query: getCommunitySelections })).resolves.toMatchObject({ + data: { + getCommunitySelections: [], + }, + }) + }) + }) + + describe('with one home-community entry', () => { + beforeEach(async () => { + await cleanDB() + jest.clearAllMocks() + + homeCom1 = DbCommunity.create() + homeCom1.foreign = false + homeCom1.url = 'http://localhost/api' + homeCom1.publicKey = Buffer.from('publicKey-HomeCommunity') + homeCom1.privateKey = Buffer.from('privateKey-HomeCommunity') + homeCom1.communityUuid = 'HomeCom-UUID' + homeCom1.authenticatedAt = new Date() + homeCom1.name = 'HomeCommunity-name' + homeCom1.description = 'HomeCommunity-description' + homeCom1.creationDate = new Date() + await DbCommunity.insert(homeCom1) + }) + + it('returns 1 home-community entry', async () => { + await expect(query({ query: getCommunitySelections })).resolves.toMatchObject({ + data: { + getCommunitySelections: [ + { + id: expect.any(Number), + foreign: homeCom1.foreign, + name: homeCom1.name, + description: homeCom1.description, + url: homeCom1.url, + creationDate: homeCom1.creationDate?.toISOString(), + uuid: homeCom1.communityUuid, + authenticatedAt: homeCom1.authenticatedAt?.toISOString(), + }, + ], + }, + }) + }) + }) + + describe('with several community entries', () => { + beforeEach(async () => { + await cleanDB() + jest.clearAllMocks() + + homeCom1 = DbCommunity.create() + homeCom1.foreign = false + homeCom1.url = 'http://localhost/api' + homeCom1.publicKey = Buffer.from('publicKey-HomeCommunity') + homeCom1.privateKey = Buffer.from('privateKey-HomeCommunity') + homeCom1.communityUuid = 'HomeCom-UUID' + homeCom1.authenticatedAt = new Date() + homeCom1.name = 'HomeCommunity-name' + homeCom1.description = 'HomeCommunity-description' + homeCom1.creationDate = new Date() + await DbCommunity.insert(homeCom1) + + 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.communityUuid = 'Stage2-Com-UUID' + foreignCom1.authenticatedAt = new Date() + foreignCom1.name = 'Stage-2_Community-name' + foreignCom1.description = 'Stage-2_Community-description' + foreignCom1.creationDate = new Date() + await DbCommunity.insert(foreignCom1) + + 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.communityUuid = 'Stage3-Com-UUID' + foreignCom2.authenticatedAt = new Date() + foreignCom2.name = 'Stage-3_Community-name' + foreignCom2.description = 'Stage-3_Community-description' + foreignCom2.creationDate = new Date() + await DbCommunity.insert(foreignCom2) + }) + + it('returns 3 community entries', async () => { + await expect(query({ query: getCommunitySelections })).resolves.toMatchObject({ + data: { + getCommunitySelections: [ + { + id: expect.any(Number), + foreign: homeCom1.foreign, + name: homeCom1.name, + description: homeCom1.description, + url: homeCom1.url, + creationDate: homeCom1.creationDate?.toISOString(), + uuid: homeCom1.communityUuid, + authenticatedAt: homeCom1.authenticatedAt?.toISOString(), + }, + { + id: expect.any(Number), + foreign: foreignCom1.foreign, + name: foreignCom1.name, + description: foreignCom1.description, + url: foreignCom1.url, + creationDate: foreignCom1.creationDate?.toISOString(), + uuid: foreignCom1.communityUuid, + authenticatedAt: foreignCom1.authenticatedAt?.toISOString(), + }, + { + id: expect.any(Number), + foreign: foreignCom2.foreign, + name: foreignCom2.name, + description: foreignCom2.description, + url: foreignCom2.url, + creationDate: foreignCom2.creationDate?.toISOString(), + uuid: foreignCom2.communityUuid, + authenticatedAt: foreignCom2.authenticatedAt?.toISOString(), + }, + ], + }, + }) + }) + }) + }) }) diff --git a/backend/src/seeds/graphql/queries.ts b/backend/src/seeds/graphql/queries.ts index f016102a2..3dda2633c 100644 --- a/backend/src/seeds/graphql/queries.ts +++ b/backend/src/seeds/graphql/queries.ts @@ -157,6 +157,21 @@ export const getCommunities = gql` } ` +export const getCommunitySelections = gql` + query { + getCommunitySelections { + id + foreign + name + description + url + creationDate + uuid + authenticatedAt + } + } +` + export const queryTransactionLink = gql` query ($code: String!) { queryTransactionLink(code: $code) { From b18dd8e636572334af9a82b9b7f7af044b11248d Mon Sep 17 00:00:00 2001 From: Claus-Peter Huebner Date: Fri, 18 Aug 2023 01:09:27 +0200 Subject: [PATCH 13/17] additional Tests --- .../PublicCommunityInfoResolver.test.ts | 64 +++++++++++++++++++ .../resolver/PublicCommunityInfoResolver.ts | 8 +-- 2 files changed, 66 insertions(+), 6 deletions(-) create mode 100644 federation/src/graphql/api/1_0/resolver/PublicCommunityInfoResolver.test.ts diff --git a/federation/src/graphql/api/1_0/resolver/PublicCommunityInfoResolver.test.ts b/federation/src/graphql/api/1_0/resolver/PublicCommunityInfoResolver.test.ts new file mode 100644 index 000000000..08657c330 --- /dev/null +++ b/federation/src/graphql/api/1_0/resolver/PublicCommunityInfoResolver.test.ts @@ -0,0 +1,64 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ +import { createTestClient } from 'apollo-server-testing' +import createServer from '@/server/createServer' +import { Community as DbCommunity } from '@entity/Community' +import CONFIG from '@/config' + +let query: any + +// to do: We need a setup for the tests that closes the connection +let con: any + +CONFIG.FEDERATION_API = '1_0' + +beforeAll(async () => { + const server = await createServer() + con = server.con + query = createTestClient(server.apollo).query + DbCommunity.clear() +}) + +afterAll(async () => { + await con.close() +}) + +describe('PublicCommunityInfoResolver', () => { + const getPublicCommunityInfoQuery = ` + query { + getPublicCommunityInfo + { + name + description + createdAt + publicKey + } + } + ` + + describe('getPublicCommunityInfo', () => { + beforeEach(async () => { + const homeCom = new DbCommunity() + homeCom.foreign = false + homeCom.url = 'homeCommunity-url' + homeCom.name = 'Community-Name' + homeCom.description = 'Community-Description' + homeCom.createdAt = new Date() + homeCom.publicKey = Buffer.from('homeCommunity-publicKey') + await DbCommunity.insert(homeCom) + }) + + it('returns public CommunityInfo', async () => { + await expect(query({ query: getPublicCommunityInfoQuery })).resolves.toMatchObject({ + data: { + getPublicCommunityInfo: { + name: 'Community-Name', + description: 'Community-Description', + createdAt: expect.any(Date), + publicKey: expect.stringMatching('homeCommunity-publicKey'), + }, + }, + }) + }) + }) +}) diff --git a/federation/src/graphql/api/1_0/resolver/PublicCommunityInfoResolver.ts b/federation/src/graphql/api/1_0/resolver/PublicCommunityInfoResolver.ts index 3bd02e346..3076edd41 100644 --- a/federation/src/graphql/api/1_0/resolver/PublicCommunityInfoResolver.ts +++ b/federation/src/graphql/api/1_0/resolver/PublicCommunityInfoResolver.ts @@ -10,13 +10,9 @@ export class PublicCommunityInfoResolver { @Query(() => GetPublicCommunityInfoResult) async getPublicCommunityInfo(): Promise { logger.debug(`getPublicCommunityInfo() via apiVersion=1_0 ...`) - const homeCom = await DbCommunity.findOneOrFail({ foreign: false }) + const homeCom = await DbCommunity.findOneByOrFail({ foreign: false }) const result = new GetPublicCommunityInfoResult(homeCom) - logger.info( - `getPublicCommunityInfo()-1_0... return publicInfo=${JSON.stringify( - result - )}` - ) + logger.info(`getPublicCommunityInfo()-1_0... return publicInfo=${JSON.stringify(result)}`) return result } } From ed1ace5aab5624a927046720d1b67669d324ed11 Mon Sep 17 00:00:00 2001 From: Claus-Peter Huebner Date: Fri, 18 Aug 2023 17:31:39 +0200 Subject: [PATCH 14/17] add test and increase coverage --- .../api/1_0/model/GetPublicCommunityInfoResult.ts | 6 +++--- .../api/1_0/resolver/PublicCommunityInfoResolver.test.ts | 9 +++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/federation/src/graphql/api/1_0/model/GetPublicCommunityInfoResult.ts b/federation/src/graphql/api/1_0/model/GetPublicCommunityInfoResult.ts index 91ed5e2ff..86ea480df 100644 --- a/federation/src/graphql/api/1_0/model/GetPublicCommunityInfoResult.ts +++ b/federation/src/graphql/api/1_0/model/GetPublicCommunityInfoResult.ts @@ -7,10 +7,10 @@ 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('hex') + this.publicKey = dbCom.publicKey.toString() this.name = dbCom.name this.description = dbCom.description - this.createdAt = dbCom.creationDate + this.creationDate = dbCom.creationDate } @Field(() => String) @@ -20,7 +20,7 @@ export class GetPublicCommunityInfoResult { description: string | null @Field(() => Date) - createdAt: Date | null + creationDate: Date | null @Field(() => String) publicKey: string 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 08657c330..d18a30a7c 100644 --- a/federation/src/graphql/api/1_0/resolver/PublicCommunityInfoResolver.test.ts +++ b/federation/src/graphql/api/1_0/resolver/PublicCommunityInfoResolver.test.ts @@ -30,20 +30,21 @@ describe('PublicCommunityInfoResolver', () => { { name description - createdAt + creationDate publicKey } } ` describe('getPublicCommunityInfo', () => { + let homeCom: DbCommunity beforeEach(async () => { - const homeCom = new DbCommunity() + homeCom = new DbCommunity() homeCom.foreign = false homeCom.url = 'homeCommunity-url' homeCom.name = 'Community-Name' homeCom.description = 'Community-Description' - homeCom.createdAt = new Date() + homeCom.creationDate = new Date() homeCom.publicKey = Buffer.from('homeCommunity-publicKey') await DbCommunity.insert(homeCom) }) @@ -54,7 +55,7 @@ describe('PublicCommunityInfoResolver', () => { getPublicCommunityInfo: { name: 'Community-Name', description: 'Community-Description', - createdAt: expect.any(Date), + creationDate: homeCom.creationDate?.toISOString(), publicKey: expect.stringMatching('homeCommunity-publicKey'), }, }, From e4cadd6ae4a56380ac9d7d8601bfd09482791cc1 Mon Sep 17 00:00:00 2001 From: Claus-Peter Huebner Date: Fri, 18 Aug 2023 17:53:58 +0200 Subject: [PATCH 15/17] increase coverage --- federation/jest.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/federation/jest.config.js b/federation/jest.config.js index f055d66e2..25ff58fb3 100644 --- a/federation/jest.config.js +++ b/federation/jest.config.js @@ -6,7 +6,7 @@ module.exports = { collectCoverageFrom: ['src/**/*.ts', '!**/node_modules/**', '!src/seeds/**', '!build/**'], coverageThreshold: { global: { - lines: 72, + lines: 76, }, }, setupFiles: ['/test/testSetup.ts'], From a5dc9a8fc876a23b172a66775ad8ce7bc5135448 Mon Sep 17 00:00:00 2001 From: Claus-Peter Huebner Date: Fri, 18 Aug 2023 17:54:41 +0200 Subject: [PATCH 16/17] switch logoutputs to debug level --- 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 7890461c9..8d915c751 100644 --- a/backend/src/federation/client/1_0/FederationClient.ts +++ b/backend/src/federation/client/1_0/FederationClient.ts @@ -51,7 +51,7 @@ export class FederationClient { } getPublicCommunityInfo = async (): Promise => { - logger.info(`Federation: getPublicCommunityInfo with endpoint='${this.endpoint}'...`) + 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, {}) @@ -63,7 +63,7 @@ export class FederationClient { ) return } - logger.info(`Federation: getPublicCommunityInfo successful from endpoint=${this.endpoint}`) + 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 From 3d23fbb10c4f8acbd777654f9a45b04f21054a68 Mon Sep 17 00:00:00 2001 From: Claus-Peter Huebner Date: Fri, 18 Aug 2023 22:10:14 +0200 Subject: [PATCH 17/17] now with writing verified communities in communities table --- .../src/federation/client/1_0/model/PublicCommunityInfo.ts | 2 +- .../federation/client/1_0/query/getPublicCommunityInfo.ts | 2 +- backend/src/federation/validateCommunities.ts | 6 ++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/backend/src/federation/client/1_0/model/PublicCommunityInfo.ts b/backend/src/federation/client/1_0/model/PublicCommunityInfo.ts index 88f8e8eeb..cad8176be 100644 --- a/backend/src/federation/client/1_0/model/PublicCommunityInfo.ts +++ b/backend/src/federation/client/1_0/model/PublicCommunityInfo.ts @@ -1,6 +1,6 @@ export interface PublicCommunityInfo { name: string description: string - createdAt: Date + creationDate: Date publicKey: string } diff --git a/backend/src/federation/client/1_0/query/getPublicCommunityInfo.ts b/backend/src/federation/client/1_0/query/getPublicCommunityInfo.ts index 4dead00bd..f075b2aae 100644 --- a/backend/src/federation/client/1_0/query/getPublicCommunityInfo.ts +++ b/backend/src/federation/client/1_0/query/getPublicCommunityInfo.ts @@ -5,7 +5,7 @@ export const getPublicCommunityInfo = gql` getPublicCommunityInfo { name description - createdAt + creationDate publicKey } } diff --git a/backend/src/federation/validateCommunities.ts b/backend/src/federation/validateCommunities.ts index 75384726e..b76e77bd7 100644 --- a/backend/src/federation/validateCommunities.ts +++ b/backend/src/federation/validateCommunities.ts @@ -55,6 +55,8 @@ export async function validateCommunities(): Promise { if (pubComInfo) { await writeForeignCommunity(dbCom, pubComInfo) logger.info(`Federation: write publicInfo of community: name=${pubComInfo.name}`) + } else { + logger.warn('Federation: missing result of getPublicCommunityInfo') } } else { logger.warn( @@ -74,7 +76,7 @@ async function writeForeignCommunity( dbCom: DbFederatedCommunity, pubInfo: PublicCommunityInfo, ): Promise { - if (!dbCom || !pubInfo || !(dbCom.publicKey.toString('hex') === pubInfo.publicKey)) { + if (!dbCom || !pubInfo || !(dbCom.publicKey.toString() === pubInfo.publicKey)) { logger.error( `Error in writeForeignCommunity: missmatching parameters or publicKey. pubInfo:${JSON.stringify( pubInfo, @@ -85,7 +87,7 @@ async function writeForeignCommunity( if (!com) { com = DbCommunity.create() } - com.creationDate = pubInfo.createdAt + com.creationDate = pubInfo.creationDate com.description = pubInfo.description com.foreign = true com.name = pubInfo.name