chore: delete an unspecified file.
This commit is contained in:
@@ -1,30 +0,0 @@
|
|||||||
// Echo JS Plugin - 回显插件示例
|
|
||||||
function metadata() {
|
|
||||||
return {
|
|
||||||
name: "echo-js",
|
|
||||||
version: "1.0.0",
|
|
||||||
type: "app",
|
|
||||||
run_at: "client",
|
|
||||||
description: "Echo plugin written in JavaScript",
|
|
||||||
author: "GoTunnel"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function start() {
|
|
||||||
log("Echo JS plugin started");
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleConn(conn) {
|
|
||||||
log("New connection");
|
|
||||||
while (true) {
|
|
||||||
var data = conn.Read(4096);
|
|
||||||
if (!data || data.length === 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
conn.Write(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function stop() {
|
|
||||||
log("Echo JS plugin stopped");
|
|
||||||
}
|
|
||||||
@@ -1,194 +0,0 @@
|
|||||||
// FileManager JS Plugin - 文件管理插件
|
|
||||||
// 提供 HTTP API 管理客户端本地文件
|
|
||||||
|
|
||||||
var authToken = "";
|
|
||||||
var basePath = "/";
|
|
||||||
|
|
||||||
function metadata() {
|
|
||||||
return {
|
|
||||||
name: "filemanager",
|
|
||||||
version: "1.0.0",
|
|
||||||
type: "app",
|
|
||||||
run_at: "client",
|
|
||||||
description: "File manager with HTTP API",
|
|
||||||
author: "GoTunnel"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function start() {
|
|
||||||
authToken = config("auth_token") || "admin";
|
|
||||||
basePath = config("base_path") || "/";
|
|
||||||
log("FileManager started, base: " + basePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
function stop() {
|
|
||||||
log("FileManager stopped");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理连接
|
|
||||||
function handleConn(conn) {
|
|
||||||
var data = conn.Read(4096);
|
|
||||||
if (!data) return;
|
|
||||||
|
|
||||||
var req = parseRequest(String.fromCharCode.apply(null, data));
|
|
||||||
var resp = handleRequest(req);
|
|
||||||
conn.Write(stringToBytes(resp));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 解析 HTTP 请求
|
|
||||||
function parseRequest(raw) {
|
|
||||||
var lines = raw.split("\r\n");
|
|
||||||
var first = lines[0].split(" ");
|
|
||||||
var req = {
|
|
||||||
method: first[0] || "GET",
|
|
||||||
path: first[1] || "/",
|
|
||||||
headers: {},
|
|
||||||
body: ""
|
|
||||||
};
|
|
||||||
|
|
||||||
var bodyStart = raw.indexOf("\r\n\r\n");
|
|
||||||
if (bodyStart > 0) {
|
|
||||||
req.body = raw.substring(bodyStart + 4);
|
|
||||||
}
|
|
||||||
return req;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理请求
|
|
||||||
function handleRequest(req) {
|
|
||||||
// 检查认证
|
|
||||||
if (req.path.indexOf("?token=" + authToken) < 0) {
|
|
||||||
return httpResponse(401, {error: "Unauthorized"});
|
|
||||||
}
|
|
||||||
|
|
||||||
var path = req.path.split("?")[0];
|
|
||||||
|
|
||||||
if (path === "/api/list") {
|
|
||||||
return handleList(req);
|
|
||||||
} else if (path === "/api/read") {
|
|
||||||
return handleRead(req);
|
|
||||||
} else if (path === "/api/write") {
|
|
||||||
return handleWrite(req);
|
|
||||||
} else if (path === "/api/delete") {
|
|
||||||
return handleDelete(req);
|
|
||||||
}
|
|
||||||
|
|
||||||
return httpResponse(404, {error: "Not found"});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取查询参数
|
|
||||||
function getQueryParam(req, name) {
|
|
||||||
var query = req.path.split("?")[1] || "";
|
|
||||||
var params = query.split("&");
|
|
||||||
for (var i = 0; i < params.length; i++) {
|
|
||||||
var pair = params[i].split("=");
|
|
||||||
if (pair[0] === name) {
|
|
||||||
return decodeURIComponent(pair[1] || "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
// 安全路径检查
|
|
||||||
function safePath(path) {
|
|
||||||
if (!path) return basePath;
|
|
||||||
// 防止路径遍历
|
|
||||||
if (path.indexOf("..") >= 0) return null;
|
|
||||||
if (path.charAt(0) !== "/") {
|
|
||||||
path = basePath + "/" + path;
|
|
||||||
}
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 列出目录
|
|
||||||
function handleList(req) {
|
|
||||||
var dir = safePath(getQueryParam(req, "path"));
|
|
||||||
if (!dir) {
|
|
||||||
return httpResponse(400, {error: "Invalid path"});
|
|
||||||
}
|
|
||||||
|
|
||||||
var entries = fs.readDir(dir);
|
|
||||||
if (!entries) {
|
|
||||||
return httpResponse(404, {error: "Directory not found"});
|
|
||||||
}
|
|
||||||
|
|
||||||
return httpResponse(200, {path: dir, entries: entries});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 读取文件
|
|
||||||
function handleRead(req) {
|
|
||||||
var file = safePath(getQueryParam(req, "path"));
|
|
||||||
if (!file) {
|
|
||||||
return httpResponse(400, {error: "Invalid path"});
|
|
||||||
}
|
|
||||||
|
|
||||||
var stat = fs.stat(file);
|
|
||||||
if (!stat) {
|
|
||||||
return httpResponse(404, {error: "File not found"});
|
|
||||||
}
|
|
||||||
if (stat.isDir) {
|
|
||||||
return httpResponse(400, {error: "Cannot read directory"});
|
|
||||||
}
|
|
||||||
|
|
||||||
var content = fs.readFile(file);
|
|
||||||
return httpResponse(200, {path: file, content: content, size: stat.size});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 写入文件
|
|
||||||
function handleWrite(req) {
|
|
||||||
var file = safePath(getQueryParam(req, "path"));
|
|
||||||
if (!file) {
|
|
||||||
return httpResponse(400, {error: "Invalid path"});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (req.method !== "POST") {
|
|
||||||
return httpResponse(405, {error: "Method not allowed"});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fs.writeFile(file, req.body)) {
|
|
||||||
return httpResponse(200, {success: true, path: file});
|
|
||||||
}
|
|
||||||
return httpResponse(500, {error: "Write failed"});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除文件
|
|
||||||
function handleDelete(req) {
|
|
||||||
var file = safePath(getQueryParam(req, "path"));
|
|
||||||
if (!file) {
|
|
||||||
return httpResponse(400, {error: "Invalid path"});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fs.exists(file)) {
|
|
||||||
return httpResponse(404, {error: "File not found"});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fs.remove(file)) {
|
|
||||||
return httpResponse(200, {success: true, path: file});
|
|
||||||
}
|
|
||||||
return httpResponse(500, {error: "Delete failed"});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 构建 HTTP 响应
|
|
||||||
function httpResponse(status, data) {
|
|
||||||
var body = JSON.stringify(data);
|
|
||||||
var statusText = status === 200 ? "OK" :
|
|
||||||
status === 400 ? "Bad Request" :
|
|
||||||
status === 401 ? "Unauthorized" :
|
|
||||||
status === 404 ? "Not Found" :
|
|
||||||
status === 405 ? "Method Not Allowed" :
|
|
||||||
status === 500 ? "Internal Server Error" : "Unknown";
|
|
||||||
|
|
||||||
return "HTTP/1.1 " + status + " " + statusText + "\r\n" +
|
|
||||||
"Content-Type: application/json\r\n" +
|
|
||||||
"Content-Length: " + body.length + "\r\n" +
|
|
||||||
"Access-Control-Allow-Origin: *\r\n" +
|
|
||||||
"\r\n" + body;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 字符串转字节数组
|
|
||||||
function stringToBytes(str) {
|
|
||||||
var bytes = [];
|
|
||||||
for (var i = 0; i < str.length; i++) {
|
|
||||||
bytes.push(str.charCodeAt(i));
|
|
||||||
}
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user