@qodalis/cli-files 2.0.0-beta.12 → 2.0.0-beta.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/public-api.d.mts +89 -2
- package/public-api.d.ts +89 -2
- package/public-api.js +357 -60
- package/public-api.js.map +1 -1
- package/public-api.mjs +352 -62
- package/public-api.mjs.map +1 -1
- package/umd/index.global.js +209 -39
package/public-api.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { ICliCompletionProvider_TOKEN, ICliFileTransferService_TOKEN, BrowserFileTransferService, DefaultLibraryAuthor, CliForegroundColor, ICliDragDropService_TOKEN } from '@qodalis/cli-core';
|
|
1
|
+
import { ICliCompletionProvider_TOKEN, ICliFileTransferService_TOKEN, CliAccessDeniedError, BrowserFileTransferService, DefaultLibraryAuthor, CliForegroundColor, resolveHeaders, cliCanAccess, ICliUserSessionService_TOKEN, ICliUserEventService_TOKEN, ICliDragDropService_TOKEN, isCliAccessDeniedError, ICliAuthorizationService_TOKEN } from '@qodalis/cli-core';
|
|
2
2
|
|
|
3
3
|
// src/lib/interfaces/i-file-system-service.ts
|
|
4
4
|
var IFileSystemService_TOKEN = "cli-file-system-service";
|
|
5
5
|
|
|
6
6
|
// src/lib/version.ts
|
|
7
|
-
var LIBRARY_VERSION = "2.0.0-beta.
|
|
7
|
+
var LIBRARY_VERSION = "2.0.0-beta.14";
|
|
8
8
|
var API_VERSION = 2;
|
|
9
9
|
|
|
10
10
|
// src/lib/processors/cli-ls-command-processor.ts
|
|
@@ -34,7 +34,7 @@ var CliLsCommandProcessor = class {
|
|
|
34
34
|
];
|
|
35
35
|
}
|
|
36
36
|
async processCommand(command, context) {
|
|
37
|
-
const fs = context.services.
|
|
37
|
+
const fs = context.services.getRequired(
|
|
38
38
|
IFileSystemService_TOKEN
|
|
39
39
|
);
|
|
40
40
|
const targetPath = command.value || fs.getCurrentDirectory();
|
|
@@ -105,7 +105,7 @@ var CliCdCommandProcessor = class {
|
|
|
105
105
|
this.metadata = { icon: "\u{1F4C1}", module: "file management" };
|
|
106
106
|
}
|
|
107
107
|
async processCommand(command, context) {
|
|
108
|
-
const fs = context.services.
|
|
108
|
+
const fs = context.services.getRequired(
|
|
109
109
|
IFileSystemService_TOKEN
|
|
110
110
|
);
|
|
111
111
|
const target = command.value || "~";
|
|
@@ -126,7 +126,7 @@ var CliPwdCommandProcessor = class {
|
|
|
126
126
|
this.metadata = { icon: "\u{1F4C2}", module: "file management" };
|
|
127
127
|
}
|
|
128
128
|
async processCommand(command, context) {
|
|
129
|
-
const fs = context.services.
|
|
129
|
+
const fs = context.services.getRequired(
|
|
130
130
|
IFileSystemService_TOKEN
|
|
131
131
|
);
|
|
132
132
|
context.writer.writeln(fs.getCurrentDirectory());
|
|
@@ -152,7 +152,7 @@ var CliMkdirCommandProcessor = class {
|
|
|
152
152
|
];
|
|
153
153
|
}
|
|
154
154
|
async processCommand(command, context) {
|
|
155
|
-
const fs = context.services.
|
|
155
|
+
const fs = context.services.getRequired(
|
|
156
156
|
IFileSystemService_TOKEN
|
|
157
157
|
);
|
|
158
158
|
const path = command.value;
|
|
@@ -180,7 +180,7 @@ var CliRmdirCommandProcessor = class {
|
|
|
180
180
|
this.metadata = { icon: "\u{1F5D1}", module: "file management" };
|
|
181
181
|
}
|
|
182
182
|
async processCommand(command, context) {
|
|
183
|
-
const fs = context.services.
|
|
183
|
+
const fs = context.services.getRequired(
|
|
184
184
|
IFileSystemService_TOKEN
|
|
185
185
|
);
|
|
186
186
|
const path = command.value;
|
|
@@ -224,7 +224,7 @@ var CliTouchCommandProcessor = class {
|
|
|
224
224
|
this.metadata = { icon: "\u{1F4C4}", module: "file management" };
|
|
225
225
|
}
|
|
226
226
|
async processCommand(command, context) {
|
|
227
|
-
const fs = context.services.
|
|
227
|
+
const fs = context.services.getRequired(
|
|
228
228
|
IFileSystemService_TOKEN
|
|
229
229
|
);
|
|
230
230
|
const path = command.value;
|
|
@@ -251,7 +251,7 @@ var CliCatCommandProcessor = class {
|
|
|
251
251
|
this.metadata = { icon: "\u{1F4D6}", module: "file management" };
|
|
252
252
|
}
|
|
253
253
|
async processCommand(command, context) {
|
|
254
|
-
const fs = context.services.
|
|
254
|
+
const fs = context.services.getRequired(
|
|
255
255
|
IFileSystemService_TOKEN
|
|
256
256
|
);
|
|
257
257
|
const path = command.value;
|
|
@@ -290,7 +290,7 @@ var CliEchoCommandProcessor = class {
|
|
|
290
290
|
}
|
|
291
291
|
return;
|
|
292
292
|
}
|
|
293
|
-
const fs = context.services.
|
|
293
|
+
const fs = context.services.getRequired(
|
|
294
294
|
IFileSystemService_TOKEN
|
|
295
295
|
);
|
|
296
296
|
let text;
|
|
@@ -362,7 +362,7 @@ var CliRmCommandProcessor = class {
|
|
|
362
362
|
];
|
|
363
363
|
}
|
|
364
364
|
async processCommand(command, context) {
|
|
365
|
-
const fs = context.services.
|
|
365
|
+
const fs = context.services.getRequired(
|
|
366
366
|
IFileSystemService_TOKEN
|
|
367
367
|
);
|
|
368
368
|
const path = command.value;
|
|
@@ -411,7 +411,7 @@ var CliCpCommandProcessor = class {
|
|
|
411
411
|
];
|
|
412
412
|
}
|
|
413
413
|
async processCommand(command, context) {
|
|
414
|
-
const fs = context.services.
|
|
414
|
+
const fs = context.services.getRequired(
|
|
415
415
|
IFileSystemService_TOKEN
|
|
416
416
|
);
|
|
417
417
|
const recursive = command.args["recursive"] || command.args["r"] || command.args["R"];
|
|
@@ -447,7 +447,7 @@ var CliMvCommandProcessor = class {
|
|
|
447
447
|
this.metadata = { icon: "\u{1F4E6}", module: "file management" };
|
|
448
448
|
}
|
|
449
449
|
async processCommand(command, context) {
|
|
450
|
-
const fs = context.services.
|
|
450
|
+
const fs = context.services.getRequired(
|
|
451
451
|
IFileSystemService_TOKEN
|
|
452
452
|
);
|
|
453
453
|
const parts = this.parseArgs(command);
|
|
@@ -470,6 +470,14 @@ var CliMvCommandProcessor = class {
|
|
|
470
470
|
return raw.split(/\s+/).filter((t) => t && !t.startsWith("--") && !t.startsWith("-"));
|
|
471
471
|
}
|
|
472
472
|
};
|
|
473
|
+
function readableChildren(fs, path) {
|
|
474
|
+
try {
|
|
475
|
+
return fs.listDirectory(path);
|
|
476
|
+
} catch (e) {
|
|
477
|
+
if (isCliAccessDeniedError(e)) return null;
|
|
478
|
+
throw e;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
473
481
|
var CliTreeCommandProcessor = class {
|
|
474
482
|
constructor() {
|
|
475
483
|
this.command = "tree";
|
|
@@ -489,7 +497,7 @@ var CliTreeCommandProcessor = class {
|
|
|
489
497
|
];
|
|
490
498
|
}
|
|
491
499
|
async processCommand(command, context) {
|
|
492
|
-
const fs = context.services.
|
|
500
|
+
const fs = context.services.getRequired(
|
|
493
501
|
IFileSystemService_TOKEN
|
|
494
502
|
);
|
|
495
503
|
const targetPath = command.value || fs.getCurrentDirectory();
|
|
@@ -516,7 +524,8 @@ var CliTreeCommandProcessor = class {
|
|
|
516
524
|
)
|
|
517
525
|
);
|
|
518
526
|
const counts = { dirs: 0, files: 0 };
|
|
519
|
-
this.
|
|
527
|
+
this.fs = fs;
|
|
528
|
+
this.printTree(node, "", true, 0, maxDepth, context, counts, resolvedPath);
|
|
520
529
|
context.writer.writeln();
|
|
521
530
|
context.writer.writeln(
|
|
522
531
|
`${counts.dirs} directories, ${counts.files} files`
|
|
@@ -525,11 +534,15 @@ var CliTreeCommandProcessor = class {
|
|
|
525
534
|
context.writer.writeError(e.message);
|
|
526
535
|
}
|
|
527
536
|
}
|
|
528
|
-
printTree(node, prefix, isRoot, depth, maxDepth, context, counts) {
|
|
529
|
-
if (
|
|
537
|
+
printTree(node, prefix, isRoot, depth, maxDepth, context, counts, path = "/") {
|
|
538
|
+
if (depth >= maxDepth) {
|
|
530
539
|
return;
|
|
531
540
|
}
|
|
532
|
-
const
|
|
541
|
+
const visible = this.fs ? readableChildren(this.fs, path) : node.children;
|
|
542
|
+
if (!visible) {
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
545
|
+
const children = [...visible].sort((a, b) => {
|
|
533
546
|
if (a.type !== b.type) {
|
|
534
547
|
return a.type === "directory" ? -1 : 1;
|
|
535
548
|
}
|
|
@@ -554,7 +567,8 @@ var CliTreeCommandProcessor = class {
|
|
|
554
567
|
depth + 1,
|
|
555
568
|
maxDepth,
|
|
556
569
|
context,
|
|
557
|
-
counts
|
|
570
|
+
counts,
|
|
571
|
+
path === "/" ? `/${child.name}` : `${path}/${child.name}`
|
|
558
572
|
);
|
|
559
573
|
} else {
|
|
560
574
|
counts.files++;
|
|
@@ -582,7 +596,7 @@ var CliHeadCommandProcessor = class {
|
|
|
582
596
|
];
|
|
583
597
|
}
|
|
584
598
|
async processCommand(command, context) {
|
|
585
|
-
const fs = context.services.
|
|
599
|
+
const fs = context.services.getRequired(
|
|
586
600
|
IFileSystemService_TOKEN
|
|
587
601
|
);
|
|
588
602
|
const count = parseInt(
|
|
@@ -647,7 +661,7 @@ var CliTailCommandProcessor = class {
|
|
|
647
661
|
];
|
|
648
662
|
}
|
|
649
663
|
async processCommand(command, context) {
|
|
650
|
-
const fs = context.services.
|
|
664
|
+
const fs = context.services.getRequired(
|
|
651
665
|
IFileSystemService_TOKEN
|
|
652
666
|
);
|
|
653
667
|
const count = parseInt(
|
|
@@ -726,7 +740,7 @@ var CliWcCommandProcessor = class {
|
|
|
726
740
|
];
|
|
727
741
|
}
|
|
728
742
|
async processCommand(command, context) {
|
|
729
|
-
const fs = context.services.
|
|
743
|
+
const fs = context.services.getRequired(
|
|
730
744
|
IFileSystemService_TOKEN
|
|
731
745
|
);
|
|
732
746
|
const showLines = command.args["lines"] || command.args["l"] || false;
|
|
@@ -820,7 +834,7 @@ var CliFindCommandProcessor = class {
|
|
|
820
834
|
];
|
|
821
835
|
}
|
|
822
836
|
async processCommand(command, context) {
|
|
823
|
-
const fs = context.services.
|
|
837
|
+
const fs = context.services.getRequired(
|
|
824
838
|
IFileSystemService_TOKEN
|
|
825
839
|
);
|
|
826
840
|
const searchPath = this.parseSearchPath(command) || fs.getCurrentDirectory();
|
|
@@ -844,6 +858,7 @@ var CliFindCommandProcessor = class {
|
|
|
844
858
|
const resolvedBase = fs.resolvePath(searchPath);
|
|
845
859
|
const nameRegex = namePattern ? this.globToRegex(namePattern) : null;
|
|
846
860
|
const results = [];
|
|
861
|
+
this.fs = fs;
|
|
847
862
|
this.walk(
|
|
848
863
|
node,
|
|
849
864
|
resolvedBase,
|
|
@@ -871,8 +886,9 @@ var CliFindCommandProcessor = class {
|
|
|
871
886
|
return new RegExp(`^${regexStr}$`, "i");
|
|
872
887
|
}
|
|
873
888
|
walk(node, currentPath, depth, maxDepth, nameRegex, typeFilter, results) {
|
|
874
|
-
|
|
875
|
-
|
|
889
|
+
const children = this.fs ? readableChildren(this.fs, currentPath) : node.children;
|
|
890
|
+
if (!children) return;
|
|
891
|
+
for (const child of children) {
|
|
876
892
|
const childPath = currentPath === "/" ? `/${child.name}` : `${currentPath}/${child.name}`;
|
|
877
893
|
let matches = true;
|
|
878
894
|
if (nameRegex && !nameRegex.test(child.name)) {
|
|
@@ -955,7 +971,7 @@ var CliGrepCommandProcessor = class {
|
|
|
955
971
|
];
|
|
956
972
|
}
|
|
957
973
|
async processCommand(command, context) {
|
|
958
|
-
const fs = context.services.
|
|
974
|
+
const fs = context.services.getRequired(
|
|
959
975
|
IFileSystemService_TOKEN
|
|
960
976
|
);
|
|
961
977
|
const ignoreCase = command.args["ignore-case"] || command.args["i"] || false;
|
|
@@ -1103,8 +1119,9 @@ var CliGrepCommandProcessor = class {
|
|
|
1103
1119
|
};
|
|
1104
1120
|
}
|
|
1105
1121
|
collectFiles(fs, basePath, node, result) {
|
|
1106
|
-
|
|
1107
|
-
|
|
1122
|
+
const children = readableChildren(fs, basePath);
|
|
1123
|
+
if (!children) return;
|
|
1124
|
+
for (const child of children) {
|
|
1108
1125
|
const childPath = basePath === "/" ? `/${child.name}` : `${basePath}/${child.name}`;
|
|
1109
1126
|
if (child.type === "file") {
|
|
1110
1127
|
result.push(childPath);
|
|
@@ -1125,7 +1142,7 @@ var CliTacCommandProcessor = class {
|
|
|
1125
1142
|
this.metadata = { icon: "\u{1F504}", module: "file management" };
|
|
1126
1143
|
}
|
|
1127
1144
|
async processCommand(command, context) {
|
|
1128
|
-
const fs = context.services.
|
|
1145
|
+
const fs = context.services.getRequired(
|
|
1129
1146
|
IFileSystemService_TOKEN
|
|
1130
1147
|
);
|
|
1131
1148
|
const paths = this.parsePaths(command);
|
|
@@ -1297,7 +1314,7 @@ var CliSortCommandProcessor = class {
|
|
|
1297
1314
|
];
|
|
1298
1315
|
}
|
|
1299
1316
|
async processCommand(command, context) {
|
|
1300
|
-
const fs = context.services.
|
|
1317
|
+
const fs = context.services.getRequired(
|
|
1301
1318
|
IFileSystemService_TOKEN
|
|
1302
1319
|
);
|
|
1303
1320
|
const reverse = !!command.args["r"] || !!command.args["reverse"];
|
|
@@ -1450,7 +1467,7 @@ var CliUniqCommandProcessor = class {
|
|
|
1450
1467
|
];
|
|
1451
1468
|
}
|
|
1452
1469
|
async processCommand(command, context) {
|
|
1453
|
-
const fs = context.services.
|
|
1470
|
+
const fs = context.services.getRequired(
|
|
1454
1471
|
IFileSystemService_TOKEN
|
|
1455
1472
|
);
|
|
1456
1473
|
const showCount = !!command.args["c"] || !!command.args["count"];
|
|
@@ -1581,7 +1598,7 @@ var CliCutCommandProcessor = class {
|
|
|
1581
1598
|
];
|
|
1582
1599
|
}
|
|
1583
1600
|
async processCommand(command, context) {
|
|
1584
|
-
const fs = context.services.
|
|
1601
|
+
const fs = context.services.getRequired(
|
|
1585
1602
|
IFileSystemService_TOKEN
|
|
1586
1603
|
);
|
|
1587
1604
|
const delimiter = command.args["d"] || command.args["delimiter"] || " ";
|
|
@@ -1731,7 +1748,7 @@ var CliPasteCommandProcessor = class {
|
|
|
1731
1748
|
];
|
|
1732
1749
|
}
|
|
1733
1750
|
async processCommand(command, context) {
|
|
1734
|
-
const fs = context.services.
|
|
1751
|
+
const fs = context.services.getRequired(
|
|
1735
1752
|
IFileSystemService_TOKEN
|
|
1736
1753
|
);
|
|
1737
1754
|
const delimiter = command.args["d"] || command.args["delimiters"] || " ";
|
|
@@ -1898,7 +1915,7 @@ var CliTrCommandProcessor = class {
|
|
|
1898
1915
|
];
|
|
1899
1916
|
}
|
|
1900
1917
|
async processCommand(command, context) {
|
|
1901
|
-
const fs = context.services.
|
|
1918
|
+
const fs = context.services.getRequired(
|
|
1902
1919
|
IFileSystemService_TOKEN
|
|
1903
1920
|
);
|
|
1904
1921
|
const raw = command.value || "";
|
|
@@ -2053,7 +2070,7 @@ var CliStatCommandProcessor = class {
|
|
|
2053
2070
|
this.parameters = [];
|
|
2054
2071
|
}
|
|
2055
2072
|
async processCommand(command, context) {
|
|
2056
|
-
const fs = context.services.
|
|
2073
|
+
const fs = context.services.getRequired(
|
|
2057
2074
|
IFileSystemService_TOKEN
|
|
2058
2075
|
);
|
|
2059
2076
|
const paths = this.parsePaths(command);
|
|
@@ -2063,6 +2080,10 @@ var CliStatCommandProcessor = class {
|
|
|
2063
2080
|
}
|
|
2064
2081
|
for (const path of paths) {
|
|
2065
2082
|
const resolved = fs.resolvePath(path);
|
|
2083
|
+
if (fs.canTraverse && !fs.canTraverse(resolved)) {
|
|
2084
|
+
context.writer.writeError(`stat: cannot stat '${path}': Permission denied`);
|
|
2085
|
+
continue;
|
|
2086
|
+
}
|
|
2066
2087
|
const node = fs.getNode(resolved);
|
|
2067
2088
|
if (!node) {
|
|
2068
2089
|
context.writer.writeError(
|
|
@@ -2106,7 +2127,7 @@ var CliChmodCommandProcessor = class {
|
|
|
2106
2127
|
];
|
|
2107
2128
|
}
|
|
2108
2129
|
async processCommand(command, context) {
|
|
2109
|
-
const fs = context.services.
|
|
2130
|
+
const fs = context.services.getRequired(
|
|
2110
2131
|
IFileSystemService_TOKEN
|
|
2111
2132
|
);
|
|
2112
2133
|
const { recursive, mode, paths } = this.parseArgs(command);
|
|
@@ -2226,7 +2247,7 @@ var CliChownCommandProcessor = class {
|
|
|
2226
2247
|
];
|
|
2227
2248
|
}
|
|
2228
2249
|
async processCommand(command, context) {
|
|
2229
|
-
const fs = context.services.
|
|
2250
|
+
const fs = context.services.getRequired(
|
|
2230
2251
|
IFileSystemService_TOKEN
|
|
2231
2252
|
);
|
|
2232
2253
|
const { recursive, ownerSpec, paths } = this.parseArgs(command);
|
|
@@ -2321,7 +2342,7 @@ var CliDuCommandProcessor = class {
|
|
|
2321
2342
|
];
|
|
2322
2343
|
}
|
|
2323
2344
|
async processCommand(command, context) {
|
|
2324
|
-
const fs = context.services.
|
|
2345
|
+
const fs = context.services.getRequired(
|
|
2325
2346
|
IFileSystemService_TOKEN
|
|
2326
2347
|
);
|
|
2327
2348
|
const { humanReadable, summaryOnly, maxDepth, paths } = this.parseArgs(command);
|
|
@@ -2331,6 +2352,10 @@ var CliDuCommandProcessor = class {
|
|
|
2331
2352
|
}
|
|
2332
2353
|
for (const path of paths) {
|
|
2333
2354
|
const resolved = fs.resolvePath(path);
|
|
2355
|
+
if (fs.canTraverse && !fs.canTraverse(resolved)) {
|
|
2356
|
+
context.writer.writeError(`du: cannot access '${path}': Permission denied`);
|
|
2357
|
+
continue;
|
|
2358
|
+
}
|
|
2334
2359
|
const node = fs.getNode(resolved);
|
|
2335
2360
|
if (!node) {
|
|
2336
2361
|
context.writer.writeError(
|
|
@@ -2344,6 +2369,7 @@ var CliDuCommandProcessor = class {
|
|
|
2344
2369
|
);
|
|
2345
2370
|
} else {
|
|
2346
2371
|
const entries = [];
|
|
2372
|
+
this.fs = fs;
|
|
2347
2373
|
this.collectSizes(node, resolved, 0, maxDepth, summaryOnly, entries);
|
|
2348
2374
|
for (const entry of entries) {
|
|
2349
2375
|
context.writer.writeln(
|
|
@@ -2366,8 +2392,9 @@ var CliDuCommandProcessor = class {
|
|
|
2366
2392
|
return node.size;
|
|
2367
2393
|
}
|
|
2368
2394
|
let total = 0;
|
|
2369
|
-
|
|
2370
|
-
|
|
2395
|
+
const children = this.fs ? readableChildren(this.fs, path) : node.children;
|
|
2396
|
+
if (children) {
|
|
2397
|
+
for (const child of children) {
|
|
2371
2398
|
const childPath = path === "/" ? `/${child.name}` : `${path}/${child.name}`;
|
|
2372
2399
|
total += this.collectSizes(
|
|
2373
2400
|
child,
|
|
@@ -2418,7 +2445,7 @@ var CliLnCommandProcessor = class {
|
|
|
2418
2445
|
];
|
|
2419
2446
|
}
|
|
2420
2447
|
async processCommand(command, context) {
|
|
2421
|
-
const fs = context.services.
|
|
2448
|
+
const fs = context.services.getRequired(
|
|
2422
2449
|
IFileSystemService_TOKEN
|
|
2423
2450
|
);
|
|
2424
2451
|
const { symbolic, target, linkName } = this.parseArgs(command);
|
|
@@ -2492,7 +2519,7 @@ var CliSedCommandProcessor = class {
|
|
|
2492
2519
|
];
|
|
2493
2520
|
}
|
|
2494
2521
|
async processCommand(command, context) {
|
|
2495
|
-
const fs = context.services.
|
|
2522
|
+
const fs = context.services.getRequired(
|
|
2496
2523
|
IFileSystemService_TOKEN
|
|
2497
2524
|
);
|
|
2498
2525
|
const { inPlace, suppress, expressions, filePath } = this.parseRawCommand(command);
|
|
@@ -2835,7 +2862,7 @@ var CliAwkCommandProcessor = class {
|
|
|
2835
2862
|
];
|
|
2836
2863
|
}
|
|
2837
2864
|
async processCommand(command, context) {
|
|
2838
|
-
const fs = context.services.
|
|
2865
|
+
const fs = context.services.getRequired(
|
|
2839
2866
|
IFileSystemService_TOKEN
|
|
2840
2867
|
);
|
|
2841
2868
|
const { program, filePath, fieldSep } = this.parseArgs(command);
|
|
@@ -3311,7 +3338,7 @@ var CliDiffCommandProcessor = class {
|
|
|
3311
3338
|
];
|
|
3312
3339
|
}
|
|
3313
3340
|
async processCommand(command, context) {
|
|
3314
|
-
const fs = context.services.
|
|
3341
|
+
const fs = context.services.getRequired(
|
|
3315
3342
|
IFileSystemService_TOKEN
|
|
3316
3343
|
);
|
|
3317
3344
|
const unified = command.args["unified"] || command.args["u"] || false;
|
|
@@ -3497,7 +3524,7 @@ var CliTeeCommandProcessor = class {
|
|
|
3497
3524
|
];
|
|
3498
3525
|
}
|
|
3499
3526
|
async processCommand(command, context) {
|
|
3500
|
-
const fs = context.services.
|
|
3527
|
+
const fs = context.services.getRequired(
|
|
3501
3528
|
IFileSystemService_TOKEN
|
|
3502
3529
|
);
|
|
3503
3530
|
const append = command.args["append"] || command.args["a"] || false;
|
|
@@ -3591,7 +3618,7 @@ var CliXargsCommandProcessor = class {
|
|
|
3591
3618
|
];
|
|
3592
3619
|
}
|
|
3593
3620
|
async processCommand(command, context) {
|
|
3594
|
-
const fs = context.services.
|
|
3621
|
+
const fs = context.services.getRequired(
|
|
3595
3622
|
IFileSystemService_TOKEN
|
|
3596
3623
|
);
|
|
3597
3624
|
const replaceStr = command.args["replace"] || command.args["I"] || null;
|
|
@@ -3704,7 +3731,7 @@ var CliShCommandProcessor = class {
|
|
|
3704
3731
|
];
|
|
3705
3732
|
}
|
|
3706
3733
|
async processCommand(command, context) {
|
|
3707
|
-
const fs = context.services.
|
|
3734
|
+
const fs = context.services.getRequired(
|
|
3708
3735
|
IFileSystemService_TOKEN
|
|
3709
3736
|
);
|
|
3710
3737
|
let filePath = (command.value || "").trim();
|
|
@@ -3830,14 +3857,14 @@ function substituteVariables(input, variables) {
|
|
|
3830
3857
|
);
|
|
3831
3858
|
return result;
|
|
3832
3859
|
}
|
|
3833
|
-
|
|
3834
|
-
// src/lib/services/indexed-db-file-system.service.ts
|
|
3835
3860
|
var DB_NAME = "qodalis-cli-filesystem";
|
|
3836
3861
|
var STORE_NAME = "filesystem";
|
|
3837
3862
|
var ROOT_KEY = "root";
|
|
3838
3863
|
var CWD_KEY = "cwd";
|
|
3839
3864
|
var HOME_KEY = "home";
|
|
3840
3865
|
var DEFAULT_HOME = "/";
|
|
3866
|
+
var SYSTEM_OWNERSHIP = { uid: "root", gid: "admin" };
|
|
3867
|
+
var ANONYMOUS_OWNERSHIP = { uid: "nobody", gid: "nogroup" };
|
|
3841
3868
|
function createSeedFileSystem() {
|
|
3842
3869
|
const now = Date.now();
|
|
3843
3870
|
return {
|
|
@@ -3885,6 +3912,88 @@ var IndexedDbFileSystemService = class {
|
|
|
3885
3912
|
this.homePath = DEFAULT_HOME;
|
|
3886
3913
|
this.currentUid = null;
|
|
3887
3914
|
this.currentGroups = [];
|
|
3915
|
+
this.systemDepth = 0;
|
|
3916
|
+
}
|
|
3917
|
+
// --- Access control ---
|
|
3918
|
+
setAccessPolicy(policy) {
|
|
3919
|
+
this.accessPolicy = policy;
|
|
3920
|
+
}
|
|
3921
|
+
runAsSystem(fn) {
|
|
3922
|
+
this.systemDepth++;
|
|
3923
|
+
try {
|
|
3924
|
+
return fn();
|
|
3925
|
+
} finally {
|
|
3926
|
+
this.systemDepth--;
|
|
3927
|
+
}
|
|
3928
|
+
}
|
|
3929
|
+
reassignOwner(fromUid, toUid) {
|
|
3930
|
+
const from = fromUid.toLowerCase();
|
|
3931
|
+
if (!from || !toUid) return 0;
|
|
3932
|
+
let changed = 0;
|
|
3933
|
+
const visit = (node) => {
|
|
3934
|
+
if (node.ownership && node.ownership.uid.toLowerCase() === from) {
|
|
3935
|
+
node.ownership = { ...node.ownership, uid: toUid };
|
|
3936
|
+
changed++;
|
|
3937
|
+
}
|
|
3938
|
+
node.children?.forEach(visit);
|
|
3939
|
+
};
|
|
3940
|
+
visit(this.root);
|
|
3941
|
+
return changed;
|
|
3942
|
+
}
|
|
3943
|
+
canTraverse(path) {
|
|
3944
|
+
try {
|
|
3945
|
+
this.assertTraverse(this.resolvePath(path), "stat", path);
|
|
3946
|
+
return true;
|
|
3947
|
+
} catch {
|
|
3948
|
+
return false;
|
|
3949
|
+
}
|
|
3950
|
+
}
|
|
3951
|
+
get enforcing() {
|
|
3952
|
+
return !!this.accessPolicy && this.systemDepth === 0;
|
|
3953
|
+
}
|
|
3954
|
+
deny(op, path, reason = "Permission denied") {
|
|
3955
|
+
throw new CliAccessDeniedError(`${op}: ${path}: ${reason}`);
|
|
3956
|
+
}
|
|
3957
|
+
/** `x` on every existing directory on the way to `resolved` (excluding the target). */
|
|
3958
|
+
assertTraverse(resolved, op, display) {
|
|
3959
|
+
if (!this.enforcing) return;
|
|
3960
|
+
const parts = resolved.split("/").filter(Boolean);
|
|
3961
|
+
let current = this.root;
|
|
3962
|
+
for (let i = 0; i < parts.length; i++) {
|
|
3963
|
+
if (!current || current.type !== "directory") return;
|
|
3964
|
+
if (!this.accessPolicy.canAccess(current, "execute")) this.deny(op, display);
|
|
3965
|
+
current = current.children?.find((c) => c.name === parts[i]);
|
|
3966
|
+
}
|
|
3967
|
+
}
|
|
3968
|
+
assertAccess(node, action, op, display) {
|
|
3969
|
+
if (this.enforcing && !this.accessPolicy.canAccess(node, action)) this.deny(op, display);
|
|
3970
|
+
}
|
|
3971
|
+
/** Recursive delete: every directory inside must allow removing its entries (`w` + `x`, readable). */
|
|
3972
|
+
assertRemovableTree(dir, dirPath, display) {
|
|
3973
|
+
if (!this.enforcing) return;
|
|
3974
|
+
this.assertAccess(dir, "read", "rm", display);
|
|
3975
|
+
this.assertAccess(dir, "execute", "rm", display);
|
|
3976
|
+
if ((dir.children?.length ?? 0) > 0) this.assertAccess(dir, "write", "rm", display);
|
|
3977
|
+
for (const child of dir.children ?? []) {
|
|
3978
|
+
if (child.type === "directory") this.assertRemovableTree(child, `${dirPath}/${child.name}`, display);
|
|
3979
|
+
}
|
|
3980
|
+
}
|
|
3981
|
+
/** Copying reads everything it copies: `r` on every file, `r` + `x` on every directory. */
|
|
3982
|
+
assertReadableTree(node, display) {
|
|
3983
|
+
if (!this.enforcing) return;
|
|
3984
|
+
this.assertAccess(node, "read", "cp", display);
|
|
3985
|
+
if (node.type !== "directory") return;
|
|
3986
|
+
this.assertAccess(node, "execute", "cp", display);
|
|
3987
|
+
for (const child of node.children ?? []) {
|
|
3988
|
+
this.assertReadableTree(child, `${display.replace(/\/+$/, "")}/${child.name}`);
|
|
3989
|
+
}
|
|
3990
|
+
}
|
|
3991
|
+
/** Creating/removing entries needs `w` and `x` on the containing directory. */
|
|
3992
|
+
assertModifyDir(dir, dirPath, op, display) {
|
|
3993
|
+
if (!this.enforcing) return;
|
|
3994
|
+
this.assertTraverse(dirPath, op, display);
|
|
3995
|
+
this.assertAccess(dir, "execute", op, display);
|
|
3996
|
+
this.assertAccess(dir, "write", op, display);
|
|
3888
3997
|
}
|
|
3889
3998
|
// --- User context ---
|
|
3890
3999
|
setCurrentUser(uid, groups) {
|
|
@@ -3892,7 +4001,9 @@ var IndexedDbFileSystemService = class {
|
|
|
3892
4001
|
this.currentGroups = groups;
|
|
3893
4002
|
}
|
|
3894
4003
|
getDefaultOwnership() {
|
|
3895
|
-
if (!this.currentUid)
|
|
4004
|
+
if (!this.currentUid) {
|
|
4005
|
+
return this.accessPolicy ? { ...ANONYMOUS_OWNERSHIP } : void 0;
|
|
4006
|
+
}
|
|
3896
4007
|
return {
|
|
3897
4008
|
uid: this.currentUid,
|
|
3898
4009
|
gid: this.currentGroups[0] || "users"
|
|
@@ -3911,6 +4022,8 @@ var IndexedDbFileSystemService = class {
|
|
|
3911
4022
|
if (node.type !== "directory") {
|
|
3912
4023
|
throw new Error(`cd: ${path}: Not a directory`);
|
|
3913
4024
|
}
|
|
4025
|
+
this.assertTraverse(resolved, "cd", path);
|
|
4026
|
+
this.assertAccess(node, "execute", "cd", path);
|
|
3914
4027
|
this.cwd = resolved;
|
|
3915
4028
|
}
|
|
3916
4029
|
getHomePath() {
|
|
@@ -3967,6 +4080,8 @@ var IndexedDbFileSystemService = class {
|
|
|
3967
4080
|
if (node.type !== "directory") {
|
|
3968
4081
|
throw new Error(`ls: ${path}: Not a directory`);
|
|
3969
4082
|
}
|
|
4083
|
+
this.assertTraverse(this.resolvePath(path), "ls", path);
|
|
4084
|
+
this.assertAccess(node, "read", "ls", path);
|
|
3970
4085
|
return node.children || [];
|
|
3971
4086
|
}
|
|
3972
4087
|
readFile(path) {
|
|
@@ -3977,6 +4092,8 @@ var IndexedDbFileSystemService = class {
|
|
|
3977
4092
|
if (node.type === "directory") {
|
|
3978
4093
|
throw new Error(`cat: ${path}: Is a directory`);
|
|
3979
4094
|
}
|
|
4095
|
+
this.assertTraverse(this.resolvePath(path), "cat", path);
|
|
4096
|
+
this.assertAccess(node, "read", "cat", path);
|
|
3980
4097
|
return node.content ?? "";
|
|
3981
4098
|
}
|
|
3982
4099
|
exists(path) {
|
|
@@ -4001,6 +4118,10 @@ var IndexedDbFileSystemService = class {
|
|
|
4001
4118
|
}
|
|
4002
4119
|
let child = current.children.find((c) => c.name === part);
|
|
4003
4120
|
if (!child) {
|
|
4121
|
+
if (this.enforcing) {
|
|
4122
|
+
this.assertAccess(current, "execute", "mkdir", path);
|
|
4123
|
+
this.assertAccess(current, "write", "mkdir", path);
|
|
4124
|
+
}
|
|
4004
4125
|
const now = Date.now();
|
|
4005
4126
|
child = {
|
|
4006
4127
|
name: part,
|
|
@@ -4016,6 +4137,8 @@ var IndexedDbFileSystemService = class {
|
|
|
4016
4137
|
current.modifiedAt = now;
|
|
4017
4138
|
} else if (child.type !== "directory") {
|
|
4018
4139
|
throw new Error(`mkdir: ${part}: Not a directory`);
|
|
4140
|
+
} else {
|
|
4141
|
+
this.assertAccess(child, "execute", "mkdir", path);
|
|
4019
4142
|
}
|
|
4020
4143
|
current = child;
|
|
4021
4144
|
}
|
|
@@ -4034,6 +4157,7 @@ var IndexedDbFileSystemService = class {
|
|
|
4034
4157
|
if (parent.children?.find((c) => c.name === dirName)) {
|
|
4035
4158
|
throw new Error(`mkdir: ${path}: File exists`);
|
|
4036
4159
|
}
|
|
4160
|
+
this.assertModifyDir(parent, parentPath, "mkdir", path);
|
|
4037
4161
|
const now = Date.now();
|
|
4038
4162
|
if (!parent.children) {
|
|
4039
4163
|
parent.children = [];
|
|
@@ -4068,6 +4192,12 @@ var IndexedDbFileSystemService = class {
|
|
|
4068
4192
|
}
|
|
4069
4193
|
const existing = parent.children?.find((c) => c.name === fileName);
|
|
4070
4194
|
const now = Date.now();
|
|
4195
|
+
if (existing) {
|
|
4196
|
+
this.assertTraverse(resolved, "touch", path);
|
|
4197
|
+
this.assertAccess(existing, "write", "touch", path);
|
|
4198
|
+
} else {
|
|
4199
|
+
this.assertModifyDir(parent, parentPath, "touch", path);
|
|
4200
|
+
}
|
|
4071
4201
|
if (existing) {
|
|
4072
4202
|
existing.modifiedAt = now;
|
|
4073
4203
|
} else {
|
|
@@ -4094,6 +4224,8 @@ var IndexedDbFileSystemService = class {
|
|
|
4094
4224
|
if (node.type === "directory") {
|
|
4095
4225
|
throw new Error(`write: ${path}: Is a directory`);
|
|
4096
4226
|
}
|
|
4227
|
+
this.assertTraverse(resolved, "write", path);
|
|
4228
|
+
this.assertAccess(node, "write", "write", path);
|
|
4097
4229
|
const now = Date.now();
|
|
4098
4230
|
node.content = append ? (node.content ?? "") + content : content;
|
|
4099
4231
|
node.size = new Blob([node.content]).size;
|
|
@@ -4122,6 +4254,8 @@ var IndexedDbFileSystemService = class {
|
|
|
4122
4254
|
if (target.type === "directory" && !recursive) {
|
|
4123
4255
|
throw new Error(`rm: ${path}: Is a directory`);
|
|
4124
4256
|
}
|
|
4257
|
+
this.assertModifyDir(parent, parentPath, "rm", path);
|
|
4258
|
+
if (target.type === "directory") this.assertRemovableTree(target, resolved, path);
|
|
4125
4259
|
parent.children.splice(index, 1);
|
|
4126
4260
|
parent.modifiedAt = Date.now();
|
|
4127
4261
|
}
|
|
@@ -4136,10 +4270,13 @@ var IndexedDbFileSystemService = class {
|
|
|
4136
4270
|
`cp: -r not specified; omitting directory '${src}'`
|
|
4137
4271
|
);
|
|
4138
4272
|
}
|
|
4273
|
+
this.assertTraverse(srcResolved, "cp", src);
|
|
4274
|
+
this.assertReadableTree(srcNode, src);
|
|
4139
4275
|
const destResolved = this.resolvePath(dest);
|
|
4140
4276
|
const destNode = this.getNode(destResolved);
|
|
4141
4277
|
if (destNode && destNode.type === "directory") {
|
|
4142
|
-
|
|
4278
|
+
this.assertModifyDir(destNode, destResolved, "cp", dest);
|
|
4279
|
+
const clone = this.ownedByCurrentUser(this.cloneNode(srcNode));
|
|
4143
4280
|
if (!destNode.children) {
|
|
4144
4281
|
destNode.children = [];
|
|
4145
4282
|
}
|
|
@@ -4159,7 +4296,8 @@ var IndexedDbFileSystemService = class {
|
|
|
4159
4296
|
if (!parent || parent.type !== "directory") {
|
|
4160
4297
|
throw new Error(`cp: ${parentPath}: No such file or directory`);
|
|
4161
4298
|
}
|
|
4162
|
-
|
|
4299
|
+
this.assertModifyDir(parent, parentPath, "cp", dest);
|
|
4300
|
+
const clone = this.ownedByCurrentUser(this.cloneNode(srcNode));
|
|
4163
4301
|
clone.name = newName;
|
|
4164
4302
|
if (!parent.children) {
|
|
4165
4303
|
parent.children = [];
|
|
@@ -4191,10 +4329,12 @@ var IndexedDbFileSystemService = class {
|
|
|
4191
4329
|
if (!srcParent || !srcParent.children) {
|
|
4192
4330
|
throw new Error(`mv: ${src}: No such file or directory`);
|
|
4193
4331
|
}
|
|
4332
|
+
this.assertModifyDir(srcParent, srcParentPath, "mv", src);
|
|
4194
4333
|
const srcIndex = srcParent.children.findIndex(
|
|
4195
4334
|
(c) => c.name === srcNode.name
|
|
4196
4335
|
);
|
|
4197
4336
|
if (destNode && destNode.type === "directory") {
|
|
4337
|
+
this.assertModifyDir(destNode, destResolved, "mv", dest);
|
|
4198
4338
|
if (!destNode.children) {
|
|
4199
4339
|
destNode.children = [];
|
|
4200
4340
|
}
|
|
@@ -4217,6 +4357,7 @@ var IndexedDbFileSystemService = class {
|
|
|
4217
4357
|
`mv: ${destParentPath}: No such file or directory`
|
|
4218
4358
|
);
|
|
4219
4359
|
}
|
|
4360
|
+
this.assertModifyDir(destParent, destParentPath, "mv", dest);
|
|
4220
4361
|
srcParent.children.splice(srcIndex, 1);
|
|
4221
4362
|
srcNode.name = newName;
|
|
4222
4363
|
if (!destParent.children) {
|
|
@@ -4240,6 +4381,9 @@ var IndexedDbFileSystemService = class {
|
|
|
4240
4381
|
if (!node) {
|
|
4241
4382
|
throw new Error(`chmod: ${path}: No such file or directory`);
|
|
4242
4383
|
}
|
|
4384
|
+
if (this.enforcing && !this.accessPolicy.canChangeOwnership(node)) {
|
|
4385
|
+
this.deny("chmod", path, "Operation not permitted");
|
|
4386
|
+
}
|
|
4243
4387
|
node.permissions = permissions;
|
|
4244
4388
|
}
|
|
4245
4389
|
chown(path, ownership) {
|
|
@@ -4248,6 +4392,9 @@ var IndexedDbFileSystemService = class {
|
|
|
4248
4392
|
if (!node) {
|
|
4249
4393
|
throw new Error(`chown: ${path}: No such file or directory`);
|
|
4250
4394
|
}
|
|
4395
|
+
if (this.enforcing && !this.accessPolicy.canChangeOwnership(node, ownership)) {
|
|
4396
|
+
this.deny("chown", path, "Operation not permitted");
|
|
4397
|
+
}
|
|
4251
4398
|
node.ownership = ownership;
|
|
4252
4399
|
}
|
|
4253
4400
|
// --- Persistence ---
|
|
@@ -4289,6 +4436,18 @@ var IndexedDbFileSystemService = class {
|
|
|
4289
4436
|
}
|
|
4290
4437
|
}
|
|
4291
4438
|
// --- Private helpers ---
|
|
4439
|
+
/** A copy belongs to whoever made it (like `cp` without `-p`) */
|
|
4440
|
+
ownedByCurrentUser(node) {
|
|
4441
|
+
const owner = this.getDefaultOwnership();
|
|
4442
|
+
if (owner) {
|
|
4443
|
+
const apply = (n) => {
|
|
4444
|
+
n.ownership = { ...owner };
|
|
4445
|
+
n.children?.forEach(apply);
|
|
4446
|
+
};
|
|
4447
|
+
apply(node);
|
|
4448
|
+
}
|
|
4449
|
+
return node;
|
|
4450
|
+
}
|
|
4292
4451
|
cloneNode(node) {
|
|
4293
4452
|
const now = Date.now();
|
|
4294
4453
|
const clone = {
|
|
@@ -4330,8 +4489,6 @@ var IndexedDbFileSystemService = class {
|
|
|
4330
4489
|
});
|
|
4331
4490
|
}
|
|
4332
4491
|
};
|
|
4333
|
-
|
|
4334
|
-
// src/lib/services/server-file-system.service.ts
|
|
4335
4492
|
var DEFAULT_HOME2 = "/home/user";
|
|
4336
4493
|
function createSeedFileSystem2() {
|
|
4337
4494
|
const now = Date.now();
|
|
@@ -4381,6 +4538,7 @@ var ServerFileSystemService = class {
|
|
|
4381
4538
|
this.currentUid = null;
|
|
4382
4539
|
this.currentGroups = [];
|
|
4383
4540
|
this.baseUrl = options.baseUrl.replace(/\/+$/, "");
|
|
4541
|
+
this.headersProvider = options.headers;
|
|
4384
4542
|
}
|
|
4385
4543
|
// --- User context ---
|
|
4386
4544
|
setCurrentUser(uid, groups) {
|
|
@@ -4788,7 +4946,14 @@ var ServerFileSystemService = class {
|
|
|
4788
4946
|
// --- Private: server communication ---
|
|
4789
4947
|
async serverFetch(endpoint, options) {
|
|
4790
4948
|
const url = `${this.baseUrl}/api/qcli/fs${endpoint}`;
|
|
4791
|
-
const
|
|
4949
|
+
const mergedHeaders = {
|
|
4950
|
+
...resolveHeaders(this.headersProvider),
|
|
4951
|
+
...options?.headers ?? {}
|
|
4952
|
+
};
|
|
4953
|
+
const response = await fetch(url, {
|
|
4954
|
+
...options,
|
|
4955
|
+
headers: mergedHeaders
|
|
4956
|
+
});
|
|
4792
4957
|
if (!response.ok) {
|
|
4793
4958
|
const body = await response.text();
|
|
4794
4959
|
throw new Error(
|
|
@@ -4957,6 +5122,115 @@ var VirtualFsFileTransferService = class {
|
|
|
4957
5122
|
return this._browserService.uploadFromBrowser(accept);
|
|
4958
5123
|
}
|
|
4959
5124
|
};
|
|
5125
|
+
var CliFilesPermissions = {
|
|
5126
|
+
/** Bypass all file permission checks */
|
|
5127
|
+
Admin: "files:admin",
|
|
5128
|
+
/** chmod/chown files you do not own */
|
|
5129
|
+
Chown: "files:chown"
|
|
5130
|
+
};
|
|
5131
|
+
var HOME_DIR_PERMISSIONS = "rwxr-x---";
|
|
5132
|
+
function authorization(context) {
|
|
5133
|
+
try {
|
|
5134
|
+
return context.services.get(ICliAuthorizationService_TOKEN);
|
|
5135
|
+
} catch {
|
|
5136
|
+
return void 0;
|
|
5137
|
+
}
|
|
5138
|
+
}
|
|
5139
|
+
function createFileAccessPolicy(context) {
|
|
5140
|
+
return {
|
|
5141
|
+
// Nodes without an owner (system seed, legacy data) belong to root:admin
|
|
5142
|
+
canAccess: (node, action) => cliCanAccess(
|
|
5143
|
+
context,
|
|
5144
|
+
node.ownership ? node : { ...node, ownership: SYSTEM_OWNERSHIP },
|
|
5145
|
+
action,
|
|
5146
|
+
[CliFilesPermissions.Admin]
|
|
5147
|
+
),
|
|
5148
|
+
canChangeOwnership: (node, newOwnership) => {
|
|
5149
|
+
const auth = authorization(context);
|
|
5150
|
+
if (!auth) return true;
|
|
5151
|
+
if (auth.can(CliFilesPermissions.Admin) || auth.can(CliFilesPermissions.Chown)) return true;
|
|
5152
|
+
const principal = auth.getPrincipal();
|
|
5153
|
+
if (!principal) return false;
|
|
5154
|
+
const owns = !!node.ownership && (node.ownership.uid === principal.name || node.ownership.uid === principal.id);
|
|
5155
|
+
const keepsOwner = !newOwnership || newOwnership.uid === node.ownership?.uid || newOwnership.uid === principal.name;
|
|
5156
|
+
return owns && keepsOwner;
|
|
5157
|
+
}
|
|
5158
|
+
};
|
|
5159
|
+
}
|
|
5160
|
+
function followUserSession(context, fs) {
|
|
5161
|
+
let sessions;
|
|
5162
|
+
try {
|
|
5163
|
+
sessions = context.services.get(ICliUserSessionService_TOKEN);
|
|
5164
|
+
} catch {
|
|
5165
|
+
sessions = void 0;
|
|
5166
|
+
}
|
|
5167
|
+
if (!sessions) return void 0;
|
|
5168
|
+
let previousUser = null;
|
|
5169
|
+
return sessions.getUserSession().subscribe((session) => {
|
|
5170
|
+
if (!session?.user) {
|
|
5171
|
+
fs.setCurrentUser("", []);
|
|
5172
|
+
if (previousUser !== null || !canEnter(fs, fs.getCurrentDirectory())) {
|
|
5173
|
+
try {
|
|
5174
|
+
fs.setCurrentDirectory("/");
|
|
5175
|
+
void fs.persist();
|
|
5176
|
+
} catch {
|
|
5177
|
+
}
|
|
5178
|
+
}
|
|
5179
|
+
previousUser = null;
|
|
5180
|
+
return;
|
|
5181
|
+
}
|
|
5182
|
+
const user = session.user;
|
|
5183
|
+
fs.setCurrentUser(user.name, user.groups ?? []);
|
|
5184
|
+
if (user.homeDir) {
|
|
5185
|
+
const home = user.homeDir;
|
|
5186
|
+
const system = (fn) => fs.runAsSystem ? fs.runAsSystem(fn) : fn();
|
|
5187
|
+
if (!fs.exists(home)) {
|
|
5188
|
+
system(() => {
|
|
5189
|
+
fs.createDirectory(home, true);
|
|
5190
|
+
if (home !== "/") {
|
|
5191
|
+
fs.chown(home, { uid: user.name, gid: user.groups?.[0] ?? "users" });
|
|
5192
|
+
fs.chmod(home, HOME_DIR_PERMISSIONS);
|
|
5193
|
+
}
|
|
5194
|
+
});
|
|
5195
|
+
void fs.persist();
|
|
5196
|
+
}
|
|
5197
|
+
fs.setHomePath(home);
|
|
5198
|
+
if (previousUser !== user.id) {
|
|
5199
|
+
try {
|
|
5200
|
+
fs.setCurrentDirectory(home);
|
|
5201
|
+
} catch {
|
|
5202
|
+
}
|
|
5203
|
+
}
|
|
5204
|
+
}
|
|
5205
|
+
previousUser = user.id;
|
|
5206
|
+
});
|
|
5207
|
+
}
|
|
5208
|
+
function canEnter(fs, path) {
|
|
5209
|
+
try {
|
|
5210
|
+
fs.setCurrentDirectory(path);
|
|
5211
|
+
return true;
|
|
5212
|
+
} catch {
|
|
5213
|
+
return false;
|
|
5214
|
+
}
|
|
5215
|
+
}
|
|
5216
|
+
function followUserAccounts(context, fs) {
|
|
5217
|
+
let events;
|
|
5218
|
+
try {
|
|
5219
|
+
events = context.services.get(ICliUserEventService_TOKEN);
|
|
5220
|
+
} catch {
|
|
5221
|
+
events = void 0;
|
|
5222
|
+
}
|
|
5223
|
+
if (!events || !fs.reassignOwner) return void 0;
|
|
5224
|
+
return events.events$.subscribe((event) => {
|
|
5225
|
+
let changed = 0;
|
|
5226
|
+
if (event.type === "user_updated" && event.previousName && event.previousName !== event.user?.name) {
|
|
5227
|
+
changed = fs.reassignOwner(event.previousName, event.user.name);
|
|
5228
|
+
} else if (event.type === "user_deleted" && event.user?.name) {
|
|
5229
|
+
changed = fs.reassignOwner(event.user.name, SYSTEM_OWNERSHIP.uid);
|
|
5230
|
+
}
|
|
5231
|
+
if (changed > 0) void fs.persist().catch(() => void 0);
|
|
5232
|
+
});
|
|
5233
|
+
}
|
|
4960
5234
|
|
|
4961
5235
|
// src/lib/completion/file-path-completion-provider.ts
|
|
4962
5236
|
var FILE_COMMANDS = /* @__PURE__ */ new Set([
|
|
@@ -5057,10 +5331,10 @@ var CliUploadCommandProcessor = class {
|
|
|
5057
5331
|
];
|
|
5058
5332
|
}
|
|
5059
5333
|
async processCommand(command, context) {
|
|
5060
|
-
const fs = context.services.
|
|
5334
|
+
const fs = context.services.getRequired(
|
|
5061
5335
|
IFileSystemService_TOKEN
|
|
5062
5336
|
);
|
|
5063
|
-
const fileService = context.services.
|
|
5337
|
+
const fileService = context.services.getRequired(
|
|
5064
5338
|
ICliFileTransferService_TOKEN
|
|
5065
5339
|
);
|
|
5066
5340
|
if (!fileService) {
|
|
@@ -5070,7 +5344,7 @@ var CliUploadCommandProcessor = class {
|
|
|
5070
5344
|
const accept = command.args?.["accept"];
|
|
5071
5345
|
const destPath = command.value?.trim() || void 0;
|
|
5072
5346
|
context.spinner?.show("Waiting for file selection...");
|
|
5073
|
-
context.
|
|
5347
|
+
context.notifier.info("Waiting for file selection");
|
|
5074
5348
|
const picked = await fileService.uploadFromBrowser(accept);
|
|
5075
5349
|
if (!picked) {
|
|
5076
5350
|
context.spinner?.hide();
|
|
@@ -5083,7 +5357,7 @@ var CliUploadCommandProcessor = class {
|
|
|
5083
5357
|
filename.startsWith("/") ? filename : cwd + "/" + filename
|
|
5084
5358
|
);
|
|
5085
5359
|
context.spinner?.show(`Saving "${picked.name}" (${picked.content.length} bytes)...`);
|
|
5086
|
-
context.
|
|
5360
|
+
context.notifier.info(`Saving ${picked.name}`);
|
|
5087
5361
|
try {
|
|
5088
5362
|
fs.writeFile(resolved, picked.content);
|
|
5089
5363
|
await fs.persist();
|
|
@@ -5151,6 +5425,10 @@ var filesModule = {
|
|
|
5151
5425
|
new CliShCommandProcessor(),
|
|
5152
5426
|
new CliUploadCommandProcessor()
|
|
5153
5427
|
],
|
|
5428
|
+
permissions: [
|
|
5429
|
+
{ name: CliFilesPermissions.Admin, description: "Bypass file permission checks" },
|
|
5430
|
+
{ name: CliFilesPermissions.Chown, description: "chmod/chown files owned by others" }
|
|
5431
|
+
],
|
|
5154
5432
|
services: [
|
|
5155
5433
|
{
|
|
5156
5434
|
provide: IFileSystemService_TOKEN,
|
|
@@ -5182,7 +5460,7 @@ var filesModule = {
|
|
|
5182
5460
|
return { ...this, config };
|
|
5183
5461
|
},
|
|
5184
5462
|
async onInit(context) {
|
|
5185
|
-
const fs = context.services.
|
|
5463
|
+
const fs = context.services.getRequired(
|
|
5186
5464
|
IFileSystemService_TOKEN
|
|
5187
5465
|
);
|
|
5188
5466
|
await fs.initialize();
|
|
@@ -5193,7 +5471,7 @@ var filesModule = {
|
|
|
5193
5471
|
}
|
|
5194
5472
|
let dragDrop;
|
|
5195
5473
|
try {
|
|
5196
|
-
dragDrop = context.services.
|
|
5474
|
+
dragDrop = context.services.getRequired(ICliDragDropService_TOKEN);
|
|
5197
5475
|
} catch {
|
|
5198
5476
|
}
|
|
5199
5477
|
if (dragDrop) {
|
|
@@ -5222,13 +5500,25 @@ var filesModule = {
|
|
|
5222
5500
|
});
|
|
5223
5501
|
}
|
|
5224
5502
|
},
|
|
5503
|
+
async onAfterBoot(context) {
|
|
5504
|
+
const fs = context.services.getRequired(IFileSystemService_TOKEN);
|
|
5505
|
+
fs.setAccessPolicy?.(createFileAccessPolicy(context));
|
|
5506
|
+
this._sessionSubscription?.unsubscribe();
|
|
5507
|
+
this._sessionSubscription = followUserSession(context, fs);
|
|
5508
|
+
this._accountsSubscription?.unsubscribe();
|
|
5509
|
+
this._accountsSubscription = followUserAccounts(context, fs);
|
|
5510
|
+
},
|
|
5225
5511
|
async onDestroy(_context) {
|
|
5226
5512
|
const sub = this._dragDropSubscription;
|
|
5227
5513
|
sub?.unsubscribe();
|
|
5228
5514
|
this._dragDropSubscription = void 0;
|
|
5515
|
+
this._sessionSubscription?.unsubscribe();
|
|
5516
|
+
this._sessionSubscription = void 0;
|
|
5517
|
+
this._accountsSubscription?.unsubscribe();
|
|
5518
|
+
this._accountsSubscription = void 0;
|
|
5229
5519
|
}
|
|
5230
5520
|
};
|
|
5231
5521
|
|
|
5232
|
-
export { CliAwkCommandProcessor, CliBasenameCommandProcessor, CliCatCommandProcessor, CliCdCommandProcessor, CliChmodCommandProcessor, CliChownCommandProcessor, CliCpCommandProcessor, CliCutCommandProcessor, CliDiffCommandProcessor, CliDirnameCommandProcessor, CliDuCommandProcessor, CliEchoCommandProcessor, CliFindCommandProcessor, CliGrepCommandProcessor, CliHeadCommandProcessor, CliLnCommandProcessor, CliLsCommandProcessor, CliMkdirCommandProcessor, CliMvCommandProcessor, CliPasteCommandProcessor, CliPwdCommandProcessor, CliRmCommandProcessor, CliRmdirCommandProcessor, CliSedCommandProcessor, CliShCommandProcessor, CliSortCommandProcessor, CliStatCommandProcessor, CliTacCommandProcessor, CliTailCommandProcessor, CliTeeCommandProcessor, CliTouchCommandProcessor, CliTrCommandProcessor, CliTreeCommandProcessor, CliUniqCommandProcessor, CliWcCommandProcessor, CliXargsCommandProcessor, FilePathCompletionProvider, IFileSystemService_TOKEN, IndexedDbFileSystemService, ServerFileSystemService, VirtualFsFileTransferService, executeScript, filesModule };
|
|
5522
|
+
export { ANONYMOUS_OWNERSHIP, CliAwkCommandProcessor, CliBasenameCommandProcessor, CliCatCommandProcessor, CliCdCommandProcessor, CliChmodCommandProcessor, CliChownCommandProcessor, CliCpCommandProcessor, CliCutCommandProcessor, CliDiffCommandProcessor, CliDirnameCommandProcessor, CliDuCommandProcessor, CliEchoCommandProcessor, CliFilesPermissions, CliFindCommandProcessor, CliGrepCommandProcessor, CliHeadCommandProcessor, CliLnCommandProcessor, CliLsCommandProcessor, CliMkdirCommandProcessor, CliMvCommandProcessor, CliPasteCommandProcessor, CliPwdCommandProcessor, CliRmCommandProcessor, CliRmdirCommandProcessor, CliSedCommandProcessor, CliShCommandProcessor, CliSortCommandProcessor, CliStatCommandProcessor, CliTacCommandProcessor, CliTailCommandProcessor, CliTeeCommandProcessor, CliTouchCommandProcessor, CliTrCommandProcessor, CliTreeCommandProcessor, CliUniqCommandProcessor, CliWcCommandProcessor, CliXargsCommandProcessor, FilePathCompletionProvider, HOME_DIR_PERMISSIONS, IFileSystemService_TOKEN, IndexedDbFileSystemService, SYSTEM_OWNERSHIP, ServerFileSystemService, VirtualFsFileTransferService, createFileAccessPolicy, executeScript, filesModule, followUserAccounts, followUserSession };
|
|
5233
5523
|
//# sourceMappingURL=public-api.mjs.map
|
|
5234
5524
|
//# sourceMappingURL=public-api.mjs.map
|