Skip to content

Commit

Permalink
Offer message handler fix (#231)
Browse files Browse the repository at this point in the history
* Offer message handler fix

* remove comment

* 1.14.0
  • Loading branch information
Kolezhniuk authored May 14, 2024
1 parent 3c8c06e commit e31fa28
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 26 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@0xpolygonid/js-sdk",
"version": "1.13.0",
"version": "1.14.0",
"description": "SDK to work with Polygon ID",
"main": "dist/node/cjs/index.js",
"module": "dist/node/esm/index.js",
Expand Down
52 changes: 35 additions & 17 deletions src/iden3comm/handlers/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,16 @@ export class FetchHandler
ctx: FetchMessageHandlerOptions
): Promise<BasicMessage | null> {
switch (message.type) {
case PROTOCOL_MESSAGE_TYPE.CREDENTIAL_OFFER_MESSAGE_TYPE:
await this.handleOfferMessage(message as CredentialsOfferMessage, ctx);
return null;
case PROTOCOL_MESSAGE_TYPE.CREDENTIAL_OFFER_MESSAGE_TYPE: {
const result = await this.handleOfferMessage(message as CredentialsOfferMessage, ctx);
if (Array.isArray(result)) {
const credWallet = this.opts?.credentialWallet;
if (!credWallet) throw new Error('Credential wallet is not provided');
await credWallet.saveAll(result);
return null;
}
return result as BasicMessage;
}
case PROTOCOL_MESSAGE_TYPE.CREDENTIAL_FETCH_REQUEST_MESSAGE_TYPE:
return this.handleFetchRequest(message as CredentialFetchRequestMessage);
case PROTOCOL_MESSAGE_TYPE.CREDENTIAL_ISSUANCE_RESPONSE_MESSAGE_TYPE:
Expand All @@ -128,16 +135,14 @@ export class FetchHandler
headers?: HeadersInit;
packerOptions?: JWSPackerParams;
}
): Promise<W3CCredential[]> {
): Promise<W3CCredential[] | BasicMessage> {
if (!ctx.mediaType) {
ctx.mediaType = MediaType.ZKPMessage;
}

const credentials: W3CCredential[] = [];

for (let index = 0; index < offerMessage.body.credentials.length; index++) {
const credentialInfo = offerMessage.body.credentials[index];

for (const credentialInfo of offerMessage.body.credentials) {
const guid = uuid.v4();
const fetchRequest: MessageFetchRequestMessage = {
id: guid,
Expand Down Expand Up @@ -167,7 +172,6 @@ export class FetchHandler
...packerOpts
})
);
let message: { body: { credential: W3CCredential } };
try {
if (!offerMessage?.body?.url) {
throw new Error(`could not fetch W3C credential, body url is missing`);
Expand All @@ -180,16 +184,24 @@ export class FetchHandler
},
body: token
});
if (resp.status !== 200) {
throw new Error(`could not fetch W3C credential, ${credentialInfo?.id}`);
const arrayBuffer = await resp.arrayBuffer();
if (!arrayBuffer.byteLength) {
throw new Error(`could not fetch , ${credentialInfo?.id}, response is empty`);
}
const { unpackedMessage: message } = await this._packerMgr.unpack(
new Uint8Array(arrayBuffer)
);
if (message.type !== PROTOCOL_MESSAGE_TYPE.CREDENTIAL_ISSUANCE_RESPONSE_MESSAGE_TYPE) {
return message;
}
message = await resp.json();
credentials.push(W3CCredential.fromJSON(message.body.credential));
credentials.push(
W3CCredential.fromJSON((message as CredentialIssuanceMessage).body.credential)
);
} catch (e: unknown) {
throw new Error(
`could not fetch W3C credential, ${credentialInfo?.id}, error: ${
(e as Error).message ?? e
}`
`could not fetch protocol message for credential offer id: , ${
credentialInfo?.id
}, error: ${(e as Error).message ?? e}`
);
}
}
Expand Down Expand Up @@ -219,11 +231,17 @@ export class FetchHandler
PROTOCOL_MESSAGE_TYPE.CREDENTIAL_OFFER_MESSAGE_TYPE
);

return this.handleOfferMessage(offerMessage, {
const result = await this.handleOfferMessage(offerMessage, {
mediaType: opts?.mediaType,
headers: opts?.headers,
packerOptions: opts?.packerOptions
});

if (Array.isArray(result)) {
return result;
}

throw new Error('invalid protocol message response');
}

private async handleFetchRequest(
Expand All @@ -242,7 +260,7 @@ export class FetchHandler

const credId = msgRequest.body?.id;
if (!credId) {
throw new Error('nvalid credential id in fetch request body');
throw new Error('invalid credential id in fetch request body');
}

if (!this.opts?.credentialWallet) {
Expand Down
6 changes: 3 additions & 3 deletions src/iden3comm/types/protocol/credentials.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export type CredentialsOfferMessage = Required<BasicMessage> & {
/** CredentialsOfferMessageBody is struct the represents offer message */
export type CredentialsOfferMessageBody = {
url: string;
credentials: Array<CredentialOffer>;
credentials: CredentialOffer[];
};

/** CredentialsOnchainOfferMessage represent Iden3message for credential onhcain offer message */
Expand All @@ -32,7 +32,7 @@ export type CredentialsOnchainOfferMessage = Required<BasicMessage> & {

/** CredentialsOnchainOfferMessageBody is struct the represents onchain offer message body */
export type CredentialsOnchainOfferMessageBody = {
credentials: Array<CredentialOffer>;
credentials: CredentialOffer[];
transaction_data: ContractInvokeTransactionData;
};

Expand All @@ -44,7 +44,7 @@ export type CredentialOffer = {

/** CredentialIssuanceMessage represent Iden3message for credential issuance */
export type CredentialIssuanceMessage = Required<BasicMessage> & {
body?: IssuanceMessageBody;
body: IssuanceMessageBody;
};

/** IssuanceMessageBody is struct the represents message when credential is issued */
Expand Down
40 changes: 37 additions & 3 deletions tests/handlers/fetch.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {
CredentialsOfferMessage,
FetchHandler,
IFetchHandler,
IPackageManager,
IDataStorage,
IdentityWallet,
Expand All @@ -17,7 +16,8 @@ import {
CredentialIssuanceMessage,
FSCircuitStorage,
ProofService,
CircuitId
CircuitId,
MessageHandler
} from '../../src';

import {
Expand All @@ -41,8 +41,9 @@ describe('fetch', () => {
let credWallet: CredentialWallet;

let dataStorage: IDataStorage;
let fetchHandler: IFetchHandler;
let fetchHandler: FetchHandler;
let packageMgr: IPackageManager;
let msgHandler: MessageHandler;
const agentUrl = 'https://testagent.com/';

const issuanceResponseMock = `{
Expand Down Expand Up @@ -134,6 +135,11 @@ describe('fetch', () => {
fetchHandler = new FetchHandler(packageMgr, {
credentialWallet: credWallet
});

msgHandler = new MessageHandler({
messageHandlers: [fetchHandler],
packageManager: packageMgr
});
});

it('fetch credential issued to genesis did', async () => {
Expand Down Expand Up @@ -252,5 +258,33 @@ describe('fetch', () => {

const cred2 = await credWallet.findById(newId);
expect(cred2).not.to.be.undefined;

const offer: CredentialsOfferMessage = {
id,
typ: PROTOCOL_CONSTANTS.MediaType.PlainMessage,
type: PROTOCOL_CONSTANTS.PROTOCOL_MESSAGE_TYPE.CREDENTIAL_OFFER_MESSAGE_TYPE,
thid: id,
body: {
url: agentUrl,
credentials: [{ id: cred2?.id as string, description: 'kyc age credentials' }]
},
from: issuerDID.string(),
to: userDID.string()
};

const bytes = await packageMgr.packMessage(
PROTOCOL_CONSTANTS.MediaType.PlainMessage,
offer,
{}
);
fetchMock.restore();
fetchMock.spy();
fetchMock.post(agentUrl, issuanceResponseMock);
expect(await credWallet.list()).to.have.length(4);

const response = await msgHandler.handleMessage(bytes, {});
// credential saved after handleing message via msgHandler
expect(response).to.be.null;
expect(await credWallet.list()).to.have.length(5);
});
});

0 comments on commit e31fa28

Please sign in to comment.