@internxt/cli 0.1.4
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/.env +11 -0
- package/README.md +297 -0
- package/bin/dev.cmd +3 -0
- package/bin/dev.js +7 -0
- package/bin/run.cmd +3 -0
- package/bin/run.js +7 -0
- package/dist/commands/config.d.ts +18 -0
- package/dist/commands/config.js +50 -0
- package/dist/commands/download.d.ts +19 -0
- package/dist/commands/download.js +119 -0
- package/dist/commands/list.d.ts +22 -0
- package/dist/commands/list.js +125 -0
- package/dist/commands/login.d.ts +21 -0
- package/dist/commands/login.js +124 -0
- package/dist/commands/logout.d.ts +9 -0
- package/dist/commands/logout.js +28 -0
- package/dist/commands/logs.d.ts +6 -0
- package/dist/commands/logs.js +12 -0
- package/dist/commands/move.d.ts +18 -0
- package/dist/commands/move.js +109 -0
- package/dist/commands/trash.d.ts +15 -0
- package/dist/commands/trash.js +85 -0
- package/dist/commands/upload.d.ts +15 -0
- package/dist/commands/upload.js +93 -0
- package/dist/commands/webdav.d.ts +12 -0
- package/dist/commands/webdav.js +64 -0
- package/dist/commands/whoami.d.ts +9 -0
- package/dist/commands/whoami.js +27 -0
- package/dist/database/migrations/20240402164914-create-files.d.ts +1 -0
- package/dist/database/migrations/20240402164914-create-files.js +55 -0
- package/dist/database/migrations/20240402165418-create-folders.d.ts +1 -0
- package/dist/database/migrations/20240402165418-create-folders.js +37 -0
- package/dist/hooks/prerun/auth_check.d.ts +3 -0
- package/dist/hooks/prerun/auth_check.js +32 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +5 -0
- package/dist/services/auth.service.d.ts +14 -0
- package/dist/services/auth.service.js +79 -0
- package/dist/services/config.service.d.ts +19 -0
- package/dist/services/config.service.js +79 -0
- package/dist/services/crypto.service.d.ts +22 -0
- package/dist/services/crypto.service.js +126 -0
- package/dist/services/database/drive-database-manager.service.d.ts +18 -0
- package/dist/services/database/drive-database-manager.service.js +76 -0
- package/dist/services/database/drive-file/drive-file.attributes.d.ts +14 -0
- package/dist/services/database/drive-file/drive-file.attributes.js +2 -0
- package/dist/services/database/drive-file/drive-file.domain.d.ts +18 -0
- package/dist/services/database/drive-file/drive-file.domain.js +51 -0
- package/dist/services/database/drive-file/drive-file.model.d.ts +17 -0
- package/dist/services/database/drive-file/drive-file.model.js +82 -0
- package/dist/services/database/drive-file/drive-file.repository.d.ts +11 -0
- package/dist/services/database/drive-file/drive-file.repository.js +40 -0
- package/dist/services/database/drive-folder/drive-folder.attributes.d.ts +9 -0
- package/dist/services/database/drive-folder/drive-folder.attributes.js +2 -0
- package/dist/services/database/drive-folder/drive-folder.domain.d.ts +13 -0
- package/dist/services/database/drive-folder/drive-folder.domain.js +36 -0
- package/dist/services/database/drive-folder/drive-folder.model.d.ts +12 -0
- package/dist/services/database/drive-folder/drive-folder.model.js +56 -0
- package/dist/services/database/drive-folder/drive-folder.repository.d.ts +11 -0
- package/dist/services/database/drive-folder/drive-folder.repository.js +40 -0
- package/dist/services/drive/drive-file.service.d.ts +15 -0
- package/dist/services/drive/drive-file.service.js +51 -0
- package/dist/services/drive/drive-folder.service.d.ts +15 -0
- package/dist/services/drive/drive-folder.service.js +49 -0
- package/dist/services/drive/trash.service.d.ts +5 -0
- package/dist/services/drive/trash.service.js +12 -0
- package/dist/services/keys.service.d.ts +14 -0
- package/dist/services/keys.service.js +110 -0
- package/dist/services/network/download.service.d.ts +7 -0
- package/dist/services/network/download.service.js +33 -0
- package/dist/services/network/network-facade.service.d.ts +21 -0
- package/dist/services/network/network-facade.service.js +128 -0
- package/dist/services/network/upload.service.d.ts +9 -0
- package/dist/services/network/upload.service.js +20 -0
- package/dist/services/realms/drive-files.realm.d.ts +23 -0
- package/dist/services/realms/drive-files.realm.js +76 -0
- package/dist/services/realms/drive-folders.realm.d.ts +20 -0
- package/dist/services/realms/drive-folders.realm.js +68 -0
- package/dist/services/realms/drive-realm-manager.service.d.ts +15 -0
- package/dist/services/realms/drive-realm-manager.service.js +63 -0
- package/dist/services/sdk-manager.service.d.ts +28 -0
- package/dist/services/sdk-manager.service.js +107 -0
- package/dist/services/usage.service.d.ts +6 -0
- package/dist/services/usage.service.js +23 -0
- package/dist/services/validation.service.d.ts +7 -0
- package/dist/services/validation.service.js +21 -0
- package/dist/types/command.types.d.ts +42 -0
- package/dist/types/command.types.js +59 -0
- package/dist/types/config.types.d.ts +13 -0
- package/dist/types/config.types.js +2 -0
- package/dist/types/drive.types.d.ts +14 -0
- package/dist/types/drive.types.js +2 -0
- package/dist/types/keys.types.d.ts +16 -0
- package/dist/types/keys.types.js +31 -0
- package/dist/types/network.types.d.ts +11 -0
- package/dist/types/network.types.js +2 -0
- package/dist/types/webdav.types.d.ts +15 -0
- package/dist/types/webdav.types.js +6 -0
- package/dist/utils/cli.utils.d.ts +32 -0
- package/dist/utils/cli.utils.js +105 -0
- package/dist/utils/crypto.utils.d.ts +6 -0
- package/dist/utils/crypto.utils.js +10 -0
- package/dist/utils/drive.utils.d.ts +6 -0
- package/dist/utils/drive.utils.js +34 -0
- package/dist/utils/errors.utils.d.ts +19 -0
- package/dist/utils/errors.utils.js +50 -0
- package/dist/utils/format.utils.d.ts +6 -0
- package/dist/utils/format.utils.js +30 -0
- package/dist/utils/hash.utils.d.ts +15 -0
- package/dist/utils/hash.utils.js +37 -0
- package/dist/utils/logger.utils.d.ts +3 -0
- package/dist/utils/logger.utils.js +50 -0
- package/dist/utils/network.utils.d.ts +22 -0
- package/dist/utils/network.utils.js +49 -0
- package/dist/utils/pm2.utils.d.ts +10 -0
- package/dist/utils/pm2.utils.js +65 -0
- package/dist/utils/stream.utils.d.ts +7 -0
- package/dist/utils/stream.utils.js +56 -0
- package/dist/utils/webdav.utils.d.ts +7 -0
- package/dist/utils/webdav.utils.js +47 -0
- package/dist/utils/xml.utils.d.ts +8 -0
- package/dist/utils/xml.utils.js +23 -0
- package/dist/webdav/handlers/GET.handler.d.ts +23 -0
- package/dist/webdav/handlers/GET.handler.js +52 -0
- package/dist/webdav/handlers/HEAD.handler.d.ts +5 -0
- package/dist/webdav/handlers/HEAD.handler.js +9 -0
- package/dist/webdav/handlers/OPTIONS.handler.d.ts +5 -0
- package/dist/webdav/handlers/OPTIONS.handler.js +11 -0
- package/dist/webdav/handlers/PROPFIND.handler.d.ts +21 -0
- package/dist/webdav/handlers/PROPFIND.handler.js +234 -0
- package/dist/webdav/handlers/PUT.handler.d.ts +23 -0
- package/dist/webdav/handlers/PUT.handler.js +51 -0
- package/dist/webdav/index.d.ts +1 -0
- package/dist/webdav/index.js +30 -0
- package/dist/webdav/middewares/auth.middleware.d.ts +3 -0
- package/dist/webdav/middewares/auth.middleware.js +27 -0
- package/dist/webdav/middewares/errors.middleware.d.ts +2 -0
- package/dist/webdav/middewares/errors.middleware.js +20 -0
- package/dist/webdav/middewares/request-logger.middleware.d.ts +7 -0
- package/dist/webdav/middewares/request-logger.middleware.js +15 -0
- package/dist/webdav/webdav-server.d.ts +25 -0
- package/dist/webdav/webdav-server.js +98 -0
- package/oclif.manifest.json +593 -0
- package/package.json +122 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.XMLUtils = void 0;
|
|
4
|
+
const fast_xml_parser_1 = require("fast-xml-parser");
|
|
5
|
+
class XMLUtils {
|
|
6
|
+
static DEFAULT_NAMESPACE_LETTER = 'D';
|
|
7
|
+
static toJSON(xml, options = {}) {
|
|
8
|
+
const parser = new fast_xml_parser_1.XMLParser(options);
|
|
9
|
+
return parser.parse(xml);
|
|
10
|
+
}
|
|
11
|
+
static toXML(object, options = { format: true }) {
|
|
12
|
+
const builder = new fast_xml_parser_1.XMLBuilder(options);
|
|
13
|
+
return builder.build(object);
|
|
14
|
+
}
|
|
15
|
+
static toWebDavXML(object, options) {
|
|
16
|
+
const xmlContent = this.toXML(object, options);
|
|
17
|
+
return `<?xml version="1.0" encoding="utf-8" ?><${XMLUtils.addDefaultNamespace('multistatus')} xmlns:${XMLUtils.DEFAULT_NAMESPACE_LETTER}="DAV:">${xmlContent}</${XMLUtils.addDefaultNamespace('multistatus')}>`;
|
|
18
|
+
}
|
|
19
|
+
static addDefaultNamespace(key) {
|
|
20
|
+
return `${XMLUtils.DEFAULT_NAMESPACE_LETTER}:${key}`;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
exports.XMLUtils = XMLUtils;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { WebDavMethodHandler } from '../../types/webdav.types';
|
|
2
|
+
import { Request, Response } from 'express';
|
|
3
|
+
import { DriveFileService } from '../../services/drive/drive-file.service';
|
|
4
|
+
import { DriveDatabaseManager } from '../../services/database/drive-database-manager.service';
|
|
5
|
+
import { NetworkFacade } from '../../services/network/network-facade.service';
|
|
6
|
+
import { UploadService } from '../../services/network/upload.service';
|
|
7
|
+
import { DownloadService } from '../../services/network/download.service';
|
|
8
|
+
import { CryptoService } from '../../services/crypto.service';
|
|
9
|
+
import { AuthService } from '../../services/auth.service';
|
|
10
|
+
export declare class GETRequestHandler implements WebDavMethodHandler {
|
|
11
|
+
private dependencies;
|
|
12
|
+
constructor(dependencies: {
|
|
13
|
+
driveFileService: DriveFileService;
|
|
14
|
+
driveDatabaseManager: DriveDatabaseManager;
|
|
15
|
+
uploadService: UploadService;
|
|
16
|
+
downloadService: DownloadService;
|
|
17
|
+
cryptoService: CryptoService;
|
|
18
|
+
authService: AuthService;
|
|
19
|
+
networkFacade: NetworkFacade;
|
|
20
|
+
});
|
|
21
|
+
handle: (req: Request, res: Response) => Promise<void>;
|
|
22
|
+
private getDriveFileDatabaseObject;
|
|
23
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GETRequestHandler = void 0;
|
|
4
|
+
const webdav_utils_1 = require("../../utils/webdav.utils");
|
|
5
|
+
const errors_utils_1 = require("../../utils/errors.utils");
|
|
6
|
+
const logger_utils_1 = require("../../utils/logger.utils");
|
|
7
|
+
class GETRequestHandler {
|
|
8
|
+
dependencies;
|
|
9
|
+
constructor(dependencies) {
|
|
10
|
+
this.dependencies = dependencies;
|
|
11
|
+
}
|
|
12
|
+
handle = async (req, res) => {
|
|
13
|
+
const resource = await webdav_utils_1.WebDavUtils.getRequestedResource(req, this.dependencies.driveDatabaseManager);
|
|
14
|
+
if (req.headers['content-range'] || req.headers['range'])
|
|
15
|
+
throw new errors_utils_1.NotImplementedError('Range requests not supported');
|
|
16
|
+
if (resource.name.startsWith('._'))
|
|
17
|
+
throw new errors_utils_1.NotFoundError('File not found');
|
|
18
|
+
logger_utils_1.webdavLogger.info(`GET request received for file at ${resource.url}`);
|
|
19
|
+
const driveFile = await this.getDriveFileDatabaseObject(resource);
|
|
20
|
+
if (!driveFile) {
|
|
21
|
+
throw new errors_utils_1.NotFoundError('Drive file not found');
|
|
22
|
+
}
|
|
23
|
+
logger_utils_1.webdavLogger.info(`✅ Found Drive File with uuid ${driveFile.uuid}`);
|
|
24
|
+
res.set('Content-Type', 'application/octet-stream');
|
|
25
|
+
res.set('Content-length', driveFile.size.toString());
|
|
26
|
+
const { mnemonic } = await this.dependencies.authService.getAuthDetails();
|
|
27
|
+
logger_utils_1.webdavLogger.info('✅ Network ready for download');
|
|
28
|
+
const writable = new WritableStream({
|
|
29
|
+
write(chunk) {
|
|
30
|
+
res.write(chunk);
|
|
31
|
+
},
|
|
32
|
+
close() {
|
|
33
|
+
res.end();
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
const [executeDownload] = await this.dependencies.networkFacade.downloadToStream(driveFile.bucket, mnemonic, driveFile.fileId, writable, {
|
|
37
|
+
progressCallback: (progress) => {
|
|
38
|
+
logger_utils_1.webdavLogger.info(`Download progress for file ${resource.name}: ${progress}%`);
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
logger_utils_1.webdavLogger.info('✅ Download prepared, executing...');
|
|
42
|
+
res.status(200);
|
|
43
|
+
await executeDownload;
|
|
44
|
+
logger_utils_1.webdavLogger.info('✅ Download ready, replying to client');
|
|
45
|
+
};
|
|
46
|
+
async getDriveFileDatabaseObject(resource) {
|
|
47
|
+
const { driveDatabaseManager } = this.dependencies;
|
|
48
|
+
const result = await driveDatabaseManager.findByRelativePath(resource.url);
|
|
49
|
+
return result;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
exports.GETRequestHandler = GETRequestHandler;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OPTIONSRequestHandler = void 0;
|
|
4
|
+
class OPTIONSRequestHandler {
|
|
5
|
+
async handle(_, res) {
|
|
6
|
+
res.header('Allow', 'OPTIONS, GET, HEAD, POST, PUT, DELETE, PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, LOCK, UNLOCK');
|
|
7
|
+
res.header('DAV', '1, 2, ordered-collections');
|
|
8
|
+
res.status(200).send();
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
exports.OPTIONSRequestHandler = OPTIONSRequestHandler;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { WebDavMethodHandler, WebDavMethodHandlerOptions } from '../../types/webdav.types';
|
|
2
|
+
import { DriveFolderService } from '../../services/drive/drive-folder.service';
|
|
3
|
+
import { Request, Response } from 'express';
|
|
4
|
+
import { DriveDatabaseManager } from '../../services/database/drive-database-manager.service';
|
|
5
|
+
export declare class PROPFINDRequestHandler implements WebDavMethodHandler {
|
|
6
|
+
private options;
|
|
7
|
+
private dependencies;
|
|
8
|
+
constructor(options: WebDavMethodHandlerOptions, dependencies: {
|
|
9
|
+
driveFolderService: DriveFolderService;
|
|
10
|
+
driveDatabaseManager: DriveDatabaseManager;
|
|
11
|
+
});
|
|
12
|
+
handle: (req: Request, res: Response) => Promise<void>;
|
|
13
|
+
private getFileMetaXML;
|
|
14
|
+
private getFolderContentXML;
|
|
15
|
+
private getFolderChildsXMLNode;
|
|
16
|
+
private getFolderRootXMLNode;
|
|
17
|
+
private getFolderXMLNode;
|
|
18
|
+
private driveFolderRootStatsToXMLNode;
|
|
19
|
+
private driveFolderItemToXMLNode;
|
|
20
|
+
private driveFileItemToXMLNode;
|
|
21
|
+
}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.PROPFINDRequestHandler = void 0;
|
|
7
|
+
const xml_utils_1 = require("../../utils/xml.utils");
|
|
8
|
+
const format_utils_1 = require("../../utils/format.utils");
|
|
9
|
+
const crypto_1 = require("crypto");
|
|
10
|
+
const mime_types_1 = __importDefault(require("mime-types"));
|
|
11
|
+
const webdav_utils_1 = require("../../utils/webdav.utils");
|
|
12
|
+
const errors_utils_1 = require("../../utils/errors.utils");
|
|
13
|
+
class PROPFINDRequestHandler {
|
|
14
|
+
options;
|
|
15
|
+
dependencies;
|
|
16
|
+
constructor(options = { debug: false }, dependencies) {
|
|
17
|
+
this.options = options;
|
|
18
|
+
this.dependencies = dependencies;
|
|
19
|
+
}
|
|
20
|
+
handle = async (req, res) => {
|
|
21
|
+
const resource = await webdav_utils_1.WebDavUtils.getRequestedResource(req, this.dependencies.driveDatabaseManager);
|
|
22
|
+
const depth = req.header('depth') ?? '1';
|
|
23
|
+
switch (resource.type) {
|
|
24
|
+
case 'file': {
|
|
25
|
+
res.status(207).send(await this.getFileMetaXML(resource));
|
|
26
|
+
break;
|
|
27
|
+
}
|
|
28
|
+
case 'folder': {
|
|
29
|
+
if (resource.url === '/') {
|
|
30
|
+
const rootFolder = await this.dependencies.driveFolderService.getFolderMetaById(req.user.rootFolderId);
|
|
31
|
+
await this.dependencies.driveDatabaseManager.createFolder({
|
|
32
|
+
name: '',
|
|
33
|
+
encryptedName: rootFolder.name,
|
|
34
|
+
bucket: rootFolder.bucket,
|
|
35
|
+
id: rootFolder.id,
|
|
36
|
+
parentId: rootFolder.parentId,
|
|
37
|
+
uuid: rootFolder.uuid,
|
|
38
|
+
createdAt: new Date(rootFolder.createdAt),
|
|
39
|
+
updatedAt: new Date(rootFolder.updatedAt),
|
|
40
|
+
});
|
|
41
|
+
res.status(207).send(await this.getFolderContentXML('/', rootFolder.uuid, depth, true));
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
const driveParentFolder = await this.dependencies.driveDatabaseManager.findByRelativePath(resource.url);
|
|
45
|
+
if (!driveParentFolder) {
|
|
46
|
+
res.status(404).send();
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
res.status(207).send(await this.getFolderContentXML(resource.url, driveParentFolder.uuid, depth));
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
async getFileMetaXML(resource) {
|
|
55
|
+
const driveFileItem = await this.dependencies.driveDatabaseManager.findByRelativePath(resource.url);
|
|
56
|
+
if (!driveFileItem || !('size' in driveFileItem))
|
|
57
|
+
throw new errors_utils_1.NotFoundError('File not found');
|
|
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
|
+
encryptedName: driveFileItem.name,
|
|
66
|
+
size: driveFileItem.size,
|
|
67
|
+
createdAt: driveFileItem.createdAt,
|
|
68
|
+
updatedAt: driveFileItem.updatedAt,
|
|
69
|
+
status: driveFileItem.status,
|
|
70
|
+
folderId: driveFileItem.folderId,
|
|
71
|
+
}, encodeURI(resource.url));
|
|
72
|
+
const xml = xml_utils_1.XMLUtils.toWebDavXML([driveFile], {
|
|
73
|
+
arrayNodeName: xml_utils_1.XMLUtils.addDefaultNamespace('response'),
|
|
74
|
+
});
|
|
75
|
+
return xml;
|
|
76
|
+
}
|
|
77
|
+
async getFolderContentXML(relativePath, folderUuid, depth, isRootFolder = false) {
|
|
78
|
+
let XMLNodes = [];
|
|
79
|
+
switch (depth) {
|
|
80
|
+
case '0':
|
|
81
|
+
if (isRootFolder) {
|
|
82
|
+
XMLNodes.push(await this.getFolderRootXMLNode(relativePath, folderUuid));
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
XMLNodes.push(await this.getFolderXMLNode(relativePath, folderUuid));
|
|
86
|
+
}
|
|
87
|
+
break;
|
|
88
|
+
case '1':
|
|
89
|
+
default:
|
|
90
|
+
if (isRootFolder) {
|
|
91
|
+
XMLNodes.push(await this.getFolderRootXMLNode(relativePath, folderUuid));
|
|
92
|
+
XMLNodes = XMLNodes.concat(await this.getFolderChildsXMLNode(relativePath, folderUuid));
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
XMLNodes.push(await this.getFolderXMLNode(relativePath, folderUuid));
|
|
96
|
+
XMLNodes = XMLNodes.concat(await this.getFolderChildsXMLNode(relativePath, folderUuid));
|
|
97
|
+
}
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
const xml = xml_utils_1.XMLUtils.toWebDavXML(XMLNodes, {
|
|
101
|
+
arrayNodeName: xml_utils_1.XMLUtils.addDefaultNamespace('response'),
|
|
102
|
+
ignoreAttributes: false,
|
|
103
|
+
suppressEmptyNode: true,
|
|
104
|
+
});
|
|
105
|
+
return xml;
|
|
106
|
+
}
|
|
107
|
+
async getFolderChildsXMLNode(relativePath, folderUuid) {
|
|
108
|
+
const { driveFolderService, driveDatabaseManager } = this.dependencies;
|
|
109
|
+
const folderContent = await driveFolderService.getFolderContent(folderUuid);
|
|
110
|
+
const foldersXML = folderContent.folders.map((folder) => {
|
|
111
|
+
const folderRelativePath = webdav_utils_1.WebDavUtils.joinURL(relativePath, folder.plainName, '/');
|
|
112
|
+
return this.driveFolderItemToXMLNode({
|
|
113
|
+
name: folder.plainName,
|
|
114
|
+
bucket: folder.bucket,
|
|
115
|
+
createdAt: new Date(folder.createdAt),
|
|
116
|
+
updatedAt: new Date(folder.updatedAt),
|
|
117
|
+
id: folder.id,
|
|
118
|
+
encryptedName: folder.name,
|
|
119
|
+
uuid: folder.uuid,
|
|
120
|
+
parentId: null,
|
|
121
|
+
}, encodeURI(folderRelativePath));
|
|
122
|
+
});
|
|
123
|
+
folderContent.folders.map(async (folder) => {
|
|
124
|
+
return await driveDatabaseManager.createFolder({
|
|
125
|
+
...folder,
|
|
126
|
+
name: folder.plainName,
|
|
127
|
+
encryptedName: folder.name,
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
const filesXML = folderContent.files.map((file) => {
|
|
131
|
+
const fileRelativePath = webdav_utils_1.WebDavUtils.joinURL(relativePath, file.type ? `${file.plainName}.${file.type}` : file.plainName);
|
|
132
|
+
return this.driveFileItemToXMLNode({
|
|
133
|
+
name: file.plainName,
|
|
134
|
+
bucket: file.bucket,
|
|
135
|
+
id: file.id,
|
|
136
|
+
createdAt: new Date(file.createdAt),
|
|
137
|
+
updatedAt: new Date(file.updatedAt),
|
|
138
|
+
fileId: file.fileId,
|
|
139
|
+
uuid: file.uuid,
|
|
140
|
+
type: file.type,
|
|
141
|
+
encryptedName: file.name,
|
|
142
|
+
status: file.status,
|
|
143
|
+
folderId: file.folderId,
|
|
144
|
+
size: Number(file.size),
|
|
145
|
+
}, encodeURI(fileRelativePath));
|
|
146
|
+
});
|
|
147
|
+
folderContent.files.map(async (file) => {
|
|
148
|
+
return await driveDatabaseManager.createFile({
|
|
149
|
+
...file,
|
|
150
|
+
name: file.plainName,
|
|
151
|
+
fileId: file.fileId,
|
|
152
|
+
size: Number(file.size),
|
|
153
|
+
encryptedName: file.name,
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
return foldersXML.concat(filesXML);
|
|
157
|
+
}
|
|
158
|
+
async getFolderRootXMLNode(relativePath, folderUuid) {
|
|
159
|
+
const { driveFolderService } = this.dependencies;
|
|
160
|
+
const folderMeta = await driveFolderService.getFolderMetaByUuid(folderUuid);
|
|
161
|
+
const folderXML = this.driveFolderRootStatsToXMLNode(folderMeta, encodeURI(relativePath));
|
|
162
|
+
return folderXML;
|
|
163
|
+
}
|
|
164
|
+
async getFolderXMLNode(relativePath, folderUuid) {
|
|
165
|
+
const { driveFolderService } = this.dependencies;
|
|
166
|
+
const folderMeta = await driveFolderService.getFolderMetaByUuid(folderUuid);
|
|
167
|
+
const folderXML = this.driveFolderItemToXMLNode(folderMeta, encodeURI(relativePath));
|
|
168
|
+
return folderXML;
|
|
169
|
+
}
|
|
170
|
+
driveFolderRootStatsToXMLNode(driveFolderItem, relativePath) {
|
|
171
|
+
const driveFolderXML = {
|
|
172
|
+
[xml_utils_1.XMLUtils.addDefaultNamespace('href')]: relativePath,
|
|
173
|
+
[xml_utils_1.XMLUtils.addDefaultNamespace('propstat')]: {
|
|
174
|
+
[xml_utils_1.XMLUtils.addDefaultNamespace('status')]: 'HTTP/1.1 200 OK',
|
|
175
|
+
[xml_utils_1.XMLUtils.addDefaultNamespace('prop')]: {
|
|
176
|
+
[xml_utils_1.XMLUtils.addDefaultNamespace('getcontenttype')]: 'application/octet-stream',
|
|
177
|
+
'x1:lastmodified': {
|
|
178
|
+
'#text': format_utils_1.FormatUtils.formatDateForWebDav(driveFolderItem.updatedAt),
|
|
179
|
+
'@_xmlns:x1': 'SAR:',
|
|
180
|
+
},
|
|
181
|
+
'x2:executable': {
|
|
182
|
+
'#text': 'F',
|
|
183
|
+
'@_xmlns:x2': 'http://apache.org/dav/props/',
|
|
184
|
+
},
|
|
185
|
+
'x3:Win32FileAttributes': {
|
|
186
|
+
'#text': '00000030',
|
|
187
|
+
'@_xmlns:x3': 'urn:schemas-microsoft-com:',
|
|
188
|
+
},
|
|
189
|
+
[xml_utils_1.XMLUtils.addDefaultNamespace('resourcetype')]: {
|
|
190
|
+
[xml_utils_1.XMLUtils.addDefaultNamespace('collection')]: '',
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
};
|
|
195
|
+
return driveFolderXML;
|
|
196
|
+
}
|
|
197
|
+
driveFolderItemToXMLNode(driveFolderItem, relativePath) {
|
|
198
|
+
const displayName = `${driveFolderItem.name}`;
|
|
199
|
+
const driveFolderXML = {
|
|
200
|
+
[xml_utils_1.XMLUtils.addDefaultNamespace('href')]: relativePath,
|
|
201
|
+
[xml_utils_1.XMLUtils.addDefaultNamespace('propstat')]: {
|
|
202
|
+
[xml_utils_1.XMLUtils.addDefaultNamespace('status')]: 'HTTP/1.1 200 OK',
|
|
203
|
+
[xml_utils_1.XMLUtils.addDefaultNamespace('prop')]: {
|
|
204
|
+
[xml_utils_1.XMLUtils.addDefaultNamespace('displayname')]: displayName,
|
|
205
|
+
[xml_utils_1.XMLUtils.addDefaultNamespace('getlastmodified')]: format_utils_1.FormatUtils.formatDateForWebDav(driveFolderItem.updatedAt),
|
|
206
|
+
[xml_utils_1.XMLUtils.addDefaultNamespace('getcontentlength')]: 0,
|
|
207
|
+
[xml_utils_1.XMLUtils.addDefaultNamespace('resourcetype')]: {
|
|
208
|
+
[xml_utils_1.XMLUtils.addDefaultNamespace('collection')]: '',
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
};
|
|
213
|
+
return driveFolderXML;
|
|
214
|
+
}
|
|
215
|
+
driveFileItemToXMLNode(driveFileItem, relativePath) {
|
|
216
|
+
const displayName = driveFileItem.type ? `${driveFileItem.name}.${driveFileItem.type}` : driveFileItem.name;
|
|
217
|
+
const driveFileXML = {
|
|
218
|
+
[xml_utils_1.XMLUtils.addDefaultNamespace('href')]: relativePath,
|
|
219
|
+
[xml_utils_1.XMLUtils.addDefaultNamespace('propstat')]: {
|
|
220
|
+
[xml_utils_1.XMLUtils.addDefaultNamespace('status')]: 'HTTP/1.1 200 OK',
|
|
221
|
+
[xml_utils_1.XMLUtils.addDefaultNamespace('prop')]: {
|
|
222
|
+
[xml_utils_1.XMLUtils.addDefaultNamespace('resourcetype')]: '',
|
|
223
|
+
[xml_utils_1.XMLUtils.addDefaultNamespace('getetag')]: '"' + (0, crypto_1.randomUUID)().replaceAll('-', '') + '"',
|
|
224
|
+
[xml_utils_1.XMLUtils.addDefaultNamespace('displayname')]: displayName,
|
|
225
|
+
[xml_utils_1.XMLUtils.addDefaultNamespace('getcontenttype')]: mime_types_1.default.lookup(displayName) || 'application/octet-stream',
|
|
226
|
+
[xml_utils_1.XMLUtils.addDefaultNamespace('getlastmodified')]: format_utils_1.FormatUtils.formatDateForWebDav(driveFileItem.updatedAt),
|
|
227
|
+
[xml_utils_1.XMLUtils.addDefaultNamespace('getcontentlength')]: driveFileItem.size,
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
};
|
|
231
|
+
return driveFileXML;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
exports.PROPFINDRequestHandler = PROPFINDRequestHandler;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Request, Response } from 'express';
|
|
2
|
+
import { DriveFileService } from '../../services/drive/drive-file.service';
|
|
3
|
+
import { NetworkFacade } from '../../services/network/network-facade.service';
|
|
4
|
+
import { UploadService } from '../../services/network/upload.service';
|
|
5
|
+
import { DownloadService } from '../../services/network/download.service';
|
|
6
|
+
import { CryptoService } from '../../services/crypto.service';
|
|
7
|
+
import { AuthService } from '../../services/auth.service';
|
|
8
|
+
import { WebDavMethodHandler } from '../../types/webdav.types';
|
|
9
|
+
import { DriveDatabaseManager } from '../../services/database/drive-database-manager.service';
|
|
10
|
+
export declare class PUTRequestHandler implements WebDavMethodHandler {
|
|
11
|
+
private dependencies;
|
|
12
|
+
constructor(dependencies: {
|
|
13
|
+
driveFileService: DriveFileService;
|
|
14
|
+
driveDatabaseManager: DriveDatabaseManager;
|
|
15
|
+
uploadService: UploadService;
|
|
16
|
+
downloadService: DownloadService;
|
|
17
|
+
cryptoService: CryptoService;
|
|
18
|
+
authService: AuthService;
|
|
19
|
+
networkFacade: NetworkFacade;
|
|
20
|
+
});
|
|
21
|
+
handle: (req: Request, res: Response) => Promise<void>;
|
|
22
|
+
private getDriveFolderRealmObject;
|
|
23
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PUTRequestHandler = void 0;
|
|
4
|
+
const drive_file_service_1 = require("../../services/drive/drive-file.service");
|
|
5
|
+
const errors_utils_1 = require("../../utils/errors.utils");
|
|
6
|
+
const webdav_utils_1 = require("../../utils/webdav.utils");
|
|
7
|
+
const logger_utils_1 = require("../../utils/logger.utils");
|
|
8
|
+
class PUTRequestHandler {
|
|
9
|
+
dependencies;
|
|
10
|
+
constructor(dependencies) {
|
|
11
|
+
this.dependencies = dependencies;
|
|
12
|
+
}
|
|
13
|
+
handle = async (req, res) => {
|
|
14
|
+
const contentLength = Number(req.headers['content-length']);
|
|
15
|
+
if (!contentLength || isNaN(contentLength) || contentLength <= 0) {
|
|
16
|
+
throw new errors_utils_1.UnsupportedMediaTypeError('Empty files are not supported');
|
|
17
|
+
}
|
|
18
|
+
const resource = await webdav_utils_1.WebDavUtils.getRequestedResource(req, this.dependencies.driveDatabaseManager);
|
|
19
|
+
const driveFolder = await this.getDriveFolderRealmObject(resource);
|
|
20
|
+
logger_utils_1.webdavLogger.info(`PUT request received for uploading file '${resource.name}' to '${resource.path.dir}'`);
|
|
21
|
+
if (!driveFolder) {
|
|
22
|
+
throw new errors_utils_1.NotFoundError('Drive destination folder not found');
|
|
23
|
+
}
|
|
24
|
+
const { user, mnemonic } = await this.dependencies.authService.getAuthDetails();
|
|
25
|
+
const [uploadPromise] = await this.dependencies.networkFacade.uploadFromStream(user.bucket, mnemonic, contentLength, req, {
|
|
26
|
+
progressCallback: (progress) => {
|
|
27
|
+
logger_utils_1.webdavLogger.info(`Upload progress for file ${resource.name}: ${progress}%`);
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
const uploadResult = await uploadPromise;
|
|
31
|
+
logger_utils_1.webdavLogger.info('✅ File uploaded to network');
|
|
32
|
+
const file = await drive_file_service_1.DriveFileService.instance.createFile({
|
|
33
|
+
name: resource.path.name,
|
|
34
|
+
type: resource.path.ext.replaceAll('.', ''),
|
|
35
|
+
size: contentLength,
|
|
36
|
+
folderId: driveFolder.id,
|
|
37
|
+
fileId: uploadResult.fileId,
|
|
38
|
+
bucket: user.bucket,
|
|
39
|
+
});
|
|
40
|
+
logger_utils_1.webdavLogger.info('✅ File uploaded to internxt drive');
|
|
41
|
+
this.dependencies.driveDatabaseManager.createFile(file);
|
|
42
|
+
res.status(200);
|
|
43
|
+
res.send();
|
|
44
|
+
};
|
|
45
|
+
async getDriveFolderRealmObject(resource) {
|
|
46
|
+
const { driveDatabaseManager } = this.dependencies;
|
|
47
|
+
const result = await driveDatabaseManager.findByRelativePath(resource.path.dir);
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
exports.PUTRequestHandler = PUTRequestHandler;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const dotenv_1 = __importDefault(require("dotenv"));
|
|
7
|
+
const webdav_server_1 = require("./webdav-server");
|
|
8
|
+
const express_1 = __importDefault(require("express"));
|
|
9
|
+
const config_service_1 = require("../services/config.service");
|
|
10
|
+
const drive_folder_service_1 = require("../services/drive/drive-folder.service");
|
|
11
|
+
const drive_database_manager_service_1 = require("../services/database/drive-database-manager.service");
|
|
12
|
+
const drive_file_repository_1 = require("../services/database/drive-file/drive-file.repository");
|
|
13
|
+
const drive_folder_repository_1 = require("../services/database/drive-folder/drive-folder.repository");
|
|
14
|
+
const drive_file_service_1 = require("../services/drive/drive-file.service");
|
|
15
|
+
const upload_service_1 = require("../services/network/upload.service");
|
|
16
|
+
const download_service_1 = require("../services/network/download.service");
|
|
17
|
+
const auth_service_1 = require("../services/auth.service");
|
|
18
|
+
const crypto_service_1 = require("../services/crypto.service");
|
|
19
|
+
dotenv_1.default.config();
|
|
20
|
+
const init = async () => {
|
|
21
|
+
await config_service_1.ConfigService.instance.ensureInternxtCliDataDirExists();
|
|
22
|
+
await config_service_1.ConfigService.instance.ensureWebdavCertsDirExists();
|
|
23
|
+
await config_service_1.ConfigService.instance.ensureInternxtLogsDirExists();
|
|
24
|
+
await drive_database_manager_service_1.DriveDatabaseManager.init();
|
|
25
|
+
new webdav_server_1.WebDavServer((0, express_1.default)(), config_service_1.ConfigService.instance, drive_file_service_1.DriveFileService.instance, drive_folder_service_1.DriveFolderService.instance, new drive_database_manager_service_1.DriveDatabaseManager(new drive_file_repository_1.DriveFileRepository(), new drive_folder_repository_1.DriveFolderRepository()), upload_service_1.UploadService.instance, download_service_1.DownloadService.instance, auth_service_1.AuthService.instance, crypto_service_1.CryptoService.instance)
|
|
26
|
+
.start()
|
|
27
|
+
.then()
|
|
28
|
+
.catch(console.error);
|
|
29
|
+
};
|
|
30
|
+
init();
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AuthMiddleware = void 0;
|
|
4
|
+
const sdk_manager_service_1 = require("../../services/sdk-manager.service");
|
|
5
|
+
const AuthMiddleware = (configService) => {
|
|
6
|
+
return (req, res, next) => {
|
|
7
|
+
(async () => {
|
|
8
|
+
try {
|
|
9
|
+
const credentials = await configService.readUser();
|
|
10
|
+
if (!credentials)
|
|
11
|
+
throw new Error('Unauthorized');
|
|
12
|
+
sdk_manager_service_1.SdkManager.init({
|
|
13
|
+
token: credentials.token,
|
|
14
|
+
newToken: credentials.newToken,
|
|
15
|
+
});
|
|
16
|
+
req.user = {
|
|
17
|
+
rootFolderId: credentials.user.root_folder_id,
|
|
18
|
+
};
|
|
19
|
+
next();
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
res.status(401).send({ error: error.message });
|
|
23
|
+
}
|
|
24
|
+
})();
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
exports.AuthMiddleware = AuthMiddleware;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ErrorHandlingMiddleware = void 0;
|
|
4
|
+
const ErrorHandlingMiddleware = (err, _, res, __) => {
|
|
5
|
+
if ('statusCode' in err) {
|
|
6
|
+
res.status(err.statusCode).send({
|
|
7
|
+
error: {
|
|
8
|
+
message: err.message,
|
|
9
|
+
},
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
else {
|
|
13
|
+
res.status(500).send({
|
|
14
|
+
error: {
|
|
15
|
+
message: 'message' in err ? err.message : 'Something went wrong',
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
exports.ErrorHandlingMiddleware = ErrorHandlingMiddleware;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RequestLoggerMiddleware = void 0;
|
|
4
|
+
const logger_utils_1 = require("../../utils/logger.utils");
|
|
5
|
+
const RequestLoggerMiddleware = (config) => {
|
|
6
|
+
return (req, _, next) => {
|
|
7
|
+
if (!config.enable)
|
|
8
|
+
return next();
|
|
9
|
+
if (config.methods && !config.methods.includes(req.method))
|
|
10
|
+
return next();
|
|
11
|
+
logger_utils_1.webdavLogger.info(`WebDav request received\nMethod: ${req.method}\nURL: ${req.url}\nBody: ${req.body}\nHeaders: ${JSON.stringify(req.headers)}`);
|
|
12
|
+
next();
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
exports.RequestLoggerMiddleware = RequestLoggerMiddleware;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Express } from 'express';
|
|
2
|
+
import { ConfigService } from '../services/config.service';
|
|
3
|
+
import { DriveFolderService } from '../services/drive/drive-folder.service';
|
|
4
|
+
import { DriveDatabaseManager } from '../services/database/drive-database-manager.service';
|
|
5
|
+
import { DriveFileService } from '../services/drive/drive-file.service';
|
|
6
|
+
import { UploadService } from '../services/network/upload.service';
|
|
7
|
+
import { DownloadService } from '../services/network/download.service';
|
|
8
|
+
import { AuthService } from '../services/auth.service';
|
|
9
|
+
import { CryptoService } from '../services/crypto.service';
|
|
10
|
+
export declare class WebDavServer {
|
|
11
|
+
private app;
|
|
12
|
+
private configService;
|
|
13
|
+
private driveFileService;
|
|
14
|
+
private driveFolderService;
|
|
15
|
+
private driveDatabaseManager;
|
|
16
|
+
private uploadService;
|
|
17
|
+
private downloadService;
|
|
18
|
+
private authService;
|
|
19
|
+
private cryptoService;
|
|
20
|
+
constructor(app: Express, configService: ConfigService, driveFileService: DriveFileService, driveFolderService: DriveFolderService, driveDatabaseManager: DriveDatabaseManager, uploadService: UploadService, downloadService: DownloadService, authService: AuthService, cryptoService: CryptoService);
|
|
21
|
+
private getNetwork;
|
|
22
|
+
private registerMiddlewares;
|
|
23
|
+
private registerHandlers;
|
|
24
|
+
start(): Promise<void>;
|
|
25
|
+
}
|