Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/prevent rm and mv ancestor folders #30

Merged
merged 3 commits into from
Nov 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions lib/path/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ export class VirtualPath {
return this.path === '';
}

isAncestor (other: VirtualPath): boolean {
return other.path.startsWith(this.path + '/');
}

isHome (username: string): boolean {
return this.equals(VirtualPath.homeDir(username));
}
Expand Down
2 changes: 2 additions & 0 deletions lib/responseCodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export enum FileCpErrorCode {
INVALID_PARAM = 1000,
INVALID_BODY = 1001,
NOT_ENOUGH_PRIVILEGE = 2000,
CP_TO_DESCENDANT = 2001,
SRC_NOT_FOUND = 3000,
DEST_NOT_FOUND = 3001,
INVALID_COPY_FOLDER_TO_FILE = 3002,
Expand Down Expand Up @@ -77,6 +78,7 @@ export enum FileMvErrorCode {
INVALID_PARAM = 1000,
INVALID_BODY = 1001,
NOT_ENOUGH_PRIVILEGE = 2000,
MV_TO_DESCENDANT = 2001,
SRC_NOT_FOUND = 3000,
DEST_NOT_FOUND = 3001,
INVALID_MV_FOLDER_TO_FILE = 3002,
Expand Down
3 changes: 3 additions & 0 deletions server/api/files/cp.post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ export default defineEventHandler(async (event) => {
if (!dest.isValid()) {
return { error: { code: FileCpErrorCode.INVALID_BODY, message: 'Expect the "dest" param to be valid path' } };
}
if (src.isAncestor(dest)) {
return { error: { code: FileCpErrorCode.CP_TO_DESCENDANT, message: 'Cannot copy a folder to it descendant' } };
}

try {
await db.serializable(dbPool, async (dbClient) => {
Expand Down
3 changes: 3 additions & 0 deletions server/api/files/mv.post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ export default defineEventHandler(async (event) => {
if (!dest.isValid()) {
return { error: { code: FileMvErrorCode.INVALID_BODY, message: 'Expect the "dest" param to be valid path' } };
}
if (src.isAncestor(dest)) {
return { error: { code: FileMvErrorCode.MV_TO_DESCENDANT, message: 'Cannot move a folder to it descendant' } };
}

try {
await db.serializable(dbPool, async (dbClient) => {
Expand Down
28 changes: 23 additions & 5 deletions services/files.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import path from 'path-browserify';
import { Err, Ok, type Diagnostic, type Result } from './types';
import { FilePostErrorCode } from '~/lib';
import type { VirtualPath } from '~/lib/path';

export enum UserKind {
OWNER = 'owner',
Expand Down Expand Up @@ -118,9 +119,13 @@ export const fileService = {
},
async removeFile (filename: string): Promise<Result<null, Diagnostic>> {
const { cwd } = useCwdStore();
const resolvedPath = cwd.value.resolve(filename);
if (resolvedPath.isAncestor(cwd.value as VirtualPath)) {
return new Err({ code: 1, message: 'Cannot remove ancestor folder' });
}
const res = await $fetch('/api/files', {
method: 'delete',
query: { name: cwd.value.resolve(filename).toString() },
query: { name: resolvedPath.toString() },
credentials: 'include',
});
if (res.error) {
Expand Down Expand Up @@ -185,11 +190,19 @@ export const fileService = {
},
async moveFile (src: string, dest: string, umask: string): Promise<Result<null, Diagnostic>> {
const { cwd } = useCwdStore();
const resolvedSrc = cwd.value.resolve(src);
const resolvedDest = cwd.value.resolve(dest);
if (resolvedSrc.isAncestor(cwd.value as VirtualPath)) {
return new Err({ code: 1, message: 'Cannot move ancestor folder' });
}
if (resolvedSrc.isAncestor(resolvedDest)) {
return new Err({ code: 1, message: 'Cannot move a folder to its descendant' });
}
const res = await $fetch('/api/files/mv', {
method: 'post',
body: {
src: cwd.value.resolve(src).toString(),
dest: cwd.value.resolve(dest).toString(),
src: resolvedSrc.toString(),
dest: resolvedDest.toString(),
permission_bits: umask,
},
credentials: 'include',
Expand All @@ -202,11 +215,16 @@ export const fileService = {
},
async copyFile (src: string, dest: string, umask: string): Promise<Result<null, Diagnostic>> {
const { cwd } = useCwdStore();
const resolvedSrc = cwd.value.resolve(src);
const resolvedDest = cwd.value.resolve(dest);
if (resolvedSrc.isAncestor(resolvedDest)) {
return new Err({ code: 1, message: 'Cannot copy a folder to its descendant' });
}
const res = await $fetch('/api/files/cp', {
method: 'post',
body: {
src: cwd.value.resolve(src).toString(),
dest: cwd.value.resolve(dest).toString(),
src: resolvedSrc.toString(),
dest: resolvedDest.toString(),
permission_bits: umask,
},
credentials: 'include',
Expand Down
Loading