Skip to content

Commit

Permalink
feat: integrating error reporting protocol (#289)
Browse files Browse the repository at this point in the history
Signed-off-by: Francisco Javier Ribo Labrador <elribonazo@gmail.com>
  • Loading branch information
elribonazo authored Sep 17, 2024
1 parent f53d728 commit 02430db
Show file tree
Hide file tree
Showing 11 changed files with 169 additions and 7 deletions.
38 changes: 36 additions & 2 deletions demos/next/src/components/Message.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ const InputFields: React.FC<{ fields: SDK.Domain.InputField[]; }> = props => {
</>;
};

function replacePlaceholders(text: string, args: any[]): string {
return text.replace(/\{(\d+)\}/g, (match, index) => {
const idx = parseInt(index) - 1; // Adjust for zero-based array index
return args[idx] !== undefined ? args[idx] : match; // Replace or keep original if undefined
});
}

export function Message({ message }) {
const app = useMountedApp();
Expand Down Expand Up @@ -370,8 +376,36 @@ export function Message({ message }) {
</div>;
}



if (message.piuri === SDK.ProtocolType.ProblemReporting) {
const content = replacePlaceholders(message.body.comment, message.body.args);

return <div className="flex items-center justify-center">
<div className="w-full bg-red-300 border-l-4 border-red-500 text-red-700 p-4 rounded-md shadow-lg my-5 w-full">
<div className="flex">
<svg
className="w-6 h-6 text-red-500 mr-3"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M18.364 5.636l-12.728 12.728M5.636 5.636l12.728 12.728"
></path>
</svg>
<div>
<p className="font-bold">Error {message.id}</p>
</div>
</div>
<div className="mt-5">
<div className="w-full shadow-lg bg-white px-10 py-4 rounded-lg">An error ocurred, {content}, CODE {message.body.code}</div>
</div>
</div>
</div>
}

if (message.piuri === "https://didcomm.atalaprism.io/present-proof/3.0/request-presentation") {
const requestPresentationMessage = SDK.RequestPresentation.fromMessage(message);
Expand Down
5 changes: 5 additions & 0 deletions src/domain/models/errors/Agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,11 @@ export class InvalidPresentationBodyError extends Error {
super(message || "Invalid Presentation body Error");
}
}
export class InvalidProblemReportBodyError extends Error {
constructor(message?: string) {
super(message || "Invalid Problem reporting body Error");
}
}
export class InvalidProposeCredentialBodyError extends Error {
constructor(message?: string) {
super(message || "Invalid Propose CredentialBody Error");
Expand Down
1 change: 0 additions & 1 deletion src/edge-agent/connectionsManager/ConnectionsManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,6 @@ export class ConnectionsManager implements ConnectionsManagerClass {
}
}
}

if (messageIds.length) {
await this.mediationHandler.registerMessagesAsRead(messageIds);
}
Expand Down
15 changes: 14 additions & 1 deletion src/edge-agent/helpers/ProtocolHelpers.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { AttachmentDescriptor, Message } from "../../domain";
import { AgentError } from "../../domain/models/Errors";
import { asArray, isArray, isNil, isObject, isString, notEmptyString, notNil } from "../../utils";
import { asArray, isArray, isEmpty, isNil, isObject, isString, notEmptyString, notNil } from "../../utils";
import { ProtocolType } from "../protocols/ProtocolTypes";
import { CredentialFormat } from "../protocols/issueCredential/CredentialFormat";
import {
Expand All @@ -14,6 +14,7 @@ import {
RequestPresentationBody,
ProposePresentationBody,
BasicMessageBody,
ProblemReportBody,
} from "../protocols/types";

export const parseCredentialAttachments = (credentials: Map<string, any>) => {
Expand Down Expand Up @@ -60,6 +61,18 @@ export const parseBasicMessageBody = (msg: Message): BasicMessageBody => {
throw new AgentError.InvalidBasicMessageBodyError("Invalid content");
};

export const parseProblemReportBody = (msg: Message): ProblemReportBody => {
if (notEmptyString(msg.body.code) &&
notEmptyString(msg.body.comment) &&
notEmptyString(msg.body.escalate_to) &&
isArray(msg.body.args) && isEmpty(msg.body.args)
) {
const { code, comment, escalate_to, args } = msg.body;
return { code, comment, escalate_to, args }
}
throw new AgentError.InvalidProblemReportBodyError()
}

export const parseCredentialBody = (msg: Message): CredentialBody => {
if (Object.keys(msg.body).length === 0) {
throw new AgentError.InvalidCredentialBodyError(
Expand Down
1 change: 0 additions & 1 deletion src/edge-agent/mediator/BasicMediatorHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,6 @@ export class BasicMediatorHandler implements MediatorHandler {
if (!message) {
return [];
}

return new PickupRunner(message, this.mercury).run();
}

Expand Down
3 changes: 2 additions & 1 deletion src/edge-agent/protocols/ProtocolTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ export enum ProtocolType {
PickupStatus = "https://didcomm.org/messagepickup/3.0/status",
PickupReceived = "https://didcomm.org/messagepickup/3.0/messages-received",
LiveDeliveryChange = "https://didcomm.org/messagepickup/3.0/live-delivery-change",
PrismRevocation = "https://atalaprism.io/revocation_notification/1.0/revoke"
PrismRevocation = "https://atalaprism.io/revocation_notification/1.0/revoke",
ProblemReporting = "https://didcomm.org/report-problem/2.0/problem-report"
}

export function findProtocolTypeByValue(string: string): ProtocolType {
Expand Down
50 changes: 50 additions & 0 deletions src/edge-agent/protocols/other/ProblemReport.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { AgentError, DID, Message } from "../../../domain/models";
import { parseProblemReportBody } from "../../helpers/ProtocolHelpers";
import { ProtocolType } from "../ProtocolTypes";
import { ProblemReportBody } from "../types";





export class ProblemReport {
public static type = ProtocolType.ProblemReporting;

constructor(
public body: ProblemReportBody,
public from: DID,
public to: DID,
public thid?: string,
) { }

makeMessage(): Message {
const body = JSON.stringify(this.body);
return new Message(
body,
undefined,
ProblemReport.type,
this.from,
this.to,
[],
this.thid
);
}

static fromMessage(fromMessage: Message): ProblemReport {
if (
fromMessage.piuri !== ProtocolType.DidcommBasicMessage ||
!fromMessage.from ||
!fromMessage.to
) {
throw new AgentError.InvalidBasicMessageBodyError(
"Invalid BasicMessage body error."
);
}
const problemReportBody = parseProblemReportBody(fromMessage);
return new ProblemReport(
problemReportBody,
fromMessage.from,
fromMessage.to
);
}
}
13 changes: 12 additions & 1 deletion src/edge-agent/protocols/pickup/PickupRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import { PickupAttachment } from "../types";

type PickupResponse =
| { type: "status"; message: Message }
| { type: "delivery"; message: Message };
| { type: "delivery"; message: Message }
| { type: 'report', message: Message };

export class PickupRunner {
private message: PickupResponse;
Expand All @@ -20,6 +21,9 @@ export class PickupRunner {
case ProtocolType.PickupDelivery:
this.message = { type: "delivery", message: message };
break;
case ProtocolType.ProblemReporting:
this.message = { type: "report", message: message };
break;
default:
throw new AgentError.InvalidPickupDeliveryMessageError();
}
Expand Down Expand Up @@ -63,6 +67,13 @@ export class PickupRunner {
message: await this.mercury.unpackMessage(attachment.data),
}))
);
} else if (this.message.type === "report") {
return [
{
attachmentId: this.message.message.id,
message: this.message.message
}
]
}

return [];
Expand Down
8 changes: 8 additions & 0 deletions src/edge-agent/protocols/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,14 @@ export interface BasicMessageBody {
content: string;
}


export interface ProblemReportBody {
code: string,
comment: string,
args: string[],
escalate_to: string
}

export interface RequestPresentationBody extends PresentationBody {
willConfirm?: boolean;
proofTypes: ProofTypes[];
Expand Down
21 changes: 21 additions & 0 deletions tests/agent/protocols/pickup/PickupRunner.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,27 @@ describe("PickupRunner Tests", () => {
expect(response).to.be.an("array").with.length(0);
});

test(`${ProtocolType.PickupDelivery} - 1 problem report message`, async () => {
const runner = new PickupRunner(Messages.Reporting, mercury);
const response = await runner.run();
expect(response).to.be.an("array").with.length(1);
expect(response[0].message.ack).to.deep.eq(Messages.Reporting.ack);
expect(response[0].message.attachments).to.deep.eq(Messages.Reporting.attachments);
expect(response[0].message.body).to.deep.eq(Messages.Reporting.body);
expect(response[0].message.createdTime).to.deep.eq(Messages.Reporting.createdTime);
expect(response[0].message.direction).to.deep.eq(Messages.Reporting.direction);
expect(response[0].message.extraHeaders).to.deep.eq(Messages.Reporting.extraHeaders);
expect(response[0].message.from).to.deep.eq(Messages.Reporting.from);
expect(response[0].message.fromPrior).to.deep.eq(Messages.Reporting.fromPrior);
expect(response[0].message.id).to.deep.eq(Messages.Reporting.id);
expect(response[0].message.piuri).to.deep.eq(Messages.Reporting.piuri);
expect(response[0].message.pthid).to.deep.eq(Messages.Reporting.pthid);
expect(response[0].message.thid).to.deep.eq(Messages.Reporting.thid);
expect(response[0].message.to).to.deep.eq(Messages.Reporting.to);
});



test(`${ProtocolType.PickupDelivery} - 1 message`, async () => {
const runner = new PickupRunner(Messages.PickupDelivery, mercury);
const response = await runner.run();
Expand Down
21 changes: 21 additions & 0 deletions tests/fixtures/messages/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { base64 } from "multiformats/bases/base64";
import * as Domain from "../../../src/domain";
import { ProtocolType } from "../../../src/edge-agent/protocols/ProtocolTypes";

// convert raw DIDComm message to domain, handles parsing idiosyncrasies
const convertDidcomm = (value: any) => new Domain.Message(
Expand Down Expand Up @@ -238,3 +239,23 @@ const pickupStatusRaw: any = {
};

export const PickupStatus = convertDidcomm(pickupStatusRaw);


export const Reporting = convertDidcomm({
"id": "033642e4-9064-4da2-ac84-6be20b3ec8b8",
"typ": "application/didcomm-plain+json",
"type": ProtocolType.ProblemReporting,
"body": {
"args": [
'did:peer:2.Ez6LSmEZPCeaFeA1vwBTZeLvXi6F24ZdEQgmzJCqHaQQojBj8.Vz6MktyGjB1ogYgsu3nt9ncjzXM4mBBGJSU5cPrCScDcC2GrN.SW10'
],
"comment": "The DID '{1}' is not enroled",
"code": "e.p.req.not_enroll",
"escalate_to": "email@email.com"
},
"from": "did:peer:2.Ez6LSghwSE437wnDE1pt3X6hVDUQzSjsHzinpX3XFvMjRAm7y.Vz6Mkhh1e5CEYYq6JBUcTZ6Cp2ranCWRrv7Yax3Le4N59R6dd.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHBzOi8vc2l0LXByaXNtLW1lZGlhdG9yLmF0YWxhcHJpc20uaW8iLCJhIjpbImRpZGNvbW0vdjIiXX19.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6IndzczovL3NpdC1wcmlzbS1tZWRpYXRvci5hdGFsYXByaXNtLmlvL3dzIiwiYSI6WyJkaWRjb21tL3YyIl19fQ",
"to": [
"did:peer:2.Ez6LSrjn3NUEgFDY2wKnxbNfbXLozs8Em5RX6xWkTJn3kqpsL.Vz6MkuK1KvyssRGvzYuerJQQaTANA9hAe3dXt2X31d6Ef9xee.SW10"
],
"thid": "dcc4af0e-0a9c-4082-98d1-bbdc582002b7"
})

1 comment on commit 02430db

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lines Statements Branches Functions
Coverage: 77%
78.11% (3430/4391) 67.2% (1508/2244) 81.73% (828/1013)

Please sign in to comment.