UNPKG

fully-api

Version:

API framework for Fully Stacked, LLC REST-ful APIs

757 lines 31.6 kB
"use strict"; 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 += '&nbsp;&nbsp;&nbsp;&nbsp;'; } 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