Skip to content

Commit

Permalink
allowExpiredMessages
Browse files Browse the repository at this point in the history
  • Loading branch information
volodymyr-basiuk committed Nov 22, 2024
1 parent 5ef322f commit c0a0bbc
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 24 deletions.
11 changes: 8 additions & 3 deletions src/iden3comm/handlers/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ export function createAuthorizationRequestWithMessage(
export type AuthResponseHandlerOptions = StateVerificationOpts & {
// acceptedProofGenerationDelay is the period of time in milliseconds that a generated proof remains valid.
acceptedProofGenerationDelay?: number;
allowExpiredMessages?: boolean;
};

/**
Expand Down Expand Up @@ -173,6 +174,7 @@ export type AuthMessageHandlerOptions = AuthReqOptions | AuthRespOptions;
export interface AuthHandlerOptions {
mediaType: MediaType;
packerOptions?: JWSPackerParams;
allowExpiredMessages?: boolean;
}

/**
Expand Down Expand Up @@ -244,7 +246,6 @@ export class AuthHandler
if (authRequest.type !== PROTOCOL_MESSAGE_TYPE.AUTHORIZATION_REQUEST_MESSAGE_TYPE) {
throw new Error('Invalid message type for authorization request');
}
verifyExpiresTime(authRequest);
// override sender did if it's explicitly specified in the auth request
const to = authRequest.to ? DID.parse(authRequest.to) : ctx.senderDid;
const guid = uuid.v4();
Expand Down Expand Up @@ -296,7 +297,9 @@ export class AuthHandler
authResponse: AuthorizationResponseMessage;
}> {
const authRequest = await this.parseAuthorizationRequest(request);

if (!opts?.allowExpiredMessages) {
verifyExpiresTime(authRequest);
}
if (!opts) {
opts = {
mediaType: MediaType.ZKPMessage
Expand Down Expand Up @@ -336,7 +339,6 @@ export class AuthHandler
ctx: AuthRespOptions
): Promise<BasicMessage | null> {
const request = ctx.request;
verifyExpiresTime(response);
if (response.type !== PROTOCOL_MESSAGE_TYPE.AUTHORIZATION_RESPONSE_MESSAGE_TYPE) {
throw new Error('Invalid message type for authorization response');
}
Expand Down Expand Up @@ -430,6 +432,9 @@ export class AuthHandler
request: AuthorizationRequestMessage;
response: AuthorizationResponseMessage;
}> {
if (!opts?.allowExpiredMessages) {
verifyExpiresTime(response);
}
const authResp = (await this.handleAuthResponse(response, {
request,
acceptedStateTransitionDelay: opts?.acceptedStateTransitionDelay,
Expand Down
6 changes: 4 additions & 2 deletions src/iden3comm/handlers/contract-request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export interface IContractRequestHandler {
export type ContractInvokeHandlerOptions = {
ethSigner: Signer;
challenge?: bigint;
allowExpiredMessages?: boolean;
};

export type ContractMessageHandlerOptions = {
Expand Down Expand Up @@ -105,7 +106,6 @@ export class ContractRequestHandler
message: ContractInvokeRequest,
ctx: ContractMessageHandlerOptions
): Promise<Map<string, ZeroKnowledgeProofResponse[]>> {
verifyExpiresTime(message);
if (message.type !== PROTOCOL_MESSAGE_TYPE.CONTRACT_INVOKE_REQUEST_MESSAGE_TYPE) {
throw new Error('Invalid message type for contract invoke request');
}
Expand Down Expand Up @@ -224,7 +224,9 @@ export class ContractRequestHandler
opts: ContractInvokeHandlerOptions
): Promise<Map<string, ZeroKnowledgeProofResponse>> {
const ciRequest = await this.parseContractInvokeRequest(request);
verifyExpiresTime(ciRequest);
if (!opts.allowExpiredMessages) {
verifyExpiresTime(ciRequest);
}
if (ciRequest.body.transaction_data.method_id !== FunctionSignatures.SubmitZKPResponseV1) {
throw new Error(`please use handle method to work with other method ids`);
}
Expand Down
13 changes: 10 additions & 3 deletions src/iden3comm/handlers/credential-proposal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,11 +132,14 @@ export interface ICredentialProposalHandler {
}

/** @beta ProposalRequestHandlerOptions represents proposal-request handler options */
export type ProposalRequestHandlerOptions = object;
export type ProposalRequestHandlerOptions = {
allowExpiredMessages?: boolean;
};

/** @beta ProposalHandlerOptions represents proposal handler options */
export type ProposalHandlerOptions = {
proposalRequest?: ProposalRequestMessage;
allowExpiredMessages?: boolean;
};

/** @beta CredentialProposalHandlerParams represents credential proposal handler params */
Expand Down Expand Up @@ -205,7 +208,6 @@ export class CredentialProposalHandler
// eslint-disable-next-line @typescript-eslint/no-unused-vars
ctx?: ProposalRequestHandlerOptions
): Promise<ProposalMessage | CredentialsOfferMessage | undefined> {
verifyExpiresTime(proposalRequest);
if (!proposalRequest.to) {
throw new Error(`failed request. empty 'to' field`);
}
Expand Down Expand Up @@ -314,7 +316,9 @@ export class CredentialProposalHandler
if (!proposalRequest.from) {
throw new Error(`failed request. empty 'from' field`);
}
verifyExpiresTime(proposalRequest);
if (!opts?.allowExpiredMessages) {
verifyExpiresTime(proposalRequest);
}

const senderDID = DID.parse(proposalRequest.from);
const message = await this.handleProposalRequestMessage(proposalRequest);
Expand All @@ -337,6 +341,9 @@ export class CredentialProposalHandler
* @inheritdoc ICredentialProposalHandler#handleProposal
*/
async handleProposal(proposal: ProposalMessage, opts?: ProposalHandlerOptions) {
if (!opts?.allowExpiredMessages) {
verifyExpiresTime(proposal);
}
if (opts?.proposalRequest && opts.proposalRequest.from !== proposal.to) {
throw new Error(
`sender of the request is not a target of response - expected ${opts.proposalRequest.from}, given ${proposal.to}`
Expand Down
59 changes: 48 additions & 11 deletions src/iden3comm/handlers/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,29 @@ export type FetchHandlerOptions = {
headers?: {
[key: string]: string;
};
allowExpiredMessages?: boolean;
};

/**
*
* Options to pass to fetch request handler
*
* @public
* @interface FetchRequestOptions
*/
export type FetchRequestOptions = {
allowExpiredMessages?: boolean;
};

/**
*
* Options to pass to issuance response handler
*
* @public
* @interface IssuanceResponseOptions
*/
export type IssuanceResponseOptions = {
allowExpiredMessages?: boolean;
};

export type FetchMessageHandlerOptions = FetchHandlerOptions;
Expand Down Expand Up @@ -65,7 +88,10 @@ export interface IFetchHandler {
* @returns A promise that resolves to the response message.
* @throws An error if the request is invalid or if the credential is not found.
*/
handleCredentialFetchRequest(basicMessage: Uint8Array): Promise<Uint8Array>;
handleCredentialFetchRequest(
basicMessage: Uint8Array,
opts?: FetchRequestOptions
): Promise<Uint8Array>;

/**
* Handles the issuance response message.
Expand All @@ -74,7 +100,10 @@ export interface IFetchHandler {
* @returns A promise that resolves to a Uint8Array.
* @throws An error if the credential wallet is not provided in the options or if the credential is missing in the issuance response message.
*/
handleIssuanceResponseMessage(basicMessage: Uint8Array): Promise<Uint8Array>;
handleIssuanceResponseMessage(
basicMessage: Uint8Array,
opts?: IssuanceResponseOptions
): Promise<Uint8Array>;
}
/**
*
Expand Down Expand Up @@ -137,7 +166,6 @@ export class FetchHandler
packerOptions?: JWSPackerParams;
}
): Promise<W3CCredential[] | BasicMessage> {
verifyExpiresTime(offerMessage);
if (!ctx.mediaType) {
ctx.mediaType = MediaType.ZKPMessage;
}
Expand Down Expand Up @@ -232,7 +260,9 @@ export class FetchHandler
offer,
PROTOCOL_MESSAGE_TYPE.CREDENTIAL_OFFER_MESSAGE_TYPE
);

if (!opts?.allowExpiredMessages) {
verifyExpiresTime(offerMessage);
}
const result = await this.handleOfferMessage(offerMessage, {
mediaType: opts?.mediaType,
headers: opts?.headers,
Expand All @@ -249,7 +279,6 @@ export class FetchHandler
private async handleFetchRequest(
msgRequest: CredentialFetchRequestMessage
): Promise<CredentialIssuanceMessage> {
verifyExpiresTime(msgRequest);
if (!msgRequest.to) {
throw new Error("failed request. empty 'to' field");
}
Expand Down Expand Up @@ -295,13 +324,18 @@ export class FetchHandler
/**
* @inheritdoc IFetchHandler#handleCredentialFetchRequest
*/
async handleCredentialFetchRequest(envelope: Uint8Array): Promise<Uint8Array> {
async handleCredentialFetchRequest(
envelope: Uint8Array,
opts?: FetchRequestOptions
): Promise<Uint8Array> {
const msgRequest = await FetchHandler.unpackMessage<CredentialFetchRequestMessage>(
this._packerMgr,
envelope,
PROTOCOL_MESSAGE_TYPE.CREDENTIAL_FETCH_REQUEST_MESSAGE_TYPE
);

if (!opts?.allowExpiredMessages) {
verifyExpiresTime(msgRequest);
}
const request = await this.handleFetchRequest(msgRequest);

return this._packerMgr.pack(
Expand All @@ -312,7 +346,6 @@ export class FetchHandler
}

private async handleIssuanceResponseMsg(issuanceMsg: CredentialIssuanceMessage): Promise<null> {
verifyExpiresTime(issuanceMsg);
if (!this.opts?.credentialWallet) {
throw new Error('please provide credential wallet in options');
}
Expand All @@ -329,15 +362,19 @@ export class FetchHandler
/**
* @inheritdoc IFetchHandler#handleIssuanceResponseMessage
*/
async handleIssuanceResponseMessage(envelop: Uint8Array): Promise<Uint8Array> {
async handleIssuanceResponseMessage(
envelop: Uint8Array,
opts?: IssuanceResponseOptions
): Promise<Uint8Array> {
const issuanceMsg = await FetchHandler.unpackMessage<CredentialIssuanceMessage>(
this._packerMgr,
envelop,
PROTOCOL_MESSAGE_TYPE.CREDENTIAL_ISSUANCE_RESPONSE_MESSAGE_TYPE
);

if (!opts?.allowExpiredMessages) {
verifyExpiresTime(issuanceMsg);
}
await this.handleIssuanceResponseMsg(issuanceMsg);

return Uint8Array.from([]);
}

Expand Down
4 changes: 4 additions & 0 deletions src/iden3comm/handlers/message-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { PaymentHandlerOptions, PaymentRequestMessageHandlerOptions } from './pa
import { MediaType } from '../constants';
import { proving } from '@iden3/js-jwz';
import { DID } from '@iden3/js-iden3-core';
import { verifyExpiresTime } from './common';
/**
* iden3 Protocol message handler interface
*/
Expand Down Expand Up @@ -41,6 +42,9 @@ export abstract class AbstractMessageHandler implements IProtocolMessageHandler
message: BasicMessage,
context: { [key: string]: unknown }
): Promise<BasicMessage | null> {
if (!context.allowExpiredMessages) {
verifyExpiresTime(message);
}
if (this.nextMessageHandler) return this.nextMessageHandler.handle(message, context);
return Promise.reject('Message handler not provided or message not supported');
}
Expand Down
11 changes: 8 additions & 3 deletions src/iden3comm/handlers/payment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,12 +235,14 @@ export type PaymentRequestMessageHandlerOptions = {
*/
nonce: string;
erc20TokenApproveHandler?: (data: Iden3PaymentRailsERC20RequestV1) => Promise<string>;
allowExpiredMessages?: boolean;
};

/** @beta PaymentHandlerOptions represents payment handler options */
export type PaymentHandlerOptions = {
paymentRequest: PaymentRequestMessage;
paymentValidationHandler: (txId: string, data: PaymentRequestTypeUnion) => Promise<void>;
allowExpiredMessages?: boolean;
};

/** @beta PaymentHandlerParams represents payment handler params */
Expand Down Expand Up @@ -313,7 +315,6 @@ export class PaymentHandler
paymentRequest: PaymentRequestMessage,
ctx: PaymentRequestMessageHandlerOptions
): Promise<BasicMessage | null> {
verifyExpiresTime(paymentRequest);
if (!paymentRequest.to) {
throw new Error(`failed request. empty 'to' field`);
}
Expand Down Expand Up @@ -412,7 +413,9 @@ export class PaymentHandler
if (!paymentRequest.to) {
throw new Error(`failed request. empty 'to' field`);
}

if (!opts?.allowExpiredMessages) {
verifyExpiresTime(paymentRequest);
}
const agentMessage = await this.handlePaymentRequestMessage(paymentRequest, opts);
if (!agentMessage) {
return null;
Expand All @@ -426,7 +429,9 @@ export class PaymentHandler
* @inheritdoc IPaymentHandler#handlePayment
*/
async handlePayment(payment: PaymentMessage, params: PaymentHandlerOptions) {
verifyExpiresTime(payment);
if (!params?.allowExpiredMessages) {
verifyExpiresTime(payment);
}
if (params.paymentRequest.from !== payment.to) {
throw new Error(
`sender of the request is not a target of response - expected ${params.paymentRequest.from}, given ${payment.to}`
Expand Down
6 changes: 4 additions & 2 deletions src/iden3comm/handlers/revocation-status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export type RevocationStatusHandlerOptions = {
mediaType: MediaType;
packerOptions?: JWSPackerParams;
treeState?: TreeState;
allowExpiredMessages?: boolean;
};

/**
Expand Down Expand Up @@ -118,7 +119,6 @@ export class RevocationStatusHandler
rsRequest: RevocationStatusRequestMessage,
context: RevocationStatusMessageHandlerOptions
): Promise<BasicMessage | null> {
verifyExpiresTime(rsRequest);
if (!rsRequest.to) {
throw new Error(`failed request. empty 'to' field`);
}
Expand Down Expand Up @@ -195,7 +195,9 @@ export class RevocationStatusHandler
}

const rsRequest = await this.parseRevocationStatusRequest(request);

if (!opts.allowExpiredMessages) {
verifyExpiresTime(rsRequest);
}
const response = await this.handleRevocationStatusRequestMessage(rsRequest, {
senderDid: did,
mediaType: opts.mediaType,
Expand Down

0 comments on commit c0a0bbc

Please sign in to comment.