fully-api
Version:
API framework for Fully Stacked, LLC REST-ful APIs
757 lines • 31.6 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Utilities = void 0;
const ErrorObj_1 = require("./ErrorObj");
const mkdirp = require('mkdirp');
const Q = require('q');
const nodemailer = require('nodemailer');
const smtpTransport = require('nodemailer-smtp-transport');
const nodemailerSendgrid = require('nodemailer-sendgrid');
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path")); // Import path to control our folder structure
const crypto = __importStar(require("crypto"));
const rootDir = path_1.default.dirname(require.main.filename);
const async = require('async');
// ===============================================================================
// UTILITY FUNCTIONS
// ===============================================================================
var settings;
var dataAccess;
var eventLog;
var errorLog;
var sessionLog;
var endpoints;
var models;
var mailTransport;
let UtilitiesExtension;
var ext_path = rootDir + '/utilities_ext.js';
var default_path = '../utilities_ext.js';
if (fs_1.default.existsSync(ext_path)) {
try {
UtilitiesExtension = require(ext_path).UtilitiesExtension;
}
catch (e) {
// tslint:disable-next-line:no-console
console.log('Error loading Access control extension. Falling back to default file.', e);
UtilitiesExtension = require(default_path).UtilitiesExtension;
}
}
else {
var ext_path = rootDir + '/services/utilities_ext.js';
if (fs_1.default.existsSync(ext_path)) {
try {
UtilitiesExtension = require(ext_path).UtilitiesExtension;
}
catch (e) {
// tslint:disable-next-line:no-console
console.log('Error loading Access control extension. Falling back to default file.', e);
UtilitiesExtension = require(default_path).UtilitiesExtension;
}
}
else {
try {
console.log('No custom utilities_ext file located. Falling back to default file.');
UtilitiesExtension = require(default_path).UtilitiesExtension;
}
catch (e) {
// tslint:disable-next-line:no-console
console.error("Failed to load default utilities_ext extension", e);
}
}
}
class Utilities {
constructor(s, d, e) {
settings = s;
dataAccess = d;
this.extension = {};
const mailAuth = {};
const mo = settings.data.mail_options;
if (mo) {
if (mo.user)
mailAuth.user = mo.user;
if (mo.pass)
mailAuth.pass = mo.pass;
if (mo.api_key)
mailAuth.api_key = mo.api_key;
let options = {};
if (mo.service) {
// SEND GRID WANTS ONLY THE API KEY IN THE AUTH FIELD IF AVAILABLE
if (mo.service.toLowerCase() === 'sendgrid' && mailAuth.api_key) {
if ([])
mailTransport = nodemailer.createTransport(nodemailerSendgrid({ apiKey: mailAuth.api_key }));
}
else {
options = {
service: mo.service,
auth: mailAuth
};
if (mo.port) {
options.port = mo.port;
}
if (mo.tls) {
options.tls = mo.tls;
}
mailTransport = nodemailer.createTransport(smtpTransport(options));
}
}
else {
options = {
host: mo.host,
port: mo.port,
auth: mailAuth
};
if (mo.tls) {
options.tls = mo.tls;
}
mailTransport = nodemailer.createTransport(smtpTransport(options));
}
}
}
getHash(alg, data, length) {
const deferred = Q.defer();
if (alg == null)
alg = 'sha256';
const h = crypto.createHash(alg);
const byteCount = length || 10;
if (data == null)
data = crypto.randomBytes(byteCount);
h.update(data);
let digest = h.digest('hex');
if (length != null)
digest = digest.substring(0, length);
deferred.resolve(digest);
return deferred.promise;
}
emailFormatValid(email) {
const validEmailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return !validEmailRegex.test(email);
}
getDataAccess() {
return dataAccess;
}
getEndpointData() {
return endpoints;
}
setEndpointData(e) {
endpoints = e;
}
setModelsData(m) {
models = m;
}
getModelsData() {
return models;
}
setDataAccess(da) {
dataAccess = da;
if (this.extension !== undefined && this.extension !== null) {
this.extension = new UtilitiesExtension(this, da, settings);
}
}
;
setLogs(evl, erl, sesl) {
eventLog = evl;
errorLog = erl;
sessionLog = sesl;
}
validateUsername(newUsername, existingUsername) {
const deferred = Q.defer();
if (newUsername === existingUsername) {
deferred.resolve();
}
else {
dataAccess.getUserByUserName(newUsername)
.then(function (userFound) {
const errorObj = new ErrorObj_1.ErrorObj(400, 'u0053', __filename, 'bsuser', 'a user already exists with the username provided');
deferred.reject(errorObj);
})
.fail(function (err) {
deferred.resolve();
});
}
return deferred.promise;
}
validateEmail(newEmail, existingEmail) {
const deferred = Q.defer();
if (newEmail === existingEmail) {
deferred.resolve();
}
else {
dataAccess.getUserByEmail(newEmail)
.then(function (userFound) {
const errorObj = new ErrorObj_1.ErrorObj(400, 'u0054', __filename, 'bsuser', 'a bsuser already exists with the email provided');
deferred.reject(errorObj);
})
.fail(function (err) {
if (err.err_code == 'da2001') {
// THERE WERE MULTIPLE ACCOUNTS FOUND WITH THIS EMAIL
// IN A PREVIOUS VERSION OF BS ACCOUNTS WERE ABLE TO SHARE EMAILS
const errorObj = new ErrorObj_1.ErrorObj(400, 'u0055', __filename, 'bsuser', 'a bsuser already exists with the email provided', err);
deferred.reject(errorObj);
}
else {
deferred.resolve();
}
});
}
return deferred.promise;
}
getUserFromApiToken(apiTkn, callback) {
const deferred = Q.defer();
dataAccess.findOne('session', { 'object_type': 'session', 'token': apiTkn })
.then(function (sessionObj) {
if (sessionObj.is_anonymous) {
return { 'object_type': 'bsuser', 'username': 'anonymous' };
}
else {
return dataAccess.findOne('bsuser', { 'object_type': 'bsuser', 'username': sessionObj.username });
}
})
.then(function (userObj) {
deferred.resolve(userObj);
})
.fail(function (err) {
// ADD LOGGING HERE?
if (err !== undefined && err !== null && typeof (err.addToError) === 'function') {
deferred.reject(err.addToError(__filename, 'getUserFromApiToken'));
}
else {
const errorObj = new ErrorObj_1.ErrorObj(500, 'u1001', __filename, 'getUserFromApiToken', 'error getting user from api token', 'Error getting user from api token', err);
deferred.reject(errorObj);
}
});
deferred.promise.nodeify(callback);
return deferred.promise;
}
;
FormatStackTraceMessage(verb, objType, versionExtension) {
return { 'class': objType + versionExtension, 'function': verb + ' ' + objType };
}
;
GetUrlForS3(obj, callback) {
const deferred = Q.defer();
const params = { Bucket: obj.resources.s3.bucket, Key: obj.resources.s3.name };
obj.resources.s3.getSignedUrl('getObject', params, function (s3_err, s3_res) {
if (!s3_err) {
deferred.resolve(s3_res);
}
else {
const errorObj = new ErrorObj_1.ErrorObj(500, 'u0001', __filename, 'GetUrlForS3', 'error getting url from s3', 'S3 error', s3_err);
deferred.reject(errorObj);
}
});
deferred.promise.nodeify(callback);
return deferred.promise;
}
;
GetValidationModel() {
return {
'success': false,
Message: '',
ValidatedObject: null
};
}
;
requestHasHeaders(req) {
return req.headers[settings.data.token_header] !== undefined && req.headers[settings.data.token_header] !== null;
}
;
isNullOrUndefinedOrZeroLength(meVar) {
return (meVar == null || meVar.length === 0 || meVar == undefined || typeof (meVar) === 'undefined');
}
;
isNullOrUndefined(meVar) {
return (meVar == null || meVar == undefined || typeof (meVar) === 'undefined');
}
;
validateBase64(stringData) {
let isValid = false;
let base64only = /^[a-zA-Z0-9\/\+]*={0,2}$/;
const remainder = stringData.length % 4;
switch (remainder) {
case 0:
// DIVISIBLE BY 4. EITHER PADDED OR LENGTH WAS PERFECT.
base64only = /^[a-zA-Z0-9\/\+]*={0,2}$/;
isValid = base64only.test(stringData);
break;
case 1:
// ERROR
isValid = false;
break;
case 2:
case 3:
base64only = /^[a-zA-Z0-9\/\+]*$/;
isValid = base64only.test(stringData);
break;
default:
isValid = false;
}
return isValid;
}
ClassAndModelInfo(directoryName, fileName) {
const className = path_1.default.basename(fileName);
const toRemove = directoryName.substring(0, directoryName.indexOf('helpers') + 9);
let version = directoryName.replace(toRemove, '');
version = version.replace('_', '.');
version = version.replace('_', '.');
return {
Class: className,
Model: className.replace('.js', '') + ' ' + version,
Version: version
};
}
;
getDirectoryFromDistNPM(realative_path) {
let path = rootDir + "/" + realative_path;
try {
if (fs_1.default.existsSync(path)) {
return path;
}
else {
let base;
if (rootDir.includes('/src')) {
base = (rootDir.split('src'))[0];
}
else if (rootDir.includes('/dist')) {
base = (rootDir.split('dist'))[0];
}
else {
base = rootDir;
}
if (realative_path.startsWith('./')) {
realative_path = (realative_path.split('./'))[1];
}
path = base + "/node_modules/fully-api/dist/" + realative_path;
if (fs_1.default.existsSync(path)) {
return path;
}
else {
console.log("No valid directory found, last path attempted", path);
console.log("No valid directory found, initial path attempted", (rootDir + "/" + realative_path));
return null;
}
}
}
catch (e) {
console.log('Error validating direcotry path: ', e);
return null;
}
}
;
copyFile(file_to_copy, destination_path) {
const deferred = Q.defer();
try {
fs_1.default.createReadStream(file_to_copy).pipe(fs_1.default.createWriteStream(destination_path));
deferred.resolve({ 'success': true });
}
catch (err) {
const errorObj = new ErrorObj_1.ErrorObj(500, 'u0002', __filename, 'copyFile', 'error with fs.createReadStream', 'External error', err);
deferred.reject(errorObj);
}
return deferred.promise;
}
;
writeToFile(file_path, strData) {
const deferred = Q.defer();
fs_1.default.writeFile(file_path, strData, function (write_err) {
if (write_err) {
const errorObj = new ErrorObj_1.ErrorObj(500, 'u0005', __filename, 'writeToFile', 'error with fs.writeToFile', 'External error', write_err);
deferred.reject(errorObj);
}
else {
deferred.resolve(true);
}
});
return deferred.promise;
}
;
getFileStream(file_to_copy) {
const deferred = Q.defer();
const getFs = fs_1.default.createReadStream(file_to_copy);
getFs.on("error", function (err) {
const errorObj = new ErrorObj_1.ErrorObj(500, 'u0003', __filename, 'getFileStream', 'error with fs.createReadStream', 'External error', err);
deferred.reject(errorObj);
});
getFs.on("open", function (err) {
deferred.resolve(getFs);
});
return deferred.promise;
}
;
getWriteFileStream(destination_path) {
const deferred = Q.defer();
const writeFs = fs_1.default.createWriteStream(destination_path);
writeFs.on("error", function (err) {
const errorObj = new ErrorObj_1.ErrorObj(500, 'u0004', __filename, 'getWriteFileStream', 'error with fs.createWriteStream', 'External error', err);
deferred.reject(errorObj);
});
writeFs.on("open", function (ex) {
deferred.resolve(writeFs);
});
return deferred.promise;
}
;
writeBinaryToFile(file_path, strData) {
const deferred = Q.defer();
mkdirp(path_1.default.dirname(file_path), function (err) {
if (!err) {
fs_1.default.writeFile(file_path, strData, 'binary', function (write_err) {
if (write_err) {
const errorObj = new ErrorObj_1.ErrorObj(500, 'u0006', __filename, 'writeBinaryToFile', 'error with fs.writeToFile', 'External error', write_err);
deferred.reject(errorObj);
}
else {
deferred.resolve(true);
}
});
}
else {
const errorObj = new ErrorObj_1.ErrorObj(500, 'u0007', __filename, 'writeToFile', 'error with mkdirp', 'External error', err);
deferred.reject(errorObj);
}
});
return deferred.promise;
}
;
writeErrorToLog(errObj) {
const deferred = Q.defer();
const logEntry = JSON.stringify(errObj) + '\n';
const writeToLog = Q.denodeify(errorLog.write);
writeToLog(logEntry)
.then(function (write_res) {
deferred.resolve();
})
.fail(function (write_err) {
deferred.reject(write_err);
});
return deferred.promise;
}
;
sendMail(send_to, sbj, bdy, html_bdy, callback) {
const deferred = Q.defer();
const mailOptions = {
from: settings.data.mail_options.account,
to: send_to,
subject: sbj,
text: bdy,
html: html_bdy
};
mailTransport.sendMail(mailOptions, function (email_err, email_res) {
if (!email_err) {
deferred.resolve(email_res);
}
else {
const errorObj = new ErrorObj_1.ErrorObj(500, 'u0009', __filename, 'sendMail', 'error with mailTransport.sendMail', 'External error', email_err);
deferred.reject(errorObj);
}
});
deferred.promise.nodeify(callback);
return deferred.promise;
}
;
sendMailTemplate(send_to, sbj, template_name, args, callback) {
const deferred = Q.defer();
if (template_name === undefined || template_name === null) {
template_name = 'default';
}
if (args === undefined || args === null) {
args = {};
}
let templatePath = rootDir + '/' + settings.data.mail_options.template_directory + template_name;
// let templatePath = path.resolve(__dirname, settings.data.mail_options.template_directory + template_name);
let txtPath = templatePath + '.txt';
let htmlPath = templatePath + '.html';
let foundTxt = true;
let foundHtml = true;
try {
fs_1.default.accessSync(txtPath);
}
catch (e) {
foundTxt = false;
}
try {
fs_1.default.accessSync(htmlPath);
}
catch (e) {
foundHtml = false;
}
let txtBody = '';
let htmlBody = '';
if (foundTxt && foundHtml) {
fs_1.default.readFile(txtPath, 'utf8', function (txt_err, txt_data) {
if (!txt_err) {
txtBody = Utilities.prototype.replaceTemplateValues(txt_data, args);
fs_1.default.readFile(htmlPath, 'utf8', function (html_err, html_data) {
if (!html_err) {
htmlBody = Utilities.prototype.replaceTemplateValues(html_data, args);
const mailOptions = {
from: settings.data.mail_options.account,
to: send_to,
subject: sbj,
text: txtBody,
html: htmlBody
};
mailTransport.sendMail(mailOptions, function (email_err, email_res) {
if (!email_err) {
deferred.resolve(email_res);
}
else {
const errorObj = new ErrorObj_1.ErrorObj(500, 'u0011', __filename, 'sendMailTemplate', 'error with mailTransport.sendMail', 'External error', email_err);
deferred.reject(errorObj);
}
});
}
else {
// SOMETHING WENT WRONG WHILE READING THE HTML TEMPLATE
const errorObj = new ErrorObj_1.ErrorObj(500, 'u0012', __filename, 'sendMailTemplate', 'error reading html template', 'There was a problem getting the html template for this email', html_err);
deferred.reject(errorObj);
}
});
}
else {
// SOMETHING WENT WRONG WHILE READING THE TXT TEMPLATE
const errorObj = new ErrorObj_1.ErrorObj(500, 'u0013', __filename, 'sendMailTemplate', 'error reading text template', 'There was a problem getting the text template for this email', txt_err);
deferred.reject(errorObj);
}
});
}
else if (foundTxt) {
fs_1.default.readFile(txtPath, 'utf8', function (txt_err, txt_data) {
if (!txt_err) {
txtBody = Utilities.prototype.replaceTemplateValues(txt_data, args);
const mailOptions = {
from: settings.data.mail_options.account,
to: send_to,
subject: sbj,
text: txtBody
};
mailTransport.sendMail(mailOptions, function (email_err, email_res) {
if (!email_err) {
deferred.resolve(email_res);
}
else {
const errorObj = new ErrorObj_1.ErrorObj(500, 'u0014', __filename, 'sendMailTemplate', 'error with mailTransport.sendMail', 'External error', email_err);
deferred.reject(errorObj);
}
});
}
else {
// SOMETHING WENT WRONG WHILE READING THE TXT TEMPLATE
const errorObj = new ErrorObj_1.ErrorObj(500, 'u0015', __filename, 'sendMailTemplate', 'error reading text template', 'There was a problem getting the text template for this email', txt_err);
deferred.reject(errorObj);
}
});
}
else if (foundHtml) {
fs_1.default.readFile(htmlPath, 'utf8', function (html_err, html_data) {
if (!html_err) {
htmlBody = Utilities.prototype.replaceTemplateValues(html_data, args);
const mailOptions = {
from: settings.data.mail_options.account,
to: send_to,
subject: sbj,
html: htmlBody
};
mailTransport.sendMail(mailOptions, function (email_err, email_res) {
if (!email_err) {
deferred.resolve(email_res);
}
else {
const errorObj = new ErrorObj_1.ErrorObj(500, 'u0016', __filename, 'sendMailTemplate', 'error with mailTransport.sendMail', 'External error', email_err);
deferred.reject(errorObj);
}
});
}
else {
// SOMETHING WENT WRONG WHILE READING THE HTML TEMPLATE
const errorObj = new ErrorObj_1.ErrorObj(500, 'u0017', __filename, 'sendMailTemplate', 'error reading html template', 'There was a problem getting the html template for this email', html_err);
deferred.reject(errorObj);
}
});
}
else {
// WE COULDN'T FIND THIS TEMPLATE. TRY USING THE DEFAULT
templatePath = settings.data.mail_options.template_directory + 'default';
txtPath = templatePath + '.txt';
htmlPath = templatePath + '.html';
fs_1.default.readFile(txtPath, 'utf8', function (txt_err, txt_data) {
if (!txt_err) {
txtBody = Utilities.prototype.replaceTemplateValues(txt_data, args);
fs_1.default.readFile(htmlPath, 'utf8', function (html_err, html_data) {
if (!html_err) {
// FOUND BOTH THE TXT AND HTML DEFAULT TEMPLATES
htmlBody = Utilities.prototype.replaceTemplateValues(html_data, args);
const mailOptions = {
from: settings.data.mail_options.account,
to: send_to,
subject: sbj,
text: txtBody,
html: htmlBody
};
mailTransport.sendMail(mailOptions, function (email_err, email_res) {
if (!email_err) {
deferred.resolve(email_res);
}
else {
const errorObj = new ErrorObj_1.ErrorObj(500, 'u0018', __filename, 'sendMailTemplate', 'error with mailTransport.sendMail', 'External error', email_err);
deferred.reject(errorObj);
}
});
}
else {
// FOUND DEFAULT TXT TEMPLATE, BUT NO HTML TEMPLATE
txtBody = Utilities.prototype.replaceTemplateValues(txt_data, args);
const messageOptions = {
from: settings.data.mail_options.account,
to: send_to,
subject: sbj,
text: txtBody
};
mailTransport.sendMail(messageOptions, function (email_err, email_res) {
if (!email_err) {
deferred.resolve(email_res);
}
else {
const errorObj = new ErrorObj_1.ErrorObj(500, 'u0019', __filename, 'sendMailTemplate', 'error with mailTransport.sendMail', 'External error', email_err);
deferred.reject(errorObj);
}
});
}
});
}
else {
fs_1.default.readFile(htmlPath, 'utf8', function (html_err, html_data) {
if (!html_err) {
// FOUND THE HTML DEFAULT TEMPLATE, BUT NO TXT TEMPLATE
htmlBody = Utilities.prototype.replaceTemplateValues(html_data, args);
const mailOptions = {
from: settings.data.mail_options.account,
to: send_to,
subject: sbj,
html: htmlBody
};
mailTransport.sendMail(mailOptions, function (email_err, email_res) {
if (!email_err) {
deferred.resolve(email_res);
}
else {
const errorObj = new ErrorObj_1.ErrorObj(500, 'u0020', __filename, 'sendMailTemplate', 'error with mailTransport.sendMail', 'External error', email_err);
deferred.reject(errorObj);
}
});
}
else {
// FAILED TO FIND DEFAULT TEMPLATE. SEND BACK AN ERROR
const errorObj = new ErrorObj_1.ErrorObj(500, 'u0021', __filename, 'sendMailTemplate', 'no template found', 'There is no email template by this name and no default template', html_err);
deferred.reject(errorObj);
}
});
}
});
}
deferred.promise.nodeify(callback);
return deferred.promise;
}
;
replaceTemplateValues(template, args) {
let updatedTemplate = template;
for (const key in args) {
updatedTemplate = updatedTemplate.replace('{{' + key + '}}', args[key]);
}
return updatedTemplate;
}
getUID(callback) {
const deferred = Q.defer();
const tKey = crypto.randomBytes(12).toString('hex');
const date = new Date();
const dateKey = new Date(date.getFullYear(), date.getMonth(), date.getDay(), date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds());
const token = crypto.createHash("md5").update(tKey + dateKey).digest('hex');
deferred.resolve(token);
deferred.promise.nodeify(callback);
return deferred.promise;
}
;
logEvent(tkn, eventDescriptor) {
const deferred = Q.defer();
const loggedEvent = {
'token': tkn,
'event_data': eventDescriptor
};
const logEntry = JSON.stringify(loggedEvent) + '\n';
eventLog.write(logEntry, () => {
deferred.resolve();
});
return deferred.promise;
}
invalidateSession(sessionObj) {
const deferred = Q.defer();
dataAccess.deleteSessions([sessionObj])
.then(() => {
if (settings.data.session_logging === true) {
const dsObj = {
session_id: sessionObj.id,
token: sessionObj.token,
user_id: sessionObj.user_id,
started_at: sessionObj.started_at,
ended_at: new Date()
};
const logEntry = JSON.stringify(dsObj) + '\n';
sessionLog.write(logEntry);
}
deferred.resolve();
})
.fail((err) => {
deferred.reject(err.addToError(__filename, 'invalidateSession'));
});
return deferred.promise;
}
htmlify(obj, idx = 0) {
const pList = Object.getOwnPropertyNames(obj);
let indentString = '';
for (let iIdx = 0; iIdx < idx; iIdx++) {
indentString += ' ';
}
let newHtmlString = '';
for (let pIdx = 0; pIdx < pList.length; pIdx++) {
const propName = pList[pIdx];
if (typeof (obj[propName]) !== 'object') {
newHtmlString += indentString + propName + ': ' + obj[propName] + '<br />';
}
else if (obj[propName] !== undefined && obj[propName] !== null) {
newHtmlString += indentString + propName + ':<br />';
const nextIdx = idx + 1;
newHtmlString += Utilities.prototype.htmlify(obj[propName], nextIdx);
}
else {
newHtmlString += indentString + propName + ': null' + '<br />';
}
}
if (idx === 0) {
newHtmlString = '<div>' + newHtmlString + '</div>';
}
return newHtmlString;
}
}
exports.Utilities = Utilities;
//# sourceMappingURL=utilities.js.map