Skip to content

Commit ff47286

Browse files
committed
Merge branch 'main' into feat/pb-5115-add-universal-link-login
2 parents 361f563 + f7fa360 commit ff47286

26 files changed

Lines changed: 263 additions & 412 deletions

WEBDAV.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ Below you can find a list of WebDav clients that we officially support in the In
2828
| CyberDuck for MacOS ||
2929
| Transmit ||
3030
| Cadaver ||
31+
| Nautilus (GNOME Files)||
3132

3233
## Supported WebDav methods
3334

src/services/database/drive-file/drive-file.domain.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ export class DriveFile implements DriveFileAttributes {
7878

7979
public toItem(): DriveFileItem {
8080
return {
81+
itemType: 'file',
8182
id: this.id,
8283
name: this.name,
8384
type: this.type,

src/services/database/drive-folder/drive-folder.domain.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ export class DriveFolder implements DriveFolderAttributes {
5454

5555
public toItem(): DriveFolderItem {
5656
return {
57+
itemType: 'folder',
5758
id: this.id,
5859
name: this.name,
5960
uuid: this.uuid,

src/services/drive/drive-file.service.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export class DriveFileService {
1111
const driveFile = await storageClient.createFileEntryByUuid(payload);
1212

1313
return {
14+
itemType: 'file',
1415
name: payload.plainName,
1516
id: driveFile.id,
1617
uuid: driveFile.uuid,

src/types/drive.types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export type DriveFileItem = Omit<
1212
| 'modificationTime'
1313
| 'type'
1414
> & {
15+
itemType: 'file';
1516
size: number;
1617
createdAt: Date;
1718
updatedAt: Date;
@@ -21,6 +22,7 @@ export type DriveFileItem = Omit<
2122
};
2223

2324
export type DriveFolderItem = Pick<DriveFolderData, 'name' | 'bucket' | 'id' | 'parentId'> & {
25+
itemType: 'folder';
2426
encryptedName: string;
2527
uuid: string;
2628
createdAt: Date;

src/types/webdav.types.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ export type WebDavMethodHandlerOptions = {
1010
};
1111

1212
export type WebDavRequestedResource = {
13-
type: 'file' | 'folder';
1413
url: string;
1514
name: string;
1615
path: ParsedPath;

src/utils/drive.utils.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { DriveFileItem, DriveFolderItem } from '../types/drive.types';
44
export class DriveUtils {
55
static driveFileMetaToItem(fileMeta: FileMeta): DriveFileItem {
66
return {
7+
itemType: 'file',
78
uuid: fileMeta.uuid ?? '',
89
status: fileMeta.status,
910
folderId: fileMeta.folderId,
@@ -23,6 +24,7 @@ export class DriveUtils {
2324

2425
static driveFolderMetaToItem(folderMeta: FolderMeta): DriveFolderItem {
2526
return {
27+
itemType: 'folder',
2628
uuid: folderMeta.uuid,
2729
id: folderMeta.id,
2830
bucket: folderMeta.bucket,
@@ -38,6 +40,7 @@ export class DriveUtils {
3840

3941
static createFolderResponseToItem(folderResponse: CreateFolderResponse): DriveFolderItem {
4042
return {
43+
itemType: 'folder',
4144
uuid: folderResponse.uuid,
4245
id: folderResponse.id,
4346
bucket: folderResponse.bucket,

src/utils/webdav.utils.ts

Lines changed: 58 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import { Request } from 'express';
21
import path from 'node:path';
32
import { WebDavRequestedResource } from '../types/webdav.types';
43
import { DriveFolderService } from '../services/drive/drive-folder.service';
54
import { DriveFileService } from '../services/drive/drive-file.service';
65
import { DriveFileItem, DriveFolderItem, DriveItem } from '../types/drive.types';
6+
import { webdavLogger } from './logger.utils';
77

88
export class WebDavUtils {
99
static joinURL(...pathComponents: string[]): string {
@@ -39,74 +39,85 @@ export class WebDavUtils {
3939
return normalizedPath;
4040
}
4141

42-
static async getRequestedResource(urlObject: string | Request, decodeUri = true): Promise<WebDavRequestedResource> {
43-
let requestUrl: string;
44-
if (typeof urlObject === 'string') {
45-
requestUrl = urlObject;
46-
} else {
47-
requestUrl = urlObject.url;
48-
}
49-
42+
static async getRequestedResource(requestUrl: string, decodeUri = true): Promise<WebDavRequestedResource> {
5043
const decodedUrl = this.decodeUrl(requestUrl, decodeUri);
5144
const parsedPath = path.parse(decodedUrl);
5245
const parentPath = this.normalizeFolderPath(path.dirname(decodedUrl));
5346

54-
const isFolder = requestUrl.endsWith('/');
55-
56-
if (isFolder) {
57-
return {
58-
type: 'folder',
59-
url: decodedUrl,
60-
name: parsedPath.base,
61-
path: parsedPath,
62-
parentPath,
63-
};
64-
} else {
65-
return {
66-
type: 'file',
67-
url: decodedUrl,
68-
name: parsedPath.name,
69-
path: parsedPath,
70-
parentPath,
71-
};
72-
}
47+
return {
48+
url: decodedUrl,
49+
name: parsedPath.base,
50+
path: parsedPath,
51+
parentPath,
52+
};
7353
}
7454

75-
static async getDriveItemFromResource(params: {
76-
resource: WebDavRequestedResource;
55+
static async tryGetFileOrFolderMetadata({
56+
url,
57+
driveFileService,
58+
driveFolderService,
59+
}: {
60+
url: string;
7761
driveFolderService: DriveFolderService;
78-
driveFileService?: never;
79-
}): Promise<DriveFolderItem | undefined>;
62+
driveFileService: DriveFileService;
63+
}): Promise<DriveItem | undefined> {
64+
try {
65+
return await driveFileService.getFileMetadataByPath(url);
66+
} catch {
67+
return await driveFolderService.getFolderMetadataByPath(url);
68+
}
69+
}
8070

81-
static async getDriveItemFromResource(params: {
82-
resource: WebDavRequestedResource;
83-
driveFolderService?: never;
71+
static async getDriveFileFromResource({
72+
url,
73+
driveFileService,
74+
}: {
75+
url: string;
8476
driveFileService: DriveFileService;
85-
}): Promise<DriveFileItem | undefined>;
77+
}): Promise<DriveFileItem | undefined> {
78+
try {
79+
return await driveFileService.getFileMetadataByPath(url);
80+
} catch (err) {
81+
webdavLogger.error('Exception while getting the file metadata by path', err);
82+
}
83+
}
8684

87-
static async getDriveItemFromResource(params: {
88-
resource: WebDavRequestedResource;
85+
static async getDriveFolderFromResource({
86+
url,
87+
driveFolderService,
88+
}: {
89+
url: string;
8990
driveFolderService: DriveFolderService;
90-
driveFileService: DriveFileService;
91-
}): Promise<DriveItem | undefined>;
91+
}): Promise<DriveFolderItem | undefined> {
92+
try {
93+
return await driveFolderService.getFolderMetadataByPath(url);
94+
} catch (err) {
95+
webdavLogger.error('Exception while getting the folder metadata by path', err);
96+
}
97+
}
9298

9399
static async getDriveItemFromResource({
94100
resource,
95101
driveFolderService,
96102
driveFileService,
97103
}: {
98104
resource: WebDavRequestedResource;
99-
driveFolderService?: DriveFolderService;
100-
driveFileService?: DriveFileService;
105+
driveFolderService: DriveFolderService;
106+
driveFileService: DriveFileService;
101107
}): Promise<DriveItem | undefined> {
102108
let item: DriveItem | undefined = undefined;
103109

110+
const isFolder = resource.url.endsWith('/');
111+
104112
try {
105-
if (resource.type === 'folder') {
106-
item = await driveFolderService?.getFolderMetadataByPath(resource.url);
107-
}
108-
if (resource.type === 'file') {
109-
item = await driveFileService?.getFileMetadataByPath(resource.url);
113+
if (isFolder) {
114+
item = await driveFolderService.getFolderMetadataByPath(resource.url);
115+
} else {
116+
item = await this.tryGetFileOrFolderMetadata({
117+
url: resource.url,
118+
driveFileService,
119+
driveFolderService,
120+
});
110121
}
111122
} catch {
112123
//no op

src/webdav/handlers/DELETE.handler.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ export class DELETERequestHandler implements WebDavMethodHandler {
1818

1919
handle = async (req: Request, res: Response) => {
2020
const { driveFileService, driveFolderService, trashService } = this.dependencies;
21-
const resource = await WebDavUtils.getRequestedResource(req);
22-
webdavLogger.info(`[DELETE] Request received for ${resource.type} at ${resource.url}`);
21+
const resource = await WebDavUtils.getRequestedResource(req.url);
22+
webdavLogger.info(`[DELETE] Request received for item at ${resource.url}`);
2323

2424
const driveItem = await WebDavUtils.getDriveItemFromResource({
2525
resource,
@@ -31,13 +31,13 @@ export class DELETERequestHandler implements WebDavMethodHandler {
3131
throw new NotFoundError(`Resource not found on Internxt Drive at ${resource.url}`);
3232
}
3333

34-
webdavLogger.info(`[DELETE] [${driveItem.uuid}] Trashing ${resource.type}`);
34+
webdavLogger.info(`[DELETE] [${driveItem.uuid}] Trashing ${driveItem.itemType}`);
3535
await trashService.trashItems({
36-
items: [{ type: resource.type, uuid: driveItem.uuid }],
36+
items: [{ type: driveItem.itemType, uuid: driveItem.uuid }],
3737
});
3838

3939
res.status(204).send();
40-
const type = resource.type.charAt(0).toUpperCase() + resource.type.substring(1);
40+
const type = driveItem.itemType.charAt(0).toUpperCase() + driveItem.itemType.substring(1);
4141
webdavLogger.info(`[DELETE] [${driveItem.uuid}] ${type} trashed successfully`);
4242
};
4343
}

src/webdav/handlers/GET.handler.ts

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import { CryptoService } from '../../services/crypto.service';
88
import { AuthService } from '../../services/auth.service';
99
import { NotFoundError } from '../../utils/errors.utils';
1010
import { webdavLogger } from '../../utils/logger.utils';
11-
import { DriveFileItem } from '../../types/drive.types';
1211
import { NetworkUtils } from '../../utils/network.utils';
1312

1413
export class GETRequestHandler implements WebDavMethodHandler {
@@ -24,21 +23,21 @@ export class GETRequestHandler implements WebDavMethodHandler {
2423

2524
handle = async (req: Request, res: Response) => {
2625
const { driveFileService, authService, networkFacade } = this.dependencies;
27-
const resource = await WebDavUtils.getRequestedResource(req);
26+
const resource = await WebDavUtils.getRequestedResource(req.url);
2827

2928
if (resource.name.startsWith('._')) throw new NotFoundError('File not found');
30-
if (resource.type === 'folder') throw new NotFoundError('Folders cannot be listed with GET. Use PROPFIND instead.');
3129

32-
webdavLogger.info(`[GET] Request received for ${resource.type} at ${resource.url}`);
33-
const driveItem = await WebDavUtils.getDriveItemFromResource({
34-
resource,
30+
webdavLogger.info(`[GET] Request received item at ${resource.url}`);
31+
const driveFile = await WebDavUtils.getDriveFileFromResource({
32+
url: resource.url,
3533
driveFileService,
3634
});
3735

38-
if (!driveItem) {
39-
throw new NotFoundError(`Resource not found on Internxt Drive at ${resource.url}`);
36+
if (!driveFile) {
37+
throw new NotFoundError(
38+
`Resource not found on Internxt Drive at ${resource.url}, if trying to access a folder use PROPFIND instead.`,
39+
);
4040
}
41-
const driveFile = driveItem as DriveFileItem;
4241

4342
webdavLogger.info(`[GET] [${driveFile.uuid}] Found Drive File`);
4443

0 commit comments

Comments
 (0)