From a93ab05310316ff55b225a1c9611ceb13dbfbcbb Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 22 Nov 2021 18:16:35 +0530 Subject: [PATCH 01/74] handle absolute paths in a few obviously problematic cases --- lib/env.js | 3 ++- lib/storage/file.js | 4 ++-- server.js | 31 ++++++++++++++++--------------- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/lib/env.js b/lib/env.js index 9970bc4f9..526f7bb0d 100644 --- a/lib/env.js +++ b/lib/env.js @@ -11,6 +11,7 @@ const Core = require("./commands/core"); const Quota = require("./commands/quota"); const Util = require("./common-util"); const Package = require("../package.json"); +const Path = require("path"); var canonicalizeOrigin = function (s) { if (typeof(s) === 'undefined') { return; } @@ -219,7 +220,7 @@ module.exports.create = function (config) { var paths = Env.paths; var keyOrDefaultString = function (key, def) { - return typeof(config[key]) === 'string'? config[key]: def; + return Path.resolve(typeof(config[key]) === 'string'? config[key]: def); }; paths.pin = keyOrDefaultString('pinPath', './pins'); diff --git a/lib/storage/file.js b/lib/storage/file.js index 30e6c7644..0a9eb4e5f 100644 --- a/lib/storage/file.js +++ b/lib/storage/file.js @@ -1042,8 +1042,8 @@ module.exports.create = function (conf, _cb) { var cb = Util.once(Util.mkAsync(_cb)); var env = { - root: conf.filePath || './datastore', - archiveRoot: conf.archivePath || './data/archive', + root: Path.resolve(conf.filePath || './datastore'), + archiveRoot: Path.resolve(conf.archivePath || './data/archive'), // supply a volumeId if you want a store to archive channels to and from // to its own subpath within the archive directory volumeId: conf.volumeId || 'datastore', diff --git a/server.js b/server.js index ddd2fcb88..171b0e9c1 100644 --- a/server.js +++ b/server.js @@ -139,7 +139,7 @@ app.head(/^\/common\/feedback\.html/, function (req, res, next) { app.use('/blob', function (req, res, next) { if (req.method === 'HEAD') { - Express.static(Path.join(__dirname, Env.paths.blob), { + Express.static(Env.paths.blob, { setHeaders: function (res, path, stat) { res.set('Access-Control-Allow-Origin', '*'); res.set('Access-Control-Allow-Headers', 'Content-Length'); @@ -169,31 +169,32 @@ app.use(function (req, res, next) { next(); }); -app.use(Express.static(__dirname + '/www')); +app.use(Express.static(Path.resolve('www'))); // FIXME I think this is a regression caused by a recent PR // correct this hack without breaking the contributor's intended behaviour. var mainPages = config.mainPages || Default.mainPages(); var mainPagePattern = new RegExp('^\/(' + mainPages.join('|') + ').html$'); -app.get(mainPagePattern, Express.static(__dirname + '/customize')); -app.get(mainPagePattern, Express.static(__dirname + '/customize.dist')); +app.get(mainPagePattern, Express.static(Path.resolve('customize'))); +app.get(mainPagePattern, Express.static(Path.resolve('customize.dist'))); -app.use("/blob", Express.static(Path.join(__dirname, Env.paths.blob), { +app.use("/blob", Express.static(Env.paths.blob, { maxAge: Env.DEV_MODE? "0d": "365d" })); -app.use("/datastore", Express.static(Path.join(__dirname, Env.paths.data), { +app.use("/datastore", Express.static(Env.paths.data, { maxAge: "0d" })); -app.use("/block", Express.static(Path.join(__dirname, Env.paths.block), { + +app.use("/block", Express.static(Env.paths.block, { maxAge: "0d", })); -app.use("/customize", Express.static(__dirname + '/customize')); -app.use("/customize", Express.static(__dirname + '/customize.dist')); -app.use("/customize.dist", Express.static(__dirname + '/customize.dist')); -app.use(/^\/[^\/]*$/, Express.static('customize')); -app.use(/^\/[^\/]*$/, Express.static('customize.dist')); +app.use("/customize", Express.static(Path.resolve('customize'))); +app.use("/customize", Express.static(Path.resolve('customize.dist'))); +app.use("/customize.dist", Express.static(Path.resolve('customize.dist'))); +app.use(/^\/[^\/]*$/, Express.static(Path.resolve('customize'))); +app.use(/^\/[^\/]*$/, Express.static(Path.resolve('customize.dist'))); // if dev mode: never cache var cacheString = function () { @@ -279,8 +280,8 @@ var serveBroadcast = makeRouteCache(function (host) { app.get('/api/config', serveConfig); app.get('/api/broadcast', serveBroadcast); -var four04_path = Path.resolve(__dirname + '/customize.dist/404.html'); -var custom_four04_path = Path.resolve(__dirname + '/customize/404.html'); +var four04_path = Path.resolve('customize.dist/404.html'); +var custom_four04_path = Path.resolve('customize/404.html'); var send404 = function (res, path) { if (!path && path !== four04_path) { path = four04_path; } @@ -299,7 +300,7 @@ app.use(function (req, res, next) { var httpServer = Env.httpServer = Http.createServer(app); nThen(function (w) { - Fs.exists(__dirname + "/customize", w(function (e) { + Fs.exists(Path.resolve("customize"), w(function (e) { if (e) { return; } console.log("CryptPad is customizable, see customize.dist/readme.md for details"); })); From caa4666e4ad2fd835d495ebe51f51f2935ae9d73 Mon Sep 17 00:00:00 2001 From: Maxime Cesson Date: Tue, 2 Aug 2022 17:07:21 +0200 Subject: [PATCH 02/74] Jade programming language not handled, triggering warnings / errors --- www/common/modes.js | 1 - 1 file changed, 1 deletion(-) diff --git a/www/common/modes.js b/www/common/modes.js index 6d005da30..62208b866 100644 --- a/www/common/modes.js +++ b/www/common/modes.js @@ -49,7 +49,6 @@ define([ "HTML htmlmixed .html", "HTTP http _", /* no extension */ "IDL idl .idl", - "JADE jade .jade", "Java text/x-java .java", "JavaScript javascript .js", "Jinja2 jinja2 .j2", From e382833545477c85d49d6ad1ff309b9c0e50b969 Mon Sep 17 00:00:00 2001 From: Maxime Cesson Date: Tue, 2 Aug 2022 17:09:55 +0200 Subject: [PATCH 03/74] C language suggested twice --- www/common/modes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/common/modes.js b/www/common/modes.js index 62208b866..d38d35c98 100644 --- a/www/common/modes.js +++ b/www/common/modes.js @@ -11,7 +11,7 @@ define([ "Asterisk asterisk", "Brainfuck brainfuck .b", "C text/x-csrc .c", - "C text/x-c++src .cpp", + "C++ text/x-c++src .cpp", "C-like clike .c", "Clojure clojure .clj", "CMake cmake _", /* no extension */ From c2b3ed7ae767833b86be436fdf78727dd7c8fddc Mon Sep 17 00:00:00 2001 From: Maxime Cesson Date: Fri, 12 Aug 2022 12:25:06 +0200 Subject: [PATCH 04/74] Filter by document type (#438), to be improved --- www/common/drive-ui.js | 156 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 146 insertions(+), 10 deletions(-) diff --git a/www/common/drive-ui.js b/www/common/drive-ui.js index 607c1d1b1..76ee30e90 100644 --- a/www/common/drive-ui.js +++ b/www/common/drive-ui.js @@ -78,6 +78,8 @@ define([ var TAGS_NAME = Messages.fm_tagsName; var SHARED_FOLDER = 'sf'; var SHARED_FOLDER_NAME = Messages.fm_sharedFolderName; + var FILTER = "filter"; + var FILTER_NAME = "I don't have any idea of what's going here..."; // XXX: English hardcoded again // Icons var faFolder = 'cptools-folder'; @@ -2467,6 +2469,7 @@ define([ case RECENT: pName = RECENT_NAME; break; case OWNED: pName = OWNED_NAME; break; case TAGS: pName = TAGS_NAME; break; + case FILTER: pName = FILTER_NAME; break; case SHARED_FOLDER: pName = SHARED_FOLDER_NAME; break; default: pName = name; } @@ -2634,6 +2637,8 @@ define([ break; case TAGS: break; + case FILTER: + break; default: msg = undefined; } @@ -3045,6 +3050,84 @@ define([ $container.append($block); }; + var createFilterButton = function (isTemplate, $container) { + if (!APP.loggedIn) { return; } + + // Create dropdown + var options = []; + if (!isTemplate) { + options.push({ + tag: 'a', + attributes: { + 'class': 'cp-app-drive-filter-doc', + 'data-type': 'link' + }, + content: [ + getIcon('link')[0], + Messages.fm_link_type, + ], + }); + options.push({ + tag: 'a', + attributes: { + 'class': 'cp-app-drive-filter-doc', + 'data-type': 'file', + 'href': '#' + }, + content: [ + getIcon('file')[0], + Messages.type['file'], + ], + }); + options.push({tag: 'hr'}); + } + getNewPadTypes().forEach(function (type) { + var attributes = { + 'class': 'cp-app-drive-filter-doc', + 'data-type': type, + 'href': '#' + }; + + var premium = common.checkRestrictedApp(type); + if (premium < 0) { + attributes.class += ' cp-app-hidden cp-app-disabled'; + } else if (premium === 0) { + attributes.class += ' cp-app-disabled'; + } + + options.push({ + tag: 'a', + attributes: attributes, + content: [ + getIcon(type)[0], + Messages.type[type], + ], + }); + }); + var dropdownConfig = { + buttonContent: [ + h('span.fa.fa-filter'), + h('span', 'Filter by'), // XXX: English hardcoded + ], + options: options, + feedback: 'DRIVE_FILTERPAD_LOCALFOLDER', // XXX: What should I input there? + common: common + }; + var $block = UIElements.createDropdown(dropdownConfig); + + // XXX: Custom style? + $block.find('button').addClass('cp-app-drive-toolbar-filter'); + + // Add a handler + $block.find('a.cp-app-drive-filter-doc, li.cp-app-drive-filter-doc') + .click(function () { + var type = $(this).attr('data-type') || 'invalid-filter'; + APP.displayDirectory([FILTER, type, currentPath]); + }); + + $container.append($block); + }; + var SORT_FOLDER_DESC = 'sortFoldersDesc'; var SORT_FILE_BY = 'sortFilesBy'; var SORT_FILE_DESC = 'sortFilesDesc'; @@ -3302,6 +3385,23 @@ define([ return keys; }; + var filterPads = function (files, type, path, useId) { + var root = path && manager.find(path); + + return files + .filter(function (e) { + return useId ? manager.isFile(e) : (path && manager.isFile(root[e])); + }) + .filter(function (e) { + var id = useId ? e : root[e]; + var data = manager.getFileData(id); + if (type === 'link') { return data.static; } + var href = data.href || data.roHref; + return href ? (href.split('/')[1] === type) : true; + // if types are unreachable, display files to avoid misleading the user + }); + }; + // Create the ghost icon to add pads/folders var createNewPadIcons = function ($block, isInRoot) { var $container = $('
'); @@ -3435,7 +3535,7 @@ define([ // Unsorted element are represented by "href" in an array: they don't have a filename // and they don't hav a hierarchical structure (folder/subfolders) - var displayHrefArray = function ($container, rootName, draggable) { + var displayHrefArray = function ($container, rootName, draggable, typeFilter) { var unsorted = files[rootName]; if (unsorted.length) { var $fileHeader = getFileListHeader(true); @@ -3445,6 +3545,7 @@ define([ var sortBy = APP.store[SORT_FILE_BY]; sortBy = sortBy === "" ? sortBy = 'name' : sortBy; var sortedFiles = sortElements(false, [rootName], keys, sortBy, !getSortFileDesc(), true); + sortedFiles = typeFilter ? filterPads(sortedFiles, typeFilter, false, true) : sortedFiles; sortedFiles.forEach(function (id) { var file = manager.getFileData(id); if (!file) { @@ -3526,7 +3627,7 @@ define([ createGhostIcon($container); }; - var displayTrashRoot = function ($list, $folderHeader, $fileHeader) { + var displayTrashRoot = function ($list, $folderHeader, $fileHeader, typeFilter) { var filesList = []; var root = files[TRASH]; var isEmpty = true; @@ -3549,13 +3650,25 @@ define([ isEmpty = false; }); + var sortedFolders = sortTrashElements(true, filesList, null, !getSortFolderDesc()); + var sortedFiles = sortTrashElements(false, filesList, APP.store[SORT_FILE_BY], !getSortFileDesc); + + if (typeFilter) { + var ids = sortedFiles.map(function (obj) { return obj.element; }); + var idsFilter = filterPads(ids, typeFilter, false, true); + sortedFiles = sortedFiles.filter(function (obj) { + return (idsFilter.indexOf(obj.element) !== -1); + }); + if (sortedFolders.length < 1 && sortedFiles.length < 1) { + isEmpty = true; + } + } + if (!isEmpty) { var $empty = createEmptyTrashButton(); $content.append($empty); } - var sortedFolders = sortTrashElements(true, filesList, null, !getSortFolderDesc()); - var sortedFiles = sortTrashElements(false, filesList, APP.store[SORT_FILE_BY], !getSortFileDesc()); if (manager.hasSubfolder(root, true)) { $list.append($folderHeader); } sortedFolders.forEach(function (f) { var $element = createElement([TRASH], f.spath, root, true); @@ -3728,7 +3841,7 @@ define([ }); }; - var displayRecent = function ($list) { + var displayRecent = function ($list, typeFilter) { var filesList = manager.getRecentPads(); var limit = 20; @@ -3744,6 +3857,14 @@ define([ var i = 0; var channels = []; + if (typeFilter) { + var ids = filesList.map(function (arr) { return arr[0]; }); + var idsFilter = filterPads(ids, typeFilter, false, true); + filesList = filesList.filter(function (arr) { + return (idsFilter.indexOf(arr[0]) !== -1); + }); + } + $list.append(h('li.cp-app-drive-element-separator', h('span', Messages.drive_active1Day))); filesList.some(function (arr) { var id = arr[0]; @@ -3932,6 +4053,15 @@ define([ $content.html(""); sel.$selectBox = $('
', {'class': 'cp-app-drive-content-select-box'}) .appendTo($content); + + var typeFilter; + var isFilter = path[0] === FILTER; + if (isFilter) { + if (path.length < 3) { return; } + typeFilter = path[1]; + path = path[2]; + currentPath = path; + } var isInRoot = manager.isPathIn(path, [ROOT]); var inTrash = manager.isPathIn(path, [TRASH]); var isTrashRoot = manager.comparePath(path, [TRASH]); @@ -3939,6 +4069,8 @@ define([ var isAllFiles = manager.comparePath(path, [FILES_DATA]); var isVirtual = virtualCategories.indexOf(path[0]) !== -1; var isSearch = path[0] === SEARCH; + var isRecent = path[0] === RECENT; + var isOwned = path[0] === OWNED; var isTags = path[0] === TAGS; // ANON_SHARED_FOLDER var isSharedFolder = path[0] === SHARED_FOLDER && APP.newSharedFolder; @@ -4040,6 +4172,9 @@ define([ if (!readOnlyFolder) { createNewButton(isInRoot, APP.toolbar.$bottomL); } + if (!isTags && !isSearch) { + createFilterButton(isTemplate, APP.toolbar.$bottomL); + } if (APP.mobile()) { var $context = $('