mirror of
https://github.com/get-drexa/drive.git
synced 2025-12-01 05:51:39 +00:00
feat: implement comprehensive access control system
- Add authorizedGet function for secure resource access - Implement ownership verification for all file/directory operations - Use security through obscurity (not found vs access denied) - Optimize bulk operations by removing redundant authorization checks - Move generateFileUrl to filesystem.ts as fetchFileUrl with proper auth - Ensure all database access goes through authorization layer Co-authored-by: Ona <no-reply@ona.com>
This commit is contained in:
@@ -3,6 +3,7 @@ import type {
|
||||
AuthenticatedMutationCtx,
|
||||
AuthenticatedQueryCtx,
|
||||
} from "../functions"
|
||||
import { authorizedGet } from "../functions"
|
||||
import * as Err from "./error"
|
||||
import {
|
||||
type DirectoryHandle,
|
||||
@@ -27,8 +28,8 @@ export async function fetchHandle(
|
||||
ctx: AuthenticatedQueryCtx,
|
||||
handle: DirectoryHandle,
|
||||
): Promise<Doc<"directories">> {
|
||||
const directory = await ctx.db.get(handle.id)
|
||||
if (!directory || directory.userId !== ctx.user._id) {
|
||||
const directory = await authorizedGet(ctx, handle.id)
|
||||
if (!directory) {
|
||||
throw Err.create(
|
||||
Err.Code.DirectoryNotFound,
|
||||
`Directory ${handle.id} not found`,
|
||||
@@ -41,7 +42,7 @@ export async function fetch(
|
||||
ctx: AuthenticatedQueryCtx,
|
||||
{ directoryId }: { directoryId: Id<"directories"> },
|
||||
): Promise<DirectoryInfo> {
|
||||
const directory = await ctx.db.get(directoryId)
|
||||
const directory = await authorizedGet(ctx, directoryId)
|
||||
if (!directory) {
|
||||
throw Err.create(
|
||||
Err.Code.DirectoryNotFound,
|
||||
@@ -57,7 +58,7 @@ export async function fetch(
|
||||
]
|
||||
let parentDirId = directory.parentId
|
||||
while (parentDirId) {
|
||||
const parentDir = await ctx.db.get(parentDirId)
|
||||
const parentDir = await authorizedGet(ctx, parentDirId)
|
||||
if (parentDir) {
|
||||
path.push({
|
||||
handle: newDirectoryHandle(parentDir._id),
|
||||
@@ -65,7 +66,7 @@ export async function fetch(
|
||||
})
|
||||
parentDirId = parentDir.parentId
|
||||
} else {
|
||||
throw Err.create(Err.Code.Internal)
|
||||
throw Err.create(Err.Code.DirectoryNotFound, "Parent directory not found")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,7 +133,7 @@ export async function create(
|
||||
ctx: AuthenticatedMutationCtx,
|
||||
{ name, parentId }: { name: string; parentId: Id<"directories"> },
|
||||
): Promise<Id<"directories">> {
|
||||
const parentDir = await ctx.db.get(parentId)
|
||||
const parentDir = await authorizedGet(ctx, parentId)
|
||||
if (!parentDir) {
|
||||
throw Err.create(
|
||||
Err.Code.DirectoryNotFound,
|
||||
@@ -180,7 +181,7 @@ export async function move(
|
||||
) {
|
||||
const conflictCheckResults = await Promise.allSettled(
|
||||
sourceDirectories.map((directory) =>
|
||||
ctx.db.get(directory.id).then((d) => {
|
||||
authorizedGet(ctx, directory.id).then((d) => {
|
||||
if (!d) {
|
||||
throw Err.create(
|
||||
Err.Code.DirectoryNotFound,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { Doc, Id } from "../_generated/dataModel"
|
||||
import type { AuthenticatedMutationCtx } from "../functions"
|
||||
import { type AuthenticatedMutationCtx, authorizedGet } from "../functions"
|
||||
import * as Err from "./error"
|
||||
import type { DirectoryHandle, FileHandle } from "./filesystem"
|
||||
|
||||
@@ -48,7 +48,7 @@ export async function move(
|
||||
) {
|
||||
const conflictCheckResults = await Promise.allSettled(
|
||||
items.map((fileHandle) =>
|
||||
ctx.db.get(fileHandle.id).then((f) => {
|
||||
authorizedGet(ctx, fileHandle.id).then((f) => {
|
||||
if (!f) {
|
||||
throw Err.create(
|
||||
Err.Code.FileNotFound,
|
||||
|
||||
@@ -4,6 +4,7 @@ import type {
|
||||
AuthenticatedMutationCtx,
|
||||
AuthenticatedQueryCtx,
|
||||
} from "../functions"
|
||||
import { authorizedGet } from "../functions"
|
||||
import * as Directories from "./directories"
|
||||
import * as Err from "./error"
|
||||
import * as Files from "./files"
|
||||
@@ -295,3 +296,20 @@ export async function emptyTrash(
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
export async function fetchFileUrl(
|
||||
ctx: AuthenticatedQueryCtx,
|
||||
{ fileId }: { fileId: Id<"files"> },
|
||||
): Promise<string> {
|
||||
const file = await authorizedGet(ctx, fileId)
|
||||
if (!file) {
|
||||
throw Err.create(Err.Code.NotFound, "file not found")
|
||||
}
|
||||
|
||||
const url = await ctx.storage.getUrl(file.storageId)
|
||||
if (!url) {
|
||||
throw Err.create(Err.Code.NotFound, "file not found")
|
||||
}
|
||||
|
||||
return url
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user