diff --git a/api/fs-provider.js b/api/fs-provider.js new file mode 100644 index 0000000..f9c0f21 --- /dev/null +++ b/api/fs-provider.js @@ -0,0 +1,39 @@ +var fs = require("node:fs"); +/** + * Create directory + * + * @param directory + */ +function mkdirSyncRecursive(directory) { + var path = directory.replace(/\/$/, "").split("/"); + for (var i = 1; i <= path.length; i++) { + var segment = path.slice(0, i).join("/"); + segment.length > 0 && !fs.existsSync(segment) + ? fs.mkdirSync(segment) + : null; + } +} + +class fsProvider { + constructor(path) { + if (!fs.existsSync(path)) { + mkdirSyncRecursive(path); + } + if (path.substr(-1) !== "/") { + path += "/"; + } + this.path = path; + } + getToken(hashName) { + if (fs.existsSync(this.path + hashName)) { + return fs.readFileSync(this.path + hashName, { encoding: "utf8" }); + } else { + return ""; + } + } + setToken(hashName, token) { + fs.writeFileSync(this.path + hashName, token); + } +} + +exports.fsProvider = fsProvider; diff --git a/api/memory-provider.js b/api/memory-provider.js new file mode 100644 index 0000000..d532736 --- /dev/null +++ b/api/memory-provider.js @@ -0,0 +1,13 @@ +class memoryProvider { + constructor() { + this.store = {}; + } + getToken(hashName) { + return this.store[hashName] || ""; + } + setToken(hashName, token) { + return (this.store[hashName] = token); + } +} + +exports.memoryProvider = memoryProvider; diff --git a/api/sendpulse.js b/api/sendpulse.js index ea5e140..2af0681 100644 --- a/api/sendpulse.js +++ b/api/sendpulse.js @@ -10,14 +10,11 @@ 'use strict'; -var https = require('https'); -var crypto = require('crypto'); -var fs = require('fs'); var API_URL = 'api.sendpulse.com'; var API_USER_ID = ''; var API_SECRET = ''; -var TOKEN_STORAGE = ''; +var TOKEN_STORAGE; var TOKEN = ''; var ERRORS = { @@ -27,15 +24,19 @@ var ERRORS = { }; /** - * MD5 + * SHA256 * * @param data * @return string */ -function md5(data) { - var md5sum = crypto.createHash('md5'); - md5sum.update(data); - return md5sum.digest('hex'); +async function sha256(data) { + const encoder = new TextEncoder(); + const dataBuffer = encoder.encode(data); + return crypto.subtle.digest('SHA-256', dataBuffer).then((hashBuffer)=>{ + const hashArray = Array.from(new Uint8Array(hashBuffer)); + const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join(''); + return hashHex; + }); } /** @@ -49,18 +50,6 @@ function base64(data) { return b.toString('base64'); } -/** - * Create directory - * - * @param directory - */ -function mkdirSyncRecursive(directory) { - var path = directory.replace(/\/$/, '').split('/'); - for (var i = 1; i <= path.length; i++) { - var segment = path.slice(0, i).join('/'); - segment.length > 0 && !fs.existsSync(segment) ? fs.mkdirSync(segment) : null; - } -}; /** * Sendpulse API initialization @@ -80,18 +69,8 @@ function init(user_id, secret, storage, callback) { } } - if (!fs.existsSync(TOKEN_STORAGE)) { - mkdirSyncRecursive(TOKEN_STORAGE); - } - - if (TOKEN_STORAGE.substr(-1) !== '/') { - TOKEN_STORAGE += '/'; - } - - var hashName = md5(API_USER_ID + '::' + API_SECRET); - if (fs.existsSync(TOKEN_STORAGE + hashName)) { - TOKEN = fs.readFileSync(TOKEN_STORAGE + hashName, {encoding: 'utf8'}); - } + var hashName = sha256(API_USER_ID + '::' + API_SECRET); + TOKEN = TOKEN_STORAGE.getToken(hashName) if (!TOKEN.length) { getToken(callback); @@ -112,76 +91,56 @@ function init(user_id, secret, storage, callback) { * Define the function that will be called * when a response is received. */ -function sendRequest(path, method, data, useToken, callback) { - var headers = {}; - headers['Content-Type'] = 'application/json'; - headers['Content-Length'] = Buffer.byteLength(JSON.stringify(data)); +function sendRequest(path, method = 'POST', data, useToken = false, callback) { + var headers = { + 'Content-Type': 'application/json', + 'Content-Length': Buffer.byteLength(JSON.stringify(data)).toString(), + }; if (useToken && TOKEN.length) { headers['Authorization'] = 'Bearer ' + TOKEN; } - if (method === undefined) { - method = 'POST'; - } - if (useToken === undefined) { - useToken = false; - } var options = { - //uri: API_URL, - path: '/' + path, - port: 443, - hostname: API_URL, method: method, headers: headers, + body: JSON.stringify(data), }; - var req = https.request( - options, - function (response) { - var str = ''; - response.on('data', function (chunk) { - str += chunk; - }); - - response.on('end', function () { - try { - var answer = JSON.parse(str); - } catch (ex) { - var answer = returnError(ERRORS.INVALID_RESPONSE); + fetch(`https://${API_URL}/${path}`, options) + .then(response => response.text().then(str => { + let answer; + + try { + answer = JSON.parse(str); + } catch (ex) { + answer = returnError(ERRORS.INVALID_RESPONSE); + } + + if (response.status === 401) { + if (answer.error === 'invalid_client') { + callback(returnError(ERRORS.INVALID_CREDENTIALS)); + return; } - if (response.statusCode === 401) { - if (answer.error === 'invalid_client') { - callback(returnError(ERRORS.INVALID_CREDENTIALS)); + getToken(function (result) { + if (result && result.is_error === 1) { + callback(result); return; } - getToken(function (result) { - if (result && result.is_error === 1) { - callback(result); - return; - } - - sendRequest(path, method, data, true, callback); - }); - return; - } + // Рекурсивно вызываем функцию с useToken = true + sendRequest(path, method, data, true, callback); + }); + return; + } - callback(answer); - }); - } - ); - req.write(JSON.stringify(data)); - req.on('error', function (error) { - if (error.message !== undefined) { - var answer = returnError(error.message, error.errno); - } else { - var answer = returnError(error.code, error.errno); - } - callback(answer); - }); - req.end(); + callback(answer); + })) + .catch(error => { + const answer = error.message ? returnError(error.message, error.errno) : returnError(error.code, error.errno); + callback(answer); + }); } /** @@ -207,9 +166,9 @@ function getToken(callback) { return; } - TOKEN = data.access_token; - var hashName = md5(API_USER_ID + '::' + API_SECRET); - fs.writeFileSync(TOKEN_STORAGE + hashName, TOKEN); + TOKEN = data.access_token ?? ""; + var hashName = sha256(API_USER_ID + '::' + API_SECRET); + TOKEN_STORAGE.setToken(hashName, TOKEN); callback(TOKEN) } } diff --git a/example.js b/example.js index ea9ae42..bc4a87b 100644 --- a/example.js +++ b/example.js @@ -5,7 +5,9 @@ * https://sendpulse.com/api */ -var sendpulse = require("sendpulse-api"); +var sendpulse = require("./api/sendpulse"); +// var memoryProvider = require("./api/memory-provider"); +var fsProvider = require("./api/fs-provider"); /* * https://login.sendpulse.com/settings/#api @@ -14,9 +16,10 @@ var sendpulse = require("sendpulse-api"); var API_USER_ID="USER_ID"; var API_SECRET="USER_SECRET"; -var TOKEN_STORAGE="/tmp/"; +var provider = new fsProvider("./tmp/"); +// var provider = new memoryProvider(); -sendpulse.init(API_USER_ID, API_SECRET, TOKEN_STORAGE, function(token) { +sendpulse.init(API_USER_ID, API_SECRET, provider, function(token) { if (token && token.is_error) { // error handling } diff --git a/package.json b/package.json index 57effaf..5a9ecab 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sendpulse-api", - "version": "1.1.7", + "version": "1.1.8", "description": "A simple SendPulse REST client library and example for Node.js", "main": "index.js", "scripts": {