Skip to content

Commit

Permalink
Init push
Browse files Browse the repository at this point in the history
  • Loading branch information
MedoDome committed Apr 24, 2019
0 parents commit c97eca6
Show file tree
Hide file tree
Showing 5 changed files with 668 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
## THIS WILL BE README FILE
20 changes: 20 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<head>
<title>3D Secure Verification</title>
<script language="Javascript">
function OnLoadEvent() { document.form.submit(); }
</script>
</head>
<body OnLoad="OnLoadEvent();">
Invoking 3-D secure form, please wait ...
<form name="form" action="https://ipgtest.pikpay.ba/acs/authenticated" method="post">
<input type="hidden" name="PaReq" value="fake authenticated pareq +=">
<input type="hidden" name="TermUrl" value="http://localhost:3000/payment/auth">
<input type="input" name="MD" value="1f9ec726ce2dbe72c19c95be45e48293eae8973b">
<noscript>
<p>Please click</p><input id="to-asc-button" type="submit">
</noscript>
</form>
</body>
</html>
296 changes: 296 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,296 @@
/**
* REQUIRED NPM MODULES
*/

const crypto = require('crypto'); // For making SHA1 digest
const axios = require('axios'); // For making requests
const convert = require('xml-js');
const jstoxml = require("js2xmlparser");
const responseCodes = require("./responseCodes");

/**
* GLOBAR VARS
*/


const HEADERS = {
'Accept' : 'application/xml',
'Content-Type' : 'application/xml; charset=UTF8'
}
/**
* DEMO FUNCTIONS
*/

function makeid(length) {
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

for (var i = 0; i < length; i++)
text += possible.charAt(Math.floor(Math.random() * possible.length));

return text;
}


/**
* FUNCTIONS
*/


function validateTransactionParams(transaction) {

/**
* Validating function which is WIP state
* @TODO
* 1. Make these check valid and test it
* @NEXT
* 1. Make configuration array for required fields ???
*
*/
// "ch-full-name" : "John Doe",
// "ch-address": "Elm Street 22",
// "ch-city" : "Mostar",
// "ch-zip": 22000,
// "ch-country": "Bosnia and Herzegovina",
// "ch-phone": "38761854123",
// "ch-email": "a@live.com",
// "pan": 4341792000000044,
// "cvv": 373,
// "expiration_date": "1912",
// "order-info": "tandara-2222",
// "order-number": "a3dsec4",
// "amount": 54301,
// "currency": "BAM",
// "ip": "127.0.0.1",
// "language": "hr",
// "transaction-type": "purchase",
// "authenticity-token" : _AUTHENTICITY_TOKEN,
// "digest": "digest"

let validationErrors = [];
if(transaction["ch-full-name"].trim().length === 0){
validationErrors.push({ valid: false, msg: "Card Holder name is not valid" });
}
if(transaction["ch-address"].trim().length === 0){
validationErrors.push({ valid: false, msg: "Card Holder name is not valid" });
}
if(transaction["ch-city"].trim().length === 0){
validationErrors.push({ valid: false, msg: "Card Holder name is not valid" });
}
if(transaction["ch-zip"].trim().length === 0){
validationErrors.push({ valid: false, msg: "Card Holder name is not valid" });
}
if(transaction["ch-country"].trim().length === 0){
validationErrors.push({ valid: false, msg: "Card Holder name is not valid" });
}
if(transaction["ch-phone"].trim().length === 0){
validationErrors.push({ valid: false, msg: "Card Holder name is not valid" });
}
if(transaction["ch-email"].trim().length === 0){
validationErrors.push({ valid: false, msg: "Card Holder name is not valid" });
}
if(transaction["pan"].trim().length === 0){
validationErrors.push({ valid: false, msg: "Card Holder name is not valid" });
}
if(transaction["ccv"].trim().length === 0){
validationErrors.push({ valid: false, msg: "Card Holder name is not valid" });
}
if(transaction["expiration_date"].trim().length === 0){
validationErrors.push({ valid: false, msg: "Card Holder name is not valid" });
}
if(transaction["order-info"].trim().length === 0){
validationErrors.push({ valid: false, msg: "Card Holder name is not valid" });
}
if(transaction["order-number"].trim().length === 0){
validationErrors.push({ valid: false, msg: "Card Holder name is not valid" });
}
if(transaction["amount"].trim().length === 0){
validationErrors.push({ valid: false, msg: "Card Holder name is not valid" });
}
if(transaction["currency"].trim().length === 0){
validationErrors.push({ valid: false, msg: "Card Holder name is not valid" });
}
if(transaction["ip"].trim().length === 0){
validationErrors.push({ valid: false, msg: "Card Holder name is not valid" });
}
if(transaction["language"].trim().length === 0){
validationErrors.push({ valid: false, msg: "Card Holder name is not valid" });
}
if(transaction["transaction-type"].trim().length === 0){
validationErrors.push({ valid: false, msg: "Card Holder name is not valid" });
}
if(transaction["authenticity-token"].trim().length === 0){
validationErrors.push({ valid: false, msg: "Card Holder name is not valid" });
}
if(transaction["digest"].trim().length === 0){
validationErrors.push({ valid: false, msg: "Card Holder name is not valid" });
}
if(validationErrors.length > 0)
return false;
return true;
}

function generateDigest(input) {
/**
* Digest is required by PikPay
* It's SHA1 hash of API AUTH KEY, order number, amount and currency
*/

var shaReady = input["api-auth-key"] + input["order-number"] + input["amount"] + input["currency"];
return crypto.createHash('sha1').update(shaReady).digest('hex')
}

function transactionResponseJSONPretty(transaction){
let object = {};
for (var key in transaction) {
object[key] = transaction[key]["_text"];
}
return object;
}
function generateXML(root, transaction) {
/**
* This will be recoded again
* Only one module should be used for XML
*/

const xml = jstoxml.parse(root, transaction, {
declaration: { encoding: "UTF-8" }
});
console.log(xml);
return xml;
}


async function asyncFinish3DTransaction(url, PaRes, MD) {
console.log("==== INCOMING ====");
console.log(PaRes,MD);
console.log("=== DEMO ===");
const threeDObject = {
"PaRes": PaRes,
"MD": MD
}


try {
const threeXMLObject = generateXML("secure-message", threeDObject);
console.log(threeXMLObject);

const response = await axios.post(url, threeXMLObject, {
headers: HEADERS
})

result1 = convert.xml2js(response.data, { compact: true, spaces: 4 });


if (response.status === 201) {
const { transaction, 'secure-message': secure } = result1;

if (typeof transaction !== "undefined") {
if (typeof responseCodes[transaction["response-code"]["_text"]] !== "undefined") {
if (responseCodes[transaction["response-code"]["_text"]]['msg'] === "Approved") {
return { status: true, errors: [], msg: "Success", responseData: response.data, data: transactionResponseJSONPretty(transaction), code: 1 };
} else {
return { status: false, errors: [responseCodes[transaction["response-code"]["_text"]]['msg']], data: null, msg: "Failed", responseData: response.data, code: 0 };
}
}
}
}
} catch (error) {
// handle error
console.log(error);
const { response } = error;
// We haven't get error here
if (typeof response === "undefined") {
console.log(error);
return { status: false, errors: ['Server error'], data: null, responseData: null, code: 0 };
} else {
return { status: false, errors: [response.data], data: null, responseData: response.data, code: 0 };

}
}

}
async function asyncCreateTransaction(orginalTransaction, url) {
/**
* RUN Validations
*/
if (!url) {
return { status: false, errors: ["Url not provided"], msg: "Failed", responseData: null, code: null };
}
// if (!validateTransactionParams(orginalTransaction))
// return; // FIX THIS
try {
const response = await axios.post(url, generateXML("transaction", orginalTransaction), {
headers: HEADERS
});
result1 = convert.xml2js(response.data, { compact: true, spaces: 4 });
// console.log(result1);
if (response.status === 201) {
const { transaction, 'secure-message': secure } = result1;

if (typeof transaction !== "undefined") {
if (typeof responseCodes[transaction["response-code"]["_text"]] !== "undefined") {
if (responseCodes[transaction["response-code"]["_text"]]['msg'] === "Approved") {
return { status: true, errors: null, msg: "Success", responseData: response.data, code: 1 };
} else {
return { status: false, errors: [responseCodes[transaction["response-code"]["_text"]]['msg']], msg: "Failed", responseData: response.data, code: 0 };
}
}
}
if (typeof secure !== "undefined") {

/**
* Here we need to send request for 3D Secure
*
*/

// Test function
// return await asyncFinish3DTransaction(secure['acs-url']['_text'],secure['pareq']['_text'],secure['authenticity-token']['_text']);


return { status: false, errors: null, msg: "Verification required", responseData: secure, data: { url: secure['acs-url']['_text'], pareq: secure['pareq']['_text'], authenticity_token: secure['authenticity-token']['_text'] }, code: 2 };



}

}

} catch (error) {
const { response } = error;
if (typeof response === "undefined") {
console.log(error);
return { status: false, errors: ['Server error'], data: null, responseData: null };
}
if(response.data === "Invalid request"){
return { status: false, errors: ['Invalid request'], data: null, responseData: null };

}
const resultData = convert.xml2js(response.data, { compact: true, spaces: 4 });

let responseErrors = [];
if (response.status === 422) {
const { error: errors } = resultData.errors;
if (Array.isArray(errors)) {
errors.forEach(err => {
responseErrors.push(err["_text"]);
});
} else {
responseErrors.push(errors["_text"]);
}

} else if (response.status === 406) {
return { status: false, errors: response.data, msg: "Failed", data: null, responseData: resultData, code: 0 };
}
return { status: false, errors: responseErrors, msg: "Failed", data: null, responseData: resultData, code: 0 };
}
}

module.exports = {
generateDigest,
makeid,
asyncCreateTransaction,
asyncFinish3DTransaction
}
// createTransaction(validNon3DSecured);
// (createTransaction(validNon3DSecured));
28 changes: 28 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "@mss.ba/pikpay-node",
"version": "0.0.1-rc1",
"description": "NodeJS wrapper for PikPay payment gateway",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Armin Comic",
"license": "MIT",
"dependencies": {
"axios": "^0.18.0",
"js2xmlparser": "^4.0.0",
"xml-js": "^1.6.11"
},
"devDependencies": {
"express": "^4.16.4",
"body-parser": "^1.18.3"
},
"repository": {
"type": "git",
"url": "ssh://git@phabricator.mss.ba/diffusion/44/int-npm-pik-pay.git"
},
"keywords": [
"pikpay",
"nodejs"
]
}
Loading

0 comments on commit c97eca6

Please sign in to comment.