UNPKG

cloudcmd

Version:

File manager for the web with console and editor

256 lines (195 loc) 6.09 kB
'use strict'; const DIR_SERVER = `${__dirname}/`; const DIR_COMMON = '../common/'; const path = require('node:path'); const fs = require('node:fs'); const Emitter = require('node:events'); const {homedir} = require('node:os'); const currify = require('currify'); const wraptile = require('wraptile'); const tryToCatch = require('try-to-catch'); const pullout = require('pullout'); const ponse = require('ponse'); const jonny = require('jonny'); const jju = require('jju'); const writejson = require('writejson'); const tryCatch = require('try-catch'); const criton = require('criton'); const exit = require(`${DIR_SERVER}exit`); const CloudFunc = require(`${DIR_COMMON}cloudfunc`); const isUndefined = (a) => typeof a === 'undefined'; const DIR = `${DIR_SERVER}../`; const HOME = homedir(); const resolve = Promise.resolve.bind(Promise); const formatMsg = currify((a, b) => CloudFunc.formatMsg(a, b)); const {apiURL} = CloudFunc; const key = (a) => Object .keys(a) .pop(); const ConfigPath = path.join(DIR, 'json/config.json'); const ConfigHome = path.join(HOME, '.cloudcmd.json'); const connection = currify(_connection); const connectionWrapped = wraptile(_connection); const middle = currify(_middle); const readjsonSync = (name) => { return jju.parse(fs.readFileSync(name, 'utf8'), { mode: 'json', }); }; const rootConfig = readjsonSync(ConfigPath); function read(filename) { if (!filename) return rootConfig; const [error, configHome] = tryCatch(readjsonSync, filename); if (error && error.code !== 'ENOENT') exit(`cloudcmd --config ${filename}: ${error.message}`); return { ...rootConfig, ...configHome, }; } module.exports.createConfig = createConfig; module.exports.configPath = ConfigHome; const manageListen = currify((manage, socket, auth) => { if (!manage('configDialog')) return middle; listen(manage, socket, auth); return middle; }); function initWrite(filename, configManager) { if (filename) return write.bind(null, filename, configManager); return resolve; } function createConfig({configPath} = {}) { const config = {}; const changeEmitter = new Emitter(); const configManager = (key, value) => { if (key === '*') return config; if (isUndefined(value)) return config[key]; config[key] = value; changeEmitter.emit('change', key, value); return `${key} = ${value}`; }; Object.assign(config, read(configPath)); configManager.middle = middle(configManager); configManager.listen = manageListen(configManager); configManager.write = initWrite(configPath, configManager); configManager.subscribe = (fn) => { changeEmitter.on('change', fn); }; configManager.unsubscribe = (fn) => { changeEmitter.off('change', fn); }; return configManager; } const write = (filename, config) => { return writejson(filename, config('*'), { mode: 0o600, }); }; function _connection(manage, socket) { socket.emit('config', manage('*')); const emit = currify((socket, name, e) => { return socket.emit(name, e.message); }); socket.on('message', (json) => { if (typeof json !== 'object') return socket.emit('err', 'Error: Wrong data type!'); traverse(cryptoPass(manage, json)); const send = () => { const data = CloudFunc.formatMsg('config', key(json)); socket.send(json); socket.emit('log', data); }; manage .write() .then(send) .catch(emit(socket, 'err')); }); } function listen(manage, sock, auth) { const prefix = manage('prefixSocket'); sock .of(`${prefix}/config`) .on('connection', (socket) => { if (!manage('auth')) return connection(manage, socket); const reject = () => socket.emit('reject'); socket.on('auth', auth(connectionWrapped(manage, socket), reject)); }); } async function _middle(manage, req, res, next) { const noConfigDialog = !manage('configDialog'); if (req.url !== `${apiURL}/config`) return next(); switch(req.method) { case 'GET': get(manage, req, res); break; case 'PATCH': if (noConfigDialog) return res .status(404) .send('Config is disabled'); await patch(manage, req, res); break; default: next(); } } function get(manage, request, response) { const data = jonny.stringify(manage('*')); ponse.send(data, { name: 'config.json', request, response, cache: false, }); } async function patch(manage, request, response) { const name = 'config.json'; const cache = false; const options = { name, request, response, cache, }; const [e] = await tryToCatch(patchConfig, manage, options); if (e) ponse.sendError(e, options); } async function patchConfig(manage, {name, request, response, cache}) { const str = await pullout(request); const json = jonny.parse(str); traverse(cryptoPass(manage, json)); await manage.write(); const msg = formatMsg('config', key(json)); ponse.send(msg, { name, request, response, cache, }); } function traverse([manage, json]) { for (const name of Object.keys(json)) { manage(name, json[name]); } } module.exports._cryptoPass = cryptoPass; function cryptoPass(manage, json) { const algo = manage('algo'); if (!json.password) return [manage, json]; const password = criton(json.password, algo); return [ manage, { ...json, password, }, ]; }