Skip to content

Commit 33f1c2f

Browse files
authored
feat: creating oob offers for credential issuance (#428)
1 parent 37f2711 commit 33f1c2f

File tree

3 files changed

+118
-2
lines changed

3 files changed

+118
-2
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
2+
import { uuid } from "@stablelib/uuid";
3+
import * as Domain from "../../domain";
4+
import { Task } from "../../utils/tasks";
5+
import { OfferCredential, OutOfBandInvitation } from "../../plugins/internal/didcomm";
6+
import { AgentContext } from "../Context";
7+
8+
/**
9+
* Asyncronously create and store a new peer did
10+
*
11+
* @async
12+
* @param {Service[]} services
13+
* @param {boolean} [updateMediator=false]
14+
* @returns {Promise<DID>}
15+
*/
16+
17+
interface Args {
18+
baseUrl?: string,
19+
from: Domain.DID,
20+
goalCode?: string,
21+
goal?: string,
22+
accept?: string[],
23+
offer: OfferCredential
24+
}
25+
26+
export class CreateOOBOffer extends Task<string, Args> {
27+
28+
get oobBody() {
29+
return {
30+
goal_code: this.args.goalCode ?? "issue-vc",
31+
goal: this.args.goal ?? "Issue Credential",
32+
accept: this.args.accept ?? ["didcomm/v2"],
33+
}
34+
}
35+
36+
get attachments() {
37+
return [
38+
new Domain.AttachmentDescriptor(
39+
{
40+
json: this.args.offer.makeMessage()
41+
},
42+
"application/json",
43+
)
44+
];
45+
}
46+
47+
async run(_ctx: AgentContext): Promise<string> {
48+
if (!this.args.offer || !(this.args.offer instanceof OfferCredential)) {
49+
throw new Error("Invalid offer");
50+
}
51+
const oobId = uuid();
52+
const oob = new OutOfBandInvitation(
53+
this.oobBody,
54+
this.args.from.toString(),
55+
oobId,
56+
this.attachments
57+
);
58+
return Buffer.from(JSON.stringify(oob)).toString("base64")
59+
}
60+
}

src/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ export { HandshakeRequest } from './plugins/internal/oea/protocols/HandshakeRequ
6464

6565
// Tasks
6666
import { CreatePrismDID } from "./edge-agent/didFunctions";
67+
import { PKInstance } from "./pollux/utils/jwt/PKInstance";
68+
import { CreateOOBOffer } from './edge-agent/didcomm/CreateOOBOffer';
6769
export const Tasks = {
68-
CreatePrismDID
70+
CreatePrismDID,
71+
PKInstance,
72+
CreateOOBOffer
6973
};

tests/agent/didcomm/invitation.test.ts

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@ import { vi, describe, it, expect, test, beforeEach, afterEach } from 'vitest';
22
import UUIDLib from "@stablelib/uuid";
33
import Agent from "../../../src/edge-agent/Agent";
44
import { AttachmentDescriptor, DID, MessageDirection, Seed } from "../../../src/domain";
5-
import { HandshakeRequest, OutOfBandInvitation, ProtocolType } from "../../../src";
5+
import { HandshakeRequest, OfferCredential, OutOfBandInvitation, ProtocolType } from "../../../src";
66
import { InvitationIsInvalidError } from "../../../src/domain/models/errors/Agent";
77
import { mockPluto } from "../../fixtures/inmemory/factory";
88
import { mockTask } from "../../testFns";
99
import { StartMediator } from '../../../src/edge-agent/didcomm/StartMediator';
1010
import { StartFetchingMessages } from '../../../src/edge-agent/didcomm/StartFetchingMessages';
1111
import { MediatorConnection } from '../../../src/plugins/internal/didcomm';
12+
import { CreateOOBOffer } from '../../../src/edge-agent/didcomm/CreateOOBOffer';
1213

1314
describe("Agent", () => {
1415
let agent: Agent;
@@ -64,6 +65,57 @@ describe("Agent", () => {
6465

6566
const encodeB64 = (value: any) => Buffer.from(JSON.stringify(value)).toString("base64");
6667

68+
it("Should issue an oob invitation with a credential offer attachment", async () => {
69+
const task = new CreateOOBOffer({
70+
from: DID.fromString("did:peer:2.Ez6LSghwSE437wnDE1pt3X6hVDUQzSjsHzinpX3XFvMjRAm7y.Vz6Mkhh1e5CEYYq6JBUcTZ6Cp2ranCWRrv7Yax3Le4N59R6dd.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly8xOTIuMTY4LjEuNDQ6ODA4MCIsImEiOlsiZGlkY29tbS92MiJdfX0.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6IndzOi8vMTkyLjE2OC4xLjQ0OjgwODAvd3MiLCJhIjpbImRpZGNvbW0vdjIiXX19"),
71+
offer: new OfferCredential(
72+
{
73+
goal_code: "Offer Credential",
74+
credential_preview: {
75+
type: "https://didcomm.org/issue-credential/3.0/credential-credential",
76+
body: {
77+
attributes: [{ name: "familyName", value: "Wonderland" }],
78+
},
79+
},
80+
},
81+
[
82+
new AttachmentDescriptor(
83+
{
84+
json: {
85+
id: "8404678b-9a36-4989-af1d-0f445347e0e3",
86+
media_type: "application/json",
87+
data: {
88+
json: {
89+
options: {
90+
challenge: "ad0f43ad-8538-41d4-9cb8-20967bc685bc",
91+
domain: "domain",
92+
},
93+
presentation_definition: {
94+
id: "748efa58-2bce-440d-921f-2520a8446663",
95+
input_descriptors: [],
96+
format: {
97+
jwt: {
98+
alg: ["ES256K"],
99+
proof_type: [],
100+
},
101+
},
102+
},
103+
},
104+
},
105+
format: "prism/jwt",
106+
},
107+
},
108+
"application/json",
109+
)
110+
]
111+
),
112+
});
113+
const oob = await agent.runTask(task);
114+
const url = `https://my.domain.com/path?_oob=${oob}`;
115+
const result = await agent.parseInvitation(url);
116+
expect(result).to.be.instanceOf(OutOfBandInvitation);
117+
});
118+
67119
it("invitation - returns OutOfBandInvitation", async () => {
68120
const oob = makeOOB();
69121
const url = `https://my.domain.com/path?_oob=${encodeB64(oob)}`;

0 commit comments

Comments
 (0)