import { IsNull } from '@dbTools/typeorm' import { Community as DbCommunity } from '@entity/Community' 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' // eslint-disable-next-line camelcase import { requestGetPublicKey as v1_1_requestGetPublicKey } from './client/1_1/FederationClient' 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 dbCommunities: DbCommunity[] = await DbCommunity.createQueryBuilder() .where({ foreign: true, verifiedAt: IsNull() }) .orWhere('verified_at < last_announced_at') .getMany() logger.debug(`Federation: found ${dbCommunities.length} dbCommunities`) for (const dbCom of dbCommunities) { logger.debug('Federation: dbCom', dbCom) const apiValueStrings: string[] = Object.values(ApiVersionType) logger.debug(`suppported ApiVersions=`, apiValueStrings) if (apiValueStrings.includes(dbCom.apiVersion)) { logger.debug( `Federation: validate publicKey for dbCom: ${dbCom.id} with apiVersion=${dbCom.apiVersion}`, ) try { const pubKey = await invokeVersionedRequestGetPublicKey(dbCom) logger.info( 'Federation: received publicKey from endpoint', pubKey, `${dbCom.endPoint}/${dbCom.apiVersion}`, ) if (pubKey && pubKey === dbCom.publicKey.toString()) { logger.info(`Federation: matching publicKey: ${pubKey}`) await DbCommunity.update({ id: dbCom.id }, { verifiedAt: new Date() }) logger.debug(`Federation: updated dbCom: ${JSON.stringify(dbCom)}`) } else { logger.warn( `Federation: received not matching publicKey -> received: ${ pubKey || 'null' }, expected: ${dbCom.publicKey.toString()} `, ) // DbCommunity.delete({ id: dbCom.id }) } } catch (err) { if (!isLogError(err)) { logger.error(`Error:`, err) } } } else { logger.warn( `Federation: dbCom: ${dbCom.id} with unsupported apiVersion=${dbCom.apiVersion}; supported versions`, apiValueStrings, ) } } } function isLogError(err: unknown) { return err instanceof LogError } async function invokeVersionedRequestGetPublicKey(dbCom: DbCommunity): Promise { switch (dbCom.apiVersion) { case ApiVersionType.V1_0: return v1_0_requestGetPublicKey(dbCom) case ApiVersionType.V1_1: return v1_1_requestGetPublicKey(dbCom) default: return undefined } }