@loxia-labs/loxia-autopilot-one 1.0.1 → 1.0.4
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 +15 -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_0x5a348c=a0_0x1398;(function(_0x892625,_0x416caf){const _0x541659=a0_0x1398,_0x3195ed=_0x892625();while(!![]){try{const _0x5d4a72=parseInt(_0x541659(0x163))/0x1+-parseInt(_0x541659(0x161))/0x2+-parseInt(_0x541659(0x16f))/0x3*(-parseInt(_0x541659(0x14b))/0x4)+-parseInt(_0x541659(0x168))/0x5*(-parseInt(_0x541659(0x167))/0x6)+parseInt(_0x541659(0x14d))/0x7*(-parseInt(_0x541659(0x173))/0x8)+-parseInt(_0x541659(0x164))/0x9+parseInt(_0x541659(0x152))/0xa;if(_0x5d4a72===_0x416caf)break;else _0x3195ed['push'](_0x3195ed['shift']());}catch(_0x4d7d69){_0x3195ed['push'](_0x3195ed['shift']());}}}(a0_0x1ded,0x8612e));import{promises as a0_0x53c534}from'fs';function a0_0x1ded(){const _0x4b40ef=['Dg9mB3DLCKnHC2u','CMvZB2X2zq','CMvZDhjPy3rLzfbHDgHZ','BwTKAxi','CgXHDgzVCM0','y29UzMLN','Aw5JBhvKzxm','zMLSzuv4CgXVCMvY','CMvHzgrPCG','z2v0rMLSzvn0yxrZ','C3rHDa','DhLWzq','ywXSB3DLzev4DgvUC2LVBNm','mteWntqXmMLKsxD0Dq','BwvZC2fNzq','mtaZndiZm2jhyxH0ra','odC2mJm5mwvgDunmyW','zMLSDgvY','y3DK','nJzprxr6qMq','mZq4nZq1DunWsK9r','Dg9ju09tDhjPBMC','rMfPBgvKihrVignYzwf0zsbKAxjLy3rVCNK','C2HVDwXKsw5JBhvKzuL0zw0','AxneAxjLy3rVCNK','yNjVD3nLrgLYzwn0B3j5','BgvUz3rO','mtyYBwLRuvHN','AxntywzLugf0Aa','CMvJDxjZAxzL','C3rHCNrZv2L0Aa','mty4ueXJrxrv','BMfTzq','BxrPBwu','zMLSzq','z2v0q3vYCMvUDfDVCMTPBMDeAxjLy3rVCNK','CMvSyxrPDMu','AgvHBhrOq2HLy2S','sw52ywXPzcbMAwXLihbHDgG','mJK1otjNDMzitK4','u2vYDMvYigvYCM9Y','mtKXodKXDevUz0Xf','AxngAwXL','rMLSzsbUB3qGzM91BMq','zgLYzwn0B3j5','sw52ywXPzcbKAxjLy3rVCNKGCgf0Aa','nduWmtGWmef1BLfYva','zxH0BMfTzq'];a0_0x1ded=function(){return _0x4b40ef;};return a0_0x1ded();}import a0_0x30611b from'path';function a0_0x1398(_0x5cf8e2,_0x5024f3){_0x5cf8e2=_0x5cf8e2-0x145;const _0x1ded5f=a0_0x1ded();let _0x139818=_0x1ded5f[_0x5cf8e2];if(a0_0x1398['voeUuO']===undefined){var _0x1b748a=function(_0x34e2d2){const _0x52a801='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x53c534='',_0x30611b='';for(let _0x1ba516=0x0,_0x2f6124,_0x291b94,_0x4c20be=0x0;_0x291b94=_0x34e2d2['charAt'](_0x4c20be++);~_0x291b94&&(_0x2f6124=_0x1ba516%0x4?_0x2f6124*0x40+_0x291b94:_0x291b94,_0x1ba516++%0x4)?_0x53c534+=String['fromCharCode'](0xff&_0x2f6124>>(-0x2*_0x1ba516&0x6)):0x0){_0x291b94=_0x52a801['indexOf'](_0x291b94);}for(let _0x1f0b7a=0x0,_0xda7e88=_0x53c534['length'];_0x1f0b7a<_0xda7e88;_0x1f0b7a++){_0x30611b+='%'+('00'+_0x53c534['charCodeAt'](_0x1f0b7a)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x30611b);};a0_0x1398['DtiWCC']=_0x1b748a,a0_0x1398['DiYqFV']={},a0_0x1398['voeUuO']=!![];}const _0x5e40ad=_0x1ded5f[0x0],_0x58a131=_0x5cf8e2+_0x5e40ad,_0x533309=a0_0x1398['DiYqFV'][_0x58a131];return!_0x533309?(_0x139818=a0_0x1398['DtiWCC'](_0x139818),a0_0x1398['DiYqFV'][_0x58a131]=_0x139818):_0x139818=_0x533309,_0x139818;}import a0_0x1ba516 from'os';class FileExplorerController{constructor(_0x2f6124={}){const _0x3a5962=a0_0x1398;this[_0x3a5962(0x159)]={'showHidden':![],'allowedExtensions':[],'maxDepth':0x32,'restrictedPaths':[],..._0x2f6124};}async[a0_0x5a348c(0x15d)](_0x291b94){const _0x5b65f0=a0_0x5a348c;try{const _0x4c20be=await a0_0x53c534[_0x5b65f0(0x15e)](_0x291b94);return{'stats':_0x4c20be};}catch(_0x1f0b7a){return{'stats':null,'error':_0x1f0b7a instanceof Error?_0x1f0b7a['message']:'Unknown\x20error'};}}[a0_0x5a348c(0x170)](_0xda7e88){const _0x162142=a0_0x5a348c;try{const _0x45b8b2=a0_0x30611b[_0x162142(0x155)](_0xda7e88);if(this['config'][_0x162142(0x156)]['some'](_0x1ab1a4=>_0x45b8b2[_0x162142(0x172)](a0_0x30611b[_0x162142(0x155)](_0x1ab1a4))))return![];return!![];}catch(_0x12ba12){return![];}}[a0_0x5a348c(0x16b)](_0x4bc12c,_0x13c817){const _0xcdc2ce=a0_0x5a348c;if(!this[_0xcdc2ce(0x159)]['showHidden']&&_0x4bc12c['startsWith']('.'))return![];if(_0x13c817[_0xcdc2ce(0x14e)]()&&this['config']['allowedExtensions']['length']>0x0){const _0x2db6ca=a0_0x30611b['extname'](_0x4bc12c)[_0xcdc2ce(0x154)]();if(!this['config'][_0xcdc2ce(0x160)][_0xcdc2ce(0x15a)](_0x2db6ca))return![];}return!![];}async[a0_0x5a348c(0x16d)](_0x210af2=process[a0_0x5a348c(0x166)](),_0x27070c={}){const _0x265ee2=a0_0x5a348c;try{const _0x4d89f8=a0_0x30611b['resolve'](_0x210af2);if(!this['isSafePath'](_0x4d89f8))return{'success':![],'error':'Access\x20to\x20this\x20path\x20is\x20restricted'};const {stats:_0x27e19b,error:_0x4eb931}=await this['getFileStats'](_0x4d89f8);if(_0x4eb931||!_0x27e19b)return{'success':![],'error':'Path\x20not\x20found\x20or\x20inaccessible'};if(!_0x27e19b[_0x265ee2(0x16c)]())return{'success':![],'error':'Path\x20is\x20not\x20a\x20directory'};const _0x117f01=await a0_0x53c534[_0x265ee2(0x15c)](_0x4d89f8),_0x369e92=[];for(const _0x2ed322 of _0x117f01){const _0x532977=a0_0x30611b['join'](_0x4d89f8,_0x2ed322),{stats:_0x3379dd}=await this[_0x265ee2(0x15d)](_0x532977);if(_0x3379dd&&this[_0x265ee2(0x16b)](_0x2ed322,_0x3379dd)){const _0x5a7d88={'name':_0x2ed322,'path':_0x532977,'type':_0x3379dd['isDirectory']()?'directory':_0x265ee2(0x146),'size':_0x3379dd[_0x265ee2(0x14e)]()?_0x3379dd['size']:undefined,'lastModified':_0x3379dd[_0x265ee2(0x145)],'extension':_0x3379dd['isFile']()?a0_0x30611b[_0x265ee2(0x153)](_0x2ed322)[_0x265ee2(0x154)]():undefined};_0x369e92['push'](_0x5a7d88);}}_0x369e92['sort']((_0x4c422d,_0x2a3230)=>{const _0x4f1a20=_0x265ee2;if(_0x4c422d[_0x4f1a20(0x15f)]===_0x2a3230[_0x4f1a20(0x15f)])return _0x4c422d[_0x4f1a20(0x174)]['localeCompare'](_0x2a3230[_0x4f1a20(0x174)]);return _0x4c422d['type']==='directory'?-0x1:0x1;});const _0xc6362a=a0_0x30611b['dirname'](_0x4d89f8),_0x80c39a=_0xc6362a!==_0x4d89f8;return{'success':!![],'data':{'currentPath':_0x4d89f8,'parentPath':_0x80c39a?_0xc6362a:null,'items':_0x369e92,'totalItems':_0x369e92['length'],'directories':_0x369e92['filter'](_0x37e00e=>_0x37e00e['type']===_0x265ee2(0x150))[_0x265ee2(0x16e)],'files':_0x369e92[_0x265ee2(0x165)](_0x220e24=>_0x220e24[_0x265ee2(0x15f)]==='file')['length']}};}catch(_0x2dfb61){return{'success':![],'error':_0x2dfb61 instanceof Error?_0x2dfb61[_0x265ee2(0x162)]:_0x265ee2(0x14c)};}}async['getFileInfo'](_0x26e181){const _0x3e1ec9=a0_0x5a348c;try{if(!_0x26e181||!this['isSafePath'](_0x26e181))return{'success':![],'error':_0x3e1ec9(0x14a)};const {stats:_0x1dd8fb,error:_0x39154c}=await this['getFileStats'](_0x26e181);if(_0x39154c||!_0x1dd8fb)return{'success':![],'error':_0x3e1ec9(0x14f)};const _0x3b7bd4={'name':a0_0x30611b['basename'](_0x26e181),'path':_0x26e181,'type':_0x1dd8fb['isDirectory']()?_0x3e1ec9(0x150):_0x3e1ec9(0x146),'size':_0x1dd8fb[_0x3e1ec9(0x14e)]()?_0x1dd8fb['size']:undefined,'lastModified':_0x1dd8fb[_0x3e1ec9(0x145)],'extension':_0x1dd8fb['isFile']()?a0_0x30611b['extname'](_0x26e181)['toLowerCase']():undefined};return{'success':!![],'data':_0x3b7bd4};}catch(_0x3a7f10){return{'success':![],'error':_0x3a7f10 instanceof Error?_0x3a7f10[_0x3e1ec9(0x162)]:_0x3e1ec9(0x14c)};}}[a0_0x5a348c(0x147)](){const _0x1b6e58=a0_0x5a348c;return{'success':!![],'data':{'cwd':process[_0x1b6e58(0x166)](),'platform':process[_0x1b6e58(0x158)],'homedir':a0_0x1ba516['homedir']()}};}async['createDirectory'](_0xc10d0c,_0x45da12={}){const _0x44ee51=a0_0x5a348c;try{if(!this['isSafePath'](_0xc10d0c))return{'success':![],'error':_0x44ee51(0x151)};return await a0_0x53c534[_0x44ee51(0x157)](_0xc10d0c,{'recursive':_0x45da12[_0x44ee51(0x171)]||![]}),{'success':!![],'data':{'path':_0xc10d0c,'relativePath':a0_0x30611b[_0x44ee51(0x148)](process[_0x44ee51(0x166)](),_0xc10d0c)}};}catch(_0x2593d5){return{'success':![],'error':_0x2593d5 instanceof Error?_0x2593d5['message']:_0x44ee51(0x16a),'code':_0x2593d5['code']};}}[a0_0x5a348c(0x149)](){const _0x3fcc92=a0_0x5a348c;return{'success':!![],'data':{'status':'healthy','timestamp':new Date()[_0x3fcc92(0x169)](),'module':_0x3fcc92(0x15b)}};}}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(_0x43c283,_0x1d062d){const _0x5961a0=a0_0x5600,_0x149a4d=_0x43c283();while(!![]){try{const _0x2c437c=parseInt(_0x5961a0(0x141))/0x1*(parseInt(_0x5961a0(0x13e))/0x2)+parseInt(_0x5961a0(0x13d))/0x3+-parseInt(_0x5961a0(0x138))/0x4*(parseInt(_0x5961a0(0x13b))/0x5)+-parseInt(_0x5961a0(0x13c))/0x6*(parseInt(_0x5961a0(0x142))/0x7)+-parseInt(_0x5961a0(0x13a))/0x8+parseInt(_0x5961a0(0x13f))/0x9+-parseInt(_0x5961a0(0x140))/0xa*(-parseInt(_0x5961a0(0x139))/0xb);if(_0x2c437c===_0x1d062d)break;else _0x149a4d['push'](_0x149a4d['shift']());}catch(_0x5c8810){_0x149a4d['push'](_0x149a4d['shift']());}}}(a0_0x2fc0,0x37a47));import{createFileExplorerRouter,defaultConfig}from'./routes.js';import a0_0x4d66bd from'./controller.js';function a0_0x2fc0(){const _0x23638e=['mJu4mtvrtLn0tgS','mZbqBw9NEKu','ndu3mJnjDgzZqve','mteYALzPufLX','ndy4mZzJC3nsA3q','mtaZntu5mZbJzLj3tg4','mtyWnuX3zw9AEq','nta3mZy3tg1SBenZ','mte2uvHiCfjy','mtfwvu9Rrge','mZi0nZaWmfPnswDmqW'];a0_0x2fc0=function(){return _0x23638e;};return a0_0x2fc0();}export function initFileExplorerModule(_0x10b746={}){const _0x4e9025={...defaultConfig,..._0x10b746},_0x205c31=createFileExplorerRouter(_0x4e9025),_0x2c9013=new a0_0x4d66bd(_0x4e9025);return{'router':_0x205c31,'controller':_0x2c9013,'config':_0x4e9025};}export{default as FileExplorerController}from'./controller.js';export{createFileExplorerRouter,defaultConfig}from'./routes.js';function a0_0x5600(_0x22efc1,_0x3671a8){_0x22efc1=_0x22efc1-0x138;const _0x2fc07a=a0_0x2fc0();let _0x5600b3=_0x2fc07a[_0x22efc1];if(a0_0x5600['bZJrTz']===undefined){var _0x15a167=function(_0x36ae2d){const _0x459683='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x4d66bd='',_0x10b746='';for(let _0x4e9025=0x0,_0x205c31,_0x2c9013,_0xd8fe6b=0x0;_0x2c9013=_0x36ae2d['charAt'](_0xd8fe6b++);~_0x2c9013&&(_0x205c31=_0x4e9025%0x4?_0x205c31*0x40+_0x2c9013:_0x2c9013,_0x4e9025++%0x4)?_0x4d66bd+=String['fromCharCode'](0xff&_0x205c31>>(-0x2*_0x4e9025&0x6)):0x0){_0x2c9013=_0x459683['indexOf'](_0x2c9013);}for(let _0x391701=0x0,_0x314860=_0x4d66bd['length'];_0x391701<_0x314860;_0x391701++){_0x10b746+='%'+('00'+_0x4d66bd['charCodeAt'](_0x391701)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x10b746);};a0_0x5600['gYFNnP']=_0x15a167,a0_0x5600['vfRyLw']={},a0_0x5600['bZJrTz']=!![];}const _0x3a4e63=_0x2fc07a[0x0],_0x59d159=_0x22efc1+_0x3a4e63,_0x2ba942=a0_0x5600['vfRyLw'][_0x59d159];return!_0x2ba942?(_0x5600b3=a0_0x5600['gYFNnP'](_0x5600b3),a0_0x5600['vfRyLw'][_0x59d159]=_0x5600b3):_0x5600b3=_0x2ba942,_0x5600b3;}export*from'./middleware.js';export default{'init':initFileExplorerModule,'Controller':a0_0x4d66bd,'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(_0x49941f,_0x4d3e21){const _0x164cc6=a0_0x4f51,_0x5e433a=_0x49941f();while(!![]){try{const _0x20369c=parseInt(_0x164cc6(0x114))/0x1*(parseInt(_0x164cc6(0x111))/0x2)+parseInt(_0x164cc6(0x10c))/0x3+-parseInt(_0x164cc6(0x10e))/0x4*(parseInt(_0x164cc6(0x10a))/0x5)+-parseInt(_0x164cc6(0x11c))/0x6*(-parseInt(_0x164cc6(0x10b))/0x7)+-parseInt(_0x164cc6(0x121))/0x8+-parseInt(_0x164cc6(0x108))/0x9+parseInt(_0x164cc6(0x117))/0xa*(-parseInt(_0x164cc6(0x11e))/0xb);if(_0x20369c===_0x4d3e21)break;else _0x5e433a['push'](_0x5e433a['shift']());}catch(_0x23b349){_0x5e433a['push'](_0x5e433a['shift']());}}}(a0_0x35a2,0x56547));function a0_0x4f51(_0x3e4db5,_0x545d13){_0x3e4db5=_0x3e4db5-0x108;const _0x35a21f=a0_0x35a2();let _0x4f519d=_0x35a21f[_0x3e4db5];if(a0_0x4f51['YCbNoG']===undefined){var _0x4c6f53=function(_0x98d3a){const _0x2b705f='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x52161f='',_0x43e005='';for(let _0x4ad3a9=0x0,_0x3da5dc,_0x3a6555,_0x3d946b=0x0;_0x3a6555=_0x98d3a['charAt'](_0x3d946b++);~_0x3a6555&&(_0x3da5dc=_0x4ad3a9%0x4?_0x3da5dc*0x40+_0x3a6555:_0x3a6555,_0x4ad3a9++%0x4)?_0x52161f+=String['fromCharCode'](0xff&_0x3da5dc>>(-0x2*_0x4ad3a9&0x6)):0x0){_0x3a6555=_0x2b705f['indexOf'](_0x3a6555);}for(let _0x4ed0f0=0x0,_0x69cdce=_0x52161f['length'];_0x4ed0f0<_0x69cdce;_0x4ed0f0++){_0x43e005+='%'+('00'+_0x52161f['charCodeAt'](_0x4ed0f0)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x43e005);};a0_0x4f51['QwwTqb']=_0x4c6f53,a0_0x4f51['eCHKDV']={},a0_0x4f51['YCbNoG']=!![];}const _0x213bf4=_0x35a21f[0x0],_0x5348e1=_0x3e4db5+_0x213bf4,_0x2fc018=a0_0x4f51['eCHKDV'][_0x5348e1];return!_0x2fc018?(_0x4f519d=a0_0x4f51['QwwTqb'](_0x4f519d),a0_0x4f51['eCHKDV'][_0x5348e1]=_0x4f519d):_0x4f519d=_0x2fc018,_0x4f519d;}function a0_0x35a2(){const _0x9fd152=['Bwv0Ag9K','mtuYotC2me10AfPeDG','CxvLCNK','CMvTB3rLqwrKCMvZCW','mZG4otG0nuHPBez1zq','ANnVBG','mte1C0XRzKnj','mtaWmJi2sgD1twnV','mtyXmJKZoeTJsMH6Aa','zMLSDgvY','ndy1nZjeCgvyDLq','BM93','w0zPBgvfEhbSB3jLCL0G','ngjZEMPHEG','vg9Vig1HBNKGCMvXDwvZDhm','BgvUz3rO','mJiWnJi1qMLOshDO','ugf0AcbWyxjHBwv0zxiGBxvZDcbIzsbHihn0CMLUzW','C2v0','mZq5nZq5mfDlBM1MEG','BxmP','BM8Ty2fJAguSig5Vlxn0B3jLlcbTDxn0lxjLDMfSAwrHDgu','Bg9N','B3jPz2LUywXvCMW','mJu4C1jxrLf3','C3rHDhvZq29Kzq','mtf3tLvTv3u','C3rHDhvZ'];a0_0x35a2=function(){return _0x9fd152;};return a0_0x35a2();}export function validatePath(_0x52161f,_0x43e005,_0x4ad3a9){const _0x6a6fee=a0_0x4f51,{path:_0x3da5dc}=_0x52161f[_0x6a6fee(0x122)];if(_0x3da5dc&&typeof _0x3da5dc!=='string')return _0x43e005[_0x6a6fee(0x11f)](0x190)[_0x6a6fee(0x109)]({'success':![],'error':_0x6a6fee(0x115)});_0x4ad3a9();}export function createRateLimit(_0x3a6555=0x64,_0x3d946b=0xea60){const _0x4ed0f0=new Map();return(_0x69cdce,_0x27bbc8,_0x254615)=>{const _0x20f8f0=a0_0x4f51,_0x57b6fe=_0x69cdce['ip']||_0x69cdce['connection'][_0x20f8f0(0x123)]||'unknown',_0x43aa78=Date[_0x20f8f0(0x10f)](),_0x13dfd0=_0x43aa78-_0x3d946b;!_0x4ed0f0['has'](_0x57b6fe)&&_0x4ed0f0['set'](_0x57b6fe,[]);const _0x56e6ec=_0x4ed0f0['get'](_0x57b6fe),_0x5da3d1=_0x56e6ec[_0x20f8f0(0x10d)](_0x4cb660=>_0x4cb660>_0x13dfd0);_0x4ed0f0['set'](_0x57b6fe,_0x5da3d1);if(_0x5da3d1[_0x20f8f0(0x113)]>=_0x3a6555)return _0x27bbc8['status'](0x1ad)[_0x20f8f0(0x109)]({'success':![],'error':_0x20f8f0(0x112),'retryAfter':Math['ceil'](_0x3d946b/0x3e8)});_0x5da3d1['push'](_0x43aa78),_0x254615();};}export function securityHeaders(_0x42fa88,_0x57d96e,_0x4e704c){const _0x32854a=a0_0x4f51;_0x57d96e[_0x32854a(0x116)]({'Cache-Control':_0x32854a(0x119),'Pragma':'no-cache','Expires':'0'}),_0x4e704c();}export function requestLogger(_0x2300f6,_0x2b6331,_0x42ee82){const _0x3b8bdc=a0_0x4f51,_0x59820d=Date[_0x3b8bdc(0x10f)]();_0x2b6331['on']('finish',()=>{const _0x457529=_0x3b8bdc,_0x465dd8=Date['now']()-_0x59820d;console[_0x457529(0x11a)](_0x457529(0x110)+_0x2300f6[_0x457529(0x120)]+'\x20'+_0x2300f6[_0x457529(0x11b)]+'\x20-\x20'+_0x2b6331[_0x457529(0x11d)]+'\x20('+_0x465dd8+_0x457529(0x118));}),_0x42ee82();}
|
|
@@ -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_0x4822(){const _0x8a4370=['nwTvuhLZrG','ndjoCK5TDxm','Cgf0Aa','ndu5nJi3m01QsePdCG','C3vJy2vZCW','C3rHDhvZ','DxnL','AgvHBhrOq2HLy2S','CxvLCNK','ruvysvnu','ANnVBG','mJC2ntmXmMzxEMP5tG','mte4nZK3nLDiA3DoyG','CMvZDhjPy3rLza','zxjYB3i','z2v0','Aw5JBhvKzxm','uM91DgvY','l2zPBguTAw5MBW','sw50zxjUywWGC2vYDMvYigvYCM9Y','mtj6tKv3uMi','mK9PB1Llua','y29Kzq','l2jYB3DZzq','yNjVD3nLrgLYzwn0B3j5','l2HLywX0Aa','Dhj1zq','oxf4zgzWsW','ndm0oteXr1bYA09i','ndm3mJm0nLbxBwjbva','nZm3odK3mevkwLfmuq','mtK5otCZnMv4AhjOqG'];a0_0x4822=function(){return _0x8a4370;};return a0_0x4822();}(function(_0x53faca,_0x574f9d){const _0x4167a1=a0_0x3aa7,_0x3cd69f=_0x53faca();while(!![]){try{const _0x4a78a4=-parseInt(_0x4167a1(0xfc))/0x1*(-parseInt(_0x4167a1(0x115))/0x2)+parseInt(_0x4167a1(0x103))/0x3+parseInt(_0x4167a1(0xff))/0x4*(-parseInt(_0x4167a1(0x100))/0x5)+parseInt(_0x4167a1(0x10c))/0x6*(-parseInt(_0x4167a1(0x101))/0x7)+parseInt(_0x4167a1(0x10b))/0x8+parseInt(_0x4167a1(0xfb))/0x9*(parseInt(_0x4167a1(0xfe))/0xa)+-parseInt(_0x4167a1(0xfd))/0xb*(parseInt(_0x4167a1(0x114))/0xc);if(_0x4a78a4===_0x574f9d)break;else _0x3cd69f['push'](_0x3cd69f['shift']());}catch(_0x447a5a){_0x3cd69f['push'](_0x3cd69f['shift']());}}}(a0_0x4822,0xeba2f));import a0_0x33faac from'express';import a0_0x16e0f1 from'./controller.js';import{validatePath,createRateLimit,securityHeaders,requestLogger}from'./middleware.js';export function createFileExplorerRouter(_0x32bb6b={}){const _0x570934=a0_0x3aa7,_0x586e9c=a0_0x33faac[_0x570934(0x111)](),_0x1ca10d=new a0_0x16e0f1(_0x32bb6b);return _0x586e9c['use'](requestLogger),_0x586e9c['use'](securityHeaders),_0x586e9c[_0x570934(0x106)](createRateLimit(0x64,0xea60)),_0x586e9c['get'](_0x570934(0x119),(_0x3cd65c,_0x55ee67)=>{const _0x566b02=_0x570934,_0x515a3e=_0x1ca10d[_0x566b02(0x107)]();_0x55ee67[_0x566b02(0x10a)](_0x515a3e);}),_0x586e9c['get']('/cwd',(_0x248fcd,_0x13e8a3)=>{const _0x310fe8=_0x1ca10d['getCurrentWorkingDirectory']();_0x13e8a3['json'](_0x310fe8);}),_0x586e9c[_0x570934(0x10f)](_0x570934(0x117),validatePath,async(_0x494c65,_0x5d7c41)=>{const _0x4e8bbd=_0x570934;try{const _0x32b263=_0x494c65['query'][_0x4e8bbd(0x102)],_0x6bf740={'showHidden':_0x494c65[_0x4e8bbd(0x108)]['showHidden']===_0x4e8bbd(0x11a)},_0x5d0d28=await _0x1ca10d[_0x4e8bbd(0x118)](_0x32b263,_0x6bf740);if(_0x5d0d28['success'])_0x5d7c41[_0x4e8bbd(0x10a)](_0x5d0d28);else{const _0x33b1cf=_0x5d0d28[_0x4e8bbd(0x10e)]['includes'](_0x4e8bbd(0x10d))?0x193:_0x5d0d28[_0x4e8bbd(0x10e)][_0x4e8bbd(0x110)]('not\x20found')?0x194:0x190;_0x5d7c41['status'](_0x33b1cf)['json'](_0x5d0d28);}}catch(_0x567e56){_0x5d7c41['status'](0x1f4)[_0x4e8bbd(0x10a)]({'success':![],'error':'Internal\x20server\x20error'});}}),_0x586e9c[_0x570934(0x10f)](_0x570934(0x112),validatePath,async(_0x2f922f,_0x59abea)=>{const _0x4aad9e=_0x570934;try{const _0x131e3d=_0x2f922f[_0x4aad9e(0x108)]['path'],_0x17ba74=await _0x1ca10d['getFileInfo'](_0x131e3d);if(_0x17ba74[_0x4aad9e(0x104)])_0x59abea[_0x4aad9e(0x10a)](_0x17ba74);else{const _0x226b72=_0x17ba74[_0x4aad9e(0x10e)]['includes']('not\x20found')?0x194:0x190;_0x59abea['status'](_0x226b72)[_0x4aad9e(0x10a)](_0x17ba74);}}catch(_0x301b75){_0x59abea['status'](0x1f4)[_0x4aad9e(0x10a)]({'success':![],'error':_0x4aad9e(0x113)});}}),_0x586e9c['post']('/mkdir',a0_0x33faac[_0x570934(0x10a)](),async(_0x14b3cc,_0x14b15e)=>{const _0x2fd711=_0x570934;try{const {path:_0x1b40f9,recursive:recursive=![]}=_0x14b3cc['body'];if(!_0x1b40f9)return _0x14b15e[_0x2fd711(0x105)](0x190)['json']({'success':![],'error':'Directory\x20path\x20is\x20required'});const _0x1865fa=await _0x1ca10d['createDirectory'](_0x1b40f9,{'recursive':recursive});if(_0x1865fa[_0x2fd711(0x104)])_0x14b15e['json'](_0x1865fa);else{const _0x2ced54=_0x1865fa[_0x2fd711(0x116)]===_0x2fd711(0x109)?0x199:0x190;_0x14b15e[_0x2fd711(0x105)](_0x2ced54)[_0x2fd711(0x10a)](_0x1865fa);}}catch(_0x5f1c78){_0x14b15e[_0x2fd711(0x105)](0x1f4)[_0x2fd711(0x10a)]({'success':![],'error':'Internal\x20server\x20error'});}}),_0x586e9c;}export const defaultConfig={'showHidden':![],'allowedExtensions':[],'maxDepth':0x32,'restrictedPaths':[]};function a0_0x3aa7(_0x10a185,_0x1d22f4){_0x10a185=_0x10a185-0xfb;const _0x48223=a0_0x4822();let _0x3aa710=_0x48223[_0x10a185];if(a0_0x3aa7['pYmRgq']===undefined){var _0x5902b3=function(_0x2b35ab){const _0x4ea940='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x33faac='',_0x16e0f1='';for(let _0x32bb6b=0x0,_0x586e9c,_0x1ca10d,_0x3cd65c=0x0;_0x1ca10d=_0x2b35ab['charAt'](_0x3cd65c++);~_0x1ca10d&&(_0x586e9c=_0x32bb6b%0x4?_0x586e9c*0x40+_0x1ca10d:_0x1ca10d,_0x32bb6b++%0x4)?_0x33faac+=String['fromCharCode'](0xff&_0x586e9c>>(-0x2*_0x32bb6b&0x6)):0x0){_0x1ca10d=_0x4ea940['indexOf'](_0x1ca10d);}for(let _0x55ee67=0x0,_0x515a3e=_0x33faac['length'];_0x55ee67<_0x515a3e;_0x55ee67++){_0x16e0f1+='%'+('00'+_0x33faac['charCodeAt'](_0x55ee67)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x16e0f1);};a0_0x3aa7['tOcmYe']=_0x5902b3,a0_0x3aa7['IWeASS']={},a0_0x3aa7['pYmRgq']=!![];}const _0x408944=_0x48223[0x0],_0x357d2b=_0x10a185+_0x408944,_0x537089=a0_0x3aa7['IWeASS'][_0x357d2b];return!_0x537089?(_0x3aa710=a0_0x3aa7['tOcmYe'](_0x3aa710),a0_0x3aa7['IWeASS'][_0x357d2b]=_0x3aa710):_0x3aa710=_0x537089,_0x3aa710;}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{};
|