Skip to content

support CloudFlare workers environment #49

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions api/fs-provider.js
Original file line number Diff line number Diff line change
@@ -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;
13 changes: 13 additions & 0 deletions api/memory-provider.js
Original file line number Diff line number Diff line change
@@ -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;
139 changes: 49 additions & 90 deletions api/sendpulse.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand All @@ -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;
});
}

/**
Expand All @@ -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
Expand All @@ -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);
Expand All @@ -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);
});
}

/**
Expand All @@ -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)
}
}
Expand Down
9 changes: 6 additions & 3 deletions example.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -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": {
Expand Down