From f01f59abbe2efa94bff5ac8ccb43944d1c71045f Mon Sep 17 00:00:00 2001 From: Magnus Kuhn <127854942+Magnus-Kuhn@users.noreply.github.com> Date: Tue, 12 Nov 2024 09:25:28 +0100 Subject: [PATCH] Personalized RelationshipTemplates (#293) * feat: add personalization to templates * refactor/fix: cleanup * feat: allow creating token for own template * test: fix tests, add token route * test: cleanup * fix: improve description * test: check forIdentity * refactor: restrict peer template query * console.log to see why tests fail only in ci * more logs * more * Revert "more" This reverts commit ed08d0d589182f708312d728565352b6d1056eea. * Revert "more logs" This reverts commit a9a96b20a2df4c2e19a70342c6673e025cc143a5. * Revert "console.log to see why tests fail only in ci" This reverts commit 5dd9ddf300a9efb3a0c0d35445cd1a9e804fe8a8. * chore: update backbone * fix: downgrade backbone * chore: bump backbone a bit --------- Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- .dev/compose.backbone.env | 2 +- .../ConnectorRelationshipTemplate.ts | 1 + .../CreateOwnRelationshipTemplateRequest.ts | 1 + ...eTokenForOwnRelationshipTemplateRequest.ts | 1 + ...QrCodeForOwnRelationshipTemplateRequest.ts | 1 + .../GetOwnRelationshipTemplatesRequest.ts | 1 + .../GetPeerRelationshipTemplatesRequest.ts | 1 + .../GetRelationshipTemplatesRequest.ts | 1 + .../sdk/src/types/tokens/ConnectorToken.ts | 1 + .../RelationshipTemplatesController.ts | 6 ++- src/modules/coreHttpApi/openapi.yml | 28 +++++++++++++ test/lib/testUtils.ts | 15 +++---- test/relationshipTemplates.test.ts | 40 +++++++++++++++---- 13 files changed, 82 insertions(+), 17 deletions(-) diff --git a/.dev/compose.backbone.env b/.dev/compose.backbone.env index d3dace30..8115afe5 100644 --- a/.dev/compose.backbone.env +++ b/.dev/compose.backbone.env @@ -1 +1 @@ -BACKBONE_VERSION=6.7.1 +BACKBONE_VERSION=6.15.2 diff --git a/packages/sdk/src/types/relationshipTemplates/ConnectorRelationshipTemplate.ts b/packages/sdk/src/types/relationshipTemplates/ConnectorRelationshipTemplate.ts index d68cacb6..654d186c 100644 --- a/packages/sdk/src/types/relationshipTemplates/ConnectorRelationshipTemplate.ts +++ b/packages/sdk/src/types/relationshipTemplates/ConnectorRelationshipTemplate.ts @@ -9,5 +9,6 @@ export interface ConnectorRelationshipTemplate { createdAt: string; content: RelationshipTemplateContentJSON | ArbitraryRelationshipTemplateContentJSON; expiresAt?: string; + forIdentity?: string; truncatedReference: string; } diff --git a/packages/sdk/src/types/relationshipTemplates/requests/CreateOwnRelationshipTemplateRequest.ts b/packages/sdk/src/types/relationshipTemplates/requests/CreateOwnRelationshipTemplateRequest.ts index 3b3738d2..2bf6dcb8 100644 --- a/packages/sdk/src/types/relationshipTemplates/requests/CreateOwnRelationshipTemplateRequest.ts +++ b/packages/sdk/src/types/relationshipTemplates/requests/CreateOwnRelationshipTemplateRequest.ts @@ -3,5 +3,6 @@ import { ArbitraryRelationshipTemplateContentJSON, RelationshipTemplateContentJS export interface CreateOwnRelationshipTemplateRequest { maxNumberOfAllocations?: number; expiresAt: string; + forIdentity?: string; content: RelationshipTemplateContentJSON | ArbitraryRelationshipTemplateContentJSON; } diff --git a/packages/sdk/src/types/relationshipTemplates/requests/CreateTokenForOwnRelationshipTemplateRequest.ts b/packages/sdk/src/types/relationshipTemplates/requests/CreateTokenForOwnRelationshipTemplateRequest.ts index d5d883fe..04d1375a 100644 --- a/packages/sdk/src/types/relationshipTemplates/requests/CreateTokenForOwnRelationshipTemplateRequest.ts +++ b/packages/sdk/src/types/relationshipTemplates/requests/CreateTokenForOwnRelationshipTemplateRequest.ts @@ -1,4 +1,5 @@ export interface CreateTokenForOwnRelationshipTemplateRequest { expiresAt?: string; ephemeral?: boolean; + forIdentity?: string; } diff --git a/packages/sdk/src/types/relationshipTemplates/requests/CreateTokenQrCodeForOwnRelationshipTemplateRequest.ts b/packages/sdk/src/types/relationshipTemplates/requests/CreateTokenQrCodeForOwnRelationshipTemplateRequest.ts index cbef70e2..536e3587 100644 --- a/packages/sdk/src/types/relationshipTemplates/requests/CreateTokenQrCodeForOwnRelationshipTemplateRequest.ts +++ b/packages/sdk/src/types/relationshipTemplates/requests/CreateTokenQrCodeForOwnRelationshipTemplateRequest.ts @@ -1,3 +1,4 @@ export interface CreateTokenQrCodeForOwnRelationshipTemplateRequest { expiresAt?: string; + forIdentity?: string; } diff --git a/packages/sdk/src/types/relationshipTemplates/requests/GetOwnRelationshipTemplatesRequest.ts b/packages/sdk/src/types/relationshipTemplates/requests/GetOwnRelationshipTemplatesRequest.ts index 9e75ce3f..bc683db4 100644 --- a/packages/sdk/src/types/relationshipTemplates/requests/GetOwnRelationshipTemplatesRequest.ts +++ b/packages/sdk/src/types/relationshipTemplates/requests/GetOwnRelationshipTemplatesRequest.ts @@ -3,4 +3,5 @@ export interface GetOwnTemplatesRequest { expiresAt?: string | string[]; createdByDevice?: string | string[]; maxNumberOfAllocations?: number | number[]; + forIdentity?: string | string[]; } diff --git a/packages/sdk/src/types/relationshipTemplates/requests/GetPeerRelationshipTemplatesRequest.ts b/packages/sdk/src/types/relationshipTemplates/requests/GetPeerRelationshipTemplatesRequest.ts index 578300e2..a1bfd834 100644 --- a/packages/sdk/src/types/relationshipTemplates/requests/GetPeerRelationshipTemplatesRequest.ts +++ b/packages/sdk/src/types/relationshipTemplates/requests/GetPeerRelationshipTemplatesRequest.ts @@ -3,4 +3,5 @@ export interface GetPeerRelationshipTemplatesRequest { expiresAt?: string | string[]; createdBy?: string | string[]; maxNumberOfAllocations?: number | number[]; + forIdentity?: string; } diff --git a/packages/sdk/src/types/relationshipTemplates/requests/GetRelationshipTemplatesRequest.ts b/packages/sdk/src/types/relationshipTemplates/requests/GetRelationshipTemplatesRequest.ts index 520476c0..db525988 100644 --- a/packages/sdk/src/types/relationshipTemplates/requests/GetRelationshipTemplatesRequest.ts +++ b/packages/sdk/src/types/relationshipTemplates/requests/GetRelationshipTemplatesRequest.ts @@ -4,5 +4,6 @@ export interface GetRelationshipTemplatesRequest { createdBy?: string | string[]; createdByDevice?: string | string[]; maxNumberOfAllocations?: number | number[]; + forIdentity?: string | string[]; isOwn?: boolean | boolean[]; } diff --git a/packages/sdk/src/types/tokens/ConnectorToken.ts b/packages/sdk/src/types/tokens/ConnectorToken.ts index 13683d5e..14abe322 100644 --- a/packages/sdk/src/types/tokens/ConnectorToken.ts +++ b/packages/sdk/src/types/tokens/ConnectorToken.ts @@ -5,6 +5,7 @@ export interface ConnectorToken { content: unknown; createdAt: string; expiresAt: string; + forIdentity?: string; truncatedReference: string; isEphemeral: boolean; } diff --git a/src/modules/coreHttpApi/controllers/RelationshipTemplatesController.ts b/src/modules/coreHttpApi/controllers/RelationshipTemplatesController.ts index 471c7be1..d5e5ceae 100644 --- a/src/modules/coreHttpApi/controllers/RelationshipTemplatesController.ts +++ b/src/modules/coreHttpApi/controllers/RelationshipTemplatesController.ts @@ -96,7 +96,8 @@ export class RelationshipTemplatesController extends BaseController { case "image/png": const qrCodeResult = await this.transportServices.relationshipTemplates.createTokenQRCodeForOwnTemplate({ templateId: id, - expiresAt: request.expiresAt + expiresAt: request.expiresAt, + forIdentity: request.forIdentity }); return this.file( qrCodeResult, @@ -110,7 +111,8 @@ export class RelationshipTemplatesController extends BaseController { const jsonResult = await this.transportServices.relationshipTemplates.createTokenForOwnTemplate({ templateId: id, expiresAt: request.expiresAt, - ephemeral: request.ephemeral + ephemeral: request.ephemeral, + forIdentity: request.forIdentity }); return this.created(jsonResult); } diff --git a/src/modules/coreHttpApi/openapi.yml b/src/modules/coreHttpApi/openapi.yml index 842677fc..e709a1ba 100644 --- a/src/modules/coreHttpApi/openapi.yml +++ b/src/modules/coreHttpApi/openapi.yml @@ -3192,6 +3192,10 @@ paths: name: maxNumberOfAllocations schema: $ref: "#/components/schemas/NumberFilter" + - in: query + name: forIdentity + schema: + $ref: "#/components/schemas/IdFilter" - in: query name: isOwn schema: @@ -3246,6 +3250,10 @@ paths: format: date-time example: 2025-01-01 description: A timestamp that describes when this relationship template expires. Expired templates cannot be used to create relationships anymore. + forIdentity: + $ref: "#/components/schemas/Address" + nullable: true + description: The only Identity that may load this RelationshipTemplate. content: oneOf: - $ref: "#/components/schemas/RelationshipTemplateContent" @@ -3309,6 +3317,10 @@ paths: name: maxNumberOfAllocations schema: $ref: "#/components/schemas/NumberFilter" + - in: query + name: forIdentity + schema: + $ref: "#/components/schemas/IdFilter" responses: 200: description: Success @@ -3409,6 +3421,10 @@ paths: name: maxNumberOfAllocations schema: $ref: "#/components/schemas/NumberFilter" + - in: query + name: forIdentity + schema: + $ref: "#/components/schemas/IdFilter" responses: 200: description: Success @@ -3507,6 +3523,10 @@ paths: ephemeral: description: If set to true the token will will not be cached in the database of the connector. Note that you will not be able to fetch this token unless you remember the truncatedReference of the token. Defaults to true. Will be ignored if Accept is set to image/png. type: boolean + forIdentity: + $ref: "#/components/schemas/Address" + nullable: true + description: The only Identity that may load this Token. If forIdentity is set for the RelationshipTemplate, that Identity must also be given here. responses: 201: description: Success @@ -5757,6 +5777,10 @@ components: type: string format: date-time description: A timestamp that describes when this relationship template expires. Expired templates cannot be used to create relationship requests anymore. + forIdentity: + $ref: "#/components/schemas/Address" + nullable: true + description: The only Identity that may load this RelationshipTemplate. content: oneOf: - $ref: "#/components/schemas/RelationshipTemplateContent" @@ -5913,6 +5937,10 @@ components: format: date-time nullable: false description: A timestamp that describes when this token expires. An expired token cannot be fetched from the platform anymore. However it will still be available for auditing purposes. + forIdentity: + $ref: "#/components/schemas/Address" + nullable: true + description: The only Identity that may load this Token. truncatedReference: type: string format: byte diff --git a/test/lib/testUtils.ts b/test/lib/testUtils.ts index 84305e8a..0e4b4cc8 100644 --- a/test/lib/testUtils.ts +++ b/test/lib/testUtils.ts @@ -179,14 +179,15 @@ export async function makeUploadRequest(values: Partial = }; } -export async function createTemplate(client: ConnectorClient): Promise { +export async function createTemplate(client: ConnectorClient, forIdentity?: string): Promise { const response = await client.relationshipTemplates.createOwnRelationshipTemplate({ maxNumberOfAllocations: 1, expiresAt: DateTime.utc().plus({ minutes: 10 }).toString(), content: { "@type": "ArbitraryRelationshipTemplateContent", value: { a: "b" } - } + }, + forIdentity }); expect(response).toBeSuccessful(ValidationSchema.RelationshipTemplate); @@ -194,10 +195,10 @@ export async function createTemplate(client: ConnectorClient): Promise { - const template = await createTemplate(client); +export async function getTemplateToken(client: ConnectorClient, forIdentity?: string): Promise { + const template = await createTemplate(client, forIdentity); - const response = await client.relationshipTemplates.createTokenForOwnRelationshipTemplate(template.id); + const response = await client.relationshipTemplates.createTokenForOwnRelationshipTemplate(template.id, { forIdentity }); expect(response).toBeSuccessful(ValidationSchema.Token); return response.result; @@ -212,8 +213,8 @@ export async function getFileToken(client: ConnectorClient): Promise { - const templateToken = await getTemplateToken(clientCreator); +export async function exchangeTemplate(clientCreator: ConnectorClient, clientRecpipient: ConnectorClient, forIdentity?: string): Promise { + const templateToken = await getTemplateToken(clientCreator, forIdentity); const response = await clientRecpipient.relationshipTemplates.loadPeerRelationshipTemplate({ reference: templateToken.truncatedReference diff --git a/test/relationshipTemplates.test.ts b/test/relationshipTemplates.test.ts index c4264a0b..35b0c2c1 100644 --- a/test/relationshipTemplates.test.ts +++ b/test/relationshipTemplates.test.ts @@ -3,7 +3,7 @@ import { DateTime } from "luxon"; import { Launcher } from "./lib/Launcher"; import { QueryParamConditions } from "./lib/QueryParamConditions"; import { getTimeout } from "./lib/setTimeout"; -import { createTemplate, exchangeTemplate } from "./lib/testUtils"; +import { createTemplate, exchangeTemplate, getTemplateToken } from "./lib/testUtils"; import { ValidationSchema } from "./lib/validation"; const launcher = new Launcher(); @@ -82,6 +82,29 @@ describe("Template Tests", () => { expect(response.isError).toBeTruthy(); expect(response.error.code).toBe("error.runtime.validation.invalidPropertyValue"); }); + + test("send and receive a personalized template", async () => { + const client2address = (await client2.account.getIdentityInfo()).result.address; + const template = await createTemplate(client1, client2address); + expect(template.forIdentity).toBe(client2address); + + const response = await client2.relationshipTemplates.loadPeerRelationshipTemplate({ + reference: template.truncatedReference + }); + expect(response).toBeSuccessful(ValidationSchema.RelationshipTemplate); + expect(response.result.forIdentity).toBe(client2address); + }); + + test("send and receive a personalized template via token", async () => { + const client2address = (await client2.account.getIdentityInfo()).result.address; + const templateToken = await getTemplateToken(client1, client2address); + + const response = await client2.relationshipTemplates.loadPeerRelationshipTemplate({ + reference: templateToken.truncatedReference + }); + expect(response).toBeSuccessful(ValidationSchema.RelationshipTemplate); + expect(response.result.forIdentity).toBe(client2address); + }); }); describe("Serialization Errors", () => { @@ -107,37 +130,40 @@ describe("Serialization Errors", () => { describe("RelationshipTemplates Query", () => { test("query templates", async () => { - const template = await createTemplate(client1); + const template = await createTemplate(client1, (await client1.account.getIdentityInfo()).result.address); const conditions = new QueryParamConditions(template, client1) .addBooleanSet("isOwn") .addDateSet("createdAt") .addDateSet("expiresAt") .addStringSet("createdBy") .addStringSet("createdByDevice") - .addNumberSet("maxNumberOfAllocations"); + .addNumberSet("maxNumberOfAllocations") + .addStringSet("forIdentity"); await conditions.executeTests((c, q) => c.relationshipTemplates.getRelationshipTemplates(q), ValidationSchema.RelationshipTemplates); }); test("query own templates", async () => { - const template = await createTemplate(client1); + const template = await createTemplate(client1, (await client1.account.getIdentityInfo()).result.address); const conditions = new QueryParamConditions(template, client1) .addDateSet("createdAt") .addDateSet("expiresAt") .addStringSet("createdBy") .addStringSet("createdByDevice") - .addNumberSet("maxNumberOfAllocations"); + .addNumberSet("maxNumberOfAllocations") + .addStringSet("forIdentity"); await conditions.executeTests((c, q) => c.relationshipTemplates.getOwnRelationshipTemplates(q), ValidationSchema.RelationshipTemplates); }); test("query peer templates", async () => { - const template = await exchangeTemplate(client1, client2); + const template = await exchangeTemplate(client1, client2, (await client2.account.getIdentityInfo()).result.address); const conditions = new QueryParamConditions(template, client2) .addDateSet("createdAt") .addDateSet("expiresAt") .addStringSet("createdBy") .addStringSet("createdByDevice") - .addNumberSet("maxNumberOfAllocations"); + .addNumberSet("maxNumberOfAllocations") + .addStringSet("forIdentity"); await conditions.executeTests((c, q) => c.relationshipTemplates.getPeerRelationshipTemplates(q), ValidationSchema.RelationshipTemplates); });