Skip to content

Commit

Permalink
Merge branch 'main' into refactor-accountcontroller
Browse files Browse the repository at this point in the history
  • Loading branch information
mergify[bot] authored Dec 10, 2024
2 parents 3c7baa0 + d2ecc42 commit b28516f
Show file tree
Hide file tree
Showing 16 changed files with 1,202 additions and 91 deletions.
8 changes: 8 additions & 0 deletions .dev/appsettings.override.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@
}
},
"Modules": {
"Announcements": {
"Infrastructure": {
"SqlDatabase": {
"Provider": "Postgres",
"ConnectionString": "User ID=announcements;Password=Passw0rd;Server=postgres;Port=5432;Database=enmeshed;"
}
}
},
"Challenges": {
"Infrastructure": {
"SqlDatabase": {
Expand Down
2 changes: 1 addition & 1 deletion .dev/compose.backbone.env
Original file line number Diff line number Diff line change
@@ -1 +1 @@
BACKBONE_VERSION=6.20.0
BACKBONE_VERSION=6.22.0
4 changes: 4 additions & 0 deletions .dev/compose.backbone.yml
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ services:
Database__Provider: Postgres
Database__ConnectionString: "Server=postgres;Database=enmeshed;User Id=devices;Password=Passw0rd;Port=5432"

networks:
default:
name: backbone

configs:
Config:
file: appsettings.override.json
1,034 changes: 985 additions & 49 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"jest-expect-message": "^1.1.3",
"madge": "^8.0.0",
"npm-check-updates": "^17.1.11",
"prettier": "^3.4.1",
"prettier": "^3.4.2",
"ts-jest": "^29.2.5",
"ts-node": "^10.9.2",
"tsconfig-paths": "^4.2.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,7 @@ export class TestObjectFactory {
createdAt: CoreDate.from("2022-01-03T00:00:00.000Z"),
createdBy: CoreAddress.from("did:e:a-domain:dids:anidentity"),
createdByDevice: CoreId.from("DVC1"),
// must be DecompositionDueToIdentityDeletion in the future
reason: RelationshipAuditLogEntryReason.Decomposition,
reason: RelationshipAuditLogEntryReason.DecompositionDueToIdentityDeletion,
oldStatus: RelationshipStatus.Active,
newStatus: RelationshipStatus.DeletionProposed
}
Expand Down
27 changes: 27 additions & 0 deletions packages/runtime/src/useCases/common/Schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22772,6 +22772,33 @@ export const GetRelationshipTemplatesRequest: any = {
}
}
]
},
"passwordProtection": {
"type": "string",
"enum": [
"",
"!"
]
},
"passwordProtection.password": {
"anyOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "string"
}
}
]
},
"passwordProtection.passwordIsPin": {
"type": "string",
"enum": [
"true",
"!"
]
}
},
"additionalProperties": false
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { QueryTranslator } from "@js-soft/docdb-querytranslator";
import { Result } from "@js-soft/ts-utils";
import { CachedRelationshipTemplate, RelationshipTemplate, RelationshipTemplateController } from "@nmshd/transport";
import { CachedRelationshipTemplate, PasswordProtection, RelationshipTemplate, RelationshipTemplateController } from "@nmshd/transport";
import { Inject } from "@nmshd/typescript-ioc";
import { nameof } from "ts-simple-nameof";
import { RelationshipTemplateDTO } from "../../../types";
Expand All @@ -15,6 +15,9 @@ export interface GetRelationshipTemplatesQuery {
createdByDevice?: string | string[];
maxNumberOfAllocations?: string | string[];
forIdentity?: string | string[];
passwordProtection?: "" | "!";
"passwordProtection.password"?: string | string[];
"passwordProtection.passwordIsPin"?: "true" | "!";
}

export interface GetRelationshipTemplatesRequest {
Expand All @@ -37,7 +40,10 @@ export class GetRelationshipTemplatesUseCase extends UseCase<GetRelationshipTemp
[nameof<RelationshipTemplateDTO>((r) => r.createdBy)]: true,
[nameof<RelationshipTemplateDTO>((r) => r.createdByDevice)]: true,
[nameof<RelationshipTemplateDTO>((r) => r.maxNumberOfAllocations)]: true,
[nameof<RelationshipTemplateDTO>((r) => r.forIdentity)]: true
[nameof<RelationshipTemplateDTO>((r) => r.forIdentity)]: true,
[nameof<RelationshipTemplateDTO>((r) => r.passwordProtection)]: true,
[`${nameof<RelationshipTemplateDTO>((r) => r.passwordProtection)}.password`]: true,
[`${nameof<RelationshipTemplateDTO>((r) => r.passwordProtection)}.passwordIsPin`]: true
},
alias: {
[nameof<RelationshipTemplateDTO>((r) => r.isOwn)]: nameof<RelationshipTemplate>((r) => r.isOwn),
Expand All @@ -50,7 +56,23 @@ export class GetRelationshipTemplatesUseCase extends UseCase<GetRelationshipTemp
[nameof<RelationshipTemplateDTO>((r) => r.maxNumberOfAllocations)]: `${nameof<RelationshipTemplate>((r) => r.cache)}.${nameof<CachedRelationshipTemplate>(
(t) => t.maxNumberOfAllocations
)}`,
[nameof<RelationshipTemplateDTO>((r) => r.forIdentity)]: `${nameof<RelationshipTemplate>((r) => r.cache)}.${nameof<CachedRelationshipTemplate>((t) => t.forIdentity)}`
[nameof<RelationshipTemplateDTO>((r) => r.forIdentity)]: `${nameof<RelationshipTemplate>((r) => r.cache)}.${nameof<CachedRelationshipTemplate>((t) => t.forIdentity)}`,
[nameof<RelationshipTemplateDTO>((r) => r.passwordProtection)]: nameof<RelationshipTemplate>((r) => r.passwordProtection)
},
custom: {
[`${nameof<RelationshipTemplateDTO>((r) => r.passwordProtection)}.password`]: (query: any, input: string) => {
query[`${nameof<RelationshipTemplate>((t) => t.passwordProtection)}.${nameof<PasswordProtection>((t) => t.password)}`] = input;
},
[`${nameof<RelationshipTemplateDTO>((t) => t.passwordProtection)}.passwordIsPin`]: (query: any, input: string) => {
if (input === "true") {
query[`${nameof<RelationshipTemplate>((t) => t.passwordProtection)}.${nameof<PasswordProtection>((t) => t.passwordType)}`] = {
$regex: "^pin"
};
}
if (input === "!") {
query[`${nameof<RelationshipTemplate>((t) => t.passwordProtection)}.${nameof<PasswordProtection>((t) => t.passwordType)}`] = "pw";
}
}
}
});

Expand Down
43 changes: 20 additions & 23 deletions packages/runtime/test/transport/messages.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import {
reactivateTerminatedRelationship,
RuntimeServiceProvider,
sendMessage,
sendMessageToMultipleRecipients,
syncUntilHasEvent,
syncUntilHasMessage,
syncUntilHasMessages,
Expand Down Expand Up @@ -360,43 +359,41 @@ describe("Message errors", () => {

describe("Message errors for peers that are in deletion", () => {
let relationshipIdToClient2: string;
let relationshipIdToClient5: string;

beforeAll(async () => {
relationshipIdToClient2 = (await client1.transport.relationships.getRelationshipByAddress({ address: client2.address })).value.id;
relationshipIdToClient5 = (await ensureActiveRelationship(client1.transport, client5.transport)).id;
await ensureActiveRelationship(client1.transport, client5.transport);
});

afterEach(async () => {
for (const client of [client2, client5]) {
const activeIdentityDeletionProcess = await client.transport.identityDeletionProcesses.getActiveIdentityDeletionProcess();
if (!activeIdentityDeletionProcess.isSuccess) {
return;
}
let abortResult;
if (activeIdentityDeletionProcess.value.status === IdentityDeletionProcessStatus.Approved) {
abortResult = await client.transport.identityDeletionProcesses.cancelIdentityDeletionProcess();
} else if (activeIdentityDeletionProcess.value.status === IdentityDeletionProcessStatus.WaitingForApproval) {
abortResult = await client.transport.identityDeletionProcesses.rejectIdentityDeletionProcess();
}
await syncUntilHasEvent(client1, PeerDeletionCancelledEvent);
if (abortResult?.isError) throw abortResult.error;
const activeIdentityDeletionProcess = await client2.transport.identityDeletionProcesses.getActiveIdentityDeletionProcess();
if (!activeIdentityDeletionProcess.isSuccess) {
return;
}
let abortResult;
if (activeIdentityDeletionProcess.value.status === IdentityDeletionProcessStatus.Approved) {
abortResult = await client2.transport.identityDeletionProcesses.cancelIdentityDeletionProcess();
} else if (activeIdentityDeletionProcess.value.status === IdentityDeletionProcessStatus.WaitingForApproval) {
abortResult = await client2.transport.identityDeletionProcesses.rejectIdentityDeletionProcess();
}
await syncUntilHasEvent(client1, PeerDeletionCancelledEvent);
if (abortResult?.isError) throw abortResult.error;
});

test("should throw correct error for Messages whose content is not a Notification if there are recipients in deletion", async () => {
await client2.transport.identityDeletionProcesses.initiateIdentityDeletionProcess();
await syncUntilHasEvent(client1, PeerToBeDeletedEvent, (e) => e.data.id === relationshipIdToClient2);
await client1.eventBus.waitForRunningEventHandlers();

await client5.transport.identityDeletionProcesses.initiateIdentityDeletionProcess();
await syncUntilHasEvent(client1, PeerToBeDeletedEvent, (e) => e.data.id === relationshipIdToClient5);
await client1.eventBus.waitForRunningEventHandlers();

const result = await sendMessageToMultipleRecipients(client1.transport, [client2.address, client5.address]);
const result = await client1.transport.messages.sendMessage({
recipients: [client2.address],
content: {
"@type": "ArbitraryMessageContent",
value: "aString"
}
});
expect(result).toBeAnError(/.*/, "error.runtime.messages.peerIsInDeletion");
expect(result.error.message).toBe(
`The Message cannot be sent as the recipient(s) with the following address(es) being in deletion: '${client2.address.toString()}', '${client5.address.toString()}'. However, please note that Messages whose content is a Notification can be sent to recipients in deletion.`
`The Message cannot be sent as the recipient(s) with the following address(es) being in deletion: '${client2.address.toString()}'. However, please note that Messages whose content is a Notification can be sent to recipients in deletion.`
);
});

Expand Down
59 changes: 54 additions & 5 deletions packages/runtime/test/transport/relationshipTemplates.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,11 @@ describe("RelationshipTemplates query", () => {
maxNumberOfAllocations: 1,
expiresAt: DateTime.utc().plus({ minutes: 10 }).toString(),
content: emptyRelationshipTemplateContent,
forIdentity: runtimeServices1.address
forIdentity: runtimeServices1.address,
passwordProtection: {
password: "1234",
passwordIsPin: true
}
})
).value;
const conditions = new QueryParamConditions<GetRelationshipTemplatesQuery>(template, runtimeServices1.transport)
Expand All @@ -287,7 +291,28 @@ describe("RelationshipTemplates query", () => {
.addStringSet("createdBy")
.addStringSet("createdByDevice")
.addNumberSet("maxNumberOfAllocations")
.addStringSet("forIdentity");
.addStringSet("forIdentity")
.addSingleCondition({
expectedResult: true,
key: "passwordProtection",
value: ""
})
.addSingleCondition({
expectedResult: false,
key: "passwordProtection",
value: "!"
})
.addStringSet("passwordProtection.password")
.addSingleCondition({
expectedResult: true,
key: "passwordProtection.passwordIsPin",
value: "true"
})
.addSingleCondition({
expectedResult: false,
key: "passwordProtection.passwordIsPin",
value: "!"
});

await conditions.executeTests((c, q) => c.relationshipTemplates.getRelationshipTemplates({ query: q }));
});
Expand All @@ -297,15 +322,29 @@ describe("RelationshipTemplates query", () => {
await runtimeServices1.transport.relationshipTemplates.createOwnRelationshipTemplate({
maxNumberOfAllocations: 1,
expiresAt: DateTime.utc().plus({ minutes: 10 }).toString(),
content: emptyRelationshipTemplateContent
content: emptyRelationshipTemplateContent,
passwordProtection: {
password: "password"
}
})
).value;
const conditions = new QueryParamConditions<GetRelationshipTemplatesQuery>(template, runtimeServices1.transport)
.addDateSet("createdAt")
.addDateSet("expiresAt")
.addStringSet("createdBy")
.addStringSet("createdByDevice")
.addNumberSet("maxNumberOfAllocations");
.addNumberSet("maxNumberOfAllocations")
.addStringSet("passwordProtection.password")
.addSingleCondition({
expectedResult: false,
key: "passwordProtection.passwordIsPin",
value: "true"
})
.addSingleCondition({
expectedResult: true,
key: "passwordProtection.passwordIsPin",
value: "!"
});
await conditions.executeTests((c, q) => c.relationshipTemplates.getRelationshipTemplates({ query: q, ownerRestriction: OwnerRestriction.Own }));
});

Expand All @@ -323,7 +362,17 @@ describe("RelationshipTemplates query", () => {
.addDateSet("expiresAt")
.addStringSet("createdBy")
.addStringSet("createdByDevice")
.addNumberSet("maxNumberOfAllocations");
.addNumberSet("maxNumberOfAllocations")
.addSingleCondition({
expectedResult: false,
key: "passwordProtection",
value: ""
})
.addSingleCondition({
expectedResult: true,
key: "passwordProtection",
value: "!"
});

await conditions.executeTests((c, q) => c.relationshipTemplates.getRelationshipTemplates({ query: q, ownerRestriction: OwnerRestriction.Peer }));
});
Expand Down
5 changes: 3 additions & 2 deletions packages/transport/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,10 @@
"@js-soft/ts-utils": "^2.3.3",
"@nmshd/core-types": "*",
"@nmshd/crypto": "2.1.0",
"axios": "^1.7.8",
"axios": "^1.7.9",
"fast-json-patch": "^3.1.1",
"form-data": "^4.0.1",
"https-proxy-agent": "^7.0.5",
"https-proxy-agent": "^7.0.6",
"json-stringify-safe": "^5.0.1",
"lodash": "^4.17.21",
"luxon": "^3.5.0",
Expand All @@ -96,6 +96,7 @@
"@types/uuid": "^10.0.0",
"correlation-id": "^5.2.0",
"expect": "^29.7.0",
"testcontainers": "^10.14.0",
"ts-mockito": "^2.6.1"
},
"publishConfig": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ export class IdentityDeletionProcessController extends TransportController {
return identityDeletionProcess;
}

public async initiateIdentityDeletionProcess(): Promise<IdentityDeletionProcess> {
const identityDeletionProcessResponse = await this.identityDeletionProcessClient.initiateIdentityDeletionProcess();
public async initiateIdentityDeletionProcess(lengthOfGracePeriodInDays?: number): Promise<IdentityDeletionProcess> {
const identityDeletionProcessResponse = await this.identityDeletionProcessClient.initiateIdentityDeletionProcess({ lengthOfGracePeriodInDays });

const identityDeletionProcess = this.createIdentityDeletionProcessFromBackboneResponse(identityDeletionProcessResponse);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export interface BackbonePostIdentityDeletionProcessRequest {
lengthOfGracePeriodInDays?: number;
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { RESTClientAuthenticate, RESTClientLogDirective } from "../../../core";
import { ClientResult } from "../../../core/backbone/ClientResult";
import { BackboneIdentityDeletionProcess } from "./BackboneIdentityDeletionProcess";
import { BackbonePostIdentityDeletionProcessRequest } from "./BackbonePostIdentityDeletionProcess";

export class IdentityDeletionProcessClient extends RESTClientAuthenticate {
protected override _logDirective = RESTClientLogDirective.LogResponse;

public async initiateIdentityDeletionProcess(): Promise<ClientResult<BackboneIdentityDeletionProcess>> {
return await this.post<BackboneIdentityDeletionProcess>("/api/v1/Identities/Self/DeletionProcesses", {});
public async initiateIdentityDeletionProcess(value: BackbonePostIdentityDeletionProcessRequest): Promise<ClientResult<BackboneIdentityDeletionProcess>> {
return await this.post<BackboneIdentityDeletionProcess>("/api/v1/Identities/Self/DeletionProcesses", value);
}

public async getIdentityDeletionProcess(identityDeletionProcessId: string): Promise<ClientResult<BackboneIdentityDeletionProcess>> {
Expand Down
Loading

0 comments on commit b28516f

Please sign in to comment.