UNPKG

jive-sdk

Version:

Node.js SDK for Jive Software to assist with the development of add-ons

922 lines (773 loc) 23.7 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Jive SDK Source: jive-sdk-api/lib/util/jiveutil.js</title> <!--[if lt IE 9]> <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> <link type="text/css" rel="stylesheet" href="styles/sunlight.default.css"> <link type="text/css" rel="stylesheet" href="styles/site.spacelab.css"> </head> <body> <div class="container-fluid"> <div class="navbar navbar-fixed-top navbar-inverse"> <div class="navbar-inner"> <a class="brand" href="index.html">Jive SDK</a> <ul class="nav"> <li class="dropdown"> <a href="modules.list.html" class="dropdown-toggle" data-toggle="dropdown">Modules<b class="caret"></b></a> <ul class="dropdown-menu "> <li> <a href="module-abstractDefinitions.html">abstractDefinitions</a> </li> <li> <a href="module-abstractInstances.html">abstractInstances</a> </li> <li> <a href="module-addOnRoutes.html">addOnRoutes</a> </li> <li> <a href="module-api.html">api</a> </li> <li> <a href="module-community.html">community</a> </li> <li> <a href="module-constants.html">constants</a> </li> <li> <a href="module-devRoutes.html">devRoutes</a> </li> <li> <a href="module-events.html">events</a> </li> <li> <a href="module-extensions.html">extensions</a> </li> <li> <a href="module-extstreamsInstances.html">extstreamsInstances</a> </li> <li> <a href="module-jiveutil.html">jiveutil</a> </li> <li> <a href="module-oauthRoutes.html">oauthRoutes</a> </li> <li> <a href="module-request.html">request</a> </li> <li> <a href="module-security.html">security</a> </li> <li> <a href="module-service.html">service</a> </li> <li> <a href="module-tasks.html">tasks</a> </li> <li> <a href="module-tileInstances.html">tileInstances</a> </li> <li> <a href="module-tileRoutes.html">tileRoutes</a> </li> <li> <a href="module-tilesDefinitions.html">tilesDefinitions</a> </li> <li> <a href="module-webhooks.html">webhooks</a> </li> </ul> </li> <li class="dropdown"> <a href="classes.list.html" class="dropdown-toggle" data-toggle="dropdown">Classes<b class="caret"></b></a> <ul class="dropdown-menu "> <li> <a href="extstreamsDefinitions.html">extstreamsDefinitions</a> </li> <li> <a href="filePersistence.html">filePersistence</a> </li> <li> <a href="memoryPersistence.html">memoryPersistence</a> </li> <li> <a href="memoryScheduler.html">memoryScheduler</a> </li> <li> <a href="oauthHandler.html">oauthHandler</a> </li> </ul> </li> </ul> </div> </div> <div class="row-fluid"> <div class="span12"> <div id="main"> <h1 class="page-title">Source: jive-sdk-api/lib/util/jiveutil.js</h1> <section> <article> <pre class="sunlight-highlight-javascript linenums">/* * Copyright 2013 Jive Software * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Library of useful functions. * @module jiveutil */ /////////////////////////////////////////////////////////////////////////////////// // private var q = require('q'); var fs = require('fs-extra'); var uuid = require('uuid'); var mustache = require('mustache'); var jive = require('../../api'); var oauth = require('./oauth'); var iterator = require('./iterator'); var crypto = require('crypto'); var constants = require("./constants"); var jiveRequest = require("./request"); var hex_high_10 = { // set the highest bit and clear the next highest '0': '8', '1': '9', '2': 'a', '3': 'b', '4': '8', '5': '9', '6': 'a', '7': 'b', '8': '8', '9': '9', 'a': 'a', 'b': 'b', 'c': '8', 'd': '9', 'e': 'a', 'f': 'b' }; /** * Useful general utility functions. * @returns {String} guid */ exports.guid = function (src) { if (!src) { return uuid.v4(); } else { var sum = crypto.createHash('sha1'); // namespace in raw form. FIXME using ns:URL for now, what should it be? sum.update(new Buffer('a6e4EZ2tEdGAtADAT9QwyA==', 'base64')); // add HTTP path sum.update(src); // get sha1 hash in hex form var u = sum.digest('hex'); // format as UUID (add dashes, version bits and reserved bits) u = u.substr(0, 8) + '-' + // time_low u.substr(8, 4) + '-' + // time_mid '5' + // time_hi_and_version high 4 bits (version) u.substr(13, 3) + '-' + // time_hi_and_version low 4 bits (time high) hex_high_10[u.substr(16, 1)] + u.substr(17, 1) + // cloc_seq_hi_and_reserved u.substr(18, 2) + '-' + // clock_seq_low u.substr(20, 12); // node return u; } }; /** * By default this will build a request of type 'application/json'. Set a Content-Type header * explicitly if its supposed to be a different type. * @param {String} url * @param {String} method * @param {Object} postBody leave null unless PUT or POST * @param {Object} headers leave null or empty [] if no additional headers * @param {Object} requestOptions leave null or empty [] if no additional request optinos * @return {Promise} Promise */ exports.buildRequest = function (url, method, postBody, headers, requestOptions) { return jiveRequest.buildRequest(url, method, postBody, headers, requestOptions ); }; /** * Useful request related utilities * @type module:jiveRequest */ exports.request = jiveRequest; /** * Gets the file size in bytes. * @param filename - the path to the file. * @return {Promise} Promise */ exports.fsGetSize = function (filename) { var deferred = q.defer(); fs.stat(filename, function (err, stats) { if (err) { deferred.reject(err); } else { deferred.resolve(stats.size); } }); return deferred.promise; }; /** * @param path * @return {Promise} Promise */ exports.fsexists = function (path) { var deferred = q.defer(); var method = fs.exists ? fs.exists : require('path').exists; method(path, function (exists) { deferred.resolve(exists); }); return deferred.promise; }; /** * @param source * @param target * @return {Promise} Promise */ exports.fscopy = function (source, target) { jive.logger.debug('Copying', source, 'to', target); var deferred = q.defer(); fs.copy(source, target, function (err) { if (err) { deferred.reject(err); } else { deferred.resolve(); } }); return q.promise; }; var fsSimpleRename = function (source, target) { var deferred = q.defer(); fs.rename(source, target, function (err) { if (err) { deferred.reject(err); } else { deferred.resolve(); } }); return deferred.promise; }; /** * @param source * @param target * @param force * @return {Promise} Promise */ exports.fsrename = function (source, target, force) { jive.logger.debug('Renaming', source, 'to', target); if (!force) { return fsSimpleRename(source, target); } return exports.fsexists(target).then(function (exists) { if (exists) { // delete return exports.fsrmdir(target).then(function () { // do rename jive.logger.debug('Renaming', source, '->', target); return fsSimpleRename(source, target); }); } else { // do rename return fsSimpleRename(source, target); } }); }; /** * @param path * @return {Promise} Promise */ exports.fsmkdir = function (path) { jive.logger.debug('Creating directory', path); var deferred = q.defer(); fs.mkdirs(path, function (err) { if (err) { deferred.reject(err); } else { deferred.resolve(); } }); return deferred.promise; }; /** * @param path * @return {Promise} Promise */ exports.fsread = function (path) { var deferred = q.defer(); fs.readFile(path, function (err, data) { deferred.resolve(data); return data; }); return deferred.promise; }; /** * @param path * @return {Promise} Promise */ exports.fsreadJson = function (path) { return exports.fsread(path).then(function (data) { return JSON.parse(new Buffer(data).toString()); }); }; /** * @param path * @return {Promise} Promise */ exports.fsreaddir = function (path) { var deferred = q.defer(); fs.readdir(path, function (err, items) { deferred.resolve(items); return items; }); return deferred.promise; }; var removeRecursive = function (path, cb) { fs.stat(path, function (err, stats) { if (err) { cb(err, stats); return; } if (stats.isFile()) { fs.unlink(path, function (err) { if (err) { cb(err, null); } else { cb(null, true); } return; }); } else if (stats.isDirectory()) { // A folder may contain files // We need to delete the files first // When all are deleted we could delete the // dir itself fs.readdir(path, function (err, files) { if (err) { cb(err, null); return; } var f_length = files.length; var f_delete_index = 0; // Check and keep track of deleted files // Delete the folder itself when the files are deleted var checkStatus = function () { // We check the status // and count till we r done if (f_length === f_delete_index) { fs.rmdir(path, function (err) { if (err) { cb(err, null); } else { cb(null, true); } }); return true; } return false; }; if (!checkStatus()) { for (var i = 0; i &lt; f_length; i++) { // Create a local scope for filePath // Not really needed, but just good practice // (as strings arn't passed by reference) (function () { var filePath = path + '/' + files[i]; // Add a named function as callback // just to enlighten debugging removeRecursive(filePath, function removeRecursiveCB(err, status) { if (!err) { f_delete_index++; checkStatus(); } else { cb(err, null); return; } }); })() } } }); } }); }; /** * @param path * @return {Promise} Promise */ exports.fsrmdir = function (path) { var deferred = q.defer(); removeRecursive(path, function (err, stats) { if (err) { deferred.reject(err); } else { deferred.resolve(); } }); return deferred.promise; }; /** * @param path * @return {Promise} Promise */ exports.fsisdir = function (path) { var deferred = q.defer(); fs.stat(path, function (err, stats) { if (err) { deferred.reject(err); } else { deferred.resolve(stats.isDirectory()); } }); return deferred.promise; }; /** * @param data * @param path * @return {Promise} Promise */ exports.fswrite = function (data, path) { var deferred = q.defer(); fs.writeFile(path, data, function (err) { if (err) { deferred.reject(err); } else { deferred.resolve(); } }); return deferred.promise; }; var supportedTemplatableExtensions = [ '.json', '.txt', '.text', '.js', '.sql', '.html', '.xml' ]; function getExtension(filename) { if (!filename) { return; } var i = filename.lastIndexOf('.'); return (i &lt; 0) ? '' : filename.substr(i); } /** * @param source * @param target * @param substitutions * @return {Promise} Promise */ exports.fsTemplateCopy = function (source, target, substitutions) { var ext = getExtension(source); if (!ext || supportedTemplatableExtensions.indexOf(ext.toLowerCase()) &lt; 0 || !substitutions) { jive.logger.debug(source + ' is not a supported templatable file type. Doing straight copying', source, '->', target); return exports.fscopy(source, target); } else { jive.logger.debug('Templatized Copying', source, '->', target); return exports.fsread(source).then(function (data) { var raw = data.toString(); var processed = mustache.render(raw, substitutions || {}); return exports.fswrite(processed, target); }); } }; /** * @param data * @param target * @param substitutions * @return {Promise} Promise */ exports.fsTemplateWrite = function (data, target, substitutions) { var ext = getExtension(target); if (!ext || supportedTemplatableExtensions.indexOf(ext.toLowerCase()) &lt; 0) { jive.logger.debug(target + ' is not a supported templatable file type. Doing straight write ->', target); return exports.fswrite(data, target); } else { jive.logger.debug('Templatized write ->', target); var processed = mustache.render(data, substitutions || {}); return exports.fswrite(processed, target); } }; /** * @param source * @param substitutions * @return {Promise} Promise */ exports.fsTemplateRead = function (source, substitutions) { return exports.fsread(source).then(function (data) { var raw = data.toString(); return mustache.render(raw, substitutions || {}); }); }; /** * @param object * @returns {*|string} */ exports.base64Encode = function (object) { return new Buffer(JSON.stringify(object)).toString('base64'); }; /** * @param str * @returns {*|string} */ exports.base64Decode = function (str) { return new Buffer(str, 'base64').toString('ascii'); }; /** * @param auth * @param clientId * @param clientSecret * @param authRequired * @returns {boolean} */ exports.basicAuthorizationHeaderValid = function (auth, clientId, clientSecret, authRequired) { if (!auth &amp;&amp; !authRequired) { return true; } if (auth.indexOf('Basic ') == 0) { var authParts = auth.split('Basic '); var p = new Buffer(authParts[1], 'base64').toString(); var pParts = p.split(':'); var authClientId = pParts[0]; var authSecret = pParts[1]; if (authClientId !== clientId || authSecret !== clientSecret) { return false; } } else { return !authRequired; } return true; }; /** * @param auth * @param clientId * @param clientSecret * @param authRequired * @returns {boolean} */ exports.jiveAuthorizationHeaderValid = function (auth, clientId, clientSecret, authRequired) { if (!auth &amp;&amp; !authRequired) { return true; } if ( !clientSecret ) { return false; } var authVars = auth.split(' '); var authFlag = authVars[0]; if (authFlag == 'JiveEXTN') { var str = ''; var authParams = authVars[1].split('&amp;'); var signature; authParams.forEach(function (p) { if (p.indexOf('signature') == 0) { signature = p.split("signature=")[1]; } else { if (str.length > 0) { str += '&amp;'; } str += p; } }); //do signature verification var hmac_signature = crypto.createHmac('SHA256', new Buffer(clientSecret, 'base64')).update(str).digest('base64'); return hmac_signature == decodeURIComponent(signature); } else { return true; } }; /** * @param o * @returns {{}} */ exports.sortObject = function (o) { var sorted = {}, key, a = []; for (key in o) { if (o.hasOwnProperty(key)) { a.push(key); } } a.sort(); for (key = 0; key &lt; a.length; key++) { sorted[a[key]] = o[a[key]]; } return sorted; }; /** * @param currentFsItem * @param root * @param targetRoot * @param force * @param processor * @return {Promise} Promise */ exports.recursiveDirectoryProcessor = function (currentFsItem, root, targetRoot, force, processor) { var recurseDirectory = function (directory) { return q.nfcall(fs.readdir, directory).then(function (subItems) { var promises = []; subItems.forEach(function (subItem) { promises.push(exports.recursiveDirectoryProcessor(directory + '/' + subItem, root, targetRoot, force, processor)); }); return q.all(promises); }); }; return q.nfcall(fs.stat, currentFsItem).then(function (stat) { var targetPath = targetRoot + '/' + currentFsItem.substr(root.length + 1, currentFsItem.length); if (stat.isDirectory()) { if (root !== currentFsItem) { return exports.fsexists(targetPath).then(function (exists) { if (root == currentFsItem || (exists &amp;&amp; !force)) { return recurseDirectory(currentFsItem); } else { return processor('dir', currentFsItem, targetPath).then(function () { return recurseDirectory(currentFsItem) }); } }); } return recurseDirectory(currentFsItem); } // must be a file return exports.fsexists(targetPath).then(function (exists) { if (!exists || force) { return processor('file', currentFsItem, targetPath) } else { return q.fcall(function () { }); } }); }); }; var copyFileProcessor = function (type, currentFsItem, targetPath, substitutions) { return q.fcall(function () { if (type === 'dir') { return exports.fsmkdir(targetPath); } else { // must be file return exports.fsTemplateCopy(currentFsItem, targetPath, substitutions); } }); }; /** * @param root * @param target * @param force * @param substitutions * @param file * @return {Promise} Promise */ exports.recursiveCopy = function (root, target, force, substitutions, file) { return exports.fsisdir(root).then( function(isDir) { if( !isDir ) { return copyFileProcessor("file", root, target, substitutions); } var substitutionProcessor = function (type, currentFsItem, targetPath) { return copyFileProcessor(type, currentFsItem, targetPath, substitutions); }; return exports.recursiveDirectoryProcessor( root, root, target, force, substitutionProcessor ); }); }; /** * @param root * @param targetZip * @param flatten * @return {Promise} Promise */ exports.zipFolder = function (root, targetZip, flatten) { var fs = require('fs'); var archiver = require('archiver'); var output = fs.createWriteStream(targetZip); var archive = archiver('zip'); archive.on('error', function (err) { throw err; }); archive.pipe(output); return exports.recursiveDirectoryProcessor(root, root, '/tmp', true,function (type, currentFsItem, targetPath, substitutions) { return q.fcall(function () { if (type === 'file') { var target = currentFsItem.substring(currentFsItem.indexOf('/') + 1, currentFsItem.length); if (flatten) { target = require('path').basename(target); } jive.logger.debug('Zipping', currentFsItem, 'to', targetZip, ' : ', target); archive.append(fs.createReadStream(currentFsItem), { name: target }) } }) }).then(function () { archive.finalize(function (err, written) { if (err) { throw err; } jive.logger.info(written + ' total bytes written to extension archive ', targetZip); }); }); }; /** * @type {*} */ exports.oauth = oauth; /** * @type {*} */ exports.iterator = iterator;</pre> </article> </section> </div> <div class="clearfix"></div> <footer> <span class="copyright"> Jive Software, Inc </span> <br /> <span class="jsdoc-message"> Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.3.0-dev</a> on Wed Jan 22 2014 12:29:37 GMT-0800 (PST) using the <a href="https://github.com/terryweiss/docstrap">DocStrap template</a>. </span> </footer> </div> <br clear="both"> </div> </div> <script src="scripts/sunlight.js"></script> <script src="scripts/sunlight.javascript.js"></script> <script src="scripts/sunlight-plugin.doclinks.js"></script> <script src="scripts/sunlight-plugin.linenumbers.js"></script> <script src="scripts/sunlight-plugin.menu.js"></script> <script src="scripts/jquery.min.js"></script> <script src="scripts/jquery.scrollTo.js"></script> <script src="scripts/jquery.localScroll.js"></script> <script src="scripts/bootstrap-dropdown.js"></script> <script src="scripts/toc.js"></script> <script> Sunlight.highlightAll({lineNumbers:true, showMenu: true, enableDoclinks :true}); </script> <script> $( function () { $( "#toc" ).toc( { selectors : "h1,h2,h3,h4", showAndHide : false, scrollTo : 60 } ); $( "#toc>ul" ).addClass( "nav nav-pills nav-stacked" ); $( "#main span[id^='toc']" ).addClass( "toc-shim" ); } ); </script> </body> </html>