diff --git a/backend/src/federation/authenticateCommunities.ts b/backend/src/federation/authenticateCommunities.ts new file mode 100644 index 000000000..57e0fa57b --- /dev/null +++ b/backend/src/federation/authenticateCommunities.ts @@ -0,0 +1,42 @@ +import { Community as DbCommunity } from '@entity/Community' +import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity' + +import { CONFIG } from '@/config' +// eslint-disable-next-line camelcase +import { AuthenticationClient as V1_0_AuthenticationClient } from '@/federation/client/1_0/AuthenticationClient' +import { backendLogger as logger } from '@/server/logger' + +import { OpenConnectionArgs } from './client/1_0/model/OpenConnectionArgs' +import { AuthenticationClientFactory } from './client/AuthenticationClientFactory' + +export async function startCommunityAuthentication( + foreignFedCom: DbFederatedCommunity, +): Promise { + const homeCom = await DbCommunity.findOneByOrFail({ foreign: false }) + const homeFedCom = await DbFederatedCommunity.findOneByOrFail({ + foreign: false, + apiVersion: CONFIG.FEDERATION_BACKEND_SEND_ON_API, + }) + const foreignCom = await DbCommunity.findOneByOrFail({ publicKey: foreignFedCom.publicKey }) + if (foreignCom && foreignCom.communityUuid === null && foreignCom.authenticatedAt === null) { + try { + const client = AuthenticationClientFactory.getInstance(homeFedCom) + // eslint-disable-next-line camelcase + if (client instanceof V1_0_AuthenticationClient) { + const args = new OpenConnectionArgs() + args.publicKey = homeCom.publicKey.toString('hex') + // TODO encrypt url with foreignCom.publicKey and sign it with homeCom.privateKey + args.url = homeFedCom.endPoint.endsWith('/') + ? homeFedCom.endPoint + : homeFedCom.endPoint + '/' + homeFedCom.apiVersion + if (await client.openConnection(args)) { + logger.info(`Authentication: successful initiated at community:`, foreignFedCom.endPoint) + } else { + logger.error(`Authentication: can't initiate at community:`, foreignFedCom.endPoint) + } + } + } catch (err) { + logger.error(`Error:`, err) + } + } +} diff --git a/backend/src/federation/client/1_0/AuthenticationClient.ts b/backend/src/federation/client/1_0/AuthenticationClient.ts new file mode 100644 index 000000000..0a59d0cc0 --- /dev/null +++ b/backend/src/federation/client/1_0/AuthenticationClient.ts @@ -0,0 +1,50 @@ +import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity' +import { GraphQLClient } from 'graphql-request' + +import { backendLogger as logger } from '@/server/logger' + +import { OpenConnectionArgs } from './model/OpenConnectionArgs' +import { openConnection } from './query/openConnection' + +export class AuthenticationClient { + dbCom: DbFederatedCommunity + endpoint: string + client: GraphQLClient + + constructor(dbCom: DbFederatedCommunity) { + this.dbCom = dbCom + this.endpoint = `${dbCom.endPoint.endsWith('/') ? dbCom.endPoint : dbCom.endPoint + '/'}${ + dbCom.apiVersion + }/` + this.client = new GraphQLClient(this.endpoint, { + method: 'GET', + jsonSerializer: { + parse: JSON.parse, + stringify: JSON.stringify, + }, + }) + } + + async openConnection(args: OpenConnectionArgs): Promise { + logger.debug('Authentication: openConnection with endpoint', this.endpoint) + 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 + if (!data?.openConnection) { + logger.warn( + 'Authentication: openConnection without response data from endpoint', + this.endpoint, + ) + return false + } + logger.debug( + 'Authentication: openConnection successfully started with endpoint', + this.endpoint, + ) + return true + } catch (err) { + logger.error('Authentication: error on openConnection', err) + } + } +} diff --git a/backend/src/federation/client/1_0/model/OpenConnectionArgs.ts b/backend/src/federation/client/1_0/model/OpenConnectionArgs.ts new file mode 100644 index 000000000..9752f4e6f --- /dev/null +++ b/backend/src/federation/client/1_0/model/OpenConnectionArgs.ts @@ -0,0 +1,10 @@ +import { ArgsType, Field } from 'type-graphql' + +@ArgsType() +export class OpenConnectionArgs { + @Field(() => String) + publicKey: string + + @Field(() => String) + url: string +} diff --git a/backend/src/federation/client/1_0/query/openConnection.ts b/backend/src/federation/client/1_0/query/openConnection.ts new file mode 100644 index 000000000..f049df5a9 --- /dev/null +++ b/backend/src/federation/client/1_0/query/openConnection.ts @@ -0,0 +1,7 @@ +import { gql } from 'graphql-request' + +export const openConnection = gql` + mutation ($args: OpenConnectionArgs!) { + openConnection(data: $args) + } +` diff --git a/backend/src/federation/client/1_1/AuthenticationClient.ts b/backend/src/federation/client/1_1/AuthenticationClient.ts new file mode 100644 index 000000000..bbb4e8140 --- /dev/null +++ b/backend/src/federation/client/1_1/AuthenticationClient.ts @@ -0,0 +1,5 @@ +// eslint-disable-next-line camelcase +import { AuthenticationClient as V1_0_AuthenticationClient } from '@/federation/client/1_0/AuthenticationClient' + +// eslint-disable-next-line camelcase +export class AuthenticationClient extends V1_0_AuthenticationClient {} diff --git a/backend/src/federation/client/AuthenticationClientFactory.ts b/backend/src/federation/client/AuthenticationClientFactory.ts new file mode 100644 index 000000000..dc9229da6 --- /dev/null +++ b/backend/src/federation/client/AuthenticationClientFactory.ts @@ -0,0 +1,62 @@ +import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity' + +// eslint-disable-next-line camelcase +import { AuthenticationClient as V1_0_AuthenticationClient } from '@/federation/client/1_0/AuthenticationClient' +// eslint-disable-next-line camelcase +import { AuthenticationClient as V1_1_AuthenticationClient } from '@/federation/client/1_1/AuthenticationClient' +import { ApiVersionType } from '@/federation/enum/apiVersionType' + +// eslint-disable-next-line camelcase +type AuthenticationClient = V1_0_AuthenticationClient | V1_1_AuthenticationClient + +interface AuthenticationClientInstance { + id: number + // eslint-disable-next-line no-use-before-define + client: AuthenticationClient +} + +// eslint-disable-next-line @typescript-eslint/no-extraneous-class +export class AuthenticationClientFactory { + private static instanceArray: AuthenticationClientInstance[] = [] + + /** + * The Singleton's constructor should always be private to prevent direct + * construction calls with the `new` operator. + */ + // eslint-disable-next-line no-useless-constructor, @typescript-eslint/no-empty-function + private constructor() {} + + private static createAuthenticationClient = (dbCom: DbFederatedCommunity) => { + switch (dbCom.apiVersion) { + case ApiVersionType.V1_0: + return new V1_0_AuthenticationClient(dbCom) + case ApiVersionType.V1_1: + return new V1_1_AuthenticationClient(dbCom) + default: + return null + } + } + + /** + * The static method that controls the access to the singleton instance. + * + * This implementation let you subclass the Singleton class while keeping + * just one instance of each subclass around. + */ + public static getInstance(dbCom: DbFederatedCommunity): AuthenticationClient | null { + const instance = AuthenticationClientFactory.instanceArray.find( + (instance) => instance.id === dbCom.id, + ) + if (instance) { + return instance.client + } + const client = AuthenticationClientFactory.createAuthenticationClient(dbCom) + if (client) { + AuthenticationClientFactory.instanceArray.push({ + id: dbCom.id, + client, + } as AuthenticationClientInstance) + } + return client + } +} diff --git a/backend/src/federation/validateCommunities.ts b/backend/src/federation/validateCommunities.ts index b76e77bd7..f497be2cb 100644 --- a/backend/src/federation/validateCommunities.ts +++ b/backend/src/federation/validateCommunities.ts @@ -10,6 +10,7 @@ import { PublicCommunityInfo } from '@/federation/client/1_0/model/PublicCommuni import { FederationClientFactory } from '@/federation/client/FederationClientFactory' import { backendLogger as logger } from '@/server/logger' +import { startCommunityAuthentication } from './authenticateCommunities' import { ApiVersionType } from './enum/apiVersionType' export async function startValidateCommunities(timerInterval: number): Promise { @@ -40,7 +41,11 @@ export async function validateCommunities(): Promise { 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) + logger.debug( + 'Federation: dbCom with unsupported apiVersion', + dbCom.endPoint, + dbCom.apiVersion, + ) continue } try { @@ -54,7 +59,8 @@ export async function validateCommunities(): Promise { const pubComInfo = await client.getPublicCommunityInfo() if (pubComInfo) { await writeForeignCommunity(dbCom, pubComInfo) - logger.info(`Federation: write publicInfo of community: name=${pubComInfo.name}`) + void startCommunityAuthentication(dbCom) + logger.debug(`Federation: write publicInfo of community: name=${pubComInfo.name}`) } else { logger.warn('Federation: missing result of getPublicCommunityInfo') } diff --git a/docu/Concepts/TechnicalRequirements/image/TechnicalOverview_V1-19.drawio.png b/docu/Concepts/TechnicalRequirements/image/TechnicalOverview_V1-19.drawio.png new file mode 100644 index 000000000..bb96811eb Binary files /dev/null and b/docu/Concepts/TechnicalRequirements/image/TechnicalOverview_V1-19.drawio.png differ diff --git a/federation/package.json b/federation/package.json index 9de75c0fa..55fb408be 100644 --- a/federation/package.json +++ b/federation/package.json @@ -16,7 +16,6 @@ "lint": "eslint --max-warnings=0 --ext .js,.ts ." }, "dependencies": { - "@types/uuid": "8.3.4", "apollo-server-express": "^2.25.2", "await-semaphore": "0.1.3", "class-validator": "^0.13.2", @@ -26,9 +25,11 @@ "dotenv": "10.0.0", "express": "4.17.1", "graphql": "15.5.1", + "graphql-request": "^5.0.0", "lodash.clonedeep": "^4.5.0", "log4js": "^6.7.1", "reflect-metadata": "^0.1.13", + "sodium-native": "^4.0.4", "type-graphql": "^1.1.1", "uuid": "8.3.2" }, @@ -37,6 +38,8 @@ "@types/jest": "27.0.2", "@types/lodash.clonedeep": "^4.5.6", "@types/node": "^16.10.3", + "@types/sodium-native": "^2.3.7", + "@types/uuid": "8.3.4", "@typescript-eslint/eslint-plugin": "^5.57.1", "@typescript-eslint/parser": "^5.57.1", "apollo-server-testing": "2.25.2", diff --git a/federation/src/client/1_0/AuthenticationClient.ts b/federation/src/client/1_0/AuthenticationClient.ts new file mode 100644 index 000000000..4437e2a69 --- /dev/null +++ b/federation/src/client/1_0/AuthenticationClient.ts @@ -0,0 +1,70 @@ +import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity' +import { GraphQLClient } from 'graphql-request' +import { federationLogger as logger } from '@/server/logger' + +import { OpenConnectionCallbackArgs } from '@/graphql/api/1_0/model/OpenConnectionCallbackArgs' +import { openConnectionCallback } from './query/openConnectionCallback' +import { AuthenticationArgs } from '@/graphql/api/1_0/model/AuthenticationArgs' +import { authenticate } from './query/authenticate' + + +export class AuthenticationClient { + dbCom: DbFederatedCommunity + endpoint: string + client: GraphQLClient + + constructor(dbCom: DbFederatedCommunity) { + this.dbCom = dbCom + this.endpoint = `${dbCom.endPoint.endsWith('/') ? dbCom.endPoint : dbCom.endPoint + '/'}${ + dbCom.apiVersion + }/` + this.client = new GraphQLClient(this.endpoint, { + method: 'GET', + jsonSerializer: { + parse: JSON.parse, + stringify: JSON.stringify, + }, + }) + } + + async openConnectionCallback(args: OpenConnectionCallbackArgs): Promise { + logger.debug('Authentication: openConnectionCallback with endpoint', this.endpoint, args) + try { + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const { data } = await this.client.rawRequest(openConnectionCallback, { args }) + if (!data?.openConnectionCallback) { + logger.warn( + 'Authentication: openConnectionCallback without response data from endpoint', + this.endpoint, + ) + return false + } + logger.debug( + 'Authentication: openConnectionCallback successfully started with endpoint', + this.endpoint, + ) + return true + } catch (err) { + logger.error('Authentication: error on openConnectionCallback', err) + } + } + + async authenticate(args: AuthenticationArgs): Promise { + logger.debug('Authentication: authenticate with endpoint=', this.endpoint) + try { + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const { data } = await this.client.rawRequest(authenticate, {}) + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + if (!data?.authenticate) { + logger.warn( + 'Authentication: authenticate without response data from endpoint', + this.endpoint, + ) + return + } + const + } catch (err) { + logger.error('Authentication: authenticate failed for endpoint', this.endpoint) + } + } +} diff --git a/federation/src/client/1_0/query/authenticate.ts b/federation/src/client/1_0/query/authenticate.ts new file mode 100644 index 000000000..3079268d9 --- /dev/null +++ b/federation/src/client/1_0/query/authenticate.ts @@ -0,0 +1,7 @@ +import { gql } from 'graphql-request' + +export const authenticate = gql` + mutation ($args: AuthenticateArgs!) { + authenticate(data: $args) + } +` diff --git a/federation/src/client/1_0/query/openConnectionCallback.ts b/federation/src/client/1_0/query/openConnectionCallback.ts new file mode 100644 index 000000000..ba026e610 --- /dev/null +++ b/federation/src/client/1_0/query/openConnectionCallback.ts @@ -0,0 +1,7 @@ +import { gql } from 'graphql-request' + +export const openConnectionCallback = gql` + mutation ($args: OpenConnectionCallbackArgs!) { + openConnectionCallback(data: $args) + } +` diff --git a/federation/src/client/1_1/AuthenticationClient.ts b/federation/src/client/1_1/AuthenticationClient.ts new file mode 100644 index 000000000..eb5721b16 --- /dev/null +++ b/federation/src/client/1_1/AuthenticationClient.ts @@ -0,0 +1,5 @@ +// eslint-disable-next-line camelcase +import { AuthenticationClient as V1_0_AuthenticationClient } from '../1_0/AuthenticationClient' + +// eslint-disable-next-line camelcase +export class AuthenticationClient extends V1_0_AuthenticationClient {} diff --git a/federation/src/client/AuthenticationClientFactory.ts b/federation/src/client/AuthenticationClientFactory.ts new file mode 100644 index 000000000..f01636498 --- /dev/null +++ b/federation/src/client/AuthenticationClientFactory.ts @@ -0,0 +1,61 @@ +import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity' +// eslint-disable-next-line camelcase +import { AuthenticationClient as V1_0_AuthenticationClient } from './1_0/AuthenticationClient' +// eslint-disable-next-line camelcase +import { AuthenticationClient as V1_1_AuthenticationClient } from './1_1/AuthenticationClient' +import { ApiVersionType } from './enum/apiVersionType' + +// eslint-disable-next-line camelcase +type AuthenticationClient = V1_0_AuthenticationClient | V1_1_AuthenticationClient + +interface AuthenticationClientInstance { + id: number + // eslint-disable-next-line no-use-before-define + client: AuthenticationClient +} + +// eslint-disable-next-line @typescript-eslint/no-extraneous-class +export class AuthenticationClientFactory { + private static instanceArray: AuthenticationClientInstance[] = [] + + /** + * The Singleton's constructor should always be private to prevent direct + * construction calls with the `new` operator. + */ + // eslint-disable-next-line no-useless-constructor, @typescript-eslint/no-empty-function + private constructor() {} + + private static createAuthenticationClient = (dbCom: DbFederatedCommunity) => { + switch (dbCom.apiVersion) { + case ApiVersionType.V1_0: + return new V1_0_AuthenticationClient(dbCom) + case ApiVersionType.V1_1: + return new V1_1_AuthenticationClient(dbCom) + default: + return null + } + } + + /** + * The static method that controls the access to the singleton instance. + * + * This implementation let you subclass the Singleton class while keeping + * just one instance of each subclass around. + */ + public static getInstance(dbCom: DbFederatedCommunity): AuthenticationClient | null { + const instance = AuthenticationClientFactory.instanceArray.find( + (instance) => instance.id === dbCom.id, + ) + if (instance) { + return instance.client + } + const client = AuthenticationClientFactory.createAuthenticationClient(dbCom) + if (client) { + AuthenticationClientFactory.instanceArray.push({ + id: dbCom.id, + client, + } as AuthenticationClientInstance) + } + return client + } +} diff --git a/federation/src/client/enum/ApiVersionType.ts b/federation/src/client/enum/ApiVersionType.ts new file mode 100644 index 000000000..60da9de57 --- /dev/null +++ b/federation/src/client/enum/ApiVersionType.ts @@ -0,0 +1,4 @@ +export enum ApiVersionType { + V1_0 = '1_0', + V1_1 = '1_1', +} diff --git a/federation/src/graphql/api/1_0/model/AuthenticationArgs.ts b/federation/src/graphql/api/1_0/model/AuthenticationArgs.ts new file mode 100644 index 000000000..d0dc200da --- /dev/null +++ b/federation/src/graphql/api/1_0/model/AuthenticationArgs.ts @@ -0,0 +1,10 @@ +import { ArgsType, Field } from 'type-graphql' + +@ArgsType() +export class AuthenticationArgs { + @Field(() => String) + oneTimeCode: string + + @Field(() => String) + uuid: string +} diff --git a/federation/src/graphql/api/1_0/model/OpenConnectionArgs.ts b/federation/src/graphql/api/1_0/model/OpenConnectionArgs.ts new file mode 100644 index 000000000..9752f4e6f --- /dev/null +++ b/federation/src/graphql/api/1_0/model/OpenConnectionArgs.ts @@ -0,0 +1,10 @@ +import { ArgsType, Field } from 'type-graphql' + +@ArgsType() +export class OpenConnectionArgs { + @Field(() => String) + publicKey: string + + @Field(() => String) + url: string +} diff --git a/federation/src/graphql/api/1_0/model/OpenConnectionCallbackArgs.ts b/federation/src/graphql/api/1_0/model/OpenConnectionCallbackArgs.ts new file mode 100644 index 000000000..fa4eb17b5 --- /dev/null +++ b/federation/src/graphql/api/1_0/model/OpenConnectionCallbackArgs.ts @@ -0,0 +1,13 @@ +import { ArgsType, Field } from 'type-graphql' + +@ArgsType() +export class OpenConnectionCallbackArgs { + @Field(() => String) + oneTimeCode: string + + @Field(() => String) + publicKey: string + + @Field(() => String) + url: string +} diff --git a/federation/src/graphql/api/1_0/resolver/AuthenticationResolver.ts b/federation/src/graphql/api/1_0/resolver/AuthenticationResolver.ts new file mode 100644 index 000000000..cd86e87da --- /dev/null +++ b/federation/src/graphql/api/1_0/resolver/AuthenticationResolver.ts @@ -0,0 +1,51 @@ +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import { Arg, Mutation, Resolver } from 'type-graphql' +import { federationLogger as logger } from '@/server/logger' +import { Community as DbCommunity } from '@entity/Community' +import { LogError } from '@/server/LogError' +import { OpenConnectionArgs } from '../model/OpenConnectionArgs' +import { + startOpenConnectionCallback, + startOpenConnectionRedirect, +} from '../util/authenticateCommunity' +import { OpenConnectionCallbackArgs } from '../model/OpenConnectionCallbackArgs' +import { ApiVersionType } from '@/client/enum/apiVersionType' + +@Resolver() +// eslint-disable-next-line @typescript-eslint/no-unused-vars +export class AuthenticationResolver { + @Mutation(() => Boolean) + async openConnection( + @Arg('data') + args: OpenConnectionArgs, + ): Promise { + logger.debug(`Authentication: openConnection() via apiVersion=1_0 ...`, args) + + // first find with args.publicKey the community, which starts openConnection request + const requestedCom = await DbCommunity.findOneBy({ + publicKey: Buffer.from(args.publicKey), + }) + if (!requestedCom) { + throw new LogError(`unknown requesting community with publicKey`, args.publicKey) + } + void startOpenConnectionRedirect(args, requestedCom, ApiVersionType.V1_0) + return true + } + + @Mutation(() => Boolean) + async openConnectionCallback( + @Arg('data') + args: OpenConnectionCallbackArgs, + ): Promise { + logger.debug(`Authentication: openConnectionCallback() via apiVersion=1_0 ...`, args) + // first find with args.publicKey the community, which invokes openConnectionCallback + const callbackCom = await DbCommunity.findOneBy({ + publicKey: Buffer.from(args.publicKey), + }) + if (!callbackCom) { + throw new LogError(`unknown callback community with publicKey`, args.publicKey) + } + void startOpenConnectionCallback(args, callbackCom) + return true + } +} diff --git a/federation/src/graphql/api/1_0/util/authenticateCommunity.ts b/federation/src/graphql/api/1_0/util/authenticateCommunity.ts new file mode 100644 index 000000000..b2a4a832c --- /dev/null +++ b/federation/src/graphql/api/1_0/util/authenticateCommunity.ts @@ -0,0 +1,75 @@ +import { OpenConnectionArgs } from '../model/OpenConnectionArgs' +import { Community as DbCommunity } from '@entity/Community' +import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity' +import { federationLogger as logger } from '@/server/logger' +import { OpenConnectionCallbackArgs } from '../model/OpenConnectionCallbackArgs' +// eslint-disable-next-line camelcase +import { randombytes_random } from 'sodium-native' +import { AuthenticationClientFactory } from '@/client/AuthenticationClientFactory' +import { ApiVersionType } from '@/client/enum/apiVersionType' +// eslint-disable-next-line camelcase +import { AuthenticationClient as V1_0_AuthenticationClient } from '@/client/1_0/AuthenticationClient' + +export async function startOpenConnectionRedirect( + args: OpenConnectionArgs, + requestedCom: DbCommunity, + api: ApiVersionType, +): Promise { + logger.debug( + `Authentication: startOpenConnectionRedirect()...`, + args.publicKey, + args.url, + requestedCom, + ) + try { + // TODO verify signing of args.url with requestedCom.publicKey and decrypt with homeCom.privateKey + const homeCom = await DbCommunity.findOneByOrFail({ foreign: false }) + const homeFedCom = await DbFederatedCommunity.findOneByOrFail({ + foreign: false, + apiVersion: api, + }) + const oneTimeCode = randombytes_random() + // store oneTimeCode in requestedCom.community_uuid for authenticate-request-identifier + requestedCom.communityUuid = oneTimeCode.toString() + await DbCommunity.save(requestedCom) + + const client = AuthenticationClientFactory.getInstance(homeFedCom) + // eslint-disable-next-line camelcase + if (client instanceof V1_0_AuthenticationClient) { + const callbackArgs = new OpenConnectionCallbackArgs() + callbackArgs.oneTimeCode = oneTimeCode.toString() + callbackArgs.publicKey = homeCom.publicKey.toString('hex') + // TODO signing of callbackArgs.url with requestedCom.publicKey and decrypt with homeCom.privateKey + callbackArgs.url = homeFedCom.endPoint.endsWith('/') + ? homeFedCom.endPoint + : homeFedCom.endPoint + '/' + homeFedCom.apiVersion + if (await client.openConnectionCallback(callbackArgs)) { + logger.debug('Authentication: startOpenConnectionRedirect() successful:', callbackArgs) + } else { + logger.error('Authentication: startOpenConnectionRedirect() failed:', callbackArgs) + } + } + } catch (err) { + logger.error('Authentication: error in startOpenConnectionRedirect:', err) + } +} + +export async function startOpenConnectionCallback( + args: OpenConnectionCallbackArgs, + callbackCom: DbCommunity, +): Promise { + logger.debug( + `Authentication: startOpenConnectionCallback()...`, + args.publicKey, + args.url, + callbackCom, + ) + try { + // TODO verify signing of args.url with requestedCom.publicKey and decrypt with homeCom.privateKey + const homeCom = await DbCommunity.findOneByOrFail({ foreign: false }) + + + } catch (err) { + logger.error('Authentication: error in startOpenConnectionCallback:', err) + } +} diff --git a/federation/yarn.lock b/federation/yarn.lock index 87bd7f0d4..1f3cdca2c 100644 --- a/federation/yarn.lock +++ b/federation/yarn.lock @@ -374,6 +374,11 @@ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.42.0.tgz#484a1d638de2911e6f5a30c12f49c7e4a3270fb6" integrity sha512-6SWlXpWU5AvId8Ac7zjzmIOqMOba/JWY8XZ4A7q7Gn1Vlfg/SFFIlrtHXt9nPn4op9ZPAkl91Jao+QQv3r/ukw== +"@graphql-typed-document-node/core@^3.1.1": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.2.0.tgz#5f3d96ec6b2354ad6d8a28bf216a1d97b5426861" + integrity sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ== + "@humanwhocodes/config-array@^0.11.10": version "0.11.10" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.10.tgz#5a3ffe32cc9306365fb3fd572596cd602d5e12d2" @@ -1052,6 +1057,13 @@ "@types/mime" "*" "@types/node" "*" +"@types/sodium-native@^2.3.7": + version "2.3.7" + resolved "https://registry.yarnpkg.com/@types/sodium-native/-/sodium-native-2.3.7.tgz#fdcbd026e9a730e574e69ccb85fd36fd50220a8c" + integrity sha512-VlwblVfVHizegm0QJX0Hgna+w7P9z5Gy+LYkO7EWlOj7tew2kj1csq8ziGMiruL+dm/WjRwaoGuE6STV+0bN2g== + dependencies: + "@types/node" "*" + "@types/stack-utils@^2.0.0": version "2.0.1" resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" @@ -1948,6 +1960,13 @@ cross-env@^7.0.3: dependencies: cross-spawn "^7.0.1" +cross-fetch@^3.1.5: + version "3.1.8" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.8.tgz#0327eba65fd68a7d119f8fb2bf9334a1a7956f82" + integrity sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg== + dependencies: + node-fetch "^2.6.12" + cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" @@ -2678,6 +2697,11 @@ express@^4.17.1: utils-merge "1.0.1" vary "~1.1.2" +extract-files@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/extract-files/-/extract-files-9.0.0.tgz#8a7744f2437f81f5ed3250ed9f1550de902fe54a" + integrity sha512-CvdFfHkC95B4bBBk36hcEmvdR2awOdhhVUYH6S/zrVj3477zven/fJMYg7121h4T1xHZC+tetUpubpAhxwI7hQ== + fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" @@ -3017,6 +3041,16 @@ graphql-query-complexity@^0.7.0: dependencies: lodash.get "^4.4.2" +graphql-request@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/graphql-request/-/graphql-request-5.2.0.tgz#a05fb54a517d91bb2d7aefa17ade4523dc5ebdca" + integrity sha512-pLhKIvnMyBERL0dtFI3medKqWOz/RhHdcgbZ+hMMIb32mEPa5MJSzS4AuXxfI4sRAu6JVVk5tvXuGfCWl9JYWQ== + dependencies: + "@graphql-typed-document-node/core" "^3.1.1" + cross-fetch "^3.1.5" + extract-files "^9.0.0" + form-data "^3.0.0" + graphql-subscriptions@^1.0.0, graphql-subscriptions@^1.1.0: version "1.2.1" resolved "https://registry.yarnpkg.com/graphql-subscriptions/-/graphql-subscriptions-1.2.1.tgz#2142b2d729661ddf967b7388f7cf1dd4cf2e061d" @@ -4228,6 +4262,18 @@ node-fetch@^2.6.1: dependencies: whatwg-url "^5.0.0" +node-fetch@^2.6.12: + version "2.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + dependencies: + whatwg-url "^5.0.0" + +node-gyp-build@^4.6.0: + version "4.6.1" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.6.1.tgz#24b6d075e5e391b8d5539d98c7fc5c210cac8a3e" + integrity sha512-24vnklJmyRS8ViBNI8KbtK/r/DmXQMRiOMXTNz2nrTnAYUwjmEEbnnpB/+kt+yWRv73bPsSPRFddrcIbAxSiMQ== + node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" @@ -4943,6 +4989,13 @@ slash@^4.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-4.0.0.tgz#2422372176c4c6c5addb5e2ada885af984b396a7" integrity sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew== +sodium-native@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/sodium-native/-/sodium-native-4.0.4.tgz#561b7c39c97789f8202d6fd224845fe2e8cd6879" + integrity sha512-faqOKw4WQKK7r/ybn6Lqo1F9+L5T6NlBJJYvpxbZPetpWylUVqz449mvlwIBKBqxEHbWakWuOlUt8J3Qpc4sWw== + dependencies: + node-gyp-build "^4.6.0" + source-map-support@^0.5.6: version "0.5.21" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f"