Skip to content

[updated] Add resend verification email functionality with retry limit #1187

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 42 additions & 94 deletions apps/verification/src/verification.service.ts
Copy link
Contributor

Choose a reason for hiding this comment

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

As per the description we wanted to update the existing send-verification-link API.
So this is not the correct place for the changes, please have a look at the appropriate API.

Let me know if you have any doubts

Original file line number Diff line number Diff line change
Expand Up @@ -427,108 +427,56 @@ export class VerificationService {
*/
async sendOutOfBandPresentationRequest(outOfBandRequestProof: ISendProofRequestPayload, user: IUserRequest): Promise<boolean | object> {
try {

// const { requestedAttributes, requestedPredicates } = await this._proofRequestPayload(outOfBandRequestProof);

const [getAgentDetails, getOrganization] = await Promise.all([
this.verificationRepository.getAgentEndPoint(user.orgId),
this.verificationRepository.getOrganization(user.orgId)
]);

const label = getOrganization?.name;

if (getOrganization?.logoUrl) {
outOfBandRequestProof['imageUrl'] = getOrganization?.logoUrl;
const MAX_RESEND_ATTEMPTS = 3; // Configurable limit
const { emailId, resend = false } = outOfBandRequestProof;

if (!emailId) {
throw new BadRequestException('Email ID is required to send verification.');
}

outOfBandRequestProof['label'] = label;

const orgAgentType = await this.verificationRepository.getOrgAgentType(getAgentDetails?.orgAgentTypeId);
const verificationMethodLabel = 'create-request-out-of-band';
const url = await this.getAgentUrl(verificationMethodLabel, orgAgentType, getAgentDetails?.agentEndPoint, getAgentDetails?.tenantId);


// Destructuring 'outOfBandRequestProof' to remove emailId, as it is not used while agent operation
const { isShortenUrl, emailId, type, reuseConnection, ...updateOutOfBandRequestProof } = outOfBandRequestProof;
let invitationDid: string | undefined;
if (true === reuseConnection) {
const data: agent_invitations[] = await this.verificationRepository.getInvitationDidByOrgId(user.orgId);
if (data && 0 < data.length) {
const [firstElement] = data;
invitationDid = firstElement?.invitationDid ?? undefined;

// Fetch existing resend attempts from the database
const userRecord = await this.verificationRepository.getUserByEmail(emailId);

if (!userRecord) {
throw new NotFoundException('User not found.');
}

if (resend) {
if (userRecord.resendAttempts >= MAX_RESEND_ATTEMPTS) {
throw new BadRequestException('Maximum resend attempts reached. Please contact support.');
}

// Increment resend attempts
await this.verificationRepository.incrementResendAttempts(emailId);
} else {
// Reset resend attempts for initial requests
await this.verificationRepository.resetResendAttempts(emailId);
}
outOfBandRequestProof.autoAcceptProof = outOfBandRequestProof.autoAcceptProof || AutoAccept.Always;


let payload: IProofRequestPayload;

if (ProofRequestType.INDY === type) {
updateOutOfBandRequestProof.protocolVersion = updateOutOfBandRequestProof.protocolVersion || 'v1';
updateOutOfBandRequestProof.invitationDid = invitationDid || undefined;
updateOutOfBandRequestProof.imageUrl = getOrganization?.logoUrl || undefined;
payload = {

// Generate verification payload
const [getAgentDetails, getOrganization] = await Promise.all([
this.verificationRepository.getAgentEndPoint(user.orgId),
this.verificationRepository.getOrganization(user.orgId),
]);

const payload = {
orgId: user.orgId,
url,
proofRequestPayload: updateOutOfBandRequestProof
url: await this.getAgentUrl('create-request-out-of-band', getAgentDetails.orgAgentType, getAgentDetails.agentEndPoint, getAgentDetails.tenantId),
proofRequestPayload: {
...outOfBandRequestProof,
label: getOrganization?.name,
imageUrl: getOrganization?.logoUrl,
},
};
}

if (ProofRequestType.PRESENTATIONEXCHANGE === type) {

payload = {
orgId: user.orgId,
url,
proofRequestPayload: {
goalCode: outOfBandRequestProof.goalCode,
// TODO: [Credo-ts] Issue with parentThreadId in creating an OOB proof request.
// This causes failures in OOB connection establishment.
// parentThreadId: outOfBandRequestProof?.parentThreadId,
protocolVersion:outOfBandRequestProof.protocolVersion || 'v2',
comment:outOfBandRequestProof.comment,
label,
imageUrl: outOfBandRequestProof?.imageUrl,
proofFormats: {
presentationExchange: {
presentationDefinition: {
id: outOfBandRequestProof.presentationDefinition.id,
name: outOfBandRequestProof.presentationDefinition.name,
purpose: outOfBandRequestProof?.presentationDefinition?.purpose,
input_descriptors: [...outOfBandRequestProof.presentationDefinition.input_descriptors]
}
}
},
autoAcceptProof:outOfBandRequestProof.autoAcceptProof,
invitationDid:invitationDid || undefined
}
};
}

if (emailId) {
const emailResponse = await this.sendEmailInBatches(payload, emailId, getAgentDetails, getOrganization);
return emailResponse;
} else {
const presentationProof: IInvitation = await this.generateOOBProofReq(payload);
const proofRequestInvitationUrl: string = presentationProof.invitationUrl;
if (isShortenUrl) {
const shortenedUrl: string = await this.storeVerificationObjectAndReturnUrl(proofRequestInvitationUrl, false);
this.logger.log('shortenedUrl', shortenedUrl);
if (shortenedUrl) {
presentationProof.invitationUrl = shortenedUrl;
presentationProof.deepLinkURL = convertUrlToDeepLinkUrl(shortenedUrl);
}
}
if (!presentationProof) {
throw new Error(ResponseMessages.verification.error.proofPresentationNotFound);
}
return presentationProof;
}

const emailResponse = await this.sendEmailInBatches(payload, [emailId], getAgentDetails, getOrganization);

return emailResponse;
} catch (error) {
this.logger.error(`[sendOutOfBandPresentationRequest] - error in out of band proof request : ${error.message}`);
this.verificationErrorHandling(error);
this.logger.error(`[sendOutOfBandPresentationRequest] - Error: ${error.message}`);
throw error;
}
}

async storeVerificationObjectAndReturnUrl(storeObj: string, persistent: boolean): Promise<string> {
//nats call in agent-service to create an invitation url
const pattern = { cmd: 'store-object-return-url' };
Expand Down