1. 1 :
  2. 2 : (function(root, factory) {
  3. 3 : if (typeof define === 'function' && define.amd) {
  4. 4 : // AMD. Register as an anonymous module.
  5. 5 : define(['superagent', 'querystring'], factory);
  6. 6 : } else if (typeof module === 'object' && module.exports) {
  7. 7 : // CommonJS-like environments that support module.exports, like Node.
  8. 8 : module.exports = factory(require('logtown').getLogger('orbipay-paymentsapi-client/src/ApiClient'), require('superagent'), require('querystring'), require('./CommonUtil'), require('crypto'));
  9. 9 : } else {
  10. 10 : // Browser globals (root is window)
  11. 11 : if (!root.OrbipayPaymentsapiClient) {
  12. 12 : root.OrbipayPaymentsapiClient = {};
  13. 13 : }
  14. 14 : root.OrbipayPaymentsapiClient.ApiClient = factory(root.superagent, root.querystring);
  15. 15 : }
  16. 16 : }(this, function(logger, superagent, querystring, CommonUtil, crypto) {
  17. 17 : 'use strict';
  18. 18 :
  19. 19 : /**
  20. 20 : * @module ApiClient
  21. 21 : */
  22. 22 :
  23. 23 : /**
  24. 24 : * <h3 style="color:red"> This class subject to change without prior notice, Please dont use this class directly. </h3>
  25. 25 :
  26. 26 : * Manages low level client-server communications, parameter marshalling, etc. There should not be any need for an
  27. 27 : * application to use this class directly - the *Api and model classes provide the public API for the service. The
  28. 28 : * contents of this file should be regarded as internal but are documented for completeness.
  29. 29 : * @alias module:ApiClient
  30. 30 : * @class
  31. 31 : */
  32. 32 : var exports = function(clientSignatureKey, basePath, clientApiKey, authScheme) {
  33. 33 : /**
  34. 34 : * The base URL against which to resolve every API call's (relative) path.
  35. 35 : * @type {String}
  36. 36 : * @default https://api.orbipay.com/payments/v1
  37. 37 : */
  38. 38 : this.basePath = basePath;
  39. 39 :
  40. 40 : /**
  41. 41 : * The authentication methods to be included for all API calls.
  42. 42 : * @type {Array.<String>}
  43. 43 : */
  44. 44 : this.authentications = {
  45. 45 : };
  46. 46 : /**
  47. 47 : * The default HTTP headers to be included for all API calls.
  48. 48 : * @type {Array.<String>}
  49. 49 : * @default {}
  50. 50 : */
  51. 51 : this.defaultHeaders = {};
  52. 52 :
  53. 53 : /**
  54. 54 : * The default HTTP timeout for all API calls.
  55. 55 : * @type {Number}
  56. 56 : * @default 60
  57. 57 : */
  58. 58 : this.timeout = 60;
  59. 59 :
  60. 60 : /**
  61. 61 : * If set to false an additional timestamp parameter is added to all API GET calls to
  62. 62 : * prevent browser caching
  63. 63 : * @type {Boolean}
  64. 64 : * @default true
  65. 65 : */
  66. 66 : this.cache = true;
  67. 67 :
  68. 68 : /**
  69. 69 : * If set to true, the client will save the cookies from each server
  70. 70 : * response, and return them in the next request.
  71. 71 : * @default false
  72. 72 : */
  73. 73 : this.enableCookies = false;
  74. 74 :
  75. 75 : /*
  76. 76 : * Used to save and return cookies in a node.js (non-browser) setting,
  77. 77 : * if this.enableCookies is set to true.
  78. 78 : */
  79. 79 : if (typeof window === 'undefined') {
  80. 80 : this.agent = new superagent.agent();
  81. 81 : }
  82. 82 :
  83. 83 : /*
  84. 84 : * Allow user to override superagent agent
  85. 85 : */
  86. 86 : this.requestAgent = null;
  87. 87 :
  88. 88 : this.clientSignatureKey = clientSignatureKey;
  89. 89 : this.clientApiKey = clientApiKey;
  90. 90 : this.authScheme = authScheme;
  91. 91 :
  92. 92 : };
  93. 93 :
  94. 94 : /**
  95. 95 : * Returns a string representation for an actual parameter.
  96. 96 : * @param param The actual parameter.
  97. 97 : * @returns {String} The string representation of <code>param</code>.
  98. 98 : */
  99. 99 : exports.prototype.paramToString = function(param) {
  100. 100 : if (param === undefined || param === null) {
  101. 101 : return '';
  102. 102 : }
  103. 103 : if (param instanceof Date) {
  104. 104 : return param.toJSON();
  105. 105 : }
  106. 106 : return param.toString();
  107. 107 : };
  108. 108 :
  109. 109 : /**
  110. 110 : * Builds full URL by appending the given path to the base URL and replacing path parameter place-holders with parameter values.
  111. 111 : * NOTE: query parameters are not handled here.
  112. 112 : * @param {String} path The path to append to the base URL.
  113. 113 : * @param {Object} pathParams The parameter values to append.
  114. 114 : * @returns {String} The encoded path with parameter values substituted.
  115. 115 : */
  116. 116 : exports.prototype.buildUrl = function(path, pathParams) {
  117. 117 : if (!path.match(/^\//)) {
  118. 118 : path = '/' + path;
  119. 119 : }
  120. 120 : var url = this.basePath + path;
  121. 121 : var _this = this;
  122. 122 : url = url.replace(/\{([\w-]+)\}/g, function(fullMatch, key) {
  123. 123 : var value;
  124. 124 : if (pathParams.hasOwnProperty(key)) {
  125. 125 : value = _this.paramToString(pathParams[key]);
  126. 126 : if(exports.isEmptyString(value)){
  127. 127 : logger.error('Missing the required parameter ' + key);
  128. 128 : throw new Error('Missing the required parameter ' + key);
  129. 129 : }
  130. 130 : } else {
  131. 131 : value = fullMatch;
  132. 132 : }
  133. 133 : return encodeURIComponent(value);
  134. 134 : });
  135. 135 : return url;
  136. 136 : };
  137. 137 :
  138. 138 : /**
  139. 139 : * Checks whether the given content type represents JSON.<br>
  140. 140 : * JSON content type examples:<br>
  141. 141 : * <ul>
  142. 142 : * <li>application/json</li>
  143. 143 : * <li>application/json; charset=UTF8</li>
  144. 144 : * <li>APPLICATION/JSON</li>
  145. 145 : * </ul>
  146. 146 : * @param {String} contentType The MIME content type to check.
  147. 147 : * @returns {Boolean} <code>true</code> if <code>contentType</code> represents JSON, otherwise <code>false</code>.
  148. 148 : */
  149. 149 : exports.prototype.isJsonMime = function(contentType) {
  150. 150 : return Boolean(contentType != null && contentType.match(/^application\/json(;.*)?$/i));
  151. 151 : };
  152. 152 :
  153. 153 : /**
  154. 154 : * Chooses a content type from the given array, with JSON preferred; i.e. return JSON if included, otherwise return the first.
  155. 155 : * @param {Array.<String>} contentTypes
  156. 156 : * @returns {String} The chosen content type, preferring JSON.
  157. 157 : */
  158. 158 : exports.prototype.jsonPreferredMime = function(contentTypes) {
  159. 159 : for (var i = 0; i < contentTypes.length; i++) {
  160. 160 : if (this.isJsonMime(contentTypes[i])) {
  161. 161 : return contentTypes[i];
  162. 162 : }
  163. 163 : }
  164. 164 : return contentTypes[0];
  165. 165 : };
  166. 166 :
  167. 167 : /**
  168. 168 : * Checks whether the given parameter value represents file-like content.
  169. 169 : * @param param The parameter to check.
  170. 170 : * @returns {Boolean} <code>true</code> if <code>param</code> represents a file.
  171. 171 : */
  172. 172 : exports.prototype.isFileParam = function(param) {
  173. 173 : // fs.ReadStream in Node.js and Electron (but not in runtime like browserify)
  174. 174 : if (typeof require === 'function') {
  175. 175 : var fs;
  176. 176 : try {
  177. 177 : fs = require('fs');
  178. 178 : } catch (err) {}
  179. 179 : if (fs && fs.ReadStream && param instanceof fs.ReadStream) {
  180. 180 : return true;
  181. 181 : }
  182. 182 : }
  183. 183 : // Buffer in Node.js
  184. 184 : if (typeof Buffer === 'function' && param instanceof Buffer) {
  185. 185 : return true;
  186. 186 : }
  187. 187 : // Blob in browser
  188. 188 : if (typeof Blob === 'function' && param instanceof Blob) {
  189. 189 : return true;
  190. 190 : }
  191. 191 : // File in browser (it seems File object is also instance of Blob, but keep this for safe)
  192. 192 : if (typeof File === 'function' && param instanceof File) {
  193. 193 : return true;
  194. 194 : }
  195. 195 : return false;
  196. 196 : };
  197. 197 :
  198. 198 : /**
  199. 199 : * Normalizes parameter values:
  200. 200 : * <ul>
  201. 201 : * <li>remove nils</li>
  202. 202 : * <li>keep files and arrays</li>
  203. 203 : * <li>format to string with `paramToString` for other cases</li>
  204. 204 : * </ul>
  205. 205 : * @param {Object.<String, Object>} params The parameters as object properties.
  206. 206 : * @returns {Object.<String, Object>} normalized parameters.
  207. 207 : */
  208. 208 : exports.prototype.normalizeParams = function(params) {
  209. 209 : var newParams = {};
  210. 210 : for (var key in params) {
  211. 211 : if (params.hasOwnProperty(key) && params[key] != undefined && params[key] != null) {
  212. 212 : var value = params[key];
  213. 213 : if (this.isFileParam(value) || Array.isArray(value)) {
  214. 214 : newParams[key] = value;
  215. 215 : } else {
  216. 216 : newParams[key] = this.paramToString(value);
  217. 217 : }
  218. 218 : }
  219. 219 : }
  220. 220 : return newParams;
  221. 221 : };
  222. 222 :
  223. 223 : /**
  224. 224 : * Enumeration of collection format separator strategies.
  225. 225 : * @enum {String}
  226. 226 : * @readonly
  227. 227 : */
  228. 228 : exports.CollectionFormatEnum = {
  229. 229 : /**
  230. 230 : * Comma-separated values. Value: <code>csv</code>
  231. 231 : * @const
  232. 232 : */
  233. 233 : CSV: ',',
  234. 234 : /**
  235. 235 : * Space-separated values. Value: <code>ssv</code>
  236. 236 : * @const
  237. 237 : */
  238. 238 : SSV: ' ',
  239. 239 : /**
  240. 240 : * Tab-separated values. Value: <code>tsv</code>
  241. 241 : * @const
  242. 242 : */
  243. 243 : TSV: '\t',
  244. 244 : /**
  245. 245 : * Pipe(|)-separated values. Value: <code>pipes</code>
  246. 246 : * @const
  247. 247 : */
  248. 248 : PIPES: '|',
  249. 249 : /**
  250. 250 : * Native array. Value: <code>multi</code>
  251. 251 : * @const
  252. 252 : */
  253. 253 : MULTI: 'multi'
  254. 254 : };
  255. 255 :
  256. 256 : /**
  257. 257 : * Builds a string representation of an array-type actual parameter, according to the given collection format.
  258. 258 : * @param {Array} param An array parameter.
  259. 259 : * @param {module:ApiClient.CollectionFormatEnum} collectionFormat The array element separator strategy.
  260. 260 : * @returns {String|Array} A string representation of the supplied collection, using the specified delimiter. Returns
  261. 261 : * <code>param</code> as is if <code>collectionFormat</code> is <code>multi</code>.
  262. 262 : */
  263. 263 : exports.prototype.buildCollectionParam = function buildCollectionParam(param, collectionFormat) {
  264. 264 : if (param == null) {
  265. 265 : return null;
  266. 266 : }
  267. 267 : switch (collectionFormat) {
  268. 268 : case 'csv':
  269. 269 : return param.map(this.paramToString).join(',');
  270. 270 : case 'ssv':
  271. 271 : return param.map(this.paramToString).join(' ');
  272. 272 : case 'tsv':
  273. 273 : return param.map(this.paramToString).join('\t');
  274. 274 : case 'pipes':
  275. 275 : return param.map(this.paramToString).join('|');
  276. 276 : case 'multi':
  277. 277 : // return the array directly as SuperAgent will handle it as expected
  278. 278 : return param.map(this.paramToString);
  279. 279 : default:
  280. 280 : throw new Error('Unknown collection format: ' + collectionFormat);
  281. 281 : }
  282. 282 : };
  283. 283 :
  284. 284 : /**
  285. 285 : * Applies authentication headers to the request.
  286. 286 : * @param {Object} request The request object created by a <code>superagent()</code> call.
  287. 287 : * @param {Array.<String>} authNames An array of authentication method names.
  288. 288 : */
  289. 289 : exports.prototype.applyAuthToRequest = function(request, authNames) {
  290. 290 : var _this = this;
  291. 291 : authNames.forEach(function(authName) {
  292. 292 : var auth = _this.authentications[authName];
  293. 293 : switch (auth.type) {
  294. 294 : case 'basic':
  295. 295 : if (auth.username || auth.password) {
  296. 296 : request.auth(auth.username || '', auth.password || '');
  297. 297 : }
  298. 298 : break;
  299. 299 : case 'apiKey':
  300. 300 : if (auth.apiKey) {
  301. 301 : var data = {};
  302. 302 : if (auth.apiKeyPrefix) {
  303. 303 : data[auth.name] = auth.apiKeyPrefix + ' ' + auth.apiKey;
  304. 304 : } else {
  305. 305 : data[auth.name] = auth.apiKey;
  306. 306 : }
  307. 307 : if (auth['in'] === 'header') {
  308. 308 : request.set(data);
  309. 309 : } else {
  310. 310 : request.query(data);
  311. 311 : }
  312. 312 : }
  313. 313 : break;
  314. 314 : case 'oauth2':
  315. 315 : if (auth.accessToken) {
  316. 316 : request.set({'Authorization': 'Bearer ' + auth.accessToken});
  317. 317 : }
  318. 318 : break;
  319. 319 : default:
  320. 320 : throw new Error('Unknown authentication type: ' + auth.type);
  321. 321 : }
  322. 322 : });
  323. 323 : };
  324. 324 :
  325. 325 : /**
  326. 326 : * Deserializes an HTTP response body into a value of the specified type.
  327. 327 : * @param {Object} response A SuperAgent response object.
  328. 328 : * @param {(String|Array.<String>|Object.<String, Object>|Function)} returnType The type to return. Pass a string for simple types
  329. 329 : * or the constructor function for a complex type. Pass an array containing the type name to return an array of that type. To
  330. 330 : * return an object, pass an object with one property whose name is the key type and whose value is the corresponding value type:
  331. 331 : * all properties on <code>data<code> will be converted to this type.
  332. 332 : * @returns A value of the specified type.
  333. 333 : */
  334. 334 : exports.prototype.deserialize = function deserialize(response, returnType) {
  335. 335 : if (response == null || returnType == null || response.status == 204) {
  336. 336 : return null;
  337. 337 : }
  338. 338 : // Rely on SuperAgent for parsing response body.
  339. 339 : // See http://visionmedia.github.io/superagent/#parsing-response-bodies
  340. 340 : var data = response.body;
  341. 341 : if (data == null || (typeof data === 'object' && typeof data.length === 'undefined' && !Object.keys(data).length)) {
  342. 342 : // SuperAgent does not always produce a body; use the unparsed response as a fallback
  343. 343 : data = response.text;
  344. 344 : }
  345. 345 : return exports.convertToType(data, returnType);
  346. 346 : };
  347. 347 :
  348. 348 : /**
  349. 349 : * Callback function to receive the result of the operation.
  350. 350 : * @callback module:ApiClient~callApiCallback
  351. 351 : * @param {String} error Error message, if any.
  352. 352 : * @param data The data returned by the service call.
  353. 353 : * @param {String} response The complete HTTP response.
  354. 354 : */
  355. 355 :
  356. 356 : /**
  357. 357 : * Invokes the REST service using the supplied settings and parameters.
  358. 358 : * @param {String} path The base URL to invoke.
  359. 359 : * @param {String} httpMethod The HTTP method to use.
  360. 360 : * @param {Object.<String, String>} pathParams A map of path parameters and their values.
  361. 361 : * @param {Object.<String, Object>} queryParams A map of query parameters and their values.
  362. 362 : * @param {Object.<String, Object>} collectionQueryParams A map of collection query parameters and their values.
  363. 363 : * @param {Object.<String, Object>} headerParams A map of header parameters and their values.
  364. 364 : * @param {Object.<String, Object>} formParams A map of form parameters and their values.
  365. 365 : * @param {Object} bodyParam The value to pass as the request body.
  366. 366 : * @param {Array.<String>} authNames An array of authentication type names.
  367. 367 : * @param {Array.<String>} contentTypes An array of request MIME types.
  368. 368 : * @param {Array.<String>} accepts An array of acceptable response MIME types.
  369. 369 : * @param {(String|Array|ObjectFunction)} returnType The required type to return; can be a string for simple types or the
  370. 370 : * constructor for a complex type.
  371. 371 : * @param {module:ApiClient~callApiCallback} callback The callback function.
  372. 372 : * @returns {Object} The SuperAgent request object.
  373. 373 : */
  374. 374 : exports.prototype.callApi = function callApi(path, httpMethod, pathParams,
  375. 375 : queryParams, headerParams, formParams, bodyParam, authNames, contentTypes, accepts,
  376. 376 : returnType, callback) {
  377. 377 :
  378. 378 : var _this = this;
  379. 379 : var url = this.buildUrl(path, pathParams);
  380. 380 : logger.debug('HTTP URL: ' + url);
  381. 381 : logger.debug('HTTP Method: ' + httpMethod);
  382. 382 :
  383. 383 : // added by us
  384. 384 :
  385. 385 : var resourcePath = this.resourcePath(path, pathParams);
  386. 386 :
  387. 387 : if(this.clientApiKey == null || this.clientApiKey == ''){
  388. 388 : this.clientApiKey = headerParams['client_key'];
  389. 389 : }
  390. 390 :
  391. 391 : if(this.authScheme == null || this.authScheme == '' || this.authScheme == 'OPAY1-HMAC-SHA256'){
  392. 392 : var authorizationData = exports.computeOPAY1HMACSHA256Hash(resourcePath, httpMethod, queryParams, headerParams, formParams, bodyParam, this.clientSignatureKey);
  393. 393 : var clientHash = authorizationData['hash'];
  394. 394 : headerParams['Authorization'] = 'OPAY1-HMAC-SHA256 Credential=' + this.clientApiKey + ',Signature=' + clientHash.trim() + '';
  395. 395 : }else if(this.authScheme == 'OPAY2-HMAC-SHA256'){
  396. 396 : var authorizationData = exports.computeOPAY2HMACSHA256Hash(headerParams['client_key'], this.clientApiKey,this.clientSignatureKey, headerParams['timestamp']);
  397. 397 : var clientHash = authorizationData['hash'];
  398. 398 : headerParams['Authorization'] = 'OPAY2-HMAC-SHA256 Credential=' + this.clientApiKey + ',Signature=' + clientHash.trim() + '';
  399. 399 : }else if(this.authScheme == 'OPAY3-HMAC-SHA256'){
  400. 400 : headerParams['Authorization'] = 'OPAY3-HMAC-SHA256 Credential=' + this.clientApiKey;
  401. 401 : }else{
  402. 402 : logger.debug('invalid auth_scheme received');
  403. 403 : throw new Error('invalid auth_scheme received');
  404. 404 : }
  405. 405 : headerParams['User-Agent'] = 'orbipay-paymentsapi-client/1.14.0/Node';
  406. 406 :
  407. 407 : var request = superagent(httpMethod, url);
  408. 408 : // apply authentications
  409. 409 : this.applyAuthToRequest(request, authNames);
  410. 410 :
  411. 411 : // set query parameters
  412. 412 : if (httpMethod.toUpperCase() === 'GET' && this.cache === false) {
  413. 413 : queryParams['_'] = new Date().getTime();
  414. 414 : }
  415. 415 : request.query(this.normalizeParams(queryParams));
  416. 416 : logger.debug('Query Params: ', JSON.stringify(queryParams));
  417. 417 : // set header parameters
  418. 418 : request.set(this.defaultHeaders).set(this.normalizeParams(headerParams));
  419. 419 : logger.debug('Request Headers: ', JSON.stringify(headerParams));
  420. 420 :
  421. 421 : logger.debug('Request Body: ', JSON.stringify(bodyParam, CommonUtil.maskSensitiveInfo));
  422. 422 :
  423. 423 : // set requestAgent if it is set by user
  424. 424 : if (this.requestAgent) {
  425. 425 : request.agent(this.requestAgent);
  426. 426 : }
  427. 427 :
  428. 428 : if (process.env['ORBIPAY_PAYMENTS_API_TIMEOUT_SECONDS']) {
  429. 429 : this.timeout = process.env['ORBIPAY_PAYMENTS_API_TIMEOUT_SECONDS'];
  430. 430 : logger.debug('HTTP TIMEOUT in seconds : ' + this.timeout);
  431. 431 : }
  432. 432 : else{
  433. 433 : logger.warn('Timeout environment variable, ORBIPAY_PAYMENTS_API_TIMEOUT_SECONDS is not found setting default value in seconds: ', this.timeout);
  434. 434 : }
  435. 435 :
  436. 436 : request.timeout(this.timeout*1000);
  437. 437 :
  438. 438 : var contentType = this.jsonPreferredMime(contentTypes);
  439. 439 : if (contentType) {
  440. 440 : // Issue with superagent and multipart/form-data (https://github.com/visionmedia/superagent/issues/746)
  441. 441 : if(contentType !== 'multipart/form-data') {
  442. 442 : request.type(contentType);
  443. 443 : }
  444. 444 : } else if (!request.header['Content-Type']) {
  445. 445 : request.type('application/json');
  446. 446 : }
  447. 447 :
  448. 448 : if (contentType === 'application/x-www-form-urlencoded') {
  449. 449 : request.send(querystring.stringify(this.normalizeParams(formParams)));
  450. 450 : } else if (contentType === 'multipart/form-data') {
  451. 451 : var _formParams = this.normalizeParams(formParams);
  452. 452 : for (var formParamKey in _formParams) {
  453. 453 : if (_formParams.hasOwnProperty(formParamKey)) {
  454. 454 : if (this.isFileParam(_formParams[formParamKey])) {
  455. 455 : // file field
  456. 456 : request.attach(formParamKey, _formParams[formParamKey]);
  457. 457 : } else {
  458. 458 : request.field(formParamKey, _formParams[formParamKey]);
  459. 459 : }
  460. 460 : }
  461. 461 : }
  462. 462 : } else if (bodyParam) {
  463. 463 : request.send(bodyParam);
  464. 464 : }
  465. 465 :
  466. 466 : var accept = this.jsonPreferredMime(accepts);
  467. 467 : if (accept) {
  468. 468 : request.accept(accept);
  469. 469 : }
  470. 470 :
  471. 471 : if (returnType === 'Blob') {
  472. 472 : request.responseType('blob');
  473. 473 : } else if (returnType === 'String') {
  474. 474 : request.responseType('string');
  475. 475 : }
  476. 476 :
  477. 477 : // Attach previously saved cookies, if enabled
  478. 478 : if (this.enableCookies){
  479. 479 : if (typeof window === 'undefined') {
  480. 480 : this.agent.attachCookies(request);
  481. 481 : }
  482. 482 : else {
  483. 483 : request.withCredentials();
  484. 484 : }
  485. 485 : }
  486. 486 :
  487. 487 :
  488. 488 : if (callback) {
  489. 489 : logger.info('Sending Request to Service');
  490. 490 : request.end(function (error, response) {
  491. 491 : var data = null;
  492. 492 : if (!error) {
  493. 493 : try {
  494. 494 : data = _this.deserialize(response, returnType);
  495. 495 : logger.info('Receive Response from Service : HTTP Status Code :', response.status);
  496. 496 : logger.debug('HTTP Response Body :', JSON.stringify(data, CommonUtil.maskSensitiveInfo));
  497. 497 : if (_this.enableCookies && typeof window === 'undefined') {
  498. 498 : _this.agent.saveCookies(response);
  499. 499 : }
  500. 500 : } catch (err) {
  501. 501 : error = err;
  502. 502 : }
  503. 503 : }
  504. 504 :
  505. 505 : if (error) {
  506. 506 : logger.info('Receive Response from Service : HTTP Status Code :', error.status);
  507. 507 : logger.error('HTTP Error code :', error.code);
  508. 508 : logger.error('HTTP Error errno :', error.errno);
  509. 509 : logger.error('HTTP Error message :', error.message);
  510. 510 : if(response && response.text) {
  511. 511 : logger.debug('HTTP Response Body :', response.text);
  512. 512 : }
  513. 513 : else{
  514. 514 : logger.warn('HTTP Body is not received ');
  515. 515 : }
  516. 516 : }
  517. 517 : response = response || {};
  518. 518 : logger.debug('Response Headers :', JSON.stringify(response['header']));
  519. 519 : if(response['header']) {
  520. 520 : logger.info('request_uuid :', response['header']['request_uuid']);
  521. 521 : }
  522. 522 : callback(error, data, response);
  523. 523 : });
  524. 524 : }
  525. 525 :
  526. 526 : return request;
  527. 527 : };
  528. 528 :
  529. 529 : /**
  530. 530 : * Parses an ISO-8601 string representation of a date value.
  531. 531 : * @param {String} str The date value as a string.
  532. 532 : * @returns {Date} The parsed date object.
  533. 533 : */
  534. 534 : exports.parseDate = function(str) {
  535. 535 : return new Date(str.replace(/T/i, ' '));
  536. 536 : };
  537. 537 :
  538. 538 : /**
  539. 539 : * Converts a value to the specified type.
  540. 540 : * @param {(String|Object)} data The data to convert, as a string or object.
  541. 541 : * @param {(String|Array.<String>|Object.<String, Object>|Function)} type The type to return. Pass a string for simple types
  542. 542 : * or the constructor function for a complex type. Pass an array containing the type name to return an array of that type. To
  543. 543 : * return an object, pass an object with one property whose name is the key type and whose value is the corresponding value type:
  544. 544 : * all properties on <code>data<code> will be converted to this type.
  545. 545 : * @returns An instance of the specified type or null or undefined if data is null or undefined.
  546. 546 : */
  547. 547 : exports.convertToType = function(data, type) {
  548. 548 : if (data === null || data === undefined)
  549. 549 : return data;
  550. 550 :
  551. 551 : switch (type) {
  552. 552 : case 'Boolean':
  553. 553 : return Boolean(data);
  554. 554 : case 'Integer':
  555. 555 : return parseInt(data, 10);
  556. 556 : case 'Number':
  557. 557 : return parseFloat(data);
  558. 558 : case 'String':
  559. 559 : if(typeof data === 'string'){
  560. 560 : return String(data);
  561. 561 : }
  562. 562 : else{
  563. 563 : return data;
  564. 564 : }
  565. 565 : case 'Date':
  566. 566 : return this.parseDate(String(data));
  567. 567 : case 'Blob':
  568. 568 : return data;
  569. 569 : default:
  570. 570 : if (type === Object) {
  571. 571 : // generic object, return directly
  572. 572 : return data;
  573. 573 : } else if (typeof type === 'function') {
  574. 574 : // for model type like: User
  575. 575 : return type.constructFromObject(data);
  576. 576 : } else if (Array.isArray(type)) {
  577. 577 : // for array type like: ['String']
  578. 578 : var itemType = type[0];
  579. 579 : return data.map(function(item) {
  580. 580 : return exports.convertToType(item, itemType);
  581. 581 : });
  582. 582 : } else if (typeof type === 'object') {
  583. 583 : // for plain object type like: {'String': 'Integer'}
  584. 584 : var keyType, valueType;
  585. 585 : for (var j in type) {
  586. 586 : if (type.hasOwnProperty(j)) {
  587. 587 : keyType = j;
  588. 588 : valueType = type[j];
  589. 589 : break;
  590. 590 : }
  591. 591 : }
  592. 592 : var result = {};
  593. 593 : for (var k in data) {
  594. 594 : if (data.hasOwnProperty(k)) {
  595. 595 : var key = exports.convertToType(k, keyType);
  596. 596 : var value = exports.convertToType(data[k], valueType);
  597. 597 : result[key] = value;
  598. 598 : }
  599. 599 : }
  600. 600 : return result;
  601. 601 : } else {
  602. 602 : // for unknown type, return the data directly
  603. 603 : return data;
  604. 604 : }
  605. 605 : }
  606. 606 : };
  607. 607 :
  608. 608 : /**
  609. 609 : * Constructs a new map or array model from REST data.
  610. 610 : * @param data {Object|Array} The REST data.
  611. 611 : * @param obj {Object|Array} The target object or array.
  612. 612 : */
  613. 613 : exports.constructFromObject = function(data, obj, itemType) {
  614. 614 : if (Array.isArray(data)) {
  615. 615 : for (var i = 0; i < data.length; i++) {
  616. 616 : if (data.hasOwnProperty(i))
  617. 617 : obj[i] = exports.convertToType(data[i], itemType);
  618. 618 : }
  619. 619 : } else {
  620. 620 : for (var k in data) {
  621. 621 : if (data.hasOwnProperty(k))
  622. 622 : obj[k] = exports.convertToType(data[k], itemType);
  623. 623 : }
  624. 624 : }
  625. 625 : };
  626. 626 :
  627. 627 : exports.prototype.resourcePath = function (path, pathParams) {
  628. 628 : if (!path.match(/^\//)) {
  629. 629 : path = '/' + path;
  630. 630 : }
  631. 631 : var url = path;
  632. 632 : var _this = this;
  633. 633 : url = url.replace(/{([\w-]+)}/g, function (fullMatch, key) {
  634. 634 : var value;
  635. 635 : if (pathParams.hasOwnProperty(key)) {
  636. 636 : value = _this.paramToString(pathParams[key]);
  637. 637 : } else {
  638. 638 : value = fullMatch;
  639. 639 : }
  640. 640 : return encodeURIComponent(value);
  641. 641 : });
  642. 642 : return url;
  643. 643 : };
  644. 644 :
  645. 645 : exports.getFormString = function (params) {
  646. 646 : var key;
  647. 647 : var response = {};
  648. 648 : var paramString = '';
  649. 649 : var logArray = [];
  650. 650 :
  651. 651 : for (key in params) {
  652. 652 : if (params.hasOwnProperty(key)) {
  653. 653 : var value = params[key];
  654. 654 : if (Array.isArray(value)) {
  655. 655 : for (var k in value) {
  656. 656 : if (value.hasOwnProperty(k)) {
  657. 657 : var v = value[k];
  658. 658 : if (!exports.isNullOrUndefined(v)) {
  659. 659 : paramString = paramString + (key.trim() + '=' + v) + '&';
  660. 660 : logArray.push({
  661. 661 : 'key': key,
  662. 662 : 'value': v
  663. 663 : });
  664. 664 : }
  665. 665 : }
  666. 666 : }
  667. 667 : } else {
  668. 668 : if (!exports.isNullOrUndefined(value)) {
  669. 669 : paramString = paramString + (key + '=' + value) + '&';
  670. 670 : logArray.push({
  671. 671 : 'key': key,
  672. 672 : 'value': value
  673. 673 : });
  674. 674 : }
  675. 675 : }
  676. 676 : }
  677. 677 : }
  678. 678 : response['paramString'] = paramString.substring(0, paramString.length - 1);
  679. 679 : response['logArray'] = logArray;
  680. 680 :
  681. 681 : return response;
  682. 682 : };
  683. 683 :
  684. 684 :
  685. 685 : exports.isNullOrUndefined = function (data) {
  686. 686 : return (typeof(data) === 'undefined' || data === null);
  687. 687 : };
  688. 688 :
  689. 689 :
  690. 690 : exports.isEmptyString = function (string) {
  691. 691 : return (string === undefined || string === null || string === '');
  692. 692 : };
  693. 693 :
  694. 694 : exports.getQueryString = function (inparams) {
  695. 695 : var key;
  696. 696 : var trimmedValue;
  697. 697 : var paramString = '';
  698. 698 : var filteredKeys = [];
  699. 699 : var params = {};
  700. 700 :
  701. 701 : for (key in inparams) {
  702. 702 : if (inparams.hasOwnProperty(key) && !exports.isEmptyString(key) && !exports.isEmptyString(key.trim()) && inparams[key] !== undefined && inparams[key] !== null) {
  703. 703 : params[key.trim()] = inparams[key];
  704. 704 : filteredKeys.push(key.trim());
  705. 705 : }
  706. 706 : }
  707. 707 :
  708. 708 : //sorting Keys
  709. 709 : filteredKeys.sort();
  710. 710 :
  711. 711 : for (var i = 0; i < filteredKeys.length; i++) {
  712. 712 : key = filteredKeys[i];
  713. 713 : var value = params[key];
  714. 714 : if (Array.isArray(value)) {
  715. 715 :
  716. 716 : value = value.map(Function.prototype.call, String.prototype.trim);
  717. 717 :
  718. 718 : //sorting values
  719. 719 : value.sort();
  720. 720 :
  721. 721 : for (var k in value) {
  722. 722 : if (value.hasOwnProperty(k)) {
  723. 723 : var v = value[k];
  724. 724 : if (!exports.isEmptyString(v)) {
  725. 725 : trimmedValue = v.trim();
  726. 726 : if (!exports.isEmptyString(trimmedValue)) {
  727. 727 : paramString = paramString + (key.trim() + '=' + trimmedValue) + '&';
  728. 728 : }
  729. 729 : }
  730. 730 : }
  731. 731 : }
  732. 732 :
  733. 733 : } else {
  734. 734 : if (!exports.isEmptyString(value)) {
  735. 735 : trimmedValue = value.trim();
  736. 736 : if (!exports.isEmptyString(trimmedValue)) {
  737. 737 : paramString = paramString + (key.trim() + '=' + trimmedValue) + '&';
  738. 738 : }
  739. 739 : }
  740. 740 : }
  741. 741 : }
  742. 742 : return paramString.substring(0, paramString.length - 1);
  743. 743 : };
  744. 744 :
  745. 745 : exports.getHeaderString = function (inparams) {
  746. 746 : var key;
  747. 747 : var trimmedValue;
  748. 748 : var paramString = '';
  749. 749 : var filteredKeys = [];
  750. 750 : var params = {};
  751. 751 :
  752. 752 : for (key in inparams) {
  753. 753 : if (inparams.hasOwnProperty(key) && !exports.isEmptyString(key) && !exports.isEmptyString(key.trim()) && exports.isValidHeaderParam(key.trim()) && inparams[key] !== undefined && inparams[key] !== null) {
  754. 754 : params[key.trim()] = inparams[key];
  755. 755 : filteredKeys.push(key.trim());
  756. 756 : }
  757. 757 : }
  758. 758 :
  759. 759 : //sorting Keys
  760. 760 : filteredKeys.sort();
  761. 761 :
  762. 762 : for (var i = 0; i < filteredKeys.length; i++) {
  763. 763 : key = filteredKeys[i];
  764. 764 : var value = params[key];
  765. 765 : if (!exports.isEmptyString(value)) {
  766. 766 : trimmedValue = value.trim();
  767. 767 : if (!exports.isEmptyString(trimmedValue)) {
  768. 768 : paramString = paramString + (key.trim() + '=' + trimmedValue) + '&';
  769. 769 : }
  770. 770 : }
  771. 771 : }
  772. 772 : return paramString.substring(0, paramString.length - 1);
  773. 773 : };
  774. 774 :
  775. 775 : exports.computeOPAY1HMACSHA256Hash = function (resourcePath, method, queryParams, headerParams, formParams, body, signatureKey) {
  776. 776 : if(signatureKey == null || signatureKey == '' ){
  777. 777 : throw new Error('Invalid value for secret');
  778. 778 : }
  779. 779 : var textToHash = '';
  780. 780 : textToHash = textToHash + method.toUpperCase() + ':';
  781. 781 : textToHash = textToHash + '/payments/v1' + decodeURIComponent(resourcePath) + ':';
  782. 782 : textToHash = textToHash + exports.getQueryString(queryParams) + ':';
  783. 783 : textToHash = textToHash + exports.getHeaderString(headerParams) + ':';
  784. 784 :
  785. 785 : if (exports.isNonEmptyObject(body)) {
  786. 786 : textToHash = textToHash + JSON.stringify(body);
  787. 787 : logger.debug('HTTP Request Body :', JSON.stringify(body, CommonUtil.maskSensitiveInfo));
  788. 788 : } else {
  789. 789 : var formData = exports.getFormString(formParams);
  790. 790 : textToHash = textToHash + formData['paramString'];
  791. 791 : logger.debug('Form Params :', CommonUtil.maskSensitiveFormParams(formData['logArray']));
  792. 792 : }
  793. 793 :
  794. 794 : var hash = exports.generateHmacHash(signatureKey, textToHash).trim();
  795. 795 :
  796. 796 : var response = {};
  797. 797 :
  798. 798 : response['hash'] = hash;
  799. 799 : return response;
  800. 800 : };
  801. 801 :
  802. 802 : exports.computeOPAY2HMACSHA256Hash = function (clientKey, apiKey, secretKey, timestamp) {
  803. 803 :
  804. 804 : if(secretKey == null || secretKey == '' ){
  805. 805 : throw new Error('Invalid value for secret');
  806. 806 : }
  807. 807 :
  808. 808 : var textToHash = '';
  809. 809 : textToHash = textToHash + clientKey + ':';
  810. 810 : textToHash = textToHash + apiKey + ':';
  811. 811 : textToHash = textToHash + secretKey + ':';
  812. 812 : textToHash = textToHash + timestamp;
  813. 813 :
  814. 814 : var hash = exports.generateHmacHash(secretKey, textToHash).trim();
  815. 815 :
  816. 816 : var response = {};
  817. 817 :
  818. 818 : response['hash'] = hash;
  819. 819 : return response;
  820. 820 : };
  821. 821 :
  822. 822 :
  823. 823 : exports.isNonEmptyObject = function (obj) {
  824. 824 : return (obj !== null && typeof obj === 'object' && Object.keys(obj).length > 0);
  825. 825 : };
  826. 826 :
  827. 827 : exports.generateHmacHash = function (key, text) {
  828. 828 : return crypto.createHmac('sha256', new Buffer(key, 'utf-8')).update(new Buffer(text, 'utf-8')).digest('base64');
  829. 829 : };
  830. 830 :
  831. 831 :
  832. 832 : exports.isValidHeaderParam = function (headerParam) {
  833. 833 : return ['product' , 'trace_id' , 'idempotent_request_key' , 'channel' , 'requestor' , 'client_key' , 'X-OPAY-Headers' , 'requestor_type' , 'timestamp'].indexOf(headerParam) !== -1;
  834. 834 : };
  835. 835 :
  836. 836 : /**
  837. 837 : * The default API client implementation.
  838. 838 : * @type {module:ApiClient}
  839. 839 : */
  840. 840 : exports.instance = new exports();
  841. 841 :
  842. 842 : return exports;
  843. 843 : }));