@internxt/cli 1.5.6 → 1.5.8
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 +38 -32
- package/dist/commands/add-cert.js +0 -1
- package/dist/commands/config.js +0 -1
- package/dist/commands/create-folder.js +0 -1
- package/dist/commands/delete-permanently-file.js +0 -1
- package/dist/commands/delete-permanently-folder.js +0 -1
- package/dist/commands/download-file.js +0 -1
- package/dist/commands/list.js +0 -1
- package/dist/commands/login.js +0 -1
- package/dist/commands/logout.js +0 -1
- package/dist/commands/logs.js +0 -1
- package/dist/commands/move-file.js +0 -1
- package/dist/commands/move-folder.js +0 -1
- package/dist/commands/rename-file.js +0 -1
- package/dist/commands/rename-folder.js +0 -1
- package/dist/commands/trash-clear.js +0 -1
- package/dist/commands/trash-file.js +0 -1
- package/dist/commands/trash-folder.js +0 -1
- package/dist/commands/trash-list.js +0 -1
- package/dist/commands/trash-restore-file.js +0 -1
- package/dist/commands/trash-restore-folder.js +0 -1
- package/dist/commands/upload-file.js +1 -2
- package/dist/commands/webdav-config.d.ts +1 -0
- package/dist/commands/webdav-config.js +10 -7
- package/dist/commands/webdav.js +0 -1
- package/dist/commands/whoami.js +0 -1
- package/dist/hooks/prerun/auth_check.js +0 -1
- package/dist/services/config.service.d.ts +1 -0
- package/dist/services/config.service.js +3 -0
- package/dist/types/command.types.d.ts +1 -0
- package/dist/types/drive.types.d.ts +1 -0
- package/dist/utils/cli.utils.d.ts +1 -2
- package/dist/utils/cli.utils.js +2 -2
- package/dist/utils/drive.utils.d.ts +2 -1
- package/dist/utils/drive.utils.js +14 -0
- package/dist/utils/errors.utils.d.ts +2 -1
- package/dist/utils/errors.utils.js +10 -4
- package/dist/utils/logger.utils.js +0 -10
- package/dist/utils/webdav.utils.d.ts +17 -5
- package/dist/utils/webdav.utils.js +15 -6
- package/dist/webdav/handlers/MKCOL.handler.d.ts +2 -0
- package/dist/webdav/handlers/MKCOL.handler.js +6 -16
- package/dist/webdav/handlers/MOVE.handler.d.ts +2 -0
- package/dist/webdav/handlers/MOVE.handler.js +3 -10
- package/dist/webdav/handlers/PUT.handler.d.ts +2 -2
- package/dist/webdav/handlers/PUT.handler.js +13 -18
- package/dist/webdav/middewares/auth.middleware.js +8 -2
- package/dist/webdav/middewares/errors.middleware.js +9 -2
- package/dist/webdav/services/webdav-folder.service.d.ts +17 -0
- package/dist/webdav/services/webdav-folder.service.js +51 -0
- package/dist/webdav/webdav-server.js +8 -1
- package/oclif.manifest.json +9 -1
- package/package.json +8 -8
|
@@ -34,5 +34,19 @@ class DriveUtils {
|
|
|
34
34
|
updatedAt: new Date(folderMeta.updatedAt),
|
|
35
35
|
};
|
|
36
36
|
}
|
|
37
|
+
static createFolderResponseToItem(folderResponse) {
|
|
38
|
+
return {
|
|
39
|
+
uuid: folderResponse.uuid,
|
|
40
|
+
id: folderResponse.id,
|
|
41
|
+
bucket: folderResponse.bucket,
|
|
42
|
+
status: folderResponse.deleted || folderResponse.removed ? 'TRASHED' : 'EXISTS',
|
|
43
|
+
name: folderResponse.plainName ?? folderResponse.name,
|
|
44
|
+
encryptedName: folderResponse.name,
|
|
45
|
+
parentId: folderResponse.parentId,
|
|
46
|
+
parentUuid: folderResponse.parentUuid,
|
|
47
|
+
createdAt: new Date(folderResponse.createdAt),
|
|
48
|
+
updatedAt: new Date(folderResponse.updatedAt),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
37
51
|
}
|
|
38
52
|
exports.DriveUtils = DriveUtils;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
export declare function isError(error: unknown): error is Error;
|
|
1
2
|
export declare class ErrorUtils {
|
|
2
|
-
static report(
|
|
3
|
+
static report(error: unknown, props?: Record<string, unknown>): void;
|
|
3
4
|
}
|
|
4
5
|
export declare class ConflictError extends Error {
|
|
5
6
|
statusCode: number;
|
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.NotImplementedError = exports.MethodNotAllowed = exports.UnsupportedMediaTypeError = exports.BadRequestError = exports.NotFoundError = exports.ConflictError = exports.ErrorUtils = void 0;
|
|
4
|
+
exports.isError = isError;
|
|
5
|
+
const logger_utils_1 = require("./logger.utils");
|
|
6
|
+
const node_util_1 = require("node:util");
|
|
7
|
+
function isError(error) {
|
|
8
|
+
return node_util_1.types.isNativeError(error);
|
|
9
|
+
}
|
|
4
10
|
class ErrorUtils {
|
|
5
|
-
static report(
|
|
6
|
-
if (error
|
|
7
|
-
|
|
11
|
+
static report(error, props = {}) {
|
|
12
|
+
if (isError(error)) {
|
|
13
|
+
logger_utils_1.logger.error(`[REPORTED_ERROR]: ${error.message}\nProperties => ${JSON.stringify(props, null, 2)}\nStack => ${error.stack}`);
|
|
8
14
|
}
|
|
9
15
|
else {
|
|
10
|
-
|
|
16
|
+
logger_utils_1.logger.error(`[REPORTED_ERROR]: ${JSON.stringify(error)}\nProperties => ${JSON.stringify(props, null, 2)}\n`);
|
|
11
17
|
}
|
|
12
18
|
}
|
|
13
19
|
}
|
|
@@ -52,13 +52,3 @@ exports.webdavLogger = winston_1.default.createLogger({
|
|
|
52
52
|
}),
|
|
53
53
|
],
|
|
54
54
|
});
|
|
55
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
56
|
-
exports.webdavLogger.add(new winston_1.default.transports.Console({
|
|
57
|
-
format: winston_1.default.format.simple(),
|
|
58
|
-
}));
|
|
59
|
-
}
|
|
60
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
61
|
-
exports.logger.add(new winston_1.default.transports.Console({
|
|
62
|
-
format: winston_1.default.format.simple(),
|
|
63
|
-
}));
|
|
64
|
-
}
|
|
@@ -2,14 +2,26 @@ import { Request } from 'express';
|
|
|
2
2
|
import { WebDavRequestedResource } from '../types/webdav.types';
|
|
3
3
|
import { DriveFolderService } from '../services/drive/drive-folder.service';
|
|
4
4
|
import { DriveFileService } from '../services/drive/drive-file.service';
|
|
5
|
-
import { DriveFileItem, DriveFolderItem } from '../types/drive.types';
|
|
5
|
+
import { DriveFileItem, DriveFolderItem, DriveItem } from '../types/drive.types';
|
|
6
6
|
export declare class WebDavUtils {
|
|
7
7
|
static joinURL(...pathComponents: string[]): string;
|
|
8
8
|
static removeHostFromURL(completeURL: string): string;
|
|
9
|
+
static decodeUrl(requestUrl: string, decodeUri?: boolean): string;
|
|
10
|
+
static normalizeFolderPath(path: string): string;
|
|
9
11
|
static getRequestedResource(urlObject: string | Request, decodeUri?: boolean): Promise<WebDavRequestedResource>;
|
|
10
|
-
static getDriveItemFromResource(
|
|
12
|
+
static getDriveItemFromResource(params: {
|
|
11
13
|
resource: WebDavRequestedResource;
|
|
12
|
-
driveFolderService
|
|
13
|
-
driveFileService?:
|
|
14
|
-
}): Promise<
|
|
14
|
+
driveFolderService: DriveFolderService;
|
|
15
|
+
driveFileService?: never;
|
|
16
|
+
}): Promise<DriveFolderItem | undefined>;
|
|
17
|
+
static getDriveItemFromResource(params: {
|
|
18
|
+
resource: WebDavRequestedResource;
|
|
19
|
+
driveFolderService?: never;
|
|
20
|
+
driveFileService: DriveFileService;
|
|
21
|
+
}): Promise<DriveFileItem | undefined>;
|
|
22
|
+
static getDriveItemFromResource(params: {
|
|
23
|
+
resource: WebDavRequestedResource;
|
|
24
|
+
driveFolderService: DriveFolderService;
|
|
25
|
+
driveFileService: DriveFileService;
|
|
26
|
+
}): Promise<DriveItem | undefined>;
|
|
15
27
|
}
|
|
@@ -19,6 +19,19 @@ class WebDavUtils {
|
|
|
19
19
|
url = '/'.concat(url);
|
|
20
20
|
return url;
|
|
21
21
|
}
|
|
22
|
+
static decodeUrl(requestUrl, decodeUri = true) {
|
|
23
|
+
return (decodeUri ? decodeURIComponent(requestUrl) : requestUrl).replaceAll('/./', '/');
|
|
24
|
+
}
|
|
25
|
+
static normalizeFolderPath(path) {
|
|
26
|
+
let normalizedPath = path;
|
|
27
|
+
if (!normalizedPath.startsWith('/')) {
|
|
28
|
+
normalizedPath = `/${normalizedPath}`;
|
|
29
|
+
}
|
|
30
|
+
if (!normalizedPath.endsWith('/')) {
|
|
31
|
+
normalizedPath = `${normalizedPath}/`;
|
|
32
|
+
}
|
|
33
|
+
return normalizedPath;
|
|
34
|
+
}
|
|
22
35
|
static async getRequestedResource(urlObject, decodeUri = true) {
|
|
23
36
|
let requestUrl;
|
|
24
37
|
if (typeof urlObject === 'string') {
|
|
@@ -27,13 +40,9 @@ class WebDavUtils {
|
|
|
27
40
|
else {
|
|
28
41
|
requestUrl = urlObject.url;
|
|
29
42
|
}
|
|
30
|
-
const decodedUrl = (
|
|
43
|
+
const decodedUrl = this.decodeUrl(requestUrl, decodeUri);
|
|
31
44
|
const parsedPath = node_path_1.default.parse(decodedUrl);
|
|
32
|
-
|
|
33
|
-
if (!parentPath.startsWith('/'))
|
|
34
|
-
parentPath = '/'.concat(parentPath);
|
|
35
|
-
if (!parentPath.endsWith('/'))
|
|
36
|
-
parentPath = parentPath.concat('/');
|
|
45
|
+
const parentPath = this.normalizeFolderPath(node_path_1.default.dirname(decodedUrl));
|
|
37
46
|
const isFolder = requestUrl.endsWith('/');
|
|
38
47
|
if (isFolder) {
|
|
39
48
|
return {
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { WebDavMethodHandler } from '../../types/webdav.types';
|
|
2
2
|
import { Request, Response } from 'express';
|
|
3
3
|
import { DriveFolderService } from '../../services/drive/drive-folder.service';
|
|
4
|
+
import { WebDavFolderService } from '../services/webdav-folder.service';
|
|
4
5
|
export declare class MKCOLRequestHandler implements WebDavMethodHandler {
|
|
5
6
|
private readonly dependencies;
|
|
6
7
|
constructor(dependencies: {
|
|
7
8
|
driveFolderService: DriveFolderService;
|
|
9
|
+
webDavFolderService: WebDavFolderService;
|
|
8
10
|
});
|
|
9
11
|
handle: (req: Request, res: Response) => Promise<void>;
|
|
10
12
|
}
|
|
@@ -4,7 +4,6 @@ exports.MKCOLRequestHandler = void 0;
|
|
|
4
4
|
const webdav_utils_1 = require("../../utils/webdav.utils");
|
|
5
5
|
const logger_utils_1 = require("../../utils/logger.utils");
|
|
6
6
|
const xml_utils_1 = require("../../utils/xml.utils");
|
|
7
|
-
const async_utils_1 = require("../../utils/async.utils");
|
|
8
7
|
const errors_utils_1 = require("../../utils/errors.utils");
|
|
9
8
|
class MKCOLRequestHandler {
|
|
10
9
|
dependencies;
|
|
@@ -12,18 +11,11 @@ class MKCOLRequestHandler {
|
|
|
12
11
|
this.dependencies = dependencies;
|
|
13
12
|
}
|
|
14
13
|
handle = async (req, res) => {
|
|
15
|
-
const { driveFolderService } = this.dependencies;
|
|
14
|
+
const { driveFolderService, webDavFolderService } = this.dependencies;
|
|
16
15
|
const resource = await webdav_utils_1.WebDavUtils.getRequestedResource(req);
|
|
17
16
|
logger_utils_1.webdavLogger.info(`[MKCOL] Request received for ${resource.type} at ${resource.url}`);
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
resource: parentResource,
|
|
21
|
-
driveFolderService,
|
|
22
|
-
});
|
|
23
|
-
if (!parentDriveItem) {
|
|
24
|
-
throw new errors_utils_1.ConflictError(`Parent folders not found on Internxt Drive at ${resource.url}`);
|
|
25
|
-
}
|
|
26
|
-
const parentFolderItem = parentDriveItem;
|
|
17
|
+
const parentDriveFolderItem = (await webDavFolderService.getDriveFolderItemFromPath(resource.parentPath)) ??
|
|
18
|
+
(await webDavFolderService.createParentPathOrThrow(resource.parentPath));
|
|
27
19
|
const driveFolderItem = await webdav_utils_1.WebDavUtils.getDriveItemFromResource({
|
|
28
20
|
resource,
|
|
29
21
|
driveFolderService,
|
|
@@ -33,13 +25,11 @@ class MKCOLRequestHandler {
|
|
|
33
25
|
logger_utils_1.webdavLogger.info(`[MKCOL] ❌ Folder '${resource.url}' already exists`);
|
|
34
26
|
throw new errors_utils_1.MethodNotAllowed('Folder already exists');
|
|
35
27
|
}
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
parentFolderUuid:
|
|
28
|
+
const newFolder = await webDavFolderService.createFolder({
|
|
29
|
+
folderName: resource.path.base,
|
|
30
|
+
parentFolderUuid: parentDriveFolderItem.uuid,
|
|
39
31
|
});
|
|
40
|
-
const newFolder = await createFolder;
|
|
41
32
|
logger_utils_1.webdavLogger.info(`[MKCOL] ✅ Folder created with UUID ${newFolder.uuid}`);
|
|
42
|
-
await async_utils_1.AsyncUtils.sleep(500);
|
|
43
33
|
res.status(201).send(xml_utils_1.XMLUtils.toWebDavXML({}, {}));
|
|
44
34
|
};
|
|
45
35
|
}
|
|
@@ -2,11 +2,13 @@ import { Request, Response } from 'express';
|
|
|
2
2
|
import { DriveFileService } from '../../services/drive/drive-file.service';
|
|
3
3
|
import { DriveFolderService } from '../../services/drive/drive-folder.service';
|
|
4
4
|
import { WebDavMethodHandler } from '../../types/webdav.types';
|
|
5
|
+
import { WebDavFolderService } from '../services/webdav-folder.service';
|
|
5
6
|
export declare class MOVERequestHandler implements WebDavMethodHandler {
|
|
6
7
|
private readonly dependencies;
|
|
7
8
|
constructor(dependencies: {
|
|
8
9
|
driveFolderService: DriveFolderService;
|
|
9
10
|
driveFileService: DriveFileService;
|
|
11
|
+
webDavFolderService: WebDavFolderService;
|
|
10
12
|
});
|
|
11
13
|
handle: (req: Request, res: Response) => Promise<void>;
|
|
12
14
|
}
|
|
@@ -10,7 +10,7 @@ class MOVERequestHandler {
|
|
|
10
10
|
this.dependencies = dependencies;
|
|
11
11
|
}
|
|
12
12
|
handle = async (req, res) => {
|
|
13
|
-
const { driveFolderService, driveFileService } = this.dependencies;
|
|
13
|
+
const { driveFolderService, driveFileService, webDavFolderService } = this.dependencies;
|
|
14
14
|
const resource = await webdav_utils_1.WebDavUtils.getRequestedResource(req);
|
|
15
15
|
logger_utils_1.webdavLogger.info(`[MOVE] Request received for ${resource.type} at ${resource.url}`);
|
|
16
16
|
const destinationUrl = req.header('destination');
|
|
@@ -49,15 +49,8 @@ class MOVERequestHandler {
|
|
|
49
49
|
}
|
|
50
50
|
else {
|
|
51
51
|
logger_utils_1.webdavLogger.info(`[MOVE] Moving ${resource.type} with UUID ${originalDriveItem.uuid} to ${destinationPath}`);
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
resource: destinationFolderResource,
|
|
55
|
-
driveFolderService,
|
|
56
|
-
});
|
|
57
|
-
if (!destinationDriveFolderItem) {
|
|
58
|
-
throw new errors_utils_1.NotFoundError(`Resource not found on Internxt Drive at ${resource.url}`);
|
|
59
|
-
}
|
|
60
|
-
const destinationFolderItem = destinationDriveFolderItem;
|
|
52
|
+
const destinationFolderItem = (await webDavFolderService.getDriveFolderItemFromPath(destinationResource.parentPath)) ??
|
|
53
|
+
(await webDavFolderService.createParentPathOrThrow(destinationResource.parentPath));
|
|
61
54
|
if (resource.type === 'folder') {
|
|
62
55
|
const folder = originalDriveItem;
|
|
63
56
|
await driveFolderService.moveFolder(folder.uuid, {
|
|
@@ -3,13 +3,13 @@ import { DriveFileService } from '../../services/drive/drive-file.service';
|
|
|
3
3
|
import { NetworkFacade } from '../../services/network/network-facade.service';
|
|
4
4
|
import { AuthService } from '../../services/auth.service';
|
|
5
5
|
import { WebDavMethodHandler } from '../../types/webdav.types';
|
|
6
|
-
import { DriveFolderService } from '../../services/drive/drive-folder.service';
|
|
7
6
|
import { TrashService } from '../../services/drive/trash.service';
|
|
7
|
+
import { WebDavFolderService } from '../services/webdav-folder.service';
|
|
8
8
|
export declare class PUTRequestHandler implements WebDavMethodHandler {
|
|
9
9
|
private readonly dependencies;
|
|
10
10
|
constructor(dependencies: {
|
|
11
11
|
driveFileService: DriveFileService;
|
|
12
|
-
|
|
12
|
+
webDavFolderService: WebDavFolderService;
|
|
13
13
|
trashService: TrashService;
|
|
14
14
|
authService: AuthService;
|
|
15
15
|
networkFacade: NetworkFacade;
|
|
@@ -10,13 +10,13 @@ const cli_utils_1 = require("../../utils/cli.utils");
|
|
|
10
10
|
const stream_utils_1 = require("../../utils/stream.utils");
|
|
11
11
|
const thumbnail_utils_1 = require("../../utils/thumbnail.utils");
|
|
12
12
|
const thumbnail_service_1 = require("../../services/thumbnail.service");
|
|
13
|
+
const async_utils_1 = require("../../utils/async.utils");
|
|
13
14
|
class PUTRequestHandler {
|
|
14
15
|
dependencies;
|
|
15
16
|
constructor(dependencies) {
|
|
16
17
|
this.dependencies = dependencies;
|
|
17
18
|
}
|
|
18
19
|
handle = async (req, res) => {
|
|
19
|
-
const { authService, networkFacade, driveFileService, driveFolderService, trashService } = this.dependencies;
|
|
20
20
|
const contentLength = Number(req.headers['content-length']);
|
|
21
21
|
if (!contentLength || isNaN(contentLength) || contentLength <= 0) {
|
|
22
22
|
throw new errors_utils_1.UnsupportedMediaTypeError('Empty files are not supported');
|
|
@@ -26,30 +26,23 @@ class PUTRequestHandler {
|
|
|
26
26
|
throw new errors_utils_1.NotFoundError('Folders cannot be created with PUT. Use MKCOL instead.');
|
|
27
27
|
logger_utils_1.webdavLogger.info(`[PUT] Request received for ${resource.type} at ${resource.url}`);
|
|
28
28
|
logger_utils_1.webdavLogger.info(`[PUT] Uploading '${resource.name}' to '${resource.parentPath}'`);
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
resource: parentResource,
|
|
32
|
-
driveFolderService,
|
|
33
|
-
});
|
|
34
|
-
if (!parentDriveFolderItem) {
|
|
35
|
-
throw new errors_utils_1.ConflictError(`Parent folders not found on Internxt Drive at ${resource.url}`);
|
|
36
|
-
}
|
|
37
|
-
const parentFolderItem = parentDriveFolderItem;
|
|
29
|
+
const parentDriveFolderItem = (await this.dependencies.webDavFolderService.getDriveFolderItemFromPath(resource.parentPath)) ??
|
|
30
|
+
(await this.dependencies.webDavFolderService.createParentPathOrThrow(resource.parentPath));
|
|
38
31
|
try {
|
|
39
|
-
const driveFileItem =
|
|
32
|
+
const driveFileItem = await webdav_utils_1.WebDavUtils.getDriveItemFromResource({
|
|
40
33
|
resource: resource,
|
|
41
|
-
driveFileService,
|
|
42
|
-
})
|
|
34
|
+
driveFileService: this.dependencies.driveFileService,
|
|
35
|
+
});
|
|
43
36
|
if (driveFileItem && driveFileItem.status === 'EXISTS') {
|
|
44
37
|
logger_utils_1.webdavLogger.info(`[PUT] File '${resource.name}' already exists in '${resource.path.dir}', trashing it...`);
|
|
45
|
-
await trashService.trashItems({
|
|
38
|
+
await this.dependencies.trashService.trashItems({
|
|
46
39
|
items: [{ type: resource.type, uuid: driveFileItem.uuid, id: null }],
|
|
47
40
|
});
|
|
48
41
|
}
|
|
49
42
|
}
|
|
50
43
|
catch {
|
|
51
44
|
}
|
|
52
|
-
const { user } = await authService.getAuthDetails();
|
|
45
|
+
const { user } = await this.dependencies.authService.getAuthDetails();
|
|
53
46
|
const fileType = resource.path.ext.replace('.', '');
|
|
54
47
|
const timer = cli_utils_1.CLIUtils.timer();
|
|
55
48
|
let bufferStream;
|
|
@@ -66,7 +59,7 @@ class PUTRequestHandler {
|
|
|
66
59
|
}
|
|
67
60
|
};
|
|
68
61
|
const fileId = await new Promise((resolve, reject) => {
|
|
69
|
-
const state = networkFacade.uploadFile(fileStream, contentLength, user.bucket, (err, res) => {
|
|
62
|
+
const state = this.dependencies.networkFacade.uploadFile(fileStream, contentLength, user.bucket, (err, res) => {
|
|
70
63
|
if (err) {
|
|
71
64
|
aborted = true;
|
|
72
65
|
return reject(err);
|
|
@@ -87,7 +80,7 @@ class PUTRequestHandler {
|
|
|
87
80
|
plainName: resource.path.name,
|
|
88
81
|
type: fileType,
|
|
89
82
|
size: contentLength,
|
|
90
|
-
folderUuid:
|
|
83
|
+
folderUuid: parentDriveFolderItem.uuid,
|
|
91
84
|
fileId: fileId,
|
|
92
85
|
bucket: user.bucket,
|
|
93
86
|
encryptVersion: types_1.EncryptionVersion.Aes03,
|
|
@@ -96,7 +89,7 @@ class PUTRequestHandler {
|
|
|
96
89
|
if (isThumbnailable && bufferStream) {
|
|
97
90
|
const thumbnailBuffer = bufferStream.getBuffer();
|
|
98
91
|
if (thumbnailBuffer) {
|
|
99
|
-
await thumbnail_service_1.ThumbnailService.instance.uploadThumbnail(thumbnailBuffer, fileType, user.bucket, file.uuid, networkFacade);
|
|
92
|
+
await thumbnail_service_1.ThumbnailService.instance.uploadThumbnail(thumbnailBuffer, fileType, user.bucket, file.uuid, this.dependencies.networkFacade);
|
|
100
93
|
}
|
|
101
94
|
}
|
|
102
95
|
}
|
|
@@ -105,6 +98,8 @@ class PUTRequestHandler {
|
|
|
105
98
|
}
|
|
106
99
|
const uploadTime = timer.stop();
|
|
107
100
|
logger_utils_1.webdavLogger.info(`[PUT] ✅ File uploaded in ${uploadTime}ms to Internxt Drive`);
|
|
101
|
+
await async_utils_1.AsyncUtils.sleep(500);
|
|
102
|
+
logger_utils_1.webdavLogger.info(`[PUT] [RESPONSE-201] ${resource.url} - Returning 201 Created after ${uploadTime}ms (+ 500ms propagation delay)`);
|
|
108
103
|
res.status(201).send();
|
|
109
104
|
};
|
|
110
105
|
}
|
|
@@ -4,6 +4,7 @@ exports.AuthMiddleware = void 0;
|
|
|
4
4
|
const sdk_manager_service_1 = require("../../services/sdk-manager.service");
|
|
5
5
|
const logger_utils_1 = require("../../utils/logger.utils");
|
|
6
6
|
const xml_utils_1 = require("../../utils/xml.utils");
|
|
7
|
+
const errors_utils_1 = require("../../utils/errors.utils");
|
|
7
8
|
const AuthMiddleware = (authService) => {
|
|
8
9
|
return (_, res, next) => {
|
|
9
10
|
(async () => {
|
|
@@ -14,10 +15,15 @@ const AuthMiddleware = (authService) => {
|
|
|
14
15
|
}
|
|
15
16
|
catch (error) {
|
|
16
17
|
let message = 'Authentication required to access this resource.';
|
|
17
|
-
if (
|
|
18
|
+
if ((0, errors_utils_1.isError)(error)) {
|
|
18
19
|
message = error.message;
|
|
20
|
+
if (error.stack) {
|
|
21
|
+
logger_utils_1.webdavLogger.error(`Error from AuthMiddleware: ${message}\nStack: ${error.stack}`);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
logger_utils_1.webdavLogger.error(`Error from AuthMiddleware: ${message}`);
|
|
25
|
+
}
|
|
19
26
|
}
|
|
20
|
-
logger_utils_1.webdavLogger.error('Error from AuthMiddleware: ' + message);
|
|
21
27
|
const errorBodyXML = xml_utils_1.XMLUtils.toWebDavXML({
|
|
22
28
|
[xml_utils_1.XMLUtils.addDefaultNamespace('responsedescription')]: message,
|
|
23
29
|
}, {}, 'error');
|
|
@@ -3,10 +3,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.ErrorHandlingMiddleware = void 0;
|
|
4
4
|
const logger_utils_1 = require("../../utils/logger.utils");
|
|
5
5
|
const xml_utils_1 = require("../../utils/xml.utils");
|
|
6
|
+
const errors_utils_1 = require("../../utils/errors.utils");
|
|
6
7
|
const ErrorHandlingMiddleware = (err, req, res, _) => {
|
|
7
|
-
|
|
8
|
+
const message = (0, errors_utils_1.isError)(err) ? err.message : 'Something went wrong';
|
|
9
|
+
if ((0, errors_utils_1.isError)(err) && err.stack) {
|
|
10
|
+
logger_utils_1.webdavLogger.error(`[ERROR MIDDLEWARE] [${req.method.toUpperCase()} - ${req.url}] ${message}\nStack: ${err.stack}`);
|
|
11
|
+
}
|
|
12
|
+
else {
|
|
13
|
+
logger_utils_1.webdavLogger.error(`[ERROR MIDDLEWARE] [${req.method.toUpperCase()} - ${req.url}] ${message}`);
|
|
14
|
+
}
|
|
8
15
|
const errorBodyXML = xml_utils_1.XMLUtils.toWebDavXML({
|
|
9
|
-
[xml_utils_1.XMLUtils.addDefaultNamespace('responsedescription')]:
|
|
16
|
+
[xml_utils_1.XMLUtils.addDefaultNamespace('responsedescription')]: message,
|
|
10
17
|
}, {}, 'error');
|
|
11
18
|
let statusCode = 500;
|
|
12
19
|
if ('statusCode' in err && !isNaN(err.statusCode)) {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ConfigService } from '../../services/config.service';
|
|
2
|
+
import { DriveFolderService } from '../../services/drive/drive-folder.service';
|
|
3
|
+
import { DriveFolderItem } from '../../types/drive.types';
|
|
4
|
+
export declare class WebDavFolderService {
|
|
5
|
+
private readonly dependencies;
|
|
6
|
+
constructor(dependencies: {
|
|
7
|
+
driveFolderService: DriveFolderService;
|
|
8
|
+
configService: ConfigService;
|
|
9
|
+
});
|
|
10
|
+
getDriveFolderItemFromPath: (path: string) => Promise<DriveFolderItem | undefined>;
|
|
11
|
+
createFolder: ({ folderName, parentFolderUuid, }: {
|
|
12
|
+
folderName: string;
|
|
13
|
+
parentFolderUuid: string;
|
|
14
|
+
}) => Promise<DriveFolderItem>;
|
|
15
|
+
createParentPathOrThrow: (parentPath: string) => Promise<DriveFolderItem>;
|
|
16
|
+
private createFolderRecursively;
|
|
17
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WebDavFolderService = void 0;
|
|
4
|
+
const errors_utils_1 = require("../../utils/errors.utils");
|
|
5
|
+
const webdav_utils_1 = require("../../utils/webdav.utils");
|
|
6
|
+
const async_utils_1 = require("../../utils/async.utils");
|
|
7
|
+
const auth_service_1 = require("../../services/auth.service");
|
|
8
|
+
const drive_utils_1 = require("../../utils/drive.utils");
|
|
9
|
+
class WebDavFolderService {
|
|
10
|
+
dependencies;
|
|
11
|
+
constructor(dependencies) {
|
|
12
|
+
this.dependencies = dependencies;
|
|
13
|
+
}
|
|
14
|
+
getDriveFolderItemFromPath = async (path) => {
|
|
15
|
+
const resource = await webdav_utils_1.WebDavUtils.getRequestedResource(path, false);
|
|
16
|
+
return await webdav_utils_1.WebDavUtils.getDriveItemFromResource({
|
|
17
|
+
resource,
|
|
18
|
+
driveFolderService: this.dependencies.driveFolderService,
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
createFolder = async ({ folderName, parentFolderUuid, }) => {
|
|
22
|
+
const [createFolderPromise] = this.dependencies.driveFolderService.createFolder({
|
|
23
|
+
plainName: folderName,
|
|
24
|
+
parentFolderUuid: parentFolderUuid,
|
|
25
|
+
});
|
|
26
|
+
const newFolder = await createFolderPromise;
|
|
27
|
+
await async_utils_1.AsyncUtils.sleep(500);
|
|
28
|
+
return drive_utils_1.DriveUtils.createFolderResponseToItem(newFolder);
|
|
29
|
+
};
|
|
30
|
+
createParentPathOrThrow = async (parentPath) => {
|
|
31
|
+
const { createFullPath } = await this.dependencies.configService.readWebdavConfig();
|
|
32
|
+
if (!createFullPath) {
|
|
33
|
+
throw new errors_utils_1.ConflictError(`Parent folders not found on Internxt Drive at ${webdav_utils_1.WebDavUtils.decodeUrl(parentPath, false)}`);
|
|
34
|
+
}
|
|
35
|
+
const folders = parentPath.split('/').filter((f) => f.length > 0);
|
|
36
|
+
const { user } = await auth_service_1.AuthService.instance.getAuthDetails();
|
|
37
|
+
return await this.createFolderRecursively(folders, user.rootFolderId);
|
|
38
|
+
};
|
|
39
|
+
async createFolderRecursively(remainingFolders, parentFolderUuid, accumulatedPath = '') {
|
|
40
|
+
const [currentFolderName, ...rest] = remainingFolders;
|
|
41
|
+
const newPath = webdav_utils_1.WebDavUtils.joinURL(accumulatedPath, currentFolderName);
|
|
42
|
+
const folderPath = webdav_utils_1.WebDavUtils.normalizeFolderPath(newPath);
|
|
43
|
+
const folder = (await this.getDriveFolderItemFromPath(folderPath)) ??
|
|
44
|
+
(await this.createFolder({ folderName: currentFolderName, parentFolderUuid }));
|
|
45
|
+
if (rest.length === 0) {
|
|
46
|
+
return folder;
|
|
47
|
+
}
|
|
48
|
+
return await this.createFolderRecursively(rest, folder.uuid, newPath);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
exports.WebDavFolderService = WebDavFolderService;
|
|
@@ -31,6 +31,7 @@ const MOVE_handler_1 = require("./handlers/MOVE.handler");
|
|
|
31
31
|
const COPY_handler_1 = require("./handlers/COPY.handler");
|
|
32
32
|
const inxt_js_1 = require("@internxt/inxt-js");
|
|
33
33
|
const mkcol_middleware_1 = require("./middewares/mkcol.middleware");
|
|
34
|
+
const webdav_folder_service_1 = require("./services/webdav-folder.service");
|
|
34
35
|
class WebDavServer {
|
|
35
36
|
app;
|
|
36
37
|
configService;
|
|
@@ -82,6 +83,10 @@ class WebDavServer {
|
|
|
82
83
|
registerHandlers = async () => {
|
|
83
84
|
const serverListenPath = /(.*)/;
|
|
84
85
|
const networkFacade = await this.getNetworkFacade();
|
|
86
|
+
const webDavFolderService = new webdav_folder_service_1.WebDavFolderService({
|
|
87
|
+
driveFolderService: this.driveFolderService,
|
|
88
|
+
configService: this.configService,
|
|
89
|
+
});
|
|
85
90
|
this.app.head(serverListenPath, (0, express_async_handler_1.default)(new HEAD_handler_1.HEADRequestHandler({
|
|
86
91
|
driveFileService: this.driveFileService,
|
|
87
92
|
}).handle));
|
|
@@ -99,13 +104,14 @@ class WebDavServer {
|
|
|
99
104
|
}).handle));
|
|
100
105
|
this.app.put(serverListenPath, (0, express_async_handler_1.default)(new PUT_handler_1.PUTRequestHandler({
|
|
101
106
|
driveFileService: this.driveFileService,
|
|
102
|
-
|
|
107
|
+
webDavFolderService: webDavFolderService,
|
|
103
108
|
authService: this.authService,
|
|
104
109
|
trashService: this.trashService,
|
|
105
110
|
networkFacade: networkFacade,
|
|
106
111
|
}).handle));
|
|
107
112
|
this.app.mkcol(serverListenPath, (0, express_async_handler_1.default)(new MKCOL_handler_1.MKCOLRequestHandler({
|
|
108
113
|
driveFolderService: this.driveFolderService,
|
|
114
|
+
webDavFolderService: webDavFolderService,
|
|
109
115
|
}).handle));
|
|
110
116
|
this.app.delete(serverListenPath, (0, express_async_handler_1.default)(new DELETE_handler_1.DELETERequestHandler({
|
|
111
117
|
trashService: this.trashService,
|
|
@@ -116,6 +122,7 @@ class WebDavServer {
|
|
|
116
122
|
this.app.move(serverListenPath, (0, express_async_handler_1.default)(new MOVE_handler_1.MOVERequestHandler({
|
|
117
123
|
driveFolderService: this.driveFolderService,
|
|
118
124
|
driveFileService: this.driveFileService,
|
|
125
|
+
webDavFolderService,
|
|
119
126
|
}).handle));
|
|
120
127
|
this.app.copy(serverListenPath, (0, express_async_handler_1.default)(new COPY_handler_1.COPYRequestHandler().handle));
|
|
121
128
|
};
|
package/oclif.manifest.json
CHANGED
|
@@ -1196,6 +1196,14 @@
|
|
|
1196
1196
|
"hasDynamicHelp": false,
|
|
1197
1197
|
"multiple": false,
|
|
1198
1198
|
"type": "option"
|
|
1199
|
+
},
|
|
1200
|
+
"createFullPath": {
|
|
1201
|
+
"char": "c",
|
|
1202
|
+
"description": "Auto-create missing parent directories during file uploads.",
|
|
1203
|
+
"name": "createFullPath",
|
|
1204
|
+
"required": false,
|
|
1205
|
+
"allowNo": true,
|
|
1206
|
+
"type": "boolean"
|
|
1199
1207
|
}
|
|
1200
1208
|
},
|
|
1201
1209
|
"hasDynamicHelp": false,
|
|
@@ -1290,5 +1298,5 @@
|
|
|
1290
1298
|
]
|
|
1291
1299
|
}
|
|
1292
1300
|
},
|
|
1293
|
-
"version": "1.5.
|
|
1301
|
+
"version": "1.5.8"
|
|
1294
1302
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"author": "Internxt <hello@internxt.com>",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.8",
|
|
4
4
|
"description": "Internxt CLI to manage your encrypted storage",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"build": "yarn clean && tsc",
|
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
"@internxt/inxt-js": "2.2.9",
|
|
41
41
|
"@internxt/lib": "1.3.1",
|
|
42
42
|
"@internxt/sdk": "1.11.12",
|
|
43
|
-
"@oclif/core": "4.5.
|
|
44
|
-
"@oclif/plugin-autocomplete": "3.2.
|
|
43
|
+
"@oclif/core": "4.5.5",
|
|
44
|
+
"@oclif/plugin-autocomplete": "3.2.36",
|
|
45
45
|
"axios": "1.12.2",
|
|
46
46
|
"bip39": "3.1.0",
|
|
47
47
|
"body-parser": "2.2.0",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"dotenv": "17.2.3",
|
|
51
51
|
"express": "5.1.0",
|
|
52
52
|
"express-async-handler": "1.2.0",
|
|
53
|
-
"fast-xml-parser": "5.
|
|
53
|
+
"fast-xml-parser": "5.3.0",
|
|
54
54
|
"mime-types": "3.0.1",
|
|
55
55
|
"openpgp": "6.2.2",
|
|
56
56
|
"otpauth": "9.4.1",
|
|
@@ -67,15 +67,15 @@
|
|
|
67
67
|
"@types/cli-progress": "3.11.6",
|
|
68
68
|
"@types/express": "5.0.3",
|
|
69
69
|
"@types/mime-types": "3.0.1",
|
|
70
|
-
"@types/node": "22.18.
|
|
70
|
+
"@types/node": "22.18.9",
|
|
71
71
|
"@types/range-parser": "1.2.7",
|
|
72
72
|
"@vitest/coverage-istanbul": "3.2.4",
|
|
73
73
|
"@vitest/spy": "3.2.4",
|
|
74
|
-
"eslint": "9.
|
|
74
|
+
"eslint": "9.37.0",
|
|
75
75
|
"husky": "9.1.7",
|
|
76
|
-
"lint-staged": "16.2.
|
|
76
|
+
"lint-staged": "16.2.4",
|
|
77
77
|
"nodemon": "3.1.10",
|
|
78
|
-
"oclif": "4.22.
|
|
78
|
+
"oclif": "4.22.32",
|
|
79
79
|
"prettier": "3.6.2",
|
|
80
80
|
"rimraf": "6.0.1",
|
|
81
81
|
"ts-node": "10.9.2",
|