UNPKG

@0xpolygonid/js-sdk

Version:
275 lines (273 loc) 12.1 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.FetchHandler = void 0; const constants_1 = require("../constants"); const constants_2 = require("../constants"); const verifiable_1 = require("../../verifiable"); const credentials_1 = require("../../credentials"); const utils_1 = require("../../utils"); const js_jwz_1 = require("@iden3/js-jwz"); const js_iden3_core_1 = require("@iden3/js-iden3-core"); const uuid = __importStar(require("uuid")); const message_handler_1 = require("./message-handler"); const common_1 = require("./common"); /** * * Allows to handle Credential offer protocol message and return fetched credential * * @public * @class FetchHandler * @implements implements IFetchHandler interface */ class FetchHandler extends message_handler_1.AbstractMessageHandler { /** * Constructs a new instance of the FetchHandler class. * * @param _packerMgr The package manager used for packing and unpacking data. * @param opts Optional configuration options for the FetchHandler. * @param opts.credentialWallet The credential wallet used for managing credentials. */ constructor(_packerMgr, opts) { super(); this._packerMgr = _packerMgr; this.opts = opts; } async handle(message, ctx) { switch (message.type) { case constants_2.PROTOCOL_MESSAGE_TYPE.CREDENTIAL_OFFER_MESSAGE_TYPE: { const result = await this.handleOfferMessage(message, 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; } case constants_2.PROTOCOL_MESSAGE_TYPE.CREDENTIAL_FETCH_REQUEST_MESSAGE_TYPE: return this.handleFetchRequest(message); case constants_2.PROTOCOL_MESSAGE_TYPE.CREDENTIAL_ISSUANCE_RESPONSE_MESSAGE_TYPE: return this.handleIssuanceResponseMsg(message); case constants_2.PROTOCOL_MESSAGE_TYPE.CREDENTIAL_ONCHAIN_OFFER_MESSAGE_TYPE: { const result = await this.handleOnchainOfferMessage(message); 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; } default: return super.handle(message, ctx); } } async handleOnchainOfferMessage(offerMessage) { if (!this.opts?.onchainIssuer) { throw new Error('onchain issuer is not provided'); } const credentials = []; for (const credentialInfo of offerMessage.body.credentials) { const issuerDID = js_iden3_core_1.DID.parse(offerMessage.from); const userDID = js_iden3_core_1.DID.parse(offerMessage.to); const credential = await this.opts.onchainIssuer.getCredential(issuerDID, userDID, BigInt(credentialInfo.id)); credentials.push(credential); } return credentials; } async handleOfferMessage(offerMessage, ctx) { if (!ctx.mediaType) { ctx.mediaType = constants_1.MediaType.ZKPMessage; } const credentials = []; for (const credentialInfo of offerMessage.body.credentials) { const guid = uuid.v4(); const fetchRequest = { id: guid, typ: ctx.mediaType, type: constants_2.PROTOCOL_MESSAGE_TYPE.CREDENTIAL_FETCH_REQUEST_MESSAGE_TYPE, thid: offerMessage.thid ?? guid, body: { id: credentialInfo.id }, from: offerMessage.to, to: offerMessage.from }; const msgBytes = utils_1.byteEncoder.encode(JSON.stringify(fetchRequest)); const packerOpts = ctx.mediaType === constants_1.MediaType.SignedMessage ? ctx.packerOptions : { provingMethodAlg: js_jwz_1.proving.provingMethodGroth16AuthV2Instance.methodAlg }; const senderDID = js_iden3_core_1.DID.parse(offerMessage.to); const token = utils_1.byteDecoder.decode(await this._packerMgr.pack(ctx.mediaType, msgBytes, { senderDID, ...packerOpts })); try { if (!offerMessage?.body?.url) { throw new Error(`could not fetch W3C credential, body url is missing`); } const resp = await fetch(offerMessage.body.url, { method: 'post', headers: { 'Content-Type': 'application/x-www-form-urlencoded', ...ctx.headers }, body: token }); 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 !== constants_2.PROTOCOL_MESSAGE_TYPE.CREDENTIAL_ISSUANCE_RESPONSE_MESSAGE_TYPE) { return message; } credentials.push(verifiable_1.W3CCredential.fromJSON(message.body.credential)); } catch (e) { throw new Error(`could not fetch protocol message for credential offer id: , ${credentialInfo?.id}, error: ${e.message ?? e}`); } } return credentials; } /** * Handles only messages with credentials/1.0/offer type * * @param { * offer: Uint8Array; offer - raw offer message * opts * }) options how to fetch credential * @returns `Promise<W3CCredential[]>` */ async handleCredentialOffer(offer, opts) { if (opts?.mediaType === constants_1.MediaType.SignedMessage && !opts.packerOptions) { throw new Error(`jws packer options are required for ${constants_1.MediaType.SignedMessage}`); } const offerMessage = await FetchHandler.unpackMessage(this._packerMgr, offer, constants_2.PROTOCOL_MESSAGE_TYPE.CREDENTIAL_OFFER_MESSAGE_TYPE); if (!opts?.allowExpiredMessages) { (0, common_1.verifyExpiresTime)(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'); } /** * Handles only messages with credentials/1.0/onchain-offer type * @beta */ async handleOnchainOffer(offer) { const offerMessage = await FetchHandler.unpackMessage(this._packerMgr, offer, constants_2.PROTOCOL_MESSAGE_TYPE.CREDENTIAL_ONCHAIN_OFFER_MESSAGE_TYPE); return this.handleOnchainOfferMessage(offerMessage); } async handleFetchRequest(msgRequest) { if (!msgRequest.to) { throw new Error("failed request. empty 'to' field"); } if (!msgRequest.from) { throw new Error("failed request. empty 'from' field"); } const issuerDID = js_iden3_core_1.DID.parse(msgRequest.to); const userDID = js_iden3_core_1.DID.parse(msgRequest.from); const credId = msgRequest.body?.id; if (!credId) { throw new Error('invalid credential id in fetch request body'); } if (!this.opts?.credentialWallet) { throw new Error('please, provide credential wallet in options'); } const cred = await this.opts.credentialWallet.findById(credId); if (!cred) { throw new Error('credential not found'); } const userToVerifyDID = (0, credentials_1.getUserDIDFromCredential)(issuerDID, cred); if (userToVerifyDID.string() !== userDID.string()) { throw new Error('credential subject is not a sender DID'); } return { id: uuid.v4(), type: constants_2.PROTOCOL_MESSAGE_TYPE.CREDENTIAL_ISSUANCE_RESPONSE_MESSAGE_TYPE, typ: msgRequest.typ ?? constants_1.MediaType.PlainMessage, thid: msgRequest.thid ?? uuid.v4(), body: { credential: cred }, from: msgRequest.to, to: msgRequest.from }; } /** * @inheritdoc IFetchHandler#handleCredentialFetchRequest */ async handleCredentialFetchRequest(envelope, opts) { const msgRequest = await FetchHandler.unpackMessage(this._packerMgr, envelope, constants_2.PROTOCOL_MESSAGE_TYPE.CREDENTIAL_FETCH_REQUEST_MESSAGE_TYPE); if (!opts?.allowExpiredMessages) { (0, common_1.verifyExpiresTime)(msgRequest); } const request = await this.handleFetchRequest(msgRequest); return this._packerMgr.pack(constants_1.MediaType.PlainMessage, utils_1.byteEncoder.encode(JSON.stringify(request)), {}); } async handleIssuanceResponseMsg(issuanceMsg) { if (!this.opts?.credentialWallet) { throw new Error('please provide credential wallet in options'); } if (!issuanceMsg.body?.credential) { throw new Error('credential is missing in issuance response message'); } await this.opts.credentialWallet.save(verifiable_1.W3CCredential.fromJSON(issuanceMsg.body.credential)); return null; } /** * @inheritdoc IFetchHandler#handleIssuanceResponseMessage */ async handleIssuanceResponseMessage(envelop, opts) { const issuanceMsg = await FetchHandler.unpackMessage(this._packerMgr, envelop, constants_2.PROTOCOL_MESSAGE_TYPE.CREDENTIAL_ISSUANCE_RESPONSE_MESSAGE_TYPE); if (!opts?.allowExpiredMessages) { (0, common_1.verifyExpiresTime)(issuanceMsg); } await this.handleIssuanceResponseMsg(issuanceMsg); return Uint8Array.from([]); } /** * @inheritdoc IFetchHandler#unpackMessage */ static async unpackMessage(packerMgr, envelope, messageType) { const { unpackedMessage: message } = await packerMgr.unpack(envelope); const msgRequest = message; if (message.type !== messageType) { throw new Error('Invalid message type'); } return msgRequest; } } exports.FetchHandler = FetchHandler;