Skip to main content
Glama
cashgram-auth.ts7.49 kB
import { httpClient, HttpMethod } from '@activepieces/pieces-common'; import * as crypto from 'crypto'; export interface CashgramAuthCredentials { clientId: string; clientSecret: string; publicKey: string; } export interface CashgramTokenResponse { success: boolean; token?: string; error?: any; message?: string; } /** * Generate x-cf-signature using client ID and public key * Based on Cashfree's Java implementation: RSA/ECB/OAEPWithSHA-1AndMGF1Padding */ export function generateCfSignature(clientId: string, publicKey: string): { signature: string, timestamp: number } { try { const timestamp = Math.floor(Date.now() / 1000); // Current UNIX timestamp const data = `${clientId}.${timestamp}`; // Parse the public key exactly like the Java code let publicKeyContent = (publicKey).trim(); // Remove all whitespace and header/footer like Java code publicKeyContent = publicKeyContent .replace(/[\t\n\r]/g, '') // Remove tabs, newlines, carriage returns .replace('-----BEGIN PUBLIC KEY-----', '') .replace('-----END PUBLIC KEY-----', ''); console.log(`Cleaned public key content length: ${publicKeyContent.length}`); // Convert to DER format (what the Java X509EncodedKeySpec expects) const keyBuffer = Buffer.from(publicKeyContent, 'base64'); // Create the key object for Node.js crypto // Node.js crypto.publicEncrypt with OAEP padding matches Java's RSA/ECB/OAEPWithSHA-1AndMGF1Padding const keyObject = { key: Buffer.concat([ Buffer.from('-----BEGIN PUBLIC KEY-----\n'), Buffer.from(publicKeyContent.match(/.{1,64}/g)?.join('\n') || publicKeyContent), Buffer.from('\n-----END PUBLIC KEY-----') ]).toString(), padding: crypto.constants.RSA_PKCS1_OAEP_PADDING, // This matches OAEP padding in Java oaepHash: 'sha1' // This matches SHA-1 in Java }; // Encrypt the data (this matches cipher.doFinal() in Java) const dataBuffer = Buffer.from(data, 'utf8'); const encrypted = crypto.publicEncrypt(keyObject, dataBuffer); // Base64 encode the result (matches Base64.getEncoder().encodeToString() in Java) const signature = encrypted.toString('base64'); console.log(`Generated signature for data: ${data}`); console.log(`Signature: ${signature}`); console.log(`Signature length: ${signature.length}`); return { signature, timestamp }; } catch (error) { if (error instanceof Error) { console.error(`Error generating signature: ${error.message}`); console.error(`Public key format check - starts with BEGIN: ${publicKey.includes('BEGIN')}`); console.error(`Public key length: ${publicKey.length}`); throw new Error(`Failed to generate signature: ${error.message}. Please verify your public key is in proper PEM format.`); } else { console.error("Error generating signature: Unknown error"); throw new Error("Failed to generate signature: Unknown error. Please verify your public key is in proper PEM format."); } } } /** * Generate bearer token for Cashgram operations using client credentials and public key * * This implementation uses crypto to generate the proper x-cf-signature. */ export async function generateCashgramToken( credentials: CashgramAuthCredentials, environment: 'sandbox' | 'production' ): Promise<CashgramTokenResponse> { try { const baseUrl = environment === 'production' ? 'https://payout-api.cashfree.com/payout/v1/authorize' : 'https://payout-gamma.cashfree.com/payout/v1/authorize'; // Generate x-cf-signature using crypto // let signature: string; // let timestamp: number; // try { // const sigResult = generateCfSignature(credentials.clientId, credentials.publicKey); // signature = sigResult.signature; // timestamp = sigResult.timestamp; // } catch (signatureError: any) { // console.error('Signature generation error:', signatureError); // return { // success: false, // error: signatureError, // message: `Failed to generate x-cf-signature: ${signatureError?.message || 'Unknown error'}. Please check your public key format.`, // }; // } // Build headers with the generated signature and timestamp const headers = { 'x-client-id': credentials.clientId, 'x-client-secret': credentials.clientSecret, // 'x-cf-signature': signature, // 'x-cf-timestamp': timestamp.toString(), 'Content-Type': 'application/json', }; const response = await httpClient.sendRequest({ method: HttpMethod.POST, url: baseUrl, headers: headers, body: {}, }); if (response.status === 200 && response.body?.data?.token) { return { success: true, token: response.body.data.token, message: 'Bearer token generated successfully', }; } else { return { success: false, error: response.body, message: `Failed to generate bearer token. Status: ${response.status}. Response: ${JSON.stringify(response.body)}`, }; } } catch (error) { console.error('Error generating Cashgram token:', error); return { success: false, error: error, message: 'An error occurred while generating the bearer token', }; } } /** * Validate authentication credentials based on auth type */ export function validateAuthCredentials(authType: string, credentials: { clientId?: string; clientSecret?: string; publicKey?: string; }): { isValid: boolean; error?: string; } { if (authType === 'client_credentials') { if (!credentials.clientId || (credentials.clientId).trim().length === 0) { return { isValid: false, error: 'Client ID is required for Client Credentials authentication', }; } if (!credentials.clientSecret || (credentials.clientSecret).trim().length === 0) { return { isValid: false, error: 'Client Secret is required for Client Credentials authentication', }; } } else if (authType === 'client_credentials_with_public_key') { if (!credentials.clientId || (credentials.clientId).trim().length === 0) { return { isValid: false, error: 'Client ID is required for Client Credentials + Public Key authentication', }; } if (!credentials.clientSecret || (credentials.clientSecret).trim().length === 0) { return { isValid: false, error: 'Client Secret is required for Client Credentials + Public Key authentication', }; } if (!credentials.publicKey || (credentials.publicKey).trim().length === 0) { return { isValid: false, error: 'Public Key is required for Client Credentials + Public Key authentication', }; } // // Basic validation for PEM format // if (!credentials.publicKey.includes('-----BEGIN') || !credentials.publicKey.includes('-----END')) { // return { // isValid: false, // error: 'Public Key must be in PEM format (including BEGIN/END markers)', // }; // } } return { isValid: true, }; } /** * Legacy function for backward compatibility * @deprecated Use validateAuthCredentials instead */ export function validateCashgramCredentials(credentials: CashgramAuthCredentials): { isValid: boolean; error?: string; } { return validateAuthCredentials('client_credentials_with_public_key', credentials); }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/activepieces/activepieces'

If you have feedback or need assistance with the MCP directory API, please join our Discord server