Skip to content

Commit

Permalink
feature:(payment):check payment status
Browse files Browse the repository at this point in the history
- start the implementation of a `checkPaymentStatus` method that
allows the user to send a request the gourl api to check the status
of a payment. The method takes an `options` parameter that include a
set of data associated with the payment whose status is to be confirmed.

[Starts #26]
  • Loading branch information
steveify1 committed Aug 24, 2020
1 parent c427df3 commit a90a1e8
Show file tree
Hide file tree
Showing 10 changed files with 213 additions and 82 deletions.
5 changes: 5 additions & 0 deletions dist/index.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,7 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const Cryptobox_1 = __importDefault(require("./lib/Cryptobox"));
exports.default = Cryptobox_1.default;
61 changes: 35 additions & 26 deletions dist/lib/Cryptobox.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
// import crypto from 'crypto';
// import https from 'https';
const crypto_1 = __importDefault(require("crypto"));
const buffer_1 = require("buffer");
const crc_32_1 = __importDefault(require("crc-32"));
const md5_1 = __importDefault(require("md5"));
Expand All @@ -84,6 +83,7 @@ const axios_1 = __importDefault(require("axios"));
const _defaults_1 = __importDefault(require("./_defaults"));
// IMPORT CONSTANTS
const constants_1 = require("./constants");
const formatExpiryPeriod_1 = __importDefault(require("./utils/formatExpiryPeriod"));
class Cryptobox {
/**
* Creates an new Cryptobox object for interfacing with a `gourl` cryptobox
Expand Down Expand Up @@ -205,22 +205,7 @@ class Cryptobox {
* which determines the period after which the cryptobox will be obselete and a new cryptobox must then be created.
*/
setExpiry() {
this.period = this.period.replace(' ', '').toUpperCase().trim();
if (this.period.substring(-1) === 'S') {
this.period = this.period.substring(0, -1);
}
const arr = [];
for (let i = 1; i <= 90; i++) {
arr.push(`${i}MINUTE`);
arr.push(`${i}HOUR`);
arr.push(`${i}DAY`);
arr.push(`${i}WEEK`);
arr.push(`${i}MONTH`);
}
if (this.period !== 'NOEXPIRY' && !arr.includes(this.period)) {
throw new Error(`Invalid Cryptobox Period - ${this.period}`);
}
this.period = this.period.replace(/(minute|hour|day|week|month)/i, (match) => ` ${match}`);
this.period = formatExpiryPeriod_1.default(this.period);
}
/**
* Sets the user's language. Defaults to `en` for English users.
Expand Down Expand Up @@ -423,17 +408,41 @@ class Cryptobox {
* @returns { Promise<Response> } - A Promise that resolves to the response from the payment gateway
*/
async createPayment() {
// return new Promise((resolve, reject) => {
// https.get(this.composeURL(), (response) => {
// let body = '';
// response.on('data', (data) => (body += data));
// response.on('error', (error) => reject(error));
// response.on('end', () => resolve(JSON.parse(body)));
// });
// });
const res = await axios_1.default.get(this.composeURL());
return res.data;
}
/**
* Checks the payment status by sending a request to the GoURL server
* options
*/
static async checkPaymentStatus(options) {
const privateKeyHash = crypto_1.default
.createHash('sha512')
.update(options.privateKey)
.digest('hex');
const period = formatExpiryPeriod_1.default(options.period);
const toHash = `${options.boxID}${privateKeyHash}${options.userID}${options.orderID}${options.language}${period}${options.ipAddress}`;
const hash = md5_1.default(toHash);
const data = {
g: privateKeyHash,
b: options.boxID,
o: options.orderID,
u: options.userID,
l: options.language,
e: period,
i: options.ipAddress,
h: hash,
};
const url = `https://coins.gourl.io/result.php`;
const res = await axios_1.default.post(url, null, {
params: data,
headers: {
'User-Agent': options.userAgent,
},
timeout: 20000,
});
return res.data;
}
left(str = '', findme = '', firstpos = true) {
const strCopy = str.toLowerCase();
const findmeCopy = findme.toLowerCase();
Expand Down
2 changes: 2 additions & 0 deletions dist/lib/interfaces/PaymentStatusOptions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
21 changes: 21 additions & 0 deletions dist/lib/utils/composeQueryString.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* Converts an object into a valid URI query string
* @param { object } data - An object whose key-value pairs
* will be converted into a URI string
*
* @return { string } A HTTP query string starting with the
* question mark (?).
*/
exports.default = (data = {}) => {
let result = '?';
for (let key in data) {
let { value } = Object.getOwnPropertyDescriptor(data, key);
value = `${value}`.split(' ').join('+');
result += `${key}=${encodeURIComponent(value)}&`;
}
// remove trailing `&`
result = result.slice(0, result.length - 1);
return result;
};
20 changes: 20 additions & 0 deletions dist/lib/utils/formatExpiryPeriod.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = (period) => {
period = period.replace(' ', '').toUpperCase().trim();
if (period.substring(-1) === 'S') {
period = period.substring(0, -1);
}
const arr = [];
for (let i = 1; i <= 90; i++) {
arr.push(`${i}MINUTE`);
arr.push(`${i}HOUR`);
arr.push(`${i}DAY`);
arr.push(`${i}WEEK`);
arr.push(`${i}MONTH`);
}
if (period !== 'NOEXPIRY' && !arr.includes(period)) {
throw new Error(`Invalid Cryptobox Period - ${period}`);
}
return period.replace(/(minute|hour|day|week|month)/i, (match) => ` ${match}`);
};
2 changes: 2 additions & 0 deletions index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
import Cryptobox from './lib/Cryptobox';

export default Cryptobox;
128 changes: 72 additions & 56 deletions lib/Cryptobox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,16 @@
*
*/

// import crypto from 'crypto';
import crypto from 'crypto';
// import https from 'https';
import querystring from 'querystring';
import { Buffer } from 'buffer';
import crc32 from 'crc-32';
import md5 from 'md5';
import axios, { AxiosResponse } from 'axios';

import CryptoboxOptions from './interfaces/CryptoboxOptions';
import PaymentStatusOptions from './interfaces/PaymentStatusOptions';
import RequestURLKeys from './interfaces/RequestURLKeys';

// IMPORT SOME DEFAULT OPTIONS
Expand All @@ -90,28 +92,32 @@ import {
CRYPTOBOX_VERSION,
} from './constants';

// IMPORT UTILS
import composeQueryString from './utils/composeQueryString';
import formatExpiryPeriod from './utils/formatExpiryPeriod';

class Cryptobox {
public baseURL: string = 'https://coins.gourl.io';
public publicKey = ''; // value from your gourl.io member page - https://gourl.io/info/memberarea
public privateKey = ''; // value from your gourl.io member page. Also you setup cryptocoin name on gourl.io member page
public webdevKey = ''; // optional, web developer affiliate key
public publicKey: string = ''; // value from your gourl.io member page - https://gourl.io/info/memberarea
public privateKey: string = ''; // value from your gourl.io member page. Also you setup cryptocoin name on gourl.io member page
public webdevKey: string = ''; // optional, web developer affiliate key
public ipAddress: string = ''; // The IP address of the current user or the server
public amount = 0; // amount of cryptocoins which will be used in the payment box/captcha, precision is 4 (number of digits after the decimal), example: 0.0001, 2.444, 100, 2455, etc.
public amount: number = 0; // amount of cryptocoins which will be used in the payment box/captcha, precision is 4 (number of digits after the decimal), example: 0.0001, 2.444, 100, 2455, etc.
/* we will use this $amount value of cryptocoins in the payment box with a small fraction after the decimal point to uniquely identify each of your users individually
* (for example, if you enter 0.5 BTC, one of your user will see 0.500011 BTC, and another will see 0.500046 BTC, etc) */
public amountUSD = 0;
public amountUSD: number = 0;
/* you can specify your price in USD and cryptobox will automatically convert that USD amount to cryptocoin amount using today live cryptocurrency exchange rates.
* Using that functionality (price in USD), you don't need to worry if cryptocurrency prices go down or up.
* User will pay you all times the actual price which is linked on current exchange price in USD on the datetime of purchase.
* You can use in cryptobox options one variable only: amount or amountUSD. You cannot place values of those two variables together. */
public period = ''; // period after which the payment becomes obsolete and new cryptobox will be shown; allow values: NOEXPIRY, 1 MINUTE..90 MINUTE, 1 HOUR..90 HOURS, 1 DAY..90 DAYS, 1 WEEK..90 WEEKS, 1 MONTH..90 MONTHS
public language = 'en'; // cryptobox localisation; en - English, es - Spanish, fr - French, de - German, nl - Dutch, it - Italian, ru - Russian, pl - Polish, pt - Portuguese, fa - Persian, ko - Korean, ja - Japanese, id - Indonesian, tr - Turkish, ar - Arabic, cn - Simplified Chinese, zh - Traditional Chinese, hi - Hindi
public iframeID = ''; // optional, html iframe element id; allow symbols: a..Z0..9_-
public orderID = ''; // your page name / product name or order name (not unique); allow symbols: a..Z0..9_-@.; max size: 50 symbols
public userID = ''; // optional, manual setup unique identifier for each of your users; allow symbols: a..Z0..9_-@.; max size: 50 symbols
public period: string = ''; // period after which the payment becomes obsolete and new cryptobox will be shown; allow values: NOEXPIRY, 1 MINUTE..90 MINUTE, 1 HOUR..90 HOURS, 1 DAY..90 DAYS, 1 WEEK..90 WEEKS, 1 MONTH..90 MONTHS
public language: string = 'en'; // cryptobox localisation; en - English, es - Spanish, fr - French, de - German, nl - Dutch, it - Italian, ru - Russian, pl - Polish, pt - Portuguese, fa - Persian, ko - Korean, ja - Japanese, id - Indonesian, tr - Turkish, ar - Arabic, cn - Simplified Chinese, zh - Traditional Chinese, hi - Hindi
public iframeID: string = ''; // optional, html iframe element id; allow symbols: a..Z0..9_-
public orderID: string = ''; // your page name / product name or order name (not unique); allow symbols: a..Z0..9_-@.; max size: 50 symbols
public userID: string = ''; // optional, manual setup unique identifier for each of your users; allow symbols: a..Z0..9_-@.; max size: 50 symbols
/* IMPORTANT - If you use Payment Box/Captcha for registered users on your website, you need to set userID manually with
* an unique value for each of your registered user. It is better than to use cookies by default. Examples: 'user1', 'user2', '3vIh9MjEis' */
public userFormat = 'MANUAL'; // this variable use only if $userID above is empty - it will save random userID in cookies, sessions or use user IP address as userID. Available values: COOKIE, SESSION, IPADDRESS
public userFormat: string = 'MANUAL'; // this variable use only if $userID above is empty - it will save random userID in cookies, sessions or use user IP address as userID. Available values: COOKIE, SESSION, IPADDRESS

/* PLEASE NOTE -
* If you use multiple stores/sites online, please create separate GoUrl Payment Box (with unique payment box public/private keys) for each of your stores/websites.
Expand All @@ -121,20 +127,20 @@ class Cryptobox {
* */

// Internal Variables
private boxID = 0; // cryptobox id, the same as on gourl.io member page. For each your cryptocoin payment boxes you will have unique public / private keys
private coinLabel = ''; // current cryptocoin label (BTC, DOGE, etc.)
private coinName = ''; // current cryptocoin name (Bitcoin, Dogecoin, etc.)
private paid = false; // paid or not
private confirmed = false; // transaction/payment have 6+ confirmations or not
private paymentID = false; // current record id in the table crypto_payments (table stores all payments from your users)
private paymentDate = ''; // transaction/payment datetime in GMT format
private amountPaid = 0; // exact paid amount; for example, $amount = 0.5 BTC and user paid - $amountPaid = 0.50002 BTC
private amountPaidUSD = 0; // approximate paid amount in USD; using cryptocurrency exchange rate on datetime of payment
private boxType = ''; // cryptobox type - 'paymentbox' or 'captchabox'
private processed = false; // optional - set flag to paid & processed
private cookieName = ''; // user cookie/session name (if cookies/sessions use)
private localisation = ''; // localisation; en - English, es - Spanish, fr - French, de - German, nl - Dutch, it - Italian, ru - Russian, pl - Polish, pt - Portuguese, fa - Persian, ko - Korean, ja - Japanese, id - Indonesian, tr - Turkish, ar - Arabic, cn - Simplified Chinese, zh - Traditional Chinese, hi - Hindi
private version = `version | gourlphp ${CRYPTOBOX_VERSION}`;
private boxID: number = 0; // cryptobox id, the same as on gourl.io member page. For each your cryptocoin payment boxes you will have unique public / private keys
private coinLabel: string = ''; // current cryptocoin label (BTC, DOGE, etc.)
private coinName: string = ''; // current cryptocoin name (Bitcoin, Dogecoin, etc.)
private paid: boolean = false; // paid or not
private confirmed: boolean = false; // transaction/payment have 6+ confirmations or not
private paymentID: boolean = false; // current record id in the table crypto_payments (table stores all payments from your users)
private paymentDate: string = ''; // transaction/payment datetime in GMT format
private amountPaid: number = 0; // exact paid amount; for example, $amount = 0.5 BTC and user paid - $amountPaid = 0.50002 BTC
private amountPaidUSD: number = 0; // approximate paid amount in USD; using cryptocurrency exchange rate on datetime of payment
private boxType: string = ''; // cryptobox type - 'paymentbox' or 'captchabox'
private processed: boolean = false; // optional - set flag to paid & processed
private cookieName: string = ''; // user cookie/session name (if cookies/sessions use)
private localisation: string = ''; // localisation; en - English, es - Spanish, fr - French, de - German, nl - Dutch, it - Italian, ru - Russian, pl - Polish, pt - Portuguese, fa - Persian, ko - Korean, ja - Japanese, id - Indonesian, tr - Turkish, ar - Arabic, cn - Simplified Chinese, zh - Traditional Chinese, hi - Hindi
private version: string = `version | gourlphp ${CRYPTOBOX_VERSION}`;
public userAgent: string = '';

/**
Expand Down Expand Up @@ -222,28 +228,7 @@ class Cryptobox {
* which determines the period after which the cryptobox will be obselete and a new cryptobox must then be created.
*/
setExpiry(): void {
this.period = this.period.replace(' ', '').toUpperCase().trim();
if (this.period.substring(-1) === 'S') {
this.period = this.period.substring(0, -1);
}

const arr: string[] = [];
for (let i = 1; i <= 90; i++) {
arr.push(`${i}MINUTE`);
arr.push(`${i}HOUR`);
arr.push(`${i}DAY`);
arr.push(`${i}WEEK`);
arr.push(`${i}MONTH`);
}

if (this.period !== 'NOEXPIRY' && !arr.includes(this.period)) {
throw new Error(`Invalid Cryptobox Period - ${this.period}`);
}

this.period = this.period.replace(
/(minute|hour|day|week|month)/i,
(match) => ` ${match}`
);
this.period = formatExpiryPeriod(this.period);
}

/**
Expand Down Expand Up @@ -493,18 +478,49 @@ class Cryptobox {
* @returns { Promise<Response> } - A Promise that resolves to the response from the payment gateway
*/
async createPayment(): Promise<AxiosResponse> {
// return new Promise((resolve, reject) => {
// https.get(this.composeURL(), (response) => {
// let body = '';
// response.on('data', (data) => (body += data));
// response.on('error', (error) => reject(error));
// response.on('end', () => resolve(JSON.parse(body)));
// });
// });
const res = await axios.get(this.composeURL());
return res.data;
}

/**
* Checks the payment status by sending a request to the GoURL server
* options
*/
static async checkPaymentStatus(options: PaymentStatusOptions): Promise<any> {
const privateKeyHash = crypto
.createHash('sha512')
.update(options.privateKey!)
.digest('hex');

const period = formatExpiryPeriod(options.period);

const toHash = `${options.boxID}${privateKeyHash}${options.userID}${options.orderID}${options.language}${period}${options.ipAddress}`;
const hash = md5(toHash);

const data = {
g: privateKeyHash,
b: options.boxID,
o: options.orderID,
u: options.userID,
l: options.language,
e: period,
i: options.ipAddress,
h: hash,
};

const url = `https://coins.gourl.io/result.php`;

const res = await axios.post(url, null, {
params: data, // converts and attaches data as a query string
headers: {
'User-Agent': options.userAgent,
},
timeout: 20000,
});

return res.data;
}

left(str = '', findme = '', firstpos = true): string {
const strCopy = str.toLowerCase();
const findmeCopy = findme.toLowerCase();
Expand Down
10 changes: 10 additions & 0 deletions lib/interfaces/PaymentStatusOptions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export default interface PaymentStatusOption {
privateKey?: string;
boxID: string;
orderID: string;
userID: string;
language?: string;
period: string;
ipAddress: string;
userAgent: string;
}
22 changes: 22 additions & 0 deletions lib/utils/composeQueryString.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* Converts an object into a valid URI query string
* @param { object } data - An object whose key-value pairs
* will be converted into a URI string
*
* @return { string } A HTTP query string starting with the
* question mark (?).
*/
export default (data: object = {}): string => {
let result = '?';

for (let key in data) {
let { value } = Object.getOwnPropertyDescriptor(data, key)!;
value = `${value}`.split(' ').join('+');
result += `${key}=${encodeURIComponent(value)}&`;
}

// remove trailing `&`
result = result.slice(0, result.length - 1);

return result;
};
24 changes: 24 additions & 0 deletions lib/utils/formatExpiryPeriod.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
export default (period: string): string => {
period = period.replace(' ', '').toUpperCase().trim();
if (period.substring(-1) === 'S') {
period = period.substring(0, -1);
}

const arr: string[] = [];
for (let i = 1; i <= 90; i++) {
arr.push(`${i}MINUTE`);
arr.push(`${i}HOUR`);
arr.push(`${i}DAY`);
arr.push(`${i}WEEK`);
arr.push(`${i}MONTH`);
}

if (period !== 'NOEXPIRY' && !arr.includes(period)) {
throw new Error(`Invalid Cryptobox Period - ${period}`);
}

return period.replace(
/(minute|hour|day|week|month)/i,
(match) => ` ${match}`
);
};

0 comments on commit a90a1e8

Please sign in to comment.