| 
									
										
										
										
											2017-10-21 21:10:33 -04:00
										 |  |  | "use strict"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-28 19:55:55 -04:00
										 |  |  | const crypto = require('crypto'); | 
					
						
							| 
									
										
										
										
											2017-12-09 20:44:06 -05:00
										 |  |  | const randtoken = require('rand-token').generator({source: 'crypto'}); | 
					
						
							| 
									
										
										
										
											2018-02-26 20:47:34 -05:00
										 |  |  | const unescape = require('unescape'); | 
					
						
							| 
									
										
										
										
											2018-11-05 12:52:50 +01:00
										 |  |  | const escape = require('escape-html'); | 
					
						
							| 
									
										
										
										
											2019-01-13 10:22:17 +01:00
										 |  |  | const sanitize = require("sanitize-filename"); | 
					
						
							| 
									
										
										
										
											2020-05-12 10:28:31 +02:00
										 |  |  | const mimeTypes = require('mime-types'); | 
					
						
							| 
									
										
										
										
											2017-10-28 19:55:55 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-02 20:30:00 -04:00
										 |  |  | function newEntityId() { | 
					
						
							| 
									
										
										
										
											2018-02-11 00:18:59 -05:00
										 |  |  |     return randomString(12); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-28 13:19:12 -04:00
										 |  |  | function randomString(length) { | 
					
						
							| 
									
										
										
										
											2017-12-09 20:44:06 -05:00
										 |  |  |     return randtoken.generate(length); | 
					
						
							| 
									
										
										
										
											2017-10-14 23:31:44 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-28 19:55:55 -04:00
										 |  |  | function randomSecureToken(bytes = 32) { | 
					
						
							| 
									
										
										
										
											2017-10-29 11:22:41 -04:00
										 |  |  |     return crypto.randomBytes(bytes).toString('base64'); | 
					
						
							| 
									
										
										
										
											2017-10-28 19:55:55 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-05 12:52:50 +01:00
										 |  |  | function md5(content) { | 
					
						
							|  |  |  |     return crypto.createHash('md5').update(content).digest('hex'); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-14 23:31:44 -04:00
										 |  |  | function toBase64(plainText) { | 
					
						
							|  |  |  |     return Buffer.from(plainText).toString('base64'); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function fromBase64(encodedText) { | 
					
						
							|  |  |  |     return Buffer.from(encodedText, 'base64'); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-29 14:55:48 -04:00
										 |  |  | function hmac(secret, value) { | 
					
						
							|  |  |  |     const hmac = crypto.createHmac('sha256', Buffer.from(secret.toString(), 'ASCII')); | 
					
						
							|  |  |  |     hmac.update(value.toString()); | 
					
						
							|  |  |  |     return hmac.digest('base64'); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-05 17:58:55 -05:00
										 |  |  | function isElectron() { | 
					
						
							|  |  |  |     return !!process.versions['electron']; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-21 22:11:27 -05:00
										 |  |  | function hash(text) { | 
					
						
							|  |  |  |     return crypto.createHash('sha1').update(text).digest('base64'); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-26 23:10:23 -05:00
										 |  |  | function isEmptyOrWhitespace(str) { | 
					
						
							|  |  |  |     return str === null || str.match(/^ *$/) !== null; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-23 09:35:00 -05:00
										 |  |  | function sanitizeSql(str) { | 
					
						
							|  |  |  |     // should be improved or usage eliminated
 | 
					
						
							| 
									
										
										
										
											2019-03-16 22:19:01 +01:00
										 |  |  |     return str.replace(/'/g, "''"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-18 22:58:30 +01:00
										 |  |  | function sanitizeSqlIdentifier(str) { | 
					
						
							| 
									
										
										
										
											2019-12-24 16:00:31 +01:00
										 |  |  |     return str.replace(/[^A-Za-z0-9_]/g, ""); | 
					
						
							| 
									
										
										
										
											2019-12-18 22:58:30 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-16 22:19:01 +01:00
										 |  |  | function prepareSqlForLike(prefix, str, suffix) { | 
					
						
							|  |  |  |     const value = str | 
					
						
							|  |  |  |         .replace(/\\/g, "\\\\") | 
					
						
							|  |  |  |         .replace(/'/g, "''") | 
					
						
							|  |  |  |         .replace(/_/g, "\\_") | 
					
						
							|  |  |  |         .replace(/%/g, "\\%"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return `'${prefix}${value}${suffix}' ESCAPE '\\'`; | 
					
						
							| 
									
										
										
										
											2017-12-23 09:35:00 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-13 15:25:09 -05:00
										 |  |  | async function stopWatch(what, func) { | 
					
						
							|  |  |  |     const start = new Date(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-22 23:18:08 -05:00
										 |  |  |     const ret = await func(); | 
					
						
							| 
									
										
										
										
											2018-01-13 15:25:09 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-10 16:36:25 +01:00
										 |  |  |     const tookMs = Date.now() - start.getTime(); | 
					
						
							| 
									
										
										
										
											2018-01-13 15:25:09 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     console.log(`${what} took ${tookMs}ms`); | 
					
						
							| 
									
										
										
										
											2018-01-22 23:18:08 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return ret; | 
					
						
							| 
									
										
										
										
											2018-01-13 15:25:09 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-05 12:52:50 +01:00
										 |  |  | function escapeHtml(str) { | 
					
						
							|  |  |  |     return escape(str); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-26 20:47:34 -05:00
										 |  |  | function unescapeHtml(str) { | 
					
						
							|  |  |  |     return unescape(str); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-04 12:06:35 -05:00
										 |  |  | function toObject(array, fn) { | 
					
						
							|  |  |  |     const obj = {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (const item of array) { | 
					
						
							|  |  |  |         const ret = fn(item); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         obj[ret[0]] = ret[1]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return obj; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-27 12:26:34 -04:00
										 |  |  | function stripTags(text) { | 
					
						
							|  |  |  |     return text.replace(/<(?:.|\n)*?>/gm, ''); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-03 20:42:25 -04:00
										 |  |  | function intersection(a, b) { | 
					
						
							|  |  |  |     return a.filter(value => b.indexOf(value) !== -1); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function union(a, b) { | 
					
						
							|  |  |  |     const obj = {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (let i = a.length-1; i >= 0; i--) { | 
					
						
							|  |  |  |         obj[a[i]] = a[i]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (let i = b.length-1; i >= 0; i--) { | 
					
						
							|  |  |  |         obj[b[i]] = b[i]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const res = []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (const k in obj) { | 
					
						
							|  |  |  |         if (obj.hasOwnProperty(k)) { // <-- optional
 | 
					
						
							|  |  |  |             res.push(obj[k]); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-07 09:35:29 +01:00
										 |  |  | function escapeRegExp(str) { | 
					
						
							|  |  |  |     return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-18 09:05:50 +01:00
										 |  |  | function crash() { | 
					
						
							|  |  |  |     if (isElectron()) { | 
					
						
							|  |  |  |         require('electron').app.exit(1); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |         process.exit(1); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-13 10:22:17 +01:00
										 |  |  | function sanitizeFilenameForHeader(filename) { | 
					
						
							|  |  |  |     let sanitizedFilename = sanitize(filename); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (sanitizedFilename.trim().length === 0) { | 
					
						
							|  |  |  |         sanitizedFilename = "file"; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return encodeURIComponent(sanitizedFilename) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function getContentDisposition(filename) { | 
					
						
							|  |  |  |     const sanitizedFilename = sanitizeFilenameForHeader(filename); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return `file; filename="${sanitizedFilename}"; filename*=UTF-8''${sanitizedFilename}`; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-25 18:21:55 +01:00
										 |  |  | const STRING_MIME_TYPES = ["application/x-javascript", "image/svg+xml"]; | 
					
						
							| 
									
										
										
										
											2019-10-31 21:58:34 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | function isStringNote(type, mime) { | 
					
						
							|  |  |  |     return ["text", "code", "relation-map", "search"].includes(type) | 
					
						
							|  |  |  |         || mime.startsWith('text/') | 
					
						
							|  |  |  |         || STRING_MIME_TYPES.includes(mime); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-12 10:28:31 +02:00
										 |  |  | function quoteRegex(url) { | 
					
						
							|  |  |  |     return url.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&'); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-02 22:55:11 +02:00
										 |  |  | function replaceAll(string, replaceWhat, replaceWith) { | 
					
						
							| 
									
										
										
										
											2020-05-12 10:28:31 +02:00
										 |  |  |     const quotedReplaceWhat = quoteRegex(replaceWhat); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return string.replace(new RegExp(quotedReplaceWhat, "g"), replaceWith); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function formatDownloadTitle(filename, type, mime) { | 
					
						
							|  |  |  |     if (!filename) { | 
					
						
							|  |  |  |         filename = "untitled"; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (type === 'text') { | 
					
						
							|  |  |  |         return filename + '.html'; | 
					
						
							|  |  |  |     } else if (['relation-map', 'search'].includes(type)) { | 
					
						
							|  |  |  |         return filename + '.json'; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         if (!mime) { | 
					
						
							|  |  |  |             return filename; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         mime = mime.toLowerCase(); | 
					
						
							|  |  |  |         const filenameLc = filename.toLowerCase(); | 
					
						
							|  |  |  |         const extensions = mimeTypes.extensions[mime]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!extensions || extensions.length === 0) { | 
					
						
							|  |  |  |             return filename; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-04-02 22:55:11 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-12 10:28:31 +02:00
										 |  |  |         for (const ext of extensions) { | 
					
						
							|  |  |  |             if (filenameLc.endsWith('.' + ext)) { | 
					
						
							|  |  |  |                 return filename; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-05 10:40:35 +02:00
										 |  |  |         if (mime === 'application/octet-stream') { | 
					
						
							|  |  |  |             // we didn't find any good guess for this one, it will be better to just return
 | 
					
						
							|  |  |  |             // the current name without fake extension. It's possible that the title still preserves to correct
 | 
					
						
							|  |  |  |             // extension too
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             return filename; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-12 10:28:31 +02:00
										 |  |  |         return filename + '.' + extensions[0]; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-04-02 22:55:11 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-13 10:23:36 +02:00
										 |  |  | function timeLimit(promise, limitMs) { | 
					
						
							|  |  |  |     return new Promise((res, rej) => { | 
					
						
							|  |  |  |         let resolved = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         promise.then(() => { | 
					
						
							|  |  |  |             resolved = true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             res(); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         setTimeout(() => { | 
					
						
							|  |  |  |             if (!resolved) { | 
					
						
							|  |  |  |                 rej(new Error('Process exceeded time limit ' + limitMs)); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }, limitMs); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-14 23:31:44 -04:00
										 |  |  | module.exports = { | 
					
						
							| 
									
										
										
										
											2017-10-28 19:55:55 -04:00
										 |  |  |     randomSecureToken, | 
					
						
							| 
									
										
										
										
											2017-10-28 12:12:20 -04:00
										 |  |  |     randomString, | 
					
						
							| 
									
										
										
										
											2018-11-05 12:52:50 +01:00
										 |  |  |     md5, | 
					
						
							| 
									
										
										
										
											2018-04-02 20:30:00 -04:00
										 |  |  |     newEntityId, | 
					
						
							| 
									
										
										
										
											2017-10-14 23:31:44 -04:00
										 |  |  |     toBase64, | 
					
						
							| 
									
										
										
										
											2017-10-29 14:55:48 -04:00
										 |  |  |     fromBase64, | 
					
						
							| 
									
										
										
										
											2017-11-05 10:41:54 -05:00
										 |  |  |     hmac, | 
					
						
							| 
									
										
										
										
											2017-11-05 21:56:42 -05:00
										 |  |  |     isElectron, | 
					
						
							| 
									
										
										
										
											2017-11-26 23:10:23 -05:00
										 |  |  |     hash, | 
					
						
							| 
									
										
										
										
											2017-12-16 00:05:37 -05:00
										 |  |  |     isEmptyOrWhitespace, | 
					
						
							| 
									
										
										
										
											2018-01-06 15:56:00 -05:00
										 |  |  |     sanitizeSql, | 
					
						
							| 
									
										
										
										
											2019-12-18 22:58:30 +01:00
										 |  |  |     sanitizeSqlIdentifier, | 
					
						
							| 
									
										
										
										
											2019-03-16 22:19:01 +01:00
										 |  |  |     prepareSqlForLike, | 
					
						
							| 
									
										
										
										
											2018-02-26 20:47:34 -05:00
										 |  |  |     stopWatch, | 
					
						
							| 
									
										
										
										
											2018-11-05 12:52:50 +01:00
										 |  |  |     escapeHtml, | 
					
						
							| 
									
										
										
										
											2018-03-04 12:06:35 -05:00
										 |  |  |     unescapeHtml, | 
					
						
							| 
									
										
										
										
											2018-05-27 12:26:34 -04:00
										 |  |  |     toObject, | 
					
						
							| 
									
										
										
										
											2018-06-03 20:42:25 -04:00
										 |  |  |     stripTags, | 
					
						
							|  |  |  |     intersection, | 
					
						
							| 
									
										
										
										
											2018-11-07 09:35:29 +01:00
										 |  |  |     union, | 
					
						
							| 
									
										
										
										
											2018-11-18 09:05:50 +01:00
										 |  |  |     escapeRegExp, | 
					
						
							| 
									
										
										
										
											2019-01-13 10:22:17 +01:00
										 |  |  |     crash, | 
					
						
							|  |  |  |     sanitizeFilenameForHeader, | 
					
						
							| 
									
										
										
										
											2019-10-31 21:58:34 +01:00
										 |  |  |     getContentDisposition, | 
					
						
							| 
									
										
										
										
											2020-04-02 22:55:11 +02:00
										 |  |  |     isStringNote, | 
					
						
							| 
									
										
										
										
											2020-05-12 10:28:31 +02:00
										 |  |  |     quoteRegex, | 
					
						
							|  |  |  |     replaceAll, | 
					
						
							| 
									
										
										
										
											2020-06-13 10:23:36 +02:00
										 |  |  |     formatDownloadTitle, | 
					
						
							|  |  |  |     timeLimit | 
					
						
							| 
									
										
										
										
											2020-05-12 10:28:31 +02:00
										 |  |  | }; |