Solution 1 :
You’re getting the error message in the functions log because you’re trying to call the static function generateSignature
as a method on an object, which is not valid.
Your code is a bit oddly organized. PaytmChecksum
only contains static methods, which means there is no real value in trying to create an instance of it as you are now. If you just want to call static methods on some class, skip the new
entirely, and just call PaytmChecksum.generateSignature()
directly.
Problem :
I am trying to use Firebase Cloud Functions in my android app for the first time. The output I get is an exception with code “INTERNAl” and details “null”.
Below is my cloud function file index.js:
"use strict";
const functions = require('firebase-functions');
// Create and Deploy Your First Cloud Functions
// https://firebase.google.com/docs/functions/write-firebase-functions
var crypto = require('crypto');
class PaytmChecksum {
static encrypt(input, key) {
var cipher = crypto.createCipheriv('AES-128-CBC', key, PaytmChecksum.iv);
var encrypted = cipher.update(input, 'binary', 'base64');
encrypted += cipher.final('base64');
return encrypted;
}
static decrypt(encrypted, key) {
var decipher = crypto.createDecipheriv('AES-128-CBC', key, PaytmChecksum.iv);
var decrypted = decipher.update(encrypted, 'base64', 'binary');
try {
decrypted += decipher.final('binary');
}
catch (e) {
console.log(e);
throw new functions.https.HttpsError('decryption-failed', e);
}
return decrypted;
}
static generateSignature(params, key) {
if (typeof params !== "object" && typeof params !== "string") {
var error = "string or object expected, " + (typeof params) + " given.";
//throw new functions.https.HttpsError('generate-signature-failed', error);
return Promise.reject(error);
}
if (typeof params !== "string"){
params = PaytmChecksum.getStringByParams(params);
}
return PaytmChecksum.generateSignatureByString(params, key);
}
static verifySignature(params, key, checksum) {
if (typeof params !== "object" && typeof params !== "string") {
var error = "string or object expected, " + (typeof params) + " given.";
//throw new functions.https.HttpsError('verify-signature-failed', error);
return Promise.reject(error);
}
if(params.hasOwnProperty("CHECKSUMHASH")){
delete params.CHECKSUMHASH
}
if (typeof params !== "string"){
params = PaytmChecksum.getStringByParams(params);
}
return PaytmChecksum.verifySignatureByString(params, key, checksum);
}
static async generateSignatureByString(params, key) {
var salt = await PaytmChecksum.generateRandomString(4);
return PaytmChecksum.calculateChecksum(params, key, salt);
}
static verifySignatureByString(params, key, checksum) {
var paytm_hash = PaytmChecksum.decrypt(checksum, key);
var salt = paytm_hash.substr(paytm_hash.length - 4);
return (paytm_hash === PaytmChecksum.calculateHash(params, salt));
}
static generateRandomString(length) {
return new Promise((resolve, reject) => {
crypto.randomBytes((length * 3.0) / 4.0, (err, buf) => {
if (!err) {
var salt = buf.toString("base64");
resolve(salt);
}
else {
console.log("error occurred in generateRandomString: " + err);
//throw new functions.https.HttpsError('generate-random-string-error', err);
reject(err);
}
});
});
}
static getStringByParams(params) {
var data = {};
Object.keys(params).sort().forEach((key,value) => {
data[key] = (params[key] !== null && params[key].toLowerCase() !== "null") ? params[key] : "";
});
return Object.values(data).join('|');
}
static calculateHash(params, salt) {
var finalString = params + "|" + salt;
return crypto.createHash('sha256').update(finalString).digest('hex') + salt;
}
static calculateChecksum(params, key, salt) {
var hashString = PaytmChecksum.calculateHash(params, salt);
return PaytmChecksum.encrypt(hashString,key);
}
}
PaytmChecksum.iv = '@@@@&&&&####$$$$';
exports.generateSignature = functions.https.onCall((data, context) => {
// Checking that the user is authenticated.
if (!context.auth) {
// Throwing an HttpsError so that the client gets the error details.
throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' +
'while authenticated.');
}
let paymentChecksum = new PaytmChecksum();
let result = paymentChecksum.generateSignature(data.params, data.key);
return result;
});
This is my activity where I have called the function and handled it’s response:
private void getChecksum(String orderId, String mId) {
Map<String, String> params = new HashMap<>();
params.put("MID", mId);
params.put("ORDERID", orderId);
String key = "000000000000000000";
Task<String> taskData = generateSignature(params, key);
taskData.addOnSuccessListener(this, new OnSuccessListener<String>() {
@Override
public void onSuccess(String s) {
Log.d(TAG, "onSuccess: paytmChecksum" + s);
}
}).addOnFailureListener(this, new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
FirebaseFunctionsException ffe = (FirebaseFunctionsException) e;
FirebaseFunctionsException.Code code = ffe.getCode();
Object details = ffe.getDetails();
Toast.makeText(getApplicationContext(), code + " " + details, Toast.LENGTH_LONG).show();
}
});
}
private Task<String> generateSignature(Map<String, String> params, String merchantKey) {
Map<String, Object> data = new HashMap<>();
data.put("params", params);
data.put("key", merchantKey);
return mFunctions.getHttpsCallable("generateSignature").call(data).continueWith(
task -> (String) task.getResult().getData()
);
}
}
When I run this code, I see a toast showing “INTERNAL null”. Also, in Cloud Functions console log, this is the error:
generateSignature
Unhandled error TypeError: paymentChecksum.generateSignature is not a function
at exports.generateSignature.functions.https.onCall (/srv/index.js:112:34)
at func (/srv/node_modules/firebase-functions/lib/providers/https.js:272:32)
at <anonymous>
at process._tickDomainCallback (internal/process/next_tick.js:229:7)
Why do I get this error? Can anyone please help? I am unable to understand why it says the it is not a function. I checked many samples on internet. Please guide me on how to write correct callable cloud functions. Thanks in advance! 🙂