phonepe #35
							
								
								
									
										24
									
								
								functions/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										24
									
								
								functions/package-lock.json
									
									
									
										generated
									
									
									
								
							| @ -11,14 +11,14 @@ | ||||
|         "@aws-sdk/client-ses": "^3.798.0", | ||||
|         "@types/node-fetch": "^2.6.12", | ||||
|         "aws-sdk": "^2.1692.0", | ||||
|         "axios": "^1.8.4", | ||||
|         "axios": "^1.9.0", | ||||
|         "cors": "^2.8.5", | ||||
|         "firebase-admin": "^12.6.0", | ||||
|         "firebase-functions": "^6.0.1", | ||||
|         "form-data": "^4.0.1", | ||||
|         "functions": "file:", | ||||
|         "html-to-text": "^9.0.5", | ||||
|         "long": "^4.0.0", | ||||
|         "long": "^5.3.2", | ||||
|         "mailgun.js": "^10.4.0", | ||||
|         "node-fetch": "^2.7.0", | ||||
|         "pdfjs-dist": "^5.0.375", | ||||
| @ -1373,12 +1373,6 @@ | ||||
|         "node": ">=6" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@grpc/proto-loader/node_modules/long": { | ||||
|       "version": "5.3.2", | ||||
|       "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", | ||||
|       "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", | ||||
|       "optional": true | ||||
|     }, | ||||
|     "node_modules/@istanbuljs/load-nyc-config": { | ||||
|       "version": "1.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", | ||||
| @ -2755,6 +2749,7 @@ | ||||
|       "integrity": "sha512-eQs9RsucA/LNjnMoJvWG/nXa7Pot/RbBzilF/QRIU/xRl+0ApxrSUFsV5lmf01SvSlqMzJ7Zwxe440wmz2SJGA==", | ||||
|       "deprecated": "This is a stub types definition. long provides its own type definitions, so you do not need this installed.", | ||||
|       "dev": true, | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "long": "*" | ||||
|       } | ||||
| @ -3051,6 +3046,7 @@ | ||||
|       "version": "1.9.0", | ||||
|       "resolved": "https://registry.npmjs.org/axios/-/axios-1.9.0.tgz", | ||||
|       "integrity": "sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "follow-redirects": "^1.15.6", | ||||
|         "form-data": "^4.0.0", | ||||
| @ -6059,9 +6055,10 @@ | ||||
|       "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" | ||||
|     }, | ||||
|     "node_modules/long": { | ||||
|       "version": "4.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", | ||||
|       "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" | ||||
|       "version": "5.3.2", | ||||
|       "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", | ||||
|       "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", | ||||
|       "license": "Apache-2.0" | ||||
|     }, | ||||
|     "node_modules/lru-cache": { | ||||
|       "version": "5.1.1", | ||||
| @ -6687,11 +6684,6 @@ | ||||
|         "node": ">=12.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/protobufjs/node_modules/long": { | ||||
|       "version": "5.3.2", | ||||
|       "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", | ||||
|       "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==" | ||||
|     }, | ||||
|     "node_modules/proxy-addr": { | ||||
|       "version": "2.0.7", | ||||
|       "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", | ||||
|  | ||||
| @ -18,14 +18,14 @@ | ||||
|     "@aws-sdk/client-ses": "^3.798.0", | ||||
|     "@types/node-fetch": "^2.6.12", | ||||
|     "aws-sdk": "^2.1692.0", | ||||
|     "axios": "^1.8.4", | ||||
|     "axios": "^1.9.0", | ||||
|     "cors": "^2.8.5", | ||||
|     "firebase-admin": "^12.6.0", | ||||
|     "firebase-functions": "^6.0.1", | ||||
|     "form-data": "^4.0.1", | ||||
|     "functions": "file:", | ||||
|     "html-to-text": "^9.0.5", | ||||
|     "long": "^4.0.0", | ||||
|     "long": "^5.3.2", | ||||
|     "mailgun.js": "^10.4.0", | ||||
|     "node-fetch": "^2.7.0", | ||||
|     "pdfjs-dist": "^5.0.375", | ||||
|  | ||||
| @ -6,6 +6,7 @@ import { SESClient } from "@aws-sdk/client-ses"; | ||||
| import { SendEmailCommand, SendRawEmailCommand } from "@aws-sdk/client-ses"; | ||||
| import { HttpsError } from "firebase-functions/v2/https"; | ||||
| import * as mime from 'mime-types'; | ||||
| import axios from 'axios'; | ||||
| 
 | ||||
| const logger = getLogger(); | ||||
| const corsHandler = getCorsHandler(); | ||||
| @ -18,6 +19,8 @@ interface EmailRequest { | ||||
|     from: string; | ||||
|     replyTo?: string; | ||||
|     attachments?: Attachment[]; | ||||
|     fileUrl?: string;   | ||||
|     fileName?: string;  | ||||
| } | ||||
| 
 | ||||
| interface Attachment { | ||||
| @ -121,31 +124,71 @@ async function sendEmailWithAttachments(data: EmailRequest, recipients: string[] | ||||
|     return { messageId: result.MessageId }; | ||||
| } | ||||
| 
 | ||||
| async function downloadFileFromUrl(url: string): Promise<Buffer> { | ||||
|     try { | ||||
|         const response = await axios.get(url, { responseType: 'arraybuffer' }); | ||||
|         return Buffer.from(response.data); | ||||
|     } catch (error) { | ||||
|         logger.error(`Error downloading file from URL: ${error}`); | ||||
|         throw new Error(`Failed to download file: ${error}`); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| export const sendEmailSES = onRequest({ | ||||
|     region: 'asia-south1' | ||||
| }, (request: Request, response) => { | ||||
|     return corsHandler(request, response, async () => { | ||||
|         const toAddress = request.body.toAddress; | ||||
|         const subject = request.body.subject; | ||||
|         const message = request.body.message; | ||||
|         const data: EmailRequest = { | ||||
|             to: toAddress, | ||||
|             subject: subject, | ||||
|             html: message, | ||||
|             text: stripHtml(message), | ||||
|             from: process.env.SES_FROM_EMAIL || 'support@fitlien.com', | ||||
|             replyTo: process.env.SES_REPLY_TO_EMAIL || 'support@fitlien.com', | ||||
|             attachments: request.body.attachments as Attachment[] || [] | ||||
|         }; | ||||
|         try { | ||||
|             const toAddress = request.body.toAddress; | ||||
|             const subject = request.body.subject; | ||||
|             const message = request.body.message; | ||||
|              | ||||
|             // Initialize data with basic fields
 | ||||
|             const data: EmailRequest = { | ||||
|                 to: toAddress, | ||||
|                 html: message, | ||||
|                 subject: subject, | ||||
|                 text: stripHtml(message), | ||||
|                 from: process.env.SES_FROM_EMAIL || 'support@fitlien.com', | ||||
|                 replyTo: process.env.SES_REPLY_TO_EMAIL || 'support@fitlien.com', | ||||
|                 attachments: request.body.attachments as Attachment[] || [] | ||||
|             }; | ||||
|              | ||||
|             // Handle file URL if provided
 | ||||
|             if (request.body.fileUrl && request.body.fileName) { | ||||
|                 logger.info(`Downloading attachment from URL: ${request.body.fileUrl}`); | ||||
|                 try { | ||||
|                     const fileContent = await downloadFileFromUrl(request.body.fileUrl); | ||||
|                      | ||||
|                     // If attachments array doesn't exist, create it
 | ||||
|                     if (!data.attachments) { | ||||
|                         data.attachments = []; | ||||
|                     } | ||||
|                      | ||||
|                     // Add the downloaded file as an attachment
 | ||||
|                     data.attachments.push({ | ||||
|                         filename: request.body.fileName, | ||||
|                         content: fileContent, | ||||
|                         contentType: mime.lookup(request.body.fileName) || 'application/octet-stream' | ||||
|                     }); | ||||
|                      | ||||
|                     logger.info(`Successfully downloaded attachment: ${request.body.fileName}`); | ||||
|                 } catch (downloadError) { | ||||
|                     logger.error(`Failed to download attachment: ${downloadError}`); | ||||
|                     throw new Error(`Failed to process attachment: ${downloadError}`); | ||||
|                 } | ||||
|             } | ||||
|              | ||||
|             if (!data.to || !data.subject || !data.html || !data.from) { | ||||
|                 throw new HttpsError( | ||||
|                     'invalid-argument', | ||||
|                     'Missing required email fields' | ||||
|                 ); | ||||
|             } | ||||
|              | ||||
|             logger.info(`Sending Email '${data.subject}' to '${data.to}' from '${data.from}'`); | ||||
|             const recipients = Array.isArray(data.to) ? data.to : [data.to]; | ||||
|              | ||||
|             if (data.attachments && data.attachments.length > 0) { | ||||
|                 const messageResult = await sendEmailWithAttachments(data, recipients); | ||||
|                 response.status(200).json(messageResult); | ||||
|  | ||||
| @ -21,7 +21,7 @@ export const phonePeWebhook = onRequest({ | ||||
|       body: request.body, | ||||
|       method: request.method | ||||
|     }); | ||||
| 
 | ||||
|      | ||||
|     const authHeader = request.headers['authorization'] as string; | ||||
|     const username = process.env.PHONEPE_WEBHOOK_USERNAME; | ||||
|     const password = process.env.PHONEPE_WEBHOOK_PASSWORD; | ||||
| @ -37,7 +37,7 @@ export const phonePeWebhook = onRequest({ | ||||
|       .createHash('sha256') | ||||
|       .update(credentialString) | ||||
|       .digest('hex'); | ||||
| 
 | ||||
|      | ||||
|     const receivedAuth = authHeader.replace(/^SHA256\s+/i, ''); | ||||
| 
 | ||||
|     if (receivedAuth.toLowerCase() !== expectedAuth.toLowerCase()) { | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user