• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

coderaiser / cloudcmd / 26469338489

26 May 2026 07:08PM UTC coverage: 49.248% (+0.5%) from 48.774%
26469338489

push

github

coderaiser
feature: cloudcmd: ratelimit: X-Forwarded-For (#437)

347 of 440 branches covered (78.86%)

35 of 57 new or added lines in 3 files covered. (61.4%)

13 existing lines in 2 files now uncovered.

3800 of 7716 relevant lines covered (49.25%)

9.58 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.85
/bin/cloudcmd.js
1
#!/usr/bin/env node
9✔
2

9✔
3
import process from 'node:process';
9✔
4
import {promisify} from 'node:util';
9✔
5
import {tryToCatch} from 'try-to-catch';
9✔
6
import parse from 'yargs-parser';
9✔
7
import exit from '../server/exit.js';
9✔
8
import {createConfig, configPath} from '../server/config.js';
9✔
9
import * as env from '../server/env.js';
9✔
10
import prefixer from '../server/prefixer.js';
9✔
11
import * as validate from '../server/validate.js';
9✔
12
import Info from '../package.json' with {
9✔
13
    type: 'json',
9✔
14
};
9✔
15

9✔
16
process.on('unhandledRejection', exit);
9✔
17

9✔
18
const isUndefined = (a) => typeof a === 'undefined';
9✔
19

9✔
20
const choose = (a, b) => {
9✔
21
    if (isUndefined(a))
207✔
22
        return b;
207✔
23
    
9✔
24
    return a;
9✔
25
};
9✔
26

9✔
27
const config = createConfig({
9✔
28
    configPath,
9✔
29
});
9✔
30

9✔
31
const maybeRoot = (a) => {
9✔
32
    if (a === '.')
9✔
33
        return process.cwd();
9!
34
    
9✔
35
    return a;
9✔
36
};
9✔
37

9✔
38
const yargsOptions = {
9✔
39
    configuration: {
9✔
40
        'strip-aliased': true,
9✔
41
        'strip-dashed': true,
9✔
42
    },
9✔
43
    coerce: {
9✔
44
        root: maybeRoot,
9✔
45
    },
9✔
46
    string: [
9✔
47
        'name',
9✔
48
        'port',
9✔
49
        'password',
9✔
50
        'username',
9✔
51
        'config',
9✔
52
        'editor',
9✔
53
        'packer',
9✔
54
        'root',
9✔
55
        'prefix',
9✔
56
        'prefix-socket',
9✔
57
        'terminal-path',
9✔
58
        'terminal-command',
9✔
59
        'columns',
9✔
60
        'menu',
9✔
61
        'theme',
9✔
62
        'import-url',
9✔
63
        'import-token',
9✔
64
        'export-token',
9✔
65
        'dropbox-token',
9✔
66
    ],
9✔
67
    boolean: [
9✔
68
        'auth',
9✔
69
        'repl',
9✔
70
        'save',
9✔
71
        'server',
9✔
72
        'online',
9✔
73
        'open',
9✔
74
        'config-dialog',
9✔
75
        'config-auth',
9✔
76
        'config-port',
9✔
77
        'console',
9✔
78
        'sync-console-path',
9✔
79
        'contact',
9✔
80
        'terminal',
9✔
81
        'terminal-auto-restart',
9✔
82
        'one-file-panel',
9✔
83
        'confirm-copy',
9✔
84
        'confirm-move',
9✔
85
        'show-config',
9✔
86
        'show-dot-files',
9✔
87
        'show-file-name',
9✔
88
        'vim',
9✔
89
        'keys-panel',
9✔
90
        'color',
9✔
91
        'export',
9✔
92
        'import',
9✔
93
        'import-listen',
9✔
94
        'log',
9✔
95
        'zip',
9✔
96
        'dropbox',
9✔
97
    ],
9✔
98
    default: {
9✔
99
        'server': true,
9✔
100
        'name': choose(env.parse('name'), config('name')),
9✔
101
        'auth': choose(env.bool('auth'), config('auth')),
9✔
102
        'port': config('port'),
9✔
103
        'online': config('online'),
9✔
104
        'open': choose(env.bool('open'), config('open')),
9✔
105
        'editor': env.parse('editor') || config('editor'),
9✔
106
        'menu': env.parse('menu') || config('menu'),
9✔
107
        'packer': config('packer') || 'tar',
9!
108
        'zip': config('zip'),
9✔
109
        'username': env.parse('username') || config('username'),
9✔
110
        'root': choose(env.parse('root'), config('root')),
9✔
111
        'prefix': choose(env.parse('prefix'), config('prefix')),
9✔
112
        'console': choose(env.bool('console'), config('console')),
9✔
113
        'contact': choose(env.bool('contact'), config('contact')),
9✔
114
        'terminal': choose(env.bool('terminal'), config('terminal')),
9✔
115
        'columns': env.parse('columns') || config('columns') || '',
9!
116
        'theme': env.parse('theme') || config('theme') || '',
9!
117
        'vim': choose(env.bool('vim'), config('vim')),
9✔
118
        'log': choose(env.bool('log'), config('log')),
9✔
119
        
9✔
120
        'import-url': env.parse('import_url') || config('importUrl'),
9✔
121
        'import-listen': choose(env.bool('import_listen'), config('importListen')),
9✔
122
        'import': choose(env.bool('import'), config('import')),
9✔
123
        'export': choose(env.bool('export'), config('export')),
9✔
124
        
9✔
125
        'prefix-socket': config('prefixSocket'),
9✔
126
        'show-dot-files': choose(env.bool('show_dot_files'), config('showDotFiles')),
9✔
127
        'show-file-name': choose(env.bool('show_file_name'), config('showFileName')),
9✔
128
        'sync-console-path': choose(env.bool('sync_console_path'), config('syncConsolePath')),
9✔
129
        'config-dialog': choose(env.bool('config_dialog'), config('configDialog')),
9✔
130
        'config-auth': choose(env.bool('config_auth'), config('configAuth')),
9✔
131
        'config-port': choose(env.bool('config_port'), config('configPort')),
9✔
132
        'terminal-path': env.parse('terminal_path') || config('terminalPath'),
9✔
133
        'terminal-command': env.parse('terminal_command') || config('terminalCommand'),
9✔
134
        'terminal-auto-restart': choose(env.bool('terminal_auto_restart'), config('terminalAutoRestart')),
9✔
135
        'one-file-panel': choose(env.bool('one_file_panel'), config('oneFilePanel')),
9✔
136
        'confirm-copy': choose(env.bool('confirm_copy'), config('confirmCopy')),
9✔
137
        'confirm-move': choose(env.bool('confirm_move'), config('confirmMove')),
9✔
138
        'keys-panel': env.bool('keys_panel') || config('keysPanel'),
9✔
139
        'import-token': env.parse('import_token') || config('importToken'),
9✔
140
        'export-token': env.parse('export_token') || config('exportToken'),
9✔
141
        
9✔
142
        'dropbox': config('dropbox'),
9✔
143
        'dropbox-token': config('dropboxToken') || '',
9✔
144
    },
9✔
145
    alias: {
9✔
146
        version: 'v',
9✔
147
        help: 'h',
9✔
148
        password: 'p',
9✔
149
        online: 'o',
9✔
150
        username: 'u',
9✔
151
        save: 's',
9✔
152
        auth: 'a',
9✔
153
        config: 'c',
9✔
154
    },
9✔
155
};
9✔
156

9✔
157
const {argv} = process;
9✔
158
const args = parse(argv.slice(2), yargsOptions);
9✔
159

9✔
160
if (args.version)
9✔
161
    version();
9✔
162
else if (args.help)
6✔
163
    help();
6✔
164
else
3✔
165
    main();
3✔
166

9✔
167
async function main() {
3✔
168
    const {validateArgs} = await import('@putout/cli-validate-args');
3✔
169
    
3✔
170
    const error = await validateArgs(args, [
3✔
171
        ...yargsOptions.boolean,
3✔
172
        ...yargsOptions.string,
3✔
173
    ]);
3✔
174
    
3✔
175
    if (error)
3✔
176
        return exit(error);
3!
177
    
3✔
178
    if (args.repl)
3✔
179
        await repl();
3!
180
    
3✔
181
    validate.columns(args.columns);
3✔
182
    validate.theme(args.theme);
3✔
183
    
3✔
184
    port(args.port);
3✔
185
    
3✔
186
    config('name', args.name);
3✔
187
    config('auth', args.auth);
3✔
188
    config('online', args.online);
3✔
189
    config('open', args.open);
3✔
190
    config('username', args.username);
3✔
191
    config('console', args.console);
3✔
192
    config('syncConsolePath', args.syncConsolePath);
3✔
193
    config('showDotFiles', args.showDotFiles);
3✔
194
    config('showFileName', args.showFileName);
3✔
195
    config('contact', args.contact);
3✔
196
    config('terminal', args.terminal);
3✔
197
    config('terminalPath', args.terminalPath);
3✔
198
    config('terminalCommand', args.terminalCommand);
3✔
199
    config('terminalAutoRestart', args.terminalAutoRestart);
3✔
200
    config('editor', args.editor);
3✔
201
    config('menu', args.menu);
3✔
202
    config('prefix', prefixer(args.prefix));
3✔
203
    config('prefixSocket', prefixer(args.prefixSocket));
3✔
204
    config('root', args.root || '/');
3!
205
    config('vim', args.vim);
3✔
206
    config('theme', args.theme);
3✔
207
    config('columns', args.columns);
3✔
208
    config('log', args.log);
3✔
209
    config('confirmCopy', args.confirmCopy);
3✔
210
    config('confirmMove', args.confirmMove);
3✔
211
    config('oneFilePanel', args.oneFilePanel);
3✔
212
    config('configDialog', args.configDialog);
3✔
213
    config('configAuth', args.configAuth);
3✔
214
    config('configPort', args.configPort);
3✔
215
    config('keysPanel', args.keysPanel);
3✔
216
    config('export', args.export);
3✔
217
    config('exportToken', args.exportToken);
3✔
218
    config('import', args.import);
3✔
219
    config('importToken', args.importToken);
3✔
220
    config('importListen', args.importListen);
3✔
221
    config('importUrl', args.importUrl);
3✔
222
    
3✔
223
    config('dropbox', args.dropbox);
3✔
224
    config('dropboxToken', args.dropboxToken);
3✔
225
    
3✔
226
    await readConfig(args.config);
3✔
227
    
3✔
228
    const options = {
3✔
229
        root: config('root'),
3✔
230
        editor: config('editor'),
3✔
231
        packer: config('packer'),
3✔
232
        prefix: config('prefix'),
3✔
233
        prefixSocket: config('prefixSocket'),
3✔
234
        columns: config('columns'),
3✔
235
        theme: config('theme'),
3✔
236
        menu: config('menu'),
3✔
237
    };
3✔
238
    
3✔
239
    const password = env.parse('password') || args.password;
3✔
240
    
3✔
241
    if (password)
3✔
242
        config('password', await getPassword(password));
3!
243
    
3✔
244
    validateRoot(options.root, config);
3✔
245
    
3✔
246
    if (args.showConfig)
3✔
247
        await showConfig();
3!
248
    
3✔
249
    const {distributeImport} = await import('../server/distribute/import.js');
3✔
250
    const importConfig = promisify(distributeImport);
3✔
251
    
3✔
252
    await start(options, config);
3✔
253
    
3✔
254
    if (args.save)
3✔
255
        config.write();
3!
256
    
3✔
257
    await tryToCatch(checkUpdate);
3✔
UNCOV
258
    await importConfig(config);
×
259
}
3✔
260

9✔
261
function validateRoot(root, config) {
3✔
262
    validate.root(root, config);
3✔
263
    
3✔
264
    if (root === '/')
3✔
265
        return;
3✔
266
    
×
NEW
267
    if (config('log'))
×
NEW
268
        console.log(`root: ${root}`);
×
269
}
3✔
270

9✔
271
async function getPassword(password) {
×
272
    const {default: criton} = await import('criton');
×
273
    return criton(password, config('algo'));
×
274
}
×
275

9✔
276
function version() {
3✔
277
    console.log('v' + Info.version);
3✔
278
}
3✔
279

9✔
280
async function start(options, config) {
3✔
281
    if (!args.server)
3✔
282
        return;
3!
283
    
3✔
284
    const {default: server} = await import('../server/server.js');
3✔
285
    server(options, config);
3✔
286
}
3✔
287

9✔
288
function port(arg) {
3✔
289
    const number = parseInt(arg, 10);
3✔
290
    
3✔
291
    if (!isNaN(number))
3✔
292
        return config('port', number);
3✔
293
    
×
294
    exit('cloudcmd --port: should be a number');
×
295
}
3✔
296

9✔
297
async function showConfig() {
×
298
    const {showConfig} = await import('../server/show-config.js');
×
299
    const data = showConfig(config('*'));
×
300
    
×
301
    console.log(data);
×
302
}
×
303

9✔
304
async function readConfig(name) {
3✔
305
    if (!name)
3✔
306
        return;
3✔
307
    
×
308
    const {default: forEachKey} = await import('for-each-key');
×
309
    
×
310
    const data = await import(name, {
×
311
        with: {
×
312
            type: 'json',
×
313
        },
×
314
    });
×
315
    
×
316
    forEachKey(config, data);
×
317
}
3✔
318

9✔
319
async function help() {
3✔
320
    const {default: bin} = await import('../json/help.json', {
3✔
321
        with: {
3✔
322
            type: 'json',
3✔
323
        },
3✔
324
    });
3✔
325
    
3✔
326
    const {default: forEachKey} = await import('for-each-key');
3✔
327
    const {default: currify} = await import('currify');
3✔
328
    
3✔
329
    const usage = 'Usage: cloudcmd [options]';
3✔
330
    const url = Info.homepage;
3✔
331
    const log = currify((a, b, c) => console.log(a, b, c));
3✔
332
    
3✔
333
    console.log(usage);
3✔
334
    console.log('Options:');
3✔
335
    forEachKey(log('  %s %s'), bin);
3✔
336
    console.log('\nGeneral help using Cloud Commander: <%s>', url);
3✔
337
}
3✔
338

9✔
339
async function repl() {
×
340
    console.log('REPL mode enabled (telnet localhost 1337)');
×
341
    await import('../server/repl.js');
×
342
}
×
343

9✔
344
async function checkUpdate() {
3✔
345
    const {default: load} = await import('package-json');
3✔
346
    const {version} = await load(Info.name, 'latest');
3✔
UNCOV
347
    
×
UNCOV
348
    await showUpdateInfo(version);
×
349
}
3✔
350

9✔
UNCOV
351
async function showUpdateInfo(version) {
×
UNCOV
352
    if (version === Info.version)
×
UNCOV
353
        return;
×
354
    
×
355
    const {default: chalk} = await import('chalk');
×
356
    
×
357
    const latestVersion = chalk.green.bold(`v${version}`);
×
358
    const latest = `update available: ${latestVersion}`;
×
359
    const current = chalk.dim(`(current: v${Info.version})`);
×
360
    
×
361
    console.log('%s %s', latest, current);
×
UNCOV
362
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc