@internxt/cli 1.5.7 → 1.6.0
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 +136 -100
- 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-legacy.d.ts +24 -0
- package/dist/commands/login-legacy.js +175 -0
- package/dist/commands/login.d.ts +3 -9
- package/dist/commands/login.js +18 -133
- 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 +1 -2
- package/dist/commands/trash-folder.js +1 -2
- 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.d.ts +2 -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 +1 -2
- package/dist/hooks/prerun/auth_check.js +2 -2
- package/dist/services/auth.service.d.ts +1 -2
- package/dist/services/auth.service.js +11 -26
- package/dist/services/config.service.d.ts +1 -0
- package/dist/services/config.service.js +3 -0
- package/dist/services/crypto.service.js +1 -1
- package/dist/services/database/drive-file/drive-file.domain.js +1 -0
- package/dist/services/database/drive-folder/drive-folder.domain.js +1 -0
- package/dist/services/drive/drive-file.service.js +1 -0
- package/dist/services/universal-link.service.d.ts +10 -0
- package/dist/services/universal-link.service.js +85 -0
- package/dist/types/command.types.d.ts +1 -2
- package/dist/types/drive.types.d.ts +3 -0
- package/dist/types/webdav.types.d.ts +0 -1
- 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 +17 -0
- package/dist/utils/errors.utils.d.ts +2 -1
- package/dist/utils/errors.utils.js +10 -4
- package/dist/utils/webdav.utils.d.ts +20 -6
- package/dist/utils/webdav.utils.js +52 -33
- package/dist/webdav/handlers/DELETE.handler.js +5 -5
- package/dist/webdav/handlers/GET.handler.js +6 -9
- package/dist/webdav/handlers/HEAD.handler.js +5 -10
- package/dist/webdav/handlers/MKCOL.handler.d.ts +2 -0
- package/dist/webdav/handlers/MKCOL.handler.js +10 -20
- package/dist/webdav/handlers/MOVE.handler.d.ts +2 -0
- package/dist/webdav/handlers/MOVE.handler.js +22 -27
- package/dist/webdav/handlers/OPTIONS.handler.js +3 -3
- package/dist/webdav/handlers/PROPFIND.handler.js +7 -31
- package/dist/webdav/handlers/PUT.handler.d.ts +3 -1
- package/dist/webdav/handlers/PUT.handler.js +20 -23
- 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 +52 -0
- package/dist/webdav/webdav-server.js +8 -0
- package/oclif.manifest.json +68 -3
- package/package.json +23 -22
|
@@ -11,8 +11,8 @@ class DELETERequestHandler {
|
|
|
11
11
|
}
|
|
12
12
|
handle = async (req, res) => {
|
|
13
13
|
const { driveFileService, driveFolderService, trashService } = this.dependencies;
|
|
14
|
-
const resource = await webdav_utils_1.WebDavUtils.getRequestedResource(req);
|
|
15
|
-
logger_utils_1.webdavLogger.info(`[DELETE] Request received for
|
|
14
|
+
const resource = await webdav_utils_1.WebDavUtils.getRequestedResource(req.url);
|
|
15
|
+
logger_utils_1.webdavLogger.info(`[DELETE] Request received for item at ${resource.url}`);
|
|
16
16
|
const driveItem = await webdav_utils_1.WebDavUtils.getDriveItemFromResource({
|
|
17
17
|
resource,
|
|
18
18
|
driveFolderService,
|
|
@@ -21,12 +21,12 @@ class DELETERequestHandler {
|
|
|
21
21
|
if (!driveItem) {
|
|
22
22
|
throw new errors_utils_1.NotFoundError(`Resource not found on Internxt Drive at ${resource.url}`);
|
|
23
23
|
}
|
|
24
|
-
logger_utils_1.webdavLogger.info(`[DELETE] [${driveItem.uuid}] Trashing ${
|
|
24
|
+
logger_utils_1.webdavLogger.info(`[DELETE] [${driveItem.uuid}] Trashing ${driveItem.itemType}`);
|
|
25
25
|
await trashService.trashItems({
|
|
26
|
-
items: [{ type:
|
|
26
|
+
items: [{ type: driveItem.itemType, uuid: driveItem.uuid }],
|
|
27
27
|
});
|
|
28
28
|
res.status(204).send();
|
|
29
|
-
const type =
|
|
29
|
+
const type = driveItem.itemType.charAt(0).toUpperCase() + driveItem.itemType.substring(1);
|
|
30
30
|
logger_utils_1.webdavLogger.info(`[DELETE] [${driveItem.uuid}] ${type} trashed successfully`);
|
|
31
31
|
};
|
|
32
32
|
}
|
|
@@ -12,20 +12,17 @@ class GETRequestHandler {
|
|
|
12
12
|
}
|
|
13
13
|
handle = async (req, res) => {
|
|
14
14
|
const { driveFileService, authService, networkFacade } = this.dependencies;
|
|
15
|
-
const resource = await webdav_utils_1.WebDavUtils.getRequestedResource(req);
|
|
15
|
+
const resource = await webdav_utils_1.WebDavUtils.getRequestedResource(req.url);
|
|
16
16
|
if (resource.name.startsWith('._'))
|
|
17
17
|
throw new errors_utils_1.NotFoundError('File not found');
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const driveItem = await webdav_utils_1.WebDavUtils.getDriveItemFromResource({
|
|
22
|
-
resource,
|
|
18
|
+
logger_utils_1.webdavLogger.info(`[GET] Request received item at ${resource.url}`);
|
|
19
|
+
const driveFile = await webdav_utils_1.WebDavUtils.getDriveFileFromResource({
|
|
20
|
+
url: resource.url,
|
|
23
21
|
driveFileService,
|
|
24
22
|
});
|
|
25
|
-
if (!
|
|
26
|
-
throw new errors_utils_1.NotFoundError(`Resource not found on Internxt Drive at ${resource.url}
|
|
23
|
+
if (!driveFile) {
|
|
24
|
+
throw new errors_utils_1.NotFoundError(`Resource not found on Internxt Drive at ${resource.url}, if trying to access a folder use PROPFIND instead.`);
|
|
27
25
|
}
|
|
28
|
-
const driveFile = driveItem;
|
|
29
26
|
logger_utils_1.webdavLogger.info(`[GET] [${driveFile.uuid}] Found Drive File`);
|
|
30
27
|
const { user } = await authService.getAuthDetails();
|
|
31
28
|
logger_utils_1.webdavLogger.info(`[GET] [${driveFile.uuid}] Network ready for download`);
|
|
@@ -12,21 +12,16 @@ class HEADRequestHandler {
|
|
|
12
12
|
}
|
|
13
13
|
handle = async (req, res) => {
|
|
14
14
|
const { driveFileService } = this.dependencies;
|
|
15
|
-
const resource = await webdav_utils_1.WebDavUtils.getRequestedResource(req);
|
|
16
|
-
|
|
17
|
-
res.status(200).send();
|
|
18
|
-
return;
|
|
19
|
-
}
|
|
20
|
-
logger_utils_1.webdavLogger.info(`[HEAD] Request received for ${resource.type} at ${resource.url}`);
|
|
15
|
+
const resource = await webdav_utils_1.WebDavUtils.getRequestedResource(req.url);
|
|
16
|
+
logger_utils_1.webdavLogger.info(`[HEAD] Request received for file at ${resource.url}`);
|
|
21
17
|
try {
|
|
22
|
-
const
|
|
23
|
-
resource,
|
|
18
|
+
const driveFile = await webdav_utils_1.WebDavUtils.getDriveFileFromResource({
|
|
19
|
+
url: resource.url,
|
|
24
20
|
driveFileService,
|
|
25
21
|
});
|
|
26
|
-
if (!
|
|
22
|
+
if (!driveFile) {
|
|
27
23
|
throw new errors_utils_1.NotFoundError(`Resource not found on Internxt Drive at ${resource.url}`);
|
|
28
24
|
}
|
|
29
|
-
const driveFile = driveItem;
|
|
30
25
|
logger_utils_1.webdavLogger.info(`[HEAD] [${driveFile.uuid}] Found Drive File`);
|
|
31
26
|
const range = req.headers['range'];
|
|
32
27
|
const rangeOptions = network_utils_1.NetworkUtils.parseRangeHeader({
|
|
@@ -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,20 +11,13 @@ class MKCOLRequestHandler {
|
|
|
12
11
|
this.dependencies = dependencies;
|
|
13
12
|
}
|
|
14
13
|
handle = async (req, res) => {
|
|
15
|
-
const { driveFolderService } = this.dependencies;
|
|
16
|
-
const resource = await webdav_utils_1.WebDavUtils.getRequestedResource(req);
|
|
17
|
-
logger_utils_1.webdavLogger.info(`[MKCOL] Request received for
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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;
|
|
27
|
-
const driveFolderItem = await webdav_utils_1.WebDavUtils.getDriveItemFromResource({
|
|
28
|
-
resource,
|
|
14
|
+
const { driveFolderService, webDavFolderService } = this.dependencies;
|
|
15
|
+
const resource = await webdav_utils_1.WebDavUtils.getRequestedResource(req.url);
|
|
16
|
+
logger_utils_1.webdavLogger.info(`[MKCOL] Request received for folder at ${resource.url}`);
|
|
17
|
+
const parentDriveFolderItem = (await webDavFolderService.getDriveFolderItemFromPath(resource.parentPath)) ??
|
|
18
|
+
(await webDavFolderService.createParentPathOrThrow(resource.parentPath));
|
|
19
|
+
const driveFolderItem = await webdav_utils_1.WebDavUtils.getDriveFolderFromResource({
|
|
20
|
+
url: resource.url,
|
|
29
21
|
driveFolderService,
|
|
30
22
|
});
|
|
31
23
|
const folderAlreadyExists = !!driveFolderItem;
|
|
@@ -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,9 +10,9 @@ class MOVERequestHandler {
|
|
|
10
10
|
this.dependencies = dependencies;
|
|
11
11
|
}
|
|
12
12
|
handle = async (req, res) => {
|
|
13
|
-
const { driveFolderService, driveFileService } = this.dependencies;
|
|
14
|
-
const resource = await webdav_utils_1.WebDavUtils.getRequestedResource(req);
|
|
15
|
-
logger_utils_1.webdavLogger.info(`[MOVE] Request received for
|
|
13
|
+
const { driveFolderService, driveFileService, webDavFolderService } = this.dependencies;
|
|
14
|
+
const resource = await webdav_utils_1.WebDavUtils.getRequestedResource(req.url);
|
|
15
|
+
logger_utils_1.webdavLogger.info(`[MOVE] Request received for item at ${resource.url}`);
|
|
16
16
|
const destinationUrl = req.header('destination');
|
|
17
17
|
if (!destinationUrl) {
|
|
18
18
|
throw new errors_utils_1.NotFoundError('[MOVE] Destination folder not received');
|
|
@@ -28,50 +28,45 @@ class MOVERequestHandler {
|
|
|
28
28
|
if (!originalDriveItem) {
|
|
29
29
|
throw new errors_utils_1.NotFoundError(`Resource not found on Internxt Drive at ${resource.url}`);
|
|
30
30
|
}
|
|
31
|
-
const newName = destinationResource.name;
|
|
32
31
|
if (destinationResource.path.dir === resource.path.dir) {
|
|
33
|
-
logger_utils_1.webdavLogger.info(`[MOVE] Renaming ${
|
|
34
|
-
|
|
32
|
+
logger_utils_1.webdavLogger.info(`[MOVE] Renaming ${originalDriveItem.itemType}
|
|
33
|
+
with UUID ${originalDriveItem.uuid} to ${destinationResource.name}`);
|
|
34
|
+
if (originalDriveItem.itemType === 'folder') {
|
|
35
35
|
const folder = originalDriveItem;
|
|
36
36
|
await driveFolderService.renameFolder({
|
|
37
37
|
folderUuid: folder.uuid,
|
|
38
|
-
name:
|
|
38
|
+
name: destinationResource.name,
|
|
39
39
|
});
|
|
40
40
|
}
|
|
41
|
-
else if (
|
|
42
|
-
const newType = destinationResource.path.ext.replace('.', '');
|
|
41
|
+
else if (originalDriveItem.itemType === 'file') {
|
|
43
42
|
const file = originalDriveItem;
|
|
43
|
+
const plainName = destinationResource.path.name;
|
|
44
|
+
const fileType = destinationResource.path.ext.replace('.', '');
|
|
44
45
|
await driveFileService.renameFile(file.uuid, {
|
|
45
|
-
plainName:
|
|
46
|
-
type:
|
|
46
|
+
plainName: plainName,
|
|
47
|
+
type: fileType,
|
|
47
48
|
});
|
|
48
49
|
}
|
|
49
50
|
}
|
|
50
51
|
else {
|
|
51
|
-
logger_utils_1.webdavLogger.info(`[MOVE] Moving ${
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
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;
|
|
61
|
-
if (resource.type === 'folder') {
|
|
52
|
+
logger_utils_1.webdavLogger.info(`[MOVE] Moving ${originalDriveItem.itemType} with UUID ${originalDriveItem.uuid} to ${destinationPath}`);
|
|
53
|
+
const destinationFolderItem = (await webDavFolderService.getDriveFolderItemFromPath(destinationResource.parentPath)) ??
|
|
54
|
+
(await webDavFolderService.createParentPathOrThrow(destinationResource.parentPath));
|
|
55
|
+
if (originalDriveItem.itemType === 'folder') {
|
|
62
56
|
const folder = originalDriveItem;
|
|
63
57
|
await driveFolderService.moveFolder(folder.uuid, {
|
|
64
58
|
destinationFolder: destinationFolderItem.uuid,
|
|
65
|
-
name:
|
|
59
|
+
name: destinationResource.name,
|
|
66
60
|
});
|
|
67
61
|
}
|
|
68
|
-
else if (
|
|
62
|
+
else if (originalDriveItem.itemType === 'file') {
|
|
69
63
|
const file = originalDriveItem;
|
|
70
|
-
const
|
|
64
|
+
const plainName = destinationResource.path.name;
|
|
65
|
+
const fileType = destinationResource.path.ext.replace('.', '');
|
|
71
66
|
await driveFileService.moveFile(file.uuid, {
|
|
72
67
|
destinationFolder: destinationFolderItem.uuid,
|
|
73
|
-
name:
|
|
74
|
-
type:
|
|
68
|
+
name: plainName,
|
|
69
|
+
type: fileType,
|
|
75
70
|
});
|
|
76
71
|
}
|
|
77
72
|
}
|
|
@@ -5,8 +5,8 @@ const webdav_utils_1 = require("../../utils/webdav.utils");
|
|
|
5
5
|
const logger_utils_1 = require("../../utils/logger.utils");
|
|
6
6
|
class OPTIONSRequestHandler {
|
|
7
7
|
handle = async (req, res) => {
|
|
8
|
-
const resource = await webdav_utils_1.WebDavUtils.getRequestedResource(req);
|
|
9
|
-
logger_utils_1.webdavLogger.info(`[OPTIONS] Request received for
|
|
8
|
+
const resource = await webdav_utils_1.WebDavUtils.getRequestedResource(req.url);
|
|
9
|
+
logger_utils_1.webdavLogger.info(`[OPTIONS] Request received for item at ${resource.url}`);
|
|
10
10
|
if (resource.url === '/' || resource.url === '') {
|
|
11
11
|
const allowedMethods = 'DELETE, GET, HEAD, MKCOL, MOVE, OPTIONS, PROPFIND, PUT';
|
|
12
12
|
logger_utils_1.webdavLogger.info(`[OPTIONS] Returning Allowed Options: ${allowedMethods}`);
|
|
@@ -14,7 +14,7 @@ class OPTIONSRequestHandler {
|
|
|
14
14
|
res.header('DAV', '1, 2, ordered-collections');
|
|
15
15
|
res.status(200).send();
|
|
16
16
|
}
|
|
17
|
-
else if (resource.
|
|
17
|
+
else if (resource.url.endsWith('/')) {
|
|
18
18
|
const allowedMethods = 'DELETE, HEAD, MKCOL, MOVE, OPTIONS, PROPFIND';
|
|
19
19
|
logger_utils_1.webdavLogger.info(`[OPTIONS] Returning Allowed Options: ${allowedMethods}`);
|
|
20
20
|
res.header('Allow', allowedMethods);
|
|
@@ -18,29 +18,18 @@ class PROPFINDRequestHandler {
|
|
|
18
18
|
}
|
|
19
19
|
handle = async (req, res) => {
|
|
20
20
|
const { driveFolderService, driveFileService } = this.dependencies;
|
|
21
|
-
const resource = await webdav_utils_1.WebDavUtils.getRequestedResource(req);
|
|
22
|
-
logger_utils_1.webdavLogger.info(`[PROPFIND] Request received for
|
|
21
|
+
const resource = await webdav_utils_1.WebDavUtils.getRequestedResource(req.url);
|
|
22
|
+
logger_utils_1.webdavLogger.info(`[PROPFIND] Request received for item at ${resource.url}`);
|
|
23
23
|
const driveItem = await webdav_utils_1.WebDavUtils.getDriveItemFromResource({
|
|
24
24
|
resource,
|
|
25
25
|
driveFolderService,
|
|
26
26
|
driveFileService,
|
|
27
27
|
});
|
|
28
28
|
if (!driveItem) {
|
|
29
|
-
res.status(
|
|
30
|
-
[xml_utils_1.XMLUtils.addDefaultNamespace('response')]: {
|
|
31
|
-
[xml_utils_1.XMLUtils.addDefaultNamespace('href')]: xml_utils_1.XMLUtils.encodeWebDavUri(resource.url),
|
|
32
|
-
[xml_utils_1.XMLUtils.addDefaultNamespace('propstat')]: {
|
|
33
|
-
[xml_utils_1.XMLUtils.addDefaultNamespace('status')]: 'HTTP/1.1 404 Not Found',
|
|
34
|
-
[xml_utils_1.XMLUtils.addDefaultNamespace('prop')]: {},
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
}, {
|
|
38
|
-
ignoreAttributes: false,
|
|
39
|
-
suppressEmptyNode: true,
|
|
40
|
-
}));
|
|
29
|
+
res.status(404).send();
|
|
41
30
|
return;
|
|
42
31
|
}
|
|
43
|
-
switch (
|
|
32
|
+
switch (driveItem.itemType) {
|
|
44
33
|
case 'file': {
|
|
45
34
|
const fileMetaXML = await this.getFileMetaXML(resource, driveItem);
|
|
46
35
|
res.status(207).send(fileMetaXML);
|
|
@@ -55,22 +44,7 @@ class PROPFINDRequestHandler {
|
|
|
55
44
|
}
|
|
56
45
|
};
|
|
57
46
|
getFileMetaXML = async (resource, driveFileItem) => {
|
|
58
|
-
const driveFile = this.driveFileItemToXMLNode(
|
|
59
|
-
name: driveFileItem.name,
|
|
60
|
-
type: driveFileItem.type,
|
|
61
|
-
bucket: driveFileItem.bucket,
|
|
62
|
-
id: driveFileItem.id,
|
|
63
|
-
uuid: driveFileItem.uuid,
|
|
64
|
-
fileId: driveFileItem.fileId,
|
|
65
|
-
size: driveFileItem.size,
|
|
66
|
-
createdAt: driveFileItem.createdAt,
|
|
67
|
-
updatedAt: driveFileItem.updatedAt,
|
|
68
|
-
status: driveFileItem.status,
|
|
69
|
-
folderId: driveFileItem.folderId,
|
|
70
|
-
folderUuid: driveFileItem.folderUuid,
|
|
71
|
-
creationTime: driveFileItem.creationTime,
|
|
72
|
-
modificationTime: driveFileItem.modificationTime,
|
|
73
|
-
}, resource.url);
|
|
47
|
+
const driveFile = this.driveFileItemToXMLNode(driveFileItem, resource.url);
|
|
74
48
|
const xml = xml_utils_1.XMLUtils.toWebDavXML([driveFile], {
|
|
75
49
|
arrayNodeName: xml_utils_1.XMLUtils.addDefaultNamespace('response'),
|
|
76
50
|
});
|
|
@@ -114,6 +88,7 @@ class PROPFINDRequestHandler {
|
|
|
114
88
|
const foldersXML = folderContent.folders.map((folder) => {
|
|
115
89
|
const folderRelativePath = webdav_utils_1.WebDavUtils.joinURL(relativePath, folder.plainName, '/');
|
|
116
90
|
return this.driveFolderItemToXMLNode({
|
|
91
|
+
itemType: 'folder',
|
|
117
92
|
name: folder.plainName,
|
|
118
93
|
bucket: folder.bucket,
|
|
119
94
|
status: folder.deleted || folder.removed ? 'TRASHED' : 'EXISTS',
|
|
@@ -129,6 +104,7 @@ class PROPFINDRequestHandler {
|
|
|
129
104
|
const filesXML = folderContent.files.map((file) => {
|
|
130
105
|
const fileRelativePath = webdav_utils_1.WebDavUtils.joinURL(relativePath, file.type ? `${file.plainName}.${file.type}` : file.plainName);
|
|
131
106
|
return this.driveFileItemToXMLNode({
|
|
107
|
+
itemType: 'file',
|
|
132
108
|
name: file.plainName,
|
|
133
109
|
bucket: file.bucket,
|
|
134
110
|
id: file.id,
|
|
@@ -3,13 +3,15 @@ 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
|
+
import { DriveFolderService } from '../../services/drive/drive-folder.service';
|
|
8
9
|
export declare class PUTRequestHandler implements WebDavMethodHandler {
|
|
9
10
|
private readonly dependencies;
|
|
10
11
|
constructor(dependencies: {
|
|
11
12
|
driveFileService: DriveFileService;
|
|
12
13
|
driveFolderService: DriveFolderService;
|
|
14
|
+
webDavFolderService: WebDavFolderService;
|
|
13
15
|
trashService: TrashService;
|
|
14
16
|
authService: AuthService;
|
|
15
17
|
networkFacade: NetworkFacade;
|
|
@@ -10,46 +10,41 @@ 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');
|
|
23
23
|
}
|
|
24
|
-
const resource = await webdav_utils_1.WebDavUtils.getRequestedResource(req);
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const parentResource = await webdav_utils_1.WebDavUtils.getRequestedResource(resource.parentPath, false);
|
|
30
|
-
const parentDriveFolderItem = await webdav_utils_1.WebDavUtils.getDriveItemFromResource({
|
|
31
|
-
resource: parentResource,
|
|
32
|
-
driveFolderService,
|
|
24
|
+
const resource = await webdav_utils_1.WebDavUtils.getRequestedResource(req.url);
|
|
25
|
+
const driveFileItem = await webdav_utils_1.WebDavUtils.getDriveItemFromResource({
|
|
26
|
+
resource: resource,
|
|
27
|
+
driveFileService: this.dependencies.driveFileService,
|
|
28
|
+
driveFolderService: this.dependencies.driveFolderService,
|
|
33
29
|
});
|
|
34
|
-
if (
|
|
35
|
-
throw new errors_utils_1.
|
|
30
|
+
if (driveFileItem?.itemType === 'folder') {
|
|
31
|
+
throw new errors_utils_1.NotFoundError('Folders cannot be created with PUT. Use MKCOL instead.');
|
|
36
32
|
}
|
|
37
|
-
|
|
33
|
+
logger_utils_1.webdavLogger.info(`[PUT] Request received for file at ${resource.url}`);
|
|
34
|
+
logger_utils_1.webdavLogger.info(`[PUT] Uploading '${resource.name}' to '${resource.parentPath}'`);
|
|
35
|
+
const parentDriveFolderItem = (await this.dependencies.webDavFolderService.getDriveFolderItemFromPath(resource.parentPath)) ??
|
|
36
|
+
(await this.dependencies.webDavFolderService.createParentPathOrThrow(resource.parentPath));
|
|
38
37
|
try {
|
|
39
|
-
const driveFileItem = (await webdav_utils_1.WebDavUtils.getDriveItemFromResource({
|
|
40
|
-
resource: resource,
|
|
41
|
-
driveFileService,
|
|
42
|
-
}));
|
|
43
38
|
if (driveFileItem && driveFileItem.status === 'EXISTS') {
|
|
44
39
|
logger_utils_1.webdavLogger.info(`[PUT] File '${resource.name}' already exists in '${resource.path.dir}', trashing it...`);
|
|
45
|
-
await trashService.trashItems({
|
|
46
|
-
items: [{ type:
|
|
40
|
+
await this.dependencies.trashService.trashItems({
|
|
41
|
+
items: [{ type: driveFileItem.itemType, uuid: driveFileItem.uuid }],
|
|
47
42
|
});
|
|
48
43
|
}
|
|
49
44
|
}
|
|
50
45
|
catch {
|
|
51
46
|
}
|
|
52
|
-
const { user } = await authService.getAuthDetails();
|
|
47
|
+
const { user } = await this.dependencies.authService.getAuthDetails();
|
|
53
48
|
const fileType = resource.path.ext.replace('.', '');
|
|
54
49
|
const timer = cli_utils_1.CLIUtils.timer();
|
|
55
50
|
let bufferStream;
|
|
@@ -66,7 +61,7 @@ class PUTRequestHandler {
|
|
|
66
61
|
}
|
|
67
62
|
};
|
|
68
63
|
const fileId = await new Promise((resolve, reject) => {
|
|
69
|
-
const state = networkFacade.uploadFile(fileStream, contentLength, user.bucket, (err, res) => {
|
|
64
|
+
const state = this.dependencies.networkFacade.uploadFile(fileStream, contentLength, user.bucket, (err, res) => {
|
|
70
65
|
if (err) {
|
|
71
66
|
aborted = true;
|
|
72
67
|
return reject(err);
|
|
@@ -87,7 +82,7 @@ class PUTRequestHandler {
|
|
|
87
82
|
plainName: resource.path.name,
|
|
88
83
|
type: fileType,
|
|
89
84
|
size: contentLength,
|
|
90
|
-
folderUuid:
|
|
85
|
+
folderUuid: parentDriveFolderItem.uuid,
|
|
91
86
|
fileId: fileId,
|
|
92
87
|
bucket: user.bucket,
|
|
93
88
|
encryptVersion: types_1.EncryptionVersion.Aes03,
|
|
@@ -96,7 +91,7 @@ class PUTRequestHandler {
|
|
|
96
91
|
if (isThumbnailable && bufferStream) {
|
|
97
92
|
const thumbnailBuffer = bufferStream.getBuffer();
|
|
98
93
|
if (thumbnailBuffer) {
|
|
99
|
-
await thumbnail_service_1.ThumbnailService.instance.uploadThumbnail(thumbnailBuffer, fileType, user.bucket, file.uuid, networkFacade);
|
|
94
|
+
await thumbnail_service_1.ThumbnailService.instance.uploadThumbnail(thumbnailBuffer, fileType, user.bucket, file.uuid, this.dependencies.networkFacade);
|
|
100
95
|
}
|
|
101
96
|
}
|
|
102
97
|
}
|
|
@@ -105,6 +100,8 @@ class PUTRequestHandler {
|
|
|
105
100
|
}
|
|
106
101
|
const uploadTime = timer.stop();
|
|
107
102
|
logger_utils_1.webdavLogger.info(`[PUT] ✅ File uploaded in ${uploadTime}ms to Internxt Drive`);
|
|
103
|
+
await async_utils_1.AsyncUtils.sleep(500);
|
|
104
|
+
logger_utils_1.webdavLogger.info(`[PUT] [RESPONSE-201] ${resource.url} - Returning 201 Created after ${uploadTime}ms (+ 500ms propagation delay)`);
|
|
108
105
|
res.status(201).send();
|
|
109
106
|
};
|
|
110
107
|
}
|
|
@@ -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,52 @@
|
|
|
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 { url } = await webdav_utils_1.WebDavUtils.getRequestedResource(path, false);
|
|
16
|
+
return await webdav_utils_1.WebDavUtils.getDriveFolderFromResource({
|
|
17
|
+
url,
|
|
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
|
+
createFullPath flag is set to: ${createFullPath}`);
|
|
35
|
+
}
|
|
36
|
+
const folders = parentPath.split('/').filter((f) => f.length > 0);
|
|
37
|
+
const { user } = await auth_service_1.AuthService.instance.getAuthDetails();
|
|
38
|
+
return await this.createFolderRecursively(folders, user.rootFolderId);
|
|
39
|
+
};
|
|
40
|
+
async createFolderRecursively(remainingFolders, parentFolderUuid, accumulatedPath = '') {
|
|
41
|
+
const [currentFolderName, ...rest] = remainingFolders;
|
|
42
|
+
const newPath = webdav_utils_1.WebDavUtils.joinURL(accumulatedPath, currentFolderName);
|
|
43
|
+
const folderPath = webdav_utils_1.WebDavUtils.normalizeFolderPath(newPath);
|
|
44
|
+
const folder = (await this.getDriveFolderItemFromPath(folderPath)) ??
|
|
45
|
+
(await this.createFolder({ folderName: currentFolderName, parentFolderUuid }));
|
|
46
|
+
if (rest.length === 0) {
|
|
47
|
+
return folder;
|
|
48
|
+
}
|
|
49
|
+
return await this.createFolderRecursively(rest, folder.uuid, newPath);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
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));
|
|
@@ -100,12 +105,14 @@ class WebDavServer {
|
|
|
100
105
|
this.app.put(serverListenPath, (0, express_async_handler_1.default)(new PUT_handler_1.PUTRequestHandler({
|
|
101
106
|
driveFileService: this.driveFileService,
|
|
102
107
|
driveFolderService: this.driveFolderService,
|
|
108
|
+
webDavFolderService: webDavFolderService,
|
|
103
109
|
authService: this.authService,
|
|
104
110
|
trashService: this.trashService,
|
|
105
111
|
networkFacade: networkFacade,
|
|
106
112
|
}).handle));
|
|
107
113
|
this.app.mkcol(serverListenPath, (0, express_async_handler_1.default)(new MKCOL_handler_1.MKCOLRequestHandler({
|
|
108
114
|
driveFolderService: this.driveFolderService,
|
|
115
|
+
webDavFolderService: webDavFolderService,
|
|
109
116
|
}).handle));
|
|
110
117
|
this.app.delete(serverListenPath, (0, express_async_handler_1.default)(new DELETE_handler_1.DELETERequestHandler({
|
|
111
118
|
trashService: this.trashService,
|
|
@@ -116,6 +123,7 @@ class WebDavServer {
|
|
|
116
123
|
this.app.move(serverListenPath, (0, express_async_handler_1.default)(new MOVE_handler_1.MOVERequestHandler({
|
|
117
124
|
driveFolderService: this.driveFolderService,
|
|
118
125
|
driveFileService: this.driveFileService,
|
|
126
|
+
webDavFolderService,
|
|
119
127
|
}).handle));
|
|
120
128
|
this.app.copy(serverListenPath, (0, express_async_handler_1.default)(new COPY_handler_1.COPYRequestHandler().handle));
|
|
121
129
|
};
|