From 0908837392d5420295565eef3d7c0172dc9f77d0 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Mon, 29 Oct 2018 20:17:18 +0200 Subject: [PATCH] feature(package) add dropbox support --- .yaspellerrc | 1 + HELP.md | 113 ++++++---- bin/cloudcmd.js | 8 + client/client.js | 2 +- client/listeners/index.js | 4 +- client/modules/operation/index.js | 4 +- json/config.json | 4 +- json/help.json | 8 +- man/cloudcmd.1 | 6 +- package.json | 8 +- server/cloudcmd.js | 22 +- server/route.js | 18 +- server/route.spec.js | 332 ++++++++++++++++++------------ test/server/terminal.js | 65 +++--- 14 files changed, 366 insertions(+), 229 deletions(-) diff --git a/.yaspellerrc b/.yaspellerrc index 582fabab..0c89ff6f 100644 --- a/.yaspellerrc +++ b/.yaspellerrc @@ -33,6 +33,7 @@ "com", "dev", "deepword", + "dropbox", "dword", "edward", "favicon", diff --git a/HELP.md b/HELP.md index fc318809..30063c25 100644 --- a/HELP.md +++ b/HELP.md @@ -107,6 +107,8 @@ Cloud Commander supports command line parameters: | `--import-token` | authorization token used to connect to export server | `--import-url` | url of an import server | `--import-listen` | enable listen on config updates from import server +| `--dropbox` | enable dropbox integration +| `--dropbox-token` | set dropbox token | `--log` | enable logging | `--no-show-config` | do not show config values | `--no-server` | do not start server @@ -132,8 +134,10 @@ Cloud Commander supports command line parameters: | `--no-export` | disable export config through a server | `--no-import` | disable import of config | `--no-import-listen` | disable listen on config updates from import server -| `--no-log` | disable logging | `--no-show-file-name` | do not show file name in view and edit +| `--no-dropbox` | disable dropbox integration +| `--no-dropbox-token` | unset dropbox token +| `--no-log` | disable logging If no parameters given Cloud Commander reads information from `~/.cloudcmd.json` and use port from it (`8000` default). if port variables `PORT` isn't exist. @@ -374,49 +378,51 @@ Here is description of options: ```js { - "name" : "", /* set tab name in web browser */ - "auth" : false, /* enable http authentication */ - "username" : "root", /* username for authentication */ -    "password"         : "toor",   /* password hash for authentication */ - "algo" : "sha512WithRSAEncryption", /* cryptographic algorithm */ - "editor" : "edward", /* default, could be "dword" or "edward" */ - "packer" : "tar", /* default, could be "tar" or "zip" */ - "diff" : true, /* when save - send patch, not whole file */ - "zip" : true, /* zip text before send / unzip before save */ - "buffer" : true, /* buffer for copying files */ - "dirStorage" : true, /* store directory listing */ - "online" : false, /* do not load js files from cdn */ - "open" : true, /* open web browser when server started */ - "oneFilePanel" : false, /* show one file panel */ - "keysPanel" : true, /* show classic panel with buttons of keys */ - "port" : 8000, /* http port */ - "ip" : null, /* ip or null(default) */ - "root" : "/", /* root directory */ - "prefix" : "", /* url prefix */ - "prefixSocket" : "", /* prefix for socket connection */ - "progress" : true, /* show progress of file operations */ - "confirmCopy" : true, /* confirm copy */ - "confirmMove" : true, /* confirm move */ - "showConfig" : false, /* show config at startap */ - "showFileName" : false /* do not show file name in view and edit */ - "contact" : true, /* enable contact */ - "configDialog" : true, /* enable config dialog */ - "configAuth" : true, /* enable auth change in config dialog */ - "console" : true, /* enable console */ - "syncConsolePath" : false /* do not sync console path */ - "terminal" : false, /* disable terminal */ - "terminalPath" : '', /* path of a terminal */ - "terminalCommand" : '', /* set command to run in terminal */ - "terminalAutoRestart" : true, /* restart command on exit */ - "vim" : false, /* disable vim hot keys */ - "columns" : "name-size-date-owner-mode", /* set visible columns */ - "export" : false, /* enable export of config through a server */ - "exportToken" : "root", /* token used by export server */ - "import" : false, /* enable import of config */ - "import-url" : "http://localhost:8000", /* url of an export server */ - "importToken" : "root", /* token used to connect to export server */ - "importListen" : false, /* listen on config updates */ - "log" : true /* logging */ + "name" : "", // set tab name in web browser + "auth" : false, // enable http authentication + "username" : "root", // username for authentication +    "password"         : "toor",   // password hash for authentication + "algo" : "sha512WithRSAEncryption", // cryptographic algorithm + "editor" : "edward", // default, could be "dword" or "edward" + "packer" : "tar", // default, could be "tar" or "zip" + "diff" : true, // when save - send patch, not whole file + "zip" : true, // zip text before send / unzip before save + "buffer" : true, // buffer for copying files + "dirStorage" : true, // store directory listing + "online" : false, // do not load js files from cdn + "open" : true, // open web browser when server started + "oneFilePanel" : false, // show one file panel + "keysPanel" : true, // show classic panel with buttons of keys + "port" : 8000, // http port + "ip" : null, // ip or null(default) + "root" : "/", // root directory + "prefix" : "", // url prefix + "prefixSocket" : "", // prefix for socket connection + "progress" : true, // show progress of file operations + "confirmCopy" : true, // confirm copy + "confirmMove" : true, // confirm move + "showConfig" : false, // show config at startup + "showFileName" : false // do not show file name in view and edit + "contact" : true, // enable contact + "configDialog" : true, // enable config dialog + "configAuth" : true, // enable auth change in config dialog + "console" : true, // enable console + "syncConsolePath" : false // do not sync console path + "terminal" : false, // disable terminal + "terminalPath" : '', // path of a terminal + "terminalCommand" : '', // set command to run in terminal + "terminalAutoRestart" : true, // restart command on exit + "vim" : false, // disable vim hot keys + "columns" : "name-size-date-owner-mode", // set visible columns + "export" : false, // enable export of config through a server + "exportToken" : "root", // token used by export server + "import" : false, // enable import of config + "import-url" : "http://localhost:8000", // url of an export server + "importToken" : "root", // token used to connect to export server + "importListen" : false, // listen on config updates + "dropbox" : false, // disable dropbox integration + "dropboxToken" : "", // unset dropbox token + "log" : true // logging } ``` @@ -785,6 +791,25 @@ When you create this file run: docker-compose up ``` +# Dropbox + +Dropbox support integrated into Cloud Commander and you can switch from local file system to a dropbox account. +All you need to do is set `--dropbox` option and [generate dropbox token](https://blogs.dropbox.com/developers/2014/05/generate-an-access-token-for-your-own-account/) for you account. + +This can look like this: + +```sh +cloudcmd --dropbox --dropbox-token your-dropbox-token +``` + +Using `dropbox` remember that there is no remote support of a `console` and `terminal. Progress of file operation also not supported. There is only basic support, but you can do next things with `files` and `directories`: + +- create +- remove +- rename/move +- view +- edit + Get involved --------------- diff --git a/bin/cloudcmd.js b/bin/cloudcmd.js index e331e0d1..24755bb8 100755 --- a/bin/cloudcmd.js +++ b/bin/cloudcmd.js @@ -43,6 +43,7 @@ const args = require('minimist')(argv.slice(2), { 'import-url', 'import-token', 'export-token', + 'dropbox-token', ], boolean: [ 'auth', @@ -71,6 +72,7 @@ const args = require('minimist')(argv.slice(2), { 'import', 'import-listen', 'log', + 'dropbox', ], default: { server : true, @@ -112,6 +114,9 @@ const args = require('minimist')(argv.slice(2), { 'keys-panel': env.bool('keys_panel') || config('keysPanel'), 'import-token': env('import_token') || config('importToken'), 'export-token': env('export_token') || config('exportToken'), + + 'dropbox': config('dropbox'), + 'dropbox-token': config('dropboxToken'), }, alias: { v: 'version', @@ -177,6 +182,9 @@ function main() { config('importListen', args['import-listen']); config('importUrl', args['import-url']); + config('dropbox', args['dropbox']); + config('dropboxToken', args['dropbox-token'] || ''); + readConfig(args.config); const options = { diff --git a/client/client.js b/client/client.js index cb694321..f58ccb03 100644 --- a/client/client.js +++ b/client/client.js @@ -143,7 +143,7 @@ function CloudCmdProto(DOM) { }; CloudCmd.prefix = prefix; - CloudCmd.prefixURL = prefix + apiURL; + CloudCmd.prefixURL = `${prefix}${apiURL}`; CloudCmd.prefixSocket = config.prefixSocket; CloudCmd.config = (key) => config[key]; diff --git a/client/listeners/index.js b/client/listeners/index.js index 0e40d24e..8c855c96 100644 --- a/client/listeners/index.js +++ b/client/listeners/index.js @@ -13,7 +13,6 @@ const uploadFiles = require('../dom/upload-files'); const { FS, - apiURL, } = require('../../common/cloudfunc'); const NBSP_REG = RegExp(String.fromCharCode(160), 'g'); @@ -303,6 +302,7 @@ function onTouch(event) { * in Chrome (HTML5) */ function onDragStart(event) { + const {prefixURL} = CloudCmd; const element = getLIElement(event.target); const isDir = Info.isDir; let link = DOM.getCurrentLink(element); @@ -313,7 +313,7 @@ function onDragStart(event) { name += EXT; link = document.createElement('a'); link.textContent = name; - link.href = apiURL + '/pack' + Info.path + EXT; + link.href = prefixURL + '/pack' + Info.path + EXT; } event.dataTransfer.setData('DownloadURL', diff --git a/client/modules/operation/index.js b/client/modules/operation/index.js index e6be55a1..63528901 100644 --- a/client/modules/operation/index.js +++ b/client/modules/operation/index.js @@ -61,14 +61,14 @@ const noFilesCheck = () => { return is; }; - + module.exports.init = promisify((callback) => { showLoad(); exec.series([ DOM.loadSocket, (callback) => { - if (!config('progress')) + if (!config('progress') || config('dropbox')) return callback(); load(initOperations(CloudCmd.prefix, callback)); diff --git a/json/config.json b/json/config.json index b925c898..eec170c8 100644 --- a/json/config.json +++ b/json/config.json @@ -41,6 +41,8 @@ "importToken": "root", "importUrl": "http://localhost:8000", "importListen": false, - "log": true + "log": true, + "dropbox": false, + "dropboxToken": "" } diff --git a/json/help.json b/json/help.json index b984a7b3..1aa7b6a7 100644 --- a/json/help.json +++ b/json/help.json @@ -38,6 +38,8 @@ "--import-url ": "url of an export server", "--import-token ": "authorization token used to connect to export server", "--import-listen ": "enable listen on config updates from import server", + "--dropbox ": "enable dropbox integration", + "--dropbox-token ": "set dropbox token", "--log ": "enable logging", "--no-show-config ": "do not show config values", "--no-server ": "do not start server", @@ -63,6 +65,8 @@ "--no-export ": "disable export config through a server", "--no-import ": "disable import of config", "--no-import-listen ": "disable listen on config updates from import server", - "--no-log ": "disable logging", - "--no-show-file-name ": "do not show file name in view and edit" + "--no-show-file-name ": "do not show file name in view and edit", + "--no-dropbox ": "disable dropbox integration", + "--no-dropbox-token ": "unset dropbox token", + "--no-log ": "disable logging" } diff --git a/man/cloudcmd.1 b/man/cloudcmd.1 index fd2ca17e..9db5e7d1 100644 --- a/man/cloudcmd.1 +++ b/man/cloudcmd.1 @@ -62,6 +62,8 @@ programs in browser from any computer, mobile or tablet device. --import-url url of an import server --import-token authorization token used to connect to export server --import-listen enable listen on config updates from import server + --dropbox enable dropbox integration + --dropbox-token set dropbox token --log enable logging --no-show-config do not show config values --no-server do not start server @@ -88,8 +90,10 @@ programs in browser from any computer, mobile or tablet device. --no-import disable import of config --no-import-url url of an import server --no-import-listen disable listen on config updates from import server - --no-log disable logging --no-show-file-name do not show file name in view and edit modes + --no-dropbox disable dropbox integration + --no-dropbox-token unset dropbox token + --no-log disable logging .SH RESOURCES AND DOCUMENTATION diff --git a/package.json b/package.json index 91532e73..00c0d17e 100644 --- a/package.json +++ b/package.json @@ -110,6 +110,7 @@ }, "subdomain": "cloudcmd", "dependencies": { + "@cloudcmd/dropbox": "^4.0.1", "@cloudcmd/fileop": "^2.0.0", "@cloudcmd/move-files": "^2.0.1", "@cloudcmd/read-files-sync": "^2.0.0", @@ -120,9 +121,9 @@ "criton": "^2.0.0", "currify": "^3.0.0", "deepmerge": "^2.0.0", - "deepword": "^5.0.0", - "dword": "^9.0.0", - "edward": "^9.0.0", + "deepword": "^5.1.0", + "dword": "^9.1.0", + "edward": "^9.1.0", "execon": "^1.2.0", "express": "^4.13.0", "files-io": "^3.0.0", @@ -147,6 +148,7 @@ "pullout": "^2.0.0", "rendy": "^2.0.0", "restafary": "^5.0.0", + "restbox": "^1.0.1", "shortdate": "^1.2.0", "socket.io": "^2.0.3", "socket.io-client": "^2.1.1", diff --git a/server/cloudcmd.js b/server/cloudcmd.js index a05da3f5..d7e8d41d 100644 --- a/server/cloudcmd.js +++ b/server/cloudcmd.js @@ -23,6 +23,7 @@ const currify = require('currify'); const apart = require('apart'); const ponse = require('ponse'); const restafary = require('restafary'); +const restbox = require('restbox'); const konsole = require('console-io'); const edward = require('edward'); const dword = require('dword'); @@ -164,6 +165,9 @@ function cloudcmd(prefix, plugins, modules) { const dir = DIR_ROOT; const ponseStatic = ponse.static(dir, {cache}); + + const dropbox = config('dropbox'); + const dropboxToken = config('dropboxToken'); const funcs = clean([ config('console') && konsole({ @@ -177,25 +181,29 @@ function cloudcmd(prefix, plugins, modules) { online, diff, zip, + dropbox, + dropboxToken, }), dword({ online, diff, zip, + dropbox, + dropboxToken, }), deepword({ online, diff, zip, + dropbox, + dropboxToken, }), - fileop({ - }), + fileop(), - nomine({ - }), + nomine(), setUrl, setSW, @@ -205,6 +213,12 @@ function cloudcmd(prefix, plugins, modules) { modules && modulas(modules), + config('dropbox') && restbox({ + prefix: cloudfunc.apiURL, + root, + token: dropboxToken, + }), + restafary({ prefix: cloudfunc.apiURL + '/fs', root diff --git a/server/route.js b/server/route.js index 85a271b8..53b68536 100644 --- a/server/route.js +++ b/server/route.js @@ -35,10 +35,20 @@ const sendIndex = (params, data) => { const {FS} = CloudFunc; -const Columns = require('./columns'); -const Template = require('./template'); +const Columns = require(`${DIR_SERVER}/columns`); +const Template = require(`${DIR_SERVER}/template`); -const read = promisify(flop.read); +const getReadDir = () => { + if (!config('dropbox')) + return promisify(flop.read); + + const tokenize = (fn, a) => (b) => fn(a, b); + const {readDir} = require('@cloudcmd/dropbox'); + + return tokenize(readDir, config('dropboxToken')); +}; + +const read = getReadDir(); const realpath = promisify(fs.realpath); /** @@ -55,6 +65,8 @@ module.exports = currify((options, request, response, next) => { .catch(next); }); +module.exports._getReadDir = getReadDir; + async function route(options, request, response) { const name = ponse.getPathName(request); const gzip = true; diff --git a/server/route.spec.js b/server/route.spec.js index 5cd12303..47431866 100644 --- a/server/route.spec.js +++ b/server/route.spec.js @@ -3,48 +3,37 @@ const path = require('path'); const fs = require('fs'); -const test = require('tape'); -const {promisify} = require('util'); -const pullout = require('pullout'); -const request = require('request'); +const tryToCatch = require('try-to-catch'); +const tryToTape = require('try-to-tape'); +const test = tryToTape(require('tape')); const mockRequire = require('mock-require'); const {reRequire} = mockRequire; -const clear = require('clear-module'); const rootDir = path.join(__dirname, '../..'); const fixtureDir = path.join(__dirname, '..', 'test', 'fixture'); const routePath = './route'; const cloudcmdPath = './cloudcmd'; -const beforePath = path.join(__dirname, '../test/before'); -const {connect} = require(beforePath); - -const warp = (fn, ...a) => (...b) => fn(...b, ...a); -const _pullout = promisify(pullout); - -const get = promisify((url, fn) => { - fn(null, request(url)); -}); - -const getStr = (url) => { - return get(url) - .then(warp(_pullout, 'string')) - .catch(console.error); -}; +const cloudcmd = require(cloudcmdPath); +const serveOnce = require('serve-once'); +const {request} = serveOnce(cloudcmd); test('cloudcmd: route: buttons: no console', async (t) => { const config = { - console: false + console: false, }; - const {port, done} = await connect({config}); - const result = await getStr(`http://localhost:${port}`); + const options = { + config, + }; - t.ok(/icon-console none/.test(result), 'should hide console'); + const {body} = await request.get('/', { + options, + }); + + t.ok(/icon-console none/.test(body), 'should hide console'); t.end(); - - await done(); }); test('cloudcmd: route: buttons: console', async (t) => { @@ -52,13 +41,16 @@ test('cloudcmd: route: buttons: console', async (t) => { console: true, }; - const {port, done} = await connect({config}); - const result = await getStr(`http://localhost:${port}`); + const options = { + config, + }; - t.notOk(/icon-console none/.test(result), 'should not hide console'); + const {body} = await request.get('/', { + options, + }); + + t.notOk(/icon-console none/.test(body), 'should not hide console'); t.end(); - - await done(); }); test('cloudcmd: route: buttons: no config', async (t) => { @@ -66,13 +58,16 @@ test('cloudcmd: route: buttons: no config', async (t) => { configDialog: false }; - const {port, done} = await connect({config}); - const result = await getStr(`http://localhost:${port}`); + const options = { + config, + }; - t.ok(/icon-config none/.test(result), 'should hide config'); + const {body} = await request.get('/', { + options, + }); + + t.ok(/icon-config none/.test(body), 'should hide config'); t.end(); - - await done(); }); test('cloudcmd: route: buttons: no contact', async (t) => { @@ -80,13 +75,16 @@ test('cloudcmd: route: buttons: no contact', async (t) => { contact: false }; - const {port, done} = await connect({config}); - const result = await getStr(`http://localhost:${port}`); + const options = { + config, + }; - t.ok(/icon-contact none/.test(result), 'should hide contact'); + const {body} = await request.get('/', { + options, + }); + + t.ok(/icon-contact none/.test(body), 'should hide contact'); t.end(); - - await done(); }); test('cloudcmd: route: buttons: one file panel: move', async (t) => { @@ -94,13 +92,16 @@ test('cloudcmd: route: buttons: one file panel: move', async (t) => { oneFilePanel: true }; - const {port, done} = await connect({config}); - const result = await getStr(`http://localhost:${port}`); + const options = { + config, + }; - t.ok(/icon-move none/.test(result), 'should hide move button'); + const {body} = await request.get('/', { + options, + }); + + t.ok(/icon-move none/.test(body), 'should hide move button'); t.end(); - - await done(); }); test('cloudcmd: route: buttons: no one file panel: move', async (t) => { @@ -108,13 +109,16 @@ test('cloudcmd: route: buttons: no one file panel: move', async (t) => { oneFilePanel: false }; - const {port, done} = await connect({config}); - const result = await getStr(`http://localhost:${port}`); + const options = { + config, + }; - t.notOk(/icon-move none/.test(result), 'should not hide move button'); + const {body} = await request.get('/', { + options, + }); + + t.notOk(/icon-move none/.test(body), 'should not hide move button'); t.end(); - - await done(); }); test('cloudcmd: route: buttons: one file panel: move', async (t) => { @@ -122,13 +126,16 @@ test('cloudcmd: route: buttons: one file panel: move', async (t) => { oneFilePanel: true }; - const {port, done} = await connect({config}); - const result = await getStr(`http://localhost:${port}`); + const options = { + config, + }; - t.ok(/icon-copy none/.test(result), 'should hide copy button'); + const {body} = await request.get('/', { + options, + }); + + t.ok(/icon-copy none/.test(body), 'should hide copy button'); t.end(); - - await done(); }); test('cloudcmd: route: keys panel: hide', async (t) => { @@ -136,13 +143,16 @@ test('cloudcmd: route: keys panel: hide', async (t) => { keysPanel: false }; - const {port, done} = await connect({config}); - const result = await getStr(`http://localhost:${port}`); + const options = { + config, + }; - t.ok(/keyspanel hidden/.test(result), 'should hide keyspanel'); + const {body} = await request.get('/', { + options, + }); + + t.ok(/keyspanel hidden/.test(body), 'should hide keyspanel'); t.end(); - - await done(); }); test('cloudcmd: route: keys panel', async (t) => { @@ -150,13 +160,16 @@ test('cloudcmd: route: keys panel', async (t) => { keysPanel: true }; - const {port, done} = await connect({config}); - const result = await getStr(`http://localhost:${port}`); + const options = { + config, + }; - t.notOk(/keyspanel hidden/.test(result), 'should show keyspanel'); + const {body} = await request.get('/', { + options, + }); + + t.notOk(/keyspanel hidden/.test(body), 'should show keyspanel'); t.end(); - - await done(); }); test('cloudcmd: route: file: fs', async (t) => { @@ -165,13 +178,16 @@ test('cloudcmd: route: file: fs', async (t) => { root, }; - const {port, done} = await connect({config}); - const empty = await getStr(`http://localhost:${port}/fs`); + const options = { + config, + }; - t.equal(empty, '', 'should equal'); + const {body} = await request.get('/', { + options, + }); + + t.equal(body, '', 'should equal'); t.end(); - - await done(); }); test('cloudcmd: route: symlink', async (t) => { @@ -183,16 +199,22 @@ test('cloudcmd: route: symlink', async (t) => { root, }; + const options = { + config, + }; + fs.symlinkSync(emptyDir, symlink); - const {port, done} = await connect({config}); - const data = await getStr(`http://localhost:${port}/fs/symlink-dir`); + const {body} = await request.get('/fs/symlink-dir', { + options, + }); - t.ok(data.length, 'should return html document'); fs.unlinkSync(symlink); - t.end(); - await done(); + console.log(body); + + t.ok(body.length, 'should return html document'); + t.end(); }); test('cloudcmd: route: not found', async (t) => { @@ -201,13 +223,16 @@ test('cloudcmd: route: not found', async (t) => { root, }; - const {port, done} = await connect({config}); - const data = await getStr(`http://localhost:${port}/fs/file-not-found`); + const options = { + config, + }; - t.ok(~data.indexOf('ENOENT: no such file or directory'), 'should return error'); + const {body} = await request.get('/fs/file-not-found', { + options, + }); + + t.ok(~body.indexOf('ENOENT: no such file or directory'), 'should return error'); t.end(); - - await done(); }); test('cloudcmd: route: realpath: error', async (t) => { @@ -223,19 +248,22 @@ test('cloudcmd: route: realpath: error', async (t) => { root: fixtureDir, }; - reRequire('./route'); - reRequire('./cloudcmd'); + const options = { + config, + }; - const {connect} = reRequire(beforePath); - const {port, done} = await connect({config}); - const data = await getStr(`http://localhost:${port}/fs/empty-file`); + reRequire(routePath); + const cloudcmd = reRequire(cloudcmdPath); + + const {request} = serveOnce(cloudcmd); + const {body} = await request.get('/fs/empty-file', { + options, + }); fs.realpath = realpath; - t.ok(/^ENOENT/.test(data), 'should return error'); + t.ok(/^ENOENT/.test(body), 'should return error'); t.end(); - - await done(); }); test('cloudcmd: route: sendIndex: encode', async (t) => { @@ -255,17 +283,14 @@ test('cloudcmd: route: sendIndex: encode', async (t) => { }); reRequire(routePath); - reRequire(cloudcmdPath); + const cloudcmd = reRequire(cloudcmdPath); - const {connect} = reRequire(beforePath); - const {port, done} = await connect(); - const data = await getStr(`http://localhost:${port}`); - - t.ok(data.includes(nameEncoded), 'should encode name'); + const {request} = serveOnce(cloudcmd); + const {body} = await request.get('/'); mockRequire.stop('flop'); - await done(); + t.ok(body.includes(nameEncoded), 'should encode name'); t.end(); }); @@ -284,22 +309,15 @@ test('cloudcmd: route: sendIndex: encode: not encoded', async (t) => { read }); - clear(routePath); - clear(cloudcmdPath); - clear(beforePath); + reRequire(routePath); + const cloudcmd = reRequire(cloudcmdPath); - const {connect} = require(beforePath); - const {port, done} = await connect(); - const data = await getStr(`http://localhost:${port}`); - - t.notOk(data.includes(name), 'should not put not encoded name'); + const {request} = serveOnce(cloudcmd); + const {body} = await request.get('/'); mockRequire.stop('flop'); - clear(routePath); - clear(cloudcmdPath); - clear(beforePath); - await done(); + t.notOk(body.includes(name), 'should not put not encoded name'); t.end(); }); @@ -318,23 +336,15 @@ test('cloudcmd: route: sendIndex: ddos: render', async (t) => { read }); - clear(routePath); - clear(cloudcmdPath); - clear(beforePath); + reRequire(routePath); + const cloudcmd = reRequire(cloudcmdPath); - const {connect} = require(beforePath); - const {port, done} = await connect(); - - await getStr(`http://localhost:${port}`); - - t.pass('should not hang up'); + const {request} = serveOnce(cloudcmd); + const {body} = await request.get('/'); mockRequire.stop('flo'); - clear(routePath); - clear(cloudcmdPath); - clear(beforePath); - await done(); + t.pass('should not hang up'); t.end(); }); @@ -343,12 +353,34 @@ test('cloudcmd: route: buttons: no terminal', async (t) => { terminal: false }; - const {port, done} = await connect({config}); - const result = await getStr(`http://localhost:${port}`); + const options = { + config, + } - t.ok(/icon-terminal none/.test(result), 'should hide terminal'); + const {request} = serveOnce(cloudcmd); + const {body} = await request.get('/', { + options + }); - await done(); + t.ok(/icon-terminal none/.test(body), 'should hide terminal'); + t.end(); +}); + +test('cloudcmd: route: no termianl: /fs', async (t) => { + const config = { + terminal: false + }; + + const options = { + config, + } + + const {request} = serveOnce(cloudcmd); + const {body} = await request.get('/fs', { + options, + }); + + t.ok(/icon-terminal none/.test(body), 'should hide terminal'); t.end(); }); @@ -358,12 +390,54 @@ test('cloudcmd: route: buttons: terminal', async (t) => { terminalPath: 'gritty', }; - const {port, done} = await connect({config}); - const result = await getStr(`http://localhost:${port}`); + const options = { + config, + } - t.notOk(/icon-terminal none/.test(result), 'should enable terminal'); + const {request} = serveOnce(cloudcmd); + const {body} = await request.get('/', { + options + }); - await done(); + t.notOk(/icon-terminal none/.test(body), 'should enable terminal'); + t.end(); +}); + +test('cloudcmd: route: buttons: contact', async (t) => { + const config = { + contact: true, + }; + + const options = { + config, + } + + const {request} = serveOnce(cloudcmd); + const {body} = await request.get('/', { + options + }); + + t.notOk(/icon-contact none/.test(body), 'should enable terminal'); + t.end(); +}); + +test('cloudcmd: route: dropbox', async (t) => { + const config = require('./config'); + const dropbox = config('dropbox'); + const dropboxToken = config('dropboxToken'); + + config('dropbox', true); + config('dropboxToken', ''); + + const {_getReadDir} = reRequire(routePath); + + const readdir = _getReadDir(); + const [e] = await tryToCatch(readdir, '/root'); + + config('dropbox', dropbox); + config('dropboxToken', dropboxToken); + + t.ok(/token/.test(e.message), 'should contain word token in message'); t.end(); }); diff --git a/test/server/terminal.js b/test/server/terminal.js index 5557d1a6..1b596047 100644 --- a/test/server/terminal.js +++ b/test/server/terminal.js @@ -1,47 +1,39 @@ 'use strict'; const test = require('tape'); -const mock = require('mock-require'); const diff = require('sinon-called-with-diff'); const sinon = diff(require('sinon')); -const stub = require('mock-require'); -const clean = require('clear-module'); +const mockRequire = require('mock-require'); +const {reRequire} = mockRequire; const configPath = '../../server/config'; const terminalPath = '../../server/terminal'; test('cloudcmd: terminal: disabled', (t) => { - clean(terminalPath); - stub(configPath, () => { + mockRequire(configPath, () => { return false; }); - const terminal = require('../../server/terminal'); - + const terminal = reRequire('../../server/terminal'); const fn = terminal(); + mockRequire.stop(configPath); + t.notOk(fn(), 'should return noop'); - - clean(configPath); - require(configPath); - t.end(); }); test('cloudcmd: terminal: disabled: listen', (t) => { - clean(terminalPath); - stub(configPath, () => false); - - const terminal = require(terminalPath); + mockRequire(configPath, () => false); + const terminal = reRequire(terminalPath); const fn = terminal().listen(); + mockRequire.stop(configPath); + reRequire(terminalPath); + t.notOk(fn, 'should return noop'); - - clean(configPath); - require(configPath); - t.end(); }); @@ -49,13 +41,15 @@ test('cloudcmd: terminal: enabled', (t) => { const term = sinon.stub(); const arg = 'hello'; - clean(terminalPath); - stub(configPath, () => '/terminal'); - stub('/terminal', term); + mockRequire(configPath, () => '/terminal'); + mockRequire(terminalPath, term); const terminal = require(terminalPath); terminal(arg); + mockRequire.stop(configPath); + mockRequire.stop(terminalPath); + t.ok(term.calledWith(arg), 'should call terminal'); t.end(); }); @@ -64,44 +58,41 @@ test('cloudcmd: terminal: enabled: no string', (t) => { const {log:originalLog} = console; const log = sinon.stub(); - clean(terminalPath); - stub(configPath, () => 'hello'); + mockRequire(configPath, () => 'hello'); console.log = log; - const terminal = require(terminalPath); + const terminal = reRequire(terminalPath); terminal(); console.log = originalLog; + mockRequire.stop(configPath); + reRequire(terminalPath); + const msg = 'cloudcmd --terminal: Cannot find module \'hello\''; t.ok(log.calledWith(msg), 'should call exit'); - t.end(); }); test('cloudcmd: terminal: no arg', (t) => { const gritty = {}; - mock('gritty', gritty); - - clean(terminalPath); - stub(configPath, (a) => { + mockRequire('gritty', gritty); + mockRequire(configPath, (a) => { if (a === 'terminal') return true; return 'gritty'; }); - const terminal = require(terminalPath); + const terminal = reRequire(terminalPath); const result = terminal(); + mockRequire.stop('gritty'); + mockRequire.stop(configPath); + reRequire(terminalPath); + t.equal(result, gritty, 'should equal'); - - mock.stop('gritty'); - - clean(configPath); - require(configPath); - t.end(); });