Skip to content

Commit 2b1ad37

Browse files
authored
Merge pull request #4 from andrecrjr/fix-security
Fix security
2 parents 9f0a9a7 + 66ca84f commit 2b1ad37

File tree

7 files changed

+143
-63
lines changed

7 files changed

+143
-63
lines changed

app/api/action/route.ts

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,22 @@ function getDecryptedPw(req: NextRequest): string | null {
4141
return decrypt(enc)
4242
}
4343

44+
function isDemoMode(serverUrl: string | null): boolean {
45+
return serverUrl?.startsWith("demo://") || false
46+
}
47+
4448
export async function GET(req: NextRequest) {
4549
const { searchParams } = new URL(req.url)
4650
const op = searchParams.get("op") || "ls"
4751
const serverUrl = searchParams.get("serverUrl")
4852
const path = searchParams.get("path") || "/"
49-
const pw = getDecryptedPw(req)
5053

54+
// Check for demo mode first
55+
if (isDemoMode(serverUrl)) {
56+
return NextResponse.json({ error: "Operation not allowed in demo mode" }, { status: 403, headers: { "Cache-Control": "no-store, max-age=0" } })
57+
}
58+
59+
const pw = getDecryptedPw(req)
5160
if (!serverUrl) return NextResponse.json({ error: "Missing serverUrl" }, { status: 400, headers: { "Cache-Control": "no-store, max-age=0" } })
5261
if (!pw) return NextResponse.json({ error: "Unauthorized" }, { status: 401, headers: { "Cache-Control": "no-store, max-age=0" } })
5362

@@ -92,6 +101,13 @@ export async function GET(req: NextRequest) {
92101
export async function POST(req: NextRequest) {
93102
const { searchParams } = new URL(req.url)
94103
const op = searchParams.get("op") || "upload"
104+
const serverUrl = searchParams.get("serverUrl")
105+
106+
// Check for demo mode first
107+
if (isDemoMode(serverUrl)) {
108+
// Block all operations in demo mode
109+
return NextResponse.json({ error: "Operation not allowed in demo mode" }, { status: 403, headers: { "Cache-Control": "no-store, max-age=0" } })
110+
}
95111

96112
if (op === "login") {
97113
const body = await req.json()
@@ -185,6 +201,7 @@ export async function POST(req: NextRequest) {
185201
export async function DELETE(req: NextRequest) {
186202
const { searchParams } = new URL(req.url)
187203
const op = searchParams.get("op") || "delete"
204+
const serverUrl = searchParams.get("serverUrl")
188205

189206
if (op === "logout") {
190207
const res = NextResponse.json({ ok: true }, { status: 200 })
@@ -201,7 +218,27 @@ export async function DELETE(req: NextRequest) {
201218
return res
202219
}
203220

204-
const serverUrl = searchParams.get("serverUrl")
221+
// Check for demo mode
222+
if (isDemoMode(serverUrl)) {
223+
// Block all operations in demo mode except logout
224+
if (op === "logout") {
225+
const res = NextResponse.json({ ok: true }, { status: 200 })
226+
res.cookies.set({
227+
name: COOKIE_NAME,
228+
value: "",
229+
httpOnly: true,
230+
secure: isSecure(req),
231+
sameSite: "lax",
232+
expires: new Date(0),
233+
path: "/",
234+
})
235+
res.headers.set("Cache-Control", "no-store, max-age=0")
236+
return res
237+
} else {
238+
return NextResponse.json({ error: "Operation not allowed in demo mode" }, { status: 403, headers: { "Cache-Control": "no-store, max-age=0" } })
239+
}
240+
}
241+
205242
const path = searchParams.get("path") || "/"
206243
const pw = getDecryptedPw(req)
207244

app/app/demo/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export default function DemoPage() {
1818
taglist: [],
1919
srvinf: "demo",
2020
acct: "demo",
21-
perms: ["read", "write", "delete"],
21+
perms: ["read"], // Only read permissions in demo mode
2222
cfg: {
2323
idx: true,
2424
itag: false,

app/app/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ export default function AppPage() {
7676
taglist: [],
7777
srvinf: "demo",
7878
acct: "demo",
79-
perms: ["read", "write", "delete"],
79+
perms: ["read"], // Only read permissions in demo mode
8080
cfg: {
8181
idx: true,
8282
itag: false,

components/file-manager.tsx

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ export function FileManager({ serverUrl, onLogout, initialData }: FileManagerPro
4444
}
4545

4646
const isDemo = serverUrl.startsWith("demo://")
47-
const hasWritePermission = !isDemo && (data?.perms.includes("write") || false)
48-
const hasDeletePermission = !isDemo && (data?.perms.includes("delete") || false)
47+
const hasWritePermission = data?.perms.includes("write") || false
48+
const hasDeletePermission = data?.perms.includes("delete") || false
4949

5050
const fetchDirectory = async (path: string) => {
5151
setIsLoading(true)
@@ -59,7 +59,7 @@ export function FileManager({ serverUrl, onLogout, initialData }: FileManagerPro
5959
taglist: [],
6060
srvinf: "demo",
6161
acct: "demo",
62-
perms: ["read"],
62+
perms: ["read"], // Only read permissions in demo mode
6363
cfg: {
6464
idx: true,
6565
itag: false,
@@ -312,9 +312,16 @@ export function FileManager({ serverUrl, onLogout, initialData }: FileManagerPro
312312

313313
{/* Main Content */}
314314
<main className="container mx-auto px-3 sm:px-4 py-4 sm:py-6 safe-px">
315-
<Button variant="default" onClick={() => setShowUpload(true)}
316-
className="cursor-pointer rounded-full gap-2 w-14 h-14 absolute
317-
right-10 bottom-10 shadow-md">
315+
<Button variant="default" onClick={() => {
316+
if (isDemo) {
317+
alert("Demo mode: uploads are disabled.");
318+
return;
319+
}
320+
setShowUpload(true);
321+
}}
322+
className="cursor-pointer rounded-full gap-2 w-14 h-14 absolute
323+
right-10 bottom-10 shadow-md"
324+
disabled={isDemo}>
318325
<UploadIcon className="h-5 w-5 sm:h-6 sm:w-6" />
319326
</Button>
320327
{/* Breadcrumbs and Actions */}
@@ -351,7 +358,7 @@ export function FileManager({ serverUrl, onLogout, initialData }: FileManagerPro
351358
</div>
352359
</div>
353360

354-
{hasWritePermission && (
361+
{(hasWritePermission && !isDemo) && (
355362
<div className="flex flex-col sm:flex-row gap-3">
356363
<div className="relative flex-1">
357364
<Input
@@ -368,6 +375,24 @@ export function FileManager({ serverUrl, onLogout, initialData }: FileManagerPro
368375
</div>
369376
</div>
370377
)}
378+
{isDemo && (
379+
<div className="flex flex-col sm:flex-row gap-3">
380+
<div className="relative flex-1">
381+
<Input
382+
placeholder="New folder name"
383+
value=""
384+
onChange={() => {}}
385+
disabled
386+
/>
387+
</div>
388+
<div className="flex items-center gap-2">
389+
<Button onClick={() => alert("Demo mode: creating folders is disabled.")} className="gap-2" disabled>
390+
<FolderPlusIcon className="h-4 w-4" />
391+
Create folder
392+
</Button>
393+
</div>
394+
</div>
395+
)}
371396
</div>
372397

373398
{/* File List */}
@@ -381,8 +406,8 @@ export function FileManager({ serverUrl, onLogout, initialData }: FileManagerPro
381406
files={data.files.filter((f) => f.href.toLowerCase().includes(searchQuery.toLowerCase()))}
382407
onNavigate={(href: string) => handleNavigate(href)}
383408
onDownload={handleDownload}
384-
onDelete={hasDeletePermission ? handleDelete : undefined}
385-
onRename={hasWritePermission ? handleRename : undefined}
409+
onDelete={hasDeletePermission && !isDemo ? handleDelete : undefined}
410+
onRename={hasWritePermission && !isDemo ? handleRename : undefined}
386411
currentPath={currentPath}
387412
serverUrl={serverUrl}
388413
/>
@@ -392,8 +417,8 @@ export function FileManager({ serverUrl, onLogout, initialData }: FileManagerPro
392417
files={data.files.filter((f) => f.href.toLowerCase().includes(searchQuery.toLowerCase()))}
393418
onNavigate={(href: string) => handleNavigate(href)}
394419
onDownload={handleDownload}
395-
onDelete={hasDeletePermission ? handleDelete : undefined}
396-
onRename={hasWritePermission ? handleRename : undefined}
420+
onDelete={hasDeletePermission && !isDemo ? handleDelete : undefined}
421+
onRename={hasWritePermission && !isDemo ? handleRename : undefined}
397422
currentPath={currentPath}
398423
serverUrl={serverUrl}
399424
/>

components/file-upload.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,11 @@ export function FileUpload({ serverUrl, currentPath, onUploadComplete, onClose }
3535
const hasActive = hasUploading || hasFinalizing
3636

3737
const handleFileSelect = (files: FileList | null) => {
38-
if (!files || isDemo) return
38+
if (!files) return
39+
if (isDemo) {
40+
alert("Demo mode: uploads are disabled.")
41+
return
42+
}
3943

4044
const newFiles: UploadFile[] = Array.from(files).map((file) => ({
4145
file,
@@ -200,7 +204,10 @@ export function FileUpload({ serverUrl, currentPath, onUploadComplete, onClose }
200204
onDrop={(e) => {
201205
e.preventDefault()
202206
setIsDragging(false)
203-
if (isDemo) return
207+
if (isDemo) {
208+
alert("Demo mode: uploads are disabled.")
209+
return
210+
}
204211
handleFileSelect(e.dataTransfer.files)
205212
}}
206213
>

0 commit comments

Comments
 (0)