/** 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' // 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 { ApiVersionType } from './enum/apiVersionType' export function startValidateCommunities(timerInterval: number): void { logger.info( `Federation: startValidateCommunities loop with an interval of ${timerInterval} ms...`, ) // TODO: replace the timer-loop by an event-based communication to verify announced foreign communities // better to use setTimeout twice than setInterval once -> see https://javascript.info/settimeout-setinterval setTimeout(function run() { void validateCommunities() setTimeout(run, timerInterval) }, timerInterval) } export async function validateCommunities(): Promise { const dbFederatedCommunities: DbFederatedCommunity[] = await DbFederatedCommunity.createQueryBuilder() .where({ foreign: true, verifiedAt: IsNull() }) .orWhere('verified_at < last_announced_at') .getMany() logger.debug(`Federation: found ${dbFederatedCommunities.length} dbCommunities`) for (const dbCom of dbFederatedCommunities) { logger.debug('Federation: dbCom', dbCom) const apiValueStrings: string[] = Object.values(ApiVersionType) logger.debug(`suppported ApiVersions=`, apiValueStrings) if (!apiValueStrings.includes(dbCom.apiVersion)) { logger.warn('Federation: dbCom with unsupported apiVersion', dbCom.endPoint, dbCom.apiVersion) continue } try { const client = FederationClientFactory.getInstance(dbCom) // eslint-disable-next-line camelcase if (client instanceof V1_0_FederationClient) { 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}`) 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...`) } } } catch (err) { logger.error(`Error:`, err) } } } async function writeForeignCommunity( dbCom: DbFederatedCommunity, pubInfo: PublicCommunityInfo, ): Promise { 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) } }