@loxia-labs/loxia-autopilot-one 1.0.1 → 1.0.3
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/README.md +44 -54
- package/bin/cli.js +1 -115
- package/bin/loxia-terminal-v2.js +3 -0
- package/bin/loxia-terminal.js +3 -0
- package/bin/start-with-terminal.js +3 -0
- package/package.json +14 -15
- package/scripts/install-scanners.js +1 -235
- package/src/analyzers/CSSAnalyzer.js +1 -297
- package/src/analyzers/ConfigValidator.js +1 -690
- package/src/analyzers/ESLintAnalyzer.js +1 -320
- package/src/analyzers/JavaScriptAnalyzer.js +1 -261
- package/src/analyzers/PrettierFormatter.js +1 -247
- package/src/analyzers/PythonAnalyzer.js +1 -266
- package/src/analyzers/SecurityAnalyzer.js +1 -729
- package/src/analyzers/TypeScriptAnalyzer.js +1 -247
- package/src/analyzers/codeCloneDetector/analyzer.js +1 -344
- package/src/analyzers/codeCloneDetector/detector.js +1 -203
- package/src/analyzers/codeCloneDetector/index.js +1 -160
- package/src/analyzers/codeCloneDetector/parser.js +1 -199
- package/src/analyzers/codeCloneDetector/reporter.js +1 -148
- package/src/analyzers/codeCloneDetector/scanner.js +1 -59
- package/src/core/agentPool.js +1 -1474
- package/src/core/agentScheduler.js +1 -2147
- package/src/core/contextManager.js +1 -709
- package/src/core/messageProcessor.js +1 -732
- package/src/core/orchestrator.js +1 -548
- package/src/core/stateManager.js +1 -877
- package/src/index.js +1 -631
- package/src/interfaces/cli.js +1 -549
- package/src/interfaces/terminal/__tests__/smoke/advancedFeatures.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/agentControl.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/agents.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/components.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/connection.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/enhancements.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/imports.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/messages.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/tools.test.js +1 -0
- package/src/interfaces/terminal/api/apiClient.js +1 -0
- package/src/interfaces/terminal/api/messageRouter.js +1 -0
- package/src/interfaces/terminal/api/session.js +1 -0
- package/src/interfaces/terminal/api/websocket.js +1 -0
- package/src/interfaces/terminal/components/AgentCreator.js +1 -0
- package/src/interfaces/terminal/components/AgentEditor.js +1 -0
- package/src/interfaces/terminal/components/AgentSwitcher.js +1 -0
- package/src/interfaces/terminal/components/ErrorBoundary.js +1 -0
- package/src/interfaces/terminal/components/ErrorPanel.js +1 -0
- package/src/interfaces/terminal/components/Header.js +1 -0
- package/src/interfaces/terminal/components/HelpPanel.js +1 -0
- package/src/interfaces/terminal/components/InputBox.js +1 -0
- package/src/interfaces/terminal/components/Layout.js +1 -0
- package/src/interfaces/terminal/components/LoadingSpinner.js +1 -0
- package/src/interfaces/terminal/components/MessageList.js +1 -0
- package/src/interfaces/terminal/components/MultilineTextInput.js +1 -0
- package/src/interfaces/terminal/components/SearchPanel.js +1 -0
- package/src/interfaces/terminal/components/SettingsPanel.js +1 -0
- package/src/interfaces/terminal/components/StatusBar.js +1 -0
- package/src/interfaces/terminal/components/TextInput.js +1 -0
- package/src/interfaces/terminal/config/agentEditorConstants.js +1 -0
- package/src/interfaces/terminal/config/constants.js +1 -0
- package/src/interfaces/terminal/index.js +1 -0
- package/src/interfaces/terminal/state/useAgentControl.js +1 -0
- package/src/interfaces/terminal/state/useAgents.js +1 -0
- package/src/interfaces/terminal/state/useConnection.js +1 -0
- package/src/interfaces/terminal/state/useMessages.js +1 -0
- package/src/interfaces/terminal/state/useTools.js +1 -0
- package/src/interfaces/terminal/utils/debugLogger.js +1 -0
- package/src/interfaces/terminal/utils/settingsStorage.js +1 -0
- package/src/interfaces/terminal/utils/theme.js +1 -0
- package/src/interfaces/webServer.js +1 -2162
- package/src/modules/fileExplorer/controller.js +1 -280
- package/src/modules/fileExplorer/index.js +1 -37
- package/src/modules/fileExplorer/middleware.js +1 -92
- package/src/modules/fileExplorer/routes.js +1 -125
- package/src/modules/fileExplorer/types.js +1 -44
- package/src/services/aiService.js +1 -1232
- package/src/services/apiKeyManager.js +1 -164
- package/src/services/benchmarkService.js +1 -366
- package/src/services/budgetService.js +1 -539
- package/src/services/contextInjectionService.js +1 -247
- package/src/services/conversationCompactionService.js +1 -637
- package/src/services/errorHandler.js +1 -810
- package/src/services/fileAttachmentService.js +1 -544
- package/src/services/modelRouterService.js +1 -366
- package/src/services/modelsService.js +1 -322
- package/src/services/qualityInspector.js +1 -796
- package/src/services/tokenCountingService.js +1 -536
- package/src/tools/agentCommunicationTool.js +1 -1344
- package/src/tools/agentDelayTool.js +1 -485
- package/src/tools/asyncToolManager.js +1 -604
- package/src/tools/baseTool.js +1 -800
- package/src/tools/browserTool.js +1 -920
- package/src/tools/cloneDetectionTool.js +1 -621
- package/src/tools/dependencyResolverTool.js +1 -1215
- package/src/tools/fileContentReplaceTool.js +1 -875
- package/src/tools/fileSystemTool.js +1 -1107
- package/src/tools/fileTreeTool.js +1 -853
- package/src/tools/imageTool.js +1 -901
- package/src/tools/importAnalyzerTool.js +1 -1060
- package/src/tools/jobDoneTool.js +1 -248
- package/src/tools/seekTool.js +1 -956
- package/src/tools/staticAnalysisTool.js +1 -1778
- package/src/tools/taskManagerTool.js +1 -2873
- package/src/tools/terminalTool.js +1 -2304
- package/src/tools/webTool.js +1 -1430
- package/src/types/agent.js +1 -519
- package/src/types/contextReference.js +1 -972
- package/src/types/conversation.js +1 -730
- package/src/types/toolCommand.js +1 -747
- package/src/utilities/attachmentValidator.js +1 -292
- package/src/utilities/configManager.js +1 -582
- package/src/utilities/constants.js +1 -722
- package/src/utilities/directoryAccessManager.js +1 -535
- package/src/utilities/fileProcessor.js +1 -307
- package/src/utilities/logger.js +1 -436
- package/src/utilities/tagParser.js +1 -1246
- package/src/utilities/toolConstants.js +1 -317
- package/web-ui/build/index.html +2 -2
- package/web-ui/build/static/{index-Dy2bYbOa.css → index-CClD1090.css} +1 -1
- package/web-ui/build/static/{index-CjkkcnFA.js → index-lCBai6dX.js} +66 -67
|
@@ -1,280 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* File Explorer Controller
|
|
3
|
-
* Handles all file system operations for the file explorer module
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { promises as fs } from 'fs';
|
|
7
|
-
import path from 'path';
|
|
8
|
-
import os from 'os';
|
|
9
|
-
|
|
10
|
-
class FileExplorerController {
|
|
11
|
-
constructor(config = {}) {
|
|
12
|
-
this.config = {
|
|
13
|
-
showHidden: false,
|
|
14
|
-
allowedExtensions: [], // Empty array = all extensions allowed
|
|
15
|
-
maxDepth: 50, // Prevent infinite directory traversal
|
|
16
|
-
restrictedPaths: [], // Paths that cannot be accessed
|
|
17
|
-
...config
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Get file/directory stats safely
|
|
23
|
-
* @param {string} filePath - Path to check
|
|
24
|
-
* @returns {Promise<{stats: fs.Stats | null, error?: string}>}
|
|
25
|
-
*/
|
|
26
|
-
async getFileStats(filePath) {
|
|
27
|
-
try {
|
|
28
|
-
const stats = await fs.stat(filePath);
|
|
29
|
-
return { stats };
|
|
30
|
-
} catch (error) {
|
|
31
|
-
return {
|
|
32
|
-
stats: null,
|
|
33
|
-
error: error instanceof Error ? error.message : 'Unknown error'
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Check if path is safe and accessible
|
|
40
|
-
* @param {string} requestedPath - Path to validate
|
|
41
|
-
* @returns {boolean}
|
|
42
|
-
*/
|
|
43
|
-
isSafePath(requestedPath) {
|
|
44
|
-
try {
|
|
45
|
-
const resolvedPath = path.resolve(requestedPath);
|
|
46
|
-
|
|
47
|
-
// Check if path is in restricted list
|
|
48
|
-
if (this.config.restrictedPaths.some(restricted =>
|
|
49
|
-
resolvedPath.startsWith(path.resolve(restricted))
|
|
50
|
-
)) {
|
|
51
|
-
return false;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return true;
|
|
55
|
-
} catch (error) {
|
|
56
|
-
return false;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Filter items based on configuration
|
|
62
|
-
* @param {string} itemName - Item name to check
|
|
63
|
-
* @param {fs.Stats} stats - File stats
|
|
64
|
-
* @returns {boolean}
|
|
65
|
-
*/
|
|
66
|
-
shouldIncludeItem(itemName, stats) {
|
|
67
|
-
// Check hidden files
|
|
68
|
-
if (!this.config.showHidden && itemName.startsWith('.')) {
|
|
69
|
-
return false;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Check file extensions (only for files)
|
|
73
|
-
if (stats.isFile() && this.config.allowedExtensions.length > 0) {
|
|
74
|
-
const ext = path.extname(itemName).toLowerCase();
|
|
75
|
-
if (!this.config.allowedExtensions.includes(ext)) {
|
|
76
|
-
return false;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
return true;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Browse directory contents
|
|
85
|
-
* @param {string} requestedPath - Directory path to browse
|
|
86
|
-
* @param {Object} options - Browse options
|
|
87
|
-
* @returns {Promise<{success: boolean, data?: BrowseResponse, error?: string}>}
|
|
88
|
-
*/
|
|
89
|
-
async browseDirectory(requestedPath = process.cwd(), options = {}) {
|
|
90
|
-
try {
|
|
91
|
-
const normalizedPath = path.resolve(requestedPath);
|
|
92
|
-
|
|
93
|
-
// Security checks
|
|
94
|
-
if (!this.isSafePath(normalizedPath)) {
|
|
95
|
-
return {
|
|
96
|
-
success: false,
|
|
97
|
-
error: 'Access to this path is restricted'
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Check if path exists and is directory
|
|
102
|
-
const { stats, error } = await this.getFileStats(normalizedPath);
|
|
103
|
-
if (error || !stats) {
|
|
104
|
-
return {
|
|
105
|
-
success: false,
|
|
106
|
-
error: 'Path not found or inaccessible'
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
if (!stats.isDirectory()) {
|
|
111
|
-
return {
|
|
112
|
-
success: false,
|
|
113
|
-
error: 'Path is not a directory'
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// Read directory contents
|
|
118
|
-
const items = await fs.readdir(normalizedPath);
|
|
119
|
-
const fileItems = [];
|
|
120
|
-
|
|
121
|
-
// Process each item
|
|
122
|
-
for (const item of items) {
|
|
123
|
-
const itemPath = path.join(normalizedPath, item);
|
|
124
|
-
const { stats: itemStats } = await this.getFileStats(itemPath);
|
|
125
|
-
|
|
126
|
-
if (itemStats && this.shouldIncludeItem(item, itemStats)) {
|
|
127
|
-
const fileItem = {
|
|
128
|
-
name: item,
|
|
129
|
-
path: itemPath,
|
|
130
|
-
type: itemStats.isDirectory() ? 'directory' : 'file',
|
|
131
|
-
size: itemStats.isFile() ? itemStats.size : undefined,
|
|
132
|
-
lastModified: itemStats.mtime,
|
|
133
|
-
extension: itemStats.isFile() ? path.extname(item).toLowerCase() : undefined
|
|
134
|
-
};
|
|
135
|
-
fileItems.push(fileItem);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Sort: directories first, then files, both alphabetically
|
|
140
|
-
fileItems.sort((a, b) => {
|
|
141
|
-
if (a.type === b.type) {
|
|
142
|
-
return a.name.localeCompare(b.name);
|
|
143
|
-
}
|
|
144
|
-
return a.type === 'directory' ? -1 : 1;
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
// Calculate parent path
|
|
148
|
-
const parentPath = path.dirname(normalizedPath);
|
|
149
|
-
const hasParent = parentPath !== normalizedPath;
|
|
150
|
-
|
|
151
|
-
return {
|
|
152
|
-
success: true,
|
|
153
|
-
data: {
|
|
154
|
-
currentPath: normalizedPath,
|
|
155
|
-
parentPath: hasParent ? parentPath : null,
|
|
156
|
-
items: fileItems,
|
|
157
|
-
totalItems: fileItems.length,
|
|
158
|
-
directories: fileItems.filter(item => item.type === 'directory').length,
|
|
159
|
-
files: fileItems.filter(item => item.type === 'file').length
|
|
160
|
-
}
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
} catch (error) {
|
|
164
|
-
return {
|
|
165
|
-
success: false,
|
|
166
|
-
error: error instanceof Error ? error.message : 'Server error'
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Get file information
|
|
173
|
-
* @param {string} filePath - File path to get info for
|
|
174
|
-
* @returns {Promise<{success: boolean, data?: FileItem, error?: string}>}
|
|
175
|
-
*/
|
|
176
|
-
async getFileInfo(filePath) {
|
|
177
|
-
try {
|
|
178
|
-
if (!filePath || !this.isSafePath(filePath)) {
|
|
179
|
-
return {
|
|
180
|
-
success: false,
|
|
181
|
-
error: 'Invalid file path'
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
const { stats, error } = await this.getFileStats(filePath);
|
|
186
|
-
if (error || !stats) {
|
|
187
|
-
return {
|
|
188
|
-
success: false,
|
|
189
|
-
error: 'File not found'
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
const fileInfo = {
|
|
194
|
-
name: path.basename(filePath),
|
|
195
|
-
path: filePath,
|
|
196
|
-
type: stats.isDirectory() ? 'directory' : 'file',
|
|
197
|
-
size: stats.isFile() ? stats.size : undefined,
|
|
198
|
-
lastModified: stats.mtime,
|
|
199
|
-
extension: stats.isFile() ? path.extname(filePath).toLowerCase() : undefined
|
|
200
|
-
};
|
|
201
|
-
|
|
202
|
-
return {
|
|
203
|
-
success: true,
|
|
204
|
-
data: fileInfo
|
|
205
|
-
};
|
|
206
|
-
|
|
207
|
-
} catch (error) {
|
|
208
|
-
return {
|
|
209
|
-
success: false,
|
|
210
|
-
error: error instanceof Error ? error.message : 'Server error'
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* Get current working directory info
|
|
217
|
-
* @returns {{success: boolean, data: {cwd: string, platform: string, homedir: string}}}
|
|
218
|
-
*/
|
|
219
|
-
getCurrentWorkingDirectory() {
|
|
220
|
-
return {
|
|
221
|
-
success: true,
|
|
222
|
-
data: {
|
|
223
|
-
cwd: process.cwd(),
|
|
224
|
-
platform: process.platform,
|
|
225
|
-
homedir: os.homedir()
|
|
226
|
-
}
|
|
227
|
-
};
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
/**
|
|
231
|
-
* Create directory
|
|
232
|
-
* @param {string} dirPath - Directory path to create
|
|
233
|
-
* @param {Object} options - Creation options
|
|
234
|
-
* @returns {Promise<{success: boolean, data?: {path: string}, error?: string}>}
|
|
235
|
-
*/
|
|
236
|
-
async createDirectory(dirPath, options = {}) {
|
|
237
|
-
try {
|
|
238
|
-
if (!this.isSafePath(dirPath)) {
|
|
239
|
-
return {
|
|
240
|
-
success: false,
|
|
241
|
-
error: 'Invalid directory path'
|
|
242
|
-
};
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
await fs.mkdir(dirPath, { recursive: options.recursive || false });
|
|
246
|
-
|
|
247
|
-
return {
|
|
248
|
-
success: true,
|
|
249
|
-
data: {
|
|
250
|
-
path: dirPath,
|
|
251
|
-
relativePath: path.relative(process.cwd(), dirPath)
|
|
252
|
-
}
|
|
253
|
-
};
|
|
254
|
-
|
|
255
|
-
} catch (error) {
|
|
256
|
-
return {
|
|
257
|
-
success: false,
|
|
258
|
-
error: error instanceof Error ? error.message : 'Failed to create directory',
|
|
259
|
-
code: error.code
|
|
260
|
-
};
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
/**
|
|
265
|
-
* Health check
|
|
266
|
-
* @returns {{success: boolean, data: {status: string, timestamp: string}}}
|
|
267
|
-
*/
|
|
268
|
-
healthCheck() {
|
|
269
|
-
return {
|
|
270
|
-
success: true,
|
|
271
|
-
data: {
|
|
272
|
-
status: 'healthy',
|
|
273
|
-
timestamp: new Date().toISOString(),
|
|
274
|
-
module: 'fileExplorer'
|
|
275
|
-
}
|
|
276
|
-
};
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
export default FileExplorerController;
|
|
1
|
+
const a0_0x202af3=a0_0x2b10;(function(_0x2aa22f,_0x548ae0){const _0x1f7b07=a0_0x2b10,_0x4203d4=_0x2aa22f();while(!![]){try{const _0x41ea98=parseInt(_0x1f7b07(0x180))/0x1+-parseInt(_0x1f7b07(0x17c))/0x2+parseInt(_0x1f7b07(0x18a))/0x3*(parseInt(_0x1f7b07(0x1aa))/0x4)+parseInt(_0x1f7b07(0x17d))/0x5*(parseInt(_0x1f7b07(0x182))/0x6)+-parseInt(_0x1f7b07(0x1a6))/0x7+-parseInt(_0x1f7b07(0x1ad))/0x8*(-parseInt(_0x1f7b07(0x187))/0x9)+-parseInt(_0x1f7b07(0x1a1))/0xa*(parseInt(_0x1f7b07(0x192))/0xb);if(_0x41ea98===_0x548ae0)break;else _0x4203d4['push'](_0x4203d4['shift']());}catch(_0x49c421){_0x4203d4['push'](_0x4203d4['shift']());}}}(a0_0x416a,0xbf26f));import{promises as a0_0x4283c4}from'fs';import a0_0x260884 from'path';import a0_0x2984ed from'os';class FileExplorerController{constructor(_0x4177e8={}){this['config']={'showHidden':![],'allowedExtensions':[],'maxDepth':0x32,'restrictedPaths':[],..._0x4177e8};}async['getFileStats'](_0xc0e61){const _0x4d0342=a0_0x2b10;try{const _0x488eeb=await a0_0x4283c4[_0x4d0342(0x196)](_0xc0e61);return{'stats':_0x488eeb};}catch(_0x4b6479){return{'stats':null,'error':_0x4b6479 instanceof Error?_0x4b6479[_0x4d0342(0x1ab)]:_0x4d0342(0x1a9)};}}[a0_0x202af3(0x18f)](_0xf9e758){const _0x4e6d95=a0_0x202af3;try{const _0x1e82b6=a0_0x260884[_0x4e6d95(0x183)](_0xf9e758);if(this[_0x4e6d95(0x190)][_0x4e6d95(0x19b)][_0x4e6d95(0x1a4)](_0xf93967=>_0x1e82b6['startsWith'](a0_0x260884['resolve'](_0xf93967))))return![];return!![];}catch(_0x15775e){return![];}}['shouldIncludeItem'](_0x5b2ce4,_0x172997){const _0x49625d=a0_0x202af3;if(!this[_0x49625d(0x190)]['showHidden']&&_0x5b2ce4[_0x49625d(0x184)]('.'))return![];if(_0x172997['isFile']()&&this[_0x49625d(0x190)]['allowedExtensions']['length']>0x0){const _0x4c5b51=a0_0x260884['extname'](_0x5b2ce4)['toLowerCase']();if(!this['config'][_0x49625d(0x1a8)]['includes'](_0x4c5b51))return![];}return!![];}async[a0_0x202af3(0x18b)](_0x4a5155=process['cwd'](),_0xaf6fdd={}){const _0x3e6281=a0_0x202af3;try{const _0x1bf48f=a0_0x260884['resolve'](_0x4a5155);if(!this['isSafePath'](_0x1bf48f))return{'success':![],'error':_0x3e6281(0x1a3)};const {stats:_0x175beb,error:_0x2e796b}=await this['getFileStats'](_0x1bf48f);if(_0x2e796b||!_0x175beb)return{'success':![],'error':'Path\x20not\x20found\x20or\x20inaccessible'};if(!_0x175beb[_0x3e6281(0x189)]())return{'success':![],'error':'Path\x20is\x20not\x20a\x20directory'};const _0x56e853=await a0_0x4283c4[_0x3e6281(0x18d)](_0x1bf48f),_0x10c2ae=[];for(const _0x368360 of _0x56e853){const _0x2abfe2=a0_0x260884['join'](_0x1bf48f,_0x368360),{stats:_0x71d8c9}=await this['getFileStats'](_0x2abfe2);if(_0x71d8c9&&this['shouldIncludeItem'](_0x368360,_0x71d8c9)){const _0x437cee={'name':_0x368360,'path':_0x2abfe2,'type':_0x71d8c9['isDirectory']()?'directory':'file','size':_0x71d8c9['isFile']()?_0x71d8c9[_0x3e6281(0x185)]:undefined,'lastModified':_0x71d8c9[_0x3e6281(0x18e)],'extension':_0x71d8c9[_0x3e6281(0x197)]()?a0_0x260884[_0x3e6281(0x193)](_0x368360)['toLowerCase']():undefined};_0x10c2ae['push'](_0x437cee);}}_0x10c2ae[_0x3e6281(0x199)]((_0x383776,_0x5ee4fd)=>{const _0x3704e3=_0x3e6281;if(_0x383776['type']===_0x5ee4fd['type'])return _0x383776[_0x3704e3(0x18c)][_0x3704e3(0x194)](_0x5ee4fd['name']);return _0x383776['type']==='directory'?-0x1:0x1;});const _0x1ba001=a0_0x260884['dirname'](_0x1bf48f),_0x4965d0=_0x1ba001!==_0x1bf48f;return{'success':!![],'data':{'currentPath':_0x1bf48f,'parentPath':_0x4965d0?_0x1ba001:null,'items':_0x10c2ae,'totalItems':_0x10c2ae['length'],'directories':_0x10c2ae[_0x3e6281(0x17e)](_0x1b1351=>_0x1b1351['type']==='directory')['length'],'files':_0x10c2ae[_0x3e6281(0x17e)](_0x388b5e=>_0x388b5e[_0x3e6281(0x1a7)]==='file')[_0x3e6281(0x188)]}};}catch(_0x36a7eb){return{'success':![],'error':_0x36a7eb instanceof Error?_0x36a7eb[_0x3e6281(0x1ab)]:'Server\x20error'};}}async[a0_0x202af3(0x1ac)](_0x2091d7){const _0x87ab48=a0_0x202af3;try{if(!_0x2091d7||!this['isSafePath'](_0x2091d7))return{'success':![],'error':_0x87ab48(0x1a2)};const {stats:_0x5694b2,error:_0x584e67}=await this['getFileStats'](_0x2091d7);if(_0x584e67||!_0x5694b2)return{'success':![],'error':'File\x20not\x20found'};const _0x2f99d6={'name':a0_0x260884['basename'](_0x2091d7),'path':_0x2091d7,'type':_0x5694b2[_0x87ab48(0x189)]()?'directory':_0x87ab48(0x19d),'size':_0x5694b2['isFile']()?_0x5694b2[_0x87ab48(0x185)]:undefined,'lastModified':_0x5694b2['mtime'],'extension':_0x5694b2[_0x87ab48(0x197)]()?a0_0x260884['extname'](_0x2091d7)[_0x87ab48(0x19c)]():undefined};return{'success':!![],'data':_0x2f99d6};}catch(_0x387663){return{'success':![],'error':_0x387663 instanceof Error?_0x387663[_0x87ab48(0x1ab)]:_0x87ab48(0x19f)};}}[a0_0x202af3(0x195)](){const _0x281aee=a0_0x202af3;return{'success':!![],'data':{'cwd':process[_0x281aee(0x1a0)](),'platform':process[_0x281aee(0x186)],'homedir':a0_0x2984ed[_0x281aee(0x1a5)]()}};}async['createDirectory'](_0x5a2673,_0xbc5d38={}){const _0x28fb1e=a0_0x202af3;try{if(!this['isSafePath'](_0x5a2673))return{'success':![],'error':'Invalid\x20directory\x20path'};return await a0_0x4283c4['mkdir'](_0x5a2673,{'recursive':_0xbc5d38[_0x28fb1e(0x191)]||![]}),{'success':!![],'data':{'path':_0x5a2673,'relativePath':a0_0x260884[_0x28fb1e(0x17f)](process[_0x28fb1e(0x1a0)](),_0x5a2673)}};}catch(_0xa0414){return{'success':![],'error':_0xa0414 instanceof Error?_0xa0414[_0x28fb1e(0x1ab)]:'Failed\x20to\x20create\x20directory','code':_0xa0414[_0x28fb1e(0x181)]};}}['healthCheck'](){const _0x507abd=a0_0x202af3;return{'success':!![],'data':{'status':_0x507abd(0x198),'timestamp':new Date()[_0x507abd(0x19e)](),'module':_0x507abd(0x19a)}};}}function a0_0x416a(){const _0x146c40=['Dg9ju09tDhjPBMC','u2vYDMvYigvYCM9Y','y3DK','mtiXmZuWt0PPt1bQ','sw52ywXPzcbMAwXLihbHDgG','qwnJzxnZihrVihrOAxmGCgf0AcbPCYbYzxn0CMLJDgvK','C29Tzq','Ag9TzwrPCG','mJCXmtq5oxndzKDMta','DhLWzq','ywXSB3DLzev4DgvUC2LVBNm','vw5RBM93BIbLCNjVCG','mJHUA2fktxy','BwvZC2fNzq','z2v0rMLSzuLUzM8','ndaXnZK1mK1my01OwG','nJq0mty2EezLuKDc','mZvjv29Wtxy','zMLSDgvY','CMvSyxrPDMu','otiYmtaZCKzXAwLJ','y29Kzq','mZyXnJaYvu9Uyw9Z','CMvZB2X2zq','C3rHCNrZv2L0Aa','C2L6zq','CgXHDgzVCM0','mtH2DeDnAM8','BgvUz3rO','AxneAxjLy3rVCNK','mtm3ntG2ALD1ruLM','yNjVD3nLrgLYzwn0B3j5','BMfTzq','CMvHzgrPCG','BxrPBwu','AxntywzLugf0Aa','y29UzMLN','CMvJDxjZAxzL','mta2n1DgqLzSta','zxH0BMfTzq','Bg9JywXLq29TCgfYzq','z2v0q3vYCMvUDfDVCMTPBMDeAxjLy3rVCNK','C3rHDa','AxngAwXL','AgvHBhrOEq','C29YDa','zMLSzuv4CgXVCMvY','CMvZDhjPy3rLzfbHDgHZ','Dg9mB3DLCKnHC2u','zMLSzq'];a0_0x416a=function(){return _0x146c40;};return a0_0x416a();}function a0_0x2b10(_0x3d24c1,_0x42931f){_0x3d24c1=_0x3d24c1-0x17c;const _0x416aac=a0_0x416a();let _0x2b1098=_0x416aac[_0x3d24c1];if(a0_0x2b10['ULbKwl']===undefined){var _0x263bc4=function(_0x372328){const _0x105398='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x4283c4='',_0x260884='';for(let _0x2984ed=0x0,_0x4177e8,_0xc0e61,_0x488eeb=0x0;_0xc0e61=_0x372328['charAt'](_0x488eeb++);~_0xc0e61&&(_0x4177e8=_0x2984ed%0x4?_0x4177e8*0x40+_0xc0e61:_0xc0e61,_0x2984ed++%0x4)?_0x4283c4+=String['fromCharCode'](0xff&_0x4177e8>>(-0x2*_0x2984ed&0x6)):0x0){_0xc0e61=_0x105398['indexOf'](_0xc0e61);}for(let _0x4b6479=0x0,_0xf9e758=_0x4283c4['length'];_0x4b6479<_0xf9e758;_0x4b6479++){_0x260884+='%'+('00'+_0x4283c4['charCodeAt'](_0x4b6479)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x260884);};a0_0x2b10['lkaqNW']=_0x263bc4,a0_0x2b10['cVVsYA']={},a0_0x2b10['ULbKwl']=!![];}const _0x4e12a1=_0x416aac[0x0],_0x4dd754=_0x3d24c1+_0x4e12a1,_0x46c4fe=a0_0x2b10['cVVsYA'][_0x4dd754];return!_0x46c4fe?(_0x2b1098=a0_0x2b10['lkaqNW'](_0x2b1098),a0_0x2b10['cVVsYA'][_0x4dd754]=_0x2b1098):_0x2b1098=_0x46c4fe,_0x2b1098;}export default FileExplorerController;
|
|
@@ -1,37 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* File Explorer Module
|
|
3
|
-
* Main entry point for the file explorer functionality
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { createFileExplorerRouter, defaultConfig } from './routes.js';
|
|
7
|
-
import FileExplorerController from './controller.js';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Initialize file explorer module
|
|
11
|
-
* @param {Object} config - Configuration options
|
|
12
|
-
* @returns {Object} Module interface
|
|
13
|
-
*/
|
|
14
|
-
export function initFileExplorerModule(config = {}) {
|
|
15
|
-
const mergedConfig = { ...defaultConfig, ...config };
|
|
16
|
-
const router = createFileExplorerRouter(mergedConfig);
|
|
17
|
-
const controller = new FileExplorerController(mergedConfig);
|
|
18
|
-
|
|
19
|
-
return {
|
|
20
|
-
router,
|
|
21
|
-
controller,
|
|
22
|
-
config: mergedConfig
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Export individual components for advanced usage
|
|
27
|
-
export { default as FileExplorerController } from './controller.js';
|
|
28
|
-
export { createFileExplorerRouter, defaultConfig } from './routes.js';
|
|
29
|
-
export * from './middleware.js';
|
|
30
|
-
|
|
31
|
-
// Default export
|
|
32
|
-
export default {
|
|
33
|
-
init: initFileExplorerModule,
|
|
34
|
-
Controller: FileExplorerController,
|
|
35
|
-
createRouter: createFileExplorerRouter,
|
|
36
|
-
defaultConfig
|
|
37
|
-
};
|
|
1
|
+
(function(_0x52e076,_0x48e922){const _0x4720cd=a0_0x3381,_0x2da9c3=_0x52e076();while(!![]){try{const _0x205cef=-parseInt(_0x4720cd(0xf4))/0x1*(-parseInt(_0x4720cd(0xf5))/0x2)+parseInt(_0x4720cd(0xef))/0x3+parseInt(_0x4720cd(0xee))/0x4+-parseInt(_0x4720cd(0xed))/0x5*(parseInt(_0x4720cd(0xf3))/0x6)+parseInt(_0x4720cd(0xec))/0x7*(-parseInt(_0x4720cd(0xf2))/0x8)+parseInt(_0x4720cd(0xf0))/0x9+-parseInt(_0x4720cd(0xf1))/0xa;if(_0x205cef===_0x48e922)break;else _0x2da9c3['push'](_0x2da9c3['shift']());}catch(_0x2f3c76){_0x2da9c3['push'](_0x2da9c3['shift']());}}}(a0_0x1b7f,0xe39ab));import{createFileExplorerRouter,defaultConfig}from'./routes.js';import a0_0x4181ad from'./controller.js';export function initFileExplorerModule(_0x2fe44d={}){const _0x1400b8={...defaultConfig,..._0x2fe44d},_0x3088a0=createFileExplorerRouter(_0x1400b8),_0x3fc8a0=new a0_0x4181ad(_0x1400b8);return{'router':_0x3088a0,'controller':_0x3fc8a0,'config':_0x1400b8};}function a0_0x1b7f(){const _0x539793=['mtm5mtGXntbYqwfLvgm','mJK3mdGWz3PgCuni','mtiXmdK4BgjivMnQ','mJaYtKr2wvvX','mtm2ndjvELnis00','n2vjveTruq','ndq1uxHXvvzf','mZKYnZy0yujjB3fb','ntuYota5mgjjzgHTvq','nZu0ntK2ow5ACejTAG'];a0_0x1b7f=function(){return _0x539793;};return a0_0x1b7f();}function a0_0x3381(_0x58836a,_0x56cf08){_0x58836a=_0x58836a-0xec;const _0x1b7fdf=a0_0x1b7f();let _0x338172=_0x1b7fdf[_0x58836a];if(a0_0x3381['zVpsof']===undefined){var _0x26bf99=function(_0x254fee){const _0x33e8c9='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x4181ad='',_0x2fe44d='';for(let _0x1400b8=0x0,_0x3088a0,_0x3fc8a0,_0x5830d9=0x0;_0x3fc8a0=_0x254fee['charAt'](_0x5830d9++);~_0x3fc8a0&&(_0x3088a0=_0x1400b8%0x4?_0x3088a0*0x40+_0x3fc8a0:_0x3fc8a0,_0x1400b8++%0x4)?_0x4181ad+=String['fromCharCode'](0xff&_0x3088a0>>(-0x2*_0x1400b8&0x6)):0x0){_0x3fc8a0=_0x33e8c9['indexOf'](_0x3fc8a0);}for(let _0x52ec06=0x0,_0x5ed149=_0x4181ad['length'];_0x52ec06<_0x5ed149;_0x52ec06++){_0x2fe44d+='%'+('00'+_0x4181ad['charCodeAt'](_0x52ec06)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x2fe44d);};a0_0x3381['jcqoNF']=_0x26bf99,a0_0x3381['qYMFHL']={},a0_0x3381['zVpsof']=!![];}const _0x2c1c60=_0x1b7fdf[0x0],_0x296cfe=_0x58836a+_0x2c1c60,_0x290c96=a0_0x3381['qYMFHL'][_0x296cfe];return!_0x290c96?(_0x338172=a0_0x3381['jcqoNF'](_0x338172),a0_0x3381['qYMFHL'][_0x296cfe]=_0x338172):_0x338172=_0x290c96,_0x338172;}export{default as FileExplorerController}from'./controller.js';export{createFileExplorerRouter,defaultConfig}from'./routes.js';export*from'./middleware.js';export default{'init':initFileExplorerModule,'Controller':a0_0x4181ad,'createRouter':createFileExplorerRouter,'defaultConfig':defaultConfig};
|
|
@@ -1,92 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* File Explorer Middleware
|
|
3
|
-
* Contains middleware functions specific to file explorer operations
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Validate path parameter middleware
|
|
8
|
-
* @param {import('express').Request} req
|
|
9
|
-
* @param {import('express').Response} res
|
|
10
|
-
* @param {import('express').NextFunction} next
|
|
11
|
-
*/
|
|
12
|
-
export function validatePath(req, res, next) {
|
|
13
|
-
const { path } = req.query;
|
|
14
|
-
|
|
15
|
-
if (path && typeof path !== 'string') {
|
|
16
|
-
return res.status(400).json({
|
|
17
|
-
success: false,
|
|
18
|
-
error: 'Path parameter must be a string'
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
next();
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Rate limiting middleware for file operations
|
|
27
|
-
* Prevents excessive file system requests
|
|
28
|
-
* @param {number} maxRequests - Max requests per window
|
|
29
|
-
* @param {number} windowMs - Time window in milliseconds
|
|
30
|
-
*/
|
|
31
|
-
export function createRateLimit(maxRequests = 100, windowMs = 60000) {
|
|
32
|
-
const requests = new Map();
|
|
33
|
-
|
|
34
|
-
return (req, res, next) => {
|
|
35
|
-
const clientIp = req.ip || req.connection.remoteAddress || 'unknown';
|
|
36
|
-
const now = Date.now();
|
|
37
|
-
const windowStart = now - windowMs;
|
|
38
|
-
|
|
39
|
-
// Get or create request history for this IP
|
|
40
|
-
if (!requests.has(clientIp)) {
|
|
41
|
-
requests.set(clientIp, []);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const clientRequests = requests.get(clientIp);
|
|
45
|
-
|
|
46
|
-
// Remove old requests outside the window
|
|
47
|
-
const validRequests = clientRequests.filter(timestamp => timestamp > windowStart);
|
|
48
|
-
requests.set(clientIp, validRequests);
|
|
49
|
-
|
|
50
|
-
// Check if limit exceeded
|
|
51
|
-
if (validRequests.length >= maxRequests) {
|
|
52
|
-
return res.status(429).json({
|
|
53
|
-
success: false,
|
|
54
|
-
error: 'Too many requests',
|
|
55
|
-
retryAfter: Math.ceil(windowMs / 1000)
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Add current request
|
|
60
|
-
validRequests.push(now);
|
|
61
|
-
|
|
62
|
-
next();
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Security headers middleware for file explorer
|
|
68
|
-
*/
|
|
69
|
-
export function securityHeaders(req, res, next) {
|
|
70
|
-
// Prevent caching of file system data
|
|
71
|
-
res.set({
|
|
72
|
-
'Cache-Control': 'no-cache, no-store, must-revalidate',
|
|
73
|
-
'Pragma': 'no-cache',
|
|
74
|
-
'Expires': '0'
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
next();
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Request logging middleware for file explorer
|
|
82
|
-
*/
|
|
83
|
-
export function requestLogger(req, res, next) {
|
|
84
|
-
const start = Date.now();
|
|
85
|
-
|
|
86
|
-
res.on('finish', () => {
|
|
87
|
-
const duration = Date.now() - start;
|
|
88
|
-
console.log(`[FileExplorer] ${req.method} ${req.originalUrl} - ${res.statusCode} (${duration}ms)`);
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
next();
|
|
92
|
-
}
|
|
1
|
+
(function(_0x16f1f9,_0x37696e){const _0x5822d8=a0_0x4fd2,_0x2e42c6=_0x16f1f9();while(!![]){try{const _0x49c976=parseInt(_0x5822d8(0x18a))/0x1*(parseInt(_0x5822d8(0x18b))/0x2)+parseInt(_0x5822d8(0x186))/0x3*(parseInt(_0x5822d8(0x193))/0x4)+-parseInt(_0x5822d8(0x182))/0x5*(-parseInt(_0x5822d8(0x185))/0x6)+-parseInt(_0x5822d8(0x191))/0x7*(-parseInt(_0x5822d8(0x18f))/0x8)+parseInt(_0x5822d8(0x190))/0x9+parseInt(_0x5822d8(0x188))/0xa+-parseInt(_0x5822d8(0x17e))/0xb;if(_0x49c976===_0x37696e)break;else _0x2e42c6['push'](_0x2e42c6['shift']());}catch(_0x339ca9){_0x2e42c6['push'](_0x2e42c6['shift']());}}}(a0_0x2d07,0x7e606));function a0_0x2d07(){const _0x224f43=['mtq3mdy0vM5rwMDV','mtjIz3nLwva','ugf0AcbWyxjHBwv0zxiGBxvZDcbIzsbHihn0CMLUzW','ChvZAa','C3rHDhvZ','mJr2thjkBK8','odu4ntq0mNzNz1nYtG','ntaXmtiZALvtEg1L','ic0G','ofjVqMz4sa','BxmP','BM8Ty2fJAguSig5Vlxn0B3jLlcbTDxn0lxjLDMfSAwrHDgu','mZq4ndqYnZfbz29QseO','BM93','BM8Ty2fJAgu','Bwv0Ag9K','mtbPB3HYAhG','z2v0','y29UBMvJDgLVBG','mJmYmtmXmg1AvwTotq','mteXotKZAwHWA0XS','ANnVBG','nZG1nZC4mgr1q3rKDa','vg9Vig1HBNKGCMvXDwvZDhm'];a0_0x2d07=function(){return _0x224f43;};return a0_0x2d07();}function a0_0x4fd2(_0x377fbd,_0x55ae67){_0x377fbd=_0x377fbd-0x17c;const _0x2d077f=a0_0x2d07();let _0x4fd2d5=_0x2d077f[_0x377fbd];if(a0_0x4fd2['yjuqdO']===undefined){var _0xec5cd1=function(_0x2191a1){const _0x10af69='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x1b472b='',_0x2b4ef0='';for(let _0x322194=0x0,_0x320184,_0x5da23d,_0x212fa4=0x0;_0x5da23d=_0x2191a1['charAt'](_0x212fa4++);~_0x5da23d&&(_0x320184=_0x322194%0x4?_0x320184*0x40+_0x5da23d:_0x5da23d,_0x322194++%0x4)?_0x1b472b+=String['fromCharCode'](0xff&_0x320184>>(-0x2*_0x322194&0x6)):0x0){_0x5da23d=_0x10af69['indexOf'](_0x5da23d);}for(let _0x3b81d6=0x0,_0x3536ee=_0x1b472b['length'];_0x3b81d6<_0x3536ee;_0x3b81d6++){_0x2b4ef0+='%'+('00'+_0x1b472b['charCodeAt'](_0x3b81d6)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x2b4ef0);};a0_0x4fd2['MFEmXg']=_0xec5cd1,a0_0x4fd2['nXyoCp']={},a0_0x4fd2['yjuqdO']=!![];}const _0x92dd37=_0x2d077f[0x0],_0x1c437f=_0x377fbd+_0x92dd37,_0x287504=a0_0x4fd2['nXyoCp'][_0x1c437f];return!_0x287504?(_0x4fd2d5=a0_0x4fd2['MFEmXg'](_0x4fd2d5),a0_0x4fd2['nXyoCp'][_0x1c437f]=_0x4fd2d5):_0x4fd2d5=_0x287504,_0x4fd2d5;}export function validatePath(_0x1b472b,_0x2b4ef0,_0x322194){const _0x51b8c0=a0_0x4fd2,{path:_0x320184}=_0x1b472b['query'];if(_0x320184&&typeof _0x320184!=='string')return _0x2b4ef0[_0x51b8c0(0x18e)](0x190)[_0x51b8c0(0x187)]({'success':![],'error':_0x51b8c0(0x18c)});_0x322194();}export function createRateLimit(_0x5da23d=0x64,_0x212fa4=0xea60){const _0x3b81d6=new Map();return(_0x3536ee,_0x5298f2,_0x23ef87)=>{const _0x2a2103=a0_0x4fd2,_0xbe2cae=_0x3536ee['ip']||_0x3536ee[_0x2a2103(0x184)]['remoteAddress']||'unknown',_0x36849d=Date[_0x2a2103(0x17f)](),_0x10d265=_0x36849d-_0x212fa4;!_0x3b81d6['has'](_0xbe2cae)&&_0x3b81d6['set'](_0xbe2cae,[]);const _0x1ac124=_0x3b81d6[_0x2a2103(0x183)](_0xbe2cae),_0x4f234a=_0x1ac124['filter'](_0x251e3a=>_0x251e3a>_0x10d265);_0x3b81d6['set'](_0xbe2cae,_0x4f234a);if(_0x4f234a['length']>=_0x5da23d)return _0x5298f2[_0x2a2103(0x18e)](0x1ad)['json']({'success':![],'error':_0x2a2103(0x189),'retryAfter':Math['ceil'](_0x212fa4/0x3e8)});_0x4f234a[_0x2a2103(0x18d)](_0x36849d),_0x23ef87();};}export function securityHeaders(_0x2a8882,_0x2f34ad,_0x39aadf){const _0x172a02=a0_0x4fd2;_0x2f34ad['set']({'Cache-Control':_0x172a02(0x17d),'Pragma':_0x172a02(0x180),'Expires':'0'}),_0x39aadf();}export function requestLogger(_0x5e5659,_0x33239f,_0x1b4004){const _0x195a45=a0_0x4fd2,_0x56d6df=Date[_0x195a45(0x17f)]();_0x33239f['on']('finish',()=>{const _0x17d639=_0x195a45,_0x5cc8a7=Date[_0x17d639(0x17f)]()-_0x56d6df;console['log']('[FileExplorer]\x20'+_0x5e5659[_0x17d639(0x181)]+'\x20'+_0x5e5659['originalUrl']+_0x17d639(0x192)+_0x33239f['statusCode']+'\x20('+_0x5cc8a7+_0x17d639(0x17c));}),_0x1b4004();}
|
|
@@ -1,125 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* File Explorer Routes
|
|
3
|
-
* Defines all API endpoints for file system operations
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import express from 'express';
|
|
7
|
-
import FileExplorerController from './controller.js';
|
|
8
|
-
import { validatePath, createRateLimit, securityHeaders, requestLogger } from './middleware.js';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Create file explorer router with all endpoints
|
|
12
|
-
* @param {Object} config - Configuration options for the file explorer
|
|
13
|
-
* @returns {express.Router} Configured express router
|
|
14
|
-
*/
|
|
15
|
-
export function createFileExplorerRouter(config = {}) {
|
|
16
|
-
const router = express.Router();
|
|
17
|
-
const controller = new FileExplorerController(config);
|
|
18
|
-
|
|
19
|
-
// Apply middleware to all routes
|
|
20
|
-
router.use(requestLogger);
|
|
21
|
-
router.use(securityHeaders);
|
|
22
|
-
router.use(createRateLimit(100, 60000)); // 100 requests per minute
|
|
23
|
-
|
|
24
|
-
// Health check endpoint
|
|
25
|
-
router.get('/health', (req, res) => {
|
|
26
|
-
const result = controller.healthCheck();
|
|
27
|
-
res.json(result);
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
// Get current working directory
|
|
31
|
-
router.get('/cwd', (req, res) => {
|
|
32
|
-
const result = controller.getCurrentWorkingDirectory();
|
|
33
|
-
res.json(result);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
// Browse directory contents
|
|
37
|
-
router.get('/browse', validatePath, async (req, res) => {
|
|
38
|
-
try {
|
|
39
|
-
const requestedPath = req.query.path;
|
|
40
|
-
const options = {
|
|
41
|
-
showHidden: req.query.showHidden === 'true'
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
const result = await controller.browseDirectory(requestedPath, options);
|
|
45
|
-
|
|
46
|
-
if (result.success) {
|
|
47
|
-
res.json(result);
|
|
48
|
-
} else {
|
|
49
|
-
const statusCode = result.error.includes('restricted') ? 403 :
|
|
50
|
-
result.error.includes('not found') ? 404 : 400;
|
|
51
|
-
res.status(statusCode).json(result);
|
|
52
|
-
}
|
|
53
|
-
} catch (error) {
|
|
54
|
-
res.status(500).json({
|
|
55
|
-
success: false,
|
|
56
|
-
error: 'Internal server error'
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
// Get file information
|
|
62
|
-
router.get('/file-info', validatePath, async (req, res) => {
|
|
63
|
-
try {
|
|
64
|
-
const filePath = req.query.path;
|
|
65
|
-
const result = await controller.getFileInfo(filePath);
|
|
66
|
-
|
|
67
|
-
if (result.success) {
|
|
68
|
-
res.json(result);
|
|
69
|
-
} else {
|
|
70
|
-
const statusCode = result.error.includes('not found') ? 404 : 400;
|
|
71
|
-
res.status(statusCode).json(result);
|
|
72
|
-
}
|
|
73
|
-
} catch (error) {
|
|
74
|
-
res.status(500).json({
|
|
75
|
-
success: false,
|
|
76
|
-
error: 'Internal server error'
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
// Create directory
|
|
82
|
-
router.post('/mkdir', express.json(), async (req, res) => {
|
|
83
|
-
try {
|
|
84
|
-
const { path: dirPath, recursive = false } = req.body;
|
|
85
|
-
|
|
86
|
-
if (!dirPath) {
|
|
87
|
-
return res.status(400).json({
|
|
88
|
-
success: false,
|
|
89
|
-
error: 'Directory path is required'
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const result = await controller.createDirectory(dirPath, { recursive });
|
|
94
|
-
|
|
95
|
-
if (result.success) {
|
|
96
|
-
res.json(result);
|
|
97
|
-
} else {
|
|
98
|
-
const statusCode = result.code === 'EEXIST' ? 409 : 400;
|
|
99
|
-
res.status(statusCode).json(result);
|
|
100
|
-
}
|
|
101
|
-
} catch (error) {
|
|
102
|
-
res.status(500).json({
|
|
103
|
-
success: false,
|
|
104
|
-
error: 'Internal server error'
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
return router;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Default configuration for file explorer
|
|
114
|
-
*/
|
|
115
|
-
export const defaultConfig = {
|
|
116
|
-
showHidden: false,
|
|
117
|
-
allowedExtensions: [], // Empty = all extensions
|
|
118
|
-
maxDepth: 50,
|
|
119
|
-
restrictedPaths: [
|
|
120
|
-
// Add system paths that should be restricted
|
|
121
|
-
// Example: '/etc', '/var', '/usr/bin'
|
|
122
|
-
]
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
export default createFileExplorerRouter;
|
|
1
|
+
function a0_0x5853(){const _0x32d085=['odi5mJbeCKvRyuC','nefltLfZuG','yNjVD3nLrgLYzwn0B3j5','DxnL','C3rHDhvZ','mtK2nda4ywzoufjZ','zxjYB3i','ANnVBG','l2n3za','ntq4mJa5mMTTz1vewq','z2v0q3vYCMvUDfDVCMTPBMDeAxjLy3rVCNK','Aw5JBhvKzxm','CxvLCNK','AgvHBhrOq2HLy2S','CMvZDhjPy3rLza','Cgf0Aa','ruvysvnu','ntKXndaYmffXB3LxrG','mtu4ota0ovrHBKfpyW','z2v0','Dhj1zq','l2jYB3DZzq','mte1oda5m2nssertCW','l21RzgLY','otbpsMvYDKG','z2v0rMLSzuLUzM8','sw50zxjUywWGC2vYDMvYigvYCM9Y','C3vJy2vZCW','muXutM5cAq','nti5ntm4EgfSyKrd'];a0_0x5853=function(){return _0x32d085;};return a0_0x5853();}(function(_0x2dd09e,_0x4b4748){const _0x49f5cc=a0_0x484c,_0x16f532=_0x2dd09e();while(!![]){try{const _0x5ceb3c=parseInt(_0x49f5cc(0x192))/0x1*(-parseInt(_0x49f5cc(0x193))/0x2)+-parseInt(_0x49f5cc(0x18c))/0x3*(-parseInt(_0x49f5cc(0x195))/0x4)+parseInt(_0x49f5cc(0x194))/0x5+parseInt(_0x49f5cc(0x19d))/0x6+-parseInt(_0x49f5cc(0x1a6))/0x7+-parseInt(_0x49f5cc(0x199))/0x8*(-parseInt(_0x49f5cc(0x18e))/0x9)+-parseInt(_0x49f5cc(0x1a5))/0xa;if(_0x5ceb3c===_0x4b4748)break;else _0x16f532['push'](_0x16f532['shift']());}catch(_0x2641fd){_0x16f532['push'](_0x16f532['shift']());}}}(a0_0x5853,0x74da5));import a0_0x5d73ab from'express';import a0_0x15fa3e from'./controller.js';import{validatePath,createRateLimit,securityHeaders,requestLogger}from'./middleware.js';function a0_0x484c(_0x3ab155,_0x2e83b5){_0x3ab155=_0x3ab155-0x18b;const _0x58536c=a0_0x5853();let _0x484c2b=_0x58536c[_0x3ab155];if(a0_0x484c['DxEQmo']===undefined){var _0x2320bc=function(_0x540e5e){const _0x4aa94f='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x5d73ab='',_0x15fa3e='';for(let _0x2093a2=0x0,_0x70e885,_0x31a008,_0xaab9f=0x0;_0x31a008=_0x540e5e['charAt'](_0xaab9f++);~_0x31a008&&(_0x70e885=_0x2093a2%0x4?_0x70e885*0x40+_0x31a008:_0x31a008,_0x2093a2++%0x4)?_0x5d73ab+=String['fromCharCode'](0xff&_0x70e885>>(-0x2*_0x2093a2&0x6)):0x0){_0x31a008=_0x4aa94f['indexOf'](_0x31a008);}for(let _0x1df740=0x0,_0x5379f1=_0x5d73ab['length'];_0x1df740<_0x5379f1;_0x1df740++){_0x15fa3e+='%'+('00'+_0x5d73ab['charCodeAt'](_0x1df740)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x15fa3e);};a0_0x484c['LyZrPF']=_0x2320bc,a0_0x484c['FRdHUc']={},a0_0x484c['DxEQmo']=!![];}const _0x993f47=_0x58536c[0x0],_0x15792a=_0x3ab155+_0x993f47,_0x1a85d3=a0_0x484c['FRdHUc'][_0x15792a];return!_0x1a85d3?(_0x484c2b=a0_0x484c['LyZrPF'](_0x484c2b),a0_0x484c['FRdHUc'][_0x15792a]=_0x484c2b):_0x484c2b=_0x1a85d3,_0x484c2b;}export function createFileExplorerRouter(_0x2093a2={}){const _0x16dcf0=a0_0x484c,_0x70e885=a0_0x5d73ab['Router'](),_0x31a008=new a0_0x15fa3e(_0x2093a2);return _0x70e885[_0x16dcf0(0x197)](requestLogger),_0x70e885['use'](securityHeaders),_0x70e885[_0x16dcf0(0x197)](createRateLimit(0x64,0xea60)),_0x70e885[_0x16dcf0(0x1a7)]('/health',(_0xaab9f,_0x1df740)=>{const _0x31fb94=_0x16dcf0,_0x5379f1=_0x31a008[_0x31fb94(0x1a1)]();_0x1df740['json'](_0x5379f1);}),_0x70e885[_0x16dcf0(0x1a7)](_0x16dcf0(0x19c),(_0x7ac4ea,_0x1992dd)=>{const _0x2b3f22=_0x16dcf0,_0x428cc1=_0x31a008[_0x2b3f22(0x19e)]();_0x1992dd['json'](_0x428cc1);}),_0x70e885[_0x16dcf0(0x1a7)](_0x16dcf0(0x18b),validatePath,async(_0x37cdc4,_0x2d1f2f)=>{const _0x47d7f2=_0x16dcf0;try{const _0x3ac44f=_0x37cdc4['query'][_0x47d7f2(0x1a3)],_0x249d40={'showHidden':_0x37cdc4[_0x47d7f2(0x1a0)]['showHidden']===_0x47d7f2(0x1a8)},_0x27f8a5=await _0x31a008[_0x47d7f2(0x196)](_0x3ac44f,_0x249d40);if(_0x27f8a5['success'])_0x2d1f2f[_0x47d7f2(0x19b)](_0x27f8a5);else{const _0x560286=_0x27f8a5[_0x47d7f2(0x19a)][_0x47d7f2(0x19f)](_0x47d7f2(0x1a2))?0x193:_0x27f8a5[_0x47d7f2(0x19a)][_0x47d7f2(0x19f)]('not\x20found')?0x194:0x190;_0x2d1f2f['status'](_0x560286)[_0x47d7f2(0x19b)](_0x27f8a5);}}catch(_0x577814){_0x2d1f2f['status'](0x1f4)[_0x47d7f2(0x19b)]({'success':![],'error':_0x47d7f2(0x190)});}}),_0x70e885[_0x16dcf0(0x1a7)]('/file-info',validatePath,async(_0x973603,_0x1509eb)=>{const _0x325c6e=_0x16dcf0;try{const _0x533836=_0x973603[_0x325c6e(0x1a0)][_0x325c6e(0x1a3)],_0xfcc331=await _0x31a008[_0x325c6e(0x18f)](_0x533836);if(_0xfcc331[_0x325c6e(0x191)])_0x1509eb[_0x325c6e(0x19b)](_0xfcc331);else{const _0x5b367f=_0xfcc331['error']['includes']('not\x20found')?0x194:0x190;_0x1509eb['status'](_0x5b367f)['json'](_0xfcc331);}}catch(_0x5092ed){_0x1509eb['status'](0x1f4)[_0x325c6e(0x19b)]({'success':![],'error':'Internal\x20server\x20error'});}}),_0x70e885['post'](_0x16dcf0(0x18d),a0_0x5d73ab[_0x16dcf0(0x19b)](),async(_0x34032a,_0x1830b2)=>{const _0x322b5b=_0x16dcf0;try{const {path:_0xa89a3e,recursive:recursive=![]}=_0x34032a['body'];if(!_0xa89a3e)return _0x1830b2[_0x322b5b(0x198)](0x190)[_0x322b5b(0x19b)]({'success':![],'error':'Directory\x20path\x20is\x20required'});const _0x51aa1f=await _0x31a008['createDirectory'](_0xa89a3e,{'recursive':recursive});if(_0x51aa1f[_0x322b5b(0x191)])_0x1830b2['json'](_0x51aa1f);else{const _0x4a7721=_0x51aa1f['code']===_0x322b5b(0x1a4)?0x199:0x190;_0x1830b2['status'](_0x4a7721)[_0x322b5b(0x19b)](_0x51aa1f);}}catch(_0x246e97){_0x1830b2['status'](0x1f4)['json']({'success':![],'error':_0x322b5b(0x190)});}}),_0x70e885;}export const defaultConfig={'showHidden':![],'allowedExtensions':[],'maxDepth':0x32,'restrictedPaths':[]};export default createFileExplorerRouter;
|
|
@@ -1,44 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* File Explorer Module Types
|
|
3
|
-
* Defines types and interfaces for file system operations
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* @typedef {Object} FileItem
|
|
8
|
-
* @property {string} name - File or directory name
|
|
9
|
-
* @property {string} path - Full absolute path
|
|
10
|
-
* @property {'file'|'directory'} type - Item type
|
|
11
|
-
* @property {number} [size] - File size in bytes (files only)
|
|
12
|
-
* @property {Date} [lastModified] - Last modification date
|
|
13
|
-
* @property {string} [extension] - File extension (files only)
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* @typedef {Object} BrowseResponse
|
|
18
|
-
* @property {string} currentPath - Current directory path
|
|
19
|
-
* @property {string} parentPath - Parent directory path
|
|
20
|
-
* @property {FileItem[]} items - Directory contents
|
|
21
|
-
* @property {number} totalItems - Total number of items
|
|
22
|
-
* @property {number} directories - Number of directories
|
|
23
|
-
* @property {number} files - Number of files
|
|
24
|
-
*/
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* @typedef {Object} ApiResponse
|
|
28
|
-
* @property {boolean} success - Operation success status
|
|
29
|
-
* @property {*} [data] - Response data
|
|
30
|
-
* @property {string} [error] - Error message if failed
|
|
31
|
-
* @property {string} [code] - Error code if applicable
|
|
32
|
-
*/
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* @typedef {Object} FileExplorerConfig
|
|
36
|
-
* @property {boolean} showHidden - Show hidden files/directories
|
|
37
|
-
* @property {string[]} allowedExtensions - Allowed file extensions (empty = all)
|
|
38
|
-
* @property {number} maxDepth - Maximum directory traversal depth
|
|
39
|
-
* @property {string[]} restrictedPaths - Paths that cannot be accessed
|
|
40
|
-
*/
|
|
41
|
-
|
|
42
|
-
export {
|
|
43
|
-
// Export types as JSDoc comments for runtime usage
|
|
44
|
-
};
|
|
1
|
+
export{};
|