@internxt/cli 1.5.8 → 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 +124 -94
- 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 -132
- package/dist/commands/trash-file.js +1 -1
- package/dist/commands/trash-folder.js +1 -1
- package/dist/commands/upload-file.d.ts +2 -1
- package/dist/commands/whoami.js +1 -1
- package/dist/hooks/prerun/auth_check.js +2 -1
- package/dist/services/auth.service.d.ts +1 -2
- package/dist/services/auth.service.js +11 -26
- 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 +0 -2
- package/dist/types/drive.types.d.ts +2 -0
- package/dist/types/webdav.types.d.ts +0 -1
- package/dist/utils/drive.utils.js +3 -0
- package/dist/utils/logger.utils.js +10 -0
- package/dist/utils/webdav.utils.d.ts +12 -10
- package/dist/utils/webdav.utils.js +39 -29
- 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.js +4 -4
- package/dist/webdav/handlers/MOVE.handler.js +19 -17
- 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 +2 -0
- package/dist/webdav/handlers/PUT.handler.js +10 -8
- package/dist/webdav/services/webdav-folder.service.js +5 -4
- package/dist/webdav/webdav-server.js +1 -0
- package/oclif.manifest.json +60 -3
- package/package.json +23 -22
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { DriveFolderData, FileMeta } from '@internxt/sdk/dist/drive/storage/types';
|
|
2
2
|
export type DriveFileItem = Omit<FileMeta, 'plainName' | 'userId' | 'encryptVersion' | 'size' | 'createdAt' | 'updatedAt' | 'creationTime' | 'modificationTime' | 'type'> & {
|
|
3
|
+
itemType: 'file';
|
|
3
4
|
size: number;
|
|
4
5
|
createdAt: Date;
|
|
5
6
|
updatedAt: Date;
|
|
@@ -8,6 +9,7 @@ export type DriveFileItem = Omit<FileMeta, 'plainName' | 'userId' | 'encryptVers
|
|
|
8
9
|
type?: string | null;
|
|
9
10
|
};
|
|
10
11
|
export type DriveFolderItem = Pick<DriveFolderData, 'name' | 'bucket' | 'id' | 'parentId'> & {
|
|
12
|
+
itemType: 'folder';
|
|
11
13
|
encryptedName: string;
|
|
12
14
|
uuid: string;
|
|
13
15
|
createdAt: Date;
|
|
@@ -4,6 +4,7 @@ exports.DriveUtils = void 0;
|
|
|
4
4
|
class DriveUtils {
|
|
5
5
|
static driveFileMetaToItem(fileMeta) {
|
|
6
6
|
return {
|
|
7
|
+
itemType: 'file',
|
|
7
8
|
uuid: fileMeta.uuid ?? '',
|
|
8
9
|
status: fileMeta.status,
|
|
9
10
|
folderId: fileMeta.folderId,
|
|
@@ -22,6 +23,7 @@ class DriveUtils {
|
|
|
22
23
|
}
|
|
23
24
|
static driveFolderMetaToItem(folderMeta) {
|
|
24
25
|
return {
|
|
26
|
+
itemType: 'folder',
|
|
25
27
|
uuid: folderMeta.uuid,
|
|
26
28
|
id: folderMeta.id,
|
|
27
29
|
bucket: folderMeta.bucket,
|
|
@@ -36,6 +38,7 @@ class DriveUtils {
|
|
|
36
38
|
}
|
|
37
39
|
static createFolderResponseToItem(folderResponse) {
|
|
38
40
|
return {
|
|
41
|
+
itemType: 'folder',
|
|
39
42
|
uuid: folderResponse.uuid,
|
|
40
43
|
id: folderResponse.id,
|
|
41
44
|
bucket: folderResponse.bucket,
|
|
@@ -52,3 +52,13 @@ 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
|
+
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { Request } from 'express';
|
|
2
1
|
import { WebDavRequestedResource } from '../types/webdav.types';
|
|
3
2
|
import { DriveFolderService } from '../services/drive/drive-folder.service';
|
|
4
3
|
import { DriveFileService } from '../services/drive/drive-file.service';
|
|
@@ -8,18 +7,21 @@ export declare class WebDavUtils {
|
|
|
8
7
|
static removeHostFromURL(completeURL: string): string;
|
|
9
8
|
static decodeUrl(requestUrl: string, decodeUri?: boolean): string;
|
|
10
9
|
static normalizeFolderPath(path: string): string;
|
|
11
|
-
static getRequestedResource(
|
|
12
|
-
static
|
|
13
|
-
|
|
10
|
+
static getRequestedResource(requestUrl: string, decodeUri?: boolean): Promise<WebDavRequestedResource>;
|
|
11
|
+
static tryGetFileOrFolderMetadata({ url, driveFileService, driveFolderService, }: {
|
|
12
|
+
url: string;
|
|
14
13
|
driveFolderService: DriveFolderService;
|
|
15
|
-
driveFileService
|
|
16
|
-
}): Promise<
|
|
17
|
-
static
|
|
18
|
-
|
|
19
|
-
driveFolderService?: never;
|
|
14
|
+
driveFileService: DriveFileService;
|
|
15
|
+
}): Promise<DriveItem | undefined>;
|
|
16
|
+
static getDriveFileFromResource({ url, driveFileService, }: {
|
|
17
|
+
url: string;
|
|
20
18
|
driveFileService: DriveFileService;
|
|
21
19
|
}): Promise<DriveFileItem | undefined>;
|
|
22
|
-
static
|
|
20
|
+
static getDriveFolderFromResource({ url, driveFolderService, }: {
|
|
21
|
+
url: string;
|
|
22
|
+
driveFolderService: DriveFolderService;
|
|
23
|
+
}): Promise<DriveFolderItem | undefined>;
|
|
24
|
+
static getDriveItemFromResource({ resource, driveFolderService, driveFileService, }: {
|
|
23
25
|
resource: WebDavRequestedResource;
|
|
24
26
|
driveFolderService: DriveFolderService;
|
|
25
27
|
driveFileService: DriveFileService;
|
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.WebDavUtils = void 0;
|
|
7
7
|
const node_path_1 = __importDefault(require("node:path"));
|
|
8
|
+
const logger_utils_1 = require("./logger.utils");
|
|
8
9
|
class WebDavUtils {
|
|
9
10
|
static joinURL(...pathComponents) {
|
|
10
11
|
return node_path_1.default.posix.join(...pathComponents);
|
|
@@ -32,45 +33,54 @@ class WebDavUtils {
|
|
|
32
33
|
}
|
|
33
34
|
return normalizedPath;
|
|
34
35
|
}
|
|
35
|
-
static async getRequestedResource(
|
|
36
|
-
let requestUrl;
|
|
37
|
-
if (typeof urlObject === 'string') {
|
|
38
|
-
requestUrl = urlObject;
|
|
39
|
-
}
|
|
40
|
-
else {
|
|
41
|
-
requestUrl = urlObject.url;
|
|
42
|
-
}
|
|
36
|
+
static async getRequestedResource(requestUrl, decodeUri = true) {
|
|
43
37
|
const decodedUrl = this.decodeUrl(requestUrl, decodeUri);
|
|
44
38
|
const parsedPath = node_path_1.default.parse(decodedUrl);
|
|
45
39
|
const parentPath = this.normalizeFolderPath(node_path_1.default.dirname(decodedUrl));
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
40
|
+
return {
|
|
41
|
+
url: decodedUrl,
|
|
42
|
+
name: parsedPath.base,
|
|
43
|
+
path: parsedPath,
|
|
44
|
+
parentPath,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
static async tryGetFileOrFolderMetadata({ url, driveFileService, driveFolderService, }) {
|
|
48
|
+
try {
|
|
49
|
+
return await driveFileService.getFileMetadataByPath(url);
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return await driveFolderService.getFolderMetadataByPath(url);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
static async getDriveFileFromResource({ url, driveFileService, }) {
|
|
56
|
+
try {
|
|
57
|
+
return await driveFileService.getFileMetadataByPath(url);
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
logger_utils_1.webdavLogger.error('Exception while getting the file metadata by path', err);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
static async getDriveFolderFromResource({ url, driveFolderService, }) {
|
|
64
|
+
try {
|
|
65
|
+
return await driveFolderService.getFolderMetadataByPath(url);
|
|
55
66
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
type: 'file',
|
|
59
|
-
url: decodedUrl,
|
|
60
|
-
name: parsedPath.name,
|
|
61
|
-
path: parsedPath,
|
|
62
|
-
parentPath,
|
|
63
|
-
};
|
|
67
|
+
catch (err) {
|
|
68
|
+
logger_utils_1.webdavLogger.error('Exception while getting the folder metadata by path', err);
|
|
64
69
|
}
|
|
65
70
|
}
|
|
66
71
|
static async getDriveItemFromResource({ resource, driveFolderService, driveFileService, }) {
|
|
67
72
|
let item = undefined;
|
|
73
|
+
const isFolder = resource.url.endsWith('/');
|
|
68
74
|
try {
|
|
69
|
-
if (
|
|
70
|
-
item = await driveFolderService
|
|
75
|
+
if (isFolder) {
|
|
76
|
+
item = await driveFolderService.getFolderMetadataByPath(resource.url);
|
|
71
77
|
}
|
|
72
|
-
|
|
73
|
-
item = await
|
|
78
|
+
else {
|
|
79
|
+
item = await this.tryGetFileOrFolderMetadata({
|
|
80
|
+
url: resource.url,
|
|
81
|
+
driveFileService,
|
|
82
|
+
driveFolderService,
|
|
83
|
+
});
|
|
74
84
|
}
|
|
75
85
|
}
|
|
76
86
|
catch {
|
|
@@ -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({
|
|
@@ -12,12 +12,12 @@ class MKCOLRequestHandler {
|
|
|
12
12
|
}
|
|
13
13
|
handle = async (req, res) => {
|
|
14
14
|
const { driveFolderService, webDavFolderService } = this.dependencies;
|
|
15
|
-
const resource = await webdav_utils_1.WebDavUtils.getRequestedResource(req);
|
|
16
|
-
logger_utils_1.webdavLogger.info(`[MKCOL] Request received for
|
|
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
17
|
const parentDriveFolderItem = (await webDavFolderService.getDriveFolderItemFromPath(resource.parentPath)) ??
|
|
18
18
|
(await webDavFolderService.createParentPathOrThrow(resource.parentPath));
|
|
19
|
-
const driveFolderItem = await webdav_utils_1.WebDavUtils.
|
|
20
|
-
resource,
|
|
19
|
+
const driveFolderItem = await webdav_utils_1.WebDavUtils.getDriveFolderFromResource({
|
|
20
|
+
url: resource.url,
|
|
21
21
|
driveFolderService,
|
|
22
22
|
});
|
|
23
23
|
const folderAlreadyExists = !!driveFolderItem;
|
|
@@ -11,8 +11,8 @@ class MOVERequestHandler {
|
|
|
11
11
|
}
|
|
12
12
|
handle = async (req, res) => {
|
|
13
13
|
const { driveFolderService, driveFileService, webDavFolderService } = this.dependencies;
|
|
14
|
-
const resource = await webdav_utils_1.WebDavUtils.getRequestedResource(req);
|
|
15
|
-
logger_utils_1.webdavLogger.info(`[MOVE] Request received for
|
|
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,43 +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
|
+
logger_utils_1.webdavLogger.info(`[MOVE] Moving ${originalDriveItem.itemType} with UUID ${originalDriveItem.uuid} to ${destinationPath}`);
|
|
52
53
|
const destinationFolderItem = (await webDavFolderService.getDriveFolderItemFromPath(destinationResource.parentPath)) ??
|
|
53
54
|
(await webDavFolderService.createParentPathOrThrow(destinationResource.parentPath));
|
|
54
|
-
if (
|
|
55
|
+
if (originalDriveItem.itemType === 'folder') {
|
|
55
56
|
const folder = originalDriveItem;
|
|
56
57
|
await driveFolderService.moveFolder(folder.uuid, {
|
|
57
58
|
destinationFolder: destinationFolderItem.uuid,
|
|
58
|
-
name:
|
|
59
|
+
name: destinationResource.name,
|
|
59
60
|
});
|
|
60
61
|
}
|
|
61
|
-
else if (
|
|
62
|
+
else if (originalDriveItem.itemType === 'file') {
|
|
62
63
|
const file = originalDriveItem;
|
|
63
|
-
const
|
|
64
|
+
const plainName = destinationResource.path.name;
|
|
65
|
+
const fileType = destinationResource.path.ext.replace('.', '');
|
|
64
66
|
await driveFileService.moveFile(file.uuid, {
|
|
65
67
|
destinationFolder: destinationFolderItem.uuid,
|
|
66
|
-
name:
|
|
67
|
-
type:
|
|
68
|
+
name: plainName,
|
|
69
|
+
type: fileType,
|
|
68
70
|
});
|
|
69
71
|
}
|
|
70
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,
|
|
@@ -5,10 +5,12 @@ import { AuthService } from '../../services/auth.service';
|
|
|
5
5
|
import { WebDavMethodHandler } from '../../types/webdav.types';
|
|
6
6
|
import { TrashService } from '../../services/drive/trash.service';
|
|
7
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;
|
|
13
|
+
driveFolderService: DriveFolderService;
|
|
12
14
|
webDavFolderService: WebDavFolderService;
|
|
13
15
|
trashService: TrashService;
|
|
14
16
|
authService: AuthService;
|
|
@@ -21,22 +21,24 @@ class PUTRequestHandler {
|
|
|
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
|
-
|
|
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,
|
|
29
|
+
});
|
|
30
|
+
if (driveFileItem?.itemType === 'folder') {
|
|
26
31
|
throw new errors_utils_1.NotFoundError('Folders cannot be created with PUT. Use MKCOL instead.');
|
|
27
|
-
|
|
32
|
+
}
|
|
33
|
+
logger_utils_1.webdavLogger.info(`[PUT] Request received for file at ${resource.url}`);
|
|
28
34
|
logger_utils_1.webdavLogger.info(`[PUT] Uploading '${resource.name}' to '${resource.parentPath}'`);
|
|
29
35
|
const parentDriveFolderItem = (await this.dependencies.webDavFolderService.getDriveFolderItemFromPath(resource.parentPath)) ??
|
|
30
36
|
(await this.dependencies.webDavFolderService.createParentPathOrThrow(resource.parentPath));
|
|
31
37
|
try {
|
|
32
|
-
const driveFileItem = await webdav_utils_1.WebDavUtils.getDriveItemFromResource({
|
|
33
|
-
resource: resource,
|
|
34
|
-
driveFileService: this.dependencies.driveFileService,
|
|
35
|
-
});
|
|
36
38
|
if (driveFileItem && driveFileItem.status === 'EXISTS') {
|
|
37
39
|
logger_utils_1.webdavLogger.info(`[PUT] File '${resource.name}' already exists in '${resource.path.dir}', trashing it...`);
|
|
38
40
|
await this.dependencies.trashService.trashItems({
|
|
39
|
-
items: [{ type:
|
|
41
|
+
items: [{ type: driveFileItem.itemType, uuid: driveFileItem.uuid }],
|
|
40
42
|
});
|
|
41
43
|
}
|
|
42
44
|
}
|
|
@@ -12,9 +12,9 @@ class WebDavFolderService {
|
|
|
12
12
|
this.dependencies = dependencies;
|
|
13
13
|
}
|
|
14
14
|
getDriveFolderItemFromPath = async (path) => {
|
|
15
|
-
const
|
|
16
|
-
return await webdav_utils_1.WebDavUtils.
|
|
17
|
-
|
|
15
|
+
const { url } = await webdav_utils_1.WebDavUtils.getRequestedResource(path, false);
|
|
16
|
+
return await webdav_utils_1.WebDavUtils.getDriveFolderFromResource({
|
|
17
|
+
url,
|
|
18
18
|
driveFolderService: this.dependencies.driveFolderService,
|
|
19
19
|
});
|
|
20
20
|
};
|
|
@@ -30,7 +30,8 @@ class WebDavFolderService {
|
|
|
30
30
|
createParentPathOrThrow = async (parentPath) => {
|
|
31
31
|
const { createFullPath } = await this.dependencies.configService.readWebdavConfig();
|
|
32
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)}
|
|
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}`);
|
|
34
35
|
}
|
|
35
36
|
const folders = parentPath.split('/').filter((f) => f.length > 0);
|
|
36
37
|
const { user } = await auth_service_1.AuthService.instance.getAuthDetails();
|
|
@@ -104,6 +104,7 @@ class WebDavServer {
|
|
|
104
104
|
}).handle));
|
|
105
105
|
this.app.put(serverListenPath, (0, express_async_handler_1.default)(new PUT_handler_1.PUTRequestHandler({
|
|
106
106
|
driveFileService: this.driveFileService,
|
|
107
|
+
driveFolderService: this.driveFolderService,
|
|
107
108
|
webDavFolderService: webDavFolderService,
|
|
108
109
|
authService: this.authService,
|
|
109
110
|
trashService: this.trashService,
|
package/oclif.manifest.json
CHANGED
|
@@ -351,10 +351,10 @@
|
|
|
351
351
|
"list.js"
|
|
352
352
|
]
|
|
353
353
|
},
|
|
354
|
-
"login": {
|
|
354
|
+
"login-legacy": {
|
|
355
355
|
"aliases": [],
|
|
356
356
|
"args": {},
|
|
357
|
-
"description": "Logs into an Internxt account. If the account is two-factor protected, then an extra code will be required.",
|
|
357
|
+
"description": "[Legacy] Logs into an Internxt account using user and password. If the account is two-factor protected, then an extra code will be required.",
|
|
358
358
|
"examples": [
|
|
359
359
|
"<%= config.bin %> <%= command.id %>"
|
|
360
360
|
],
|
|
@@ -435,6 +435,63 @@
|
|
|
435
435
|
},
|
|
436
436
|
"hasDynamicHelp": false,
|
|
437
437
|
"hiddenAliases": [],
|
|
438
|
+
"id": "login-legacy",
|
|
439
|
+
"pluginAlias": "@internxt/cli",
|
|
440
|
+
"pluginName": "@internxt/cli",
|
|
441
|
+
"pluginType": "core",
|
|
442
|
+
"strict": true,
|
|
443
|
+
"enableJsonFlag": true,
|
|
444
|
+
"isESM": false,
|
|
445
|
+
"relativePath": [
|
|
446
|
+
"dist",
|
|
447
|
+
"commands",
|
|
448
|
+
"login-legacy.js"
|
|
449
|
+
]
|
|
450
|
+
},
|
|
451
|
+
"login": {
|
|
452
|
+
"aliases": [],
|
|
453
|
+
"args": {},
|
|
454
|
+
"description": "Logs into your Internxt account using the web-based login flow. A temporary local server is started to securely receive the authentication response.",
|
|
455
|
+
"examples": [
|
|
456
|
+
"<%= config.bin %> <%= command.id %>"
|
|
457
|
+
],
|
|
458
|
+
"flags": {
|
|
459
|
+
"json": {
|
|
460
|
+
"description": "Format output as json.",
|
|
461
|
+
"helpGroup": "GLOBAL",
|
|
462
|
+
"name": "json",
|
|
463
|
+
"allowNo": false,
|
|
464
|
+
"type": "boolean"
|
|
465
|
+
},
|
|
466
|
+
"host": {
|
|
467
|
+
"aliases": [
|
|
468
|
+
"host"
|
|
469
|
+
],
|
|
470
|
+
"char": "h",
|
|
471
|
+
"description": "IP address of the machine where the CLI is running. If you are opening the login page in a browser on another device, set this to the IP address of the machine running the CLI. Defaults to 127.0.0.1.",
|
|
472
|
+
"env": "INXT_LOGIN_SERVER_HOST",
|
|
473
|
+
"name": "host",
|
|
474
|
+
"required": false,
|
|
475
|
+
"hasDynamicHelp": false,
|
|
476
|
+
"multiple": false,
|
|
477
|
+
"type": "option"
|
|
478
|
+
},
|
|
479
|
+
"port": {
|
|
480
|
+
"aliases": [
|
|
481
|
+
"port"
|
|
482
|
+
],
|
|
483
|
+
"char": "p",
|
|
484
|
+
"description": "Port used by the temporary local server to handle the login callback. If not specified, a random available port will be used automatically.",
|
|
485
|
+
"env": "INXT_LOGIN_SERVER_PORT",
|
|
486
|
+
"name": "port",
|
|
487
|
+
"required": false,
|
|
488
|
+
"hasDynamicHelp": false,
|
|
489
|
+
"multiple": false,
|
|
490
|
+
"type": "option"
|
|
491
|
+
}
|
|
492
|
+
},
|
|
493
|
+
"hasDynamicHelp": false,
|
|
494
|
+
"hiddenAliases": [],
|
|
438
495
|
"id": "login",
|
|
439
496
|
"pluginAlias": "@internxt/cli",
|
|
440
497
|
"pluginName": "@internxt/cli",
|
|
@@ -1298,5 +1355,5 @@
|
|
|
1298
1355
|
]
|
|
1299
1356
|
}
|
|
1300
1357
|
},
|
|
1301
|
-
"version": "1.
|
|
1358
|
+
"version": "1.6.0"
|
|
1302
1359
|
}
|