Skip to content

Commit

Permalink
Issue with Network Tokenization is fixed.
Browse files Browse the repository at this point in the history
  • Loading branch information
GayatriSasanam committed Aug 12, 2024
1 parent 0ae2332 commit b4e5e18
Showing 1 changed file with 126 additions and 113 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,140 +15,153 @@ var cybersourceRestApi = require('../apiClient/index');

var instance;

server.use('tokenUpdate', function (req, res, next) {
if (req.httpMethod === 'POST') {
var digitalSignature = req.httpHeaders.get('v-c-signature');
var payload = JSON.parse(req.body);
var organizationId = payload.payload[0].organizationId;
var message = JSON.stringify(payload.payload[0]);
server.use('tokenUpdate', function (req, res, next) {
if (configObject.networkTokenizationEnabled && req.httpMethod === 'POST') {
var digitalSignature = req.httpHeaders.get('v-c-signature');
var payload = JSON.parse(req.body);
var organizationId = payload.payload[0].organizationId;
var message = JSON.stringify(payload.payload);

if (validator(digitalSignature, message, organizationId)) {
var webhookId = payload.webhookId;
var data = payload.payload[0].data._links;
var instrumentIdentifierLink = data.instrumentIdentifiers[0].href;
var instrumentIdentifier = instrumentIdentifierLink.substring(instrumentIdentifierLink.lastIndexOf('/') + 1);
var customerLink = data.customers[0].href;
var customerId = customerLink.substring(customerLink.lastIndexOf('/') + 1);
var paymentInstrument;
if (data.paymentInstruments) {
var paymentInstrumentLink = data.paymentInstruments[0].href;
paymentInstrument = paymentInstrumentLink.substring(paymentInstrumentLink.lastIndexOf('/') + 1);
}

instance = new cybersourceRestApi.InstrumentIdentifierApi(configObject);
var cardData; var cardNumber; var state;
try { // eslint-disable-line no-useless-catch
instance.getInstrumentIdentifier(instrumentIdentifier, configObject.profileId, function (data, error, response) {
if (!error) {
cardData = data.tokenizedCard.card;
cardNumber = data.card.number;
state = data.tokenizedCard.state;
} else {
throw new Error(data);
}
});
} catch (error) {
throw error;
}
if (validator(digitalSignature, message, organizationId)) {
var webhookId = payload.webhookId;
var data = payload.payload[0].data._links;
var instrumentIdentifierLink = data.instrumentIdentifiers[0].href;
var instrumentIdentifier = instrumentIdentifierLink.substring(instrumentIdentifierLink.lastIndexOf('/') + 1);
var customerLink = data.customers[0].href;
var customerId = customerLink.substring(customerLink.lastIndexOf('/') + 1);
var paymentInstrument;
if (data.paymentInstruments) {
var paymentInstrumentLink = data.paymentInstruments[0].href;
paymentInstrument = paymentInstrumentLink.substring(paymentInstrumentLink.lastIndexOf('/') + 1);
}

if (state == 'ACTIVE') {
instance = new cybersourceRestApi.CustomerApi(configObject);
var email;
instance = new cybersourceRestApi.InstrumentIdentifierApi(configObject);
var cardData; var cardNumber; var state;
try { // eslint-disable-line no-useless-catch
instance.getCustomer(customerId, configObject.profileId, function (data, error, response) {
instance.getInstrumentIdentifier(instrumentIdentifier, configObject.profileId, function (data, error, response) {
if (!error) {
email = data._embedded.defaultPaymentInstrument.billTo.email;
cardData = data.tokenizedCard.card;
cardNumber = data.card.number;
state = data.tokenizedCard.state;
} else {
throw new Error(data);
Logger.info('Card details does not exist');
res.setStatusCode(404);
}
});
} catch (error) {
throw error;
Logger.info('Token update failed'+ error);
res.setStatusCode(404);
}

var customer = CustomerMgr.getCustomerByLogin(email);
var wallet = customer.profile.wallet;
var paymentInstruments = wallet.getPaymentInstruments();
var paymentToDelete = array.find(paymentInstruments, function (item) {
var token = item.creditCardToken;
var tokenInfo = mapper.deserializeTokenInformation(token);
return instrumentIdentifier === tokenInfo.instrumentIdentifier.id;
});

Transaction.wrap(function () {
var cardHolder = paymentToDelete.creditCardHolder;
var cardType = paymentToDelete.creditCardType;
var cardToken = paymentToDelete.creditCardToken;
wallet.removePaymentInstrument(paymentToDelete);
var newPaymentInstrument = wallet.createPaymentInstrument(PaymentInstrument.METHOD_CREDIT_CARD);
newPaymentInstrument.setCreditCardHolder(cardHolder);
var newCardNumber = cardNumber.slice(0, -4) + cardData.suffix;
newPaymentInstrument.setCreditCardNumber(newCardNumber);
newPaymentInstrument.setCreditCardType(cardType);
newPaymentInstrument.setCreditCardExpirationMonth(Number(cardData.expirationMonth));
newPaymentInstrument.setCreditCardExpirationYear(Number(cardData.expirationYear));
if (empty(paymentInstrument)) {
var oldToken = mapper.deserializeTokenInformation(cardToken);
paymentInstrument = oldToken.paymentInstrument.id;
if (state == 'ACTIVE') {
instance = new cybersourceRestApi.CustomerApi(configObject);
var email;
try { // eslint-disable-line no-useless-catch
instance.getCustomer(customerId, configObject.profileId, function (data, error, response) {
if (!error) {
email = data._embedded.defaultPaymentInstrument.billTo.email;
} else {
Logger.info('Customer data does not exist');
res.setStatusCode(404);
}
});
} catch (error) {
Logger.info('Token update failed'+ error);
res.setStatusCode(404);
}
var tokenInfo = {
instrumentIdentifier: { id: instrumentIdentifier },
paymentInstrument: { id: paymentInstrument }
};

var token = mapper.serializeTokenInformation(tokenInfo);
newPaymentInstrument.setCreditCardToken(token);
});
} else {
Logger.info('Network token state is not Active');
var customer = CustomerMgr.getCustomerByLogin(email);
var wallet = customer.profile.wallet;
var paymentInstruments = wallet.getPaymentInstruments();
var paymentToDelete = array.find(paymentInstruments, function (item) {
var token = item.creditCardToken;
var tokenInfo = mapper.deserializeTokenInformation(token);
return instrumentIdentifier === tokenInfo.instrumentIdentifier.id;
});

Transaction.wrap(function () {
var cardHolder = paymentToDelete.creditCardHolder;
var cardType = paymentToDelete.creditCardType;
var cardToken = paymentToDelete.creditCardToken;
wallet.removePaymentInstrument(paymentToDelete);
var newPaymentInstrument = wallet.createPaymentInstrument(PaymentInstrument.METHOD_CREDIT_CARD);
newPaymentInstrument.setCreditCardHolder(cardHolder);
var newCardNumber = cardNumber.slice(0, -4) + cardData.suffix;
newPaymentInstrument.setCreditCardNumber(newCardNumber);
newPaymentInstrument.setCreditCardType(cardType);
newPaymentInstrument.setCreditCardExpirationMonth(Number(cardData.expirationMonth));
newPaymentInstrument.setCreditCardExpirationYear(Number(cardData.expirationYear));
if (empty(paymentInstrument)) {
var oldToken = mapper.deserializeTokenInformation(cardToken);
paymentInstrument = oldToken.paymentInstrument.id;
}
var tokenInfo = {
instrumentIdentifier: { id: instrumentIdentifier },
paymentInstrument: { id: paymentInstrument }
};

var token = mapper.serializeTokenInformation(tokenInfo);
newPaymentInstrument.setCreditCardToken(token);
res.setStatusCode(200);
});
} else {
Logger.info('Network token state is not Active');
res.setStatusCode(404);
}
}
else{
res.setStatusCode(404);
}
}
}
});
else{
Logger.info('Network token updates disabled');
res.setStatusCode(404);
}
});

function validator(digitalSignature, message, merchantId) {
var signatureParts;
var timestamp;
var keyId;
try {
signatureParts = digitalSignature.split(';');
timestamp = parseInt(signatureParts[0].split('=')[1]);
keyId = signatureParts[1].split('=')[1];
signature = signatureParts[2].split('=')[1];
} catch (e) {
Logger.error('Invalid digital signature format');
}
function validator(digitalSignature, message, merchantId) {
var signatureParts;
var timestamp;
var keyId;
try {
signatureParts = digitalSignature.split(';');
timestamp = parseInt(signatureParts[0].split('=')[1]);
keyId = signatureParts[1].split('=')[1];
signature = signatureParts[2].split('=')[1];
} catch (e) {
Logger.error('Invalid digital signature format');
}

if (isValidTimestamp(timestamp)) {
const regeneratedSignature = regenerateSignature(timestamp, message, merchantId);
if (regeneratedSignature.toString() === Encoding.fromBase64(signature).toString()) {
return true;
if (isValidTimestamp(timestamp)) {
const regeneratedSignature = regenerateSignature(timestamp, message, merchantId);
if (regeneratedSignature.toString() === Encoding.fromBase64(signature).toString()) {
return true;
}
Logger.error('No match in signature');
return false;
}
Logger.error('No match in signature');
return false;
}
}

function regenerateSignature(timestamp, message, merchantId) {
const timestampedMessage = `${timestamp}.${message}`;
const key = getSecurityKey(merchantId);
try {
var hmac = new Mac('HmacSHA256');
return hmac.digest(new Bytes(timestampedMessage, 'utf8'), Encoding.fromBase64(key));
} catch (e) {
throw new Error('Failed to calculate hmac-sha256');
function regenerateSignature(timestamp, message, merchantId) {
const timestampedMessage = `${timestamp}.${message}`;
const key = getSecurityKey(merchantId);
try {
var hmac = new Mac('HmacSHA256');
return hmac.digest(new Bytes(timestampedMessage, 'utf8'), Encoding.fromBase64(key));
} catch (e) {
throw new Error('Failed to calculate hmac-sha256');
}
}
}

function getSecurityKey(merchantId) {
var obj = CustomObjectMgr.getCustomObject('Network Tokens Webhook', merchantId);
return obj.custom.SecurityKey;
}
function getSecurityKey(merchantId) {
var obj = CustomObjectMgr.getCustomObject('Network Tokens Webhook', merchantId);
return obj.custom.SecurityKey;
}

function isValidTimestamp(timestamp) {
const tolerance = 60 * 60 * 1000;
const currentTime = Date.now();
return currentTime - timestamp < tolerance;
}
function isValidTimestamp(timestamp) {
const tolerance = 60 * 60 * 1000;
const currentTime = Date.now();
return currentTime - timestamp < tolerance;
}

module.exports = server.exports();

0 comments on commit b4e5e18

Please sign in to comment.