chore: 添加远程桌面控制组件、文档和构建产物
This commit is contained in:
163
dist-api/chunk-ER4KPD22.js
Normal file
163
dist-api/chunk-ER4KPD22.js
Normal file
@@ -0,0 +1,163 @@
|
||||
import {
|
||||
NOTEBOOK_ROOT
|
||||
} from "./chunk-74TMTGBG.js";
|
||||
|
||||
// shared/errors/index.ts
|
||||
var AppError = class extends Error {
|
||||
constructor(code, message, statusCode = 500, details) {
|
||||
super(message);
|
||||
this.code = code;
|
||||
this.name = "AppError";
|
||||
this.statusCode = statusCode;
|
||||
this.details = details;
|
||||
}
|
||||
statusCode;
|
||||
details;
|
||||
toJSON() {
|
||||
return {
|
||||
name: this.name,
|
||||
code: this.code,
|
||||
message: this.message,
|
||||
statusCode: this.statusCode,
|
||||
details: this.details
|
||||
};
|
||||
}
|
||||
};
|
||||
var ValidationError = class extends AppError {
|
||||
constructor(message, details) {
|
||||
super("VALIDATION_ERROR", message, 400, details);
|
||||
this.name = "ValidationError";
|
||||
}
|
||||
};
|
||||
var NotFoundError = class extends AppError {
|
||||
constructor(message = "Resource not found", details) {
|
||||
super("NOT_FOUND", message, 404, details);
|
||||
this.name = "NotFoundError";
|
||||
}
|
||||
};
|
||||
var AccessDeniedError = class extends AppError {
|
||||
constructor(message = "Access denied", details) {
|
||||
super("ACCESS_DENIED", message, 403, details);
|
||||
this.name = "AccessDeniedError";
|
||||
}
|
||||
};
|
||||
var BadRequestError = class extends AppError {
|
||||
constructor(message, details) {
|
||||
super("BAD_REQUEST", message, 400, details);
|
||||
this.name = "BadRequestError";
|
||||
}
|
||||
};
|
||||
var NotADirectoryError = class extends AppError {
|
||||
constructor(message = "\u4E0D\u662F\u76EE\u5F55", details) {
|
||||
super("NOT_A_DIRECTORY", message, 400, details);
|
||||
this.name = "NotADirectoryError";
|
||||
}
|
||||
};
|
||||
var AlreadyExistsError = class extends AppError {
|
||||
constructor(message = "Resource already exists", details) {
|
||||
super("ALREADY_EXISTS", message, 409, details);
|
||||
this.name = "AlreadyExistsError";
|
||||
}
|
||||
};
|
||||
var ForbiddenError = class extends AppError {
|
||||
constructor(message = "\u7981\u6B62\u8BBF\u95EE", details) {
|
||||
super("FORBIDDEN", message, 403, details);
|
||||
this.name = "ForbiddenError";
|
||||
}
|
||||
};
|
||||
var UnsupportedMediaTypeError = class extends AppError {
|
||||
constructor(message = "\u4E0D\u652F\u6301\u7684\u5A92\u4F53\u7C7B\u578B", details) {
|
||||
super("UNSUPPORTED_MEDIA_TYPE", message, 415, details);
|
||||
this.name = "UnsupportedMediaTypeError";
|
||||
}
|
||||
};
|
||||
var ResourceLockedError = class extends AppError {
|
||||
constructor(message = "\u8D44\u6E90\u5DF2\u9501\u5B9A", details) {
|
||||
super("RESOURCE_LOCKED", message, 423, details);
|
||||
this.name = "ResourceLockedError";
|
||||
}
|
||||
};
|
||||
var InternalError = class extends AppError {
|
||||
constructor(message = "\u670D\u52A1\u5668\u5185\u90E8\u9519\u8BEF", details) {
|
||||
super("INTERNAL_ERROR", message, 500, details);
|
||||
this.name = "InternalError";
|
||||
}
|
||||
};
|
||||
function isAppError(error) {
|
||||
return error instanceof AppError;
|
||||
}
|
||||
function isNodeError(error) {
|
||||
return error instanceof Error && "code" in error;
|
||||
}
|
||||
|
||||
// api/utils/pathSafety.ts
|
||||
import path from "path";
|
||||
var DANGEROUS_PATTERNS = [
|
||||
/\.\./,
|
||||
/\0/,
|
||||
/%2e%2e[%/]/i,
|
||||
/%252e%252e[%/]/i,
|
||||
/\.\.%2f/i,
|
||||
/\.\.%5c/i,
|
||||
/%c0%ae/i,
|
||||
/%c1%9c/i,
|
||||
/%c0%ae%c0%ae/i,
|
||||
/%c1%9c%c1%9c/i,
|
||||
/\.\.%c0%af/i,
|
||||
/\.\.%c1%9c/i,
|
||||
/%252e/i,
|
||||
/%uff0e/i,
|
||||
/%u002e/i
|
||||
];
|
||||
var DOUBLE_ENCODE_PATTERNS = [
|
||||
/%25[0-9a-fA-F]{2}/,
|
||||
/%[0-9a-fA-F]{2}%[0-9a-fA-F]{2}/
|
||||
];
|
||||
var normalizeRelPath = (input) => {
|
||||
const trimmed = input.replace(/\0/g, "").trim();
|
||||
return trimmed.replace(/^[/\\]+/, "");
|
||||
};
|
||||
var containsPathTraversal = (input) => {
|
||||
const decoded = decodeURIComponentSafe(input);
|
||||
return DANGEROUS_PATTERNS.some((pattern) => pattern.test(input) || pattern.test(decoded));
|
||||
};
|
||||
var containsDoubleEncoding = (input) => {
|
||||
return DOUBLE_ENCODE_PATTERNS.some((pattern) => pattern.test(input));
|
||||
};
|
||||
var hasPathSecurityIssues = (input) => {
|
||||
return containsPathTraversal(input) || containsDoubleEncoding(input);
|
||||
};
|
||||
var decodeURIComponentSafe = (input) => {
|
||||
try {
|
||||
return decodeURIComponent(input);
|
||||
} catch {
|
||||
return input;
|
||||
}
|
||||
};
|
||||
var resolveNotebookPath = (relPath) => {
|
||||
if (hasPathSecurityIssues(relPath)) {
|
||||
throw new AccessDeniedError("Path traversal detected");
|
||||
}
|
||||
const safeRelPath = normalizeRelPath(relPath);
|
||||
const notebookRoot = path.resolve(NOTEBOOK_ROOT);
|
||||
const fullPath = path.resolve(notebookRoot, safeRelPath);
|
||||
if (!fullPath.startsWith(notebookRoot)) {
|
||||
throw new AccessDeniedError("Access denied");
|
||||
}
|
||||
return { safeRelPath, fullPath };
|
||||
};
|
||||
|
||||
export {
|
||||
ValidationError,
|
||||
NotFoundError,
|
||||
BadRequestError,
|
||||
NotADirectoryError,
|
||||
AlreadyExistsError,
|
||||
ForbiddenError,
|
||||
UnsupportedMediaTypeError,
|
||||
ResourceLockedError,
|
||||
InternalError,
|
||||
isAppError,
|
||||
isNodeError,
|
||||
resolveNotebookPath
|
||||
};
|
||||
Reference in New Issue
Block a user